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