]> git.ozlabs.org Git - ccan/commitdiff
base64: fix for unsigned chars (e.g. ARM). master
authorRusty Russell <rusty@rustcorp.com.au>
Tue, 1 Aug 2023 01:43:53 +0000 (11:13 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Tue, 1 Aug 2023 01:43:53 +0000 (11:13 +0930)
```
ccan/ccan/base64/base64.c:34:10: error: result of comparison of constant 255 with expression of type 'int8_t' (aka 'signed char') is always false [-Werror,-Wtautological-constant-out-of-range-compare]
        if (ret == (char)0xff) {
            ~~~ ^  ~~~~~~~~~~
ccan/ccan/base64/base64.c:44:57: error: result of comparison of constant 255 with expression of type 'const signed char' is always true [-Werror,-Wtautological-constant-out-of-range-compare]
        return (maps->decode_map[(const unsigned char)b64char] != (char)0xff);
                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^  ~~~~~~~~~~
```

Reported-by: Christian Decker
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
49 files changed:
ccan/antithread/alloc/tiny.c
ccan/base64/base64.c
ccan/bitops/test/run.c
ccan/bytestring/bytestring.h
ccan/crypto/hmac_sha256/hmac_sha256.c
ccan/darray/darray.h
ccan/failtest/failtest.c
ccan/htable/htable_type.h
ccan/idtree/idtree.c
ccan/ilog/ilog.h
ccan/io/fdpass/_info
ccan/mem/mem.h
ccan/membuf/_info
ccan/objset/_info
ccan/opt/helpers.c
ccan/opt/opt.c
ccan/opt/opt.h
ccan/opt/parse.c
ccan/opt/test/run-add_desc.c
ccan/opt/test/run-correct-reporting.c
ccan/opt/test/run-helpers.c
ccan/opt/test/run-set_alloc.c
ccan/opt/test/run-userbits.c [new file with mode: 0644]
ccan/opt/test/utils.c
ccan/opt/test/utils.h
ccan/opt/usage.c
ccan/rbuf/rbuf.c
ccan/rune/coding.c
ccan/rune/rune.h
ccan/rune/test/run.c
ccan/rune/test/test_vectors.csv
ccan/stringbuilder/stringbuilder.c
ccan/tal/tal.c
ccan/tal/test/run-notifier.c
ccan/tally/tally.c
ccan/tcon/tcon.h
ccan/tcon/test/compile_fail-container1.c
ccan/tcon/test/compile_fail-container1w.c
ccan/tcon/test/compile_fail-container3.c
ccan/tcon/test/compile_fail-container3w.c
ccan/ungraph/LICENSE [new symlink]
ccan/ungraph/_info [new file with mode: 0644]
ccan/ungraph/test/run.c [new file with mode: 0644]
ccan/ungraph/ungraph.c [new file with mode: 0644]
ccan/ungraph/ungraph.h [new file with mode: 0644]
ccan/version/version.h
tools/ccanlint/async.c
tools/configurator/configurator.c
tools/read_config_header.c

index ffd17c65734f881f1ca355ed9e1a5b705dd3ff46..d84974ee02cd3ce0f4c967c239e30e6b466f3241 100644 (file)
@@ -353,7 +353,8 @@ bool tiny_alloc_check(void *pool, unsigned long poolsize)
        unsigned long arrsize = free_array_size(poolsize);
        unsigned char *arr = pool;
        unsigned long len, off, hdrlen;
-       unsigned long i, freearr[arrsize], num_freearr = 0;
+       /* Don't have sanitizer complain here if arrsize is 0! */
+       unsigned long i, freearr[arrsize ? arrsize : 1], num_freearr = 0;
        bool free;
 
        if (poolsize < MIN_BLOCK_SIZE)
index b2326293a992b45d011999a5211b4fc9fa54634e..c28e0da2a496dcbdd09abf7688caf5bbc37e117d 100644 (file)
@@ -31,7 +31,7 @@ static int8_t sixbit_from_b64(const base64_maps_t *maps,
        int8_t ret;
 
        ret = maps->decode_map[(unsigned char)b64letter];
-       if (ret == (char)0xff) {
+       if (ret == '\xff') {
                errno = EDOM;
                return -1;
        }
@@ -41,7 +41,7 @@ static int8_t sixbit_from_b64(const base64_maps_t *maps,
 
 bool base64_char_in_alphabet(const base64_maps_t *maps, const char b64char)
 {
-       return (maps->decode_map[(const unsigned char)b64char] != (char)0xff);
+       return (maps->decode_map[(const unsigned char)b64char] != '\xff');
 }
 
 void base64_init_maps(base64_maps_t *dest, const char src[64])
index 5dba932d4799af3b61134a0eb3ecd6d135e18b8e..6bb3acf5037173a328fa50b0c6b120dc310f8d82 100644 (file)
@@ -10,7 +10,7 @@ int main(void)
        plan_tests(68 + 6 * (31 + 63));
 
        for (i = 0; i < 32; i++)
-               ok1(bitops_ffs32(1 << i) == i+1);
+               ok1(bitops_ffs32(1U << i) == i+1);
        ok1(bitops_ffs32(0) == 0);
        for (i = 0; i < 64; i++)
                ok1(bitops_ffs64((uint64_t)1 << i) == i+1);
@@ -25,19 +25,19 @@ int main(void)
        ok1(bitops_ffs64(0) == 0);
 
        for (i = 0; i < 32; i++)
-               ok1(bitops_clz32(1 << i) == 31 - i);
+               ok1(bitops_clz32(1U << i) == 31 - i);
        for (i = 0; i < 64; i++)
                ok1(bitops_clz64((uint64_t)1 << i) == 63 - i);
 
        /* Lower bits don't effect results */
        for (i = 0; i < 32; i++)
-               ok1(bitops_clz32((1 << i) + (1 << i)-1) == 31 - i);
+               ok1(bitops_clz32((1U << i) + (1U << i)-1) == 31 - i);
        for (i = 0; i < 64; i++)
                ok1(bitops_clz64(((uint64_t)1 << i) + ((uint64_t)1 << i)-1)
                    == 63 - i);
 
        for (i = 0; i < 32; i++)
-               ok1(bitops_ctz32(1 << i) == i);
+               ok1(bitops_ctz32(1U << i) == i);
        for (i = 0; i < 64; i++)
                ok1(bitops_ctz64((uint64_t)1 << i) == i);
 
index bc99e7951c739e94221148e12491ea994642fbae..a0689db15b2f4457a9a15525edf08ee5ae4b55f2 100644 (file)
@@ -203,8 +203,13 @@ static inline const char *bytestring_rindex(struct bytestring haystack,
 static inline struct bytestring bytestring_bytestring(struct bytestring haystack,
                                                      struct bytestring needle)
 {
-       const char *p = memmem(haystack.ptr, haystack.len,
-                              needle.ptr, needle.len);
+       const char *p;
+
+       /* Allow needle.ptr == NULL, without memmem sanitizer complaining */
+       if (needle.len == 0)
+               return bytestring(haystack.ptr, 0);
+
+       p = memmem(haystack.ptr, haystack.len, needle.ptr, needle.len);
        if (p)
                return bytestring(p, needle.len);
        else
index 0392afe5c1127134e61e48d864dffe94252aeaa8..2238f9dc8fffbd4ee049ec8c965e0c11aeef37e2 100644 (file)
@@ -35,7 +35,8 @@ void hmac_sha256_init(struct hmac_sha256_ctx *ctx,
         *  (e.g., if K is of length 20 bytes and B=64, then K will be
         *   appended with 44 zero bytes 0x00)
         */
-       memcpy(k_ipad, k, ksize);
+       if (ksize != 0)
+               memcpy(k_ipad, k, ksize);
        memset((char *)k_ipad + ksize, 0, HMAC_SHA256_BLOCKSIZE - ksize);
 
        /*
index 58470fdee6c5561e49c265b1a975fa90b6b9ca26..0b98fdacddb4febe6d0d92bb5d07bfd4a454fd62 100644 (file)
@@ -183,15 +183,21 @@ typedef darray(unsigned long)  darray_ulong;
 
 #define darray_append_items(arr, items, count) do { \
                size_t count_ = (count), oldSize_ = (arr).size; \
-               darray_resize(arr, oldSize_ + count_); \
-               memcpy((arr).item + oldSize_, items, count_ * sizeof(*(arr).item)); \
+               /* Don't memcpy NULL! */                        \
+               if (count_) {                                   \
+                       darray_resize(arr, oldSize_ + count_);          \
+                       memcpy((arr).item + oldSize_, items, count_ * sizeof(*(arr).item)); \
+               }                                                       \
        } while(0)
 
 #define darray_prepend_items(arr, items, count) do { \
                size_t count_ = (count), oldSize_ = (arr).size; \
                darray_resize(arr, count_ + oldSize_); \
-               memmove((arr).item + count_, (arr).item, oldSize_ * sizeof(*(arr).item)); \
-               memcpy((arr).item, items, count_ * sizeof(*(arr).item)); \
+               /* Don't memcpy NULL! */                        \
+               if (count_) {                                   \
+                       memmove((arr).item + count_, (arr).item, oldSize_ * sizeof(*(arr).item)); \
+                       memcpy((arr).item, items, count_ * sizeof(*(arr).item)); \
+               }                                                       \
        } while(0)
 
 #define darray_append_items_nullterminate(arr, items, count) do { \
index c61ce442a5d03b39444a87a468514f23c6f3c962..205ded254709e6611d67b4465ca3967744306252 100644 (file)
@@ -179,7 +179,8 @@ static struct failtest_call *add_history_(enum failtest_call_type type,
        call->line = line;
        call->cleanup = NULL;
        call->backtrace = get_backtrace(&call->backtrace_num);
-       memcpy(&call->u, elem, elem_size);
+       if (elem_size != 0)
+               memcpy(&call->u, elem, elem_size);
        tlist_add_tail(&history, call, list);
        return call;
 }
@@ -1202,9 +1203,8 @@ static void cleanup_pipe(struct pipe_call *call, bool restore)
 int failtest_pipe(int pipefd[2], const char *file, unsigned line)
 {
        struct failtest_call *p;
-       struct pipe_call call;
 
-       p = add_history(FAILTEST_PIPE, true, file, line, &call);
+       p = add_history_(FAILTEST_PIPE, true, file, line, NULL, 0);
        if (should_fail(p)) {
                p->u.open.ret = -1;
                /* FIXME: Play with error codes? */
index bb5ea086b7319fd3cd1c19b0dceece1974cfe8d4..0aacb7f334925ffe58d2c8cb489a9ae0efe36b66 100644 (file)
                                                size_t seed,            \
                                                struct name##_iter *iter) \
        {                                                               \
-               /* Note &iter->i == NULL iff iter is NULL */            \
-               return htable_pick(&ht->raw, seed, &iter->i);                   \
+               return htable_pick(&ht->raw, seed, iter ? &iter->i : NULL); \
        }                                                               \
        static inline UNNEEDED type *name##_first(const struct name *ht, \
                                         struct name##_iter *iter)      \
index 6e75450e67e85af287a9967cd7e88af66e147a5b..e10c17239cdfc407e40da7c77dfb4e5f57edc42a 100644 (file)
@@ -42,9 +42,9 @@
 #define MAX_LEVEL (MAX_ID_SHIFT + IDTREE_BITS - 1) / IDTREE_BITS
 #define IDTREE_FREE_MAX MAX_LEVEL + MAX_LEVEL
 
-#define set_bit(bit, v) (v) |= (1<<(bit))
-#define clear_bit(bit, v) (v) &= ~(1<<(bit))
-#define test_bit(bit, v) ((v) & (1<<(bit)))
+#define set_bit(bit, v) (v) |= (1U<<(bit))
+#define clear_bit(bit, v) (v) &= ~(1U<<(bit))
+#define test_bit(bit, v) ((v) & (1U<<(bit)))
 
 struct idtree_layer {
        uint32_t                 bitmap;
@@ -122,7 +122,7 @@ restart:
                        /* no space available go back to previous layer. */
                        l++;
                        oid = id;
-                       id = (id | ((1 << (IDTREE_BITS*l))-1)) + 1;
+                       id = (id | ((1U << (IDTREE_BITS*l))-1)) + 1;
 
                        /* if already at the top layer, we need to grow */
                        if (!(p = pa[l])) {
index 9adbb8243f6c4f67da7ccefbc8fc7735f63cda7e..32702b178567e503c11d606d655738fe9dbfc3aa 100644 (file)
@@ -120,7 +120,10 @@ int ilog64_nz(uint64_t _v) CONST_FUNCTION;
 #endif
 
 #ifdef builtin_ilog32_nz
-#define ilog32(_v) (builtin_ilog32_nz(_v)&-!!(_v))
+/* This used to be builtin_ilog32_nz(_v)&-!!(_v), which means it zeroes out
+ * the undefined builtin_ilog32_nz(0) return.  But clang UndefinedBehaviorSantizer
+ * complains, so do the branch: */
+#define ilog32(_v) ((_v) ? builtin_ilog32_nz(_v) : 0)
 #define ilog32_nz(_v) builtin_ilog32_nz(_v)
 #else
 #define ilog32_nz(_v) ilog32(_v)
@@ -128,7 +131,7 @@ int ilog64_nz(uint64_t _v) CONST_FUNCTION;
 #endif /* builtin_ilog32_nz */
 
 #ifdef builtin_ilog64_nz
-#define ilog64(_v) (builtin_ilog64_nz(_v)&-!!(_v))
+#define ilog32(_v) ((_v) ? builtin_ilog32_nz(_v) : 0)
 #define ilog64_nz(_v) builtin_ilog64_nz(_v)
 #else
 #define ilog64_nz(_v) ilog64(_v)
index ba09025aaf8e5bed001debd89a018f9385415910..0b10e8a8bbf489bb2ddcf6223d27ece866240610 100644 (file)
  *                                     read_more, buf);
  *     }
  *
+ *     // Clean up allocation so -fsanitize=address doesn't see leak!
+ *     static void free_buf(struct io_conn *c, struct buf *buf)
+ *     {
+ *             free(buf);
+ *     }
+ *
  *     // Child has received fd, start reading loop.
  *     static struct io_plan *got_infd(struct io_conn *conn, int *infd)
  *     {
  *             struct buf *buf = calloc(1, sizeof(*buf));
+ *             struct io_conn *new_conn;
  *
- *             io_new_conn(NULL, *infd, read_more, buf);
+ *             new_conn = io_new_conn(NULL, *infd, read_more, buf);
+ *             io_set_finish(new_conn, free_buf, buf);
  *             return io_close(conn);
  *     }
  *     // Child is receiving the fd to read into. 
index 19f69c038c67efe1e11ac8ab5cec036123aa3b95..20286dcbefd42f99a7e88932ab1ef4cda115f2e2 100644 (file)
@@ -104,7 +104,7 @@ void *memcchr(void const *data, int c, size_t data_len);
 PURE_FUNCTION
 static inline bool memeq(const void *a, size_t al, const void *b, size_t bl)
 {
-       return al == bl && !memcmp(a, b, bl);
+       return al == bl && (al == 0 || !memcmp(a, b, bl));
 }
 
 /**
index bdcbce2b2f205724d39a6783e212eee2da3a7e83..a859318c62ee3486f5110ad9dbe7ee74e9e08438 100644 (file)
  *
  *     membuf_init(&charbuf, malloc(10), 10, membuf_realloc);
  *
- *     for (int i = 1; i < argc; i++)
- *             strcpy(membuf_add(&charbuf, strlen(argv[i])), argv[i]);
+ *     for (int i = 1; i < argc; i++) {
+ *             size_t len = strlen(argv[i]);
+ *             memcpy(membuf_add(&charbuf, len), argv[i], len);
+ *     }
  *
  *     // This is dumb, we could do all at once, but shows technique.
  *     while (membuf_num_elems(&charbuf) > 0)
  *             printf("%c", *(char *)membuf_consume(&charbuf, 1));
  *     printf("\n");
+ *     free(membuf_cleanup(&charbuf));
  *     return 0;
  * }
  */
index 967764e7e86cb9de97c622e9b297e74071b85907..116c2596ee622308cabc0f2268b9f74346321fa5 100644 (file)
@@ -39,6 +39,8 @@
  *                                     printf("%i,", i);
  *                     printf("\n");
  *             }
+ *             // Keep -fsanitize=address leak detection happy.
+ *             objset_clear(&args);
  *             return 0;
  *     }
  *     // Given "a b c" outputs No arguments start with -.
index 118e543602e06b981e6faee7dd5f416cf819d5cd..df7ee6bb1f20cf791fe82525393e7c809b6f7afb 100644 (file)
@@ -138,10 +138,11 @@ char *opt_set_floatval(const char *arg, float *f)
        return NULL;
 }
 
-void opt_show_floatval(char buf[OPT_SHOW_LEN], const float *f)
+bool opt_show_floatval(char *buf, size_t len, const float *f)
 {
        double d = *f;
-       opt_show_doubleval(buf, &d);
+       opt_show_doubleval(buf, len, &d);
+       return true;
 }
 
 char *opt_set_doubleval(const char *arg, double *d)
@@ -160,9 +161,10 @@ char *opt_set_doubleval(const char *arg, double *d)
        return NULL;
 }
 
-void opt_show_doubleval(char buf[OPT_SHOW_LEN], const double *d)
+bool opt_show_doubleval(char *buf, size_t len, const double *d)
 {
-       snprintf(buf, OPT_SHOW_LEN, "%f", *d);
+       snprintf(buf, len, "%f", *d);
+       return true;
 }
 
 char *opt_inc_intval(int *i)
@@ -196,52 +198,60 @@ char *opt_usage_and_exit(const char *extra)
        exit(0);
 }
 
-void opt_show_bool(char buf[OPT_SHOW_LEN], const bool *b)
+bool opt_show_bool(char *buf, size_t len, const bool *b)
 {
-       strncpy(buf, *b ? "true" : "false", OPT_SHOW_LEN);
+       strncpy(buf, *b ? "true" : "false", len);
+       return true;
 }
 
-void opt_show_invbool(char buf[OPT_SHOW_LEN], const bool *b)
+bool opt_show_invbool(char *buf, size_t len, const bool *b)
 {
-       strncpy(buf, *b ? "false" : "true", OPT_SHOW_LEN);
+       strncpy(buf, *b ? "false" : "true", len);
+       return true;
 }
 
-void opt_show_charp(char buf[OPT_SHOW_LEN], char *const *p)
+bool opt_show_charp(char *buf, size_t len, char *const *p)
 {
-       if (*p){
-               size_t len = strlen(*p);
+       if (*p) {
+               size_t plen = strlen(*p);
+               if (len < 2)
+                       return false;
                buf[0] = '"';
-               if (len > OPT_SHOW_LEN - 2)
-                       len = OPT_SHOW_LEN - 2;
-               strncpy(buf+1, *p, len);
-               buf[1+len] = '"';
-               if (len < OPT_SHOW_LEN - 2)
-                       buf[2+len] = '\0';
-       }
-       else {
-               strncpy(buf, "(nil)", OPT_SHOW_LEN);
+               if (plen > len - 2)
+                       plen = len - 2;
+               strncpy(buf+1, *p, plen);
+               buf[1+plen] = '"';
+               if (plen < len - 2)
+                       buf[2+plen] = '\0';
+               return true;
+       else {
+               return false;
        }
 }
 
 /* Show an integer value, various forms. */
-void opt_show_intval(char buf[OPT_SHOW_LEN], const int *i)
+bool opt_show_intval(char *buf, size_t len, const int *i)
 {
-       snprintf(buf, OPT_SHOW_LEN, "%i", *i);
+       snprintf(buf, len, "%i", *i);
+       return true;
 }
 
-void opt_show_uintval(char buf[OPT_SHOW_LEN], const unsigned int *ui)
+bool opt_show_uintval(char *buf, size_t len, const unsigned int *ui)
 {
-       snprintf(buf, OPT_SHOW_LEN, "%u", *ui);
+       snprintf(buf, len, "%u", *ui);
+       return true;
 }
 
-void opt_show_longval(char buf[OPT_SHOW_LEN], const long *l)
+bool opt_show_longval(char *buf, size_t len, const long *l)
 {
-       snprintf(buf, OPT_SHOW_LEN, "%li", *l);
+       snprintf(buf, len, "%li", *l);
+       return true;
 }
 
-void opt_show_ulongval(char buf[OPT_SHOW_LEN], const unsigned long *ul)
+bool opt_show_ulongval(char *buf, size_t len, const unsigned long *ul)
 {
-       snprintf(buf, OPT_SHOW_LEN, "%lu", *ul);
+       snprintf(buf, len, "%lu", *ul);
+       return true;
 }
 
 /* a helper function that multiplies out an argument's kMGTPE suffix in the
@@ -447,14 +457,14 @@ char * opt_set_uintval_si(const char *arg, unsigned int *u)
   are separate but essentially identical functions for signed and unsigned
   values, so that unsigned values greater than LLONG_MAX get suffixes.
  */
-static void show_llong_with_suffix(char buf[OPT_SHOW_LEN], long long ll,
-                                   const long long base)
+static void show_llong_with_suffix(char *buf, size_t len, long long ll,
+                                  const long long base)
 {
        const char *suffixes = "kMGTPE";
        int i;
        if (ll == 0){
                /*zero is special because everything divides it (you'd get "0E")*/
-               snprintf(buf, OPT_SHOW_LEN, "0");
+               snprintf(buf, len, "0");
                return;
        }
        for (i = 0; i < strlen(suffixes); i++){
@@ -464,19 +474,20 @@ static void show_llong_with_suffix(char buf[OPT_SHOW_LEN], long long ll,
                ll = tmp;
        }
        if (i == 0)
-               snprintf(buf, OPT_SHOW_LEN, "%"PRId64, (int64_t)ll);
+               snprintf(buf, len, "%"PRId64, (int64_t)ll);
        else
-               snprintf(buf, OPT_SHOW_LEN, "%"PRId64"%c", (int64_t)ll, suffixes[i - 1]);
+               snprintf(buf, len, "%"PRId64"%c", (int64_t)ll, suffixes[i - 1]);
 }
 
-static void show_ullong_with_suffix(char buf[OPT_SHOW_LEN], unsigned long long ull,
+static void show_ullong_with_suffix(char *buf, size_t len,
+                                   unsigned long long ull,
                                    const unsigned base)
 {
        const char *suffixes = "kMGTPE";
        int i;
        if (ull == 0){
                /*zero is special because everything divides it (you'd get "0E")*/
-               snprintf(buf, OPT_SHOW_LEN, "0");
+               snprintf(buf, len, "0");
                return;
        }
        for (i = 0; i < strlen(suffixes); i++){
@@ -486,72 +497,84 @@ static void show_ullong_with_suffix(char buf[OPT_SHOW_LEN], unsigned long long u
                ull = tmp;
        }
        if (i == 0)
-               snprintf(buf, OPT_SHOW_LEN, "%"PRIu64, (uint64_t)ull);
+               snprintf(buf, len, "%"PRIu64, (uint64_t)ull);
        else
-               snprintf(buf, OPT_SHOW_LEN, "%"PRIu64"%c", (uint64_t)ull, suffixes[i - 1]);
+               snprintf(buf, len, "%"PRIu64"%c", (uint64_t)ull, suffixes[i - 1]);
 }
 
 /* _bi, signed */
-void opt_show_intval_bi(char buf[OPT_SHOW_LEN], const int *x)
+bool opt_show_intval_bi(char *buf, size_t len, const int *x)
 {
-       show_llong_with_suffix(buf, *x, 1024);
+       show_llong_with_suffix(buf, len, *x, 1024);
+       return true;
 }
 
-void opt_show_longval_bi(char buf[OPT_SHOW_LEN], const long *x)
+bool opt_show_longval_bi(char *buf, size_t len, const long *x)
 {
-       show_llong_with_suffix(buf, *x, 1024);
+       show_llong_with_suffix(buf, len, *x, 1024);
+       return true;
 }
 
-void opt_show_longlongval_bi(char buf[OPT_SHOW_LEN], const long long *x)
+bool opt_show_longlongval_bi(char *buf, size_t len, const long long *x)
 {
-       show_llong_with_suffix(buf, *x, 1024);
+       show_llong_with_suffix(buf, len, *x, 1024);
+       return true;
 }
 
 /* _bi, unsigned */
-void opt_show_uintval_bi(char buf[OPT_SHOW_LEN], const unsigned int *x)
+bool opt_show_uintval_bi(char *buf, size_t len, const unsigned int *x)
 {
-       show_ullong_with_suffix(buf, (unsigned long long) *x, 1024);
+       show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1024);
+       return true;
 }
 
-void opt_show_ulongval_bi(char buf[OPT_SHOW_LEN], const unsigned long *x)
+bool opt_show_ulongval_bi(char *buf, size_t len, const unsigned long *x)
 {
-       show_ullong_with_suffix(buf, (unsigned long long) *x, 1024);
+       show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1024);
+       return true;
 }
 
-void opt_show_ulonglongval_bi(char buf[OPT_SHOW_LEN], const unsigned long long *x)
+bool opt_show_ulonglongval_bi(char *buf, size_t len, const unsigned long long *x)
 {
-       show_ullong_with_suffix(buf, (unsigned long long) *x, 1024);
+       show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1024);
+       return true;
 }
 
 /* _si, signed */
-void opt_show_intval_si(char buf[OPT_SHOW_LEN], const int *x)
+bool opt_show_intval_si(char *buf, size_t len, const int *x)
 {
-       show_llong_with_suffix(buf, (long long) *x, 1000);
+       show_llong_with_suffix(buf, len, (long long) *x, 1000);
+       return true;
 }
 
-void opt_show_longval_si(char buf[OPT_SHOW_LEN], const long *x)
+bool opt_show_longval_si(char *buf, size_t len, const long *x)
 {
-       show_llong_with_suffix(buf, (long long) *x, 1000);
+       show_llong_with_suffix(buf, len, (long long) *x, 1000);
+       return true;
 }
 
-void opt_show_longlongval_si(char buf[OPT_SHOW_LEN], const long long *x)
+bool opt_show_longlongval_si(char *buf, size_t len, const long long *x)
 {
-       show_llong_with_suffix(buf, *x, 1000);
+       show_llong_with_suffix(buf, len, *x, 1000);
+       return true;
 }
 
 /* _si, unsigned */
-void opt_show_uintval_si(char buf[OPT_SHOW_LEN], const unsigned int *x)
+bool opt_show_uintval_si(char *buf, size_t len, const unsigned int *x)
 {
-       show_ullong_with_suffix(buf, (unsigned long long) *x, 1000);
+       show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1000);
+       return true;
 }
 
-void opt_show_ulongval_si(char buf[OPT_SHOW_LEN], const unsigned long *x)
+bool opt_show_ulongval_si(char *buf, size_t len, const unsigned long *x)
 {
-       show_ullong_with_suffix(buf, (unsigned long long) *x, 1000);
+       show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1000);
+       return true;
 }
 
-void opt_show_ulonglongval_si(char buf[OPT_SHOW_LEN], const unsigned long long *x)
+bool opt_show_ulonglongval_si(char *buf, size_t len, const unsigned long long *x)
 {
-       show_ullong_with_suffix(buf, (unsigned long long) *x, 1000);
+       show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1000);
+       return true;
 }
 
index d376a598da932445de592c8f12e2466d4bc431bd..9149374cb001e6152eb46e03de6cc092ef6e4297 100644 (file)
@@ -34,7 +34,7 @@ static const char *next_name(const char *names, unsigned *len)
 static const char *first_opt(unsigned *i, unsigned *len)
 {
        for (*i = 0; *i < opt_count; (*i)++) {
-               if (opt_table[*i].type == OPT_SUBTABLE)
+               if (opt_table[*i].type & OPT_SUBTABLE)
                        continue;
                return first_name(opt_table[*i].names, len);
        }
@@ -44,7 +44,7 @@ static const char *first_opt(unsigned *i, unsigned *len)
 static const char *next_opt(const char *p, unsigned *i, unsigned *len)
 {
        for (; *i < opt_count; (*i)++) {
-               if (opt_table[*i].type == OPT_SUBTABLE)
+               if (opt_table[*i].type & OPT_SUBTABLE)
                        continue;
                if (!p)
                        return first_name(opt_table[*i].names, len);
@@ -114,10 +114,11 @@ static void check_opt(const struct opt_table *entry)
 {
        const char *p;
        unsigned len;
+       enum opt_type type = entry->type & (OPT_USER_MIN-1);
 
-       if (entry->type != OPT_HASARG && entry->type != OPT_NOARG
-           && entry->type != (OPT_EARLY|OPT_HASARG)
-           && entry->type != (OPT_EARLY|OPT_NOARG))
+       if (type != OPT_HASARG && type != OPT_NOARG
+           && type != (OPT_EARLY|OPT_HASARG)
+           && type != (OPT_EARLY|OPT_NOARG))
                failmsg("Option %s: unknown entry type %u",
                        entry->names, entry->type);
 
@@ -161,7 +162,7 @@ static void add_opt(const struct opt_table *entry)
 void _opt_register(const char *names, enum opt_type type,
                   char *(*cb)(void *arg),
                   char *(*cb_arg)(const char *optarg, void *arg),
-                  void (*show)(char buf[OPT_SHOW_LEN], const void *arg),
+                  bool (*show)(char *buf, size_t len, const void *arg),
                   const void *arg, const char *desc)
 {
        struct opt_table opt;
@@ -181,7 +182,7 @@ bool opt_unregister(const char *names)
        int found = -1, i;
 
        for (i = 0; i < opt_count; i++) {
-               if (opt_table[i].type == OPT_SUBTABLE)
+               if (opt_table[i].type & OPT_SUBTABLE)
                        continue;
                if (strcmp(opt_table[i].names, names) == 0)
                        found = i;
@@ -203,7 +204,7 @@ void opt_register_table(const struct opt_table entry[], const char *desc)
                add_opt(&heading);
        }
        for (i = 0; entry[i].type != OPT_END; i++) {
-               if (entry[i].type == OPT_SUBTABLE)
+               if (entry[i].type & OPT_SUBTABLE)
                        opt_register_table(subtable_of(&entry[i]),
                                           entry[i].desc);
                else {
index 6f4b9dda8c85a4f33389863963b57f1a87214ea4..e0331be264230cb57a100f30e26a6f119bf6ca6c 100644 (file)
@@ -47,10 +47,11 @@ struct opt_table;
  * where "type" is the type of the @arg argument.  The first argument to the
  * @cb is the argument found on the commandline.
  *
- * Similarly, if @show is not NULL, it should be of type "void *show(char *,
- * const type *)".  It should write up to OPT_SHOW_LEN bytes into the first
- * argument; unless it uses the entire OPT_SHOW_LEN bytes it should
- * nul-terminate that buffer.
+ * Similarly, if @show is not NULL, it should be of type "bool show(char *,
+ * size_t len, const type *)".  If there is no default, it should return false,
+ * otherwise it should write up to len bytes into the first argument and
+ * return true; unless it uses the entire len bytes it should nul-terminate that
+ * buffer.
  *
  * Any number of equivalent short or long options can be listed in @names,
  * separated by '|'.  Short options are a single hyphen followed by a single
@@ -429,40 +430,38 @@ void opt_usage_exit_fail(const char *msg, ...) NORETURN;
  */
 extern const char opt_hidden[];
 
-/* Maximum length of arg to show in opt_usage */
-#define OPT_SHOW_LEN 80
-
 /* Standard helpers.  You can write your own: */
 /* Sets the @b to true. */
 char *opt_set_bool(bool *b);
 /* Sets @b based on arg: (yes/no/true/false). */
 char *opt_set_bool_arg(const char *arg, bool *b);
-void opt_show_bool(char buf[OPT_SHOW_LEN], const bool *b);
+bool opt_show_bool(char *buf, size_t len, const bool *b);
 /* The inverse */
 char *opt_set_invbool(bool *b);
-void opt_show_invbool(char buf[OPT_SHOW_LEN], const bool *b);
+bool opt_show_invbool(char *buf, size_t len, const bool *b);
 /* Sets @b based on !arg: (yes/no/true/false). */
 char *opt_set_invbool_arg(const char *arg, bool *b);
 
 /* Set a char *. */
 char *opt_set_charp(const char *arg, char **p);
-void opt_show_charp(char buf[OPT_SHOW_LEN], char *const *p);
+/* If *p is NULL, this returns false (i.e. doesn't show a default) */
+bool opt_show_charp(char *buf, size_t len, char *const *p);
 
 /* Set an integer value, various forms.  Sets to 1 on arg == NULL. */
 char *opt_set_intval(const char *arg, int *i);
-void opt_show_intval(char buf[OPT_SHOW_LEN], const int *i);
+bool opt_show_intval(char *buf, size_t len, const int *i);
 char *opt_set_uintval(const char *arg, unsigned int *ui);
-void opt_show_uintval(char buf[OPT_SHOW_LEN], const unsigned int *ui);
+bool opt_show_uintval(char *buf, size_t len, const unsigned int *ui);
 char *opt_set_longval(const char *arg, long *l);
-void opt_show_longval(char buf[OPT_SHOW_LEN], const long *l);
+bool opt_show_longval(char *buf, size_t len, const long *l);
 char *opt_set_ulongval(const char *arg, unsigned long *ul);
-void opt_show_ulongval(char buf[OPT_SHOW_LEN], const unsigned long *ul);
+bool opt_show_ulongval(char *buf, size_t len, const unsigned long *ul);
 
 /* Set an floating point value, various forms. */
 char *opt_set_floatval(const char *arg, float *f);
-void opt_show_floatval(char buf[OPT_SHOW_LEN], const float *f);
+bool opt_show_floatval(char *buf, size_t len, const float *f);
 char *opt_set_doubleval(const char *arg, double *d);
-void opt_show_doubleval(char buf[OPT_SHOW_LEN], const double *d);
+bool opt_show_doubleval(char *buf, size_t len, const double *d);
 
 /* the following setting functions accept k, M, G, T, P, or E suffixes, which
    multiplies the numeric value by the corresponding power of 1000 or 1024
@@ -482,19 +481,19 @@ char *opt_set_ulonglongval_bi(const char *arg, unsigned long long *ll);
 char *opt_set_ulonglongval_si(const char *arg, unsigned long long *ll);
 
 
-void opt_show_intval_bi(char buf[OPT_SHOW_LEN], const int *x);
-void opt_show_longval_bi(char buf[OPT_SHOW_LEN], const long *x);
-void opt_show_longlongval_bi(char buf[OPT_SHOW_LEN], const long long *x);
-void opt_show_uintval_bi(char buf[OPT_SHOW_LEN], const unsigned int *x);
-void opt_show_ulongval_bi(char buf[OPT_SHOW_LEN], const unsigned long *x);
-void opt_show_ulonglongval_bi(char buf[OPT_SHOW_LEN], const unsigned long long *x);
+bool opt_show_intval_bi(char *buf, size_t len, const int *x);
+bool opt_show_longval_bi(char *buf, size_t len, const long *x);
+bool opt_show_longlongval_bi(char *buf, size_t len, const long long *x);
+bool opt_show_uintval_bi(char *buf, size_t len, const unsigned int *x);
+bool opt_show_ulongval_bi(char *buf, size_t len, const unsigned long *x);
+bool opt_show_ulonglongval_bi(char *buf, size_t len, const unsigned long long *x);
 
-void opt_show_intval_si(char buf[OPT_SHOW_LEN], const int *x);
-void opt_show_longval_si(char buf[OPT_SHOW_LEN], const long *x);
-void opt_show_longlongval_si(char buf[OPT_SHOW_LEN], const long long *x);
-void opt_show_uintval_si(char buf[OPT_SHOW_LEN], const unsigned int *x);
-void opt_show_ulongval_si(char buf[OPT_SHOW_LEN], const unsigned long *x);
-void opt_show_ulonglongval_si(char buf[OPT_SHOW_LEN], const unsigned long long *x);
+bool opt_show_intval_si(char *buf, size_t len, const int *x);
+bool opt_show_longval_si(char *buf, size_t len, const long *x);
+bool opt_show_longlongval_si(char *buf, size_t len, const long long *x);
+bool opt_show_uintval_si(char *buf, size_t len, const unsigned int *x);
+bool opt_show_ulongval_si(char *buf, size_t len, const unsigned long *x);
+bool opt_show_ulonglongval_si(char *buf, size_t len, const unsigned long long *x);
 
 
 
@@ -509,6 +508,30 @@ char *opt_version_and_exit(const char *version);
 /* Display usage string to stdout, exit(0). */
 char *opt_usage_and_exit(const char *extra);
 
+/**
+ * opt_find_long: low-level access to the parser
+ * @arg: string of form 'arg' or 'arg=val'.
+ * @optarg: set to `val` of present in arg, otherwise NULL.  Can be NULL.
+ *
+ * Returns NULL if option is unknown.  Sets *@optarg to NULL if
+ * there's no '='.
+ */
+struct opt_table *opt_find_long(const char *arg, const char **optarg);
+
+/**
+ * opt_find_short: low-level access to the parser
+ * @arg: character representing short option
+ *
+ * Returns NULL if option is unknown.
+ */
+struct opt_table *opt_find_short(char arg);
+
+/* opt_type bits reserved for users to play with (ignored!).
+ * You can set bits in type e.g. (1<<OPT_USER_START) to (1<<OPT_USER_END)
+ * when calling _opt_register. */
+#define OPT_USER_START 8
+#define OPT_USER_END 15
+
 /* Below here are private declarations. */
 /* You can use this directly to build tables, but the macros will ensure
  * consistency and type safety. */
@@ -518,6 +541,11 @@ enum opt_type {
        OPT_SUBTABLE = 4,       /* Actually, longopt points to a subtable... */
        OPT_EARLY = 8,          /* Parse this from opt_early_parse() only. */
        OPT_END = 16,           /* End of the table. */
+
+       /* Make sure no compiler will assume we never have large
+        * values in the enum! */
+       OPT_USER_MIN = (1 << OPT_USER_START),
+       OPT_USER_MAX = (1 << OPT_USER_END),
 };
 
 struct opt_table {
@@ -525,7 +553,7 @@ struct opt_table {
        enum opt_type type;
        char *(*cb)(void *arg); /* OPT_NOARG */
        char *(*cb_arg)(const char *optarg, void *arg); /* OPT_HASARG */
-       void (*show)(char buf[OPT_SHOW_LEN], const void *arg);
+       bool (*show)(char *buf, size_t len, const void *arg);
        union {
                const void *carg;
                void *arg;
@@ -551,14 +579,14 @@ struct opt_table {
                          char *(*)(const char *, const typeof(*(arg))*), \
                          char *(*)(const char *, const void *),        \
                          (cb)),                                        \
-       typesafe_cb_cast(void (*)(char buf[], const void *),            \
-                        void (*)(char buf[], const typeof(*(arg))*), (show))
+       typesafe_cb_cast(bool (*)(char *buf, size_t, const void *), \
+                        bool (*)(char *buf, size_t, const typeof(*(arg))*), (show))
 
 /* Non-typesafe register function. */
 void _opt_register(const char *names, enum opt_type type,
                   char *(*cb)(void *arg),
                   char *(*cb_arg)(const char *optarg, void *arg),
-                  void (*show)(char buf[OPT_SHOW_LEN], const void *arg),
+                  bool (*show)(char *buf, size_t len, const void *arg),
                   const void *arg, const char *desc);
 
 /* We use this to get typechecking for OPT_SUBTABLE */
index d227f7bca2ab679033dd920fe426983dc0ea9314..b932bf333571620d0e19edca1b10a82cc70d8397 100644 (file)
@@ -14,7 +14,8 @@
 /tmp/opt-example: option requires an argument -- 's'
 */
 static int parse_err(void (*errlog)(const char *fmt, ...),
-                    const char *argv0, const char *arg, unsigned len,
+                    const char *argv0,
+                    const char *arg, unsigned len,
                     const char *problem)
 {
        errlog("%s: %.*s: %s", argv0, len, arg, problem);
@@ -28,13 +29,63 @@ static void consume_option(int *argc, char *argv[], unsigned optnum)
        (*argc)--;
 }
 
+/* This sets the len and o to indicate how far it is into the
+ * opt_table's names field. */
+static struct opt_table *opt_find_long_extra(const char *arg,
+                                            const char **optarg,
+                                            unsigned int *len,
+                                            const char **o)
+{
+       unsigned i;
+
+       *optarg = NULL;
+       for (*o = first_lopt(&i, len);
+            *o;
+            *o = next_lopt(*o, &i, len)) {
+               if (strncmp(arg, *o, *len) != 0)
+                       continue;
+               if (arg[*len] == '=')
+                       *optarg = arg + *len + 1;
+               else if (arg[*len] != '\0')
+                       continue;
+               return &opt_table[i];
+
+       }
+       return NULL;
+}
+
+struct opt_table *opt_find_long(const char *arg, const char **optarg)
+{
+       unsigned len;
+       const char *o;
+
+       return opt_find_long_extra(arg, optarg ? optarg : &o, &len, &o);
+}
+
+static struct opt_table *opt_find_short_extra(char arg, const char **o)
+{
+       unsigned i;
+       for (*o = first_sopt(&i); *o; *o = next_sopt(*o, &i)) {
+               if (arg == **o)
+                       return &opt_table[i];
+       }
+       return NULL;
+}
+
+struct opt_table *opt_find_short(char arg)
+{
+       const char *o;
+       return opt_find_short_extra(arg, &o);
+}
+
 /* Returns 1 if argument consumed, 0 if all done, -1 on error. */
 int parse_one(int *argc, char *argv[], enum opt_type is_early, unsigned *offset,
              void (*errlog)(const char *fmt, ...), bool unknown_ok)
 {
-       unsigned i, arg, len;
+       unsigned arg, len;
        const char *o, *optarg = NULL;
        char *problem = NULL;
+       struct opt_table *ot;
 
        if (getenv("POSIXLY_CORRECT")) {
                /* Don't find options after non-options. */
@@ -58,34 +109,22 @@ int parse_one(int *argc, char *argv[], enum opt_type is_early, unsigned *offset,
        /* Long options start with -- */
        if (argv[arg][1] == '-') {
                assert(*offset == 0);
-               for (o = first_lopt(&i, &len); o; o = next_lopt(o, &i, &len)) {
-                       if (strncmp(argv[arg] + 2, o, len) != 0)
-                               continue;
-                       if (argv[arg][2 + len] == '=')
-                               optarg = argv[arg] + 2 + len + 1;
-                       else if (argv[arg][2 + len] != '\0')
-                               continue;
-                       break;
-               }
-               if (!o) {
+
+               ot = opt_find_long_extra(argv[arg]+2, &optarg, &len, &o);
+               if (!ot) {
                        if (unknown_ok)
                                goto ok;
                        return parse_err(errlog, argv[0],
                                         argv[arg], strlen(argv[arg]),
                                         "unrecognized option");
                }
+
                /* For error messages, we include the leading '--' */
                o -= 2;
                len += 2;
        } else {
-               /* offset allows us to handle -abc */
-               for (o = first_sopt(&i); o; o = next_sopt(o, &i)) {
-                       if (argv[arg][*offset + 1] != *o)
-                               continue;
-                       (*offset)++;
-                       break;
-               }
-               if (!o) {
+               ot = opt_find_short_extra(argv[arg][*offset + 1], &o);
+               if (!ot) {
                        if (unknown_ok) {
                                (*offset)++;
                                goto ok;
@@ -94,17 +133,19 @@ int parse_one(int *argc, char *argv[], enum opt_type is_early, unsigned *offset,
                                         argv[arg], strlen(argv[arg]),
                                         "unrecognized option");
                }
+
+               (*offset)++;
                /* For error messages, we include the leading '-' */
                o--;
                len = 2;
        }
 
-       if ((opt_table[i].type & ~OPT_EARLY) == OPT_NOARG) {
+       if (ot->type & OPT_NOARG) {
                if (optarg)
                        return parse_err(errlog, argv[0], o, len,
                                         "doesn't allow an argument");
-               if ((opt_table[i].type & OPT_EARLY) == is_early)
-                       problem = opt_table[i].cb(opt_table[i].u.arg);
+               if ((ot->type & OPT_EARLY) == is_early)
+                       problem = ot->cb(ot->u.arg);
        } else {
                if (!optarg) {
                        /* Swallow any short options as optarg, eg -afile */
@@ -117,9 +158,8 @@ int parse_one(int *argc, char *argv[], enum opt_type is_early, unsigned *offset,
                if (!optarg)
                        return parse_err(errlog, argv[0], o, len,
                                         "requires an argument");
-               if ((opt_table[i].type & OPT_EARLY) == is_early)
-                       problem = opt_table[i].cb_arg(optarg,
-                                                     opt_table[i].u.arg);
+               if ((ot->type & OPT_EARLY) == is_early)
+                       problem = ot->cb_arg(optarg, ot->u.arg);
        }
 
        if (problem) {
index b559c7f747689bae70d34589ee9794f4cf710ac0..03e6986dd191954c7f14491353db1adfe0e51d51 100644 (file)
@@ -4,15 +4,24 @@
 #include <ccan/opt/helpers.c>
 #include <ccan/opt/parse.c>
 
-static void show_10(char buf[OPT_SHOW_LEN], const void *arg UNNEEDED)
+static bool show_10(char *buf, size_t len, const void *arg UNNEEDED)
 {
        memset(buf, 'X', 10);
        buf[10] = '\0';
+       return true;
 }
 
-static void show_max(char buf[OPT_SHOW_LEN], const void *arg UNNEEDED)
+static bool show_10_false(char *buf, size_t len, const void *arg UNNEEDED)
+{
+       memset(buf, 'X', 10);
+       buf[10] = '\0';
+       return false;
+}
+
+static bool show_max(char *buf, size_t len, const void *arg UNNEEDED)
 {
        memset(buf, 'X', OPT_SHOW_LEN);
+       return true;
 }
 
 /* Test add_desc helper. */
@@ -22,7 +31,7 @@ int main(void)
        char *ret;
        size_t len, max;
 
-       plan_tests(30);
+       plan_tests(32);
 
        opt.show = NULL;
        opt.names = "01234";
@@ -113,6 +122,14 @@ int main(void)
                   "        (default: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...)\n") == 0);
        free(ret); len = max = 0;
 
+       /* With show function which fails doesn't print. */
+       opt.show = show_10_false;
+       ret = add_desc(NULL, &len, &max, 7, 41, &opt);
+       ok1(len < max);
+       ret[len] = '\0';
+       ok1(strcmp(ret, "01234  0123456789 0\n") == 0);
+       free(ret); len = max = 0;
+
        /* With added " <arg>".  Fits, just. */
        opt.show = NULL;
        opt.type = OPT_HASARG;
index 8534f291ac3e9accfeafb0685fc61286b6adf4b6..0c4f6c8693972b489440feddd1a38b260a8011f9 100644 (file)
@@ -10,7 +10,7 @@
 
 int main(int argc, char *argv[])
 {
-       plan_tests(12);
+       plan_tests(14);
 
        /* --aaa without args. */
        opt_register_arg("-a|--aaa", test_arg, NULL, "aaa", "");
@@ -42,6 +42,10 @@ int main(int argc, char *argv[])
        free(err_output);
        err_output = NULL;
 
+       opt_register_noarg("-d", test_noarg, NULL, "");
+       ok1(!parse_args(&argc, &argv, "-dc", NULL));
+       ok1(strstr(err_output, ": -c: requires an argument"));
+
        /* parse_args allocates argv */
        free(argv);
        return exit_status();
index 0a08a85f7aa3930011cba5600186f3a21d5c5f09..9aa41fe8db62c5f384b517a811b9b49b3ca3577d 100644 (file)
@@ -476,26 +476,26 @@ int main(int argc, char *argv[])
                        char buf[OPT_SHOW_LEN+2] = { 0 };
                        buf[OPT_SHOW_LEN] = '!';
                        i = -77;
-                       opt_show_intval_bi(buf, &i);
+                       opt_show_intval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "-77") == 0);
                        i = 0;
-                       opt_show_intval_bi(buf, &i);
+                       opt_show_intval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "0") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 77;
-                       opt_show_intval_bi(buf, &i);
+                       opt_show_intval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "77") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = -1234 * k;
-                       opt_show_intval_bi(buf, &i);
+                       opt_show_intval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "-1234k") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 500 * M;
-                       opt_show_intval_bi(buf, &i);
+                       opt_show_intval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "500M") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 1024 * M;
-                       opt_show_intval_bi(buf, &i);
+                       opt_show_intval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "1G") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                }
@@ -506,27 +506,27 @@ int main(int argc, char *argv[])
                        char buf[OPT_SHOW_LEN+2] = { 0 };
                        buf[OPT_SHOW_LEN] = '!';
                        i = -77;
-                       opt_show_longval_bi(buf, &i);
+                       opt_show_longval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "-77") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 77;
-                       opt_show_longval_bi(buf, &i);
+                       opt_show_longval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "77") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = -1 * k;
-                       opt_show_longval_bi(buf, &i);
+                       opt_show_longval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "-1k") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 500 * M;
-                       opt_show_longval_bi(buf, &i);
+                       opt_show_longval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "500M") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 1024 * M;
-                       opt_show_longval_bi(buf, &i);
+                       opt_show_longval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "1G") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 0;
-                       opt_show_longval_bi(buf, &i);
+                       opt_show_longval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "0") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                }
@@ -537,23 +537,23 @@ int main(int argc, char *argv[])
                        char buf[OPT_SHOW_LEN+2] = { 0 };
                        buf[OPT_SHOW_LEN] = '!';
                        i = -7777;
-                       opt_show_longlongval_bi(buf, &i);
+                       opt_show_longlongval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "-7777") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 7777;
-                       opt_show_longlongval_bi(buf, &i);
+                       opt_show_longlongval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "7777") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = -10240000 * k;
-                       opt_show_longlongval_bi(buf, &i);
+                       opt_show_longlongval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "-10000M") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 5 * P;
-                       opt_show_longlongval_bi(buf, &i);
+                       opt_show_longlongval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "5P") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 1024 * P;
-                       opt_show_longlongval_bi(buf, &i);
+                       opt_show_longlongval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "1E") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                }
@@ -564,19 +564,19 @@ int main(int argc, char *argv[])
                        char buf[OPT_SHOW_LEN+2] = { 0 };
                        buf[OPT_SHOW_LEN] = '!';
                        i = 77;
-                       opt_show_uintval_bi(buf, &i);
+                       opt_show_uintval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "77") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 1234 * k;
-                       opt_show_uintval_bi(buf, &i);
+                       opt_show_uintval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "1234k") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 500 * M;
-                       opt_show_uintval_bi(buf, &i);
+                       opt_show_uintval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "500M") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 1024 * M;
-                       opt_show_uintval_bi(buf, &i);
+                       opt_show_uintval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "1G") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                }
@@ -587,23 +587,23 @@ int main(int argc, char *argv[])
                        char buf[OPT_SHOW_LEN+2] = { 0 };
                        buf[OPT_SHOW_LEN] = '!';
                        i = 77;
-                       opt_show_ulongval_bi(buf, &i);
+                       opt_show_ulongval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "77") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = k;
-                       opt_show_ulongval_bi(buf, &i);
+                       opt_show_ulongval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "1k") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 500 * M;
-                       opt_show_ulongval_bi(buf, &i);
+                       opt_show_ulongval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "500M") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 1024 * M;
-                       opt_show_ulongval_bi(buf, &i);
+                       opt_show_ulongval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "1G") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 0;
-                       opt_show_ulongval_bi(buf, &i);
+                       opt_show_ulongval_bi(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "0") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                }
@@ -614,19 +614,19 @@ int main(int argc, char *argv[])
                        char buf[OPT_SHOW_LEN+2] = { 0 };
                        buf[OPT_SHOW_LEN] = '!';
                        i = 7777;
-                       opt_show_ulonglongval_bi(buf, (unsigned long long *)&i);
+                       opt_show_ulonglongval_bi(buf, OPT_SHOW_LEN, (unsigned long long *)&i);
                        ok1(strcmp(buf, "7777") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 10240000 * k;
-                       opt_show_ulonglongval_bi(buf, (unsigned long long *)&i);
+                       opt_show_ulonglongval_bi(buf, OPT_SHOW_LEN, (unsigned long long *)&i);
                        ok1(strcmp(buf, "10000M") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 5 * P;
-                       opt_show_ulonglongval_bi(buf, (unsigned long long *)&i);
+                       opt_show_ulonglongval_bi(buf, OPT_SHOW_LEN, (unsigned long long *)&i);
                        ok1(strcmp(buf, "5P") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 1024 * P;
-                       opt_show_ulonglongval_bi(buf, (unsigned long long *)&i);
+                       opt_show_ulonglongval_bi(buf, OPT_SHOW_LEN, (unsigned long long *)&i);
                        ok1(strcmp(buf, "1E") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                }
@@ -860,26 +860,26 @@ int main(int argc, char *argv[])
                        char buf[OPT_SHOW_LEN+2] = { 0 };
                        buf[OPT_SHOW_LEN] = '!';
                        i = -77;
-                       opt_show_intval_si(buf, &i);
+                       opt_show_intval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "-77") == 0);
                        i = 0;
-                       opt_show_intval_si(buf, &i);
+                       opt_show_intval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "0") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 77;
-                       opt_show_intval_si(buf, &i);
+                       opt_show_intval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "77") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = -1234 * k;
-                       opt_show_intval_si(buf, &i);
+                       opt_show_intval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "-1234k") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 500 * M;
-                       opt_show_intval_si(buf, &i);
+                       opt_show_intval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "500M") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 1000 * M;
-                       opt_show_intval_si(buf, &i);
+                       opt_show_intval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "1G") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                }
@@ -890,27 +890,27 @@ int main(int argc, char *argv[])
                        char buf[OPT_SHOW_LEN+2] = { 0 };
                        buf[OPT_SHOW_LEN] = '!';
                        i = -77;
-                       opt_show_longval_si(buf, &i);
+                       opt_show_longval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "-77") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 77;
-                       opt_show_longval_si(buf, &i);
+                       opt_show_longval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "77") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = -1 * k;
-                       opt_show_longval_si(buf, &i);
+                       opt_show_longval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "-1k") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 500 * M;
-                       opt_show_longval_si(buf, &i);
+                       opt_show_longval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "500M") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 1000 * M;
-                       opt_show_longval_si(buf, &i);
+                       opt_show_longval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "1G") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 0;
-                       opt_show_longval_si(buf, &i);
+                       opt_show_longval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "0") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                }
@@ -921,23 +921,23 @@ int main(int argc, char *argv[])
                        char buf[OPT_SHOW_LEN+2] = { 0 };
                        buf[OPT_SHOW_LEN] = '!';
                        i = -7777;
-                       opt_show_longlongval_si(buf, &i);
+                       opt_show_longlongval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "-7777") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 7777;
-                       opt_show_longlongval_si(buf, &i);
+                       opt_show_longlongval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "7777") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = -10240000 * k;
-                       opt_show_longlongval_si(buf, &i);
+                       opt_show_longlongval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "-10240M") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 5 * P;
-                       opt_show_longlongval_si(buf, &i);
+                       opt_show_longlongval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "5P") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 2000 * P;
-                       opt_show_longlongval_si(buf, &i);
+                       opt_show_longlongval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "2E") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                }
@@ -948,19 +948,19 @@ int main(int argc, char *argv[])
                        char buf[OPT_SHOW_LEN+2] = { 0 };
                        buf[OPT_SHOW_LEN] = '!';
                        i = 77;
-                       opt_show_uintval_si(buf, &i);
+                       opt_show_uintval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "77") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 1234 * k;
-                       opt_show_uintval_si(buf, &i);
+                       opt_show_uintval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "1234k") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 500 * M;
-                       opt_show_uintval_si(buf, &i);
+                       opt_show_uintval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "500M") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 1000 * M;
-                       opt_show_uintval_si(buf, &i);
+                       opt_show_uintval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "1G") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                }
@@ -971,23 +971,23 @@ int main(int argc, char *argv[])
                        char buf[OPT_SHOW_LEN+2] = { 0 };
                        buf[OPT_SHOW_LEN] = '!';
                        i = 77;
-                       opt_show_ulongval_si(buf, &i);
+                       opt_show_ulongval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "77") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = k;
-                       opt_show_ulongval_si(buf, &i);
+                       opt_show_ulongval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "1k") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 500 * M;
-                       opt_show_ulongval_si(buf, &i);
+                       opt_show_ulongval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "500M") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 1024 * M;
-                       opt_show_ulongval_si(buf, &i);
+                       opt_show_ulongval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "1024M") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 0;
-                       opt_show_ulongval_si(buf, &i);
+                       opt_show_ulongval_si(buf, OPT_SHOW_LEN, &i);
                        ok1(strcmp(buf, "0") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                }
@@ -998,19 +998,19 @@ int main(int argc, char *argv[])
                        char buf[OPT_SHOW_LEN+2] = { 0 };
                        buf[OPT_SHOW_LEN] = '!';
                        i = 7777;
-                       opt_show_ulonglongval_si(buf, (unsigned long long *)&i);
+                       opt_show_ulonglongval_si(buf, OPT_SHOW_LEN, (unsigned long long *)&i);
                        ok1(strcmp(buf, "7777") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 10240000 * k;
-                       opt_show_ulonglongval_si(buf, (unsigned long long *)&i);
+                       opt_show_ulonglongval_si(buf, OPT_SHOW_LEN, (unsigned long long *)&i);
                        ok1(strcmp(buf, "10240M") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 5 * P;
-                       opt_show_ulonglongval_si(buf, (unsigned long long *)&i);
+                       opt_show_ulonglongval_si(buf, OPT_SHOW_LEN, (unsigned long long *)&i);
                        ok1(strcmp(buf, "5P") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                        i = 1000 * P;
-                       opt_show_ulonglongval_si(buf, (unsigned long long *)&i);
+                       opt_show_ulonglongval_si(buf, OPT_SHOW_LEN, (unsigned long long *)&i);
                        ok1(strcmp(buf, "1E") == 0);
                        ok1(buf[OPT_SHOW_LEN] == '!');
                }
@@ -1090,12 +1090,12 @@ int main(int argc, char *argv[])
                buf[OPT_SHOW_LEN] = '!';
 
                b = true;
-               opt_show_bool(buf, &b);
+               opt_show_bool(buf, OPT_SHOW_LEN, &b);
                ok1(strcmp(buf, "true") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
 
                b = false;
-               opt_show_bool(buf, &b);
+               opt_show_bool(buf, OPT_SHOW_LEN, &b);
                ok1(strcmp(buf, "false") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
        }
@@ -1107,12 +1107,12 @@ int main(int argc, char *argv[])
                buf[OPT_SHOW_LEN] = '!';
 
                b = true;
-               opt_show_invbool(buf, &b);
+               opt_show_invbool(buf, OPT_SHOW_LEN, &b);
                ok1(strcmp(buf, "false") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
 
                b = false;
-               opt_show_invbool(buf, &b);
+               opt_show_invbool(buf, OPT_SHOW_LEN, &b);
                ok1(strcmp(buf, "true") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
        }
@@ -1126,14 +1126,14 @@ int main(int argc, char *argv[])
                /* Short test. */
                p = str;
                strcpy(p, "short");
-               opt_show_charp(buf, &p);
+               opt_show_charp(buf, OPT_SHOW_LEN, &p);
                ok1(strcmp(buf, "\"short\"") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
 
                /* Truncate test. */
                memset(p, 'x', OPT_SHOW_LEN*2);
                p[OPT_SHOW_LEN*2-1] = '\0';
-               opt_show_charp(buf, &p);
+               opt_show_charp(buf, OPT_SHOW_LEN, &p);
                ok1(buf[0] == '"');
                ok1(buf[OPT_SHOW_LEN-1] == '"');
                ok1(buf[OPT_SHOW_LEN] == '!');
@@ -1147,12 +1147,12 @@ int main(int argc, char *argv[])
                buf[OPT_SHOW_LEN] = '!';
 
                i = -77;
-               opt_show_intval(buf, &i);
+               opt_show_intval(buf, OPT_SHOW_LEN, &i);
                ok1(strcmp(buf, "-77") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
 
                i = 77;
-               opt_show_intval(buf, &i);
+               opt_show_intval(buf, OPT_SHOW_LEN, &i);
                ok1(strcmp(buf, "77") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
        }
@@ -1164,7 +1164,7 @@ int main(int argc, char *argv[])
                buf[OPT_SHOW_LEN] = '!';
 
                ui = 4294967295U;
-               opt_show_uintval(buf, &ui);
+               opt_show_uintval(buf, OPT_SHOW_LEN, &ui);
                ok1(strcmp(buf, "4294967295") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
        }
@@ -1176,7 +1176,7 @@ int main(int argc, char *argv[])
                buf[OPT_SHOW_LEN] = '!';
 
                l = 1234567890L;
-               opt_show_longval(buf, &l);
+               opt_show_longval(buf, OPT_SHOW_LEN, &l);
                ok1(strcmp(buf, "1234567890") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
        }
@@ -1188,7 +1188,7 @@ int main(int argc, char *argv[])
                buf[OPT_SHOW_LEN] = '!';
 
                ul = 4294967295UL;
-               opt_show_ulongval(buf, &ul);
+               opt_show_ulongval(buf, OPT_SHOW_LEN, &ul);
                ok1(strcmp(buf, "4294967295") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
        }
@@ -1200,12 +1200,12 @@ int main(int argc, char *argv[])
                buf[OPT_SHOW_LEN] = '!';
 
                f = -77.5;
-               opt_show_floatval(buf, &f);
+               opt_show_floatval(buf, OPT_SHOW_LEN, &f);
                ok1(strcmp(buf, "-77.500000") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
 
                f = 77.5;
-               opt_show_floatval(buf, &f);
+               opt_show_floatval(buf, OPT_SHOW_LEN, &f);
                ok1(strcmp(buf, "77.500000") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
        }
@@ -1217,12 +1217,12 @@ int main(int argc, char *argv[])
                buf[OPT_SHOW_LEN] = '!';
 
                d = -77;
-               opt_show_doubleval(buf, &d);
+               opt_show_doubleval(buf, OPT_SHOW_LEN, &d);
                ok1(strcmp(buf, "-77.000000") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
 
                d = 77;
-               opt_show_doubleval(buf, &d);
+               opt_show_doubleval(buf, OPT_SHOW_LEN, &d);
                ok1(strcmp(buf, "77.000000") == 0);
                ok1(buf[OPT_SHOW_LEN] == '!');
        }
index 1dbb351bedf41b0022a8abd26b3c0fbbc07ad445..2d7410ae22853e6bb9fbe6c3896c58dc01773a5c 100644 (file)
@@ -59,8 +59,8 @@ static void *reallocfn(void *ptr, size_t size)
 static void freefn(void *ptr)
 {
        free_count++;
-       free(ptr);
        *find_ptr(ptr) = NULL;
+       free(ptr);
 }
 
 int main(int argc, char *argv[])
diff --git a/ccan/opt/test/run-userbits.c b/ccan/opt/test/run-userbits.c
new file mode 100644 (file)
index 0000000..7f102f0
--- /dev/null
@@ -0,0 +1,59 @@
+#include <ccan/tap/tap.h>
+#include <stdlib.h>
+#include <ccan/opt/opt.c>
+#include <ccan/opt/usage.c>
+#include <ccan/opt/helpers.c>
+#include <ccan/opt/parse.c>
+#include "utils.h"
+
+int main(int argc, char *argv[])
+{
+       const char *myname = argv[0];
+
+       plan_tests(28);
+
+       opt_register_noarg("-a", test_noarg, NULL, "All");
+       opt_register_noarg("--aaa", test_noarg, NULL, "AAAAll");
+       opt_register_arg("-b|--bbb", test_arg, NULL, "bbb", "AAAAAAll");
+
+       ok1(strcmp(opt_table[0].names, "-a") == 0);
+       ok1(opt_table[0].type == OPT_NOARG);
+       ok1(strcmp(opt_table[1].names, "--aaa") == 0);
+       ok1(opt_table[1].type == OPT_NOARG);
+       ok1(strcmp(opt_table[2].names, "-b|--bbb") == 0);
+       ok1(opt_table[2].type == OPT_HASARG);
+
+       opt_table[0].type |= (1 << OPT_USER_START);
+       opt_table[1].type |= ((1 << OPT_USER_END)-1) - ((1 << OPT_USER_START)-1);
+       opt_table[2].type |= (1 << OPT_USER_END);
+
+       /* Should all work fine! */
+       ok1(parse_args(&argc, &argv, "-a", NULL));
+       ok1(argc == 1);
+       ok1(argv[0] == myname);
+       ok1(test_cb_called == 1);
+
+       ok1(parse_args(&argc, &argv, "--aaa", NULL));
+       ok1(argc == 1);
+       ok1(argv[0] == myname);
+       ok1(test_cb_called == 2);
+
+       /* This one needs an arg. */
+       ok1(parse_args(&argc, &argv, "-b", NULL) == false);
+       ok1(test_cb_called == 2);
+       ok1(parse_args(&argc, &argv, "-b", "bbb", NULL));
+       ok1(argc == 1);
+       ok1(argv[0] == myname);
+       ok1(argv[1] == NULL);
+       ok1(test_cb_called == 3);
+
+       ok1(parse_args(&argc, &argv, "--bbb", "bbb", NULL));
+       ok1(argc == 1);
+       ok1(argv[0] == myname);
+       ok1(argv[1] == NULL);
+       ok1(test_cb_called == 4);
+
+       /* parse_args allocates argv */
+       free(argv);
+       return exit_status();
+}
index 2ff04884ebdc0efe6dc4d9dd8fe4ae6af4b9175b..61199fb4676dbdeaa8a5cdf81a6fba7a27d5de5d 100644 (file)
@@ -21,9 +21,10 @@ char *test_arg(const char *optarg, const char *arg)
        return NULL;
 }
 
-void show_arg(char buf[OPT_SHOW_LEN], const char *arg)
+bool show_arg(char *buf, size_t len, const char *arg)
 {
-       strncpy(buf, arg, OPT_SHOW_LEN);
+       strncpy(buf, arg, len);
+       return true;
 }
 
 char *err_output = NULL;
index 12cf0b753e99be441ead57f73b1dc1c3e2d79999..3ada62d117c048ef666f5078d874c5bcc6a47129 100644 (file)
@@ -13,7 +13,7 @@ void reset_options(void);
 extern unsigned int test_cb_called;
 char *test_noarg(void *arg);
 char *test_arg(const char *optarg, const char *arg);
-void show_arg(char buf[OPT_SHOW_LEN], const char *arg);
+bool show_arg(char *buf, size_t len, const char *arg);
 
 extern struct opt_table short_table[];
 extern struct opt_table long_table[];
index 12f44a48752e0e0d4e0d722c74b7513561334733..568e4661d8098bf1fd009a169867b0d369339fb2 100644 (file)
@@ -20,6 +20,9 @@ const char opt_hidden[1];
 #define MIN_DESC_WIDTH 40
 #define MIN_TOTAL_WIDTH 50
 
+/* Maximum length of arg to show in opt_usage */
+#define OPT_SHOW_LEN 80
+
 static unsigned int get_columns(void)
 {
        int ws_col = 0;
@@ -72,7 +75,8 @@ static size_t consume_words(const char *words, size_t maxlen, size_t *prefix,
                }
        }
 
-       *start = (words[oldlen - 1] == '\n');
+       if (oldlen != 0)
+               *start = (words[oldlen - 1] == '\n');
        return oldlen;
 }
 
@@ -147,20 +151,20 @@ static char *add_desc(char *base, size_t *len, size_t *max,
        if (opt->show) {
                char buf[OPT_SHOW_LEN + sizeof("...")];
                strcpy(buf + OPT_SHOW_LEN, "...");
-               opt->show(buf, opt->u.arg);
+               if (opt->show(buf, OPT_SHOW_LEN, opt->u.arg)) {
+                       /* If it doesn't fit on this line, indent. */
+                       if (off + strlen(" (default: ") + strlen(buf) + strlen(")")
+                           > width) {
+                               base = add_indent(base, len, max, indent);
+                       } else {
+                               /* Remove \n. */
+                               (*len)--;
+                       }
 
-               /* If it doesn't fit on this line, indent. */
-               if (off + strlen(" (default: ") + strlen(buf) + strlen(")")
-                   > width) {
-                       base = add_indent(base, len, max, indent);
-               } else {
-                       /* Remove \n. */
-                       (*len)--;
+                       base = add_str(base, len, max, " (default: ");
+                       base = add_str(base, len, max, buf);
+                       base = add_str(base, len, max, ")\n");
                }
-
-               base = add_str(base, len, max, " (default: ");
-               base = add_str(base, len, max, buf);
-               base = add_str(base, len, max, ")\n");
        }
        return base;
 }
@@ -181,10 +185,10 @@ char *opt_usage(const char *argv0, const char *extra)
                size_t l;
                if (opt_table[i].desc == opt_hidden)
                        continue;
-               if (opt_table[i].type == OPT_SUBTABLE)
+               if (opt_table[i].type & OPT_SUBTABLE)
                        continue;
                l = strlen(opt_table[i].names);
-               if (opt_table[i].type == OPT_HASARG
+               if ((opt_table[i].type & OPT_HASARG)
                    && !strchr(opt_table[i].names, ' ')
                    && !strchr(opt_table[i].names, '='))
                        l += strlen(" <arg>");
@@ -220,7 +224,7 @@ char *opt_usage(const char *argv0, const char *extra)
        for (i = 0; i < opt_count; i++) {
                if (opt_table[i].desc == opt_hidden)
                        continue;
-               if (opt_table[i].type == OPT_SUBTABLE) {
+               if (opt_table[i].type & OPT_SUBTABLE) {
                        ret = add_str(ret, &len, &max, opt_table[i].desc);
                        ret = add_str(ret, &len, &max, ":\n");
                        continue;
index d8d658d37a3923454324dfe06a3d4bac777b91d0..cc10cf3d7f25e25531d58a9c4b07c8500ff93bf7 100644 (file)
@@ -74,9 +74,11 @@ char *rbuf_read_str(struct rbuf *rbuf, char term)
        ssize_t r = 0;
        size_t prev = 0;
 
-       while (!(p = memchr(membuf_elems(&rbuf->m) + prev,
-                           term,
-                           membuf_num_elems(&rbuf->m) - prev))) {
+       /* memchr(NULL, ..., 0) is illegal.  FML. */
+       while (membuf_num_elems(&rbuf->m) == prev
+              || !(p = memchr(membuf_elems(&rbuf->m) + prev,
+                              term,
+                              membuf_num_elems(&rbuf->m) - prev))) {
                prev += r;
                r = get_more(rbuf);
                if (r < 0)
index 380a225c948319c66dbb5e004383e8bd07dc28f5..495d37c34e313e6a754f9e310f7d74a77f22e522 100644 (file)
@@ -184,7 +184,7 @@ static bool pull_char(const char **data, size_t *len, char *c)
        return true;
 }
 
-static bool is_valid_cond(enum rune_condition cond)
+bool rune_condition_is_valid(enum rune_condition cond)
 {
        switch (cond) {
        case RUNE_COND_IF_MISSING:
@@ -203,31 +203,35 @@ static bool is_valid_cond(enum rune_condition cond)
        return false;
 }
 
+size_t rune_altern_fieldname_len(const char *alternstr, size_t alternstrlen)
+{
+       for (size_t i = 0; i < alternstrlen; i++) {
+               if (cispunct(alternstr[i]) && alternstr[i] != '_')
+                       return i;
+       }
+       return alternstrlen;
+}
+
 /* Sets *more on success: true if another altern follows */
 static struct rune_altern *rune_altern_decode(const tal_t *ctx,
                                              const char **data, size_t *len,
                                              bool *more)
 {
        struct rune_altern *alt = tal(ctx, struct rune_altern);
-       const char *strstart = *data;
        char *value;
-       size_t strlen = 0;
+       size_t strlen;
        char c;
 
-        /* Swallow field up to conditional */
-       for (;;) {
-               if (!pull_char(data, len, &c))
-                       return tal_free(alt);
-               if (cispunct(c))
-                       break;
-               strlen++;
-       }
+        /* Swallow field up to possible conditional */
+       strlen = rune_altern_fieldname_len(*data, *len);
+       alt->fieldname = tal_strndup(alt, *data, strlen);
+       *data += strlen;
+       *len -= strlen;
 
-       alt->fieldname = tal_strndup(alt, strstart, strlen);
-       if (!is_valid_cond(c)) {
-               pull_invalid(data, len);
+       /* Grab conditional */
+       if (!pull_char(data, len, &c) || !rune_condition_is_valid(c))
                return tal_free(alt);
-       }
+
        alt->condition = c;
 
        /* Assign worst case. */
index b67b78281edad3ba2659b1a54798f932e78840f6..c373269aa0c90fcf4372b8b67a7097da71c43418 100644 (file)
@@ -376,4 +376,25 @@ char *rune_to_string(const tal_t *ctx, const struct rune *rune);
 struct rune_restr *rune_restr_from_string(const tal_t *ctx,
                                          const char *str,
                                          size_t len);
+
+/**
+ * rune_condition_is_valid: is this a valid condition?
+ * @cond: potential condition character.
+ *
+ * Returns true if it's one of enum rune_condition.
+ */
+bool rune_condition_is_valid(enum rune_condition cond);
+
+/**
+ * rune_altern_fieldname_len: how much of this string is condition?
+ * @alternstr: potential alternative string
+ * @alternstrlen: length
+ *
+ * This helps parsing your own runes.
+ *
+ * Returns the first possible condition (check with rune_condition_is_valid)
+ * or alternstrlen if none found.
+ */
+size_t rune_altern_fieldname_len(const char *alternstr, size_t alternstrlen);
+
 #endif /* CCAN_RUNE_RUNE_H */
index e532655284dbade2701fe22f0d156efa937c65f1..d90b701c609cc48401029f8988e97dfe660f7f21 100644 (file)
@@ -43,7 +43,7 @@ int main(void)
        assert(vecs);
        lines = tal_strsplit(mr, take(vecs), "\n", STR_NO_EMPTY);
 
-       plan_tests(343);
+       plan_tests(355);
 
        for (size_t i = 0; lines[i]; i++) {
                struct rune *rune1, *rune2;
index a8411693c60533b1cebd41d05246bab50b76fde8..880ea3c69f3ce441fd81229fecc6bc4ba64e2c26 100644 (file)
@@ -94,6 +94,12 @@ PASS,f1=
 PASS,f1=/
 PASS,f1=11
 PASS
+VALID,f_with_underscores equals v1,ee979e1f2c376d69923aab0e8e001111963af038bdce394ffd7ecdc9e7020a6e:f_with_underscores=v1,7peeHyw3bWmSOqsOjgAREZY68Di9zjlP_X7NyecCCm5mX3dpdGhfdW5kZXJzY29yZXM9djE=
+PASS,f_with_underscores=v1
+FAIL,f_with_underscores=v
+FAIL,f_with_underscores=v1a
+FAIL
+FAIL,f2=f_with_underscores
 VALID,f1=1 or f2=3,85c3643dc102f0a0d6f20eeb8c294092151688fae41ef7c8ec7272ab23918376:f1=1|f2=3,hcNkPcEC8KDW8g7rjClAkhUWiPrkHvfI7HJyqyORg3ZmMT0xfGYyPTM=
 PASS,f1=1
 PASS,f1=1,f2=2
@@ -144,7 +150,6 @@ MALFORMED,Bad condition ?,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87
 MALFORMED,Bad condition [,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1[11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMVsxMQ==
 MALFORMED,Bad condition \,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1\11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMVwxMQ==
 MALFORMED,Bad condition ],76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1]11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMV0xMQ==
-MALFORMED,Bad condition _,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1_11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMV8xMQ==
 MALFORMED,Bad condition `,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1`11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMWAxMQ==
 MALFORMED,Bad condition |,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0f:f1|11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw9mMXwxMQ==
 BAD DERIVATION,Incremented sha,76bdd625de0e12058956e6c8a07cac58d7dc2253609a6bfb959f87cc094f3f0e:f1#11,dr3WJd4OEgWJVubIoHysWNfcIlNgmmv7lZ-HzAlPPw5mMSMxMQ==
index d34de811b3542dbea10610f875f554dc4e734085..8eb4ab42fc812d32f5b0bb99c2b31e82fc0b90b2 100644 (file)
@@ -22,7 +22,8 @@ static int stringbuilder_cpy(
        if (*str != s) {
                if (!s_len)
                        s_len = strlen(s);
-               if (s_len > *str_sz)
+               /* Include nul term! */
+               if (s_len >= *str_sz)
                        return EMSGSIZE;
                strcpy(*str, s);
        }
index 2d05dd93f73b06a35538b1697ccf2eb56cdce2e0..1230d8cacafcd2bfb05b659435480ba0ac77f9c5 100644 (file)
@@ -28,7 +28,8 @@ enum prop_type {
 
 struct tal_hdr {
        struct list_node list;
-       struct prop_hdr *prop;
+       /* Use is_prop_hdr tell if this is a struct prop_hdr or string! */
+       char *prop;
        /* XOR with TAL_PTR_OBFUSTICATOR */
        intptr_t parent_child;
        size_t bytelen;
@@ -36,7 +37,8 @@ struct tal_hdr {
 
 struct prop_hdr {
        enum prop_type type;
-       struct prop_hdr *next;
+       /* Use is_prop_hdr to tell if this is a struct prop_hdr or string! */
+       char *next;
 };
 
 struct children {
@@ -72,7 +74,7 @@ static struct {
        struct tal_hdr hdr;
        struct children c;
 } null_parent = { { { &null_parent.hdr.list, &null_parent.hdr.list },
-                   &null_parent.c.hdr, TAL_PTR_OBFUSTICATOR, 0 },
+               (char *)&null_parent.c.hdr, TAL_PTR_OBFUSTICATOR, 0 },
                  { { CHILDREN, NULL },
                    &null_parent.hdr,
                    { { &null_parent.c.children.n,
@@ -123,9 +125,11 @@ void tal_cleanup(void)
 }
 
 /* We carefully start all real properties with a zero byte. */
-static bool is_literal(const struct prop_hdr *prop)
+static struct prop_hdr *is_prop_hdr(const char *ptr)
 {
-       return ((char *)prop)[0] != 0;
+       if (*ptr != 0)
+               return NULL;
+       return (struct prop_hdr *)ptr;
 }
 
 #ifndef NDEBUG
@@ -174,8 +178,11 @@ static struct tal_hdr *to_tal_hdr(const void *ctx)
        check_bounds(ignore_destroying_bit(t->parent_child));
        check_bounds(t->list.next);
        check_bounds(t->list.prev);
-       if (t->prop && !is_literal(t->prop))
-               check_bounds(t->prop);
+       if (t->prop) {
+               struct prop_hdr *p = is_prop_hdr(t->prop);
+               if (p)
+                       check_bounds(p);
+       }
        return t;
 }
 
@@ -215,13 +222,12 @@ static void notify(const struct tal_hdr *ctx,
                   enum tal_notify_type type, const void *info,
                   int saved_errno)
 {
-        const struct prop_hdr *p;
+        const char *ptr;
+       const struct prop_hdr *p;
 
-        for (p = ctx->prop; p; p = p->next) {
+        for (ptr = ctx->prop; ptr && (p = is_prop_hdr(ptr)) != NULL; ptr = p->next) {
                struct notifier *n;
 
-                if (is_literal(p))
-                       break;
                 if (p->type != NOTIFIER)
                        continue;
                n = (struct notifier *)p;
@@ -255,29 +261,54 @@ static void *allocate(size_t size)
        return ret;
 }
 
-static struct prop_hdr **find_property_ptr(const struct tal_hdr *t,
-                                          enum prop_type type)
+/* Returns a pointer to the pointer: can cast (*ret) to a (struct prop_ptr *) */
+static char **find_property_ptr(struct tal_hdr *t, enum prop_type type)
 {
-        struct prop_hdr **p;
+       char **ptr;
+        struct prop_hdr *p;
 
-        for (p = (struct prop_hdr **)&t->prop; *p; p = &(*p)->next) {
-                if (is_literal(*p)) {
-                        if (type == NAME)
-                                return p;
-                        break;
-                }
-                if ((*p)->type == type)
-                        return p;
-        }
-        return NULL;
+       /* NAME is special, as it can be a literal: see find_name_property */
+       assert(type != NAME);
+       for (ptr = &t->prop; *ptr; ptr = &p->next) {
+               if (!is_prop_hdr(*ptr))
+                       break;
+               p = (struct prop_hdr *)*ptr;
+                if (p->type == type)
+                        return ptr;
+       }
+       return NULL;
+}
+
+/* This is special:
+ * NULL - not found
+ * *literal: true - char **, pointer to literal pointer.
+ * *literal: false - struct prop_hdr **, pointer to header ptr.
+ */
+static char **find_name_property(struct tal_hdr *t, bool *literal)
+{
+       char **ptr;
+        struct prop_hdr *p;
+
+       for (ptr = &t->prop; *ptr; ptr = &p->next) {
+               if (!is_prop_hdr(*ptr)) {
+                       *literal = true;
+                       return ptr;
+               }
+               p = (struct prop_hdr *)*ptr;
+                if (p->type == NAME) {
+                       *literal = false;
+                        return ptr;
+               }
+       }
+       return NULL;
 }
 
-static void *find_property(const struct tal_hdr *parent, enum prop_type type)
+static void *find_property(struct tal_hdr *parent, enum prop_type type)
 {
-        struct prop_hdr **p = find_property_ptr(parent, type);
+        char **ptr = find_property_ptr(parent, type);
 
-        if (p)
-                return *p;
+        if (ptr)
+                return (struct prop_hdr *)*ptr;
         return NULL;
 }
 
@@ -287,7 +318,7 @@ static void init_property(struct prop_hdr *hdr,
 {
        hdr->type = type;
        hdr->next = parent->prop;
-       parent->prop = hdr;
+       parent->prop = (char *)hdr;
 }
 
 static struct notifier *add_notifier_property(struct tal_hdr *t,
@@ -321,17 +352,20 @@ static enum tal_notify_type del_notifier_property(struct tal_hdr *t,
                                                  bool match_extra_arg,
                                                  void *extra_arg)
 {
-        struct prop_hdr **p;
+       char **ptr;
+       struct prop_hdr *p;
 
-        for (p = (struct prop_hdr **)&t->prop; *p; p = &(*p)->next) {
+       for (ptr = &t->prop; *ptr; ptr = &p->next) {
                struct notifier *n;
                enum tal_notify_type types;
 
-                if (is_literal(*p))
+               p = is_prop_hdr(*ptr);
+               if (!p)
                        break;
-                if ((*p)->type != NOTIFIER)
+
+                if (p->type != NOTIFIER)
                        continue;
-               n = (struct notifier *)*p;
+               n = (struct notifier *)p;
                if (n->u.notifyfn != fn)
                        continue;
 
@@ -341,8 +375,8 @@ static enum tal_notify_type del_notifier_property(struct tal_hdr *t,
                    && extra_arg != EXTRA_ARG(n))
                        continue;
 
-               *p = (*p)->next;
-               freefn(n);
+               *ptr = p->next;
+               freefn(p);
                return types & ~(NOTIFY_IS_DESTRUCTOR|NOTIFY_EXTRA_ARG);
         }
         return 0;
@@ -388,7 +422,8 @@ static bool add_child(struct tal_hdr *parent, struct tal_hdr *child)
 
 static void del_tree(struct tal_hdr *t, const tal_t *orig, int saved_errno)
 {
-       struct prop_hdr **prop, *p, *next;
+       struct prop_hdr *prop;
+       char *ptr, *next;
 
        assert(!taken(from_tal_hdr(t)));
 
@@ -402,10 +437,10 @@ static void del_tree(struct tal_hdr *t, const tal_t *orig, int saved_errno)
        notify(t, TAL_NOTIFY_FREE, (tal_t *)orig, saved_errno);
 
        /* Now free children and groups. */
-       prop = find_property_ptr(t, CHILDREN);
+       prop = find_property(t, CHILDREN);
        if (prop) {
                struct tal_hdr *i;
-               struct children *c = (struct children *)*prop;
+               struct children *c = (struct children *)prop;
 
                while ((i = list_top(&c->children, struct tal_hdr, list))) {
                        list_del(&i->list);
@@ -414,9 +449,9 @@ static void del_tree(struct tal_hdr *t, const tal_t *orig, int saved_errno)
        }
 
         /* Finally free our properties. */
-        for (p = t->prop; p && !is_literal(p); p = next) {
-                next = p->next;
-               freefn(p);
+       for (ptr = t->prop; ptr && (prop = is_prop_hdr(ptr)); ptr = next) {
+                next = prop->next;
+               freefn(ptr);
         }
         freefn(t);
 }
@@ -590,25 +625,34 @@ bool tal_del_destructor2_(const tal_t *ctx, void (*destroy)(void *me, void *arg)
 bool tal_set_name_(tal_t *ctx, const char *name, bool literal)
 {
         struct tal_hdr *t = debug_tal(to_tal_hdr(ctx));
-        struct prop_hdr **prop = find_property_ptr(t, NAME);
+       bool was_literal;
+       char **nptr;
 
         /* Get rid of any old name */
-        if (prop) {
-                struct name *oldname = (struct name *)*prop;
-                if (is_literal(&oldname->hdr))
-                        *prop = NULL;
-                else {
-                        *prop = oldname->hdr.next;
+       nptr = find_name_property(t, &was_literal);
+       if (nptr) {
+               if (was_literal)
+                       *nptr = NULL;
+               else {
+                       struct name *oldname;
+
+                       oldname = (struct name *)*nptr;
+                       *nptr = oldname->hdr.next;
                        freefn(oldname);
-                }
+               }
         }
 
         if (literal && name[0]) {
-                struct prop_hdr **p;
+               char **ptr;
+               struct prop_hdr *prop;
 
                 /* Append literal. */
-                for (p = &t->prop; *p && !is_literal(*p); p = &(*p)->next);
-                *p = (struct prop_hdr *)name;
+               for (ptr = &t->prop; *ptr; ptr = &prop->next) {
+                       prop = is_prop_hdr(*ptr);
+                       if (!prop)
+                               break;
+               }
+                *ptr = (char *)name;
         } else if (!add_name_property(t, name))
                return false;
 
@@ -620,15 +664,16 @@ bool tal_set_name_(tal_t *ctx, const char *name, bool literal)
 
 const char *tal_name(const tal_t *t)
 {
-        struct name *n;
+       char **nptr;
+       bool literal;
 
-       n = find_property(debug_tal(to_tal_hdr(t)), NAME);
-       if (!n)
+       nptr = find_name_property(debug_tal(to_tal_hdr(t)), &literal);
+       if (!nptr)
                return NULL;
+       if (literal)
+               return *nptr;
 
-       if (is_literal(&n->hdr))
-               return (const char *)n;
-       return n->name;
+       return ((struct name *)(*nptr))->name;
 }
 
 size_t tal_bytelen(const tal_t *ptr)
@@ -803,7 +848,7 @@ void *tal_dup_(const tal_t *ctx, const void *p, size_t size,
        }
 
        ret = tal_alloc_arr_(ctx, size, n + extra, false, label);
-       if (ret)
+       if (ret && p)
                memcpy(ret, p, nbytes);
        return ret;
 }
@@ -832,36 +877,38 @@ void tal_set_backend(void *(*alloc_fn)(size_t size),
 static void dump_node(unsigned int indent, const struct tal_hdr *t)
 {
        unsigned int i;
-        const struct prop_hdr *p;
+        const struct prop_hdr *prop;
+       const char *ptr;
 
        for (i = 0; i < indent; i++)
                fprintf(stderr, "  ");
        fprintf(stderr, "%p len=%zu", t, t->bytelen);
-        for (p = t->prop; p; p = p->next) {
+        for (ptr = t->prop; ptr; ptr = prop->next) {
                struct children *c;
                struct name *n;
                struct notifier *no;
-                if (is_literal(p)) {
-                       fprintf(stderr, " \"%s\"", (const char *)p);
+                prop = is_prop_hdr(ptr);
+               if (!prop) {
+                       fprintf(stderr, " \"%s\"", ptr);
                        break;
                }
-               switch (p->type) {
+               switch (prop->type) {
                case CHILDREN:
-                       c = (struct children *)p;
+                       c = (struct children *)prop;
                        fprintf(stderr, " CHILDREN(%p):parent=%p,children={%p,%p}",
-                              p, c->parent,
+                              prop, c->parent,
                               c->children.n.prev, c->children.n.next);
                        break;
                case NAME:
-                       n = (struct name *)p;
-                       fprintf(stderr, " NAME(%p):%s", p, n->name);
+                       n = (struct name *)prop;
+                       fprintf(stderr, " NAME(%p):%s", prop, n->name);
                        break;
                case NOTIFIER:
-                       no = (struct notifier *)p;
-                       fprintf(stderr, " NOTIFIER(%p):fn=%p", p, no->u.notifyfn);
+                       no = (struct notifier *)prop;
+                       fprintf(stderr, " NOTIFIER(%p):fn=%p", prop, no->u.notifyfn);
                        break;
                default:
-                       fprintf(stderr, " **UNKNOWN(%p):%i**", pp->type);
+                       fprintf(stderr, " **UNKNOWN(%p):%i**", prop, prop->type);
                }
        }
        fprintf(stderr, "\n");
@@ -873,7 +920,7 @@ static void tal_dump_(unsigned int level, const struct tal_hdr *t)
 
        dump_node(level, t);
 
-       children = find_property(t, CHILDREN);
+       children = find_property((struct tal_hdr *)t, CHILDREN);
        if (children) {
                struct tal_hdr *i;
 
@@ -904,7 +951,8 @@ static bool check_err(struct tal_hdr *t, const char *errorstr,
 static bool check_node(struct children *parent_child,
                       struct tal_hdr *t, const char *errorstr)
 {
-       struct prop_hdr *p;
+       struct prop_hdr *prop;
+       char *p;
        struct name *name = NULL;
        struct children *children = NULL;
 
@@ -914,23 +962,24 @@ static bool check_node(struct children *parent_child,
        if (ignore_destroying_bit(t->parent_child) != parent_child)
                return check_err(t, errorstr, "incorrect parent");
 
-       for (p = t->prop; p; p = p->next) {
-               if (is_literal(p)) {
+       for (p = t->prop; p; p = prop->next) {
+               prop = is_prop_hdr(p);
+               if (!prop) {
                        if (name)
                                return check_err(t, errorstr,
                                                 "has extra literal");
                        break;
                }
-               if (!in_bounds(p))
+               if (!in_bounds(prop))
                        return check_err(t, errorstr,
                                         "has bad property pointer");
 
-               switch (p->type) {
+               switch (prop->type) {
                case CHILDREN:
                        if (children)
                                return check_err(t, errorstr,
                                                 "has two child nodes");
-                       children = (struct children *)p;
+                       children = (struct children *)prop;
                        break;
                case NOTIFIER:
                        break;
@@ -938,7 +987,7 @@ static bool check_node(struct children *parent_child,
                        if (name)
                                return check_err(t, errorstr,
                                                 "has two names");
-                       name = (struct name *)p;
+                       name = (struct name *)prop;
                        break;
                default:
                        return check_err(t, errorstr, "has unknown property");
index 150f00adae9e2d60c0df655ff2ac105e34c2c85a..47e436408cbe4ce803951eabb59410e2d6fde1d2 100644 (file)
@@ -13,8 +13,8 @@ static void *my_realloc(void *old, size_t size)
        void *new = realloc(old, size);
        if (new == old) {
                void *p = malloc(size);
-               memcpy(p, old, size);
-               free(old);
+               memcpy(p, new, size);
+               free(new);
                new = p;
        }
        return new;
index 29f055588015f5e38f02513c6dcce39b4657ff20..5cc3352a4a90df99362ac74ea0e9a6635ccafec4 100644 (file)
@@ -56,7 +56,7 @@ static unsigned bucket_of(ssize_t min, unsigned step_bits, ssize_t val)
                return 0;
        }
        assert(step_bits < SIZET_BITS);
-       return (size_t)(val - min) >> step_bits;
+       return ((size_t)val - (size_t)min) >> step_bits;
 }
 
 /* Return the min value in bucket b. */
@@ -67,7 +67,7 @@ static ssize_t bucket_min(ssize_t min, unsigned step_bits, unsigned b)
                return min;
        }
        assert(step_bits < SIZET_BITS);
-       return min + ((ssize_t)b << step_bits);
+       return min + ((size_t)b << step_bits);
 }
 
 /* Does shifting by this many bits truncate the number? */
@@ -76,6 +76,9 @@ static bool shift_overflows(size_t num, unsigned bits)
        if (bits == 0) {
                return false;
        }
+       if (bits >= SIZET_BITS) {
+               return true;
+       }
 
        return ((num << bits) >> 1) != (num << (bits - 1));
 }
@@ -94,7 +97,7 @@ static void renormalize(struct tally *tally,
 
        /* If we don't have sufficient range, increase step bits until
         * buckets cover entire range of ssize_t anyway. */
-       range = (new_max - new_min) + 1;
+       range = ((size_t)new_max - (size_t)new_min) + 1;
        while (!shift_overflows(tally->buckets, tally->step_bits)
               && range > ((size_t)tally->buckets << tally->step_bits)) {
                /* Collapse down. */
@@ -113,11 +116,13 @@ static void renormalize(struct tally *tally,
        memset(tally->counts, 0, sizeof(tally->counts[0]) * old_min);
 
        /* If we moved boundaries, adjust buckets to that ratio. */
-       spill = (tally->min - new_min) % (1 << tally->step_bits);
-       for (i = 0; i < tally->buckets-1; i++) {
-               size_t adjust = (tally->counts[i] >> tally->step_bits) * spill;
-               tally->counts[i] -= adjust;
-               tally->counts[i+1] += adjust;
+       if (tally->step_bits < SIZET_BITS) {
+               spill = (tally->min - new_min) % ((size_t)1 << tally->step_bits);
+               for (i = 0; i < tally->buckets-1; i++) {
+                       size_t adjust = (tally->counts[i] >> tally->step_bits) * spill;
+                       tally->counts[i] -= adjust;
+                       tally->counts[i+1] += adjust;
+               }
        }
 
 update:
index e0f84b383976c4d106e6d9fe3ee9043c449d1ed8..df3aac88b785a4acc241e125a9c377766a55272d 100644 (file)
  * It evaluates to @x so you can chain it.
  */
 #define tcon_check_ptr(x, canary, expr)                                \
-       (sizeof(&(x)->_tcon[0].canary == (expr)) ? (x) : (x))
-
+       (sizeof((expr) ? (expr) : &(x)->_tcon[0].canary) ? (x) : (x))
 
 /**
  * tcon_type - the type within a container (or void *)
index 44645a7ec6d417875ceed8910915efea3a0d2193..ed1d3e206acd97eee8cf46b69e8018a5a87096e4 100644 (file)
@@ -25,7 +25,7 @@ struct info_tcon {
 int main(void)
 {
        struct info_tcon info;
-       struct outer ovar;
+       struct outer ovar = { 0, { 0 } };
 #ifdef FAIL
 #if !HAVE_TYPEOF
 #error We cannot detect type problems without HAVE_TYPEOF
index 19ba5bdcc915d22851009a630b4bda32dd85f242..a03f6514e1793b0dce08c45cc23cd34c7078d01c 100644 (file)
@@ -21,7 +21,7 @@ int main(void)
 {
        TCON_WRAP(struct info_base,
                  TCON_CONTAINER(concan, struct outer, inner)) info;
-       struct outer ovar;
+       struct outer ovar = { 0, { 0 } };
 #ifdef FAIL
 #if !HAVE_TYPEOF
 #error We cannot detect type problems without HAVE_TYPEOF
index 9185225a9361903e25e86ce616e31da0e502e577..dfdfdba9a3412ef692311762b9cdfdd54d01c4e5 100644 (file)
@@ -25,7 +25,7 @@ struct info_tcon {
 int main(void)
 {
        struct info_tcon info;
-       struct outer ovar;
+       struct outer ovar = { 0, { 0 } };
 #ifdef FAIL
 #if !HAVE_TYPEOF
 #error We cannot detect type problems without HAVE_TYPEOF
index 958e5c8b3dca47c67c1f23aa25fe9fc29e759e90..a56e510f1e2bb86f326b917ad61bc17c839281b2 100644 (file)
@@ -21,7 +21,7 @@ int main(void)
 {
        TCON_WRAP(struct info_base,
                  TCON_CONTAINER(concan, struct outer, inner)) info;
-       struct outer ovar;
+       struct outer ovar = { 0, { 0 } };
 #ifdef FAIL
 #if !HAVE_TYPEOF
 #error We cannot detect type problems without HAVE_TYPEOF
diff --git a/ccan/ungraph/LICENSE b/ccan/ungraph/LICENSE
new file mode 120000 (symlink)
index 0000000..2354d12
--- /dev/null
@@ -0,0 +1 @@
+../../licenses/BSD-MIT
\ No newline at end of file
diff --git a/ccan/ungraph/_info b/ccan/ungraph/_info
new file mode 100644 (file)
index 0000000..6088c5e
--- /dev/null
@@ -0,0 +1,77 @@
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+
+/**
+ * ungraph - extract a graph from an ASCII diagram.
+ *
+ * This code takes an ASCII diagram and converts it to a graph.
+ * The following things are assumed:
+ * 1. The input consists of \n-terminated lines
+ * 2. /-\|+ are used for edges.
+ * 3. <^>v are used for arrowheads.
+ * 4. + can be used to cross-over.
+ * 5. No arrowheads or both-ended arrowheads are shortcuts for "both ways".
+ * 6. Edges can turn with or without a +, by up to 90 degrees.
+ * 7. Edges must go from one node name to another.
+ * 8. Any other text is an edge label which must be next to an edge or
+ *    another label.
+ *
+ * License: BSD-MIT
+ * Example:
+ * // Convert an ASCII graph to Graphviz dot format
+ * #include <ccan/err/err.h>
+ * #include <ccan/grab_file/grab_file.h>
+ * #include <ccan/ungraph/ungraph.h>
+ *
+ * // Just return the name as our node.
+ * static void *add_node(const tal_t *ctx,
+ *                       const char *name,
+ *                       const char **errstr,
+ *                       void *unused)
+ * {
+ *         return (void *)name;
+ * }
+ *
+ * static const char *add_edge(const tal_t *ctx,
+ *                             void *source_node,
+ *                             void *dest_node,
+ *                             bool bidir,
+ *                             const char **labels,
+ *                             void *arg)
+ * {
+ *         printf("%s -> %s;\n", 
+ *                (char *)source_node, (char *)dest_node);
+ *         if (bidir)
+ *                 printf("%s -> %s;\n", 
+ *                        (char *)dest_node, (char *)source_node);
+ *         return NULL;
+ * }
+ *
+ * int main(int argc, char *argv[])
+ * {
+ *         const char *graph = grab_file(NULL, argv[1], NULL), *errmsg;
+ *        printf("digraph %s {\n", argv[1] ? argv[1] : "stdin");
+ *         errmsg = ungraph(NULL, graph, add_node, add_edge, NULL);
+ *         if (errmsg)
+ *                 errx(1, "%s", errmsg);
+ *         printf("}");
+ * }
+ *
+ * Author: Rusty Russell <rusty@rustcorp.com.au>
+ */
+int main(int argc, char *argv[])
+{
+       /* Expect exactly one argument */
+       if (argc != 2)
+               return 1;
+
+       if (strcmp(argv[1], "depends") == 0) {
+               printf("ccan/tal\n");
+               printf("ccan/tal/str\n");
+               printf("ccan/typesafe_cb\n");
+               return 0;
+       }
+
+       return 1;
+}
diff --git a/ccan/ungraph/test/run.c b/ccan/ungraph/test/run.c
new file mode 100644 (file)
index 0000000..a9ae9be
--- /dev/null
@@ -0,0 +1,140 @@
+#include <ccan/ungraph/ungraph.h>
+/* Include the C files directly. */
+#include <ccan/ungraph/ungraph.c>
+#include <ccan/tap/tap.h>
+#include <assert.h>
+
+static void *add_node(const tal_t *ctx,
+                     const char *name,
+                     const char **errstr,
+                     char **out)
+{
+       tal_append_fmt(out, "add_node %s\n", (char *)name);
+       return (void *)tal_steal(ctx, name);
+}
+
+static const char *add_edge(const tal_t *ctx,
+                           void *source_node,
+                           void *dest_node,
+                           bool bidir,
+                           const char **labels,
+                           char **out)
+{
+       tal_append_fmt(out, "add_edge %s-%s bidir=%i\n",
+                      (char *)source_node,
+                      (char *)dest_node,
+                      bidir);
+       for (size_t i = 0; i < tal_count(labels); i++)
+               tal_append_fmt(out, "- label %s\n", labels[i]);
+       return NULL;
+}
+
+int main(void)
+{
+       const tal_t *ctx = tal(NULL, char);
+       char *out = tal_arrz(ctx, char, 1);
+       /* This is how many tests you plan to run */
+       plan_tests(16);
+
+       ok1(ungraph(ctx,
+                   "AAA----->BBB",
+                   add_node, add_edge, &out) == NULL);
+       ok1(strcmp(out,
+                  "add_node AAA\n"
+                  "add_node BBB\n"
+                  "add_edge AAA-BBB bidir=0\n") == 0);
+       
+       out = tal_arrz(ctx, char, 1);
+       ok1(ungraph(ctx,
+                   "AAA<------BBB",
+                   add_node, add_edge, &out) == NULL);
+       ok1(strcmp(out,
+                  "add_node AAA\n"
+                  "add_node BBB\n"
+                  "add_edge BBB-AAA bidir=0\n") == 0);
+       
+       out = tal_arrz(ctx, char, 1);
+       ok1(ungraph(ctx,
+                   "AAA------BBB",
+                   add_node, add_edge, &out) == NULL);
+       ok1(strcmp(out,
+                  "add_node AAA\n"
+                  "add_node BBB\n"
+                  "add_edge AAA-BBB bidir=1\n") == 0);
+
+       out = tal_arrz(ctx, char, 1);
+       ok1(ungraph(ctx,
+                   "AAA<------>BBB",
+                   add_node, add_edge, &out) == NULL);
+       ok1(strcmp(out,
+                  "add_node AAA\n"
+                  "add_node BBB\n"
+                  "add_edge AAA-BBB bidir=1\n") == 0);
+
+       out = tal_arrz(ctx, char, 1);
+       ok1(ungraph(ctx,
+                   "AAA\n"
+                   " ^ \n"
+                   " | \n"
+                   " | \n"
+                   " v \n"
+                   "BBB",
+                   add_node, add_edge, &out) == NULL);
+       ok1(strcmp(out,
+                  "add_node AAA\n"
+                  "add_node BBB\n"
+                  "add_edge AAA-BBB bidir=1\n") == 0);
+       
+       out = tal_arrz(ctx, char, 1);
+       ok1(ungraph(ctx,
+                   "AAA\n"
+                   " / \n"
+                   "| \n"
+                   " \\ \n"
+                   "  v \n"
+                   "  BBB\n",
+                   add_node, add_edge, &out) == NULL);
+       ok1(strcmp(out,
+                  "add_node AAA\n"
+                  "add_node BBB\n"
+                  "add_edge AAA-BBB bidir=0\n") == 0);
+       
+       out = tal_arrz(ctx, char, 1);
+       ok1(ungraph(ctx,
+                   "AAA\n"
+                   " / \n"
+                   "|xyx \n"
+                   " \\ \n"
+                   "  v \n"
+                   "  BBB",
+                   add_node, add_edge, &out) == NULL);
+       ok1(strcmp(out,
+                  "add_node AAA\n"
+                  "add_node BBB\n"
+                  "add_edge AAA-BBB bidir=0\n"
+                  "- label xyx\n") == 0);
+
+       out = tal_arrz(ctx, char, 1);
+       ok1(ungraph(ctx,
+                   " AAA \n"
+                   "  |   \n"
+                   "A-+----B \n"
+                   "  | LABEL  \n"
+                   "  |  xyz\n"
+                   "  v  \n"
+                   " BBB",
+                   add_node, add_edge, &out) == NULL);
+       ok1(strcmp(out,
+                  "add_node AAA\n"
+                  "add_node BBB\n"
+                  "add_node A\n"
+                  "add_node B\n"
+                  "add_edge AAA-BBB bidir=0\n"
+                  "add_edge A-B bidir=1\n"
+                  "- label LABEL\n"
+                  "- label xyz\n") == 0);
+
+       tal_free(ctx);
+       /* This exits depending on whether all tests passed */
+       return exit_status();
+}
diff --git a/ccan/ungraph/ungraph.c b/ccan/ungraph/ungraph.c
new file mode 100644 (file)
index 0000000..ba29d22
--- /dev/null
@@ -0,0 +1,721 @@
+/* MIT (BSD) license - see LICENSE file for details */
+#include <ccan/ungraph/ungraph.h>
+#include <ccan/tal/str/str.h>
+
+struct xy {
+       size_t x, y;
+};
+
+struct text {
+       struct xy xy;
+       size_t width;
+       const char *text;
+       /* If it's a node, this is non-NULL */
+       void *node;
+       /* NULL if none found, edge it one found, self if > 1 */
+       struct edge *nearest_edge;
+};
+
+struct edge {
+       struct text *src, *dst;
+       bool bidir;
+       const char **labels;
+};
+
+/* This means we actually found two "nearest_edge" */
+static struct edge fake_edge;
+
+#define EDGES "+/-\\|"
+#define ARROWS "<^>v"
+
+enum dir {
+       UP,
+       UP_RIGHT,
+       RIGHT,
+       DOWN_RIGHT,
+       DOWN,
+       DOWN_LEFT,
+       LEFT,
+       UP_LEFT,
+       INVALID,
+};
+
+static enum dir opposite_dir(enum dir dir)
+{
+       return (dir + 4) % 8;
+}
+
+static enum dir clockwise(enum dir dir)
+{
+       return (dir + 1) % 8;
+}
+
+static enum dir anticlockwise(enum dir dir)
+{
+       return (dir + 7) % 8;
+}
+
+static enum dir dir_away(const struct text *t, struct xy xy)
+{
+       int xdir, ydir;
+       enum dir dirs[3][3] = {{UP_LEFT, UP, UP_RIGHT},
+                              {LEFT, INVALID, RIGHT},
+                              {DOWN_LEFT, DOWN, DOWN_RIGHT}};
+       
+       if (xy.y < t->xy.y)
+               ydir = -1;
+       else if (xy.y > t->xy.y)
+               ydir = 1;
+       else
+               ydir = 0;
+       if (xy.x >= t->xy.x + t->width)
+               xdir = 1;
+       else if (xy.x < t->xy.x)
+               xdir = -1;
+       else
+               xdir = 0;
+
+       return dirs[ydir+1][xdir+1];
+}
+
+static char line_for_dir(enum dir dir)
+{
+       switch (dir) {
+       case UP:
+       case DOWN:
+               return '|';
+       case UP_RIGHT:
+       case DOWN_LEFT:
+               return '/';
+       case RIGHT:
+       case LEFT:
+               return '-';
+       case DOWN_RIGHT:
+       case UP_LEFT:
+               return '\\';
+       case INVALID:
+               break;
+       }
+       abort();
+}
+
+static char arrow_for_dir(enum dir dir)
+{
+       switch (dir) {
+       case UP:
+       case UP_RIGHT:
+       case UP_LEFT:
+               return '^';
+       case DOWN:
+       case DOWN_RIGHT:
+       case DOWN_LEFT:
+               return 'v';
+       case LEFT:
+               return '<';
+       case RIGHT:
+               return '>';
+       case INVALID:
+               break;
+       }
+       abort();
+}
+
+static struct xy move_in_dir(struct xy xy, enum dir dir)
+{
+       switch (dir) {
+       case UP:
+               xy.y = xy.y - 1;
+               return xy;
+       case DOWN:
+               xy.y = xy.y + 1;
+               return xy;
+       case UP_RIGHT:
+               xy.x = xy.x + 1;
+               xy.y = xy.y - 1;
+               return xy;
+       case DOWN_LEFT:
+               xy.x = xy.x - 1;
+               xy.y = xy.y + 1;
+               return xy;
+       case RIGHT:
+               xy.x = xy.x + 1;
+               return xy;
+       case LEFT:
+               xy.x = xy.x - 1;
+               return xy;
+       case DOWN_RIGHT:
+               xy.x = xy.x + 1;
+               xy.y = xy.y + 1;
+               return xy;
+       case UP_LEFT:
+               xy.x = xy.x - 1;
+               xy.y = xy.y - 1;
+               return xy;
+       case INVALID:
+               break;
+       }
+       abort();
+}
+
+static char *sqc(char **sq, struct xy xy)
+{
+       return &sq[xy.y][xy.x];
+}
+
+/* Try straight ahead first, then a bit to either side, then
+ * finally left and right */
+static struct xy scan_move_next(struct xy xy, enum dir start, enum dir *cur)
+{
+       if (*cur == start)
+               *cur = clockwise(start);
+       else if (*cur == clockwise(start))
+               *cur = anticlockwise(start);
+       else if (*cur == anticlockwise(start))
+               *cur = anticlockwise(anticlockwise(start));
+       else if (*cur == anticlockwise(anticlockwise(start)))
+               *cur = clockwise(clockwise(start));
+       else {
+               *cur = INVALID;
+               return xy;
+       }
+       return move_in_dir(xy, *cur);
+}
+
+static void start_perimeter(struct xy *xyp, enum dir *dirp, struct xy xy)
+{
+       *dirp = RIGHT;
+       xyp->x = xy.x - 1;
+       xyp->y = xy.y - 1;
+}
+
+static void next_perimeter(struct xy *xyp, enum dir *dirp, struct xy xy, size_t width)
+{
+       *xyp = move_in_dir(*xyp, *dirp);
+       if (*dirp == RIGHT && xyp->x == xy.x + width)
+               *dirp = DOWN;
+       else if (*dirp == DOWN && xyp->y == xy.y + 1)
+               *dirp = LEFT;
+       else if (*dirp == LEFT && xyp->x == xy.x - 1)
+               *dirp = UP;
+       else if (*dirp == UP && xyp->y == xy.y - 2)
+               *dirp = INVALID;
+}
+
+/* Useful iterators. */
+#define for_each_scan_dir(xyp, dirp, xy, dir)                  \
+       for (*dirp = dir, *xyp = move_in_dir(xy, *dirp);        \
+            *dirp != INVALID;                                  \
+            *xyp = scan_move_next(xy, dir, dirp))
+
+#define for_each_perimeter(xyp, dirp, xy, width)       \
+       for (start_perimeter(xyp, dirp, xy);            \
+            *dirp != INVALID;                          \
+            next_perimeter(xyp, dirp, xy, width))
+
+/* Canonicalizes str into array of characters, finds text strings. */
+static char **square(const tal_t *ctx,
+                    const char *str,
+                    struct text **texts)
+{
+       size_t width = 0, height = 0;
+       size_t line_len = 0;
+       char **sq;
+       struct text *cur_text;
+       size_t strlen;
+
+       *texts = tal_arr(ctx, struct text, 0);
+
+       strlen = 0;
+       for (size_t i = 0; str[i]; i++) {
+               if (str[i] == '\n') {
+                       height++;
+                       line_len = 0;
+               } else {
+                       line_len++;
+                       if (line_len > width)
+                               width = line_len;
+               }
+               strlen++;
+       }
+
+       /* If didn't end in \n, it's implied */
+       if (line_len != 0) {
+               height++;
+               strlen++;
+       }
+
+       /* For analysis simplicity, create a blank border. */
+       sq = tal_arr(ctx, char *, height + 2);
+       for (size_t i = 0; i < height + 2; i++) {
+               sq[i] = tal_arr(sq, char, width + 2);
+               memset(sq[i], ' ', width + 2);
+       }
+
+       /* Copy across and find text */
+       cur_text = NULL;
+       width = height = 1;
+       for (size_t i = 0; i < strlen; i++) {
+               bool end_text;
+               bool eol;
+
+               eol = (str[i] == '\n' || str[i] == '\0');
+               if (!eol)
+                       sq[height][width] = str[i];
+
+               /* v by itself handled separately below */
+               if (strchr(EDGES ARROWS "\n", str[i]) && str[i] != 'v') {
+                       end_text = (cur_text != NULL);
+               } else if (cur_text) {
+                       /* Two spaces ends text */
+                       end_text = (str[i] == ' ' && str[i-1] == ' ') || eol;
+               } else if (str[i] != ' ') {
+                       size_t num_texts = tal_count(*texts);
+                       tal_resize(texts, num_texts+1);
+                       cur_text = &(*texts)[num_texts];
+                       cur_text->xy.x = width;
+                       cur_text->xy.y = height;
+                       cur_text->width = 0;
+                       cur_text->node = NULL;
+                       cur_text->nearest_edge = NULL;
+                       end_text = false;
+               } else
+                       end_text = false;
+
+               if (end_text) {
+                       /* Trim final space */
+                       if (sq[cur_text->xy.y][cur_text->xy.x + cur_text->width-1] == ' ')
+                               cur_text->width--;
+                       /* Ignore lone 'v' */
+                       if (cur_text->width == 1 && sq[cur_text->xy.y][cur_text->xy.x] == 'v')
+                               tal_resize(texts, tal_count(*texts)-1);
+                       else {
+                               cur_text->text = tal_strndup(ctx, &sq[cur_text->xy.y][cur_text->xy.x],
+                                                            cur_text->width);
+                       }
+                       cur_text = NULL;
+               }
+
+               if (cur_text)
+                       cur_text->width++;
+               if (eol) {
+                       height++;
+                       width = 1;
+               } else
+                       width++;
+       }
+
+       return sq;
+}
+
+/* If text was not previously a node, it is now! */
+static const char *text_now_node(const tal_t *ctx,
+                                char **sq,
+                                struct text *text,
+                                void *(*add_node)(const tal_t *ctx,
+                                                  const char *name,
+                                                  const char **errstr,
+                                                  void *arg),
+                                void *arg)
+{
+       const char *err;
+
+       /* Already a node? */
+       if (text->node)
+               return NULL;
+
+       text->node = add_node(ctx, text->text, &err, arg);
+       if (!text->node)
+               return err;
+       return NULL;
+}
+
+static bool correct_line_char(char c, enum dir dir, enum dir *newdir)
+{
+       if (c == line_for_dir(dir)) {
+               *newdir = dir;
+               return true;
+       } else if (c == line_for_dir(anticlockwise(dir))) {
+               *newdir = anticlockwise(dir);
+               return true;
+       } else if (c == line_for_dir(clockwise(dir))) {
+               *newdir = clockwise(dir);
+               return true;
+       }
+       return false;
+}
+
+static bool seek_line(char **sq, struct xy *xy, enum dir *dir)
+{
+       struct xy scan;
+       enum dir scandir;
+
+       for_each_scan_dir(&scan, &scandir, *xy, *dir) {
+               if (correct_line_char(*sqc(sq, scan), scandir, &scandir))
+                       goto found;
+               /* + in front always works */
+               if (*dir == scandir && *sqc(sq, scan) == '+')
+                       goto found;
+       }
+       return false;
+
+found:
+       *xy = scan;
+       *dir = scandir;
+       return true;
+}
+
+static bool seek_arrowhead(char **sq, struct xy *xy, enum dir *dir)
+{
+       struct xy scan;
+       enum dir scandir;
+
+       for_each_scan_dir(&scan, &scandir, *xy, *dir) {
+               if (strchr(ARROWS, *sqc(sq, scan))) {
+                       *xy = scan;
+                       *dir = scandir;
+                       return true;
+               }
+       }
+       return false;
+}
+
+static struct text *in_text(struct text *texts, struct xy xy)
+{
+       for (size_t i = 0; i < tal_count(texts); i++) {
+               if (texts[i].xy.y != xy.y)
+                       continue;
+               if (xy.x >= texts[i].xy.x + texts[i].width)
+                       continue;
+               if (xy.x < texts[i].xy.x)
+                       continue;
+               return texts + i;
+       }
+       return NULL;
+}
+
+static struct text *seek_text(struct text *texts,
+                             struct xy xy, enum dir dir)
+{
+       struct xy scan;
+       enum dir scandir;
+
+       for_each_scan_dir(&scan, &scandir, xy, dir) {
+               struct text *t = in_text(texts, scan);
+               if (t)
+                       return t;
+       }
+       return NULL;
+}
+
+static void erase_line(char **sq,
+                      struct xy xy,
+                      enum dir dir,
+                      enum dir prev_dir)
+{
+       char c = ' ';
+
+       /* If we go straight through a +, convert for crossover */
+       if (prev_dir == dir && *sqc(sq, xy) == '+') {
+               if (dir == UP || dir == DOWN)
+                       c = '-';
+               if (dir == LEFT || dir == RIGHT)
+                       c = '|';
+       }
+       *sqc(sq, xy) = c;
+}
+
+static bool in_nearby(struct text **nearby, const struct text *t)
+{
+       for (size_t i = 0; i < tal_count(nearby); i++) {
+               if (nearby[i] == t)
+                       return true;
+       }
+       return false;
+}
+
+static void add_nearby(struct text ***nearby,
+                      struct text *texts,
+                      struct xy xy)
+{
+       struct xy perim;
+       enum dir pdir;
+       size_t n = tal_count(*nearby);
+
+       for_each_perimeter(&perim, &pdir, xy, 1) {
+               struct text *t = in_text(texts, perim);
+               if (!t)
+                       continue;
+               /* Don't care if it's already a node */
+               if (t->node)
+                       continue;
+               if (in_nearby(*nearby, t))
+                       continue;
+               tal_resize(nearby, n+1);
+               (*nearby)[n++] = t;
+       }
+}
+
+/* Clears lines as it goes. */
+static struct text *follow_line(char **sq,
+                               struct text *texts,
+                               struct xy xy,
+                               enum dir dir,
+                               bool *arrow_src,
+                               bool *arrow_dst,
+                               bool *dangling,
+                               struct text ***nearby)
+{
+       char expect_arrow = arrow_for_dir(opposite_dir(dir));
+       enum dir prev_dir;
+
+       *nearby = tal_arr(sq, struct text *, 0);
+
+       if (*sqc(sq, xy) == expect_arrow) {
+               *arrow_src = true;
+       } else if (*sqc(sq, xy) == line_for_dir(dir)) {
+               *arrow_src = false;
+       } else if (*sqc(sq, xy) == line_for_dir(anticlockwise(dir))) {
+               *arrow_src = false;
+               dir = anticlockwise(dir);
+       } else if (*sqc(sq, xy) == line_for_dir(clockwise(dir))) {
+               *arrow_src = false;
+               dir = clockwise(dir);
+       } else {
+               *dangling = false;
+               /* No arrow is fine. */
+               return NULL;
+       }
+
+       erase_line(sq, xy, dir, INVALID);
+       add_nearby(nearby, texts, xy);
+
+       *arrow_dst = false;
+       prev_dir = dir;
+       for (;;) {
+               /* Try to continue line */
+               if (!*arrow_dst && seek_line(sq, &xy, &dir)) {
+                       erase_line(sq, xy, dir, prev_dir);
+                       add_nearby(nearby, texts, xy);
+                       prev_dir = dir;
+                       continue;
+               }
+               /* Look for arrow */
+               if (!*arrow_dst && seek_arrowhead(sq, &xy, &dir)) {
+                       erase_line(sq, xy, dir, prev_dir);
+                       add_nearby(nearby, texts, xy);
+                       *arrow_dst = true;
+                       prev_dir = dir;
+                       continue;
+               }
+               break;
+       }
+
+       /* Must be in text! */
+       *dangling = true;
+       return seek_text(texts, xy, dir);
+}
+
+static const char *try_create_edge(const tal_t *ctx,
+                                  char **sq,
+                                  struct text *texts,
+                                  struct xy xy,
+                                  struct text *src,
+                                  void *(*add_node)(const tal_t *ctx,
+                                                    const char *name,
+                                                    const char **errstr,
+                                                    void *arg),
+                                  void *arg,
+                                  struct edge **edge)
+{
+       struct text *dst;
+       bool arrow_src, arrow_dst, dangling;
+       struct text **nearby;
+       const char *err;
+
+       *edge = NULL;
+       if (in_text(texts, xy))
+               return NULL;
+
+       dst = follow_line(sq, texts, xy, dir_away(src, xy), &arrow_src, &arrow_dst, &dangling, &nearby);
+       if (!dst) {
+               if (dangling)
+                       return tal_fmt(ctx, "Found dangling arrow at (%zu,%zu)", xy.x-1, xy.y-1);
+               return NULL;
+       }
+
+       /* If you weren't a node before, you are now! */
+       err = text_now_node(ctx, sq, src, add_node, arg);
+       if (err)
+               return err;
+       err = text_now_node(ctx, sq, dst, add_node, arg);
+       if (err)
+               return err;
+
+       /* No arrows equiv to both arrows */
+       if (!arrow_src && !arrow_dst)
+               arrow_src = arrow_dst = true;
+
+       *edge = tal(NULL, struct edge);
+       if (arrow_dst) {
+               (*edge)->src = src;
+               (*edge)->dst = dst;
+               (*edge)->bidir = arrow_src;
+       } else {
+               (*edge)->src = dst;
+               (*edge)->dst = src;
+               (*edge)->bidir = false;
+       }
+       (*edge)->labels = tal_arr(*edge, const char *, 0);
+
+       /* Now record any texts it passed by, in case they're labels */
+       for (size_t i = 0; i < tal_count(nearby); i++) {
+               /* We might have just made it a node */
+               if (nearby[i]->node)
+                       continue;
+               /* Already has an edge?  Mark it as near two, to error
+                * later if it's a label */
+               if (nearby[i]->nearest_edge)
+                       nearby[i]->nearest_edge = &fake_edge;
+               else
+                       nearby[i]->nearest_edge = *edge;
+       }
+               
+       return NULL;
+}
+
+static const char *scan_for_unused(const tal_t *ctx,
+                                  struct text *texts,
+                                  char **sq)
+{
+       struct xy xy;
+       for (xy.y = 0; xy.y < tal_count(sq); xy.y++) {
+               for (xy.x = 0; xy.x < tal_count(sq[xy.y]); xy.x++) {
+                       if (in_text(texts, xy))
+                               continue;
+                       if (*sqc(sq,xy) != ' ')
+                               return tal_fmt(ctx, "Unused '%c' at (%zu,%zu)",
+                                              *sqc(sq, xy), xy.x-1, xy.y-1);
+               }
+       }
+       return NULL;
+}
+
+static void add_label(struct edge *edge, const struct text *label)
+{
+       size_t n = tal_count(edge->labels);
+       tal_resize(&edge->labels, n+1);
+       edge->labels[n] = label->text;
+}
+       
+const char *ungraph_(const tal_t *ctx,
+                    const char *str,
+                    void *(*add_node)(const tal_t *ctx,
+                                      const char *name,
+                                      const char **errstr,
+                                      void *arg),
+                    const char *(*add_edge)(const tal_t *ctx,
+                                            void *source_node,
+                                            void *dest_node,
+                                            bool bidir,
+                                            const char **labels,
+                                            void *arg),
+                    void *arg)
+{
+       /* To hold all our temporaries! */
+       const tal_t *sub = tal(ctx, char);
+       char **sq;
+       struct text *texts, *remaining_label;
+       const char *err;
+       bool progress;
+       struct edge **edges = tal_arr(sub, struct edge *, 0);
+       size_t num_edges = 0;
+
+       /* We create canonical square, find texts. */
+       sq = square(sub, str, &texts);
+
+       /* Now search for arrows around each text, cleaning
+        * as we go! */
+       for (size_t i = 0; i < tal_count(texts); i++) {
+               struct xy perim;
+               enum dir pdir;
+               struct text *t = &texts[i];
+
+               for_each_perimeter(&perim, &pdir, t->xy, t->width) {
+                       struct edge *edge;
+                       err = try_create_edge(ctx, sq, texts, perim, t, add_node, arg, &edge);
+                       if (err)
+                               goto fail;
+                       if (edge) {
+                               tal_resize(&edges, num_edges+1);
+                               edges[num_edges++] = tal_steal(edges, edge);
+                       }
+               }
+       }
+
+       /* Now attach any remaining labels */
+       for (size_t i = 0; i < tal_count(texts); i++) {
+               struct text *t = &texts[i];
+
+               if (t->node)
+                       continue;
+               if (t->nearest_edge == &fake_edge) {
+                       err = tal_fmt(ctx, "Label at (%zu,%zu) near more than one edge",
+                                     t->xy.x-1, t->xy.y-1);
+                       goto fail;
+               }
+               if (t->nearest_edge)
+                       add_label(t->nearest_edge, t);
+       }
+
+       /* Any remaining labels must be attached to already-attached labels */
+       do {
+               progress = false;
+               remaining_label = NULL;
+
+               for (size_t i = 0; i < tal_count(texts); i++) {
+                       struct xy perim;
+                       enum dir pdir;
+                       struct text *t = &texts[i];
+
+                       if (t->node || t->nearest_edge)
+                               continue;
+
+                       remaining_label = t;
+                       for_each_perimeter(&perim, &pdir, t->xy, t->width) {
+                               struct text *neighbor = in_text(texts, perim);
+                               if (!neighbor || neighbor->node || !neighbor->nearest_edge)
+                                       continue;
+                               t->nearest_edge = neighbor->nearest_edge;
+                               add_label(t->nearest_edge, t);
+                               progress = true;
+                               break;
+                       }
+               }
+       } while (progress);
+
+       if (remaining_label) {
+               err = tal_fmt(ctx, "Label at (%zu,%zu) not near any edge",
+                             remaining_label->xy.x-1,
+                             remaining_label->xy.y-1);
+               goto fail;
+       }
+
+       err = scan_for_unused(ctx, texts, sq);
+       if (err)
+               goto fail;
+
+       /* Now add edges, complete with labels */
+       for (size_t i = 0; i < tal_count(edges); i++) {
+               err = add_edge(ctx, edges[i]->src->node, edges[i]->dst->node,
+                              edges[i]->bidir, edges[i]->labels, arg);
+               if (err)
+                       goto fail;
+       }
+       
+       tal_free(sub);
+       return NULL;
+
+fail:
+       tal_free(sub);
+       return err;
+}
diff --git a/ccan/ungraph/ungraph.h b/ccan/ungraph/ungraph.h
new file mode 100644 (file)
index 0000000..8480b35
--- /dev/null
@@ -0,0 +1,53 @@
+/* MIT (BSD) license - see LICENSE file for details */
+#ifndef CCAN_UNGRAPH_H
+#define CCAN_UNGRAPH_H
+#include <ccan/tal/tal.h>
+#include <ccan/typesafe_cb/typesafe_cb.h>
+
+/**
+ * ungraph: extract a graph from an ASCII graph.
+ * @ctx: context for callbacks, and/or returned errstr.
+ * @str: a string containing a graph.
+ * @add_node: callback for a new node, returns node.
+ * @add_edge: callback for a new edge, with tal_count(labels).
+ * @arg: callback argument.
+ *
+ * On success, returns NULL.  On failure, returns some error message
+ * (allocated off @ctx, or returned from callbacks).
+ *
+ * If @add_node returns NULL, it must set @errstr. @add_edge
+ * returns the error message directly.
+ *
+ * @add_node and @add_edge can tal_steal the name/labels if they want,
+ * otherwise they will be freed.
+ */
+const char *ungraph_(const tal_t *ctx,
+                    const char *str,
+                    void *(*add_node)(const tal_t *ctx,
+                                      const char *name,
+                                      const char **errstr,
+                                      void *arg),
+                    const char *(*add_edge)(const tal_t *ctx,
+                                            void *source_node,
+                                            void *dest_node,
+                                            bool bidir,
+                                            const char **labels,
+                                            void *arg),
+                    void *arg);
+
+#define ungraph(ctx, str, add_node, add_edge, arg)                     \
+       ungraph_((ctx), (str),                                          \
+                typesafe_cb_preargs(void *, void *,                    \
+                                    (add_node), (arg),                 \
+                                    const tal_t *,                     \
+                                    const char *,                      \
+                                    const char **errstr),              \
+                typesafe_cb_preargs(const char *, void *,              \
+                                    (add_edge), (arg),                 \
+                                    const tal_t *,                     \
+                                    void *,                            \
+                                    void *,                            \
+                                    bool,                              \
+                                    const char **),                    \
+                arg)
+#endif /* CCAN_UNGRAPH_H */
index 8820f17410293fcb9763b63272f41d5702d8ac13..9e805a3a387cc4c083aeaadce450c8baa53f854b 100644 (file)
@@ -55,7 +55,7 @@ static inline uint16_t version_minor(const struct version v) {
  */
 static inline struct version version(uint16_t major, uint16_t minor)
 {
-       struct version v = { ._v = major << 16 | minor };
+       struct version v = { ._v = (uint32_t)major << 16 | minor };
        return v;
 }
 
index f3d1a5ba13b36354d23bdf309ae28d8c75617bd3..3f88bbcdf830d0ca7afbd9e4214936e6940a1f9d 100644 (file)
@@ -151,11 +151,12 @@ static void reap_output(void)
                        int old_len, len;
                        /* This length includes nul terminator! */
                        old_len = tal_count(c->output);
-                       tal_resize(&c->output, old_len + 1024);
-                       len = read(c->output_fd, c->output + old_len - 1, 1024);
+                       tal_resize(&c->output, old_len + 65536);
+                       len = read(c->output_fd, c->output + old_len - 1, 65536);
                        if (len < 0)
                                err(1, "Reading from async command");
-                       tal_resize(&c->output, old_len + len);
+                       if (len != 65536)
+                               tal_resize(&c->output, old_len + len);
                        c->output[old_len + len - 1] = '\0';
                        if (len == 0) {
                                struct rusage ru;
index f830cbca14eb3eb3a2f4070fc6564674a0428d2d..7d8f6b095de4b6e615591b6fb37319a20fe603a3 100644 (file)
@@ -197,7 +197,7 @@ static const struct test base_tests[] = {
          "return __builtin_clzll(1) == (sizeof(long long)*8 - 1) ? 0 : 1;" },
        { "HAVE_BUILTIN_CTZ", "__builtin_ctz support",
          "INSIDE_MAIN", NULL, NULL,
-         "return __builtin_ctz(1 << (sizeof(int)*8 - 1)) == (sizeof(int)*8 - 1) ? 0 : 1;" },
+         "return __builtin_ctz(1U << (sizeof(int)*8 - 1)) == (sizeof(int)*8 - 1) ? 0 : 1;" },
        { "HAVE_BUILTIN_CTZL", "__builtin_ctzl support",
          "INSIDE_MAIN", NULL, NULL,
          "return __builtin_ctzl(1UL << (sizeof(long)*8 - 1)) == (sizeof(long)*8 - 1) ? 0 : 1;" },
@@ -471,7 +471,7 @@ static const struct test base_tests[] = {
          "#include <stddef.h>\n"
          "#include <ucontext.h>\n"
          "static int worked = 0;\n"
-         "static char stack[1024];\n"
+         "static char stack[8192];\n"
          "static ucontext_t a, b;\n"
          "static void fn(void *p, void *q) {\n"
          "     void *cp = &worked;\n"
index da9ed0a3fad62bdd3330285ae67751ef8084c7d2..da3e00cd73ba7088981d7a40ad3b995c4ad48e2b 100644 (file)
@@ -96,10 +96,11 @@ char *read_config_header(const char *ccan_dir, bool verbose)
        char *config_header;
 
        config_header = grab_file(NULL, fname);
-       tal_free(fname);
 
-       if (!config_header)
+       if (!config_header) {
+               tal_free(fname);
                return NULL;
+       }
 
        lines = tal_strsplit(config_header, config_header, "\n", STR_EMPTY_OK);
        for (i = 0; i < tal_count(lines) - 1; i++) {
@@ -129,5 +130,6 @@ char *read_config_header(const char *ccan_dir, bool verbose)
                                       fname, cflags);
                }
        }
+       tal_free(fname);
        return config_header;
 }