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