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