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 */
9 #include "poptalloca.h"
26 static char * strerror(int errno
) {
28 extern char * sys_errlist
[];
30 if ((0 <= errno
) && (errno
< sys_nerr
))
31 return sys_errlist
[errno
];
33 return POPT_("unknown errno");
37 void poptSetExecPath(poptContext con
, const char * path
, int allowAbsolute
) {
38 if (con
->execPath
) free(con
->execPath
);
39 con
->execPath
= strdup(path
);
40 con
->execAbsolute
= allowAbsolute
;
43 static void invokeCallbacks(poptContext con
, const struct poptOption
* table
,
45 const struct poptOption
* opt
= table
;
48 while (opt
->longName
|| opt
->shortName
|| opt
->arg
) {
49 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
50 invokeCallbacks(con
, opt
->arg
, post
);
51 } else if (((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
) &&
52 ((!post
&& (opt
->argInfo
& POPT_CBFLAG_PRE
)) ||
53 ( post
&& (opt
->argInfo
& POPT_CBFLAG_POST
)))) {
54 cb
= (poptCallbackType
)opt
->arg
;
55 cb(con
, post
? POPT_CALLBACK_REASON_POST
: POPT_CALLBACK_REASON_PRE
,
56 NULL
, NULL
, opt
->descrip
);
62 poptContext
poptGetContext(char * name
, int argc
, char ** argv
,
63 const struct poptOption
* options
, int flags
) {
64 poptContext con
= malloc(sizeof(*con
));
66 memset(con
, 0, sizeof(*con
));
68 con
->os
= con
->optionStack
;
72 if (!(flags
& POPT_CONTEXT_KEEP_FIRST
))
73 con
->os
->next
= 1; /* skip argv[0] */
75 con
->leftovers
= malloc(sizeof(char *) * (argc
+ 1));
76 con
->options
= options
;
77 con
->finalArgv
= malloc(sizeof(*con
->finalArgv
) * (argc
* 2));
78 con
->finalArgvAlloced
= argc
* 2;
80 con
->execAbsolute
= 1;
82 if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
83 con
->flags
|= POPT_CONTEXT_POSIXMEHARDER
;
86 con
->appName
= strcpy(malloc(strlen(name
) + 1), name
);
88 invokeCallbacks(con
, con
->options
, 0);
93 void poptResetContext(poptContext con
) {
96 con
->os
= con
->optionStack
;
97 con
->os
->currAlias
= NULL
;
98 con
->os
->nextCharArg
= NULL
;
99 con
->os
->nextArg
= NULL
;
100 con
->os
->next
= 1; /* skip argv[0] */
102 con
->numLeftovers
= 0;
103 con
->nextLeftover
= 0;
104 con
->restLeftover
= 0;
107 for (i
= 0; i
< con
->finalArgvCount
; i
++)
108 free(con
->finalArgv
[i
]);
110 con
->finalArgvCount
= 0;
113 /* Only one of longName, shortName may be set at a time */
114 static int handleExec(poptContext con
, char * longName
, char shortName
) {
117 i
= con
->numExecs
- 1;
119 while (i
>= 0 && (!con
->execs
[i
].longName
||
120 strcmp(con
->execs
[i
].longName
, longName
))) i
--;
123 con
->execs
[i
].shortName
!= shortName
) i
--;
128 if (con
->flags
& POPT_CONTEXT_NO_EXEC
)
132 con
->doExec
= con
->execs
+ i
;
136 /* We already have an exec to do; remember this option for next
138 if ((con
->finalArgvCount
+ 1) >= (con
->finalArgvAlloced
)) {
139 con
->finalArgvAlloced
+= 10;
140 con
->finalArgv
= realloc(con
->finalArgv
,
141 sizeof(*con
->finalArgv
) * con
->finalArgvAlloced
);
144 i
= con
->finalArgvCount
++;
145 con
->finalArgv
[i
] = malloc((longName
? strlen(longName
) : 0) + 3);
147 sprintf(con
->finalArgv
[i
], "--%s", longName
);
149 sprintf(con
->finalArgv
[i
], "-%c", shortName
);
154 /* Only one of longName, shortName may be set at a time */
155 static int handleAlias(poptContext con
, char * longName
, char shortName
,
156 char * nextCharArg
) {
159 if (con
->os
->currAlias
&& con
->os
->currAlias
->longName
&& longName
&&
160 !strcmp(con
->os
->currAlias
->longName
, longName
))
162 if (con
->os
->currAlias
&& shortName
&&
163 shortName
== con
->os
->currAlias
->shortName
)
166 i
= con
->numAliases
- 1;
168 while (i
>= 0 && (!con
->aliases
[i
].longName
||
169 strcmp(con
->aliases
[i
].longName
, longName
))) i
--;
172 con
->aliases
[i
].shortName
!= shortName
) i
--;
177 if ((con
->os
- con
->optionStack
+ 1)
178 == POPT_OPTION_DEPTH
)
179 return POPT_ERROR_OPTSTOODEEP
;
181 if (nextCharArg
&& *nextCharArg
)
182 con
->os
->nextCharArg
= nextCharArg
;
186 con
->os
->stuffed
= 0;
187 con
->os
->nextArg
= con
->os
->nextCharArg
= NULL
;
188 con
->os
->currAlias
= con
->aliases
+ i
;
189 con
->os
->argc
= con
->os
->currAlias
->argc
;
190 con
->os
->argv
= con
->os
->currAlias
->argv
;
195 static void execCommand(poptContext con
) {
198 char * script
= con
->doExec
->script
;
200 argv
= malloc(sizeof(*argv
) *
201 (6 + con
->numLeftovers
+ con
->finalArgvCount
));
203 if (!con
->execAbsolute
&& strchr(script
, '/')) return;
205 if (!strchr(script
, '/') && con
->execPath
) {
206 argv
[pos
] = alloca(strlen(con
->execPath
) + strlen(script
) + 2);
207 sprintf(argv
[pos
], "%s/%s", con
->execPath
, script
);
213 argv
[pos
] = findProgramPath(con
->os
->argv
[0]);
214 if (argv
[pos
]) pos
++;
217 memcpy(argv
+ pos
, con
->finalArgv
, sizeof(*argv
) * con
->finalArgvCount
);
218 pos
+= con
->finalArgvCount
;
220 if (con
->numLeftovers
) {
222 memcpy(argv
+ pos
, con
->leftovers
, sizeof(*argv
) * con
->numLeftovers
);
223 pos
+= con
->numLeftovers
;
229 setresuid(getuid(), getuid(),-1);
232 * XXX " ... on BSD systems setuid() should be preferred over setreuid()"
233 * XXX sez' Timur Bakeyev <mc@bat.ru>
234 * XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
236 #if defined(HAVE_SETUID)
238 #elif defined (HAVE_SETREUID)
239 setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
241 ; /* Cannot drop privileges */
245 execvp(argv
[0], argv
);
248 static const struct poptOption
* findOption(const struct poptOption
* table
,
249 const char * longName
,
251 poptCallbackType
* callback
,
252 void ** callbackData
,
254 const struct poptOption
* opt
= table
;
255 const struct poptOption
* opt2
;
256 const struct poptOption
* cb
= NULL
;
258 /* This happens when a single - is given */
259 if (singleDash
&& !shortName
&& !*longName
)
262 while (opt
->longName
|| opt
->shortName
|| opt
->arg
) {
263 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
264 opt2
= findOption(opt
->arg
, longName
, shortName
, callback
,
265 callbackData
, singleDash
);
267 if (*callback
&& !*callbackData
)
268 *callbackData
= opt
->descrip
;
271 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
) {
273 } else if (longName
&& opt
->longName
&&
274 (!singleDash
|| (opt
->argInfo
& POPT_ARGFLAG_ONEDASH
)) &&
275 !strcmp(longName
, opt
->longName
)) {
277 } else if (shortName
&& shortName
== opt
->shortName
) {
283 if (!opt
->longName
&& !opt
->shortName
) return NULL
;
284 *callbackData
= NULL
;
287 *callback
= (poptCallbackType
)cb
->arg
;
288 if (!(cb
->argInfo
& POPT_CBFLAG_INC_DATA
))
289 *callbackData
= cb
->descrip
;
295 /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
296 int poptGetNextOpt(poptContext con
) {
297 char * optString
, * chptr
, * localOptString
;
298 char * longArg
= NULL
;
299 char * origOptString
;
302 const struct poptOption
* opt
= NULL
;
310 while (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
311 && con
->os
> con
->optionStack
)
313 if (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
) {
314 invokeCallbacks(con
, con
->options
, 1);
315 if (con
->doExec
) execCommand(con
);
319 if (!con
->os
->nextCharArg
) {
321 origOptString
= con
->os
->argv
[con
->os
->next
++];
323 if (con
->restLeftover
|| *origOptString
!= '-') {
324 con
->leftovers
[con
->numLeftovers
++] = origOptString
;
325 if (con
->flags
& POPT_CONTEXT_POSIXMEHARDER
)
326 con
->restLeftover
= 1;
330 /* Make a copy we can hack at */
331 localOptString
= optString
=
332 strcpy(alloca(strlen(origOptString
) + 1),
336 return POPT_ERROR_BADOPT
;
338 if (optString
[1] == '-' && !optString
[2]) {
339 con
->restLeftover
= 1;
343 if (*optString
== '-')
344 singleDash
= 0, optString
++;
348 if (handleAlias(con
, optString
, '\0', NULL
))
350 if (handleExec(con
, optString
, '\0'))
354 while (*chptr
&& *chptr
!= '=') chptr
++;
356 longArg
= origOptString
+ (chptr
- localOptString
) + 1;
360 opt
= findOption(con
->options
, optString
, '\0', &cb
, &cbData
,
362 if (!opt
&& !singleDash
) return POPT_ERROR_BADOPT
;
366 con
->os
->nextCharArg
= origOptString
+ 1;
369 if (con
->os
->nextCharArg
) {
370 origOptString
= con
->os
->nextCharArg
;
372 con
->os
->nextCharArg
= NULL
;
374 if (handleAlias(con
, NULL
, *origOptString
,
375 origOptString
+ 1)) {
379 if (handleExec(con
, NULL
, *origOptString
))
382 opt
= findOption(con
->options
, NULL
, *origOptString
, &cb
,
384 if (!opt
) return POPT_ERROR_BADOPT
;
388 con
->os
->nextCharArg
= origOptString
;
391 if (opt
->arg
&& (opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_NONE
) {
392 *((int *)opt
->arg
) = 1;
393 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_VAL
) {
394 if (opt
->arg
) *((int *) opt
->arg
) = opt
->val
;
395 } else if ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_NONE
) {
397 con
->os
->nextArg
= longArg
;
398 } else if (con
->os
->nextCharArg
) {
399 con
->os
->nextArg
= con
->os
->nextCharArg
;
400 con
->os
->nextCharArg
= NULL
;
402 while (con
->os
->next
== con
->os
->argc
&&
403 con
->os
> con
->optionStack
)
405 if (con
->os
->next
== con
->os
->argc
)
406 return POPT_ERROR_NOARG
;
408 con
->os
->nextArg
= con
->os
->argv
[con
->os
->next
++];
412 switch (opt
->argInfo
& POPT_ARG_MASK
) {
413 case POPT_ARG_STRING
:
414 *((char **) opt
->arg
) = con
->os
->nextArg
;
419 aLong
= strtol(con
->os
->nextArg
, &end
, 0);
420 if (!(end
&& *end
== '\0'))
421 return POPT_ERROR_BADNUMBER
;
423 if (aLong
== LONG_MIN
|| aLong
== LONG_MAX
)
424 return POPT_ERROR_OVERFLOW
;
425 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_LONG
) {
426 *((long *) opt
->arg
) = aLong
;
428 if (aLong
> INT_MAX
|| aLong
< INT_MIN
)
429 return POPT_ERROR_OVERFLOW
;
430 *((int *) opt
->arg
) =aLong
;
435 fprintf(stdout
, POPT_("option type (%d) not implemented in popt\n"),
436 opt
->argInfo
& POPT_ARG_MASK
);
443 cb(con
, POPT_CALLBACK_REASON_OPTION
, opt
, con
->os
->nextArg
, cbData
);
444 else if (opt
->val
&& ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_VAL
))
447 if ((con
->finalArgvCount
+ 2) >= (con
->finalArgvAlloced
)) {
448 con
->finalArgvAlloced
+= 10;
449 con
->finalArgv
= realloc(con
->finalArgv
,
450 sizeof(*con
->finalArgv
) * con
->finalArgvAlloced
);
453 i
= con
->finalArgvCount
++;
455 malloc((opt
->longName
? strlen(opt
->longName
) : 0) + 3);
457 sprintf(con
->finalArgv
[i
], "--%s", opt
->longName
);
459 sprintf(con
->finalArgv
[i
], "-%c", opt
->shortName
);
461 if (opt
->arg
&& (opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_NONE
462 && (opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_VAL
)
463 con
->finalArgv
[con
->finalArgvCount
++] = strdup(con
->os
->nextArg
);
469 char * poptGetOptArg(poptContext con
) {
470 char * ret
= con
->os
->nextArg
;
471 con
->os
->nextArg
= NULL
;
475 char * poptGetArg(poptContext con
) {
476 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
477 return (con
->leftovers
[con
->nextLeftover
++]);
480 char * poptPeekArg(poptContext con
) {
481 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
482 return (con
->leftovers
[con
->nextLeftover
]);
485 char ** poptGetArgs(poptContext con
) {
486 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
488 /* some apps like [like RPM ;-) ] need this NULL terminated */
489 con
->leftovers
[con
->numLeftovers
] = NULL
;
491 return (con
->leftovers
+ con
->nextLeftover
);
494 void poptFreeContext(poptContext con
) {
497 for (i
= 0; i
< con
->numAliases
; i
++) {
498 if (con
->aliases
[i
].longName
) free(con
->aliases
[i
].longName
);
499 free(con
->aliases
[i
].argv
);
502 for (i
= 0; i
< con
->numExecs
; i
++) {
503 if (con
->execs
[i
].longName
) free(con
->execs
[i
].longName
);
504 free(con
->execs
[i
].script
);
507 for (i
= 0; i
< con
->finalArgvCount
; i
++)
508 free(con
->finalArgv
[i
]);
510 free(con
->leftovers
);
511 free(con
->finalArgv
);
512 if (con
->appName
) free(con
->appName
);
513 if (con
->aliases
) free(con
->aliases
);
514 if (con
->otherHelp
) free(con
->otherHelp
);
515 if (con
->execPath
) free(con
->execPath
);
519 int poptAddAlias(poptContext con
, struct poptAlias newAlias
, int flags
) {
520 int aliasNum
= con
->numAliases
++;
521 struct poptAlias
* alias
;
523 /* SunOS won't realloc(NULL, ...) */
525 con
->aliases
= malloc(sizeof(newAlias
) * con
->numAliases
);
527 con
->aliases
= realloc(con
->aliases
,
528 sizeof(newAlias
) * con
->numAliases
);
529 alias
= con
->aliases
+ aliasNum
;
533 alias
->longName
= strcpy(malloc(strlen(alias
->longName
) + 1),
536 alias
->longName
= NULL
;
541 char * poptBadOption(poptContext con
, int flags
) {
542 struct optionStackEntry
* os
;
544 if (flags
& POPT_BADOPTION_NOALIAS
)
545 os
= con
->optionStack
;
549 return os
->argv
[os
->next
- 1];
552 #define POPT_ERROR_NOARG -10
553 #define POPT_ERROR_BADOPT -11
554 #define POPT_ERROR_OPTSTOODEEP -13
555 #define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
556 #define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
558 const char * poptStrerror(const int error
) {
560 case POPT_ERROR_NOARG
:
561 return POPT_("missing argument");
562 case POPT_ERROR_BADOPT
:
563 return POPT_("unknown option");
564 case POPT_ERROR_OPTSTOODEEP
:
565 return POPT_("aliases nested too deeply");
566 case POPT_ERROR_BADQUOTE
:
567 return POPT_("error in paramter quoting");
568 case POPT_ERROR_BADNUMBER
:
569 return POPT_("invalid numeric value");
570 case POPT_ERROR_OVERFLOW
:
571 return POPT_("number too large or too small");
572 case POPT_ERROR_ERRNO
:
573 return strerror(errno
);
575 return POPT_("unknown error");
579 int poptStuffArgs(poptContext con
, char ** argv
) {
582 if ((con
->os
- con
->optionStack
) == POPT_OPTION_DEPTH
)
583 return POPT_ERROR_OPTSTOODEEP
;
585 for (i
= 0; argv
[i
]; i
++);
589 con
->os
->nextArg
= con
->os
->nextCharArg
= NULL
;
590 con
->os
->currAlias
= NULL
;
592 con
->os
->argv
= argv
;
593 con
->os
->stuffed
= 1;
598 const char * poptGetInvocationName(poptContext con
) {
599 return con
->os
->argv
[0];