aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/HtmlSearch.c103
1 files changed, 88 insertions, 15 deletions
diff --git a/src/HtmlSearch.c b/src/HtmlSearch.c
index b5aef91..b7801b9 100644
--- a/src/HtmlSearch.c
+++ b/src/HtmlSearch.c
@@ -4,6 +4,87 @@
#include <tidy.h>
#include <tidybuffio.h>
+static void string_init(QuickMediaString *self) {
+ self->data = NULL;
+ self->size = 0;
+ self->capacity = 0;
+}
+
+static void string_deinit(QuickMediaString *self) {
+ free(self->data);
+ self->data = NULL;
+ self->size = 0;
+ self->capacity = 0;
+}
+
+static int string_append(QuickMediaString *self, const char *str, size_t size) {
+ size_t new_capacity = self->capacity;
+ if(new_capacity == 0) {
+ new_capacity = 8;
+ }
+
+ size_t new_size = self->size + size;
+ while(new_size + 1 > new_capacity) {
+ new_capacity += (new_capacity >> 1);
+ }
+
+ void *new_data = realloc(self->data, new_capacity);
+ if(!new_data) {
+ fprintf(stderr, "Failed to realloc %p to size: %zu\n", (void*)self->data, new_capacity);
+ return 1;
+ }
+
+ memcpy((char*)new_data + self->size, str, size);
+ ((char*)new_data)[self->size + size] = '\0';
+ self->data = (char*)new_data;
+ self->size = new_size;
+ self->capacity = new_capacity;
+ return 0;
+}
+
+static void lstrip_newline(const char *str, size_t size, const char **output_str, size_t *output_size) {
+ size_t i = 0;
+ while(i < size && str[i] == '\n') {
+ ++i;
+ }
+ *output_str = str + i;
+ *output_size = size - i;
+}
+
+static void rstrip_newline(const char *str, size_t size, size_t *output_size) {
+ ssize_t i = size - 1;
+ while(i >= 0 && str[i] == '\n') {
+ --i;
+ }
+ *output_size = i + 1;
+}
+
+static void strip_newline(const char *str, size_t size, const char **output_str, size_t *output_size) {
+ lstrip_newline(str, size, output_str, output_size);
+ rstrip_newline(*output_str, *output_size, output_size);
+}
+
+static int add_inner_text_recursive(const TidyDoc doc, const TidyNode node, QuickMediaString *str) {
+ for(TidyNode child = tidyGetChild(node); child; child = tidyGetNext(child)) {
+ if(tidyNodeGetType(child) == TidyNode_Text) {
+ TidyBuffer tidy_buffer;
+ tidyBufInit(&tidy_buffer);
+ if(tidyNodeGetText(doc, child, &tidy_buffer)) {
+ const char *inner_text = (const char*)tidy_buffer.bp;
+ size_t inner_text_size = tidy_buffer.size;
+ strip_newline(inner_text, inner_text_size, &inner_text, &inner_text_size);
+ string_append(str, inner_text, inner_text_size);
+ }
+ tidyBufFree(&tidy_buffer);
+ } else {
+ int res = add_inner_text_recursive(doc, child, str);
+ if(res != 0)
+ return res;
+ }
+ }
+ return 0;
+}
+
static TidyAttr get_attribute_by_name(TidyNode node, const char *name) {
assert(name);
for(TidyAttr attr = tidyAttrFirst(node); attr; attr = tidyAttrNext(attr)) {
@@ -31,12 +112,9 @@ static void find_child_nodes(TidyDoc tdoc, TidyNode node, const QuickMediaNodeSe
QuickMediaHtmlNode node; \
node.doc = tdoc; \
node.node = child; \
- node.text = NULL; \
+ string_init(&node.text); \
result_callback(&node, userdata); \
- if(node.text){ \
- tidyBufFree(node.text); \
- free(node.text); \
- } \
+ string_deinit(&node.text); \
} \
} while(0)
@@ -76,18 +154,13 @@ const char* quickmedia_html_node_get_attribute_value(QuickMediaHtmlNode *self, c
}
const char* quickmedia_html_node_get_text(QuickMediaHtmlNode *self) {
- if(self->text)
- return (const char*)((TidyBuffer*)self->text)->bp;
-
- TidyNode child_node = tidyGetChild(self->node);
- if(tidyNodeGetType(child_node) != TidyNode_Text)
- return NULL;
+ if(self->text.data)
+ return self->text.data;
- self->text = malloc(sizeof(TidyBuffer));
- tidyBufInit(self->text);
- tidyNodeGetText(self->doc, child_node, self->text);
+ if(add_inner_text_recursive((TidyDoc)self->doc, (TidyNode)self->node, &self->text) != 0)
+ string_append(&self->text, " ", 1);
- return (const char*)((TidyBuffer*)self->text)->bp;
+ return self->text.data;
}
static int quickmedia_html_find_nodes(QuickMediaHtmlSearch *self, QuickMediaNodeSearch *search_data, QuickMediaHtmlSearchResultCallback result_callback, void *userdata) {