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