]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/source-cache.c
Rename common to gdbsupport
[thirdparty/binutils-gdb.git] / gdb / source-cache.c
CommitLineData
62f29fda 1/* Cache of styled source file text
42a4f53d 2 Copyright (C) 2018-2019 Free Software Foundation, Inc.
62f29fda
TT
3
4 This file is part of GDB.
5
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.
10
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.
15
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/>. */
18
19#include "defs.h"
20#include "source-cache.h"
268a13a5 21#include "gdbsupport/scoped_fd.h"
62f29fda
TT
22#include "source.h"
23#include "cli/cli-style.h"
24
25#ifdef HAVE_SOURCE_HIGHLIGHT
3a350822
EZ
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. */
30#undef open
31#undef close
62f29fda
TT
32#include <fstream>
33#include <sstream>
34#include <srchilite/sourcehighlight.h>
35#include <srchilite/langmap.h>
36#endif
37
38/* The number of source files we'll cache. */
39
40#define MAX_ENTRIES 5
41
42/* See source-cache.h. */
43
44source_cache g_source_cache;
45
46/* See source-cache.h. */
47
48bool
49source_cache::get_plain_source_lines (struct symtab *s, int first_line,
50 int last_line, std::string *lines)
51{
00df30ae 52 scoped_fd desc (open_source_file_with_line_charpos (s));
62f29fda
TT
53 if (desc.get () < 0)
54 return false;
55
62f29fda
TT
56 if (first_line < 1 || first_line > s->nlines || last_line < 1)
57 return false;
58
59 if (lseek (desc.get (), s->line_charpos[first_line - 1], SEEK_SET) < 0)
60 perror_with_name (symtab_to_filename_for_display (s));
61
62 int last_charpos;
63 if (last_line >= s->nlines)
64 {
65 struct stat st;
66
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;
71 }
72 else
73 last_charpos = s->line_charpos[last_line];
74
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));
78
79 return true;
80}
81
82/* See source-cache.h. */
83
3b336828 84std::string
62f29fda 85source_cache::extract_lines (const struct source_text &text, int first_line,
3b336828 86 int last_line)
62f29fda
TT
87{
88 int lineno = 1;
89 std::string::size_type pos = 0;
90 std::string::size_type first_pos = std::string::npos;
91
92 while (pos != std::string::npos && lineno <= last_line)
93 {
94 std::string::size_type new_pos = text.contents.find ('\n', pos);
95
96 if (lineno == first_line)
97 first_pos = pos;
98
99 pos = new_pos;
100 if (lineno == last_line || pos == std::string::npos)
101 {
3b336828
TT
102 if (first_pos == std::string::npos)
103 return {};
62f29fda
TT
104 if (pos == std::string::npos)
105 pos = text.contents.size ();
3b336828 106 return text.contents.substr (first_pos, pos - first_pos);
62f29fda
TT
107 }
108 ++lineno;
109 ++pos;
110 }
111
3b336828 112 return {};
62f29fda
TT
113}
114
64c45143
TT
115#ifdef HAVE_SOURCE_HIGHLIGHT
116
62f29fda
TT
117/* Return the Source Highlight language name, given a gdb language
118 LANG. Returns NULL if the language is not known. */
119
120static const char *
121get_language_name (enum language lang)
122{
123 switch (lang)
124 {
125 case language_c:
126 case language_objc:
127 return "c.lang";
128
129 case language_cplus:
130 return "cpp.lang";
131
132 case language_d:
133 return "d.lang";
134
135 case language_go:
136 return "go.lang";
137
138 case language_fortran:
139 return "fortran.lang";
140
141 case language_m2:
142 /* Not handled by Source Highlight. */
143 break;
144
145 case language_asm:
146 return "asm.lang";
147
148 case language_pascal:
149 return "pascal.lang";
150
151 case language_opencl:
152 /* Not handled by Source Highlight. */
153 break;
154
155 case language_rust:
156 /* Not handled by Source Highlight. */
157 break;
158
159 case language_ada:
160 return "ada.lang";
161
162 default:
163 break;
164 }
165
166 return nullptr;
167}
168
64c45143
TT
169#endif /* HAVE_SOURCE_HIGHLIGHT */
170
62f29fda
TT
171/* See source-cache.h. */
172
173bool
174source_cache::get_source_lines (struct symtab *s, int first_line,
175 int last_line, std::string *lines)
176{
177 if (first_line < 1 || last_line < 1 || first_line > last_line)
178 return false;
179
180#ifdef HAVE_SOURCE_HIGHLIGHT
8a522c6c 181 if (source_styling && gdb_stdout->can_emit_style_escape ())
62f29fda
TT
182 {
183 const char *fullname = symtab_to_fullname (s);
184
185 for (const auto &item : m_source_map)
186 {
187 if (item.fullname == fullname)
3b336828
TT
188 {
189 *lines = extract_lines (item, first_line, last_line);
190 return true;
191 }
62f29fda
TT
192 }
193
194 const char *lang_name = get_language_name (SYMTAB_LANGUAGE (s));
195 if (lang_name != nullptr)
196 {
197 std::ifstream input (fullname);
198 if (input.is_open ())
199 {
dcf37923
TT
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
204 source-cache.h. */
205 static srchilite::SourceHighlight *highlighter;
206
ab42892f
EZ
207 if (s->line_charpos == 0)
208 {
00df30ae 209 scoped_fd desc (open_source_file_with_line_charpos (s));
ab42892f
EZ
210 if (desc.get () < 0)
211 return false;
068ef30e
SM
212
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
216 use-after-free. */
217 fullname = symtab_to_fullname (s);
ab42892f 218 }
dcf37923
TT
219
220 if (highlighter == nullptr)
221 {
222 highlighter = new srchilite::SourceHighlight ("esc.outlang");
223 highlighter->setStyleFile ("esc.style");
224 }
62f29fda
TT
225
226 std::ostringstream output;
dcf37923 227 highlighter->highlight (input, output, lang_name, fullname);
62f29fda
TT
228
229 source_text result = { fullname, output.str () };
230 m_source_map.push_back (std::move (result));
231
232 if (m_source_map.size () > MAX_ENTRIES)
233 m_source_map.erase (m_source_map.begin ());
234
3b336828
TT
235 *lines = extract_lines (m_source_map.back (), first_line,
236 last_line);
237 return true;
62f29fda
TT
238 }
239 }
240 }
241#endif /* HAVE_SOURCE_HIGHLIGHT */
242
243 return get_plain_source_lines (s, first_line, last_line, lines);
244}