popt  1.14
popt.c
Go to the documentation of this file.
00001 
00005 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
00006    file accompanying popt source distributions, available from
00007    ftp://ftp.rpm.org/pub/rpm/dist */
00008 
00009 #undef  MYDEBUG
00010 
00011 #include "system.h"
00012 
00013 #if defined(__LCLINT__)
00014 /*@-declundef -exportheader @*/
00015 extern long long int strtoll(const char *nptr, /*@null@*/ char **endptr,
00016                 int base)
00017         /*@modifies *endptr@*/;
00018 /*@=declundef =exportheader @*/
00019 #endif
00020 
00021 #ifdef HAVE_FLOAT_H
00022 #include <float.h>
00023 #endif
00024 #include <math.h>
00025 
00026 #include "poptint.h"
00027 
00028 #ifdef  MYDEBUG
00029 /*@unchecked@*/
00030 int _popt_debug = 0;
00031 #endif
00032 
00033 #if !defined(HAVE_STRERROR) && !defined(__LCLINT__)
00034 static char * strerror(int errno)
00035 {
00036     extern int sys_nerr;
00037     extern char * sys_errlist[];
00038 
00039     if ((0 <= errno) && (errno < sys_nerr))
00040         return sys_errlist[errno];
00041     else
00042         return POPT_("unknown errno");
00043 }
00044 #endif
00045 
00046 #ifdef MYDEBUG
00047 /*@unused@*/
00048 static void prtcon(const char *msg, poptContext con)
00049 {
00050     if (msg) fprintf(stderr, "%s", msg);
00051     fprintf(stderr, "\tcon %p os %p nextCharArg \"%s\" nextArg \"%s\" argv[%d] \"%s\"\n",
00052         con, con->os,
00053         (con->os->nextCharArg ? con->os->nextCharArg : ""),
00054         (con->os->nextArg ? con->os->nextArg : ""),
00055         con->os->next,
00056         (con->os->argv && con->os->argv[con->os->next]
00057                 ? con->os->argv[con->os->next] : ""));
00058 }
00059 #endif
00060 
00061 void poptSetExecPath(poptContext con, const char * path, int allowAbsolute)
00062 {
00063     if (con == NULL) return;
00064     con->execPath = _free(con->execPath);
00065     con->execPath = xstrdup(path);
00066     con->execAbsolute = allowAbsolute;
00067     return;
00068 }
00069 
00070 static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt)
00071         /*@globals internalState@*/
00072         /*@modifies internalState@*/
00073 {
00074     if (con == NULL || opt == NULL) return;
00075     for (; opt->longName || opt->shortName || opt->arg; opt++) {
00076         poptArg arg = { .ptr = opt->arg };
00077         if (arg.ptr)
00078         switch (poptArgType(opt)) {
00079         case POPT_ARG_INCLUDE_TABLE:    /* Recurse on included sub-tables. */
00080             poptSubstituteHelpI18N(arg.opt);    /* XXX side effects */
00081             invokeCallbacksPRE(con, arg.opt);
00082             /*@switchbreak@*/ break;
00083         case POPT_ARG_CALLBACK:         /* Perform callback. */
00084             if (!CBF_ISSET(opt, PRE))
00085                 /*@switchbreak@*/ break;
00086 /*@-noeffectuncon @*/   /* XXX no known way to annotate (*vector) calls. */
00087             arg.cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip);
00088 /*@=noeffectuncon @*/
00089             /*@switchbreak@*/ break;
00090         }
00091     }
00092 }
00093 
00094 static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt)
00095         /*@globals internalState@*/
00096         /*@modifies internalState@*/
00097 {
00098     if (con == NULL || opt == NULL) return;
00099     for (; opt->longName || opt->shortName || opt->arg; opt++) {
00100         poptArg arg = { .ptr = opt->arg };
00101         if (arg.ptr)
00102         switch (poptArgType(opt)) {
00103         case POPT_ARG_INCLUDE_TABLE:    /* Recurse on included sub-tables. */
00104             poptSubstituteHelpI18N(arg.opt);    /* XXX side effects */
00105             invokeCallbacksPOST(con, arg.opt);
00106             /*@switchbreak@*/ break;
00107         case POPT_ARG_CALLBACK:         /* Perform callback. */
00108             if (!CBF_ISSET(opt, POST))
00109                 /*@switchbreak@*/ break;
00110 /*@-noeffectuncon @*/   /* XXX no known way to annotate (*vector) calls. */
00111             arg.cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip);
00112 /*@=noeffectuncon @*/
00113             /*@switchbreak@*/ break;
00114         }
00115     }
00116 }
00117 
00118 static void invokeCallbacksOPTION(poptContext con,
00119                                 const struct poptOption * opt,
00120                                 const struct poptOption * myOpt,
00121                                 /*@null@*/ const void * myData, int shorty)
00122         /*@globals internalState@*/
00123         /*@modifies internalState@*/
00124 {
00125     const struct poptOption * cbopt = NULL;
00126     poptArg cbarg = { .ptr = NULL };
00127 
00128     if (con == NULL || opt == NULL) return;
00129     for (; opt->longName || opt->shortName || opt->arg; opt++) {
00130         poptArg arg = { .ptr = opt->arg };
00131         switch (poptArgType(opt)) {
00132         case POPT_ARG_INCLUDE_TABLE:    /* Recurse on included sub-tables. */
00133             poptSubstituteHelpI18N(arg.opt);    /* XXX side effects */
00134             if (opt->arg != NULL)
00135                 invokeCallbacksOPTION(con, opt->arg, myOpt, myData, shorty);
00136             /*@switchbreak@*/ break;
00137         case POPT_ARG_CALLBACK:         /* Save callback info. */
00138             if (CBF_ISSET(opt, SKIPOPTION))
00139                 /*@switchbreak@*/ break;
00140             cbopt = opt;
00141             cbarg.ptr = opt->arg;
00142             /*@switchbreak@*/ break;
00143         default:                /* Perform callback on matching option. */
00144             if (cbopt == NULL || cbarg.cb == NULL)
00145                 /*@switchbreak@*/ break;
00146             if ((myOpt->shortName && opt->shortName && shorty &&
00147                         myOpt->shortName == opt->shortName)
00148              || (myOpt->longName != NULL && opt->longName != NULL &&
00149                         !strcmp(myOpt->longName, opt->longName)))
00150             {   const void *cbData = (cbopt->descrip ? cbopt->descrip : myData);
00151 /*@-noeffectuncon @*/   /* XXX no known way to annotate (*vector) calls. */
00152                 cbarg.cb(con, POPT_CALLBACK_REASON_OPTION,
00153                         myOpt, con->os->nextArg, cbData);
00154 /*@=noeffectuncon @*/
00155                 /* Terminate (unless explcitly continuing). */
00156                 if (!CBF_ISSET(cbopt, CONTINUE))
00157                     return;
00158             }
00159             /*@switchbreak@*/ break;
00160         }
00161     }
00162 }
00163 
00164 poptContext poptGetContext(const char * name, int argc, const char ** argv,
00165                         const struct poptOption * options, unsigned int flags)
00166 {
00167     poptContext con;
00168 
00169     if (argc < 1) return NULL;
00170 
00171     con = malloc(sizeof(*con));
00172     if (con == NULL) return NULL;       /* XXX can't happen */
00173     memset(con, 0, sizeof(*con));
00174 
00175     con->os = con->optionStack;
00176     con->os->argc = argc;
00177 /*@-dependenttrans -assignexpose@*/     /* FIX: W2DO? */
00178     con->os->argv = argv;
00179 /*@=dependenttrans =assignexpose@*/
00180     con->os->argb = NULL;
00181 
00182     if (!(flags & POPT_CONTEXT_KEEP_FIRST))
00183         con->os->next = 1;                      /* skip argv[0] */
00184 
00185     con->leftovers = calloc( (size_t)(argc + 1), sizeof(*con->leftovers) );
00186 /*@-dependenttrans -assignexpose@*/     /* FIX: W2DO? */
00187     con->options = options;
00188 /*@=dependenttrans =assignexpose@*/
00189     con->aliases = NULL;
00190     con->numAliases = 0;
00191     con->flags = flags;
00192     con->execs = NULL;
00193     con->numExecs = 0;
00194     con->finalArgvAlloced = argc * 2;
00195     con->finalArgv = calloc( (size_t)con->finalArgvAlloced, sizeof(*con->finalArgv) );
00196     if (con->finalArgv == NULL) con->finalArgvAlloced = 0;
00197     con->execAbsolute = 1;
00198     con->arg_strip = NULL;
00199 
00200     if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
00201         con->flags |= POPT_CONTEXT_POSIXMEHARDER;
00202 
00203     if (name)
00204         con->appName = xstrdup(name);
00205 
00206     invokeCallbacksPRE(con, con->options);
00207 
00208     return con;
00209 }
00210 
00211 static void cleanOSE(/*@special@*/ struct optionStackEntry *os)
00212         /*@uses os @*/
00213         /*@releases os->nextArg, os->argv, os->argb @*/
00214         /*@modifies os @*/
00215 {
00216     os->nextArg = _free(os->nextArg);
00217     os->argv = _free(os->argv);
00218     os->argb = PBM_FREE(os->argb);
00219 }
00220 
00221 void poptResetContext(poptContext con)
00222 {
00223     int i;
00224 
00225     if (con == NULL) return;
00226     while (con->os > con->optionStack) {
00227         cleanOSE(con->os--);
00228     }
00229     con->os->argb = PBM_FREE(con->os->argb);
00230     con->os->currAlias = NULL;
00231     con->os->nextCharArg = NULL;
00232     con->os->nextArg = NULL;
00233     con->os->next = 1;                  /* skip argv[0] */
00234 
00235     con->numLeftovers = 0;
00236     con->nextLeftover = 0;
00237     con->restLeftover = 0;
00238     con->doExec = NULL;
00239 
00240     if (con->finalArgv != NULL)
00241     for (i = 0; i < con->finalArgvCount; i++) {
00242 /*@-unqualifiedtrans@*/         /* FIX: typedef double indirection. */
00243         con->finalArgv[i] = _free(con->finalArgv[i]);
00244 /*@=unqualifiedtrans@*/
00245     }
00246 
00247     con->finalArgvCount = 0;
00248     con->arg_strip = PBM_FREE(con->arg_strip);
00249 /*@-nullstate@*/        /* FIX: con->finalArgv != NULL */
00250     return;
00251 /*@=nullstate@*/
00252 }
00253 
00254 /* Only one of longName, shortName should be set, not both. */
00255 static int handleExec(/*@special@*/ poptContext con,
00256                 /*@null@*/ const char * longName, char shortName)
00257         /*@uses con->execs, con->numExecs, con->flags, con->doExec,
00258                 con->finalArgv, con->finalArgvAlloced, con->finalArgvCount @*/
00259         /*@modifies con @*/
00260 {
00261     poptItem item;
00262     int i;
00263 
00264     if (con == NULL || con->execs == NULL || con->numExecs <= 0) /* XXX can't happen */
00265         return 0;
00266 
00267     for (i = con->numExecs - 1; i >= 0; i--) {
00268         item = con->execs + i;
00269         if (longName && !(item->option.longName &&
00270                         !strcmp(longName, item->option.longName)))
00271             continue;
00272         else if (shortName != item->option.shortName)
00273             continue;
00274         break;
00275     }
00276     if (i < 0) return 0;
00277 
00278 
00279     if (con->flags & POPT_CONTEXT_NO_EXEC)
00280         return 1;
00281 
00282     if (con->doExec == NULL) {
00283         con->doExec = con->execs + i;
00284         return 1;
00285     }
00286 
00287     /* We already have an exec to do; remember this option for next
00288        time 'round */
00289     if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) {
00290         con->finalArgvAlloced += 10;
00291         con->finalArgv = realloc(con->finalArgv,
00292                         sizeof(*con->finalArgv) * con->finalArgvAlloced);
00293         if (con->finalArgv == NULL) con->finalArgvCount = con->finalArgvAlloced = 0;
00294     }
00295 
00296     i = con->finalArgvCount++;
00297     if (con->finalArgv != NULL) /* XXX can't happen */
00298     {   char *s  = malloc((longName ? strlen(longName) : 0) + sizeof("--"));
00299         if (s != NULL) {        /* XXX can't happen */
00300             con->finalArgv[i] = s;
00301             *s++ = '-';
00302             if (longName)
00303                 s = stpcpy( stpcpy(s, "-"), longName);
00304             else
00305                 *s++ = shortName;
00306             *s = '\0';
00307         } else
00308             con->finalArgv[i] = NULL;
00309     }
00310 
00311     return 1;
00312 }
00313 
00314 /* Only one of longName, shortName may be set at a time */
00315 static int handleAlias(/*@special@*/ poptContext con,
00316                 /*@null@*/ const char * longName, size_t longNameLen,
00317                 char shortName,
00318                 /*@exposed@*/ /*@null@*/ const char * nextArg)
00319         /*@uses con->aliases, con->numAliases, con->optionStack, con->os,
00320                 con->os->currAlias, con->os->currAlias->option.longName @*/
00321         /*@modifies con @*/
00322 {
00323     poptItem item = (con && con->os) ? con->os->currAlias : NULL;
00324     int rc;
00325     int i;
00326 
00327     if (item) {
00328         if (longName && item->option.longName != NULL
00329          && longNameLen == strlen(item->option.longName)
00330          && !strncmp(longName, item->option.longName, longNameLen))
00331             return 0;
00332         else
00333         if (shortName && shortName == item->option.shortName)
00334             return 0;
00335     }
00336 
00337     if (con == NULL || con->aliases == NULL || con->numAliases <= 0) /* XXX can't happen */
00338         return 0;
00339 
00340     for (i = con->numAliases - 1; i >= 0; i--) {
00341         item = con->aliases + i;
00342         if (longName) {
00343             if (item->option.longName == NULL)
00344                 continue;
00345             if (longNameLen != strlen(item->option.longName))
00346                 continue;
00347             if (strncmp(longName, item->option.longName, longNameLen))
00348                 continue;
00349         } else if (shortName != item->option.shortName)
00350             continue;
00351         break;
00352     }
00353     if (i < 0) return 0;
00354 
00355     if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
00356         return POPT_ERROR_OPTSTOODEEP;
00357 
00358     if (longName == NULL && nextArg != NULL && *nextArg != '\0')
00359         con->os->nextCharArg = nextArg;
00360 
00361     con->os++;
00362     con->os->next = 0;
00363     con->os->stuffed = 0;
00364     con->os->nextArg = NULL;
00365     con->os->nextCharArg = NULL;
00366     con->os->currAlias = con->aliases + i;
00367     {   const char ** av;
00368         int ac = con->os->currAlias->argc;
00369         /* Append --foo=bar arg to alias argv array (if present). */ 
00370         if (longName && nextArg != NULL && *nextArg != '\0') {
00371             av = malloc((ac + 1 + 1) * sizeof(*av));
00372             if (av != NULL) {   /* XXX won't happen. */
00373                 for (i = 0; i < ac; i++) {
00374                     av[i] = con->os->currAlias->argv[i];
00375                 }
00376                 av[ac++] = nextArg;
00377                 av[ac] = NULL;
00378             } else      /* XXX revert to old popt behavior if malloc fails. */
00379                 av = con->os->currAlias->argv;
00380         } else
00381             av = con->os->currAlias->argv;
00382         rc = poptDupArgv(ac, av, &con->os->argc, &con->os->argv);
00383         if (av != NULL && av != con->os->currAlias->argv)
00384             free(av);
00385     }
00386     con->os->argb = NULL;
00387 
00388     return (rc ? rc : 1);
00389 }
00390 
00396 static /*@null@*/
00397 const char * findProgramPath(/*@null@*/ const char * argv0)
00398         /*@*/
00399 {
00400     char *path = NULL, *s = NULL, *se;
00401     char *t = NULL;
00402 
00403     if (argv0 == NULL) return NULL;     /* XXX can't happen */
00404 
00405     /* If there is a / in argv[0], it has to be an absolute path. */
00406     /* XXX Hmmm, why not if (argv0[0] == '/') ... instead? */
00407     if (strchr(argv0, '/'))
00408         return xstrdup(argv0);
00409 
00410     if ((path = getenv("PATH")) == NULL || (path = xstrdup(path)) == NULL)
00411         return NULL;
00412 
00413     /* The return buffer in t is big enough for any path. */
00414     if ((t = malloc(strlen(path) + strlen(argv0) + sizeof("/"))) != NULL)
00415     for (s = path; s && *s; s = se) {
00416 
00417         /* Snip PATH element into [s,se). */
00418         if ((se = strchr(s, ':')))
00419             *se++ = '\0';
00420 
00421         /* Append argv0 to PATH element. */
00422         (void) stpcpy(stpcpy(stpcpy(t, s), "/"), argv0);
00423 
00424         /* If file is executable, bingo! */
00425         if (!access(t, X_OK))
00426             break;
00427     }
00428 
00429     /* If no executable was found in PATH, return NULL. */
00430     if (!(s && *s) && t != NULL) {
00431         free(t);
00432         t = NULL;
00433     }
00434 /*@-modobserver -observertrans -usedef @*/
00435     if (path != NULL)
00436         free(path);
00437 /*@=modobserver =observertrans =usedef @*/
00438 
00439     return t;
00440 }
00441 
00442 static int execCommand(poptContext con)
00443         /*@globals internalState @*/
00444         /*@modifies internalState @*/
00445 {
00446     poptItem item = con ? con->doExec : NULL;
00447     poptArgv argv = NULL;
00448     int argc = 0;
00449     int rc;
00450     int ec = POPT_ERROR_ERRNO;
00451 
00452     if (item == NULL) /*XXX can't happen*/
00453         return POPT_ERROR_NOARG;
00454 
00455     if (item->argv == NULL || item->argc < 1 ||
00456         (!con->execAbsolute && strchr(item->argv[0], '/')))
00457             return POPT_ERROR_NOARG;
00458 
00459     argv = malloc(sizeof(*argv) *
00460                         (6 + item->argc + con->numLeftovers + con->finalArgvCount));
00461     if (argv == NULL) return POPT_ERROR_MALLOC;
00462 
00463     if (!strchr(item->argv[0], '/') && con->execPath != NULL) {
00464         char *s = malloc(strlen(con->execPath) + strlen(item->argv[0]) + sizeof("/"));
00465         if (s)
00466             (void)stpcpy(stpcpy(stpcpy(s, con->execPath), "/"), item->argv[0]);
00467 
00468         argv[argc] = s;
00469     } else
00470         argv[argc] = findProgramPath(item->argv[0]);
00471     if (argv[argc++] == NULL) {
00472         ec = POPT_ERROR_NOARG;
00473         goto exit;
00474     }
00475 
00476     if (item->argc > 1) {
00477         memcpy(argv + argc, item->argv + 1, sizeof(*argv) * (item->argc - 1));
00478         argc += (item->argc - 1);
00479     }
00480 
00481     if (con->finalArgv != NULL && con->finalArgvCount > 0) {
00482         memcpy(argv + argc, con->finalArgv,
00483                 sizeof(*argv) * con->finalArgvCount);
00484         argc += con->finalArgvCount;
00485     }
00486 
00487     if (con->leftovers != NULL && con->numLeftovers > 0) {
00488         memcpy(argv + argc, con->leftovers, sizeof(*argv) * con->numLeftovers);
00489         argc += con->numLeftovers;
00490     }
00491 
00492     argv[argc] = NULL;
00493 
00494 #if defined(hpux) || defined(__hpux)
00495     rc = setresgid(getgid(), getgid(),-1);
00496     if (rc) goto exit;
00497     rc = setresuid(getuid(), getuid(),-1);
00498     if (rc) goto exit;
00499 #else
00500 /*
00501  * XXX " ... on BSD systems setuid() should be preferred over setreuid()"
00502  * XXX  sez' Timur Bakeyev <mc@bat.ru>
00503  * XXX  from Norbert Warmuth <nwarmuth@privat.circular.de>
00504  */
00505 #if defined(HAVE_SETUID)
00506     rc = setgid(getgid());
00507     if (rc) goto exit;
00508     rc = setuid(getuid());
00509     if (rc) goto exit;
00510 #elif defined (HAVE_SETREUID)
00511     rc = setregid(getgid(), getgid());
00512     if (rc) goto exit;
00513     rc = setreuid(getuid(), getuid());
00514     if (rc) goto exit;
00515 #else
00516     ; /* Can't drop privileges */
00517 #endif
00518 #endif
00519 
00520 #ifdef  MYDEBUG
00521 if (_popt_debug)
00522     {   poptArgv avp;
00523         fprintf(stderr, "==> execvp(%s) argv[%d]:", argv[0], argc);
00524         for (avp = argv; *avp; avp++)
00525             fprintf(stderr, " '%s'", *avp);
00526         fprintf(stderr, "\n");
00527     }
00528 #endif
00529 
00530 /*@-nullstate@*/
00531     rc = execvp(argv[0], (char *const *)argv);
00532 /*@=nullstate@*/
00533 
00534 exit:
00535     if (argv) {
00536         if (argv[0])
00537             free((void *)argv[0]);
00538         free(argv);
00539     }
00540     return ec;
00541 }
00542 
00543 /*@observer@*/ /*@null@*/ static const struct poptOption *
00544 findOption(const struct poptOption * opt,
00545                 /*@null@*/ const char * longName, size_t longNameLen,
00546                 char shortName,
00547                 /*@null@*/ /*@out@*/ poptCallbackType * callback,
00548                 /*@null@*/ /*@out@*/ const void ** callbackData,
00549                 int singleDash)
00550         /*@modifies *callback, *callbackData */
00551 {
00552     const struct poptOption * cb = NULL;
00553     poptArg cbarg = { .ptr = NULL };
00554 
00555     /* This happens when a single - is given */
00556     if (singleDash && !shortName && (longName && *longName == '\0'))
00557         shortName = '-';
00558 
00559     for (; opt->longName || opt->shortName || opt->arg; opt++) {
00560         poptArg arg = { .ptr = opt->arg };
00561 
00562         if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) {
00563             const struct poptOption * opt2;
00564 
00565             poptSubstituteHelpI18N(arg.opt);    /* XXX side effects */
00566             /* Recurse on included sub-tables. */
00567             if (arg.ptr == NULL) continue;      /* XXX program error */
00568             opt2 = findOption(arg.opt, longName, longNameLen, shortName, callback,
00569                               callbackData, singleDash);
00570             if (opt2 == NULL) continue;
00571             /* Sub-table data will be inheirited if no data yet. */
00572             if (!(callback && *callback)) return opt2;
00573             if (!(callbackData && *callbackData == NULL)) return opt2;
00574 /*@-observertrans -dependenttrans @*/
00575             *callbackData = opt->descrip;
00576 /*@=observertrans =dependenttrans @*/
00577             return opt2;
00578         } else if (poptArgType(opt) == POPT_ARG_CALLBACK) {
00579             cb = opt;
00580             cbarg.ptr = opt->arg;
00581         } else if (longName != NULL && opt->longName != NULL &&
00582                    (!singleDash || F_ISSET(opt, ONEDASH)) &&
00583                    (!strncmp(longName, opt->longName, longNameLen) && strlen(opt->longName) == longNameLen))
00584         {
00585             break;
00586         } else if (shortName && shortName == opt->shortName) {
00587             break;
00588         }
00589     }
00590 
00591     if (opt->longName == NULL && !opt->shortName)
00592         return NULL;
00593 
00594 /*@-modobserver -mods @*/
00595     if (callback)
00596         *callback = (cb ? cbarg.cb : NULL);
00597     if (callbackData)
00598 /*@-observertrans@*/    /* FIX: typedef double indirection. */
00599         *callbackData = (cb && !CBF_ISSET(cb, INC_DATA) ? cb->descrip : NULL);
00600 /*@=observertrans@*/
00601 /*@=modobserver =mods @*/
00602 
00603     return opt;
00604 }
00605 
00606 static const char * findNextArg(/*@special@*/ poptContext con,
00607                 unsigned argx, int delete_arg)
00608         /*@uses con->optionStack, con->os,
00609                 con->os->next, con->os->argb, con->os->argc, con->os->argv @*/
00610         /*@modifies con @*/
00611 {
00612     struct optionStackEntry * os = con ? con->os : NULL;
00613     const char * arg;
00614 
00615     if (os == NULL || con->optionStack == NULL) return NULL;
00616 
00617     do {
00618         int i;
00619         arg = NULL;
00620         while (os->next == os->argc && os > con->optionStack) os--;
00621         if (os->next == os->argc && os == con->optionStack) break;
00622         if (os->argv != NULL)
00623         for (i = os->next; i < os->argc; i++) {
00624 /*@-sizeoftype@*/
00625             if (os->argb && PBM_ISSET(i, os->argb))
00626                 /*@innercontinue@*/ continue;
00627             if (*os->argv[i] == '-')
00628                 /*@innercontinue@*/ continue;
00629             if (--argx > 0)
00630                 /*@innercontinue@*/ continue;
00631             arg = os->argv[i];
00632             if (delete_arg) {
00633                 if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc);
00634                 if (os->argb != NULL)   /* XXX can't happen */
00635                     PBM_SET(i, os->argb);
00636             }
00637             /*@innerbreak@*/ break;
00638 /*@=sizeoftype@*/
00639         }
00640         if (os > con->optionStack) os--;
00641     } while (arg == NULL);
00642     return arg;
00643 }
00644 
00645 static /*@only@*/ /*@null@*/ const char *
00646 expandNextArg(/*@special@*/ poptContext con, const char * s)
00647         /*@uses con->optionStack, con->os,
00648                 con->os->next, con->os->argb, con->os->argc, con->os->argv @*/
00649         /*@modifies con @*/
00650 {
00651     const char * a = NULL;
00652     char *t, *te;
00653     size_t tn = strlen(s) + 1;
00654     char c;
00655 
00656     if (con == NULL) return NULL;
00657 
00658     te = t = malloc(tn);
00659     if (t == NULL) return NULL;         /* XXX can't happen */
00660     *t = '\0';
00661     while ((c = *s++) != '\0') {
00662         switch (c) {
00663 #if 0   /* XXX can't do this */
00664         case '\\':      /* escape */
00665             c = *s++;
00666             /*@switchbreak@*/ break;
00667 #endif
00668         case '!':
00669             if (!(s[0] == '#' && s[1] == ':' && s[2] == '+'))
00670                 /*@switchbreak@*/ break;
00671             /* XXX Make sure that findNextArg deletes only next arg. */
00672             if (a == NULL) {
00673                 if ((a = findNextArg(con, 1U, 1)) == NULL)
00674                     /*@switchbreak@*/ break;
00675             }
00676             s += 3;
00677 
00678             tn += strlen(a);
00679             {   size_t pos = (size_t) (te - t);
00680                 t = realloc(t, tn);
00681                 if (t == NULL) return NULL;
00682                 te = stpcpy(t + pos, a);
00683             }
00684             continue;
00685             /*@notreached@*/ /*@switchbreak@*/ break;
00686         default:
00687             /*@switchbreak@*/ break;
00688         }
00689         *te++ = c;
00690     }
00691     *te++ = '\0';
00692     /* If the new string is longer than needed, shorten. */
00693     if ((t + tn) > te) {
00694 /*@-usereleased@*/      /* XXX splint can't follow the pointers. */
00695         if ((te = realloc(t, (size_t)(te - t))) == NULL)
00696             free(t);
00697         t = te;
00698 /*@=usereleased@*/
00699     }
00700     return t;
00701 }
00702 
00703 static void poptStripArg(/*@special@*/ poptContext con, int which)
00704         /*@uses con->optionStack @*/
00705         /*@defines con->arg_strip @*/
00706         /*@modifies con @*/
00707 {
00708 /*@-compdef -sizeoftype -usedef @*/
00709     if (con->arg_strip == NULL)
00710         con->arg_strip = PBM_ALLOC(con->optionStack[0].argc);
00711     if (con->arg_strip != NULL)         /* XXX can't happen */
00712     PBM_SET(which, con->arg_strip);
00713     return;
00714 /*@=compdef =sizeoftype =usedef @*/
00715 }
00716 
00717 int poptSaveString(const char *** argvp,
00718                 /*@unused@*/ UNUSED(unsigned int argInfo), const char * val)
00719 {
00720     int argc = 0;
00721 
00722     if (argvp == NULL)
00723         return -1;
00724 
00725     /* XXX likely needs an upper bound on argc. */
00726     if (*argvp != NULL)
00727     while ((*argvp)[argc] != NULL)
00728         argc++;
00729  
00730 /*@-unqualifiedtrans -nullstate@*/      /* XXX no annotation for (*argvp) */
00731     if ((*argvp = xrealloc(*argvp, (argc + 1 + 1) * sizeof(**argvp))) != NULL) {
00732         (*argvp)[argc++] = xstrdup(val);
00733         (*argvp)[argc  ] = NULL;
00734     }
00735     return 0;
00736 /*@=unqualifiedtrans =nullstate@*/
00737 }
00738 
00739 /*@unchecked@*/
00740 static unsigned int seed = 0;
00741 
00742 int poptSaveLongLong(long long * arg, unsigned int argInfo, long long aLongLong)
00743 {
00744     if (arg == NULL
00745 #ifdef  NOTYET
00746     /* XXX Check alignment, may fail on funky platforms. */
00747      || (((unsigned long long)arg) & (sizeof(*arg)-1))
00748 #endif
00749     )
00750         return POPT_ERROR_NULLARG;
00751 
00752     if (aLongLong != 0 && LF_ISSET(RANDOM)) {
00753         if (!seed) {
00754             srandom((unsigned)getpid());
00755             srandom((unsigned)random());
00756         }
00757         aLongLong = (long long)(random() % (aLongLong > 0 ? aLongLong : -aLongLong));
00758         aLongLong++;
00759     }
00760     if (LF_ISSET(NOT))
00761         aLongLong = ~aLongLong;
00762     switch (LF_ISSET(LOGICALOPS)) {
00763     case 0:
00764         *arg = aLongLong;
00765         break;
00766     case POPT_ARGFLAG_OR:
00767         *(unsigned long long *)arg |= (unsigned long long)aLongLong;
00768         break;
00769     case POPT_ARGFLAG_AND:
00770         *(unsigned long long *)arg &= (unsigned long long)aLongLong;
00771         break;
00772     case POPT_ARGFLAG_XOR:
00773         *(unsigned long long *)arg ^= (unsigned long long)aLongLong;
00774         break;
00775     default:
00776         return POPT_ERROR_BADOPERATION;
00777         /*@notreached@*/ break;
00778     }
00779     return 0;
00780 }
00781 
00782 int poptSaveLong(long * arg, unsigned int argInfo, long aLong)
00783 {
00784     /* XXX Check alignment, may fail on funky platforms. */
00785     if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
00786         return POPT_ERROR_NULLARG;
00787 
00788     if (aLong != 0 && LF_ISSET(RANDOM)) {
00789         if (!seed) {
00790             srandom((unsigned)getpid());
00791             srandom((unsigned)random());
00792         }
00793         aLong = random() % (aLong > 0 ? aLong : -aLong);
00794         aLong++;
00795     }
00796     if (LF_ISSET(NOT))
00797         aLong = ~aLong;
00798     switch (LF_ISSET(LOGICALOPS)) {
00799     case 0:
00800         *arg = aLong;
00801         break;
00802     case POPT_ARGFLAG_OR:
00803         *(unsigned long *)arg |= (unsigned long)aLong;
00804         break;
00805     case POPT_ARGFLAG_AND:
00806         *(unsigned long *)arg &= (unsigned long)aLong;
00807         break;
00808     case POPT_ARGFLAG_XOR:
00809         *(unsigned long *)arg ^= (unsigned long)aLong;
00810         break;
00811     default:
00812         return POPT_ERROR_BADOPERATION;
00813         /*@notreached@*/ break;
00814     }
00815     return 0;
00816 }
00817 
00818 int poptSaveInt(/*@null@*/ int * arg, unsigned int argInfo, long aLong)
00819 {
00820     /* XXX Check alignment, may fail on funky platforms. */
00821     if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
00822         return POPT_ERROR_NULLARG;
00823 
00824     if (aLong != 0 && LF_ISSET(RANDOM)) {
00825         if (!seed) {
00826             srandom((unsigned)getpid());
00827             srandom((unsigned)random());
00828         }
00829         aLong = random() % (aLong > 0 ? aLong : -aLong);
00830         aLong++;
00831     }
00832     if (LF_ISSET(NOT))
00833         aLong = ~aLong;
00834     switch (LF_ISSET(LOGICALOPS)) {
00835     case 0:
00836         *arg = (int) aLong;
00837         break;
00838     case POPT_ARGFLAG_OR:
00839         *(unsigned int *)arg |= (unsigned int) aLong;
00840         break;
00841     case POPT_ARGFLAG_AND:
00842         *(unsigned int *)arg &= (unsigned int) aLong;
00843         break;
00844     case POPT_ARGFLAG_XOR:
00845         *(unsigned int *)arg ^= (unsigned int) aLong;
00846         break;
00847     default:
00848         return POPT_ERROR_BADOPERATION;
00849         /*@notreached@*/ break;
00850     }
00851     return 0;
00852 }
00853 
00854 /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
00855 int poptGetNextOpt(poptContext con)
00856 {
00857     const struct poptOption * opt = NULL;
00858     int done = 0;
00859 
00860     if (con == NULL)
00861         return -1;
00862     while (!done) {
00863         const char * origOptString = NULL;
00864         poptCallbackType cb = NULL;
00865         const void * cbData = NULL;
00866         const char * longArg = NULL;
00867         int canstrip = 0;
00868         int shorty = 0;
00869 
00870         while (!con->os->nextCharArg && con->os->next == con->os->argc
00871                 && con->os > con->optionStack) {
00872             cleanOSE(con->os--);
00873         }
00874         if (!con->os->nextCharArg && con->os->next == con->os->argc) {
00875             invokeCallbacksPOST(con, con->options);
00876 
00877             if (con->maincall) {
00878                 /*@-noeffectuncon @*/
00879                 (void) (*con->maincall) (con->finalArgvCount, con->finalArgv);
00880                 /*@=noeffectuncon @*/
00881                 return -1;
00882             }
00883 
00884             if (con->doExec) return execCommand(con);
00885             return -1;
00886         }
00887 
00888         /* Process next long option */
00889         if (!con->os->nextCharArg) {
00890             const char * optString;
00891             size_t optStringLen;
00892             int thisopt;
00893 
00894 /*@-sizeoftype@*/
00895             if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) {
00896                 con->os->next++;
00897                 continue;
00898             }
00899 /*@=sizeoftype@*/
00900             thisopt = con->os->next;
00901             if (con->os->argv != NULL)  /* XXX can't happen */
00902             origOptString = con->os->argv[con->os->next++];
00903 
00904             if (origOptString == NULL)  /* XXX can't happen */
00905                 return POPT_ERROR_BADOPT;
00906 
00907             if (con->restLeftover || *origOptString != '-' ||
00908                 (*origOptString == '-' && origOptString[1] == '\0'))
00909             {
00910                 if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
00911                     con->restLeftover = 1;
00912                 if (con->flags & POPT_CONTEXT_ARG_OPTS) {
00913                     con->os->nextArg = xstrdup(origOptString);
00914                     return 0;
00915                 }
00916                 if (con->leftovers != NULL)     /* XXX can't happen */
00917                     con->leftovers[con->numLeftovers++] = origOptString;
00918                 continue;
00919             }
00920 
00921             /* Make a copy we can hack at */
00922             optString = origOptString;
00923 
00924             if (optString[0] == '\0')
00925                 return POPT_ERROR_BADOPT;
00926 
00927             if (optString[1] == '-' && !optString[2]) {
00928                 con->restLeftover = 1;
00929                 continue;
00930             } else {
00931                 const char *oe;
00932                 int singleDash;
00933 
00934                 optString++;
00935                 if (*optString == '-')
00936                     singleDash = 0, optString++;
00937                 else
00938                     singleDash = 1;
00939 
00940                 /* Check for "--long=arg" option. */
00941                 for (oe = optString; *oe && *oe != '='; oe++)
00942                     {};
00943                 optStringLen = (size_t)(oe - optString);
00944                 if (*oe == '=')
00945                     longArg = oe + 1;
00946 
00947                 /* XXX aliases with arg substitution need "--alias=arg" */
00948                 if (handleAlias(con, optString, optStringLen, '\0', longArg)) {
00949                     longArg = NULL;
00950                     continue;
00951                 }
00952 
00953                 if (handleExec(con, optString, '\0'))
00954                     continue;
00955 
00956                 opt = findOption(con->options, optString, optStringLen, '\0', &cb, &cbData,
00957                                  singleDash);
00958                 if (!opt && !singleDash)
00959                     return POPT_ERROR_BADOPT;
00960             }
00961 
00962             if (!opt) {
00963                 con->os->nextCharArg = origOptString + 1;
00964                 longArg = NULL;
00965             } else {
00966                 if (con->os == con->optionStack && F_ISSET(opt, STRIP))
00967                 {
00968                     canstrip = 1;
00969                     poptStripArg(con, thisopt);
00970                 }
00971                 shorty = 0;
00972             }
00973         }
00974 
00975         /* Process next short option */
00976         if (con->os->nextCharArg) {
00977             origOptString = con->os->nextCharArg;
00978 
00979             con->os->nextCharArg = NULL;
00980 
00981             if (handleAlias(con, NULL, 0, *origOptString, origOptString + 1))
00982                 continue;
00983 
00984             if (handleExec(con, NULL, *origOptString)) {
00985                 /* Restore rest of short options for further processing */
00986                 origOptString++;
00987                 if (*origOptString != '\0')
00988                     con->os->nextCharArg = origOptString;
00989                 continue;
00990             }
00991 
00992             opt = findOption(con->options, NULL, 0, *origOptString, &cb,
00993                              &cbData, 0);
00994             if (!opt)
00995                 return POPT_ERROR_BADOPT;
00996             shorty = 1;
00997 
00998             origOptString++;
00999             if (*origOptString != '\0')
01000                 con->os->nextCharArg = origOptString + (int)(*origOptString == '=');
01001         }
01002 
01003         if (opt == NULL) return POPT_ERROR_BADOPT;      /* XXX can't happen */
01004         if (opt->arg && poptArgType(opt) == POPT_ARG_NONE) {
01005             if (poptSaveInt((int *)opt->arg, opt->argInfo, 1L))
01006                 return POPT_ERROR_BADOPERATION;
01007         } else if (poptArgType(opt) == POPT_ARG_VAL) {
01008             if (opt->arg) {
01009                 if (poptSaveInt((int *)opt->arg, opt->argInfo, (long)opt->val))
01010                     return POPT_ERROR_BADOPERATION;
01011             }
01012         } else if (poptArgType(opt) != POPT_ARG_NONE) {
01013             con->os->nextArg = _free(con->os->nextArg);
01014             if (longArg) {
01015                 longArg = expandNextArg(con, longArg);
01016                 con->os->nextArg = (char *) longArg;
01017             } else if (con->os->nextCharArg) {
01018                 longArg = expandNextArg(con, con->os->nextCharArg);
01019                 con->os->nextArg = (char *) longArg;
01020                 con->os->nextCharArg = NULL;
01021             } else {
01022                 while (con->os->next == con->os->argc &&
01023                         con->os > con->optionStack)
01024                 {
01025                     cleanOSE(con->os--);
01026                 }
01027                 if (con->os->next == con->os->argc) {
01028                     if (!F_ISSET(opt, OPTIONAL))
01029                         return POPT_ERROR_NOARG;
01030                     con->os->nextArg = NULL;
01031                 } else {
01032 
01033                     /*
01034                      * Make sure this isn't part of a short arg or the
01035                      * result of an alias expansion.
01036                      */
01037                     if (con->os == con->optionStack
01038                      && F_ISSET(opt, STRIP) && canstrip)
01039                     {
01040                         poptStripArg(con, con->os->next);
01041                     }
01042                 
01043                     if (con->os->argv != NULL) {        /* XXX can't happen */
01044                         if (F_ISSET(opt, OPTIONAL) &&
01045                             con->os->argv[con->os->next][0] == '-') {
01046                             con->os->nextArg = NULL;
01047                         } else {
01048                             /* XXX watchout: subtle side-effects live here. */
01049                             longArg = con->os->argv[con->os->next++];
01050                             longArg = expandNextArg(con, longArg);
01051                             con->os->nextArg = (char *) longArg;
01052                         }
01053                     }
01054                 }
01055             }
01056             longArg = NULL;
01057 
01058             if (opt->arg) {
01059                 poptArg arg = { .ptr = opt->arg };
01060                 switch (poptArgType(opt)) {
01061                 case POPT_ARG_ARGV:
01062                     /* XXX memory leak, application is responsible for free. */
01063                     if (con->os->nextArg == NULL)
01064                         return POPT_ERROR_NULLARG;      /* XXX better return? */
01065                     if (poptSaveString(arg.ptr, opt->argInfo, con->os->nextArg))
01066                         return POPT_ERROR_BADOPERATION;
01067                     /*@switchbreak@*/ break;
01068                 case POPT_ARG_STRING:
01069                     /* XXX memory leak, application is responsible for free. */
01070                     arg.argv[0] = (con->os->nextArg)
01071                         ? xstrdup(con->os->nextArg) : NULL;
01072                     /*@switchbreak@*/ break;
01073 
01074                 case POPT_ARG_INT:
01075                 case POPT_ARG_LONG:
01076                 case POPT_ARG_LONGLONG:
01077                 {   long long aNUM = 0;
01078                     char *end = NULL;
01079 
01080                     if (con->os->nextArg) {
01081                         aNUM = strtoll(con->os->nextArg, &end, 0);
01082                         if (!(end && *end == '\0'))
01083                             return POPT_ERROR_BADNUMBER;
01084                     }
01085 
01086 /* XXX let's not demand C99 compiler flags for <limits.h> quite yet. */
01087 #if !defined(LLONG_MAX)
01088 #   define LLONG_MAX    9223372036854775807LL
01089 #   define LLONG_MIN    (-LLONG_MAX - 1LL)
01090 #endif
01091 
01092                     if (poptArgType(opt) == POPT_ARG_LONGLONG) {
01093                         if (aNUM == LLONG_MAX || aNUM == LLONG_MIN)
01094                             return POPT_ERROR_OVERFLOW;
01095                         if (poptSaveLongLong(arg.longlongp, opt->argInfo, aNUM))
01096                             return POPT_ERROR_BADOPERATION;
01097                     } else
01098                     if (poptArgType(opt) == POPT_ARG_LONG) {
01099                         if (aNUM > (long long)LONG_MAX || aNUM < (long long)LONG_MIN)
01100                             return POPT_ERROR_OVERFLOW;
01101                         if (poptSaveLong(arg.longp, opt->argInfo, (long)aNUM))
01102                             return POPT_ERROR_BADOPERATION;
01103                     } else
01104                     if (poptArgType(opt) == POPT_ARG_INT) {
01105                         if (aNUM > (long long)INT_MAX || aNUM < (long long)INT_MIN)
01106                             return POPT_ERROR_OVERFLOW;
01107                         if (poptSaveInt(arg.intp, opt->argInfo, (long)aNUM))
01108                             return POPT_ERROR_BADOPERATION;
01109                     } else
01110                         return POPT_ERROR_BADOPERATION;
01111                 }   /*@switchbreak@*/ break;
01112 
01113                 case POPT_ARG_FLOAT:
01114                 case POPT_ARG_DOUBLE:
01115                 {   double aDouble = 0.0;
01116                     char *end;
01117 
01118                     if (con->os->nextArg) {
01119 /*@-mods@*/
01120                         int saveerrno = errno;
01121                         errno = 0;
01122                         aDouble = strtod(con->os->nextArg, &end);
01123                         if (errno == ERANGE)
01124                             return POPT_ERROR_OVERFLOW;
01125                         errno = saveerrno;
01126 /*@=mods@*/
01127                         if (*end != '\0')
01128                             return POPT_ERROR_BADNUMBER;
01129                     }
01130 
01131                     if (poptArgType(opt) == POPT_ARG_DOUBLE) {
01132                         arg.doublep[0] = aDouble;
01133                     } else {
01134 #if !defined(DBL_EPSILON) && !defined(__LCLINT__)
01135 #define DBL_EPSILON 2.2204460492503131e-16
01136 #endif
01137 #define POPT_ABS(a)     ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
01138                         if ((POPT_ABS(aDouble) - FLT_MAX) > DBL_EPSILON)
01139                             return POPT_ERROR_OVERFLOW;
01140                         if ((FLT_MIN - POPT_ABS(aDouble)) > DBL_EPSILON)
01141                             return POPT_ERROR_OVERFLOW;
01142                         arg.floatp[0] = (float) aDouble;
01143                     }
01144                 }   /*@switchbreak@*/ break;
01145                 case POPT_ARG_MAINCALL:
01146 /*@-type@*/
01147                     con->maincall = opt->arg;
01148 /*@=type@*/
01149                     /*@switchbreak@*/ break;
01150                 default:
01151                     fprintf(stdout,
01152                         POPT_("option type (%u) not implemented in popt\n"),
01153                         poptArgType(opt));
01154                     exit(EXIT_FAILURE);
01155                     /*@notreached@*/ /*@switchbreak@*/ break;
01156                 }
01157             }
01158         }
01159 
01160         if (cb)
01161             invokeCallbacksOPTION(con, con->options, opt, cbData, shorty);
01162         else if (opt->val && (poptArgType(opt) != POPT_ARG_VAL))
01163             done = 1;
01164 
01165         if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
01166             con->finalArgvAlloced += 10;
01167             con->finalArgv = realloc(con->finalArgv,
01168                             sizeof(*con->finalArgv) * con->finalArgvAlloced);
01169             if (con->finalArgv == NULL) con->finalArgvCount = con->finalArgvAlloced = 0;
01170         }
01171 
01172         if (con->finalArgv != NULL)
01173         {   char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + sizeof("--"));
01174             if (s != NULL) {    /* XXX can't happen */
01175                 con->finalArgv[con->finalArgvCount++] = s;
01176                 *s++ = '-';
01177                 if (opt->longName) {
01178                     if (!F_ISSET(opt, ONEDASH))
01179                         *s++ = '-';
01180                     s = stpcpy(s, opt->longName);
01181                 } else {
01182                     *s++ = opt->shortName;
01183                     *s = '\0';
01184                 }
01185             } else
01186                 con->finalArgv[con->finalArgvCount++] = NULL;
01187         }
01188 
01189         if (opt->arg && poptArgType(opt) == POPT_ARG_NONE)
01190             /*@-ifempty@*/ ; /*@=ifempty@*/
01191         else if (poptArgType(opt) == POPT_ARG_VAL)
01192             /*@-ifempty@*/ ; /*@=ifempty@*/
01193         else if (poptArgType(opt) != POPT_ARG_NONE) {
01194             if (con->finalArgv != NULL && con->os->nextArg != NULL)
01195                 con->finalArgv[con->finalArgvCount++] =
01196                         xstrdup(con->os->nextArg);
01197         }
01198     }
01199 
01200     return (opt ? opt->val : -1);       /* XXX can't happen */
01201 }
01202 
01203 char * poptGetOptArg(poptContext con)
01204 {
01205     char * ret = NULL;
01206     if (con) {
01207         ret = con->os->nextArg;
01208         con->os->nextArg = NULL;
01209     }
01210     return ret;
01211 }
01212 
01213 const char * poptGetArg(poptContext con)
01214 {
01215     const char * ret = NULL;
01216     if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers)
01217         ret = con->leftovers[con->nextLeftover++];
01218     return ret;
01219 }
01220 
01221 const char * poptPeekArg(poptContext con)
01222 {
01223     const char * ret = NULL;
01224     if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers)
01225         ret = con->leftovers[con->nextLeftover];
01226     return ret;
01227 }
01228 
01229 const char ** poptGetArgs(poptContext con)
01230 {
01231     if (con == NULL ||
01232         con->leftovers == NULL || con->numLeftovers == con->nextLeftover)
01233         return NULL;
01234 
01235     /* some apps like [like RPM ;-) ] need this NULL terminated */
01236     con->leftovers[con->numLeftovers] = NULL;
01237 
01238 /*@-nullret -nullstate @*/      /* FIX: typedef double indirection. */
01239     return (con->leftovers + con->nextLeftover);
01240 /*@=nullret =nullstate @*/
01241 }
01242 
01243 static /*@null@*/
01244 poptItem poptFreeItems(/*@only@*/ /*@null@*/ poptItem items, int nitems)
01245         /*@modifies items @*/
01246 {
01247     if (items != NULL) {
01248         poptItem item = items;
01249         while (--nitems >= 0) {
01250 /*@-modobserver -observertrans -dependenttrans@*/
01251             item->option.longName = _free(item->option.longName);
01252             item->option.descrip = _free(item->option.descrip);
01253             item->option.argDescrip = _free(item->option.argDescrip);
01254 /*@=modobserver =observertrans =dependenttrans@*/
01255             item->argv = _free(item->argv);
01256             item++;
01257         }
01258         items = _free(items);
01259     }
01260     return NULL;
01261 }
01262 
01263 poptContext poptFreeContext(poptContext con)
01264 {
01265     if (con == NULL) return con;
01266     poptResetContext(con);
01267     con->os->argb = _free(con->os->argb);
01268 
01269     con->aliases = poptFreeItems(con->aliases, con->numAliases);
01270     con->numAliases = 0;
01271 
01272     con->execs = poptFreeItems(con->execs, con->numExecs);
01273     con->numExecs = 0;
01274 
01275     con->leftovers = _free(con->leftovers);
01276     con->finalArgv = _free(con->finalArgv);
01277     con->appName = _free(con->appName);
01278     con->otherHelp = _free(con->otherHelp);
01279     con->execPath = _free(con->execPath);
01280     con->arg_strip = PBM_FREE(con->arg_strip);
01281     
01282     con = _free(con);
01283     return con;
01284 }
01285 
01286 int poptAddAlias(poptContext con, struct poptAlias alias,
01287                 /*@unused@*/ UNUSED(int flags))
01288 {
01289     struct poptItem_s item_buf;
01290     poptItem item = &item_buf;
01291 
01292     if (con == NULL) return 1;
01293 
01294     memset(item, 0, sizeof(*item));
01295     item->option.longName = alias.longName;
01296     item->option.shortName = alias.shortName;
01297     item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
01298     item->option.arg = 0;
01299     item->option.val = 0;
01300     item->option.descrip = NULL;
01301     item->option.argDescrip = NULL;
01302     item->argc = alias.argc;
01303     item->argv = alias.argv;
01304     return poptAddItem(con, item, 0);
01305 }
01306 
01307 int poptAddItem(poptContext con, poptItem newItem, int flags)
01308 {
01309     poptItem * items, item;
01310     int * nitems;
01311 
01312     if (con == NULL) return 1;
01313 
01314     switch (flags) {
01315     case 1:
01316         items = &con->execs;
01317         nitems = &con->numExecs;
01318         break;
01319     case 0:
01320         items = &con->aliases;
01321         nitems = &con->numAliases;
01322         break;
01323     default:
01324         return 1;
01325         /*@notreached@*/ break;
01326     }
01327 
01328     *items = realloc((*items), ((*nitems) + 1) * sizeof(**items));
01329     if ((*items) == NULL)
01330         return 1;
01331 
01332     item = (*items) + (*nitems);
01333 
01334     item->option.longName =
01335         (newItem->option.longName ? xstrdup(newItem->option.longName) : NULL);
01336     item->option.shortName = newItem->option.shortName;
01337     item->option.argInfo = newItem->option.argInfo;
01338     item->option.arg = newItem->option.arg;
01339     item->option.val = newItem->option.val;
01340     item->option.descrip =
01341         (newItem->option.descrip ? xstrdup(newItem->option.descrip) : NULL);
01342     item->option.argDescrip =
01343        (newItem->option.argDescrip ? xstrdup(newItem->option.argDescrip) : NULL);
01344     item->argc = newItem->argc;
01345     item->argv = newItem->argv;
01346 
01347     (*nitems)++;
01348 
01349     return 0;
01350 }
01351 
01352 const char * poptBadOption(poptContext con, unsigned int flags)
01353 {
01354     struct optionStackEntry * os;
01355 
01356     if (!con)
01357         return NULL;
01358 
01359     os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os;
01360     if (!os)
01361         return NULL;
01362 
01363     if (con->doExec && con->doExec->argv && !os->nextCharArg && os->next == os->argc)
01364         return con->doExec->argv[0];
01365 
01366     return ((os->argv && (os->next > 0)) ? os->argv[os->next - 1] : NULL);
01367 }
01368 
01369 const char * poptStrerror(const int error)
01370 {
01371     switch (error) {
01372       case POPT_ERROR_NOARG:
01373         return POPT_("missing argument");
01374       case POPT_ERROR_BADOPT:
01375         return POPT_("unknown option");
01376       case POPT_ERROR_BADOPERATION:
01377         return POPT_("mutually exclusive logical operations requested");
01378       case POPT_ERROR_NULLARG:
01379         return POPT_("opt->arg should not be NULL");
01380       case POPT_ERROR_OPTSTOODEEP:
01381         return POPT_("aliases nested too deeply");
01382       case POPT_ERROR_BADQUOTE:
01383         return POPT_("error in parameter quoting");
01384       case POPT_ERROR_BADNUMBER:
01385         return POPT_("invalid numeric value");
01386       case POPT_ERROR_OVERFLOW:
01387         return POPT_("number too large or too small");
01388       case POPT_ERROR_MALLOC:
01389         return POPT_("memory allocation failed");
01390       case POPT_ERROR_ERRNO:
01391         return strerror(errno);
01392       case POPT_ERROR_NOCONTEXT:
01393         return POPT_("no context");
01394       default:
01395         return POPT_("unknown error");
01396     }
01397 }
01398 
01399 int poptStuffArgs(poptContext con, const char ** argv)
01400 {
01401     int argc;
01402     int rc;
01403 
01404     if (con == NULL)
01405         return POPT_ERROR_NOCONTEXT;
01406 
01407     if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
01408         return POPT_ERROR_OPTSTOODEEP;
01409 
01410     for (argc = 0; argv[argc]; argc++)
01411         {};
01412 
01413     con->os++;
01414     con->os->next = 0;
01415     con->os->nextArg = NULL;
01416     con->os->nextCharArg = NULL;
01417     con->os->currAlias = NULL;
01418     rc = poptDupArgv(argc, argv, &con->os->argc, &con->os->argv);
01419     con->os->argb = NULL;
01420     con->os->stuffed = 1;
01421 
01422     return rc;
01423 }
01424 
01425 const char * poptGetInvocationName(poptContext con)
01426 {
01427     return ((con && con->os->argv) ? con->os->argv[0] : "");
01428 }
01429 
01430 int poptStrippedArgv(poptContext con, int argc, char ** argv)
01431 {
01432     int numargs = argc;
01433     int j = 1;
01434     int i;
01435     
01436 /*@-sizeoftype@*/
01437     if (con && con->arg_strip)
01438     for (i = 1; i < argc; i++) {
01439         if (PBM_ISSET(i, con->arg_strip))
01440             numargs--;
01441     }
01442     
01443     for (i = 1; i < argc; i++) {
01444         if (con && con->arg_strip && PBM_ISSET(i, con->arg_strip))
01445             continue;
01446         argv[j] = (j < numargs) ? argv[i] : NULL;
01447         j++;
01448     }
01449 /*@=sizeoftype@*/
01450     
01451     return numargs;
01452 }

Generated for popt by  doxygen 1.7.6.1