]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/hwinfo/src/ids/check_hd.c
Kleiner netter neuer Versuch.
[people/pmueller/ipfire-2.x.git] / src / hwinfo / src / ids / check_hd.c
CommitLineData
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
23typedef uint32_t hddb_entry_mask_t;
24
25typedef enum {
26 match_any, match_all
27} match_t;
28
29typedef enum {
30 pref_empty, pref_new, pref_and, pref_or, pref_add
31} prefix_t;
32
33typedef struct line_s {
34 prefix_t prefix;
35 hddb_entry_t key;
36 char *value;
37} line_t;
38
39typedef struct str_s {
40 struct str_s *next;
41 char *str;
42} str_t;
43
44typedef struct list_any_s {
45 struct list_any_s *next;
46} list_any_t;
47
48typedef struct {
49 void *first;
50 void *last;
51} list_t;
52
53typedef struct {
54 unsigned flag;
55 unsigned remove;
56} hid_any_t;
57
58typedef 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
71typedef struct {
72 unsigned flag;
73 unsigned remove;
74 list_t list;
75} hid_str_t;
76
77typedef union {
78 hid_any_t any;
79 hid_num_t num;
80 hid_str_t str;
81} hid_t;
82
83typedef struct skey_s {
84 struct skey_s *next;
85 hid_t *hid[he_nomask];
86} skey_t;
87
88typedef 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
97typedef 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
104typedef 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
116void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);
117#endif
118void *new_mem(size_t size);
119void *free_mem(void *ptr);
120char *new_str(char *str);
121void *add_list(list_t *list, void *entry);
122void sort_list(list_t *list, int (*cmp_func)(const void *, const void *));
123unsigned eisa_id(char *s);
124char *eisa_str(unsigned id);
125void write_stats(FILE *f);
126
127void read_items(char *file);
128line_t *parse_line(char *str);
129hddb_entry_mask_t add_entry(skey_t *skey, hddb_entry_t idx, char *val);
130
131void write_items(char *file, list_t *hd);
132void write_item(FILE *f, item_t *item);
133void write_skey(FILE *f, prefix_t pre, skey_t *skey);
134void write_ent_name(FILE *f, hid_t *hid, char pre, hddb_entry_t ent);
135void write_id(FILE *f, hddb_entry_t ent, hid_t *hid);
136void write_drv(FILE *f, char pre, hid_t *hid);
137void write_drv1(FILE *f, hid_t *hid, char pre, char *val);
138void log_items(FILE *f, item_t *item0, item_t *item1);
139
140int count_common_hids(skey_t *skey0, skey_t *skey1);
141int strip_skey(skey_t *skey0, skey_t *skey1, int do_it);
142void remove_deleted_hids(skey_t *skey);
143void undelete_hids(skey_t *skey);
144str_t *split(char del, char *s);
145char *join(char del, str_t *str);
146
147int cmp_driver_info(char *str0, char *str1);
148int cmp_str_s(const void *p0, const void *p1);
149int cmp_hid(hid_t *hid0, hid_t *hid1);
150int cmp_skey(skey_t *skey0, skey_t *skey1);
151int cmp_skey_s(const void *p0, const void *p1);
152int cmp_item(item_t *item0, item_t *item1);
153int cmp_item_s(const void *p0, const void *p1);
154
155int match_hid(hid_t *hid0, hid_t *hid1, match_t match);
156int match_skey(skey_t *skey0, skey_t *skey1, match_t match);
157int match_item(item_t *item0, item_t *item1, match_t match);
158
159int combine_keys(skey_t *skey0, skey_t *skey1);
160
161str_t *clone_str(str_t *str);
162hid_t *clone_hid(hid_t *hid);
163skey_t *clone_skey(skey_t *skey);
164item_t *clone_item(item_t *item);
165
166str_t *free_str(str_t *str, int follow_next);
167hid_t *free_hid(hid_t *hid);
168skey_t *free_skey(skey_t *skey, int follow_next);
169item_t *free_item(item_t *item, int follow_next);
170
171unsigned driver_entry_types(hid_t *hid);
172
173void remove_items(list_t *hd);
174void remove_nops(list_t *hd);
175void check_items(list_t *hd);
176void split_items(list_t *hd);
177void combine_driver(list_t *hd);
178void combine_requires(list_t *hd);
179void join_items_by_value(list_t *hd);
180void join_items_by_key(list_t *hd);
181void remove_unimportant_items(list_t *hd);
182
183void write_cfile(FILE *f, list_t *hd);
184
185
186/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
187struct 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
206list_t hd;
207
208char *item_ind = NULL;
209FILE *logfh = NULL;
210
211struct {
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
231struct {
232 unsigned items_in, items_out;
233 unsigned diffs, errors, errors_res;
234} stats;
235
236
237/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
238int 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/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
443void *new_mem(size_t size)
444{
445 if(size == 0) return NULL;
446
447 return calloc(size, 1);
448}
449
450
451void *free_mem(void *ptr)
452{
453 if(ptr) free(ptr);
454
455 return NULL;
456}
457
458
459char *new_str(char *str)
460{
461 if(!str) return NULL;
462
463 return strdup(str);
464}
465
466
467void *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
482void 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
513unsigned 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
528char *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
541void 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/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
553void 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
682line_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
757int 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
821hddb_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/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
975void 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
1003void 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
1017void 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
1045void 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
1075void 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
1134void 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
1155void 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
1211void 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 */
1231int 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 */
1259int 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 */
1285void 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 */
1300void 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
1310str_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
1332char *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 */
1362int 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 */
1411int 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
1422int 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
1484int 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 */
1527int 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
1538int 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 */
1559int 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 */
1590int 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 */
1722int 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 */
1741int 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/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1762int 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/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1813str_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
1826hid_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
1848skey_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
1865item_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/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1887str_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
1904hid_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
1917skey_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
1938item_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/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1960unsigned 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/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1987void 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
2010void 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
2026void 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
2065void 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
2240void 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
2351void 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
2442void 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
2489void 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
2526void 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 */
2566unsigned 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
2585void 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
2599unsigned 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
2632unsigned 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
2645unsigned 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
2685void 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
2723void 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
2736void 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
2752unsigned 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
2789void 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