- Expand text attributes word from 8-bit to 16-bit
authorMatthew Mondor <mmondor@pulsar-zone.net>
Sat, 9 Apr 2022 11:28:51 +0000 (11:28 +0000)
committerMatthew Mondor <mmondor@pulsar-zone.net>
Sat, 9 Apr 2022 11:28:51 +0000 (11:28 +0000)
- Adapt functions for the larger attributes/mode word
- Reimplement delete-char using clear/move
- Cleanup old cursor related code
- Implement more text attributes
  - double underline
  - strike
  - invisible
- Make conditional unused blink related code

MATT/TODO.txt
MATT/test/m.sh
hacks/analogterm-main.c
hacks/analogterm.c
hacks/analogterm.h

index c394388..d53991d 100644 (file)
@@ -3,9 +3,8 @@ BUILD
 - make
 
 TODO
-- All uint8_t mode bits are already allocated.  Ideally we would need a larger
-  word but this will affect operations using memset(3), memmove(3) and
-  memcpy(3).  Double-underline, italics and striked currently lack a mode bit.
+- When blinking and double-underline, the line doesn't blink.
+- Italics is currently mapped to inverse, like in rxvt.
 - There's an apparent bug in utf8wc.c's utf8_split() function.
   Does not appear to be used by analogterm itself but is included
   as a module because of other functions in use.
index bf8ec25..9182049 100755 (executable)
@@ -1,4 +1,5 @@
 #!/bin/sh
-printf '\033[1mbold\033[m \033[2mdim\033[m \033[3mitalic\033[m \033[4munderline\033[m \033[5mblink\033[m \033[6mbold\033[m \033[7minverse\033[m \033[8minvisible\033[m \033[9mstriked\033[m \033[21mdouble-underline\033[m\n'
+printf '\033[1mbold\033[m \033[2mdim\033[m \033[3mitalic\033[m \033[4munderline\033[m \033[5mblink\033[m \033[6mbold\033[m \033[7minverse\033[m \033[8minvisible\033[m \033[9mStriked\033[m \033[21mdouble-underline\033[m\n'
 printf '\033[1m\033[7mBoldInverse\033[m \033[1m\033[5mBoldBlink\033[m \033[7m\033[5mInverseBlink\033[m \033[1m\033[5m\033[7mBoldInverseBlink\033[m\n'
 printf '\033[2m\033[7mDimInverse\033[m \033[2m\033[5mDimBlink\033[m \033[7m\033[5mInverseBlink\033[m \033[2m\033[5m\033[7mDimInverseBlink\033[m\n'
+printf '\033[4m\033[5mUnderBlink\033[m \033[5m\033[21mDUnderBlink\033[m \033[4m\033[7mUnderInverse\033[m \033[21m\033[7mDUnderInverse\033[m \033[4m\033[9mUnderStrike\033[m\n'
index c663643..6e82ed0 100644 (file)
@@ -103,7 +103,7 @@ struct terminal_controller_data {
   int cursor_x, cursor_y;
   int saved_x,  saved_y;
   int unicruds; char unicrud[7];
-  unsigned char mode;
+  uint16_t mode;
   Bool fast_p;
 };
 
@@ -172,7 +172,7 @@ unsupported(struct terminal_controller_data *state, int statei, char statec,
 }
 
 static void
-at_ascii_printc (analogterm_state_t *st, unsigned char c, unsigned char m,
+at_ascii_printc (analogterm_state_t *st, unsigned char c, uint16_t m,
                 Bool scroll_p)
 {
 
@@ -688,7 +688,6 @@ at_vt100_printc (analogterm_sim_t *sim, struct terminal_controller_data *state,
                  state->mode &= ~TMODE_BOLD;
                   break;
                case 4:
-               case 21: /* FALLTHROUGH (doubly underline) */
                  state->mode |= TMODE_UNDERLINE;
                  break;
                 case 5:
@@ -698,9 +697,14 @@ at_vt100_printc (analogterm_sim_t *sim, struct terminal_controller_data *state,
                 case 7: /* FALLTHROUGH */
                  state->mode |= TMODE_INVERSE;
                   break;
-               case 8: /* XXX Invisible, not yet implemented. */
+               case 8: /* Invisible */
+                 state->mode |= TMODE_INVISIBLE;
                  break;
-               case 9: /* XXX Striked, not yet implemented. */
+               case 9:
+                 state->mode |= TMODE_STRIKE;
+                 break;
+               case 21:
+                 state->mode |= TMODE_DUNDERLINE;
                  break;
                /* XXX Enable colors, converted to other attributes */
                /* Foreground color */
@@ -751,7 +755,7 @@ at_vt100_printc (analogterm_sim_t *sim, struct terminal_controller_data *state,
                  state->mode &= ~(TMODE_BOLD | TMODE_DIM);
                   break;
                case 24:
-                 state->mode &= ~TMODE_UNDERLINE;
+                 state->mode &= ~(TMODE_UNDERLINE | TMODE_DUNDERLINE);
                  break;
                 case 25:
                  state->mode &= ~TMODE_BLINK;
@@ -760,9 +764,11 @@ at_vt100_printc (analogterm_sim_t *sim, struct terminal_controller_data *state,
                 case 27: /* FALLTHROUGH */
                  state->mode &= ~TMODE_INVERSE;
                   break;
-               case 28: /* XXX Visible, not yet implemented. */
+               case 28: /* Visible, not yet implemented. */
+                 state->mode &= ~TMODE_INVISIBLE;
                  break;
-               case 29: /* XXX Not striked, not yet implemented. */
+               case 29:
+                 state->mode &= ~TMODE_STRIKE;
                  break;
                 case 39: /* Default fg color */
                  state->mode &= ~TMODE_FGCOLOR;
@@ -794,30 +800,18 @@ at_vt100_printc (analogterm_sim_t *sim, struct terminal_controller_data *state,
          /*
           * Interestingly, in this case both dhc1 and dch with 0 are
           * considered equivalent.  dch <n> > 1 delete more than 1.
-          * XXX Could use at_move() and at_clear().
           */
          many = (state->csiparam[0] > 1 ? state->csiparam[0] : 1);
          if (many >= cols - st->cursx) {
              /* Clear rest of line in this case, like K */
              many = cols - st->cursx;
-             (void)memset(&st->textlines_char[st->cursy][st->cursx], ' ',
-                 many);
-             (void)memset(&st->textlines_mode[st->cursy][st->cursx],
-                 state->mode & TMODE_BGCOLOR, many);
+             at_clear(st, st->cursx, st->cursy, many);
          } else {
-             unsigned char *cptr;
-
              /* Move n chars from right to left */
-             cptr = &st->textlines_char[st->cursy][st->cursx];
-             (void)memmove(cptr, &cptr[many], cols - st->cursx - many);
-             cptr = &st->textlines_mode[st->cursy][st->cursx];
-             (void)memmove(cptr, &cptr[many], cols - st->cursx - many);
+             at_move(st, st->cursx, st->cursy, st->cursx + many, st->cursy,
+                     cols - st->cursx - many);
              /* Fill hole at right with emptyness */
-             /* XXX Make sure this is the correct implementation */
-             cptr = &st->textlines_char[st->cursy][cols];
-             (void)memset(&cptr[-many], ' ', many);
-             cptr = &st->textlines_mode[st->cursy][cols];
-             (void)memset(&cptr[-many], state->mode & TMODE_BGCOLOR, many);
+             at_clear(st, cols - many, st->cursy, many);
          }
          state->escstate = 0;
          break;
index 2daec2d..c5ddb5e 100644 (file)
@@ -68,15 +68,19 @@ at_move(analogterm_state_t *st, int dx, int dy, int sx, int sy, int len)
        (void)memmove(&st->textlines_char[dy][dx],
            &st->textlines_char[sy][sx], len);
        (void)memmove(&st->textlines_mode[dy][dx],
-           &st->textlines_mode[sy][sx], len);
+           &st->textlines_mode[sy][sx], len * sizeof(uint16_t));
 }
 
 void
 at_clear(analogterm_state_t *st, int x, int y, int len)
 {
+       int f, t;
+       uint16_t *mptr, *tptr;
 
        (void)memset(&st->textlines_char[y][x], ' ', len);
-       (void)memset(&st->textlines_mode[y][x], st->mode & TMODE_BGCOLOR, len);
+       for (mptr = &st->textlines_mode[y][x], tptr = &mptr[len];
+            mptr < tptr; mptr++)
+               *mptr = st->mode & TMODE_BGCOLOR;
 }
 
 /*
@@ -86,26 +90,24 @@ void
 at_insert(analogterm_state_t *st, int many)
 {
        unsigned char *cptr;
+       uint16_t *mptr, *tptr;
        int s;
 
        if (many < 1)
                return;
 
-       /* Disable cursor */
-       /*st->textlines_mode[st->cursy][st->cursx] &= ~TMODE_BLINK;*/
-
        if (many > 80 - st->cursx)
                many = 80 - st->cursx;
        s = 80 - st->cursx - many;
+
        cptr = &st->textlines_char[st->cursy][st->cursx];
        (void)memmove(&cptr[many], cptr, s);
        (void)memset(cptr, ' ', many);
-       cptr = &st->textlines_mode[st->cursy][st->cursx];
-       (void)memmove(&cptr[many], cptr, s);
-       (void)memset(cptr, st->mode & TMODE_BGCOLOR, many);
 
-       /* Restore cursor, may not always be necessary */
-       /*st->textlines_mode[st->cursy][st->cursx] |= TMODE_BLINK;*/
+       mptr = &st->textlines_mode[st->cursy][st->cursx];
+       (void)memmove(&mptr[many], mptr, s * sizeof(uint16_t));
+       for (tptr = &mptr[many]; mptr < tptr; mptr++)
+               *mptr = st->mode & TMODE_BGCOLOR;
 }
 
 static signed char cursorstate = 127;
@@ -130,9 +132,12 @@ at_drawcursor(analogterm_sim_t *sim)
        }*/
 
        /* Block cursor, a bit bizarre for now :) */
-       /* XXX This memory design is very inefficient */
-       /* XXX Should probably use a well defined range instead of cycling
-        * completely. */
+       /*
+        * XXX
+        * - This memory design is very inefficient
+        * - Should probably use a well-defined range instead of full cycle
+        * - Blinking speed should rely in a configurable timer
+        */
        for (y = 0; y < 8; y++) {
                pp = &sim->inp->signal[(ANALOGTV_TOP+3) + (8 * st->cursy) + y]
                   [(ANALOGTV_PIC_START+100) + (7 * st->cursx)];
@@ -173,20 +178,16 @@ at_scroll_range(analogterm_state_t *st, int offset)
        if (offset == 0)
                return;
 
-       /* Disable cursor */
-       /*st->textlines_mode[st->cursy][st->cursx] &= ~TMODE_BLINK;*/
-
        /* Only one line to clear */
        if (st->scroll_top == st->scroll_bottom) {
                at_clear(st, 0, st->cursy, 80);
-               /*goto done;*/
                return;
        }
+
        /* Nothing to move, clear whole scrolling region */
        if (abs(offset) > st->scroll_bottom - st->scroll_top) {
                for (y = st->scroll_top; y < st->scroll_bottom; y++)
                        at_clear(st, 0, y, 80);
-               /*goto done;*/
                return;
        }
 
@@ -205,10 +206,6 @@ at_scroll_range(analogterm_state_t *st, int offset)
                for (y = st->scroll_top; offset > 0; offset--, y++)
                        at_clear(st, 0, y, 80);
        }
-
-/*done:*/
-       /* Restore cursor, may not always be necessary */
-       /*st->textlines_mode[st->cursy][st->cursx] |= TMODE_BLINK;*/
 }
 
 void
@@ -218,10 +215,11 @@ at_scroll(analogterm_state_t *st)
        at_scroll_range(st, -1);
 }
 
+/* XXX Mode could use a state structure */
 static void
-at_printc_1(analogterm_state_t *st, char c, unsigned char m, int scroll_p)
+at_printc_1(analogterm_state_t *st, char c, uint16_t m, int scroll_p)
 {
-  /*st->textlines_mode[st->cursy][st->cursx] &= ~TMODE_BLINK;*/ /* turn off blink */
+
   at_resetcursor();
 
   if (c == '\n')                      /* ^J == NL */
@@ -273,25 +271,23 @@ at_printc_1(analogterm_state_t *st, char c, unsigned char m, int scroll_p)
         st->cursx=0;
       }
     }
-
-  /*st->textlines_mode[st->cursy][st->cursx] |= TMODE_BLINK;*/ /* turn on blink */
 }
 
 void
-at_printc(analogterm_state_t *st, char c, unsigned char m)
+at_printc(analogterm_state_t *st, char c, uint16_t m)
 {
   at_printc_1(st, c, m, 1);
 }
 
 void
-at_printc_noscroll(analogterm_state_t *st, char c, unsigned char m)
+at_printc_noscroll(analogterm_state_t *st, char c, uint16_t m)
 {
   at_printc_1(st, c, m, 0);
 }
 
 
 void
-at_prints(analogterm_state_t *st, char *s, unsigned char m)
+at_prints(analogterm_state_t *st, char *s, uint16_t m)
 {
   while (*s) at_printc(st, *s++, m);
 }
@@ -301,10 +297,10 @@ at_goto(analogterm_state_t *st, int r, int c)
 {
   if (r > 24) r = 24;
   if (c > 79) c = 79;
-  /*st->textlines_mode[st->cursy][st->cursx] &= ~TMODE_BLINK;*/ /* turn off blink */
-  st->cursy=r;
-  st->cursx=c;
-  /*st->textlines_mode[st->cursy][st->cursx] |= TMODE_BLINK;*/ /* turn on blink */
+
+  st->cursy = r;
+  st->cursx = c;
+
   at_resetcursor();
 }
 
@@ -315,11 +311,14 @@ at_goto(analogterm_state_t *st, int r, int c)
 void
 at_cls(analogterm_state_t *st)
 {
-  int i;
-
-  for (i=0; i<25; i++) {
-    memset(st->textlines_char[i], ' ', 80);
-    memset(st->textlines_mode[i], st->mode & TMODE_BGCOLOR, 80);
+  int y;
+  uint16_t *mptr, *tptr;
+
+  for (y = 0; y < 25; y++) {
+    memset(st->textlines_char[y], ' ', 80);
+    for (mptr = st->textlines_mode[y], tptr = &mptr[80];
+        mptr < tptr; mptr++)
+           *mptr = st->mode & TMODE_BGCOLOR;
   }
 }
 
@@ -451,6 +450,8 @@ analogterm_one_frame (analogterm_sim_t *sim)
        reasonable. (I soldered a resistor in mine to make it blink faster.) */
     i=st->blink;
     st->blink=((int)blinkphase)&1;
+
+#if 0
     if (st->blink!=i && !(st->gr_mode&A2_GR_FULL)) {
       int downcounter=0;
       /* For every row with blinking text, set the changed flag. This basically
@@ -459,8 +460,8 @@ analogterm_one_frame (analogterm_sim_t *sim)
       int row, col;
       for (row=(st->gr_mode ? 20 : 0); row<25; row++) {
         for (col=0; col<80; col++) {
-          int c = st->textlines_mode[row][col];
-          if ((c & TMODE_BLINK) != 0) {
+          uint16_t m = st->textlines_mode[row][col];
+          if ((m & TMODE_BLINK) != 0) {
             downcounter=4;
             break;
           }
@@ -470,6 +471,7 @@ analogterm_one_frame (analogterm_sim_t *sim)
         }
       }
     }
+#endif
 
     if (sim->curtime >= sim->delay)
       sim->stepno = A2CONTROLLER_DONE;
@@ -566,6 +568,7 @@ analogterm_one_frame (analogterm_sim_t *sim)
         signed char *pp;
        int col;
        int lastrow = row == textrow * 8 + 7;
+       int midrow = row == textrow * 8 + 3;
 
         /* First we generate the pattern that the video circuitry shifts out
            of memory. It has a 14.something MHz dot clock, equal to 4 times
@@ -577,9 +580,9 @@ analogterm_one_frame (analogterm_sim_t *sim)
        pp=&sim->inp->signal[row+ANALOGTV_TOP+/*4*/3][ANALOGTV_PIC_START+100];
        for (col=0; col<80; col++) {
             int rev, level, olevel, iblink;
-            int c = st->textlines_char[textrow][col] & 0xff;
-           unsigned char m = st->textlines_mode[textrow][col] & 0xff;
-           XImage *im = sim->text_im[m & TMODE_GFX ? 1 : 0];
+            int c = st->textlines_char[textrow][col] & 0xff; /* XXX */
+           uint16_t m = st->textlines_mode[textrow][col];
+           XImage *im = sim->text_im[(m & TMODE_GFX) != 0 ? 1 : 0];
 
            rev = ((m & (TMODE_INVERSE | TMODE_BGCOLOR)) != 0);
 
@@ -611,9 +614,19 @@ analogterm_one_frame (analogterm_sim_t *sim)
 
                if (c < 32 || c > 126)
                        c = 32;
-               pix = XGetPixel(im, (c - 32) * 7 + i, row % 8);
-               if ((m & TMODE_UNDERLINE) != 0 && lastrow)
+               if ((m & TMODE_INVISIBLE) != 0)
+                       pix = 0;
+               else
+                       pix = XGetPixel(im, (c - 32) * 7 + i, row % 8);
+
+               if (lastrow &&
+                   (m & (TMODE_UNDERLINE | TMODE_DUNDERLINE)) != 0) {
+                       pix = 1;
+                       if ((m & TMODE_DUNDERLINE) != 0)
+                               level = olevel = TMODE_BOLD_LEVEL;
+               } else if (midrow && (m & TMODE_STRIKE) != 0)
                        pix = 1;
+
                if (iblink) {
                        if (!pix)
                                pix = olevel;
@@ -636,4 +649,3 @@ analogterm_one_frame (analogterm_sim_t *sim)
  
     return 1;
 }
-
index a19e4f8..8722fe1 100644 (file)
 #include "analogtv.h"
 
 
-#define TMODE_INVERSE  (1 << 0)
-#define TMODE_BLINK    (1 << 1)
-#define TMODE_BOLD     (1 << 2)
-#define TMODE_UNDERLINE        (1 << 3)
-#define TMODE_DIM      (1 << 4)
-#define TMODE_GFX      (1 << 5)
-/* We implement these with inverse and dim */
-#define TMODE_FGCOLOR  (1 << 6)
-#define TMODE_BGCOLOR  (1 << 7)
+/* Text attributes */
+
+#define TMODE_BOLD             (1L << 0)
+#define TMODE_DIM              (1L << 1)
+#define TMODE_ITALIC           (1L << 2)
+#define TMODE_UNDERLINE                (1L << 3)
+#define TMODE_BLINK            (1L << 4)
+#define TMODE_INVERSE          (1L << 5)
+#define TMODE_INVISIBLE                (1L << 6)
+#define TMODE_STRIKE           (1L << 7)
+#define TMODE_DUNDERLINE       (1L << 8)
+#define TMODE_GFX              (1L << 9)
+/* We implement these pseudocolors with attributes */
+#define TMODE_FGCOLOR          (1L << 10)
+#define TMODE_BGCOLOR          (1L << 11)
 
 #define TMODE_NORMAL_LEVEL     (ANALOGTV_WHITE_LEVEL - 35)
 #define TMODE_BOLD_LEVEL       (ANALOGTV_WHITE_LEVEL + 25)
@@ -38,7 +44,7 @@
 typedef struct analogterm_state {
   unsigned char hireslines[192][80];
   unsigned char textlines_char[25][80]; /* XXX Use definition/macro */
-  unsigned char textlines_mode[25][80];
+  uint16_t textlines_mode[25][80];
   int gr_text;
   enum {
     A2_GR_FULL=1,
@@ -47,7 +53,7 @@ typedef struct analogterm_state {
   } gr_mode;
   int cursx;
   int cursy;
-  int mode;
+  uint16_t mode;
   int blink; /* XXX Still needed? */
   int scroll_top, scroll_bottom;
   int lastchar;
@@ -129,9 +135,9 @@ void at_add_disk_item(analogterm_state_t *st, char *name, unsigned char *data,
                       int len, char type);
 void at_scroll_range(analogterm_state_t *st, int offset);
 void at_scroll(analogterm_state_t *st);
-void at_printc(analogterm_state_t *st, char c, unsigned char m);
-void at_printc_noscroll(analogterm_state_t *st, char c, unsigned char m);
-void at_prints(analogterm_state_t *st, char *s, unsigned char m);
+void at_printc(analogterm_state_t *st, char c, uint16_t m);
+void at_printc_noscroll(analogterm_state_t *st, char c, uint16_t m);
+void at_prints(analogterm_state_t *st, char *s, uint16_t m);
 void at_goto(analogterm_state_t *st, int r, int c);
 void at_cls(analogterm_state_t *st);
 void at_clear_hgr(analogterm_state_t *st);