diff options
-rw-r--r-- | deps/sysobj_early/include/strstr_word.h | 11 | ||||
-rw-r--r-- | deps/sysobj_early/src/strstr_word.c | 56 | ||||
-rw-r--r-- | hardinfo/vendor.c | 206 | ||||
-rw-r--r-- | includes/vendor.h | 24 |
4 files changed, 194 insertions, 103 deletions
diff --git a/deps/sysobj_early/include/strstr_word.h b/deps/sysobj_early/include/strstr_word.h index f607b2ed..f17e78ff 100644 --- a/deps/sysobj_early/include/strstr_word.h +++ b/deps/sysobj_early/include/strstr_word.h @@ -18,13 +18,18 @@ * */ -/* versions of strstr() and strcasestr() where the match must be preceded and - * succeded by a non-alpha-numeric character. */ - #ifndef __STRSTR_WORD_H__ #define __STRSTR_WORD_H__ +/* versions of strstr() and strcasestr() where the match must be preceded and + * succeded by a non-alpha-numeric character. */ char *strstr_word(const char *haystack, const char *needle); char *strcasestr_word(const char *haystack, const char *needle); +/* word boundary at start only (prefix), or end only (suffix) */ +char *strstr_word_prefix(const char *haystack, const char *needle); +char *strcasestr_word_prefix(const char *haystack, const char *needle); +char *strstr_word_suffix(const char *haystack, const char *needle); +char *strcasestr_word_suffix(const char *haystack, const char *needle); + #endif diff --git a/deps/sysobj_early/src/strstr_word.c b/deps/sysobj_early/src/strstr_word.c index b12f01a2..0b51e4ac 100644 --- a/deps/sysobj_early/src/strstr_word.c +++ b/deps/sysobj_early/src/strstr_word.c @@ -25,40 +25,56 @@ #include <string.h> #include <ctype.h> -char *strstr_word(const char *haystack, const char *needle) { +static char *_strstr(const char *haystack, const char *needle, int anycase) { + return anycase + ? strcasestr(haystack, needle) + : strstr(haystack, needle); +} + +static char *_strstr_word(const char *haystack, const char *needle, + int anycase, int prefix_ok, int suffix_ok) { + if (!haystack || !needle) return NULL; char *c; const char *p = haystack; size_t l = strlen(needle); - while(c = strstr(p, needle)) { + while((c = _strstr(p, needle, anycase))) { const char *before = (c == haystack) ? NULL : c-1; const char *after = c + l; - int ok = 1; - if (isalnum(*after)) ok = 0; - if (before && isalnum(*before)) ok = 0; + int ok = 1, wbs = 1, wbe = 1; + if (isalnum(*after)) wbe = 0; + if (before && isalnum(*before)) wbs = 0; + if (!wbe && !prefix_ok) ok = 0; + if (!wbs && !suffix_ok) ok = 0; + if (!(wbs || wbe)) ok = 0; if (ok) return c; p++; } return NULL; } +char *strstr_word(const char *haystack, const char *needle) { + return _strstr_word(haystack, needle, 0, 0, 0); +} + char *strcasestr_word(const char *haystack, const char *needle) { - if (!haystack || !needle) - return NULL; + return _strstr_word(haystack, needle, 1, 0, 0); +} - char *c; - const char *p = haystack; - size_t l = strlen(needle); - while(c = strcasestr(p, needle)) { - const char *before = (c == haystack) ? NULL : c-1; - const char *after = c + l; - int ok = 1; - if (isalnum(*after)) ok = 0; - if (before && isalnum(*before)) ok = 0; - if (ok) return c; - p++; - } - return NULL; +char *strstr_word_prefix(const char *haystack, const char *needle) { + return _strstr_word(haystack, needle, 0, 1, 0); +} + +char *strcasestr_word_prefix(const char *haystack, const char *needle) { + return _strstr_word(haystack, needle, 1, 1, 0); +} + +char *strstr_word_suffix(const char *haystack, const char *needle) { + return _strstr_word(haystack, needle, 0, 0, 1); +} + +char *strcasestr_word_suffix(const char *haystack, const char *needle) { + return _strstr_word(haystack, needle, 1, 0, 1); } diff --git a/hardinfo/vendor.c b/hardinfo/vendor.c index fa3b4d96..ff560390 100644 --- a/hardinfo/vendor.c +++ b/hardinfo/vendor.c @@ -58,19 +58,22 @@ static Vendor vendors_builtin[] = { }; #define ven_msg(msg, ...) fprintf (stderr, "[%s] " msg "\n", __FUNCTION__, ##__VA_ARGS__) /**/ +#define ven_file_err(msg, ...) { \ + ven_msg(msg, ##__VA_ARGS__); \ + fflush(stderr); \ + if (vendor_die_on_error) exit(-1); } static vendor_list vendors = NULL; const vendor_list get_vendors_list() { return vendors; } +gboolean vendor_die_on_error = FALSE; /* sort the vendor list by length of match_string, * LONGEST first */ int vendor_sort (const Vendor *ap, const Vendor *bp) { int la = 0, lb = 0; - if (ap && ap->match_string) la = strlen(ap->match_string); - if (bp && bp->match_string) lb = strlen(bp->match_string); - if (la == lb) return 0; - if (la > lb) return -1; - return 1; + if (ap) la = ap->weight; + if (bp) lb = bp->weight; + return lb-la; } static int read_from_vendor_conf(const char *path) { @@ -132,6 +135,7 @@ static int read_from_vendor_ids(const char *path) { char *wikipedia = vars[4]; char *note = vars[5]; char *ansi_color = vars[6]; + int name_rule_count = -1; int count = 0; FILE *fd; @@ -151,7 +155,7 @@ static int read_from_vendor_ids(const char *path) { if (b) *b = 0; else - ven_msg("%s:%d: line longer than VEN_BUFF_SIZE (%lu)", path, line, (unsigned long)VEN_BUFF_SIZE); + ven_file_err("%s:%d: line longer than VEN_BUFF_SIZE (%lu)", path, line, (unsigned long)VEN_BUFF_SIZE); b = strchr(buff, '#'); if (b) *b = 0; /* line ends at comment */ @@ -159,6 +163,8 @@ static int read_from_vendor_ids(const char *path) { p = buff; VEN_FFWD(); if (VEN_CHK("name ")) { + if (name_rule_count == 0) + ven_file_err("%s:%d: name \"%s\" had no match rules", path, line, name); strncpy(name, p + tl, VEN_BUFF_SIZE - 1); strcpy(name_short, ""); strcpy(url, ""); @@ -166,6 +172,7 @@ static int read_from_vendor_ids(const char *path) { strcpy(wikipedia, ""); strcpy(note, ""); strcpy(ansi_color, ""); + name_rule_count = 0; } if (VEN_CHK("name_short ")) strncpy(name_short, p + tl, VEN_BUFF_SIZE - 1); @@ -182,12 +189,32 @@ static int read_from_vendor_ids(const char *path) { #define dup_if_not_empty(s) (strlen(s) ? g_strdup(s) : NULL) - if (VEN_CHK("match_string ")) { + int mrule = -1; + if (VEN_CHK("match_string ")) + mrule = VENDOR_MATCH_RULE_WORD_IGNORE_CASE; + else if (VEN_CHK("match_string_case ")) + mrule = VENDOR_MATCH_RULE_WORD_MATCH_CASE; + else if (VEN_CHK("match_string_exact ")) + mrule = VENDOR_MATCH_RULE_EXACT; + else if (VEN_CHK("match_string_prefix ")) + mrule = VENDOR_MATCH_RULE_WORD_PREFIX_IGNORE_CASE; + else if (VEN_CHK("match_string_prefix_case ")) + mrule = VENDOR_MATCH_RULE_WORD_PREFIX_MATCH_CASE; + else if (VEN_CHK("match_string_suffix ")) + mrule = VENDOR_MATCH_RULE_WORD_PREFIX_IGNORE_CASE; + else if (VEN_CHK("match_string_suffix_case ")) + mrule = VENDOR_MATCH_RULE_WORD_PREFIX_MATCH_CASE; + else if (VEN_CHK("match_string_num_prefix ")) + mrule = VENDOR_MATCH_RULE_NUM_PREFIX_IGNORE_CASE; + else if (VEN_CHK("match_string_num_prefix_case ")) + mrule = VENDOR_MATCH_RULE_NUM_PREFIX_MATCH_CASE; + + if (mrule >= 0) { Vendor *v = g_new0(Vendor, 1); v->file_line = line; v->match_string = g_strdup(p+tl); v->ms_length = strlen(v->match_string); - v->match_rule = 0; + v->match_rule = mrule; v->name = g_strdup(name); v->name_short = dup_if_not_empty(name_short); v->url = dup_if_not_empty(url); @@ -195,47 +222,23 @@ static int read_from_vendor_ids(const char *path) { v->wikipedia = dup_if_not_empty(wikipedia); v->note = dup_if_not_empty(note); v->ansi_color = dup_if_not_empty(ansi_color); - vendors = g_slist_prepend(vendors, v); - count++; - } - if (VEN_CHK("match_string_case ")) { - Vendor *v = g_new0(Vendor, 1); - v->file_line = line; - v->match_string = g_strdup(p+tl); - v->ms_length = strlen(v->match_string); - v->match_rule = 1; - v->name = g_strdup(name); - v->name_short = dup_if_not_empty(name_short); - v->url = dup_if_not_empty(url); - v->url_support = dup_if_not_empty(url_support); - v->wikipedia = dup_if_not_empty(wikipedia); - v->note = dup_if_not_empty(note); - v->ansi_color = dup_if_not_empty(ansi_color); - vendors = g_slist_prepend(vendors, v); - count++; - } + v->weight = v->ms_length; + /* NUM_PREFIX rules consider +1 characters */ + if (v->match_rule == VENDOR_MATCH_RULE_NUM_PREFIX_MATCH_CASE + || v->match_rule == VENDOR_MATCH_RULE_NUM_PREFIX_IGNORE_CASE) + v->weight++; + + v->has_parens = g_utf8_strchr(v->match_string, -1, '(') ? TRUE : FALSE; - if (VEN_CHK("match_string_exact ")) { - Vendor *v = g_new0(Vendor, 1); - v->file_line = line; - v->match_string = g_strdup(p+tl); - v->ms_length = strlen(v->match_string); - v->match_rule = 2; - v->name = g_strdup(name); - v->name_short = dup_if_not_empty(name_short); - v->url = dup_if_not_empty(url); - v->url_support = dup_if_not_empty(url_support); - v->wikipedia = dup_if_not_empty(wikipedia); - v->note = dup_if_not_empty(note); - v->ansi_color = dup_if_not_empty(ansi_color); vendors = g_slist_prepend(vendors, v); + name_rule_count++; count++; } g_strstrip(buff); if (!ok && *buff != 0) - ven_msg("unrecognised item at %s:%d, %s", path, line, p); + ven_file_err("unrecognised item at %s:%d, %s", path, line, buff); } fclose(fd); @@ -487,6 +490,26 @@ vendor_list vendor_list_concat_va(int count, vendor_list vl, ...) { return ret; } +int vendor_cmp_deep(const Vendor *a, const Vendor *b) { + int r; + if (a && !b) return 1; + if (!a && b) return -1; + if (!a && !b) return 0; + r = g_strcmp0(a->name, b->name); + if (!!r) return r; + r = g_strcmp0(a->name_short, b->name_short); + if (!!r) return r; + r = g_strcmp0(a->ansi_color, b->ansi_color); + if (!!r) return r; + r = g_strcmp0(a->url, b->url); + if (!!r) return r; + r = g_strcmp0(a->url_support, b->url_support); + if (!!r) return r; + r = g_strcmp0(a->wikipedia, b->wikipedia); + if (!!r) return r; + return 0; +} + vendor_list vendor_list_remove_duplicates_deep(vendor_list vl) { /* vendor_list is GSList* */ GSList *tvl = vl; @@ -496,13 +519,7 @@ vendor_list vendor_list_remove_duplicates_deep(vendor_list vl) { evl = tvl->next; while(evl) { const Vendor *ev = evl->data; - if ( SEQ(ev->name, tv->name) - && SEQ(ev->name_short, tv->name_short) - && SEQ(ev->ansi_color, tv->ansi_color) - && SEQ(ev->url, tv->url) - && SEQ(ev->url_support, tv->url_support) - && SEQ(ev->wikipedia, tv->wikipedia) - ) { + if (vendor_cmp_deep(ev, tv) == 0) { GSList *next = evl->next; vl = g_slist_delete_link(vl, evl); evl = next; @@ -546,54 +563,86 @@ vendor_list vendors_match_core(const gchar *str, int limit) { int found = 0; vendor_list ret = NULL; - /* first pass (passes[1]): ignore text in (), - * like (formerly ...) or (nee ...) - * second pass (passes[0]): full text */ - gchar *passes[2] = { g_strdup(str), g_strdup(str) }; + /* pass [array_index]: function + * 1st [3]: only check match strings that have () in them + * 2nd [2]: ignore text in (), like (formerly ...) or (nee ...), + * but unfortunately also (now ...) + * 3rd [1]: (passes[0]): full text */ + gchar *passes[3] = { g_strdup(str), g_strdup(str), g_strdup(str) }; int pass = 1; p = passes[1]; - while(p = strchr(p, '(') ) { - pass = 2; p++; + while((p = strchr(p, '('))) { + pass = 3; p++; while(*p && *p != ')') { *p = ' '; p++; } } for (; pass > 0; pass--) { for (vlp = vendors; vlp; vlp = vlp->next) { - //sysobj_stats.ven_iter++; Vendor *v = (Vendor *)vlp->data; - char *m = NULL, *s = NULL; + char *m = NULL; if (!v) continue; if (!v->match_string) continue; + if (v->has_parens) + if (pass != 3) continue; + + //ven_msg("pass:%d <<%s>> EXAMINE: \"%s\"", pass, v->match_string, passes[pass-1]); + int epass; + +#define standard_match_work_inner(fn) { \ + /* clear so it doesn't match again */ \ + for(epass = pass; epass > 0; epass--) \ + { char *s = passes[epass-1] + (m - passes[pass-1]); \ + char *e = s + v->ms_length; \ + for(; s < e; s++) *s = ' '; \ + g_strstrip(passes[epass-1]); } \ + /* add to return list */ \ + ret = vendor_list_append(ret, v); \ + found++; \ + if (*passes[0] == 0) \ + goto vendors_match_core_finish; \ + if (limit > 0 && found >= limit) \ + goto vendors_match_core_finish; } +#define standard_match_work(fn) \ + if ((m = fn(passes[pass-1], v->match_string))) \ + standard_match_work_inner(); + switch(v->match_rule) { - case 0: - if (m = strcasestr_word(passes[pass-1], v->match_string) ) { - /* clear so it doesn't match again */ - for(s = m; s < m + v->ms_length; s++) *s = ' '; + case VENDOR_MATCH_RULE_EXACT: + if (SEQ(passes[pass-1], v->match_string) ) { /* add to return list */ ret = vendor_list_append(ret, v); found++; - if (limit > 0 && found >= limit) - goto vendors_match_core_finish; + goto vendors_match_core_finish; /* no way for any other match to happen */ } break; - case 1: /* match case */ - if (m = strstr_word(passes[pass-1], v->match_string) ) { - /* clear so it doesn't match again */ - for(s = m; s < m + v->ms_length; s++) *s = ' '; - /* add to return list */ - ret = vendor_list_append(ret, v); - found++; - if (limit > 0 && found >= limit) - goto vendors_match_core_finish; - } + case VENDOR_MATCH_RULE_WORD_IGNORE_CASE: + standard_match_work(strcasestr_word); break; - case 2: /* match exact */ - if (SEQ(passes[pass-1], v->match_string) ) { - ret = vendor_list_append(ret, v); - found++; - goto vendors_match_core_finish; /* no way for any other match to happen */ - } + case VENDOR_MATCH_RULE_WORD_MATCH_CASE: + standard_match_work(strstr_word); + break; + case VENDOR_MATCH_RULE_WORD_PREFIX_MATCH_CASE: + standard_match_work(strstr_word_prefix); + break; + case VENDOR_MATCH_RULE_WORD_PREFIX_IGNORE_CASE: + standard_match_work(strcasestr_word_prefix); + break; + case VENDOR_MATCH_RULE_WORD_SUFFIX_MATCH_CASE: + standard_match_work(strstr_word_suffix); + break; + case VENDOR_MATCH_RULE_WORD_SUFFIX_IGNORE_CASE: + standard_match_work(strcasestr_word_suffix); + break; + case VENDOR_MATCH_RULE_NUM_PREFIX_IGNORE_CASE: + if ((m = strstr_word_prefix(passes[pass-1], v->match_string))) + if (isdigit(m[v->ms_length])) + standard_match_work_inner(); + break; + case VENDOR_MATCH_RULE_NUM_PREFIX_MATCH_CASE: + if ((m = strcasestr_word_prefix(passes[pass-1], v->match_string))) + if (isdigit(m[v->ms_length])) + standard_match_work_inner(); break; } } @@ -603,5 +652,6 @@ vendors_match_core_finish: g_free(passes[0]); g_free(passes[1]); + g_free(passes[2]); return ret; } diff --git a/includes/vendor.h b/includes/vendor.h index 50c23c50..451a6134 100644 --- a/includes/vendor.h +++ b/includes/vendor.h @@ -28,9 +28,22 @@ vendor_list vendor_list_concat_va(int count, vendor_list vl, ...); /* count = -1 #define vendor_list_remove_duplicates(vl) gg_slist_remove_duplicates(vl) vendor_list vendor_list_remove_duplicates_deep(vendor_list vl); +enum { + VENDOR_MATCH_RULE_WORD_IGNORE_CASE = 0, + VENDOR_MATCH_RULE_WORD_MATCH_CASE = 1, + VENDOR_MATCH_RULE_EXACT = 2, + VENDOR_MATCH_RULE_WORD_PREFIX_IGNORE_CASE = 3, + VENDOR_MATCH_RULE_WORD_PREFIX_MATCH_CASE = 4, + VENDOR_MATCH_RULE_WORD_SUFFIX_IGNORE_CASE = 5, + VENDOR_MATCH_RULE_WORD_SUFFIX_MATCH_CASE = 6, + /* "ST" hits for "ST3600A" but not "AST" or "STMicro" or "STEC" */ + VENDOR_MATCH_RULE_NUM_PREFIX_IGNORE_CASE = 7, + VENDOR_MATCH_RULE_NUM_PREFIX_MATCH_CASE = 8, +}; + typedef struct { char *match_string; - int match_rule; /* 0 = ignore case, 1 = match case, 2 = exact */ + int match_rule; /* VENDOR_MATCH_RULE_* enum */ char *name; char *name_short; char *url; @@ -41,11 +54,16 @@ typedef struct { unsigned long file_line; unsigned long ms_length; + unsigned long weight; + gboolean has_parens; } Vendor; void vendor_init(void); void vendor_cleanup(void); -const Vendor *vendor_match(const gchar *id_str, ...) /* end list of strings with NULL */ +/* end list of strings with NULL */ +const Vendor *vendor_match(const gchar *id_str, ...) + __attribute__((sentinel)); +vendor_list vendors_match(const gchar *id_str, ...) __attribute__((sentinel)); const gchar *vendor_get_name(const gchar *id_str); const gchar *vendor_get_shortest_name(const gchar *id_str); @@ -56,4 +74,6 @@ void vendor_free(Vendor *v); vendor_list vendors_match_core(const gchar *str, int limit); +extern gboolean vendor_die_on_error; + #endif /* __VENDOR_H__ */ |