Split code out into separate files and remove some global variables to
[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) {
6afe7f23 230 char *s = malloc(strlen(con->execPath) + strlen(script) + 2);
b348deae
MP
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 400
6afe7f23
AT
401 /* looks a bit tricky to get rid of alloca properly in this fn */
402#if HAVE_ALLOCA_H
403#define ALLOCA(x) alloca(x)
404#else
405#define ALLOCA(x) malloc(x)
406#endif
407
408
62402cb1 409 while (!done) {
b348deae
MP
410 const char * origOptString = NULL;
411 poptCallbackType cb = NULL;
412 const void * cbData = NULL;
413 const char * longArg = NULL;
414 int canstrip = 0;
415
416 while (!con->os->nextCharArg && con->os->next == con->os->argc
417 && con->os > con->optionStack) {
418 cleanOSE(con->os--);
419 }
62402cb1
MP
420 if (!con->os->nextCharArg && con->os->next == con->os->argc) {
421 invokeCallbacks(con, con->options, 1);
422 if (con->doExec) execCommand(con);
423 return -1;
424 }
425
b348deae 426 /* Process next long option */
62402cb1 427 if (!con->os->nextCharArg) {
b348deae
MP
428 char * localOptString, * optString;
429 int thisopt;
430
431 if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) {
432 con->os->next++;
433 continue;
434 }
435 thisopt=con->os->next;
62402cb1
MP
436 origOptString = con->os->argv[con->os->next++];
437
438 if (con->restLeftover || *origOptString != '-') {
439 con->leftovers[con->numLeftovers++] = origOptString;
440 if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
441 con->restLeftover = 1;
442 continue;
443 }
444
445 /* Make a copy we can hack at */
b348deae 446 localOptString = optString =
6afe7f23 447 strcpy(ALLOCA(strlen(origOptString) + 1),
62402cb1
MP
448 origOptString);
449
450 if (!optString[0])
451 return POPT_ERROR_BADOPT;
452
453 if (optString[1] == '-' && !optString[2]) {
454 con->restLeftover = 1;
455 continue;
456 } else {
b348deae
MP
457 char *oe;
458 int singleDash;
459
62402cb1
MP
460 optString++;
461 if (*optString == '-')
462 singleDash = 0, optString++;
463 else
464 singleDash = 1;
465
b348deae 466 /* XXX aliases with arg substitution need "--alias=arg" */
62402cb1
MP
467 if (handleAlias(con, optString, '\0', NULL))
468 continue;
469 if (handleExec(con, optString, '\0'))
470 continue;
471
b348deae
MP
472 /* Check for "--long=arg" option. */
473 for (oe = optString; *oe && *oe != '='; oe++)
474 ;
475 if (*oe == '=') {
476 *oe++ = '\0';
477 /* XXX longArg is mapped back to persistent storage. */
478 longArg = origOptString + (oe - localOptString);
62402cb1
MP
479 }
480
481 opt = findOption(con->options, optString, '\0', &cb, &cbData,
482 singleDash);
b348deae
MP
483 if (!opt && !singleDash)
484 return POPT_ERROR_BADOPT;
62402cb1
MP
485 }
486
b348deae 487 if (!opt) {
62402cb1 488 con->os->nextCharArg = origOptString + 1;
b348deae
MP
489 } else {
490 if(con->os == con->optionStack &&
491 opt->argInfo & POPT_ARGFLAG_STRIP) {
492 canstrip = 1;
493 poptStripArg(con, thisopt);
494 }
495 }
62402cb1
MP
496 }
497
b348deae 498 /* Process next short option */
62402cb1
MP
499 if (con->os->nextCharArg) {
500 origOptString = con->os->nextCharArg;
501
502 con->os->nextCharArg = NULL;
503
504 if (handleAlias(con, NULL, *origOptString,
505 origOptString + 1)) {
506 origOptString++;
507 continue;
508 }
509 if (handleExec(con, NULL, *origOptString))
510 continue;
511
b348deae 512 opt = findOption(con->options, NULL, *origOptString, &cb,
62402cb1 513 &cbData, 0);
b348deae
MP
514 if (!opt)
515 return POPT_ERROR_BADOPT;
62402cb1
MP
516
517 origOptString++;
518 if (*origOptString)
519 con->os->nextCharArg = origOptString;
520 }
521
b348deae 522 if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
62402cb1 523 *((int *)opt->arg) = 1;
b348deae
MP
524 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
525 if (opt->arg)
526 *((int *) opt->arg) = opt->val;
527 } else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
528 if (con->os->nextArg) {
529 xfree(con->os->nextArg);
530 con->os->nextArg = NULL;
531 }
62402cb1 532 if (longArg) {
b348deae 533 con->os->nextArg = expandNextArg(con, longArg);
62402cb1 534 } else if (con->os->nextCharArg) {
b348deae 535 con->os->nextArg = expandNextArg(con, con->os->nextCharArg);
62402cb1 536 con->os->nextCharArg = NULL;
b348deae
MP
537 } else {
538 while (con->os->next == con->os->argc &&
539 con->os > con->optionStack) {
540 cleanOSE(con->os--);
541 }
62402cb1
MP
542 if (con->os->next == con->os->argc)
543 return POPT_ERROR_NOARG;
544
b348deae
MP
545 /* make sure this isn't part of a short arg or the
546 result of an alias expansion */
547 if(con->os == con->optionStack &&
548 opt->argInfo & POPT_ARGFLAG_STRIP &&
549 canstrip) {
550 poptStripArg(con, con->os->next);
551 }
552
553 con->os->nextArg = expandNextArg(con, con->os->argv[con->os->next++]);
62402cb1
MP
554 }
555
556 if (opt->arg) {
b348deae
MP
557 long aLong;
558 char *end;
559
62402cb1
MP
560 switch (opt->argInfo & POPT_ARG_MASK) {
561 case POPT_ARG_STRING:
b348deae
MP
562 /* XXX memory leak, hard to plug */
563 *((const char **) opt->arg) = xstrdup(con->os->nextArg);
62402cb1
MP
564 break;
565
566 case POPT_ARG_INT:
567 case POPT_ARG_LONG:
568 aLong = strtol(con->os->nextArg, &end, 0);
b348deae 569 if (!(end && *end == '\0'))
62402cb1
MP
570 return POPT_ERROR_BADNUMBER;
571
572 if (aLong == LONG_MIN || aLong == LONG_MAX)
573 return POPT_ERROR_OVERFLOW;
574 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
575 *((long *) opt->arg) = aLong;
576 } else {
577 if (aLong > INT_MAX || aLong < INT_MIN)
578 return POPT_ERROR_OVERFLOW;
b348deae 579 *((int *) opt->arg) = aLong;
62402cb1
MP
580 }
581 break;
582
583 default:
584 fprintf(stdout, POPT_("option type (%d) not implemented in popt\n"),
585 opt->argInfo & POPT_ARG_MASK);
b348deae 586 exit(EXIT_FAILURE);
62402cb1
MP
587 }
588 }
589 }
590
591 if (cb)
592 cb(con, POPT_CALLBACK_REASON_OPTION, opt, con->os->nextArg, cbData);
b348deae 593 else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
62402cb1
MP
594 done = 1;
595
596 if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
597 con->finalArgvAlloced += 10;
598 con->finalArgv = realloc(con->finalArgv,
599 sizeof(*con->finalArgv) * con->finalArgvAlloced);
600 }
601
b348deae
MP
602 { char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + 3);
603 if (opt->longName)
604 sprintf(s, "--%s", opt->longName);
605 else
606 sprintf(s, "-%c", opt->shortName);
607 con->finalArgv[con->finalArgvCount++] = s;
608 }
62402cb1 609
b348deae
MP
610 if (opt->arg && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE
611 && (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL) {
612 con->finalArgv[con->finalArgvCount++] = xstrdup(con->os->nextArg);
613 }
62402cb1
MP
614 }
615
616 return opt->val;
617}
618
b348deae
MP
619const char * poptGetOptArg(poptContext con) {
620 const char * ret = con->os->nextArg;
62402cb1
MP
621 con->os->nextArg = NULL;
622 return ret;
623}
624
b348deae 625const char * poptGetArg(poptContext con) {
62402cb1 626 if (con->numLeftovers == con->nextLeftover) return NULL;
b348deae 627 return con->leftovers[con->nextLeftover++];
62402cb1
MP
628}
629
b348deae 630const char * poptPeekArg(poptContext con) {
62402cb1 631 if (con->numLeftovers == con->nextLeftover) return NULL;
b348deae 632 return con->leftovers[con->nextLeftover];
62402cb1
MP
633}
634
b348deae 635const char ** poptGetArgs(poptContext con) {
62402cb1
MP
636 if (con->numLeftovers == con->nextLeftover) return NULL;
637
638 /* some apps like [like RPM ;-) ] need this NULL terminated */
639 con->leftovers[con->numLeftovers] = NULL;
640
641 return (con->leftovers + con->nextLeftover);
642}
643
644void poptFreeContext(poptContext con) {
645 int i;
646
b348deae
MP
647 poptResetContext(con);
648 if (con->os->argb) free(con->os->argb);
649
62402cb1 650 for (i = 0; i < con->numAliases; i++) {
b348deae 651 if (con->aliases[i].longName) xfree(con->aliases[i].longName);
62402cb1
MP
652 free(con->aliases[i].argv);
653 }
654
655 for (i = 0; i < con->numExecs; i++) {
b348deae
MP
656 if (con->execs[i].longName) xfree(con->execs[i].longName);
657 xfree(con->execs[i].script);
62402cb1 658 }
b348deae 659 if (con->execs) xfree(con->execs);
62402cb1
MP
660
661 free(con->leftovers);
662 free(con->finalArgv);
b348deae 663 if (con->appName) xfree(con->appName);
62402cb1 664 if (con->aliases) free(con->aliases);
b348deae
MP
665 if (con->otherHelp) xfree(con->otherHelp);
666 if (con->execPath) xfree(con->execPath);
667 if (con->arg_strip) PBM_FREE(con->arg_strip);
668
62402cb1
MP
669 free(con);
670}
671
b348deae
MP
672int poptAddAlias(poptContext con, struct poptAlias newAlias,
673 /*@unused@*/ int flags)
674{
62402cb1
MP
675 int aliasNum = con->numAliases++;
676 struct poptAlias * alias;
677
678 /* SunOS won't realloc(NULL, ...) */
679 if (!con->aliases)
680 con->aliases = malloc(sizeof(newAlias) * con->numAliases);
681 else
b348deae 682 con->aliases = realloc(con->aliases,
62402cb1
MP
683 sizeof(newAlias) * con->numAliases);
684 alias = con->aliases + aliasNum;
b348deae
MP
685
686 alias->longName = (newAlias.longName)
687 ? strcpy(malloc(strlen(newAlias.longName) + 1), newAlias.longName)
688 : NULL;
689 alias->shortName = newAlias.shortName;
690 alias->argc = newAlias.argc;
691 alias->argv = newAlias.argv;
62402cb1
MP
692
693 return 0;
694}
695
b348deae 696const char * poptBadOption(poptContext con, int flags) {
62402cb1
MP
697 struct optionStackEntry * os;
698
699 if (flags & POPT_BADOPTION_NOALIAS)
700 os = con->optionStack;
701 else
702 os = con->os;
703
704 return os->argv[os->next - 1];
705}
706
707#define POPT_ERROR_NOARG -10
708#define POPT_ERROR_BADOPT -11
709#define POPT_ERROR_OPTSTOODEEP -13
710#define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
711#define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
712
b348deae 713const char *const poptStrerror(const int error) {
62402cb1
MP
714 switch (error) {
715 case POPT_ERROR_NOARG:
716 return POPT_("missing argument");
717 case POPT_ERROR_BADOPT:
718 return POPT_("unknown option");
719 case POPT_ERROR_OPTSTOODEEP:
720 return POPT_("aliases nested too deeply");
721 case POPT_ERROR_BADQUOTE:
722 return POPT_("error in paramter quoting");
723 case POPT_ERROR_BADNUMBER:
724 return POPT_("invalid numeric value");
725 case POPT_ERROR_OVERFLOW:
726 return POPT_("number too large or too small");
727 case POPT_ERROR_ERRNO:
728 return strerror(errno);
729 default:
730 return POPT_("unknown error");
731 }
732}
733
b348deae
MP
734int poptStuffArgs(poptContext con, const char ** argv) {
735 int argc;
62402cb1
MP
736
737 if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
738 return POPT_ERROR_OPTSTOODEEP;
739
b348deae
MP
740 for (argc = 0; argv[argc]; argc++)
741 ;
62402cb1
MP
742
743 con->os++;
744 con->os->next = 0;
b348deae
MP
745 con->os->nextArg = NULL;
746 con->os->nextCharArg = NULL;
62402cb1 747 con->os->currAlias = NULL;
b348deae
MP
748 poptDupArgv(argc, argv, &con->os->argc, &con->os->argv);
749 con->os->argb = NULL;
62402cb1
MP
750 con->os->stuffed = 1;
751
752 return 0;
753}
754
755const char * poptGetInvocationName(poptContext con) {
756 return con->os->argv[0];
757}
b348deae
MP
758
759int poptStrippedArgv(poptContext con, int argc, char **argv)
760{
761 int i,j=1, numargs=argc;
762
763 for(i=1; i<argc; i++) {
764 if(PBM_ISSET(i, con->arg_strip)) {
765 numargs--;
766 }
767 }
768
769 for(i=1; i<argc; i++) {
770 if(PBM_ISSET(i, con->arg_strip)) {
771 continue;
772 } else {
773 if(j<numargs) {
774 argv[j++]=argv[i];
775 } else {
776 argv[j++]='\0';
777 }
778 }
779 }
780
781 return(numargs);
782}