|     14 #include "include/misc.h" | 
    14 #include "include/misc.h" | 
|     15 #include "include/optparser.h" | 
    15 #include "include/optparser.h" | 
|     16 #include "include/output.h" | 
    16 #include "include/output.h" | 
|     17  | 
    17  | 
|     18  | 
    18  | 
|     19 #define O_CHAINABLE(o)	(o->flags&OPT_CHAINABLE) | 
        | 
|     20 #define O_IMM_ARG(o)	(o->flags&OPT__IMM_ARG) | 
        | 
|     21 #define O_NO_DASH(o)	(o->flags&OPT_NO_DASH) | 
        | 
|     22 #define O_MIDLONG(o)	(o->flags&OPT_MIDLONG) | 
        | 
|     23 #define O_NO_LONG(o)	(o->flags&OPT_NO_LONG) | 
        | 
|     24 #define O_ARGS(o)		(o->flags&OPT_OPT_ARG) | 
    19 #define O_ARGS(o)		(o->flags&OPT_OPT_ARG) | 
|     25 #define O_ARG(o)		(o->flasg&OPT_ARG) | 
    20 #define O_ARG(o)		(o->flasg&OPT_ARG) | 
|     26 #define O_OPT_ARG(o)	(O_ARGS(o)==OPT_OPT_ARG) | 
    21 #define O_OPT_ARG(o)	(O_ARGS(o)==OPT_OPT_ARG) | 
|     27 #define O_ID(o)			(o->optid) | 
    22 #define O_ID(o)			(o->optid) | 
|     28  | 
    23  | 
|     32 static int o_left=0; | 
    27 static int o_left=0; | 
|     33 static const char* o_chain_ptr=NULL; | 
    28 static const char* o_chain_ptr=NULL; | 
|     34 static int o_args_left=0; | 
    29 static int o_args_left=0; | 
|     35 static const char*o_tmp=NULL; | 
    30 static const char*o_tmp=NULL; | 
|     36 static int o_error=0; | 
    31 static int o_error=0; | 
|     37  | 
    32 static int o_mode=OPTP_CHAIN; | 
|     38  | 
    33  | 
|     39 /* */ | 
    34  | 
|     40  | 
    35 /* */ | 
|     41  | 
    36  | 
|     42 void optparser_init(int argc, char *const argv[], const OptParserOpt *opts) | 
    37  | 
|     43 { | 
    38 void optparser_init(int argc, char *const argv[], int mode, | 
|         | 
    39 					const OptParserOpt *opts) | 
|         | 
    40 { | 
|         | 
    41 	o_mode=mode; | 
|     44 	o_opts=opts; | 
    42 	o_opts=opts; | 
|     45 	o_current=argv+1; | 
    43 	o_current=argv+1; | 
|     46 	o_left=argc-1; | 
    44 	o_left=argc-1; | 
|     47 	o_chain_ptr=NULL; | 
    45 	o_chain_ptr=NULL; | 
|     48 	o_args_left=0; | 
    46 	o_args_left=0; | 
|     54  | 
    52  | 
|     55  | 
    53  | 
|     56 static const OptParserOpt *find_chain_opt(char p, const OptParserOpt *o) | 
    54 static const OptParserOpt *find_chain_opt(char p, const OptParserOpt *o) | 
|     57 { | 
    55 { | 
|     58 	for(;O_ID(o);o++){ | 
    56 	for(;O_ID(o);o++){ | 
|     59 		if(O_CHAINABLE(o) && O_ID(o)==p) | 
    57 		if(O_ID(o)==p) | 
|     60 			return o; | 
    58 			return o; | 
|     61 	} | 
    59 	} | 
|     62 	return NULL; | 
    60 	return NULL; | 
|     63 } | 
    61 } | 
|     64  | 
    62  | 
|     65  | 
    63  | 
|     66 static bool valid_chain(const char *p, const OptParserOpt *o) | 
    64 /*static bool valid_chain(const char *p, const OptParserOpt *o) | 
|     67 { | 
    65 { | 
|     68 	while(*p!='\0'){ | 
    66 	while(*p!='\0'){ | 
|     69 		if(!find_chain_opt(*p, o)) | 
    67 		if(!find_chain_opt(*p, o)) | 
|     70 			return FALSE; | 
    68 			return FALSE; | 
|     71 		p++; | 
    69 		p++; | 
|     72 	} | 
    70 	} | 
|     73 	return TRUE; | 
    71 	return TRUE; | 
|     74 } | 
    72 }*/ | 
|     75 	 | 
    73 	 | 
|     76  | 
    74  | 
|     77 static bool is_option(const char *p) | 
    75 static bool is_option(const char *p) | 
|     78 { | 
    76 { | 
|     79 	 if(p==NULL) | 
    77 	 if(p==NULL) | 
|     88 } | 
    86 } | 
|     89 	 | 
    87 	 | 
|     90  | 
    88  | 
|     91 /* */ | 
    89 /* */ | 
|     92  | 
    90  | 
|         | 
    91 enum{ | 
|         | 
    92 	SHORT, MIDLONG, LONG | 
|         | 
    93 }; | 
|         | 
    94  | 
|     93  | 
    95  | 
|     94 int optparser_get_opt() | 
    96 int optparser_get_opt() | 
|     95 { | 
    97 { | 
|     96 #define RET(X) return o_tmp=p, o_error=X | 
    98 #define RET(X) return o_tmp=p, o_error=X | 
|     97 	const char *p, *p2=NULL; | 
    99 	const char *p, *p2=NULL; | 
|     98 	bool lo=FALSE, dash=TRUE; | 
   100 	bool dash=TRUE; | 
|         | 
   101 	int type=SHORT; | 
|     99 	const OptParserOpt *o; | 
   102 	const OptParserOpt *o; | 
|    100 	int l; | 
   103 	int l; | 
|    101  | 
   104  | 
|    102 	while(o_args_left) | 
   105 	while(o_args_left) | 
|    103 		optparser_get_arg(); | 
   106 		optparser_get_arg(); | 
|    104  | 
   107  | 
|    105 	o_tmp=NULL; | 
   108 	o_tmp=NULL; | 
|    106  | 
   109  | 
|    107 	/* Are we doing a chain (i.e. opt. of style 'tar xzf') ? */ | 
   110 	/* Are we doing a chain (i.e. opt. of style 'tar xzf')? */ | 
|    108 	if(o_chain_ptr!=NULL){ | 
   111 	if(o_chain_ptr!=NULL){ | 
|    109 		p=o_chain_ptr++; | 
   112 		p=o_chain_ptr++; | 
|    110 		if(!*o_chain_ptr) | 
   113 		if(!*o_chain_ptr) | 
|    111 			o_chain_ptr=NULL; | 
   114 			o_chain_ptr=NULL; | 
|    112  | 
   115  | 
|    123  | 
   126  | 
|    124 	o_left--; | 
   127 	o_left--; | 
|    125 	p=*o_current++; | 
   128 	p=*o_current++; | 
|    126 	 | 
   129 	 | 
|    127 	if(*p!='-'){ | 
   130 	if(*p!='-'){ | 
|    128 		/* foo */ | 
        | 
|    129 		dash=FALSE; | 
   131 		dash=FALSE; | 
|         | 
   132 		if(o_mode!=OPTP_NO_DASH) | 
|         | 
   133 			RET(OPT_ID_ARGUMENT); | 
|    130 	}else if(*(p+1)=='-'){ | 
   134 	}else if(*(p+1)=='-'){ | 
|    131 		/* --foo */ | 
   135 		/* --foo */ | 
|    132 		if(*(p+2)=='\0'){ | 
   136 		if(*(p+2)=='\0'){ | 
|    133 			/* -- */ | 
   137 			/* -- arguments */ | 
|    134 			o_args_left=o_left; | 
   138 			o_args_left=o_left; | 
|    135 			RET(OPT_ID_ARGUMENT); | 
   139 			RET(OPT_ID_ARGUMENT); | 
|    136 		} | 
   140 		} | 
|    137 		lo=TRUE; | 
   141 		/*argptr=strchr(p, '='); | 
|         | 
   142 		if(argptr!=NULL) | 
|         | 
   143 			argptr++; | 
|         | 
   144 		*/ | 
|         | 
   145 		type=LONG; | 
|    138 		p2=p+2; | 
   146 		p2=p+2; | 
|    139 	}else{ | 
   147 	}else{ | 
|    140 		/* -foo */ | 
   148 		/* -foo */ | 
|    141 		if(*(p+1)=='\0'){ | 
   149 		if(*(p+1)=='\0'){ | 
|    142 			/* - */ | 
   150 			/* - */ | 
|    143 			o_args_left=1; | 
   151 			o_args_left=1; | 
|    144 			RET(OPT_ID_ARGUMENT); | 
   152 			RET(OPT_ID_ARGUMENT); | 
|    145 		} | 
   153 		} | 
|         | 
   154 		if(*(p+2)!='\0' && o_mode==OPTP_MIDLONG) | 
|         | 
   155 			type=MIDLONG; | 
|         | 
   156 	 | 
|    146 		p2=p+1; | 
   157 		p2=p+1; | 
|    147 	} | 
   158 	} | 
|    148  | 
   159  | 
|    149 	o=o_opts; | 
   160 	o=o_opts; | 
|    150  | 
   161  | 
|    151 again: | 
   162 again: | 
|    152 	for(;O_ID(o);o++){ | 
   163 	for(;O_ID(o);o++){ | 
|    153 		if(lo){ | 
   164 		if(type==LONG){ | 
|    154 			/* Do long option (--foo=bar) */ | 
   165 			/* Do long option (--foo=bar) */ | 
|    155 			if(o->longopt==NULL) | 
   166 			if(o->longopt==NULL) | 
|    156 				continue; | 
   167 				continue; | 
|    157 			l=strlen(o->longopt); | 
   168 			l=strlen(o->longopt); | 
|    158 			if(strncmp(p2, o->longopt, l)!=0) | 
   169 			if(strncmp(p2, o->longopt, l)!=0) | 
|    159 				continue; | 
   170 				continue; | 
|    160 			 | 
   171 			 | 
|    161 			if(O_NO_LONG(o)) | 
        | 
|    162 				RET(E_OPT_INVALID_OPTION); | 
        | 
|    163  | 
        | 
|    164 			if(p2[l]=='\0'){ | 
   172 			if(p2[l]=='\0'){ | 
|    165 				if(O_ARGS(o)==OPT_ARG) | 
   173 				if(O_ARGS(o)==OPT_ARG) | 
|    166 					 RET(E_OPT_MISSING_ARGUMENT); | 
   174 					 RET(E_OPT_MISSING_ARGUMENT); | 
|    167 				return O_ID(o); | 
   175 				return O_ID(o); | 
|    168 			}else if(p2[l]=='='){ | 
   176 			}else if(p2[l]=='='){ | 
|    172 					 RET(E_OPT_MISSING_ARGUMENT); | 
   180 					 RET(E_OPT_MISSING_ARGUMENT); | 
|    173 				o_tmp=p2+l+1; | 
   181 				o_tmp=p2+l+1; | 
|    174 				o_args_left=1; | 
   182 				o_args_left=1; | 
|    175 				return O_ID(o); | 
   183 				return O_ID(o); | 
|    176 			} | 
   184 			} | 
|    177 		}else{ | 
   185 			continue; | 
|    178 			/* Do midlong option (-foobar) */ | 
   186 		}else if(type==MIDLONG){ | 
|    179 			if(dash && o->longopt!=NULL && strcmp(p2, o->longopt)==0){ | 
   187 			if(o->longopt==NULL) | 
|    180 				if(!O_MIDLONG(o)) | 
   188 				continue; | 
|    181 					 RET(E_OPT_INVALID_OPTION); | 
   189 			 | 
|    182 				goto do_arg; | 
   190 			if(strcmp(p2, o->longopt)!=0) | 
|    183 			} | 
   191 				continue; | 
|    184 	 | 
   192 		}else{ /* type==SHORT */ | 
|    185 			/* Do short option (-f) */ | 
   193 			if(*p2!=O_ID(o)) | 
|    186 			if((!dash && !O_NO_DASH(o)) || *p2!=O_ID(o)) | 
        | 
|    187 				continue; | 
   194 				continue; | 
|    188 			    | 
   195 			    | 
|    189 			if(*(p2+1)!='\0'){ | 
   196 			if(*(p2+1)!='\0'){ | 
|    190 				if(O_CHAINABLE(o) && valid_chain(p2+1, o_opts)){ | 
   197 				if(o_mode==OPTP_CHAIN || o_mode==OPTP_NO_DASH){ | 
|    191 					 o_chain_ptr=p2+1; | 
   198 					/*valid_chain(p2+1, o_opts)*/ | 
|    192 				}else if(O_IMM_ARG(o)){ | 
   199 					o_chain_ptr=p2+1; | 
|    193 					 o_tmp=p2+1; | 
   200 					p++; | 
|    194 					 o_args_left=1; | 
   201 				}else if(o_mode==OPTP_IMMEDIATE){ | 
|    195 					 return O_ID(o); | 
   202 					if(!O_ARGS(o)){ | 
|         | 
   203 						if(*(p2+1)!='\0') | 
|         | 
   204 							RET(E_OPT_UNEXPECTED_ARGUMENT); | 
|         | 
   205 					}else{ | 
|         | 
   206 						if(*(p2+1)=='\0') | 
|         | 
   207 							RET(E_OPT_MISSING_ARGUMENT); | 
|         | 
   208 						o_tmp=p2+1; | 
|         | 
   209 						o_args_left=1; | 
|         | 
   210 					} | 
|         | 
   211 					return O_ID(o); | 
|    196 				}else{ | 
   212 				}else{ | 
|    197 					 continue; | 
   213 					RET(E_OPT_SYNTAX_ERROR); | 
|    198 				} | 
   214 				} | 
|    199 			} | 
   215 			} | 
|    200 do_arg: | 
   216 		} | 
|    201 			if(!O_ARGS(o)) | 
   217 		 | 
|         | 
   218 	do_arg: | 
|         | 
   219 		 | 
|         | 
   220 		if(!O_ARGS(o)) | 
|         | 
   221 			return O_ID(o); | 
|         | 
   222 		 | 
|         | 
   223 		if(!o_left || is_option(*o_current)){ | 
|         | 
   224 			if(O_ARGS(o)==OPT_OPT_ARG) | 
|    202 				return O_ID(o); | 
   225 				return O_ID(o); | 
|    203 			    | 
   226 			RET(E_OPT_MISSING_ARGUMENT); | 
|    204 			if(O_ARGS(o)==OPT_ARG){ | 
        | 
|    205 				if(o_left==0) | 
        | 
|    206 					 RET(E_OPT_MISSING_ARGUMENT); | 
        | 
|    207 			}else{ | 
        | 
|    208 				if(!o_left || is_option(*o_current)) | 
        | 
|    209 					 return O_ID(o); | 
        | 
|    210 			} | 
        | 
|    211  | 
        | 
|    212 			o_args_left=1; | 
        | 
|    213 			return O_ID(o); | 
        | 
|    214 		} | 
   227 		} | 
|         | 
   228  | 
|         | 
   229 		o_args_left=1; | 
|         | 
   230 		return O_ID(o); | 
|    215 	} | 
   231 	} | 
|    216  | 
   232  | 
|    217 	if(dash) | 
   233 	if(dash) | 
|    218 		RET(E_OPT_INVALID_OPTION); | 
   234 		RET(E_OPT_INVALID_OPTION); | 
|    219 	 | 
   235 	 | 
|    252  | 
   268  | 
|    253 /* */ | 
   269 /* */ | 
|    254  | 
   270  | 
|    255 static void warn_arg(const char *e) | 
   271 static void warn_arg(const char *e) | 
|    256 { | 
   272 { | 
|    257 	const char*p=optparser_get_arg(); | 
   273 	const char *p=optparser_get_arg(); | 
|    258 	 | 
   274 	 | 
|    259 	if(p==NULL) | 
   275 	if(p==NULL) | 
|    260 		warn("%s (null)", e); | 
   276 		warn("%s (null)", e); | 
|    261 	else | 
   277 	else | 
|    262 		warn("%s \'%s\'", e, p); | 
   278 		warn("%s \'%s\'", e, p); | 
|    263 } | 
   279 } | 
|    264  | 
   280  | 
|    265  | 
   281  | 
|    266 static void warn_opt(const char *e) | 
   282 static void warn_opt(const char *e) | 
|    267 { | 
   283 { | 
|    268 	if(o_chain_ptr!=NULL && o_tmp!=NULL) | 
   284 	if(o_tmp!=NULL && o_chain_ptr!=NULL) | 
|    269 		warn("%s \'-%c\'", e, *o_tmp); | 
   285 		warn("%s \'-%c\'", e, *o_tmp); | 
|    270 	else | 
   286 	else | 
|    271 		warn_arg(e); | 
   287 		warn_arg(e); | 
|    272 } | 
   288 } | 
|    273  | 
   289  | 
|    274  | 
   290  | 
|    275 void optparser_print_error() | 
   291 void optparser_print_error() | 
|    276 { | 
   292 { | 
|    277 	switch(o_error){ | 
   293 	switch(o_error){ | 
|    278 	case E_OPT_INVALID_OPTION: | 
   294 	case E_OPT_INVALID_OPTION: | 
|         | 
   295 	case E_OPT_INVALID_CHAIN_OPTION: | 
|    279 		warn_opt(TR("Invalid option")); | 
   296 		warn_opt(TR("Invalid option")); | 
|    280 		break; | 
   297 		break; | 
|    281  | 
        | 
|    282 	case E_OPT_INVALID_CHAIN_OPTION: | 
        | 
|    283 		warn_opt(TR("Invalid option in chain (this cannot happen)")); | 
        | 
|    284 		break;		 | 
        | 
|    285  | 
   298  | 
|    286 	case E_OPT_SYNTAX_ERROR: | 
   299 	case E_OPT_SYNTAX_ERROR: | 
|    287 		warn_arg(TR("Syntax error while parsing")); | 
   300 		warn_arg(TR("Syntax error while parsing")); | 
|    288 		break; | 
   301 		break; | 
|    289 				  | 
   302 				  | 
|    290 	case E_OPT_MISSING_ARGUMENT: | 
   303 	case E_OPT_MISSING_ARGUMENT: | 
|    291 		warn_opt(TR("Missing argument to")); | 
   304 		warn_opt(TR("Missing argument to")); | 
|    292 		break; | 
   305 		break; | 
|    293  | 
   306  | 
|    294 	case E_OPT_UNEXPECTED_ARGUMENT: | 
   307 	case E_OPT_UNEXPECTED_ARGUMENT: | 
|    295 		warn_opt(TR("No argument expected to")); | 
   308 		warn_opt(TR("No argument expected:")); | 
|    296 		break; | 
   309 		break; | 
|    297 		 | 
   310 		 | 
|    298 	case OPT_ID_ARGUMENT: | 
   311 	case OPT_ID_ARGUMENT: | 
|    299 		warn(TR("Unexpected argument")); | 
   312 		warn(TR("Unexpected argument")); | 
|    300 		break; | 
   313 		break; |