-/* 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;
}
/* Set a char *. */
char *opt_set_charp(const char *arg, char **p)
{
- *p = (char *)arg;
+ *p = cast_const(char *, arg);
return NULL;
}
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, size_t len, const float *f)
+{
+ double d = *f;
+ opt_show_doubleval(buf, len, &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, size_t len, const double *d)
+{
+ snprintf(buf, 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);
}
-void opt_show_bool(char buf[OPT_SHOW_LEN], const bool *b)
+void 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);
}
-void opt_show_invbool(char buf[OPT_SHOW_LEN], const bool *b)
+void 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);
}
-void opt_show_charp(char buf[OPT_SHOW_LEN], char *const *p)
+void 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;
+ 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';
+ }
+ else {
+ strncpy(buf, "(nil)", len);
+ }
}
/* Show an integer value, various forms. */
-void opt_show_intval(char buf[OPT_SHOW_LEN], const int *i)
+void opt_show_intval(char *buf, size_t len, const int *i)
{
- snprintf(buf, OPT_SHOW_LEN, "%i", *i);
+ snprintf(buf, len, "%i", *i);
}
-void opt_show_uintval(char buf[OPT_SHOW_LEN], const unsigned int *ui)
+void opt_show_uintval(char *buf, size_t len, const unsigned int *ui)
{
- snprintf(buf, OPT_SHOW_LEN, "%u", *ui);
+ snprintf(buf, len, "%u", *ui);
}
-void opt_show_longval(char buf[OPT_SHOW_LEN], const long *l)
+void opt_show_longval(char *buf, size_t len, const long *l)
{
- snprintf(buf, OPT_SHOW_LEN, "%li", *l);
+ snprintf(buf, len, "%li", *l);
}
-void opt_show_ulongval(char buf[OPT_SHOW_LEN], const unsigned long *ul)
+void opt_show_ulongval(char *buf, size_t len, const unsigned long *ul)
{
- snprintf(buf, OPT_SHOW_LEN, "%lu", *ul);
+ snprintf(buf, len, "%lu", *ul);
}
/* a helper function that multiplies out an argument's kMGTPE suffix in the
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)
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++){
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++){
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)
+void 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);
}
-void opt_show_longval_bi(char buf[OPT_SHOW_LEN], const long *x)
+void 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);
}
-void opt_show_longlongval_bi(char buf[OPT_SHOW_LEN], const long long *x)
+void 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);
}
/* _bi, unsigned */
-void opt_show_uintval_bi(char buf[OPT_SHOW_LEN], const unsigned int *x)
+void 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);
}
-void opt_show_ulongval_bi(char buf[OPT_SHOW_LEN], const unsigned long *x)
+void 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);
}
-void opt_show_ulonglongval_bi(char buf[OPT_SHOW_LEN], const unsigned long long *x)
+void 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);
}
/* _si, signed */
-void opt_show_intval_si(char buf[OPT_SHOW_LEN], const int *x)
+void 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);
}
-void opt_show_longval_si(char buf[OPT_SHOW_LEN], const long *x)
+void 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);
}
-void opt_show_longlongval_si(char buf[OPT_SHOW_LEN], const long long *x)
+void 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);
}
/* _si, unsigned */
-void opt_show_uintval_si(char buf[OPT_SHOW_LEN], const unsigned int *x)
+void 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);
}
-void opt_show_ulongval_si(char buf[OPT_SHOW_LEN], const unsigned long *x)
+void 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);
}
-void opt_show_ulonglongval_si(char buf[OPT_SHOW_LEN], const unsigned long long *x)
+void 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);
}