1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <soulng/lexer/XmlParsingLog.hpp>
  7 #include <soulng/util/Unicode.hpp>
  8 #include <algorithm>
  9 #include <sstream>
 10 #include <cctype>
 11 
 12 namespace soulng { namespace lexer {
 13 
 14 using namespace soulng::unicode;
 15 
 16 std::u32string XmlHexEscape(char32_t c)
 17 {
 18     std::stringstream s;
 19     s << "&#x" << std::hex << (unsigned int)c << ";";
 20     return ToUtf32(s.str());
 21 }
 22 
 23 std::u32string XmlCharStr(char32_t c)
 24 {
 25     switch (c)
 26     {
 27         case '&': return U"&amp;";
 28         case '<': return U"&lt;";
 29         case '>': return U"&gt;";
 30         case '\a': return U"\\a";
 31         case '\b': return U"\\b";
 32         case '\f': return U"\\f";
 33         case '\n': return U"\\n";
 34         case '\r': return U"\\r";
 35         case '\t': return U"\\t";
 36         case '\v': return U"\\v";
 37         default:
 38         {
 39             if (((int)c >= 32 && (int)c <= 126))
 40             {
 41                 return std::u32string(1c);
 42             }
 43             else
 44             {
 45                 return XmlHexEscape(c);
 46             }
 47         }
 48     }
 49     return std::u32string();
 50 }
 51 
 52 std::u32string XmlEscape(const std::u32string& s)
 53 {
 54     std::u32string result;
 55     result.reserve(2 * s.length());
 56     std::u32string::const_iterator e = s.end();
 57     for (std::u32string::const_iterator i = s.begin(); i != e; ++i)
 58     {
 59         result.append(XmlCharStr(*i));
 60     }
 61     return result;
 62 }
 63 
 64 XmlParsingLog::XmlParsingLog(std::ostream& stream_) : ParsingLog()formatter(stream_)
 65 {
 66     formatter.SetIndentSize(1);
 67 }
 68 
 69 XmlParsingLog::XmlParsingLog(std::ostream& stream_int maxLineLength_) : ParsingLog(maxLineLength_)formatter(stream_)
 70 {
 71     formatter.SetIndentSize(1);
 72 }
 73 
 74 void XmlParsingLog::IncIndent()
 75 {
 76     formatter.IncIndent();
 77 }
 78 
 79 void XmlParsingLog::DecIndent()
 80 {
 81     formatter.DecIndent();
 82 }
 83 
 84 void XmlParsingLog::WriteBeginRule(const std::u32string& ruleName)
 85 {
 86     Write(U"<" + ruleName + U">");
 87 }
 88 
 89 void XmlParsingLog::WriteEndRule(const std::u32string& ruleName)
 90 {
 91     Write(U"</" + ruleName + U">");
 92 }
 93 
 94 void XmlParsingLog::WriteTry(const std::u32string& s)
 95 {
 96     WriteElement(U"try"s);
 97 }
 98 
 99 void XmlParsingLog::WriteSuccess(const std::u32string& match)
100 {
101     WriteElement(U"success"match);
102 }
103 
104 void XmlParsingLog::WriteFail()
105 {
106     Write(U"<fail/>");
107 }
108 
109 void XmlParsingLog::WriteElement(const std::u32string& elementNameconst std::u32string& elementContent)
110 {
111     std::u32string converted = XmlEscape(elementContent);
112     int convertedLength = static_cast<int>(converted.length());
113     int lineLength = 2 * static_cast<int>(elementName.length()) + 5 + convertedLength;
114     std::u32string s = converted;
115     if (lineLength > MaxLineLength())
116     {
117         lineLength += 3;
118         s = converted.substr(0std::max(0convertedLength - (lineLength - MaxLineLength()))) + U"...";
119     }
120     Write(U"<" + elementName + U">" + s + U"</" + elementName + U">");
121 }
122 
123 void XmlParsingLog::Write(const std::u32string& s)
124 {
125     formatter.WriteLine(ToUtf8(s));
126 }
127 
128 } } // namespace soulng::lexer