9base

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

lex.c (2505B)


      1 #include	"mk.h"
      2 
      3 static	int	bquote(Biobuf*, Bufblock*);
      4 
      5 /*
      6  *	Assemble a line skipping blank lines, comments, and eliding
      7  *	escaped newlines
      8  */
      9 int
     10 assline(Biobuf *bp, Bufblock *buf)
     11 {
     12 	int c;
     13 	int lastc;
     14 
     15 	buf->current=buf->start;
     16 	while ((c = nextrune(bp, 1)) >= 0){
     17 		switch(c)
     18 		{
     19 		case '\r':		/* consumes CRs for Win95 */
     20 			continue;
     21 		case '\n':
     22 			if (buf->current != buf->start) {
     23 				insert(buf, 0);
     24 				return 1;
     25 			}
     26 			break;		/* skip empty lines */
     27 		case '\\':
     28 		case '\'':
     29 		case '"':
     30 			rinsert(buf, c);
     31 			if (shellt->escapetoken(bp, buf, 1, c) == 0)
     32 				Exit();
     33 			break;
     34 		case '`':
     35 			if (bquote(bp, buf) == 0)
     36 				Exit();
     37 			break;
     38 		case '#':
     39 			lastc = '#';
     40 			while ((c = Bgetc(bp)) != '\n') {
     41 				if (c < 0)
     42 					goto eof;
     43 				if(c != '\r')
     44 					lastc = c;
     45 			}
     46 			mkinline++;
     47 			if (lastc == '\\')
     48 				break;		/* propagate escaped newlines??*/
     49 			if (buf->current != buf->start) {
     50 				insert(buf, 0);
     51 				return 1;
     52 			}
     53 			break;
     54 		default:
     55 			rinsert(buf, c);
     56 			break;
     57 		}
     58 	}
     59 eof:
     60 	insert(buf, 0);
     61 	return *buf->start != 0;
     62 }
     63 
     64 /*
     65  *	assemble a back-quoted shell command into a buffer
     66  */
     67 static int
     68 bquote(Biobuf *bp, Bufblock *buf)
     69 {
     70 	int c, line, term;
     71 	int start;
     72 
     73 	line = mkinline;
     74 	while((c = Bgetrune(bp)) == ' ' || c == '\t')
     75 			;
     76 	if(c == '{'){
     77 		term = '}';		/* rc style */
     78 		while((c = Bgetrune(bp)) == ' ' || c == '\t')
     79 			;
     80 	} else
     81 		term = '`';		/* sh style */
     82 
     83 	start = buf->current-buf->start;
     84 	for(;c > 0; c = nextrune(bp, 0)){
     85 		if(c == term){
     86 			insert(buf, '\n');
     87 			insert(buf,0);
     88 			buf->current = buf->start+start;
     89 			execinit();
     90 			execsh(0, buf->current, buf, envy, shellt, shellcmd);
     91 			return 1;
     92 		}
     93 		if(c == '\n')
     94 			break;
     95 		if(c == '\'' || c == '"' || c == '\\'){
     96 			insert(buf, c);
     97 			if(!shellt->escapetoken(bp, buf, 1, c))
     98 				return 0;
     99 			continue;
    100 		}
    101 		rinsert(buf, c);
    102 	}
    103 	SYNERR(line);
    104 	fprint(2, "missing closing %c after `\n", term);
    105 	return 0;
    106 }
    107 
    108 /*
    109  *	get next character stripping escaped newlines
    110  *	the flag specifies whether escaped newlines are to be elided or
    111  *	replaced with a blank.
    112  */
    113 int
    114 nextrune(Biobuf *bp, int elide)
    115 {
    116 	int c, c2;
    117 	static int savec;
    118 
    119 	if(savec){
    120 		c = savec;
    121 		savec = 0;
    122 		return c;
    123 	}
    124 
    125 	for (;;) {
    126 		c = Bgetrune(bp);
    127 		if (c == '\\') {
    128 			c2 = Bgetrune(bp);
    129 			if(c2 == '\r'){
    130 				savec = c2;
    131 				c2 = Bgetrune(bp);
    132 			}
    133 			if (c2 == '\n') {
    134 				savec = 0;
    135 				mkinline++;
    136 				if (elide)
    137 					continue;
    138 				return ' ';
    139 			}
    140 			Bungetrune(bp);
    141 		}
    142 		if (c == '\n')
    143 			mkinline++;
    144 		return c;
    145 	}
    146 }