4 * Copyright (c) Tuomo Valkonen 1999-2004.
6 * You may distribute and modify this library under the terms of either
7 * the Clarified Artistic License or the GNU LGPL, version 2.1 or later.
15 #include "optparser.h"
20 #define O_ARGS(o) (o->flags&OPT_OPT_ARG)
21 #define O_ARG(o) (o->flasg&OPT_ARG)
22 #define O_OPT_ARG(o) (O_ARGS(o)==OPT_OPT_ARG)
23 #define O_ID(o) (o->optid)
26 static const OptParserOpt
*o_opts
=NULL
;
27 static char *const *o_current
=NULL
;
29 static const char* o_chain_ptr
=NULL
;
30 static int o_args_left
=0;
31 static const char*o_tmp
=NULL
;
33 static int o_mode
=OPTP_CHAIN
;
39 void optparser_init(int argc
, char *const argv
[], int mode
,
40 const OptParserOpt
*opts
)
55 static const OptParserOpt
*find_chain_opt(char p
, const OptParserOpt
*o
)
58 if((O_ID(o
)&~OPT_ID_RESERVED_FLAG
)==p
)
65 static bool is_option(const char *p
)
86 int optparser_get_opt()
88 #define RET(X) return o_tmp=p, o_error=X
89 const char *p
, *p2
=NULL
;
92 const OptParserOpt
*o
;
100 /* Are we doing a chain (i.e. opt. of style 'tar xzf')? */
101 if(o_chain_ptr
!=NULL
){
106 o
=find_chain_opt(*p
, o_opts
);
109 RET(E_OPT_INVALID_CHAIN_OPTION
);
122 if(o_mode
!=OPTP_NO_DASH
)
123 RET(OPT_ID_ARGUMENT
);
125 }else if(*(p
+1)=='-'){
130 RET(OPT_ID_ARGUMENT
);
139 RET(OPT_ID_ARGUMENT
);
141 if(*(p
+2)!='\0' && o_mode
==OPTP_MIDLONG
)
151 /* Do long option (--foo=bar) */
154 l
=strlen(o
->longopt
);
155 if(strncmp(p2
, o
->longopt
, l
)!=0)
159 if(O_ARGS(o
)==OPT_ARG
)
160 RET(E_OPT_MISSING_ARGUMENT
);
162 }else if(p2
[l
]=='='){
164 RET(E_OPT_UNEXPECTED_ARGUMENT
);
166 RET(E_OPT_MISSING_ARGUMENT
);
172 }else if(type
==MIDLONG
){
176 if(strcmp(p2
, o
->longopt
)!=0)
178 }else{ /* type==SHORT */
179 if(*p2
!=(O_ID(o
)&~OPT_ID_RESERVED_FLAG
))
183 if(o_mode
==OPTP_CHAIN
|| o_mode
==OPTP_NO_DASH
){
184 /*valid_chain(p2+1, o_opts)*/
187 }else if(o_mode
==OPTP_IMMEDIATE
){
190 RET(E_OPT_UNEXPECTED_ARGUMENT
);
193 RET(E_OPT_MISSING_ARGUMENT
);
199 RET(E_OPT_SYNTAX_ERROR
);
209 if(!o_left
|| is_option(*o_current
)){
210 if(O_ARGS(o
)==OPT_OPT_ARG
)
212 RET(E_OPT_MISSING_ARGUMENT
);
220 RET(E_OPT_INVALID_OPTION
);
222 RET(OPT_ID_ARGUMENT
);
230 const char* optparser_get_arg()
235 /* If o_args_left==0, then were returning an invalid option
236 * otherwise an immediate argument (e.g. -funsigned-char
237 * where '-f' is the option and 'unsigned-char' the argument)
246 if(o_args_left
<1 || o_left
<1)
257 static void warn_arg(const char *e
)
259 const char *p
=optparser_get_arg();
262 warn("%s (null)", e
);
264 warn("%s \'%s\'", e
, p
);
268 static void warn_opt(const char *e
)
270 if(o_tmp
!=NULL
&& o_chain_ptr
!=NULL
)
271 warn("%s \'-%c\'", e
, *o_tmp
);
277 void optparser_print_error()
280 case E_OPT_INVALID_OPTION
:
281 case E_OPT_INVALID_CHAIN_OPTION
:
282 warn_opt(TR("Invalid option"));
285 case E_OPT_SYNTAX_ERROR
:
286 warn_arg(TR("Syntax error while parsing"));
289 case E_OPT_MISSING_ARGUMENT
:
290 warn_opt(TR("Missing argument to"));
293 case E_OPT_UNEXPECTED_ARGUMENT
:
294 warn_opt(TR("No argument expected:"));
297 case OPT_ID_ARGUMENT
:
298 warn(TR("Unexpected argument"));
302 warn(TR("(unknown error)"));
313 static uint
opt_w(const OptParserOpt
*opt
, bool midlong
)
317 if((opt
->optid
&OPT_ID_NOSHORT_FLAG
)==0){
319 if(opt
->longopt
!=NULL
)
323 if(opt
->longopt
!=NULL
)
324 w
+=strlen(opt
->longopt
)+(midlong
? 1 : 2);
327 if(opt
->argname
==NULL
)
330 w
+=1+strlen(opt
->argname
); /* "=ARG" or " ARG" */
346 static void print_opt(const OptParserOpt
*opt
, bool midlong
,
350 const char *p
, *p2
, *p3
;
357 if((O_ID(opt
)&OPT_ID_NOSHORT_FLAG
)==0){
358 fprintf(f
, "-%c", O_ID(opt
)&~OPT_ID_RESERVED_FLAG
);
361 if(opt
->longopt
!=NULL
){
369 if(opt
->longopt
!=NULL
){
372 fprintf(f
, "-%s", opt
->longopt
);
375 fprintf(f
, "--%s", opt
->longopt
);
377 w
+=strlen(opt
->longopt
);
384 if(opt
->longopt
!=NULL
&& !midlong
)
394 if(opt
->argname
!=NULL
){
395 fprintf(f
, "%s", opt
->argname
);
396 w
+=strlen(opt
->argname
);
426 while(*p2
!=' ' && p2
!=p
)
429 while(*p3
!=' ' && *p3
!='\0')
432 if((uint
)(p3
-p2
)>tw
){
433 /* long word - just wrap */
450 fprintf(f
, "%s\n", p
);
454 void optparser_printhelp(int mode
, const OptParserOpt
*opts
)
457 const OptParserOpt
*o
;
458 bool midlong
=mode
&OPTP_MIDLONG
;
470 print_opt(o
, midlong
, maxw
, TERM_W
);