1/*	$NetBSD: getopt.c,v 1.29 2014/06/05 22:00:22 christos Exp $	*/
2
3/*-
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Copyright (c) 1987, 1993, 1994
7 *	The Regents of the University of California.  All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if defined(LIBC_SCCS) && !defined(lint)
35static char sccsid[] = "@(#)getopt.c	8.3 (Berkeley) 4/27/95";
36#endif /* LIBC_SCCS and not lint */
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD$");
39
40#include "namespace.h"
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45#include "un-namespace.h"
46
47#include "libc_private.h"
48
49int	opterr = 1,		/* if error message should be printed */
50	optind = 1,		/* index into parent argv vector */
51	optopt,			/* character checked for validity */
52	optreset;		/* reset getopt */
53char	*optarg;		/* argument associated with option */
54
55#define	BADCH	(int)'?'
56#define	BADARG	(int)':'
57#define	EMSG	""
58
59/*
60 * getopt --
61 *	Parse argc/argv argument vector.
62 */
63int
64getopt(int nargc, char * const nargv[], const char *ostr)
65{
66	static char *place = EMSG;		/* option letter processing */
67	char *oli;				/* option letter list index */
68
69	if (optreset || *place == 0) {		/* update scanning pointer */
70		optreset = 0;
71		place = nargv[optind];
72		if (optind >= nargc || *place++ != '-') {
73			/* Argument is absent or is not an option */
74			place = EMSG;
75			return (-1);
76		}
77		optopt = *place++;
78		if (optopt == '-' && *place == 0) {
79			/* "--" => end of options */
80			++optind;
81			place = EMSG;
82			return (-1);
83		}
84		if (optopt == 0) {
85			/* Solitary '-', treat as a '-' option
86			   if the program (eg su) is looking for it. */
87			place = EMSG;
88			if (strchr(ostr, '-') == NULL)
89				return (-1);
90			optopt = '-';
91		}
92	} else
93		optopt = *place++;
94
95	/* See if option letter is one the caller wanted... */
96	if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
97		if (*place == 0)
98			++optind;
99		if (opterr && *ostr != ':')
100			(void)fprintf(stderr,
101			    "%s: illegal option -- %c\n", _getprogname(),
102			    optopt);
103		return (BADCH);
104	}
105
106	/* Does this option need an argument? */
107	if (oli[1] != ':') {
108		/* don't need argument */
109		optarg = NULL;
110		if (*place == 0)
111			++optind;
112	} else {
113		/* Option-argument is either the rest of this argument or the
114		   entire next argument. */
115		if (*place)
116			optarg = place;
117		else if (oli[2] == ':')
118			/*
119			 * GNU Extension, for optional arguments if the rest of
120			 * the argument is empty, we return NULL
121			 */
122			optarg = NULL;
123		else if (nargc > ++optind)
124			optarg = nargv[optind];
125		else {
126			/* option-argument absent */
127			place = EMSG;
128			if (*ostr == ':')
129				return (BADARG);
130			if (opterr)
131				(void)fprintf(stderr,
132				    "%s: option requires an argument -- %c\n",
133				    _getprogname(), optopt);
134			return (BADCH);
135		}
136		place = EMSG;
137		++optind;
138	}
139	return (optopt);			/* return option letter */
140}
141