ref: 44ce0097b612a1fefd754065bdf8d9d2e5ef60c8
dir: /libinterp/string.c/
#include "lib9.h" #include "isa.h" #include "interp.h" #include "raise.h" #include "pool.h" #define DP if(1){}else print #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; WORD v; String *ss; v = W(m); ss = S(s); if(ss == H) error(exNilref); l = ss->len; DP("indc string %s len %d v %zd\n", string2c(ss), l, v); 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); if(nc == 0) return H; ns = newrunes(nc); memmove(ns->Srune, &ds->Srune[start], nc*sizeof(Rune)); } else { l = ds->len; if(v < start || v > l) error(exBounds); if(nc == 0) return H; 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, "%zd", 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; }