xatonum_template.c 4.9 KB

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