| #include "mk.h" |
| |
| /* |
| * This file contains functions that depend on rc's syntax. Most |
| * of the routines extract strings observing rc's escape conventions |
| */ |
| |
| |
| /* |
| * skip a token in single quotes. |
| */ |
| static char * |
| squote(char *cp) |
| { |
| Rune r; |
| int n; |
| |
| while(*cp){ |
| n = chartorune(&r, cp); |
| if(r == '\'') { |
| n += chartorune(&r, cp+n); |
| if(r != '\'') |
| return(cp); |
| } |
| cp += n; |
| } |
| SYNERR(-1); /* should never occur */ |
| fprint(2, "missing closing '\n"); |
| return 0; |
| } |
| |
| /* |
| * search a string for characters in a pattern set |
| * characters in quotes and variable generators are escaped |
| */ |
| char * |
| rccharin(char *cp, char *pat) |
| { |
| Rune r; |
| int n, vargen; |
| |
| vargen = 0; |
| while(*cp){ |
| n = chartorune(&r, cp); |
| switch(r){ |
| case '\'': /* skip quoted string */ |
| cp = squote(cp+1); /* n must = 1 */ |
| if(!cp) |
| return 0; |
| break; |
| case '$': |
| if(*(cp+1) == '{') |
| vargen = 1; |
| break; |
| case '}': |
| if(vargen) |
| vargen = 0; |
| else if(utfrune(pat, r)) |
| return cp; |
| break; |
| default: |
| if(vargen == 0 && utfrune(pat, r)) |
| return cp; |
| break; |
| } |
| cp += n; |
| } |
| if(vargen){ |
| SYNERR(-1); |
| fprint(2, "missing closing } in pattern generator\n"); |
| } |
| return 0; |
| } |
| |
| /* |
| * extract an escaped token. Possible escape chars are single-quote, |
| * double-quote,and backslash. Only the first is valid for rc. the |
| * others are just inserted into the receiving buffer. |
| */ |
| char* |
| rcexpandquote(char *s, Rune r, Bufblock *b) |
| { |
| if (r != '\'') { |
| rinsert(b, r); |
| return s; |
| } |
| |
| while(*s){ |
| s += chartorune(&r, s); |
| if(r == '\'') { |
| if(*s == '\'') |
| s++; |
| else |
| return s; |
| } |
| rinsert(b, r); |
| } |
| return 0; |
| } |
| |
| /* |
| * Input an escaped token. Possible escape chars are single-quote, |
| * double-quote and backslash. Only the first is a valid escape for |
| * rc; the others are just inserted into the receiving buffer. |
| */ |
| int |
| rcescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc) |
| { |
| int c, line; |
| |
| if(esc != '\'') |
| return 1; |
| |
| line = mkinline; |
| while((c = nextrune(bp, 0)) > 0){ |
| if(c == '\''){ |
| if(preserve) |
| rinsert(buf, c); |
| c = Bgetrune(bp); |
| if (c < 0) |
| break; |
| if(c != '\''){ |
| Bungetrune(bp); |
| return 1; |
| } |
| } |
| rinsert(buf, c); |
| } |
| SYNERR(line); fprint(2, "missing closing %c\n", esc); |
| return 0; |
| } |
| |
| /* |
| * copy a single-quoted string; s points to char after opening quote |
| */ |
| static char * |
| copysingle(char *s, Bufblock *buf) |
| { |
| Rune r; |
| |
| while(*s){ |
| s += chartorune(&r, s); |
| rinsert(buf, r); |
| if(r == '\'') |
| break; |
| } |
| return s; |
| } |
| /* |
| * check for quoted strings. backquotes are handled here; single quotes above. |
| * s points to char after opening quote, q. |
| */ |
| char * |
| rccopyq(char *s, Rune q, Bufblock *buf) |
| { |
| if(q == '\'') /* copy quoted string */ |
| return copysingle(s, buf); |
| |
| if(q != '`') /* not quoted */ |
| return s; |
| |
| while(*s){ /* copy backquoted string */ |
| s += chartorune(&q, s); |
| rinsert(buf, q); |
| if(q == '}') |
| break; |
| if(q == '\'') |
| s = copysingle(s, buf); /* copy quoted string */ |
| } |
| return s; |
| } |
| |
| static int |
| rcmatchname(char *name) |
| { |
| char *p; |
| |
| if((p = strrchr(name, '/')) != nil) |
| name = p+1; |
| if(name[0] == 'r' && name[1] == 'c') |
| return 1; |
| return 0; |
| } |
| |
| Shell rcshell = { |
| "rc", |
| "'= \t", |
| '\1', |
| rccharin, |
| rcexpandquote, |
| rcescapetoken, |
| rccopyq, |
| rcmatchname |
| }; |