/* input.c: i/o routines for files and pseudo-files (strings) */
NB: character unget is supported for up to two characters, but NOT
in the case of EOF. Since EOF does not fit in a char, it is easiest
to support only one unget of EOF.
int fd
, index
, read
, lineno
, last
;
#define BUFSIZE ((size_t) 256)
static int fdgchar(void);
static int stringgchar(void);
static void history(void);
static void pushcommon(void);
static size_t istacksize
, chars_out
, chars_in
;
static bool eofread
= FALSE
, save_lineno
= TRUE
;
static Input
*istack
, *itop
;
static int (*realgchar
)(void);
static void (*realugchar
)(int);
extern void ugchar(int c
) {
static void ugdead(int c
) {
static void ugalive(int c
) {
/* get the next character from a string. */
static int stringgchar() {
return last
= (inbuf
[chars_out
] == '\0' ? EOF
: inbuf
[chars_out
++]);
/* signal-safe readline wrapper */
read a character from a file-descriptor. If GNU readline is defined, add a newline and doctor
the buffer to look like a regular fdgchar buffer.
if (chars_out
>= chars_in
+ 2) { /* has the buffer been exhausted? if so, replenish it */
long /*ssize_t*/ r
= rc_read(istack
->fd
, inbuf
+ 2, BUFSIZE
);
continue; /* Suppose it was interrupted by a signal */
writeall(2, inbuf
+ 2, chars_in
);
return last
= inbuf
[chars_out
++];
/* set up the input stack, and put a "dead" input at the bottom, so that yyparse will always read eof */
extern void initinput() {
istack
= itop
= ealloc(istacksize
= 256 * sizeof (Input
));
/* push an input source onto the stack. set up a new input buffer, and set gchar() */
static void pushcommon() {
istack
->index
= chars_out
;
istack
->saved
= save_lineno
;
istack
->eofread
= eofread
;
if (idiff
>= istacksize
/ sizeof (Input
)) {
itop
= erealloc(itop
, istacksize
*= 2);
extern void pushfd(int fd
) {
inbuf
= ealloc(BUFSIZE
+ 2);
extern void pushstring(char **a
, bool save
) {
inbuf
= mprint("..%A", a
);
/* remove an input source from the stack. restore the right kind of getchar (string,fd) etc. */
realgchar
= (istack
->t
== iString
? stringgchar
: fdgchar
);
if (istack
->fd
== -1) { /* top of input stack */
eofread
= istack
->eofread
;
chars_out
= istack
->index
;
save_lineno
= istack
->saved
;
/* flush input characters upto newline. Used by scanerror() */
if (last
== '\n' || last
== EOF
)
while ((c
= gchar()) != '\n' && c
!= EOF
)
/* the wrapper loop in rc: prompt for commands until EOF, calling yyparse and walk() */
extern Node
*doit(bool execit
) {
except(eError
, jerror
, &e1
);
for (eof
= FALSE
; !eof
;) {
except(eArena
, block
, &e2
);
fname
[1] = concat(varlookup("home"), word("/.rcrc", NULL
))->w
;
if (!dashen
&& fnlookup("prompt") != NULL
) {
static char *arglist
[] = { "prompt", NULL
};
if ((s
= varlookup("prompt")) != NULL
) {
prompt2
= (s
->n
== NULL
? "" : s
->n
->w
);
if (yyparse() == 1 && execit
)
eof
= (last
== EOF
); /* "last" can be clobbered during a walk() */
else if (dashex
&& dashen
)
fprint(2, "%T\n", parsetree
);
/* parse a function imported from the environment */
extern Node
*parseline(char *extdef
) {
/* write last command out to a file. Check to see if $history has changed, also */
if ((histlist
= varlookup("history")) == NULL
) {
if (histstr
== NULL
|| !streq(histstr
, histlist
->w
)) { /* open new file */
histstr
= ecpy(histlist
->w
);
histfd
= rc_open(histstr
, rAppend
);
Small unix hack: since read() reads only up to a newline
from a terminal, then presumably this write() will write at
most only one input line at a time.
for (a
= 2; a
< chars_in
+ 2; a
++) { /* skip empty lines and comments in history. */
if (inbuf
[a
] == '#' || inbuf
[a
] == '\n')
if (inbuf
[a
] != ' ' && inbuf
[a
] != '\t')
writeall(histfd
, inbuf
+ 2, chars_in
);
/* close file descriptors after a fork() */
if (histstr
!= NULL
) { /* Close an open history file */
histstr
= NULL
; /* But prevent re-closing of the same file-descriptor */
for (i
= istack
; i
!= itop
; --i
) /* close open scripts */
if (i
->t
== iFd
&& i
->fd
> 2) {