pcw / cwr.c

#include <termios.h>
#include <stdio.h>
#include <sys/select.h>

int main(int argc, char **argv)
{
	struct termios set;
	char buf[4096], bufout[4096], tput_cub[32], tmp[L_tmpnam], cmd[1024];
	int i, j, len;
	FILE *pipe, *fifo;
	fd_set rd;

	if ((pipe = popen("tput cub1", "r")) == NULL)
		warn("failed on popen tput (please forgive me)");

	if (fgets(tput_cub, sizeof(tput_cub), pipe) == NULL)
		warn("failed to read tput cub1 (please forgive me)");

	pclose(pipe);

	if (mkfifo(tmpnam(tmp), 0700) < 0)
		err(1, "could not mkfifo %s", tmp);

	sprintf(cmd, "%s > %s", argv[1], tmp);

	if ((pipe = popen(cmd, "w")) == NULL)
		warn("could not popen %s", cmd);

	if ((fifo = fopen(tmp, "w+")) == NULL)
		err(1, "could not open fifo %s", tmp);

	tcgetattr(0, &set);
	set.c_lflag &= ~(ICANON | ECHO);
	set.c_cc[VMIN ] = 1;
	set.c_cc[VTIME] = 0;
	tcsetattr(0, TCSANOW, &set);

	//for (i = 0; i < sizeof(buf) - 1 && read(0, buf + i, 1) > 0; i++) {
	for (;;) {
		FD_ZERO(&rd);
		FD_SET(0, &rd);
		FD_SET(fileno(fifo), &rd);

		select(fileno(fifo) + 1, &rd, NULL, NULL, NULL);

		if (FD_ISSET(0, &rd)) {
			if (read(0, buf + i, 1) < 0)
				warn("failed reading from stdin");

			buf[i + 1] = '\0';

			switch (buf[i]) {
				case '\n' :
					if (i == 0) {
						i = -1;
						break;
					}
					for (j = 0; j < i; j++)
						printf("%s %s", tput_cub, tput_cub);
					fputs(buf, pipe);
					fflush(pipe);
					buf[0] = '\0';
					i = -1;
					break;
				case '\b' :
				case 127  :
					if (i--) {
						buf[i--] = '\0';
						fprintf(stdout, "%s %s", tput_cub, tput_cub);
					}
					break;
				default :
					putc(buf[i], stdout);
			}
			fflush(stdout);
			i++;
		}
		if (FD_ISSET(fileno(fifo), &rd)) {
			for (j = 0; j < i; j++)
				printf("%s %s", tput_cub, tput_cub);
			fflush(stdout);

			if ((len = read(fileno(fifo), bufout, sizeof(bufout))) < 0)
				warn("failed to read from fifo %s", tmp);
			write(1, bufout, len);

			fputs(buf, stdout);
			fflush(stdout);
		}
	}

	return 0;
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.