egetopt.c revision 98552
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1991 Keith Muller.
31590Srgrimes * Copyright (c) 1993
41590Srgrimes *	The Regents of the University of California.  All rights reserved.
51590Srgrimes *
61590Srgrimes * This code is derived from software contributed to Berkeley by
71590Srgrimes * Keith Muller of the University of California, San Diego.
81590Srgrimes *
91590Srgrimes * Redistribution and use in source and binary forms, with or without
101590Srgrimes * modification, are permitted provided that the following conditions
111590Srgrimes * are met:
121590Srgrimes * 1. Redistributions of source code must retain the above copyright
131590Srgrimes *    notice, this list of conditions and the following disclaimer.
141590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151590Srgrimes *    notice, this list of conditions and the following disclaimer in the
161590Srgrimes *    documentation and/or other materials provided with the distribution.
171590Srgrimes * 3. All advertising materials mentioning features or use of this software
181590Srgrimes *    must display the following acknowledgement:
191590Srgrimes *	This product includes software developed by the University of
201590Srgrimes *	California, Berkeley and its contributors.
211590Srgrimes * 4. Neither the name of the University nor the names of its contributors
221590Srgrimes *    may be used to endorse or promote products derived from this software
231590Srgrimes *    without specific prior written permission.
241590Srgrimes *
251590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351590Srgrimes * SUCH DAMAGE.
361590Srgrimes */
371590Srgrimes
3898552Smarkm#if 0
391590Srgrimes#ifndef lint
401590Srgrimesstatic char sccsid[] = "@(#)egetopt.c	8.1 (Berkeley) 6/6/93";
411590Srgrimes#endif /* not lint */
4298552Smarkm#endif
431590Srgrimes
4498552Smarkm#include <sys/cdefs.h>
4598552Smarkm__FBSDID("$FreeBSD: head/usr.bin/pr/egetopt.c 98552 2002-06-21 10:14:57Z markm $");
4698552Smarkm
471590Srgrimes#include <ctype.h>
481590Srgrimes#include <stdio.h>
491590Srgrimes#include <stdlib.h>
501590Srgrimes#include <string.h>
511590Srgrimes
521590Srgrimes#include "extern.h"
531590Srgrimes
541590Srgrimes/*
551590Srgrimes * egetopt:	get option letter from argument vector (an extended
561590Srgrimes *		version of getopt).
571590Srgrimes *
581590Srgrimes * Non standard additions to the ostr specs are:
591590Srgrimes * 1) '?': immediate value following arg is optional (no white space
601590Srgrimes *    between the arg and the value)
611590Srgrimes * 2) '#': +/- followed by a number (with an optional sign but
621590Srgrimes *    no white space between the arg and the number). The - may be
631590Srgrimes *    combined with other options, but the + cannot.
641590Srgrimes */
651590Srgrimes
661590Srgrimesint	eopterr = 1;		/* if error message should be printed */
671590Srgrimesint	eoptind = 1;		/* index into parent argv vector */
681590Srgrimesint	eoptopt;		/* character checked for validity */
691590Srgrimeschar	*eoptarg;		/* argument associated with option */
701590Srgrimes
711590Srgrimes#define	BADCH	(int)'?'
721590Srgrimes
7398552Smarkmstatic char	emsg[] = "";
7498552Smarkm
751590Srgrimesint
7698552Smarkmegetopt(int nargc, char * const *nargv, const char *ostr)
771590Srgrimes{
7898552Smarkm	static char *place = emsg;	/* option letter processing */
7998552Smarkm	char *oli;			/* option letter list index */
801590Srgrimes	static int delim;		/* which option delimeter */
8198552Smarkm	char *p;
821590Srgrimes	static char savec = '\0';
831590Srgrimes
841590Srgrimes	if (savec != '\0') {
851590Srgrimes		*place = savec;
861590Srgrimes		savec = '\0';
871590Srgrimes	}
881590Srgrimes
891590Srgrimes	if (!*place) {
901590Srgrimes		/*
911590Srgrimes		 * update scanning pointer
921590Srgrimes		 */
931590Srgrimes		if ((eoptind >= nargc) ||
941590Srgrimes		    ((*(place = nargv[eoptind]) != '-') && (*place != '+'))) {
9598552Smarkm			place = emsg;
961590Srgrimes			return (EOF);
971590Srgrimes		}
981590Srgrimes
991590Srgrimes		delim = (int)*place;
1001590Srgrimes		if (place[1] && *++place == '-' && !place[1]) {
1011590Srgrimes			/*
1021590Srgrimes			 * found "--"
1031590Srgrimes			 */
1041590Srgrimes			++eoptind;
10598552Smarkm			place = emsg;
1061590Srgrimes			return (EOF);
1071590Srgrimes		}
1081590Srgrimes	}
1091590Srgrimes
1101590Srgrimes	/*
1111590Srgrimes	 * check option letter
1121590Srgrimes	 */
1131590Srgrimes	if ((eoptopt = (int)*place++) == (int)':' || (eoptopt == (int)'?') ||
1141590Srgrimes	    !(oli = strchr(ostr, eoptopt))) {
1151590Srgrimes		/*
1161590Srgrimes		 * if the user didn't specify '-' as an option,
1171590Srgrimes		 * assume it means EOF when by itself.
1181590Srgrimes		 */
1191590Srgrimes		if ((eoptopt == (int)'-') && !*place)
1201590Srgrimes			return (EOF);
1211590Srgrimes		if (strchr(ostr, '#') && (isdigit(eoptopt) ||
1221590Srgrimes		    (((eoptopt == (int)'-') || (eoptopt == (int)'+')) &&
1231590Srgrimes		      isdigit(*place)))) {
1241590Srgrimes			/*
1251590Srgrimes			 * # option: +/- with a number is ok
1261590Srgrimes			 */
1271590Srgrimes			for (p = place; *p != '\0'; ++p) {
1281590Srgrimes				if (!isdigit(*p))
1291590Srgrimes					break;
1301590Srgrimes			}
1311590Srgrimes			eoptarg = place-1;
1321590Srgrimes
1331590Srgrimes			if (*p == '\0') {
13498552Smarkm				place = emsg;
1351590Srgrimes				++eoptind;
1361590Srgrimes			} else {
1371590Srgrimes				place = p;
1381590Srgrimes				savec = *p;
1391590Srgrimes				*place = '\0';
1401590Srgrimes			}
1411590Srgrimes			return (delim);
1421590Srgrimes		}
1431590Srgrimes
1441590Srgrimes		if (!*place)
1451590Srgrimes			++eoptind;
1461590Srgrimes		if (eopterr) {
1471590Srgrimes			if (!(p = strrchr(*nargv, '/')))
1481590Srgrimes				p = *nargv;
1491590Srgrimes			else
1501590Srgrimes				++p;
1511590Srgrimes			(void)fprintf(stderr, "%s: illegal option -- %c\n",
1521590Srgrimes			    p, eoptopt);
1531590Srgrimes		}
1541590Srgrimes		return (BADCH);
1551590Srgrimes	}
1561590Srgrimes	if (delim == (int)'+') {
1571590Srgrimes		/*
1581590Srgrimes		 * '+' is only allowed with numbers
1591590Srgrimes		 */
1601590Srgrimes		if (!*place)
1611590Srgrimes			++eoptind;
1621590Srgrimes		if (eopterr) {
1631590Srgrimes			if (!(p = strrchr(*nargv, '/')))
1641590Srgrimes				p = *nargv;
1651590Srgrimes			else
1661590Srgrimes				++p;
1671590Srgrimes			(void)fprintf(stderr,
1681590Srgrimes				"%s: illegal '+' delimiter with option -- %c\n",
1691590Srgrimes				p, eoptopt);
1701590Srgrimes		}
1711590Srgrimes		return (BADCH);
1721590Srgrimes	}
1731590Srgrimes	++oli;
1741590Srgrimes	if ((*oli != ':') && (*oli != '?')) {
1751590Srgrimes		/*
1761590Srgrimes		 * don't need argument
1771590Srgrimes		 */
1781590Srgrimes		eoptarg = NULL;
1791590Srgrimes		if (!*place)
1801590Srgrimes			++eoptind;
1811590Srgrimes		return (eoptopt);
1821590Srgrimes	}
1831590Srgrimes
1841590Srgrimes	if (*place) {
1851590Srgrimes		/*
1861590Srgrimes		 * no white space
1871590Srgrimes		 */
1881590Srgrimes		eoptarg = place;
1891590Srgrimes	} else if (*oli == '?') {
1901590Srgrimes		/*
1911590Srgrimes		 * no arg, but NOT required
1921590Srgrimes		 */
1931590Srgrimes		eoptarg = NULL;
1941590Srgrimes	} else if (nargc <= ++eoptind) {
1951590Srgrimes		/*
1961590Srgrimes		 * no arg, but IS required
1971590Srgrimes		 */
19898552Smarkm		place = emsg;
1991590Srgrimes		if (eopterr) {
2001590Srgrimes			if (!(p = strrchr(*nargv, '/')))
2011590Srgrimes				p = *nargv;
2021590Srgrimes			else
2031590Srgrimes				++p;
2041590Srgrimes			(void)fprintf(stderr,
2051590Srgrimes			    "%s: option requires an argument -- %c\n", p,
2061590Srgrimes			    eoptopt);
2071590Srgrimes		}
2081590Srgrimes		return (BADCH);
2091590Srgrimes	} else {
2101590Srgrimes		/*
2111590Srgrimes		 * arg has white space
2121590Srgrimes		 */
2131590Srgrimes		eoptarg = nargv[eoptind];
2141590Srgrimes	}
21598552Smarkm	place = emsg;
2161590Srgrimes	++eoptind;
2171590Srgrimes	return (eoptopt);
2181590Srgrimes}
219