]> mj.ucw.cz Git - libucw.git/blob - sherlock/xml/common.h
XML: Split to several files, revised part of iface and
[libucw.git] / sherlock / xml / common.h
1 /*
2  *      Sherlock Library -- A simple XML parser
3  *
4  *      (c) 2007 Pavel Charvat <pchar@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #ifndef _SHERLOCK_XML_COMMON_H
11 #define _SHERLOCK_XML_COMMON_H
12
13 #include "sherlock/xml/xml.h"
14 #include "sherlock/xml/dtd.h"
15
16 /*** Debugging ***/
17
18 #ifdef LOCAL_DEBUG
19 #define TRACE(c, f, p...) do { DBG("XML %u: " f, xml_row(c), ##p); } while(0)
20 #else
21 #define TRACE(c, f, p...) do {} while(0)
22 #endif
23
24 /*** Error handling ***/
25
26 void NONRET xml_throw(struct xml_context *ctx);
27 void xml_warn(struct xml_context *ctx, const char *format, ...);
28 void xml_error(struct xml_context *ctx, const char *format, ...);
29 void xml_fatal(struct xml_context *ctx, const char *format, ...);
30
31 /*** Charecter categorization ***/
32
33 #include "obj/sherlock/xml/unicat.h"
34
35 static inline uns
36 xml_char_cat(uns c)
37 {
38   if (c < 0x10000)
39     return 1U << xml_char_tab1[(c & 0xff) + xml_char_tab2[c >> 8]];
40   else if (likely(c < 0x110000))
41     return 1U << xml_char_tab3[c >> 16];
42   else
43     return 1;
44 }
45
46 static inline uns
47 xml_ascii_cat(uns c)
48 {
49   return xml_char_tab1[c];
50 }
51
52 /*** Memory management ***/
53
54 void NONRET xml_fatal_nested(struct xml_context *ctx);
55
56 static inline void
57 xml_inc(struct xml_context *ctx)
58 {
59   /* Called after the first character of a block */
60   TRACE(ctx, "inc");
61   ctx->depth++;
62 }
63
64 static inline void
65 xml_dec(struct xml_context *ctx)
66 {
67   /* Called after the last character of a block */
68   TRACE(ctx, "dec");
69   if (unlikely(!ctx->depth--))
70     xml_fatal_nested(ctx);
71 }
72
73 struct xml_stack {
74   struct xml_stack *next;
75   struct mempool_state state;
76   uns flags;
77 };
78
79 static inline void *
80 xml_do_push(struct xml_context *ctx, uns size)
81 {
82   /* Saves ctx->stack and ctx->flags state */
83   struct mempool_state state;
84   mp_save(ctx->stack, &state);
85   struct xml_stack *s = mp_alloc(ctx->stack, size);
86   s->state = state;
87   s->flags = ctx->flags;
88   s->next = ctx->stack_list;
89   ctx->stack_list = s;
90   return s;
91 }
92
93 static inline void
94 xml_do_pop(struct xml_context *ctx, struct xml_stack *s)
95 {
96   /* Restore ctx->stack and ctx->flags state */
97   ctx->stack_list = s->next;
98   ctx->flags = s->flags;
99   mp_restore(ctx->stack, &s->state);
100 }
101
102 static inline void
103 xml_push(struct xml_context *ctx)
104 {
105   TRACE(ctx, "push");
106   xml_do_push(ctx, sizeof(struct xml_stack));
107 }
108
109 static inline void
110 xml_pop(struct xml_context *ctx)
111 {
112   TRACE(ctx, "pop");
113   ASSERT(ctx->stack_list);
114   xml_do_pop(ctx, ctx->stack_list);
115 }
116
117 struct xml_dom_stack {
118   struct xml_stack stack;
119   struct mempool_state state;
120 };
121
122 static inline struct xml_node *
123 xml_push_dom(struct xml_context *ctx)
124 {
125   /* Create a new DOM node */
126   TRACE(ctx, "push_dom");
127   struct xml_dom_stack *s = xml_do_push(ctx, sizeof(*s));
128   mp_save(ctx->pool, &s->state);
129   struct xml_node *n = mp_alloc(ctx->pool, sizeof(*n));
130   if (n->parent = ctx->node)
131     clist_add_tail(&n->parent->sons, &n->n);
132   return ctx->node = n;
133 }
134
135 static inline void
136 xml_pop_dom(struct xml_context *ctx)
137 {
138   /* Leave DOM subtree */
139   TRACE(ctx, "pop_dom");
140   ASSERT(ctx->node);
141   struct xml_node *p = ctx->node->parent;
142   struct xml_dom_stack *s = (void *)ctx->stack_list;
143   if (ctx->flags & XML_DOM_FREE)
144     {
145       /* See xml_pop_element() for cleanup of attribute hash table */
146       if (p)
147         clist_remove(&ctx->node->n);
148       mp_restore(ctx->pool, &s->state);
149     }
150   ctx->node = p;
151   xml_do_pop(ctx, &s->stack);
152 }
153
154 #define XML_HASH_HDR_SIZE ALIGN_TO(sizeof(void *), CPU_STRUCT_ALIGN)
155 #define XML_HASH_GIVE_ALLOC struct HASH_PREFIX(table); \
156   static inline void *HASH_PREFIX(alloc)(struct HASH_PREFIX(table) *t, uns size) \
157   { return mp_alloc(*(void **)((void *)t - XML_HASH_HDR_SIZE), size); } \
158   static inline void HASH_PREFIX(free)(struct HASH_PREFIX(table) *t UNUSED, void *p UNUSED) {}
159
160 void *xml_hash_new(struct mempool *pool, uns size);
161
162 static inline void
163 xml_start_chars(struct xml_context *ctx)
164 {
165   struct fastbuf *fb = &ctx->chars;
166   fb->bstop = fb->bptr = fb->buffer = mp_start_noalign(ctx->pool, 1);
167   fb->bufend = fb->buffer + mp_avail(ctx->pool);
168 }
169
170 static inline char *
171 xml_end_chars(struct xml_context *ctx, uns *len)
172 {
173   struct fastbuf *fb = &ctx->chars;
174   uns l = fb->bufend - fb->buffer;
175   if (fb->bptr == fb->bufend)
176     fb->bptr = mp_expand(ctx->pool) + l;
177   *fb->bptr = 0;
178   char *c = mp_end(ctx->pool, fb->bptr + 1);
179   fb->bptr = fb->bstop = fb->buffer = fb->bufend = NULL;
180   *len = l;
181   return c;
182 }
183
184 /*** Reading of document/external entities ***/
185
186 struct xml_source *xml_push_source(struct xml_context *ctx, uns flags);
187 void xml_push_entity(struct xml_context *ctx, struct xml_dtd_ent *ent);
188
189 void xml_refill(struct xml_context *ctx);
190
191 static inline uns
192 xml_peek_char(struct xml_context *ctx)
193 {
194   if (ctx->bptr == ctx->bstop)
195     xml_refill(ctx);
196   return ctx->bptr[0];
197 }
198
199 static inline uns
200 xml_peek_cat(struct xml_context *ctx)
201 {
202   if (ctx->bptr == ctx->bstop)
203     xml_refill(ctx);
204   return ctx->bptr[1];
205 }
206
207 static inline uns
208 xml_get_char(struct xml_context *ctx)
209 {
210   uns c = xml_peek_char(ctx);
211   ctx->bptr += 2;
212   return c;
213 }
214
215 static inline uns
216 xml_get_cat(struct xml_context *ctx)
217 {
218   uns c = xml_peek_cat(ctx);
219   ctx->bptr += 2;
220   return c;
221 }
222
223 static inline uns
224 xml_last_char(struct xml_context *ctx)
225 {
226   return ctx->bptr[-2];
227 }
228
229 static inline uns
230 xml_last_cat(struct xml_context *ctx)
231 {
232   return ctx->bptr[-1];
233 }
234
235 static inline uns
236 xml_skip_char(struct xml_context *ctx)
237 {
238   uns c = ctx->bptr[0];
239   ctx->bptr += 2;
240   return c;
241 }
242
243 static inline uns
244 xml_unget_char(struct xml_context *ctx)
245 {
246   return *(ctx->bptr -= 2);
247 }
248
249 /*** Basic parsing ***/
250
251 void NONRET xml_fatal_expected(struct xml_context *ctx, uns c);
252 void NONRET xml_fatal_expected_white(struct xml_context *ctx);
253 void NONRET xml_fatal_expected_quot(struct xml_context *ctx);
254
255 static inline uns
256 xml_parse_white(struct xml_context *ctx, uns mandatory)
257 {
258   /* mandatory=1 -> S ::= (#x20 | #x9 | #xD | #xA)+
259    * mandatory=0 -> S? */
260   uns cnt = 0;
261   while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
262     {
263       xml_skip_char(ctx);
264       cnt++;
265     }
266   if (unlikely(mandatory && !cnt))
267     xml_fatal_expected_white(ctx);
268   return cnt;
269 }
270
271 static inline void
272 xml_parse_char(struct xml_context *ctx, uns c)
273 {
274   /* Consumes a given Unicode character */
275   if (unlikely(c != xml_get_char(ctx)))
276     xml_fatal_expected(ctx, c);
277 }
278
279 static inline void
280 xml_parse_seq(struct xml_context *ctx, const char *seq)
281 {
282   /* Consumes a given sequence of ASCII characters */
283   while (*seq)
284     xml_parse_char(ctx, *seq++);
285 }
286
287 void xml_parse_eq(struct xml_context *ctx);
288
289 static inline uns
290 xml_parse_quote(struct xml_context *ctx)
291 {
292   /* "'" | '"' */
293   uns c = xml_get_char(ctx);
294   if (unlikely(c != '\'' && c != '\"'))
295     xml_fatal_expected_quot(ctx);
296   return c;
297 }
298
299 /* Names and nmtokens */
300
301 char *xml_parse_name(struct xml_context *ctx, struct mempool *pool);
302 void xml_skip_name(struct xml_context *ctx);
303 char *xml_parse_nmtoken(struct xml_context *ctx, struct mempool *pool);
304
305 /* Simple literals */
306
307 char *xml_parse_system_literal(struct xml_context *ctx, struct mempool *pool);
308 char *xml_parse_pubid_literal(struct xml_context *ctx, struct mempool *pool);
309
310 /* Parsing */
311
312 uns xml_parse_char_ref(struct xml_context *ctx);
313 void xml_parse_ref(struct xml_context *ctx);
314 void xml_parse_pe_ref(struct xml_context *ctx);
315 char *xml_parse_attr_value(struct xml_context *ctx, struct xml_dtd_attr *attr);
316 void xml_parse_notation_decl(struct xml_context *ctx);
317 void xml_parse_entity_decl(struct xml_context *ctx);
318 void xml_parse_element_decl(struct xml_context *ctx);
319 void xml_parse_attr_list_decl(struct xml_context *ctx);
320 void xml_push_comment(struct xml_context *ctx);
321 void xml_pop_comment(struct xml_context *ctx);
322 void xml_skip_comment(struct xml_context *ctx);
323 void xml_push_pi(struct xml_context *ctx);
324 void xml_pop_pi(struct xml_context *ctx);
325 void xml_skip_pi(struct xml_context *ctx);
326
327 #endif