1258945Sroberto/*
2258945Sroberto * Portions Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
3258945Sroberto * Portions Copyright (C) 1999-2001  Internet Software Consortium.
4258945Sroberto *
5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any
6258945Sroberto * purpose with or without fee is hereby granted, provided that the above
7258945Sroberto * copyright notice and this permission notice appear in all copies.
8258945Sroberto *
9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11258945Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15258945Sroberto * PERFORMANCE OF THIS SOFTWARE.
16258945Sroberto */
17258945Sroberto
18258945Sroberto/*
19258945Sroberto * Copyright (c) 1987, 1993, 1994
20258945Sroberto *	The Regents of the University of California.  All rights reserved.
21258945Sroberto *
22258945Sroberto * Redistribution and use in source and binary forms, with or without
23258945Sroberto * modification, are permitted provided that the following conditions
24258945Sroberto * are met:
25258945Sroberto * 1. Redistributions of source code must retain the above copyright
26258945Sroberto *    notice, this list of conditions and the following disclaimer.
27258945Sroberto * 2. Redistributions in binary form must reproduce the above copyright
28258945Sroberto *    notice, this list of conditions and the following disclaimer in the
29258945Sroberto *    documentation and/or other materials provided with the distribution.
30258945Sroberto * 3. All advertising materials mentioning features or use of this software
31258945Sroberto *    must display the following acknowledgement:
32258945Sroberto *	This product includes software developed by the University of
33258945Sroberto *	California, Berkeley and its contributors.
34258945Sroberto * 4. Neither the name of the University nor the names of its contributors
35258945Sroberto *    may be used to endorse or promote products derived from this software
36258945Sroberto *    without specific prior written permission.
37258945Sroberto *
38258945Sroberto * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
39258945Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40258945Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41258945Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
42258945Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43258945Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44258945Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45258945Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46258945Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47258945Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48258945Sroberto * SUCH DAMAGE.
49258945Sroberto */
50258945Sroberto
51258945Sroberto/* $Id: commandline.c,v 1.22 2008/09/25 04:02:39 tbox Exp $ */
52258945Sroberto
53258945Sroberto/*! \file
54258945Sroberto * This file was adapted from the NetBSD project's source tree, RCS ID:
55258945Sroberto *    NetBSD: getopt.c,v 1.15 1999/09/20 04:39:37 lukem Exp
56258945Sroberto *
57258945Sroberto * The primary change has been to rename items to the ISC namespace
58258945Sroberto * and format in the ISC coding style.
59258945Sroberto */
60258945Sroberto
61258945Sroberto/*
62258945Sroberto * \author Principal Authors: Computer Systems Research Group at UC Berkeley
63258945Sroberto * \author Principal ISC caretaker: DCL
64258945Sroberto */
65258945Sroberto
66258945Sroberto#include <config.h>
67258945Sroberto
68258945Sroberto#include <stdio.h>
69258945Sroberto
70258945Sroberto#include <isc/commandline.h>
71258945Sroberto#include <isc/msgs.h>
72258945Sroberto#include <isc/string.h>
73258945Sroberto#include <isc/util.h>
74258945Sroberto
75258945Sroberto/*% Index into parent argv vector. */
76258945SrobertoLIBISC_EXTERNAL_DATA int isc_commandline_index = 1;
77258945Sroberto/*% Character checked for validity. */
78258945SrobertoLIBISC_EXTERNAL_DATA int isc_commandline_option;
79258945Sroberto/*% Argument associated with option. */
80258945SrobertoLIBISC_EXTERNAL_DATA char *isc_commandline_argument;
81258945Sroberto/*% For printing error messages. */
82258945SrobertoLIBISC_EXTERNAL_DATA char *isc_commandline_progname;
83258945Sroberto/*% Print error messages. */
84258945SrobertoLIBISC_EXTERNAL_DATA isc_boolean_t isc_commandline_errprint = ISC_TRUE;
85258945Sroberto/*% Reset processing. */
86258945SrobertoLIBISC_EXTERNAL_DATA isc_boolean_t isc_commandline_reset = ISC_TRUE;
87258945Sroberto
88258945Srobertostatic char endopt = '\0';
89258945Sroberto
90258945Sroberto#define	BADOPT	'?'
91258945Sroberto#define	BADARG	':'
92258945Sroberto#define ENDOPT  &endopt
93258945Sroberto
94258945Sroberto/*!
95258945Sroberto * getopt --
96258945Sroberto *	Parse argc/argv argument vector.
97258945Sroberto */
98258945Srobertoint
99258945Srobertoisc_commandline_parse(int argc, char * const *argv, const char *options) {
100258945Sroberto	static char *place = ENDOPT;
101258945Sroberto	char *option;			/* Index into *options of option. */
102258945Sroberto
103258945Sroberto	REQUIRE(argc >= 0 && argv != NULL && options != NULL);
104258945Sroberto
105258945Sroberto	/*
106258945Sroberto	 * Update scanning pointer, either because a reset was requested or
107258945Sroberto	 * the previous argv was finished.
108258945Sroberto	 */
109258945Sroberto	if (isc_commandline_reset || *place == '\0') {
110258945Sroberto		if (isc_commandline_reset) {
111258945Sroberto			isc_commandline_index = 1;
112258945Sroberto			isc_commandline_reset = ISC_FALSE;
113258945Sroberto		}
114258945Sroberto
115258945Sroberto		if (isc_commandline_progname == NULL)
116258945Sroberto			isc_commandline_progname = argv[0];
117258945Sroberto
118258945Sroberto		if (isc_commandline_index >= argc ||
119258945Sroberto		    *(place = argv[isc_commandline_index]) != '-') {
120258945Sroberto			/*
121258945Sroberto			 * Index out of range or points to non-option.
122258945Sroberto			 */
123258945Sroberto			place = ENDOPT;
124258945Sroberto			return (-1);
125258945Sroberto		}
126258945Sroberto
127258945Sroberto		if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
128258945Sroberto			/*
129258945Sroberto			 * Found '--' to signal end of options.  Advance
130258945Sroberto			 * index to next argv, the first non-option.
131258945Sroberto			 */
132258945Sroberto			isc_commandline_index++;
133258945Sroberto			place = ENDOPT;
134258945Sroberto			return (-1);
135258945Sroberto		}
136258945Sroberto	}
137258945Sroberto
138258945Sroberto	isc_commandline_option = *place++;
139258945Sroberto	option = strchr(options, isc_commandline_option);
140258945Sroberto
141258945Sroberto	/*
142258945Sroberto	 * Ensure valid option has been passed as specified by options string.
143258945Sroberto	 * '-:' is never a valid command line option because it could not
144258945Sroberto	 * distinguish ':' from the argument specifier in the options string.
145258945Sroberto	 */
146258945Sroberto	if (isc_commandline_option == ':' || option == NULL) {
147258945Sroberto		if (*place == '\0')
148258945Sroberto			isc_commandline_index++;
149258945Sroberto
150258945Sroberto		if (isc_commandline_errprint && *options != ':')
151258945Sroberto			fprintf(stderr, "%s: %s -- %c\n",
152258945Sroberto				isc_commandline_progname,
153258945Sroberto				isc_msgcat_get(isc_msgcat,
154258945Sroberto					       ISC_MSGSET_COMMANDLINE,
155258945Sroberto					       ISC_MSG_ILLEGALOPT,
156258945Sroberto					       "illegal option"),
157258945Sroberto				isc_commandline_option);
158258945Sroberto
159258945Sroberto		return (BADOPT);
160258945Sroberto	}
161258945Sroberto
162258945Sroberto	if (*++option != ':') {
163258945Sroberto		/*
164258945Sroberto		 * Option does not take an argument.
165258945Sroberto		 */
166258945Sroberto		isc_commandline_argument = NULL;
167258945Sroberto
168258945Sroberto		/*
169258945Sroberto		 * Skip to next argv if at the end of the current argv.
170258945Sroberto		 */
171258945Sroberto		if (*place == '\0')
172258945Sroberto			++isc_commandline_index;
173258945Sroberto
174258945Sroberto	} else {
175258945Sroberto		/*
176258945Sroberto		 * Option needs an argument.
177258945Sroberto		 */
178258945Sroberto		if (*place != '\0')
179258945Sroberto			/*
180258945Sroberto			 * Option is in this argv, -D1 style.
181258945Sroberto			 */
182258945Sroberto			isc_commandline_argument = place;
183258945Sroberto
184258945Sroberto		else if (argc > ++isc_commandline_index)
185258945Sroberto			/*
186258945Sroberto			 * Option is next argv, -D 1 style.
187258945Sroberto			 */
188258945Sroberto			isc_commandline_argument = argv[isc_commandline_index];
189258945Sroberto
190258945Sroberto		else {
191258945Sroberto			/*
192258945Sroberto			 * Argument needed, but no more argv.
193258945Sroberto			 */
194258945Sroberto			place = ENDOPT;
195258945Sroberto
196258945Sroberto			/*
197258945Sroberto			 * Silent failure with "missing argument" return
198258945Sroberto			 * when ':' starts options string, per historical spec.
199258945Sroberto			 */
200258945Sroberto			if (*options == ':')
201258945Sroberto				return (BADARG);
202258945Sroberto
203258945Sroberto			if (isc_commandline_errprint)
204258945Sroberto				fprintf(stderr, "%s: %s -- %c\n",
205258945Sroberto					isc_commandline_progname,
206258945Sroberto					isc_msgcat_get(isc_msgcat,
207258945Sroberto						       ISC_MSGSET_COMMANDLINE,
208258945Sroberto						       ISC_MSG_OPTNEEDARG,
209258945Sroberto						       "option requires "
210258945Sroberto						       "an argument"),
211258945Sroberto					isc_commandline_option);
212258945Sroberto
213258945Sroberto			return (BADOPT);
214258945Sroberto		}
215258945Sroberto
216258945Sroberto		place = ENDOPT;
217258945Sroberto
218258945Sroberto		/*
219258945Sroberto		 * Point to argv that follows argument.
220258945Sroberto		 */
221258945Sroberto		isc_commandline_index++;
222258945Sroberto	}
223258945Sroberto
224258945Sroberto	return (isc_commandline_option);
225258945Sroberto}
226