summaryrefslogtreecommitdiff
path: root/libinterp/string.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /libinterp/string.c
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'libinterp/string.c')
-rw-r--r--libinterp/string.c612
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;
+}