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