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"
24 static char * strerror(int errno
) {
26 extern char * sys_errlist
[];
28 if ((0 <= errno
) && (errno
< sys_nerr
))
29 return sys_errlist
[errno
];
31 return POPT_("unknown errno");
35 void poptSetExecPath(poptContext con
, const char * path
, int allowAbsolute
) {
36 if (con
->execPath
) free(con
->execPath
);
37 con
->execPath
= strdup(path
);
38 con
->execAbsolute
= allowAbsolute
;
41 static void invokeCallbacks(poptContext con
, const struct poptOption
* table
,
43 const struct poptOption
* opt
= table
;
46 while (opt
->longName
|| opt
->shortName
|| opt
->arg
) {
47 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
48 invokeCallbacks(con
, opt
->arg
, post
);
49 } else if (((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
) &&
50 ((!post
&& (opt
->argInfo
& POPT_CBFLAG_PRE
)) ||
51 ( post
&& (opt
->argInfo
& POPT_CBFLAG_POST
)))) {
52 cb
= (poptCallbackType
)opt
->arg
;
53 cb(con
, post
? POPT_CALLBACK_REASON_POST
: POPT_CALLBACK_REASON_PRE
,
54 NULL
, NULL
, opt
->descrip
);
60 poptContext
poptGetContext(char * name
, int argc
, char ** argv
,
61 const struct poptOption
* options
, int flags
) {
62 poptContext con
= malloc(sizeof(*con
));
64 memset(con
, 0, sizeof(*con
));
66 con
->os
= con
->optionStack
;
70 if (!(flags
& POPT_CONTEXT_KEEP_FIRST
))
71 con
->os
->next
= 1; /* skip argv[0] */
73 con
->leftovers
= malloc(sizeof(char *) * (argc
+ 1));
74 con
->options
= options
;
75 con
->finalArgv
= malloc(sizeof(*con
->finalArgv
) * (argc
* 2));
76 con
->finalArgvAlloced
= argc
* 2;
78 con
->execAbsolute
= 1;
80 if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
81 con
->flags
|= POPT_CONTEXT_POSIXMEHARDER
;
84 con
->appName
= strcpy(malloc(strlen(name
) + 1), name
);
86 invokeCallbacks(con
, con
->options
, 0);
91 void poptResetContext(poptContext con
) {
94 con
->os
= con
->optionStack
;
95 con
->os
->currAlias
= NULL
;
96 con
->os
->nextCharArg
= NULL
;
97 con
->os
->nextArg
= NULL
;
98 con
->os
->next
= 1; /* skip argv[0] */
100 con
->numLeftovers
= 0;
101 con
->nextLeftover
= 0;
102 con
->restLeftover
= 0;
105 for (i
= 0; i
< con
->finalArgvCount
; i
++)
106 free(con
->finalArgv
[i
]);
108 con
->finalArgvCount
= 0;
111 /* Only one of longName, shortName may be set at a time */
112 static int handleExec(poptContext con
, char * longName
, char shortName
) {
115 i
= con
->numExecs
- 1;
117 while (i
>= 0 && (!con
->execs
[i
].longName
||
118 strcmp(con
->execs
[i
].longName
, longName
))) i
--;
121 con
->execs
[i
].shortName
!= shortName
) i
--;
126 if (con
->flags
& POPT_CONTEXT_NO_EXEC
)
130 con
->doExec
= con
->execs
+ i
;
134 /* We already have an exec to do; remember this option for next
136 if ((con
->finalArgvCount
+ 1) >= (con
->finalArgvAlloced
)) {
137 con
->finalArgvAlloced
+= 10;
138 con
->finalArgv
= realloc(con
->finalArgv
,
139 sizeof(*con
->finalArgv
) * con
->finalArgvAlloced
);
142 i
= con
->finalArgvCount
++;
143 con
->finalArgv
[i
] = malloc((longName
? strlen(longName
) : 0) + 3);
145 sprintf(con
->finalArgv
[i
], "--%s", longName
);
147 sprintf(con
->finalArgv
[i
], "-%c", shortName
);
152 /* Only one of longName, shortName may be set at a time */
153 static int handleAlias(poptContext con
, char * longName
, char shortName
,
154 char * nextCharArg
) {
157 if (con
->os
->currAlias
&& con
->os
->currAlias
->longName
&& longName
&&
158 !strcmp(con
->os
->currAlias
->longName
, longName
))
160 if (con
->os
->currAlias
&& shortName
&&
161 shortName
== con
->os
->currAlias
->shortName
)
164 i
= con
->numAliases
- 1;
166 while (i
>= 0 && (!con
->aliases
[i
].longName
||
167 strcmp(con
->aliases
[i
].longName
, longName
))) i
--;
170 con
->aliases
[i
].shortName
!= shortName
) i
--;
175 if ((con
->os
- con
->optionStack
+ 1)
176 == POPT_OPTION_DEPTH
)
177 return POPT_ERROR_OPTSTOODEEP
;
179 if (nextCharArg
&& *nextCharArg
)
180 con
->os
->nextCharArg
= nextCharArg
;
184 con
->os
->stuffed
= 0;
185 con
->os
->nextArg
= con
->os
->nextCharArg
= NULL
;
186 con
->os
->currAlias
= con
->aliases
+ i
;
187 con
->os
->argc
= con
->os
->currAlias
->argc
;
188 con
->os
->argv
= con
->os
->currAlias
->argv
;
193 static void execCommand(poptContext con
) {
196 char * script
= con
->doExec
->script
;
198 argv
= malloc(sizeof(*argv
) *
199 (6 + con
->numLeftovers
+ con
->finalArgvCount
));
201 if (!con
->execAbsolute
&& strchr(script
, '/')) return;
203 if (!strchr(script
, '/') && con
->execPath
) {
204 argv
[pos
] = alloca(strlen(con
->execPath
) + strlen(script
) + 2);
205 sprintf(argv
[pos
], "%s/%s", con
->execPath
, script
);
211 argv
[pos
] = findProgramPath(con
->os
->argv
[0]);
212 if (argv
[pos
]) pos
++;
215 memcpy(argv
+ pos
, con
->finalArgv
, sizeof(*argv
) * con
->finalArgvCount
);
216 pos
+= con
->finalArgvCount
;
218 if (con
->numLeftovers
) {
220 memcpy(argv
+ pos
, con
->leftovers
, sizeof(*argv
) * con
->numLeftovers
);
221 pos
+= con
->numLeftovers
;
227 setresuid(getuid(), getuid(),-1);
230 * XXX " ... on BSD systems setuid() should be preferred over setreuid()"
231 * XXX sez' Timur Bakeyev <mc@bat.ru>
232 * XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
234 #if defined(HAVE_SETUID)
236 #elif defined (HAVE_SETREUID)
237 setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
239 ; /* Can't drop privileges */
243 execvp(argv
[0], argv
);
246 static const struct poptOption
* findOption(const struct poptOption
* table
,
247 const char * longName
,
249 poptCallbackType
* callback
,
250 void ** callbackData
,
252 const struct poptOption
* opt
= table
;
253 const struct poptOption
* opt2
;
254 const struct poptOption
* cb
= NULL
;
256 /* This happens when a single - is given */
257 if (singleDash
&& !shortName
&& !*longName
)
260 while (opt
->longName
|| opt
->shortName
|| opt
->arg
) {
261 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
262 opt2
= findOption(opt
->arg
, longName
, shortName
, callback
,
263 callbackData
, singleDash
);
265 if (*callback
&& !*callbackData
)
266 *callbackData
= opt
->descrip
;
269 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
) {
271 } else if (longName
&& opt
->longName
&&
272 (!singleDash
|| (opt
->argInfo
& POPT_ARGFLAG_ONEDASH
)) &&
273 !strcmp(longName
, opt
->longName
)) {
275 } else if (shortName
&& shortName
== opt
->shortName
) {
281 if (!opt
->longName
&& !opt
->shortName
) return NULL
;
282 *callbackData
= NULL
;
285 *callback
= (poptCallbackType
)cb
->arg
;
286 if (!(cb
->argInfo
& POPT_CBFLAG_INC_DATA
))
287 *callbackData
= cb
->descrip
;
293 /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
294 int poptGetNextOpt(poptContext con
) {
295 char * optString
, * chptr
, * localOptString
;
296 char * longArg
= NULL
;
297 char * origOptString
;
300 const struct poptOption
* opt
= NULL
;
308 while (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
309 && con
->os
> con
->optionStack
)
311 if (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
) {
312 invokeCallbacks(con
, con
->options
, 1);
313 if (con
->doExec
) execCommand(con
);
317 if (!con
->os
->nextCharArg
) {
319 origOptString
= con
->os
->argv
[con
->os
->next
++];
321 if (con
->restLeftover
|| *origOptString
!= '-') {
322 con
->leftovers
[con
->numLeftovers
++] = origOptString
;
323 if (con
->flags
& POPT_CONTEXT_POSIXMEHARDER
)
324 con
->restLeftover
= 1;
328 /* Make a copy we can hack at */
329 localOptString
= optString
=
330 strcpy(alloca(strlen(origOptString
) + 1),
334 return POPT_ERROR_BADOPT
;
336 if (optString
[1] == '-' && !optString
[2]) {
337 con
->restLeftover
= 1;
341 if (*optString
== '-')
342 singleDash
= 0, optString
++;
346 if (handleAlias(con
, optString
, '\0', NULL
))
348 if (handleExec(con
, optString
, '\0'))
352 while (*chptr
&& *chptr
!= '=') chptr
++;
354 longArg
= origOptString
+ (chptr
- localOptString
) + 1;
358 opt
= findOption(con
->options
, optString
, '\0', &cb
, &cbData
,
360 if (!opt
&& !singleDash
) return POPT_ERROR_BADOPT
;
364 con
->os
->nextCharArg
= origOptString
+ 1;
367 if (con
->os
->nextCharArg
) {
368 origOptString
= con
->os
->nextCharArg
;
370 con
->os
->nextCharArg
= NULL
;
372 if (handleAlias(con
, NULL
, *origOptString
,
373 origOptString
+ 1)) {
377 if (handleExec(con
, NULL
, *origOptString
))
380 opt
= findOption(con
->options
, NULL
, *origOptString
, &cb
,
382 if (!opt
) return POPT_ERROR_BADOPT
;
386 con
->os
->nextCharArg
= origOptString
;
389 if (opt
->arg
&& (opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_NONE
) {
390 *((int *)opt
->arg
) = 1;
391 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_VAL
) {
392 if (opt
->arg
) *((int *) opt
->arg
) = opt
->val
;
393 } else if ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_NONE
) {
395 con
->os
->nextArg
= longArg
;
396 } else if (con
->os
->nextCharArg
) {
397 con
->os
->nextArg
= con
->os
->nextCharArg
;
398 con
->os
->nextCharArg
= NULL
;
400 while (con
->os
->next
== con
->os
->argc
&&
401 con
->os
> con
->optionStack
)
403 if (con
->os
->next
== con
->os
->argc
)
404 return POPT_ERROR_NOARG
;
406 con
->os
->nextArg
= con
->os
->argv
[con
->os
->next
++];
410 switch (opt
->argInfo
& POPT_ARG_MASK
) {
411 case POPT_ARG_STRING
:
412 *((char **) opt
->arg
) = con
->os
->nextArg
;
417 aLong
= strtol(con
->os
->nextArg
, &end
, 0);
418 if (!(end
&& *end
== '\0'))
419 return POPT_ERROR_BADNUMBER
;
421 if (aLong
== LONG_MIN
|| aLong
== LONG_MAX
)
422 return POPT_ERROR_OVERFLOW
;
423 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_LONG
) {
424 *((long *) opt
->arg
) = aLong
;
426 if (aLong
> INT_MAX
|| aLong
< INT_MIN
)
427 return POPT_ERROR_OVERFLOW
;
428 *((int *) opt
->arg
) =aLong
;
433 fprintf(stdout
, POPT_("option type (%d) not implemented in popt\n"),
434 opt
->argInfo
& POPT_ARG_MASK
);
441 cb(con
, POPT_CALLBACK_REASON_OPTION
, opt
, con
->os
->nextArg
, cbData
);
442 else if (opt
->val
&& ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_VAL
))
445 if ((con
->finalArgvCount
+ 2) >= (con
->finalArgvAlloced
)) {
446 con
->finalArgvAlloced
+= 10;
447 con
->finalArgv
= realloc(con
->finalArgv
,
448 sizeof(*con
->finalArgv
) * con
->finalArgvAlloced
);
451 i
= con
->finalArgvCount
++;
453 malloc((opt
->longName
? strlen(opt
->longName
) : 0) + 3);
455 sprintf(con
->finalArgv
[i
], "--%s", opt
->longName
);
457 sprintf(con
->finalArgv
[i
], "-%c", opt
->shortName
);
459 if (opt
->arg
&& (opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_NONE
460 && (opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_VAL
)
461 con
->finalArgv
[con
->finalArgvCount
++] = strdup(con
->os
->nextArg
);
467 char * poptGetOptArg(poptContext con
) {
468 char * ret
= con
->os
->nextArg
;
469 con
->os
->nextArg
= NULL
;
473 char * poptGetArg(poptContext con
) {
474 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
475 return (con
->leftovers
[con
->nextLeftover
++]);
478 char * poptPeekArg(poptContext con
) {
479 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
480 return (con
->leftovers
[con
->nextLeftover
]);
483 char ** poptGetArgs(poptContext con
) {
484 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
486 /* some apps like [like RPM ;-) ] need this NULL terminated */
487 con
->leftovers
[con
->numLeftovers
] = NULL
;
489 return (con
->leftovers
+ con
->nextLeftover
);
492 void poptFreeContext(poptContext con
) {
495 for (i
= 0; i
< con
->numAliases
; i
++) {
496 if (con
->aliases
[i
].longName
) free(con
->aliases
[i
].longName
);
497 free(con
->aliases
[i
].argv
);
500 for (i
= 0; i
< con
->numExecs
; i
++) {
501 if (con
->execs
[i
].longName
) free(con
->execs
[i
].longName
);
502 free(con
->execs
[i
].script
);
505 for (i
= 0; i
< con
->finalArgvCount
; i
++)
506 free(con
->finalArgv
[i
]);
508 free(con
->leftovers
);
509 free(con
->finalArgv
);
510 if (con
->appName
) free(con
->appName
);
511 if (con
->aliases
) free(con
->aliases
);
512 if (con
->otherHelp
) free(con
->otherHelp
);
513 if (con
->execPath
) free(con
->execPath
);
517 int poptAddAlias(poptContext con
, struct poptAlias newAlias
, int flags
) {
518 int aliasNum
= con
->numAliases
++;
519 struct poptAlias
* alias
;
521 /* SunOS won't realloc(NULL, ...) */
523 con
->aliases
= malloc(sizeof(newAlias
) * con
->numAliases
);
525 con
->aliases
= realloc(con
->aliases
,
526 sizeof(newAlias
) * con
->numAliases
);
527 alias
= con
->aliases
+ aliasNum
;
531 alias
->longName
= strcpy(malloc(strlen(alias
->longName
) + 1),
534 alias
->longName
= NULL
;
539 char * poptBadOption(poptContext con
, int flags
) {
540 struct optionStackEntry
* os
;
542 if (flags
& POPT_BADOPTION_NOALIAS
)
543 os
= con
->optionStack
;
547 return os
->argv
[os
->next
- 1];
550 #define POPT_ERROR_NOARG -10
551 #define POPT_ERROR_BADOPT -11
552 #define POPT_ERROR_OPTSTOODEEP -13
553 #define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
554 #define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
556 const char * poptStrerror(const int error
) {
558 case POPT_ERROR_NOARG
:
559 return POPT_("missing argument");
560 case POPT_ERROR_BADOPT
:
561 return POPT_("unknown option");
562 case POPT_ERROR_OPTSTOODEEP
:
563 return POPT_("aliases nested too deeply");
564 case POPT_ERROR_BADQUOTE
:
565 return POPT_("error in paramter quoting");
566 case POPT_ERROR_BADNUMBER
:
567 return POPT_("invalid numeric value");
568 case POPT_ERROR_OVERFLOW
:
569 return POPT_("number too large or too small");
570 case POPT_ERROR_ERRNO
:
571 return strerror(errno
);
573 return POPT_("unknown error");
577 int poptStuffArgs(poptContext con
, char ** argv
) {
580 if ((con
->os
- con
->optionStack
) == POPT_OPTION_DEPTH
)
581 return POPT_ERROR_OPTSTOODEEP
;
583 for (i
= 0; argv
[i
]; i
++);
587 con
->os
->nextArg
= con
->os
->nextCharArg
= NULL
;
588 con
->os
->currAlias
= NULL
;
590 con
->os
->argv
= argv
;
591 con
->os
->stuffed
= 1;
596 const char * poptGetInvocationName(poptContext con
) {
597 return con
->os
->argv
[0];