/* $NetBSD: getopt.c,v 1.1 2009/03/22 22:33:13 joerg Exp $*/
/* Modified by David Anderson to work with GNU/Linux and freebsd.
Added {} for clarity.
Switched to standard dwarfdump formatting.
Treatment of : modified so that :: gets dwoptarg NULL
if space follows the letter
(the dwoptarg is set to null).
renamed to make it clear this is a private version.
Oct 17 2017: Created dwgetopt_long(). See dwgetopt.h
*/
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* This does not presently handle the option string
leading + or leading - features. Such are not used
by by libdwarfdump. Nor does it understand the
GNU Env var POSIXLY_CORRECT .
It does know of the leading ":" in the option string.
See BADCH below.
*/
#include <config.h>
#include <stddef.h> /* NULL size_t */
#include <stdio.h> /* printf() */
#include <string.h> /* strlen() strchr() strcmp() strncmp() */
#include "dd_minimal.h" /* dd_minimal_count_global_error */
#include "dd_getopt.h"
#define STRIP_OFF_CONSTNESS(a) ((void *)(size_t)(const void *)(a))
int dwopterr = 1, /* if error message should be printed */
dwoptind = 1, /* index into parent argv vector */
dwoptopt, /* character checked for validity */
dwoptreset; /* reset getopt */
char *dwoptarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
#define TRUE 1
#define FALSE 0
#if 0 /* FOR DEBUGGING ONLY */
/* Use for testing dwgetopt only.
Not a standard function. */
void
dwgetoptresetfortestingonly(void)
{
dwopterr = 1;
dwoptind = 1;
dwoptopt = 0;
dwoptreset = 0;
dwoptarg = 0;
}
#endif /* FOR DEBUGGING ONLY */
static const char *place = EMSG;/* option letter processing */
/* Post Condition:
if return FALSE then *argerr is set false. */
static int
dwoptnamematches(
const struct dwoption *dwlopt,
const char *iplace,
const char **argloc,
int *argerr)
{
const char *eq = 0;
unsigned long namelen = 0;
size_t arglenszt = 0;
int d = 0;
for (eq = iplace; *eq; ++eq) {
if (*eq != '=') {
continue;
}
/* Found =, arg should follow */
namelen = (unsigned long)(eq - iplace);
if (namelen != (unsigned long)strlen(dwlopt->name)) {
return FALSE;
}
eq++;
arglenszt = strlen(eq);
break;
}
if (namelen) {
d = strncmp(iplace,dwlopt->name,namelen);
if (d) {
return FALSE;
}
if (dwlopt->has_arg == 0) {
*argerr = TRUE;
return TRUE;
}
if (arglenszt) {
/* Discarding const, avoiding warning.
Data is in user space, so this is ok. */
dwoptarg = (char *)eq;
*argloc = (const char *)eq;
} else {
/* Has arg = but arg is empty. */
dwoptarg = 0;
}
return TRUE;
} else {
d = strcmp(iplace,dwlopt->name);
if (d) {
return FALSE;
}
if (dwlopt->has_arg == 1) {
*argerr = TRUE;
return TRUE;
}
dwoptarg = 0;
return TRUE;
}
}
/* dwgetopt_long
A reimplemention of a portion of
the getopt(3) GNU/Linux getopt_long().
See dwgetopt.h for more details.
*/
int dwgetopt_long(int nargc, char *const nargv[],
const char *ostr,
const struct dwoption* longopts,
int *longindex)
{
char *lplace = 0;
if (dwoptreset) {
/* Not really supported. */
place = EMSG;
return (-1);
}
if (*place) {
int v = dwgetopt(nargc,nargv,ostr);
return v;
}
/* Use local lplace in case we need to call getopt()
just below. */
lplace = nargv[dwoptind];
if (dwoptind >= nargc || *lplace++ != '-') {
/* Argument is absent or is not an option */
place = EMSG;
return (-1);
}
if (*lplace != '-') {
/* Notice place not disturbed. */
int v = dwgetopt(nargc,nargv,ostr);
return v;
}
/* Starts with two dashes.
Now we set the global place */
place = lplace+1;
if (!*place) {
/* "--" => end of options */
++dwoptind;
place = EMSG;
return (-1);
}
/* We think this is a longopt. */
{
int lo_num = 0;
int dwlopt_val = 0;
for (;;lo_num++) {
const struct dwoption *dwlopt = longopts +lo_num;
const char * argloc = 0;
int argerr = 0;
int resmatch = 0;
if (!dwlopt->name) {
dwoptind++;
(void)printf("ERROR:"
" invalid long option '--%s'\n", place);
/* Leave longindex unchanged. */
dd_minimal_count_global_error();
place = EMSG;
return (BADCH);
}
resmatch= dwoptnamematches(dwlopt,place,
&argloc,&argerr);
if (resmatch) {
dwoptarg = 0;
if (argloc) {
/* Must drop const here. Ugh. */
dwoptarg = (char *)argloc;
}
}
if (argerr) {
/* resmatch == TRUE
arg option missing if required, present
but not allowed.
GNU Behavior not well documented.
Had to experiment.
if argument-not-allowed, and we have one,
do ???
If argument-required,
then here GNU
would take the next argv as the argument.
we are not currently doing that. */
/**longindex = lo_num; */
if (dwlopt->has_arg) {
/* Missing required arg, this does not
match GNU getopt_long behavior
of taking next argv as the arg value.
and thus making getopt_long succeed. */
(void)printf("ERROR:"
" missing required long option "
"argument '--%s'\n", place);
dd_minimal_count_global_error();
} else {
/* has arg but should not */
(void)printf("ERROR:"
" option '--%s' does not allow an argument\n",
dwlopt->name);
dd_minimal_count_global_error();
}
dwoptind++;
place = EMSG;
return (BADCH);
}
if (resmatch) {
*longindex = lo_num;
dwlopt_val = dwlopt->val;
break;
}
}
place = EMSG;
dwoptind++;
return dwlopt_val;
}
}
/*
* getopt --
* Parse argc/argv argument vector.
* a: means
* -afoo
* -a foo
* and 'foo' is returned in dwoptarg
* b:: means
* -b
* and dwoptarg is null
* -bother
* and dwoptarg is 'other'
*/
int
dwgetopt(int nargc, char * const nargv[], const char *ostr)
{
char *oli; /* option letter list index */
if (dwoptreset || *place == 0) { /* update scanning pointer */
dwoptreset = 0;
place = nargv[dwoptind];
if (dwoptind >= nargc || *place++ != '-') {
/* Argument is absent or is not an option */
place = EMSG;
return (-1);
}
dwoptopt = *place++;
if (dwoptopt == '-' && *place == 0) {
/* "--" => end of options */
++dwoptind;
place = EMSG;
return (-1);
}
if (dwoptopt == 0) {
/* Solitary '-', treat as a '-' option
if the program (eg su) is looking for it. */
place = EMSG;
if (strchr(ostr, '-') == NULL) {
return -1;
}
dwoptopt = '-';
}
} else {
dwoptopt = *place++;
}
/* See if option letter is one the caller wanted... */
if (dwoptopt == ':' || (oli = strchr(ostr, dwoptopt)) == NULL) {
if (*place == 0) {
++dwoptind;
}
if (dwopterr && *ostr != ':') {
(void)printf("ERROR:"
" invalid option -- '%c'\n", dwoptopt);
dd_minimal_count_global_error();
}
return (BADCH);
}
/* Does this option need an argument? */
if (oli[1] != ':') {
/* don't need argument */
dwoptarg = NULL;
if (*place == 0) {
++dwoptind;
}
} else {
int reqnextarg = 1;
if (oli[1] && (oli[2] == ':')) {
/* Pair of :: means special treatment of dwoptarg */
reqnextarg = 0;
}
/* Option-argument is either the rest of this argument or the
entire next argument. */
if (*place ) {
/* Whether : or :: */
dwoptarg = STRIP_OFF_CONSTNESS(place);
} else if (reqnextarg) {
/* ! *place */
if (nargc > (++dwoptind)) {
dwoptarg = nargv[dwoptind];
} else {
place=EMSG;
/* Next arg required, but is missing */
if (*ostr == ':') {
/* Leading : in ostr calls for BADARG return. */
return (BADARG);
}
if (dwopterr) {
(void)printf("ERROR:"
" option requires an argument. -- '%c'\n",
dwoptopt);
dd_minimal_count_global_error();
}
return (BADCH);
}
} else {
/* ! *place */
/* The key part of :: treatment. */
dwoptarg = NULL;
}
place = EMSG;
++dwoptind;
}
return (dwoptopt); /* return option letter */
}