diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-20 08:59:03 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-20 08:59:03 +0000 |
| commit | 4c9e9c4314e6f997f37814fffc6b49ebd24bd6be (patch) | |
| tree | 5df6ccef20e28a939ee1a1cebcb60ee1b4f94c7b | |
| parent | 078323010b5d88485748d05e512d451b876992b5 (diff) | |
| download | busybox-w32-4c9e9c4314e6f997f37814fffc6b49ebd24bd6be.tar.gz busybox-w32-4c9e9c4314e6f997f37814fffc6b49ebd24bd6be.tar.bz2 busybox-w32-4c9e9c4314e6f997f37814fffc6b49ebd24bd6be.zip | |
vi: handle chars 0x80, 0x81... correctly
| -rw-r--r-- | editors/vi.c | 125 |
1 files changed, 64 insertions, 61 deletions
diff --git a/editors/vi.c b/editors/vi.c index 50dda7f3a..55154dcd7 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
| @@ -57,29 +57,33 @@ enum { | |||
| 57 | MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN, | 57 | MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN, |
| 58 | }; | 58 | }; |
| 59 | 59 | ||
| 60 | // Misc. non-Ascii keys that report an escape sequence | 60 | // "Keycodes" that report an escape sequence. |
| 61 | #define VI_K_UP (char)128 // cursor key Up | 61 | // We use something which fits into signed char, |
| 62 | #define VI_K_DOWN (char)129 // cursor key Down | 62 | // yet doesn't represent any valid Unicode characher. |
| 63 | #define VI_K_RIGHT (char)130 // Cursor Key Right | 63 | enum { |
| 64 | #define VI_K_LEFT (char)131 // cursor key Left | 64 | VI_K_UP = -1, // cursor key Up |
| 65 | #define VI_K_HOME (char)132 // Cursor Key Home | 65 | VI_K_DOWN = -2, // cursor key Down |
| 66 | #define VI_K_END (char)133 // Cursor Key End | 66 | VI_K_RIGHT = -3, // Cursor Key Right |
| 67 | #define VI_K_INSERT (char)134 // Cursor Key Insert | 67 | VI_K_LEFT = -4, // cursor key Left |
| 68 | #define VI_K_DELETE (char)135 // Cursor Key Insert | 68 | VI_K_HOME = -5, // Cursor Key Home |
| 69 | #define VI_K_PAGEUP (char)136 // Cursor Key Page Up | 69 | VI_K_END = -6, // Cursor Key End |
| 70 | #define VI_K_PAGEDOWN (char)137 // Cursor Key Page Down | 70 | VI_K_INSERT = -7, // Cursor Key Insert |
| 71 | #define VI_K_FUN1 (char)138 // Function Key F1 | 71 | VI_K_DELETE = -8, // Cursor Key Insert |
| 72 | #define VI_K_FUN2 (char)139 // Function Key F2 | 72 | VI_K_PAGEUP = -9, // Cursor Key Page Up |
| 73 | #define VI_K_FUN3 (char)140 // Function Key F3 | 73 | VI_K_PAGEDOWN = -10, // Cursor Key Page Down |
| 74 | #define VI_K_FUN4 (char)141 // Function Key F4 | 74 | VI_K_FUN1 = -11, // Function Key F1 |
| 75 | #define VI_K_FUN5 (char)142 // Function Key F5 | 75 | VI_K_FUN2 = -12, // Function Key F2 |
| 76 | #define VI_K_FUN6 (char)143 // Function Key F6 | 76 | VI_K_FUN3 = -13, // Function Key F3 |
| 77 | #define VI_K_FUN7 (char)144 // Function Key F7 | 77 | VI_K_FUN4 = -14, // Function Key F4 |
| 78 | #define VI_K_FUN8 (char)145 // Function Key F8 | 78 | VI_K_FUN5 = -15, // Function Key F5 |
| 79 | #define VI_K_FUN9 (char)146 // Function Key F9 | 79 | VI_K_FUN6 = -16, // Function Key F6 |
| 80 | #define VI_K_FUN10 (char)147 // Function Key F10 | 80 | VI_K_FUN7 = -17, // Function Key F7 |
| 81 | #define VI_K_FUN11 (char)148 // Function Key F11 | 81 | VI_K_FUN8 = -18, // Function Key F8 |
| 82 | #define VI_K_FUN12 (char)149 // Function Key F12 | 82 | VI_K_FUN9 = -19, // Function Key F9 |
| 83 | VI_K_FUN10 = -20, // Function Key F10 | ||
| 84 | VI_K_FUN11 = -21, // Function Key F11 | ||
| 85 | VI_K_FUN12 = -22, // Function Key F12 | ||
| 86 | }; | ||
| 83 | 87 | ||
| 84 | /* vt102 typical ESC sequence */ | 88 | /* vt102 typical ESC sequence */ |
| 85 | /* terminal standout start/normal ESC sequence */ | 89 | /* terminal standout start/normal ESC sequence */ |
| @@ -171,9 +175,9 @@ struct globals { | |||
| 171 | char *screen; // pointer to the virtual screen buffer | 175 | char *screen; // pointer to the virtual screen buffer |
| 172 | int screensize; // and its size | 176 | int screensize; // and its size |
| 173 | int tabstop; | 177 | int tabstop; |
| 178 | int last_forward_char; // last char searched for with 'f' (int because of Unicode) | ||
| 174 | char erase_char; // the users erase character | 179 | char erase_char; // the users erase character |
| 175 | char last_input_char; // last char read from user | 180 | char last_input_char; // last char read from user |
| 176 | char last_forward_char; // last char searched for with 'f' | ||
| 177 | 181 | ||
| 178 | #if ENABLE_FEATURE_VI_DOT_CMD | 182 | #if ENABLE_FEATURE_VI_DOT_CMD |
| 179 | smallint adding2q; // are we currently adding user input to q | 183 | smallint adding2q; // are we currently adding user input to q |
| @@ -298,7 +302,7 @@ struct globals { | |||
| 298 | 302 | ||
| 299 | static int init_text_buffer(char *); // init from file or create new | 303 | static int init_text_buffer(char *); // init from file or create new |
| 300 | static void edit_file(char *); // edit one file | 304 | static void edit_file(char *); // edit one file |
| 301 | static void do_cmd(char); // execute a command | 305 | static void do_cmd(int); // execute a command |
| 302 | static int next_tabstop(int); | 306 | static int next_tabstop(int); |
| 303 | static void sync_cursor(char *, int *, int *); // synchronize the screen cursor to dot | 307 | static void sync_cursor(char *, int *, int *); // synchronize the screen cursor to dot |
| 304 | static char *begin_line(char *); // return pointer to cur line B-o-l | 308 | static char *begin_line(char *); // return pointer to cur line B-o-l |
| @@ -334,8 +338,8 @@ static void rawmode(void); // set "raw" mode on tty | |||
| 334 | static void cookmode(void); // return to "cooked" mode on tty | 338 | static void cookmode(void); // return to "cooked" mode on tty |
| 335 | // sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready) | 339 | // sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready) |
| 336 | static int mysleep(int); | 340 | static int mysleep(int); |
| 337 | static char readit(void); // read (maybe cursor) key from stdin | 341 | static int readit(void); // read (maybe cursor) key from stdin |
| 338 | static char get_one_char(void); // read 1 char from stdin | 342 | static int get_one_char(void); // read 1 char from stdin |
| 339 | static int file_size(const char *); // what is the byte size of "fn" | 343 | static int file_size(const char *); // what is the byte size of "fn" |
| 340 | #if ENABLE_FEATURE_VI_READONLY | 344 | #if ENABLE_FEATURE_VI_READONLY |
| 341 | static int file_insert(const char *, char *, int); | 345 | static int file_insert(const char *, char *, int); |
| @@ -524,7 +528,7 @@ static void edit_file(char *fn) | |||
| 524 | #if ENABLE_FEATURE_VI_YANKMARK | 528 | #if ENABLE_FEATURE_VI_YANKMARK |
| 525 | #define cur_line edit_file__cur_line | 529 | #define cur_line edit_file__cur_line |
| 526 | #endif | 530 | #endif |
| 527 | char c; | 531 | int c; |
| 528 | int size; | 532 | int size; |
| 529 | #if ENABLE_FEATURE_VI_USE_SIGNALS | 533 | #if ENABLE_FEATURE_VI_USE_SIGNALS |
| 530 | int sig; | 534 | int sig; |
| @@ -622,8 +626,10 @@ static void edit_file(char *fn) | |||
| 622 | // These are commands that change text[]. | 626 | // These are commands that change text[]. |
| 623 | // Remember the input for the "." command | 627 | // Remember the input for the "." command |
| 624 | if (!adding2q && ioq_start == NULL | 628 | if (!adding2q && ioq_start == NULL |
| 625 | && cmd_mode == 0 /* command mode */ | 629 | && cmd_mode == 0 // command mode |
| 626 | && c != '\0' && strchr(modifying_cmds, c) | 630 | && c > '\0' // exclude NUL and non-ASCII chars |
| 631 | && c < 0x7f // (Unicode and such) | ||
| 632 | && strchr(modifying_cmds, c) | ||
| 627 | ) { | 633 | ) { |
| 628 | start_new_cmd_q(c); | 634 | start_new_cmd_q(c); |
| 629 | } | 635 | } |
| @@ -1198,7 +1204,7 @@ static void colon(char *buf) | |||
| 1198 | 1204 | ||
| 1199 | static void Hit_Return(void) | 1205 | static void Hit_Return(void) |
| 1200 | { | 1206 | { |
| 1201 | char c; | 1207 | int c; |
| 1202 | 1208 | ||
| 1203 | standout_start(); | 1209 | standout_start(); |
| 1204 | write1("[Hit return to continue]"); | 1210 | write1("[Hit return to continue]"); |
| @@ -2191,15 +2197,15 @@ static int mysleep(int hund) // sleep for 'h' 1/100 seconds | |||
| 2191 | } | 2197 | } |
| 2192 | 2198 | ||
| 2193 | //----- IO Routines -------------------------------------------- | 2199 | //----- IO Routines -------------------------------------------- |
| 2194 | static char readit(void) // read (maybe cursor) key from stdin | 2200 | static int readit(void) // read (maybe cursor) key from stdin |
| 2195 | { | 2201 | { |
| 2196 | char c; | 2202 | int c; |
| 2197 | int n; | 2203 | int n; |
| 2198 | 2204 | ||
| 2199 | // Known escape sequences for cursor and function keys. | 2205 | // Known escape sequences for cursor and function keys. |
| 2200 | static const struct esc_cmds { | 2206 | static const struct esc_cmds { |
| 2201 | const char seq[4]; | 2207 | const char seq[4]; |
| 2202 | char val; //TODO: int? Need to make it at least 8-bit clean! | 2208 | signed char val; |
| 2203 | } esccmds[] = { | 2209 | } esccmds[] = { |
| 2204 | {"OA" , VI_K_UP }, // Cursor Key Up | 2210 | {"OA" , VI_K_UP }, // Cursor Key Up |
| 2205 | {"OB" , VI_K_DOWN }, // Cursor Key Down | 2211 | {"OB" , VI_K_DOWN }, // Cursor Key Down |
| @@ -2256,7 +2262,7 @@ static char readit(void) // read (maybe cursor) key from stdin | |||
| 2256 | } | 2262 | } |
| 2257 | 2263 | ||
| 2258 | // Grab character to return from buffer | 2264 | // Grab character to return from buffer |
| 2259 | c = readbuffer[0]; | 2265 | c = (unsigned char)readbuffer[0]; |
| 2260 | // Returning NUL from this routine would be bad. | 2266 | // Returning NUL from this routine would be bad. |
| 2261 | if (c == '\0') | 2267 | if (c == '\0') |
| 2262 | c = ' '; | 2268 | c = ' '; |
| @@ -2302,7 +2308,7 @@ static char readit(void) // read (maybe cursor) key from stdin | |||
| 2302 | break; // try next seq | 2308 | break; // try next seq |
| 2303 | i++; | 2309 | i++; |
| 2304 | if (i == 4 || !eindex->seq[i]) { // entire seq matched | 2310 | if (i == 4 || !eindex->seq[i]) { // entire seq matched |
| 2305 | c = eindex->val; | 2311 | c = eindex->val; // sign extended! |
| 2306 | n = 0; | 2312 | n = 0; |
| 2307 | // n -= i; memmove(...); | 2313 | // n -= i; memmove(...); |
| 2308 | // would be more correct, | 2314 | // would be more correct, |
| @@ -2322,9 +2328,9 @@ static char readit(void) // read (maybe cursor) key from stdin | |||
| 2322 | } | 2328 | } |
| 2323 | 2329 | ||
| 2324 | //----- IO Routines -------------------------------------------- | 2330 | //----- IO Routines -------------------------------------------- |
| 2325 | static char get_one_char(void) | 2331 | static int get_one_char(void) |
| 2326 | { | 2332 | { |
| 2327 | char c; | 2333 | int c; |
| 2328 | 2334 | ||
| 2329 | #if ENABLE_FEATURE_VI_DOT_CMD | 2335 | #if ENABLE_FEATURE_VI_DOT_CMD |
| 2330 | if (!adding2q) { | 2336 | if (!adding2q) { |
| @@ -2335,7 +2341,8 @@ static char get_one_char(void) | |||
| 2335 | c = readit(); // get the users input | 2341 | c = readit(); // get the users input |
| 2336 | } else { | 2342 | } else { |
| 2337 | // there is a queue to get chars from first | 2343 | // there is a queue to get chars from first |
| 2338 | c = *ioq++; | 2344 | // careful with correct sign expansion! |
| 2345 | c = (unsigned char)*ioq++; | ||
| 2339 | if (c == '\0') { | 2346 | if (c == '\0') { |
| 2340 | // the end of the q, read from STDIN | 2347 | // the end of the q, read from STDIN |
| 2341 | free(ioq_start); | 2348 | free(ioq_start); |
| @@ -2365,7 +2372,7 @@ static char *get_input_line(const char *prompt) | |||
| 2365 | // char [MAX_INPUT_LEN] | 2372 | // char [MAX_INPUT_LEN] |
| 2366 | #define buf get_input_line__buf | 2373 | #define buf get_input_line__buf |
| 2367 | 2374 | ||
| 2368 | char c; | 2375 | int c; |
| 2369 | int i; | 2376 | int i; |
| 2370 | 2377 | ||
| 2371 | strcpy(buf, prompt); | 2378 | strcpy(buf, prompt); |
| @@ -2384,7 +2391,8 @@ static char *get_input_line(const char *prompt) | |||
| 2384 | write1("\b \b"); // erase char on screen | 2391 | write1("\b \b"); // erase char on screen |
| 2385 | if (i <= 0) // user backs up before b-o-l, exit | 2392 | if (i <= 0) // user backs up before b-o-l, exit |
| 2386 | break; | 2393 | break; |
| 2387 | } else { | 2394 | } else if (c > 0 && c < 256) { // exclude Unicode |
| 2395 | // (TODO: need to handle Unicode) | ||
| 2388 | buf[i] = c; | 2396 | buf[i] = c; |
| 2389 | buf[++i] = '\0'; | 2397 | buf[++i] = '\0'; |
| 2390 | bb_putchar(c); | 2398 | bb_putchar(c); |
| @@ -2987,13 +2995,14 @@ static void refresh(int full_screen) | |||
| 2987 | //--------------------------------------------------------------------- | 2995 | //--------------------------------------------------------------------- |
| 2988 | 2996 | ||
| 2989 | //----- Execute a Vi Command ----------------------------------- | 2997 | //----- Execute a Vi Command ----------------------------------- |
| 2990 | static void do_cmd(char c) | 2998 | static void do_cmd(int c) |
| 2991 | { | 2999 | { |
| 2992 | const char *msg = msg; // for compiler | 3000 | const char *msg = msg; // for compiler |
| 2993 | char c1, *p, *q, *save_dot; | 3001 | char *p, *q, *save_dot; |
| 2994 | char buf[12]; | 3002 | char buf[12]; |
| 2995 | int dir = dir; // for compiler | 3003 | int dir = dir; // for compiler |
| 2996 | int cnt, i, j; | 3004 | int cnt, i, j; |
| 3005 | int c1; | ||
| 2997 | 3006 | ||
| 2998 | // c1 = c; // quiet the compiler | 3007 | // c1 = c; // quiet the compiler |
| 2999 | // cnt = yf = 0; // quiet the compiler | 3008 | // cnt = yf = 0; // quiet the compiler |
| @@ -3173,21 +3182,18 @@ static void do_cmd(char c) | |||
| 3173 | break; | 3182 | break; |
| 3174 | #if ENABLE_FEATURE_VI_YANKMARK | 3183 | #if ENABLE_FEATURE_VI_YANKMARK |
| 3175 | case '"': // "- name a register to use for Delete/Yank | 3184 | case '"': // "- name a register to use for Delete/Yank |
| 3176 | c1 = get_one_char(); | 3185 | c1 = (get_one_char() | 0x20) - 'a'; // | 0x20 is tolower() |
| 3177 | c1 = tolower(c1); | 3186 | if ((unsigned)c1 <= 25) { // a-z? |
| 3178 | if (islower(c1)) { | 3187 | YDreg = c1; |
| 3179 | YDreg = c1 - 'a'; | ||
| 3180 | } else { | 3188 | } else { |
| 3181 | indicate_error(c); | 3189 | indicate_error(c); |
| 3182 | } | 3190 | } |
| 3183 | break; | 3191 | break; |
| 3184 | case '\'': // '- goto a specific mark | 3192 | case '\'': // '- goto a specific mark |
| 3185 | c1 = get_one_char(); | 3193 | c1 = (get_one_char() | 0x20) - 'a'; |
| 3186 | c1 = tolower(c1); | 3194 | if ((unsigned)c1 <= 25) { // a-z? |
| 3187 | if (islower(c1)) { | ||
| 3188 | c1 = c1 - 'a'; | ||
| 3189 | // get the b-o-l | 3195 | // get the b-o-l |
| 3190 | q = mark[(unsigned char) c1]; | 3196 | q = mark[c1]; |
| 3191 | if (text <= q && q < end) { | 3197 | if (text <= q && q < end) { |
| 3192 | dot = q; | 3198 | dot = q; |
| 3193 | dot_begin(); // go to B-o-l | 3199 | dot_begin(); // go to B-o-l |
| @@ -3206,12 +3212,10 @@ static void do_cmd(char c) | |||
| 3206 | // between text[0] and dot then this mark will not point to the | 3212 | // between text[0] and dot then this mark will not point to the |
| 3207 | // correct location! It could be off by many lines! | 3213 | // correct location! It could be off by many lines! |
| 3208 | // Well..., at least its quick and dirty. | 3214 | // Well..., at least its quick and dirty. |
| 3209 | c1 = get_one_char(); | 3215 | c1 = (get_one_char() | 0x20) - 'a'; |
| 3210 | c1 = tolower(c1); | 3216 | if ((unsigned)c1 <= 25) { // a-z? |
| 3211 | if (islower(c1)) { | ||
| 3212 | c1 = c1 - 'a'; | ||
| 3213 | // remember the line | 3217 | // remember the line |
| 3214 | mark[(int) c1] = dot; | 3218 | mark[c1] = dot; |
| 3215 | } else { | 3219 | } else { |
| 3216 | indicate_error(c); | 3220 | indicate_error(c); |
| 3217 | } | 3221 | } |
| @@ -3546,12 +3550,11 @@ static void do_cmd(char c) | |||
| 3546 | end_cmd_q(); // stop adding to q | 3550 | end_cmd_q(); // stop adding to q |
| 3547 | #endif | 3551 | #endif |
| 3548 | break; | 3552 | break; |
| 3549 | case 'g': // 'gg' goto a line number (from vim) | 3553 | case 'g': // 'gg' goto a line number (vim) (default: very first line) |
| 3550 | // (default to first line in file) | ||
| 3551 | c1 = get_one_char(); | 3554 | c1 = get_one_char(); |
| 3552 | if (c1 != 'g') { | 3555 | if (c1 != 'g') { |
| 3553 | buf[0] = 'g'; | 3556 | buf[0] = 'g'; |
| 3554 | buf[1] = c1; | 3557 | buf[1] = c1; // TODO: if Unicode? |
| 3555 | buf[2] = '\0'; | 3558 | buf[2] = '\0'; |
| 3556 | not_implemented(buf); | 3559 | not_implemented(buf); |
| 3557 | break; | 3560 | break; |
| @@ -3804,7 +3807,7 @@ static void do_cmd(char c) | |||
| 3804 | do_cmd(';'); | 3807 | do_cmd(';'); |
| 3805 | if (*dot == last_forward_char) | 3808 | if (*dot == last_forward_char) |
| 3806 | dot_left(); | 3809 | dot_left(); |
| 3807 | last_forward_char= 0; | 3810 | last_forward_char = 0; |
| 3808 | break; | 3811 | break; |
| 3809 | case 'w': // w- forward a word | 3812 | case 'w': // w- forward a word |
| 3810 | if (cmdcnt-- > 1) { | 3813 | if (cmdcnt-- > 1) { |
