Upgrade from popt 1.2 to a cut-down 1.5
[rsync/rsync.git] / popt / popt.c
CommitLineData
62402cb1 1/* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
b348deae 2 file accompanying popt source distributions, available from
62402cb1
MP
3 ftp://ftp.redhat.com/pub/code/popt */
4
b348deae 5#include "system.h"
62402cb1 6#include "findme.h"
62402cb1
MP
7#include "poptint.h"
8
9#ifndef HAVE_STRERROR
10static char * strerror(int errno) {
11 extern int sys_nerr;
12 extern char * sys_errlist[];
13
14 if ((0 <= errno) && (errno < sys_nerr))
15 return sys_errlist[errno];
16 else
17 return POPT_("unknown errno");
18}
19#endif
20
21void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) {
b348deae
MP
22 if (con->execPath) xfree(con->execPath);
23 con->execPath = xstrdup(path);
62402cb1
MP
24 con->execAbsolute = allowAbsolute;
25}
26
27static void invokeCallbacks(poptContext con, const struct poptOption * table,
28 int post) {
29 const struct poptOption * opt = table;
30 poptCallbackType cb;
b348deae 31
62402cb1
MP
32 while (opt->longName || opt->shortName || opt->arg) {
33 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
34 invokeCallbacks(con, opt->arg, post);
35 } else if (((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) &&
36 ((!post && (opt->argInfo & POPT_CBFLAG_PRE)) ||
37 ( post && (opt->argInfo & POPT_CBFLAG_POST)))) {
b348deae 38 cb = (poptCallbackType)opt->arg;
62402cb1
MP
39 cb(con, post ? POPT_CALLBACK_REASON_POST : POPT_CALLBACK_REASON_PRE,
40 NULL, NULL, opt->descrip);
41 }
42 opt++;
43 }
44}
45
b348deae 46poptContext poptGetContext(const char * name, int argc, const char ** argv,
62402cb1
MP
47 const struct poptOption * options, int flags) {
48 poptContext con = malloc(sizeof(*con));
49
50 memset(con, 0, sizeof(*con));
51
52 con->os = con->optionStack;
53 con->os->argc = argc;
54 con->os->argv = argv;
b348deae 55 con->os->argb = NULL;
62402cb1
MP
56
57 if (!(flags & POPT_CONTEXT_KEEP_FIRST))
58 con->os->next = 1; /* skip argv[0] */
59
b348deae 60 con->leftovers = calloc( (argc + 1), sizeof(char *) );
62402cb1 61 con->options = options;
b348deae
MP
62 con->aliases = NULL;
63 con->numAliases = 0;
62402cb1 64 con->flags = flags;
b348deae
MP
65 con->execs = NULL;
66 con->numExecs = 0;
67 con->finalArgvAlloced = argc * 2;
68 con->finalArgv = calloc( con->finalArgvAlloced, sizeof(*con->finalArgv) );
62402cb1 69 con->execAbsolute = 1;
b348deae 70 con->arg_strip = NULL;
62402cb1
MP
71
72 if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
73 con->flags |= POPT_CONTEXT_POSIXMEHARDER;
b348deae 74
62402cb1
MP
75 if (name)
76 con->appName = strcpy(malloc(strlen(name) + 1), name);
77
78 invokeCallbacks(con, con->options, 0);
79
80 return con;
81}
82
b348deae
MP
83static void cleanOSE(struct optionStackEntry *os)
84{
85 if (os->nextArg) {
86 xfree(os->nextArg);
87 os->nextArg = NULL;
88 }
89 if (os->argv) {
90 xfree(os->argv);
91 os->argv = NULL;
92 }
93 if (os->argb) {
94 PBM_FREE(os->argb);
95 os->argb = NULL;
96 }
97}
98
62402cb1 99void poptResetContext(poptContext con) {
b348deae
MP
100 int i;
101
102 while (con->os > con->optionStack) {
103 cleanOSE(con->os--);
104 }
105 if (con->os->argb) {
106 PBM_FREE(con->os->argb);
107 con->os->argb = NULL;
108 }
62402cb1
MP
109 con->os->currAlias = NULL;
110 con->os->nextCharArg = NULL;
111 con->os->nextArg = NULL;
112 con->os->next = 1; /* skip argv[0] */
113
114 con->numLeftovers = 0;
115 con->nextLeftover = 0;
116 con->restLeftover = 0;
117 con->doExec = NULL;
b348deae
MP
118
119 for (i = 0; i < con->finalArgvCount; i++) {
120 if (con->finalArgv[i]) {
121 xfree(con->finalArgv[i]);
122 con->finalArgv[i] = NULL;
123 }
124 }
125
62402cb1 126 con->finalArgvCount = 0;
b348deae
MP
127
128 if (con->arg_strip) {
129 PBM_FREE(con->arg_strip);
130 con->arg_strip = NULL;
131 }
62402cb1
MP
132}
133
134/* Only one of longName, shortName may be set at a time */
135static int handleExec(poptContext con, char * longName, char shortName) {
136 int i;
137
138 i = con->numExecs - 1;
139 if (longName) {
140 while (i >= 0 && (!con->execs[i].longName ||
141 strcmp(con->execs[i].longName, longName))) i--;
142 } else {
143 while (i >= 0 &&
144 con->execs[i].shortName != shortName) i--;
145 }
146
147 if (i < 0) return 0;
148
149 if (con->flags & POPT_CONTEXT_NO_EXEC)
150 return 1;
151
b348deae 152 if (con->doExec == NULL) {
62402cb1
MP
153 con->doExec = con->execs + i;
154 return 1;
155 }
156
157 /* We already have an exec to do; remember this option for next
158 time 'round */
159 if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) {
160 con->finalArgvAlloced += 10;
161 con->finalArgv = realloc(con->finalArgv,
162 sizeof(*con->finalArgv) * con->finalArgvAlloced);
163 }
164
165 i = con->finalArgvCount++;
b348deae
MP
166 { char *s = malloc((longName ? strlen(longName) : 0) + 3);
167 if (longName)
168 sprintf(s, "--%s", longName);
169 else
170 sprintf(s, "-%c", shortName);
171 con->finalArgv[i] = s;
172 }
62402cb1
MP
173
174 return 1;
175}
176
177/* Only one of longName, shortName may be set at a time */
b348deae
MP
178static int handleAlias(poptContext con, const char * longName, char shortName,
179 /*@keep@*/ const char * nextCharArg) {
62402cb1
MP
180 int i;
181
182 if (con->os->currAlias && con->os->currAlias->longName && longName &&
b348deae 183 !strcmp(con->os->currAlias->longName, longName))
62402cb1 184 return 0;
b348deae
MP
185 if (con->os->currAlias && shortName &&
186 shortName == con->os->currAlias->shortName)
62402cb1
MP
187 return 0;
188
189 i = con->numAliases - 1;
190 if (longName) {
191 while (i >= 0 && (!con->aliases[i].longName ||
192 strcmp(con->aliases[i].longName, longName))) i--;
193 } else {
194 while (i >= 0 &&
195 con->aliases[i].shortName != shortName) i--;
196 }
197
198 if (i < 0) return 0;
199
b348deae 200 if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
62402cb1
MP
201 return POPT_ERROR_OPTSTOODEEP;
202
203 if (nextCharArg && *nextCharArg)
204 con->os->nextCharArg = nextCharArg;
205
206 con->os++;
207 con->os->next = 0;
208 con->os->stuffed = 0;
b348deae
MP
209 con->os->nextArg = NULL;
210 con->os->nextCharArg = NULL;
62402cb1 211 con->os->currAlias = con->aliases + i;
b348deae
MP
212 poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv,
213 &con->os->argc, &con->os->argv);
214 con->os->argb = NULL;
62402cb1
MP
215
216 return 1;
217}
218
219static void execCommand(poptContext con) {
b348deae 220 const char ** argv;
62402cb1 221 int pos = 0;
b348deae 222 const char * script = con->doExec->script;
62402cb1 223
b348deae 224 argv = malloc(sizeof(*argv) *
62402cb1
MP
225 (6 + con->numLeftovers + con->finalArgvCount));
226
227 if (!con->execAbsolute && strchr(script, '/')) return;
228
229 if (!strchr(script, '/') && con->execPath) {
b348deae
MP
230 char *s = alloca(strlen(con->execPath) + strlen(script) + 2);
231 sprintf(s, "%s/%s", con->execPath, script);
232 argv[pos] = s;
62402cb1
MP
233 } else {
234 argv[pos] = script;
235 }
236 pos++;
237
238 argv[pos] = findProgramPath(con->os->argv[0]);
239 if (argv[pos]) pos++;
240 argv[pos++] = ";";
241
242 memcpy(argv + pos, con->finalArgv, sizeof(*argv) * con->finalArgvCount);
243 pos += con->finalArgvCount;
244
245 if (con->numLeftovers) {
246 argv[pos++] = "--";
247 memcpy(argv + pos, con->leftovers, sizeof(*argv) * con->numLeftovers);
248 pos += con->numLeftovers;
249 }
250
251 argv[pos++] = NULL;
252
253#ifdef __hpux
254 setresuid(getuid(), getuid(),-1);
255#else
b348deae
MP
256/*
257 * XXX " ... on BSD systems setuid() should be preferred over setreuid()"
258 * XXX sez' Timur Bakeyev <mc@bat.ru>
259 * XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
260 */
261#if defined(HAVE_SETUID)
262 setuid(getuid());
263#elif defined (HAVE_SETREUID)
62402cb1 264 setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
b348deae
MP
265#else
266 ; /* Can't drop privileges */
267#endif
62402cb1
MP
268#endif
269
b348deae 270 execvp(argv[0], (char *const *)argv);
62402cb1
MP
271}
272
b348deae
MP
273/*@observer@*/ static const struct poptOption *
274findOption(const struct poptOption * table, const char * longName,
275 char shortName,
276 /*@out@*/ poptCallbackType * callback, /*@out@*/ const void ** callbackData,
277 int singleDash)
278{
62402cb1
MP
279 const struct poptOption * opt = table;
280 const struct poptOption * opt2;
281 const struct poptOption * cb = NULL;
282
b348deae
MP
283 /* This happens when a single - is given */
284 if (singleDash && !shortName && !*longName)
285 shortName = '-';
286
62402cb1
MP
287 while (opt->longName || opt->shortName || opt->arg) {
288 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
b348deae 289 opt2 = findOption(opt->arg, longName, shortName, callback,
62402cb1
MP
290 callbackData, singleDash);
291 if (opt2) {
292 if (*callback && !*callbackData)
293 *callbackData = opt->descrip;
294 return opt2;
295 }
296 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) {
297 cb = opt;
b348deae 298 } else if (longName && opt->longName &&
62402cb1
MP
299 (!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) &&
300 !strcmp(longName, opt->longName)) {
301 break;
302 } else if (shortName && shortName == opt->shortName) {
303 break;
304 }
305 opt++;
306 }
307
308 if (!opt->longName && !opt->shortName) return NULL;
309 *callbackData = NULL;
310 *callback = NULL;
311 if (cb) {
b348deae 312 *callback = (poptCallbackType)cb->arg;
62402cb1
MP
313 if (!(cb->argInfo & POPT_CBFLAG_INC_DATA))
314 *callbackData = cb->descrip;
315 }
316
317 return opt;
318}
319
b348deae
MP
320static const char *findNextArg(poptContext con, unsigned argx, int delete)
321{
322 struct optionStackEntry * os = con->os;
323 const char * arg;
324
325 do {
326 int i;
327 arg = NULL;
328 while (os->next == os->argc && os > con->optionStack) os--;
329 if (os->next == os->argc && os == con->optionStack) break;
330 for (i = os->next; i < os->argc; i++) {
331 if (os->argb && PBM_ISSET(i, os->argb)) continue;
332 if (*os->argv[i] == '-') continue;
333 if (--argx > 0) continue;
334 arg = os->argv[i];
335 if (delete) {
336 if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc);
337 PBM_SET(i, os->argb);
338 }
339 break;
340 }
341 if (os > con->optionStack) os--;
342 } while (arg == NULL);
343 return arg;
344}
345
346static /*@only@*/ const char * expandNextArg(poptContext con, const char * s)
347{
348 const char *a;
349 size_t alen;
350 char *t, *te;
351 size_t tn = strlen(s) + 1;
352 char c;
353
354 te = t = malloc(tn);;
355 while ((c = *s++) != '\0') {
356 switch (c) {
357#if 0 /* XXX can't do this */
358 case '\\': /* escape */
359 c = *s++;
360 break;
361#endif
362 case '!':
363 if (!(s[0] == '#' && s[1] == ':' && s[2] == '+'))
364 break;
365 if ((a = findNextArg(con, 1, 1)) == NULL)
366 break;
367 s += 3;
368
369 alen = strlen(a);
370 tn += alen;
371 *te = '\0';
372 t = realloc(t, tn);
373 te = t + strlen(t);
374 strncpy(te, a, alen); te += alen;
375 continue;
376 /*@notreached@*/ break;
377 default:
378 break;
379 }
380 *te++ = c;
381 }
382 *te = '\0';
383 t = realloc(t, strlen(t)+1); /* XXX memory leak, hard to plug */
384 return t;
385}
386
387static void poptStripArg(poptContext con, int which)
388{
389 if(con->arg_strip == NULL) {
390 con->arg_strip = PBM_ALLOC(con->optionStack[0].argc);
391 }
392 PBM_SET(which, con->arg_strip);
393}
394
62402cb1 395/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
b348deae
MP
396int poptGetNextOpt(poptContext con)
397{
62402cb1
MP
398 const struct poptOption * opt = NULL;
399 int done = 0;
62402cb1
MP
400
401 while (!done) {
b348deae
MP
402 const char * origOptString = NULL;
403 poptCallbackType cb = NULL;
404 const void * cbData = NULL;
405 const char * longArg = NULL;
406 int canstrip = 0;
407
408 while (!con->os->nextCharArg && con->os->next == con->os->argc
409 && con->os > con->optionStack) {
410 cleanOSE(con->os--);
411 }
62402cb1
MP
412 if (!con->os->nextCharArg && con->os->next == con->os->argc) {
413 invokeCallbacks(con, con->options, 1);
414 if (con->doExec) execCommand(con);
415 return -1;
416 }
417
b348deae 418 /* Process next long option */
62402cb1 419 if (!con->os->nextCharArg) {
b348deae
MP
420 char * localOptString, * optString;
421 int thisopt;
422
423 if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) {
424 con->os->next++;
425 continue;
426 }
427 thisopt=con->os->next;
62402cb1
MP
428 origOptString = con->os->argv[con->os->next++];
429
430 if (con->restLeftover || *origOptString != '-') {
431 con->leftovers[con->numLeftovers++] = origOptString;
432 if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
433 con->restLeftover = 1;
434 continue;
435 }
436
437 /* Make a copy we can hack at */
b348deae
MP
438 localOptString = optString =
439 strcpy(alloca(strlen(origOptString) + 1),
62402cb1
MP
440 origOptString);
441
442 if (!optString[0])
443 return POPT_ERROR_BADOPT;
444
445 if (optString[1] == '-' && !optString[2]) {
446 con->restLeftover = 1;
447 continue;
448 } else {
b348deae
MP
449 char *oe;
450 int singleDash;
451
62402cb1
MP
452 optString++;
453 if (*optString == '-')
454 singleDash = 0, optString++;
455 else
456 singleDash = 1;
457
b348deae 458 /* XXX aliases with arg substitution need "--alias=arg" */
62402cb1
MP
459 if (handleAlias(con, optString, '\0', NULL))
460 continue;
461 if (handleExec(con, optString, '\0'))
462 continue;
463
b348deae
MP
464 /* Check for "--long=arg" option. */
465 for (oe = optString; *oe && *oe != '='; oe++)
466 ;
467 if (*oe == '=') {
468 *oe++ = '\0';
469 /* XXX longArg is mapped back to persistent storage. */
470 longArg = origOptString + (oe - localOptString);
62402cb1
MP
471 }
472
473 opt = findOption(con->options, optString, '\0', &cb, &cbData,
474 singleDash);
b348deae
MP
475 if (!opt && !singleDash)
476 return POPT_ERROR_BADOPT;
62402cb1
MP
477 }
478
b348deae 479 if (!opt) {
62402cb1 480 con->os->nextCharArg = origOptString + 1;
b348deae
MP
481 } else {
482 if(con->os == con->optionStack &&
483 opt->argInfo & POPT_ARGFLAG_STRIP) {
484 canstrip = 1;
485 poptStripArg(con, thisopt);
486 }
487 }
62402cb1
MP
488 }
489
b348deae 490 /* Process next short option */
62402cb1
MP
491 if (con->os->nextCharArg) {
492 origOptString = con->os->nextCharArg;
493
494 con->os->nextCharArg = NULL;
495
496 if (handleAlias(con, NULL, *origOptString,
497 origOptString + 1)) {
498 origOptString++;
499 continue;
500 }
501 if (handleExec(con, NULL, *origOptString))
502 continue;
503
b348deae 504 opt = findOption(con->options, NULL, *origOptString, &cb,
62402cb1 505 &cbData, 0);
b348deae
MP
506 if (!opt)
507 return POPT_ERROR_BADOPT;
62402cb1
MP
508
509 origOptString++;
510 if (*origOptString)
511 con->os->nextCharArg = origOptString;
512 }
513
b348deae 514 if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
62402cb1 515 *((int *)opt->arg) = 1;
b348deae
MP
516 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
517 if (opt->arg)
518 *((int *) opt->arg) = opt->val;
519 } else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
520 if (con->os->nextArg) {
521 xfree(con->os->nextArg);
522 con->os->nextArg = NULL;
523 }
62402cb1 524 if (longArg) {
b348deae 525 con->os->nextArg = expandNextArg(con, longArg);
62402cb1 526 } else if (con->os->nextCharArg) {
b348deae 527 con->os->nextArg = expandNextArg(con, con->os->nextCharArg);
62402cb1 528 con->os->nextCharArg = NULL;
b348deae
MP
529 } else {
530 while (con->os->next == con->os->argc &&
531 con->os > con->optionStack) {
532 cleanOSE(con->os--);
533 }
62402cb1
MP
534 if (con->os->next == con->os->argc)
535 return POPT_ERROR_NOARG;
536
b348deae
MP
537 /* make sure this isn't part of a short arg or the
538 result of an alias expansion */
539 if(con->os == con->optionStack &&
540 opt->argInfo & POPT_ARGFLAG_STRIP &&
541 canstrip) {
542 poptStripArg(con, con->os->next);
543 }
544
545 con->os->nextArg = expandNextArg(con, con->os->argv[con->os->next++]);
62402cb1
MP
546 }
547
548 if (opt->arg) {
b348deae
MP
549 long aLong;
550 char *end;
551
62402cb1
MP
552 switch (opt->argInfo & POPT_ARG_MASK) {
553 case POPT_ARG_STRING:
b348deae
MP
554 /* XXX memory leak, hard to plug */
555 *((const char **) opt->arg) = xstrdup(con->os->nextArg);
62402cb1
MP
556 break;
557
558 case POPT_ARG_INT:
559 case POPT_ARG_LONG:
560 aLong = strtol(con->os->nextArg, &end, 0);
b348deae 561 if (!(end && *end == '\0'))
62402cb1
MP
562 return POPT_ERROR_BADNUMBER;
563
564 if (aLong == LONG_MIN || aLong == LONG_MAX)
565 return POPT_ERROR_OVERFLOW;
566 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
567 *((long *) opt->arg) = aLong;
568 } else {
569 if (aLong > INT_MAX || aLong < INT_MIN)
570 return POPT_ERROR_OVERFLOW;
b348deae 571 *((int *) opt->arg) = aLong;
62402cb1
MP
572 }
573 break;
574
575 default:
576 fprintf(stdout, POPT_("option type (%d) not implemented in popt\n"),
577 opt->argInfo & POPT_ARG_MASK);
b348deae 578 exit(EXIT_FAILURE);
62402cb1
MP
579 }
580 }
581 }
582
583 if (cb)
584 cb(con, POPT_CALLBACK_REASON_OPTION, opt, con->os->nextArg, cbData);
b348deae 585 else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
62402cb1
MP
586 done = 1;
587
588 if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
589 con->finalArgvAlloced += 10;
590 con->finalArgv = realloc(con->finalArgv,
591 sizeof(*con->finalArgv) * con->finalArgvAlloced);
592 }
593
b348deae
MP
594 { char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + 3);
595 if (opt->longName)
596 sprintf(s, "--%s", opt->longName);
597 else
598 sprintf(s, "-%c", opt->shortName);
599 con->finalArgv[con->finalArgvCount++] = s;
600 }
62402cb1 601
b348deae
MP
602 if (opt->arg && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE
603 && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL) {
604 con->finalArgv[con->finalArgvCount++] = xstrdup(con->os->nextArg);
605 }
62402cb1
MP
606 }
607
608 return opt->val;
609}
610
b348deae
MP
611const char * poptGetOptArg(poptContext con) {
612 const char * ret = con->os->nextArg;
62402cb1
MP
613 con->os->nextArg = NULL;
614 return ret;
615}
616
b348deae 617const char * poptGetArg(poptContext con) {
62402cb1 618 if (con->numLeftovers == con->nextLeftover) return NULL;
b348deae 619 return con->leftovers[con->nextLeftover++];
62402cb1
MP
620}
621
b348deae 622const char * poptPeekArg(poptContext con) {
62402cb1 623 if (con->numLeftovers == con->nextLeftover) return NULL;
b348deae 624 return con->leftovers[con->nextLeftover];
62402cb1
MP
625}
626
b348deae 627const char ** poptGetArgs(poptContext con) {
62402cb1
MP
628 if (con->numLeftovers == con->nextLeftover) return NULL;
629
630 /* some apps like [like RPM ;-) ] need this NULL terminated */
631 con->leftovers[con->numLeftovers] = NULL;
632
633 return (con->leftovers + con->nextLeftover);
634}
635
636void poptFreeContext(poptContext con) {
637 int i;
638
b348deae
MP
639 poptResetContext(con);
640 if (con->os->argb) free(con->os->argb);
641
62402cb1 642 for (i = 0; i < con->numAliases; i++) {
b348deae 643 if (con->aliases[i].longName) xfree(con->aliases[i].longName);
62402cb1
MP
644 free(con->aliases[i].argv);
645 }
646
647 for (i = 0; i < con->numExecs; i++) {
b348deae
MP
648 if (con->execs[i].longName) xfree(con->execs[i].longName);
649 xfree(con->execs[i].script);
62402cb1 650 }
b348deae 651 if (con->execs) xfree(con->execs);
62402cb1
MP
652
653 free(con->leftovers);
654 free(con->finalArgv);
b348deae 655 if (con->appName) xfree(con->appName);
62402cb1 656 if (con->aliases) free(con->aliases);
b348deae
MP
657 if (con->otherHelp) xfree(con->otherHelp);
658 if (con->execPath) xfree(con->execPath);
659 if (con->arg_strip) PBM_FREE(con->arg_strip);
660
62402cb1
MP
661 free(con);
662}
663
b348deae
MP
664int poptAddAlias(poptContext con, struct poptAlias newAlias,
665 /*@unused@*/ int flags)
666{
62402cb1
MP
667 int aliasNum = con->numAliases++;
668 struct poptAlias * alias;
669
670 /* SunOS won't realloc(NULL, ...) */
671 if (!con->aliases)
672 con->aliases = malloc(sizeof(newAlias) * con->numAliases);
673 else
b348deae 674 con->aliases = realloc(con->aliases,
62402cb1
MP
675 sizeof(newAlias) * con->numAliases);
676 alias = con->aliases + aliasNum;
b348deae
MP
677
678 alias->longName = (newAlias.longName)
679 ? strcpy(malloc(strlen(newAlias.longName) + 1), newAlias.longName)
680 : NULL;
681 alias->shortName = newAlias.shortName;
682 alias->argc = newAlias.argc;
683 alias->argv = newAlias.argv;
62402cb1
MP
684
685 return 0;
686}
687
b348deae 688const char * poptBadOption(poptContext con, int flags) {
62402cb1
MP
689 struct optionStackEntry * os;
690
691 if (flags & POPT_BADOPTION_NOALIAS)
692 os = con->optionStack;
693 else
694 os = con->os;
695
696 return os->argv[os->next - 1];
697}
698
699#define POPT_ERROR_NOARG -10
700#define POPT_ERROR_BADOPT -11
701#define POPT_ERROR_OPTSTOODEEP -13
702#define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
703#define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
704
b348deae 705const char *const poptStrerror(const int error) {
62402cb1
MP
706 switch (error) {
707 case POPT_ERROR_NOARG:
708 return POPT_("missing argument");
709 case POPT_ERROR_BADOPT:
710 return POPT_("unknown option");
711 case POPT_ERROR_OPTSTOODEEP:
712 return POPT_("aliases nested too deeply");
713 case POPT_ERROR_BADQUOTE:
714 return POPT_("error in paramter quoting");
715 case POPT_ERROR_BADNUMBER:
716 return POPT_("invalid numeric value");
717 case POPT_ERROR_OVERFLOW:
718 return POPT_("number too large or too small");
719 case POPT_ERROR_ERRNO:
720 return strerror(errno);
721 default:
722 return POPT_("unknown error");
723 }
724}
725
b348deae
MP
726int poptStuffArgs(poptContext con, const char ** argv) {
727 int argc;
62402cb1
MP
728
729 if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
730 return POPT_ERROR_OPTSTOODEEP;
731
b348deae
MP
732 for (argc = 0; argv[argc]; argc++)
733 ;
62402cb1
MP
734
735 con->os++;
736 con->os->next = 0;
b348deae
MP
737 con->os->nextArg = NULL;
738 con->os->nextCharArg = NULL;
62402cb1 739 con->os->currAlias = NULL;
b348deae
MP
740 poptDupArgv(argc, argv, &con->os->argc, &con->os->argv);
741 con->os->argb = NULL;
62402cb1
MP
742 con->os->stuffed = 1;
743
744 return 0;
745}
746
747const char * poptGetInvocationName(poptContext con) {
748 return con->os->argv[0];
749}
b348deae
MP
750
751int poptStrippedArgv(poptContext con, int argc, char **argv)
752{
753 int i,j=1, numargs=argc;
754
755 for(i=1; i<argc; i++) {
756 if(PBM_ISSET(i, con->arg_strip)) {
757 numargs--;
758 }
759 }
760
761 for(i=1; i<argc; i++) {
762 if(PBM_ISSET(i, con->arg_strip)) {
763 continue;
764 } else {
765 if(j<numargs) {
766 argv[j++]=argv[i];
767 } else {
768 argv[j++]='\0';
769 }
770 }
771 }
772
773 return(numargs);
774}