diff --git a/ex.c b/ex.c
index 372a5688..47491e8b 100644
--- a/ex.c
+++ b/ex.c
@@ -392,7 +392,9 @@ int ex_edit(const char *path, int len)
 static void *ec_edit(char *loc, char *cmd, char *arg)
 {
 	char msg[128];
-	int fd, len, rd = 0, cd = 0;
+	int fd = 0, len, rd = 0, cd = 0;
+	if (!cmd)
+		goto ret;
 	if (arg[0] == '.' && arg[1] == '/')
 		cd = 2;
 	len = strlen(arg+cd);
@@ -411,6 +413,9 @@ static void *ec_edit(char *loc, char *cmd, char *arg)
 		ex_bufpostfix(ex_buf, arg[0]);
 		syn_setft(xb_ft);
 	}
+	if (!loc)
+		return fd < 0 || rd ? xuerr : NULL;
+	ret:
 	snprintf(msg, sizeof(msg), "\"%s\" %dL [%c]",
 			*xb_path ? xb_path : "unnamed", lbuf_len(xb),
 			fd < 0 || rd ? 'f' : 'r');
@@ -1395,15 +1400,35 @@ void ex(void)
 
 void ex_init(char **files, int n)
 {
-	xbufsalloc = MAX(n, xbufsalloc);
+	xbufsalloc = MAX(n + !!stdin_fd, xbufsalloc);
 	ec_setbufsmax(NULL, NULL, "");
 	char *s = files[0] ? files[0] : "";
+	int i = n;
 	do {
-		ec_edit("", "e", s);
+		ec_edit(!n && stdin_fd ? NULL : "", "e", s);
 		s = *(++files);
 	} while (--n > 0);
+	if (stdin_fd) {
+		if (i)
+			ec_edit(NULL, "", "");
+		i = lbuf_rd(xb, STDIN_FILENO, 0, lbuf_len(xb));
+		term_done();
+		term_init();
+		lbuf_saved(xb, 1);
+		if (i)
+			ex_print("stdin read failed", msg_ft)
+		else
+			ec_edit("", NULL, ""); /* shebang patch compat */
+		close(0);
+		if (dup2(stdin_fd, 0) == -1) {
+			fprintf(stderr, "error: %s\n", "dup2");
+			close(stdin_fd);
+			exit(1);
+		}
+	}
 	xmpt = 0;
 	xvis &= ~8;
+	signal(SIGINT, SIG_DFL); /* got past init? ok remove ^c */
 	if ((s = getenv("EXINIT")))
 		ex_command(s)
 }
diff --git a/term.c b/term.c
index 757c26eb..22b91105 100644
--- a/term.c
+++ b/term.c
@@ -5,6 +5,8 @@ int xrows, xcols;
 unsigned int ibuf_pos, ibuf_cnt, ibuf_sz = 128, icmd_pos;
 unsigned char *ibuf, icmd[4096];
 unsigned int texec, tn;
+int stdin_fd;
+static int isig;
 
 void term_init(void)
 {
@@ -13,20 +15,24 @@ void term_init(void)
 	struct winsize win;
 	struct termios newtermios;
 	sbuf_make(term_sbuf, 2048)
-	tcgetattr(0, &termios);
+	tcgetattr(stdin_fd, &termios);
 	newtermios = termios;
-	newtermios.c_lflag &= ~(ICANON | ISIG | ECHO);
-	tcsetattr(0, TCSAFLUSH, &newtermios);
+	if (!isig && stdin_fd)
+		newtermios.c_lflag &= ~(ICANON);
+	else
+		newtermios.c_lflag &= ~(ICANON | ISIG | ECHO);
+	tcsetattr(stdin_fd, TCSAFLUSH, &newtermios);
 	if (getenv("LINES"))
 		xrows = atoi(getenv("LINES"));
 	if (getenv("COLUMNS"))
 		xcols = atoi(getenv("COLUMNS"));
-	if (!ioctl(0, TIOCGWINSZ, &win)) {
+	if (!ioctl(stdin_fd, TIOCGWINSZ, &win)) {
 		xcols = win.ws_col;
 		xrows = win.ws_row;
 	}
 	xcols = xcols ? xcols : 80;
 	xrows = xrows ? xrows : 25;
+	isig = 1;
 }
 
 void term_done(void)
@@ -36,7 +42,7 @@ void term_done(void)
 	term_commit();
 	sbuf_free(term_sbuf)
 	term_sbuf = NULL;
-	tcsetattr(0, 0, &termios);
+	tcsetattr(stdin_fd, 0, &termios);
 }
 
 void term_clean(void)
@@ -149,12 +155,12 @@ int term_read(void)
 			if (texec == '&')
 				goto err;
 		}
-		ufds[0].fd = STDIN_FILENO;
+		ufds[0].fd = stdin_fd;
 		ufds[0].events = POLLIN;
 		/* read a single input character */
 		if (xquit < 0 || poll(ufds, 1, -1) <= 0 ||
-				read(STDIN_FILENO, ibuf, 1) <= 0) {
-			xquit = !isatty(STDIN_FILENO) ? -1 : xquit;
+				read(stdin_fd, ibuf, 1) <= 0) {
+			xquit = !isatty(stdin_fd) ? -1 : xquit;
 			err:
 			*ibuf = 0;
 		}
@@ -289,7 +295,7 @@ sbuf *cmd_pipe(char *cmd, sbuf *ibuf, int oproc, int *status)
 	fds[0].events = POLLIN;
 	fds[1].fd = ifd;
 	fds[1].events = POLLOUT;
-	fds[2].fd = ibuf ? 0 : -1;
+	fds[2].fd = ibuf ? stdin_fd : -1;
 	fds[2].events = POLLIN;
 	while ((fds[0].fd >= 0 || fds[1].fd >= 0) && poll(fds, 3, 200) >= 0) {
 		if (fds[0].revents & POLLIN) {
@@ -332,7 +338,7 @@ sbuf *cmd_pipe(char *cmd, sbuf *ibuf, int oproc, int *status)
 		close(ifd);
 	waitpid(pid, status, 0);
 	signal(SIGTTOU, SIG_IGN);
-	tcsetpgrp(STDIN_FILENO, getpgrp());
+	tcsetpgrp(stdin_fd, getpgrp());
 	signal(SIGTTOU, SIG_DFL);
 	if (!ibuf) {
 		term_init();
diff --git a/vi.c b/vi.c
index b83a1df9..ea421418 100644
--- a/vi.c
+++ b/vi.c
@@ -1775,7 +1775,8 @@ static int setup_signals(void)
 	struct sigaction sa;
 	memset(&sa, 0, sizeof(sa));
 	sa.sa_handler = sighandler;
-	if (sigaction(SIGWINCH, &sa, NULL))
+	if (sigaction(SIGWINCH, &sa, NULL)
+			|| sigaction(SIGINT, &sa, NULL))
 		return 0;
 	return 1;
 }
@@ -1793,7 +1794,8 @@ int main(int argc, char *argv[])
 		if (argv[i][1] == '-' && !argv[i][2]) {
 			i++;
 			break;
-		}
+		} else if (!argv[i][1])
+			stdin_fd = MAX(0, open(ctermid(NULL), O_RDONLY));
 		for (j = 1; argv[i][j]; j++) {
 			if (argv[i][j] == 's')
 				xvis |= 2|4;
diff --git a/vi.h b/vi.h
index 1bef0600..5b197527 100644
--- a/vi.h
+++ b/vi.h
@@ -514,6 +514,7 @@ extern int vi_hidch;
 extern int vi_insmov;
 extern int vi_lncol;
 extern char vi_msg[512];
+extern int stdin_fd;
 /* file system */
 extern rset *fsincl;
 extern char *fs_exdir;
