r5657: Fix uninitialized variable warning
[Samba.git] / source / popt / popt.c
blob9fa8650312cd87cbad54a282dcdec005d3bd17f8
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 */
5 #include "system.h"
6 #include "findme.h"
7 #include "poptint.h"
9 #ifndef HAVE_STRERROR
10 static char * strerror(int errno) {
11 extern int sys_nerr;
12 extern char * sys_errlist[];
14 if ((0 <= errno) && (errno < sys_nerr))
15 return sys_errlist[errno];
16 else
17 return POPT_("unknown errno");
19 #endif
21 void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) {
22 if (con->execPath) xfree(con->execPath);
23 con->execPath = xstrdup(path);
24 con->execAbsolute = allowAbsolute;
27 static void invokeCallbacks(poptContext con, const struct poptOption * table,
28 int post) {
29 const struct poptOption * opt = table;
30 poptCallbackType cb;
32 while (opt->longName || opt->shortName || opt->arg) {
33 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
34 invokeCallbacks(con, opt->arg, post);
35 } else if (((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) &&
36 ((!post && (opt->argInfo & POPT_CBFLAG_PRE)) ||
37 ( post && (opt->argInfo & POPT_CBFLAG_POST)))) {
38 cb = (poptCallbackType)opt->arg;
39 cb(con, post ? POPT_CALLBACK_REASON_POST : POPT_CALLBACK_REASON_PRE,
40 NULL, NULL, opt->descrip);
42 opt++;
46 poptContext poptGetContext(const char * name, int argc, const char ** argv,
47 const struct poptOption * options, int flags) {
48 poptContext con = malloc(sizeof(*con));
50 memset(con, 0, sizeof(*con));
52 con->os = con->optionStack;
53 con->os->argc = argc;
54 con->os->argv = argv;
55 con->os->argb = NULL;
57 if (!(flags & POPT_CONTEXT_KEEP_FIRST))
58 con->os->next = 1; /* skip argv[0] */
60 con->leftovers = calloc( (argc + 1), sizeof(char *) );
61 con->options = options;
62 con->aliases = NULL;
63 con->numAliases = 0;
64 con->flags = flags;
65 con->execs = NULL;
66 con->numExecs = 0;
67 con->finalArgvAlloced = argc * 2;
68 con->finalArgv = calloc( con->finalArgvAlloced, sizeof(*con->finalArgv) );
69 con->execAbsolute = 1;
70 con->arg_strip = NULL;
72 if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
73 con->flags |= POPT_CONTEXT_POSIXMEHARDER;
75 if (name)
76 con->appName = strcpy(malloc(strlen(name) + 1), name);
78 invokeCallbacks(con, con->options, 0);
80 return con;
83 static void cleanOSE(struct optionStackEntry *os)
85 if (os->nextArg) {
86 xfree(os->nextArg);
87 os->nextArg = NULL;
89 if (os->argv) {
90 xfree(os->argv);
91 os->argv = NULL;
93 if (os->argb) {
94 PBM_FREE(os->argb);
95 os->argb = NULL;
99 void poptResetContext(poptContext con) {
100 int i;
102 while (con->os > con->optionStack) {
103 cleanOSE(con->os--);
105 if (con->os->argb) {
106 PBM_FREE(con->os->argb);
107 con->os->argb = NULL;
109 con->os->currAlias = NULL;
110 con->os->nextCharArg = NULL;
111 con->os->nextArg = NULL;
112 con->os->next = 1; /* skip argv[0] */
114 con->numLeftovers = 0;
115 con->nextLeftover = 0;
116 con->restLeftover = 0;
117 con->doExec = NULL;
119 for (i = 0; i < con->finalArgvCount; i++) {
120 if (con->finalArgv[i]) {
121 xfree(con->finalArgv[i]);
122 con->finalArgv[i] = NULL;
126 con->finalArgvCount = 0;
128 if (con->arg_strip) {
129 PBM_FREE(con->arg_strip);
130 con->arg_strip = NULL;
134 /* Only one of longName, shortName may be set at a time */
135 static int handleExec(poptContext con, char * longName, char shortName) {
136 int i;
138 i = con->numExecs - 1;
139 if (longName) {
140 while (i >= 0 && (!con->execs[i].longName ||
141 strcmp(con->execs[i].longName, longName))) i--;
142 } else {
143 while (i >= 0 &&
144 con->execs[i].shortName != shortName) i--;
147 if (i < 0) return 0;
149 if (con->flags & POPT_CONTEXT_NO_EXEC)
150 return 1;
152 if (con->doExec == NULL) {
153 con->doExec = con->execs + i;
154 return 1;
157 /* We already have an exec to do; remember this option for next
158 time 'round */
159 if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) {
160 con->finalArgvAlloced += 10;
161 con->finalArgv = realloc(con->finalArgv,
162 sizeof(*con->finalArgv) * con->finalArgvAlloced);
165 i = con->finalArgvCount++;
166 { char *s = malloc((longName ? strlen(longName) : 0) + 3);
167 if (longName)
168 sprintf(s, "--%s", longName);
169 else
170 sprintf(s, "-%c", shortName);
171 con->finalArgv[i] = s;
174 return 1;
177 /* Only one of longName, shortName may be set at a time */
178 static int handleAlias(poptContext con, const char * longName, char shortName,
179 /*@keep@*/ const char * nextCharArg) {
180 int i;
182 if (con->os->currAlias && con->os->currAlias->longName && longName &&
183 !strcmp(con->os->currAlias->longName, longName))
184 return 0;
185 if (con->os->currAlias && shortName &&
186 shortName == con->os->currAlias->shortName)
187 return 0;
189 i = con->numAliases - 1;
190 if (longName) {
191 while (i >= 0 && (!con->aliases[i].longName ||
192 strcmp(con->aliases[i].longName, longName))) i--;
193 } else {
194 while (i >= 0 &&
195 con->aliases[i].shortName != shortName) i--;
198 if (i < 0) return 0;
200 if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
201 return POPT_ERROR_OPTSTOODEEP;
203 if (nextCharArg && *nextCharArg)
204 con->os->nextCharArg = nextCharArg;
206 con->os++;
207 con->os->next = 0;
208 con->os->stuffed = 0;
209 con->os->nextArg = NULL;
210 con->os->nextCharArg = NULL;
211 con->os->currAlias = con->aliases + i;
212 poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv,
213 &con->os->argc, &con->os->argv);
214 con->os->argb = NULL;
216 return 1;
219 static void execCommand(poptContext con) {
220 const char ** argv;
221 int pos = 0;
222 const char * script = con->doExec->script;
224 argv = malloc(sizeof(*argv) *
225 (6 + con->numLeftovers + con->finalArgvCount));
227 if (!con->execAbsolute && strchr(script, '/')) return;
229 if (!strchr(script, '/') && con->execPath) {
230 char *s = malloc(strlen(con->execPath) + strlen(script) + 2);
231 sprintf(s, "%s/%s", con->execPath, script);
232 argv[pos] = s;
233 } else {
234 argv[pos] = script;
236 pos++;
238 argv[pos] = findProgramPath(con->os->argv[0]);
239 if (argv[pos]) pos++;
240 argv[pos++] = ";";
242 memcpy(argv + pos, con->finalArgv, sizeof(*argv) * con->finalArgvCount);
243 pos += con->finalArgvCount;
245 if (con->numLeftovers) {
246 argv[pos++] = "--";
247 memcpy(argv + pos, con->leftovers, sizeof(*argv) * con->numLeftovers);
248 pos += con->numLeftovers;
251 argv[pos++] = NULL;
253 #ifdef __hpux
254 setresuid(getuid(), getuid(),-1);
255 #else
257 * XXX " ... on BSD systems setuid() should be preferred over setreuid()"
258 * XXX sez' Timur Bakeyev <mc@bat.ru>
259 * XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
261 #if defined(HAVE_SETUID)
262 setuid(getuid());
263 #elif defined (HAVE_SETREUID)
264 setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
265 #else
266 ; /* Can't drop privileges */
267 #endif
268 #endif
270 execvp(argv[0], (char *const *)argv);
273 /*@observer@*/ static const struct poptOption *
274 findOption(const struct poptOption * table, const char * longName,
275 char shortName,
276 /*@out@*/ poptCallbackType * callback, /*@out@*/ const void ** callbackData,
277 int singleDash)
279 const struct poptOption * opt = table;
280 const struct poptOption * opt2;
281 const struct poptOption * cb = NULL;
283 /* This happens when a single - is given */
284 if (singleDash && !shortName && !*longName)
285 shortName = '-';
287 while (opt->longName || opt->shortName || opt->arg) {
288 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
289 opt2 = findOption(opt->arg, longName, shortName, callback,
290 callbackData, singleDash);
291 if (opt2) {
292 if (*callback && !*callbackData)
293 *callbackData = opt->descrip;
294 return opt2;
296 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) {
297 cb = opt;
298 } else if (longName && opt->longName &&
299 (!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) &&
300 !strcmp(longName, opt->longName)) {
301 break;
302 } else if (shortName && shortName == opt->shortName) {
303 break;
305 opt++;
308 if (!opt->longName && !opt->shortName) return NULL;
309 *callbackData = NULL;
310 *callback = NULL;
311 if (cb) {
312 *callback = (poptCallbackType)cb->arg;
313 if (!(cb->argInfo & POPT_CBFLAG_INC_DATA))
314 *callbackData = cb->descrip;
317 return opt;
320 static const char *findNextArg(poptContext con, unsigned argx, int delete)
322 struct optionStackEntry * os = con->os;
323 const char * arg;
325 do {
326 int i;
327 arg = NULL;
328 while (os->next == os->argc && os > con->optionStack) os--;
329 if (os->next == os->argc && os == con->optionStack) break;
330 for (i = os->next; i < os->argc; i++) {
331 if (os->argb && PBM_ISSET(i, os->argb)) continue;
332 if (*os->argv[i] == '-') continue;
333 if (--argx > 0) continue;
334 arg = os->argv[i];
335 if (delete) {
336 if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc);
337 PBM_SET(i, os->argb);
339 break;
341 if (os > con->optionStack) os--;
342 } while (arg == NULL);
343 return arg;
346 static /*@only@*/ const char * expandNextArg(poptContext con, const char * s)
348 const char *a;
349 size_t alen;
350 char *t, *te;
351 size_t tn = strlen(s) + 1;
352 char c;
354 te = t = malloc(tn);;
355 while ((c = *s++) != '\0') {
356 switch (c) {
357 #if 0 /* XXX can't do this */
358 case '\\': /* escape */
359 c = *s++;
360 break;
361 #endif
362 case '!':
363 if (!(s[0] == '#' && s[1] == ':' && s[2] == '+'))
364 break;
365 if ((a = findNextArg(con, 1, 1)) == NULL)
366 break;
367 s += 3;
369 alen = strlen(a);
370 tn += alen;
371 *te = '\0';
372 t = realloc(t, tn);
373 te = t + strlen(t);
374 strncpy(te, a, alen); te += alen;
375 continue;
376 /*@notreached@*/ break;
377 default:
378 break;
380 *te++ = c;
382 *te = '\0';
383 t = realloc(t, strlen(t)+1); /* XXX memory leak, hard to plug */
384 return t;
387 static void poptStripArg(poptContext con, int which)
389 if(con->arg_strip == NULL) {
390 con->arg_strip = PBM_ALLOC(con->optionStack[0].argc);
392 PBM_SET(which, con->arg_strip);
395 /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
396 int poptGetNextOpt(poptContext con)
398 const struct poptOption * opt = NULL;
399 int done = 0;
401 /* looks a bit tricky to get rid of alloca properly in this fn */
402 #if HAVE_ALLOCA_H
403 #define ALLOCA(x) alloca(x)
404 #else
405 #define ALLOCA(x) malloc(x)
406 #endif
409 while (!done) {
410 const char * origOptString = NULL;
411 poptCallbackType cb = NULL;
412 const void * cbData = NULL;
413 const char * longArg = NULL;
414 int canstrip = 0;
416 while (!con->os->nextCharArg && con->os->next == con->os->argc
417 && con->os > con->optionStack) {
418 cleanOSE(con->os--);
420 if (!con->os->nextCharArg && con->os->next == con->os->argc) {
421 invokeCallbacks(con, con->options, 1);
422 if (con->doExec) execCommand(con);
423 return -1;
426 /* Process next long option */
427 if (!con->os->nextCharArg) {
428 char * localOptString, * optString;
429 int thisopt;
431 if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) {
432 con->os->next++;
433 continue;
435 thisopt=con->os->next;
436 origOptString = con->os->argv[con->os->next++];
438 if (con->restLeftover || *origOptString != '-') {
439 con->leftovers[con->numLeftovers++] = origOptString;
440 if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
441 con->restLeftover = 1;
442 continue;
445 /* Make a copy we can hack at */
446 localOptString = optString =
447 strcpy(ALLOCA(strlen(origOptString) + 1),
448 origOptString);
450 if (!optString[0])
451 return POPT_ERROR_BADOPT;
453 if (optString[1] == '-' && !optString[2]) {
454 con->restLeftover = 1;
455 continue;
456 } else {
457 char *oe;
458 int singleDash;
460 optString++;
461 if (*optString == '-')
462 singleDash = 0, optString++;
463 else
464 singleDash = 1;
466 /* XXX aliases with arg substitution need "--alias=arg" */
467 if (handleAlias(con, optString, '\0', NULL))
468 continue;
469 if (handleExec(con, optString, '\0'))
470 continue;
472 /* Check for "--long=arg" option. */
473 for (oe = optString; *oe && *oe != '='; oe++)
475 if (*oe == '=') {
476 *oe++ = '\0';
477 /* XXX longArg is mapped back to persistent storage. */
478 longArg = origOptString + (oe - localOptString);
481 opt = findOption(con->options, optString, '\0', &cb, &cbData,
482 singleDash);
483 if (!opt && !singleDash)
484 return POPT_ERROR_BADOPT;
487 if (!opt) {
488 con->os->nextCharArg = origOptString + 1;
489 } else {
490 if(con->os == con->optionStack &&
491 opt->argInfo & POPT_ARGFLAG_STRIP) {
492 canstrip = 1;
493 poptStripArg(con, thisopt);
498 /* Process next short option */
499 if (con->os->nextCharArg) {
500 origOptString = con->os->nextCharArg;
502 con->os->nextCharArg = NULL;
504 if (handleAlias(con, NULL, *origOptString,
505 origOptString + 1)) {
506 origOptString++;
507 continue;
509 if (handleExec(con, NULL, *origOptString))
510 continue;
512 opt = findOption(con->options, NULL, *origOptString, &cb,
513 &cbData, 0);
514 if (!opt)
515 return POPT_ERROR_BADOPT;
517 origOptString++;
518 if (*origOptString)
519 con->os->nextCharArg = origOptString;
522 if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
523 *((int *)opt->arg) = 1;
524 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
525 if (opt->arg)
526 *((int *) opt->arg) = opt->val;
527 } else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
528 if (con->os->nextArg) {
529 xfree(con->os->nextArg);
530 con->os->nextArg = NULL;
532 if (longArg) {
533 con->os->nextArg = expandNextArg(con, longArg);
534 } else if (con->os->nextCharArg) {
535 con->os->nextArg = expandNextArg(con, con->os->nextCharArg);
536 con->os->nextCharArg = NULL;
537 } else {
538 while (con->os->next == con->os->argc &&
539 con->os > con->optionStack) {
540 cleanOSE(con->os--);
542 if (con->os->next == con->os->argc)
543 return POPT_ERROR_NOARG;
545 /* make sure this isn't part of a short arg or the
546 result of an alias expansion */
547 if(con->os == con->optionStack &&
548 opt->argInfo & POPT_ARGFLAG_STRIP &&
549 canstrip) {
550 poptStripArg(con, con->os->next);
553 con->os->nextArg = expandNextArg(con, con->os->argv[con->os->next++]);
556 if (opt->arg) {
557 long aLong;
558 char *end;
560 switch (opt->argInfo & POPT_ARG_MASK) {
561 case POPT_ARG_STRING:
562 /* XXX memory leak, hard to plug */
563 *((const char **) opt->arg) = xstrdup(con->os->nextArg);
564 break;
566 case POPT_ARG_INT:
567 case POPT_ARG_LONG:
568 aLong = strtol(con->os->nextArg, &end, 0);
569 if (!(end && *end == '\0'))
570 return POPT_ERROR_BADNUMBER;
572 if (aLong == LONG_MIN || aLong == LONG_MAX)
573 return POPT_ERROR_OVERFLOW;
574 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
575 *((long *) opt->arg) = aLong;
576 } else {
577 if (aLong > INT_MAX || aLong < INT_MIN)
578 return POPT_ERROR_OVERFLOW;
579 *((int *) opt->arg) = aLong;
581 break;
583 default:
584 fprintf(stdout, POPT_("option type (%d) not implemented in popt\n"),
585 opt->argInfo & POPT_ARG_MASK);
586 exit(EXIT_FAILURE);
591 if (cb)
592 cb(con, POPT_CALLBACK_REASON_OPTION, opt, con->os->nextArg, cbData);
593 else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
594 done = 1;
596 if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
597 con->finalArgvAlloced += 10;
598 con->finalArgv = realloc(con->finalArgv,
599 sizeof(*con->finalArgv) * con->finalArgvAlloced);
602 { char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + 3);
603 if (opt->longName)
604 sprintf(s, "--%s", opt->longName);
605 else
606 sprintf(s, "-%c", opt->shortName);
607 con->finalArgv[con->finalArgvCount++] = s;
610 if (opt->arg && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE
611 && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL) {
612 con->finalArgv[con->finalArgvCount++] = xstrdup(con->os->nextArg);
616 return opt->val;
619 const char * poptGetOptArg(poptContext con) {
620 const char * ret = con->os->nextArg;
621 con->os->nextArg = NULL;
622 return ret;
625 const char * poptGetArg(poptContext con) {
626 if (con->numLeftovers == con->nextLeftover) return NULL;
627 return con->leftovers[con->nextLeftover++];
630 const char * poptPeekArg(poptContext con) {
631 if (con->numLeftovers == con->nextLeftover) return NULL;
632 return con->leftovers[con->nextLeftover];
635 const char ** poptGetArgs(poptContext con) {
636 if (con->numLeftovers == con->nextLeftover) return NULL;
638 /* some apps like [like RPM ;-) ] need this NULL terminated */
639 con->leftovers[con->numLeftovers] = NULL;
641 return (con->leftovers + con->nextLeftover);
644 void poptFreeContext(poptContext con) {
645 int i;
647 poptResetContext(con);
648 if (con->os->argb) free(con->os->argb);
650 for (i = 0; i < con->numAliases; i++) {
651 if (con->aliases[i].longName) xfree(con->aliases[i].longName);
652 free(con->aliases[i].argv);
655 for (i = 0; i < con->numExecs; i++) {
656 if (con->execs[i].longName) xfree(con->execs[i].longName);
657 xfree(con->execs[i].script);
659 if (con->execs) xfree(con->execs);
661 free(con->leftovers);
662 free(con->finalArgv);
663 if (con->appName) xfree(con->appName);
664 if (con->aliases) free(con->aliases);
665 if (con->otherHelp) xfree(con->otherHelp);
666 if (con->execPath) xfree(con->execPath);
667 if (con->arg_strip) PBM_FREE(con->arg_strip);
669 free(con);
672 int poptAddAlias(poptContext con, struct poptAlias newAlias,
673 /*@unused@*/ int flags)
675 int aliasNum = con->numAliases++;
676 struct poptAlias * alias;
678 /* SunOS won't realloc(NULL, ...) */
679 if (!con->aliases)
680 con->aliases = malloc(sizeof(newAlias) * con->numAliases);
681 else
682 con->aliases = realloc(con->aliases,
683 sizeof(newAlias) * con->numAliases);
684 alias = con->aliases + aliasNum;
686 alias->longName = (newAlias.longName)
687 ? strcpy(malloc(strlen(newAlias.longName) + 1), newAlias.longName)
688 : NULL;
689 alias->shortName = newAlias.shortName;
690 alias->argc = newAlias.argc;
691 alias->argv = newAlias.argv;
693 return 0;
696 const char * poptBadOption(poptContext con, int flags) {
697 struct optionStackEntry * os;
699 if (flags & POPT_BADOPTION_NOALIAS)
700 os = con->optionStack;
701 else
702 os = con->os;
704 return os->argv[os->next - 1];
707 #define POPT_ERROR_NOARG -10
708 #define POPT_ERROR_BADOPT -11
709 #define POPT_ERROR_OPTSTOODEEP -13
710 #define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
711 #define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
713 const char *poptStrerror(const int error) {
714 switch (error) {
715 case POPT_ERROR_NOARG:
716 return POPT_("missing argument");
717 case POPT_ERROR_BADOPT:
718 return POPT_("unknown option");
719 case POPT_ERROR_OPTSTOODEEP:
720 return POPT_("aliases nested too deeply");
721 case POPT_ERROR_BADQUOTE:
722 return POPT_("error in paramter quoting");
723 case POPT_ERROR_BADNUMBER:
724 return POPT_("invalid numeric value");
725 case POPT_ERROR_OVERFLOW:
726 return POPT_("number too large or too small");
727 case POPT_ERROR_ERRNO:
728 return strerror(errno);
729 default:
730 return POPT_("unknown error");
734 int poptStuffArgs(poptContext con, const char ** argv) {
735 int argc;
737 if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
738 return POPT_ERROR_OPTSTOODEEP;
740 for (argc = 0; argv[argc]; argc++)
743 con->os++;
744 con->os->next = 0;
745 con->os->nextArg = NULL;
746 con->os->nextCharArg = NULL;
747 con->os->currAlias = NULL;
748 poptDupArgv(argc, argv, &con->os->argc, &con->os->argv);
749 con->os->argb = NULL;
750 con->os->stuffed = 1;
752 return 0;
755 const char * poptGetInvocationName(poptContext con) {
756 return con->os->argv[0];
759 int poptStrippedArgv(poptContext con, int argc, char **argv)
761 int i,j=1, numargs=argc;
763 for(i=1; i<argc; i++) {
764 if(PBM_ISSET(i, con->arg_strip)) {
765 numargs--;
769 for(i=1; i<argc; i++) {
770 if(PBM_ISSET(i, con->arg_strip)) {
771 continue;
772 } else {
773 if(j<numargs) {
774 argv[j++]=argv[i];
775 } else {
776 argv[j++]='\0';
781 return(numargs);