popt
1.16
|
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 /*@unchecked@*/ 00034 unsigned int _poptArgMask = POPT_ARG_MASK; 00035 /*@unchecked@*/ 00036 unsigned int _poptGroupMask = POPT_GROUP_MASK; 00037 00038 #if !defined(HAVE_STRERROR) && !defined(__LCLINT__) 00039 static char * strerror(int errno) 00040 { 00041 extern int sys_nerr; 00042 extern char * sys_errlist[]; 00043 00044 if ((0 <= errno) && (errno < sys_nerr)) 00045 return sys_errlist[errno]; 00046 else 00047 return POPT_("unknown errno"); 00048 } 00049 #endif 00050 00051 #ifdef MYDEBUG 00052 /*@unused@*/ 00053 static void prtcon(const char *msg, poptContext con) 00054 { 00055 if (msg) fprintf(stderr, "%s", msg); 00056 fprintf(stderr, "\tcon %p os %p nextCharArg \"%s\" nextArg \"%s\" argv[%d] \"%s\"\n", 00057 con, con->os, 00058 (con->os->nextCharArg ? con->os->nextCharArg : ""), 00059 (con->os->nextArg ? con->os->nextArg : ""), 00060 con->os->next, 00061 (con->os->argv && con->os->argv[con->os->next] 00062 ? con->os->argv[con->os->next] : "")); 00063 } 00064 #endif 00065 00066 void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) 00067 { 00068 if (con == NULL) return; 00069 con->execPath = _free(con->execPath); 00070 con->execPath = xstrdup(path); 00071 con->execAbsolute = allowAbsolute; 00072 return; 00073 } 00074 00075 static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt) 00076 /*@globals internalState@*/ 00077 /*@modifies internalState@*/ 00078 { 00079 if (con == NULL || opt == NULL) return; 00080 for (; opt->longName || opt->shortName || opt->arg; opt++) { 00081 poptArg arg = { .ptr = opt->arg }; 00082 if (arg.ptr) 00083 switch (poptArgType(opt)) { 00084 case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */ 00085 poptSubstituteHelpI18N(arg.opt); /* XXX side effects */ 00086 invokeCallbacksPRE(con, arg.opt); 00087 /*@switchbreak@*/ break; 00088 case POPT_ARG_CALLBACK: /* Perform callback. */ 00089 if (!CBF_ISSET(opt, PRE)) 00090 /*@switchbreak@*/ break; 00091 /*@-noeffectuncon @*/ /* XXX no known way to annotate (*vector) calls. */ 00092 arg.cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip); 00093 /*@=noeffectuncon @*/ 00094 /*@switchbreak@*/ break; 00095 } 00096 } 00097 } 00098 00099 static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt) 00100 /*@globals internalState@*/ 00101 /*@modifies internalState@*/ 00102 { 00103 if (con == NULL || opt == NULL) return; 00104 for (; opt->longName || opt->shortName || opt->arg; opt++) { 00105 poptArg arg = { .ptr = opt->arg }; 00106 if (arg.ptr) 00107 switch (poptArgType(opt)) { 00108 case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */ 00109 poptSubstituteHelpI18N(arg.opt); /* XXX side effects */ 00110 invokeCallbacksPOST(con, arg.opt); 00111 /*@switchbreak@*/ break; 00112 case POPT_ARG_CALLBACK: /* Perform callback. */ 00113 if (!CBF_ISSET(opt, POST)) 00114 /*@switchbreak@*/ break; 00115 /*@-noeffectuncon @*/ /* XXX no known way to annotate (*vector) calls. */ 00116 arg.cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip); 00117 /*@=noeffectuncon @*/ 00118 /*@switchbreak@*/ break; 00119 } 00120 } 00121 } 00122 00123 static void invokeCallbacksOPTION(poptContext con, 00124 const struct poptOption * opt, 00125 const struct poptOption * myOpt, 00126 /*@null@*/ const void * myData, int shorty) 00127 /*@globals internalState@*/ 00128 /*@modifies internalState@*/ 00129 { 00130 const struct poptOption * cbopt = NULL; 00131 poptArg cbarg = { .ptr = NULL }; 00132 00133 if (con == NULL || opt == NULL) return; 00134 for (; opt->longName || opt->shortName || opt->arg; opt++) { 00135 poptArg arg = { .ptr = opt->arg }; 00136 switch (poptArgType(opt)) { 00137 case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */ 00138 poptSubstituteHelpI18N(arg.opt); /* XXX side effects */ 00139 if (opt->arg != NULL) 00140 invokeCallbacksOPTION(con, opt->arg, myOpt, myData, shorty); 00141 /*@switchbreak@*/ break; 00142 case POPT_ARG_CALLBACK: /* Save callback info. */ 00143 if (CBF_ISSET(opt, SKIPOPTION)) 00144 /*@switchbreak@*/ break; 00145 cbopt = opt; 00146 cbarg.ptr = opt->arg; 00147 /*@switchbreak@*/ break; 00148 default: /* Perform callback on matching option. */ 00149 if (cbopt == NULL || cbarg.cb == NULL) 00150 /*@switchbreak@*/ break; 00151 if ((myOpt->shortName && opt->shortName && shorty && 00152 myOpt->shortName == opt->shortName) 00153 || (myOpt->longName != NULL && opt->longName != NULL && 00154 !strcmp(myOpt->longName, opt->longName))) 00155 { const void *cbData = (cbopt->descrip ? cbopt->descrip : myData); 00156 /*@-noeffectuncon @*/ /* XXX no known way to annotate (*vector) calls. */ 00157 cbarg.cb(con, POPT_CALLBACK_REASON_OPTION, 00158 myOpt, con->os->nextArg, cbData); 00159 /*@=noeffectuncon @*/ 00160 /* Terminate (unless explcitly continuing). */ 00161 if (!CBF_ISSET(cbopt, CONTINUE)) 00162 return; 00163 } 00164 /*@switchbreak@*/ break; 00165 } 00166 } 00167 } 00168 00169 poptContext poptGetContext(const char * name, int argc, const char ** argv, 00170 const struct poptOption * options, unsigned int flags) 00171 { 00172 poptContext con; 00173 00174 if (argc < 1) return NULL; 00175 00176 con = malloc(sizeof(*con)); 00177 if (con == NULL) return NULL; /* XXX can't happen */ 00178 memset(con, 0, sizeof(*con)); 00179 00180 con->os = con->optionStack; 00181 con->os->argc = argc; 00182 /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ 00183 con->os->argv = argv; 00184 /*@=dependenttrans =assignexpose@*/ 00185 con->os->argb = NULL; 00186 00187 if (!(flags & POPT_CONTEXT_KEEP_FIRST)) 00188 con->os->next = 1; /* skip argv[0] */ 00189 00190 con->leftovers = calloc( (size_t)(argc + 1), sizeof(*con->leftovers) ); 00191 /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ 00192 con->options = options; 00193 /*@=dependenttrans =assignexpose@*/ 00194 con->aliases = NULL; 00195 con->numAliases = 0; 00196 con->flags = flags; 00197 con->execs = NULL; 00198 con->numExecs = 0; 00199 con->finalArgvAlloced = argc * 2; 00200 con->finalArgv = calloc( (size_t)con->finalArgvAlloced, sizeof(*con->finalArgv) ); 00201 if (con->finalArgv == NULL) con->finalArgvAlloced = 0; 00202 con->execAbsolute = 1; 00203 con->arg_strip = NULL; 00204 00205 if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER")) 00206 con->flags |= POPT_CONTEXT_POSIXMEHARDER; 00207 00208 if (name) 00209 con->appName = xstrdup(name); 00210 00211 invokeCallbacksPRE(con, con->options); 00212 00213 return con; 00214 } 00215 00216 static void cleanOSE(/*@special@*/ struct optionStackEntry *os) 00217 /*@uses os @*/ 00218 /*@releases os->nextArg, os->argv, os->argb @*/ 00219 /*@modifies os @*/ 00220 { 00221 os->nextArg = _free(os->nextArg); 00222 os->argv = _free(os->argv); 00223 os->argb = PBM_FREE(os->argb); 00224 } 00225 00226 void poptResetContext(poptContext con) 00227 { 00228 int i; 00229 00230 if (con == NULL) return; 00231 while (con->os > con->optionStack) { 00232 cleanOSE(con->os--); 00233 } 00234 con->os->argb = PBM_FREE(con->os->argb); 00235 con->os->currAlias = NULL; 00236 con->os->nextCharArg = NULL; 00237 con->os->nextArg = NULL; 00238 con->os->next = 1; /* skip argv[0] */ 00239 00240 con->numLeftovers = 0; 00241 con->nextLeftover = 0; 00242 con->restLeftover = 0; 00243 con->doExec = NULL; 00244 00245 if (con->finalArgv != NULL) 00246 for (i = 0; i < con->finalArgvCount; i++) { 00247 /*@-unqualifiedtrans@*/ /* FIX: typedef double indirection. */ 00248 con->finalArgv[i] = _free(con->finalArgv[i]); 00249 /*@=unqualifiedtrans@*/ 00250 } 00251 00252 con->finalArgvCount = 0; 00253 con->arg_strip = PBM_FREE(con->arg_strip); 00254 /*@-nullstate@*/ /* FIX: con->finalArgv != NULL */ 00255 return; 00256 /*@=nullstate@*/ 00257 } 00258 00259 /* Only one of longName, shortName should be set, not both. */ 00260 static int handleExec(/*@special@*/ poptContext con, 00261 /*@null@*/ const char * longName, char shortName) 00262 /*@uses con->execs, con->numExecs, con->flags, con->doExec, 00263 con->finalArgv, con->finalArgvAlloced, con->finalArgvCount @*/ 00264 /*@modifies con @*/ 00265 { 00266 poptItem item; 00267 int i; 00268 00269 if (con == NULL || con->execs == NULL || con->numExecs <= 0) /* XXX can't happen */ 00270 return 0; 00271 00272 for (i = con->numExecs - 1; i >= 0; i--) { 00273 item = con->execs + i; 00274 if (longName && !(item->option.longName && 00275 !strcmp(longName, item->option.longName))) 00276 continue; 00277 else if (shortName != item->option.shortName) 00278 continue; 00279 break; 00280 } 00281 if (i < 0) return 0; 00282 00283 00284 if (con->flags & POPT_CONTEXT_NO_EXEC) 00285 return 1; 00286 00287 if (con->doExec == NULL) { 00288 con->doExec = con->execs + i; 00289 return 1; 00290 } 00291 00292 /* We already have an exec to do; remember this option for next 00293 time 'round */ 00294 if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) { 00295 con->finalArgvAlloced += 10; 00296 con->finalArgv = realloc(con->finalArgv, 00297 sizeof(*con->finalArgv) * con->finalArgvAlloced); 00298 if (con->finalArgv == NULL) con->finalArgvCount = con->finalArgvAlloced = 0; 00299 } 00300 00301 i = con->finalArgvCount++; 00302 if (con->finalArgv != NULL) /* XXX can't happen */ 00303 { char *s = malloc((longName ? strlen(longName) : 0) + sizeof("--")); 00304 if (s != NULL) { /* XXX can't happen */ 00305 con->finalArgv[i] = s; 00306 *s++ = '-'; 00307 if (longName) 00308 s = stpcpy( stpcpy(s, "-"), longName); 00309 else 00310 *s++ = shortName; 00311 *s = '\0'; 00312 } else 00313 con->finalArgv[i] = NULL; 00314 } 00315 00316 return 1; 00317 } 00318 00326 static int 00327 longOptionStrcmp(const struct poptOption * opt, 00328 /*@null@*/ const char * longName, size_t longNameLen) 00329 /*@*/ 00330 { 00331 const char * optLongName = opt->longName; 00332 int rc; 00333 00334 if (optLongName == NULL || longName == NULL) /* XXX can't heppen */ 00335 return 0; 00336 00337 if (F_ISSET(opt, TOGGLE)) { 00338 if (optLongName[0] == 'n' && optLongName[1] == 'o') { 00339 optLongName += sizeof("no") - 1; 00340 if (optLongName[0] == '-') 00341 optLongName++; 00342 } 00343 if (longName[0] == 'n' && longName[1] == 'o') { 00344 longName += sizeof("no") - 1; 00345 longNameLen -= sizeof("no") - 1; 00346 if (longName[0] == '-') { 00347 longName++; 00348 longNameLen--; 00349 } 00350 } 00351 } 00352 rc = (int)(strlen(optLongName) == longNameLen); 00353 if (rc) 00354 rc = (int)(strncmp(optLongName, longName, longNameLen) == 0); 00355 return rc; 00356 } 00357 00358 /* Only one of longName, shortName may be set at a time */ 00359 static int handleAlias(/*@special@*/ poptContext con, 00360 /*@null@*/ const char * longName, size_t longNameLen, 00361 char shortName, 00362 /*@exposed@*/ /*@null@*/ const char * nextArg) 00363 /*@uses con->aliases, con->numAliases, con->optionStack, con->os, 00364 con->os->currAlias, con->os->currAlias->option.longName @*/ 00365 /*@modifies con @*/ 00366 { 00367 poptItem item = (con && con->os) ? con->os->currAlias : NULL; 00368 int rc; 00369 int i; 00370 00371 if (item) { 00372 if (longName && item->option.longName != NULL 00373 && longOptionStrcmp(&item->option, longName, longNameLen)) 00374 return 0; 00375 else 00376 if (shortName && shortName == item->option.shortName) 00377 return 0; 00378 } 00379 00380 if (con == NULL || con->aliases == NULL || con->numAliases <= 0) /* XXX can't happen */ 00381 return 0; 00382 00383 for (i = con->numAliases - 1; i >= 0; i--) { 00384 item = con->aliases + i; 00385 if (longName) { 00386 if (item->option.longName == NULL) 00387 continue; 00388 if (!longOptionStrcmp(&item->option, longName, longNameLen)) 00389 continue; 00390 } else if (shortName != item->option.shortName) 00391 continue; 00392 break; 00393 } 00394 if (i < 0) return 0; 00395 00396 if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH) 00397 return POPT_ERROR_OPTSTOODEEP; 00398 00399 if (longName == NULL && nextArg != NULL && *nextArg != '\0') 00400 con->os->nextCharArg = nextArg; 00401 00402 con->os++; 00403 con->os->next = 0; 00404 con->os->stuffed = 0; 00405 con->os->nextArg = NULL; 00406 con->os->nextCharArg = NULL; 00407 con->os->currAlias = con->aliases + i; 00408 { const char ** av; 00409 int ac = con->os->currAlias->argc; 00410 /* Append --foo=bar arg to alias argv array (if present). */ 00411 if (longName && nextArg != NULL && *nextArg != '\0') { 00412 av = malloc((ac + 1 + 1) * sizeof(*av)); 00413 if (av != NULL) { /* XXX won't happen. */ 00414 for (i = 0; i < ac; i++) { 00415 av[i] = con->os->currAlias->argv[i]; 00416 } 00417 av[ac++] = nextArg; 00418 av[ac] = NULL; 00419 } else /* XXX revert to old popt behavior if malloc fails. */ 00420 av = con->os->currAlias->argv; 00421 } else 00422 av = con->os->currAlias->argv; 00423 rc = poptDupArgv(ac, av, &con->os->argc, &con->os->argv); 00424 if (av != NULL && av != con->os->currAlias->argv) 00425 free(av); 00426 } 00427 con->os->argb = NULL; 00428 00429 return (rc ? rc : 1); 00430 } 00431 00437 static /*@null@*/ 00438 const char * findProgramPath(/*@null@*/ const char * argv0) 00439 /*@*/ 00440 { 00441 char *path = NULL, *s = NULL, *se; 00442 char *t = NULL; 00443 00444 if (argv0 == NULL) return NULL; /* XXX can't happen */ 00445 00446 /* If there is a / in argv[0], it has to be an absolute path. */ 00447 /* XXX Hmmm, why not if (argv0[0] == '/') ... instead? */ 00448 if (strchr(argv0, '/')) 00449 return xstrdup(argv0); 00450 00451 if ((path = getenv("PATH")) == NULL || (path = xstrdup(path)) == NULL) 00452 return NULL; 00453 00454 /* The return buffer in t is big enough for any path. */ 00455 if ((t = malloc(strlen(path) + strlen(argv0) + sizeof("/"))) != NULL) 00456 for (s = path; s && *s; s = se) { 00457 00458 /* Snip PATH element into [s,se). */ 00459 if ((se = strchr(s, ':'))) 00460 *se++ = '\0'; 00461 00462 /* Append argv0 to PATH element. */ 00463 (void) stpcpy(stpcpy(stpcpy(t, s), "/"), argv0); 00464 00465 /* If file is executable, bingo! */ 00466 if (!access(t, X_OK)) 00467 break; 00468 } 00469 00470 /* If no executable was found in PATH, return NULL. */ 00471 /*@-compdef@*/ 00472 if (!(s && *s) && t != NULL) 00473 t = _free(t); 00474 /*@=compdef@*/ 00475 /*@-modobserver -observertrans -usedef @*/ 00476 path = _free(path); 00477 /*@=modobserver =observertrans =usedef @*/ 00478 00479 return t; 00480 } 00481 00482 static int execCommand(poptContext con) 00483 /*@globals internalState @*/ 00484 /*@modifies internalState @*/ 00485 { 00486 poptItem item = con ? con->doExec : NULL; 00487 poptArgv argv = NULL; 00488 int argc = 0; 00489 int rc; 00490 int ec = POPT_ERROR_ERRNO; 00491 00492 if (item == NULL) /*XXX can't happen*/ 00493 return POPT_ERROR_NOARG; 00494 00495 if (item->argv == NULL || item->argc < 1 || 00496 (!con->execAbsolute && strchr(item->argv[0], '/'))) 00497 return POPT_ERROR_NOARG; 00498 00499 argv = malloc(sizeof(*argv) * 00500 (6 + item->argc + con->numLeftovers + con->finalArgvCount)); 00501 if (argv == NULL) return POPT_ERROR_MALLOC; 00502 00503 if (!strchr(item->argv[0], '/') && con->execPath != NULL) { 00504 char *s = malloc(strlen(con->execPath) + strlen(item->argv[0]) + sizeof("/")); 00505 if (s) 00506 (void)stpcpy(stpcpy(stpcpy(s, con->execPath), "/"), item->argv[0]); 00507 00508 argv[argc] = s; 00509 } else 00510 argv[argc] = findProgramPath(item->argv[0]); 00511 if (argv[argc++] == NULL) { 00512 ec = POPT_ERROR_NOARG; 00513 goto exit; 00514 } 00515 00516 if (item->argc > 1) { 00517 memcpy(argv + argc, item->argv + 1, sizeof(*argv) * (item->argc - 1)); 00518 argc += (item->argc - 1); 00519 } 00520 00521 if (con->finalArgv != NULL && con->finalArgvCount > 0) { 00522 memcpy(argv + argc, con->finalArgv, 00523 sizeof(*argv) * con->finalArgvCount); 00524 argc += con->finalArgvCount; 00525 } 00526 00527 if (con->leftovers != NULL && con->numLeftovers > 0) { 00528 memcpy(argv + argc, con->leftovers, sizeof(*argv) * con->numLeftovers); 00529 argc += con->numLeftovers; 00530 } 00531 00532 argv[argc] = NULL; 00533 00534 #if defined(hpux) || defined(__hpux) 00535 rc = setresgid(getgid(), getgid(),-1); 00536 if (rc) goto exit; 00537 rc = setresuid(getuid(), getuid(),-1); 00538 if (rc) goto exit; 00539 #else 00540 /* 00541 * XXX " ... on BSD systems setuid() should be preferred over setreuid()" 00542 * XXX sez' Timur Bakeyev <mc@bat.ru> 00543 * XXX from Norbert Warmuth <nwarmuth@privat.circular.de> 00544 */ 00545 #if defined(HAVE_SETUID) 00546 rc = setgid(getgid()); 00547 if (rc) goto exit; 00548 rc = setuid(getuid()); 00549 if (rc) goto exit; 00550 #elif defined (HAVE_SETREUID) 00551 rc = setregid(getgid(), getgid()); 00552 if (rc) goto exit; 00553 rc = setreuid(getuid(), getuid()); 00554 if (rc) goto exit; 00555 #else 00556 ; /* Can't drop privileges */ 00557 #endif 00558 #endif 00559 00560 #ifdef MYDEBUG 00561 if (_popt_debug) 00562 { poptArgv avp; 00563 fprintf(stderr, "==> execvp(%s) argv[%d]:", argv[0], argc); 00564 for (avp = argv; *avp; avp++) 00565 fprintf(stderr, " '%s'", *avp); 00566 fprintf(stderr, "\n"); 00567 } 00568 #endif 00569 00570 /*@-nullstate@*/ 00571 rc = execvp(argv[0], (char *const *)argv); 00572 /*@=nullstate@*/ 00573 00574 exit: 00575 if (argv) { 00576 if (argv[0]) 00577 free((void *)argv[0]); 00578 free(argv); 00579 } 00580 return ec; 00581 } 00582 00583 /*@observer@*/ /*@null@*/ 00584 static const struct poptOption * 00585 findOption(const struct poptOption * opt, 00586 /*@null@*/ const char * longName, size_t longNameLen, 00587 char shortName, 00588 /*@null@*/ /*@out@*/ poptCallbackType * callback, 00589 /*@null@*/ /*@out@*/ const void ** callbackData, 00590 unsigned int argInfo) 00591 /*@modifies *callback, *callbackData */ 00592 { 00593 const struct poptOption * cb = NULL; 00594 poptArg cbarg = { .ptr = NULL }; 00595 00596 /* This happens when a single - is given */ 00597 if (LF_ISSET(ONEDASH) && !shortName && (longName && *longName == '\0')) 00598 shortName = '-'; 00599 00600 for (; opt->longName || opt->shortName || opt->arg; opt++) { 00601 poptArg arg = { .ptr = opt->arg }; 00602 00603 switch (poptArgType(opt)) { 00604 case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */ 00605 { const struct poptOption * opt2; 00606 00607 poptSubstituteHelpI18N(arg.opt); /* XXX side effects */ 00608 if (arg.ptr == NULL) continue; /* XXX program error */ 00609 opt2 = findOption(arg.opt, longName, longNameLen, shortName, callback, 00610 callbackData, argInfo); 00611 if (opt2 == NULL) continue; 00612 /* Sub-table data will be inheirited if no data yet. */ 00613 /*@-observertrans -dependenttrans @*/ 00614 if (callback && *callback 00615 && callbackData && *callbackData == NULL) 00616 *callbackData = opt->descrip; 00617 /*@=observertrans =dependenttrans @*/ 00618 return opt2; 00619 } /*@notreached@*/ /*@switchbreak@*/ break; 00620 case POPT_ARG_CALLBACK: 00621 cb = opt; 00622 cbarg.ptr = opt->arg; 00623 continue; 00624 /*@notreached@*/ /*@switchbreak@*/ break; 00625 default: 00626 /*@switchbreak@*/ break; 00627 } 00628 00629 if (longName != NULL && opt->longName != NULL && 00630 (!LF_ISSET(ONEDASH) || F_ISSET(opt, ONEDASH)) && 00631 longOptionStrcmp(opt, longName, longNameLen)) 00632 { 00633 break; 00634 } else if (shortName && shortName == opt->shortName) { 00635 break; 00636 } 00637 } 00638 00639 if (opt->longName == NULL && !opt->shortName) 00640 return NULL; 00641 00642 /*@-modobserver -mods @*/ 00643 if (callback) 00644 *callback = (cb ? cbarg.cb : NULL); 00645 if (callbackData) 00646 /*@-observertrans -dependenttrans @*/ 00647 *callbackData = (cb && !CBF_ISSET(cb, INC_DATA) ? cb->descrip : NULL); 00648 /*@=observertrans =dependenttrans @*/ 00649 /*@=modobserver =mods @*/ 00650 00651 return opt; 00652 } 00653 00654 static const char * findNextArg(/*@special@*/ poptContext con, 00655 unsigned argx, int delete_arg) 00656 /*@uses con->optionStack, con->os, 00657 con->os->next, con->os->argb, con->os->argc, con->os->argv @*/ 00658 /*@modifies con @*/ 00659 { 00660 struct optionStackEntry * os = con ? con->os : NULL; 00661 const char * arg; 00662 00663 if (os == NULL || con->optionStack == NULL) return NULL; 00664 00665 do { 00666 int i; 00667 arg = NULL; 00668 while (os->next == os->argc && os > con->optionStack) os--; 00669 if (os->next == os->argc && os == con->optionStack) break; 00670 if (os->argv != NULL) 00671 for (i = os->next; i < os->argc; i++) { 00672 /*@-sizeoftype@*/ 00673 if (os->argb && PBM_ISSET(i, os->argb)) 00674 /*@innercontinue@*/ continue; 00675 if (*os->argv[i] == '-') 00676 /*@innercontinue@*/ continue; 00677 if (--argx > 0) 00678 /*@innercontinue@*/ continue; 00679 arg = os->argv[i]; 00680 if (delete_arg) { 00681 if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc); 00682 if (os->argb != NULL) /* XXX can't happen */ 00683 PBM_SET(i, os->argb); 00684 } 00685 /*@innerbreak@*/ break; 00686 /*@=sizeoftype@*/ 00687 } 00688 if (os > con->optionStack) os--; 00689 } while (arg == NULL); 00690 return arg; 00691 } 00692 00693 static /*@only@*/ /*@null@*/ const char * 00694 expandNextArg(/*@special@*/ poptContext con, const char * s) 00695 /*@uses con->optionStack, con->os, 00696 con->os->next, con->os->argb, con->os->argc, con->os->argv @*/ 00697 /*@modifies con @*/ 00698 { 00699 const char * a = NULL; 00700 char *t, *te; 00701 size_t tn = strlen(s) + 1; 00702 char c; 00703 00704 if (con == NULL) return NULL; 00705 00706 te = t = malloc(tn); 00707 if (t == NULL) return NULL; /* XXX can't happen */ 00708 *t = '\0'; 00709 while ((c = *s++) != '\0') { 00710 switch (c) { 00711 #if 0 /* XXX can't do this */ 00712 case '\\': /* escape */ 00713 c = *s++; 00714 /*@switchbreak@*/ break; 00715 #endif 00716 case '!': 00717 if (!(s[0] == '#' && s[1] == ':' && s[2] == '+')) 00718 /*@switchbreak@*/ break; 00719 /* XXX Make sure that findNextArg deletes only next arg. */ 00720 if (a == NULL) { 00721 if ((a = findNextArg(con, 1U, 1)) == NULL) 00722 /*@switchbreak@*/ break; 00723 } 00724 s += sizeof("#:+") - 1; 00725 00726 tn += strlen(a); 00727 { size_t pos = (size_t) (te - t); 00728 if ((t = realloc(t, tn)) == NULL) /* XXX can't happen */ 00729 return NULL; 00730 te = stpcpy(t + pos, a); 00731 } 00732 continue; 00733 /*@notreached@*/ /*@switchbreak@*/ break; 00734 default: 00735 /*@switchbreak@*/ break; 00736 } 00737 *te++ = c; 00738 } 00739 *te++ = '\0'; 00740 /* If the new string is longer than needed, shorten. */ 00741 if ((t + tn) > te) { 00742 /*@-usereleased@*/ /* XXX splint can't follow the pointers. */ 00743 if ((te = realloc(t, (size_t)(te - t))) == NULL) 00744 free(t); 00745 t = te; 00746 /*@=usereleased@*/ 00747 } 00748 return t; 00749 } 00750 00751 static void poptStripArg(/*@special@*/ poptContext con, int which) 00752 /*@uses con->optionStack @*/ 00753 /*@defines con->arg_strip @*/ 00754 /*@modifies con @*/ 00755 { 00756 /*@-compdef -sizeoftype -usedef @*/ 00757 if (con->arg_strip == NULL) 00758 con->arg_strip = PBM_ALLOC(con->optionStack[0].argc); 00759 if (con->arg_strip != NULL) /* XXX can't happen */ 00760 PBM_SET(which, con->arg_strip); 00761 return; 00762 /*@=compdef =sizeoftype =usedef @*/ 00763 } 00764 00765 /*@unchecked@*/ 00766 unsigned int _poptBitsN = _POPT_BITS_N; 00767 /*@unchecked@*/ 00768 unsigned int _poptBitsM = _POPT_BITS_M; 00769 /*@unchecked@*/ 00770 unsigned int _poptBitsK = _POPT_BITS_K; 00771 00772 /*@-sizeoftype@*/ 00773 static int _poptBitsNew(/*@null@*/ poptBits *bitsp) 00774 /*@globals _poptBitsN, _poptBitsM, _poptBitsK @*/ 00775 /*@modifies *bitsp, _poptBitsN, _poptBitsM, _poptBitsK @*/ 00776 { 00777 if (bitsp == NULL) 00778 return POPT_ERROR_NULLARG; 00779 00780 /* XXX handle negated initialization. */ 00781 if (*bitsp == NULL) { 00782 if (_poptBitsN == 0) { 00783 _poptBitsN = _POPT_BITS_N; 00784 _poptBitsM = _POPT_BITS_M; 00785 } 00786 if (_poptBitsM == 0U) _poptBitsM = (3 * _poptBitsN) / 2; 00787 if (_poptBitsK == 0U || _poptBitsK > 32U) _poptBitsK = _POPT_BITS_K; 00788 *bitsp = PBM_ALLOC(_poptBitsM-1); 00789 } 00790 /*@-nullstate@*/ 00791 return 0; 00792 /*@=nullstate@*/ 00793 } 00794 00795 int poptBitsAdd(poptBits bits, const char * s) 00796 { 00797 size_t ns = (s ? strlen(s) : 0); 00798 uint32_t h0 = 0; 00799 uint32_t h1 = 0; 00800 00801 if (bits == NULL || ns == 0) 00802 return POPT_ERROR_NULLARG; 00803 00804 poptJlu32lpair(s, ns, &h0, &h1); 00805 00806 for (ns = 0; ns < (size_t)_poptBitsK; ns++) { 00807 uint32_t h = h0 + ns * h1; 00808 uint32_t ix = (h % _poptBitsM); 00809 PBM_SET(ix, bits); 00810 } 00811 return 0; 00812 } 00813 00814 int poptBitsChk(poptBits bits, const char * s) 00815 { 00816 size_t ns = (s ? strlen(s) : 0); 00817 uint32_t h0 = 0; 00818 uint32_t h1 = 0; 00819 int rc = 1; 00820 00821 if (bits == NULL || ns == 0) 00822 return POPT_ERROR_NULLARG; 00823 00824 poptJlu32lpair(s, ns, &h0, &h1); 00825 00826 for (ns = 0; ns < (size_t)_poptBitsK; ns++) { 00827 uint32_t h = h0 + ns * h1; 00828 uint32_t ix = (h % _poptBitsM); 00829 if (PBM_ISSET(ix, bits)) 00830 continue; 00831 rc = 0; 00832 break; 00833 } 00834 return rc; 00835 } 00836 00837 int poptBitsClr(poptBits bits) 00838 { 00839 static size_t nbw = (__PBM_NBITS/8); 00840 size_t nw = (__PBM_IX(_poptBitsM-1) + 1); 00841 00842 if (bits == NULL) 00843 return POPT_ERROR_NULLARG; 00844 memset(bits, 0, nw * nbw); 00845 return 0; 00846 } 00847 00848 int poptBitsDel(poptBits bits, const char * s) 00849 { 00850 size_t ns = (s ? strlen(s) : 0); 00851 uint32_t h0 = 0; 00852 uint32_t h1 = 0; 00853 00854 if (bits == NULL || ns == 0) 00855 return POPT_ERROR_NULLARG; 00856 00857 poptJlu32lpair(s, ns, &h0, &h1); 00858 00859 for (ns = 0; ns < (size_t)_poptBitsK; ns++) { 00860 uint32_t h = h0 + ns * h1; 00861 uint32_t ix = (h % _poptBitsM); 00862 PBM_CLR(ix, bits); 00863 } 00864 return 0; 00865 } 00866 00867 int poptBitsIntersect(poptBits *ap, const poptBits b) 00868 { 00869 __pbm_bits *abits; 00870 __pbm_bits *bbits; 00871 __pbm_bits rc = 0; 00872 size_t nw = (__PBM_IX(_poptBitsM-1) + 1); 00873 size_t i; 00874 00875 if (ap == NULL || b == NULL || _poptBitsNew(ap)) 00876 return POPT_ERROR_NULLARG; 00877 abits = __PBM_BITS(*ap); 00878 bbits = __PBM_BITS(b); 00879 00880 for (i = 0; i < nw; i++) { 00881 abits[i] &= bbits[i]; 00882 rc |= abits[i]; 00883 } 00884 return (rc ? 1 : 0); 00885 } 00886 00887 int poptBitsUnion(poptBits *ap, const poptBits b) 00888 { 00889 __pbm_bits *abits; 00890 __pbm_bits *bbits; 00891 __pbm_bits rc = 0; 00892 size_t nw = (__PBM_IX(_poptBitsM-1) + 1); 00893 size_t i; 00894 00895 if (ap == NULL || b == NULL || _poptBitsNew(ap)) 00896 return POPT_ERROR_NULLARG; 00897 abits = __PBM_BITS(*ap); 00898 bbits = __PBM_BITS(b); 00899 00900 for (i = 0; i < nw; i++) { 00901 abits[i] |= bbits[i]; 00902 rc |= abits[i]; 00903 } 00904 return (rc ? 1 : 0); 00905 } 00906 00907 int poptBitsArgs(poptContext con, poptBits *ap) 00908 { 00909 const char ** av; 00910 int rc = 0; 00911 00912 if (con == NULL || ap == NULL || _poptBitsNew(ap) || 00913 con->leftovers == NULL || con->numLeftovers == con->nextLeftover) 00914 return POPT_ERROR_NULLARG; 00915 00916 /* some apps like [like RPM ;-) ] need this NULL terminated */ 00917 con->leftovers[con->numLeftovers] = NULL; 00918 00919 for (av = con->leftovers + con->nextLeftover; *av != NULL; av++) { 00920 if ((rc = poptBitsAdd(*ap, *av)) != 0) 00921 break; 00922 } 00923 /*@-nullstate@*/ 00924 return rc; 00925 /*@=nullstate@*/ 00926 } 00927 00928 int poptSaveBits(poptBits * bitsp, 00929 /*@unused@*/ UNUSED(unsigned int argInfo), const char * s) 00930 { 00931 char *tbuf = NULL; 00932 char *t, *te; 00933 int rc = 0; 00934 00935 if (bitsp == NULL || s == NULL || *s == '\0' || _poptBitsNew(bitsp)) 00936 return POPT_ERROR_NULLARG; 00937 00938 /* Parse comma separated attributes. */ 00939 te = tbuf = xstrdup(s); 00940 while ((t = te) != NULL && *t) { 00941 while (*te != '\0' && *te != ',') 00942 te++; 00943 if (*te != '\0') 00944 *te++ = '\0'; 00945 /* XXX Ignore empty strings. */ 00946 if (*t == '\0') 00947 continue; 00948 /* XXX Permit negated attributes. caveat emptor: false negatives. */ 00949 if (*t == '!') { 00950 t++; 00951 if ((rc = poptBitsChk(*bitsp, t)) > 0) 00952 rc = poptBitsDel(*bitsp, t); 00953 } else 00954 rc = poptBitsAdd(*bitsp, t); 00955 if (rc) 00956 break; 00957 } 00958 tbuf = _free(tbuf); 00959 return rc; 00960 } 00961 /*@=sizeoftype@*/ 00962 00963 int poptSaveString(const char *** argvp, 00964 /*@unused@*/ UNUSED(unsigned int argInfo), const char * val) 00965 { 00966 int argc = 0; 00967 00968 if (argvp == NULL || val == NULL) 00969 return POPT_ERROR_NULLARG; 00970 00971 /* XXX likely needs an upper bound on argc. */ 00972 if (*argvp != NULL) 00973 while ((*argvp)[argc] != NULL) 00974 argc++; 00975 00976 /*@-unqualifiedtrans -nullstate@*/ /* XXX no annotation for (*argvp) */ 00977 if ((*argvp = xrealloc(*argvp, (argc + 1 + 1) * sizeof(**argvp))) != NULL) { 00978 (*argvp)[argc++] = xstrdup(val); 00979 (*argvp)[argc ] = NULL; 00980 } 00981 return 0; 00982 /*@=unqualifiedtrans =nullstate@*/ 00983 } 00984 00985 /*@unchecked@*/ 00986 static unsigned int seed = 0; 00987 00988 int poptSaveLongLong(long long * arg, unsigned int argInfo, long long aLongLong) 00989 { 00990 if (arg == NULL 00991 #ifdef NOTYET 00992 /* XXX Check alignment, may fail on funky platforms. */ 00993 || (((unsigned long long)arg) & (sizeof(*arg)-1)) 00994 #endif 00995 ) 00996 return POPT_ERROR_NULLARG; 00997 00998 if (aLongLong != 0 && LF_ISSET(RANDOM)) { 00999 #if defined(HAVE_SRANDOM) 01000 if (!seed) { 01001 srandom((unsigned)getpid()); 01002 srandom((unsigned)random()); 01003 } 01004 aLongLong = (long long)(random() % (aLongLong > 0 ? aLongLong : -aLongLong)); 01005 aLongLong++; 01006 #else 01007 /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */ 01008 return POPT_ERROR_BADOPERATION; 01009 #endif 01010 } 01011 if (LF_ISSET(NOT)) 01012 aLongLong = ~aLongLong; 01013 switch (LF_ISSET(LOGICALOPS)) { 01014 case 0: 01015 *arg = aLongLong; 01016 break; 01017 case POPT_ARGFLAG_OR: 01018 *(unsigned long long *)arg |= (unsigned long long)aLongLong; 01019 break; 01020 case POPT_ARGFLAG_AND: 01021 *(unsigned long long *)arg &= (unsigned long long)aLongLong; 01022 break; 01023 case POPT_ARGFLAG_XOR: 01024 *(unsigned long long *)arg ^= (unsigned long long)aLongLong; 01025 break; 01026 default: 01027 return POPT_ERROR_BADOPERATION; 01028 /*@notreached@*/ break; 01029 } 01030 return 0; 01031 } 01032 01033 int poptSaveLong(long * arg, unsigned int argInfo, long aLong) 01034 { 01035 /* XXX Check alignment, may fail on funky platforms. */ 01036 if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1))) 01037 return POPT_ERROR_NULLARG; 01038 01039 if (aLong != 0 && LF_ISSET(RANDOM)) { 01040 #if defined(HAVE_SRANDOM) 01041 if (!seed) { 01042 srandom((unsigned)getpid()); 01043 srandom((unsigned)random()); 01044 } 01045 aLong = random() % (aLong > 0 ? aLong : -aLong); 01046 aLong++; 01047 #else 01048 /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */ 01049 return POPT_ERROR_BADOPERATION; 01050 #endif 01051 } 01052 if (LF_ISSET(NOT)) 01053 aLong = ~aLong; 01054 switch (LF_ISSET(LOGICALOPS)) { 01055 case 0: *arg = aLong; break; 01056 case POPT_ARGFLAG_OR: *(unsigned long *)arg |= (unsigned long)aLong; break; 01057 case POPT_ARGFLAG_AND: *(unsigned long *)arg &= (unsigned long)aLong; break; 01058 case POPT_ARGFLAG_XOR: *(unsigned long *)arg ^= (unsigned long)aLong; break; 01059 default: 01060 return POPT_ERROR_BADOPERATION; 01061 /*@notreached@*/ break; 01062 } 01063 return 0; 01064 } 01065 01066 int poptSaveInt(/*@null@*/ int * arg, unsigned int argInfo, long aLong) 01067 { 01068 /* XXX Check alignment, may fail on funky platforms. */ 01069 if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1))) 01070 return POPT_ERROR_NULLARG; 01071 01072 if (aLong != 0 && LF_ISSET(RANDOM)) { 01073 #if defined(HAVE_SRANDOM) 01074 if (!seed) { 01075 srandom((unsigned)getpid()); 01076 srandom((unsigned)random()); 01077 } 01078 aLong = random() % (aLong > 0 ? aLong : -aLong); 01079 aLong++; 01080 #else 01081 /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */ 01082 return POPT_ERROR_BADOPERATION; 01083 #endif 01084 } 01085 if (LF_ISSET(NOT)) 01086 aLong = ~aLong; 01087 switch (LF_ISSET(LOGICALOPS)) { 01088 case 0: *arg = (int) aLong; break; 01089 case POPT_ARGFLAG_OR: *(unsigned int *)arg |= (unsigned int) aLong; break; 01090 case POPT_ARGFLAG_AND: *(unsigned int *)arg &= (unsigned int) aLong; break; 01091 case POPT_ARGFLAG_XOR: *(unsigned int *)arg ^= (unsigned int) aLong; break; 01092 default: 01093 return POPT_ERROR_BADOPERATION; 01094 /*@notreached@*/ break; 01095 } 01096 return 0; 01097 } 01098 01099 int poptSaveShort(/*@null@*/ short * arg, unsigned int argInfo, long aLong) 01100 { 01101 /* XXX Check alignment, may fail on funky platforms. */ 01102 if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1))) 01103 return POPT_ERROR_NULLARG; 01104 01105 if (aLong != 0 && LF_ISSET(RANDOM)) { 01106 #if defined(HAVE_SRANDOM) 01107 if (!seed) { 01108 srandom((unsigned)getpid()); 01109 srandom((unsigned)random()); 01110 } 01111 aLong = random() % (aLong > 0 ? aLong : -aLong); 01112 aLong++; 01113 #else 01114 /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */ 01115 return POPT_ERROR_BADOPERATION; 01116 #endif 01117 } 01118 if (LF_ISSET(NOT)) 01119 aLong = ~aLong; 01120 switch (LF_ISSET(LOGICALOPS)) { 01121 case 0: *arg = (short) aLong; 01122 break; 01123 case POPT_ARGFLAG_OR: *(unsigned short *)arg |= (unsigned short) aLong; 01124 break; 01125 case POPT_ARGFLAG_AND: *(unsigned short *)arg &= (unsigned short) aLong; 01126 break; 01127 case POPT_ARGFLAG_XOR: *(unsigned short *)arg ^= (unsigned short) aLong; 01128 break; 01129 default: return POPT_ERROR_BADOPERATION; 01130 /*@notreached@*/ break; 01131 } 01132 return 0; 01133 } 01134 01141 static unsigned int poptArgInfo(poptContext con, const struct poptOption * opt) 01142 /*@*/ 01143 { 01144 unsigned int argInfo = opt->argInfo; 01145 01146 if (con->os->argv != NULL && con->os->next > 0 && opt->longName != NULL) 01147 if (LF_ISSET(TOGGLE)) { 01148 const char * longName = con->os->argv[con->os->next-1]; 01149 while (*longName == '-') longName++; 01150 /* XXX almost good enough but consider --[no]nofoo corner cases. */ 01151 if (longName[0] != opt->longName[0] || longName[1] != opt->longName[1]) 01152 { 01153 if (!LF_ISSET(XOR)) { /* XXX dont toggle with XOR */ 01154 /* Toggle POPT_BIT_SET <=> POPT_BIT_CLR. */ 01155 if (LF_ISSET(LOGICALOPS)) 01156 argInfo ^= (POPT_ARGFLAG_OR|POPT_ARGFLAG_AND); 01157 argInfo ^= POPT_ARGFLAG_NOT; 01158 } 01159 } 01160 } 01161 return argInfo; 01162 } 01163 01171 static int poptParseInteger(long long * llp, 01172 /*@unused@*/ UNUSED(unsigned int argInfo), 01173 /*@null@*/ const char * val) 01174 /*@modifies *llp @*/ 01175 { 01176 if (val) { 01177 char *end = NULL; 01178 *llp = strtoll(val, &end, 0); 01179 01180 /* XXX parse scaling suffixes here. */ 01181 01182 if (!(end && *end == '\0')) 01183 return POPT_ERROR_BADNUMBER; 01184 } else 01185 *llp = 0; 01186 return 0; 01187 } 01188 01195 static int poptSaveArg(poptContext con, const struct poptOption * opt) 01196 /*@globals fileSystem, internalState @*/ 01197 /*@modifies con, fileSystem, internalState @*/ 01198 { 01199 poptArg arg = { .ptr = opt->arg }; 01200 int rc = 0; /* assume success */ 01201 01202 switch (poptArgType(opt)) { 01203 case POPT_ARG_BITSET: 01204 /* XXX memory leak, application is responsible for free. */ 01205 rc = poptSaveBits(arg.ptr, opt->argInfo, con->os->nextArg); 01206 /*@switchbreak@*/ break; 01207 case POPT_ARG_ARGV: 01208 /* XXX memory leak, application is responsible for free. */ 01209 rc = poptSaveString(arg.ptr, opt->argInfo, con->os->nextArg); 01210 /*@switchbreak@*/ break; 01211 case POPT_ARG_STRING: 01212 /* XXX memory leak, application is responsible for free. */ 01213 arg.argv[0] = (con->os->nextArg) ? xstrdup(con->os->nextArg) : NULL; 01214 /*@switchbreak@*/ break; 01215 01216 case POPT_ARG_INT: 01217 case POPT_ARG_SHORT: 01218 case POPT_ARG_LONG: 01219 case POPT_ARG_LONGLONG: 01220 { unsigned int argInfo = poptArgInfo(con, opt); 01221 long long aNUM = 0; 01222 01223 if ((rc = poptParseInteger(&aNUM, argInfo, con->os->nextArg)) != 0) 01224 break; 01225 01226 switch (poptArgType(opt)) { 01227 case POPT_ARG_LONGLONG: 01228 /* XXX let's not demand C99 compiler flags for <limits.h> quite yet. */ 01229 #if !defined(LLONG_MAX) 01230 # define LLONG_MAX 9223372036854775807LL 01231 # define LLONG_MIN (-LLONG_MAX - 1LL) 01232 #endif 01233 rc = !(aNUM == LLONG_MIN || aNUM == LLONG_MAX) 01234 ? poptSaveLongLong(arg.longlongp, argInfo, aNUM) 01235 : POPT_ERROR_OVERFLOW; 01236 /*@innerbreak@*/ break; 01237 case POPT_ARG_LONG: 01238 rc = !(aNUM < (long long)LONG_MIN || aNUM > (long long)LONG_MAX) 01239 ? poptSaveLong(arg.longp, argInfo, (long)aNUM) 01240 : POPT_ERROR_OVERFLOW; 01241 /*@innerbreak@*/ break; 01242 case POPT_ARG_INT: 01243 rc = !(aNUM < (long long)INT_MIN || aNUM > (long long)INT_MAX) 01244 ? poptSaveInt(arg.intp, argInfo, (long)aNUM) 01245 : POPT_ERROR_OVERFLOW; 01246 /*@innerbreak@*/ break; 01247 case POPT_ARG_SHORT: 01248 rc = !(aNUM < (long long)SHRT_MIN || aNUM > (long long)SHRT_MAX) 01249 ? poptSaveShort(arg.shortp, argInfo, (long)aNUM) 01250 : POPT_ERROR_OVERFLOW; 01251 /*@innerbreak@*/ break; 01252 } 01253 } /*@switchbreak@*/ break; 01254 01255 case POPT_ARG_FLOAT: 01256 case POPT_ARG_DOUBLE: 01257 { char *end = NULL; 01258 double aDouble = 0.0; 01259 01260 if (con->os->nextArg) { 01261 /*@-mods@*/ 01262 int saveerrno = errno; 01263 errno = 0; 01264 aDouble = strtod(con->os->nextArg, &end); 01265 if (errno == ERANGE) { 01266 rc = POPT_ERROR_OVERFLOW; 01267 break; 01268 } 01269 errno = saveerrno; 01270 /*@=mods@*/ 01271 if (*end != '\0') { 01272 rc = POPT_ERROR_BADNUMBER; 01273 break; 01274 } 01275 } 01276 01277 switch (poptArgType(opt)) { 01278 case POPT_ARG_DOUBLE: 01279 arg.doublep[0] = aDouble; 01280 /*@innerbreak@*/ break; 01281 case POPT_ARG_FLOAT: 01282 #if !defined(DBL_EPSILON) && !defined(__LCLINT__) 01283 #define DBL_EPSILON 2.2204460492503131e-16 01284 #endif 01285 #define POPT_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a)) 01286 if ((FLT_MIN - POPT_ABS(aDouble)) > DBL_EPSILON 01287 || (POPT_ABS(aDouble) - FLT_MAX) > DBL_EPSILON) 01288 rc = POPT_ERROR_OVERFLOW; 01289 else 01290 arg.floatp[0] = (float) aDouble; 01291 /*@innerbreak@*/ break; 01292 } 01293 } /*@switchbreak@*/ break; 01294 case POPT_ARG_MAINCALL: 01295 /*@-assignexpose -type@*/ 01296 con->maincall = opt->arg; 01297 /*@=assignexpose =type@*/ 01298 /*@switchbreak@*/ break; 01299 default: 01300 fprintf(stdout, POPT_("option type (%u) not implemented in popt\n"), 01301 poptArgType(opt)); 01302 exit(EXIT_FAILURE); 01303 /*@notreached@*/ /*@switchbreak@*/ break; 01304 } 01305 return rc; 01306 } 01307 01308 /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */ 01309 int poptGetNextOpt(poptContext con) 01310 { 01311 const struct poptOption * opt = NULL; 01312 int done = 0; 01313 01314 if (con == NULL) 01315 return -1; 01316 while (!done) { 01317 const char * origOptString = NULL; 01318 poptCallbackType cb = NULL; 01319 const void * cbData = NULL; 01320 const char * longArg = NULL; 01321 int canstrip = 0; 01322 int shorty = 0; 01323 01324 while (!con->os->nextCharArg && con->os->next == con->os->argc 01325 && con->os > con->optionStack) { 01326 cleanOSE(con->os--); 01327 } 01328 if (!con->os->nextCharArg && con->os->next == con->os->argc) { 01329 invokeCallbacksPOST(con, con->options); 01330 01331 if (con->maincall) { 01332 /*@-noeffectuncon @*/ 01333 (void) (*con->maincall) (con->finalArgvCount, con->finalArgv); 01334 /*@=noeffectuncon @*/ 01335 return -1; 01336 } 01337 01338 if (con->doExec) return execCommand(con); 01339 return -1; 01340 } 01341 01342 /* Process next long option */ 01343 if (!con->os->nextCharArg) { 01344 const char * optString; 01345 size_t optStringLen; 01346 int thisopt; 01347 01348 /*@-sizeoftype@*/ 01349 if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) { 01350 con->os->next++; 01351 continue; 01352 } 01353 /*@=sizeoftype@*/ 01354 thisopt = con->os->next; 01355 if (con->os->argv != NULL) /* XXX can't happen */ 01356 origOptString = con->os->argv[con->os->next++]; 01357 01358 if (origOptString == NULL) /* XXX can't happen */ 01359 return POPT_ERROR_BADOPT; 01360 01361 if (con->restLeftover || *origOptString != '-' || 01362 (*origOptString == '-' && origOptString[1] == '\0')) 01363 { 01364 if (con->flags & POPT_CONTEXT_POSIXMEHARDER) 01365 con->restLeftover = 1; 01366 if (con->flags & POPT_CONTEXT_ARG_OPTS) { 01367 con->os->nextArg = xstrdup(origOptString); 01368 return 0; 01369 } 01370 if (con->leftovers != NULL) /* XXX can't happen */ 01371 con->leftovers[con->numLeftovers++] = origOptString; 01372 continue; 01373 } 01374 01375 /* Make a copy we can hack at */ 01376 optString = origOptString; 01377 01378 if (optString[0] == '\0') 01379 return POPT_ERROR_BADOPT; 01380 01381 if (optString[1] == '-' && !optString[2]) { 01382 con->restLeftover = 1; 01383 continue; 01384 } else { 01385 const char *oe; 01386 unsigned int argInfo = 0; 01387 01388 optString++; 01389 if (*optString == '-') 01390 optString++; 01391 else 01392 argInfo |= POPT_ARGFLAG_ONEDASH; 01393 01394 /* Check for "--long=arg" option. */ 01395 for (oe = optString; *oe && *oe != '='; oe++) 01396 {}; 01397 optStringLen = (size_t)(oe - optString); 01398 if (*oe == '=') 01399 longArg = oe + 1; 01400 01401 /* XXX aliases with arg substitution need "--alias=arg" */ 01402 if (handleAlias(con, optString, optStringLen, '\0', longArg)) { 01403 longArg = NULL; 01404 continue; 01405 } 01406 01407 if (handleExec(con, optString, '\0')) 01408 continue; 01409 01410 opt = findOption(con->options, optString, optStringLen, '\0', &cb, &cbData, 01411 argInfo); 01412 if (!opt && !LF_ISSET(ONEDASH)) 01413 return POPT_ERROR_BADOPT; 01414 } 01415 01416 if (!opt) { 01417 con->os->nextCharArg = origOptString + 1; 01418 longArg = NULL; 01419 } else { 01420 if (con->os == con->optionStack && F_ISSET(opt, STRIP)) 01421 { 01422 canstrip = 1; 01423 poptStripArg(con, thisopt); 01424 } 01425 shorty = 0; 01426 } 01427 } 01428 01429 /* Process next short option */ 01430 if (con->os->nextCharArg) { 01431 const char * nextCharArg = con->os->nextCharArg; 01432 01433 con->os->nextCharArg = NULL; 01434 01435 if (handleAlias(con, NULL, 0, *nextCharArg, nextCharArg + 1)) 01436 continue; 01437 01438 if (handleExec(con, NULL, *nextCharArg)) { 01439 /* Restore rest of short options for further processing */ 01440 nextCharArg++; 01441 if (*nextCharArg != '\0') 01442 con->os->nextCharArg = nextCharArg; 01443 continue; 01444 } 01445 01446 opt = findOption(con->options, NULL, 0, *nextCharArg, &cb, 01447 &cbData, 0); 01448 if (!opt) 01449 return POPT_ERROR_BADOPT; 01450 shorty = 1; 01451 01452 nextCharArg++; 01453 if (*nextCharArg != '\0') 01454 con->os->nextCharArg = nextCharArg + (int)(*nextCharArg == '='); 01455 } 01456 01457 if (opt == NULL) return POPT_ERROR_BADOPT; /* XXX can't happen */ 01458 if (opt->arg && poptArgType(opt) == POPT_ARG_NONE) { 01459 unsigned int argInfo = poptArgInfo(con, opt); 01460 if (poptSaveInt((int *)opt->arg, argInfo, 1L)) 01461 return POPT_ERROR_BADOPERATION; 01462 } else if (poptArgType(opt) == POPT_ARG_VAL) { 01463 if (opt->arg) { 01464 unsigned int argInfo = poptArgInfo(con, opt); 01465 if (poptSaveInt((int *)opt->arg, argInfo, (long)opt->val)) 01466 return POPT_ERROR_BADOPERATION; 01467 } 01468 } else if (poptArgType(opt) != POPT_ARG_NONE) { 01469 int rc; 01470 01471 con->os->nextArg = _free(con->os->nextArg); 01472 if (longArg) { 01473 longArg = expandNextArg(con, longArg); 01474 con->os->nextArg = (char *) longArg; 01475 } else if (con->os->nextCharArg) { 01476 longArg = expandNextArg(con, con->os->nextCharArg); 01477 con->os->nextArg = (char *) longArg; 01478 con->os->nextCharArg = NULL; 01479 } else { 01480 while (con->os->next == con->os->argc && 01481 con->os > con->optionStack) 01482 { 01483 cleanOSE(con->os--); 01484 } 01485 if (con->os->next == con->os->argc) { 01486 if (!F_ISSET(opt, OPTIONAL)) 01487 return POPT_ERROR_NOARG; 01488 con->os->nextArg = NULL; 01489 } else { 01490 01491 /* 01492 * Make sure this isn't part of a short arg or the 01493 * result of an alias expansion. 01494 */ 01495 if (con->os == con->optionStack 01496 && F_ISSET(opt, STRIP) && canstrip) 01497 { 01498 poptStripArg(con, con->os->next); 01499 } 01500 01501 if (con->os->argv != NULL) { /* XXX can't happen */ 01502 if (F_ISSET(opt, OPTIONAL) && 01503 con->os->argv[con->os->next][0] == '-') { 01504 con->os->nextArg = NULL; 01505 } else { 01506 /* XXX watchout: subtle side-effects live here. */ 01507 longArg = con->os->argv[con->os->next++]; 01508 longArg = expandNextArg(con, longArg); 01509 con->os->nextArg = (char *) longArg; 01510 } 01511 } 01512 } 01513 } 01514 longArg = NULL; 01515 01516 /* Save the option argument through a (*opt->arg) pointer. */ 01517 if (opt->arg != NULL && (rc = poptSaveArg(con, opt)) != 0) 01518 return rc; 01519 } 01520 01521 if (cb) 01522 invokeCallbacksOPTION(con, con->options, opt, cbData, shorty); 01523 else if (opt->val && (poptArgType(opt) != POPT_ARG_VAL)) 01524 done = 1; 01525 01526 if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) { 01527 con->finalArgvAlloced += 10; 01528 con->finalArgv = realloc(con->finalArgv, 01529 sizeof(*con->finalArgv) * con->finalArgvAlloced); 01530 if (con->finalArgv == NULL) con->finalArgvCount = con->finalArgvAlloced = 0; 01531 } 01532 01533 if (con->finalArgv != NULL) 01534 { char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + sizeof("--")); 01535 if (s != NULL) { /* XXX can't happen */ 01536 con->finalArgv[con->finalArgvCount++] = s; 01537 *s++ = '-'; 01538 if (opt->longName) { 01539 if (!F_ISSET(opt, ONEDASH)) 01540 *s++ = '-'; 01541 s = stpcpy(s, opt->longName); 01542 } else { 01543 *s++ = opt->shortName; 01544 *s = '\0'; 01545 } 01546 } else 01547 con->finalArgv[con->finalArgvCount++] = NULL; 01548 } 01549 01550 if (opt->arg && poptArgType(opt) == POPT_ARG_NONE) 01551 /*@-ifempty@*/ ; /*@=ifempty@*/ 01552 else if (poptArgType(opt) == POPT_ARG_VAL) 01553 /*@-ifempty@*/ ; /*@=ifempty@*/ 01554 else if (poptArgType(opt) != POPT_ARG_NONE) { 01555 if (con->finalArgv != NULL && con->os->nextArg != NULL) 01556 con->finalArgv[con->finalArgvCount++] = 01557 xstrdup(con->os->nextArg); 01558 } 01559 } 01560 01561 return (opt ? opt->val : -1); /* XXX can't happen */ 01562 } 01563 01564 char * poptGetOptArg(poptContext con) 01565 { 01566 char * ret = NULL; 01567 if (con) { 01568 ret = con->os->nextArg; 01569 con->os->nextArg = NULL; 01570 } 01571 return ret; 01572 } 01573 01574 const char * poptGetArg(poptContext con) 01575 { 01576 const char * ret = NULL; 01577 if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers) 01578 ret = con->leftovers[con->nextLeftover++]; 01579 return ret; 01580 } 01581 01582 const char * poptPeekArg(poptContext con) 01583 { 01584 const char * ret = NULL; 01585 if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers) 01586 ret = con->leftovers[con->nextLeftover]; 01587 return ret; 01588 } 01589 01590 const char ** poptGetArgs(poptContext con) 01591 { 01592 if (con == NULL || 01593 con->leftovers == NULL || con->numLeftovers == con->nextLeftover) 01594 return NULL; 01595 01596 /* some apps like [like RPM ;-) ] need this NULL terminated */ 01597 con->leftovers[con->numLeftovers] = NULL; 01598 01599 /*@-nullret -nullstate @*/ /* FIX: typedef double indirection. */ 01600 return (con->leftovers + con->nextLeftover); 01601 /*@=nullret =nullstate @*/ 01602 } 01603 01604 static /*@null@*/ 01605 poptItem poptFreeItems(/*@only@*/ /*@null@*/ poptItem items, int nitems) 01606 /*@modifies items @*/ 01607 { 01608 if (items != NULL) { 01609 poptItem item = items; 01610 while (--nitems >= 0) { 01611 /*@-modobserver -observertrans -dependenttrans@*/ 01612 item->option.longName = _free(item->option.longName); 01613 item->option.descrip = _free(item->option.descrip); 01614 item->option.argDescrip = _free(item->option.argDescrip); 01615 /*@=modobserver =observertrans =dependenttrans@*/ 01616 item->argv = _free(item->argv); 01617 item++; 01618 } 01619 items = _free(items); 01620 } 01621 return NULL; 01622 } 01623 01624 poptContext poptFreeContext(poptContext con) 01625 { 01626 if (con == NULL) return con; 01627 poptResetContext(con); 01628 con->os->argb = _free(con->os->argb); 01629 01630 con->aliases = poptFreeItems(con->aliases, con->numAliases); 01631 con->numAliases = 0; 01632 01633 con->execs = poptFreeItems(con->execs, con->numExecs); 01634 con->numExecs = 0; 01635 01636 con->leftovers = _free(con->leftovers); 01637 con->finalArgv = _free(con->finalArgv); 01638 con->appName = _free(con->appName); 01639 con->otherHelp = _free(con->otherHelp); 01640 con->execPath = _free(con->execPath); 01641 con->arg_strip = PBM_FREE(con->arg_strip); 01642 01643 con = _free(con); 01644 return con; 01645 } 01646 01647 int poptAddAlias(poptContext con, struct poptAlias alias, 01648 /*@unused@*/ UNUSED(int flags)) 01649 { 01650 struct poptItem_s item_buf; 01651 poptItem item = &item_buf; 01652 01653 if (con == NULL) return 1; 01654 01655 memset(item, 0, sizeof(*item)); 01656 item->option.longName = alias.longName; 01657 item->option.shortName = alias.shortName; 01658 item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN; 01659 item->option.arg = 0; 01660 item->option.val = 0; 01661 item->option.descrip = NULL; 01662 item->option.argDescrip = NULL; 01663 item->argc = alias.argc; 01664 item->argv = alias.argv; 01665 return poptAddItem(con, item, 0); 01666 } 01667 01668 int poptAddItem(poptContext con, poptItem newItem, int flags) 01669 { 01670 poptItem * items, item; 01671 int * nitems; 01672 01673 if (con == NULL) return 1; 01674 01675 switch (flags) { 01676 case 1: 01677 items = &con->execs; 01678 nitems = &con->numExecs; 01679 break; 01680 case 0: 01681 items = &con->aliases; 01682 nitems = &con->numAliases; 01683 break; 01684 default: 01685 return 1; 01686 /*@notreached@*/ break; 01687 } 01688 01689 *items = realloc((*items), ((*nitems) + 1) * sizeof(**items)); 01690 if ((*items) == NULL) 01691 return 1; 01692 01693 item = (*items) + (*nitems); 01694 01695 item->option.longName = 01696 (newItem->option.longName ? xstrdup(newItem->option.longName) : NULL); 01697 item->option.shortName = newItem->option.shortName; 01698 item->option.argInfo = newItem->option.argInfo; 01699 item->option.arg = newItem->option.arg; 01700 item->option.val = newItem->option.val; 01701 item->option.descrip = 01702 (newItem->option.descrip ? xstrdup(newItem->option.descrip) : NULL); 01703 item->option.argDescrip = 01704 (newItem->option.argDescrip ? xstrdup(newItem->option.argDescrip) : NULL); 01705 item->argc = newItem->argc; 01706 item->argv = newItem->argv; 01707 01708 (*nitems)++; 01709 01710 return 0; 01711 } 01712 01713 const char * poptBadOption(poptContext con, unsigned int flags) 01714 { 01715 struct optionStackEntry * os; 01716 01717 if (!con) 01718 return NULL; 01719 01720 os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os; 01721 if (!os) 01722 return NULL; 01723 01724 if (con->doExec && con->doExec->argv && !os->nextCharArg && os->next == os->argc) 01725 return con->doExec->argv[0]; 01726 01727 return ((os->argv && (os->next > 0)) ? os->argv[os->next - 1] : NULL); 01728 } 01729 01730 const char * poptStrerror(const int error) 01731 { 01732 switch (error) { 01733 case POPT_ERROR_NOARG: 01734 return POPT_("missing argument"); 01735 case POPT_ERROR_BADOPT: 01736 return POPT_("unknown option"); 01737 case POPT_ERROR_BADOPERATION: 01738 return POPT_("mutually exclusive logical operations requested"); 01739 case POPT_ERROR_NULLARG: 01740 return POPT_("opt->arg should not be NULL"); 01741 case POPT_ERROR_OPTSTOODEEP: 01742 return POPT_("aliases nested too deeply"); 01743 case POPT_ERROR_BADQUOTE: 01744 return POPT_("error in parameter quoting"); 01745 case POPT_ERROR_BADNUMBER: 01746 return POPT_("invalid numeric value"); 01747 case POPT_ERROR_OVERFLOW: 01748 return POPT_("number too large or too small"); 01749 case POPT_ERROR_MALLOC: 01750 return POPT_("memory allocation failed"); 01751 case POPT_ERROR_BADCONFIG: 01752 return POPT_("config file failed sanity test"); 01753 case POPT_ERROR_ERRNO: 01754 return strerror(errno); 01755 case POPT_ERROR_NOCONTEXT: 01756 return POPT_("no context"); 01757 default: 01758 return POPT_("unknown error"); 01759 } 01760 } 01761 01762 int poptStuffArgs(poptContext con, const char ** argv) 01763 { 01764 int argc; 01765 int rc; 01766 01767 if (con == NULL) 01768 return POPT_ERROR_NOCONTEXT; 01769 01770 if ((con->os - con->optionStack) == POPT_OPTION_DEPTH) 01771 return POPT_ERROR_OPTSTOODEEP; 01772 01773 for (argc = 0; argv[argc]; argc++) 01774 {}; 01775 01776 con->os++; 01777 con->os->next = 0; 01778 con->os->nextArg = NULL; 01779 con->os->nextCharArg = NULL; 01780 con->os->currAlias = NULL; 01781 rc = poptDupArgv(argc, argv, &con->os->argc, &con->os->argv); 01782 con->os->argb = NULL; 01783 con->os->stuffed = 1; 01784 01785 return rc; 01786 } 01787 01788 const char * poptGetInvocationName(poptContext con) 01789 { 01790 return ((con && con->os->argv) ? con->os->argv[0] : ""); 01791 } 01792 01793 int poptStrippedArgv(poptContext con, int argc, char ** argv) 01794 { 01795 int numargs = argc; 01796 int j = 1; 01797 int i; 01798 01799 /*@-sizeoftype@*/ 01800 if (con && con->arg_strip) 01801 for (i = 1; i < argc; i++) { 01802 if (PBM_ISSET(i, con->arg_strip)) 01803 numargs--; 01804 } 01805 01806 for (i = 1; i < argc; i++) { 01807 if (con && con->arg_strip && PBM_ISSET(i, con->arg_strip)) 01808 continue; 01809 argv[j] = (j < numargs) ? argv[i] : NULL; 01810 j++; 01811 } 01812 /*@=sizeoftype@*/ 01813 01814 return numargs; 01815 }