summaryrefslogtreecommitdiff
path: root/third_party
diff options
context:
space:
mode:
authorAmitay Isaacs <amitay@gmail.com>2018-05-08 15:25:12 +1000
committerAndreas Schneider <asn@cryptomilk.org>2018-05-08 12:55:04 +0200
commit2073fd0956a1c26220ae05d87e965095b9ce1b2f (patch)
treeef4ae80dc4094df379f5d0c70e54c53f010ca381 /third_party
parentdf16777ce4e3d2221b9215c523aa7d63e516db5f (diff)
downloadsamba-2073fd0956a1c26220ae05d87e965095b9ce1b2f.tar.gz
third_party: Update popt to 1.16 release
Signed-off-by: Amitay Isaacs <amitay@gmail.com> Reviewed-by: Andreas Schneider <asn@samba.org> Autobuild-User(master): Andreas Schneider <asn@cryptomilk.org> Autobuild-Date(master): Tue May 8 12:55:04 CEST 2018 on sn-devel-144
Diffstat (limited to 'third_party')
-rw-r--r--third_party/popt/README10
-rw-r--r--third_party/popt/dummy.in0
-rw-r--r--third_party/popt/findme.c50
-rw-r--r--third_party/popt/lookup3.c969
-rw-r--r--third_party/popt/popt.c1428
-rw-r--r--third_party/popt/popt.h333
-rw-r--r--third_party/popt/poptconfig.c598
-rw-r--r--third_party/popt/popthelp.c706
-rw-r--r--third_party/popt/poptint.c199
-rw-r--r--third_party/popt/poptint.h130
-rw-r--r--third_party/popt/poptparse.c69
-rw-r--r--third_party/popt/system.h87
-rw-r--r--third_party/popt/wscript6
13 files changed, 3575 insertions, 1010 deletions
diff --git a/third_party/popt/README b/third_party/popt/README
index 95f8f8dc242..c66432d104f 100644
--- a/third_party/popt/README
+++ b/third_party/popt/README
@@ -1,18 +1,16 @@
-This is the popt command line option parsing library. While it is similiar
+This is the popt(3) command line option parsing library. While it is similiar
to getopt(3), it contains a number of enhancements, including:
1) popt is fully reentrant
2) popt can parse arbitrary argv[] style arrays while
- getopt(2) makes this quite difficult
+ getopt(3) makes this quite difficult
3) popt allows users to alias command line arguments
4) popt provides convience functions for parsing strings
into argv[] style arrays
-popt is used by rpm, the Red Hat install program, and many other Red Hat
-utilities, all of which provide excellent examples of how to use popt.
-Complete documentation on popt is available in popt.ps (included in this
+Complete documentation on popt(3) is available in popt.ps (included in this
tarball), which is excerpted with permission from the book "Linux
Application Development" by Michael K. Johnson and Erik Troan (available
from Addison Wesley in May, 1998).
-Comments on popt should be addressed to ewt@redhat.com.
+Comments on popt should be addressed to popt-devel@rpm5.org.
diff --git a/third_party/popt/dummy.in b/third_party/popt/dummy.in
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/third_party/popt/dummy.in
+++ /dev/null
diff --git a/third_party/popt/findme.c b/third_party/popt/findme.c
deleted file mode 100644
index b28981ba1f4..00000000000
--- a/third_party/popt/findme.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/** \ingroup popt
- * \file popt/findme.c
- */
-
-/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
- file accompanying popt source distributions, available from
- ftp://ftp.rpm.org/pub/rpm/dist. */
-
-#include "system.h"
-#include "findme.h"
-
-const char * findProgramPath(const char * argv0) {
- char * path = getenv("PATH");
- char * pathbuf;
- char * start, * chptr;
- char * buf;
-
- if (argv0 == NULL) return NULL; /* XXX can't happen */
- /* If there is a / in the argv[0], it has to be an absolute path */
- if (strchr(argv0, '/'))
- return xstrdup(argv0);
-
- if (path == NULL) return NULL;
-
- start = pathbuf = (char *)alloca(strlen(path) + 1);
- buf = (char *)malloc(strlen(path) + strlen(argv0) + sizeof("/"));
- if (buf == NULL) return NULL; /* XXX can't happen */
- strcpy(pathbuf, path);
-
- chptr = NULL;
- /*@-branchstate@*/
- do {
- if ((chptr = strchr(start, ':')))
- *chptr = '\0';
- sprintf(buf, "%s/%s", start, argv0);
-
- if (!access(buf, X_OK))
- return buf;
-
- if (chptr)
- start = chptr + 1;
- else
- start = NULL;
- } while (start && *start);
- /*@=branchstate@*/
-
- free(buf);
-
- return NULL;
-}
diff --git a/third_party/popt/lookup3.c b/third_party/popt/lookup3.c
new file mode 100644
index 00000000000..eb4e5ce6bdf
--- /dev/null
+++ b/third_party/popt/lookup3.c
@@ -0,0 +1,969 @@
+/* -------------------------------------------------------------------- */
+/*
+ * lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+ *
+ * These are functions for producing 32-bit hashes for hash table lookup.
+ * jlu32w(), jlu32l(), jlu32lpair(), jlu32b(), _JLU3_MIX(), and _JLU3_FINAL()
+ * are externally useful functions. Routines to test the hash are included
+ * if SELF_TEST is defined. You can use this free for any purpose. It's in
+ * the public domain. It has no warranty.
+ *
+ * You probably want to use jlu32l(). jlu32l() and jlu32b()
+ * hash byte arrays. jlu32l() is is faster than jlu32b() on
+ * little-endian machines. Intel and AMD are little-endian machines.
+ * On second thought, you probably want jlu32lpair(), which is identical to
+ * jlu32l() except it returns two 32-bit hashes for the price of one.
+ * You could implement jlu32bpair() if you wanted but I haven't bothered here.
+ *
+ * If you want to find a hash of, say, exactly 7 integers, do
+ * a = i1; b = i2; c = i3;
+ * _JLU3_MIX(a,b,c);
+ * a += i4; b += i5; c += i6;
+ * _JLU3_MIX(a,b,c);
+ * a += i7;
+ * _JLU3_FINAL(a,b,c);
+ * then use c as the hash value. If you have a variable size array of
+ * 4-byte integers to hash, use jlu32w(). If you have a byte array (like
+ * a character string), use jlu32l(). If you have several byte arrays, or
+ * a mix of things, see the comments above jlu32l().
+ *
+ * Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
+ * then mix those integers. This is fast (you can do a lot more thorough
+ * mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+ * on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+*/
+/* -------------------------------------------------------------------- */
+
+#include <stdint.h>
+
+#if defined(_JLU3_SELFTEST)
+# define _JLU3_jlu32w 1
+# define _JLU3_jlu32l 1
+# define _JLU3_jlu32lpair 1
+# define _JLU3_jlu32b 1
+#endif
+
+/*@-redef@*/
+/*@unchecked@*/
+static const union _dbswap {
+ const uint32_t ui;
+ const unsigned char uc[4];
+} endian = { .ui = 0x11223344 };
+# define HASH_LITTLE_ENDIAN (endian.uc[0] == (unsigned char) 0x44)
+# define HASH_BIG_ENDIAN (endian.uc[0] == (unsigned char) 0x11)
+/*@=redef@*/
+
+#ifndef ROTL32
+# define ROTL32(x, s) (((x) << (s)) | ((x) >> (32 - (s))))
+#endif
+
+/* NOTE: The _size parameter should be in bytes. */
+#define _JLU3_INIT(_h, _size) (0xdeadbeef + ((uint32_t)(_size)) + (_h))
+
+/* -------------------------------------------------------------------- */
+/*
+ * _JLU3_MIX -- mix 3 32-bit values reversibly.
+ *
+ * This is reversible, so any information in (a,b,c) before _JLU3_MIX() is
+ * still in (a,b,c) after _JLU3_MIX().
+ *
+ * If four pairs of (a,b,c) inputs are run through _JLU3_MIX(), or through
+ * _JLU3_MIX() in reverse, there are at least 32 bits of the output that
+ * are sometimes the same for one pair and different for another pair.
+ * This was tested for:
+ * * pairs that differed by one bit, by two bits, in any combination
+ * of top bits of (a,b,c), or in any combination of bottom bits of
+ * (a,b,c).
+ * * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ * the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ * is commonly produced by subtraction) look like a single 1-bit
+ * difference.
+ * * the base values were pseudorandom, all zero but one bit set, or
+ * all zero plus a counter that starts at zero.
+ *
+ * Some k values for my "a-=c; a^=ROTL32(c,k); c+=b;" arrangement that
+ * satisfy this are
+ * 4 6 8 16 19 4
+ * 9 15 3 18 27 15
+ * 14 9 3 7 17 3
+ * Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+ * for "differ" defined as + with a one-bit base and a two-bit delta. I
+ * used http://burtleburtle.net/bob/hash/avalanche.html to choose
+ * the operations, constants, and arrangements of the variables.
+ *
+ * This does not achieve avalanche. There are input bits of (a,b,c)
+ * that fail to affect some output bits of (a,b,c), especially of a. The
+ * most thoroughly mixed value is c, but it doesn't really even achieve
+ * avalanche in c.
+ *
+ * This allows some parallelism. Read-after-writes are good at doubling
+ * the number of bits affected, so the goal of mixing pulls in the opposite
+ * direction as the goal of parallelism. I did what I could. Rotates
+ * seem to cost as much as shifts on every machine I could lay my hands
+ * on, and rotates are much kinder to the top and bottom bits, so I used
+ * rotates.
+ */
+/* -------------------------------------------------------------------- */
+#define _JLU3_MIX(a,b,c) \
+{ \
+ a -= c; a ^= ROTL32(c, 4); c += b; \
+ b -= a; b ^= ROTL32(a, 6); a += c; \
+ c -= b; c ^= ROTL32(b, 8); b += a; \
+ a -= c; a ^= ROTL32(c,16); c += b; \
+ b -= a; b ^= ROTL32(a,19); a += c; \
+ c -= b; c ^= ROTL32(b, 4); b += a; \
+}
+
+/* -------------------------------------------------------------------- */
+/**
+ * _JLU3_FINAL -- final mixing of 3 32-bit values (a,b,c) into c
+ *
+ * Pairs of (a,b,c) values differing in only a few bits will usually
+ * produce values of c that look totally different. This was tested for
+ * * pairs that differed by one bit, by two bits, in any combination
+ * of top bits of (a,b,c), or in any combination of bottom bits of
+ * (a,b,c).
+ * * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ * the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ * is commonly produced by subtraction) look like a single 1-bit
+ * difference.
+ * * the base values were pseudorandom, all zero but one bit set, or
+ * all zero plus a counter that starts at zero.
+ *
+ * These constants passed:
+ * 14 11 25 16 4 14 24
+ * 12 14 25 16 4 14 24
+ * and these came close:
+ * 4 8 15 26 3 22 24
+ * 10 8 15 26 3 22 24
+ * 11 8 15 26 3 22 24
+ */
+/* -------------------------------------------------------------------- */
+#define _JLU3_FINAL(a,b,c) \
+{ \
+ c ^= b; c -= ROTL32(b,14); \
+ a ^= c; a -= ROTL32(c,11); \
+ b ^= a; b -= ROTL32(a,25); \
+ c ^= b; c -= ROTL32(b,16); \
+ a ^= c; a -= ROTL32(c,4); \
+ b ^= a; b -= ROTL32(a,14); \
+ c ^= b; c -= ROTL32(b,24); \
+}
+
+#if defined(_JLU3_jlu32w)
+uint32_t jlu32w(uint32_t h, /*@null@*/ const uint32_t *k, size_t size)
+ /*@*/;
+/* -------------------------------------------------------------------- */
+/**
+ * This works on all machines. To be useful, it requires
+ * -- that the key be an array of uint32_t's, and
+ * -- that the size be the number of uint32_t's in the key
+ *
+ * The function jlu32w() is identical to jlu32l() on little-endian
+ * machines, and identical to jlu32b() on big-endian machines,
+ * except that the size has to be measured in uint32_ts rather than in
+ * bytes. jlu32l() is more complicated than jlu32w() only because
+ * jlu32l() has to dance around fitting the key bytes into registers.
+ *
+ * @param h the previous hash, or an arbitrary value
+ * @param *k the key, an array of uint32_t values
+ * @param size the size of the key, in uint32_ts
+ * @return the lookup3 hash
+ */
+/* -------------------------------------------------------------------- */
+uint32_t jlu32w(uint32_t h, const uint32_t *k, size_t size)
+{
+ uint32_t a = _JLU3_INIT(h, (size * sizeof(*k)));
+ uint32_t b = a;
+ uint32_t c = a;
+
+ if (k == NULL)
+ goto exit;
+
+ /*----------------------------------------------- handle most of the key */
+ while (size > 3) {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ _JLU3_MIX(a,b,c);
+ size -= 3;
+ k += 3;
+ }
+
+ /*----------------------------------------- handle the last 3 uint32_t's */
+ switch (size) {
+ case 3 : c+=k[2];
+ case 2 : b+=k[1];
+ case 1 : a+=k[0];
+ _JLU3_FINAL(a,b,c);
+ /*@fallthrough@*/
+ case 0:
+ break;
+ }
+ /*---------------------------------------------------- report the result */
+exit:
+ return c;
+}
+#endif /* defined(_JLU3_jlu32w) */
+
+#if defined(_JLU3_jlu32l)
+uint32_t jlu32l(uint32_t h, const void *key, size_t size)
+ /*@*/;
+/* -------------------------------------------------------------------- */
+/*
+ * jlu32l() -- hash a variable-length key into a 32-bit value
+ * h : can be any 4-byte value
+ * k : the key (the unaligned variable-length array of bytes)
+ * size : the size of the key, counting by bytes
+ * Returns a 32-bit value. Every bit of the key affects every bit of
+ * the return value. Two keys differing by one or two bits will have
+ * totally different hash values.
+ *
+ * The best hash table sizes are powers of 2. There is no need to do
+ * mod a prime (mod is sooo slow!). If you need less than 32 bits,
+ * use a bitmask. For example, if you need only 10 bits, do
+ * h = (h & hashmask(10));
+ * In which case, the hash table should have hashsize(10) elements.
+ *
+ * If you are hashing n strings (uint8_t **)k, do it like this:
+ * for (i=0, h=0; i<n; ++i) h = jlu32l(h, k[i], len[i]);
+ *
+ * By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
+ * code any way you wish, private, educational, or commercial. It's free.
+ *
+ * Use for hash table lookup, or anything where one collision in 2^^32 is
+ * acceptable. Do NOT use for cryptographic purposes.
+ *
+ * @param h the previous hash, or an arbitrary value
+ * @param *k the key, an array of uint8_t values
+ * @param size the size of the key
+ * @return the lookup3 hash
+ */
+/* -------------------------------------------------------------------- */
+uint32_t jlu32l(uint32_t h, const void *key, size_t size)
+{
+ union { const void *ptr; size_t i; } u;
+ uint32_t a = _JLU3_INIT(h, size);
+ uint32_t b = a;
+ uint32_t c = a;
+
+ if (key == NULL)
+ goto exit;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+#ifdef VALGRIND
+ const uint8_t *k8;
+#endif
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (size > 12) {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ _JLU3_MIX(a,b,c);
+ size -= 12;
+ k += 3;
+ }
+
+ /*------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch (size) {
+ case 12: c += k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c += k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c += k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9: c += k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8: b += k[1]; a+=k[0]; break;
+ case 7: b += k[1]&0xffffff; a+=k[0]; break;
+ case 6: b += k[1]&0xffff; a+=k[0]; break;
+ case 5: b += k[1]&0xff; a+=k[0]; break;
+ case 4: a += k[0]; break;
+ case 3: a += k[0]&0xffffff; break;
+ case 2: a += k[0]&0xffff; break;
+ case 1: a += k[0]&0xff; break;
+ case 0: goto exit;
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch (size) {
+ case 12: c += k[2]; b+=k[1]; a+=k[0] break;
+ case 11: c += ((uint32_t)k8[10])<<16; /*@fallthrough@*/
+ case 10: c += ((uint32_t)k8[9])<<8; /*@fallthrough@*/
+ case 9: c += k8[8]; /*@fallthrough@*/
+ case 8: b += k[1]; a+=k[0]; break;
+ case 7: b += ((uint32_t)k8[6])<<16; /*@fallthrough@*/
+ case 6: b += ((uint32_t)k8[5])<<8; /*@fallthrough@*/
+ case 5: b += k8[4]; /*@fallthrough@*/
+ case 4: a += k[0]; break;
+ case 3: a += ((uint32_t)k8[2])<<16; /*@fallthrough@*/
+ case 2: a += ((uint32_t)k8[1])<<8; /*@fallthrough@*/
+ case 1: a += k8[0]; break;
+ case 0: goto exit;
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ /*----------- all but last block: aligned reads and different mixing */
+ while (size > 12) {
+ a += k[0] + (((uint32_t)k[1])<<16);
+ b += k[2] + (((uint32_t)k[3])<<16);
+ c += k[4] + (((uint32_t)k[5])<<16);
+ _JLU3_MIX(a,b,c);
+ size -= 12;
+ k += 6;
+ }
+
+ /*------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *)k;
+ switch (size) {
+ case 12:
+ c += k[4]+(((uint32_t)k[5])<<16);
+ b += k[2]+(((uint32_t)k[3])<<16);
+ a += k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 11:
+ c += ((uint32_t)k8[10])<<16;
+ /*@fallthrough@*/
+ case 10:
+ c += (uint32_t)k[4];
+ b += k[2]+(((uint32_t)k[3])<<16);
+ a += k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 9:
+ c += (uint32_t)k8[8];
+ /*@fallthrough@*/
+ case 8:
+ b += k[2]+(((uint32_t)k[3])<<16);
+ a += k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 7:
+ b += ((uint32_t)k8[6])<<16;
+ /*@fallthrough@*/
+ case 6:
+ b += (uint32_t)k[2];
+ a += k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 5:
+ b += (uint32_t)k8[4];
+ /*@fallthrough@*/
+ case 4:
+ a += k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 3:
+ a += ((uint32_t)k8[2])<<16;
+ /*@fallthrough@*/
+ case 2:
+ a += (uint32_t)k[0];
+ break;
+ case 1:
+ a += (uint32_t)k8[0];
+ break;
+ case 0:
+ goto exit;
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*----------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (size > 12) {
+ a += (uint32_t)k[0];
+ a += ((uint32_t)k[1])<<8;
+ a += ((uint32_t)k[2])<<16;
+ a += ((uint32_t)k[3])<<24;
+ b += (uint32_t)k[4];
+ b += ((uint32_t)k[5])<<8;
+ b += ((uint32_t)k[6])<<16;
+ b += ((uint32_t)k[7])<<24;
+ c += (uint32_t)k[8];
+ c += ((uint32_t)k[9])<<8;
+ c += ((uint32_t)k[10])<<16;
+ c += ((uint32_t)k[11])<<24;
+ _JLU3_MIX(a,b,c);
+ size -= 12;
+ k += 12;
+ }
+
+ /*---------------------------- last block: affect all 32 bits of (c) */
+ switch (size) {
+ case 12: c += ((uint32_t)k[11])<<24; /*@fallthrough@*/
+ case 11: c += ((uint32_t)k[10])<<16; /*@fallthrough@*/
+ case 10: c += ((uint32_t)k[9])<<8; /*@fallthrough@*/
+ case 9: c += (uint32_t)k[8]; /*@fallthrough@*/
+ case 8: b += ((uint32_t)k[7])<<24; /*@fallthrough@*/
+ case 7: b += ((uint32_t)k[6])<<16; /*@fallthrough@*/
+ case 6: b += ((uint32_t)k[5])<<8; /*@fallthrough@*/
+ case 5: b += (uint32_t)k[4]; /*@fallthrough@*/
+ case 4: a += ((uint32_t)k[3])<<24; /*@fallthrough@*/
+ case 3: a += ((uint32_t)k[2])<<16; /*@fallthrough@*/
+ case 2: a += ((uint32_t)k[1])<<8; /*@fallthrough@*/
+ case 1: a += (uint32_t)k[0];
+ break;
+ case 0:
+ goto exit;
+ }
+ }
+
+ _JLU3_FINAL(a,b,c);
+
+exit:
+ return c;
+}
+#endif /* defined(_JLU3_jlu32l) */
+
+#if defined(_JLU3_jlu32lpair)
+/**
+ * jlu32lpair: return 2 32-bit hash values.
+ *
+ * This is identical to jlu32l(), except it returns two 32-bit hash
+ * values instead of just one. This is good enough for hash table
+ * lookup with 2^^64 buckets, or if you want a second hash if you're not
+ * happy with the first, or if you want a probably-unique 64-bit ID for
+ * the key. *pc is better mixed than *pb, so use *pc first. If you want
+ * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
+ *
+ * @param h the previous hash, or an arbitrary value
+ * @param *key the key, an array of uint8_t values
+ * @param size the size of the key in bytes
+ * @retval *pc, IN: primary initval, OUT: primary hash
+ * *retval *pb IN: secondary initval, OUT: secondary hash
+ */
+void jlu32lpair(const void *key, size_t size, uint32_t *pc, uint32_t *pb)
+{
+ union { const void *ptr; size_t i; } u;
+ uint32_t a = _JLU3_INIT(*pc, size);
+ uint32_t b = a;
+ uint32_t c = a;
+
+ if (key == NULL)
+ goto exit;
+
+ c += *pb; /* Add the secondary hash. */
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+#ifdef VALGRIND
+ const uint8_t *k8;
+#endif
+
+ /*-- all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (size > (size_t)12) {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ _JLU3_MIX(a,b,c);
+ size -= 12;
+ k += 3;
+ }
+ /*------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch (size) {
+ case 12: c += k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c += k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c += k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9: c += k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8: b += k[1]; a+=k[0]; break;
+ case 7: b += k[1]&0xffffff; a+=k[0]; break;
+ case 6: b += k[1]&0xffff; a+=k[0]; break;
+ case 5: b += k[1]&0xff; a+=k[0]; break;
+ case 4: a += k[0]; break;
+ case 3: a += k[0]&0xffffff; break;
+ case 2: a += k[0]&0xffff; break;
+ case 1: a += k[0]&0xff; break;
+ case 0: goto exit;
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch (size) {
+ case 12: c += k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c += ((uint32_t)k8[10])<<16; /*@fallthrough@*/
+ case 10: c += ((uint32_t)k8[9])<<8; /*@fallthrough@*/
+ case 9: c += k8[8]; /*@fallthrough@*/
+ case 8: b += k[1]; a+=k[0]; break;
+ case 7: b += ((uint32_t)k8[6])<<16; /*@fallthrough@*/
+ case 6: b += ((uint32_t)k8[5])<<8; /*@fallthrough@*/
+ case 5: b += k8[4]; /*@fallthrough@*/
+ case 4: a += k[0]; break;
+ case 3: a += ((uint32_t)k8[2])<<16; /*@fallthrough@*/
+ case 2: a += ((uint32_t)k8[1])<<8; /*@fallthrough@*/
+ case 1: a += k8[0]; break;
+ case 0: goto exit;
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ /*----------- all but last block: aligned reads and different mixing */
+ while (size > (size_t)12) {
+ a += k[0] + (((uint32_t)k[1])<<16);
+ b += k[2] + (((uint32_t)k[3])<<16);
+ c += k[4] + (((uint32_t)k[5])<<16);
+ _JLU3_MIX(a,b,c);
+ size -= 12;
+ k += 6;
+ }
+
+ /*------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *)k;
+ switch (size) {
+ case 12:
+ c += k[4]+(((uint32_t)k[5])<<16);
+ b += k[2]+(((uint32_t)k[3])<<16);
+ a += k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 11:
+ c += ((uint32_t)k8[10])<<16;
+ /*@fallthrough@*/
+ case 10:
+ c += k[4];
+ b += k[2]+(((uint32_t)k[3])<<16);
+ a += k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 9:
+ c += k8[8];
+ /*@fallthrough@*/
+ case 8:
+ b += k[2]+(((uint32_t)k[3])<<16);
+ a += k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 7:
+ b += ((uint32_t)k8[6])<<16;
+ /*@fallthrough@*/
+ case 6:
+ b += k[2];
+ a += k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 5:
+ b += k8[4];
+ /*@fallthrough@*/
+ case 4:
+ a += k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 3:
+ a += ((uint32_t)k8[2])<<16;
+ /*@fallthrough@*/
+ case 2:
+ a += k[0];
+ break;
+ case 1:
+ a += k8[0];
+ break;
+ case 0:
+ goto exit;
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*----------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (size > (size_t)12) {
+ a += k[0];
+ a += ((uint32_t)k[1])<<8;
+ a += ((uint32_t)k[2])<<16;
+ a += ((uint32_t)k[3])<<24;
+ b += k[4];
+ b += ((uint32_t)k[5])<<8;
+ b += ((uint32_t)k[6])<<16;
+ b += ((uint32_t)k[7])<<24;
+ c += k[8];
+ c += ((uint32_t)k[9])<<8;
+ c += ((uint32_t)k[10])<<16;
+ c += ((uint32_t)k[11])<<24;
+ _JLU3_MIX(a,b,c);
+ size -= 12;
+ k += 12;
+ }
+
+ /*---------------------------- last block: affect all 32 bits of (c) */
+ switch (size) {
+ case 12: c += ((uint32_t)k[11])<<24; /*@fallthrough@*/
+ case 11: c += ((uint32_t)k[10])<<16; /*@fallthrough@*/
+ case 10: c += ((uint32_t)k[9])<<8; /*@fallthrough@*/
+ case 9: c += k[8]; /*@fallthrough@*/
+ case 8: b += ((uint32_t)k[7])<<24; /*@fallthrough@*/
+ case 7: b += ((uint32_t)k[6])<<16; /*@fallthrough@*/
+ case 6: b += ((uint32_t)k[5])<<8; /*@fallthrough@*/
+ case 5: b += k[4]; /*@fallthrough@*/
+ case 4: a += ((uint32_t)k[3])<<24; /*@fallthrough@*/
+ case 3: a += ((uint32_t)k[2])<<16; /*@fallthrough@*/
+ case 2: a += ((uint32_t)k[1])<<8; /*@fallthrough@*/
+ case 1: a += k[0];
+ break;
+ case 0:
+ goto exit;
+ }
+ }
+
+ _JLU3_FINAL(a,b,c);
+
+exit:
+ *pc = c;
+ *pb = b;
+ return;
+}
+#endif /* defined(_JLU3_jlu32lpair) */
+
+#if defined(_JLU3_jlu32b)
+uint32_t jlu32b(uint32_t h, /*@null@*/ const void *key, size_t size)
+ /*@*/;
+/*
+ * jlu32b():
+ * This is the same as jlu32w() on big-endian machines. It is different
+ * from jlu32l() on all machines. jlu32b() takes advantage of
+ * big-endian byte ordering.
+ *
+ * @param h the previous hash, or an arbitrary value
+ * @param *k the key, an array of uint8_t values
+ * @param size the size of the key
+ * @return the lookup3 hash
+ */
+uint32_t jlu32b(uint32_t h, const void *key, size_t size)
+{
+ union { const void *ptr; size_t i; } u;
+ uint32_t a = _JLU3_INIT(h, size);
+ uint32_t b = a;
+ uint32_t c = a;
+
+ if (key == NULL)
+ return h;
+
+ u.ptr = key;
+ if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+#ifdef VALGRIND
+ const uint8_t *k8;
+#endif
+
+ /*-- all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (size > 12) {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ _JLU3_MIX(a,b,c);
+ size -= 12;
+ k += 3;
+ }
+
+ /*------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]<<8" actually reads beyond the end of the string, but
+ * then shifts out the part it's not allowed to read. Because the
+ * string is aligned, the illegal read is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch (size) {
+ case 12: c += k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c += k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;
+ case 10: c += k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;
+ case 9: c += k[2]&0xff000000; b+=k[1]; a+=k[0]; break;
+ case 8: b += k[1]; a+=k[0]; break;
+ case 7: b += k[1]&0xffffff00; a+=k[0]; break;
+ case 6: b += k[1]&0xffff0000; a+=k[0]; break;
+ case 5: b += k[1]&0xff000000; a+=k[0]; break;
+ case 4: a += k[0]; break;
+ case 3: a += k[0]&0xffffff00; break;
+ case 2: a += k[0]&0xffff0000; break;
+ case 1: a += k[0]&0xff000000; break;
+ case 0: goto exit;
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch (size) { /* all the case statements fall through */
+ case 12: c += k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c += ((uint32_t)k8[10])<<8; /*@fallthrough@*/
+ case 10: c += ((uint32_t)k8[9])<<16; /*@fallthrough@*/
+ case 9: c += ((uint32_t)k8[8])<<24; /*@fallthrough@*/
+ case 8: b += k[1]; a+=k[0]; break;
+ case 7: b += ((uint32_t)k8[6])<<8; /*@fallthrough@*/
+ case 6: b += ((uint32_t)k8[5])<<16; /*@fallthrough@*/
+ case 5: b += ((uint32_t)k8[4])<<24; /*@fallthrough@*/
+ case 4: a += k[0]; break;
+ case 3: a += ((uint32_t)k8[2])<<8; /*@fallthrough@*/
+ case 2: a += ((uint32_t)k8[1])<<16; /*@fallthrough@*/
+ case 1: a += ((uint32_t)k8[0])<<24; break;
+ case 0: goto exit;
+ }
+
+#endif /* !VALGRIND */
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*----------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (size > 12) {
+ a += ((uint32_t)k[0])<<24;
+ a += ((uint32_t)k[1])<<16;
+ a += ((uint32_t)k[2])<<8;
+ a += ((uint32_t)k[3]);
+ b += ((uint32_t)k[4])<<24;
+ b += ((uint32_t)k[5])<<16;
+ b += ((uint32_t)k[6])<<8;
+ b += ((uint32_t)k[7]);
+ c += ((uint32_t)k[8])<<24;
+ c += ((uint32_t)k[9])<<16;
+ c += ((uint32_t)k[10])<<8;
+ c += ((uint32_t)k[11]);
+ _JLU3_MIX(a,b,c);
+ size -= 12;
+ k += 12;
+ }
+
+ /*---------------------------- last block: affect all 32 bits of (c) */
+ switch (size) { /* all the case statements fall through */
+ case 12: c += k[11]; /*@fallthrough@*/
+ case 11: c += ((uint32_t)k[10])<<8; /*@fallthrough@*/
+ case 10: c += ((uint32_t)k[9])<<16; /*@fallthrough@*/
+ case 9: c += ((uint32_t)k[8])<<24; /*@fallthrough@*/
+ case 8: b += k[7]; /*@fallthrough@*/
+ case 7: b += ((uint32_t)k[6])<<8; /*@fallthrough@*/
+ case 6: b += ((uint32_t)k[5])<<16; /*@fallthrough@*/
+ case 5: b += ((uint32_t)k[4])<<24; /*@fallthrough@*/
+ case 4: a += k[3]; /*@fallthrough@*/
+ case 3: a += ((uint32_t)k[2])<<8; /*@fallthrough@*/
+ case 2: a += ((uint32_t)k[1])<<16; /*@fallthrough@*/
+ case 1: a += ((uint32_t)k[0])<<24; /*@fallthrough@*/
+ break;
+ case 0:
+ goto exit;
+ }
+ }
+
+ _JLU3_FINAL(a,b,c);
+
+exit:
+ return c;
+}
+#endif /* defined(_JLU3_jlu32b) */
+
+#if defined(_JLU3_SELFTEST)
+
+/* used for timings */
+static void driver1(void)
+ /*@*/
+{
+ uint8_t buf[256];
+ uint32_t i;
+ uint32_t h=0;
+ time_t a,z;
+
+ time(&a);
+ for (i=0; i<256; ++i) buf[i] = 'x';
+ for (i=0; i<1; ++i) {
+ h = jlu32l(h, &buf[0], sizeof(buf[0]));
+ }
+ time(&z);
+ if (z-a > 0) printf("time %d %.8x\n", (int)(z-a), h);
+}
+
+/* check that every input bit changes every output bit half the time */
+#define HASHSTATE 1
+#define HASHLEN 1
+#define MAXPAIR 60
+#define MAXLEN 70
+static void driver2(void)
+ /*@*/
+{
+ uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1];
+ uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z;
+ uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE];
+ uint32_t x[HASHSTATE],y[HASHSTATE];
+ uint32_t hlen;
+
+ printf("No more than %d trials should ever be needed \n",MAXPAIR/2);
+ for (hlen=0; hlen < MAXLEN; ++hlen) {
+ z=0;
+ for (i=0; i<hlen; ++i) { /*-------------- for each input byte, */
+ for (j=0; j<8; ++j) { /*--------------- for each input bit, */
+ for (m=1; m<8; ++m) { /*--- for serveral possible initvals, */
+ for (l=0; l<HASHSTATE; ++l)
+ e[l]=f[l]=g[l]=h[l]=x[l]=y[l]=~((uint32_t)0);
+
+ /* check that every output bit is affected by that input bit */
+ for (k=0; k<MAXPAIR; k+=2) {
+ uint32_t finished=1;
+ /* keys have one bit different */
+ for (l=0; l<hlen+1; ++l) {a[l] = b[l] = (uint8_t)0;}
+ /* have a and b be two keys differing in only one bit */
+ a[i] ^= (k<<j);
+ a[i] ^= (k>>(8-j));
+ c[0] = jlu32l(m, a, hlen);
+ b[i] ^= ((k+1)<<j);
+ b[i] ^= ((k+1)>>(8-j));
+ d[0] = jlu32l(m, b, hlen);
+ /* check every bit is 1, 0, set, and not set at least once */
+ for (l=0; l<HASHSTATE; ++l) {
+ e[l] &= (c[l]^d[l]);
+ f[l] &= ~(c[l]^d[l]);
+ g[l] &= c[l];
+ h[l] &= ~c[l];
+ x[l] &= d[l];
+ y[l] &= ~d[l];
+ if (e[l]|f[l]|g[l]|h[l]|x[l]|y[l]) finished=0;
+ }
+ if (finished) break;
+ }
+ if (k>z) z=k;
+ if (k == MAXPAIR) {
+ printf("Some bit didn't change: ");
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x ",
+ e[0],f[0],g[0],h[0],x[0],y[0]);
+ printf("i %d j %d m %d len %d\n", i, j, m, hlen);
+ }
+ if (z == MAXPAIR) goto done;
+ }
+ }
+ }
+ done:
+ if (z < MAXPAIR) {
+ printf("Mix success %2d bytes %2d initvals ",i,m);
+ printf("required %d trials\n", z/2);
+ }
+ }
+ printf("\n");
+}
+
+/* Check for reading beyond the end of the buffer and alignment problems */
+static void driver3(void)
+ /*@*/
+{
+ uint8_t buf[MAXLEN+20], *b;
+ uint32_t len;
+ uint8_t q[] = "This is the time for all good men to come to the aid of their country...";
+ uint32_t h;
+ uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country...";
+ uint32_t i;
+ uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country...";
+ uint32_t j;
+ uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country...";
+ uint32_t ref,x,y;
+ uint8_t *p;
+ uint32_t m = 13;
+
+ printf("Endianness. These lines should all be the same (for values filled in):\n");
+ printf("%.8x %.8x %.8x\n",
+ jlu32w(m, (const uint32_t *)q, (sizeof(q)-1)/4),
+ jlu32w(m, (const uint32_t *)q, (sizeof(q)-5)/4),
+ jlu32w(m, (const uint32_t *)q, (sizeof(q)-9)/4));
+ p = q;
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2),
+ jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4),
+ jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6),
+ jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8),
+ jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10),
+ jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12));
+ p = &qq[1];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2),
+ jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4),
+ jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6),
+ jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8),
+ jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10),
+ jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12));
+ p = &qqq[2];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2),
+ jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4),
+ jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6),
+ jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8),
+ jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10),
+ jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12));
+ p = &qqqq[3];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ jlu32l(m, p, sizeof(q)-1), jlu32l(m, p, sizeof(q)-2),
+ jlu32l(m, p, sizeof(q)-3), jlu32l(m, p, sizeof(q)-4),
+ jlu32l(m, p, sizeof(q)-5), jlu32l(m, p, sizeof(q)-6),
+ jlu32l(m, p, sizeof(q)-7), jlu32l(m, p, sizeof(q)-8),
+ jlu32l(m, p, sizeof(q)-9), jlu32l(m, p, sizeof(q)-10),
+ jlu32l(m, p, sizeof(q)-11), jlu32l(m, p, sizeof(q)-12));
+ printf("\n");
+ for (h=0, b=buf+1; h<8; ++h, ++b) {
+ for (i=0; i<MAXLEN; ++i) {
+ len = i;
+ for (j=0; j<i; ++j)
+ *(b+j)=0;
+
+ /* these should all be equal */
+ m = 1;
+ ref = jlu32l(m, b, len);
+ *(b+i)=(uint8_t)~0;
+ *(b-1)=(uint8_t)~0;
+ x = jlu32l(m, b, len);
+ y = jlu32l(m, b, len);
+ if ((ref != x) || (ref != y))
+ printf("alignment error: %.8x %.8x %.8x %d %d\n",ref,x,y, h, i);
+ }
+ }
+}
+
+/* check for problems with nulls */
+static void driver4(void)
+ /*@*/
+{
+ uint8_t buf[1];
+ uint32_t h;
+ uint32_t i;
+ uint32_t state[HASHSTATE];
+
+ buf[0] = ~0;
+ for (i=0; i<HASHSTATE; ++i)
+ state[i] = 1;
+ printf("These should all be different\n");
+ h = 0;
+ for (i=0; i<8; ++i) {
+ h = jlu32l(h, buf, 0);
+ printf("%2ld 0-byte strings, hash is %.8x\n", (long)i, h);
+ }
+}
+
+
+int main(int argc, char ** argv)
+{
+ driver1(); /* test that the key is hashed: used for timings */
+ driver2(); /* test that whole key is hashed thoroughly */
+ driver3(); /* test that nothing but the key is hashed */
+ driver4(); /* test hashing multiple buffers (all buffers are null) */
+ return 1;
+}
+
+#endif /* _JLU3_SELFTEST */
diff --git a/third_party/popt/popt.c b/third_party/popt/popt.c
index d9e8411b9f2..c6bae95aeca 100644
--- a/third_party/popt/popt.c
+++ b/third_party/popt/popt.c
@@ -10,12 +10,19 @@
#include "system.h"
-#if HAVE_FLOAT_H
+#if defined(__LCLINT__)
+/*@-declundef -exportheader @*/
+extern long long int strtoll(const char *nptr, /*@null@*/ char **endptr,
+ int base)
+ /*@modifies *endptr@*/;
+/*@=declundef =exportheader @*/
+#endif
+
+#ifdef HAVE_FLOAT_H
#include <float.h>
#endif
#include <math.h>
-#include "findme.h"
#include "poptint.h"
#ifdef MYDEBUG
@@ -23,8 +30,14 @@
int _popt_debug = 0;
#endif
-#ifndef HAVE_STRERROR
-static char * strerror(int errno) {
+/*@unchecked@*/
+unsigned int _poptArgMask = POPT_ARG_MASK;
+/*@unchecked@*/
+unsigned int _poptGroupMask = POPT_GROUP_MASK;
+
+#if !defined(HAVE_STRERROR) && !defined(__LCLINT__)
+static char * strerror(int errno)
+{
extern int sys_nerr;
extern char * sys_errlist[];
@@ -36,7 +49,8 @@ static char * strerror(int errno) {
#endif
#ifdef MYDEBUG
-/*@unused@*/ static void prtcon(const char *msg, poptContext con)
+/*@unused@*/
+static void prtcon(const char *msg, poptContext con)
{
if (msg) fprintf(stderr, "%s", msg);
fprintf(stderr, "\tcon %p os %p nextCharArg \"%s\" nextArg \"%s\" argv[%d] \"%s\"\n",
@@ -51,12 +65,10 @@ static char * strerror(int errno) {
void poptSetExecPath(poptContext con, const char * path, int allowAbsolute)
{
- con->execPath = (const char *)_free(con->execPath);
+ con->execPath = _free(con->execPath);
con->execPath = xstrdup(path);
con->execAbsolute = allowAbsolute;
- /*@-nullstate@*/ /* LCL: con->execPath can be NULL? */
return;
- /*@=nullstate@*/
}
static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt)
@@ -65,19 +77,20 @@ static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt)
{
if (opt != NULL)
for (; opt->longName || opt->shortName || opt->arg; opt++) {
- if (opt->arg == NULL) continue; /* XXX program error. */
- if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
- /* Recurse on included sub-tables. */
- invokeCallbacksPRE(con, (const struct poptOption *)opt->arg);
- } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
- (opt->argInfo & POPT_CBFLAG_PRE))
- { /*@-castfcnptr@*/
- poptCallbackType cb = (poptCallbackType)opt->arg;
- /*@=castfcnptr@*/
- /* Perform callback. */
- /*@-moduncon -noeffectuncon @*/
- cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip);
- /*@=moduncon =noeffectuncon @*/
+ poptArg arg = { .ptr = opt->arg };
+ if (arg.ptr)
+ switch (poptArgType(opt)) {
+ case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */
+ poptSubstituteHelpI18N(arg.opt); /* XXX side effects */
+ invokeCallbacksPRE(con, arg.opt);
+ /*@switchbreak@*/ break;
+ case POPT_ARG_CALLBACK: /* Perform callback. */
+ if (!CBF_ISSET(opt, PRE))
+ /*@switchbreak@*/ break;
+/*@-noeffectuncon @*/ /* XXX no known way to annotate (*vector) calls. */
+ arg.cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip);
+/*@=noeffectuncon @*/
+ /*@switchbreak@*/ break;
}
}
}
@@ -88,114 +101,109 @@ static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt)
{
if (opt != NULL)
for (; opt->longName || opt->shortName || opt->arg; opt++) {
- if (opt->arg == NULL) continue; /* XXX program error. */
- if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
- /* Recurse on included sub-tables. */
- invokeCallbacksPOST(con, (const struct poptOption *)opt->arg);
- } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
- (opt->argInfo & POPT_CBFLAG_POST))
- { /*@-castfcnptr@*/
- poptCallbackType cb = (poptCallbackType)opt->arg;
- /*@=castfcnptr@*/
- /* Perform callback. */
- /*@-moduncon -noeffectuncon @*/
- cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip);
- /*@=moduncon =noeffectuncon @*/
+ poptArg arg = { .ptr = opt->arg };
+ if (arg.ptr)
+ switch (poptArgType(opt)) {
+ case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */
+ poptSubstituteHelpI18N(arg.opt); /* XXX side effects */
+ invokeCallbacksPOST(con, arg.opt);
+ /*@switchbreak@*/ break;
+ case POPT_ARG_CALLBACK: /* Perform callback. */
+ if (!CBF_ISSET(opt, POST))
+ /*@switchbreak@*/ break;
+/*@-noeffectuncon @*/ /* XXX no known way to annotate (*vector) calls. */
+ arg.cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip);
+/*@=noeffectuncon @*/
+ /*@switchbreak@*/ break;
}
}
}
static void invokeCallbacksOPTION(poptContext con,
- const struct poptOption * opt,
- const struct poptOption * myOpt,
- /*@null@*/ const void * myData, int shorty)
+ const struct poptOption * opt,
+ const struct poptOption * myOpt,
+ /*@null@*/ const void * myData, int shorty)
/*@globals internalState@*/
/*@modifies internalState@*/
{
const struct poptOption * cbopt = NULL;
+ poptArg cbarg = { .ptr = NULL };
if (opt != NULL)
for (; opt->longName || opt->shortName || opt->arg; opt++) {
- if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
- /* Recurse on included sub-tables. */
- if (opt->arg != NULL) /* XXX program error */
- invokeCallbacksOPTION(con, (const struct poptOption *)opt->arg,
- myOpt, myData, shorty);
- } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK &&
- !(opt->argInfo & POPT_CBFLAG_SKIPOPTION)) {
- /* Save callback info. */
+ poptArg arg = { .ptr = opt->arg };
+ switch (poptArgType(opt)) {
+ case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */
+ poptSubstituteHelpI18N(arg.opt); /* XXX side effects */
+ if (opt->arg != NULL)
+ invokeCallbacksOPTION(con, opt->arg, myOpt, myData, shorty);
+ /*@switchbreak@*/ break;
+ case POPT_ARG_CALLBACK: /* Save callback info. */
+ if (CBF_ISSET(opt, SKIPOPTION))
+ /*@switchbreak@*/ break;
cbopt = opt;
- } else if (cbopt != NULL &&
- ((myOpt->shortName && opt->shortName && shorty &&
- myOpt->shortName == opt->shortName) ||
- (myOpt->longName && opt->longName &&
- /*@-nullpass@*/ /* LCL: opt->longName != NULL */
+ cbarg.ptr = opt->arg;
+ /*@switchbreak@*/ break;
+ default: /* Perform callback on matching option. */
+ if (cbopt == NULL || cbarg.cb == NULL)
+ /*@switchbreak@*/ break;
+ if ((myOpt->shortName && opt->shortName && shorty &&
+ myOpt->shortName == opt->shortName)
+ || (myOpt->longName != NULL && opt->longName != NULL &&
!strcmp(myOpt->longName, opt->longName)))
- /*@=nullpass@*/
- )
- { /*@-castfcnptr@*/
- poptCallbackType cb = (poptCallbackType)cbopt->arg;
- /*@=castfcnptr@*/
- const void * cbData = (cbopt->descrip ? cbopt->descrip : myData);
- /* Perform callback. */
- if (cb != NULL) { /* XXX program error */
- /*@-moduncon -noeffectuncon @*/
- cb(con, POPT_CALLBACK_REASON_OPTION, myOpt,
- con->os->nextArg, cbData);
- /*@=moduncon =noeffectuncon @*/
+ { const void *cbData = (cbopt->descrip ? cbopt->descrip : myData);
+/*@-noeffectuncon @*/ /* XXX no known way to annotate (*vector) calls. */
+ cbarg.cb(con, POPT_CALLBACK_REASON_OPTION,
+ myOpt, con->os->nextArg, cbData);
+/*@=noeffectuncon @*/
+ /* Terminate (unless explcitly continuing). */
+ if (!CBF_ISSET(cbopt, CONTINUE))
+ return;
}
- /* Terminate (unless explcitly continuing). */
- if (!(cbopt->argInfo & POPT_CBFLAG_CONTINUE))
- return;
+ /*@switchbreak@*/ break;
}
}
}
poptContext poptGetContext(const char * name, int argc, const char ** argv,
- const struct poptOption * options, int flags)
+ const struct poptOption * options, unsigned int flags)
{
- poptContext con = (poptContext)malloc(sizeof(*con));
+ poptContext con = malloc(sizeof(*con));
if (con == NULL) return NULL; /* XXX can't happen */
memset(con, 0, sizeof(*con));
con->os = con->optionStack;
con->os->argc = argc;
- /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */
+/*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */
con->os->argv = argv;
- /*@=dependenttrans =assignexpose@*/
+/*@=dependenttrans =assignexpose@*/
con->os->argb = NULL;
if (!(flags & POPT_CONTEXT_KEEP_FIRST))
- con->os->next = 1; /* skip argv[0] */
+ con->os->next = 1; /* skip argv[0] */
- con->leftovers = (const char **)calloc( (argc + 1),
- sizeof(*con->leftovers) );
- /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */
+ con->leftovers = calloc( (size_t)(argc + 1), sizeof(*con->leftovers) );
+/*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */
con->options = options;
- /*@=dependenttrans =assignexpose@*/
+/*@=dependenttrans =assignexpose@*/
con->aliases = NULL;
con->numAliases = 0;
con->flags = flags;
con->execs = NULL;
con->numExecs = 0;
con->finalArgvAlloced = argc * 2;
- con->finalArgv = (const char **)calloc( con->finalArgvAlloced,
- sizeof(*con->finalArgv) );
+ con->finalArgv = calloc( (size_t)con->finalArgvAlloced, sizeof(*con->finalArgv) );
con->execAbsolute = 1;
con->arg_strip = NULL;
if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER"))
con->flags |= POPT_CONTEXT_POSIXMEHARDER;
- if (name) {
- char * t = (char *)malloc(strlen(name) + 1);
- if (t) con->appName = strcpy(t, name);
- }
+ if (name)
+ con->appName = xstrdup(name);
- /*@-internalglobs@*/
invokeCallbacksPRE(con, con->options);
- /*@=internalglobs@*/
return con;
}
@@ -205,12 +213,11 @@ static void cleanOSE(/*@special@*/ struct optionStackEntry *os)
/*@releases os->nextArg, os->argv, os->argb @*/
/*@modifies os @*/
{
- os->nextArg = (const char *)_free(os->nextArg);
- os->argv = (const char **)_free(os->argv);
- os->argb = (pbm_set *)PBM_FREE(os->argb);
+ os->nextArg = _free(os->nextArg);
+ os->argv = _free(os->argv);
+ os->argb = PBM_FREE(os->argb);
}
-/*@-boundswrite@*/
void poptResetContext(poptContext con)
{
int i;
@@ -219,7 +226,7 @@ void poptResetContext(poptContext con)
while (con->os > con->optionStack) {
cleanOSE(con->os--);
}
- con->os->argb = (pbm_set *)PBM_FREE(con->os->argb);
+ con->os->argb = PBM_FREE(con->os->argb);
con->os->currAlias = NULL;
con->os->nextCharArg = NULL;
con->os->nextArg = NULL;
@@ -232,21 +239,19 @@ void poptResetContext(poptContext con)
if (con->finalArgv != NULL)
for (i = 0; i < con->finalArgvCount; i++) {
- /*@-unqualifiedtrans@*/ /* FIX: typedef double indirection. */
- con->finalArgv[i] = (const char *)_free(con->finalArgv[i]);
- /*@=unqualifiedtrans@*/
+/*@-unqualifiedtrans@*/ /* FIX: typedef double indirection. */
+ con->finalArgv[i] = _free(con->finalArgv[i]);
+/*@=unqualifiedtrans@*/
}
con->finalArgvCount = 0;
- con->arg_strip = ( pbm_set *)PBM_FREE(con->arg_strip);
- /*@-nullstate@*/ /* FIX: con->finalArgv != NULL */
+ con->arg_strip = PBM_FREE(con->arg_strip);
+/*@-nullstate@*/ /* FIX: con->finalArgv != NULL */
return;
- /*@=nullstate@*/
+/*@=nullstate@*/
}
-/*@=boundswrite@*/
/* Only one of longName, shortName should be set, not both. */
-/*@-boundswrite@*/
static int handleExec(/*@special@*/ poptContext con,
/*@null@*/ const char * longName, char shortName)
/*@uses con->execs, con->numExecs, con->flags, con->doExec,
@@ -283,33 +288,72 @@ static int handleExec(/*@special@*/ poptContext con,
time 'round */
if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) {
con->finalArgvAlloced += 10;
- con->finalArgv = (const char **)realloc(con->finalArgv,
+ con->finalArgv = realloc(con->finalArgv,
sizeof(*con->finalArgv) * con->finalArgvAlloced);
}
i = con->finalArgvCount++;
if (con->finalArgv != NULL) /* XXX can't happen */
- { char *s = (char *)malloc((longName ? strlen(longName) : 0) + 3);
+ { char *s = malloc((longName ? strlen(longName) : 0) + sizeof("--"));
if (s != NULL) { /* XXX can't happen */
+ con->finalArgv[i] = s;
+ *s++ = '-';
if (longName)
- sprintf(s, "--%s", longName);
+ s = stpcpy( stpcpy(s, "-"), longName);
else
- sprintf(s, "-%c", shortName);
- con->finalArgv[i] = s;
+ *s++ = shortName;
+ *s = '\0';
} else
con->finalArgv[i] = NULL;
}
- /*@-nullstate@*/ /* FIX: con->finalArgv[] == NULL */
return 1;
- /*@=nullstate@*/
}
-/*@=boundswrite@*/
+
+/**
+ * Compare long option for equality, adjusting for POPT_ARGFLAG_TOGGLE.
+ * @param opt option
+ * @param longName arg option
+ * @param longNameLen arg option length
+ * @return does long option match?
+ */
+static int
+longOptionStrcmp(const struct poptOption * opt,
+ /*@null@*/ const char * longName, size_t longNameLen)
+ /*@*/
+{
+ const char * optLongName = opt->longName;
+ int rc;
+
+ if (optLongName == NULL || longName == NULL) /* XXX can't heppen */
+ return 0;
+
+ if (F_ISSET(opt, TOGGLE)) {
+ if (optLongName[0] == 'n' && optLongName[1] == 'o') {
+ optLongName += sizeof("no") - 1;
+ if (optLongName[0] == '-')
+ optLongName++;
+ }
+ if (longName[0] == 'n' && longName[1] == 'o') {
+ longName += sizeof("no") - 1;
+ longNameLen -= sizeof("no") - 1;
+ if (longName[0] == '-') {
+ longName++;
+ longNameLen--;
+ }
+ }
+ }
+ rc = (int)(strlen(optLongName) == longNameLen);
+ if (rc)
+ rc = (int)(strncmp(optLongName, longName, longNameLen) == 0);
+ return rc;
+}
/* Only one of longName, shortName may be set at a time */
static int handleAlias(/*@special@*/ poptContext con,
- /*@null@*/ const char * longName, char shortName,
- /*@exposed@*/ /*@null@*/ const char * nextCharArg)
+ /*@null@*/ const char * longName, size_t longNameLen,
+ char shortName,
+ /*@exposed@*/ /*@null@*/ const char * nextArg)
/*@uses con->aliases, con->numAliases, con->optionStack, con->os,
con->os->currAlias, con->os->currAlias->option.longName @*/
/*@modifies con @*/
@@ -319,9 +363,10 @@ static int handleAlias(/*@special@*/ poptContext con,
int i;
if (item) {
- if (longName && (item->option.longName &&
- !strcmp(longName, item->option.longName)))
+ if (longName && item->option.longName != NULL
+ && longOptionStrcmp(&item->option, longName, longNameLen))
return 0;
+ else
if (shortName && shortName == item->option.shortName)
return 0;
}
@@ -331,10 +376,12 @@ static int handleAlias(/*@special@*/ poptContext con,
for (i = con->numAliases - 1; i >= 0; i--) {
item = con->aliases + i;
- if (longName && !(item->option.longName &&
- !strcmp(longName, item->option.longName)))
- continue;
- else if (shortName != item->option.shortName)
+ if (longName) {
+ if (item->option.longName == NULL)
+ continue;
+ if (!longOptionStrcmp(&item->option, longName, longNameLen))
+ continue;
+ } else if (shortName != item->option.shortName)
continue;
break;
}
@@ -343,10 +390,8 @@ static int handleAlias(/*@special@*/ poptContext con,
if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
return POPT_ERROR_OPTSTOODEEP;
-/*@-boundsread@*/
- if (nextCharArg && *nextCharArg)
- con->os->nextCharArg = nextCharArg;
-/*@=boundsread@*/
+ if (longName == NULL && nextArg != NULL && *nextArg != '\0')
+ con->os->nextCharArg = nextArg;
con->os++;
con->os->next = 0;
@@ -354,22 +399,89 @@ static int handleAlias(/*@special@*/ poptContext con,
con->os->nextArg = NULL;
con->os->nextCharArg = NULL;
con->os->currAlias = con->aliases + i;
- rc = poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv,
- &con->os->argc, &con->os->argv);
+ { const char ** av;
+ int ac = con->os->currAlias->argc;
+ /* Append --foo=bar arg to alias argv array (if present). */
+ if (longName && nextArg != NULL && *nextArg != '\0') {
+ av = malloc((ac + 1 + 1) * sizeof(*av));
+ if (av != NULL) { /* XXX won't happen. */
+ for (i = 0; i < ac; i++) {
+ av[i] = con->os->currAlias->argv[i];
+ }
+ av[ac++] = nextArg;
+ av[ac] = NULL;
+ } else /* XXX revert to old popt behavior if malloc fails. */
+ av = con->os->currAlias->argv;
+ } else
+ av = con->os->currAlias->argv;
+ rc = poptDupArgv(ac, av, &con->os->argc, &con->os->argv);
+ if (av != NULL && av != con->os->currAlias->argv)
+ free(av);
+ }
con->os->argb = NULL;
return (rc ? rc : 1);
}
-/*@-bounds -boundswrite @*/
+/**
+ * Return absolute path to executable by searching PATH.
+ * @param argv0 name of executable
+ * @return (malloc'd) absolute path to executable (or NULL)
+ */
+static /*@null@*/
+const char * findProgramPath(/*@null@*/ const char * argv0)
+ /*@*/
+{
+ char *path = NULL, *s = NULL, *se;
+ char *t = NULL;
+
+ if (argv0 == NULL) return NULL; /* XXX can't happen */
+
+ /* If there is a / in argv[0], it has to be an absolute path. */
+ /* XXX Hmmm, why not if (argv0[0] == '/') ... instead? */
+ if (strchr(argv0, '/'))
+ return xstrdup(argv0);
+
+ if ((path = getenv("PATH")) == NULL || (path = xstrdup(path)) == NULL)
+ return NULL;
+
+ /* The return buffer in t is big enough for any path. */
+ if ((t = malloc(strlen(path) + strlen(argv0) + sizeof("/"))) != NULL)
+ for (s = path; s && *s; s = se) {
+
+ /* Snip PATH element into [s,se). */
+ if ((se = strchr(s, ':')))
+ *se++ = '\0';
+
+ /* Append argv0 to PATH element. */
+ (void) stpcpy(stpcpy(stpcpy(t, s), "/"), argv0);
+
+ /* If file is executable, bingo! */
+ if (!access(t, X_OK))
+ break;
+ }
+
+ /* If no executable was found in PATH, return NULL. */
+/*@-compdef@*/
+ if (!(s && *s) && t != NULL)
+ t = _free(t);
+/*@=compdef@*/
+/*@-modobserver -observertrans -usedef @*/
+ path = _free(path);
+/*@=modobserver =observertrans =usedef @*/
+
+ return t;
+}
+
static int execCommand(poptContext con)
/*@globals internalState @*/
/*@modifies internalState @*/
{
poptItem item = con->doExec;
- const char ** argv;
+ poptArgv argv = NULL;
int argc = 0;
int rc;
+ int ec = POPT_ERROR_ERRNO;
if (item == NULL) /*XXX can't happen*/
return POPT_ERROR_NOARG;
@@ -378,19 +490,22 @@ static int execCommand(poptContext con)
(!con->execAbsolute && strchr(item->argv[0], '/')))
return POPT_ERROR_NOARG;
- argv = (const char **)malloc(
- sizeof(*argv) * (6 + item->argc + con->numLeftovers + con->finalArgvCount));
- if (argv == NULL) return POPT_ERROR_MALLOC; /* XXX can't happen */
+ argv = malloc(sizeof(*argv) *
+ (6 + item->argc + con->numLeftovers + con->finalArgvCount));
+ if (argv == NULL) return POPT_ERROR_MALLOC;
+
+ if (!strchr(item->argv[0], '/') && con->execPath != NULL) {
+ char *s = malloc(strlen(con->execPath) + strlen(item->argv[0]) + sizeof("/"));
+ if (s)
+ (void)stpcpy(stpcpy(stpcpy(s, con->execPath), "/"), item->argv[0]);
- if (!strchr(item->argv[0], '/') && con->execPath) {
- char *s = (char *)alloca(
- strlen(con->execPath) + strlen(item->argv[0]) + sizeof("/"));
- sprintf(s, "%s/%s", con->execPath, item->argv[0]);
argv[argc] = s;
- } else {
+ } else
argv[argc] = findProgramPath(item->argv[0]);
+ if (argv[argc++] == NULL) {
+ ec = POPT_ERROR_NOARG;
+ goto exit;
}
- if (argv[argc++] == NULL) return POPT_ERROR_NOARG;
if (item->argc > 1) {
memcpy(argv + argc, item->argv + 1, sizeof(*argv) * (item->argc - 1));
@@ -404,18 +519,17 @@ static int execCommand(poptContext con)
}
if (con->leftovers != NULL && con->numLeftovers > 0) {
-#if 0
- argv[argc++] = "--";
-#endif
memcpy(argv + argc, con->leftovers, sizeof(*argv) * con->numLeftovers);
argc += con->numLeftovers;
}
argv[argc] = NULL;
-#ifdef __hpux
+#if defined(hpux) || defined(__hpux)
+ rc = setresgid(getgid(), getgid(),-1);
+ if (rc) goto exit;
rc = setresuid(getuid(), getuid(),-1);
- if (rc) return POPT_ERROR_ERRNO;
+ if (rc) goto exit;
#else
/*
* XXX " ... on BSD systems setuid() should be preferred over setreuid()"
@@ -423,22 +537,23 @@ static int execCommand(poptContext con)
* XXX from Norbert Warmuth <nwarmuth@privat.circular.de>
*/
#if defined(HAVE_SETUID)
+ rc = setgid(getgid());
+ if (rc) goto exit;
rc = setuid(getuid());
- if (rc) return POPT_ERROR_ERRNO;
+ if (rc) goto exit;
#elif defined (HAVE_SETREUID)
- rc = setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */
- if (rc) return POPT_ERROR_ERRNO;
+ rc = setregid(getgid(), getgid());
+ if (rc) goto exit;
+ rc = setreuid(getuid(), getuid());
+ if (rc) goto exit;
#else
; /* Can't drop privileges */
#endif
#endif
- if (argv[0] == NULL)
- return POPT_ERROR_NOARG;
-
#ifdef MYDEBUG
if (_popt_debug)
- { const char ** avp;
+ { poptArgv avp;
fprintf(stderr, "==> execvp(%s) argv[%d]:", argv[0], argc);
for (avp = argv; *avp; avp++)
fprintf(stderr, " '%s'", *avp);
@@ -446,56 +561,68 @@ if (_popt_debug)
}
#endif
+/*@-nullstate@*/
rc = execvp(argv[0], (char *const *)argv);
- /* notreached */
- if (rc) {
- return POPT_ERROR_ERRNO;
+/*@=nullstate@*/
+
+exit:
+ if (argv) {
+ if (argv[0])
+ free((void *)argv[0]);
+ free(argv);
}
-
- return 0;
+ return ec;
}
-/*@=bounds =boundswrite @*/
-/*@-boundswrite@*/
-/*@observer@*/ /*@null@*/ static const struct poptOption *
-findOption(const struct poptOption * opt, /*@null@*/ const char * longName,
+/*@observer@*/ /*@null@*/
+static const struct poptOption *
+findOption(const struct poptOption * opt,
+ /*@null@*/ const char * longName, size_t longNameLen,
char shortName,
/*@null@*/ /*@out@*/ poptCallbackType * callback,
/*@null@*/ /*@out@*/ const void ** callbackData,
- int singleDash)
+ unsigned int argInfo)
/*@modifies *callback, *callbackData */
{
const struct poptOption * cb = NULL;
+ poptArg cbarg = { .ptr = NULL };
/* This happens when a single - is given */
- if (singleDash && !shortName && (longName && *longName == '\0'))
+ if (LF_ISSET(ONEDASH) && !shortName && (longName && *longName == '\0'))
shortName = '-';
for (; opt->longName || opt->shortName || opt->arg; opt++) {
+ poptArg arg = { .ptr = opt->arg };
- if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
- const struct poptOption * opt2;
+ switch (poptArgType(opt)) {
+ case POPT_ARG_INCLUDE_TABLE: /* Recurse on included sub-tables. */
+ { const struct poptOption * opt2;
- /* Recurse on included sub-tables. */
- if (opt->arg == NULL) continue; /* XXX program error */
- opt2 = findOption((const struct poptOption *)opt->arg, longName,
- shortName, callback,
- callbackData, singleDash);
+ poptSubstituteHelpI18N(arg.opt); /* XXX side effects */
+ if (arg.ptr == NULL) continue; /* XXX program error */
+ opt2 = findOption(arg.opt, longName, longNameLen, shortName, callback,
+ callbackData, argInfo);
if (opt2 == NULL) continue;
/* Sub-table data will be inheirited if no data yet. */
- if (!(callback && *callback)) return opt2;
- if (!(callbackData && *callbackData == NULL)) return opt2;
- /*@-observertrans -dependenttrans @*/
- *callbackData = opt->descrip;
- /*@=observertrans =dependenttrans @*/
+/*@-observertrans -dependenttrans @*/
+ if (callback && *callback
+ && callbackData && *callbackData == NULL)
+ *callbackData = opt->descrip;
+/*@=observertrans =dependenttrans @*/
return opt2;
- } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) {
+ } /*@notreached@*/ /*@switchbreak@*/ break;
+ case POPT_ARG_CALLBACK:
cb = opt;
- } else if (longName && opt->longName &&
- (!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) &&
- /*@-nullpass@*/ /* LCL: opt->longName != NULL */
- !strcmp(longName, opt->longName))
- /*@=nullpass@*/
+ cbarg.ptr = opt->arg;
+ continue;
+ /*@notreached@*/ /*@switchbreak@*/ break;
+ default:
+ /*@switchbreak@*/ break;
+ }
+
+ if (longName != NULL && opt->longName != NULL &&
+ (!LF_ISSET(ONEDASH) || F_ISSET(opt, ONEDASH)) &&
+ longOptionStrcmp(opt, longName, longNameLen))
{
break;
} else if (shortName && shortName == opt->shortName) {
@@ -503,28 +630,20 @@ findOption(const struct poptOption * opt, /*@null@*/ const char * longName,
}
}
- if (!opt->longName && !opt->shortName)
+ if (opt->longName == NULL && !opt->shortName)
return NULL;
- /*@-modobserver -mods @*/
- if (callback) *callback = NULL;
- if (callbackData) *callbackData = NULL;
- if (cb) {
- if (callback)
- /*@-castfcnptr@*/
- *callback = (poptCallbackType)cb->arg;
- /*@=castfcnptr@*/
- if (!(cb->argInfo & POPT_CBFLAG_INC_DATA)) {
- if (callbackData)
- /*@-observertrans@*/ /* FIX: typedef double indirection. */
- *callbackData = cb->descrip;
- /*@=observertrans@*/
- }
- }
- /*@=modobserver =mods @*/
+
+/*@-modobserver -mods @*/
+ if (callback)
+ *callback = (cb ? cbarg.cb : NULL);
+ if (callbackData)
+/*@-observertrans -dependenttrans @*/
+ *callbackData = (cb && !CBF_ISSET(cb, INC_DATA) ? cb->descrip : NULL);
+/*@=observertrans =dependenttrans @*/
+/*@=modobserver =mods @*/
return opt;
}
-/*@=boundswrite@*/
static const char * findNextArg(/*@special@*/ poptContext con,
unsigned argx, int delete_arg)
@@ -542,7 +661,7 @@ static const char * findNextArg(/*@special@*/ poptContext con,
if (os->next == os->argc && os == con->optionStack) break;
if (os->argv != NULL)
for (i = os->next; i < os->argc; i++) {
- /*@-sizeoftype@*/
+/*@-sizeoftype@*/
if (os->argb && PBM_ISSET(i, os->argb))
/*@innercontinue@*/ continue;
if (*os->argv[i] == '-')
@@ -551,19 +670,18 @@ static const char * findNextArg(/*@special@*/ poptContext con,
/*@innercontinue@*/ continue;
arg = os->argv[i];
if (delete_arg) {
- if (os->argb == NULL) os->argb = (pbm_set *)PBM_ALLOC(os->argc);
+ if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc);
if (os->argb != NULL) /* XXX can't happen */
- PBM_SET(i, os->argb);
+ PBM_SET(i, os->argb);
}
/*@innerbreak@*/ break;
- /*@=sizeoftype@*/
+/*@=sizeoftype@*/
}
if (os > con->optionStack) os--;
} while (arg == NULL);
return arg;
}
-/*@-boundswrite@*/
static /*@only@*/ /*@null@*/ const char *
expandNextArg(/*@special@*/ poptContext con, const char * s)
/*@uses con->optionStack, con->os,
@@ -571,13 +689,13 @@ expandNextArg(/*@special@*/ poptContext con, const char * s)
/*@modifies con @*/
{
const char * a = NULL;
- size_t alen;
char *t, *te;
size_t tn = strlen(s) + 1;
char c;
- te = t = (char *)malloc(tn);;
+ te = t = malloc(tn);
if (t == NULL) return NULL; /* XXX can't happen */
+ *t = '\0';
while ((c = *s++) != '\0') {
switch (c) {
#if 0 /* XXX can't do this */
@@ -590,17 +708,17 @@ expandNextArg(/*@special@*/ poptContext con, const char * s)
/*@switchbreak@*/ break;
/* XXX Make sure that findNextArg deletes only next arg. */
if (a == NULL) {
- if ((a = findNextArg(con, 1, 1)) == NULL)
+ if ((a = findNextArg(con, 1U, 1)) == NULL)
/*@switchbreak@*/ break;
}
- s += 3;
-
- alen = strlen(a);
- tn += alen;
- *te = '\0';
- t = (char *)realloc(t, tn);
- te = t + strlen(t);
- strncpy(te, a, alen); te += alen;
+ s += sizeof("#:+") - 1;
+
+ tn += strlen(a);
+ { size_t pos = (size_t) (te - t);
+ if ((t = realloc(t, tn)) == NULL) /* XXX can't happen */
+ return NULL;
+ te = stpcpy(t + pos, a);
+ }
continue;
/*@notreached@*/ /*@switchbreak@*/ break;
default:
@@ -608,48 +726,292 @@ expandNextArg(/*@special@*/ poptContext con, const char * s)
}
*te++ = c;
}
- *te = '\0';
- t = (char *)realloc(t, strlen(t) + 1); /* XXX memory leak, hard to plug */
+ *te++ = '\0';
+ /* If the new string is longer than needed, shorten. */
+ if ((t + tn) > te) {
+/*@-usereleased@*/ /* XXX splint can't follow the pointers. */
+ if ((te = realloc(t, (size_t)(te - t))) == NULL)
+ free(t);
+ t = te;
+/*@=usereleased@*/
+ }
return t;
}
-/*@=boundswrite@*/
static void poptStripArg(/*@special@*/ poptContext con, int which)
- /*@uses con->arg_strip, con->optionStack @*/
+ /*@uses con->optionStack @*/
/*@defines con->arg_strip @*/
/*@modifies con @*/
{
- /*@-sizeoftype@*/
+/*@-compdef -sizeoftype -usedef @*/
if (con->arg_strip == NULL)
- con->arg_strip = (pbm_set *)PBM_ALLOC(con->optionStack[0].argc);
+ con->arg_strip = PBM_ALLOC(con->optionStack[0].argc);
if (con->arg_strip != NULL) /* XXX can't happen */
PBM_SET(which, con->arg_strip);
- /*@=sizeoftype@*/
- /*@-compdef@*/ /* LCL: con->arg_strip udefined? */
return;
- /*@=compdef@*/
+/*@=compdef =sizeoftype =usedef @*/
+}
+
+/*@unchecked@*/
+unsigned int _poptBitsN = _POPT_BITS_N;
+/*@unchecked@*/
+unsigned int _poptBitsM = _POPT_BITS_M;
+/*@unchecked@*/
+unsigned int _poptBitsK = _POPT_BITS_K;
+
+/*@-sizeoftype@*/
+static int _poptBitsNew(/*@null@*/ poptBits *bitsp)
+ /*@globals _poptBitsN, _poptBitsM, _poptBitsK @*/
+ /*@modifies *bitsp, _poptBitsN, _poptBitsM, _poptBitsK @*/
+{
+ if (bitsp == NULL)
+ return POPT_ERROR_NULLARG;
+
+ /* XXX handle negated initialization. */
+ if (*bitsp == NULL) {
+ if (_poptBitsN == 0) {
+ _poptBitsN = _POPT_BITS_N;
+ _poptBitsM = _POPT_BITS_M;
+ }
+ if (_poptBitsM == 0U) _poptBitsM = (3 * _poptBitsN) / 2;
+ if (_poptBitsK == 0U || _poptBitsK > 32U) _poptBitsK = _POPT_BITS_K;
+ *bitsp = PBM_ALLOC(_poptBitsM-1);
+ }
+/*@-nullstate@*/
+ return 0;
+/*@=nullstate@*/
+}
+
+int poptBitsAdd(poptBits bits, const char * s)
+{
+ size_t ns = (s ? strlen(s) : 0);
+ uint32_t h0 = 0;
+ uint32_t h1 = 0;
+
+ if (bits == NULL || ns == 0)
+ return POPT_ERROR_NULLARG;
+
+ poptJlu32lpair(s, ns, &h0, &h1);
+
+ for (ns = 0; ns < (size_t)_poptBitsK; ns++) {
+ uint32_t h = h0 + ns * h1;
+ uint32_t ix = (h % _poptBitsM);
+ PBM_SET(ix, bits);
+ }
+ return 0;
}
-int poptSaveLong(long * arg, int argInfo, long aLong)
+int poptBitsChk(poptBits bits, const char * s)
{
+ size_t ns = (s ? strlen(s) : 0);
+ uint32_t h0 = 0;
+ uint32_t h1 = 0;
+ int rc = 1;
+
+ if (bits == NULL || ns == 0)
+ return POPT_ERROR_NULLARG;
+
+ poptJlu32lpair(s, ns, &h0, &h1);
+
+ for (ns = 0; ns < (size_t)_poptBitsK; ns++) {
+ uint32_t h = h0 + ns * h1;
+ uint32_t ix = (h % _poptBitsM);
+ if (PBM_ISSET(ix, bits))
+ continue;
+ rc = 0;
+ break;
+ }
+ return rc;
+}
+
+int poptBitsClr(poptBits bits)
+{
+ static size_t nbw = (__PBM_NBITS/8);
+ size_t nw = (__PBM_IX(_poptBitsM-1) + 1);
+
+ if (bits == NULL)
+ return POPT_ERROR_NULLARG;
+ memset(bits, 0, nw * nbw);
+ return 0;
+}
+
+int poptBitsDel(poptBits bits, const char * s)
+{
+ size_t ns = (s ? strlen(s) : 0);
+ uint32_t h0 = 0;
+ uint32_t h1 = 0;
+
+ if (bits == NULL || ns == 0)
+ return POPT_ERROR_NULLARG;
+
+ poptJlu32lpair(s, ns, &h0, &h1);
+
+ for (ns = 0; ns < (size_t)_poptBitsK; ns++) {
+ uint32_t h = h0 + ns * h1;
+ uint32_t ix = (h % _poptBitsM);
+ PBM_CLR(ix, bits);
+ }
+ return 0;
+}
+
+int poptBitsIntersect(poptBits *ap, const poptBits b)
+{
+ __pbm_bits *abits;
+ __pbm_bits *bbits;
+ __pbm_bits rc = 0;
+ size_t nw = (__PBM_IX(_poptBitsM-1) + 1);
+ size_t i;
+
+ if (ap == NULL || b == NULL || _poptBitsNew(ap))
+ return POPT_ERROR_NULLARG;
+ abits = __PBM_BITS(*ap);
+ bbits = __PBM_BITS(b);
+
+ for (i = 0; i < nw; i++) {
+ abits[i] &= bbits[i];
+ rc |= abits[i];
+ }
+ return (rc ? 1 : 0);
+}
+
+int poptBitsUnion(poptBits *ap, const poptBits b)
+{
+ __pbm_bits *abits;
+ __pbm_bits *bbits;
+ __pbm_bits rc = 0;
+ size_t nw = (__PBM_IX(_poptBitsM-1) + 1);
+ size_t i;
+
+ if (ap == NULL || b == NULL || _poptBitsNew(ap))
+ return POPT_ERROR_NULLARG;
+ abits = __PBM_BITS(*ap);
+ bbits = __PBM_BITS(b);
+
+ for (i = 0; i < nw; i++) {
+ abits[i] |= bbits[i];
+ rc |= abits[i];
+ }
+ return (rc ? 1 : 0);
+}
+
+int poptBitsArgs(poptContext con, poptBits *ap)
+{
+ const char ** av;
+ int rc = 0;
+
+ if (con == NULL || ap == NULL || _poptBitsNew(ap) ||
+ con->leftovers == NULL || con->numLeftovers == con->nextLeftover)
+ return POPT_ERROR_NULLARG;
+
+ /* some apps like [like RPM ;-) ] need this NULL terminated */
+ con->leftovers[con->numLeftovers] = NULL;
+
+ for (av = con->leftovers + con->nextLeftover; *av != NULL; av++) {
+ if ((rc = poptBitsAdd(*ap, *av)) != 0)
+ break;
+ }
+/*@-nullstate@*/
+ return rc;
+/*@=nullstate@*/
+}
+
+int poptSaveBits(poptBits * bitsp,
+ /*@unused@*/ UNUSED(unsigned int argInfo), const char * s)
+{
+ char *tbuf = NULL;
+ char *t, *te;
+ int rc = 0;
+
+ if (bitsp == NULL || s == NULL || *s == '\0' || _poptBitsNew(bitsp))
+ return POPT_ERROR_NULLARG;
+
+ /* Parse comma separated attributes. */
+ te = tbuf = xstrdup(s);
+ while ((t = te) != NULL && *t) {
+ while (*te != '\0' && *te != ',')
+ te++;
+ if (*te != '\0')
+ *te++ = '\0';
+ /* XXX Ignore empty strings. */
+ if (*t == '\0')
+ continue;
+ /* XXX Permit negated attributes. caveat emptor: false negatives. */
+ if (*t == '!') {
+ t++;
+ if ((rc = poptBitsChk(*bitsp, t)) > 0)
+ rc = poptBitsDel(*bitsp, t);
+ } else
+ rc = poptBitsAdd(*bitsp, t);
+ if (rc)
+ break;
+ }
+ tbuf = _free(tbuf);
+ return rc;
+}
+/*@=sizeoftype@*/
+
+int poptSaveString(const char *** argvp,
+ /*@unused@*/ UNUSED(unsigned int argInfo), const char * val)
+{
+ int argc = 0;
+
+ if (argvp == NULL || val == NULL)
+ return POPT_ERROR_NULLARG;
+
+ /* XXX likely needs an upper bound on argc. */
+ if (*argvp != NULL)
+ while ((*argvp)[argc] != NULL)
+ argc++;
+
+/*@-unqualifiedtrans -nullstate@*/ /* XXX no annotation for (*argvp) */
+ if ((*argvp = xrealloc(*argvp, (argc + 1 + 1) * sizeof(**argvp))) != NULL) {
+ (*argvp)[argc++] = xstrdup(val);
+ (*argvp)[argc ] = NULL;
+ }
+ return 0;
+/*@=unqualifiedtrans =nullstate@*/
+}
+
+/*@unchecked@*/
+static unsigned int seed = 0;
+
+int poptSaveLongLong(long long * arg, unsigned int argInfo, long long aLongLong)
+{
+ if (arg == NULL
+#ifdef NOTYET
/* XXX Check alignment, may fail on funky platforms. */
- if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
+ || (((unsigned long long)arg) & (sizeof(*arg)-1))
+#endif
+ )
return POPT_ERROR_NULLARG;
- if (argInfo & POPT_ARGFLAG_NOT)
- aLong = ~aLong;
- switch (argInfo & POPT_ARGFLAG_LOGICALOPS) {
+ if (aLongLong != 0 && LF_ISSET(RANDOM)) {
+#if defined(HAVE_SRANDOM)
+ if (!seed) {
+ srandom((unsigned)getpid());
+ srandom((unsigned)random());
+ }
+ aLongLong = (long long)(random() % (aLongLong > 0 ? aLongLong : -aLongLong));
+ aLongLong++;
+#else
+ /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */
+ return POPT_ERROR_BADOPERATION;
+#endif
+ }
+ if (LF_ISSET(NOT))
+ aLongLong = ~aLongLong;
+ switch (LF_ISSET(LOGICALOPS)) {
case 0:
- *arg = aLong;
+ *arg = aLongLong;
break;
case POPT_ARGFLAG_OR:
- *arg |= aLong;
+ *(unsigned long long *)arg |= (unsigned long long)aLongLong;
break;
case POPT_ARGFLAG_AND:
- *arg &= aLong;
+ *(unsigned long long *)arg &= (unsigned long long)aLongLong;
break;
case POPT_ARGFLAG_XOR:
- *arg ^= aLong;
+ *(unsigned long long *)arg ^= (unsigned long long)aLongLong;
break;
default:
return POPT_ERROR_BADOPERATION;
@@ -658,35 +1020,281 @@ int poptSaveLong(long * arg, int argInfo, long aLong)
return 0;
}
-int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong)
+int poptSaveLong(long * arg, unsigned int argInfo, long aLong)
{
/* XXX Check alignment, may fail on funky platforms. */
if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
return POPT_ERROR_NULLARG;
- if (argInfo & POPT_ARGFLAG_NOT)
+ if (aLong != 0 && LF_ISSET(RANDOM)) {
+#if defined(HAVE_SRANDOM)
+ if (!seed) {
+ srandom((unsigned)getpid());
+ srandom((unsigned)random());
+ }
+ aLong = random() % (aLong > 0 ? aLong : -aLong);
+ aLong++;
+#else
+ /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */
+ return POPT_ERROR_BADOPERATION;
+#endif
+ }
+ if (LF_ISSET(NOT))
aLong = ~aLong;
- switch (argInfo & POPT_ARGFLAG_LOGICALOPS) {
- case 0:
- *arg = aLong;
+ switch (LF_ISSET(LOGICALOPS)) {
+ case 0: *arg = aLong; break;
+ case POPT_ARGFLAG_OR: *(unsigned long *)arg |= (unsigned long)aLong; break;
+ case POPT_ARGFLAG_AND: *(unsigned long *)arg &= (unsigned long)aLong; break;
+ case POPT_ARGFLAG_XOR: *(unsigned long *)arg ^= (unsigned long)aLong; break;
+ default:
+ return POPT_ERROR_BADOPERATION;
+ /*@notreached@*/ break;
+ }
+ return 0;
+}
+
+int poptSaveInt(/*@null@*/ int * arg, unsigned int argInfo, long aLong)
+{
+ /* XXX Check alignment, may fail on funky platforms. */
+ if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
+ return POPT_ERROR_NULLARG;
+
+ if (aLong != 0 && LF_ISSET(RANDOM)) {
+#if defined(HAVE_SRANDOM)
+ if (!seed) {
+ srandom((unsigned)getpid());
+ srandom((unsigned)random());
+ }
+ aLong = random() % (aLong > 0 ? aLong : -aLong);
+ aLong++;
+#else
+ /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */
+ return POPT_ERROR_BADOPERATION;
+#endif
+ }
+ if (LF_ISSET(NOT))
+ aLong = ~aLong;
+ switch (LF_ISSET(LOGICALOPS)) {
+ case 0: *arg = (int) aLong; break;
+ case POPT_ARGFLAG_OR: *(unsigned int *)arg |= (unsigned int) aLong; break;
+ case POPT_ARGFLAG_AND: *(unsigned int *)arg &= (unsigned int) aLong; break;
+ case POPT_ARGFLAG_XOR: *(unsigned int *)arg ^= (unsigned int) aLong; break;
+ default:
+ return POPT_ERROR_BADOPERATION;
+ /*@notreached@*/ break;
+ }
+ return 0;
+}
+
+int poptSaveShort(/*@null@*/ short * arg, unsigned int argInfo, long aLong)
+{
+ /* XXX Check alignment, may fail on funky platforms. */
+ if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1)))
+ return POPT_ERROR_NULLARG;
+
+ if (aLong != 0 && LF_ISSET(RANDOM)) {
+#if defined(HAVE_SRANDOM)
+ if (!seed) {
+ srandom((unsigned)getpid());
+ srandom((unsigned)random());
+ }
+ aLong = random() % (aLong > 0 ? aLong : -aLong);
+ aLong++;
+#else
+ /* XXX avoid adding POPT_ERROR_UNIMPLEMENTED to minimize i18n churn. */
+ return POPT_ERROR_BADOPERATION;
+#endif
+ }
+ if (LF_ISSET(NOT))
+ aLong = ~aLong;
+ switch (LF_ISSET(LOGICALOPS)) {
+ case 0: *arg = (short) aLong;
break;
- case POPT_ARGFLAG_OR:
- *arg |= aLong;
+ case POPT_ARGFLAG_OR: *(unsigned short *)arg |= (unsigned short) aLong;
break;
- case POPT_ARGFLAG_AND:
- *arg &= aLong;
+ case POPT_ARGFLAG_AND: *(unsigned short *)arg &= (unsigned short) aLong;
break;
- case POPT_ARGFLAG_XOR:
- *arg ^= aLong;
+ case POPT_ARGFLAG_XOR: *(unsigned short *)arg ^= (unsigned short) aLong;
break;
- default:
- return POPT_ERROR_BADOPERATION;
+ default: return POPT_ERROR_BADOPERATION;
/*@notreached@*/ break;
}
return 0;
}
-/*@-boundswrite@*/
+/**
+ * Return argInfo field, handling POPT_ARGFLAG_TOGGLE overrides.
+ * @param con context
+ * @param opt option
+ * @return argInfo
+ */
+static unsigned int poptArgInfo(poptContext con, const struct poptOption * opt)
+ /*@*/
+{
+ unsigned int argInfo = opt->argInfo;
+
+ if (con->os->argv != NULL && con->os->next > 0 && opt->longName != NULL)
+ if (LF_ISSET(TOGGLE)) {
+ const char * longName = con->os->argv[con->os->next-1];
+ while (*longName == '-') longName++;
+ /* XXX almost good enough but consider --[no]nofoo corner cases. */
+ if (longName[0] != opt->longName[0] || longName[1] != opt->longName[1])
+ {
+ if (!LF_ISSET(XOR)) { /* XXX dont toggle with XOR */
+ /* Toggle POPT_BIT_SET <=> POPT_BIT_CLR. */
+ if (LF_ISSET(LOGICALOPS))
+ argInfo ^= (POPT_ARGFLAG_OR|POPT_ARGFLAG_AND);
+ argInfo ^= POPT_ARGFLAG_NOT;
+ }
+ }
+ }
+ return argInfo;
+}
+
+/**
+ * Parse an integer expression.
+ * @retval *llp integer expression value
+ * @param argInfo integer expression type
+ * @param val integer expression string
+ * @return 0 on success, otherwise POPT_* error.
+ */
+static int poptParseInteger(long long * llp,
+ /*@unused@*/ UNUSED(unsigned int argInfo),
+ /*@null@*/ const char * val)
+ /*@modifies *llp @*/
+{
+ if (val) {
+ char *end = NULL;
+ *llp = strtoll(val, &end, 0);
+
+ /* XXX parse scaling suffixes here. */
+
+ if (!(end && *end == '\0'))
+ return POPT_ERROR_BADNUMBER;
+ } else
+ *llp = 0;
+ return 0;
+}
+
+/**
+ * Save the option argument through the (*opt->arg) pointer.
+ * @param con context
+ * @param opt option
+ * @return 0 on success, otherwise POPT_* error.
+ */
+static int poptSaveArg(poptContext con, const struct poptOption * opt)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies con, fileSystem, internalState @*/
+{
+ poptArg arg = { .ptr = opt->arg };
+ int rc = 0; /* assume success */
+
+ switch (poptArgType(opt)) {
+ case POPT_ARG_BITSET:
+ /* XXX memory leak, application is responsible for free. */
+ rc = poptSaveBits(arg.ptr, opt->argInfo, con->os->nextArg);
+ /*@switchbreak@*/ break;
+ case POPT_ARG_ARGV:
+ /* XXX memory leak, application is responsible for free. */
+ rc = poptSaveString(arg.ptr, opt->argInfo, con->os->nextArg);
+ /*@switchbreak@*/ break;
+ case POPT_ARG_STRING:
+ /* XXX memory leak, application is responsible for free. */
+ arg.argv[0] = (con->os->nextArg) ? xstrdup(con->os->nextArg) : NULL;
+ /*@switchbreak@*/ break;
+
+ case POPT_ARG_INT:
+ case POPT_ARG_SHORT:
+ case POPT_ARG_LONG:
+ case POPT_ARG_LONGLONG:
+ { unsigned int argInfo = poptArgInfo(con, opt);
+ long long aNUM = 0;
+
+ if ((rc = poptParseInteger(&aNUM, argInfo, con->os->nextArg)) != 0)
+ break;
+
+ switch (poptArgType(opt)) {
+ case POPT_ARG_LONGLONG:
+/* XXX let's not demand C99 compiler flags for <limits.h> quite yet. */
+#if !defined(LLONG_MAX)
+# define LLONG_MAX 9223372036854775807LL
+# define LLONG_MIN (-LLONG_MAX - 1LL)
+#endif
+ rc = !(aNUM == LLONG_MIN || aNUM == LLONG_MAX)
+ ? poptSaveLongLong(arg.longlongp, argInfo, aNUM)
+ : POPT_ERROR_OVERFLOW;
+ /*@innerbreak@*/ break;
+ case POPT_ARG_LONG:
+ rc = !(aNUM < (long long)LONG_MIN || aNUM > (long long)LONG_MAX)
+ ? poptSaveLong(arg.longp, argInfo, (long)aNUM)
+ : POPT_ERROR_OVERFLOW;
+ /*@innerbreak@*/ break;
+ case POPT_ARG_INT:
+ rc = !(aNUM < (long long)INT_MIN || aNUM > (long long)INT_MAX)
+ ? poptSaveInt(arg.intp, argInfo, (long)aNUM)
+ : POPT_ERROR_OVERFLOW;
+ /*@innerbreak@*/ break;
+ case POPT_ARG_SHORT:
+ rc = !(aNUM < (long long)SHRT_MIN || aNUM > (long long)SHRT_MAX)
+ ? poptSaveShort(arg.shortp, argInfo, (long)aNUM)
+ : POPT_ERROR_OVERFLOW;
+ /*@innerbreak@*/ break;
+ }
+ } /*@switchbreak@*/ break;
+
+ case POPT_ARG_FLOAT:
+ case POPT_ARG_DOUBLE:
+ { char *end = NULL;
+ double aDouble = 0.0;
+
+ if (con->os->nextArg) {
+/*@-mods@*/
+ int saveerrno = errno;
+ errno = 0;
+ aDouble = strtod(con->os->nextArg, &end);
+ if (errno == ERANGE) {
+ rc = POPT_ERROR_OVERFLOW;
+ break;
+ }
+ errno = saveerrno;
+/*@=mods@*/
+ if (*end != '\0') {
+ rc = POPT_ERROR_BADNUMBER;
+ break;
+ }
+ }
+
+ switch (poptArgType(opt)) {
+ case POPT_ARG_DOUBLE:
+ arg.doublep[0] = aDouble;
+ /*@innerbreak@*/ break;
+ case POPT_ARG_FLOAT:
+#if !defined(DBL_EPSILON) && !defined(__LCLINT__)
+#define DBL_EPSILON 2.2204460492503131e-16
+#endif
+#define POPT_ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
+ if ((FLT_MIN - POPT_ABS(aDouble)) > DBL_EPSILON
+ || (POPT_ABS(aDouble) - FLT_MAX) > DBL_EPSILON)
+ rc = POPT_ERROR_OVERFLOW;
+ else
+ arg.floatp[0] = (float) aDouble;
+ /*@innerbreak@*/ break;
+ }
+ } /*@switchbreak@*/ break;
+ case POPT_ARG_MAINCALL:
+/*@-assignexpose -type@*/
+ con->maincall = opt->arg;
+/*@=assignexpose =type@*/
+ /*@switchbreak@*/ break;
+ default:
+ fprintf(stdout, POPT_("option type (%u) not implemented in popt\n"),
+ poptArgType(opt));
+ exit(EXIT_FAILURE);
+ /*@notreached@*/ /*@switchbreak@*/ break;
+ }
+ return rc;
+}
+
/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
int poptGetNextOpt(poptContext con)
{
@@ -708,24 +1316,31 @@ int poptGetNextOpt(poptContext con)
cleanOSE(con->os--);
}
if (!con->os->nextCharArg && con->os->next == con->os->argc) {
- /*@-internalglobs@*/
invokeCallbacksPOST(con, con->options);
- /*@=internalglobs@*/
+
+ if (con->maincall) {
+ /*@-noeffectuncon @*/
+ (void) (*con->maincall) (con->finalArgvCount, con->finalArgv);
+ /*@=noeffectuncon @*/
+ return -1;
+ }
+
if (con->doExec) return execCommand(con);
return -1;
}
/* Process next long option */
if (!con->os->nextCharArg) {
- char * localOptString, * optString;
+ const char * optString;
+ size_t optStringLen;
int thisopt;
- /*@-sizeoftype@*/
+/*@-sizeoftype@*/
if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) {
con->os->next++;
continue;
}
- /*@=sizeoftype@*/
+/*@=sizeoftype@*/
thisopt = con->os->next;
if (con->os->argv != NULL) /* XXX can't happen */
origOptString = con->os->argv[con->os->next++];
@@ -733,7 +1348,9 @@ int poptGetNextOpt(poptContext con)
if (origOptString == NULL) /* XXX can't happen */
return POPT_ERROR_BADOPT;
- if (con->restLeftover || *origOptString != '-') {
+ if (con->restLeftover || *origOptString != '-' ||
+ (*origOptString == '-' && origOptString[1] == '\0'))
+ {
if (con->flags & POPT_CONTEXT_POSIXMEHARDER)
con->restLeftover = 1;
if (con->flags & POPT_CONTEXT_ARG_OPTS) {
@@ -746,9 +1363,7 @@ int poptGetNextOpt(poptContext con)
}
/* Make a copy we can hack at */
- localOptString = optString =
- strcpy((char *)alloca(strlen(origOptString) + 1),
- origOptString);
+ optString = origOptString;
if (optString[0] == '\0')
return POPT_ERROR_BADOPT;
@@ -757,42 +1372,42 @@ int poptGetNextOpt(poptContext con)
con->restLeftover = 1;
continue;
} else {
- char *oe;
- int singleDash;
+ const char *oe;
+ unsigned int argInfo = 0;
optString++;
if (*optString == '-')
- singleDash = 0, optString++;
+ optString++;
else
- singleDash = 1;
+ argInfo |= POPT_ARGFLAG_ONEDASH;
+
+ /* Check for "--long=arg" option. */
+ for (oe = optString; *oe && *oe != '='; oe++)
+ {};
+ optStringLen = (size_t)(oe - optString);
+ if (*oe == '=')
+ longArg = oe + 1;
/* XXX aliases with arg substitution need "--alias=arg" */
- if (handleAlias(con, optString, '\0', NULL))
+ if (handleAlias(con, optString, optStringLen, '\0', longArg)) {
+ longArg = NULL;
continue;
+ }
if (handleExec(con, optString, '\0'))
continue;
- /* Check for "--long=arg" option. */
- for (oe = optString; *oe && *oe != '='; oe++)
- {};
- if (*oe == '=') {
- *oe++ = '\0';
- /* XXX longArg is mapped back to persistent storage. */
- longArg = origOptString + (oe - localOptString);
- }
-
- opt = findOption(con->options, optString, '\0', &cb, &cbData,
- singleDash);
- if (!opt && !singleDash)
+ opt = findOption(con->options, optString, optStringLen, '\0', &cb, &cbData,
+ argInfo);
+ if (!opt && !LF_ISSET(ONEDASH))
return POPT_ERROR_BADOPT;
}
if (!opt) {
con->os->nextCharArg = origOptString + 1;
+ longArg = NULL;
} else {
- if (con->os == con->optionStack &&
- opt->argInfo & POPT_ARGFLAG_STRIP)
+ if (con->os == con->optionStack && F_ISSET(opt, STRIP))
{
canstrip = 1;
poptStripArg(con, thisopt);
@@ -802,65 +1417,64 @@ int poptGetNextOpt(poptContext con)
}
/* Process next short option */
- /*@-branchstate@*/ /* FIX: W2DO? */
if (con->os->nextCharArg) {
- origOptString = con->os->nextCharArg;
+ const char * nextCharArg = con->os->nextCharArg;
con->os->nextCharArg = NULL;
- if (handleAlias(con, NULL, *origOptString, origOptString + 1))
+ if (handleAlias(con, NULL, 0, *nextCharArg, nextCharArg + 1))
continue;
- if (handleExec(con, NULL, *origOptString)) {
+ if (handleExec(con, NULL, *nextCharArg)) {
/* Restore rest of short options for further processing */
- origOptString++;
- if (*origOptString != '\0')
- con->os->nextCharArg = origOptString;
+ nextCharArg++;
+ if (*nextCharArg != '\0')
+ con->os->nextCharArg = nextCharArg;
continue;
}
- opt = findOption(con->options, NULL, *origOptString, &cb,
+ opt = findOption(con->options, NULL, 0, *nextCharArg, &cb,
&cbData, 0);
if (!opt)
return POPT_ERROR_BADOPT;
shorty = 1;
- origOptString++;
- if (*origOptString != '\0')
- con->os->nextCharArg = origOptString;
+ nextCharArg++;
+ if (*nextCharArg != '\0')
+ con->os->nextCharArg = nextCharArg + (int)(*nextCharArg == '=');
}
- /*@=branchstate@*/
if (opt == NULL) return POPT_ERROR_BADOPT; /* XXX can't happen */
- if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) {
- if (poptSaveInt((int *)opt->arg, opt->argInfo, 1L))
+ if (opt->arg && poptArgType(opt) == POPT_ARG_NONE) {
+ unsigned int argInfo = poptArgInfo(con, opt);
+ if (poptSaveInt((int *)opt->arg, argInfo, 1L))
return POPT_ERROR_BADOPERATION;
- } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) {
+ } else if (poptArgType(opt) == POPT_ARG_VAL) {
if (opt->arg) {
- if (poptSaveInt((int *)opt->arg, opt->argInfo, (long)opt->val))
+ unsigned int argInfo = poptArgInfo(con, opt);
+ if (poptSaveInt((int *)opt->arg, argInfo, (long)opt->val))
return POPT_ERROR_BADOPERATION;
}
- } else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
- con->os->nextArg = (const char *)_free(con->os->nextArg);
- /*@-usedef@*/ /* FIX: W2DO? */
+ } else if (poptArgType(opt) != POPT_ARG_NONE) {
+ int rc;
+
+ con->os->nextArg = _free(con->os->nextArg);
if (longArg) {
- /*@=usedef@*/
longArg = expandNextArg(con, longArg);
- con->os->nextArg = longArg;
+ con->os->nextArg = (char *) longArg;
} else if (con->os->nextCharArg) {
longArg = expandNextArg(con, con->os->nextCharArg);
- con->os->nextArg = longArg;
+ con->os->nextArg = (char *) longArg;
con->os->nextCharArg = NULL;
} else {
while (con->os->next == con->os->argc &&
- con->os > con->optionStack) {
+ con->os > con->optionStack)
+ {
cleanOSE(con->os--);
}
if (con->os->next == con->os->argc) {
- if (!(opt->argInfo & POPT_ARGFLAG_OPTIONAL))
- /*@-compdef@*/ /* FIX: con->os->argv not defined */
+ if (!F_ISSET(opt, OPTIONAL))
return POPT_ERROR_NOARG;
- /*@=compdef@*/
con->os->nextArg = NULL;
} else {
@@ -868,149 +1482,81 @@ int poptGetNextOpt(poptContext con)
* Make sure this isn't part of a short arg or the
* result of an alias expansion.
*/
- if (con->os == con->optionStack &&
- (opt->argInfo & POPT_ARGFLAG_STRIP) &&
- canstrip) {
+ if (con->os == con->optionStack
+ && F_ISSET(opt, STRIP) && canstrip)
+ {
poptStripArg(con, con->os->next);
}
if (con->os->argv != NULL) { /* XXX can't happen */
- /* XXX watchout: subtle side-effects live here. */
- longArg = con->os->argv[con->os->next++];
- longArg = expandNextArg(con, longArg);
- con->os->nextArg = longArg;
+ if (F_ISSET(opt, OPTIONAL) &&
+ con->os->argv[con->os->next][0] == '-') {
+ con->os->nextArg = NULL;
+ } else {
+ /* XXX watchout: subtle side-effects live here. */
+ longArg = con->os->argv[con->os->next++];
+ longArg = expandNextArg(con, longArg);
+ con->os->nextArg = (char *) longArg;
+ }
}
}
}
longArg = NULL;
- if (opt->arg) {
- switch (opt->argInfo & POPT_ARG_MASK) {
- case POPT_ARG_STRING:
- /* XXX memory leak, hard to plug */
- *((const char **) opt->arg) = (con->os->nextArg)
- ? xstrdup(con->os->nextArg) : NULL;
- /*@switchbreak@*/ break;
-
- case POPT_ARG_INT:
- case POPT_ARG_LONG:
- { long aLong = 0;
- char *end;
-
- if (con->os->nextArg) {
- aLong = strtol(con->os->nextArg, &end, 0);
- if (!(end && *end == '\0'))
- return POPT_ERROR_BADNUMBER;
- }
-
- if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) {
- if (aLong == LONG_MIN || aLong == LONG_MAX)
- return POPT_ERROR_OVERFLOW;
- if (poptSaveLong((long *)opt->arg, opt->argInfo, aLong))
- return POPT_ERROR_BADOPERATION;
- } else {
- if (aLong > INT_MAX || aLong < INT_MIN)
- return POPT_ERROR_OVERFLOW;
- if (poptSaveInt((int *)opt->arg, opt->argInfo, aLong))
- return POPT_ERROR_BADOPERATION;
- }
- } /*@switchbreak@*/ break;
-
- case POPT_ARG_FLOAT:
- case POPT_ARG_DOUBLE:
- { double aDouble = 0.0;
- char *end;
-
- if (con->os->nextArg) {
- /*@-mods@*/
- int saveerrno = errno;
- errno = 0;
- aDouble = strtod(con->os->nextArg, &end);
- if (errno == ERANGE)
- return POPT_ERROR_OVERFLOW;
- errno = saveerrno;
- /*@=mods@*/
- if (*end != '\0')
- return POPT_ERROR_BADNUMBER;
- }
-
- if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_DOUBLE) {
- *((double *) opt->arg) = aDouble;
- } else {
-#ifndef _ABS
-#define _ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a))
-#endif
- if ((_ABS(aDouble) - FLT_MAX) > DBL_EPSILON)
- return POPT_ERROR_OVERFLOW;
- if ((FLT_MIN - _ABS(aDouble)) > DBL_EPSILON)
- return POPT_ERROR_OVERFLOW;
- *((float *) opt->arg) = aDouble;
- }
- } /*@switchbreak@*/ break;
- default:
- fprintf(stdout,
- POPT_("option type (%d) not implemented in popt\n"),
- (opt->argInfo & POPT_ARG_MASK));
- exit(EXIT_FAILURE);
- /*@notreached@*/ /*@switchbreak@*/ break;
- }
- }
+ /* Save the option argument through a (*opt->arg) pointer. */
+ if (opt->arg != NULL && (rc = poptSaveArg(con, opt)) != 0)
+ return rc;
}
- if (cb) {
- /*@-internalglobs@*/
+ if (cb)
invokeCallbacksOPTION(con, con->options, opt, cbData, shorty);
- /*@=internalglobs@*/
- } else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL))
+ else if (opt->val && (poptArgType(opt) != POPT_ARG_VAL))
done = 1;
if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) {
con->finalArgvAlloced += 10;
- con->finalArgv = (const char **)realloc(con->finalArgv,
+ con->finalArgv = realloc(con->finalArgv,
sizeof(*con->finalArgv) * con->finalArgvAlloced);
}
if (con->finalArgv != NULL)
- { char *s = (char *)malloc(
- (opt->longName ? strlen(opt->longName) : 0) + 3);
+ { char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + sizeof("--"));
if (s != NULL) { /* XXX can't happen */
- if (opt->longName)
- sprintf(s, "%s%s",
- ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
- opt->longName);
- else
- sprintf(s, "-%c", opt->shortName);
con->finalArgv[con->finalArgvCount++] = s;
+ *s++ = '-';
+ if (opt->longName) {
+ if (!F_ISSET(opt, ONEDASH))
+ *s++ = '-';
+ s = stpcpy(s, opt->longName);
+ } else {
+ *s++ = opt->shortName;
+ *s = '\0';
+ }
} else
con->finalArgv[con->finalArgvCount++] = NULL;
}
- if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE)
+ if (opt->arg && poptArgType(opt) == POPT_ARG_NONE)
/*@-ifempty@*/ ; /*@=ifempty@*/
- else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL)
+ else if (poptArgType(opt) == POPT_ARG_VAL)
/*@-ifempty@*/ ; /*@=ifempty@*/
- else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) {
- if (con->finalArgv != NULL && con->os->nextArg)
+ else if (poptArgType(opt) != POPT_ARG_NONE) {
+ if (con->finalArgv != NULL && con->os->nextArg != NULL)
con->finalArgv[con->finalArgvCount++] =
- /*@-nullpass@*/ /* LCL: con->os->nextArg != NULL */
xstrdup(con->os->nextArg);
- /*@=nullpass@*/
}
}
return (opt ? opt->val : -1); /* XXX can't happen */
}
-/*@=boundswrite@*/
-const char * poptGetOptArg(poptContext con)
+char * poptGetOptArg(poptContext con)
{
- const char * ret = NULL;
- /*@-branchstate@*/
+ char * ret = NULL;
if (con) {
ret = con->os->nextArg;
con->os->nextArg = NULL;
}
- /*@=branchstate@*/
return ret;
}
@@ -1030,7 +1576,6 @@ const char * poptPeekArg(poptContext con)
return ret;
}
-/*@-boundswrite@*/
const char ** poptGetArgs(poptContext con)
{
if (con == NULL ||
@@ -1040,60 +1585,59 @@ const char ** poptGetArgs(poptContext con)
/* some apps like [like RPM ;-) ] need this NULL terminated */
con->leftovers[con->numLeftovers] = NULL;
- /*@-nullret -nullstate @*/ /* FIX: typedef double indirection. */
+/*@-nullret -nullstate @*/ /* FIX: typedef double indirection. */
return (con->leftovers + con->nextLeftover);
- /*@=nullret =nullstate @*/
+/*@=nullret =nullstate @*/
}
-/*@=boundswrite@*/
-poptContext poptFreeContext(poptContext con)
+static /*@null@*/
+poptItem poptFreeItems(/*@only@*/ /*@null@*/ poptItem items, int nitems)
+ /*@modifies items @*/
{
- poptItem item;
- int i;
+ if (items != NULL) {
+ poptItem item = items;
+ while (--nitems >= 0) {
+/*@-modobserver -observertrans -dependenttrans@*/
+ item->option.longName = _free(item->option.longName);
+ item->option.descrip = _free(item->option.descrip);
+ item->option.argDescrip = _free(item->option.argDescrip);
+/*@=modobserver =observertrans =dependenttrans@*/
+ item->argv = _free(item->argv);
+ item++;
+ }
+ items = _free(items);
+ }
+ return NULL;
+}
+poptContext poptFreeContext(poptContext con)
+{
if (con == NULL) return con;
poptResetContext(con);
- con->os->argb = (pbm_set *)_free(con->os->argb);
+ con->os->argb = _free(con->os->argb);
- if (con->aliases != NULL)
- for (i = 0; i < con->numAliases; i++) {
- item = con->aliases + i;
- /*@-modobserver -observertrans -dependenttrans@*/
- item->option.longName = (const char *)_free(item->option.longName);
- item->option.descrip = (const char *)_free(item->option.descrip);
- item->option.argDescrip = (const char *)_free(item->option.argDescrip);
- /*@=modobserver =observertrans =dependenttrans@*/
- item->argv = (const char **)_free(item->argv);
- }
- con->aliases = (poptItem)_free(con->aliases);
+ con->aliases = poptFreeItems(con->aliases, con->numAliases);
+ con->numAliases = 0;
- if (con->execs != NULL)
- for (i = 0; i < con->numExecs; i++) {
- item = con->execs + i;
- /*@-modobserver -observertrans -dependenttrans@*/
- item->option.longName = (const char *)_free(item->option.longName);
- item->option.descrip = (const char *)_free(item->option.descrip);
- item->option.argDescrip = (const char *)_free(item->option.argDescrip);
- /*@=modobserver =observertrans =dependenttrans@*/
- item->argv = (const char **)_free(item->argv);
- }
- con->execs = (poptItem)_free(con->execs);
-
- con->leftovers = (const char **)_free(con->leftovers);
- con->finalArgv = (const char **)_free(con->finalArgv);
- con->appName = (const char *)_free(con->appName);
- con->otherHelp = (const char *)_free(con->otherHelp);
- con->execPath = (const char *)_free(con->execPath);
- con->arg_strip = (pbm_set *)PBM_FREE(con->arg_strip);
+ con->execs = poptFreeItems(con->execs, con->numExecs);
+ con->numExecs = 0;
+
+ con->leftovers = _free(con->leftovers);
+ con->finalArgv = _free(con->finalArgv);
+ con->appName = _free(con->appName);
+ con->otherHelp = _free(con->otherHelp);
+ con->execPath = _free(con->execPath);
+ con->arg_strip = PBM_FREE(con->arg_strip);
- con = (poptContext)_free(con);
+ con = _free(con);
return con;
}
int poptAddAlias(poptContext con, struct poptAlias alias,
- /*@unused@*/ int flags)
+ /*@unused@*/ UNUSED(int flags))
{
- poptItem item = (poptItem)alloca(sizeof(*item));
+ struct poptItem_s item_buf;
+ poptItem item = &item_buf;
memset(item, 0, sizeof(*item));
item->option.longName = alias.longName;
item->option.shortName = alias.shortName;
@@ -1107,8 +1651,6 @@ int poptAddAlias(poptContext con, struct poptAlias alias,
return poptAddItem(con, item, 0);
}
-/*@-boundswrite@*/
-/*@-mustmod@*/ /* LCL: con not modified? */
int poptAddItem(poptContext con, poptItem newItem, int flags)
{
poptItem * items, item;
@@ -1128,7 +1670,7 @@ int poptAddItem(poptContext con, poptItem newItem, int flags)
/*@notreached@*/ break;
}
- *items = (poptItem)realloc((*items), ((*nitems) + 1) * sizeof(**items));
+ *items = realloc((*items), ((*nitems) + 1) * sizeof(**items));
if ((*items) == NULL)
return 1;
@@ -1151,22 +1693,18 @@ int poptAddItem(poptContext con, poptItem newItem, int flags)
return 0;
}
-/*@=mustmod@*/
-/*@=boundswrite@*/
-const char * poptBadOption(poptContext con, int flags)
+const char * poptBadOption(poptContext con, unsigned int flags)
{
struct optionStackEntry * os = NULL;
if (con != NULL)
os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os;
- /*@-nullderef@*/ /* LCL: os->argv != NULL */
- return (os && os->argv ? os->argv[os->next - 1] : NULL);
- /*@=nullderef@*/
+ return (os != NULL && os->argv != NULL ? os->argv[os->next - 1] : NULL);
}
-const char *poptStrerror(const int error)
+const char * poptStrerror(const int error)
{
switch (error) {
case POPT_ERROR_NOARG:
@@ -1187,6 +1725,8 @@ const char *poptStrerror(const int error)
return POPT_("number too large or too small");
case POPT_ERROR_MALLOC:
return POPT_("memory allocation failed");
+ case POPT_ERROR_BADCONFIG:
+ return POPT_("config file failed sanity test");
case POPT_ERROR_ERRNO:
return strerror(errno);
default:
@@ -1222,14 +1762,13 @@ const char * poptGetInvocationName(poptContext con)
return (con->os->argv ? con->os->argv[0] : "");
}
-/*@-boundswrite@*/
int poptStrippedArgv(poptContext con, int argc, char ** argv)
{
int numargs = argc;
int j = 1;
int i;
- /*@-sizeoftype@*/
+/*@-sizeoftype@*/
if (con->arg_strip)
for (i = 1; i < argc; i++) {
if (PBM_ISSET(i, con->arg_strip))
@@ -1242,8 +1781,7 @@ int poptStrippedArgv(poptContext con, int argc, char ** argv)
argv[j] = (j < numargs) ? argv[i] : NULL;
j++;
}
- /*@=sizeoftype@*/
+/*@=sizeoftype@*/
return numargs;
}
-/*@=boundswrite@*/
diff --git a/third_party/popt/popt.h b/third_party/popt/popt.h
index c60ae29c190..a12d143c97d 100644
--- a/third_party/popt/popt.h
+++ b/third_party/popt/popt.h
@@ -17,41 +17,49 @@
* \name Arg type identifiers
*/
/*@{*/
-#define POPT_ARG_NONE 0 /*!< no arg */
-#define POPT_ARG_STRING 1 /*!< arg will be saved as string */
-#define POPT_ARG_INT 2 /*!< arg will be converted to int */
-#define POPT_ARG_LONG 3 /*!< arg will be converted to long */
-#define POPT_ARG_INCLUDE_TABLE 4 /*!< arg points to table */
-#define POPT_ARG_CALLBACK 5 /*!< table-wide callback... must be
+#define POPT_ARG_NONE 0U /*!< no arg */
+#define POPT_ARG_STRING 1U /*!< arg will be saved as string */
+#define POPT_ARG_INT 2U /*!< arg ==> int */
+#define POPT_ARG_LONG 3U /*!< arg ==> long */
+#define POPT_ARG_INCLUDE_TABLE 4U /*!< arg points to table */
+#define POPT_ARG_CALLBACK 5U /*!< table-wide callback... must be
set first in table; arg points
to callback, descrip points to
callback data to pass */
-#define POPT_ARG_INTL_DOMAIN 6 /*!< set the translation domain
+#define POPT_ARG_INTL_DOMAIN 6U /*!< set the translation domain
for this table and any
included tables; arg points
to the domain string */
-#define POPT_ARG_VAL 7 /*!< arg should take value val */
-#define POPT_ARG_FLOAT 8 /*!< arg will be converted to float */
-#define POPT_ARG_DOUBLE 9 /*!< arg will be converted to double */
+#define POPT_ARG_VAL 7U /*!< arg should take value val */
+#define POPT_ARG_FLOAT 8U /*!< arg ==> float */
+#define POPT_ARG_DOUBLE 9U /*!< arg ==> double */
+#define POPT_ARG_LONGLONG 10U /*!< arg ==> long long */
+
+#define POPT_ARG_MAINCALL 16U+11U /*!< EXPERIMENTAL: return (*arg) (argc, argv) */
+#define POPT_ARG_ARGV 12U /*!< dupe'd arg appended to realloc'd argv array. */
+#define POPT_ARG_SHORT 13U /*!< arg ==> short */
+#define POPT_ARG_BITSET 16U+14U /*!< arg ==> bit set */
+
+#define POPT_ARG_MASK 0x000000FFU
+#define POPT_GROUP_MASK 0x0000FF00U
-#define POPT_ARG_MASK 0x0000FFFF
/*@}*/
/** \ingroup popt
* \name Arg modifiers
*/
/*@{*/
-#define POPT_ARGFLAG_ONEDASH 0x80000000 /*!< allow -longoption */
-#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000 /*!< don't show in help/usage */
-#define POPT_ARGFLAG_STRIP 0x20000000 /*!< strip this arg from argv(only applies to long args) */
-#define POPT_ARGFLAG_OPTIONAL 0x10000000 /*!< arg may be missing */
-
-#define POPT_ARGFLAG_OR 0x08000000 /*!< arg will be or'ed */
-#define POPT_ARGFLAG_NOR 0x09000000 /*!< arg will be nor'ed */
-#define POPT_ARGFLAG_AND 0x04000000 /*!< arg will be and'ed */
-#define POPT_ARGFLAG_NAND 0x05000000 /*!< arg will be nand'ed */
-#define POPT_ARGFLAG_XOR 0x02000000 /*!< arg will be xor'ed */
-#define POPT_ARGFLAG_NOT 0x01000000 /*!< arg will be negated */
+#define POPT_ARGFLAG_ONEDASH 0x80000000U /*!< allow -longoption */
+#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000U /*!< don't show in help/usage */
+#define POPT_ARGFLAG_STRIP 0x20000000U /*!< strip this arg from argv(only applies to long args) */
+#define POPT_ARGFLAG_OPTIONAL 0x10000000U /*!< arg may be missing */
+
+#define POPT_ARGFLAG_OR 0x08000000U /*!< arg will be or'ed */
+#define POPT_ARGFLAG_NOR 0x09000000U /*!< arg will be nor'ed */
+#define POPT_ARGFLAG_AND 0x04000000U /*!< arg will be and'ed */
+#define POPT_ARGFLAG_NAND 0x05000000U /*!< arg will be nand'ed */
+#define POPT_ARGFLAG_XOR 0x02000000U /*!< arg will be xor'ed */
+#define POPT_ARGFLAG_NOT 0x01000000U /*!< arg will be negated */
#define POPT_ARGFLAG_LOGICALOPS \
(POPT_ARGFLAG_OR|POPT_ARGFLAG_AND|POPT_ARGFLAG_XOR)
@@ -60,7 +68,9 @@
#define POPT_BIT_CLR (POPT_ARG_VAL|POPT_ARGFLAG_NAND)
/*!< clear arg bit(s) */
-#define POPT_ARGFLAG_SHOW_DEFAULT 0x00800000 /*!< show default value in --help */
+#define POPT_ARGFLAG_SHOW_DEFAULT 0x00800000U /*!< show default value in --help */
+#define POPT_ARGFLAG_RANDOM 0x00400000U /*!< random value in [1,arg] */
+#define POPT_ARGFLAG_TOGGLE 0x00200000U /*!< permit --[no]opt prefix toggle */
/*@}*/
@@ -68,12 +78,12 @@
* \name Callback modifiers
*/
/*@{*/
-#define POPT_CBFLAG_PRE 0x80000000 /*!< call the callback before parse */
-#define POPT_CBFLAG_POST 0x40000000 /*!< call the callback after parse */
-#define POPT_CBFLAG_INC_DATA 0x20000000 /*!< use data from the include line,
+#define POPT_CBFLAG_PRE 0x80000000U /*!< call the callback before parse */
+#define POPT_CBFLAG_POST 0x40000000U /*!< call the callback after parse */
+#define POPT_CBFLAG_INC_DATA 0x20000000U /*!< use data from the include line,
not the subtable */
-#define POPT_CBFLAG_SKIPOPTION 0x10000000 /*!< don't callback with option */
-#define POPT_CBFLAG_CONTINUE 0x08000000 /*!< continue callbacks with option */
+#define POPT_CBFLAG_SKIPOPTION 0x10000000U /*!< don't callback with option */
+#define POPT_CBFLAG_CONTINUE 0x08000000U /*!< continue callbacks with option */
/*@}*/
/** \ingroup popt
@@ -83,30 +93,31 @@
#define POPT_ERROR_NOARG -10 /*!< missing argument */
#define POPT_ERROR_BADOPT -11 /*!< unknown option */
#define POPT_ERROR_OPTSTOODEEP -13 /*!< aliases nested too deeply */
-#define POPT_ERROR_BADQUOTE -15 /*!< error in parameter quoting */
+#define POPT_ERROR_BADQUOTE -15 /*!< error in paramter quoting */
#define POPT_ERROR_ERRNO -16 /*!< errno set, use strerror(errno) */
#define POPT_ERROR_BADNUMBER -17 /*!< invalid numeric value */
#define POPT_ERROR_OVERFLOW -18 /*!< number too large or too small */
#define POPT_ERROR_BADOPERATION -19 /*!< mutually exclusive logical operations requested */
#define POPT_ERROR_NULLARG -20 /*!< opt->arg should not be NULL */
#define POPT_ERROR_MALLOC -21 /*!< memory allocation failed */
+#define POPT_ERROR_BADCONFIG -22 /*!< config file failed sanity test */
/*@}*/
/** \ingroup popt
* \name poptBadOption() flags
*/
/*@{*/
-#define POPT_BADOPTION_NOALIAS (1 << 0) /*!< don't go into an alias */
+#define POPT_BADOPTION_NOALIAS (1U << 0) /*!< don't go into an alias */
/*@}*/
/** \ingroup popt
* \name poptGetContext() flags
*/
/*@{*/
-#define POPT_CONTEXT_NO_EXEC (1 << 0) /*!< ignore exec expansions */
-#define POPT_CONTEXT_KEEP_FIRST (1 << 1) /*!< pay attention to argv[0] */
-#define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /*!< options can't follow args */
-#define POPT_CONTEXT_ARG_OPTS (1 << 4) /*!< return args as options with value 0 */
+#define POPT_CONTEXT_NO_EXEC (1U << 0) /*!< ignore exec expansions */
+#define POPT_CONTEXT_KEEP_FIRST (1U << 1) /*!< pay attention to argv[0] */
+#define POPT_CONTEXT_POSIXMEHARDER (1U << 2) /*!< options can't follow args */
+#define POPT_CONTEXT_ARG_OPTS (1U << 4) /*!< return args as options with value 0 */
/*@}*/
/** \ingroup popt
@@ -114,8 +125,8 @@
struct poptOption {
/*@observer@*/ /*@null@*/
const char * longName; /*!< may be NULL */
- char shortName; /*!< may be '\0' */
- int argInfo;
+ char shortName; /*!< may be NUL */
+ unsigned int argInfo;
/*@shared@*/ /*@null@*/
void * arg; /*!< depends on argInfo */
int val; /*!< 0 means don't return, just update flag */
@@ -131,7 +142,7 @@ struct poptOption {
struct poptAlias {
/*@owned@*/ /*@null@*/
const char * longName; /*!< may be NULL */
- char shortName; /*!< may be '\0' */
+ char shortName; /*!< may be NUL */
int argc;
/*@owned@*/
const char ** argv; /*!< must be free()able */
@@ -171,10 +182,16 @@ extern struct poptOption poptAliasOptions[];
/*@unchecked@*/ /*@observer@*/
extern struct poptOption poptHelpOptions[];
/*@=exportvar@*/
+
+/*@-exportvar@*/
+/*@unchecked@*/ /*@observer@*/
+extern struct poptOption * poptHelpOptionsI18N;
+/*@=exportvar@*/
+
#define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \
0, "Help options:", NULL },
-#define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
+#define POPT_TABLEEND { NULL, '\0', 0, NULL, 0, NULL, NULL }
/*@}*/
/** \ingroup popt
@@ -191,6 +208,8 @@ typedef struct poptOption * poptOption;
/*@=exporttype =typeuse@*/
#endif
+/** \ingroup popt
+ */
/*@-exportconst@*/
enum poptCallbackReason {
POPT_CALLBACK_REASON_PRE = 0,
@@ -217,7 +236,17 @@ typedef void (*poptCallbackType) (poptContext con,
/*@null@*/ const struct poptOption * opt,
/*@null@*/ const char * arg,
/*@null@*/ const void * data)
- /*@*/;
+ /*@globals internalState @*/
+ /*@modifies internalState @*/;
+
+/** \ingroup popt
+ * Destroy context.
+ * @param con context
+ * @return NULL always
+ */
+/*@null@*/
+poptContext poptFreeContext( /*@only@*/ /*@null@*/ poptContext con)
+ /*@modifies con @*/;
/** \ingroup popt
* Initialize popt context.
@@ -228,12 +257,39 @@ typedef void (*poptCallbackType) (poptContext con,
* @param flags or'd POPT_CONTEXT_* bits
* @return initialized popt context
*/
-/*@only@*/ /*@null@*/ poptContext poptGetContext(
+/*@only@*/ /*@null@*/
+poptContext poptGetContext(
/*@dependent@*/ /*@keep@*/ const char * name,
int argc, /*@dependent@*/ /*@keep@*/ const char ** argv,
/*@dependent@*/ /*@keep@*/ const struct poptOption * options,
- int flags)
- /*@*/;
+ unsigned int flags)
+ /*@globals internalState @*/
+ /*@modifies internalState @*/;
+
+/** \ingroup popt
+ * Destroy context (alternative implementation).
+ * @param con context
+ * @return NULL always
+ */
+/*@null@*/
+poptContext poptFini( /*@only@*/ /*@null@*/ poptContext con)
+ /*@modifies con @*/;
+
+/** \ingroup popt
+ * Initialize popt context (alternative implementation).
+ * This routine does poptGetContext() and then poptReadConfigFiles().
+ * @param argc no. of arguments
+ * @param argv argument array
+ * @param options address of popt option table
+ * @param configPaths colon separated file path(s) to read.
+ * @return initialized popt context (NULL on error).
+ */
+/*@only@*/ /*@null@*/ /*@unused@*/
+poptContext poptInit(int argc, /*@dependent@*/ /*@keep@*/ const char ** argv,
+ /*@dependent@*/ /*@keep@*/ const struct poptOption * options,
+ /*@null@*/ const char * configPaths)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies fileSystem, internalState @*/;
/** \ingroup popt
* Reinitialize popt context.
@@ -257,7 +313,8 @@ int poptGetNextOpt(/*@null@*/poptContext con)
* @param con context
* @return option argument, NULL if no argument is available
*/
-/*@observer@*/ /*@null@*/ const char * poptGetOptArg(/*@null@*/poptContext con)
+/*@observer@*/ /*@null@*/ /*@unused@*/
+char * poptGetOptArg(/*@null@*/poptContext con)
/*@modifies con @*/;
/** \ingroup popt
@@ -265,7 +322,8 @@ int poptGetNextOpt(/*@null@*/poptContext con)
* @param con context
* @return next argument, NULL if no argument is available
*/
-/*@observer@*/ /*@null@*/ const char * poptGetArg(/*@null@*/poptContext con)
+/*@observer@*/ /*@null@*/ /*@unused@*/
+const char * poptGetArg(/*@null@*/poptContext con)
/*@modifies con @*/;
/** \ingroup popt
@@ -273,7 +331,8 @@ int poptGetNextOpt(/*@null@*/poptContext con)
* @param con context
* @return current argument, NULL if no argument is available
*/
-/*@observer@*/ /*@null@*/ const char * poptPeekArg(/*@null@*/poptContext con)
+/*@observer@*/ /*@null@*/ /*@unused@*/
+const char * poptPeekArg(/*@null@*/poptContext con)
/*@*/;
/** \ingroup popt
@@ -281,7 +340,8 @@ int poptGetNextOpt(/*@null@*/poptContext con)
* @param con context
* @return argument array, NULL terminated
*/
-/*@observer@*/ /*@null@*/ const char ** poptGetArgs(/*@null@*/poptContext con)
+/*@observer@*/ /*@null@*/
+const char ** poptGetArgs(/*@null@*/poptContext con)
/*@modifies con @*/;
/** \ingroup popt
@@ -290,23 +350,17 @@ int poptGetNextOpt(/*@null@*/poptContext con)
* @param flags
* @return offending option
*/
-/*@observer@*/ const char * poptBadOption(/*@null@*/poptContext con, int flags)
+/*@observer@*/
+const char * poptBadOption(/*@null@*/poptContext con, unsigned int flags)
/*@*/;
/** \ingroup popt
- * Destroy context.
- * @param con context
- * @return NULL always
- */
-/*@null@*/ poptContext poptFreeContext( /*@only@*/ /*@null@*/ poptContext con)
- /*@modifies con @*/;
-
-/** \ingroup popt
* Add arguments to context.
* @param con context
* @param argv argument array, NULL terminated
* @return 0 on success, POPT_ERROR_OPTSTOODEEP on failure
*/
+/*@unused@*/
int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv)
/*@modifies con @*/;
@@ -334,15 +388,52 @@ int poptAddItem(poptContext con, poptItem newItem, int flags)
/*@modifies con @*/;
/** \ingroup popt
+ * Perform sanity checks on a file path.
+ * @param fn file name
+ * @return 0 on OK, 1 on NOTOK.
+ */
+int poptSaneFile(const char * fn)
+ /*@globals errno, internalState @*/
+ /*@modifies errno, internalState @*/;
+
+/**
+ * Read a file into a buffer.
+ * @param fn file name
+ * @retval *bp buffer (malloc'd) (or NULL)
+ * @retval *nbp no. of bytes in buffer (including final NUL) (or NULL)
+ * @param flags 1 to trim escaped newlines
+ * return 0 on success
+ */
+int poptReadFile(const char * fn, /*@null@*/ /*@out@*/ char ** bp,
+ /*@null@*/ /*@out@*/ size_t * nbp, int flags)
+ /*@globals errno, fileSystem, internalState @*/
+ /*@modifies *bp, *nbp, errno, fileSystem, internalState @*/;
+#define POPT_READFILE_TRIMNEWLINES 1
+
+/** \ingroup popt
* Read configuration file.
* @param con context
* @param fn file name to read
* @return 0 on success, POPT_ERROR_ERRNO on failure
*/
int poptReadConfigFile(poptContext con, const char * fn)
- /*@globals fileSystem, internalState @*/
+ /*@globals errno, fileSystem, internalState @*/
/*@modifies con->execs, con->numExecs,
- fileSystem, internalState @*/;
+ errno, fileSystem, internalState @*/;
+
+/** \ingroup popt
+ * Read configuration file(s).
+ * Colon separated files to read, looping over poptReadConfigFile().
+ * Note that an '@' character preceeding a path in the list will
+ * also perform additional sanity checks on the file before reading.
+ * @param con context
+ * @param paths colon separated file name(s) to read
+ * @return 0 on success, POPT_ERROR_BADCONFIG on failure
+ */
+int poptReadConfigFiles(poptContext con, /*@null@*/ const char * paths)
+ /*@globals errno, fileSystem, internalState @*/
+ /*@modifies con->execs, con->numExecs,
+ errno, fileSystem, internalState @*/;
/** \ingroup popt
* Read default configuration from /etc/popt and $HOME/.popt.
@@ -350,6 +441,7 @@ int poptReadConfigFile(poptContext con, const char * fn)
* @param useEnv (unused)
* @return 0 on success, POPT_ERROR_ERRNO on failure
*/
+/*@unused@*/
int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv)
/*@globals fileSystem, internalState @*/
/*@modifies con->execs, con->numExecs,
@@ -443,7 +535,8 @@ int poptConfigFileToString(FILE *fp, /*@out@*/ char ** argstrp, int flags)
* @param error popt error
* @return error string
*/
-/*@observer@*/ const char* poptStrerror(const int error)
+/*@observer@*/
+const char * poptStrerror(const int error)
/*@*/;
/** \ingroup popt
@@ -452,28 +545,29 @@ int poptConfigFileToString(FILE *fp, /*@out@*/ char ** argstrp, int flags)
* @param path single path to search for executables
* @param allowAbsolute absolute paths only?
*/
+/*@unused@*/
void poptSetExecPath(poptContext con, const char * path, int allowAbsolute)
/*@modifies con @*/;
/** \ingroup popt
* Print detailed description of options.
* @param con context
- * @param fp output file handle
+ * @param fp ouput file handle
* @param flags (unused)
*/
void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
/*@globals fileSystem @*/
- /*@modifies *fp, fileSystem @*/;
+ /*@modifies fp, fileSystem @*/;
/** \ingroup popt
* Print terse description of options.
* @param con context
- * @param fp output file handle
+ * @param fp ouput file handle
* @param flags (unused)
*/
void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
/*@globals fileSystem @*/
- /*@modifies *fp, fileSystem @*/;
+ /*@modifies fp, fileSystem @*/;
/** \ingroup popt
* Provide text to replace default "[OPTION...]" in help/usage output.
@@ -491,7 +585,8 @@ void poptSetOtherOptionHelp(poptContext con, const char * text)
* @return argv[0]
*/
/*@-fcnuse@*/
-/*@observer@*/ const char * poptGetInvocationName(poptContext con)
+/*@observer@*/
+const char * poptGetInvocationName(poptContext con)
/*@*/;
/*@=fcnuse@*/
@@ -508,6 +603,35 @@ int poptStrippedArgv(poptContext con, int argc, char ** argv)
/*@=fcnuse@*/
/**
+ * Add a string to an argv array.
+ * @retval *argvp argv array
+ * @param argInfo (unused)
+ * @param val string arg to add (using strdup)
+ * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
+ */
+/*@unused@*/
+int poptSaveString(/*@null@*/ const char *** argvp, unsigned int argInfo,
+ /*@null@*/const char * val)
+ /*@modifies *argvp @*/;
+
+/**
+ * Save a long long, performing logical operation with value.
+ * @warning Alignment check may be too strict on certain platorms.
+ * @param arg integer pointer, aligned on int boundary.
+ * @param argInfo logical operation (see POPT_ARGFLAG_*)
+ * @param aLongLong value to use
+ * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
+ */
+/*@-incondefs@*/
+/*@unused@*/
+int poptSaveLongLong(/*@null@*/ long long * arg, unsigned int argInfo,
+ long long aLongLong)
+ /*@globals internalState @*/
+ /*@modifies *arg, internalState @*/
+ /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/;
+/*@=incondefs@*/
+
+/**
* Save a long, performing logical operation with value.
* @warning Alignment check may be too strict on certain platorms.
* @param arg integer pointer, aligned on int boundary.
@@ -517,8 +641,25 @@ int poptStrippedArgv(poptContext con, int argc, char ** argv)
*/
/*@-incondefs@*/
/*@unused@*/
-int poptSaveLong(/*@null@*/ long * arg, int argInfo, long aLong)
- /*@modifies *arg @*/
+int poptSaveLong(/*@null@*/ long * arg, unsigned int argInfo, long aLong)
+ /*@globals internalState @*/
+ /*@modifies *arg, internalState @*/
+ /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/;
+/*@=incondefs@*/
+
+/**
+ * Save a short integer, performing logical operation with value.
+ * @warning Alignment check may be too strict on certain platorms.
+ * @param arg short pointer, aligned on short boundary.
+ * @param argInfo logical operation (see POPT_ARGFLAG_*)
+ * @param aLong value to use
+ * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
+ */
+/*@-incondefs@*/
+/*@unused@*/
+int poptSaveShort(/*@null@*/ short * arg, unsigned int argInfo, long aLong)
+ /*@globals internalState @*/
+ /*@modifies *arg, internalState @*/
/*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/;
/*@=incondefs@*/
@@ -532,12 +673,70 @@ int poptSaveLong(/*@null@*/ long * arg, int argInfo, long aLong)
*/
/*@-incondefs@*/
/*@unused@*/
-int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong)
- /*@modifies *arg @*/
+int poptSaveInt(/*@null@*/ int * arg, unsigned int argInfo, long aLong)
+ /*@globals internalState @*/
+ /*@modifies *arg, internalState @*/
/*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/;
/*@=incondefs@*/
+/* The bit set typedef. */
+/*@-exporttype@*/
+typedef struct poptBits_s {
+ unsigned int bits[1];
+} * poptBits;
+/*@=exporttype@*/
+
+#define _POPT_BITS_N 1024U /* estimated population */
+#define _POPT_BITS_M ((3U * _POPT_BITS_N) / 2U)
+#define _POPT_BITS_K 16U /* no. of linear hash combinations */
+
+/*@-exportlocal -exportvar -globuse @*/
+/*@unchecked@*/
+extern unsigned int _poptBitsN;
+/*@unchecked@*/
+extern unsigned int _poptBitsM;
+/*@unchecked@*/
+extern unsigned int _poptBitsK;
+/*@=exportlocal =exportvar =globuse @*/
+
+/*@-exportlocal@*/
+int poptBitsAdd(/*@null@*/poptBits bits, /*@null@*/const char * s)
+ /*@modifies bits @*/;
+/*@=exportlocal@*/
+int poptBitsChk(/*@null@*/poptBits bits, /*@null@*/const char * s)
+ /*@*/;
+int poptBitsClr(/*@null@*/poptBits bits)
+ /*@modifies bits @*/;
+/*@-exportlocal@*/
+int poptBitsDel(/*@null@*/poptBits bits, /*@null@*/const char * s)
+ /*@modifies bits @*/;
+/*@-fcnuse@*/
+int poptBitsIntersect(/*@null@*/ poptBits * ap, /*@null@*/ const poptBits b)
+ /*@modifies *ap @*/;
+int poptBitsUnion(/*@null@*/ poptBits * ap, /*@null@*/ const poptBits b)
+ /*@modifies *ap @*/;
+int poptBitsArgs(/*@null@*/ poptContext con, /*@null@*/ poptBits * ap)
+ /*@modifies con, *ap @*/;
+/*@=fcnuse@*/
+/*@=exportlocal@*/
+
+/**
+ * Save a string into a bit set (experimental).
+ * @retval *bits bit set (lazily malloc'd if NULL)
+ * @param argInfo logical operation (see POPT_ARGFLAG_*)
+ * @param s string to add to bit set
+ * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION
+ */
+/*@-incondefs@*/
+/*@unused@*/
+int poptSaveBits(/*@null@*/ poptBits * bitsp, unsigned int argInfo,
+ /*@null@*/ const char * s)
+ /*@globals _poptBitsN, _poptBitsM, _poptBitsK, internalState @*/
+ /*@modifies *bitsp, _poptBitsN, _poptBitsM, _poptBitsK, internalState @*/;
+/*@=incondefs@*/
+
/*@=type@*/
+
#ifdef __cplusplus
}
#endif
diff --git a/third_party/popt/poptconfig.c b/third_party/popt/poptconfig.c
index 837828ccf92..f0a92e01bd5 100644
--- a/third_party/popt/poptconfig.c
+++ b/third_party/popt/poptconfig.c
@@ -8,53 +8,346 @@
#include "system.h"
#include "poptint.h"
+#include <sys/stat.h>
+
+#if defined(HAVE_FNMATCH_H)
+#include <fnmatch.h>
+
+#if defined(__LCLINT__)
+/*@-declundef -exportheader -incondefs -protoparammatch -redecl -type @*/
+extern int fnmatch (const char *__pattern, const char *__name, int __flags)
+ /*@*/;
+/*@=declundef =exportheader =incondefs =protoparammatch =redecl =type @*/
+#endif /* __LCLINT__ */
+#endif
+
+#if defined(HAVE_GLOB_H)
+#include <glob.h>
+
+#if defined(__LCLINT__)
+/*@-declundef -exportheader -incondefs -protoparammatch -redecl -type @*/
+extern int glob (const char *__pattern, int __flags,
+ /*@null@*/ int (*__errfunc) (const char *, int),
+ /*@out@*/ glob_t *__pglob)
+ /*@globals errno, fileSystem @*/
+ /*@modifies *__pglob, errno, fileSystem @*/;
+
+/* XXX only annotation is a white lie */
+extern void globfree (/*@only@*/ glob_t *__pglob)
+ /*@modifies *__pglob @*/;
+
+/* XXX _GNU_SOURCE ifdef and/or retrofit is needed for portability. */
+extern int glob_pattern_p (const char *__pattern, int __quote)
+ /*@*/;
+/*@=declundef =exportheader =incondefs =protoparammatch =redecl =type @*/
+#endif /* __LCLINT__ */
+
+#if !defined(__GLIBC__)
+/* Return nonzero if PATTERN contains any metacharacters.
+ Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
+static int
+glob_pattern_p (const char * pattern, int quote)
+ /*@*/
+{
+ const char * p;
+ int open = 0;
+
+ for (p = pattern; *p != '\0'; ++p)
+ switch (*p) {
+ case '?':
+ case '*':
+ return 1;
+ /*@notreached@*/ /*@switchbreak@*/ break;
+ case '\\':
+ if (quote && p[1] != '\0')
+ ++p;
+ /*@switchbreak@*/ break;
+ case '[':
+ open = 1;
+ /*@switchbreak@*/ break;
+ case ']':
+ if (open)
+ return 1;
+ /*@switchbreak@*/ break;
+ }
+ return 0;
+}
+#endif /* !defined(__GLIBC__) */
+
+/*@unchecked@*/
+static int poptGlobFlags = 0;
+
+static int poptGlob_error(/*@unused@*/ UNUSED(const char * epath),
+ /*@unused@*/ UNUSED(int eerrno))
+ /*@*/
+{
+ return 1;
+}
+#endif /* HAVE_GLOB_H */
+
+/**
+ * Return path(s) from a glob pattern.
+ * @param con context
+ * @param pattern glob pattern
+ * @retval *acp no. of paths
+ * @retval *avp array of paths
+ * @return 0 on success
+ */
+static int poptGlob(/*@unused@*/ UNUSED(poptContext con), const char * pattern,
+ /*@out@*/ int * acp, /*@out@*/ const char *** avp)
+ /*@modifies *acp, *avp @*/
+{
+ const char * pat = pattern;
+ int rc = 0; /* assume success */
+
+ /* XXX skip the attention marker. */
+ if (pat[0] == '@' && pat[1] != '(')
+ pat++;
+
+#if defined(HAVE_GLOB_H)
+ if (glob_pattern_p(pat, 0)) {
+ glob_t _g, *pglob = &_g;
+
+ if (!glob(pat, poptGlobFlags, poptGlob_error, pglob)) {
+ if (acp) {
+ *acp = (int) pglob->gl_pathc;
+ pglob->gl_pathc = 0;
+ }
+ if (avp) {
+/*@-onlytrans@*/
+ *avp = (const char **) pglob->gl_pathv;
+/*@=onlytrans@*/
+ pglob->gl_pathv = NULL;
+ }
+/*@-nullstate@*/
+ globfree(pglob);
+/*@=nullstate@*/
+ } else
+ rc = POPT_ERROR_ERRNO;
+ } else
+#endif /* HAVE_GLOB_H */
+ {
+ if (acp)
+ *acp = 1;
+ if (avp && (*avp = calloc((size_t)(1 + 1), sizeof (**avp))) != NULL)
+ (*avp)[0] = xstrdup(pat);
+ }
+
+ return rc;
+}
+
+/*@access poptContext @*/
+
+int poptSaneFile(const char * fn)
+{
+ struct stat sb;
+ uid_t uid = getuid();
+
+ if (stat(fn, &sb) == -1)
+ return 1;
+ if ((uid_t)sb.st_uid != uid)
+ return 0;
+ if (!S_ISREG(sb.st_mode))
+ return 0;
+/*@-bitwisesigned@*/
+ if (sb.st_mode & (S_IWGRP|S_IWOTH))
+ return 0;
+/*@=bitwisesigned@*/
+ return 1;
+}
+
+int poptReadFile(const char * fn, char ** bp, size_t * nbp, int flags)
+{
+ int fdno;
+ char * b = NULL;
+ off_t nb = 0;
+ char * s, * t, * se;
+ int rc = POPT_ERROR_ERRNO; /* assume failure */
+
+ fdno = open(fn, O_RDONLY);
+ if (fdno < 0)
+ goto exit;
+
+ if ((nb = lseek(fdno, 0, SEEK_END)) == (off_t)-1
+ || lseek(fdno, 0, SEEK_SET) == (off_t)-1
+ || (b = calloc(sizeof(*b), (size_t)nb + 1)) == NULL
+ || read(fdno, (char *)b, (size_t)nb) != (ssize_t)nb)
+ {
+ int oerrno = errno;
+ (void) close(fdno);
+ errno = oerrno;
+ goto exit;
+ }
+ if (close(fdno) == -1)
+ goto exit;
+ if (b == NULL) {
+ rc = POPT_ERROR_MALLOC;
+ goto exit;
+ }
+ rc = 0;
+
+ /* Trim out escaped newlines. */
+/*@-bitwisesigned@*/
+ if (flags & POPT_READFILE_TRIMNEWLINES)
+/*@=bitwisesigned@*/
+ {
+ for (t = b, s = b, se = b + nb; *s && s < se; s++) {
+ switch (*s) {
+ case '\\':
+ if (s[1] == '\n') {
+ s++;
+ continue;
+ }
+ /*@fallthrough@*/
+ default:
+ *t++ = *s;
+ /*@switchbreak@*/ break;
+ }
+ }
+ *t++ = '\0';
+ nb = (off_t)(t - b);
+ }
+
+exit:
+ if (rc != 0) {
+/*@-usedef@*/
+ if (b)
+ free(b);
+/*@=usedef@*/
+ b = NULL;
+ nb = 0;
+ }
+ if (bp)
+ *bp = b;
+/*@-usereleased@*/
+ else if (b)
+ free(b);
+/*@=usereleased@*/
+ if (nbp)
+ *nbp = (size_t)nb;
+/*@-compdef -nullstate @*/ /* XXX cannot annotate char ** correctly */
+ return rc;
+/*@=compdef =nullstate @*/
+}
+
+/**
+ * Check for application match.
+ * @param con context
+ * @param s config application name
+ * return 0 if config application matches
+ */
+static int configAppMatch(poptContext con, const char * s)
+ /*@*/
+{
+ int rc = 1;
+
+ if (con->appName == NULL) /* XXX can't happen. */
+ return rc;
+
+#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
+ if (glob_pattern_p(s, 1)) {
+/*@-bitwisesigned@*/
+ static int flags = FNM_PATHNAME | FNM_PERIOD;
+#ifdef FNM_EXTMATCH
+ flags |= FNM_EXTMATCH;
+#endif
+/*@=bitwisesigned@*/
+ rc = fnmatch(s, con->appName, flags);
+ } else
+#endif
+ rc = strcmp(s, con->appName);
+ return rc;
+}
/*@-compmempass@*/ /* FIX: item->option.longName kept, not dependent. */
-static void configLine(poptContext con, char * line)
- /*@modifies con @*/
+static int poptConfigLine(poptContext con, char * line)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies con, fileSystem, internalState @*/
{
- /*@-type@*/
- int nameLength = strlen(con->appName);
- /*@=type@*/
+ char *b = NULL;
+ size_t nb = 0;
+ char * se = line;
+ const char * appName;
const char * entryType;
const char * opt;
- poptItem item = (poptItem)alloca(sizeof(*item));
+ struct poptItem_s item_buf;
+ poptItem item = &item_buf;
int i, j;
+ int rc = POPT_ERROR_BADCONFIG;
+
+ if (con->appName == NULL)
+ goto exit;
-/*@-boundswrite@*/
memset(item, 0, sizeof(*item));
- /*@-type@*/
- if (strncmp(line, con->appName, nameLength)) return;
- /*@=type@*/
+ appName = se;
+ while (*se != '\0' && !_isspaceptr(se)) se++;
+ if (*se == '\0')
+ goto exit;
+ else
+ *se++ = '\0';
- line += nameLength;
- if (*line == '\0' || !isspace(*line)) return;
+ if (configAppMatch(con, appName)) goto exit;
- while (*line != '\0' && isspace(*line)) line++;
- entryType = line;
- while (*line == '\0' || !isspace(*line)) line++;
- *line++ = '\0';
+ while (*se != '\0' && _isspaceptr(se)) se++;
+ entryType = se;
+ while (*se != '\0' && !_isspaceptr(se)) se++;
+ if (*se != '\0') *se++ = '\0';
- while (*line != '\0' && isspace(*line)) line++;
- if (*line == '\0') return;
- opt = line;
- while (*line == '\0' || !isspace(*line)) line++;
- *line++ = '\0';
+ while (*se != '\0' && _isspaceptr(se)) se++;
+ if (*se == '\0') goto exit;
+ opt = se;
+ while (*se != '\0' && !_isspaceptr(se)) se++;
+ if (opt[0] == '-' && *se == '\0') goto exit;
+ if (*se != '\0') *se++ = '\0';
- while (*line != '\0' && isspace(*line)) line++;
- if (*line == '\0') return;
+ while (*se != '\0' && _isspaceptr(se)) se++;
+ if (opt[0] == '-' && *se == '\0') goto exit;
- /*@-temptrans@*/ /* FIX: line alias is saved */
+/*@-temptrans@*/ /* FIX: line alias is saved */
if (opt[0] == '-' && opt[1] == '-')
item->option.longName = opt + 2;
else if (opt[0] == '-' && opt[2] == '\0')
item->option.shortName = opt[1];
- /*@=temptrans@*/
+ else {
+ const char * fn = opt;
- if (poptParseArgvString(line, &item->argc, &item->argv)) return;
+ /* XXX handle globs and directories in fn? */
+ if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0)
+ goto exit;
+ if (b == NULL || nb == 0)
+ goto exit;
- /*@-modobserver@*/
+ /* Append remaining text to the interpolated file option text. */
+ if (*se != '\0') {
+ size_t nse = strlen(se) + 1;
+ if ((b = realloc(b, (nb + nse))) == NULL) /* XXX can't happen */
+ goto exit;
+ (void) stpcpy( stpcpy(&b[nb-1], " "), se);
+ nb += nse;
+ }
+ se = b;
+
+ /* Use the basename of the path as the long option name. */
+ { const char * longName = strrchr(fn, '/');
+ if (longName != NULL)
+ longName++;
+ else
+ longName = fn;
+ if (longName == NULL) /* XXX can't happen. */
+ goto exit;
+ /* Single character basenames are treated as short options. */
+ if (longName[1] != '\0')
+ item->option.longName = longName;
+ else
+ item->option.shortName = longName[0];
+ }
+ }
+/*@=temptrans@*/
+
+ if (poptParseArgvString(se, &item->argc, &item->argv)) goto exit;
+
+/*@-modobserver@*/
item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN;
for (i = 0, j = 0; i < item->argc; i++, j++) {
const char * f;
@@ -80,111 +373,210 @@ static void configLine(poptContext con, char * line)
item->argv[j] = NULL;
item->argc = j;
}
- /*@=modobserver@*/
-/*@=boundswrite@*/
+/*@=modobserver@*/
- /*@-nullstate@*/ /* FIX: item->argv[] may be NULL */
+/*@-nullstate@*/ /* FIX: item->argv[] may be NULL */
if (!strcmp(entryType, "alias"))
- (void) poptAddItem(con, item, 0);
+ rc = poptAddItem(con, item, 0);
else if (!strcmp(entryType, "exec"))
- (void) poptAddItem(con, item, 1);
- /*@=nullstate@*/
+ rc = poptAddItem(con, item, 1);
+/*@=nullstate@*/
+exit:
+ rc = 0; /* XXX for now, always return success */
+ if (b)
+ free(b);
+ return rc;
}
/*@=compmempass@*/
int poptReadConfigFile(poptContext con, const char * fn)
{
- const char * file, * chptr, * end;
- char * buf;
-/*@dependent@*/ char * dst;
- int fd, rc;
- off_t fileLength;
-
- fd = open(fn, O_RDONLY);
- if (fd < 0)
- return (errno == ENOENT ? 0 : POPT_ERROR_ERRNO);
-
- fileLength = lseek(fd, 0, SEEK_END);
- if (fileLength == -1 || lseek(fd, 0, 0) == -1) {
- rc = errno;
- (void) close(fd);
- /*@-mods@*/
- errno = rc;
- /*@=mods@*/
- return POPT_ERROR_ERRNO;
- }
+ char * b = NULL, *be;
+ size_t nb = 0;
+ const char *se;
+ char *t, *te;
+ int rc;
+ int xx;
- file = (const char *)alloca(fileLength + 1);
- if (read(fd, (char *)file, fileLength) != fileLength) {
- rc = errno;
- (void) close(fd);
- /*@-mods@*/
- errno = rc;
- /*@=mods@*/
- return POPT_ERROR_ERRNO;
- }
- if (close(fd) == -1)
- return POPT_ERROR_ERRNO;
+ if ((rc = poptReadFile(fn, &b, &nb, POPT_READFILE_TRIMNEWLINES)) != 0)
+ return (errno == ENOENT ? 0 : rc);
+ if (b == NULL || nb == 0)
+ return POPT_ERROR_BADCONFIG;
-/*@-boundswrite@*/
- dst = buf = (char *)alloca(fileLength + 1);
+ if ((t = malloc(nb + 1)) == NULL)
+ goto exit;
+ te = t;
- chptr = file;
- end = (file + fileLength);
- /*@-infloops@*/ /* LCL: can't detect chptr++ */
- while (chptr < end) {
- switch (*chptr) {
+ be = (b + nb);
+ for (se = b; se < be; se++) {
+ switch (*se) {
case '\n':
- *dst = '\0';
- dst = buf;
- while (*dst && isspace(*dst)) dst++;
- if (*dst && *dst != '#')
- configLine(con, dst);
- chptr++;
+ *te = '\0';
+ te = t;
+ while (*te && _isspaceptr(te)) te++;
+ if (*te && *te != '#')
+ xx = poptConfigLine(con, te);
/*@switchbreak@*/ break;
+/*@-usedef@*/ /* XXX *se may be uninitialized */
case '\\':
- *dst++ = *chptr++;
- if (chptr < end) {
- if (*chptr == '\n')
- dst--, chptr++;
- /* \ at the end of a line does not insert a \n */
- else
- *dst++ = *chptr++;
+ *te = *se++;
+ /* \ at the end of a line does not insert a \n */
+ if (se < be && *se != '\n') {
+ te++;
+ *te++ = *se;
}
/*@switchbreak@*/ break;
default:
- *dst++ = *chptr++;
+ *te++ = *se;
/*@switchbreak@*/ break;
+/*@=usedef@*/
}
}
- /*@=infloops@*/
-/*@=boundswrite@*/
- return 0;
+ free(t);
+ rc = 0;
+
+exit:
+ if (b)
+ free(b);
+ return rc;
}
-int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv)
+int poptReadConfigFiles(poptContext con, const char * paths)
{
- char * fn, * home;
- int rc;
+ char * buf = (paths ? xstrdup(paths) : NULL);
+ const char * p;
+ char * pe;
+ int rc = 0; /* assume success */
+
+ for (p = buf; p != NULL && *p != '\0'; p = pe) {
+ const char ** av = NULL;
+ int ac = 0;
+ int i;
+ int xx;
+
+ /* locate start of next path element */
+ pe = strchr(p, ':');
+ if (pe != NULL && *pe == ':')
+ *pe++ = '\0';
+ else
+ pe = (char *) (p + strlen(p));
+
+ xx = poptGlob(con, p, &ac, &av);
+
+ /* work-off each resulting file from the path element */
+ for (i = 0; i < ac; i++) {
+ const char * fn = av[i];
+ if (av[i] == NULL) /* XXX can't happen */
+ /*@innercontinue@*/ continue;
+ /* XXX should '@' attention be pushed into poptReadConfigFile? */
+ if (p[0] == '@' && p[1] != '(') {
+ if (fn[0] == '@' && fn[1] != '(')
+ fn++;
+ xx = poptSaneFile(fn);
+ if (!xx && rc == 0)
+ rc = POPT_ERROR_BADCONFIG;
+ /*@innercontinue@*/ continue;
+ }
+ xx = poptReadConfigFile(con, fn);
+ if (xx && rc == 0)
+ rc = xx;
+ free((void *)av[i]);
+ av[i] = NULL;
+ }
+ free(av);
+ av = NULL;
+ }
- /*@-type@*/
- if (!con->appName) return 0;
- /*@=type@*/
+/*@-usedef@*/
+ if (buf)
+ free(buf);
+/*@=usedef@*/
- rc = poptReadConfigFile(con, "/etc/popt");
- if (rc) return rc;
-#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
- if (getuid() != geteuid()) return 0;
+ return rc;
+}
+
+int poptReadDefaultConfig(poptContext con, /*@unused@*/ UNUSED(int useEnv))
+{
+ static const char _popt_sysconfdir[] = POPT_SYSCONFDIR "/popt";
+ static const char _popt_etc[] = "/etc/popt";
+ char * home;
+ struct stat sb;
+ int rc = 0; /* assume success */
+
+ if (con->appName == NULL) goto exit;
+
+ if (strcmp(_popt_sysconfdir, _popt_etc)) {
+ rc = poptReadConfigFile(con, _popt_sysconfdir);
+ if (rc) goto exit;
+ }
+
+ rc = poptReadConfigFile(con, _popt_etc);
+ if (rc) goto exit;
+
+#if defined(HAVE_GLOB_H)
+ if (!stat("/etc/popt.d", &sb) && S_ISDIR(sb.st_mode)) {
+ const char ** av = NULL;
+ int ac = 0;
+ int i;
+
+ if ((rc = poptGlob(con, "/etc/popt.d/*", &ac, &av)) == 0) {
+ for (i = 0; rc == 0 && i < ac; i++) {
+ const char * fn = av[i];
+ if (fn == NULL || strstr(fn, ".rpmnew") || strstr(fn, ".rpmsave"))
+ continue;
+ if (!stat(fn, &sb)) {
+ if (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode))
+ continue;
+ }
+ rc = poptReadConfigFile(con, fn);
+ free((void *)av[i]);
+ av[i] = NULL;
+ }
+ free(av);
+ av = NULL;
+ }
+ }
+ if (rc) goto exit;
#endif
if ((home = getenv("HOME"))) {
- fn = (char *)alloca(strlen(home) + 20);
- strcpy(fn, home);
- strcat(fn, "/.popt");
- rc = poptReadConfigFile(con, fn);
- if (rc) return rc;
+ char * fn = malloc(strlen(home) + 20);
+ if (fn != NULL) {
+ (void) stpcpy(stpcpy(fn, home), "/.popt");
+ rc = poptReadConfigFile(con, fn);
+ free(fn);
+ } else
+ rc = POPT_ERROR_ERRNO;
+ if (rc) goto exit;
}
- return 0;
+exit:
+ return rc;
+}
+
+poptContext
+poptFini(poptContext con)
+{
+ return poptFreeContext(con);
+}
+
+poptContext
+poptInit(int argc, const char ** argv,
+ const struct poptOption * options, const char * configPaths)
+{
+ poptContext con = NULL;
+ const char * argv0;
+
+ if (argv == NULL || argv[0] == NULL || options == NULL)
+ return con;
+
+ if ((argv0 = strrchr(argv[0], '/')) != NULL) argv0++;
+ else argv0 = argv[0];
+
+ con = poptGetContext(argv0, argc, (const char **)argv, options, 0);
+ if (con != NULL&& poptReadConfigFiles(con, configPaths))
+ con = poptFini(con);
+
+ return con;
}
diff --git a/third_party/popt/popthelp.c b/third_party/popt/popthelp.c
index 4e2a1a56ced..0d8548bdd76 100644
--- a/third_party/popt/popthelp.c
+++ b/third_party/popt/popthelp.c
@@ -1,6 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/*@-type@*/
/** \ingroup popt
* \file popt/popthelp.c
*/
@@ -10,8 +9,21 @@
ftp://ftp.rpm.org/pub/rpm/dist. */
#include "system.h"
+
+#define POPT_USE_TIOCGWINSZ
+#ifdef POPT_USE_TIOCGWINSZ
+#include <sys/ioctl.h>
+#endif
+
+#define POPT_WCHAR_HACK
+#ifdef POPT_WCHAR_HACK
+#include <wchar.h> /* for mbsrtowcs */
+/*@access mbstate_t @*/
+#endif
#include "poptint.h"
+/*@access poptContext@*/
+
/**
* Display arguments.
* @param con context
@@ -20,10 +32,12 @@
* @param arg (unused)
* @param data (unused)
*/
+/*@exits@*/
static void displayArgs(poptContext con,
- /*@unused@*/ enum poptCallbackReason foo,
+ /*@unused@*/ UNUSED(enum poptCallbackReason foo),
struct poptOption * key,
- /*@unused@*/ const char * arg, /*@unused@*/ void * data)
+ /*@unused@*/ UNUSED(const char * arg),
+ /*@unused@*/ UNUSED(void * data))
/*@globals fileSystem@*/
/*@modifies fileSystem@*/
{
@@ -31,6 +45,10 @@ static void displayArgs(poptContext con,
poptPrintHelp(con, stdout, 0);
else
poptPrintUsage(con, stdout, 0);
+
+#if !defined(__LCLINT__) /* XXX keep both splint & valgrind happy */
+ con = poptFreeContext(con);
+#endif
exit(0);
}
@@ -53,30 +71,97 @@ struct poptOption poptAliasOptions[] = {
/*@-castfcnptr@*/
/*@observer@*/ /*@unchecked@*/
struct poptOption poptHelpOptions[] = {
- { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
- { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
- { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
+ { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL },
+ { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL },
+ { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL },
+ POPT_TABLEEND
+} ;
+
+/*@observer@*/ /*@unchecked@*/
+static struct poptOption poptHelpOptions2[] = {
+/*@-readonlytrans@*/
+ { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL},
+/*@=readonlytrans@*/
+ { NULL, '\0', POPT_ARG_CALLBACK, (void *)displayArgs, 0, NULL, NULL },
+ { "help", '?', 0, NULL, (int)'?', N_("Show this help message"), NULL },
+ { "usage", '\0', 0, NULL, (int)'u', N_("Display brief usage message"), NULL },
#ifdef NOTYET
{ "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
N_("Display option defaults in message"), NULL },
#endif
+ { "", '\0', 0, NULL, 0, N_("Terminate options"), NULL },
POPT_TABLEEND
} ;
+
+/*@observer@*/ /*@unchecked@*/
+struct poptOption * poptHelpOptionsI18N = poptHelpOptions2;
/*@=castfcnptr@*/
+#define _POPTHELP_MAXLINE ((size_t)79)
+
+typedef struct columns_s {
+ size_t cur;
+ size_t max;
+} * columns_t;
+
/**
- * @param table option(s)
+ * Return no. of columns in output window.
+ * @param fp FILE
+ * @return no. of columns
*/
-/*@observer@*/ /*@null@*/ static const char *
-getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
+static size_t maxColumnWidth(FILE *fp)
+ /*@*/
+{
+ size_t maxcols = _POPTHELP_MAXLINE;
+#if defined(TIOCGWINSZ)
+ struct winsize ws;
+ int fdno = fileno(fp ? fp : stdout);
+
+ memset(&ws, 0, sizeof(ws));
+ if (fdno >= 0 && !ioctl(fdno, (unsigned long)TIOCGWINSZ, &ws)) {
+ size_t ws_col = (size_t)ws.ws_col;
+ if (ws_col > maxcols && ws_col < (size_t)256)
+ maxcols = ws_col - 1;
+ }
+#endif
+ return maxcols;
+}
+
+/**
+ * Determine number of display characters in a string.
+ * @param s string
+ * @return no. of display characters.
+ */
+static inline size_t stringDisplayWidth(const char *s)
/*@*/
{
- const struct poptOption *opt;
+ size_t n = strlen(s);
+#ifdef POPT_WCHAR_HACK
+ mbstate_t t;
- if (table != NULL)
- for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
+ memset ((void *)&t, 0, sizeof (t)); /* In initial state. */
+ /* Determine number of display characters. */
+ n = mbsrtowcs (NULL, &s, n, &t);
+#else
+ n = 0;
+ for (; *s; s = POPT_next_char(s))
+ n++;
+#endif
+
+ return n;
+}
+
+/**
+ * @param opt option(s)
+ */
+/*@observer@*/ /*@null@*/ static const char *
+getTableTranslationDomain(/*@null@*/ const struct poptOption *opt)
+ /*@*/
+{
+ if (opt != NULL)
+ for (; opt->longName || opt->shortName || opt->arg; opt++) {
if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
- return (char *)opt->arg;
+ return opt->arg;
}
return NULL;
}
@@ -92,14 +177,26 @@ getArgDescrip(const struct poptOption * opt,
/*@=paramuse@*/
/*@*/
{
- if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
-
- if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2))
- if (opt->argDescrip) return POPT_(opt->argDescrip);
-
- if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
+ if (!poptArgType(opt)) return NULL;
+
+ if (poptArgType(opt) == POPT_ARG_MAINCALL)
+ return opt->argDescrip;
+ if (poptArgType(opt) == POPT_ARG_ARGV)
+ return opt->argDescrip;
+
+ if (opt->argDescrip) {
+ /* Some strings need popt library, not application, i18n domain. */
+ if (opt == (poptHelpOptions + 1)
+ || opt == (poptHelpOptions + 2)
+ || !strcmp(opt->argDescrip, N_("Help options:"))
+ || !strcmp(opt->argDescrip, N_("Options implemented via popt alias/exec:")))
+ return POPT_(opt->argDescrip);
+
+ /* Use the application i18n domain. */
+ return D_(translation_domain, opt->argDescrip);
+ }
- switch (opt->argInfo & POPT_ARG_MASK) {
+ switch (poptArgType(opt)) {
case POPT_ARG_NONE: return POPT_("NONE");
#ifdef DYING
case POPT_ARG_VAL: return POPT_("VAL");
@@ -107,23 +204,27 @@ getArgDescrip(const struct poptOption * opt,
case POPT_ARG_VAL: return NULL;
#endif
case POPT_ARG_INT: return POPT_("INT");
+ case POPT_ARG_SHORT: return POPT_("SHORT");
case POPT_ARG_LONG: return POPT_("LONG");
+ case POPT_ARG_LONGLONG: return POPT_("LONGLONG");
case POPT_ARG_STRING: return POPT_("STRING");
case POPT_ARG_FLOAT: return POPT_("FLOAT");
case POPT_ARG_DOUBLE: return POPT_("DOUBLE");
+ case POPT_ARG_MAINCALL: return NULL;
+ case POPT_ARG_ARGV: return NULL;
default: return POPT_("ARG");
}
}
/**
* Display default value for an option.
- * @param lineLength
+ * @param lineLength display positions remaining
* @param opt option(s)
* @param translation_domain translation domain
* @return
*/
static /*@only@*/ /*@null@*/ char *
-singleOptionDefaultValue(int lineLength,
+singleOptionDefaultValue(size_t lineLength,
const struct poptOption * opt,
/*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
/*@null@*/ const char * translation_domain)
@@ -131,58 +232,67 @@ singleOptionDefaultValue(int lineLength,
/*@*/
{
const char * defstr = D_(translation_domain, "default");
- char * le = (char *)malloc(4*lineLength + 1);
+ char * le = malloc(4*lineLength + 1);
char * l = le;
if (le == NULL) return NULL; /* XXX can't happen */
-/*@-boundswrite@*/
*le = '\0';
*le++ = '(';
- strcpy(le, defstr); le += strlen(le);
+ le = stpcpy(le, defstr);
*le++ = ':';
*le++ = ' ';
- if (opt->arg) /* XXX programmer error */
- switch (opt->argInfo & POPT_ARG_MASK) {
+ if (opt->arg) { /* XXX programmer error */
+ poptArg arg = { .ptr = opt->arg };
+ switch (poptArgType(opt)) {
case POPT_ARG_VAL:
case POPT_ARG_INT:
- { long aLong = *((int *)opt->arg);
- le += sprintf(le, "%ld", aLong);
- } break;
+ le += sprintf(le, "%d", arg.intp[0]);
+ break;
+ case POPT_ARG_SHORT:
+ le += sprintf(le, "%hd", arg.shortp[0]);
+ break;
case POPT_ARG_LONG:
- { long aLong = *((long *)opt->arg);
- le += sprintf(le, "%ld", aLong);
- } break;
+ le += sprintf(le, "%ld", arg.longp[0]);
+ break;
+ case POPT_ARG_LONGLONG:
+ le += sprintf(le, "%lld", arg.longlongp[0]);
+ break;
case POPT_ARG_FLOAT:
- { double aDouble = *((float *)opt->arg);
+ { double aDouble = (double) arg.floatp[0];
le += sprintf(le, "%g", aDouble);
} break;
case POPT_ARG_DOUBLE:
- { double aDouble = *((double *)opt->arg);
- le += sprintf(le, "%g", aDouble);
- } break;
+ le += sprintf(le, "%g", arg.doublep[0]);
+ break;
+ case POPT_ARG_MAINCALL:
+ le += sprintf(le, "%p", opt->arg);
+ break;
+ case POPT_ARG_ARGV:
+ le += sprintf(le, "%p", opt->arg);
+ break;
case POPT_ARG_STRING:
- { const char * s = *(const char **)opt->arg;
- if (s == NULL) {
- strcpy(le, "null"); le += strlen(le);
- } else {
- size_t slen = 4*lineLength - (le - l) - sizeof("\"...\")");
+ { const char * s = arg.argv[0];
+ if (s == NULL)
+ le = stpcpy(le, "null");
+ else {
+ size_t limit = 4*lineLength - (le - l) - sizeof("\"\")");
+ size_t slen;
*le++ = '"';
- strncpy(le, s, slen); le[slen] = '\0'; le += strlen(le);
- if (slen < strlen(s)) {
- strcpy(le, "..."); le += strlen(le);
- }
+ strncpy(le, s, limit); le[limit] = '\0'; le += (slen = strlen(le));
+ if (slen == limit && s[limit])
+ le[-1] = le[-2] = le[-3] = '.';
*le++ = '"';
}
} break;
case POPT_ARG_NONE:
default:
- l = (char *)_free(l);
+ l = _free(l);
return NULL;
/*@notreached@*/ break;
}
+ }
*le++ = ')';
*le = '\0';
-/*@=boundswrite@*/
return l;
}
@@ -190,85 +300,104 @@ singleOptionDefaultValue(int lineLength,
/**
* Display help text for an option.
* @param fp output file handle
- * @param maxLeftCol
+ * @param columns output display width control
* @param opt option(s)
* @param translation_domain translation domain
*/
-static void singleOptionHelp(FILE * fp, int maxLeftCol,
+static void singleOptionHelp(FILE * fp, columns_t columns,
const struct poptOption * opt,
/*@null@*/ const char * translation_domain)
/*@globals fileSystem @*/
- /*@modifies *fp, fileSystem @*/
+ /*@modifies fp, fileSystem @*/
{
- int indentLength = maxLeftCol + 5;
- int lineLength = 79 - indentLength;
+ size_t maxLeftCol = columns->cur;
+ size_t indentLength = maxLeftCol + 5;
+ size_t lineLength = columns->max - indentLength;
const char * help = D_(translation_domain, opt->descrip);
const char * argDescrip = getArgDescrip(opt, translation_domain);
- int helpLength;
+ /* Display shortName iff printable non-space. */
+ int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' ');
+ size_t helpLength;
char * defs = NULL;
char * left;
- int nb = maxLeftCol + 1;
+ size_t nb = maxLeftCol + 1;
+ int displaypad = 0;
+ int xx;
/* Make sure there's more than enough room in target buffer. */
if (opt->longName) nb += strlen(opt->longName);
+ if (F_ISSET(opt, TOGGLE)) nb += sizeof("[no]") - 1;
if (argDescrip) nb += strlen(argDescrip);
-/*@-boundswrite@*/
- left = (char *)malloc(nb);
+ left = malloc(nb);
if (left == NULL) return; /* XXX can't happen */
left[0] = '\0';
left[maxLeftCol] = '\0';
- if (opt->longName && opt->shortName)
- sprintf(left, "-%c, %s%s", opt->shortName,
- ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
- opt->longName);
- else if (opt->shortName != '\0')
- sprintf(left, "-%c", opt->shortName);
- else if (opt->longName)
- sprintf(left, "%s%s",
- ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
- opt->longName);
- if (!*left) goto out;
+#define prtlong (opt->longName != NULL) /* XXX splint needs a clue */
+ if (!(prtshort || prtlong))
+ goto out;
+ if (prtshort && prtlong) {
+ char *dash = F_ISSET(opt, ONEDASH) ? "-" : "--";
+ left[0] = '-';
+ left[1] = opt->shortName;
+ (void) stpcpy(stpcpy(stpcpy(left+2, ", "), dash), opt->longName);
+ } else if (prtshort) {
+ left[0] = '-';
+ left[1] = opt->shortName;
+ left[2] = '\0';
+ } else if (prtlong) {
+ /* XXX --long always padded for alignment with/without "-X, ". */
+ char *dash = poptArgType(opt) == POPT_ARG_MAINCALL ? ""
+ : (F_ISSET(opt, ONEDASH) ? "-" : "--");
+ const char *longName = opt->longName;
+ const char *toggle;
+ if (F_ISSET(opt, TOGGLE)) {
+ toggle = "[no]";
+ if (longName[0] == 'n' && longName[1] == 'o') {
+ longName += sizeof("no") - 1;
+ if (longName[0] == '-')
+ longName++;
+ }
+ } else
+ toggle = "";
+ (void) stpcpy(stpcpy(stpcpy(stpcpy(left, " "), dash), toggle), longName);
+ }
+#undef prtlong
if (argDescrip) {
char * le = left + strlen(left);
- if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
+ if (F_ISSET(opt, OPTIONAL))
*le++ = '[';
/* Choose type of output */
- /*@-branchstate@*/
- if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
- defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
- if (defs) {
- char * t = (char *)malloc((help ? strlen(help) : 0) +
+ if (F_ISSET(opt, SHOW_DEFAULT)) {
+ defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
+ if (defs) {
+ char * t = malloc((help ? strlen(help) : 0) +
strlen(defs) + sizeof(" "));
- if (t) {
- char * te = t;
- *te = '\0';
- if (help) {
- strcpy(te, help);
- te += strlen(te);
- }
- *te++ = ' ';
- strcpy(te, defs);
- }
- defs = (char *)_free(defs);
- defs = t;
+ if (t) {
+ char * te = t;
+ if (help)
+ te = stpcpy(te, help);
+ *te++ = ' ';
+ strcpy(te, defs);
+ defs = _free(defs);
+ defs = t;
}
+ }
}
- /*@=branchstate@*/
if (opt->argDescrip == NULL) {
- switch (opt->argInfo & POPT_ARG_MASK) {
+ switch (poptArgType(opt)) {
case POPT_ARG_NONE:
break;
case POPT_ARG_VAL:
#ifdef NOTNOW /* XXX pug ugly nerdy output */
{ long aLong = opt->val;
- int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
- int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
+ int ops = F_ISSET(opt, LOGICALOPS);
+ int negate = F_ISSET(opt, NOT);
/* Don't bother displaying typical values */
if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
@@ -287,7 +416,7 @@ static void singleOptionHelp(FILE * fp, int maxLeftCol,
default:
/*@innerbreak@*/ break;
}
- *le++ = '=';
+ *le++ = (opt->longName != NULL ? '=' : ' ');
if (negate) *le++ = '~';
/*@-formatconst@*/
le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong);
@@ -297,104 +426,133 @@ static void singleOptionHelp(FILE * fp, int maxLeftCol,
#endif
break;
case POPT_ARG_INT:
+ case POPT_ARG_SHORT:
case POPT_ARG_LONG:
+ case POPT_ARG_LONGLONG:
case POPT_ARG_FLOAT:
case POPT_ARG_DOUBLE:
case POPT_ARG_STRING:
- *le++ = '=';
- strcpy(le, argDescrip); le += strlen(le);
+ *le++ = (opt->longName != NULL ? '=' : ' ');
+ le = stpcpy(le, argDescrip);
break;
default:
break;
}
} else {
- *le++ = '=';
- strcpy(le, argDescrip); le += strlen(le);
+ char *leo;
+
+ /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
+ if (!strchr(" =(", argDescrip[0]))
+ *le++ = ((poptArgType(opt) == POPT_ARG_MAINCALL) ? ' ' :
+ (poptArgType(opt) == POPT_ARG_ARGV) ? ' ' : '=');
+ le = stpcpy(leo = le, argDescrip);
+
+ /* Adjust for (possible) wide characters. */
+ displaypad = (int)((le - leo) - stringDisplayWidth(argDescrip));
}
- if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
+ if (F_ISSET(opt, OPTIONAL))
*le++ = ']';
*le = '\0';
}
-/*@=boundswrite@*/
if (help)
- fprintf(fp," %-*s ", maxLeftCol, left);
+ xx = POPT_fprintf(fp," %-*s ", (int)(maxLeftCol+displaypad), left);
else {
- fprintf(fp," %s\n", left);
+ xx = POPT_fprintf(fp," %s\n", left);
goto out;
}
- left = (char *)_free(left);
- if (defs) {
+ left = _free(left);
+ if (defs)
help = defs;
- }
helpLength = strlen(help);
-/*@-boundsread@*/
while (helpLength > lineLength) {
const char * ch;
char format[16];
ch = help + lineLength - 1;
- while (ch > help && !isspace(*ch)) ch--;
+ while (ch > help && !_isspaceptr(ch))
+ ch = POPT_prev_char(ch);
if (ch == help) break; /* give up */
- while (ch > (help + 1) && isspace(*ch)) ch--;
- ch++;
+ while (ch > (help + 1) && _isspaceptr(ch))
+ ch = POPT_prev_char (ch);
+ ch = POPT_next_char(ch);
+
+ /*
+ * XXX strdup is necessary to add NUL terminator so that an unknown
+ * no. of (possible) multi-byte characters can be displayed.
+ */
+ { char * fmthelp = xstrdup(help);
+ if (fmthelp) {
+ fmthelp[ch - help] = '\0';
+ sprintf(format, "%%s\n%%%ds", (int) indentLength);
+ /*@-formatconst@*/
+ xx = POPT_fprintf(fp, format, fmthelp, " ");
+ /*@=formatconst@*/
+ free(fmthelp);
+ }
+ }
- sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength);
- /*@-formatconst@*/
- fprintf(fp, format, help, " ");
- /*@=formatconst@*/
help = ch;
- while (isspace(*help) && *help) help++;
+ while (_isspaceptr(help) && *help)
+ help = POPT_next_char(help);
helpLength = strlen(help);
}
-/*@=boundsread@*/
if (helpLength) fprintf(fp, "%s\n", help);
+ help = NULL;
out:
/*@-dependenttrans@*/
- defs = (char *)_free(defs);
+ defs = _free(defs);
/*@=dependenttrans@*/
- left = (char *)_free(left);
+ left = _free(left);
}
/**
+ * Find display width for longest argument string.
* @param opt option(s)
* @param translation_domain translation domain
+ * @return display width
*/
-static int maxArgWidth(const struct poptOption * opt,
+static size_t maxArgWidth(const struct poptOption * opt,
/*@null@*/ const char * translation_domain)
/*@*/
{
- int max = 0;
- int len = 0;
- const char * s;
+ size_t max = 0;
+ size_t len = 0;
+ const char * argDescrip;
if (opt != NULL)
while (opt->longName || opt->shortName || opt->arg) {
- if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
+ if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) {
if (opt->arg) /* XXX program error */
- len = maxArgWidth((const struct poptOption *)opt->arg, translation_domain);
+ len = maxArgWidth(opt->arg, translation_domain);
if (len > max) max = len;
- } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
+ } else if (!F_ISSET(opt, DOC_HIDDEN)) {
len = sizeof(" ")-1;
- if (opt->shortName != '\0') len += sizeof("-X")-1;
- if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1;
+ /* XXX --long always padded for alignment with/without "-X, ". */
+ len += sizeof("-X, ")-1;
if (opt->longName) {
- len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
- ? sizeof("-")-1 : sizeof("--")-1);
+ len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1;
len += strlen(opt->longName);
}
- s = getArgDescrip(opt, translation_domain);
- if (s)
- len += sizeof("=")-1 + strlen(s);
- if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
+ argDescrip = getArgDescrip(opt, translation_domain);
+
+ if (argDescrip) {
+
+ /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
+ if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1;
+
+ /* Adjust for (possible) wide characters. */
+ len += stringDisplayWidth(argDescrip);
+ }
+
+ if (F_ISSET(opt, OPTIONAL)) len += sizeof("[]")-1;
if (len > max) max = len;
}
-
opt++;
}
@@ -406,14 +564,15 @@ static int maxArgWidth(const struct poptOption * opt,
* @param fp output file handle
* @param items alias/exec array
* @param nitems no. of alias/exec entries
- * @param left
+ * @param columns output display width control
* @param translation_domain translation domain
*/
static void itemHelp(FILE * fp,
- /*@null@*/ poptItem items, int nitems, int left,
+ /*@null@*/ poptItem items, int nitems,
+ columns_t columns,
/*@null@*/ const char * translation_domain)
/*@globals fileSystem @*/
- /*@modifies *fp, fileSystem @*/
+ /*@modifies fp, fileSystem @*/
{
poptItem item;
int i;
@@ -422,9 +581,8 @@ static void itemHelp(FILE * fp,
for (i = 0, item = items; i < nitems; i++, item++) {
const struct poptOption * opt;
opt = &item->option;
- if ((opt->longName || opt->shortName) &&
- !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
- singleOptionHelp(fp, left, opt, translation_domain);
+ if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN))
+ singleOptionHelp(fp, columns, opt, translation_domain);
}
}
@@ -433,44 +591,47 @@ static void itemHelp(FILE * fp,
* @param con context
* @param fp output file handle
* @param table option(s)
- * @param left
+ * @param columns output display width control
* @param translation_domain translation domain
*/
static void singleTableHelp(poptContext con, FILE * fp,
- /*@null@*/ const struct poptOption * table, int left,
+ /*@null@*/ const struct poptOption * table,
+ columns_t columns,
/*@null@*/ const char * translation_domain)
/*@globals fileSystem @*/
- /*@modifies *fp, fileSystem @*/
+ /*@modifies fp, columns->cur, fileSystem @*/
{
const struct poptOption * opt;
const char *sub_transdom;
+ int xx;
if (table == poptAliasOptions) {
- itemHelp(fp, con->aliases, con->numAliases, left, NULL);
- itemHelp(fp, con->execs, con->numExecs, left, NULL);
+ itemHelp(fp, con->aliases, con->numAliases, columns, NULL);
+ itemHelp(fp, con->execs, con->numExecs, columns, NULL);
return;
}
if (table != NULL)
- for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
- if ((opt->longName || opt->shortName) &&
- !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
- singleOptionHelp(fp, left, opt, translation_domain);
+ for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
+ if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN))
+ singleOptionHelp(fp, columns, opt, translation_domain);
}
if (table != NULL)
- for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
- if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
+ for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
+ if (poptArgType(opt) != POPT_ARG_INCLUDE_TABLE)
continue;
- sub_transdom = getTableTranslationDomain(
- (const struct poptOption *)opt->arg);
+ sub_transdom = getTableTranslationDomain(opt->arg);
if (sub_transdom == NULL)
sub_transdom = translation_domain;
+ /* If no popt aliases/execs, skip poptAliasOption processing. */
+ if (opt->arg == poptAliasOptions && !(con->numAliases || con->numExecs))
+ continue;
if (opt->descrip)
- fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
+ xx = POPT_fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
- singleTableHelp(con, fp, (const struct poptOption *)opt->arg, left, sub_transdom);
+ singleTableHelp(con, fp, opt->arg, columns, sub_transdom);
}
}
@@ -478,22 +639,20 @@ static void singleTableHelp(poptContext con, FILE * fp,
* @param con context
* @param fp output file handle
*/
-static int showHelpIntro(poptContext con, FILE * fp)
+static size_t showHelpIntro(poptContext con, FILE * fp)
/*@globals fileSystem @*/
- /*@modifies *fp, fileSystem @*/
+ /*@modifies fp, fileSystem @*/
{
- int len = 6;
- const char * fn;
+ size_t len = (size_t)6;
+ int xx;
- fprintf(fp, POPT_("Usage:"));
+ xx = POPT_fprintf(fp, POPT_("Usage:"));
if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
-/*@-boundsread@*/
- /*@-nullderef@*/ /* LCL: wazzup? */
- fn = con->optionStack->argv[0];
- /*@=nullderef@*/
-/*@=boundsread@*/
+ struct optionStackEntry * os = con->optionStack;
+ const char * fn = (os->argv ? os->argv[0] : NULL);
if (fn == NULL) return len;
if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
+ /* XXX POPT_fprintf not needed for argv[0] display. */
fprintf(fp, " %s", fn);
len += strlen(fn) + 1;
}
@@ -501,108 +660,119 @@ static int showHelpIntro(poptContext con, FILE * fp)
return len;
}
-void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags)
+void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
{
- int leftColWidth;
+ columns_t columns = calloc((size_t)1, sizeof(*columns));
+ int xx;
(void) showHelpIntro(con, fp);
if (con->otherHelp)
- fprintf(fp, " %s\n", con->otherHelp);
+ xx = POPT_fprintf(fp, " %s\n", con->otherHelp);
else
- fprintf(fp, " %s\n", POPT_("[OPTION...]"));
+ xx = POPT_fprintf(fp, " %s\n", POPT_("[OPTION...]"));
- leftColWidth = maxArgWidth(con->options, NULL);
- singleTableHelp(con, fp, con->options, leftColWidth, NULL);
+ if (columns) {
+ columns->cur = maxArgWidth(con->options, NULL);
+ columns->max = maxColumnWidth(fp);
+ singleTableHelp(con, fp, con->options, columns, NULL);
+ free(columns);
+ }
}
/**
+ * Display usage text for an option.
* @param fp output file handle
- * @param cursor
+ * @param columns output display width control
* @param opt option(s)
* @param translation_domain translation domain
*/
-static int singleOptionUsage(FILE * fp, int cursor,
+static size_t singleOptionUsage(FILE * fp, columns_t columns,
const struct poptOption * opt,
/*@null@*/ const char *translation_domain)
/*@globals fileSystem @*/
- /*@modifies *fp, fileSystem @*/
+ /*@modifies fp, columns->cur, fileSystem @*/
{
- int len = 4;
- char shortStr[2] = { '\0', '\0' };
- const char * item = shortStr;
+ size_t len = sizeof(" []")-1;
const char * argDescrip = getArgDescrip(opt, translation_domain);
-
- if (opt->shortName != '\0' && opt->longName != NULL) {
- len += 2;
- if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
- len += strlen(opt->longName);
- } else if (opt->shortName != '\0') {
- len++;
- shortStr[0] = opt->shortName;
- shortStr[1] = '\0';
- } else if (opt->longName) {
+ /* Display shortName iff printable non-space. */
+ int prtshort = (int)(isprint((int)opt->shortName) && opt->shortName != ' ');
+
+#define prtlong (opt->longName != NULL) /* XXX splint needs a clue */
+ if (!(prtshort || prtlong))
+ return columns->cur;
+
+ len = sizeof(" []")-1;
+ if (prtshort)
+ len += sizeof("-c")-1;
+ if (prtlong) {
+ if (prtshort) len += sizeof("|")-1;
+ len += (F_ISSET(opt, ONEDASH) ? sizeof("-") : sizeof("--")) - 1;
len += strlen(opt->longName);
- if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
- item = opt->longName;
}
- if (len == 4) return cursor;
+ if (argDescrip) {
+
+ /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
+ if (!strchr(" =(", argDescrip[0])) len += sizeof("=")-1;
- if (argDescrip)
- len += strlen(argDescrip) + 1;
+ /* Adjust for (possible) wide characters. */
+ len += stringDisplayWidth(argDescrip);
+ }
- if ((cursor + len) > 79) {
+ if ((columns->cur + len) > columns->max) {
fprintf(fp, "\n ");
- cursor = 7;
+ columns->cur = (size_t)7;
}
- if (opt->longName && opt->shortName) {
- fprintf(fp, " [-%c|-%s%s%s%s]",
- opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"),
- opt->longName,
- (argDescrip ? " " : ""),
- (argDescrip ? argDescrip : ""));
- } else {
- fprintf(fp, " [-%s%s%s%s]",
- ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
- item,
- (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
- (argDescrip ? argDescrip : ""));
+ fprintf(fp, " [");
+ if (prtshort)
+ fprintf(fp, "-%c", opt->shortName);
+ if (prtlong)
+ fprintf(fp, "%s%s%s",
+ (prtshort ? "|" : ""),
+ (F_ISSET(opt, ONEDASH) ? "-" : "--"),
+ opt->longName);
+#undef prtlong
+
+ if (argDescrip) {
+ /* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
+ if (!strchr(" =(", argDescrip[0])) fprintf(fp, "=");
+ fprintf(fp, "%s", argDescrip);
}
+ fprintf(fp, "]");
- return cursor + len + 1;
+ return columns->cur + len + 1;
}
/**
* Display popt alias and exec usage.
* @param fp output file handle
- * @param cursor
+ * @param columns output display width control
* @param item alias/exec array
* @param nitems no. of ara/exec entries
* @param translation_domain translation domain
*/
-static int itemUsage(FILE * fp, int cursor, poptItem item, int nitems,
+static size_t itemUsage(FILE * fp, columns_t columns,
+ /*@null@*/ poptItem item, int nitems,
/*@null@*/ const char * translation_domain)
/*@globals fileSystem @*/
- /*@modifies *fp, fileSystem @*/
+ /*@modifies fp, columns->cur, fileSystem @*/
{
int i;
- /*@-branchstate@*/ /* FIX: W2DO? */
if (item != NULL)
for (i = 0; i < nitems; i++, item++) {
const struct poptOption * opt;
opt = &item->option;
- if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
+ if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) {
translation_domain = (const char *)opt->arg;
- } else if ((opt->longName || opt->shortName) &&
- !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
- cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
+ } else
+ if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) {
+ columns->cur = singleOptionUsage(fp, columns, opt, translation_domain);
}
}
- /*@=branchstate@*/
- return cursor;
+ return columns->cur;
}
/**
@@ -611,6 +781,7 @@ static int itemUsage(FILE * fp, int cursor, poptItem item, int nitems,
typedef struct poptDone_s {
int nopts;
int maxopts;
+/*@null@*/
const void ** opts;
} * poptDone;
@@ -618,31 +789,30 @@ typedef struct poptDone_s {
* Display usage text for a table of options.
* @param con context
* @param fp output file handle
- * @param cursor
+ * @param columns output display width control
* @param opt option(s)
* @param translation_domain translation domain
* @param done tables already processed
* @return
*/
-static int singleTableUsage(poptContext con, FILE * fp, int cursor,
+static size_t singleTableUsage(poptContext con, FILE * fp, columns_t columns,
/*@null@*/ const struct poptOption * opt,
/*@null@*/ const char * translation_domain,
/*@null@*/ poptDone done)
/*@globals fileSystem @*/
- /*@modifies *fp, done, fileSystem @*/
+ /*@modifies fp, columns->cur, done, fileSystem @*/
{
- /*@-branchstate@*/ /* FIX: W2DO? */
if (opt != NULL)
for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
- if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
+ if (poptArgType(opt) == POPT_ARG_INTL_DOMAIN) {
translation_domain = (const char *)opt->arg;
- } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
+ } else
+ if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE) {
if (done) {
int i = 0;
+ if (done->opts != NULL)
for (i = 0; i < done->nopts; i++) {
-/*@-boundsread@*/
const void * that = done->opts[i];
-/*@=boundsread@*/
if (that == NULL || that != opt->arg)
/*@innercontinue@*/ continue;
/*@innerbreak@*/ break;
@@ -650,21 +820,18 @@ static int singleTableUsage(poptContext con, FILE * fp, int cursor,
/* Skip if this table has already been processed. */
if (opt->arg == NULL || i < done->nopts)
continue;
-/*@-boundswrite@*/
- if (done->nopts < done->maxopts)
+ if (done->opts != NULL && done->nopts < done->maxopts)
done->opts[done->nopts++] = (const void *) opt->arg;
-/*@=boundswrite@*/
}
- cursor = singleTableUsage(con, fp, cursor, (const struct poptOption *)opt->arg,
+ columns->cur = singleTableUsage(con, fp, columns, opt->arg,
translation_domain, done);
- } else if ((opt->longName || opt->shortName) &&
- !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
- cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
+ } else
+ if ((opt->longName || opt->shortName) && !F_ISSET(opt, DOC_HIDDEN)) {
+ columns->cur = singleOptionUsage(fp, columns, opt, translation_domain);
}
}
- /*@=branchstate@*/
- return cursor;
+ return columns->cur;
}
/**
@@ -675,67 +842,84 @@ static int singleTableUsage(poptContext con, FILE * fp, int cursor,
* @retval str concatenation of short options
* @return length of display string
*/
-static int showShortOptions(const struct poptOption * opt, FILE * fp,
+static size_t showShortOptions(const struct poptOption * opt, FILE * fp,
/*@null@*/ char * str)
/*@globals fileSystem @*/
- /*@modifies *str, *fp, fileSystem @*/
+ /*@modifies str, *fp, fileSystem @*/
/*@requires maxRead(str) >= 0 @*/
{
- /* bufsize larger then the ascii set, lazy alloca on top level call. */
- char * s = (str != NULL ? str : (char *)memset(alloca(300), 0, 300));
- int len = 0;
+ /* bufsize larger then the ascii set, lazy allocation on top level call. */
+ size_t nb = (size_t)300;
+ char * s = (str != NULL ? str : calloc((size_t)1, nb));
+ size_t len = (size_t)0;
+
+ if (s == NULL)
+ return 0;
-/*@-boundswrite@*/
if (opt != NULL)
for (; (opt->longName || opt->shortName || opt->arg); opt++) {
- if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
- s[strlen(s)] = opt->shortName;
- else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
+ if (!F_ISSET(opt, DOC_HIDDEN) && opt->shortName && !poptArgType(opt))
+ {
+ /* Display shortName iff unique printable non-space. */
+ if (!strchr(s, opt->shortName) && isprint((int)opt->shortName)
+ && opt->shortName != ' ')
+ s[strlen(s)] = opt->shortName;
+ } else if (poptArgType(opt) == POPT_ARG_INCLUDE_TABLE)
if (opt->arg) /* XXX program error */
- len = showShortOptions(
- (const struct poptOption *)opt->arg, fp, s);
+ len = showShortOptions(opt->arg, fp, s);
}
-/*@=boundswrite@*/
/* On return to top level, print the short options, return print length. */
- if (s == str && *s != '\0') {
+ if (s != str && *s != '\0') {
fprintf(fp, " [-%s]", s);
len = strlen(s) + sizeof(" [-]")-1;
}
+/*@-temptrans@*/ /* LCL: local s, not str arg, is being freed. */
+ if (s != str)
+ free(s);
+/*@=temptrans@*/
return len;
}
-void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags)
+void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
{
- poptDone done = (poptDone)memset(alloca(sizeof(*done)), 0, sizeof(*done));
- int cursor;
+ columns_t columns = calloc((size_t)1, sizeof(*columns));
+ struct poptDone_s done_buf;
+ poptDone done = &done_buf;
+ memset(done, 0, sizeof(*done));
done->nopts = 0;
done->maxopts = 64;
- cursor = done->maxopts * sizeof(*done->opts);
-/*@-boundswrite@*/
- done->opts = (const void **)memset(alloca(cursor), 0, cursor);
- done->opts[done->nopts++] = (const void *) con->options;
-/*@=boundswrite@*/
-
- cursor = showHelpIntro(con, fp);
- cursor += showShortOptions(con->options, fp, NULL);
- cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done);
- cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
- cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
+ if (columns) {
+ columns->cur = done->maxopts * sizeof(*done->opts);
+ columns->max = maxColumnWidth(fp);
+ done->opts = calloc((size_t)1, columns->cur);
+ /*@-keeptrans@*/
+ if (done->opts != NULL)
+ done->opts[done->nopts++] = (const void *) con->options;
+ /*@=keeptrans@*/
+
+ columns->cur = showHelpIntro(con, fp);
+ columns->cur += showShortOptions(con->options, fp, NULL);
+ columns->cur = singleTableUsage(con, fp, columns, con->options, NULL, done);
+ columns->cur = itemUsage(fp, columns, con->aliases, con->numAliases, NULL);
+ columns->cur = itemUsage(fp, columns, con->execs, con->numExecs, NULL);
if (con->otherHelp) {
- cursor += strlen(con->otherHelp) + 1;
- if (cursor > 79) fprintf(fp, "\n ");
+ columns->cur += strlen(con->otherHelp) + 1;
+ if (columns->cur > columns->max) fprintf(fp, "\n ");
fprintf(fp, " %s", con->otherHelp);
}
fprintf(fp, "\n");
+ if (done->opts != NULL)
+ free(done->opts);
+ free(columns);
+ }
}
void poptSetOtherOptionHelp(poptContext con, const char * text)
{
- con->otherHelp = (const char *)_free(con->otherHelp);
+ con->otherHelp = _free(con->otherHelp);
con->otherHelp = xstrdup(text);
}
-/*@=type@*/
diff --git a/third_party/popt/poptint.c b/third_party/popt/poptint.c
new file mode 100644
index 00000000000..1af46ff8c7b
--- /dev/null
+++ b/third_party/popt/poptint.c
@@ -0,0 +1,199 @@
+#include "system.h"
+#include <stdarg.h>
+#include "poptint.h"
+
+/* Any pair of 32 bit hashes can be used. lookup3.c generates pairs, will do. */
+#define _JLU3_jlu32lpair 1
+#define jlu32lpair poptJlu32lpair
+#include "lookup3.c"
+
+/*@-varuse +charint +ignoresigns @*/
+/*@unchecked@*/ /*@observer@*/
+static const unsigned char utf8_skip_data[256] = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
+};
+/*@=varuse =charint =ignoresigns @*/
+
+const char *
+POPT_prev_char (const char *str)
+{
+ const char *p = str;
+
+ while (1) {
+ p--;
+ if (((unsigned)*p & 0xc0) != (unsigned)0x80)
+ return p;
+ }
+}
+
+const char *
+POPT_next_char (const char *str)
+{
+ const char *p = str;
+
+ while (*p != '\0') {
+ p++;
+ if (((unsigned)*p & 0xc0) != (unsigned)0x80)
+ break;
+ }
+ return p;
+}
+
+#if !defined(POPT_fprintf) /* XXX lose all the goop ... */
+
+#if defined(HAVE_DCGETTEXT) && !defined(__LCLINT__)
+/*
+ * Rebind a "UTF-8" codeset for popt's internal use.
+ */
+char *
+POPT_dgettext(const char * dom, const char * str)
+{
+ char * codeset = NULL;
+ char * retval = NULL;
+
+ if (!dom)
+ dom = textdomain(NULL);
+ codeset = bind_textdomain_codeset(dom, NULL);
+ bind_textdomain_codeset(dom, "UTF-8");
+ retval = dgettext(dom, str);
+ bind_textdomain_codeset(dom, codeset);
+
+ return retval;
+}
+#endif
+
+#ifdef HAVE_ICONV
+/**
+ * Return malloc'd string converted from UTF-8 to current locale.
+ * @param istr input string (UTF-8 encoding assumed)
+ * @return localized string
+ */
+static /*@only@*/ /*@null@*/ char *
+strdup_locale_from_utf8 (/*@null@*/ char * istr)
+ /*@*/
+{
+ char * codeset = NULL;
+ char * ostr = NULL;
+ iconv_t cd;
+
+ if (istr == NULL)
+ return NULL;
+
+#ifdef HAVE_LANGINFO_H
+ codeset = nl_langinfo ((nl_item)CODESET);
+#endif
+
+ if (codeset != NULL && strcmp(codeset, "UTF-8") != 0
+ && (cd = iconv_open(codeset, "UTF-8")) != (iconv_t)-1)
+ {
+ char * shift_pin = NULL;
+ size_t db = strlen(istr);
+/*@owned@*/
+ char * dstr = malloc((db + 1) * sizeof(*dstr));
+ char * pin = istr;
+ char * pout = dstr;
+ size_t ib = db;
+ size_t ob = db;
+ size_t err;
+
+ if (dstr == NULL)
+ return NULL;
+ err = iconv(cd, NULL, NULL, NULL, NULL);
+ while (1) {
+ *pout = '\0';
+ err = iconv(cd, &pin, &ib, &pout, &ob);
+ if (err != (size_t)-1) {
+ if (shift_pin == NULL) {
+ shift_pin = pin;
+ pin = NULL;
+ ib = 0;
+ continue;
+ }
+ } else
+ switch (errno) {
+ case E2BIG:
+ { size_t used = (size_t)(pout - dstr);
+ db *= 2;
+ dstr = realloc(dstr, (db + 1) * sizeof(*dstr));
+ if (dstr != NULL) {
+ pout = dstr + used;
+ ob = db - used;
+ continue;
+ }
+ } /*@switchbreak@*/ break;
+ case EINVAL:
+ case EILSEQ:
+ default:
+ /*@switchbreak@*/ break;
+ }
+ break;
+ }
+ (void) iconv_close(cd);
+ *pout = '\0';
+ ostr = xstrdup(dstr);
+ free(dstr);
+ } else
+ ostr = xstrdup(istr);
+
+ return ostr;
+}
+#endif
+
+int
+POPT_fprintf (FILE * stream, const char * format, ...)
+{
+ char * b = NULL, * ob = NULL;
+ int rc;
+ va_list ap;
+
+#if defined(HAVE_VASPRINTF) && !defined(__LCLINT__)
+ va_start(ap, format);
+ if ((rc = vasprintf(&b, format, ap)) < 0)
+ b = NULL;
+ va_end(ap);
+#else
+ size_t nb = (size_t)1;
+
+ /* HACK: add +1 to the realloc no. of bytes "just in case". */
+ /* XXX Likely unneeded, the issues wrto vsnprintf(3) return b0rkage have
+ * to do with whether the final '\0' is counted (or not). The code
+ * below already adds +1 for the (possibly already counted) trailing NUL.
+ */
+ while ((b = realloc(b, nb+1)) != NULL) {
+ va_start(ap, format);
+ rc = vsnprintf(b, nb, format, ap);
+ va_end(ap);
+ if (rc > -1) { /* glibc 2.1 */
+ if ((size_t)rc < nb)
+ break;
+ nb = (size_t)(rc + 1); /* precise buffer length known */
+ } else /* glibc 2.0 */
+ nb += (nb < (size_t)100 ? (size_t)100 : nb);
+ ob = b;
+ }
+#endif
+
+ rc = 0;
+ if (b != NULL) {
+#ifdef HAVE_ICONV
+ ob = strdup_locale_from_utf8(b);
+ if (ob != NULL) {
+ rc = fprintf(stream, "%s", ob);
+ free(ob);
+ } else
+#endif
+ rc = fprintf(stream, "%s", b);
+ free (b);
+ }
+
+ return rc;
+}
+
+#endif /* !defined(POPT_fprintf) */
diff --git a/third_party/popt/poptint.h b/third_party/popt/poptint.h
index 5d308efe96a..80cbaca0faf 100644
--- a/third_party/popt/poptint.h
+++ b/third_party/popt/poptint.h
@@ -9,6 +9,8 @@
#ifndef H_POPTINT
#define H_POPTINT
+#include <stdint.h>
+
/**
* Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
* @param p memory to free
@@ -42,15 +44,67 @@ typedef struct {
#define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
#define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
+extern void poptJlu32lpair(/*@null@*/ const void *key, size_t size,
+ uint32_t *pc, uint32_t *pb)
+ /*@modifies *pc, *pb@*/;
+
+/** \ingroup popt
+ * Typedef's for string and array of strings.
+ */
+/*@-exporttype@*/
+typedef const char * poptString;
+typedef poptString * poptArgv;
+/*@=exporttype@*/
+
+/** \ingroup popt
+ * A union to simplify opt->arg access without casting.
+ */
+/*@-exporttype -fielduse@*/
+typedef union poptArg_u {
+/*@shared@*/
+ void * ptr;
+ int * intp;
+ short * shortp;
+ long * longp;
+ long long * longlongp;
+ float * floatp;
+ double * doublep;
+ const char ** argv;
+ poptCallbackType cb;
+/*@shared@*/
+ poptOption opt;
+} poptArg;
+/*@=exporttype =fielduse@*/
+
+/*@-exportvar@*/
+/*@unchecked@*/
+extern unsigned int _poptArgMask;
+/*@unchecked@*/
+extern unsigned int _poptGroupMask;
+/*@=exportvar@*/
+
+#define poptArgType(_opt) ((_opt)->argInfo & _poptArgMask)
+#define poptGroup(_opt) ((_opt)->argInfo & _poptGroupMask)
+
+#define F_ISSET(_opt, _FLAG) ((_opt)->argInfo & POPT_ARGFLAG_##_FLAG)
+#define LF_ISSET(_FLAG) (argInfo & POPT_ARGFLAG_##_FLAG)
+#define CBF_ISSET(_opt, _FLAG) ((_opt)->argInfo & POPT_CBFLAG_##_FLAG)
+
+/* XXX sick hack to preserve pretense of a popt-1.x ABI. */
+#define poptSubstituteHelpI18N(opt) \
+ { /*@-observertrans@*/ \
+ if ((opt) == poptHelpOptions) (opt) = poptHelpOptionsI18N; \
+ /*@=observertrans@*/ }
+
struct optionStackEntry {
int argc;
/*@only@*/ /*@null@*/
- const char ** argv;
+ poptArgv argv;
/*@only@*/ /*@null@*/
pbm_set * argb;
int next;
/*@only@*/ /*@null@*/
- const char * nextArg;
+ char * nextArg;
/*@observer@*/ /*@null@*/
const char * nextCharArg;
/*@dependent@*/ /*@null@*/
@@ -63,7 +117,7 @@ struct poptContext_s {
/*@dependent@*/
struct optionStackEntry * os;
/*@owned@*/ /*@null@*/
- const char ** leftovers;
+ poptArgv leftovers;
int numLeftovers;
int nextLeftover;
/*@keep@*/
@@ -74,37 +128,90 @@ struct poptContext_s {
/*@only@*/ /*@null@*/
poptItem aliases;
int numAliases;
- int flags;
+ unsigned int flags;
/*@owned@*/ /*@null@*/
poptItem execs;
int numExecs;
/*@only@*/ /*@null@*/
- const char ** finalArgv;
+ poptArgv finalArgv;
int finalArgvCount;
int finalArgvAlloced;
+/*@null@*/
+ int (*maincall) (int argc, const char **argv);
/*@dependent@*/ /*@null@*/
poptItem doExec;
-/*@only@*/
+/*@only@*/ /*@null@*/
const char * execPath;
int execAbsolute;
-/*@only@*/
+/*@only@*/ /*@relnull@*/
const char * otherHelp;
/*@null@*/
pbm_set * arg_strip;
};
-#ifdef HAVE_LIBINTL_H
+#if defined(POPT_fprintf)
+#define POPT_dgettext dgettext
+#else
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#if defined(__LCLINT__)
+/*@-declundef -incondefs @*/
+extern /*@only@*/ iconv_t iconv_open(const char *__tocode, const char *__fromcode)
+ /*@*/;
+
+extern size_t iconv(iconv_t __cd, /*@null@*/ char ** __inbuf,
+ /*@null@*/ /*@out@*/ size_t * __inbytesleft,
+ /*@null@*/ /*@out@*/ char ** __outbuf,
+ /*@null@*/ /*@out@*/ size_t * __outbytesleft)
+ /*@modifies __cd,
+ *__inbuf, *__inbytesleft, *__outbuf, *__outbytesleft @*/;
+
+extern int iconv_close(/*@only@*/ iconv_t __cd)
+ /*@modifies __cd @*/;
+/*@=declundef =incondefs @*/
+#endif
+#endif
+
+#ifdef HAVE_LANGINFO_H
+#include <langinfo.h>
+#if defined(__LCLINT__)
+/*@-declundef -incondefs @*/
+extern char *nl_langinfo (nl_item __item)
+ /*@*/;
+/*@=declundef =incondefs @*/
+#endif
+#endif
+
+#if defined(HAVE_DCGETTEXT) && !defined(__LCLINT__)
+char *POPT_dgettext(const char * dom, const char * str)
+ /*@*/;
+#endif
+
+int POPT_fprintf (FILE* stream, const char *format, ...)
+ /*@globals fileSystem @*/
+ /*@modifies stream, fileSystem @*/;
+#endif /* !defined(POPT_fprintf) */
+
+const char *POPT_prev_char (/*@returned@*/ const char *str)
+ /*@*/;
+
+const char *POPT_next_char (/*@returned@*/ const char *str)
+ /*@*/;
+
+#endif
+
+#if defined(ENABLE_NLS) && defined(HAVE_LIBINTL_H)
#include <libintl.h>
#endif
-#if defined(HAVE_GETTEXT) && !defined(__LCLINT__)
+#if defined(ENABLE_NLS) && defined(HAVE_GETTEXT) && !defined(__LCLINT__)
#define _(foo) gettext(foo)
#else
#define _(foo) foo
#endif
-#if defined(HAVE_DCGETTEXT) && !defined(__LCLINT__)
-#define D_(dom, str) dgettext(dom, str)
+#if defined(ENABLE_NLS) && defined(HAVE_DCGETTEXT) && !defined(__LCLINT__)
+#define D_(dom, str) POPT_dgettext(dom, str)
#define POPT_(foo) D_("popt", foo)
#else
#define D_(dom, str) str
@@ -113,4 +220,3 @@ struct poptContext_s {
#define N_(foo) foo
-#endif
diff --git a/third_party/popt/poptparse.c b/third_party/popt/poptparse.c
index b03deef0850..39bf1aad195 100644
--- a/third_party/popt/poptparse.c
+++ b/third_party/popt/poptparse.c
@@ -10,7 +10,6 @@
#define POPT_ARGV_ARRAY_GROW_DELTA 5
-/*@-boundswrite@*/
int poptDupArgv(int argc, const char **argv,
int * argcPtr, const char *** argvPtr)
{
@@ -27,18 +26,18 @@ int poptDupArgv(int argc, const char **argv,
nb += strlen(argv[i]) + 1;
}
- dst = (char *)malloc(nb);
+ dst = malloc(nb);
if (dst == NULL) /* XXX can't happen */
return POPT_ERROR_MALLOC;
- argv2 = (const char **) dst;
+ argv2 = (void *) dst;
dst += (argc + 1) * sizeof(*argv);
+ *dst = '\0';
- /*@-branchstate@*/
for (i = 0; i < argc; i++) {
argv2[i] = dst;
- dst += strlen(strcpy(dst, argv[i])) + 1;
+ dst = stpcpy(dst, argv[i]);
+ dst++; /* trailing NUL */
}
- /*@=branchstate@*/
argv2[argc] = NULL;
if (argvPtr) {
@@ -51,21 +50,24 @@ int poptDupArgv(int argc, const char **argv,
*argcPtr = argc;
return 0;
}
-/*@=boundswrite@*/
-/*@-bounds@*/
int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
{
const char * src;
char quote = '\0';
int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
- const char ** argv = (const char **)malloc(sizeof(*argv) * argvAlloced);
+ const char ** argv = malloc(sizeof(*argv) * argvAlloced);
int argc = 0;
- int buflen = strlen(s) + 1;
- char * buf = (char*)memset(alloca(buflen), 0, buflen);
+ size_t buflen = strlen(s) + 1;
+ char * buf, * bufOrig = NULL;
int rc = POPT_ERROR_MALLOC;
if (argv == NULL) return rc;
+ buf = bufOrig = calloc((size_t)1, buflen);
+ if (buf == NULL) {
+ free(argv);
+ return rc;
+ }
argv[argc] = buf;
for (src = s; *src != '\0'; src++) {
@@ -81,12 +83,12 @@ int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
if (*src != quote) *buf++ = '\\';
}
*buf++ = *src;
- } else if (isspace(*src)) {
+ } else if (_isspaceptr(src)) {
if (*argv[argc] != '\0') {
buf++, argc++;
if (argc == argvAlloced) {
argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
- argv = (const char **)realloc(argv, sizeof(*argv) * argvAlloced);
+ argv = realloc(argv, sizeof(*argv) * argvAlloced);
if (argv == NULL) goto exit;
}
argv[argc] = buf;
@@ -116,29 +118,29 @@ int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
rc = poptDupArgv(argc, argv, argcPtr, argvPtr);
exit:
+ if (bufOrig) free(bufOrig);
if (argv) free(argv);
return rc;
}
-/*@=bounds@*/
/* still in the dev stage.
* return values, perhaps 1== file erro
* 2== line to long
* 3== umm.... more?
*/
-int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ int flags)
+int poptConfigFileToString(FILE *fp, char ** argstrp,
+ /*@unused@*/ UNUSED(int flags))
{
char line[999];
char * argstr;
char * p;
char * q;
char * x;
- int t;
- int argvlen = 0;
+ size_t t;
+ size_t argvlen = 0;
size_t maxlinelen = sizeof(line);
size_t linelen;
- int maxargvlen = 480;
- int linenum = 0;
+ size_t maxargvlen = (size_t)480;
*argstrp = NULL;
@@ -149,41 +151,42 @@ int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ int flags)
if (fp == NULL)
return POPT_ERROR_NULLARG;
- argstr = (char *)calloc(maxargvlen, sizeof(*argstr));
+ argstr = calloc(maxargvlen, sizeof(*argstr));
if (argstr == NULL) return POPT_ERROR_MALLOC;
while (fgets(line, (int)maxlinelen, fp) != NULL) {
- linenum++;
p = line;
/* loop until first non-space char or EOL */
- while( *p != '\0' && isspace(*p) )
+ while( *p != '\0' && _isspaceptr(p) )
p++;
linelen = strlen(p);
- if (linelen >= maxlinelen-1)
+ if (linelen >= maxlinelen-1) {
+ free(argstr);
return POPT_ERROR_OVERFLOW; /* XXX line too long */
+ }
if (*p == '\0' || *p == '\n') continue; /* line is empty */
if (*p == '#') continue; /* comment line */
q = p;
- while (*q != '\0' && (!isspace(*q)) && *q != '=')
+ while (*q != '\0' && (!_isspaceptr(q)) && *q != '=')
q++;
- if (isspace(*q)) {
+ if (_isspaceptr(q)) {
/* a space after the name, find next non space */
*q++='\0';
- while( *q != '\0' && isspace((int)*q) ) q++;
+ while( *q != '\0' && _isspaceptr(q) ) q++;
}
if (*q == '\0') {
/* single command line option (ie, no name=val, just name) */
q[-1] = '\0'; /* kill off newline from fgets() call */
- argvlen += (t = q - p) + (sizeof(" --")-1);
+ argvlen += (t = (size_t)(q - p)) + (sizeof(" --")-1);
if (argvlen >= maxargvlen) {
maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
- argstr = (char *)realloc(argstr, maxargvlen);
+ argstr = realloc(argstr, maxargvlen);
if (argstr == NULL) return POPT_ERROR_MALLOC;
}
strcat(argstr, " --");
@@ -197,22 +200,22 @@ int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ int flags)
*q++ = '\0';
/* find next non-space letter of value */
- while (*q != '\0' && isspace(*q))
+ while (*q != '\0' && _isspaceptr(q))
q++;
if (*q == '\0')
continue; /* XXX silently ignore missing value */
/* now, loop and strip all ending whitespace */
x = p + linelen;
- while (isspace(*--x))
- *x = 0; /* null out last char if space (including fgets() NL) */
+ while (_isspaceptr(--x))
+ *x = '\0'; /* null out last char if space (including fgets() NL) */
/* rest of line accept */
- t = x - p;
+ t = (size_t)(x - p);
argvlen += t + (sizeof("' --='")-1);
if (argvlen >= maxargvlen) {
maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2;
- argstr = (char *)realloc(argstr, maxargvlen);
+ argstr = realloc(argstr, maxargvlen);
if (argstr == NULL) return POPT_ERROR_MALLOC;
}
strcat(argstr, " --");
diff --git a/third_party/popt/system.h b/third_party/popt/system.h
index bbb4f6cc264..452bf40dc1a 100644
--- a/third_party/popt/system.h
+++ b/third_party/popt/system.h
@@ -1,3 +1,7 @@
+/**
+ * \file popt/system.h
+ */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -13,11 +17,14 @@ extern __const __int32_t *__ctype_toupper;
#include <ctype.h>
+/* XXX isspace(3) has i18n encoding signednesss issues on Solaris. */
+#define _isspaceptr(_chp) isspace((int)(*(unsigned char *)(_chp)))
+
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
-#if HAVE_MCHECK_H
+#ifdef HAVE_MCHECK_H
#include <mcheck.h>
#endif
@@ -25,7 +32,7 @@ extern __const __int32_t *__ctype_toupper;
#include <stdlib.h>
#include <string.h>
-#if HAVE_UNISTD_H
+#if defined(HAVE_UNISTD_H) && !defined(__LCLINT__)
#include <unistd.h>
#endif
@@ -35,44 +42,62 @@ extern __const __int32_t *__ctype_toupper;
#include <libc.h>
#endif
-#if defined(__LCLINT__)
-/*@-declundef -incondefs -redecl@*/ /* LCL: missing annotation */
-/*@only@*/ void * alloca (size_t __size)
- /*@ensures MaxSet(result) == (__size - 1) @*/
+/*@-incondefs@*/
+/*@mayexit@*/ /*@only@*/ /*@out@*/ /*@unused@*/
+void * xmalloc (size_t size)
+ /*@globals errno @*/
+ /*@ensures maxSet(result) == (size - 1) @*/
+ /*@modifies errno @*/;
+
+/*@mayexit@*/ /*@only@*/ /*@unused@*/
+void * xcalloc (size_t nmemb, size_t size)
+ /*@ensures maxSet(result) == (nmemb - 1) @*/
/*@*/;
-/*@=declundef =incondefs =redecl@*/
-#endif
-/* AIX requires this to be the first thing in the file. */
-#ifndef __GNUC__
-# if HAVE_ALLOCA_H
-# include <alloca.h>
-# else
-# ifdef _AIX
-#pragma alloca
-# else
-# ifndef alloca /* predefined by HP cc +Olibcalls */
-char *alloca ();
-# endif
-# endif
-# endif
-#elif defined(__GNUC__) && defined(__STRICT_ANSI__)
-#define alloca __builtin_alloca
-#elif defined(__GNUC__) && defined(HAVE_ALLOCA_H)
-# include <alloca.h>
-#endif
+/*@mayexit@*/ /*@only@*/ /*@unused@*/
+void * xrealloc (/*@null@*/ /*@only@*/ void * ptr, size_t size)
+ /*@ensures maxSet(result) == (size - 1) @*/
+ /*@modifies *ptr @*/;
-/*@-redecl -redef@*/
-/*@mayexit@*/ /*@only@*/ char * xstrdup (const char *str)
+/*@mayexit@*/ /*@only@*/ /*@unused@*/
+char * xstrdup (const char *str)
/*@*/;
-/*@=redecl =redef@*/
+/*@=incondefs@*/
+
+#if !defined(HAVE_STPCPY)
+/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */
+static inline char * stpcpy (char *dest, const char * src) {
+ register char *d = dest;
+ register const char *s = src;
-#if HAVE_MCHECK_H && defined(__GNUC__)
+ do
+ *d++ = *s;
+ while (*s++ != '\0');
+ return d - 1;
+}
+#endif
+
+/* Memory allocation via macro defs to get meaningful locations from mtrace() */
+#if defined(HAVE_MCHECK_H) && defined(__GNUC__)
#define vmefail() (fprintf(stderr, "virtual memory exhausted.\n"), exit(EXIT_FAILURE), NULL)
+#define xmalloc(_size) (malloc(_size) ? : vmefail())
+#define xcalloc(_nmemb, _size) (calloc((_nmemb), (_size)) ? : vmefail())
+#define xrealloc(_ptr, _size) (realloc((_ptr), (_size)) ? : vmefail())
#define xstrdup(_str) (strcpy((malloc(strlen(_str)+1) ? : vmefail()), (_str)))
#else
+#define xmalloc(_size) malloc(_size)
+#define xcalloc(_nmemb, _size) calloc((_nmemb), (_size))
+#define xrealloc(_ptr, _size) realloc((_ptr), (_size))
#define xstrdup(_str) strdup(_str)
-#endif /* HAVE_MCHECK_H && defined(__GNUC__) */
+#endif /* defined(HAVE_MCHECK_H) && defined(__GNUC__) */
+#if defined(HAVE___SECURE_GETENV) && !defined(__LCLINT__)
+#define getenv(_s) __secure_getenv(_s)
+#endif
+
+#if !defined(__GNUC__) && !defined(__attribute__)
+#define __attribute__(x)
+#endif
+#define UNUSED(x) x __attribute__((__unused__))
#include "popt.h"
diff --git a/third_party/popt/wscript b/third_party/popt/wscript
index e81572c7b71..eae8602ea6c 100644
--- a/third_party/popt/wscript
+++ b/third_party/popt/wscript
@@ -4,6 +4,7 @@ import Options
def configure(conf):
conf.CHECK_HEADERS('float.h')
+ conf.CHECK_FUNCS('stpcpy')
if conf.CHECK_POPT():
conf.define('USING_SYSTEM_POPT', 1)
@@ -12,8 +13,9 @@ def build(bld):
if bld.CONFIG_SET('USING_SYSTEM_POPT'):
return
+ cflags = '-DPACKAGE="popt" -DPOPT_SYSCONFDIR="%s"' % bld.env.SYSCONFDIR
bld.SAMBA_LIBRARY('popt',
- source='findme.c popt.c poptconfig.c popthelp.c poptparse.c',
- cflags='-DDBL_EPSILON=__DBL_EPSILON__',
+ source='popt.c poptconfig.c popthelp.c poptint.c poptparse.c',
+ cflags=cflags,
allow_warnings=True,
private_library=True)