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 (s
));
56 if (s
->line_charpos
== 0)
57 find_source_lines (s
, desc
.get ());
59 if (first_line
< 1 || first_line
> s
->nlines
|| last_line
< 1)
62 if (lseek (desc
.get (), s
->line_charpos
[first_line
- 1], SEEK_SET
) < 0)
63 perror_with_name (symtab_to_filename_for_display (s
));
66 if (last_line
>= s
->nlines
)
70 if (fstat (desc
.get (), &st
) < 0)
71 perror_with_name (symtab_to_filename_for_display (s
));
72 /* We could cache this in line_charpos... */
73 last_charpos
= st
.st_size
;
76 last_charpos
= s
->line_charpos
[last_line
];
78 lines
->resize (last_charpos
- s
->line_charpos
[first_line
- 1]);
79 if (myread (desc
.get (), &(*lines
)[0], lines
->size ()) < 0)
80 perror_with_name (symtab_to_filename_for_display (s
));
85 /* See source-cache.h. */
88 source_cache::extract_lines (const struct source_text
&text
, int first_line
,
92 std::string::size_type pos
= 0;
93 std::string::size_type first_pos
= std::string::npos
;
95 while (pos
!= std::string::npos
&& lineno
<= last_line
)
97 std::string::size_type new_pos
= text
.contents
.find ('\n', pos
);
99 if (lineno
== first_line
)
103 if (lineno
== last_line
|| pos
== std::string::npos
)
105 if (first_pos
== std::string::npos
)
107 if (pos
== std::string::npos
)
108 pos
= text
.contents
.size ();
109 return text
.contents
.substr (first_pos
, pos
- first_pos
);
118 #ifdef HAVE_SOURCE_HIGHLIGHT
120 /* Return the Source Highlight language name, given a gdb language
121 LANG. Returns NULL if the language is not known. */
124 get_language_name (enum language lang
)
141 case language_fortran
:
142 return "fortran.lang";
145 /* Not handled by Source Highlight. */
151 case language_pascal
:
152 return "pascal.lang";
154 case language_opencl
:
155 /* Not handled by Source Highlight. */
159 /* Not handled by Source Highlight. */
172 #endif /* HAVE_SOURCE_HIGHLIGHT */
174 /* See source-cache.h. */
177 source_cache::get_source_lines (struct symtab
*s
, int first_line
,
178 int last_line
, std::string
*lines
)
180 if (first_line
< 1 || last_line
< 1 || first_line
> last_line
)
183 #ifdef HAVE_SOURCE_HIGHLIGHT
184 if (source_styling
&& can_emit_style_escape (gdb_stdout
))
186 const char *fullname
= symtab_to_fullname (s
);
188 for (const auto &item
: m_source_map
)
190 if (item
.fullname
== fullname
)
192 *lines
= extract_lines (item
, first_line
, last_line
);
197 const char *lang_name
= get_language_name (SYMTAB_LANGUAGE (s
));
198 if (lang_name
!= nullptr)
200 std::ifstream
input (fullname
);
201 if (input
.is_open ())
203 if (s
->line_charpos
== 0)
205 scoped_fd desc
= open_source_file (s
);
208 find_source_lines (s
, desc
.get ());
210 /* FULLNAME points to a value owned by the symtab
211 (symtab::fullname). Calling open_source_file reallocates
212 that value, so we must refresh FULLNAME to avoid a
214 fullname
= symtab_to_fullname (s
);
216 srchilite::SourceHighlight
highlighter ("esc.outlang");
217 highlighter
.setStyleFile("esc.style");
219 std::ostringstream output
;
220 highlighter
.highlight (input
, output
, lang_name
, fullname
);
222 source_text result
= { fullname
, output
.str () };
223 m_source_map
.push_back (std::move (result
));
225 if (m_source_map
.size () > MAX_ENTRIES
)
226 m_source_map
.erase (m_source_map
.begin ());
228 *lines
= extract_lines (m_source_map
.back (), first_line
,
234 #endif /* HAVE_SOURCE_HIGHLIGHT */
236 return get_plain_source_lines (s
, first_line
, last_line
, lines
);