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