Factor out the ANSI engine from the ANSI and VESA consoles
authorH. Peter Anvin <hpa@zytor.com>
Mon, 11 Sep 2006 01:03:06 +0000 (18:03 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Mon, 11 Sep 2006 01:03:06 +0000 (18:03 -0700)
In preparation for the VESA console needing to fall back to text mode...

com32/lib/Makefile
com32/lib/sys/ansi.c [new file with mode: 0644]
com32/lib/sys/ansi.h [new file with mode: 0644]
com32/lib/sys/ansicon_write.c
com32/lib/sys/vesa/background.c
com32/lib/sys/vesa/drawtxt.c
com32/lib/sys/vesa/video.h
com32/lib/sys/vesacon_write.c

index d84b7c6..53a8bdb 100644 (file)
@@ -36,6 +36,8 @@ LIBOBJS = \
        \
        sys/xserial_write.o                                             \
        \
+       sys/ansi.o                                                      \
+       \
        sys/ansicon_write.o sys/ansiserial_write.o                      \
        \
        sys/vesacon_write.o sys/vesaserial_write.o                      \
diff --git a/com32/lib/sys/ansi.c b/com32/lib/sys/ansi.c
new file mode 100644 (file)
index 0000000..244b627
--- /dev/null
@@ -0,0 +1,434 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2006 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * ansi.c
+ *
+ * ANSI character code engine
+ */
+
+#include <string.h>
+#include <colortbl.h>
+#include "ansi.h"
+
+static const struct term_state default_state =
+{
+  .xy = { 0, 0 },
+  .cindex = 0,                 /* First color table entry */
+  .vtgraphics = 0,
+  .intensity = 1,
+  .underline = 0,
+  .blink = 0,
+  .reverse = 0,
+  .fg = 7,
+  .bg = 0,
+  .autocr = 0,
+  .saved_xy = { 0, 0 },
+  .cursor_type = 0x0607,
+  .state = st_init,
+  .pvt = 0,
+  .nparms = 0,
+  .xy = { 0, 0 },
+};
+
+/* DEC VT graphics to codepage 437 table (characters 0x60-0x7F only) */
+static const char decvt_to_cp437[] =
+  {
+    0004, 0261, 0007, 0007, 0007, 0007, 0370, 0361,
+    0007, 0007, 0331, 0277, 0332, 0300, 0305, 0304,
+    0304, 0304, 0137, 0137, 0303, 0264, 0301, 0302,
+    0263, 0363, 0362, 0343, 0330, 0234, 0007, 00
+  };
+
+void __ansi_init(const struct term_info *ti)
+{
+  memcpy(ti->ts, &default_state, sizeof default_state);
+}
+
+void __ansi_putchar(const struct term_info *ti, uint8_t ch)
+{
+  const struct ansi_ops *op = ti->op;
+  struct term_state *st = ti->ts;
+  const int rows  = ti->rows;
+  const int cols  = ti->cols;
+  struct curxy xy = st->xy;
+
+  switch ( st->state ) {
+  case st_init:
+    switch ( ch ) {
+    case 1:
+      st->state = st_soh;
+      break;
+    case '\b':
+      if ( xy.x > 0 ) xy.x--;
+      break;
+    case '\t':
+      {
+       int nsp = 8 - (xy.x & 7);
+       while ( nsp-- )
+         __ansi_putchar(ti, ' ');
+      }
+      return;                  /* Cursor already updated */
+    case '\n':
+    case '\v':
+    case '\f':
+      xy.y++;
+      if ( st->autocr )
+       xy.x = 0;
+      break;
+    case '\r':
+      xy.x = 0;
+      break;
+    case 127:
+      /* Ignore delete */
+      break;
+    case 14:
+      st->vtgraphics = 1;
+      break;
+    case 15:
+      st->vtgraphics = 0;
+      break;
+    case 27:
+      st->state = st_esc;
+      break;
+    default:
+      /* Print character */
+      if ( ch >= 32 ) {
+       if ( st->vtgraphics && (ch & 0xe0) == 0x60 )
+         ch = decvt_to_cp437[ch - 0x60];
+
+       op->write_char(xy.x, xy.y, ch, st);
+       xy.x++;
+      }
+      break;
+    }
+    break;
+
+  case st_esc:
+    switch ( ch ) {
+    case '%':
+    case '(':
+    case ')':
+    case '#':
+      /* Ignore this plus the subsequent character, allows
+        compatibility with Linux sequence to set charset */
+      break;
+    case '[':
+      st->state = st_csi;
+      st->nparms = st->pvt = 0;
+      memset(st->parms, 0, sizeof st->parms);
+      break;
+    case 'c':
+      /* Reset terminal */
+      memcpy(&st, &default_state, sizeof st);
+      op->erase(st, 0, 0, cols-1, rows-1);
+      xy.x = xy.y = 0;
+      st->state = st_init;
+      break;
+    default:
+      /* Ignore sequence */
+      st->state = st_init;
+      break;
+    }
+    break;
+
+  case st_csi:
+    {
+      int p0 = st->parms[0] ? st->parms[0] : 1;
+
+      if ( ch >= '0' && ch <= '9' ) {
+       st->parms[st->nparms] = st->parms[st->nparms]*10 + (ch-'0');
+      } else if ( ch == ';' ) {
+       st->nparms++;
+       if ( st->nparms >= ANSI_MAX_PARMS )
+         st->nparms = ANSI_MAX_PARMS-1;
+       break;
+      } else if ( ch == '?' ) {
+       st->pvt = 1;
+      } else {
+       switch ( ch ) {
+       case 'A':
+         {
+           int y = xy.y - p0;
+           xy.y = (y < 0) ? 0 : y;
+         }
+         break;
+       case 'B':
+         {
+           int y = xy.y + p0;
+           xy.y = (y >= rows) ? rows-1 : y;
+         }
+         break;
+       case 'C':
+         {
+           int x = xy.x + p0;
+           xy.x = (x >= cols) ? cols-1 : x;
+         }
+         break;
+       case 'D':
+         {
+           int x = xy.x - p0;
+           xy.x = (x < 0) ? 0 : x;
+         }
+         break;
+       case 'E':
+         {
+           int y = xy.y + p0;
+           xy.y = (y >= rows) ? rows-1 : y;
+           xy.x = 0;
+         }
+         break;
+       case 'F':
+         {
+           int y = xy.y - p0;
+           xy.y = (y < 0) ? 0 : y;
+           xy.x = 0;
+         }
+         break;
+       case 'G':
+       case '\'':
+         {
+           int x = st->parms[0] - 1;
+           xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x;
+         }
+         break;
+       case 'H':
+       case 'f':
+         {
+           int y = st->parms[0] - 1;
+           int x = st->parms[1] - 1;
+
+           xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x;
+           xy.y = (y >= rows) ? rows-1 : (y < 0) ? 0 : y;
+         }
+         break;
+       case 'J':
+         {
+           switch ( st->parms[0] ) {
+           case 0:
+             op->erase(st, xy.x, xy.y, cols-1, xy.y);
+             if ( xy.y < rows-1 )
+               op->erase(st, 0, xy.y+1, cols-1, rows-1);
+             break;
+
+           case 1:
+             if ( xy.y > 0 )
+               op->erase(st, 0, 0, cols-1, xy.y-1);
+             if ( xy.y > 0 )
+               op->erase(st, 0, xy.y, xy.x-1, xy.y);
+             break;
+
+           case 2:
+             op->erase(st, 0, 0, cols-1, rows-1);
+             break;
+
+           default:
+             /* Ignore */
+             break;
+           }
+         }
+         break;
+       case 'K':
+         {
+           switch ( st->parms[0] ) {
+           case 0:
+             op->erase(st, xy.x, xy.y, cols-1, xy.y);
+             break;
+
+           case 1:
+             if ( xy.x > 0 )
+               op->erase(st, 0, xy.y, xy.x-1, xy.y);
+             break;
+
+           case 2:
+             op->erase(st, 0, xy.y, cols-1, xy.y);
+             break;
+
+           default:
+             /* Ignore */
+             break;
+           }
+         }
+         break;
+       case 'h':
+       case 'l':
+         {
+           int set = (ch == 'h');
+           switch ( st->parms[0] ) {
+           case 20:
+             st->autocr = set;
+             break;
+           case 25:
+             op->showcursor(st, set);
+             break;
+           default:
+             /* Ignore */
+             break;
+           }
+         }
+         break;
+       case 'm':
+         {
+           static const int ansi2pc[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
+           int i;
+           for ( i = 0 ; i <= st->nparms ; i++ ) {
+             int a = st->parms[i];
+             switch ( a ) {
+             case 0:
+               st->fg = 7;
+               st->bg = 0;
+               st->intensity = 1;
+               st->underline = 0;
+               st->blink = 0;
+               st->reverse = 0;
+               break;
+             case 1:
+               st->intensity = 2;
+               break;
+             case 2:
+               st->intensity = 0;
+               break;
+             case 4:
+               st->underline = 1;
+               break;
+             case 5:
+               st->blink = 1;
+               break;
+             case 7:
+               st->reverse = 1;
+               break;
+             case 21:
+             case 22:
+               st->intensity = 1;
+               break;
+             case 24:
+               st->underline = 0;
+               break;
+             case 25:
+               st->blink = 0;
+               break;
+             case 27:
+               st->reverse = 0;
+               break;
+             case 30 ... 37:
+               st->fg = ansi2pc[a-30];
+               break;
+             case 38:
+               st->fg = 7;
+               st->underline = 1;
+               break;
+             case 39:
+               st->fg = 7;
+               st->underline = 0;
+               break;
+             case 40 ... 47:
+               st->bg = ansi2pc[a-40];
+               break;
+             case 49:
+               st->bg = 7;
+               break;
+             default:
+               /* Do nothing */
+               break;
+             }
+           }
+         }
+         break;
+       case 's':
+         st->saved_xy = xy;
+         break;
+       case 'u':
+         xy = st->saved_xy;
+         break;
+       default:                /* Includes CAN and SUB */
+         break;                /* Drop unknown sequence */
+       }
+       st->state = st_init;
+      }
+    }
+    break;
+
+  case st_soh:
+    if ( ch == '#' )
+      st->state = st_sohc;
+    else
+      st->state = st_init;
+    break;
+
+  case st_sohc:
+    {
+      int n = (unsigned char)ch - '0';
+      if (n < 10) {
+       st->parms[0] = n*10;
+       st->state = st_sohc1;
+      } else {
+       st->state = st_init;
+      }
+    }
+    break;
+
+  case st_sohc1:
+    {
+      int n = (unsigned char)ch - '0';
+      const char *p;
+
+      if (n < 10) {
+       st->parms[0] += n;
+       if (st->parms[0] < console_color_table_size) {
+         /* Set the color table index */
+         st->cindex = st->parms[0];
+
+         /* See if there are any other attributes we care about */
+         p = console_color_table[st->parms[0]].ansi;
+         st->state = st_esc;
+         __ansi_putchar(ti, '[');
+         while (*p)
+           __ansi_putchar(ti, *p++);
+         __ansi_putchar(ti, 'm');
+       }
+      }
+
+      st->state = st_init;
+    }
+    break;
+  }
+
+  /* If we fell off the end of the screen, adjust */
+  if ( xy.x >= cols ) {
+    xy.x = 0;
+    xy.y++;
+  }
+  while ( xy.y >= rows ) {
+    xy.y--;
+    op->scroll_up(st);
+  }
+
+  /* Update cursor position */
+  op->set_cursor(xy.x, xy.y);
+  st->xy = xy;
+}
diff --git a/com32/lib/sys/ansi.h b/com32/lib/sys/ansi.h
new file mode 100644 (file)
index 0000000..f4074c2
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * ansi.h
+ */
+
+#ifndef COM32_LIB_SYS_ANSI_H
+#define COM32_LIB_SYS_ANSI_H
+
+#include <inttypes.h>
+
+#define ANSI_MAX_PARMS 16
+
+enum ansi_state {
+  st_init,
+  st_esc,
+  st_csi,
+  st_soh,
+  st_sohc,
+  st_sohc1,
+};
+
+struct curxy {
+  uint8_t x, y;
+} __attribute__((packed));
+
+struct term_state {
+  struct curxy xy;
+  int attr;                    /* Current display attribute */
+  int cindex;                  /* SOH color index */
+  int vtgraphics;              /* VT graphics on/off */
+  int intensity;
+  int underline;
+  int blink;
+  int reverse;
+  int fg;
+  int bg;
+  int autocr;
+  struct curxy saved_xy;
+  uint16_t cursor_type;
+  enum ansi_state state;
+  int pvt;                     /* Private code? */
+  int nparms;                  /* Number of parameters seen */
+  int parms[ANSI_MAX_PARMS];
+};
+
+
+struct ansi_ops {
+  void (*erase)(const struct term_state *st, int x0, int y0, int x1, int y1);
+  void (*write_char)(int x, int y, uint8_t ch, const struct term_state *st);
+  void (*showcursor)(const struct term_state *st, int);
+  void (*scroll_up)(const struct term_state *st);
+  void (*set_cursor)(int x, int y);
+};
+
+struct term_info {
+  int rows, cols;              /* Screen size */
+  int disabled;
+  struct term_state *ts;
+  const struct ansi_ops *op;
+};
+
+void __ansi_init(const struct term_info *ti);
+void __ansi_putchar(const struct term_info *ti, uint8_t ch);
+
+#endif /* COM32_LIB_SYS_ANSI_H */
index 594a01f..e3fb0ec 100644 (file)
 #include <colortbl.h>
 #include <klibc/compiler.h>
 #include "file.h"
+#include "ansi.h"
+
+static void ansicon_erase(const struct term_state *, int, int, int, int);
+static void ansicon_write_char(int, int, uint8_t, const struct term_state *);
+static void ansicon_showcursor(const struct term_state *, int);
+static void ansicon_scroll_up(const struct term_state *);
+static void ansicon_set_cursor(int, int);
+
+static struct term_state ts;
+struct ansi_ops __ansicon_ops = {
+  .erase       = ansicon_erase,
+  .write_char  = ansicon_write_char,
+  .showcursor   = ansicon_showcursor,
+  .set_cursor   = ansicon_set_cursor,
+  .scroll_up    = ansicon_scroll_up,
+};
+
+static struct term_info ti =
+  {
+    .disabled = 0,
+    .ts = &ts,
+    .op = &__ansicon_ops
+  };
 
-struct curxy {
-  uint8_t x, y;
-} __attribute__((packed));
 #define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */
 #define BIOS_ROWS (*(uint8_t *)0x484)      /* Minus one; if zero use 24 (= 25 lines) */
 #define BIOS_COLS (*(uint16_t *)0x44A)
 #define BIOS_PAGE (*(uint8_t *)0x462)
 
-enum ansi_state {
-  st_init,                     /* Normal (no ESC seen) */
-  st_esc,                      /* ESC seen */
-  st_csi,                      /* CSI seen */
-  st_soh,                      /* SOH seen */
-  st_sohc,                     /* SOH # seen */
-  st_sohc1,                    /* SOH # digit seen */
-};
-
-#define MAX_PARMS      16
-
-struct term_state {
-  int disabled;
-  int attr;                    /* Current display attribute */
-  int vtgraphics;              /* VT graphics on/off */
-  int intensity;
-  int underline;
-  int blink;
-  int reverse;
-  int fg;
-  int bg;
-  int autocr;
-  struct curxy saved_xy;
-  uint16_t cursor_type;
-  enum ansi_state state;
-  int pvt;                     /* Private code? */
-  int nparms;                  /* Number of parameters seen */
-  int parms[MAX_PARMS];
-};
-
-static const struct term_state default_state =
-{
-  .disabled = 0,
-  .attr = 0x07,                        /* Grey on black */
-  .vtgraphics = 0,
-  .intensity = 1,
-  .underline = 0,
-  .blink = 0,
-  .reverse = 0,
-  .fg = 7,
-  .bg = 0,
-  .autocr = 0,
-  .saved_xy = { 0, 0 },
-  .cursor_type = 0x0607,
-  .state = st_init,
-  .pvt = 0,
-  .nparms = 0,
-};
-
-static struct term_state st;
-
-/* DEC VT graphics to codepage 437 table (characters 0x60-0x7F only) */
-static const char decvt_to_cp437[] =
-  { 0004, 0261, 0007, 0007, 0007, 0007, 0370, 0361, 0007, 0007, 0331, 0277, 0332, 0300, 0305, 0304,
-    0304, 0304, 0137, 0137, 0303, 0264, 0301, 0302, 0263, 0363, 0362, 0343, 0330, 0234, 0007, 00 };
-
-/* Reference counter to the screen, to keep track of if we need reinitialization. */
+/* Reference counter to the screen, to keep track of if we need
+   reinitialization. */
 static int ansicon_counter = 0;
 
 /* Common setup */
@@ -116,16 +81,18 @@ int __ansicon_open(struct file_info *fp)
   (void)fp;
 
   if (!ansicon_counter) {
-    /* Initial state */
-    memcpy(&st, &default_state, sizeof st);
-
     /* Are we disabled? */
     ireg.eax.w[0] = 0x000b;
     __intcall(0x22, &ireg, &oreg);
 
     if ( (signed char)oreg.ebx.b[1] < 0 ) {
-      st.disabled = 1;
+      ti.disabled = 1;
     } else {
+      /* Initial state */
+      ti.rows = BIOS_ROWS ? BIOS_ROWS+1 : 25;
+      ti.cols = BIOS_COLS;
+      __ansi_init(&ti);
+
       /* Force text mode */
       ireg.eax.w[0] = 0x0005;
       __intcall(0x22, &ireg, NULL);
@@ -134,7 +101,7 @@ int __ansicon_open(struct file_info *fp)
       ireg.eax.b[1] = 0x03;
       ireg.ebx.b[1] = BIOS_PAGE;
       __intcall(0x10, &ireg, &oreg);
-      st.cursor_type = oreg.ecx.w[0];
+      ti.ts->cursor_type = oreg.ecx.w[0];
     }
   }
 
@@ -150,13 +117,42 @@ int __ansicon_close(struct file_info *fp)
   return 0;
 }
 
+/* Turn ANSI attributes into VGA attributes */
+static uint8_t ansicon_attribute(const struct term_state *st)
+{
+  int bg = st->bg;
+  int fg;
+
+  if ( st->underline )
+    fg = 0x01;
+  else if ( st->intensity == 0 )
+    fg = 0x08;
+  else
+    fg = st->fg;
+
+  if ( st->reverse ) {
+    bg = fg & 0x07;
+    fg &= 0x08;
+    fg |= st->bg;
+  }
+
+  if ( st->blink )
+    bg ^= 0x08;
+
+  if ( st->intensity == 2 )
+    fg ^= 0x08;
+
+  return (bg << 4) | fg;
+}
+
 /* Erase a region of the screen */
-static void ansicon_erase(int x0, int y0, int x1, int y1)
+static void ansicon_erase(const struct term_state *st,
+                         int x0, int y0, int x1, int y1)
 {
   static com32sys_t ireg;
 
   ireg.eax.w[0] = 0x0600;      /* Clear window */
-  ireg.ebx.b[1] = st.attr;     /* Fill with current attribute */
+  ireg.ebx.b[1] = ansicon_attribute(st);
   ireg.ecx.b[0] = x0;
   ireg.ecx.b[1] = y0;
   ireg.edx.b[0] = x1;
@@ -165,413 +161,56 @@ static void ansicon_erase(int x0, int y0, int x1, int y1)
 }
 
 /* Show or hide the cursor */
-static void showcursor(int yes)
+static void ansicon_showcursor(const struct term_state *st, int yes)
 {
   static com32sys_t ireg;
 
   ireg.eax.b[1] = 0x01;
-  ireg.ecx.w[0] = yes ? st.cursor_type : 0x2020;
+  ireg.ecx.w[0] = yes ? st->cursor_type : 0x2020;
   __intcall(0x10, &ireg, NULL);
 }
 
-static void ansicon_putchar(int ch)
+static void ansicon_set_cursor(int x, int y)
 {
-  static com32sys_t ireg;
-  const int rows  = BIOS_ROWS ? BIOS_ROWS+1 : 25;
-  const int cols  = BIOS_COLS;
   const int page  = BIOS_PAGE;
   struct curxy xy = BIOS_CURXY[page];
+  static com32sys_t ireg;
 
-  switch ( st.state ) {
-  case st_init:
-    switch ( ch ) {
-    case 1:
-      st.state = st_soh;
-      break;
-    case '\b':
-      if ( xy.x > 0 ) xy.x--;
-      break;
-    case '\t':
-      {
-       int nsp = 8 - (xy.x & 7);
-       while ( nsp-- )
-         ansicon_putchar(' ');
-      }
-      return;                  /* Cursor already updated */
-    case '\n':
-    case '\v':
-    case '\f':
-      xy.y++;
-      if ( st.autocr )
-       xy.x = 0;
-      break;
-    case '\r':
-      xy.x = 0;
-      break;
-    case 127:
-      /* Ignore delete */
-      break;
-    case 14:
-      st.vtgraphics = 1;
-      break;
-    case 15:
-      st.vtgraphics = 0;
-      break;
-    case 27:
-      st.state = st_esc;
-      break;
-    default:
-      /* Print character */
-      if ( ch >= 32 ) {
-       if ( st.vtgraphics && (ch & 0xe0) == 0x60 )
-         ch = decvt_to_cp437[ch - 0x60];
-
-       ireg.eax.b[1] = 0x09;
-       ireg.eax.b[0] = ch;
-       ireg.ebx.b[1] = page;
-       ireg.ebx.b[0] = st.attr;
-       ireg.ecx.w[0] = 1;
-       __intcall(0x10, &ireg, NULL);
-       xy.x++;
-      }
-      break;
-    }
-    break;
-
-  case st_esc:
-    switch ( ch ) {
-    case '%':
-    case '(':
-    case ')':
-    case '#':
-      /* Ignore this plus the subsequent character, allows
-        compatibility with Linux sequence to set charset */
-      break;
-    case '[':
-      st.state = st_csi;
-      st.nparms = st.pvt = 0;
-      memset(st.parms, 0, sizeof st.parms);
-      break;
-    case 'c':
-      /* Reset terminal */
-      memcpy(&st, &default_state, sizeof st);
-      ansicon_erase(0, 0, cols-1, rows-1);
-      xy.x = xy.y = 1;
-      break;
-    default:
-      /* Ignore sequence */
-      st.state = st_init;
-      break;
-    }
-    break;
-
-  case st_csi:
-    {
-      int p0 = st.parms[0] ? st.parms[0] : 1;
-
-      if ( ch >= '0' && ch <= '9' ) {
-       st.parms[st.nparms] = st.parms[st.nparms]*10 + (ch-'0');
-      } else if ( ch == ';' ) {
-       st.nparms++;
-       if ( st.nparms >= MAX_PARMS )
-         st.nparms = MAX_PARMS-1;
-       break;
-      } else if ( ch == '?' ) {
-       st.pvt = 1;
-      } else {
-       switch ( ch ) {
-       case 'A':
-         {
-           int y = xy.y - p0;
-           xy.y = (y < 0) ? 0 : y;
-         }
-         break;
-       case 'B':
-         {
-           int y = xy.y + p0;
-           xy.y = (y >= rows) ? rows-1 : y;
-         }
-         break;
-       case 'C':
-         {
-           int x = xy.x + p0;
-           xy.x = (x >= cols) ? cols-1 : x;
-         }
-         break;
-       case 'D':
-         {
-           int x = xy.x - p0;
-           xy.x = (x < 0) ? 0 : x;
-         }
-         break;
-       case 'E':
-         {
-           int y = xy.y + p0;
-           xy.y = (y >= rows) ? rows-1 : y;
-           xy.x = 0;
-         }
-         break;
-       case 'F':
-         {
-           int y = xy.y - p0;
-           xy.y = (y < 0) ? 0 : y;
-           xy.x = 0;
-         }
-         break;
-       case 'G':
-       case '\'':
-         {
-           int x = st.parms[0] - 1;
-           xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x;
-         }
-         break;
-       case 'H':
-       case 'f':
-         {
-           int y = st.parms[0] - 1;
-           int x = st.parms[1] - 1;
-
-           xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x;
-           xy.y = (y >= rows) ? rows-1 : (y < 0) ? 0 : y;
-         }
-         break;
-       case 'J':
-         {
-           switch ( st.parms[0] ) {
-           case 0:
-             ansicon_erase(xy.x, xy.y, cols-1, xy.y);
-             if ( xy.y < rows-1 )
-               ansicon_erase(0, xy.y+1, cols-1, rows-1);
-             break;
-
-           case 1:
-             if ( xy.y > 0 )
-               ansicon_erase(0, 0, cols-1, xy.y-1);
-             if ( xy.y > 0 )
-               ansicon_erase(0, xy.y, xy.x-1, xy.y);
-             break;
-
-           case 2:
-             ansicon_erase(0, 0, cols-1, rows-1);
-             break;
-
-           default:
-             /* Ignore */
-             break;
-           }
-         }
-         break;
-       case 'K':
-         {
-           switch ( st.parms[0] ) {
-           case 0:
-             ansicon_erase(xy.x, xy.y, cols-1, xy.y);
-             break;
-
-           case 1:
-             if ( xy.x > 0 )
-               ansicon_erase(0, xy.y, xy.x-1, xy.y);
-             break;
-
-           case 2:
-             ansicon_erase(0, xy.y, cols-1, xy.y);
-             break;
-
-           default:
-             /* Ignore */
-             break;
-           }
-         }
-         break;
-       case 'h':
-       case 'l':
-         {
-           int set = (ch == 'h');
-           switch ( st.parms[0] ) {
-           case 20:
-             st.autocr = set;
-             break;
-           case 25:
-             showcursor(set);
-             break;
-           default:
-             /* Ignore */
-             break;
-           }
-         }
-         break;
-       case 'm':
-         {
-           static const int ansi2pc[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
-
-           int i;
-           for ( i = 0 ; i <= st.nparms ; i++ ) {
-             int a = st.parms[i];
-             switch ( a ) {
-             case 0:
-               st.fg = 7;
-               st.bg = 0;
-               st.intensity = 1;
-               st.underline = 0;
-               st.blink = 0;
-               st.reverse = 0;
-               break;
-             case 1:
-               st.intensity = 2;
-               break;
-             case 2:
-               st.intensity = 0;
-               break;
-             case 4:
-               st.underline = 1;
-               break;
-             case 5:
-               st.blink = 1;
-               break;
-             case 7:
-               st.reverse = 1;
-               break;
-             case 21:
-             case 22:
-               st.intensity = 1;
-               break;
-             case 24:
-               st.underline = 0;
-               break;
-             case 25:
-               st.blink = 0;
-               break;
-             case 27:
-               st.reverse = 0;
-               break;
-             case 30 ... 37:
-               st.fg = ansi2pc[a-30];
-               break;
-             case 38:
-               st.fg = 7;
-               st.underline = 1;
-               break;
-             case 39:
-               st.fg = 7;
-               st.underline = 0;
-               break;
-             case 40 ... 47:
-               st.bg = ansi2pc[a-40];
-               break;
-             case 49:
-               st.bg = 7;
-               break;
-             default:
-               /* Do nothing */
-               break;
-             }
-           }
-
-           /* Turn into an attribute code */
-           {
-             int bg = st.bg;
-             int fg;
-
-             if ( st.underline )
-               fg = 0x01;
-             else if ( st.intensity == 0 )
-               fg = 0x08;
-             else
-               fg = st.fg;
-
-             if ( st.reverse ) {
-               bg = fg & 0x07;
-               fg &= 0x08;
-               fg |= st.bg;
-             }
-
-             if ( st.blink )
-               bg ^= 0x08;
-
-             if ( st.intensity == 2 )
-               fg ^= 0x08;
-
-             st.attr = (bg << 4) | fg;
-           }
-         }
-         break;
-       case 's':
-         st.saved_xy = xy;
-         break;
-       case 'u':
-         xy = st.saved_xy;
-         break;
-       default:                /* Includes CAN and SUB */
-         break;                /* Drop unknown sequence */
-       }
-       st.state = st_init;
-      }
-    }
-    break;
-
-  case st_soh:
-    if ( ch == '#' )
-      st.state = st_sohc;
-    else
-      st.state = st_init;
-    break;
-
-  case st_sohc:
-    {
-      int n = (unsigned char)ch - '0';
-      if (n < 10) {
-       st.parms[0] = n*10;
-       st.state = st_sohc1;
-      } else {
-       st.state = st_init;
-      }
-    }
-    break;
-
-  case st_sohc1:
-    {
-      int n = (unsigned char)ch - '0';
-      const char *p;
-
-      if (n < 10) {
-       st.parms[0] += n;
-       /* Emulate the appropriate CSI m sequence */
-       if (st.parms[0] < console_color_table_size) {
-         st.state = st_csi;
-         for (p = console_color_table[st.parms[0]].ansi; *p; p++)
-           ansicon_putchar(*p);
-         ansicon_putchar('m');
-       }
-      }
-
-      st.state = st_init;
-    }
-    break;
+  if (xy.x != x || xy.y != y) {
+    ireg.eax.b[1] = 0x02;
+    ireg.ebx.b[1] = page;
+    ireg.edx.b[1] = xy.y;
+    ireg.edx.b[0] = xy.x;
+    __intcall(0x10, &ireg, NULL);
   }
+}
 
-  /* If we fell off the end of the screen, adjust */
-  if ( xy.x >= cols ) {
-    xy.x = 0;
-    xy.y++;
-  }
-  while ( xy.y >= rows ) {
-    xy.y--;
-    ireg.eax.w[0] = 0x0601;
-    ireg.ebx.b[1] = st.attr;
-    ireg.ecx.w[0] = 0;
-    ireg.edx.b[1] = rows-1;
-    ireg.edx.b[0] = cols-1;
-    __intcall(0x10, &ireg, NULL); /* Scroll */
-  }
+static void ansicon_write_char(int x, int y, uint8_t ch,
+                              const struct term_state *st)
+{
+  static com32sys_t ireg;
 
-  /* Update cursor position */
-  ireg.eax.b[1] = 0x02;
-  ireg.ebx.b[1] = page;
-  ireg.edx.b[1] = xy.y;
-  ireg.edx.b[0] = xy.x;
+  ansicon_set_cursor(x, y);
+
+  ireg.eax.b[1] = 0x09;
+  ireg.eax.b[0] = ch;
+  ireg.ebx.b[1] = BIOS_PAGE;
+  ireg.ebx.b[0] = ansicon_attribute(st);
+  ireg.ecx.w[0] = 1;
   __intcall(0x10, &ireg, NULL);
 }
 
+static void ansicon_scroll_up(const struct term_state *st)
+{
+  static com32sys_t ireg;
+
+  ireg.eax.w[0] = 0x0601;
+  ireg.ebx.b[1] = ansicon_attribute(st);
+  ireg.ecx.w[0] = 0;
+  ireg.edx.b[1] = ti.rows-1;
+  ireg.edx.b[0] = ti.cols-1;
+  __intcall(0x10, &ireg, NULL); /* Scroll */
+}
 
 ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
 {
@@ -580,11 +219,11 @@ ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
 
   (void)fp;
 
-  if ( st.disabled )
+  if ( ti.disabled )
     return n;                  /* Nothing to do */
 
   while ( count-- ) {
-    ansicon_putchar(*bufp++);
+    __ansi_putchar(&ti, *bufp++);
     n++;
   }
 
index bfdc9f4..a599d05 100644 (file)
@@ -1,5 +1,5 @@
 /* ----------------------------------------------------------------------- *
- *   
+ *
  *   Copyright 2006 H. Peter Anvin - All Rights Reserved
  *
  *   Permission is hereby granted, free of charge, to any person
  *   sell copies of the Software, and to permit persons to whom
  *   the Software is furnished to do so, subject to the following
  *   conditions:
- *   
+ *
  *   The above copyright notice and this permission notice shall
  *   be included in all copies or substantial portions of the Software.
- *   
+ *
  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -85,12 +85,12 @@ static int read_png_file(FILE *fp)
 
   /* Set the appropriate set of transformations.  We need to end up
      with 32-bit BGRA format, no more, no less. */
-  
+
   switch (info_ptr->color_type) {
   case PNG_COLOR_TYPE_GRAY_ALPHA:
     png_set_gray_to_rgb(png_ptr);
     /* fall through */
-    
+
   case PNG_COLOR_TYPE_RGB_ALPHA:
     break;
 
@@ -104,7 +104,7 @@ static int read_png_file(FILE *fp)
     else
       png_set_add_alpha(png_ptr, ~0, PNG_FILLER_AFTER);
     break;
-    
+
   case PNG_COLOR_TYPE_PALETTE:
     png_set_palette_to_rgb(png_ptr);
     break;
@@ -129,11 +129,11 @@ static int read_png_file(FILE *fp)
     png_set_background(png_ptr, &my_background,
                       PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
 #endif
-    
+
   /* Whew!  Now we should get the stuff we want... */
   for (i = 0; i < (int)info_ptr->height; i++)
     row_pointers[i] = (void *)__vesacon_background[i];
-    
+
   passes = png_set_interlace_handling(png_ptr);
 
   for (i = 0; i < passes; i++)
@@ -201,7 +201,7 @@ static int read_jpeg_file(FILE *fp, uint8_t *header, int len)
     free(jpeg_file);
 
   return rv;
-}   
+}
 
 int vesacon_load_background(const char *filename)
 {
@@ -226,7 +226,7 @@ int vesacon_load_background(const char *filename)
     rv = read_png_file(fp);
   } else if (!jpeg_sig_cmp(header, 8)) {
     rv = read_jpeg_file(fp, header, 8);
-  }    
+  }
 
   /* This actually displays the stuff */
   draw_background();
index 820fc40..b2265e8 100644 (file)
@@ -1,5 +1,5 @@
 /* ----------------------------------------------------------------------- *
- *   
+ *
  *   Copyright 2006 H. Peter Anvin - All Rights Reserved
  *
  *   Permission is hereby granted, free of charge, to any person
  *   sell copies of the Software, and to permit persons to whom
  *   the Software is furnished to do so, subject to the following
  *   conditions:
- *   
+ *
  *   The above copyright notice and this permission notice shall
  *   be included in all copies or substantial portions of the Software.
- *   
+ *
  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -93,7 +93,7 @@ static void vesacon_update_characters(int row, int col, int nrows, int ncols)
     chsbits ^= (csptr->sha & 0x01) ? 0xff : 0x00;
     chsbits <<= 6;
     csptr++;
-    
+
     for (j = width*ncols; j >= 0; j--) {
       chbits <<= 1;
       chsbits <<= 1;
@@ -134,7 +134,7 @@ static void vesacon_update_characters(int row, int col, int nrows, int ncols)
        color >>= 2;
        color &= 0x3f3f3f;
       }
-      
+
       *fbptr++ = color;
     }
 
@@ -207,7 +207,7 @@ void __vesacon_scroll_up(int nrows, uint8_t attr, int rev)
 
   /* Danger, Will Robinson: this is wrong if rev != SHADOW_NORMAL */
   vesacon_fill(toptr, fill, dword_count);
-  
+
   vesacon_update_characters(0, 0, __vesacon_text_rows,
                            TEXT_PIXEL_COLS/FONT_WIDTH);
 }
@@ -234,7 +234,7 @@ void __vesacon_write_at(int x, int y, const char *str,
 }
 
 /* Draw one character text at a specific area of the screen */
-void __vesacon_write_char(int x, int y, char ch, uint8_t attr, int rev)
+void __vesacon_write_char(int x, int y, uint8_t ch, uint8_t attr, int rev)
 {
   struct vesa_char *ptr = &__vesacon_text_display
     [(y+1)*(TEXT_PIXEL_COLS/FONT_WIDTH+2)+(x+1)];
@@ -245,4 +245,3 @@ void __vesacon_write_char(int x, int y, char ch, uint8_t attr, int rev)
 
   vesacon_update_characters(y, x, 1, 1);
 }
-
index 82b14a4..bfb1466 100644 (file)
@@ -66,6 +66,6 @@ int __vesacon_init(void);
 void __vesacon_erase(int, int, int, int, uint8_t, int);
 void __vesacon_scroll_up(int, uint8_t, int);
 void __vesacon_write_at(int, int, const char *, uint8_t, int);
-void __vesacon_write_char(int, int, char, uint8_t, int);
+void __vesacon_write_char(int, int, uint8_t, uint8_t, int);
 
 #endif /* LIB_SYS_VESA_VIDEO_H */
index e0d47f3..ee9c193 100644 (file)
 #include <minmax.h>
 #include <colortbl.h>
 #include <klibc/compiler.h>
+#include "ansi.h"
 #include "file.h"
 #include "vesa/video.h"
 
-struct curxy {
-  uint8_t x, y;
-} __attribute__((packed));
-
-enum ansi_state {
-  st_init,                     /* Normal (no ESC seen) */
-  st_esc,                      /* ESC seen */
-  st_csi,                      /* CSI seen */
-  st_soh,                      /* SOH seen */
-  st_sohc,                     /* SOH # seen */
-  st_sohc1,                    /* SOH # digit seen */
-};
-
-#define MAX_PARMS      16
-
-struct term_state {
-  int disabled;
-  int attr;                    /* Current display attribute */
-  int vtgraphics;              /* VT graphics on/off */
-  int intensity;
-  int underline;
-  int blink;
-  int reverse;
-  int fg;
-  int bg;
-  int autocr;
-  struct curxy saved_xy;
-  uint16_t cursor_type;
-  enum ansi_state state;
-  int pvt;                     /* Private code? */
-  int nparms;                  /* Number of parameters seen */
-  int parms[MAX_PARMS];
-  struct curxy xy;
-};
-
-static const struct term_state default_state =
-{
-  .disabled = 0,
-  .attr = 0,                   /* First color table entry */
-  .vtgraphics = 0,
-  .intensity = 1,
-  .underline = 0,
-  .blink = 0,
-  .reverse = 0,
-  .fg = 7,
-  .bg = 0,
-  .autocr = 0,
-  .saved_xy = { 0, 0 },
-  .cursor_type = 0x0607,
-  .state = st_init,
-  .pvt = 0,
-  .nparms = 0,
-  .xy = { 0, 0 },
+static void vesacon_erase(const struct term_state *, int, int, int, int);
+static void vesacon_write_char(int, int, uint8_t, const struct term_state *);
+static void vesacon_showcursor(const struct term_state *, int);
+static void vesacon_scroll_up(const struct term_state *);
+static void vesacon_set_cursor(int, int);
+
+static struct term_state ts;
+static struct ansi_ops op = {
+  .erase       = vesacon_erase,
+  .write_char  = vesacon_write_char,
+  .showcursor   = vesacon_showcursor,
+  .set_cursor   = vesacon_set_cursor,
+  .scroll_up    = vesacon_scroll_up,
 };
 
-static struct term_state st;
-
-/* DEC VT graphics to codepage 437 table (characters 0x60-0x7F only) */
-static const char decvt_to_cp437[] =
-  { 0004, 0261, 0007, 0007, 0007, 0007, 0370, 0361, 0007, 0007, 0331, 0277, 0332, 0300, 0305, 0304,
-    0304, 0304, 0137, 0137, 0303, 0264, 0301, 0302, 0263, 0363, 0362, 0343, 0330, 0234, 0007, 00 };
+static struct term_info ti =
+  {
+    .cols = TEXT_PIXEL_COLS/FONT_WIDTH,
+    .disabled = 0,
+    .ts = &ts,
+    .op = &op
+  };
 
 /* Reference counter to the screen, to keep track of if we need reinitialization. */
 static int vesacon_counter = 0;
@@ -115,19 +77,20 @@ int __vesacon_open(struct file_info *fp)
   (void)fp;
 
   if (!vesacon_counter) {
-    /* Initial state */
-    memcpy(&st, &default_state, sizeof st);
-
     /* Are we disabled? */
     ireg.eax.w[0] = 0x000b;
     __intcall(0x22, &ireg, &oreg);
 
     if ( (signed char)oreg.ebx.b[1] < 0 ) {
-      st.disabled = 1;
+      ti.disabled = 1;
     } else {
       /* Switch mode */
       if (__vesacon_init())
        return EIO;
+
+      /* Initial state */
+      __ansi_init(&ti);
+      ti.rows = __vesacon_text_rows;
     }
   }
 
@@ -144,382 +107,40 @@ int __vesacon_close(struct file_info *fp)
 }
 
 /* Erase a region of the screen */
-static void vesacon_erase(int x0, int y0, int x1, int y1)
+static void vesacon_erase(const struct term_state *st,
+                         int x0, int y0, int x1, int y1)
 {
-  __vesacon_erase(x0, y0, x1, y1, st.attr,
-                 st.reverse ? SHADOW_ALL : SHADOW_NORMAL);
+  __vesacon_erase(x0, y0, x1, y1, st->attr,
+                 st->reverse ? SHADOW_ALL : SHADOW_NORMAL);
+}
+
+/* Draw text on the screen */
+static void vesacon_write_char(int x, int y, uint8_t ch,
+                              const struct term_state *st)
+{
+  __vesacon_write_char(x, y, ch, st->cindex,
+                      st->reverse ? SHADOW_ALL : SHADOW_NORMAL);
 }
 
 /* Show or hide the cursor */
-static void showcursor(int yes)
+static void vesacon_showcursor(const struct term_state *st, int yes)
 {
+  (void)st;
   (void)yes;
   /* Do something here */
 }
 
-static void vesacon_putchar(int ch)
+static void vesacon_set_cursor(int x, int y)
 {
-  const int rows  = __vesacon_text_rows;
-  const int cols  = TEXT_PIXEL_COLS/FONT_WIDTH;
-  struct curxy xy = st.xy;
-
-  switch ( st.state ) {
-  case st_init:
-    switch ( ch ) {
-    case 1:
-      st.state = st_soh;
-      break;
-    case '\b':
-      if ( xy.x > 0 ) xy.x--;
-      break;
-    case '\t':
-      {
-       int nsp = 8 - (xy.x & 7);
-       while ( nsp-- )
-         vesacon_putchar(' ');
-      }
-      return;                  /* Cursor already updated */
-    case '\n':
-    case '\v':
-    case '\f':
-      xy.y++;
-      if ( st.autocr )
-       xy.x = 0;
-      break;
-    case '\r':
-      xy.x = 0;
-      break;
-    case 127:
-      /* Ignore delete */
-      break;
-    case 14:
-      st.vtgraphics = 1;
-      break;
-    case 15:
-      st.vtgraphics = 0;
-      break;
-    case 27:
-      st.state = st_esc;
-      break;
-    default:
-      /* Print character */
-      if ( ch >= 32 ) {
-       if ( st.vtgraphics && (ch & 0xe0) == 0x60 )
-         ch = decvt_to_cp437[ch - 0x60];
-
-       __vesacon_write_char(xy.x, xy.y, ch, st.attr,
-                            st.reverse ? SHADOW_ALL : SHADOW_NORMAL);
-       xy.x++;
-      }
-      break;
-    }
-    break;
-
-  case st_esc:
-    switch ( ch ) {
-    case '%':
-    case '(':
-    case ')':
-    case '#':
-      /* Ignore this plus the subsequent character, allows
-        compatibility with Linux sequence to set charset */
-      break;
-    case '[':
-      st.state = st_csi;
-      st.nparms = st.pvt = 0;
-      memset(st.parms, 0, sizeof st.parms);
-      break;
-    case 'c':
-      /* Reset terminal */
-      memcpy(&st, &default_state, sizeof st);
-      vesacon_erase(0, 0, cols-1, rows-1);
-      xy.x = xy.y = 1;
-      st.state = st_init;
-      break;
-    default:
-      /* Ignore sequence */
-      st.state = st_init;
-      break;
-    }
-    break;
-
-  case st_csi:
-    {
-      int p0 = st.parms[0] ? st.parms[0] : 1;
-
-      if ( ch >= '0' && ch <= '9' ) {
-       st.parms[st.nparms] = st.parms[st.nparms]*10 + (ch-'0');
-      } else if ( ch == ';' ) {
-       st.nparms++;
-       if ( st.nparms >= MAX_PARMS )
-         st.nparms = MAX_PARMS-1;
-       break;
-      } else if ( ch == '?' ) {
-       st.pvt = 1;
-      } else {
-       switch ( ch ) {
-       case 'A':
-         {
-           int y = xy.y - p0;
-           xy.y = (y < 0) ? 0 : y;
-         }
-         break;
-       case 'B':
-         {
-           int y = xy.y + p0;
-           xy.y = (y >= rows) ? rows-1 : y;
-         }
-         break;
-       case 'C':
-         {
-           int x = xy.x + p0;
-           xy.x = (x >= cols) ? cols-1 : x;
-         }
-         break;
-       case 'D':
-         {
-           int x = xy.x - p0;
-           xy.x = (x < 0) ? 0 : x;
-         }
-         break;
-       case 'E':
-         {
-           int y = xy.y + p0;
-           xy.y = (y >= rows) ? rows-1 : y;
-           xy.x = 0;
-         }
-         break;
-       case 'F':
-         {
-           int y = xy.y - p0;
-           xy.y = (y < 0) ? 0 : y;
-           xy.x = 0;
-         }
-         break;
-       case 'G':
-       case '\'':
-         {
-           int x = st.parms[0] - 1;
-           xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x;
-         }
-         break;
-       case 'H':
-       case 'f':
-         {
-           int y = st.parms[0] - 1;
-           int x = st.parms[1] - 1;
-
-           xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x;
-           xy.y = (y >= rows) ? rows-1 : (y < 0) ? 0 : y;
-         }
-         break;
-       case 'J':
-         {
-           switch ( st.parms[0] ) {
-           case 0:
-             vesacon_erase(xy.x, xy.y, cols-1, xy.y);
-             if ( xy.y < rows-1 )
-               vesacon_erase(0, xy.y+1, cols-1, rows-1);
-             break;
-
-           case 1:
-             if ( xy.y > 0 )
-               vesacon_erase(0, 0, cols-1, xy.y-1);
-             if ( xy.y > 0 )
-               vesacon_erase(0, xy.y, xy.x-1, xy.y);
-             break;
-
-           case 2:
-             vesacon_erase(0, 0, cols-1, rows-1);
-             break;
-
-           default:
-             /* Ignore */
-             break;
-           }
-         }
-         break;
-       case 'K':
-         {
-           switch ( st.parms[0] ) {
-           case 0:
-             vesacon_erase(xy.x, xy.y, cols-1, xy.y);
-             break;
-
-           case 1:
-             if ( xy.x > 0 )
-               vesacon_erase(0, xy.y, xy.x-1, xy.y);
-             break;
-
-           case 2:
-             vesacon_erase(0, xy.y, cols-1, xy.y);
-             break;
-
-           default:
-             /* Ignore */
-             break;
-           }
-         }
-         break;
-       case 'h':
-       case 'l':
-         {
-           int set = (ch == 'h');
-           switch ( st.parms[0] ) {
-           case 20:
-             st.autocr = set;
-             break;
-           case 25:
-             showcursor(set);
-             break;
-           default:
-             /* Ignore */
-             break;
-           }
-         }
-         break;
-       case 'm':
-         {
-           static const int ansi2pc[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
-
-           int i;
-           for ( i = 0 ; i <= st.nparms ; i++ ) {
-             int a = st.parms[i];
-             switch ( a ) {
-             case 0:
-               st.fg = 7;
-               st.bg = 0;
-               st.intensity = 1;
-               st.underline = 0;
-               st.blink = 0;
-               st.reverse = 0;
-               break;
-             case 1:
-               st.intensity = 2;
-               break;
-             case 2:
-               st.intensity = 0;
-               break;
-             case 4:
-               st.underline = 1;
-               break;
-             case 5:
-               st.blink = 1;
-               break;
-             case 7:
-               st.reverse = 1;
-               break;
-             case 21:
-             case 22:
-               st.intensity = 1;
-               break;
-             case 24:
-               st.underline = 0;
-               break;
-             case 25:
-               st.blink = 0;
-               break;
-             case 27:
-               st.reverse = 0;
-               break;
-             case 30 ... 37:
-               st.fg = ansi2pc[a-30];
-               break;
-             case 38:
-               st.fg = 7;
-               st.underline = 1;
-               break;
-             case 39:
-               st.fg = 7;
-               st.underline = 0;
-               break;
-             case 40 ... 47:
-               st.bg = ansi2pc[a-40];
-               break;
-             case 49:
-               st.bg = 7;
-               break;
-             default:
-               /* Do nothing */
-               break;
-             }
-           }
-         }
-         break;
-       case 's':
-         st.saved_xy = xy;
-         break;
-       case 'u':
-         xy = st.saved_xy;
-         break;
-       default:                /* Includes CAN and SUB */
-         break;                /* Drop unknown sequence */
-       }
-       st.state = st_init;
-      }
-    }
-    break;
-
-  case st_soh:
-    if ( ch == '#' )
-      st.state = st_sohc;
-    else
-      st.state = st_init;
-    break;
-
-  case st_sohc:
-    {
-      int n = (unsigned char)ch - '0';
-      if (n < 10) {
-       st.parms[0] = n*10;
-       st.state = st_sohc1;
-      } else {
-       st.state = st_init;
-      }
-    }
-    break;
-
-  case st_sohc1:
-    {
-      int n = (unsigned char)ch - '0';
-      const char *p;
-
-      if (n < 10) {
-       st.parms[0] += n;
-       if (st.parms[0] < console_color_table_size) {
-         /* Set the color table index */
-         st.attr = st.parms[0];
-
-         /* See if there are any other attributes we care about */
-         p = console_color_table[st.parms[0]].ansi;
-         st.state = st_esc;
-         vesacon_putchar('[');
-         while (*p)
-           vesacon_putchar(*p++);
-         vesacon_putchar('m');
-       }
-      }
-
-      st.state = st_init;
-    }
-    break;
-  }
-
-  /* If we fell off the end of the screen, adjust */
-  if ( xy.x >= cols ) {
-    xy.x = 0;
-    xy.y++;
-  }
-  while ( xy.y >= rows ) {
-    xy.y--;
-    __vesacon_scroll_up(1, st.attr, st.reverse ? SHADOW_ALL : SHADOW_NORMAL);
-  }
-
-  /* Update cursor position */
-  /* vesacon_set_cursor(xy.x, xy.y); */
-  st.xy = xy;
+  (void)x; (void)y;
+  /* Do something here */
 }
 
+static void vesacon_scroll_up(const struct term_state *st)
+{
+  __vesacon_scroll_up(1, st->cindex,
+                     st->reverse ? SHADOW_ALL : SHADOW_NORMAL);
+}
 
 ssize_t __vesacon_write(struct file_info *fp, const void *buf, size_t count)
 {
@@ -528,11 +149,11 @@ ssize_t __vesacon_write(struct file_info *fp, const void *buf, size_t count)
 
   (void)fp;
 
-  if ( st.disabled )
+  if ( ti.disabled )
     return n;                  /* Nothing to do */
 
   while ( count-- ) {
-    vesacon_putchar(*bufp++);
+    __ansi_putchar(&ti, *bufp++);
     n++;
   }