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