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 "gdbsupport/scoped_fd.h"
23 #include "cli/cli-style.h"
25 #include "gdbsupport/selftest.h"
27 #ifdef HAVE_SOURCE_HIGHLIGHT
28 /* If Gnulib redirects 'open' and 'close' to its replacements
29 'rpl_open' and 'rpl_close' via cpp macros, including <fstream>
30 below with those macros in effect will cause unresolved externals
31 when GDB is linked. Happens, e.g., in the MinGW build. */
35 #include <srchilite/sourcehighlight.h>
36 #include <srchilite/langmap.h>
39 /* The number of source files we'll cache. */
43 /* See source-cache.h. */
45 source_cache g_source_cache
;
47 /* See source-cache.h. */
50 source_cache::get_plain_source_lines (struct symtab
*s
, std::string
*lines
)
52 scoped_fd
desc (open_source_file_with_line_charpos (s
));
58 if (fstat (desc
.get (), &st
) < 0)
59 perror_with_name (symtab_to_filename_for_display (s
));
61 /* We could cache this in line_charpos... */
62 lines
->resize (st
.st_size
);
63 if (myread (desc
.get (), &(*lines
)[0], lines
->size ()) < 0)
64 perror_with_name (symtab_to_filename_for_display (s
));
69 /* A helper function for get_plain_source_lines that extracts the
70 desired source lines from TEXT, putting them into LINES_OUT. The
71 arguments are as for get_source_lines. The return value is the
74 extract_lines (const std::string
&text
, int first_line
, int last_line
)
77 std::string::size_type pos
= 0;
78 std::string::size_type first_pos
= std::string::npos
;
80 while (pos
!= std::string::npos
&& lineno
<= last_line
)
82 std::string::size_type new_pos
= text
.find ('\n', pos
);
84 if (lineno
== first_line
)
88 if (lineno
== last_line
|| pos
== std::string::npos
)
90 if (first_pos
== std::string::npos
)
92 if (pos
== std::string::npos
)
96 return text
.substr (first_pos
, pos
- first_pos
);
105 #ifdef HAVE_SOURCE_HIGHLIGHT
107 /* Return the Source Highlight language name, given a gdb language
108 LANG. Returns NULL if the language is not known. */
111 get_language_name (enum language lang
)
128 case language_fortran
:
129 return "fortran.lang";
132 /* Not handled by Source Highlight. */
138 case language_pascal
:
139 return "pascal.lang";
141 case language_opencl
:
142 /* Not handled by Source Highlight. */
146 /* Not handled by Source Highlight. */
159 #endif /* HAVE_SOURCE_HIGHLIGHT */
161 /* See source-cache.h. */
164 source_cache::get_source_lines (struct symtab
*s
, int first_line
,
165 int last_line
, std::string
*lines
)
167 if (first_line
< 1 || last_line
< 1 || first_line
> last_line
)
170 std::string fullname
= symtab_to_fullname (s
);
172 for (const auto &item
: m_source_map
)
174 if (item
.fullname
== fullname
)
176 *lines
= extract_lines (item
.contents
, first_line
, last_line
);
181 std::string contents
;
182 if (!get_plain_source_lines (s
, &contents
))
185 #ifdef HAVE_SOURCE_HIGHLIGHT
186 if (source_styling
&& gdb_stdout
->can_emit_style_escape ())
188 const char *lang_name
= get_language_name (SYMTAB_LANGUAGE (s
));
189 if (lang_name
!= nullptr)
191 /* The global source highlight object, or null if one was
192 never constructed. This is stored here rather than in
193 the class so that we don't need to include anything or do
194 conditional compilation in source-cache.h. */
195 static srchilite::SourceHighlight
*highlighter
;
197 if (highlighter
== nullptr)
199 highlighter
= new srchilite::SourceHighlight ("esc.outlang");
200 highlighter
->setStyleFile ("esc.style");
203 std::istringstream
input (contents
);
204 std::ostringstream output
;
205 highlighter
->highlight (input
, output
, lang_name
, fullname
);
207 contents
= output
.str ();
210 #endif /* HAVE_SOURCE_HIGHLIGHT */
212 source_text result
= { std::move (fullname
), std::move (contents
) };
213 m_source_map
.push_back (std::move (result
));
215 if (m_source_map
.size () > MAX_ENTRIES
)
216 m_source_map
.erase (m_source_map
.begin ());
218 *lines
= extract_lines (m_source_map
.back ().contents
,
219 first_line
, last_line
);
226 static void extract_lines_test ()
228 std::string input_text
= "abc\ndef\nghi\njkl\n";
230 SELF_CHECK (extract_lines (input_text
, 1, 1) == "abc\n");
231 SELF_CHECK (extract_lines (input_text
, 2, 1) == "");
232 SELF_CHECK (extract_lines (input_text
, 1, 2) == "abc\ndef\n");
233 SELF_CHECK (extract_lines ("abc", 1, 1) == "abc");
239 _initialize_source_cache ()
242 selftests::register_test ("source-cache", selftests::extract_lines_test
);