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