9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

sh.c (3427B)


      1 #include	"mk.h"
      2 
      3 /*
      4  *	This file contains functions that depend on the shell's syntax.  Most
      5  *	of the routines extract strings observing the shell's escape conventions.
      6  */
      7 
      8 
      9 /*
     10  *	skip a token in quotes.
     11  */
     12 static char *
     13 squote(char *cp, int c)
     14 {
     15 	Rune r;
     16 	int n;
     17 
     18 	while(*cp){
     19 		n = chartorune(&r, cp);
     20 		if(r == c)
     21 			return cp;
     22 		if(r == '\\')
     23 			n += chartorune(&r, cp+n);
     24 		cp += n;
     25 	}
     26 	SYNERR(-1);		/* should never occur */
     27 	fprint(2, "missing closing '\n");
     28 	return 0;
     29 }
     30 /*
     31  *	search a string for unescaped characters in a pattern set
     32  */
     33 static char *
     34 shcharin(char *cp, char *pat)
     35 {
     36 	Rune r;
     37 	int n, vargen;
     38 
     39 	vargen = 0;
     40 	while(*cp){
     41 		n = chartorune(&r, cp);
     42 		switch(r){
     43 		case '\\':			/* skip escaped char */
     44 			cp += n;
     45 			n = chartorune(&r, cp);
     46 			break;
     47 		case '\'':			/* skip quoted string */
     48 		case '"':
     49 			cp = squote(cp+1, r);	/* n must = 1 */
     50 			if(!cp)
     51 				return 0;
     52 			break;
     53 		case '$':
     54 			if(*(cp+1) == '{')
     55 				vargen = 1;
     56 			break;
     57 		case '}':
     58 			if(vargen)
     59 				vargen = 0;
     60 			else if(utfrune(pat, r))
     61 				return cp;
     62 			break;
     63 		default:
     64 			if(vargen == 0 && utfrune(pat, r))
     65 				return cp;
     66 			break;
     67 		}
     68 		cp += n;
     69 	}
     70 	if(vargen){
     71 		SYNERR(-1);
     72 		fprint(2, "missing closing } in pattern generator\n");
     73 	}
     74 	return 0;
     75 }
     76 
     77 /*
     78  *	extract an escaped token.  Possible escape chars are single-quote,
     79  *	double-quote,and backslash.
     80  */
     81 static char*
     82 shexpandquote(char *s, Rune esc, Bufblock *b)
     83 {
     84 	Rune r;
     85 
     86 	if (esc == '\\') {
     87 		s += chartorune(&r, s);
     88 		rinsert(b, r);
     89 		return s;
     90 	}
     91 
     92 	while(*s){
     93 		s += chartorune(&r, s);
     94 		if(r == esc)
     95 			return s;
     96 		if (r == '\\') {
     97 			rinsert(b, r);
     98 			s += chartorune(&r, s);
     99 		}
    100 		rinsert(b, r);
    101 	}
    102 	return 0;
    103 }
    104 
    105 /*
    106  *	Input an escaped token.  Possible escape chars are single-quote,
    107  *	double-quote and backslash.
    108  */
    109 static int
    110 shescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
    111 {
    112 	int c, line;
    113 
    114 	if(esc == '\\') {
    115 		c = Bgetrune(bp);
    116 		if(c == '\r')
    117 			c = Bgetrune(bp);
    118 		if (c == '\n')
    119 			mkinline++;
    120 		rinsert(buf, c);
    121 		return 1;
    122 	}
    123 
    124 	line = mkinline;
    125 	while((c = nextrune(bp, 0)) >= 0){
    126 		if(c == esc){
    127 			if(preserve)
    128 				rinsert(buf, c);
    129 			return 1;
    130 		}
    131 		if(c == '\\') {
    132 			rinsert(buf, c);
    133 			c = Bgetrune(bp);
    134 			if(c == '\r')
    135 				c = Bgetrune(bp);
    136 			if (c < 0)
    137 				break;
    138 			if (c == '\n')
    139 				mkinline++;
    140 		}
    141 		rinsert(buf, c);
    142 	}
    143 	SYNERR(line); fprint(2, "missing closing %c\n", esc);
    144 	return 0;
    145 }
    146 
    147 /*
    148  *	copy a quoted string; s points to char after opening quote
    149  */
    150 static char *
    151 copysingle(char *s, Rune q, Bufblock *buf)
    152 {
    153 	Rune r;
    154 
    155 	while(*s){
    156 		s += chartorune(&r, s);
    157 		rinsert(buf, r);
    158 		if(r == q)
    159 			break;
    160 	}
    161 	return s;
    162 }
    163 /*
    164  *	check for quoted strings.  backquotes are handled here; single quotes above.
    165  *	s points to char after opening quote, q.
    166  */
    167 static char *
    168 shcopyq(char *s, Rune q, Bufblock *buf)
    169 {
    170 	if(q == '\'' || q == '"')		/* copy quoted string */
    171 		return copysingle(s, q, buf);
    172 
    173 	if(q != '`')				/* not quoted */
    174 		return s;
    175 
    176 	while(*s){				/* copy backquoted string */
    177 		s += chartorune(&q, s);
    178 		rinsert(buf, q);
    179 		if(q == '`')
    180 			break;
    181 		if(q == '\'' || q == '"')
    182 			s = copysingle(s, q, buf);	/* copy quoted string */
    183 	}
    184 	return s;
    185 }
    186 
    187 static int
    188 shmatchname(char *name)
    189 {
    190 	USED(name);
    191 
    192 	return 1;
    193 }
    194 
    195 
    196 Shell shshell = {
    197 	"sh",
    198 	"\"'= \t",	/*used in parse.c to isolate assignment attribute*/
    199 	' ',	/* inter-word separator in env */
    200 	shcharin,
    201 	shexpandquote,
    202 	shescapetoken,
    203 	shcopyq,
    204 	shmatchname
    205 };
    206