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