summaryrefslogtreecommitdiff
path: root/css
diff options
context:
space:
mode:
Diffstat (limited to 'css')
-rw-r--r--css/css.c78
-rw-r--r--css/css.h6
-rw-r--r--css/parser.y42
-rw-r--r--css/scanner.l3
4 files changed, 129 insertions, 0 deletions
diff --git a/css/css.c b/css/css.c
index 9287096f3..6ff243b18 100644
--- a/css/css.c
+++ b/css/css.c
@@ -870,6 +870,69 @@ bool css_match_detail(const struct css_selector *detail,
match = true;
break;
+ case CSS_SELECTOR_ATTRIB_PRE:
+ /* matches if the attribute begins with a certain
+ * value (CSS3) */
+ word = strndup(detail->data, detail->data_length);
+ if (!word) {
+ /** \todo report to user */
+ return false;
+ }
+ s = (char *)xmlGetProp(element,
+ (const xmlChar *) word);
+ free(word);
+ if (s && strncasecmp(detail->data2, s,
+ detail->data2_length) == 0)
+ match = true;
+ break;
+
+ case CSS_SELECTOR_ATTRIB_SUF:
+ /* matches if the attribute ends with a certain
+ * value (CSS3) */
+ word = strndup(detail->data, detail->data_length);
+ if (!word) {
+ /** \todo report to user */
+ return false;
+ }
+ s = (char *)xmlGetProp(element,
+ (const xmlChar *) word);
+ free(word);
+ if (!s)
+ break;
+ word = s + (strlen(s) - detail->data2_length);
+ if (s && strncasecmp(detail->data2, word,
+ detail->data2_length) == 0)
+ match = true;
+ break;
+
+ case CSS_SELECTOR_ATTRIB_SUB:
+ /* matches if the attribute contains a certain
+ * value (CSS3) */
+ word = strndup(detail->data, detail->data_length);
+ if (!word) {
+ /** \todo report to user */
+ return false;
+ }
+ s = (char *)xmlGetProp(element,
+ (const xmlChar *) word);
+ free(word);
+ if (!s)
+ break;
+ /* case insensitive strstr follows */
+ /* space -> last possible start position */
+ /* word -> start of string to search */
+ space = s + (strlen(s) - detail->data2_length);
+ word = s;
+ while (word <= space) {
+ if (strncasecmp(detail->data2, word,
+ detail->data2_length) == 0) {
+ match = true;
+ break;
+ }
+ word++;
+ }
+ break;
+
case CSS_SELECTOR_PSEUDO:
break;
@@ -1336,6 +1399,21 @@ void css_dump_selector(const struct css_selector *r)
m->data_length, m->data,
m->data2_length, m->data2);
break;
+ case CSS_SELECTOR_ATTRIB_PRE:
+ fprintf(stderr, "[%.*s^=%.*s]",
+ m->data_length, m->data,
+ m->data2_length, m->data2);
+ break;
+ case CSS_SELECTOR_ATTRIB_SUF:
+ fprintf(stderr, "[%.*s$=%.*s]",
+ m->data_length, m->data,
+ m->data2_length, m->data2);
+ break;
+ case CSS_SELECTOR_ATTRIB_SUB:
+ fprintf(stderr, "[%.*s*=%.*s]",
+ m->data_length, m->data,
+ m->data2_length, m->data2);
+ break;
case CSS_SELECTOR_PSEUDO:
fprintf(stderr, ":%.*s",
m->data_length, m->data);
diff --git a/css/css.h b/css/css.h
index f3b476d0b..5a8af7ca1 100644
--- a/css/css.h
+++ b/css/css.h
@@ -222,6 +222,9 @@ typedef enum {
CSS_SELECTOR_ATTRIB_EQ,
CSS_SELECTOR_ATTRIB_INC,
CSS_SELECTOR_ATTRIB_DM,
+ CSS_SELECTOR_ATTRIB_PRE,
+ CSS_SELECTOR_ATTRIB_SUF,
+ CSS_SELECTOR_ATTRIB_SUB,
CSS_SELECTOR_PSEUDO,
} css_selector_type;
@@ -263,6 +266,9 @@ typedef enum {
CSS_NODE_INCLUDES,
CSS_NODE_FUNCTION,
CSS_NODE_DASHMATCH,
+ CSS_NODE_PREFIX,
+ CSS_NODE_SUFFIX,
+ CSS_NODE_SUBSTR,
CSS_NODE_COLON,
CSS_NODE_COMMA,
CSS_NODE_DOT,
diff --git a/css/parser.y b/css/parser.y
index 1dd567ff1..f043ef823 100644
--- a/css/parser.y
+++ b/css/parser.y
@@ -185,6 +185,36 @@ detail(A) ::= LBRAC IDENT(B) DASHMATCH STRING(C) RBRAC.
if (A) { A->data2 = C.text + 1; A->data2_length = C.length - 2;
A->specificity = 0x100; }
else param->memory_error = true; }
+detail(A) ::= LBRAC IDENT(B) PREFIX IDENT(C) RBRAC.
+ { A = css_new_selector(CSS_SELECTOR_ATTRIB_PRE, B.text, B.length);
+ if (A) { A->data2 = C.text; A->data2_length = C.length;
+ A->specificity = 0x100; }
+ else param->memory_error = true; }
+detail(A) ::= LBRAC IDENT(B) PREFIX STRING(C) RBRAC.
+ { A = css_new_selector(CSS_SELECTOR_ATTRIB_PRE, B.text, B.length);
+ if (A) { A->data2 = C.text + 1; A->data2_length = C.length - 2;
+ A->specificity = 0x100; }
+ else param->memory_error = true; }
+detail(A) ::= LBRAC IDENT(B) SUFFIX IDENT(C) RBRAC.
+ { A = css_new_selector(CSS_SELECTOR_ATTRIB_SUF, B.text, B.length);
+ if (A) { A->data2 = C.text; A->data2_length = C.length;
+ A->specificity = 0x100; }
+ else param->memory_error = true; }
+detail(A) ::= LBRAC IDENT(B) SUFFIX STRING(C) RBRAC.
+ { A = css_new_selector(CSS_SELECTOR_ATTRIB_SUF, B.text, B.length);
+ if (A) { A->data2 = C.text + 1; A->data2_length = C.length - 2;
+ A->specificity = 0x100; }
+ else param->memory_error = true; }
+detail(A) ::= LBRAC IDENT(B) SUBSTR IDENT(C) RBRAC.
+ { A = css_new_selector(CSS_SELECTOR_ATTRIB_SUB, B.text, B.length);
+ if (A) { A->data2 = C.text; A->data2_length = C.length;
+ A->specificity = 0x100; }
+ else param->memory_error = true; }
+detail(A) ::= LBRAC IDENT(B) SUBSTR STRING(C) RBRAC.
+ { A = css_new_selector(CSS_SELECTOR_ATTRIB_SUB, B.text, B.length);
+ if (A) { A->data2 = C.text + 1; A->data2_length = C.length - 2;
+ A->specificity = 0x100; }
+ else param->memory_error = true; }
detail(A) ::= COLON IDENT(B).
{ if (B.length == 4 && strncasecmp(B.text, "link", 4) == 0) {
A = css_new_selector(CSS_SELECTOR_ATTRIB, "href", 4);
@@ -297,6 +327,18 @@ any(A) ::= DASHMATCH.
{ A = css_new_node(param->stylesheet, CSS_NODE_DASHMATCH,
0, 0);
if (!A) param->memory_error = true; }
+any(A) ::= PREFIX.
+ { A = css_new_node(param->stylesheet, CSS_NODE_PREFIX,
+ 0, 0);
+ if (!A) param->memory_error = true; }
+any(A) ::= SUFFIX.
+ { A = css_new_node(param->stylesheet, CSS_NODE_SUFFIX,
+ 0, 0);
+ if (!A) param->memory_error = true; }
+any(A) ::= SUBSTR.
+ { A = css_new_node(param->stylesheet, CSS_NODE_SUBSTR,
+ 0, 0);
+ if (!A) param->memory_error = true; }
any(A) ::= COLON.
{ A = css_new_node(param->stylesheet, CSS_NODE_COLON, 0, 0);
if (!A) param->memory_error = true; }
diff --git a/css/scanner.l b/css/scanner.l
index 36347b3a8..708a9ebe8 100644
--- a/css/scanner.l
+++ b/css/scanner.l
@@ -86,6 +86,9 @@ ident "(" { return FUNCTION; }
"=" { return EQUALS; }
"~=" { return INCLUDES; }
"|=" { return DASHMATCH; }
+"^=" { return PREFIX; }
+"$=" { return SUFFIX; }
+"*=" { return SUBSTR; }
":" { return COLON; }
"," { return COMMA; }
"+" { return PLUS; }