|
|
#include <sys/types.h> |
|
|
#include <string.h> |
|
|
#include <ctype.h> |
|
|
#include <stdlib.h> |
|
|
#include <stdio.h> |
|
|
#include <errno.h> |
|
|
#include <limits.h> |
|
|
|
|
|
#include "int.h" |
|
|
#include "girstring.h" |
|
|
#include "casprintf.h" |
|
|
|
|
|
#include "string_parser.h" |
|
|
|
|
|
static const char * |
|
|
strippedSubstring(const char * const string) { |
|
|
|
|
|
const char * p; |
|
|
|
|
|
for (p = &string[0]; isspace(*p); ++p); |
|
|
|
|
|
return p; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
interpretUll(const char * const string, |
|
|
uint64_t * const ullP, |
|
|
const char ** const errorP) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char * const strippedString = strippedSubstring(string); |
|
|
|
|
|
if (strippedString[0] == '\0') |
|
|
casprintf(errorP, "Null (or all whitespace) string."); |
|
|
else if (!isdigit(strippedString[0])) |
|
|
casprintf(errorP, "First non-blank character is '%c', not a digit.", |
|
|
strippedString[0]); |
|
|
else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char * tail; |
|
|
|
|
|
errno = 0; |
|
|
|
|
|
*ullP = XMLRPC_STRTOULL(strippedString, &tail, 10); |
|
|
|
|
|
if (tail[0] != '\0') |
|
|
casprintf(errorP, "Non-digit stuff in string: %s", tail); |
|
|
else if (errno == ERANGE) |
|
|
casprintf(errorP, "Number too large"); |
|
|
else |
|
|
*errorP = NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
interpretLl(const char * const string, |
|
|
int64_t * const llP, |
|
|
const char ** const errorP) { |
|
|
|
|
|
if (string[0] == '\0') |
|
|
casprintf(errorP, "Null string."); |
|
|
else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char * tail; |
|
|
|
|
|
errno = 0; |
|
|
|
|
|
*llP = XMLRPC_STRTOLL(string, &tail, 10); |
|
|
|
|
|
if (tail[0] != '\0') |
|
|
casprintf(errorP, "Non-digit stuff in string: %s", tail); |
|
|
else if (errno == ERANGE) |
|
|
casprintf(errorP, "Number too large"); |
|
|
else |
|
|
*errorP = NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
interpretUint(const char * const string, |
|
|
unsigned int * const uintP, |
|
|
const char ** const errorP) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char * const strippedString = strippedSubstring(string); |
|
|
|
|
|
if (strippedString[0] == '\0') |
|
|
casprintf(errorP, "Null (or all whitespace) string."); |
|
|
else if (!isdigit(strippedString[0])) |
|
|
casprintf(errorP, "First non-blank character is '%c', not a digit.", |
|
|
strippedString[0]); |
|
|
else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char * tail; |
|
|
unsigned long ulongValue; |
|
|
|
|
|
errno = 0; |
|
|
|
|
|
ulongValue = strtoul(strippedString, &tail, 10); |
|
|
|
|
|
if (tail[0] != '\0') |
|
|
casprintf(errorP, "Non-digit stuff in string: %s", tail); |
|
|
else if (errno == ERANGE) |
|
|
casprintf(errorP, "Number too large"); |
|
|
else if (ulongValue > UINT_MAX) |
|
|
casprintf(errorP, "Number too large"); |
|
|
else { |
|
|
*uintP = ulongValue; |
|
|
*errorP = NULL; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
interpretInt(const char * const string, |
|
|
int * const intP, |
|
|
const char ** const errorP) { |
|
|
|
|
|
if (string[0] == '\0') |
|
|
casprintf(errorP, "Null string."); |
|
|
else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char * tail; |
|
|
long longValue; |
|
|
|
|
|
errno = 0; |
|
|
|
|
|
longValue = strtol(string, &tail, 10); |
|
|
|
|
|
if (tail[0] != '\0') |
|
|
casprintf(errorP, "Non-digit stuff in string: %s", tail); |
|
|
else if (errno == ERANGE) |
|
|
casprintf(errorP, "Number too large"); |
|
|
else if (longValue > INT_MAX) |
|
|
casprintf(errorP, "Number too large"); |
|
|
else if (longValue < INT_MIN) |
|
|
casprintf(errorP, "Number too negative"); |
|
|
else { |
|
|
*intP = longValue; |
|
|
*errorP = NULL; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
interpretBinUint(const char * const string, |
|
|
uint64_t * const valueP, |
|
|
const char ** const errorP) { |
|
|
|
|
|
char * tailptr; |
|
|
long const mantissa_long = strtol(string, &tailptr, 10); |
|
|
|
|
|
if (errno == ERANGE) |
|
|
casprintf(errorP, |
|
|
"Numeric value out of range for computation: '%s'. " |
|
|
"Try a smaller number with a K, M, G, etc. suffix.", |
|
|
string); |
|
|
else { |
|
|
int64_t const mantissa = mantissa_long; |
|
|
|
|
|
int64_t argNumber; |
|
|
|
|
|
*errorP = NULL; |
|
|
|
|
|
if (*tailptr == '\0') |
|
|
|
|
|
argNumber = mantissa * 1; |
|
|
else if (stripcaseeq(tailptr, "K")) |
|
|
argNumber = mantissa * 1024; |
|
|
else if (stripcaseeq(tailptr, "M")) |
|
|
argNumber = mantissa * 1024 * 1024; |
|
|
else if (stripcaseeq(tailptr, "G")) |
|
|
argNumber = mantissa * 1024 * 1024 * 1024; |
|
|
else if (stripcaseeq(tailptr, "T")) |
|
|
argNumber = mantissa * 1024 * 1024 * 1024 * 1024; |
|
|
else if (stripcaseeq(tailptr, "P")) |
|
|
argNumber = mantissa * 1024 * 1024 * 1024 * 1024 * 1024; |
|
|
else { |
|
|
argNumber = 0; |
|
|
casprintf(errorP, "Garbage suffix '%s' on number", tailptr); |
|
|
} |
|
|
if (!*errorP) { |
|
|
if (argNumber < 0) |
|
|
casprintf(errorP, "Unsigned numeric value is " |
|
|
"negative: %" PRId64, argNumber); |
|
|
else |
|
|
*valueP = (uint64_t) argNumber; |
|
|
} |
|
|
} |
|
|
} |
|
|
|