Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / core / parseopt.c
1 /*
2  * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stddef.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <getopt.h>
29 #include <ipxe/netdevice.h>
30 #include <ipxe/menu.h>
31 #include <ipxe/settings.h>
32 #include <ipxe/params.h>
33 #include <ipxe/timer.h>
34 #include <ipxe/parseopt.h>
35
36 /** @file
37  *
38  * Command line option parsing
39  *
40  */
41
42 /** Return status code for "--help" option */
43 #define ECANCELED_NO_OP __einfo_error ( EINFO_ECANCELED_NO_OP )
44 #define EINFO_ECANCELED_NO_OP \
45         __einfo_uniqify ( EINFO_ECANCELED, 0x01, "Nothing to do" )
46
47 /* Disambiguate the various error codes */
48 #define EINVAL_INTEGER __einfo_error ( EINFO_EINVAL_INTEGER )
49 #define EINFO_EINVAL_INTEGER \
50         __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid integer value" )
51 #define EINVAL_UNKNOWN_OPTION __einfo_error ( EINFO_EINVAL_UNKNOWN_OPTION )
52 #define EINFO_EINVAL_UNKNOWN_OPTION \
53         __einfo_uniqify ( EINFO_EINVAL, 0x02, "Unrecognised option" )
54 #define EINVAL_MISSING_ARGUMENT __einfo_error ( EINFO_EINVAL_MISSING_ARGUMENT )
55 #define EINFO_EINVAL_MISSING_ARGUMENT \
56         __einfo_uniqify ( EINFO_EINVAL, 0x03, "Missing argument" )
57
58 /**
59 * Parse string value
60  *
61  * @v text              Text
62  * @ret value           String value
63  * @ret rc              Return status code
64  */
65 int parse_string ( char *text, char **value ) {
66
67         /* Sanity check */
68         assert ( text != NULL );
69
70         /* Parse string */
71         *value = text;
72
73         return 0;
74 }
75
76 /**
77  * Parse integer value
78  *
79  * @v text              Text
80  * @ret value           Integer value
81  * @ret rc              Return status code
82  */
83 int parse_integer ( char *text, unsigned int *value ) {
84         char *endp;
85
86         /* Sanity check */
87         assert ( text != NULL );
88
89         /* Parse integer */
90         *value = strtoul ( text, &endp, 0 );
91         if ( *endp ) {
92                 printf ( "\"%s\": invalid integer value\n", text );
93                 return -EINVAL_INTEGER;
94         }
95
96         return 0;
97 }
98
99 /**
100  * Parse timeout value (in ms)
101  *
102  * @v text              Text
103  * @ret value           Integer value
104  * @ret rc              Return status code
105  */
106 int parse_timeout ( char *text, unsigned long *value ) {
107         unsigned int value_ms;
108         int rc;
109
110         /* Parse raw integer value */
111         if ( ( rc = parse_integer ( text, &value_ms ) ) != 0 )
112                 return rc;
113
114         /* Convert to a number of timer ticks */
115         *value = ( ( value_ms * TICKS_PER_SEC ) / 1000 );
116
117         return 0;
118 }
119
120 /**
121  * Parse network device name
122  *
123  * @v text              Text
124  * @ret netdev          Network device
125  * @ret rc              Return status code
126  */
127 int parse_netdev ( char *text, struct net_device **netdev ) {
128
129         /* Sanity check */
130         assert ( text != NULL );
131
132         /* Find network device */
133         *netdev = find_netdev ( text );
134         if ( ! *netdev ) {
135                 printf ( "\"%s\": no such network device\n", text );
136                 return -ENODEV;
137         }
138
139         return 0;
140 }
141
142 /**
143  * Parse network device configurator name
144  *
145  * @v text              Text
146  * @ret configurator    Network device configurator
147  * @ret rc              Return status code
148  */
149 int parse_netdev_configurator ( char *text,
150                                 struct net_device_configurator **configurator ){
151
152         /* Sanity check */
153         assert ( text != NULL );
154
155         /* Find network device configurator */
156         *configurator = find_netdev_configurator ( text );
157         if ( ! *configurator ) {
158                 printf ( "\"%s\": no such configurator\n", text );
159                 return -ENOTSUP;
160         }
161
162         return 0;
163 }
164
165 /**
166  * Parse menu name
167  *
168  * @v text              Text
169  * @ret menu            Menu
170  * @ret rc              Return status code
171  */
172 int parse_menu ( char *text, struct menu **menu ) {
173
174         /* Find menu */
175         *menu = find_menu ( text );
176         if ( ! *menu ) {
177                 if ( text ) {
178                         printf ( "\"%s\": no such menu\n", text );
179                 } else {
180                         printf ( "No default menu\n" );
181                 }
182                 return -ENOENT;
183         }
184
185         return 0;
186 }
187
188 /**
189  * Parse flag
190  *
191  * @v text              Text (ignored)
192  * @ret flag            Flag to set
193  * @ret rc              Return status code
194  */
195 int parse_flag ( char *text __unused, int *flag ) {
196
197         /* Set flag */
198         *flag = 1;
199
200         return 0;
201 }
202
203 /**
204  * Parse key
205  *
206  * @v text              Text
207  * @ret key             Key
208  * @ret rc              Return status code
209  */
210 int parse_key ( char *text, unsigned int *key ) {
211
212         /* Interpret single characters as being a literal key character */
213         if ( text[0] && ! text[1] ) {
214                 *key = text[0];
215                 return 0;
216         }
217
218         /* Otherwise, interpret as an integer */
219         return parse_integer ( text, key );
220 }
221
222 /**
223  * Parse settings block name
224  *
225  * @v text              Text
226  * @ret value           Integer value
227  * @ret rc              Return status code
228  */
229 int parse_settings ( char *text, struct settings **value ) {
230
231         /* Sanity check */
232         assert ( text != NULL );
233
234         /* Parse scope name */
235         *value = find_settings ( text );
236         if ( ! *value ) {
237                 printf ( "\"%s\": no such scope\n", text );
238                 return -EINVAL;
239         }
240
241         return 0;
242 }
243
244 /**
245  * Parse setting name
246  *
247  * @v text              Text
248  * @v setting           Named setting to fill in
249  * @v get_child         Function to find or create child settings block
250  * @ret rc              Return status code
251  *
252  * Note that this function modifies the original @c text.
253  */
254 int parse_setting ( char *text, struct named_setting *setting,
255                     get_child_settings_t get_child ) {
256         int rc;
257
258         /* Sanity check */
259         assert ( text != NULL );
260
261         /* Parse setting name */
262         if ( ( rc = parse_setting_name ( text, get_child, &setting->settings,
263                                          &setting->setting ) ) != 0 ) {
264                 printf ( "\"%s\": invalid setting\n", text );
265                 return rc;
266         }
267
268         return 0;
269 }
270
271 /**
272  * Parse existing setting name
273  *
274  * @v text              Text
275  * @v setting           Named setting to fill in
276  * @ret rc              Return status code
277  *
278  * Note that this function modifies the original @c text.
279  */
280 int parse_existing_setting ( char *text, struct named_setting *setting ) {
281
282         return parse_setting ( text, setting, find_child_settings );
283 }
284
285 /**
286  * Parse and autovivify setting name
287  *
288  * @v text              Text
289  * @v setting           Named setting to fill in
290  * @ret rc              Return status code
291  *
292  * Note that this function modifies the original @c text.
293  */
294 int parse_autovivified_setting ( char *text, struct named_setting *setting ) {
295
296         return parse_setting ( text, setting, autovivify_child_settings );
297 }
298
299 /**
300  * Parse form parameter list name
301  *
302  * @v text              Text
303  * @ret params          Parameter list
304  * @ret rc              Return status code
305  */
306 int parse_parameters ( char *text, struct parameters **params ) {
307
308         /* Find parameter list */
309         *params = find_parameters ( text );
310         if ( ! *params ) {
311                 if ( text ) {
312                         printf ( "\"%s\": no such parameter list\n", text );
313                 } else {
314                         printf ( "No default parameter list\n" );
315                 }
316                 return -ENOENT;
317         }
318
319         return 0;
320 }
321
322 /**
323  * Print command usage message
324  *
325  * @v cmd               Command descriptor
326  * @v argv              Argument list
327  */
328 void print_usage ( struct command_descriptor *cmd, char **argv ) {
329         struct option_descriptor *option;
330         unsigned int i;
331         int is_optional;
332
333         printf ( "Usage:\n\n  %s", argv[0] );
334         for ( i = 0 ; i < cmd->num_options ; i++ ) {
335                 option = &cmd->options[i];
336                 printf ( " [-%c|--%s", option->shortopt, option->longopt );
337                 if ( option->has_arg ) {
338                         is_optional = ( option->has_arg == optional_argument );
339                         printf ( " %s<%s>%s", ( is_optional ? "[" : "" ),
340                                  option->longopt, ( is_optional ? "]" : "" ) );
341                 }
342                 printf ( "]" );
343         }
344         if ( cmd->usage )
345                 printf ( " %s", cmd->usage );
346         printf ( "\n\nSee http://ipxe.org/cmd/%s for further information\n",
347                  argv[0] );
348 }
349
350 /**
351  * Reparse command-line options
352  *
353  * @v argc              Argument count
354  * @v argv              Argument list
355  * @v cmd               Command descriptor
356  * @v opts              Options (already initialised with default values)
357  * @ret rc              Return status code
358  */
359 int reparse_options ( int argc, char **argv, struct command_descriptor *cmd,
360                       void *opts ) {
361         struct option longopts[ cmd->num_options + 1 /* help */ + 1 /* end */ ];
362         char shortopts[ cmd->num_options * 3 /* possible "::" */ + 1 /* "h" */
363                         + 1 /* NUL */ ];
364         unsigned int shortopt_idx = 0;
365         int ( * parse ) ( char *text, void *value );
366         void *value;
367         unsigned int i;
368         unsigned int j;
369         unsigned int num_args;
370         int c;
371         int rc;
372
373         /* Construct long and short option lists for getopt_long() */
374         memset ( longopts, 0, sizeof ( longopts ) );
375         for ( i = 0 ; i < cmd->num_options ; i++ ) {
376                 longopts[i].name = cmd->options[i].longopt;
377                 longopts[i].has_arg = cmd->options[i].has_arg;
378                 longopts[i].val = cmd->options[i].shortopt;
379                 shortopts[shortopt_idx++] = cmd->options[i].shortopt;
380                 assert ( cmd->options[i].has_arg <= optional_argument );
381                 for ( j = cmd->options[i].has_arg ; j > 0 ; j-- )
382                         shortopts[shortopt_idx++] = ':';
383         }
384         longopts[i].name = "help";
385         longopts[i].val = 'h';
386         shortopts[shortopt_idx++] = 'h';
387         shortopts[shortopt_idx++] = '\0';
388         assert ( shortopt_idx <= sizeof ( shortopts ) );
389         DBGC ( cmd,  "Command \"%s\" has options \"%s\", %d-%d args, len %d\n",
390                argv[0], shortopts, cmd->min_args, cmd->max_args, cmd->len );
391
392         /* Parse options */
393         while ( ( c = getopt_long ( argc, argv, shortopts, longopts,
394                                     NULL ) ) >= 0 ) {
395                 switch ( c ) {
396                 case 'h' :
397                         /* Print help */
398                         print_usage ( cmd, argv );
399                         return -ECANCELED_NO_OP;
400                 case '?' :
401                         /* Print usage message */
402                         print_usage ( cmd, argv );
403                         return -EINVAL_UNKNOWN_OPTION;
404                 case ':' :
405                         /* Print usage message */
406                         print_usage ( cmd, argv );
407                         return -EINVAL_MISSING_ARGUMENT;
408                 default:
409                         /* Search for an option to parse */
410                         for ( i = 0 ; i < cmd->num_options ; i++ ) {
411                                 if ( c != cmd->options[i].shortopt )
412                                         continue;
413                                 parse = cmd->options[i].parse;
414                                 value = ( opts + cmd->options[i].offset );
415                                 if ( ( rc = parse ( optarg, value ) ) != 0 )
416                                         return rc;
417                                 break;
418                         }
419                         assert ( i < cmd->num_options );
420                 }
421         }
422
423         /* Check remaining arguments */
424         num_args = ( argc - optind );
425         if ( ( num_args < cmd->min_args ) || ( num_args > cmd->max_args ) ) {
426                 print_usage ( cmd, argv );
427                 return -ERANGE;
428         }
429
430         return 0;
431 }
432
433 /**
434  * Parse command-line options
435  *
436  * @v argc              Argument count
437  * @v argv              Argument list
438  * @v cmd               Command descriptor
439  * @v opts              Options (may be uninitialised)
440  * @ret rc              Return status code
441  */
442 int parse_options ( int argc, char **argv, struct command_descriptor *cmd,
443                     void *opts ) {
444
445         /* Clear options */
446         memset ( opts, 0, cmd->len );
447
448         return reparse_options ( argc, argv, cmd, opts );
449 }