]> git.mxchange.org Git - simgear.git/blobdiff - simgear/nasal/string.c
Add a new node "float-property" to be used in float comparision in effect predicates
[simgear.git] / simgear / nasal / string.c
index 8d781c7ee9c24c101fc95c157948df89edbfb578..4855054cddd24cc1983eb0d373056c64c7b66bf3 100644 (file)
 // 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);
 
+#define LEN(s) ((s)->emblen != -1 ? (s)->emblen : (s)->data.ref.len)
+#define DATA(s) ((s)->emblen != -1 ? (s)->data.buf : (s)->data.ref.ptr)
+
 int naStr_len(naRef s)
 {
-    if(!IS_STR(s)) return 0;
-    return s.ref.ptr.str->len;
+    return IS_STR(s) ? LEN(PTR(s).str) : 0;
 }
 
 char* naStr_data(naRef s)
 {
-    if(!IS_STR(s)) return 0;
-    return s.ref.ptr.str->data;
+    return IS_STR(s) ? (char*)DATA(PTR(s).str) : 0;
 }
 
 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);
+    if(s->emblen == -1 && DATA(s)) naFree(s->data.ref.ptr);
+    if(sz > MAX_STR_EMBLEN) {
+        s->emblen = -1;
+        s->data.ref.len = sz;
+        s->data.ref.ptr = naAlloc(sz+1);
+    } else {
+        s->emblen = sz;
     }
-    s->len = sz - 1;
-    s->data[s->len] = 0; // nul terminate
+    DATA(s)[sz] = 0; // nul terminate
+}
+
+naRef naStr_buf(naRef dst, int len)
+{
+    setlen(PTR(dst).str, len);
+    naBZero(DATA(PTR(dst).str), len);
+    return dst;
 }
 
-naRef naStr_fromdata(naRef dst, char* data, int len)
+naRef naStr_fromdata(naRef dst, const char* data, int len)
 {
     if(!IS_STR(dst)) return naNil();
-    setlen(dst.ref.ptr.str, len);
-    memcpy(dst.ref.ptr.str->data, data, len);
+    setlen(PTR(dst).str, len);
+    memcpy(DATA(PTR(dst).str), data, len);
     return dst;
 }
 
 naRef naStr_concat(naRef dest, naRef s1, naRef s2)
 {
-    struct naStr* dst = dest.ref.ptr.str;
-    struct naStr* a = s1.ref.ptr.str;
-    struct naStr* b = s2.ref.ptr.str;
+    struct naStr* dst = PTR(dest).str;
+    struct naStr* a = PTR(s1).str;
+    struct naStr* b = PTR(s2).str;
     if(!(IS_STR(s1)&&IS_STR(s2)&&IS_STR(dest))) return naNil();
-    setlen(dst, a->len + b->len);
-    memcpy(dst->data, a->data, a->len);
-    memcpy(dst->data + a->len, b->data, b->len);
+    setlen(dst, LEN(a) + LEN(b));
+    memcpy(DATA(dst), DATA(a), LEN(a));
+    memcpy(DATA(dst) + LEN(a), DATA(b), LEN(b));
     return dest;
 }
 
 naRef naStr_substr(naRef dest, naRef str, int start, int len)
 {
-    struct naStr* dst = dest.ref.ptr.str;
-    struct naStr* s = str.ref.ptr.str;
+    struct naStr* dst = PTR(dest).str;
+    struct naStr* s = PTR(str).str;
     if(!(IS_STR(dest)&&IS_STR(str))) return naNil();
-    if(start + len > s->len) { dst->len = 0; dst->data = 0; return naNil(); }
+    if(start + len > LEN(s)) return naNil();
     setlen(dst, len);
-    memcpy(dst->data, s->data + start, len);
+    memcpy(DATA(dst), DATA(s) + start, len);
     return dest;
 }
 
 int naStr_equal(naRef s1, naRef s2)
 {
-    struct naStr* a = s1.ref.ptr.str;
-    struct naStr* b = s2.ref.ptr.str;
-    if(a->data == b->data) return 1;
-    if(a->len != b->len) return 0;
-    if(memcmp(a->data, b->data, a->len) == 0) return 1;
+    struct naStr* a = PTR(s1).str;
+    struct naStr* b = PTR(s2).str;
+    if(DATA(a) == DATA(b)) return 1;
+    if(LEN(a) != LEN(b)) return 0;
+    if(memcmp(DATA(a), DATA(b), LEN(a)) == 0) return 1;
     return 0;
 }
 
 naRef naStr_fromnum(naRef dest, double num)
 {
-    struct naStr* dst = dest.ref.ptr.str;
+    struct naStr* dst = PTR(dest).str;
     unsigned char buf[DIGITS+8];
     setlen(dst, fromnum(num, buf));
-    memcpy(dst->data, buf, dst->len);
+    memcpy(DATA(dst), buf, LEN(dst));
     return dest;
 }
 
 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)
 {
-    return tonum(str.ref.ptr.str->data, str.ref.ptr.str->len, out);
+    return tonum(DATA(PTR(str).str), LEN(PTR(str).str), out);
 }
 
 int naStr_numeric(naRef str)
 {
     double dummy;
-    return tonum(str.ref.ptr.str->data, str.ref.ptr.str->len, &dummy);
+    return tonum(DATA(PTR(str).str), LEN(PTR(str).str), &dummy);
 }
 
 void naStr_gcclean(struct naStr* str)
 {
-    if(str->len > MINLEN) {
-        naFree(str->data);
-        str->data = 0;
-    }
-    str->len = 0;
+    if(str->emblen == -1) naFree(str->data.ref.ptr);
+    str->data.ref.ptr = 0;
+    str->data.ref.len = 0;
+    str->emblen = -1;
 }
 
 ////////////////////////////////////////////////////////////////////////
@@ -147,17 +148,21 @@ static int readdec(unsigned char* s, int len, int i, double* v)
 
 // 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;
     double sgn=1, val;
     if(i >= len) { *v = 0; return len; }
     if(s[i] == '+')      { i++; }
     else if(s[i] == '-') { i++; sgn = -1; }
-    i = readdec(s, len, i, &val);
+    i2 = readdec(s, len, i, &val);
+    if(i0 == i && i2 == i) {
+        *v = 0;
+        return i0; // don't successfully parse bare "+" or "-"
+    }
     *v = sgn*val;
-    return i;
+    return i2;
 }
 
 
@@ -180,6 +185,15 @@ static int tonum(unsigned char* s, int len, double* result)
     int i=0, fraclen=0;
     double sgn=1, val, frac=0, exp=0;
 
+    if(len == 1 && (*s=='.' || *s=='-' || *s=='+')) 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; }
@@ -191,9 +205,15 @@ static int tonum(unsigned char* s, int len, double* result)
         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);
@@ -205,13 +225,13 @@ static int tonum(unsigned char* s, int len, double* result)
 
 // 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++; }
@@ -270,7 +290,7 @@ static int fromnum(double val, unsigned char* s)
         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];