// double.
#define DIGITS 16
-// The minimum size we'll allocate for a string. Since a string
-// structure is already 12 bytes, and each naRef that points to it is
-// 8, there isn't much point in being stingy.
-#define MINLEN 16
-
static int tonum(unsigned char* s, int len, double* result);
static int fromnum(double val, unsigned char* s);
char* naStr_data(naRef s)
{
if(!IS_STR(s)) return 0;
- return s.ref.ptr.str->data;
+ return (char*)s.ref.ptr.str->data;
}
static void setlen(struct naStr* s, int sz)
{
- int currSz, waste;
- sz += 1; // Allow for an extra nul terminator
- currSz = s->len+1 < MINLEN ? MINLEN : s->len+1;
- waste = currSz - sz; // how much extra if we don't reallocate?
- if(s->data == 0 || waste < 0 || waste > MINLEN) {
- naFree(s->data);
- s->data = naAlloc(sz < MINLEN ? MINLEN : sz);
- }
- s->len = sz - 1;
- s->data[s->len] = 0; // nul terminate
+ if(s->data) naFree(s->data);
+ s->len = sz;
+ s->data = naAlloc(sz+1);
+ s->data[sz] = 0; // nul terminate
+}
+
+naRef naStr_buf(naRef dst, int len)
+{
+ setlen(dst.ref.ptr.str, len);
+ naBZero(dst.ref.ptr.str->data, len);
+ return dst;
}
naRef naStr_fromdata(naRef dst, char* data, int len)
int naStr_parsenum(char* str, int len, double* result)
{
- return tonum(str, len, result);
+ return tonum((unsigned char*)str, len, result);
}
int naStr_tonum(naRef str, double* out)
void naStr_gcclean(struct naStr* str)
{
- if(str->len > MINLEN) {
- naFree(str->data);
- str->data = 0;
- }
+ naFree(str->data);
+ str->data = 0;
str->len = 0;
}
// Reads a signed integer out of the string starting at i, stores it
// in v, and returns the next index to start at. Zero-length
-// decimal numbers (and length-1 strings like '+') are allowed, and
-// are returned as zero.
+// decimal numbers are allowed, and are returned as zero.
static int readsigned(unsigned char* s, int len, int i, double* v)
{
int i0 = i, i2;
if(s[i] == '+') { i++; }
else if(s[i] == '-') { i++; sgn = -1; }
i2 = readdec(s, len, i, &val);
- if(i2 == i)
- return i0; // don't parse "+" or "-" as zero.
+ if(i0 == i && i2 == i) {
+ *v = 0;
+ return i0; // don't successfully parse bare "+" or "-"
+ }
*v = sgn*val;
- return i;
+ return i2;
}
int i=0, fraclen=0;
double sgn=1, val, frac=0, exp=0;
+ // Special case, "." is not a number, even though "1." and ".0" are.
+ if(len == 1 && s[0] == '.')
+ return 0;
+
+ // Strip off the leading negative sign first, so we can correctly
+ // parse things like -.xxx which would otherwise confuse
+ // readsigned.
+ if(len > 1 && s[0] == '-' && s[1] != '-') {
+ sgn = -1; s++; len--;
+ }
+
// Read the integer part
i = readsigned(s, len, i, &val);
if(val < 0) { sgn = -1; val = -val; }
i += fraclen;
}
+ // Nothing so far? Then the parse failed.
+ if(i == 0) return 0;
+
// Read the exponent, if any
- if(i < len && (s[i] == 'e' || s[i] == 'E'))
+ if(i < len && (s[i] == 'e' || s[i] == 'E')) {
+ int i0 = i+1;
i = readsigned(s, len, i+1, &exp);
+ if(i == i0) return 0; // Must have a number after the "e"
+ }
// compute the result
*result = sgn * (val + frac * decpow(-fraclen)) * decpow(exp);
// Very simple positive (!) integer print routine. Puts the result in
// s and returns the number of characters written. Does not null
-// terminate the result.
+// terminate the result. Presumes at least a 32 bit integer, and
+// cannot print integers larger than 9999999999.
static int decprint(int val, unsigned char* s)
{
int p=1, i=0;
if(val == 0) { *s = '0'; return 1; }
- while(p <= val) p *= 10;
- p /= 10;
+ while(p <= 999999999 && p*10 <= val) p *= 10;
while(p > 0) {
int count = 0;
while(val >= p) { val -= p; count++; }
if(raw[i] != '0') break;
digs = i+1;
- if(exp > 0 || exp < -(DIGITS+2)) {
+ if(exp > 0 || exp < -(DIGITS+3)) {
// Standard scientific notation
exp += DIGITS-1;
*ptr++ = raw[0];