getopt_long.c revision 1.3 1 1.1 mcr /*
2 1.1 mcr * Copyright (c) 1987, 1993, 1994, 1996
3 1.1 mcr * The Regents of the University of California. All rights reserved.
4 1.1 mcr *
5 1.1 mcr * Redistribution and use in source and binary forms, with or without
6 1.1 mcr * modification, are permitted provided that the following conditions
7 1.1 mcr * are met:
8 1.1 mcr * 1. Redistributions of source code must retain the above copyright
9 1.1 mcr * notice, this list of conditions and the following disclaimer.
10 1.1 mcr * 2. Redistributions in binary form must reproduce the above copyright
11 1.1 mcr * notice, this list of conditions and the following disclaimer in the
12 1.1 mcr * documentation and/or other materials provided with the distribution.
13 1.1 mcr * 3. All advertising materials mentioning features or use of this software
14 1.1 mcr * must display the following acknowledgement:
15 1.1 mcr * This product includes software developed by the University of
16 1.1 mcr * California, Berkeley and its contributors.
17 1.1 mcr * 4. Neither the name of the University nor the names of its contributors
18 1.1 mcr * may be used to endorse or promote products derived from this software
19 1.1 mcr * without specific prior written permission.
20 1.1 mcr *
21 1.1 mcr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 1.1 mcr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 1.1 mcr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 1.1 mcr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 1.1 mcr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 1.1 mcr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 1.1 mcr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 1.1 mcr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 1.1 mcr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 1.1 mcr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 1.1 mcr * SUCH DAMAGE.
32 1.1 mcr */
33 1.1 mcr
34 1.2 lukem #include <sys/cdefs.h>
35 1.2 lukem
36 1.2 lukem #include <assert.h>
37 1.2 lukem #include <errno.h>
38 1.1 mcr #include <stdio.h>
39 1.1 mcr #include <stdlib.h>
40 1.1 mcr #include <string.h>
41 1.1 mcr #include "getopt.h"
42 1.1 mcr
43 1.1 mcr extern int opterr; /* if error message should be printed */
44 1.1 mcr extern int optind; /* index into parent argv vector */
45 1.1 mcr extern int optopt; /* character checked for validity */
46 1.1 mcr extern int optreset; /* reset getopt */
47 1.1 mcr extern char *optarg; /* argument associated with option */
48 1.1 mcr
49 1.1 mcr static char * __progname __P((char *));
50 1.1 mcr int getopt_internal __P((int, char * const *, const char *));
51 1.1 mcr
52 1.2 lukem static char *
53 1.2 lukem __progname(nargv0)
54 1.2 lukem char * nargv0;
55 1.1 mcr {
56 1.2 lukem char * tmp;
57 1.2 lukem
58 1.2 lukem _DIAGASSERT(nargv0 != NULL);
59 1.2 lukem
60 1.2 lukem tmp = strrchr(nargv0, '/');
61 1.2 lukem if (tmp)
62 1.2 lukem tmp++;
63 1.2 lukem else
64 1.2 lukem tmp = nargv0;
65 1.2 lukem return(tmp);
66 1.1 mcr }
67 1.1 mcr
68 1.1 mcr #define BADCH (int)'?'
69 1.1 mcr #define BADARG (int)':'
70 1.1 mcr #define EMSG ""
71 1.1 mcr
72 1.1 mcr /*
73 1.1 mcr * getopt --
74 1.1 mcr * Parse argc/argv argument vector.
75 1.1 mcr */
76 1.1 mcr int
77 1.1 mcr getopt_internal(nargc, nargv, ostr)
78 1.1 mcr int nargc;
79 1.1 mcr char * const *nargv;
80 1.1 mcr const char *ostr;
81 1.1 mcr {
82 1.1 mcr static char *place = EMSG; /* option letter processing */
83 1.1 mcr char *oli; /* option letter list index */
84 1.1 mcr
85 1.2 lukem _DIAGASSERT(nargv != NULL);
86 1.2 lukem _DIAGASSERT(ostr != NULL);
87 1.2 lukem
88 1.1 mcr if (optreset || !*place) { /* update scanning pointer */
89 1.1 mcr optreset = 0;
90 1.1 mcr if (optind >= nargc || *(place = nargv[optind]) != '-') {
91 1.1 mcr place = EMSG;
92 1.1 mcr return (-1);
93 1.1 mcr }
94 1.1 mcr if (place[1] && *++place == '-') { /* found "--" */
95 1.1 mcr /* ++optind; */
96 1.1 mcr place = EMSG;
97 1.1 mcr return (-2);
98 1.1 mcr }
99 1.1 mcr } /* option letter okay? */
100 1.1 mcr if ((optopt = (int)*place++) == (int)':' ||
101 1.1 mcr !(oli = strchr(ostr, optopt))) {
102 1.1 mcr /*
103 1.1 mcr * if the user didn't specify '-' as an option,
104 1.1 mcr * assume it means -1.
105 1.1 mcr */
106 1.1 mcr if (optopt == (int)'-')
107 1.1 mcr return (-1);
108 1.1 mcr if (!*place)
109 1.1 mcr ++optind;
110 1.1 mcr if (opterr && *ostr != ':')
111 1.1 mcr (void)fprintf(stderr,
112 1.1 mcr "%s: illegal option -- %c\n", __progname(nargv[0]), optopt);
113 1.1 mcr return (BADCH);
114 1.1 mcr }
115 1.1 mcr if (*++oli != ':') { /* don't need argument */
116 1.1 mcr optarg = NULL;
117 1.1 mcr if (!*place)
118 1.1 mcr ++optind;
119 1.1 mcr } else { /* need an argument */
120 1.1 mcr if (*place) /* no white space */
121 1.1 mcr optarg = place;
122 1.1 mcr else if (nargc <= ++optind) { /* no arg */
123 1.1 mcr place = EMSG;
124 1.1 mcr if ((opterr) && (*ostr != ':'))
125 1.1 mcr (void)fprintf(stderr,
126 1.1 mcr "%s: option requires an argument -- %c\n",
127 1.1 mcr __progname(nargv[0]), optopt);
128 1.1 mcr return (BADARG);
129 1.1 mcr } else /* white space */
130 1.1 mcr optarg = nargv[optind];
131 1.1 mcr place = EMSG;
132 1.1 mcr ++optind;
133 1.1 mcr }
134 1.1 mcr return (optopt); /* dump back option letter */
135 1.1 mcr }
136 1.1 mcr
137 1.1 mcr #if 0
138 1.1 mcr /*
139 1.1 mcr * getopt --
140 1.1 mcr * Parse argc/argv argument vector.
141 1.1 mcr */
142 1.1 mcr int
143 1.1 mcr getopt2(nargc, nargv, ostr)
144 1.1 mcr int nargc;
145 1.1 mcr char * const *nargv;
146 1.1 mcr const char *ostr;
147 1.1 mcr {
148 1.1 mcr int retval;
149 1.1 mcr
150 1.1 mcr if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) {
151 1.1 mcr retval = -1;
152 1.1 mcr ++optind;
153 1.1 mcr }
154 1.1 mcr return(retval);
155 1.1 mcr }
156 1.1 mcr #endif
157 1.1 mcr
158 1.1 mcr /*
159 1.1 mcr * getopt_long --
160 1.1 mcr * Parse argc/argv argument vector.
161 1.1 mcr */
162 1.1 mcr int
163 1.1 mcr getopt_long(nargc, nargv, options, long_options, index)
164 1.2 lukem int nargc;
165 1.2 lukem char ** nargv;
166 1.2 lukem char * options;
167 1.2 lukem struct option * long_options;
168 1.2 lukem int * index;
169 1.1 mcr {
170 1.1 mcr int retval;
171 1.1 mcr
172 1.2 lukem _DIAGASSERT(nargv != NULL);
173 1.2 lukem _DIAGASSERT(ostr != NULL);
174 1.2 lukem _DIAGASSERT(long_options != NULL);
175 1.2 lukem /* index may be NULL */
176 1.2 lukem
177 1.1 mcr if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
178 1.1 mcr char *current_argv = nargv[optind++] + 2, *has_equal;
179 1.1 mcr int i, current_argv_len, match = -1;
180 1.1 mcr
181 1.1 mcr if (*current_argv == '\0') {
182 1.1 mcr return(-1);
183 1.1 mcr }
184 1.1 mcr if ((has_equal = strchr(current_argv, '=')) != NULL) {
185 1.1 mcr current_argv_len = has_equal - current_argv;
186 1.1 mcr has_equal++;
187 1.1 mcr } else
188 1.1 mcr current_argv_len = strlen(current_argv);
189 1.1 mcr
190 1.1 mcr for (i = 0; long_options[i].name; i++) {
191 1.1 mcr if (strncmp(current_argv, long_options[i].name, current_argv_len))
192 1.1 mcr continue;
193 1.1 mcr
194 1.1 mcr if (strlen(long_options[i].name) == (unsigned)current_argv_len) {
195 1.1 mcr match = i;
196 1.1 mcr break;
197 1.1 mcr }
198 1.1 mcr if (match == -1)
199 1.1 mcr match = i;
200 1.1 mcr }
201 1.1 mcr if (match != -1) {
202 1.1 mcr if (long_options[match].has_arg == required_argument ||
203 1.1 mcr long_options[match].has_arg == optional_argument) {
204 1.1 mcr if (has_equal)
205 1.1 mcr optarg = has_equal;
206 1.1 mcr else
207 1.1 mcr optarg = nargv[optind++];
208 1.1 mcr }
209 1.1 mcr if ((long_options[match].has_arg == required_argument)
210 1.1 mcr && (optarg == NULL)) {
211 1.1 mcr /*
212 1.1 mcr * Missing argument, leading :
213 1.1 mcr * indicates no error should be generated
214 1.1 mcr */
215 1.1 mcr if ((opterr) && (*options != ':'))
216 1.1 mcr (void)fprintf(stderr,
217 1.1 mcr "%s: option requires an argument -- %s\n",
218 1.1 mcr __progname(nargv[0]), current_argv);
219 1.1 mcr return (BADARG);
220 1.1 mcr }
221 1.1 mcr } else { /* No matching argument */
222 1.1 mcr if ((opterr) && (*options != ':'))
223 1.1 mcr (void)fprintf(stderr,
224 1.1 mcr "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv);
225 1.1 mcr return (BADCH);
226 1.1 mcr }
227 1.1 mcr if (long_options[match].flag) {
228 1.1 mcr *long_options[match].flag = long_options[match].val;
229 1.1 mcr retval = 0;
230 1.1 mcr } else
231 1.1 mcr retval = long_options[match].val;
232 1.1 mcr if (index)
233 1.1 mcr *index = match;
234 1.1 mcr }
235 1.1 mcr return(retval);
236 1.1 mcr }
237