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 */
6 * \brief Source: a module for parsing command line options
13 #include "poptalloca.h"
28 static char * strerror(int errno
) {
30 extern char * sys_errlist
[];
32 if ((0 <= errno
) && (errno
< sys_nerr
))
33 return sys_errlist
[errno
];
35 return POPT_("unknown errno");
39 void poptSetExecPath(poptContext con
, const char * path
, int allowAbsolute
) {
40 if (con
->execPath
) free(con
->execPath
);
41 con
->execPath
= strdup(path
);
42 con
->execAbsolute
= allowAbsolute
;
45 static void invokeCallbacks(poptContext con
, const struct poptOption
* table
,
47 const struct poptOption
* opt
= table
;
49 while (opt
->longName
|| opt
->shortName
|| opt
->arg
.p
) {
50 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
51 invokeCallbacks(con
, opt
->arg
.p
, post
);
52 } else if (((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
) &&
53 ((!post
&& (opt
->argInfo
& POPT_CBFLAG_PRE
)) ||
54 ( post
&& (opt
->argInfo
& POPT_CBFLAG_POST
)))) {
55 opt
->arg
.f1(con
, post
? POPT_CALLBACK_REASON_POST
: POPT_CALLBACK_REASON_PRE
,
56 NULL
, NULL
, opt
->descrip
);
62 poptContext
poptGetContext(const 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
) {
199 char * script
= con
->doExec
->script
;
201 argv
= malloc(sizeof(*argv
) *
202 (6 + con
->numLeftovers
+ con
->finalArgvCount
));
204 if (!con
->execAbsolute
&& strchr(script
, '/')) return;
206 if (!strchr(script
, '/') && con
->execPath
) {
207 argv
[pos
] = alloca(strlen(con
->execPath
) + strlen(script
) + 2);
208 sprintf(argv
[pos
], "%s/%s", con
->execPath
, script
);
214 argv
[pos
] = findProgramPath(con
->os
->argv
[0]);
215 if (argv
[pos
]) pos
++;
218 memcpy(argv
+ pos
, con
->finalArgv
, sizeof(*argv
) * con
->finalArgvCount
);
219 pos
+= con
->finalArgvCount
;
221 if (con
->numLeftovers
) {
223 memcpy(argv
+ pos
, con
->leftovers
, sizeof(*argv
) * con
->numLeftovers
);
224 pos
+= con
->numLeftovers
;
229 execvp(argv
[0], argv
);
236 static const struct poptOption
* findOption(const struct poptOption
* table
,
237 const char * longName
,
239 poptCallbackType
* callback
,
240 void ** callbackData
,
242 const struct poptOption
* opt
= table
;
243 const struct poptOption
* opt2
;
244 const struct poptOption
* cb
= NULL
;
246 /* This happens when a single - is given */
247 if (singleDash
&& !shortName
&& !*longName
)
250 while (opt
->longName
|| opt
->shortName
|| opt
->arg
.p
) {
251 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
252 opt2
= findOption(opt
->arg
.p
, longName
, shortName
, callback
,
253 callbackData
, singleDash
);
255 if (*callback
&& !*callbackData
)
256 *callbackData
= opt
->descrip
;
259 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
) {
261 } else if (longName
&& opt
->longName
&&
262 (!singleDash
|| (opt
->argInfo
& POPT_ARGFLAG_ONEDASH
)) &&
263 !strcmp(longName
, opt
->longName
)) {
265 } else if (shortName
&& shortName
== opt
->shortName
) {
271 if (!opt
->longName
&& !opt
->shortName
) return NULL
;
272 *callbackData
= NULL
;
275 *callback
= cb
->arg
.f2
;
276 if (!(cb
->argInfo
& POPT_CBFLAG_INC_DATA
))
277 *callbackData
= cb
->descrip
;
283 /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
284 int poptGetNextOpt(poptContext con
) {
285 char * optString
, * chptr
, * localOptString
;
286 char * longArg
= NULL
;
287 char * origOptString
;
290 const struct poptOption
* opt
= NULL
;
298 while (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
299 && con
->os
> con
->optionStack
)
301 if (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
) {
302 invokeCallbacks(con
, con
->options
, 1);
303 if (con
->doExec
) execCommand(con
);
307 if (!con
->os
->nextCharArg
) {
309 origOptString
= con
->os
->argv
[con
->os
->next
++];
311 if (con
->restLeftover
|| *origOptString
!= '-') {
312 con
->leftovers
[con
->numLeftovers
++] = origOptString
;
313 if (con
->flags
& POPT_CONTEXT_POSIXMEHARDER
)
314 con
->restLeftover
= 1;
318 /* Make a copy we can hack at */
319 localOptString
= optString
=
320 strcpy(alloca(strlen(origOptString
) + 1),
324 return POPT_ERROR_BADOPT
;
326 if (optString
[1] == '-' && !optString
[2]) {
327 con
->restLeftover
= 1;
331 if (*optString
== '-')
332 singleDash
= 0, optString
++;
336 if (handleAlias(con
, optString
, '\0', NULL
))
338 if (handleExec(con
, optString
, '\0'))
342 while (*chptr
&& *chptr
!= '=') chptr
++;
344 longArg
= origOptString
+ (chptr
- localOptString
) + 1;
348 opt
= findOption(con
->options
, optString
, '\0', &cb
, &cbData
,
350 if (!opt
&& !singleDash
) return POPT_ERROR_BADOPT
;
354 con
->os
->nextCharArg
= origOptString
+ 1;
357 if (con
->os
->nextCharArg
) {
358 origOptString
= con
->os
->nextCharArg
;
360 con
->os
->nextCharArg
= NULL
;
362 if (handleAlias(con
, NULL
, *origOptString
,
363 origOptString
+ 1)) {
367 if (handleExec(con
, NULL
, *origOptString
))
370 opt
= findOption(con
->options
, NULL
, *origOptString
, &cb
,
372 if (!opt
) return POPT_ERROR_BADOPT
;
376 con
->os
->nextCharArg
= origOptString
;
379 if (opt
->arg
.p
&& (opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_NONE
) {
380 *((int *)opt
->arg
.p
) = 1;
381 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_VAL
) {
382 if (opt
->arg
.p
) *((int *) opt
->arg
.p
) = opt
->val
;
383 } else if ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_NONE
) {
385 con
->os
->nextArg
= longArg
;
386 } else if (con
->os
->nextCharArg
) {
387 con
->os
->nextArg
= con
->os
->nextCharArg
;
388 con
->os
->nextCharArg
= NULL
;
390 while (con
->os
->next
== con
->os
->argc
&&
391 con
->os
> con
->optionStack
)
393 if (con
->os
->next
== con
->os
->argc
)
394 return POPT_ERROR_NOARG
;
396 con
->os
->nextArg
= con
->os
->argv
[con
->os
->next
++];
400 switch (opt
->argInfo
& POPT_ARG_MASK
) {
401 case POPT_ARG_STRING
:
402 *((char **) opt
->arg
.p
) = con
->os
->nextArg
;
407 aLong
= strtol(con
->os
->nextArg
, &end
, 0);
408 if (!(end
&& *end
== '\0'))
409 return POPT_ERROR_BADNUMBER
;
411 if (aLong
== LONG_MIN
|| aLong
== LONG_MAX
)
412 return POPT_ERROR_OVERFLOW
;
413 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_LONG
) {
414 *((long *) opt
->arg
.p
) = aLong
;
416 if (aLong
> INT_MAX
|| aLong
< INT_MIN
)
417 return POPT_ERROR_OVERFLOW
;
418 *((int *) opt
->arg
.p
) =aLong
;
423 fprintf(stdout
, POPT_("option type (%d) not implemented in popt\n"),
424 opt
->argInfo
& POPT_ARG_MASK
);
431 cb(con
, POPT_CALLBACK_REASON_OPTION
, opt
, con
->os
->nextArg
, cbData
);
432 else if (opt
->val
&& ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_VAL
))
435 if ((con
->finalArgvCount
+ 2) >= (con
->finalArgvAlloced
)) {
436 con
->finalArgvAlloced
+= 10;
437 con
->finalArgv
= realloc(con
->finalArgv
,
438 sizeof(*con
->finalArgv
) * con
->finalArgvAlloced
);
441 i
= con
->finalArgvCount
++;
443 malloc((opt
->longName
? strlen(opt
->longName
) : 0) + 3);
445 sprintf(con
->finalArgv
[i
], "--%s", opt
->longName
);
447 sprintf(con
->finalArgv
[i
], "-%c", opt
->shortName
);
449 if (opt
->arg
.p
&& (opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_NONE
450 && (opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_VAL
)
451 con
->finalArgv
[con
->finalArgvCount
++] = strdup(con
->os
->nextArg
);
457 char * poptGetOptArg(poptContext con
) {
458 char * ret
= con
->os
->nextArg
;
459 con
->os
->nextArg
= NULL
;
463 char * poptGetArg(poptContext con
) {
464 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
465 return (con
->leftovers
[con
->nextLeftover
++]);
468 char * poptPeekArg(poptContext con
) {
469 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
470 return (con
->leftovers
[con
->nextLeftover
]);
473 char ** poptGetArgs(poptContext con
) {
474 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
476 /* some apps like [like RPM ;-) ] need this NULL terminated */
477 con
->leftovers
[con
->numLeftovers
] = NULL
;
479 return (con
->leftovers
+ con
->nextLeftover
);
482 void poptFreeContext(poptContext con
) {
485 for (i
= 0; i
< con
->numAliases
; i
++) {
486 if (con
->aliases
[i
].longName
) free(con
->aliases
[i
].longName
);
487 free(con
->aliases
[i
].argv
);
490 for (i
= 0; i
< con
->numExecs
; i
++) {
491 if (con
->execs
[i
].longName
) free(con
->execs
[i
].longName
);
492 free(con
->execs
[i
].script
);
495 for (i
= 0; i
< con
->finalArgvCount
; i
++)
496 free(con
->finalArgv
[i
]);
498 free(con
->leftovers
);
499 free(con
->finalArgv
);
500 if (con
->appName
) free(con
->appName
);
501 if (con
->aliases
) free(con
->aliases
);
502 if (con
->otherHelp
) free(con
->otherHelp
);
503 if (con
->execPath
) free(con
->execPath
);
507 int poptAddAlias(poptContext con
, struct poptAlias newAlias
, int flags
) {
508 int aliasNum
= con
->numAliases
++;
509 struct poptAlias
* alias
;
513 /* SunOS won't realloc(NULL, ...) */
515 con
->aliases
= malloc(sizeof(newAlias
) * con
->numAliases
);
517 con
->aliases
= realloc(con
->aliases
,
518 sizeof(newAlias
) * con
->numAliases
);
519 alias
= con
->aliases
+ aliasNum
;
523 alias
->longName
= strcpy(malloc(strlen(alias
->longName
) + 1),
526 alias
->longName
= NULL
;
531 char * poptBadOption(poptContext con
, int flags
) {
532 struct optionStackEntry
* os
;
534 if (flags
& POPT_BADOPTION_NOALIAS
)
535 os
= con
->optionStack
;
539 return os
->argv
[os
->next
- 1];
542 #define POPT_ERROR_NOARG -10
543 #define POPT_ERROR_BADOPT -11
544 #define POPT_ERROR_OPTSTOODEEP -13
545 #define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
546 #define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
548 const char * poptStrerror(const int error
) {
550 case POPT_ERROR_NOARG
:
551 return _("missing argument");
552 case POPT_ERROR_BADOPT
:
553 return _("unknown option");
554 case POPT_ERROR_OPTSTOODEEP
:
555 return POPT_("aliases nested too deeply");
556 case POPT_ERROR_BADQUOTE
:
557 return POPT_("error in parameter quoting");
558 case POPT_ERROR_BADNUMBER
:
559 return _("invalid numeric value");
560 case POPT_ERROR_OVERFLOW
:
561 return POPT_("number too large or too small");
562 case POPT_ERROR_ERRNO
:
563 return strerror(errno
);
565 return POPT_("unknown error");
569 int poptStuffArgs(poptContext con
, char ** argv
) {
572 if ((con
->os
- con
->optionStack
) == POPT_OPTION_DEPTH
)
573 return POPT_ERROR_OPTSTOODEEP
;
575 for (i
= 0; argv
[i
]; i
++);
579 con
->os
->nextArg
= con
->os
->nextCharArg
= NULL
;
580 con
->os
->currAlias
= NULL
;
582 con
->os
->argv
= argv
;
583 con
->os
->stuffed
= 1;
588 const char * poptGetInvocationName(poptContext con
) {
589 return con
->os
->argv
[0];