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