242 lines
3.1 KiB
C
242 lines
3.1 KiB
C
/*
|
|
* 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;
|
|
}
|
|
}
|