From a588541a27d417f5e3cf57fa8ad2dba49a8a1cd1 Mon Sep 17 00:00:00 2001 From: Bart House Date: Mon, 2 Oct 2017 21:11:30 -0700 Subject: [PATCH] Win32GUI: Gather raw_print text and display it all in single dialog Defined strbuf_t and related routines to support dynamically sized strings. Modified strip_newline() to strip the last newline in a string instead of the first. Simplified splash window code using new strbuf_t. Prior to exiting game, re-enable getreturn and call wait_synch() in case there is buffered raw prints that must be displayed to user. --- include/extern.h | 5 +++ include/hack.h | 6 ++++ src/hacklib.c | 72 +++++++++++++++++++++++++++++++++++++++++- sys/share/pcmain.c | 9 ++++++ sys/share/pcsys.c | 2 ++ win/win32/mhmsgwnd.c | 53 +++++++++++++++++++++++++------ win/win32/mhsplash.c | 75 +++++++++----------------------------------- win/win32/mswproc.c | 57 +++++++++++++++++++++++++++------ win/win32/winMS.h | 1 + 9 files changed, 200 insertions(+), 80 deletions(-) diff --git a/include/extern.h b/include/extern.h index bc1c183ab..de7c35999 100644 --- a/include/extern.h +++ b/include/extern.h @@ -924,6 +924,11 @@ E int NDECL(phase_of_the_moon); E boolean NDECL(friday_13th); E int NDECL(night); E int NDECL(midnight); +E void FDECL(strbuf_init, (strbuf_t *)); +E void FDECL(strbuf_append, (strbuf_t *, const char *)); +E void FDECL(strbuf_reserve, (strbuf_t *, int)); +E void FDECL(strbuf_empty, (strbuf_t *)); +E void FDECL(strbuf_nl_to_crlf, (strbuf_t *)); /* ### invent.c ### */ diff --git a/include/hack.h b/include/hack.h index b3a05ca67..9bc2fc403 100644 --- a/include/hack.h +++ b/include/hack.h @@ -151,6 +151,12 @@ enum game_end_types { ASCENDED }; +typedef struct strbuf { + int len; + char * str; + char buf[256]; +} strbuf_t; + #include "align.h" #include "dungeon.h" #include "monsym.h" diff --git a/src/hacklib.c b/src/hacklib.c index 5d18fcbf7..69cfc3f5b 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -61,6 +61,11 @@ boolean friday_13th (void) int night (void) int midnight (void) + void strbuf_init (strbuf *, const char *) + void strbuf_append (strbuf *, const char *) + void strbuf_reserve (strbuf *, int) + void strbuf_empty (strbuf *) + void strbuf_nl_to_crlf (strbuf_t *) =*/ #ifdef LINT #define Static /* pacify lint */ @@ -183,7 +188,7 @@ char * strip_newline(str) char *str; { - char *p = index(str, '\n'); + char *p = rindex(str, '\n'); if (p) { if (p > str && *(p - 1) == '\r') @@ -1101,4 +1106,69 @@ midnight() return (getlt()->tm_hour == 0); } +/* strbuf_init() initializes strbuf state for use */ +void strbuf_init(strbuf_t * strbuf) +{ + strbuf->str = NULL; + strbuf->len = 0; +} + +/* strbuf_append() appends given str to strbuf->str */ +void strbuf_append(strbuf_t * strbuf, const char * str) +{ + if (strbuf->str == NULL) + strbuf_reserve(strbuf, strlen(str) + 1); + else + strbuf_reserve(strbuf, strlen(strbuf->str) + strlen(str) + 1); + + strcat(strbuf->str, str); +} + +/* strbuf_reserve() ensure strbuf->str has storage for len characters */ +void strbuf_reserve(strbuf_t * strbuf, int len) +{ + if (strbuf->str == NULL) { + strbuf->str = strbuf->buf; + strbuf->str[0] = '\0'; + strbuf->len = sizeof(strbuf->buf); + } + + if (len > strbuf->len) { + char * oldbuf = strbuf->str; + strbuf->len = len + sizeof(strbuf->buf); + strbuf->str = (char *) alloc(strbuf->len); + strcpy(strbuf->str, oldbuf); + if (oldbuf != strbuf->buf) free(oldbuf); + } +} + +/* strbuf_empty() frees allocated memory and set strbuf to initial state */ +void strbuf_empty(strbuf_t * strbuf) +{ + if (strbuf->str != strbuf->buf) + free(strbuf->str); + strbuf_init(strbuf); +} + +/* strbuf_nl_to_crlf() converts all occurences of \n to \r\n */ +void strbuf_nl_to_crlf(strbuf_t * strbuf) +{ + if (strbuf->str) { + int len = strlen(strbuf->str); + int count = 0; + char * cp = strbuf->str; + while (*cp) if (*cp++ == '\n') count++; + if (count) { + strbuf_reserve(strbuf, len + count + 1); + cp = strbuf->str + len + count; + while (count) { + if ((*cp-- = cp[-count]) == '\n') { + *cp-- = '\r'; + count--; + } + } + } + } +} + /*hacklib.c*/ diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index d62d234cc..a18157639 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -139,6 +139,15 @@ char *argv[]; /* use STDERR by default _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ +/* Heap Debugging + _CrtSetDbgFlag( _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) + | _CRTDBG_ALLOC_MEM_DF + | _CRTDBG_CHECK_ALWAYS_DF + | _CRTDBG_CHECK_CRT_DF + | _CRTDBG_DELAY_FREE_MEM_DF + | _CRTDBG_LEAK_CHECK_DF); + _CrtSetBreakAlloc(1423); +*/ # endif #endif diff --git a/sys/share/pcsys.c b/sys/share/pcsys.c index 085956c76..5746b778c 100644 --- a/sys/share/pcsys.c +++ b/sys/share/pcsys.c @@ -546,6 +546,8 @@ msexit() getreturn("to end"); synch_cursor(); #endif + getreturn_enabled = TRUE; + wait_synch(); return; } #endif /* MICRO || WIN32 || OS2 */ diff --git a/win/win32/mhmsgwnd.c b/win/win32/mhmsgwnd.c index 40b4791ef..22b0fdd9f 100644 --- a/win/win32/mhmsgwnd.c +++ b/win/win32/mhmsgwnd.c @@ -245,6 +245,25 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (wParam) { case MSNH_MSG_PUTSTR: { + /* Add the passed in message to the existing text. Support the + * adding of text that ends in newline. A newline in text + * will force any subsequent text that is added to be added on + * a new output line. + * + * TODO: Text can be added with newlines occurring within the text not + * just at the end. As currently implemented, this can cause + * the text to be rendered such that the text following the + * newline is rendered on a new line. This can cause a poor + * user experience when the user has set only a single text line + * for the message window. In this case, the user will not see + * any line other then the last line of text and the --MORE-- + * message thus missing any text that appears before the last + * embedded newline. This does not meet the requirements of the + * message window. + * This code should be changed to do the right thing and split + * the text so that only lines that end in newlines are added to + * the stored window text. + */ PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr) lParam; SCROLLINFO si; char *p; @@ -271,10 +290,17 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) /* check for "--more--" */ if (!data->nevermore && more_prompt_check(hWnd)) { int okkey = 0; - int chop; + char tmptext[MAXWINDOWTEXT + 1]; + // @@@ Ok respnses - /* append more prompt and inticate the update */ + /* save original text */ + strcpy(tmptext, data->window_text[MSG_LINES - 1].text); + + /* text could end in newline so strip it */ + strip_newline(data->window_text[MSG_LINES - 1].text); + + /* append more prompt and indicate the update */ strncat( data->window_text[MSG_LINES - 1].text, MORE, MAXWINDOWTEXT @@ -301,10 +327,9 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) } } - /* erase the "--more--" prompt */ - chop = strlen(data->window_text[MSG_LINES - 1].text) - - strlen(MORE); - data->window_text[MSG_LINES - 1].text[chop] = '\0'; + /* restore original text */ + strcpy(data->window_text[MSG_LINES - 1].text, tmptext); + data->lines_not_seen = 0; } @@ -601,6 +626,7 @@ onPaint(HWND hWnd) - (client_rt.bottom - ps.rcPaint.bottom) / data->yChar); y = min(ps.rcPaint.bottom, client_rt.bottom); for (i = LastLine; i >= FirstLine; i--) { + char tmptext[MAXWINDOWTEXT + 1]; x = data->xChar * (2 - data->xPos); draw_rt.left = x; @@ -612,8 +638,10 @@ onPaint(HWND hWnd) hdc, mswin_get_font(NHW_MESSAGE, data->window_text[i].attr, hdc, FALSE)); - /* convert to UNICODE */ - NH_A2W(data->window_text[i].text, wbuf, sizeof(wbuf)); + /* convert to UNICODE stripping newline */ + strcpy(tmptext, data->window_text[i].text); + strip_newline(tmptext); + NH_A2W(tmptext, wbuf, sizeof(wbuf)); wlen = _tcslen(wbuf); setMsgTextColor(hdc, i < (MSG_LINES - data->lines_last_turn)); #ifdef MSG_WRAP_TEXT @@ -765,6 +793,10 @@ can_append_text(HWND hWnd, int attr, const char *text) if (data->window_text[MSG_LINES - 1].attr != attr) return FALSE; + /* cannot append if current line ends in newline */ + if (str_end_is(data->window_text[MSG_LINES - 1].text, "\n")) + return FALSE; + /* check if the maximum string langth will be exceeded */ if (strlen(data->window_text[MSG_LINES - 1].text) + 2 + /* space characters */ @@ -772,10 +804,11 @@ can_append_text(HWND hWnd, int attr, const char *text) >= MAXWINDOWTEXT) return FALSE; - /* check if the text is goinf to fin into a single line */ + /* check if the text is going to fit into a single line */ strcpy(tmptext, data->window_text[MSG_LINES - 1].text); strcat(tmptext, " "); strcat(tmptext, text); + strip_newline(tmptext); strcat(tmptext, MORE); hdc = GetDC(hWnd); @@ -836,6 +869,8 @@ more_prompt_check(HWND hWnd) hdc, FALSE)); strcpy(tmptext, data->window_text[MSG_LINES - i - 1].text); + strip_newline(tmptext); + if (i == 0) strcat(tmptext, MORE); diff --git a/win/win32/mhsplash.c b/win/win32/mhsplash.c index 680da598e..d1bceaa07 100644 --- a/win/win32/mhsplash.c +++ b/win/win32/mhsplash.c @@ -36,13 +36,9 @@ mswin_display_splash_window(BOOL show_ver) RECT controlrt; HWND hWnd; int buttop; - int strsize = 0; - int bufsize = BUFSZ; - char *buf = malloc(bufsize); + strbuf_t strbuf; - if (buf == NULL) - panic("out of memory"); - buf[0] = '\0'; + strbuf_init(&strbuf); hWnd = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_SPLASH), GetNHApp()->hMainWnd, NHSplashWndProc); @@ -87,9 +83,9 @@ mswin_display_splash_window(BOOL show_ver) clientrt.right - 2 * SPLASH_OFFSET_X, controlrt.bottom, TRUE); /* Fill the text control */ - Sprintf(buf, "%s\r\n%s\r\n%s\r\n%s\r\n\r\n", COPYRIGHT_BANNER_A, + strbuf_reserve(&strbuf, BUFSIZ); + Sprintf(strbuf.str, "%s\n%s\n%s\n%s\n\n", COPYRIGHT_BANNER_A, COPYRIGHT_BANNER_B, COPYRIGHT_BANNER_C, COPYRIGHT_BANNER_D); - strsize = strlen(buf); if (show_ver) { /* Show complete version information */ @@ -98,43 +94,16 @@ mswin_display_splash_window(BOOL show_ver) int verstrsize = 0; getversionstring(verbuf); - verstrsize = strlen(verbuf); - if (verstrsize + strlen("\r\n\r\n") + 1 < BUFSZ - 1) - strcat(verbuf, "\r\n\r\n"); - verstrsize = strlen(verbuf); - - if (strsize + verstrsize + 1 > bufsize) { - bufsize += BUFSZ; - buf = realloc(buf, bufsize); - if (buf == NULL) - panic("out of memory"); - } - strcat(buf, verbuf); - strsize = strlen(buf); + strbuf_append(&strbuf, verbuf); + strbuf_append(&strbuf, "\n\n"); /* Add compile options */ f = dlb_fopen(OPTIONS_USED, RDTMODE); if (f) { char line[LLEN + 1]; - while (dlb_fgets(line, LLEN, f)) { - size_t len; - len = strlen(line); - if (len > 0 && line[len - 1] == '\n') { - line[len - 1] = '\r'; - line[len] = '\n'; - line[len + 1] = '\0'; - len++; - } - if (strsize + (int) len + 1 > bufsize) { - bufsize += BUFSZ; - buf = realloc(buf, bufsize); - if (buf == NULL) - panic("out of memory"); - } - strcat(buf, line); - strsize += len; - } + while (dlb_fgets(line, LLEN, f)) + strbuf_append(&strbuf, line); (void) dlb_fclose(f); } } else { @@ -147,32 +116,18 @@ mswin_display_splash_window(BOOL show_ver) if (nf != NULL) { char line[LLEN + 1]; - while (fgets(line, LLEN, nf)) { - size_t len; - len = strlen(line); - if (len > 0 && line[len - 1] == '\n') { - line[len - 1] = '\r'; - line[len] = '\n'; - line[len + 1] = '\0'; - len++; - } - if (strsize + (int) len + 1 > bufsize) { - bufsize += BUFSZ; - buf = realloc(buf, bufsize); - if (buf == NULL) - panic("out of memory"); - } - strcat(buf, line); - strsize += len; - } + while (fgets(line, LLEN, nf)) + strbuf_append(&strbuf, line); (void) fclose(nf); } else { - strcat(buf, "No news."); + strbuf_append(&strbuf, "No news."); } } } - SetWindowText(GetDlgItem(hWnd, IDC_EXTRAINFO), buf); - free(buf); + + strbuf_nl_to_crlf(&strbuf); + SetWindowText(GetDlgItem(hWnd, IDC_EXTRAINFO), strbuf.str); + strbuf_empty(&strbuf); ShowWindow(hWnd, SW_SHOW); while (IsWindow(hWnd) && GetMessage(&msg, NULL, 0, 0) != 0) { diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 236396b83..c20fffbff 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -75,6 +75,8 @@ COLORREF status_fg_color = RGB(0xFF, 0xFF, 0xFF); COLORREF message_bg_color = RGB(0, 0, 0); COLORREF message_fg_color = RGB(0xFF, 0xFF, 0xFF); +strbuf_t raw_print_strbuf = { 0 }; + /* Interface definition, for windows.c */ struct window_procs mswin_procs = { "MSWIN", @@ -717,8 +719,7 @@ mswin_exit_nhwindows(const char *str) /* Write Window settings to the registry */ mswin_write_reg(); - while (max_brush) - DeleteObject(brush_table[--max_brush]); + } /* Prepare the window to be suspended. */ @@ -1238,6 +1239,7 @@ void mswin_wait_synch() { logDebug("mswin_wait_synch()\n"); + mswin_raw_print_flush(); } /* @@ -1293,6 +1295,40 @@ mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph) } } +/* + * mswin_raw_print_accumulate() accumulate the given text into + * raw_print_strbuf. + */ +void +mswin_raw_print_accumulate(const char * str, boolean bold) +{ + bold; // ignored for now + + if (raw_print_strbuf.str != NULL) strbuf_append(&raw_print_strbuf, "\n"); + strbuf_append(&raw_print_strbuf, str); +} + +/* + * mswin_raw_print_flush() - display any text found in raw_print_strbuf in a + * dialog box and clear raw_print_strbuf. + */ +void +mswin_raw_print_flush() +{ + if (raw_print_strbuf.str != NULL) { + int wlen = strlen(raw_print_strbuf.str) + 1; + TCHAR * wbuf = (TCHAR *) alloc(wlen * sizeof(TCHAR)); + if (wbuf != NULL) { + NHMessageBox(GetNHApp()->hMainWnd, + NH_A2W(raw_print_strbuf.str, wbuf, wlen), + MB_ICONINFORMATION | MB_OK); + free(wbuf); + } + strbuf_empty(&raw_print_strbuf); + } +} + + /* raw_print(str) -- Print directly to a screen, or otherwise guarantee that the user sees str. raw_print() appends a newline to str. @@ -1305,14 +1341,12 @@ raw_print(str) -- Print directly to a screen, or otherwise guarantee that void mswin_raw_print(const char *str) { - TCHAR wbuf[255]; logDebug("mswin_raw_print(%s)\n", str); + if (str && *str) { extern int redirect_stdout; if (!redirect_stdout) - NHMessageBox(GetNHApp()->hMainWnd, - NH_A2W(str, wbuf, sizeof(wbuf)), - MB_ICONINFORMATION | MB_OK); + mswin_raw_print_accumulate(str, FALSE); else fprintf(stdout, "%s", str); } @@ -1326,11 +1360,14 @@ possible). void mswin_raw_print_bold(const char *str) { - TCHAR wbuf[255]; logDebug("mswin_raw_print_bold(%s)\n", str); - if (str && *str) - NHMessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), - MB_ICONINFORMATION | MB_OK); + if (str && *str) { + extern int redirect_stdout; + if (!redirect_stdout) + mswin_raw_print_accumulate(str, TRUE); + else + fprintf(stdout, "%s", str); + } } /* diff --git a/win/win32/winMS.h b/win/win32/winMS.h index b799da1e7..0347674ff 100644 --- a/win/win32/winMS.h +++ b/win/win32/winMS.h @@ -164,6 +164,7 @@ void mswin_cliparound(int x, int y); void mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph); void mswin_raw_print(const char *str); void mswin_raw_print_bold(const char *str); +void mswin_raw_print_flush(); int mswin_nhgetch(void); int mswin_nh_poskey(int *x, int *y, int *mod); void mswin_nhbell(void);