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