10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*6812Sraf * Common Development and Distribution License (the "License").
6*6812Sraf * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21*6812Sraf
220Sstevel@tonic-gate /*
23*6812Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */
280Sstevel@tonic-gate /* All Rights Reserved */
290Sstevel@tonic-gate
30*6812Sraf #pragma ident "%Z%%M% %I% %E% SMI"
310Sstevel@tonic-gate
320Sstevel@tonic-gate /*
330Sstevel@tonic-gate * See getopt(3C) and SUS/XPG getopt() for function definition and
340Sstevel@tonic-gate * requirements.
350Sstevel@tonic-gate *
360Sstevel@tonic-gate * This actual implementation is a bit looser than the specification
370Sstevel@tonic-gate * as it allows any character other than ':' and '(' to be used as
380Sstevel@tonic-gate * a short option character - The specification only guarantees the
390Sstevel@tonic-gate * alnum characters ([a-z][A-Z][0-9]).
400Sstevel@tonic-gate */
410Sstevel@tonic-gate
42*6812Sraf #pragma weak _getopt = getopt
430Sstevel@tonic-gate
44*6812Sraf #include "lint.h"
450Sstevel@tonic-gate #include "_libc_gettext.h"
460Sstevel@tonic-gate
470Sstevel@tonic-gate #include <unistd.h>
480Sstevel@tonic-gate #include <string.h>
490Sstevel@tonic-gate #include <stdio.h>
500Sstevel@tonic-gate
510Sstevel@tonic-gate /*
520Sstevel@tonic-gate * Generalized error processing macro. The parameter i is a pointer to
530Sstevel@tonic-gate * the failed option string. If it is NULL, the character in c is converted
540Sstevel@tonic-gate * to a string and displayed instead. s is the error text.
550Sstevel@tonic-gate *
560Sstevel@tonic-gate * This could be / should be a static function if it is used more, but
570Sstevel@tonic-gate * that would require moving the 'optstring[0]' test outside of the
580Sstevel@tonic-gate * function.
590Sstevel@tonic-gate */
600Sstevel@tonic-gate #define ERR(s, c, i) if (opterr && optstring[0] != ':') { \
610Sstevel@tonic-gate char errbuf[256]; \
620Sstevel@tonic-gate char cbuf[2]; \
630Sstevel@tonic-gate cbuf[0] = c; \
640Sstevel@tonic-gate cbuf[1] = '\0'; \
650Sstevel@tonic-gate (void) snprintf(errbuf, sizeof (errbuf), s, argv[0], \
660Sstevel@tonic-gate (i ? argv[i]+2 : cbuf)); \
670Sstevel@tonic-gate (void) write(2, errbuf, strlen(errbuf)); }
680Sstevel@tonic-gate
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate * _sp is required to keep state between successive calls to getopt() while
710Sstevel@tonic-gate * extracting aggregated short-options (ie: -abcd). Hence, getopt() is not
720Sstevel@tonic-gate * thread safe or reentrant, but it really doesn't matter.
730Sstevel@tonic-gate *
740Sstevel@tonic-gate * So, why isn't this "static" you ask? Because the historical Bourne
750Sstevel@tonic-gate * shell has actually latched on to this little piece of private data.
760Sstevel@tonic-gate */
770Sstevel@tonic-gate int _sp = 1;
780Sstevel@tonic-gate
790Sstevel@tonic-gate /*
800Sstevel@tonic-gate * Determine if the specified character (c) is present in the string
810Sstevel@tonic-gate * (optstring) as a regular, single character option. If the option is found,
820Sstevel@tonic-gate * return a pointer into optstring pointing at the short-option character,
830Sstevel@tonic-gate * otherwise return null. The characters ':' and '(' are not allowed.
840Sstevel@tonic-gate */
850Sstevel@tonic-gate static char *
parseshort(const char * optstring,const char c)860Sstevel@tonic-gate parseshort(const char *optstring, const char c)
870Sstevel@tonic-gate {
880Sstevel@tonic-gate char *cp = (char *)optstring;
890Sstevel@tonic-gate
900Sstevel@tonic-gate if (c == ':' || c == '(')
910Sstevel@tonic-gate return (NULL);
920Sstevel@tonic-gate do {
930Sstevel@tonic-gate if (*cp == c)
940Sstevel@tonic-gate return (cp);
950Sstevel@tonic-gate while (*cp == '(')
960Sstevel@tonic-gate while (*cp != '\0' && *cp != ')')
970Sstevel@tonic-gate cp++;
980Sstevel@tonic-gate } while (*cp++ != '\0');
990Sstevel@tonic-gate return (NULL);
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate /*
1030Sstevel@tonic-gate * Determine if the specified string (opt) is present in the string
1040Sstevel@tonic-gate * (optstring) as a long-option contained within parenthesis. If the
1050Sstevel@tonic-gate * long-option specifies option-argument, return a pointer to it in
1060Sstevel@tonic-gate * longoptarg. Otherwise set longoptarg to null. If the option is found,
1070Sstevel@tonic-gate * return a pointer into optstring pointing at the short-option character
1080Sstevel@tonic-gate * associated with this long-option; otherwise return null.
1090Sstevel@tonic-gate *
1100Sstevel@tonic-gate * optstring The entire optstring passed to getopt() by the caller
1110Sstevel@tonic-gate *
1120Sstevel@tonic-gate * opt The long option read from the command line
1130Sstevel@tonic-gate *
1140Sstevel@tonic-gate * longoptarg The argument to the option is returned in this parameter,
1150Sstevel@tonic-gate * if an option exists. Possible return values in longoptarg
1160Sstevel@tonic-gate * are:
1170Sstevel@tonic-gate * NULL No argument was found
1180Sstevel@tonic-gate * empty string ("") Argument was explicitly left empty
1190Sstevel@tonic-gate * by the user (e.g., --option= )
1200Sstevel@tonic-gate * valid string Argument found on the command line
1210Sstevel@tonic-gate *
1220Sstevel@tonic-gate * returns Pointer to equivalent short-option in optstring, null
1230Sstevel@tonic-gate * if option not found in optstring.
1240Sstevel@tonic-gate *
1250Sstevel@tonic-gate * ASSUMES: No parameters are NULL
1260Sstevel@tonic-gate *
1270Sstevel@tonic-gate */
1280Sstevel@tonic-gate static char *
parselong(const char * optstring,const char * opt,char ** longoptarg)1290Sstevel@tonic-gate parselong(const char *optstring, const char *opt, char **longoptarg)
1300Sstevel@tonic-gate {
1310Sstevel@tonic-gate char *cp; /* ptr into optstring, beginning of one option spec. */
1320Sstevel@tonic-gate char *ip; /* ptr into optstring, traverses every char */
1330Sstevel@tonic-gate char *op; /* pointer into opt */
1340Sstevel@tonic-gate int match; /* nonzero if opt is matching part of optstring */
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate cp = ip = (char *)optstring;
1370Sstevel@tonic-gate do {
1380Sstevel@tonic-gate if (*ip != '(' && *++ip == '\0')
1390Sstevel@tonic-gate break;
1400Sstevel@tonic-gate if (*ip == ':' && *++ip == '\0')
1410Sstevel@tonic-gate break;
1420Sstevel@tonic-gate while (*ip == '(') {
1430Sstevel@tonic-gate if (*++ip == '\0')
1440Sstevel@tonic-gate break;
1450Sstevel@tonic-gate op = (char *)opt;
1460Sstevel@tonic-gate match = 1;
1470Sstevel@tonic-gate while (*ip != ')' && *ip != '\0' && *op != '\0')
1480Sstevel@tonic-gate match = (*ip++ == *op++ && match);
1490Sstevel@tonic-gate if (match && *ip == ')' &&
1500Sstevel@tonic-gate (*op == '\0' || *op == '=')) {
1510Sstevel@tonic-gate if ((*op) == '=') {
152*6812Sraf /* may be an empty string - OK */
153*6812Sraf (*longoptarg) = op + 1;
1540Sstevel@tonic-gate } else {
155*6812Sraf (*longoptarg) = NULL;
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate return (cp);
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate if (*ip == ')' && *++ip == '\0')
1600Sstevel@tonic-gate break;
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate cp = ip;
1630Sstevel@tonic-gate /*
1640Sstevel@tonic-gate * Handle double-colon in optstring ("a::(longa)")
1650Sstevel@tonic-gate * The old getopt() accepts it and treats it as a
1660Sstevel@tonic-gate * required argument.
1670Sstevel@tonic-gate */
1680Sstevel@tonic-gate while ((cp > optstring) && ((*cp) == ':')) {
169*6812Sraf --cp;
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate } while (*cp != '\0');
1720Sstevel@tonic-gate return (NULL);
1730Sstevel@tonic-gate } /* parselong() */
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate /*
1760Sstevel@tonic-gate * External function entry point.
1770Sstevel@tonic-gate */
1780Sstevel@tonic-gate int
getopt(int argc,char * const * argv,const char * optstring)1790Sstevel@tonic-gate getopt(int argc, char *const *argv, const char *optstring)
1800Sstevel@tonic-gate {
1810Sstevel@tonic-gate char c;
1820Sstevel@tonic-gate char *cp;
1830Sstevel@tonic-gate int longopt;
1840Sstevel@tonic-gate char *longoptarg;
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate /*
1870Sstevel@tonic-gate * Has the end of the options been encountered? The following
1880Sstevel@tonic-gate * implements the SUS requirements:
1890Sstevel@tonic-gate *
1900Sstevel@tonic-gate * If, when getopt() is called:
1910Sstevel@tonic-gate * argv[optind] is a null pointer
1920Sstevel@tonic-gate * *argv[optind] is not the character '-'
1930Sstevel@tonic-gate * argv[optind] points to the string "-"
1940Sstevel@tonic-gate * getopt() returns -1 without changing optind. If
1950Sstevel@tonic-gate * argv[optind] points to the string "--"
1960Sstevel@tonic-gate * getopt() returns -1 after incrementing optind.
1970Sstevel@tonic-gate */
1980Sstevel@tonic-gate if (_sp == 1) {
1990Sstevel@tonic-gate if (optind >= argc || argv[optind][0] != '-' ||
2000Sstevel@tonic-gate argv[optind] == NULL || argv[optind][1] == '\0')
2010Sstevel@tonic-gate return (EOF);
2020Sstevel@tonic-gate else if (strcmp(argv[optind], "--") == NULL) {
2030Sstevel@tonic-gate optind++;
2040Sstevel@tonic-gate return (EOF);
2050Sstevel@tonic-gate }
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate /*
2090Sstevel@tonic-gate * Getting this far indicates that an option has been encountered.
2100Sstevel@tonic-gate * Note that the syntax of optstring applies special meanings to
2110Sstevel@tonic-gate * the characters ':' and '(', so they are not permissible as
2120Sstevel@tonic-gate * option letters. A special meaning is also applied to the ')'
2130Sstevel@tonic-gate * character, but its meaning can be determined from context.
2140Sstevel@tonic-gate * Note that the specification only requires that the alnum
2150Sstevel@tonic-gate * characters be accepted.
2160Sstevel@tonic-gate *
2170Sstevel@tonic-gate * If the second character of the argument is a '-' this must be
2180Sstevel@tonic-gate * a long-option, otherwise it must be a short option. Scan for
2190Sstevel@tonic-gate * the option in optstring by the appropriate algorithm. Either
2200Sstevel@tonic-gate * scan will return a pointer to the short-option character in
2210Sstevel@tonic-gate * optstring if the option is found and NULL otherwise.
2220Sstevel@tonic-gate *
2230Sstevel@tonic-gate * For an unrecognized long-option, optopt will equal 0, but
2240Sstevel@tonic-gate * since long-options can't aggregate the failing option can
2250Sstevel@tonic-gate * be identified by argv[optind-1].
2260Sstevel@tonic-gate */
2270Sstevel@tonic-gate optopt = c = (unsigned char)argv[optind][_sp];
2280Sstevel@tonic-gate optarg = NULL;
2290Sstevel@tonic-gate longopt = (_sp == 1 && c == '-');
2300Sstevel@tonic-gate if (!(longopt ?
2310Sstevel@tonic-gate ((cp = parselong(optstring, argv[optind]+2, &longoptarg)) != NULL) :
2320Sstevel@tonic-gate ((cp = parseshort(optstring, c)) != NULL))) {
2330Sstevel@tonic-gate ERR(_libc_gettext("%s: illegal option -- %s\n"),
2340Sstevel@tonic-gate c, (longopt ? optind : 0));
2350Sstevel@tonic-gate /*
2360Sstevel@tonic-gate * Note: When the long option is unrecognized, optopt
2370Sstevel@tonic-gate * will be '-' here, which matches the specification.
2380Sstevel@tonic-gate */
2390Sstevel@tonic-gate if (argv[optind][++_sp] == '\0' || longopt) {
2400Sstevel@tonic-gate optind++;
2410Sstevel@tonic-gate _sp = 1;
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate return ('?');
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate optopt = c = *cp;
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate /*
2480Sstevel@tonic-gate * A valid option has been identified. If it should have an
2490Sstevel@tonic-gate * option-argument, process that now. SUS defines the setting
2500Sstevel@tonic-gate * of optarg as follows:
2510Sstevel@tonic-gate *
2520Sstevel@tonic-gate * 1. If the option was the last character in the string pointed to
2530Sstevel@tonic-gate * by an element of argv, then optarg contains the next element
2540Sstevel@tonic-gate * of argv, and optind is incremented by 2. If the resulting
2550Sstevel@tonic-gate * value of optind is not less than argc, this indicates a
2560Sstevel@tonic-gate * missing option-argument, and getopt() returns an error
2570Sstevel@tonic-gate * indication.
2580Sstevel@tonic-gate *
2590Sstevel@tonic-gate * 2. Otherwise, optarg points to the string following the option
2600Sstevel@tonic-gate * character in that element of argv, and optind is incremented
2610Sstevel@tonic-gate * by 1.
2620Sstevel@tonic-gate *
2630Sstevel@tonic-gate * The second clause allows -abcd (where b requires an option-argument)
2640Sstevel@tonic-gate * to be interpreted as "-a -b cd".
2650Sstevel@tonic-gate *
2660Sstevel@tonic-gate * Note that the option-argument can legally be an empty string,
2670Sstevel@tonic-gate * such as:
2680Sstevel@tonic-gate * command --option= operand
2690Sstevel@tonic-gate * which explicitly sets the value of --option to nil
2700Sstevel@tonic-gate */
2710Sstevel@tonic-gate if (*(cp + 1) == ':') {
2720Sstevel@tonic-gate /* The option takes an argument */
2730Sstevel@tonic-gate if (!longopt && argv[optind][_sp+1] != '\0') {
2740Sstevel@tonic-gate optarg = &argv[optind++][_sp+1];
2750Sstevel@tonic-gate } else if (longopt && longoptarg) {
2760Sstevel@tonic-gate /*
2770Sstevel@tonic-gate * The option argument was explicitly set to
2780Sstevel@tonic-gate * the empty string on the command line (--option=)
2790Sstevel@tonic-gate */
2800Sstevel@tonic-gate optind++;
2810Sstevel@tonic-gate optarg = longoptarg;
2820Sstevel@tonic-gate } else if (++optind >= argc) {
2830Sstevel@tonic-gate ERR(_libc_gettext("%s: option requires an argument" \
2840Sstevel@tonic-gate " -- %s\n"), c, (longopt ? optind - 1 : 0));
2850Sstevel@tonic-gate _sp = 1;
2860Sstevel@tonic-gate optarg = NULL;
2870Sstevel@tonic-gate return (optstring[0] == ':' ? ':' : '?');
2880Sstevel@tonic-gate } else
2890Sstevel@tonic-gate optarg = argv[optind++];
2900Sstevel@tonic-gate _sp = 1;
2910Sstevel@tonic-gate } else {
2920Sstevel@tonic-gate /* The option does NOT take an argument */
2930Sstevel@tonic-gate if (longopt && (longoptarg != NULL)) {
294*6812Sraf /* User supplied an arg to an option that takes none */
295*6812Sraf ERR(_libc_gettext(
296*6812Sraf "%s: option doesn't take an argument -- %s\n"),
297*6812Sraf 0, (longopt ? optind : 0));
298*6812Sraf optarg = longoptarg = NULL;
299*6812Sraf c = '?';
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate if (longopt || argv[optind][++_sp] == '\0') {
3030Sstevel@tonic-gate _sp = 1;
3040Sstevel@tonic-gate optind++;
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate optarg = NULL;
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate return (c);
3090Sstevel@tonic-gate } /* getopt() */
310