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"
25 static char * strerror(int errno
) {
27 extern char * sys_errlist
[];
29 if ((0 <= errno
) && (errno
< sys_nerr
))
30 return sys_errlist
[errno
];
32 return POPT_("unknown errno");
36 void poptSetExecPath(poptContext con
, const char * path
, int allowAbsolute
) {
37 if (con
->execPath
) free(con
->execPath
);
38 con
->execPath
= strdup(path
);
39 con
->execAbsolute
= allowAbsolute
;
42 static void invokeCallbacks(poptContext con
, const struct poptOption
* table
,
44 const struct poptOption
* opt
= table
;
47 while (opt
->longName
|| opt
->shortName
|| opt
->arg
) {
48 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
49 invokeCallbacks(con
, opt
->arg
, post
);
50 } else if (((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
) &&
51 ((!post
&& (opt
->argInfo
& POPT_CBFLAG_PRE
)) ||
52 ( post
&& (opt
->argInfo
& POPT_CBFLAG_POST
)))) {
53 cb
= (poptCallbackType
)opt
->arg
;
54 cb(con
, post
? POPT_CALLBACK_REASON_POST
: POPT_CALLBACK_REASON_PRE
,
55 NULL
, NULL
, opt
->descrip
);
61 poptContext
poptGetContext(char * name
, int argc
, char ** argv
,
62 const struct poptOption
* options
, int flags
) {
63 poptContext con
= malloc(sizeof(*con
));
65 memset(con
, 0, sizeof(*con
));
67 con
->os
= con
->optionStack
;
71 if (!(flags
& POPT_CONTEXT_KEEP_FIRST
))
72 con
->os
->next
= 1; /* skip argv[0] */
74 con
->leftovers
= malloc(sizeof(char *) * (argc
+ 1));
75 con
->options
= options
;
76 con
->finalArgv
= malloc(sizeof(*con
->finalArgv
) * (argc
* 2));
77 con
->finalArgvAlloced
= argc
* 2;
79 con
->execAbsolute
= 1;
81 if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
82 con
->flags
|= POPT_CONTEXT_POSIXMEHARDER
;
85 con
->appName
= strcpy(malloc(strlen(name
) + 1), name
);
87 invokeCallbacks(con
, con
->options
, 0);
92 void poptResetContext(poptContext con
) {
95 con
->os
= con
->optionStack
;
96 con
->os
->currAlias
= NULL
;
97 con
->os
->nextCharArg
= NULL
;
98 con
->os
->nextArg
= NULL
;
99 con
->os
->next
= 1; /* skip argv[0] */
101 con
->numLeftovers
= 0;
102 con
->nextLeftover
= 0;
103 con
->restLeftover
= 0;
106 for (i
= 0; i
< con
->finalArgvCount
; i
++)
107 free(con
->finalArgv
[i
]);
109 con
->finalArgvCount
= 0;
112 /* Only one of longName, shortName may be set at a time */
113 static int handleExec(poptContext con
, char * longName
, char shortName
) {
116 i
= con
->numExecs
- 1;
118 while (i
>= 0 && (!con
->execs
[i
].longName
||
119 strcmp(con
->execs
[i
].longName
, longName
))) i
--;
122 con
->execs
[i
].shortName
!= shortName
) i
--;
127 if (con
->flags
& POPT_CONTEXT_NO_EXEC
)
131 con
->doExec
= con
->execs
+ i
;
135 /* We already have an exec to do; remember this option for next
137 if ((con
->finalArgvCount
+ 1) >= (con
->finalArgvAlloced
)) {
138 con
->finalArgvAlloced
+= 10;
139 con
->finalArgv
= realloc(con
->finalArgv
,
140 sizeof(*con
->finalArgv
) * con
->finalArgvAlloced
);
143 i
= con
->finalArgvCount
++;
144 con
->finalArgv
[i
] = malloc((longName
? strlen(longName
) : 0) + 3);
146 sprintf(con
->finalArgv
[i
], "--%s", longName
);
148 sprintf(con
->finalArgv
[i
], "-%c", shortName
);
153 /* Only one of longName, shortName may be set at a time */
154 static int handleAlias(poptContext con
, char * longName
, char shortName
,
155 char * nextCharArg
) {
158 if (con
->os
->currAlias
&& con
->os
->currAlias
->longName
&& longName
&&
159 !strcmp(con
->os
->currAlias
->longName
, longName
))
161 if (con
->os
->currAlias
&& shortName
&&
162 shortName
== con
->os
->currAlias
->shortName
)
165 i
= con
->numAliases
- 1;
167 while (i
>= 0 && (!con
->aliases
[i
].longName
||
168 strcmp(con
->aliases
[i
].longName
, longName
))) i
--;
171 con
->aliases
[i
].shortName
!= shortName
) i
--;
176 if ((con
->os
- con
->optionStack
+ 1)
177 == POPT_OPTION_DEPTH
)
178 return POPT_ERROR_OPTSTOODEEP
;
180 if (nextCharArg
&& *nextCharArg
)
181 con
->os
->nextCharArg
= nextCharArg
;
185 con
->os
->stuffed
= 0;
186 con
->os
->nextArg
= con
->os
->nextCharArg
= NULL
;
187 con
->os
->currAlias
= con
->aliases
+ i
;
188 con
->os
->argc
= con
->os
->currAlias
->argc
;
189 con
->os
->argv
= con
->os
->currAlias
->argv
;
194 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
;
228 execvp(argv
[0], argv
);
234 static const struct poptOption
* findOption(const struct poptOption
* table
,
235 const char * longName
,
237 poptCallbackType
* callback
,
238 void ** callbackData
,
240 const struct poptOption
* opt
= table
;
241 const struct poptOption
* opt2
;
242 const struct poptOption
* cb
= NULL
;
244 /* This happens when a single - is given */
245 if (singleDash
&& !shortName
&& !*longName
)
248 while (opt
->longName
|| opt
->shortName
|| opt
->arg
) {
249 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
250 opt2
= findOption(opt
->arg
, longName
, shortName
, callback
,
251 callbackData
, singleDash
);
253 if (*callback
&& !*callbackData
)
254 *callbackData
= opt
->descrip
;
257 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
) {
259 } else if (longName
&& opt
->longName
&&
260 (!singleDash
|| (opt
->argInfo
& POPT_ARGFLAG_ONEDASH
)) &&
261 !strcmp(longName
, opt
->longName
)) {
263 } else if (shortName
&& shortName
== opt
->shortName
) {
269 if (!opt
->longName
&& !opt
->shortName
) return NULL
;
270 *callbackData
= NULL
;
273 *callback
= (poptCallbackType
)cb
->arg
;
274 if (!(cb
->argInfo
& POPT_CBFLAG_INC_DATA
))
275 *callbackData
= cb
->descrip
;
281 /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
282 int poptGetNextOpt(poptContext con
) {
283 char * optString
, * chptr
, * localOptString
;
284 char * longArg
= NULL
;
285 char * origOptString
;
288 const struct poptOption
* opt
= NULL
;
296 while (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
297 && con
->os
> con
->optionStack
)
299 if (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
) {
300 invokeCallbacks(con
, con
->options
, 1);
301 if (con
->doExec
) execCommand(con
);
305 if (!con
->os
->nextCharArg
) {
307 origOptString
= con
->os
->argv
[con
->os
->next
++];
309 if (con
->restLeftover
|| *origOptString
!= '-') {
310 con
->leftovers
[con
->numLeftovers
++] = origOptString
;
311 if (con
->flags
& POPT_CONTEXT_POSIXMEHARDER
)
312 con
->restLeftover
= 1;
316 /* Make a copy we can hack at */
317 localOptString
= optString
=
318 strcpy(alloca(strlen(origOptString
) + 1),
322 return POPT_ERROR_BADOPT
;
324 if (optString
[1] == '-' && !optString
[2]) {
325 con
->restLeftover
= 1;
329 if (*optString
== '-')
330 singleDash
= 0, optString
++;
334 if (handleAlias(con
, optString
, '\0', NULL
))
336 if (handleExec(con
, optString
, '\0'))
340 while (*chptr
&& *chptr
!= '=') chptr
++;
342 longArg
= origOptString
+ (chptr
- localOptString
) + 1;
346 opt
= findOption(con
->options
, optString
, '\0', &cb
, &cbData
,
348 if (!opt
&& !singleDash
) return POPT_ERROR_BADOPT
;
352 con
->os
->nextCharArg
= origOptString
+ 1;
355 if (con
->os
->nextCharArg
) {
356 origOptString
= con
->os
->nextCharArg
;
358 con
->os
->nextCharArg
= NULL
;
360 if (handleAlias(con
, NULL
, *origOptString
,
361 origOptString
+ 1)) {
365 if (handleExec(con
, NULL
, *origOptString
))
368 opt
= findOption(con
->options
, NULL
, *origOptString
, &cb
,
370 if (!opt
) return POPT_ERROR_BADOPT
;
374 con
->os
->nextCharArg
= origOptString
;
377 if (opt
->arg
&& (opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_NONE
) {
378 *((int *)opt
->arg
) = 1;
379 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_VAL
) {
380 if (opt
->arg
) *((int *) opt
->arg
) = opt
->val
;
381 } else if ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_NONE
) {
383 con
->os
->nextArg
= longArg
;
384 } else if (con
->os
->nextCharArg
) {
385 con
->os
->nextArg
= con
->os
->nextCharArg
;
386 con
->os
->nextCharArg
= NULL
;
388 while (con
->os
->next
== con
->os
->argc
&&
389 con
->os
> con
->optionStack
)
391 if (con
->os
->next
== con
->os
->argc
)
392 return POPT_ERROR_NOARG
;
394 con
->os
->nextArg
= con
->os
->argv
[con
->os
->next
++];
398 switch (opt
->argInfo
& POPT_ARG_MASK
) {
399 case POPT_ARG_STRING
:
400 *((char **) opt
->arg
) = con
->os
->nextArg
;
405 aLong
= strtol(con
->os
->nextArg
, &end
, 0);
406 if (!(end
&& *end
== '\0'))
407 return POPT_ERROR_BADNUMBER
;
409 if (aLong
== LONG_MIN
|| aLong
== LONG_MAX
)
410 return POPT_ERROR_OVERFLOW
;
411 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_LONG
) {
412 *((long *) opt
->arg
) = aLong
;
414 if (aLong
> INT_MAX
|| aLong
< INT_MIN
)
415 return POPT_ERROR_OVERFLOW
;
416 *((int *) opt
->arg
) =aLong
;
421 fprintf(stdout
, POPT_("option type (%d) not implemented in popt\n"),
422 opt
->argInfo
& POPT_ARG_MASK
);
429 cb(con
, POPT_CALLBACK_REASON_OPTION
, opt
, con
->os
->nextArg
, cbData
);
430 else if (opt
->val
&& ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_VAL
))
433 if ((con
->finalArgvCount
+ 2) >= (con
->finalArgvAlloced
)) {
434 con
->finalArgvAlloced
+= 10;
435 con
->finalArgv
= realloc(con
->finalArgv
,
436 sizeof(*con
->finalArgv
) * con
->finalArgvAlloced
);
439 i
= con
->finalArgvCount
++;
441 malloc((opt
->longName
? strlen(opt
->longName
) : 0) + 3);
443 sprintf(con
->finalArgv
[i
], "--%s", opt
->longName
);
445 sprintf(con
->finalArgv
[i
], "-%c", opt
->shortName
);
447 if (opt
->arg
&& (opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_NONE
448 && (opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_VAL
)
449 con
->finalArgv
[con
->finalArgvCount
++] = strdup(con
->os
->nextArg
);
455 char * poptGetOptArg(poptContext con
) {
456 char * ret
= con
->os
->nextArg
;
457 con
->os
->nextArg
= NULL
;
461 char * poptGetArg(poptContext con
) {
462 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
463 return (con
->leftovers
[con
->nextLeftover
++]);
466 char * poptPeekArg(poptContext con
) {
467 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
468 return (con
->leftovers
[con
->nextLeftover
]);
471 char ** poptGetArgs(poptContext con
) {
472 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
474 /* some apps like [like RPM ;-) ] need this NULL terminated */
475 con
->leftovers
[con
->numLeftovers
] = NULL
;
477 return (con
->leftovers
+ con
->nextLeftover
);
480 void poptFreeContext(poptContext con
) {
483 for (i
= 0; i
< con
->numAliases
; i
++) {
484 if (con
->aliases
[i
].longName
) free(con
->aliases
[i
].longName
);
485 free(con
->aliases
[i
].argv
);
488 for (i
= 0; i
< con
->numExecs
; i
++) {
489 if (con
->execs
[i
].longName
) free(con
->execs
[i
].longName
);
490 free(con
->execs
[i
].script
);
493 for (i
= 0; i
< con
->finalArgvCount
; i
++)
494 free(con
->finalArgv
[i
]);
496 free(con
->leftovers
);
497 free(con
->finalArgv
);
498 if (con
->appName
) free(con
->appName
);
499 if (con
->aliases
) free(con
->aliases
);
500 if (con
->otherHelp
) free(con
->otherHelp
);
501 if (con
->execPath
) free(con
->execPath
);
505 int poptAddAlias(poptContext con
, struct poptAlias newAlias
, int flags
) {
506 int aliasNum
= con
->numAliases
++;
507 struct poptAlias
* alias
;
509 /* SunOS won't realloc(NULL, ...) */
511 con
->aliases
= malloc(sizeof(newAlias
) * con
->numAliases
);
513 con
->aliases
= realloc(con
->aliases
,
514 sizeof(newAlias
) * con
->numAliases
);
515 alias
= con
->aliases
+ aliasNum
;
519 alias
->longName
= strcpy(malloc(strlen(alias
->longName
) + 1),
522 alias
->longName
= NULL
;
527 char * poptBadOption(poptContext con
, int flags
) {
528 struct optionStackEntry
* os
;
530 if (flags
& POPT_BADOPTION_NOALIAS
)
531 os
= con
->optionStack
;
535 return os
->argv
[os
->next
- 1];
538 #define POPT_ERROR_NOARG -10
539 #define POPT_ERROR_BADOPT -11
540 #define POPT_ERROR_OPTSTOODEEP -13
541 #define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
542 #define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
544 const char * poptStrerror(const int error
) {
546 case POPT_ERROR_NOARG
:
547 return _("missing argument");
548 case POPT_ERROR_BADOPT
:
549 return _("unknown option");
550 case POPT_ERROR_OPTSTOODEEP
:
551 return POPT_("aliases nested too deeply");
552 case POPT_ERROR_BADQUOTE
:
553 return POPT_("error in parameter quoting");
554 case POPT_ERROR_BADNUMBER
:
555 return _("invalid numeric value");
556 case POPT_ERROR_OVERFLOW
:
557 return POPT_("number too large or too small");
558 case POPT_ERROR_ERRNO
:
559 return strerror(errno
);
561 return POPT_("unknown error");
565 int poptStuffArgs(poptContext con
, char ** argv
) {
568 if ((con
->os
- con
->optionStack
) == POPT_OPTION_DEPTH
)
569 return POPT_ERROR_OPTSTOODEEP
;
571 for (i
= 0; argv
[i
]; i
++);
575 con
->os
->nextArg
= con
->os
->nextCharArg
= NULL
;
576 con
->os
->currAlias
= NULL
;
578 con
->os
->argv
= argv
;
579 con
->os
->stuffed
= 1;
584 const char * poptGetInvocationName(poptContext con
) {
585 return con
->os
->argv
[0];