<libroxml  version="3.0.0" />
contact: tristan.lelong@libroxml.net
roxml_xpath.c
Go to the documentation of this file.
1 
11 #include <stdlib.h>
12 #include <string.h>
13 #include "roxml_mem.h"
14 #include "roxml_core.h"
15 #include "roxml_xpath.h"
16 #include "roxml_parser.h"
17 
25 ROXML_STATIC ROXML_INT int roxml_is_number(char *input)
26 {
27  char *end;
28  int is_number = 0;
29 
30  /*
31  * we don't need the value per se and some compiler will
32  * complain about an initialized but unused variable if we
33  * get it.
34  */
35  roxml_strtonum(input, &end);
36 
37  if ((end == NULL) ||
38  (roxml_is_separator(end[0])) ||
39  (end[0] == '"') ||
40  (end[0] == '\'') ||
41  (end[0] == '\0')) {
42  is_number = 1;
43  }
44 
45  return is_number;
46 }
47 
55 ROXML_STATIC ROXML_INT void roxml_free_xcond(xpath_cond_t *xcond)
56 {
57  if (xcond->next)
58  roxml_free_xcond(xcond->next);
59  if (xcond->xp)
60  roxml_free_xpath(xcond->xp, xcond->func2);
61  free(xcond);
62 }
63 
64 ROXML_INT void roxml_free_xpath(xpath_node_t *xpath, int nb)
65 {
66  int i = 0;
67  for (i = 0; i < nb; i++) {
68  if (xpath[i].next)
69  roxml_free_xpath(xpath[i].next, 1);
70  if (xpath[i].cond)
71  roxml_free_xcond(xpath[i].cond);
72  free(xpath[i].xp_cond);
73  }
74  free(xpath);
75 }
76 
86 ROXML_STATIC ROXML_INT int roxml_in_pool(node_t *root, node_t *n, int req_id)
87 {
88  roxml_lock(root);
89  if (n->priv) {
90  xpath_tok_t *tok = (xpath_tok_t *)n->priv;
91  if (tok->id == req_id) {
92  roxml_unlock(root);
93  return 1;
94  } else {
95  while (tok) {
96  if (tok->id == req_id) {
97  roxml_unlock(root);
98  return 1;
99  }
100  tok = tok->next;
101  }
102  }
103  }
104  roxml_unlock(root);
105 
106  return 0;
107 }
108 
118 ROXML_STATIC ROXML_INT void roxml_del_from_pool(node_t *root, node_t *n, int req_id)
119 {
120  roxml_lock(root);
121  if (n->priv) {
122  xpath_tok_t *prev = (xpath_tok_t *)n->priv;
123  xpath_tok_t *tok = (xpath_tok_t *)n->priv;
124  if (tok->id == req_id) {
125  n->priv = (void *)tok->next;
126  free(tok);
127  } else {
128  while (tok) {
129  if (tok->id == req_id) {
130  prev->next = tok->next;
131  free(tok);
132  break;
133  }
134  prev = tok;
135  tok = tok->next;
136  }
137  }
138  }
139  roxml_unlock(root);
140 }
141 
152 ROXML_STATIC ROXML_INT int roxml_add_to_pool(node_t *root, node_t *n, int req_id)
153 {
154  xpath_tok_t *tok;
155  xpath_tok_t *last_tok = NULL;
156 
157  if (req_id == 0)
158  return 1;
159 
160  roxml_lock(root);
161  tok = (xpath_tok_t *)n->priv;
162 
163  while (tok) {
164  if (tok->id == req_id) {
165  roxml_unlock(root);
166  return 0;
167  }
168  last_tok = tok;
169  tok = (xpath_tok_t *)tok->next;
170  }
171  if (last_tok == NULL) {
172  n->priv = calloc(1, sizeof(xpath_tok_t));
173  last_tok = (xpath_tok_t *)n->priv;
174  } else {
175  last_tok->next = calloc(1, sizeof(xpath_tok_t));
176  last_tok = last_tok->next;
177  }
178  last_tok->id = req_id;
179  roxml_unlock(root);
180 
181  return 1;
182 }
183 
194 ROXML_STATIC ROXML_INT void roxml_release_id(node_t *root, node_t **pool, int pool_len, int req_id)
195 {
196  int i;
197  xpath_tok_table_t *table = (xpath_tok_table_t *)root->priv;
198 
199  for (i = 0; i < pool_len; i++)
200  roxml_del_from_pool(root, pool[i], req_id);
201 
202  roxml_lock(root);
203  table->ids[req_id] = 0;
204  roxml_unlock(root);
205 }
206 
214 ROXML_STATIC ROXML_INT int roxml_request_id(node_t *root)
215 {
216  int i = 0;
217  xpath_tok_table_t *table = (xpath_tok_table_t *)root->priv;
218 
219  roxml_lock(root);
220  for (i = ROXML_XPATH_FIRST_ID; i < 255; i++) {
221  if (table->ids[i] == 0) {
222  table->ids[i]++;
223  roxml_unlock(root);
224  return i;
225  }
226  }
227  roxml_unlock(root);
228 
229  return -1;
230 }
231 
242 ROXML_STATIC ROXML_INT void roxml_compute_and(node_t *root, node_t **node_set, int *count, int cur_req_id,
243  int prev_req_id)
244 {
245  int i = 0;
246  int limit = *count;
247  int pool1 = 0, pool2 = 0;
248 
249  for (i = 0; i < limit; i++) {
250  if (pool1 == 0)
251  if (roxml_in_pool(root, node_set[i], cur_req_id))
252  pool1++;
253  if (pool2 == 0)
254  if (roxml_in_pool(root, node_set[i], prev_req_id))
255  pool2++;
256  if (pool1 && pool2)
257  break;
258  }
259 
260  if (!pool1 || !pool2) {
261  for (i = 0; i < limit; i++) {
262  roxml_del_from_pool(root, node_set[i], cur_req_id);
263  roxml_del_from_pool(root, node_set[i], prev_req_id);
264  }
265  *count = 0;
266  }
267 }
268 
280 ROXML_STATIC ROXML_INT void roxml_compute_or(node_t *root, node_t **node_set, int *count, int req_id, int glob_id)
281 {
282  int i = 0;
283  for (i = 0; i < *count; i++) {
284  if (roxml_in_pool(root, node_set[i], req_id)) {
285  roxml_add_to_pool(root, node_set[i], glob_id);
286  roxml_del_from_pool(root, node_set[i], req_id);
287  }
288  }
289 }
290 
300 ROXML_STATIC ROXML_INT int roxml_parse_xpath(char *path, xpath_node_t **xpath, int context)
301 {
302  int ret = 0;
303  roxml_xpath_ctx_t ctx;
304  roxml_parser_item_t *parser = NULL;
305  ctx.pos = 0;
306  ctx.nbpath = 1;
307  ctx.bracket = 0;
308  ctx.parenthesys = 0;
309  ctx.quoted = 0;
310  ctx.dquoted = 0;
311  ctx.content_quoted = 0;
312  ctx.is_first_node = 1;
313  ctx.wait_first_node = 1;
314  ctx.shorten_cond = 0;
315  ctx.context = context;
316  ctx.first_node = calloc(1, sizeof(xpath_node_t));
317  ctx.new_node = ctx.first_node;
318  ctx.new_cond = NULL;
319  ctx.first_node->rel = ROXML_OPERATOR_OR;
320 
321  parser = roxml_append_parser_item(parser, " ", _func_xpath_ignore);
322  parser = roxml_append_parser_item(parser, "\t", _func_xpath_ignore);
323  parser = roxml_append_parser_item(parser, "\n", _func_xpath_ignore);
324  parser = roxml_append_parser_item(parser, "\r", _func_xpath_ignore);
325  parser = roxml_append_parser_item(parser, "\"", _func_xpath_dquote);
326  parser = roxml_append_parser_item(parser, "\'", _func_xpath_quote);
327  parser = roxml_append_parser_item(parser, "/", _func_xpath_new_node);
328  parser = roxml_append_parser_item(parser, "(", _func_xpath_open_parenthesys);
329  parser = roxml_append_parser_item(parser, ")", _func_xpath_close_parenthesys);
330  parser = roxml_append_parser_item(parser, "[", _func_xpath_open_brackets);
331  parser = roxml_append_parser_item(parser, "]", _func_xpath_close_brackets);
332  parser = roxml_append_parser_item(parser, "=", _func_xpath_operator_equal);
333  parser = roxml_append_parser_item(parser, ">", _func_xpath_operator_sup);
334  parser = roxml_append_parser_item(parser, "<", _func_xpath_operator_inf);
335  parser = roxml_append_parser_item(parser, "!", _func_xpath_operator_diff);
336  parser = roxml_append_parser_item(parser, "0", _func_xpath_number);
337  parser = roxml_append_parser_item(parser, "1", _func_xpath_number);
338  parser = roxml_append_parser_item(parser, "2", _func_xpath_number);
339  parser = roxml_append_parser_item(parser, "3", _func_xpath_number);
340  parser = roxml_append_parser_item(parser, "4", _func_xpath_number);
341  parser = roxml_append_parser_item(parser, "5", _func_xpath_number);
342  parser = roxml_append_parser_item(parser, "6", _func_xpath_number);
343  parser = roxml_append_parser_item(parser, "7", _func_xpath_number);
344  parser = roxml_append_parser_item(parser, "8", _func_xpath_number);
345  parser = roxml_append_parser_item(parser, "9", _func_xpath_number);
346  parser = roxml_append_parser_item(parser, "+", _func_xpath_operator_add);
347  parser = roxml_append_parser_item(parser, "-", _func_xpath_operator_subs);
348  parser = roxml_append_parser_item(parser, ROXML_PATH_OR, _func_xpath_path_or);
349  parser = roxml_append_parser_item(parser, ROXML_COND_OR, _func_xpath_condition_or);
350  parser = roxml_append_parser_item(parser, ROXML_COND_AND, _func_xpath_condition_and);
351  parser = roxml_append_parser_item(parser, ROXML_FUNC_POS_STR, _func_xpath_position);
352  parser = roxml_append_parser_item(parser, ROXML_FUNC_FIRST_STR, _func_xpath_first);
353  parser = roxml_append_parser_item(parser, ROXML_FUNC_LAST_STR, _func_xpath_last);
354  parser = roxml_append_parser_item(parser, ROXML_FUNC_NSURI_STR, _func_xpath_nsuri);
355  parser = roxml_append_parser_item(parser, ROXML_FUNC_LNAME_STR, _func_xpath_lname);
356  parser = roxml_append_parser_item(parser, "", _func_xpath_default);
357 
358  parser = roxml_parser_prepare(parser);
359  ret = roxml_parse_line(parser, path, 0, &ctx);
360  roxml_parser_free(parser);
361 
362  if (ret >= 0) {
363  if (xpath)
364  *xpath = ctx.first_node;
365  return ctx.nbpath;
366  }
367 
369  return -1;
370 }
371 
379 ROXML_STATIC ROXML_INT int roxml_get_node_internal_position(node_t *n)
380 {
381  int idx = 1;
382  node_t *prnt;
383  node_t *first;
384  if (n == NULL)
385  return 0;
386 
387  prnt = n->prnt;
388  if (!prnt)
389  return 1;
390  first = prnt->chld;
391 
392  while ((first) && (first != n)) {
393  idx++;
394  first = first->sibl;
395  }
396 
397  return idx;
398 }
399 
409 ROXML_STATIC ROXML_INT double roxml_double_oper(double a, double b, int op)
410 {
411  if (op == ROXML_OPERATOR_ADD)
412  return (a + b);
413  else if (op == ROXML_OPERATOR_SUB)
414  return (a - b);
415  else if (op == ROXML_OPERATOR_MUL)
416  return (a * b);
417  else if (op == ROXML_OPERATOR_DIV)
418  return (a / b);
419  return 0;
420 }
421 
431 ROXML_STATIC ROXML_INT int roxml_double_cmp(double a, double b, int op)
432 {
433  if (op == ROXML_OPERATOR_DIFF)
434  return (a != b);
435  else if (op == ROXML_OPERATOR_EINF)
436  return (a <= b);
437  else if (op == ROXML_OPERATOR_INF)
438  return (a < b);
439  else if (op == ROXML_OPERATOR_ESUP)
440  return (a >= b);
441  else if (op == ROXML_OPERATOR_SUP)
442  return (a > b);
443  else if (op == ROXML_OPERATOR_EQU)
444  return (a == b);
445  return 0;
446 }
447 
457 ROXML_STATIC ROXML_INT int roxml_string_cmp(char *sa, char *sb, int op)
458 {
459  int result;
460 
461  if (!sa)
462  sa = "";
463  if (!sb)
464  sb = "";
465 
466  result = strcmp(sa, sb);
467 
468  if (op == ROXML_OPERATOR_DIFF)
469  return (result != 0);
470  else if (op == ROXML_OPERATOR_EINF)
471  return (result <= 0);
472  else if (op == ROXML_OPERATOR_INF)
473  return (result < 0);
474  else if (op == ROXML_OPERATOR_ESUP)
475  return (result >= 0);
476  else if (op == ROXML_OPERATOR_SUP)
477  return (result > 0);
478  else if (op == ROXML_OPERATOR_EQU)
479  return (result == 0);
480  return 0;
481 }
482 
492 ROXML_STATIC ROXML_INT int roxml_validate_predicat(xpath_node_t *xn, xpath_cond_t *condition, node_t *candidat)
493 {
494  int valid;
495 
496  if (!condition)
497  return 1;
498 
499  valid = (condition->rel == ROXML_OPERATOR_AND);
500 
501  while (condition) {
502  int status = 0;
503  double iarg2 = 1;
504  double iarg1 = 0;
505  char *sarg1 = NULL;
506  node_t *val = candidat;
507  node_t **node_set;
508 
509  if (xn->name[0] == '*')
510  iarg1 = roxml_get_node_internal_position(candidat);
511  else
512  iarg1 = roxml_get_node_position(candidat);
513 
514  switch (condition->func) {
515  case ROXML_FUNC_POS:
516  iarg2 = roxml_strtonum(condition->arg2, NULL);
517  status = roxml_double_cmp(iarg1, iarg2, condition->op);
518  break;
519  case ROXML_FUNC_LAST:
520  iarg2 = roxml_get_chld_nb(candidat->prnt);
521  case ROXML_FUNC_FIRST:
522  if (condition->op > 0)
523  iarg2 = roxml_double_oper(iarg2, roxml_strtonum(condition->arg2, NULL), condition->op);
524  status = roxml_double_cmp(iarg1, iarg2, ROXML_OPERATOR_EQU);
525  break;
526  case ROXML_FUNC_INTCOMP:
527  if (condition->arg1)
528  val = roxml_get_attr(candidat, condition->arg1 + 1, 0);
529  sarg1 = roxml_get_content(val, NULL, 0, &status);
530  iarg1 = roxml_strtonum(sarg1, NULL);
531  iarg2 = roxml_strtonum(condition->arg2, NULL);
532  status = roxml_double_cmp(iarg1, iarg2, condition->op);
533  roxml_release(sarg1);
534  break;
535  case ROXML_FUNC_NSURI:
536  val = roxml_get_ns(candidat);
537  sarg1 = roxml_get_content(val, NULL, 0, &status);
538  status = roxml_string_cmp(sarg1, condition->arg2, condition->op);
539  break;
540  case ROXML_FUNC_STRCOMP:
541  if (condition->arg1)
542  val = roxml_get_attr(candidat, condition->arg1 + 1, 0);
543  sarg1 = roxml_get_content(val, NULL, 0, &status);
544  status = roxml_string_cmp(sarg1, condition->arg2, condition->op);
545  break;
546  case ROXML_FUNC_LNAME:
547  sarg1 = roxml_get_name(candidat, NULL, 0);
548  status = strcmp(sarg1, condition->arg2) == 0;
549  roxml_release(sarg1);
550  break;
551  case ROXML_FUNC_XPATH:
552  val = roxml_get_root(candidat);
553  node_set = roxml_exec_xpath(val, candidat, condition->xp, condition->func2, &status);
554  roxml_release(node_set);
555  status = ! !status;
556  break;
557  default:
558  break;
559  }
560 
561  if (condition->rel == ROXML_OPERATOR_OR)
562  valid = valid || status;
563  else if (condition->rel == ROXML_OPERATOR_AND)
564  valid = valid && status;
565  else
566  valid = status;
567 
568  condition = condition->next;
569  }
570 
571  return valid;
572 }
573 
574 ROXML_STATIC ROXML_INT void roxml_add_to_set(node_t *root, node_t *candidat, node_t ***ans, int *nb, int *max,
575  int req_id)
576 {
577  if (roxml_add_to_pool(root, candidat, req_id)) {
578  if (ans) {
579  if ((*nb) >= (*max)) {
580  int new_max = (*max) * 2;
581  node_t **new_ans = roxml_malloc(sizeof(node_t *), new_max, PTR_NODE_RESULT);
582  memcpy(new_ans, (*ans), *(max) * sizeof(node_t *));
583  roxml_release(*ans);
584  *ans = new_ans;
585  *max = new_max;
586  }
587  (*ans)[*nb] = candidat;
588  }
589  (*nb)++;
590  }
591 }
592 
593 ROXML_STATIC ROXML_INT int roxml_validate_axe_func(node_t *root, node_t **candidat, xpath_node_t *xn)
594 {
595  int valid = 0;
596  char *axes = xn->name;
597  int type = (*candidat)->type;
598 
599  if ((axes == NULL) || (strcmp("node()", axes) == 0)) {
600  valid = 1;
601  } else if (strcmp("*", axes) == 0) {
602  if (type & (ROXML_ELM_NODE | ROXML_ATTR_NODE))
603  valid = 1;
604  } else if (strcmp("comment()", axes) == 0) {
605  if (type & ROXML_CMT_NODE)
606  valid = 1;
607  } else if (strcmp("processing-instruction()", axes) == 0) {
608  if (type & ROXML_PI_NODE)
609  valid = 1;
610  } else if (strcmp("text()", axes) == 0) {
611  if (type & ROXML_TXT_NODE)
612  valid = 1;
613  } else if (strcmp("", axes) == 0) {
614  if (xn->abs) {
615  *candidat = root;
616  valid = 1;
617  }
618  }
619 
620  /* comments and pi can only be reached using their comment()
621  * and processing-instruction() functions */
622  if (!valid)
623  if (type & (ROXML_PI_NODE | ROXML_CMT_NODE))
624  return -1;
625  return valid;
626 }
627 
628 ROXML_STATIC ROXML_INT int roxml_validate_axe_name(node_t *candidat, xpath_node_t *xn)
629 {
630  int valid = 0;
631  int ns_len;
632  char *name;
633 
634  ROXML_GET_BASE_BUFFER(intern_buff);
635 
636  if (candidat->ns) {
637  name = roxml_get_name(candidat->ns, intern_buff, ROXML_BASE_LEN);
638  ns_len = strlen(name);
639  if (ns_len)
640  name[ns_len++] = ':';
641  } else {
642  ns_len = 0;
643  name = intern_buff;
644  }
645 
646  roxml_get_name(candidat, name + ns_len, ROXML_BASE_LEN - ns_len);
647  if (name && strcmp(name, xn->name) == 0)
648  valid = 1;
649 
650  ROXML_PUT_BASE_BUFFER(intern_buff);
651 
652  return valid;
653 }
654 
668 ROXML_STATIC ROXML_INT int roxml_validate_axes(node_t *root, node_t *candidat, node_t ***ans, int *nb, int *max,
669  xpath_node_t *xn, int req_id)
670 {
671  int valid = 0;
672  int path_end = 0;
673  xpath_node_t empty;
674 
675  if (xn == NULL) {
676  valid = 1;
677  path_end = 1;
678  xn = &empty;
679  memset(xn, 0, sizeof(empty));
680  } else {
681  valid = roxml_validate_axe_func(root, &candidat, xn);
682 
683  if (xn->next == NULL)
684  path_end = 1;
685  if ((xn->axes == ROXML_ID_SELF) || (xn->axes == ROXML_ID_PARENT))
686  valid = 1;
687 
688  if (valid == 0)
689  valid = roxml_validate_axe_name(candidat, xn);
690  }
691 
692  if (valid == 1)
693  valid = roxml_validate_predicat(xn, xn->cond, candidat);
694  if (valid == 1)
695  valid = roxml_validate_predicat(xn, xn->xp_cond, candidat);
696 
697  if ((valid == 1) && (path_end))
698  roxml_add_to_set(root, candidat, ans, nb, max, req_id);
699 
700  return (valid == 1);
701 }
702 
717 ROXML_STATIC ROXML_INT void roxml_check_node(xpath_node_t *xp, node_t *root, node_t *context, node_t ***ans,
718  int *nb, int *max, int ignore, int req_id)
719 {
720  int validate_node = 0;
721 
722  if ((req_id == 0) && (*nb > 0))
723  return;
724 
725  if (!xp)
726  return;
727 
728  // if found a "all document" axes
729  if (ignore == ROXML_DESC_ONLY) {
730  node_t *current = context->chld;
731  while (current) {
732  roxml_check_node(xp, root, current, ans, nb, max, ignore, req_id);
733  current = current->sibl;
734  }
735  }
736 
737  switch (xp->axes) {
738  case ROXML_ID_CHILD:{
739  node_t *current = context->chld;
740  while (current) {
741  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
742  if (validate_node)
743  roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
744  current = current->sibl;
745  }
746  if ((xp->name == NULL) || (strcmp(xp->name, "text()") == 0)
747  || (strcmp(xp->name, "node()") == 0)) {
748  node_t *current = roxml_get_txt(context, 0);
749  while (current) {
750  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
751  current = current->sibl;
752  }
753  }
754  if ((xp->name == NULL) || (strcmp(xp->name, "node()") == 0)) {
755  node_t *current = context->attr;
756  while (current) {
757  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
758  current = current->sibl;
759  }
760  }
761  }
762  break;
763  case ROXML_ID_DESC:{
764  roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DESC_ONLY, req_id);
765  }
766  break;
767  case ROXML_ID_DESC_O_SELF:{
768  xp = xp->next;
769  validate_node = roxml_validate_axes(root, context, ans, nb, max, xp, req_id);
770  if (validate_node)
771  roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DIRECT, req_id);
772  roxml_check_node(xp, root, context, ans, nb, max, ROXML_DESC_ONLY, req_id);
773  }
774  break;
775  case ROXML_ID_SELF:{
776  validate_node = roxml_validate_axes(root, context, ans, nb, max, xp, req_id);
777  roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DIRECT, req_id);
778  }
779  break;
780  case ROXML_ID_PARENT:{
781  if (context->prnt) {
782  validate_node = roxml_validate_axes(root, context->prnt, ans, nb, max, xp, req_id);
783  roxml_check_node(xp->next, root, context->prnt, ans, nb, max, ROXML_DIRECT, req_id);
784  } else {
785  validate_node = 0;
786  }
787  }
788  break;
789  case ROXML_ID_ATTR:{
790  node_t *attribute = context->attr;
791  while (attribute) {
792  validate_node = roxml_validate_axes(root, attribute, ans, nb, max, xp, req_id);
793  if (validate_node)
794  roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DIRECT, req_id);
795  attribute = attribute->sibl;
796  }
797  }
798  break;
799  case ROXML_ID_ANC:{
800  node_t *current = context->prnt;
801  while (current) {
802  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
803  if (validate_node)
804  roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
805  current = current->prnt;
806  }
807  }
808  break;
809  case ROXML_ID_NEXT_SIBL:{
810  node_t *current = context->sibl;
811  while (current) {
812  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
813  if (validate_node)
814  roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
815  current = current->sibl;
816  }
817  }
818  break;
819  case ROXML_ID_PREV_SIBL:{
820  node_t *current = context->prnt->chld;
821  while (current != context) {
822  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
823  if (validate_node)
824  roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
825  current = current->sibl;
826  }
827  }
828  break;
829  case ROXML_ID_NEXT:{
830  node_t *current = context;
831  while (current) {
832  node_t *following = current->sibl;
833  while (following) {
834  validate_node = roxml_validate_axes(root, following, ans, nb, max, xp, req_id);
835  if (validate_node) {
836  roxml_check_node(xp->next, root, following, ans, nb, max, ROXML_DIRECT,
837  req_id);
838  } else {
839  xp->axes = ROXML_ID_CHILD;
840  roxml_check_node(xp, root, following, ans, nb, max, ROXML_DESC_ONLY,
841  req_id);
842  xp->axes = ROXML_ID_NEXT;
843  }
844  following = following->sibl;
845  }
846  following = current->prnt->chld;
847  while (following != current)
848  following = following->sibl;
849  current = following->sibl;
850  }
851  }
852  break;
853  case ROXML_ID_PREV:{
854  node_t *current = context;
855  while (current && current->prnt) {
856  node_t *preceding = current->prnt->chld;
857  while (preceding != current) {
858  validate_node = roxml_validate_axes(root, preceding, ans, nb, max, xp, req_id);
859  if (validate_node) {
860  roxml_check_node(xp->next, root, preceding, ans, nb, max, ROXML_DIRECT,
861  req_id);
862  } else {
863  xp->axes = ROXML_ID_CHILD;
864  roxml_check_node(xp, root, preceding, ans, nb, max, ROXML_DESC_ONLY,
865  req_id);
866  xp->axes = ROXML_ID_PREV;
867  }
868  preceding = preceding->sibl;
869  }
870  current = current->prnt;
871  }
872  }
873  break;
874  case ROXML_ID_NS:{
875  validate_node = roxml_validate_axes(root, context->ns, ans, nb, max, xp, req_id);
876  if (validate_node)
877  roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DIRECT, req_id);
878  }
879  break;
880  case ROXML_ID_ANC_O_SELF:{
881  node_t *current = context;
882  while (current) {
883  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
884  if (validate_node)
885  roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
886  current = current->prnt;
887  }
888  }
889  break;
890  }
891 
892  return;
893 }
894 
895 ROXML_INT node_t **roxml_exec_xpath(node_t *root, node_t *n, xpath_node_t *xpath, int index, int *count)
896 {
897  int path_id;
898  int max_answers = 1;
899  int glob_id = 0;
900  int *req_ids = NULL;
901  node_t **node_set;
902 
903  *count = 0;
904  glob_id = roxml_request_id(root);
905  if (glob_id < 0)
906  return NULL;
907  req_ids = calloc(index, sizeof(int));
908  node_set = roxml_malloc(sizeof(node_t *), max_answers, PTR_NODE_RESULT);
909 
910  /* process all AND xpath */
911  for (path_id = 0; path_id < index; path_id++) {
912  xpath_node_t *cur_xpath = NULL;
913  xpath_node_t *next_xpath = NULL;
914  cur_xpath = &xpath[path_id];
915 
916  if (path_id < index - 1)
917  next_xpath = &xpath[path_id + 1];
918 
919  if ((cur_xpath->rel == ROXML_OPERATOR_AND) || ((next_xpath) && (next_xpath->rel == ROXML_OPERATOR_AND))) {
920  int req_id = roxml_request_id(root);
921  node_t *orig = n;
922 
923  if (cur_xpath->abs)
924  /* context node is root */
925  orig = root;
926 
927  roxml_check_node(cur_xpath, root, orig, &node_set, count, &max_answers, ROXML_DIRECT, req_id);
928 
929  if (cur_xpath->rel == ROXML_OPERATOR_AND)
930  roxml_compute_and(root, node_set, count, req_id, req_ids[path_id - 1]);
931  req_ids[path_id] = req_id;
932  }
933  }
934 
935  /* process all OR xpath */
936  for (path_id = 0; path_id < index; path_id++) {
937  xpath_node_t *cur_xpath = &xpath[path_id];
938 
939  if (cur_xpath->rel == ROXML_OPERATOR_OR) {
940  node_t *orig = n;
941 
942  if (req_ids[path_id] == 0) {
943  if (cur_xpath->abs)
944  orig = root;
945 
946  /* assign a new request ID */
947  roxml_check_node(cur_xpath, root, orig, &node_set, count, &max_answers, ROXML_DIRECT,
948  glob_id);
949  } else {
950  roxml_compute_or(root, node_set, count, req_ids[path_id + 1], glob_id);
951  roxml_release_id(root, node_set, *count, req_ids[path_id + 1]);
952  }
953  }
954  }
955 
956  roxml_release_id(root, node_set, *count, glob_id);
957 
958  for (path_id = 0; path_id < index; path_id++)
959  if (req_ids[path_id] != 0)
960  roxml_release_id(root, node_set, *count, req_ids[path_id]);
961  free(req_ids);
962 
963  return node_set;
964 }
965 
966 ROXML_API node_t **roxml_xpath(node_t *n, char *path, int *nb_ans)
967 {
968  int count = 0;
969  node_t **node_set = NULL;
970  int index = 0;
971  xpath_node_t *xpath = NULL;
972  node_t *root = n;
973  char *full_path_to_find;
974 
975  if (n == ROXML_INVALID_DOC) {
976  if (nb_ans)
977  *nb_ans = 0;
978  return NULL;
979  }
980 
981  root = roxml_get_root(n);
982 
983  full_path_to_find = strdup(path);
984 
985  index = roxml_parse_xpath(full_path_to_find, &xpath, 0);
986 
987  if (index >= 0) {
988  node_set = roxml_exec_xpath(root, n, xpath, index, &count);
989  roxml_free_xpath(xpath, index);
990 
991  if (count == 0) {
992  roxml_release(node_set);
993  node_set = NULL;
994  }
995  }
996  if (nb_ans)
997  *nb_ans = count;
998  free(full_path_to_find);
999 
1000  return node_set;
1001 }
1002 
1012 ROXML_STATIC ROXML_INT xpath_node_t *roxml_set_axes(xpath_node_t *node, char *axes, int *offset)
1013 {
1014  struct _xpath_axes {
1015  char id;
1016  char *name;
1017  };
1018 
1019  struct _xpath_axes xpath_axes[14] = {
1020  {ROXML_ID_PARENT, ROXML_L_PARENT},
1021  {ROXML_ID_PARENT, ROXML_S_PARENT},
1022  {ROXML_ID_SELF, ROXML_L_SELF},
1023  {ROXML_ID_SELF, ROXML_S_SELF},
1024  {ROXML_ID_ATTR, ROXML_L_ATTR},
1025  {ROXML_ID_ATTR, ROXML_S_ATTR},
1026  {ROXML_ID_ANC, ROXML_L_ANC},
1027  {ROXML_ID_ANC_O_SELF, ROXML_L_ANC_O_SELF},
1028  {ROXML_ID_NEXT_SIBL, ROXML_L_NEXT_SIBL},
1029  {ROXML_ID_PREV_SIBL, ROXML_L_PREV_SIBL},
1030  {ROXML_ID_NEXT, ROXML_L_NEXT},
1031  {ROXML_ID_PREV, ROXML_L_PREV},
1032  {ROXML_ID_NS, ROXML_L_NS},
1033  {ROXML_ID_CHILD, ROXML_L_CHILD},
1034  };
1035 
1036  xpath_node_t *tmp_node;
1037  if (axes[0] == '/') {
1038  axes[0] = '\0';
1039  *offset += 1;
1040  axes++;
1041  }
1042  if (axes[0] == '/') {
1043  /* ROXML_S_DESC_O_SELF */
1044  node->axes = ROXML_ID_DESC_O_SELF;
1045  node->name = axes + 1;
1046  tmp_node = calloc(1, sizeof(xpath_node_t));
1047  tmp_node->axes = ROXML_ID_CHILD;
1048  node->next = tmp_node;
1049  if (strlen(node->name) > 0) {
1050  tmp_node = calloc(1, sizeof(xpath_node_t));
1051  node->next->next = tmp_node;
1052  node = roxml_set_axes(tmp_node, axes + 1, offset);
1053  }
1054  } else if (strncmp(ROXML_L_DESC_O_SELF, axes, strlen(ROXML_L_DESC_O_SELF)) == 0) {
1055  /* ROXML_L_DESC_O_SELF */
1056  node->axes = ROXML_ID_DESC_O_SELF;
1057  node->name = axes + strlen(ROXML_L_DESC_O_SELF);
1058  *offset += strlen(ROXML_L_DESC_O_SELF);
1059  tmp_node = calloc(1, sizeof(xpath_node_t));
1060  tmp_node->axes = ROXML_ID_CHILD;
1061  node->next = tmp_node;
1062  node = roxml_set_axes(tmp_node, axes + strlen(ROXML_L_DESC_O_SELF), offset);
1063  } else if (strncmp(ROXML_L_DESC, axes, strlen(ROXML_L_DESC)) == 0) {
1064  /* ROXML_L_DESC */
1065  node->axes = ROXML_ID_DESC;
1066  node->name = axes + strlen(ROXML_L_DESC);
1067  *offset += strlen(ROXML_L_DESC);
1068  tmp_node = calloc(1, sizeof(xpath_node_t));
1069  tmp_node->axes = ROXML_ID_CHILD;
1070  node->next = tmp_node;
1071  node = roxml_set_axes(tmp_node, axes + strlen(ROXML_L_DESC), offset);
1072  } else {
1073  int i = 0;
1074 
1075  /* ROXML_S_CHILD is default */
1076  node->axes = ROXML_ID_CHILD;
1077  node->name = axes;
1078 
1079  for (i = 0; i < 14; i++) {
1080  int len = strlen(xpath_axes[i].name);
1081  if (strncmp(xpath_axes[i].name, axes, len) == 0) {
1082  node->axes = xpath_axes[i].id;
1083  node->name = axes + len;
1084  break;
1085  }
1086  }
1087  }
1088  return node;
1089 }
1090 
1091 ROXML_INT int _func_xpath_ignore(roxml_parser_item_t *parser, char *chunk, void *data)
1092 {
1093 #ifdef DEBUG_PARSING
1094  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1095 #endif /* DEBUG_PARSING */
1096  return 1;
1097 }
1098 
1099 ROXML_INT int _func_xpath_new_node(roxml_parser_item_t *parser, char *chunk, void *data)
1100 {
1101  int cur = 0;
1102  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1103 #ifdef DEBUG_PARSING
1104  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1105 #endif /* DEBUG_PARSING */
1106  if (!ctx->quoted && !ctx->dquoted && !ctx->parenthesys && !ctx->bracket) {
1107  int offset = 0;
1108  xpath_node_t *tmp_node = calloc(1, sizeof(xpath_node_t));
1109  if ((chunk[cur] == '/') && (ctx->is_first_node)) {
1110  free(tmp_node);
1111  ctx->new_node = ctx->first_node;
1112  ctx->first_node->abs = 1;
1113  } else if ((chunk[cur] == '/') && (ctx->wait_first_node)) {
1114  free(tmp_node);
1115  ctx->first_node->abs = 1;
1116  } else if ((ctx->is_first_node) || (ctx->wait_first_node)) {
1117  free(tmp_node);
1118  } else {
1119  if (ctx->new_node)
1120  ctx->new_node->next = tmp_node;
1121  ctx->new_node = tmp_node;
1122  }
1123  ctx->is_first_node = 0;
1124  ctx->wait_first_node = 0;
1125  ctx->new_node = roxml_set_axes(ctx->new_node, chunk + cur, &offset);
1126  cur = offset + 1;
1127  }
1128  ctx->shorten_cond = 0;
1129  return cur;
1130 }
1131 
1132 ROXML_INT int _func_xpath_quote(roxml_parser_item_t *parser, char *chunk, void *data)
1133 {
1134  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1135 #ifdef DEBUG_PARSING
1136  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1137 #endif /* DEBUG_PARSING */
1138  if (!ctx->dquoted) {
1139  if (ctx->quoted && ctx->content_quoted == MODE_COMMENT_QUOTE) {
1141  chunk[0] = '\0';
1142  }
1143  ctx->quoted = (ctx->quoted + 1) % 2;
1144  }
1145  ctx->shorten_cond = 0;
1146  return 1;
1147 }
1148 
1149 ROXML_INT int _func_xpath_dquote(roxml_parser_item_t *parser, char *chunk, void *data)
1150 {
1151  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1152 #ifdef DEBUG_PARSING
1153  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1154 #endif /* DEBUG_PARSING */
1155  if (!ctx->quoted) {
1156  if (ctx->dquoted && ctx->content_quoted == MODE_COMMENT_DQUOTE) {
1158  chunk[0] = '\0';
1159  }
1160  ctx->dquoted = (ctx->dquoted + 1) % 2;
1161  }
1162  ctx->shorten_cond = 0;
1163  return 1;
1164 }
1165 
1166 ROXML_INT int _func_xpath_open_parenthesys(roxml_parser_item_t *parser, char *chunk, void *data)
1167 {
1168  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1169 #ifdef DEBUG_PARSING
1170  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1171 #endif /* DEBUG_PARSING */
1172  if (!ctx->quoted && !ctx->dquoted)
1173  ctx->parenthesys = (ctx->parenthesys + 1) % 2;
1174  ctx->shorten_cond = 0;
1175  return 1;
1176 }
1177 
1178 ROXML_INT int _func_xpath_close_parenthesys(roxml_parser_item_t *parser, char *chunk, void *data)
1179 {
1180  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1181 #ifdef DEBUG_PARSING
1182  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1183 #endif /* DEBUG_PARSING */
1184  if (!ctx->quoted && !ctx->dquoted)
1185  ctx->parenthesys = (ctx->parenthesys + 1) % 2;
1186  ctx->shorten_cond = 0;
1187  return 1;
1188 }
1189 
1190 ROXML_INT int _func_xpath_open_brackets(roxml_parser_item_t *parser, char *chunk, void *data)
1191 {
1192  xpath_cond_t *tmp_cond;
1193  int cur = 0;
1194 #ifdef DEBUG_PARSING
1195  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1196 #endif /* DEBUG_PARSING */
1197  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1198  if (!ctx->quoted && !ctx->dquoted) {
1199  ctx->bracket = (ctx->bracket + 1) % 2;
1200  chunk[0] = '\0';
1201 
1202  ctx->shorten_cond = 1;
1203  tmp_cond = calloc(1, sizeof(xpath_cond_t));
1204  ctx->new_node->cond = tmp_cond;
1205  ctx->new_cond = tmp_cond;
1206  ctx->new_cond->arg1 = chunk + cur + 1;
1207  } else {
1208  ctx->shorten_cond = 0;
1209  }
1210  cur++;
1211  return 1;
1212 }
1213 
1214 ROXML_INT int _func_xpath_close_brackets(roxml_parser_item_t *parser, char *chunk, void *data)
1215 {
1216  int cur = 0;
1217  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1218 #ifdef DEBUG_PARSING
1219  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1220 #endif /* DEBUG_PARSING */
1221  if (!ctx->quoted && !ctx->dquoted) {
1222  ctx->bracket = (ctx->bracket + 1) % 2;
1223  chunk[0] = '\0';
1224 
1225  if (ctx->new_cond) {
1226  if (ctx->new_cond->func == ROXML_FUNC_XPATH) {
1227  xpath_node_t *xp;
1228  ctx->new_cond->func2 = roxml_parse_xpath(ctx->new_cond->arg1, &xp, 1);
1229  ctx->new_cond->xp = xp;
1230  }
1231  } else {
1232  return -1;
1233  }
1234  }
1235  cur++;
1236  ctx->shorten_cond = 0;
1237  return 1;
1238 }
1239 
1240 ROXML_INT int _func_xpath_condition_or(roxml_parser_item_t *parser, char *chunk, void *data)
1241 {
1242  xpath_node_t *tmp_node;
1243  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1244  int cur = 0;
1245  int len = 0;
1246  xpath_cond_t *tmp_cond;
1247 #ifdef DEBUG_PARSING
1248  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1249 #endif /* DEBUG_PARSING */
1250 
1251  len = strlen(ROXML_COND_OR);
1252 
1253  if (strncmp(chunk, ROXML_COND_OR, len) == 0) {
1254  if (roxml_is_separator(*(chunk - 1)) && roxml_is_separator(*(chunk + len))) {
1255  if (!ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1256  if (ctx->context != 1) {
1257  return 0;
1258  }
1259  chunk[-1] = '\0';
1260  cur += strlen(ROXML_COND_OR);
1261  tmp_node = calloc(ctx->nbpath + 1, sizeof(xpath_node_t));
1262  memcpy(tmp_node, ctx->first_node, ctx->nbpath * sizeof(xpath_node_t));
1263  free(ctx->first_node);
1264  ctx->first_node = tmp_node;
1265  ctx->wait_first_node = 1;
1266  ctx->new_node = tmp_node + ctx->nbpath;
1267  ctx->new_node->rel = ROXML_OPERATOR_OR;
1268  ctx->nbpath++;
1269  } else if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1270  if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1271  chunk[-1] = '\0';
1272  cur += strlen(ROXML_COND_OR);
1273  tmp_cond = calloc(1, sizeof(xpath_cond_t));
1274  if (ctx->new_cond) {
1275  ctx->new_cond->next = tmp_cond;
1276  }
1277  ctx->new_cond = tmp_cond;
1278  ctx->new_cond->rel = ROXML_OPERATOR_OR;
1279  ctx->new_cond->arg1 = chunk + cur + 1;
1280  }
1281  }
1282  }
1283  }
1284  if (cur)
1285  ctx->shorten_cond = 0;
1286  return cur;
1287 }
1288 
1289 ROXML_INT int _func_xpath_condition_and(roxml_parser_item_t *parser, char *chunk, void *data)
1290 {
1291  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1292  int cur = 0;
1293  int len = 0;
1294  xpath_node_t *tmp_node;
1295  xpath_cond_t *tmp_cond;
1296 #ifdef DEBUG_PARSING
1297  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1298 #endif /* DEBUG_PARSING */
1299 
1300  len = strlen(ROXML_COND_AND);
1301 
1302  if (strncmp(chunk, ROXML_COND_AND, len) == 0) {
1303  if (roxml_is_separator(*(chunk - 1)) && roxml_is_separator(*(chunk + len))) {
1304  if (!ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1305  if (ctx->context != 1)
1306  return 0;
1307  chunk[-1] = '\0';
1308  cur += strlen(ROXML_COND_AND);
1309  tmp_node = calloc(ctx->nbpath + 1, sizeof(xpath_node_t));
1310  memcpy(tmp_node, ctx->first_node, ctx->nbpath * sizeof(xpath_node_t));
1311  free(ctx->first_node);
1312  ctx->first_node = tmp_node;
1313  ctx->wait_first_node = 1;
1314  ctx->new_node = tmp_node + ctx->nbpath;
1315  ctx->new_node->rel = ROXML_OPERATOR_AND;
1316  ctx->nbpath++;
1317  } else if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1318  if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1319  chunk[-1] = '\0';
1320  cur += strlen(ROXML_COND_AND);
1321  tmp_cond = calloc(1, sizeof(xpath_cond_t));
1322  if (ctx->new_cond) {
1323  ctx->new_cond->next = tmp_cond;
1324  }
1325  ctx->new_cond = tmp_cond;
1326  ctx->new_cond->rel = ROXML_OPERATOR_AND;
1327  ctx->new_cond->arg1 = chunk + cur + 1;
1328  }
1329  }
1330  }
1331  }
1332  if (cur)
1333  ctx->shorten_cond = 0;
1334  return cur;
1335 }
1336 
1337 ROXML_INT int _func_xpath_path_or(roxml_parser_item_t *parser, char *chunk, void *data)
1338 {
1339  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1340  int cur = 0;
1341  xpath_node_t *tmp_node;
1342 #ifdef DEBUG_PARSING
1343  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1344 #endif /* DEBUG_PARSING */
1345 
1346  if (!ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1347  chunk[-1] = '\0';
1348  cur += strlen(ROXML_PATH_OR);
1349  tmp_node = calloc(ctx->nbpath + 1, sizeof(xpath_node_t));
1350  memcpy(tmp_node, ctx->first_node, ctx->nbpath * sizeof(xpath_node_t));
1351  free(ctx->first_node);
1352  ctx->first_node = tmp_node;
1353  ctx->wait_first_node = 1;
1354  ctx->new_node = tmp_node + ctx->nbpath;
1355  ctx->new_node->rel = ROXML_OPERATOR_OR;
1356  ctx->nbpath++;
1357  }
1358  ctx->shorten_cond = 0;
1359  return cur;
1360 }
1361 
1362 ROXML_INT int _func_xpath_operators(roxml_parser_item_t *parser, char *chunk, void *data, int operator, int operator_bis)
1363 {
1364  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1365  int cur = 0;
1366  if (!ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1367  xpath_node_t *xp_root = ctx->new_node;
1368  xpath_cond_t *xp_cond = calloc(1, sizeof(xpath_cond_t));
1369  xp_root->xp_cond = xp_cond;
1370  chunk[cur] = '\0';
1371  xp_cond->op = operator;
1372  if (ROXML_WHITE(chunk[cur - 1]))
1373  chunk[cur - 1] = '\0';
1374  if (chunk[cur + 1] == '=') {
1375  chunk[++cur] = '\0';
1376  xp_cond->op = operator_bis;
1377  }
1378  if (ROXML_WHITE(chunk[cur + 1]))
1379  chunk[++cur] = '\0';
1380 
1381  xp_cond->arg2 = chunk + cur + 1;
1382  if (xp_cond->arg2[0] == '"') {
1384  xp_cond->arg2++;
1385  } else if (xp_cond->arg2[0] == '\'') {
1387  xp_cond->arg2++;
1388  }
1389  if (!xp_cond->func) {
1390  xp_cond->func = ROXML_FUNC_INTCOMP;
1391  if (!roxml_is_number(xp_cond->arg2))
1392  xp_cond->func = ROXML_FUNC_STRCOMP;
1393  }
1394  cur++;
1395  } else if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1396  if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1397  chunk[cur] = '\0';
1398  ctx->new_cond->op = operator;
1399  if (ROXML_WHITE(chunk[cur - 1]))
1400  chunk[cur - 1] = '\0';
1401  if (chunk[cur + 1] == '=') {
1402  chunk[++cur] = '\0';
1403  ctx->new_cond->op = operator_bis;
1404  }
1405  if (ROXML_WHITE(chunk[cur + 1]))
1406  chunk[++cur] = '\0';
1407  ctx->new_cond->arg2 = chunk + cur + 1;
1408  if (ctx->new_cond->arg2[0] == '"') {
1410  ctx->new_cond->arg2++;
1411  } else if (ctx->new_cond->arg2[0] == '\'') {
1413  ctx->new_cond->arg2++;
1414  }
1415  if (ctx->new_cond->func == 0) {
1416  ctx->new_cond->func = ROXML_FUNC_INTCOMP;
1417  if (!roxml_is_number(ctx->new_cond->arg2))
1418  ctx->new_cond->func = ROXML_FUNC_STRCOMP;
1419  }
1420  cur++;
1421  }
1422  }
1423  ctx->shorten_cond = 0;
1424  return cur;
1425 }
1426 
1427 ROXML_INT int _func_xpath_operator_equal(roxml_parser_item_t *parser, char *chunk, void *data)
1428 {
1429 #ifdef DEBUG_PARSING
1430  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1431 #endif /* DEBUG_PARSING */
1432  return _func_xpath_operators(parser, chunk, data, ROXML_OPERATOR_EQU, ROXML_OPERATOR_EQU);
1433 }
1434 
1435 ROXML_INT int _func_xpath_operator_sup(roxml_parser_item_t *parser, char *chunk, void *data)
1436 {
1437 #ifdef DEBUG_PARSING
1438  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1439 #endif /* DEBUG_PARSING */
1440  return _func_xpath_operators(parser, chunk, data, ROXML_OPERATOR_SUP, ROXML_OPERATOR_ESUP);
1441 }
1442 
1443 ROXML_INT int _func_xpath_operator_inf(roxml_parser_item_t *parser, char *chunk, void *data)
1444 {
1445 #ifdef DEBUG_PARSING
1446  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1447 #endif /* DEBUG_PARSING */
1448  return _func_xpath_operators(parser, chunk, data, ROXML_OPERATOR_INF, ROXML_OPERATOR_EINF);
1449 }
1450 
1451 ROXML_INT int _func_xpath_operator_diff(roxml_parser_item_t *parser, char *chunk, void *data)
1452 {
1453 #ifdef DEBUG_PARSING
1454  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1455 #endif /* DEBUG_PARSING */
1456  return _func_xpath_operators(parser, chunk, data, ROXML_OPERATOR_DIFF, ROXML_OPERATOR_DIFF);
1457 }
1458 
1459 ROXML_INT int _func_xpath_number(roxml_parser_item_t *parser, char *chunk, void *data)
1460 {
1461 #ifdef DEBUG_PARSING
1462  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1463 #endif /* DEBUG_PARSING */
1464  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1465  int cur = 0;
1466  if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1467  if ((ctx->new_cond->func != ROXML_FUNC_XPATH) && (ctx->shorten_cond)) {
1468  cur = 1;
1469  ctx->new_cond->func = ROXML_FUNC_POS;
1470  ctx->new_cond->op = ROXML_OPERATOR_EQU;
1471  ctx->new_cond->arg2 = chunk;
1472  while ((chunk[cur + 1] >= '0') && (chunk[cur + 1] <= '9'))
1473  cur++;
1474  }
1475  }
1476  ctx->shorten_cond = 0;
1477  return cur;
1478 }
1479 
1480 ROXML_INT int _func_xpath_funcs(roxml_parser_item_t *parser, char *chunk, void *data, int func, char *name)
1481 {
1482 #ifdef DEBUG_PARSING
1483  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1484 #endif /* DEBUG_PARSING */
1485  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1486  int cur = 0;
1487 
1488  if (strncmp(chunk, name, strlen(name)) == 0) {
1489  if (ctx->new_cond->func != func) {
1490  cur += strlen(name);
1491  ctx->new_cond->func = func;
1492  }
1493  }
1494  if (cur)
1495  ctx->shorten_cond = 0;
1496  return cur;
1497 }
1498 
1499 ROXML_INT int _func_xpath_position(roxml_parser_item_t *parser, char *chunk, void *data)
1500 {
1501 #ifdef DEBUG_PARSING
1502  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1503 #endif /* DEBUG_PARSING */
1504  return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_POS, ROXML_FUNC_POS_STR);
1505 }
1506 
1507 ROXML_INT int _func_xpath_first(roxml_parser_item_t *parser, char *chunk, void *data)
1508 {
1509 #ifdef DEBUG_PARSING
1510  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1511 #endif /* DEBUG_PARSING */
1512  return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_FIRST, ROXML_FUNC_FIRST_STR);
1513 }
1514 
1515 ROXML_INT int _func_xpath_last(roxml_parser_item_t *parser, char *chunk, void *data)
1516 {
1517 #ifdef DEBUG_PARSING
1518  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1519 #endif /* DEBUG_PARSING */
1520  return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_LAST, ROXML_FUNC_LAST_STR);
1521 }
1522 
1523 ROXML_INT int _func_xpath_nsuri(roxml_parser_item_t *parser, char *chunk, void *data)
1524 {
1525 #ifdef DEBUG_PARSING
1526  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1527 #endif /* DEBUG_PARSING */
1528  return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_NSURI, ROXML_FUNC_NSURI_STR);
1529 }
1530 
1531 ROXML_INT int _func_xpath_lname(roxml_parser_item_t *parser, char *chunk, void *data)
1532 {
1533 #ifdef DEBUG_PARSING
1534  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1535 #endif /* DEBUG_PARSING */
1536  return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_LNAME, ROXML_FUNC_LNAME_STR);
1537 }
1538 
1539 ROXML_INT int _func_xpath_operator_add(roxml_parser_item_t *parser, char *chunk, void *data)
1540 {
1541 #ifdef DEBUG_PARSING
1542  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1543 #endif /* DEBUG_PARSING */
1544  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1545  int cur = 0;
1546  if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1547  if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1548  if ((ctx->new_cond->func == ROXML_FUNC_LAST) || (ctx->new_cond->func == ROXML_FUNC_FIRST))
1549  ctx->new_cond->op = ROXML_OPERATOR_ADD;
1550  chunk[cur] = '\0';
1551  if (ROXML_WHITE(chunk[cur + 1]))
1552  chunk[++cur] = '\0';
1553  ctx->new_cond->arg2 = chunk + cur + 1;
1554  }
1555  }
1556  ctx->shorten_cond = 0;
1557  return cur;
1558 }
1559 
1560 ROXML_INT int _func_xpath_operator_subs(roxml_parser_item_t *parser, char *chunk, void *data)
1561 {
1562 #ifdef DEBUG_PARSING
1563  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1564 #endif /* DEBUG_PARSING */
1565  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1566  int cur = 0;
1567  if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1568  if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1569  if ((ctx->new_cond->func == ROXML_FUNC_LAST) || (ctx->new_cond->func == ROXML_FUNC_FIRST))
1570  ctx->new_cond->op = ROXML_OPERATOR_SUB;
1571  chunk[cur] = '\0';
1572  if (ROXML_WHITE(chunk[cur + 1]))
1573  chunk[++cur] = '\0';
1574  ctx->new_cond->arg2 = chunk + cur + 1;
1575  }
1576  }
1577  ctx->shorten_cond = 0;
1578  return cur;
1579 }
1580 
1581 ROXML_INT int _func_xpath_default(roxml_parser_item_t *parser, char *chunk, void *data)
1582 {
1583 #ifdef DEBUG_PARSING
1584  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1585 #endif /* DEBUG_PARSING */
1586  int cur = 0;
1587  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1588 
1589  if ((ctx->is_first_node) || (ctx->wait_first_node)) {
1590  if (!ctx->quoted && !ctx->dquoted && !ctx->parenthesys && !ctx->bracket) {
1591  int offset = 0;
1592  xpath_node_t *tmp_node = calloc(1, sizeof(xpath_node_t));
1593  if ((chunk[cur] == '/') && (ctx->is_first_node)) {
1594  free(tmp_node);
1595  ctx->new_node = ctx->first_node;
1596  ctx->first_node->abs = 1;
1597  } else if ((chunk[cur] == '/') && (ctx->wait_first_node)) {
1598  free(tmp_node);
1599  ctx->first_node->abs = 1;
1600  } else if ((ctx->is_first_node) || (ctx->wait_first_node)) {
1601  free(tmp_node);
1602  } else {
1603  if (ctx->new_node)
1604  ctx->new_node->next = tmp_node;
1605  ctx->new_node = tmp_node;
1606  }
1607  ctx->is_first_node = 0;
1608  ctx->wait_first_node = 0;
1609  ctx->new_node = roxml_set_axes(ctx->new_node, chunk + cur, &offset);
1610  cur += offset;
1611  }
1612  } else if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1613  if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1614  if (ctx->shorten_cond) {
1615  int bracket_lvl = 1;
1616  ctx->new_cond->func = ROXML_FUNC_XPATH;
1617  ctx->new_cond->arg1 = chunk + cur;
1618  while (bracket_lvl > 0) {
1619  if (chunk[cur] == '[')
1620  bracket_lvl++;
1621  else if (chunk[cur] == ']')
1622  bracket_lvl--;
1623  cur++;
1624  }
1625  cur--;
1626  }
1627  }
1628  }
1629  ctx->shorten_cond = 0;
1630  return cur > 0 ? cur : 1;
1631 }
#define PTR_NODE_RESULT
struct _roxml_parser_item * next
Definition: roxml_types.h:225
ROXML_API node_t * roxml_get_ns(node_t *n)
namespace getter function
xpath_node_t * new_node
Definition: roxml_types.h:202
#define ROXML_INVALID_DOC
Definition: roxml.h:195
ROXML_API node_t * roxml_get_txt(node_t *n, int nth)
text node getter function
ROXML_STATIC ROXML_INT int roxml_add_to_pool(node_t *root, node_t *n, int req_id)
add a token top node function
Definition: roxml_xpath.c:152
node_t structure
Definition: roxml_types.h:133
ROXML_STATIC ROXML_INT int roxml_request_id(node_t *root)
id reservation function
Definition: roxml_xpath.c:214
ROXML_API int roxml_get_chld_nb(node_t *n)
chlds number getter function
struct _xpath_cond * next
Definition: roxml_types.h:66
ROXML_API void roxml_release(void *data)
memory cleanning function
Definition: roxml_mem.c:109
struct node * attr
Definition: roxml_types.h:145
ROXML_STATIC ROXML_INT void roxml_free_xcond(xpath_cond_t *xcond)
xpath condition free function
Definition: roxml_xpath.c:55
ROXML_INT roxml_parser_item_t * roxml_append_parser_item(roxml_parser_item_t *parser, char *key, roxml_parse_func func)
parser item creation function
Definition: roxml_parser.c:41
#define ROXML_ATTR_NODE
Definition: roxml.h:51
ROXML_INT int roxml_is_separator(char sep)
separator tester
Definition: roxml_core.c:128
ROXML_STATIC ROXML_INT int roxml_get_node_internal_position(node_t *n)
node absolute position get
Definition: roxml_xpath.c:379
xpath_node_t * first_node
Definition: roxml_types.h:201
ROXML_STATIC ROXML_INT int roxml_parse_xpath(char *path, xpath_node_t **xpath, int context)
xpath parsing function
Definition: roxml_xpath.c:300
ROXML_API node_t * roxml_get_attr(node_t *n, char *name, int nth)
attribute getter function
#define ROXML_PI_NODE
Definition: roxml.h:94
ROXML_STATIC ROXML_INT double roxml_double_oper(double a, double b, int op)
double operation function
Definition: roxml_xpath.c:409
struct node * chld
Definition: roxml_types.h:143
ROXML_INT int roxml_parse_line(roxml_parser_item_t *parser, char *line, int len, void *ctx)
line parsing function
Definition: roxml_parser.c:149
ROXML_STATIC ROXML_INT xpath_node_t * roxml_set_axes(xpath_node_t *node, char *axes, int *offset)
axes setter function
Definition: roxml_xpath.c:1012
#define MODE_COMMENT_DQUOTE
struct _xpath_tok * next
Definition: roxml_types.h:109
#define ROXML_API
Definition: roxml.h:24
#define MODE_COMMENT_NONE
char * arg2
Definition: roxml_types.h:64
struct node * sibl
Definition: roxml_types.h:142
xpath token structure
Definition: roxml_types.h:107
ROXML_STATIC ROXML_INT void roxml_compute_or(node_t *root, node_t **node_set, int *count, int req_id, int glob_id)
node set or function
Definition: roxml_xpath.c:280
char * arg1
Definition: roxml_types.h:63
ROXML_STATIC ROXML_INT int roxml_validate_axes(node_t *root, node_t *candidat, node_t ***ans, int *nb, int *max, xpath_node_t *xn, int req_id)
axe validation function
Definition: roxml_xpath.c:668
Parsing engine.
#define ROXML_CMT_NODE
Definition: roxml.h:86
xpath node structure
Definition: roxml_types.h:76
ROXML_INT void roxml_free_xpath(xpath_node_t *xpath, int nb)
xpath free function
Definition: roxml_xpath.c:64
ROXML_STATIC ROXML_INT int roxml_in_pool(node_t *root, node_t *n, int req_id)
node pool presence tester function
Definition: roxml_xpath.c:86
#define MODE_COMMENT_QUOTE
struct node * ns
Definition: roxml_types.h:147
XML parsing core module.
ROXML_API char * roxml_get_content(node_t *n, char *buffer, int bufsize, int *size)
content getter function
ROXML_STATIC ROXML_INT void roxml_check_node(xpath_node_t *xp, node_t *root, node_t *context, node_t ***ans, int *nb, int *max, int ignore, int req_id)
real xpath validation function
Definition: roxml_xpath.c:717
xpath execution module
ROXML_STATIC ROXML_INT void roxml_compute_and(node_t *root, node_t **node_set, int *count, int cur_req_id, int prev_req_id)
node set and function
Definition: roxml_xpath.c:242
char * name
Definition: roxml_types.h:80
struct _xpath_cond * cond
Definition: roxml_types.h:82
ROXML_API node_t ** roxml_xpath(node_t *n, char *path, int *nb_ans)
exec path function
Definition: roxml_xpath.c:966
ROXML_STATIC ROXML_INT int roxml_validate_predicat(xpath_node_t *xn, xpath_cond_t *condition, node_t *candidat)
predicat validation function
Definition: roxml_xpath.c:492
the parser item struct
#define ROXML_ELM_NODE
Definition: roxml.h:70
XML internal memory management module.
xpath parsing context
Definition: roxml_types.h:189
ROXML_API node_t * roxml_get_root(node_t *n)
root getter function
Definition: roxml_nav.c:55
void * priv
Definition: roxml_types.h:148
ROXML_INT node_t ** roxml_exec_xpath(node_t *root, node_t *n, xpath_node_t *xpath, int index, int *count)
real xpath execution
Definition: roxml_xpath.c:895
struct node * prnt
Definition: roxml_types.h:144
#define ROXML_WHITE(n)
#define ROXML_BASE_LEN
Definition: roxml_defines.h:91
struct _xpath_cond * xp_cond
Definition: roxml_types.h:81
ROXML_INT void roxml_parser_free(roxml_parser_item_t *parser)
parser table deletion
Definition: roxml_parser.c:100
unsigned char ids[256]
Definition: roxml_types.h:95
xpath cond structure
Definition: roxml_types.h:56
#define ROXML_TXT_NODE
Definition: roxml.h:78
ROXML_API char * roxml_get_name(node_t *n, char *buffer, int size)
name getter function
ROXML_STATIC ROXML_INT void roxml_release_id(node_t *root, node_t **pool, int pool_len, int req_id)
release id function
Definition: roxml_xpath.c:194
ROXML_INT void * roxml_malloc(int size, int num, int type)
alloc memory function
Definition: roxml_mem.c:124
ROXML_STATIC ROXML_INT int roxml_double_cmp(double a, double b, int op)
double comparison function
Definition: roxml_xpath.c:431
unsigned char id
Definition: roxml_types.h:108
struct _xpath_node * next
Definition: roxml_types.h:83
ROXML_API int roxml_get_node_position(node_t *n)
node get position function
ROXML_INT roxml_parser_item_t * roxml_parser_prepare(roxml_parser_item_t *parser)
parser preparation function
Definition: roxml_parser.c:105
struct _xpath_node * xp
Definition: roxml_types.h:65
ROXML_STATIC ROXML_INT void roxml_del_from_pool(node_t *root, node_t *n, int req_id)
pool node delete function
Definition: roxml_xpath.c:118
ROXML_STATIC ROXML_INT int roxml_string_cmp(char *sa, char *sb, int op)
string comparison function
Definition: roxml_xpath.c:457
xpath_cond_t * new_cond
Definition: roxml_types.h:203
ROXML_STATIC ROXML_INT int roxml_is_number(char *input)
number tester
Definition: roxml_xpath.c:25
xpath token structure
Definition: roxml_types.h:93