+#include <msp/strings/format.h>
+#include <msp/strings/regex.h>
+#include <msp/strings/utils.h>
+#include "sourcemap.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+namespace SL {
+
+SourceMap::SourceMap():
+ base_index(0)
+{ }
+
+void SourceMap::set_name(unsigned i, const std::string &n)
+{
+ if(source_names.empty())
+ base_index = i;
+ else if(i<base_index)
+ {
+ source_names.insert(source_names.begin(), base_index-i, string());
+ base_index = i;
+ }
+ i -= base_index;
+
+ if(source_names.size()<=i)
+ source_names.resize(i+1);
+ source_names[i] = n;
+}
+
+void SourceMap::merge_from(const SourceMap &other)
+{
+ if(other.base_index<base_index)
+ {
+ source_names.insert(source_names.begin(), base_index-other.base_index, string());
+ base_index = other.base_index;
+ }
+ if(get_count()<other.get_count())
+ source_names.resize(other.get_count()-base_index);
+
+ for(unsigned i=0; i<other.source_names.size(); ++i)
+ if(!other.source_names[i].empty())
+ source_names[i+other.base_index-base_index] = other.source_names[i];
+}
+
+string SourceMap::translate_errors(const string &errors) const
+{
+ static const Regex r_message("^(([0-9]+)\\(([0-9]+)\\) :|ERROR: ([0-9]+):([0-9]+):) (.*)$");
+ vector<string> lines = split(errors, '\n');
+ string translated;
+ for(vector<string>::const_iterator i=lines.begin(); i!=lines.end(); ++i)
+ {
+ RegMatch m = r_message.match(*i);
+ if(m)
+ {
+ unsigned index = 0;
+ unsigned line = 0;
+ if(m[2])
+ {
+ index = lexical_cast<unsigned>(m[2].str);
+ line = lexical_cast<unsigned>(m[3].str);
+ }
+ else if(m[4])
+ {
+ index = lexical_cast<unsigned>(m[4].str);
+ line = lexical_cast<unsigned>(m[5].str);
+ }
+ const char *src = "<unknown>";
+ if(index<source_names.size() && !source_names[index].empty())
+ src = source_names[index].c_str();
+ translated += format("%s:%d: %s", src, line, m[6].str);
+ }
+ else
+ translated += *i;
+ translated += '\n';
+ }
+
+ return translated;
+}
+
+} // namespace SL
+} // namespace GL
+} // namespace Msp