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