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