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);