From cc248aae9bff569a771210e9b63f6f4dfe83e3a6 Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 27 Jul 2002 18:32:25 +0000 Subject: [PATCH] Updated to version 1.6.4. --- popt/CHANGES | 5 +- popt/README | 2 +- popt/README.rsync | 9 +- popt/findme.c | 30 +- popt/findme.h | 16 +- popt/popt.c | 1032 ++++++++++++++++++++++++++++++++------------- popt/popt.h | 484 +++++++++++++++++---- popt/poptconfig.c | 173 +++++--- popt/popthelp.c | 591 ++++++++++++++++++++------ popt/poptint.h | 73 ++-- popt/poptparse.c | 58 ++- popt/system.h | 13 +- 12 files changed, 1837 insertions(+), 649 deletions(-) diff --git a/popt/CHANGES b/popt/CHANGES index b6ab2aa3..db16a5fd 100644 --- a/popt/CHANGES +++ b/popt/CHANGES @@ -1,4 +1,7 @@ -1.3 -> +1.5 -> 1.6 + - add ability to perform callbacks for every, not just first, match. + +1.3 -> 1.5 - heavy dose of const's - poptParseArgvString() now NULL terminates the list diff --git a/popt/README b/popt/README index 7fccc836..0b5205bf 100644 --- a/popt/README +++ b/popt/README @@ -5,7 +5,7 @@ to getopt(3), it contains a number of enhancements, including: 2) popt can parse arbitrary argv[] style arrays while getopt(2) makes this quite difficult 3) popt allows users to alias command line arguments - 4) popt provides convience functions for parsting strings + 4) popt provides convience functions for parsing strings into argv[] style arrays popt is used by rpm, the Red Hat install program, and many other Red Hat diff --git a/popt/README.rsync b/popt/README.rsync index f31a8820..1cf54d5d 100644 --- a/popt/README.rsync +++ b/popt/README.rsync @@ -1,5 +1,4 @@ -Unlike zlib, this is a perfectly ordinary copy of libpopt. It's only -used on platforms that don't have a sufficiently up-to-date copy of -their own. If you build rsync on a platform which has popt, this -directory should not be used. (You can control that using ---with-included-popt.) +This is a perfectly ordinary copy of libpopt. It is only used on platforms +that do not have a sufficiently up-to-date copy of their own. If you build +rsync on a platform which has popt, this directory should not be used. (You +can control that using the --with-included-popt configure flag.) diff --git a/popt/findme.c b/popt/findme.c index f2ad05bb..e98e0611 100644 --- a/popt/findme.c +++ b/popt/findme.c @@ -1,6 +1,10 @@ -/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING +/** \ingroup popt + * \file popt/findme.c + */ + +/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from - ftp://ftp.redhat.com/pub/code/popt */ + ftp://ftp.rpm.org/pub/rpm/dist. */ #include "system.h" #include "findme.h" @@ -9,38 +13,38 @@ const char * findProgramPath(const char * argv0) { char * path = getenv("PATH"); char * pathbuf; char * start, * chptr; - char * buf, *local = NULL; + char * buf; - /* If there is a / in the argv[0], it has to be an absolute - path */ + if (argv0 == NULL) return NULL; /* XXX can't happen */ + /* If there is a / in the argv[0], it has to be an absolute path */ if (strchr(argv0, '/')) return xstrdup(argv0); - if (!path) return NULL; + if (path == NULL) return NULL; - local = start = pathbuf = malloc(strlen(path) + 1); - buf = malloc(strlen(path) + strlen(argv0) + 2); + start = pathbuf = alloca(strlen(path) + 1); + buf = malloc(strlen(path) + strlen(argv0) + sizeof("/")); + if (buf == NULL) return NULL; /* XXX can't happen */ strcpy(pathbuf, path); chptr = NULL; + /*@-branchstate@*/ do { if ((chptr = strchr(start, ':'))) *chptr = '\0'; sprintf(buf, "%s/%s", start, argv0); - if (!access(buf, X_OK)) { - if (local) free(local); - return buf; - } + if (!access(buf, X_OK)) + return buf; if (chptr) start = chptr + 1; else start = NULL; } while (start && *start); + /*@=branchstate@*/ free(buf); - if (local) free(local); return NULL; } diff --git a/popt/findme.h b/popt/findme.h index 5e93963d..a016b867 100644 --- a/popt/findme.h +++ b/popt/findme.h @@ -1,10 +1,20 @@ -/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING +/** \ingroup popt + * \file popt/findme.h + */ + +/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from - ftp://ftp.redhat.com/pub/code/popt */ + ftp://ftp.rpm.org/pub/rpm/dist. */ #ifndef H_FINDME #define H_FINDME -const char * findProgramPath(const char * argv0); +/** + * Return absolute path to executable by searching PATH. + * @param argv0 name of executable + * @return (malloc'd) absolute path to executable (or NULL) + */ +/*@null@*/ const char * findProgramPath(/*@null@*/ const char * argv0) + /*@*/; #endif diff --git a/popt/popt.c b/popt/popt.c index aef79566..962f9732 100644 --- a/popt/popt.c +++ b/popt/popt.c @@ -1,8 +1,20 @@ -/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING +/** \ingroup popt + * \file popt/popt.c + */ + +/* (C) 19982000 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from - ftp://ftp.redhat.com/pub/code/popt */ + ftp://ftp.rpm.org/pub/rpm/dist */ + +#undef MYDEBUG #include "system.h" + +#if HAVE_FLOAT_H +#include +#endif +#include + #include "findme.h" #include "poptint.h" @@ -18,47 +30,143 @@ static char * strerror(int errno) { } #endif -void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) { - if (con->execPath) xfree(con->execPath); +#ifdef MYDEBUG +/*@unused@*/ static void prtcon(const char *msg, poptContext con) +{ + if (msg) fprintf(stderr, "%s", msg); + fprintf(stderr, "\tcon %p os %p nextCharArg \"%s\" nextArg \"%s\" argv[%d] \"%s\"\n", + con, con->os, + (con->os->nextCharArg ? con->os->nextCharArg : ""), + (con->os->nextArg ? con->os->nextArg : ""), + con->os->next, + (con->os->argv && con->os->argv[con->os->next] + ? con->os->argv[con->os->next] : "")); +} +#endif + +void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) +{ + con->execPath = _free(con->execPath); con->execPath = xstrdup(path); con->execAbsolute = allowAbsolute; + /*@-nullstate@*/ /* LCL: con->execPath can be NULL? */ + return; + /*@=nullstate@*/ } -static void invokeCallbacks(poptContext con, const struct poptOption * table, - int post) { - const struct poptOption * opt = table; - poptCallbackType cb; +static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt) + /*@globals internalState@*/ + /*@modifies internalState@*/ +{ + if (opt != NULL) + for (; opt->longName || opt->shortName || opt->arg; opt++) { + if (opt->arg == NULL) continue; /* XXX program error. */ + if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { + /* Recurse on included sub-tables. */ + invokeCallbacksPRE(con, opt->arg); + } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && + (opt->argInfo & POPT_CBFLAG_PRE)) + { /*@-castfcnptr@*/ + poptCallbackType cb = (poptCallbackType)opt->arg; + /*@=castfcnptr@*/ + /* Perform callback. */ + /*@-moduncon -noeffectuncon @*/ + cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip); + /*@=moduncon =noeffectuncon @*/ + } + } +} - while (opt->longName || opt->shortName || opt->arg) { +static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt) + /*@globals internalState@*/ + /*@modifies internalState@*/ +{ + if (opt != NULL) + for (; opt->longName || opt->shortName || opt->arg; opt++) { + if (opt->arg == NULL) continue; /* XXX program error. */ if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { - invokeCallbacks(con, opt->arg, post); - } else if (((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) && - ((!post && (opt->argInfo & POPT_CBFLAG_PRE)) || - ( post && (opt->argInfo & POPT_CBFLAG_POST)))) { - cb = (poptCallbackType)opt->arg; - cb(con, post ? POPT_CALLBACK_REASON_POST : POPT_CALLBACK_REASON_PRE, - NULL, NULL, opt->descrip); + /* Recurse on included sub-tables. */ + invokeCallbacksPOST(con, opt->arg); + } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && + (opt->argInfo & POPT_CBFLAG_POST)) + { /*@-castfcnptr@*/ + poptCallbackType cb = (poptCallbackType)opt->arg; + /*@=castfcnptr@*/ + /* Perform callback. */ + /*@-moduncon -noeffectuncon @*/ + cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip); + /*@=moduncon =noeffectuncon @*/ + } + } +} + +static void invokeCallbacksOPTION(poptContext con, + const struct poptOption * opt, + const struct poptOption * myOpt, + /*@null@*/ const void * myData, int shorty) + /*@globals internalState@*/ + /*@modifies internalState@*/ +{ + const struct poptOption * cbopt = NULL; + + if (opt != NULL) + for (; opt->longName || opt->shortName || opt->arg; opt++) { + if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { + /* Recurse on included sub-tables. */ + if (opt->arg != NULL) /* XXX program error */ + invokeCallbacksOPTION(con, opt->arg, myOpt, myData, shorty); + } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && + !(opt->argInfo & POPT_CBFLAG_SKIPOPTION)) { + /* Save callback info. */ + cbopt = opt; + } else if (cbopt != NULL && + ((myOpt->shortName && opt->shortName && shorty && + myOpt->shortName == opt->shortName) || + (myOpt->longName && opt->longName && + /*@-nullpass@*/ /* LCL: opt->longName != NULL */ + !strcmp(myOpt->longName, opt->longName))) + /*@=nullpass@*/ + ) + { /*@-castfcnptr@*/ + poptCallbackType cb = (poptCallbackType)cbopt->arg; + /*@=castfcnptr@*/ + const void * cbData = (cbopt->descrip ? cbopt->descrip : myData); + /* Perform callback. */ + if (cb != NULL) { /* XXX program error */ + /*@-moduncon -noeffectuncon @*/ + cb(con, POPT_CALLBACK_REASON_OPTION, myOpt, + con->os->nextArg, cbData); + /*@=moduncon =noeffectuncon @*/ + } + /* Terminate (unless explcitly continuing). */ + if (!(cbopt->argInfo & POPT_CBFLAG_CONTINUE)) + return; } - opt++; } } poptContext poptGetContext(const char * name, int argc, const char ** argv, - const struct poptOption * options, int flags) { + const struct poptOption * options, int flags) +{ poptContext con = malloc(sizeof(*con)); + if (con == NULL) return NULL; /* XXX can't happen */ memset(con, 0, sizeof(*con)); con->os = con->optionStack; con->os->argc = argc; + /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ con->os->argv = argv; + /*@=dependenttrans =assignexpose@*/ con->os->argb = NULL; if (!(flags & POPT_CONTEXT_KEEP_FIRST)) con->os->next = 1; /* skip argv[0] */ - con->leftovers = calloc( (argc + 1), sizeof(char *) ); + con->leftovers = calloc( (argc + 1), sizeof(*con->leftovers) ); + /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ con->options = options; + /*@=dependenttrans =assignexpose@*/ con->aliases = NULL; con->numAliases = 0; con->flags = flags; @@ -72,40 +180,37 @@ poptContext poptGetContext(const char * name, int argc, const char ** argv, if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER")) con->flags |= POPT_CONTEXT_POSIXMEHARDER; - if (name) - con->appName = strcpy(malloc(strlen(name) + 1), name); + if (name) { + char * t = malloc(strlen(name) + 1); + if (t) con->appName = strcpy(t, name); + } - invokeCallbacks(con, con->options, 0); + /*@-internalglobs@*/ + invokeCallbacksPRE(con, con->options); + /*@=internalglobs@*/ return con; } -static void cleanOSE(struct optionStackEntry *os) +static void cleanOSE(/*@special@*/ struct optionStackEntry *os) + /*@uses os @*/ + /*@releases os->nextArg, os->argv, os->argb @*/ + /*@modifies os @*/ { - if (os->nextArg) { - xfree(os->nextArg); - os->nextArg = NULL; - } - if (os->argv) { - xfree(os->argv); - os->argv = NULL; - } - if (os->argb) { - PBM_FREE(os->argb); - os->argb = NULL; - } + os->nextArg = _free(os->nextArg); + os->argv = _free(os->argv); + os->argb = PBM_FREE(os->argb); } -void poptResetContext(poptContext con) { +void poptResetContext(poptContext con) +{ int i; + if (con == NULL) return; while (con->os > con->optionStack) { cleanOSE(con->os--); } - if (con->os->argb) { - PBM_FREE(con->os->argb); - con->os->argb = NULL; - } + con->os->argb = PBM_FREE(con->os->argb); con->os->currAlias = NULL; con->os->nextCharArg = NULL; con->os->nextArg = NULL; @@ -116,36 +221,44 @@ void poptResetContext(poptContext con) { con->restLeftover = 0; con->doExec = NULL; - for (i = 0; i < con->finalArgvCount; i++) { - if (con->finalArgv[i]) { - xfree(con->finalArgv[i]); - con->finalArgv[i] = NULL; - } - } + if (con->finalArgv != NULL) + for (i = 0; i < con->finalArgvCount; i++) + /*@-unqualifiedtrans@*/ /* FIX: typedef double indirection. */ + con->finalArgv[i] = _free(con->finalArgv[i]); + /*@=unqualifiedtrans@*/ con->finalArgvCount = 0; - - if (con->arg_strip) { - PBM_FREE(con->arg_strip); - con->arg_strip = NULL; - } + con->arg_strip = PBM_FREE(con->arg_strip); + /*@-nullstate@*/ /* FIX: con->finalArgv != NULL */ + return; + /*@=nullstate@*/ } -/* Only one of longName, shortName may be set at a time */ -static int handleExec(poptContext con, char * longName, char shortName) { +/* Only one of longName, shortName should be set, not both. */ +static int handleExec(/*@special@*/ poptContext con, + /*@null@*/ const char * longName, char shortName) + /*@uses con->execs, con->numExecs, con->flags, con->doExec, + con->finalArgv, con->finalArgvAlloced, con->finalArgvCount @*/ + /*@modifies con @*/ +{ + poptItem item; int i; - i = con->numExecs - 1; - if (longName) { - while (i >= 0 && (!con->execs[i].longName || - strcmp(con->execs[i].longName, longName))) i--; - } else { - while (i >= 0 && - con->execs[i].shortName != shortName) i--; - } + if (con->execs == NULL || con->numExecs <= 0) /* XXX can't happen */ + 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; @@ -163,38 +276,55 @@ static int handleExec(poptContext con, char * longName, char shortName) { } i = con->finalArgvCount++; + if (con->finalArgv != NULL) /* XXX can't happen */ { char *s = malloc((longName ? strlen(longName) : 0) + 3); - if (longName) - sprintf(s, "--%s", longName); - else - sprintf(s, "-%c", shortName); - con->finalArgv[i] = s; + if (s != NULL) { /* XXX can't happen */ + if (longName) + sprintf(s, "--%s", longName); + else + sprintf(s, "-%c", shortName); + con->finalArgv[i] = s; + } else + con->finalArgv[i] = NULL; } + /*@-nullstate@*/ /* FIX: con->finalArgv[] == NULL */ return 1; + /*@=nullstate@*/ } /* Only one of longName, shortName may be set at a time */ -static int handleAlias(poptContext con, const char * longName, char shortName, - /*@keep@*/ const char * nextCharArg) { +static int handleAlias(/*@special@*/ poptContext con, + /*@null@*/ const char * longName, char shortName, + /*@keep@*/ /*@null@*/ const char * nextCharArg) + /*@uses con->aliases, con->numAliases, con->optionStack, con->os, + con->os->currAlias, con->os->currAlias->option.longName @*/ + /*@modifies con @*/ +{ + poptItem item = con->os->currAlias; + int rc; int i; - if (con->os->currAlias && con->os->currAlias->longName && longName && - !strcmp(con->os->currAlias->longName, longName)) - return 0; - if (con->os->currAlias && shortName && - shortName == con->os->currAlias->shortName) + 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) /* XXX can't happen */ return 0; - i = con->numAliases - 1; - if (longName) { - while (i >= 0 && (!con->aliases[i].longName || - strcmp(con->aliases[i].longName, longName))) i--; - } else { - while (i >= 0 && - con->aliases[i].shortName != shortName) i--; + 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) @@ -209,49 +339,65 @@ static int handleAlias(poptContext con, const char * longName, char shortName, con->os->nextArg = NULL; con->os->nextCharArg = NULL; con->os->currAlias = con->aliases + i; - poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv, + rc = poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv, &con->os->argc, &con->os->argv); con->os->argb = NULL; - return 1; + return (rc ? rc : 1); } -static void execCommand(poptContext con) { +static int execCommand(poptContext con) + /*@*/ +{ + poptItem item = con->doExec; const char ** argv; - int pos = 0; - const char * script = con->doExec->script; + int argc = 0; + int rc; - argv = malloc(sizeof(*argv) * - (6 + con->numLeftovers + con->finalArgvCount)); + if (item == NULL) /*XXX can't happen*/ + return POPT_ERROR_NOARG; - if (!con->execAbsolute && strchr(script, '/')) return; + 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; /* XXX can't happen */ - if (!strchr(script, '/') && con->execPath) { - char *s = malloc(strlen(con->execPath) + strlen(script) + 2); - sprintf(s, "%s/%s", con->execPath, script); - argv[pos] = s; + 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[pos] = script; + argv[argc] = findProgramPath(item->argv[0]); } - pos++; + if (argv[argc++] == NULL) return POPT_ERROR_NOARG; - argv[pos] = findProgramPath(con->os->argv[0]); - if (argv[pos]) pos++; - argv[pos++] = ";"; + if (item->argc > 1) { + memcpy(argv + argc, item->argv + 1, sizeof(*argv) * (item->argc - 1)); + argc += (item->argc - 1); + } - memcpy(argv + pos, con->finalArgv, sizeof(*argv) * con->finalArgvCount); - pos += con->finalArgvCount; + if (con->finalArgv != NULL && con->finalArgvCount > 0) { + memcpy(argv + argc, con->finalArgv, + sizeof(*argv) * con->finalArgvCount); + argc += con->finalArgvCount; + } - if (con->numLeftovers) { - argv[pos++] = "--"; - memcpy(argv + pos, con->leftovers, sizeof(*argv) * con->numLeftovers); - pos += con->numLeftovers; + if (con->leftovers != NULL && con->numLeftovers > 0) { +#if 0 + argv[argc++] = "--"; +#endif + memcpy(argv + argc, con->leftovers, sizeof(*argv) * con->numLeftovers); + argc += con->numLeftovers; } - argv[pos++] = NULL; + argv[argc] = NULL; #ifdef __hpux - setresuid(getuid(), getuid(),-1); + rc = setresuid(getuid(), getuid(),-1); + if (rc) return POPT_ERROR_ERRNO; #else /* * XXX " ... on BSD systems setuid() should be preferred over setreuid()" @@ -259,65 +405,103 @@ static void execCommand(poptContext con) { * XXX from Norbert Warmuth */ #if defined(HAVE_SETUID) - setuid(getuid()); + rc = setuid(getuid()); + if (rc) return POPT_ERROR_ERRNO; #elif defined (HAVE_SETREUID) - setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */ + rc = setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */ + if (rc) return POPT_ERROR_ERRNO; #else ; /* Can't drop privileges */ #endif #endif - execvp(argv[0], (char *const *)argv); + if (argv[0] == NULL) + return POPT_ERROR_NOARG; +#ifdef MYDEBUG + { const char ** avp; + fprintf(stderr, "==> execvp(%s) argv[%d]:", argv[0], argc); + for (avp = argv; *avp; avp++) + fprintf(stderr, " '%s'", *avp); + fprintf(stderr, "\n"); + } +#endif + + rc = execvp(argv[0], (char *const *)argv); + return POPT_ERROR_ERRNO; } -/*@observer@*/ static const struct poptOption * -findOption(const struct poptOption * table, const char * longName, - char shortName, - /*@out@*/ poptCallbackType * callback, /*@out@*/ const void ** callbackData, - int singleDash) +/*@observer@*/ /*@null@*/ static const struct poptOption * +findOption(const struct poptOption * opt, /*@null@*/ const char * longName, + char shortName, + /*@null@*/ /*@out@*/ poptCallbackType * callback, + /*@null@*/ /*@out@*/ const void ** callbackData, + int singleDash) + /*@modifies *callback, *callbackData */ { - const struct poptOption * opt = table; - const struct poptOption * opt2; const struct poptOption * cb = NULL; /* This happens when a single - is given */ - if (singleDash && !shortName && !*longName) + if (singleDash && !shortName && (longName && *longName == '\0')) shortName = '-'; - while (opt->longName || opt->shortName || opt->arg) { + for (; opt->longName || opt->shortName || opt->arg; opt++) { + if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { + const struct poptOption * opt2; + + /* Recurse on included sub-tables. */ + if (opt->arg == NULL) continue; /* XXX program error */ opt2 = findOption(opt->arg, longName, shortName, callback, callbackData, singleDash); - if (opt2) { - if (*callback && !*callbackData) - *callbackData = opt->descrip; - return opt2; - } + if (opt2 == NULL) continue; + /* Sub-table data will be inheirited if no data yet. */ + if (!(callback && *callback)) return opt2; + if (!(callbackData && *callbackData == NULL)) return opt2; + /*@-observertrans -dependenttrans @*/ + *callbackData = opt->descrip; + /*@=observertrans =dependenttrans @*/ + 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)) { + /*@-nullpass@*/ /* LCL: opt->longName != NULL */ + !strcmp(longName, opt->longName)) + /*@=nullpass@*/ + { break; } else if (shortName && shortName == opt->shortName) { break; } - opt++; } - if (!opt->longName && !opt->shortName) return NULL; - *callbackData = NULL; - *callback = NULL; + if (!opt->longName && !opt->shortName) + return NULL; + /*@-modobserver -mods @*/ + if (callback) *callback = NULL; + if (callbackData) *callbackData = NULL; if (cb) { - *callback = (poptCallbackType)cb->arg; - if (!(cb->argInfo & POPT_CBFLAG_INC_DATA)) - *callbackData = cb->descrip; + if (callback) + /*@-castfcnptr@*/ + *callback = (poptCallbackType)cb->arg; + /*@=castfcnptr@*/ + if (!(cb->argInfo & POPT_CBFLAG_INC_DATA)) { + if (callbackData) + /*@-observertrans@*/ /* FIX: typedef double indirection. */ + *callbackData = cb->descrip; + /*@=observertrans@*/ + } } + /*@=modobserver =mods @*/ return opt; } -static const char *findNextArg(poptContext con, unsigned argx, int delete) +static const char * findNextArg(/*@special@*/ poptContext con, + unsigned argx, int delete_arg) + /*@uses con->optionStack, con->os, + con->os->next, con->os->argb, con->os->argc, con->os->argv @*/ + /*@modifies con @*/ { struct optionStackEntry * os = con->os; const char * arg; @@ -327,43 +511,58 @@ static const char *findNextArg(poptContext con, unsigned argx, int delete) 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; + /*@-sizeoftype@*/ + if (os->argb && PBM_ISSET(i, os->argb)) + /*@innercontinue@*/ continue; + if (*os->argv[i] == '-') + /*@innercontinue@*/ continue; + if (--argx > 0) + /*@innercontinue@*/ continue; arg = os->argv[i]; - if (delete) { + if (delete_arg) { if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc); + if (os->argb != NULL) /* XXX can't happen */ PBM_SET(i, os->argb); } - break; + /*@innerbreak@*/ break; + /*@=sizeoftype@*/ } if (os > con->optionStack) os--; } while (arg == NULL); return arg; } -static /*@only@*/ const char * expandNextArg(poptContext con, const char * s) +static /*@only@*/ /*@null@*/ const char * +expandNextArg(/*@special@*/ poptContext con, const char * s) + /*@uses con->optionStack, con->os, + con->os->next, con->os->argb, con->os->argc, con->os->argv @*/ + /*@modifies con @*/ { - const char *a; + 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; /* XXX can't happen */ while ((c = *s++) != '\0') { switch (c) { #if 0 /* XXX can't do this */ case '\\': /* escape */ c = *s++; - break; + /*@switchbreak@*/ break; #endif case '!': if (!(s[0] == '#' && s[1] == ':' && s[2] == '+')) - break; - if ((a = findNextArg(con, 1, 1)) == NULL) - break; + /*@switchbreak@*/ break; + /* XXX Make sure that findNextArg deletes only next arg. */ + if (a == NULL) { + if ((a = findNextArg(con, 1, 1)) == NULL) + /*@switchbreak@*/ break; + } s += 3; alen = strlen(a); @@ -373,23 +572,87 @@ static /*@only@*/ const char * expandNextArg(poptContext con, const char * s) te = t + strlen(t); strncpy(te, a, alen); te += alen; continue; - /*@notreached@*/ break; + /*@notreached@*/ /*@switchbreak@*/ break; default: - break; + /*@switchbreak@*/ break; } *te++ = c; } *te = '\0'; - t = realloc(t, strlen(t)+1); /* XXX memory leak, hard to plug */ + t = realloc(t, strlen(t) + 1); /* XXX memory leak, hard to plug */ return t; } -static void poptStripArg(poptContext con, int which) +static void poptStripArg(/*@special@*/ poptContext con, int which) + /*@uses con->arg_strip, con->optionStack @*/ + /*@defines con->arg_strip @*/ + /*@modifies con @*/ { - if(con->arg_strip == NULL) { + /*@-sizeoftype@*/ + if (con->arg_strip == NULL) con->arg_strip = PBM_ALLOC(con->optionStack[0].argc); - } + if (con->arg_strip != NULL) /* XXX can't happen */ PBM_SET(which, con->arg_strip); + /*@=sizeoftype@*/ + /*@-compdef@*/ /* LCL: con->arg_strip udefined? */ + return; + /*@=compdef@*/ +} + +static int poptSaveLong(const struct poptOption * opt, long aLong) + /*@modifies opt->arg @*/ +{ + if (opt->arg == NULL) + return POPT_ERROR_NULLARG; + + if (opt->argInfo & POPT_ARGFLAG_NOT) + aLong = ~aLong; + switch (opt->argInfo & POPT_ARGFLAG_LOGICALOPS) { + case 0: + *((long *) opt->arg) = aLong; + break; + case POPT_ARGFLAG_OR: + *((long *) opt->arg) |= aLong; + break; + case POPT_ARGFLAG_AND: + *((long *) opt->arg) &= aLong; + break; + case POPT_ARGFLAG_XOR: + *((long *) opt->arg) ^= aLong; + break; + default: + return POPT_ERROR_BADOPERATION; + /*@notreached@*/ break; + } + return 0; +} + +static int poptSaveInt(const struct poptOption * opt, long aLong) + /*@modifies opt->arg @*/ +{ + if (opt->arg == NULL) + return POPT_ERROR_NULLARG; + + if (opt->argInfo & POPT_ARGFLAG_NOT) + aLong = ~aLong; + switch (opt->argInfo & POPT_ARGFLAG_LOGICALOPS) { + case 0: + *((int *) opt->arg) = aLong; + break; + case POPT_ARGFLAG_OR: + *((int *) opt->arg) |= aLong; + break; + case POPT_ARGFLAG_AND: + *((int *) opt->arg) &= aLong; + break; + case POPT_ARGFLAG_XOR: + *((int *) opt->arg) ^= aLong; + break; + default: + return POPT_ERROR_BADOPERATION; + /*@notreached@*/ break; + } + return 0; } /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */ @@ -398,28 +661,25 @@ int poptGetNextOpt(poptContext con) const struct poptOption * opt = NULL; int done = 0; - /* looks a bit tricky to get rid of alloca properly in this fn */ -#if HAVE_ALLOCA_H -#define ALLOCA(x) alloca(x) -#else -#define ALLOCA(x) malloc(x) -#endif - - + if (con == NULL) + return -1; while (!done) { const char * origOptString = NULL; poptCallbackType 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) { - invokeCallbacks(con, con->options, 1); - if (con->doExec) execCommand(con); + /*@-internalglobs@*/ + invokeCallbacksPOST(con, con->options); + /*@=internalglobs@*/ + if (con->doExec) return execCommand(con); return -1; } @@ -428,26 +688,36 @@ int poptGetNextOpt(poptContext con) char * localOptString, * optString; int thisopt; + /*@-sizeoftype@*/ if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) { con->os->next++; continue; } - thisopt=con->os->next; + /*@=sizeoftype@*/ + thisopt = con->os->next; + if (con->os->argv != NULL) /* XXX can't happen */ origOptString = con->os->argv[con->os->next++]; + if (origOptString == NULL) /* XXX can't happen */ + return POPT_ERROR_BADOPT; + if (con->restLeftover || *origOptString != '-') { - con->leftovers[con->numLeftovers++] = origOptString; if (con->flags & POPT_CONTEXT_POSIXMEHARDER) con->restLeftover = 1; + if (con->flags & POPT_CONTEXT_ARG_OPTS) { + con->os->nextArg = xstrdup(origOptString); + return 0; + } + if (con->leftovers != NULL) /* XXX can't happen */ + con->leftovers[con->numLeftovers++] = origOptString; continue; } /* Make a copy we can hack at */ localOptString = optString = - strcpy(ALLOCA(strlen(origOptString) + 1), - origOptString); + strcpy(alloca(strlen(origOptString) + 1), origOptString); - if (!optString[0]) + if (optString[0] == '\0') return POPT_ERROR_BADOPT; if (optString[1] == '-' && !optString[2]) { @@ -466,12 +736,13 @@ int poptGetNextOpt(poptContext con) /* XXX aliases with arg substitution need "--alias=arg" */ if (handleAlias(con, optString, '\0', NULL)) continue; + if (handleExec(con, optString, '\0')) continue; /* Check for "--long=arg" option. */ for (oe = optString; *oe && *oe != '='; oe++) - ; + {}; if (*oe == '=') { *oe++ = '\0'; /* XXX longArg is mapped back to persistent storage. */ @@ -487,110 +758,175 @@ int poptGetNextOpt(poptContext con) if (!opt) { con->os->nextCharArg = origOptString + 1; } else { - if(con->os == con->optionStack && - opt->argInfo & POPT_ARGFLAG_STRIP) { + if (con->os == con->optionStack && + opt->argInfo & POPT_ARGFLAG_STRIP) + { canstrip = 1; poptStripArg(con, thisopt); } + shorty = 0; } } /* Process next short option */ + /*@-branchstate@*/ /* FIX: W2DO? */ if (con->os->nextCharArg) { origOptString = con->os->nextCharArg; con->os->nextCharArg = NULL; - if (handleAlias(con, NULL, *origOptString, - origOptString + 1)) { + if (handleAlias(con, NULL, *origOptString, origOptString + 1)) + continue; + + if (handleExec(con, NULL, *origOptString)) { + /* Restore rest of short options for further processing */ origOptString++; + if (*origOptString != '\0') + con->os->nextCharArg = origOptString; continue; } - if (handleExec(con, NULL, *origOptString)) - continue; opt = findOption(con->options, NULL, *origOptString, &cb, &cbData, 0); if (!opt) return POPT_ERROR_BADOPT; + shorty = 1; origOptString++; - if (*origOptString) + if (*origOptString != '\0') con->os->nextCharArg = origOptString; } + /*@=branchstate@*/ + if (opt == NULL) return POPT_ERROR_BADOPT; /* XXX can't happen */ if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) { - *((int *)opt->arg) = 1; + if (poptSaveInt(opt, 1L)) + return POPT_ERROR_BADOPERATION; } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) { - if (opt->arg) - *((int *) opt->arg) = opt->val; - } else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) { - if (con->os->nextArg) { - xfree(con->os->nextArg); - con->os->nextArg = NULL; + if (opt->arg) { + if (poptSaveInt(opt, (long)opt->val)) + return POPT_ERROR_BADOPERATION; } + } else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) { + con->os->nextArg = _free(con->os->nextArg); + /*@-usedef@*/ /* FIX: W2DO? */ if (longArg) { - con->os->nextArg = expandNextArg(con, longArg); + /*@=usedef@*/ + longArg = expandNextArg(con, longArg); + con->os->nextArg = longArg; } else if (con->os->nextCharArg) { - con->os->nextArg = expandNextArg(con, 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) - return POPT_ERROR_NOARG; - - /* make sure this isn't part of a short arg or the - result of an alias expansion */ - if(con->os == con->optionStack && - opt->argInfo & POPT_ARGFLAG_STRIP && - canstrip) { - poptStripArg(con, con->os->next); - } + if (con->os->next == con->os->argc) { + if (!(opt->argInfo & POPT_ARGFLAG_OPTIONAL)) + /*@-compdef@*/ /* FIX: con->os->argv not defined */ + return POPT_ERROR_NOARG; + /*@=compdef@*/ + con->os->nextArg = NULL; + } else { + + /* + * Make sure this isn't part of a short arg or the + * result of an alias expansion. + */ + if (con->os == con->optionStack && + (opt->argInfo & POPT_ARGFLAG_STRIP) && + canstrip) { + poptStripArg(con, con->os->next); + } - con->os->nextArg = expandNextArg(con, con->os->argv[con->os->next++]); + if (con->os->argv != NULL) { /* XXX can't happen */ + /* XXX watchout: subtle side-effects live here. */ + longArg = con->os->argv[con->os->next++]; + longArg = expandNextArg(con, longArg); + con->os->nextArg = longArg; + } + } } + longArg = NULL; if (opt->arg) { - long aLong; - char *end; - switch (opt->argInfo & POPT_ARG_MASK) { - case POPT_ARG_STRING: + case POPT_ARG_STRING: /* XXX memory leak, hard to plug */ - *((const char **) opt->arg) = xstrdup(con->os->nextArg); - break; - - case POPT_ARG_INT: - case POPT_ARG_LONG: - aLong = strtol(con->os->nextArg, &end, 0); - if (!(end && *end == '\0')) - return POPT_ERROR_BADNUMBER; + *((const char **) opt->arg) = (con->os->nextArg) + ? xstrdup(con->os->nextArg) : NULL; + /*@switchbreak@*/ 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 (aLong == LONG_MIN || aLong == LONG_MAX) - return POPT_ERROR_OVERFLOW; if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) { - *((long *) opt->arg) = aLong; + if (aLong == LONG_MIN || aLong == LONG_MAX) + return POPT_ERROR_OVERFLOW; + if (poptSaveLong(opt, aLong)) + return POPT_ERROR_BADOPERATION; } else { if (aLong > INT_MAX || aLong < INT_MIN) return POPT_ERROR_OVERFLOW; - *((int *) opt->arg) = aLong; + if (poptSaveInt(opt, aLong)) + return POPT_ERROR_BADOPERATION; + } + } /*@switchbreak@*/ break; + + case POPT_ARG_FLOAT: + case POPT_ARG_DOUBLE: + { double aDouble = 0.0; + char *end; + + if (con->os->nextArg) { + /*@-mods@*/ + int saveerrno = errno; + errno = 0; + aDouble = strtod(con->os->nextArg, &end); + if (errno == ERANGE) + return POPT_ERROR_OVERFLOW; + errno = saveerrno; + /*@=mods@*/ + if (*end != '\0') + return POPT_ERROR_BADNUMBER; } - break; - default: - fprintf(stdout, POPT_("option type (%d) not implemented in popt\n"), - opt->argInfo & POPT_ARG_MASK); + if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_DOUBLE) { + *((double *) opt->arg) = aDouble; + } else { +#define _ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a)) + if ((_ABS(aDouble) - FLT_MAX) > DBL_EPSILON) + return POPT_ERROR_OVERFLOW; + if ((FLT_MIN - _ABS(aDouble)) > DBL_EPSILON) + return POPT_ERROR_OVERFLOW; + *((float *) opt->arg) = aDouble; + } + } /*@switchbreak@*/ break; + default: + fprintf(stdout, + POPT_("option type (%d) not implemented in popt\n"), + (opt->argInfo & POPT_ARG_MASK)); exit(EXIT_FAILURE); + /*@notreached@*/ /*@switchbreak@*/ break; } } } - if (cb) - cb(con, POPT_CALLBACK_REASON_OPTION, opt, con->os->nextArg, cbData); - else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)) + if (cb) { + /*@-internalglobs@*/ + invokeCallbacksOPTION(con, con->options, opt, cbData, shorty); + /*@=internalglobs@*/ + } else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)) done = 1; if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) { @@ -599,131 +935,217 @@ int poptGetNextOpt(poptContext con) sizeof(*con->finalArgv) * con->finalArgvAlloced); } - { char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + 3); - if (opt->longName) - sprintf(s, "--%s", opt->longName); - else - sprintf(s, "-%c", opt->shortName); - con->finalArgv[con->finalArgvCount++] = s; + if (con->finalArgv != NULL) + { char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + 3); + if (s != NULL) { /* XXX can't happen */ + 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 - && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL) { - con->finalArgv[con->finalArgvCount++] = xstrdup(con->os->nextArg); + if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) + /*@-ifempty@*/ ; /*@=ifempty@*/ + else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) + /*@-ifempty@*/ ; /*@=ifempty@*/ + else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) { + if (con->finalArgv != NULL && con->os->nextArg) + con->finalArgv[con->finalArgvCount++] = + /*@-nullpass@*/ /* LCL: con->os->nextArg != NULL */ + xstrdup(con->os->nextArg); + /*@=nullpass@*/ } } - return opt->val; + return (opt ? opt->val : -1); /* XXX can't happen */ } -const char * poptGetOptArg(poptContext con) { - const char * ret = con->os->nextArg; - con->os->nextArg = NULL; +const char * poptGetOptArg(poptContext con) +{ + const char * ret = NULL; + /*@-branchstate@*/ + if (con) { + ret = con->os->nextArg; + con->os->nextArg = NULL; + } + /*@=branchstate@*/ return ret; } -const char * poptGetArg(poptContext con) { - if (con->numLeftovers == con->nextLeftover) return NULL; - return con->leftovers[con->nextLeftover++]; +const char * poptGetArg(poptContext con) +{ + const char * ret = NULL; + if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers) + ret = con->leftovers[con->nextLeftover++]; + return ret; } -const char * poptPeekArg(poptContext con) { - if (con->numLeftovers == con->nextLeftover) return NULL; - return con->leftovers[con->nextLeftover]; +const char * poptPeekArg(poptContext con) +{ + const char * ret = NULL; + if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers) + ret = con->leftovers[con->nextLeftover]; + return ret; } -const char ** poptGetArgs(poptContext con) { - if (con->numLeftovers == con->nextLeftover) return NULL; +const char ** poptGetArgs(poptContext con) +{ + if (con == NULL || + con->leftovers == NULL || con->numLeftovers == con->nextLeftover) + return NULL; /* some apps like [like RPM ;-) ] need this NULL terminated */ con->leftovers[con->numLeftovers] = NULL; + /*@-nullret -nullstate @*/ /* FIX: typedef double indirection. */ return (con->leftovers + con->nextLeftover); + /*@=nullret =nullstate @*/ } -void poptFreeContext(poptContext con) { +poptContext poptFreeContext(poptContext con) +{ + poptItem item; int i; + if (con == NULL) return con; poptResetContext(con); - if (con->os->argb) free(con->os->argb); + con->os->argb = _free(con->os->argb); + if (con->aliases != NULL) for (i = 0; i < con->numAliases; i++) { - if (con->aliases[i].longName) xfree(con->aliases[i].longName); - free(con->aliases[i].argv); + item = con->aliases + i; + /*@-modobserver -observertrans -dependenttrans@*/ + item->option.longName = _free(item->option.longName); + item->option.descrip = _free(item->option.descrip); + item->option.argDescrip = _free(item->option.argDescrip); + /*@=modobserver =observertrans =dependenttrans@*/ + item->argv = _free(item->argv); } + con->aliases = _free(con->aliases); + if (con->execs != NULL) for (i = 0; i < con->numExecs; i++) { - if (con->execs[i].longName) xfree(con->execs[i].longName); - xfree(con->execs[i].script); + item = con->execs + i; + /*@-modobserver -observertrans -dependenttrans@*/ + item->option.longName = _free(item->option.longName); + item->option.descrip = _free(item->option.descrip); + item->option.argDescrip = _free(item->option.argDescrip); + /*@=modobserver =observertrans =dependenttrans@*/ + item->argv = _free(item->argv); } - if (con->execs) xfree(con->execs); - - free(con->leftovers); - free(con->finalArgv); - if (con->appName) xfree(con->appName); - if (con->aliases) free(con->aliases); - if (con->otherHelp) xfree(con->otherHelp); - if (con->execPath) xfree(con->execPath); - if (con->arg_strip) PBM_FREE(con->arg_strip); + 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); - free(con); + con = _free(con); + return con; } -int poptAddAlias(poptContext con, struct poptAlias newAlias, +int poptAddAlias(poptContext con, struct poptAlias alias, /*@unused@*/ int flags) { - int aliasNum = con->numAliases++; - struct poptAlias * alias; + poptItem 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 poptAddItem(con, item, 0); +} - /* SunOS won't realloc(NULL, ...) */ - if (!con->aliases) - con->aliases = malloc(sizeof(newAlias) * con->numAliases); - else - con->aliases = realloc(con->aliases, - sizeof(newAlias) * con->numAliases); - alias = con->aliases + aliasNum; +/*@-mustmod@*/ /* LCL: con not modified? */ +int poptAddItem(poptContext con, poptItem newItem, int flags) +{ + poptItem * 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; + /*@notreached@*/ break; + } + + *items = realloc((*items), ((*nitems) + 1) * sizeof(**items)); + if ((*items) == NULL) + return 1; + + item = (*items) + (*nitems); - alias->longName = (newAlias.longName) - ? strcpy(malloc(strlen(newAlias.longName) + 1), newAlias.longName) - : NULL; - alias->shortName = newAlias.shortName; - alias->argc = newAlias.argc; - alias->argv = newAlias.argv; + item->option.longName = + (newItem->option.longName ? xstrdup(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 ? xstrdup(newItem->option.descrip) : NULL); + item->option.argDescrip = + (newItem->option.argDescrip ? xstrdup(newItem->option.argDescrip) : NULL); + item->argc = newItem->argc; + item->argv = newItem->argv; + + (*nitems)++; return 0; } +/*@=mustmod@*/ -const char * poptBadOption(poptContext con, int flags) { - struct optionStackEntry * os; +const char * poptBadOption(poptContext con, int flags) +{ + struct optionStackEntry * os = NULL; - if (flags & POPT_BADOPTION_NOALIAS) - os = con->optionStack; - else - os = con->os; + if (con != NULL) + os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os; - return os->argv[os->next - 1]; + /*@-nullderef@*/ /* LCL: os->argv != NULL */ + return (os && os->argv ? os->argv[os->next - 1] : NULL); + /*@=nullderef@*/ } -#define POPT_ERROR_NOARG -10 -#define POPT_ERROR_BADOPT -11 -#define POPT_ERROR_OPTSTOODEEP -13 -#define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */ -#define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */ - -const char *const poptStrerror(const int error) { +const char *const poptStrerror(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 paramter quoting"); + 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: @@ -731,52 +1153,54 @@ const char *const poptStrerror(const int error) { } } -int poptStuffArgs(poptContext con, const char ** argv) { +int poptStuffArgs(poptContext 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; - poptDupArgv(argc, argv, &con->os->argc, &con->os->argv); + rc = poptDupArgv(argc, argv, &con->os->argc, &con->os->argv); con->os->argb = NULL; con->os->stuffed = 1; - return 0; + return rc; } -const char * poptGetInvocationName(poptContext con) { - return con->os->argv[0]; +const char * poptGetInvocationName(poptContext con) +{ + return (con->os->argv ? con->os->argv[0] : ""); } -int poptStrippedArgv(poptContext con, int argc, char **argv) +int poptStrippedArgv(poptContext con, int argc, char ** argv) { - int i,j=1, numargs=argc; + int numargs = argc; + int j = 1; + int i; - for(i=1; iarg_strip)) { + /*@-sizeoftype@*/ + if (con->arg_strip) + for (i = 1; i < argc; i++) { + if (PBM_ISSET(i, con->arg_strip)) numargs--; - } } - for(i=1; iarg_strip)) { + for (i = 1; i < argc; i++) { + if (con->arg_strip && PBM_ISSET(i, con->arg_strip)) continue; - } else { - if(j /* for FILE * */ #define POPT_OPTION_DEPTH 10 -#define POPT_ARG_NONE 0 -#define POPT_ARG_STRING 1 -#define POPT_ARG_INT 2 -#define POPT_ARG_LONG 3 -#define POPT_ARG_INCLUDE_TABLE 4 /* arg points to table */ -#define POPT_ARG_CALLBACK 5 /* table-wide callback... must be +/** \ingroup popt + * \name Arg type identifiers + */ +/*@{*/ +#define POPT_ARG_NONE 0 /*!< no arg */ +#define POPT_ARG_STRING 1 /*!< arg will be saved as string */ +#define POPT_ARG_INT 2 /*!< arg will be converted to int */ +#define POPT_ARG_LONG 3 /*!< arg will be converted to long */ +#define POPT_ARG_INCLUDE_TABLE 4 /*!< arg points to table */ +#define POPT_ARG_CALLBACK 5 /*!< table-wide callback... must be set first in table; arg points to callback, descrip points to callback data to pass */ -#define POPT_ARG_INTL_DOMAIN 6 /* set the translation domain +#define POPT_ARG_INTL_DOMAIN 6 /*!< set the translation domain for this table and any included tables; arg points to the domain string */ -#define POPT_ARG_VAL 7 /* arg should take value val */ +#define POPT_ARG_VAL 7 /*!< arg should take value val */ +#define POPT_ARG_FLOAT 8 /*!< arg will be converted to float */ +#define POPT_ARG_DOUBLE 9 /*!< arg will be converted to double */ + #define POPT_ARG_MASK 0x0000FFFF -#define POPT_ARGFLAG_ONEDASH 0x80000000 /* allow -longoption */ -#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000 /* don't show in help/usage */ -#define POPT_ARGFLAG_STRIP 0x20000000 /* strip this arg from argv (only applies to long args) */ -#define POPT_CBFLAG_PRE 0x80000000 /* call the callback before parse */ -#define POPT_CBFLAG_POST 0x40000000 /* call the callback after parse */ -#define POPT_CBFLAG_INC_DATA 0x20000000 /* use data from the include line, +/*@}*/ + +/** \ingroup popt + * \name Arg modifiers + */ +/*@{*/ +#define POPT_ARGFLAG_ONEDASH 0x80000000 /*!< allow -longoption */ +#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000 /*!< don't show in help/usage */ +#define POPT_ARGFLAG_STRIP 0x20000000 /*!< strip this arg from argv(only applies to long args) */ +#define POPT_ARGFLAG_OPTIONAL 0x10000000 /*!< arg may be missing */ + +#define POPT_ARGFLAG_OR 0x08000000 /*!< arg will be or'ed */ +#define POPT_ARGFLAG_NOR 0x09000000 /*!< arg will be nor'ed */ +#define POPT_ARGFLAG_AND 0x04000000 /*!< arg will be and'ed */ +#define POPT_ARGFLAG_NAND 0x05000000 /*!< arg will be nand'ed */ +#define POPT_ARGFLAG_XOR 0x02000000 /*!< arg will be xor'ed */ +#define POPT_ARGFLAG_NOT 0x01000000 /*!< arg will be negated */ +#define POPT_ARGFLAG_LOGICALOPS \ + (POPT_ARGFLAG_OR|POPT_ARGFLAG_AND|POPT_ARGFLAG_XOR) + +#define POPT_BIT_SET (POPT_ARG_VAL|POPT_ARGFLAG_OR) + /*!< set arg bit(s) */ +#define POPT_BIT_CLR (POPT_ARG_VAL|POPT_ARGFLAG_NAND) + /*!< clear arg bit(s) */ + +#define POPT_ARGFLAG_SHOW_DEFAULT 0x00800000 /*!< show default value in --help */ + +/*@}*/ + +/** \ingroup popt + * \name Callback modifiers + */ +/*@{*/ +#define POPT_CBFLAG_PRE 0x80000000 /*!< call the callback before parse */ +#define POPT_CBFLAG_POST 0x40000000 /*!< call the callback after parse */ +#define POPT_CBFLAG_INC_DATA 0x20000000 /*!< use data from the include line, not the subtable */ +#define POPT_CBFLAG_SKIPOPTION 0x10000000 /*!< don't callback with option */ +#define POPT_CBFLAG_CONTINUE 0x08000000 /*!< continue callbacks with option */ +/*@}*/ -#define POPT_ERROR_NOARG -10 -#define POPT_ERROR_BADOPT -11 -#define POPT_ERROR_OPTSTOODEEP -13 -#define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */ -#define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */ -#define POPT_ERROR_BADNUMBER -17 -#define POPT_ERROR_OVERFLOW -18 +/** \ingroup popt + * \name Error return values + */ +/*@{*/ +#define POPT_ERROR_NOARG -10 /*!< missing argument */ +#define POPT_ERROR_BADOPT -11 /*!< unknown option */ +#define POPT_ERROR_OPTSTOODEEP -13 /*!< aliases nested too deeply */ +#define POPT_ERROR_BADQUOTE -15 /*!< error in paramter quoting */ +#define POPT_ERROR_ERRNO -16 /*!< errno set, use strerror(errno) */ +#define POPT_ERROR_BADNUMBER -17 /*!< invalid numeric value */ +#define POPT_ERROR_OVERFLOW -18 /*!< number too large or too small */ +#define POPT_ERROR_BADOPERATION -19 /*!< mutually exclusive logical operations requested */ +#define POPT_ERROR_NULLARG -20 /*!< opt->arg should not be NULL */ +#define POPT_ERROR_MALLOC -21 /*!< memory allocation failed */ +/*@}*/ -/* poptBadOption() flags */ -#define POPT_BADOPTION_NOALIAS (1 << 0) /* don't go into an alias */ +/** \ingroup popt + * \name poptBadOption() flags + */ +/*@{*/ +#define POPT_BADOPTION_NOALIAS (1 << 0) /*!< don't go into an alias */ +/*@}*/ -/* poptGetContext() flags */ -#define POPT_CONTEXT_NO_EXEC (1 << 0) /* ignore exec expansions */ -#define POPT_CONTEXT_KEEP_FIRST (1 << 1) /* pay attention to argv[0] */ -#define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /* options can't follow args */ +/** \ingroup popt + * \name poptGetContext() flags + */ +/*@{*/ +#define POPT_CONTEXT_NO_EXEC (1 << 0) /*!< ignore exec expansions */ +#define POPT_CONTEXT_KEEP_FIRST (1 << 1) /*!< pay attention to argv[0] */ +#define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /*!< options can't follow args */ +#define POPT_CONTEXT_ARG_OPTS (1 << 4) /*!< return args as options with value 0 */ +/*@}*/ +/** \ingroup popt + */ struct poptOption { - /*@observer@*/ /*@null@*/ const char * longName; /* may be NULL */ - char shortName; /* may be '\0' */ +/*@observer@*/ /*@null@*/ const char * longName; /*!< may be NULL */ + char shortName; /*!< may be '\0' */ int argInfo; - /*@shared@*/ /*@null@*/ void * arg; /* depends on argInfo */ - int val; /* 0 means don't return, just update flag */ - /*@shared@*/ /*@null@*/ const char * descrip; /* description for autohelp -- may be NULL */ - /*@shared@*/ /*@null@*/ const char * argDescrip; /* argument description for autohelp */ +/*@shared@*/ /*@null@*/ void * arg; /*!< depends on argInfo */ + int val; /*!< 0 means don't return, just update flag */ +/*@observer@*/ /*@null@*/ const char * descrip; /*!< description for autohelp -- may be NULL */ +/*@observer@*/ /*@null@*/ const char * argDescrip; /*!< argument description for autohelp */ }; +/** \ingroup popt + * A popt alias argument for poptAddAlias(). + */ struct poptAlias { - /*@owned@*/ /*@null@*/ const char * longName; /* may be NULL */ - char shortName; /* may be '\0' */ +/*@owned@*/ /*@null@*/ const char * longName; /*!< may be NULL */ + char shortName; /*!< may be '\0' */ int argc; - /*@owned@*/ const char ** argv; /* must be free()able */ +/*@owned@*/ const char ** argv; /*!< must be free()able */ }; +/** \ingroup popt + * A popt alias or exec argument for poptAddItem(). + */ +typedef struct poptItem_s { + struct poptOption option; /*!< alias/exec name(s) and description. */ + int argc; /*!< (alias) no. of args. */ +/*@owned@*/ const char ** argv; /*!< (alias) args, must be free()able. */ +} * poptItem; + +/** \ingroup popt + * \name Auto-generated help/usage + */ +/*@{*/ + +/** + * Empty table marker to enable displaying popt alias/exec options. + */ +/*@observer@*/ /*@checked@*/ +extern struct poptOption poptAliasOptions[]; +#define POPT_AUTOALIAS { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptAliasOptions, \ + 0, "Options implemented via popt alias/exec:", NULL }, + +/** + * Auto help table options. + */ +/*@observer@*/ /*@checked@*/ extern struct poptOption poptHelpOptions[]; #define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \ - 0, "Help options", NULL }, + 0, "Help options:", NULL }, -typedef struct poptContext_s * poptContext; +#define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL } +/*@}*/ + +/** \ingroup popt + */ +typedef /*@abstract@*/ struct poptContext_s * poptContext; + +/** \ingroup popt + */ #ifndef __cplusplus +/*@-typeuse@*/ typedef struct poptOption * poptOption; +/*@=typeuse@*/ #endif enum poptCallbackReason { POPT_CALLBACK_REASON_PRE, POPT_CALLBACK_REASON_POST, POPT_CALLBACK_REASON_OPTION }; -typedef void (*poptCallbackType)(poptContext con, - enum poptCallbackReason reason, - const struct poptOption * opt, - const char * arg, const void * data); - -/*@only@*/ poptContext poptGetContext(/*@keep@*/ const char * name, - int argc, /*@keep@*/ const char ** argv, - /*@keep@*/ const struct poptOption * options, int flags); -void poptResetContext(poptContext con); - -/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */ -int poptGetNextOpt(poptContext con); -/* returns NULL if no argument is available */ -/*@observer@*/ /*@null@*/ const char * poptGetOptArg(poptContext con); -/* returns NULL if no more options are available */ -/*@observer@*/ /*@null@*/ const char * poptGetArg(poptContext con); -/*@observer@*/ /*@null@*/ const char * poptPeekArg(poptContext con); -/*@observer@*/ /*@null@*/ const char ** poptGetArgs(poptContext con); -/* returns the option which caused the most recent error */ -/*@observer@*/ const char * poptBadOption(poptContext con, int flags); -void poptFreeContext( /*@only@*/ poptContext con); -int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv); -int poptAddAlias(poptContext con, struct poptAlias alias, int flags); -int poptReadConfigFile(poptContext con, const char * fn); -/* like above, but reads /etc/popt and $HOME/.popt along with environment - vars */ -int poptReadDefaultConfig(poptContext con, int useEnv); -/* argv should be freed -- this allows ', ", and \ quoting, but ' is treated - the same as " and both may include \ quotes */ -int poptDupArgv(int argc, const char **argv, - /*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr); + +#ifdef __cplusplus +extern "C" { +#endif +/*@-type@*/ + +/** \ingroup popt + * Table callback prototype. + * @param con context + * @param reason reason for callback + * @param opt option that triggered callback + * @param arg @todo Document. + * @param data @todo Document. + */ +typedef void (*poptCallbackType) (poptContext con, + enum poptCallbackReason reason, + /*@null@*/ const struct poptOption * opt, + /*@null@*/ const char * arg, + /*@null@*/ const void * data) + /*@*/; + +/** \ingroup popt + * Initialize popt context. + * @param name + * @param argc no. of arguments + * @param argv argument array + * @param options address of popt option table + * @param flags or'd POPT_CONTEXT_* bits + * @return initialized popt context + */ +/*@only@*/ /*@null@*/ poptContext poptGetContext( + /*@dependent@*/ /*@keep@*/ const char * name, + int argc, /*@dependent@*/ /*@keep@*/ const char ** argv, + /*@dependent@*/ /*@keep@*/ const struct poptOption * options, + int flags) + /*@*/; + +/** \ingroup popt + * Reinitialize popt context. + * @param con context + */ +void poptResetContext(/*@null@*/poptContext con) + /*@modifies con @*/; + +/** \ingroup popt + * Return value of next option found. + * @param con context + * @return next option val, -1 on last item, POPT_ERROR_* on error + */ +int poptGetNextOpt(/*@null@*/poptContext con) + /*@globals fileSystem@*/ + /*@modifies con, fileSystem @*/; + +/*@-redecl@*/ +/** \ingroup popt + * Return next option argument (if any). + * @param con context + * @return option argument, NULL if no more options are available + */ +/*@observer@*/ /*@null@*/ const char * poptGetOptArg(/*@null@*/poptContext con) + /*@modifies con @*/; + +/** \ingroup popt + * Return current option's argument. + * @param con context + * @return option argument, NULL if no more options are available + */ +/*@observer@*/ /*@null@*/ const char * poptGetArg(/*@null@*/poptContext con) + /*@modifies con @*/; + +/** \ingroup popt + * Peek at current option's argument. + * @param con context + * @return option argument + */ +/*@observer@*/ /*@null@*/ const char * poptPeekArg(/*@null@*/poptContext con) + /*@*/; + +/** \ingroup popt + * Return remaining arguments. + * @param con context + * @return argument array, terminated with NULL + */ +/*@observer@*/ /*@null@*/ const char ** poptGetArgs(/*@null@*/poptContext con) + /*@modifies con @*/; + +/** \ingroup popt + * Return the option which caused the most recent error. + * @param con context + * @return offending option + */ +/*@observer@*/ const char * poptBadOption(/*@null@*/poptContext con, int flags) + /*@*/; +/*@=redecl@*/ + +/** \ingroup popt + * Destroy context. + * @param con context + * @return NULL always + */ +/*@null@*/ poptContext poptFreeContext( /*@only@*/ /*@null@*/ poptContext con) + /*@modifies con @*/; + +/** \ingroup popt + * Add arguments to context. + * @param con context + * @param argv argument array, NULL terminated + * @return 0 on success, POPT_ERROR_OPTSTOODEEP on failure + */ +int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv) + /*@modifies con @*/; + +/** \ingroup popt + * Add alias to context. + * @todo Pass alias by reference, not value. + * @deprecated Use poptAddItem instead. + * @param con context + * @param alias alias to add + * @param flags (unused) + * @return 0 on success + */ +/*@unused@*/ +int poptAddAlias(poptContext con, struct poptAlias alias, int flags) + /*@modifies con @*/; + +/** \ingroup popt + * Add alias/exec item to context. + * @param con context + * @param item alias/exec item to add + * @param flags 0 for alias, 1 for exec + * @return 0 on success + */ +int poptAddItem(poptContext con, poptItem newItem, int flags) + /*@modifies con @*/; + +/** \ingroup popt + * Read configuration file. + * @param con context + * @param fn file name to read + * @return 0 on success, POPT_ERROR_ERRNO on failure + */ +int poptReadConfigFile(poptContext con, const char * fn) + /*@globals fileSystem@*/ + /*@modifies fileSystem, + con->execs, con->numExecs @*/; + +/** \ingroup popt + * Read default configuration from /etc/popt and $HOME/.popt. + * @param con context + * @param useEnv (unused) + * @return 0 on success, POPT_ERROR_ERRNO on failure + */ +int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) + /*@globals fileSystem@*/ + /*@modifies fileSystem, + con->execs, con->numExecs @*/; + +/** \ingroup popt + * Duplicate an argument array. + * @note: The argument array is malloc'd as a single area, so only argv must + * be free'd. + * + * @param argc no. of arguments + * @param argv argument array + * @retval argcPtr address of returned no. of arguments + * @retval argvPtr address of returned argument array + * @return 0 on success, POPT_ERROR_NOARG on failure + */ +int poptDupArgv(int argc, /*@null@*/ const char **argv, + /*@null@*/ /*@out@*/ int * argcPtr, + /*@null@*/ /*@out@*/ const char *** argvPtr) + /*@modifies *argcPtr, *argvPtr @*/; + +/** \ingroup popt + * Parse a string into an argument array. + * The parse allows ', ", and \ quoting, but ' is treated the same as " and + * both may include \ quotes. + * @note: The argument array is malloc'd as a single area, so only argv must + * be free'd. + * + * @param s string to parse + * @retval argcPtr address of returned no. of arguments + * @retval argvPtr address of returned argument array + */ int poptParseArgvString(const char * s, - /*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr); -/*@observer@*/ const char *const poptStrerror(const int error); -void poptSetExecPath(poptContext con, const char * path, int allowAbsolute); -void poptPrintHelp(poptContext con, FILE * f, int flags); -void poptPrintUsage(poptContext con, FILE * f, int flags); -void poptSetOtherOptionHelp(poptContext con, const char * text); -/*@observer@*/ const char * poptGetInvocationName(poptContext con); -/* shuffles argv pointers to remove stripped args, returns new argc */ -int poptStrippedArgv(poptContext con, int argc, char **argv); + /*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr) + /*@modifies *argcPtr, *argvPtr @*/; + +/** \ingroup popt + * Return formatted error string for popt failure. + * @param error popt error + * @return error string + */ +/*@-redecl@*/ +/*@observer@*/ const char *const poptStrerror(const int error) + /*@*/; +/*@=redecl@*/ + +/** \ingroup popt + * Limit search for executables. + * @param con context + * @param path single path to search for executables + * @param allowAbsolute absolute paths only? + */ +void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) + /*@modifies con @*/; + +/** \ingroup popt + * Print detailed description of options. + * @param con context + * @param fp ouput file handle + * @param flags (unused) + */ +void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/; + +/** \ingroup popt + * Print terse description of options. + * @param con context + * @param fp ouput file handle + * @param flags (unused) + */ +void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/; + +/** \ingroup popt + * Provide text to replace default "[OPTION...]" in help/usage output. + * @param con context + * @param text replacement text + */ +/*@-fcnuse@*/ +void poptSetOtherOptionHelp(poptContext con, const char * text) + /*@modifies con @*/; +/*@=fcnuse@*/ + +/** \ingroup popt + * Return argv[0] from context. + * @param con context + * @return argv[0] + */ +/*@-redecl -fcnuse@*/ +/*@observer@*/ const char * poptGetInvocationName(poptContext con) + /*@*/; +/*@=redecl =fcnuse@*/ + +/** \ingroup popt + * Shuffle argv pointers to remove stripped args, returns new argc. + * @param con context + * @param argc no. of args + * @param argv arg vector + * @return new argc + */ +/*@-fcnuse@*/ +int poptStrippedArgv(poptContext con, int argc, char ** argv) + /*@modifies *argv @*/; +/*@=fcnuse@*/ +/*@=type@*/ #ifdef __cplusplus } #endif diff --git a/popt/poptconfig.c b/popt/poptconfig.c index eb769413..58ccf015 100644 --- a/popt/poptconfig.c +++ b/popt/poptconfig.c @@ -1,101 +1,144 @@ -/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING +/** \ingroup popt + * \file popt/poptconfig.c + */ + +/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from - ftp://ftp.redhat.com/pub/code/popt */ + ftp://ftp.rpm.org/pub/rpm/dist. */ #include "system.h" #include "poptint.h" -static void configLine(poptContext con, char * line) { +/*@-compmempass@*/ /* FIX: item->option.longName kept, not dependent. */ +static void configLine(poptContext con, char * line) + /*@modifies con @*/ +{ + /*@-type@*/ int nameLength = strlen(con->appName); - char * opt; - struct poptAlias alias; - char * entryType; - char * longName = NULL; - char shortName = '\0'; + /*@=type@*/ + const char * entryType; + const char * opt; + poptItem item = alloca(sizeof(*item)); + int i, j; + memset(item, 0, sizeof(*item)); + + /*@-type@*/ if (strncmp(line, con->appName, nameLength)) return; + /*@=type@*/ + line += nameLength; - if (!*line || !isspace(*line)) return; - while (*line && isspace(*line)) line++; - entryType = line; + if (*line == '\0' || !isspace(*line)) return; - while (!*line || !isspace(*line)) line++; + while (*line != '\0' && isspace(*line)) line++; + entryType = line; + while (*line == '\0' || !isspace(*line)) line++; *line++ = '\0'; - while (*line && isspace(*line)) line++; - if (!*line) return; - opt = line; - while (!*line || !isspace(*line)) line++; + while (*line != '\0' && isspace(*line)) line++; + if (*line == '\0') return; + opt = line; + while (*line == '\0' || !isspace(*line)) line++; *line++ = '\0'; - while (*line && isspace(*line)) line++; - if (!*line) return; + while (*line != '\0' && isspace(*line)) line++; + if (*line == '\0') return; + + /*@-temptrans@*/ /* FIX: line alias is saved */ if (opt[0] == '-' && opt[1] == '-') - longName = opt + 2; - else if (opt[0] == '-' && !opt[2]) - shortName = opt[1]; - - if (!strcmp(entryType, "alias")) { - if (poptParseArgvString(line, &alias.argc, &alias.argv)) return; - alias.longName = longName, alias.shortName = shortName; - poptAddAlias(con, alias, 0); - } else if (!strcmp(entryType, "exec")) { - con->execs = realloc(con->execs, - sizeof(*con->execs) * (con->numExecs + 1)); - if (longName) - con->execs[con->numExecs].longName = xstrdup(longName); - else - con->execs[con->numExecs].longName = NULL; - - con->execs[con->numExecs].shortName = shortName; - con->execs[con->numExecs].script = xstrdup(line); - - con->numExecs++; + item->option.longName = opt + 2; + else if (opt[0] == '-' && opt[2] == '\0') + item->option.shortName = opt[1]; + /*@=temptrans@*/ + + if (poptParseArgvString(line, &item->argc, &item->argv)) return; + + /*@-modobserver@*/ + 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; } + /*@=modobserver@*/ + + /*@-nullstate@*/ /* FIX: item->argv[] may be NULL */ + if (!strcmp(entryType, "alias")) + (void) poptAddItem(con, item, 0); + else if (!strcmp(entryType, "exec")) + (void) poptAddItem(con, item, 1); + /*@=nullstate@*/ } +/*@=compmempass@*/ -int poptReadConfigFile(poptContext con, const char * fn) { - char * file=NULL, * chptr, * end; - char * buf=NULL, * dst; +int poptReadConfigFile(poptContext con, const char * fn) +{ + const char * file, * chptr, * end; + char * buf; +/*@dependent@*/ char * dst; int fd, rc; - int fileLength; + off_t fileLength; fd = open(fn, O_RDONLY); - if (fd < 0) { - if (errno == ENOENT) - return 0; - else - return POPT_ERROR_ERRNO; - } + if (fd < 0) + return (errno == ENOENT ? 0 : POPT_ERROR_ERRNO); fileLength = lseek(fd, 0, SEEK_END); - (void) lseek(fd, 0, 0); + if (fileLength == -1 || lseek(fd, 0, 0) == -1) { + rc = errno; + (void) close(fd); + /*@-mods@*/ + errno = rc; + /*@=mods@*/ + return POPT_ERROR_ERRNO; + } - file = malloc(fileLength + 1); - if (read(fd, file, fileLength) != fileLength) { + file = alloca(fileLength + 1); + if (read(fd, (char *)file, fileLength) != fileLength) { rc = errno; - close(fd); + (void) close(fd); + /*@-mods@*/ errno = rc; - if (file) free(file); + /*@=mods@*/ return POPT_ERROR_ERRNO; } - close(fd); + if (close(fd) == -1) + return POPT_ERROR_ERRNO; - dst = buf = malloc(fileLength + 1); + dst = buf = alloca(fileLength + 1); chptr = file; end = (file + fileLength); + /*@-infloops@*/ /* LCL: can't detect chptr++ */ while (chptr < end) { switch (*chptr) { case '\n': *dst = '\0'; dst = buf; while (*dst && isspace(*dst)) dst++; - if (*dst && *dst != '#') { + if (*dst && *dst != '#') configLine(con, dst); - } chptr++; - break; + /*@switchbreak@*/ break; case '\\': *dst++ = *chptr++; if (chptr < end) { @@ -105,15 +148,13 @@ int poptReadConfigFile(poptContext con, const char * fn) { else *dst++ = *chptr++; } - break; + /*@switchbreak@*/ break; default: *dst++ = *chptr++; - break; + /*@switchbreak@*/ break; } } - - free(file); - free(buf); + /*@=infloops@*/ return 0; } @@ -122,21 +163,21 @@ int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) { char * fn, * home; int rc; + /*@-type@*/ if (!con->appName) return 0; + /*@=type@*/ rc = poptReadConfigFile(con, "/etc/popt"); if (rc) return rc; if (getuid() != geteuid()) return 0; if ((home = getenv("HOME"))) { - fn = malloc(strlen(home) + 20); + fn = alloca(strlen(home) + 20); strcpy(fn, home); strcat(fn, "/.popt"); rc = poptReadConfigFile(con, fn); - free(fn); if (rc) return rc; } return 0; } - diff --git a/popt/popthelp.c b/popt/popthelp.c index c36ecead..17adc6f2 100644 --- a/popt/popthelp.c +++ b/popt/popthelp.c @@ -1,48 +1,92 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING +/*@-type@*/ +/** \ingroup popt + * \file popt/popthelp.c + */ + +/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from - ftp://ftp.redhat.com/pub/code/popt */ + ftp://ftp.rpm.org/pub/rpm/dist. */ #include "system.h" #include "poptint.h" +/** + * @param con context + * @param key option(s) + */ static void displayArgs(poptContext con, /*@unused@*/ enum poptCallbackReason foo, struct poptOption * key, - /*@unused@*/ const char * arg, /*@unused@*/ void * data) { - if (key->shortName== '?') + /*@unused@*/ const char * arg, /*@unused@*/ void * data) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ +{ + if (key->shortName == '?') poptPrintHelp(con, stdout, 0); else poptPrintUsage(con, stdout, 0); exit(0); } +#ifdef NOTYET +/*@unchecked@*/ +static int show_option_defaults = 0; +#endif + +/** + * Empty table marker to enable displaying popt alias/exec options. + */ +/*@observer@*/ /*@unchecked@*/ +struct poptOption poptAliasOptions[] = { + POPT_TABLEEND +}; + +/** + * Auto help table options. + */ +/*@-castfcnptr@*/ +/*@observer@*/ /*@unchecked@*/ struct poptOption poptHelpOptions[] = { - { 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 }, - { NULL, '\0', 0, NULL, 0, NULL, NULL } + { 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 }, +#ifdef NOTYET + { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0, + N_("Display option defaults in message"), NULL }, +#endif + POPT_TABLEEND } ; +/*@=castfcnptr@*/ - +/** + * @param table option(s) + */ /*@observer@*/ /*@null@*/ static const char *const -getTableTranslationDomain(const struct poptOption *table) +getTableTranslationDomain(/*@null@*/ const struct poptOption *table) + /*@*/ { - const struct poptOption *opt; - - for(opt = table; - opt->longName || opt->shortName || opt->arg; - opt++) { - if(opt->argInfo == POPT_ARG_INTL_DOMAIN) - return opt->arg; - } + const struct poptOption *opt; - return NULL; + 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; } +/** + * @param opt option(s) + * @param translation_domain translation domain + */ /*@observer@*/ /*@null@*/ static const char *const -getArgDescrip(const struct poptOption * opt, const char *translation_domain) +getArgDescrip(const struct poptOption * opt, + /*@-paramuse@*/ /* FIX: wazzup? */ + /*@null@*/ const char * translation_domain) + /*@=paramuse@*/ + /*@*/ { if (!(opt->argInfo & POPT_ARG_MASK)) return NULL; @@ -50,45 +94,224 @@ getArgDescrip(const struct poptOption * opt, const char *translation_domain) if (opt->argDescrip) return POPT_(opt->argDescrip); if (opt->argDescrip) return D_(translation_domain, opt->argDescrip); - return POPT_("ARG"); + + switch (opt->argInfo & POPT_ARG_MASK) { + case POPT_ARG_NONE: return POPT_("NONE"); + case POPT_ARG_VAL: return POPT_("VAL"); + 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"); + } +} + +/** + * @param opt option(s) + * @param translation_domain translation domain + */ +static /*@only@*/ /*@null@*/ char * +singleOptionDefaultValue(int lineLength, + const struct poptOption * opt, + /*@-paramuse@*/ /* FIX: i18n macros disable with lclint */ + /*@null@*/ const char * translation_domain) + /*@=paramuse@*/ + /*@*/ +{ + const char * defstr = D_(translation_domain, "default"); + char * le = malloc(4*lineLength + 1); + char * l = le; + + if (le == NULL) return NULL; /* XXX can't happen */ + *le = '\0'; + *le++ = '('; + strcpy(le, defstr); le += strlen(le); + *le++ = ':'; + *le++ = ' '; + if (opt->arg) /* XXX programmer error */ + 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; + /*@notreached@*/ break; + } + *le++ = ')'; + *le = '\0'; + + return l; } -static void singleOptionHelp(FILE * f, int maxLeftCol, - const struct poptOption * opt, - const char *translation_domain) { +/** + * @param fp output file handle + * @param opt option(s) + * @param translation_domain translation domain + */ +static void singleOptionHelp(FILE * fp, int maxLeftCol, + const struct poptOption * opt, + /*@null@*/ const char * translation_domain) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/ +{ 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; - const char * ch; - char format[10]; + char * defs = NULL; char * left; - const char * argDescrip = getArgDescrip(opt, translation_domain); + int nb = maxLeftCol + 1; + + /* Make sure there's more than enough room in target buffer. */ + if (opt->longName) nb += strlen(opt->longName); + if (argDescrip) nb += strlen(argDescrip); - left = malloc(maxLeftCol + 1); - *left = '\0'; + left = malloc(nb); + if (left == NULL) return; /* XXX can't happen */ + left[0] = '\0'; + left[maxLeftCol] = '\0'; if (opt->longName && opt->shortName) - sprintf(left, "-%c, --%s", opt->shortName, opt->longName); - else if (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", opt->longName); - if (!*left) return ; + sprintf(left, "%s%s", + ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), + opt->longName); + if (!*left) goto out; if (argDescrip) { - strcat(left, "="); - strcat(left, argDescrip); + char * le = left + strlen(left); + + if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) + *le++ = '['; + + /* Choose type of output */ + /*@-branchstate@*/ + 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; + } + } + /*@=branchstate@*/ + + if (opt->argDescrip == NULL) { + switch (opt->argInfo & POPT_ARG_MASK) { + case POPT_ARG_NONE: + break; + case POPT_ARG_VAL: + { long aLong = opt->val; + int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS); + int negate = (opt->argInfo & POPT_ARGFLAG_NOT); + + /* Don't bother displaying typical values */ + if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L)) + break; + *le++ = '['; + switch (ops) { + case POPT_ARGFLAG_OR: + *le++ = '|'; + /*@innerbreak@*/ break; + case POPT_ARGFLAG_AND: + *le++ = '&'; + /*@innerbreak@*/ break; + case POPT_ARGFLAG_XOR: + *le++ = '^'; + /*@innerbreak@*/ break; + default: + /*@innerbreak@*/ break; + } + *le++ = '='; + if (negate) *le++ = '~'; + /*@-formatconst@*/ + le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong); + /*@=formatconst@*/ + *le++ = ']'; + } 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(f," %-*s ", maxLeftCol, left); + fprintf(fp," %-*s ", maxLeftCol, left); else { - fprintf(f," %s\n", left); + 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[10]; + ch = help + lineLength - 1; while (ch > help && !isspace(*ch)) ch--; if (ch == help) break; /* give up */ @@ -96,39 +319,56 @@ static void singleOptionHelp(FILE * f, int maxLeftCol, ch++; sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength); - fprintf(f, format, help, " "); + /*@-formatconst@*/ + fprintf(fp, format, help, " "); + /*@=formatconst@*/ help = ch; while (isspace(*help) && *help) help++; helpLength = strlen(help); } - if (helpLength) fprintf(f, "%s\n", help); + if (helpLength) fprintf(fp, "%s\n", help); out: - free(left); + /*@-dependenttrans@*/ + defs = _free(defs); + /*@=dependenttrans@*/ + left = _free(left); } +/** + * @param opt option(s) + * @param translation_domain translation domain + */ static int maxArgWidth(const struct poptOption * opt, - const char * translation_domain) { + /*@null@*/ const char * translation_domain) + /*@*/ +{ int max = 0; - int this; + 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) { - this = maxArgWidth(opt->arg, translation_domain); - if (this > max) max = this; + if (opt->arg) /* XXX program error */ + len = maxArgWidth(opt->arg, translation_domain); + if (len > max) max = len; } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { - this = opt->shortName ? 2 : 0; + len = sizeof(" ")-1; + if (opt->shortName != '\0') len += sizeof("-X")-1; + if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1; if (opt->longName) { - if (this) this += 2; - this += strlen(opt->longName) + 2; + len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH) + ? sizeof("-")-1 : sizeof("--")-1); + len += strlen(opt->longName); } s = getArgDescrip(opt, translation_domain); if (s) - this += strlen(s) + 1; - if (this > max) max = this; + len += sizeof("=")-1 + strlen(s); + if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1; + if (len > max) max = len; } opt++; @@ -137,77 +377,134 @@ static int maxArgWidth(const struct poptOption * opt, return max; } -static void singleTableHelp(FILE * f, const struct poptOption * table, - int left, - const char *translation_domain) { +/** + * Display popt alias and exec help. + * @param fp output file handle + * @param items alias/exec array + * @param nitems no. of alias/exec entries + * @param translation_domain translation domain + */ +static void itemHelp(FILE * fp, + /*@null@*/ poptItem items, int nitems, int left, + /*@null@*/ const char * translation_domain) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/ +{ + poptItem item; + int i; + + if (items != NULL) + for (i = 0, item = items; i < nitems; i++, item++) { + const struct poptOption * opt; + opt = &item->option; + if ((opt->longName || opt->shortName) && + !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) + singleOptionHelp(fp, left, opt, translation_domain); + } +} + +/** + * @param fp output file handle + * @param table option(s) + * @param translation_domain translation domain + */ +static void singleTableHelp(poptContext con, FILE * fp, + /*@null@*/ const struct poptOption * table, int left, + /*@null@*/ const char * translation_domain) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/ +{ const struct poptOption * opt; const char *sub_transdom; - opt = table; - while (opt->longName || opt->shortName || opt->arg) { + if (table == poptAliasOptions) { + 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(f, left, opt, translation_domain); - opt++; + singleOptionHelp(fp, left, opt, translation_domain); } - opt = table; - while (opt->longName || opt->shortName || opt->arg) { - if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { - sub_transdom = getTableTranslationDomain(opt->arg); - if(!sub_transdom) - sub_transdom = 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(f, "\n%s\n", D_(sub_transdom, opt->descrip)); + if (opt->descrip) + fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip)); - singleTableHelp(f, opt->arg, left, sub_transdom); - } - opt++; + singleTableHelp(con, fp, opt->arg, left, sub_transdom); } } -static int showHelpIntro(poptContext con, FILE * f) { +/** + * @param con context + * @param fp output file handle + */ +static int showHelpIntro(poptContext con, FILE * fp) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/ +{ int len = 6; const char * fn; - fprintf(f, POPT_("Usage:")); + fprintf(fp, POPT_("Usage:")); if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) { + /*@-nullderef@*/ /* LCL: wazzup? */ fn = con->optionStack->argv[0]; - if (strchr(fn, '/')) fn = strchr(fn, '/') + 1; - fprintf(f, " %s", fn); + /*@=nullderef@*/ + if (fn == NULL) return len; + if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1; + fprintf(fp, " %s", fn); len += strlen(fn) + 1; } return len; } -void poptPrintHelp(poptContext con, FILE * f, /*@unused@*/ int flags) { +void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags) +{ int leftColWidth; - showHelpIntro(con, f); + (void) showHelpIntro(con, fp); if (con->otherHelp) - fprintf(f, " %s\n", con->otherHelp); + fprintf(fp, " %s\n", con->otherHelp); else - fprintf(f, " %s\n", POPT_("[OPTION...]")); + fprintf(fp, " %s\n", POPT_("[OPTION...]")); leftColWidth = maxArgWidth(con->options, NULL); - singleTableHelp(f, con->options, leftColWidth, NULL); + singleTableHelp(con, fp, con->options, leftColWidth, NULL); } -static int singleOptionUsage(FILE * f, int cursor, - const struct poptOption * opt, - const char *translation_domain) { +/** + * @param fp output file handle + * @param opt option(s) + * @param translation_domain translation domain + */ +static int singleOptionUsage(FILE * fp, int cursor, + const struct poptOption * opt, + /*@null@*/ const char *translation_domain) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/ +{ int len = 3; char shortStr[2] = { '\0', '\0' }; const char * item = shortStr; const char * argDescrip = getArgDescrip(opt, translation_domain); - if (opt->shortName) { + if (opt->shortName!= '\0' ) { if (!(opt->argInfo & POPT_ARG_MASK)) return cursor; /* we did these already */ len++; - *shortStr = opt->shortName; + shortStr[0] = opt->shortName; shortStr[1] = '\0'; } else if (opt->longName) { len += 1 + strlen(opt->longName); @@ -220,82 +517,140 @@ static int singleOptionUsage(FILE * f, int cursor, len += strlen(argDescrip) + 1; if ((cursor + len) > 79) { - fprintf(f, "\n "); + fprintf(fp, "\n "); cursor = 7; } - fprintf(f, " [-%s%s%s%s]", opt->shortName ? "" : "-", item, - argDescrip ? (opt->shortName ? " " : "=") : "", - argDescrip ? argDescrip : ""); + 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 singleTableUsage(FILE * f, int cursor, const struct poptOption * table, - const char *translation_domain) { - const struct poptOption * opt; - - opt = table; - while (opt->longName || opt->shortName || opt->arg) { - if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) +/** + * Display popt alias and exec usage. + * @param fp output file handle + * @param item alias/exec array + * @param nitems no. of ara/exec entries + * @param translation_domain translation domain + */ +static int itemUsage(FILE * fp, int cursor, poptItem item, int nitems, + /*@null@*/ const char * translation_domain) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/ +{ + int i; + + /*@-branchstate@*/ /* FIX: W2DO? */ + if (item != NULL) + for (i = 0; i < nitems; i++, item++) { + const struct poptOption * opt; + opt = &item->option; + 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) - cursor = singleTableUsage(f, cursor, opt->arg, - translation_domain); - else if ((opt->longName || opt->shortName) && - !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) - cursor = singleOptionUsage(f, cursor, opt, translation_domain); + } else if ((opt->longName || opt->shortName) && + !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { + cursor = singleOptionUsage(fp, cursor, opt, translation_domain); + } + } + /*@=branchstate@*/ - opt++; + return cursor; +} + +/** + * @param fp output file handle + * @param opt option(s) + * @param translation_domain translation domain + */ +static int singleTableUsage(poptContext con, FILE * fp, + int cursor, const struct poptOption * opt, + /*@null@*/ const char * translation_domain) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/ +{ + /*@-branchstate@*/ /* FIX: W2DO? */ + 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 (opt->arg) /* XXX program error */ + cursor = singleTableUsage(con, fp, cursor, opt->arg, + translation_domain); + } else if ((opt->longName || opt->shortName) && + !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { + cursor = singleOptionUsage(fp, cursor, opt, translation_domain); + } } + /*@=branchstate@*/ return cursor; } -static int showShortOptions(const struct poptOption * opt, FILE * f, - char * str) { - char s[300]; /* this is larger then the ascii set, so - it should do just fine */ +/** + * Return concatenated short options for display. + * @param opt option(s) + * @param fp output file handle + * @retval str concatenation of short options + * @return length of display string + */ +static int showShortOptions(const struct poptOption * opt, FILE * fp, + /*@null@*/ char * str) + /*@globals fileSystem @*/ + /*@modifies *str, *fp, fileSystem @*/ +{ + char * s = alloca(300); /* larger then the ascii set */ s[0] = '\0'; + /*@-branchstate@*/ /* FIX: W2DO? */ if (str == NULL) { memset(s, 0, sizeof(s)); str = s; } + /*@=branchstate@*/ - while (opt->longName || opt->shortName || opt->arg) { + 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) - showShortOptions(opt->arg, f, str); - - opt++; + if (opt->arg) /* XXX program error */ + (void) showShortOptions(opt->arg, fp, str); } - if (s != str || !*s) + if (s != str || *s != '\0') return 0; - fprintf(f, " [-%s]", s); + fprintf(fp, " [-%s]", s); return strlen(s) + 4; } -void poptPrintUsage(poptContext con, FILE * f, /*@unused@*/ int flags) { +void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags) +{ int cursor; - cursor = showHelpIntro(con, f); - cursor += showShortOptions(con->options, f, NULL); - singleTableUsage(f, cursor, con->options, NULL); + cursor = showHelpIntro(con, fp); + cursor += showShortOptions(con->options, fp, NULL); + (void) singleTableUsage(con, fp, cursor, con->options, NULL); + (void) itemUsage(fp, cursor, con->aliases, con->numAliases, NULL); + (void) itemUsage(fp, cursor, con->execs, con->numExecs, NULL); if (con->otherHelp) { cursor += strlen(con->otherHelp) + 1; - if (cursor > 79) fprintf(f, "\n "); - fprintf(f, " %s", con->otherHelp); + if (cursor > 79) fprintf(fp, "\n "); + fprintf(fp, " %s", con->otherHelp); } - fprintf(f, "\n"); + fprintf(fp, "\n"); } -void poptSetOtherOptionHelp(poptContext con, const char * text) { - if (con->otherHelp) xfree(con->otherHelp); +void poptSetOtherOptionHelp(poptContext con, const char * text) +{ + con->otherHelp = _free(con->otherHelp); con->otherHelp = xstrdup(text); } +/*@=type@*/ diff --git a/popt/poptint.h b/popt/poptint.h index a1edb97c..30172fea 100644 --- a/popt/poptint.h +++ b/popt/poptint.h @@ -1,69 +1,78 @@ -/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING +/** \ingroup popt + * \file popt/poptint.h + */ + +/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from - ftp://ftp.redhat.com/pub/code/popt */ + ftp://ftp.rpm.org/pub/rpm/dist. */ #ifndef H_POPTINT #define H_POPTINT +/** + * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL. + * @param p memory to free + * @retval NULL always + */ +/*@unused@*/ static inline /*@null@*/ void * +_free(/*@only@*/ /*@null@*/ const void * p) + /*@modifies p @*/ +{ + if (p != NULL) free((void *)p); + return NULL; +} + /* Bit mask macros. */ 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 << ((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_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; - /*@only@*/ const char ** argv; - /*@only@*/ pbm_set * argb; +/*@only@*/ /*@null@*/ const char ** argv; +/*@only@*/ /*@null@*/ pbm_set * argb; int next; - /*@only@*/ const char * nextArg; - /*@keep@*/ const char * nextCharArg; - /*@dependent@*/ struct poptAlias * currAlias; +/*@only@*/ /*@null@*/ const char * nextArg; +/*@keep@*/ /*@null@*/ const char * nextCharArg; +/*@dependent@*/ /*@null@*/ poptItem currAlias; int stuffed; }; -struct execEntry { - const char * longName; - char shortName; - const char * script; -}; - struct poptContext_s { struct optionStackEntry optionStack[POPT_OPTION_DEPTH]; - /*@dependent@*/ struct optionStackEntry * os; - /*@owned@*/ const char ** leftovers; +/*@dependent@*/ struct optionStackEntry * os; +/*@owned@*/ /*@null@*/ const char ** leftovers; int numLeftovers; int nextLeftover; - /*@keep@*/ const struct poptOption * options; +/*@keep@*/ const struct poptOption * options; int restLeftover; - /*@only@*/ const char * appName; - /*@only@*/ struct poptAlias * aliases; +/*@only@*/ /*@null@*/ const char * appName; +/*@only@*/ /*@null@*/ poptItem aliases; int numAliases; int flags; - struct execEntry * execs; +/*@owned@*/ /*@null@*/ poptItem execs; int numExecs; - /*@only@*/ const char ** finalArgv; +/*@only@*/ /*@null@*/ const char ** finalArgv; int finalArgvCount; int finalArgvAlloced; - /*@dependent@*/ struct execEntry * doExec; - /*@only@*/ const char * execPath; +/*@dependent@*/ /*@null@*/ poptItem doExec; +/*@only@*/ const char * execPath; int execAbsolute; - /*@only@*/ const char * otherHelp; - pbm_set * arg_strip; +/*@only@*/ const char * otherHelp; +/*@null@*/ pbm_set * arg_strip; }; -#define xfree(_a) free((void *)_a) - #ifdef HAVE_LIBINTL_H #include #endif @@ -71,17 +80,17 @@ struct poptContext_s { #if defined(HAVE_GETTEXT) && !defined(__LCLINT__) #define _(foo) gettext(foo) #else -#define _(foo) (foo) +#define _(foo) foo #endif #if defined(HAVE_DGETTEXT) && !defined(__LCLINT__) #define D_(dom, str) dgettext(dom, str) #define POPT_(foo) D_("popt", foo) #else -#define POPT_(foo) (foo) -#define D_(dom, str) (str) +#define D_(dom, str) str +#define POPT_(foo) foo #endif -#define N_(foo) (foo) +#define N_(foo) foo #endif diff --git a/popt/poptparse.c b/popt/poptparse.c index 8f00769b..2ffb7dd2 100644 --- a/popt/poptparse.c +++ b/popt/poptparse.c @@ -1,6 +1,10 @@ -/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING +/** \ingroup popt + * \file popt/poptparse.c + */ + +/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from - ftp://ftp.redhat.com/pub/code/popt */ + ftp://ftp.rpm.org/pub/rpm/dist. */ #include "system.h" @@ -14,6 +18,8 @@ int poptDupArgv(int argc, const char **argv, char * dst; int i; + if (argc <= 0 || argv == NULL) /* XXX can't happen */ + return POPT_ERROR_NOARG; for (i = 0; i < argc; i++) { if (argv[i] == NULL) return POPT_ERROR_NOARG; @@ -21,17 +27,27 @@ int poptDupArgv(int argc, const char **argv, } dst = malloc(nb); + if (dst == NULL) /* XXX can't happen */ + return POPT_ERROR_MALLOC; argv2 = (void *) dst; dst += (argc + 1) * sizeof(*argv); + /*@-branchstate@*/ for (i = 0; i < argc; i++) { argv2[i] = dst; dst += strlen(strcpy(dst, argv[i])) + 1; } + /*@=branchstate@*/ argv2[argc] = NULL; - *argvPtr = argv2; - *argcPtr = argc; + if (argvPtr) { + *argvPtr = argv2; + } else { + free(argv2); + argv2 = NULL; + } + if (argcPtr) + *argcPtr = argc; return 0; } @@ -43,31 +59,32 @@ int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) const char ** argv = malloc(sizeof(*argv) * argvAlloced); int argc = 0; int buflen = strlen(s) + 1; - char *buf0 = calloc(buflen, 1); - char *buf = buf0; + char * buf = memset(alloca(buflen), 0, buflen); + int rc = POPT_ERROR_MALLOC; + if (argv == NULL) return rc; argv[argc] = buf; - for (src = s; *src; src++) { + for (src = s; *src != '\0'; src++) { if (quote == *src) { quote = '\0'; - } else if (quote) { + } else if (quote != '\0') { if (*src == '\\') { src++; if (!*src) { - free(argv); - free(buf0); - return POPT_ERROR_BADQUOTE; + rc = POPT_ERROR_BADQUOTE; + goto exit; } if (*src != quote) *buf++ = '\\'; } *buf++ = *src; } else if (isspace(*src)) { - if (*argv[argc]) { + 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; } @@ -75,18 +92,17 @@ int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) case '"': case '\'': quote = *src; - break; + /*@switchbreak@*/ break; case '\\': src++; if (!*src) { - free(argv); - free(buf0); - return POPT_ERROR_BADQUOTE; + rc = POPT_ERROR_BADQUOTE; + goto exit; } /*@fallthrough@*/ default: *buf++ = *src; - break; + /*@switchbreak@*/ break; } } @@ -94,9 +110,9 @@ int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) argc++, buf++; } - (void) poptDupArgv(argc, argv, argcPtr, argvPtr); + rc = poptDupArgv(argc, argv, argcPtr, argvPtr); - free(argv); - free(buf0); - return 0; +exit: + if (argv) free(argv); + return rc; } diff --git a/popt/system.h b/popt/system.h index 43ad70f9..338be45b 100644 --- a/popt/system.h +++ b/popt/system.h @@ -25,6 +25,14 @@ #include #endif +#if defined(__LCLINT__) +/*@-declundef -incondefs -redecl@*/ /* LCL: missing annotation */ +/*@only@*/ void * alloca (size_t __size) + /*@ensures MaxSet(result) == (__size - 1) @*/ + /*@*/; +/*@=declundef =incondefs =redecl@*/ +#endif + /* AIX requires this to be the first thing in the file. */ #ifndef __GNUC__ # if HAVE_ALLOCA_H @@ -42,7 +50,10 @@ char *alloca (); #define alloca __builtin_alloca #endif -/*@only@*/ char * xstrdup (const char *str); +/*@-redecl -redef@*/ +/*@mayexit@*/ /*@only@*/ char * xstrdup (const char *str) + /*@*/; +/*@=redecl =redef@*/ #if HAVE_MCHECK_H && defined(__GNUC__) #define vmefail() (fprintf(stderr, "virtual memory exhausted.\n"), exit(EXIT_FAILURE), NULL) -- 2.34.1