From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 34933 invoked by alias); 16 Nov 2019 00:58:13 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 34920 invoked by uid 89); 16 Nov 2019 00:58:13 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-14.3 required=5.0 tests=AWL,BAYES_00,FREEMAIL_FROM,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_ASCII_DIVIDERS,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.1 spammy=HX-Received:382 X-HELO: mail-vs1-f48.google.com Received: from mail-vs1-f48.google.com (HELO mail-vs1-f48.google.com) (209.85.217.48) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 16 Nov 2019 00:58:06 +0000 Received: by mail-vs1-f48.google.com with SMTP id q21so7570760vsg.3 for ; Fri, 15 Nov 2019 16:58:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=64WdT/fnGJrrWDZc8h/VHDSe+OTChu3aisL9GQItaR8=; b=LaDwk6+fIVg0RGu31oIEFb/8hFvA82ziORt7UGawGmbnwkUeYVnrt0VLVfJy76ErkH Qnaz9gU1NFupJyty1VrmxKgKACoXKNss+jZh7ycNvO6FtNBsu3u/JWM/d1P+HcBYXq9F mF3hAi5aLk271jrWv4bTt/1DwgRzuyO6IDKar1Y0LvVaE0N36Ygb0c56w94AxOczCnfe LqZQCDw9gYonh62RZGmqggQyhxBWYl+GDn8mNF41ePc8JEoyK30UHCmqSPZ3hVbMARSd 7F+Y4IQcp1mdGjDw30kl6x1IHUd2V7PDZeYKwyCNb8qWa3NbI/zk27hlI11DUjlZMilu KHfQ== MIME-Version: 1.0 References: <20181128001435.12703-1-tom@tromey.com> <20181128001435.12703-16-tom@tromey.com> In-Reply-To: <20181128001435.12703-16-tom@tromey.com> From: Andrew Pinski Date: Sat, 16 Nov 2019 00:58:00 -0000 Message-ID: Subject: Re: [PATCH 15/16] Highlight source code using GNU Source Highlight To: Tom Tromey Cc: GDB Patches Content-Type: text/plain; charset="UTF-8" X-IsSubscribed: yes X-SW-Source: 2019-11/txt/msg00494.txt.bz2 On Tue, Nov 27, 2018 at 4:16 PM Tom Tromey wrote: > > This changes gdb to highlight source using GNU Source Highlight, if it > is available. > > This affects the output of the "list" command and also the TUI source > window. > > No new test because I didn't see a way to make it work when Source > Highlight is not found. I know this patch has been in for almost a year now. But I have a question, is there a way to build GNU Source Highlight as a static library and have it built at the top level? Like what is done for GMP/MPFR for GCC? It would reduce how I built a gdb that is for a non-native target. If it cannot be compiled at a top-level, does it support as a static library? I have not looked fully though. The reason is I want to support one gdb that can be run on multiple (some older) distros. Thanks, Andrew Pinski > > gdb/ChangeLog > 2018-11-27 Tom Tromey > > * 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. > --- > gdb/ChangeLog | 29 ++++ > gdb/Makefile.in | 12 +- > gdb/cli/cli-style.c | 9 +- > gdb/config.in | 3 + > gdb/configure | 30 ++++ > gdb/configure.ac | 23 +++ > gdb/source-cache.c | 209 +++++++++++++++++++++++++++ > gdb/source-cache.h | 79 +++++++++++ > gdb/source.c | 38 ++--- > gdb/tui/tui-data.c | 5 +- > gdb/tui/tui-io.c | 11 +- > gdb/tui/tui-io.h | 4 +- > gdb/tui/tui-source.c | 302 +++++++++++++++++++--------------------- > gdb/tui/tui-winsource.c | 17 +-- > gdb/utils.c | 4 +- > gdb/utils.h | 4 + > 16 files changed, 576 insertions(+), 203 deletions(-) > create mode 100644 gdb/source-cache.c > create mode 100644 gdb/source-cache.h > > diff --git a/gdb/Makefile.in b/gdb/Makefile.in > index 54baf96ea3..50d429d792 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) > @@ -565,7 +569,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) > > @@ -591,7 +596,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 \ > @@ -1376,6 +1383,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 74e3958eb8..16415e0f88 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. */ > > @@ -216,6 +217,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 760db6b320..ea907d2b56 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 header file. */ > #undef HAVE_STDINT_H > > diff --git a/gdb/configure b/gdb/configure > index 44df6ebcfb..811664ed40 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 56cd0927bb..7d2d39b710 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 0000000000..56851806e4 > --- /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 . */ > + > +#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 > +#include > +#include > +#include > +#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 0000000000..2236d38846 > --- /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 . */ > + > +#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 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 7552496f78..aa7eb8a6d4 100644 > --- a/gdb/source.c > +++ b/gdb/source.c > @@ -45,6 +45,7 @@ > #include "common/scoped_fd.h" > #include > #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 4391f0d100..2b95f197fd 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 b1099246dd..0c7b88f1c7 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 11752d0845..95887639ec 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 3c4f06b01a..260b274297 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 0bf74383b1..00b4b9e4fa 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 85b0fb14e3..00f524c52e 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 1f09ec2d47..16ee9fbd33 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); > > -- > 2.17.2 >