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