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