xref: /original-bsd/usr.bin/pr/egetopt.c (revision c3e32dec)
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  * %sccs.include.redist.c%
10  */
11 
12 #ifndef lint
13 static char sccsid[] = "@(#)egetopt.c	8.1 (Berkeley) 06/06/93";
14 #endif /* not lint */
15 
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #include "extern.h"
22 
23 /*
24  * egetopt:	get option letter from argument vector (an extended
25  *		version of getopt).
26  *
27  * Non standard additions to the ostr specs are:
28  * 1) '?': immediate value following arg is optional (no white space
29  *    between the arg and the value)
30  * 2) '#': +/- followed by a number (with an optional sign but
31  *    no white space between the arg and the number). The - may be
32  *    combined with other options, but the + cannot.
33  */
34 
35 int	eopterr = 1;		/* if error message should be printed */
36 int	eoptind = 1;		/* index into parent argv vector */
37 int	eoptopt;		/* character checked for validity */
38 char	*eoptarg;		/* argument associated with option */
39 
40 #define	BADCH	(int)'?'
41 #define	EMSG	""
42 
43 int
44 egetopt(nargc, nargv, ostr)
45 	int nargc;
46 	char * const *nargv;
47 	const char *ostr;
48 {
49 	static char *place = EMSG;	/* option letter processing */
50 	register char *oli;		/* option letter list index */
51 	static int delim;		/* which option delimeter */
52 	register char *p;
53 	static char savec = '\0';
54 
55 	if (savec != '\0') {
56 		*place = savec;
57 		savec = '\0';
58 	}
59 
60 	if (!*place) {
61 		/*
62 		 * update scanning pointer
63 		 */
64 		if ((eoptind >= nargc) ||
65 		    ((*(place = nargv[eoptind]) != '-') && (*place != '+'))) {
66 			place = EMSG;
67 			return (EOF);
68 		}
69 
70 		delim = (int)*place;
71 		if (place[1] && *++place == '-' && !place[1]) {
72 			/*
73 			 * found "--"
74 			 */
75 			++eoptind;
76 			place = EMSG;
77 			return (EOF);
78 		}
79 	}
80 
81 	/*
82 	 * check option letter
83 	 */
84 	if ((eoptopt = (int)*place++) == (int)':' || (eoptopt == (int)'?') ||
85 	    !(oli = strchr(ostr, eoptopt))) {
86 		/*
87 		 * if the user didn't specify '-' as an option,
88 		 * assume it means EOF when by itself.
89 		 */
90 		if ((eoptopt == (int)'-') && !*place)
91 			return (EOF);
92 		if (strchr(ostr, '#') && (isdigit(eoptopt) ||
93 		    (((eoptopt == (int)'-') || (eoptopt == (int)'+')) &&
94 		      isdigit(*place)))) {
95 			/*
96 			 * # option: +/- with a number is ok
97 			 */
98 			for (p = place; *p != '\0'; ++p) {
99 				if (!isdigit(*p))
100 					break;
101 			}
102 			eoptarg = place-1;
103 
104 			if (*p == '\0') {
105 				place = EMSG;
106 				++eoptind;
107 			} else {
108 				place = p;
109 				savec = *p;
110 				*place = '\0';
111 			}
112 			return (delim);
113 		}
114 
115 		if (!*place)
116 			++eoptind;
117 		if (eopterr) {
118 			if (!(p = strrchr(*nargv, '/')))
119 				p = *nargv;
120 			else
121 				++p;
122 			(void)fprintf(stderr, "%s: illegal option -- %c\n",
123 			    p, eoptopt);
124 		}
125 		return (BADCH);
126 	}
127 	if (delim == (int)'+') {
128 		/*
129 		 * '+' is only allowed with numbers
130 		 */
131 		if (!*place)
132 			++eoptind;
133 		if (eopterr) {
134 			if (!(p = strrchr(*nargv, '/')))
135 				p = *nargv;
136 			else
137 				++p;
138 			(void)fprintf(stderr,
139 				"%s: illegal '+' delimiter with option -- %c\n",
140 				p, eoptopt);
141 		}
142 		return (BADCH);
143 	}
144 	++oli;
145 	if ((*oli != ':') && (*oli != '?')) {
146 		/*
147 		 * don't need argument
148 		 */
149 		eoptarg = NULL;
150 		if (!*place)
151 			++eoptind;
152 		return (eoptopt);
153 	}
154 
155 	if (*place) {
156 		/*
157 		 * no white space
158 		 */
159 		eoptarg = place;
160 	} else if (*oli == '?') {
161 		/*
162 		 * no arg, but NOT required
163 		 */
164 		eoptarg = NULL;
165 	} else if (nargc <= ++eoptind) {
166 		/*
167 		 * no arg, but IS required
168 		 */
169 		place = EMSG;
170 		if (eopterr) {
171 			if (!(p = strrchr(*nargv, '/')))
172 				p = *nargv;
173 			else
174 				++p;
175 			(void)fprintf(stderr,
176 			    "%s: option requires an argument -- %c\n", p,
177 			    eoptopt);
178 		}
179 		return (BADCH);
180 	} else {
181 		/*
182 		 * arg has white space
183 		 */
184 		eoptarg = nargv[eoptind];
185 	}
186 	place = EMSG;
187 	++eoptind;
188 	return (eoptopt);
189 }
190