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