xref: /netbsd-src/common/lib/libc/stdlib/getopt.c (revision f77396c90347ac2cf626f1ad822fbb0db8a8b11e)
1*f77396c9Srin /*	$NetBSD: getopt.c,v 1.2 2024/06/29 07:56:56 rin Exp $	*/
230d0c2dbSrin 
330d0c2dbSrin /*
430d0c2dbSrin  * Copyright (c) 1987, 1993, 1994
530d0c2dbSrin  *	The Regents of the University of California.  All rights reserved.
630d0c2dbSrin  *
730d0c2dbSrin  * Redistribution and use in source and binary forms, with or without
830d0c2dbSrin  * modification, are permitted provided that the following conditions
930d0c2dbSrin  * are met:
1030d0c2dbSrin  * 1. Redistributions of source code must retain the above copyright
1130d0c2dbSrin  *    notice, this list of conditions and the following disclaimer.
1230d0c2dbSrin  * 2. Redistributions in binary form must reproduce the above copyright
1330d0c2dbSrin  *    notice, this list of conditions and the following disclaimer in the
1430d0c2dbSrin  *    documentation and/or other materials provided with the distribution.
1530d0c2dbSrin  * 3. Neither the name of the University nor the names of its contributors
1630d0c2dbSrin  *    may be used to endorse or promote products derived from this software
1730d0c2dbSrin  *    without specific prior written permission.
1830d0c2dbSrin  *
1930d0c2dbSrin  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2030d0c2dbSrin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2130d0c2dbSrin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2230d0c2dbSrin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2330d0c2dbSrin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2430d0c2dbSrin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2530d0c2dbSrin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2630d0c2dbSrin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2730d0c2dbSrin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2830d0c2dbSrin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2930d0c2dbSrin  * SUCH DAMAGE.
3030d0c2dbSrin  */
3130d0c2dbSrin 
3230d0c2dbSrin #include <sys/cdefs.h>
33*f77396c9Srin __RCSID("$NetBSD: getopt.c,v 1.2 2024/06/29 07:56:56 rin Exp $");
34*f77396c9Srin 
35*f77396c9Srin #if defined(_KERNEL) || defined(_STANDALONE)
36*f77396c9Srin 
37*f77396c9Srin #include <lib/libsa/stand.h>
38*f77396c9Srin #include <lib/libkern/libkern.h>
39*f77396c9Srin 
40*f77396c9Srin #define	EPRINTF(fmt, args...)	printf(fmt, ##args)
41*f77396c9Srin 
42*f77396c9Srin #else
4330d0c2dbSrin 
4430d0c2dbSrin #include "namespace.h"
4530d0c2dbSrin 
4630d0c2dbSrin #include <assert.h>
4730d0c2dbSrin #include <errno.h>
4830d0c2dbSrin #include <stdio.h>
4930d0c2dbSrin #include <stdlib.h>
5030d0c2dbSrin #include <string.h>
5130d0c2dbSrin #include <unistd.h>
5230d0c2dbSrin 
5330d0c2dbSrin #ifdef __weak_alias
5430d0c2dbSrin __weak_alias(getopt,_getopt)
5530d0c2dbSrin #endif
5630d0c2dbSrin 
57*f77396c9Srin #define	EPRINTF(fmt, args...)						\
58*f77396c9Srin     fprintf(stderr, "%s: " fmt, getprogname(), ##args)
59*f77396c9Srin 
60*f77396c9Srin #endif /* !_KERNEL && !_STANDALONE */
61*f77396c9Srin 
6230d0c2dbSrin int	opterr = 1,		/* if error message should be printed */
6330d0c2dbSrin 	optind = 1,		/* index into parent argv vector */
6430d0c2dbSrin 	optopt,			/* character checked for validity */
6530d0c2dbSrin 	optreset;		/* reset getopt */
6630d0c2dbSrin char	*optarg;		/* argument associated with option */
6730d0c2dbSrin 
6830d0c2dbSrin #define	BADCH	(int)'?'
6930d0c2dbSrin #define	BADARG	(int)':'
7030d0c2dbSrin #define	EMSG	""
7130d0c2dbSrin 
7230d0c2dbSrin /*
7330d0c2dbSrin  * getopt --
7430d0c2dbSrin  *	Parse argc/argv argument vector.
7530d0c2dbSrin  */
7630d0c2dbSrin int
getopt(int nargc,char * const nargv[],const char * ostr)7730d0c2dbSrin getopt(int nargc, char * const nargv[], const char *ostr)
7830d0c2dbSrin {
7930d0c2dbSrin 	static const char *place = EMSG;	/* option letter processing */
8030d0c2dbSrin 	const char *oli;			/* option letter list index */
8130d0c2dbSrin 
8230d0c2dbSrin 	_DIAGASSERT(nargv != NULL);
8330d0c2dbSrin 	_DIAGASSERT(ostr != NULL);
8430d0c2dbSrin 
8530d0c2dbSrin 	if (optreset || *place == 0) {		/* update scanning pointer */
8630d0c2dbSrin 		optreset = 0;
8730d0c2dbSrin 		place = nargv[optind];
8830d0c2dbSrin 		if (optind >= nargc || *place++ != '-') {
8930d0c2dbSrin 			/* Argument is absent or is not an option */
9030d0c2dbSrin 			place = EMSG;
9130d0c2dbSrin 			return (-1);
9230d0c2dbSrin 		}
9330d0c2dbSrin 		optopt = *place++;
9430d0c2dbSrin 		if (optopt == '-' && *place == 0) {
9530d0c2dbSrin 			/* "--" => end of options */
9630d0c2dbSrin 			++optind;
9730d0c2dbSrin 			place = EMSG;
9830d0c2dbSrin 			return (-1);
9930d0c2dbSrin 		}
10030d0c2dbSrin 		if (optopt == 0) {
10130d0c2dbSrin 			/* Solitary '-', treat as a '-' option
10230d0c2dbSrin 			   if the program (eg su) is looking for it. */
10330d0c2dbSrin 			place = EMSG;
10430d0c2dbSrin 			if (strchr(ostr, '-') == NULL)
10530d0c2dbSrin 				return -1;
10630d0c2dbSrin 			optopt = '-';
10730d0c2dbSrin 		}
10830d0c2dbSrin 	} else
10930d0c2dbSrin 		optopt = *place++;
11030d0c2dbSrin 
11130d0c2dbSrin 	/* See if option letter is one the caller wanted... */
11230d0c2dbSrin 	if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
11330d0c2dbSrin 		if (*place == 0)
11430d0c2dbSrin 			++optind;
11530d0c2dbSrin 		if (opterr && *ostr != ':')
116*f77396c9Srin 			(void)EPRINTF("unknown option -- %c\n", optopt);
11730d0c2dbSrin 		return (BADCH);
11830d0c2dbSrin 	}
11930d0c2dbSrin 
12030d0c2dbSrin 	/* Does this option need an argument? */
12130d0c2dbSrin 	if (oli[1] != ':') {
12230d0c2dbSrin 		/* don't need argument */
12330d0c2dbSrin 		optarg = NULL;
12430d0c2dbSrin 		if (*place == 0)
12530d0c2dbSrin 			++optind;
12630d0c2dbSrin 	} else {
12730d0c2dbSrin 		/* Option-argument is either the rest of this argument or the
12830d0c2dbSrin 		   entire next argument. */
12930d0c2dbSrin 		if (*place)
13030d0c2dbSrin 			optarg = __UNCONST(place);
13130d0c2dbSrin 		else if (oli[2] == ':')
13230d0c2dbSrin 			/*
13330d0c2dbSrin 			 * GNU Extension, for optional arguments if the rest of
13430d0c2dbSrin 			 * the argument is empty, we return NULL
13530d0c2dbSrin 			 */
13630d0c2dbSrin 			optarg = NULL;
13730d0c2dbSrin 		else if (nargc > ++optind)
13830d0c2dbSrin 			optarg = nargv[optind];
13930d0c2dbSrin 		else {
14030d0c2dbSrin 			/* option-argument absent */
14130d0c2dbSrin 			place = EMSG;
14230d0c2dbSrin 			if (*ostr == ':')
14330d0c2dbSrin 				return (BADARG);
14430d0c2dbSrin 			if (opterr)
145*f77396c9Srin 				(void)EPRINTF(
146*f77396c9Srin 				    "option requires an argument -- %c\n",
147*f77396c9Srin 				    optopt);
14830d0c2dbSrin 			return (BADCH);
14930d0c2dbSrin 		}
15030d0c2dbSrin 		place = EMSG;
15130d0c2dbSrin 		++optind;
15230d0c2dbSrin 	}
15330d0c2dbSrin 	return (optopt);			/* return option letter */
15430d0c2dbSrin }
155