]>
Commit | Line | Data |
---|---|---|
cc248aae | 1 | /** \ingroup popt |
4c8683c8 | 2 | * @file |
cc248aae WD |
3 | */ |
4 | ||
bc93ee84 | 5 | /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING |
b348deae | 6 | file accompanying popt source distributions, available from |
cc248aae WD |
7 | ftp://ftp.rpm.org/pub/rpm/dist */ |
8 | ||
9 | #undef MYDEBUG | |
62402cb1 | 10 | |
b348deae | 11 | #include "system.h" |
cc248aae | 12 | |
cc248aae | 13 | #include <float.h> |
cc248aae | 14 | #include <math.h> |
4c8683c8 AT |
15 | #include <unistd.h> |
16 | #include <limits.h> | |
17 | #include <errno.h> | |
cc248aae | 18 | |
62402cb1 MP |
19 | #include "poptint.h" |
20 | ||
4c8683c8 AT |
21 | #ifdef HAVE_STDALIGN_H |
22 | #include <stdalign.h> | |
23 | #define ALIGNOF(x) alignof(x) | |
24 | #elif defined __GNUC__ | |
25 | #define ALIGNOF(x) __alignof__(x) | |
26 | #else | |
27 | #define ALIGNOF(x) sizeof(x) | |
684576ff WD |
28 | #endif |
29 | ||
bc93ee84 | 30 | #ifdef MYDEBUG |
bc93ee84 WD |
31 | int _popt_debug = 0; |
32 | #endif | |
33 | ||
4c8683c8 AT |
34 | unsigned int _poptArgMask = POPT_ARG_MASK; |
35 | unsigned int _poptGroupMask = POPT_GROUP_MASK; | |
36 | ||
37 | #if !defined(HAVE_STRERROR) | |
bc93ee84 WD |
38 | static char * strerror(int errno) |
39 | { | |
62402cb1 MP |
40 | extern int sys_nerr; |
41 | extern char * sys_errlist[]; | |
42 | ||
43 | if ((0 <= errno) && (errno < sys_nerr)) | |
44 | return sys_errlist[errno]; | |
45 | else | |
46 | return POPT_("unknown errno"); | |
47 | } | |
48 | #endif | |
49 | ||
cc248aae | 50 | #ifdef MYDEBUG |
bc93ee84 | 51 | static void prtcon(const char *msg, poptContext con) |
cc248aae WD |
52 | { |
53 | if (msg) fprintf(stderr, "%s", msg); | |
54 | fprintf(stderr, "\tcon %p os %p nextCharArg \"%s\" nextArg \"%s\" argv[%d] \"%s\"\n", | |
55 | con, con->os, | |
56 | (con->os->nextCharArg ? con->os->nextCharArg : ""), | |
57 | (con->os->nextArg ? con->os->nextArg : ""), | |
58 | con->os->next, | |
59 | (con->os->argv && con->os->argv[con->os->next] | |
60 | ? con->os->argv[con->os->next] : "")); | |
61 | } | |
62 | #endif | |
63 | ||
64 | void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) | |
65 | { | |
66 | con->execPath = _free(con->execPath); | |
b348deae | 67 | con->execPath = xstrdup(path); |
62402cb1 | 68 | con->execAbsolute = allowAbsolute; |
cc248aae | 69 | return; |
62402cb1 MP |
70 | } |
71 | ||
cc248aae | 72 | static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt) |
cc248aae WD |
73 | { |
74 | if (opt != NULL) | |
75 | for (; opt->longName || opt->shortName || opt->arg; opt++) { | |
4c8683c8 AT |
76 | poptArg arg = { .ptr = opt->arg }; |
77 | if (arg.ptr) | |
78 | switch (poptArgType(opt)) { | |
79 | case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */ | |
80 | poptSubstituteHelpI18N(arg.opt); /* XXX side effects */ | |
81 | invokeCallbacksPRE(con, arg.opt); | |
82 | break; | |
83 | case POPT_ARG_CALLBACK: /* Perform callback. */ | |
84 | if (!CBF_ISSET(opt, PRE)) | |
85 | break; | |
86 | arg.cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip); | |
87 | break; | |
cc248aae WD |
88 | } |
89 | } | |
90 | } | |
b348deae | 91 | |
cc248aae | 92 | static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt) |
cc248aae WD |
93 | { |
94 | if (opt != NULL) | |
95 | for (; opt->longName || opt->shortName || opt->arg; opt++) { | |
4c8683c8 AT |
96 | poptArg arg = { .ptr = opt->arg }; |
97 | if (arg.ptr) | |
98 | switch (poptArgType(opt)) { | |
99 | case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */ | |
100 | poptSubstituteHelpI18N(arg.opt); /* XXX side effects */ | |
101 | invokeCallbacksPOST(con, arg.opt); | |
102 | break; | |
103 | case POPT_ARG_CALLBACK: /* Perform callback. */ | |
104 | if (!CBF_ISSET(opt, POST)) | |
105 | break; | |
106 | arg.cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip); | |
107 | break; | |
cc248aae WD |
108 | } |
109 | } | |
110 | } | |
111 | ||
112 | static void invokeCallbacksOPTION(poptContext con, | |
4c8683c8 AT |
113 | const struct poptOption * opt, |
114 | const struct poptOption * myOpt, | |
115 | const void * myData, int shorty) | |
cc248aae WD |
116 | { |
117 | const struct poptOption * cbopt = NULL; | |
4c8683c8 | 118 | poptArg cbarg = { .ptr = NULL }; |
cc248aae WD |
119 | |
120 | if (opt != NULL) | |
121 | for (; opt->longName || opt->shortName || opt->arg; opt++) { | |
4c8683c8 AT |
122 | poptArg arg = { .ptr = opt->arg }; |
123 | switch (poptArgType(opt)) { | |
124 | case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */ | |
125 | poptSubstituteHelpI18N(arg.opt); /* XXX side effects */ | |
126 | if (opt->arg != NULL) | |
cc248aae | 127 | invokeCallbacksOPTION(con, opt->arg, myOpt, myData, shorty); |
4c8683c8 AT |
128 | break; |
129 | case POPT_ARG_CALLBACK: /* Save callback info. */ | |
130 | if (CBF_ISSET(opt, SKIPOPTION)) | |
131 | break; | |
cc248aae | 132 | cbopt = opt; |
4c8683c8 AT |
133 | cbarg.ptr = opt->arg; |
134 | break; | |
135 | default: /* Perform callback on matching option. */ | |
136 | if (cbopt == NULL || cbarg.cb == NULL) | |
137 | break; | |
138 | if ((myOpt->shortName && opt->shortName && shorty && | |
139 | myOpt->shortName == opt->shortName) | |
140 | || (myOpt->longName != NULL && opt->longName != NULL && | |
cc248aae | 141 | !strcmp(myOpt->longName, opt->longName))) |
4c8683c8 AT |
142 | { const void *cbData = (cbopt->descrip ? cbopt->descrip : myData); |
143 | cbarg.cb(con, POPT_CALLBACK_REASON_OPTION, | |
144 | myOpt, con->os->nextArg, cbData); | |
145 | /* Terminate (unless explcitly continuing). */ | |
146 | if (!CBF_ISSET(cbopt, CONTINUE)) | |
147 | return; | |
cc248aae | 148 | } |
4c8683c8 | 149 | break; |
62402cb1 | 150 | } |
62402cb1 MP |
151 | } |
152 | } | |
153 | ||
b348deae | 154 | poptContext poptGetContext(const char * name, int argc, const char ** argv, |
4c8683c8 | 155 | const struct poptOption * options, unsigned int flags) |
cc248aae | 156 | { |
62402cb1 MP |
157 | poptContext con = malloc(sizeof(*con)); |
158 | ||
cc248aae | 159 | if (con == NULL) return NULL; /* XXX can't happen */ |
62402cb1 MP |
160 | memset(con, 0, sizeof(*con)); |
161 | ||
162 | con->os = con->optionStack; | |
163 | con->os->argc = argc; | |
164 | con->os->argv = argv; | |
b348deae | 165 | con->os->argb = NULL; |
62402cb1 MP |
166 | |
167 | if (!(flags & POPT_CONTEXT_KEEP_FIRST)) | |
4c8683c8 | 168 | con->os->next = 1; /* skip argv[0] */ |
62402cb1 | 169 | |
4c8683c8 AT |
170 | con->leftovers = calloc( (size_t)(argc + 1), sizeof(*con->leftovers) ); |
171 | con->allocLeftovers = argc + 1; | |
62402cb1 | 172 | con->options = options; |
b348deae MP |
173 | con->aliases = NULL; |
174 | con->numAliases = 0; | |
62402cb1 | 175 | con->flags = flags; |
b348deae MP |
176 | con->execs = NULL; |
177 | con->numExecs = 0; | |
4c8683c8 | 178 | con->execFail = NULL; |
b348deae | 179 | con->finalArgvAlloced = argc * 2; |
4c8683c8 | 180 | con->finalArgv = calloc( (size_t)con->finalArgvAlloced, sizeof(*con->finalArgv) ); |
62402cb1 | 181 | con->execAbsolute = 1; |
b348deae | 182 | con->arg_strip = NULL; |
62402cb1 MP |
183 | |
184 | if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER")) | |
185 | con->flags |= POPT_CONTEXT_POSIXMEHARDER; | |
b348deae | 186 | |
4c8683c8 AT |
187 | if (name) |
188 | con->appName = xstrdup(name); | |
62402cb1 | 189 | |
cc248aae | 190 | invokeCallbacksPRE(con, con->options); |
62402cb1 MP |
191 | |
192 | return con; | |
193 | } | |
194 | ||
4c8683c8 | 195 | static void cleanOSE(struct optionStackEntry *os) |
b348deae | 196 | { |
cc248aae WD |
197 | os->nextArg = _free(os->nextArg); |
198 | os->argv = _free(os->argv); | |
199 | os->argb = PBM_FREE(os->argb); | |
b348deae MP |
200 | } |
201 | ||
cc248aae WD |
202 | void poptResetContext(poptContext con) |
203 | { | |
b348deae MP |
204 | int i; |
205 | ||
cc248aae | 206 | if (con == NULL) return; |
b348deae MP |
207 | while (con->os > con->optionStack) { |
208 | cleanOSE(con->os--); | |
209 | } | |
cc248aae | 210 | con->os->argb = PBM_FREE(con->os->argb); |
62402cb1 MP |
211 | con->os->currAlias = NULL; |
212 | con->os->nextCharArg = NULL; | |
4c8683c8 AT |
213 | con->os->nextArg = _free(con->os->nextArg); |
214 | if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) | |
215 | con->os->next = 1; /* skip argv[0] */ | |
216 | else | |
217 | con->os->next = 0; | |
62402cb1 | 218 | |
4c8683c8 AT |
219 | for (i = 0; i < con->numLeftovers; i++) { |
220 | con->leftovers[i] = _free(con->leftovers[i]); | |
221 | } | |
62402cb1 MP |
222 | con->numLeftovers = 0; |
223 | con->nextLeftover = 0; | |
224 | con->restLeftover = 0; | |
225 | con->doExec = NULL; | |
4c8683c8 | 226 | con->execFail = _free(con->execFail); |
b348deae | 227 | |
cc248aae | 228 | if (con->finalArgv != NULL) |
bc93ee84 | 229 | for (i = 0; i < con->finalArgvCount; i++) { |
cc248aae | 230 | con->finalArgv[i] = _free(con->finalArgv[i]); |
bc93ee84 | 231 | } |
b348deae | 232 | |
62402cb1 | 233 | con->finalArgvCount = 0; |
cc248aae | 234 | con->arg_strip = PBM_FREE(con->arg_strip); |
cc248aae | 235 | return; |
62402cb1 MP |
236 | } |
237 | ||
cc248aae | 238 | /* Only one of longName, shortName should be set, not both. */ |
4c8683c8 AT |
239 | static int handleExec(poptContext con, |
240 | const char * longName, char shortName) | |
cc248aae WD |
241 | { |
242 | poptItem item; | |
62402cb1 MP |
243 | int i; |
244 | ||
cc248aae WD |
245 | if (con->execs == NULL || con->numExecs <= 0) /* XXX can't happen */ |
246 | return 0; | |
62402cb1 | 247 | |
cc248aae WD |
248 | for (i = con->numExecs - 1; i >= 0; i--) { |
249 | item = con->execs + i; | |
250 | if (longName && !(item->option.longName && | |
251 | !strcmp(longName, item->option.longName))) | |
252 | continue; | |
253 | else if (shortName != item->option.shortName) | |
254 | continue; | |
255 | break; | |
256 | } | |
62402cb1 MP |
257 | if (i < 0) return 0; |
258 | ||
cc248aae | 259 | |
62402cb1 MP |
260 | if (con->flags & POPT_CONTEXT_NO_EXEC) |
261 | return 1; | |
262 | ||
b348deae | 263 | if (con->doExec == NULL) { |
62402cb1 MP |
264 | con->doExec = con->execs + i; |
265 | return 1; | |
266 | } | |
267 | ||
268 | /* We already have an exec to do; remember this option for next | |
269 | time 'round */ | |
270 | if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) { | |
271 | con->finalArgvAlloced += 10; | |
272 | con->finalArgv = realloc(con->finalArgv, | |
273 | sizeof(*con->finalArgv) * con->finalArgvAlloced); | |
274 | } | |
275 | ||
276 | i = con->finalArgvCount++; | |
cc248aae | 277 | if (con->finalArgv != NULL) /* XXX can't happen */ |
4c8683c8 | 278 | { char *s = malloc((longName ? strlen(longName) : 0) + sizeof("--")); |
cc248aae | 279 | if (s != NULL) { /* XXX can't happen */ |
4c8683c8 AT |
280 | con->finalArgv[i] = s; |
281 | *s++ = '-'; | |
cc248aae | 282 | if (longName) |
4c8683c8 | 283 | s = stpcpy( stpcpy(s, "-"), longName); |
cc248aae | 284 | else |
4c8683c8 AT |
285 | *s++ = shortName; |
286 | *s = '\0'; | |
cc248aae WD |
287 | } else |
288 | con->finalArgv[i] = NULL; | |
b348deae | 289 | } |
62402cb1 MP |
290 | |
291 | return 1; | |
292 | } | |
4c8683c8 AT |
293 | |
294 | /** | |
295 | * Compare long option for equality, adjusting for POPT_ARGFLAG_TOGGLE. | |
296 | * @param opt option | |
297 | * @param longName arg option | |
298 | * @param longNameLen arg option length | |
299 | * @return does long option match? | |
300 | */ | |
301 | static int | |
302 | longOptionStrcmp(const struct poptOption * opt, | |
303 | const char * longName, size_t longNameLen) | |
304 | { | |
305 | const char * optLongName = opt->longName; | |
306 | int rc; | |
307 | ||
308 | if (optLongName == NULL || longName == NULL) /* XXX can't heppen */ | |
309 | return 0; | |
310 | ||
311 | if (F_ISSET(opt, TOGGLE)) { | |
312 | if (optLongName[0] == 'n' && optLongName[1] == 'o') { | |
313 | optLongName += sizeof("no") - 1; | |
314 | if (optLongName[0] == '-') | |
315 | optLongName++; | |
316 | } | |
317 | if (longName[0] == 'n' && longName[1] == 'o') { | |
318 | longName += sizeof("no") - 1; | |
319 | longNameLen -= sizeof("no") - 1; | |
320 | if (longName[0] == '-') { | |
321 | longName++; | |
322 | longNameLen--; | |
323 | } | |
324 | } | |
325 | } | |
326 | rc = (int)(strlen(optLongName) == longNameLen); | |
327 | if (rc) | |
328 | rc = (int)(strncmp(optLongName, longName, longNameLen) == 0); | |
329 | return rc; | |
330 | } | |
62402cb1 MP |
331 | |
332 | /* Only one of longName, shortName may be set at a time */ | |
4c8683c8 AT |
333 | static int handleAlias(poptContext con, |
334 | const char * longName, size_t longNameLen, | |
335 | char shortName, | |
336 | const char * nextArg) | |
cc248aae WD |
337 | { |
338 | poptItem item = con->os->currAlias; | |
339 | int rc; | |
62402cb1 MP |
340 | int i; |
341 | ||
cc248aae | 342 | if (item) { |
4c8683c8 AT |
343 | if (longName && item->option.longName != NULL |
344 | && longOptionStrcmp(&item->option, longName, longNameLen)) | |
cc248aae | 345 | return 0; |
4c8683c8 | 346 | else |
cc248aae WD |
347 | if (shortName && shortName == item->option.shortName) |
348 | return 0; | |
349 | } | |
350 | ||
351 | if (con->aliases == NULL || con->numAliases <= 0) /* XXX can't happen */ | |
62402cb1 MP |
352 | return 0; |
353 | ||
cc248aae WD |
354 | for (i = con->numAliases - 1; i >= 0; i--) { |
355 | item = con->aliases + i; | |
4c8683c8 AT |
356 | if (longName) { |
357 | if (item->option.longName == NULL) | |
358 | continue; | |
359 | if (!longOptionStrcmp(&item->option, longName, longNameLen)) | |
360 | continue; | |
361 | } else if (shortName != item->option.shortName) | |
cc248aae WD |
362 | continue; |
363 | break; | |
62402cb1 | 364 | } |
62402cb1 MP |
365 | if (i < 0) return 0; |
366 | ||
b348deae | 367 | if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH) |
62402cb1 MP |
368 | return POPT_ERROR_OPTSTOODEEP; |
369 | ||
4c8683c8 AT |
370 | if (longName == NULL && nextArg != NULL && *nextArg != '\0') |
371 | con->os->nextCharArg = nextArg; | |
62402cb1 MP |
372 | |
373 | con->os++; | |
374 | con->os->next = 0; | |
375 | con->os->stuffed = 0; | |
b348deae MP |
376 | con->os->nextArg = NULL; |
377 | con->os->nextCharArg = NULL; | |
62402cb1 | 378 | con->os->currAlias = con->aliases + i; |
4c8683c8 AT |
379 | { const char ** av; |
380 | int ac = con->os->currAlias->argc; | |
381 | /* Append --foo=bar arg to alias argv array (if present). */ | |
382 | if (longName && nextArg != NULL && *nextArg != '\0') { | |
383 | av = malloc((ac + 1 + 1) * sizeof(*av)); | |
384 | if (av != NULL) { /* XXX won't happen. */ | |
385 | for (i = 0; i < ac; i++) { | |
386 | av[i] = con->os->currAlias->argv[i]; | |
387 | } | |
388 | av[ac++] = nextArg; | |
389 | av[ac] = NULL; | |
390 | } else /* XXX revert to old popt behavior if malloc fails. */ | |
391 | av = con->os->currAlias->argv; | |
392 | } else | |
393 | av = con->os->currAlias->argv; | |
394 | rc = poptDupArgv(ac, av, &con->os->argc, &con->os->argv); | |
395 | if (av != NULL && av != con->os->currAlias->argv) | |
396 | free(av); | |
397 | } | |
b348deae | 398 | con->os->argb = NULL; |
62402cb1 | 399 | |
cc248aae | 400 | return (rc ? rc : 1); |
62402cb1 MP |
401 | } |
402 | ||
4c8683c8 AT |
403 | /** |
404 | * Return absolute path to executable by searching PATH. | |
405 | * @param argv0 name of executable | |
406 | * @return (malloc'd) absolute path to executable (or NULL) | |
407 | */ | |
408 | static | |
409 | const char * findProgramPath(const char * argv0) | |
410 | { | |
411 | char *path = NULL, *s = NULL, *se; | |
412 | char *t = NULL; | |
413 | ||
414 | if (argv0 == NULL) return NULL; /* XXX can't happen */ | |
415 | ||
416 | /* If there is a / in argv[0], it has to be an absolute path. */ | |
417 | /* XXX Hmmm, why not if (argv0[0] == '/') ... instead? */ | |
418 | if (strchr(argv0, '/')) | |
419 | return xstrdup(argv0); | |
420 | ||
421 | if ((path = getenv("PATH")) == NULL || (path = xstrdup(path)) == NULL) | |
422 | return NULL; | |
423 | ||
424 | /* The return buffer in t is big enough for any path. */ | |
425 | if ((t = malloc(strlen(path) + strlen(argv0) + sizeof("/"))) != NULL) | |
426 | for (s = path; s && *s; s = se) { | |
427 | ||
428 | /* Snip PATH element into [s,se). */ | |
429 | if ((se = strchr(s, ':'))) | |
430 | *se++ = '\0'; | |
431 | ||
432 | /* Append argv0 to PATH element. */ | |
433 | (void) stpcpy(stpcpy(stpcpy(t, s), "/"), argv0); | |
434 | ||
435 | /* If file is executable, bingo! */ | |
436 | if (!access(t, X_OK)) | |
437 | break; | |
438 | } | |
439 | ||
440 | /* If no executable was found in PATH, return NULL. */ | |
441 | if (!(s && *s) && t != NULL) | |
442 | t = _free(t); | |
443 | path = _free(path); | |
444 | ||
445 | return t; | |
446 | } | |
447 | ||
cc248aae | 448 | static int execCommand(poptContext con) |
cc248aae WD |
449 | { |
450 | poptItem item = con->doExec; | |
4c8683c8 | 451 | poptArgv argv = NULL; |
cc248aae | 452 | int argc = 0; |
4c8683c8 AT |
453 | int rc; |
454 | int ec = POPT_ERROR_ERRNO; | |
62402cb1 | 455 | |
cc248aae WD |
456 | if (item == NULL) /*XXX can't happen*/ |
457 | return POPT_ERROR_NOARG; | |
62402cb1 | 458 | |
cc248aae WD |
459 | if (item->argv == NULL || item->argc < 1 || |
460 | (!con->execAbsolute && strchr(item->argv[0], '/'))) | |
461 | return POPT_ERROR_NOARG; | |
462 | ||
463 | argv = malloc(sizeof(*argv) * | |
464 | (6 + item->argc + con->numLeftovers + con->finalArgvCount)); | |
bc93ee84 | 465 | if (argv == NULL) return POPT_ERROR_MALLOC; |
62402cb1 | 466 | |
bc93ee84 | 467 | if (!strchr(item->argv[0], '/') && con->execPath != NULL) { |
4c8683c8 AT |
468 | char *s = malloc(strlen(con->execPath) + strlen(item->argv[0]) + sizeof("/")); |
469 | if (s) | |
470 | (void)stpcpy(stpcpy(stpcpy(s, con->execPath), "/"), item->argv[0]); | |
471 | ||
cc248aae | 472 | argv[argc] = s; |
bc93ee84 | 473 | } else |
cc248aae | 474 | argv[argc] = findProgramPath(item->argv[0]); |
4c8683c8 AT |
475 | if (argv[argc++] == NULL) { |
476 | ec = POPT_ERROR_NOARG; | |
477 | goto exit; | |
478 | } | |
62402cb1 | 479 | |
cc248aae WD |
480 | if (item->argc > 1) { |
481 | memcpy(argv + argc, item->argv + 1, sizeof(*argv) * (item->argc - 1)); | |
482 | argc += (item->argc - 1); | |
483 | } | |
62402cb1 | 484 | |
cc248aae WD |
485 | if (con->finalArgv != NULL && con->finalArgvCount > 0) { |
486 | memcpy(argv + argc, con->finalArgv, | |
487 | sizeof(*argv) * con->finalArgvCount); | |
488 | argc += con->finalArgvCount; | |
489 | } | |
62402cb1 | 490 | |
cc248aae | 491 | if (con->leftovers != NULL && con->numLeftovers > 0) { |
cc248aae WD |
492 | memcpy(argv + argc, con->leftovers, sizeof(*argv) * con->numLeftovers); |
493 | argc += con->numLeftovers; | |
62402cb1 MP |
494 | } |
495 | ||
cc248aae | 496 | argv[argc] = NULL; |
62402cb1 | 497 | |
4c8683c8 AT |
498 | #if defined(hpux) || defined(__hpux) |
499 | rc = setresgid(getgid(), getgid(),-1); | |
500 | if (rc) goto exit; | |
cc248aae | 501 | rc = setresuid(getuid(), getuid(),-1); |
4c8683c8 | 502 | if (rc) goto exit; |
62402cb1 | 503 | #else |
b348deae MP |
504 | /* |
505 | * XXX " ... on BSD systems setuid() should be preferred over setreuid()" | |
506 | * XXX sez' Timur Bakeyev <mc@bat.ru> | |
507 | * XXX from Norbert Warmuth <nwarmuth@privat.circular.de> | |
508 | */ | |
509 | #if defined(HAVE_SETUID) | |
4c8683c8 AT |
510 | rc = setgid(getgid()); |
511 | if (rc) goto exit; | |
cc248aae | 512 | rc = setuid(getuid()); |
4c8683c8 | 513 | if (rc) goto exit; |
b348deae | 514 | #elif defined (HAVE_SETREUID) |
4c8683c8 AT |
515 | rc = setregid(getgid(), getgid()); |
516 | if (rc) goto exit; | |
bc93ee84 | 517 | rc = setreuid(getuid(), getuid()); |
4c8683c8 | 518 | if (rc) goto exit; |
b348deae | 519 | #else |
4c8683c8 AT |
520 | /* refuse to exec if we cannot drop suid/sgid privileges */ |
521 | if (getuid() != geteuid() || getgid() != getegid()) { | |
522 | errno = ENOTSUP; | |
523 | goto exit; | |
524 | } | |
b348deae | 525 | #endif |
62402cb1 | 526 | #endif |
bc93ee84 WD |
527 | |
528 | #ifdef MYDEBUG | |
529 | if (_popt_debug) | |
4c8683c8 | 530 | { poptArgv avp; |
cc248aae WD |
531 | fprintf(stderr, "==> execvp(%s) argv[%d]:", argv[0], argc); |
532 | for (avp = argv; *avp; avp++) | |
533 | fprintf(stderr, " '%s'", *avp); | |
534 | fprintf(stderr, "\n"); | |
535 | } | |
536 | #endif | |
537 | ||
4c8683c8 | 538 | rc = execvp(argv[0], (char *const *)argv); |
bc93ee84 | 539 | |
4c8683c8 AT |
540 | /* only reached on execvp() failure */ |
541 | con->execFail = xstrdup(argv[0]); | |
542 | ||
543 | exit: | |
544 | if (argv) { | |
545 | if (argv[0]) | |
546 | free((void *)argv[0]); | |
547 | free(argv); | |
548 | } | |
549 | return ec; | |
62402cb1 MP |
550 | } |
551 | ||
4c8683c8 AT |
552 | static const struct poptOption * |
553 | findOption(const struct poptOption * opt, | |
554 | const char * longName, size_t longNameLen, | |
cc248aae | 555 | char shortName, |
4c8683c8 AT |
556 | poptCallbackType * callback, |
557 | const void ** callbackData, | |
558 | unsigned int argInfo) | |
b348deae | 559 | { |
62402cb1 | 560 | const struct poptOption * cb = NULL; |
4c8683c8 | 561 | poptArg cbarg = { .ptr = NULL }; |
62402cb1 | 562 | |
b348deae | 563 | /* This happens when a single - is given */ |
4c8683c8 | 564 | if (LF_ISSET(ONEDASH) && !shortName && (longName && *longName == '\0')) |
b348deae MP |
565 | shortName = '-'; |
566 | ||
cc248aae | 567 | for (; opt->longName || opt->shortName || opt->arg; opt++) { |
4c8683c8 | 568 | poptArg arg = { .ptr = opt->arg }; |
cc248aae | 569 | |
4c8683c8 AT |
570 | switch (poptArgType(opt)) { |
571 | case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */ | |
572 | { const struct poptOption * opt2; | |
573 | ||
574 | poptSubstituteHelpI18N(arg.opt); /* XXX side effects */ | |
575 | if (arg.ptr == NULL) continue; /* XXX program error */ | |
576 | opt2 = findOption(arg.opt, longName, longNameLen, shortName, callback, | |
577 | callbackData, argInfo); | |
cc248aae WD |
578 | if (opt2 == NULL) continue; |
579 | /* Sub-table data will be inheirited if no data yet. */ | |
4c8683c8 AT |
580 | if (callback && *callback |
581 | && callbackData && *callbackData == NULL) | |
582 | *callbackData = opt->descrip; | |
cc248aae | 583 | return opt2; |
4c8683c8 AT |
584 | } break; |
585 | case POPT_ARG_CALLBACK: | |
62402cb1 | 586 | cb = opt; |
4c8683c8 AT |
587 | cbarg.ptr = opt->arg; |
588 | continue; | |
589 | break; | |
590 | default: | |
591 | break; | |
592 | } | |
593 | ||
594 | if (longName != NULL && opt->longName != NULL && | |
595 | (!LF_ISSET(ONEDASH) || F_ISSET(opt, ONEDASH)) && | |
596 | longOptionStrcmp(opt, longName, longNameLen)) | |
cc248aae | 597 | { |
62402cb1 MP |
598 | break; |
599 | } else if (shortName && shortName == opt->shortName) { | |
600 | break; | |
601 | } | |
62402cb1 MP |
602 | } |
603 | ||
4c8683c8 | 604 | if (opt->longName == NULL && !opt->shortName) |
cc248aae | 605 | return NULL; |
4c8683c8 AT |
606 | |
607 | if (callback) | |
608 | *callback = (cb ? cbarg.cb : NULL); | |
609 | if (callbackData) | |
610 | *callbackData = (cb && !CBF_ISSET(cb, INC_DATA) ? cb->descrip : NULL); | |
62402cb1 MP |
611 | |
612 | return opt; | |
613 | } | |
614 | ||
4c8683c8 | 615 | static const char * findNextArg(poptContext con, |
cc248aae | 616 | unsigned argx, int delete_arg) |
b348deae MP |
617 | { |
618 | struct optionStackEntry * os = con->os; | |
619 | const char * arg; | |
620 | ||
621 | do { | |
622 | int i; | |
623 | arg = NULL; | |
624 | while (os->next == os->argc && os > con->optionStack) os--; | |
625 | if (os->next == os->argc && os == con->optionStack) break; | |
cc248aae | 626 | if (os->argv != NULL) |
b348deae | 627 | for (i = os->next; i < os->argc; i++) { |
cc248aae | 628 | if (os->argb && PBM_ISSET(i, os->argb)) |
4c8683c8 | 629 | continue; |
cc248aae | 630 | if (*os->argv[i] == '-') |
4c8683c8 | 631 | continue; |
cc248aae | 632 | if (--argx > 0) |
4c8683c8 | 633 | continue; |
b348deae | 634 | arg = os->argv[i]; |
cc248aae | 635 | if (delete_arg) { |
b348deae | 636 | if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc); |
cc248aae | 637 | if (os->argb != NULL) /* XXX can't happen */ |
4c8683c8 | 638 | PBM_SET(i, os->argb); |
b348deae | 639 | } |
4c8683c8 | 640 | break; |
b348deae MP |
641 | } |
642 | if (os > con->optionStack) os--; | |
643 | } while (arg == NULL); | |
644 | return arg; | |
645 | } | |
646 | ||
4c8683c8 AT |
647 | static const char * |
648 | expandNextArg(poptContext con, const char * s) | |
b348deae | 649 | { |
cc248aae | 650 | const char * a = NULL; |
4c8683c8 | 651 | char *t, *t_tmp, *te; |
b348deae MP |
652 | size_t tn = strlen(s) + 1; |
653 | char c; | |
654 | ||
4c8683c8 | 655 | te = t = malloc(tn); |
cc248aae | 656 | if (t == NULL) return NULL; /* XXX can't happen */ |
4c8683c8 | 657 | *t = '\0'; |
b348deae MP |
658 | while ((c = *s++) != '\0') { |
659 | switch (c) { | |
660 | #if 0 /* XXX can't do this */ | |
661 | case '\\': /* escape */ | |
662 | c = *s++; | |
4c8683c8 | 663 | break; |
b348deae MP |
664 | #endif |
665 | case '!': | |
666 | if (!(s[0] == '#' && s[1] == ':' && s[2] == '+')) | |
4c8683c8 | 667 | break; |
cc248aae WD |
668 | /* XXX Make sure that findNextArg deletes only next arg. */ |
669 | if (a == NULL) { | |
4c8683c8 AT |
670 | if ((a = findNextArg(con, 1U, 1)) == NULL) |
671 | break; | |
672 | } | |
673 | s += sizeof("#:+") - 1; | |
674 | ||
675 | tn += strlen(a); | |
676 | { size_t pos = (size_t) (te - t); | |
677 | if ((t_tmp = realloc(t, tn)) == NULL) { /* XXX can't happen */ | |
678 | free(t); | |
679 | return NULL; | |
680 | } | |
681 | t = t_tmp; | |
682 | te = stpcpy(t + pos, a); | |
cc248aae | 683 | } |
b348deae | 684 | continue; |
4c8683c8 | 685 | break; |
b348deae | 686 | default: |
4c8683c8 | 687 | break; |
b348deae MP |
688 | } |
689 | *te++ = c; | |
690 | } | |
4c8683c8 AT |
691 | *te++ = '\0'; |
692 | /* If the new string is longer than needed, shorten. */ | |
693 | if ((t + tn) > te) { | |
694 | if ((te = realloc(t, (size_t)(te - t))) == NULL) | |
695 | free(t); | |
696 | t = te; | |
697 | } | |
b348deae MP |
698 | return t; |
699 | } | |
700 | ||
4c8683c8 | 701 | static void poptStripArg(poptContext con, int which) |
b348deae | 702 | { |
cc248aae | 703 | if (con->arg_strip == NULL) |
b348deae | 704 | con->arg_strip = PBM_ALLOC(con->optionStack[0].argc); |
cc248aae | 705 | if (con->arg_strip != NULL) /* XXX can't happen */ |
b348deae | 706 | PBM_SET(which, con->arg_strip); |
cc248aae | 707 | return; |
cc248aae WD |
708 | } |
709 | ||
4c8683c8 AT |
710 | unsigned int _poptBitsN = _POPT_BITS_N; |
711 | unsigned int _poptBitsM = _POPT_BITS_M; | |
712 | unsigned int _poptBitsK = _POPT_BITS_K; | |
713 | ||
714 | static int _poptBitsNew(poptBits *bitsp) | |
715 | { | |
716 | if (bitsp == NULL) | |
717 | return POPT_ERROR_NULLARG; | |
718 | ||
719 | /* XXX handle negated initialization. */ | |
720 | if (*bitsp == NULL) { | |
721 | if (_poptBitsN == 0) { | |
722 | _poptBitsN = _POPT_BITS_N; | |
723 | _poptBitsM = _POPT_BITS_M; | |
724 | } | |
725 | if (_poptBitsM == 0U) _poptBitsM = (3 * _poptBitsN) / 2; | |
726 | if (_poptBitsK == 0U || _poptBitsK > 32U) _poptBitsK = _POPT_BITS_K; | |
727 | *bitsp = PBM_ALLOC(_poptBitsM-1); | |
728 | } | |
729 | return 0; | |
730 | } | |
731 | ||
732 | int poptBitsAdd(poptBits bits, const char * s) | |
733 | { | |
734 | size_t ns = (s ? strlen(s) : 0); | |
735 | uint32_t h0 = 0; | |
736 | uint32_t h1 = 0; | |
737 | ||
738 | if (bits == NULL || ns == 0) | |
739 | return POPT_ERROR_NULLARG; | |
740 | ||
741 | poptJlu32lpair(s, ns, &h0, &h1); | |
742 | ||
743 | for (ns = 0; ns < (size_t)_poptBitsK; ns++) { | |
744 | uint32_t h = h0 + ns * h1; | |
745 | uint32_t ix = (h % _poptBitsM); | |
746 | PBM_SET(ix, bits); | |
747 | } | |
748 | return 0; | |
749 | } | |
750 | ||
751 | int poptBitsChk(poptBits bits, const char * s) | |
752 | { | |
753 | size_t ns = (s ? strlen(s) : 0); | |
754 | uint32_t h0 = 0; | |
755 | uint32_t h1 = 0; | |
756 | int rc = 1; | |
757 | ||
758 | if (bits == NULL || ns == 0) | |
759 | return POPT_ERROR_NULLARG; | |
760 | ||
761 | poptJlu32lpair(s, ns, &h0, &h1); | |
762 | ||
763 | for (ns = 0; ns < (size_t)_poptBitsK; ns++) { | |
764 | uint32_t h = h0 + ns * h1; | |
765 | uint32_t ix = (h % _poptBitsM); | |
766 | if (PBM_ISSET(ix, bits)) | |
767 | continue; | |
768 | rc = 0; | |
769 | break; | |
770 | } | |
771 | return rc; | |
772 | } | |
773 | ||
774 | int poptBitsClr(poptBits bits) | |
775 | { | |
776 | static size_t nbw = (__PBM_NBITS/8); | |
777 | size_t nw = (__PBM_IX(_poptBitsM-1) + 1); | |
778 | ||
779 | if (bits == NULL) | |
780 | return POPT_ERROR_NULLARG; | |
781 | memset(bits, 0, nw * nbw); | |
782 | return 0; | |
783 | } | |
784 | ||
785 | int poptBitsDel(poptBits bits, const char * s) | |
786 | { | |
787 | size_t ns = (s ? strlen(s) : 0); | |
788 | uint32_t h0 = 0; | |
789 | uint32_t h1 = 0; | |
790 | ||
791 | if (bits == NULL || ns == 0) | |
792 | return POPT_ERROR_NULLARG; | |
793 | ||
794 | poptJlu32lpair(s, ns, &h0, &h1); | |
795 | ||
796 | for (ns = 0; ns < (size_t)_poptBitsK; ns++) { | |
797 | uint32_t h = h0 + ns * h1; | |
798 | uint32_t ix = (h % _poptBitsM); | |
799 | PBM_CLR(ix, bits); | |
800 | } | |
801 | return 0; | |
802 | } | |
803 | ||
804 | int poptBitsIntersect(poptBits *ap, const poptBits b) | |
805 | { | |
806 | __pbm_bits *abits; | |
807 | __pbm_bits *bbits; | |
808 | __pbm_bits rc = 0; | |
809 | size_t nw = (__PBM_IX(_poptBitsM-1) + 1); | |
810 | size_t i; | |
811 | ||
812 | if (ap == NULL || b == NULL || _poptBitsNew(ap)) | |
813 | return POPT_ERROR_NULLARG; | |
814 | abits = __PBM_BITS(*ap); | |
815 | bbits = __PBM_BITS(b); | |
816 | ||
817 | for (i = 0; i < nw; i++) { | |
818 | abits[i] &= bbits[i]; | |
819 | rc |= abits[i]; | |
820 | } | |
821 | return (rc ? 1 : 0); | |
822 | } | |
823 | ||
824 | int poptBitsUnion(poptBits *ap, const poptBits b) | |
825 | { | |
826 | __pbm_bits *abits; | |
827 | __pbm_bits *bbits; | |
828 | __pbm_bits rc = 0; | |
829 | size_t nw = (__PBM_IX(_poptBitsM-1) + 1); | |
830 | size_t i; | |
831 | ||
832 | if (ap == NULL || b == NULL || _poptBitsNew(ap)) | |
833 | return POPT_ERROR_NULLARG; | |
834 | abits = __PBM_BITS(*ap); | |
835 | bbits = __PBM_BITS(b); | |
836 | ||
837 | for (i = 0; i < nw; i++) { | |
838 | abits[i] |= bbits[i]; | |
839 | rc |= abits[i]; | |
840 | } | |
841 | return (rc ? 1 : 0); | |
842 | } | |
843 | ||
844 | int poptBitsArgs(poptContext con, poptBits *ap) | |
845 | { | |
846 | const char ** av; | |
847 | int rc = 0; | |
848 | ||
849 | if (con == NULL || ap == NULL || _poptBitsNew(ap) || | |
850 | con->leftovers == NULL || con->numLeftovers == con->nextLeftover) | |
851 | return POPT_ERROR_NULLARG; | |
852 | ||
853 | /* some apps like [like RPM ;-) ] need this NULL terminated */ | |
854 | con->leftovers[con->numLeftovers] = NULL; | |
855 | ||
856 | for (av = con->leftovers + con->nextLeftover; *av != NULL; av++) { | |
857 | if ((rc = poptBitsAdd(*ap, *av)) != 0) | |
858 | break; | |
859 | } | |
860 | return rc; | |
861 | } | |
862 | ||
863 | int poptSaveBits(poptBits * bitsp, | |
864 | UNUSED(unsigned int argInfo), const char * s) | |
865 | { | |
866 | char *tbuf = NULL; | |
867 | char *t, *te; | |
868 | int rc = 0; | |
869 | ||
870 | if (bitsp == NULL || s == NULL || *s == '\0' || _poptBitsNew(bitsp)) | |
871 | return POPT_ERROR_NULLARG; | |
872 | ||
873 | /* Parse comma separated attributes. */ | |
874 | te = tbuf = xstrdup(s); | |
875 | while ((t = te) != NULL && *t) { | |
876 | while (*te != '\0' && *te != ',') | |
877 | te++; | |
878 | if (*te != '\0') | |
879 | *te++ = '\0'; | |
880 | /* XXX Ignore empty strings. */ | |
881 | if (*t == '\0') | |
882 | continue; | |
883 | /* XXX Permit negated attributes. caveat emptor: false negatives. */ | |
884 | if (*t == '!') { | |
885 | t++; | |
886 | if ((rc = poptBitsChk(*bitsp, t)) > 0) | |
887 | rc = poptBitsDel(*bitsp, t); | |
888 | } else | |
889 | rc = poptBitsAdd(*bitsp, t); | |
890 | if (rc) | |
891 | break; | |
892 | } | |
893 | tbuf = _free(tbuf); | |
894 | return rc; | |
895 | } | |
896 | ||
897 | int poptSaveString(const char *** argvp, | |
898 | UNUSED(unsigned int argInfo), const char * val) | |
899 | { | |
900 | int argc = 0; | |
901 | ||
902 | if (argvp == NULL || val == NULL) | |
903 | return POPT_ERROR_NULLARG; | |
904 | ||
905 | /* XXX likely needs an upper bound on argc. */ | |
906 | if (*argvp != NULL) | |
907 | while ((*argvp)[argc] != NULL) | |
908 | argc++; | |
909 | ||
910 | if ((*argvp = xrealloc(*argvp, (argc + 1 + 1) * sizeof(**argvp))) != NULL) { | |
911 | (*argvp)[argc++] = xstrdup(val); | |
912 | (*argvp)[argc ] = NULL; | |
913 | } | |
914 | return 0; | |
915 | } | |
916 | ||
917 | static long long poptRandomValue(long long limit) | |
918 | { | |
919 | #if defined(HAVE_SRANDOM) | |
920 | static int seed = 1; | |
921 | ||
922 | if (seed) { | |
923 | srandom((unsigned)getpid()); | |
924 | srandom((unsigned)random()); | |
925 | seed = 0; | |
926 | } | |
927 | ||
928 | return random() % limit + 1; | |
929 | #else | |
930 | /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */ | |
931 | return POPT_ERROR_BADOPERATION; | |
932 | #endif | |
933 | } | |
934 | ||
935 | int poptSaveLongLong(long long * arg, unsigned int argInfo, long long aLongLong) | |
cc248aae | 936 | { |
bc93ee84 | 937 | /* XXX Check alignment, may fail on funky platforms. */ |
4c8683c8 | 938 | if (arg == NULL || (((unsigned long)arg) & (ALIGNOF(*arg)-1))) |
cc248aae WD |
939 | return POPT_ERROR_NULLARG; |
940 | ||
4c8683c8 AT |
941 | if (aLongLong != 0 && LF_ISSET(RANDOM)) { |
942 | aLongLong = poptRandomValue(aLongLong); | |
943 | if (aLongLong < 0) | |
944 | return aLongLong; | |
945 | } | |
946 | if (LF_ISSET(NOT)) | |
947 | aLongLong = ~aLongLong; | |
948 | switch (LF_ISSET(LOGICALOPS)) { | |
cc248aae | 949 | case 0: |
4c8683c8 | 950 | *arg = aLongLong; |
cc248aae WD |
951 | break; |
952 | case POPT_ARGFLAG_OR: | |
4c8683c8 | 953 | *(unsigned long long *)arg |= (unsigned long long)aLongLong; |
cc248aae WD |
954 | break; |
955 | case POPT_ARGFLAG_AND: | |
4c8683c8 | 956 | *(unsigned long long *)arg &= (unsigned long long)aLongLong; |
cc248aae WD |
957 | break; |
958 | case POPT_ARGFLAG_XOR: | |
4c8683c8 | 959 | *(unsigned long long *)arg ^= (unsigned long long)aLongLong; |
cc248aae WD |
960 | break; |
961 | default: | |
962 | return POPT_ERROR_BADOPERATION; | |
4c8683c8 | 963 | break; |
cc248aae WD |
964 | } |
965 | return 0; | |
966 | } | |
967 | ||
4c8683c8 | 968 | int poptSaveLong(long * arg, unsigned int argInfo, long aLong) |
cc248aae | 969 | { |
bc93ee84 | 970 | /* XXX Check alignment, may fail on funky platforms. */ |
4c8683c8 | 971 | if (arg == NULL || (((unsigned long)arg) & (ALIGNOF(*arg)-1))) |
cc248aae WD |
972 | return POPT_ERROR_NULLARG; |
973 | ||
4c8683c8 AT |
974 | if (aLong != 0 && LF_ISSET(RANDOM)) { |
975 | aLong = (long)poptRandomValue(aLong); | |
976 | if (aLong < 0) | |
977 | return aLong; | |
978 | } | |
979 | if (LF_ISSET(NOT)) | |
cc248aae | 980 | aLong = ~aLong; |
4c8683c8 AT |
981 | switch (LF_ISSET(LOGICALOPS)) { |
982 | case 0: *arg = aLong; break; | |
983 | case POPT_ARGFLAG_OR: *(unsigned long *)arg |= (unsigned long)aLong; break; | |
984 | case POPT_ARGFLAG_AND: *(unsigned long *)arg &= (unsigned long)aLong; break; | |
985 | case POPT_ARGFLAG_XOR: *(unsigned long *)arg ^= (unsigned long)aLong; break; | |
986 | default: | |
987 | return POPT_ERROR_BADOPERATION; | |
cc248aae | 988 | break; |
4c8683c8 AT |
989 | } |
990 | return 0; | |
991 | } | |
992 | ||
993 | int poptSaveInt(int * arg, unsigned int argInfo, long aLong) | |
994 | { | |
995 | /* XXX Check alignment, may fail on funky platforms. */ | |
996 | if (arg == NULL || (((unsigned long)arg) & (ALIGNOF(*arg)-1))) | |
997 | return POPT_ERROR_NULLARG; | |
998 | ||
999 | if (aLong != 0 && LF_ISSET(RANDOM)) { | |
1000 | aLong = (int)poptRandomValue(aLong); | |
1001 | if (aLong < 0) | |
1002 | return aLong; | |
1003 | } | |
1004 | if (LF_ISSET(NOT)) | |
1005 | aLong = ~aLong; | |
1006 | switch (LF_ISSET(LOGICALOPS)) { | |
1007 | case 0: *arg = (int) aLong; break; | |
1008 | case POPT_ARGFLAG_OR: *(unsigned int *)arg |= (unsigned int) aLong; break; | |
1009 | case POPT_ARGFLAG_AND: *(unsigned int *)arg &= (unsigned int) aLong; break; | |
1010 | case POPT_ARGFLAG_XOR: *(unsigned int *)arg ^= (unsigned int) aLong; break; | |
1011 | default: | |
1012 | return POPT_ERROR_BADOPERATION; | |
cc248aae | 1013 | break; |
4c8683c8 AT |
1014 | } |
1015 | return 0; | |
1016 | } | |
1017 | ||
1018 | int poptSaveShort(short * arg, unsigned int argInfo, long aLong) | |
1019 | { | |
1020 | /* XXX Check alignment, may fail on funky platforms. */ | |
1021 | if (arg == NULL || (((unsigned long)arg) & (ALIGNOF(*arg)-1))) | |
1022 | return POPT_ERROR_NULLARG; | |
1023 | ||
1024 | if (aLong != 0 && LF_ISSET(RANDOM)) { | |
1025 | aLong = (short)poptRandomValue(aLong); | |
1026 | if (aLong < 0) | |
1027 | return aLong; | |
1028 | } | |
1029 | if (LF_ISSET(NOT)) | |
1030 | aLong = ~aLong; | |
1031 | switch (LF_ISSET(LOGICALOPS)) { | |
1032 | case 0: *arg = (short) aLong; | |
cc248aae | 1033 | break; |
4c8683c8 AT |
1034 | case POPT_ARGFLAG_OR: *(unsigned short *)arg |= (unsigned short) aLong; |
1035 | break; | |
1036 | case POPT_ARGFLAG_AND: *(unsigned short *)arg &= (unsigned short) aLong; | |
1037 | break; | |
1038 | case POPT_ARGFLAG_XOR: *(unsigned short *)arg ^= (unsigned short) aLong; | |
1039 | break; | |
1040 | default: return POPT_ERROR_BADOPERATION; | |
cc248aae | 1041 | break; |
cc248aae WD |
1042 | } |
1043 | return 0; | |
b348deae MP |
1044 | } |
1045 | ||
4c8683c8 AT |
1046 | /** |
1047 | * Return argInfo field, handling POPT_ARGFLAG_TOGGLE overrides. | |
1048 | * @param con context | |
1049 | * @param opt option | |
1050 | * @return argInfo | |
1051 | */ | |
1052 | static unsigned int poptArgInfo(poptContext con, const struct poptOption * opt) | |
1053 | { | |
1054 | unsigned int argInfo = opt->argInfo; | |
1055 | ||
1056 | if (con->os->argv != NULL && con->os->next > 0 && opt->longName != NULL) | |
1057 | if (LF_ISSET(TOGGLE)) { | |
1058 | const char * longName = con->os->argv[con->os->next-1]; | |
1059 | while (*longName == '-') longName++; | |
1060 | /* XXX almost good enough but consider --[no]nofoo corner cases. */ | |
1061 | if (longName[0] != opt->longName[0] || longName[1] != opt->longName[1]) | |
1062 | { | |
1063 | if (!LF_ISSET(XOR)) { /* XXX dont toggle with XOR */ | |
1064 | /* Toggle POPT_BIT_SET <=> POPT_BIT_CLR. */ | |
1065 | if (LF_ISSET(LOGICALOPS)) | |
1066 | argInfo ^= (POPT_ARGFLAG_OR|POPT_ARGFLAG_AND); | |
1067 | argInfo ^= POPT_ARGFLAG_NOT; | |
1068 | } | |
1069 | } | |
1070 | } | |
1071 | return argInfo; | |
1072 | } | |
1073 | ||
1074 | /** | |
1075 | * Parse an integer expression. | |
1076 | * @retval *llp integer expression value | |
1077 | * @param argInfo integer expression type | |
1078 | * @param val integer expression string | |
1079 | * @return 0 on success, otherwise POPT_* error. | |
1080 | */ | |
1081 | static int poptParseInteger(long long * llp, | |
1082 | UNUSED(unsigned int argInfo), | |
1083 | const char * val) | |
1084 | { | |
1085 | if (val) { | |
1086 | char *end = NULL; | |
1087 | *llp = strtoll(val, &end, 0); | |
1088 | ||
1089 | /* XXX parse scaling suffixes here. */ | |
1090 | ||
1091 | if (!(end && *end == '\0')) | |
1092 | return POPT_ERROR_BADNUMBER; | |
1093 | } else | |
1094 | *llp = 0; | |
1095 | return 0; | |
1096 | } | |
1097 | ||
1098 | /** | |
1099 | * Save the option argument through the (*opt->arg) pointer. | |
1100 | * @param con context | |
1101 | * @param opt option | |
1102 | * @return 0 on success, otherwise POPT_* error. | |
1103 | */ | |
1104 | static int poptSaveArg(poptContext con, const struct poptOption * opt) | |
1105 | { | |
1106 | poptArg arg = { .ptr = opt->arg }; | |
1107 | int rc = 0; /* assume success */ | |
1108 | ||
1109 | switch (poptArgType(opt)) { | |
1110 | case POPT_ARG_BITSET: | |
1111 | /* XXX memory leak, application is responsible for free. */ | |
1112 | rc = poptSaveBits(arg.ptr, opt->argInfo, con->os->nextArg); | |
1113 | break; | |
1114 | case POPT_ARG_ARGV: | |
1115 | /* XXX memory leak, application is responsible for free. */ | |
1116 | rc = poptSaveString(arg.ptr, opt->argInfo, con->os->nextArg); | |
1117 | break; | |
1118 | case POPT_ARG_STRING: | |
1119 | /* XXX memory leak, application is responsible for free. */ | |
1120 | arg.argv[0] = (con->os->nextArg) ? xstrdup(con->os->nextArg) : NULL; | |
1121 | break; | |
1122 | ||
1123 | case POPT_ARG_INT: | |
1124 | case POPT_ARG_SHORT: | |
1125 | case POPT_ARG_LONG: | |
1126 | case POPT_ARG_LONGLONG: | |
1127 | { unsigned int argInfo = poptArgInfo(con, opt); | |
1128 | long long aNUM = 0; | |
1129 | ||
1130 | if ((rc = poptParseInteger(&aNUM, argInfo, con->os->nextArg)) != 0) | |
1131 | break; | |
1132 | ||
1133 | switch (poptArgType(opt)) { | |
1134 | case POPT_ARG_LONGLONG: | |
1135 | /* XXX let's not demand C99 compiler flags for <limits.h> quite yet. */ | |
1136 | #if !defined(LLONG_MAX) | |
1137 | # define LLONG_MAX 9223372036854775807LL | |
1138 | # define LLONG_MIN (-LLONG_MAX - 1LL) | |
1139 | #endif | |
1140 | rc = !(aNUM == LLONG_MIN || aNUM == LLONG_MAX) | |
1141 | ? poptSaveLongLong(arg.longlongp, argInfo, aNUM) | |
1142 | : POPT_ERROR_OVERFLOW; | |
1143 | break; | |
1144 | case POPT_ARG_LONG: | |
1145 | rc = !(aNUM < (long long)LONG_MIN || aNUM > (long long)LONG_MAX) | |
1146 | ? poptSaveLong(arg.longp, argInfo, (long)aNUM) | |
1147 | : POPT_ERROR_OVERFLOW; | |
1148 | break; | |
1149 | case POPT_ARG_INT: | |
1150 | rc = !(aNUM < (long long)INT_MIN || aNUM > (long long)INT_MAX) | |
1151 | ? poptSaveInt(arg.intp, argInfo, (long)aNUM) | |
1152 | : POPT_ERROR_OVERFLOW; | |
1153 | break; | |
1154 | case POPT_ARG_SHORT: | |
1155 | rc = !(aNUM < (long long)SHRT_MIN || aNUM > (long long)SHRT_MAX) | |
1156 | ? poptSaveShort(arg.shortp, argInfo, (long)aNUM) | |
1157 | : POPT_ERROR_OVERFLOW; | |
1158 | break; | |
1159 | } | |
1160 | } break; | |
1161 | ||
1162 | case POPT_ARG_FLOAT: | |
1163 | case POPT_ARG_DOUBLE: | |
1164 | { char *end = NULL; | |
1165 | double aDouble = 0.0; | |
1166 | ||
1167 | if (con->os->nextArg) { | |
1168 | int saveerrno = errno; | |
1169 | errno = 0; | |
1170 | aDouble = strtod(con->os->nextArg, &end); | |
1171 | if (errno == ERANGE) { | |
1172 | rc = POPT_ERROR_OVERFLOW; | |
1173 | break; | |
1174 | } | |
1175 | errno = saveerrno; | |
1176 | if (*end != '\0') { | |
1177 | rc = POPT_ERROR_BADNUMBER; | |
1178 | break; | |
1179 | } | |
1180 | } | |
1181 | ||
1182 | switch (poptArgType(opt)) { | |
1183 | case POPT_ARG_DOUBLE: | |
1184 | arg.doublep[0] = aDouble; | |
1185 | break; | |
1186 | case POPT_ARG_FLOAT: | |
1187 | #define POPT_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a)) | |
1188 | if ((FLT_MIN - POPT_ABS(aDouble)) > DBL_EPSILON | |
1189 | || (POPT_ABS(aDouble) - FLT_MAX) > DBL_EPSILON) | |
1190 | rc = POPT_ERROR_OVERFLOW; | |
1191 | else | |
1192 | arg.floatp[0] = (float) aDouble; | |
1193 | break; | |
1194 | } | |
1195 | } break; | |
1196 | case POPT_ARG_MAINCALL: | |
1197 | con->maincall = opt->arg; | |
1198 | break; | |
1199 | default: | |
1200 | fprintf(stdout, POPT_("option type (%u) not implemented in popt\n"), | |
1201 | poptArgType(opt)); | |
1202 | exit(EXIT_FAILURE); | |
1203 | break; | |
1204 | } | |
1205 | return rc; | |
1206 | } | |
1207 | ||
62402cb1 | 1208 | /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */ |
b348deae MP |
1209 | int poptGetNextOpt(poptContext con) |
1210 | { | |
62402cb1 MP |
1211 | const struct poptOption * opt = NULL; |
1212 | int done = 0; | |
62402cb1 | 1213 | |
cc248aae WD |
1214 | if (con == NULL) |
1215 | return -1; | |
62402cb1 | 1216 | while (!done) { |
b348deae MP |
1217 | const char * origOptString = NULL; |
1218 | poptCallbackType cb = NULL; | |
1219 | const void * cbData = NULL; | |
1220 | const char * longArg = NULL; | |
1221 | int canstrip = 0; | |
cc248aae | 1222 | int shorty = 0; |
b348deae MP |
1223 | |
1224 | while (!con->os->nextCharArg && con->os->next == con->os->argc | |
1225 | && con->os > con->optionStack) { | |
1226 | cleanOSE(con->os--); | |
1227 | } | |
62402cb1 | 1228 | if (!con->os->nextCharArg && con->os->next == con->os->argc) { |
cc248aae | 1229 | invokeCallbacksPOST(con, con->options); |
4c8683c8 AT |
1230 | |
1231 | if (con->maincall) { | |
1232 | (void) (*con->maincall) (con->finalArgvCount, con->finalArgv); | |
1233 | return -1; | |
1234 | } | |
1235 | ||
cc248aae | 1236 | if (con->doExec) return execCommand(con); |
62402cb1 MP |
1237 | return -1; |
1238 | } | |
1239 | ||
b348deae | 1240 | /* Process next long option */ |
62402cb1 | 1241 | if (!con->os->nextCharArg) { |
4c8683c8 AT |
1242 | const char * optString; |
1243 | size_t optStringLen; | |
b348deae MP |
1244 | int thisopt; |
1245 | ||
1246 | if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) { | |
1247 | con->os->next++; | |
1248 | continue; | |
1249 | } | |
cc248aae WD |
1250 | thisopt = con->os->next; |
1251 | if (con->os->argv != NULL) /* XXX can't happen */ | |
62402cb1 MP |
1252 | origOptString = con->os->argv[con->os->next++]; |
1253 | ||
cc248aae WD |
1254 | if (origOptString == NULL) /* XXX can't happen */ |
1255 | return POPT_ERROR_BADOPT; | |
1256 | ||
4c8683c8 AT |
1257 | if (con->restLeftover || *origOptString != '-' || |
1258 | (*origOptString == '-' && origOptString[1] == '\0')) | |
1259 | { | |
62402cb1 MP |
1260 | if (con->flags & POPT_CONTEXT_POSIXMEHARDER) |
1261 | con->restLeftover = 1; | |
cc248aae WD |
1262 | if (con->flags & POPT_CONTEXT_ARG_OPTS) { |
1263 | con->os->nextArg = xstrdup(origOptString); | |
1264 | return 0; | |
1265 | } | |
4c8683c8 AT |
1266 | if (con->leftovers != NULL) { /* XXX can't happen */ |
1267 | /* One might think we can never overflow the leftovers | |
1268 | array. Actually, that's true, as long as you don't | |
1269 | use poptStuffArgs()... */ | |
1270 | if ((con->numLeftovers + 1) >= (con->allocLeftovers)) { | |
1271 | con->allocLeftovers += 10; | |
1272 | con->leftovers = | |
1273 | realloc(con->leftovers, | |
1274 | sizeof(*con->leftovers) * con->allocLeftovers); | |
1275 | } | |
1276 | con->leftovers[con->numLeftovers++] | |
1277 | = xstrdup(origOptString); /* so a free of a stuffed | |
1278 | argv doesn't give us a | |
1279 | dangling pointer */ | |
1280 | } | |
62402cb1 MP |
1281 | continue; |
1282 | } | |
1283 | ||
1284 | /* Make a copy we can hack at */ | |
4c8683c8 | 1285 | optString = origOptString; |
62402cb1 | 1286 | |
cc248aae | 1287 | if (optString[0] == '\0') |
62402cb1 MP |
1288 | return POPT_ERROR_BADOPT; |
1289 | ||
1290 | if (optString[1] == '-' && !optString[2]) { | |
1291 | con->restLeftover = 1; | |
1292 | continue; | |
1293 | } else { | |
4c8683c8 AT |
1294 | const char *oe; |
1295 | unsigned int argInfo = 0; | |
b348deae | 1296 | |
62402cb1 MP |
1297 | optString++; |
1298 | if (*optString == '-') | |
4c8683c8 | 1299 | optString++; |
62402cb1 | 1300 | else |
4c8683c8 AT |
1301 | argInfo |= POPT_ARGFLAG_ONEDASH; |
1302 | ||
1303 | /* Check for "--long=arg" option. */ | |
1304 | for (oe = optString; *oe && *oe != '='; oe++) | |
1305 | {}; | |
1306 | optStringLen = (size_t)(oe - optString); | |
1307 | if (*oe == '=') | |
1308 | longArg = oe + 1; | |
62402cb1 | 1309 | |
b348deae | 1310 | /* XXX aliases with arg substitution need "--alias=arg" */ |
4c8683c8 AT |
1311 | if (handleAlias(con, optString, optStringLen, '\0', longArg)) { |
1312 | longArg = NULL; | |
62402cb1 | 1313 | continue; |
4c8683c8 | 1314 | } |
cc248aae | 1315 | |
62402cb1 MP |
1316 | if (handleExec(con, optString, '\0')) |
1317 | continue; | |
1318 | ||
4c8683c8 AT |
1319 | opt = findOption(con->options, optString, optStringLen, '\0', &cb, &cbData, |
1320 | argInfo); | |
1321 | if (!opt && !LF_ISSET(ONEDASH)) | |
b348deae | 1322 | return POPT_ERROR_BADOPT; |
62402cb1 MP |
1323 | } |
1324 | ||
b348deae | 1325 | if (!opt) { |
62402cb1 | 1326 | con->os->nextCharArg = origOptString + 1; |
894e6299 | 1327 | longArg = NULL; |
b348deae | 1328 | } else { |
4c8683c8 | 1329 | if (con->os == con->optionStack && F_ISSET(opt, STRIP)) |
cc248aae | 1330 | { |
b348deae MP |
1331 | canstrip = 1; |
1332 | poptStripArg(con, thisopt); | |
1333 | } | |
cc248aae | 1334 | shorty = 0; |
b348deae | 1335 | } |
62402cb1 MP |
1336 | } |
1337 | ||
b348deae | 1338 | /* Process next short option */ |
62402cb1 | 1339 | if (con->os->nextCharArg) { |
4c8683c8 | 1340 | const char * nextCharArg = con->os->nextCharArg; |
62402cb1 MP |
1341 | |
1342 | con->os->nextCharArg = NULL; | |
1343 | ||
4c8683c8 | 1344 | if (handleAlias(con, NULL, 0, *nextCharArg, nextCharArg + 1)) |
cc248aae WD |
1345 | continue; |
1346 | ||
4c8683c8 | 1347 | if (handleExec(con, NULL, *nextCharArg)) { |
cc248aae | 1348 | /* Restore rest of short options for further processing */ |
4c8683c8 AT |
1349 | nextCharArg++; |
1350 | if (*nextCharArg != '\0') | |
1351 | con->os->nextCharArg = nextCharArg; | |
62402cb1 MP |
1352 | continue; |
1353 | } | |
62402cb1 | 1354 | |
4c8683c8 | 1355 | opt = findOption(con->options, NULL, 0, *nextCharArg, &cb, |
62402cb1 | 1356 | &cbData, 0); |
b348deae MP |
1357 | if (!opt) |
1358 | return POPT_ERROR_BADOPT; | |
cc248aae | 1359 | shorty = 1; |
62402cb1 | 1360 | |
4c8683c8 AT |
1361 | nextCharArg++; |
1362 | if (*nextCharArg != '\0') | |
1363 | con->os->nextCharArg = nextCharArg; | |
62402cb1 MP |
1364 | } |
1365 | ||
cc248aae | 1366 | if (opt == NULL) return POPT_ERROR_BADOPT; /* XXX can't happen */ |
4c8683c8 | 1367 | if (poptArgType(opt) == POPT_ARG_NONE || poptArgType(opt) == POPT_ARG_VAL) { |
25082d1e WD |
1368 | if (longArg || (con->os->nextCharArg && con->os->nextCharArg[0] == '=')) |
1369 | return POPT_ERROR_UNWANTEDARG; | |
cc248aae | 1370 | if (opt->arg) { |
4c8683c8 AT |
1371 | long val = poptArgType(opt) == POPT_ARG_VAL ? opt->val : 1; |
1372 | unsigned int argInfo = poptArgInfo(con, opt); | |
1373 | if (poptSaveInt((int *)opt->arg, argInfo, val)) | |
cc248aae | 1374 | return POPT_ERROR_BADOPERATION; |
b348deae | 1375 | } |
25082d1e | 1376 | } else { |
4c8683c8 AT |
1377 | int rc; |
1378 | ||
cc248aae | 1379 | con->os->nextArg = _free(con->os->nextArg); |
62402cb1 | 1380 | if (longArg) { |
cc248aae | 1381 | longArg = expandNextArg(con, longArg); |
4c8683c8 | 1382 | con->os->nextArg = (char *) longArg; |
62402cb1 | 1383 | } else if (con->os->nextCharArg) { |
4c8683c8 AT |
1384 | longArg = expandNextArg(con, con->os->nextCharArg + (int)(*con->os->nextCharArg == '=')); |
1385 | con->os->nextArg = (char *) longArg; | |
62402cb1 | 1386 | con->os->nextCharArg = NULL; |
b348deae MP |
1387 | } else { |
1388 | while (con->os->next == con->os->argc && | |
4c8683c8 AT |
1389 | con->os > con->optionStack) |
1390 | { | |
b348deae MP |
1391 | cleanOSE(con->os--); |
1392 | } | |
cc248aae | 1393 | if (con->os->next == con->os->argc) { |
4c8683c8 | 1394 | if (!F_ISSET(opt, OPTIONAL)) |
cc248aae | 1395 | return POPT_ERROR_NOARG; |
cc248aae WD |
1396 | con->os->nextArg = NULL; |
1397 | } else { | |
1398 | ||
1399 | /* | |
1400 | * Make sure this isn't part of a short arg or the | |
1401 | * result of an alias expansion. | |
1402 | */ | |
4c8683c8 AT |
1403 | if (con->os == con->optionStack |
1404 | && F_ISSET(opt, STRIP) && canstrip) | |
1405 | { | |
cc248aae WD |
1406 | poptStripArg(con, con->os->next); |
1407 | } | |
b348deae | 1408 | |
cc248aae | 1409 | if (con->os->argv != NULL) { /* XXX can't happen */ |
4c8683c8 AT |
1410 | if (F_ISSET(opt, OPTIONAL) && |
1411 | con->os->argv[con->os->next][0] == '-') { | |
1412 | con->os->nextArg = NULL; | |
1413 | } else { | |
1414 | /* XXX watchout: subtle side-effects live here. */ | |
1415 | longArg = con->os->argv[con->os->next++]; | |
1416 | longArg = expandNextArg(con, longArg); | |
1417 | con->os->nextArg = (char *) longArg; | |
1418 | } | |
cc248aae WD |
1419 | } |
1420 | } | |
62402cb1 | 1421 | } |
cc248aae | 1422 | longArg = NULL; |
62402cb1 | 1423 | |
4c8683c8 AT |
1424 | /* Save the option argument through a (*opt->arg) pointer. */ |
1425 | if (opt->arg != NULL && (rc = poptSaveArg(con, opt)) != 0) | |
1426 | return rc; | |
62402cb1 MP |
1427 | } |
1428 | ||
4c8683c8 | 1429 | if (cb) |
cc248aae | 1430 | invokeCallbacksOPTION(con, con->options, opt, cbData, shorty); |
4c8683c8 | 1431 | else if (opt->val && (poptArgType(opt) != POPT_ARG_VAL)) |
62402cb1 MP |
1432 | done = 1; |
1433 | ||
1434 | if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) { | |
1435 | con->finalArgvAlloced += 10; | |
1436 | con->finalArgv = realloc(con->finalArgv, | |
1437 | sizeof(*con->finalArgv) * con->finalArgvAlloced); | |
1438 | } | |
1439 | ||
cc248aae | 1440 | if (con->finalArgv != NULL) |
4c8683c8 | 1441 | { char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + sizeof("--")); |
cc248aae | 1442 | if (s != NULL) { /* XXX can't happen */ |
cc248aae | 1443 | con->finalArgv[con->finalArgvCount++] = s; |
4c8683c8 AT |
1444 | *s++ = '-'; |
1445 | if (opt->longName) { | |
1446 | if (!F_ISSET(opt, ONEDASH)) | |
1447 | *s++ = '-'; | |
1448 | s = stpcpy(s, opt->longName); | |
1449 | } else { | |
1450 | *s++ = opt->shortName; | |
1451 | *s = '\0'; | |
1452 | } | |
cc248aae WD |
1453 | } else |
1454 | con->finalArgv[con->finalArgvCount++] = NULL; | |
b348deae | 1455 | } |
62402cb1 | 1456 | |
4c8683c8 AT |
1457 | if (opt->arg && poptArgType(opt) == POPT_ARG_NONE) |
1458 | ; | |
1459 | else if (poptArgType(opt) == POPT_ARG_VAL) | |
1460 | ; | |
1461 | else if (poptArgType(opt) != POPT_ARG_NONE) { | |
1462 | if (con->finalArgv != NULL && con->os->nextArg != NULL) | |
cc248aae | 1463 | con->finalArgv[con->finalArgvCount++] = |
cc248aae | 1464 | xstrdup(con->os->nextArg); |
b348deae | 1465 | } |
62402cb1 MP |
1466 | } |
1467 | ||
cc248aae | 1468 | return (opt ? opt->val : -1); /* XXX can't happen */ |
62402cb1 MP |
1469 | } |
1470 | ||
4c8683c8 | 1471 | char * poptGetOptArg(poptContext con) |
cc248aae | 1472 | { |
4c8683c8 | 1473 | char * ret = NULL; |
cc248aae WD |
1474 | if (con) { |
1475 | ret = con->os->nextArg; | |
1476 | con->os->nextArg = NULL; | |
1477 | } | |
62402cb1 MP |
1478 | return ret; |
1479 | } | |
1480 | ||
cc248aae WD |
1481 | const char * poptGetArg(poptContext con) |
1482 | { | |
1483 | const char * ret = NULL; | |
1484 | if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers) | |
1485 | ret = con->leftovers[con->nextLeftover++]; | |
1486 | return ret; | |
62402cb1 MP |
1487 | } |
1488 | ||
cc248aae WD |
1489 | const char * poptPeekArg(poptContext con) |
1490 | { | |
1491 | const char * ret = NULL; | |
1492 | if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers) | |
1493 | ret = con->leftovers[con->nextLeftover]; | |
1494 | return ret; | |
62402cb1 MP |
1495 | } |
1496 | ||
cc248aae WD |
1497 | const char ** poptGetArgs(poptContext con) |
1498 | { | |
1499 | if (con == NULL || | |
1500 | con->leftovers == NULL || con->numLeftovers == con->nextLeftover) | |
1501 | return NULL; | |
62402cb1 MP |
1502 | |
1503 | /* some apps like [like RPM ;-) ] need this NULL terminated */ | |
1504 | con->leftovers[con->numLeftovers] = NULL; | |
1505 | ||
1506 | return (con->leftovers + con->nextLeftover); | |
1507 | } | |
4c8683c8 AT |
1508 | |
1509 | static | |
1510 | poptItem poptFreeItems(poptItem items, int nitems) | |
1511 | { | |
1512 | if (items != NULL) { | |
1513 | poptItem item = items; | |
1514 | while (--nitems >= 0) { | |
1515 | item->option.longName = _free(item->option.longName); | |
1516 | item->option.descrip = _free(item->option.descrip); | |
1517 | item->option.argDescrip = _free(item->option.argDescrip); | |
1518 | item->argv = _free(item->argv); | |
1519 | item++; | |
1520 | } | |
1521 | _free(items); | |
1522 | } | |
1523 | return NULL; | |
1524 | } | |
62402cb1 | 1525 | |
cc248aae WD |
1526 | poptContext poptFreeContext(poptContext con) |
1527 | { | |
62402cb1 MP |
1528 | int i; |
1529 | ||
cc248aae | 1530 | if (con == NULL) return con; |
b348deae | 1531 | poptResetContext(con); |
b348deae | 1532 | |
4c8683c8 AT |
1533 | con->aliases = poptFreeItems(con->aliases, con->numAliases); |
1534 | con->numAliases = 0; | |
62402cb1 | 1535 | |
4c8683c8 AT |
1536 | con->execs = poptFreeItems(con->execs, con->numExecs); |
1537 | con->numExecs = 0; | |
cc248aae | 1538 | |
4c8683c8 AT |
1539 | for (i = 0; i < con->numLeftovers; i++) { |
1540 | con->leftovers[i] = _free(con->leftovers[i]); | |
1541 | } | |
cc248aae | 1542 | con->leftovers = _free(con->leftovers); |
4c8683c8 | 1543 | |
cc248aae WD |
1544 | con->finalArgv = _free(con->finalArgv); |
1545 | con->appName = _free(con->appName); | |
1546 | con->otherHelp = _free(con->otherHelp); | |
1547 | con->execPath = _free(con->execPath); | |
1548 | con->arg_strip = PBM_FREE(con->arg_strip); | |
b348deae | 1549 | |
cc248aae WD |
1550 | con = _free(con); |
1551 | return con; | |
62402cb1 MP |
1552 | } |
1553 | ||
cc248aae | 1554 | int poptAddAlias(poptContext con, struct poptAlias alias, |
4c8683c8 | 1555 | UNUSED(int flags)) |
b348deae | 1556 | { |
4c8683c8 AT |
1557 | struct poptItem_s item_buf; |
1558 | poptItem item = &item_buf; | |
cc248aae WD |
1559 | memset(item, 0, sizeof(*item)); |
1560 | item->option.longName = alias.longName; | |
1561 | item->option.shortName = alias.shortName; | |
1562 | item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN; | |
1563 | item->option.arg = 0; | |
1564 | item->option.val = 0; | |
1565 | item->option.descrip = NULL; | |
1566 | item->option.argDescrip = NULL; | |
1567 | item->argc = alias.argc; | |
1568 | item->argv = alias.argv; | |
1569 | return poptAddItem(con, item, 0); | |
1570 | } | |
62402cb1 | 1571 | |
cc248aae WD |
1572 | int poptAddItem(poptContext con, poptItem newItem, int flags) |
1573 | { | |
4c8683c8 | 1574 | poptItem * items, item_tmp, item; |
cc248aae WD |
1575 | int * nitems; |
1576 | ||
1577 | switch (flags) { | |
1578 | case 1: | |
1579 | items = &con->execs; | |
1580 | nitems = &con->numExecs; | |
1581 | break; | |
1582 | case 0: | |
1583 | items = &con->aliases; | |
1584 | nitems = &con->numAliases; | |
1585 | break; | |
1586 | default: | |
1587 | return 1; | |
4c8683c8 | 1588 | break; |
cc248aae WD |
1589 | } |
1590 | ||
4c8683c8 AT |
1591 | item_tmp = realloc((*items), ((*nitems) + 1) * sizeof(**items)); |
1592 | if (item_tmp == NULL) | |
cc248aae | 1593 | return 1; |
4c8683c8 | 1594 | *items = item_tmp; |
cc248aae WD |
1595 | |
1596 | item = (*items) + (*nitems); | |
b348deae | 1597 | |
cc248aae WD |
1598 | item->option.longName = |
1599 | (newItem->option.longName ? xstrdup(newItem->option.longName) : NULL); | |
1600 | item->option.shortName = newItem->option.shortName; | |
1601 | item->option.argInfo = newItem->option.argInfo; | |
1602 | item->option.arg = newItem->option.arg; | |
1603 | item->option.val = newItem->option.val; | |
1604 | item->option.descrip = | |
1605 | (newItem->option.descrip ? xstrdup(newItem->option.descrip) : NULL); | |
1606 | item->option.argDescrip = | |
1607 | (newItem->option.argDescrip ? xstrdup(newItem->option.argDescrip) : NULL); | |
1608 | item->argc = newItem->argc; | |
1609 | item->argv = newItem->argv; | |
1610 | ||
1611 | (*nitems)++; | |
62402cb1 MP |
1612 | |
1613 | return 0; | |
1614 | } | |
1615 | ||
4c8683c8 | 1616 | const char * poptBadOption(poptContext con, unsigned int flags) |
cc248aae WD |
1617 | { |
1618 | struct optionStackEntry * os = NULL; | |
4c8683c8 AT |
1619 | const char *badOpt = NULL; |
1620 | ||
1621 | if (con != NULL) { | |
1622 | /* Stupid hack to return something semi-meaningful from exec failure */ | |
1623 | if (con->execFail) { | |
1624 | badOpt = con->execFail; | |
1625 | } else { | |
1626 | os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os; | |
1627 | badOpt = os->argv[os->next - 1]; | |
1628 | } | |
1629 | } | |
62402cb1 | 1630 | |
4c8683c8 | 1631 | return badOpt; |
62402cb1 MP |
1632 | } |
1633 | ||
4fd4b3d6 | 1634 | const char * poptStrerror(const int error) |
cc248aae | 1635 | { |
62402cb1 MP |
1636 | switch (error) { |
1637 | case POPT_ERROR_NOARG: | |
1638 | return POPT_("missing argument"); | |
25082d1e WD |
1639 | case POPT_ERROR_UNWANTEDARG: |
1640 | return POPT_("option does not take an argument"); | |
62402cb1 MP |
1641 | case POPT_ERROR_BADOPT: |
1642 | return POPT_("unknown option"); | |
cc248aae WD |
1643 | case POPT_ERROR_BADOPERATION: |
1644 | return POPT_("mutually exclusive logical operations requested"); | |
1645 | case POPT_ERROR_NULLARG: | |
1646 | return POPT_("opt->arg should not be NULL"); | |
62402cb1 MP |
1647 | case POPT_ERROR_OPTSTOODEEP: |
1648 | return POPT_("aliases nested too deeply"); | |
1649 | case POPT_ERROR_BADQUOTE: | |
cc248aae | 1650 | return POPT_("error in parameter quoting"); |
62402cb1 MP |
1651 | case POPT_ERROR_BADNUMBER: |
1652 | return POPT_("invalid numeric value"); | |
1653 | case POPT_ERROR_OVERFLOW: | |
1654 | return POPT_("number too large or too small"); | |
cc248aae WD |
1655 | case POPT_ERROR_MALLOC: |
1656 | return POPT_("memory allocation failed"); | |
4c8683c8 AT |
1657 | case POPT_ERROR_BADCONFIG: |
1658 | return POPT_("config file failed sanity test"); | |
62402cb1 MP |
1659 | case POPT_ERROR_ERRNO: |
1660 | return strerror(errno); | |
1661 | default: | |
1662 | return POPT_("unknown error"); | |
1663 | } | |
1664 | } | |
1665 | ||
cc248aae WD |
1666 | int poptStuffArgs(poptContext con, const char ** argv) |
1667 | { | |
b348deae | 1668 | int argc; |
cc248aae | 1669 | int rc; |
62402cb1 MP |
1670 | |
1671 | if ((con->os - con->optionStack) == POPT_OPTION_DEPTH) | |
1672 | return POPT_ERROR_OPTSTOODEEP; | |
1673 | ||
b348deae | 1674 | for (argc = 0; argv[argc]; argc++) |
cc248aae | 1675 | {}; |
62402cb1 MP |
1676 | |
1677 | con->os++; | |
1678 | con->os->next = 0; | |
b348deae MP |
1679 | con->os->nextArg = NULL; |
1680 | con->os->nextCharArg = NULL; | |
62402cb1 | 1681 | con->os->currAlias = NULL; |
cc248aae | 1682 | rc = poptDupArgv(argc, argv, &con->os->argc, &con->os->argv); |
b348deae | 1683 | con->os->argb = NULL; |
62402cb1 MP |
1684 | con->os->stuffed = 1; |
1685 | ||
cc248aae | 1686 | return rc; |
62402cb1 MP |
1687 | } |
1688 | ||
cc248aae WD |
1689 | const char * poptGetInvocationName(poptContext con) |
1690 | { | |
1691 | return (con->os->argv ? con->os->argv[0] : ""); | |
62402cb1 | 1692 | } |
b348deae | 1693 | |
cc248aae | 1694 | int poptStrippedArgv(poptContext con, int argc, char ** argv) |
b348deae | 1695 | { |
cc248aae WD |
1696 | int numargs = argc; |
1697 | int j = 1; | |
1698 | int i; | |
b348deae | 1699 | |
cc248aae WD |
1700 | if (con->arg_strip) |
1701 | for (i = 1; i < argc; i++) { | |
1702 | if (PBM_ISSET(i, con->arg_strip)) | |
b348deae | 1703 | numargs--; |
b348deae MP |
1704 | } |
1705 | ||
cc248aae WD |
1706 | for (i = 1; i < argc; i++) { |
1707 | if (con->arg_strip && PBM_ISSET(i, con->arg_strip)) | |
b348deae | 1708 | continue; |
cc248aae WD |
1709 | argv[j] = (j < numargs) ? argv[i] : NULL; |
1710 | j++; | |
b348deae MP |
1711 | } |
1712 | ||
cc248aae | 1713 | return numargs; |
b348deae | 1714 | } |