comparison jansson/src/strconv.c @ 0:0047655db1aa

jansson: import 2.7
author David Demelier <markand@malikania.fr>
date Wed, 24 Feb 2016 20:50:05 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:0047655db1aa
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 }