|  | #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 | 
|  | }; |