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