Mercurial > hg > toybox
comparison lib/args.c @ 306:523441f8ed01
Teach option parsing logic that ^ means stop parsing after this option.
author | Rob Landley <rob@landley.net> |
---|---|
date | Thu, 03 Jul 2008 19:14:23 -0500 |
parents | 93223118c813 |
children | 4fb1fa3e6603 |
comparison
equal
deleted
inserted
replaced
305:b094b81830b0 | 306:523441f8ed01 |
---|---|
16 // * plus a string argument, appended to a list | 16 // * plus a string argument, appended to a list |
17 // # plus a signed long argument (TODO: Bounds checking?) | 17 // # plus a signed long argument (TODO: Bounds checking?) |
18 // @ plus an occurrence counter (which is a long) | 18 // @ plus an occurrence counter (which is a long) |
19 // (longopt) | 19 // (longopt) |
20 // | this is required. If more than one marked, only one required. | 20 // | this is required. If more than one marked, only one required. |
21 // ^ Stop parsing after encountering this argument | |
21 // | 22 // |
22 // These modify other option letters (previously seen in string): | 23 // These modify other option letters (previously seen in string): |
23 // +X enabling this enables X (switch on) | 24 // +X enabling this enables X (switch on) |
24 // ~X enabling this disables X (switch off) | 25 // ~X enabling this disables X (switch off) |
25 // !X die with error if X already set (x!x die if x supplied twice) | 26 // !X die with error if X already set (x!x die if x supplied twice) |
68 */ | 69 */ |
69 | 70 |
70 // Linked list of all known options (get_opt string is parsed into this). | 71 // Linked list of all known options (get_opt string is parsed into this). |
71 struct opts { | 72 struct opts { |
72 struct opts *next; | 73 struct opts *next; |
74 long *arg; // Pointer into union "this" to store arguments at. | |
73 uint32_t edx[3]; // Flag mask to enable/disable/exclude. | 75 uint32_t edx[3]; // Flag mask to enable/disable/exclude. |
74 long *arg; // Pointer into union this to store arguments at. | |
75 int c; // Short argument character | 76 int c; // Short argument character |
77 int flags; // |=1, ^=2 | |
76 char type; // Type of arguments to store | 78 char type; // Type of arguments to store |
77 }; | 79 }; |
78 | 80 |
79 // State during argument parsing. | 81 // State during argument parsing. |
80 struct getoptflagstate | 82 struct getoptflagstate |
81 { | 83 { |
82 int argc; | 84 int argc; |
83 char *arg; | 85 char *arg; |
84 struct opts *opts, *this; | 86 struct opts *opts, *this; |
85 int noerror, nodash_now; | 87 int noerror, nodash_now, stopearly; |
86 uint32_t excludes; | 88 uint32_t excludes; |
87 }; | 89 }; |
88 | 90 |
89 // Parse one command line option. | 91 // Parse one command line option. |
90 | 92 |
99 error_exit("Unknown option %s", gof->arg); | 101 error_exit("Unknown option %s", gof->arg); |
100 } | 102 } |
101 toys.optflags |= opt->edx[0]; | 103 toys.optflags |= opt->edx[0]; |
102 toys.optflags &= ~opt->edx[1]; | 104 toys.optflags &= ~opt->edx[1]; |
103 gof->excludes = opt->edx[2]; | 105 gof->excludes = opt->edx[2]; |
106 if (opt->flags&2) gof->stopearly=2; | |
104 | 107 |
105 // Does this option take an argument? | 108 // Does this option take an argument? |
106 gof->arg++; | 109 gof->arg++; |
107 type = opt->type; | 110 type = opt->type; |
108 if (type) { | 111 if (type) { |
140 // Fill out toys.optflags and toys.optargs. | 143 // Fill out toys.optflags and toys.optargs. |
141 | 144 |
142 static char *plustildenot = "+~!"; | 145 static char *plustildenot = "+~!"; |
143 void get_optflags(void) | 146 void get_optflags(void) |
144 { | 147 { |
145 int stopearly = 0, nodash = 0, minargs = 0, maxargs; | 148 int nodash = 0, minargs = 0, maxargs; |
146 struct longopts { | 149 struct longopts { |
147 struct longopts *next; | 150 struct longopts *next; |
148 struct opts *opt; | 151 struct opts *opt; |
149 char *str; | 152 char *str; |
150 int len; | 153 int len; |
165 // Parse option format | 168 // Parse option format |
166 if (options) { | 169 if (options) { |
167 | 170 |
168 // Parse leading special behavior indicators | 171 // Parse leading special behavior indicators |
169 for (;;) { | 172 for (;;) { |
170 if (*options == '^') stopearly++; | 173 if (*options == '^') gof.stopearly++; |
171 else if (*options == '<') minargs=*(++options)-'0'; | 174 else if (*options == '<') minargs=*(++options)-'0'; |
172 else if (*options == '>') maxargs=*(++options)-'0'; | 175 else if (*options == '>') maxargs=*(++options)-'0'; |
173 else if (*options == '?') gof.noerror++; | 176 else if (*options == '?') gof.noerror++; |
174 else if (*options == '&') nodash++; | 177 else if (*options == '&') nodash++; |
175 else break; | 178 else break; |
176 options++; | 179 options++; |
177 } | 180 } |
178 | 181 |
179 if (!*options) stopearly++; | 182 if (!*options) gof.stopearly++; |
180 // Parse rest of opts into array | 183 // Parse rest of opts into array |
181 while (*options) { | 184 while (*options) { |
182 char *temp; | 185 char *temp; |
183 | 186 |
184 // Allocate a new option entry when necessary | 187 // Allocate a new option entry when necessary |
228 i++; | 231 i++; |
229 } | 232 } |
230 gof.this->edx[idx] |= 1<<i; | 233 gof.this->edx[idx] |= 1<<i; |
231 | 234 |
232 } else if (*options == '[') { | 235 } else if (*options == '[') { |
233 } else if (*options == '|') { | 236 } else if (*options == '|') gof.this->flags |= 1; |
237 else if (*options == '^') gof.this->flags |= 2; | |
234 | 238 |
235 // At this point, we've hit the end of the previous option. The | 239 // At this point, we've hit the end of the previous option. The |
236 // current character is the start of a new option. If we've already | 240 // current character is the start of a new option. If we've already |
237 // assigned an option to this struct, loop to allocate a new one. | 241 // assigned an option to this struct, loop to allocate a new one. |
238 // (It'll get back here afterwards and fall through to next else.) | 242 // (It'll get back here afterwards and fall through to next else.) |
239 } else if(gof.this->c) { | 243 else if(gof.this->c) { |
240 gof.this = NULL; | 244 gof.this = NULL; |
241 continue; | 245 continue; |
242 | 246 |
243 // Claim this option, loop to see what's after it. | 247 // Claim this option, loop to see what's after it. |
244 } else gof.this->c = *options; | 248 } else gof.this->c = *options; |
266 for (gof.argc=1; toys.argv[gof.argc]; gof.argc++) { | 270 for (gof.argc=1; toys.argv[gof.argc]; gof.argc++) { |
267 gof.arg = toys.argv[gof.argc]; | 271 gof.arg = toys.argv[gof.argc]; |
268 gof.this = NULL; | 272 gof.this = NULL; |
269 | 273 |
270 // Parse this argument | 274 // Parse this argument |
271 if (stopearly>1) goto notflag; | 275 if (gof.stopearly>1) goto notflag; |
272 | 276 |
273 gof.nodash_now = 0; | 277 gof.nodash_now = 0; |
274 | 278 |
275 // Various things with dashes | 279 // Various things with dashes |
276 if (*gof.arg == '-') { | 280 if (*gof.arg == '-') { |
282 struct longopts *lo; | 286 struct longopts *lo; |
283 | 287 |
284 gof.arg++; | 288 gof.arg++; |
285 // Handle -- | 289 // Handle -- |
286 if (!*gof.arg) { | 290 if (!*gof.arg) { |
287 stopearly += 2; | 291 gof.stopearly += 2; |
288 goto notflag; | 292 goto notflag; |
289 } | 293 } |
290 // Handle --longopt | 294 // Handle --longopt |
291 | 295 |
292 for (lo = longopts; lo; lo = lo->next) { | 296 for (lo = longopts; lo; lo = lo->next) { |
338 } | 342 } |
339 continue; | 343 continue; |
340 | 344 |
341 // Not a flag, save value in toys.optargs[] | 345 // Not a flag, save value in toys.optargs[] |
342 notflag: | 346 notflag: |
343 if (stopearly) stopearly++; | 347 if (gof.stopearly) gof.stopearly++; |
344 toys.optargs[toys.optc++] = toys.argv[gof.argc]; | 348 toys.optargs[toys.optc++] = toys.argv[gof.argc]; |
345 } | 349 } |
346 | 350 |
347 // Sanity check | 351 // Sanity check |
348 if (toys.optc<minargs) { | 352 if (toys.optc<minargs) { |