aboutsummaryrefslogtreecommitdiff
path: root/src/references.c
blob: ff64b0000840e1d755072499583c10db9100fafe (plain)
  1. #include "stmd.h"
  2. #include "utf8.h"
  3. #include "references.h"
  4. static unsigned int
  5. refhash(const unsigned char *link_ref)
  6. {
  7. unsigned int hash = 0;
  8. while (*link_ref)
  9. hash = (*link_ref++) + (hash << 6) + (hash << 16) - hash;
  10. return hash;
  11. }
  12. // normalize reference: collapse internal whitespace to single space,
  13. // remove leading/trailing whitespace, case fold
  14. static unsigned char *normalize_reference(chunk *ref)
  15. {
  16. strbuf normalized = GH_BUF_INIT;
  17. utf8proc_case_fold(&normalized, ref->data, ref->len);
  18. strbuf_trim(&normalized);
  19. strbuf_normalize_whitespace(&normalized);
  20. return strbuf_detach(&normalized);
  21. }
  22. static void add_reference(reference_map *map, reference* ref)
  23. {
  24. ref->next = map->table[ref->hash % REFMAP_SIZE];
  25. map->table[ref->hash % REFMAP_SIZE] = ref;
  26. }
  27. extern reference *reference_create(reference_map *map, chunk *label, chunk *url, chunk *title)
  28. {
  29. reference *ref;
  30. ref = malloc(sizeof(reference));
  31. ref->label = normalize_reference(label);
  32. ref->hash = refhash(ref->label);
  33. ref->url = clean_url(url);
  34. ref->title = clean_title(title);
  35. ref->next = NULL;
  36. add_reference(map, ref);
  37. return ref;
  38. }
  39. // Returns reference if refmap contains a reference with matching
  40. // label, otherwise NULL.
  41. reference* reference_lookup(reference_map *map, chunk *label)
  42. {
  43. reference *ref = NULL;
  44. unsigned char *norm;
  45. unsigned int hash;
  46. if (map == NULL)
  47. return NULL;
  48. norm = normalize_reference(label);
  49. hash = refhash(norm);
  50. ref = map->table[hash % REFMAP_SIZE];
  51. while (ref) {
  52. if (ref->label[0] == norm[0] &&
  53. !strcmp((char *)ref->label, (char *)norm))
  54. break;
  55. ref = ref->next;
  56. }
  57. free(norm);
  58. return ref;
  59. }
  60. static void reference_free(reference *ref)
  61. {
  62. free(ref->label);
  63. free(ref->url);
  64. free(ref->title);
  65. free(ref);
  66. }
  67. void reference_map_free(reference_map *map)
  68. {
  69. unsigned int i;
  70. for (i = 0; i < REFMAP_SIZE; ++i) {
  71. reference *ref = map->table[i];
  72. reference *next;
  73. while (ref) {
  74. next = ref->next;
  75. reference_free(ref);
  76. ref = next;
  77. }
  78. }
  79. free(map->table);
  80. free(map);
  81. }
  82. reference_map *reference_map_new(void)
  83. {
  84. reference_map *map = malloc(sizeof(reference_map));
  85. memset(map, 0x0, sizeof(reference_map));
  86. return map;
  87. }