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"
26 #ifdef HAVE_SOURCE_HIGHLIGHT
27 /* If Gnulib redirects 'open' and 'close' to its replacements
28 'rpl_open' and 'rpl_close' via cpp macros, including <fstream>
29 below with those macros in effect will cause unresolved externals
30 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
, int first_line
,
51 int last_line
, std::string
*lines
)
53 scoped_fd
desc (open_source_file_with_line_charpos (s
));
57 if (first_line
< 1 || first_line
> s
->nlines
|| last_line
< 1)
60 if (lseek (desc
.get (), s
->line_charpos
[first_line
- 1], SEEK_SET
) < 0)
61 perror_with_name (symtab_to_filename_for_display (s
));
64 if (last_line
>= s
->nlines
)
68 if (fstat (desc
.get (), &st
) < 0)
69 perror_with_name (symtab_to_filename_for_display (s
));
70 /* We could cache this in line_charpos... */
71 last_charpos
= st
.st_size
;
74 last_charpos
= s
->line_charpos
[last_line
];
76 lines
->resize (last_charpos
- s
->line_charpos
[first_line
- 1]);
77 if (myread (desc
.get (), &(*lines
)[0], lines
->size ()) < 0)
78 perror_with_name (symtab_to_filename_for_display (s
));
83 /* See source-cache.h. */
86 source_cache::extract_lines (const struct source_text
&text
, int first_line
,
90 std::string::size_type pos
= 0;
91 std::string::size_type first_pos
= std::string::npos
;
93 while (pos
!= std::string::npos
&& lineno
<= last_line
)
95 std::string::size_type new_pos
= text
.contents
.find ('\n', pos
);
97 if (lineno
== first_line
)
101 if (lineno
== last_line
|| pos
== std::string::npos
)
103 if (first_pos
== std::string::npos
)
105 if (pos
== std::string::npos
)
106 pos
= text
.contents
.size ();
107 return text
.contents
.substr (first_pos
, pos
- first_pos
);
116 #ifdef HAVE_SOURCE_HIGHLIGHT
118 /* Return the Source Highlight language name, given a gdb language
119 LANG. Returns NULL if the language is not known. */
122 get_language_name (enum language lang
)
139 case language_fortran
:
140 return "fortran.lang";
143 /* Not handled by Source Highlight. */
149 case language_pascal
:
150 return "pascal.lang";
152 case language_opencl
:
153 /* Not handled by Source Highlight. */
157 /* Not handled by Source Highlight. */
170 #endif /* HAVE_SOURCE_HIGHLIGHT */
172 /* See source-cache.h. */
175 source_cache::get_source_lines (struct symtab
*s
, int first_line
,
176 int last_line
, std::string
*lines
)
178 if (first_line
< 1 || last_line
< 1 || first_line
> last_line
)
181 #ifdef HAVE_SOURCE_HIGHLIGHT
182 if (source_styling
&& gdb_stdout
->can_emit_style_escape ())
184 const char *fullname
= symtab_to_fullname (s
);
186 for (const auto &item
: m_source_map
)
188 if (item
.fullname
== fullname
)
190 *lines
= extract_lines (item
, first_line
, last_line
);
195 const char *lang_name
= get_language_name (SYMTAB_LANGUAGE (s
));
196 if (lang_name
!= nullptr)
198 std::ifstream
input (fullname
);
199 if (input
.is_open ())
201 /* The global source highlight object, or null if one
202 was never constructed. This is stored here rather
203 than in the class so that we don't need to include
204 anything or do conditional compilation in
206 static srchilite::SourceHighlight
*highlighter
;
208 if (s
->line_charpos
== 0)
210 scoped_fd
desc (open_source_file_with_line_charpos (s
));
214 /* FULLNAME points to a value owned by the symtab
215 (symtab::fullname). Calling open_source_file reallocates
216 that value, so we must refresh FULLNAME to avoid a
218 fullname
= symtab_to_fullname (s
);
221 if (highlighter
== nullptr)
223 highlighter
= new srchilite::SourceHighlight ("esc.outlang");
224 highlighter
->setStyleFile ("esc.style");
227 std::ostringstream output
;
228 highlighter
->highlight (input
, output
, lang_name
, fullname
);
230 source_text result
= { fullname
, output
.str () };
231 m_source_map
.push_back (std::move (result
));
233 if (m_source_map
.size () > MAX_ENTRIES
)
234 m_source_map
.erase (m_source_map
.begin ());
236 *lines
= extract_lines (m_source_map
.back (), first_line
,
242 #endif /* HAVE_SOURCE_HIGHLIGHT */
244 return get_plain_source_lines (s
, first_line
, last_line
, lines
);