summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Haszlakiewicz <erh+git@nimenees.com>2013-02-26 21:09:10 -0600
committerEric Haszlakiewicz <erh+git@nimenees.com>2013-02-26 21:09:10 -0600
commit5b36a432c8b13f3534ade4c4b5ac721b6e35287a (patch)
tree624962b6a45b3c9bfa642c773aabe5fdab8a59e3
parent9b64c05ff9feb1cdb1e5ae5e134e5e6ff85dbb1b (diff)
parent32d149c8f60a5bdad4f678013a83d052ffd8ad43 (diff)
downloadjson-c-5b36a432c8b13f3534ade4c4b5ac721b6e35287a.tar.gz
Merge branch 'remicollet-issue-float'
Conflicts: json_util.c
-rw-r--r--configure.in4
-rw-r--r--json_object.c23
-rw-r--r--json_object.h4
-rw-r--r--json_tokener.c18
-rw-r--r--json_util.c5
-rw-r--r--json_util.h1
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/test_locale.c31
8 files changed, 85 insertions, 4 deletions
diff --git a/configure.in b/configure.in
index 5a3c0df..1a428b6 100644
--- a/configure.in
+++ b/configure.in
@@ -23,7 +23,7 @@ AM_CONDITIONAL(ENABLE_OLDNAME_COMPAT, [test "x${enable_oldname_compat}" != "xno"
AM_CONFIG_HEADER(config.h)
AM_CONFIG_HEADER(json_config.h)
AC_HEADER_STDC
-AC_CHECK_HEADERS(fcntl.h limits.h strings.h syslog.h unistd.h [sys/cdefs.h] [sys/param.h] stdarg.h)
+AC_CHECK_HEADERS(fcntl.h limits.h strings.h syslog.h unistd.h [sys/cdefs.h] [sys/param.h] stdarg.h locale.h)
AC_CHECK_HEADER(inttypes.h,[AC_DEFINE([JSON_C_HAVE_INTTYPES_H],[1],[Public define for json_inttypes.h])])
# Checks for typedefs, structures, and compiler characteristics.
@@ -35,7 +35,7 @@ AC_FUNC_VPRINTF
AC_FUNC_MEMCMP
AC_FUNC_MALLOC
AC_FUNC_REALLOC
-AC_CHECK_FUNCS(strcasecmp strdup strndup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp)
+AC_CHECK_FUNCS(strcasecmp strdup strndup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale)
#check if .section.gnu.warning accepts long strings (for __warn_references)
AC_LANG_PUSH([C])
diff --git a/json_object.c b/json_object.c
index 9dc6637..f2b5ce0 100644
--- a/json_object.c
+++ b/json_object.c
@@ -559,7 +559,28 @@ static int json_object_double_to_json_string(struct json_object* jso,
int level,
int flags)
{
- return sprintbuf(pb, "%f", jso->o.c_double);
+ char buf[128], *p, *q;
+ int size;
+
+ size = snprintf(buf, 128, "%f", jso->o.c_double);
+ p = strchr(buf, ',');
+ if (p) {
+ *p = '.';
+ } else {
+ p = strchr(buf, '.');
+ }
+ if (p && (flags & JSON_C_TO_STRING_NOZERO)) {
+ /* last useful digit, always keep 1 zero */
+ p++;
+ for (q=p ; *q ; q++) {
+ if (*q!='0') p=q;
+ }
+ /* drop trailing zeroes */
+ *(++p) = 0;
+ size = p-buf;
+ }
+ printbuf_memappend(pb, buf, size);
+ return size;
}
struct json_object* json_object_new_double(double d)
diff --git a/json_object.h b/json_object.h
index e18af8a..7085d0a 100644
--- a/json_object.h
+++ b/json_object.h
@@ -42,6 +42,10 @@ extern "C" {
* for an example of the format.
*/
#define JSON_C_TO_STRING_PRETTY (1<<1)
+/**
+ * A flag to drop trailing zero for float values
+ */
+#define JSON_C_TO_STRING_NOZERO (1<<2)
#undef FALSE
#define FALSE ((json_bool)0)
diff --git a/json_tokener.c b/json_tokener.c
index e0edca0..8040fea 100644
--- a/json_tokener.c
+++ b/json_tokener.c
@@ -31,6 +31,10 @@
#include "json_tokener.h"
#include "json_util.h"
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif /* HAVE_LOCALE_H */
+
#if !HAVE_STRDUP && defined(_MSC_VER)
/* MSC has the version as _strdup */
# define strdup _strdup
@@ -239,6 +243,13 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
{
struct json_object *obj = NULL;
char c = '\1';
+#ifdef HAVE_SETLOCALE
+ char *oldlocale=NULL, *tmplocale;
+
+ tmplocale = setlocale(LC_NUMERIC, NULL);
+ if (tmplocale) oldlocale = strdup(tmplocale);
+ setlocale(LC_NUMERIC, "C");
+#endif
tok->char_offset = 0;
tok->err = json_tokener_success;
@@ -597,7 +608,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
double numd;
if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) {
current = json_object_new_int64(num64);
- } else if(tok->is_double && sscanf(tok->pb->buf, "%lf", &numd) == 1) {
+ } else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0) {
current = json_object_new_double(numd);
} else {
tok->err = json_tokener_error_parse_number;
@@ -736,6 +747,11 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
tok->err = json_tokener_error_parse_eof;
}
+#ifdef HAVE_SETLOCALE
+ setlocale(LC_NUMERIC, oldlocale);
+ if (oldlocale) free(oldlocale);
+#endif
+
if (tok->err == json_tokener_success)
{
json_object *ret = json_object_get(current);
diff --git a/json_util.c b/json_util.c
index 194f290..111fa01 100644
--- a/json_util.c
+++ b/json_util.c
@@ -146,6 +146,11 @@ int json_object_to_file(char *filename, struct json_object *obj)
return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN);
}
+int json_parse_double(const char *buf, double *retval)
+{
+ return (sscanf(buf, "%lf", retval)==1 ? 0 : 1);
+}
+
/*
* Not all implementations of sscanf actually work properly.
* Check whether the one we're currently using does, and if
diff --git a/json_util.h b/json_util.h
index 277c3a7..b9a69c8 100644
--- a/json_util.h
+++ b/json_util.h
@@ -25,6 +25,7 @@ extern struct json_object* json_object_from_file(const char *filename);
extern int json_object_to_file(char *filename, struct json_object *obj);
extern int json_object_to_file_ext(char *filename, struct json_object *obj, int flags);
extern int json_parse_int64(const char *buf, int64_t *retval);
+extern int json_parse_double(const char *buf, double *retval);
/**
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0f06590..881c7e7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -11,6 +11,7 @@ check_PROGRAMS += test_parse_int64
check_PROGRAMS += test_null
check_PROGRAMS += test_cast
check_PROGRAMS += test_parse
+check_PROGRAMS += test_locale
test1_LDADD = $(LIBJSON_LA)
@@ -36,6 +37,8 @@ test_cast_LDADD = $(LIBJSON_LA)
test_parse_LDADD = $(LIBJSON_LA)
+test_locale_LDADD = $(LIBJSON_LA)
+
TESTS = test1.test test2.test test4.test testReplaceExisting.test parse_int64.test test_null.test test_cast.test test_parse.test
TESTS+= test_printbuf.test
diff --git a/tests/test_locale.c b/tests/test_locale.c
new file mode 100644
index 0000000..da070cf
--- /dev/null
+++ b/tests/test_locale.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+#include "config.h"
+#include "json.h"
+#include "json_tokener.h"
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif /* HAVE_LOCALE_H */
+
+int main(int argc, char **argv)
+{
+ json_object *new_obj;
+#ifdef HAVE_SETLOCALE
+ setlocale(LC_NUMERIC, "de_DE");
+#else
+ printf("No locale\n");
+#endif
+
+ MC_SET_DEBUG(1);
+
+ new_obj = json_tokener_parse("[1.2,3.4,123456.78,5.0,2.3e10]");
+ printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
+ printf("new_obj.to_string()=%s\n", json_object_to_json_string_ext(new_obj,JSON_C_TO_STRING_NOZERO));
+ json_object_put(new_obj);
+}
+