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