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