]> git.ozlabs.org Git - ccan/blobdiff - ccan/opt/helpers.c
base64: fix for unsigned chars (e.g. ARM).
[ccan] / ccan / opt / helpers.c
index 53fb0158827aca291e5ce39ff5566da60f49c8ec..df7ee6bb1f20cf791fe82525393e7c809b6f7afb 100644 (file)
@@ -1,19 +1,22 @@
-/* Licensed under GPLv3+ - see LICENSE file for details */
+/* Licensed under GPLv2+ - see LICENSE file for details */
 #include <ccan/opt/opt.h>
+#include <ccan/cast/cast.h>
+#include <inttypes.h>
 #include <string.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <stdio.h>
 #include <limits.h>
 #include "private.h"
+#include <float.h>
 
 /* Upper bound to sprintf this simple type?  Each 3 bits < 1 digit. */
 #define CHAR_SIZE(type) (((sizeof(type)*CHAR_BIT + 2) / 3) + 1)
 
-/* FIXME: asprintf module? */
 static char *arg_bad(const char *fmt, const char *arg)
 {
-       char *str = malloc(strlen(fmt) + strlen(arg));
+       char *str = opt_alloc.alloc(strlen(fmt) + strlen(arg));
        sprintf(str, fmt, arg);
        return str;
 }
@@ -52,7 +55,7 @@ char *opt_set_invbool_arg(const char *arg, bool *b)
 /* Set a char *. */
 char *opt_set_charp(const char *arg, char **p)
 {
-       *p = (char *)arg;
+       *p = cast_const(char *, arg);
        return NULL;
 }
 
@@ -66,8 +69,8 @@ char *opt_set_intval(const char *arg, int *i)
        if (err)
                return err;
        *i = l;
-       /* Beware truncation... */
-       if (*i != l)
+       /* Beware truncation, but don't generate untestable code. */
+       if (sizeof(*i) != sizeof(l) && *i != l)
                return arg_bad("value '%s' does not fit into an integer", arg);
        return err;
 }
@@ -113,66 +116,142 @@ char *opt_set_ulongval(const char *arg, unsigned long *ul)
        return NULL;
 }
 
+char *opt_set_floatval(const char *arg, float *f)
+{
+       double d;
+       char *err;
+
+       err = opt_set_doubleval(arg, &d);
+       if (err)
+               return err;
+
+       *f = d;
+
+       /*allow true infinity via --foo=INF, while avoiding isinf() from math.h
+         because it wasn't standard 25 years ago.*/
+       double inf = 1e300 * 1e300; /*direct 1e600 annoys -Woverflow*/
+       if ((d > FLT_MAX || d < -FLT_MAX) && d != inf && d != -inf)
+               return arg_bad("'%s' is out of range for a 32 bit float", arg);
+       if (d != 0 && *f == 0)
+               return arg_bad("'%s' is out of range (truncated to zero)", arg);
+
+       return NULL;
+}
+
+bool opt_show_floatval(char *buf, size_t len, const float *f)
+{
+       double d = *f;
+       opt_show_doubleval(buf, len, &d);
+       return true;
+}
+
+char *opt_set_doubleval(const char *arg, double *d)
+{
+       char *endp;
+
+       /* This is how the manpage says to do it.  Yech. */
+       errno = 0;
+       /* Don't assume strtof */
+       *d = strtod(arg, &endp);
+       if (*endp || !arg[0])
+               return arg_bad("'%s' is not a number", arg);
+       if (errno)
+               return arg_bad("'%s' is out of range", arg);
+
+       return NULL;
+}
+
+bool opt_show_doubleval(char *buf, size_t len, const double *d)
+{
+       snprintf(buf, len, "%f", *d);
+       return true;
+}
+
 char *opt_inc_intval(int *i)
 {
        (*i)++;
        return NULL;
 }
 
+char *opt_dec_intval(int *i)
+{
+       (*i)--;
+       return NULL;
+}
+
 /* Display version string. */
 char *opt_version_and_exit(const char *version)
 {
        printf("%s\n", version);
+       /* Don't have valgrind complain! */
+       opt_free_table();
        exit(0);
 }
 
 char *opt_usage_and_exit(const char *extra)
 {
-       printf("%s", opt_usage(opt_argv0, extra));
+       char *usage = opt_usage(opt_argv0, extra);
+       printf("%s", usage);
+       /* Don't have valgrind complain! */
+       opt_alloc.free(usage);
+       opt_free_table();
        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)
 {
-       size_t len = strlen(*p);
-       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';
+       if (*p) {
+               size_t plen = strlen(*p);
+               if (len < 2)
+                       return false;
+               buf[0] = '"';
+               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
@@ -186,9 +265,10 @@ static char *set_llong_with_suffix(const char *arg, long long *ll,
                                   const long long base)
 {
        char *endp;
-       if (!arg[0])
+       if (!arg[0]){
+               *ll = 0;
                return arg_bad("'%s' (an empty string) is not a number", arg);
-
+       }
        errno = 0;
        *ll = strtoll(arg, &endp, 0);
        if (errno)
@@ -258,7 +338,8 @@ static char * set_long_with_suffix(const char *arg, long *l, const long base)
                return err;
 
        *l = ll;
-       if (*l != ll)
+       /* Beware truncation, but don't generate untestable code. */
+       if (sizeof(*l) != sizeof(ll) && *l != ll)
                return arg_bad("value '%s' does not fit into a long", arg);
        return NULL;
 }
@@ -272,7 +353,8 @@ static char * set_ulong_with_suffix(const char *arg, unsigned long *ul, const lo
        if (ll < 0)
                return arg_bad("'%s' is negative but destination is unsigned", arg);
        *ul = ll;
-       if (*ul != ll)
+       /* Beware truncation, but don't generate untestable code. */
+       if (sizeof(*ul) != sizeof(ll) && *ul != ll)
                return arg_bad("value '%s' does not fit into an unsigned long", arg);
        return NULL;
 }
@@ -375,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++){
@@ -392,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, "%lld", ll);
+               snprintf(buf, len, "%"PRId64, (int64_t)ll);
        else
-               snprintf(buf, OPT_SHOW_LEN, "%lld%c", 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++){
@@ -414,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, "%llu", ull);
+               snprintf(buf, len, "%"PRIu64, (uint64_t)ull);
        else
-               snprintf(buf, OPT_SHOW_LEN, "%llu%c", 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;
 }