7 // The maximum number of significant (decimal!) figures in an IEEE
11 static int tonum(unsigned char* s, int len, double* result);
12 static int fromnum(double val, unsigned char* s);
14 #define LEN(s) ((s)->emblen != -1 ? (s)->emblen : (s)->data.ref.len)
15 #define DATA(s) ((s)->emblen != -1 ? (s)->data.buf : (s)->data.ref.ptr)
17 int naStr_len(naRef s)
19 return IS_STR(s) ? LEN(PTR(s).str) : 0;
22 char* naStr_data(naRef s)
24 return IS_STR(s) ? (char*)DATA(PTR(s).str) : 0;
27 static void setlen(struct naStr* s, int sz)
29 if(s->emblen == -1 && DATA(s)) naFree(s->data.ref.ptr);
30 if(sz > MAX_STR_EMBLEN) {
33 s->data.ref.ptr = naAlloc(sz+1);
37 DATA(s)[sz] = 0; // nul terminate
40 naRef naStr_buf(naRef dst, int len)
42 setlen(PTR(dst).str, len);
43 naBZero(DATA(PTR(dst).str), len);
47 naRef naStr_fromdata(naRef dst, const char* data, int len)
49 if(!IS_STR(dst)) return naNil();
50 setlen(PTR(dst).str, len);
51 memcpy(DATA(PTR(dst).str), data, len);
55 naRef naStr_concat(naRef dest, naRef s1, naRef s2)
57 struct naStr* dst = PTR(dest).str;
58 struct naStr* a = PTR(s1).str;
59 struct naStr* b = PTR(s2).str;
60 if(!(IS_STR(s1)&&IS_STR(s2)&&IS_STR(dest))) return naNil();
61 setlen(dst, LEN(a) + LEN(b));
62 memcpy(DATA(dst), DATA(a), LEN(a));
63 memcpy(DATA(dst) + LEN(a), DATA(b), LEN(b));
67 naRef naStr_substr(naRef dest, naRef str, int start, int len)
69 struct naStr* dst = PTR(dest).str;
70 struct naStr* s = PTR(str).str;
71 if(!(IS_STR(dest)&&IS_STR(str))) return naNil();
72 if(start + len > LEN(s)) return naNil();
74 memcpy(DATA(dst), DATA(s) + start, len);
78 int naStr_equal(naRef s1, naRef s2)
80 struct naStr* a = PTR(s1).str;
81 struct naStr* b = PTR(s2).str;
82 if(DATA(a) == DATA(b)) return 1;
83 if(LEN(a) != LEN(b)) return 0;
84 if(memcmp(DATA(a), DATA(b), LEN(a)) == 0) return 1;
88 naRef naStr_fromnum(naRef dest, double num)
90 struct naStr* dst = PTR(dest).str;
91 unsigned char buf[DIGITS+8];
92 setlen(dst, fromnum(num, buf));
93 memcpy(DATA(dst), buf, LEN(dst));
97 int naStr_parsenum(char* str, int len, double* result)
99 return tonum((unsigned char*)str, len, result);
102 int naStr_tonum(naRef str, double* out)
104 return tonum(DATA(PTR(str).str), LEN(PTR(str).str), out);
107 int naStr_numeric(naRef str)
110 return tonum(DATA(PTR(str).str), LEN(PTR(str).str), &dummy);
113 void naStr_gcclean(struct naStr* str)
115 if(str->emblen == -1) naFree(str->data.ref.ptr);
116 str->data.ref.ptr = 0;
117 str->data.ref.len = 0;
121 ////////////////////////////////////////////////////////////////////////
122 // Below is a custom double<->string conversion library. Why not
123 // simply use sprintf and atof? Because they aren't acceptably
124 // platform independant, sadly. I've seen some very strange results.
125 // This works the same way everywhere, although it is tied to an
126 // assumption of standard IEEE 64 bit floating point doubles.
128 // In practice, these routines work quite well. Testing conversions
129 // of random doubles to strings and back, this routine is beaten by
130 // glibc on roundoff error 23% of the time, beats glibc in 10% of
131 // cases, and ties (usually with an error of exactly zero) the
133 ////////////////////////////////////////////////////////////////////////
135 // TODO unify with number conversion in lex.c
136 static int hex(char c)
138 if(c >= '0' && c <= '9') return c - '0';
139 if(c >= 'A' && c <= 'F') return c - 'A' + 10;
140 if(c >= 'a' && c <= 'f') return c - 'a' + 10;
144 // Reads an unsigned integer out of the scalar starting at i, stores
145 // it in v, and returns the next index to start at. Zero-length
146 // integer numbers are allowed, and are returned as zero.
147 static int readint(unsigned char* s, int len, int i, double* v, int base)
151 if(i >= len) return len;
152 while(i < len && (val = hex(s[i])) >= 0 && val < base) {
153 *v= (*v) * base + val;
159 // Reads a signed integer out of the string starting at i, stores it
160 // in v, and returns the next index to start at. Zero-length
161 // decimal numbers are allowed, and are returned as zero.
162 static int readsigned(unsigned char* s, int len, int i, double* v)
164 int i0 = i, i2, base = 10;
166 if(i >= len) { *v = 0; return len; }
167 if(s[i] == '+') { i++; }
168 else if(s[i] == '-') { i++; sgn = -1; }
169 if(s[i] == '0' && ++i < len) {
170 if( s[i] == 'x' ) { i++; base = 16; }
171 if( s[i] == 'o' ) { i++; base = 8; }
173 i2 = readint(s, len, i, &val, base);
174 if(i0 == i && i2 == i) {
176 return i0; // don't successfully parse bare "+" or "-"
183 // Integer decimal power utility, with a tweak that enforces
184 // integer-exactness for arguments where that is possible.
185 static double decpow(int exp)
189 if(exp < 0 || exp >= DIGITS)
192 absexp = exp < 0 ? -exp : exp;
193 while(absexp--) v *= 10.0;
197 static int tonum(unsigned char* s, int len, double* result)
200 double sgn=1, val, frac=0, exp=0;
202 if(len == 1 && (*s=='.' || *s=='-' || *s=='+')) return 0;
204 // Strip off the leading negative sign first, so we can correctly
205 // parse things like -.xxx which would otherwise confuse
207 if(len > 1 && s[0] == '-' && s[1] != '-') {
208 sgn = -1; s++; len--;
211 // Read the integer part
212 i = readsigned(s, len, i, &val);
213 if(val < 0) { sgn = -1; val = -val; }
215 // Read the fractional part, if any
216 if(i < len && s[i] == '.') {
218 fraclen = readint(s, len, i, &frac, 10) - i;
222 // Nothing so far? Then the parse failed.
225 // Read the exponent, if any
226 if(i < len && (s[i] == 'e' || s[i] == 'E')) {
228 i = readsigned(s, len, i+1, &exp);
229 if(i == i0) return 0; // Must have a number after the "e"
232 // compute the result
233 *result = sgn * (val + frac * decpow(-fraclen)) * decpow(exp);
235 // if we didn't use the whole string, return failure
236 if(i < len) return 0;
240 // Very simple positive (!) integer print routine. Puts the result in
241 // s and returns the number of characters written. Does not null
242 // terminate the result. Presumes at least a 32 bit integer, and
243 // cannot print integers larger than 9999999999.
244 static int decprint(int val, unsigned char* s)
247 if(val == 0) { *s = '0'; return 1; }
248 while(p <= 999999999 && p*10 <= val) p *= 10;
251 while(val >= p) { val -= p; count++; }
252 s[i++] = '0' + count;
258 // Takes a positive (!) floating point numbers, and returns exactly
259 // DIGITS decimal numbers in the buffer pointed to by s, and an
260 // integer exponent as the return value. For example, printing 1.0
261 // will result in "1000000000000000" in the buffer and -15 as the
262 // exponent. The caller can then place the floating point as needed.
263 static int rawprint(double val, unsigned char* s)
265 int exponent = (int)floor(log10(val));
266 double mantissa = val / pow(10, exponent);
268 for(i=0; i<DIGITS-1; i++) {
269 int digit = (int)floor(mantissa);
274 // Round (i.e. don't floor) the last digit
275 c = (int)floor(mantissa);
276 if(mantissa - c >= 0.5) c++;
280 return exponent - DIGITS + 1;
283 static int fromnum(double val, unsigned char* s)
285 unsigned char raw[DIGITS];
286 unsigned char* ptr = s;
290 if(val < 0) { *ptr++ = '-'; val = -val; }
292 // Exactly an integer is a special case
293 if(val == (int)val) {
294 ptr += decprint(val, ptr);
299 // Get the raw digits
300 exp = rawprint(val, raw);
302 // Examine trailing zeros to get a significant digit count
303 for(i=DIGITS-1; i>0; i--)
304 if(raw[i] != '0') break;
307 if(exp > 0 || exp < -(DIGITS+3)) {
308 // Standard scientific notation
313 for(i=1; i<digs; i++) *ptr++ = raw[i];
316 if(exp < 0) { exp = -exp; *ptr++ = '-'; }
317 else { *ptr++ = '+'; }
318 if(exp < 10) *ptr++ = '0';
319 ptr += decprint(exp, ptr);
320 } else if(exp < 1-DIGITS) {
321 // Fraction with insignificant leading zeros
322 *ptr++ = '0'; *ptr++ = '.';
323 for(i=0; i<-(exp+DIGITS); i++) *ptr++ = '0';
324 for(i=0; i<digs; i++) *ptr++ = raw[i];
327 for(i=0; i<DIGITS+exp; i++) *ptr++ = raw[i];
331 while(i<digs) *ptr++ = raw[i++];
339 //------------------------------------------------------------------------------
340 static naRef string_methods;
341 static int init = 0; // As we can't use naNil() for static initialization we
342 // need a separate variable for saving whether we have
343 // already initialized.
345 //------------------------------------------------------------------------------
346 naRef naInit_string(naContext c)
348 string_methods = naNewHash(c);
350 return string_methods;
353 //------------------------------------------------------------------------------
354 naRef getStringMethods(naContext c)
359 return string_methods;