diff options
Diffstat (limited to 'src/nix-log2xml/log2xml.cc')
-rw-r--r-- | src/nix-log2xml/log2xml.cc | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/src/nix-log2xml/log2xml.cc b/src/nix-log2xml/log2xml.cc new file mode 100644 index 000000000000..6645dc500fed --- /dev/null +++ b/src/nix-log2xml/log2xml.cc @@ -0,0 +1,200 @@ +#include <vector> +#include <iostream> +#include <cstdio> +#include <string> +#include <cstring> + +using namespace std; + + +struct Decoder +{ + enum { stTop, stEscape, stCSI } state; + string line; + bool inHeader; + int level; + vector<int> args; + bool newNumber; + int priority; + bool ignoreLF; + int lineNo, charNo; + bool warning; + bool error; + + Decoder() + { + state = stTop; + line = ""; + inHeader = false; + level = 0; + priority = 1; + ignoreLF = false; + lineNo = 1; + charNo = 0; + warning = false; + error = false; + } + + void pushChar(char c); + + void finishLine(); + + void decodeFile(istream & st); +}; + + +void Decoder::pushChar(char c) +{ + if (c == '\n') { + lineNo++; + charNo = 0; + } else charNo++; + + switch (state) { + + case stTop: + if (c == '\e') { + state = stEscape; + } else if (c == '\n' && !ignoreLF) { + finishLine(); + } else line += c; + break; + + case stEscape: + if (c == '[') { + state = stCSI; + args.clear(); + newNumber = true; + } else + state = stTop; /* !!! wrong */ + break; + + case stCSI: + if (c >= 0x40 && c != 0x7e) { + state = stTop; + switch (c) { + case 'p': + if (line.size()) finishLine(); + level++; + inHeader = true; + cout << "<nest>" << endl; + priority = args.size() >= 1 ? args[0] : 1; + break; + case 'q': + if (line.size()) finishLine(); + if (level > 0) { + level--; + cout << "</nest>" << endl; + } else + cerr << "not enough nesting levels at line " + << lineNo << ", character " << charNo << endl; + break; + case 's': + if (line.size()) finishLine(); + priority = args.size() >= 1 ? args[0] : 1; + break; + case 'a': + ignoreLF = true; + break; + case 'b': + ignoreLF = false; + break; + case 'e': + error = true; + break; + case 'w': + warning = true; + break; + } + } else if (c >= '0' && c <= '9') { + int n = 0; + if (!newNumber) { + n = args.back() * 10; + args.pop_back(); + } + n += c - '0'; + args.push_back(n); + } + break; + + } +} + + +void Decoder::finishLine() +{ + string storeDir = "/nix/store/"; + int sz = storeDir.size(); + string tag = inHeader ? "head" : "line"; + cout << "<" << tag; + if (priority != 1) cout << " priority='" << priority << "'"; + if (warning) cout << " warning='1'"; + if (error) cout << " error='1'"; + cout << ">"; + + for (unsigned int i = 0; i < line.size(); i++) { + + if (line[i] == '<') cout << "<"; + else if (line[i] == '&') cout << "&"; + else if (line[i] == '\r') ; /* ignore carriage return */ + else if (line[i] < 32 && line[i] != 9) cout << "�"; + else if (i + sz + 33 < line.size() && + string(line, i, sz) == storeDir && + line[i + sz + 32] == '-') + { + int j = i + sz + 32; + /* skip name */ + while (!strchr("/\n\r\t ()[]:;?<>", line[j])) j++; + int k = j; + while (!strchr("\n\r\t ()[]:;?<>", line[k])) k++; + // !!! escaping + cout << "<storeref>" + << "<storedir>" + << string(line, i, sz) + << "</storedir>" + << "<hash>" + << string(line, i + sz, 32) + << "</hash>" + << "<name>" + << string(line, i + sz + 32, j - (i + sz + 32)) + << "</name>" + << "<path>" + << string(line, j, k - j) + << "</path>" + << "</storeref>"; + i = k - 1; + } else cout << line[i]; + } + + cout << "</" << tag << ">" << endl; + line = ""; + inHeader = false; + priority = 1; + warning = false; + error = false; +} + + +void Decoder::decodeFile(istream & st) +{ + int c; + + cout << "<logfile>" << endl; + + while ((c = st.get()) != EOF) { + pushChar(c); + } + + if (line.size()) finishLine(); + + while (level--) cout << "</nest>" << endl; + + cout << "</logfile>" << endl; +} + + +int main(int argc, char * * argv) +{ + Decoder dec; + dec.decodeFile(cin); +} |