5 /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
6 file accompanying popt source distributions, available from
7 ftp://ftp.rpm.org/pub/rpm/dist */
22 #define DBL_EPSILON 2.2204460492503131e-16
30 #if !defined(HAVE_STRERROR) && !defined(__LCLINT__)
31 static char * strerror(int errno
)
34 extern char * sys_errlist
[];
36 if ((0 <= errno
) && (errno
< sys_nerr
))
37 return sys_errlist
[errno
];
39 return POPT_("unknown errno");
45 static void prtcon(const char *msg
, poptContext con
)
47 if (msg
) fprintf(stderr
, "%s", msg
);
48 fprintf(stderr
, "\tcon %p os %p nextCharArg \"%s\" nextArg \"%s\" argv[%d] \"%s\"\n",
50 (con
->os
->nextCharArg
? con
->os
->nextCharArg
: ""),
51 (con
->os
->nextArg
? con
->os
->nextArg
: ""),
53 (con
->os
->argv
&& con
->os
->argv
[con
->os
->next
]
54 ? con
->os
->argv
[con
->os
->next
] : ""));
58 void poptSetExecPath(poptContext con
, const char * path
, int allowAbsolute
)
60 con
->execPath
= _free(con
->execPath
);
61 con
->execPath
= xstrdup(path
);
62 con
->execAbsolute
= allowAbsolute
;
63 /*@-nullstate@*/ /* LCL: con->execPath not NULL */
68 static void invokeCallbacksPRE(poptContext con
, const struct poptOption
* opt
)
69 /*@globals internalState@*/
70 /*@modifies internalState@*/
73 for (; opt
->longName
|| opt
->shortName
|| opt
->arg
; opt
++) {
74 if (opt
->arg
== NULL
) continue; /* XXX program error. */
75 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
76 void * arg
= opt
->arg
;
78 /* XXX sick hack to preserve pretense of ABI. */
79 if (arg
== poptHelpOptions
) arg
= poptHelpOptionsI18N
;
81 /* Recurse on included sub-tables. */
82 invokeCallbacksPRE(con
, arg
);
83 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
&&
84 (opt
->argInfo
& POPT_CBFLAG_PRE
))
86 poptCallbackType cb
= (poptCallbackType
)opt
->arg
;
88 /* Perform callback. */
90 cb(con
, POPT_CALLBACK_REASON_PRE
, NULL
, NULL
, opt
->descrip
);
96 static void invokeCallbacksPOST(poptContext con
, const struct poptOption
* opt
)
97 /*@globals internalState@*/
98 /*@modifies internalState@*/
101 for (; opt
->longName
|| opt
->shortName
|| opt
->arg
; opt
++) {
102 if (opt
->arg
== NULL
) continue; /* XXX program error. */
103 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
104 void * arg
= opt
->arg
;
106 /* XXX sick hack to preserve pretense of ABI. */
107 if (arg
== poptHelpOptions
) arg
= poptHelpOptionsI18N
;
109 /* Recurse on included sub-tables. */
110 invokeCallbacksPOST(con
, arg
);
111 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
&&
112 (opt
->argInfo
& POPT_CBFLAG_POST
))
114 poptCallbackType cb
= (poptCallbackType
)opt
->arg
;
116 /* Perform callback. */
117 /*@-noeffectuncon @*/
118 cb(con
, POPT_CALLBACK_REASON_POST
, NULL
, NULL
, opt
->descrip
);
119 /*@=noeffectuncon @*/
124 static void invokeCallbacksOPTION(poptContext con
,
125 const struct poptOption
* opt
,
126 const struct poptOption
* myOpt
,
127 /*@null@*/ const void * myData
, int shorty
)
128 /*@globals internalState@*/
129 /*@modifies internalState@*/
131 const struct poptOption
* cbopt
= NULL
;
134 for (; opt
->longName
|| opt
->shortName
|| opt
->arg
; opt
++) {
135 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
136 void * arg
= opt
->arg
;
138 /* XXX sick hack to preserve pretense of ABI. */
139 if (arg
== poptHelpOptions
) arg
= poptHelpOptionsI18N
;
141 /* Recurse on included sub-tables. */
142 if (opt
->arg
!= NULL
) /* XXX program error */
143 invokeCallbacksOPTION(con
, opt
->arg
, myOpt
, myData
, shorty
);
144 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
&&
145 !(opt
->argInfo
& POPT_CBFLAG_SKIPOPTION
)) {
146 /* Save callback info. */
148 } else if (cbopt
!= NULL
&&
149 ((myOpt
->shortName
&& opt
->shortName
&& shorty
&&
150 myOpt
->shortName
== opt
->shortName
) ||
151 (myOpt
->longName
&& opt
->longName
&&
152 /*@-nullpass@*/ /* LCL: opt->longName != NULL */
153 !strcmp(myOpt
->longName
, opt
->longName
)))
157 poptCallbackType cb
= (poptCallbackType
)cbopt
->arg
;
159 const void * cbData
= (cbopt
->descrip
? cbopt
->descrip
: myData
);
160 /* Perform callback. */
161 if (cb
!= NULL
) { /* XXX program error */
162 /*@-noeffectuncon @*/
163 cb(con
, POPT_CALLBACK_REASON_OPTION
, myOpt
,
164 con
->os
->nextArg
, cbData
);
165 /*@=noeffectuncon @*/
167 /* Terminate (unless explcitly continuing). */
168 if (!(cbopt
->argInfo
& POPT_CBFLAG_CONTINUE
))
174 poptContext
poptGetContext(const char * name
, int argc
, const char ** argv
,
175 const struct poptOption
* options
, int flags
)
177 poptContext con
= malloc(sizeof(*con
));
179 if (con
== NULL
) return NULL
; /* XXX can't happen */
180 memset(con
, 0, sizeof(*con
));
182 con
->os
= con
->optionStack
;
183 con
->os
->argc
= argc
;
184 /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */
185 con
->os
->argv
= argv
;
186 /*@=dependenttrans =assignexpose@*/
187 con
->os
->argb
= NULL
;
189 if (!(flags
& POPT_CONTEXT_KEEP_FIRST
))
190 con
->os
->next
= 1; /* skip argv[0] */
192 con
->leftovers
= calloc( (argc
+ 1), sizeof(*con
->leftovers
) );
193 /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */
194 con
->options
= options
;
195 /*@=dependenttrans =assignexpose@*/
201 con
->finalArgvAlloced
= argc
* 2;
202 con
->finalArgv
= calloc( con
->finalArgvAlloced
, sizeof(*con
->finalArgv
) );
203 con
->execAbsolute
= 1;
204 con
->arg_strip
= NULL
;
206 if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
207 con
->flags
|= POPT_CONTEXT_POSIXMEHARDER
;
210 size_t bufsize
= strlen(name
) + 1;
211 char * t
= malloc(bufsize
);
213 strlcpy(t
, name
, bufsize
);
219 invokeCallbacksPRE(con
, con
->options
);
225 static void cleanOSE(/*@special@*/ struct optionStackEntry
*os
)
227 /*@releases os->nextArg, os->argv, os->argb @*/
230 os
->nextArg
= _free(os
->nextArg
);
231 os
->argv
= _free(os
->argv
);
232 os
->argb
= PBM_FREE(os
->argb
);
236 void poptResetContext(poptContext con
)
240 if (con
== NULL
) return;
241 while (con
->os
> con
->optionStack
) {
244 con
->os
->argb
= PBM_FREE(con
->os
->argb
);
245 con
->os
->currAlias
= NULL
;
246 con
->os
->nextCharArg
= NULL
;
247 con
->os
->nextArg
= NULL
;
248 con
->os
->next
= 1; /* skip argv[0] */
250 con
->numLeftovers
= 0;
251 con
->nextLeftover
= 0;
252 con
->restLeftover
= 0;
255 if (con
->finalArgv
!= NULL
)
256 for (i
= 0; i
< con
->finalArgvCount
; i
++) {
257 /*@-unqualifiedtrans@*/ /* FIX: typedef double indirection. */
258 con
->finalArgv
[i
] = _free(con
->finalArgv
[i
]);
259 /*@=unqualifiedtrans@*/
262 con
->finalArgvCount
= 0;
263 con
->arg_strip
= PBM_FREE(con
->arg_strip
);
264 /*@-nullstate@*/ /* FIX: con->finalArgv != NULL */
270 /* Only one of longName, shortName should be set, not both. */
272 static int handleExec(/*@special@*/ poptContext con
,
273 /*@null@*/ const char * longName
, char shortName
)
274 /*@uses con->execs, con->numExecs, con->flags, con->doExec,
275 con->finalArgv, con->finalArgvAlloced, con->finalArgvCount @*/
281 if (con
->execs
== NULL
|| con
->numExecs
<= 0) /* XXX can't happen */
284 for (i
= con
->numExecs
- 1; i
>= 0; i
--) {
285 item
= con
->execs
+ i
;
286 if (longName
&& !(item
->option
.longName
&&
287 !strcmp(longName
, item
->option
.longName
)))
289 else if (shortName
!= item
->option
.shortName
)
296 if (con
->flags
& POPT_CONTEXT_NO_EXEC
)
299 if (con
->doExec
== NULL
) {
300 con
->doExec
= con
->execs
+ i
;
304 /* We already have an exec to do; remember this option for next
306 if ((con
->finalArgvCount
+ 1) >= (con
->finalArgvAlloced
)) {
307 con
->finalArgvAlloced
+= 10;
308 con
->finalArgv
= realloc(con
->finalArgv
,
309 sizeof(*con
->finalArgv
) * con
->finalArgvAlloced
);
312 i
= con
->finalArgvCount
++;
313 if (con
->finalArgv
!= NULL
) /* XXX can't happen */
314 { size_t bufsize
= (longName
? strlen(longName
) : 0) + 3;
315 char *s
= malloc(bufsize
);
316 if (s
!= NULL
) { /* XXX can't happen */
318 snprintf(s
, bufsize
, "--%s", longName
);
320 snprintf(s
, bufsize
, "-%c", shortName
);
321 con
->finalArgv
[i
] = s
;
323 con
->finalArgv
[i
] = NULL
;
326 /*@-nullstate@*/ /* FIX: con->finalArgv[] == NULL */
332 /* Only one of longName, shortName may be set at a time */
333 static int handleAlias(/*@special@*/ poptContext con
,
334 /*@null@*/ const char * longName
, char shortName
,
335 /*@exposed@*/ /*@null@*/ const char * nextCharArg
)
336 /*@uses con->aliases, con->numAliases, con->optionStack, con->os,
337 con->os->currAlias, con->os->currAlias->option.longName @*/
340 poptItem item
= con
->os
->currAlias
;
345 if (longName
&& (item
->option
.longName
&&
346 !strcmp(longName
, item
->option
.longName
)))
348 if (shortName
&& shortName
== item
->option
.shortName
)
352 if (con
->aliases
== NULL
|| con
->numAliases
<= 0) /* XXX can't happen */
355 for (i
= con
->numAliases
- 1; i
>= 0; i
--) {
356 item
= con
->aliases
+ i
;
357 if (longName
&& !(item
->option
.longName
&&
358 !strcmp(longName
, item
->option
.longName
)))
360 else if (shortName
!= item
->option
.shortName
)
366 if ((con
->os
- con
->optionStack
+ 1) == POPT_OPTION_DEPTH
)
367 return POPT_ERROR_OPTSTOODEEP
;
370 if (nextCharArg
&& *nextCharArg
)
371 con
->os
->nextCharArg
= nextCharArg
;
376 con
->os
->stuffed
= 0;
377 con
->os
->nextArg
= NULL
;
378 con
->os
->nextCharArg
= NULL
;
379 con
->os
->currAlias
= con
->aliases
+ i
;
380 rc
= poptDupArgv(con
->os
->currAlias
->argc
, con
->os
->currAlias
->argv
,
381 &con
->os
->argc
, &con
->os
->argv
);
382 con
->os
->argb
= NULL
;
384 return (rc
? rc
: 1);
387 /*@-bounds -boundswrite @*/
388 static int execCommand(poptContext con
)
389 /*@globals internalState @*/
390 /*@modifies internalState @*/
392 poptItem item
= con
->doExec
;
396 if (item
== NULL
) /*XXX can't happen*/
397 return POPT_ERROR_NOARG
;
399 if (item
->argv
== NULL
|| item
->argc
< 1 ||
400 (!con
->execAbsolute
&& strchr(item
->argv
[0], '/')))
401 return POPT_ERROR_NOARG
;
403 argv
= malloc(sizeof(*argv
) *
404 (6 + item
->argc
+ con
->numLeftovers
+ con
->finalArgvCount
));
405 if (argv
== NULL
) return POPT_ERROR_MALLOC
;
407 if (!strchr(item
->argv
[0], '/') && con
->execPath
!= NULL
) {
408 size_t bufsize
= strlen(con
->execPath
) + strlen(item
->argv
[0]) + sizeof "/";
409 char *s
= alloca(bufsize
);
410 snprintf(s
, bufsize
, "%s/%s", con
->execPath
, item
->argv
[0]);
413 argv
[argc
] = findProgramPath(item
->argv
[0]);
414 if (argv
[argc
++] == NULL
) return POPT_ERROR_NOARG
;
416 if (item
->argc
> 1) {
417 memcpy(argv
+ argc
, item
->argv
+ 1, sizeof(*argv
) * (item
->argc
- 1));
418 argc
+= (item
->argc
- 1);
421 if (con
->finalArgv
!= NULL
&& con
->finalArgvCount
> 0) {
422 memcpy(argv
+ argc
, con
->finalArgv
,
423 sizeof(*argv
) * con
->finalArgvCount
);
424 argc
+= con
->finalArgvCount
;
427 if (con
->leftovers
!= NULL
&& con
->numLeftovers
> 0) {
428 memcpy(argv
+ argc
, con
->leftovers
, sizeof(*argv
) * con
->numLeftovers
);
429 argc
+= con
->numLeftovers
;
436 int rc
= setresgid(getgid(), getgid(),-1);
437 if (rc
) return POPT_ERROR_ERRNO
;
438 rc
= setresuid(getuid(), getuid(),-1);
439 if (rc
) return POPT_ERROR_ERRNO
;
442 * XXX " ... on BSD systems setuid() should be preferred over setreuid()"
443 * XXX sez' Timur Bakeyev <mc@bat.ru>
444 * XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
446 #if defined(HAVE_SETUID)
447 int rc
= setgid(getgid());
448 if (rc
) return POPT_ERROR_ERRNO
;
449 rc
= setuid(getuid());
450 if (rc
) return POPT_ERROR_ERRNO
;
451 #elif defined (HAVE_SETREUID)
452 int rc
= setregid(getgid(), getgid());
453 if (rc
) return POPT_ERROR_ERRNO
;
454 rc
= setreuid(getuid(), getuid());
455 if (rc
) return POPT_ERROR_ERRNO
;
457 ; /* Can't drop privileges */
463 return POPT_ERROR_NOARG
;
468 fprintf(stderr
, "==> execvp(%s) argv[%d]:", argv
[0], argc
);
469 for (avp
= argv
; *avp
; avp
++)
470 fprintf(stderr
, " '%s'", *avp
);
471 fprintf(stderr
, "\n");
475 execvp(argv
[0], (char *const *)argv
);
477 return POPT_ERROR_ERRNO
;
479 /*@=bounds =boundswrite @*/
482 /*@observer@*/ /*@null@*/ static const struct poptOption
*
483 findOption(const struct poptOption
* opt
, /*@null@*/ const char * longName
,
485 /*@null@*/ /*@out@*/ poptCallbackType
* callback
,
486 /*@null@*/ /*@out@*/ const void ** callbackData
,
488 /*@modifies *callback, *callbackData */
490 const struct poptOption
* cb
= NULL
;
492 /* This happens when a single - is given */
493 if (singleDash
&& !shortName
&& (longName
&& *longName
== '\0'))
496 for (; opt
->longName
|| opt
->shortName
|| opt
->arg
; opt
++) {
498 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_INCLUDE_TABLE
) {
499 const struct poptOption
* opt2
;
500 void * arg
= opt
->arg
;
503 /* XXX sick hack to preserve pretense of ABI. */
504 if (arg
== poptHelpOptions
) arg
= poptHelpOptionsI18N
;
506 /* Recurse on included sub-tables. */
507 if (arg
== NULL
) continue; /* XXX program error */
508 opt2
= findOption(arg
, longName
, shortName
, callback
,
509 callbackData
, singleDash
);
510 if (opt2
== NULL
) continue;
511 /* Sub-table data will be inheirited if no data yet. */
512 if (!(callback
&& *callback
)) return opt2
;
513 if (!(callbackData
&& *callbackData
== NULL
)) return opt2
;
514 /*@-observertrans -dependenttrans @*/
515 *callbackData
= opt
->descrip
;
516 /*@=observertrans =dependenttrans @*/
518 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_CALLBACK
) {
520 } else if (longName
&& opt
->longName
&&
521 (!singleDash
|| (opt
->argInfo
& POPT_ARGFLAG_ONEDASH
)) &&
522 /*@-nullpass@*/ /* LCL: opt->longName != NULL */
523 !strcmp(longName
, opt
->longName
))
527 } else if (shortName
&& shortName
== opt
->shortName
) {
532 if (!opt
->longName
&& !opt
->shortName
)
534 /*@-modobserver -mods @*/
535 if (callback
) *callback
= NULL
;
536 if (callbackData
) *callbackData
= NULL
;
540 *callback
= (poptCallbackType
)cb
->arg
;
542 if (!(cb
->argInfo
& POPT_CBFLAG_INC_DATA
)) {
544 /*@-observertrans@*/ /* FIX: typedef double indirection. */
545 *callbackData
= cb
->descrip
;
549 /*@=modobserver =mods @*/
555 static const char * findNextArg(/*@special@*/ poptContext con
,
556 unsigned argx
, int delete_arg
)
557 /*@uses con->optionStack, con->os,
558 con->os->next, con->os->argb, con->os->argc, con->os->argv @*/
561 struct optionStackEntry
* os
= con
->os
;
567 while (os
->next
== os
->argc
&& os
> con
->optionStack
) os
--;
568 if (os
->next
== os
->argc
&& os
== con
->optionStack
) break;
569 if (os
->argv
!= NULL
)
570 for (i
= os
->next
; i
< os
->argc
; i
++) {
572 if (os
->argb
&& PBM_ISSET(i
, os
->argb
))
573 /*@innercontinue@*/ continue;
574 if (*os
->argv
[i
] == '-')
575 /*@innercontinue@*/ continue;
577 /*@innercontinue@*/ continue;
580 if (os
->argb
== NULL
) os
->argb
= PBM_ALLOC(os
->argc
);
581 if (os
->argb
!= NULL
) /* XXX can't happen */
582 PBM_SET(i
, os
->argb
);
584 /*@innerbreak@*/ break;
587 if (os
> con
->optionStack
) os
--;
588 } while (arg
== NULL
);
593 static /*@only@*/ /*@null@*/ const char *
594 expandNextArg(/*@special@*/ poptContext con
, const char * s
)
595 /*@uses con->optionStack, con->os,
596 con->os->next, con->os->argb, con->os->argc, con->os->argv @*/
599 const char * a
= NULL
;
602 size_t tn
= strlen(s
) + 1;
605 te
= t
= malloc(tn
);;
606 if (t
== NULL
) return NULL
; /* XXX can't happen */
607 while ((c
= *s
++) != '\0') {
609 #if 0 /* XXX can't do this */
610 case '\\': /* escape */
612 /*@switchbreak@*/ break;
615 if (!(s
[0] == '#' && s
[1] == ':' && s
[2] == '+'))
616 /*@switchbreak@*/ break;
617 /* XXX Make sure that findNextArg deletes only next arg. */
619 if ((a
= findNextArg(con
, 1, 1)) == NULL
)
620 /*@switchbreak@*/ break;
629 strncpy(te
, a
, alen
); te
+= alen
;
631 /*@notreached@*/ /*@switchbreak@*/ break;
633 /*@switchbreak@*/ break;
638 t
= realloc(t
, strlen(t
) + 1); /* XXX memory leak, hard to plug */
643 static void poptStripArg(/*@special@*/ poptContext con
, int which
)
644 /*@uses con->arg_strip, con->optionStack @*/
645 /*@defines con->arg_strip @*/
649 if (con
->arg_strip
== NULL
)
650 con
->arg_strip
= PBM_ALLOC(con
->optionStack
[0].argc
);
651 if (con
->arg_strip
!= NULL
) /* XXX can't happen */
652 PBM_SET(which
, con
->arg_strip
);
654 /*@-compdef@*/ /* LCL: con->arg_strip udefined? */
659 int poptSaveLong(long * arg
, int argInfo
, long aLong
)
661 /* XXX Check alignment, may fail on funky platforms. */
662 if (arg
== NULL
|| (((unsigned long)arg
) & (sizeof(*arg
)-1)))
663 return POPT_ERROR_NULLARG
;
665 if (argInfo
& POPT_ARGFLAG_NOT
)
667 switch (argInfo
& POPT_ARGFLAG_LOGICALOPS
) {
671 case POPT_ARGFLAG_OR
:
674 case POPT_ARGFLAG_AND
:
677 case POPT_ARGFLAG_XOR
:
681 return POPT_ERROR_BADOPERATION
;
682 /*@notreached@*/ break;
687 int poptSaveInt(/*@null@*/ int * arg
, int argInfo
, long aLong
)
689 /* XXX Check alignment, may fail on funky platforms. */
690 if (arg
== NULL
|| (((unsigned long)arg
) & (sizeof(*arg
)-1)))
691 return POPT_ERROR_NULLARG
;
693 if (argInfo
& POPT_ARGFLAG_NOT
)
695 switch (argInfo
& POPT_ARGFLAG_LOGICALOPS
) {
699 case POPT_ARGFLAG_OR
:
702 case POPT_ARGFLAG_AND
:
705 case POPT_ARGFLAG_XOR
:
709 return POPT_ERROR_BADOPERATION
;
710 /*@notreached@*/ break;
716 /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
717 int poptGetNextOpt(poptContext con
)
719 const struct poptOption
* opt
= NULL
;
725 const char * origOptString
= NULL
;
726 poptCallbackType cb
= NULL
;
727 const void * cbData
= NULL
;
728 const char * longArg
= NULL
;
732 while (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
733 && con
->os
> con
->optionStack
) {
736 if (!con
->os
->nextCharArg
&& con
->os
->next
== con
->os
->argc
) {
738 invokeCallbacksPOST(con
, con
->options
);
740 if (con
->doExec
) return execCommand(con
);
744 /* Process next long option */
745 if (!con
->os
->nextCharArg
) {
746 char * localOptString
, * optString
;
750 if (con
->os
->argb
&& PBM_ISSET(con
->os
->next
, con
->os
->argb
)) {
755 thisopt
= con
->os
->next
;
756 if (con
->os
->argv
!= NULL
) /* XXX can't happen */
757 origOptString
= con
->os
->argv
[con
->os
->next
++];
759 if (origOptString
== NULL
) /* XXX can't happen */
760 return POPT_ERROR_BADOPT
;
762 if (con
->restLeftover
|| *origOptString
!= '-') {
763 if (con
->flags
& POPT_CONTEXT_POSIXMEHARDER
)
764 con
->restLeftover
= 1;
765 if (con
->flags
& POPT_CONTEXT_ARG_OPTS
) {
766 con
->os
->nextArg
= xstrdup(origOptString
);
769 if (con
->leftovers
!= NULL
) /* XXX can't happen */
770 con
->leftovers
[con
->numLeftovers
++] = origOptString
;
774 /* Make a copy we can hack at */
775 { size_t bufsize
= strlen(origOptString
) + 1;
776 localOptString
= optString
= alloca(bufsize
);
777 if (optString
== NULL
) /* XXX can't happen */
778 return POPT_ERROR_BADOPT
;
779 strlcpy(optString
, origOptString
, bufsize
);
782 if (optString
[0] == '\0')
783 return POPT_ERROR_BADOPT
;
785 if (optString
[1] == '-' && !optString
[2]) {
786 con
->restLeftover
= 1;
793 if (*optString
== '-')
794 singleDash
= 0, optString
++;
798 /* XXX aliases with arg substitution need "--alias=arg" */
799 if (handleAlias(con
, optString
, '\0', NULL
))
802 if (handleExec(con
, optString
, '\0'))
805 /* Check for "--long=arg" option. */
806 for (oe
= optString
; *oe
&& *oe
!= '='; oe
++)
810 /* XXX longArg is mapped back to persistent storage. */
811 longArg
= origOptString
+ (oe
- localOptString
);
814 opt
= findOption(con
->options
, optString
, '\0', &cb
, &cbData
,
816 if (!opt
&& !singleDash
)
817 return POPT_ERROR_BADOPT
;
821 con
->os
->nextCharArg
= origOptString
+ 1;
823 if (con
->os
== con
->optionStack
&&
824 opt
->argInfo
& POPT_ARGFLAG_STRIP
)
827 poptStripArg(con
, thisopt
);
833 /* Process next short option */
834 /*@-branchstate@*/ /* FIX: W2DO? */
835 if (con
->os
->nextCharArg
) {
836 origOptString
= con
->os
->nextCharArg
;
838 con
->os
->nextCharArg
= NULL
;
840 if (handleAlias(con
, NULL
, *origOptString
, origOptString
+ 1))
843 if (handleExec(con
, NULL
, *origOptString
)) {
844 /* Restore rest of short options for further processing */
846 if (*origOptString
!= '\0')
847 con
->os
->nextCharArg
= origOptString
;
851 opt
= findOption(con
->options
, NULL
, *origOptString
, &cb
,
854 return POPT_ERROR_BADOPT
;
858 if (*origOptString
!= '\0')
859 con
->os
->nextCharArg
= origOptString
;
863 if (opt
== NULL
) return POPT_ERROR_BADOPT
; /* XXX can't happen */
864 if (opt
->arg
&& (opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_NONE
) {
865 if (poptSaveInt((int *)opt
->arg
, opt
->argInfo
, 1L))
866 return POPT_ERROR_BADOPERATION
;
867 } else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_VAL
) {
869 if (poptSaveInt((int *)opt
->arg
, opt
->argInfo
, (long)opt
->val
))
870 return POPT_ERROR_BADOPERATION
;
872 } else if ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_NONE
) {
873 con
->os
->nextArg
= _free(con
->os
->nextArg
);
874 /*@-usedef@*/ /* FIX: W2DO? */
877 longArg
= expandNextArg(con
, longArg
);
878 con
->os
->nextArg
= longArg
;
879 } else if (con
->os
->nextCharArg
) {
880 longArg
= expandNextArg(con
, con
->os
->nextCharArg
);
881 con
->os
->nextArg
= longArg
;
882 con
->os
->nextCharArg
= NULL
;
884 while (con
->os
->next
== con
->os
->argc
&&
885 con
->os
> con
->optionStack
) {
888 if (con
->os
->next
== con
->os
->argc
) {
889 if (!(opt
->argInfo
& POPT_ARGFLAG_OPTIONAL
))
890 /*@-compdef@*/ /* FIX: con->os->argv not defined */
891 return POPT_ERROR_NOARG
;
893 con
->os
->nextArg
= NULL
;
897 * Make sure this isn't part of a short arg or the
898 * result of an alias expansion.
900 if (con
->os
== con
->optionStack
&&
901 (opt
->argInfo
& POPT_ARGFLAG_STRIP
) &&
903 poptStripArg(con
, con
->os
->next
);
906 if (con
->os
->argv
!= NULL
) { /* XXX can't happen */
907 /* XXX watchout: subtle side-effects live here. */
908 longArg
= con
->os
->argv
[con
->os
->next
++];
909 longArg
= expandNextArg(con
, longArg
);
910 con
->os
->nextArg
= longArg
;
917 switch (opt
->argInfo
& POPT_ARG_MASK
) {
918 case POPT_ARG_STRING
:
919 /* XXX memory leak, hard to plug */
920 *((const char **) opt
->arg
) = (con
->os
->nextArg
)
921 ? xstrdup(con
->os
->nextArg
) : NULL
;
922 /*@switchbreak@*/ break;
929 if (con
->os
->nextArg
) {
930 aLong
= strtol(con
->os
->nextArg
, &end
, 0);
931 if (!(end
&& *end
== '\0'))
932 return POPT_ERROR_BADNUMBER
;
935 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_LONG
) {
936 if (aLong
== LONG_MIN
|| aLong
== LONG_MAX
)
937 return POPT_ERROR_OVERFLOW
;
938 if (poptSaveLong((long *)opt
->arg
, opt
->argInfo
, aLong
))
939 return POPT_ERROR_BADOPERATION
;
941 if (aLong
> INT_MAX
|| aLong
< INT_MIN
)
942 return POPT_ERROR_OVERFLOW
;
943 if (poptSaveInt((int *)opt
->arg
, opt
->argInfo
, aLong
))
944 return POPT_ERROR_BADOPERATION
;
946 } /*@switchbreak@*/ break;
949 case POPT_ARG_DOUBLE
:
950 { double aDouble
= 0.0;
953 if (con
->os
->nextArg
) {
955 int saveerrno
= errno
;
957 aDouble
= strtod(con
->os
->nextArg
, &end
);
959 return POPT_ERROR_OVERFLOW
;
963 return POPT_ERROR_BADNUMBER
;
966 if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_DOUBLE
) {
967 *((double *) opt
->arg
) = aDouble
;
969 #define MY_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
970 if ((MY_ABS(aDouble
) - FLT_MAX
) > DBL_EPSILON
)
971 return POPT_ERROR_OVERFLOW
;
972 if ((FLT_MIN
- MY_ABS(aDouble
)) > DBL_EPSILON
)
973 return POPT_ERROR_OVERFLOW
;
974 *((float *) opt
->arg
) = aDouble
;
976 } /*@switchbreak@*/ break;
979 POPT_("option type (%d) not implemented in popt\n"),
980 (opt
->argInfo
& POPT_ARG_MASK
));
982 /*@notreached@*/ /*@switchbreak@*/ break;
989 invokeCallbacksOPTION(con
, con
->options
, opt
, cbData
, shorty
);
991 } else if (opt
->val
&& ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_VAL
))
994 if ((con
->finalArgvCount
+ 2) >= (con
->finalArgvAlloced
)) {
995 con
->finalArgvAlloced
+= 10;
996 con
->finalArgv
= realloc(con
->finalArgv
,
997 sizeof(*con
->finalArgv
) * con
->finalArgvAlloced
);
1000 if (con
->finalArgv
!= NULL
)
1001 { ssize_t bufsize
= (opt
->longName
? strlen(opt
->longName
) : 0) + 3;
1002 char *s
= malloc(bufsize
);
1003 if (s
!= NULL
) { /* XXX can't happen */
1005 snprintf(s
, bufsize
, "%s%s",
1006 ((opt
->argInfo
& POPT_ARGFLAG_ONEDASH
) ? "-" : "--"),
1009 snprintf(s
, bufsize
, "-%c", opt
->shortName
);
1010 con
->finalArgv
[con
->finalArgvCount
++] = s
;
1012 con
->finalArgv
[con
->finalArgvCount
++] = NULL
;
1015 if (opt
->arg
&& (opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_NONE
)
1016 /*@-ifempty@*/ ; /*@=ifempty@*/
1017 else if ((opt
->argInfo
& POPT_ARG_MASK
) == POPT_ARG_VAL
)
1018 /*@-ifempty@*/ ; /*@=ifempty@*/
1019 else if ((opt
->argInfo
& POPT_ARG_MASK
) != POPT_ARG_NONE
) {
1020 if (con
->finalArgv
!= NULL
&& con
->os
->nextArg
)
1021 con
->finalArgv
[con
->finalArgvCount
++] =
1022 /*@-nullpass@*/ /* LCL: con->os->nextArg != NULL */
1023 xstrdup(con
->os
->nextArg
);
1028 return (opt
? opt
->val
: -1); /* XXX can't happen */
1032 const char * poptGetOptArg(poptContext con
)
1034 const char * ret
= NULL
;
1037 ret
= con
->os
->nextArg
;
1038 con
->os
->nextArg
= NULL
;
1044 const char * poptGetArg(poptContext con
)
1046 const char * ret
= NULL
;
1047 if (con
&& con
->leftovers
!= NULL
&& con
->nextLeftover
< con
->numLeftovers
)
1048 ret
= con
->leftovers
[con
->nextLeftover
++];
1052 const char * poptPeekArg(poptContext con
)
1054 const char * ret
= NULL
;
1055 if (con
&& con
->leftovers
!= NULL
&& con
->nextLeftover
< con
->numLeftovers
)
1056 ret
= con
->leftovers
[con
->nextLeftover
];
1061 const char ** poptGetArgs(poptContext con
)
1064 con
->leftovers
== NULL
|| con
->numLeftovers
== con
->nextLeftover
)
1067 /* some apps like [like RPM ;-) ] need this NULL terminated */
1068 con
->leftovers
[con
->numLeftovers
] = NULL
;
1070 /*@-nullret -nullstate @*/ /* FIX: typedef double indirection. */
1071 return (con
->leftovers
+ con
->nextLeftover
);
1072 /*@=nullret =nullstate @*/
1076 poptContext
poptFreeContext(poptContext con
)
1081 if (con
== NULL
) return con
;
1082 poptResetContext(con
);
1083 con
->os
->argb
= _free(con
->os
->argb
);
1085 if (con
->aliases
!= NULL
)
1086 for (i
= 0; i
< con
->numAliases
; i
++) {
1087 item
= con
->aliases
+ i
;
1088 /*@-modobserver -observertrans -dependenttrans@*/
1089 item
->option
.longName
= _free(item
->option
.longName
);
1090 item
->option
.descrip
= _free(item
->option
.descrip
);
1091 item
->option
.argDescrip
= _free(item
->option
.argDescrip
);
1092 /*@=modobserver =observertrans =dependenttrans@*/
1093 item
->argv
= _free(item
->argv
);
1095 con
->aliases
= _free(con
->aliases
);
1097 if (con
->execs
!= NULL
)
1098 for (i
= 0; i
< con
->numExecs
; i
++) {
1099 item
= con
->execs
+ i
;
1100 /*@-modobserver -observertrans -dependenttrans@*/
1101 item
->option
.longName
= _free(item
->option
.longName
);
1102 item
->option
.descrip
= _free(item
->option
.descrip
);
1103 item
->option
.argDescrip
= _free(item
->option
.argDescrip
);
1104 /*@=modobserver =observertrans =dependenttrans@*/
1105 item
->argv
= _free(item
->argv
);
1107 con
->execs
= _free(con
->execs
);
1109 con
->leftovers
= _free(con
->leftovers
);
1110 con
->finalArgv
= _free(con
->finalArgv
);
1111 con
->appName
= _free(con
->appName
);
1112 con
->otherHelp
= _free(con
->otherHelp
);
1113 con
->execPath
= _free(con
->execPath
);
1114 con
->arg_strip
= PBM_FREE(con
->arg_strip
);
1120 int poptAddAlias(poptContext con
, struct poptAlias alias
,
1121 /*@unused@*/ UNUSED(int flags
))
1123 poptItem item
= (poptItem
) alloca(sizeof(*item
));
1124 memset(item
, 0, sizeof(*item
));
1125 item
->option
.longName
= alias
.longName
;
1126 item
->option
.shortName
= alias
.shortName
;
1127 item
->option
.argInfo
= POPT_ARGFLAG_DOC_HIDDEN
;
1128 item
->option
.arg
= 0;
1129 item
->option
.val
= 0;
1130 item
->option
.descrip
= NULL
;
1131 item
->option
.argDescrip
= NULL
;
1132 item
->argc
= alias
.argc
;
1133 item
->argv
= alias
.argv
;
1134 return poptAddItem(con
, item
, 0);
1138 /*@-mustmod@*/ /* LCL: con not modified? */
1139 int poptAddItem(poptContext con
, poptItem newItem
, int flags
)
1141 poptItem
* items
, item
;
1146 items
= &con
->execs
;
1147 nitems
= &con
->numExecs
;
1150 items
= &con
->aliases
;
1151 nitems
= &con
->numAliases
;
1155 /*@notreached@*/ break;
1158 *items
= realloc((*items
), ((*nitems
) + 1) * sizeof(**items
));
1159 if ((*items
) == NULL
)
1162 item
= (*items
) + (*nitems
);
1164 item
->option
.longName
=
1165 (newItem
->option
.longName
? xstrdup(newItem
->option
.longName
) : NULL
);
1166 item
->option
.shortName
= newItem
->option
.shortName
;
1167 item
->option
.argInfo
= newItem
->option
.argInfo
;
1168 item
->option
.arg
= newItem
->option
.arg
;
1169 item
->option
.val
= newItem
->option
.val
;
1170 item
->option
.descrip
=
1171 (newItem
->option
.descrip
? xstrdup(newItem
->option
.descrip
) : NULL
);
1172 item
->option
.argDescrip
=
1173 (newItem
->option
.argDescrip
? xstrdup(newItem
->option
.argDescrip
) : NULL
);
1174 item
->argc
= newItem
->argc
;
1175 item
->argv
= newItem
->argv
;
1184 const char * poptBadOption(poptContext con
, int flags
)
1186 struct optionStackEntry
* os
= NULL
;
1189 os
= (flags
& POPT_BADOPTION_NOALIAS
) ? con
->optionStack
: con
->os
;
1191 /*@-nullderef@*/ /* LCL: os->argv != NULL */
1192 return (os
&& os
->argv
? os
->argv
[os
->next
- 1] : NULL
);
1196 const char * poptStrerror(const int error
)
1199 case POPT_ERROR_NOARG
:
1200 return POPT_("missing argument");
1201 case POPT_ERROR_BADOPT
:
1202 return POPT_("unknown option");
1203 case POPT_ERROR_BADOPERATION
:
1204 return POPT_("mutually exclusive logical operations requested");
1205 case POPT_ERROR_NULLARG
:
1206 return POPT_("opt->arg should not be NULL");
1207 case POPT_ERROR_OPTSTOODEEP
:
1208 return POPT_("aliases nested too deeply");
1209 case POPT_ERROR_BADQUOTE
:
1210 return POPT_("error in parameter quoting");
1211 case POPT_ERROR_BADNUMBER
:
1212 return POPT_("invalid numeric value");
1213 case POPT_ERROR_OVERFLOW
:
1214 return POPT_("number too large or too small");
1215 case POPT_ERROR_MALLOC
:
1216 return POPT_("memory allocation failed");
1217 case POPT_ERROR_ERRNO
:
1218 return strerror(errno
);
1220 return POPT_("unknown error");
1224 int poptStuffArgs(poptContext con
, const char ** argv
)
1229 if ((con
->os
- con
->optionStack
) == POPT_OPTION_DEPTH
)
1230 return POPT_ERROR_OPTSTOODEEP
;
1232 for (argc
= 0; argv
[argc
]; argc
++)
1237 con
->os
->nextArg
= NULL
;
1238 con
->os
->nextCharArg
= NULL
;
1239 con
->os
->currAlias
= NULL
;
1240 rc
= poptDupArgv(argc
, argv
, &con
->os
->argc
, &con
->os
->argv
);
1241 con
->os
->argb
= NULL
;
1242 con
->os
->stuffed
= 1;
1247 const char * poptGetInvocationName(poptContext con
)
1249 return (con
->os
->argv
? con
->os
->argv
[0] : "");
1253 int poptStrippedArgv(poptContext con
, int argc
, char ** argv
)
1261 for (i
= 1; i
< argc
; i
++) {
1262 if (PBM_ISSET(i
, con
->arg_strip
))
1266 for (i
= 1; i
< argc
; i
++) {
1267 if (con
->arg_strip
&& PBM_ISSET(i
, con
->arg_strip
))
1269 argv
[j
] = (j
< numargs
) ? argv
[i
] : NULL
;