xref: /inferno-os/libinterp/runt.c (revision 4a062f32e3dd93bf371feb27f3ccc28d7930099e)
1 #include "lib9.h"
2 #include "isa.h"
3 #include "interp.h"
4 #include "runt.h"
5 #include "sysmod.h"
6 #include "raise.h"
7 
8 
9 static	int		utfnleng(char*, int, int*);
10 
11 void
sysmodinit(void)12 sysmodinit(void)
13 {
14 	sysinit();
15 	builtinmod("$Sys", Sysmodtab, Sysmodlen);
16 }
17 
18 int
xprint(Prog * xp,void * vfp,void * vva,String * s1,char * buf,int n)19 xprint(Prog *xp, void *vfp, void *vva, String *s1, char *buf, int n)
20 {
21 	WORD i;
22 	void *p;
23 	LONG bg;
24 	Type *t;
25 	double d;
26 	String *ss;
27 	ulong *ptr;
28 	uchar *fp, *va;
29 	int nc, c, isbig, isr, sip;
30 	char *b, *eb, *f, fmt[32];
31 	Rune r;
32 
33 	fp = vfp;
34 	va = vva;
35 
36 	sip = 0;
37 	isr = 0;
38 	if(s1 == H)
39 		return 0;
40 	nc = s1->len;
41 	if(nc < 0) {
42 		nc = -nc;
43 		isr = 1;
44 	}
45 
46 	b = buf;
47 	eb = buf+n-1;
48 	while(nc--) {
49 		c = isr ? s1->Srune[sip] : s1->Sascii[sip];
50 		sip++;
51 		if(c != '%') {
52 			if(b < eb) {
53 				if(c < Runeself)
54 					*b++ = c;
55 				else
56 					b += snprint(b, eb-b, "%C", c);
57 			}
58 			continue;
59 		}
60 		f = fmt;
61 		*f++ = c;
62 		isbig = 0;
63 		while(nc--) {
64 			c = isr ? s1->Srune[sip] : s1->Sascii[sip];
65 			sip++;
66 			*f++ = c;
67 			*f = '\0';
68 			switch(c) {
69 			default:
70 				continue;
71 			case '*':
72 				i = *(WORD*)va;
73 				f--;
74 				f += snprint(f, sizeof(fmt)-(f-fmt), "%d", i);
75 				va += IBY2WD;
76 				continue;
77 			case 'b':
78 				f[-1] = 'l';
79 				*f++ = 'l';
80 				*f = '\0';
81 				isbig = 1;
82 				continue;
83 			case '%':
84 				if(b < eb)
85 					*b++ = '%';
86 				break;
87 			case 'q':
88 			case 's':
89 				ss = *(String**)va;
90 				va += IBY2WD;
91 				if(ss == H)
92 					p = "";
93 				else
94 				if(ss->len < 0) {
95 					f[-1] += 'A'-'a';
96 					ss->Srune[-ss->len] = L'\0';
97 					p = ss->Srune;
98 				}
99 				else {
100 					ss->Sascii[ss->len] = '\0';
101 					p = ss->Sascii;
102 				}
103 				b += snprint(b, eb-b, fmt, p);
104 				break;
105 			case 'E':
106 				f--;
107 				r = 0x00c9;	/* L'É' */
108 				f += runetochar(f, &r);	/* avoid clash with ether address */
109 				*f = '\0';
110 				/* fall through */
111 			case 'e':
112 			case 'f':
113 			case 'g':
114 			case 'G':
115 				while((va - fp) & (sizeof(REAL)-1))
116 					va++;
117 				d = *(REAL*)va;
118 				b += snprint(b, eb-b, fmt, d);
119 				va += sizeof(REAL);
120 				break;
121 			case 'd':
122 			case 'o':
123 			case 'x':
124 			case 'X':
125 			case 'c':
126 				if(isbig) {
127 					while((va - fp) & (IBY2LG-1))
128 						va++;
129 					bg = *(LONG*)va;
130 					b += snprint(b, eb-b, fmt, bg);
131 					va += IBY2LG;
132 				}
133 				else {
134 					i = *(WORD*)va;
135 					/* always a unicode character */
136 					if(c == 'c')
137 						f[-1] = 'C';
138 					b += snprint(b, eb-b, fmt, i);
139 					va += IBY2WD;
140 				}
141 				break;
142 			case 'r':
143 				b = syserr(b, eb, xp);
144 				break;
145 /* Debugging formats - may disappear */
146 			case 'H':
147 				ptr = *(ulong**)va;
148 				c = -1;
149 				t = nil;
150 				if(ptr != H) {
151 					c = D2H(ptr)->ref;
152 					t = D2H(ptr)->t;
153 				}
154 				b += snprint(b, eb-b, "%d.%.8lux", c, (ulong)t);
155 				va += IBY2WD;
156 				break;
157 			}
158 			break;
159 		}
160 	}
161 	return b - buf;
162 }
163 
164 int
bigxprint(Prog * xp,void * vfp,void * vva,String * s1,char ** buf,int s)165 bigxprint(Prog *xp, void *vfp, void *vva, String *s1, char **buf, int s)
166 {
167 	char *b;
168 	int m, n;
169 
170 	m = s;
171 	for (;;) {
172 		m *= 2;
173 		b = malloc(m);
174 		if (b == nil)
175 			error(exNomem);
176 		n = xprint(xp, vfp, vva, s1, b, m);
177 		if (n < m-UTFmax-2)
178 			break;
179 		free(b);
180 	}
181 	*buf = b;
182 	return n;
183 }
184 
185 void
Sys_sprint(void * fp)186 Sys_sprint(void *fp)
187 {
188 	int n;
189 	char buf[256], *b = buf;
190 	F_Sys_sprint *f;
191 
192 	f = fp;
193 	n = xprint(currun(), f, &f->vargs, f->s, buf, sizeof(buf));
194 	if (n >= sizeof(buf)-UTFmax-2)
195 		n = bigxprint(currun(), f, &f->vargs, f->s, &b, sizeof(buf));
196 	b[n] = '\0';
197 	retstr(b, f->ret);
198 	if (b != buf)
199 		free(b);
200 }
201 
202 void
Sys_aprint(void * fp)203 Sys_aprint(void *fp)
204 {
205 	int n;
206 	char buf[256], *b = buf;
207 	F_Sys_aprint *f;
208 
209 	f = fp;
210 	n = xprint(currun(), f, &f->vargs, f->s, buf, sizeof(buf));
211 	if (n >= sizeof(buf)-UTFmax-2)
212 		n = bigxprint(currun(), f, &f->vargs, f->s, &b, sizeof(buf));
213 	destroy(*f->ret);
214 	*f->ret = mem2array(b, n);
215 	if (b != buf)
216 		free(b);
217 }
218 
219 static int
tokdelim(int c,String * d)220 tokdelim(int c, String *d)
221 {
222 	int l;
223 	char *p;
224 	Rune *r;
225 
226 	l = d->len;
227 	if(l < 0) {
228 		l = -l;
229 		for(r = d->Srune; l != 0; l--)
230 			if(*r++ == c)
231 				return 1;
232 		return 0;
233 	}
234 	for(p = d->Sascii; l != 0; l--)
235 		if(*p++ == c)
236 			return 1;
237 	return 0;
238 }
239 
240 void
Sys_tokenize(void * fp)241 Sys_tokenize(void *fp)
242 {
243 	String *s, *d;
244 	List **h, *l, *nl;
245 	F_Sys_tokenize *f;
246 	int n, c, nc, first, last, srune;
247 
248 	f = fp;
249 	s = f->s;
250 	d = f->delim;
251 
252 	if(s == H || d == H) {
253 		f->ret->t0 = 0;
254 		destroy(f->ret->t1);
255 		f->ret->t1 = H;
256 		return;
257 	}
258 
259 	n = 0;
260 	l = H;
261 	h = &l;
262 	first = 0;
263 	srune = 0;
264 
265 	nc = s->len;
266 	if(nc < 0) {
267 		nc = -nc;
268 		srune = 1;
269 	}
270 
271 	while(first < nc) {
272 		while(first < nc) {
273 			c = srune ? s->Srune[first] : s->Sascii[first];
274 			if(tokdelim(c, d) == 0)
275 				break;
276 			first++;
277 		}
278 
279 		last = first;
280 
281 		while(last < nc) {
282 			c = srune ? s->Srune[last] : s->Sascii[last];
283 			if(tokdelim(c, d) != 0)
284 				break;
285 			last++;
286 		}
287 
288 		if(first == last)
289 			break;
290 
291 		nl = cons(IBY2WD, h);
292 		nl->tail = H;
293 		nl->t = &Tptr;
294 		Tptr.ref++;
295 		*(String**)nl->data = slicer(first, last, s);
296 		h = &nl->tail;
297 
298 		first = last;
299 		n++;
300 	}
301 
302 	f->ret->t0 = n;
303 	destroy(f->ret->t1);
304 	f->ret->t1 = l;
305 }
306 
307 void
Sys_utfbytes(void * fp)308 Sys_utfbytes(void *fp)
309 {
310 	Array *a;
311 	int nbyte;
312 	F_Sys_utfbytes *f;
313 
314 	f = fp;
315 	a = f->buf;
316 	if(a == H || (UWORD)f->n > a->len)
317 		error(exBounds);
318 
319 	utfnleng((char*)a->data, f->n, &nbyte);
320 	*f->ret = nbyte;
321 }
322 
323 void
Sys_byte2char(void * fp)324 Sys_byte2char(void *fp)
325 {
326 	Rune r;
327 	char *p;
328 	int n, w;
329 	Array *a;
330 	F_Sys_byte2char *f;
331 
332 	f = fp;
333 	a = f->buf;
334 	n = f->n;
335 	if(a == H || (UWORD)n >= a->len)
336 		error(exBounds);
337 	r = a->data[n];
338 	if(r < Runeself){
339 		f->ret->t0 = r;
340 		f->ret->t1 = 1;
341 		f->ret->t2 = 1;
342 		return;
343 	}
344 	p = (char*)a->data+n;
345 	if(n+UTFmax <= a->len || fullrune(p, a->len-n))
346 		w = chartorune(&r, p);
347 	else {
348 		/* insufficient data */
349 		f->ret->t0 = Runeerror;
350 		f->ret->t1 = 0;
351 		f->ret->t2 = 0;
352 		return;
353 	}
354 	if(r == Runeerror && w==1){	/* encoding error */
355 		f->ret->t0 = Runeerror;
356 		f->ret->t1 = 1;
357 		f->ret->t2 = 0;
358 		return;
359 	}
360 	f->ret->t0 = r;
361 	f->ret->t1 = w;
362 	f->ret->t2 = 1;
363 }
364 
365 void
Sys_char2byte(void * fp)366 Sys_char2byte(void *fp)
367 {
368 	F_Sys_char2byte *f;
369 	Array *a;
370 	int n, c;
371 	Rune r;
372 
373 	f = fp;
374 	a = f->buf;
375 	n = f->n;
376 	c = f->c;
377 	if(a == H || (UWORD)n>=a->len)
378 		error(exBounds);
379 	if(c<0 || c>=Runemax)
380 		c = Runeerror;
381 	if(c < Runeself){
382 		a->data[n] = c;
383 		*f->ret = 1;
384 		return;
385 	}
386 	r = c;
387 	if(n+UTFmax<=a->len || runelen(c)<=a->len-n){
388 		*f->ret = runetochar((char*)a->data+n, &r);
389 		return;
390 	}
391 	*f->ret = 0;
392 }
393 
394 Module *
builtinmod(char * name,void * vr,int rlen)395 builtinmod(char *name, void *vr, int rlen)
396 {
397 	Runtab *r = vr;
398 	Type *t;
399 	Module *m;
400 	Link *l;
401 
402 	m = newmod(name);
403 	if(rlen == 0){
404 		while(r->name){
405 			rlen++;
406 			r++;
407 		}
408 		r = vr;
409 	}
410 	l = m->ext = (Link*)malloc((rlen+1)*sizeof(Link));
411 	if(l == nil){
412 		freemod(m);
413 		return nil;
414 	}
415 	while(r->name) {
416 		t = dtype(freeheap, r->size, r->map, r->np);
417 		runtime(m, l, r->name, r->sig, r->fn, t);
418 		r++;
419 		l++;
420 	}
421 	l->name = nil;
422 	return m;
423 }
424 
425 void
retnstr(char * s,int n,String ** d)426 retnstr(char *s, int n, String **d)
427 {
428 	String *s1;
429 
430 	s1 = H;
431 	if(n != 0)
432 		s1 = c2string(s, n);
433 	destroy(*d);
434 	*d = s1;
435 }
436 
437 void
retstr(char * s,String ** d)438 retstr(char *s, String **d)
439 {
440 	String *s1;
441 
442 	s1 = H;
443 	if(s != nil)
444 		s1 = c2string(s, strlen(s));
445 	destroy(*d);
446 	*d = s1;
447 }
448 
449 Array*
mem2array(void * va,int n)450 mem2array(void *va, int n)
451 {
452 	Heap *h;
453 	Array *a;
454 
455 	if(n < 0)
456 		n = 0;
457 	h = nheap(sizeof(Array)+n);
458 	h->t = &Tarray;
459 	h->t->ref++;
460 	a = H2D(Array*, h);
461 	a->t = &Tbyte;
462 	Tbyte.ref++;
463 	a->len = n;
464 	a->root = H;
465 	a->data = (uchar*)a+sizeof(Array);
466 	if(va != 0)
467 		memmove(a->data, va, n);
468 
469 	return a;
470 }
471 
472 static int
utfnleng(char * s,int nb,int * ngood)473 utfnleng(char *s, int nb, int *ngood)
474 {
475 	int c;
476 	long n;
477 	Rune rune;
478 	char *es, *starts;
479 
480 	starts = s;
481 	es = s+nb;
482 	for(n = 0; s < es; n++) {
483 		c = *(uchar*)s;
484 		if(c < Runeself)
485 			s++;
486 		else {
487 			if(s+UTFmax<=es || fullrune(s, es-s))
488 				s += chartorune(&rune, s);
489 			else
490 				break;
491 		}
492 	}
493 	if(ngood)
494 		*ngood = s-starts;
495 	return n;
496 }
497