source: bootcd/isolinux/syslinux-6.03/libinstaller/getopt/getopt_long.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: 3.1 KB
Line 
1/*
2 * getopt.c
3 *
4 * getopt_long(), or at least a common subset thereof:
5 *
6 * - Option reordering is not supported
7 * - -W foo is not supported
8 * - First optstring character "-" not supported.
9 */
10
11#include <stdint.h>
12#include <string.h>
13#include <stddef.h>
14#include <getopt.h>
15
16char *optarg;
17int optind, opterr, optopt;
18static struct getopt_private_state {
19        const char *optptr;
20        const char *last_optstring;
21        char *const *last_argv;
22} pvt;
23
24static inline const char *option_matches(const char *arg_str,
25                                         const char *opt_name)
26{
27        while (*arg_str != '\0' && *arg_str != '=') {
28                if (*arg_str++ != *opt_name++)
29                        return NULL;
30        }
31
32        if (*opt_name)
33                return NULL;
34
35        return arg_str;
36}
37
38int getopt_long(int argc, char *const *argv, const char *optstring,
39                const struct option *longopts, int *longindex)
40{
41        const char *carg;
42        const char *osptr;
43        int opt;
44
45        /* getopt() relies on a number of different global state
46           variables, which can make this really confusing if there is
47           more than one use of getopt() in the same program.  This
48           attempts to detect that situation by detecting if the
49           "optstring" or "argv" argument have changed since last time
50           we were called; if so, reinitialize the query state. */
51
52        if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
53            optind < 1 || optind > argc) {
54                /* optind doesn't match the current query */
55                pvt.last_optstring = optstring;
56                pvt.last_argv = argv;
57                optind = 1;
58                pvt.optptr = NULL;
59        }
60
61        carg = argv[optind];
62
63        /* First, eliminate all non-option cases */
64
65        if (!carg || carg[0] != '-' || !carg[1])
66                return -1;
67
68        if (carg[1] == '-') {
69                const struct option *lo;
70                const char *opt_end = NULL;
71
72                optind++;
73
74                /* Either it's a long option, or it's -- */
75                if (!carg[2]) {
76                        /* It's -- */
77                        return -1;
78                }
79
80                for (lo = longopts; lo->name; lo++) {
81                        if ((opt_end = option_matches(carg+2, lo->name)))
82                            break;
83                }
84                if (!opt_end)
85                        return '?';
86
87                if (longindex)
88                        *longindex = lo-longopts;
89
90                if (*opt_end == '=') {
91                        if (lo->has_arg)
92                                optarg = (char *)opt_end+1;
93                        else
94                                return '?';
95                } else if (lo->has_arg == 1) {
96                        if (!(optarg = argv[optind]))
97                                return '?';
98                        optind++;
99                }
100
101                if (lo->flag) {
102                        *lo->flag = lo->val;
103                        return 0;
104                } else {
105                        return lo->val;
106                }
107        }
108
109        if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
110                /* Someone frobbed optind, change to new opt. */
111                pvt.optptr = carg + 1;
112        }
113
114        opt = *pvt.optptr++;
115
116        if (opt != ':' && (osptr = strchr(optstring, opt))) {
117                if (osptr[1] == ':') {
118                        if (*pvt.optptr) {
119                                /* Argument-taking option with attached
120                                   argument */
121                                optarg = (char *)pvt.optptr;
122                                optind++;
123                        } else {
124                                /* Argument-taking option with non-attached
125                                   argument */
126                                if (argv[optind + 1]) {
127                                        optarg = (char *)argv[optind+1];
128                                        optind += 2;
129                                } else {
130                                        /* Missing argument */
131                                        optind++;
132                                        return (optstring[0] == ':')
133                                                ? ':' : '?';
134                                }
135                        }
136                        return opt;
137                } else {
138                        /* Non-argument-taking option */
139                        /* pvt.optptr will remember the exact position to
140                           resume at */
141                        if (!*pvt.optptr)
142                                optind++;
143                        return opt;
144                }
145        } else {
146                /* Unknown option */
147                optopt = opt;
148                if (!*pvt.optptr)
149                        optind++;
150                return '?';
151        }
152}
Note: See TracBrowser for help on using the repository browser.