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