1 #include "iwconv.h"
2 #include <math.h>
3 #include <string.h>
4 #include <assert.h>
5 #include <ctype.h>
6 #include <errno.h>
7 #include <stdio.h>
8
9 // mapping of ASCII characters to hex values
10 static const uint8_t ascii2hex[] = {
11 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
12 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
13 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
14 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
15 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // !"#$%&'
16 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ()*+,-./
17 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567
18 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>?
19 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // @ABCDEFG
20 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // HIJKLMNO
21 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // PQRSTUVW
22 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // XYZ[\]^_
23 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // `abcdefg
24 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hijklmno
25 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pqrstuvw
26 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xyz{|}~.
27 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
28 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
33 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
34 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
38 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
40 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ........
43 };
44
iwhex2bin(const char * hex,int hexlen,char * out,int max)45 size_t iwhex2bin(const char *hex, int hexlen, char *out, int max) {
46 size_t pos = 0, vpos = 0;
47 uint8_t idx0, idx1;
48 while (pos < hexlen) {
49 if (!pos && (hexlen % 2)) { // first iteration + odd chars in hex
50 idx0 = '0'; // add '0' prefix
51 idx1 = hex[0];
52 pos += 1;
53 } else { // even chars in hex
54 idx0 = hex[pos];
55 idx1 = hex[pos + 1];
56 pos += 2;
57 }
58 out[vpos++] = (uint8_t) (ascii2hex[idx0] << 4) | ascii2hex[idx1];
59 if (vpos >= max) {
60 return vpos;
61 }
62 }
63 return vpos;
64 }
65
iwbin2hex(char * const hex,const size_t hex_maxlen,const unsigned char * const bin,const size_t bin_len)66 char* iwbin2hex(
67 char* const hex,
68 const size_t hex_maxlen,
69 const unsigned char* const bin,
70 const size_t bin_len
71 ) {
72 size_t i = (size_t) 0U;
73 unsigned int x;
74 int b;
75 int c;
76
77 if ((bin_len >= SIZE_MAX / 2) || (hex_maxlen <= bin_len * 2U)) {
78 //errx(2, "bin2hex length wrong");
79 return 0;
80 }
81 while (i < bin_len) {
82 c = bin[i] & 0xf;
83 b = bin[i] >> 4;
84 x = (unsigned char) (87U + c + (((c - 10U) >> 8) & ~38U)) << 8
85 | (unsigned char) (87U + b + (((b - 10U) >> 8) & ~38U));
86 hex[i * 2U] = (char) x;
87 x >>= 8;
88 hex[i * 2U + 1U] = (char) x;
89 i++;
90 }
91 hex[i * 2U] = 0U;
92 return hex;
93 }
94
iwitoa(int64_t v,char * buf,int max)95 int iwitoa(int64_t v, char *buf, int max) {
96 #define ITOA_SZSTEP(_step) if ((ret += (_step)) >= max) { \
97 *ptr = 0; \
98 return ret; \
99 }
100 int ret = 0;
101 char c, *ptr = buf, *p, *p1;
102 if (!v) {
103 ITOA_SZSTEP(1);
104 *ptr++ = '0';
105 *ptr = 0;
106 return ret;
107 }
108 // sign stuff
109 if (v < 0) {
110 if (IW_UNLIKELY(v == INT64_MIN)) {
111 return snprintf(buf, max, "-9223372036854775808");
112 } else {
113 v = -v;
114 ITOA_SZSTEP(1)
115 * ptr++ = '-';
116 }
117 }
118 // save start pointer
119 p = ptr;
120 while (v) {
121 if (++ret >= max) { //overflow condition
122 memmove(ptr, ptr + 1, p - ptr);
123 p--;
124 }
125 *p++ = '0' + v % 10;
126 v /= 10;
127 }
128 // save end pos
129 p1 = p;
130 // reverse result
131 while (p > ptr) {
132 c = *--p;
133 *p = *ptr;
134 *ptr++ = c;
135 }
136 ptr = p1;
137 *ptr = 0;
138 return ret;
139
140 #undef ITOA_SZSTEP
141 }
142
iwftoa(long double n,char s[static IWNUMBUF_SIZE])143 char* iwftoa(long double n, char s[static IWNUMBUF_SIZE]) {
144 static double PRECISION = 0.00000000000001;
145 // handle special cases
146 if (isnan(n)) {
147 strcpy(s, "nan");
148 } else if (isinf(n)) {
149 strcpy(s, "inf");
150 } else if (n == 0.0) { // -V550
151 strcpy(s, "0");
152 } else {
153 int digit, m, m1;
154 char *c = s;
155 int neg = (n < 0);
156 if (neg) {
157 n = -n;
158 }
159 // calculate magnitude
160 m = (int) log10l(n);
161 int useExp = (m >= 14 || (neg && m >= 9) || m <= -9);
162 if (neg) {
163 *(c++) = '-';
164 }
165 // set up for scientific notation
166 if (useExp) {
167 if (m < 0) {
168 m -= 1;
169 }
170 n = n / pow(10.0, m);
171 m1 = m;
172 m = 0;
173 }
174 if (m < 1) {
175 m = 0;
176 }
177 // convert the number
178 while (n > PRECISION || m >= 0) {
179 double weight = pow(10.0, m);
180 if ((weight > 0) && !isinf(weight)) {
181 digit = (int) floorl(n / weight);
182 n -= (digit * weight);
183 *(c++) = '0' + digit;
184 }
185 if ((m == 0) && (n > 0)) {
186 *(c++) = '.';
187 }
188 m--;
189 }
190 if (useExp) {
191 // convert the exponent
192 int i, j;
193 *(c++) = 'e';
194 if (m1 > 0) {
195 *(c++) = '+';
196 } else {
197 *(c++) = '-';
198 m1 = -m1;
199 }
200 m = 0;
201 while (m1 > 0) {
202 *(c++) = '0' + m1 % 10;
203 m1 /= 10;
204 m++;
205 }
206 c -= m;
207 for (i = 0, j = m - 1; i < j; i++, j--) {
208 c[i] ^= c[j];
209 c[j] ^= c[i];
210 c[i] ^= c[j];
211 }
212 c += m;
213 }
214 *(c) = '\0';
215 }
216 return s;
217 }
218
iwatoi(const char * str)219 int64_t iwatoi(const char *str) {
220 assert(str);
221 while (*str > '\0' && *str <= ' ') {
222 str++;
223 }
224 int sign = 1;
225 int64_t num = 0;
226 if (*str == '-') {
227 str++;
228 sign = -1;
229 } else if (*str == '+') {
230 str++;
231 }
232 if (!strcmp(str, "inf")) {
233 return (INT64_MAX * sign);
234 }
235 while (*str != '\0') {
236 if ((*str < '0') || (*str > '9')) {
237 break;
238 }
239 num = num * 10 + *str - '0';
240 str++;
241 }
242 return num * sign;
243 }
244
iwatoi2(const char * str,size_t len)245 int64_t iwatoi2(const char *str, size_t len) {
246 while (len > 0 && *str > '\0' && *str <= ' ') {
247 str++;
248 len--;
249 }
250 if (len == 0) {
251 return 0;
252 }
253 int sign = 1;
254 int64_t num = 0;
255 if (*str == '-') {
256 str++;
257 len--;
258 sign = -1;
259 } else if (*str == '+') {
260 str++;
261 len--;
262 }
263 if (!strcmp(str, "inf")) {
264 return (INT64_MAX * sign);
265 }
266 while (len > 0 && *str != '\0') {
267 if ((*str < '0') || (*str > '9')) {
268 break;
269 }
270 num = num * 10 + *str - '0';
271 str++;
272 len--;
273 }
274 return num * sign;
275 }
276
iwatof(const char * str)277 long double iwatof(const char *str) {
278 assert(str);
279 while (*str > '\0' && *str <= ' ') {
280 str++;
281 }
282 int sign = 1;
283 if (*str == '-') {
284 str++;
285 sign = -1;
286 } else if (*str == '+') {
287 str++;
288 }
289 if (!strcmp(str, "inf")) {
290 return HUGE_VAL * sign;
291 }
292 long double num = 0;
293 while (*str != '\0') {
294 if ((*str < '0') || (*str > '9')) {
295 break;
296 }
297 num = num * 10 + *str - '0';
298 str++;
299 }
300 if (*str == '.') {
301 str++;
302 long double fract = 0.0;
303 long double base = 10;
304 while (*str != '\0') {
305 if ((*str < '0') || (*str > '9')) {
306 break;
307 }
308 fract += (*str - '0') / base;
309 str++;
310 base *= 10;
311 }
312 num += fract;
313 }
314 if ((*str == 'e') || (*str == 'E')) {
315 str++;
316 num *= pow(10, iwatoi(str));
317 }
318 return num * sign;
319 }
320
321 /**
322 * Compare two strings as real numbers
323 */
iwafcmp(const char * aptr,int asiz,const char * bptr,int bsiz)324 int iwafcmp(const char *aptr, int asiz, const char *bptr, int bsiz) {
325 const unsigned char *arp = (const unsigned char*) aptr;
326 const unsigned char *brp = (const unsigned char*) bptr;
327 int alen = asiz, blen = bsiz;
328 int64_t anum = 0, bnum = 0;
329 int asign = 1, bsign = 1;
330
331 // A part
332 while (alen > 0 && (*arp <= ' ' || *arp == 0x7f)) {
333 arp++;
334 alen--;
335 }
336 if ((alen > 0) && (*arp == '-')) {
337 arp++;
338 alen--;
339 asign = -1;
340 }
341 while (alen > 0) {
342 int c = *arp;
343 if ((c < '0') || (c > '9')) {
344 break;
345 }
346 anum = anum * 10 + c - '0';
347 arp++;
348 alen--;
349 }
350 anum *= asign;
351
352 // B part
353 while (blen > 0 && (*brp <= ' ' || *brp == 0x7f)) {
354 brp++;
355 blen--;
356 }
357 if ((blen > 0) && (*brp == '-')) {
358 brp++;
359 blen--;
360 bsign = -1;
361 }
362 while (blen > 0) {
363 int c = *brp;
364 if ((c < '0') || (c > '9')) {
365 break;
366 }
367 bnum = bnum * 10 + c - '0';
368 brp++;
369 blen--;
370 }
371 bnum *= bsign;
372 if (anum < bnum) {
373 return -1;
374 }
375 if (anum > bnum) {
376 return 1;
377 }
378 if (((alen > 1) && (*arp == '.')) || ((blen > 1) && (*brp == '.'))) {
379 long double aflt = 0;
380 long double bflt = 0;
381 if ((alen > 1) && (*arp == '.')) {
382 arp++;
383 alen--;
384 if (alen > IWNUMBUF_SIZE) {
385 alen = IWNUMBUF_SIZE;
386 }
387 long double base = 10;
388 while (alen > 0) {
389 if ((*arp < '0') || (*arp > '9')) {
390 break;
391 }
392 aflt += (*arp - '0') / base;
393 arp++;
394 alen--;
395 base *= 10;
396 }
397 aflt *= asign;
398 }
399 if ((blen > 1) && (*brp == '.')) {
400 brp++;
401 blen--;
402 if (blen > IWNUMBUF_SIZE) {
403 blen = IWNUMBUF_SIZE;
404 }
405 long double base = 10;
406 while (blen > 0) {
407 if ((*brp < '0') || (*brp > '9')) {
408 break;
409 }
410 bflt += (*brp - '0') / base;
411 brp++;
412 blen--;
413 base *= 10;
414 }
415 bflt *= bsign;
416 }
417 if (aflt < bflt) {
418 return -1;
419 }
420 if (aflt > bflt) {
421 return 1;
422 }
423 }
424 int rv = strncmp(aptr, bptr, MIN(asiz, bsiz));
425 if (!rv) {
426 return (asiz - bsiz);
427 } else {
428 return rv;
429 }
430 }
431
432 /// MIT Licensed
433 /// Taken https://github.com/mattn/strtod/blob/master/strtod.c
434
skipwhite(const char * q)435 static const char* skipwhite(const char *q) {
436 const char *p = q;
437 while (isspace(*p)) {
438 ++p;
439 }
440 return p;
441 }
442
iwstrtod(const char * str,char ** end)443 double iwstrtod(const char *str, char **end) {
444 double d = 0.0;
445 int sign;
446 const char *p, *a;
447
448 a = p = str;
449 p = skipwhite(p);
450
451 /* decimal part */
452 sign = 1;
453 if (*p == '-') {
454 sign = -1;
455 ++p;
456 } else if (*p == '+') {
457 ++p;
458 }
459 if (isdigit(*p)) {
460 d = (double) (*p++ - '0');
461 while (*p && isdigit(*p)) {
462 d = d * 10.0 + (double) (*p - '0');
463 ++p;
464 }
465 a = p;
466 } else if (*p != '.') {
467 goto done;
468 }
469 d *= sign;
470
471 /* fraction part */
472 if (*p == '.') {
473 double f = 0.0;
474 double base = 0.1;
475 ++p;
476
477 if (isdigit(*p)) {
478 while (*p && isdigit(*p)) {
479 f += base * (*p - '0');
480 base /= 10.0;
481 ++p;
482 }
483 }
484 d += f * sign;
485 a = p;
486 }
487
488 /* exponential part */
489 if ((*p == 'E') || (*p == 'e')) {
490 int e = 0;
491 ++p;
492
493 sign = 1;
494 if (*p == '-') {
495 sign = -1;
496 ++p;
497 } else if (*p == '+') {
498 ++p;
499 }
500
501 if (isdigit(*p)) {
502 while (*p == '0') {
503 ++p;
504 }
505 if (*p == '\0') {
506 --p;
507 }
508 e = (*p++ - '0');
509 while (*p && isdigit(*p)) {
510 e = e * 10 + (*p - '0');
511 ++p;
512 }
513 e *= sign;
514 } else if (!isdigit(*(a - 1))) {
515 a = str;
516 goto done;
517 } else if (*p == 0) {
518 goto done;
519 }
520
521 if (d == 2.2250738585072011 && e == -308) {
522 d = 0.0;
523 a = p;
524 errno = ERANGE;
525 goto done;
526 }
527 if (d == 2.2250738585072012 && e <= -308) {
528 d *= 1.0e-308;
529 a = p;
530 goto done;
531 }
532 d *= pow(10.0, (double) e);
533 a = p;
534 } else if (p > str && !isdigit(*(p - 1))) {
535 a = str;
536 goto done;
537 }
538
539 done:
540 if (end) {
541 *end = (char*) a;
542 }
543 return d;
544 }
545