diff options
author | Mark Pulford <mark@kyne.com.au> | 2011-12-29 23:03:58 +1030 |
---|---|---|
committer | Mark Pulford <mark@kyne.com.au> | 2012-03-04 18:54:34 +1030 |
commit | ca42b9a996f9046ba3876ad8a81cda1d935b39cf (patch) | |
tree | 229cc0e408e28abc882778c68496c87af0d781ba | |
parent | 8eecc878e0560461ef42bd3cd8d6dfe33cf148e8 (diff) | |
download | lua-cjson-ca42b9a996f9046ba3876ad8a81cda1d935b39cf.tar.gz lua-cjson-ca42b9a996f9046ba3876ad8a81cda1d935b39cf.tar.bz2 lua-cjson-ca42b9a996f9046ba3876ad8a81cda1d935b39cf.zip |
Use internal dtoa/strtod for double conversion
The internal Lua CJSON dtoa/strtod routines have locale support
disabled. This avoids problems under locales with comma decimal
separators.
Build changes:
- CMake: Check for big endian architectures
- Makefile: Provide option to build with dtoa.c
Modifications to dtoa.c:
- Include locale dtoa_config.h configuration
- Rename Infinity/NaN to inf/nan to match common C libraries
- Rename strtod() -> internal_strtod() to prevent conflict with libc
function
Modifications to g_fmt.c:
- Return output string length (instead of original buffer pointer)
- Provide precision as an argument to g_fmt()
- Silence compilations warnings from vendor source
- while(a = b)
- Unused label "done:"
- Only swap to scientific notation when once the number of decimal
digits required exceeds the precision available. This matches
standard printf format %g.
- Display a "0" in front of numbers < 1.
-rw-r--r-- | CMakeLists.txt | 6 | ||||
-rw-r--r-- | Makefile | 21 | ||||
-rw-r--r-- | dtoa.c | 10 | ||||
-rw-r--r-- | dtoa_config.h | 66 | ||||
-rw-r--r-- | fpconv.h | 10 | ||||
-rw-r--r-- | g_fmt.c | 26 |
6 files changed, 123 insertions, 16 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d8a420..ffc718b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
@@ -11,6 +11,12 @@ set(CMAKE_BUILD_TYPE Release) | |||
11 | find_package(Lua51 REQUIRED) | 11 | find_package(Lua51 REQUIRED) |
12 | include_directories(${LUA_INCLUDE_DIR}) | 12 | include_directories(${LUA_INCLUDE_DIR}) |
13 | 13 | ||
14 | include(TestBigEndian) | ||
15 | TEST_BIG_ENDIAN(BIG_ENDIAN) | ||
16 | if(HAVE_BIG_ENDIAN) | ||
17 | add_definitions(-DIEEE_BIG_ENDIAN) | ||
18 | endif() | ||
19 | |||
14 | # Handle platforms missing isinf() macro (Eg, some Solaris systems). | 20 | # Handle platforms missing isinf() macro (Eg, some Solaris systems). |
15 | include(CheckSymbolExists) | 21 | include(CheckSymbolExists) |
16 | CHECK_SYMBOL_EXISTS(isinf math.h HAVE_ISINF) | 22 | CHECK_SYMBOL_EXISTS(isinf math.h HAVE_ISINF) |
@@ -4,6 +4,10 @@ | |||
4 | ## DISABLE_CJSON_GLOBAL: Do not store module is "cjson" global. | 4 | ## DISABLE_CJSON_GLOBAL: Do not store module is "cjson" global. |
5 | ## DISABLE_INVALID_NUMBERS: Permanently disable invalid JSON numbers: | 5 | ## DISABLE_INVALID_NUMBERS: Permanently disable invalid JSON numbers: |
6 | ## NaN, Infinity, hex. | 6 | ## NaN, Infinity, hex. |
7 | ## | ||
8 | ## Optional built-in number conversion uses the following defines: | ||
9 | ## USE_INTERNAL_DTOA: Use builtin strtod/dtoa for numeric conversions. | ||
10 | ## IEEE_BIG_ENDIAN: Required on big endian architectures. | ||
7 | 11 | ||
8 | ##### Build defaults ##### | 12 | ##### Build defaults ##### |
9 | LUA_VERSION = 5.1 | 13 | LUA_VERSION = 5.1 |
@@ -42,10 +46,25 @@ INSTALL_CMD = install | |||
42 | #CJSON_CFLAGS = -DDISABLE_INVALID_NUMBERS | 46 | #CJSON_CFLAGS = -DDISABLE_INVALID_NUMBERS |
43 | #CJSON_LDFLAGS = -shared -L$(PREFIX)/lib -llua51 | 47 | #CJSON_LDFLAGS = -shared -L$(PREFIX)/lib -llua51 |
44 | 48 | ||
49 | ##### Use built in number conversion (optional) ##### | ||
50 | |||
51 | ## Enable built in number conversion | ||
52 | #FPCONV_OBJS = g_fmt.o dtoa.o | ||
53 | #CJSON_CFLAGS += -DUSE_INTERNAL_DTOA | ||
54 | |||
55 | ## Compile built in number conversion for big endian architectures | ||
56 | #CJSON_CFLAGS += -DIEEE_BIG_ENDIAN | ||
57 | |||
58 | ## Compile built in number conversion to support multi-threaded | ||
59 | ## applications (recommended) | ||
60 | #CJSON_CFLAGS += -pthread -DMULTIPLE_THREADS | ||
61 | #CJSON_LDFLAGS += -pthread | ||
62 | |||
45 | ##### End customisable sections ##### | 63 | ##### End customisable sections ##### |
46 | 64 | ||
47 | BUILD_CFLAGS = -I$(LUA_INCLUDE_DIR) $(CJSON_CFLAGS) | 65 | BUILD_CFLAGS = -I$(LUA_INCLUDE_DIR) $(CJSON_CFLAGS) |
48 | OBJS := lua_cjson.o strbuf.o fpconv.o | 66 | FPCONV_OBJS ?= fpconv.o |
67 | OBJS := lua_cjson.o strbuf.o $(FPCONV_OBJS) | ||
49 | 68 | ||
50 | .PHONY: all clean install package doc | 69 | .PHONY: all clean install package doc |
51 | 70 | ||
@@ -185,6 +185,8 @@ | |||
185 | * used for input more than STRTOD_DIGLIM digits long (default 40). | 185 | * used for input more than STRTOD_DIGLIM digits long (default 40). |
186 | */ | 186 | */ |
187 | 187 | ||
188 | #include "dtoa_config.h" | ||
189 | |||
188 | #ifndef Long | 190 | #ifndef Long |
189 | #define Long long | 191 | #define Long long |
190 | #endif | 192 | #endif |
@@ -523,7 +525,7 @@ BCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflc | |||
523 | #define Kmax 7 | 525 | #define Kmax 7 |
524 | 526 | ||
525 | #ifdef __cplusplus | 527 | #ifdef __cplusplus |
526 | extern "C" double strtod(const char *s00, char **se); | 528 | extern "C" double fpconv_strtod(const char *s00, char **se); |
527 | extern "C" char *dtoa(double d, int mode, int ndigits, | 529 | extern "C" char *dtoa(double d, int mode, int ndigits, |
528 | int *decpt, int *sign, char **rve); | 530 | int *decpt, int *sign, char **rve); |
529 | #endif | 531 | #endif |
@@ -2471,7 +2473,7 @@ retlow1: | |||
2471 | #endif /* NO_STRTOD_BIGCOMP */ | 2473 | #endif /* NO_STRTOD_BIGCOMP */ |
2472 | 2474 | ||
2473 | double | 2475 | double |
2474 | strtod | 2476 | fpconv_strtod |
2475 | #ifdef KR_headers | 2477 | #ifdef KR_headers |
2476 | (s00, se) CONST char *s00; char **se; | 2478 | (s00, se) CONST char *s00; char **se; |
2477 | #else | 2479 | #else |
@@ -3746,9 +3748,9 @@ dtoa | |||
3746 | *decpt = 9999; | 3748 | *decpt = 9999; |
3747 | #ifdef IEEE_Arith | 3749 | #ifdef IEEE_Arith |
3748 | if (!word1(&u) && !(word0(&u) & 0xfffff)) | 3750 | if (!word1(&u) && !(word0(&u) & 0xfffff)) |
3749 | return nrv_alloc("Infinity", rve, 8); | 3751 | return nrv_alloc("inf", rve, 8); |
3750 | #endif | 3752 | #endif |
3751 | return nrv_alloc("NaN", rve, 3); | 3753 | return nrv_alloc("nan", rve, 3); |
3752 | } | 3754 | } |
3753 | #endif | 3755 | #endif |
3754 | #ifdef IBM | 3756 | #ifdef IBM |
diff --git a/dtoa_config.h b/dtoa_config.h new file mode 100644 index 0000000..294351d --- /dev/null +++ b/dtoa_config.h | |||
@@ -0,0 +1,66 @@ | |||
1 | #ifndef _DTOA_CONFIG_H | ||
2 | #define _DTOA_CONFIG_H | ||
3 | |||
4 | #include <stdio.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <stdint.h> | ||
7 | |||
8 | /* Ensure dtoa.c does not USE_LOCALE. Lua CJSON must not use locale | ||
9 | * aware conversion routines. */ | ||
10 | #undef USE_LOCALE | ||
11 | |||
12 | /* dtoa.c should not touch errno, Lua CJSON does not use it, and it | ||
13 | * may not be threadsafe */ | ||
14 | #define NO_ERRNO | ||
15 | |||
16 | #define Long int32_t | ||
17 | #define ULong uint32_t | ||
18 | #define Llong int64_t | ||
19 | #define ULLong uint64_t | ||
20 | |||
21 | #ifdef IEEE_BIG_ENDIAN | ||
22 | #define IEEE_MC68k | ||
23 | #else | ||
24 | #define IEEE_8087 | ||
25 | #endif | ||
26 | |||
27 | #define MALLOC(n) xmalloc(n) | ||
28 | |||
29 | static void *xmalloc(size_t size) | ||
30 | { | ||
31 | void *p; | ||
32 | |||
33 | p = malloc(size); | ||
34 | if (!p) { | ||
35 | fprintf(stderr, "Out of memory"); | ||
36 | abort(); | ||
37 | } | ||
38 | |||
39 | return p; | ||
40 | } | ||
41 | |||
42 | #ifdef MULTIPLE_THREADS | ||
43 | |||
44 | /* Enable locking to support multi-threaded applications */ | ||
45 | |||
46 | #include <pthread.h> | ||
47 | |||
48 | static pthread_mutex_t private_dtoa_lock[2] = { | ||
49 | PTHREAD_MUTEX_INITIALIZER, | ||
50 | PTHREAD_MUTEX_INITIALIZER | ||
51 | }; | ||
52 | |||
53 | #define ACQUIRE_DTOA_LOCK(n) do { \ | ||
54 | pthread_mutex_lock(&private_dtoa_lock[n]); \ | ||
55 | } while (0) | ||
56 | |||
57 | #define FREE_DTOA_LOCK(n) do { \ | ||
58 | pthread_mutex_unlock(&private_dtoa_lock[n]); \ | ||
59 | } while (0) | ||
60 | |||
61 | #endif /* MULTIPLE_THREADS */ | ||
62 | |||
63 | #endif /* _DTOA_CONFIG_H */ | ||
64 | |||
65 | /* vi:ai et sw=4 ts=4: | ||
66 | */ | ||
@@ -6,7 +6,15 @@ | |||
6 | * -1.7976931348623e+308 */ | 6 | * -1.7976931348623e+308 */ |
7 | # define FPCONV_G_FMT_BUFSIZE 32 | 7 | # define FPCONV_G_FMT_BUFSIZE 32 |
8 | 8 | ||
9 | extern void fpconv_init(); | 9 | #ifdef USE_INTERNAL_DTOA |
10 | static inline void fpconv_init() | ||
11 | { | ||
12 | /* Do nothing - not required */ | ||
13 | } | ||
14 | #else | ||
15 | extern inline void fpconv_init(); | ||
16 | #endif | ||
17 | |||
10 | extern int fpconv_g_fmt(char*, double, int); | 18 | extern int fpconv_g_fmt(char*, double, int); |
11 | extern double fpconv_strtod(const char*, char**); | 19 | extern double fpconv_strtod(const char*, char**); |
12 | 20 | ||
@@ -26,14 +26,14 @@ | |||
26 | extern "C" { | 26 | extern "C" { |
27 | #endif | 27 | #endif |
28 | extern char *dtoa(double, int, int, int *, int *, char **); | 28 | extern char *dtoa(double, int, int, int *, int *, char **); |
29 | extern char *g_fmt(char *, double); | 29 | extern int g_fmt(char *, double, int); |
30 | extern void freedtoa(char*); | 30 | extern void freedtoa(char*); |
31 | #ifdef __cplusplus | 31 | #ifdef __cplusplus |
32 | } | 32 | } |
33 | #endif | 33 | #endif |
34 | 34 | ||
35 | char * | 35 | int |
36 | g_fmt(register char *b, double x) | 36 | fpconv_g_fmt(char *b, double x, int precision) |
37 | { | 37 | { |
38 | register int i, k; | 38 | register int i, k; |
39 | register char *s; | 39 | register char *s; |
@@ -48,18 +48,21 @@ g_fmt(register char *b, double x) | |||
48 | goto done; | 48 | goto done; |
49 | } | 49 | } |
50 | #endif | 50 | #endif |
51 | s = s0 = dtoa(x, 0, 0, &decpt, &sign, &se); | 51 | s = s0 = dtoa(x, 2, precision, &decpt, &sign, &se); |
52 | if (sign) | 52 | if (sign) |
53 | *b++ = '-'; | 53 | *b++ = '-'; |
54 | if (decpt == 9999) /* Infinity or Nan */ { | 54 | if (decpt == 9999) /* Infinity or Nan */ { |
55 | while(*b++ = *s++); | 55 | while((*b++ = *s++)); |
56 | /* "b" is used to calculate the return length. Decrement to exclude the | ||
57 | * Null terminator from the length */ | ||
58 | b--; | ||
56 | goto done0; | 59 | goto done0; |
57 | } | 60 | } |
58 | if (decpt <= -4 || decpt > se - s + 5) { | 61 | if (decpt <= -4 || decpt > precision) { |
59 | *b++ = *s++; | 62 | *b++ = *s++; |
60 | if (*s) { | 63 | if (*s) { |
61 | *b++ = '.'; | 64 | *b++ = '.'; |
62 | while(*b = *s++) | 65 | while((*b = *s++)) |
63 | b++; | 66 | b++; |
64 | } | 67 | } |
65 | *b++ = 'e'; | 68 | *b++ = 'e'; |
@@ -82,13 +85,14 @@ g_fmt(register char *b, double x) | |||
82 | *b = 0; | 85 | *b = 0; |
83 | } | 86 | } |
84 | else if (decpt <= 0) { | 87 | else if (decpt <= 0) { |
88 | *b++ = '0'; | ||
85 | *b++ = '.'; | 89 | *b++ = '.'; |
86 | for(; decpt < 0; decpt++) | 90 | for(; decpt < 0; decpt++) |
87 | *b++ = '0'; | 91 | *b++ = '0'; |
88 | while(*b++ = *s++); | 92 | while((*b++ = *s++)); |
89 | } | 93 | } |
90 | else { | 94 | else { |
91 | while(*b = *s++) { | 95 | while((*b = *s++)) { |
92 | b++; | 96 | b++; |
93 | if (--decpt == 0 && *s) | 97 | if (--decpt == 0 && *s) |
94 | *b++ = '.'; | 98 | *b++ = '.'; |
@@ -99,6 +103,8 @@ g_fmt(register char *b, double x) | |||
99 | } | 103 | } |
100 | done0: | 104 | done0: |
101 | freedtoa(s0); | 105 | freedtoa(s0); |
106 | #ifdef IGNORE_ZERO_SIGN | ||
102 | done: | 107 | done: |
103 | return b0; | 108 | #endif |
109 | return b - b0; | ||
104 | } | 110 | } |