string_parser.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #include <sys/types.h>
  2. #include <string.h>
  3. #include <ctype.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <errno.h>
  7. #include <limits.h>
  8. #include "int.h"
  9. #include "girstring.h"
  10. #include "casprintf.h"
  11. #include "string_parser.h"
  12. static const char *
  13. strippedSubstring(const char * const string) {
  14. const char * p;
  15. for (p = &string[0]; isspace(*p); ++p);
  16. return p;
  17. }
  18. void
  19. interpretUll(const char * const string,
  20. uint64_t * const ullP,
  21. const char ** const errorP) {
  22. /* strtoull() has the same disappointing weaknesses of strtoul().
  23. See interpretUint().
  24. */
  25. const char * const strippedString = strippedSubstring(string);
  26. if (strippedString[0] == '\0')
  27. casprintf(errorP, "Null (or all whitespace) string.");
  28. else if (!isdigit(strippedString[0]))
  29. casprintf(errorP, "First non-blank character is '%c', not a digit.",
  30. strippedString[0]);
  31. else {
  32. /* strtoull() does a bizarre thing where if the number is out
  33. of range, it returns a clamped value but tells you about it
  34. by setting errno = ERANGE. If it is not out of range,
  35. strtoull() leaves errno alone.
  36. */
  37. char * tail;
  38. errno = 0; /* So we can tell if strtoull() overflowed */
  39. *ullP = XMLRPC_STRTOULL(strippedString, &tail, 10);
  40. if (tail[0] != '\0')
  41. casprintf(errorP, "Non-digit stuff in string: %s", tail);
  42. else if (errno == ERANGE)
  43. casprintf(errorP, "Number too large");
  44. else
  45. *errorP = NULL;
  46. }
  47. }
  48. void
  49. interpretLl(const char * const string,
  50. int64_t * const llP,
  51. const char ** const errorP) {
  52. if (string[0] == '\0')
  53. casprintf(errorP, "Null string.");
  54. else {
  55. /* strtoll() does a bizarre thing where if the number is out
  56. of range, it returns a clamped value but tells you about it
  57. by setting errno = ERANGE. If it is not out of range,
  58. strtoll() leaves errno alone.
  59. */
  60. char * tail;
  61. errno = 0; /* So we can tell if strtoll() overflowed */
  62. *llP = XMLRPC_STRTOLL(string, &tail, 10);
  63. if (tail[0] != '\0')
  64. casprintf(errorP, "Non-digit stuff in string: %s", tail);
  65. else if (errno == ERANGE)
  66. casprintf(errorP, "Number too large");
  67. else
  68. *errorP = NULL;
  69. }
  70. }
  71. void
  72. interpretUint(const char * const string,
  73. unsigned int * const uintP,
  74. const char ** const errorP) {
  75. /* strtoul() does a lousy job of dealing with invalid numbers. A null
  76. string is just zero; a negative number is a large positive one; a
  77. positive (cf unsigned) number is accepted. strtoul is inconsistent
  78. in its treatment of the tail; if there is no valid number at all,
  79. it returns the entire string as the tail, including leading white
  80. space and sign, which are not themselves invalid.
  81. */
  82. const char * const strippedString = strippedSubstring(string);
  83. if (strippedString[0] == '\0')
  84. casprintf(errorP, "Null (or all whitespace) string.");
  85. else if (!isdigit(strippedString[0]))
  86. casprintf(errorP, "First non-blank character is '%c', not a digit.",
  87. strippedString[0]);
  88. else {
  89. /* strtoul() does a bizarre thing where if the number is out
  90. of range, it returns a clamped value but tells you about it
  91. by setting errno = ERANGE. If it is not out of range,
  92. strtoul() leaves errno alone.
  93. */
  94. char * tail;
  95. unsigned long ulongValue;
  96. errno = 0; /* So we can tell if strtoul() overflowed */
  97. ulongValue = strtoul(strippedString, &tail, 10);
  98. if (tail[0] != '\0')
  99. casprintf(errorP, "Non-digit stuff in string: %s", tail);
  100. else if (errno == ERANGE)
  101. casprintf(errorP, "Number too large");
  102. else if (ulongValue > UINT_MAX)
  103. casprintf(errorP, "Number too large");
  104. else {
  105. *uintP = ulongValue;
  106. *errorP = NULL;
  107. }
  108. }
  109. }
  110. void
  111. interpretInt(const char * const string,
  112. int * const intP,
  113. const char ** const errorP) {
  114. if (string[0] == '\0')
  115. casprintf(errorP, "Null string.");
  116. else {
  117. /* strtol() does a bizarre thing where if the number is out
  118. of range, it returns a clamped value but tells you about it
  119. by setting errno = ERANGE. If it is not out of range,
  120. strtol() leaves errno alone.
  121. */
  122. char * tail;
  123. long longValue;
  124. errno = 0; /* So we can tell if strtol() overflowed */
  125. longValue = strtol(string, &tail, 10);
  126. if (tail[0] != '\0')
  127. casprintf(errorP, "Non-digit stuff in string: %s", tail);
  128. else if (errno == ERANGE)
  129. casprintf(errorP, "Number too large");
  130. else if (longValue > INT_MAX)
  131. casprintf(errorP, "Number too large");
  132. else if (longValue < INT_MIN)
  133. casprintf(errorP, "Number too negative");
  134. else {
  135. *intP = longValue;
  136. *errorP = NULL;
  137. }
  138. }
  139. }
  140. void
  141. interpretBinUint(const char * const string,
  142. uint64_t * const valueP,
  143. const char ** const errorP) {
  144. char * tailptr;
  145. long const mantissa_long = strtol(string, &tailptr, 10);
  146. if (errno == ERANGE)
  147. casprintf(errorP,
  148. "Numeric value out of range for computation: '%s'. "
  149. "Try a smaller number with a K, M, G, etc. suffix.",
  150. string);
  151. else {
  152. int64_t const mantissa = mantissa_long;
  153. int64_t argNumber;
  154. *errorP = NULL; /* initial assumption */
  155. if (*tailptr == '\0')
  156. /* There's no suffix. A pure number */
  157. argNumber = mantissa * 1;
  158. else if (stripcaseeq(tailptr, "K"))
  159. argNumber = mantissa * 1024;
  160. else if (stripcaseeq(tailptr, "M"))
  161. argNumber = mantissa * 1024 * 1024;
  162. else if (stripcaseeq(tailptr, "G"))
  163. argNumber = mantissa * 1024 * 1024 * 1024;
  164. else if (stripcaseeq(tailptr, "T"))
  165. argNumber = mantissa * 1024 * 1024 * 1024 * 1024;
  166. else if (stripcaseeq(tailptr, "P"))
  167. argNumber = mantissa * 1024 * 1024 * 1024 * 1024 * 1024;
  168. else {
  169. argNumber = 0; /* quiet compiler warning */
  170. casprintf(errorP, "Garbage suffix '%s' on number", tailptr);
  171. }
  172. if (!*errorP) {
  173. if (argNumber < 0)
  174. casprintf(errorP, "Unsigned numeric value is "
  175. "negative: %" PRId64, argNumber);
  176. else
  177. *valueP = (uint64_t) argNumber;
  178. }
  179. }
  180. }