Blob
1 /*2 * Read input files.3 */4 #include "a.h"6 typedef struct Istack Istack;7 struct Istack8 {9 Rune unget[3];10 int nunget;11 Biobuf *b;12 Rune *p;13 Rune *ep;14 Rune *s;15 int lineno;16 Rune *name;17 Istack *next;18 void (*fn)(void);19 };21 Istack *istack;22 Istack *ibottom;24 static void25 setname(void)26 {27 Rune *r, *p;29 if(istack == nil || istack->name == nil)30 return;31 _nr(L(".F"), istack->name);32 r = erunestrdup(istack->name);33 p = runestrchr(r, '.');34 if(p)35 *p = 0;36 _nr(L(".B"), r);37 free(r);38 }40 static void41 ipush(Istack *is)42 {43 if(istack == nil)44 ibottom = is;45 else46 is->next = istack;47 istack = is;48 setname();49 }51 static void52 iqueue(Istack *is)53 {54 if(ibottom == nil){55 istack = is;56 setname();57 }else58 ibottom->next = is;59 ibottom = is;60 }62 int63 _inputfile(Rune *s, void (*push)(Istack*))64 {65 Istack *is;66 Biobuf *b;67 char *t;69 t = esmprint("%S", s);70 if((b = Bopen(t, OREAD)) == nil){71 free(t);72 fprint(2, "%s: open %S: %r\n", argv0, s);73 return -1;74 }75 free(t);76 is = emalloc(sizeof *is);77 is->b = b;78 is->name = erunestrdup(s);79 is->lineno = 1;80 push(is);81 return 0;82 }84 int85 pushinputfile(Rune *s)86 {87 return _inputfile(s, ipush);88 }90 int91 queueinputfile(Rune *s)92 {93 return _inputfile(s, iqueue);94 }96 int97 _inputstdin(void (*push)(Istack*))98 {99 Biobuf *b;100 Istack *is;102 if((b = Bopen("/dev/null", OREAD)) == nil){103 fprint(2, "%s: open /dev/null: %r\n", argv0);104 return -1;105 }106 dup(0, b->fid);107 is = emalloc(sizeof *is);108 is->b = b;109 is->name = erunestrdup(L("stdin"));110 is->lineno = 1;111 push(is);112 return 0;113 }115 int116 pushstdin(void)117 {118 return _inputstdin(ipush);119 }121 int122 queuestdin(void)123 {124 return _inputstdin(iqueue);125 }127 void128 _inputstring(Rune *s, void (*push)(Istack*))129 {130 Istack *is;132 is = emalloc(sizeof *is);133 is->s = erunestrdup(s);134 is->p = is->s;135 is->ep = is->p+runestrlen(is->p);136 push(is);137 }139 void140 pushinputstring(Rune *s)141 {142 _inputstring(s, ipush);143 }146 void147 inputnotify(void (*fn)(void))148 {149 if(istack)150 istack->fn = fn;151 }153 int154 popinput(void)155 {156 Istack *is;158 is = istack;159 if(is == nil)160 return 0;162 istack = istack->next;163 if(is->b)164 Bterm(is->b);165 free(is->s);166 free(is->name);167 if(is->fn)168 is->fn();169 free(is);170 setname();171 return 1;172 }174 int175 getrune(void)176 {177 Rune r;178 int c;180 top:181 if(istack == nil)182 return -1;183 if(istack->nunget)184 return istack->unget[--istack->nunget];185 else if(istack->p){186 if(istack->p >= istack->ep){187 popinput();188 goto top;189 }190 r = *istack->p++;191 }else if(istack->b){192 if((c = Bgetrune(istack->b)) < 0){193 popinput();194 goto top;195 }196 r = c;197 }else{198 r = 0;199 sysfatal("getrune - can't happen");200 }201 if(r == '\n')202 istack->lineno++;203 return r;204 }206 void207 ungetrune(Rune r)208 {209 if(istack == nil || istack->nunget >= nelem(istack->unget))210 pushinputstring(L(""));211 istack->unget[istack->nunget++] = r;212 }214 int215 linefmt(Fmt *f)216 {217 Istack *is;219 for(is=istack; is && !is->b; is=is->next)220 ;221 if(is)222 return fmtprint(f, "%S:%d", is->name, is->lineno);223 else224 return fmtprint(f, "<no input>");225 }227 void228 setlinenumber(Rune *s, int n)229 {230 Istack *is;232 for(is=istack; is && !is->name; is=is->next)233 ;234 if(is){235 if(s){236 free(is->name);237 is->name = erunestrdup(s);238 }239 is->lineno = n;240 }241 }