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