<libroxml  version="3.0.2" />
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  // fall through
522  case ROXML_FUNC_FIRST:
523  if (condition->op > 0)
524  iarg2 = roxml_double_oper(iarg2, roxml_strtonum(condition->arg2, NULL), condition->op);
525  status = roxml_double_cmp(iarg1, iarg2, ROXML_OPERATOR_EQU);
526  break;
527  case ROXML_FUNC_INTCOMP:
528  if (condition->arg1)
529  val = roxml_get_attr(candidat, condition->arg1 + 1, 0);
530  sarg1 = roxml_get_content(val, NULL, 0, &status);
531  iarg1 = roxml_strtonum(sarg1, NULL);
532  iarg2 = roxml_strtonum(condition->arg2, NULL);
533  status = roxml_double_cmp(iarg1, iarg2, condition->op);
534  roxml_release(sarg1);
535  break;
536  case ROXML_FUNC_NSURI:
537  val = roxml_get_ns(candidat);
538  sarg1 = roxml_get_content(val, NULL, 0, &status);
539  status = roxml_string_cmp(sarg1, condition->arg2, condition->op);
540  roxml_release(sarg1);
541  break;
542  case ROXML_FUNC_STRCOMP:
543  if (condition->arg1)
544  val = roxml_get_attr(candidat, condition->arg1 + 1, 0);
545  sarg1 = roxml_get_content(val, NULL, 0, &status);
546  status = roxml_string_cmp(sarg1, condition->arg2, condition->op);
547  roxml_release(sarg1);
548  break;
549  case ROXML_FUNC_LNAME:
550  sarg1 = roxml_get_name(candidat, NULL, 0);
551  status = strcmp(sarg1, condition->arg2) == 0;
552  roxml_release(sarg1);
553  break;
554  case ROXML_FUNC_XPATH:
555  val = roxml_get_root(candidat);
556  node_set = roxml_exec_xpath(val, candidat, condition->xp, condition->func2, &status);
557  roxml_release(node_set);
558  status = ! !status;
559  break;
560  default:
561  break;
562  }
563 
564  if (condition->rel == ROXML_OPERATOR_OR)
565  valid = valid || status;
566  else if (condition->rel == ROXML_OPERATOR_AND)
567  valid = valid && status;
568  else
569  valid = status;
570 
571  condition = condition->next;
572  }
573 
574  return valid;
575 }
576 
577 ROXML_STATIC ROXML_INT void roxml_add_to_set(node_t *root, node_t *candidat, node_t ***ans, int *nb, int *max,
578  int req_id)
579 {
580  if (roxml_add_to_pool(root, candidat, req_id)) {
581  if (ans) {
582  if ((*nb) >= (*max)) {
583  int new_max = (*max) * 2;
584  node_t **new_ans = roxml_malloc(sizeof(node_t *), new_max, PTR_NODE_RESULT);
585  memcpy(new_ans, (*ans), *(max) * sizeof(node_t *));
586  roxml_release(*ans);
587  *ans = new_ans;
588  *max = new_max;
589  }
590  (*ans)[*nb] = candidat;
591  }
592  (*nb)++;
593  }
594 }
595 
596 ROXML_STATIC ROXML_INT int roxml_validate_axe_func(node_t *root, node_t **candidat, xpath_node_t *xn)
597 {
598  int valid = 0;
599  char *axes = xn->name;
600  int type = (*candidat)->type;
601 
602  if ((axes == NULL) || (strcmp("node()", axes) == 0)) {
603  valid = 1;
604  } else if (strcmp("*", axes) == 0) {
605  if (type & (ROXML_ELM_NODE | ROXML_ATTR_NODE))
606  valid = 1;
607  } else if (strcmp("comment()", axes) == 0) {
608  if (type & ROXML_CMT_NODE)
609  valid = 1;
610  } else if (strcmp("processing-instruction()", axes) == 0) {
611  if (type & ROXML_PI_NODE)
612  valid = 1;
613  } else if (strcmp("text()", axes) == 0) {
614  if (type & ROXML_TXT_NODE)
615  valid = 1;
616  } else if (strcmp("", axes) == 0) {
617  if (xn->abs) {
618  *candidat = root;
619  valid = 1;
620  }
621  }
622 
623  /* comments and pi can only be reached using their comment()
624  * and processing-instruction() functions */
625  if (!valid)
626  if (type & (ROXML_PI_NODE | ROXML_CMT_NODE))
627  return -1;
628  return valid;
629 }
630 
631 ROXML_STATIC ROXML_INT int roxml_validate_axe_name(node_t *candidat, xpath_node_t *xn)
632 {
633  int valid = 0;
634  int ns_len;
635  char *name;
636 
637  ROXML_GET_BASE_BUFFER(intern_buff);
638 
639  if (candidat->ns) {
640  name = roxml_get_name(candidat->ns, intern_buff, ROXML_BASE_LEN);
641  ns_len = strlen(name);
642  if (ns_len)
643  name[ns_len++] = ':';
644  } else {
645  ns_len = 0;
646  name = intern_buff;
647  }
648 
649  roxml_get_name(candidat, name + ns_len, ROXML_BASE_LEN - ns_len);
650  if (name && strcmp(name, xn->name) == 0)
651  valid = 1;
652 
653  ROXML_PUT_BASE_BUFFER(intern_buff);
654 
655  return valid;
656 }
657 
671 ROXML_STATIC ROXML_INT int roxml_validate_axes(node_t *root, node_t *candidat, node_t ***ans, int *nb, int *max,
672  xpath_node_t *xn, int req_id)
673 {
674  int valid = 0;
675  int path_end = 0;
676  xpath_node_t empty;
677 
678  if (xn == NULL) {
679  valid = 1;
680  path_end = 1;
681  xn = &empty;
682  memset(xn, 0, sizeof(empty));
683  } else {
684  valid = roxml_validate_axe_func(root, &candidat, xn);
685 
686  if (xn->next == NULL)
687  path_end = 1;
688  if ((xn->axes == ROXML_ID_SELF) || (xn->axes == ROXML_ID_PARENT))
689  valid = 1;
690 
691  if (valid == 0)
692  valid = roxml_validate_axe_name(candidat, xn);
693  }
694 
695  if (valid == 1)
696  valid = roxml_validate_predicat(xn, xn->cond, candidat);
697  if (valid == 1)
698  valid = roxml_validate_predicat(xn, xn->xp_cond, candidat);
699 
700  if ((valid == 1) && (path_end))
701  roxml_add_to_set(root, candidat, ans, nb, max, req_id);
702 
703  return (valid == 1);
704 }
705 
720 ROXML_STATIC ROXML_INT void roxml_check_node(xpath_node_t *xp, node_t *root, node_t *context, node_t ***ans,
721  int *nb, int *max, int ignore, int req_id)
722 {
723  int validate_node = 0;
724 
725  if ((req_id == 0) && (*nb > 0))
726  return;
727 
728  if (!xp)
729  return;
730 
731  // if found a "all document" axes
732  if (ignore == ROXML_DESC_ONLY) {
733  node_t *current = context->chld;
734  while (current) {
735  roxml_check_node(xp, root, current, ans, nb, max, ignore, req_id);
736  current = current->sibl;
737  }
738  }
739 
740  switch (xp->axes) {
741  case ROXML_ID_CHILD:{
742  node_t *current = context->chld;
743  while (current) {
744  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
745  if (validate_node)
746  roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
747  current = current->sibl;
748  }
749  if ((xp->name == NULL) || (strcmp(xp->name, "text()") == 0)
750  || (strcmp(xp->name, "node()") == 0)) {
751  node_t *current = roxml_get_txt(context, 0);
752  while (current) {
753  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
754  current = current->sibl;
755  }
756  }
757  if ((xp->name == NULL) || (strcmp(xp->name, "node()") == 0)) {
758  node_t *current = context->attr;
759  while (current) {
760  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
761  current = current->sibl;
762  }
763  }
764  }
765  break;
766  case ROXML_ID_DESC:{
767  roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DESC_ONLY, req_id);
768  }
769  break;
770  case ROXML_ID_DESC_O_SELF:{
771  xp = xp->next;
772  validate_node = roxml_validate_axes(root, context, ans, nb, max, xp, req_id);
773  if (validate_node)
774  roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DIRECT, req_id);
775  roxml_check_node(xp, root, context, ans, nb, max, ROXML_DESC_ONLY, req_id);
776  }
777  break;
778  case ROXML_ID_SELF:{
779  validate_node = roxml_validate_axes(root, context, ans, nb, max, xp, req_id);
780  roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DIRECT, req_id);
781  }
782  break;
783  case ROXML_ID_PARENT:{
784  if (context->prnt) {
785  validate_node = roxml_validate_axes(root, context->prnt, ans, nb, max, xp, req_id);
786  roxml_check_node(xp->next, root, context->prnt, ans, nb, max, ROXML_DIRECT, req_id);
787  } else {
788  validate_node = 0;
789  }
790  }
791  break;
792  case ROXML_ID_ATTR:{
793  node_t *attribute = context->attr;
794  while (attribute) {
795  validate_node = roxml_validate_axes(root, attribute, ans, nb, max, xp, req_id);
796  if (validate_node)
797  roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DIRECT, req_id);
798  attribute = attribute->sibl;
799  }
800  }
801  break;
802  case ROXML_ID_ANC:{
803  node_t *current = context->prnt;
804  while (current) {
805  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
806  if (validate_node)
807  roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
808  current = current->prnt;
809  }
810  }
811  break;
812  case ROXML_ID_NEXT_SIBL:{
813  node_t *current = context->sibl;
814  while (current) {
815  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
816  if (validate_node)
817  roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
818  current = current->sibl;
819  }
820  }
821  break;
822  case ROXML_ID_PREV_SIBL:{
823  node_t *current = context->prnt->chld;
824  while (current != context) {
825  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
826  if (validate_node)
827  roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
828  current = current->sibl;
829  }
830  }
831  break;
832  case ROXML_ID_NEXT:{
833  node_t *current = context;
834  while (current) {
835  node_t *following = current->sibl;
836  while (following) {
837  validate_node = roxml_validate_axes(root, following, ans, nb, max, xp, req_id);
838  if (validate_node) {
839  roxml_check_node(xp->next, root, following, ans, nb, max, ROXML_DIRECT,
840  req_id);
841  } else {
842  xp->axes = ROXML_ID_CHILD;
843  roxml_check_node(xp, root, following, ans, nb, max, ROXML_DESC_ONLY,
844  req_id);
845  xp->axes = ROXML_ID_NEXT;
846  }
847  following = following->sibl;
848  }
849  following = current->prnt->chld;
850  while (following != current)
851  following = following->sibl;
852  current = following->sibl;
853  }
854  }
855  break;
856  case ROXML_ID_PREV:{
857  node_t *current = context;
858  while (current && current->prnt) {
859  node_t *preceding = current->prnt->chld;
860  while (preceding != current) {
861  validate_node = roxml_validate_axes(root, preceding, ans, nb, max, xp, req_id);
862  if (validate_node) {
863  roxml_check_node(xp->next, root, preceding, ans, nb, max, ROXML_DIRECT,
864  req_id);
865  } else {
866  xp->axes = ROXML_ID_CHILD;
867  roxml_check_node(xp, root, preceding, ans, nb, max, ROXML_DESC_ONLY,
868  req_id);
869  xp->axes = ROXML_ID_PREV;
870  }
871  preceding = preceding->sibl;
872  }
873  current = current->prnt;
874  }
875  }
876  break;
877  case ROXML_ID_NS:{
878  validate_node = roxml_validate_axes(root, context->ns, ans, nb, max, xp, req_id);
879  if (validate_node)
880  roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DIRECT, req_id);
881  }
882  break;
883  case ROXML_ID_ANC_O_SELF:{
884  node_t *current = context;
885  while (current) {
886  validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
887  if (validate_node)
888  roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
889  current = current->prnt;
890  }
891  }
892  break;
893  }
894 
895  return;
896 }
897 
898 ROXML_INT node_t **roxml_exec_xpath(node_t *root, node_t *n, xpath_node_t *xpath, int index, int *count)
899 {
900  int path_id;
901  int max_answers = 1;
902  int glob_id = 0;
903  int *req_ids = NULL;
904  node_t **node_set;
905 
906  *count = 0;
907  glob_id = roxml_request_id(root);
908  if (glob_id < 0)
909  return NULL;
910  req_ids = calloc(index, sizeof(int));
911  node_set = roxml_malloc(sizeof(node_t *), max_answers, PTR_NODE_RESULT);
912 
913  /* process all AND xpath */
914  for (path_id = 0; path_id < index; path_id++) {
915  xpath_node_t *cur_xpath = NULL;
916  xpath_node_t *next_xpath = NULL;
917  cur_xpath = &xpath[path_id];
918 
919  if (path_id < index - 1)
920  next_xpath = &xpath[path_id + 1];
921 
922  if ((cur_xpath->rel == ROXML_OPERATOR_AND) || ((next_xpath) && (next_xpath->rel == ROXML_OPERATOR_AND))) {
923  int req_id = roxml_request_id(root);
924  node_t *orig = n;
925 
926  if (cur_xpath->abs)
927  /* context node is root */
928  orig = root;
929 
930  roxml_check_node(cur_xpath, root, orig, &node_set, count, &max_answers, ROXML_DIRECT, req_id);
931 
932  if (cur_xpath->rel == ROXML_OPERATOR_AND)
933  roxml_compute_and(root, node_set, count, req_id, req_ids[path_id - 1]);
934  req_ids[path_id] = req_id;
935  }
936  }
937 
938  /* process all OR xpath */
939  for (path_id = 0; path_id < index; path_id++) {
940  xpath_node_t *cur_xpath = &xpath[path_id];
941 
942  if (cur_xpath->rel == ROXML_OPERATOR_OR) {
943  node_t *orig = n;
944 
945  if (req_ids[path_id] == 0) {
946  if (cur_xpath->abs)
947  orig = root;
948 
949  /* assign a new request ID */
950  roxml_check_node(cur_xpath, root, orig, &node_set, count, &max_answers, ROXML_DIRECT,
951  glob_id);
952  } else {
953  roxml_compute_or(root, node_set, count, req_ids[path_id + 1], glob_id);
954  roxml_release_id(root, node_set, *count, req_ids[path_id + 1]);
955  }
956  }
957  }
958 
959  roxml_release_id(root, node_set, *count, glob_id);
960 
961  for (path_id = 0; path_id < index; path_id++)
962  if (req_ids[path_id] != 0)
963  roxml_release_id(root, node_set, *count, req_ids[path_id]);
964  free(req_ids);
965 
966  return node_set;
967 }
968 
969 ROXML_API node_t **roxml_xpath(node_t *n, char *path, int *nb_ans)
970 {
971  int count = 0;
972  node_t **node_set = NULL;
973  int index = 0;
974  xpath_node_t *xpath = NULL;
975  node_t *root = n;
976  char *full_path_to_find;
977 
978  if (n == ROXML_INVALID_DOC) {
979  if (nb_ans)
980  *nb_ans = 0;
981  return NULL;
982  }
983 
984  root = roxml_get_root(n);
985 
986  full_path_to_find = strdup(path);
987 
988  index = roxml_parse_xpath(full_path_to_find, &xpath, 0);
989 
990  if (index >= 0) {
991  node_set = roxml_exec_xpath(root, n, xpath, index, &count);
992  roxml_free_xpath(xpath, index);
993 
994  if (count == 0) {
995  roxml_release(node_set);
996  node_set = NULL;
997  }
998  }
999  if (nb_ans)
1000  *nb_ans = count;
1001  free(full_path_to_find);
1002 
1003  return node_set;
1004 }
1005 
1015 ROXML_STATIC ROXML_INT xpath_node_t *roxml_set_axes(xpath_node_t *node, char *axes, int *offset)
1016 {
1017  struct _xpath_axes {
1018  char id;
1019  char *name;
1020  };
1021 
1022  struct _xpath_axes xpath_axes[14] = {
1023  {ROXML_ID_PARENT, ROXML_L_PARENT},
1024  {ROXML_ID_PARENT, ROXML_S_PARENT},
1025  {ROXML_ID_SELF, ROXML_L_SELF},
1026  {ROXML_ID_SELF, ROXML_S_SELF},
1027  {ROXML_ID_ATTR, ROXML_L_ATTR},
1028  {ROXML_ID_ATTR, ROXML_S_ATTR},
1029  {ROXML_ID_ANC, ROXML_L_ANC},
1030  {ROXML_ID_ANC_O_SELF, ROXML_L_ANC_O_SELF},
1031  {ROXML_ID_NEXT_SIBL, ROXML_L_NEXT_SIBL},
1032  {ROXML_ID_PREV_SIBL, ROXML_L_PREV_SIBL},
1033  {ROXML_ID_NEXT, ROXML_L_NEXT},
1034  {ROXML_ID_PREV, ROXML_L_PREV},
1035  {ROXML_ID_NS, ROXML_L_NS},
1036  {ROXML_ID_CHILD, ROXML_L_CHILD},
1037  };
1038 
1039  xpath_node_t *tmp_node;
1040  if (axes[0] == '/') {
1041  axes[0] = '\0';
1042  *offset += 1;
1043  axes++;
1044  }
1045  if (axes[0] == '/') {
1046  /* ROXML_S_DESC_O_SELF */
1047  node->axes = ROXML_ID_DESC_O_SELF;
1048  node->name = axes + 1;
1049  tmp_node = calloc(1, sizeof(xpath_node_t));
1050  tmp_node->axes = ROXML_ID_CHILD;
1051  node->next = tmp_node;
1052  if (strlen(node->name) > 0) {
1053  tmp_node = calloc(1, sizeof(xpath_node_t));
1054  node->next->next = tmp_node;
1055  node = roxml_set_axes(tmp_node, axes + 1, offset);
1056  }
1057  } else if (strncmp(ROXML_L_DESC_O_SELF, axes, strlen(ROXML_L_DESC_O_SELF)) == 0) {
1058  /* ROXML_L_DESC_O_SELF */
1059  node->axes = ROXML_ID_DESC_O_SELF;
1060  node->name = axes + strlen(ROXML_L_DESC_O_SELF);
1061  *offset += strlen(ROXML_L_DESC_O_SELF);
1062  tmp_node = calloc(1, sizeof(xpath_node_t));
1063  tmp_node->axes = ROXML_ID_CHILD;
1064  node->next = tmp_node;
1065  node = roxml_set_axes(tmp_node, axes + strlen(ROXML_L_DESC_O_SELF), offset);
1066  } else if (strncmp(ROXML_L_DESC, axes, strlen(ROXML_L_DESC)) == 0) {
1067  /* ROXML_L_DESC */
1068  node->axes = ROXML_ID_DESC;
1069  node->name = axes + strlen(ROXML_L_DESC);
1070  *offset += strlen(ROXML_L_DESC);
1071  tmp_node = calloc(1, sizeof(xpath_node_t));
1072  tmp_node->axes = ROXML_ID_CHILD;
1073  node->next = tmp_node;
1074  node = roxml_set_axes(tmp_node, axes + strlen(ROXML_L_DESC), offset);
1075  } else {
1076  int i = 0;
1077 
1078  /* ROXML_S_CHILD is default */
1079  node->axes = ROXML_ID_CHILD;
1080  node->name = axes;
1081 
1082  for (i = 0; i < 14; i++) {
1083  int len = strlen(xpath_axes[i].name);
1084  if (strncmp(xpath_axes[i].name, axes, len) == 0) {
1085  node->axes = xpath_axes[i].id;
1086  node->name = axes + len;
1087  break;
1088  }
1089  }
1090  }
1091  return node;
1092 }
1093 
1094 ROXML_INT int _func_xpath_ignore(roxml_parser_item_t *parser, char *chunk, void *data)
1095 {
1096 #ifdef DEBUG_PARSING
1097  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1098 #endif /* DEBUG_PARSING */
1099  return 1;
1100 }
1101 
1102 ROXML_INT int _func_xpath_new_node(roxml_parser_item_t *parser, char *chunk, void *data)
1103 {
1104  int cur = 0;
1105  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1106 #ifdef DEBUG_PARSING
1107  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1108 #endif /* DEBUG_PARSING */
1109  if (!ctx->quoted && !ctx->dquoted && !ctx->parenthesys && !ctx->bracket) {
1110  int offset = 0;
1111  xpath_node_t *tmp_node = calloc(1, sizeof(xpath_node_t));
1112  if ((chunk[cur] == '/') && (ctx->is_first_node)) {
1113  free(tmp_node);
1114  ctx->new_node = ctx->first_node;
1115  ctx->first_node->abs = 1;
1116  } else if ((chunk[cur] == '/') && (ctx->wait_first_node)) {
1117  free(tmp_node);
1118  ctx->first_node->abs = 1;
1119  } else if ((ctx->is_first_node) || (ctx->wait_first_node)) {
1120  free(tmp_node);
1121  } else {
1122  if (ctx->new_node)
1123  ctx->new_node->next = tmp_node;
1124  ctx->new_node = tmp_node;
1125  }
1126  ctx->is_first_node = 0;
1127  ctx->wait_first_node = 0;
1128  ctx->new_node = roxml_set_axes(ctx->new_node, chunk + cur, &offset);
1129  cur = offset + 1;
1130  }
1131  ctx->shorten_cond = 0;
1132  return cur;
1133 }
1134 
1135 ROXML_INT int _func_xpath_quote(roxml_parser_item_t *parser, char *chunk, void *data)
1136 {
1137  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1138 #ifdef DEBUG_PARSING
1139  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1140 #endif /* DEBUG_PARSING */
1141  if (!ctx->dquoted) {
1142  if (ctx->quoted && ctx->content_quoted == MODE_COMMENT_QUOTE) {
1144  chunk[0] = '\0';
1145  }
1146  ctx->quoted = (ctx->quoted + 1) % 2;
1147  }
1148  ctx->shorten_cond = 0;
1149  return 1;
1150 }
1151 
1152 ROXML_INT int _func_xpath_dquote(roxml_parser_item_t *parser, char *chunk, void *data)
1153 {
1154  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1155 #ifdef DEBUG_PARSING
1156  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1157 #endif /* DEBUG_PARSING */
1158  if (!ctx->quoted) {
1159  if (ctx->dquoted && ctx->content_quoted == MODE_COMMENT_DQUOTE) {
1161  chunk[0] = '\0';
1162  }
1163  ctx->dquoted = (ctx->dquoted + 1) % 2;
1164  }
1165  ctx->shorten_cond = 0;
1166  return 1;
1167 }
1168 
1169 ROXML_INT int _func_xpath_open_parenthesys(roxml_parser_item_t *parser, char *chunk, void *data)
1170 {
1171  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1172 #ifdef DEBUG_PARSING
1173  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1174 #endif /* DEBUG_PARSING */
1175  if (!ctx->quoted && !ctx->dquoted)
1176  ctx->parenthesys = (ctx->parenthesys + 1) % 2;
1177  ctx->shorten_cond = 0;
1178  return 1;
1179 }
1180 
1181 ROXML_INT int _func_xpath_close_parenthesys(roxml_parser_item_t *parser, char *chunk, void *data)
1182 {
1183  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1184 #ifdef DEBUG_PARSING
1185  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1186 #endif /* DEBUG_PARSING */
1187  if (!ctx->quoted && !ctx->dquoted)
1188  ctx->parenthesys = (ctx->parenthesys + 1) % 2;
1189  ctx->shorten_cond = 0;
1190  return 1;
1191 }
1192 
1193 ROXML_INT int _func_xpath_open_brackets(roxml_parser_item_t *parser, char *chunk, void *data)
1194 {
1195  xpath_cond_t *tmp_cond;
1196  int cur = 0;
1197 #ifdef DEBUG_PARSING
1198  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1199 #endif /* DEBUG_PARSING */
1200  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1201  if (!ctx->quoted && !ctx->dquoted) {
1202  ctx->bracket = (ctx->bracket + 1) % 2;
1203  chunk[0] = '\0';
1204 
1205  ctx->shorten_cond = 1;
1206  tmp_cond = calloc(1, sizeof(xpath_cond_t));
1207  ctx->new_node->cond = tmp_cond;
1208  ctx->new_cond = tmp_cond;
1209  ctx->new_cond->arg1 = chunk + cur + 1;
1210  } else {
1211  ctx->shorten_cond = 0;
1212  }
1213  cur++;
1214  return 1;
1215 }
1216 
1217 ROXML_INT int _func_xpath_close_brackets(roxml_parser_item_t *parser, char *chunk, void *data)
1218 {
1219  int cur = 0;
1220  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1221 #ifdef DEBUG_PARSING
1222  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1223 #endif /* DEBUG_PARSING */
1224  if (!ctx->quoted && !ctx->dquoted) {
1225  ctx->bracket = (ctx->bracket + 1) % 2;
1226  chunk[0] = '\0';
1227 
1228  if (ctx->new_cond) {
1229  if (ctx->new_cond->func == ROXML_FUNC_XPATH) {
1230  xpath_node_t *xp;
1231  ctx->new_cond->func2 = roxml_parse_xpath(ctx->new_cond->arg1, &xp, 1);
1232  ctx->new_cond->xp = xp;
1233  }
1234  } else {
1235  return -1;
1236  }
1237  }
1238  cur++;
1239  ctx->shorten_cond = 0;
1240  return 1;
1241 }
1242 
1243 ROXML_INT int _func_xpath_condition_or(roxml_parser_item_t *parser, char *chunk, void *data)
1244 {
1245  xpath_node_t *tmp_node;
1246  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1247  int cur = 0;
1248  int len = 0;
1249  xpath_cond_t *tmp_cond;
1250 #ifdef DEBUG_PARSING
1251  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1252 #endif /* DEBUG_PARSING */
1253 
1254  len = strlen(ROXML_COND_OR);
1255 
1256  if (strncmp(chunk, ROXML_COND_OR, len) == 0) {
1257  if (roxml_is_separator(*(chunk - 1)) && roxml_is_separator(*(chunk + len))) {
1258  if (!ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1259  if (ctx->context != 1) {
1260  return 0;
1261  }
1262  chunk[-1] = '\0';
1263  cur += strlen(ROXML_COND_OR);
1264  tmp_node = calloc(ctx->nbpath + 1, sizeof(xpath_node_t));
1265  memcpy(tmp_node, ctx->first_node, ctx->nbpath * sizeof(xpath_node_t));
1266  free(ctx->first_node);
1267  ctx->first_node = tmp_node;
1268  ctx->wait_first_node = 1;
1269  ctx->new_node = tmp_node + ctx->nbpath;
1270  ctx->new_node->rel = ROXML_OPERATOR_OR;
1271  ctx->nbpath++;
1272  } else if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1273  if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1274  chunk[-1] = '\0';
1275  cur += strlen(ROXML_COND_OR);
1276  tmp_cond = calloc(1, sizeof(xpath_cond_t));
1277  if (ctx->new_cond) {
1278  ctx->new_cond->next = tmp_cond;
1279  }
1280  ctx->new_cond = tmp_cond;
1281  ctx->new_cond->rel = ROXML_OPERATOR_OR;
1282  ctx->new_cond->arg1 = chunk + cur + 1;
1283  }
1284  }
1285  }
1286  }
1287  if (cur)
1288  ctx->shorten_cond = 0;
1289  return cur;
1290 }
1291 
1292 ROXML_INT int _func_xpath_condition_and(roxml_parser_item_t *parser, char *chunk, void *data)
1293 {
1294  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1295  int cur = 0;
1296  int len = 0;
1297  xpath_node_t *tmp_node;
1298  xpath_cond_t *tmp_cond;
1299 #ifdef DEBUG_PARSING
1300  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1301 #endif /* DEBUG_PARSING */
1302 
1303  len = strlen(ROXML_COND_AND);
1304 
1305  if (strncmp(chunk, ROXML_COND_AND, len) == 0) {
1306  if (roxml_is_separator(*(chunk - 1)) && roxml_is_separator(*(chunk + len))) {
1307  if (!ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1308  if (ctx->context != 1)
1309  return 0;
1310  chunk[-1] = '\0';
1311  cur += strlen(ROXML_COND_AND);
1312  tmp_node = calloc(ctx->nbpath + 1, sizeof(xpath_node_t));
1313  memcpy(tmp_node, ctx->first_node, ctx->nbpath * sizeof(xpath_node_t));
1314  free(ctx->first_node);
1315  ctx->first_node = tmp_node;
1316  ctx->wait_first_node = 1;
1317  ctx->new_node = tmp_node + ctx->nbpath;
1318  ctx->new_node->rel = ROXML_OPERATOR_AND;
1319  ctx->nbpath++;
1320  } else if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1321  if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1322  chunk[-1] = '\0';
1323  cur += strlen(ROXML_COND_AND);
1324  tmp_cond = calloc(1, sizeof(xpath_cond_t));
1325  if (ctx->new_cond) {
1326  ctx->new_cond->next = tmp_cond;
1327  }
1328  ctx->new_cond = tmp_cond;
1329  ctx->new_cond->rel = ROXML_OPERATOR_AND;
1330  ctx->new_cond->arg1 = chunk + cur + 1;
1331  }
1332  }
1333  }
1334  }
1335  if (cur)
1336  ctx->shorten_cond = 0;
1337  return cur;
1338 }
1339 
1340 ROXML_INT int _func_xpath_path_or(roxml_parser_item_t *parser, char *chunk, void *data)
1341 {
1342  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1343  int cur = 0;
1344  xpath_node_t *tmp_node;
1345 #ifdef DEBUG_PARSING
1346  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1347 #endif /* DEBUG_PARSING */
1348 
1349  if (!ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1350  chunk[-1] = '\0';
1351  cur += strlen(ROXML_PATH_OR);
1352  tmp_node = calloc(ctx->nbpath + 1, sizeof(xpath_node_t));
1353  memcpy(tmp_node, ctx->first_node, ctx->nbpath * sizeof(xpath_node_t));
1354  free(ctx->first_node);
1355  ctx->first_node = tmp_node;
1356  ctx->wait_first_node = 1;
1357  ctx->new_node = tmp_node + ctx->nbpath;
1358  ctx->new_node->rel = ROXML_OPERATOR_OR;
1359  ctx->nbpath++;
1360  }
1361  ctx->shorten_cond = 0;
1362  return cur;
1363 }
1364 
1365 ROXML_INT int _func_xpath_operators(roxml_parser_item_t *parser, char *chunk, void *data, int operator, int operator_bis)
1366 {
1367  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1368  int cur = 0;
1369  if (!ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1370  xpath_node_t *xp_root = ctx->new_node;
1371  xpath_cond_t *xp_cond = calloc(1, sizeof(xpath_cond_t));
1372  xp_root->xp_cond = xp_cond;
1373  chunk[cur] = '\0';
1374  xp_cond->op = operator;
1375  if (ROXML_WHITE(chunk[cur - 1]))
1376  chunk[cur - 1] = '\0';
1377  if (chunk[cur + 1] == '=') {
1378  chunk[++cur] = '\0';
1379  xp_cond->op = operator_bis;
1380  }
1381  if (ROXML_WHITE(chunk[cur + 1]))
1382  chunk[++cur] = '\0';
1383 
1384  xp_cond->arg2 = chunk + cur + 1;
1385  if (xp_cond->arg2[0] == '"') {
1387  xp_cond->arg2++;
1388  } else if (xp_cond->arg2[0] == '\'') {
1390  xp_cond->arg2++;
1391  }
1392  if (!xp_cond->func) {
1393  xp_cond->func = ROXML_FUNC_INTCOMP;
1394  if (!roxml_is_number(xp_cond->arg2))
1395  xp_cond->func = ROXML_FUNC_STRCOMP;
1396  }
1397  cur++;
1398  } else if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1399  if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1400  chunk[cur] = '\0';
1401  ctx->new_cond->op = operator;
1402  if (ROXML_WHITE(chunk[cur - 1]))
1403  chunk[cur - 1] = '\0';
1404  if (chunk[cur + 1] == '=') {
1405  chunk[++cur] = '\0';
1406  ctx->new_cond->op = operator_bis;
1407  }
1408  if (ROXML_WHITE(chunk[cur + 1]))
1409  chunk[++cur] = '\0';
1410  ctx->new_cond->arg2 = chunk + cur + 1;
1411  if (ctx->new_cond->arg2[0] == '"') {
1413  ctx->new_cond->arg2++;
1414  } else if (ctx->new_cond->arg2[0] == '\'') {
1416  ctx->new_cond->arg2++;
1417  }
1418  if (ctx->new_cond->func == 0) {
1419  ctx->new_cond->func = ROXML_FUNC_INTCOMP;
1420  if (!roxml_is_number(ctx->new_cond->arg2))
1421  ctx->new_cond->func = ROXML_FUNC_STRCOMP;
1422  }
1423  cur++;
1424  }
1425  }
1426  ctx->shorten_cond = 0;
1427  return cur;
1428 }
1429 
1430 ROXML_INT int _func_xpath_operator_equal(roxml_parser_item_t *parser, char *chunk, void *data)
1431 {
1432 #ifdef DEBUG_PARSING
1433  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1434 #endif /* DEBUG_PARSING */
1435  return _func_xpath_operators(parser, chunk, data, ROXML_OPERATOR_EQU, ROXML_OPERATOR_EQU);
1436 }
1437 
1438 ROXML_INT int _func_xpath_operator_sup(roxml_parser_item_t *parser, char *chunk, void *data)
1439 {
1440 #ifdef DEBUG_PARSING
1441  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1442 #endif /* DEBUG_PARSING */
1443  return _func_xpath_operators(parser, chunk, data, ROXML_OPERATOR_SUP, ROXML_OPERATOR_ESUP);
1444 }
1445 
1446 ROXML_INT int _func_xpath_operator_inf(roxml_parser_item_t *parser, char *chunk, void *data)
1447 {
1448 #ifdef DEBUG_PARSING
1449  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1450 #endif /* DEBUG_PARSING */
1451  return _func_xpath_operators(parser, chunk, data, ROXML_OPERATOR_INF, ROXML_OPERATOR_EINF);
1452 }
1453 
1454 ROXML_INT int _func_xpath_operator_diff(roxml_parser_item_t *parser, char *chunk, void *data)
1455 {
1456 #ifdef DEBUG_PARSING
1457  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1458 #endif /* DEBUG_PARSING */
1459  return _func_xpath_operators(parser, chunk, data, ROXML_OPERATOR_DIFF, ROXML_OPERATOR_DIFF);
1460 }
1461 
1462 ROXML_INT int _func_xpath_number(roxml_parser_item_t *parser, char *chunk, void *data)
1463 {
1464 #ifdef DEBUG_PARSING
1465  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1466 #endif /* DEBUG_PARSING */
1467  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1468  int cur = 0;
1469  if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1470  if ((ctx->new_cond->func != ROXML_FUNC_XPATH) && (ctx->shorten_cond)) {
1471  cur = 1;
1472  ctx->new_cond->func = ROXML_FUNC_POS;
1473  ctx->new_cond->op = ROXML_OPERATOR_EQU;
1474  ctx->new_cond->arg2 = chunk;
1475  while ((chunk[cur + 1] >= '0') && (chunk[cur + 1] <= '9'))
1476  cur++;
1477  }
1478  }
1479  ctx->shorten_cond = 0;
1480  return cur;
1481 }
1482 
1483 ROXML_INT int _func_xpath_funcs(roxml_parser_item_t *parser, char *chunk, void *data, int func, char *name)
1484 {
1485 #ifdef DEBUG_PARSING
1486  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1487 #endif /* DEBUG_PARSING */
1488  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1489  int cur = 0;
1490 
1491  if (strncmp(chunk, name, strlen(name)) == 0) {
1492  if (ctx->new_cond->func != func) {
1493  cur += strlen(name);
1494  ctx->new_cond->func = func;
1495  }
1496  }
1497  if (cur)
1498  ctx->shorten_cond = 0;
1499  return cur;
1500 }
1501 
1502 ROXML_INT int _func_xpath_position(roxml_parser_item_t *parser, char *chunk, void *data)
1503 {
1504 #ifdef DEBUG_PARSING
1505  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1506 #endif /* DEBUG_PARSING */
1507  return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_POS, ROXML_FUNC_POS_STR);
1508 }
1509 
1510 ROXML_INT int _func_xpath_first(roxml_parser_item_t *parser, char *chunk, void *data)
1511 {
1512 #ifdef DEBUG_PARSING
1513  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1514 #endif /* DEBUG_PARSING */
1515  return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_FIRST, ROXML_FUNC_FIRST_STR);
1516 }
1517 
1518 ROXML_INT int _func_xpath_last(roxml_parser_item_t *parser, char *chunk, void *data)
1519 {
1520 #ifdef DEBUG_PARSING
1521  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1522 #endif /* DEBUG_PARSING */
1523  return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_LAST, ROXML_FUNC_LAST_STR);
1524 }
1525 
1526 ROXML_INT int _func_xpath_nsuri(roxml_parser_item_t *parser, char *chunk, void *data)
1527 {
1528 #ifdef DEBUG_PARSING
1529  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1530 #endif /* DEBUG_PARSING */
1531  return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_NSURI, ROXML_FUNC_NSURI_STR);
1532 }
1533 
1534 ROXML_INT int _func_xpath_lname(roxml_parser_item_t *parser, char *chunk, void *data)
1535 {
1536 #ifdef DEBUG_PARSING
1537  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1538 #endif /* DEBUG_PARSING */
1539  return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_LNAME, ROXML_FUNC_LNAME_STR);
1540 }
1541 
1542 ROXML_INT int _func_xpath_operator_add(roxml_parser_item_t *parser, char *chunk, void *data)
1543 {
1544 #ifdef DEBUG_PARSING
1545  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1546 #endif /* DEBUG_PARSING */
1547  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1548  int cur = 0;
1549  if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1550  if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1551  if ((ctx->new_cond->func == ROXML_FUNC_LAST) || (ctx->new_cond->func == ROXML_FUNC_FIRST))
1552  ctx->new_cond->op = ROXML_OPERATOR_ADD;
1553  chunk[cur] = '\0';
1554  if (ROXML_WHITE(chunk[cur + 1]))
1555  chunk[++cur] = '\0';
1556  ctx->new_cond->arg2 = chunk + cur + 1;
1557  }
1558  }
1559  ctx->shorten_cond = 0;
1560  return cur;
1561 }
1562 
1563 ROXML_INT int _func_xpath_operator_subs(roxml_parser_item_t *parser, char *chunk, void *data)
1564 {
1565 #ifdef DEBUG_PARSING
1566  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1567 #endif /* DEBUG_PARSING */
1568  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1569  int cur = 0;
1570  if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1571  if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1572  if ((ctx->new_cond->func == ROXML_FUNC_LAST) || (ctx->new_cond->func == ROXML_FUNC_FIRST))
1573  ctx->new_cond->op = ROXML_OPERATOR_SUB;
1574  chunk[cur] = '\0';
1575  if (ROXML_WHITE(chunk[cur + 1]))
1576  chunk[++cur] = '\0';
1577  ctx->new_cond->arg2 = chunk + cur + 1;
1578  }
1579  }
1580  ctx->shorten_cond = 0;
1581  return cur;
1582 }
1583 
1584 ROXML_INT int _func_xpath_default(roxml_parser_item_t *parser, char *chunk, void *data)
1585 {
1586 #ifdef DEBUG_PARSING
1587  fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1588 #endif /* DEBUG_PARSING */
1589  int cur = 0;
1590  roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1591 
1592  if ((ctx->is_first_node) || (ctx->wait_first_node)) {
1593  if (!ctx->quoted && !ctx->dquoted && !ctx->parenthesys && !ctx->bracket) {
1594  int offset = 0;
1595  xpath_node_t *tmp_node = calloc(1, sizeof(xpath_node_t));
1596  if ((chunk[cur] == '/') && (ctx->is_first_node)) {
1597  free(tmp_node);
1598  ctx->new_node = ctx->first_node;
1599  ctx->first_node->abs = 1;
1600  } else if ((chunk[cur] == '/') && (ctx->wait_first_node)) {
1601  free(tmp_node);
1602  ctx->first_node->abs = 1;
1603  } else if ((ctx->is_first_node) || (ctx->wait_first_node)) {
1604  free(tmp_node);
1605  } else {
1606  if (ctx->new_node)
1607  ctx->new_node->next = tmp_node;
1608  ctx->new_node = tmp_node;
1609  }
1610  ctx->is_first_node = 0;
1611  ctx->wait_first_node = 0;
1612  ctx->new_node = roxml_set_axes(ctx->new_node, chunk + cur, &offset);
1613  cur += offset;
1614  }
1615  } else if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1616  if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1617  if (ctx->shorten_cond) {
1618  int bracket_lvl = 1;
1619  ctx->new_cond->func = ROXML_FUNC_XPATH;
1620  ctx->new_cond->arg1 = chunk + cur;
1621  while (bracket_lvl > 0) {
1622  if (chunk[cur] == '[')
1623  bracket_lvl++;
1624  else if (chunk[cur] == ']')
1625  bracket_lvl--;
1626  cur++;
1627  }
1628  cur--;
1629  }
1630  }
1631  }
1632  ctx->shorten_cond = 0;
1633  return cur > 0 ? cur : 1;
1634 }
#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:235
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:1015
#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:671
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:720
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:969
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:898
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