add rudimentary argument parsing facility
[platform/upstream/isl.git] / isl_arg.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "isl_arg.h"
6
7 static void set_default_choice(struct isl_arg *arg, void *opt)
8 {
9         *(unsigned *)(((char *)opt) + arg->offset) = arg->u.choice.default_value;
10 }
11
12 static void set_default_bool(struct isl_arg *arg, void *opt)
13 {
14         *(unsigned *)(((char *)opt) + arg->offset) = arg->u.b.default_value;
15 }
16
17 static void set_default_child(struct isl_arg *arg, void *opt)
18 {
19         void *child = calloc(1, arg->u.child.size);
20
21         if (child)
22                 isl_arg_set_defaults(arg->u.child.child, child);
23
24         *(void **)(((char *)opt) + arg->offset) = child;
25 }
26
27 void isl_arg_set_defaults(struct isl_arg *arg, void *opt)
28 {
29         int i;
30
31         for (i = 0; arg[i].type != isl_arg_end; ++i) {
32                 switch (arg[i].type) {
33                 case isl_arg_choice:
34                         set_default_choice(&arg[i], opt);
35                         break;
36                 case isl_arg_bool:
37                         set_default_bool(&arg[i], opt);
38                         break;
39                 case isl_arg_child:
40                         set_default_child(&arg[i], opt);
41                         break;
42                 }
43         }
44 }
45
46 static void print_arg_help(struct isl_arg *decl, const char *prefix)
47 {
48         if (decl->short_name)
49                 printf("  -%c, --", decl->short_name);
50         else
51                 printf("      --");
52         if (prefix)
53                 printf("%s-", prefix);
54         printf("%s", decl->long_name);
55 }
56
57 static void print_choice_help(struct isl_arg *decl, const char *prefix)
58 {
59         int i;
60
61         print_arg_help(decl, prefix);
62         printf("=");
63
64         for (i = 0; decl->u.choice.choice[i].name; ++i) {
65                 if (i)
66                         printf("|");
67                 printf("%s", decl->u.choice.choice[i].name);
68         }
69
70         printf("\n");
71 }
72
73 static void print_bool_help(struct isl_arg *decl, const char *prefix)
74 {
75         print_arg_help(decl, prefix);
76         printf("\n");
77 }
78
79 static void print_help(struct isl_arg *arg, const char *prefix)
80 {
81         int i;
82
83         for (i = 0; arg[i].type != isl_arg_end; ++i) {
84                 switch (arg[i].type) {
85                 case isl_arg_choice:
86                         print_choice_help(&arg[i], prefix);
87                         break;
88                 case isl_arg_bool:
89                         print_bool_help(&arg[i], prefix);
90                         break;
91                 }
92         }
93
94         for (i = 0; arg[i].type != isl_arg_end; ++i) {
95                 if (arg[i].type != isl_arg_child)
96                         continue;
97
98                 printf("\n");
99                 print_help(arg[i].u.child.child, arg[i].long_name);
100         }
101 }
102
103 static void print_help_and_exit(struct isl_arg *arg, const char *prog)
104 {
105         const char *slash;
106
107         slash = strrchr(prog, '/');
108         if (slash)
109                 printf("Usage: %s [OPTION...]\n\n", slash + 1);
110
111         print_help(arg, NULL);
112
113         exit(0);
114 }
115
116 static int parse_choice_option(struct isl_arg *decl, const char *arg,
117         const char *prefix, void *opt)
118 {
119         int i;
120         const char *equal;
121         const char *name;
122
123         if (strncmp(arg, "--", 2))
124                 return 0;
125
126         name = arg + 2;
127         equal = strchr(name, '=');
128         if (!equal)
129                 return 0;
130
131         if (prefix) {
132                 size_t prefix_len = strlen(prefix);
133                 if (strncmp(name, prefix, prefix_len) == 0 &&
134                     name[prefix_len] == '-')
135                         name += prefix_len + 1;
136         }
137
138         if (strncmp(name, decl->long_name, equal - name))
139                 return 0;
140
141         for (i = 0; decl->u.choice.choice[i].name; ++i) {
142                 if (strcmp(equal + 1, decl->u.choice.choice[i].name))
143                         continue;
144
145                 *(unsigned *)(((char *)opt) + decl->offset) =
146                         decl->u.choice.choice[i].value;
147
148                 return 1;
149         }
150
151         return 0;
152 }
153
154 static int parse_bool_option(struct isl_arg *decl, const char *arg, void *opt)
155 {
156         int i;
157
158         if ((arg[0] == '-' && arg[1] == decl->short_name && arg[2] == '\0') ||
159             (strncmp(arg, "--", 2) == 0 &&
160              strcmp(arg + 2, decl->long_name) == 0)) {
161                 *(unsigned *)(((char *)opt) + decl->offset) = 1;
162
163                 return 1;
164         }
165
166         return 0;
167 }
168
169 static int parse_option(struct isl_arg *decl, const char *arg,
170         const char *prefix, void *opt);
171
172 static int parse_child_option(struct isl_arg *decl, const char *arg, void *opt)
173 {
174         return parse_option(decl->u.child.child, arg, decl->long_name,
175                                 *(void **)(((char *)opt) + decl->offset));
176 }
177
178 static int parse_option(struct isl_arg *decl, const char *arg,
179         const char *prefix, void *opt)
180 {
181         int i;
182
183         for (i = 0; decl[i].type != isl_arg_end; ++i) {
184                 switch (decl[i].type) {
185                 case isl_arg_choice:
186                         if (parse_choice_option(&decl[i], arg, prefix, opt))
187                                 return 1;
188                         break;
189                 case isl_arg_bool:
190                         if (parse_bool_option(&decl[i], arg, opt))
191                                 return 1;
192                         break;
193                 case isl_arg_child:
194                         if (parse_child_option(&decl[i], arg, opt))
195                                 return 1;
196                         break;
197                 }
198         }
199
200         return 0;
201 }
202
203 static int drop_argument(int argc, char **argv, int drop)
204 {
205         for (; drop < argc; ++drop)
206                 argv[drop] = argv[drop + 1];
207
208         return argc - 1;
209 }
210
211 int isl_arg_parse(struct isl_arg *arg, int argc, char **argv, void *opt)
212 {
213         int skip = 0;
214         int i;
215
216         for (i = 1; i < argc; ++i) {
217                 if (strcmp(argv[i], "--help") == 0)
218                         print_help_and_exit(arg, argv[0]);
219         }
220
221         while (argc > 1 + skip) {
222                 if (parse_option(arg, argv[1 + skip], NULL, opt))
223                         argc = drop_argument(argc, argv, 1 + skip);
224                 else {
225                         fprintf(stderr, "unrecognized option: %s\n",
226                                         argv[1 + skip]);
227                         exit(-1);
228                 }
229         }
230
231         return argc;
232 }