#include "rc.h" #define c0 t->child[0] #define c1 t->child[1] #define c2 t->child[2] #undef bufsize #define bufsize 512 #define strsize 100 //------------------------------------------------------------------------ // buffer operations /* open file */ Io* openfd(int fd) { Io *f; f = emalloc(sizeof *f + bufsize); f->fd = fd; f->b = f->e = f->buf; return f; } /* open string */ Io* openstr(void) { Io *f; f = emalloc(sizeof *f + strsize + 1); f->fd = -1; f->b = f->buf; f->e = f->buf+strsize; memset(f->b, 0, strsize+1); return f; } /* open core (not nil terminated) */ Io* opencore(int len, char *s) { Io *f; f = emalloc(sizeof *f + len); f->fd = -1; f->b = f->buf; f->e = f->buf+len; memcpy(f->b, s, len); return f; } void rewindio(Io *f) { if (f->fd < 0) f->b = f->buf; else { f->b = f->e = f->buf; lseek(f->fd, 0, 0); } } void closeio(Io *f) { if (f->fd >= 0) close(f->fd); efree(f); } /* has the chance to realloc */ void flush(Io **fp) { int n; char *s; Io *f; f = *fp; if (f->fd < 0) { n = f->e - f->b; f = erealloc(f, sizeof *f + n + strsize + 1); if (!f) panic("can't realloc %d bytes in flush", n+strsize+1); f->b = f->buf+n; f->e = f->buf+n+strsize; memset(f->b, 0, strsize+1); } else { n = f->b - f->buf; if (n && write(f->fd, f->buf, n) < 0) { write(3, "write error\n", 12); // if (ntrap) // dotrap(); } f->b = f->buf; f->e = f->buf + bufsize; } *fp = f; } //------------------------------------------------------------------------ // read from io int rchr(Io *f) { int n; if (f->b == f->e) { if (f->fd < 0 || (n = read(f->fd, f->buf, bufsize)) <= 0) return EOF; f->b = f->buf; f->e = f->b + n; } return *f->b++&0xFF; } //------------------------------------------------------------------------ // printf functionality /* character literal */ int pchr(Io *f, int c) { if (f->b == f->e) flush(&f); return *f->b++=c; } /* quote */ void pquo(Io *f, char *s) { pchr(f, '\''); for (; *s; s++) if (*s == '\'') pfmt(f, "''"); else pchr(f, *s); pchr(f, '\''); } /* word */ void pwrd(Io *f, char *s) { char *t; for(t = s; *t; t++) if(!wordchr(*t)) break; if(t == s || *t) pquo(f, s); else pstr(f, s); } /* pointer */ void pptr(Io *f, void *v) { int n; uintptr p; if (!v) { pstr(f, ""); return; } p = (uintptr)v; if ((sizeof(uintptr) == sizeof(uvlong)) && p >>32) for (n = 60; n >= 32; n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]); for (n = 28; n >= 0; n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]); } /* string */ void pstr(Io *f, char *s) { if(!s || !s[0]) s = ""; while(*s) pchr(f, *s++); } /* decimal */ void pdec(Io *f, int n) { if (n < 0) { n = -n; pchr(f, '-'); if (n >= 0) { pdec(f, n); return; } n = 1 - n; pdec(f, n/10); pchr(f, n%10+'1'); return; } if (n > 9) pdec(f, n/10); pchr(f, n%10+'0'); } /* octal */ void poct(Io *f, uint n) { if (n > 7) poct(f, n>>3); pchr(f, (n&7)+'0'); } /* value */ void pval(Io *f, Word *a) { if(a) { while(a->link && a->link->word) { pwrd(f, a->word); pchr(f, ' '); a = a->link; } pwrd(f, a->word); } } /* tree */ static void pdeglob(Io *f, char *s) { while(*s){ if(*s==GLOB) s++; pchr(f, *s++); } } void pcmd(Io *f, Tree *t) { if(!t) return; switch(t->type){ default: pfmt(f, "bad<%d> %p %p %p", t->type, c0, c1, c2); break; case Tdol: pfmt(f, "$%t", c0); break; case Tquote: pfmt(f, "$\"%t", c0); break; case Tand: pfmt(f, "%t&", c0); break; case Tcarot: pfmt(f, "%t^%t", c0, c1); break; case Ttick: pfmt(f, "`%t", c0); break; case Tandand: pfmt(f, "%t && %t", c0, c1); break; case Tbang: pfmt(f, "! %t", c0); break; case Tbrace: pfmt(f, "{%t}", c0); break; case Tcount: pfmt(f, "$#%t", c0); break; case Tfunc: pfmt(f, "func %t %t", c0, c1); break; case Tif: (c2) ? pfmt(f, "if%t%t else %t", c0, c1, c2): pfmt(f, "if%t%t", c0, c1); break; case Toror: pfmt(f, "%t || %t", c0, c1); break; case Tpcmd: /* fallthrough */ case Tparen: pfmt(f, "(%t)", c0); break; case Tsub: pfmt(f, "$%t(%t)", c0, c1); break; case Tsimple: pfmt(f, "%t", c0); break; case Tsubshell: pfmt(f, "@ %t", c0); break; case Tswitch: pfmt(f, "switch %t %t", c0, c1); break; case Tcase: pfmt(f, "case %t:\n%t", c0, c1); break; case Ttwiddle: pfmt(f, "~ %t %t", c0, c1); break; case Twhile: pfmt(f, "while %t%t", c0, c1); break; case Targs: if(c0==0) pfmt(f, "%t", c1); else if(c1==0) pfmt(f, "%t", c0); else pfmt(f, "%t %t", c0, c1); break; case Tsemi: if(c0) { if(c1) pfmt(f, "%t%c%t", c0, '\n', c1); else pfmt(f, "%t", c0); } else pfmt(f, "%t", c1); break; case Twords: if(c0) pfmt(f, "%t ", c0); pfmt(f, "%t", c1); break; case Tfor: pfmt(f, "for(%t", c0); if(c1) pfmt(f, " in %t", c1); pfmt(f, ")%t", c2); break; case Tword: if(t->quoted) pfmt(f, "%Q", t->str); else pdeglob(f, t->str); break; case Tdup: if(t->redir.type==Rdupfd) pfmt(f, ">[%d=%d]", t->redir.fd[1], t->redir.fd[0]); /* yes, fd1, then fd0; read lex.c */ else pfmt(f, ">[%d=]", t->redir.fd[0]); pfmt(f, "%t", c1); break; case Tpipefd: case Tredir: switch(t->redir.type){ case Rhere: pchr(f, '<'); case Rread: case Rrdwr: pchr(f, '<'); if(t->redir.type==Rrdwr) pchr(f, '>'); if(t->redir.fd[0]!=0) pfmt(f, "[%d]", t->redir.fd[0]); break; case Rappend: pchr(f, '>'); case Rwrite: pchr(f, '>'); if(t->redir.fd[0]!=1) pfmt(f, "[%d]", t->redir.fd[0]); break; } pfmt(f, "%t", c0); if(c1) pfmt(f, " %t", c1); break; case Teq: pfmt(f, "%t=%t", c0, c1); if(c2) pfmt(f, " %t", c2); break; case Tpipe: pfmt(f, "%t|", c0); if(t->redir.fd[1]==0){ if(t->redir.fd[0]!=1) pfmt(f, "[%d]", t->redir.fd[0]); } else pfmt(f, "[%d=%d]", t->redir.fd[0], t->redir.fd[1]); pfmt(f, "%t", c1); break; } } /* rc specific printf */ static int pfmtlev; void vpfmt(Io *f, char *fmt, va_list args) { char err[124]; pfmtlev++; for (; *fmt; fmt++) if (*fmt!='%') pchr(f, *fmt); else switch(*++fmt) { case '\0': break; case 'c': pchr(f, va_arg(args, int)); break; case 'd': pdec(f, va_arg(args, int)); break; case 'o': poct(f, va_arg(args, uint)); break; case 'p': pptr(f, va_arg(args, void*)); break; case 'Q': pquo(f, va_arg(args, char*)); break; case 'q': pwrd(f, va_arg(args, char*)); break; case 'r': pstr(f, strerror(errno)); break; case 's': pstr(f, va_arg(args, char*)); break; case 't': pcmd(f, va_arg(args, Tree*)); break; case 'v': pval(f, va_arg(args, Word*)); break; } if (--pfmtlev==0) flush(&f); } void pfmt(Io *f, char *fmt, ...) { va_list args; char err[124]; va_start(args, fmt); vpfmt(f, fmt, args); va_end(args); }