| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- #include <assert.h>
- #include <errno.h>
- #include <stdio.h>
- #include <string.h>
- #include "jansson_private.h"
- #include "strbuffer.h"
- #if JSON_HAVE_LOCALECONV
- #include <locale.h>
- /*
- - This code assumes that the decimal separator is exactly one
- character.
- - If setlocale() is called by another thread between the call to
- localeconv() and the call to sprintf() or strtod(), the result may
- be wrong. setlocale() is not thread-safe and should not be used
- this way. Multi-threaded programs should use uselocale() instead.
- */
- static void to_locale(strbuffer_t *strbuffer)
- {
- const char *point;
- char *pos;
- point = localeconv()->decimal_point;
- if(*point == '.') {
- /* No conversion needed */
- return;
- }
- pos = strchr(strbuffer->value, '.');
- if(pos)
- *pos = *point;
- }
- static void from_locale(char *buffer)
- {
- const char *point;
- char *pos;
- point = localeconv()->decimal_point;
- if(*point == '.') {
- /* No conversion needed */
- return;
- }
- pos = strchr(buffer, *point);
- if(pos)
- *pos = '.';
- }
- #endif
- int jsonp_strtod(strbuffer_t *strbuffer, double *out)
- {
- double value;
- char *end;
- #if JSON_HAVE_LOCALECONV
- to_locale(strbuffer);
- #endif
- errno = 0;
- value = strtod(strbuffer->value, &end);
- assert(end == strbuffer->value + strbuffer->length);
- if(errno == ERANGE && value != 0) {
- /* Overflow */
- return -1;
- }
- *out = value;
- return 0;
- }
- int jsonp_dtostr(char *buffer, size_t size, double value)
- {
- int ret;
- char *start, *end;
- size_t length;
- ret = snprintf(buffer, size, "%.17g", value);
- if(ret < 0)
- return -1;
- length = (size_t)ret;
- if(length >= size)
- return -1;
- #if JSON_HAVE_LOCALECONV
- from_locale(buffer);
- #endif
- /* Make sure there's a dot or 'e' in the output. Otherwise
- a real is converted to an integer when decoding */
- if(strchr(buffer, '.') == NULL &&
- strchr(buffer, 'e') == NULL)
- {
- if(length + 3 >= size) {
- /* No space to append ".0" */
- return -1;
- }
- buffer[length] = '.';
- buffer[length + 1] = '0';
- buffer[length + 2] = '\0';
- length += 2;
- }
- /* Remove leading '+' from positive exponent. Also remove leading
- zeros from exponents (added by some printf() implementations) */
- start = strchr(buffer, 'e');
- if(start) {
- start++;
- end = start + 1;
- if(*start == '-')
- start++;
- while(*end == '0')
- end++;
- if(end != start) {
- memmove(start, end, length - (size_t)(end - buffer));
- length -= (size_t)(end - start);
- }
- }
- return (int)length;
- }
|