[contrib] Allow Network Protocol header to display in rom-o-matic
[gpxe.git] / src / core / getopt.c
blobb67da0c1301a26675751ebe064c96087d84312d5
1 /*
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.
19 FILE_LICENCE ( GPL2_OR_LATER );
21 #include <stdint.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <getopt.h>
26 /** @file
28 * Parse command-line options
32 /**
33 * Option argument
35 * This will point to the argument for the most recently returned
36 * option, if applicable.
38 char *optarg;
40 /**
41 * Current option index
43 * This is an index into the argv[] array. When getopt() returns -1,
44 * @c optind is the index to the first element that is not an option.
46 int optind;
48 /**
49 * Current option character index
51 * This is an index into the current element of argv[].
53 int nextchar;
55 /**
56 * Unrecognised option
58 * When an unrecognised option is encountered, the actual option
59 * character is stored in @c optopt.
61 int optopt;
63 /**
64 * Get option argument from argv[] array
66 * @v argc Argument count
67 * @v argv Argument list
68 * @ret argument Option argument, or NULL
70 * Grab the next element of argv[], if it exists and is not an option.
72 static const char * get_argv_argument ( int argc, char * const argv[] ) {
73 char *arg;
75 /* Don't overrun argv[] */
76 if ( optind >= argc )
77 return NULL;
78 arg = argv[optind];
80 /* If next argv element is an option, then it's not usable as
81 * an argument.
83 if ( *arg == '-' )
84 return NULL;
86 /** Consume this argv element, and return it */
87 optind++;
88 return arg;
91 /**
92 * Match long option
94 * @v argc Argument count
95 * @v argv Argument list
96 * @v opttext Option text within current argv[] element
97 * @v longopt Long option specification
98 * @ret option Option to return from getopt()
99 * @ret matched Found a match for this long option
101 static int match_long_option ( int argc, char * const argv[],
102 const char *opttext,
103 const struct option *longopt, int *option ) {
104 size_t optlen;
105 const char *argument = NULL;
107 /* Compare option name */
108 optlen = strlen ( longopt->name );
109 if ( strncmp ( opttext, longopt->name, optlen ) != 0 )
110 return 0;
112 /* Check for inline argument */
113 if ( opttext[optlen] == '=' ) {
114 argument = &opttext[ optlen + 1 ];
115 } else if ( opttext[optlen] ) {
116 /* Long option with trailing garbage - no match */
117 return 0;
120 /* Consume this argv element */
121 optind++;
123 /* If we want an argument but don't have one yet, try to grab
124 * the next argv element
126 if ( ( longopt->has_arg != no_argument ) && ( ! argument ) )
127 argument = get_argv_argument ( argc, argv );
129 /* If we need an argument but don't have one, sulk */
130 if ( ( longopt->has_arg == required_argument ) && ( ! argument ) ) {
131 printf ( "Option \"%s\" requires an argument\n",
132 longopt->name );
133 *option = ':';
134 return 1;
137 /* If we have an argument where we shouldn't have one, sulk */
138 if ( ( longopt->has_arg == no_argument ) && argument ) {
139 printf ( "Option \"%s\" takes no argument\n", longopt->name );
140 *option = ':';
141 return 1;
144 /* Store values and return success */
145 optarg = ( char * ) argument;
146 if ( longopt->flag ) {
147 *(longopt->flag) = longopt->val;
148 *option = 0;
149 } else {
150 *option = longopt->val;
152 return 1;
156 * Match short option
158 * @v argc Argument count
159 * @v argv Argument list
160 * @v opttext Option text within current argv[] element
161 * @v shortopt Option character from option specification
162 * @ret option Option to return from getopt()
163 * @ret matched Found a match for this short option
165 static int match_short_option ( int argc, char * const argv[],
166 const char *opttext, int shortopt,
167 enum getopt_argument_requirement has_arg,
168 int *option ) {
169 const char *argument = NULL;
171 /* Compare option character */
172 if ( *opttext != shortopt )
173 return 0;
175 /* Consume option character */
176 opttext++;
177 nextchar++;
178 if ( *opttext ) {
179 if ( has_arg != no_argument ) {
180 /* Consume remainder of element as inline argument */
181 argument = opttext;
182 optind++;
183 nextchar = 0;
185 } else {
186 /* Reached end of argv element */
187 optind++;
188 nextchar = 0;
191 /* If we want an argument but don't have one yet, try to grab
192 * the next argv element
194 if ( ( has_arg != no_argument ) && ( ! argument ) )
195 argument = get_argv_argument ( argc, argv );
197 /* If we need an argument but don't have one, sulk */
198 if ( ( has_arg == required_argument ) && ( ! argument ) ) {
199 printf ( "Option \"%c\" requires an argument\n", shortopt );
200 *option = ':';
201 return 1;
204 /* Store values and return success */
205 optarg = ( char * ) argument;
206 *option = shortopt;
207 return 1;
211 * Parse command-line options
213 * @v argc Argument count
214 * @v argv Argument list
215 * @v optstring Option specification string
216 * @v longopts Long option specification table
217 * @ret longindex Index of long option (or NULL)
218 * @ret option Option found, or -1 for no more options
220 * Note that the caller must arrange for reset_getopt() to be called
221 * before each set of calls to getopt_long(). In Etherboot, this is
222 * done automatically by execv().
224 int getopt_long ( int argc, char * const argv[], const char *optstring,
225 const struct option *longopts, int *longindex ) {
226 const char *opttext = argv[optind];
227 const struct option *longopt;
228 int shortopt;
229 enum getopt_argument_requirement has_arg;
230 int option;
232 /* Check for end of argv array */
233 if ( optind >= argc )
234 return -1;
236 /* Check for end of options */
237 if ( *(opttext++) != '-' )
238 return -1;
240 /* Check for long options */
241 if ( *(opttext++) == '-' ) {
242 for ( longopt = longopts ; longopt->name ; longopt++ ) {
243 if ( ! match_long_option ( argc, argv, opttext,
244 longopt, &option ) )
245 continue;
246 if ( longindex )
247 *longindex = ( longopt - longopts );
248 return option;
250 optopt = '?';
251 printf ( "Unrecognised option \"--%s\"\n", opttext );
252 return '?';
255 /* Check for short options */
256 if ( nextchar < 1 )
257 nextchar = 1;
258 opttext = ( argv[optind] + nextchar );
259 while ( ( shortopt = *(optstring++) ) ) {
260 has_arg = no_argument;
261 while ( *optstring == ':' ) {
262 has_arg++;
263 optstring++;
265 if ( match_short_option ( argc, argv, opttext, shortopt,
266 has_arg, &option ) ) {
267 return option;
270 optopt = *opttext;
271 printf ( "Unrecognised option \"-%c\"\n", optopt );
272 return '?';