Packages

The argon2 "plugin" for ExPassword (as a NIF)

Current section

Files

Jump to
expassword_argon2 src parsenum.c
Raw

src/parsenum.c

#include <stdbool.h>
#include <string.h>
#include <limits.h>
#include <stdint.h>
#include "parsenum.h"
/**
* - PARSE_NUM_NO_ERR: all characters of the string were consumed to convert it into an integer
*
* - PARSE_NUM_ERR_INVALID_BASE: base parameter is invalid
*
* - PARSE_NUM_ERR_NO_DIGIT_FOUND: the given string contains no digit at all, meaning we reach the end of the string without finding a first digit for
* the conversion into integer. Empty strings ("") as empty prefixed binary (0b) and hexadecimal (0x) numbers ("0x" as "0b") will throw this error.
* There is an exception: "0" with base auto-detection (base = 0) will be recognized as a (octal) zero without throwing this error.
*
* - PARSE_NUM_ERR_NON_DIGIT_FOUND: conversion failed on a character which can't be a digit (according to the actual base)
*
* - PARSE_NUM_ERR_TOO_SMALL:
* - PARSE_NUM_ERR_TOO_LARGE:
* the number is valid but is out of physical limits
*
* - PARSE_NUM_ERR_LESS_THAN_MIN:
* - PARSE_NUM_ERR_GREATER_THAN_MAX:
* the number is valid but is out of user limits
**/
#define parse_signed(type, unsigned_type, value_type_min, value_type_max) \
ParseNumError strto## type(const char *nptr, char **endptr, int base, type *min, type *max, type *ret) { \
return strnto## type(nptr, nptr + strlen(nptr), endptr, base, min, max, ret); \
} \
\
ParseNumError strnto## type(const char *nptr, const char * const end, char **endptr, int base, type *min, type *max, type *ret) { \
char c; \
char ***spp; \
bool negative; \
int any, cutlim; \
ParseNumError err; \
unsigned_type cutoff, acc; \
\
acc = any = 0; \
negative = false; \
err = PARSE_NUM_NO_ERR; \
if (NULL == endptr) { \
char **sp; \
\
sp = (char **) &nptr; \
spp = &sp; \
} else { \
spp = &endptr; \
*endptr = (char *) nptr; \
} \
if (**spp < end) { \
if ('-' == ***spp) { \
++**spp; \
negative = true; \
} else { \
negative = false; \
if ('+' == ***spp) { \
++**spp; \
} \
} \
if ((0 == base || 2 == base) && '0' == ***spp && (end - **spp) > 1 && ('b' == (**spp)[1] || 'B' == (**spp)[1])) { \
**spp += 2; \
base = 2; \
} \
if ((0 == base || 16 == base) && '0' == ***spp && (end - **spp) > 1 && ('x' == (**spp)[1] || 'X' == (**spp)[1])) { \
**spp += 2; \
base = 16; \
} \
if (0 == base) { \
base = '0' == ***spp ? 8 : 10; \
} \
if (base < 2 || base > 36) { \
return PARSE_NUM_ERR_INVALID_BASE; \
} \
cutoff = negative ? (unsigned_type) - (value_type_min + value_type_max) + value_type_max : value_type_max; \
cutlim = cutoff % base; \
cutoff /= base; \
while (**spp < end) { \
if (***spp >= '0' && ***spp <= '9') { \
c = ***spp - '0'; \
} else if (base > 10 && ***spp >= 'A' && ***spp <= 'Z') { \
c = ***spp - 'A' - 10; \
} else if (base > 10 && ***spp >= 'a' && ***spp <= 'z') { \
c = ***spp - 'a' - 10; \
} else { \
err = PARSE_NUM_ERR_NON_DIGIT_FOUND; \
break; \
} \
if (c >= base) { \
err = PARSE_NUM_ERR_NON_DIGIT_FOUND; \
break; \
} \
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) { \
any = -1; \
} else { \
any = 1; \
acc *= base; \
acc += c; \
} \
++**spp; \
} \
} \
if (any < 0) { \
if (negative) { \
*ret = value_type_min; \
return PARSE_NUM_ERR_TOO_SMALL; \
} else { \
*ret = value_type_max; \
return PARSE_NUM_ERR_TOO_LARGE; \
} \
} else if (!any && PARSE_NUM_NO_ERR == err) { \
err = PARSE_NUM_ERR_NO_DIGIT_FOUND; \
} else if (negative) { \
*ret = -acc; \
} else { \
*ret = acc; \
} \
if (PARSE_NUM_NO_ERR == err) { \
if (NULL != min && *ret < *min) { \
err = PARSE_NUM_ERR_LESS_THAN_MIN; \
} \
if (NULL != max && *ret > *max) { \
err = PARSE_NUM_ERR_GREATER_THAN_MAX; \
} \
} \
\
return err; \
}
// parse_signed(int8_t, uint8_t, INT8_MIN, INT8_MAX);
// parse_signed(int16_t, uint16_t, INT16_MIN, INT16_MAX);
// parse_signed(int32_t, uint32_t, INT32_MIN, INT32_MAX);
// parse_signed(int64_t, uint64_t, INT64_MIN, INT64_MAX);
#undef parse_signed
#define parse_unsigned(type, value_type_max) \
ParseNumError strto## type(const char *nptr, char **endptr, int base, type *min, type *max, type *ret) { \
return strnto## type(nptr, nptr + strlen(nptr), endptr, base, min, max, ret); \
} \
\
ParseNumError strnto## type(const char *nptr, const char * const end, char **endptr, int base, type *min, type *max, type *ret) { \
char c; \
char ***spp; \
bool negative; \
int any, cutlim; \
type cutoff, acc; \
ParseNumError err; \
\
acc = any = 0; \
negative = false; \
err = PARSE_NUM_NO_ERR; \
if (NULL == endptr) { \
char **sp; \
\
sp = (char **) &nptr; \
spp = &sp; \
} else { \
spp = &endptr; \
*endptr = (char *) nptr; \
} \
if (**spp < end) { \
if ('-' == ***spp) { \
++**spp; \
negative = true; \
} else { \
negative = false; \
if ('+' == ***spp) { \
++**spp; \
} \
} \
if ((0 == base || 2 == base) && '0' == ***spp && (end - **spp) > 1 && ('b' == (**spp)[1] || 'B' == (**spp)[1])) { \
**spp += 2; \
base = 2; \
} \
if ((0 == base || 16 == base) && '0' == ***spp && (end - **spp) > 1 && ('x' == (**spp)[1] || 'X' == (**spp)[1])) { \
**spp += 2; \
base = 16; \
} \
if (0 == base) { \
base = '0' == ***spp ? 8 : 10; \
} \
if (base < 2 || base > 36) { \
return PARSE_NUM_ERR_INVALID_BASE; \
} \
cutoff = value_type_max / base; \
cutlim = value_type_max % base; \
while (**spp < end) { \
if (***spp >= '0' && ***spp <= '9') { \
c = ***spp - '0'; \
} else if (base > 10 && ***spp >= 'A' && ***spp <= 'Z') { \
c = ***spp - 'A' - 10; \
} else if (base > 10 && ***spp >= 'a' && ***spp <= 'z') { \
c = ***spp - 'a' - 10; \
} else { \
err = PARSE_NUM_ERR_NON_DIGIT_FOUND; \
break; \
} \
if (c >= base) { \
err = PARSE_NUM_ERR_NON_DIGIT_FOUND; \
break; \
} \
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) { \
any = -1; \
} else { \
any = 1; \
acc *= base; \
acc += c; \
} \
++**spp; \
} \
} \
if (any < 0) { \
*ret = value_type_max; \
return PARSE_NUM_ERR_TOO_LARGE; \
} else if (!any && PARSE_NUM_NO_ERR == err) { \
err = PARSE_NUM_ERR_NO_DIGIT_FOUND; \
} else if (negative) { \
*ret = -acc; \
} else { \
*ret = acc; \
} \
if (PARSE_NUM_NO_ERR == err) { \
if (NULL != min && *ret < *min) { \
err = PARSE_NUM_ERR_LESS_THAN_MIN; \
} \
if (NULL != max && *ret > *max) { \
err = PARSE_NUM_ERR_GREATER_THAN_MAX; \
} \
} \
\
return err; \
}
// parse_unsigned(uint8_t, UINT8_MAX);
// parse_unsigned(uint16_t, UINT16_MAX);
parse_unsigned(uint32_t, UINT32_MAX);
// parse_unsigned(uint64_t, UINT64_MAX);
#undef parse_unsigned