On July 9, 2015 9:18:41 PM GMT+02:00, Jacob Wahlgren <[email protected]> wrote:

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 -'.

I've revised my previous patch to use more of the libbb functions and reduced 
it's
size considerably by merging the file_insert and fd_insert functions. I think 
this
version is much cleaner. Below is output from bloat-o-meter on my x86-64 
machine.

function                                             old     new   delta
file_insert                                          363     466    +103
edit_file                                            892     928     +36
init_text_buffer                                     184     203     +19
.rodata                                            75322   75338     +16
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/0 up/down: 174/0)             Total: 174 bytes
   text    data     bss     dec     hex filename
 455403    3872    9360  468635   7269b busybox_old
 455579    3872    9360  468811   7274b busybox_unstripped

Don't we have something like open_file_or_stdin?
See LONE_DASH spots, maybe.
There is a function called open_file_or_warn_stdin, which works, except that it 
would
make it impossible to open a file called "-". This is because LONE_DASH checks 
for both
bb_msg_standard_input (which I'm using in this patch as a sentinel value) and a 
literal
"-".

I think we already have open_read_close().
I'm not sure how that function could be used in this context, because the 
length of
the input from a pipe is uknown ahead of time.

I had to change the signature of several functions to take a const filename, 
this is
to enable them to receive bb_msg_standard_input. They didn't need a non-const 
pointer
at all, so this shouldn't hurt.

Cheers,
Jacob

Signed-off-by: Jacob Wahlgren<[email protected]>
---
 editors/vi.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 70 insertions(+), 21 deletions(-)

diff --git a/editors/vi.c b/editors/vi.c
index 6ce513c..392243a 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -491,7 +491,7 @@ struct globals {
 } while (0)
-static void edit_file(char *); // edit one file
+static void edit_file(const char *);   // edit one file
 static void do_cmd(int);       // execute a command
 static int next_tabstop(int);
 static void sync_cursor(char *, int *, int *); // synchronize the screen 
cursor to dot
@@ -716,7 +716,7 @@ 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)
+static int init_text_buffer(const char *fn)
 {
        int rc;
@@ -735,6 +735,9 @@ static int init_text_buffer(char *fn) if (fn != current_filename) {
                free(current_filename);
+               if (fn == bb_msg_standard_input)
+                       current_filename = NULL;
+               else
                        current_filename = xstrdup(fn);
        }
        rc = file_insert(fn, text, 1);
@@ -759,7 +762,7 @@ static int query_screen_dimensions(void)
 # define query_screen_dimensions() (0)
 #endif
-static void edit_file(char *fn)
+static void edit_file(const char *fn)
 {
 #if ENABLE_FEATURE_VI_YANKMARK
 #define cur_line edit_file__cur_line
@@ -770,9 +773,21 @@ static void edit_file(char *fn)
 #endif
editing = 1; // 0 = exit, 1 = one file, 2 = multiple files
-       rawmode();
        rows = 24;
        columns = 80;
+
+       if (fn && LONE_DASH(fn)) {
+               int tmpfd;
+
+               init_text_buffer(bb_msg_standard_input);
+               tmpfd = xopen("/dev/tty", O_RDONLY);
+               xmove_fd(tmpfd, STDIN_FILENO);
+       } else {
+               init_text_buffer(fn);
+       }
+
+       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 */) {
@@ -791,8 +806,8 @@ static void edit_file(char *fn)
                }
        }
 #endif
+
        new_screen(rows, columns);      // get memory for virtual screen
-       init_text_buffer(fn);
#if ENABLE_FEATURE_VI_YANKMARK
        YDreg = 26;                     // default Yank/Delete reg
@@ -2905,22 +2920,32 @@ static char *get_input_line(const char *prompt)
 }
// might reallocate text[]!
+// read from stdin if fn = bb_msg_standard_input
 static int file_insert(const char *fn, char *p, int initial)
 {
-       int cnt = -1;
-       int fd, size;
+       int cnt = 0;
+       int total = 0;
+       int unused_size = 0;
+       int fd;
        struct stat statbuf;
if (p < text || p > end) {
                status_line_bold("Trying to insert file outside of memory");
-               return cnt;
+               return -1;
+       } else if (fn == NULL) {
+               return -1;
        }
+ // We can't use LONE_DASH because it checks for "-" too
+       if (fn == bb_msg_standard_input)
+               fd = STDIN_FILENO;
+       else
                fd = open(fn, O_RDONLY);
+
        if (fd < 0) {
                if (!initial)
                        status_line_bold_errno(fn);
-               return cnt;
+               return fd;
        }
/* Validate file */
@@ -2928,26 +2953,49 @@ static int file_insert(const char *fn, char *p, int 
initial)
                status_line_bold_errno(fn);
                goto fi;
        }
-       if (!S_ISREG(statbuf.st_mode)) {
-               status_line_bold("'%s' is not a regular file", fn);
+
+       if (!S_ISREG (statbuf.st_mode)
+        && !S_ISFIFO(statbuf.st_mode)) {
+               status_line_bold("'%s' is not a regular file or pipe", fn);
                goto fi;
        }
-       size = (statbuf.st_size < INT_MAX ? (int)statbuf.st_size : INT_MAX);
-       p += text_hole_make(p, size);
-       cnt = full_read(fd, p, size);
-       if (cnt < 0) {
-               status_line_bold_errno(fn);
-               p = text_hole_delete(p, p + size - 1, NO_UNDO); // un-do buffer 
insert
-       } else if (cnt < size) {
-               // There was a partial read, shrink unused space
-               p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO);
+
+       do {
+               p += text_hole_make(p + total, BUFSIZ);
+               cnt = full_read(fd, p + total, BUFSIZ);
+               total += cnt;
+       } while (cnt == BUFSIZ);
+
+       if (cnt < 0
+        || (S_ISREG(statbuf.st_mode)
+         && total < statbuf.st_size)) {
+               if (total) {
+                       // Un-do buffer insert
+                       if (cnt < 0)
+                               unused_size = total - 1;
+                       else
+                               unused_size = total - cnt - 1;
+               }
+               total = cnt;
+       } else {
+               // Delete unused part of buffer
+               p += total;
+               unused_size = BUFSIZ - cnt - 1;
+       }
+
+       if (unused_size) {
+               text_hole_delete(p, p + unused_size, NO_UNDO);
+               if (cnt < 0)
                        status_line_bold("can't read '%s'", fn);
        }
+
  fi:
        close(fd);
+
 #if ENABLE_FEATURE_VI_READONLY
        if (initial
+        && fn != bb_msg_standard_input
         && ((access(fn, W_OK) < 0) ||
                /* root will always have access()
                 * so we check fileperms too */
@@ -2957,7 +3005,8 @@ static int file_insert(const char *fn, char *p, int 
initial)
                SET_READONLY_FILE(readonly_mode);
        }
 #endif
-       return cnt;
+
+       return total;   // negative if a read failed
 }
static int file_write(char *fn, char *first, char *last)

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

Reply via email to