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 <[email protected]>
---
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

_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to