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