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