diff options
-rw-r--r-- | gdb/ChangeLog | 29 | ||||
-rw-r--r-- | gdb/Makefile.in | 12 | ||||
-rw-r--r-- | gdb/cli/cli-style.c | 9 | ||||
-rw-r--r-- | gdb/config.in | 3 | ||||
-rwxr-xr-x | gdb/configure | 30 | ||||
-rw-r--r-- | gdb/configure.ac | 23 | ||||
-rw-r--r-- | gdb/source-cache.c | 209 | ||||
-rw-r--r-- | gdb/source-cache.h | 79 | ||||
-rw-r--r-- | gdb/source.c | 38 | ||||
-rw-r--r-- | gdb/tui/tui-data.c | 5 | ||||
-rw-r--r-- | gdb/tui/tui-io.c | 11 | ||||
-rw-r--r-- | gdb/tui/tui-io.h | 4 | ||||
-rw-r--r-- | gdb/tui/tui-source.c | 302 | ||||
-rw-r--r-- | gdb/tui/tui-winsource.c | 17 | ||||
-rw-r--r-- | gdb/utils.c | 4 | ||||
-rw-r--r-- | gdb/utils.h | 4 |
16 files changed, 576 insertions, 203 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 449cf84..c853279 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,34 @@ 2018-12-28 Tom Tromey <tom@tromey.com> + * utils.h (can_emit_style_escape): Declare. + * utils.c (can_emit_style_escape): No longer static. + * cli/cli-style.c (set_style_enabled): New function. + (_initialize_cli_style): Use it. + * tui/tui-winsource.c (tui_show_source_line): Use tui_puts. + (tui_alloc_source_buffer): Change how source lines are allocated. + * tui/tui-source.c (copy_source_line): New function. + (tui_set_source_content): Use source cache. + * tui/tui-io.h (tui_puts): Update. + * tui/tui-io.c (tui_puts_internal): Add window parameter. + (tui_puts): Likewise. + (tui_redisplay_readline): Update. + * tui/tui-data.c (free_content_elements): Change how source window + contents are freed. + * source.c (forget_cached_source_info): Clear the source cache. + (print_source_lines_base): Use the source cache. + * source-cache.h: New file. + * source-cache.c: New file. + * configure.ac: Check for GNU Source Highlight library. + * configure: Update. + * config.in: Update. + * Makefile.in (SRCHIGH_LIBS, SRCHIGH_CFLAGS): New variables. + (INTERNAL_CFLAGS_BASE): Add SRCHIGH_CFLAGS. + (CLIBS): Add SRCHIGH_LIBS. + (COMMON_SFILES): Add source-cache.c. + (HFILES_NO_SRCDIR): Add source-cache.h. + +2018-12-28 Tom Tromey <tom@tromey.com> + * tui/tui-winsource.c (tui_show_source_line): Use wclrtoeol. 2018-12-28 Tom Tromey <tom@tromey.com> diff --git a/gdb/Makefile.in b/gdb/Makefile.in index b2a1281..1ec1147 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -194,6 +194,10 @@ LIBIPT = @LIBIPT@ # Where is libmpfr? This will be empty if libmpfr was not available. LIBMPFR = @LIBMPFR@ +# GNU source highlight library. +SRCHIGH_LIBS = @SRCHIGH_LIBS@ +SRCHIGH_CFLAGS = @SRCHIGH_CFLAGS@ + WARN_CFLAGS = @WARN_CFLAGS@ WERROR_CFLAGS = @WERROR_CFLAGS@ GDB_WARN_CFLAGS = $(WARN_CFLAGS) @@ -566,7 +570,8 @@ INTERNAL_CFLAGS_BASE = \ $(CXXFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \ $(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) $(ZLIBINC) \ $(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \ - $(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) + $(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) \ + $(SRCHIGH_CFLAGS) INTERNAL_WARN_CFLAGS = $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS) INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS) @@ -589,7 +594,8 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(ZLIB) $(INTL) $(LIBIBERTY) $(LIBD $(XM_CLIBS) $(GDBTKLIBS) \ @LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \ $(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \ - $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR) + $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR) \ + $(SRCHIGH_LIBS) CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \ $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) @@ -1101,6 +1107,7 @@ COMMON_SFILES = \ solib.c \ solib-target.c \ source.c \ + source-cache.c \ stabsread.c \ stack.c \ std-regs.c \ @@ -1377,6 +1384,7 @@ HFILES_NO_SRCDIR = \ solib-target.h \ solist.h \ source.h \ + source-cache.h \ sparc-nat.h \ sparc-ravenscar-thread.h \ sparc-tdep.h \ diff --git a/gdb/cli/cli-style.c b/gdb/cli/cli-style.c index 0d850b1..0308e1c 100644 --- a/gdb/cli/cli-style.c +++ b/gdb/cli/cli-style.c @@ -20,6 +20,7 @@ #include "defs.h" #include "cli/cli-cmds.h" #include "cli/cli-style.h" +#include "source-cache.h" /* True if styling is enabled. */ @@ -217,6 +218,12 @@ show_style (const char *arg, int from_tty) } static void +set_style_enabled (const char *args, int from_tty, struct cmd_list_element *c) +{ + g_source_cache.clear (); +} + +static void show_style_enabled (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { @@ -245,7 +252,7 @@ Configure various style-related variables, such as colors"), Set whether CLI styling is enabled."), _("\ Show whether CLI is enabled."), _("\ If enabled, output to the terminal is styled."), - NULL, show_style_enabled, + set_style_enabled, show_style_enabled, &style_set_list, &style_show_list); file_name_style.add_setshow_commands ("filename", no_class, diff --git a/gdb/config.in b/gdb/config.in index 760db6b..ea907d2 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -426,6 +426,9 @@ /* Define to 1 if the system has the type `socklen_t'. */ #undef HAVE_SOCKLEN_T +/* Define to 1 if the source-highlight library is available */ +#undef HAVE_SOURCE_HIGHLIGHT + /* Define to 1 if you have the <stdint.h> header file. */ #undef HAVE_STDINT_H diff --git a/gdb/configure b/gdb/configure index da701cd..9c99213 100755 --- a/gdb/configure +++ b/gdb/configure @@ -701,6 +701,8 @@ ALLOCA LTLIBIPT LIBIPT HAVE_LIBIPT +SRCHIGH_CFLAGS +SRCHIGH_LIBS HAVE_GUILE_FALSE HAVE_GUILE_TRUE GUILE_LIBS @@ -11469,6 +11471,34 @@ else fi +# ---------------------------- # +# Check for source highlight. # +# ---------------------------- # + +SRCHIGH_LIBS= +SRCHIGH_CFLAGS= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for source highlight" >&5 +$as_echo_n "checking for source highlight... " >&6; } +if test "${pkg_config_prog_path}" = "missing"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no - pkg-config not found" >&5 +$as_echo "no - pkg-config not found" >&6; } +else + if ${pkg_config_prog_path} --exists source-highlight; then + SRCHIGH_CFLAGS=`${pkg_config_prog_path} --cflags source-highlight` + SRCHIGH_LIBS=`${pkg_config_prog_path} --libs source-highlight` + +$as_echo "#define HAVE_SOURCE_HIGHLIGHT 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi +fi + + + # --------------------- # # Check for libmcheck. # # --------------------- # diff --git a/gdb/configure.ac b/gdb/configure.ac index 0025b1d..dbd332e 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -1226,6 +1226,29 @@ AC_SUBST(GUILE_CPPFLAGS) AC_SUBST(GUILE_LIBS) AM_CONDITIONAL(HAVE_GUILE, test "${have_libguile}" != no) +# ---------------------------- # +# Check for source highlight. # +# ---------------------------- # + +SRCHIGH_LIBS= +SRCHIGH_CFLAGS= +AC_MSG_CHECKING([for the source-highlight library]) +if test "${pkg_config_prog_path}" = "missing"; then + AC_MSG_RESULT([no - pkg-config not found]) +else + if ${pkg_config_prog_path} --exists source-highlight; then + SRCHIGH_CFLAGS=`${pkg_config_prog_path} --cflags source-highlight` + SRCHIGH_LIBS=`${pkg_config_prog_path} --libs source-highlight` + AC_DEFINE([HAVE_SOURCE_HIGHLIGHT], 1, + [Define to 1 if the source-highlight library is available]) + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi +fi +AC_SUBST(SRCHIGH_LIBS) +AC_SUBST(SRCHIGH_CFLAGS) + # --------------------- # # Check for libmcheck. # # --------------------- # diff --git a/gdb/source-cache.c b/gdb/source-cache.c new file mode 100644 index 0000000..5685180 --- /dev/null +++ b/gdb/source-cache.c @@ -0,0 +1,209 @@ +/* Cache of styled source file text + Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of GDB. + + 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/>. */ + +#include "defs.h" +#include "source-cache.h" +#include "common/scoped_fd.h" +#include "source.h" +#include "cli/cli-style.h" + +#ifdef HAVE_SOURCE_HIGHLIGHT +#include <fstream> +#include <sstream> +#include <srchilite/sourcehighlight.h> +#include <srchilite/langmap.h> +#endif + +/* The number of source files we'll cache. */ + +#define MAX_ENTRIES 5 + +/* See source-cache.h. */ + +source_cache g_source_cache; + +/* See source-cache.h. */ + +bool +source_cache::get_plain_source_lines (struct symtab *s, int first_line, + int last_line, std::string *lines) +{ + scoped_fd desc (open_source_file (s)); + if (desc.get () < 0) + return false; + + if (s->line_charpos == 0) + find_source_lines (s, desc.get ()); + + if (first_line < 1 || first_line > s->nlines || last_line < 1) + return false; + + if (lseek (desc.get (), s->line_charpos[first_line - 1], SEEK_SET) < 0) + perror_with_name (symtab_to_filename_for_display (s)); + + int last_charpos; + if (last_line >= s->nlines) + { + struct stat st; + + if (fstat (desc.get (), &st) < 0) + perror_with_name (symtab_to_filename_for_display (s)); + /* We could cache this in line_charpos... */ + last_charpos = st.st_size; + } + else + last_charpos = s->line_charpos[last_line]; + + lines->resize (last_charpos - s->line_charpos[first_line - 1]); + if (myread (desc.get (), &(*lines)[0], lines->size ()) < 0) + perror_with_name (symtab_to_filename_for_display (s)); + + return true; +} + +/* See source-cache.h. */ + +bool +source_cache::extract_lines (const struct source_text &text, int first_line, + int last_line, std::string *lines) +{ + int lineno = 1; + std::string::size_type pos = 0; + std::string::size_type first_pos = std::string::npos; + + while (pos != std::string::npos && lineno <= last_line) + { + std::string::size_type new_pos = text.contents.find ('\n', pos); + + if (lineno == first_line) + first_pos = pos; + + pos = new_pos; + if (lineno == last_line || pos == std::string::npos) + { + if (pos == std::string::npos) + pos = text.contents.size (); + *lines = text.contents.substr (first_pos, pos - first_pos); + return true; + } + ++lineno; + ++pos; + } + + return false; +} + +/* Return the Source Highlight language name, given a gdb language + LANG. Returns NULL if the language is not known. */ + +static const char * +get_language_name (enum language lang) +{ + switch (lang) + { + case language_c: + case language_objc: + return "c.lang"; + + case language_cplus: + return "cpp.lang"; + + case language_d: + return "d.lang"; + + case language_go: + return "go.lang"; + + case language_fortran: + return "fortran.lang"; + + case language_m2: + /* Not handled by Source Highlight. */ + break; + + case language_asm: + return "asm.lang"; + + case language_pascal: + return "pascal.lang"; + + case language_opencl: + /* Not handled by Source Highlight. */ + break; + + case language_rust: + /* Not handled by Source Highlight. */ + break; + + case language_ada: + return "ada.lang"; + + default: + break; + } + + return nullptr; +} + +/* See source-cache.h. */ + +bool +source_cache::get_source_lines (struct symtab *s, int first_line, + int last_line, std::string *lines) +{ + if (first_line < 1 || last_line < 1 || first_line > last_line) + return false; + +#ifdef HAVE_SOURCE_HIGHLIGHT + if (can_emit_style_escape (gdb_stdout)) + { + const char *fullname = symtab_to_fullname (s); + + for (const auto &item : m_source_map) + { + if (item.fullname == fullname) + return extract_lines (item, first_line, last_line, lines); + } + + const char *lang_name = get_language_name (SYMTAB_LANGUAGE (s)); + if (lang_name != nullptr) + { + std::ifstream input (fullname); + if (input.is_open ()) + { + srchilite::SourceHighlight highlighter ("esc.outlang"); + highlighter.setStyleFile("esc.style"); + + std::ostringstream output; + highlighter.highlight (input, output, lang_name, fullname); + + source_text result = { fullname, output.str () }; + m_source_map.push_back (std::move (result)); + + if (m_source_map.size () > MAX_ENTRIES) + m_source_map.erase (m_source_map.begin ()); + + return extract_lines (m_source_map.back (), first_line, + last_line, lines); + } + } + } +#endif /* HAVE_SOURCE_HIGHLIGHT */ + + return get_plain_source_lines (s, first_line, last_line, lines); +} diff --git a/gdb/source-cache.h b/gdb/source-cache.h new file mode 100644 index 0000000..2236d38 --- /dev/null +++ b/gdb/source-cache.h @@ -0,0 +1,79 @@ +/* Cache of styled source file text + Copyright (C) 2018 Free Software Foundation, Inc. + + This file is part of GDB. + + 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/>. */ + +#ifndef SOURCE_CACHE_H +#define SOURCE_CACHE_H + +/* This caches highlighted source text, keyed by the source file's + full name. A size-limited LRU cache is used. + + Highlighting depends on the GNU Source Highlight library. When not + available, this cache will fall back on reading plain text from the + appropriate file. */ +class source_cache +{ +public: + + source_cache () + { + } + + /* Get the source text for the source file in symtab S. FIRST_LINE + and LAST_LINE are the first and last lines to return; line + numbers are 1-based. If the file cannot be read, false is + returned. Otherwise, LINES is set to the desired text. The + returned text may include ANSI terminal escapes. */ + bool get_source_lines (struct symtab *s, int first_line, + int last_line, std::string *lines); + + /* Remove all the items from the source cache. */ + void clear () + { + m_source_map.clear (); + } + +private: + + /* One element in the cache. */ + struct source_text + { + /* The full name of the file. */ + std::string fullname; + /* The contents of the file. */ + std::string contents; + }; + + /* A helper function for get_source_lines that is used when the + source lines are not highlighted. The arguments and return value + are as for get_source_lines. */ + bool get_plain_source_lines (struct symtab *s, int first_line, + int last_line, std::string *lines); + /* A helper function for get_plain_source_lines that extracts the + desired source lines from TEXT, putting them into LINES. The + arguments and return value are as for get_source_lines. */ + bool extract_lines (const struct source_text &text, int first_line, + int last_line, std::string *lines); + + /* The contents of the cache. */ + std::vector<source_text> m_source_map; +}; + +/* The global source cache. */ +extern source_cache g_source_cache; + +#endif /* SOURCE_CACHE_H */ diff --git a/gdb/source.c b/gdb/source.c index 575e46c..66ef883 100644 --- a/gdb/source.c +++ b/gdb/source.c @@ -45,6 +45,7 @@ #include "common/scoped_fd.h" #include <algorithm> #include "common/pathstuff.h" +#include "source-cache.h" #define OPEN_MODE (O_RDONLY | O_BINARY) #define FDOPEN_MODE FOPEN_RB @@ -393,6 +394,7 @@ forget_cached_source_info (void) forget_cached_source_info_for_objfile (objfile); } + g_source_cache.clear (); last_source_visited = NULL; } @@ -1344,25 +1346,18 @@ print_source_lines_base (struct symtab *s, int line, int stopline, last_source_error = 0; - if (s->line_charpos == 0) - find_source_lines (s, desc.get ()); - - if (line < 1 || line > s->nlines) + std::string lines; + if (!g_source_cache.get_source_lines (s, line, stopline - 1, &lines)) error (_("Line number %d out of range; %s has %d lines."), line, symtab_to_filename_for_display (s), s->nlines); - if (lseek (desc.get (), s->line_charpos[line - 1], 0) < 0) - perror_with_name (symtab_to_filename_for_display (s)); - - gdb_file_up stream = desc.to_file (FDOPEN_MODE); - clearerr (stream.get ()); - + const char *iter = lines.c_str (); while (nlines-- > 0) { char buf[20]; - c = fgetc (stream.get ()); - if (c == EOF) + c = *iter++; + if (c == '\0') break; last_line_listed = current_source_line; if (flags & PRINT_SOURCE_LINES_FILENAME) @@ -1374,7 +1369,7 @@ print_source_lines_base (struct symtab *s, int line, int stopline, uiout->text (buf); do { - if (c < 040 && c != '\t' && c != '\n' && c != '\r') + if (c < 040 && c != '\t' && c != '\n' && c != '\r' && c != '\033') { xsnprintf (buf, sizeof (buf), "^%c", c + 0100); uiout->text (buf); @@ -1384,12 +1379,13 @@ print_source_lines_base (struct symtab *s, int line, int stopline, else if (c == '\r') { /* Skip a \r character, but only before a \n. */ - int c1 = fgetc (stream.get ()); - - if (c1 != '\n') + if (iter[1] == '\n') + { + ++iter; + c = '\n'; + } + else printf_filtered ("^%c", c + 0100); - if (c1 != EOF) - ungetc (c1, stream.get ()); } else { @@ -1397,8 +1393,12 @@ print_source_lines_base (struct symtab *s, int line, int stopline, uiout->text (buf); } } - while (c != '\n' && (c = fgetc (stream.get ())) >= 0); + while (c != '\n' && (c = *iter++) != '\0'); + if (c == '\0') + break; } + if (lines.back () != '\n') + uiout->text ("\n"); } /* Show source lines from the file of symtab S, starting with line diff --git a/gdb/tui/tui-data.c b/gdb/tui/tui-data.c index 4391f0d..2b95f19 100644 --- a/gdb/tui/tui-data.c +++ b/gdb/tui/tui-data.c @@ -838,7 +838,7 @@ free_content_elements (tui_win_content content, { int i; - if (type == SRC_WIN || type == DISASSEM_WIN) + if (type == DISASSEM_WIN) { /* Free whole source block. */ xfree (content[0]->which_element.source.line); @@ -854,6 +854,9 @@ free_content_elements (tui_win_content content, { switch (type) { + case SRC_WIN: + xfree (element->which_element.source.line); + break; case DATA_WIN: xfree (element); break; diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c index 5a84d08..29994a6 100644 --- a/gdb/tui/tui-io.c +++ b/gdb/tui/tui-io.c @@ -367,9 +367,8 @@ tui_write (const char *buf, size_t length) } static void -tui_puts_internal (const char *string, int *height) +tui_puts_internal (WINDOW *w, const char *string, int *height) { - WINDOW *w = TUI_CMD_WIN->generic.handle; char c; int prev_col = 0; @@ -410,9 +409,11 @@ tui_puts_internal (const char *string, int *height) necessary. */ void -tui_puts (const char *string) +tui_puts (const char *string, WINDOW *w) { - tui_puts_internal (string, nullptr); + if (w == nullptr) + w = TUI_CMD_WIN->generic.handle; + tui_puts_internal (w, string, nullptr); } /* Readline callback. @@ -453,7 +454,7 @@ tui_redisplay_readline (void) prev_col = 0; height = 1; if (prompt != nullptr) - tui_puts_internal (prompt, &height); + tui_puts_internal (TUI_CMD_WIN->generic.handle, prompt, &height); prev_col = getcurx (w); for (in = 0; in <= rl_end; in++) diff --git a/gdb/tui/tui-io.h b/gdb/tui/tui-io.h index 11752d0..9588763 100644 --- a/gdb/tui/tui-io.h +++ b/gdb/tui/tui-io.h @@ -22,11 +22,13 @@ #ifndef TUI_IO_H #define TUI_IO_H +#include "gdb_curses.h" + struct ui_out; class cli_ui_out; /* Print the string in the curses command window. */ -extern void tui_puts (const char *); +extern void tui_puts (const char *, WINDOW * = nullptr); /* Print LENGTH characters from the buffer pointed to by BUF to the curses command window. */ diff --git a/gdb/tui/tui-source.c b/gdb/tui/tui-source.c index 3c4f06b..260b274 100644 --- a/gdb/tui/tui-source.c +++ b/gdb/tui/tui-source.c @@ -28,14 +28,90 @@ #include "symtab.h" #include "objfiles.h" #include "filenames.h" +#include "source-cache.h" #include "tui/tui.h" #include "tui/tui-data.h" +#include "tui/tui-io.h" #include "tui/tui-stack.h" #include "tui/tui-winsource.h" #include "tui/tui-source.h" #include "gdb_curses.h" +/* A helper function for tui_set_source_content that extracts some + source text from PTR. LINE_NO is the line number; FIRST_COL is the + first column to extract, and LINE_WIDTH is the number of characters + to display. Returns a string holding the desired text. */ + +static std::string +copy_source_line (const char **ptr, int line_no, int first_col, + int line_width) +{ + const char *lineptr = *ptr; + + /* Init the line with the line number. */ + std::string result = string_printf ("%-6d", line_no); + int len = result.size (); + len = len - ((len / tui_tab_width) * tui_tab_width); + result.append (len, ' '); + + int column = 0; + char c; + do + { + int skip_bytes; + + c = *lineptr; + if (c == '\033' && skip_ansi_escape (lineptr, &skip_bytes)) + { + /* We always have to preserve escapes. */ + result.append (lineptr, lineptr + skip_bytes); + lineptr += skip_bytes; + continue; + } + + ++lineptr; + ++column; + /* We have to process all the text in order to pick up all the + escapes. */ + if (column < first_col || column > first_col + line_width) + continue; + + if (c == '\n' || c == '\r' || c == '\0') + { + /* Nothing. */ + } + else if (c < 040 && c != '\t') + { + result.push_back ('^'); + result.push_back (c + 0100); + } + else if (c == 0177) + { + result.push_back ('^'); + result.push_back ('?'); + } + else if (c == '\t') + { + int j, max_tab_len = tui_tab_width; + + for (j = column - ((column / max_tab_len) * max_tab_len); + j < max_tab_len && column < first_col + line_width; + column++, j++) + result.push_back (' '); + } + else + result.push_back (c); + } + while (c != '\0' && c != '\n' && c != '\r'); + + if (c == '\r' && *lineptr == '\n') + ++lineptr; + *ptr = lineptr; + + return result; +} + /* Function to display source in the source window. */ enum tui_status tui_set_source_content (struct symtab *s, @@ -46,8 +122,7 @@ tui_set_source_content (struct symtab *s, if (s != (struct symtab *) NULL) { - int i, c, line_width, nlines; - char *src_line = 0; + int line_width, nlines; if ((ret = tui_alloc_source_buffer (TUI_SRC_WIN)) == TUI_SUCCESS) { @@ -55,8 +130,10 @@ tui_set_source_content (struct symtab *s, /* Take hilite (window border) into account, when calculating the number of lines. */ nlines = (line_no + (TUI_SRC_WIN->generic.height - 2)) - line_no; - scoped_fd desc = open_source_file (s); - if (desc.get () < 0) + + std::string srclines; + if (!g_source_cache.get_source_lines (s, line_no, line_no + nlines, + &srclines)) { if (!noerror) { @@ -70,165 +147,68 @@ tui_set_source_content (struct symtab *s, } else { - if (s->line_charpos == 0) - find_source_lines (s, desc.get ()); - - if (line_no < 1 || line_no > s->nlines) - printf_unfiltered ("Line number %d out of range; " - "%s has %d lines.\n", - line_no, - symtab_to_filename_for_display (s), - s->nlines); - else if (lseek (desc.get (), s->line_charpos[line_no - 1], 0) - < 0) - perror_with_name (symtab_to_filename_for_display (s)); - else + int cur_line_no, cur_line; + struct tui_gen_win_info *locator + = tui_locator_win_info_ptr (); + struct tui_source_info *src + = &TUI_SRC_WIN->detail.source_info; + const char *s_filename = symtab_to_filename_for_display (s); + + if (TUI_SRC_WIN->generic.title) + xfree (TUI_SRC_WIN->generic.title); + TUI_SRC_WIN->generic.title = xstrdup (s_filename); + + xfree (src->fullname); + src->fullname = xstrdup (symtab_to_fullname (s)); + + cur_line = 0; + src->gdbarch = get_objfile_arch (SYMTAB_OBJFILE (s)); + src->start_line_or_addr.loa = LOA_LINE; + cur_line_no = src->start_line_or_addr.u.line_no = line_no; + + const char *iter = srclines.c_str (); + while (cur_line < nlines) { - int offset, cur_line_no, cur_line, cur_len, threshold; - struct tui_gen_win_info *locator - = tui_locator_win_info_ptr (); - struct tui_source_info *src - = &TUI_SRC_WIN->detail.source_info; - const char *s_filename = symtab_to_filename_for_display (s); - - if (TUI_SRC_WIN->generic.title) - xfree (TUI_SRC_WIN->generic.title); - TUI_SRC_WIN->generic.title = xstrdup (s_filename); - - xfree (src->fullname); - src->fullname = xstrdup (symtab_to_fullname (s)); - - /* Determine the threshold for the length of the - line and the offset to start the display. */ - offset = src->horizontal_offset; - threshold = (line_width - 1) + offset; - gdb_file_up stream = desc.to_file (FOPEN_RT); - clearerr (stream.get ()); - cur_line = 0; - src->gdbarch = get_objfile_arch (SYMTAB_OBJFILE (s)); - src->start_line_or_addr.loa = LOA_LINE; - cur_line_no = src->start_line_or_addr.u.line_no = line_no; - if (offset > 0) - src_line = (char *) xmalloc ( - (threshold + 1) * sizeof (char)); - while (cur_line < nlines) - { - struct tui_win_element *element - = TUI_SRC_WIN->generic.content[cur_line]; - - /* Get the first character in the line. */ - c = fgetc (stream.get ()); - - if (offset == 0) - src_line = TUI_SRC_WIN->generic.content[cur_line] - ->which_element.source.line; - /* Init the line with the line number. */ - sprintf (src_line, "%-6d", cur_line_no); - cur_len = strlen (src_line); - i = cur_len - ((cur_len / tui_tab_width) - * tui_tab_width); - while (i < tui_tab_width) - { - src_line[cur_len] = ' '; - i++; - cur_len++; - } - src_line[cur_len] = (char) 0; - - /* Set whether element is the execution point - and whether there is a break point on it. */ - element->which_element.source.line_or_addr.loa = - LOA_LINE; - element->which_element.source.line_or_addr.u.line_no = - cur_line_no; - element->which_element.source.is_exec_point = - (filename_cmp (locator->content[0] - ->which_element.locator.full_name, - symtab_to_fullname (s)) == 0 - && cur_line_no - == locator->content[0] - ->which_element.locator.line_no); - if (c != EOF) - { - i = strlen (src_line) - 1; - do - { - if ((c != '\n') && (c != '\r') - && (++i < threshold)) - { - if (c < 040 && c != '\t') - { - src_line[i++] = '^'; - src_line[i] = c + 0100; - } - else if (c == 0177) - { - src_line[i++] = '^'; - src_line[i] = '?'; - } - else - { /* Store the charcter in the - line buffer. If it is a tab, - then translate to the correct - number of chars so we don't - overwrite our buffer. */ - if (c == '\t') - { - int j, max_tab_len - = tui_tab_width; - - for (j = i - ((i / max_tab_len) - * max_tab_len); - j < max_tab_len - && i < threshold; - i++, j++) - src_line[i] = ' '; - i--; - } - else - src_line[i] = c; - } - src_line[i + 1] = 0; - } - else - { /* If we have not reached EOL, then - eat chars until we do. */ - while (c != EOF && c != '\n' && c != '\r') - c = fgetc (stream.get ()); - /* Handle non-'\n' end-of-line. */ - if (c == '\r' - && (c = fgetc (stream.get ())) != '\n' - && c != EOF) - { - ungetc (c, stream.get ()); - c = '\r'; - } - - } - } - while (c != EOF && c != '\n' && c != '\r' - && i < threshold - && (c = fgetc (stream.get ()))); - } - /* Now copy the line taking the offset into - account. */ - if (offset == 0) - ; - else if (strlen (src_line) > offset) - strcpy (TUI_SRC_WIN->generic.content[cur_line] - ->which_element.source.line, - &src_line[offset]); - else - TUI_SRC_WIN->generic.content[cur_line] - ->which_element.source.line[0] = (char) 0; - cur_line++; - cur_line_no++; - } - if (offset > 0) - xfree (src_line); - TUI_SRC_WIN->generic.content_size = nlines; - ret = TUI_SUCCESS; + struct tui_win_element *element + = TUI_SRC_WIN->generic.content[cur_line]; + + std::string text; + if (*iter != '\0') + text = copy_source_line (&iter, cur_line_no, + src->horizontal_offset, + line_width); + + /* Set whether element is the execution point + and whether there is a break point on it. */ + element->which_element.source.line_or_addr.loa = + LOA_LINE; + element->which_element.source.line_or_addr.u.line_no = + cur_line_no; + element->which_element.source.is_exec_point = + (filename_cmp (locator->content[0] + ->which_element.locator.full_name, + symtab_to_fullname (s)) == 0 + && cur_line_no + == locator->content[0] + ->which_element.locator.line_no); + + xfree (TUI_SRC_WIN->generic.content[cur_line] + ->which_element.source.line); + int alloc_len = text.size (); + if (alloc_len < line_width) + alloc_len = line_width + 1; + TUI_SRC_WIN->generic.content[cur_line] + ->which_element.source.line + = (char *) xmalloc (alloc_len); + strcpy (TUI_SRC_WIN->generic.content[cur_line] + ->which_element.source.line, + text.c_str ()); + + cur_line++; + cur_line_no++; } + TUI_SRC_WIN->generic.content_size = nlines; + ret = TUI_SUCCESS; } } } diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c index 0bf7438..00b4b9e 100644 --- a/gdb/tui/tui-winsource.c +++ b/gdb/tui/tui-winsource.c @@ -31,6 +31,7 @@ #include "tui/tui.h" #include "tui/tui-data.h" +#include "tui/tui-io.h" #include "tui/tui-stack.h" #include "tui/tui-win.h" #include "tui/tui-wingeneral.h" @@ -277,8 +278,9 @@ tui_show_source_line (struct tui_win_info *win_info, int lineno) if (line->which_element.source.is_exec_point) wattron (win_info->generic.handle, A_STANDOUT); - mvwaddstr (win_info->generic.handle, lineno, 1, - line->which_element.source.line); + wmove (win_info->generic.handle, lineno, 1); + tui_puts (line->which_element.source.line, + win_info->generic.handle); if (line->which_element.source.is_exec_point) wattroff (win_info->generic.handle, A_STANDOUT); @@ -595,7 +597,6 @@ tui_update_exec_info (struct tui_win_info *win_info) enum tui_status tui_alloc_source_buffer (struct tui_win_info *win_info) { - char *src_line_buf; int i, line_width, max_lines; /* The window width/height includes the highlight box. Determine actual @@ -603,20 +604,14 @@ tui_alloc_source_buffer (struct tui_win_info *win_info) max_lines = win_info->generic.height - 2; line_width = win_info->generic.width - 2 + 1; - /* - * Allocate the buffer for the source lines. Do this only once - * since they will be re-used for all source displays. The only - * other time this will be done is when a window's size changes. - */ + /* Allocate the buffer for the source lines. */ if (win_info->generic.content == NULL) { - src_line_buf = (char *) - xmalloc ((max_lines * line_width) * sizeof (char)); /* Allocate the content list. */ win_info->generic.content = tui_alloc_content (max_lines, SRC_WIN); for (i = 0; i < max_lines; i++) win_info->generic.content[i]->which_element.source.line - = src_line_buf + (line_width * i); + = (char *) xmalloc (line_width); } return TUI_SUCCESS; diff --git a/gdb/utils.c b/gdb/utils.c index 4bb2f34..3a6f796 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -1444,9 +1444,9 @@ emit_style_escape (const ui_file_style &style) wrap_buffer.append (style.to_ansi ()); } -/* Return true if ANSI escapes can be used on STREAM. */ +/* See utils.h. */ -static bool +bool can_emit_style_escape (struct ui_file *stream) { if (stream != gdb_stdout diff --git a/gdb/utils.h b/gdb/utils.h index 1f09ec2..16ee9fb 100644 --- a/gdb/utils.h +++ b/gdb/utils.h @@ -443,6 +443,10 @@ extern void fputs_styled (const char *linebuffer, extern void reset_terminal_style (struct ui_file *stream); +/* Return true if ANSI escapes can be used on STREAM. */ + +extern bool can_emit_style_escape (struct ui_file *stream); + /* Display the host ADDR on STREAM formatted as ``0x%x''. */ extern void gdb_print_host_address_1 (const void *addr, struct ui_file *stream); |