Blame dwarfdump/dwgetopt.c

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