xref: /dragonfly/usr.bin/pr/egetopt.c (revision 36a3d1d6)
1 /*-
2  * Copyright (c) 1991 Keith Muller.
3  * Copyright (c) 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Keith Muller of the University of California, San Diego.
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. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by the University of
20  *	California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  * @(#)egetopt.c	8.1 (Berkeley) 6/6/93
38  *
39  * $DragonFly: src/usr.bin/pr/egetopt.c,v 1.4 2008/10/16 01:52:32 swildner Exp $
40  */
41 
42 #include <ctype.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 
47 #include "extern.h"
48 
49 /*
50  * egetopt:	get option letter from argument vector (an extended
51  *		version of getopt).
52  *
53  * Non standard additions to the ostr specs are:
54  * 1) '?': immediate value following arg is optional (no white space
55  *    between the arg and the value)
56  * 2) '#': +/- followed by a number (with an optional sign but
57  *    no white space between the arg and the number). The - may be
58  *    combined with other options, but the + cannot.
59  */
60 
61 int	eopterr = 1;		/* if error message should be printed */
62 int	eoptind = 1;		/* index into parent argv vector */
63 int	eoptopt;		/* character checked for validity */
64 char	*eoptarg;		/* argument associated with option */
65 
66 #define	BADCH	(int)'?'
67 #define	EMSG	""
68 
69 int
70 egetopt(int nargc, char * const *nargv, const char *ostr)
71 {
72 	static char *place = EMSG;	/* option letter processing */
73 	char *oli;			/* option letter list index */
74 	static int delim;		/* which option delimeter */
75 	char *p;
76 	static char savec = '\0';
77 
78 	if (savec != '\0') {
79 		*place = savec;
80 		savec = '\0';
81 	}
82 
83 	if (!*place) {
84 		/*
85 		 * update scanning pointer
86 		 */
87 		if ((eoptind >= nargc) ||
88 		    ((*(place = nargv[eoptind]) != '-') && (*place != '+'))) {
89 			place = EMSG;
90 			return (EOF);
91 		}
92 
93 		delim = (int)*place;
94 		if (place[1] && *++place == '-' && !place[1]) {
95 			/*
96 			 * found "--"
97 			 */
98 			++eoptind;
99 			place = EMSG;
100 			return (EOF);
101 		}
102 	}
103 
104 	/*
105 	 * check option letter
106 	 */
107 	if ((eoptopt = (int)*place++) == (int)':' || (eoptopt == (int)'?') ||
108 	    !(oli = strchr(ostr, eoptopt))) {
109 		/*
110 		 * if the user didn't specify '-' as an option,
111 		 * assume it means EOF when by itself.
112 		 */
113 		if ((eoptopt == (int)'-') && !*place)
114 			return (EOF);
115 		if (strchr(ostr, '#') && (isdigit(eoptopt) ||
116 		    (((eoptopt == (int)'-') || (eoptopt == (int)'+')) &&
117 		      isdigit(*place)))) {
118 			/*
119 			 * # option: +/- with a number is ok
120 			 */
121 			for (p = place; *p != '\0'; ++p) {
122 				if (!isdigit(*p))
123 					break;
124 			}
125 			eoptarg = place-1;
126 
127 			if (*p == '\0') {
128 				place = EMSG;
129 				++eoptind;
130 			} else {
131 				place = p;
132 				savec = *p;
133 				*place = '\0';
134 			}
135 			return (delim);
136 		}
137 
138 		if (!*place)
139 			++eoptind;
140 		if (eopterr) {
141 			if (!(p = strrchr(*nargv, '/')))
142 				p = *nargv;
143 			else
144 				++p;
145 			(void)fprintf(stderr, "%s: illegal option -- %c\n",
146 			    p, eoptopt);
147 		}
148 		return (BADCH);
149 	}
150 	if (delim == (int)'+') {
151 		/*
152 		 * '+' is only allowed with numbers
153 		 */
154 		if (!*place)
155 			++eoptind;
156 		if (eopterr) {
157 			if (!(p = strrchr(*nargv, '/')))
158 				p = *nargv;
159 			else
160 				++p;
161 			(void)fprintf(stderr,
162 				"%s: illegal '+' delimiter with option -- %c\n",
163 				p, eoptopt);
164 		}
165 		return (BADCH);
166 	}
167 	++oli;
168 	if ((*oli != ':') && (*oli != '?')) {
169 		/*
170 		 * don't need argument
171 		 */
172 		eoptarg = NULL;
173 		if (!*place)
174 			++eoptind;
175 		return (eoptopt);
176 	}
177 
178 	if (*place) {
179 		/*
180 		 * no white space
181 		 */
182 		eoptarg = place;
183 	} else if (*oli == '?') {
184 		/*
185 		 * no arg, but NOT required
186 		 */
187 		eoptarg = NULL;
188 	} else if (nargc <= ++eoptind) {
189 		/*
190 		 * no arg, but IS required
191 		 */
192 		place = EMSG;
193 		if (eopterr) {
194 			if (!(p = strrchr(*nargv, '/')))
195 				p = *nargv;
196 			else
197 				++p;
198 			(void)fprintf(stderr,
199 			    "%s: option requires an argument -- %c\n", p,
200 			    eoptopt);
201 		}
202 		return (BADCH);
203 	} else {
204 		/*
205 		 * arg has white space
206 		 */
207 		eoptarg = nargv[eoptind];
208 	}
209 	place = EMSG;
210 	++eoptind;
211 	return (eoptopt);
212 }
213