fa453587c32a2fc1d76331fc08f1678f68269491
[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 void set_default_choice(struct isl_arg *arg, void *opt)
18 {
19         *(unsigned *)(((char *)opt) + arg->offset) = arg->u.choice.default_value;
20 }
21
22 static void set_default_flags(struct isl_arg *arg, void *opt)
23 {
24         *(unsigned *)(((char *)opt) + arg->offset) = arg->u.flags.default_value;
25 }
26
27 static void set_default_bool(struct isl_arg *arg, void *opt)
28 {
29         if (arg->offset == (size_t) -1)
30                 return;
31         *(unsigned *)(((char *)opt) + arg->offset) = arg->u.b.default_value;
32 }
33
34 static void set_default_child(struct isl_arg *arg, void *opt)
35 {
36         void *child = calloc(1, arg->u.child.size);
37
38         if (child)
39                 isl_arg_set_defaults(arg->u.child.child, child);
40
41         *(void **)(((char *)opt) + arg->offset) = child;
42 }
43
44 static void set_default_user(struct isl_arg *arg, void *opt)
45 {
46         arg->u.user.init(((char *)opt) + arg->offset);
47 }
48
49 static void set_default_long(struct isl_arg *arg, void *opt)
50 {
51         *(long *)(((char *)opt) + arg->offset) = arg->u.l.default_value;
52 }
53
54 static void set_default_ulong(struct isl_arg *arg, void *opt)
55 {
56         *(unsigned long *)(((char *)opt) + arg->offset) = arg->u.ul.default_value;
57 }
58
59 static void set_default_str(struct isl_arg *arg, void *opt)
60 {
61         const char *str = NULL;
62         if (arg->u.str.default_value)
63                 str = strdup(arg->u.str.default_value);
64         *(const char **)(((char *)opt) + arg->offset) = str;
65 }
66
67 void isl_arg_set_defaults(struct isl_arg *arg, void *opt)
68 {
69         int i;
70
71         for (i = 0; arg[i].type != isl_arg_end; ++i) {
72                 switch (arg[i].type) {
73                 case isl_arg_choice:
74                         set_default_choice(&arg[i], opt);
75                         break;
76                 case isl_arg_flags:
77                         set_default_flags(&arg[i], opt);
78                         break;
79                 case isl_arg_bool:
80                         set_default_bool(&arg[i], opt);
81                         break;
82                 case isl_arg_child:
83                         set_default_child(&arg[i], opt);
84                         break;
85                 case isl_arg_user:
86                         set_default_user(&arg[i], opt);
87                         break;
88                 case isl_arg_long:
89                         set_default_long(&arg[i], opt);
90                         break;
91                 case isl_arg_ulong:
92                         set_default_ulong(&arg[i], opt);
93                         break;
94                 case isl_arg_arg:
95                 case isl_arg_str:
96                         set_default_str(&arg[i], opt);
97                         break;
98                 case isl_arg_version:
99                 case isl_arg_end:
100                         break;
101                 }
102         }
103 }
104
105 void isl_arg_free(struct isl_arg *arg, void *opt)
106 {
107         int i;
108
109         if (!opt)
110                 return;
111
112         for (i = 0; arg[i].type != isl_arg_end; ++i) {
113                 switch (arg[i].type) {
114                 case isl_arg_child:
115                         isl_arg_free(arg[i].u.child.child,
116                                 *(void **)(((char *)opt) + arg[i].offset));
117                         break;
118                 case isl_arg_arg:
119                 case isl_arg_str:
120                         free(*(char **)(((char *)opt) + arg[i].offset));
121                         break;
122                 case isl_arg_user:
123                         if (arg[i].u.user.clear)
124                                 arg[i].u.user.clear(((char *)opt) + arg[i].offset);
125                         break;
126                 case isl_arg_bool:
127                 case isl_arg_choice:
128                 case isl_arg_flags:
129                 case isl_arg_long:
130                 case isl_arg_ulong:
131                 case isl_arg_version:
132                 case isl_arg_end:
133                         break;
134                 }
135         }
136
137         free(opt);
138 }
139
140 static int print_arg_help(struct isl_arg *decl, const char *prefix, int no)
141 {
142         int len = 0;
143
144         if (!decl->long_name) {
145                 printf("  -%c", decl->short_name);
146                 return 4;
147         }
148
149         if (decl->short_name)
150                 printf("  -%c, --", decl->short_name);
151         else
152                 printf("      --");
153         len += 8;
154
155         if (prefix) {
156                 printf("%s-", prefix);
157                 len += strlen(prefix) + 1;
158         }
159         if (no) {
160                 printf("no-");
161                 len += 3;
162         }
163         printf("%s", decl->long_name);
164         len += strlen(decl->long_name);
165
166         return len;
167 }
168
169 const void *isl_memrchr(const void *s, int c, size_t n)
170 {
171         const char *p = s;
172         while (n-- > 0)
173                 if (p[n] == c)
174                         return p + n;
175         return NULL;
176 }
177
178 static int print_help_msg(struct isl_arg *decl, int pos)
179 {
180         int len;
181         const char *s;
182
183         if (!decl->help_msg)
184                 return pos;
185
186         if (pos >= 29)
187                 printf("\n%30s", "");
188         else
189                 printf("%*s", 30 - pos, "");
190
191         s = decl->help_msg;
192         len = strlen(s);
193         while (len > 45) {
194                 const char *space = isl_memrchr(s, ' ', 45);
195                 int l;
196
197                 if (!space)
198                         space = strchr(s + 45, ' ');
199                 if (!space)
200                         break;
201                 l = space - s;
202                 printf("%.*s", l, s);
203                 s = space + 1;
204                 len -= l + 1;
205                 printf("\n%30s", "");
206         }
207
208         printf("%s", s);
209         return len;
210 }
211
212 static void print_default(struct isl_arg *decl, const char *def, int pos)
213 {
214         int i;
215         const char *default_prefix = "[default: ";
216         const char *default_suffix = "]";
217         int len;
218
219         len = strlen(default_prefix) + strlen(def) + strlen(default_suffix);
220
221         if (!decl->help_msg) {
222                 if (pos >= 29)
223                         printf("\n%30s", "");
224                 else
225                         printf("%*s", 30 - pos, "");
226                 pos = 0;
227         } else {
228                 if (pos + len >= 48)
229                         printf("\n%30s", "");
230                 else
231                         printf(" ");
232         }
233         printf("%s%s%s", default_prefix, def, default_suffix);
234 }
235
236 static void print_default_choice(struct isl_arg *decl, int pos)
237 {
238         int i;
239         const char *s = "none";
240
241         for (i = 0; decl->u.choice.choice[i].name; ++i)
242                 if (decl->u.choice.choice[i].value == decl->u.choice.default_value) {
243                         s = decl->u.choice.choice[i].name;
244                         break;
245                 }
246
247         print_default(decl, s, pos);
248 }
249
250 static void print_choice_help(struct isl_arg *decl, const char *prefix)
251 {
252         int i;
253         int pos;
254
255         pos = print_arg_help(decl, prefix, 0);
256         printf("=");
257         pos++;
258
259         for (i = 0; decl->u.choice.choice[i].name; ++i) {
260                 if (i) {
261                         printf("|");
262                         pos++;
263                 }
264                 printf("%s", decl->u.choice.choice[i].name);
265                 pos += strlen(decl->u.choice.choice[i].name);
266         }
267
268         pos = print_help_msg(decl, pos);
269         print_default_choice(decl, pos);
270
271         printf("\n");
272 }
273
274 static void print_default_flags(struct isl_arg *decl, int pos)
275 {
276         int i, first;
277         const char *default_prefix = "[default: ";
278         const char *default_suffix = "]";
279         int len = strlen(default_prefix) + strlen(default_suffix);
280
281         for (i = 0; decl->u.flags.flags[i].name; ++i)
282                 if ((decl->u.flags.default_value & decl->u.flags.flags[i].mask) ==
283                      decl->u.flags.flags[i].value)
284                         len += strlen(decl->u.flags.flags[i].name);
285
286         if (!decl->help_msg) {
287                 if (pos >= 29)
288                         printf("\n%30s", "");
289                 else
290                         printf("%*s", 30 - pos, "");
291                 pos = 0;
292         } else {
293                 if (pos + len >= 48)
294                         printf("\n%30s", "");
295                 else
296                         printf(" ");
297         }
298         printf("%s", default_prefix);
299
300         for (first = 1, i = 0; decl->u.flags.flags[i].name; ++i)
301                 if ((decl->u.flags.default_value & decl->u.flags.flags[i].mask) ==
302                      decl->u.flags.flags[i].value) {
303                         if (!first)
304                                 printf(",");
305                         printf("%s", decl->u.flags.flags[i].name);
306                         first = 0;
307                 }
308
309         printf("%s", default_suffix);
310 }
311
312 static void print_flags_help(struct isl_arg *decl, const char *prefix)
313 {
314         int i, j;
315         int pos;
316
317         pos = print_arg_help(decl, prefix, 0);
318         printf("=");
319         pos++;
320
321         for (i = 0; decl->u.flags.flags[i].name; ++i) {
322                 if (i) {
323                         printf(",");
324                         pos++;
325                 }
326                 for (j = i;
327                      decl->u.flags.flags[j].mask == decl->u.flags.flags[i].mask;
328                      ++j) {
329                         if (j != i) {
330                                 printf("|");
331                                 pos++;
332                         }
333                         printf("%s", decl->u.flags.flags[j].name);
334                         pos += strlen(decl->u.flags.flags[j].name);
335                 }
336                 i = j - 1;
337         }
338
339         pos = print_help_msg(decl, pos);
340         print_default_flags(decl, pos);
341
342         printf("\n");
343 }
344
345 static void print_bool_help(struct isl_arg *decl, const char *prefix)
346 {
347         int pos;
348         int no = decl->u.b.default_value == 1;
349         pos = print_arg_help(decl, prefix, no);
350         pos = print_help_msg(decl, pos);
351         if (decl->offset != (size_t) -1)
352                 print_default(decl, no ? "yes" : "no", pos);
353         printf("\n");
354 }
355
356 static int print_argument_name(struct isl_arg *decl, const char *name, int pos)
357 {
358         printf("%c<%s>", decl->long_name ? '=' : ' ', name);
359         return pos + 3 + strlen(name);
360 }
361
362 static void print_long_help(struct isl_arg *decl, const char *prefix)
363 {
364         int pos;
365         pos = print_arg_help(decl, prefix, 0);
366         if (decl->u.l.default_value != decl->u.l.default_selected) {
367                 printf("[");
368                 pos++;
369         }
370         printf("=long");
371         pos += 5;
372         if (decl->u.l.default_value != decl->u.l.default_selected) {
373                 printf("]");
374                 pos++;
375         }
376         print_help_msg(decl, pos);
377         printf("\n");
378 }
379
380 static void print_ulong_help(struct isl_arg *decl, const char *prefix)
381 {
382         int pos;
383         pos = print_arg_help(decl, prefix, 0);
384         printf("=ulong");
385         pos += 6;
386         print_help_msg(decl, pos);
387         printf("\n");
388 }
389
390 static void print_str_help(struct isl_arg *decl, const char *prefix)
391 {
392         int pos;
393         const char *a = decl->argument_name ? decl->argument_name : "string";
394         pos = print_arg_help(decl, prefix, 0);
395         pos = print_argument_name(decl, a, pos);
396         pos = print_help_msg(decl, pos);
397         if (decl->u.str.default_value)
398                 print_default(decl, decl->u.str.default_value, pos);
399         printf("\n");
400 }
401
402 static void print_help(struct isl_arg *arg, const char *prefix)
403 {
404         int i;
405
406         for (i = 0; arg[i].type != isl_arg_end; ++i) {
407                 switch (arg[i].type) {
408                 case isl_arg_flags:
409                         print_flags_help(&arg[i], prefix);
410                         break;
411                 case isl_arg_choice:
412                         print_choice_help(&arg[i], prefix);
413                         break;
414                 case isl_arg_bool:
415                         print_bool_help(&arg[i], prefix);
416                         break;
417                 case isl_arg_long:
418                         print_long_help(&arg[i], prefix);
419                         break;
420                 case isl_arg_ulong:
421                         print_ulong_help(&arg[i], prefix);
422                         break;
423                 case isl_arg_str:
424                         print_str_help(&arg[i], prefix);
425                         break;
426                 case isl_arg_version:
427                 case isl_arg_arg:
428                 case isl_arg_child:
429                 case isl_arg_user:
430                 case isl_arg_end:
431                         break;
432                 }
433         }
434
435         for (i = 0; arg[i].type != isl_arg_end; ++i) {
436                 if (arg[i].type != isl_arg_child)
437                         continue;
438
439                 printf("\n");
440                 if (arg[i].help_msg)
441                         printf(" %s\n", arg[i].help_msg);
442                 print_help(arg[i].u.child.child, arg[i].long_name);
443         }
444 }
445
446 static const char *prog_name(const char *prog)
447 {
448         const char *slash;
449
450         slash = strrchr(prog, '/');
451         if (slash)
452                 prog = slash + 1;
453         if (strncmp(prog, "lt-", 3) == 0)
454                 prog += 3;
455
456         return prog;
457 }
458
459 static int any_version(struct isl_arg *decl)
460 {
461         int i;
462
463         for (i = 0; decl[i].type != isl_arg_end; ++i) {
464                 switch (decl[i].type) {
465                 case isl_arg_version:
466                         return 1;
467                 case isl_arg_child:
468                         if (any_version(decl[i].u.child.child))
469                                 return 1;
470                         break;
471                 default:
472                         break;
473                 }
474         }
475
476         return 0;
477 }
478
479 static void print_help_and_exit(struct isl_arg *arg, const char *prog)
480 {
481         int i;
482
483         printf("Usage: %s [OPTION...]", prog_name(prog));
484
485         for (i = 0; arg[i].type != isl_arg_end; ++i)
486                 if (arg[i].type == isl_arg_arg)
487                         printf(" %s", arg[i].argument_name);
488
489         printf("\n\n");
490
491         print_help(arg, NULL);
492         if (any_version(arg)) {
493                 printf("\n");
494                 printf("  -V, --version\n");
495         }
496
497         exit(0);
498 }
499
500 static const char *skip_name(struct isl_arg *decl, const char *arg,
501         const char *prefix, int need_argument, int *has_argument)
502 {
503         const char *equal;
504         const char *name;
505         const char *end;
506
507         if (arg[0] == '-' && arg[1] && arg[1] == decl->short_name) {
508                 if (need_argument && !arg[2])
509                         return NULL;
510                 if (has_argument)
511                         *has_argument = arg[2] != '\0';
512                 return arg + 2;
513         }
514         if (!decl->long_name)
515                 return NULL;
516
517         if (strncmp(arg, "--", 2))
518                 return NULL;
519
520         name = arg + 2;
521         equal = strchr(name, '=');
522         if (need_argument && !equal)
523                 return NULL;
524
525         if (has_argument)
526                 *has_argument = !!equal;
527         end = equal ? equal : name + strlen(name);
528
529         if (prefix) {
530                 size_t prefix_len = strlen(prefix);
531                 if (strncmp(name, prefix, prefix_len) == 0 &&
532                     name[prefix_len] == '-')
533                         name += prefix_len + 1;
534         }
535
536         if (end - name != strlen(decl->long_name) ||
537             strncmp(name, decl->long_name, end - name))
538                 return NULL;
539
540         return equal ? equal + 1 : end;
541 }
542
543 static int parse_choice_option(struct isl_arg *decl, char **arg,
544         const char *prefix, void *opt)
545 {
546         int i;
547         int has_argument;
548         const char *choice;
549
550         choice = skip_name(decl, arg[0], prefix, 0, &has_argument);
551         if (!choice)
552                 return 0;
553
554         if (!has_argument && (!arg[1] || arg[1][0] == '-')) {
555                 unsigned u = decl->u.choice.default_selected;
556                 if (decl->u.choice.set)
557                         decl->u.choice.set(opt, u);
558                 else
559                         *(unsigned *)(((char *)opt) + decl->offset) = u;
560
561                 return 1;
562         }
563
564         if (!has_argument)
565                 choice = arg[1];
566
567         for (i = 0; decl->u.choice.choice[i].name; ++i) {
568                 unsigned u;
569
570                 if (strcmp(choice, decl->u.choice.choice[i].name))
571                         continue;
572
573                 u = decl->u.choice.choice[i].value;
574                 if (decl->u.choice.set)
575                         decl->u.choice.set(opt, u);
576                 else
577                         *(unsigned *)(((char *)opt) + decl->offset) = u;
578
579                 return has_argument ? 1 : 2;
580         }
581
582         return 0;
583 }
584
585 static int set_flag(struct isl_arg *decl, unsigned *val, const char *flag,
586         size_t len)
587 {
588         int i;
589
590         for (i = 0; decl->u.flags.flags[i].name; ++i) {
591                 if (strncmp(flag, decl->u.flags.flags[i].name, len))
592                         continue;
593
594                 *val &= ~decl->u.flags.flags[i].mask;
595                 *val |= decl->u.flags.flags[i].value;
596
597                 return 1;
598         }
599
600         return 0;
601 }
602
603 static int parse_flags_option(struct isl_arg *decl, char **arg,
604         const char *prefix, void *opt)
605 {
606         int has_argument;
607         const char *flags;
608         const char *comma;
609         unsigned val;
610
611         flags = skip_name(decl, arg[0], prefix, 0, &has_argument);
612         if (!flags)
613                 return 0;
614
615         if (!has_argument && !arg[1])
616                 return 0;
617
618         if (!has_argument)
619                 flags = arg[1];
620
621         val = *(unsigned *)(((char *)opt) + decl->offset);
622
623         while ((comma = strchr(flags, ',')) != NULL) {
624                 if (!set_flag(decl, &val, flags, comma - flags))
625                         return 0;
626                 flags = comma + 1;
627         }
628         if (!set_flag(decl, &val, flags, strlen(flags)))
629                 return 0;
630
631         *(unsigned *)(((char *)opt) + decl->offset) = val;
632
633         return has_argument ? 1 : 2;
634 }
635
636 static int parse_bool_option(struct isl_arg *decl, const char *arg,
637         const char *prefix, void *opt)
638 {
639         unsigned *p = (unsigned *)(((char *)opt) + decl->offset);
640
641         if (skip_name(decl, arg, prefix, 0, NULL)) {
642                 if (decl->u.b.set)
643                         decl->u.b.set(opt, 1);
644                 else if (decl->offset != (size_t) -1)
645                         *p = 1;
646
647                 return 1;
648         }
649
650         if (!decl->long_name)
651                 return 0;
652
653         if (strncmp(arg, "--", 2))
654                 return 0;
655         arg += 2;
656
657         if (prefix) {
658                 size_t prefix_len = strlen(prefix);
659                 if (strncmp(arg, prefix, prefix_len) == 0 &&
660                     arg[prefix_len] == '-') {
661                         arg += prefix_len + 1;
662                         prefix = NULL;
663                 }
664         }
665
666         if (strncmp(arg, "no-", 3))
667                 return 0;
668         arg += 3;
669
670         if (prefix) {
671                 size_t prefix_len = strlen(prefix);
672                 if (strncmp(arg, prefix, prefix_len) == 0 &&
673                     arg[prefix_len] == '-')
674                         arg += prefix_len + 1;
675         }
676
677         if (!strcmp(arg, decl->long_name)) {
678                 if (decl->u.b.set)
679                         decl->u.b.set(opt, 0);
680                 else if (decl->offset != (size_t) -1)
681                         *p = 0;
682
683                 return 1;
684         }
685
686         return 0;
687 }
688
689 static int parse_str_option(struct isl_arg *decl, char **arg,
690         const char *prefix, void *opt)
691 {
692         int has_argument;
693         const char *s;
694         char **p = (char **)(((char *)opt) + decl->offset);
695
696         s = skip_name(decl, arg[0], prefix, 0, &has_argument);
697         if (!s)
698                 return 0;
699
700         if (has_argument) {
701                 free(*p);
702                 *p = strdup(s);
703                 return 1;
704         }
705
706         if (arg[1]) {
707                 free(*p);
708                 *p = strdup(arg[1]);
709                 return 2;
710         }
711
712         return 0;
713 }
714
715 static int parse_long_option(struct isl_arg *decl, char **arg,
716         const char *prefix, void *opt)
717 {
718         int has_argument;
719         const char *val;
720         char *endptr;
721         long *p = (long *)(((char *)opt) + decl->offset);
722
723         val = skip_name(decl, arg[0], prefix, 0, &has_argument);
724         if (!val)
725                 return 0;
726
727         if (has_argument) {
728                 long l = strtol(val, NULL, 0);
729                 if (decl->u.l.set)
730                         decl->u.l.set(opt, l);
731                 else
732                         *p = l;
733                 return 1;
734         }
735
736         if (arg[1]) {
737                 long l = strtol(arg[1], &endptr, 0);
738                 if (*endptr == '\0') {
739                         if (decl->u.l.set)
740                                 decl->u.l.set(opt, l);
741                         else
742                                 *p = l;
743                         return 2;
744                 }
745         }
746
747         if (decl->u.l.default_value != decl->u.l.default_selected) {
748                 if (decl->u.l.set)
749                         decl->u.l.set(opt, decl->u.l.default_selected);
750                 else
751                         *p = decl->u.l.default_selected;
752                 return 1;
753         }
754
755         return 0;
756 }
757
758 static int parse_ulong_option(struct isl_arg *decl, char **arg,
759         const char *prefix, void *opt)
760 {
761         int has_argument;
762         const char *val;
763         char *endptr;
764         unsigned long *p = (unsigned long *)(((char *)opt) + decl->offset);
765
766         val = skip_name(decl, arg[0], prefix, 0, &has_argument);
767         if (!val)
768                 return 0;
769
770         if (has_argument) {
771                 *p = strtoul(val, NULL, 0);
772                 return 1;
773         }
774
775         if (arg[1]) {
776                 unsigned long ul = strtoul(arg[1], &endptr, 0);
777                 if (*endptr == '\0') {
778                         *p = ul;
779                         return 2;
780                 }
781         }
782
783         return 0;
784 }
785
786 static int parse_option(struct isl_arg *decl, char **arg,
787         const char *prefix, void *opt);
788
789 static int parse_child_option(struct isl_arg *decl, char **arg, void *opt)
790 {
791         return parse_option(decl->u.child.child, arg, decl->long_name,
792                                 *(void **)(((char *)opt) + decl->offset));
793 }
794
795 static int parse_option(struct isl_arg *decl, char **arg,
796         const char *prefix, void *opt)
797 {
798         int i;
799
800         for (i = 0; decl[i].type != isl_arg_end; ++i) {
801                 int parsed = 0;
802                 switch (decl[i].type) {
803                 case isl_arg_choice:
804                         parsed = parse_choice_option(&decl[i], arg, prefix, opt);
805                         break;
806                 case isl_arg_flags:
807                         parsed = parse_flags_option(&decl[i], arg, prefix, opt);
808                         break;
809                 case isl_arg_long:
810                         parsed = parse_long_option(&decl[i], arg, prefix, opt);
811                         break;
812                 case isl_arg_ulong:
813                         parsed = parse_ulong_option(&decl[i], arg, prefix, opt);
814                         break;
815                 case isl_arg_bool:
816                         parsed = parse_bool_option(&decl[i], *arg, prefix, opt);
817                         break;
818                 case isl_arg_str:
819                         parsed = parse_str_option(&decl[i], arg, prefix, opt);
820                         break;
821                 case isl_arg_child:
822                         parsed = parse_child_option(&decl[i], arg, opt);
823                         break;
824                 case isl_arg_arg:
825                 case isl_arg_user:
826                 case isl_arg_version:
827                 case isl_arg_end:
828                         break;
829                 }
830                 if (parsed)
831                         return parsed;
832         }
833
834         return 0;
835 }
836
837 static void print_version(struct isl_arg *decl)
838 {
839         int i;
840
841         for (i = 0; decl[i].type != isl_arg_end; ++i) {
842                 switch (decl[i].type) {
843                 case isl_arg_version:
844                         decl[i].u.version.print_version();
845                         break;
846                 case isl_arg_child:
847                         print_version(decl[i].u.child.child);
848                         break;
849                 default:
850                         break;
851                 }
852         }
853 }
854
855 static void print_version_and_exit(struct isl_arg *decl)
856 {
857         print_version(decl);
858
859         exit(0);
860 }
861
862 static int drop_argument(int argc, char **argv, int drop, int n)
863 {
864         for (; drop < argc; ++drop)
865                 argv[drop] = argv[drop + n];
866
867         return argc - n;
868 }
869
870 static int n_arg(struct isl_arg *arg)
871 {
872         int i;
873         int n_arg = 0;
874
875         for (i = 0; arg[i].type != isl_arg_end; ++i)
876                 if (arg[i].type == isl_arg_arg)
877                         n_arg++;
878
879         return n_arg;
880 }
881
882 static int next_arg(struct isl_arg *arg, int a)
883 {
884         for (++a; arg[a].type != isl_arg_end; ++a)
885                 if (arg[a].type == isl_arg_arg)
886                         return a;
887
888         return -1;
889 }
890
891 int isl_arg_parse(struct isl_arg *arg, int argc, char **argv, void *opt,
892         unsigned flags)
893 {
894         int a = -1;
895         int skip = 0;
896         int i;
897         int n;
898
899         n = n_arg(arg);
900
901         for (i = 1; i < argc; ++i) {
902                 if (strcmp(argv[i], "--help") == 0)
903                         print_help_and_exit(arg, argv[0]);
904         }
905
906         for (i = 1; i < argc; ++i) {
907                 if ((strcmp(argv[i], "--version") == 0 ||
908                      strcmp(argv[i], "-V") == 0) && any_version(arg))
909                         print_version_and_exit(arg);
910         }
911
912         while (argc > 1 + skip) {
913                 int parsed;
914                 if (argv[1 + skip][0] != '-') {
915                         a = next_arg(arg, a);
916                         if (a >= 0) {
917                                 char **p;
918                                 p = (char **)(((char *)opt)+arg[a].offset);
919                                 free(*p);
920                                 *p = strdup(argv[1 + skip]);
921                                 argc = drop_argument(argc, argv, 1 + skip, 1);
922                                 --n;
923                         } else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) {
924                                 fprintf(stderr, "%s: extra argument: %s\n",
925                                             prog_name(argv[0]), argv[1 + skip]);
926                                 exit(-1);
927                         } else
928                                 ++skip;
929                         continue;
930                 }
931                 parsed = parse_option(arg, &argv[1 + skip], NULL, opt);
932                 if (parsed)
933                         argc = drop_argument(argc, argv, 1 + skip, parsed);
934                 else if (ISL_FL_ISSET(flags, ISL_ARG_ALL)) {
935                         fprintf(stderr, "%s: unrecognized option: %s\n",
936                                         prog_name(argv[0]), argv[1 + skip]);
937                         exit(-1);
938                 } else
939                         ++skip;
940         }
941
942         if (n > 0) {
943                 fprintf(stderr, "%s: expecting %d more argument(s)\n",
944                                 prog_name(argv[0]), n);
945                 exit(-1);
946         }
947
948         return argc;
949 }