numconv.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * numconv.c
  3. *
  4. * Copyright (C) 2017 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <ctype.h>
  22. #define DEFINE_XTOA(t, p, s) \
  23. char *p##toa(t value, char *str, int base) \
  24. { \
  25. char *ptr = str; \
  26. if (base < 2 || base > 36) return NULL; \
  27. \
  28. if (value == 0##s) \
  29. { \
  30. *ptr++ = '0'; \
  31. *ptr++ = '\0'; \
  32. return str; \
  33. } \
  34. \
  35. if (value < 0##s) \
  36. { \
  37. *ptr++ = '-'; \
  38. value = -value; \
  39. } \
  40. \
  41. t temp; \
  42. for (temp = value; temp > 0##s; temp /= (t)base) ptr++; \
  43. *ptr = '\0'; \
  44. \
  45. while (value > 0##s) \
  46. { \
  47. *--ptr = all_digits[value % (t)base]; \
  48. value /= (t)base; \
  49. } \
  50. \
  51. return str; \
  52. } \
  53. \
  54. char *u##p##toa(unsigned t value, char *str, int base) \
  55. { \
  56. char *ptr = str; \
  57. if (base < 2 || base > 36) return NULL; \
  58. \
  59. if (value == 0U##s) \
  60. { \
  61. *ptr++ = '0'; \
  62. *ptr++ = '\0'; \
  63. return str; \
  64. } \
  65. \
  66. unsigned t temp; \
  67. for (temp = value; temp > 0U##s; temp /= (unsigned t)base) ptr++; \
  68. *ptr = '\0'; \
  69. \
  70. while (value > 0U##s) \
  71. { \
  72. *--ptr = all_digits[value % (unsigned t)base]; \
  73. value /= (unsigned t)base; \
  74. } \
  75. \
  76. return str; \
  77. }
  78. #define DEFINE_ATOX(t, n, p, s) \
  79. t ato##p(const char *str) \
  80. { \
  81. return strto##p(str, NULL, 10); \
  82. } \
  83. \
  84. t strto##p(const char *str, char **endptr, int base) \
  85. { \
  86. const char *ptr; \
  87. t result = 0##s; \
  88. int overflow = 0, negative = 0; \
  89. \
  90. if (base < 2 || base > 36) return 0; \
  91. \
  92. switch (*str) \
  93. { \
  94. case '-': \
  95. negative = 1; \
  96. case '+': \
  97. str++; \
  98. break; \
  99. } \
  100. \
  101. for (ptr = str; *ptr; ptr++) \
  102. { \
  103. char *digit_ptr = strchr(all_digits, toupper(*ptr)); \
  104. if (digit_ptr == NULL) break; \
  105. \
  106. t digit = (t)(digit_ptr - all_digits); \
  107. if (digit >= base) break; \
  108. \
  109. t new_result = result * (t)base + digit; \
  110. if (new_result < result) overflow = 1; \
  111. result = new_result; \
  112. } \
  113. \
  114. if (overflow) \
  115. { \
  116. errno = ERANGE; \
  117. return negative ? n##_MIN : n##_MAX; \
  118. } \
  119. \
  120. if (negative) result = -result; \
  121. if (endptr) *endptr = (char*)ptr; \
  122. return result; \
  123. } \
  124. \
  125. unsigned t strtou##p(const char *str, char **endptr, int base) \
  126. { \
  127. const char *ptr; \
  128. unsigned t result = 0UL; \
  129. int overflow = 0; \
  130. \
  131. if (base < 2 || base > 36) return 0; \
  132. \
  133. for (ptr = str; *ptr; ptr++) \
  134. { \
  135. char *digit_ptr = strchr(all_digits, toupper(*ptr)); \
  136. if (digit_ptr == NULL) break; \
  137. \
  138. unsigned t digit = (unsigned t)(digit_ptr - all_digits); \
  139. if (digit >= base) break; \
  140. \
  141. unsigned t new_result = result * (unsigned t)base + digit; \
  142. if (new_result < result) overflow = 1; \
  143. result = new_result; \
  144. } \
  145. \
  146. if (overflow) \
  147. { \
  148. errno = ERANGE; \
  149. return U##n##_MAX; \
  150. } \
  151. \
  152. if (endptr) *endptr = (char*)ptr; \
  153. return result; \
  154. }
  155. static const char all_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  156. DEFINE_XTOA(int, i, );
  157. DEFINE_XTOA(long, l, L);
  158. DEFINE_XTOA(long long, ll, LL);
  159. DEFINE_ATOX(long, LONG, l, L);
  160. DEFINE_ATOX(long long, LLONG, ll, LL);
  161. int atoi(const char *str)
  162. {
  163. return (int)strtol(str, NULL, 10);
  164. }