[PATCH] Fix bug 6968 - vi cannot accept input from pipe

Jacob Wahlgren jacob.wahlgren at gmail.com
Thu Jul 9 19:18:41 UTC 2015


With this patch, vi can load an initial buffer from stdin and then
start reading user input from /dev/tty. This is done by invoking it as
'vi -'. Example from the bug report: 'ls -l dir1 | vi -'.

Cheers,
Jacob

Signed-off-by: Jacob Wahlgren <jacob.wahlgren at gmail.com>
---
  editors/vi.c | 66 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
  1 file changed, 61 insertions(+), 5 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index 6ce513c..26514c3 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -544,6 +544,7 @@ static int readit(void);    // read (maybe cursor) 
key from stdin
  static int get_one_char(void);    // read 1 char from stdin
  // file_insert might reallocate text[]!
  static int file_insert(const char *, char *, int);
+static int fd_insert(int, char *);
  static int file_write(char *, char *, char *);
  static void place_cursor(int, int);
  static void screen_erase(void);
@@ -716,7 +717,8 @@ int vi_main(int argc, char **argv)

  /* read text from file or create an empty buf */
  /* will also update current_filename */
-static int init_text_buffer(char *fn)
+/* read from fd instead if fd >= 0 */
+static int init_text_buffer(char *fn, int fd)
  {
      int rc;

@@ -737,11 +739,18 @@ static int init_text_buffer(char *fn)
          free(current_filename);
          current_filename = xstrdup(fn);
      }
-    rc = file_insert(fn, text, 1);
+
+    if (fd >= 0) {
+        rc = fd_insert(fd, text);
+    } else {
+        rc = file_insert(fn, text, 1);
+    }
+
      if (rc < 0) {
          // file doesnt exist. Start empty buf with dummy line
          char_insert(text, '\n', NO_UNDO);
      }
+
      return rc;
  }

@@ -765,14 +774,32 @@ static void edit_file(char *fn)
  #define cur_line edit_file__cur_line
  #endif
      int c;
+    int fd;            // set if piping from stdin, otherwise -1
  #if ENABLE_FEATURE_VI_USE_SIGNALS
      int sig;
  #endif

      editing = 1;    // 0 = exit, 1 = one file, 2 = multiple files
-    rawmode();
      rows = 24;
      columns = 80;
+
+    if (fn && strcmp("-", fn) == 0) {
+        // set fd = pipe in, stdin = tty
+        int tmpfd;
+
+        fn[0] = '\0';
+        tmpfd = open("/dev/tty", O_RDONLY);
+        if (tmpfd < 0)
+            bb_perror_msg_and_die("/dev/tty");
+        if ((fd = dup(STDIN_FILENO)) < 0
+         || dup2(tmpfd, STDIN_FILENO) < 0)
+            bb_perror_msg_and_die("dup");
+        close(tmpfd);
+    } else {
+        fd = -1;    // don't use fd, open fn instead
+    }
+    rawmode();
+
      IF_FEATURE_VI_ASK_TERMINAL(G.get_rowcol_error =) 
query_screen_dimensions();
  #if ENABLE_FEATURE_VI_ASK_TERMINAL
      if (G.get_rowcol_error /* TODO? && no input on stdin */) {
@@ -792,7 +819,10 @@ static void edit_file(char *fn)
      }
  #endif
      new_screen(rows, columns);    // get memory for virtual screen
-    init_text_buffer(fn);
+    init_text_buffer(fn, fd);
+
+    if (fd >= 0)
+        close(fd);

  #if ENABLE_FEATURE_VI_YANKMARK
      YDreg = 26;            // default Yank/Delete reg
@@ -1195,7 +1225,7 @@ static void colon(char *buf)
              goto ret;
          }

-        size = init_text_buffer(fn);
+        size = init_text_buffer(fn, -1);

  #if ENABLE_FEATURE_VI_YANKMARK
          if (Ureg >= 0 && Ureg < 28) {
@@ -2960,6 +2990,32 @@ static int file_insert(const char *fn, char *p, 
int initial)
      return cnt;
  }

+static int fd_insert(int fd, char *p)
+{
+    int size = BUFSIZ;
+    int cnt = 0;
+    int total = 0;
+
+    do {
+        total += cnt;
+        p += text_hole_make(p + total, size);
+        cnt = full_read(fd, p + total, size);
+    } while (cnt == size);
+
+    if (cnt < 0) {
+        status_line_bold_errno("can't read from fd");
+        if (total)    // un-do buffer insert
+            p = text_hole_delete(p, p + total - 1, NO_UNDO);
+        total = cnt;
+    } else {
+        total += cnt;
+        // shrink unused space
+        p = text_hole_delete(p + total, p + total + size - cnt - 1, 
NO_UNDO);
+    }
+
+    return total;
+}
+
  static int file_write(char *fn, char *first, char *last)
  {
      int fd, cnt, charcnt;
-- 
1.9.1



More information about the busybox mailing list