+static bool
+extract_lines (const std::string &text, int first_line, int last_line,
+ std::string *lines_out)
+{
+ int lineno = 1;
+ std::string::size_type pos = 0;
+ std::string::size_type first_pos = std::string::npos;
+
+ while (pos != std::string::npos && lineno <= last_line)
+ {
+ std::string::size_type new_pos = text.find ('\n', pos);
+
+ if (lineno == first_line)
+ first_pos = pos;
+
+ pos = new_pos;
+ if (lineno == last_line || pos == std::string::npos)
+ {
+ /* A newline at the end does not start a new line. */
+ if (first_pos == std::string::npos
+ || first_pos == text.size ())
+ return false;
+ if (pos == std::string::npos)
+ pos = text.size ();
+ else
+ ++pos;
+ *lines_out = text.substr (first_pos, pos - first_pos);
+ return true;
+ }
+ ++lineno;
+ ++pos;
+ }
+
+ return false;
+}
+
+/* See source-cache.h. */
+
+bool
+source_cache::get_source_lines (struct symtab *s, int first_line,
+ int last_line, std::string *lines)
+{
+ if (first_line < 1 || last_line < 1 || first_line > last_line)
+ return false;
+
+ if (!ensure (s))
+ return false;
+
+ return extract_lines (m_source_map.back ().contents,
+ first_line, last_line, lines);
+}
+
+#if GDB_SELF_TEST
+namespace selftests
+{
+static void extract_lines_test ()
+{
+ std::string input_text = "abc\ndef\nghi\njkl\n";
+ std::string result;
+
+ SELF_CHECK (extract_lines (input_text, 1, 1, &result)
+ && result == "abc\n");
+ SELF_CHECK (!extract_lines (input_text, 2, 1, &result));
+ SELF_CHECK (extract_lines (input_text, 1, 2, &result)
+ && result == "abc\ndef\n");
+ SELF_CHECK (extract_lines ("abc", 1, 1, &result)
+ && result == "abc");
+}
+}
+#endif
+
+void
+_initialize_source_cache ()
+{
+#if GDB_SELF_TEST
+ selftests::register_test ("source-cache", selftests::extract_lines_test);
+#endif