Actually working ANSI device; add demo
authorhpa <hpa>
Tue, 30 Nov 2004 22:09:56 +0000 (22:09 +0000)
committerhpa <hpa>
Tue, 30 Nov 2004 22:09:56 +0000 (22:09 +0000)
com32/include/console.h
com32/include/dev.h
com32/lib/Makefile
com32/lib/sys/ansicon_write.c
com32/lib/sys/ansiserial_write.c [new file with mode: 0644]
com32/lib/sys/serial_write.c
com32/modules/Makefile
com32/modules/fancyhello.c [new file with mode: 0644]
com32/modules/hello.c

index 5590427..494b0ba 100644 (file)
@@ -47,5 +47,14 @@ extern const struct output_dev dev_stdcon_w;
 extern const struct input_dev  dev_rawcon_r;
 extern const struct output_dev dev_rawcon_w;
 
+/* These are output-only consoles; combine with one of the input methods */
+
+/* Serial port only */
+extern const struct output_dev dev_serial_w;
+/* ANSI console (output only; combine with one of the input methods) */
+extern const struct output_dev dev_ansicon_w;
+/* ANSI plus serial port */
+extern const struct output_dev dev_ansiserial_w;
+
 #endif /* _CONSOLE_H */
 
index a8cea76..a5afbaf 100644 (file)
@@ -44,9 +44,12 @@ struct output_dev;
 __extern int opendev(const struct input_dev *, const struct output_dev *, int);
 
 /* Common generic devices */
+
+/* Null device */
 extern const struct input_dev  dev_null_r;
 extern const struct output_dev dev_null_w;
 
+/* Error device */
 extern const struct input_dev  dev_error_r;
 extern const struct output_dev dev_error_w;
 
index acc385f..9896bef 100644 (file)
@@ -25,7 +25,7 @@ LIBOBJS = abort.o atexit.o atoi.o atol.o atoll.o calloc.o creat.o     \
        sys/rawcon_read.o sys/rawcon_write.o                            \
        sys/err_read.o    sys/err_write.o                               \
        sys/null_read.o   sys/null_write.o                              \
-       sys/ansicon_write.o
+       sys/serial_write.o sys/ansicon_write.o sys/ansiserial_write.o
 
 
 all: libcom32.a
index 59eec01..1e4e3cc 100644 (file)
@@ -52,16 +52,14 @@ struct curxy {
   uint8_t x, y;
 } __attribute__((packed));
 #define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */
-#define BIOS_ROWS (*(uint8_t *)0x449)      /* Minus one */
+#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)
-#define BIOS_FB   (*(uint16_t *)0x44E)     /* Current page fb address */
 
 enum ansi_state {
   st_init,                     /* Normal (no ESC seen) */
   st_esc,                      /* ESC seen */
-  st_empty,                    /* CSI seen, empty position */
-  st_digits,                   /* CSI seen, digits seen in this position */
+  st_csi,                      /* CSI seen */
 };
 
 #define MAX_PARMS      16
@@ -89,7 +87,6 @@ static struct {
   .saved_xy = { 0, 0 },
   .state = st_init,
   .nparms = 0,
-  .parms = { 0, },
 };
 
 /* Erase a region of the screen */
@@ -113,292 +110,309 @@ static void ansicon_putchar(int ch)
   const int cols  = BIOS_COLS;
   const int page  = BIOS_PAGE;
   struct curxy xy = BIOS_CURXY[page];
-  int again;
 
-  do {
-    again = 0;
-
-    switch ( st.state ) {
-    case st_init:
-      switch ( ch ) {
-      case '\a':
-       /* Ignore beep */
-       break;
-      case '\b':
-       if ( xy.y > 0 ) xy.y--;
-       break;
-      case '\t':
-       {
-         int nsp = 8 - (xy.y & 7);
-         while ( nsp-- )
-           ansicon_putchar(' ');
-       }
-       return;                 /* Cursor already updated */
-      case '\n':
-      case '\v':
-      case '\f':
-       xy.y++;
-       break;
-      case '\r':
-       xy.x = 0;
-       break;
-      case '\0':
-      case 127:
-       /* Ignore null or delete */
-       break;
-      case 27:
-       st.state = st_esc;
-       break;
-      default:
-       /* Print character */
-       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;
-      }
+  switch ( st.state ) {
+  case st_init:
+    switch ( ch ) {
+    case '\a':
+      /* Ignore beep */
       break;
-      
-    case st_esc:
-      if ( ch == '[' ) {
-       int i;
-       st.state = st_empty;
-       st.nparms = 0;
-       for ( i = 0 ; i < MAX_PARMS ; i++ )
-         st.parms[i] = 1;      /* 1 is the default, not 0 */
-      } else {
-       st.state = st_init;
-       again = 1;
+    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++;
+      break;
+    case '\r':
+      xy.x = 0;
+      break;
+    case '\0':
+    case 127:
+      /* Ignore null or delete */
+      break;
+    case 27:
+      st.state = st_esc;
+      break;
+    default:
+      /* Print character */
+      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_empty:
-    case st_digits:
-      switch ( ch ) {
-       case '0' ... '9':
-       if ( st.state == st_empty ) {
-         st.parms[st.nparms] = ch - '0';
-         st.state = st_digits;
-       } else {
-         st.parms[st.nparms] = st.parms[st.nparms]*10 + (ch-'0');
-       }
-       break;
-      case ';':
+  case st_esc:
+    if ( ch == '[' ) {
+      st.state = st_csi;
+      st.nparms = 0;
+      memset(st.parms, 0, sizeof st.parms);
+    } else {
+      st.state = st_init;      /* Discard ESC+other symbol */
+    }
+    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;
-       st.state = st_empty;
        break;
-      case 'A':
-       {
-         int y = xy.y - st.parms[0];
-         xy.y = (y < 0) ? 0 : y;
-       }
-       break;
-      case 'B':
-       {
-         int y = xy.y + st.parms[0];
-         xy.y = (y >= rows) ? rows-1 : y;
-       }
-       break;
-      case 'C':
-       {
-         int x = xy.x + st.parms[0];
-         xy.x = (x >= cols) ? cols-1 : x;
-       }
-       break;
-      case 'D':
-       {
-         int x = xy.x - st.parms[0];
-         xy.x = (x < 0) ? 0 : x;
-       }
-       break;
-      case 'E':
-       {
-         int y = xy.y + st.parms[0];
-         xy.y = (y >= rows) ? rows-1 : y;
-         xy.x = 0;
-       }
-       break;
-      case 'F':
-       {
-         int y = xy.y - st.parms[0];
-         xy.y = (y < 0) ? 0 : y;
-         xy.x = 0;
-       }
-       break;
-      case 'H':
-      case 'f':
-       {
-         int x = st.parms[0];
-         int y = st.parms[1];
-
-         xy.x = (x >= cols) ? cols-1 : x;
-         xy.y = (y >= rows) ? rows-1 : y;
-       }
-       break;
-      case 'J':
-       {
-         if ( st.parms[0] == 2 ) {
-           ansicon_erase(0, 0, cols-1, rows-1);
-         } else {
-           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);
+      } else {
+       switch ( ch ) {
+       case 'A':
+         {
+           int y = xy.y - p0;
+           xy.y = (y < 0) ? 0 : y;
          }
-       }
-       break;
-      case 'K':
-       {
-         if ( st.parms[0] == 2 )
-           ansicon_erase(0, xy.y, cols-1, xy.y);
-         else
-           ansicon_erase(xy.x, xy.y, cols-1, xy.y);
-       }
-       break;
-      case 'm':
-       {
-         static const int ansi2pc[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+         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 'H':
+       case 'f':
+         {
+           int x = st.parms[0] - 1;
+           int y = st.parms[1] - 1;
 
-         int i;
-         for ( i = 0 ; i < st.nparms ; i++ ) {
-           int a = st.parms[i];
-           switch ( a ) {
+           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:
-             st.fg = 7;
-             st.bg = 7;
-             st.intensity = 1;
-             st.underline = 0;
-             st.blink = 0;
-             st.reverse = 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:
-             st.intensity = 2;
+             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:
-             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;
+             ansicon_erase(0, 0, cols-1, rows-1);
              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;
+
+           default:
+             /* Ignore */
              break;
-           case 39:
-             st.fg = 7;
-             st.underline = 0;
+           }
+         }
+         break;
+       case 'K':
+         {
+           switch ( st.parms[0] ) {
+           case 0:
+             ansicon_erase(xy.x, xy.y, cols-1, xy.y);
              break;
-           case 40 ... 47:
-             st.bg = ansi2pc[a-40];
+
+           case 1:
+             if ( xy.x > 0 )
+               ansicon_erase(0, xy.y, xy.x-1, xy.y);
              break;
-           case 49:
-             st.bg = 7;
+
+           case 2:
+             ansicon_erase(0, xy.y, cols-1, xy.y);
              break;
+         
            default:
-             /* Do nothing */
+             /* Ignore */
              break;
            }
          }
-         
-         /* Turn into an attribute code */
+         break;
+       case 'm':
          {
-           int bg = st.bg;
-           int fg;
-
-           if ( st.underline )
-             fg = 0x01;
-           else if ( st.intensity == 0 )
-             fg = 0x08;
-           else
-             fg = st.fg;
+           static const int ansi2pc[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
 
-           if ( st.reverse ) {
-             bg = fg & 0x07;
-             fg &= 0x08;
-             fg |= st.bg;
+           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.blink )
-             bg ^= 0x08;
+             if ( st.underline )
+               fg = 0x01;
+             else if ( st.intensity == 0 )
+               fg = 0x08;
+             else
+               fg = st.fg;
 
-           if ( st.intensity == 2 )
-             fg ^= 0x08;
+             if ( st.reverse ) {
+               bg = fg & 0x07;
+               fg &= 0x08;
+               fg |= st.bg;
+             }
 
-           st.attr = (bg << 4) | fg;
+             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;
        }
-       break;
-      case 's':
-       st.saved_xy = xy;
-       break;
-      case 'u':
-       xy = st.saved_xy;
-       break;
+       st.state = st_init;
       }
     }
-  } while ( again );
+    break;
+  }
 
   /* If we fell off the end of the screen, adjust */
   if ( xy.x >= cols ) {
     xy.x = 0;
     xy.y++;
-    if ( xy.y >= rows ) {
-      xy.y = 0;
-      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 */
-    }
+  }
+  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 */
   }
 
   /* Update cursor position */
-  ireg.eax.b[1] = 0x04;
-  ireg.ebx.b[1] = BIOS_PAGE;
+  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);
 }      
       
 
-static ssize_t ansicon_write(struct file_info *fp, const void *buf, size_t count)
+ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
 {
-  com32sys_t ireg;
-  const char *bufp = buf;
+  const unsigned char *bufp = buf;
   size_t n = 0;
 
   (void)fp;
 
-  memset(&ireg, 0, sizeof ireg); 
-  ireg.eax.b[1] = 0x04;
-
   while ( count-- ) {
     ansicon_putchar(*bufp++);
     n++;
@@ -411,6 +425,6 @@ const struct output_dev dev_ansicon_w = {
   .dev_magic  = __DEV_MAGIC,
   .flags      = __DEV_TTY | __DEV_OUTPUT,
   .fileflags  = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND,
-  .write      = ansicon_write,
+  .write      = __ansicon_write,
   .close      = NULL,
 };
diff --git a/com32/lib/sys/ansiserial_write.c b/com32/lib/sys/ansiserial_write.c
new file mode 100644 (file)
index 0000000..95f1c74
--- /dev/null
@@ -0,0 +1,56 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2004 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * ansiserial_write.c
+ *
+ * Write to both to the ANSI console and the serial port
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <com32.h>
+#include <minmax.h>
+#include "file.h"
+
+extern ssize_t __ansicon_write(struct file_info *, const void *, size_t);
+extern ssize_t __serial_write(struct file_info *, const void *, size_t);
+
+static ssize_t __ansiserial_write(struct file_info *fp, const void *buf, size_t count)
+{
+  __ansicon_write(fp, buf, count);
+  return __serial_write(fp, buf, count);
+}
+
+const struct output_dev dev_ansiserial_w = {
+  .dev_magic  = __DEV_MAGIC,
+  .flags      = __DEV_TTY | __DEV_OUTPUT,
+  .fileflags  = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND,
+  .write      = __ansiserial_write,
+  .close      = NULL,
+};
index 27fd73c..44f3137 100644 (file)
@@ -38,7 +38,7 @@
 #include <minmax.h>
 #include "file.h"
 
-static ssize_t __serial_write(struct file_info *fp, const void *buf, size_t count)
+ssize_t __serial_write(struct file_info *fp, const void *buf, size_t count)
 {
   com32sys_t ireg;
   const char *bufp = buf;
index af72f6b..cfd44b4 100644 (file)
@@ -35,7 +35,7 @@ LIBGCC    := $(shell $(CC) --print-libgcc)
 
 .SUFFIXES: .lss .c .o .elf .c32
 
-all: hello.c32
+all: hello.c32 fancyhello.c32
 
 .PRECIOUS: %.o
 %.o: %.S
diff --git a/com32/modules/fancyhello.c b/com32/modules/fancyhello.c
new file mode 100644 (file)
index 0000000..a59be43
--- /dev/null
@@ -0,0 +1,44 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Bostom MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * fancyhello.c
+ *
+ * Hello, World! using libcom32 and ASI console
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <console.h>
+
+int main(void)
+{
+  char buffer[1024];
+
+  /* Write both to the ANSI console and the serial port, if configured */
+  openconsole(&dev_stdcon_r, &dev_ansiserial_w);
+
+  printf("(lifesign)\r\n(another)\r\n(another)\r\n");
+  printf("\033[1;33;44m *** \033[37mHello, World!\033[33m *** \033[0m\r\n");
+
+  for (;;) {
+    printf("\033[1;36m>\033[0m ");
+    fgets(buffer, sizeof buffer, stdin);
+    /* fgets() prints an \n for us, but not \r */
+    putchar('\r');
+    if ( !strncmp(buffer, "exit", 4) )
+      break;
+    printf("\033[1m:\033[0m %s\r", buffer);
+  }
+  return 0;
+}
index 98964e0..7d0504b 100644 (file)
@@ -1,7 +1,7 @@
 #ident "$Id$"
 /* ----------------------------------------------------------------------- *
  *   
- *   Copyright 2002 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2004 H. Peter Anvin - All Rights Reserved
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by