Upgrade from popt 1.2 to a cut-down 1.5
[rsync/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 = alloca(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     while (!done) {
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         }
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
418         /* Process next long option */
419         if (!con->os->nextCharArg) {
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;
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 */
438             localOptString = optString =
439                         strcpy(alloca(strlen(origOptString) + 1),
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 {
449                 char *oe;
450                 int singleDash;
451
452                 optString++;
453                 if (*optString == '-')
454                     singleDash = 0, optString++;
455                 else
456                     singleDash = 1;
457
458                 /* XXX aliases with arg substitution need "--alias=arg" */
459                 if (handleAlias(con, optString, '\0', NULL))
460                     continue;
461                 if (handleExec(con, optString, '\0'))
462                     continue;
463
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);
471                 }
472
473                 opt = findOption(con->options, optString, '\0', &cb, &cbData,
474                                  singleDash);
475                 if (!opt && !singleDash)
476                     return POPT_ERROR_BADOPT;
477             }
478
479             if (!opt) {
480                 con->os->nextCharArg = origOptString + 1;
481             } else {
482                 if(con->os == con->optionStack &&
483                    opt->argInfo & POPT_ARGFLAG_STRIP) {
484                     canstrip = 1;
485                     poptStripArg(con, thisopt);
486                 }
487             }
488         }
489
490         /* Process next short option */
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
504             opt = findOption(con->options, NULL, *origOptString, &cb,
505                              &cbData, 0);
506             if (!opt)
507                 return POPT_ERROR_BADOPT;
508
509             origOptString++;
510             if (*origOptString)
511                 con->os->nextCharArg = origOptString;
512         }
513
514         if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
515             *((int *)opt->arg) = 1;
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             }
524             if (longArg) {
525                 con->os->nextArg = expandNextArg(con, longArg);
526             } else if (con->os->nextCharArg) {
527                 con->os->nextArg = expandNextArg(con, con->os->nextCharArg);
528                 con->os->nextCharArg = NULL;
529             } else {
530                 while (con->os->next == con->os->argc &&
531                        con->os > con->optionStack) {
532                     cleanOSE(con->os--);
533                 }
534                 if (con->os->next == con->os->argc)
535                     return POPT_ERROR_NOARG;
536
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++]);
546             }
547
548             if (opt->arg) {
549                 long aLong;
550                 char *end;
551
552                 switch (opt->argInfo & POPT_ARG_MASK) {
553                   case POPT_ARG_STRING:
554                     /* XXX memory leak, hard to plug */
555                     *((const char **) opt->arg) = xstrdup(con->os->nextArg);
556                     break;
557
558                   case POPT_ARG_INT:
559                   case POPT_ARG_LONG:
560                     aLong = strtol(con->os->nextArg, &end, 0);
561                     if (!(end && *end == '\0'))
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;
571                         *((int *) opt->arg) = aLong;
572                     }
573                     break;
574
575                   default:
576                     fprintf(stdout, POPT_("option type (%d) not implemented in popt\n"),
577                       opt->argInfo & POPT_ARG_MASK);
578                     exit(EXIT_FAILURE);
579                 }
580             }
581         }
582
583         if (cb)
584             cb(con, POPT_CALLBACK_REASON_OPTION, opt, con->os->nextArg, cbData);
585         else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
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
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         }
601
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         }
606     }
607
608     return opt->val;
609 }
610
611 const char * poptGetOptArg(poptContext con) {
612     const char * ret = con->os->nextArg;
613     con->os->nextArg = NULL;
614     return ret;
615 }
616
617 const char * poptGetArg(poptContext con) {
618     if (con->numLeftovers == con->nextLeftover) return NULL;
619     return con->leftovers[con->nextLeftover++];
620 }
621
622 const char * poptPeekArg(poptContext con) {
623     if (con->numLeftovers == con->nextLeftover) return NULL;
624     return con->leftovers[con->nextLeftover];
625 }
626
627 const char ** poptGetArgs(poptContext con) {
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
636 void poptFreeContext(poptContext con) {
637     int i;
638
639     poptResetContext(con);
640     if (con->os->argb) free(con->os->argb);
641
642     for (i = 0; i < con->numAliases; i++) {
643         if (con->aliases[i].longName) xfree(con->aliases[i].longName);
644         free(con->aliases[i].argv);
645     }
646
647     for (i = 0; i < con->numExecs; i++) {
648         if (con->execs[i].longName) xfree(con->execs[i].longName);
649         xfree(con->execs[i].script);
650     }
651     if (con->execs) xfree(con->execs);
652
653     free(con->leftovers);
654     free(con->finalArgv);
655     if (con->appName) xfree(con->appName);
656     if (con->aliases) free(con->aliases);
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     
661     free(con);
662 }
663
664 int poptAddAlias(poptContext con, struct poptAlias newAlias,
665                 /*@unused@*/ int flags)
666 {
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
674         con->aliases = realloc(con->aliases,
675                                sizeof(newAlias) * con->numAliases);
676     alias = con->aliases + aliasNum;
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;
684
685     return 0;
686 }
687
688 const char * poptBadOption(poptContext con, int flags) {
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
705 const char *const poptStrerror(const int error) {
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
726 int poptStuffArgs(poptContext con, const char ** argv) {
727     int argc;
728
729     if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
730         return POPT_ERROR_OPTSTOODEEP;
731
732     for (argc = 0; argv[argc]; argc++)
733         ;
734
735     con->os++;
736     con->os->next = 0;
737     con->os->nextArg = NULL;
738     con->os->nextCharArg = NULL;
739     con->os->currAlias = NULL;
740     poptDupArgv(argc, argv, &con->os->argc, &con->os->argv);
741     con->os->argb = NULL;
742     con->os->stuffed = 1;
743
744     return 0;
745 }
746
747 const char * poptGetInvocationName(poptContext con) {
748     return con->os->argv[0];
749 }
750
751 int 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 }