]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4util/lib/src/parse_cmdline.c
e5000c8ac12ef4bbce4c72ec99faec38e9a96a59
[l4.git] / l4 / pkg / l4util / lib / src / parse_cmdline.c
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
45 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
56 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     const char*longform, *comment;
60     struct option *longopts, *longptr;
61     char *optstring, *optptr;
62     struct parse_cmdline_struct *pa;
63     int err;
64
65     va_copy(va, va0);
66     /* calculate the number of argument-descriptors */
67     shortform = arg0;
68     for(count=0; shortform; count++){
69         int type;
70         int standard_int, *int_p;
71         const char *standard_string, **string_p;
72  
73         longform = va_arg(va, const char*);
74         comment = va_arg(va, const char*);
75         type = va_arg(va, int);
76         switch(type){
77         case PARSE_CMD_INT:
78             standard_int = va_arg(va, int);
79             int_p = va_arg(va, int*);
80             *int_p = standard_int;
81             break;
82         case PARSE_CMD_SWITCH:
83             TRASH(int, va_arg(va, int));
84             TRASH(int*, va_arg(va, int*));
85             break;
86         case PARSE_CMD_STRING:
87             standard_string = va_arg(va, char*);
88             string_p  = va_arg(va, const char**);
89             *string_p = standard_string;
90             break;
91         case PARSE_CMD_FN:
92         case PARSE_CMD_FN_ARG:
93             TRASH(int, va_arg(va, int));
94             TRASH(parse_cmd_fn_t, va_arg(va, parse_cmd_fn_t));
95             break;
96         case PARSE_CMD_INC:
97             standard_int = va_arg(va, int);
98             int_p = va_arg(va, int*);
99             *int_p = standard_int;
100             break;
101         case PARSE_CMD_DEC:
102             standard_int = va_arg(va, int);
103             int_p = va_arg(va, int*);
104             *int_p = standard_int;
105             break;
106         default:
107             return -1;
108         }
109         shortform = va_arg(va, int);
110     }
111
112     /* consider the --help and -h */
113     count++;
114
115     /* allocate the fields for short options, long options and parse args */
116     longopts = (struct option*)alloca(sizeof(struct option)*(count+1));
117     if(longopts==0) return -2;
118     
119     optstring = (char*)alloca(count*2+1);
120     if(optstring==0) return -2;
121     
122     pa = (struct parse_cmdline_struct*)
123          alloca(count * sizeof(struct parse_cmdline_struct));
124     if(pa==0) return -2;
125     
126     /* fill in the short options field, longopts and parse args */
127     va_copy(va, va0);
128     shortform = arg0;
129     optptr    = optstring;
130     longptr   = longopts;
131
132     /* Prefill the 'help' switches. We know it is the first entry, so
133        we can check for idx 0 when parsing the table. */
134     *optptr++='h';
135     pa->shortform = 'h';
136     pa->longform = "help";
137     pa->comment = "this help";
138     pa->type = PARSE_CMD_SWITCH;
139     longptr->name = pa->longform;
140     longptr->flag = &cur_longopt;
141     longptr->val = 0;
142     longptr->has_arg = 0;
143     longptr++;
144
145     for(c=1;shortform; c++){
146         if(shortform!=' ') *optptr++ = shortform;
147         pa[c].shortform = shortform;
148         pa[c].longform = va_arg(va, const char*);
149         pa[c].comment = va_arg(va, const char*);
150         pa[c].type = va_arg(va, int);
151
152         /* prefill a few of the longoptions fields */
153         if(pa[c].longform){
154             longptr->name = pa[c].longform;
155             longptr->flag = &cur_longopt;
156             longptr->val = c;
157         }
158         switch(pa[c].type){
159         case PARSE_CMD_INT:
160             if(shortform!=' ') *optptr++ = ':';
161             if(pa[c].longform) longptr->has_arg = 1;
162
163             pa[c].val.default_int = va_arg(va, int);
164             pa[c].arg.argptr = va_arg(va, int*);
165             break;
166
167         case PARSE_CMD_SWITCH:
168             if(pa[c].longform) longptr->has_arg = 0;
169
170             pa[c].val.switch_to = va_arg(va, int);
171             pa[c].arg.argptr = va_arg(va, int*);
172             break;
173         case PARSE_CMD_STRING:
174             if(shortform!=' ') *optptr++ = ':';
175             if(pa[c].longform) longptr->has_arg = 1;
176
177             pa[c].val.default_string = va_arg(va, char*);
178             pa[c].arg.argptr = va_arg(va, char**);
179             break;
180         case PARSE_CMD_FN:
181             if(pa[c].longform) longptr->has_arg = 0;
182
183             pa[c].val.id = va_arg(va, int);
184             pa[c].arg.fn = va_arg(va, parse_cmd_fn_t);
185             break;
186         case PARSE_CMD_FN_ARG:
187             if(shortform!=' ') *optptr++ = ':';
188             if(pa[c].longform) longptr->has_arg = 1;
189
190             pa[c].val.id = va_arg(va, int);
191             pa[c].arg.fn_arg = va_arg(va, parse_cmd_fn_arg_t);
192             break;
193         case PARSE_CMD_INC:
194         case PARSE_CMD_DEC:
195             if(pa[c].longform) longptr->has_arg = 0;
196
197             TRASH(int, va_arg(va, int));
198             pa[c].arg.argptr = va_arg(va, int*);
199             break;
200         }
201
202         if(pa[c].longform) longptr++;
203         // next short form
204         shortform = va_arg(va, int);
205     }
206
207     // end the optstring string
208     *optptr=0;
209
210     // end the longopt field
211     longptr->name=0;
212     longptr->has_arg=0;
213     longptr->flag=0;
214     longptr->val=0;
215
216     err = -3;
217
218     /* now, parse the arguments */
219     do{
220         int val;
221         int idx;
222
223         val = getopt_long_only(*argc, (char**)*argv, optstring, longopts, &idx);
224         switch(val){
225         case ':':
226             printf("Option -%c requires an argument\n",optopt);
227             goto e_help;
228         case '?':
229             if(opterr){
230                 printf("Unrecognized option: - %c\n", optopt ? optopt : '?');
231                 goto e_help;
232             }
233             break;
234         case -1:
235             *argc-=optind;
236             *argv+=optind;
237             optind=1;
238             return 0;
239         default:
240             /* we got an option. If it is a short option (val!=0),
241                lookup the index. */
242             if(val!=0){
243                 for(idx = 0; idx < count; idx++){
244                     if(pa[idx].shortform == val) break;
245                 }
246             } else {
247                 /* it was a long option. We are lucky, the pa-element is
248                    stored in the cur_longopt variable. */
249                 idx = cur_longopt;
250             }
251             if(idx == 0){
252                 err = -4;
253                 goto e_help;
254             }
255             if(idx<count){
256                 switch(pa[idx].type){
257                 case PARSE_CMD_INT:
258                     *((int*)pa[idx].arg.argptr) = strtol(optarg, 0, 0);
259                     break;
260                 case PARSE_CMD_SWITCH:
261                     *((int*)pa[idx].arg.argptr) = pa[idx].val.switch_to;
262                     break;
263                 case PARSE_CMD_STRING:
264                     *((const char**)pa[idx].arg.argptr) = optarg;
265                     break;
266                 case PARSE_CMD_FN:
267                     pa[idx].arg.fn(pa[idx].val.id);
268                     break;
269                 case PARSE_CMD_FN_ARG:
270                     pa[idx].arg.fn_arg(pa[idx].val.id,
271                                        optarg, strtol(optarg, 0, 0));
272                     break;
273                 case PARSE_CMD_INC:
274                     (*((int*)pa[idx].arg.argptr))++;
275                     break;
276                 case PARSE_CMD_DEC:
277                     (*((int*)pa[idx].arg.argptr))--;
278                     break;
279                 break;
280                 }
281             }
282             break;
283         } // switch val
284     } while(1);
285
286   e_help:
287     printf("Usage: %s <options>. Option list:\n", *argv[0]);
288     for(c=0;c<count;c++){
289         int l;
290         char buf[3];
291         
292         if(pa[c].shortform!=' '){
293                 buf[0]='-';buf[1]=pa[c].shortform;buf[2]=0;
294         } else {
295                 buf[0]=0;
296         }
297         
298         l = printf(" [ %s%s%s%s%s ]",
299                    buf,
300                    (buf[0] && pa[c].longform) ? " | " : "",
301                    pa[c].longform ? "--" : "",
302                    pa[c].longform ? pa[c].longform : "",
303                    pa[c].type==PARSE_CMD_INT ? " num" :
304                    pa[c].type==PARSE_CMD_STRING ? " string" : "");
305         if(pa[c].comment) printf(" %*s- %s", l<25?25-l:0,
306                                  "", pa[c].comment);
307         if(pa[c].type == PARSE_CMD_STRING)
308                 printf(" (\"%s\")", pa[c].val.default_string);
309         if(pa[c].type == PARSE_CMD_INT)
310                 printf(" (%#x)", pa[c].val.default_int);
311         printf("\n");
312     }
313   optind=1;
314   return err;
315 }
316
317 int parse_cmdline_extra(const char*argv0, const char*line, char delim,
318                         char arg0,...){
319     int i, argc_=1;
320     char*s, *line_=0;
321     const char**argv_;
322     va_list va;
323
324     if(line && *line){
325         if((line_ = alloca(strlen(line)))==0) return -2;
326         strcpy(line_, line);
327         argc_++;
328         for(s=line_;*s;s++)if(*s==delim) argc_++;
329     }
330     argv_ = alloca(sizeof(char*)*argc_);
331     argv_[0]=argv0;
332     argc_=1;
333     s=line_;
334     if(line) while(*line){
335         argv_[argc_]=s;
336         while((*s=*line)!=0 && *s!=delim){line++; s++;}
337         *s++=0;
338         if(*line)line++;
339         argc_++;
340     }
341     va_start(va, arg0);
342     i = parse_cmdlinev(&argc_, &argv_, arg0, va);
343     va_end(va);
344     return i;
345 }