Added internal wrapping ability.
authorEric Mullins <emwine@earthlink.net>
Sat, 17 Oct 2009 04:54:12 +0000 (22:54 -0600)
committerEric Mullins <emwine@earthlink.net>
Sat, 17 Oct 2009 04:54:12 +0000 (22:54 -0600)
New options:
  -wrapContinuationSequence "foo"  (default: "\\   "
  -useInternalWrap (Winboard default: false, XBoard default: true)

Note: -keepLineBreaksICS if set, prevents wrapping, usurping the
   useInternalWrap setting.  The idea is if you want to keep ICS line
   breaks, then you don't want internal wrapping.  Because of this,
   the new default for keepLineBreaksICS is now false for XBoard.

backend.c
backend.h
common.h
winboard/winboard.c
xboard.c

index 06796c1..5b8dcfa 100755 (executable)
--- a/backend.c
+++ b/backend.c
@@ -1042,6 +1042,7 @@ InitBackEnd2()
        fprintf(debugFP, "%s\n", programVersion);
     }
 
        fprintf(debugFP, "%s\n", programVersion);
     }
 
+    set_cont_sequence(appData.wrapContSeq);
     if (appData.matchGames > 0) {
        appData.matchMode = TRUE;
     } else if (appData.matchMode) {
     if (appData.matchGames > 0) {
        appData.matchMode = TRUE;
     } else if (appData.matchMode) {
@@ -13968,3 +13969,110 @@ EditPositionPasteFEN(char *fen)
     }
   }
 }
     }
   }
 }
+
+static char cseq[12] = "\\   ";
+
+Boolean set_cont_sequence(char *new_seq)
+{
+    int len;
+    Boolean ret;
+
+    // handle bad attempts to set the sequence
+       if (!new_seq)
+               return 0; // acceptable error - no debug
+
+    len = strlen(new_seq);
+    ret = (len > 0) && (len < sizeof(cseq));
+    if (ret)
+        strcpy(cseq, new_seq);
+    else if (appData.debugMode)
+        fprintf(debugFP, "Invalid continuation sequence \"%s\"  (maximum length is: %d)\n", new_seq, sizeof(cseq)-1);
+    return ret;
+}
+
+/*
+    reformat a source message so words don't cross the width boundary.  internal
+    newlines are not removed.  returns the wrapped size (no null character unless
+    included in source message).  If dest is NULL, only calculate the size required
+    for the dest buffer.  lp argument indicats line position upon entry, and it's
+    passed back upon exit.
+*/
+int wrap(char *dest, char *src, int count, int width, int *lp)
+{
+    int len, i, ansi, cseq_len, line, old_line, old_i, old_len, clen;
+
+    cseq_len = strlen(cseq);
+    old_line = line = *lp;
+    ansi = len = clen = 0;
+
+    for (i=0; i < count; i++)
+    {
+        if (src[i] == '\033')
+            ansi = 1;
+
+        // if we hit the width, back up
+        if (!ansi && (line >= width) && src[i] != '\n' && src[i] != ' ')
+        {
+            // store i & len in case the word is too long
+            old_i = i, old_len = len;
+
+            // find the end of the last word
+            while (i && src[i] != ' ' && src[i] != '\n')
+            {
+                i--;
+                len--;
+            }
+
+            // word too long?  restore i & len before splitting it
+            if ((old_i-i+clen) >= width)
+            {
+                i = old_i;
+                len = old_len;
+            }
+
+            // extra space?
+            if (i && src[i-1] == ' ')
+                len--;
+
+            if (src[i] != ' ' && src[i] != '\n')
+            {
+                i--;
+                if (len)
+                    len--;
+            }
+
+            // now append the newline and continuation sequence
+            if (dest)
+                dest[len] = '\n';
+            len++;
+            if (dest)
+                strncpy(dest+len, cseq, cseq_len);
+            len += cseq_len;
+            line = cseq_len;
+            clen = cseq_len;
+            continue;
+        }
+
+        if (dest)
+            dest[len] = src[i];
+        len++;
+        if (!ansi)
+            line++;
+        if (src[i] == '\n')
+            line = 0;
+        if (src[i] == 'm')
+            ansi = 0;
+    }
+    if (dest && appData.debugMode)
+    {
+        fprintf(debugFP, "wrap(count:%d,width:%d,line:%d,len:%d,*lp:%d,src: ",
+            count, width, line, len, *lp);
+        show_bytes(debugFP, src, count);
+        fprintf(debugFP, "\ndest: ");
+        show_bytes(debugFP, dest, len);
+        fprintf(debugFP, "\n");
+    }
+    *lp = dest ? line : old_line;
+
+    return len;
+}
index 0d6b3a4..b44c45a 100644 (file)
--- a/backend.h
+++ b/backend.h
@@ -259,6 +259,9 @@ char * GameListLineFull P(( int, GameInfo *));
 extern char* StripHighlight P((char *));  /* returns static data */
 extern char* StripHighlightAndTitle P((char *));  /* returns static data */
 extern void ics_update_width P((int new_width));
 extern char* StripHighlight P((char *));  /* returns static data */
 extern char* StripHighlightAndTitle P((char *));  /* returns static data */
 extern void ics_update_width P((int new_width));
+extern Boolean set_cont_sequence P((char *new_seq));
+extern int wrap P((char *dest, char *src, int count, int width, int *lp));
+
 typedef enum { CheckBox, ComboBox, TextBox, Button, Spin, ResetButton,
                   SaveButton, FileName, PathName, Slider, Message } Control;
 
 typedef enum { CheckBox, ComboBox, TextBox, Button, Spin, ResetButton,
                   SaveButton, FileName, PathName, Slider, Message } Control;
 
index 9ab3048..a48aee5 100644 (file)
--- a/common.h
+++ b/common.h
@@ -603,6 +603,8 @@ typedef struct {
     Boolean keepAlive;  /* [HGM] alive     */
     Boolean forceIllegal;/*[HGM] illegal   */
     Boolean noJoin;     /* [HGM] join      */
     Boolean keepAlive;  /* [HGM] alive     */
     Boolean forceIllegal;/*[HGM] illegal   */
     Boolean noJoin;     /* [HGM] join      */
+    char *wrapContSeq; /* continuation sequence when xboard wraps text */
+    Boolean useInternalWrap; /* use internal wrapping -- noJoin usurps this if set */
 } AppData, *AppDataPtr;
 
 /* [AS] PGN tags (for showing in the game list) */
 } AppData, *AppDataPtr;
 
 /* [AS] PGN tags (for showing in the game list) */
index 4ab4f93..62d5072 100644 (file)
@@ -1393,7 +1393,9 @@ ArgDescriptor argDescriptors[] = {
   { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },\r
   { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },\r
   { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE },\r
   { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },\r
   { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },\r
   { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE },\r
-\r
+  { "wrapContinuationSequence", ArgString, (LPVOID) &appData.wrapContSeq, FALSE },\r
+  { "useInternalWrap", ArgTrue, (LPVOID) &appData.useInternalWrap, FALSE }, /* noJoin usurps this if set */\r
+  \r
   // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others\r
   { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed\r
   { "minY", ArgZ, (LPVOID) &minY, FALSE },\r
   // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others\r
   { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed\r
   { "minY", ArgZ, (LPVOID) &minY, FALSE },\r
@@ -5277,34 +5279,55 @@ LoadGameDialog(HWND hwnd, char* title)
   }\r
 }\r
 \r
   }\r
 }\r
 \r
+int get_term_width()\r
+{\r
+    HDC hdc;\r
+    TEXTMETRIC tm;\r
+    RECT rc;\r
+    HFONT hfont, hold_font;\r
+    LOGFONT lf;\r
+    HWND hText;\r
+\r
+    if (hwndConsole)\r
+        hText = GetDlgItem(hwndConsole, OPT_ConsoleText);\r
+    else\r
+        return 79;\r
+\r
+    // get the text metrics\r
+    hdc = GetDC(hText);\r
+    lf = font[boardSize][CONSOLE_FONT]->lf;\r
+    if (consoleCF.dwEffects & CFE_BOLD)\r
+        lf.lfWeight = FW_BOLD;\r
+    if (consoleCF.dwEffects & CFE_ITALIC)\r
+        lf.lfItalic = TRUE;\r
+    if (consoleCF.dwEffects & CFE_STRIKEOUT)\r
+        lf.lfStrikeOut = TRUE;\r
+    if (consoleCF.dwEffects & CFE_UNDERLINE)\r
+        lf.lfUnderline = TRUE;\r
+    hfont = CreateFontIndirect(&lf);\r
+    hold_font = SelectObject(hdc, hfont);\r
+    GetTextMetrics(hdc, &tm);\r
+    SelectObject(hdc, hold_font);\r
+    DeleteObject(hfont);\r
+    ReleaseDC(hText, hdc);\r
+\r
+    // get the rectangle\r
+    SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);\r
+\r
+    return (rc.right-rc.left) / tm.tmAveCharWidth;\r
+}\r
+\r
 void UpdateICSWidth(HWND hText)\r
 {\r
 void UpdateICSWidth(HWND hText)\r
 {\r
-       HDC hdc;\r
-       TEXTMETRIC tm;\r
-       RECT rc;\r
-       HFONT hfont, hold_font;\r
-       LONG old_width, new_width;\r
-       \r
-       // get the text metrics\r
-       hdc = GetDC(hText);\r
-       hfont = CreateFontIndirect(&font[boardSize][CONSOLE_FONT]->lf);\r
-       hold_font = SelectObject(hdc, hfont);\r
-       GetTextMetrics(hdc, &tm);\r
-       SelectObject(hdc, hold_font);\r
-       DeleteObject(hfont);\r
-       ReleaseDC(hText, hdc);\r
-\r
-       // get the rectangle\r
-       SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);\r
-\r
-       // update the width\r
-       new_width = (rc.right-rc.left) / tm.tmAveCharWidth;\r
-       old_width = GetWindowLong(hText, GWL_USERDATA);\r
-       if (new_width != old_width)\r
-       {\r
-               ics_update_width(new_width);\r
-               SetWindowLong(hText, GWL_USERDATA, new_width);\r
-       }\r
+    LONG old_width, new_width;\r
+\r
+    new_width = get_term_width(hText, FALSE);\r
+    old_width = GetWindowLong(hText, GWL_USERDATA);\r
+    if (new_width != old_width)\r
+    {\r
+        ics_update_width(new_width);\r
+        SetWindowLong(hText, GWL_USERDATA, new_width);\r
+    }\r
 }\r
 \r
 VOID\r
 }\r
 \r
 VOID\r
@@ -8026,7 +8049,7 @@ ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
     }\r
 \r
    // Allow hText to highlight URLs and send notifications on them\r
     }\r
 \r
    // Allow hText to highlight URLs and send notifications on them\r
-   wMask = SendMessage(hText, EM_GETEVENTMASK, 0, 0L);\r
+   wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);\r
    SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);\r
    SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);\r
    SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width\r
    SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);\r
    SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);\r
    SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width\r
@@ -10340,6 +10363,11 @@ RemoveInputSource(InputSourceRef isr)
   }\r
 }\r
 \r
   }\r
 }\r
 \r
+int no_wrap(char *message, int count)\r
+{\r
+    ConsoleOutput(message, count, FALSE);\r
+    return count;\r
+}\r
 \r
 int\r
 OutputToProcess(ProcRef pr, char *message, int count, int *outError)\r
 \r
 int\r
 OutputToProcess(ProcRef pr, char *message, int count, int *outError)\r
@@ -10348,11 +10376,32 @@ OutputToProcess(ProcRef pr, char *message, int count, int *outError)
   int outCount = SOCKET_ERROR;\r
   ChildProc *cp = (ChildProc *) pr;\r
   static OVERLAPPED ovl;\r
   int outCount = SOCKET_ERROR;\r
   ChildProc *cp = (ChildProc *) pr;\r
   static OVERLAPPED ovl;\r
+  static int line = 0;\r
 \r
 \r
-  if (pr == NoProc) {\r
-    ConsoleOutput(message, count, FALSE);\r
-    return count;\r
-  } \r
+  if (pr == NoProc)\r
+  {\r
+    if (appData.noJoin || !appData.useInternalWrap)\r
+      return no_wrap(message, count);\r
+    else\r
+    {\r
+      int width = get_term_width();\r
+      int len = wrap(NULL, message, count, width, &line);\r
+      char *msg = malloc(len);\r
+      int dbgchk;\r
+\r
+      if (!msg)\r
+        return no_wrap(message, count);\r
+      else\r
+      {\r
+        dbgchk = wrap(msg, message, count, width, &line);\r
+        if (dbgchk != len && appData.debugMode)\r
+            fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);\r
+        ConsoleOutput(msg, len, FALSE);\r
+        free(msg);\r
+        return len;\r
+      }\r
+    }\r
+  }\r
 \r
   if (ovl.hEvent == NULL) {\r
     ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\r
 \r
   if (ovl.hEvent == NULL) {\r
     ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);\r
index 59221fc..911f005 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -1409,6 +1409,12 @@ XtResource clientResources[] = {
        XtRImmediate, (XtPointer) False},
     { "keepLineBreaksICS", "keepLineBreaksICS", XtRBoolean,
        sizeof(Boolean), XtOffset(AppDataPtr, noJoin),
        XtRImmediate, (XtPointer) False},
     { "keepLineBreaksICS", "keepLineBreaksICS", XtRBoolean,
        sizeof(Boolean), XtOffset(AppDataPtr, noJoin),
+       XtRImmediate, (XtPointer) False},
+    { "wrapContinuationSequence", "wrapContinuationSequence", XtRString,
+       sizeof(String), XtOffset(AppDataPtr, wrapContSeq),
+       XtRString, ""},
+    { "useInternalWrap", "useInternalWrap", XtRBoolean,
+       sizeof(Boolean), XtOffset(AppDataPtr, useInternalWrap),
        XtRImmediate, (XtPointer) True},
 };
 
        XtRImmediate, (XtPointer) True},
 };
 
@@ -1780,9 +1786,10 @@ XrmOptionDescRec shellOptions[] = {
     { "-keepAlive", "keepAlive", XrmoptionSepArg, NULL },
     { "-forceIllegalMoves", "forceIllegalMoves", XrmoptionNoArg, "True" },
     { "-keepLineBreaksICS", "keepLineBreaksICS", XrmoptionSepArg, NULL },
     { "-keepAlive", "keepAlive", XrmoptionSepArg, NULL },
     { "-forceIllegalMoves", "forceIllegalMoves", XrmoptionNoArg, "True" },
     { "-keepLineBreaksICS", "keepLineBreaksICS", XrmoptionSepArg, NULL },
+    { "-wrapContinuationSequence", "wrapContinuationSequence", XrmoptionSepArg, NULL },
+    { "-useInternalWrap", "useInternalWrap", XrmoptionSepArg, NULL },
 };
 
 };
 
-
 XtActionsRec boardActions[] = {
     { "DrawPosition", DrawPositionProc },
     { "HandleUserMove", HandleUserMove },
 XtActionsRec boardActions[] = {
     { "DrawPosition", DrawPositionProc },
     { "HandleUserMove", HandleUserMove },
@@ -8506,11 +8513,33 @@ int OutputToProcess(pr, message, count, outError)
      int count;
      int *outError;
 {
      int count;
      int *outError;
 {
+    static int line = 0;
     ChildProc *cp = (ChildProc *) pr;
     int outCount;
 
     if (pr == NoProc)
     ChildProc *cp = (ChildProc *) pr;
     int outCount;
 
     if (pr == NoProc)
-      outCount = fwrite(message, 1, count, stdout);
+    {
+        if (appData.noJoin || !appData.useInternalWrap)
+            outCount = fwrite(message, 1, count, stdout);
+        else
+        {
+            int width = get_term_width();
+            int len = wrap(NULL, message, count, width, &line);
+            char *msg = malloc(len);
+            int dbgchk;
+
+            if (!msg)
+                outCount = fwrite(message, 1, count, stdout);
+            else
+            {
+                dbgchk = wrap(msg, message, count, width, &line);
+                if (dbgchk != len && appData.debugMode)
+                    fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
+                outCount = fwrite(msg, 1, dbgchk, stdout);
+                free(msg);
+            }
+        }
+    }
     else
       outCount = write(cp->fdTo, message, count);
 
     else
       outCount = write(cp->fdTo, message, count);