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