1/** \ingroup popt 2 * \file popt/popt.c 3 */ 4 5/* (C) 19982000 Red Hat, Inc. -- Licensing details are in the COPYING 6 file accompanying popt source distributions, available from 7 ftp://ftp.rpm.org/pub/rpm/dist */ 8 9#undef MYDEBUG 10 11#include "system.h" 12 13#if HAVE_FLOAT_H 14#include <float.h> 15#endif 16#include <math.h> 17 18#include "findme.h" 19#include "poptint.h" 20 21#ifndef HAVE_STRERROR 22static char * strerror(int errno) { 23 extern int sys_nerr; 24 extern char * sys_errlist[]; 25 26 if ((0 <= errno) && (errno < sys_nerr)) 27 return sys_errlist[errno]; 28 else 29 return POPT_("unknown errno"); 30} 31#endif 32 33#ifdef MYDEBUG 34/*@unused@*/ static void prtcon(const char *msg, poptContext con) 35{ 36 if (msg) fprintf(stderr, "%s", msg); 37 fprintf(stderr, "\tcon %p os %p nextCharArg \"%s\" nextArg \"%s\" argv[%d] \"%s\"\n", 38 con, con->os, 39 (con->os->nextCharArg ? con->os->nextCharArg : ""), 40 (con->os->nextArg ? con->os->nextArg : ""), 41 con->os->next, 42 (con->os->argv && con->os->argv[con->os->next] 43 ? con->os->argv[con->os->next] : "")); 44} 45#endif 46 47void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) 48{ 49 con->execPath = _free(con->execPath); 50 con->execPath = xstrdup(path); 51 con->execAbsolute = allowAbsolute; 52 /*@-nullstate@*/ /* LCL: con->execPath can be NULL? */ 53 return; 54 /*@=nullstate@*/ 55} 56 57static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt) 58 /*@globals internalState@*/ 59 /*@modifies internalState@*/ 60{ 61 if (opt != NULL) 62 for (; opt->longName || opt->shortName || opt->arg; opt++) { 63 if (opt->arg == NULL) continue; /* XXX program error. */ 64 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { 65 /* Recurse on included sub-tables. */ 66 invokeCallbacksPRE(con, opt->arg); 67 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && 68 (opt->argInfo & POPT_CBFLAG_PRE)) 69 { /*@-castfcnptr@*/ 70 poptCallbackType cb = (poptCallbackType)opt->arg; 71 /*@=castfcnptr@*/ 72 /* Perform callback. */ 73 /*@-moduncon -noeffectuncon @*/ 74 cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip); 75 /*@=moduncon =noeffectuncon @*/ 76 } 77 } 78} 79 80static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt) 81 /*@globals internalState@*/ 82 /*@modifies internalState@*/ 83{ 84 if (opt != NULL) 85 for (; opt->longName || opt->shortName || opt->arg; opt++) { 86 if (opt->arg == NULL) continue; /* XXX program error. */ 87 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { 88 /* Recurse on included sub-tables. */ 89 invokeCallbacksPOST(con, opt->arg); 90 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && 91 (opt->argInfo & POPT_CBFLAG_POST)) 92 { /*@-castfcnptr@*/ 93 poptCallbackType cb = (poptCallbackType)opt->arg; 94 /*@=castfcnptr@*/ 95 /* Perform callback. */ 96 /*@-moduncon -noeffectuncon @*/ 97 cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip); 98 /*@=moduncon =noeffectuncon @*/ 99 } 100 } 101} 102 103static void invokeCallbacksOPTION(poptContext con, 104 const struct poptOption * opt, 105 const struct poptOption * myOpt, 106 /*@null@*/ const void * myData, int shorty) 107 /*@globals internalState@*/ 108 /*@modifies internalState@*/ 109{ 110 const struct poptOption * cbopt = NULL; 111 112 if (opt != NULL) 113 for (; opt->longName || opt->shortName || opt->arg; opt++) { 114 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { 115 /* Recurse on included sub-tables. */ 116 if (opt->arg != NULL) /* XXX program error */ 117 invokeCallbacksOPTION(con, opt->arg, myOpt, myData, shorty); 118 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && 119 !(opt->argInfo & POPT_CBFLAG_SKIPOPTION)) { 120 /* Save callback info. */ 121 cbopt = opt; 122 } else if (cbopt != NULL && 123 ((myOpt->shortName && opt->shortName && shorty && 124 myOpt->shortName == opt->shortName) || 125 (myOpt->longName && opt->longName && 126 /*@-nullpass@*/ /* LCL: opt->longName != NULL */ 127 !strcmp(myOpt->longName, opt->longName))) 128 /*@=nullpass@*/ 129 ) 130 { /*@-castfcnptr@*/ 131 poptCallbackType cb = (poptCallbackType)cbopt->arg; 132 /*@=castfcnptr@*/ 133 const void * cbData = (cbopt->descrip ? cbopt->descrip : myData); 134 /* Perform callback. */ 135 if (cb != NULL) { /* XXX program error */ 136 /*@-moduncon -noeffectuncon @*/ 137 cb(con, POPT_CALLBACK_REASON_OPTION, myOpt, 138 con->os->nextArg, cbData); 139 /*@=moduncon =noeffectuncon @*/ 140 } 141 /* Terminate (unless explcitly continuing). */ 142 if (!(cbopt->argInfo & POPT_CBFLAG_CONTINUE)) 143 return; 144 } 145 } 146} 147 148poptContext poptGetContext(const char * name, int argc, const char ** argv, 149 const struct poptOption * options, int flags) 150{ 151 poptContext con = malloc(sizeof(*con)); 152 153 if (con == NULL) return NULL; /* XXX can't happen */ 154 memset(con, 0, sizeof(*con)); 155 156 con->os = con->optionStack; 157 con->os->argc = argc; 158 /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ 159 con->os->argv = argv; 160 /*@=dependenttrans =assignexpose@*/ 161 con->os->argb = NULL; 162 163 if (!(flags & POPT_CONTEXT_KEEP_FIRST)) 164 con->os->next = 1; /* skip argv[0] */ 165 166 con->leftovers = calloc( (argc + 1), sizeof(*con->leftovers) ); 167 /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ 168 con->options = options; 169 /*@=dependenttrans =assignexpose@*/ 170 con->aliases = NULL; 171 con->numAliases = 0; 172 con->flags = flags; 173 con->execs = NULL; 174 con->numExecs = 0; 175 con->finalArgvAlloced = argc * 2; 176 con->finalArgv = calloc( con->finalArgvAlloced, sizeof(*con->finalArgv) ); 177 con->execAbsolute = 1; 178 con->arg_strip = NULL; 179 180 if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER")) 181 con->flags |= POPT_CONTEXT_POSIXMEHARDER; 182 183 if (name) { 184 char * t = malloc(strlen(name) + 1); 185 if (t) con->appName = strcpy(t, name); 186 } 187 188 /*@-internalglobs@*/ 189 invokeCallbacksPRE(con, con->options); 190 /*@=internalglobs@*/ 191 192 return con; 193} 194 195static void cleanOSE(/*@special@*/ struct optionStackEntry *os) 196 /*@uses os @*/ 197 /*@releases os->nextArg, os->argv, os->argb @*/ 198 /*@modifies os @*/ 199{ 200 os->nextArg = _free(os->nextArg); 201 os->argv = _free(os->argv); 202 os->argb = PBM_FREE(os->argb); 203} 204 205void poptResetContext(poptContext con) 206{ 207 int i; 208 209 if (con == NULL) return; 210 while (con->os > con->optionStack) { 211 cleanOSE(con->os--); 212 } 213 con->os->argb = PBM_FREE(con->os->argb); 214 con->os->currAlias = NULL; 215 con->os->nextCharArg = NULL; 216 con->os->nextArg = NULL; 217 con->os->next = 1; /* skip argv[0] */ 218 219 con->numLeftovers = 0; 220 con->nextLeftover = 0; 221 con->restLeftover = 0; 222 con->doExec = NULL; 223 224 if (con->finalArgv != NULL) 225 for (i = 0; i < con->finalArgvCount; i++) 226 /*@-unqualifiedtrans@*/ /* FIX: typedef double indirection. */ 227 con->finalArgv[i] = _free(con->finalArgv[i]); 228 /*@=unqualifiedtrans@*/ 229 230 con->finalArgvCount = 0; 231 con->arg_strip = PBM_FREE(con->arg_strip); 232 /*@-nullstate@*/ /* FIX: con->finalArgv != NULL */ 233 return; 234 /*@=nullstate@*/ 235} 236 237/* Only one of longName, shortName should be set, not both. */ 238static int handleExec(/*@special@*/ poptContext con, 239 /*@null@*/ const char * longName, char shortName) 240 /*@uses con->execs, con->numExecs, con->flags, con->doExec, 241 con->finalArgv, con->finalArgvAlloced, con->finalArgvCount @*/ 242 /*@modifies con @*/ 243{ 244 poptItem item; 245 int i; 246 247 if (con->execs == NULL || con->numExecs <= 0) /* XXX can't happen */ 248 return 0; 249 250 for (i = con->numExecs - 1; i >= 0; i--) { 251 item = con->execs + i; 252 if (longName && !(item->option.longName && 253 !strcmp(longName, item->option.longName))) 254 continue; 255 else if (shortName != item->option.shortName) 256 continue; 257 break; 258 } 259 if (i < 0) return 0; 260 261 262 if (con->flags & POPT_CONTEXT_NO_EXEC) 263 return 1; 264 265 if (con->doExec == NULL) { 266 con->doExec = con->execs + i; 267 return 1; 268 } 269 270 /* We already have an exec to do; remember this option for next 271 time 'round */ 272 if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) { 273 con->finalArgvAlloced += 10; 274 con->finalArgv = realloc(con->finalArgv, 275 sizeof(*con->finalArgv) * con->finalArgvAlloced); 276 } 277 278 i = con->finalArgvCount++; 279 if (con->finalArgv != NULL) /* XXX can't happen */ 280 { char *s = malloc((longName ? strlen(longName) : 0) + 3); 281 if (s != NULL) { /* XXX can't happen */ 282 if (longName) 283 sprintf(s, "--%s", longName); 284 else 285 sprintf(s, "-%c", shortName); 286 con->finalArgv[i] = s; 287 } else 288 con->finalArgv[i] = NULL; 289 } 290 291 /*@-nullstate@*/ /* FIX: con->finalArgv[] == NULL */ 292 return 1; 293 /*@=nullstate@*/ 294} 295 296/* Only one of longName, shortName may be set at a time */ 297static int handleAlias(/*@special@*/ poptContext con, 298 /*@null@*/ const char * longName, char shortName, 299 /*@keep@*/ /*@null@*/ const char * nextCharArg) 300 /*@uses con->aliases, con->numAliases, con->optionStack, con->os, 301 con->os->currAlias, con->os->currAlias->option.longName @*/ 302 /*@modifies con @*/ 303{ 304 poptItem item = con->os->currAlias; 305 int rc; 306 int i; 307 308 if (item) { 309 if (longName && (item->option.longName && 310 !strcmp(longName, item->option.longName))) 311 return 0; 312 if (shortName && shortName == item->option.shortName) 313 return 0; 314 } 315 316 if (con->aliases == NULL || con->numAliases <= 0) /* XXX can't happen */ 317 return 0; 318 319 for (i = con->numAliases - 1; i >= 0; i--) { 320 item = con->aliases + i; 321 if (longName && !(item->option.longName && 322 !strcmp(longName, item->option.longName))) 323 continue; 324 else if (shortName != item->option.shortName) 325 continue; 326 break; 327 } 328 if (i < 0) return 0; 329 330 if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH) 331 return POPT_ERROR_OPTSTOODEEP; 332 333 if (nextCharArg && *nextCharArg) 334 con->os->nextCharArg = nextCharArg; 335 336 con->os++; 337 con->os->next = 0; 338 con->os->stuffed = 0; 339 con->os->nextArg = NULL; 340 con->os->nextCharArg = NULL; 341 con->os->currAlias = con->aliases + i; 342 rc = poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv, 343 &con->os->argc, &con->os->argv); 344 con->os->argb = NULL; 345 346 return (rc ? rc : 1); 347} 348 349static int execCommand(poptContext con) 350 /*@*/ 351{ 352 poptItem item = con->doExec; 353 const char ** argv; 354 int argc = 0; 355 int rc; 356 357 if (item == NULL) /*XXX can't happen*/ 358 return POPT_ERROR_NOARG; 359 360 if (item->argv == NULL || item->argc < 1 || 361 (!con->execAbsolute && strchr(item->argv[0], '/'))) 362 return POPT_ERROR_NOARG; 363 364 argv = malloc(sizeof(*argv) * 365 (6 + item->argc + con->numLeftovers + con->finalArgvCount)); 366 if (argv == NULL) return POPT_ERROR_MALLOC; /* XXX can't happen */ 367 368 if (!strchr(item->argv[0], '/') && con->execPath) { 369 char *s = alloca(strlen(con->execPath) + strlen(item->argv[0]) + sizeof("/")); 370 sprintf(s, "%s/%s", con->execPath, item->argv[0]); 371 argv[argc] = s; 372 } else { 373 argv[argc] = findProgramPath(item->argv[0]); 374 } 375 if (argv[argc++] == NULL) return POPT_ERROR_NOARG; 376 377 if (item->argc > 1) { 378 memcpy(argv + argc, item->argv + 1, sizeof(*argv) * (item->argc - 1)); 379 argc += (item->argc - 1); 380 } 381 382 if (con->finalArgv != NULL && con->finalArgvCount > 0) { 383 memcpy(argv + argc, con->finalArgv, 384 sizeof(*argv) * con->finalArgvCount); 385 argc += con->finalArgvCount; 386 } 387 388 if (con->leftovers != NULL && con->numLeftovers > 0) { 389#if 0 390 argv[argc++] = "--"; 391#endif 392 memcpy(argv + argc, con->leftovers, sizeof(*argv) * con->numLeftovers); 393 argc += con->numLeftovers; 394 } 395 396 argv[argc] = NULL; 397 398#ifdef __hpux 399 rc = setresuid(getuid(), getuid(),-1); 400 if (rc) return POPT_ERROR_ERRNO; 401#else 402/* 403 * XXX " ... on BSD systems setuid() should be preferred over setreuid()" 404 * XXX sez' Timur Bakeyev <mc@bat.ru> 405 * XXX from Norbert Warmuth <nwarmuth@privat.circular.de> 406 */ 407#if defined(HAVE_SETUID) 408 rc = setuid(getuid()); 409 if (rc) return POPT_ERROR_ERRNO; 410#elif defined (HAVE_SETREUID) 411 rc = setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */ 412 if (rc) return POPT_ERROR_ERRNO; 413#else 414 ; /* Can't drop privileges */ 415#endif 416#endif 417 418 if (argv[0] == NULL) 419 return POPT_ERROR_NOARG; 420#ifdef MYDEBUG 421 { const char ** avp; 422 fprintf(stderr, "==> execvp(%s) argv[%d]:", argv[0], argc); 423 for (avp = argv; *avp; avp++) 424 fprintf(stderr, " '%s'", *avp); 425 fprintf(stderr, "\n"); 426 } 427#endif 428 429 rc = execvp(argv[0], (char *const *)argv); 430 return POPT_ERROR_ERRNO; 431} 432 433/*@observer@*/ /*@null@*/ static const struct poptOption * 434findOption(const struct poptOption * opt, /*@null@*/ const char * longName, 435 char shortName, 436 /*@null@*/ /*@out@*/ poptCallbackType * callback, 437 /*@null@*/ /*@out@*/ const void ** callbackData, 438 int singleDash) 439 /*@modifies *callback, *callbackData */ 440{ 441 const struct poptOption * cb = NULL; 442 443 /* This happens when a single - is given */ 444 if (singleDash && !shortName && (longName && *longName == '\0')) 445 shortName = '-'; 446 447 for (; opt->longName || opt->shortName || opt->arg; opt++) { 448 449 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { 450 const struct poptOption * opt2; 451 452 /* Recurse on included sub-tables. */ 453 if (opt->arg == NULL) continue; /* XXX program error */ 454 opt2 = findOption(opt->arg, longName, shortName, callback, 455 callbackData, singleDash); 456 if (opt2 == NULL) continue; 457 /* Sub-table data will be inheirited if no data yet. */ 458 if (!(callback && *callback)) return opt2; 459 if (!(callbackData && *callbackData == NULL)) return opt2; 460 /*@-observertrans -dependenttrans @*/ 461 *callbackData = opt->descrip; 462 /*@=observertrans =dependenttrans @*/ 463 return opt2; 464 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) { 465 cb = opt; 466 } else if (longName && opt->longName && 467 (!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) && 468 /*@-nullpass@*/ /* LCL: opt->longName != NULL */ 469 !strcmp(longName, opt->longName)) 470 /*@=nullpass@*/ 471 { 472 break; 473 } else if (shortName && shortName == opt->shortName) { 474 break; 475 } 476 } 477 478 if (!opt->longName && !opt->shortName) 479 return NULL; 480 /*@-modobserver -mods @*/ 481 if (callback) *callback = NULL; 482 if (callbackData) *callbackData = NULL; 483 if (cb) { 484 if (callback) 485 /*@-castfcnptr@*/ 486 *callback = (poptCallbackType)cb->arg; 487 /*@=castfcnptr@*/ 488 if (!(cb->argInfo & POPT_CBFLAG_INC_DATA)) { 489 if (callbackData) 490 /*@-observertrans@*/ /* FIX: typedef double indirection. */ 491 *callbackData = cb->descrip; 492 /*@=observertrans@*/ 493 } 494 } 495 /*@=modobserver =mods @*/ 496 497 return opt; 498} 499 500static const char * findNextArg(/*@special@*/ poptContext con, 501 unsigned argx, int delete_arg) 502 /*@uses con->optionStack, con->os, 503 con->os->next, con->os->argb, con->os->argc, con->os->argv @*/ 504 /*@modifies con @*/ 505{ 506 struct optionStackEntry * os = con->os; 507 const char * arg; 508 509 do { 510 int i; 511 arg = NULL; 512 while (os->next == os->argc && os > con->optionStack) os--; 513 if (os->next == os->argc && os == con->optionStack) break; 514 if (os->argv != NULL) 515 for (i = os->next; i < os->argc; i++) { 516 /*@-sizeoftype@*/ 517 if (os->argb && PBM_ISSET(i, os->argb)) 518 /*@innercontinue@*/ continue; 519 if (*os->argv[i] == '-') 520 /*@innercontinue@*/ continue; 521 if (--argx > 0) 522 /*@innercontinue@*/ continue; 523 arg = os->argv[i]; 524 if (delete_arg) { 525 if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc); 526 if (os->argb != NULL) /* XXX can't happen */ 527 PBM_SET(i, os->argb); 528 } 529 /*@innerbreak@*/ break; 530 /*@=sizeoftype@*/ 531 } 532 if (os > con->optionStack) os--; 533 } while (arg == NULL); 534 return arg; 535} 536 537static /*@only@*/ /*@null@*/ const char * 538expandNextArg(/*@special@*/ poptContext con, const char * s) 539 /*@uses con->optionStack, con->os, 540 con->os->next, con->os->argb, con->os->argc, con->os->argv @*/ 541 /*@modifies con @*/ 542{ 543 const char * a = NULL; 544 size_t alen; 545 char *t, *te; 546 size_t tn = strlen(s) + 1; 547 char c; 548 549 te = t = malloc(tn);; 550 if (t == NULL) return NULL; /* XXX can't happen */ 551 while ((c = *s++) != '\0') { 552 switch (c) { 553#if 0 /* XXX can't do this */ 554 case '\\': /* escape */ 555 c = *s++; 556 /*@switchbreak@*/ break; 557#endif 558 case '!': 559 if (!(s[0] == '#' && s[1] == ':' && s[2] == '+')) 560 /*@switchbreak@*/ break; 561 /* XXX Make sure that findNextArg deletes only next arg. */ 562 if (a == NULL) { 563 if ((a = findNextArg(con, 1, 1)) == NULL) 564 /*@switchbreak@*/ break; 565 } 566 s += 3; 567 568 alen = strlen(a); 569 tn += alen; 570 *te = '\0'; 571 t = realloc(t, tn); 572 te = t + strlen(t); 573 strncpy(te, a, alen); te += alen; 574 continue; 575 /*@notreached@*/ /*@switchbreak@*/ break; 576 default: 577 /*@switchbreak@*/ break; 578 } 579 *te++ = c; 580 } 581 *te = '\0'; 582 t = realloc(t, strlen(t) + 1); /* XXX memory leak, hard to plug */ 583 return t; 584} 585 586static void poptStripArg(/*@special@*/ poptContext con, int which) 587 /*@uses con->arg_strip, con->optionStack @*/ 588 /*@defines con->arg_strip @*/ 589 /*@modifies con @*/ 590{ 591 /*@-sizeoftype@*/ 592 if (con->arg_strip == NULL) 593 con->arg_strip = PBM_ALLOC(con->optionStack[0].argc); 594 if (con->arg_strip != NULL) /* XXX can't happen */ 595 PBM_SET(which, con->arg_strip); 596 /*@=sizeoftype@*/ 597 /*@-compdef@*/ /* LCL: con->arg_strip udefined? */ 598 return; 599 /*@=compdef@*/ 600} 601 602static int poptSaveLong(const struct poptOption * opt, long aLong) 603 /*@modifies opt->arg @*/ 604{ 605 if (opt->arg == NULL) 606 return POPT_ERROR_NULLARG; 607 608 if (opt->argInfo & POPT_ARGFLAG_NOT) 609 aLong = ~aLong; 610 switch (opt->argInfo & POPT_ARGFLAG_LOGICALOPS) { 611 case 0: 612 *((long *) opt->arg) = aLong; 613 break; 614 case POPT_ARGFLAG_OR: 615 *((long *) opt->arg) |= aLong; 616 break; 617 case POPT_ARGFLAG_AND: 618 *((long *) opt->arg) &= aLong; 619 break; 620 case POPT_ARGFLAG_XOR: 621 *((long *) opt->arg) ^= aLong; 622 break; 623 default: 624 return POPT_ERROR_BADOPERATION; 625 /*@notreached@*/ break; 626 } 627 return 0; 628} 629 630static int poptSaveInt(const struct poptOption * opt, long aLong) 631 /*@modifies opt->arg @*/ 632{ 633 if (opt->arg == NULL) 634 return POPT_ERROR_NULLARG; 635 636 if (opt->argInfo & POPT_ARGFLAG_NOT) 637 aLong = ~aLong; 638 switch (opt->argInfo & POPT_ARGFLAG_LOGICALOPS) { 639 case 0: 640 *((int *) opt->arg) = aLong; 641 break; 642 case POPT_ARGFLAG_OR: 643 *((int *) opt->arg) |= aLong; 644 break; 645 case POPT_ARGFLAG_AND: 646 *((int *) opt->arg) &= aLong; 647 break; 648 case POPT_ARGFLAG_XOR: 649 *((int *) opt->arg) ^= aLong; 650 break; 651 default: 652 return POPT_ERROR_BADOPERATION; 653 /*@notreached@*/ break; 654 } 655 return 0; 656} 657 658/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */ 659int poptGetNextOpt(poptContext con) 660{ 661 const struct poptOption * opt = NULL; 662 int done = 0; 663 664 if (con == NULL) 665 return -1; 666 while (!done) { 667 const char * origOptString = NULL; 668 poptCallbackType cb = NULL; 669 const void * cbData = NULL; 670 const char * longArg = NULL; 671 int canstrip = 0; 672 int shorty = 0; 673 674 while (!con->os->nextCharArg && con->os->next == con->os->argc 675 && con->os > con->optionStack) { 676 cleanOSE(con->os--); 677 } 678 if (!con->os->nextCharArg && con->os->next == con->os->argc) { 679 /*@-internalglobs@*/ 680 invokeCallbacksPOST(con, con->options); 681 /*@=internalglobs@*/ 682 if (con->doExec) return execCommand(con); 683 return -1; 684 } 685 686 /* Process next long option */ 687 if (!con->os->nextCharArg) { 688 char * localOptString, * optString; 689 int thisopt; 690 691 /*@-sizeoftype@*/ 692 if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) { 693 con->os->next++; 694 continue; 695 } 696 /*@=sizeoftype@*/ 697 thisopt = con->os->next; 698 if (con->os->argv != NULL) /* XXX can't happen */ 699 origOptString = con->os->argv[con->os->next++]; 700 701 if (origOptString == NULL) /* XXX can't happen */ 702 return POPT_ERROR_BADOPT; 703 704 if (con->restLeftover || *origOptString != '-') { 705 if (con->flags & POPT_CONTEXT_POSIXMEHARDER) 706 con->restLeftover = 1; 707 if (con->flags & POPT_CONTEXT_ARG_OPTS) { 708 con->os->nextArg = xstrdup(origOptString); 709 return 0; 710 } 711 if (con->leftovers != NULL) /* XXX can't happen */ 712 con->leftovers[con->numLeftovers++] = origOptString; 713 continue; 714 } 715 716 /* Make a copy we can hack at */ 717 localOptString = optString = 718 strcpy(alloca(strlen(origOptString) + 1), origOptString); 719 720 if (optString[0] == '\0') 721 return POPT_ERROR_BADOPT; 722 723 if (optString[1] == '-' && !optString[2]) { 724 con->restLeftover = 1; 725 continue; 726 } else { 727 char *oe; 728 int singleDash; 729 730 optString++; 731 if (*optString == '-') 732 singleDash = 0, optString++; 733 else 734 singleDash = 1; 735 736 /* XXX aliases with arg substitution need "--alias=arg" */ 737 if (handleAlias(con, optString, '\0', NULL)) 738 continue; 739 740 if (handleExec(con, optString, '\0')) 741 continue; 742 743 /* Check for "--long=arg" option. */ 744 for (oe = optString; *oe && *oe != '='; oe++) 745 {}; 746 if (*oe == '=') { 747 *oe++ = '\0'; 748 /* XXX longArg is mapped back to persistent storage. */ 749 longArg = origOptString + (oe - localOptString); 750 } 751 752 opt = findOption(con->options, optString, '\0', &cb, &cbData, 753 singleDash); 754 if (!opt && !singleDash) 755 return POPT_ERROR_BADOPT; 756 } 757 758 if (!opt) { 759 con->os->nextCharArg = origOptString + 1; 760 } else { 761 if (con->os == con->optionStack && 762 opt->argInfo & POPT_ARGFLAG_STRIP) 763 { 764 canstrip = 1; 765 poptStripArg(con, thisopt); 766 } 767 shorty = 0; 768 } 769 } 770 771 /* Process next short option */ 772 /*@-branchstate@*/ /* FIX: W2DO? */ 773 if (con->os->nextCharArg) { 774 origOptString = con->os->nextCharArg; 775 776 con->os->nextCharArg = NULL; 777 778 if (handleAlias(con, NULL, *origOptString, origOptString + 1)) 779 continue; 780 781 if (handleExec(con, NULL, *origOptString)) { 782 /* Restore rest of short options for further processing */ 783 origOptString++; 784 if (*origOptString != '\0') 785 con->os->nextCharArg = origOptString; 786 continue; 787 } 788 789 opt = findOption(con->options, NULL, *origOptString, &cb, 790 &cbData, 0); 791 if (!opt) 792 return POPT_ERROR_BADOPT; 793 shorty = 1; 794 795 origOptString++; 796 if (*origOptString != '\0') 797 con->os->nextCharArg = origOptString; 798 } 799 /*@=branchstate@*/ 800 801 if (opt == NULL) return POPT_ERROR_BADOPT; /* XXX can't happen */ 802 if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) { 803 if (poptSaveInt(opt, 1L)) 804 return POPT_ERROR_BADOPERATION; 805 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) { 806 if (opt->arg) { 807 if (poptSaveInt(opt, (long)opt->val)) 808 return POPT_ERROR_BADOPERATION; 809 } 810 } else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) { 811 con->os->nextArg = _free(con->os->nextArg); 812 /*@-usedef@*/ /* FIX: W2DO? */ 813 if (longArg) { 814 /*@=usedef@*/ 815 longArg = expandNextArg(con, longArg); 816 con->os->nextArg = longArg; 817 } else if (con->os->nextCharArg) { 818 longArg = expandNextArg(con, con->os->nextCharArg); 819 con->os->nextArg = longArg; 820 con->os->nextCharArg = NULL; 821 } else { 822 while (con->os->next == con->os->argc && 823 con->os > con->optionStack) { 824 cleanOSE(con->os--); 825 } 826 if (con->os->next == con->os->argc) { 827 if (!(opt->argInfo & POPT_ARGFLAG_OPTIONAL)) 828 /*@-compdef@*/ /* FIX: con->os->argv not defined */ 829 return POPT_ERROR_NOARG; 830 /*@=compdef@*/ 831 con->os->nextArg = NULL; 832 } else { 833 834 /* 835 * Make sure this isn't part of a short arg or the 836 * result of an alias expansion. 837 */ 838 if (con->os == con->optionStack && 839 (opt->argInfo & POPT_ARGFLAG_STRIP) && 840 canstrip) { 841 poptStripArg(con, con->os->next); 842 } 843 844 if (con->os->argv != NULL) { /* XXX can't happen */ 845 /* XXX watchout: subtle side-effects live here. */ 846 longArg = con->os->argv[con->os->next++]; 847 longArg = expandNextArg(con, longArg); 848 con->os->nextArg = longArg; 849 } 850 } 851 } 852 longArg = NULL; 853 854 if (opt->arg) { 855 switch (opt->argInfo & POPT_ARG_MASK) { 856 case POPT_ARG_STRING: 857 /* XXX memory leak, hard to plug */ 858 *((const char **) opt->arg) = (con->os->nextArg) 859 ? xstrdup(con->os->nextArg) : NULL; 860 /*@switchbreak@*/ break; 861 862 case POPT_ARG_INT: 863 case POPT_ARG_LONG: 864 { long aLong = 0; 865 char *end; 866 867 if (con->os->nextArg) { 868 aLong = strtol(con->os->nextArg, &end, 0); 869 if (!(end && *end == '\0')) 870 return POPT_ERROR_BADNUMBER; 871 } 872 873 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) { 874 if (aLong == LONG_MIN || aLong == LONG_MAX) 875 return POPT_ERROR_OVERFLOW; 876 if (poptSaveLong(opt, aLong)) 877 return POPT_ERROR_BADOPERATION; 878 } else { 879 if (aLong > INT_MAX || aLong < INT_MIN) 880 return POPT_ERROR_OVERFLOW; 881 if (poptSaveInt(opt, aLong)) 882 return POPT_ERROR_BADOPERATION; 883 } 884 } /*@switchbreak@*/ break; 885 886 case POPT_ARG_FLOAT: 887 case POPT_ARG_DOUBLE: 888 { double aDouble = 0.0; 889 char *end; 890 891 if (con->os->nextArg) { 892 /*@-mods@*/ 893 int saveerrno = errno; 894 errno = 0; 895 aDouble = strtod(con->os->nextArg, &end); 896 if (errno == ERANGE) 897 return POPT_ERROR_OVERFLOW; 898 errno = saveerrno; 899 /*@=mods@*/ 900 if (*end != '\0') 901 return POPT_ERROR_BADNUMBER; 902 } 903 904 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_DOUBLE) { 905 *((double *) opt->arg) = aDouble; 906 } else { 907#ifndef DBL_EPSILON 908#define DBL_EPSILON 2.2204460492503131e-16 909#endif 910#define MY_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a)) 911 if ((MY_ABS(aDouble) - FLT_MAX) > DBL_EPSILON) 912 return POPT_ERROR_OVERFLOW; 913 if ((FLT_MIN - MY_ABS(aDouble)) > DBL_EPSILON) 914 return POPT_ERROR_OVERFLOW; 915 *((float *) opt->arg) = aDouble; 916 } 917 } /*@switchbreak@*/ break; 918 default: 919 fprintf(stdout, 920 POPT_("option type (%d) not implemented in popt\n"), 921 (opt->argInfo & POPT_ARG_MASK)); 922 exit(EXIT_FAILURE); 923 /*@notreached@*/ /*@switchbreak@*/ break; 924 } 925 } 926 } 927 928 if (cb) { 929 /*@-internalglobs@*/ 930 invokeCallbacksOPTION(con, con->options, opt, cbData, shorty); 931 /*@=internalglobs@*/ 932 } else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)) 933 done = 1; 934 935 if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) { 936 con->finalArgvAlloced += 10; 937 con->finalArgv = realloc(con->finalArgv, 938 sizeof(*con->finalArgv) * con->finalArgvAlloced); 939 } 940 941 if (con->finalArgv != NULL) 942 { char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + 3); 943 if (s != NULL) { /* XXX can't happen */ 944 if (opt->longName) 945 sprintf(s, "%s%s", 946 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), 947 opt->longName); 948 else 949 sprintf(s, "-%c", opt->shortName); 950 con->finalArgv[con->finalArgvCount++] = s; 951 } else 952 con->finalArgv[con->finalArgvCount++] = NULL; 953 } 954 955 if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) 956 /*@-ifempty@*/ ; /*@=ifempty@*/ 957 else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) 958 /*@-ifempty@*/ ; /*@=ifempty@*/ 959 else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) { 960 if (con->finalArgv != NULL && con->os->nextArg) 961 con->finalArgv[con->finalArgvCount++] = 962 /*@-nullpass@*/ /* LCL: con->os->nextArg != NULL */ 963 xstrdup(con->os->nextArg); 964 /*@=nullpass@*/ 965 } 966 } 967 968 return (opt ? opt->val : -1); /* XXX can't happen */ 969} 970 971const char * poptGetOptArg(poptContext con) 972{ 973 const char * ret = NULL; 974 /*@-branchstate@*/ 975 if (con) { 976 ret = con->os->nextArg; 977 con->os->nextArg = NULL; 978 } 979 /*@=branchstate@*/ 980 return ret; 981} 982 983const char * poptGetArg(poptContext con) 984{ 985 const char * ret = NULL; 986 if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers) 987 ret = con->leftovers[con->nextLeftover++]; 988 return ret; 989} 990 991const char * poptPeekArg(poptContext con) 992{ 993 const char * ret = NULL; 994 if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers) 995 ret = con->leftovers[con->nextLeftover]; 996 return ret; 997} 998 999const char ** poptGetArgs(poptContext con) 1000{ 1001 if (con == NULL || 1002 con->leftovers == NULL || con->numLeftovers == con->nextLeftover) 1003 return NULL; 1004 1005 /* some apps like [like RPM ;-) ] need this NULL terminated */ 1006 con->leftovers[con->numLeftovers] = NULL; 1007 1008 /*@-nullret -nullstate @*/ /* FIX: typedef double indirection. */ 1009 return (con->leftovers + con->nextLeftover); 1010 /*@=nullret =nullstate @*/ 1011} 1012 1013poptContext poptFreeContext(poptContext con) 1014{ 1015 poptItem item; 1016 int i; 1017 1018 if (con == NULL) return con; 1019 poptResetContext(con); 1020 con->os->argb = _free(con->os->argb); 1021 1022 if (con->aliases != NULL) 1023 for (i = 0; i < con->numAliases; i++) { 1024 item = con->aliases + i; 1025 /*@-modobserver -observertrans -dependenttrans@*/ 1026 item->option.longName = _free(item->option.longName); 1027 item->option.descrip = _free(item->option.descrip); 1028 item->option.argDescrip = _free(item->option.argDescrip); 1029 /*@=modobserver =observertrans =dependenttrans@*/ 1030 item->argv = _free(item->argv); 1031 } 1032 con->aliases = _free(con->aliases); 1033 1034 if (con->execs != NULL) 1035 for (i = 0; i < con->numExecs; i++) { 1036 item = con->execs + i; 1037 /*@-modobserver -observertrans -dependenttrans@*/ 1038 item->option.longName = _free(item->option.longName); 1039 item->option.descrip = _free(item->option.descrip); 1040 item->option.argDescrip = _free(item->option.argDescrip); 1041 /*@=modobserver =observertrans =dependenttrans@*/ 1042 item->argv = _free(item->argv); 1043 } 1044 con->execs = _free(con->execs); 1045 1046 con->leftovers = _free(con->leftovers); 1047 con->finalArgv = _free(con->finalArgv); 1048 con->appName = _free(con->appName); 1049 con->otherHelp = _free(con->otherHelp); 1050 con->execPath = _free(con->execPath); 1051 con->arg_strip = PBM_FREE(con->arg_strip); 1052 1053 con = _free(con); 1054 return con; 1055} 1056 1057int poptAddAlias(poptContext con, struct poptAlias alias, 1058 /*@unused@*/ UNUSED(int flags)) 1059{ 1060 poptItem item = (poptItem) alloca(sizeof(*item)); 1061 memset(item, 0, sizeof(*item)); 1062 item->option.longName = alias.longName; 1063 item->option.shortName = alias.shortName; 1064 item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN; 1065 item->option.arg = 0; 1066 item->option.val = 0; 1067 item->option.descrip = NULL; 1068 item->option.argDescrip = NULL; 1069 item->argc = alias.argc; 1070 item->argv = alias.argv; 1071 return poptAddItem(con, item, 0); 1072} 1073 1074/*@-mustmod@*/ /* LCL: con not modified? */ 1075int poptAddItem(poptContext con, poptItem newItem, int flags) 1076{ 1077 poptItem * items, item; 1078 int * nitems; 1079 1080 switch (flags) { 1081 case 1: 1082 items = &con->execs; 1083 nitems = &con->numExecs; 1084 break; 1085 case 0: 1086 items = &con->aliases; 1087 nitems = &con->numAliases; 1088 break; 1089 default: 1090 return 1; 1091 /*@notreached@*/ break; 1092 } 1093 1094 *items = realloc((*items), ((*nitems) + 1) * sizeof(**items)); 1095 if ((*items) == NULL) 1096 return 1; 1097 1098 item = (*items) + (*nitems); 1099 1100 item->option.longName = 1101 (newItem->option.longName ? xstrdup(newItem->option.longName) : NULL); 1102 item->option.shortName = newItem->option.shortName; 1103 item->option.argInfo = newItem->option.argInfo; 1104 item->option.arg = newItem->option.arg; 1105 item->option.val = newItem->option.val; 1106 item->option.descrip = 1107 (newItem->option.descrip ? xstrdup(newItem->option.descrip) : NULL); 1108 item->option.argDescrip = 1109 (newItem->option.argDescrip ? xstrdup(newItem->option.argDescrip) : NULL); 1110 item->argc = newItem->argc; 1111 item->argv = newItem->argv; 1112 1113 (*nitems)++; 1114 1115 return 0; 1116} 1117/*@=mustmod@*/ 1118 1119const char * poptBadOption(poptContext con, int flags) 1120{ 1121 struct optionStackEntry * os = NULL; 1122 1123 if (con != NULL) 1124 os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os; 1125 1126 /*@-nullderef@*/ /* LCL: os->argv != NULL */ 1127 return (os && os->argv ? os->argv[os->next - 1] : NULL); 1128 /*@=nullderef@*/ 1129} 1130 1131const char * poptStrerror(const int error) 1132{ 1133 switch (error) { 1134 case POPT_ERROR_NOARG: 1135 return POPT_("missing argument"); 1136 case POPT_ERROR_BADOPT: 1137 return POPT_("unknown option"); 1138 case POPT_ERROR_BADOPERATION: 1139 return POPT_("mutually exclusive logical operations requested"); 1140 case POPT_ERROR_NULLARG: 1141 return POPT_("opt->arg should not be NULL"); 1142 case POPT_ERROR_OPTSTOODEEP: 1143 return POPT_("aliases nested too deeply"); 1144 case POPT_ERROR_BADQUOTE: 1145 return POPT_("error in parameter quoting"); 1146 case POPT_ERROR_BADNUMBER: 1147 return POPT_("invalid numeric value"); 1148 case POPT_ERROR_OVERFLOW: 1149 return POPT_("number too large or too small"); 1150 case POPT_ERROR_MALLOC: 1151 return POPT_("memory allocation failed"); 1152 case POPT_ERROR_ERRNO: 1153 return strerror(errno); 1154 default: 1155 return POPT_("unknown error"); 1156 } 1157} 1158 1159int poptStuffArgs(poptContext con, const char ** argv) 1160{ 1161 int argc; 1162 int rc; 1163 1164 if ((con->os - con->optionStack) == POPT_OPTION_DEPTH) 1165 return POPT_ERROR_OPTSTOODEEP; 1166 1167 for (argc = 0; argv[argc]; argc++) 1168 {}; 1169 1170 con->os++; 1171 con->os->next = 0; 1172 con->os->nextArg = NULL; 1173 con->os->nextCharArg = NULL; 1174 con->os->currAlias = NULL; 1175 rc = poptDupArgv(argc, argv, &con->os->argc, &con->os->argv); 1176 con->os->argb = NULL; 1177 con->os->stuffed = 1; 1178 1179 return rc; 1180} 1181 1182const char * poptGetInvocationName(poptContext con) 1183{ 1184 return (con->os->argv ? con->os->argv[0] : ""); 1185} 1186 1187int poptStrippedArgv(poptContext con, int argc, char ** argv) 1188{ 1189 int numargs = argc; 1190 int j = 1; 1191 int i; 1192 1193 /*@-sizeoftype@*/ 1194 if (con->arg_strip) 1195 for (i = 1; i < argc; i++) { 1196 if (PBM_ISSET(i, con->arg_strip)) 1197 numargs--; 1198 } 1199 1200 for (i = 1; i < argc; i++) { 1201 if (con->arg_strip && PBM_ISSET(i, con->arg_strip)) 1202 continue; 1203 argv[j] = (j < numargs) ? argv[i] : NULL; 1204 j++; 1205 } 1206 /*@=sizeoftype@*/ 1207 1208 return numargs; 1209} 1210