#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); }