From 105660d3f9b537fa47fe6e33c0418a1d8f85e0e9 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 19 Mar 2005 19:31:25 +0000 Subject: r5906: Fix the usage of the internal popt (make proto should ignore it) Updated included popt to 1.7. (This used to be commit d60cb643e8a46771f3d836307ea45b869f34dc9b) --- source4/lib/popt/CHANGES | 5 +- source4/lib/popt/README | 2 +- source4/lib/popt/config.m4 | 15 +- source4/lib/popt/config.mk | 11 + source4/lib/popt/findme.c | 33 +- source4/lib/popt/findme.h | 16 +- source4/lib/popt/popt.c | 1048 +++++++++++++++++++++++++++++------------ source4/lib/popt/popt.h | 585 +++++++++++++++++++---- source4/lib/popt/poptconfig.c | 176 ++++--- source4/lib/popt/popthelp.c | 680 +++++++++++++++++++++----- source4/lib/popt/poptint.h | 103 ++-- source4/lib/popt/poptparse.c | 169 ++++++- source4/lib/popt/system.h | 23 +- 13 files changed, 2205 insertions(+), 661 deletions(-) create mode 100644 source4/lib/popt/config.mk (limited to 'source4/lib/popt') diff --git a/source4/lib/popt/CHANGES b/source4/lib/popt/CHANGES index b6ab2aa308..db16a5fdd0 100644 --- a/source4/lib/popt/CHANGES +++ b/source4/lib/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/source4/lib/popt/README b/source4/lib/popt/README index 7fccc836ff..0b5205bfdd 100644 --- a/source4/lib/popt/README +++ b/source4/lib/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/source4/lib/popt/config.m4 b/source4/lib/popt/config.m4 index ff4455efa2..d5a8df9200 100644 --- a/source4/lib/popt/config.m4 +++ b/source4/lib/popt/config.m4 @@ -25,16 +25,17 @@ fi AC_MSG_CHECKING(whether to use included popt) if test x"$INCLUDED_POPT" != x"no"; then - TMP_LIBPOPT_OBJS="lib/popt/findme.o lib/popt/popt.o lib/popt/poptconfig.o \ - lib/popt/popthelp.o lib/popt/poptparse.o" CPPFLAGS="$CPPFLAGS -I$srcdir/lib/popt" + SMB_SUBSYSTEM(LIBPOPT,[], + [], + [INT_LIB_POPT]) AC_MSG_RESULT(yes) else + SMB_SUBSYSTEM(LIBPOPT,[], + [], + [EXT_LIB_POPT]) + SMB_EXT_LIB(POPT, [${TMP_LIBPOPT_LIBS}]) AC_MSG_RESULT(no) fi -SMB_EXT_LIB(POPT, [${TMP_LIBPOPT_LIBS}]) - -SMB_SUBSYSTEM(LIBPOPT,[], - [${TMP_LIBPOPT_OBJS}], - [EXT_LIB_POPT]) +AC_CHECK_HEADERS([float.h]) diff --git a/source4/lib/popt/config.mk b/source4/lib/popt/config.mk new file mode 100644 index 0000000000..fee3ab1e4b --- /dev/null +++ b/source4/lib/popt/config.mk @@ -0,0 +1,11 @@ +############################## +# Start SUBSYSTEM INT_LIB_POPT +[SUBSYSTEM::INT_LIB_POPT] +ADD_OBJ_FILES = lib/popt/findme.o \ + lib/popt/popt.o \ + lib/popt/poptconfig.o \ + lib/popt/popthelp.o \ + lib/popt/poptparse.o +NOPROTO = YES +# End SUBSYSTEM INT_LIB_POPT +############################## diff --git a/source4/lib/popt/findme.c b/source4/lib/popt/findme.c index 67a535ac65..a950e50018 100644 --- a/source4/lib/popt/findme.c +++ b/source4/lib/popt/findme.c @@ -1,47 +1,50 @@ -/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING +/** \ingroup popt + * \file popt/findme.c + */ + +/* (C) 1998-2002 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" - const char * findProgramPath(const char * argv0) -{ +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/source4/lib/popt/findme.h b/source4/lib/popt/findme.h index 5e93963d60..a016b867ea 100644 --- a/source4/lib/popt/findme.h +++ b/source4/lib/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/source4/lib/popt/popt.c b/source4/lib/popt/popt.c index a607f19f2f..eb81c720f5 100644 --- a/source4/lib/popt/popt.c +++ b/source4/lib/popt/popt.c @@ -1,11 +1,28 @@ -/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING +/** \ingroup popt + * \file popt/popt.c + */ + +/* (C) 1998-2002 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" +#ifdef MYDEBUG +/*@unchecked@*/ +int _popt_debug = 0; +#endif + #ifndef HAVE_STRERROR static char * strerror(int errno) { extern int sys_nerr; @@ -18,50 +35,143 @@ static char * strerror(int errno) { } #endif - void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) +#ifdef MYDEBUG +/*@unused@*/ static void prtcon(const char *msg, poptContext con) { - if (con->execPath) xfree(con->execPath); + 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 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 @*/ + } + } } -static void invokeCallbacks(poptContext con, const struct poptOption * table, - int post) +static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt) + /*@globals internalState@*/ + /*@modifies internalState@*/ { - const struct poptOption * opt = table; - poptCallbackType cb; + 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. */ + 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 @*/ + } + } +} - while (opt->longName || opt->shortName || opt->arg) { +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) { - 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. */ + 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, +poptContext poptGetContext(const char * name, int argc, const char ** argv, 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; @@ -75,41 +185,38 @@ static void invokeCallbacks(poptContext con, const struct poptOption * table, 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) +/*@-boundswrite@*/ +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; @@ -120,37 +227,47 @@ static void cleanOSE(struct optionStackEntry *os) con->restLeftover = 0; con->doExec = NULL; + if (con->finalArgv != NULL) for (i = 0; i < con->finalArgvCount; i++) { - if (con->finalArgv[i]) { - xfree(con->finalArgv[i]); - con->finalArgv[i] = NULL; - } + /*@-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) +/*@=boundswrite@*/ + +/* Only one of longName, shortName should be set, not both. */ +/*@-boundswrite@*/ +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; @@ -168,46 +285,65 @@ 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@*/ } +/*@=boundswrite@*/ /* 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, + /*@exposed@*/ /*@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) return POPT_ERROR_OPTSTOODEEP; +/*@-boundsread@*/ if (nextCharArg && *nextCharArg) con->os->nextCharArg = nextCharArg; +/*@=boundsread@*/ con->os++; con->os->next = 0; @@ -215,50 +351,67 @@ 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) +/*@-bounds -boundswrite @*/ +static int execCommand(poptContext con) + /*@globals internalState @*/ + /*@modifies internalState @*/ { + 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()" @@ -266,65 +419,109 @@ 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; -/*@observer@*/ static const struct poptOption * -findOption(const struct poptOption * table, const char * longName, - char shortName, - /*@out@*/ poptCallbackType * callback, /*@out@*/ const void ** callbackData, - int singleDash) +#ifdef MYDEBUG +if (_popt_debug) + { 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; +} +/*@=bounds =boundswrite @*/ + +/*@-boundswrite@*/ +/*@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; } +/*@=boundswrite@*/ -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; @@ -334,43 +531,59 @@ 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) +/*@-boundswrite@*/ +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); @@ -380,53 +593,116 @@ 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; } +/*@=boundswrite@*/ -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@*/ } +int poptSaveLong(long * arg, int argInfo, long aLong) +{ + /* XXX Check alignment, may fail on funky platforms. */ + if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1))) + return POPT_ERROR_NULLARG; + + if (argInfo & POPT_ARGFLAG_NOT) + aLong = ~aLong; + switch (argInfo & POPT_ARGFLAG_LOGICALOPS) { + case 0: + *arg = aLong; + break; + case POPT_ARGFLAG_OR: + *arg |= aLong; + break; + case POPT_ARGFLAG_AND: + *arg &= aLong; + break; + case POPT_ARGFLAG_XOR: + *arg ^= aLong; + break; + default: + return POPT_ERROR_BADOPERATION; + /*@notreached@*/ break; + } + return 0; +} + +int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong) +{ + /* XXX Check alignment, may fail on funky platforms. */ + if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1))) + return POPT_ERROR_NULLARG; + + if (argInfo & POPT_ARGFLAG_NOT) + aLong = ~aLong; + switch (argInfo & POPT_ARGFLAG_LOGICALOPS) { + case 0: + *arg = aLong; + break; + case POPT_ARGFLAG_OR: + *arg |= aLong; + break; + case POPT_ARGFLAG_AND: + *arg &= aLong; + break; + case POPT_ARGFLAG_XOR: + *arg ^= aLong; + break; + default: + return POPT_ERROR_BADOPERATION; + /*@notreached@*/ break; + } + return 0; +} + +/*@-boundswrite@*/ /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */ - int poptGetNextOpt(poptContext con) +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; } @@ -435,26 +711,36 @@ static void poptStripArg(poptContext con, int which) 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]) { @@ -473,12 +759,13 @@ static void poptStripArg(poptContext con, int which) /* 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. */ @@ -494,110 +781,175 @@ static void poptStripArg(poptContext con, int which) 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((int *)opt->arg, opt->argInfo, 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((int *)opt->arg, opt->argInfo, (long)opt->val)) + return POPT_ERROR_BADOPERATION; } + } else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) { + con->os->nextArg = _free(con->os->nextArg); + /*@-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((long *)opt->arg, opt->argInfo, aLong)) + return POPT_ERROR_BADOPERATION; } else { if (aLong > INT_MAX || aLong < INT_MIN) return POPT_ERROR_OVERFLOW; - *((int *) opt->arg) = aLong; + if (poptSaveInt((int *)opt->arg, opt->argInfo, 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)) { @@ -606,138 +958,222 @@ static void poptStripArg(poptContext con, int which) 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 */ } +/*@=boundswrite@*/ - const char * poptGetOptArg(poptContext con) +const char * poptGetOptArg(poptContext con) { - const char * ret = con->os->nextArg; - con->os->nextArg = NULL; + const char * ret = NULL; + /*@-branchstate@*/ + if (con) { + ret = con->os->nextArg; + con->os->nextArg = NULL; + } + /*@=branchstate@*/ return ret; } - const char * poptGetArg(poptContext con) +const char * poptGetArg(poptContext con) { - if (con->numLeftovers == con->nextLeftover) return NULL; - return con->leftovers[con->nextLeftover++]; + 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) +const char * poptPeekArg(poptContext con) { - if (con->numLeftovers == con->nextLeftover) return NULL; - return con->leftovers[con->nextLeftover]; + 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) +/*@-boundswrite@*/ +const char ** poptGetArgs(poptContext con) { - if (con->numLeftovers == con->nextLeftover) return NULL; + 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 @*/ } +/*@=boundswrite@*/ - 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; +/*@-boundswrite@*/ +/*@-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); + + 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; - 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; + (*nitems)++; return 0; } +/*@=mustmod@*/ +/*@=boundswrite@*/ - const char * poptBadOption(poptContext con, int flags) +const char * poptBadOption(poptContext con, int flags) { - struct optionStackEntry * os; + 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 *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: @@ -745,54 +1181,56 @@ static void poptStripArg(poptContext con, int which) } } - 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) +const char * poptGetInvocationName(poptContext con) { - return con->os->argv[0]; + return (con->os->argv ? con->os->argv[0] : ""); } - int poptStrippedArgv(poptContext con, int argc, char **argv) +/*@-boundswrite@*/ +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(). + */ +/*@-exporttype@*/ +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; +/*@=exporttype@*/ + +/** \ingroup popt + * \name Auto-generated help/usage + */ +/*@{*/ + +/** + * Empty table marker to enable displaying popt alias/exec options. + */ +/*@-exportvar@*/ +/*@unchecked@*/ /*@observer@*/ +extern struct poptOption poptAliasOptions[]; +/*@=exportvar@*/ +#define POPT_AUTOALIAS { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptAliasOptions, \ + 0, "Options implemented via popt alias/exec:", NULL }, + +/** + * Auto help table options. + */ +/*@-exportvar@*/ +/*@unchecked@*/ /*@observer@*/ extern struct poptOption poptHelpOptions[]; +/*@=exportvar@*/ #define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \ - 0, "Help options", NULL }, + 0, "Help options:", NULL }, + +#define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL } +/*@}*/ -typedef struct poptContext_s * poptContext; +/** \ingroup popt + */ +/*@-exporttype@*/ +typedef /*@abstract@*/ struct poptContext_s * poptContext; +/*@=exporttype@*/ + +/** \ingroup popt + */ #ifndef __cplusplus +/*@-exporttype -typeuse@*/ typedef struct poptOption * poptOption; +/*@=exporttype =typeuse@*/ +#endif + +/*@-exportconst@*/ +enum poptCallbackReason { + POPT_CALLBACK_REASON_PRE = 0, + POPT_CALLBACK_REASON_POST = 1, + POPT_CALLBACK_REASON_OPTION = 2 +}; +/*@=exportconst@*/ + +#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) + /*@*/; -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); +/** \ingroup popt + * Reinitialize popt context. + * @param con context + */ +/*@-exportlocal@*/ +void poptResetContext(/*@null@*/poptContext con) + /*@modifies con @*/; +/*@=exportlocal@*/ + +/** \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, internalState @*/ + /*@modifies con, fileSystem, internalState @*/; + +/*@-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 + * @param flags + * @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 newItem 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, internalState @*/ + /*@modifies con->execs, con->numExecs, + fileSystem, internalState @*/; + +/** \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, internalState @*/ + /*@modifies con->execs, con->numExecs, + fileSystem, internalState @*/; + +/** \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 *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 + * Parses an input configuration file and returns an string that is a + * command line. For use with popt. You must free the return value when done. + * + * Given the file: +\verbatim +# this line is ignored + # this one too +aaa + bbb + ccc +bla=bla + +this_is = fdsafdas + bad_line= + reall bad line + reall bad line = again +5555= 55555 + test = with lots of spaces +\endverbatim +* +* The result is: +\verbatim +--aaa --bbb --ccc --bla="bla" --this_is="fdsafdas" --5555="55555" --test="with lots of spaces" +\endverbatim +* +* Passing this to poptParseArgvString() yields an argv of: +\verbatim +'--aaa' +'--bbb' +'--ccc' +'--bla=bla' +'--this_is=fdsafdas' +'--5555=55555' +'--test=with lots of spaces' +\endverbatim + * + * @bug NULL is returned if file line is too long. + * @bug Silently ignores invalid lines. + * + * @param fp file handle to read + * @param *argstrp return string of options (malloc'd) + * @param flags unused + * @return 0 on success + * @see poptParseArgvString + */ +/*@-fcnuse@*/ +int poptConfigFileToString(FILE *fp, /*@out@*/ char ** argstrp, int flags) + /*@globals fileSystem @*/ + /*@modifies *fp, *argstrp, fileSystem @*/; +/*@=fcnuse@*/ + +/** \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@*/ + +/** + * Save a long, performing logical operation with value. + * @warning Alignment check may be too strict on certain platorms. + * @param arg integer pointer, aligned on int boundary. + * @param argInfo logical operation (see POPT_ARGFLAG_*) + * @param aLong value to use + * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION + */ +/*@-incondefs@*/ +int poptSaveLong(/*@null@*/ long * arg, int argInfo, long aLong) + /*@modifies *arg @*/ + /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/; +/*@=incondefs@*/ + +/** + * Save an integer, performing logical operation with value. + * @warning Alignment check may be too strict on certain platorms. + * @param arg integer pointer, aligned on int boundary. + * @param argInfo logical operation (see POPT_ARGFLAG_*) + * @param aLong value to use + * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION + */ +/*@-incondefs@*/ +int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong) + /*@modifies *arg @*/ + /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/; +/*@=incondefs@*/ +/*@=type@*/ #ifdef __cplusplus } #endif diff --git a/source4/lib/popt/poptconfig.c b/source4/lib/popt/poptconfig.c index 113270a569..a600a92905 100644 --- a/source4/lib/popt/poptconfig.c +++ b/source4/lib/popt/poptconfig.c @@ -1,103 +1,147 @@ -/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING +/** \ingroup popt + * \file popt/poptconfig.c + */ + +/* (C) 1998-2002 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" +/*@-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; +/*@-boundswrite@*/ + 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@*/ +/*@=boundswrite@*/ + + /*@-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) +int poptReadConfigFile(poptContext con, const char * fn) { - char * file=NULL, * chptr, * end; - char * buf=NULL, * dst; + 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); +/*@-boundswrite@*/ + 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) { @@ -107,36 +151,38 @@ static void configLine(poptContext con, char * line) else *dst++ = *chptr++; } - break; + /*@switchbreak@*/ break; default: *dst++ = *chptr++; - break; + /*@switchbreak@*/ break; } } - - free(file); - free(buf); + /*@=infloops@*/ +/*@=boundswrite@*/ return 0; } - int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) +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 defined(HAVE_GETUID) && defined(HAVE_GETEUID) if (getuid() != geteuid()) return 0; +#endif 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; } diff --git a/source4/lib/popt/popthelp.c b/source4/lib/popt/popthelp.c index 562995c011..4d8f0efc24 100644 --- a/source4/lib/popt/popthelp.c +++ b/source4/lib/popt/popthelp.c @@ -1,49 +1,96 @@ /* -*- 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-2002 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" +/** + * Display arguments. + * @param con context + * @param foo (unused) + * @param key option(s) + * @param arg (unused) + * @param data (unused) + */ static void displayArgs(poptContext con, /*@unused@*/ enum poptCallbackReason foo, struct poptOption * key, /*@unused@*/ const char * arg, /*@unused@*/ void * data) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ { - if (key->shortName== '?') + 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 } ; - - -/*@observer@*/ /*@null@*/ static const char * -getTableTranslationDomain(const struct poptOption *table) +/*@=castfcnptr@*/ + +/** + * @param table option(s) + */ +/*@observer@*/ /*@null@*/ static const char *const +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; } -/*@observer@*/ /*@null@*/ static const char * -getArgDescrip(const struct poptOption * opt, const char *translation_domain) +/** + * @param opt option(s) + * @param translation_domain translation domain + */ +/*@observer@*/ /*@null@*/ static const char *const +getArgDescrip(const struct poptOption * opt, + /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ + /*@null@*/ const char * translation_domain) + /*@=paramuse@*/ + /*@*/ { if (!(opt->argInfo & POPT_ARG_MASK)) return NULL; @@ -51,46 +98,242 @@ 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"); +#ifdef DYING + case POPT_ARG_VAL: return POPT_("VAL"); +#else + case POPT_ARG_VAL: return NULL; +#endif + case POPT_ARG_INT: return POPT_("INT"); + case POPT_ARG_LONG: return POPT_("LONG"); + case POPT_ARG_STRING: return POPT_("STRING"); + case POPT_ARG_FLOAT: return POPT_("FLOAT"); + case POPT_ARG_DOUBLE: return POPT_("DOUBLE"); + default: return POPT_("ARG"); + } } -static void singleOptionHelp(FILE * f, int maxLeftCol, - const struct poptOption * opt, - const char *translation_domain) +/** + * Display default value for an option. + * @param lineLength + * @param opt option(s) + * @param translation_domain translation domain + * @return + */ +static /*@only@*/ /*@null@*/ char * +singleOptionDefaultValue(int lineLength, + const struct poptOption * opt, + /*@-paramuse@*/ /* FIX: i18n macros disabled 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 */ +/*@-boundswrite@*/ + *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'; +/*@=boundswrite@*/ + + return l; +} + +/** + * Display help text for an option. + * @param fp output file handle + * @param maxLeftCol + * @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'; +/*@-boundswrite@*/ + 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: +#ifdef NOTNOW /* XXX pug ugly nerdy output */ + { 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++ = ']'; + } +#endif + break; + case POPT_ARG_INT: + case POPT_ARG_LONG: + case POPT_ARG_FLOAT: + case POPT_ARG_DOUBLE: + case POPT_ARG_STRING: + *le++ = '='; + strcpy(le, argDescrip); le += strlen(le); + break; + default: + break; + } + } else { + *le++ = '='; + strcpy(le, argDescrip); le += strlen(le); + } + if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) + *le++ = ']'; + *le = '\0'; } +/*@=boundswrite@*/ 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); +/*@-boundsread@*/ while (helpLength > lineLength) { + const char * ch; + char format[16]; + ch = help + lineLength - 1; while (ch > help && !isspace(*ch)) ch--; if (ch == help) break; /* give up */ @@ -98,40 +341,57 @@ 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); } +/*@=boundsread@*/ - 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++; @@ -140,173 +400,343 @@ 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 left + * @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); + } +} + +/** + * Display help text for a table of options. + * @param con context + * @param fp output file handle + * @param table option(s) + * @param left + * @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)) { +/*@-boundsread@*/ + /*@-nullderef@*/ /* LCL: wazzup? */ fn = con->optionStack->argv[0]; - if (strchr(fn, '/')) fn = strchr(fn, '/') + 1; - fprintf(f, " %s", fn); + /*@=nullderef@*/ +/*@=boundsread@*/ + 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 cursor + * @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; + int len = 4; char shortStr[2] = { '\0', '\0' }; const char * item = shortStr; const char * argDescrip = getArgDescrip(opt, translation_domain); - if (opt->shortName) { - if (!(opt->argInfo & POPT_ARG_MASK)) - return cursor; /* we did these already */ + if (opt->shortName != '\0' && opt->longName != NULL) { + len += 2; + if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++; + len += strlen(opt->longName); + } else if (opt->shortName != '\0') { len++; - *shortStr = opt->shortName; + shortStr[0] = opt->shortName; shortStr[1] = '\0'; } else if (opt->longName) { - len += 1 + strlen(opt->longName); + len += strlen(opt->longName); + if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++; item = opt->longName; } - if (len == 3) return cursor; + if (len == 4) return cursor; if (argDescrip) 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 : ""); + if (opt->longName && opt->shortName) { + fprintf(fp, " [-%c|-%s%s%s%s]", + opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"), + opt->longName, + (argDescrip ? " " : ""), + (argDescrip ? argDescrip : "")); + } else { + fprintf(fp, " [-%s%s%s%s]", + ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"), + item, + (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""), + (argDescrip ? argDescrip : "")); + } return cursor + len + 1; } -static int singleTableUsage(FILE * f, int cursor, const struct poptOption * table, - const char *translation_domain) +/** + * Display popt alias and exec usage. + * @param fp output file handle + * @param cursor + * @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 @*/ { - const struct poptOption * opt; - - opt = table; - while (opt->longName || opt->shortName || opt->arg) { - if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) + 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; +} + +/** + * Keep track of option tables already processed. + */ +typedef struct poptDone_s { + int nopts; + int maxopts; + const void ** opts; +} * poptDone; + +/** + * Display usage text for a table of options. + * @param con context + * @param fp output file handle + * @param cursor + * @param opt option(s) + * @param translation_domain translation domain + * @param done tables already processed + * @return + */ +static int singleTableUsage(poptContext con, FILE * fp, int cursor, + /*@null@*/ const struct poptOption * opt, + /*@null@*/ const char * translation_domain, + /*@null@*/ poptDone done) + /*@globals fileSystem @*/ + /*@modifies *fp, done, 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 (done) { + int i = 0; + for (i = 0; i < done->nopts; i++) { +/*@-boundsread@*/ + const void * that = done->opts[i]; +/*@=boundsread@*/ + if (that == NULL || that != opt->arg) + /*@innercontinue@*/ continue; + /*@innerbreak@*/ break; + } + /* Skip if this table has already been processed. */ + if (opt->arg == NULL || i < done->nopts) + continue; +/*@-boundswrite@*/ + if (done->nopts < done->maxopts) + done->opts[done->nopts++] = (const void *) opt->arg; +/*@=boundswrite@*/ + } + cursor = singleTableUsage(con, fp, cursor, opt->arg, + translation_domain, done); + } else if ((opt->longName || opt->shortName) && + !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { + cursor = singleOptionUsage(fp, cursor, opt, translation_domain); + } } + /*@=branchstate@*/ return cursor; } -static int showShortOptions(const struct poptOption * opt, FILE * f, - char * str) +/** + * Return concatenated short options for display. + * @todo Sub-tables should be recursed. + * @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[300]; /* this is larger then the ascii set, so - it should do just fine */ + 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) { +/*@-boundswrite@*/ + 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); } +/*@=boundswrite@*/ - 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) { + poptDone done = memset(alloca(sizeof(*done)), 0, sizeof(*done)); int cursor; - cursor = showHelpIntro(con, f); - cursor += showShortOptions(con->options, f, NULL); - singleTableUsage(f, cursor, con->options, NULL); + done->nopts = 0; + done->maxopts = 64; + cursor = done->maxopts * sizeof(*done->opts); +/*@-boundswrite@*/ + done->opts = memset(alloca(cursor), 0, cursor); + done->opts[done->nopts++] = (const void *) con->options; +/*@=boundswrite@*/ + + cursor = showHelpIntro(con, fp); + cursor += showShortOptions(con->options, fp, NULL); + cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done); + cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL); + cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL); if (con->otherHelp) { cursor += strlen(con->otherHelp) + 1; - if (cursor > 79) fprintf(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) +void poptSetOtherOptionHelp(poptContext con, const char * text) { - if (con->otherHelp) xfree(con->otherHelp); + con->otherHelp = _free(con->otherHelp); con->otherHelp = xstrdup(text); } +/*@=type@*/ diff --git a/source4/lib/popt/poptint.h b/source4/lib/popt/poptint.h index 1847ffafe6..5d308efe96 100644 --- a/source4/lib/popt/poptint.h +++ b/source4/lib/popt/poptint.h @@ -1,71 +1,116 @@ -/* (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. */ +/*@-exporttype -redef @*/ typedef unsigned int __pbm_bits; +/*@=exporttype =redef @*/ #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)) +/*@-exporttype -redef @*/ typedef struct { __pbm_bits bits[1]; } pbm_set; +/*@=exporttype =redef @*/ #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; +/*@observer@*/ /*@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; +/*@only@*/ + const char * otherHelp; +/*@null@*/ pbm_set * arg_strip; }; -#define xfree(_a) free((void *)_a) +#ifdef HAVE_LIBINTL_H +#include +#endif + +#if defined(HAVE_GETTEXT) && !defined(__LCLINT__) +#define _(foo) gettext(foo) +#else +#define _(foo) foo +#endif + +#if defined(HAVE_DCGETTEXT) && !defined(__LCLINT__) +#define D_(dom, str) dgettext(dom, str) +#define POPT_(foo) D_("popt", foo) +#else +#define D_(dom, str) str +#define POPT_(foo) foo +#endif -#define POPT_(foo) (foo) -#define D_(dom, str) (str) -#define N_(foo) (foo) +#define N_(foo) foo #endif diff --git a/source4/lib/popt/poptparse.c b/source4/lib/popt/poptparse.c index 93bf7acfb8..a0dea80041 100644 --- a/source4/lib/popt/poptparse.c +++ b/source4/lib/popt/poptparse.c @@ -1,12 +1,17 @@ -/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING +/** \ingroup popt + * \file popt/poptparse.c + */ + +/* (C) 1998-2002 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" #define POPT_ARGV_ARRAY_GROW_DELTA 5 - int poptDupArgv(int argc, const char **argv, +/*@-boundswrite@*/ +int poptDupArgv(int argc, const char **argv, int * argcPtr, const char *** argvPtr) { size_t nb = (argc + 1) * sizeof(*argv); @@ -14,6 +19,8 @@ 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,21 +28,33 @@ } 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; } +/*@=boundswrite@*/ - int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) +/*@-bounds@*/ +int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) { const char * src; char quote = '\0'; @@ -43,31 +62,32 @@ 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 +95,17 @@ 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 +113,115 @@ argc++, buf++; } - (void) poptDupArgv(argc, argv, argcPtr, argvPtr); + rc = poptDupArgv(argc, argv, argcPtr, argvPtr); + +exit: + if (argv) free(argv); + return rc; +} +/*@=bounds@*/ + +/* still in the dev stage. + * return values, perhaps 1== file erro + * 2== line to long + * 3== umm.... more? + */ +int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ int flags) +{ + char line[999]; + char * argstr; + char * p; + char * q; + char * x; + int t; + int argvlen = 0; + size_t maxlinelen = sizeof(line); + size_t linelen; + int maxargvlen = 480; + int linenum = 0; + + *argstrp = NULL; + + /* | this_is = our_line + * p q x + */ + + if (fp == NULL) + return POPT_ERROR_NULLARG; + + argstr = calloc(maxargvlen, sizeof(*argstr)); + if (argstr == NULL) return POPT_ERROR_MALLOC; + + while (fgets(line, (int)maxlinelen, fp) != NULL) { + linenum++; + p = line; + + /* loop until first non-space char or EOL */ + while( *p != '\0' && isspace(*p) ) + p++; + + linelen = strlen(p); + if (linelen >= maxlinelen-1) + return POPT_ERROR_OVERFLOW; /* XXX line too long */ + + if (*p == '\0' || *p == '\n') continue; /* line is empty */ + if (*p == '#') continue; /* comment line */ + + q = p; + + while (*q != '\0' && (!isspace(*q)) && *q != '=') + q++; + + if (isspace(*q)) { + /* a space after the name, find next non space */ + *q++='\0'; + while( *q != '\0' && isspace((int)*q) ) q++; + } + if (*q == '\0') { + /* single command line option (ie, no name=val, just name) */ + q[-1] = '\0'; /* kill off newline from fgets() call */ + argvlen += (t = q - p) + (sizeof(" --")-1); + if (argvlen >= maxargvlen) { + maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; + argstr = realloc(argstr, maxargvlen); + if (argstr == NULL) return POPT_ERROR_MALLOC; + } + strcat(argstr, " --"); + strcat(argstr, p); + continue; + } + if (*q != '=') + continue; /* XXX for now, silently ignore bogus line */ + + /* *q is an equal sign. */ + *q++ = '\0'; + + /* find next non-space letter of value */ + while (*q != '\0' && isspace(*q)) + q++; + if (*q == '\0') + continue; /* XXX silently ignore missing value */ + + /* now, loop and strip all ending whitespace */ + x = p + linelen; + while (isspace(*--x)) + *x = 0; /* null out last char if space (including fgets() NL) */ + + /* rest of line accept */ + t = x - p; + argvlen += t + (sizeof("' --='")-1); + if (argvlen >= maxargvlen) { + maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; + argstr = realloc(argstr, maxargvlen); + if (argstr == NULL) return POPT_ERROR_MALLOC; + } + strcat(argstr, " --"); + strcat(argstr, p); + strcat(argstr, "=\""); + strcat(argstr, q); + strcat(argstr, "\""); + } - free(argv); - free(buf0); + *argstrp = argstr; return 0; } diff --git a/source4/lib/popt/system.h b/source4/lib/popt/system.h index 059c045817..000e23d484 100644 --- a/source4/lib/popt/system.h +++ b/source4/lib/popt/system.h @@ -1,6 +1,16 @@ #include "config.h" +#if defined (__GLIBC__) && defined(__LCLINT__) +/*@-declundef@*/ +/*@unchecked@*/ +extern __const __int32_t *__ctype_tolower; +/*@unchecked@*/ +extern __const __int32_t *__ctype_toupper; +/*@=declundef@*/ +#endif + #include + #include #include #include @@ -23,6 +33,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 @@ -40,7 +58,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) -- cgit