From 94a79a605f3e76a43f1f87a5044f6761b99e5ca5 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 10 Sep 2014 18:33:27 +0200 Subject: Cleanup reference implementation --- src/references.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/references.c (limited to 'src/references.c') diff --git a/src/references.c b/src/references.c new file mode 100644 index 0000000..ff64b00 --- /dev/null +++ b/src/references.c @@ -0,0 +1,109 @@ +#include "stmd.h" +#include "utf8.h" +#include "references.h" + +static unsigned int +refhash(const unsigned char *link_ref) +{ + unsigned int hash = 0; + + while (*link_ref) + hash = (*link_ref++) + (hash << 6) + (hash << 16) - hash; + + return hash; +} + +// normalize reference: collapse internal whitespace to single space, +// remove leading/trailing whitespace, case fold +static unsigned char *normalize_reference(chunk *ref) +{ + strbuf normalized = GH_BUF_INIT; + + utf8proc_case_fold(&normalized, ref->data, ref->len); + strbuf_trim(&normalized); + strbuf_normalize_whitespace(&normalized); + + return strbuf_detach(&normalized); +} + +static void add_reference(reference_map *map, reference* ref) +{ + ref->next = map->table[ref->hash % REFMAP_SIZE]; + map->table[ref->hash % REFMAP_SIZE] = ref; +} + +extern reference *reference_create(reference_map *map, chunk *label, chunk *url, chunk *title) +{ + reference *ref; + ref = malloc(sizeof(reference)); + ref->label = normalize_reference(label); + ref->hash = refhash(ref->label); + ref->url = clean_url(url); + ref->title = clean_title(title); + ref->next = NULL; + + add_reference(map, ref); + + return ref; +} + +// Returns reference if refmap contains a reference with matching +// label, otherwise NULL. +reference* reference_lookup(reference_map *map, chunk *label) +{ + reference *ref = NULL; + unsigned char *norm; + unsigned int hash; + + if (map == NULL) + return NULL; + + norm = normalize_reference(label); + hash = refhash(norm); + ref = map->table[hash % REFMAP_SIZE]; + + while (ref) { + if (ref->label[0] == norm[0] && + !strcmp((char *)ref->label, (char *)norm)) + break; + ref = ref->next; + } + + free(norm); + return ref; +} + +static void reference_free(reference *ref) +{ + free(ref->label); + free(ref->url); + free(ref->title); + free(ref); +} + +void reference_map_free(reference_map *map) +{ + unsigned int i; + + for (i = 0; i < REFMAP_SIZE; ++i) { + reference *ref = map->table[i]; + reference *next; + + while (ref) { + next = ref->next; + reference_free(ref); + ref = next; + } + } + + free(map->table); + free(map); +} + +reference_map *reference_map_new(void) +{ + reference_map *map = malloc(sizeof(reference_map)); + memset(map, 0x0, sizeof(reference_map)); + return map; +} + -- cgit v1.2.3 From c04e1e7aef06ce0836984b17e48a1d09bb83ce04 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 10 Sep 2014 18:38:56 +0200 Subject: Fix misc bugs --- src/references.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'src/references.c') diff --git a/src/references.c b/src/references.c index ff64b00..84cb773 100644 --- a/src/references.c +++ b/src/references.c @@ -13,6 +13,14 @@ refhash(const unsigned char *link_ref) return hash; } +static void reference_free(reference *ref) +{ + free(ref->label); + free(ref->url); + free(ref->title); + free(ref); +} + // normalize reference: collapse internal whitespace to single space, // remove leading/trailing whitespace, case fold static unsigned char *normalize_reference(chunk *ref) @@ -28,7 +36,18 @@ static unsigned char *normalize_reference(chunk *ref) static void add_reference(reference_map *map, reference* ref) { - ref->next = map->table[ref->hash % REFMAP_SIZE]; + reference *t = ref->next = map->table[ref->hash % REFMAP_SIZE]; + + while (t) { + if (t->hash == ref->hash && + !strcmp((char *)t->label, (char *)ref->label)) { + reference_free(ref); + return; + } + + t = t->next; + } + map->table[ref->hash % REFMAP_SIZE] = ref; } @@ -63,7 +82,7 @@ reference* reference_lookup(reference_map *map, chunk *label) ref = map->table[hash % REFMAP_SIZE]; while (ref) { - if (ref->label[0] == norm[0] && + if (ref->hash == hash && !strcmp((char *)ref->label, (char *)norm)) break; ref = ref->next; @@ -73,14 +92,6 @@ reference* reference_lookup(reference_map *map, chunk *label) return ref; } -static void reference_free(reference *ref) -{ - free(ref->label); - free(ref->url); - free(ref->title); - free(ref); -} - void reference_map_free(reference_map *map) { unsigned int i; @@ -96,7 +107,6 @@ void reference_map_free(reference_map *map) } } - free(map->table); free(map); } -- cgit v1.2.3 From 8c028e1a88c2d2aac4a4086202568bee43678aa8 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 10 Sep 2014 19:50:29 +0200 Subject: Do not create references with empty names --- src/references.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'src/references.c') diff --git a/src/references.c b/src/references.c index 84cb773..300bbcc 100644 --- a/src/references.c +++ b/src/references.c @@ -23,15 +23,29 @@ static void reference_free(reference *ref) // normalize reference: collapse internal whitespace to single space, // remove leading/trailing whitespace, case fold +// Return NULL if the reference name is actually empty (i.e. composed +// solely from whitespace) static unsigned char *normalize_reference(chunk *ref) { strbuf normalized = GH_BUF_INIT; + unsigned char *result; + + if (ref->len == 0) + return NULL; utf8proc_case_fold(&normalized, ref->data, ref->len); strbuf_trim(&normalized); strbuf_normalize_whitespace(&normalized); - return strbuf_detach(&normalized); + result = strbuf_detach(&normalized); + assert(result); + + if (result[0] == '\0') { + free(result); + return NULL; + } + + return result; } static void add_reference(reference_map *map, reference* ref) @@ -51,19 +65,23 @@ static void add_reference(reference_map *map, reference* ref) map->table[ref->hash % REFMAP_SIZE] = ref; } -extern reference *reference_create(reference_map *map, chunk *label, chunk *url, chunk *title) +extern void reference_create(reference_map *map, chunk *label, chunk *url, chunk *title) { reference *ref; + unsigned char *reflabel = normalize_reference(label); + + /* empty reference name, or composed from only whitespace */ + if (reflabel == NULL) + return; + ref = malloc(sizeof(reference)); - ref->label = normalize_reference(label); + ref->label = reflabel; ref->hash = refhash(ref->label); ref->url = clean_url(url); ref->title = clean_title(title); ref->next = NULL; add_reference(map, ref); - - return ref; } // Returns reference if refmap contains a reference with matching @@ -78,6 +96,9 @@ reference* reference_lookup(reference_map *map, chunk *label) return NULL; norm = normalize_reference(label); + if (norm == NULL) + return NULL; + hash = refhash(norm); ref = map->table[hash % REFMAP_SIZE]; -- cgit v1.2.3 From 118e3d3c39242225baa876319cdbfbb1adadc77b Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 15 Sep 2014 15:28:49 +0200 Subject: Cleanup external APIs --- src/references.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/references.c') diff --git a/src/references.c b/src/references.c index 300bbcc..3e54b48 100644 --- a/src/references.c +++ b/src/references.c @@ -1,6 +1,7 @@ #include "stmd.h" #include "utf8.h" #include "references.h" +#include "inlines.h" static unsigned int refhash(const unsigned char *link_ref) -- cgit v1.2.3