ossp-pkg/popt/popt.c
/*
* Option Parsing Library (POPT)
* Copyright (c) 1998-2002 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of the X Consortium shall not be
* used in advertising or otherwise to promote the sale, use or other dealings
* in this Software without prior written authorization from the X Consortium.
*
* NOTICE:
* This is an automatically generated, stripped down version of the
* POPT 1.7 library from Red Hat, Inc. This version is still
* distributed under above Open Source license, but Red Hat is no longer
* responsible for this version. Contact The OSSP Project instead.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined (__GLIBC__) && defined(__LCLINT__)
extern __const __int32_t *__ctype_tolower;
extern __const __int32_t *__ctype_toupper;
#endif
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifndef __GNUC__
# if HAVE_ALLOCA_H
# include <alloca.h>
# else
# ifdef _AIX
#pragma alloca
# else
# ifndef alloca
char *alloca();
# endif
# endif
# endif
#elif defined(__GNUC__) && defined(__STRICT_ANSI__)
#define alloca __builtin_alloca
#endif
#include "popt.h"
#ifndef H_POPTINT
#define H_POPTINT
static void *_free(const void *p)
{
if (p != NULL)
free((void *)p);
return NULL;
}
typedef unsigned int __pbm_bits;
#define __PBM_NBITS (8 * sizeof (__pbm_bits))
#define __PBM_IX(d) ((d) / __PBM_NBITS)
#define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS))
typedef struct {
__pbm_bits bits[1];
} pbm_set;
#define __PBM_BITS(set) ((set)->bits)
#define PBM_ALLOC(d) calloc(__PBM_IX (d) + 1, sizeof(__pbm_bits))
#define PBM_FREE(s) _free(s);
#define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d))
#define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
#define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
struct optionStackEntry {
int argc;
const char **argv;
pbm_set *argb;
int next;
const char *nextArg;
const char *nextCharArg;
popt_item currAlias;
int stuffed;
};
struct popt_context_s {
struct optionStackEntry optionStack[POPT_OPTION_DEPTH];
struct optionStackEntry *os;
const char **leftovers;
int numLeftovers;
int nextLeftover;
const struct popt_option *options;
int restLeftover;
const char *appName;
popt_item aliases;
int numAliases;
int flags;
popt_item execs;
int numExecs;
const char **finalArgv;
int finalArgvCount;
int finalArgvAlloced;
popt_item doExec;
const char *execPath;
int execAbsolute;
const char *otherHelp;
pbm_set *arg_strip;
};
#ifdef HAVE_LIBINTL_H
#include <libintl.h>
#endif
#if defined(HAVE_GETTEXT) && !defined(__LCLINT__)
#define _(foo) gettext(foo)
#else
#define _(foo) foo
#endif
#if defined(HAVE_DCGETTEXT) && !defined(__LCLINT__)
#define D_(dom, str) dgettext(dom, str)
#define POPT_(foo) D_("popt", foo)
#else
#define D_(dom, str) str
#define POPT_(foo) foo
#endif
#define N_(foo) foo
#endif
static const char *findProgramPath(const char *argv0)
{
char *path = getenv("PATH");
char *pathbuf;
char *start, *chptr;
char *buf;
if (argv0 == NULL)
return NULL;
if (strchr(argv0, '/'))
return strdup(argv0);
if (path == NULL)
return NULL;
start = pathbuf = alloca(strlen(path) + 1);
buf = malloc(strlen(path) + strlen(argv0) + sizeof ("/"));
if (buf == NULL)
return NULL;
strcpy(pathbuf, path);
chptr = NULL;
do {
if ((chptr = strchr(start, ':')))
*chptr = '\0';
sprintf(buf, "%s/%s", start, argv0);
if (!access(buf, X_OK))
return buf;
if (chptr)
start = chptr + 1;
else
start = NULL;
} while (start && *start);
free(buf);
return NULL;
}
#if HAVE_FLOAT_H
#include <float.h>
#endif
#include <math.h>
void popt_setexecpath(popt_context con, const char *path, int allowAbsolute)
{
con->execPath = _free(con->execPath);
con->execPath = strdup(path);
con->execAbsolute = allowAbsolute;
return;
}
static void invokeCallbacksPRE(popt_context con,
const struct popt_option *opt)
{
if (opt != NULL)
for (; opt->longName || opt->shortName || opt->arg; opt++) {
if (opt->arg == NULL)
continue;
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
invokeCallbacksPRE(con, opt->arg);
}
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
(opt->argInfo & POPT_CBFLAG_PRE)) {
popt_callbacktype cb = (popt_callbacktype) opt->arg;
cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip);
}
}
}
static void invokeCallbacksPOST(popt_context con,
const struct popt_option *opt)
{
if (opt != NULL)
for (; opt->longName || opt->shortName || opt->arg; opt++) {
if (opt->arg == NULL)
continue;
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
invokeCallbacksPOST(con, opt->arg);
}
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
(opt->argInfo & POPT_CBFLAG_POST)) {
popt_callbacktype cb = (popt_callbacktype) opt->arg;
cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip);
}
}
}
static void invokeCallbacksOPTION(popt_context con,
const struct popt_option *opt,
const struct popt_option *myOpt,
const void *myData, int shorty)
{
const struct popt_option *cbopt = NULL;
if (opt != NULL)
for (; opt->longName || opt->shortName || opt->arg; opt++) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
if (opt->arg != NULL)
invokeCallbacksOPTION(con, opt->arg, myOpt, myData,
shorty);
}
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
!(opt->argInfo & POPT_CBFLAG_SKIPOPTION)) {
cbopt = opt;
}
else if (cbopt != NULL &&
((myOpt->shortName && opt->shortName && shorty &&
myOpt->shortName == opt->shortName) ||
(myOpt->longName && opt->longName &&
!strcmp(myOpt->longName, opt->longName)))
) {
popt_callbacktype cb = (popt_callbacktype) cbopt->arg;
const void *cbData =
(cbopt->descrip ? cbopt->descrip : myData);
if (cb != NULL) {
cb(con, POPT_CALLBACK_REASON_OPTION, myOpt,
con->os->nextArg, cbData);
}
if (!(cbopt->argInfo & POPT_CBFLAG_CONTINUE))
return;
}
}
}
popt_context popt_getcontext(const char *name, int argc, const char **argv,
const struct popt_option * options, int flags)
{
popt_context con = malloc(sizeof (*con));
if (con == NULL)
return NULL;
memset(con, 0, sizeof (*con));
con->os = con->optionStack;
con->os->argc = argc;
con->os->argv = argv;
con->os->argb = NULL;
if (!(flags & POPT_CONTEXT_KEEP_FIRST))
con->os->next = 1;
con->leftovers = calloc((argc + 1), sizeof (*con->leftovers));
con->options = options;
con->aliases = NULL;
con->numAliases = 0;
con->flags = flags;
con->execs = NULL;
con->numExecs = 0;
con->finalArgvAlloced = argc * 2;
con->finalArgv = calloc(con->finalArgvAlloced, sizeof (*con->finalArgv));
con->execAbsolute = 1;
con->arg_strip = NULL;
if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
con->flags |= POPT_CONTEXT_POSIXMEHARDER;
if (name) {
char *t = malloc(strlen(name) + 1);
if (t)
con->appName = strcpy(t, name);
}
invokeCallbacksPRE(con, con->options);
return con;
}
static void cleanOSE(struct optionStackEntry *os)
{
os->nextArg = _free(os->nextArg);
os->argv = _free(os->argv);
os->argb = PBM_FREE(os->argb);
}
void popt_resetcontext(popt_context con)
{
int i;
if (con == NULL)
return;
while (con->os > con->optionStack) {
cleanOSE(con->os--);
}
con->os->argb = PBM_FREE(con->os->argb);
con->os->currAlias = NULL;
con->os->nextCharArg = NULL;
con->os->nextArg = NULL;
con->os->next = 1;
con->numLeftovers = 0;
con->nextLeftover = 0;
con->restLeftover = 0;
con->doExec = NULL;
if (con->finalArgv != NULL)
for (i = 0; i < con->finalArgvCount; i++) {
con->finalArgv[i] = _free(con->finalArgv[i]);
}
con->finalArgvCount = 0;
con->arg_strip = PBM_FREE(con->arg_strip);
return;
}
static int handleExec(popt_context con, const char *longName, char shortName)
{
popt_item item;
int i;
if (con->execs == NULL || con->numExecs <= 0)
return 0;
for (i = con->numExecs - 1; i >= 0; i--) {
item = con->execs + i;
if (longName && !(item->option.longName &&
!strcmp(longName, item->option.longName)))
continue;
else if (shortName != item->option.shortName)
continue;
break;
}
if (i < 0)
return 0;
if (con->flags & POPT_CONTEXT_NO_EXEC)
return 1;
if (con->doExec == NULL) {
con->doExec = con->execs + i;
return 1;
}
if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) {
con->finalArgvAlloced += 10;
con->finalArgv = realloc(con->finalArgv,
sizeof (*con->finalArgv) *
con->finalArgvAlloced);
}
i = con->finalArgvCount++;
if (con->finalArgv != NULL) {
char *s = malloc((longName ? strlen(longName) : 0) + 3);
if (s != NULL) {
if (longName)
sprintf(s, "--%s", longName);
else
sprintf(s, "-%c", shortName);
con->finalArgv[i] = s;
}
else
con->finalArgv[i] = NULL;
}
return 1;
}
static int handleAlias(popt_context con,
const char *longName, char shortName,
const char *nextCharArg)
{
popt_item item = con->os->currAlias;
int rc;
int i;
if (item) {
if (longName && (item->option.longName &&
!strcmp(longName, item->option.longName)))
return 0;
if (shortName && shortName == item->option.shortName)
return 0;
}
if (con->aliases == NULL || con->numAliases <= 0)
return 0;
for (i = con->numAliases - 1; i >= 0; i--) {
item = con->aliases + i;
if (longName && !(item->option.longName &&
!strcmp(longName, item->option.longName)))
continue;
else if (shortName != item->option.shortName)
continue;
break;
}
if (i < 0)
return 0;
if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
return POPT_ERROR_OPTSTOODEEP;
if (nextCharArg && *nextCharArg)
con->os->nextCharArg = nextCharArg;
con->os++;
con->os->next = 0;
con->os->stuffed = 0;
con->os->nextArg = NULL;
con->os->nextCharArg = NULL;
con->os->currAlias = con->aliases + i;
rc = popt_dupargv(con->os->currAlias->argc, con->os->currAlias->argv,
&con->os->argc, &con->os->argv);
con->os->argb = NULL;
return (rc ? rc : 1);
}
static int execCommand(popt_context con)
{
popt_item item = con->doExec;
const char **argv;
int argc = 0;
int rc;
if (item == NULL)
return POPT_ERROR_NOARG;
if (item->argv == NULL || item->argc < 1 ||
(!con->execAbsolute && strchr(item->argv[0], '/')))
return POPT_ERROR_NOARG;
argv = malloc(sizeof (*argv) *
(6 + item->argc + con->numLeftovers + con->finalArgvCount));
if (argv == NULL)
return POPT_ERROR_MALLOC;
if (!strchr(item->argv[0], '/') && con->execPath) {
char *s =
alloca(strlen(con->execPath) + strlen(item->argv[0]) +
sizeof ("/"));
sprintf(s, "%s/%s", con->execPath, item->argv[0]);
argv[argc] = s;
}
else {
argv[argc] = findProgramPath(item->argv[0]);
}
if (argv[argc++] == NULL)
return POPT_ERROR_NOARG;
if (item->argc > 1) {
memcpy(argv + argc, item->argv + 1,
sizeof (*argv) * (item->argc - 1));
argc += (item->argc - 1);
}
if (con->finalArgv != NULL && con->finalArgvCount > 0) {
memcpy(argv + argc, con->finalArgv,
sizeof (*argv) * con->finalArgvCount);
argc += con->finalArgvCount;
}
if (con->leftovers != NULL && con->numLeftovers > 0) {
memcpy(argv + argc, con->leftovers,
sizeof (*argv) * con->numLeftovers);
argc += con->numLeftovers;
}
argv[argc] = NULL;
#ifdef __hpux
rc = setresuid(getuid(), getuid(), -1);
if (rc)
return POPT_ERROR_ERRNO;
#else
#if defined(HAVE_SETUID)
rc = setuid(getuid());
if (rc)
return POPT_ERROR_ERRNO;
#elif defined (HAVE_SETREUID)
rc = setreuid(getuid(), getuid());
if (rc)
return POPT_ERROR_ERRNO;
#else
;
#endif
#endif
if (argv[0] == NULL)
return POPT_ERROR_NOARG;
rc = execvp(argv[0], (char *const *)argv);
return POPT_ERROR_ERRNO;
}
static const struct popt_option *findOption(const struct popt_option *opt,
const char *longName,
char shortName,
popt_callbacktype * callback,
const void **callbackData,
int singleDash)
{
const struct popt_option *cb = NULL;
if (singleDash && !shortName && (longName && *longName == '\0'))
shortName = '-';
for (; opt->longName || opt->shortName || opt->arg; opt++) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
const struct popt_option *opt2;
if (opt->arg == NULL)
continue;
opt2 = findOption(opt->arg, longName, shortName, callback,
callbackData, singleDash);
if (opt2 == NULL)
continue;
if (!(callback && *callback))
return opt2;
if (!(callbackData && *callbackData == NULL))
return opt2;
*callbackData = opt->descrip;
return opt2;
}
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) {
cb = opt;
}
else if (longName && opt->longName &&
(!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) &&
!strcmp(longName, opt->longName))
{
break;
}
else if (shortName && shortName == opt->shortName) {
break;
}
}
if (!opt->longName && !opt->shortName)
return NULL;
if (callback)
*callback = NULL;
if (callbackData)
*callbackData = NULL;
if (cb) {
if (callback)
*callback = (popt_callbacktype) cb->arg;
if (!(cb->argInfo & POPT_CBFLAG_INC_DATA)) {
if (callbackData)
*callbackData = cb->descrip;
}
}
return opt;
}
static const char *findNextArg(popt_context con,
unsigned argx, int delete_arg)
{
struct optionStackEntry *os = con->os;
const char *arg;
do {
int i;
arg = NULL;
while (os->next == os->argc && os > con->optionStack)
os--;
if (os->next == os->argc && os == con->optionStack)
break;
if (os->argv != NULL)
for (i = os->next; i < os->argc; i++) {
if (os->argb && PBM_ISSET(i, os->argb))
continue;
if (*os->argv[i] == '-')
continue;
if (--argx > 0)
continue;
arg = os->argv[i];
if (delete_arg) {
if (os->argb == NULL)
os->argb = PBM_ALLOC(os->argc);
if (os->argb != NULL)
PBM_SET(i, os->argb);
}
break;
}
if (os > con->optionStack)
os--;
} while (arg == NULL);
return arg;
}
static const char *expandNextArg(popt_context con, const char *s)
{
const char *a = NULL;
size_t alen;
char *t, *te;
size_t tn = strlen(s) + 1;
char c;
te = t = malloc(tn);;
if (t == NULL)
return NULL;
while ((c = *s++) != '\0') {
switch (c) {
case '!':
if (!(s[0] == '#' && s[1] == ':' && s[2] == '+'))
break;
if (a == NULL) {
if ((a = findNextArg(con, 1, 1)) == NULL)
break;
}
s += 3;
alen = strlen(a);
tn += alen;
*te = '\0';
t = realloc(t, tn);
te = t + strlen(t);
strncpy(te, a, alen);
te += alen;
continue;
break;
default:
break;
}
*te++ = c;
}
*te = '\0';
t = realloc(t, strlen(t) + 1);
return t;
}
static void poptStripArg(popt_context con, int which)
{
if (con->arg_strip == NULL)
con->arg_strip = PBM_ALLOC(con->optionStack[0].argc);
if (con->arg_strip != NULL)
PBM_SET(which, con->arg_strip);
return;
}
int poptSaveLong(long *arg, int argInfo, long aLong)
{
if (arg == NULL || (((unsigned long)arg) & (sizeof (*arg) - 1)))
return POPT_ERROR_NULLARG;
if (argInfo & POPT_ARGFLAG_NOT)
aLong = ~aLong;
switch (argInfo & POPT_ARGFLAG_LOGICALOPS) {
case 0:
*arg = aLong;
break;
case POPT_ARGFLAG_OR:
*arg |= aLong;
break;
case POPT_ARGFLAG_AND:
*arg &= aLong;
break;
case POPT_ARGFLAG_XOR:
*arg ^= aLong;
break;
default:
return POPT_ERROR_BADOPERATION;
break;
}
return 0;
}
int poptSaveInt(int *arg, int argInfo, long aLong)
{
if (arg == NULL || (((unsigned long)arg) & (sizeof (*arg) - 1)))
return POPT_ERROR_NULLARG;
if (argInfo & POPT_ARGFLAG_NOT)
aLong = ~aLong;
switch (argInfo & POPT_ARGFLAG_LOGICALOPS) {
case 0:
*arg = aLong;
break;
case POPT_ARGFLAG_OR:
*arg |= aLong;
break;
case POPT_ARGFLAG_AND:
*arg &= aLong;
break;
case POPT_ARGFLAG_XOR:
*arg ^= aLong;
break;
default:
return POPT_ERROR_BADOPERATION;
break;
}
return 0;
}
int popt_getnextopt(popt_context con)
{
const struct popt_option *opt = NULL;
int done = 0;
if (con == NULL)
return -1;
while (!done) {
const char *origOptString = NULL;
popt_callbacktype cb = NULL;
const void *cbData = NULL;
const char *longArg = NULL;
int canstrip = 0;
int shorty = 0;
while (!con->os->nextCharArg && con->os->next == con->os->argc
&& con->os > con->optionStack) {
cleanOSE(con->os--);
}
if (!con->os->nextCharArg && con->os->next == con->os->argc) {
invokeCallbacksPOST(con, con->options);
if (con->doExec)
return execCommand(con);
return -1;
}
if (!con->os->nextCharArg) {
char *localOptString, *optString;
int thisopt;
if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) {
con->os->next++;
continue;
}
thisopt = con->os->next;
if (con->os->argv != NULL)
origOptString = con->os->argv[con->os->next++];
if (origOptString == NULL)
return POPT_ERROR_BADOPT;
if (con->restLeftover || *origOptString != '-') {
if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
con->restLeftover = 1;
if (con->flags & POPT_CONTEXT_ARG_OPTS) {
con->os->nextArg = strdup(origOptString);
return 0;
}
if (con->leftovers != NULL)
con->leftovers[con->numLeftovers++] = origOptString;
continue;
}
localOptString = optString =
strcpy(alloca(strlen(origOptString) + 1), origOptString);
if (optString[0] == '\0')
return POPT_ERROR_BADOPT;
if (optString[1] == '-' && !optString[2]) {
con->restLeftover = 1;
continue;
}
else {
char *oe;
int singleDash;
optString++;
if (*optString == '-')
singleDash = 0, optString++;
else
singleDash = 1;
if (handleAlias(con, optString, '\0', NULL))
continue;
if (handleExec(con, optString, '\0'))
continue;
for (oe = optString; *oe && *oe != '='; oe++) {
};
if (*oe == '=') {
*oe++ = '\0';
longArg = origOptString + (oe - localOptString);
}
opt = findOption(con->options, optString, '\0', &cb, &cbData,
singleDash);
if (!opt && !singleDash)
return POPT_ERROR_BADOPT;
}
if (!opt) {
con->os->nextCharArg = origOptString + 1;
}
else {
if (con->os == con->optionStack &&
opt->argInfo & POPT_ARGFLAG_STRIP) {
canstrip = 1;
poptStripArg(con, thisopt);
}
shorty = 0;
}
}
if (con->os->nextCharArg) {
origOptString = con->os->nextCharArg;
con->os->nextCharArg = NULL;
if (handleAlias(con, NULL, *origOptString, origOptString + 1))
continue;
if (handleExec(con, NULL, *origOptString)) {
origOptString++;
if (*origOptString != '\0')
con->os->nextCharArg = origOptString;
continue;
}
opt = findOption(con->options, NULL, *origOptString, &cb,
&cbData, 0);
if (!opt)
return POPT_ERROR_BADOPT;
shorty = 1;
origOptString++;
if (*origOptString != '\0')
con->os->nextCharArg = origOptString;
}
if (opt == NULL)
return POPT_ERROR_BADOPT;
if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
if (poptSaveInt((int *)opt->arg, opt->argInfo, 1L))
return POPT_ERROR_BADOPERATION;
}
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
if (opt->arg) {
if (poptSaveInt
((int *)opt->arg, opt->argInfo, (long)opt->val))
return POPT_ERROR_BADOPERATION;
}
}
else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
con->os->nextArg = _free(con->os->nextArg);
if (longArg) {
longArg = expandNextArg(con, longArg);
con->os->nextArg = longArg;
}
else if (con->os->nextCharArg) {
longArg = expandNextArg(con, con->os->nextCharArg);
con->os->nextArg = longArg;
con->os->nextCharArg = NULL;
}
else {
while (con->os->next == con->os->argc &&
con->os > con->optionStack) {
cleanOSE(con->os--);
}
if (con->os->next == con->os->argc) {
if (!(opt->argInfo & POPT_ARGFLAG_OPTIONAL))
return POPT_ERROR_NOARG;
con->os->nextArg = NULL;
}
else {
if (con->os == con->optionStack &&
(opt->argInfo & POPT_ARGFLAG_STRIP) && canstrip) {
poptStripArg(con, con->os->next);
}
if (con->os->argv != NULL) {
longArg = con->os->argv[con->os->next++];
longArg = expandNextArg(con, longArg);
con->os->nextArg = longArg;
}
}
}
longArg = NULL;
if (opt->arg) {
switch (opt->argInfo & POPT_ARG_MASK) {
case POPT_ARG_STRING:
*((const char **)opt->arg) = (con->os->nextArg)
? strdup(con->os->nextArg) : NULL;
break;
case POPT_ARG_INT:
case POPT_ARG_LONG:
{
long aLong = 0;
char *end;
if (con->os->nextArg) {
aLong = strtol(con->os->nextArg, &end, 0);
if (!(end && *end == '\0'))
return POPT_ERROR_BADNUMBER;
}
if ((opt->argInfo & POPT_ARG_MASK) ==
POPT_ARG_LONG) {
if (aLong == LONG_MIN || aLong == LONG_MAX)
return POPT_ERROR_OVERFLOW;
if (poptSaveLong
((long *)opt->arg, opt->argInfo, aLong))
return POPT_ERROR_BADOPERATION;
}
else {
if (aLong > INT_MAX || aLong < INT_MIN)
return POPT_ERROR_OVERFLOW;
if (poptSaveInt
((int *)opt->arg, opt->argInfo, aLong))
return POPT_ERROR_BADOPERATION;
}
}
break;
case POPT_ARG_FLOAT:
case POPT_ARG_DOUBLE:
{
double aDouble = 0.0;
char *end;
if (con->os->nextArg) {
int saveerrno = errno;
errno = 0;
aDouble = strtod(con->os->nextArg, &end);
if (errno == ERANGE)
return POPT_ERROR_OVERFLOW;
errno = saveerrno;
if (*end != '\0')
return POPT_ERROR_BADNUMBER;
}
if ((opt->argInfo & POPT_ARG_MASK) ==
POPT_ARG_DOUBLE) {
*((double *)opt->arg) = aDouble;
}
else {
#define POPT_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
if ((POPT_ABS(aDouble) - FLT_MAX) > DBL_EPSILON)
return POPT_ERROR_OVERFLOW;
if ((FLT_MIN - POPT_ABS(aDouble)) > DBL_EPSILON)
return POPT_ERROR_OVERFLOW;
*((float *)opt->arg) = aDouble;
}
} break;
default:
fprintf(stdout,
POPT_
("option type (%d) not implemented in popt\n"),
(opt->argInfo & POPT_ARG_MASK));
exit(EXIT_FAILURE);
break;
}
}
}
if (cb) {
invokeCallbacksOPTION(con, con->options, opt, cbData, shorty);
}
else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
done = 1;
if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
con->finalArgvAlloced += 10;
con->finalArgv = realloc(con->finalArgv,
sizeof (*con->finalArgv) *
con->finalArgvAlloced);
}
if (con->finalArgv != NULL) {
char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + 3);
if (s != NULL) {
if (opt->longName)
sprintf(s, "%s%s",
((opt->
argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
opt->longName);
else
sprintf(s, "-%c", opt->shortName);
con->finalArgv[con->finalArgvCount++] = s;
}
else
con->finalArgv[con->finalArgvCount++] = NULL;
}
if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) ;
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) ;
else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
if (con->finalArgv != NULL && con->os->nextArg)
con->finalArgv[con->finalArgvCount++] =
strdup(con->os->nextArg);
}
}
return (opt ? opt->val : -1);
}
const char *popt_getoptarg(popt_context con)
{
const char *ret = NULL;
if (con) {
ret = con->os->nextArg;
con->os->nextArg = NULL;
}
return ret;
}
const char *popt_getarg(popt_context con)
{
const char *ret = NULL;
if (con && con->leftovers != NULL
&& con->nextLeftover < con->numLeftovers)
ret = con->leftovers[con->nextLeftover++];
return ret;
}
const char *popt_peekarg(popt_context con)
{
const char *ret = NULL;
if (con && con->leftovers != NULL
&& con->nextLeftover < con->numLeftovers)
ret = con->leftovers[con->nextLeftover];
return ret;
}
const char **popt_getargs(popt_context con)
{
if (con == NULL ||
con->leftovers == NULL || con->numLeftovers == con->nextLeftover)
return NULL;
con->leftovers[con->numLeftovers] = NULL;
return (con->leftovers + con->nextLeftover);
}
popt_context popt_freecontext(popt_context con)
{
popt_item item;
int i;
if (con == NULL)
return con;
popt_resetcontext(con);
con->os->argb = _free(con->os->argb);
if (con->aliases != NULL)
for (i = 0; i < con->numAliases; i++) {
item = con->aliases + i;
item->option.longName = _free(item->option.longName);
item->option.descrip = _free(item->option.descrip);
item->option.argDescrip = _free(item->option.argDescrip);
item->argv = _free(item->argv);
}
con->aliases = _free(con->aliases);
if (con->execs != NULL)
for (i = 0; i < con->numExecs; i++) {
item = con->execs + i;
item->option.longName = _free(item->option.longName);
item->option.descrip = _free(item->option.descrip);
item->option.argDescrip = _free(item->option.argDescrip);
item->argv = _free(item->argv);
}
con->execs = _free(con->execs);
con->leftovers = _free(con->leftovers);
con->finalArgv = _free(con->finalArgv);
con->appName = _free(con->appName);
con->otherHelp = _free(con->otherHelp);
con->execPath = _free(con->execPath);
con->arg_strip = PBM_FREE(con->arg_strip);
con = _free(con);
return con;
}
int popt_addalias(popt_context con, struct popt_alias alias, int flags)
{
popt_item item = alloca(sizeof (*item));
memset(item, 0, sizeof (*item));
item->option.longName = alias.longName;
item->option.shortName = alias.shortName;
item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
item->option.arg = 0;
item->option.val = 0;
item->option.descrip = NULL;
item->option.argDescrip = NULL;
item->argc = alias.argc;
item->argv = alias.argv;
return popt_additem(con, item, 0);
}
int popt_additem(popt_context con, popt_item newItem, int flags)
{
popt_item *items, item;
int *nitems;
switch (flags) {
case 1:
items = &con->execs;
nitems = &con->numExecs;
break;
case 0:
items = &con->aliases;
nitems = &con->numAliases;
break;
default:
return 1;
break;
}
*items = realloc((*items), ((*nitems) + 1) * sizeof (**items));
if ((*items) == NULL)
return 1;
item = (*items) + (*nitems);
item->option.longName =
(newItem->option.longName ? strdup(newItem->option.longName) : NULL);
item->option.shortName = newItem->option.shortName;
item->option.argInfo = newItem->option.argInfo;
item->option.arg = newItem->option.arg;
item->option.val = newItem->option.val;
item->option.descrip =
(newItem->option.descrip ? strdup(newItem->option.descrip) : NULL);
item->option.argDescrip =
(newItem->option.
argDescrip ? strdup(newItem->option.argDescrip) : NULL);
item->argc = newItem->argc;
item->argv = newItem->argv;
(*nitems)++;
return 0;
}
const char *popt_badoption(popt_context con, int flags)
{
struct optionStackEntry *os = NULL;
if (con != NULL)
os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os;
return (os && os->argv ? os->argv[os->next - 1] : NULL);
}
const char *const popt_strerror(const int error)
{
switch (error) {
case POPT_ERROR_NOARG:
return POPT_("missing argument");
case POPT_ERROR_BADOPT:
return POPT_("unknown option");
case POPT_ERROR_BADOPERATION:
return POPT_("mutually exclusive logical operations requested");
case POPT_ERROR_NULLARG:
return POPT_("opt->arg should not be NULL");
case POPT_ERROR_OPTSTOODEEP:
return POPT_("aliases nested too deeply");
case POPT_ERROR_BADQUOTE:
return POPT_("error in parameter quoting");
case POPT_ERROR_BADNUMBER:
return POPT_("invalid numeric value");
case POPT_ERROR_OVERFLOW:
return POPT_("number too large or too small");
case POPT_ERROR_MALLOC:
return POPT_("memory allocation failed");
case POPT_ERROR_ERRNO:
return strerror(errno);
default:
return POPT_("unknown error");
}
}
int popt_stuffargs(popt_context con, const char **argv)
{
int argc;
int rc;
if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
return POPT_ERROR_OPTSTOODEEP;
for (argc = 0; argv[argc]; argc++) {
};
con->os++;
con->os->next = 0;
con->os->nextArg = NULL;
con->os->nextCharArg = NULL;
con->os->currAlias = NULL;
rc = popt_dupargv(argc, argv, &con->os->argc, &con->os->argv);
con->os->argb = NULL;
con->os->stuffed = 1;
return rc;
}
const char *popt_getinvocationname(popt_context con)
{
return (con->os->argv ? con->os->argv[0] : "");
}
int popt_strippedargv(popt_context con, int argc, char **argv)
{
int numargs = argc;
int j = 1;
int i;
if (con->arg_strip)
for (i = 1; i < argc; i++) {
if (PBM_ISSET(i, con->arg_strip))
numargs--;
}
for (i = 1; i < argc; i++) {
if (con->arg_strip && PBM_ISSET(i, con->arg_strip))
continue;
argv[j] = (j < numargs) ? argv[i] : NULL;
j++;
}
return numargs;
}
#define POPT_ARGV_ARRAY_GROW_DELTA 5
int popt_dupargv(int argc, const char **argv,
int *argcPtr, const char ***argvPtr)
{
size_t nb = (argc + 1) * sizeof (*argv);
const char **argv2;
char *dst;
int i;
if (argc <= 0 || argv == NULL)
return POPT_ERROR_NOARG;
for (i = 0; i < argc; i++) {
if (argv[i] == NULL)
return POPT_ERROR_NOARG;
nb += strlen(argv[i]) + 1;
}
dst = malloc(nb);
if (dst == NULL)
return POPT_ERROR_MALLOC;
argv2 = (void *)dst;
dst += (argc + 1) * sizeof (*argv);
for (i = 0; i < argc; i++) {
argv2[i] = dst;
dst += strlen(strcpy(dst, argv[i])) + 1;
}
argv2[argc] = NULL;
if (argvPtr) {
*argvPtr = argv2;
}
else {
free(argv2);
argv2 = NULL;
}
if (argcPtr)
*argcPtr = argc;
return 0;
}
int popt_parseargvstring(const char *s, int *argcPtr, const char ***argvPtr)
{
const char *src;
char quote = '\0';
int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
const char **argv = malloc(sizeof (*argv) * argvAlloced);
int argc = 0;
int buflen = strlen(s) + 1;
char *buf = memset(alloca(buflen), 0, buflen);
int rc = POPT_ERROR_MALLOC;
if (argv == NULL)
return rc;
argv[argc] = buf;
for (src = s; *src != '\0'; src++) {
if (quote == *src) {
quote = '\0';
}
else if (quote != '\0') {
if (*src == '\\') {
src++;
if (!*src) {
rc = POPT_ERROR_BADQUOTE;
goto exit;
}
if (*src != quote)
*buf++ = '\\';
}
*buf++ = *src;
}
else if (isspace(*src)) {
if (*argv[argc] != '\0') {
buf++, argc++;
if (argc == argvAlloced) {
argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
argv = realloc(argv, sizeof (*argv) * argvAlloced);
if (argv == NULL)
goto exit;
}
argv[argc] = buf;
}
}
else
switch (*src) {
case '"':
case '\'':
quote = *src;
break;
case '\\':
src++;
if (!*src) {
rc = POPT_ERROR_BADQUOTE;
goto exit;
}
default:
*buf++ = *src;
break;
}
}
if (strlen(argv[argc])) {
argc++, buf++;
}
rc = popt_dupargv(argc, argv, argcPtr, argvPtr);
exit:
if (argv)
free(argv);
return rc;
}
int poptConfigFileToString(FILE * fp, char **argstrp, int flags)
{
char line[999];
char *argstr;
char *p;
char *q;
char *x;
int t;
int argvlen = 0;
size_t maxlinelen = sizeof (line);
size_t linelen;
int maxargvlen = 480;
int linenum = 0;
*argstrp = NULL;
if (fp == NULL)
return POPT_ERROR_NULLARG;
argstr = calloc(maxargvlen, sizeof (*argstr));
if (argstr == NULL)
return POPT_ERROR_MALLOC;
while (fgets(line, (int)maxlinelen, fp) != NULL) {
linenum++;
p = line;
while (*p != '\0' && isspace(*p))
p++;
linelen = strlen(p);
if (linelen >= maxlinelen - 1)
return POPT_ERROR_OVERFLOW;
if (*p == '\0' || *p == '\n')
continue;
if (*p == '#')
continue;
q = p;
while (*q != '\0' && (!isspace(*q)) && *q != '=')
q++;
if (isspace(*q)) {
*q++ = '\0';
while (*q != '\0' && isspace((int)*q))
q++;
}
if (*q == '\0') {
q[-1] = '\0';
argvlen += (t = q - p) + (sizeof (" --") - 1);
if (argvlen >= maxargvlen) {
maxargvlen = (t > maxargvlen) ? t * 2 : maxargvlen * 2;
argstr = realloc(argstr, maxargvlen);
if (argstr == NULL)
return POPT_ERROR_MALLOC;
}
strcat(argstr, " --");
strcat(argstr, p);
continue;
}
if (*q != '=')
continue;
*q++ = '\0';
while (*q != '\0' && isspace(*q))
q++;
if (*q == '\0')
continue;
x = p + linelen;
while (isspace(*--x))
*x = 0;
t = x - p;
argvlen += t + (sizeof ("' --='") - 1);
if (argvlen >= maxargvlen) {
maxargvlen = (t > maxargvlen) ? t * 2 : maxargvlen * 2;
argstr = realloc(argstr, maxargvlen);
if (argstr == NULL)
return POPT_ERROR_MALLOC;
}
strcat(argstr, " --");
strcat(argstr, p);
strcat(argstr, "=\"");
strcat(argstr, q);
strcat(argstr, "\"");
}
*argstrp = argstr;
return 0;
}
static void configLine(popt_context con, char *line)
{
int nameLength = strlen(con->appName);
const char *entryType;
const char *opt;
popt_item item = alloca(sizeof (*item));
int i, j;
memset(item, 0, sizeof (*item));
if (strncmp(line, con->appName, nameLength))
return;
line += nameLength;
if (*line == '\0' || !isspace(*line))
return;
while (*line != '\0' && isspace(*line))
line++;
entryType = line;
while (*line == '\0' || !isspace(*line))
line++;
*line++ = '\0';
while (*line != '\0' && isspace(*line))
line++;
if (*line == '\0')
return;
opt = line;
while (*line == '\0' || !isspace(*line))
line++;
*line++ = '\0';
while (*line != '\0' && isspace(*line))
line++;
if (*line == '\0')
return;
if (opt[0] == '-' && opt[1] == '-')
item->option.longName = opt + 2;
else if (opt[0] == '-' && opt[2] == '\0')
item->option.shortName = opt[1];
if (popt_parseargvstring(line, &item->argc, &item->argv))
return;
item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
for (i = 0, j = 0; i < item->argc; i++, j++) {
const char *f;
if (!strncmp
(item->argv[i], "--POPTdesc=", sizeof ("--POPTdesc=") - 1)) {
f = item->argv[i] + sizeof ("--POPTdesc=");
if (f[0] == '$' && f[1] == '"')
f++;
item->option.descrip = f;
item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
j--;
}
else if (!strncmp
(item->argv[i], "--POPTargs=", sizeof ("--POPTargs=") - 1)) {
f = item->argv[i] + sizeof ("--POPTargs=");
if (f[0] == '$' && f[1] == '"')
f++;
item->option.argDescrip = f;
item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN;
item->option.argInfo |= POPT_ARG_STRING;
j--;
}
else if (j != i)
item->argv[j] = item->argv[i];
}
if (j != i) {
item->argv[j] = NULL;
item->argc = j;
}
if (!strcmp(entryType, "alias"))
(void)popt_additem(con, item, 0);
else if (!strcmp(entryType, "exec"))
(void)popt_additem(con, item, 1);
}
int popt_readconfigfile(popt_context con, const char *fn)
{
const char *file, *chptr, *end;
char *buf;
char *dst;
int fd, rc;
off_t fileLength;
fd = open(fn, O_RDONLY);
if (fd < 0)
return (errno == ENOENT ? 0 : POPT_ERROR_ERRNO);
fileLength = lseek(fd, 0, SEEK_END);
if (fileLength == -1 || lseek(fd, 0, 0) == -1) {
rc = errno;
(void)close(fd);
errno = rc;
return POPT_ERROR_ERRNO;
}
file = alloca(fileLength + 1);
if (read(fd, (char *)file, fileLength) != fileLength) {
rc = errno;
(void)close(fd);
errno = rc;
return POPT_ERROR_ERRNO;
}
if (close(fd) == -1)
return POPT_ERROR_ERRNO;
dst = buf = alloca(fileLength + 1);
chptr = file;
end = (file + fileLength);
while (chptr < end) {
switch (*chptr) {
case '\n':
*dst = '\0';
dst = buf;
while (*dst && isspace(*dst))
dst++;
if (*dst && *dst != '#')
configLine(con, dst);
chptr++;
break;
case '\\':
*dst++ = *chptr++;
if (chptr < end) {
if (*chptr == '\n')
dst--, chptr++;
else
*dst++ = *chptr++;
}
break;
default:
*dst++ = *chptr++;
break;
}
}
return 0;
}
int popt_readdefaultconfig(popt_context con, int useEnv)
{
char *fn, *home;
int rc;
if (!con->appName)
return 0;
rc = popt_readconfigfile(con, "/etc/popt");
if (rc)
return rc;
#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
if (getuid() != geteuid())
return 0;
#endif
if ((home = getenv("HOME"))) {
fn = alloca(strlen(home) + 20);
strcpy(fn, home);
strcat(fn, "/.popt");
rc = popt_readconfigfile(con, fn);
if (rc)
return rc;
}
return 0;
}
static void displayArgs(popt_context con,
enum popt_callbackreason foo,
struct popt_option *key, const char *arg, void *data)
{
if (key->shortName == '?')
popt_printhelp(con, stdout, 0);
else
popt_printusage(con, stdout, 0);
exit(0);
}
struct popt_option popt_aliasOptions[] = {
POPT_TABLEEND
};
struct popt_option popt_helpoptions[] = {
{NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL},
{"help", '?', 0, NULL, '?', N_("Show this help message"), NULL},
{"usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL},
POPT_TABLEEND
};
static const char *const
getTableTranslationDomain(const struct popt_option *table)
{
const struct popt_option *opt;
if (table != NULL)
for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
return opt->arg;
}
return NULL;
}
static const char *const
getArgDescrip(const struct popt_option *opt, const char *translation_domain)
{
if (!(opt->argInfo & POPT_ARG_MASK))
return NULL;
if (opt == (popt_helpoptions + 1) || opt == (popt_helpoptions + 2))
if (opt->argDescrip)
return POPT_(opt->argDescrip);
if (opt->argDescrip)
return D_(translation_domain, opt->argDescrip);
switch (opt->argInfo & POPT_ARG_MASK) {
case POPT_ARG_NONE:
return POPT_("NONE");
#ifdef DYING
case POPT_ARG_VAL:
return POPT_("VAL");
#else
case POPT_ARG_VAL:
return NULL;
#endif
case POPT_ARG_INT:
return POPT_("INT");
case POPT_ARG_LONG:
return POPT_("LONG");
case POPT_ARG_STRING:
return POPT_("STRING");
case POPT_ARG_FLOAT:
return POPT_("FLOAT");
case POPT_ARG_DOUBLE:
return POPT_("DOUBLE");
default:
return POPT_("ARG");
}
}
static char *singleOptionDefaultValue(int lineLength,
const struct popt_option *opt,
const char *translation_domain)
{
const char *defstr = D_(translation_domain, "default");
char *le = malloc(4 * lineLength + 1);
char *l = le;
if (le == NULL)
return NULL;
*le = '\0';
*le++ = '(';
strcpy(le, defstr);
le += strlen(le);
*le++ = ':';
*le++ = ' ';
if (opt->arg)
switch (opt->argInfo & POPT_ARG_MASK) {
case POPT_ARG_VAL:
case POPT_ARG_INT:
{
long aLong = *((int *)opt->arg);
le += sprintf(le, "%ld", aLong);
} break;
case POPT_ARG_LONG:
{
long aLong = *((long *)opt->arg);
le += sprintf(le, "%ld", aLong);
} break;
case POPT_ARG_FLOAT:
{
double aDouble = *((float *)opt->arg);
le += sprintf(le, "%g", aDouble);
} break;
case POPT_ARG_DOUBLE:
{
double aDouble = *((double *)opt->arg);
le += sprintf(le, "%g", aDouble);
} break;
case POPT_ARG_STRING:
{
const char *s = *(const char **)opt->arg;
if (s == NULL) {
strcpy(le, "null");
le += strlen(le);
}
else {
size_t slen =
4 * lineLength - (le - l) - sizeof ("\"...\")");
*le++ = '"';
strncpy(le, s, slen);
le[slen] = '\0';
le += strlen(le);
if (slen < strlen(s)) {
strcpy(le, "...");
le += strlen(le);
}
*le++ = '"';
}
}
break;
case POPT_ARG_NONE:
default:
l = _free(l);
return NULL;
break;
}
*le++ = ')';
*le = '\0';
return l;
}
static void singleOptionHelp(FILE * fp, int maxLeftCol,
const struct popt_option *opt,
const char *translation_domain)
{
int indentLength = maxLeftCol + 5;
int lineLength = 79 - indentLength;
const char *help = D_(translation_domain, opt->descrip);
const char *argDescrip = getArgDescrip(opt, translation_domain);
int helpLength;
char *defs = NULL;
char *left;
int nb = maxLeftCol + 1;
if (opt->longName)
nb += strlen(opt->longName);
if (argDescrip)
nb += strlen(argDescrip);
left = malloc(nb);
if (left == NULL)
return;
left[0] = '\0';
left[maxLeftCol] = '\0';
if (opt->longName && opt->shortName)
sprintf(left, "-%c, %s%s", opt->shortName,
((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
opt->longName);
else if (opt->shortName != '\0')
sprintf(left, "-%c", opt->shortName);
else if (opt->longName)
sprintf(left, "%s%s",
((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
opt->longName);
if (!*left)
goto out;
if (argDescrip) {
char *le = left + strlen(left);
if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
*le++ = '[';
if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
defs =
singleOptionDefaultValue(lineLength, opt, translation_domain);
if (defs) {
char *t = malloc((help ? strlen(help) : 0) +
strlen(defs) + sizeof (" "));
if (t) {
char *te = t;
*te = '\0';
if (help) {
strcpy(te, help);
te += strlen(te);
}
*te++ = ' ';
strcpy(te, defs);
defs = _free(defs);
}
defs = t;
}
}
if (opt->argDescrip == NULL) {
switch (opt->argInfo & POPT_ARG_MASK) {
case POPT_ARG_NONE:
break;
case POPT_ARG_VAL:
#ifdef NOTNOW
{
long aLong = opt->val;
int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
if (!ops
&& (aLong == 0L || aLong == 1L || aLong == -1L))
break;
*le++ = '[';
switch (ops) {
case POPT_ARGFLAG_OR:
*le++ = '|';
break;
case POPT_ARGFLAG_AND:
*le++ = '&';
break;
case POPT_ARGFLAG_XOR:
*le++ = '^';
break;
default:
break;
}
*le++ = '=';
if (negate)
*le++ = '~';
le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong);
*le++ = ']';
}
#endif
break;
case POPT_ARG_INT:
case POPT_ARG_LONG:
case POPT_ARG_FLOAT:
case POPT_ARG_DOUBLE:
case POPT_ARG_STRING:
*le++ = '=';
strcpy(le, argDescrip);
le += strlen(le);
break;
default:
break;
}
}
else {
*le++ = '=';
strcpy(le, argDescrip);
le += strlen(le);
}
if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
*le++ = ']';
*le = '\0';
}
if (help)
fprintf(fp, " %-*s ", maxLeftCol, left);
else {
fprintf(fp, " %s\n", left);
goto out;
}
left = _free(left);
if (defs) {
help = defs;
defs = NULL;
}
helpLength = strlen(help);
while (helpLength > lineLength) {
const char *ch;
char format[16];
ch = help + lineLength - 1;
while (ch > help && !isspace(*ch))
ch--;
if (ch == help)
break;
while (ch > (help + 1) && isspace(*ch))
ch--;
ch++;
sprintf(format, "%%.%ds\n%%%ds", (int)(ch - help), indentLength);
fprintf(fp, format, help, " ");
help = ch;
while (isspace(*help) && *help)
help++;
helpLength = strlen(help);
}
if (helpLength)
fprintf(fp, "%s\n", help);
out:
defs = _free(defs);
left = _free(left);
}
static int maxArgWidth(const struct popt_option *opt,
const char *translation_domain)
{
int max = 0;
int len = 0;
const char *s;
if (opt != NULL)
while (opt->longName || opt->shortName || opt->arg) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
if (opt->arg)
len = maxArgWidth(opt->arg, translation_domain);
if (len > max)
max = len;
}
else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
len = sizeof (" ") - 1;
if (opt->shortName != '\0')
len += sizeof ("-X") - 1;
if (opt->shortName != '\0' && opt->longName)
len += sizeof (", ") - 1;
if (opt->longName) {
len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
? sizeof ("-") - 1 : sizeof ("--") - 1);
len += strlen(opt->longName);
}
s = getArgDescrip(opt, translation_domain);
if (s)
len += sizeof ("=") - 1 + strlen(s);
if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
len += sizeof ("[]") - 1;
if (len > max)
max = len;
}
opt++;
}
return max;
}
static void itemHelp(FILE * fp,
popt_item items, int nitems, int left,
const char *translation_domain)
{
popt_item item;
int i;
if (items != NULL)
for (i = 0, item = items; i < nitems; i++, item++) {
const struct popt_option *opt;
opt = &item->option;
if ((opt->longName || opt->shortName) &&
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
singleOptionHelp(fp, left, opt, translation_domain);
}
}
static void singleTableHelp(popt_context con, FILE * fp,
const struct popt_option *table, int left,
const char *translation_domain)
{
const struct popt_option *opt;
const char *sub_transdom;
if (table == popt_aliasOptions) {
itemHelp(fp, con->aliases, con->numAliases, left, NULL);
itemHelp(fp, con->execs, con->numExecs, left, NULL);
return;
}
if (table != NULL)
for (opt = table; (opt->longName || opt->shortName || opt->arg);
opt++) {
if ((opt->longName || opt->shortName)
&& !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
singleOptionHelp(fp, left, opt, translation_domain);
}
if (table != NULL)
for (opt = table; (opt->longName || opt->shortName || opt->arg);
opt++) {
if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
continue;
sub_transdom = getTableTranslationDomain(opt->arg);
if (sub_transdom == NULL)
sub_transdom = translation_domain;
if (opt->descrip)
fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
singleTableHelp(con, fp, opt->arg, left, sub_transdom);
}
}
static int showHelpIntro(popt_context con, FILE * fp)
{
int len = 6;
const char *fn;
fprintf(fp, POPT_("Usage:"));
if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
fn = con->optionStack->argv[0];
if (fn == NULL)
return len;
if (strchr(fn, '/'))
fn = strrchr(fn, '/') + 1;
fprintf(fp, " %s", fn);
len += strlen(fn) + 1;
}
return len;
}
void popt_printhelp(popt_context con, FILE * fp, int flags)
{
int leftColWidth;
(void)showHelpIntro(con, fp);
if (con->otherHelp)
fprintf(fp, " %s\n", con->otherHelp);
else
fprintf(fp, " %s\n", POPT_("[OPTION...]"));
leftColWidth = maxArgWidth(con->options, NULL);
singleTableHelp(con, fp, con->options, leftColWidth, NULL);
}
static int singleOptionUsage(FILE * fp, int cursor,
const struct popt_option *opt,
const char *translation_domain)
{
int len = 4;
char shortStr[2] = { '\0', '\0' };
const char *item = shortStr;
const char *argDescrip = getArgDescrip(opt, translation_domain);
if (opt->shortName != '\0' && opt->longName != NULL) {
len += 2;
if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH))
len++;
len += strlen(opt->longName);
}
else if (opt->shortName != '\0') {
len++;
shortStr[0] = opt->shortName;
shortStr[1] = '\0';
}
else if (opt->longName) {
len += strlen(opt->longName);
if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH))
len++;
item = opt->longName;
}
if (len == 4)
return cursor;
if (argDescrip)
len += strlen(argDescrip) + 1;
if ((cursor + len) > 79) {
fprintf(fp, "\n ");
cursor = 7;
}
if (opt->longName && opt->shortName) {
fprintf(fp, " [-%c|-%s%s%s%s]",
opt->shortName,
((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"),
opt->longName, (argDescrip ? " " : ""),
(argDescrip ? argDescrip : ""));
}
else {
fprintf(fp, " [-%s%s%s%s]",
((opt->shortName
|| (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"), item,
(argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
(argDescrip ? argDescrip : ""));
}
return cursor + len + 1;
}
static int itemUsage(FILE * fp, int cursor, popt_item item, int nitems,
const char *translation_domain)
{
int i;
if (item != NULL)
for (i = 0; i < nitems; i++, item++) {
const struct popt_option *opt;
opt = &item->option;
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
translation_domain = (const char *)opt->arg;
}
else if ((opt->longName || opt->shortName) &&
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
cursor =
singleOptionUsage(fp, cursor, opt, translation_domain);
}
}
return cursor;
}
typedef struct poptDone_s {
int nopts;
int maxopts;
const void **opts;
} *poptDone;
static int singleTableUsage(popt_context con, FILE * fp, int cursor,
const struct popt_option *opt,
const char *translation_domain, poptDone done)
{
if (opt != NULL)
for (; (opt->longName || opt->shortName || opt->arg); opt++) {
if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
translation_domain = (const char *)opt->arg;
}
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
if (done) {
int i = 0;
for (i = 0; i < done->nopts; i++) {
const void *that = done->opts[i];
if (that == NULL || that != opt->arg)
continue;
break;
}
if (opt->arg == NULL || i < done->nopts)
continue;
if (done->nopts < done->maxopts)
done->opts[done->nopts++] = (const void *)opt->arg;
}
cursor = singleTableUsage(con, fp, cursor, opt->arg,
translation_domain, done);
}
else if ((opt->longName || opt->shortName) &&
!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
cursor =
singleOptionUsage(fp, cursor, opt, translation_domain);
}
}
return cursor;
}
static int showShortOptions(const struct popt_option *opt, FILE * fp,
char *str)
{
char *s = alloca(300);
s[0] = '\0';
if (str == NULL) {
memset(s, 0, sizeof (s));
str = s;
}
if (opt != NULL)
for (; (opt->longName || opt->shortName || opt->arg); opt++) {
if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
str[strlen(str)] = opt->shortName;
else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
if (opt->arg)
(void)showShortOptions(opt->arg, fp, str);
}
if (s != str || *s != '\0')
return 0;
fprintf(fp, " [-%s]", s);
return strlen(s) + 4;
}
void popt_printusage(popt_context con, FILE * fp, int flags)
{
poptDone done = memset(alloca(sizeof (*done)), 0, sizeof (*done));
int cursor;
done->nopts = 0;
done->maxopts = 64;
cursor = done->maxopts * sizeof (*done->opts);
done->opts = memset(alloca(cursor), 0, cursor);
done->opts[done->nopts++] = (const void *)con->options;
cursor = showHelpIntro(con, fp);
cursor += showShortOptions(con->options, fp, NULL);
cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done);
cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
if (con->otherHelp) {
cursor += strlen(con->otherHelp) + 1;
if (cursor > 79)
fprintf(fp, "\n ");
fprintf(fp, " %s", con->otherHelp);
}
fprintf(fp, "\n");
}
void popt_setotheroptionhelp(popt_context con, const char *text)
{
con->otherHelp = _free(con->otherHelp);
con->otherHelp = strdup(text);
}