xatonum_template.c 4.6 KB

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