1 /* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
2 file accompanying popt source distributions, available from
3 ftp://ftp.redhat.com/pub/code/popt */
11 void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) {
12 if (con->execPath) free(con->execPath);
13 con->execPath = g_strdup(path);
14 con->execAbsolute = allowAbsolute;
17 static void invokeCallbacks(poptContext con, const struct poptOption * table,
19 const struct poptOption * opt = table;
22 while (opt->longName || opt->shortName || opt->arg) {
23 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
24 invokeCallbacks(con, opt->arg, post);
25 } else if (((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) &&
26 ((!post && (opt->argInfo & POPT_CBFLAG_PRE)) ||
27 ( post && (opt->argInfo & POPT_CBFLAG_POST)))) {
28 cb = (poptCallbackType)opt->arg;
29 cb(con, post ? POPT_CALLBACK_REASON_POST : POPT_CALLBACK_REASON_PRE,
30 NULL, NULL, opt->descrip);
36 poptContext poptGetContext(char * name, int argc, char ** argv,
37 const struct poptOption * options, int flags) {
38 poptContext con = malloc(sizeof(*con));
40 memset(con, 0, sizeof(*con));
42 con->os = con->optionStack;
46 if (!(flags & POPT_CONTEXT_KEEP_FIRST))
47 con->os->next = 1; /* skip argv[0] */
49 con->leftovers = malloc(sizeof(char *) * (argc + 1));
50 con->options = options;
51 con->finalArgv = malloc(sizeof(*con->finalArgv) * (argc * 2));
52 con->finalArgvAlloced = argc * 2;
54 con->execAbsolute = 1;
56 if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
57 con->flags |= POPT_CONTEXT_POSIXMEHARDER;
60 con->appName = strcpy(malloc(strlen(name) + 1), name);
62 invokeCallbacks(con, con->options, 0);
67 void poptResetContext(poptContext con) {
70 con->os = con->optionStack;
71 con->os->currAlias = NULL;
72 con->os->nextCharArg = NULL;
73 con->os->nextArg = NULL;
74 con->os->next = 1; /* skip argv[0] */
76 con->numLeftovers = 0;
77 con->nextLeftover = 0;
78 con->restLeftover = 0;
81 for (i = 0; i < con->finalArgvCount; i++)
82 free(con->finalArgv[i]);
84 con->finalArgvCount = 0;
87 /* Only one of longName, shortName may be set at a time */
88 static int handleExec(poptContext con, char * longName, char shortName) {
91 i = con->numExecs - 1;
93 while (i >= 0 && (!con->execs[i].longName ||
94 strcmp(con->execs[i].longName, longName))) i--;
97 con->execs[i].shortName != shortName) i--;
102 if (con->flags & POPT_CONTEXT_NO_EXEC)
106 con->doExec = con->execs + i;
110 /* We already have an exec to do; remember this option for next
112 if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) {
113 con->finalArgvAlloced += 10;
114 con->finalArgv = realloc(con->finalArgv,
115 sizeof(*con->finalArgv) * con->finalArgvAlloced);
118 i = con->finalArgvCount++;
119 con->finalArgv[i] = malloc((longName ? strlen(longName) : 0) + 3);
121 sprintf(con->finalArgv[i], "--%s", longName);
123 sprintf(con->finalArgv[i], "-%c", shortName);
128 /* Only one of longName, shortName may be set at a time */
129 static int handleAlias(poptContext con, char * longName, char shortName,
130 char * nextCharArg) {
133 if (con->os->currAlias && con->os->currAlias->longName && longName &&
134 !strcmp(con->os->currAlias->longName, longName))
136 if (con->os->currAlias && shortName &&
137 shortName == con->os->currAlias->shortName)
140 i = con->numAliases - 1;
142 while (i >= 0 && (!con->aliases[i].longName ||
143 strcmp(con->aliases[i].longName, longName))) i--;
146 con->aliases[i].shortName != shortName) i--;
151 if ((con->os - con->optionStack + 1)
152 == POPT_OPTION_DEPTH)
153 return POPT_ERROR_OPTSTOODEEP;
155 if (nextCharArg && *nextCharArg)
156 con->os->nextCharArg = nextCharArg;
160 con->os->stuffed = 0;
161 con->os->nextArg = con->os->nextCharArg = NULL;
162 con->os->currAlias = con->aliases + i;
163 con->os->argc = con->os->currAlias->argc;
164 con->os->argv = con->os->currAlias->argv;
169 static void execCommand(poptContext con) {
172 char * script = con->doExec->script;
174 argv = malloc(sizeof(*argv) *
175 (6 + con->numLeftovers + con->finalArgvCount));
177 if (!con->execAbsolute && strchr(script, '/')) return;
179 if (!strchr(script, '/') && con->execPath) {
180 argv[pos] = g_strdup_printf("%s/%s", con->execPath, script);
186 argv[pos] = findProgramPath(con->os->argv[0]);
187 if (argv[pos]) pos++;
190 memcpy(argv + pos, con->finalArgv, sizeof(*argv) * con->finalArgvCount);
191 pos += con->finalArgvCount;
193 if (con->numLeftovers) {
195 memcpy(argv + pos, con->leftovers, sizeof(*argv) * con->numLeftovers);
196 pos += con->numLeftovers;
202 setresuid(getuid(), getuid(),-1);
205 * XXX " ... on BSD systems setuid() should be preferred over setreuid()"
206 * XXX sez' Timur Bakeyev <mc@bat.ru>
207 * XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
209 #if defined(HAVE_SETUID)
211 #elif defined (HAVE_SETREUID)
212 setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
214 ; /* Can't drop privileges */
218 execvp(argv[0], argv);
221 static const struct poptOption * findOption(const struct poptOption * table,
222 const char * longName,
224 poptCallbackType * callback,
225 void ** callbackData,
227 const struct poptOption * opt = table;
228 const struct poptOption * opt2;
229 const struct poptOption * cb = NULL;
231 /* This happens when a single - is given */
232 if (singleDash && !shortName && !*longName)
235 while (opt->longName || opt->shortName || opt->arg) {
236 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
237 opt2 = findOption(opt->arg, longName, shortName, callback,
238 callbackData, singleDash);
240 if (*callback && !*callbackData)
241 *callbackData = opt->descrip;
244 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) {
246 } else if (longName && opt->longName &&
247 (!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) &&
248 !strcmp(longName, opt->longName)) {
250 } else if (shortName && shortName == opt->shortName) {
256 if (!opt->longName && !opt->shortName) return NULL;
257 *callbackData = NULL;
260 *callback = (poptCallbackType)cb->arg;
261 if (!(cb->argInfo & POPT_CBFLAG_INC_DATA))
262 *callbackData = cb->descrip;
268 /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
269 int poptGetNextOpt(poptContext con) {
270 char * optString, * chptr, * localOptString;
271 char * longArg = NULL;
272 char * origOptString, *dup;
275 const struct poptOption * opt = NULL;
288 while (!con->os->nextCharArg && con->os->next == con->os->argc
289 && con->os > con->optionStack)
291 if (!con->os->nextCharArg && con->os->next == con->os->argc) {
292 invokeCallbacks(con, con->options, 1);
293 if (con->doExec) execCommand(con);
297 if (!con->os->nextCharArg) {
299 origOptString = con->os->argv[con->os->next++];
301 if (con->restLeftover || *origOptString != '-') {
302 con->leftovers[con->numLeftovers++] = origOptString;
303 if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
304 con->restLeftover = 1;
308 /* Make a copy we can hack at */
309 dup = localOptString = optString =
310 g_strdup(origOptString);
314 return POPT_ERROR_BADOPT;
317 if (optString[1] == '-' && !optString[2]) {
318 con->restLeftover = 1;
322 if (*optString == '-')
323 singleDash = 0, optString++;
327 if (handleAlias(con, optString, '\0', NULL))
329 if (handleExec(con, optString, '\0'))
333 while (*chptr && *chptr != '=') chptr++;
335 longArg = origOptString + (chptr - localOptString) + 1;
339 opt = findOption(con->options, optString, '\0', &cb, &cbData,
341 if (!opt && !singleDash) {
343 return POPT_ERROR_BADOPT;
348 con->os->nextCharArg = origOptString + 1;
351 if (con->os->nextCharArg) {
352 origOptString = con->os->nextCharArg;
354 con->os->nextCharArg = NULL;
356 if (handleAlias(con, NULL, *origOptString,
357 origOptString + 1)) {
361 if (handleExec(con, NULL, *origOptString))
364 opt = findOption(con->options, NULL, *origOptString, &cb,
368 return POPT_ERROR_BADOPT;
372 con->os->nextCharArg = origOptString;
375 if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
376 *((int *)opt->arg) = 1;
377 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
378 if (opt->arg) *((int *) opt->arg) = opt->val;
379 } else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
381 con->os->nextArg = longArg;
382 } else if (con->os->nextCharArg) {
383 con->os->nextArg = con->os->nextCharArg;
384 con->os->nextCharArg = NULL;
386 while (con->os->next == con->os->argc &&
387 con->os > con->optionStack)
389 if (con->os->next == con->os->argc) {
391 return POPT_ERROR_NOARG;
394 con->os->nextArg = con->os->argv[con->os->next++];
398 switch (opt->argInfo & POPT_ARG_MASK) {
399 case POPT_ARG_STRING:
400 *((char **) opt->arg) = con->os->nextArg;
405 aLong = strtol(con->os->nextArg, &end, 0);
406 if (!(end && *end == '\0')) {
408 return POPT_ERROR_BADNUMBER;
411 if (aLong == LONG_MIN || aLong == LONG_MAX) {
413 return POPT_ERROR_OVERFLOW;
415 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
416 *((long *) opt->arg) = aLong;
418 if (aLong > INT_MAX || aLong < INT_MIN) {
420 return POPT_ERROR_OVERFLOW;
422 *((int *) opt->arg) =aLong;
427 fprintf(stdout, POPT_("option type (%d) not implemented in popt\n"),
428 opt->argInfo & POPT_ARG_MASK);
435 cb(con, POPT_CALLBACK_REASON_OPTION, opt, con->os->nextArg, cbData);
436 else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
439 if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
440 con->finalArgvAlloced += 10;
441 con->finalArgv = realloc(con->finalArgv,
442 sizeof(*con->finalArgv) * con->finalArgvAlloced);
445 i = con->finalArgvCount++;
447 malloc((opt->longName ? strlen(opt->longName) : 0) + 3);
449 sprintf(con->finalArgv[i], "--%s", opt->longName);
451 sprintf(con->finalArgv[i], "-%c", opt->shortName);
453 if (opt->arg && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE
454 && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)
455 con->finalArgv[con->finalArgvCount++] =
456 strcpy(malloc(strlen(con->os->nextArg)+1), con->os->nextArg);
459 if (dup) g_free(dup);
463 char * poptGetOptArg(poptContext con) {
464 char * ret = con->os->nextArg;
465 con->os->nextArg = NULL;
469 char * poptGetArg(poptContext con) {
470 if (con->numLeftovers == con->nextLeftover) return NULL;
471 return (con->leftovers[con->nextLeftover++]);
474 char * poptPeekArg(poptContext con) {
475 if (con->numLeftovers == con->nextLeftover) return NULL;
476 return (con->leftovers[con->nextLeftover]);
479 char ** poptGetArgs(poptContext con) {
480 if (con->numLeftovers == con->nextLeftover) return NULL;
482 /* some apps like [like RPM ;-) ] need this NULL terminated */
483 con->leftovers[con->numLeftovers] = NULL;
485 return (con->leftovers + con->nextLeftover);
488 void poptFreeContext(poptContext con) {
491 for (i = 0; i < con->numAliases; i++) {
492 if (con->aliases[i].longName) free(con->aliases[i].longName);
493 free(con->aliases[i].argv);
496 for (i = 0; i < con->numExecs; i++) {
497 if (con->execs[i].longName) free(con->execs[i].longName);
498 free(con->execs[i].script);
501 for (i = 0; i < con->finalArgvCount; i++)
502 free(con->finalArgv[i]);
504 free(con->leftovers);
505 free(con->finalArgv);
506 if (con->appName) free(con->appName);
507 if (con->aliases) free(con->aliases);
508 if (con->otherHelp) free(con->otherHelp);
509 if (con->execPath) free(con->execPath);
513 int poptAddAlias(poptContext con, struct poptAlias newAlias, int flags) {
514 int aliasNum = con->numAliases++;
515 struct poptAlias * alias;
517 /* SunOS won't realloc(NULL, ...) */
519 con->aliases = malloc(sizeof(newAlias) * con->numAliases);
521 con->aliases = realloc(con->aliases,
522 sizeof(newAlias) * con->numAliases);
523 alias = con->aliases + aliasNum;
527 alias->longName = strcpy(malloc(strlen(alias->longName) + 1),
530 alias->longName = NULL;
535 char * poptBadOption(poptContext con, int flags) {
536 struct optionStackEntry * os;
538 if (flags & POPT_BADOPTION_NOALIAS)
539 os = con->optionStack;
543 return os->argv[os->next - 1];
546 #define POPT_ERROR_NOARG -10
547 #define POPT_ERROR_BADOPT -11
548 #define POPT_ERROR_OPTSTOODEEP -13
549 #define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
550 #define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
552 const char * poptStrerror(const int error) {
554 case POPT_ERROR_NOARG:
555 return POPT_("missing argument");
556 case POPT_ERROR_BADOPT:
557 return POPT_("unknown option");
558 case POPT_ERROR_OPTSTOODEEP:
559 return POPT_("aliases nested too deeply");
560 case POPT_ERROR_BADQUOTE:
561 return POPT_("error in paramter quoting");
562 case POPT_ERROR_BADNUMBER:
563 return POPT_("invalid numeric value");
564 case POPT_ERROR_OVERFLOW:
565 return POPT_("number too large or too small");
566 case POPT_ERROR_ERRNO:
567 return strerror(errno);
569 return POPT_("unknown error");
573 int poptStuffArgs(poptContext con, char ** argv) {
576 if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
577 return POPT_ERROR_OPTSTOODEEP;
579 for (i = 0; argv[i]; i++);
583 con->os->nextArg = con->os->nextCharArg = NULL;
584 con->os->currAlias = NULL;
586 con->os->argv = argv;
587 con->os->stuffed = 1;
592 const char * poptGetInvocationName(poptContext con) {
593 return con->os->argv[0];