1 /* Cache of styled source file text
2 Copyright (C) 2018-2019 Free Software Foundation, Inc.
4 This file is part of GDB.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include "source-cache.h"
21 #include "common/scoped_fd.h"
23 #include "cli/cli-style.h"
25 #ifdef HAVE_SOURCE_HIGHLIGHT
26 /* If Gnulib redirects 'open' and 'close' to its replacements
27 'rpl_open' and 'rpl_close' via cpp macros, including <fstream>
28 below with those macros in effect will cause unresolved externals
29 when GDB is linked. Happens, e.g., in the MinGW build. */
34 #include <srchilite/sourcehighlight.h>
35 #include <srchilite/langmap.h>
38 /* The number of source files we'll cache. */
42 /* See source-cache.h. */
44 source_cache g_source_cache;
46 /* See source-cache.h. */
49 source_cache::get_plain_source_lines (struct symtab *s, int first_line,
50 int last_line, std::string *lines)
52 scoped_fd desc (open_source_file_with_line_charpos (s));
56 if (first_line < 1 || first_line > s->nlines || last_line < 1)
59 if (lseek (desc.get (), s->line_charpos[first_line - 1], SEEK_SET) < 0)
60 perror_with_name (symtab_to_filename_for_display (s));
63 if (last_line >= s->nlines)
67 if (fstat (desc.get (), &st) < 0)
68 perror_with_name (symtab_to_filename_for_display (s));
69 /* We could cache this in line_charpos... */
70 last_charpos = st.st_size;
73 last_charpos = s->line_charpos[last_line];
75 lines->resize (last_charpos - s->line_charpos[first_line - 1]);
76 if (myread (desc.get (), &(*lines)[0], lines->size ()) < 0)
77 perror_with_name (symtab_to_filename_for_display (s));
82 /* See source-cache.h. */
85 source_cache::extract_lines (const struct source_text &text, int first_line,
89 std::string::size_type pos = 0;
90 std::string::size_type first_pos = std::string::npos;
92 while (pos != std::string::npos && lineno <= last_line)
94 std::string::size_type new_pos = text.contents.find ('\n', pos);
96 if (lineno == first_line)
100 if (lineno == last_line || pos == std::string::npos)
102 if (first_pos == std::string::npos)
104 if (pos == std::string::npos)
105 pos = text.contents.size ();
106 return text.contents.substr (first_pos, pos - first_pos);
115 #ifdef HAVE_SOURCE_HIGHLIGHT
117 /* Return the Source Highlight language name, given a gdb language
118 LANG. Returns NULL if the language is not known. */
121 get_language_name (enum language lang)
138 case language_fortran:
139 return "fortran.lang";
142 /* Not handled by Source Highlight. */
148 case language_pascal:
149 return "pascal.lang";
151 case language_opencl:
152 /* Not handled by Source Highlight. */
156 /* Not handled by Source Highlight. */
169 #endif /* HAVE_SOURCE_HIGHLIGHT */
171 /* See source-cache.h. */
174 source_cache::get_source_lines (struct symtab *s, int first_line,
175 int last_line, std::string *lines)
177 if (first_line < 1 || last_line < 1 || first_line > last_line)
180 #ifdef HAVE_SOURCE_HIGHLIGHT
181 if (source_styling && gdb_stdout->can_emit_style_escape ())
183 const char *fullname = symtab_to_fullname (s);
185 for (const auto &item : m_source_map)
187 if (item.fullname == fullname)
189 *lines = extract_lines (item, first_line, last_line);
194 const char *lang_name = get_language_name (SYMTAB_LANGUAGE (s));
195 if (lang_name != nullptr)
197 std::ifstream input (fullname);
198 if (input.is_open ())
200 /* The global source highlight object, or null if one
201 was never constructed. This is stored here rather
202 than in the class so that we don't need to include
203 anything or do conditional compilation in
205 static srchilite::SourceHighlight *highlighter;
207 if (s->line_charpos == 0)
209 scoped_fd desc (open_source_file_with_line_charpos (s));
213 /* FULLNAME points to a value owned by the symtab
214 (symtab::fullname). Calling open_source_file reallocates
215 that value, so we must refresh FULLNAME to avoid a
217 fullname = symtab_to_fullname (s);
220 if (highlighter == nullptr)
222 highlighter = new srchilite::SourceHighlight ("esc.outlang");
223 highlighter->setStyleFile ("esc.style");
226 std::ostringstream output;
227 highlighter->highlight (input, output, lang_name, fullname);
229 source_text result = { fullname, output.str () };
230 m_source_map.push_back (std::move (result));
232 if (m_source_map.size () > MAX_ENTRIES)
233 m_source_map.erase (m_source_map.begin ());
235 *lines = extract_lines (m_source_map.back (), first_line,
241 #endif /* HAVE_SOURCE_HIGHLIGHT */
243 return get_plain_source_lines (s, first_line, last_line, lines);