]> mj.ucw.cz Git - libucw.git/blob - sherlock/xml/dtd.c
Small changes in XML parser:
[libucw.git] / sherlock / xml / dtd.c
1 /*
2  *      Sherlock Library -- A simple XML parser
3  *
4  *      (c) 2007--2008 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 #undef LOCAL_DEBUG
11
12 #include "sherlock/sherlock.h"
13 #include "sherlock/xml/xml.h"
14 #include "sherlock/xml/dtd.h"
15 #include "sherlock/xml/internals.h"
16 #include "lib/fastbuf.h"
17 #include "lib/ff-unicode.h"
18 #include "lib/unicode.h"
19
20 /* Notations */
21
22 #define HASH_PREFIX(x) xml_dtd_notns_##x
23 #define HASH_NODE struct xml_dtd_notn
24 #define HASH_KEY_STRING name
25 #define HASH_ZERO_FILL
26 #define HASH_TABLE_DYNAMIC
27 #define HASH_WANT_LOOKUP
28 #define HASH_WANT_FIND
29 #define HASH_GIVE_ALLOC
30 #define HASH_TABLE_ALLOC
31 XML_HASH_GIVE_ALLOC
32 #include "lib/hashtable.h"
33
34 struct xml_dtd_notn *
35 xml_dtd_find_notn(struct xml_context *ctx, char *name)
36 {
37   struct xml_dtd *dtd = ctx->dtd;
38   struct xml_dtd_notn *notn = xml_dtd_notns_find(dtd->tab_notns, name);
39   return !notn ? NULL : (notn->flags & XML_DTD_NOTN_DECLARED) ? notn : NULL;
40 }
41
42 /* General entities */
43
44 #define HASH_PREFIX(x) xml_dtd_ents_##x
45 #define HASH_NODE struct xml_dtd_entity
46 #define HASH_KEY_STRING name
47 #define HASH_ZERO_FILL
48 #define HASH_TABLE_DYNAMIC
49 #define HASH_WANT_FIND
50 #define HASH_WANT_LOOKUP
51 #define HASH_GIVE_ALLOC
52 #define HASH_TABLE_ALLOC
53 XML_HASH_GIVE_ALLOC
54 #include "lib/hashtable.h"
55
56 static struct xml_dtd_entity *
57 xml_dtd_declare_trivial_entity(struct xml_context *ctx, char *name, char *text)
58 {
59   struct xml_dtd *dtd = ctx->dtd;
60   struct xml_dtd_entity *ent = xml_dtd_ents_lookup(dtd->tab_ents, name);
61   if (ent->flags & XML_DTD_ENTITY_DECLARED)
62     {
63       xml_warn(ctx, "Entity &%s; already declared", name);
64       return NULL;
65     }
66   slist_add_tail(&dtd->ents, &ent->n);
67   ent->flags = XML_DTD_ENTITY_DECLARED | XML_DTD_ENTITY_TRIVIAL;
68   ent->text = text;
69   return ent;
70 }
71
72 static void
73 xml_dtd_declare_default_entities(struct xml_context *ctx)
74 {
75   xml_dtd_declare_trivial_entity(ctx, "lt", "<");
76   xml_dtd_declare_trivial_entity(ctx, "gt", ">");
77   xml_dtd_declare_trivial_entity(ctx, "amp", "&");
78   xml_dtd_declare_trivial_entity(ctx, "apos", "'");
79   xml_dtd_declare_trivial_entity(ctx, "quot", "\"");
80 }
81
82 struct xml_dtd_entity *
83 xml_def_find_entity(struct xml_context *ctx UNUSED, char *name)
84 {
85 #define ENT(n, t) ent_##n = { .name = #n, .text = t, .flags = XML_DTD_ENTITY_DECLARED | XML_DTD_ENTITY_TRIVIAL }
86   static struct xml_dtd_entity ENT(lt, "<"), ENT(gt, ">"), ENT(amp, "&"), ENT(apos, "'"), ENT(quot, "\"");
87 #undef ENT
88   switch (name[0])
89     {
90       case 'l':
91         if (!strcmp(name, "lt"))
92           return &ent_lt;
93         break;
94       case 'g':
95         if (!strcmp(name, "gt"))
96           return &ent_gt;
97         break;
98       case 'a':
99         if (!strcmp(name, "amp"))
100           return &ent_amp;
101         if (!strcmp(name, "apos"))
102           return &ent_apos;
103         break;
104       case 'q':
105         if (!strcmp(name, "quot"))
106           return &ent_quot;
107         break;
108     }
109   return NULL;
110 }
111
112 struct xml_dtd_entity *
113 xml_dtd_find_entity(struct xml_context *ctx, char *name)
114 {
115   struct xml_dtd *dtd = ctx->dtd;
116   if (ctx->h_find_entity)
117     return ctx->h_find_entity(ctx, name);
118   else if (dtd)
119     {
120       struct xml_dtd_entity *ent = xml_dtd_ents_find(dtd->tab_ents, name);
121       return !ent ? NULL : (ent->flags & XML_DTD_ENTITY_DECLARED) ? ent : NULL;
122     }
123   else
124     return xml_def_find_entity(ctx, name);
125 }
126
127 /* Parameter entities */
128
129 static struct xml_dtd_entity *
130 xml_dtd_find_pentity(struct xml_context *ctx, char *name)
131 {
132   struct xml_dtd *dtd = ctx->dtd;
133   struct xml_dtd_entity *ent = xml_dtd_ents_find(dtd->tab_pents, name);
134   return !ent ? NULL : (ent->flags & XML_DTD_ENTITY_DECLARED) ? ent : NULL;
135 }
136
137 /* Elements */
138
139 #define HASH_PREFIX(x) xml_dtd_elems_##x
140 #define HASH_NODE struct xml_dtd_elem
141 #define HASH_KEY_STRING name
142 #define HASH_TABLE_DYNAMIC
143 #define HASH_ZERO_FILL
144 #define HASH_WANT_FIND
145 #define HASH_WANT_LOOKUP
146 #define HASH_GIVE_ALLOC
147 #define HASH_TABLE_ALLOC
148 XML_HASH_GIVE_ALLOC
149 #include "lib/hashtable.h"
150
151 struct xml_dtd_elem *
152 xml_dtd_find_elem(struct xml_context *ctx, char *name)
153 {
154   return ctx->dtd ? xml_dtd_elems_find(ctx->dtd->tab_elems, name) : NULL;
155 }
156
157 /* Element sons */
158
159 struct xml_dtd_enodes_table;
160
161 static inline uns
162 xml_dtd_enodes_hash(struct xml_dtd_enodes_table *tab UNUSED, struct xml_dtd_elem_node *parent, struct xml_dtd_elem *elem)
163 {
164   return hash_pointer(parent) ^ hash_pointer(elem);
165 }
166
167 static inline int
168 xml_dtd_enodes_eq(struct xml_dtd_enodes_table *tab UNUSED, struct xml_dtd_elem_node *parent1, struct xml_dtd_elem *elem1, struct xml_dtd_elem_node *parent2, struct xml_dtd_elem *elem2)
169 {
170   return (parent1 == parent2) && (elem1 == elem2);
171 }
172
173 static inline void
174 xml_dtd_enodes_init_key(struct xml_dtd_enodes_table *tab UNUSED, struct xml_dtd_elem_node *node, struct xml_dtd_elem_node *parent, struct xml_dtd_elem *elem)
175 {
176   node->parent = parent;
177   node->elem = elem;
178 }
179
180 #define HASH_PREFIX(x) xml_dtd_enodes_##x
181 #define HASH_NODE struct xml_dtd_elem_node
182 #define HASH_KEY_COMPLEX(x) x parent, x elem
183 #define HASH_KEY_DECL struct xml_dtd_elem_node *parent, struct xml_dtd_elem *elem
184 #define HASH_GIVE_HASHFN
185 #define HASH_GIVE_EQ
186 #define HASH_GIVE_INIT_KEY
187 #define HASH_TABLE_DYNAMIC
188 #define HASH_ZERO_FILL
189 #define HASH_WANT_FIND
190 #define HASH_WANT_NEW
191 #define HASH_GIVE_ALLOC
192 #define HASH_TABLE_ALLOC
193 XML_HASH_GIVE_ALLOC
194 #include "lib/hashtable.h"
195
196 /* Element attributes */
197
198 struct xml_dtd_attrs_table;
199
200 static inline uns
201 xml_dtd_attrs_hash(struct xml_dtd_attrs_table *tab UNUSED, struct xml_dtd_elem *elem, char *name)
202 {
203   return hash_pointer(elem) ^ hash_string(name);
204 }
205
206 static inline int
207 xml_dtd_attrs_eq(struct xml_dtd_attrs_table *tab UNUSED, struct xml_dtd_elem *elem1, char *name1, struct xml_dtd_elem *elem2, char *name2)
208 {
209   return (elem1 == elem2) && !strcmp(name1, name2);
210 }
211
212 static inline void
213 xml_dtd_attrs_init_key(struct xml_dtd_attrs_table *tab UNUSED, struct xml_dtd_attr *attr, struct xml_dtd_elem *elem, char *name)
214 {
215   attr->elem = elem;
216   attr->name = name;
217 }
218
219 #define HASH_PREFIX(x) xml_dtd_attrs_##x
220 #define HASH_NODE struct xml_dtd_attr
221 #define HASH_ZERO_FILL
222 #define HASH_TABLE_DYNAMIC
223 #define HASH_KEY_COMPLEX(x) x elem, x name
224 #define HASH_KEY_DECL struct xml_dtd_elem *elem, char *name
225 #define HASH_GIVE_HASHFN
226 #define HASH_GIVE_EQ
227 #define HASH_GIVE_INIT_KEY
228 #define HASH_WANT_FIND
229 #define HASH_WANT_NEW
230 #define HASH_GIVE_ALLOC
231 #define HASH_TABLE_ALLOC
232 XML_HASH_GIVE_ALLOC
233 #include "lib/hashtable.h"
234
235 struct xml_dtd_attr *
236 xml_dtd_find_attr(struct xml_context *ctx, struct xml_dtd_elem *elem, char *name)
237 {
238   return ctx->dtd ? xml_dtd_attrs_find(ctx->dtd->tab_attrs, elem, name) : NULL;
239 }
240
241 /* Enumerated attribute values */
242
243 struct xml_dtd_evals_table;
244
245 static inline uns
246 xml_dtd_evals_hash(struct xml_dtd_evals_table *tab UNUSED, struct xml_dtd_attr *attr, char *val)
247 {
248   return hash_pointer(attr) ^ hash_string(val);
249 }
250
251 static inline int
252 xml_dtd_evals_eq(struct xml_dtd_evals_table *tab UNUSED, struct xml_dtd_attr *attr1, char *val1, struct xml_dtd_attr *attr2, char *val2)
253 {
254   return (attr1 == attr2) && !strcmp(val1, val2);
255 }
256
257 static inline void
258 xml_dtd_evals_init_key(struct xml_dtd_evals_table *tab UNUSED, struct xml_dtd_eval *eval, struct xml_dtd_attr *attr, char *val)
259 {
260   eval->attr = attr;
261   eval->val = val;
262 }
263
264 #define HASH_PREFIX(x) xml_dtd_evals_##x
265 #define HASH_NODE struct xml_dtd_eval
266 #define HASH_TABLE_DYNAMIC
267 #define HASH_KEY_COMPLEX(x) x attr, x val
268 #define HASH_KEY_DECL struct xml_dtd_attr *attr, char *val
269 #define HASH_GIVE_HASHFN
270 #define HASH_GIVE_EQ
271 #define HASH_GIVE_INIT_KEY
272 #define HASH_WANT_FIND
273 #define HASH_WANT_NEW
274 #define HASH_GIVE_ALLOC
275 #define HASH_TABLE_ALLOC
276 XML_HASH_GIVE_ALLOC
277 #include "lib/hashtable.h"
278
279 /* Enumerated attribute notations */
280
281 struct xml_dtd_enotns_table;
282
283 static inline uns
284 xml_dtd_enotns_hash(struct xml_dtd_enotns_table *tab UNUSED, struct xml_dtd_attr *attr, struct xml_dtd_notn *notn)
285 {
286   return hash_pointer(attr) ^ hash_pointer(notn);
287 }
288
289 static inline int
290 xml_dtd_enotns_eq(struct xml_dtd_enotns_table *tab UNUSED, struct xml_dtd_attr *attr1, struct xml_dtd_notn *notn1, struct xml_dtd_attr *attr2, struct xml_dtd_notn *notn2)
291 {
292   return (attr1 == attr2) && (notn1 == notn2);
293 }
294
295 static inline void
296 xml_dtd_enotns_init_key(struct xml_dtd_enotns_table *tab UNUSED, struct xml_dtd_enotn *enotn, struct xml_dtd_attr *attr, struct xml_dtd_notn *notn)
297 {
298   enotn->attr = attr;
299   enotn->notn = notn;
300 }
301
302 #define HASH_PREFIX(x) xml_dtd_enotns_##x
303 #define HASH_NODE struct xml_dtd_enotn
304 #define HASH_TABLE_DYNAMIC
305 #define HASH_KEY_COMPLEX(x) x attr, x notn
306 #define HASH_KEY_DECL struct xml_dtd_attr *attr, struct xml_dtd_notn *notn
307 #define HASH_GIVE_HASHFN
308 #define HASH_GIVE_EQ
309 #define HASH_GIVE_INIT_KEY
310 #define HASH_WANT_FIND
311 #define HASH_WANT_NEW
312 #define HASH_GIVE_ALLOC
313 #define HASH_TABLE_ALLOC
314 XML_HASH_GIVE_ALLOC
315 #include "lib/hashtable.h"
316
317 /* DTD initialization/cleanup */
318
319 void
320 xml_dtd_init(struct xml_context *ctx)
321 {
322   if (ctx->dtd)
323     return;
324   struct mempool *pool = mp_new(4096);
325   struct xml_dtd *dtd = ctx->dtd = mp_alloc_zero(pool, sizeof(*ctx->dtd));
326   dtd->pool = pool;
327   xml_dtd_ents_init(dtd->tab_ents = xml_hash_new(pool, sizeof(struct xml_dtd_ents_table)));
328   xml_dtd_ents_init(dtd->tab_pents = xml_hash_new(pool, sizeof(struct xml_dtd_ents_table)));
329   xml_dtd_notns_init(dtd->tab_notns = xml_hash_new(pool, sizeof(struct xml_dtd_notns_table)));
330   xml_dtd_elems_init(dtd->tab_elems = xml_hash_new(pool, sizeof(struct xml_dtd_elems_table)));
331   xml_dtd_enodes_init(dtd->tab_enodes = xml_hash_new(pool, sizeof(struct xml_dtd_enodes_table)));
332   xml_dtd_attrs_init(dtd->tab_attrs = xml_hash_new(pool, sizeof(struct xml_dtd_attrs_table)));
333   xml_dtd_evals_init(dtd->tab_evals = xml_hash_new(pool, sizeof(struct xml_dtd_evals_table)));
334   xml_dtd_enotns_init(dtd->tab_enotns = xml_hash_new(pool, sizeof(struct xml_dtd_enotns_table)));
335   xml_dtd_declare_default_entities(ctx);
336 }
337
338 void
339 xml_dtd_cleanup(struct xml_context *ctx)
340 {
341   if (!ctx->dtd)
342     return;
343   mp_delete(ctx->dtd->pool);
344   ctx->dtd = NULL;
345 }
346
347 void
348 xml_dtd_finish(struct xml_context *ctx)
349 {
350   if (!ctx->dtd)
351     return;
352   // FIXME: validity checks
353 }
354
355 /*** Parsing functions ***/
356
357 /* References to parameter entities */
358
359 void
360 xml_parse_pe_ref(struct xml_context *ctx)
361 {
362   /* PEReference ::= '%' Name ';'
363    * Already parsed: '%' */
364   struct mempool_state state;
365   mp_save(ctx->stack, &state);
366   char *name = xml_parse_name(ctx, ctx->stack);
367   xml_parse_char(ctx, ';');
368   struct xml_dtd_entity *ent = xml_dtd_find_pentity(ctx, name);
369   if (!ent)
370     xml_error(ctx, "Unknown entity %%%s;", name);
371   else
372     {
373       TRACE(ctx, "Pushed entity %%%s;", name);
374       mp_restore(ctx->stack, &state);
375       xml_dec(ctx);
376       xml_push_entity(ctx, ent);
377       return;
378     }
379   mp_restore(ctx->stack, &state);
380   xml_dec(ctx);
381 }
382
383 static uns
384 xml_parse_dtd_pe(struct xml_context *ctx, uns entity_decl)
385 {
386   /* Already parsed: '%' */
387   do
388     {
389       xml_inc(ctx);
390       if (!~entity_decl && (xml_peek_cat(ctx) & XML_CHAR_WHITE))
391         {
392           xml_dec(ctx);
393           return ~0U;
394         }
395       xml_parse_pe_ref(ctx);
396       while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
397         xml_skip_char(ctx);
398     }
399   while (xml_get_char(ctx) == '%');
400   xml_unget_char(ctx);
401   return 1;
402 }
403
404 static inline uns
405 xml_parse_dtd_white(struct xml_context *ctx, uns mandatory)
406 {
407   /* Whitespace or parameter entity,
408    * mandatory==~0U has a special maening of the whitespace before the '%' character in an parameter entity declaration */
409   uns cnt = 0;
410   while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
411     {
412       xml_skip_char(ctx);
413       cnt = 1;
414     }
415   if (xml_peek_char(ctx) == '%')
416     {
417       xml_skip_char(ctx);
418       return xml_parse_dtd_pe(ctx, mandatory);
419     }
420   else if (unlikely(mandatory && !cnt))
421     xml_fatal_expected_white(ctx);
422   return cnt;
423 }
424
425 static void
426 xml_dtd_parse_external_id(struct xml_context *ctx, char **system_id, char **public_id, uns allow_public)
427 {
428   struct xml_dtd *dtd = ctx->dtd;
429   uns c = xml_peek_char(ctx);
430   if (c == 'S')
431     {
432       xml_parse_seq(ctx, "SYSTEM");
433       xml_parse_dtd_white(ctx, 1);
434       *public_id = NULL;
435       *system_id = xml_parse_system_literal(ctx, dtd->pool);
436     }
437   else if (c == 'P')
438     {
439       xml_parse_seq(ctx, "PUBLIC");
440       xml_parse_dtd_white(ctx, 1);
441       *system_id = NULL;
442       *public_id = xml_parse_pubid_literal(ctx, dtd->pool);
443       if (xml_parse_dtd_white(ctx, !allow_public))
444         if ((c = xml_peek_char(ctx)) == '\'' || c == '"' || !allow_public)
445           *system_id = xml_parse_system_literal(ctx, dtd->pool);
446     }
447   else
448     xml_fatal(ctx, "Expected an external ID");
449 }
450
451 /* DTD: <!NOTATION ...> */
452
453 void
454 xml_parse_notation_decl(struct xml_context *ctx)
455 {
456   /* NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
457    * Already parsed: '<!NOTATION' */
458   TRACE(ctx, "parse_notation_decl");
459   struct xml_dtd *dtd = ctx->dtd;
460   xml_parse_dtd_white(ctx, 1);
461
462   struct xml_dtd_notn *notn = xml_dtd_notns_lookup(dtd->tab_notns, xml_parse_name(ctx, dtd->pool));
463   xml_parse_dtd_white(ctx, 1);
464   char *system_id, *public_id;
465   xml_dtd_parse_external_id(ctx, &system_id, &public_id, 1);
466   xml_parse_dtd_white(ctx, 0);
467   xml_parse_char(ctx, '>');
468
469   if (notn->flags & XML_DTD_NOTN_DECLARED)
470     xml_warn(ctx, "Notation %s already declared", notn->name);
471   else
472     {
473       notn->flags = XML_DTD_NOTN_DECLARED;
474       notn->system_id = system_id;
475       notn->public_id = public_id;
476       slist_add_tail(&dtd->notns, &notn->n);
477     }
478   xml_dec(ctx);
479 }
480
481 /* DTD: <!ENTITY ...> */
482
483 void
484 xml_parse_entity_decl(struct xml_context *ctx)
485 {
486   /* Already parsed: '<!ENTITY' */
487   TRACE(ctx, "parse_entity_decl");
488   struct xml_dtd *dtd = ctx->dtd;
489   uns flags = ~xml_parse_dtd_white(ctx, ~0U) ? 0 : XML_DTD_ENTITY_PARAMETER;
490   if (flags)
491     xml_parse_dtd_white(ctx, 1);
492   struct xml_dtd_entity *ent = xml_dtd_ents_lookup(flags ? dtd->tab_pents : dtd->tab_ents, xml_parse_name(ctx, dtd->pool));
493   xml_parse_dtd_white(ctx, 1);
494   slist *list = flags ? &dtd->pents : &dtd->ents;
495   if (ent->flags & XML_DTD_ENTITY_DECLARED)
496     {
497        xml_fatal(ctx, "Entity &%s; already declared, skipping not implemented", ent->name);
498        // FIXME: should be only warning
499     }
500   uns c, sep = xml_get_char(ctx);
501   if (sep == '\'' || sep == '"')
502     {
503       /* Internal entity:
504        * EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | "'" ([^%&'] | PEReference | Reference)* "'" */
505       char *p = mp_start_noalign(dtd->pool, 1);
506       while (1)
507         {
508           if ((c = xml_get_char(ctx)) == sep)
509             break;
510           if (c == '%')
511             {
512               // FIXME
513               ASSERT(0);
514               //xml_parse_parameter_ref(ctx);
515               continue;
516             }
517           if (c == '&')
518             {
519               xml_inc(ctx);
520               if (xml_peek_char(ctx) != '#')
521                 {
522                   /* Bypass references to general entities */
523                   struct mempool_state state;
524                   mp_save(ctx->stack, &state);
525                   char *n = xml_parse_name(ctx, ctx->stack);
526                   xml_parse_char(ctx, ';');
527                   xml_dec(ctx);
528                   uns l = strlen(n);
529                   p = mp_spread(dtd->pool, p, 3 + l);
530                   *p++ = '&';
531                   memcpy(p, n, l);
532                   p += l;
533                   *p++ = ';';;
534                   mp_restore(ctx->stack, &state);
535                   continue;
536                 }
537               else
538                 {
539                   xml_skip_char(ctx);
540                   c = xml_parse_char_ref(ctx);
541                 }
542             }
543           p = mp_spread(dtd->pool, p, 5);
544           p = utf8_32_put(p, c);
545         }
546       *p = 0;
547       ent->len = p - (char *)mp_ptr(dtd->pool);
548       ent->text = mp_end(dtd->pool, p + 1);
549       slist_add_tail(list, &ent->n);
550       ent->flags = flags | XML_DTD_ENTITY_DECLARED;
551     }
552   else
553     {
554       /* External entity */
555       struct xml_dtd_notn *notn = NULL;
556       char *system_id, *public_id;
557       xml_unget_char(ctx);
558       xml_dtd_parse_external_id(ctx, &system_id, &public_id, 0);
559       if (xml_parse_dtd_white(ctx, 0) && flags && xml_peek_char(ctx) != '>')
560         {
561           /* General external unparsed entity */
562           flags |= XML_DTD_ENTITY_UNPARSED;
563           xml_parse_seq(ctx, "NDATA");
564           xml_parse_dtd_white(ctx, 1);
565           notn = xml_dtd_notns_lookup(dtd->tab_notns, xml_parse_name(ctx, dtd->pool));
566         }
567       slist_add_tail(list, &ent->n);
568       ent->flags = flags | XML_DTD_ENTITY_DECLARED | XML_DTD_ENTITY_EXTERNAL;
569       ent->system_id = system_id;
570       ent->public_id = public_id;
571       ent->notn = notn;
572     }
573   xml_parse_dtd_white(ctx, 0);
574   xml_parse_char(ctx, '>');
575   xml_dec(ctx);
576 }
577
578 /* DTD: <!ELEMENT ...> */
579
580 void
581 xml_parse_element_decl(struct xml_context *ctx)
582 {
583   /* Elementdecl ::= '<!ELEMENT' S  Name  S  contentspec  S? '>'
584    * Already parsed: '<!ELEMENT' */
585   struct xml_dtd *dtd = ctx->dtd;
586   xml_parse_dtd_white(ctx, 1);
587   char *name = xml_parse_name(ctx, dtd->pool);
588   xml_parse_dtd_white(ctx, 1);
589   struct xml_dtd_elem *elem = xml_dtd_elems_lookup(dtd->tab_elems, name);
590   if (elem->flags & XML_DTD_ELEM_DECLARED)
591     xml_fatal(ctx, "Element <%s> already declared", name);
592
593   /* contentspec ::= 'EMPTY' | 'ANY' | Mixed | children */
594   uns c = xml_peek_char(ctx);
595   if (c == 'E')
596     {
597       xml_parse_seq(ctx, "EMPTY");
598       elem->type = XML_DTD_ELEM_EMPTY;
599     }
600   else if (c == 'A')
601     {
602       xml_parse_seq(ctx, "ANY");
603       elem->type = XML_DTD_ELEM_ANY;
604     }
605   else if (c == '(')
606     {
607       xml_skip_char(ctx);
608       xml_inc(ctx);
609       xml_parse_dtd_white(ctx, 0);
610       struct xml_dtd_elem_node *parent = elem->node = mp_alloc_zero(dtd->pool, sizeof(*parent));
611       if (xml_peek_char(ctx) == '#')
612         {
613           /* Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')' */
614           xml_skip_char(ctx);
615           xml_parse_seq(ctx, "PCDATA");
616           elem->type = XML_DTD_ELEM_MIXED;
617           parent->type = XML_DTD_ELEM_PCDATA;
618           while (1)
619             {
620               xml_parse_dtd_white(ctx, 0);
621               if ((c = xml_get_char(ctx)) == ')')
622                 break;
623               else if (c != '|')
624                 xml_fatal_expected(ctx, ')');
625               xml_parse_dtd_white(ctx, 0);
626               struct xml_dtd_elem *son_elem = xml_dtd_elems_lookup(dtd->tab_elems, xml_parse_name(ctx, dtd->pool));
627               if (xml_dtd_enodes_find(dtd->tab_enodes, parent, son_elem))
628                 xml_error(ctx, "Duplicate content '%s'", son_elem->name);
629               else
630                 {
631                   struct xml_dtd_elem_node *son = xml_dtd_enodes_new(dtd->tab_enodes, parent, son_elem);
632                   slist_add_tail(&parent->sons, &son->n);
633                 }
634             }
635           xml_dec(ctx);
636           if (xml_peek_char(ctx) == '*')
637             {
638               xml_skip_char(ctx);
639               parent->occur = XML_DTD_ELEM_OCCUR_MULT;
640             }
641           else if (!slist_head(&parent->sons))
642             parent->occur = XML_DTD_ELEM_OCCUR_ONCE;
643           else
644             xml_fatal_expected(ctx, '*');
645         }
646       else
647         {
648           /* children ::= (choice | seq) ('?' | '*' | '+')?
649            * cp ::= (Name | choice | seq) ('?' | '*' | '+')?
650            * choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')'
651            * seq ::= '(' S? cp ( S? ',' S? cp )* S? ')' */
652
653           elem->type = XML_DTD_ELEM_CHILDREN;
654           parent->type = XML_DTD_ELEM_PCDATA;
655           uns c;
656           goto first;
657
658           while (1)
659             {
660               /* After name */
661               xml_parse_dtd_white(ctx, 0);
662               if ((c = xml_get_char(ctx)) ==  ')')
663                 {
664                   xml_dec(ctx);
665                   if (parent->type == XML_DTD_ELEM_PCDATA)
666                     parent->type = XML_DTD_ELEM_SEQ;
667                   if ((c = xml_get_char(ctx)) == '?')
668                     parent->occur = XML_DTD_ELEM_OCCUR_OPT;
669                   else if (c == '*')
670                     parent->occur = XML_DTD_ELEM_OCCUR_MULT;
671                   else if (c == '+')
672                     parent->occur = XML_DTD_ELEM_OCCUR_PLUS;
673                   else
674                     {
675                       xml_unget_char(ctx);
676                       parent->occur = XML_DTD_ELEM_OCCUR_ONCE;
677                     }
678                   if (!parent->parent)
679                     break;
680                   parent = parent->parent;
681                   continue;
682                 }
683               else if (c == '|')
684                 {
685                   if (parent->type == XML_DTD_ELEM_PCDATA)
686                     parent->type = XML_DTD_ELEM_OR;
687                   else if (parent->type != XML_DTD_ELEM_OR)
688                     xml_fatal(ctx, "Mixed operators in the list of element children");
689                 }
690               else if (c == ',')
691                 {
692                   if (parent->type == XML_DTD_ELEM_PCDATA)
693                     parent->type = XML_DTD_ELEM_SEQ;
694                   else if (parent->type != XML_DTD_ELEM_SEQ)
695                     xml_fatal(ctx, "Mixed operators in the list of element children");
696                 }
697               else if (c == '(')
698                 {
699                   xml_inc(ctx);
700                   struct xml_dtd_elem_node *son = mp_alloc_zero(dtd->pool, sizeof(*son));
701                   son->parent = parent;
702                   slist_add_tail(&parent->sons, &son->n);
703                   parent = son->parent;
704                   son->type = XML_DTD_ELEM_MIXED;
705                 }
706               else
707                 xml_unget_char(ctx);
708
709               /* Before name */
710               xml_parse_dtd_white(ctx, 0);
711 first:;
712               struct xml_dtd_elem *son_elem = xml_dtd_elems_lookup(dtd->tab_elems, xml_parse_name(ctx, dtd->pool));
713               // FIXME: duplicates, occurance
714               //struct xml_dtd_elem_node *son = xml_dtd_enodes_new(dtd->tab_enodes, parent, son_elem);
715               struct xml_dtd_elem_node *son = mp_alloc_zero(dtd->pool, sizeof(*son));
716               son->parent = parent;
717               son->elem = son_elem;
718               slist_add_tail(&parent->sons, &son->n);
719             }
720         }
721     }
722   else
723     xml_fatal(ctx, "Expected element content specification");
724
725   xml_parse_dtd_white(ctx, 0);
726   xml_parse_char(ctx, '>');
727   xml_dec(ctx);
728 }
729
730 void
731 xml_parse_attr_list_decl(struct xml_context *ctx)
732 {
733   /* AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
734    * AttDef ::= S Name S AttType S DefaultDecl
735    * Already parsed: '<!ATTLIST' */
736   struct xml_dtd *dtd = ctx->dtd;
737   xml_parse_dtd_white(ctx, 1);
738   struct xml_dtd_elem *elem = xml_dtd_elems_lookup(ctx->dtd->tab_elems, xml_parse_name(ctx, dtd->pool));
739
740   while (xml_parse_dtd_white(ctx, 0) && xml_peek_char(ctx) != '>')
741     {
742       char *name = xml_parse_name(ctx, dtd->pool);
743       struct xml_dtd_attr *attr = xml_dtd_attrs_find(dtd->tab_attrs, elem, name);
744       uns ignored = 0;
745       if (attr)
746         {
747           xml_warn(ctx, "Duplicate attribute definition");
748           ignored++;
749         }
750       else
751         attr = xml_dtd_attrs_new(ctx->dtd->tab_attrs, elem, name);
752       xml_parse_dtd_white(ctx, 1);
753       if (xml_peek_char(ctx) == '(')
754         {
755           xml_skip_char(ctx); // FIXME: xml_inc/dec ?
756           if (!ignored)
757             attr->type = XML_ATTR_ENUM;
758           do
759             {
760               xml_parse_dtd_white(ctx, 0);
761               char *value = xml_parse_nmtoken(ctx, dtd->pool);
762               if (!ignored)
763                 if (xml_dtd_evals_find(ctx->dtd->tab_evals, attr, value))
764                   xml_error(ctx, "Duplicate enumeration value");
765                 else
766                   xml_dtd_evals_new(ctx->dtd->tab_evals, attr, value);
767               xml_parse_dtd_white(ctx, 0);
768             }
769           while (xml_get_char(ctx) == '|');
770           xml_unget_char(ctx);
771           xml_parse_char(ctx, ')');
772         }
773       else
774         {
775           char *type = xml_parse_name(ctx, dtd->pool);
776           enum xml_dtd_attr_type t = XML_ATTR_CDATA;
777           if (!strcmp(type, "CDATA"))
778             t = XML_ATTR_CDATA;
779           else if (!strcmp(type, "ID"))
780             t = XML_ATTR_ID;
781           else if (!strcmp(type, "IDREF"))
782             t = XML_ATTR_IDREF;
783           else if (!strcmp(type, "IDREFS"))
784             t = XML_ATTR_IDREFS;
785           else if (!strcmp(type, "ENTITY"))
786             t = XML_ATTR_ENTITY;
787           else if (!strcmp(type, "ENTITIES"))
788             t = XML_ATTR_ENTITIES;
789           else if (!strcmp(type, "NMTOKEN"))
790             t = XML_ATTR_NMTOKEN;
791           else if (!strcmp(type, "NMTOKENS"))
792             t = XML_ATTR_NMTOKENS;
793           else if (!strcmp(type, "NOTATION"))
794             {
795               if (elem->type == XML_DTD_ELEM_EMPTY)
796                 xml_fatal(ctx, "Empty element must not have notation attribute");
797               // FIXME: An element type MUST NOT have more than one NOTATION attribute specified.
798               t = XML_ATTR_NOTATION;
799               xml_parse_dtd_white(ctx, 1);
800               xml_parse_char(ctx, '(');
801               do
802                 {
803                   xml_parse_dtd_white(ctx, 0);
804                   struct xml_dtd_notn *n = xml_dtd_notns_lookup(ctx->dtd->tab_notns, xml_parse_name(ctx, dtd->pool));
805                   if (!ignored)
806                     if (xml_dtd_enotns_find(ctx->dtd->tab_enotns, attr, n))
807                       xml_error(ctx, "Duplicate enumerated notation");
808                     else
809                       xml_dtd_enotns_new(ctx->dtd->tab_enotns, attr, n);
810                   xml_parse_dtd_white(ctx, 0);
811                 }
812               while (xml_get_char(ctx) == '|');
813               xml_unget_char(ctx);
814               xml_parse_char(ctx, ')');
815             }
816           else
817             xml_fatal(ctx, "Unknown attribute type");
818           if (!ignored)
819             attr->type = t;
820         }
821       xml_parse_dtd_white(ctx, 1);
822       enum xml_dtd_attr_default def = XML_ATTR_NONE;
823       if (xml_get_char(ctx) == '#')
824         switch (xml_peek_char(ctx))
825           {
826             case 'R':
827               xml_parse_seq(ctx, "REQUIRED");
828               def = XML_ATTR_REQUIRED;
829               break;
830             case 'I':
831               xml_parse_seq(ctx, "IMPLIED");
832               def = XML_ATTR_IMPLIED;
833               break;
834             case 'F':
835               xml_parse_seq(ctx, "FIXED");
836               def = XML_ATTR_FIXED;
837               xml_parse_dtd_white(ctx, 1);
838               break;
839             default:
840               xml_fatal(ctx, "Expected a modifier for default attribute value");
841           }
842       else
843         xml_unget_char(ctx);
844       if (def != XML_ATTR_REQUIRED && def != XML_ATTR_IMPLIED)
845         {
846           char *v = xml_parse_attr_value(ctx, attr);
847           if (!ignored)
848             attr->default_value = v;
849         }
850       if (!ignored)
851         attr->default_mode = def;
852     }
853   xml_skip_char(ctx);
854   xml_dec(ctx);
855 }
856
857 void
858 xml_skip_internal_subset(struct xml_context *ctx)
859 {
860   TRACE(ctx, "skip_internal_subset");
861   /* AlreadyParsed: '[' */
862   uns c;
863   while ((c = xml_get_char(ctx)) != ']')
864     {
865       if (c != '<')
866         continue;
867       if ((c = xml_get_char(ctx)) == '?')
868         {
869           xml_inc(ctx);
870           xml_skip_pi(ctx);
871         }
872       else if (c != '!')
873         xml_dec(ctx);
874       else if (xml_get_char(ctx) == '-')
875         {
876           xml_inc(ctx);
877           xml_skip_comment(ctx);
878         }
879       else
880         while ((c = xml_get_char(ctx)) != '>')
881           if (c == '\'' || c == '"')
882             while (xml_get_char(ctx) != c);
883     }
884   xml_dec(ctx);
885 }
886
887 /*** Validation of attribute values ***/
888
889 static uns
890 xml_check_tokens(char *value, uns first_cat, uns next_cat, uns seq)
891 {
892   char *p = value;
893   uns u;
894   while (1)
895     {
896       p = utf8_32_get(p, &u);
897       if (!(xml_char_cat(u) & first_cat))
898         return 0;
899       while (*p & ~0x20)
900         {
901           p = utf8_32_get(p, &u);
902           if (!(xml_char_cat(u) & next_cat))
903             return 0;
904         }
905       if (!*p)
906         return 1;
907       if (!seq)
908         return 0;
909       p++;
910     }
911 }
912
913 static uns
914 xml_is_name(struct xml_context *ctx, char *value)
915 {
916   /* Name ::= NameStartChar (NameChar)* */
917   return xml_check_tokens(value, ctx->cat_sname, ctx->cat_name, 0);
918 }
919
920 static uns
921 xml_is_names(struct xml_context *ctx, char *value)
922 {
923   /* Names ::= Name (#x20 Name)* */
924   return xml_check_tokens(value, ctx->cat_sname, ctx->cat_name, 1);
925 }
926
927 static uns
928 xml_is_nmtoken(struct xml_context *ctx, char *value)
929 {
930   /* Nmtoken ::= (NameChar)+ */
931   return xml_check_tokens(value, ctx->cat_name, ctx->cat_name, 0);
932 }
933
934 static uns
935 xml_is_nmtokens(struct xml_context *ctx, char *value)
936 {
937   /* Nmtokens ::= Nmtoken (#x20 Nmtoken)* */
938   return xml_check_tokens(value, ctx->cat_name, ctx->cat_name, 1);
939 }
940
941 static void
942 xml_err_attr_format(struct xml_context *ctx, struct xml_dtd_attr *dtd, char *type)
943 {
944   xml_error(ctx, "Attribute %s in <%s> does not match the production of %s", dtd->name, dtd->elem->name, type);
945 }
946
947 void
948 xml_validate_attr(struct xml_context *ctx, struct xml_dtd_attr *dtd, char *value)
949 {
950   if (dtd->type == XML_ATTR_CDATA)
951     return;
952   xml_normalize_white(ctx, value);
953   switch (dtd->type)
954     {
955       case XML_ATTR_ID:
956         if (!xml_is_name(ctx, value))
957           xml_err_attr_format(ctx, dtd, "NAME");
958         //FIXME: add to a hash table
959         break;
960       case XML_ATTR_IDREF:
961         if (!xml_is_name(ctx, value))
962           xml_err_attr_format(ctx, dtd, "NAME");
963         // FIXME: find in hash table (beware forward references)
964         break;
965       case XML_ATTR_IDREFS:
966         if (!xml_is_names(ctx, value))
967           xml_err_attr_format(ctx, dtd, "NAMES");
968         // FIXME: find
969         break;
970       case XML_ATTR_ENTITY:
971         // FIXME
972         break;
973       case XML_ATTR_ENTITIES:
974         // FIXME
975         break;
976       case XML_ATTR_NMTOKEN:
977         if (!xml_is_nmtoken(ctx, value))
978           xml_err_attr_format(ctx, dtd, "NMTOKEN");
979         break;
980       case XML_ATTR_NMTOKENS:
981         if (!xml_is_nmtokens(ctx, value))
982           xml_err_attr_format(ctx, dtd, "NMTOKENS");
983         break;
984       case XML_ATTR_ENUM:
985         if (!xml_dtd_evals_find(ctx->dtd->tab_evals, dtd, value))
986           xml_error(ctx, "Attribute %s in <%s> contains an undefined enumeration value", dtd->name, dtd->elem->name);
987         break;
988       case XML_ATTR_NOTATION:
989         if (!xml_dtd_find_notn(ctx, value))
990           xml_error(ctx, "Attribute %s in <%s> contains an undefined notation", dtd->name, dtd->elem->name);
991         break;
992     }
993 }