aboutsummaryrefslogtreecommitdiff
path: root/editors/vi.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-12-21 21:34:37 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-12-21 21:34:37 +0000
commit26b6fba9d33bb4ce117db4ad22a94f05d04ff8be (patch)
tree29d3d380a03219ec64c0f4720917d3fada20f2e5 /editors/vi.c
parent619879246d57c9c54fa8e8eef138dde0876b0ef0 (diff)
downloadbusybox-26b6fba9d33bb4ce117db4ad22a94f05d04ff8be.tar.gz
vi: fix a problem with displaying overlong lines
Diffstat (limited to 'editors/vi.c')
-rw-r--r--editors/vi.c227
1 files changed, 120 insertions, 107 deletions
diff --git a/editors/vi.c b/editors/vi.c
index 9426ab855..e58d6b310 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -35,6 +35,7 @@
enum {
MAX_LINELEN = CONFIG_FEATURE_VI_MAX_LEN,
MAX_SCR_COLS = CONFIG_FEATURE_VI_MAX_LEN,
+ MAX_TABSTOP = 32, // sanity limit
};
// Misc. non-Ascii keys that report an escape sequence
@@ -116,7 +117,8 @@ static int fn_start; // index of first cmd line file name
static int save_argc; // how many file names on cmd line
static int cmdcnt; // repetition count
static int rows, columns; // the terminal screen is this size
-static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset
+static int crow, ccol; // cursor is on Crow x Ccol
+static int offset; // chars scrolled off the screen to the left
static char *status_buffer; // mesages to the user
#define STATUS_BUFFER_LEN 200
static int have_status_msg; // is default edit status needed?
@@ -253,6 +255,9 @@ static int file_insert(const char *, char *, int);
static int file_insert(const char *, char *);
#endif
static int file_write(char *, char *, char *);
+#if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
+#define place_cursor(a, b, optimize) place_cursor(a, b)
+#endif
static void place_cursor(int, int, int);
static void screen_erase(void);
static void clear_to_eol(void);
@@ -266,7 +271,7 @@ static void psbs(const char *, ...); // Print Status Buf in standout mode
static void ni(const char *); // display messages
static int format_edit_status(void); // format file status on status line
static void redraw(int); // force a full screen refresh
-static void format_line(char*, char*, int);
+static int format_line(char*, char*, int);
static void refresh(int); // update the terminal from screen[]
static void Indicate_Error(void); // use flash or beep to indicate error
@@ -992,7 +997,7 @@ static void colon(char * buf)
/* tabstopXXXX */
if (strncasecmp(argp + i, "tabstop=%d ", 7) == 0) {
sscanf(strchr(argp + i, '='), "tabstop=%d" + 7, &ch);
- if (ch > 0 && ch < columns - 1)
+ if (ch > 0 && ch <= MAX_TABSTOP)
tabstop = ch;
}
while (*argp && *argp != ' ')
@@ -1252,7 +1257,7 @@ static char *end_line(char * p) // return pointer to NL of cur line line
return p;
}
-static inline char *dollar_line(char * p) // return pointer to just before NL line
+static char *dollar_line(char * p) // return pointer to just before NL line
{
while (p < end - 1 && *p != '\n')
p++; // go to cur line E-o-l
@@ -1923,7 +1928,7 @@ static void show_help(void)
);
}
-static inline void print_literal(char * buf, const char * s) // copy s to buf, convert unprintable
+static void print_literal(char * buf, const char * s) // copy s to buf, convert unprintable
{
unsigned char c;
char b[2];
@@ -2055,7 +2060,7 @@ static void check_context(char cmd)
}
}
-static inline char *swap_context(char * p) // goto new context for '' command make this the current context
+static char *swap_context(char * p) // goto new context for '' command make this the current context
{
char *tmp;
@@ -2147,7 +2152,7 @@ static int mysleep(int hund) // sleep for 'h' 1/100 seconds
return safe_poll(pfd, 1, hund*10) > 0;
}
-static int readed_for_parse;
+static int chars_to_parse;
//----- IO Routines --------------------------------------------
static char readit(void) // read (maybe cursor) key from stdin
@@ -2199,7 +2204,7 @@ static char readit(void) // read (maybe cursor) key from stdin
alarm(0); // turn alarm OFF while we wait for input
fflush(stdout);
- n = readed_for_parse;
+ n = chars_to_parse;
// get input from User- are there already input chars in Q?
if (n <= 0) {
// the Q is empty, wait for a typed char
@@ -2228,7 +2233,7 @@ static char readit(void) // read (maybe cursor) key from stdin
n += r;
}
}
- readed_for_parse = n;
+ chars_to_parse = n;
}
c = readbuffer[0];
if (c == 27 && n > 1) {
@@ -2256,7 +2261,7 @@ static char readit(void) // read (maybe cursor) key from stdin
n = 1;
}
// remove key sequence from Q
- readed_for_parse -= n;
+ chars_to_parse -= n;
memmove(readbuffer, readbuffer + n, MAX_LINELEN - n);
alarm(3); // we are done waiting for input, turn alarm ON
return c;
@@ -2265,7 +2270,7 @@ static char readit(void) // read (maybe cursor) key from stdin
//----- IO Routines --------------------------------------------
static char get_one_char(void)
{
- static char c;
+ char c;
#if ENABLE_FEATURE_VI_DOT_CMD
// ! adding2q && ioq == 0 read()
@@ -2290,7 +2295,7 @@ static char get_one_char(void)
} else {
// adding STDIN chars to q
c = readit(); // get the users input
- if (last_modifying_cmd != 0) {
+ if (last_modifying_cmd != NULL) {
int len = strlen(last_modifying_cmd);
if (len >= MAX_LINELEN - 1) {
psbs("last_modifying_cmd overrun");
@@ -2303,17 +2308,18 @@ static char get_one_char(void)
#else
c = readit(); // get the users input
#endif /* FEATURE_VI_DOT_CMD */
- return c; // return the char, where ever it came from
+ return c;
}
static char *get_input_line(const char * prompt) // get input line- use "status line"
{
- static char *obufp;
+ static char *buf; // [MAX_LINELEN]
- char buf[MAX_LINELEN];
char c;
int i;
+ if (!buf) buf = xmalloc(MAX_LINELEN);
+
strcpy(buf, prompt);
last_status_cksum = 0; // force status update
place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
@@ -2329,7 +2335,7 @@ static char *get_input_line(const char * prompt) // get input line- use "status
// user wants to erase prev char
i--; // backup to prev char
buf[i] = '\0'; // erase the char
- buf[i + 1] = '\0'; // null terminate buffer
+ //buf[i + 1] = '\0'; // null terminate buffer
write1("\b \b"); // erase char on screen
if (i <= 0) { // user backs up before b-o-l, exit
break;
@@ -2342,9 +2348,7 @@ static char *get_input_line(const char * prompt) // get input line- use "status
}
}
refresh(FALSE);
- free(obufp);
- obufp = xstrdup(buf);
- return obufp;
+ return buf;
}
static int file_size(const char *fn) // what is the byte size of "fn"
@@ -2434,12 +2438,11 @@ static int file_write(char * fn, char * first, char * last)
return -2;
}
charcnt = 0;
- // FIXIT- use the correct umask()
- fd = open(fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664);
+ fd = open(fn, (O_WRONLY | O_CREAT | O_TRUNC), 0666);
if (fd < 0)
return -1;
cnt = last - first + 1;
- charcnt = write(fd, first, cnt);
+ charcnt = full_write(fd, first, cnt);
if (charcnt == cnt) {
// good write
//file_modified = FALSE; // the file has not been modified
@@ -2459,22 +2462,13 @@ static int file_write(char * fn, char * first, char * last)
// . ... .
// . ... .
// 22,0 ... 22,79
-// 23,0 ... 23,79 status line
-//
+// 23,0 ... 23,79 <- status line
//----- Move the cursor to row x col (count from 0, not 1) -------
-static void place_cursor(int row, int col, int opti)
+static void place_cursor(int row, int col, int optimize)
{
- char cm1[MAX_LINELEN];
+ char cm1[32];
char *cm;
-#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
- char cm2[MAX_LINELEN];
- char *screenp;
- // char cm3[MAX_LINELEN];
- int Rrow = last_row;
-#endif
-
- memset(cm1, '\0', MAX_LINELEN); // clear the buffer
if (row < 0) row = 0;
if (row >= rows) row = rows - 1;
@@ -2484,45 +2478,42 @@ static void place_cursor(int row, int col, int opti)
//----- 1. Try the standard terminal ESC sequence
sprintf(cm1, CMrc, row + 1, col + 1);
cm = cm1;
- if (!opti)
- goto pc0;
#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
- //----- find the minimum # of chars to move cursor -------------
- //----- 2. Try moving with discreet chars (Newline, [back]space, ...)
- memset(cm2, '\0', MAX_LINELEN); // clear the buffer
+ if (optimize && col < 16) {
+ char cm2[MAX_LINELEN]; // better size estimate?
+ char *screenp;
+ int Rrow = last_row;
- // move to the correct row
- while (row < Rrow) {
- // the cursor has to move up
- strcat(cm2, CMup);
- Rrow--;
- }
- while (row > Rrow) {
- // the cursor has to move down
- strcat(cm2, CMdown);
- Rrow++;
- }
+ //----- find the minimum # of chars to move cursor -------------
+ //----- 2. Try moving with discreet chars (Newline, [back]space, ...)
+ cm2[0] = '\0';
- // now move to the correct column
- strcat(cm2, "\r"); // start at col 0
- // just send out orignal source char to get to correct place
- screenp = &screen[row * columns]; // start of screen line
- strncat(cm2, screenp, col);
+ // move to the correct row
+ while (row < Rrow) {
+ // the cursor has to move up
+ strcat(cm2, CMup);
+ Rrow--;
+ }
+ while (row > Rrow) {
+ // the cursor has to move down
+ strcat(cm2, CMdown);
+ Rrow++;
+ }
- //----- 3. Try some other way of moving cursor
- //---------------------------------------------
+ // now move to the correct column
+ strcat(cm2, "\r"); // start at col 0
+ // just send out orignal source char to get to correct place
+ screenp = &screen[row * columns]; // start of screen line
+ strncat(cm2, screenp, col);
- // pick the shortest cursor motion to send out
- cm = cm1;
- if (strlen(cm2) < strlen(cm)) {
- cm = cm2;
- } /* else if (strlen(cm3) < strlen(cm)) {
- cm= cm3;
- } */
+ // pick the shortest cursor motion to send out
+ if (strlen(cm2) < strlen(cm)) {
+ cm = cm2;
+ }
+ }
#endif /* FEATURE_VI_OPTIMIZE_CURSOR */
- pc0:
- write1(cm); // move the cursor
+ write1(cm);
}
//----- Erase from cursor to end of line -----------------------
@@ -2721,11 +2712,15 @@ static void redraw(int full_screen)
}
//----- Format a text[] line into a buffer ---------------------
-static void format_line(char *dest, char *src, int li)
+// Returns number of leading chars which should be ignored
+// (return value is always <= offset)
+static int format_line(char *dest, char *src, int li)
{
- int co;
char c;
+ int co;
+ int ofs = offset;
+ memset(dest, ' ', MAX_SCR_COLS);
for (co = 0; co < MAX_SCR_COLS; co++) {
c = ' '; // assume blank
if (li > 0 && co == 0) {
@@ -2734,33 +2729,52 @@ static void format_line(char *dest, char *src, int li)
// are there chars in text[] and have we gone past the end
if (text < end && src < end) {
c = *src++;
- }
- if (c == '\n')
- break;
- if ((c & 0x80) && !Isprint(c)) {
- c = '.';
- }
- if ((unsigned char)(c) < ' ' || c == 0x7f) {
- if (c == '\t') {
- c = ' ';
- // co % 8 != 7
- for (; (co % tabstop) != (tabstop - 1); co++) {
- dest[co] = c;
+
+ if (c == '\n')
+ break;
+ if ((c & 0x80) && !Isprint(c)) {
+ c = '.';
+ }
+ if ((unsigned char)(c) < ' ' || c == 0x7f) {
+ if (c == '\t') {
+ c = ' ';
+ // co % 8 != 7
+ while ((co % tabstop) != (tabstop - 1)) {
+ dest[co++] = c;
+ if (co >= MAX_SCR_COLS)
+ goto ret;
+ }
+ } else {
+ dest[co++] = '^';
+ if (co >= MAX_SCR_COLS)
+ goto ret;
+ if (c == 0x7f)
+ c = '?';
+ else
+ c += '@'; // make it visible
}
- } else {
- dest[co++] = '^';
- if (c == 0x7f)
- c = '?';
- else
- c += '@'; // make it visible
}
}
// the co++ is done here so that the column will
// not be overwritten when we blank-out the rest of line
dest[co] = c;
+ // discard scrolled-off portion, in tabstop-sized pieces
+ if (ofs >= tabstop && co >= tabstop) {
+ co -= tabstop;
+ ofs -= tabstop;
+ memset(&dest[co + 1], ' ', tabstop);
+ }
if (src >= end)
break;
}
+ ret:
+ if (co < ofs) {
+ // entire line has scrolled off, make it entirely blank
+ memset(dest, ' ', MAX_SCR_COLS);
+ ofs = 0;
+ }
+ dest[MAX_SCR_COLS-1] = '\0';
+ return ofs;
}
//----- Refresh the changed screen lines -----------------------
@@ -2786,19 +2800,19 @@ static void refresh(int full_screen)
// compare text[] to screen[] and mark screen[] lines that need updating
for (li = 0; li < rows - 1; li++) {
+ int ofs;
int cs, ce; // column start & end
- memset(buf, ' ', MAX_SCR_COLS); // blank-out the buffer
- buf[MAX_SCR_COLS-1] = 0; // NULL terminate the buffer
// format current text line into buf
- format_line(buf, tp, li);
+ ofs = format_line(buf, tp, li);
// skip to the end of the current text[] line
- while (tp < end && *tp++ != '\n') /*no-op*/;
+ while (tp < end && *tp++ != '\n')
+ continue;
// see if there are any changes between vitual screen and buf
changed = FALSE; // assume no change
- cs= 0;
- ce= columns-1;
+ cs = 0;
+ ce = columns - 1;
sp = &screen[li * columns]; // start of screen line
if (full_screen) {
// force re-draw of every single column from 0 - columns-1
@@ -2807,15 +2821,15 @@ static void refresh(int full_screen)
// compare newly formatted buffer with virtual screen
// look forward for first difference between buf and screen
for (; cs <= ce; cs++) {
- if (buf[cs + offset] != sp[cs]) {
+ if (buf[cs + ofs] != sp[cs]) {
changed = TRUE; // mark for redraw
break;
}
}
// look backward for last difference between buf and screen
- for ( ; ce >= cs; ce--) {
- if (buf[ce + offset] != sp[ce]) {
+ for (; ce >= cs; ce--) {
+ if (buf[ce + ofs] != sp[ce]) {
changed = TRUE; // mark for redraw
break;
}
@@ -2829,13 +2843,13 @@ static void refresh(int full_screen)
}
// make a sanity check of columns indexes
- if (cs < 0) cs= 0;
- if (ce > columns-1) ce= columns-1;
- if (cs > ce) { cs= 0; ce= columns-1; }
+ if (cs < 0) cs = 0;
+ if (ce > columns - 1) ce = columns - 1;
+ if (cs > ce) { cs = 0; ce = columns - 1; }
// is there a change between vitual screen and buf
if (changed) {
- // copy changed part of buffer to virtual screen
- memmove(sp+cs, buf+(cs+offset), ce-cs+1);
+ // copy changed part of buffer to virtual screen
+ memmove(sp+cs, buf+(cs+ofs), ce-cs+1);
// move cursor to column of first change
if (offset != old_offset) {
@@ -2848,7 +2862,7 @@ static void refresh(int full_screen)
// try to optimize cursor movement
// otherwise, use standard ESC sequence
place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE);
- last_li= li;
+ last_li = li;
#else
place_cursor(li, cs, FALSE); // use standard ESC sequence
#endif /* FEATURE_VI_OPTIMIZE_CURSOR */
@@ -2859,7 +2873,7 @@ static void refresh(int full_screen)
int nic = ce - cs + 1;
char *out = sp + cs;
- while (nic-- > 0) {
+ while (--nic >= 0) {
bb_putchar(*out);
out++;
}
@@ -2877,8 +2891,7 @@ static void refresh(int full_screen)
place_cursor(crow, ccol, FALSE);
#endif
- if (offset != old_offset)
- old_offset = offset;
+ old_offset = offset;
}
//---------------------------------------------------------------------
@@ -3230,7 +3243,7 @@ static void do_cmd(char c)
case '.': // .- repeat the last modifying command
// Stuff the last_modifying_cmd back into stdin
// and let it be re-executed.
- if (last_modifying_cmd != 0) {
+ if (last_modifying_cmd != NULL) {
ioq = ioq_start = xstrdup(last_modifying_cmd);
}
break;
@@ -3844,7 +3857,7 @@ static void crash_dummy()
cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL";
// is there already a command running?
- if (readed_for_parse > 0)
+ if (chars_to_parse > 0)
goto cd1;
cd0:
startrbi = rbi = 0;
@@ -3921,7 +3934,7 @@ static void crash_dummy()
}
strcat(readbuffer, "\033");
}
- readed_for_parse = strlen(readbuffer);
+ chars_to_parse = strlen(readbuffer);
cd1:
totalcmds++;
if (sleeptime > 0)