proxmark3/client/jansson/strconv.c

141 lines
3.2 KiB
C
Raw Normal View History

2018-11-12 21:00:35 +08:00
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#ifdef __MINGW32__
#undef __NO_ISOCEXT /* ensure stdlib.h will declare prototypes for mingw own 'strtod' replacement, called '__strtod' */
#endif
#include "jansson_private.h"
#include "strbuffer.h"
/* need jansson_private_config.h to get the correct snprintf */
#ifdef HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#ifdef __MINGW32__
#define strtod __strtod
#endif
#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) {
2018-11-12 21:00:35 +08:00
const char *point;
char *pos;
point = localeconv()->decimal_point;
2019-03-10 07:00:59 +08:00
if (*point == '.') {
2018-11-12 21:00:35 +08:00
/* No conversion needed */
return;
}
pos = strchr(strbuffer->value, '.');
2019-03-10 07:00:59 +08:00
if (pos)
2018-11-12 21:00:35 +08:00
*pos = *point;
}
static void from_locale(char *buffer) {
2018-11-12 21:00:35 +08:00
const char *point;
char *pos;
point = localeconv()->decimal_point;
2019-03-10 07:00:59 +08:00
if (*point == '.') {
2018-11-12 21:00:35 +08:00
/* No conversion needed */
return;
}
pos = strchr(buffer, *point);
2019-03-10 07:00:59 +08:00
if (pos)
2018-11-12 21:00:35 +08:00
*pos = '.';
}
#endif
int jsonp_strtod(strbuffer_t *strbuffer, double *out) {
2018-11-12 21:00:35 +08:00
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);
2019-03-10 07:00:59 +08:00
if ((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) {
2018-11-12 21:00:35 +08:00
/* Overflow */
return -1;
}
*out = value;
return 0;
}
int jsonp_dtostr(char *buffer, size_t size, double value, int precision) {
2018-11-12 21:00:35 +08:00
int ret;
char *start, *end;
size_t length;
if (precision == 0)
precision = 17;
ret = snprintf(buffer, size, "%.*g", precision, value);
2019-03-10 07:00:59 +08:00
if (ret < 0)
2018-11-12 21:00:35 +08:00
return -1;
length = (size_t)ret;
2019-03-10 07:00:59 +08:00
if (length >= size)
2018-11-12 21:00:35 +08:00
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 */
2019-03-10 07:00:59 +08:00
if (strchr(buffer, '.') == NULL &&
strchr(buffer, 'e') == NULL) {
2019-03-10 07:00:59 +08:00
if (length + 3 >= size) {
2018-11-12 21:00:35 +08:00
/* 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');
2019-03-10 07:00:59 +08:00
if (start) {
2018-11-12 21:00:35 +08:00
start++;
end = start + 1;
2019-03-10 07:00:59 +08:00
if (*start == '-')
2018-11-12 21:00:35 +08:00
start++;
2019-03-10 07:00:59 +08:00
while (*end == '0')
2018-11-12 21:00:35 +08:00
end++;
2019-03-10 07:00:59 +08:00
if (end != start) {
2018-11-12 21:00:35 +08:00
memmove(start, end, length - (size_t)(end - buffer));
length -= (size_t)(end - start);
}
}
return (int)length;
}