Add --with-static-standard-libraries to the top level
[deliverable/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"
0d12e84c 24#include "symtab.h"
269249d9 25#include "gdbsupport/selftest.h"
cb44333d
TT
26#include "objfiles.h"
27#include "exec.h"
62f29fda
TT
28
29#ifdef HAVE_SOURCE_HIGHLIGHT
3a350822
EZ
30/* If Gnulib redirects 'open' and 'close' to its replacements
31 'rpl_open' and 'rpl_close' via cpp macros, including <fstream>
32 below with those macros in effect will cause unresolved externals
33 when GDB is linked. Happens, e.g., in the MinGW build. */
34#undef open
35#undef close
62f29fda
TT
36#include <sstream>
37#include <srchilite/sourcehighlight.h>
38#include <srchilite/langmap.h>
39#endif
40
41/* The number of source files we'll cache. */
42
43#define MAX_ENTRIES 5
44
45/* See source-cache.h. */
46
47source_cache g_source_cache;
48
49/* See source-cache.h. */
50
cb44333d
TT
51std::string
52source_cache::get_plain_source_lines (struct symtab *s,
53 const std::string &fullname)
62f29fda 54{
cb44333d 55 scoped_fd desc (open_source_file (s));
62f29fda 56 if (desc.get () < 0)
cb44333d 57 perror_with_name (symtab_to_filename_for_display (s));
62f29fda 58
872dceaa 59 struct stat st;
872dceaa 60 if (fstat (desc.get (), &st) < 0)
62f29fda
TT
61 perror_with_name (symtab_to_filename_for_display (s));
62
cb44333d
TT
63 std::string lines;
64 lines.resize (st.st_size);
65 if (myread (desc.get (), &lines[0], lines.size ()) < 0)
62f29fda
TT
66 perror_with_name (symtab_to_filename_for_display (s));
67
cb44333d
TT
68 time_t mtime = 0;
69 if (SYMTAB_OBJFILE (s) != NULL && SYMTAB_OBJFILE (s)->obfd != NULL)
70 mtime = SYMTAB_OBJFILE (s)->mtime;
71 else if (exec_bfd)
72 mtime = exec_bfd_mtime;
62f29fda 73
cb44333d
TT
74 if (mtime && mtime < st.st_mtime)
75 warning (_("Source file is more recent than executable."));
62f29fda 76
cb44333d
TT
77 std::vector<off_t> offsets;
78 offsets.push_back (0);
79 for (size_t offset = lines.find ('\n');
80 offset != std::string::npos;
81 offset = lines.find ('\n', offset))
62f29fda 82 {
cb44333d
TT
83 ++offset;
84 /* A newline at the end does not start a new line. It would
85 seem simpler to just strip the newline in this function, but
86 then "list" won't print the final newline. */
87 if (offset != lines.size ())
88 offsets.push_back (offset);
62f29fda
TT
89 }
90
cb44333d
TT
91 offsets.shrink_to_fit ();
92 m_offset_cache.emplace (fullname, std::move (offsets));
93
94 return lines;
62f29fda
TT
95}
96
64c45143
TT
97#ifdef HAVE_SOURCE_HIGHLIGHT
98
62f29fda
TT
99/* Return the Source Highlight language name, given a gdb language
100 LANG. Returns NULL if the language is not known. */
101
102static const char *
103get_language_name (enum language lang)
104{
105 switch (lang)
106 {
107 case language_c:
108 case language_objc:
109 return "c.lang";
110
111 case language_cplus:
112 return "cpp.lang";
113
114 case language_d:
115 return "d.lang";
116
117 case language_go:
118 return "go.lang";
119
120 case language_fortran:
121 return "fortran.lang";
122
123 case language_m2:
124 /* Not handled by Source Highlight. */
125 break;
126
127 case language_asm:
128 return "asm.lang";
129
130 case language_pascal:
131 return "pascal.lang";
132
133 case language_opencl:
134 /* Not handled by Source Highlight. */
135 break;
136
137 case language_rust:
138 /* Not handled by Source Highlight. */
139 break;
140
141 case language_ada:
142 return "ada.lang";
143
144 default:
145 break;
146 }
147
148 return nullptr;
149}
150
64c45143
TT
151#endif /* HAVE_SOURCE_HIGHLIGHT */
152
62f29fda
TT
153/* See source-cache.h. */
154
155bool
cb44333d 156source_cache::ensure (struct symtab *s)
62f29fda 157{
872dceaa 158 std::string fullname = symtab_to_fullname (s);
62f29fda 159
cb44333d
TT
160 size_t size = m_source_map.size ();
161 for (int i = 0; i < size; ++i)
872dceaa 162 {
cb44333d 163 if (m_source_map[i].fullname == fullname)
62f29fda 164 {
cb44333d
TT
165 /* This should always hold, because we create the file
166 offsets when reading the file, and never free them
167 without also clearing the contents cache. */
168 gdb_assert (m_offset_cache.find (fullname)
169 != m_offset_cache.end ());
170 /* Not strictly LRU, but at least ensure that the most
171 recently used entry is always the last candidate for
172 deletion. Note that this property is relied upon by at
173 least one caller. */
174 if (i != size - 1)
175 std::swap (m_source_map[i], m_source_map[size - 1]);
872dceaa 176 return true;
62f29fda 177 }
872dceaa 178 }
62f29fda 179
cb44333d 180 std::string contents = get_plain_source_lines (s, fullname);
872dceaa
TT
181
182#ifdef HAVE_SOURCE_HIGHLIGHT
183 if (source_styling && gdb_stdout->can_emit_style_escape ())
184 {
62f29fda
TT
185 const char *lang_name = get_language_name (SYMTAB_LANGUAGE (s));
186 if (lang_name != nullptr)
187 {
872dceaa
TT
188 /* The global source highlight object, or null if one was
189 never constructed. This is stored here rather than in
190 the class so that we don't need to include anything or do
191 conditional compilation in source-cache.h. */
192 static srchilite::SourceHighlight *highlighter;
193
194 if (highlighter == nullptr)
62f29fda 195 {
872dceaa
TT
196 highlighter = new srchilite::SourceHighlight ("esc.outlang");
197 highlighter->setStyleFile ("esc.style");
62f29fda 198 }
872dceaa
TT
199
200 std::istringstream input (contents);
201 std::ostringstream output;
202 highlighter->highlight (input, output, lang_name, fullname);
203
204 contents = output.str ();
62f29fda
TT
205 }
206 }
207#endif /* HAVE_SOURCE_HIGHLIGHT */
208
872dceaa
TT
209 source_text result = { std::move (fullname), std::move (contents) };
210 m_source_map.push_back (std::move (result));
211
212 if (m_source_map.size () > MAX_ENTRIES)
213 m_source_map.erase (m_source_map.begin ());
214
872dceaa 215 return true;
62f29fda 216}
269249d9 217
cb44333d
TT
218/* See source-cache.h. */
219
220bool
221source_cache::get_line_charpos (struct symtab *s,
222 const std::vector<off_t> **offsets)
223{
224 std::string fullname = symtab_to_fullname (s);
225
226 auto iter = m_offset_cache.find (fullname);
227 if (iter == m_offset_cache.end ())
228 {
229 ensure (s);
230 iter = m_offset_cache.find (fullname);
231 /* cache_source_text ensured this was entered. */
232 gdb_assert (iter != m_offset_cache.end ());
233 }
234
235 *offsets = &iter->second;
236 return true;
237}
238
239/* A helper function that extracts the desired source lines from TEXT,
240 putting them into LINES_OUT. The arguments are as for
241 get_source_lines. Returns true on success, false if the line
242 numbers are invalid. */
243
244static bool
245extract_lines (const std::string &text, int first_line, int last_line,
246 std::string *lines_out)
247{
248 int lineno = 1;
249 std::string::size_type pos = 0;
250 std::string::size_type first_pos = std::string::npos;
251
252 while (pos != std::string::npos && lineno <= last_line)
253 {
254 std::string::size_type new_pos = text.find ('\n', pos);
255
256 if (lineno == first_line)
257 first_pos = pos;
258
259 pos = new_pos;
260 if (lineno == last_line || pos == std::string::npos)
261 {
262 /* A newline at the end does not start a new line. */
263 if (first_pos == std::string::npos
264 || first_pos == text.size ())
265 return false;
266 if (pos == std::string::npos)
267 pos = text.size ();
268 else
269 ++pos;
270 *lines_out = text.substr (first_pos, pos - first_pos);
271 return true;
272 }
273 ++lineno;
274 ++pos;
275 }
276
277 return false;
278}
279
280/* See source-cache.h. */
281
282bool
283source_cache::get_source_lines (struct symtab *s, int first_line,
284 int last_line, std::string *lines)
285{
286 if (first_line < 1 || last_line < 1 || first_line > last_line)
287 return false;
288
289 if (!ensure (s))
290 return false;
291
292 return extract_lines (m_source_map.back ().contents,
293 first_line, last_line, lines);
294}
295
269249d9
TT
296#if GDB_SELF_TEST
297namespace selftests
298{
299static void extract_lines_test ()
300{
301 std::string input_text = "abc\ndef\nghi\njkl\n";
cb44333d
TT
302 std::string result;
303
304 SELF_CHECK (extract_lines (input_text, 1, 1, &result)
305 && result == "abc\n");
306 SELF_CHECK (!extract_lines (input_text, 2, 1, &result));
307 SELF_CHECK (extract_lines (input_text, 1, 2, &result)
308 && result == "abc\ndef\n");
309 SELF_CHECK (extract_lines ("abc", 1, 1, &result)
310 && result == "abc");
269249d9
TT
311}
312}
313#endif
314
315void
316_initialize_source_cache ()
317{
318#if GDB_SELF_TEST
319 selftests::register_test ("source-cache", selftests::extract_lines_test);
320#endif
321}
This page took 0.119538 seconds and 4 git commands to generate.