xref: /plan9-contrib/sys/src/cmd/vi/cmd.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 #include <ctype.h>
6 #define Extern extern
7 #include "mips.h"
8 
9 char	buf[128], lastcmd[128];
10 char	fmt = 'X';
11 int	width = 60;
12 int	inc;
13 
14 ulong	expr(char*);
15 ulong	expr1(char*);
16 char*	term(char*, ulong*);
17 
18 char *
19 nextc(char *p)
20 {
21 	while(*p && (*p == ' ' || *p == '\t') && *p != '\n')
22 		p++;
23 
24 	if(*p == '\n')
25 		*p = '\0';
26 
27 	return p;
28 }
29 
30 char *
31 numsym(char *addr, ulong *val)
32 {
33 	char tsym[128], *t;
34 	static char *delim = "`'<>/\\@*|-~+-/=?\n";
35 	Symbol s;
36 	char c;
37 
38 	t = tsym;
39 	while(c = *addr) {
40 		if(strchr(delim, c))
41 			break;
42 		*t++ = c;
43 		addr++;
44 	}
45 	t[0] = '\0';
46 
47 	if(strcmp(tsym, ".") == 0) {
48 		*val = dot;
49 		return addr;
50 	}
51 
52 	if(lookup(0, tsym, &s))
53 		*val = s.value;
54 	else {
55 		if(tsym[0] == '#')
56 			*val = strtoul(tsym+1, 0, 16);
57 		else
58 			*val = strtoul(tsym, 0, 0);
59 	}
60 	return addr;
61 }
62 
63 ulong
64 expr(char *addr)
65 {
66 	ulong t, t2;
67 	char op;
68 
69 	if(*addr == '\0')
70 		return dot;
71 
72 	addr = numsym(addr, &t);
73 
74 	if(*addr == '\0')
75 		return t;
76 
77 	addr = nextc(addr);
78 	op = *addr++;
79 	numsym(addr, &t2);
80 	switch(op) {
81 	default:
82 		Bprint(bioout, "expr syntax\n");
83 		return 0;
84 	case '+':
85 		t += t2;
86 		break;
87 	case '-':
88 		t -= t2;
89 		break;
90 	case '%':
91 		t /= t2;
92 		break;
93 	case '&':
94 		t &= t2;
95 		break;
96 	case '|':
97 		t |= t2;
98 		break;
99 	}
100 
101 	return t;
102 }
103 
104 int
105 buildargv(char *str, char **args, int max)
106 {
107 	int na = 0;
108 
109 	while (na < max) {
110 		while((*str == ' ' || *str == '\t' || *str == '\n') && *str != '\0')
111 			str++;
112 
113 		if(*str == '\0')
114 			return na;
115 
116 		args[na++] = str;
117 		while(!(*str == ' ' || *str == '\t'|| *str == '\n') && *str != '\0')
118 			str++;
119 
120 		if(*str == '\n')
121 			*str = '\0';
122 
123 		if(*str == '\0')
124 			break;
125 
126 		*str++ = '\0';
127 	}
128 	return na;
129 }
130 
131 void
132 colon(char *addr, char *cp)
133 {
134 	int argc;
135 	char *argv[100];
136 	char tbuf[512];
137 
138 	cp = nextc(cp);
139 	switch(*cp) {
140 	default:
141 		Bprint(bioout, "?\n");
142 		return;
143 	case 'b':
144 		breakpoint(addr, cp+1);
145 		return;
146 
147 	case 'd':
148 		delbpt(addr);
149 		return;
150 
151 	/* These fall through to print the stopped address */
152 	case 'r':
153 		reset();
154 		argc = buildargv(cp+1, argv, 100);
155 		initstk(argc, argv);
156 		count = 0;
157 		atbpt = 0;
158 		run();
159 		break;
160 	case 'c':
161 		count = 0;
162 		atbpt = 0;
163 		run();
164 		break;
165 	case 's':
166 		cp = nextc(cp+1);
167 		count = 0;
168 		if(*cp)
169 			count = strtoul(cp, 0, 0);
170 		if(count == 0)
171 			count = 1;
172 		atbpt = 0;
173 		run();
174 		break;
175 	}
176 
177 	dot = reg.pc;
178 	Bprint(bioout, "%s at #%lux ", atbpt ? "breakpoint" : "stopped", dot);
179 	symoff(tbuf, sizeof(tbuf), dot, CTEXT);
180 	Bprint(bioout, tbuf);
181 	if(fmt == 'z')
182 		printsource(dot);
183 
184 	Bprint(bioout, "\n");
185 }
186 
187 
188 void
189 dollar(char *cp)
190 {
191 	cp = nextc(cp);
192 	switch(*cp) {
193 	default:
194 		Bprint(bioout, "?\n");
195 		break;
196 
197 	case 'c':
198 		stktrace(*cp);
199 		break;
200 
201 	case 'C':
202 		stktrace(*cp);
203 		break;
204 
205 	case 'b':
206 		dobplist();
207 		break;
208 
209 	case 'r':
210 		dumpreg();
211 		break;
212 
213 	case 'R':
214 		dumpreg();
215 
216 	case 'f':
217 		dumpfreg();
218 		break;
219 
220 	case 'F':
221 		dumpdreg();
222 		break;
223 
224 	case 'q':
225 		exits(0);
226 		break;
227 
228 	case 'Q':
229 		isum();
230 		tlbsum();
231 		segsum();
232 		break;
233 
234 	case 't':
235 		cp++;
236 		switch(*cp) {
237 		default:
238 			Bprint(bioout, ":t[0sic]\n");
239 			break;
240 		case '\0':
241 			trace = 1;
242 			break;
243 		case '0':
244 			trace = 0;
245 			sysdbg = 0;
246 			calltree = 0;
247 			break;
248 		case 's':
249 			sysdbg = 1;
250 			break;
251 		case 'i':
252 			trace = 1;
253 			break;
254 		case 'c':
255 			calltree = 1;
256 			break;
257 		}
258 		break;
259 
260 	case 'i':
261 		cp++;
262 		switch(*cp) {
263 		default:
264 			Bprint(bioout, "$i[itsa]\n");
265 			break;
266 		case 'i':
267 			isum();
268 			break;
269 		case 't':
270 			tlbsum();
271 			break;
272 		case 's':
273 			segsum();
274 			break;
275 		case 'a':
276 			isum();
277 			tlbsum();
278 			segsum();
279 			iprofile();
280 			break;
281 		case 'p':
282 			iprofile();
283 			break;
284 		}
285 	}
286 }
287 
288 int
289 pfmt(char fmt, int mem, ulong val)
290 {
291 	int c, i;
292 	Symbol s;
293 	char *p, ch, str[1024];
294 
295 	c = 0;
296 	switch(fmt) {
297 	default:
298 		Bprint(bioout, "bad modifier\n");
299 		return 0;
300 	case 'o':
301 		c = Bprint(bioout, "%-4o ", mem ? (ushort)getmem_2(dot) : val);
302 		inc = 2;
303 		break;
304 
305 	case 'O':
306 		c = Bprint(bioout, "%-8o ", mem ? getmem_4(dot) : val);
307 		inc = 4;
308 		break;
309 
310 	case 'q':
311 		c = Bprint(bioout, "%-4o ", mem ? (short)getmem_2(dot) : val);
312 		inc = 2;
313 		break;
314 
315 	case 'Q':
316 		c = Bprint(bioout, "%-8o ", mem ? (long)getmem_4(dot) : val);
317 		inc = 4;
318 		break;
319 
320 	case 'd':
321 		c = Bprint(bioout, "%-5ld ", mem ? (short)getmem_2(dot) : val);
322 		inc = 2;
323 		break;
324 
325 
326 	case 'D':
327 		c = Bprint(bioout, "%-8ld ", mem ? (long)getmem_4(dot) : val);
328 		inc = 4;
329 		break;
330 
331 	case 'x':
332 		c = Bprint(bioout, "#%-4lux ", mem ? (long)getmem_2(dot) : val);
333 		inc = 2;
334 		break;
335 
336 	case 'X':
337 		c = Bprint(bioout, "#%-8lux ", mem ? (long)getmem_4(dot) : val);
338 		inc = 4;
339 		break;
340 
341 	case 'u':
342 		c = Bprint(bioout, "%-5ld ", mem ? (ushort)getmem_2(dot) : val);
343 		inc = 2;
344 		break;
345 
346 	case 'U':
347 		c = Bprint(bioout, "%-8ld ", mem ? (ulong)getmem_4(dot) : val);
348 		inc = 4;
349 		break;
350 
351 	case 'b':
352 		c = Bprint(bioout, "%-3d ", mem ? getmem_b(dot) : val);
353 		inc = 1;
354 		break;
355 
356 	case 'c':
357 		c = Bprint(bioout, "%c ", mem ? getmem_b(dot) : val);
358 		inc = 1;
359 		break;
360 
361 	case 'C':
362 		ch = mem ? getmem_b(dot) : val;
363 		if(isprint(ch))
364 			c = Bprint(bioout, "%c ", ch);
365 		else
366 			c = Bprint(bioout, "\\x%.2x ", ch);
367 		inc = 1;
368 		break;
369 
370 	case 's':
371 		i = 0;
372 		while(ch = getmem_b(dot+i))
373 			str[i++] = ch;
374 		str[i] = '\0';
375 		dot += i;
376 		c = Bprint(bioout, "%s", str);
377 		inc = 0;
378 		break;
379 
380 	case 'S':
381 		i = 0;
382 		while(ch = getmem_b(dot+i))
383 			str[i++] = ch;
384 		str[i] = '\0';
385 		dot += i;
386 		for(p = str; *p; p++)
387 			if(isprint(*p))
388 				c += Bprint(bioout, "%c", *p);
389 			else
390 				c += Bprint(bioout, "\\x%.2lux", *p);
391 		inc = 0;
392 		break;
393 
394 	case 'Y':
395 		p = ctime(mem ? getmem_b(dot) : val);
396 		p[30] = '\0';
397 		c = Bprint(bioout, "%s", p);
398 		inc = 4;
399 		break;
400 
401 	case 'a':
402 		symoff(str, sizeof(str), dot, CTEXT);
403 		c = Bprint(bioout, str);
404 		inc = 0;
405 		break;
406 
407 	case 'e':
408 		for (i = 0; globalsym(&s, i); i++)
409 			Bprint(bioout, "%-15s #%lux\n", s.name,	getmem_4(s.value));
410 		inc = 0;
411 		break;
412 
413 	case 'i':
414 		inc = _mipscoinst(symmap, dot, str, sizeof(str));
415 		if (inc < 0) {
416 			Bprint(bioout, "vi: %r\n");
417 			return 0;
418 		}
419 		c = Bprint(bioout, str);
420 		break;
421 
422 	case 'n':
423 		c = width+1;
424 		inc = 0;
425 		break;
426 
427 	case '-':
428 		c = 0;
429 		inc = -1;
430 		break;
431 
432 	case '+':
433 		c = 0;
434 		inc = 1;
435 		break;
436 
437 	case '^':
438 		c = 0;
439 		if(inc > 0)
440 			inc = -inc;
441 		break;
442 
443 	case 'z':
444 		if (findsym(dot, CTEXT, &s))
445 			Bprint(bioout, "  %s() ", s.name);
446 		printsource(dot);
447 		inc = 0;
448 		break;
449 	}
450 	return c;
451 }
452 
453 void
454 eval(char *addr, char *p)
455 {
456 	ulong val;
457 
458 	val = expr(addr);
459 	p = nextc(p);
460 	if(*p == '\0') {
461 		p[0] = fmt;
462 		p[1] = '\0';
463 	}
464 	pfmt(*p, 0, val);
465 	Bprint(bioout, "\n");
466 }
467 
468 void
469 quesie(char *p)
470 {
471 	int c, count, i;
472 	char tbuf[512];
473 
474 	c = 0;
475 	symoff(tbuf, sizeof(tbuf), dot, CTEXT);
476 	Bprint(bioout, "%s?\t", tbuf);
477 
478 	while(*p) {
479 		p = nextc(p);
480 		if(*p == '"') {
481 			for(p++; *p && *p != '"'; p++) {
482 				Bputc(bioout, *p);
483 				c++;
484 			}
485 			if(*p)
486 				p++;
487 			continue;
488 		}
489 		count = 0;
490 		while(*p >= '0' && *p <= '9')
491 			count = count*10 + (*p++ - '0');
492 		if(count == 0)
493 			count = 1;
494 		p = nextc(p);
495 		if(*p == '\0') {
496 			p[0] = fmt;
497 			p[1] = '\0';
498 		}
499 		for(i = 0; i < count; i++) {
500 			c += pfmt(*p, 1, 0);
501 			dot += inc;
502 			if(c > width) {
503 				Bprint(bioout, "\n");
504 				symoff(tbuf, sizeof(tbuf), dot, CTEXT);
505 				Bprint(bioout, "%s?\t", tbuf);
506 				c = 0;
507 			}
508 		}
509 		fmt = *p++;
510 		p = nextc(p);
511 	}
512 	Bprint(bioout, "\n");
513 }
514 
515 void
516 catcher(void *a, char *msg)
517 {
518 	USED(a);
519 	if(strcmp(msg, "interrupt") != 0)
520 		noted(NDFLT);
521 
522 	count = 1;
523 	print("vi\n");
524 	noted(NCONT);
525 }
526 
527 void
528 setreg(char *addr, char *cp)
529 {
530 	int rn;
531 
532 	dot = expr(addr);
533 	cp = nextc(cp);
534 	if(strcmp(cp, "pc") == 0) {
535 		reg.pc = dot;
536 		return;
537 	}
538 	if(strcmp(cp, "sp") == 0) {
539 		reg.r[29] = dot;
540 		return;
541 	}
542 	if(strcmp(cp, "mh") == 0) {
543 		reg.mhi = dot;
544 		return;
545 	}
546 	if(strcmp(cp, "ml") == 0) {
547 		reg.mlo = dot;
548 		return;
549 	}
550 	if(*cp++ == 'r') {
551 		rn = strtoul(cp, 0, 10);
552 		if(rn > 0 && rn < 32) {
553 			reg.r[rn] = dot;
554 			return;
555 		}
556 	}
557 	Bprint(bioout, "bad register\n");
558 }
559 
560 void
561 cmd(void)
562 {
563 	char *p, *a, *cp, *gotint;
564 	char addr[128];
565 	static char *cmdlet = ":$?/=>";
566 	int n, i;
567 
568 	notify(catcher);
569 
570 	dot = reg.pc;
571 	setjmp(errjmp);
572 
573 	for(;;) {
574 		Bflush(bioout);
575 		p = buf;
576 		n = 0;
577 		for(;;) {
578 			i = Bgetc(bin);
579 			if(i < 0)
580 				exits(0);
581 			*p++ = i;
582 			n++;
583 			if(i == '\n')
584 				break;
585 		}
586 
587 		if(buf[0] == '\n')
588 			strcpy(buf, lastcmd);
589 		else {
590 			buf[n-1] = '\0';
591 			strcpy(lastcmd, buf);
592 		}
593 		p = buf;
594 		a = addr;
595 
596 		for(;;) {
597 			p = nextc(p);
598 			if(*p == 0 || strchr(cmdlet, *p))
599 				break;
600 			*a++ = *p++;
601 		}
602 
603 		*a = '\0';
604 		cmdcount = 1;
605 		cp = strchr(addr, ',');
606 		if(cp != 0) {
607 			if(cp[1] == '#')
608 				cmdcount = strtoul(cp+2, &gotint, 16);
609 			else
610 				cmdcount = strtoul(cp+1, &gotint, 0);
611 			*cp = '\0';
612 		}
613 
614 		switch(*p) {
615 		case '$':
616 			dollar(p+1);
617 			break;
618 		case ':':
619 			colon(addr, p+1);
620 			break;
621 		case '/':
622 		case '?':
623 			dot = expr(addr);
624 			for(i = 0; i < cmdcount; i++)
625 				quesie(p+1);
626 			break;
627 		case '=':
628 			eval(addr, p+1);
629 			break;
630 		case '>':
631 			setreg(addr, p+1);
632 			break;
633 		default:
634 			Bprint(bioout, "?\n");
635 			break;
636 		}
637 	}
638 }
639