8df787b383c196d8ee7c7a06c73f64ca937cd93a
[platform/upstream/isl.git] / isl_arg.c
1 /*
2  * Copyright 2008-2009 Katholieke Universiteit Leuven
3  *
4  * Use of this software is governed by the GNU LGPLv2.1 license
5  *
6  * Written by Sven Verdoolaege, K.U.Leuven, Departement
7  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include <isl/arg.h>
15 #include <isl/ctx.h>
16
17 static struct isl_arg help_arg[] = {
18 ISL_ARG_PHANTOM_BOOL('h', "help", NULL, "print this help, then exit")
19 ISL_ARG_END
20 };
21
22 static void set_default_choice(struct isl_arg *arg, void *opt)
23 {
24         *(unsigned *)(((char *)opt) + arg->offset) = arg->u.choice.default_value;
25 }
26
27 static void set_default_flags(struct isl_arg *arg, void *opt)
28 {
29         *(unsigned *)(((char *)opt) + arg->offset) = arg->u.flags.default_value;
30 }
31
32 static void set_default_bool(struct isl_arg *arg, void *opt)
33 {
34         if (arg->offset == (size_t) -1)
35                 return;
36         *(unsigned *)(((char *)opt) + arg->offset) = arg->u.b.default_value;
37 }
38
39 static void set_default_child(struct isl_arg *arg, void *opt)
40 {
41         void *child = calloc(1, arg->u.child.size);
42
43         if (child)
44                 isl_arg_set_defaults(arg->u.child.child, child);
45
46         *(void **)(((char *)opt) + arg->offset) = child;
47 }
48
49 static void set_default_user(struct isl_arg *arg, void *opt)
50 {
51         arg->u.user.init(((char *)opt) + arg->offset);
52 }
53
54 static void set_default_int(struct isl_arg *arg, void *opt)
55 {
56         *(int *)(((char *)opt) + arg->offset) = arg->u.i.default_value;
57 }
58
59 static void set_default_long(struct isl_arg *arg, void *opt)
60 {
61         *(long *)(((char *)opt) + arg->offset) = arg->u.l.default_value;
62 }
63
64 static void set_default_ulong(struct isl_arg *arg, void *opt)
65 {
66         *(unsigned long *)(((char *)opt) + arg->offset) = arg->u.ul.default_value;
67 }
68
69 static void set_default_str(struct isl_arg *arg, void *opt)
70 {
71         const char *str = NULL;
72         if (arg->u.str.default_value)
73                 str = strdup(arg->u.str.default_value);
74         *(const char **)(((char *)opt) + arg->offset) = str;
75 }
76
77 void isl_arg_set_defaults(struct isl_arg *arg, void *opt)
78 {
79         int i;
80
81         for (i = 0; arg[i].type != isl_arg_end; ++i) {
82                 switch (arg[i].type) {
83                 case isl_arg_choice:
84                         set_default_choice(&arg[i], opt);
85                         break;
86                 case isl_arg_flags:
87                         set_default_flags(&arg[i], opt);
88                         break;
89                 case isl_arg_bool:
90                         set_default_bool(&arg[i], opt);
91                         break;
92                 case isl_arg_child:
93                         set_default_child(&arg[i], opt);
94                         break;
95                 case isl_arg_user:
96                         set_default_user(&arg[i], opt);
97                         break;
98                 case isl_arg_int:
99                         set_default_int(&arg[i], opt);
100                         break;
101                 case isl_arg_long:
102                         set_default_long(&arg[i], opt);
103                         break;
104                 case isl_arg_ulong:
105                         set_default_ulong(&arg[i], opt);
106                         break;
107                 case isl_arg_arg:
108                 case isl_arg_str:
109                         set_default_str(&arg[i], opt);
110                         break;
111                 case isl_arg_alias:
112                 case isl_arg_version:
113                 case isl_arg_end:
114                         break;
115                 }
116         }
117 }
118
119 void isl_arg_free(struct isl_arg *arg, void *opt)
120 {
121         int i;
122
123         if (!opt)
124                 return;
125
126         for (i = 0; arg[i].type != isl_arg_end; ++i) {
127                 switch (arg[i].type) {
128                 case isl_arg_child:
129                         isl_arg_free(arg[i].u.child.child,
130                                 *(void **)(((char *)opt) + arg[i].offset));
131                         break;
132                 case isl_arg_arg:
133                 case isl_arg_str:
134                         free(*(char **)(((char *)opt) + arg[i].offset));
135                         break;
136                 case isl_arg_user:
137                         if (arg[i].u.user.clear)
138                                 arg[i].u.user.clear(((char *)opt) + arg[i].offset);
139                         break;
140                 case isl_arg_alias:
141                 case isl_arg_bool:
142                 case isl_arg_choice:
143                 case isl_arg_flags:
144                 case isl_arg_int:
145                 case isl_arg_long:
146                 case isl_arg_ulong:
147                 case isl_arg_version:
148                 case isl_arg_end:
149                         break;
150                 }
151         }
152
153         free(opt);
154 }
155
156 static int print_arg_help(struct isl_arg *decl, const char *prefix, int no)
157 {
158         int len = 0;
159
160         if (!decl->long_name) {
161                 printf("  -%c", decl->short_name);
162                 return 4;
163         }
164
165         if (decl->short_name) {
166                 printf("  -%c, --", decl->short_name);
167                 len += 8;
168         } else if (decl->flags & ISL_ARG_SINGLE_DASH) {
169                 printf("  -");
170                 len += 3;
171         } else {
172                 printf("      --");
173                 len += 8;
174         }
175
176         if (prefix) {
177                 printf("%s-", prefix);
178                 len += strlen(prefix) + 1;
179         }
180         if (no) {
181                 printf("no-");
182                 len += 3;
183         }
184         printf("%s", decl->long_name);
185         len += strlen(decl->long_name);
186
187         while ((++decl)->type == isl_arg_alias) {
188                 printf(", --");
189                 len += 4;
190                 if (no) {
191                         printf("no-");
192                         len += 3;
193                 }
194                 printf("%s", decl->long_name);
195                 len += strlen(decl->long_name);
196         }
197
198         return len;
199 }
200
201 const void *isl_memrchr(const void *s, int c, size_t n)
202 {
203         const char *p = s;
204         while (n-- > 0)
205                 if (p[n] == c)
206                         return p + n;
207         return NULL;
208 }
209
210 static int print_help_msg(struct isl_arg *decl, int pos)
211 {
212         int len;
213         const char *s;
214
215         if (!decl->help_msg)
216                 return pos;
217
218         if (pos >= 29)
219                 printf("\n%30s", "");
220         else
221                 printf("%*s", 30 - pos, "");
222
223         s = decl->help_msg;
224         len = strlen(s);
225         while (len > 45) {
226                 const char *space = isl_memrchr(s, ' ', 45);
227                 int l;
228
229                 if (!space)
230                         space = strchr(s + 45, ' ');
231                 if (!space)
232                         break;
233                 l = space - s;
234                 printf("%.*s", l, s);
235                 s = space + 1;
236                 len -= l + 1;
237                 printf("\n%30s", "");
238         }
239
240         printf("%s", s);
241         return len;
242 }
243
244 static void print_default(struct isl_arg *decl, const char *def, int pos)
245 {
246         int i;
247         const char *default_prefix = "[default: ";
248         const char *default_suffix = "]";
249         int len;
250
251         len = strlen(default_prefix) + strlen(def) + strlen(default_suffix);
252
253         if (!decl->help_msg) {
254                 if (pos >= 29)
255                         printf("\n%30s", "");
256                 else
257                         printf("%*s", 30 - pos, "");
258                 pos = 0;
259         } else {
260                 if (pos + len >= 48)
261                         printf("\n%30s", "");
262                 else
263                         printf(" ");
264         }
265         printf("%s%s%s", default_prefix, def, default_suffix);
266 }
267
268 static void print_default_choice(struct isl_arg *decl, int pos)
269 {
270         int i;
271         const char *s = "none";
272
273         for (i = 0; decl->u.choice.choice[i].name; ++i)
274                 if (decl->u.choice.choice[i].value == decl->u.choice.default_value) {
275                         s = decl->u.choice.choice[i].name;
276                         break;
277                 }
278
279         print_default(decl, s, pos);
280 }
281
282 static void print_choice_help(struct isl_arg *decl, const char *prefix)
283 {
284         int i;
285         int pos;
286
287         pos = print_arg_help(decl, prefix, 0);
288         printf("=");
289         pos++;
290
291         for (i = 0; decl->u.choice.choice[i].name; ++i) {
292                 if (i) {
293                         printf("|");
294                         pos++;
295                 }
296                 printf("%s", decl->u.choice.choice[i].name);
297                 pos += strlen(decl->u.choice.choice[i].name);
298         }
299
300         pos = print_help_msg(decl, pos);
301         print_default_choice(decl, pos);
302
303         printf("\n");
304 }
305
306 static void print_default_flags(struct isl_arg *decl, int pos)
307 {
308         int i, first;
309         const char *default_prefix = "[default: ";
310         const char *default_suffix = "]";
311         int len = strlen(default_prefix) + strlen(default_suffix);
312
313         for (i = 0; decl->u.flags.flags[i].name; ++i)
314                 if ((decl->u.flags.default_value & decl->u.flags.flags[i].mask) ==
315                      decl->u.flags.flags[i].value)
316                         len += strlen(decl->u.flags.flags[i].name);
317
318         if (!decl->help_msg) {
319                 if (pos >= 29)
320                         printf("\n%30s", "");
321                 else
322                         printf("%*s", 30 - pos, "");
323                 pos = 0;
324         } else {
325                 if (pos + len >= 48)
326                         printf("\n%30s", "");
327                 else
328                         printf(" ");
329         }
330         printf("%s", default_prefix);
331
332         for (first = 1, i = 0; decl->u.flags.flags[i].name; ++i)
333                 if ((decl->u.flags.default_value & decl->u.flags.flags[i].mask) ==
334                      decl->u.flags.flags[i].value) {
335                         if (!first)
336                                 printf(",");
337                         printf("%s", decl->u.flags.flags[i].name);
338                         first = 0;
339                 }
340
341         printf("%s", default_suffix);
342 }
343
344 static void print_flags_help(struct isl_arg *decl, const char *prefix)
345 {
346         int i, j;
347         int pos;
348
349         pos = print_arg_help(decl, prefix, 0);
350         printf("=");
351         pos++;
352
353         for (i = 0; decl->u.flags.flags[i].name; ++i) {
354                 if (i) {
355                         printf(",");
356                         pos++;
357                 }
358                 for (j = i;
359                      decl->u.flags.flags[j].mask == decl->u.flags.flags[i].mask;
360                      ++j) {
361                         if (j != i) {
362                                 printf("|");
363                                 pos++;
364                         }
365                         printf("%s", decl->u.flags.flags[j].name);
366                         pos += strlen(decl->u.flags.flags[j].name);
367                 }
368                 i = j - 1;
369         }
370
371         pos = print_help_msg(decl, pos);
372         print_default_flags(decl, pos);
373
374         printf("\n");
375 }
376
377 static void print_bool_help(struct isl_arg *decl, const char *prefix)
378 {
379         int pos;
380         int no = decl->u.b.default_value == 1;
381         pos = print_arg_help(decl, prefix, no);
382         pos = print_help_msg(decl, pos);
383         if (decl->offset != (size_t) -1)
384                 print_default(decl, no ? "yes" : "no", pos);
385         printf("\n");
386 }
387
388 static int print_argument_name(struct isl_arg *decl, const char *name, int pos)
389 {
390         printf("%c<%s>", decl->long_name ? '=' : ' ', name);
391         return pos + 3 + strlen(name);
392 }
393
394 static void print_int_help(struct isl_arg *decl, const char *prefix)
395 {
396         int pos;
397         char val[20];
398         pos = print_arg_help(decl, prefix, 0);
399         pos = print_argument_name(decl, decl->argument_name, pos);
400         pos = print_help_msg(decl, pos);
401         snprintf(val, sizeof(val), "%d", decl->u.i.default_value);
402         print_default(decl, val, pos);
403         printf("\n");
404 }
405
406 static void print_long_help(struct isl_arg *decl, const char *prefix)
407 {
408         int pos;
409         pos = print_arg_help(decl, prefix, 0);
410         if (decl->u.l.default_value != decl->u.l.default_selected) {
411                 printf("[");
412                 pos++;
413         }
414         printf("=long");
415         pos += 5;
416         if (decl->u.l.default_value != decl->u.l.default_selected) {
417                 printf("]");
418                 pos++;
419         }
420         print_help_msg(decl, pos);
421         printf("\n");
422 }
423
424 static void print_ulong_help(struct isl_arg *decl, const char *prefix)
425 {
426         int pos;
427         pos = print_arg_help(decl, prefix, 0);
428         printf("=ulong");
429         pos += 6;
430         print_help_msg(decl, pos);
431         printf("\n");
432 }
433
434 static void print_str_help(struct isl_arg *decl, const char *prefix)
435 {
436         int pos;
437         const char *a = decl->argument_name ? decl->argument_name : "string";
438         pos = print_arg_help(decl, prefix, 0);
439         pos = print_argument_name(decl, a, pos);
440         pos = print_help_msg(decl, pos);
441         if (decl->u.str.default_value)
442                 print_default(decl, decl->u.str.default_value, pos);
443         printf("\n");
444 }
445
446 static void print_help(struct isl_arg *arg, const char *prefix)
447 {
448         int i;
449
450         for (i = 0; arg[i].type != isl_arg_end; ++i) {
451                 if (arg[i].flags & ISL_ARG_HIDDEN)
452                         continue;
453                 switch (arg[i].type) {
454                 case isl_arg_flags:
455                         print_flags_help(&arg[i], prefix);
456                         break;
457                 case isl_arg_choice:
458                         print_choice_help(&arg[i], prefix);
459                         break;
460                 case isl_arg_bool:
461                         print_bool_help(&arg[i], prefix);
462                         break;
463                 case isl_arg_int:
464                         print_int_help(&arg[i], prefix);
465                         break;
466                 case isl_arg_long:
467                         print_long_help(&arg[i], prefix);
468                         break;
469                 case isl_arg_ulong:
470                         print_ulong_help(&arg[i], prefix);
471                         break;
472                 case isl_arg_str:
473                         print_str_help(&arg[i], prefix);
474                         break;
475                 case isl_arg_alias:
476                 case isl_arg_version:
477                 case isl_arg_arg:
478                 case isl_arg_child:
479                 case isl_arg_user:
480                 case isl_arg_end:
481                         break;
482                 }
483         }
484
485         for (i = 0; arg[i].type != isl_arg_end; ++i) {
486                 if (arg[i].type != isl_arg_child)
487                         continue;
488                 if (arg[i].flags & ISL_ARG_HIDDEN)
489                         continue;
490
491                 printf("\n");
492                 if (arg[i].help_msg)
493                         printf(" %s\n", arg[i].help_msg);
494                 print_help(arg[i].u.child.child, arg[i].long_name);
495         }
496 }
497
498 static const char *prog_name(const char *prog)
499 {
500         const char *slash;
501
502         slash = strrchr(prog, '/');
503         if (slash)
504                 prog = slash + 1;
505         if (strncmp(prog, "lt-", 3) == 0)
506                 prog += 3;
507
508         return prog;
509 }
510
511 static int any_version(struct isl_arg *decl)
512 {
513         int i;
514
515         for (i = 0; decl[i].type != isl_arg_end; ++i) {
516                 switch (decl[i].type) {
517                 case isl_arg_version:
518                         return 1;
519                 case isl_arg_child:
520                         if (any_version(decl[i].u.child.child))
521                                 return 1;
522                         break;
523                 default:
524                         break;
525                 }
526         }
527
528         return 0;
529 }
530
531 static void print_help_and_exit(struct isl_arg *arg, const char *prog)
532 {
533         int i;
534
535         printf("Usage: %s [OPTION...]", prog_name(prog));
536
537         for (i = 0; arg[i].type != isl_arg_end; ++i)
538                 if (arg[i].type == isl_arg_arg)
539                         printf(" %s", arg[i].argument_name);
540
541         printf("\n\n");
542
543         print_help(arg, NULL);
544         printf("\n");
545         if (any_version(arg))
546                 printf("  -V, --version\n");
547         print_bool_help(help_arg, NULL);
548
549         exit(0);
550 }
551
552 static int match_long_name(struct isl_arg *decl,
553         const char *start, const char *end)
554 {
555         do {
556                 if (end - start == strlen(decl->long_name) &&
557                     !strncmp(start, decl->long_name, end - start))
558                         return 1;
559         } while ((++decl)->type == isl_arg_alias);
560
561         return 0;
562 }
563
564 static const char *skip_dash_dash(struct isl_arg *decl, const char *arg)
565 {
566         if (!strncmp(arg, "--", 2))
567                 return arg + 2;
568         if ((decl->flags & ISL_ARG_SINGLE_DASH) && arg[0] == '-')
569                 return arg + 1;
570         return NULL;
571 }
572
573 static const char *skip_name(struct isl_arg *decl, const char *arg,
574         const char *prefix, int need_argument, int *has_argument)
575 {
576         const char *equal;
577         const char *name;
578         const char *end;
579
580         if (arg[0] == '-' && arg[1] && arg[1] == decl->short_name) {
581                 if (need_argument && !arg[2])
582                         return NULL;
583                 if (has_argument)
584                         *has_argument = arg[2] != '\0';
585                 return arg + 2;
586         }
587         if (!decl->long_name)
588                 return NULL;
589
590         name = skip_dash_dash(decl, arg);
591         if (!name)
592                 return NULL;
593
594         equal = strchr(name, '=');
595         if (need_argument && !equal)
596                 return NULL;
597
598         if (has_argument)
599                 *has_argument = !!equal;
600         end = equal ? equal : name + strlen(name);
601
602         if (prefix) {
603                 size_t prefix_len = strlen(prefix);
604                 if (strncmp(name, prefix, prefix_len) == 0 &&
605                     name[prefix_len] == '-')
606                         name += prefix_len + 1;
607         }
608
609         if (!match_long_name(decl, name, end))
610                 return NULL;
611
612         return equal ? equal + 1 : end;
613 }
614
615 static int parse_choice_option(struct isl_arg *decl, char **arg,
616         const char *prefix, void *opt)
617 {
618         int i;
619         int has_argument;
620         const char *choice;
621
622         choice = skip_name(decl, arg[0], prefix, 0, &has_argument);
623         if (!choice)
624                 return 0;
625
626         if (!has_argument && (!arg[1] || arg[1][0] == '-')) {
627                 unsigned u = decl->u.choice.default_selected;
628                 if (decl->u.choice.set)
629                         decl->u.choice.set(opt, u);
630                 else
631                         *(unsigned *)(((char *)opt) + decl->offset) = u;
632
633                 return 1;
634         }
635
636         if (!has_argument)
637                 choice = arg[1];
638
639         for (i = 0; decl->u.choice.choice[i].name; ++i) {
640                 unsigned u;
641
642                 if (strcmp(choice, decl->u.choice.choice[i].name))
643                         continue;
644
645                 u = decl->u.choice.choice[i].value;
646                 if (decl->u.choice.set)
647                         decl->u.choice.set(opt, u);
648                 else
649                         *(unsigned *)(((char *)opt) + decl->offset) = u;
650
651                 return has_argument ? 1 : 2;
652         }
653
654         return 0;
655 }
656
657 static int set_flag(struct isl_arg *decl, unsigned *val, const char *flag,
658         size_t len)
659 {
660         int i;
661
662         for (i = 0; decl->u.flags.flags[i].name; ++i) {
663                 if (strncmp(flag, decl->u.flags.flags[i].name, len))
664                         continue;
665
666                 *val &= ~decl->u.flags.flags[i].mask;
667                 *val |= decl->u.flags.flags[i].value;
668
669                 return 1;
670         }
671
672         return 0;
673 }
674
675 static int parse_flags_option(struct isl_arg *decl, char **arg,
676         const char *prefix, void *opt)
677 {
678         int has_argument;
679         const char *flags;
680         const char *comma;
681         unsigned val;
682
683         flags = skip_name(decl, arg[0], prefix, 0, &has_argument);
684         if (!flags)
685                 return 0;
686
687         if (!has_argument && !arg[1])
688                 return 0;
689
690         if (!has_argument)
691                 flags = arg[1];
692
693         val = *(unsigned *)(((char *)opt) + decl->offset);
694
695         while ((comma = strchr(flags, ',')) != NULL) {
696                 if (!set_flag(decl, &val, flags, comma - flags))
697                         return 0;
698                 flags = comma + 1;
699         }
700         if (!set_flag(decl, &val, flags, strlen(flags)))
701                 return 0;
702
703         *(unsigned *)(((char *)opt) + decl->offset) = val;
704
705         return has_argument ? 1 : 2;
706 }
707
708 static int parse_bool_option(struct isl_arg *decl, char **arg,
709         const char *prefix, void *opt)
710 {
711         const char *name;
712         unsigned *p = (unsigned *)(((char *)opt) + decl->offset);
713
714         if (skip_name(decl, arg[0], prefix, 0, NULL)) {
715                 if ((decl->flags && ISL_ARG_BOOL_ARG) && arg[1]) {
716                         char *endptr;
717                         int val = strtol(arg[1], &endptr, 0);
718                         if (*endptr == '\0' && (val == 0 || val == 1)) {
719                                 if (decl->u.b.set)
720                                         decl->u.b.set(opt, val);
721                                 else if (decl->offset != (size_t) -1)
722                                         *p = val;
723                                 return 2;
724                         }
725                 }
726                 if (decl->u.b.set)
727                         decl->u.b.set(opt, 1);
728                 else if (decl->offset != (size_t) -1)
729                         *p = 1;
730
731                 return 1;
732         }
733
734         if (!decl->long_name)
735                 return 0;
736
737         name = skip_dash_dash(decl, arg[0]);
738         if (!name)
739                 return 0;
740
741         if (prefix) {
742                 size_t prefix_len = strlen(prefix);
743                 if (strncmp(name, prefix, prefix_len) == 0 &&
744                     name[prefix_len] == '-') {
745                         name += prefix_len + 1;
746                         prefix = NULL;
747                 }
748         }
749
750         if (strncmp(name, "no-", 3))
751                 return 0;
752         name += 3;
753
754         if (prefix) {
755                 size_t prefix_len = strlen(prefix);
756                 if (strncmp(name, prefix, prefix_len) == 0 &&
757                     name[prefix_len] == '-')
758                         name += prefix_len + 1;
759         }
760
761         if (match_long_name(decl, name, name + strlen(name))) {
762                 if (decl->u.b.set)
763                         decl->u.b.set(opt, 0);
764                 else if (decl->offset != (size_t) -1)
765                         *p = 0;
766
767                 return 1;
768         }
769
770         return 0;
771 }
772
773 static int parse_str_option(struct isl_arg *decl, char **arg,
774         const char *prefix, void *opt)
775 {
776         int has_argument;
777         const char *s;
778         char **p = (char **)(((char *)opt) + decl->offset);
779
780         s = skip_name(decl, arg[0], prefix, 0, &has_argument);
781         if (!s)
782                 return 0;
783
784         if (has_argument) {
785                 free(*p);
786                 *p = strdup(s);
787                 return 1;
788         }
789
790         if (arg[1]) {
791                 free(*p);
792                 *p = strdup(arg[1]);
793                 return 2;
794         }
795
796         return 0;
797 }
798
799 static int parse_int_option(struct isl_arg *decl, char **arg,
800         const char *prefix, void *opt)
801 {
802         int has_argument;
803         const char *val;
804         char *endptr;
805         int *p = (int *)(((char *)opt) + decl->offset);
806
807         val = skip_name(decl, arg[0], prefix, 0, &has_argument);
808         if (!val)
809                 return 0;
810
811         if (has_argument) {
812                 *p = atoi(val);
813                 return 1;
814         }
815
816         if (arg[1]) {
817                 int i = strtol(arg[1], &endptr, 0);
818                 if (*endptr == '\0') {
819                         *p = i;
820                         return 2;
821                 }
822         }
823
824         return 0;
825 }
826
827 static int parse_long_option(struct isl_arg *decl, char **arg,
828         const char *prefix, void *opt)
829 {
830         int has_argument;
831         const char *val;
832         char *endptr;
833         long *p = (long *)(((char *)opt) + decl->offset);
834
835         val = skip_name(decl, arg[0], prefix, 0, &has_argument);
836         if (!val)
837                 return 0;
838
839         if (has_argument) {
840                 long l = strtol(val, NULL, 0);
841                 if (decl->u.l.set)
842                         decl->u.l.set(opt, l);
843                 else
844                         *p = l;
845                 return 1;
846         }
847
848         if (arg[1]) {
849                 long l = strtol(arg[1], &endptr, 0);
850                 if (*endptr == '\0') {
851                         if (decl->u.l.set)
852                                 decl->u.l.set(opt, l);
853                         else
854                                 *p = l;
855                         return 2;
856                 }
857         }
858
859         if (decl->u.l.default_value != decl->u.l.default_selected) {
860                 if (decl->u.l.set)
861                         decl->u.l.set(opt, decl->u.l.default_selected);
862                 else
863                         *p = decl->u.l.default_selected;
864                 return 1;
865         }
866
867         return 0;
868 }
869
870 static int parse_ulong_option(struct isl_arg *decl, char **arg,
871         const char *prefix, void *opt)
872 {
873         int has_argument;
874         const char *val;
875         char *endptr;
876         unsigned long *p = (unsigned long *)(((char *)opt) + decl->offset);
877
878         val = skip_name(decl, arg[0], prefix, 0, &has_argument);
879         if (!val)
880                 return 0;
881
882         if (has_argument) {
883                 *p = strtoul(val, NULL, 0);
884                 return 1;
885         }
886
887         if (arg[1]) {
888                 unsigned long ul = strtoul(arg[1], &endptr, 0);
889                 if (*endptr == '\0') {
890                         *p = ul;
891                         return 2;
892                 }
893         }
894
895         return 0;
896 }
897
898 static int parse_option(struct isl_arg *decl, char **arg,
899         const char *prefix, void *opt);
900
901 static int parse_child_option(struct isl_arg *decl, char **arg, void *opt)
902 {
903         return parse_option(decl->u.child.child, arg, decl->long_name,
904                                 *(void **)(((char *)opt) + decl->offset));
905 }
906
907 static int parse_option(struct isl_arg *decl, char **arg,
908         const char *prefix, void *opt)
909 {
910         int i;
911
912         for (i = 0; decl[i].type != isl_arg_end; ++i) {
913                 int parsed = 0;
914                 switch (decl[i].type) {
915                 case isl_arg_choice:
916                         parsed = parse_choice_option(&decl[i], arg, prefix, opt);
917                         break;
918                 case isl_arg_flags:
919                         parsed = parse_flags_option(&decl[i], arg, prefix, opt);
920                         break;
921                 case isl_arg_int:
922                         parsed = parse_int_option(&decl[i], arg, prefix, opt);
923                         break;
924                 case isl_arg_long:
925                         parsed = parse_long_option(&decl[i], arg, prefix, opt);
926                         break;
927                 case isl_arg_ulong:
928                         parsed = parse_ulong_option(&decl[i], arg, prefix, opt);
929                         break;
930                 case isl_arg_bool:
931                         parsed = parse_bool_option(&decl[i], arg, prefix, opt);
932                         break;
933                 case isl_arg_str:
934                         parsed = parse_str_option(&decl[i], arg, prefix, opt);
935                         break;
936                 case isl_arg_child:
937                         parsed = parse_child_option(&decl[i], arg, opt);
938                         break;
939                 case isl_arg_alias:
940                 case isl_arg_arg:
941                 case isl_arg_user:
942                 case isl_arg_version:
943                 case isl_arg_end:
944                         break;
945                 }
946                 if (parsed)
947                         return parsed;
948         }
949
950         return 0;
951 }
952
953 static void print_version(struct isl_arg *decl)
954 {
955         int i;
956
957         for (i = 0; decl[i].type != isl_arg_end; ++i) {
958                 switch (decl[i].type) {
959                 case isl_arg_version:
960                         decl[i].u.version.print_version();
961                         break;
962                 case isl_arg_child:
963                         print_version(decl[i].u.child.child);
964                         break;
965                 default:
966                         break;
967                 }
968         }
969 }
970
971 static void print_version_and_exit(struct isl_arg *decl)
972 {
973         print_version(decl);
974
975         exit(0);
976 }
977
978 static int drop_argument(int argc, char **argv, int drop, int n)
979 {
980         for (; drop < argc; ++drop)
981                 argv[drop] = argv[drop + n];
982
983         return argc - n;
984 }
985
986 static int n_arg(struct isl_arg *arg)
987 {
988         int i;
989         int n_arg = 0;
990
991         for (i = 0; arg[i].type != isl_arg_end; ++i)
992                 if (arg[i].type == isl_arg_arg)
993                         n_arg++;
994
995         return n_arg;
996 }
997
998 static int next_arg(struct isl_arg *arg, int a)
999 {
1000         for (++a; arg[a].type != isl_arg_end; ++a)
1001                 if (arg[a].type == isl_arg_arg)
1002                         return a;
1003
1004         return -1;
1005 }
1006
1007 int isl_arg_parse(struct isl_arg *arg, int argc, char **argv, void *opt,
1008         unsigned flags)
1009 {
1010         int a = -1;
1011         int skip = 0;
1012         int i;
1013         int n;
1014
1015         n = n_arg(arg);
1016
1017         for (i = 1; i < argc; ++i) {
1018                 if (strcmp(argv[i], "--help") == 0)
1019                         print_help_and_exit(arg, argv[0]);
1020         }
1021
1022         for (i = 1; i < argc; ++i) {
1023                 if ((strcmp(argv[i], "--version") == 0 ||
1024                      strcmp(argv[i], "-V") == 0) && any_version(arg))
1025                         print_version_and_exit(arg);
1026         }
1027
1028         while (argc > 1 + skip) {
1029                 int parsed;
1030                 if (argv[1 + skip][0] != '-') {
1031                         a = next_arg(arg, a);
1032                         if (a >= 0) {
1033                                 char **p;
1034                                 p = (char **)(((char *)opt)+arg[a].offset);
1035                                 free(*p);
1036                                 *p = strdup(argv[1 + skip]);
1037                                 argc = drop_argument(argc, argv, 1 + skip, 1);
1038                                 --n;
1039                         } else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) {
1040                                 fprintf(stderr, "%s: extra argument: %s\n",
1041                                             prog_name(argv[0]), argv[1 + skip]);
1042                                 exit(-1);
1043                         } else
1044                                 ++skip;
1045                         continue;
1046                 }
1047                 parsed = parse_option(arg, &argv[1 + skip], NULL, opt);
1048                 if (parsed)
1049                         argc = drop_argument(argc, argv, 1 + skip, parsed);
1050                 else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) {
1051                         fprintf(stderr, "%s: unrecognized option: %s\n",
1052                                         prog_name(argv[0]), argv[1 + skip]);
1053                         exit(-1);
1054                 } else
1055                         ++skip;
1056         }
1057
1058         if (n > 0) {
1059                 fprintf(stderr, "%s: expecting %d more argument(s)\n",
1060                                 prog_name(argv[0]), n);
1061                 exit(-1);
1062         }
1063
1064         return argc;
1065 }