| /* |
| * Read input files. |
| */ |
| #include "a.h" |
| |
| typedef struct Istack Istack; |
| struct Istack |
| { |
| Rune unget[3]; |
| int nunget; |
| Biobuf *b; |
| Rune *p; |
| Rune *ep; |
| Rune *s; |
| int lineno; |
| Rune *name; |
| Istack *next; |
| void (*fn)(void); |
| }; |
| |
| Istack *istack; |
| Istack *ibottom; |
| |
| static void |
| setname(void) |
| { |
| Rune *r, *p; |
| |
| if(istack == nil || istack->name == nil) |
| return; |
| _nr(L(".F"), istack->name); |
| r = erunestrdup(istack->name); |
| p = runestrchr(r, '.'); |
| if(p) |
| *p = 0; |
| _nr(L(".B"), r); |
| free(r); |
| } |
| |
| static void |
| ipush(Istack *is) |
| { |
| if(istack == nil) |
| ibottom = is; |
| else |
| is->next = istack; |
| istack = is; |
| setname(); |
| } |
| |
| static void |
| iqueue(Istack *is) |
| { |
| if(ibottom == nil){ |
| istack = is; |
| setname(); |
| }else |
| ibottom->next = is; |
| ibottom = is; |
| } |
| |
| int |
| _inputfile(Rune *s, void (*push)(Istack*)) |
| { |
| Istack *is; |
| Biobuf *b; |
| char *t; |
| |
| t = esmprint("%S", s); |
| if((b = Bopen(t, OREAD)) == nil){ |
| free(t); |
| fprint(2, "%s: open %S: %r\n", argv0, s); |
| return -1; |
| } |
| free(t); |
| is = emalloc(sizeof *is); |
| is->b = b; |
| is->name = erunestrdup(s); |
| is->lineno = 1; |
| push(is); |
| return 0; |
| } |
| |
| int |
| pushinputfile(Rune *s) |
| { |
| return _inputfile(s, ipush); |
| } |
| |
| int |
| queueinputfile(Rune *s) |
| { |
| return _inputfile(s, iqueue); |
| } |
| |
| int |
| _inputstdin(void (*push)(Istack*)) |
| { |
| Biobuf *b; |
| Istack *is; |
| |
| if((b = Bopen("/dev/null", OREAD)) == nil){ |
| fprint(2, "%s: open /dev/null: %r\n", argv0); |
| return -1; |
| } |
| dup(0, b->fid); |
| is = emalloc(sizeof *is); |
| is->b = b; |
| is->name = erunestrdup(L("stdin")); |
| is->lineno = 1; |
| push(is); |
| return 0; |
| } |
| |
| int |
| pushstdin(void) |
| { |
| return _inputstdin(ipush); |
| } |
| |
| int |
| queuestdin(void) |
| { |
| return _inputstdin(iqueue); |
| } |
| |
| void |
| _inputstring(Rune *s, void (*push)(Istack*)) |
| { |
| Istack *is; |
| |
| is = emalloc(sizeof *is); |
| is->s = erunestrdup(s); |
| is->p = is->s; |
| is->ep = is->p+runestrlen(is->p); |
| push(is); |
| } |
| |
| void |
| pushinputstring(Rune *s) |
| { |
| _inputstring(s, ipush); |
| } |
| |
| |
| void |
| inputnotify(void (*fn)(void)) |
| { |
| if(istack) |
| istack->fn = fn; |
| } |
| |
| int |
| popinput(void) |
| { |
| Istack *is; |
| |
| is = istack; |
| if(is == nil) |
| return 0; |
| |
| istack = istack->next; |
| if(is->b) |
| Bterm(is->b); |
| free(is->s); |
| free(is->name); |
| if(is->fn) |
| is->fn(); |
| free(is); |
| setname(); |
| return 1; |
| } |
| |
| int |
| getrune(void) |
| { |
| Rune r; |
| int c; |
| |
| top: |
| if(istack == nil) |
| return -1; |
| if(istack->nunget) |
| return istack->unget[--istack->nunget]; |
| else if(istack->p){ |
| if(istack->p >= istack->ep){ |
| popinput(); |
| goto top; |
| } |
| r = *istack->p++; |
| }else if(istack->b){ |
| if((c = Bgetrune(istack->b)) < 0){ |
| popinput(); |
| goto top; |
| } |
| r = c; |
| }else{ |
| r = 0; |
| sysfatal("getrune - can't happen"); |
| } |
| if(r == '\n') |
| istack->lineno++; |
| return r; |
| } |
| |
| void |
| ungetrune(Rune r) |
| { |
| if(istack == nil || istack->nunget >= nelem(istack->unget)) |
| pushinputstring(L("")); |
| istack->unget[istack->nunget++] = r; |
| } |
| |
| int |
| linefmt(Fmt *f) |
| { |
| Istack *is; |
| |
| for(is=istack; is && !is->b; is=is->next) |
| ; |
| if(is) |
| return fmtprint(f, "%S:%d", is->name, is->lineno); |
| else |
| return fmtprint(f, "<no input>"); |
| } |
| |
| void |
| setlinenumber(Rune *s, int n) |
| { |
| Istack *is; |
| |
| for(is=istack; is && !is->name; is=is->next) |
| ; |
| if(is){ |
| if(s){ |
| free(is->name); |
| is->name = erunestrdup(s); |
| } |
| is->lineno = n; |
| } |
| } |