From 29138fff8643194ec49cb79304d2a878d46c378b Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Tue, 16 Nov 2021 12:08:59 -0800 Subject: Feat: added heredocs Heredocs are simply strings written to tmp files. There was minimal bug testing here. Also, various bug fixes are included --- src/cmd/rc/lex.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 190 insertions(+), 17 deletions(-) (limited to 'src/cmd/rc/lex.c') diff --git a/src/cmd/rc/lex.c b/src/cmd/rc/lex.c index 3722606..0eb023c 100644 --- a/src/cmd/rc/lex.c +++ b/src/cmd/rc/lex.c @@ -16,12 +16,29 @@ struct Lexer char buf[BUFSIZ]; }; -static struct Lexer lexer = { .c={0, EOF}, .doprompt=1 }; +struct Here +{ + Tree *tag; + char *name; + struct Here *link; +}; +// ----------------------------------------------------------------------- +// globals + +static struct Lexer lexer = { .c={0, EOF}, .doprompt=1 }; #define put1(b) lexer.buf[0] = (b), lexer.buf[1] = 0; #define put2(b0,b1) lexer.buf[0] = (b0), lexer.buf[1] = (b1), lexer.buf[2] = 0; #define put3(b0,b1,b2) lexer.buf[0] = (b0), lexer.buf[1] = (b1), lexer.buf[2] = b2, lexer.buf[3] = 0; +static struct Here *heres, **endhere; +static char hex[]="0123456789abcdef"; +static char tmp[]="/tmp/here0000.0000"; +static int numhere; + +// ----------------------------------------------------------------------- +// internal functions + void yyerror(const char *msg) { @@ -41,6 +58,80 @@ yyerror(const char *msg) advance(); } +static void +hexnum(char *p, int n) +{ + *p++=hex[(n>>12)&0xF]; + *p++=hex[(n>>8)&0xF]; + *p++=hex[(n>>4)&0xF]; + *p = hex[n&0xF]; +} + +static void +pword(Io *io, Word *arg) +{ + if(arg){ + while(arg->link && arg->link->str){ + printstr(io, arg->str); + printchar(io, ' '); + arg = arg->link; + } + printstr(io, arg->str); + } +} + +static void +psubst(Io *io, char *s) +{ + char *t, *u; + int savec, n; + Word *star; + + while(*s){ + if(*s!='$'){ + if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){ + printchar(io, *s++); + if(*s=='\0') + break; + }else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){ + printchar(io, *s++); + if(*s=='\0') + break; + printchar(io, *s++); + if(*s=='\0') + break; + } + printchar(io, *s++); + }else{ + t=++s; + if(*t=='$') + printchar(io, *t++); + else{ + while(*t && isidentchar(*t)) + t++; + savec=*t; + *t='\0'; + n = 0; + for(u = s;*u && '0'<=*u && *u<='9';u++) n = n*10+*u-'0'; + if(n && *u=='\0'){ + star = var("*")->val; + if(star && 1<=n && n<=count(star)){ + while(--n) + star = star->link; + printstr(io, star->str); + } + } + else + pword(io, var(s)->val); + *t = savec; + if(savec=='^') + t++; + } + s = t; + } + } +} + int readc(void) { @@ -68,8 +159,7 @@ readc(void) return c; } -static -int +static int peekc(void) { if(lexer.c[1] == EOF) @@ -78,8 +168,7 @@ peekc(void) return lexer.c[1]; } -static -int +static int advance(void) { int c = peekc(); @@ -88,8 +177,7 @@ advance(void) return c; } -static -void +static void skipws(void) { int c; @@ -102,8 +190,7 @@ skipws(void) } } -static -void +static void skipnl(void) { int c; @@ -116,8 +203,7 @@ skipnl(void) } } -static -int +static int nextis(int c) { if(peekc()==c){ @@ -127,8 +213,7 @@ nextis(int c) return 0; } -static -char * +static char * putbyte(char *buf, int c) { if(!buf) @@ -165,7 +250,93 @@ putrune(char *buf, int c) } // ----------------------------------------------------------------------- -// exported functions +// here doc exports + +Tree * +heredoc(Tree *tag) +{ + struct Here *h; + if(tag->type != Tword) + yyerror("bad here tag"); + + h = emalloc(sizeof(*h)); + h->link = nil; + if(heres) + *endhere = h; + else + heres = h; + + h->tag = tag; + hexnum(&tmp[9], getpid()); + hexnum(&tmp[14], numhere++); + h->name = strdup(tmp); + return token(Tword, tmp); +} + +void +readhere(void) +{ + Io *io; + int c, sub; + long len; + struct Here *h, *nh; + char *s, *beg, *end, *tag, line[PAGESIZE+1]; + + for(h=heres; h; h = nh){ + sub = !h->tag->quoted; + tag = h->tag->str; + + if((c=open(h->name,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))<0) + yyerror("failed to make heredoc"); + io = openfd(c); + + prompt(&lexer.doprompt); + + beg=line, s=line, end=arrend(line)-1, len=PAGESIZE; + while((c=get(runner->cmd.io))!=EOF){ + /* out of space: get bigger buffer */ + if(s == end){ + s = beg; + beg = (beg == line) ? emalloc(2*len+1) : erealloc(beg, 2*len+1); + memcpy(beg, s, len); + s = beg + len; + len *= 2; + end = beg + len; + } + + if(c!='\n'){ + *s++ = c; + continue; + } + /* c == '\n' */ + *s = 0; + if(tag && strcmp(beg, tag) == 0) + break; + if(sub) + psubst(io, beg); + else + printstr(io, beg); + /* reset */ + s = beg; + prompt(&lexer.doprompt); + printchar(io, c); + } + + flush(io); + terminate(io); + emitdelhere(h->name); + nh = h->link; + if(beg != line) + efree(beg); + efree(h); + } + heres = nil; + lexer.doprompt = 1; +} + + +// ----------------------------------------------------------------------- +// lexer exported functions // TODO: turn into static tables int @@ -183,8 +354,8 @@ isidentchar(int c) int yylex(void) { - int c, d = peekc(); Tree *node; + int c, d = peekc(); char *w = lexer.buf; yylval.tree = nil; @@ -194,7 +365,7 @@ yylex(void) lexer.hadword = 0; if(d=='('){ advance(); - strcpy(lexer.buf, "( [Tindex]"); + strcpy(lexer.buf, "(Tindex)"); return Tindex; } if(iswordchar(d) || d=='\'' || d=='`' || d=='$' || d=='"'){ @@ -225,6 +396,7 @@ yylex(void) put1('$'); return '$'; +#if 0 case '@': lexer.haddollar = 0; put1('@'); @@ -234,6 +406,7 @@ yylex(void) lexer.haddollar = 0; put1('!'); return Tbang; +#endif case '&': lexer.haddollar = 0; @@ -294,7 +467,7 @@ yylex(void) *w++='['; c = advance(); *w++ = c; - if(c < '0' || '9' < c){ + if(c<'0' || '9'type == Tpipe ? "pipe syntax" : "redirection syntax"); -- cgit v1.2.1