Werner's Miscellanea
Sign in or create your account | Project List | Help
Werner's Miscellanea Git Source Tree
Root/
Source at commit af27092667ad86f3ba299169dc41548717862d4c created 13 years 4 months ago. By Werner Almesberger, qpkg/gobble.c (gobble_buf): initialize pkg->conflicts and pkg->depends | |
---|---|
1 | #include <stdlib.h> |
2 | #include <stdio.h> |
3 | #include <string.h> |
4 | #include <ctype.h> |
5 | #include <fcntl.h> |
6 | #include <sys/stat.h> |
7 | #include <sys/mman.h> |
8 | |
9 | #include "util.h" |
10 | #include "id.h" |
11 | #include "qpkg.h" |
12 | #include "gobble.h" |
13 | |
14 | |
15 | #define CHARS_AFTER_ERROR 20 |
16 | |
17 | |
18 | #define EXPECT(s) \ |
19 | do { \ |
20 | if (end-buf < sizeof(s)-1) \ |
21 | FAIL; \ |
22 | if (memcmp(buf, s, sizeof(s)-1)) \ |
23 | FAIL; \ |
24 | buf += sizeof(s)-1; \ |
25 | } \ |
26 | while (0) |
27 | |
28 | |
29 | #define NEXT (buf == end ? '?' : *buf++) |
30 | |
31 | |
32 | #define WHITESPACE \ |
33 | do { \ |
34 | if (buf == end) \ |
35 | FAIL; \ |
36 | if (*buf == '\n') \ |
37 | break; \ |
38 | if (!isspace(*buf)) \ |
39 | break; \ |
40 | buf++; \ |
41 | } \ |
42 | while (0) |
43 | |
44 | |
45 | #define ISTERM(c) \ |
46 | ((c) == ' ' || (c) == '\t' || (c) == '\n' || \ |
47 | (c) == ',' || (c) == ')') |
48 | |
49 | |
50 | #define ID(tree) \ |
51 | ({ \ |
52 | const char *start; \ |
53 | \ |
54 | if (buf == end) \ |
55 | FAIL; \ |
56 | start = buf; \ |
57 | while (buf != end && !ISTERM(*buf)) \ |
58 | buf++; \ |
59 | make_id(tree, start, buf-start); \ |
60 | }) |
61 | |
62 | |
63 | #define FAIL \ |
64 | do { \ |
65 | failed_at = __LINE__; \ |
66 | goto fail; \ |
67 | } \ |
68 | while (0) |
69 | |
70 | |
71 | #define DONE goto done |
72 | |
73 | |
74 | static void compact_pkg(struct pkg *new) |
75 | { |
76 | struct pkg *old; |
77 | |
78 | for (old = new->more; old; old = old->more) |
79 | if (old->version == new->version) |
80 | goto compact; |
81 | return; |
82 | |
83 | compact: |
84 | new->id->value = new->more; |
85 | old->installed = old->installed || new->installed; |
86 | /* @@@ we may leak a little */ |
87 | free(new); |
88 | } |
89 | |
90 | |
91 | static void gobble_buf(const char *name, const char *buf, size_t len) |
92 | { |
93 | const char *end = buf+len; |
94 | int lineno = 1; |
95 | struct pkg *pkg = NULL; /* current package */ |
96 | struct ref **anchor = NULL; |
97 | int i, failed_at = 0; |
98 | |
99 | initial: |
100 | if (buf == end) |
101 | DONE; |
102 | if (*buf == '\n') { |
103 | lineno++; |
104 | buf++; |
105 | goto initial; |
106 | } |
107 | |
108 | /* decode the tag */ |
109 | |
110 | switch (*buf++) { |
111 | case 'A': /* Architecture // Auto-Installed */ |
112 | switch (NEXT) { |
113 | case 'r': |
114 | EXPECT("chitecture:"); |
115 | /* @@@ use later */ |
116 | goto skip_data; |
117 | case 'u': |
118 | EXPECT("to-Installed:"); |
119 | goto skip_data; |
120 | default: |
121 | FAIL; |
122 | } |
123 | |
124 | case 'C': /* Conflicts // Conffiles */ |
125 | EXPECT("onf"); |
126 | switch (NEXT) { |
127 | case 'l': |
128 | EXPECT("icts:"); |
129 | goto conflicts; |
130 | case 'f': |
131 | EXPECT("iles:"); |
132 | goto skip_data; |
133 | default: |
134 | FAIL; |
135 | } |
136 | |
137 | case 'D': /* Depends, Description */ |
138 | EXPECT("e"); |
139 | switch (NEXT) { |
140 | case 'p': |
141 | EXPECT("ends:"); |
142 | goto depends; |
143 | case 's': |
144 | EXPECT("cription:"); |
145 | goto skip_data; |
146 | default: |
147 | FAIL; |
148 | } |
149 | |
150 | case 'F': /* Filename */ |
151 | EXPECT("ilename:"); |
152 | goto filename; |
153 | |
154 | case 'H': /* HomePage, Homepage */ |
155 | EXPECT("ome"); |
156 | switch (NEXT) { |
157 | case 'P': |
158 | case 'p': |
159 | EXPECT("age:"); |
160 | goto skip_data; |
161 | default: |
162 | FAIL; |
163 | } |
164 | |
165 | case 'I': /* Installed-Time */ |
166 | EXPECT("nstalled-Time:"); |
167 | goto skip_data; |
168 | |
169 | case 'L': /* License */ |
170 | EXPECT("icense:"); |
171 | goto skip_data; |
172 | |
173 | case 'M': /* Maintainer, MD5Sum */ |
174 | switch (NEXT) { |
175 | case 'a': |
176 | EXPECT("intainer:"); |
177 | goto skip_data; |
178 | case 'D': |
179 | EXPECT("5Sum:"); |
180 | goto skip_data; |
181 | default: |
182 | FAIL; |
183 | } |
184 | |
185 | case 'O': /* OE */ |
186 | EXPECT("E:"); |
187 | goto skip_data; |
188 | |
189 | case 'P': /* Package, Priority, Provides */ |
190 | switch (NEXT) { |
191 | case 'a': |
192 | EXPECT("ckage:"); |
193 | goto package; |
194 | case 'r': |
195 | break; |
196 | default: |
197 | FAIL; |
198 | } |
199 | switch (NEXT) { |
200 | case 'i': |
201 | EXPECT("ority:"); |
202 | goto skip_data; |
203 | case 'o': |
204 | EXPECT("vides:"); |
205 | goto provides; |
206 | default: |
207 | FAIL; |
208 | } |
209 | |
210 | case 'R': /* Recommends, Replaces */ |
211 | EXPECT("e"); |
212 | switch (NEXT) { |
213 | case 'c': |
214 | EXPECT("ommends:"); |
215 | goto skip_data; |
216 | case 'p': |
217 | EXPECT("laces:"); |
218 | goto skip_data; |
219 | default: |
220 | FAIL; |
221 | } |
222 | |
223 | case 'S': /* Section, Size, Source, Suggests // Status */ |
224 | switch (NEXT) { |
225 | case 'e': |
226 | EXPECT("ction:"); |
227 | goto skip_data; |
228 | case 'i': |
229 | EXPECT("ze:"); |
230 | goto skip_data; |
231 | case 'o': |
232 | EXPECT("urce:"); |
233 | goto skip_data; |
234 | case 'u': |
235 | EXPECT("ggests:"); |
236 | goto skip_data; |
237 | case 't': |
238 | EXPECT("atus:"); |
239 | goto status; |
240 | default: |
241 | FAIL; |
242 | } |
243 | |
244 | case 'V': /* Version */ |
245 | EXPECT("ersion:"); |
246 | goto version; |
247 | |
248 | default: |
249 | FAIL; |
250 | } |
251 | |
252 | conflicts: |
253 | anchor = &pkg->conflicts; |
254 | goto list_with_version; |
255 | |
256 | depends: |
257 | anchor = &pkg->depends; |
258 | goto list_with_version; |
259 | |
260 | package: |
261 | if (pkg) |
262 | compact_pkg(pkg); |
263 | |
264 | WHITESPACE; |
265 | pkg = alloc_type(struct pkg); |
266 | pkg->id = ID(packages); |
267 | pkg->more = pkg->id->value; |
268 | pkg->id->value = pkg; |
269 | pkg->version = NULL; |
270 | pkg->conflicts = pkg->depends = NULL; |
271 | pkg->filename = NULL; |
272 | pkg->installed = 0; |
273 | pkg->mark = 0; |
274 | goto eol; |
275 | |
276 | version: |
277 | WHITESPACE; |
278 | if (pkg->version) |
279 | FAIL; |
280 | pkg->version = ID(versions); |
281 | goto eol; |
282 | |
283 | provides: |
284 | /* @@@ later */ |
285 | goto skip_data; |
286 | |
287 | status: |
288 | pkg->installed = 1; |
289 | /* @@@ later */ |
290 | goto skip_data; |
291 | |
292 | filename: |
293 | WHITESPACE; |
294 | pkg->filename = buf; |
295 | goto skip_data; |
296 | |
297 | eol: |
298 | while (buf != end) { |
299 | if (*buf == ' ' || *buf == '\t') { |
300 | buf++; |
301 | continue; |
302 | } |
303 | if (*buf++ != '\n') |
304 | FAIL; |
305 | lineno++; |
306 | if (buf == end) |
307 | DONE; |
308 | if (*buf == ' ' || *buf == '\t') |
309 | FAIL; |
310 | goto initial; |
311 | } |
312 | DONE; |
313 | |
314 | skip_data: |
315 | while (buf != end) { |
316 | if (*buf++ != '\n') |
317 | continue; |
318 | lineno++; |
319 | if (buf == end) |
320 | DONE; |
321 | if (*buf != ' ' && *buf != '\t') |
322 | goto initial; |
323 | } |
324 | DONE; |
325 | |
326 | list_with_version: |
327 | while (1) { |
328 | struct ref *ref; |
329 | |
330 | WHITESPACE; |
331 | ref = alloc_type(struct ref); |
332 | ref->pkg = ID(packages); |
333 | |
334 | /* |
335 | * Work around the Wireshark Anomaly |
336 | */ |
337 | if (buf != end && *buf == ')') |
338 | buf++; |
339 | |
340 | WHITESPACE; |
341 | if (buf == end || *buf != '(') |
342 | ref->version = NULL; |
343 | else { |
344 | buf++; |
345 | if (buf == end) |
346 | FAIL; |
347 | switch (*buf++) { |
348 | case '=': |
349 | ref->relop = rel_eq; |
350 | break; |
351 | case '<': |
352 | ref->relop = rel_lt; |
353 | break; |
354 | case '>': |
355 | EXPECT("="); |
356 | ref->relop = rel_ge; |
357 | break; |
358 | default: |
359 | FAIL; |
360 | } |
361 | WHITESPACE; |
362 | ref->version = ID(versions); |
363 | EXPECT(")"); |
364 | } |
365 | ref->next = *anchor; |
366 | *anchor = ref; |
367 | if (buf == end) |
368 | DONE; |
369 | if (*buf != ',') |
370 | break; |
371 | buf++; |
372 | } |
373 | anchor = NULL; |
374 | goto eol; |
375 | |
376 | done: |
377 | if (pkg) |
378 | compact_pkg(pkg); |
379 | return; |
380 | |
381 | fail: |
382 | fprintf(stderr, "syntax derailment #%d at %s line %d: ", |
383 | failed_at, name, lineno); |
384 | for (i = 0; i != CHARS_AFTER_ERROR && buf != end; i++) { |
385 | if (*buf == '\n') |
386 | fprintf(stderr, "\\n"); |
387 | else if (isspace(*buf)) |
388 | fputc(' ', stderr); |
389 | else if (isprint(*buf)) |
390 | fputc(*buf, stderr); |
391 | buf++; |
392 | } |
393 | fprintf(stderr, "%s\n", buf == end ? "": "..."); |
394 | exit(1); |
395 | } |
396 | |
397 | |
398 | void gobble(const char *name) |
399 | { |
400 | int fd; |
401 | struct stat st; |
402 | void *map; |
403 | |
404 | fd = open(name, O_RDONLY); |
405 | if (fd < 0) { |
406 | perror(name); |
407 | exit(1); |
408 | } |
409 | if (fstat(fd, &st) < 0) { |
410 | perror("fstat"); |
411 | exit(1); |
412 | } |
413 | map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); |
414 | if (map == MAP_FAILED) { |
415 | perror("mmap"); |
416 | exit(1); |
417 | } |
418 | if (posix_madvise(map, st.st_size, POSIX_MADV_WILLNEED) < 0) { |
419 | perror("posix_madvise(POSIX_MADV_WILLNEED)"); |
420 | exit(1); |
421 | } |
422 | gobble_buf(name, map, st.st_size); |
423 | if (posix_madvise(map, st.st_size, POSIX_MADV_RANDOM) < 0) { |
424 | perror("posix_madvise(POSIX_MADV_RANDOM)"); |
425 | exit(1); |
426 | } |
427 | } |
428 |
Branches:
master