Browse Source

Working buffers / timeouts.

This changes everything.  Instead
of working with c null term strings,
everything moves to using char * +
length.

We can now handle null values in the
buffer.

One of the bugs was in mangler.
It can no longer use the buffer --
because we process the buffer in
chunks ending in "\r\n"!
(It now has own buffer [2K].)

If we insert, we overwrite the pending/
buffered data.
bugz 4 years ago
parent
commit
1b60b2a1bf
1 changed files with 255 additions and 93 deletions
  1. 255 93
      mystic.cpp

+ 255 - 93
mystic.cpp

@@ -197,6 +197,24 @@ int randrange(int M, int N) {
   return M + rand() / (RAND_MAX / (N - M + 1) + 1);
 }
 
+/*
+ * strnstr()
+ *
+ * buffer safe version that looks for a string.
+ */
+const char *strnstr(const char *source, int len, const char *needle) {
+  int pos;
+
+  for (pos = 0; pos < len; pos++) {
+    if (source[pos] == needle[0]) {
+      if (strncmp(source + pos, needle, strlen(needle)) == 0) {
+        return source + pos;
+      }
+    }
+  }
+  return NULL;
+}
+
 /*
 What is the name of the actual, real Mystic executable
 that we'll be executing and mangling?
@@ -204,7 +222,7 @@ that we'll be executing and mangling?
 
 #define TARGET "./mySTIC"
 // Size of our input and output buffers.
-#define BSIZE 128
+#define BSIZE 1024
 
 /*
  * string_insert()
@@ -1016,21 +1034,23 @@ void render_effect(int fd, char ch) {
  * Handles TRIGGER.
  * Renders with effects.
  */
-void render(int fd, const char *string_out) {
+void render(int fd, const char *string_out, int len) {
   const char *cp = string_out;
   const char *trigger = cp;
+
   time_t start = time(NULL);
   int elapsed;
   int over = 0;
 
   reset_render();
 
-  ZF_LOGV("render(%d, %s)", fd, repr(string_out));
+  // ZF_LOGV("render(%d, %s)", fd, repr(string_out));
+  ZF_LOGV_MEM(string_out, len, "render(%d, %d bytes):", fd, len);
 
   // Check our time from time to time.
   // If we start running long, disable sleeps.
 
-  while ((trigger = strstr(cp, TRIGGER)) != NULL) {
+  while ((trigger = strnstr(cp, len - (cp - trigger), TRIGGER)) != NULL) {
     // There is special things to handle in here.
     while (cp != trigger) {
       elapsed = time(NULL) - start;
@@ -1054,7 +1074,7 @@ void render(int fd, const char *string_out) {
   };
 
   // We still might be under a rendering effect.
-  while (*cp != 0) {
+  while (cp < (string_out + len)) {
     elapsed = time(NULL) - start;
     if (elapsed > SLEEP_LIMIT) {
       render_overlimit = 1;
@@ -1126,7 +1146,7 @@ void harry_idle_event(int fd) {
 
   sprintf(buffer, "^S2^C%02d%s^P2^CR^D%02d", color, cp, (int)strlen(cp));
   ZF_LOGD("harry_event: render(%d, \"%s\")", fd, buffer);
-  render(fd, buffer);
+  render(fd, buffer, strlen(buffer));
 }
 
 void init_harry() {
@@ -1228,7 +1248,7 @@ int regmatch(regex_t *preg, const char *string, size_t nmatch,
 
   while (matches < nmatch) {
     int ret = regexec(preg, string + offset, nmatch - matches, pmatch + matches,
-                  eflags);
+                      eflags);
     if (!ret) {
       int current = offset;
       offset += pmatch[matches].rm_eo;
@@ -1393,27 +1413,45 @@ int word_mangler(char *buffer, int len) {
   return count;
 }
 
+int buffer_insert(char *buffer, int len, int max_length, int pos,
+                  const char *insert) {
+  if (len + strlen(insert) > max_length) {
+    ZF_LOGD("buffer_insert failed [%s]", repr(insert));
+    return 0;
+  }
+  memmove(buffer + pos + strlen(insert), buffer + pos, len - pos);
+  strncpy(buffer + pos, insert, strlen(insert));
+  return 1;
+}
+
 /*
  * The buffer that we've been given is much larger now.
  *
+ * We can no longer mangle or insert into the given buffer.
+ * Why?  Because we don't know what is behind it now!
  */
-int mangle(int fd, char *buffer) {
+int mangle(int fd, const char *buffer, int len) {
   int x, i;
   int need_render = 0; // changing word case around doesn't need the render
   int mangled = 0;
   int mangled_chars = 0;
+  char play[2048];
+  const char *cp;
 
-  char *cp;
+  memcpy(play, buffer, len);
+
+  // NEVER reference buffer from this point on!
 
   // Ok, we want to look for words to:
   // MaNGlE , or transpose (both?!)
   // or possibly transpose words
-  char work[(BSIZE * 4) + 1];
+  char work[2048];
 
   // Use terminal - clean out ANSI
 
-  ZF_LOGI("mangle:");
-  ZF_LOGI_REPR(buffer);
+  // ZF_LOGI("mangle:");
+  ZF_LOGI_MEM(play, len, "Mangle (%u bytes):", len);
+
   // strcpy(work, buffer);
 
   /*
@@ -1430,7 +1468,7 @@ int mangle(int fd, char *buffer) {
       display ANSI graphic file, with delays ... then CLS
    */
   const char *ANSI_CLS = "\x1b[2J";
-  cp = strstr(buffer, ANSI_CLS);
+  cp = strnstr(play, len, ANSI_CLS); // strstr(buffer, ANSI_CLS);
 
   if (cp != NULL) {
     static int ANSI_CLS_count = 0; // count the number we've seen
@@ -1445,7 +1483,7 @@ int mangle(int fd, char *buffer) {
       // Make exact copy of our current console state.
       memcpy(&temp_console, &console, sizeof(console));
       // Play the buffer into the console
-      console_receive(&temp_console, buffer, cp - buffer);
+      console_receive(&temp_console, play, cp - play);
       char restore_color[30]; // ansi color
       strcpy(restore_color, color_restore(&temp_console));
 
@@ -1457,11 +1495,10 @@ int mangle(int fd, char *buffer) {
           const char *filename;
           int cls;
           int rand_pos;
-        } possibles[] = {{"goofy_head", 1, 0}, {"bat", 1, 0},
-                         {"panther", 1, 0},    {"wolf", 1, 0},
-                         {"skull", 0, 1},      {"skull2", 0, 1},
-                         {"guy", 0, 1},        {"blinkman", 0, 1},
-                         {"ghost", 1, 0}};
+        } possibles[] = {
+            {"goofy_head", 1, 0}, {"bat", 1, 0},      {"panther", 1, 0},
+            {"wolf", 1, 0},       {"skull", 0, 1},    {"skull2", 0, 1},
+            {"guy", 0, 1},        {"blinkman", 0, 1}, {"ghost", 1, 0}};
 
         //          bat.ans       creature.ans  goofy_head.ans  panther.ans
         //          skull.ans       ghost.ans
@@ -1501,18 +1538,23 @@ int mangle(int fd, char *buffer) {
         ZF_LOGI("mangle(ANSI_CLS): %d file inserted %s", r, repr(display));
 
         // Move the buffer so there's room for the display string.
-        if (string_insert(buffer, BSIZE * 4, cp - buffer, display)) {
-          ZF_LOGI("mangle(ANSI_CLS):");
-          ZF_LOGI_REPR(buffer);
-          ZF_LOGI("mangle(ANSI_CLS): [%s]", repr(buffer));
+        if (buffer_insert(play, len, sizeof(play), cp - play, display)) {
+          len += strlen(display);
+          // if (string_insert(buffer, 1024, cp - buffer, display)) {
+
+          ZF_LOGI_MEM(play, len, "mangle(ANSI_CLS) (%u bytes):", len);
+          // ZF_LOGI("mangle(ANSI_CLS):");
+          // ZF_LOGI_REPR(buffer);
+          // ZF_LOGI("mangle(ANSI_CLS): [%s]", repr(buffer));
           need_render = 1;
 
           /*
           Copy the new buffer over, but hide our "render" code
           from the remaining mangler steps.
           */
-          strcpy(work, buffer);
-          i = cp - buffer;
+          memcpy(work, play, len);
+          // strcpy(work, buffer);
+          i = cp - play;
           // find offset into "buffer"
           // apply to work.
           memset(work + i, ' ', strlen(display));
@@ -1563,20 +1605,27 @@ int mangle(int fd, char *buffer) {
 
           // sprintf(display, "^P1^S3^C%02d%s^S0^R0%s^P1", color, phrasing[r],
           // restore_color);
-          ZF_LOGI("mangle(ANSI_CLS): Inserted (%02d) %s", color, phrasing[r]);
+          // ZF_LOGI("mangle(ANSI_CLS): Inserted (%02d) %s", color,
+          // phrasing[r]);
+          ZF_LOGI_MEM(play, len, "mangle(ANSI_CLS) :");
 
           // Move the buffer so there's room for the display string.
-          if (string_insert(buffer, BSIZE * 4, cp - buffer, display)) {
-            ZF_LOGI("mangle(ANSI_CLS):");
-            ZF_LOGI_REPR(buffer);
+          if (buffer_insert(play, len, 1024, cp - play, display)) {
+            len += strlen(display);
+
+            // if (string_insert(buffer, BSIZE * 4, cp - buffer, display)) {
+            ZF_LOGI_MEM(play, len, "mangle(ANSI_CLS) + :");
+            // ZF_LOGI("mangle(ANSI_CLS):");
+            // ZF_LOGI_REPR(buffer);
             need_render = 1;
 
             /*
             Copy the new buffer over, but hide our "render" code
             from the remaining mangler steps.
             */
-            strcpy(work, buffer);
-            i = cp - buffer;
+            memcpy(work, play, len);
+            // strcpy(work, buffer);
+            i = cp - play;
             // find offset into "buffer"
             // apply to work.
             memset(work + i, ' ', strlen(display));
@@ -1589,19 +1638,30 @@ int mangle(int fd, char *buffer) {
     }
   }
 
-  strcpy(work, buffer); // sure.
+  memcpy(work, play, len);
+
+  // strcpy(work, buffer); // sure.
 
   const char replace_with = ' ';
-  for (x = 0; x < strlen(buffer); x++) {
-    int ansi = console_char(&console, buffer[x]);
+  for (x = 0; x < len; x++) {
+    int ansi = console_char(&console, play[x]);
     if (ansi) {
       work[x] = replace_with;
     }
+    // fixup "work" so it's a valid C string
+    if (buffer[x] == 0) {
+      work[x] = replace_with;
+    }
   }
+  // fixup "work" buffer so it's a valid c string
+  work[len] = 0;
 
+  ZF_LOGI_MEM(work, len, "Work now:");
+  /*
   ZF_LOGD("work now:");
   ZF_LOGD_REPR(work);
   ZF_LOGD("Work Now: [%s]", repr(work));
+  */
 
 #ifdef OLD_WAY
 
@@ -1632,7 +1692,7 @@ int mangle(int fd, char *buffer) {
 
       // Yes!  Be random!
       if (random_activate(8)) {
-        int c = word_mangler(buffer + rxmatch[i].rm_so,
+        int c = word_mangler(play + rxmatch[i].rm_so,
                              rxmatch[i].rm_eo - rxmatch[i].rm_so);
         if (c) {
           mangled++;
@@ -1653,18 +1713,21 @@ int mangle(int fd, char *buffer) {
    */
 
   if (need_render) {
-    ZF_LOGD("HH %d : (%d) %s", need_render, (int)strlen(buffer), repr(buffer));
+    ZF_LOGD_MEM(play, len, "Ready to render:");
+    // ZF_LOGD("HH %d : (%d) %s", need_render, (int)strlen(buffer), repr(buffer));
   } else {
     if (mangled) {
-      ZF_LOGD("Mangled %d words, %d chars : %s", mangled, mangled_chars,
-              repr(buffer));
+      ZF_LOGD_MEM(play, len, "Mangled %d words, %d chars:", mangled,
+                  mangled_chars);
+      /* ZF_LOGD("Mangled %d words, %d chars : %s", mangled, mangled_chars,
+              repr(buffer)); */
     }
   }
 
   if (need_render) {
-    render(fd, buffer);
+    render(fd, play, len);
   } else {
-    write(fd, buffer, strlen(buffer));
+    write(fd, play, len); // strlen(buffer));
   };
   return need_render && mangled;
 }
@@ -1686,7 +1749,7 @@ int harry_happens(time_t *last_event, int wakeup) {
 TO FIX:  Stop using c strings, must use char * buffer + int length.
 MAY CONTAIN NULL VALUES.
 
-Rework some things here.  
+Rework some things here.
 
 Here's the "plan":
 
@@ -1705,10 +1768,11 @@ Here's the "plan":
 
   ON READ:
     read/append to current buffer.
-    We can't use nulls -- what if they are using ZModem, there's nulls in the file!
-    Look for trailing  / the very last "\r\n".  
+    We can't use nulls -- what if they are using ZModem, there's nulls in the
+file! Look for trailing  / the very last "\r\n".
 
-    (I could mangle/chunk it line by line.  But I'm not sure I'd need to do that.)
+    (I could mangle/chunk it line by line.  But I'm not sure I'd need to do
+that.)
 
     Optional "mangle" buffer up to that very point -- and send up to that point.
 
@@ -1722,14 +1786,59 @@ Here's the "plan":
     else:
       Ok, we *STILL* haven't received any more characters into the buffer --
       even after waiting.  (Maybe we haven't waited long enough?)
-      send the pending information in the buffer and clear it out. 
+      send the pending information in the buffer and clear it out.
       Maybe this is a prompt, and there won't be a \r\n.
 
 This allows for cleaner process of "lines" of buffer.  We shouldn't break
 in the midDLE OF A WORD.  Downside is that we sit on buffer contents a little
 while / some amount of time -- which will add some lag to prompts showing up.
 
+
+ZModem:
+
+    start:  "rz^M**"...
+
+    05-12 18:12:15.916 >> rz^M**^XB00000000000000^M<8A>^Q
+    05-12 18:12:15.928 << **\x18B0100000023be50\r\n\x11
+    05-12 18:12:15.928 >> *^XC^D
+    05-12 18:12:15.939 << **\x18B0900000000a87c\r\n\x11
+    05-12 18:12:15.940 >> *^XC
+    # Start of PK zipfile.
+    05-12 18:12:15.941 >> PK^C^D^T
+
+    end:
+    05-12 18:26:38.700 << **\x18B0100000023be50\r\n\x11
+    05-12 18:26:38.700 >> **^XB0823a77600344c^M<8A>
+    05-12 18:26:38.711 << **\x18B0800000000022d\r\n
+    05-12 18:26:38.712 >> OO^MESC[0m
+
+ */
+
+/*
+ * rstrnstr() Reverse string find in a string
+ *
+ * This obeys the len, and handles nulls in buffer.
+ * find is a c-string (null terminated)
  */
+int rstrnstr(const char *buffer, int len, const char *find) {
+  int flen = strlen(find);
+
+  if (len < flen) {
+    // I can't find a string in a buffer smaller then it is!
+    return -1;
+  }
+  int pos = len - flen;
+  while (pos > 0) {
+    if (buffer[pos] == find[0]) {
+      // First chars match, check them all.
+      if (strncmp(buffer + pos, find, flen) == 0) {
+        return pos;
+      }
+    }
+    pos--;
+  }
+  return -1;
+}
 
 int main(int argc, char *argv[]) {
   int master;
@@ -1781,9 +1890,6 @@ int main(int argc, char *argv[]) {
   if (!init_regex())
     return 2;
 
-  // With IGNBRK  I don't think I need this anymore.  (Nope!)
-  // signal(SIGINT, SIG_IGN);
-
   pid = forkpty(&master, NULL, NULL, NULL);
 
   // impossible to fork
@@ -1808,8 +1914,6 @@ int main(int argc, char *argv[]) {
 
   // parent
   else {
-    // remove the echo
-    // ICANON - raw mode.  No more line buffering!
     struct termios tios, orig1;
     struct timeval timeout;
     time_t last_event = 0; // time(NULL);
@@ -1818,19 +1922,27 @@ int main(int argc, char *argv[]) {
 
     tcgetattr(master, &tios);
     tios.c_lflag &= ~(ECHO | ECHONL | ICANON);
+    /*
+    tios.c_iflag &= ~(ICRNL | IXON | BRKINT);
+    tios.c_iflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+    tios.c_oflag &= ~(OPOST);
+    */
     tcsetattr(master, TCSAFLUSH, &tios);
 
     tcgetattr(1, &orig1);
     tios = orig1;
-    tios.c_iflag &= ~(ICRNL | IXON); // Disable software flow control
-
+    tios.c_iflag &= ~(ICRNL | IXON | BRKINT);
     tios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+    tios.c_oflag &= ~(OPOST);
 
     // https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html
-    // ISIG should be Ctrl-C and Ctrl-Z IGNBRK +
     tcsetattr(1, TCSAFLUSH, &tios);
 
+    char buffer[1024];
+    int size = 0;
+
     for (;;) {
+      int time_idle;
 
       // define estruturas para o select, que serve para verificar qual
       // se tornou "pronto pra uso"
@@ -1858,67 +1970,117 @@ int main(int argc, char *argv[]) {
        And as we get closer, 15-25 seconds.
       */
 
-      // we're in luck!  The last parameter is time interval/timeout.  :D
-      timeout.tv_sec = 10;
-      timeout.tv_usec = 0;
+      if (size == 0) {
+        // buffer is empty
+        timeout.tv_sec = randrange(10, 20);
+        timeout.tv_usec = 0;
+        time_idle = 1;
+      } else {
+        // buffer is not empty
+        timeout.tv_sec = 0;
+        timeout.tv_usec = 1;
+        time_idle = 0;
+      }
 
-      // select(master+1, &read_fd, &write_fd, &except_fd, NULL);
       if (select(master + 1, &read_fd, &write_fd, &except_fd, &timeout) == 0) {
         // This means timeout!
-        ZF_LOGI("TIMEOUT");
-        harry_idle_event(STDOUT_FILENO);
+        if (time_idle) {
+          ZF_LOGI("TIMEOUT");
+          harry_idle_event(STDOUT_FILENO);
+        } else {
+          ZF_LOGI_MEM(buffer, size, "TIMEOUT size=%d", size);
+          console_receive(&console, buffer, size);
+          write(STDOUT_FILENO, buffer, size);
+          size = 0;
+          // buffer is empty now
+        }
       }
 
-      char input[BSIZE + 1];
+      /*
       static char output[(BSIZE * 4) + 1];
+      */
       int total;
 
       // read_fd esta atribuido com read_fd?
       if (FD_ISSET(master, &read_fd)) {
         // leia o que bc esta mandando
-        if ((total = read(master, &output, BSIZE)) != -1) {
-          // e escreva isso na saida padrao
-          output[total] = 0;
-
-          // if ( harry_happens( &last_event, 5)) {
-          if (1) {
-            ZF_LOGI("harry_happens");
-            if (mangle(STDOUT_FILENO, output) == 0) {
-              // failed, so.  Try again.
-              last_event = 0;
-            }
+        // ZF_LOGD("read (%d) %d bytes", size, BSIZE - size);
+
+        if ((total = read(master, buffer + size, BSIZE - size)) != -1) {
+          // Ok, we've read more into the buffer.
+          // ZF_LOGD("total = %d", total);
+          /*
+          // this ... isn't working.
+          ZF_LOGD_MEM(buffer, total, "Buffer now:");
+          write(STDOUT_FILENO, buffer, total);
+          size = 0;
+          */
+
+          ZF_LOGD_MEM(buffer + size, total, "Read %d bytes:", total);
+          size += total;
+          ZF_LOGD_MEM(buffer, size, "Buffer now:");
+          int pos = rstrnstr(buffer, size, "\r\n");
+          if (pos >= 0) {
+            // found something!
+            pos += 2;
+            ZF_LOGD_MEM(buffer, pos, "mangle buffer %d bytes:", pos);
+            mangle(STDOUT_FILENO, buffer, pos);
+            memmove(buffer, buffer + pos, size - pos);
+            size -= pos;
           } else {
-            write(STDOUT_FILENO, &output, total);
-            // This is OUTPUT from the BBS
-            // ZF_LOGI( ">> %s", repr(output));
-            ZF_LOGI(">> %d chars", (int)strlen(output));
-            //   I think repr is flipping out here.  :(
-            // ZF_LOGI( ">> %d", (int)strlen(repr(output)));
+            ZF_LOGD("position of /r/n not found.");
           }
 
         } else
           break;
       }
 
-      // read_fd esta atribuido com a entrada padrao?
-      if (FD_ISSET(STDIN_FILENO, &read_fd)) {
-        // leia a entrada padrao
-        total = read(STDIN_FILENO, &input, BSIZE);
-        input[total] = 0;
-        // e escreva no bc
-        ZF_LOGI("<< %s", repr(input));
-
-        write(master, &input, total);
+#ifdef OLD_CRUFTY
+      if ((total = read(master, &output, BSIZE)) != -1) {
+        // e escreva isso na saida padrao
+        output[total] = 0;
+
+        // if ( harry_happens( &last_event, 5)) {
+        if (1) {
+          ZF_LOGI("harry_happens");
+          if (mangle(STDOUT_FILENO, output) == 0) {
+            // failed, so.  Try again.
+            last_event = 0;
+          }
+        } else {
+          write(STDOUT_FILENO, &output, total);
+          // This is OUTPUT from the BBS
+          // ZF_LOGI( ">> %s", repr(output));
+          ZF_LOGI(">> %d chars", (int)strlen(output));
+          //   I think repr is flipping out here.  :(
+          // ZF_LOGI( ">> %d", (int)strlen(repr(output)));
+        }
 
-        // This is INPUT from the USER
-        // ZF_LOGI_MEM( input, strlen(input), "<< ");
-      }
+      } else
+        break;
     }
+#endif
+
+    // read_fd esta atribuido com a entrada padrao?
+    if (FD_ISSET(STDIN_FILENO, &read_fd)) {
+      // leia a entrada padrao
+      char input[BSIZE];
+      int r = read(STDIN_FILENO, &input, BSIZE);
+      input[r] = 0;
+      // e escreva no bc
+      ZF_LOGI("<< %s", repr(input));
+
+      write(master, &input, r);
 
-    // Restore terminal
-    tcsetattr(1, TCSAFLUSH, &orig1);
-    ZF_LOGD("exit");
+      // This is INPUT from the USER
+      // ZF_LOGI_MEM( input, strlen(input), "<< ");
+    }
   }
 
-  return 0;
+  // Restore terminal
+  tcsetattr(1, TCSAFLUSH, &orig1);
+  ZF_LOGD("exit");
+}
+
+return 0;
 }