/* * numconv.c * * Copyright (C) 2017 Aleksandar Andrejevic * * 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 . */ #include #include #include #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); }