import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / gen / getopt.c
blob5a064f327b5684e3f5f2238e62b2d26ff3c370b3
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
32 * See getopt(3C) and SUS/XPG getopt() for function definition and
33 * requirements.
35 * This actual implementation is a bit looser than the specification
36 * as it allows any character other than ':' and '(' to be used as
37 * a short option character - The specification only guarantees the
38 * alnum characters ([a-z][A-Z][0-9]).
41 #pragma weak _getopt = getopt
43 #include "lint.h"
44 #include "_libc_gettext.h"
46 #include <unistd.h>
47 #include <string.h>
48 #include <stdio.h>
51 * Generalized error processing macro. The parameter i is a pointer to
52 * the failed option string. If it is NULL, the character in c is converted
53 * to a string and displayed instead. s is the error text.
55 * This could be / should be a static function if it is used more, but
56 * that would require moving the 'optstring[0]' test outside of the
57 * function.
59 #define ERR(s, c, i) if (opterr && optstring[0] != ':') { \
60 char errbuf[256]; \
61 char cbuf[2]; \
62 cbuf[0] = c; \
63 cbuf[1] = '\0'; \
64 (void) snprintf(errbuf, sizeof (errbuf), s, argv[0], \
65 (i ? argv[i]+2 : cbuf)); \
66 (void) write(2, errbuf, strlen(errbuf)); }
69 * _sp is required to keep state between successive calls to getopt() while
70 * extracting aggregated short-options (ie: -abcd). Hence, getopt() is not
71 * thread safe or reentrant, but it really doesn't matter.
73 * So, why isn't this "static" you ask? Because the historical Bourne
74 * shell has actually latched on to this little piece of private data.
76 int _sp = 1;
79 * Determine if the specified character (c) is present in the string
80 * (optstring) as a regular, single character option. If the option is found,
81 * return a pointer into optstring pointing at the short-option character,
82 * otherwise return null. The characters ':' and '(' are not allowed.
84 static char *
85 parseshort(const char *optstring, const char c)
87 char *cp = (char *)optstring;
89 if (c == ':' || c == '(')
90 return (NULL);
91 do {
92 if (*cp == c)
93 return (cp);
94 while (*cp == '(')
95 while (*cp != '\0' && *cp != ')')
96 cp++;
97 } while (*cp++ != '\0');
98 return (NULL);
102 * Determine if the specified string (opt) is present in the string
103 * (optstring) as a long-option contained within parenthesis. If the
104 * long-option specifies option-argument, return a pointer to it in
105 * longoptarg. Otherwise set longoptarg to null. If the option is found,
106 * return a pointer into optstring pointing at the short-option character
107 * associated with this long-option; otherwise return null.
109 * optstring The entire optstring passed to getopt() by the caller
111 * opt The long option read from the command line
113 * longoptarg The argument to the option is returned in this parameter,
114 * if an option exists. Possible return values in longoptarg
115 * are:
116 * NULL No argument was found
117 * empty string ("") Argument was explicitly left empty
118 * by the user (e.g., --option= )
119 * valid string Argument found on the command line
121 * returns Pointer to equivalent short-option in optstring, null
122 * if option not found in optstring.
124 * ASSUMES: No parameters are NULL
127 static char *
128 parselong(const char *optstring, const char *opt, char **longoptarg)
130 char *cp; /* ptr into optstring, beginning of one option spec. */
131 char *ip; /* ptr into optstring, traverses every char */
132 char *op; /* pointer into opt */
133 int match; /* nonzero if opt is matching part of optstring */
135 cp = ip = (char *)optstring;
136 do {
137 if (*ip != '(' && *++ip == '\0')
138 break;
139 if (*ip == ':' && *++ip == '\0')
140 break;
141 while (*ip == '(') {
142 if (*++ip == '\0')
143 break;
144 op = (char *)opt;
145 match = 1;
146 while (*ip != ')' && *ip != '\0' && *op != '\0')
147 match = (*ip++ == *op++ && match);
148 if (match && *ip == ')' &&
149 (*op == '\0' || *op == '=')) {
150 if ((*op) == '=') {
151 /* may be an empty string - OK */
152 (*longoptarg) = op + 1;
153 } else {
154 (*longoptarg) = NULL;
156 return (cp);
158 if (*ip == ')' && *++ip == '\0')
159 break;
161 cp = ip;
163 * Handle double-colon in optstring ("a::(longa)")
164 * The old getopt() accepts it and treats it as a
165 * required argument.
167 while ((cp > optstring) && ((*cp) == ':')) {
168 --cp;
170 } while (*cp != '\0');
171 return (NULL);
172 } /* parselong() */
175 * External function entry point.
178 getopt(int argc, char *const *argv, const char *optstring)
180 char c;
181 char *cp;
182 int longopt;
183 char *longoptarg;
186 * Has the end of the options been encountered? The following
187 * implements the SUS requirements:
189 * If, when getopt() is called:
190 * argv[optind] is a null pointer
191 * *argv[optind] is not the character '-'
192 * argv[optind] points to the string "-"
193 * getopt() returns -1 without changing optind. If
194 * argv[optind] points to the string "--"
195 * getopt() returns -1 after incrementing optind.
197 if (_sp == 1) {
198 if (optind >= argc || argv[optind][0] != '-' ||
199 argv[optind] == NULL || argv[optind][1] == '\0')
200 return (EOF);
201 else if (strcmp(argv[optind], "--") == 0) {
202 optind++;
203 return (EOF);
208 * Getting this far indicates that an option has been encountered.
209 * Note that the syntax of optstring applies special meanings to
210 * the characters ':' and '(', so they are not permissible as
211 * option letters. A special meaning is also applied to the ')'
212 * character, but its meaning can be determined from context.
213 * Note that the specification only requires that the alnum
214 * characters be accepted.
216 * If the second character of the argument is a '-' this must be
217 * a long-option, otherwise it must be a short option. Scan for
218 * the option in optstring by the appropriate algorithm. Either
219 * scan will return a pointer to the short-option character in
220 * optstring if the option is found and NULL otherwise.
222 * For an unrecognized long-option, optopt will equal 0, but
223 * since long-options can't aggregate the failing option can
224 * be identified by argv[optind-1].
226 optopt = c = (unsigned char)argv[optind][_sp];
227 optarg = NULL;
228 longopt = (_sp == 1 && c == '-');
229 if (!(longopt ?
230 ((cp = parselong(optstring, argv[optind]+2, &longoptarg)) != NULL) :
231 ((cp = parseshort(optstring, c)) != NULL))) {
232 ERR(_libc_gettext("%s: illegal option -- %s\n"),
233 c, (longopt ? optind : 0));
235 * Note: When the long option is unrecognized, optopt
236 * will be '-' here, which matches the specification.
238 if (argv[optind][++_sp] == '\0' || longopt) {
239 optind++;
240 _sp = 1;
242 return ('?');
244 optopt = c = *cp;
247 * A valid option has been identified. If it should have an
248 * option-argument, process that now. SUS defines the setting
249 * of optarg as follows:
251 * 1. If the option was the last character in the string pointed to
252 * by an element of argv, then optarg contains the next element
253 * of argv, and optind is incremented by 2. If the resulting
254 * value of optind is not less than argc, this indicates a
255 * missing option-argument, and getopt() returns an error
256 * indication.
258 * 2. Otherwise, optarg points to the string following the option
259 * character in that element of argv, and optind is incremented
260 * by 1.
262 * The second clause allows -abcd (where b requires an option-argument)
263 * to be interpreted as "-a -b cd".
265 * Note that the option-argument can legally be an empty string,
266 * such as:
267 * command --option= operand
268 * which explicitly sets the value of --option to nil
270 if (*(cp + 1) == ':') {
271 /* The option takes an argument */
272 if (!longopt && argv[optind][_sp+1] != '\0') {
273 optarg = &argv[optind++][_sp+1];
274 } else if (longopt && longoptarg) {
276 * The option argument was explicitly set to
277 * the empty string on the command line (--option=)
279 optind++;
280 optarg = longoptarg;
281 } else if (++optind >= argc) {
282 ERR(_libc_gettext("%s: option requires an argument" \
283 " -- %s\n"), c, (longopt ? optind - 1 : 0));
284 _sp = 1;
285 optarg = NULL;
286 return (optstring[0] == ':' ? ':' : '?');
287 } else
288 optarg = argv[optind++];
289 _sp = 1;
290 } else {
291 /* The option does NOT take an argument */
292 if (longopt && (longoptarg != NULL)) {
293 /* User supplied an arg to an option that takes none */
294 ERR(_libc_gettext(
295 "%s: option doesn't take an argument -- %s\n"),
296 0, (longopt ? optind : 0));
297 optarg = longoptarg = NULL;
298 c = '?';
301 if (longopt || argv[optind][++_sp] == '\0') {
302 _sp = 1;
303 optind++;
305 optarg = NULL;
307 return (c);
308 } /* getopt() */