Use macros to allow prefixing C runtime library symbols
[monolithium.git] / libraries / mlcrt / src / numconv.c
1 /*
2  * numconv.c
3  *
4  * Copyright (C) 2019 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
20 #include <stdlib.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include "crt_priv.h"
24
25 #define DEFINE_XTOA(t, p, s)                                            \
26     char *__CRT_PUBLIC(p##toa)(t value, char *str, int base)            \
27     {                                                                   \
28         char *ptr = str;                                                \
29         if (base < 2 || base > 36) return NULL;                         \
30                                                                         \
31         if (value == 0##s)                                              \
32         {                                                               \
33             *ptr++ = '0';                                               \
34             *ptr++ = '\0';                                              \
35             return str;                                                 \
36         }                                                               \
37                                                                         \
38         if (value < 0##s)                                               \
39         {                                                               \
40             *ptr++ = '-';                                               \
41             value = -value;                                             \
42         }                                                               \
43                                                                         \
44         t temp;                                                         \
45         for (temp = value; temp > 0##s; temp /= (t)base) ptr++;         \
46         *ptr = '\0';                                                    \
47                                                                         \
48         while (value > 0##s)                                            \
49         {                                                               \
50             *--ptr = all_digits[value % (t)base];                       \
51             value /= (t)base;                                           \
52         }                                                               \
53                                                                         \
54         return str;                                                     \
55     }                                                                   \
56                                                                         \
57     char *__CRT_PUBLIC(u##p##toa)(unsigned t value, char *str, int base) \
58     {                                                                   \
59         char *ptr = str;                                                \
60         if (base < 2 || base > 36) return NULL;                         \
61                                                                         \
62         if (value == 0U##s)                                             \
63         {                                                               \
64             *ptr++ = '0';                                               \
65             *ptr++ = '\0';                                              \
66             return str;                                                 \
67         }                                                               \
68                                                                         \
69         unsigned t temp;                                                \
70         for (temp = value; temp > 0U##s; temp /= (unsigned t)base) ptr++; \
71         *ptr = '\0';                                                    \
72                                                                         \
73         while (value > 0U##s)                                           \
74         {                                                               \
75             *--ptr = all_digits[value % (unsigned t)base];              \
76             value /= (unsigned t)base;                                  \
77         }                                                               \
78                                                                         \
79         return str;                                                     \
80     }
81
82 #define DEFINE_ATOX(t, n, p, s)                                         \
83     t __CRT_PUBLIC(ato##p)(const char *str)                             \
84     {                                                                   \
85         return __CRT_PUBLIC(strto##p)(str, NULL, 10);                   \
86     }                                                                   \
87                                                                         \
88     t __CRT_PUBLIC(strto##p)(const char *str, char **endptr, int base)  \
89     {                                                                   \
90         const char *ptr;                                                \
91         t result = 0##s;                                                \
92         int overflow = 0, negative = 0;                                 \
93                                                                         \
94         if (base < 2 || base > 36) return 0;                            \
95                                                                         \
96         switch (*str)                                                   \
97         {                                                               \
98         case '-':                                                       \
99             negative = 1;                                               \
100         case '+':                                                       \
101             str++;                                                      \
102             break;                                                      \
103         }                                                               \
104                                                                         \
105         for (ptr = str; *ptr; ptr++)                                    \
106         {                                                               \
107             char *digit_ptr = __CRT_PUBLIC(strchr)(all_digits, __CRT_PUBLIC(toupper)(*ptr)); \
108             if (digit_ptr == NULL) break;                               \
109                                                                         \
110             t digit = (t)(digit_ptr - all_digits);                      \
111             if (digit >= base) break;                                   \
112                                                                         \
113             t new_result = result * (t)base + digit;                    \
114             if (new_result < result) overflow = 1;                      \
115             result = new_result;                                        \
116         }                                                               \
117                                                                         \
118         if (overflow)                                                   \
119         {                                                               \
120             __CRT_PUBLIC(errno) = ERANGE;                               \
121             return negative ? n##_MIN : n##_MAX;                        \
122         }                                                               \
123                                                                         \
124         if (negative) result = -result;                                 \
125         if (endptr) *endptr = (char*)ptr;                               \
126         return result;                                                  \
127     }                                                                   \
128                                                                         \
129     unsigned t __CRT_PUBLIC(strtou##p)(const char *str, char **endptr, int base) \
130     {                                                                   \
131         const char *ptr;                                                \
132         unsigned t result = 0UL;                                        \
133         int overflow = 0;                                               \
134                                                                         \
135         if (base < 2 || base > 36) return 0;                            \
136                                                                         \
137         for (ptr = str; *ptr; ptr++)                                    \
138         {                                                               \
139             char *digit_ptr = __CRT_PUBLIC(strchr)(all_digits, __CRT_PUBLIC(toupper)(*ptr)); \
140             if (digit_ptr == NULL) break;                               \
141                                                                         \
142             unsigned t digit = (unsigned t)(digit_ptr - all_digits);    \
143             if (digit >= base) break;                                   \
144                                                                         \
145             unsigned t new_result = result * (unsigned t)base + digit;  \
146             if (new_result < result) overflow = 1;                      \
147             result = new_result;                                        \
148         }                                                               \
149                                                                         \
150         if (overflow)                                                   \
151         {                                                               \
152             __CRT_PUBLIC(errno) = ERANGE;                               \
153             return U##n##_MAX;                                          \
154         }                                                               \
155                                                                         \
156         if (endptr) *endptr = (char*)ptr;                               \
157         return result;                                                  \
158     }
159
160 static const char all_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
161
162 DEFINE_XTOA(int, i, );
163 DEFINE_XTOA(long, l, L);
164 DEFINE_XTOA(long long, ll, LL);
165
166 DEFINE_ATOX(long, LONG, l, L);
167 DEFINE_ATOX(long long, LLONG, ll, LL);
168
169 int __CRT_PUBLIC(atoi)(const char *str)
170 {
171     return (int)__CRT_PUBLIC(strtol)(str, NULL, 10);
172 }