ref: 369cba5f938d3f804210b6e09d36c6f7ecb017fa
parent: 70edb7fbae4f0a38593c0dc1f936838adc6861ac
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Jan 7 15:50:00 EST 2022
rc: read heredoc when receiving '\n' (thanks Eckard Brauer) Eckard's test case: cat <<! | cat asdf ! The issue is that we have to continue parsing until we see the '\n' before consuming the here document. So we revert to the old approach of having two functions: heredoc() which remembers if we'v seen a heredoc redirection and a second readhere() function that reads the doc from the lexers input and sets Tree.str on thee REDIR node.
--- a/sys/src/cmd/rc/fns.h
+++ b/sys/src/cmd/rc/fns.h
@@ -58,7 +58,8 @@
void pushlist(void);
void pushredir(int, int, int);
word* pushword(char*);
-char* readhere(tree*, io*);
+void readhere(io*);
+void heredoc(tree*);
void setstatus(char*);
void skipnl(void);
void start(code*, int, var*, redir*);
--- a/sys/src/cmd/rc/here.c
+++ b/sys/src/cmd/rc/here.c
@@ -6,16 +6,12 @@
void psubst(io*, unsigned char*);
void pstrs(io*, word*);
-char*
-readhere(tree *tag, io *in)
+static char*
+readhere1(tree *tag, io *in)
{
io *out;
char c, *m;
- if(tag->type!=WORD){
- yyerror("Bad here tag");
- return 0;
- }
pprompt();
out = openiostr();
m = tag->str;
@@ -45,6 +41,34 @@
}
doprompt = 1;
return closeiostr(out);
+}
+
+static tree *head, *tail;
+
+void
+heredoc(tree *redir)
+{
+ if(redir->child[0]->type!=WORD){
+ yyerror("Bad here tag");
+ return;
+ }
+ redir->child[2]=0;
+ if(head)
+ tail->child[2]=redir;
+ else
+ head=redir;
+ tail=redir;
+}
+
+void
+readhere(io *in)
+{
+ while(head){
+ tail=head->child[2];
+ head->child[2]=0;
+ head->str=readhere1(head->child[0], in);
+ head=tail;
+ }
}
void
--- a/sys/src/cmd/rc/syn.y
+++ b/sys/src/cmd/rc/syn.y
@@ -22,7 +22,7 @@
%type<tree> WORD REDIR DUP PIPE
%%
rc: { return 1;}
-| line '\n' {return !compile($1);}
+| line '\n' {readhere(lex->input); return !compile($1);}
line: cmd
| cmdsa line {$$=tree2(';', $1, $2);}
body: cmd
@@ -30,13 +30,13 @@
cmdsa: cmd ';'
| cmd '&' {$$=tree1('&', $1);}
cmdsan: cmdsa
-| cmd '\n'
+| cmd '\n' {readhere(lex->input);}
brace: '{' body '}' {$$=tree1(BRACE, $2);}
paren: '(' body ')' {$$=tree1(PCMD, $2);}
assign: first '=' word {$$=tree2('=', $1, $3);}
epilog: {$$=0;}
| redir epilog {$$=mung2($1, $1->child[0], $2);}
-redir: REDIR word {($$=mung1($1, $2))->str=$1->rtype==HERE?readhere($2,lex->input):0;}
+redir: REDIR word {$$=mung1($1, $2); if($$->rtype==HERE) heredoc($$);}
| DUP
cmd: {$$=0;}
| brace epilog {$$=epimung($1, $2);}