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