xatonum_template.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. *
  3. * Licensed under GPLv2, see file LICENSE in this tarball for details.
  4. */
  5. /*
  6. You need to define the following (example):
  7. #define type long
  8. #define xstrtou(rest) xstrtoul##rest
  9. #define xstrto(rest) xstrtol##rest
  10. #define xatou(rest) xatoul##rest
  11. #define xato(rest) xatol##rest
  12. #define XSTR_UTYPE_MAX ULONG_MAX
  13. #define XSTR_TYPE_MAX LONG_MAX
  14. #define XSTR_TYPE_MIN LONG_MIN
  15. #define XSTR_STRTOU strtoul
  16. */
  17. unsigned type FAST_FUNC xstrtou(_range_sfx)(const char *numstr, int base,
  18. unsigned type lower,
  19. unsigned type upper,
  20. const struct suffix_mult *suffixes)
  21. {
  22. unsigned type r;
  23. int old_errno;
  24. char *e;
  25. /* Disallow '-' and any leading whitespace. Make sure we get the
  26. * actual isspace function rather than a macro implementaion. */
  27. if (*numstr == '-' || *numstr == '+' || (isspace)(*numstr))
  28. goto inval;
  29. /* Since this is a lib function, we're not allowed to reset errno to 0.
  30. * Doing so could break an app that is deferring checking of errno.
  31. * So, save the old value so that we can restore it if successful. */
  32. old_errno = errno;
  33. errno = 0;
  34. r = XSTR_STRTOU(numstr, &e, base);
  35. /* Do the initial validity check. Note: The standards do not
  36. * guarantee that errno is set if no digits were found. So we
  37. * must test for this explicitly. */
  38. if (errno || numstr == e)
  39. goto inval; /* error / no digits / illegal trailing chars */
  40. errno = old_errno; /* Ok. So restore errno. */
  41. /* Do optional suffix parsing. Allow 'empty' suffix tables.
  42. * Note that we also allow nul suffixes with associated multipliers,
  43. * to allow for scaling of the numstr by some default multiplier. */
  44. if (suffixes) {
  45. while (suffixes->mult) {
  46. if (strcmp(suffixes->suffix, e) == 0) {
  47. if (XSTR_UTYPE_MAX / suffixes->mult < r)
  48. goto range; /* overflow! */
  49. r *= suffixes->mult;
  50. goto chk_range;
  51. }
  52. ++suffixes;
  53. }
  54. }
  55. /* Note: trailing space is an error.
  56. It would be easy enough to allow though if desired. */
  57. if (*e)
  58. goto inval;
  59. chk_range:
  60. /* Finally, check for range limits. */
  61. if (r >= lower && r <= upper)
  62. return r;
  63. range:
  64. bb_error_msg_and_die("number %s is not in %llu..%llu range",
  65. numstr, (unsigned long long)lower,
  66. (unsigned long long)upper);
  67. inval:
  68. bb_error_msg_and_die("invalid number '%s'", numstr);
  69. }
  70. unsigned type FAST_FUNC xstrtou(_range)(const char *numstr, int base,
  71. unsigned type lower,
  72. unsigned type upper)
  73. {
  74. return xstrtou(_range_sfx)(numstr, base, lower, upper, NULL);
  75. }
  76. unsigned type FAST_FUNC xstrtou(_sfx)(const char *numstr, int base,
  77. const struct suffix_mult *suffixes)
  78. {
  79. return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, suffixes);
  80. }
  81. unsigned type FAST_FUNC xstrtou()(const char *numstr, int base)
  82. {
  83. return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, NULL);
  84. }
  85. unsigned type FAST_FUNC xatou(_range_sfx)(const char *numstr,
  86. unsigned type lower,
  87. unsigned type upper,
  88. const struct suffix_mult *suffixes)
  89. {
  90. return xstrtou(_range_sfx)(numstr, 10, lower, upper, suffixes);
  91. }
  92. unsigned type FAST_FUNC xatou(_range)(const char *numstr,
  93. unsigned type lower,
  94. unsigned type upper)
  95. {
  96. return xstrtou(_range_sfx)(numstr, 10, lower, upper, NULL);
  97. }
  98. unsigned type FAST_FUNC xatou(_sfx)(const char *numstr,
  99. const struct suffix_mult *suffixes)
  100. {
  101. return xstrtou(_range_sfx)(numstr, 10, 0, XSTR_UTYPE_MAX, suffixes);
  102. }
  103. unsigned type FAST_FUNC xatou()(const char *numstr)
  104. {
  105. return xatou(_sfx)(numstr, NULL);
  106. }
  107. /* Signed ones */
  108. type FAST_FUNC xstrto(_range_sfx)(const char *numstr, int base,
  109. type lower,
  110. type upper,
  111. const struct suffix_mult *suffixes)
  112. {
  113. unsigned type u = XSTR_TYPE_MAX;
  114. type r;
  115. const char *p = numstr;
  116. /* NB: if you'll decide to disallow '+':
  117. * at least renice applet needs to allow it */
  118. if (p[0] == '+' || p[0] == '-') {
  119. ++p;
  120. if (p[0] == '-')
  121. ++u; /* = <type>_MIN (01111... + 1 == 10000...) */
  122. }
  123. r = xstrtou(_range_sfx)(p, base, 0, u, suffixes);
  124. if (*numstr == '-') {
  125. r = -r;
  126. }
  127. if (r < lower || r > upper) {
  128. bb_error_msg_and_die("number %s is not in %lld..%lld range",
  129. numstr, (long long)lower, (long long)upper);
  130. }
  131. return r;
  132. }
  133. type FAST_FUNC xstrto(_range)(const char *numstr, int base, type lower, type upper)
  134. {
  135. return xstrto(_range_sfx)(numstr, base, lower, upper, NULL);
  136. }
  137. type FAST_FUNC xstrto()(const char *numstr, int base)
  138. {
  139. return xstrto(_range_sfx)(numstr, base, XSTR_TYPE_MIN, XSTR_TYPE_MAX, NULL);
  140. }
  141. type FAST_FUNC xato(_range_sfx)(const char *numstr,
  142. type lower,
  143. type upper,
  144. const struct suffix_mult *suffixes)
  145. {
  146. return xstrto(_range_sfx)(numstr, 10, lower, upper, suffixes);
  147. }
  148. type FAST_FUNC xato(_range)(const char *numstr, type lower, type upper)
  149. {
  150. return xstrto(_range_sfx)(numstr, 10, lower, upper, NULL);
  151. }
  152. type FAST_FUNC xato(_sfx)(const char *numstr, const struct suffix_mult *suffixes)
  153. {
  154. return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, suffixes);
  155. }
  156. type FAST_FUNC xato()(const char *numstr)
  157. {
  158. return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, NULL);
  159. }
  160. #undef type
  161. #undef xstrtou
  162. #undef xstrto
  163. #undef xatou
  164. #undef xato
  165. #undef XSTR_UTYPE_MAX
  166. #undef XSTR_TYPE_MAX
  167. #undef XSTR_TYPE_MIN
  168. #undef XSTR_STRTOU