got rid of dependency on alloca in popt
[rsync.git] / popt / popt.c
1 /* (C) 1998 Red Hat Software, Inc. -- Licensing details are in the COPYING
2    file accompanying popt source distributions, available from
3    ftp://ftp.redhat.com/pub/code/popt */
4
5 #include "system.h"
6 #include "findme.h"
7 #include "poptint.h"
8
9 #ifndef HAVE_STRERROR
10 static 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
21 void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) {
22     if (con->execPath) xfree(con->execPath);
23     con->execPath = xstrdup(path);
24     con->execAbsolute = allowAbsolute;
25 }
26
27 static void invokeCallbacks(poptContext con, const struct poptOption * table,
28                             int post) {
29     const struct poptOption * opt = table;
30     poptCallbackType cb;
31
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)))) {
38             cb = (poptCallbackType)opt->arg;
39             cb(con, post ? POPT_CALLBACK_REASON_POST : POPT_CALLBACK_REASON_PRE,
40                NULL, NULL, opt->descrip);
41         }
42         opt++;
43     }
44 }
45
46 poptContext poptGetContext(const char * name, int argc, const char ** argv,
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;
55     con->os->argb = NULL;
56
57     if (!(flags & POPT_CONTEXT_KEEP_FIRST))
58         con->os->next = 1;                      /* skip argv[0] */
59
60     con->leftovers = calloc( (argc + 1), sizeof(char *) );
61     con->options = options;
62     con->aliases = NULL;
63     con->numAliases = 0;
64     con->flags = flags;
65     con->execs = NULL;
66     con->numExecs = 0;
67     con->finalArgvAlloced = argc * 2;
68     con->finalArgv = calloc( con->finalArgvAlloced, sizeof(*con->finalArgv) );
69     con->execAbsolute = 1;
70     con->arg_strip = NULL;
71
72     if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
73         con->flags |= POPT_CONTEXT_POSIXMEHARDER;
74
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
83 static 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
99 void poptResetContext(poptContext con) {
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     }
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;
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
126     con->finalArgvCount = 0;
127
128     if (con->arg_strip) {
129         PBM_FREE(con->arg_strip);
130         con->arg_strip = NULL;
131     }
132 }
133
134 /* Only one of longName, shortName may be set at a time */
135 static 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
152     if (con->doExec == NULL) {
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++;
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     }
173
174     return 1;
175 }
176
177 /* Only one of longName, shortName may be set at a time */
178 static int handleAlias(poptContext con, const char * longName, char shortName,
179                        /*@keep@*/ const char * nextCharArg) {
180     int i;
181
182     if (con->os->currAlias && con->os->currAlias->longName && longName &&
183         !strcmp(con->os->currAlias->longName, longName))
184         return 0;
185     if (con->os->currAlias && shortName &&
186             shortName == con->os->currAlias->shortName)
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
200     if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
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;
209     con->os->nextArg = NULL;
210     con->os->nextCharArg = NULL;
211     con->os->currAlias = con->aliases + i;
212     poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv,
213                 &con->os->argc, &con->os->argv);
214     con->os->argb = NULL;
215
216     return 1;
217 }
218
219 static void execCommand(poptContext con) {
220     const char ** argv;
221     int pos = 0;
222     const char * script = con->doExec->script;
223
224     argv = malloc(sizeof(*argv) *
225                         (6 + con->numLeftovers + con->finalArgvCount));
226
227     if (!con->execAbsolute && strchr(script, '/')) return;
228
229     if (!strchr(script, '/') && con->execPath) {
230         char *s = malloc(strlen(con->execPath) + strlen(script) + 2);
231         sprintf(s, "%s/%s", con->execPath, script);
232         argv[pos] = s;
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
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)
264     setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
265 #else
266     ; /* Can't drop privileges */
267 #endif
268 #endif
269
270     execvp(argv[0], (char *const *)argv);
271 }
272
273 /*@observer@*/ static const struct poptOption *
274 findOption(const struct poptOption * table, const char * longName,
275     char shortName,
276     /*@out@*/ poptCallbackType * callback, /*@out@*/ const void ** callbackData,
277     int singleDash)
278 {
279     const struct poptOption * opt = table;
280     const struct poptOption * opt2;
281     const struct poptOption * cb = NULL;
282
283     /* This happens when a single - is given */
284     if (singleDash && !shortName && !*longName)
285         shortName = '-';
286
287     while (opt->longName || opt->shortName || opt->arg) {
288         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
289             opt2 = findOption(opt->arg, longName, shortName, callback,
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;
298         } else if (longName && opt->longName &&
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) {
312         *callback = (poptCallbackType)cb->arg;
313         if (!(cb->argInfo & POPT_CBFLAG_INC_DATA))
314             *callbackData = cb->descrip;
315     }
316
317     return opt;
318 }
319
320 static 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
346 static /*@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
387 static 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
395 /* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
396 int poptGetNextOpt(poptContext con)
397 {
398     const struct poptOption * opt = NULL;
399     int done = 0;
400
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
409     while (!done) {
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         }
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
426         /* Process next long option */
427         if (!con->os->nextCharArg) {
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;
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 */
446             localOptString = optString =
447                         strcpy(ALLOCA(strlen(origOptString) + 1),
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 {
457                 char *oe;
458                 int singleDash;
459
460                 optString++;
461                 if (*optString == '-')
462                     singleDash = 0, optString++;
463                 else
464                     singleDash = 1;
465
466                 /* XXX aliases with arg substitution need "--alias=arg" */
467                 if (handleAlias(con, optString, '\0', NULL))
468                     continue;
469                 if (handleExec(con, optString, '\0'))
470                     continue;
471
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);
479                 }
480
481                 opt = findOption(con->options, optString, '\0', &cb, &cbData,
482                                  singleDash);
483                 if (!opt && !singleDash)
484                     return POPT_ERROR_BADOPT;
485             }
486
487             if (!opt) {
488                 con->os->nextCharArg = origOptString + 1;
489             } else {
490                 if(con->os == con->optionStack &&
491                    opt->argInfo & POPT_ARGFLAG_STRIP) {
492                     canstrip = 1;
493                     poptStripArg(con, thisopt);
494                 }
495             }
496         }
497
498         /* Process next short option */
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
512             opt = findOption(con->options, NULL, *origOptString, &cb,
513                              &cbData, 0);
514             if (!opt)
515                 return POPT_ERROR_BADOPT;
516
517             origOptString++;
518             if (*origOptString)
519                 con->os->nextCharArg = origOptString;
520         }
521
522         if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
523             *((int *)opt->arg) = 1;
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             }
532             if (longArg) {
533                 con->os->nextArg = expandNextArg(con, longArg);
534             } else if (con->os->nextCharArg) {
535                 con->os->nextArg = expandNextArg(con, con->os->nextCharArg);
536                 con->os->nextCharArg = NULL;
537             } else {
538                 while (con->os->next == con->os->argc &&
539                        con->os > con->optionStack) {
540                     cleanOSE(con->os--);
541                 }
542                 if (con->os->next == con->os->argc)
543                     return POPT_ERROR_NOARG;
544
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++]);
554             }
555
556             if (opt->arg) {
557                 long aLong;
558                 char *end;
559
560                 switch (opt->argInfo & POPT_ARG_MASK) {
561                   case POPT_ARG_STRING:
562                     /* XXX memory leak, hard to plug */
563                     *((const char **) opt->arg) = xstrdup(con->os->nextArg);
564                     break;
565
566                   case POPT_ARG_INT:
567                   case POPT_ARG_LONG:
568                     aLong = strtol(con->os->nextArg, &end, 0);
569                     if (!(end && *end == '\0'))
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;
579                         *((int *) opt->arg) = aLong;
580                     }
581                     break;
582
583                   default:
584                     fprintf(stdout, POPT_("option type (%d) not implemented in popt\n"),
585                       opt->argInfo & POPT_ARG_MASK);
586                     exit(EXIT_FAILURE);
587                 }
588             }
589         }
590
591         if (cb)
592             cb(con, POPT_CALLBACK_REASON_OPTION, opt, con->os->nextArg, cbData);
593         else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
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
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         }
609
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         }
614     }
615
616     return opt->val;
617 }
618
619 const char * poptGetOptArg(poptContext con) {
620     const char * ret = con->os->nextArg;
621     con->os->nextArg = NULL;
622     return ret;
623 }
624
625 const char * poptGetArg(poptContext con) {
626     if (con->numLeftovers == con->nextLeftover) return NULL;
627     return con->leftovers[con->nextLeftover++];
628 }
629
630 const char * poptPeekArg(poptContext con) {
631     if (con->numLeftovers == con->nextLeftover) return NULL;
632     return con->leftovers[con->nextLeftover];
633 }
634
635 const char ** poptGetArgs(poptContext con) {
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
644 void poptFreeContext(poptContext con) {
645     int i;
646
647     poptResetContext(con);
648     if (con->os->argb) free(con->os->argb);
649
650     for (i = 0; i < con->numAliases; i++) {
651         if (con->aliases[i].longName) xfree(con->aliases[i].longName);
652         free(con->aliases[i].argv);
653     }
654
655     for (i = 0; i < con->numExecs; i++) {
656         if (con->execs[i].longName) xfree(con->execs[i].longName);
657         xfree(con->execs[i].script);
658     }
659     if (con->execs) xfree(con->execs);
660
661     free(con->leftovers);
662     free(con->finalArgv);
663     if (con->appName) xfree(con->appName);
664     if (con->aliases) free(con->aliases);
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     
669     free(con);
670 }
671
672 int poptAddAlias(poptContext con, struct poptAlias newAlias,
673                 /*@unused@*/ int flags)
674 {
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
682         con->aliases = realloc(con->aliases,
683                                sizeof(newAlias) * con->numAliases);
684     alias = con->aliases + aliasNum;
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;
692
693     return 0;
694 }
695
696 const char * poptBadOption(poptContext con, int flags) {
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
713 const char *const poptStrerror(const int error) {
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
734 int poptStuffArgs(poptContext con, const char ** argv) {
735     int argc;
736
737     if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
738         return POPT_ERROR_OPTSTOODEEP;
739
740     for (argc = 0; argv[argc]; argc++)
741         ;
742
743     con->os++;
744     con->os->next = 0;
745     con->os->nextArg = NULL;
746     con->os->nextCharArg = NULL;
747     con->os->currAlias = NULL;
748     poptDupArgv(argc, argv, &con->os->argc, &con->os->argv);
749     con->os->argb = NULL;
750     con->os->stuffed = 1;
751
752     return 0;
753 }
754
755 const char * poptGetInvocationName(poptContext con) {
756     return con->os->argv[0];
757 }
758
759 int 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 }