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