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