1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <ctype.h> 5 #include <mach.h> 6 #include <regexp.h> 7 #define Extern extern 8 #include "acid.h" 9 #include "y.tab.h" 10 11 void cvtatof(Node*, Node*); 12 void cvtatoi(Node*, Node*); 13 void cvtitoa(Node*, Node*); 14 void bprint(Node*, Node*); 15 void funcbound(Node*, Node*); 16 void printto(Node*, Node*); 17 void getfile(Node*, Node*); 18 void fmt(Node*, Node*); 19 void pcfile(Node*, Node*); 20 void pcline(Node*, Node*); 21 void setproc(Node*, Node*); 22 void strace(Node*, Node*); 23 void follow(Node*, Node*); 24 void reason(Node*, Node*); 25 void newproc(Node*, Node*); 26 void startstop(Node*, Node*); 27 void match(Node*, Node*); 28 void status(Node*, Node*); 29 void kill(Node*,Node*); 30 void waitstop(Node*, Node*); 31 void stop(Node*, Node*); 32 void start(Node*, Node*); 33 void filepc(Node*, Node*); 34 void doerror(Node*, Node*); 35 void rc(Node*, Node*); 36 void doaccess(Node*, Node*); 37 void map(Node*, Node*); 38 void readfile(Node*, Node*); 39 void interpret(Node*, Node*); 40 void include(Node*, Node*); 41 void regexp(Node*, Node*); 42 43 typedef struct Btab Btab; 44 struct Btab 45 { 46 char *name; 47 void (*fn)(Node*, Node*); 48 } tab[] = 49 { 50 "atof", cvtatof, 51 "atoi", cvtatoi, 52 "error", doerror, 53 "file", getfile, 54 "readfile", readfile, 55 "access", doaccess, 56 "filepc", filepc, 57 "fnbound", funcbound, 58 "fmt", fmt, 59 "follow", follow, 60 "itoa", cvtitoa, 61 "kill", kill, 62 "match", match, 63 "newproc", newproc, 64 "pcfile", pcfile, 65 "pcline", pcline, 66 "print", bprint, 67 "printto", printto, 68 "rc", rc, 69 "reason", reason, 70 "setproc", setproc, 71 "start", start, 72 "startstop", startstop, 73 "status", status, 74 "stop", stop, 75 "strace", strace, 76 "waitstop", waitstop, 77 "map", map, 78 "interpret", interpret, 79 "include", include, 80 "regexp", regexp, 81 0 82 }; 83 84 void 85 mkprint(Lsym *s) 86 { 87 prnt = malloc(sizeof(Node)); 88 prnt->op = OCALL; 89 prnt->left = malloc(sizeof(Node)); 90 prnt->left->sym = s; 91 } 92 93 void 94 installbuiltin(void) 95 { 96 Btab *b; 97 Lsym *s; 98 99 b = tab; 100 while(b->name) { 101 s = look(b->name); 102 if(s == 0) 103 s = enter(b->name, Tid); 104 105 s->builtin = b->fn; 106 if(b->fn == bprint) 107 mkprint(s); 108 b++; 109 } 110 } 111 112 void 113 match(Node *r, Node *args) 114 { 115 int i; 116 List *f; 117 Node *av[Maxarg]; 118 Node resi, resl; 119 120 na = 0; 121 flatten(av, args); 122 if(na != 2) 123 error("match(obj, list): arg count"); 124 125 expr(av[1], &resl); 126 if(resl.type != TLIST) 127 error("match(obj, list): need list"); 128 expr(av[0], &resi); 129 130 r->op = OCONST; 131 r->type = TINT; 132 r->fmt = 'D'; 133 r->ival = -1; 134 135 i = 0; 136 for(f = resl.l; f; f = f->next) { 137 if(resi.type == f->type) { 138 switch(resi.type) { 139 case TINT: 140 if(resi.ival == f->ival) { 141 r->ival = i; 142 return; 143 } 144 break; 145 case TFLOAT: 146 if(resi.fval == f->fval) { 147 r->ival = i; 148 return; 149 } 150 break; 151 case TSTRING: 152 if(scmp(resi.string, f->string)) { 153 r->ival = i; 154 return; 155 } 156 break; 157 case TLIST: 158 error("match(obj, list): not defined for list"); 159 } 160 } 161 i++; 162 } 163 } 164 165 void 166 newproc(Node *r, Node *args) 167 { 168 int i; 169 Node res; 170 char *p, *e; 171 char *argv[Maxarg], buf[Strsize]; 172 173 i = 1; 174 argv[0] = aout; 175 176 if(args) { 177 expr(args, &res); 178 if(res.type != TSTRING) 179 error("newproc(): arg not string"); 180 if(res.string->len >= sizeof(buf)) 181 error("newproc(): too many arguments"); 182 memmove(buf, res.string->string, res.string->len); 183 buf[res.string->len] = '\0'; 184 p = buf; 185 e = buf+res.string->len; 186 for(;;) { 187 while(p < e && (*p == '\t' || *p == ' ')) 188 *p++ = '\0'; 189 if(p >= e) 190 break; 191 argv[i++] = p; 192 if(i >= Maxarg) 193 error("newproc: too many arguments"); 194 while(p < e && *p != '\t' && *p != ' ') 195 p++; 196 } 197 } 198 argv[i] = 0; 199 r->op = OCONST; 200 r->type = TINT; 201 r->fmt = 'D'; 202 r->ival = nproc(argv); 203 } 204 205 void 206 startstop(Node *r, Node *args) 207 { 208 Node res; 209 210 USED(r); 211 if(args == 0) 212 error("startstop(pid): no pid"); 213 expr(args, &res); 214 if(res.type != TINT) 215 error("startstop(pid): arg type"); 216 217 msg(res.ival, "startstop"); 218 notes(res.ival); 219 dostop(res.ival); 220 } 221 222 void 223 waitstop(Node *r, Node *args) 224 { 225 Node res; 226 227 USED(r); 228 if(args == 0) 229 error("waitstop(pid): no pid"); 230 expr(args, &res); 231 if(res.type != TINT) 232 error("waitstop(pid): arg type"); 233 234 Bflush(bout); 235 msg(res.ival, "waitstop"); 236 notes(res.ival); 237 dostop(res.ival); 238 } 239 240 void 241 start(Node *r, Node *args) 242 { 243 Node res; 244 245 USED(r); 246 if(args == 0) 247 error("start(pid): no pid"); 248 expr(args, &res); 249 if(res.type != TINT) 250 error("start(pid): arg type"); 251 252 msg(res.ival, "start"); 253 } 254 255 void 256 stop(Node *r, Node *args) 257 { 258 Node res; 259 260 USED(r); 261 if(args == 0) 262 error("stop(pid): no pid"); 263 expr(args, &res); 264 if(res.type != TINT) 265 error("stop(pid): arg type"); 266 267 Bflush(bout); 268 msg(res.ival, "stop"); 269 notes(res.ival); 270 dostop(res.ival); 271 } 272 273 void 274 kill(Node *r, Node *args) 275 { 276 Node res; 277 278 USED(r); 279 if(args == 0) 280 error("kill(pid): no pid"); 281 expr(args, &res); 282 if(res.type != TINT) 283 error("kill(pid): arg type"); 284 285 msg(res.ival, "kill"); 286 deinstall(res.ival); 287 } 288 289 void 290 status(Node *r, Node *args) 291 { 292 Node res; 293 char *p; 294 295 USED(r); 296 if(args == 0) 297 error("status(pid): no pid"); 298 expr(args, &res); 299 if(res.type != TINT) 300 error("status(pid): arg type"); 301 302 p = getstatus(res.ival); 303 r->string = strnode(p); 304 r->op = OCONST; 305 r->fmt = 's'; 306 r->type = TSTRING; 307 } 308 309 void 310 reason(Node *r, Node *args) 311 { 312 Node res; 313 314 if(args == 0) 315 error("reason(cause): no cause"); 316 expr(args, &res); 317 if(res.type != TINT) 318 error("reason(cause): arg type"); 319 320 r->op = OCONST; 321 r->type = TSTRING; 322 r->fmt = 's'; 323 r->string = strnode((*machdata->excep)(cormap, rget)); 324 } 325 326 void 327 follow(Node *r, Node *args) 328 { 329 int n, i; 330 Node res; 331 ulong f[10]; 332 List **tail, *l; 333 334 if(args == 0) 335 error("follow(addr): no addr"); 336 expr(args, &res); 337 if(res.type != TINT) 338 error("follow(addr): arg type"); 339 340 n = (*machdata->foll)(cormap, res.ival, rget, f); 341 if (n < 0) 342 error("follow(addr): %r"); 343 tail = &r->l; 344 for(i = 0; i < n; i++) { 345 l = al(TINT); 346 l->ival = f[i]; 347 l->fmt = 'X'; 348 *tail = l; 349 tail = &l->next; 350 } 351 } 352 353 void 354 funcbound(Node *r, Node *args) 355 { 356 int n; 357 Node res; 358 ulong bounds[2]; 359 List *l; 360 361 if(args == 0) 362 error("fnbound(addr): no addr"); 363 expr(args, &res); 364 if(res.type != TINT) 365 error("fnbound(addr): arg type"); 366 367 n = fnbound(res.ival, bounds); 368 if (n != 0) { 369 r->l = al(TINT); 370 l = r->l; 371 l->ival = bounds[0]; 372 l->fmt = 'X'; 373 l->next = al(TINT); 374 l = l->next; 375 l->ival = bounds[1]; 376 l->fmt = 'X'; 377 } 378 } 379 380 void 381 setproc(Node *r, Node *args) 382 { 383 Node res; 384 385 USED(r); 386 if(args == 0) 387 error("setproc(pid): no pid"); 388 expr(args, &res); 389 if(res.type != TINT) 390 error("setproc(pid): arg type"); 391 392 sproc(res.ival); 393 } 394 395 void 396 filepc(Node *r, Node *args) 397 { 398 Node res; 399 char *p, c; 400 401 if(args == 0) 402 error("filepc(filename:line): arg count"); 403 expr(args, &res); 404 if(res.type != TSTRING) 405 error("filepc(filename:line): arg type"); 406 407 p = strchr(res.string->string, ':'); 408 if(p == 0) 409 error("filepc(filename:line): bad arg format"); 410 411 c = *p; 412 *p++ = '\0'; 413 r->ival = file2pc(res.string->string, atoi(p)); 414 p[-1] = c; 415 if(r->ival == -1) 416 error("filepc(filename:line): can't find address"); 417 418 r->op = OCONST; 419 r->type = TINT; 420 r->fmt = 'X'; 421 } 422 423 void 424 interpret(Node *r, Node *args) 425 { 426 Node res; 427 int isave; 428 429 if(args == 0) 430 error("interpret(string): arg count"); 431 expr(args, &res); 432 if(res.type != TSTRING) 433 error("interpret(string): arg type"); 434 435 pushstr(&res); 436 437 isave = interactive; 438 interactive = 0; 439 r->ival = yyparse(); 440 interactive = isave; 441 popio(); 442 r->op = OCONST; 443 r->type = TINT; 444 r->fmt = 'D'; 445 } 446 447 void 448 include(Node *r, Node *args) 449 { 450 Node res; 451 int isave; 452 453 if(args == 0) 454 error("include(string): arg count"); 455 expr(args, &res); 456 if(res.type != TSTRING) 457 error("include(string): arg type"); 458 459 pushfile(res.string->string); 460 461 isave = interactive; 462 interactive = 0; 463 r->ival = yyparse(); 464 interactive = isave; 465 popio(); 466 r->op = OCONST; 467 r->type = TINT; 468 r->fmt = 'D'; 469 } 470 471 void 472 rc(Node *r, Node *args) 473 { 474 Node res; 475 int pid; 476 char *p, *q, *argv[4]; 477 478 USED(r); 479 if(args == 0) 480 error("error(string): arg count"); 481 expr(args, &res); 482 if(res.type != TSTRING) 483 error("error(string): arg type"); 484 485 argv[0] = "/bin/rc"; 486 argv[1] = "-c"; 487 argv[2] = res.string->string; 488 argv[3] = 0; 489 490 pid = fork(); 491 switch(pid) { 492 case -1: 493 error("fork %r"); 494 case 0: 495 exec("/bin/rc", argv); 496 exits(0); 497 default: 498 p = waitfor(pid); 499 break; 500 } 501 q = strrchr(p, ':'); 502 if (q) 503 p = q+1; 504 505 r->op = OCONST; 506 r->type = TSTRING; 507 r->string = strnode(p); 508 r->fmt = 's'; 509 } 510 511 void 512 doerror(Node *r, Node *args) 513 { 514 Node res; 515 516 USED(r); 517 if(args == 0) 518 error("error(string): arg count"); 519 expr(args, &res); 520 if(res.type != TSTRING) 521 error("error(string): arg type"); 522 523 error(res.string->string); 524 } 525 526 void 527 doaccess(Node *r, Node *args) 528 { 529 Node res; 530 531 if(args == 0) 532 error("access(filename): arg count"); 533 expr(args, &res); 534 if(res.type != TSTRING) 535 error("access(filename): arg type"); 536 537 r->op = OCONST; 538 r->type = TINT; 539 r->ival = 0; 540 if(access(res.string->string, OREAD) == 0) 541 r->ival = 1; 542 } 543 544 void 545 readfile(Node *r, Node *args) 546 { 547 Node res; 548 int n, fd; 549 char *buf; 550 Dir db; 551 552 if(args == 0) 553 error("readfile(filename): arg count"); 554 expr(args, &res); 555 if(res.type != TSTRING) 556 error("readfile(filename): arg type"); 557 558 fd = open(res.string->string, OREAD); 559 if(fd < 0) 560 return; 561 562 dirfstat(fd, &db); 563 if(db.length == 0) 564 n = 8192; 565 else 566 n = db.length; 567 568 buf = malloc(n); 569 n = read(fd, buf, n); 570 571 if(n > 0) { 572 r->op = OCONST; 573 r->type = TSTRING; 574 r->string = strnodlen(buf, n); 575 r->fmt = 's'; 576 } 577 free(buf); 578 close(fd); 579 } 580 581 void 582 getfile(Node *r, Node *args) 583 { 584 int n; 585 char *p; 586 Node res; 587 String *s; 588 Biobuf *bp; 589 List **l, *new; 590 591 if(args == 0) 592 error("file(filename): arg count"); 593 expr(args, &res); 594 if(res.type != TSTRING) 595 error("file(filename): arg type"); 596 597 r->op = OCONST; 598 r->type = TLIST; 599 r->l = 0; 600 601 p = res.string->string; 602 bp = Bopen(p, OREAD); 603 if(bp == 0) 604 return; 605 606 l = &r->l; 607 for(;;) { 608 p = Brdline(bp, '\n'); 609 n = BLINELEN(bp); 610 if(p == 0) { 611 if(n == 0) 612 break; 613 s = strnodlen(0, n); 614 Bread(bp, s->string, n); 615 } 616 else 617 s = strnodlen(p, n-1); 618 619 new = al(TSTRING); 620 new->string = s; 621 new->fmt = 's'; 622 *l = new; 623 l = &new->next; 624 } 625 Bterm(bp); 626 } 627 628 void 629 cvtatof(Node *r, Node *args) 630 { 631 Node res; 632 633 if(args == 0) 634 error("atof(string): arg count"); 635 expr(args, &res); 636 if(res.type != TSTRING) 637 error("atof(string): arg type"); 638 639 r->op = OCONST; 640 r->type = TFLOAT; 641 r->fval = atof(res.string->string); 642 r->fmt = 'f'; 643 } 644 645 void 646 cvtatoi(Node *r, Node *args) 647 { 648 Node res; 649 650 if(args == 0) 651 error("atoi(string): arg count"); 652 expr(args, &res); 653 if(res.type != TSTRING) 654 error("atoi(string): arg type"); 655 656 r->op = OCONST; 657 r->type = TINT; 658 r->ival = strtoul(res.string->string, 0, 0); 659 r->fmt = 'D'; 660 } 661 662 void 663 cvtitoa(Node *r, Node *args) 664 { 665 Node res; 666 char buf[128]; 667 668 if(args == 0) 669 error("itoa(integer): arg count"); 670 expr(args, &res); 671 if(res.type != TINT) 672 error("itoa(integer): arg type"); 673 674 sprint(buf, "%d", res.ival); 675 r->op = OCONST; 676 r->type = TSTRING; 677 r->string = strnode(buf); 678 r->fmt = 's'; 679 } 680 681 List* 682 mapent(Map *m) 683 { 684 int i; 685 List *l, *n, **t, *h; 686 687 h = 0; 688 t = &h; 689 for(i = 0; i < m->nsegs; i++) { 690 if(m->seg[i].inuse == 0) 691 continue; 692 l = al(TSTRING); 693 n = al(TLIST); 694 n->l = l; 695 *t = n; 696 t = &n->next; 697 l->string = strnode(m->seg[i].name); 698 l->fmt = 's'; 699 l->next = al(TINT); 700 l = l->next; 701 l->ival = m->seg[i].b; 702 l->fmt = 'X'; 703 l->next = al(TINT); 704 l = l->next; 705 l->ival = m->seg[i].e; 706 l->fmt = 'X'; 707 l->next = al(TINT); 708 l = l->next; 709 l->ival = m->seg[i].f; 710 l->fmt = 'X'; 711 } 712 return h; 713 } 714 715 void 716 map(Node *r, Node *args) 717 { 718 int i; 719 Map *m; 720 List *l; 721 char *ent; 722 Node *av[Maxarg], res; 723 724 na = 0; 725 flatten(av, args); 726 727 if(na != 0) { 728 expr(av[0], &res); 729 if(res.type != TLIST) 730 error("map(list): map needs a list"); 731 if(listlen(res.l) != 4) 732 error("map(list): list must have 4 entries"); 733 734 l = res.l; 735 if(l->type != TSTRING) 736 error("map name must be a string"); 737 ent = l->string->string; 738 m = symmap; 739 i = findseg(m, ent); 740 if(i < 0) { 741 m = cormap; 742 i = findseg(m, ent); 743 } 744 if(i < 0) 745 error("%s is not a map entry", ent); 746 l = l->next; 747 if(l->type != TINT) 748 error("map entry not int"); 749 m->seg[i].b = l->ival; 750 if (strcmp(ent, "text") == 0) 751 textseg(l->ival, &fhdr); 752 l = l->next; 753 if(l->type != TINT) 754 error("map entry not int"); 755 m->seg[i].e = l->ival; 756 l = l->next; 757 if(l->type != TINT) 758 error("map entry not int"); 759 m->seg[i].f = l->ival; 760 } 761 762 r->type = TLIST; 763 r->l = 0; 764 if(symmap) 765 r->l = mapent(symmap); 766 if(cormap) { 767 if(r->l == 0) 768 r->l = mapent(cormap); 769 else { 770 for(l = r->l; l->next; l = l->next) 771 ; 772 l->next = mapent(cormap); 773 } 774 } 775 } 776 777 void 778 flatten(Node **av, Node *n) 779 { 780 if(n == 0) 781 return; 782 783 switch(n->op) { 784 case OLIST: 785 flatten(av, n->left); 786 flatten(av, n->right); 787 break; 788 default: 789 av[na++] = n; 790 if(na >= Maxarg) 791 error("too many function arguments"); 792 break; 793 } 794 } 795 796 void 797 strace(Node *r, Node *args) 798 { 799 Node *av[Maxarg], *n, res; 800 ulong pc, sp; 801 802 na = 0; 803 flatten(av, args); 804 if(na != 3) 805 error("strace(pc, sp, link): arg count"); 806 807 n = av[0]; 808 expr(n, &res); 809 if(res.type != TINT) 810 error("strace(pc, sp, link): pc bad type"); 811 pc = res.ival; 812 813 n = av[1]; 814 expr(n, &res); 815 if(res.type != TINT) 816 error("strace(pc, sp, link): sp bad type"); 817 sp = res.ival; 818 819 n = av[2]; 820 expr(n, &res); 821 if(res.type != TINT) 822 error("strace(pc, sp, link): link bad type"); 823 824 tracelist = 0; 825 if ((*machdata->ctrace)(cormap, pc, sp, res.ival, trlist) <= 0) 826 error("no stack frame"); 827 r->type = TLIST; 828 r->l = tracelist; 829 } 830 831 void 832 regerror(char *msg) 833 { 834 error(msg); 835 } 836 837 void 838 regexp(Node *r, Node *args) 839 { 840 Node res; 841 Reprog *rp; 842 Node *av[Maxarg]; 843 844 na = 0; 845 flatten(av, args); 846 if(na != 2) 847 error("regexp(pattern, string): arg count"); 848 expr(av[0], &res); 849 if(res.type != TSTRING) 850 error("regexp(pattern, string): pattern must be string"); 851 rp = regcomp(res.string->string); 852 if(rp == 0) 853 return; 854 855 expr(av[1], &res); 856 if(res.type != TSTRING) 857 error("regexp(pattern, string): bad string"); 858 859 r->fmt = 'D'; 860 r->type = TINT; 861 r->ival = regexec(rp, res.string->string, 0, 0); 862 free(rp); 863 } 864 865 char vfmt[] = "cCBbsxXdDuUoOaFfiIqQrRYgG"; 866 867 void 868 fmt(Node *r, Node *args) 869 { 870 Node res; 871 Node *av[Maxarg]; 872 873 na = 0; 874 flatten(av, args); 875 if(na != 2) 876 error("fmt(obj, fmt): arg count"); 877 expr(av[1], &res); 878 if(res.type != TINT || strchr(vfmt, res.ival) == 0) 879 error("fmt(obj, fmt): bad format '%c'", res.ival); 880 expr(av[0], r); 881 r->fmt = res.ival; 882 } 883 884 void 885 patom(char type, Store *res) 886 { 887 int i; 888 char *p; 889 extern char *typestr[]; 890 char buf[512]; 891 892 switch(res->fmt) { 893 case 'c': 894 Bprint(bout, "%c", res->ival); 895 break; 896 case 'C': 897 if(res->ival < ' ' || res->ival >= 0x7f) 898 Bprint(bout, "%3d", res->ival&0xff); 899 else 900 Bprint(bout, "%3c", res->ival); 901 break; 902 case 'r': 903 Bprint(bout, "%C", res->ival); 904 break; 905 case 'b': 906 Bprint(bout, "%3d", res->ival&0xff); 907 break; 908 case 'B': 909 memset(buf, '0', 34); 910 buf[1] = 'b'; 911 for(i = 0; i < 32; i++) { 912 if(res->ival & (1<<i)) 913 buf[33-i] = '1'; 914 } 915 buf[35] = '\0'; 916 Bprint(bout, "%s", buf); 917 break; 918 case 'X': 919 Bprint(bout, "%.8lux", res->ival); 920 break; 921 case 'x': 922 Bprint(bout, "%.4lux", res->ival&0xffff); 923 break; 924 case 'D': 925 Bprint(bout, "%d", res->ival); 926 break; 927 case 'd': 928 Bprint(bout, "%d", (ushort)res->ival); 929 break; 930 case 'u': 931 Bprint(bout, "%d", res->ival&0xffff); 932 break; 933 case 'U': 934 Bprint(bout, "%d", (ulong)res->ival); 935 break; 936 case 'o': 937 Bprint(bout, "0%.11uo", res->ival&0xffff); 938 break; 939 case 'O': 940 Bprint(bout, "0%.6uo", res->ival); 941 break; 942 case 'q': 943 Bprint(bout, "0%.11o", (short)(res->ival&0xffff)); 944 break; 945 case 'Q': 946 Bprint(bout, "0%.6o", res->ival); 947 break; 948 case 'f': 949 case 'F': 950 if(type != TFLOAT) 951 Bprint(bout, "*%c<%s>*", res->fmt, typestr[type]); 952 else 953 Bprint(bout, "%g", res->fval); 954 break; 955 case 's': 956 case 'g': 957 case 'G': 958 if(type != TSTRING) 959 Bprint(bout, "*%c<%s>*", res->fmt, typestr[type]); 960 else 961 Bwrite(bout, res->string->string, res->string->len); 962 break; 963 case 'R': 964 if(type != TSTRING) 965 Bprint(bout, "*%c<%s>*", res->fmt, typestr[type]); 966 else 967 Bprint(bout, "%S", res->string->string); 968 break; 969 case 'a': 970 case 'A': 971 symoff(buf, sizeof(buf), res->ival, CANY); 972 Bprint(bout, "%s", buf); 973 break; 974 case 'Y': 975 p = ctime(res->ival); 976 p[strlen(p)-1] = '\0'; 977 Bprint(bout, "%s", p); 978 break; 979 case 'I': 980 case 'i': 981 if(type != TINT) 982 Bprint(bout, "*%c<%s>*", res->fmt, typestr[type]); 983 else { 984 if ((*machdata->das)(symmap, res->ival, res->fmt, buf, sizeof(buf)) < 0) 985 Bprint(bout, "no instruction: %r"); 986 else 987 Bprint(bout, "%s", buf); 988 } 989 break; 990 } 991 } 992 993 void 994 blprint(List *l) 995 { 996 Bprint(bout, "{"); 997 while(l) { 998 switch(l->type) { 999 default: 1000 patom(l->type, &l->Store); 1001 break; 1002 case TSTRING: 1003 Bputc(bout, '"'); 1004 patom(l->type, &l->Store); 1005 Bputc(bout, '"'); 1006 break; 1007 case TLIST: 1008 blprint(l->l); 1009 break; 1010 case TCODE: 1011 pcode(l->cc, 0); 1012 break; 1013 } 1014 l = l->next; 1015 if(l) 1016 Bprint(bout, ", "); 1017 } 1018 Bprint(bout, "}"); 1019 } 1020 1021 int 1022 comx(Node res) 1023 { 1024 Lsym *sl; 1025 Node *n, xx; 1026 1027 if(res.fmt != 'a' && res.fmt != 'A') 1028 return 0; 1029 1030 if(res.comt == 0 || res.comt->base == 0) 1031 return 0; 1032 1033 sl = res.comt->base; 1034 if(sl->proc) { 1035 res.left = ZN; 1036 res.right = ZN; 1037 n = an(ONAME, ZN, ZN); 1038 n->sym = sl; 1039 n = an(OCALL, n, &res); 1040 n->left->sym = sl; 1041 expr(n, &xx); 1042 return 1; 1043 } 1044 print("(%s)", sl->name); 1045 return 0; 1046 } 1047 1048 void 1049 bprint(Node *r, Node *args) 1050 { 1051 int i, nas; 1052 Node res, *av[Maxarg]; 1053 1054 USED(r); 1055 na = 0; 1056 flatten(av, args); 1057 nas = na; 1058 for(i = 0; i < nas; i++) { 1059 expr(av[i], &res); 1060 switch(res.type) { 1061 default: 1062 if(comx(res)) 1063 break; 1064 patom(res.type, &res.Store); 1065 break; 1066 case TCODE: 1067 pcode(res.cc, 0); 1068 break; 1069 case TLIST: 1070 blprint(res.l); 1071 break; 1072 } 1073 } 1074 if(ret == 0) 1075 Bputc(bout, '\n'); 1076 } 1077 1078 void 1079 printto(Node *r, Node *args) 1080 { 1081 int fd; 1082 Biobuf *b; 1083 int i, nas; 1084 Node res, *av[Maxarg]; 1085 1086 USED(r); 1087 na = 0; 1088 flatten(av, args); 1089 nas = na; 1090 1091 expr(av[0], &res); 1092 if(res.type != TSTRING) 1093 error("printto(string, ...): need string"); 1094 1095 fd = create(res.string->string, OWRITE, 0666); 1096 if(fd < 0) 1097 fd = open(res.string->string, OWRITE); 1098 if(fd < 0) 1099 error("printto: open %s: %r", res.string->string); 1100 1101 b = gmalloc(sizeof(Biobuf)); 1102 Binit(b, fd, OWRITE); 1103 1104 Bflush(bout); 1105 io[iop++] = bout; 1106 bout = b; 1107 1108 for(i = 1; i < nas; i++) { 1109 expr(av[i], &res); 1110 switch(res.type) { 1111 default: 1112 if(comx(res)) 1113 break; 1114 patom(res.type, &res.Store); 1115 break; 1116 case TLIST: 1117 blprint(res.l); 1118 break; 1119 } 1120 } 1121 if(ret == 0) 1122 Bputc(bout, '\n'); 1123 1124 Bterm(b); 1125 close(fd); 1126 free(b); 1127 bout = io[--iop]; 1128 } 1129 1130 void 1131 pcfile(Node *r, Node *args) 1132 { 1133 Node res; 1134 char *p, buf[128]; 1135 1136 if(args == 0) 1137 error("pcfile(addr): arg count"); 1138 expr(args, &res); 1139 if(res.type != TINT) 1140 error("pcfile(addr): arg type"); 1141 1142 r->type = TSTRING; 1143 r->fmt = 's'; 1144 if(fileline(buf, sizeof(buf), res.ival) == 0) { 1145 r->string = strnode("?file?"); 1146 return; 1147 } 1148 p = strrchr(buf, ':'); 1149 if(p == 0) 1150 error("pcfile(addr): funny file %s", buf); 1151 *p = '\0'; 1152 r->string = strnode(buf); 1153 } 1154 1155 void 1156 pcline(Node *r, Node *args) 1157 { 1158 Node res; 1159 char *p, buf[128]; 1160 1161 if(args == 0) 1162 error("pcline(addr): arg count"); 1163 expr(args, &res); 1164 if(res.type != TINT) 1165 error("pcline(addr): arg type"); 1166 1167 r->type = TINT; 1168 r->fmt = 'D'; 1169 if(fileline(buf, sizeof(buf), res.ival) == 0) { 1170 r->ival = 0; 1171 return; 1172 } 1173 1174 p = strrchr(buf, ':'); 1175 if(p == 0) 1176 error("pcline(addr): funny file %s", buf); 1177 r->ival = atoi(p+1); 1178 } 1179