aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2017-03-08 00:14:59 +0000
committerPedro Alves <palves@redhat.com>2017-03-08 00:14:59 +0000
commit9753a2f6d74dc92d2ad94993a5479ee0edbc6887 (patch)
tree8249537542c50a6d702920e67170e7c0f51bd770
parent1a4dd9ddae4ce51724b4e08c6304e7c64f8f916f (diff)
downloadgdb-9753a2f6d74dc92d2ad94993a5479ee0edbc6887.zip
gdb-9753a2f6d74dc92d2ad94993a5479ee0edbc6887.tar.gz
gdb-9753a2f6d74dc92d2ad94993a5479ee0edbc6887.tar.bz2
Fix PR tui/21216: TUI line breaks regression
Commit d7e747318f4d04 ("Eliminate make_cleanup_ui_file_delete / make ui_file a class hierarchy") regressed the TUI's command window. Newlines miss doing a "carriage return", resulting in output like: ~~~~~~~~~~~~~~~~~~ (gdb) helpList of classes of commands: aliases -- Aliases of other commands breakpoints -- Making program stop at certain points ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Before the commit mentioned above, the default ui_file->to_write implementation had a hack that would defer into the ui_file->to_fputs method. The TUI's ui_file did not implement the to_write method, so all writes would end up going to the ncurses window via tui_file_fputs -> tui_puts. After the commit above, the hack is gone, but the TUI's ui_file still does not implement the ui_file::write method. Since tui_file inherits from stdio_file, writing to a tui_file ends up doing fwrite on the FILE stream the TUI is "associated" with, via stdio_file::write, instead of writing to the ncurses window. The fix is to have tui_file override the "write" method. New test included. gdb/ChangeLog: 2017-03-08 Pedro Alves <palves@redhat.com> PR tui/21216 * tui/tui-file.c (tui_file::write): New. * tui/tui-file.h (tui_file): Override "write". * tui/tui-io.c (do_tui_putc, update_start_line): New functions, factored out from ... (tui_puts): ... here. (tui_putc): Use them. (tui_write): New function. * tui/tui-io.h (tui_write): Declare. gdb/testsuite/ChangeLog: 2017-03-08 Pedro Alves <palves@redhat.com> PR tui/21216 * gdb.tui/tui-nl-filtered-output.exp: New file.
-rw-r--r--gdb/ChangeLog12
-rw-r--r--gdb/testsuite/ChangeLog5
-rw-r--r--gdb/testsuite/gdb.tui/tui-nl-filtered-output.exp57
-rw-r--r--gdb/tui/tui-file.c10
-rw-r--r--gdb/tui/tui-file.h3
-rw-r--r--gdb/tui/tui-io.c114
-rw-r--r--gdb/tui/tui-io.h4
7 files changed, 165 insertions, 40 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 3a156ad..432cdcc 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,15 @@
+2017-03-08 Pedro Alves <palves@redhat.com>
+
+ PR tui/21216
+ * tui/tui-file.c (tui_file::write): New.
+ * tui/tui-file.h (tui_file): Override "write".
+ * tui/tui-io.c (do_tui_putc, update_start_line): New functions,
+ factored out from ...
+ (tui_puts): ... here.
+ (tui_putc): Use them.
+ (tui_write): New function.
+ * tui/tui-io.h (tui_write): Declare.
+
2017-03-07 Sergio Durigan Junior <sergiodj@redhat.com>
* Makefile.in (SFILES): Replace "environ.c" with
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index f986520..0654bef 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,10 @@
2017-03-08 Pedro Alves <palves@redhat.com>
+ PR tui/21216
+ * gdb.tui/tui-nl-filtered-output.exp: New file.
+
+2017-03-08 Pedro Alves <palves@redhat.com>
+
* gdb.base/completion.exp: Move TUI completion tests to ...
* gdb.tui/completion.exp: ... this new file.
diff --git a/gdb/testsuite/gdb.tui/tui-nl-filtered-output.exp b/gdb/testsuite/gdb.tui/tui-nl-filtered-output.exp
new file mode 100644
index 0000000..d1f56f2
--- /dev/null
+++ b/gdb/testsuite/gdb.tui/tui-nl-filtered-output.exp
@@ -0,0 +1,57 @@
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Regression test for PR tui/21216 - TUI line breaks regression.
+#
+# Tests that newlines in filtered output force a "carriage return" in
+# the TUI command window. With a broken gdb, instead of:
+#
+# (gdb) printf "hello\nworld\n"
+# hello
+# world
+# (gdb)
+#
+# we'd get:
+#
+# (gdb) printf "hello\nworld\n"hello
+# world
+#
+# (gdb)
+
+gdb_exit
+gdb_start
+
+if {[skip_tui_tests]} {
+ return
+}
+
+# Enable the TUI.
+
+set test "tui enable"
+gdb_test_multiple "tui enable" $test {
+ -re "$gdb_prompt $" {
+ pass $test
+ }
+}
+
+# Make sure filtering/pagination is enabled, but make the window high
+# enough that we don't paginate in practice.
+gdb_test_no_output "set pagination on"
+gdb_test_no_output "set height 2000"
+
+gdb_test \
+ {printf "hello\nworld\n"} \
+ "hello\r\nworld" \
+ "correct line breaks"
diff --git a/gdb/tui/tui-file.c b/gdb/tui/tui-file.c
index 2f895b7..80a31f8 100644
--- a/gdb/tui/tui-file.c
+++ b/gdb/tui/tui-file.c
@@ -44,6 +44,16 @@ tui_file::puts (const char *linebuffer)
}
void
+tui_file::write (const char *buf, long length_buf)
+{
+ tui_write (buf, length_buf);
+ /* gdb_stdout is buffered, and the caller must gdb_flush it at
+ appropriate times. Other streams are not so buffered. */
+ if (this != gdb_stdout)
+ tui_refresh_cmd_win ();
+}
+
+void
tui_file::flush ()
{
/* gdb_stdout is buffered. Other files are always flushed on
diff --git a/gdb/tui/tui-file.h b/gdb/tui/tui-file.h
index aceaab6..c426a83 100644
--- a/gdb/tui/tui-file.h
+++ b/gdb/tui/tui-file.h
@@ -28,8 +28,9 @@ class tui_file : public stdio_file
public:
explicit tui_file (FILE *stream);
- void flush () override;
+ void write (const char *buf, long length_buf) override;
void puts (const char *) override;
+ void flush () override;
};
#endif
diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c
index 433762b..ba1ee9a 100644
--- a/gdb/tui/tui-io.c
+++ b/gdb/tui/tui-io.c
@@ -137,58 +137,94 @@ static int tui_readline_pipe[2];
This may be the main gdb prompt or a secondary prompt. */
static char *tui_rl_saved_prompt;
+/* Print a character in the curses command window. The output is
+ buffered. It is up to the caller to refresh the screen if
+ necessary. */
+
+static void
+do_tui_putc (WINDOW *w, char c)
+{
+ static int tui_skip_line = -1;
+
+ /* Catch annotation and discard them. We need two \032 and discard
+ until a \n is seen. */
+ if (c == '\032')
+ {
+ tui_skip_line++;
+ }
+ else if (tui_skip_line != 1)
+ {
+ tui_skip_line = -1;
+ /* Expand TABs, since ncurses on MS-Windows doesn't. */
+ if (c == '\t')
+ {
+ int col;
+
+ col = getcurx (w);
+ do
+ {
+ waddch (w, ' ');
+ col++;
+ }
+ while ((col % 8) != 0);
+ }
+ else
+ waddch (w, c);
+ }
+ else if (c == '\n')
+ tui_skip_line = -1;
+}
+
+/* Update the cached value of the command window's start line based on
+ the window's current Y coordinate. */
+
+static void
+update_cmdwin_start_line ()
+{
+ TUI_CMD_WIN->detail.command_info.start_line
+ = getcury (TUI_CMD_WIN->generic.handle);
+}
+
+/* Print a character in the curses command window. The output is
+ buffered. It is up to the caller to refresh the screen if
+ necessary. */
+
static void
tui_putc (char c)
{
- char buf[2];
+ WINDOW *w = TUI_CMD_WIN->generic.handle;
+
+ do_tui_putc (w, c);
+ update_cmdwin_start_line ();
+}
+
+/* Print LENGTH characters from the buffer pointed to by BUF to the
+ curses command window. The output is buffered. It is up to the
+ caller to refresh the screen if necessary. */
+
+void
+tui_write (const char *buf, size_t length)
+{
+ WINDOW *w = TUI_CMD_WIN->generic.handle;
- buf[0] = c;
- buf[1] = 0;
- tui_puts (buf);
+ for (size_t i = 0; i < length; i++)
+ do_tui_putc (w, buf[i]);
+ update_cmdwin_start_line ();
}
-/* Print the string in the curses command window.
- The output is buffered. It is up to the caller to refresh the screen
- if necessary. */
+/* Print a string in the curses command window. The output is
+ buffered. It is up to the caller to refresh the screen if
+ necessary. */
void
tui_puts (const char *string)
{
- static int tui_skip_line = -1;
+ WINDOW *w = TUI_CMD_WIN->generic.handle;
char c;
- WINDOW *w;
- w = TUI_CMD_WIN->generic.handle;
while ((c = *string++) != 0)
- {
- /* Catch annotation and discard them. We need two \032 and
- discard until a \n is seen. */
- if (c == '\032')
- {
- tui_skip_line++;
- }
- else if (tui_skip_line != 1)
- {
- tui_skip_line = -1;
- /* Expand TABs, since ncurses on MS-Windows doesn't. */
- if (c == '\t')
- {
- int col;
-
- col = getcurx (w);
- do
- {
- waddch (w, ' ');
- col++;
- } while ((col % 8) != 0);
- }
- else
- waddch (w, c);
- }
- else if (c == '\n')
- tui_skip_line = -1;
- }
- TUI_CMD_WIN->detail.command_info.start_line = getcury (w);
+ do_tui_putc (w, c);
+ update_cmdwin_start_line ();
}
/* Readline callback.
diff --git a/gdb/tui/tui-io.h b/gdb/tui/tui-io.h
index e1d5f86..3bd465f 100644
--- a/gdb/tui/tui-io.h
+++ b/gdb/tui/tui-io.h
@@ -28,6 +28,10 @@ class cli_ui_out;
/* Print the string in the curses command window. */
extern void tui_puts (const char *);
+/* Print LENGTH characters from the buffer pointed to by BUF to the
+ curses command window. */
+extern void tui_write (const char *buf, size_t length);
+
/* Setup the IO for curses or non-curses mode. */
extern void tui_setup_io (int mode);