aboutsummaryrefslogtreecommitdiff
path: root/src/XpathParser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/XpathParser.c')
-rw-r--r--src/XpathParser.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/XpathParser.c b/src/XpathParser.c
new file mode 100644
index 0000000..24e1d6e
--- /dev/null
+++ b/src/XpathParser.c
@@ -0,0 +1,88 @@
+#include "../include/quickmedia/XpathParser.h"
+#include "../include/quickmedia/XpathTokenizer.h"
+#include <stdlib.h>
+
+typedef struct {
+ QuickMediaXpathTokenizer tokenizer;
+} QuickMediaXpathParser;
+
+static void quickmedia_xpath_parser_init(QuickMediaXpathParser *self, const char *xpath) {
+ quickmedia_xpath_tokenizer_init(&self->tokenizer, xpath);
+}
+
+/* ('[' IDENTIFIER '=' '"' STRING '"' ']')? */
+static int xpath_parse_param(QuickMediaXpathParser *self, QuickMediaNodeSearchParam *result) {
+ if(quickmedia_xpath_tokenizer_next_if(&self->tokenizer, QUICKMEDIA_XPATH_TOKEN_OPEN_BRACKET) != 0)
+ return 1;
+
+ QuickMediaXpathToken token = quickmedia_xpath_tokenizer_next(&self->tokenizer);
+ if(token != QUICKMEDIA_XPATH_TOKEN_IDENTIFIER)
+ return -1;
+
+ result->name = quickmedia_xpath_tokenizer_copy_identifier(&self->tokenizer);
+
+ token = quickmedia_xpath_tokenizer_next(&self->tokenizer);
+ if(token != QUICKMEDIA_XPATH_TOKEN_EQUAL)
+ return -2;
+
+ token = quickmedia_xpath_tokenizer_next(&self->tokenizer);
+ if(token != QUICKMEDIA_XPATH_TOKEN_STRING)
+ return -3;
+
+ result->value = quickmedia_xpath_tokenizer_copy_string(&self->tokenizer);
+
+ token = quickmedia_xpath_tokenizer_next(&self->tokenizer);
+ if(token != QUICKMEDIA_XPATH_TOKEN_CLOSING_BRACKET)
+ return -4;
+
+ return 0;
+}
+
+static int xpath_parse_node(QuickMediaXpathParser *self, QuickMediaNodeSearch *result) {
+ quickmedia_node_search_init(result);
+ QuickMediaXpathToken token = quickmedia_xpath_tokenizer_next(&self->tokenizer);
+ /* // or / */
+ if(token == QUICKMEDIA_XPATH_TOKEN_CHILD || token == QUICKMEDIA_XPATH_TOKEN_CHILD_RECURSIVE) {
+ result->recursive = (token == QUICKMEDIA_XPATH_TOKEN_CHILD_RECURSIVE);
+
+ token = quickmedia_xpath_tokenizer_next(&self->tokenizer);
+ if(token != QUICKMEDIA_XPATH_TOKEN_IDENTIFIER)
+ return -1;
+
+ result->name = quickmedia_xpath_tokenizer_copy_identifier(&self->tokenizer);
+
+ int param_result = xpath_parse_param(self, &result->param);
+ if(param_result < 0) {
+ quickmedia_node_search_deinit(result);
+ return param_result;
+ } else if(param_result == 0) {
+ result->param_defined = 1;
+ }
+
+ result->child = malloc(sizeof(QuickMediaNodeSearch));
+ int node_result = xpath_parse_node(self, result->child);
+ if(node_result > 0) {
+ node_result = 0;
+ /* Didn't have child, remove child */
+ free(result->child);
+ result->child = NULL;
+ } else if(node_result < 0) {
+ quickmedia_node_search_deinit(result);
+ }
+
+ return node_result;
+ } else if(token == QUICKMEDIA_XPATH_TOKEN_END_OF_FILE) {
+ return 1;
+ } else {
+ return -2;
+ }
+}
+
+int quickmedia_parse_xpath(const char *xpath, QuickMediaNodeSearch *result) {
+ QuickMediaXpathParser parser;
+ quickmedia_xpath_parser_init(&parser, xpath);
+ int parse_result = xpath_parse_node(&parser, result);
+ if(parse_result > 0)
+ parse_result = -1;
+ return parse_result;
+}