Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / core / getopt.c
1 /*
2  * Copyright (C) 2006 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 <stdint.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <getopt.h>
26
27 /** @file
28  *
29  * Parse command-line options
30  *
31  */
32
33 /**
34  * Option argument
35  *
36  * This will point to the argument for the most recently returned
37  * option, if applicable.
38  */
39 char *optarg;
40
41 /**
42  * Current option index
43  *
44  * This is an index into the argv[] array.  When getopt() returns -1,
45  * @c optind is the index to the first element that is not an option.
46  */
47 int optind;
48
49 /**
50  * Current option character index
51  *
52  * This is an index into the current element of argv[].
53  */
54 int nextchar;
55
56 /**
57  * Unrecognised option
58  *
59  * When an unrecognised option is encountered, the actual option
60  * character is stored in @c optopt.
61  */
62 int optopt;
63
64 /**
65  * Get option argument from argv[] array
66  *
67  * @v argc              Argument count
68  * @v argv              Argument list
69  * @ret argument        Option argument, or NULL
70  *
71  * Grab the next element of argv[], if it exists and is not an option.
72  */
73 static const char * get_argv_argument ( int argc, char * const argv[] ) {
74         char *arg;
75
76         /* Don't overrun argv[] */
77         if ( optind >= argc )
78                 return NULL;
79         arg = argv[optind];
80
81         /* If next argv element is an option, then it's not usable as
82          * an argument.
83          */
84         if ( *arg == '-' )
85                 return NULL;
86
87         /** Consume this argv element, and return it */
88         optind++;
89         return arg;
90 }
91
92 /**
93  * Match long option
94  *
95  * @v argc              Argument count
96  * @v argv              Argument list
97  * @v opttext           Option text within current argv[] element
98  * @v longopt           Long option specification
99  * @ret option          Option to return from getopt()
100  * @ret matched         Found a match for this long option
101  */
102 static int match_long_option ( int argc, char * const argv[],
103                                const char *opttext,
104                                const struct option *longopt, int *option ) {
105         size_t optlen;
106         const char *argument = NULL;
107
108         /* Compare option name */
109         optlen = strlen ( longopt->name );
110         if ( strncmp ( opttext, longopt->name, optlen ) != 0 )
111                 return 0;
112
113         /* Check for inline argument */
114         if ( opttext[optlen] == '=' ) {
115                 argument = &opttext[ optlen + 1 ];
116         } else if ( opttext[optlen] ) {
117                 /* Long option with trailing garbage - no match */
118                 return 0;
119         }
120
121         /* Consume this argv element */
122         optind++;
123
124         /* If we want an argument but don't have one yet, try to grab
125          * the next argv element
126          */
127         if ( ( longopt->has_arg != no_argument ) && ( ! argument ) )
128                 argument = get_argv_argument ( argc, argv );
129
130         /* If we need an argument but don't have one, sulk */
131         if ( ( longopt->has_arg == required_argument ) && ( ! argument ) ) {
132                 printf ( "Option \"%s\" requires an argument\n",
133                          longopt->name );
134                 *option = ':';
135                 return 1;
136         }
137
138         /* If we have an argument where we shouldn't have one, sulk */
139         if ( ( longopt->has_arg == no_argument ) && argument ) {
140                 printf ( "Option \"%s\" takes no argument\n", longopt->name );
141                 *option = ':';
142                 return 1;
143         }
144
145         /* Store values and return success */
146         optarg = ( char * ) argument;
147         if ( longopt->flag ) {
148                 *(longopt->flag) = longopt->val;
149                 *option = 0;
150         } else {
151                 *option = longopt->val;
152         }
153         return 1;
154 }
155
156 /**
157  * Match short option
158  *
159  * @v argc              Argument count
160  * @v argv              Argument list
161  * @v opttext           Option text within current argv[] element
162  * @v shortopt          Option character from option specification
163  * @ret option          Option to return from getopt()
164  * @ret matched         Found a match for this short option
165  */
166 static int match_short_option ( int argc, char * const argv[],
167                                 const char *opttext, int shortopt,
168                                 enum getopt_argument_requirement has_arg,
169                                 int *option ) {
170         const char *argument = NULL;
171
172         /* Compare option character */
173         if ( *opttext != shortopt )
174                 return 0;
175
176         /* Consume option character */
177         opttext++;
178         nextchar++;
179         if ( *opttext ) {
180                 if ( has_arg != no_argument ) {
181                         /* Consume remainder of element as inline argument */
182                         argument = opttext;
183                         optind++;
184                         nextchar = 0;
185                 }
186         } else {
187                 /* Reached end of argv element */
188                 optind++;
189                 nextchar = 0;
190         }
191
192         /* If we want an argument but don't have one yet, try to grab
193          * the next argv element
194          */
195         if ( ( has_arg != no_argument ) && ( ! argument ) )
196                 argument = get_argv_argument ( argc, argv );
197
198         /* If we need an argument but don't have one, sulk */
199         if ( ( has_arg == required_argument ) && ( ! argument ) ) {
200                 printf ( "Option \"%c\" requires an argument\n", shortopt );
201                 *option = ':';
202                 return 1;
203         }
204
205         /* Store values and return success */
206         optarg = ( char * ) argument;
207         *option = shortopt;
208         return 1;
209 }
210
211 /**
212  * Parse command-line options
213  *
214  * @v argc              Argument count
215  * @v argv              Argument list
216  * @v optstring         Option specification string
217  * @v longopts          Long option specification table
218  * @ret longindex       Index of long option (or NULL)
219  * @ret option          Option found, or -1 for no more options
220  *
221  * Note that the caller must arrange for reset_getopt() to be called
222  * before each set of calls to getopt_long().  In Etherboot, this is
223  * done automatically by execv().
224  */
225 int getopt_long ( int argc, char * const argv[], const char *optstring,
226                   const struct option *longopts, int *longindex ) {
227         const char *opttext = argv[optind];
228         const struct option *longopt;
229         int shortopt;
230         enum getopt_argument_requirement has_arg;
231         int option;
232
233         /* Check for end of argv array */
234         if ( optind >= argc )
235                 return -1;
236
237         /* Check for end of options */
238         if ( *(opttext++) != '-' )
239                 return -1;
240
241         /* Check for long options */
242         if ( *(opttext++) == '-' ) {
243                 /* "--" indicates end of options */
244                 if ( *opttext == '\0' ) {
245                         optind++;
246                         return -1;
247                 }
248                 for ( longopt = longopts ; longopt->name ; longopt++ ) {
249                         if ( ! match_long_option ( argc, argv, opttext,
250                                                    longopt, &option ) )
251                                 continue;
252                         if ( longindex )
253                                 *longindex = ( longopt - longopts );
254                         return option;
255                 }
256                 optopt = '?';
257                 printf ( "Unrecognised option \"--%s\"\n", opttext );
258                 return '?';
259         }
260
261         /* Check for short options */
262         if ( nextchar < 1 )
263                 nextchar = 1;
264         opttext = ( argv[optind] + nextchar );
265         while ( ( shortopt = *(optstring++) ) ) {
266                 has_arg = no_argument;
267                 while ( *optstring == ':' ) {
268                         has_arg++;
269                         optstring++;
270                 }
271                 if ( match_short_option ( argc, argv, opttext, shortopt,
272                                           has_arg, &option ) ) {
273                         return option;
274                 }
275         }
276         optopt = *opttext;
277         printf ( "Unrecognised option \"-%c\"\n", optopt );
278         return '?';
279 }