Explorar el Código

Updated with initial console terminal code.

TODO:  Make it so that all the terminal routines
take a pointer to the console_details structure.
bugz hace 4 años
padre
commit
ab9be2d8a5
Se han modificado 1 ficheros con 319 adiciones y 45 borrados
  1. 319 45
      mystic.c

+ 319 - 45
mystic.c

@@ -194,6 +194,280 @@ void render_sleep(void) {
   }
 }
 
+/*
+Terminal tracking
+ */
+
+struct console_details {
+  int posx, posy;
+  int savedx, savedy;
+  char ansi[20]; // current ANSI command being processed.
+  int in_ansi;
+  int fgcolor; // 0-15
+  int bgcolor; // 0-7
+  int status;  // 0 or 5 (Blink)
+} console;
+
+void console_init(struct console_details *cdp) {
+  cdp->posx = 0;
+  cdp->posy = 0;
+  cdp->savedx = 0;
+  cdp->savedy = 0;
+  cdp->in_ansi = 0;
+  cdp->fgcolor = 0;
+  cdp->bgcolor = 0;
+  cdp->status = 0;
+}
+
+void console_ansi(const char *ansi) {
+  int understood = 0;
+  const char *cp = ansi;
+  const char *last = ansi + strlen(ansi) - 1;
+  int number, number2;
+
+  if (*cp == '\x1b') {
+    cp++;
+    // Ok, that's expected.
+    if (*cp == '[') {
+      cp++;
+
+      // https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences
+
+      switch (*last) {
+      case 'A':
+        // cursor up
+        if (cp == last) {
+          number = 1;
+        } else {
+          number = atoi(cp);
+          if (number < 1) {
+            ZF_LOGD("console_ansi( %s ): number error (%d)", repr(ansi), number);
+            number = 1;
+          }
+        };
+        console.posy -= number;
+        if (console.posy < 0) {
+          console.posy = 0;
+          ZF_LOGD("console_ansi( %s ): attempt to move above top of screen (%d)", repr(ansi), number);            
+        }
+        understood = 1;
+        return;
+      case 'B':
+        // cursor down
+        if (cp == last) {
+          number = 1;
+        } else {
+          number = atoi(cp);
+          if (number < 1) {
+            ZF_LOGD("console_ansi( %s ): number error (%d)", repr(ansi), number);
+            number = 1;
+          }
+        };
+        console.posy += number;
+        // check range/"scroll"
+        understood = 1;
+        return;
+
+      case 'C':
+        // cursor forward
+        if (cp == last) {
+          number = 1;
+        } else {
+          number = atoi(cp);
+          if (number < 1) {
+            ZF_LOGD("console_ansi( %s ): number error (%d)", repr(ansi), number);
+            number = 1;
+          }
+        };
+        console.posx += number;
+
+        // Well.  According to the "spec", the screen limits are hard
+        // If the cursor is already at the edge of the screen, this has no effect. 
+        // ^ This is *NOT* how any ANSI BBS terminal program acts!
+
+        while (console.posx > 79) {
+          console.posy++;
+          // check range/"scroll"
+          console.posx -= 79;
+        }
+        understood = 1;
+        return;
+
+      case 'D':
+        // cursor backwards
+        if (cp == last) {
+          number = 1;
+        } else {
+          number = atoi(cp);
+          if (number < 1) {
+            ZF_LOGD("console_ansi( %s ): number error (%d)", repr(ansi), number);
+            number = 1;
+          }
+        };
+        console.posx -= number;
+
+        // Well.  According to the "spec", the screen limits are hard
+        // If the cursor is already at the edge of the screen, this has no effect. 
+        // ^ This is *NOT* how any ANSI BBS terminal program acts!
+        
+        while (console.posx < 0) {
+          console.posy--;
+          if (console.posy < 0 ) {
+            console.posy = 0;
+          }
+          console.posx += 79;
+        }
+        understood = 1;
+        return;
+
+      case 'H':
+        // cursor position
+
+        if (*cp == ';') {
+          // Missing first number
+          number = 1;
+          cp++;
+          if (cp == last) {
+            // missing 2nd number as well?
+            number2 = 1;
+          } else {
+            number2 = atoi(cp);
+          }
+        } else {
+          // Ok, find the first number
+          number = atoi(cp);
+
+          cp = strchr(cp, ';');
+          if ( cp == NULL) {
+            // Missing 2nd number
+            number2 = 1;
+          } else {
+            // 2nd number found, maybe.
+            cp++;
+            if (cp == last) {
+              number2 = 1;
+            } else {
+              number2 = atoi(cp);
+            }
+          }
+        }
+
+        // Our positions start at zero, not one.
+        console.posx = number - 1;
+        console.posy = number2 - 1;
+
+        understood = 1;
+        break;
+
+      case 'J':   
+        // clear
+        if (cp == last) {
+          number = 0;
+        } else {
+          number = atoi(cp);
+        };
+
+        // clears ... part of the screen.
+        if (number == 2 ) {
+          console.posx = 0;
+          console.posy = 0;
+        };
+        understood = 1;
+        break;
+
+      default:
+        // unsure -- possibly not important
+        ZF_LOGD("console_ansi( %s ): ???", repr(ansi));        
+        understood = 0;
+      }
+    }
+  };
+
+  if (!understood) {
+    ZF_LOGD("console_ansi( %s ): was not understood.", repr(ansi));
+  }
+}
+
+void console_char(char ch) {
+  char *cp;
+
+  if (console.in_ansi) {
+    // Ok, append this char
+    cp = console.ansi + strlen(console.ansi);
+    *cp = ch;
+    cp++;
+    *cp = 0;
+    if (isalpha(ch)) {
+      // Ok!
+      console_ansi(console.ansi);
+      console.in_ansi = 0;
+      console.ansi[0] = 0;
+      return;
+    }
+  } else {
+    if (ch == '\x1b') {
+      cp = console.ansi;
+      *cp = ch;
+      cp++;
+      *cp = 0;
+      console.in_ansi = 1;
+      return;
+    }
+    if (ch == '\r') {
+      // Carriage return
+      console.posx = 0;
+      return;
+    }
+    if (ch == '\n') {
+      console.posy++;
+      // check range/"scroll"
+      return;
+    }
+    if (ch == '\b') {
+      // Backspace.
+      if (console.posx > 0) {
+        console.posx--;
+      }
+      return;
+    }
+    if (ch == '\f') {
+      // form feed
+      // treat as clear screen
+      console.posx = 0;
+      console.posy = 0;
+      return;
+    }
+
+    /*
+      I don't believe that anything else can possibly be here, other then an
+      actual printable character.  So!
+    */
+
+    console.posx++;
+
+    if (console.posx > 79) {
+      console.posx = 0;
+      console.posy++;
+      // check range/"scroll"
+    }
+  }
+}
+
+void console_string(const char *chars) {
+  int x;
+  for (x = 0; x < strlen(chars); x++) {
+    console_char(chars[x]);
+  }
+}
+
+void console_receive(const char *chars, int len) {
+  int x;
+
+  for (x = 0; x < len; x++) {
+    console_char(chars[x]);
+  }
+}
+
 /*
 Well SNAP!  Mystic numbers don't remotely match ANSI color codes.
 
@@ -232,7 +506,7 @@ Well SNAP!  Mystic numbers don't remotely match ANSI color codes.
  30 : Sets the current background to brown with blinking foreground     5;43
  31 : Sets the current background to grey with blinking foreground      5;47
 
-Other things that Mystic does ... 
+Other things that Mystic does ...
 
   [A## - Move the cursor up ## lines
   [B## - Move the cursor down ## lines
@@ -254,7 +528,7 @@ Other things that Mystic does ...
 
 // Covert MYSTIC color to (Proper) ANSI COLOR.
 
-const int MYSTIC[] = { 0, 4, 2, 6, 1, 5, 3, 7};
+const int MYSTIC[] = {0, 4, 2, 6, 1, 5, 3, 7};
 
 // ANSI_color = MYSTIC[ odd_mystic_color % 8 ]
 
@@ -262,49 +536,49 @@ void write_color(int fd, int color) {
   char buffer[10];
 
   switch (color) {
-    case 0:
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-    case 5:
-    case 6:
-    case 7:
-      sprintf(buffer, "\x1b[0;3%dm", MYSTIC[color]);
-      break;
-    case 8:
-    case 9:
-    case 10:
-    case 11:
-    case 12:
-    case 13:
-    case 14:
-    case 15:
-      sprintf(buffer, "\x1b[1;3%dm", MYSTIC[color - 8]);
-      break;
-    case 16:
-    case 17:
-    case 18:
-    case 19:
-    case 20:
-    case 21:
-    case 22:
-    case 23:
-      sprintf(buffer, "\x1b[4%dm", MYSTIC[color - 16]);
-      break;
-    case 24:
-    case 25:
-    case 26:
-    case 27:
-    case 28:
-    case 29:
-    case 30:
-    case 31:
-      sprintf(buffer, "\x1b[5;4%dm", MYSTIC[color - 24]);
-      break;
-    default:
-      buffer[0] = 0;
-      break;
+  case 0:
+  case 1:
+  case 2:
+  case 3:
+  case 4:
+  case 5:
+  case 6:
+  case 7:
+    sprintf(buffer, "\x1b[0;3%dm", MYSTIC[color]);
+    break;
+  case 8:
+  case 9:
+  case 10:
+  case 11:
+  case 12:
+  case 13:
+  case 14:
+  case 15:
+    sprintf(buffer, "\x1b[1;3%dm", MYSTIC[color - 8]);
+    break;
+  case 16:
+  case 17:
+  case 18:
+  case 19:
+  case 20:
+  case 21:
+  case 22:
+  case 23:
+    sprintf(buffer, "\x1b[4%dm", MYSTIC[color - 16]);
+    break;
+  case 24:
+  case 25:
+  case 26:
+  case 27:
+  case 28:
+  case 29:
+  case 30:
+  case 31:
+    sprintf(buffer, "\x1b[5;4%dm", MYSTIC[color - 24]);
+    break;
+  default:
+    buffer[0] = 0;
+    break;
   }
   ZF_LOGD("write_color( %d ): %s", color, repr(buffer));
   write(fd, buffer, strlen(buffer));