aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Pulford <mark@kyne.com.au>2011-12-29 23:03:58 +1030
committerMark Pulford <mark@kyne.com.au>2012-03-04 18:54:34 +1030
commitca42b9a996f9046ba3876ad8a81cda1d935b39cf (patch)
tree229cc0e408e28abc882778c68496c87af0d781ba
parent8eecc878e0560461ef42bd3cd8d6dfe33cf148e8 (diff)
downloadlua-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.txt6
-rw-r--r--Makefile21
-rw-r--r--dtoa.c10
-rw-r--r--dtoa_config.h66
-rw-r--r--fpconv.h10
-rw-r--r--g_fmt.c26
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)
11find_package(Lua51 REQUIRED) 11find_package(Lua51 REQUIRED)
12include_directories(${LUA_INCLUDE_DIR}) 12include_directories(${LUA_INCLUDE_DIR})
13 13
14include(TestBigEndian)
15TEST_BIG_ENDIAN(BIG_ENDIAN)
16if(HAVE_BIG_ENDIAN)
17 add_definitions(-DIEEE_BIG_ENDIAN)
18endif()
19
14# Handle platforms missing isinf() macro (Eg, some Solaris systems). 20# Handle platforms missing isinf() macro (Eg, some Solaris systems).
15include(CheckSymbolExists) 21include(CheckSymbolExists)
16CHECK_SYMBOL_EXISTS(isinf math.h HAVE_ISINF) 22CHECK_SYMBOL_EXISTS(isinf math.h HAVE_ISINF)
diff --git a/Makefile b/Makefile
index 57f2e1b..b283634 100644
--- a/Makefile
+++ b/Makefile
@@ -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 #####
9LUA_VERSION = 5.1 13LUA_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
47BUILD_CFLAGS = -I$(LUA_INCLUDE_DIR) $(CJSON_CFLAGS) 65BUILD_CFLAGS = -I$(LUA_INCLUDE_DIR) $(CJSON_CFLAGS)
48OBJS := lua_cjson.o strbuf.o fpconv.o 66FPCONV_OBJS ?= fpconv.o
67OBJS := 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
diff --git a/dtoa.c b/dtoa.c
index 4a458a4..520926c 100644
--- a/dtoa.c
+++ b/dtoa.c
@@ -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
526extern "C" double strtod(const char *s00, char **se); 528extern "C" double fpconv_strtod(const char *s00, char **se);
527extern "C" char *dtoa(double d, int mode, int ndigits, 529extern "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
2474strtod 2476fpconv_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
29static 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
48static 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 */
diff --git a/fpconv.h b/fpconv.h
index ea875c0..ac2f2c4 100644
--- a/fpconv.h
+++ b/fpconv.h
@@ -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
9extern void fpconv_init(); 9#ifdef USE_INTERNAL_DTOA
10static inline void fpconv_init()
11{
12 /* Do nothing - not required */
13}
14#else
15extern inline void fpconv_init();
16#endif
17
10extern int fpconv_g_fmt(char*, double, int); 18extern int fpconv_g_fmt(char*, double, int);
11extern double fpconv_strtod(const char*, char**); 19extern double fpconv_strtod(const char*, char**);
12 20
diff --git a/g_fmt.c b/g_fmt.c
index 543430a..130dcd4 100644
--- a/g_fmt.c
+++ b/g_fmt.c
@@ -26,14 +26,14 @@
26extern "C" { 26extern "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 * 35int
36g_fmt(register char *b, double x) 36fpconv_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 }