source: bootcd/isolinux/syslinux-6.03/gpxe/src/core/getopt.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 6.7 KB
Line 
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19FILE_LICENCE ( GPL2_OR_LATER );
20
21#include <stdint.h>
22#include <string.h>
23#include <stdio.h>
24#include <getopt.h>
25
26/** @file
27 *
28 * Parse command-line options
29 *
30 */
31
32/**
33 * Option argument
34 *
35 * This will point to the argument for the most recently returned
36 * option, if applicable.
37 */
38char *optarg;
39
40/**
41 * Current option index
42 *
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.
45 */
46int optind;
47
48/**
49 * Current option character index
50 *
51 * This is an index into the current element of argv[].
52 */
53int nextchar;
54
55/**
56 * Unrecognised option
57 *
58 * When an unrecognised option is encountered, the actual option
59 * character is stored in @c optopt.
60 */
61int optopt;
62
63/**
64 * Get option argument from argv[] array
65 *
66 * @v argc              Argument count
67 * @v argv              Argument list
68 * @ret argument        Option argument, or NULL
69 *
70 * Grab the next element of argv[], if it exists and is not an option.
71 */
72static const char * get_argv_argument ( int argc, char * const argv[] ) {
73        char *arg;
74
75        /* Don't overrun argv[] */
76        if ( optind >= argc )
77                return NULL;
78        arg = argv[optind];
79
80        /* If next argv element is an option, then it's not usable as
81         * an argument.
82         */
83        if ( *arg == '-' )
84                return NULL;
85
86        /** Consume this argv element, and return it */
87        optind++;
88        return arg;
89}
90
91/**
92 * Match long option
93 *
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
100 */
101static 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;
106
107        /* Compare option name */
108        optlen = strlen ( longopt->name );
109        if ( strncmp ( opttext, longopt->name, optlen ) != 0 )
110                return 0;
111
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;
118        }
119
120        /* Consume this argv element */
121        optind++;
122
123        /* If we want an argument but don't have one yet, try to grab
124         * the next argv element
125         */
126        if ( ( longopt->has_arg != no_argument ) && ( ! argument ) )
127                argument = get_argv_argument ( argc, argv );
128
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;
135        }
136
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;
142        }
143
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;
151        }
152        return 1;
153}
154
155/**
156 * Match short option
157 *
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
164 */
165static 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;
170
171        /* Compare option character */
172        if ( *opttext != shortopt )
173                return 0;
174
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;
184                }
185        } else {
186                /* Reached end of argv element */
187                optind++;
188                nextchar = 0;
189        }
190
191        /* If we want an argument but don't have one yet, try to grab
192         * the next argv element
193         */
194        if ( ( has_arg != no_argument ) && ( ! argument ) )
195                argument = get_argv_argument ( argc, argv );
196
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;
202        }
203
204        /* Store values and return success */
205        optarg = ( char * ) argument;
206        *option = shortopt;
207        return 1;
208}
209
210/**
211 * Parse command-line options
212 *
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
219 *
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().
223 */
224int 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;
231
232        /* Check for end of argv array */
233        if ( optind >= argc )
234                return -1;
235
236        /* Check for end of options */
237        if ( *(opttext++) != '-' )
238                return -1;
239
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;
249                }
250                optopt = '?';
251                printf ( "Unrecognised option \"--%s\"\n", opttext );
252                return '?';
253        }
254
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++;
264                }
265                if ( match_short_option ( argc, argv, opttext, shortopt,
266                                          has_arg, &option ) ) {
267                        return option;
268                }
269        }
270        optopt = *opttext;
271        printf ( "Unrecognised option \"-%c\"\n", optopt );
272        return '?';
273}
Note: See TracBrowser for help on using the repository browser.