Mercurial > malikania
comparison extern/jansson/src/strconv.c @ 0:8991989c4708
Initial import
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 22 Mar 2016 18:26:05 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:8991989c4708 |
---|---|
1 #include <assert.h> | |
2 #include <errno.h> | |
3 #include <stdio.h> | |
4 #include <string.h> | |
5 #include <math.h> | |
6 #include "jansson_private.h" | |
7 #include "strbuffer.h" | |
8 | |
9 /* need jansson_private_config.h to get the correct snprintf */ | |
10 #ifdef HAVE_CONFIG_H | |
11 #include <jansson_private_config.h> | |
12 #endif | |
13 | |
14 #if JSON_HAVE_LOCALECONV | |
15 #include <locale.h> | |
16 | |
17 /* | |
18 - This code assumes that the decimal separator is exactly one | |
19 character. | |
20 | |
21 - If setlocale() is called by another thread between the call to | |
22 localeconv() and the call to sprintf() or strtod(), the result may | |
23 be wrong. setlocale() is not thread-safe and should not be used | |
24 this way. Multi-threaded programs should use uselocale() instead. | |
25 */ | |
26 | |
27 static void to_locale(strbuffer_t *strbuffer) | |
28 { | |
29 const char *point; | |
30 char *pos; | |
31 | |
32 point = localeconv()->decimal_point; | |
33 if(*point == '.') { | |
34 /* No conversion needed */ | |
35 return; | |
36 } | |
37 | |
38 pos = strchr(strbuffer->value, '.'); | |
39 if(pos) | |
40 *pos = *point; | |
41 } | |
42 | |
43 static void from_locale(char *buffer) | |
44 { | |
45 const char *point; | |
46 char *pos; | |
47 | |
48 point = localeconv()->decimal_point; | |
49 if(*point == '.') { | |
50 /* No conversion needed */ | |
51 return; | |
52 } | |
53 | |
54 pos = strchr(buffer, *point); | |
55 if(pos) | |
56 *pos = '.'; | |
57 } | |
58 #endif | |
59 | |
60 int jsonp_strtod(strbuffer_t *strbuffer, double *out) | |
61 { | |
62 double value; | |
63 char *end; | |
64 | |
65 #if JSON_HAVE_LOCALECONV | |
66 to_locale(strbuffer); | |
67 #endif | |
68 | |
69 errno = 0; | |
70 value = strtod(strbuffer->value, &end); | |
71 assert(end == strbuffer->value + strbuffer->length); | |
72 | |
73 if((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) { | |
74 /* Overflow */ | |
75 return -1; | |
76 } | |
77 | |
78 *out = value; | |
79 return 0; | |
80 } | |
81 | |
82 int jsonp_dtostr(char *buffer, size_t size, double value, int precision) | |
83 { | |
84 int ret; | |
85 char *start, *end; | |
86 size_t length; | |
87 | |
88 if (precision == 0) | |
89 precision = 17; | |
90 | |
91 ret = snprintf(buffer, size, "%.*g", precision, value); | |
92 if(ret < 0) | |
93 return -1; | |
94 | |
95 length = (size_t)ret; | |
96 if(length >= size) | |
97 return -1; | |
98 | |
99 #if JSON_HAVE_LOCALECONV | |
100 from_locale(buffer); | |
101 #endif | |
102 | |
103 /* Make sure there's a dot or 'e' in the output. Otherwise | |
104 a real is converted to an integer when decoding */ | |
105 if(strchr(buffer, '.') == NULL && | |
106 strchr(buffer, 'e') == NULL) | |
107 { | |
108 if(length + 3 >= size) { | |
109 /* No space to append ".0" */ | |
110 return -1; | |
111 } | |
112 buffer[length] = '.'; | |
113 buffer[length + 1] = '0'; | |
114 buffer[length + 2] = '\0'; | |
115 length += 2; | |
116 } | |
117 | |
118 /* Remove leading '+' from positive exponent. Also remove leading | |
119 zeros from exponents (added by some printf() implementations) */ | |
120 start = strchr(buffer, 'e'); | |
121 if(start) { | |
122 start++; | |
123 end = start + 1; | |
124 | |
125 if(*start == '-') | |
126 start++; | |
127 | |
128 while(*end == '0') | |
129 end++; | |
130 | |
131 if(end != start) { | |
132 memmove(start, end, length - (size_t)(end - buffer)); | |
133 length -= (size_t)(end - start); | |
134 } | |
135 } | |
136 | |
137 return (int)length; | |
138 } |