1 #define _GNU_SOURCE /* memmem */
11 #include "../hd/hddb_int.h"
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 */
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))
23 typedef uint32_t hddb_entry_mask_t
;
30 pref_empty
, pref_new
, pref_and
, pref_or
, pref_add
33 typedef struct line_s
{
39 typedef struct str_s
{
44 typedef struct list_any_s
{
45 struct list_any_s
*next
;
83 typedef struct skey_s
{
85 hid_t
*hid
[he_nomask
];
88 typedef struct item_s
{
92 list_t key
; /* skey_t */
97 typedef struct hddb_list_s
{
98 hddb_entry_mask_t key_mask
;
99 hddb_entry_mask_t value_mask
;
105 unsigned list_len
, list_max
;
107 unsigned ids_len
, ids_max
;
109 unsigned strings_len
, strings_max
;
114 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
116 void *memmem(const void *haystack
, size_t haystacklen
, const void *needle
, size_t needlelen
);
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
);
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
);
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
);
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
);
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
);
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
);
159 int combine_keys(skey_t
*skey0
, skey_t
*skey1
);
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
);
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
);
171 unsigned driver_entry_types(hid_t
*hid
);
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
);
183 void write_cfile(FILE *f
, list_t
*hd
);
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},
208 char *item_ind
= NULL
;
217 unsigned with_source
:1;
220 unsigned no_compact
:1;
221 unsigned join_keys_first
:1;
222 unsigned combine
:1; /* always combine driver info */
232 unsigned items_in
, items_out
;
233 unsigned diffs
, errors
, errors_res
;
237 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
238 int main(int argc
, char **argv
)
240 int i
, close_log
= 0, close_cfile
= 0;
244 for(opterr
= 0; (i
= getopt_long(argc
, argv
, "", options
, NULL
)) != -1; ) {
248 opt
.debug
= strtol(optarg
, NULL
, 0);
253 opt
.logfile
= optarg
;
254 if(!*opt
.logfile
) opt
.logfile
= NULL
;
283 opt
.outfile
= optarg
;
284 if(!*opt
.outfile
) opt
.outfile
= NULL
;
293 if(!*opt
.cfile
) opt
.cfile
= NULL
;
301 opt
.join_keys_first
= 1;
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"
331 if(opt
.logfile
&& strcmp(opt
.logfile
, "-")) {
332 logfh
= fopen(opt
.logfile
, "w");
343 for(argv
+= optind
; *argv
; argv
++) {
347 for(item
= hd
.first
; item
; item
= item
->next
) stats
.items_in
++;
349 fprintf(logfh
, "- removing useless entries\n");
354 fprintf(logfh
, "- building mini version\n");
356 remove_unimportant_items(&hd
);
359 if(opt
.check
|| opt
.split
) {
360 fprintf(logfh
, "- splitting entries\n");
366 fprintf(logfh
, "- combining driver info\n");
370 fprintf(logfh
, "- combining requires info\n");
372 combine_requires(&hd
);
374 fprintf(logfh
, "- checking for consistency\n");
378 fprintf(logfh
, "- join items\n");
380 if(opt
.join_keys_first
) {
381 join_items_by_key(&hd
);
382 join_items_by_value(&hd
);
385 join_items_by_value(&hd
);
386 join_items_by_key(&hd
);
389 if(opt
.split
) split_items(&hd
);
393 fprintf(logfh
, "- sorting\n");
395 sort_list(&hd
, cmp_item_s
);
398 for(item
= hd
.first
; item
; item
= item
->next
) stats
.items_out
++;
400 write_items(opt
.outfile
, &hd
);
403 if(opt
.cfile
&& strcmp(opt
.cfile
, "-")) {
404 cfile
= fopen(opt
.cfile
, "w");
417 write_cfile(cfile
, &hd
);
419 if(close_cfile
) fclose(cfile
);
422 fprintf(logfh
, "- statistics\n");
424 if(logfh
!= stdout
) {
425 if(opt
.outfile
&& strcmp(opt
.outfile
, "-")) {
426 fprintf(stderr
, "data written to \"%s\"\n", opt
.outfile
);
428 if(opt
.logfile
&& strcmp(opt
.logfile
, "-")) {
429 fprintf(stderr
, "log written to \"%s\"\n", opt
.logfile
);
431 fprintf(stderr
, "statistics:\n");
435 free_item(hd
.first
, 1);
437 if(close_log
) fclose(logfh
);
442 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
443 void *new_mem(size_t size
)
445 if(size
== 0) return NULL
;
447 return calloc(size
, 1);
451 void *free_mem(void *ptr
)
459 char *new_str(char *str
)
461 if(!str
) return NULL
;
467 void *add_list(list_t
*list
, void *entry
)
470 ((list_any_t
*) list
->last
)->next
= entry
;
482 void sort_list(list_t
*list
, int (*cmp_func
)(const void *, const void *))
485 list_any_t
*list_entry
;
486 list_t new_list
= {};
487 list_any_t
**list_array
;
489 for(list_entry
= list
->first
; list_entry
; list_entry
= list_entry
->next
) list_len
++;
490 if(list_len
< 2) return;
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
;
497 qsort(list_array
, list_len
, sizeof *list_array
, cmp_func
);
499 for(i
= 0; i
< list_len
; i
++) {
500 add_list(&new_list
, list_array
[i
]);
504 ((list_any_t
*) new_list
.last
)->next
= NULL
;
509 free_mem(list_array
);
513 unsigned eisa_id(char *s
)
518 for(i
= 0; i
< 3; i
++) {
520 if(s
[i
] < 'A' - 1 || s
[i
] > 'A' - 1 + 0x1f) return 0;
524 return MAKE_ID(TAG_EISA
, u
);
528 char *eisa_str(unsigned id
)
532 s
[0] = ((id
>> 10) & 0x1f) + 'A' - 1;
533 s
[1] = ((id
>> 5) & 0x1f) + 'A' - 1;
534 s
[2] = ( id
& 0x1f) + 'A' - 1;
541 void write_stats(FILE *f
)
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
);
547 fprintf(f
, " %u items in\n", stats
.items_in
);
548 fprintf(f
, " %u items out\n", stats
.items_out
);
552 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
553 void read_items(char *file
)
556 char buf
[1024], fpos
[256];
557 unsigned u
, state
, l_nr
;
558 hddb_entry_mask_t entry_mask
= 0;
563 if(!(f
= fopen(file
, "r"))) {
568 item
= new_mem(sizeof *item
);
569 skey
= new_mem(sizeof *skey
);
571 sprintf(fpos
, "%s(1)", file
);
572 item
->pos
= new_str(fpos
);
574 for(l_nr
= 1, state
= 0; fgets(buf
, sizeof buf
, f
); l_nr
++) {
577 fprintf(stderr
, "%s: invalid line\n", fpos
);
581 if(l
->prefix
== pref_empty
) continue;
585 add_list(&item
->key
, skey
);
586 skey
= new_mem(sizeof *skey
);
588 else if(state
== 2) {
590 skey
= new_mem(sizeof *skey
);
592 if(state
== 2 || state
== 1) {
594 item
= new_mem(sizeof *item
);
596 sprintf(fpos
, "%s(%d)", file
, l_nr
);
597 item
->pos
= new_str(fpos
);
606 fprintf(stderr
, "%s: must start item first\n", fpos
);
613 if(state
!= 1 || !entry_mask
) {
614 fprintf(stderr
, "%s: must start item first\n", fpos
);
618 add_list(&item
->key
, skey
);
619 skey
= new_mem(sizeof *skey
);
624 if(state
== 1 && !entry_mask
) {
625 fprintf(stderr
, "%s: driver info not allowed\n", fpos
);
630 add_list(&item
->key
, skey
);
631 skey
= new_mem(sizeof *skey
);
636 fprintf(stderr
, "%s: driver info not allowed\n", fpos
);
647 u
= add_entry(skey
, l
->key
, l
->value
);
652 fprintf(stderr
, "%s: invalid info\n", fpos
);
657 if(state
== 4) break; /* error */
661 /* finalize last item */
662 if(entry_mask
&& (state
== 1 || state
== 2)) {
664 add_list(&item
->key
, skey
);
667 else if(state
== 2) {
682 line_t
*parse_line(char *str
)
688 /* drop leading spaces */
689 while(isspace(*str
)) str
++;
691 /* skip emtpy lines and comments */
692 if(!*str
|| *str
== ';' || *str
== '#') {
693 l
.prefix
= pref_empty
;
717 while(isspace(*str
)) str
++;
720 while(*str
&& !isspace(*str
)) str
++;
722 while(isspace(*str
)) str
++;
724 for(i
= 0; (unsigned) i
< sizeof hddb_entry_strings
/ sizeof *hddb_entry_strings
; i
++) {
725 if(!strcmp(s
, hddb_entry_strings
[i
])) {
731 if((unsigned) i
>= sizeof hddb_entry_strings
/ sizeof *hddb_entry_strings
) return NULL
;
735 /* drop trailing white space */
738 if(isspace(str
[i
- 1]))
744 /* special case: drop leading and final double quotes, if any */
746 if(i
>= 2 && l
.value
[0] == '"' && l
.value
[i
- 1] == '"') {
751 // fprintf(stderr, "pre = %d, key = %d, val = \"%s\"\n", l.prefix, l.key, l.value);
757 int parse_id(char *str
, unsigned *id
, unsigned *tag
, unsigned *range
, unsigned *mask
)
759 static unsigned id0
, val
;
760 char c
= 0, *s
, *t
= NULL
;
762 *id
= *tag
= *range
= *mask
= 0;
764 if(!str
|| !*str
) return 0;
766 for(s
= str
; *str
&& !isspace(*str
); str
++);
768 c
= *(t
= str
); /* remember for later */
771 while(isspace(*str
)) str
++;
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
;
782 if(t
) *t
= c
; /* restore */
786 id0
= strtoul(str
, &s
, 0);
793 if(!*tag
) *tag
= TAG_EISA
;
796 while(isspace(*s
)) s
++;
797 if(*s
&& *s
!= '&' && *s
!= '+') return 0;
805 while(isspace(*s
)) s
++;
807 val
= strtoul(s
, &str
, 0);
809 if(s
== str
) return 0;
811 while(isspace(*str
)) str
++;
815 if(c
== '+') *range
= val
; else *mask
= val
;
817 return c
== '+' ? 2 : 3;
821 hddb_entry_mask_t
add_entry(skey_t
*skey
, hddb_entry_t idx
, char *val
)
823 hddb_entry_mask_t e_mask
= 0;
825 unsigned id
, tag
, range
, mask
;
826 char *s
, *s1
, *s2
, c
;
830 for(i
= 0; (unsigned) i
< sizeof hddb_is_numeric
/ sizeof *hddb_is_numeric
; i
++) {
831 if(idx
== hddb_is_numeric
[i
]) break;
834 // printf("i = %d, idx = %d, val = >%s<\n", i, idx, val);
836 if((unsigned) i
< sizeof hddb_is_numeric
/ sizeof *hddb_is_numeric
) {
840 i
= parse_id(val
, &id
, &tag
, &range
, &mask
);
842 // printf("parse_id = %d\n", i);
845 skey
->hid
[idx
] = hid
= new_mem(sizeof *hid
);
846 hid
->num
.flag
= FLAG_ID
;
859 hid
->num
.range
= range
;
860 hid
->num
.has
.range
= 1;
864 hid
->num
.mask
= mask
;
865 hid
->num
.has
.mask
= 1;
873 if(idx
< he_nomask
) {
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
);
885 if(idx
== he_class_id
) {
886 i
= parse_id(val
, &id
, &tag
, &range
, &mask
);
889 skey
->hid
[he_baseclass_id
] = hid
= new_mem(sizeof *hid
);
890 hid
->num
.flag
= FLAG_ID
;
892 hid
->num
.id
= id
>> 8;
894 skey
->hid
[he_subclass_id
] = hid
= new_mem(sizeof *hid
);
895 hid
->num
.flag
= FLAG_ID
;
897 hid
->num
.id
= id
& 0xff;
899 e_mask
|= (1 << he_baseclass_id
) + (1 << he_subclass_id
) /* + (1 << he_progif_id) */;
903 case he_driver_module_insmod
:
907 case he_driver_module_modprobe
:
911 case he_driver_module_config
:
915 case he_driver_xfree
:
919 case he_driver_xfree_config
:
923 case he_driver_mouse
:
927 case he_driver_display
:
940 s
= new_mem(strlen(val
) + 3);
944 hid
= skey
->hid
[he_driver
];
946 skey
->hid
[he_driver
] = hid
= new_mem(sizeof *hid
);
947 hid
->str
.flag
= FLAG_STRING
;
950 (c
== 'X' || c
== 'M') &&
951 hid
->str
.list
.last
&&
952 (s1
= ((str_t
*) hid
->str
.list
.last
)->str
)
954 s2
= new_mem(strlen(s1
) + strlen(s
) + 2);
955 sprintf(s2
, "%s\001%s", s1
, s
);
957 ((str_t
*) hid
->str
.list
.last
)->str
= s2
;
960 str
= add_list(&hid
->str
.list
, new_mem(sizeof *str
));
961 str
->str
= new_str(s
);
963 e_mask
|= (1 << he_driver
);
974 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
975 void write_items(char *file
, list_t
*hd
)
981 if(file
&& strcmp(file
, "-")) {
982 f
= fopen(file
, "w");
993 for(item
= hd
->first
; item
; item
= item
->next
) {
994 if(opt
.with_source
) fprintf(f
, "# %s\n", item
->pos
);
999 if(close_it
) fclose(f
);
1003 void write_item(FILE *f
, item_t
*item
)
1009 for(skey
= item
->key
.first
; skey
; skey
= skey
->next
) {
1010 write_skey(f
, pre
, skey
);
1013 write_skey(f
, pref_add
, item
->value
);
1017 void write_skey(FILE *f
, prefix_t pre
, skey_t
*skey
)
1019 static char pref_char
[5] = { ' ', ' ', '&', '|', '+' };
1022 if(pre
>= sizeof pref_char
) {
1023 fprintf(stderr
, "internal oops\n");
1029 for(i
= 0; (unsigned) i
< sizeof skey
->hid
/ sizeof *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
]);
1037 write_drv(f
, pref_char
[pre
], skey
->hid
[i
]);
1039 if(pre
!= pref_add
) pre
= pref_and
;
1045 void write_ent_name(FILE *f
, hid_t
*hid
, char pre
, hddb_entry_t ent
)
1047 int len
, tab_ind
= 24;
1050 if(ent
>= sizeof hddb_entry_strings
/ sizeof *hddb_entry_strings
) {
1051 fprintf(stderr
, "internal oops\n");
1055 len
= item_ind
? strlen(item_ind
) : 0;
1058 fprintf(f
, "%c%s\t", pre
, hddb_entry_strings
[ent
]);
1061 c
= hid
->any
.remove
? '*' : ':';
1062 fprintf(f
, "%s%c %c%s\t", item_ind
, c
, pre
, hddb_entry_strings
[ent
]);
1067 len
+= strlen(hddb_entry_strings
[ent
]) + 1;
1069 for(len
= (len
& ~7) + 8; len
< tab_ind
; len
+= 8) {
1075 void write_id(FILE *f
, hddb_entry_t ent
, hid_t
*hid
)
1077 static char *tag_name
[6] = { "", "pci ", "eisa ", "usb ", "special ", "pcmcia " };
1082 switch(hid
->any
.flag
) {
1085 if((unsigned) tag
>= sizeof tag_name
/ sizeof *tag_name
) {
1086 fprintf(stderr
, "internal oops\n");
1089 if(tag
== TAG_EISA
&& (ent
== he_vendor_id
|| ent
== he_subvendor_id
)) {
1090 fprintf(f
, "%s", eisa_str(hid
->num
.id
));
1094 if(ent
== he_bus_id
|| ent
== he_subclass_id
|| ent
== he_progif_id
) {
1097 else if(ent
== he_baseclass_id
) {
1100 fprintf(f
, "%s0x%0*x", tag_name
[tag
], u
, hid
->num
.id
);
1102 if(hid
->num
.has
.range
|| hid
->num
.has
.mask
) {
1103 if(hid
->num
.has
.range
) {
1111 fprintf(f
, "%c0x%04x", c
, u
);
1116 if( /* not exactly 1 string */
1117 !hid
->str
.list
.first
||
1118 ((str_t
*) hid
->str
.list
.first
)->next
1120 fprintf(stderr
, "internal oops\n");
1123 fprintf(f
, "%s", ((str_t
*) hid
->str
.list
.first
)->str
);
1127 fprintf(stderr
, "internal oops\n");
1134 void write_drv(FILE *f
, char pre
, hid_t
*hid
)
1139 if(hid
->any
.flag
!= FLAG_STRING
) {
1140 fprintf(stderr
, "internal oops\n");
1144 for(str
= hid
->str
.list
.first
; str
; str
= str
->next
) {
1145 for(s
= str
->str
; (t
= strchr(s
, '\001')); s
= t
+ 1) {
1147 write_drv1(f
, hid
, pre
, s
);
1150 write_drv1(f
, hid
, pre
, s
);
1155 void write_drv1(FILE *f
, hid_t
*hid
, char pre
, char *val
)
1161 if(!type
|| val
[1] != '\t') {
1162 fprintf(stderr
, "internal oops\n");
1168 ent
= he_driver_xfree
;
1172 ent
= he_driver_xfree_config
;
1176 ent
= he_driver_module_insmod
;
1180 ent
= he_driver_module_modprobe
;
1184 ent
= he_driver_module_config
;
1188 ent
= he_driver_mouse
;
1192 ent
= he_driver_display
;
1196 ent
= he_driver_any
;
1200 fprintf(stderr
, "internal oops\n");
1205 write_ent_name(f
, hid
, pre
, ent
);
1206 fprintf(f
, "%s\n", val
+ 2);
1211 void log_items(FILE *f
, item_t
*item0
, item_t
*item1
)
1213 char *save_ind
= item_ind
;
1217 write_item(f
, item0
);
1222 write_item(f
, item1
);
1225 item_ind
= save_ind
;
1229 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1230 /* count common defined hid entries */
1231 int count_common_hids(skey_t
*skey0
, skey_t
*skey1
)
1235 if(!skey0
|| !skey1
) return 0;
1237 for(i
= 0; (unsigned) i
< sizeof skey0
->hid
/ sizeof *skey0
->hid
; i
++) {
1238 if(skey0
->hid
[i
] && skey1
->hid
[i
]) cnt
++;
1246 * remove hid entries from skey0 that are defined in skey1
1249 * 0: don't remove anything, just count
1250 * 1: remove identical entries
1251 * 2: remove differing entries
1252 * 3: both of the above
1255 * bits 0- 7: identical entries
1256 * 8-15: different entries
1257 * 16-23: critical conflicts
1259 int strip_skey(skey_t
*skey0
, skey_t
*skey1
, int do_it
)
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
])) {
1267 if(i
== he_driver
|| i
== he_requires
) {
1270 if((do_it
& 2)) skey0
->hid
[i
]->any
.remove
= 1;
1274 if((do_it
& 1)) skey0
->hid
[i
]->any
.remove
= 1;
1283 * remove deleted hid entries from skey
1285 void remove_deleted_hids(skey_t
*skey
)
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
]);
1298 * undeleted hid entries from skey
1300 void undelete_hids(skey_t
*skey
)
1304 for(i
= 0; (unsigned) i
< sizeof skey
->hid
/ sizeof *skey
->hid
; i
++) {
1305 if(skey
->hid
[i
]) skey
->hid
[i
]->any
.remove
= 0;
1310 str_t
*split(char del
, char *s
)
1318 for(s0
= s
= new_str(s
); (t
= strchr(s
, del
)); s
= t
+ 1) {
1320 str
= add_list(&list
, new_mem(sizeof *str
));
1321 str
->str
= new_str(s
);
1323 str
= add_list(&list
, new_mem(sizeof *str
));
1324 str
->str
= new_str(s
);
1332 char *join(char del
, str_t
*str
)
1338 for(str0
= str
; str0
; str0
= str0
->next
) {
1339 len
+= strlen(str0
->str
) + 1;
1342 if(!len
) return NULL
;
1346 t
[0] = del
; t
[1] = 0;
1348 for(; str
; str
= str
->next
) {
1349 strcat(s
, str
->str
);
1350 if(str
->next
) strcat(s
, t
);
1357 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1360 * str0 & str1 _must_ hold valid driver info
1362 int cmp_driver_info(char *str0
, char *str1
)
1366 int _3d0
, _3d1
, res
;
1371 if(type0
== 'a' || type1
== 'a') {
1372 if(type0
== 'a' && type1
== 'a') return 0;
1373 if(type0
== 'a') return 1;
1377 if(type0
!= 'x' || type1
!= 'x') return 0;
1382 sl0
= split('|', str0
);
1383 sl1
= split('|', str1
);
1389 /* xfree v4 first, then xfree v3 */
1390 if(*sl0
->str
!= *sl1
->str
) res
= *sl0
->str
< *sl1
->str
? 1 : -1;
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;
1398 /* entries without 3d support first */
1410 /* wrapper for qsort */
1411 int cmp_str_s(const void *p0
, const void *p1
)
1413 str_t
**str0
, **str1
;
1415 str0
= (str_t
**) p0
;
1416 str1
= (str_t
**) p1
;
1418 return strcmp((*str0
)->str
, (*str1
)->str
);
1422 int cmp_hid(hid_t
*hid0
, hid_t
*hid1
)
1427 if(!hid0
&& !hid1
) return 0;
1428 if(!hid0
) return -1;
1431 if(hid0
->any
.flag
!= hid1
->any
.flag
) {
1432 return hid0
->any
.flag
< hid1
->any
.flag
? -1 : 1;
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
);
1446 if(str0
) i
= 1; else if(str1
) i
= -1;
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;
1453 else if(hid0
->num
.id
!= hid1
->num
.id
) {
1454 i
= hid0
->num
.id
< hid1
->num
.id
? -1 : 1;
1456 else if(hid0
->num
.has
.range
|| hid1
->num
.has
.range
) {
1457 if(!hid0
->num
.has
.range
) {
1460 else if(!hid1
->num
.has
.range
) {
1463 else if(hid0
->num
.range
!= hid1
->num
.range
) {
1464 i
= hid0
->num
.range
< hid1
->num
.range
? -1 : 1;
1467 else if(hid0
->num
.has
.mask
|| hid1
->num
.has
.mask
) {
1468 if(!hid0
->num
.has
.mask
) {
1471 else if(!hid1
->num
.has
.mask
) {
1474 else if(hid0
->num
.mask
!= hid1
->num
.mask
) {
1475 i
= hid0
->num
.mask
< hid1
->num
.mask
? -1 : 1;
1484 int cmp_skey(skey_t
*skey0
, skey_t
*skey1
)
1486 int i
, j
, len0
, len1
, len
;
1488 if(!skey0
&& !skey1
) return 0;
1489 if(!skey0
) return -1;
1490 if(!skey1
) return 1;
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
;
1499 // printf("len0 = %d, len1 = %d\n", len0, len1);
1501 len
= len0
< len1
? len0
: len1
;
1503 for(i
= j
= 0; j
< len
; j
++) {
1504 // printf("0: j = %d\n", j);
1506 if(!skey0
->hid
[j
] && !skey1
->hid
[j
]) continue;
1508 /* note: this looks reversed, but is intentional! */
1509 if(!skey0
->hid
[j
]) { i
= 1; break; }
1510 if(!skey1
->hid
[j
]) { i
= -1; break; }
1512 i
= cmp_hid(skey0
->hid
[j
], skey1
->hid
[j
]);
1513 // printf("1: j = %d, i = %d\n", j, i);
1518 if(!i
&& len0
!= len1
) {
1519 i
= len0
> len1
? 1 : -1;
1526 /* wrapper for qsort */
1527 int cmp_skey_s(const void *p0
, const void *p1
)
1529 skey_t
**skey0
, **skey1
;
1531 skey0
= (skey_t
**) p0
;
1532 skey1
= (skey_t
**) p1
;
1534 return cmp_skey(*skey0
, *skey1
);
1538 int cmp_item(item_t
*item0
, item_t
*item1
)
1541 skey_t
*skey0
, *skey1
;
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;
1548 if(!i
) i
= cmp_skey(skey0
, skey1
);
1550 if(!i
) i
= 2 * cmp_skey(item0
->value
, item1
->value
);
1552 // printf("%s -- %s : %d\n", item0->pos, item1->pos, i);
1558 /* wrapper for qsort */
1559 int cmp_item_s(const void *p0
, const void *p1
)
1562 item_t
**item0
, **item1
;
1564 item0
= (item_t
**) p0
;
1565 item1
= (item_t
**) p1
;
1568 i
= ((rand() / 317) % 3) - 1;
1570 else if(opt
.reverse
) {
1571 i
= cmp_item(*item1
, *item0
);
1574 i
= cmp_item(*item0
, *item1
);
1581 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1583 * Does hid1 match if hid0 does?
1584 * > 0: yes, 0: no, < 0: maybe
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))
1590 int match_hid(hid_t
*hid0
, hid_t
*hid1
, match_t match
)
1598 if(hid0
->any
.flag
!= hid1
->any
.flag
) return 0;
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
);
1607 m
= str0
|| str1
? 0 : 1;
1609 else if(hid0
->any
.flag
== FLAG_ID
) {
1610 if(hid0
->num
.tag
!= hid1
->num
.tag
) return 0;
1612 if(match
== match_any
) {
1614 if(hid0
->num
.has
.range
) {
1615 if(hid1
->num
.has
.range
) {
1618 hid1
->num
.id
>= hid0
->num
.id
&&
1619 hid1
->num
.id
< hid0
->num
.id
+ hid0
->num
.range
1622 hid0
->num
.id
>= hid1
->num
.id
&&
1623 hid0
->num
.id
< hid1
->num
.id
+ hid1
->num
.range
1627 else if(hid1
->num
.has
.mask
) {
1633 hid1
->num
.id
>= hid0
->num
.id
&&
1634 hid1
->num
.id
< hid0
->num
.id
+ hid0
->num
.range
1638 else if(hid0
->num
.has
.mask
) {
1639 if(hid1
->num
.has
.range
) {
1642 else if(hid1
->num
.has
.mask
) {
1646 m
= (hid1
->num
.id
& ~hid0
->num
.mask
) == hid0
->num
.id
? 1 : 0;
1650 if(hid1
->num
.has
.range
) {
1653 hid0
->num
.id
>= hid1
->num
.id
&&
1654 hid0
->num
.id
< hid1
->num
.id
+ hid1
->num
.range
1657 else if(hid1
->num
.has
.mask
) {
1658 m
= (hid0
->num
.id
& ~hid1
->num
.mask
) == hid1
->num
.id
? 1 : 0;
1661 m
= hid0
->num
.id
== hid1
->num
.id
? 1 : 0;
1666 else { /* match_all */
1668 if(hid0
->num
.has
.range
) {
1669 if(hid1
->num
.has
.range
) {
1672 hid0
->num
.id
>= hid1
->num
.id
&&
1673 hid0
->num
.id
+ hid0
->num
.range
<= hid1
->num
.id
+ hid1
->num
.range
1675 // fprintf(logfh, "id0 = 0x%x, id1 = 0x%x, m = %d\n", hid0->num.id, hid1->num.id, m);
1677 else if(hid1
->num
.has
.mask
) {
1681 m
= hid1
->num
.id
== hid0
->num
.id
&& hid0
->num
.range
== 1 ? 1 : 0;
1684 else if(hid0
->num
.has
.mask
) {
1685 if(hid1
->num
.has
.range
) {
1688 else if(hid1
->num
.has
.mask
) {
1692 m
= (hid1
->num
.id
& ~hid0
->num
.mask
) == hid0
->num
.id
&& hid0
->num
.mask
== 0 ? 1 : 0;
1696 if(hid1
->num
.has
.range
) {
1699 hid0
->num
.id
>= hid1
->num
.id
&&
1700 hid0
->num
.id
< hid1
->num
.id
+ hid1
->num
.range
1703 else if(hid1
->num
.has
.mask
) {
1704 m
= (hid0
->num
.id
& ~hid1
->num
.mask
) == hid1
->num
.id
? 1 : 0;
1707 m
= hid0
->num
.id
== hid1
->num
.id
? 1 : 0;
1719 * Does skey1 match if skey0 does?
1720 * > 0: yes, 0: no, < 0: maybe
1722 int match_skey(skey_t
*skey0
, skey_t
*skey1
, match_t match
)
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
);
1738 * Does item1 match if item0 does?
1739 * > 0: yes, 0: no, < 0: maybe
1741 int match_item(item_t
*item0
, item_t
*item1
, match_t match
)
1744 skey_t
*skey0
, *skey1
;
1746 skey0
= item0
->key
.first
;
1747 skey1
= item1
->key
.first
;
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
);
1761 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1762 int combine_keys(skey_t
*skey0
, skey_t
*skey1
)
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;
1776 if(ind
< 0) return 0;
1778 /* ok, exactly one hid differs */
1779 hid0
= skey0
->hid
[ind
];
1780 hid1
= skey1
->hid
[ind
];
1782 /* must be numerical */
1783 if(hid0
->any
.flag
!= FLAG_ID
|| hid1
->any
.flag
!= FLAG_ID
) return 0;
1786 if(hid0
->num
.has
.mask
|| hid1
->num
.has
.mask
) return 0;
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;
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
;
1796 hid0
->num
.range
= i
;
1797 hid0
->num
.has
.range
= 1;
1800 hid0
->num
.range
= 0;
1801 hid0
->num
.has
.range
= 0;
1812 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1813 str_t
*clone_str(str_t
*str
)
1817 if(!str
) return NULL
;
1819 n_str
= new_mem(sizeof *n_str
);
1820 n_str
->str
= new_str(str
->str
);
1826 hid_t
*clone_hid(hid_t
*hid
)
1831 if(!hid
) return NULL
;
1833 new_hid
= new_mem(sizeof *new_hid
);
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
));
1848 skey_t
*clone_skey(skey_t
*skey
)
1853 if(!skey
) return NULL
;
1855 new_skey
= new_mem(sizeof *new_skey
);
1857 for(i
= 0; (unsigned) i
< sizeof skey
->hid
/ sizeof *skey
->hid
; i
++) {
1858 new_skey
->hid
[i
] = clone_hid(skey
->hid
[i
]);
1865 item_t
*clone_item(item_t
*item
)
1870 if(!item
) return NULL
;
1872 new_item
= new_mem(sizeof *new_item
);
1874 new_item
->pos
= new_str(item
->pos
);
1876 for(skey
= item
->key
.first
; skey
; skey
= skey
->next
) {
1877 add_list(&new_item
->key
, clone_skey(skey
));
1880 new_item
->value
= clone_skey(item
->value
);
1886 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1887 str_t
*free_str(str_t
*str
, int follow_next
)
1891 for(; str
; str
= next
) {
1897 if(!follow_next
) break;
1904 hid_t
*free_hid(hid_t
*hid
)
1906 if(!hid
) return NULL
;
1908 if(hid
->any
.flag
== FLAG_STRING
) {
1909 free_str(hid
->str
.list
.first
, 1);
1917 skey_t
*free_skey(skey_t
*skey
, int follow_next
)
1922 for(; skey
; skey
= next
) {
1925 for(i
= 0; (unsigned) i
< sizeof skey
->hid
/ sizeof *skey
->hid
; i
++) {
1926 free_hid(skey
->hid
[i
]);
1931 if(!follow_next
) break;
1938 item_t
*free_item(item_t
*item
, int follow_next
)
1942 for(; item
; item
= next
) {
1945 free_mem(item
->pos
);
1947 free_skey(item
->key
.first
, 1);
1948 free_skey(item
->value
, 0);
1952 if(!follow_next
) break;
1959 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1960 unsigned driver_entry_types(hid_t
*hid
)
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]) {
1986 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1987 void remove_items(list_t
*hd
)
1989 item_t
*item
, *next
;
1992 for(item
= hd
->first
; item
; item
= next
) {
1998 add_list(&hd_new
, item
);
2003 ((list_any_t
*) hd_new
.last
)->next
= NULL
;
2010 void remove_nops(list_t
*hd
)
2015 for(item
= hd
->first
; item
; item
= item
->next
) {
2016 if(!item
->value
|| !item
->key
.first
) {
2022 if(cnt
) remove_items(hd
);
2026 void split_items(list_t
*hd
)
2028 item_t
*item
, *new_item
, *next_item
;
2029 skey_t
*skey
, *next
;
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
) {
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
);
2047 new_item
->value
= clone_skey(item
->value
);
2048 add_list(&new_item
->key
, clone_skey(skey
));
2053 add_list(&hd_new
, item
);
2058 ((list_any_t
*) hd_new
.last
)->next
= NULL
;
2065 void check_items(list_t
*hd
)
2067 int i
, j
, k
, m
, mr
, m_all
, mr_all
, c_ident
, c_diff
, c_crit
;
2069 item_t
*item0
, *item1
, *item_a
, *item_b
;
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;
2077 item_a
= item0
; item_b
= item1
;
2079 m
= match_item(item0
, item1
, match_any
);
2080 mr
= match_item(item1
, item0
, match_any
);
2085 m_all
= match_item(item0
, item1
, match_all
);
2086 mr_all
= match_item(item1
, item0
, match_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
;
2094 item_a
= item1
; item_b
= item0
;
2099 m_all
= match_item(item_a
, item_b
, match_all
);
2100 mr_all
= match_item(item_b
, item_a
, match_all
);
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
2114 * item_b matches (at least) everything that item_a does
2115 * (item_a is a special case of item_b)
2118 i
= cmp_item(item_a
, item_b
); /* just informational */
2120 /* identical keys and values */
2122 "%s: duplicate of %s, item removed\n",
2123 item_a
->pos
, item_b
->pos
2128 /* matching keys, differing values */
2130 j
= count_common_hids(item_a
->key
.first
, item_b
->key
.first
);
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
)
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
2141 j
= strip_skey(item_a
->value
, item_b
->value
, 1);
2144 c_diff
= (j
>> 8) & 0xff;
2145 if(c_diff
&& c_ident
) {
2147 "%s: some info identical to %s, identical info removed\n",
2148 item_a
->pos
, item_b
->pos
2150 log_items(logfh
, item_a
, item_b
);
2154 "%s: info is identical to %s, info removed\n",
2155 item_a
->pos
, item_b
->pos
2157 log_items(logfh
, item_a
, item_b
);
2159 remove_deleted_hids(item_a
->value
);
2163 j
= strip_skey(item_a
->value
, item_b
->value
, 3);
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
;
2174 stat_cnt
= &stats
.diffs
;
2177 * if the keys are identical, make it a warning,
2178 * else make it an error
2180 if(c_diff
&& !c_ident
) {
2183 "%s: info %s %s, info removed\n",
2184 item_a
->pos
, s
, item_b
->pos
2187 else if(c_diff
&& c_ident
) {
2190 "%s: info %s/is identical to %s, info removed\n",
2191 item_a
->pos
, s
, item_b
->pos
2196 "%s: info is identical to %s, info removed\n",
2197 item_a
->pos
, item_b
->pos
2200 log_items(logfh
, item_a
, item_b
);
2201 remove_deleted_hids(item_a
->value
);
2205 if(!count_common_hids(item_a
->value
, item_a
->value
)) {
2206 /* remove if no values left */
2208 fprintf(logfh
, "%s: no info left, item removed\n", item_a
->pos
);
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
);
2217 /* differing keys, differing values */
2218 j
= strip_skey(item_b
->value
, item_a
->value
, 2);
2219 c_diff
= (j
>> 8) & 0xff;
2221 /* different keys, conflicting values --> error */
2224 "%s: info conflicts with %s\n",
2225 item_b
->pos
, item_a
->pos
2227 log_items(logfh
, item_b
, item_a
);
2229 undelete_hids(item_b
->value
);
2240 void combine_driver(list_t
*hd
)
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
;
2248 for(item0
= hd
->first
; item0
; item0
= item0
->next
) {
2252 !(hid0
= item0
->value
->hid
[he_driver
]) ||
2253 hid0
->any
.flag
!= FLAG_STRING
2255 for(item1
= item0
->next
; item1
&& !item0
->remove
; item1
= item1
->next
) {
2256 hid0
= item0
->value
->hid
[he_driver
];
2260 !(hid1
= item1
->value
->hid
[he_driver
]) ||
2261 hid1
->any
.flag
!= FLAG_STRING
2264 i
= cmp_item(item0
, item1
);
2266 /* remove duplicate entries */
2272 /* work only on entries with identical keys */
2273 if(i
== -1 || i
== 1) continue;
2275 /* ensure these are proper driver entries */
2276 if(!(type0
= driver_entry_types(hid0
))) continue;
2277 if(!(type1
= driver_entry_types(hid1
))) continue;
2280 * Allow only (x11 + x11) & (!any + any)
2281 * unless --combine option was used.
2283 if(!opt
.combine
&& (((type0
& type1
) & 5) || ((type0
| type1
) & 6) == 6)) {
2285 "%s: can't combine driver info with %s %d %d\n",
2286 item0
->pos
, item1
->pos
, type0
, type1
2288 log_items(logfh
, item0
, item1
);
2304 fprintf(logfh
, "%s: combine with %s\n", item_a
->pos
, item_b
->pos
);
2305 log_items(logfh
, item_a
, item_b
);
2307 new_hid
= clone_hid(hid_a
);
2309 for(str1
= hid_b
->str
.list
.first
; str1
; str1
= str1
->next
) {
2311 for(str0
= new_hid
->str
.list
.first
; str0
; last_str
= str0
, str0
= str0
->next
) {
2312 i
= cmp_driver_info(str1
->str
, str0
->str
);
2316 tmp_str
= last_str
->next
;
2317 last_str
->next
= clone_str(str1
);
2318 last_str
->next
->next
= tmp_str
;
2320 new_hid
->str
.list
.last
= last_str
->next
;
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
;
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
]);
2335 fprintf(logfh
, " --\n");
2336 log_items(logfh
, item_a
, item_b
);
2338 if(!count_common_hids(item_b
->value
, item_b
->value
)) {
2339 /* remove if no values left */
2341 fprintf(logfh
, "%s: no info left, item removed\n", item_b
->pos
);
2351 void combine_requires(list_t
*hd
)
2354 item_t
*item0
, *item1
;
2357 str_t
*str
, *str0
, *str1
;
2359 for(item0
= hd
->first
; item0
; item0
= item0
->next
) {
2363 !(hid0
= item0
->value
->hid
[he_requires
]) ||
2364 hid0
->any
.flag
!= FLAG_STRING
2366 for(item1
= item0
->next
; item1
; item1
= item1
->next
) {
2370 !(hid1
= item1
->value
->hid
[he_requires
]) ||
2371 hid1
->any
.flag
!= FLAG_STRING
2374 i
= cmp_item(item0
, item1
);
2376 /* remove duplicate entries */
2382 /* work only on entries with identical keys */
2383 if(i
== -1 || i
== 1) continue;
2385 if(!cmp_hid(hid0
, hid1
)) {
2386 hid1
->any
.remove
= 1;
2388 "%s: info is identical to %s, info removed\n",
2389 item1
->pos
, item0
->pos
2391 log_items(logfh
, item1
, item0
);
2392 item1
->value
->hid
[he_requires
] = free_hid(item1
->value
->hid
[he_requires
]);
2395 slist
.first
= split('|', ((str_t
*) hid0
->str
.list
.first
)->str
);
2397 /* add pointer to last element */
2398 for(str
= slist
.first
; str
; str
= str
->next
) {
2399 if(!str
->next
) slist
.last
= str
;
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;
2407 if(!str0
) add_list(&slist
, clone_str(str
));
2411 sort_list(&slist
, cmp_str_s
);
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
);
2418 free_str(slist
.first
, 1);
2420 hid1
->any
.remove
= 1;
2423 "%s: combine with %s, info removed\n",
2424 item1
->pos
, item0
->pos
2426 log_items(logfh
, item1
, item0
);
2427 item1
->value
->hid
[he_requires
] = free_hid(item1
->value
->hid
[he_requires
]);
2430 if(!count_common_hids(item1
->value
, item1
->value
)) {
2431 /* remove if no values left */
2433 fprintf(logfh
, "%s: no info left, item removed\n", item1
->pos
);
2442 void join_items_by_value(list_t
*hd
)
2444 item_t
*item0
, *item1
;
2445 skey_t
*skey
, *next
;
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;
2453 if(!cmp_skey(item0
->value
, item1
->value
)) {
2454 for(skey
= item1
->key
.first
; skey
; skey
= next
) {
2456 add_list(&item0
->key
, skey
);
2458 memset(&item1
->key
, 0, sizeof item1
->key
);
2460 fprintf(logfh
, "%s: info added to %s, item removed\n", item1
->pos
, item0
->pos
);
2467 for(item0
= hd
->first
; item0
; item0
= item0
->next
) {
2469 /* sort key entries */
2470 sort_list(&item0
->key
, cmp_skey_s
);
2472 /* try to join adjacent keys */
2473 for(skey
= item0
->key
.first
; skey
&& (next
= skey
->next
); ) {
2474 i
= combine_keys(skey
, next
);
2479 if(!(skey
->next
= next
->next
)) {
2480 /* last element has changed */
2481 item0
->key
.last
= skey
;
2489 void join_items_by_key(list_t
*hd
)
2491 item_t
*item0
, *item1
;
2492 skey_t
*val0
, *val1
;
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;
2501 i
= cmp_item(item0
, item1
);
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 */
2509 for(i
= 0; (unsigned) i
< sizeof val1
->hid
/ sizeof *val1
->hid
; i
++) {
2511 val0
->hid
[i
] = val1
->hid
[i
];
2512 val1
->hid
[i
] = NULL
;
2516 fprintf(logfh
, "%s: info added to %s, item removed\n", item1
->pos
, item0
->pos
);
2526 void remove_unimportant_items(list_t
*hd
)
2533 for(item
= hd
->first
; item
; item
= item
->next
) {
2537 for(i
= 0; (unsigned) i
< sizeof val
->hid
/ sizeof *val
->hid
; i
++) {
2538 if(i
== he_driver
&& val
->hid
[i
]) {
2540 val
->hid
[i
]->any
.flag
== FLAG_STRING
&&
2541 (str
= val
->hid
[i
]->str
.list
.first
) &&
2543 (*str
->str
== 'i' || *str
->str
== 'm')
2545 val
->hid
[i
] = free_hid(val
->hid
[i
]);
2548 else if(val
->hid
[i
]) {
2549 if(val
->hid
[i
]->any
.flag
!= FLAG_ID
) val
->hid
[i
] = free_hid(val
->hid
[i
]);
2551 if(val
->hid
[i
]) cnt
++;
2554 /* no values left */
2555 if(!cnt
) item
->remove
= 1;
2562 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2565 /* returns index in hddb2->ids */
2566 unsigned store_entry(hddb2_data_t
*x
, tmp_entry_t
*te
)
2569 unsigned ent
= -1, u
, v
;
2571 for(i
= 0; i
< he_nomask
; i
++) {
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
;
2585 void add_value(tmp_entry_t
*te
, hddb_entry_t idx
, unsigned val
)
2587 if(idx
>= he_nomask
) return;
2590 if(te
->len
>= sizeof te
->val
/ sizeof *te
->val
) return;
2592 te
->val
[te
->len
++] = val
;
2599 unsigned hddb_store_string(hddb_data_t
*hddb
, char *str
)
2601 unsigned l
= strlen(str
), u
;
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
;
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
);
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;
2623 if(l
== 0) return 0; /* 1st byte is always 0 */
2625 strcpy(hddb
->strings
+ (u
= hddb
->strings_len
), str
);
2626 hddb
->strings_len
+= l
+ 1;
2632 unsigned hddb_store_value(hddb_data_t
*hddb
, unsigned val
)
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
);
2639 hddb
->ids
[hddb
->ids_len
++] = val
;
2641 return hddb
->ids_len
- 1;
2645 unsigned hddb_store_hid(hddb_data_t
*hddb
, hid_t
*hid
, hddb_entry_t entry
)
2647 unsigned u
, idx
= -1;
2648 str_t
*str
, *str0
, *str1
;
2650 if(!hid
) return idx
;
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));
2656 else if(hid
->num
.has
.mask
) {
2657 idx
= hddb_store_value(hddb
, MAKE_DATA(FLAG_MASK
, hid
->num
.mask
) | (1 << 31));
2659 u
= hddb_store_value(hddb
, MAKE_DATA(FLAG_ID
, hid
->num
.id
+ (hid
->num
.tag
<< 16)));
2660 if(idx
== -1u) idx
= u
;
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
;
2676 u
= hddb_store_string(hddb
, ((str_t
*) hid
->str
.list
.first
)->str
);
2677 idx
= hddb_store_value(hddb
, MAKE_DATA(FLAG_STRING
, u
));
2685 void hddb_store_skey(hddb_data_t
*hddb
, skey_t
*skey
, unsigned *mask
, unsigned *idx
)
2689 hddb_data_t save_db
= *hddb
;
2696 for(i
= 0; (unsigned) i
< sizeof skey
->hid
/ sizeof *skey
->hid
; i
++) {
2698 ent
= hddb_store_hid(hddb
, skey
->hid
[i
], i
);
2699 if(!*mask
) *idx
= ent
;
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
;
2723 void hddb_store_list(hddb_data_t
*hddb
, hddb_list_t
*list
)
2725 if(!list
|| !list
->key_mask
|| !list
->value_mask
) return;
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
);
2732 hddb
->list
[hddb
->list_len
++] = *list
;
2736 void hddb_init(hddb_data_t
*hddb
, list_t
*hd
)
2739 hddb_list_t db_list
= {};
2742 for(item_cnt
= 0, item
= hd
->first
; item
; item
= item
->next
, item_cnt
++) {
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
);
2747 hddb_store_list(hddb
, &db_list
);
2752 unsigned char *quote_string(unsigned char *str
, int len
)
2754 unsigned char *qstr
;
2757 if(!str
|| !len
) return NULL
;
2759 qstr
= new_mem(4 * len
+ 1); /* enough */
2761 for(i
= j
= 0; i
< len
; i
++) {
2762 if(str
[i
] == '\\' || str
[i
] == '"' || str
[i
] == '?') {
2766 else if(str
[i
] == '\n') {
2770 else if(str
[i
] == '\t') {
2774 else if(str
[i
] < ' ') {
2776 qstr
[j
++] = (str
[i
] >> 6) + '0';
2777 qstr
[j
++] = ((str
[i
] >> 3) & 7) + '0';
2778 qstr
[j
++] = (str
[i
] & 7) + '0';
2789 void write_cfile(FILE *f
, list_t
*hd
)
2791 hddb_data_t hddb
= {};
2793 unsigned u
, qstr_len
, len
;
2795 fprintf(logfh
, "- building C version\n");
2798 hddb_init(&hddb
, hd
);
2800 fprintf(logfh
, " db size: %u bytes\n",
2801 (unsigned) (sizeof hddb
+
2803 hddb
.ids_len
* sizeof *hddb
.ids
+
2804 hddb
.list_len
* sizeof *hddb
.list
)
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"
2816 hddb
.list_len
, hddb
.list_len
,
2817 hddb
.ids_len
, hddb
.ids_len
,
2818 hddb
.strings_len
, hddb
.strings_len
2821 fprintf(f
, "static hddb_list_t hddb_internal_list[%u] = {\n", hddb
.list_len
);
2822 for(u
= 0; u
< hddb
.list_len
; u
++) {
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
? "" : ","
2830 fprintf(f
, "};\n\n");
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
);
2839 fprintf(f
, "};\n\n");
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
; ) {
2846 if(len
> 72) len
= 72;
2847 while(len
--) fputc(qstr
[u
++], f
);
2850 fprintf(f
, "\";\n\n");
2854 free_mem(hddb
.list
);
2856 free_mem(hddb
.strings
);