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