V10/cmd/mk/src/bquote.c

#include	"mk.h"

bquote(fd, src, dest)
	register char *src, *dest;
{
	int childin[2], childout[2], pid, i;
	int quotedone = 1;
	char *ldest, *t;
	char *newline = "\n";
	int wearedone = 0;
	int initdone = 0;
	extern char **environ;

	while(wearedone == 0)
		switch(*src)
		{
		default:
			*dest++ = *src++;
			break;
		case 0:
			if(quotedone)
				wearedone = 1;
			else {
				if(t = Frdline(fd)){
					inline++;
					*dest++ = '\n'|EBIT;
					strcpy(src, t);
					continue;
				} else {
					SYNERR(-1); Fprint(2, "missing closing `\n");
					break;
				}
			}
			break;
		case '\\':
			if(*src)
				*dest++ = *src++;
			else
				if(t = Frdline(fd)){
					inline++;
					strcpy(src, t);
				}
			break;
		case '`':
			if(quotedone = 1-quotedone){
				if(initdone == 0){
					execinit();
					initdone = 1;
				}
				Fflush(1);
				Fflush(2);
				if(pipe(childin) < 0){
					SYNERR(-1); perror("pipe1");
					Exit();
				}
				if(pipe(childout) < 0){
					SYNERR(-1); perror("pipe2");
					Exit();
				}
				if((pid = fork()) < 0){
					SYNERR(-1); perror("fork");
					Exit();
				}
				if(pid){	/* parent */
					close(childin[0]);
					close(childout[1]);
					if(ldest < dest){
						writeout(childin[1], ldest, dest);
						writeout(childin[1], newline, newline+1);
					}
					close(childin[1]);
					dest = ldest;
					while((i = read(childout[0], dest, 512)) > 0)
						dest += i;
					if((dest > ldest) && (dest[-1] == '\n'))
						dest--;
					close(childout[0]);
				} else {
					dup2(childin[0], 0);
					dup2(childout[1], 1);
					close(childin[0]);
					close(childin[1]);
					close(childout[0]);
					close(childout[1]);
					if(execle(SHELL, "sh", (char *)0, environ) < 0)
						perror("exec");
					_exit(1);
				}
			} else
				ldest = dest;
			src++;
			break;
		}
	*dest = 0;
}

writeout(fd, b, e)
	register char *b, *e;
{
	char buf[BIGBLOCK];
	register char *s;

	for(s = buf; b < e;){
		if(s >= &buf[BIGBLOCK-1]){
			SYNERR(-1); Fprint(2, "too much text (%d chars) for `expr`\n", s-buf);
			Exit();
		}
		if(*b&EBIT){
			*s++ = '\\';
			*s++ = (~EBIT) & *b++;
		} else
			*s++ = *b++;
	}
	write(fd, buf, s-buf);
}