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