123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- #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) {
- /* strtoull() has the same disappointing weaknesses of strtoul().
- See interpretUint().
- */
- 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 {
- /* strtoull() does a bizarre thing where if the number is out
- of range, it returns a clamped value but tells you about it
- by setting errno = ERANGE. If it is not out of range,
- strtoull() leaves errno alone.
- */
- char * tail;
-
- errno = 0; /* So we can tell if strtoull() overflowed */
- *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 {
- /* strtoll() does a bizarre thing where if the number is out
- of range, it returns a clamped value but tells you about it
- by setting errno = ERANGE. If it is not out of range,
- strtoll() leaves errno alone.
- */
- char * tail;
-
- errno = 0; /* So we can tell if strtoll() overflowed */
- *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) {
- /* strtoul() does a lousy job of dealing with invalid numbers. A null
- string is just zero; a negative number is a large positive one; a
- positive (cf unsigned) number is accepted. strtoul is inconsistent
- in its treatment of the tail; if there is no valid number at all,
- it returns the entire string as the tail, including leading white
- space and sign, which are not themselves invalid.
- */
- 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 {
- /* strtoul() does a bizarre thing where if the number is out
- of range, it returns a clamped value but tells you about it
- by setting errno = ERANGE. If it is not out of range,
- strtoul() leaves errno alone.
- */
- char * tail;
- unsigned long ulongValue;
-
- errno = 0; /* So we can tell if strtoul() overflowed */
- 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 {
- /* strtol() does a bizarre thing where if the number is out
- of range, it returns a clamped value but tells you about it
- by setting errno = ERANGE. If it is not out of range,
- strtol() leaves errno alone.
- */
- char * tail;
- long longValue;
-
- errno = 0; /* So we can tell if strtol() overflowed */
- 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; /* initial assumption */
- if (*tailptr == '\0')
- /* There's no suffix. A pure number */
- 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; /* quiet compiler warning */
- 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;
- }
- }
- }
|