xref: /inferno-os/libinterp/string.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
1 #include "lib9.h"
2 #include "isa.h"
3 #include "interp.h"
4 #include "raise.h"
5 #include "pool.h"
6 
7 #define OP(fn)	void fn(void)
8 #define B(r)	*((BYTE*)(R.r))
9 #define W(r)	*((WORD*)(R.r))
10 #define F(r)	*((REAL*)(R.r))
11 #define V(r)	*((LONG*)(R.r))
12 #define	S(r)	*((String**)(R.r))
13 #define	A(r)	*((Array**)(R.r))
14 #define	L(r)	*((List**)(R.r))
15 #define P(r)	*((WORD**)(R.r))
16 #define C(r)	*((Channel**)(R.r))
17 #define T(r)	*((void**)(R.r))
18 
19 OP(indc)
20 {
21 	int l;
22 	ulong v;
23 	String *ss;
24 
25 	v = W(m);
26 	ss = S(s);
27 
28 	if(ss == H)
29 		error(exNilref);
30 
31 	l = ss->len;
32 	if(l < 0) {
33 		if(v >= -l)
34 e:			error(exBounds);
35 		l = ss->Srune[v];
36 	}
37 	else {
38 		if(v >= l)
39 			goto e;
40 		l = ss->Sascii[v];
41 	}
42 	W(d) = l;
43 }
44 
45 OP(insc)
46 {
47 	ulong v;
48 	int l, r, expand;
49 	String *ss, *ns, **sp;
50 
51 	r = W(s);
52 	v = W(m);
53 	ss = S(d);
54 
55 	expand = r >= Runeself;
56 
57 	if(ss == H) {
58 		ss = newstring(0);
59 		if(expand) {
60 			l = 0;
61 			ss->max /= sizeof(Rune);
62 			goto r;
63 		}
64 	}
65 	else
66 	if(D2H(ss)->ref > 1 || (expand && ss->len > 0))
67 		ss = splitc(R.d, expand);
68 
69 	l = ss->len;
70 	if(l < 0 || expand) {
71 		l = -l;
72 r:
73 		if(v < l)
74 			ss->Srune[v] = r;
75 		else
76 		if(v == l && v < ss->max) {
77 			ss->len = -(v+1);
78 			ss->Srune[v] = r;
79 		}
80 		else {
81 			if(v != l)
82 				error(exBounds);
83 			ns = newstring((v + 1 + v/4)*sizeof(Rune));
84 			memmove(ns->Srune, ss->Srune, -ss->len*sizeof(Rune));
85 			ns->Srune[v] = r;
86 			ns->len = -(v+1);
87 			ns->max /= sizeof(Rune);
88 			ss = ns;
89 		}
90 	}
91 	else {
92 		if(v < l)
93 			ss->Sascii[v] = r;
94 		else
95 		if(v == l && v < ss->max) {
96 			ss->len = v+1;
97 			ss->Sascii[v] = r;
98 		}
99 		else {
100 			if(v != l)
101 				error(exBounds);
102 			ns = newstring(v + 1 + v/4);
103 			memmove(ns->Sascii, ss->Sascii, l);
104 			ns->Sascii[v] = r;
105 			ns->len = v+1;
106 			ss = ns;
107 		}
108 	}
109 	if(ss != S(d)) {
110 		sp = R.d;
111 		destroy(*sp);
112 		*sp = ss;
113 	}
114 }
115 
116 String*
117 slicer(ulong start, ulong v, String *ds)
118 {
119 	String *ns;
120 	int l, nc;
121 
122 	if(ds == H) {
123 		if(start == 0 && v == 0)
124 			return H;
125 
126 		error(exBounds);
127 	}
128 
129 	nc = v - start;
130 	if(ds->len < 0) {
131 		l = -ds->len;
132 		if(v < start || v > l)
133 			error(exBounds);
134 		if(nc == 0)
135 			return H;
136 		ns = newrunes(nc);
137 		memmove(ns->Srune, &ds->Srune[start], nc*sizeof(Rune));
138 	}
139 	else {
140 		l = ds->len;
141 		if(v < start || v > l)
142 			error(exBounds);
143 		if(nc == 0)
144 			return H;
145 		ns = newstring(nc);
146 		memmove(ns->Sascii, &ds->Sascii[start], nc);
147 	}
148 
149 	return ns;
150 }
151 
152 OP(slicec)
153 {
154 	String *ns, **sp;
155 
156 	ns = slicer(W(s), W(m), S(d));
157 	sp = R.d;
158 	destroy(*sp);
159 	*sp = ns;
160 }
161 
162 void
163 cvtup(Rune *r, String *s)
164 {
165 	uchar *bp, *ep;
166 
167 	bp = (uchar*)s->Sascii;
168 	ep = bp + s->len;
169 	while(bp < ep)
170 		*r++ = *bp++;
171 }
172 
173 String*
174 addstring(String *s1, String *s2, int append)
175 {
176 	Rune *r;
177 	String *ns;
178 	int l, l1, l2;
179 
180 	if(s1 == H) {
181 		if(s2 == H)
182 			return H;
183 		return stringdup(s2);
184 	}
185 	if(D2H(s1)->ref > 1)
186 		append = 0;
187 	if(s2 == H) {
188 		if(append)
189 			return s1;
190 		return stringdup(s1);
191 	}
192 
193 	if(s1->len < 0) {
194 		l1 = -s1->len;
195 		if(s2->len < 0)
196 			l = l1 - s2->len;
197 		else
198 			l = l1 + s2->len;
199 		if(append && l <= s1->max)
200 			ns = s1;
201 		else {
202 			ns = newrunes(append? (l+l/4): l);
203 			memmove(ns->Srune, s1->Srune, l1*sizeof(Rune));
204 		}
205 		ns->len = -l;
206 		r = &ns->Srune[l1];
207 		if(s2->len < 0)
208 			memmove(r, s2->Srune, -s2->len*sizeof(Rune));
209 		else
210 			cvtup(r, s2);
211 
212 		return ns;
213 	}
214 
215 	if(s2->len < 0) {
216 		l2 = -s2->len;
217 		l = s1->len + l2;
218 		ns = newrunes(append? (l+l/4): l);
219 		ns->len = -l;
220 		cvtup(ns->Srune, s1);
221 		memmove(&ns->Srune[s1->len], s2->Srune, l2*sizeof(Rune));
222 		return ns;
223 	}
224 
225 	l1 = s1->len;
226 	l = l1 + s2->len;
227 	if(append && l <= s1->max)
228 		ns = s1;
229 	else {
230 		ns = newstring(append? (l+l/4): l);
231 		memmove(ns->Sascii, s1->Sascii, l1);
232 	}
233 	ns->len = l;
234 	memmove(ns->Sascii+l1, s2->Sascii, s2->len);
235 
236 	return ns;
237 }
238 
239 OP(addc)
240 {
241 	String *ns, **sp;
242 
243 	ns = addstring(S(m), S(s), R.m == R.d);
244 
245 	sp = R.d;
246 	if(ns != *sp) {
247 		destroy(*sp);
248 		*sp = ns;
249 	}
250 }
251 
252 OP(cvtca)
253 {
254 	int l;
255 	Rune *r;
256 	char *p;
257 	String *ss;
258  	Array *a, **ap;
259 
260 	ss = S(s);
261 	if(ss == H) {
262 		a = mem2array(nil, 0);
263 		goto r;
264 	}
265 	if(ss->len < 0) {
266 		l = -ss->len;
267 		a = mem2array(nil, runenlen(ss->Srune, l));
268 		p = (char*)a->data;
269 		r = ss->Srune;
270 		while(l--)
271 			p += runetochar(p, r++);
272 		goto r;
273 	}
274 	a = mem2array(ss->Sascii, ss->len);
275 
276 r:	ap = R.d;
277 	destroy(*ap);
278 	*ap = a;
279 }
280 
281 OP(cvtac)
282 {
283 	Array *a;
284 	String *ds, **dp;
285 
286 	ds = H;
287 	a = A(s);
288 	if(a != H)
289 		ds = c2string((char*)a->data, a->len);
290 
291 	dp = R.d;
292 	destroy(*dp);
293 	*dp = ds;
294 }
295 
296 OP(lenc)
297 {
298 	int l;
299 	String *ss;
300 
301 	l = 0;
302 	ss = S(s);
303 	if(ss != H) {
304 		l = ss->len;
305 		if(l < 0)
306 			l = -l;
307 	}
308 	W(d) = l;
309 }
310 
311 OP(cvtcw)
312 {
313 	String *s;
314 
315 	s = S(s);
316 	if(s == H)
317 		W(d) = 0;
318 	else
319 	if(s->len < 0)
320 		W(d) = strtol(string2c(s), nil, 10);
321 	else {
322 		s->Sascii[s->len] = '\0';
323 		W(d) = strtol(s->Sascii, nil, 10);
324 	}
325 }
326 
327 OP(cvtcf)
328 {
329 	String *s;
330 
331 	s = S(s);
332 	if(s == H)
333 		F(d) = 0.0;
334 	else
335 	if(s->len < 0)
336 		F(d) = strtod(string2c(s), nil);
337 	else {
338 		s->Sascii[s->len] = '\0';
339 		F(d) = strtod(s->Sascii, nil);
340 	}
341 }
342 
343 OP(cvtwc)
344 {
345 	String *ds, **dp;
346 
347 	ds = newstring(16);
348 	ds->len = sprint(ds->Sascii, "%d", W(s));
349 
350 	dp = R.d;
351 	destroy(*dp);
352 	*dp = ds;
353 }
354 
355 OP(cvtlc)
356 {
357 	String *ds, **dp;
358 
359 	ds = newstring(16);
360 	ds->len = sprint(ds->Sascii, "%lld", V(s));
361 
362 	dp = R.d;
363 	destroy(*dp);
364 	*dp = ds;
365 }
366 
367 OP(cvtfc)
368 {
369 	String *ds, **dp;
370 
371 	ds = newstring(32);
372 	ds->len = sprint(ds->Sascii, "%g", F(s));
373 	dp = R.d;
374 	destroy(*dp);
375 	*dp = ds;
376 }
377 
378 char*
379 string2c(String *s)
380 {
381 	char *p;
382 	int c, l, nc;
383 	Rune *r, *er;
384 
385 	if(s == H)
386 		return "";
387 
388 	if(s->len >= 0) {
389 		s->Sascii[s->len] = '\0';
390 		return s->Sascii;
391 	}
392 
393 	nc = -s->len;
394 	l = (nc * UTFmax) + UTFmax;
395 	if(s->tmp == nil || msize(s->tmp) < l) {
396 		free(s->tmp);
397 		s->tmp = malloc(l);
398 		if(s->tmp == nil)
399 			error(exNomem);
400 	}
401 
402 	p = s->tmp;
403 	r = s->Srune;
404 	er = r + nc;
405 	while(r < er) {
406 		c = *r++;
407 		if(c < Runeself)
408 			*p++ = c;
409 		else
410 			p += runetochar(p, r-1);
411 	}
412 
413 	*p = 0;
414 
415 	return s->tmp;
416 }
417 
418 String*
419 c2string(char *cs, int len)
420 {
421 	uchar *p;
422 	char *ecs;
423 	String *s;
424 	Rune *r, junk;
425 	int c, nc, isrune;
426 
427 	isrune = 0;
428 	ecs = cs+len;
429 	p = (uchar*)cs;
430 	while(len--) {
431 		c = *p++;
432 		if(c >= Runeself) {
433 			isrune = 1;
434 			break;
435 		}
436 	}
437 
438 	if(isrune == 0) {
439 		nc = ecs - cs;
440 		s = newstring(nc);
441 		memmove(s->Sascii, cs, nc);
442 		return s;
443 	}
444 
445 	p--;
446 	nc = p - (uchar*)cs;
447 	while(p < (uchar*)ecs) {
448 		c = *p;
449 		if(c < Runeself)
450 			p++;
451 		else if(p+UTFmax<=(uchar*)ecs || fullrune((char*)p, (uchar*)ecs-p))
452 			p += chartorune(&junk, (char*)p);
453 		else
454 			break;
455 		nc++;
456 	}
457 	s = newrunes(nc);
458 	r = s->Srune;
459 	while(nc--)
460 		cs += chartorune(r++, cs);
461 
462 	return s;
463 }
464 
465 String*
466 newstring(int nb)
467 {
468 	Heap *h;
469 	String *s;
470 
471 	h = nheap(sizeof(String)+nb);
472 	h->t = &Tstring;
473 	Tstring.ref++;
474 	s = H2D(String*, h);
475 	s->tmp = nil;
476 	s->len = nb;
477 	s->max = hmsize(h) - (sizeof(String)+sizeof(Heap));
478 	return s;
479 }
480 
481 String*
482 newrunes(int nr)
483 {
484 	Heap *h;
485 	String *s;
486 
487 	if(nr == 0)
488 		return newstring(nr);
489 	if(nr < 0)
490 		nr = -nr;
491 	h = nheap(sizeof(String)+nr*sizeof(Rune));
492 	h->t = &Tstring;
493 	Tstring.ref++;
494 	s = H2D(String*, h);
495 	s->tmp = nil;
496 	s->len = -nr;
497 	s->max = (hmsize(h) - (sizeof(String)+sizeof(Heap)))/sizeof(Rune);
498 	return s;
499 }
500 
501 String*
502 stringdup(String *s)
503 {
504 	String *ns;
505 
506 	if(s == H)
507 		return H;
508 
509 	if(s->len >= 0) {
510 		ns = newstring(s->len);
511 		memmove(ns->Sascii, s->Sascii, s->len);
512 		return ns;
513 	}
514 
515 	ns = newrunes(-s->len);
516 	memmove(ns->Srune, s->Srune,-s->len*sizeof(Rune));
517 
518 	return ns;
519 }
520 
521 int
522 stringcmp(String *s1, String *s2)
523 {
524 	Rune *r1, *r2;
525 	char *a1, *a2;
526 	int v, n, n1, n2, c1, c2;
527 	static String snil = { 0, 0, nil };
528 
529 	if(s1 == H)
530 		s1 = &snil;
531 	if(s2 == H)
532 		s2 = &snil;
533 
534 	if(s1 == s2)
535 		return 0;
536 
537 	v = 0;
538 	n1 = s1->len;
539 	if(n1 < 0) {
540 		n1 = -n1;
541 		v |= 1;
542 	}
543 	n2 = s2->len;
544 	if(n2 < 0) {
545 		n2 = -n2;
546 		v |= 2;
547 	}
548 
549 	n = n1;
550 	if(n2 < n)
551 		n = n2;
552 
553 	switch(v) {
554 	case 0:		/* Ascii Ascii */
555 		n = memcmp(s1->Sascii, s2->Sascii, n);
556 		if(n == 0)
557 			n = n1 - n2;
558 		return n;
559 	case 1:		/* Rune Ascii */
560 		r1 = s1->Srune;
561 		a2 = s2->Sascii;
562 		while(n > 0) {
563 			c1 = *r1++;
564 			c2 = *a2++;
565 			if(c1 != c2)
566 				goto ne;
567 			n--;
568 		}
569 		break;
570 	case 2:		/* Ascii Rune */
571 		a1 = s1->Sascii;
572 		r2 = s2->Srune;
573 		while(n > 0) {
574 			c1 = *a1++;
575 			c2 = *r2++;
576 			if(c1 != c2)
577 				goto ne;
578 			n--;
579 		}
580 		break;
581 	case 3:		/* Rune Rune */
582 		r1 = s1->Srune;
583 		r2 = s2->Srune;
584 		while(n > 0) {
585 			c1 = *r1++;
586 			c2 = *r2++;
587 			if(c1 != c2)
588 				goto ne;
589 			n--;
590 		}
591 		break;
592 	}
593 	return n1 - n2;
594 
595 ne:	if(c1 < c2)
596 		return -1;
597 	return 1;
598 }
599 
600 String*
601 splitc(String **s, int expand)
602 {
603 	String *ss, *ns;
604 
605 	ss = *s;
606 	if(expand && ss->len > 0) {
607 		ns = newrunes(ss->len);
608 		cvtup(ns->Srune, ss);
609 	}
610 	else
611 		ns = stringdup(ss);
612 
613 	destroy(ss);
614 	*s = ns;
615 	return ns;
616 }
617