ref: 7a7dfee4fab3e9a725422edff93251ef0a717492
dir: /libinterp/string.c/
#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);
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, "%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;
}