aboutsummaryrefslogtreecommitdiff
path: root/lobject.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2013-05-27 14:42:38 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2013-05-27 14:42:38 -0300
commitee865b9fe768195bb81abec0cbc85136526e6894 (patch)
treef8f3c349104e85468c6d1b8384ef479aa3ec035e /lobject.c
parentd630daca1a3dad6357226fdc6472692fa7e4b5c0 (diff)
downloadlua-ee865b9fe768195bb81abec0cbc85136526e6894.tar.gz
lua-ee865b9fe768195bb81abec0cbc85136526e6894.tar.bz2
lua-ee865b9fe768195bb81abec0cbc85136526e6894.zip
new implementation for 'lua_strx2number' to correct small
problems with numbers like 0x10000...000p-100
Diffstat (limited to 'lobject.c')
-rw-r--r--lobject.c60
1 files changed, 36 insertions, 24 deletions
diff --git a/lobject.c b/lobject.c
index f249f9f2..8a70c2c2 100644
--- a/lobject.c
+++ b/lobject.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lobject.c,v 2.63 2013/05/14 15:59:04 roberto Exp roberto $ 2** $Id: lobject.c,v 2.64 2013/05/26 14:43:35 roberto Exp roberto $
3** Some generic functions over Lua objects 3** Some generic functions over Lua objects
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -145,52 +145,64 @@ static int isneg (const char **s) {
145#include <math.h> 145#include <math.h>
146 146
147 147
148static lua_Number readhexa (const char **s, lua_Number r, int *count) { 148/* maximum number of significant digits to read (to avoid overflows
149 for (; lisxdigit(cast_uchar(**s)); (*s)++) { /* read integer part */ 149 even with single floats) */
150 r = (r * cast_num(16.0)) + cast_num(luaO_hexavalue(cast_uchar(**s))); 150#define MAXSIGDIG 30
151 (*count)++;
152 }
153 return r;
154}
155
156 151
157/* 152/*
158** convert an hexadecimal numeric string to a number, following 153** convert an hexadecimal numeric string to a number, following
159** C99 specification for 'strtod' 154** C99 specification for 'strtod'
160*/ 155*/
161static lua_Number lua_strx2number (const char *s, char **endptr) { 156static lua_Number lua_strx2number (const char *s, char **endptr) {
162 lua_Number r = 0.0; 157 lua_Number r = 0.0; /* result (accumulator) */
163 int e = 0, i = 0; 158 int sigdig = 0; /* number of significant digits */
159 int nosigdig = 0; /* number of non-significant digits */
160 int e = 0; /* exponent correction */
164 int neg = 0; /* 1 if number is negative */ 161 int neg = 0; /* 1 if number is negative */
162 int dot = 0; /* true after seen a dot */
165 *endptr = cast(char *, s); /* nothing is valid yet */ 163 *endptr = cast(char *, s); /* nothing is valid yet */
166 while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ 164 while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
167 neg = isneg(&s); /* check signal */ 165 neg = isneg(&s); /* check signal */
168 if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ 166 if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */
169 return 0.0; /* invalid format (no '0x') */ 167 return 0.0; /* invalid format (no '0x') */
170 s += 2; /* skip '0x' */ 168 for (s += 2; ; s++) { /* skip '0x' and read numeral */
171 r = readhexa(&s, r, &i); /* read integer part */ 169 if (*s == '.') {
172 if (*s == '.') { 170 if (dot) break; /* second dot? stop loop */
173 s++; /* skip dot */ 171 else dot = 1;
174 r = readhexa(&s, r, &e); /* read fractional part */ 172 }
173 else if (lisxdigit(cast_uchar(*s))) {
174 if (sigdig == 0 && *s == '0') { /* non-significant zero? */
175 nosigdig++;
176 if (dot) e--; /* zero after dot? correct exponent */
177 }
178 else {
179 if (++sigdig <= MAXSIGDIG) { /* can read it without overflow? */
180 r = (r * cast_num(16.0)) + luaO_hexavalue(cast_uchar(*s));
181 if (dot) e--; /* decimal digit */
182 }
183 else /* too many digits; ignore */
184 if (!dot) e++; /* still count it for exponent */
185 }
186 }
187 else break; /* neither a dot nor a digit */
175 } 188 }
176 if (i == 0 && e == 0) 189 if (nosigdig + sigdig == 0) /* no digits? */
177 return 0.0; /* invalid format (no digit) */ 190 return 0.0; /* invalid format */
178 e *= -4; /* each fractional digit divides value by 2^-4 */
179 *endptr = cast(char *, s); /* valid up to here */ 191 *endptr = cast(char *, s); /* valid up to here */
192 e *= 4; /* each digit multiplies/divides value by 2^4 */
180 if (*s == 'p' || *s == 'P') { /* exponent part? */ 193 if (*s == 'p' || *s == 'P') { /* exponent part? */
181 int exp1 = 0; 194 int exp1 = 0; /* exponent value */
182 int neg1; 195 int neg1; /* exponent signal */
183 s++; /* skip 'p' */ 196 s++; /* skip 'p' */
184 neg1 = isneg(&s); /* signal */ 197 neg1 = isneg(&s); /* signal */
185 if (!lisdigit(cast_uchar(*s))) 198 if (!lisdigit(cast_uchar(*s)))
186 goto ret; /* must have at least one digit */ 199 return 0.0; /* invalid; must have at least one digit */
187 while (lisdigit(cast_uchar(*s))) /* read exponent */ 200 while (lisdigit(cast_uchar(*s))) /* read exponent */
188 exp1 = exp1 * 10 + *(s++) - '0'; 201 exp1 = exp1 * 10 + *(s++) - '0';
189 if (neg1) exp1 = -exp1; 202 if (neg1) exp1 = -exp1;
190 e += exp1; 203 e += exp1;
204 *endptr = cast(char *, s); /* valid up to here */
191 } 205 }
192 *endptr = cast(char *, s); /* valid up to here */
193 ret:
194 if (neg) r = -r; 206 if (neg) r = -r;
195 return l_mathop(ldexp)(r, e); 207 return l_mathop(ldexp)(r, e);
196} 208}