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
) {
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
);
235 static const struct poptOption
* findOption(const struct poptOption
* table
,
236 const char * longName
,
238 poptCallbackType
* callback
,
239 void ** callbackData
,
241 const struct poptOption
* opt
= table
;
242 const struct poptOption
* opt2
;
243 const struct poptOption
* cb
= NULL
;
245 /* This happens when a single - is given */
246 if (singleDash
&& !shortName
&& !*longName
)
249 while (opt
->longName
|| opt
->shortName
|| opt
->arg
) {
250 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
251 opt2
= findOption(opt
->arg
, longName
, shortName
, callback
,
252 callbackData
, singleDash
);
254 if (*callback
&& !*callbackData
)
255 *callbackData
= opt
->descrip
;
258 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
) {
260 } else if (longName
&& opt
->longName
&&
261 (!singleDash
|| (opt
->argInfo
& POPT_ARGFLAG_ONEDASH
)) &&
262 !strcmp(longName
, opt
->longName
)) {
264 } else if (shortName
&& shortName
== opt
->shortName
) {
270 if (!opt
->longName
&& !opt
->shortName
) return NULL
;
271 *callbackData
= NULL
;
274 *callback
= (poptCallbackType
)cb
->arg
;
275 if (!(cb
->argInfo
& POPT_CBFLAG_INC_DATA
))
276 *callbackData
= cb
->descrip
;
282 /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
283 int poptGetNextOpt(poptContext con
) {
284 char * optString
, * chptr
, * localOptString
;
285 char * longArg
= NULL
;
286 char * origOptString
;
289 const struct poptOption
* opt
= NULL
;
297 while (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
298 && con
->os
> con
->optionStack
)
300 if (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
) {
301 invokeCallbacks(con
, con
->options
, 1);
302 if (con
->doExec
) execCommand(con
);
306 if (!con
->os
->nextCharArg
) {
308 origOptString
= con
->os
->argv
[con
->os
->next
++];
310 if (con
->restLeftover
|| *origOptString
!= '-') {
311 con
->leftovers
[con
->numLeftovers
++] = origOptString
;
312 if (con
->flags
& POPT_CONTEXT_POSIXMEHARDER
)
313 con
->restLeftover
= 1;
317 /* Make a copy we can hack at */
318 localOptString
= optString
=
319 strcpy(alloca(strlen(origOptString
) + 1),
323 return POPT_ERROR_BADOPT
;
325 if (optString
[1] == '-' && !optString
[2]) {
326 con
->restLeftover
= 1;
330 if (*optString
== '-')
331 singleDash
= 0, optString
++;
335 if (handleAlias(con
, optString
, '\0', NULL
))
337 if (handleExec(con
, optString
, '\0'))
341 while (*chptr
&& *chptr
!= '=') chptr
++;
343 longArg
= origOptString
+ (chptr
- localOptString
) + 1;
347 opt
= findOption(con
->options
, optString
, '\0', &cb
, &cbData
,
349 if (!opt
&& !singleDash
) return POPT_ERROR_BADOPT
;
353 con
->os
->nextCharArg
= origOptString
+ 1;
356 if (con
->os
->nextCharArg
) {
357 origOptString
= con
->os
->nextCharArg
;
359 con
->os
->nextCharArg
= NULL
;
361 if (handleAlias(con
, NULL
, *origOptString
,
362 origOptString
+ 1)) {
366 if (handleExec(con
, NULL
, *origOptString
))
369 opt
= findOption(con
->options
, NULL
, *origOptString
, &cb
,
371 if (!opt
) return POPT_ERROR_BADOPT
;
375 con
->os
->nextCharArg
= origOptString
;
378 if (opt
->arg
&& (opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_NONE
) {
379 *((int *)opt
->arg
) = 1;
380 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_VAL
) {
381 if (opt
->arg
) *((int *) opt
->arg
) = opt
->val
;
382 } else if ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_NONE
) {
384 con
->os
->nextArg
= longArg
;
385 } else if (con
->os
->nextCharArg
) {
386 con
->os
->nextArg
= con
->os
->nextCharArg
;
387 con
->os
->nextCharArg
= NULL
;
389 while (con
->os
->next
== con
->os
->argc
&&
390 con
->os
> con
->optionStack
)
392 if (con
->os
->next
== con
->os
->argc
)
393 return POPT_ERROR_NOARG
;
395 con
->os
->nextArg
= con
->os
->argv
[con
->os
->next
++];
399 switch (opt
->argInfo
& POPT_ARG_MASK
) {
400 case POPT_ARG_STRING
:
401 *((char **) opt
->arg
) = con
->os
->nextArg
;
406 aLong
= strtol(con
->os
->nextArg
, &end
, 0);
407 if (!(end
&& *end
== '\0'))
408 return POPT_ERROR_BADNUMBER
;
410 if (aLong
== LONG_MIN
|| aLong
== LONG_MAX
)
411 return POPT_ERROR_OVERFLOW
;
412 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_LONG
) {
413 *((long *) opt
->arg
) = aLong
;
415 if (aLong
> INT_MAX
|| aLong
< INT_MIN
)
416 return POPT_ERROR_OVERFLOW
;
417 *((int *) opt
->arg
) =aLong
;
422 fprintf(stdout
, POPT_("option type (%d) not implemented in popt\n"),
423 opt
->argInfo
& POPT_ARG_MASK
);
430 cb(con
, POPT_CALLBACK_REASON_OPTION
, opt
, con
->os
->nextArg
, cbData
);
431 else if (opt
->val
&& ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_VAL
))
434 if ((con
->finalArgvCount
+ 2) >= (con
->finalArgvAlloced
)) {
435 con
->finalArgvAlloced
+= 10;
436 con
->finalArgv
= realloc(con
->finalArgv
,
437 sizeof(*con
->finalArgv
) * con
->finalArgvAlloced
);
440 i
= con
->finalArgvCount
++;
442 malloc((opt
->longName
? strlen(opt
->longName
) : 0) + 3);
444 sprintf(con
->finalArgv
[i
], "--%s", opt
->longName
);
446 sprintf(con
->finalArgv
[i
], "-%c", opt
->shortName
);
448 if (opt
->arg
&& (opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_NONE
449 && (opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_VAL
)
450 con
->finalArgv
[con
->finalArgvCount
++] = strdup(con
->os
->nextArg
);
456 char * poptGetOptArg(poptContext con
) {
457 char * ret
= con
->os
->nextArg
;
458 con
->os
->nextArg
= NULL
;
462 char * poptGetArg(poptContext con
) {
463 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
464 return (con
->leftovers
[con
->nextLeftover
++]);
467 char * poptPeekArg(poptContext con
) {
468 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
469 return (con
->leftovers
[con
->nextLeftover
]);
472 char ** poptGetArgs(poptContext con
) {
473 if (con
->numLeftovers
== con
->nextLeftover
) return NULL
;
475 /* some apps like [like RPM ;-) ] need this NULL terminated */
476 con
->leftovers
[con
->numLeftovers
] = NULL
;
478 return (con
->leftovers
+ con
->nextLeftover
);
481 void poptFreeContext(poptContext con
) {
484 for (i
= 0; i
< con
->numAliases
; i
++) {
485 if (con
->aliases
[i
].longName
) free(con
->aliases
[i
].longName
);
486 free(con
->aliases
[i
].argv
);
489 for (i
= 0; i
< con
->numExecs
; i
++) {
490 if (con
->execs
[i
].longName
) free(con
->execs
[i
].longName
);
491 free(con
->execs
[i
].script
);
494 for (i
= 0; i
< con
->finalArgvCount
; i
++)
495 free(con
->finalArgv
[i
]);
497 free(con
->leftovers
);
498 free(con
->finalArgv
);
499 if (con
->appName
) free(con
->appName
);
500 if (con
->aliases
) free(con
->aliases
);
501 if (con
->otherHelp
) free(con
->otherHelp
);
502 if (con
->execPath
) free(con
->execPath
);
506 int poptAddAlias(poptContext con
, struct poptAlias newAlias
, int flags
) {
507 int aliasNum
= con
->numAliases
++;
508 struct poptAlias
* alias
;
510 /* SunOS won't realloc(NULL, ...) */
512 con
->aliases
= malloc(sizeof(newAlias
) * con
->numAliases
);
514 con
->aliases
= realloc(con
->aliases
,
515 sizeof(newAlias
) * con
->numAliases
);
516 alias
= con
->aliases
+ aliasNum
;
520 alias
->longName
= strcpy(malloc(strlen(alias
->longName
) + 1),
523 alias
->longName
= NULL
;
528 char * poptBadOption(poptContext con
, int flags
) {
529 struct optionStackEntry
* os
;
531 if (flags
& POPT_BADOPTION_NOALIAS
)
532 os
= con
->optionStack
;
536 return os
->argv
[os
->next
- 1];
539 #define POPT_ERROR_NOARG -10
540 #define POPT_ERROR_BADOPT -11
541 #define POPT_ERROR_OPTSTOODEEP -13
542 #define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
543 #define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
545 const char * poptStrerror(const int error
) {
547 case POPT_ERROR_NOARG
:
548 return POPT_("missing argument");
549 case POPT_ERROR_BADOPT
:
550 return POPT_("unknown option");
551 case POPT_ERROR_OPTSTOODEEP
:
552 return POPT_("aliases nested too deeply");
553 case POPT_ERROR_BADQUOTE
:
554 return POPT_("error in paramter quoting");
555 case POPT_ERROR_BADNUMBER
:
556 return POPT_("invalid numeric value");
557 case POPT_ERROR_OVERFLOW
:
558 return POPT_("number too large or too small");
559 case POPT_ERROR_ERRNO
:
560 return strerror(errno
);
562 return POPT_("unknown error");
566 int poptStuffArgs(poptContext con
, char ** argv
) {
569 if ((con
->os
- con
->optionStack
) == POPT_OPTION_DEPTH
)
570 return POPT_ERROR_OPTSTOODEEP
;
572 for (i
= 0; argv
[i
]; i
++);
576 con
->os
->nextArg
= con
->os
->nextCharArg
= NULL
;
577 con
->os
->currAlias
= NULL
;
579 con
->os
->argv
= argv
;
580 con
->os
->stuffed
= 1;
585 const char * poptGetInvocationName(poptContext con
) {
586 return con
->os
->argv
[0];