aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/rc/lex.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/rc/lex.c')
-rw-r--r--src/cmd/rc/lex.c207
1 files changed, 190 insertions, 17 deletions
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'<c){
badredir:
*w = 0;
yyerror(node->type == Tpipe ? "pipe syntax" : "redirection syntax");