Anonymous avatar Anonymous committed 5e2fb40

oh hell yeah

Comments (0)

Files changed (1)

+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <stdio.h>
+#include <pty.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+#define STDIN  0
+#define STDOUT 1
+#define STDERR 2
+
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+char csi[] = {0x1b, '[', 0};
+char buf[4096], usrbuf[4096];
+char scrl_prompt[] = "<";
+char nrml_prompt[] = ">";
+int pos = 0;
+
+void my_write(int fd, const void *buf, size_t count)
+{
+	int i, wrlen;
+
+	for (i = wrlen = 0; i < count; i += wrlen)
+		if ((wrlen = write(fd, buf + i, count - i)) < 0)
+			warn("failed to write fd = %d", fd);
+}
+
+void prompt(int *start, int *cols, int pos)
+{
+	int prompt_len, scrl_len, nrml_len;
+	char *prompt;
+
+	nrml_len = strlen(nrml_prompt);
+	scrl_len = strlen(scrl_prompt);
+
+	*start = MAX(0, pos - *cols + nrml_len);
+
+	prompt     = *start ? scrl_prompt : nrml_prompt;
+	prompt_len = *start ? scrl_len    : nrml_len;
+
+	*start = MAX(0, pos - *cols + prompt_len);
+
+	my_write(STDOUT, prompt, prompt_len);
+	*cols -= prompt_len;
+}
+
+void erase_usr()
+{
+	printf("%s1G", csi); //first column
+	printf("%sJ",  csi); //erase
+	fflush(stdout);
+}
+
+void print_usr()
+{
+	int start, cols;
+	struct winsize ws;
+
+	if (ioctl(1, TIOCGWINSZ, &ws) < 0)
+		err(1, "failed ioctl");
+
+	cols = ws.ws_col - 1;
+
+	erase_usr();
+	prompt(&start, &cols, pos);
+	my_write(STDOUT, usrbuf + start, pos - start);
+}
+
+int main(int argc, char **argv)
+{
+	int mfd, rdlen, wrlen, i;
+	fd_set rd;
+	struct termios set;
+
+	tcgetattr(0, &set);
+	set.c_lflag &= ~ECHO;
+
+	if (forkpty(&mfd, NULL, &set, NULL) == 0) { //child
+		execvp(argv[1], &argv[1]);
+		err("failed execvp %s", argv[1]);
+	}
+
+	// read one character at a time;
+	set.c_lflag    &= ~(ICANON | ECHO);
+	set.c_cc[VMIN ] = 1;
+	set.c_cc[VTIME] = 0;
+	tcsetattr(0, TCSANOW, &set);
+
+	print_usr();
+
+	for (;;) {
+		FD_ZERO(&rd);
+		FD_SET(STDIN, &rd);
+		FD_SET(mfd,   &rd);
+
+		select(mfd + 1, &rd, NULL, NULL, NULL);
+
+		if (FD_ISSET(STDIN, &rd)) {
+			if ((rdlen = read(STDIN, usrbuf + pos, 1)) < 0)
+				warn("failed to read from stdin");
+
+			switch (usrbuf[pos++]) {
+				case '\n':
+					erase_usr();
+					my_write(mfd, usrbuf, pos);
+					pos = 0;
+					break;
+				case '\b':
+				case 127 :
+					pos -= (pos > 1) ? 2 : 1;
+					break;
+			}
+			print_usr();
+
+		}
+		if (FD_ISSET(mfd, &rd)) {
+			if ((rdlen = read(mfd, buf, sizeof(buf))) < 0)
+				warn("failed to read from master");
+
+			erase_usr();
+			my_write(STDOUT, buf, rdlen);
+			print_usr();
+		}
+	}
+	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.