<libroxml  version="3.0.2" />
contact: tristan.lelong@libroxml.net
roxml_parser.c
Go to the documentation of this file.
1 
12 #include <stdlib.h>
13 #include <string.h>
14 #include "roxml_parser.h"
15 
16 /* #define DEBUG_PARSING */
17 #define ROXML_PARSER_NCELLS 256
18 #define ROXML_PARSER_NCELLS_MAX 512
19 
20 #define ROXML_PARSER_ITEM(parser, item) (parser + item)
21 
22 ROXML_INT int roxml_parser_multiple(roxml_parser_item_t *parser, char *chunk, void *data)
23 {
24  roxml_parser_item_t *item = ROXML_PARSER_ITEM(parser, *chunk)->next;
25 
26  /* collision can only occurs on callbacks
27  * that verify the chunk value so we can
28  * just call all cb in turns */
29  while (item) {
30  int ret = item->func(parser, chunk, data);
31 
32  if (ret > 0)
33  return ret;
34  else if (ret < 0)
35  return -1;
36  item = item->next;
37  }
38  return 0;
39 }
40 
41 ROXML_INT roxml_parser_item_t *roxml_append_parser_item(roxml_parser_item_t *parser, char *key, roxml_parse_func func)
42 {
43  if (!parser)
44  parser = roxml_parser_allocate();
45 
46  if (!ROXML_PARSER_ITEM(parser, *key)->func) {
47  /* first callback registered */
48  ROXML_PARSER_ITEM(parser, *key)->func = func;
49  } else if (!ROXML_PARSER_ITEM(parser, *key)->next){
50  /* second callback registered:
51  * 1) find free cells in collision pool
52  * 2) initialize cells
53  * 3) enable multiple callbacks.
54  */
55  roxml_parser_item_t *collision = parser + ROXML_PARSER_NCELLS;
56 
57  while (collision->func)
58  collision++;
59 
60  /* relocate existing callback in collision pool */
61  ROXML_PARSER_ITEM(parser, *key)->next = collision;
62  collision->func = ROXML_PARSER_ITEM(parser, *key)->func;
63  collision->next = collision + 1;
64 
65  /* next available callback is right after (since we do not free single entries) */
66  collision++;
67  collision->func = func;
68  collision->next = NULL;
69 
70  ROXML_PARSER_ITEM(parser, *key)->func = roxml_parser_multiple;
71  } else {
72  /* third or more callback registered: just append */
73  roxml_parser_item_t *last;
74  roxml_parser_item_t *collision = ROXML_PARSER_ITEM(parser, *key);
75  while (collision->next)
76  collision = collision->next;
77  last = collision;
78  while (collision->func)
79  collision++;
80  last->next = collision;
81  collision->func = func;
82  collision->next = NULL;
83  }
84 
85  return parser;
86 }
87 
89 {
90  roxml_parser_item_t *parser;
91 
92  /* allocate a new parser.
93  * 512 cells allow up to 256 collisions. */
94  parser = malloc(sizeof(roxml_parser_item_t) * ROXML_PARSER_NCELLS_MAX);
95  memset(parser, 0 , sizeof(roxml_parser_item_t) * ROXML_PARSER_NCELLS_MAX);
96 
97  return parser;
98 }
99 
100 ROXML_INT void roxml_parser_free(roxml_parser_item_t *parser)
101 {
102  free(parser);
103 }
104 
106 {
107  int i, j;
108  roxml_parser_item_t *new;
109  roxml_parser_item_t *collision;
110 
111  new = roxml_parser_allocate();
112  collision = new + ROXML_PARSER_NCELLS;
113 
114  for (i = 0; i < ROXML_PARSER_NCELLS; i++) {
115  /* copy parser and assign default */
116  if (parser[i].func) {
117  new[i].func = parser[i].func;
118 
119  if (parser[i].next) {
120  roxml_parser_item_t *item = parser[i].next;
121 
122  new[i].next = collision;
123 
124  /* group all collision callbacks in collision pool */
125  while (1) {
126  collision->func = item->func;
127 
128  if (item->next)
129  collision->next = collision + 1;
130  else
131  break;
132 
133  collision = collision->next;
134  item = item->next;
135  }
136  collision++;
137  }
138  } else {
139  new[i].func = parser[0].func;
140  new[i].next = parser[0].next;
141  }
142  }
143 
144  roxml_parser_free(parser);
145 
146  return new;
147 }
148 
149 ROXML_INT int roxml_parse_line(roxml_parser_item_t *parser, char *line, int len, void *ctx)
150 {
151  char *line_end = line;
152  char *chunk = line;
153 
154  if (len > 0)
155  line_end = line + len;
156  else
157  line_end = line + strlen(line);
158 
159  while (chunk < line_end) {
160  /* main callbacks */
161  int ret = ROXML_PARSER_ITEM(parser, *chunk)->func(parser, chunk, ctx);
162 
163  if (ret > 0) {
164  chunk += ret;
165  continue;
166  } else if (ret < 0) {
167  return ret;
168  }
169 
170  /* default callbacks */
171  ret = ROXML_PARSER_ITEM(parser, 0)->func(parser, chunk, ctx);
172 
173  if (ret > 0) {
174  chunk += ret;
175  continue;
176  } else if (ret < 0) {
177  return ret;
178  }
179  }
180 
181  return (chunk - line);
182 }
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
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
Parsing engine.
ROXML_INT roxml_parser_item_t * roxml_parser_allocate(void)
parser table allocation
Definition: roxml_parser.c:88
the parser item struct
ROXML_INT void roxml_parser_free(roxml_parser_item_t *parser)
parser table deletion
Definition: roxml_parser.c:100
ROXML_INT roxml_parser_item_t * roxml_parser_prepare(roxml_parser_item_t *parser)
parser preparation function
Definition: roxml_parser.c:105