X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Fopt%2Fhelpers.c;h=f247301cd7a2ba236871f8327c56a79ea144509f;hb=54f85c236ad6f04734cda522ffb78bce7be824bf;hp=dfeb4e2e790a553173830d039ae84b8026df2fa8;hpb=ac9d55d8c5af9697be8c4dd4f27de61e3cb8bf95;p=ccan diff --git a/ccan/opt/helpers.c b/ccan/opt/helpers.c index dfeb4e2e..f247301c 100644 --- a/ccan/opt/helpers.c +++ b/ccan/opt/helpers.c @@ -1,11 +1,15 @@ -/* Licensed under GPLv3+ - see LICENSE file for details */ +/* Licensed under GPLv2+ - see LICENSE file for details */ #include +#include +#include #include +#include #include #include #include #include #include "private.h" +#include /* Upper bound to sprintf this simple type? Each 3 bits < 1 digit. */ #define CHAR_SIZE(type) (((sizeof(type)*CHAR_BIT + 2) / 3) + 1) @@ -52,7 +56,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; } @@ -113,22 +117,83 @@ 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; +} + +void opt_show_floatval(char buf[OPT_SHOW_LEN], const float *f) +{ + double d = *f; + opt_show_doubleval(buf, &d); +} + +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; +} + +void opt_show_doubleval(char buf[OPT_SHOW_LEN], const double *d) +{ + snprintf(buf, OPT_SHOW_LEN, "%f", *d); +} + 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); } @@ -144,14 +209,19 @@ void opt_show_invbool(char buf[OPT_SHOW_LEN], const bool *b) void opt_show_charp(char buf[OPT_SHOW_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 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'; + } + else { + strncpy(buf, "(nil)", OPT_SHOW_LEN); + } } /* Show an integer value, various forms. */ @@ -186,9 +256,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 +329,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 +344,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; } @@ -392,9 +465,9 @@ 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, OPT_SHOW_LEN, "%"PRId64, (int64_t)ll); else - snprintf(buf, OPT_SHOW_LEN, "%lld%c", ll, suffixes[i - 1]); + snprintf(buf, OPT_SHOW_LEN, "%"PRId64"%c", (int64_t)ll, suffixes[i - 1]); } static void show_ullong_with_suffix(char buf[OPT_SHOW_LEN], unsigned long long ull, @@ -414,9 +487,9 @@ 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, OPT_SHOW_LEN, "%"PRIu64, (uint64_t)ull); else - snprintf(buf, OPT_SHOW_LEN, "%llu%c", ull, suffixes[i - 1]); + snprintf(buf, OPT_SHOW_LEN, "%"PRIu64"%c", (uint64_t)ull, suffixes[i - 1]); } /* _bi, signed */