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