From 8f41cc827b3c4096da4cd770175f43a085231bbf Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 3 Jul 2021 17:11:39 +0200 Subject: Case insensitive tag and attribute key match --- README.md | 3 ++- src/HtmlSearch.c | 24 +++++++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0516066..b7f6ea6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ Html search using non-standard xpath, written in C. See tests/main.c # Note -This library does not decode html sequences in text and attribute values \ No newline at end of file +This library does not decode html sequences in text and attribute values. +Tag and attribute key matching is case-insensitive. \ No newline at end of file diff --git a/src/HtmlSearch.c b/src/HtmlSearch.c index 267ec6a..bc58881 100644 --- a/src/HtmlSearch.c +++ b/src/HtmlSearch.c @@ -118,16 +118,30 @@ static int str_glob_match(const QuickMediaStringView str, const QuickMediaString return 1; } -static int string_views_equal(const QuickMediaStringView str1, const QuickMediaStringView str2) { - if(str2.size == str1.size && memcmp(str2.data, str1.data, str1.size) == 0) - return 0; +static char to_upper(char c) { + if(c >= 'a' && c <= 'z') + return c - 32; else + return c; +} + +static int string_views_equal_case_insensitive(const QuickMediaStringView str1, const QuickMediaStringView str2) { + if(str2.size != str1.size) return 1; + + for(size_t i = 0; i < str1.size; ++i) { + char c1 = str1.data[i]; + char c2 = str2.data[i]; + if(to_upper(c1) != to_upper(c2)) + return 1; + } + + return 0; } static QuickMediaHtmlAttribute* get_attribute_by_name(QuickMediaHtmlNode *node, QuickMediaStringView name) { for(QuickMediaHtmlAttribute *attr = node->first_attribute; attr; attr = attr->next) { - if(string_views_equal(attr->key, name) == 0) + if(string_views_equal_case_insensitive(attr->key, name) == 0) return attr; } return NULL; @@ -144,7 +158,7 @@ static int find_child_nodes(QuickMediaHtmlChildNode *node, const QuickMediaNodeS continue; /* Match without node name or node name matches */ - if(search_data->name.size == 0 || string_views_equal(child->node.name, search_data->name) == 0) { + if(search_data->name.size == 0 || string_views_equal_case_insensitive(child->node.name, search_data->name) == 0) { #define on_match() do { \ if(search_data->child) { \ if(find_child_nodes(child->node.first_child, search_data->child, result_callback, userdata) != 0) \ -- cgit v1.2.3