]>
Commit | Line | Data |
---|---|---|
a6316ce4 MT |
1 | #define _GNU_SOURCE /* memmem */ |
2 | #include <stdio.h> | |
3 | #include <stdlib.h> | |
4 | #include <string.h> | |
5 | #include <ctype.h> | |
6 | #include <inttypes.h> | |
7 | #include <unistd.h> | |
8 | #include <time.h> | |
9 | #include <getopt.h> | |
10 | ||
11 | #include "../hd/hddb_int.h" | |
12 | ||
13 | #define TAG_PCI 1 /* pci ids */ | |
14 | #define TAG_EISA 2 /* eisa ids */ | |
15 | #define TAG_USB 3 /* usb ids */ | |
16 | #define TAG_SPECIAL 4 /* internally used ids */ | |
17 | #define TAG_PCMCIA 5 /* pcmcia ids */ | |
18 | ||
19 | #define ID_VALUE(id) ((id) & 0xffff) | |
20 | #define ID_TAG(id) (((id) >> 16) & 0xf) | |
21 | #define MAKE_ID(tag, id_val) ((tag << 16) | (id_val)) | |
22 | ||
23 | typedef uint32_t hddb_entry_mask_t; | |
24 | ||
25 | typedef enum { | |
26 | match_any, match_all | |
27 | } match_t; | |
28 | ||
29 | typedef enum { | |
30 | pref_empty, pref_new, pref_and, pref_or, pref_add | |
31 | } prefix_t; | |
32 | ||
33 | typedef struct line_s { | |
34 | prefix_t prefix; | |
35 | hddb_entry_t key; | |
36 | char *value; | |
37 | } line_t; | |
38 | ||
39 | typedef struct str_s { | |
40 | struct str_s *next; | |
41 | char *str; | |
42 | } str_t; | |
43 | ||
44 | typedef struct list_any_s { | |
45 | struct list_any_s *next; | |
46 | } list_any_t; | |
47 | ||
48 | typedef struct { | |
49 | void *first; | |
50 | void *last; | |
51 | } list_t; | |
52 | ||
53 | typedef struct { | |
54 | unsigned flag; | |
55 | unsigned remove; | |
56 | } hid_any_t; | |
57 | ||
58 | typedef struct { | |
59 | unsigned flag; | |
60 | unsigned remove; | |
61 | unsigned tag; | |
62 | unsigned id; | |
63 | unsigned range; | |
64 | unsigned mask; | |
65 | struct { | |
66 | unsigned range:1; | |
67 | unsigned mask:1; | |
68 | } has; | |
69 | } hid_num_t; | |
70 | ||
71 | typedef struct { | |
72 | unsigned flag; | |
73 | unsigned remove; | |
74 | list_t list; | |
75 | } hid_str_t; | |
76 | ||
77 | typedef union { | |
78 | hid_any_t any; | |
79 | hid_num_t num; | |
80 | hid_str_t str; | |
81 | } hid_t; | |
82 | ||
83 | typedef struct skey_s { | |
84 | struct skey_s *next; | |
85 | hid_t *hid[he_nomask]; | |
86 | } skey_t; | |
87 | ||
88 | typedef struct item_s { | |
89 | struct item_s *next; | |
90 | unsigned remove:1; | |
91 | char *pos; | |
92 | list_t key; /* skey_t */ | |
93 | skey_t *value; | |
94 | } item_t; | |
95 | ||
96 | ||
97 | typedef struct hddb_list_s { | |
98 | hddb_entry_mask_t key_mask; | |
99 | hddb_entry_mask_t value_mask; | |
100 | unsigned key; | |
101 | unsigned value; | |
102 | } hddb_list_t; | |
103 | ||
104 | typedef struct { | |
105 | unsigned list_len, list_max; | |
106 | hddb_list_t *list; | |
107 | unsigned ids_len, ids_max; | |
108 | unsigned *ids; | |
109 | unsigned strings_len, strings_max; | |
110 | char *strings; | |
111 | } hddb_data_t; | |
112 | ||
113 | ||
114 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
115 | #ifdef UCLIBC | |
116 | void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); | |
117 | #endif | |
118 | void *new_mem(size_t size); | |
119 | void *free_mem(void *ptr); | |
120 | char *new_str(char *str); | |
121 | void *add_list(list_t *list, void *entry); | |
122 | void sort_list(list_t *list, int (*cmp_func)(const void *, const void *)); | |
123 | unsigned eisa_id(char *s); | |
124 | char *eisa_str(unsigned id); | |
125 | void write_stats(FILE *f); | |
126 | ||
127 | void read_items(char *file); | |
128 | line_t *parse_line(char *str); | |
129 | hddb_entry_mask_t add_entry(skey_t *skey, hddb_entry_t idx, char *val); | |
130 | ||
131 | void write_items(char *file, list_t *hd); | |
132 | void write_item(FILE *f, item_t *item); | |
133 | void write_skey(FILE *f, prefix_t pre, skey_t *skey); | |
134 | void write_ent_name(FILE *f, hid_t *hid, char pre, hddb_entry_t ent); | |
135 | void write_id(FILE *f, hddb_entry_t ent, hid_t *hid); | |
136 | void write_drv(FILE *f, char pre, hid_t *hid); | |
137 | void write_drv1(FILE *f, hid_t *hid, char pre, char *val); | |
138 | void log_items(FILE *f, item_t *item0, item_t *item1); | |
139 | ||
140 | int count_common_hids(skey_t *skey0, skey_t *skey1); | |
141 | int strip_skey(skey_t *skey0, skey_t *skey1, int do_it); | |
142 | void remove_deleted_hids(skey_t *skey); | |
143 | void undelete_hids(skey_t *skey); | |
144 | str_t *split(char del, char *s); | |
145 | char *join(char del, str_t *str); | |
146 | ||
147 | int cmp_driver_info(char *str0, char *str1); | |
148 | int cmp_str_s(const void *p0, const void *p1); | |
149 | int cmp_hid(hid_t *hid0, hid_t *hid1); | |
150 | int cmp_skey(skey_t *skey0, skey_t *skey1); | |
151 | int cmp_skey_s(const void *p0, const void *p1); | |
152 | int cmp_item(item_t *item0, item_t *item1); | |
153 | int cmp_item_s(const void *p0, const void *p1); | |
154 | ||
155 | int match_hid(hid_t *hid0, hid_t *hid1, match_t match); | |
156 | int match_skey(skey_t *skey0, skey_t *skey1, match_t match); | |
157 | int match_item(item_t *item0, item_t *item1, match_t match); | |
158 | ||
159 | int combine_keys(skey_t *skey0, skey_t *skey1); | |
160 | ||
161 | str_t *clone_str(str_t *str); | |
162 | hid_t *clone_hid(hid_t *hid); | |
163 | skey_t *clone_skey(skey_t *skey); | |
164 | item_t *clone_item(item_t *item); | |
165 | ||
166 | str_t *free_str(str_t *str, int follow_next); | |
167 | hid_t *free_hid(hid_t *hid); | |
168 | skey_t *free_skey(skey_t *skey, int follow_next); | |
169 | item_t *free_item(item_t *item, int follow_next); | |
170 | ||
171 | unsigned driver_entry_types(hid_t *hid); | |
172 | ||
173 | void remove_items(list_t *hd); | |
174 | void remove_nops(list_t *hd); | |
175 | void check_items(list_t *hd); | |
176 | void split_items(list_t *hd); | |
177 | void combine_driver(list_t *hd); | |
178 | void combine_requires(list_t *hd); | |
179 | void join_items_by_value(list_t *hd); | |
180 | void join_items_by_key(list_t *hd); | |
181 | void remove_unimportant_items(list_t *hd); | |
182 | ||
183 | void write_cfile(FILE *f, list_t *hd); | |
184 | ||
185 | ||
186 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
187 | struct option options[] = { | |
188 | { "help", 0, NULL, 1 }, | |
189 | // { "debug", 1, NULL, 2 }, | |
190 | { "log", 1, NULL, 3 }, | |
191 | { "mini", 0, NULL, 4 }, | |
192 | { "sort", 0, NULL, 5 }, | |
193 | { "reverse", 0, NULL, 6 }, /* for debugging */ | |
194 | { "random", 0, NULL, 7 }, /* dto */ | |
195 | { "check", 0, NULL, 8 }, | |
196 | { "with-source", 0, NULL, 9 }, | |
197 | { "out", 1, NULL, 10}, | |
198 | { "split", 0, NULL, 11}, | |
199 | { "cfile", 1, NULL, 12}, | |
200 | { "no-compact", 0, NULL, 13}, | |
201 | { "join-keys-first", 0, NULL, 14}, | |
202 | { "combine", 0, NULL, 15}, | |
203 | { } | |
204 | }; | |
205 | ||
206 | list_t hd; | |
207 | ||
208 | char *item_ind = NULL; | |
209 | FILE *logfh = NULL; | |
210 | ||
211 | struct { | |
212 | int debug; | |
213 | unsigned sort:1; | |
214 | unsigned reverse:1; | |
215 | unsigned random:1; | |
216 | unsigned check:1; | |
217 | unsigned with_source:1; | |
218 | unsigned mini:1; | |
219 | unsigned split:1; | |
220 | unsigned no_compact:1; | |
221 | unsigned join_keys_first:1; | |
222 | unsigned combine:1; /* always combine driver info */ | |
223 | char *logfile; | |
224 | char *outfile; | |
225 | char *cfile; | |
226 | } opt = { | |
227 | logfile: "hd.log", | |
228 | outfile: "hd.ids" | |
229 | }; | |
230 | ||
231 | struct { | |
232 | unsigned items_in, items_out; | |
233 | unsigned diffs, errors, errors_res; | |
234 | } stats; | |
235 | ||
236 | ||
237 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
238 | int main(int argc, char **argv) | |
239 | { | |
240 | int i, close_log = 0, close_cfile = 0; | |
241 | item_t *item; | |
242 | FILE *cfile; | |
243 | ||
244 | for(opterr = 0; (i = getopt_long(argc, argv, "", options, NULL)) != -1; ) { | |
245 | switch(i) { | |
246 | #if 0 | |
247 | case 2: | |
248 | opt.debug = strtol(optarg, NULL, 0); | |
249 | break; | |
250 | #endif | |
251 | ||
252 | case 3: | |
253 | opt.logfile = optarg; | |
254 | if(!*opt.logfile) opt.logfile = NULL; | |
255 | break; | |
256 | ||
257 | case 4: | |
258 | opt.mini = 1; | |
259 | break; | |
260 | ||
261 | case 5: | |
262 | opt.sort = 1; | |
263 | break; | |
264 | ||
265 | case 6: | |
266 | opt.reverse = 1; | |
267 | break; | |
268 | ||
269 | case 7: | |
270 | opt.random = 1; | |
271 | srand(time(NULL)); | |
272 | break; | |
273 | ||
274 | case 8: | |
275 | opt.check = 1; | |
276 | break; | |
277 | ||
278 | case 9: | |
279 | opt.with_source = 1; | |
280 | break; | |
281 | ||
282 | case 10: | |
283 | opt.outfile = optarg; | |
284 | if(!*opt.outfile) opt.outfile = NULL; | |
285 | break; | |
286 | ||
287 | case 11: | |
288 | opt.split = 1; | |
289 | break; | |
290 | ||
291 | case 12: | |
292 | opt.cfile = optarg; | |
293 | if(!*opt.cfile) opt.cfile = NULL; | |
294 | break; | |
295 | ||
296 | case 13: | |
297 | opt.no_compact = 1; | |
298 | break; | |
299 | ||
300 | case 14: | |
301 | opt.join_keys_first = 1; | |
302 | break; | |
303 | ||
304 | case 15: | |
305 | opt.combine = 1; | |
306 | break; | |
307 | ||
308 | default: | |
309 | fprintf(stderr, | |
310 | "Usage: check_hd [options] files\n" | |
311 | "Try to put hardware data into a consistent form.\n" | |
312 | " --check\t\tdo a lot of checks and remove unnecessary data\n" | |
313 | " --sort\t\tsort data\n" | |
314 | " --reverse\t\treverse sorting order\n" | |
315 | " --split\t\twrite separate entries for each key\n" | |
316 | " --with-source\t\tadd comment to each item indicating info source\n" | |
317 | " --mini\t\tminimal data base (basically driver info only)\n" | |
318 | " --join-keys-first\twhen combining similar items, join entries with\n" | |
319 | " \t\t\tcommon keys first (default is common values first)\n" | |
320 | " --cfile file\t\tcreate C file to be included in libhd\n" | |
321 | " --no-compact\t\tdon't try to make C version as small as possible\n" | |
322 | " --out file\t\twrite results to file, default is \"hd.ids\"\n" | |
323 | " --log file\t\twrite log info to file, default is \"hd.log\"\n\n" | |
324 | " Note: check_hd works with libhd/hwinfo internal format only;\n" | |
325 | " to convert to other formats, use convert_hd\n" | |
326 | ); | |
327 | return 1; | |
328 | } | |
329 | } | |
330 | ||
331 | if(opt.logfile && strcmp(opt.logfile, "-")) { | |
332 | logfh = fopen(opt.logfile, "w"); | |
333 | if(!logfh) { | |
334 | perror(opt.logfile); | |
335 | return 3; | |
336 | } | |
337 | close_log = 1; | |
338 | } | |
339 | else { | |
340 | logfh = stdout; | |
341 | } | |
342 | ||
343 | for(argv += optind; *argv; argv++) { | |
344 | read_items(*argv); | |
345 | } | |
346 | ||
347 | for(item = hd.first; item; item = item->next) stats.items_in++; | |
348 | ||
349 | fprintf(logfh, "- removing useless entries\n"); | |
350 | fflush(logfh); | |
351 | remove_nops(&hd); | |
352 | ||
353 | if(opt.mini) { | |
354 | fprintf(logfh, "- building mini version\n"); | |
355 | fflush(logfh); | |
356 | remove_unimportant_items(&hd); | |
357 | } | |
358 | ||
359 | if(opt.check || opt.split) { | |
360 | fprintf(logfh, "- splitting entries\n"); | |
361 | fflush(logfh); | |
362 | split_items(&hd); | |
363 | } | |
364 | ||
365 | if(opt.check) { | |
366 | fprintf(logfh, "- combining driver info\n"); | |
367 | fflush(logfh); | |
368 | combine_driver(&hd); | |
369 | ||
370 | fprintf(logfh, "- combining requires info\n"); | |
371 | fflush(logfh); | |
372 | combine_requires(&hd); | |
373 | ||
374 | fprintf(logfh, "- checking for consistency\n"); | |
375 | fflush(logfh); | |
376 | check_items(&hd); | |
377 | ||
378 | fprintf(logfh, "- join items\n"); | |
379 | fflush(logfh); | |
380 | if(opt.join_keys_first) { | |
381 | join_items_by_key(&hd); | |
382 | join_items_by_value(&hd); | |
383 | } | |
384 | else { | |
385 | join_items_by_value(&hd); | |
386 | join_items_by_key(&hd); | |
387 | } | |
388 | ||
389 | if(opt.split) split_items(&hd); | |
390 | } | |
391 | ||
392 | if(opt.sort) { | |
393 | fprintf(logfh, "- sorting\n"); | |
394 | fflush(logfh); | |
395 | sort_list(&hd, cmp_item_s); | |
396 | } | |
397 | ||
398 | for(item = hd.first; item; item = item->next) stats.items_out++; | |
399 | ||
400 | write_items(opt.outfile, &hd); | |
401 | ||
402 | if(opt.cfile) { | |
403 | if(opt.cfile && strcmp(opt.cfile, "-")) { | |
404 | cfile = fopen(opt.cfile, "w"); | |
405 | if(!cfile) { | |
406 | perror(opt.cfile); | |
407 | return 3; | |
408 | } | |
409 | close_cfile = 1; | |
410 | } | |
411 | else { | |
412 | cfile = stdout; | |
413 | } | |
414 | ||
415 | split_items(&hd); | |
416 | ||
417 | write_cfile(cfile, &hd); | |
418 | ||
419 | if(close_cfile) fclose(cfile); | |
420 | } | |
421 | ||
422 | fprintf(logfh, "- statistics\n"); | |
423 | write_stats(logfh); | |
424 | if(logfh != stdout) { | |
425 | if(opt.outfile && strcmp(opt.outfile, "-")) { | |
426 | fprintf(stderr, "data written to \"%s\"\n", opt.outfile); | |
427 | } | |
428 | if(opt.logfile && strcmp(opt.logfile, "-")) { | |
429 | fprintf(stderr, "log written to \"%s\"\n", opt.logfile); | |
430 | } | |
431 | fprintf(stderr, "statistics:\n"); | |
432 | write_stats(stderr); | |
433 | } | |
434 | ||
435 | free_item(hd.first, 1); | |
436 | ||
437 | if(close_log) fclose(logfh); | |
438 | ||
439 | return 0; | |
440 | } | |
441 | ||
442 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
443 | void *new_mem(size_t size) | |
444 | { | |
445 | if(size == 0) return NULL; | |
446 | ||
447 | return calloc(size, 1); | |
448 | } | |
449 | ||
450 | ||
451 | void *free_mem(void *ptr) | |
452 | { | |
453 | if(ptr) free(ptr); | |
454 | ||
455 | return NULL; | |
456 | } | |
457 | ||
458 | ||
459 | char *new_str(char *str) | |
460 | { | |
461 | if(!str) return NULL; | |
462 | ||
463 | return strdup(str); | |
464 | } | |
465 | ||
466 | ||
467 | void *add_list(list_t *list, void *entry) | |
468 | { | |
469 | if(list->last) { | |
470 | ((list_any_t *) list->last)->next = entry; | |
471 | } | |
472 | list->last = entry; | |
473 | ||
474 | if(!list->first) { | |
475 | list->first = entry; | |
476 | } | |
477 | ||
478 | return entry; | |
479 | } | |
480 | ||
481 | ||
482 | void sort_list(list_t *list, int (*cmp_func)(const void *, const void *)) | |
483 | { | |
484 | int i, list_len = 0; | |
485 | list_any_t *list_entry; | |
486 | list_t new_list = {}; | |
487 | list_any_t **list_array; | |
488 | ||
489 | for(list_entry = list->first; list_entry; list_entry = list_entry->next) list_len++; | |
490 | if(list_len < 2) return; | |
491 | ||
492 | list_array = new_mem(list_len * sizeof *list_array); | |
493 | for(i = 0, list_entry = list->first; list_entry; list_entry = list_entry->next) { | |
494 | list_array[i++] = list_entry; | |
495 | } | |
496 | ||
497 | qsort(list_array, list_len, sizeof *list_array, cmp_func); | |
498 | ||
499 | for(i = 0; i < list_len; i++) { | |
500 | add_list(&new_list, list_array[i]); | |
501 | } | |
502 | ||
503 | if(new_list.last) { | |
504 | ((list_any_t *) new_list.last)->next = NULL; | |
505 | } | |
506 | ||
507 | *list = new_list; | |
508 | ||
509 | free_mem(list_array); | |
510 | } | |
511 | ||
512 | ||
513 | unsigned eisa_id(char *s) | |
514 | { | |
515 | int i; | |
516 | unsigned u = 0; | |
517 | ||
518 | for(i = 0; i < 3; i++) { | |
519 | u <<= 5; | |
520 | if(s[i] < 'A' - 1 || s[i] > 'A' - 1 + 0x1f) return 0; | |
521 | u += s[i] - 'A' + 1; | |
522 | } | |
523 | ||
524 | return MAKE_ID(TAG_EISA, u); | |
525 | } | |
526 | ||
527 | ||
528 | char *eisa_str(unsigned id) | |
529 | { | |
530 | static char s[4]; | |
531 | ||
532 | s[0] = ((id >> 10) & 0x1f) + 'A' - 1; | |
533 | s[1] = ((id >> 5) & 0x1f) + 'A' - 1; | |
534 | s[2] = ( id & 0x1f) + 'A' - 1; | |
535 | s[3] = 0; | |
536 | ||
537 | return s; | |
538 | } | |
539 | ||
540 | ||
541 | void write_stats(FILE *f) | |
542 | { | |
543 | fprintf(f, " %u inconsistencies%s\n", stats.diffs, stats.diffs ? " fixed" : ""); | |
544 | fprintf(f, " %u errors", stats.errors + stats.errors_res); | |
545 | if(stats.errors_res) fprintf(f, ", %u resolved", stats.errors_res); | |
546 | fprintf(f, "\n"); | |
547 | fprintf(f, " %u items in\n", stats.items_in); | |
548 | fprintf(f, " %u items out\n", stats.items_out); | |
549 | } | |
550 | ||
551 | ||
552 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
553 | void read_items(char *file) | |
554 | { | |
555 | FILE *f; | |
556 | char buf[1024], fpos[256]; | |
557 | unsigned u, state, l_nr; | |
558 | hddb_entry_mask_t entry_mask = 0; | |
559 | line_t *l; | |
560 | item_t *item; | |
561 | skey_t *skey; | |
562 | ||
563 | if(!(f = fopen(file, "r"))) { | |
564 | perror(file); | |
565 | return; | |
566 | } | |
567 | ||
568 | item = new_mem(sizeof *item); | |
569 | skey = new_mem(sizeof *skey); | |
570 | ||
571 | sprintf(fpos, "%s(1)", file); | |
572 | item->pos = new_str(fpos); | |
573 | ||
574 | for(l_nr = 1, state = 0; fgets(buf, sizeof buf, f); l_nr++) { | |
575 | l = parse_line(buf); | |
576 | if(!l) { | |
577 | fprintf(stderr, "%s: invalid line\n", fpos); | |
578 | state = 4; | |
579 | break; | |
580 | }; | |
581 | if(l->prefix == pref_empty) continue; | |
582 | switch(l->prefix) { | |
583 | case pref_new: | |
584 | if(state == 1) { | |
585 | add_list(&item->key, skey); | |
586 | skey = new_mem(sizeof *skey); | |
587 | } | |
588 | else if(state == 2) { | |
589 | item->value = skey; | |
590 | skey = new_mem(sizeof *skey); | |
591 | } | |
592 | if(state == 2 || state == 1) { | |
593 | add_list(&hd, item); | |
594 | item = new_mem(sizeof *item); | |
595 | if(!item->pos) { | |
596 | sprintf(fpos, "%s(%d)", file, l_nr); | |
597 | item->pos = new_str(fpos); | |
598 | } | |
599 | } | |
600 | entry_mask = 0; | |
601 | state = 1; | |
602 | break; | |
603 | ||
604 | case pref_and: | |
605 | if(state != 1) { | |
606 | fprintf(stderr, "%s: must start item first\n", fpos); | |
607 | state = 4; | |
608 | break; | |
609 | } | |
610 | break; | |
611 | ||
612 | case pref_or: | |
613 | if(state != 1 || !entry_mask) { | |
614 | fprintf(stderr, "%s: must start item first\n", fpos); | |
615 | state = 4; | |
616 | break; | |
617 | } | |
618 | add_list(&item->key, skey); | |
619 | skey = new_mem(sizeof *skey); | |
620 | entry_mask = 0; | |
621 | break; | |
622 | ||
623 | case pref_add: | |
624 | if(state == 1 && !entry_mask) { | |
625 | fprintf(stderr, "%s: driver info not allowed\n", fpos); | |
626 | state = 4; | |
627 | break; | |
628 | } | |
629 | if(state == 1) { | |
630 | add_list(&item->key, skey); | |
631 | skey = new_mem(sizeof *skey); | |
632 | entry_mask = 0; | |
633 | state = 2; | |
634 | } | |
635 | if(state != 2) { | |
636 | fprintf(stderr, "%s: driver info not allowed\n", fpos); | |
637 | state = 4; | |
638 | break; | |
639 | } | |
640 | break; | |
641 | ||
642 | default: | |
643 | state = 4; | |
644 | } | |
645 | ||
646 | if(state != 4) { | |
647 | u = add_entry(skey, l->key, l->value); | |
648 | if(u) { | |
649 | entry_mask |= u; | |
650 | } | |
651 | else { | |
652 | fprintf(stderr, "%s: invalid info\n", fpos); | |
653 | state = 4; | |
654 | } | |
655 | } | |
656 | ||
657 | if(state == 4) break; /* error */ | |
658 | ||
659 | } | |
660 | ||
661 | /* finalize last item */ | |
662 | if(entry_mask && (state == 1 || state == 2)) { | |
663 | if(state == 1) { | |
664 | add_list(&item->key, skey); | |
665 | skey = NULL; | |
666 | } | |
667 | else if(state == 2) { | |
668 | item->value = skey; | |
669 | skey = NULL; | |
670 | } | |
671 | add_list(&hd, item); | |
672 | item = NULL; | |
673 | } | |
674 | ||
675 | free_mem(skey); | |
676 | free_mem(item); | |
677 | ||
678 | fclose(f); | |
679 | } | |
680 | ||
681 | ||
682 | line_t *parse_line(char *str) | |
683 | { | |
684 | static line_t l; | |
685 | char *s; | |
686 | int i; | |
687 | ||
688 | /* drop leading spaces */ | |
689 | while(isspace(*str)) str++; | |
690 | ||
691 | /* skip emtpy lines and comments */ | |
692 | if(!*str || *str == ';' || *str == '#') { | |
693 | l.prefix = pref_empty; | |
694 | return &l; | |
695 | } | |
696 | ||
697 | l.prefix = pref_new; | |
698 | ||
699 | switch(*str) { | |
700 | case '&': | |
701 | l.prefix = pref_and; | |
702 | str++; | |
703 | break; | |
704 | ||
705 | case '|': | |
706 | l.prefix = pref_or; | |
707 | str++; | |
708 | break; | |
709 | ||
710 | case '+': | |
711 | l.prefix = pref_add; | |
712 | str++; | |
713 | break; | |
714 | } | |
715 | ||
716 | /* skip spaces */ | |
717 | while(isspace(*str)) str++; | |
718 | ||
719 | s = str; | |
720 | while(*str && !isspace(*str)) str++; | |
721 | if(*str) *str++ = 0; | |
722 | while(isspace(*str)) str++; | |
723 | ||
724 | for(i = 0; (unsigned) i < sizeof hddb_entry_strings / sizeof *hddb_entry_strings; i++) { | |
725 | if(!strcmp(s, hddb_entry_strings[i])) { | |
726 | l.key = i; | |
727 | break; | |
728 | } | |
729 | } | |
730 | ||
731 | if((unsigned) i >= sizeof hddb_entry_strings / sizeof *hddb_entry_strings) return NULL; | |
732 | ||
733 | l.value = str; | |
734 | ||
735 | /* drop trailing white space */ | |
736 | i = strlen(str); | |
737 | while(i > 0) { | |
738 | if(isspace(str[i - 1])) | |
739 | str[--i] = 0; | |
740 | else | |
741 | break; | |
742 | } | |
743 | ||
744 | /* special case: drop leading and final double quotes, if any */ | |
745 | i = strlen(l.value); | |
746 | if(i >= 2 && l.value[0] == '"' && l.value[i - 1] == '"') { | |
747 | l.value[i - 1] = 0; | |
748 | l.value++; | |
749 | } | |
750 | ||
751 | // fprintf(stderr, "pre = %d, key = %d, val = \"%s\"\n", l.prefix, l.key, l.value); | |
752 | ||
753 | return &l; | |
754 | } | |
755 | ||
756 | ||
757 | int parse_id(char *str, unsigned *id, unsigned *tag, unsigned *range, unsigned *mask) | |
758 | { | |
759 | static unsigned id0, val; | |
760 | char c = 0, *s, *t = NULL; | |
761 | ||
762 | *id = *tag = *range = *mask = 0; | |
763 | ||
764 | if(!str || !*str) return 0; | |
765 | ||
766 | for(s = str; *str && !isspace(*str); str++); | |
767 | if(*str) { | |
768 | c = *(t = str); /* remember for later */ | |
769 | *str++ = 0; | |
770 | } | |
771 | while(isspace(*str)) str++; | |
772 | ||
773 | if(*s) { | |
774 | if(!strcmp(s, "pci")) *tag = TAG_PCI; | |
775 | else if(!strcmp(s, "usb")) *tag = TAG_USB; | |
776 | else if(!strcmp(s, "special")) *tag = TAG_SPECIAL; | |
777 | else if(!strcmp(s, "eisa")) *tag = TAG_EISA; | |
778 | else if(!strcmp(s, "isapnp")) *tag = TAG_EISA; | |
779 | else if(!strcmp(s, "pcmcia")) *tag = TAG_PCMCIA; | |
780 | else { | |
781 | str = s; | |
782 | if(t) *t = c; /* restore */ | |
783 | } | |
784 | } | |
785 | ||
786 | id0 = strtoul(str, &s, 0); | |
787 | ||
788 | if(s == str) { | |
789 | id0 = eisa_id(str); | |
790 | if(!id0) return 0; | |
791 | s = str + 3; | |
792 | id0 = ID_VALUE(id0); | |
793 | if(!*tag) *tag = TAG_EISA; | |
794 | } | |
795 | ||
796 | while(isspace(*s)) s++; | |
797 | if(*s && *s != '&' && *s != '+') return 0; | |
798 | ||
799 | *id = id0; | |
800 | ||
801 | if(!*s) return 1; | |
802 | ||
803 | c = *s++; | |
804 | ||
805 | while(isspace(*s)) s++; | |
806 | ||
807 | val = strtoul(s, &str, 0); | |
808 | ||
809 | if(s == str) return 0; | |
810 | ||
811 | while(isspace(*str)) str++; | |
812 | ||
813 | if(*str) return 0; | |
814 | ||
815 | if(c == '+') *range = val; else *mask = val; | |
816 | ||
817 | return c == '+' ? 2 : 3; | |
818 | } | |
819 | ||
820 | ||
821 | hddb_entry_mask_t add_entry(skey_t *skey, hddb_entry_t idx, char *val) | |
822 | { | |
823 | hddb_entry_mask_t e_mask = 0; | |
824 | int i; | |
825 | unsigned id, tag, range, mask; | |
826 | char *s, *s1, *s2, c; | |
827 | hid_t *hid; | |
828 | str_t *str; | |
829 | ||
830 | for(i = 0; (unsigned) i < sizeof hddb_is_numeric / sizeof *hddb_is_numeric; i++) { | |
831 | if(idx == hddb_is_numeric[i]) break; | |
832 | } | |
833 | ||
834 | // printf("i = %d, idx = %d, val = >%s<\n", i, idx, val); | |
835 | ||
836 | if((unsigned) i < sizeof hddb_is_numeric / sizeof *hddb_is_numeric) { | |
837 | /* numeric id */ | |
838 | e_mask |= 1 << idx; | |
839 | ||
840 | i = parse_id(val, &id, &tag, &range, &mask); | |
841 | ||
842 | // printf("parse_id = %d\n", i); | |
843 | ||
844 | if(i) { | |
845 | skey->hid[idx] = hid = new_mem(sizeof *hid); | |
846 | hid->num.flag = FLAG_ID; | |
847 | hid->num.tag = tag; | |
848 | hid->num.id = id; | |
849 | } | |
850 | else { | |
851 | return 0; | |
852 | } | |
853 | ||
854 | switch(i) { | |
855 | case 1: | |
856 | break; | |
857 | ||
858 | case 2: | |
859 | hid->num.range = range; | |
860 | hid->num.has.range = 1; | |
861 | break; | |
862 | ||
863 | case 3: | |
864 | hid->num.mask = mask; | |
865 | hid->num.has.mask = 1; | |
866 | break; | |
867 | ||
868 | default: | |
869 | return 0; | |
870 | } | |
871 | } | |
872 | else { | |
873 | if(idx < he_nomask) { | |
874 | /* strings */ | |
875 | ||
876 | e_mask |= 1 << idx; | |
877 | skey->hid[idx] = hid = new_mem(sizeof *hid); | |
878 | hid->str.flag = FLAG_STRING; | |
879 | str = add_list(&hid->str.list, new_mem(sizeof *str)); | |
880 | str->str = new_str(val); | |
881 | } | |
882 | else { | |
883 | /* special */ | |
884 | ||
885 | if(idx == he_class_id) { | |
886 | i = parse_id(val, &id, &tag, &range, &mask); | |
887 | if(i != 1) return 0; | |
888 | ||
889 | skey->hid[he_baseclass_id] = hid = new_mem(sizeof *hid); | |
890 | hid->num.flag = FLAG_ID; | |
891 | hid->num.tag = tag; | |
892 | hid->num.id = id >> 8; | |
893 | ||
894 | skey->hid[he_subclass_id] = hid = new_mem(sizeof *hid); | |
895 | hid->num.flag = FLAG_ID; | |
896 | hid->num.tag = tag; | |
897 | hid->num.id = id & 0xff; | |
898 | ||
899 | e_mask |= (1 << he_baseclass_id) + (1 << he_subclass_id) /* + (1 << he_progif_id) */; | |
900 | } | |
901 | else { | |
902 | switch(idx) { | |
903 | case he_driver_module_insmod: | |
904 | c = 'i'; | |
905 | break; | |
906 | ||
907 | case he_driver_module_modprobe: | |
908 | c = 'm'; | |
909 | break; | |
910 | ||
911 | case he_driver_module_config: | |
912 | c = 'M'; | |
913 | break; | |
914 | ||
915 | case he_driver_xfree: | |
916 | c = 'x'; | |
917 | break; | |
918 | ||
919 | case he_driver_xfree_config: | |
920 | c = 'X'; | |
921 | break; | |
922 | ||
923 | case he_driver_mouse: | |
924 | c = 'p'; | |
925 | break; | |
926 | ||
927 | case he_driver_display: | |
928 | c = 'd'; | |
929 | break; | |
930 | ||
931 | case he_driver_any: | |
932 | c = 'a'; | |
933 | break; | |
934 | ||
935 | default: | |
936 | c = 0; | |
937 | break; | |
938 | } | |
939 | if(c) { | |
940 | s = new_mem(strlen(val) + 3); | |
941 | s[0] = c; | |
942 | s[1] = '\t'; | |
943 | strcpy(s + 2, val); | |
944 | hid = skey->hid[he_driver]; | |
945 | if(!hid) { | |
946 | skey->hid[he_driver] = hid = new_mem(sizeof *hid); | |
947 | hid->str.flag = FLAG_STRING; | |
948 | } | |
949 | if( | |
950 | (c == 'X' || c == 'M') && | |
951 | hid->str.list.last && | |
952 | (s1 = ((str_t *) hid->str.list.last)->str) | |
953 | ) { | |
954 | s2 = new_mem(strlen(s1) + strlen(s) + 2); | |
955 | sprintf(s2, "%s\001%s", s1, s); | |
956 | free_mem(s1); | |
957 | ((str_t *) hid->str.list.last)->str = s2; | |
958 | } | |
959 | else { | |
960 | str = add_list(&hid->str.list, new_mem(sizeof *str)); | |
961 | str->str = new_str(s); | |
962 | } | |
963 | e_mask |= (1 << he_driver); | |
964 | s = free_mem(s); | |
965 | } | |
966 | } | |
967 | } | |
968 | } | |
969 | ||
970 | return e_mask; | |
971 | } | |
972 | ||
973 | ||
974 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
975 | void write_items(char *file, list_t *hd) | |
976 | { | |
977 | FILE *f; | |
978 | item_t *item; | |
979 | int close_it = 0; | |
980 | ||
981 | if(file && strcmp(file, "-")) { | |
982 | f = fopen(file, "w"); | |
983 | if(!f) { | |
984 | perror(file); | |
985 | return; | |
986 | } | |
987 | close_it = 1; | |
988 | } | |
989 | else { | |
990 | f = stdout; | |
991 | } | |
992 | ||
993 | for(item = hd->first; item; item = item->next) { | |
994 | if(opt.with_source) fprintf(f, "# %s\n", item->pos); | |
995 | write_item(f, item); | |
996 | fputc('\n', f); | |
997 | } | |
998 | ||
999 | if(close_it) fclose(f); | |
1000 | } | |
1001 | ||
1002 | ||
1003 | void write_item(FILE *f, item_t *item) | |
1004 | { | |
1005 | skey_t *skey; | |
1006 | prefix_t pre; | |
1007 | ||
1008 | pre = pref_new; | |
1009 | for(skey = item->key.first; skey; skey = skey->next) { | |
1010 | write_skey(f, pre, skey); | |
1011 | pre = pref_or; | |
1012 | } | |
1013 | write_skey(f, pref_add, item->value); | |
1014 | } | |
1015 | ||
1016 | ||
1017 | void write_skey(FILE *f, prefix_t pre, skey_t *skey) | |
1018 | { | |
1019 | static char pref_char[5] = { ' ', ' ', '&', '|', '+' }; | |
1020 | int i; | |
1021 | ||
1022 | if(pre >= sizeof pref_char) { | |
1023 | fprintf(stderr, "internal oops\n"); | |
1024 | exit(2); | |
1025 | } | |
1026 | ||
1027 | if(!skey) return; | |
1028 | ||
1029 | for(i = 0; (unsigned) i < sizeof skey->hid / sizeof *skey->hid; i++) { | |
1030 | if(skey->hid[i]) { | |
1031 | if(i != he_driver) { | |
1032 | write_ent_name(f, skey->hid[i], pref_char[pre], i); | |
1033 | write_id(f, i, skey->hid[i]); | |
1034 | fputc('\n', f); | |
1035 | } | |
1036 | else { | |
1037 | write_drv(f, pref_char[pre], skey->hid[i]); | |
1038 | } | |
1039 | if(pre != pref_add) pre = pref_and; | |
1040 | } | |
1041 | } | |
1042 | } | |
1043 | ||
1044 | ||
1045 | void write_ent_name(FILE *f, hid_t *hid, char pre, hddb_entry_t ent) | |
1046 | { | |
1047 | int len, tab_ind = 24; | |
1048 | char c; | |
1049 | ||
1050 | if(ent >= sizeof hddb_entry_strings / sizeof *hddb_entry_strings) { | |
1051 | fprintf(stderr, "internal oops\n"); | |
1052 | exit(2); | |
1053 | } | |
1054 | ||
1055 | len = item_ind ? strlen(item_ind) : 0; | |
1056 | ||
1057 | if(!len) { | |
1058 | fprintf(f, "%c%s\t", pre, hddb_entry_strings[ent]); | |
1059 | } | |
1060 | else { | |
1061 | c = hid->any.remove ? '*' : ':'; | |
1062 | fprintf(f, "%s%c %c%s\t", item_ind, c, pre, hddb_entry_strings[ent]); | |
1063 | len += 2; | |
1064 | tab_ind += 8; | |
1065 | } | |
1066 | ||
1067 | len += strlen(hddb_entry_strings[ent]) + 1; | |
1068 | ||
1069 | for(len = (len & ~7) + 8; len < tab_ind; len += 8) { | |
1070 | fputc('\t', f); | |
1071 | } | |
1072 | } | |
1073 | ||
1074 | ||
1075 | void write_id(FILE *f, hddb_entry_t ent, hid_t *hid) | |
1076 | { | |
1077 | static char *tag_name[6] = { "", "pci ", "eisa ", "usb ", "special ", "pcmcia " }; | |
1078 | int tag; | |
1079 | unsigned u; | |
1080 | char c; | |
1081 | ||
1082 | switch(hid->any.flag) { | |
1083 | case FLAG_ID: | |
1084 | tag = hid->num.tag; | |
1085 | if((unsigned) tag >= sizeof tag_name / sizeof *tag_name) { | |
1086 | fprintf(stderr, "internal oops\n"); | |
1087 | exit(2); | |
1088 | } | |
1089 | if(tag == TAG_EISA && (ent == he_vendor_id || ent == he_subvendor_id)) { | |
1090 | fprintf(f, "%s", eisa_str(hid->num.id)); | |
1091 | } | |
1092 | else { | |
1093 | u = 4; | |
1094 | if(ent == he_bus_id || ent == he_subclass_id || ent == he_progif_id) { | |
1095 | u = 2; | |
1096 | } | |
1097 | else if(ent == he_baseclass_id) { | |
1098 | u = 3; | |
1099 | } | |
1100 | fprintf(f, "%s0x%0*x", tag_name[tag], u, hid->num.id); | |
1101 | } | |
1102 | if(hid->num.has.range || hid->num.has.mask) { | |
1103 | if(hid->num.has.range) { | |
1104 | u = hid->num.range; | |
1105 | c = '+'; | |
1106 | } | |
1107 | else { | |
1108 | u = hid->num.mask; | |
1109 | c = '&'; | |
1110 | } | |
1111 | fprintf(f, "%c0x%04x", c, u); | |
1112 | } | |
1113 | break; | |
1114 | ||
1115 | case FLAG_STRING: | |
1116 | if( /* not exactly 1 string */ | |
1117 | !hid->str.list.first || | |
1118 | ((str_t *) hid->str.list.first)->next | |
1119 | ) { | |
1120 | fprintf(stderr, "internal oops\n"); | |
1121 | exit(2); | |
1122 | } | |
1123 | fprintf(f, "%s", ((str_t *) hid->str.list.first)->str); | |
1124 | break; | |
1125 | ||
1126 | default: | |
1127 | fprintf(stderr, "internal oops\n"); | |
1128 | exit(2); | |
1129 | break; | |
1130 | } | |
1131 | } | |
1132 | ||
1133 | ||
1134 | void write_drv(FILE *f, char pre, hid_t *hid) | |
1135 | { | |
1136 | str_t *str; | |
1137 | char *s, *t; | |
1138 | ||
1139 | if(hid->any.flag != FLAG_STRING) { | |
1140 | fprintf(stderr, "internal oops\n"); | |
1141 | exit(2); | |
1142 | } | |
1143 | ||
1144 | for(str = hid->str.list.first; str; str = str->next) { | |
1145 | for(s = str->str; (t = strchr(s, '\001')); s = t + 1) { | |
1146 | *t = 0; | |
1147 | write_drv1(f, hid, pre, s); | |
1148 | *t = '\001'; | |
1149 | } | |
1150 | write_drv1(f, hid, pre, s); | |
1151 | } | |
1152 | } | |
1153 | ||
1154 | ||
1155 | void write_drv1(FILE *f, hid_t *hid, char pre, char *val) | |
1156 | { | |
1157 | char type; | |
1158 | int ent; | |
1159 | ||
1160 | type = val[0]; | |
1161 | if(!type || val[1] != '\t') { | |
1162 | fprintf(stderr, "internal oops\n"); | |
1163 | exit(2); | |
1164 | } | |
1165 | ||
1166 | switch(type) { | |
1167 | case 'x': | |
1168 | ent = he_driver_xfree; | |
1169 | break; | |
1170 | ||
1171 | case 'X': | |
1172 | ent = he_driver_xfree_config; | |
1173 | break; | |
1174 | ||
1175 | case 'i': | |
1176 | ent = he_driver_module_insmod; | |
1177 | break; | |
1178 | ||
1179 | case 'm': | |
1180 | ent = he_driver_module_modprobe; | |
1181 | break; | |
1182 | ||
1183 | case 'M': | |
1184 | ent = he_driver_module_config; | |
1185 | break; | |
1186 | ||
1187 | case 'p': | |
1188 | ent = he_driver_mouse; | |
1189 | break; | |
1190 | ||
1191 | case 'd': | |
1192 | ent = he_driver_display; | |
1193 | break; | |
1194 | ||
1195 | case 'a': | |
1196 | ent = he_driver_any; | |
1197 | break; | |
1198 | ||
1199 | default: | |
1200 | fprintf(stderr, "internal oops\n"); | |
1201 | exit(2); | |
1202 | break; | |
1203 | } | |
1204 | ||
1205 | write_ent_name(f, hid, pre, ent); | |
1206 | fprintf(f, "%s\n", val + 2); | |
1207 | ||
1208 | } | |
1209 | ||
1210 | ||
1211 | void log_items(FILE *f, item_t *item0, item_t *item1) | |
1212 | { | |
1213 | char *save_ind = item_ind; | |
1214 | ||
1215 | if(item0) { | |
1216 | item_ind = " 0"; | |
1217 | write_item(f, item0); | |
1218 | } | |
1219 | ||
1220 | if(item1) { | |
1221 | item_ind = " 1"; | |
1222 | write_item(f, item1); | |
1223 | } | |
1224 | ||
1225 | item_ind = save_ind; | |
1226 | } | |
1227 | ||
1228 | ||
1229 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
1230 | /* count common defined hid entries */ | |
1231 | int count_common_hids(skey_t *skey0, skey_t *skey1) | |
1232 | { | |
1233 | int i, cnt = 0; | |
1234 | ||
1235 | if(!skey0 || !skey1) return 0; | |
1236 | ||
1237 | for(i = 0; (unsigned) i < sizeof skey0->hid / sizeof *skey0->hid; i++) { | |
1238 | if(skey0->hid[i] && skey1->hid[i]) cnt++; | |
1239 | } | |
1240 | ||
1241 | return cnt; | |
1242 | } | |
1243 | ||
1244 | ||
1245 | /* | |
1246 | * remove hid entries from skey0 that are defined in skey1 | |
1247 | * | |
1248 | * do_it: | |
1249 | * 0: don't remove anything, just count | |
1250 | * 1: remove identical entries | |
1251 | * 2: remove differing entries | |
1252 | * 3: both of the above | |
1253 | * | |
1254 | * return | |
1255 | * bits 0- 7: identical entries | |
1256 | * 8-15: different entries | |
1257 | * 16-23: critical conflicts | |
1258 | */ | |
1259 | int strip_skey(skey_t *skey0, skey_t *skey1, int do_it) | |
1260 | { | |
1261 | int i, cnt; | |
1262 | ||
1263 | for(i = cnt = 0; (unsigned) i < sizeof skey0->hid / sizeof *skey0->hid; i++) { | |
1264 | if(!skey0->hid[i] || !skey1->hid[i]) continue; | |
1265 | if(cmp_hid(skey0->hid[i], skey1->hid[i])) { | |
1266 | cnt += 1 << 8; | |
1267 | if(i == he_driver || i == he_requires) { | |
1268 | cnt += 1 << 16; | |
1269 | } | |
1270 | if((do_it & 2)) skey0->hid[i]->any.remove = 1; | |
1271 | } | |
1272 | else { | |
1273 | cnt++; | |
1274 | if((do_it & 1)) skey0->hid[i]->any.remove = 1; | |
1275 | } | |
1276 | } | |
1277 | ||
1278 | return cnt; | |
1279 | } | |
1280 | ||
1281 | ||
1282 | /* | |
1283 | * remove deleted hid entries from skey | |
1284 | */ | |
1285 | void remove_deleted_hids(skey_t *skey) | |
1286 | { | |
1287 | int i; | |
1288 | ||
1289 | for(i = 0; (unsigned) i < sizeof skey->hid / sizeof *skey->hid; i++) { | |
1290 | if(skey->hid[i] && skey->hid[i]->any.remove) { | |
1291 | skey->hid[i] = free_hid(skey->hid[i]); | |
1292 | } | |
1293 | } | |
1294 | } | |
1295 | ||
1296 | ||
1297 | /* | |
1298 | * undeleted hid entries from skey | |
1299 | */ | |
1300 | void undelete_hids(skey_t *skey) | |
1301 | { | |
1302 | int i; | |
1303 | ||
1304 | for(i = 0; (unsigned) i < sizeof skey->hid / sizeof *skey->hid; i++) { | |
1305 | if(skey->hid[i]) skey->hid[i]->any.remove = 0; | |
1306 | } | |
1307 | } | |
1308 | ||
1309 | ||
1310 | str_t *split(char del, char *s) | |
1311 | { | |
1312 | char *t, *s0; | |
1313 | list_t list = {}; | |
1314 | str_t *str; | |
1315 | ||
1316 | if(!s) return NULL; | |
1317 | ||
1318 | for(s0 = s = new_str(s); (t = strchr(s, del)); s = t + 1) { | |
1319 | *t = 0; | |
1320 | str = add_list(&list, new_mem(sizeof *str)); | |
1321 | str->str = new_str(s); | |
1322 | } | |
1323 | str = add_list(&list, new_mem(sizeof *str)); | |
1324 | str->str = new_str(s); | |
1325 | ||
1326 | free_mem(s0); | |
1327 | ||
1328 | return list.first; | |
1329 | } | |
1330 | ||
1331 | ||
1332 | char *join(char del, str_t *str) | |
1333 | { | |
1334 | char *s, t[2]; | |
1335 | str_t *str0; | |
1336 | int len = 0; | |
1337 | ||
1338 | for(str0 = str; str0; str0 = str0->next) { | |
1339 | len += strlen(str0->str) + 1; | |
1340 | } | |
1341 | ||
1342 | if(!len) return NULL; | |
1343 | ||
1344 | s = new_mem(len); | |
1345 | ||
1346 | t[0] = del; t[1] = 0; | |
1347 | ||
1348 | for(; str; str = str->next) { | |
1349 | strcat(s, str->str); | |
1350 | if(str->next) strcat(s, t); | |
1351 | } | |
1352 | ||
1353 | return s; | |
1354 | } | |
1355 | ||
1356 | ||
1357 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
1358 | ||
1359 | /* | |
1360 | * str0 & str1 _must_ hold valid driver info | |
1361 | */ | |
1362 | int cmp_driver_info(char *str0, char *str1) | |
1363 | { | |
1364 | char type0, type1; | |
1365 | str_t *sl0, *sl1; | |
1366 | int _3d0, _3d1, res; | |
1367 | ||
1368 | type0 = *str0; | |
1369 | type1 = *str1; | |
1370 | ||
1371 | if(type0 == 'a' || type1 == 'a') { | |
1372 | if(type0 == 'a' && type1 == 'a') return 0; | |
1373 | if(type0 == 'a') return 1; | |
1374 | return -1; | |
1375 | } | |
1376 | ||
1377 | if(type0 != 'x' || type1 != 'x') return 0; | |
1378 | ||
1379 | str0 += 2; | |
1380 | str1 += 2; | |
1381 | ||
1382 | sl0 = split('|', str0); | |
1383 | sl1 = split('|', str1); | |
1384 | ||
1385 | res = 0; | |
1386 | ||
1387 | if(sl0 && sl1) { | |
1388 | ||
1389 | /* xfree v4 first, then xfree v3 */ | |
1390 | if(*sl0->str != *sl1->str) res = *sl0->str < *sl1->str ? 1 : -1; | |
1391 | ||
1392 | if(!res) { | |
1393 | _3d0 = _3d1 = 0; | |
1394 | ||
1395 | if(sl0->next && sl0->next->next && *sl0->next->next->str) _3d0 = 1; | |
1396 | if(sl1->next && sl1->next->next && *sl1->next->next->str) _3d1 = 1; | |
1397 | ||
1398 | /* entries without 3d support first */ | |
1399 | res = _3d0 - _3d1; | |
1400 | } | |
1401 | } | |
1402 | ||
1403 | free_str(sl0, 1); | |
1404 | free_str(sl1, 1); | |
1405 | ||
1406 | return res; | |
1407 | } | |
1408 | ||
1409 | ||
1410 | /* wrapper for qsort */ | |
1411 | int cmp_str_s(const void *p0, const void *p1) | |
1412 | { | |
1413 | str_t **str0, **str1; | |
1414 | ||
1415 | str0 = (str_t **) p0; | |
1416 | str1 = (str_t **) p1; | |
1417 | ||
1418 | return strcmp((*str0)->str, (*str1)->str); | |
1419 | } | |
1420 | ||
1421 | ||
1422 | int cmp_hid(hid_t *hid0, hid_t *hid1) | |
1423 | { | |
1424 | int i = 0; | |
1425 | str_t *str0, *str1; | |
1426 | ||
1427 | if(!hid0 && !hid1) return 0; | |
1428 | if(!hid0) return -1; | |
1429 | if(!hid1) return 1; | |
1430 | ||
1431 | if(hid0->any.flag != hid1->any.flag) { | |
1432 | return hid0->any.flag < hid1->any.flag ? -1 : 1; | |
1433 | } | |
1434 | ||
1435 | if(hid0->any.flag == FLAG_STRING) { | |
1436 | str0 = hid0->str.list.first; | |
1437 | str1 = hid1->str.list.first; | |
1438 | for(; str0 && str1; str0 = str0->next, str1 = str1->next) { | |
1439 | i = strcmp(str0->str, str1->str); | |
1440 | if(i) { | |
1441 | i = i > 0 ? 1 : -1; | |
1442 | break; | |
1443 | } | |
1444 | } | |
1445 | if(!i) { | |
1446 | if(str0) i = 1; else if(str1) i = -1; | |
1447 | } | |
1448 | } | |
1449 | else if(hid0->any.flag == FLAG_ID) { | |
1450 | if(hid0->num.tag != hid1->num.tag) { | |
1451 | i = hid0->num.tag < hid1->num.tag ? -1 : 1; | |
1452 | } | |
1453 | else if(hid0->num.id != hid1->num.id) { | |
1454 | i = hid0->num.id < hid1->num.id ? -1 : 1; | |
1455 | } | |
1456 | else if(hid0->num.has.range || hid1->num.has.range) { | |
1457 | if(!hid0->num.has.range) { | |
1458 | i = -1; | |
1459 | } | |
1460 | else if(!hid1->num.has.range) { | |
1461 | i = 1; | |
1462 | } | |
1463 | else if(hid0->num.range != hid1->num.range) { | |
1464 | i = hid0->num.range < hid1->num.range ? -1 : 1; | |
1465 | } | |
1466 | } | |
1467 | else if(hid0->num.has.mask || hid1->num.has.mask) { | |
1468 | if(!hid0->num.has.mask) { | |
1469 | i = -1; | |
1470 | } | |
1471 | else if(!hid1->num.has.mask) { | |
1472 | i = 1; | |
1473 | } | |
1474 | else if(hid0->num.mask != hid1->num.mask) { | |
1475 | i = hid0->num.mask < hid1->num.mask ? -1 : 1; | |
1476 | } | |
1477 | } | |
1478 | } | |
1479 | ||
1480 | return i; | |
1481 | } | |
1482 | ||
1483 | ||
1484 | int cmp_skey(skey_t *skey0, skey_t *skey1) | |
1485 | { | |
1486 | int i, j, len0, len1, len; | |
1487 | ||
1488 | if(!skey0 && !skey1) return 0; | |
1489 | if(!skey0) return -1; | |
1490 | if(!skey1) return 1; | |
1491 | ||
1492 | for(i = len0 = len1 = 0; (unsigned) i < sizeof skey0->hid / sizeof *skey0->hid; i++) { | |
1493 | if(skey0->hid[i]) len0 = i; | |
1494 | if(skey1->hid[i]) len1 = i; | |
1495 | } | |
1496 | len0++; | |
1497 | len1++; | |
1498 | ||
1499 | // printf("len0 = %d, len1 = %d\n", len0, len1); | |
1500 | ||
1501 | len = len0 < len1 ? len0 : len1; | |
1502 | ||
1503 | for(i = j = 0; j < len; j++) { | |
1504 | // printf("0: j = %d\n", j); | |
1505 | ||
1506 | if(!skey0->hid[j] && !skey1->hid[j]) continue; | |
1507 | ||
1508 | /* note: this looks reversed, but is intentional! */ | |
1509 | if(!skey0->hid[j]) { i = 1; break; } | |
1510 | if(!skey1->hid[j]) { i = -1; break; } | |
1511 | ||
1512 | i = cmp_hid(skey0->hid[j], skey1->hid[j]); | |
1513 | // printf("1: j = %d, i = %d\n", j, i); | |
1514 | ||
1515 | if(i) break; | |
1516 | } | |
1517 | ||
1518 | if(!i && len0 != len1) { | |
1519 | i = len0 > len1 ? 1 : -1; | |
1520 | } | |
1521 | ||
1522 | return i; | |
1523 | } | |
1524 | ||
1525 | ||
1526 | /* wrapper for qsort */ | |
1527 | int cmp_skey_s(const void *p0, const void *p1) | |
1528 | { | |
1529 | skey_t **skey0, **skey1; | |
1530 | ||
1531 | skey0 = (skey_t **) p0; | |
1532 | skey1 = (skey_t **) p1; | |
1533 | ||
1534 | return cmp_skey(*skey0, *skey1); | |
1535 | } | |
1536 | ||
1537 | ||
1538 | int cmp_item(item_t *item0, item_t *item1) | |
1539 | { | |
1540 | int i; | |
1541 | skey_t *skey0, *skey1; | |
1542 | ||
1543 | skey0 = item0->key.first; | |
1544 | skey1 = item1->key.first; | |
1545 | for(i = 0; skey0 && skey1; skey0 = skey0->next, skey1 = skey1->next) { | |
1546 | if((i = cmp_skey(skey0, skey1))) break; | |
1547 | } | |
1548 | if(!i) i = cmp_skey(skey0, skey1); | |
1549 | ||
1550 | if(!i) i = 2 * cmp_skey(item0->value, item1->value); | |
1551 | ||
1552 | // printf("%s -- %s : %d\n", item0->pos, item1->pos, i); | |
1553 | ||
1554 | return i; | |
1555 | } | |
1556 | ||
1557 | ||
1558 | /* wrapper for qsort */ | |
1559 | int cmp_item_s(const void *p0, const void *p1) | |
1560 | { | |
1561 | int i; | |
1562 | item_t **item0, **item1; | |
1563 | ||
1564 | item0 = (item_t **) p0; | |
1565 | item1 = (item_t **) p1; | |
1566 | ||
1567 | if(opt.random) { | |
1568 | i = ((rand() / 317) % 3) - 1; | |
1569 | } | |
1570 | else if(opt.reverse) { | |
1571 | i = cmp_item(*item1, *item0); | |
1572 | } | |
1573 | else { | |
1574 | i = cmp_item(*item0, *item1); | |
1575 | } | |
1576 | ||
1577 | return i; | |
1578 | } | |
1579 | ||
1580 | ||
1581 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
1582 | /* | |
1583 | * Does hid1 match if hid0 does? | |
1584 | * > 0: yes, 0: no, < 0: maybe | |
1585 | * | |
1586 | * match: | |
1587 | * match_any: at least one common id in hid1 & hid0 | |
1588 | * match_all: hid1 matches whenever hid0 does (hid0 is special case of hid1)) | |
1589 | */ | |
1590 | int match_hid(hid_t *hid0, hid_t *hid1, match_t match) | |
1591 | { | |
1592 | int i, m = -1; | |
1593 | str_t *str0, *str1; | |
1594 | ||
1595 | if(!hid1) return 1; | |
1596 | if(!hid0) return 0; | |
1597 | ||
1598 | if(hid0->any.flag != hid1->any.flag) return 0; | |
1599 | ||
1600 | if(hid0->any.flag == FLAG_STRING) { | |
1601 | str0 = hid0->str.list.first; | |
1602 | str1 = hid1->str.list.first; | |
1603 | for(; str0 && str1; str0 = str0->next, str1 = str1->next) { | |
1604 | i = strcmp(str0->str, str1->str); | |
1605 | if(i) return 0; | |
1606 | } | |
1607 | m = str0 || str1 ? 0 : 1; | |
1608 | } | |
1609 | else if(hid0->any.flag == FLAG_ID) { | |
1610 | if(hid0->num.tag != hid1->num.tag) return 0; | |
1611 | ||
1612 | if(match == match_any) { | |
1613 | ||
1614 | if(hid0->num.has.range) { | |
1615 | if(hid1->num.has.range) { | |
1616 | m = | |
1617 | ( | |
1618 | hid1->num.id >= hid0->num.id && | |
1619 | hid1->num.id < hid0->num.id + hid0->num.range | |
1620 | ) || | |
1621 | ( | |
1622 | hid0->num.id >= hid1->num.id && | |
1623 | hid0->num.id < hid1->num.id + hid1->num.range | |
1624 | ) ? 1 : 0; | |
1625 | ||
1626 | } | |
1627 | else if(hid1->num.has.mask) { | |
1628 | ||
1629 | } | |
1630 | else { | |
1631 | m = | |
1632 | ( | |
1633 | hid1->num.id >= hid0->num.id && | |
1634 | hid1->num.id < hid0->num.id + hid0->num.range | |
1635 | ) ? 1 : 0; | |
1636 | } | |
1637 | } | |
1638 | else if(hid0->num.has.mask) { | |
1639 | if(hid1->num.has.range) { | |
1640 | ||
1641 | } | |
1642 | else if(hid1->num.has.mask) { | |
1643 | ||
1644 | } | |
1645 | else { | |
1646 | m = (hid1->num.id & ~hid0->num.mask) == hid0->num.id ? 1 : 0; | |
1647 | } | |
1648 | } | |
1649 | else { | |
1650 | if(hid1->num.has.range) { | |
1651 | m = | |
1652 | ( | |
1653 | hid0->num.id >= hid1->num.id && | |
1654 | hid0->num.id < hid1->num.id + hid1->num.range | |
1655 | ) ? 1 : 0; | |
1656 | } | |
1657 | else if(hid1->num.has.mask) { | |
1658 | m = (hid0->num.id & ~hid1->num.mask) == hid1->num.id ? 1 : 0; | |
1659 | } | |
1660 | else { | |
1661 | m = hid0->num.id == hid1->num.id ? 1 : 0; | |
1662 | } | |
1663 | } | |
1664 | ||
1665 | } | |
1666 | else { /* match_all */ | |
1667 | ||
1668 | if(hid0->num.has.range) { | |
1669 | if(hid1->num.has.range) { | |
1670 | m = | |
1671 | ( | |
1672 | hid0->num.id >= hid1->num.id && | |
1673 | hid0->num.id + hid0->num.range <= hid1->num.id + hid1->num.range | |
1674 | ) ? 1 : 0; | |
1675 | // fprintf(logfh, "id0 = 0x%x, id1 = 0x%x, m = %d\n", hid0->num.id, hid1->num.id, m); | |
1676 | } | |
1677 | else if(hid1->num.has.mask) { | |
1678 | ||
1679 | } | |
1680 | else { | |
1681 | m = hid1->num.id == hid0->num.id && hid0->num.range == 1 ? 1 : 0; | |
1682 | } | |
1683 | } | |
1684 | else if(hid0->num.has.mask) { | |
1685 | if(hid1->num.has.range) { | |
1686 | ||
1687 | } | |
1688 | else if(hid1->num.has.mask) { | |
1689 | ||
1690 | } | |
1691 | else { | |
1692 | m = (hid1->num.id & ~hid0->num.mask) == hid0->num.id && hid0->num.mask == 0 ? 1 : 0; | |
1693 | } | |
1694 | } | |
1695 | else { | |
1696 | if(hid1->num.has.range) { | |
1697 | m = | |
1698 | ( | |
1699 | hid0->num.id >= hid1->num.id && | |
1700 | hid0->num.id < hid1->num.id + hid1->num.range | |
1701 | ) ? 1 : 0; | |
1702 | } | |
1703 | else if(hid1->num.has.mask) { | |
1704 | m = (hid0->num.id & ~hid1->num.mask) == hid1->num.id ? 1 : 0; | |
1705 | } | |
1706 | else { | |
1707 | m = hid0->num.id == hid1->num.id ? 1 : 0; | |
1708 | } | |
1709 | } | |
1710 | ||
1711 | } | |
1712 | } | |
1713 | ||
1714 | return m; | |
1715 | } | |
1716 | ||
1717 | ||
1718 | /* | |
1719 | * Does skey1 match if skey0 does? | |
1720 | * > 0: yes, 0: no, < 0: maybe | |
1721 | */ | |
1722 | int match_skey(skey_t *skey0, skey_t *skey1, match_t match) | |
1723 | { | |
1724 | int i, k, m = 1; | |
1725 | ||
1726 | for(i = k = 0; (unsigned) i < sizeof skey0->hid / sizeof *skey0->hid; i++) { | |
1727 | k = match_hid(skey0->hid[i], skey1->hid[i], match); | |
1728 | if(k > 0) continue; | |
1729 | if(!k) return 0; | |
1730 | m = k; | |
1731 | } | |
1732 | ||
1733 | return m; | |
1734 | } | |
1735 | ||
1736 | ||
1737 | /* | |
1738 | * Does item1 match if item0 does? | |
1739 | * > 0: yes, 0: no, < 0: maybe | |
1740 | */ | |
1741 | int match_item(item_t *item0, item_t *item1, match_t match) | |
1742 | { | |
1743 | int i, k = 0; | |
1744 | skey_t *skey0, *skey1; | |
1745 | ||
1746 | skey0 = item0->key.first; | |
1747 | skey1 = item1->key.first; | |
1748 | ||
1749 | for(skey0 = item0->key.first; skey0; skey0 = skey0->next) { | |
1750 | for(skey1 = item1->key.first; skey1; skey1 = skey1->next) { | |
1751 | i = match_skey(skey0, skey1, match); | |
1752 | if(i > 0) return i; | |
1753 | if(i) k = i; | |
1754 | } | |
1755 | } | |
1756 | ||
1757 | return k; | |
1758 | } | |
1759 | ||
1760 | ||
1761 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
1762 | int combine_keys(skey_t *skey0, skey_t *skey1) | |
1763 | { | |
1764 | int i, ind; | |
1765 | unsigned r0, r1; | |
1766 | hid_t *hid0, *hid1; | |
1767 | ||
1768 | for(ind = -1, i = 0; (unsigned) i < sizeof skey0->hid / sizeof *skey0->hid; i++) { | |
1769 | if(!skey0->hid[i] && !skey1->hid[i]) continue; | |
1770 | if(!skey0->hid[i] || !skey1->hid[i]) return 0; | |
1771 | if(!cmp_hid(skey0->hid[i], skey1->hid[i])) continue; | |
1772 | if(ind >= 0) return 0; | |
1773 | ind = i; | |
1774 | } | |
1775 | ||
1776 | if(ind < 0) return 0; | |
1777 | ||
1778 | /* ok, exactly one hid differs */ | |
1779 | hid0 = skey0->hid[ind]; | |
1780 | hid1 = skey1->hid[ind]; | |
1781 | ||
1782 | /* must be numerical */ | |
1783 | if(hid0->any.flag != FLAG_ID || hid1->any.flag != FLAG_ID) return 0; | |
1784 | ||
1785 | /* no mask value */ | |
1786 | if(hid0->num.has.mask || hid1->num.has.mask) return 0; | |
1787 | ||
1788 | /* must be adjacent ranges, can overlap */ | |
1789 | r0 = hid0->num.has.range ? hid0->num.range : 1; | |
1790 | r1 = hid1->num.has.range ? hid1->num.range : 1; | |
1791 | ||
1792 | if(hid1->num.id >= hid0->num.id && hid1->num.id <= hid0->num.id + r0) { | |
1793 | i = hid1->num.id + r1 - hid0->num.id; | |
1794 | if((unsigned) i < r0) i = r0; | |
1795 | if(i != 1) { | |
1796 | hid0->num.range = i; | |
1797 | hid0->num.has.range = 1; | |
1798 | } | |
1799 | else { | |
1800 | hid0->num.range = 0; | |
1801 | hid0->num.has.range = 0; | |
1802 | } | |
1803 | } | |
1804 | else { | |
1805 | return 0; | |
1806 | } | |
1807 | ||
1808 | return 1; | |
1809 | } | |
1810 | ||
1811 | ||
1812 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
1813 | str_t *clone_str(str_t *str) | |
1814 | { | |
1815 | str_t *n_str; | |
1816 | ||
1817 | if(!str) return NULL; | |
1818 | ||
1819 | n_str = new_mem(sizeof *n_str); | |
1820 | n_str->str = new_str(str->str); | |
1821 | ||
1822 | return n_str; | |
1823 | } | |
1824 | ||
1825 | ||
1826 | hid_t *clone_hid(hid_t *hid) | |
1827 | { | |
1828 | hid_t *new_hid; | |
1829 | str_t *str; | |
1830 | ||
1831 | if(!hid) return NULL; | |
1832 | ||
1833 | new_hid = new_mem(sizeof *new_hid); | |
1834 | ||
1835 | *new_hid = *hid; | |
1836 | ||
1837 | if(hid->any.flag == FLAG_STRING) { | |
1838 | memset(&new_hid->str.list, 0, sizeof new_hid->str.list); | |
1839 | for(str = hid->str.list.first; str; str = str->next) { | |
1840 | add_list(&new_hid->str.list, clone_str(str)); | |
1841 | } | |
1842 | } | |
1843 | ||
1844 | return new_hid; | |
1845 | } | |
1846 | ||
1847 | ||
1848 | skey_t *clone_skey(skey_t *skey) | |
1849 | { | |
1850 | int i; | |
1851 | skey_t *new_skey; | |
1852 | ||
1853 | if(!skey) return NULL; | |
1854 | ||
1855 | new_skey = new_mem(sizeof *new_skey); | |
1856 | ||
1857 | for(i = 0; (unsigned) i < sizeof skey->hid / sizeof *skey->hid; i++) { | |
1858 | new_skey->hid[i] = clone_hid(skey->hid[i]); | |
1859 | } | |
1860 | ||
1861 | return new_skey; | |
1862 | } | |
1863 | ||
1864 | ||
1865 | item_t *clone_item(item_t *item) | |
1866 | { | |
1867 | item_t *new_item; | |
1868 | skey_t *skey; | |
1869 | ||
1870 | if(!item) return NULL; | |
1871 | ||
1872 | new_item = new_mem(sizeof *new_item); | |
1873 | ||
1874 | new_item->pos = new_str(item->pos); | |
1875 | ||
1876 | for(skey = item->key.first; skey; skey = skey->next) { | |
1877 | add_list(&new_item->key, clone_skey(skey)); | |
1878 | } | |
1879 | ||
1880 | new_item->value = clone_skey(item->value); | |
1881 | ||
1882 | return new_item; | |
1883 | } | |
1884 | ||
1885 | ||
1886 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
1887 | str_t *free_str(str_t *str, int follow_next) | |
1888 | { | |
1889 | str_t *next; | |
1890 | ||
1891 | for(; str; str = next) { | |
1892 | next = str->next; | |
1893 | ||
1894 | free_mem(str->str); | |
1895 | free_mem(str); | |
1896 | ||
1897 | if(!follow_next) break; | |
1898 | } | |
1899 | ||
1900 | return NULL; | |
1901 | } | |
1902 | ||
1903 | ||
1904 | hid_t *free_hid(hid_t *hid) | |
1905 | { | |
1906 | if(!hid) return NULL; | |
1907 | ||
1908 | if(hid->any.flag == FLAG_STRING) { | |
1909 | free_str(hid->str.list.first, 1); | |
1910 | } | |
1911 | free_mem(hid); | |
1912 | ||
1913 | return NULL; | |
1914 | } | |
1915 | ||
1916 | ||
1917 | skey_t *free_skey(skey_t *skey, int follow_next) | |
1918 | { | |
1919 | skey_t *next; | |
1920 | int i; | |
1921 | ||
1922 | for(; skey; skey = next) { | |
1923 | next = skey->next; | |
1924 | ||
1925 | for(i = 0; (unsigned) i < sizeof skey->hid / sizeof *skey->hid; i++) { | |
1926 | free_hid(skey->hid[i]); | |
1927 | } | |
1928 | ||
1929 | free_mem(skey); | |
1930 | ||
1931 | if(!follow_next) break; | |
1932 | } | |
1933 | ||
1934 | return NULL; | |
1935 | } | |
1936 | ||
1937 | ||
1938 | item_t *free_item(item_t *item, int follow_next) | |
1939 | { | |
1940 | item_t *next; | |
1941 | ||
1942 | for(; item; item = next) { | |
1943 | next = item->next; | |
1944 | ||
1945 | free_mem(item->pos); | |
1946 | ||
1947 | free_skey(item->key.first, 1); | |
1948 | free_skey(item->value, 0); | |
1949 | ||
1950 | free_mem(item); | |
1951 | ||
1952 | if(!follow_next) break; | |
1953 | } | |
1954 | ||
1955 | return NULL; | |
1956 | } | |
1957 | ||
1958 | ||
1959 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
1960 | unsigned driver_entry_types(hid_t *hid) | |
1961 | { | |
1962 | str_t *str; | |
1963 | unsigned ent = 0; | |
1964 | ||
1965 | for(str = hid->str.list.first; str; str = str->next) { | |
1966 | if(!str->str[0] || str->str[1] != '\t') break; | |
1967 | switch(str->str[0]) { | |
1968 | case 'a': | |
1969 | ent |= 1; | |
1970 | break; | |
1971 | ||
1972 | case 'x': | |
1973 | case 'X': | |
1974 | ent |= 2; | |
1975 | break; | |
1976 | ||
1977 | default: | |
1978 | ent |= 4; | |
1979 | } | |
1980 | } | |
1981 | ||
1982 | return ent; | |
1983 | } | |
1984 | ||
1985 | ||
1986 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
1987 | void remove_items(list_t *hd) | |
1988 | { | |
1989 | item_t *item, *next; | |
1990 | list_t hd_new = {}; | |
1991 | ||
1992 | for(item = hd->first; item; item = next) { | |
1993 | next = item->next; | |
1994 | if(item->remove) { | |
1995 | free_item(item, 0); | |
1996 | } | |
1997 | else { | |
1998 | add_list(&hd_new, item); | |
1999 | } | |
2000 | } | |
2001 | ||
2002 | if(hd_new.last) { | |
2003 | ((list_any_t *) hd_new.last)->next = NULL; | |
2004 | } | |
2005 | ||
2006 | *hd = hd_new; | |
2007 | } | |
2008 | ||
2009 | ||
2010 | void remove_nops(list_t *hd) | |
2011 | { | |
2012 | item_t *item; | |
2013 | int cnt = 0; | |
2014 | ||
2015 | for(item = hd->first; item; item = item->next) { | |
2016 | if(!item->value || !item->key.first) { | |
2017 | item->remove = 1; | |
2018 | cnt++; | |
2019 | } | |
2020 | } | |
2021 | ||
2022 | if(cnt) remove_items(hd); | |
2023 | } | |
2024 | ||
2025 | ||
2026 | void split_items(list_t *hd) | |
2027 | { | |
2028 | item_t *item, *new_item, *next_item; | |
2029 | skey_t *skey, *next; | |
2030 | list_t hd_new = {}; | |
2031 | int cnt, l; | |
2032 | char buf[16]; | |
2033 | ||
2034 | for(item = hd->first; item; item = next_item) { | |
2035 | next_item = item->next; | |
2036 | skey = item->key.first; | |
2037 | if(skey && skey->next) { | |
2038 | for(cnt = 0, skey = item->key.first; skey; skey = next) { | |
2039 | next = skey->next; | |
2040 | new_item = add_list(&hd_new, new_mem(sizeof *new_item)); | |
2041 | if(item->pos && (l = strlen(item->pos))) { | |
2042 | sprintf(buf, ",%d)", cnt++); | |
2043 | new_item->pos = new_mem(l - 1 + strlen(buf) + 1); | |
2044 | strcpy(new_item->pos, item->pos); | |
2045 | strcpy(new_item->pos + l - 1, buf); | |
2046 | } | |
2047 | new_item->value = clone_skey(item->value); | |
2048 | add_list(&new_item->key, clone_skey(skey)); | |
2049 | } | |
2050 | free_item(item, 0); | |
2051 | } | |
2052 | else { | |
2053 | add_list(&hd_new, item); | |
2054 | } | |
2055 | } | |
2056 | ||
2057 | if(hd_new.last) { | |
2058 | ((list_any_t *) hd_new.last)->next = NULL; | |
2059 | } | |
2060 | ||
2061 | *hd = hd_new; | |
2062 | } | |
2063 | ||
2064 | ||
2065 | void check_items(list_t *hd) | |
2066 | { | |
2067 | int i, j, k, m, mr, m_all, mr_all, c_ident, c_diff, c_crit; | |
2068 | char *s; | |
2069 | item_t *item0, *item1, *item_a, *item_b; | |
2070 | unsigned *stat_cnt; | |
2071 | ||
2072 | for(item0 = hd->first; item0; item0 = item0->next) { | |
2073 | if(item0->remove) continue; | |
2074 | for(item1 = item0->next; item1 && !item0->remove; item1 = item1->next) { | |
2075 | if(item1->remove) continue; | |
2076 | ||
2077 | item_a = item0; item_b = item1; | |
2078 | ||
2079 | m = match_item(item0, item1, match_any); | |
2080 | mr = match_item(item1, item0, match_any); | |
2081 | ||
2082 | m_all = mr_all = 0; | |
2083 | ||
2084 | if(m && mr) { | |
2085 | m_all = match_item(item0, item1, match_all); | |
2086 | mr_all = match_item(item1, item0, match_all); | |
2087 | if(mr_all) { | |
2088 | item_a = item1; item_b = item0; | |
2089 | i = m_all; m_all = mr_all; mr_all = i; | |
2090 | i = m; m = mr; mr = i; | |
2091 | } | |
2092 | } | |
2093 | else if(mr && !m) { | |
2094 | item_a = item1; item_b = item0; | |
2095 | m = mr; mr = 0; | |
2096 | } | |
2097 | ||
2098 | if(m && !mr) { | |
2099 | m_all = match_item(item_a, item_b, match_all); | |
2100 | mr_all = match_item(item_b, item_a, match_all); | |
2101 | } | |
2102 | ||
2103 | if(m) { | |
2104 | #if 0 | |
2105 | fprintf( | |
2106 | logfh, "a = %s, b = %s, m = %d, mr = %d, m_all = %d, mr_all = %d\n", | |
2107 | item_a->pos, item_b->pos, | |
2108 | m, mr, m_all, mr_all | |
2109 | ); | |
2110 | #endif | |
2111 | ||
2112 | if(m_all) { | |
2113 | /* | |
2114 | * item_b matches (at least) everything that item_a does | |
2115 | * (item_a is a special case of item_b) | |
2116 | */ | |
2117 | ||
2118 | i = cmp_item(item_a, item_b); /* just informational */ | |
2119 | if(!i) { | |
2120 | /* identical keys and values */ | |
2121 | fprintf(logfh, | |
2122 | "%s: duplicate of %s, item removed\n", | |
2123 | item_a->pos, item_b->pos | |
2124 | ); | |
2125 | item_a->remove = 1; | |
2126 | } | |
2127 | else { | |
2128 | /* matching keys, differing values */ | |
2129 | ||
2130 | j = count_common_hids(item_a->key.first, item_b->key.first); | |
2131 | k = ( | |
2132 | j == count_common_hids(item_b->key.first, item_b->key.first) && | |
2133 | j < count_common_hids(item_a->key.first, item_a->key.first) | |
2134 | ) ? 1 : 0; | |
2135 | ||
2136 | if(k) { | |
2137 | /* | |
2138 | * item_a is a special case of item_b _and_ item_a has more hid fields | |
2139 | * --> libhd can handle differing info in this case | |
2140 | */ | |
2141 | j = strip_skey(item_a->value, item_b->value, 1); | |
2142 | if(j) { | |
2143 | c_ident = j & 0xff; | |
2144 | c_diff = (j >> 8) & 0xff; | |
2145 | if(c_diff && c_ident) { | |
2146 | fprintf(logfh, | |
2147 | "%s: some info identical to %s, identical info removed\n", | |
2148 | item_a->pos, item_b->pos | |
2149 | ); | |
2150 | log_items(logfh, item_a, item_b); | |
2151 | } | |
2152 | else if(!c_diff) { | |
2153 | fprintf(logfh, | |
2154 | "%s: info is identical to %s, info removed\n", | |
2155 | item_a->pos, item_b->pos | |
2156 | ); | |
2157 | log_items(logfh, item_a, item_b); | |
2158 | } | |
2159 | remove_deleted_hids(item_a->value); | |
2160 | } | |
2161 | } | |
2162 | else { | |
2163 | j = strip_skey(item_a->value, item_b->value, 3); | |
2164 | if(j) { | |
2165 | c_ident = j & 0xff; | |
2166 | c_diff = (j >> 8) & 0xff; | |
2167 | c_crit = (j >> 16) & 0xff; | |
2168 | if(c_crit || cmp_skey(item_a->key.first, item_b->key.first)) { | |
2169 | s = "conflicts with"; | |
2170 | stat_cnt = &stats.errors_res; | |
2171 | } | |
2172 | else { | |
2173 | s = "differs from"; | |
2174 | stat_cnt = &stats.diffs; | |
2175 | } | |
2176 | /* | |
2177 | * if the keys are identical, make it a warning, | |
2178 | * else make it an error | |
2179 | */ | |
2180 | if(c_diff && !c_ident) { | |
2181 | (*stat_cnt)++; | |
2182 | fprintf(logfh, | |
2183 | "%s: info %s %s, info removed\n", | |
2184 | item_a->pos, s, item_b->pos | |
2185 | ); | |
2186 | } | |
2187 | else if(c_diff && c_ident) { | |
2188 | (*stat_cnt)++; | |
2189 | fprintf(logfh, | |
2190 | "%s: info %s/is identical to %s, info removed\n", | |
2191 | item_a->pos, s, item_b->pos | |
2192 | ); | |
2193 | } | |
2194 | else { | |
2195 | fprintf(logfh, | |
2196 | "%s: info is identical to %s, info removed\n", | |
2197 | item_a->pos, item_b->pos | |
2198 | ); | |
2199 | } | |
2200 | log_items(logfh, item_a, item_b); | |
2201 | remove_deleted_hids(item_a->value); | |
2202 | } | |
2203 | } | |
2204 | ||
2205 | if(!count_common_hids(item_a->value, item_a->value)) { | |
2206 | /* remove if no values left */ | |
2207 | item_a->remove = 1; | |
2208 | fprintf(logfh, "%s: no info left, item removed\n", item_a->pos); | |
2209 | } | |
2210 | ||
2211 | } | |
2212 | } | |
2213 | else if(count_common_hids(item_a->value, item_b->value)) { | |
2214 | /* different keys, potentially conflicting values */ | |
2215 | k = cmp_skey(item_a->value, item_b->value); | |
2216 | if(k) { | |
2217 | /* differing keys, differing values */ | |
2218 | j = strip_skey(item_b->value, item_a->value, 2); | |
2219 | c_diff = (j >> 8) & 0xff; | |
2220 | if(c_diff) { | |
2221 | /* different keys, conflicting values --> error */ | |
2222 | stats.errors++; | |
2223 | fprintf(logfh, | |
2224 | "%s: info conflicts with %s\n", | |
2225 | item_b->pos, item_a->pos | |
2226 | ); | |
2227 | log_items(logfh, item_b, item_a); | |
2228 | } | |
2229 | undelete_hids(item_b->value); | |
2230 | } | |
2231 | } | |
2232 | } | |
2233 | } | |
2234 | } | |
2235 | ||
2236 | remove_items(hd); | |
2237 | } | |
2238 | ||
2239 | ||
2240 | void combine_driver(list_t *hd) | |
2241 | { | |
2242 | int i; | |
2243 | item_t *item0, *item1, *item_a, *item_b; | |
2244 | hid_t *hid0, *hid1, *new_hid, *hid_a, *hid_b; | |
2245 | str_t *str0, *str1, *tmp_str, *last_str; | |
2246 | unsigned type0, type1; | |
2247 | ||
2248 | for(item0 = hd->first; item0; item0 = item0->next) { | |
2249 | if( | |
2250 | item0->remove || | |
2251 | !item0->value || | |
2252 | !(hid0 = item0->value->hid[he_driver]) || | |
2253 | hid0->any.flag != FLAG_STRING | |
2254 | ) continue; | |
2255 | for(item1 = item0->next; item1 && !item0->remove; item1 = item1->next) { | |
2256 | hid0 = item0->value->hid[he_driver]; | |
2257 | if( | |
2258 | item1->remove || | |
2259 | !item1->value || | |
2260 | !(hid1 = item1->value->hid[he_driver]) || | |
2261 | hid1->any.flag != FLAG_STRING | |
2262 | ) continue; | |
2263 | ||
2264 | i = cmp_item(item0, item1); | |
2265 | ||
2266 | /* remove duplicate entries */ | |
2267 | if(!i) { | |
2268 | item1->remove = 1; | |
2269 | continue; | |
2270 | } | |
2271 | ||
2272 | /* work only on entries with identical keys */ | |
2273 | if(i == -1 || i == 1) continue; | |
2274 | ||
2275 | /* ensure these are proper driver entries */ | |
2276 | if(!(type0 = driver_entry_types(hid0))) continue; | |
2277 | if(!(type1 = driver_entry_types(hid1))) continue; | |
2278 | ||
2279 | /* | |
2280 | * Allow only (x11 + x11) & (!any + any) | |
2281 | * unless --combine option was used. | |
2282 | */ | |
2283 | if(!opt.combine && (((type0 & type1) & 5) || ((type0 | type1) & 6) == 6)) { | |
2284 | fprintf(logfh, | |
2285 | "%s: can't combine driver info with %s %d %d\n", | |
2286 | item0->pos, item1->pos, type0, type1 | |
2287 | ); | |
2288 | log_items(logfh, item0, item1); | |
2289 | continue; | |
2290 | } | |
2291 | ||
2292 | item_a = item0; | |
2293 | item_b = item1; | |
2294 | hid_a = hid0; | |
2295 | hid_b = hid1; | |
2296 | ||
2297 | if(type0 == 1) { | |
2298 | item_a = item1; | |
2299 | item_b = item0; | |
2300 | hid_a = hid1; | |
2301 | hid_b = hid0; | |
2302 | } | |
2303 | ||
2304 | fprintf(logfh, "%s: combine with %s\n", item_a->pos, item_b->pos); | |
2305 | log_items(logfh, item_a, item_b); | |
2306 | ||
2307 | new_hid = clone_hid(hid_a); | |
2308 | ||
2309 | for(str1 = hid_b->str.list.first; str1; str1 = str1->next) { | |
2310 | last_str = NULL; | |
2311 | for(str0 = new_hid->str.list.first; str0; last_str = str0, str0 = str0->next) { | |
2312 | i = cmp_driver_info(str1->str, str0->str); | |
2313 | if(i < 0) break; | |
2314 | } | |
2315 | if(last_str) { | |
2316 | tmp_str = last_str->next; | |
2317 | last_str->next = clone_str(str1); | |
2318 | last_str->next->next = tmp_str; | |
2319 | if(!tmp_str) { | |
2320 | new_hid->str.list.last = last_str->next; | |
2321 | } | |
2322 | } | |
2323 | else { | |
2324 | /* smaller than first entry */ | |
2325 | tmp_str = clone_str(str1); | |
2326 | tmp_str->next = new_hid->str.list.first; | |
2327 | new_hid->str.list.first = tmp_str; | |
2328 | } | |
2329 | } | |
2330 | ||
2331 | free_hid(item_a->value->hid[he_driver]); | |
2332 | item_a->value->hid[he_driver] = new_hid; | |
2333 | item_b->value->hid[he_driver] = free_hid(item_b->value->hid[he_driver]); | |
2334 | ||
2335 | fprintf(logfh, " --\n"); | |
2336 | log_items(logfh, item_a, item_b); | |
2337 | ||
2338 | if(!count_common_hids(item_b->value, item_b->value)) { | |
2339 | /* remove if no values left */ | |
2340 | item_b->remove = 1; | |
2341 | fprintf(logfh, "%s: no info left, item removed\n", item_b->pos); | |
2342 | } | |
2343 | ||
2344 | } | |
2345 | } | |
2346 | ||
2347 | remove_items(hd); | |
2348 | } | |
2349 | ||
2350 | ||
2351 | void combine_requires(list_t *hd) | |
2352 | { | |
2353 | int i; | |
2354 | item_t *item0, *item1; | |
2355 | hid_t *hid0, *hid1; | |
2356 | list_t slist = {}; | |
2357 | str_t *str, *str0, *str1; | |
2358 | ||
2359 | for(item0 = hd->first; item0; item0 = item0->next) { | |
2360 | if( | |
2361 | item0->remove || | |
2362 | !item0->value || | |
2363 | !(hid0 = item0->value->hid[he_requires]) || | |
2364 | hid0->any.flag != FLAG_STRING | |
2365 | ) continue; | |
2366 | for(item1 = item0->next; item1; item1 = item1->next) { | |
2367 | if( | |
2368 | item1->remove || | |
2369 | !item1->value || | |
2370 | !(hid1 = item1->value->hid[he_requires]) || | |
2371 | hid1->any.flag != FLAG_STRING | |
2372 | ) continue; | |
2373 | ||
2374 | i = cmp_item(item0, item1); | |
2375 | ||
2376 | /* remove duplicate entries */ | |
2377 | if(!i) { | |
2378 | item1->remove = 1; | |
2379 | continue; | |
2380 | } | |
2381 | ||
2382 | /* work only on entries with identical keys */ | |
2383 | if(i == -1 || i == 1) continue; | |
2384 | ||
2385 | if(!cmp_hid(hid0, hid1)) { | |
2386 | hid1->any.remove = 1; | |
2387 | fprintf(logfh, | |
2388 | "%s: info is identical to %s, info removed\n", | |
2389 | item1->pos, item0->pos | |
2390 | ); | |
2391 | log_items(logfh, item1, item0); | |
2392 | item1->value->hid[he_requires] = free_hid(item1->value->hid[he_requires]); | |
2393 | } | |
2394 | else { | |
2395 | slist.first = split('|', ((str_t *) hid0->str.list.first)->str); | |
2396 | ||
2397 | /* add pointer to last element */ | |
2398 | for(str = slist.first; str; str = str->next) { | |
2399 | if(!str->next) slist.last = str; | |
2400 | } | |
2401 | ||
2402 | str1 = split('|', ((str_t *) hid1->str.list.first)->str); | |
2403 | for(str = str1; str; str = str->next) { | |
2404 | for(str0 = slist.first; str0; str0 = str0->next) { | |
2405 | if(!strcmp(str->str, str0->str)) break; | |
2406 | } | |
2407 | if(!str0) add_list(&slist, clone_str(str)); | |
2408 | } | |
2409 | free_str(str1, 1); | |
2410 | ||
2411 | sort_list(&slist, cmp_str_s); | |
2412 | ||
2413 | free_str(hid0->str.list.first, 1); | |
2414 | hid0->str.list.last = NULL; | |
2415 | hid0->str.list.first = add_list(&hid0->str.list, new_mem(sizeof (str_t))); | |
2416 | ((str_t *) hid0->str.list.first)->str = join('|', slist.first); | |
2417 | ||
2418 | free_str(slist.first, 1); | |
2419 | ||
2420 | hid1->any.remove = 1; | |
2421 | ||
2422 | fprintf(logfh, | |
2423 | "%s: combine with %s, info removed\n", | |
2424 | item1->pos, item0->pos | |
2425 | ); | |
2426 | log_items(logfh, item1, item0); | |
2427 | item1->value->hid[he_requires] = free_hid(item1->value->hid[he_requires]); | |
2428 | } | |
2429 | ||
2430 | if(!count_common_hids(item1->value, item1->value)) { | |
2431 | /* remove if no values left */ | |
2432 | item1->remove = 1; | |
2433 | fprintf(logfh, "%s: no info left, item removed\n", item1->pos); | |
2434 | } | |
2435 | } | |
2436 | } | |
2437 | ||
2438 | remove_items(hd); | |
2439 | } | |
2440 | ||
2441 | ||
2442 | void join_items_by_value(list_t *hd) | |
2443 | { | |
2444 | item_t *item0, *item1; | |
2445 | skey_t *skey, *next; | |
2446 | int i; | |
2447 | ||
2448 | for(item0 = hd->first; item0; item0 = item0->next) { | |
2449 | if(item0->remove) continue; | |
2450 | for(item1 = item0->next; item1; item1 = item1->next) { | |
2451 | if(item1->remove) continue; | |
2452 | ||
2453 | if(!cmp_skey(item0->value, item1->value)) { | |
2454 | for(skey = item1->key.first; skey; skey = next) { | |
2455 | next = skey->next; | |
2456 | add_list(&item0->key, skey); | |
2457 | } | |
2458 | memset(&item1->key, 0, sizeof item1->key); | |
2459 | item1->remove = 1; | |
2460 | fprintf(logfh, "%s: info added to %s, item removed\n", item1->pos, item0->pos); | |
2461 | } | |
2462 | } | |
2463 | } | |
2464 | ||
2465 | remove_items(hd); | |
2466 | ||
2467 | for(item0 = hd->first; item0; item0 = item0->next) { | |
2468 | ||
2469 | /* sort key entries */ | |
2470 | sort_list(&item0->key, cmp_skey_s); | |
2471 | ||
2472 | /* try to join adjacent keys */ | |
2473 | for(skey = item0->key.first; skey && (next = skey->next); ) { | |
2474 | i = combine_keys(skey, next); | |
2475 | if(!i) { | |
2476 | skey = next; | |
2477 | continue; | |
2478 | } | |
2479 | if(!(skey->next = next->next)) { | |
2480 | /* last element has changed */ | |
2481 | item0->key.last = skey; | |
2482 | } | |
2483 | free_skey(next, 0); | |
2484 | } | |
2485 | } | |
2486 | } | |
2487 | ||
2488 | ||
2489 | void join_items_by_key(list_t *hd) | |
2490 | { | |
2491 | item_t *item0, *item1; | |
2492 | skey_t *val0, *val1; | |
2493 | int i; | |
2494 | ||
2495 | for(item0 = hd->first; item0; item0 = item0->next) { | |
2496 | if(item0->remove) continue; | |
2497 | val0 = item0->value; | |
2498 | for(item1 = item0->next; item1; item1 = item1->next) { | |
2499 | if(item1->remove) continue; | |
2500 | ||
2501 | i = cmp_item(item0, item1); | |
2502 | ||
2503 | if(i == 2 || i == -2) { | |
2504 | /* identical keys, values differ */ | |
2505 | val1 = item1->value; | |
2506 | if(!count_common_hids(val0, val1)) { | |
2507 | /* move everything from item1 to item0 */ | |
2508 | ||
2509 | for(i = 0; (unsigned) i < sizeof val1->hid / sizeof *val1->hid; i++) { | |
2510 | if(val1->hid[i]) { | |
2511 | val0->hid[i] = val1->hid[i]; | |
2512 | val1->hid[i] = NULL; | |
2513 | } | |
2514 | } | |
2515 | item1->remove = 1; | |
2516 | fprintf(logfh, "%s: info added to %s, item removed\n", item1->pos, item0->pos); | |
2517 | } | |
2518 | } | |
2519 | } | |
2520 | } | |
2521 | ||
2522 | remove_items(hd); | |
2523 | } | |
2524 | ||
2525 | ||
2526 | void remove_unimportant_items(list_t *hd) | |
2527 | { | |
2528 | item_t *item; | |
2529 | skey_t *val; | |
2530 | str_t *str; | |
2531 | int i, cnt; | |
2532 | ||
2533 | for(item = hd->first; item; item = item->next) { | |
2534 | val = item->value; | |
2535 | cnt = 0; | |
2536 | if(val) { | |
2537 | for(i = 0; (unsigned) i < sizeof val->hid / sizeof *val->hid; i++) { | |
2538 | if(i == he_driver && val->hid[i]) { | |
2539 | if(!( | |
2540 | val->hid[i]->any.flag == FLAG_STRING && | |
2541 | (str = val->hid[i]->str.list.first) && | |
2542 | str->str && | |
2543 | (*str->str == 'i' || *str->str == 'm') | |
2544 | )) { | |
2545 | val->hid[i] = free_hid(val->hid[i]); | |
2546 | } | |
2547 | } | |
2548 | else if(val->hid[i]) { | |
2549 | if(val->hid[i]->any.flag != FLAG_ID) val->hid[i] = free_hid(val->hid[i]); | |
2550 | } | |
2551 | if(val->hid[i]) cnt++; | |
2552 | } | |
2553 | } | |
2554 | /* no values left */ | |
2555 | if(!cnt) item->remove = 1; | |
2556 | } | |
2557 | ||
2558 | remove_items(hd); | |
2559 | } | |
2560 | ||
2561 | ||
2562 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
2563 | ||
2564 | #if 0 | |
2565 | /* returns index in hddb2->ids */ | |
2566 | unsigned store_entry(hddb2_data_t *x, tmp_entry_t *te) | |
2567 | { | |
2568 | int i, j; | |
2569 | unsigned ent = -1, u, v; | |
2570 | ||
2571 | for(i = 0; i < he_nomask; i++) { | |
2572 | if(te[i].len) { | |
2573 | for(j = 0; j < te[i].len; j++) { | |
2574 | v = te[i].val[j] | (1 << 31); | |
2575 | if(j == te[i].len - 1) v &= ~(1 << 31); | |
2576 | u = store_value(x, v); | |
2577 | if(ent == -1) ent = u; | |
2578 | } | |
2579 | } | |
2580 | } | |
2581 | ||
2582 | return ent; | |
2583 | } | |
2584 | ||
2585 | void add_value(tmp_entry_t *te, hddb_entry_t idx, unsigned val) | |
2586 | { | |
2587 | if(idx >= he_nomask) return; | |
2588 | te += idx; | |
2589 | ||
2590 | if(te->len >= sizeof te->val / sizeof *te->val) return; | |
2591 | ||
2592 | te->val[te->len++] = val; | |
2593 | } | |
2594 | ||
2595 | #endif | |
2596 | ||
2597 | ||
2598 | ||
2599 | unsigned hddb_store_string(hddb_data_t *hddb, char *str) | |
2600 | { | |
2601 | unsigned l = strlen(str), u; | |
2602 | char *s; | |
2603 | ||
2604 | if(!opt.no_compact) { | |
2605 | /* maybe we already have it... */ | |
2606 | if(l && l < hddb->strings_len) { | |
2607 | s = memmem(hddb->strings, hddb->strings_len, str, l + 1); | |
2608 | if(s) return s - hddb->strings; | |
2609 | } | |
2610 | } | |
2611 | ||
2612 | if(hddb->strings_len + l >= hddb->strings_max) { | |
2613 | hddb->strings_max += l + 0x1000; /* >4k steps */ | |
2614 | hddb->strings = realloc(hddb->strings, hddb->strings_max * sizeof *hddb->strings); | |
2615 | } | |
2616 | ||
2617 | /* make sure the 1st byte is 0 */ | |
2618 | if(hddb->strings_len == 0) { | |
2619 | *hddb->strings = 0; /* realloc does _not_ clear memory */ | |
2620 | hddb->strings_len = 1; | |
2621 | } | |
2622 | ||
2623 | if(l == 0) return 0; /* 1st byte is always 0 */ | |
2624 | ||
2625 | strcpy(hddb->strings + (u = hddb->strings_len), str); | |
2626 | hddb->strings_len += l + 1; | |
2627 | ||
2628 | return u; | |
2629 | } | |
2630 | ||
2631 | ||
2632 | unsigned hddb_store_value(hddb_data_t *hddb, unsigned val) | |
2633 | { | |
2634 | if(hddb->ids_len == hddb->ids_max) { | |
2635 | hddb->ids_max += 0x400; /* 4k steps */ | |
2636 | hddb->ids = realloc(hddb->ids, hddb->ids_max * sizeof *hddb->ids); | |
2637 | } | |
2638 | ||
2639 | hddb->ids[hddb->ids_len++] = val; | |
2640 | ||
2641 | return hddb->ids_len - 1; | |
2642 | } | |
2643 | ||
2644 | ||
2645 | unsigned hddb_store_hid(hddb_data_t *hddb, hid_t *hid, hddb_entry_t entry) | |
2646 | { | |
2647 | unsigned u, idx = -1; | |
2648 | str_t *str, *str0, *str1; | |
2649 | ||
2650 | if(!hid) return idx; | |
2651 | ||
2652 | if(hid->any.flag == FLAG_ID) { | |
2653 | if(hid->num.has.range) { | |
2654 | idx = hddb_store_value(hddb, MAKE_DATA(FLAG_RANGE, hid->num.range) | (1 << 31)); | |
2655 | } | |
2656 | else if(hid->num.has.mask) { | |
2657 | idx = hddb_store_value(hddb, MAKE_DATA(FLAG_MASK, hid->num.mask) | (1 << 31)); | |
2658 | } | |
2659 | u = hddb_store_value(hddb, MAKE_DATA(FLAG_ID, hid->num.id + (hid->num.tag << 16))); | |
2660 | if(idx == -1u) idx = u; | |
2661 | } | |
2662 | else if(hid->any.flag == FLAG_STRING) { | |
2663 | if(entry == he_driver ) { | |
2664 | for(str = hid->str.list.first; str; str = str->next) { | |
2665 | str0 = split('\001', str->str); | |
2666 | for(str1 = str0; str1; str1 = str1->next) { | |
2667 | u = hddb_store_string(hddb, str1->str); | |
2668 | if(str->next || str1->next) u |= 1 << 31; | |
2669 | u = hddb_store_value(hddb, MAKE_DATA(FLAG_STRING, u)); | |
2670 | if(idx == -1u) idx = u; | |
2671 | } | |
2672 | free_str(str0, 1); | |
2673 | } | |
2674 | } | |
2675 | else { | |
2676 | u = hddb_store_string(hddb, ((str_t *) hid->str.list.first)->str); | |
2677 | idx = hddb_store_value(hddb, MAKE_DATA(FLAG_STRING, u)); | |
2678 | } | |
2679 | } | |
2680 | ||
2681 | return idx; | |
2682 | } | |
2683 | ||
2684 | ||
2685 | void hddb_store_skey(hddb_data_t *hddb, skey_t *skey, unsigned *mask, unsigned *idx) | |
2686 | { | |
2687 | int i, j, end; | |
2688 | unsigned ent; | |
2689 | hddb_data_t save_db = *hddb; | |
2690 | ||
2691 | *mask = 0; | |
2692 | *idx = 0; | |
2693 | ||
2694 | if(!skey) return; | |
2695 | ||
2696 | for(i = 0; (unsigned) i < sizeof skey->hid / sizeof *skey->hid; i++) { | |
2697 | if(skey->hid[i]) { | |
2698 | ent = hddb_store_hid(hddb, skey->hid[i], i); | |
2699 | if(!*mask) *idx = ent; | |
2700 | *mask |= (1 << i); | |
2701 | } | |
2702 | } | |
2703 | ||
2704 | if(!opt.no_compact) { | |
2705 | /* maybe there was an identical skey before... */ | |
2706 | if(save_db.ids_len && hddb->ids_len > save_db.ids_len) { | |
2707 | j = hddb->ids_len - save_db.ids_len; | |
2708 | end = save_db.ids_len - j; | |
2709 | /* this is pretty slow, but avoids memmem() alignment problems */ | |
2710 | for(i = 0; i < end; i++) { | |
2711 | if(!memcmp(hddb->ids + i, hddb->ids + save_db.ids_len, j * sizeof *hddb->ids)) { | |
2712 | /* remove new id entries and return existing entry */ | |
2713 | hddb->ids_len = save_db.ids_len; | |
2714 | *idx = i; | |
2715 | break; | |
2716 | } | |
2717 | } | |
2718 | } | |
2719 | } | |
2720 | } | |
2721 | ||
2722 | ||
2723 | void hddb_store_list(hddb_data_t *hddb, hddb_list_t *list) | |
2724 | { | |
2725 | if(!list || !list->key_mask || !list->value_mask) return; | |
2726 | ||
2727 | if(hddb->list_len == hddb->list_max) { | |
2728 | hddb->list_max += 0x100; /* 4k steps */ | |
2729 | hddb->list = realloc(hddb->list, hddb->list_max * sizeof *hddb->list); | |
2730 | } | |
2731 | ||
2732 | hddb->list[hddb->list_len++] = *list; | |
2733 | } | |
2734 | ||
2735 | ||
2736 | void hddb_init(hddb_data_t *hddb, list_t *hd) | |
2737 | { | |
2738 | item_t *item; | |
2739 | hddb_list_t db_list = {}; | |
2740 | unsigned item_cnt; | |
2741 | ||
2742 | for(item_cnt = 0, item = hd->first; item; item = item->next, item_cnt++) { | |
2743 | ||
2744 | hddb_store_skey(hddb, item->key.first, &db_list.key_mask, &db_list.key); | |
2745 | hddb_store_skey(hddb, item->value, &db_list.value_mask, &db_list.value); | |
2746 | ||
2747 | hddb_store_list(hddb, &db_list); | |
2748 | } | |
2749 | } | |
2750 | ||
2751 | ||
2752 | unsigned char *quote_string(unsigned char *str, int len) | |
2753 | { | |
2754 | unsigned char *qstr; | |
2755 | int i, j; | |
2756 | ||
2757 | if(!str || !len) return NULL; | |
2758 | ||
2759 | qstr = new_mem(4 * len + 1); /* enough */ | |
2760 | ||
2761 | for(i = j = 0; i < len; i++) { | |
2762 | if(str[i] == '\\' || str[i] == '"' || str[i] == '?') { | |
2763 | qstr[j++] = '\\'; | |
2764 | qstr[j++] = str[i]; | |
2765 | } | |
2766 | else if(str[i] == '\n') { | |
2767 | qstr[j++] = '\\'; | |
2768 | qstr[j++] = 'n'; | |
2769 | } | |
2770 | else if(str[i] == '\t') { | |
2771 | qstr[j++] = '\\'; | |
2772 | qstr[j++] = 't'; | |
2773 | } | |
2774 | else if(str[i] < ' ') { | |
2775 | qstr[j++] = '\\'; | |
2776 | qstr[j++] = (str[i] >> 6) + '0'; | |
2777 | qstr[j++] = ((str[i] >> 3) & 7) + '0'; | |
2778 | qstr[j++] = (str[i] & 7) + '0'; | |
2779 | } | |
2780 | else { | |
2781 | qstr[j++] = str[i]; | |
2782 | } | |
2783 | } | |
2784 | ||
2785 | return qstr; | |
2786 | } | |
2787 | ||
2788 | ||
2789 | void write_cfile(FILE *f, list_t *hd) | |
2790 | { | |
2791 | hddb_data_t hddb = {}; | |
2792 | char *qstr; | |
2793 | unsigned u, qstr_len, len; | |
2794 | ||
2795 | fprintf(logfh, "- building C version\n"); | |
2796 | fflush(logfh); | |
2797 | ||
2798 | hddb_init(&hddb, hd); | |
2799 | ||
2800 | fprintf(logfh, " db size: %u bytes\n", | |
2801 | (unsigned) (sizeof hddb + | |
2802 | hddb.strings_len + | |
2803 | hddb.ids_len * sizeof *hddb.ids + | |
2804 | hddb.list_len * sizeof *hddb.list) | |
2805 | ); | |
2806 | ||
2807 | fprintf(f, | |
2808 | "static hddb_list_t hddb_internal_list[];\n" | |
2809 | "static unsigned hddb_internal_ids[];\n" | |
2810 | "static char hddb_internal_strings[];\n\n" | |
2811 | "hddb2_data_t hddb_internal = {\n" | |
2812 | " %u, %u, hddb_internal_list,\n" | |
2813 | " %u, %u, hddb_internal_ids,\n" | |
2814 | " %u, %u, hddb_internal_strings\n" | |
2815 | "};\n\n", | |
2816 | hddb.list_len, hddb.list_len, | |
2817 | hddb.ids_len, hddb.ids_len, | |
2818 | hddb.strings_len, hddb.strings_len | |
2819 | ); | |
2820 | ||
2821 | fprintf(f, "static hddb_list_t hddb_internal_list[%u] = {\n", hddb.list_len); | |
2822 | for(u = 0; u < hddb.list_len; u++) { | |
2823 | fprintf(f, | |
2824 | " { 0x%08x, 0x%08x, 0x%08x, 0x%08x }%s\n", | |
2825 | hddb.list[u].key_mask, hddb.list[u].value_mask, | |
2826 | hddb.list[u].key, hddb.list[u].value, | |
2827 | u + 1 == hddb.list_len ? "" : "," | |
2828 | ); | |
2829 | } | |
2830 | fprintf(f, "};\n\n"); | |
2831 | ||
2832 | fprintf(f, "static unsigned hddb_internal_ids[%u] = {\n", hddb.ids_len); | |
2833 | for(u = 0; u < hddb.ids_len; u++) { | |
2834 | if((u % 6) == 0) fputc(' ', f); | |
2835 | fprintf(f, " 0x%08x", hddb.ids[u]); | |
2836 | if(u + 1 != hddb.ids_len) fputc(',', f); | |
2837 | if(u % 6 == 6 - 1 || u + 1 == hddb.ids_len) fputc('\n', f); | |
2838 | } | |
2839 | fprintf(f, "};\n\n"); | |
2840 | ||
2841 | qstr = quote_string(hddb.strings, hddb.strings_len); | |
2842 | qstr_len = qstr ? strlen(qstr) : 0; | |
2843 | fprintf(f, "static char hddb_internal_strings[%u] = \"\\\n", hddb.strings_len); | |
2844 | for(u = 0; u < qstr_len; ) { | |
2845 | len = qstr_len - u; | |
2846 | if(len > 72) len = 72; | |
2847 | while(len--) fputc(qstr[u++], f); | |
2848 | fprintf(f, "\\\n"); | |
2849 | } | |
2850 | fprintf(f, "\";\n\n"); | |
2851 | ||
2852 | free_mem(qstr); | |
2853 | ||
2854 | free_mem(hddb.list); | |
2855 | free_mem(hddb.ids); | |
2856 | free_mem(hddb.strings); | |
2857 | } | |
2858 | ||
2859 |