xref: /php-src/ext/dom/lexbor/lexbor/core/conv.c (revision f0934090)
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