blob: 99e0d56e9d806cc79794bfee92724380b94c0b3a [file] [log] [blame]
/*
* 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;
}
}