123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- /*
- * numconv.c
- *
- * Copyright (C) 2017 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #define DEFINE_XTOA(t, p, s) \
- char *p##toa(t value, char *str, int base) \
- { \
- char *ptr = str; \
- if (base < 2 || base > 36) return NULL; \
- \
- if (value == 0##s) \
- { \
- *ptr++ = '0'; \
- *ptr++ = '\0'; \
- return str; \
- } \
- \
- if (value < 0##s) \
- { \
- *ptr++ = '-'; \
- value = -value; \
- } \
- \
- t temp; \
- for (temp = value; temp > 0##s; temp /= (t)base) ptr++; \
- *ptr = '\0'; \
- \
- while (value > 0##s) \
- { \
- *--ptr = all_digits[value % (t)base]; \
- value /= (t)base; \
- } \
- \
- return str; \
- } \
- \
- char *u##p##toa(unsigned t value, char *str, int base) \
- { \
- char *ptr = str; \
- if (base < 2 || base > 36) return NULL; \
- \
- if (value == 0U##s) \
- { \
- *ptr++ = '0'; \
- *ptr++ = '\0'; \
- return str; \
- } \
- \
- unsigned t temp; \
- for (temp = value; temp > 0U##s; temp /= (unsigned t)base) ptr++; \
- *ptr = '\0'; \
- \
- while (value > 0U##s) \
- { \
- *--ptr = all_digits[value % (unsigned t)base]; \
- value /= (unsigned t)base; \
- } \
- \
- return str; \
- }
- #define DEFINE_ATOX(t, n, p, s) \
- t ato##p(const char *str) \
- { \
- return strto##p(str, NULL, 10); \
- } \
- \
- t strto##p(const char *str, char **endptr, int base) \
- { \
- const char *ptr; \
- t result = 0##s; \
- int overflow = 0, negative = 0; \
- \
- if (base < 2 || base > 36) return 0; \
- \
- switch (*str) \
- { \
- case '-': \
- negative = 1; \
- case '+': \
- str++; \
- break; \
- } \
- \
- for (ptr = str; *ptr; ptr++) \
- { \
- char *digit_ptr = strchr(all_digits, toupper(*ptr)); \
- if (digit_ptr == NULL) break; \
- \
- t digit = (t)(digit_ptr - all_digits); \
- if (digit >= base) break; \
- \
- t new_result = result * (t)base + digit; \
- if (new_result < result) overflow = 1; \
- result = new_result; \
- } \
- \
- if (overflow) \
- { \
- errno = ERANGE; \
- return negative ? n##_MIN : n##_MAX; \
- } \
- \
- if (negative) result = -result; \
- if (endptr) *endptr = (char*)ptr; \
- return result; \
- } \
- \
- unsigned t strtou##p(const char *str, char **endptr, int base) \
- { \
- const char *ptr; \
- unsigned t result = 0UL; \
- int overflow = 0; \
- \
- if (base < 2 || base > 36) return 0; \
- \
- for (ptr = str; *ptr; ptr++) \
- { \
- char *digit_ptr = strchr(all_digits, toupper(*ptr)); \
- if (digit_ptr == NULL) break; \
- \
- unsigned t digit = (unsigned t)(digit_ptr - all_digits); \
- if (digit >= base) break; \
- \
- unsigned t new_result = result * (unsigned t)base + digit; \
- if (new_result < result) overflow = 1; \
- result = new_result; \
- } \
- \
- if (overflow) \
- { \
- errno = ERANGE; \
- return U##n##_MAX; \
- } \
- \
- if (endptr) *endptr = (char*)ptr; \
- return result; \
- }
- static const char all_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- DEFINE_XTOA(int, i, );
- DEFINE_XTOA(long, l, L);
- DEFINE_XTOA(long long, ll, LL);
- DEFINE_ATOX(long, LONG, l, L);
- DEFINE_ATOX(long long, LLONG, ll, LL);
- int atoi(const char *str)
- {
- return (int)strtol(str, NULL, 10);
- }
|