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