See `struct fingerprint` for an explanation of what a fingerprint is. * \param result the fingerprint of the string is stored here. This must be * freed later using free_fingerprint. * \param line_begin the start of the string * \param line_end the end of the string */
| 407 | * \param line_end the end of the string |
| 408 | */ |
| 409 | static void get_fingerprint(struct fingerprint *result, |
| 410 | const char *line_begin, |
| 411 | const char *line_end) |
| 412 | { |
| 413 | unsigned int hash, c0 = 0, c1; |
| 414 | const char *p; |
| 415 | int max_map_entry_count = 1 + line_end - line_begin; |
| 416 | struct fingerprint_entry *entry = xcalloc(max_map_entry_count, |
| 417 | sizeof(struct fingerprint_entry)); |
| 418 | struct fingerprint_entry *found_entry; |
| 419 | |
| 420 | hashmap_init(&result->map, NULL, NULL, max_map_entry_count); |
| 421 | result->entries = entry; |
| 422 | for (p = line_begin; p <= line_end; ++p, c0 = c1) { |
| 423 | /* Always terminate the string with whitespace. |
| 424 | * Normalise whitespace to 0, and normalise letters to |
| 425 | * lower case. This won't work for multibyte characters but at |
| 426 | * worst will match some unrelated characters. |
| 427 | */ |
| 428 | if ((p == line_end) || isspace(*p)) |
| 429 | c1 = 0; |
| 430 | else |
| 431 | c1 = tolower(*p); |
| 432 | hash = c0 | (c1 << 8); |
| 433 | /* Ignore whitespace pairs */ |
| 434 | if (hash == 0) |
| 435 | continue; |
| 436 | hashmap_entry_init(&entry->entry, hash); |
| 437 | |
| 438 | found_entry = hashmap_get_entry(&result->map, entry, |
| 439 | /* member name */ entry, NULL); |
| 440 | if (found_entry) { |
| 441 | found_entry->count += 1; |
| 442 | } else { |
| 443 | entry->count = 1; |
| 444 | hashmap_add(&result->map, &entry->entry); |
| 445 | ++entry; |
| 446 | } |
| 447 | } |
| 448 | } |
| 449 | |
| 450 | static void free_fingerprint(struct fingerprint *f) |
| 451 | { |
no test coverage detected