Robert de Bath's implementation of ESC [ Z (backtab)
[u/mdw/putty] / terminal.c
index 9f623e5..f0dc9b1 100644 (file)
@@ -94,6 +94,7 @@ static int wrap, wrapnext;           /* wrap flags */
 static int insert;                    /* insert-mode flag */
 static int cset;                      /* 0 or 1: which char set */
 static int save_cset, save_csattr;     /* saved with cursor position */
+static int save_utf;                  /* saved with cursor position */
 static int rvideo;                    /* global reverse video flag */
 static int rvbell_timeout;            /* for ESC[?5hESC[?5l vbell */
 static int cursor_on;                 /* cursor enabled flag */
@@ -104,6 +105,7 @@ static int tblinker;                       /* When the blinking text is on */
 static int blink_is_real;             /* Actually blink blinking text */
 static int term_echoing;              /* Does terminal want local echo? */
 static int term_editing;              /* Does terminal want local edit? */
+static int sco_acs, save_sco_acs;      /* CSI 10,11,12m -> OEM charset */
 static int vt52_bold;                 /* Force bold on non-bold colours */
 static int utf_state;                 /* Is there a pending UTF-8 character */
 static int utf_char;                  /* and what is it so far. */
@@ -116,7 +118,7 @@ static unsigned long cset_attr[2];
 /*
  * Saved settings on the alternate screen.
  */
-static int alt_x, alt_y, alt_om, alt_wrap, alt_wnext, alt_ins, alt_cset;
+static int alt_x, alt_y, alt_om, alt_wrap, alt_wnext, alt_ins, alt_cset, alt_sco_acs, alt_utf;
 static int alt_t, alt_b;
 static int alt_which;
 
@@ -252,6 +254,7 @@ unsigned long *lineptr(int y, int lineno)
     if (newline != line) {
        delpos234(whichtree, treeindex);
        addpos234(whichtree, newline, treeindex);
+        line = newline;
     }
 
     return line + 1;
@@ -278,6 +281,8 @@ static void power_on(void)
     alt_wnext = wrapnext = alt_ins = insert = FALSE;
     alt_wrap = wrap = cfg.wrap_mode;
     alt_cset = cset = 0;
+    alt_utf = utf = 0;
+    alt_sco_acs = sco_acs = 0;
     cset_attr[0] = cset_attr[1] = ATTR_ASCII;
     rvideo = 0;
     in_vbell = FALSE;
@@ -536,6 +541,12 @@ static void swap_screen(int which)
     t = cset;
     cset = alt_cset;
     alt_cset = t;
+    t = utf;
+    utf = alt_utf;
+    alt_utf = t;
+    t = sco_acs;
+    sco_acs = alt_sco_acs;
+    alt_sco_acs = t;
 
     fix_cpos;
 }
@@ -689,7 +700,9 @@ static void save_cursor(int save)
        savecurs = curs;
        save_attr = curr_attr;
        save_cset = cset;
+       save_utf = utf;
        save_csattr = cset_attr[cset];
+       save_sco_acs = sco_acs;
     } else {
        curs = savecurs;
        /* Make sure the window hasn't shrunk since the save */
@@ -700,10 +713,13 @@ static void save_cursor(int save)
 
        curr_attr = save_attr;
        cset = save_cset;
+       utf = save_utf;
        cset_attr[cset] = save_csattr;
+       sco_acs = save_sco_acs;
        fix_cpos;
        if (use_bce)
-           erase_char = (' ' | (curr_attr & (ATTR_FGMASK | ATTR_BGMASK)));
+           erase_char = (' ' | ATTR_ASCII |
+                        (curr_attr & (ATTR_FGMASK | ATTR_BGMASK)));
     }
 }
 
@@ -934,18 +950,15 @@ void term_out(void)
 
        /* First see about all those translations. */
        if (termstate == TOPLEVEL) {
-           if (utf)
+           if (in_utf)
                switch (utf_state) {
                  case 0:
                    if (c < 0x80) {
-                       /* I know; gotos are evil. This one is really bad!
-                        * But before you try removing it follow the path of the
-                        * sequence "0x5F 0xC0 0x71" with UTF and VTGraphics on.
-                        */
-                       /*
-                          if (cfg.no_vt_graph_with_utf8) break;
-                        */
-                       goto evil_jump;
+                       /* UTF-8 must be stateless so we ignore iso2022. */
+                       if (unitab_ctrl[c] != 0xFF) 
+                            c = unitab_ctrl[c];
+                       else c = ((unsigned char)c) | ATTR_ASCII;
+                       break;
                    } else if ((c & 0xe0) == 0xc0) {
                        utf_size = utf_state = 1;
                        utf_char = (c & 0x1f);
@@ -1024,8 +1037,14 @@ void term_out(void)
                    if (c >= 0x10000)
                        c = 0xFFFD;
                    break;
+           }
+           /* Are we in the nasty ACS mode? Note: no sco in utf mode. */
+           else if(sco_acs && 
+                   (c!='\033' && c!='\n' && c!='\r' && c!='\b'))
+           {
+              if (sco_acs == 2) c ^= 0x80;
+              c |= ATTR_SCOACS;
            } else {
-             evil_jump:;
                switch (cset_attr[cset]) {
                    /* 
                     * Linedraw characters are different from 'ESC ( B'
@@ -1052,6 +1071,9 @@ void term_out(void)
                    else
                        c = ((unsigned char) c) | ATTR_ASCII;
                    break;
+               case ATTR_SCOACS:
+                   if (c>=' ') c = ((unsigned char)c) | ATTR_SCOACS;
+                   break;
                }
            }
        }
@@ -1483,6 +1505,10 @@ void term_out(void)
                    compatibility(VT100);
                    cset_attr[0] = ATTR_LINEDRW;
                    break;
+                 case ANSI('U', '('): 
+                   compatibility(OTHER);
+                   cset_attr[0] = ATTR_SCOACS; 
+                   break;
 
                  case ANSI('A', ')'):
                    compatibility(VT100);
@@ -1496,6 +1522,10 @@ void term_out(void)
                    compatibility(VT100);
                    cset_attr[1] = ATTR_LINEDRW;
                    break;
+                 case ANSI('U', ')'): 
+                   compatibility(OTHER);
+                   cset_attr[1] = ATTR_SCOACS; 
+                   break;
 
                  case ANSI('8', '%'):  /* Old Linux code */
                  case ANSI('G', '%'):
@@ -1504,8 +1534,7 @@ void term_out(void)
                    break;
                  case ANSI('@', '%'):
                    compatibility(OTHER);
-                   if (line_codepage != CP_UTF8)
-                       utf = 0;
+                   utf = 0;
                    break;
                }
                break;
@@ -1763,6 +1792,15 @@ void term_out(void)
                                  case 7:       /* enable reverse video */
                                    curr_attr |= ATTR_REVERSE;
                                    break;
+                                 case 10:      /* SCO acs off */
+                                   compatibility(SCOANSI);
+                                   sco_acs = 0; break;
+                                 case 11:      /* SCO acs on */
+                                   compatibility(SCOANSI);
+                                   sco_acs = 1; break;
+                                 case 12:      /* SCO acs on flipped */
+                                   compatibility(SCOANSI);
+                                   sco_acs = 2; break;
                                  case 22:      /* disable bold */
                                    compatibility2(OTHER, VT220);
                                    curr_attr &= ~ATTR_BOLD;
@@ -1816,11 +1854,9 @@ void term_out(void)
                                }
                            }
                            if (use_bce)
-                               erase_char =
-                                   (' ' |
-                                    (curr_attr &
-                                     (ATTR_FGMASK | ATTR_BGMASK |
-                                      ATTR_BLINK)));
+                               erase_char = (' ' | ATTR_ASCII |
+                                            (curr_attr & 
+                                             (ATTR_FGMASK | ATTR_BGMASK)));
                        }
                        break;
                      case 's':       /* save cursor */
@@ -1913,15 +1949,29 @@ void term_out(void)
                            }
                        }
                        break;
+                     case 'Z':         /* BackTab for xterm */
+                       compatibility(OTHER);
+                       {
+                           int i = def(esc_args[0], 1);
+                           pos old_curs = curs;
+
+                           for(;i>0 && curs.x>0; i--) {
+                               do {
+                                   curs.x--;
+                               } while (curs.x >0 && !tabs[curs.x]);
+                           }
+                           fix_cpos;
+                           check_selection(old_curs, curs);
+                       }
+                       break;
                      case ANSI('L', '='):
                        compatibility(OTHER);
                        use_bce = (esc_args[0] <= 0);
                        erase_char = ERASE_CHAR;
                        if (use_bce)
-                           erase_char =
-                               (' ' |
-                                (curr_attr &
-                                 (ATTR_FGMASK | ATTR_BGMASK)));
+                           erase_char = (' ' | ATTR_ASCII |
+                                        (curr_attr & 
+                                         (ATTR_FGMASK | ATTR_BGMASK)));
                        break;
                      case ANSI('E', '='):
                        compatibility(OTHER);
@@ -2313,10 +2363,9 @@ void term_out(void)
                    vt52_bold = FALSE;
                    curr_attr = ATTR_DEFAULT;
                    if (use_bce)
-                       erase_char = (' ' |
-                                     (curr_attr &
-                                      (ATTR_FGMASK | ATTR_BGMASK |
-                                       ATTR_BLINK)));
+                       erase_char = (' ' | ATTR_ASCII |
+                                    (curr_attr & 
+                                     (ATTR_FGMASK | ATTR_BGMASK)));
                    break;
                  case 'S':
                    /* compatibility(VI50) */
@@ -2358,10 +2407,8 @@ void term_out(void)
                    curr_attr |= ATTR_BOLD;
 
                if (use_bce)
-                   erase_char = (' ' |
-                                 (curr_attr &
-                                  (ATTR_FGMASK | ATTR_BGMASK |
-                                   ATTR_BLINK)));
+                   erase_char = (' ' | ATTR_ASCII |
+                                (curr_attr & (ATTR_FGMASK | ATTR_BGMASK)));
                break;
              case VT52_BG:
                termstate = TOPLEVEL;
@@ -2374,10 +2421,8 @@ void term_out(void)
                    curr_attr |= ATTR_BLINK;
 
                if (use_bce)
-                   erase_char = (' ' |
-                                 (curr_attr &
-                                  (ATTR_FGMASK | ATTR_BGMASK |
-                                   ATTR_BLINK)));
+                   erase_char = (' ' | ATTR_ASCII |
+                                (curr_attr & (ATTR_FGMASK | ATTR_BGMASK)));
                break;
 #endif
              default: break;          /* placate gcc warning about enum use */
@@ -2499,6 +2544,9 @@ static void do_paint(Context ctx, int may_optimise)
              case ATTR_LINEDRW:
                tchar = unitab_xterm[tchar & 0xFF];
                break;
+             case ATTR_SCOACS:  
+               tchar = unitab_scoacs[tchar&0xFF]; 
+               break;
            }
            tattr |= (tchar & CSET_MASK);
            tchar &= CHAR_MASK;
@@ -2733,6 +2781,9 @@ static void clipme(pos top, pos bottom)
              case ATTR_ASCII:
                uc = unitab_line[uc & 0xFF];
                break;
+             case ATTR_SCOACS:  
+               uc = unitab_scoacs[uc&0xFF]; 
+               break;
            }
            switch (uc & CSET_MASK) {
              case ATTR_ACP:
@@ -2893,6 +2944,9 @@ static int wordtype(int uc)
       case ATTR_ASCII:
        uc = unitab_line[uc & 0xFF];
        break;
+      case ATTR_SCOACS:  
+       uc = unitab_scoacs[uc&0xFF]; 
+       break;
     }
     switch (uc & CSET_MASK) {
       case ATTR_ACP: