vi: handle chars 0x80, 0x81... correctly
authorDenis Vlasenko <vda.linux@googlemail.com>
Mon, 20 Oct 2008 08:59:03 +0000 (08:59 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Mon, 20 Oct 2008 08:59:03 +0000 (08:59 -0000)
editors/vi.c

index 50dda7f3ae0a47804d561b8c077d411fc7d133a8..55154dcd7da18fd9a0cdc520f8e192b2a02a49ac 100644 (file)
@@ -57,29 +57,33 @@ enum {
        MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN,
 };
 
-// Misc. non-Ascii keys that report an escape sequence
-#define VI_K_UP                        (char)128       // cursor key Up
-#define VI_K_DOWN              (char)129       // cursor key Down
-#define VI_K_RIGHT             (char)130       // Cursor Key Right
-#define VI_K_LEFT              (char)131       // cursor key Left
-#define VI_K_HOME              (char)132       // Cursor Key Home
-#define VI_K_END               (char)133       // Cursor Key End
-#define VI_K_INSERT            (char)134       // Cursor Key Insert
-#define VI_K_DELETE            (char)135       // Cursor Key Insert
-#define VI_K_PAGEUP            (char)136       // Cursor Key Page Up
-#define VI_K_PAGEDOWN          (char)137       // Cursor Key Page Down
-#define VI_K_FUN1              (char)138       // Function Key F1
-#define VI_K_FUN2              (char)139       // Function Key F2
-#define VI_K_FUN3              (char)140       // Function Key F3
-#define VI_K_FUN4              (char)141       // Function Key F4
-#define VI_K_FUN5              (char)142       // Function Key F5
-#define VI_K_FUN6              (char)143       // Function Key F6
-#define VI_K_FUN7              (char)144       // Function Key F7
-#define VI_K_FUN8              (char)145       // Function Key F8
-#define VI_K_FUN9              (char)146       // Function Key F9
-#define VI_K_FUN10             (char)147       // Function Key F10
-#define VI_K_FUN11             (char)148       // Function Key F11
-#define VI_K_FUN12             (char)149       // Function Key F12
+// "Keycodes" that report an escape sequence.
+// We use something which fits into signed char,
+// yet doesn't represent any valid Unicode characher.
+enum {
+       VI_K_UP       = -1,     // cursor key Up
+       VI_K_DOWN     = -2,     // cursor key Down
+       VI_K_RIGHT    = -3,     // Cursor Key Right
+       VI_K_LEFT     = -4,     // cursor key Left
+       VI_K_HOME     = -5,     // Cursor Key Home
+       VI_K_END      = -6,     // Cursor Key End
+       VI_K_INSERT   = -7,     // Cursor Key Insert
+       VI_K_DELETE   = -8,     // Cursor Key Insert
+       VI_K_PAGEUP   = -9,     // Cursor Key Page Up
+       VI_K_PAGEDOWN = -10,    // Cursor Key Page Down
+       VI_K_FUN1     = -11,    // Function Key F1
+       VI_K_FUN2     = -12,    // Function Key F2
+       VI_K_FUN3     = -13,    // Function Key F3
+       VI_K_FUN4     = -14,    // Function Key F4
+       VI_K_FUN5     = -15,    // Function Key F5
+       VI_K_FUN6     = -16,    // Function Key F6
+       VI_K_FUN7     = -17,    // Function Key F7
+       VI_K_FUN8     = -18,    // Function Key F8
+       VI_K_FUN9     = -19,    // Function Key F9
+       VI_K_FUN10    = -20,    // Function Key F10
+       VI_K_FUN11    = -21,    // Function Key F11
+       VI_K_FUN12    = -22,    // Function Key F12
+};
 
 /* vt102 typical ESC sequence */
 /* terminal standout start/normal ESC sequence */
@@ -171,9 +175,9 @@ struct globals {
        char *screen;            // pointer to the virtual screen buffer
        int screensize;          //            and its size
        int tabstop;
+       int last_forward_char;   // last char searched for with 'f' (int because of Unicode)
        char erase_char;         // the users erase character
        char last_input_char;    // last char read from user
-       char last_forward_char;  // last char searched for with 'f'
 
 #if ENABLE_FEATURE_VI_DOT_CMD
        smallint adding2q;       // are we currently adding user input to q
@@ -298,7 +302,7 @@ struct globals {
 
 static int init_text_buffer(char *); // init from file or create new
 static void edit_file(char *); // edit one file
-static void do_cmd(char);      // execute a command
+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
 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
 static void cookmode(void);    // return to "cooked" mode on tty
 // sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready)
 static int mysleep(int);
-static char readit(void);      // read (maybe cursor) key from stdin
-static char get_one_char(void);        // read 1 char from stdin
+static int readit(void);       // read (maybe cursor) key from stdin
+static int get_one_char(void); // read 1 char from stdin
 static int file_size(const char *);   // what is the byte size of "fn"
 #if ENABLE_FEATURE_VI_READONLY
 static int file_insert(const char *, char *, int);
@@ -524,7 +528,7 @@ static void edit_file(char *fn)
 #if ENABLE_FEATURE_VI_YANKMARK
 #define cur_line edit_file__cur_line
 #endif
-       char c;
+       int c;
        int size;
 #if ENABLE_FEATURE_VI_USE_SIGNALS
        int sig;
@@ -622,8 +626,10 @@ static void edit_file(char *fn)
                // These are commands that change text[].
                // Remember the input for the "." command
                if (!adding2q && ioq_start == NULL
-                && cmd_mode == 0 /* command mode */
-                && c != '\0' && strchr(modifying_cmds, c)
+                && cmd_mode == 0 // command mode
+                && c > '\0' // exclude NUL and non-ASCII chars
+                && c < 0x7f // (Unicode and such)
+                && strchr(modifying_cmds, c)
                ) {
                        start_new_cmd_q(c);
                }
@@ -1198,7 +1204,7 @@ static void colon(char *buf)
 
 static void Hit_Return(void)
 {
-       char c;
+       int c;
 
        standout_start();
        write1("[Hit return to continue]");
@@ -2191,15 +2197,15 @@ static int mysleep(int hund)    // sleep for 'h' 1/100 seconds
 }
 
 //----- IO Routines --------------------------------------------
-static char readit(void)       // read (maybe cursor) key from stdin
+static int readit(void) // read (maybe cursor) key from stdin
 {
-       char c;
+       int c;
        int n;
 
        // Known escape sequences for cursor and function keys.
        static const struct esc_cmds {
                const char seq[4];
-               char val; //TODO: int? Need to make it at least 8-bit clean!
+               signed char val;
        } esccmds[] = {
                {"OA"  , VI_K_UP      },   // Cursor Key Up
                {"OB"  , VI_K_DOWN    },   // Cursor Key Down
@@ -2256,7 +2262,7 @@ static char readit(void)  // read (maybe cursor) key from stdin
        }
 
        // Grab character to return from buffer
-       c = readbuffer[0];
+       c = (unsigned char)readbuffer[0];
        // Returning NUL from this routine would be bad.
        if (c == '\0')
                c = ' ';
@@ -2302,7 +2308,7 @@ static char readit(void)  // read (maybe cursor) key from stdin
                                        break; // try next seq
                                i++;
                                if (i == 4 || !eindex->seq[i]) { // entire seq matched
-                                       c = eindex->val;
+                                       c = eindex->val; // sign extended!
                                        n = 0;
                                        // n -= i; memmove(...);
                                        // would be more correct,
@@ -2322,9 +2328,9 @@ static char readit(void)  // read (maybe cursor) key from stdin
 }
 
 //----- IO Routines --------------------------------------------
-static char get_one_char(void)
+static int get_one_char(void)
 {
-       char c;
+       int c;
 
 #if ENABLE_FEATURE_VI_DOT_CMD
        if (!adding2q) {
@@ -2335,7 +2341,8 @@ static char get_one_char(void)
                        c = readit();   // get the users input
                } else {
                        // there is a queue to get chars from first
-                       c = *ioq++;
+                       // careful with correct sign expansion!
+                       c = (unsigned char)*ioq++;
                        if (c == '\0') {
                                // the end of the q, read from STDIN
                                free(ioq_start);
@@ -2365,7 +2372,7 @@ static char *get_input_line(const char *prompt)
        // char [MAX_INPUT_LEN]
 #define buf get_input_line__buf
 
-       char c;
+       int c;
        int i;
 
        strcpy(buf, prompt);
@@ -2384,7 +2391,8 @@ static char *get_input_line(const char *prompt)
                        write1("\b \b"); // erase char on screen
                        if (i <= 0) // user backs up before b-o-l, exit
                                break;
-               } else {
+               } else if (c > 0 && c < 256) { // exclude Unicode
+                       // (TODO: need to handle Unicode)
                        buf[i] = c;
                        buf[++i] = '\0';
                        bb_putchar(c);
@@ -2987,13 +2995,14 @@ static void refresh(int full_screen)
 //---------------------------------------------------------------------
 
 //----- Execute a Vi Command -----------------------------------
-static void do_cmd(char c)
+static void do_cmd(int c)
 {
        const char *msg = msg; // for compiler
-       char c1, *p, *q, *save_dot;
+       char *p, *q, *save_dot;
        char buf[12];
        int dir = dir; // for compiler
        int cnt, i, j;
+       int c1;
 
 //     c1 = c; // quiet the compiler
 //     cnt = yf = 0; // quiet the compiler
@@ -3173,21 +3182,18 @@ static void do_cmd(char c)
                break;
 #if ENABLE_FEATURE_VI_YANKMARK
        case '"':                       // "- name a register to use for Delete/Yank
-               c1 = get_one_char();
-               c1 = tolower(c1);
-               if (islower(c1)) {
-                       YDreg = c1 - 'a';
+               c1 = (get_one_char() | 0x20) - 'a'; // | 0x20 is tolower()
+               if ((unsigned)c1 <= 25) { // a-z?
+                       YDreg = c1;
                } else {
                        indicate_error(c);
                }
                break;
        case '\'':                      // '- goto a specific mark
-               c1 = get_one_char();
-               c1 = tolower(c1);
-               if (islower(c1)) {
-                       c1 = c1 - 'a';
+               c1 = (get_one_char() | 0x20) - 'a';
+               if ((unsigned)c1 <= 25) { // a-z?
                        // get the b-o-l
-                       q = mark[(unsigned char) c1];
+                       q = mark[c1];
                        if (text <= q && q < end) {
                                dot = q;
                                dot_begin();    // go to B-o-l
@@ -3206,12 +3212,10 @@ static void do_cmd(char c)
                // between text[0] and dot then this mark will not point to the
                // correct location! It could be off by many lines!
                // Well..., at least its quick and dirty.
-               c1 = get_one_char();
-               c1 = tolower(c1);
-               if (islower(c1)) {
-                       c1 = c1 - 'a';
+               c1 = (get_one_char() | 0x20) - 'a';
+               if ((unsigned)c1 <= 25) { // a-z?
                        // remember the line
-                       mark[(int) c1] = dot;
+                       mark[c1] = dot;
                } else {
                        indicate_error(c);
                }
@@ -3546,12 +3550,11 @@ static void do_cmd(char c)
                        end_cmd_q();    // stop adding to q
 #endif
                break;
-       case 'g':                       // 'gg' goto a line number (from vim)
-                                       // (default to first line in file)
+       case 'g': // 'gg' goto a line number (vim) (default: very first line)
                c1 = get_one_char();
                if (c1 != 'g') {
                        buf[0] = 'g';
-                       buf[1] = c1;
+                       buf[1] = c1; // TODO: if Unicode?
                        buf[2] = '\0';
                        not_implemented(buf);
                        break;
@@ -3804,7 +3807,7 @@ static void do_cmd(char c)
                do_cmd(';');
                if (*dot == last_forward_char)
                        dot_left();
-               last_forward_char= 0;
+               last_forward_char = 0;
                break;
        case 'w':                       // w- forward a word
                if (cmdcnt-- > 1) {