/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* requirements.
*
* This actual implementation is a bit looser than the specification
* as it allows any character other than ':' and '(' to be used as
* a short option character - The specification only guarantees the
* alnum characters ([a-z][A-Z][0-9]).
*/
#include "lint.h"
#include "_libc_gettext.h"
#include <unistd.h>
#include <string.h>
#include <stdio.h>
/*
* Generalized error processing macro. The parameter i is a pointer to
* the failed option string. If it is NULL, the character in c is converted
* to a string and displayed instead. s is the error text.
*
* This could be / should be a static function if it is used more, but
* that would require moving the 'optstring[0]' test outside of the
* function.
*/
char errbuf[256]; \
char cbuf[2]; \
cbuf[0] = c; \
/*
* _sp is required to keep state between successive calls to getopt() while
* extracting aggregated short-options (ie: -abcd). Hence, getopt() is not
* thread safe or reentrant, but it really doesn't matter.
*
* So, why isn't this "static" you ask? Because the historical Bourne
* shell has actually latched on to this little piece of private data.
*/
/*
* Determine if the specified character (c) is present in the string
* (optstring) as a regular, single character option. If the option is found,
* return a pointer into optstring pointing at the short-option character,
* otherwise return null. The characters ':' and '(' are not allowed.
*/
static char *
{
if (c == ':' || c == '(')
return (NULL);
do {
if (*cp == c)
return (cp);
while (*cp == '(')
cp++;
} while (*cp++ != '\0');
return (NULL);
}
/*
* Determine if the specified string (opt) is present in the string
* (optstring) as a long-option contained within parenthesis. If the
* long-option specifies option-argument, return a pointer to it in
* longoptarg. Otherwise set longoptarg to null. If the option is found,
* return a pointer into optstring pointing at the short-option character
* associated with this long-option; otherwise return null.
*
* optstring The entire optstring passed to getopt() by the caller
*
* opt The long option read from the command line
*
* longoptarg The argument to the option is returned in this parameter,
* if an option exists. Possible return values in longoptarg
* are:
* NULL No argument was found
* empty string ("") Argument was explicitly left empty
* by the user (e.g., --option= )
* valid string Argument found on the command line
*
* returns Pointer to equivalent short-option in optstring, null
* if option not found in optstring.
*
* ASSUMES: No parameters are NULL
*
*/
static char *
{
do {
break;
break;
while (*ip == '(') {
if (*++ip == '\0')
break;
match = 1;
if ((*op) == '=') {
/* may be an empty string - OK */
} else {
(*longoptarg) = NULL;
}
return (cp);
}
break;
}
/*
* Handle double-colon in optstring ("a::(longa)")
* The old getopt() accepts it and treats it as a
* required argument.
*/
--cp;
}
} while (*cp != '\0');
return (NULL);
} /* parselong() */
/*
* External function entry point.
*/
int
{
char c;
char *cp;
int longopt;
char *longoptarg;
/*
* Has the end of the options been encountered? The following
* implements the SUS requirements:
*
* If, when getopt() is called:
* argv[optind] is a null pointer
* *argv[optind] is not the character '-'
* argv[optind] points to the string "-"
* getopt() returns -1 without changing optind. If
* argv[optind] points to the string "--"
* getopt() returns -1 after incrementing optind.
*/
if (_sp == 1) {
return (EOF);
optind++;
return (EOF);
}
}
/*
* Getting this far indicates that an option has been encountered.
* Note that the syntax of optstring applies special meanings to
* the characters ':' and '(', so they are not permissible as
* option letters. A special meaning is also applied to the ')'
* character, but its meaning can be determined from context.
* Note that the specification only requires that the alnum
* characters be accepted.
*
* If the second character of the argument is a '-' this must be
* a long-option, otherwise it must be a short option. Scan for
* the option in optstring by the appropriate algorithm. Either
* scan will return a pointer to the short-option character in
* optstring if the option is found and NULL otherwise.
*
* For an unrecognized long-option, optopt will equal 0, but
* since long-options can't aggregate the failing option can
* be identified by argv[optind-1].
*/
if (!(longopt ?
/*
* Note: When the long option is unrecognized, optopt
* will be '-' here, which matches the specification.
*/
optind++;
_sp = 1;
}
return ('?');
}
/*
* A valid option has been identified. If it should have an
* option-argument, process that now. SUS defines the setting
* of optarg as follows:
*
* 1. If the option was the last character in the string pointed to
* by an element of argv, then optarg contains the next element
* of argv, and optind is incremented by 2. If the resulting
* value of optind is not less than argc, this indicates a
* missing option-argument, and getopt() returns an error
* indication.
*
* 2. Otherwise, optarg points to the string following the option
* character in that element of argv, and optind is incremented
* by 1.
*
* The second clause allows -abcd (where b requires an option-argument)
* to be interpreted as "-a -b cd".
*
* Note that the option-argument can legally be an empty string,
* such as:
* command --option= operand
* which explicitly sets the value of --option to nil
*/
/* The option takes an argument */
} else if (longopt && longoptarg) {
/*
* The option argument was explicitly set to
* the empty string on the command line (--option=)
*/
optind++;
optarg = longoptarg;
_sp = 1;
} else
_sp = 1;
} else {
/* The option does NOT take an argument */
/* User supplied an arg to an option that takes none */
"%s: option doesn't take an argument -- %s\n"),
c = '?';
}
_sp = 1;
optind++;
}
}
return (c);
} /* getopt() */