]> granicus.if.org Git - nethack/commitdiff
tty message history line-wrapping fix
authorPatR <rankin@nethack.org>
Thu, 30 Jun 2016 01:55:02 +0000 (18:55 -0700)
committerPatR <rankin@nethack.org>
Thu, 30 Jun 2016 01:55:02 +0000 (18:55 -0700)
Reported directly to devteam last October, for 3.4.3 on NAO,
subject "UI flaw in message history":

"Applying the stethoscope at self informs:
"Status of Xxxxxxxx (piously neutral):  Level 14  HP 138(138)  AC -15, very
"fast, invisible.--More--

This is reproducible with shorter character name "wizard" by being
"nominally neutral" or "nominally chaotic".  I had a 2 digit level
but didn't notice that my AC took up only 1 digit and ended up
using 125ish blessed potions of full healing to get 4 digits of hit
points in order to get the line to wrap between "very" and "fast".

"But the message history with Ctrl-P shows:
"Message History
"
"Status of Xxxxxxxx (piously neutral): Level 14 HP 138(138) AC -15, very
"invisible.

The key was "Message History", indicating msg_window:full or other
setting which causes ^P to bypass the top line message window and
use a general text window to deliver all history lines at once.

The original feedback splits the line by replacing the space
between "very" and "fast" with a newline, which topline handling
notices and processes as special, but then leaves in place.
msg_window:full results in tty_putstr() case NHW_TEXT, which treats
newline as an ordinary character since it doesn't expect to see
that in text.  Squeezing out three doubled spaces made room for
"very\nfast," on the top line.  process_text_window() attempted to
write it there, but putchar() wrote up through "very," on one line,
then output the newline which resulted in "fast," on the next line.
Then explicit cursor positioning set things up to put "invisible"
at the start of that line, overwriting "fast," so making it appear
to be missing.

doc/fixes36.1
win/tty/topl.c
win/tty/wintty.c

index 3b8bd6ca165a4ebf32a28055c793ca1c9d23391e..90b9a6a8ac5870a9f6c12b884cadc639dc1ff8b2 100644 (file)
@@ -347,6 +347,8 @@ tty: if color is disabled and use_inverse is enabled, display lava in inverse
 tty: if "--More--" was written to leftmost column (beginning of second line)
        while hero was swallowed, cursor would end up in wrong place (at end
        of status line instead back on map) after message line was cleared
+tty: long message lines which wrap when shown on the top line might be
+       re-displayed incorrectly by ^P for msg_window={full,combo,reverse}
 unix/X11: in top level Makefile, some commented out definitions of VARDATND
        misspelled pilemark.xbm (as pilemark.xpm)
 unix: options file with CR+LF line ends and an invalid option line resulted in
index 4c857cb81e9abaa6657c4df3cfeead672cf05b35..dd6758a4e26bf71083c65dcdc232725481b99e15 100644 (file)
@@ -8,7 +8,6 @@
 
 #include "tcap.h"
 #include "wintty.h"
-#include <ctype.h>
 
 #ifndef C /* this matches src/cmd.c */
 #define C(c) (0x1f & (c))
@@ -48,8 +47,7 @@ tty_doprev_message()
             do {
                 morc = 0;
                 if (cw->maxcol == cw->maxrow) {
-                    ttyDisplay->dismiss_more =
-                        C('p'); /* <ctrl/P> allowed at --More-- */
+                    ttyDisplay->dismiss_more = C('p'); /* ^P ok at --More-- */
                     redotoplin(toplines);
                     cw->maxcol--;
                     if (cw->maxcol < 0)
@@ -57,8 +55,7 @@ tty_doprev_message()
                     if (!cw->data[cw->maxcol])
                         cw->maxcol = cw->maxrow;
                 } else if (cw->maxcol == (cw->maxrow - 1)) {
-                    ttyDisplay->dismiss_more =
-                        C('p'); /* <ctrl/P> allowed at --More-- */
+                    ttyDisplay->dismiss_more = C('p'); /* ^P ok at --More-- */
                     redotoplin(cw->data[cw->maxcol]);
                     cw->maxcol--;
                     if (cw->maxcol < 0)
@@ -130,6 +127,7 @@ redotoplin(str)
 const char *str;
 {
     int otoplin = ttyDisplay->toplin;
+
     home();
     if (*str & 0x80) {
         /* kludge for the / command, the only time we ever want a */
@@ -251,10 +249,11 @@ register const char *bp;
     (void) strncpy(toplines, bp, TBUFSZ);
     toplines[TBUFSZ - 1] = 0;
 
-    for (tl = toplines; n0 >= CO;) {
+    for (tl = toplines; n0 >= CO; ) {
         otl = tl;
-        for (tl += CO - 1; tl != otl && !isspace(*tl); --tl)
-            ;
+        for (tl += CO - 1; tl != otl; --tl)
+            if (*tl == ' ')
+                break;
         if (tl == otl) {
             /* Eek!  A huge token.  Try splitting after it. */
             tl = index(otl, ' ');
@@ -299,7 +298,7 @@ char c;
         break;
     default:
         if (ttyDisplay->curx == CO - 1)
-            topl_putsym('\n'); /* 1 <= curx <= CO; avoid CO */
+            topl_putsym('\n'); /* 1 <= curx < CO; avoid CO */
 #ifdef WIN32CON
         (void) putchar(c);
 #endif
index 8ceb1dc4e132ba7bb479ee7d2a3ba72e42a1d404..e38e3e7c877952cc95b62a4eaaddf9004436327e 100644 (file)
@@ -2443,22 +2443,27 @@ compress_str(str)
 const char *str;
 {
     static char cbuf[BUFSZ];
-    /* compress in case line too long */
-    if ((int) strlen(str) >= CO) {
+
+    /* compress out consecutive spaces if line is too long;
+       topline wrapping converts space at wrap point into newline,
+       we reverse that here */
+    if ((int) strlen(str) >= CO || index(str, '\n')) {
         register const char *bp0 = str;
-        register char *bp1 = cbuf;
+        char c, nxtc, *bp1 = cbuf, *endbp1 = &cbuf[sizeof cbuf - 1];
 
+        cbuf[0] = cbuf[sizeof cbuf - 1] = '\0'; /* superfluous */
+        nxtc = (*bp0 == '\n') ? ' ' : *bp0;
         do {
-#ifdef CLIPPING
-            if (*bp0 != ' ' || bp0[1] != ' ')
-#else
-            if (*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ')
-#endif
-                *bp1++ = *bp0;
-        } while (*bp0++);
-    } else
-        return str;
-    return cbuf;
+            c = nxtc;
+            nxtc = bp0[1];
+            if (nxtc == '\n')
+                nxtc = ' ';
+            if (c != ' ' || nxtc != ' ')
+                *bp1++ = c;
+        } while (*bp0++ && bp1 < endbp1);
+        str = cbuf;
+    }
+    return str;
 }
 
 void
@@ -2601,7 +2606,7 @@ const char *str;
         }
         if (cw->data[cw->cury])
             free((genericptr_t) cw->data[cw->cury]);
-        n0 = strlen(str) + 1;
+        n0 = (long) strlen(str) + 1L;
         ob = cw->data[cw->cury] = (char *) alloc((unsigned) n0 + 1);
         *ob++ = (char) (attr + 1); /* avoid nuls, for convenience */
         Strcpy(ob, str);