bb_strtonum.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Utility routines.
  4. *
  5. * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
  6. *
  7. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  8. */
  9. #include "libbb.h"
  10. /* On exit: errno = 0 only if there was non-empty, '\0' terminated value
  11. * errno = EINVAL if value was not '\0' terminated, but othervise ok
  12. * Return value is still valid, caller should just check whether end[0]
  13. * is a valid terminating char for particular case. OTOH, if caller
  14. * requires '\0' terminated input, [s]he can just check errno == 0.
  15. * errno = ERANGE if value had alphanumeric terminating char ("1234abcg").
  16. * errno = ERANGE if value is out of range, missing, etc.
  17. * errno = ERANGE if value had minus sign for strtouXX (even "-0" is not ok )
  18. * return value is all-ones in this case.
  19. */
  20. static unsigned long long ret_ERANGE(void)
  21. {
  22. errno = ERANGE; /* this ain't as small as it looks (on glibc) */
  23. return ULLONG_MAX;
  24. }
  25. static unsigned long long handle_errors(unsigned long long v, char **endp, char *endptr)
  26. {
  27. if (endp) *endp = endptr;
  28. /* Check for the weird "feature":
  29. * a "-" string is apparently a valid "number" for strto[u]l[l]!
  30. * It returns zero and errno is 0! :( */
  31. if (endptr[-1] == '-')
  32. return ret_ERANGE();
  33. /* errno is already set to ERANGE by strtoXXX if value overflowed */
  34. if (endptr[0]) {
  35. /* "1234abcg" or out-of-range? */
  36. if (isalnum(endptr[0]) || errno)
  37. return ret_ERANGE();
  38. /* good number, just suspicious terminator */
  39. errno = EINVAL;
  40. }
  41. return v;
  42. }
  43. unsigned long long bb_strtoull(const char *arg, char **endp, int base)
  44. {
  45. unsigned long long v;
  46. char *endptr;
  47. /* strtoul(" -4200000000") returns 94967296, errno 0 (!) */
  48. /* I don't think that this is right. Preventing this... */
  49. if (!isalnum(arg[0])) return ret_ERANGE();
  50. /* not 100% correct for lib func, but convenient for the caller */
  51. errno = 0;
  52. v = strtoull(arg, &endptr, base);
  53. return handle_errors(v, endp, endptr);
  54. }
  55. long long bb_strtoll(const char *arg, char **endp, int base)
  56. {
  57. unsigned long long v;
  58. char *endptr;
  59. if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE();
  60. errno = 0;
  61. v = strtoll(arg, &endptr, base);
  62. return handle_errors(v, endp, endptr);
  63. }
  64. #if ULONG_MAX != ULLONG_MAX
  65. unsigned long bb_strtoul(const char *arg, char **endp, int base)
  66. {
  67. unsigned long v;
  68. char *endptr;
  69. if (!isalnum(arg[0])) return ret_ERANGE();
  70. errno = 0;
  71. v = strtoul(arg, &endptr, base);
  72. return handle_errors(v, endp, endptr);
  73. }
  74. long bb_strtol(const char *arg, char **endp, int base)
  75. {
  76. long v;
  77. char *endptr;
  78. if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE();
  79. errno = 0;
  80. v = strtol(arg, &endptr, base);
  81. return handle_errors(v, endp, endptr);
  82. }
  83. #endif
  84. #if UINT_MAX != ULONG_MAX
  85. unsigned bb_strtou(const char *arg, char **endp, int base)
  86. {
  87. unsigned long v;
  88. char *endptr;
  89. if (!isalnum(arg[0])) return ret_ERANGE();
  90. errno = 0;
  91. v = strtoul(arg, &endptr, base);
  92. if (v > UINT_MAX) return ret_ERANGE();
  93. return handle_errors(v, endp, endptr);
  94. }
  95. int bb_strtoi(const char *arg, char **endp, int base)
  96. {
  97. long v;
  98. char *endptr;
  99. if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE();
  100. errno = 0;
  101. v = strtol(arg, &endptr, base);
  102. if (v > INT_MAX) return ret_ERANGE();
  103. if (v < INT_MIN) return ret_ERANGE();
  104. return handle_errors(v, endp, endptr);
  105. }
  106. #endif
  107. /* Floating point */
  108. #if 0
  109. #include <math.h> /* just for HUGE_VAL */
  110. #define NOT_DIGIT(a) (((unsigned char)(a-'0')) > 9)
  111. double bb_strtod(const char *arg, char **endp)
  112. {
  113. double v;
  114. char *endptr;
  115. if (arg[0] != '-' && NOT_DIGIT(arg[0])) goto err;
  116. errno = 0;
  117. v = strtod(arg, &endptr);
  118. if (endp) *endp = endptr;
  119. if (endptr[0]) {
  120. /* "1234abcg" or out-of-range? */
  121. if (isalnum(endptr[0]) || errno) {
  122. err:
  123. errno = ERANGE;
  124. return HUGE_VAL;
  125. }
  126. /* good number, just suspicious terminator */
  127. errno = EINVAL;
  128. }
  129. return v;
  130. }
  131. #endif