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