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