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