xstrtol.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /* A more useful interface to strtol.
  2. Copyright (C) 1995-2021
  3. Free Software Foundation, Inc.
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  14. /* Written by Jim Meyering. */
  15. #include <config.h>
  16. /* Some pre-ANSI implementations (e.g. SunOS 4)
  17. need stderr defined if assertion checking is enabled. */
  18. #include <stdio.h>
  19. #include <ctype.h>
  20. #include <errno.h>
  21. #include <inttypes.h>
  22. #include <limits.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include "lib/strutil.h"
  26. /*** global variables ****************************************************************************/
  27. /*** file scope macro definitions ****************************************************************/
  28. /*** file scope type declarations ****************************************************************/
  29. /*** file scope variables ************************************************************************/
  30. /* --------------------------------------------------------------------------------------------- */
  31. /*** file scope functions ************************************************************************/
  32. /* --------------------------------------------------------------------------------------------- */
  33. static strtol_error_t
  34. bkm_scale (uintmax_t * x, int scale_factor)
  35. {
  36. if (UINTMAX_MAX / scale_factor < *x)
  37. {
  38. *x = UINTMAX_MAX;
  39. return LONGINT_OVERFLOW;
  40. }
  41. *x *= scale_factor;
  42. return LONGINT_OK;
  43. }
  44. /* --------------------------------------------------------------------------------------------- */
  45. static strtol_error_t
  46. bkm_scale_by_power (uintmax_t * x, int base, int power)
  47. {
  48. strtol_error_t err = LONGINT_OK;
  49. while (power-- != 0)
  50. err |= bkm_scale (x, base);
  51. return err;
  52. }
  53. /* --------------------------------------------------------------------------------------------- */
  54. /*** public functions ****************************************************************************/
  55. /* --------------------------------------------------------------------------------------------- */
  56. strtol_error_t
  57. xstrtoumax (const char *s, char **ptr, int base, uintmax_t * val, const char *valid_suffixes)
  58. {
  59. char *t_ptr;
  60. char **p;
  61. uintmax_t tmp;
  62. strtol_error_t err = LONGINT_OK;
  63. g_assert (0 <= base && base <= 36);
  64. p = (ptr != NULL ? ptr : &t_ptr);
  65. {
  66. const char *q = s;
  67. unsigned char ch = *q;
  68. while (isspace (ch))
  69. ch = *++q;
  70. if (ch == '-')
  71. return LONGINT_INVALID;
  72. }
  73. errno = 0;
  74. tmp = strtol (s, p, base);
  75. if (*p == s)
  76. {
  77. /* If there is no number but there is a valid suffix, assume the
  78. number is 1. The string is invalid otherwise. */
  79. if (valid_suffixes != NULL && **p != '\0' && strchr (valid_suffixes, **p) != NULL)
  80. tmp = 1;
  81. else
  82. return LONGINT_INVALID;
  83. }
  84. else if (errno != 0)
  85. {
  86. if (errno != ERANGE)
  87. return LONGINT_INVALID;
  88. err = LONGINT_OVERFLOW;
  89. }
  90. /* Let valid_suffixes == NULL mean "allow any suffix". */
  91. /* FIXME: update all callers except the ones that allow suffixes
  92. after the number, changing last parameter NULL to "". */
  93. if (valid_suffixes == NULL)
  94. {
  95. *val = tmp;
  96. return err;
  97. }
  98. if (**p != '\0')
  99. {
  100. int suffixes = 1;
  101. strtol_error_t overflow;
  102. if (strchr (valid_suffixes, **p) == NULL)
  103. {
  104. *val = tmp;
  105. return err | LONGINT_INVALID_SUFFIX_CHAR;
  106. }
  107. base = 1024;
  108. switch (**p)
  109. {
  110. case 'E':
  111. case 'G':
  112. case 'g':
  113. case 'k':
  114. case 'K':
  115. case 'M':
  116. case 'm':
  117. case 'P':
  118. case 'T':
  119. case 't':
  120. case 'Y':
  121. case 'Z':
  122. if (strchr (valid_suffixes, '0') != NULL)
  123. {
  124. /* The "valid suffix" '0' is a special flag meaning that
  125. an optional second suffix is allowed, which can change
  126. the base. A suffix "B" (e.g. "100MB") stands for a power
  127. of 1000, whereas a suffix "iB" (e.g. "100MiB") stands for
  128. a power of 1024. If no suffix (e.g. "100M"), assume
  129. power-of-1024. */
  130. switch (p[0][1])
  131. {
  132. case 'i':
  133. if (p[0][2] == 'B')
  134. suffixes += 2;
  135. break;
  136. case 'B':
  137. case 'D': /* 'D' is obsolescent */
  138. base = 1000;
  139. suffixes++;
  140. break;
  141. default:
  142. break;
  143. }
  144. }
  145. break;
  146. default:
  147. break;
  148. }
  149. switch (**p)
  150. {
  151. case 'b':
  152. overflow = bkm_scale (&tmp, 512);
  153. break;
  154. case 'B':
  155. /* This obsolescent first suffix is distinct from the 'B'
  156. second suffix above. E.g., 'tar -L 1000B' means change
  157. the tape after writing 1000 KiB of data. */
  158. overflow = bkm_scale (&tmp, 1024);
  159. break;
  160. case 'c':
  161. overflow = LONGINT_OK;
  162. break;
  163. case 'E': /* exa or exbi */
  164. overflow = bkm_scale_by_power (&tmp, base, 6);
  165. break;
  166. case 'G': /* giga or gibi */
  167. case 'g': /* 'g' is undocumented; for compatibility only */
  168. overflow = bkm_scale_by_power (&tmp, base, 3);
  169. break;
  170. case 'k': /* kilo */
  171. case 'K': /* kibi */
  172. overflow = bkm_scale_by_power (&tmp, base, 1);
  173. break;
  174. case 'M': /* mega or mebi */
  175. case 'm': /* 'm' is undocumented; for compatibility only */
  176. overflow = bkm_scale_by_power (&tmp, base, 2);
  177. break;
  178. case 'P': /* peta or pebi */
  179. overflow = bkm_scale_by_power (&tmp, base, 5);
  180. break;
  181. case 'T': /* tera or tebi */
  182. case 't': /* 't' is undocumented; for compatibility only */
  183. overflow = bkm_scale_by_power (&tmp, base, 4);
  184. break;
  185. case 'w':
  186. overflow = bkm_scale (&tmp, 2);
  187. break;
  188. case 'Y': /* yotta or 2**80 */
  189. overflow = bkm_scale_by_power (&tmp, base, 8);
  190. break;
  191. case 'Z': /* zetta or 2**70 */
  192. overflow = bkm_scale_by_power (&tmp, base, 7);
  193. break;
  194. default:
  195. *val = tmp;
  196. return err | LONGINT_INVALID_SUFFIX_CHAR;
  197. }
  198. err |= overflow;
  199. *p += suffixes;
  200. if (**p != '\0')
  201. err |= LONGINT_INVALID_SUFFIX_CHAR;
  202. }
  203. *val = tmp;
  204. return err;
  205. }
  206. /* --------------------------------------------------------------------------------------------- */