1 : #include <vector>
2 : #include <iostream>
3 : #include <cstdio>
4 : #include <string>
5 :
6 : using namespace std;
7 :
8 :
9 : struct Decoder
10 : {
11 : enum { stTop, stEscape, stCSI } state;
12 : string line;
13 : bool inHeader;
14 : int level;
15 : vector<int> args;
16 : bool newNumber;
17 : int priority;
18 : bool ignoreLF;
19 : int lineNo, charNo;
20 :
21 : Decoder()
22 2 : {
23 1 : state = stTop;
24 1 : line = "";
25 1 : inHeader = false;
26 1 : level = 0;
27 1 : priority = 1;
28 1 : ignoreLF = false;
29 1 : lineNo = 1;
30 1 : charNo = 0;
31 1 : }
32 2 :
33 0 : void pushChar(char c);
34 :
35 : void finishLine();
36 : };
37 :
38 :
39 : void Decoder::pushChar(char c)
40 2167 : {
41 2167 : if (c == '\n') {
42 20 : lineNo++;
43 20 : charNo = 0;
44 2147 : } else charNo++;
45 :
46 2167 : switch (state) {
47 :
48 : case stTop:
49 2125 : if (c == '\e') {
50 16 : state = stEscape;
51 2109 : } else if (c == '\n' && !ignoreLF) {
52 20 : finishLine();
53 2089 : } else line += c;
54 2089 : break;
55 :
56 : case stEscape:
57 16 : if (c == '[') {
58 16 : state = stCSI;
59 16 : args.clear();
60 16 : newNumber = true;
61 : } else
62 0 : state = stTop; /* !!! wrong */
63 0 : break;
64 :
65 : case stCSI:
66 26 : if (c >= 0x40 && c != 0x7e) {
67 16 : state = stTop;
68 16 : switch (c) {
69 : case 'p':
70 6 : if (line.size()) finishLine();
71 6 : level++;
72 6 : inHeader = true;
73 6 : cout << "<nest>" << endl;
74 6 : priority = args.size() >= 1 ? args[0] : 1;
75 6 : break;
76 : case 'q':
77 6 : if (line.size()) finishLine();
78 6 : if (level > 0) {
79 6 : level--;
80 6 : cout << "</nest>" << endl;
81 : } else
82 0 : cerr << "not enough nesting levels at line "
83 : << lineNo << ", character " << charNo << endl;
84 0 : break;
85 : case 's':
86 4 : if (line.size()) finishLine();
87 4 : priority = args.size() >= 1 ? args[0] : 1;
88 4 : break;
89 : case 'a':
90 0 : ignoreLF = true;
91 0 : break;
92 : case 'b':
93 0 : ignoreLF = false;
94 0 : break;
95 : }
96 10 : } else if (c >= '0' && c <= '9') {
97 10 : int n = 0;
98 10 : if (!newNumber) {
99 0 : n = args.back() * 10;
100 0 : args.pop_back();
101 : }
102 10 : n += c - '0';
103 10 : args.push_back(n);
104 : }
105 2167 : break;
106 :
107 : }
108 : }
109 :
110 :
111 : void Decoder::finishLine()
112 20 : {
113 20 : string storeDir = "/nix/store/";
114 20 : int sz = storeDir.size();
115 20 : string tag = inHeader ? "head" : "line";
116 20 : cout << "<" << tag;
117 20 : if (priority != 1) cout << " priority='" << priority << "'";
118 20 : cout << ">";
119 :
120 1932 : for (unsigned int i = 0; i < line.size(); i++) {
121 :
122 1912 : if (line[i] == '<') cout << "<";
123 1912 : else if (line[i] == '&') cout << "&";
124 1912 : else if (line[i] < 32 && line[i] != 9) cout << "�";
125 1912 : else if (i + sz + 33 < line.size() &&
126 : string(line, i, sz) == storeDir &&
127 : line[i + sz + 32] == '-')
128 : {
129 3 : int j = i + sz + 32;
130 : /* skip name */
131 30 : while (!strchr("/\n\r\t ()[]:;?<>", line[j])) j++;
132 3 : int k = j;
133 27 : while (!strchr("\n\r\t ()[]:;?<>", line[k])) k++;
134 : // !!! escaping
135 3 : cout << "<storeref>"
136 : << "<storedir>"
137 : << string(line, i, sz)
138 : << "</storedir>"
139 : << "<hash>"
140 : << string(line, i + sz, 32)
141 : << "</hash>"
142 : << "<name>"
143 : << string(line, i + sz + 32, j - (i + sz + 32))
144 : << "</name>"
145 : << "<path>"
146 : << string(line, j, k - j)
147 : << "</path>"
148 : << "</storeref>";
149 3 : i = k - 1;
150 1909 : } else cout << line[i];
151 : }
152 :
153 20 : cout << "</" << tag << ">" << endl;
154 20 : line = "";
155 20 : inHeader = false;
156 20 : priority = 1;
157 : }
158 :
159 :
160 : int main(int argc, char * * argv)
161 1 : {
162 3 : Decoder dec;
163 1 : int c;
164 :
165 1 : cout << "<logfile>" << endl;
166 :
167 2168 : while ((c = getchar()) != EOF) {
168 2167 : dec.pushChar(c);
169 : }
170 :
171 1 : cout << "</logfile>" << endl;
172 1 : }
|