1 /*
2 * Copyright (C) 2018 Alexander Borisov
3 *
4 * Author: Alexander Borisov <borisov@lexbor.com>
5 */
6
7 #include <math.h>
8 #include <float.h>
9
10 #include "lexbor/core/conv.h"
11 #include "lexbor/core/dtoa.h"
12 #include "lexbor/core/strtod.h"
13
14
15 size_t
lexbor_conv_float_to_data(double num,lxb_char_t * buf,size_t len)16 lexbor_conv_float_to_data(double num, lxb_char_t *buf, size_t len)
17 {
18 return lexbor_dtoa(num, buf, len);
19 }
20
21 size_t
lexbor_conv_long_to_data(long num,lxb_char_t * buf,size_t len)22 lexbor_conv_long_to_data(long num, lxb_char_t *buf, size_t len)
23 {
24 return lexbor_conv_int64_to_data((int64_t) num, buf, len);
25 }
26
27 size_t
lexbor_conv_int64_to_data(int64_t num,lxb_char_t * buf,size_t len)28 lexbor_conv_int64_to_data(int64_t num, lxb_char_t *buf, size_t len)
29 {
30 int64_t tmp;
31 size_t have_minus, i, length;
32
33 static const lxb_char_t *digits = (const lxb_char_t *) "0123456789";
34
35 if (num != 0) {
36 tmp = num;
37 length = 0;
38 have_minus = 0;
39
40 if (num < 0) {
41 length = 1;
42 num = -num;
43 have_minus = 1;
44 }
45
46 while (tmp != 0) {
47 length += 1;
48 tmp /= 10;
49 }
50
51 /* length += (size_t) floor(log10(labs((long) num))) + 1; */
52 }
53 else {
54 if (len > 0) {
55 buf[0] = '0';
56 return 1;
57 }
58
59 return 0;
60 }
61
62 if (len < length) {
63 i = (length + have_minus) - len;
64
65 while (i != have_minus) {
66 i -= 1;
67 num /= 10;
68 }
69
70 length = len;
71 }
72
73 if (have_minus) {
74 buf[0] = '-';
75 }
76
77 i = length;
78 buf[length] = '\0';
79
80 while (i != have_minus) {
81 i -= 1;
82 buf[i] = digits[ num % 10 ];
83 num /= 10;
84 }
85
86 return length;
87 }
88
89 double
lexbor_conv_data_to_double(const lxb_char_t ** start,size_t len)90 lexbor_conv_data_to_double(const lxb_char_t **start, size_t len)
91 {
92 int exponent, exp, insignf;
93 lxb_char_t c, *pos;
94 bool minus, ex_minus;
95 double num;
96 const lxb_char_t *e, *p, *last, *end;
97 lxb_char_t data[128];
98
99 end = *start + len;
100
101 exponent = 0;
102 insignf = 0;
103
104 pos = data;
105 last = data + sizeof(data);
106
107 minus = false;
108
109 switch (**start) {
110 case '-':
111 minus = true;
112 /* fall through */
113 case '+':
114 (*start)++;
115 /* fall through */
116 default:
117 break;
118 }
119
120 for (p = *start; p < end; p++) {
121 /* Values less than '0' become >= 208. */
122 c = *p - '0';
123
124 if (c > 9) {
125 break;
126 }
127
128 if (pos < last) {
129 *pos++ = *p;
130 }
131 else {
132 insignf++;
133 }
134 }
135
136 /* Do not emit a '.', but adjust the exponent instead. */
137 if (p < end && *p == '.') {
138
139 for (p++; p < end; p++) {
140 /* Values less than '0' become >= 208. */
141 c = *p - '0';
142
143 if (c > 9) {
144 break;
145 }
146
147 if (pos < last) {
148 *pos++ = *p;
149 exponent--;
150 }
151 else {
152 /* Ignore insignificant digits in the fractional part. */
153 }
154 }
155 }
156
157 e = p + 1;
158
159 if (e < end && (*p == 'e' || *p == 'E')) {
160 ex_minus = 0;
161
162 if (e + 1 < end) {
163 if (*e == '-') {
164 e++;
165 ex_minus = 1;
166 }
167 else if (*e == '+') {
168 e++;
169 }
170 }
171
172 /* Values less than '0' become >= 208. */
173 c = *e - '0';
174
175 if (c <= 9) {
176 exp = c;
177
178 for (p = e + 1; p < end; p++) {
179 /* Values less than '0' become >= 208. */
180 c = *p - '0';
181
182 if (c > 9) {
183 break;
184 }
185
186 exp = exp * 10 + c;
187 }
188
189 exponent += ex_minus ? -exp : exp;
190 }
191 }
192
193 *start = p;
194
195 exponent += insignf;
196
197 num = lexbor_strtod_internal(data, pos - data, exponent);
198
199 if (minus) {
200 num = -num;
201 }
202
203 return num;
204 }
205
206 unsigned long
lexbor_conv_data_to_ulong(const lxb_char_t ** data,size_t length)207 lexbor_conv_data_to_ulong(const lxb_char_t **data, size_t length)
208 {
209 const lxb_char_t *p = *data;
210 const lxb_char_t *end = p + length;
211 unsigned long last_number = 0, number = 0;
212
213 for (; p < end; p++) {
214 if (*p < '0' || *p > '9') {
215 goto done;
216 }
217
218 number = (*p - '0') + number * 10;
219
220 if (last_number > number) {
221 *data = p - 1;
222 return last_number;
223 }
224
225 last_number = number;
226 }
227
228 done:
229
230 *data = p;
231
232 return number;
233 }
234
235 long
lexbor_conv_data_to_long(const lxb_char_t ** data,size_t length)236 lexbor_conv_data_to_long(const lxb_char_t **data, size_t length)
237 {
238 bool minus;
239 const lxb_char_t *p;
240 const lxb_char_t *end;
241 unsigned long n = 0, number = 0;
242
243 minus = false;
244 p = *data;
245 end = p + length;
246
247 switch (*p) {
248 case '-':
249 minus = true;
250 /* fall through */
251 case '+':
252 p++;
253 /* fall through */
254 default:
255 break;
256 }
257
258 for (; p < end; p++) {
259 if (*p < '0' || *p > '9') {
260 break;
261 }
262
263 n = (*p - '0') + number * 10;
264
265 if (n > LONG_MAX) {
266 p -= 1;
267 break;
268 }
269
270 number = n;
271 }
272
273 *data = p;
274
275 return (minus) ? -number : number;
276 }
277
278 unsigned
lexbor_conv_data_to_uint(const lxb_char_t ** data,size_t length)279 lexbor_conv_data_to_uint(const lxb_char_t **data, size_t length)
280 {
281 const lxb_char_t *p = *data;
282 const lxb_char_t *end = p + length;
283 unsigned last_number = 0, number = 0;
284
285 for (; p < end; p++) {
286 if (*p < '0' || *p > '9') {
287 goto done;
288 }
289
290 number = (*p - '0') + number * 10;
291
292 if (last_number > number) {
293 *data = p - 1;
294 return last_number;
295 }
296
297 last_number = number;
298 }
299
300 done:
301
302 *data = p;
303
304 return number;
305 }
306
307 size_t
lexbor_conv_dec_to_hex(uint32_t number,lxb_char_t * out,size_t length)308 lexbor_conv_dec_to_hex(uint32_t number, lxb_char_t *out, size_t length)
309 {
310 lxb_char_t c;
311 size_t len;
312 uint32_t tmp;
313
314 static const lxb_char_t map_str[] = "0123456789abcdef";
315
316 if(number != 0) {
317 tmp = number;
318 len = 0;
319
320 while (tmp != 0) {
321 len += 1;
322 tmp /= 16;
323 }
324
325 /* len = (size_t) floor(log10(labs((long) number))) + 1; */
326 }
327 else {
328 if (length > 0) {
329 out[0] = '0';
330 return 1;
331 }
332
333 return 0;
334 }
335
336 length = len - 1;
337
338 while (number != 0) {
339 c = number % 16;
340 number = number / 16;
341
342 out[ length-- ] = map_str[c];
343 }
344
345 return len;
346 }
347