1f2e63b7aa6b9304fc3a627c4652ec3afb41ab2c
[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         int any = 0;
463
464         for (i = 0; arg[i].type != isl_arg_end; ++i) {
465                 if (arg[i].flags & ISL_ARG_HIDDEN)
466                         continue;
467                 switch (arg[i].type) {
468                 case isl_arg_flags:
469                         print_flags_help(&arg[i], prefix);
470                         any = 1;
471                         break;
472                 case isl_arg_choice:
473                         print_choice_help(&arg[i], prefix);
474                         any = 1;
475                         break;
476                 case isl_arg_bool:
477                         print_bool_help(&arg[i], prefix);
478                         any = 1;
479                         break;
480                 case isl_arg_int:
481                         print_int_help(&arg[i], prefix);
482                         any = 1;
483                         break;
484                 case isl_arg_long:
485                         print_long_help(&arg[i], prefix);
486                         any = 1;
487                         break;
488                 case isl_arg_ulong:
489                         print_ulong_help(&arg[i], prefix);
490                         any = 1;
491                         break;
492                 case isl_arg_str:
493                         print_str_help(&arg[i], prefix);
494                         any = 1;
495                         break;
496                 case isl_arg_alias:
497                 case isl_arg_version:
498                 case isl_arg_arg:
499                 case isl_arg_child:
500                 case isl_arg_user:
501                 case isl_arg_end:
502                         break;
503                 }
504         }
505
506         for (i = 0; arg[i].type != isl_arg_end; ++i) {
507                 if (arg[i].type != isl_arg_child)
508                         continue;
509                 if (arg[i].flags & ISL_ARG_HIDDEN)
510                         continue;
511
512                 if (any)
513                         printf("\n");
514                 if (arg[i].help_msg)
515                         printf(" %s\n", arg[i].help_msg);
516                 print_help(arg[i].u.child.child, arg[i].long_name);
517                 any = 1;
518         }
519 }
520
521 static const char *prog_name(const char *prog)
522 {
523         const char *slash;
524
525         slash = strrchr(prog, '/');
526         if (slash)
527                 prog = slash + 1;
528         if (strncmp(prog, "lt-", 3) == 0)
529                 prog += 3;
530
531         return prog;
532 }
533
534 static int any_version(struct isl_arg *decl)
535 {
536         int i;
537
538         for (i = 0; decl[i].type != isl_arg_end; ++i) {
539                 switch (decl[i].type) {
540                 case isl_arg_version:
541                         return 1;
542                 case isl_arg_child:
543                         if (any_version(decl[i].u.child.child))
544                                 return 1;
545                         break;
546                 default:
547                         break;
548                 }
549         }
550
551         return 0;
552 }
553
554 static void print_help_and_exit(struct isl_arg *arg, const char *prog)
555 {
556         int i;
557
558         printf("Usage: %s [OPTION...]", prog_name(prog));
559
560         for (i = 0; arg[i].type != isl_arg_end; ++i)
561                 if (arg[i].type == isl_arg_arg)
562                         printf(" %s", arg[i].argument_name);
563
564         printf("\n\n");
565
566         print_help(arg, NULL);
567         printf("\n");
568         if (any_version(arg))
569                 printf("  -V, --version\n");
570         print_bool_help(help_arg, NULL);
571
572         exit(0);
573 }
574
575 static int match_long_name(struct isl_arg *decl,
576         const char *start, const char *end)
577 {
578         do {
579                 if (end - start == strlen(decl->long_name) &&
580                     !strncmp(start, decl->long_name, end - start))
581                         return 1;
582         } while ((++decl)->type == isl_arg_alias);
583
584         return 0;
585 }
586
587 static const char *skip_dash_dash(struct isl_arg *decl, const char *arg)
588 {
589         if (!strncmp(arg, "--", 2))
590                 return arg + 2;
591         if ((decl->flags & ISL_ARG_SINGLE_DASH) && arg[0] == '-')
592                 return arg + 1;
593         return NULL;
594 }
595
596 static const char *skip_name(struct isl_arg *decl, const char *arg,
597         const char *prefix, int need_argument, int *has_argument)
598 {
599         const char *equal;
600         const char *name;
601         const char *end;
602
603         if (arg[0] == '-' && arg[1] && arg[1] == decl->short_name) {
604                 if (need_argument && !arg[2])
605                         return NULL;
606                 if (has_argument)
607                         *has_argument = arg[2] != '\0';
608                 return arg + 2;
609         }
610         if (!decl->long_name)
611                 return NULL;
612
613         name = skip_dash_dash(decl, arg);
614         if (!name)
615                 return NULL;
616
617         equal = strchr(name, '=');
618         if (need_argument && !equal)
619                 return NULL;
620
621         if (has_argument)
622                 *has_argument = !!equal;
623         end = equal ? equal : name + strlen(name);
624
625         if (prefix) {
626                 size_t prefix_len = strlen(prefix);
627                 if (strncmp(name, prefix, prefix_len) == 0 &&
628                     name[prefix_len] == '-')
629                         name += prefix_len + 1;
630         }
631
632         if (!match_long_name(decl, name, end))
633                 return NULL;
634
635         return equal ? equal + 1 : end;
636 }
637
638 static int parse_choice_option(struct isl_arg *decl, char **arg,
639         const char *prefix, void *opt)
640 {
641         int i;
642         int has_argument;
643         const char *choice;
644
645         choice = skip_name(decl, arg[0], prefix, 0, &has_argument);
646         if (!choice)
647                 return 0;
648
649         if (!has_argument && (!arg[1] || arg[1][0] == '-')) {
650                 unsigned u = decl->u.choice.default_selected;
651                 if (decl->u.choice.set)
652                         decl->u.choice.set(opt, u);
653                 else
654                         *(unsigned *)(((char *)opt) + decl->offset) = u;
655
656                 return 1;
657         }
658
659         if (!has_argument)
660                 choice = arg[1];
661
662         for (i = 0; decl->u.choice.choice[i].name; ++i) {
663                 unsigned u;
664
665                 if (strcmp(choice, decl->u.choice.choice[i].name))
666                         continue;
667
668                 u = decl->u.choice.choice[i].value;
669                 if (decl->u.choice.set)
670                         decl->u.choice.set(opt, u);
671                 else
672                         *(unsigned *)(((char *)opt) + decl->offset) = u;
673
674                 return has_argument ? 1 : 2;
675         }
676
677         return 0;
678 }
679
680 static int set_flag(struct isl_arg *decl, unsigned *val, const char *flag,
681         size_t len)
682 {
683         int i;
684
685         for (i = 0; decl->u.flags.flags[i].name; ++i) {
686                 if (strncmp(flag, decl->u.flags.flags[i].name, len))
687                         continue;
688
689                 *val &= ~decl->u.flags.flags[i].mask;
690                 *val |= decl->u.flags.flags[i].value;
691
692                 return 1;
693         }
694
695         return 0;
696 }
697
698 static int parse_flags_option(struct isl_arg *decl, char **arg,
699         const char *prefix, void *opt)
700 {
701         int has_argument;
702         const char *flags;
703         const char *comma;
704         unsigned val;
705
706         flags = skip_name(decl, arg[0], prefix, 0, &has_argument);
707         if (!flags)
708                 return 0;
709
710         if (!has_argument && !arg[1])
711                 return 0;
712
713         if (!has_argument)
714                 flags = arg[1];
715
716         val = *(unsigned *)(((char *)opt) + decl->offset);
717
718         while ((comma = strchr(flags, ',')) != NULL) {
719                 if (!set_flag(decl, &val, flags, comma - flags))
720                         return 0;
721                 flags = comma + 1;
722         }
723         if (!set_flag(decl, &val, flags, strlen(flags)))
724                 return 0;
725
726         *(unsigned *)(((char *)opt) + decl->offset) = val;
727
728         return has_argument ? 1 : 2;
729 }
730
731 static int parse_bool_option(struct isl_arg *decl, char **arg,
732         const char *prefix, void *opt)
733 {
734         const char *name;
735         unsigned *p = (unsigned *)(((char *)opt) + decl->offset);
736
737         if (skip_name(decl, arg[0], prefix, 0, NULL)) {
738                 if ((decl->flags && ISL_ARG_BOOL_ARG) && arg[1]) {
739                         char *endptr;
740                         int val = strtol(arg[1], &endptr, 0);
741                         if (*endptr == '\0' && (val == 0 || val == 1)) {
742                                 if (decl->u.b.set)
743                                         decl->u.b.set(opt, val);
744                                 else if (decl->offset != (size_t) -1)
745                                         *p = val;
746                                 return 2;
747                         }
748                 }
749                 if (decl->u.b.set)
750                         decl->u.b.set(opt, 1);
751                 else if (decl->offset != (size_t) -1)
752                         *p = 1;
753
754                 return 1;
755         }
756
757         if (!decl->long_name)
758                 return 0;
759
760         name = skip_dash_dash(decl, arg[0]);
761         if (!name)
762                 return 0;
763
764         if (prefix) {
765                 size_t prefix_len = strlen(prefix);
766                 if (strncmp(name, prefix, prefix_len) == 0 &&
767                     name[prefix_len] == '-') {
768                         name += prefix_len + 1;
769                         prefix = NULL;
770                 }
771         }
772
773         if (strncmp(name, "no-", 3))
774                 return 0;
775         name += 3;
776
777         if (prefix) {
778                 size_t prefix_len = strlen(prefix);
779                 if (strncmp(name, prefix, prefix_len) == 0 &&
780                     name[prefix_len] == '-')
781                         name += prefix_len + 1;
782         }
783
784         if (match_long_name(decl, name, name + strlen(name))) {
785                 if (decl->u.b.set)
786                         decl->u.b.set(opt, 0);
787                 else if (decl->offset != (size_t) -1)
788                         *p = 0;
789
790                 return 1;
791         }
792
793         return 0;
794 }
795
796 static int parse_str_option(struct isl_arg *decl, char **arg,
797         const char *prefix, void *opt)
798 {
799         int has_argument;
800         const char *s;
801         char **p = (char **)(((char *)opt) + decl->offset);
802
803         s = skip_name(decl, arg[0], prefix, 0, &has_argument);
804         if (!s)
805                 return 0;
806
807         if (has_argument) {
808                 free(*p);
809                 *p = strdup(s);
810                 return 1;
811         }
812
813         if (arg[1]) {
814                 free(*p);
815                 *p = strdup(arg[1]);
816                 return 2;
817         }
818
819         return 0;
820 }
821
822 static int parse_int_option(struct isl_arg *decl, char **arg,
823         const char *prefix, void *opt)
824 {
825         int has_argument;
826         const char *val;
827         char *endptr;
828         int *p = (int *)(((char *)opt) + decl->offset);
829
830         val = skip_name(decl, arg[0], prefix, 0, &has_argument);
831         if (!val)
832                 return 0;
833
834         if (has_argument) {
835                 *p = atoi(val);
836                 return 1;
837         }
838
839         if (arg[1]) {
840                 int i = strtol(arg[1], &endptr, 0);
841                 if (*endptr == '\0') {
842                         *p = i;
843                         return 2;
844                 }
845         }
846
847         return 0;
848 }
849
850 static int parse_long_option(struct isl_arg *decl, char **arg,
851         const char *prefix, void *opt)
852 {
853         int has_argument;
854         const char *val;
855         char *endptr;
856         long *p = (long *)(((char *)opt) + decl->offset);
857
858         val = skip_name(decl, arg[0], prefix, 0, &has_argument);
859         if (!val)
860                 return 0;
861
862         if (has_argument) {
863                 long l = strtol(val, NULL, 0);
864                 if (decl->u.l.set)
865                         decl->u.l.set(opt, l);
866                 else
867                         *p = l;
868                 return 1;
869         }
870
871         if (arg[1]) {
872                 long l = strtol(arg[1], &endptr, 0);
873                 if (*endptr == '\0') {
874                         if (decl->u.l.set)
875                                 decl->u.l.set(opt, l);
876                         else
877                                 *p = l;
878                         return 2;
879                 }
880         }
881
882         if (decl->u.l.default_value != decl->u.l.default_selected) {
883                 if (decl->u.l.set)
884                         decl->u.l.set(opt, decl->u.l.default_selected);
885                 else
886                         *p = decl->u.l.default_selected;
887                 return 1;
888         }
889
890         return 0;
891 }
892
893 static int parse_ulong_option(struct isl_arg *decl, char **arg,
894         const char *prefix, void *opt)
895 {
896         int has_argument;
897         const char *val;
898         char *endptr;
899         unsigned long *p = (unsigned long *)(((char *)opt) + decl->offset);
900
901         val = skip_name(decl, arg[0], prefix, 0, &has_argument);
902         if (!val)
903                 return 0;
904
905         if (has_argument) {
906                 *p = strtoul(val, NULL, 0);
907                 return 1;
908         }
909
910         if (arg[1]) {
911                 unsigned long ul = strtoul(arg[1], &endptr, 0);
912                 if (*endptr == '\0') {
913                         *p = ul;
914                         return 2;
915                 }
916         }
917
918         return 0;
919 }
920
921 static int parse_option(struct isl_arg *decl, char **arg,
922         const char *prefix, void *opt);
923
924 static int parse_child_option(struct isl_arg *decl, char **arg,
925         const char *prefix, void *opt)
926 {
927         void *child;
928
929         if (decl->offset == (size_t) -1)
930                 child = opt;
931         else {
932                 child = *(void **)(((char *)opt) + decl->offset);
933                 prefix = decl->long_name;
934         }
935         return parse_option(decl->u.child.child, arg, prefix, child);
936 }
937
938 static int parse_option(struct isl_arg *decl, char **arg,
939         const char *prefix, void *opt)
940 {
941         int i;
942
943         for (i = 0; decl[i].type != isl_arg_end; ++i) {
944                 int parsed = 0;
945                 switch (decl[i].type) {
946                 case isl_arg_choice:
947                         parsed = parse_choice_option(&decl[i], arg, prefix, opt);
948                         break;
949                 case isl_arg_flags:
950                         parsed = parse_flags_option(&decl[i], arg, prefix, opt);
951                         break;
952                 case isl_arg_int:
953                         parsed = parse_int_option(&decl[i], arg, prefix, opt);
954                         break;
955                 case isl_arg_long:
956                         parsed = parse_long_option(&decl[i], arg, prefix, opt);
957                         break;
958                 case isl_arg_ulong:
959                         parsed = parse_ulong_option(&decl[i], arg, prefix, opt);
960                         break;
961                 case isl_arg_bool:
962                         parsed = parse_bool_option(&decl[i], arg, prefix, opt);
963                         break;
964                 case isl_arg_str:
965                         parsed = parse_str_option(&decl[i], arg, prefix, opt);
966                         break;
967                 case isl_arg_child:
968                         parsed = parse_child_option(&decl[i], arg, prefix, opt);
969                         break;
970                 case isl_arg_alias:
971                 case isl_arg_arg:
972                 case isl_arg_user:
973                 case isl_arg_version:
974                 case isl_arg_end:
975                         break;
976                 }
977                 if (parsed)
978                         return parsed;
979         }
980
981         return 0;
982 }
983
984 static void print_version(struct isl_arg *decl)
985 {
986         int i;
987
988         for (i = 0; decl[i].type != isl_arg_end; ++i) {
989                 switch (decl[i].type) {
990                 case isl_arg_version:
991                         decl[i].u.version.print_version();
992                         break;
993                 case isl_arg_child:
994                         print_version(decl[i].u.child.child);
995                         break;
996                 default:
997                         break;
998                 }
999         }
1000 }
1001
1002 static void print_version_and_exit(struct isl_arg *decl)
1003 {
1004         print_version(decl);
1005
1006         exit(0);
1007 }
1008
1009 static int drop_argument(int argc, char **argv, int drop, int n)
1010 {
1011         for (; drop < argc; ++drop)
1012                 argv[drop] = argv[drop + n];
1013
1014         return argc - n;
1015 }
1016
1017 static int n_arg(struct isl_arg *arg)
1018 {
1019         int i;
1020         int n_arg = 0;
1021
1022         for (i = 0; arg[i].type != isl_arg_end; ++i)
1023                 if (arg[i].type == isl_arg_arg)
1024                         n_arg++;
1025
1026         return n_arg;
1027 }
1028
1029 static int next_arg(struct isl_arg *arg, int a)
1030 {
1031         for (++a; arg[a].type != isl_arg_end; ++a)
1032                 if (arg[a].type == isl_arg_arg)
1033                         return a;
1034
1035         return -1;
1036 }
1037
1038 int isl_arg_parse(struct isl_arg *arg, int argc, char **argv, void *opt,
1039         unsigned flags)
1040 {
1041         int a = -1;
1042         int skip = 0;
1043         int i;
1044         int n;
1045
1046         n = n_arg(arg);
1047
1048         for (i = 1; i < argc; ++i) {
1049                 if (strcmp(argv[i], "--help") == 0)
1050                         print_help_and_exit(arg, argv[0]);
1051         }
1052
1053         for (i = 1; i < argc; ++i) {
1054                 if ((strcmp(argv[i], "--version") == 0 ||
1055                      strcmp(argv[i], "-V") == 0) && any_version(arg))
1056                         print_version_and_exit(arg);
1057         }
1058
1059         while (argc > 1 + skip) {
1060                 int parsed;
1061                 if (argv[1 + skip][0] != '-') {
1062                         a = next_arg(arg, a);
1063                         if (a >= 0) {
1064                                 char **p;
1065                                 p = (char **)(((char *)opt)+arg[a].offset);
1066                                 free(*p);
1067                                 *p = strdup(argv[1 + skip]);
1068                                 argc = drop_argument(argc, argv, 1 + skip, 1);
1069                                 --n;
1070                         } else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) {
1071                                 fprintf(stderr, "%s: extra argument: %s\n",
1072                                             prog_name(argv[0]), argv[1 + skip]);
1073                                 exit(-1);
1074                         } else
1075                                 ++skip;
1076                         continue;
1077                 }
1078                 parsed = parse_option(arg, &argv[1 + skip], NULL, opt);
1079                 if (parsed)
1080                         argc = drop_argument(argc, argv, 1 + skip, parsed);
1081                 else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) {
1082                         fprintf(stderr, "%s: unrecognized option: %s\n",
1083                                         prog_name(argv[0]), argv[1 + skip]);
1084                         exit(-1);
1085                 } else
1086                         ++skip;
1087         }
1088
1089         if (n > 0) {
1090                 fprintf(stderr, "%s: expecting %d more argument(s)\n",
1091                                 prog_name(argv[0]), n);
1092                 exit(-1);
1093         }
1094
1095         return argc;
1096 }