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 */
10 static char * strerror(int errno
) {
12 extern char * sys_errlist
[];
14 if ((0 <= errno
) && (errno
< sys_nerr
))
15 return sys_errlist
[errno
];
17 return POPT_("unknown errno");
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
,
29 const struct poptOption
* opt
= table
;
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
);
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
;
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
;
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
;
76 con
->appName
= strcpy(malloc(strlen(name
) + 1), name
);
78 invokeCallbacks(con
, con
->options
, 0);
83 static void cleanOSE(struct optionStackEntry
*os
)
99 void poptResetContext(poptContext con
) {
102 while (con
->os
> con
->optionStack
) {
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;
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
) {
138 i
= con
->numExecs
- 1;
140 while (i
>= 0 && (!con
->execs
[i
].longName
||
141 strcmp(con
->execs
[i
].longName
, longName
))) i
--;
144 con
->execs
[i
].shortName
!= shortName
) i
--;
149 if (con
->flags
& POPT_CONTEXT_NO_EXEC
)
152 if (con
->doExec
== NULL
) {
153 con
->doExec
= con
->execs
+ i
;
157 /* We already have an exec to do; remember this option for next
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);
168 sprintf(s
, "--%s", longName
);
170 sprintf(s
, "-%c", shortName
);
171 con
->finalArgv
[i
] = s
;
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
) {
182 if (con
->os
->currAlias
&& con
->os
->currAlias
->longName
&& longName
&&
183 !strcmp(con
->os
->currAlias
->longName
, longName
))
185 if (con
->os
->currAlias
&& shortName
&&
186 shortName
== con
->os
->currAlias
->shortName
)
189 i
= con
->numAliases
- 1;
191 while (i
>= 0 && (!con
->aliases
[i
].longName
||
192 strcmp(con
->aliases
[i
].longName
, longName
))) i
--;
195 con
->aliases
[i
].shortName
!= shortName
) i
--;
200 if ((con
->os
- con
->optionStack
+ 1) == POPT_OPTION_DEPTH
)
201 return POPT_ERROR_OPTSTOODEEP
;
203 if (nextCharArg
&& *nextCharArg
)
204 con
->os
->nextCharArg
= nextCharArg
;
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
;
219 static void execCommand(poptContext con
) {
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
);
238 argv
[pos
] = findProgramPath(con
->os
->argv
[0]);
239 if (argv
[pos
]) pos
++;
242 memcpy(argv
+ pos
, con
->finalArgv
, sizeof(*argv
) * con
->finalArgvCount
);
243 pos
+= con
->finalArgvCount
;
245 if (con
->numLeftovers
) {
247 memcpy(argv
+ pos
, con
->leftovers
, sizeof(*argv
) * con
->numLeftovers
);
248 pos
+= con
->numLeftovers
;
254 setresuid(getuid(), getuid(),-1);
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)
263 #elif defined (HAVE_SETREUID)
264 setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
266 ; /* Can't drop privileges */
270 execvp(argv
[0], (char *const *)argv
);
273 /*@observer@*/ static const struct poptOption
*
274 findOption(const struct poptOption
* table
, const char * longName
,
276 /*@out@*/ poptCallbackType
* callback
, /*@out@*/ const void ** callbackData
,
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
)
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
);
292 if (*callback
&& !*callbackData
)
293 *callbackData
= opt
->descrip
;
296 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
) {
298 } else if (longName
&& opt
->longName
&&
299 (!singleDash
|| (opt
->argInfo
& POPT_ARGFLAG_ONEDASH
)) &&
300 !strcmp(longName
, opt
->longName
)) {
302 } else if (shortName
&& shortName
== opt
->shortName
) {
308 if (!opt
->longName
&& !opt
->shortName
) return NULL
;
309 *callbackData
= NULL
;
312 *callback
= (poptCallbackType
)cb
->arg
;
313 if (!(cb
->argInfo
& POPT_CBFLAG_INC_DATA
))
314 *callbackData
= cb
->descrip
;
320 static const char *findNextArg(poptContext con
, unsigned argx
, int delete)
322 struct optionStackEntry
* os
= con
->os
;
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;
336 if (os
->argb
== NULL
) os
->argb
= PBM_ALLOC(os
->argc
);
337 PBM_SET(i
, os
->argb
);
341 if (os
> con
->optionStack
) os
--;
342 } while (arg
== NULL
);
346 static /*@only@*/ const char * expandNextArg(poptContext con
, const char * s
)
351 size_t tn
= strlen(s
) + 1;
354 te
= t
= malloc(tn
);;
355 while ((c
= *s
++) != '\0') {
357 #if 0 /* XXX can't do this */
358 case '\\': /* escape */
363 if (!(s
[0] == '#' && s
[1] == ':' && s
[2] == '+'))
365 if ((a
= findNextArg(con
, 1, 1)) == NULL
)
374 strncpy(te
, a
, alen
); te
+= alen
;
376 /*@notreached@*/ break;
383 t
= realloc(t
, strlen(t
)+1); /* XXX memory leak, hard to plug */
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
;
401 /* looks a bit tricky to get rid of alloca properly in this fn */
403 #define ALLOCA(x) alloca(x)
405 #define ALLOCA(x) malloc(x)
410 const char * origOptString
= NULL
;
411 poptCallbackType cb
= NULL
;
412 const void * cbData
= NULL
;
413 const char * longArg
= NULL
;
416 while (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
417 && con
->os
> con
->optionStack
) {
420 if (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
) {
421 invokeCallbacks(con
, con
->options
, 1);
422 if (con
->doExec
) execCommand(con
);
426 /* Process next long option */
427 if (!con
->os
->nextCharArg
) {
428 char * localOptString
, * optString
;
431 if (con
->os
->argb
&& PBM_ISSET(con
->os
->next
, con
->os
->argb
)) {
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;
445 /* Make a copy we can hack at */
446 localOptString
= optString
=
447 strcpy(ALLOCA(strlen(origOptString
) + 1),
451 return POPT_ERROR_BADOPT
;
453 if (optString
[1] == '-' && !optString
[2]) {
454 con
->restLeftover
= 1;
461 if (*optString
== '-')
462 singleDash
= 0, optString
++;
466 /* XXX aliases with arg substitution need "--alias=arg" */
467 if (handleAlias(con
, optString
, '\0', NULL
))
469 if (handleExec(con
, optString
, '\0'))
472 /* Check for "--long=arg" option. */
473 for (oe
= optString
; *oe
&& *oe
!= '='; oe
++)
477 /* XXX longArg is mapped back to persistent storage. */
478 longArg
= origOptString
+ (oe
- localOptString
);
481 opt
= findOption(con
->options
, optString
, '\0', &cb
, &cbData
,
483 if (!opt
&& !singleDash
)
484 return POPT_ERROR_BADOPT
;
488 con
->os
->nextCharArg
= origOptString
+ 1;
490 if(con
->os
== con
->optionStack
&&
491 opt
->argInfo
& POPT_ARGFLAG_STRIP
) {
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)) {
509 if (handleExec(con
, NULL
, *origOptString
))
512 opt
= findOption(con
->options
, NULL
, *origOptString
, &cb
,
515 return POPT_ERROR_BADOPT
;
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
) {
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
;
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
;
538 while (con
->os
->next
== con
->os
->argc
&&
539 con
->os
> con
->optionStack
) {
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
&&
550 poptStripArg(con
, con
->os
->next
);
553 con
->os
->nextArg
= expandNextArg(con
, con
->os
->argv
[con
->os
->next
++]);
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
);
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
;
577 if (aLong
> INT_MAX
|| aLong
< INT_MIN
)
578 return POPT_ERROR_OVERFLOW
;
579 *((int *) opt
->arg
) = aLong
;
584 fprintf(stdout
, POPT_("option type (%d) not implemented in popt\n"),
585 opt
->argInfo
& POPT_ARG_MASK
);
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
))
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);
604 sprintf(s
, "--%s", opt
->longName
);
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
);
619 const char * poptGetOptArg(poptContext con
) {
620 const char * ret
= con
->os
->nextArg
;
621 con
->os
->nextArg
= NULL
;
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
) {
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
);
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, ...) */
680 con
->aliases
= malloc(sizeof(newAlias
) * con
->numAliases
);
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
)
689 alias
->shortName
= newAlias
.shortName
;
690 alias
->argc
= newAlias
.argc
;
691 alias
->argv
= newAlias
.argv
;
696 const char * poptBadOption(poptContext con
, int flags
) {
697 struct optionStackEntry
* os
;
699 if (flags
& POPT_BADOPTION_NOALIAS
)
700 os
= con
->optionStack
;
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
) {
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
);
730 return POPT_("unknown error");
734 int poptStuffArgs(poptContext con
, const char ** argv
) {
737 if ((con
->os
- con
->optionStack
) == POPT_OPTION_DEPTH
)
738 return POPT_ERROR_OPTSTOODEEP
;
740 for (argc
= 0; argv
[argc
]; argc
++)
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;
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
)) {
769 for(i
=1; i
<argc
; i
++) {
770 if(PBM_ISSET(i
, con
->arg_strip
)) {