1 /*
2 * (c) 2008-2009 Frank Mehnert <fm3@os.inf.tu-dresden.de>,
3 * Torsten Frenzel <frenzel@os.inf.tu-dresden.de>,
4 * Jork Löser <jork@os.inf.tu-dresden.de>
5 * economic rights: Technische Universität Dresden (Germany)
6 * This file is part of TUD:OS and distributed under the terms of the
7 * GNU Lesser General Public License 2.1.
8 * Please see the COPYING-LGPL-2.1 file for details.
9 */
10 /*
11 * Parse the command-line for specified arguments and store the values into
12 * variables.
13 *
14 * For a more detailed documentation, see parse_cmd.h in the include dir.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdarg.h>
20 #include <alloca.h>
21 #include <string.h>
22 #include <l4/util/getopt.h>
23 #include <l4/util/parse_cmd.h>
24
25 struct parse_cmdline_struct{
26 enum parse_cmd_type type; // which type (int, switch, string)
27 char shortform; // short symbol
28 const char *longform; // long name
29 union{
30 void *argptr; // ptr to variable getting the value
31 parse_cmd_fn_t fn; // function to call
32 parse_cmd_fn_arg_t fn_arg; // function to call with args
33 } arg;
34 union{
35 int switch_to; // value a switch sets
36 const char* default_string; // default string value
37 unsigned default_int; // default int value
38 int id; // identifier to pass to function
39 }val;
40 const char *comment; // a description for the generated help
41 };
42
43 #define TRASH(type, val) { type dummy __attribute__ ((unused)) = (val); }
44
parse_cmdline(int * argc,const char *** argv,char arg0,...)45 L4_CV int parse_cmdline(int *argc, const char***argv, char arg0, ...){
46 va_list va;
47 int err;
48
49 /* calculate the number of argument-descriptors */
50 va_start(va, arg0);
51 err = parse_cmdlinev(argc, argv, arg0, va);
52 va_end(va);
53 return err;
54 }
55
parse_cmdlinev(int * argc,const char *** argv,char arg0,va_list va0)56 L4_CV int parse_cmdlinev(int *argc, const char***argv, char arg0, va_list va0){
57 va_list va;
58 int c, count, shortform, cur_longopt;
59 struct option *longopts, *longptr;
60 char *optstring, *optptr;
61 struct parse_cmdline_struct *pa;
62 int err;
63
64 va_copy(va, va0);
65 /* calculate the number of argument-descriptors */
66 shortform = arg0;
67 for(count=0; shortform; count++){
68 int type;
69 int standard_int, *int_p;
70 const char *standard_string, **string_p;
71
72 va_arg(va, const char*); /* skip long form */
73 va_arg(va, const char*); /* skip comment */
74 type = va_arg(va, int);
75 switch(type){
76 case PARSE_CMD_INT:
77 standard_int = va_arg(va, int);
78 int_p = va_arg(va, int*);
79 *int_p = standard_int;
80 break;
81 case PARSE_CMD_SWITCH:
82 TRASH(int, va_arg(va, int));
83 TRASH(int*, va_arg(va, int*));
84 break;
85 case PARSE_CMD_STRING:
86 standard_string = va_arg(va, char*);
87 string_p = va_arg(va, const char**);
88 *string_p = standard_string;
89 break;
90 case PARSE_CMD_FN:
91 case PARSE_CMD_FN_ARG:
92 TRASH(int, va_arg(va, int));
93 TRASH(parse_cmd_fn_t, va_arg(va, parse_cmd_fn_t));
94 break;
95 case PARSE_CMD_INC:
96 standard_int = va_arg(va, int);
97 int_p = va_arg(va, int*);
98 *int_p = standard_int;
99 break;
100 case PARSE_CMD_DEC:
101 standard_int = va_arg(va, int);
102 int_p = va_arg(va, int*);
103 *int_p = standard_int;
104 break;
105 default:
106 return -1;
107 }
108 shortform = va_arg(va, int);
109 }
110
111 /* consider the --help and -h */
112 count++;
113
114 /* allocate the fields for short options, long options and parse args */
115 longopts = (struct option*)alloca(sizeof(struct option)*(count+1));
116 if(longopts==0) return -2;
117
118 optstring = (char*)alloca(count*2+1);
119 if(optstring==0) return -2;
120
121 pa = (struct parse_cmdline_struct*)
122 alloca(count * sizeof(struct parse_cmdline_struct));
123 if(pa==0) return -2;
124
125 /* fill in the short options field, longopts and parse args */
126 va_copy(va, va0);
127 shortform = arg0;
128 optptr = optstring;
129 longptr = longopts;
130
131 /* Prefill the 'help' switches. We know it is the first entry, so
132 we can check for idx 0 when parsing the table. */
133 *optptr++='h';
134 pa->shortform = 'h';
135 pa->longform = "help";
136 pa->comment = "this help";
137 pa->type = PARSE_CMD_SWITCH;
138 longptr->name = pa->longform;
139 longptr->flag = &cur_longopt;
140 longptr->val = 0;
141 longptr->has_arg = 0;
142 longptr++;
143
144 for(c=1;shortform; c++){
145 if(shortform!=' ') *optptr++ = shortform;
146 pa[c].shortform = shortform;
147 pa[c].longform = va_arg(va, const char*);
148 pa[c].comment = va_arg(va, const char*);
149 pa[c].type = va_arg(va, int);
150
151 /* prefill a few of the longoptions fields */
152 if(pa[c].longform){
153 longptr->name = pa[c].longform;
154 longptr->flag = &cur_longopt;
155 longptr->val = c;
156 }
157 switch(pa[c].type){
158 case PARSE_CMD_INT:
159 if(shortform!=' ') *optptr++ = ':';
160 if(pa[c].longform) longptr->has_arg = 1;
161
162 pa[c].val.default_int = va_arg(va, int);
163 pa[c].arg.argptr = va_arg(va, int*);
164 break;
165
166 case PARSE_CMD_SWITCH:
167 if(pa[c].longform) longptr->has_arg = 0;
168
169 pa[c].val.switch_to = va_arg(va, int);
170 pa[c].arg.argptr = va_arg(va, int*);
171 break;
172 case PARSE_CMD_STRING:
173 if(shortform!=' ') *optptr++ = ':';
174 if(pa[c].longform) longptr->has_arg = 1;
175
176 pa[c].val.default_string = va_arg(va, char*);
177 pa[c].arg.argptr = va_arg(va, char**);
178 break;
179 case PARSE_CMD_FN:
180 if(pa[c].longform) longptr->has_arg = 0;
181
182 pa[c].val.id = va_arg(va, int);
183 pa[c].arg.fn = va_arg(va, parse_cmd_fn_t);
184 break;
185 case PARSE_CMD_FN_ARG:
186 if(shortform!=' ') *optptr++ = ':';
187 if(pa[c].longform) longptr->has_arg = 1;
188
189 pa[c].val.id = va_arg(va, int);
190 pa[c].arg.fn_arg = va_arg(va, parse_cmd_fn_arg_t);
191 break;
192 case PARSE_CMD_INC:
193 case PARSE_CMD_DEC:
194 if(pa[c].longform) longptr->has_arg = 0;
195
196 TRASH(int, va_arg(va, int));
197 pa[c].arg.argptr = va_arg(va, int*);
198 break;
199 }
200
201 if(pa[c].longform) longptr++;
202 // next short form
203 shortform = va_arg(va, int);
204 }
205
206 // end the optstring string
207 *optptr=0;
208
209 // end the longopt field
210 longptr->name=0;
211 longptr->has_arg=0;
212 longptr->flag=0;
213 longptr->val=0;
214
215 err = -3;
216
217 /* now, parse the arguments */
218 do{
219 int val;
220 int idx;
221
222 val = getopt_long_only(*argc, (char**)*argv, optstring, longopts, &idx);
223 switch(val){
224 case ':':
225 printf("Option -%c requires an argument\n",optopt);
226 goto e_help;
227 case '?':
228 if(opterr){
229 printf("Unrecognized option: - %c\n", optopt ? optopt : '?');
230 goto e_help;
231 }
232 break;
233 case -1:
234 *argc-=optind;
235 *argv+=optind;
236 optind=1;
237 return 0;
238 default:
239 /* we got an option. If it is a short option (val!=0),
240 lookup the index. */
241 if(val!=0){
242 for(idx = 0; idx < count; idx++){
243 if(pa[idx].shortform == val) break;
244 }
245 } else {
246 /* it was a long option. We are lucky, the pa-element is
247 stored in the cur_longopt variable. */
248 idx = cur_longopt;
249 }
250 if(idx == 0){
251 err = -4;
252 goto e_help;
253 }
254 if(idx<count){
255 switch(pa[idx].type){
256 case PARSE_CMD_INT:
257 *((int*)pa[idx].arg.argptr) = strtol(optarg, 0, 0);
258 break;
259 case PARSE_CMD_SWITCH:
260 *((int*)pa[idx].arg.argptr) = pa[idx].val.switch_to;
261 break;
262 case PARSE_CMD_STRING:
263 *((const char**)pa[idx].arg.argptr) = optarg;
264 break;
265 case PARSE_CMD_FN:
266 pa[idx].arg.fn(pa[idx].val.id);
267 break;
268 case PARSE_CMD_FN_ARG:
269 pa[idx].arg.fn_arg(pa[idx].val.id,
270 optarg, strtol(optarg, 0, 0));
271 break;
272 case PARSE_CMD_INC:
273 (*((int*)pa[idx].arg.argptr))++;
274 break;
275 case PARSE_CMD_DEC:
276 (*((int*)pa[idx].arg.argptr))--;
277 break;
278 break;
279 }
280 }
281 break;
282 } // switch val
283 } while(1);
284
285 e_help:
286 printf("Usage: %s <options>. Option list:\n", *argv[0]);
287 for(c=0;c<count;c++){
288 int l;
289 char buf[3];
290
291 if(pa[c].shortform!=' '){
292 buf[0]='-';buf[1]=pa[c].shortform;buf[2]=0;
293 } else {
294 buf[0]=0;
295 }
296
297 l = printf(" [ %s%s%s%s%s ]",
298 buf,
299 (buf[0] && pa[c].longform) ? " | " : "",
300 pa[c].longform ? "--" : "",
301 pa[c].longform ? pa[c].longform : "",
302 pa[c].type==PARSE_CMD_INT ? " num" :
303 pa[c].type==PARSE_CMD_STRING ? " string" : "");
304 if(pa[c].comment) printf(" %*s- %s", l<25?25-l:0,
305 "", pa[c].comment);
306 if(pa[c].type == PARSE_CMD_STRING)
307 printf(" (\"%s\")", pa[c].val.default_string);
308 if(pa[c].type == PARSE_CMD_INT)
309 printf(" (%#x)", pa[c].val.default_int);
310 printf("\n");
311 }
312 optind=1;
313 return err;
314 }
315
parse_cmdline_extra(const char * argv0,const char * line,char delim,char arg0,...)316 L4_CV int parse_cmdline_extra(const char*argv0, const char*line, char delim,
317 char arg0,...){
318 int i, argc_=1;
319 char*s, *line_=0;
320 const char**argv_;
321 va_list va;
322
323 if(line && *line){
324 if((line_ = strdupa(line))==0) return -2;
325 argc_++;
326 for(s=line_;*s;s++)if(*s==delim) argc_++;
327 }
328 argv_ = alloca(sizeof(char*)*argc_);
329 argv_[0]=argv0;
330 argc_=1;
331 s=line_;
332 if(line) while(*line){
333 argv_[argc_]=s;
334 while((*s=*line)!=0 && *s!=delim){line++; s++;}
335 *s++=0;
336 if(*line)line++;
337 argc_++;
338 }
339 va_start(va, arg0);
340 i = parse_cmdlinev(&argc_, &argv_, arg0, va);
341 va_end(va);
342 return i;
343 }
344