From b1de94f922965efa22e3b85a0c29e36e8c168a32 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 7 Feb 2019 16:04:24 -0800 Subject: [PATCH 1/2] custompline(SUPPRESS_HISTORY,...) for curses The curses interface already has a hack to keep 'Count: 12', 'Count: 123' intermediate multi-digit counts out of its message recall history for ^P, but it was flushing real messages when getpos()'s 'autodescribe' reported what the cursor moved over. Overload the count hack to support putstr(WIN_MESSAGE, ATR_NOHISTORY, text) (which is what custompline(SUPPRESS_HISTORY, ...) eventually calls). The conditional logic for when to create the 'count_window' was pretty convoluted. This simplification has the same semantics but I don't have PDCURSES to actually verify that. --- doc/fixes36.2 | 4 +++- win/curses/cursmain.c | 25 +++++++++++++++----- win/curses/cursmesg.c | 54 +++++++++++++++++++++++++------------------ win/curses/cursmisc.c | 8 +++++-- 4 files changed, 60 insertions(+), 31 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 159e58cfb..dacb4f4a9 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.249 $ $NHDT-Date: 1549334449 2019/02/05 02:40:49 $ +$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.250 $ $NHDT-Date: 1549584261 2019/02/08 00:04:21 $ This fixes36.2 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.1 in April 2018. Please note, however, @@ -437,6 +437,8 @@ tty: fix leftover display artifact when the last field on the row got placed X11: its use of genl_status_update exposed a negative index use that could lead to a segfault X11: rollback disabling of keystroke input for PICK_NONE menus (for scrolling) +curses: catch up with tty to not put dolook/whatis autodescribe feedback into + ^P message recall (multi-digit count feedback was already handled) Platform- and/or Interface-Specific Fixes or Features diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index 72dbc78b8..8ae781a98 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -20,8 +20,9 @@ struct window_procs curses_procs = { #if defined(STATUS_HILITES) | WC2_HILITE_STATUS #endif - | WC2_HITPOINTBAR | WC2_FLUSH_STATUS - | WC2_TERM_SIZE | WC2_WINDOWBORDERS | WC2_PETATTR | WC2_GUICOLOR), + | WC2_HITPOINTBAR | WC2_FLUSH_STATUS + | WC2_TERM_SIZE | WC2_WINDOWBORDERS | WC2_PETATTR | WC2_GUICOLOR + | WC2_SUPPRESS_HIST), curses_init_nhwindows, curses_player_selection, curses_askname, @@ -377,10 +378,19 @@ Attributes void curses_putstr(winid wid, int attr, const char *text) { - int curses_attr = curses_convert_attr(attr); + int mesgflags, curses_attr; - /* We need to convert NetHack attributes to curses attributes */ - curses_puts(wid, curses_attr, text); + mesgflags = attr & (ATR_URGENT | ATR_NOHISTORY); + attr &= ~mesgflags; + + if (wid == WIN_MESSAGE && (mesgflags & ATR_NOHISTORY) != 0) { + /* display message without saving it in recall history */ + curses_count_window(text); + } else { + /* We need to convert NetHack attributes to curses attributes */ + curses_attr = curses_convert_attr(attr); + curses_puts(wid, curses_attr, text); + } } /* Display the file named str. Complain about missing files @@ -442,7 +452,10 @@ curses_add_menu(winid wid, int glyph, const ANY_P * identifier, CHAR_P accelerator, CHAR_P group_accel, int attr, const char *str, BOOLEAN_P presel) { - int curses_attr = curses_convert_attr(attr); + int curses_attr; + + attr &= ~(ATR_URGENT | ATR_NOHISTORY); + curses_attr = curses_convert_attr(attr); if (inv_update) { curses_add_inv(inv_update, glyph, accelerator, curses_attr, str); diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index fd8c9a875..3f90ed8bc 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -50,10 +50,20 @@ curses_message_win_puts(const char *message, boolean recursed) int border_space = 0; static long suppress_turn = -1; +#if 1 + /* + * Handled by core's use of putstr(WIN_MESSAGE,ATR_NOHISTORY,message) + * for intermediate counts, but get_count() also uses putmsghistory() + * for the final count, to remember that without showing it. But + * curses is using genl_putmsghistory() which just delivers the text + * via a normal pline(). This hides that at cost of not having in + * it ^P recall and being out of sync with DUMPLOG's message history. + */ if (strncmp("Count:", message, 6) == 0) { curses_count_window(message); return; } +#endif if (suppress_turn == moves) { return; @@ -73,7 +83,9 @@ curses_message_win_puts(const char *message, boolean recursed) linespace = ((width + border_space) - 3) - mx; if (strcmp(message, "#") == 0) { /* Extended command or Count: */ - if ((strcmp(toplines, "#") != 0) && (my >= (height - 1 + border_space)) && (height != 1)) { /* Bottom of message window */ + if ((strcmp(toplines, "#") != 0) + /* Bottom of message window */ + && (my >= (height - 1 + border_space)) && (height != 1)) { scroll_window(MESSAGE_WIN); mx = width; my--; @@ -89,7 +101,8 @@ curses_message_win_puts(const char *message, boolean recursed) } if (linespace < message_length) { - if (my >= (height - 1 + border_space)) { /* bottom of message win */ + if (my >= (height - 1 + border_space)) { + /* bottom of message win */ if ((turn_lines > height) || (height == 1)) { /* Pause until key is hit - Esc suppresses any further messages that turn */ @@ -124,8 +137,8 @@ curses_message_win_puts(const char *message, boolean recursed) if (height > 1) { curses_toggle_color_attr(win, NONE, A_BOLD, OFF); } - curses_message_win_puts(tmpstr = curses_str_remainder(message, (width - 2), 1), - TRUE); + tmpstr = curses_str_remainder(message, (width - 2), 1); + curses_message_win_puts(tmpstr, TRUE); free(tmpstr); } else { mvwprintw(win, my, mx, "%s", message); @@ -217,7 +230,7 @@ curses_clear_unhighlight_message_window() /* Reset message window cursor to starting position, and display most -recent messages. */ + recent messages. */ void curses_last_messages() @@ -236,7 +249,7 @@ curses_last_messages() for (i = (num_messages - 1); i > 0; i--) { mesg = get_msg_line(TRUE, i); - if (mesg && mesg->str && strcmp(mesg->str, "")) + if (mesg && mesg->str && *mesg->str) curses_message_win_puts(mesg->str, TRUE); } curses_message_win_puts(toplines, TRUE); @@ -293,8 +306,10 @@ curses_prev_mesg() } -/* Shows Count: at the bottom of the message window, - popup_dialog is not currently implemented for this function */ +/* Display at the bottom of the message window without remembering the + line for ^P recall. Used for putstr(WIN_MESSAGE,ATR_NOHISTORY,text) + which core currently uses for 'Count: 123' and dolook's autodescribe. + popup_dialog is not currently implemented for this function. */ void curses_count_window(const char *count_text) @@ -303,13 +318,12 @@ curses_count_window(const char *count_text) int messageh, messagew; static WINDOW *countwin = NULL; - if ((count_text == NULL) && (countwin != NULL)) { - delwin(countwin); - countwin = NULL; + if (!count_text) { + if (countwin) + delwin(countwin), countwin = NULL; counting = FALSE; return; } - counting = TRUE; curses_get_window_xy(MESSAGE_WIN, &winx, &winy); @@ -322,18 +336,14 @@ curses_count_window(const char *count_text) winy += messageh - 1; - if (countwin == NULL) { -#ifndef PDCURSES - countwin = newwin(1, 25, winy, winx); -#endif /* !PDCURSES */ - } #ifdef PDCURSES - else { - curses_destroy_win(countwin); - } - - countwin = newwin(1, 25, winy, winx); + if (countwin) + curses_destroy_win(countwin), countwin = NULL; #endif /* PDCURSES */ + /* this used to specify a width of 25; that was adequate for 'Count: 123' + but not for dolook's autodescribe when it refers to a named monster */ + if (!countwin) + countwin = newwin(1, messagew, winy, winx); startx = 0; starty = 0; diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index 0c47d775d..c20138453 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -632,7 +632,7 @@ curses_get_count(int first_digit) current_count = LARGEST_INT; } - pline("Count: %ld", current_count); + custompline(SUPPRESS_HISTORY, "Count: %ld", current_count); current_char = curses_read_char(); } @@ -647,13 +647,17 @@ curses_get_count(int first_digit) /* Convert the given NetHack text attributes into the format curses -understands, and return that format mask. */ + understands, and return that format mask. */ int curses_convert_attr(int attr) { int curses_attr; + /* first, strip off control flags masked onto the display attributes + (caller should have already done this...) */ + attr &= ~(ATR_URGENT | ATR_NOHISTORY); + switch (attr) { case ATR_NONE: curses_attr = A_NORMAL; From 19d737951e62b0abab366a67ac46a6f9fad310e3 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 7 Feb 2019 16:48:37 -0800 Subject: [PATCH 2/2] curses: change from malloc() to nethack's alloc() There was no provision for malloc() potentially returning Null and it wasn't integrated with nethack's MONITOR_HEAP. 'heaputil' shows that the curses interface is leaking like a sieve. If some things are actually being allocated separately and then freed from within curses, those need to be thoroughly documented and maybe switched back to malloc(). --- doc/fixes36.2 | 5 ++++- win/curses/cursdial.c | 7 ++++--- win/curses/cursmesg.c | 9 +++++---- win/curses/cursmisc.c | 6 +++--- win/curses/curswins.c | 31 ++++++++++++++++++++----------- 5 files changed, 36 insertions(+), 22 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index dacb4f4a9..3073017f8 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.250 $ $NHDT-Date: 1549584261 2019/02/08 00:04:21 $ +$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.251 $ $NHDT-Date: 1549586901 2019/02/08 00:48:21 $ This fixes36.2 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.1 in April 2018. Please note, however, @@ -439,6 +439,9 @@ X11: its use of genl_status_update exposed a negative index use that could X11: rollback disabling of keystroke input for PICK_NONE menus (for scrolling) curses: catch up with tty to not put dolook/whatis autodescribe feedback into ^P message recall (multi-digit count feedback was already handled) +curses: if the interface code ran out of memory, it would crash rather than + attempt a controlled panic (which is fairly likely crash anyway if + done when there's no memory available) Platform- and/or Interface-Specific Fixes or Features diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index fd41e64ce..b4c5e66f1 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -478,7 +478,7 @@ curses_create_nhmenu(winid wid) return; } - new_menu = malloc(sizeof (nhmenu)); + new_menu = (nhmenu *) alloc((signed) sizeof (nhmenu)); new_menu->wid = wid; new_menu->prompt = NULL; new_menu->entries = NULL; @@ -524,7 +524,7 @@ curses_add_nhmenu_item(winid wid, int glyph, const ANY_P * identifier, new_str = curses_copy_of(str); curses_rtrim((char *) new_str); - new_item = malloc(sizeof (nhmenu_item)); + new_item = (nhmenu_item *) alloc((unsigned) sizeof (nhmenu_item)); new_item->wid = wid; new_item->glyph = glyph; new_item->identifier = *identifier; @@ -630,7 +630,8 @@ curses_display_nhmenu(winid wid, int how, MENU_ITEM_P ** _selected) curses_destroy_win(win); if (num_chosen > 0) { - selected = (MENU_ITEM_P *) malloc(num_chosen * sizeof (MENU_ITEM_P)); + selected = (MENU_ITEM_P *) alloc((unsigned) + (num_chosen * sizeof (MENU_ITEM_P))); count = 0; menu_item_ptr = current_menu->entries; diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index 3f90ed8bc..3876449a0 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -287,7 +287,7 @@ curses_prev_mesg() wid = curses_get_wid(NHW_MENU); curses_create_nhmenu(wid); - identifier = malloc(sizeof (anything)); + identifier = (anything *) alloc((unsigned) sizeof (anything)); identifier->a_void = NULL; for (count = 0; count < num_messages; count++) { @@ -380,13 +380,13 @@ curses_message_win_getline(const char *prompt, char *answer, int buffer) maxy = height - 1 + border_space; maxx = width - 1 + border_space; - tmpbuf = (char *)malloc(strlen(prompt) + buffer + 2); + tmpbuf = (char *) alloc((unsigned) ((int) strlen(prompt) + buffer + 2)); maxlines = buffer / width * 2; strcpy(tmpbuf, prompt); strcat(tmpbuf, " "); nlines = curses_num_lines(tmpbuf,width); maxlines += nlines * 2; - linestarts = (char **)malloc(sizeof(char*) * maxlines); + linestarts = (char **) alloc((unsigned) (sizeof (char *) * maxlines)); p_answer = tmpbuf + strlen(tmpbuf); linestarts[0] = tmpbuf; @@ -573,7 +573,8 @@ static void mesg_add_line(char *mline) { nhprev_mesg *tmp_mesg = NULL; - nhprev_mesg *current_mesg = malloc(sizeof (nhprev_mesg)); + nhprev_mesg *current_mesg = (nhprev_mesg *) alloc((unsigned) + (sizeof (nhprev_mesg))); current_mesg->str = curses_copy_of(mline); current_mesg->turn = moves; diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index c20138453..57a637bfe 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -220,12 +220,12 @@ curses_copy_of(const char *s) { if (!s) s = ""; - return strcpy((char *) alloc((unsigned) (strlen(s) + 1)), s); + return dupstr(s); } /* Determine the number of lines needed for a string for a dialog window -of the given width */ + of the given width */ int curses_num_lines(const char *str, int width) @@ -588,7 +588,7 @@ curses_view_file(const char *filename, boolean must_exist) wid = curses_get_wid(NHW_MENU); curses_create_nhmenu(wid); - identifier = malloc(sizeof (anything)); + identifier = (anything *) alloc(sizeof (anything)); identifier->a_void = NULL; while (dlb_fgets(buf, BUFSZ, fp) != NULL) { diff --git a/win/curses/curswins.c b/win/curses/curswins.c index c74a39871..d347b3133 100644 --- a/win/curses/curswins.c +++ b/win/curses/curswins.c @@ -79,7 +79,8 @@ curses_create_window(int width, int height, orient orientation) height += 2; if ((width > term_cols) || (height > term_rows)) { - impossible("curses_create_window: Terminal too small for dialog window"); + impossible( + "curses_create_window: Terminal too small for dialog window"); width = term_cols; height = term_rows; } @@ -193,7 +194,8 @@ WINDOW * curses_get_nhwin(winid wid) { if (!is_main_window(wid)) { - impossible("curses_get_nhwin: wid %d out of range. Not a main window.", wid); + impossible("curses_get_nhwin: wid %d out of range. Not a main window.", + wid); return NULL; } @@ -212,7 +214,8 @@ curses_add_nhwin(winid wid, int height, int width, int y, int x, int real_height = height; if (!is_main_window(wid)) { - impossible("curses_add_nhwin: wid %d out of range. Not a main window.", wid); + impossible("curses_add_nhwin: wid %d out of range. Not a main window.", + wid); return; } @@ -266,7 +269,7 @@ curses_add_wid(winid wid) nethack_wid *new_wid; nethack_wid *widptr = nhwids; - new_wid = malloc(sizeof (nethack_wid)); + new_wid = (nethack_wid *) alloc((unsigned) sizeof (nethack_wid)); new_wid->nhwid = wid; new_wid->next_wid = NULL; @@ -305,7 +308,8 @@ curses_del_nhwin(winid wid) } if (!is_main_window(wid)) { - impossible("curses_del_nhwin: wid %d out of range. Not a main window.", wid); + impossible("curses_del_nhwin: wid %d out of range. Not a main window.", + wid); return; } @@ -396,7 +400,9 @@ void curses_get_window_xy(winid wid, int *x, int *y) { if (!is_main_window(wid)) { - impossible("curses_get_window_xy: wid %d out of range. Not a main window.", wid); + impossible( + "curses_get_window_xy: wid %d out of range. Not a main window.", + wid); *x = 0; *y = 0; return; @@ -451,8 +457,9 @@ int curses_get_window_orientation(winid wid) { if (!is_main_window(wid)) { - impossible - ("curses_get_window_orientation: wid %d out of range. Not a main window.", wid); + impossible( + "curses_get_window_orientation: wid %d out of range. Not a main window.", + wid); return CENTER; } @@ -461,7 +468,7 @@ curses_get_window_orientation(winid wid) /* Output a line of text to specified NetHack window with given coordinates -and text attributes */ + and text attributes */ void curses_puts(winid wid, int attr, const char *text) @@ -490,10 +497,12 @@ curses_puts(winid wid, int attr, const char *text) if (curses_is_menu(wid) || curses_is_text(wid)) { if (!curses_menu_exists(wid)) { - impossible("curses_puts: Attempted write to nonexistant window %d!", wid); + impossible( + "curses_puts: Attempted write to nonexistant window %d!", + wid); return; } - identifier = malloc(sizeof (anything)); + identifier = (anything *) alloc((unsigned) sizeof (anything)); identifier->a_void = NULL; curses_add_nhmenu_item(wid, NO_GLYPH, identifier, 0, 0, attr, text, FALSE);