Packages

Native Elixir wrapper for the Scrypt KDF

Current section

Files

Jump to
scrypt_elixir_copy scrypt libcperciva util parsenum.h
Raw

scrypt/libcperciva/util/parsenum.h

#ifndef _PARSENUM_H_
#define _PARSENUM_H_
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
/* Handle compiler warnings about implicit variable conversion in PARSENUM. */
#ifdef __clang__
/* Disable clang warnings. */
#define PARSENUM_PROLOGUE \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") \
_Pragma("clang diagnostic ignored \"-Wfloat-conversion\"") \
_Pragma("clang diagnostic ignored \"-Wsign-conversion\"") \
_Pragma("clang diagnostic ignored \"-Wshorten-64-to-32\"") \
_Pragma("clang diagnostic ignored \"-Wconversion\"")
/* Enable clang warnings for code outside of PARSENUM. */
#define PARSENUM_EPILOGUE \
_Pragma("clang diagnostic pop")
/* Other compilers don't need any special handling */
#else
#define PARSENUM_PROLOGUE /* NOTHING */
#define PARSENUM_EPILOGUE /* NOTHING */
#endif /* !__clang__ */
/* Print a message before assert(). */
#define ASSERT_FAIL(s) \
( \
fprintf(stderr, "Assertion failed: " s \
", function %s, file %s, line %d\n", \
__func__, __FILE__, __LINE__), \
abort() \
)
/**
* PARSENUM(x, s, min, max):
* Parse the string ${s} according to the type of the unsigned integer, signed
* integer, or floating-point number variable ${x}. If the string consists of
* optional whitespace followed by a number (and nothing else) and the numeric
* interpretation of the number is between ${min} and ${max} inclusive, store
* the value into ${x}, set errno to zero, and return zero. Otherwise, return
* nonzero with an unspecified value of ${x} and errno set to EINVAL or ERANGE
* as appropriate.
*
* For floating-point and unsigned integer variables ${x}, this can also be
* invoked as PARSENUM(x, s), in which case the minimum and maximum values are
* set to +/- infinity or the limits of the unsigned integer type.
*/
#define PARSENUM2(x, s) \
PARSENUM_EX4(x, s, 0, 0, "PARSENUM")
#define PARSENUM4(x, s, min, max) \
PARSENUM_EX6(x, s, min, max, 0, 0, "PARSENUM")
/* Magic to select which version of PARSENUM to use. */
#define PARSENUM(...) PARSENUM_(PARSENUM_COUNT(__VA_ARGS__))(__VA_ARGS__)
#define PARSENUM_(N) PARSENUM__(N)
#define PARSENUM__(N) PARSENUM ## N
#define PARSENUM_COUNT(...) PARSENUM_COUNT_(__VA_ARGS__, 4, 3, 2, 1)
#define PARSENUM_COUNT_(_1, _2, _3, _4, N, ...) N
/**
* PARSENUM_EX(x, s, min, max, base, trailing):
* Parse the string ${s} according to the type of the unsigned integer or
* signed integer variable ${x}, in the specified ${base}. If the string
* consists of optional whitespace followed by a number (and nothing else) and
* the numeric interpretation of the number is between ${min} and ${max}
* inclusive, store the value into ${x}, set errno to zero, and return zero.
* Otherwise, return nonzero with an unspecified value of ${x} and errno set
* to EINVAL or ERANGE as appropriate. The check for trailing characters (and
* EINVAL if they are found) is disabled if ${trailing} is non-zero.
*
* For an unsigned integer variable ${x}, this can also be invoked as
* PARSENUM_EX(x, s, base), in which case the minimum and maximum values are
* set to the limits of the unsigned integer type.
*
* For a floating-point variable ${x}, the ${base} must be 0.
*/
#define PARSENUM_EX4(x, s, base, trailing, _define_name) \
( \
PARSENUM_PROLOGUE \
errno = 0, \
(((*(x)) = 1, (*(x)) /= 2) > 0) ? \
(((base) == 0) ? \
((*(x)) = parsenum_float((s), \
(double)-INFINITY, \
(double)INFINITY, (trailing))) : \
(ASSERT_FAIL(_define_name " applied to" \
" float with base != 0"), 1)) : \
(((*(x)) = -1) > 0) ? \
((*(x)) = parsenum_unsigned((s), 0, (*(x)), \
(*(x)), (base), (trailing))) : \
(ASSERT_FAIL(_define_name " applied to signed" \
" integer without specified bounds"), 1), \
errno != 0 \
PARSENUM_EPILOGUE \
)
#define PARSENUM_EX6(x, s, min, max, base, trailing, _define_name) \
( \
PARSENUM_PROLOGUE \
errno = 0, \
(((*(x)) = 1, (*(x)) /= 2) > 0) ? \
(((base) == 0) ? \
((*(x)) = parsenum_float((s), \
(double)(min), (double)(max), \
(trailing))) : \
(ASSERT_FAIL(_define_name " applied to" \
" float with base != 0"), 1)) : \
(((*(x)) = -1) <= 0) ? \
((*(x)) = parsenum_signed((s), \
(*(x) <= 0) ? (min) : 0, \
(*(x) <= 0) ? (max) : 0, (base), \
(trailing))) : \
(((*(x)) = parsenum_unsigned((s), \
(min) <= 0 ? 0 : (min), \
(uintmax_t)(max), *(x), (base), \
(trailing))), \
((((max) < 0) && (errno == 0)) ? \
(errno = ERANGE) : 0)), \
errno != 0 \
PARSENUM_EPILOGUE \
)
/* Magic to select which version of PARSENUM_EX to use. */
#define PARSENUM_EX(...) PARSENUM_EX_(PARSENUM_EX_COUNT(__VA_ARGS__))(__VA_ARGS__, "PARSENUM_EX")
#define PARSENUM_EX_(N) PARSENUM_EX__(N)
#define PARSENUM_EX__(N) PARSENUM_EX ## N
#define PARSENUM_EX_COUNT(...) PARSENUM_EX_COUNT_(__VA_ARGS__, 6, 5, 4, 3, 2, 1)
#define PARSENUM_EX_COUNT_(_1, _2, _3, _4, _5, _6, N, ...) N
/* Functions for performing the parsing and parameter checking. */
static inline double
parsenum_float(const char * s, double min, double max, int trailing)
{
char * eptr;
double val;
val = strtod(s, &eptr);
if (eptr == s || (!trailing && (*eptr != '\0')))
errno = EINVAL;
else if ((val < min) || (val > max))
errno = ERANGE;
return (val);
}
static inline intmax_t
parsenum_signed(const char * s, intmax_t min, intmax_t max, int base,
int trailing)
{
char * eptr;
intmax_t val;
val = strtoimax(s, &eptr, base);
if (eptr == s || (!trailing && (*eptr != '\0')))
errno = EINVAL;
else if ((val < min) || (val > max)) {
errno = ERANGE;
val = 0;
}
return (val);
}
static inline uintmax_t
parsenum_unsigned(const char * s, uintmax_t min, uintmax_t max,
uintmax_t typemax, int base, int trailing)
{
char * eptr;
uintmax_t val;
val = strtoumax(s, &eptr, base);
if (eptr == s || (!trailing && (*eptr != '\0')))
errno = EINVAL;
else if ((val < min) || (val > max) || (val > typemax))
errno = ERANGE;
return (val);
}
#endif /* !_PARSENUM_H_ */