diff options
Diffstat (limited to 'libinterp/string.c')
| -rw-r--r-- | libinterp/string.c | 612 |
1 files changed, 612 insertions, 0 deletions
diff --git a/libinterp/string.c b/libinterp/string.c new file mode 100644 index 00000000..4a4eb54e --- /dev/null +++ b/libinterp/string.c @@ -0,0 +1,612 @@ +#include "lib9.h" +#include "isa.h" +#include "interp.h" +#include "raise.h" +#include "pool.h" + +#define OP(fn) void fn(void) +#define B(r) *((BYTE*)(R.r)) +#define W(r) *((WORD*)(R.r)) +#define F(r) *((REAL*)(R.r)) +#define V(r) *((LONG*)(R.r)) +#define S(r) *((String**)(R.r)) +#define A(r) *((Array**)(R.r)) +#define L(r) *((List**)(R.r)) +#define P(r) *((WORD**)(R.r)) +#define C(r) *((Channel**)(R.r)) +#define T(r) *((void**)(R.r)) + +OP(indc) +{ + int l; + ulong v; + String *ss; + + v = W(m); + ss = S(s); + + if(ss == H) + error(exNilref); + + l = ss->len; + if(l < 0) { + if(v >= -l) +e: error(exBounds); + l = ss->Srune[v]; + } + else { + if(v >= l) + goto e; + l = ss->Sascii[v]; + } + W(d) = l; +} + +OP(insc) +{ + ulong v; + int l, r, expand; + String *ss, *ns, **sp; + + r = W(s); + v = W(m); + ss = S(d); + + expand = r >= Runeself; + + if(ss == H) { + ss = newstring(0); + if(expand) { + l = 0; + ss->max /= sizeof(Rune); + goto r; + } + } + else + if(D2H(ss)->ref > 1 || (expand && ss->len > 0)) + ss = splitc(R.d, expand); + + l = ss->len; + if(l < 0 || expand) { + l = -l; +r: + if(v < l) + ss->Srune[v] = r; + else + if(v == l && v < ss->max) { + ss->len = -(v+1); + ss->Srune[v] = r; + } + else { + if(v != l) + error(exBounds); + ns = newstring((v + 1 + v/4)*sizeof(Rune)); + memmove(ns->Srune, ss->Srune, -ss->len*sizeof(Rune)); + ns->Srune[v] = r; + ns->len = -(v+1); + ns->max /= sizeof(Rune); + ss = ns; + } + } + else { + if(v < l) + ss->Sascii[v] = r; + else + if(v == l && v < ss->max) { + ss->len = v+1; + ss->Sascii[v] = r; + } + else { + if(v != l) + error(exBounds); + ns = newstring(v + 1 + v/4); + memmove(ns->Sascii, ss->Sascii, l); + ns->Sascii[v] = r; + ns->len = v+1; + ss = ns; + } + } + if(ss != S(d)) { + sp = R.d; + destroy(*sp); + *sp = ss; + } +} + +String* +slicer(ulong start, ulong v, String *ds) +{ + String *ns; + int l, nc; + + if(ds == H) { + if(start == 0 && v == 0) + return H; + + error(exBounds); + } + + nc = v - start; + if(ds->len < 0) { + l = -ds->len; + if(v < start || v > l) + error(exBounds); + ns = newrunes(nc); + memmove(ns->Srune, &ds->Srune[start], nc*sizeof(Rune)); + } + else { + l = ds->len; + if(v < start || v > l) + error(exBounds); + ns = newstring(nc); + memmove(ns->Sascii, &ds->Sascii[start], nc); + } + + return ns; +} + +OP(slicec) +{ + String *ns, **sp; + + ns = slicer(W(s), W(m), S(d)); + sp = R.d; + destroy(*sp); + *sp = ns; +} + +void +cvtup(Rune *r, String *s) +{ + uchar *bp, *ep; + + bp = (uchar*)s->Sascii; + ep = bp + s->len; + while(bp < ep) + *r++ = *bp++; +} + +String* +addstring(String *s1, String *s2, int append) +{ + Rune *r; + String *ns; + int l, l1, l2; + + if(s1 == H) { + if(s2 == H) + return H; + return stringdup(s2); + } + if(D2H(s1)->ref > 1) + append = 0; + if(s2 == H) { + if(append) + return s1; + return stringdup(s1); + } + + if(s1->len < 0) { + l1 = -s1->len; + if(s2->len < 0) + l = l1 - s2->len; + else + l = l1 + s2->len; + if(append && l <= s1->max) + ns = s1; + else { + ns = newrunes(append? (l+l/4): l); + memmove(ns->Srune, s1->Srune, l1*sizeof(Rune)); + } + ns->len = -l; + r = &ns->Srune[l1]; + if(s2->len < 0) + memmove(r, s2->Srune, -s2->len*sizeof(Rune)); + else + cvtup(r, s2); + + return ns; + } + + if(s2->len < 0) { + l2 = -s2->len; + l = s1->len + l2; + ns = newrunes(append? (l+l/4): l); + ns->len = -l; + cvtup(ns->Srune, s1); + memmove(&ns->Srune[s1->len], s2->Srune, l2*sizeof(Rune)); + return ns; + } + + l1 = s1->len; + l = l1 + s2->len; + if(append && l <= s1->max) + ns = s1; + else { + ns = newstring(append? (l+l/4): l); + memmove(ns->Sascii, s1->Sascii, l1); + } + ns->len = l; + memmove(ns->Sascii+l1, s2->Sascii, s2->len); + + return ns; +} + +OP(addc) +{ + String *ns, **sp; + + ns = addstring(S(m), S(s), R.m == R.d); + + sp = R.d; + if(ns != *sp) { + destroy(*sp); + *sp = ns; + } +} + +OP(cvtca) +{ + int l; + Rune *r; + char *p; + String *ss; + Array *a, **ap; + + ss = S(s); + if(ss == H) { + a = mem2array(nil, 0); + goto r; + } + if(ss->len < 0) { + l = -ss->len; + a = mem2array(nil, runenlen(ss->Srune, l)); + p = (char*)a->data; + r = ss->Srune; + while(l--) + p += runetochar(p, r++); + goto r; + } + a = mem2array(ss->Sascii, ss->len); + +r: ap = R.d; + destroy(*ap); + *ap = a; +} + +OP(cvtac) +{ + Array *a; + String *ds, **dp; + + ds = H; + a = A(s); + if(a != H) + ds = c2string((char*)a->data, a->len); + + dp = R.d; + destroy(*dp); + *dp = ds; +} + +OP(lenc) +{ + int l; + String *ss; + + l = 0; + ss = S(s); + if(ss != H) { + l = ss->len; + if(l < 0) + l = -l; + } + W(d) = l; +} + +OP(cvtcw) +{ + String *s; + + s = S(s); + if(s == H) + W(d) = 0; + else + if(s->len < 0) + W(d) = strtol(string2c(s), nil, 10); + else { + s->Sascii[s->len] = '\0'; + W(d) = strtol(s->Sascii, nil, 10); + } +} + +OP(cvtcf) +{ + String *s; + + s = S(s); + if(s == H) + F(d) = 0.0; + else + if(s->len < 0) + F(d) = strtod(string2c(s), nil); + else { + s->Sascii[s->len] = '\0'; + F(d) = strtod(s->Sascii, nil); + } +} + +OP(cvtwc) +{ + String *ds, **dp; + + ds = newstring(16); + ds->len = sprint(ds->Sascii, "%d", W(s)); + + dp = R.d; + destroy(*dp); + *dp = ds; +} + +OP(cvtlc) +{ + String *ds, **dp; + + ds = newstring(16); + ds->len = sprint(ds->Sascii, "%lld", V(s)); + + dp = R.d; + destroy(*dp); + *dp = ds; +} + +OP(cvtfc) +{ + String *ds, **dp; + + ds = newstring(32); + ds->len = sprint(ds->Sascii, "%g", F(s)); + dp = R.d; + destroy(*dp); + *dp = ds; +} + +char* +string2c(String *s) +{ + char *p; + int c, l, nc; + Rune *r, *er; + + if(s == H) + return ""; + + if(s->len >= 0) { + s->Sascii[s->len] = '\0'; + return s->Sascii; + } + + nc = -s->len; + l = (nc * UTFmax) + UTFmax; + if(s->tmp == nil || msize(s->tmp) < l) { + free(s->tmp); + s->tmp = malloc(l); + if(s->tmp == nil) + error(exNomem); + } + + p = s->tmp; + r = s->Srune; + er = r + nc; + while(r < er) { + c = *r++; + if(c < Runeself) + *p++ = c; + else + p += runetochar(p, r-1); + } + + *p = 0; + + return s->tmp; +} + +String* +c2string(char *cs, int len) +{ + uchar *p; + char *ecs; + String *s; + Rune *r, junk; + int c, nc, isrune; + + isrune = 0; + ecs = cs+len; + p = (uchar*)cs; + while(len--) { + c = *p++; + if(c >= Runeself) { + isrune = 1; + break; + } + } + + if(isrune == 0) { + nc = ecs - cs; + s = newstring(nc); + memmove(s->Sascii, cs, nc); + return s; + } + + p--; + nc = p - (uchar*)cs; + while(p < (uchar*)ecs) { + c = *p; + if(c < Runeself) + p++; + else if(p+UTFmax<=(uchar*)ecs || fullrune((char*)p, (uchar*)ecs-p)) + p += chartorune(&junk, (char*)p); + else + break; + nc++; + } + s = newrunes(nc); + r = s->Srune; + while(nc--) + cs += chartorune(r++, cs); + + return s; +} + +String* +newstring(int nb) +{ + Heap *h; + String *s; + + h = nheap(sizeof(String)+nb); + h->t = &Tstring; + Tstring.ref++; + s = H2D(String*, h); + s->tmp = nil; + s->len = nb; + s->max = hmsize(h) - (sizeof(String)+sizeof(Heap)); + return s; +} + +String* +newrunes(int nr) +{ + Heap *h; + String *s; + + if(nr == 0) + return newstring(nr); + if(nr < 0) + nr = -nr; + h = nheap(sizeof(String)+nr*sizeof(Rune)); + h->t = &Tstring; + Tstring.ref++; + s = H2D(String*, h); + s->tmp = nil; + s->len = -nr; + s->max = (hmsize(h) - (sizeof(String)+sizeof(Heap)))/sizeof(Rune); + return s; +} + +String* +stringdup(String *s) +{ + String *ns; + + if(s == H) + return H; + + if(s->len >= 0) { + ns = newstring(s->len); + memmove(ns->Sascii, s->Sascii, s->len); + return ns; + } + + ns = newrunes(-s->len); + memmove(ns->Srune, s->Srune,-s->len*sizeof(Rune)); + + return ns; +} + +int +stringcmp(String *s1, String *s2) +{ + Rune *r1, *r2; + char *a1, *a2; + int v, n, n1, n2, c1, c2; + static String snil = { 0, 0, nil }; + + if(s1 == H) + s1 = &snil; + if(s2 == H) + s2 = &snil; + + if(s1 == s2) + return 0; + + v = 0; + n1 = s1->len; + if(n1 < 0) { + n1 = -n1; + v |= 1; + } + n2 = s2->len; + if(n2 < 0) { + n2 = -n2; + v |= 2; + } + + n = n1; + if(n2 < n) + n = n2; + + switch(v) { + case 0: /* Ascii Ascii */ + n = memcmp(s1->Sascii, s2->Sascii, n); + if(n == 0) + n = n1 - n2; + return n; + case 1: /* Rune Ascii */ + r1 = s1->Srune; + a2 = s2->Sascii; + while(n > 0) { + c1 = *r1++; + c2 = *a2++; + if(c1 != c2) + goto ne; + n--; + } + break; + case 2: /* Ascii Rune */ + a1 = s1->Sascii; + r2 = s2->Srune; + while(n > 0) { + c1 = *a1++; + c2 = *r2++; + if(c1 != c2) + goto ne; + n--; + } + break; + case 3: /* Rune Rune */ + r1 = s1->Srune; + r2 = s2->Srune; + while(n > 0) { + c1 = *r1++; + c2 = *r2++; + if(c1 != c2) + goto ne; + n--; + } + break; + } + return n1 - n2; + +ne: if(c1 < c2) + return -1; + return 1; +} + +String* +splitc(String **s, int expand) +{ + String *ss, *ns; + + ss = *s; + if(expand && ss->len > 0) { + ns = newrunes(ss->len); + cvtup(ns->Srune, ss); + } + else + ns = stringdup(ss); + + destroy(ss); + *s = ns; + return ns; +} |
