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