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