00001 #include <math.h>
00002 #include <string.h>
00003
00004 #include "nasal.h"
00005 #include "data.h"
00006
00007
00008
00009 #define DIGITS 16
00010
00011 static int tonum(unsigned char* s, int len, double* result);
00012 static int fromnum(double val, unsigned char* s);
00013
00014 #define LEN(s) ((s)->emblen != -1 ? (s)->emblen : (s)->data.ref.len)
00015 #define DATA(s) ((s)->emblen != -1 ? (s)->data.buf : (s)->data.ref.ptr)
00016
00017 int naStr_len(naRef s)
00018 {
00019 return IS_STR(s) ? LEN(PTR(s).str) : 0;
00020 }
00021
00022 char* naStr_data(naRef s)
00023 {
00024 return IS_STR(s) ? (char*)DATA(PTR(s).str) : 0;
00025 }
00026
00027 static void setlen(struct naStr* s, int sz)
00028 {
00029 if(s->emblen == -1 && DATA(s)) naFree(s->data.ref.ptr);
00030 if(sz > MAX_STR_EMBLEN) {
00031 s->emblen = -1;
00032 s->data.ref.len = sz;
00033 s->data.ref.ptr = naAlloc(sz+1);
00034 } else {
00035 s->emblen = sz;
00036 }
00037 DATA(s)[sz] = 0;
00038 }
00039
00040 naRef naStr_buf(naRef dst, int len)
00041 {
00042 setlen(PTR(dst).str, len);
00043 naBZero(DATA(PTR(dst).str), len);
00044 return dst;
00045 }
00046
00047 naRef naStr_fromdata(naRef dst, const char* data, int len)
00048 {
00049 if(!IS_STR(dst)) return naNil();
00050 setlen(PTR(dst).str, len);
00051 memcpy(DATA(PTR(dst).str), data, len);
00052 return dst;
00053 }
00054
00055 naRef naStr_concat(naRef dest, naRef s1, naRef s2)
00056 {
00057 struct naStr* dst = PTR(dest).str;
00058 struct naStr* a = PTR(s1).str;
00059 struct naStr* b = PTR(s2).str;
00060 if(!(IS_STR(s1)&&IS_STR(s2)&&IS_STR(dest))) return naNil();
00061 setlen(dst, LEN(a) + LEN(b));
00062 memcpy(DATA(dst), DATA(a), LEN(a));
00063 memcpy(DATA(dst) + LEN(a), DATA(b), LEN(b));
00064 return dest;
00065 }
00066
00067 naRef naStr_substr(naRef dest, naRef str, int start, int len)
00068 {
00069 struct naStr* dst = PTR(dest).str;
00070 struct naStr* s = PTR(str).str;
00071 if(!(IS_STR(dest)&&IS_STR(str))) return naNil();
00072 if(start + len > LEN(s)) return naNil();
00073 setlen(dst, len);
00074 memcpy(DATA(dst), DATA(s) + start, len);
00075 return dest;
00076 }
00077
00078 int naStr_equal(naRef s1, naRef s2)
00079 {
00080 struct naStr* a = PTR(s1).str;
00081 struct naStr* b = PTR(s2).str;
00082 if(DATA(a) == DATA(b)) return 1;
00083 if(LEN(a) != LEN(b)) return 0;
00084 if(memcmp(DATA(a), DATA(b), LEN(a)) == 0) return 1;
00085 return 0;
00086 }
00087
00088 naRef naStr_fromnum(naRef dest, double num)
00089 {
00090 struct naStr* dst = PTR(dest).str;
00091 unsigned char buf[DIGITS+8];
00092 setlen(dst, fromnum(num, buf));
00093 memcpy(DATA(dst), buf, LEN(dst));
00094 return dest;
00095 }
00096
00097 int naStr_parsenum(char* str, int len, double* result)
00098 {
00099 return tonum((unsigned char*)str, len, result);
00100 }
00101
00102 int naStr_tonum(naRef str, double* out)
00103 {
00104 return tonum(DATA(PTR(str).str), LEN(PTR(str).str), out);
00105 }
00106
00107 int naStr_numeric(naRef str)
00108 {
00109 double dummy;
00110 return tonum(DATA(PTR(str).str), LEN(PTR(str).str), &dummy);
00111 }
00112
00113 void naStr_gcclean(struct naStr* str)
00114 {
00115 if(str->emblen == -1) naFree(str->data.ref.ptr);
00116 str->data.ref.ptr = 0;
00117 str->data.ref.len = 0;
00118 str->emblen = -1;
00119 }
00120
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00134
00135
00136
00137
00138 static int readdec(unsigned char* s, int len, int i, double* v)
00139 {
00140 *v = 0;
00141 if(i >= len) return len;
00142 while(i < len && s[i] >= '0' && s[i] <= '9') {
00143 *v= (*v) * 10 + (s[i] - '0');
00144 i++;
00145 }
00146 return i;
00147 }
00148
00149
00150
00151
00152 static int readsigned(unsigned char* s, int len, int i, double* v)
00153 {
00154 int i0 = i, i2;
00155 double sgn=1, val;
00156 if(i >= len) { *v = 0; return len; }
00157 if(s[i] == '+') { i++; }
00158 else if(s[i] == '-') { i++; sgn = -1; }
00159 i2 = readdec(s, len, i, &val);
00160 if(i0 == i && i2 == i) {
00161 *v = 0;
00162 return i0;
00163 }
00164 *v = sgn*val;
00165 return i2;
00166 }
00167
00168
00169
00170
00171 static double decpow(int exp)
00172 {
00173 double v = 1;
00174 int absexp;
00175 if(exp < 0 || exp >= DIGITS)
00176 return pow(10, exp);
00177 else
00178 absexp = exp < 0 ? -exp : exp;
00179 while(absexp--) v *= 10.0;
00180 return v;
00181 }
00182
00183 static int tonum(unsigned char* s, int len, double* result)
00184 {
00185 int i=0, fraclen=0;
00186 double sgn=1, val, frac=0, exp=0;
00187
00188 if(len == 1 && (*s=='.' || *s=='-' || *s=='+')) return 0;
00189
00190
00191
00192
00193 if(len > 1 && s[0] == '-' && s[1] != '-') {
00194 sgn = -1; s++; len--;
00195 }
00196
00197
00198 i = readsigned(s, len, i, &val);
00199 if(val < 0) { sgn = -1; val = -val; }
00200
00201
00202 if(i < len && s[i] == '.') {
00203 i++;
00204 fraclen = readdec(s, len, i, &frac) - i;
00205 i += fraclen;
00206 }
00207
00208
00209 if(i == 0) return 0;
00210
00211
00212 if(i < len && (s[i] == 'e' || s[i] == 'E')) {
00213 int i0 = i+1;
00214 i = readsigned(s, len, i+1, &exp);
00215 if(i == i0) return 0;
00216 }
00217
00218
00219 *result = sgn * (val + frac * decpow(-fraclen)) * decpow(exp);
00220
00221
00222 if(i < len) return 0;
00223 return 1;
00224 }
00225
00226
00227
00228
00229
00230 static int decprint(int val, unsigned char* s)
00231 {
00232 int p=1, i=0;
00233 if(val == 0) { *s = '0'; return 1; }
00234 while(p <= 999999999 && p*10 <= val) p *= 10;
00235 while(p > 0) {
00236 int count = 0;
00237 while(val >= p) { val -= p; count++; }
00238 s[i++] = '0' + count;
00239 p /= 10;
00240 }
00241 return i;
00242 }
00243
00244
00245
00246
00247
00248
00249 static int rawprint(double val, unsigned char* s)
00250 {
00251 int exponent = (int)floor(log10(val));
00252 double mantissa = val / pow(10, exponent);
00253 int i, c;
00254 for(i=0; i<DIGITS-1; i++) {
00255 int digit = (int)floor(mantissa);
00256 s[i] = '0' + digit;
00257 mantissa -= digit;
00258 mantissa *= 10.0;
00259 }
00260
00261 c = (int)floor(mantissa);
00262 if(mantissa - c >= 0.5) c++;
00263 if(c < 0) c = 0;
00264 if(c > 9) c = 9;
00265 s[i] = '0' + c;
00266 return exponent - DIGITS + 1;
00267 }
00268
00269 static int fromnum(double val, unsigned char* s)
00270 {
00271 unsigned char raw[DIGITS];
00272 unsigned char* ptr = s;
00273 int exp, digs, i=0;
00274
00275
00276 if(val < 0) { *ptr++ = '-'; val = -val; }
00277
00278
00279 if(val == (int)val) {
00280 ptr += decprint(val, ptr);
00281 *ptr = 0;
00282 return ptr - s;
00283 }
00284
00285
00286 exp = rawprint(val, raw);
00287
00288
00289 for(i=DIGITS-1; i>0; i--)
00290 if(raw[i] != '0') break;
00291 digs = i+1;
00292
00293 if(exp > 0 || exp < -(DIGITS+3)) {
00294
00295 exp += DIGITS-1;
00296 *ptr++ = raw[0];
00297 if(digs > 1) {
00298 *ptr++ = '.';
00299 for(i=1; i<digs; i++) *ptr++ = raw[i];
00300 }
00301 *ptr++ = 'e';
00302 if(exp < 0) { exp = -exp; *ptr++ = '-'; }
00303 else { *ptr++ = '+'; }
00304 if(exp < 10) *ptr++ = '0';
00305 ptr += decprint(exp, ptr);
00306 } else if(exp < 1-DIGITS) {
00307
00308 *ptr++ = '0'; *ptr++ = '.';
00309 for(i=0; i<-(exp+DIGITS); i++) *ptr++ = '0';
00310 for(i=0; i<digs; i++) *ptr++ = raw[i];
00311 } else {
00312
00313 for(i=0; i<DIGITS+exp; i++) *ptr++ = raw[i];
00314 if(i < digs) {
00315
00316 *ptr++ = '.';
00317 while(i<digs) *ptr++ = raw[i++];
00318 }
00319 }
00320 *ptr = 0;
00321 return ptr - s;
00322 }