2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * Parse command-line options
33 * This will point to the argument for the most recently returned
34 * option, if applicable.
39 * Current option index
41 * This is an index into the argv[] array. When getopt() returns -1,
42 * @c optind is the index to the first element that is not an option.
47 * Current option character index
49 * This is an index into the current element of argv[].
51 static int nextchar = 0;
56 * When an unrecognised option is encountered, the actual option
57 * character is stored in @c optopt.
62 * Reset getopt() internal state
64 * Due to a limitation of the POSIX getopt() API, it is necessary to
65 * add a call to reset_getopt() before each set of calls to getopt()
66 * or getopt_long(). This arises because POSIX assumes that each
67 * process will parse command line arguments no more than once; this
68 * assumption is not valid within Etherboot. We work around the
69 * limitation by arranging for execv() to call reset_getopt() before
70 * executing the command.
72 void reset_getopt ( void ) {
78 * Get option argument from argv[] array
80 * @v argc Argument count
81 * @v argv Argument list
82 * @ret argument Option argument, or NULL
84 * Grab the next element of argv[], if it exists and is not an option.
86 static const char * get_argv_argument ( int argc, char * const argv[] ) {
89 /* Don't overrun argv[] */
94 /* If next argv element is an option, then it's not usable as
100 /** Consume this argv element, and return it */
108 * @v argc Argument count
109 * @v argv Argument list
110 * @v opttext Option text within current argv[] element
111 * @v longopt Long option specification
112 * @ret option Option to return from getopt()
113 * @ret matched Found a match for this long option
115 static int match_long_option ( int argc, char * const argv[],
117 const struct option *longopt, int *option ) {
119 const char *argument = NULL;
121 /* Compare option name */
122 optlen = strlen ( longopt->name );
123 if ( strncmp ( opttext, longopt->name, optlen ) != 0 )
126 /* Check for inline argument */
127 if ( opttext[optlen] == '=' ) {
128 argument = &opttext[ optlen + 1 ];
129 } else if ( opttext[optlen] ) {
130 /* Long option with trailing garbage - no match */
134 /* Consume this argv element */
137 /* If we want an argument but don't have one yet, try to grab
138 * the next argv element
140 if ( ( longopt->has_arg != no_argument ) && ( ! argument ) )
141 argument = get_argv_argument ( argc, argv );
143 /* If we need an argument but don't have one, sulk */
144 if ( ( longopt->has_arg == required_argument ) && ( ! argument ) ) {
145 printf ( "Option \"%s\" requires an argument\n",
151 /* If we have an argument where we shouldn't have one, sulk */
152 if ( ( longopt->has_arg == no_argument ) && argument ) {
153 printf ( "Option \"%s\" takes no argument\n", longopt->name );
158 /* Store values and return success */
159 optarg = ( char * ) argument;
160 if ( longopt->flag ) {
161 *(longopt->flag) = longopt->val;
164 *option = longopt->val;
172 * @v argc Argument count
173 * @v argv Argument list
174 * @v opttext Option text within current argv[] element
175 * @v shortopt Option character from option specification
176 * @ret option Option to return from getopt()
177 * @ret matched Found a match for this short option
179 static int match_short_option ( int argc, char * const argv[],
180 const char *opttext, int shortopt,
181 enum getopt_argument_requirement has_arg,
183 const char *argument = NULL;
185 /* Compare option character */
186 if ( *opttext != shortopt )
189 /* Consume option character */
193 if ( has_arg != no_argument ) {
194 /* Consume remainder of element as inline argument */
200 /* Reached end of argv element */
205 /* If we want an argument but don't have one yet, try to grab
206 * the next argv element
208 if ( ( has_arg != no_argument ) && ( ! argument ) )
209 argument = get_argv_argument ( argc, argv );
211 /* If we need an argument but don't have one, sulk */
212 if ( ( has_arg == required_argument ) && ( ! argument ) ) {
213 printf ( "Option \"%c\" requires an argument\n", shortopt );
218 /* Store values and return success */
219 optarg = ( char * ) argument;
225 * Parse command-line options
227 * @v argc Argument count
228 * @v argv Argument list
229 * @v optstring Option specification string
230 * @v longopts Long option specification table
231 * @ret longindex Index of long option (or NULL)
232 * @ret option Option found, or -1 for no more options
235 int getopt_long ( int argc, char * const argv[], const char *optstring,
236 const struct option *longopts, int *longindex ) {
237 const char *opttext = argv[optind];
238 const struct option *longopt;
240 enum getopt_argument_requirement has_arg;
243 /* Check for end of options */
244 if ( *(opttext++) != '-' )
247 /* Check for long options */
248 if ( *(opttext++) == '-' ) {
249 for ( longopt = longopts ; longopt->name ; longopt++ ) {
250 if ( ! match_long_option ( argc, argv, opttext,
254 *longindex = ( longopt - longopts );
258 printf ( "Unrecognised option \"--%s\"\n", opttext );
262 /* Check for short options */
265 opttext = ( argv[optind] + nextchar );
266 while ( ( shortopt = *(optstring++) ) ) {
267 has_arg = no_argument;
268 while ( *optstring == ':' ) {
272 if ( match_short_option ( argc, argv, opttext, shortopt,
273 has_arg, &option ) ) {
278 printf ( "Unrecognised option \"-%c\"\n", optopt );