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