aboutsummaryrefslogtreecommitdiff
path: root/gdb/source-cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/source-cache.c')
-rw-r--r--gdb/source-cache.c209
1 files changed, 209 insertions, 0 deletions
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);
+}