]> mj.ucw.cz Git - libucw.git/blob - sherlock/xml/dtd.c
XML: Split to several files, revised part of iface and
[libucw.git] / sherlock / xml / dtd.c
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 #define LOCAL_DEBUG
11
12 #include "sherlock/sherlock.h"
13 #include "sherlock/xml/xml.h"
14 #include "sherlock/xml/dtd.h"
15 #include "sherlock/xml/common.h"
16 #include "lib/fastbuf.h"
17 #include "lib/ff-unicode.h"
18
19 /* Notations */
20
21 #define HASH_PREFIX(x) xml_dtd_notns_##x
22 #define HASH_NODE struct xml_dtd_notn
23 #define HASH_KEY_STRING name
24 #define HASH_ZERO_FILL
25 #define HASH_TABLE_DYNAMIC
26 #define HASH_WANT_FIND
27 #define HASH_WANT_LOOKUP
28 #define HASH_GIVE_ALLOC
29 #define HASH_TABLE_ALLOC
30 XML_HASH_GIVE_ALLOC
31 #include "lib/hashtable.h"
32
33 /* General entities */
34
35 #define HASH_PREFIX(x) xml_dtd_ents_##x
36 #define HASH_NODE struct xml_dtd_ent
37 #define HASH_KEY_STRING name
38 #define HASH_ZERO_FILL
39 #define HASH_TABLE_DYNAMIC
40 #define HASH_WANT_FIND
41 #define HASH_WANT_LOOKUP
42 #define HASH_GIVE_ALLOC
43 #define HASH_TABLE_ALLOC
44 XML_HASH_GIVE_ALLOC
45 #include "lib/hashtable.h"
46
47 static struct xml_dtd_ent *
48 xml_dtd_declare_trivial_gent(struct xml_context *ctx, char *name, char *text)
49 {
50   struct xml_dtd *dtd = ctx->dtd;
51   struct xml_dtd_ent *ent = xml_dtd_ents_lookup(dtd->tab_gents, name);
52   if (ent->flags & XML_DTD_ENT_DECLARED)
53     {
54       xml_warn(ctx, "Entity &%s; already declared", name);
55       return NULL;
56     }
57   slist_add_tail(&dtd->gents, &ent->n);
58   ent->flags = XML_DTD_ENT_DECLARED | XML_DTD_ENT_TRIVIAL;
59   ent->text = text;
60   ent->len = strlen(text);
61   return ent;
62 }
63
64 static void
65 xml_dtd_declare_default_gents(struct xml_context *ctx)
66 {
67   xml_dtd_declare_trivial_gent(ctx, "lt", "<");
68   xml_dtd_declare_trivial_gent(ctx, "gt", ">");
69   xml_dtd_declare_trivial_gent(ctx, "amp", "&");
70   xml_dtd_declare_trivial_gent(ctx, "apos", "'");
71   xml_dtd_declare_trivial_gent(ctx, "quot", "\"");
72 }
73
74 struct xml_dtd_ent *
75 xml_dtd_find_gent(struct xml_context *ctx, char *name)
76 {
77   struct xml_dtd *dtd = ctx->dtd;
78   if (dtd)
79     {
80       struct xml_dtd_ent *ent = xml_dtd_ents_find(dtd->tab_gents, name);
81       return !ent ? NULL : (ent->flags & XML_DTD_ENT_DECLARED) ? ent : NULL;
82     }
83   else
84     {
85 #define ENT(n, t) ent_##n = { .name = #n, .text = t, .len = 1, .flags = XML_DTD_ENT_DECLARED | XML_DTD_ENT_TRIVIAL }
86       static struct xml_dtd_ent 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
113 /* Parameter entities */
114
115 static struct xml_dtd_ent *
116 xml_dtd_find_pent(struct xml_context *ctx, char *name)
117 {
118   struct xml_dtd *dtd = ctx->dtd;
119   struct xml_dtd_ent *ent = xml_dtd_ents_find(dtd->tab_pents, name);
120   return !ent ? NULL : (ent->flags & XML_DTD_ENT_DECLARED) ? ent : NULL;
121 }
122
123 /* Elements */
124
125 #define HASH_PREFIX(x) xml_dtd_elems_##x
126 #define HASH_NODE struct xml_dtd_elem
127 #define HASH_KEY_STRING name
128 #define HASH_TABLE_DYNAMIC
129 #define HASH_ZERO_FILL
130 #define HASH_WANT_LOOKUP
131 #define HASH_GIVE_ALLOC
132 #define HASH_TABLE_ALLOC
133 XML_HASH_GIVE_ALLOC
134 #include "lib/hashtable.h"
135
136 /* Element sons */
137
138 struct xml_dtd_enodes_table;
139
140 static inline uns
141 xml_dtd_enodes_hash(struct xml_dtd_enodes_table *tab UNUSED, struct xml_dtd_elem_node *parent, struct xml_dtd_elem *elem)
142 {
143   return hash_pointer(parent) ^ hash_pointer(elem);
144 }
145
146 static inline int
147 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)
148 {
149   return (parent1 == parent2) && (elem1 == elem2);
150 }
151
152 static inline void
153 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)
154 {
155   node->parent = parent;
156   node->elem = elem;
157 }
158
159 #define HASH_PREFIX(x) xml_dtd_enodes_##x
160 #define HASH_NODE struct xml_dtd_elem_node
161 #define HASH_KEY_COMPLEX(x) x parent, x elem
162 #define HASH_KEY_DECL struct xml_dtd_elem_node *parent, struct xml_dtd_elem *elem
163 #define HASH_GIVE_HASHFN
164 #define HASH_GIVE_EQ
165 #define HASH_GIVE_INIT_KEY
166 #define HASH_TABLE_DYNAMIC
167 #define HASH_ZERO_FILL
168 #define HASH_WANT_FIND
169 #define HASH_WANT_NEW
170 #define HASH_GIVE_ALLOC
171 #define HASH_TABLE_ALLOC
172 XML_HASH_GIVE_ALLOC
173 #include "lib/hashtable.h"
174
175 /* Element attributes */
176
177 struct xml_dtd_attrs_table;
178
179 static inline uns
180 xml_dtd_attrs_hash(struct xml_dtd_attrs_table *tab UNUSED, struct xml_dtd_elem *elem, char *name)
181 {
182   return hash_pointer(elem) ^ hash_string(name);
183 }
184
185 static inline int
186 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)
187 {
188   return (elem1 == elem2) && !strcmp(name1, name2);
189 }
190
191 static inline void
192 xml_dtd_attrs_init_key(struct xml_dtd_attrs_table *tab UNUSED, struct xml_dtd_attr *attr, struct xml_dtd_elem *elem, char *name)
193 {
194   attr->elem = elem;
195   attr->name = name;
196 }
197
198 #define HASH_PREFIX(x) xml_dtd_attrs_##x
199 #define HASH_NODE struct xml_dtd_attr
200 #define HASH_ZERO_FILL
201 #define HASH_TABLE_DYNAMIC
202 #define HASH_KEY_COMPLEX(x) x elem, x name
203 #define HASH_KEY_DECL struct xml_dtd_elem *elem, char *name
204 #define HASH_GIVE_HASHFN
205 #define HASH_GIVE_EQ
206 #define HASH_GIVE_INIT_KEY
207 #define HASH_WANT_FIND
208 #define HASH_WANT_NEW
209 #define HASH_GIVE_ALLOC
210 #define HASH_TABLE_ALLOC
211 XML_HASH_GIVE_ALLOC
212 #include "lib/hashtable.h"
213
214 /* Enumerated attribute values */
215
216 struct xml_dtd_evals_table;
217
218 static inline uns
219 xml_dtd_evals_hash(struct xml_dtd_evals_table *tab UNUSED, struct xml_dtd_attr *attr, char *val)
220 {
221   return hash_pointer(attr) ^ hash_string(val);
222 }
223
224 static inline int
225 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)
226 {
227   return (attr1 == attr2) && !strcmp(val1, val2);
228 }
229
230 static inline void
231 xml_dtd_evals_init_key(struct xml_dtd_evals_table *tab UNUSED, struct xml_dtd_eval *eval, struct xml_dtd_attr *attr, char *val)
232 {
233   eval->attr = attr;
234   eval->val = val;
235 }
236
237 #define HASH_PREFIX(x) xml_dtd_evals_##x
238 #define HASH_NODE struct xml_dtd_eval
239 #define HASH_TABLE_DYNAMIC
240 #define HASH_KEY_COMPLEX(x) x attr, x val
241 #define HASH_KEY_DECL struct xml_dtd_attr *attr, char *val
242 #define HASH_GIVE_HASHFN
243 #define HASH_GIVE_EQ
244 #define HASH_GIVE_INIT_KEY
245 #define HASH_WANT_FIND
246 #define HASH_WANT_NEW
247 #define HASH_GIVE_ALLOC
248 #define HASH_TABLE_ALLOC
249 XML_HASH_GIVE_ALLOC
250 #include "lib/hashtable.h"
251
252 /* Enumerated attribute notations */
253
254 struct xml_dtd_enotns_table;
255
256 static inline uns
257 xml_dtd_enotns_hash(struct xml_dtd_enotns_table *tab UNUSED, struct xml_dtd_attr *attr, struct xml_dtd_notn *notn)
258 {
259   return hash_pointer(attr) ^ hash_pointer(notn);
260 }
261
262 static inline int
263 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)
264 {
265   return (attr1 == attr2) && (notn1 == notn2);
266 }
267
268 static inline void
269 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)
270 {
271   enotn->attr = attr;
272   enotn->notn = notn;
273 }
274
275 #define HASH_PREFIX(x) xml_dtd_enotns_##x
276 #define HASH_NODE struct xml_dtd_enotn
277 #define HASH_TABLE_DYNAMIC
278 #define HASH_KEY_COMPLEX(x) x attr, x notn
279 #define HASH_KEY_DECL struct xml_dtd_attr *attr, struct xml_dtd_notn *notn
280 #define HASH_GIVE_HASHFN
281 #define HASH_GIVE_EQ
282 #define HASH_GIVE_INIT_KEY
283 #define HASH_WANT_FIND
284 #define HASH_WANT_NEW
285 #define HASH_GIVE_ALLOC
286 #define HASH_TABLE_ALLOC
287 XML_HASH_GIVE_ALLOC
288 #include "lib/hashtable.h"
289
290 /* DTD initialization/cleanup */
291
292 void
293 xml_dtd_init(struct xml_context *ctx)
294 {
295   if (ctx->dtd)
296     return;
297   struct mempool *pool = mp_new(4096);
298   struct xml_dtd *dtd = ctx->dtd = mp_alloc_zero(pool, sizeof(*ctx->dtd));
299   dtd->pool = pool;
300   xml_dtd_ents_init(dtd->tab_gents = xml_hash_new(pool, sizeof(struct xml_dtd_ents_table)));
301   xml_dtd_ents_init(dtd->tab_pents = xml_hash_new(pool, sizeof(struct xml_dtd_ents_table)));
302   xml_dtd_notns_init(dtd->tab_notns = xml_hash_new(pool, sizeof(struct xml_dtd_notns_table)));
303   xml_dtd_elems_init(dtd->tab_elems = xml_hash_new(pool, sizeof(struct xml_dtd_elems_table)));
304   xml_dtd_enodes_init(dtd->tab_enodes = xml_hash_new(pool, sizeof(struct xml_dtd_enodes_table)));
305   xml_dtd_attrs_init(dtd->tab_attrs = xml_hash_new(pool, sizeof(struct xml_dtd_attrs_table)));
306   xml_dtd_evals_init(dtd->tab_evals = xml_hash_new(pool, sizeof(struct xml_dtd_evals_table)));
307   xml_dtd_enotns_init(dtd->tab_enotns = xml_hash_new(pool, sizeof(struct xml_dtd_enotns_table)));
308   xml_dtd_declare_default_gents(ctx);
309 }
310
311 void
312 xml_dtd_cleanup(struct xml_context *ctx)
313 {
314   if (!ctx->dtd)
315     return;
316   mp_delete(ctx->dtd->pool);
317   ctx->dtd = NULL;
318 }
319
320 void
321 xml_dtd_finish(struct xml_context *ctx)
322 {
323   if (!ctx->dtd)
324     return;
325   // FIXME: validity checks
326 }
327
328 /*** Parsing functions ***/
329
330 /* References to parameter entities */
331
332 void
333 xml_parse_pe_ref(struct xml_context *ctx)
334 {
335   /* PEReference ::= '%' Name ';'
336    * Already parsed: '%' */
337   struct mempool_state state;
338   mp_save(ctx->stack, &state);
339   char *name = xml_parse_name(ctx, ctx->stack);
340   xml_parse_char(ctx, ';');
341   struct xml_dtd_ent *ent = xml_dtd_find_pent(ctx, name);
342   if (!ent)
343     xml_error(ctx, "Unknown entity %%%s;", name);
344   else
345     {
346       TRACE(ctx, "Pushed entity %%%s;", name);
347       mp_restore(ctx->stack, &state);
348       xml_dec(ctx);
349       xml_push_entity(ctx, ent);
350       return;
351     }
352   mp_restore(ctx->stack, &state);
353   xml_dec(ctx);
354 }
355
356 static void
357 xml_parse_dtd_pe(struct xml_context *ctx)
358 {
359   do
360     {
361       xml_skip_char(ctx);
362       xml_inc(ctx);
363       while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
364         xml_skip_char(ctx);
365       xml_parse_pe_ref(ctx);
366     }
367   while (xml_peek_char(ctx) != '%');
368 }
369
370 static inline uns
371 xml_parse_dtd_white(struct xml_context *ctx, uns mandatory)
372 {
373   /* Whitespace or parameter entity */
374   uns cnt = 0;
375   while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
376     {
377       xml_skip_char(ctx);
378       cnt = 1;
379     }
380   if (xml_peek_char(ctx) == '%')
381     {
382       xml_parse_dtd_pe(ctx);
383       return 1;
384     }
385   else if (unlikely(mandatory && !cnt))
386     xml_fatal_expected_white(ctx);
387   return cnt;
388 }
389
390 static void
391 xml_dtd_parse_external_id(struct xml_context *ctx, struct xml_ext_id *eid, uns allow_public)
392 {
393   struct xml_dtd *dtd = ctx->dtd;
394   bzero(eid, sizeof(*eid));
395   uns c = xml_peek_char(ctx);
396   if (c == 'S')
397     {
398       xml_parse_seq(ctx, "SYSTEM");
399       xml_parse_dtd_white(ctx, 1);
400       eid->system_id = xml_parse_system_literal(ctx, dtd->pool);
401     }
402   else if (c == 'P')
403     {
404       xml_parse_seq(ctx, "PUBLIC");
405       xml_parse_dtd_white(ctx, 1);
406       eid->public_id = xml_parse_pubid_literal(ctx, dtd->pool);
407       if (xml_parse_dtd_white(ctx, 0)) // FIXME
408         if ((c = xml_peek_char(ctx)) == '\'' || c == '"' || !allow_public)
409           eid->system_id = xml_parse_system_literal(ctx, dtd->pool);
410     }
411   else
412     xml_fatal(ctx, "Expected an external ID");
413 }
414
415 /* DTD: <!NOTATION ...> */
416
417 void
418 xml_parse_notation_decl(struct xml_context *ctx)
419 {
420   /* NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
421    * Already parsed: '<!NOTATION' */
422   TRACE(ctx, "parse_notation_decl");
423   struct xml_dtd *dtd = ctx->dtd;
424   xml_parse_dtd_white(ctx, 1);
425
426   struct xml_dtd_notn *notn = xml_dtd_notns_lookup(dtd->tab_notns, xml_parse_name(ctx, dtd->pool));
427   xml_parse_dtd_white(ctx, 1);
428   struct xml_ext_id eid;
429   xml_dtd_parse_external_id(ctx, &eid, 1);
430   xml_parse_dtd_white(ctx, 0);
431   xml_parse_char(ctx, '>');
432
433   if (notn->flags & XML_DTD_NOTN_DECLARED)
434     xml_warn(ctx, "Notation %s already declared", notn->name);
435   else
436     {
437       notn->flags = XML_DTD_NOTN_DECLARED;
438       notn->eid = eid;
439       slist_add_tail(&dtd->notns, &notn->n);
440     }
441   xml_dec(ctx);
442 }
443
444 /* DTD: <!ENTITY ...> */
445
446 void
447 xml_parse_entity_decl(struct xml_context *ctx)
448 {
449   /* Already parsed: '<!ENTITY' */
450   TRACE(ctx, "parse_entity_decl");
451   struct xml_dtd *dtd = ctx->dtd;
452   xml_parse_dtd_white(ctx, 1);
453
454   uns flags = (xml_get_char(ctx) == '%') ? XML_DTD_ENT_PARAMETER : 0;
455   if (flags)
456     xml_parse_dtd_white(ctx, 1);
457   else
458     xml_unget_char(ctx);
459
460   struct xml_dtd_ent *ent = xml_dtd_ents_lookup(flags ? dtd->tab_pents : dtd->tab_gents, xml_parse_name(ctx, dtd->pool));
461   slist *list = flags ? &dtd->pents : &dtd->gents;
462   xml_parse_dtd_white(ctx, 1);
463   if (ent->flags & XML_DTD_ENT_DECLARED)
464     {
465        xml_fatal(ctx, "Entity &%s; already declared, skipping not implemented", ent->name);
466        // FIXME: should be only warning
467     }
468
469   uns c, sep = xml_get_char(ctx);
470   if (sep == '\'' || sep == '"')
471     {
472       /* Internal entity:
473        * EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | "'" ([^%&'] | PEReference | Reference)* "'" */
474       char *p = mp_start_noalign(dtd->pool, 1);
475       while (1)
476         {
477           if ((c = xml_get_char(ctx)) == sep)
478             break;
479           if (c == '%')
480             {
481               // FIXME
482               ASSERT(0);
483               //xml_parse_parameter_ref(ctx);
484               continue;
485             }
486           if (c == '&')
487             {
488               xml_inc(ctx);
489               if (xml_peek_char(ctx) != '#')
490                 {
491                   /* Bypass references to general entities */
492                   struct mempool_state state;
493                   mp_save(ctx->stack, &state);
494                   char *n = xml_parse_name(ctx, ctx->stack);
495                   xml_parse_char(ctx, ';');
496                   xml_dec(ctx);
497                   uns l = strlen(n);
498                   p = mp_spread(dtd->pool, p, 3 + l);
499                   *p++ = '&';
500                   memcpy(p, n, l);
501                   *p++ = ';';;
502                   mp_restore(ctx->stack, &state);
503                   continue;
504                 }
505               else
506                 {
507                   xml_skip_char(ctx);
508                   c = xml_parse_char_ref(ctx);
509                 }
510             }
511           p = mp_spread(dtd->pool, p, 5);
512           p = utf8_32_put(p, c);
513         }
514       *p = 0;
515       ent->len = p - (char *)mp_ptr(dtd->pool);
516       ent->text = mp_end(dtd->pool, p + 1);
517       slist_add_tail(list, &ent->n);
518       ent->flags = flags | XML_DTD_ENT_DECLARED;
519     }
520   else
521     {
522       /* External entity */
523       struct xml_ext_id eid;
524       struct xml_dtd_notn *notn = NULL;
525       xml_dtd_parse_external_id(ctx, &eid, 0);
526       if (!xml_parse_dtd_white(ctx, 0) || !flags)
527         xml_parse_char(ctx, '>');
528       else if (xml_get_char(ctx) != '>')
529         {
530           /* General external unparsed entity */
531           flags |= XML_DTD_ENT_UNPARSED;
532           xml_parse_seq(ctx, "NDATA");
533           xml_parse_dtd_white(ctx, 1);
534           notn = xml_dtd_notns_lookup(dtd->tab_notns, xml_parse_name(ctx, dtd->pool));
535         }
536       slist_add_tail(list, &ent->n);
537       ent->flags = flags | XML_DTD_ENT_DECLARED | XML_DTD_ENT_EXTERNAL;
538       ent->eid = eid;
539       ent->notn = notn;
540     }
541   xml_parse_dtd_white(ctx, 0);
542   xml_parse_char(ctx, '>');
543   xml_dec(ctx);
544 }
545
546 /* DTD: <!ELEMENT ...> */
547
548 void
549 xml_parse_element_decl(struct xml_context *ctx)
550 {
551   /* Elementdecl ::= '<!ELEMENT' S  Name  S  contentspec  S? '>'
552    * Already parsed: '<!ELEMENT' */
553   struct xml_dtd *dtd = ctx->dtd;
554   xml_parse_dtd_white(ctx, 1);
555   char *name = xml_parse_name(ctx, dtd->pool);
556   xml_parse_dtd_white(ctx, 1);
557   struct xml_dtd_elem *elem = xml_dtd_elems_lookup(dtd->tab_elems, name);
558   if (elem->flags & XML_DTD_ELEM_DECLARED)
559     xml_fatal(ctx, "Element <%s> already declared", name);
560
561   /* contentspec ::= 'EMPTY' | 'ANY' | Mixed | children */
562   uns c = xml_peek_char(ctx);
563   if (c == 'E')
564     {
565       xml_parse_seq(ctx, "EMPTY");
566       elem->type = XML_DTD_ELEM_EMPTY;
567     }
568   else if (c == 'A')
569     {
570       xml_parse_seq(ctx, "ANY");
571       elem->type = XML_DTD_ELEM_ANY;
572     }
573   else if (c == '(')
574     {
575       xml_skip_char(ctx);
576       xml_inc(ctx);
577       xml_parse_dtd_white(ctx, 0);
578       struct xml_dtd_elem_node *parent = elem->node = mp_alloc_zero(dtd->pool, sizeof(*parent));
579       if (xml_peek_char(ctx) == '#')
580         {
581           /* Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')' */
582           xml_skip_char(ctx);
583           xml_parse_seq(ctx, "PCDATA");
584           elem->type = XML_DTD_ELEM_MIXED;
585           parent->type = XML_DTD_ELEM_PCDATA;
586           while (1)
587             {
588               xml_parse_dtd_white(ctx, 0);
589               if ((c = xml_get_char(ctx)) == ')')
590                 break;
591               else if (c != '|')
592                 xml_fatal_expected(ctx, ')');
593               xml_parse_dtd_white(ctx, 0);
594               struct xml_dtd_elem *son_elem = xml_dtd_elems_lookup(dtd->tab_elems, xml_parse_name(ctx, dtd->pool));
595               if (xml_dtd_enodes_find(dtd->tab_enodes, parent, son_elem))
596                 xml_error(ctx, "Duplicate content '%s'", son_elem->name);
597               else
598                 {
599                   struct xml_dtd_elem_node *son = xml_dtd_enodes_new(dtd->tab_enodes, parent, son_elem);
600                   slist_add_tail(&parent->sons, &son->n);
601                 }
602             }
603           xml_dec(ctx);
604           if (xml_peek_char(ctx) == '*')
605             {
606               xml_skip_char(ctx);
607               parent->occur = XML_DTD_ELEM_OCCUR_MULT;
608             }
609           else if (!slist_head(&parent->sons))
610             parent->occur = XML_DTD_ELEM_OCCUR_ONCE;
611           else
612             xml_fatal_expected(ctx, '*');
613         }
614       else
615         {
616           /* children ::= (choice | seq) ('?' | '*' | '+')?
617            * cp ::= (Name | choice | seq) ('?' | '*' | '+')?
618            * choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')'
619            * seq ::= '(' S? cp ( S? ',' S? cp )* S? ')' */
620
621           elem->type = XML_DTD_ELEM_CHILDREN;
622           parent->type = XML_DTD_ELEM_PCDATA;
623           uns c;
624           goto first;
625
626           while (1)
627             {
628               /* After name */
629               xml_parse_dtd_white(ctx, 0);
630               if ((c = xml_get_char(ctx)) ==  ')')
631                 {
632                   xml_dec(ctx);
633                   if (parent->type == XML_DTD_ELEM_PCDATA)
634                     parent->type = XML_DTD_ELEM_SEQ;
635                   if ((c = xml_get_char(ctx)) == '?')
636                     parent->occur = XML_DTD_ELEM_OCCUR_OPT;
637                   else if (c == '*')
638                     parent->occur = XML_DTD_ELEM_OCCUR_MULT;
639                   else if (c == '+')
640                     parent->occur = XML_DTD_ELEM_OCCUR_PLUS;
641                   else
642                     {
643                       xml_unget_char(ctx);
644                       parent->occur = XML_DTD_ELEM_OCCUR_ONCE;
645                     }
646                   if (!parent->parent)
647                     break;
648                   parent = parent->parent;
649                   continue;
650                 }
651               else if (c == '|')
652                 {
653                   if (parent->type == XML_DTD_ELEM_PCDATA)
654                     parent->type = XML_DTD_ELEM_OR;
655                   else if (parent->type != XML_DTD_ELEM_OR)
656                     xml_fatal(ctx, "Mixed operators in the list of element children");
657                 }
658               else if (c == ',')
659                 {
660                   if (parent->type == XML_DTD_ELEM_PCDATA)
661                     parent->type = XML_DTD_ELEM_SEQ;
662                   else if (parent->type != XML_DTD_ELEM_SEQ)
663                     xml_fatal(ctx, "Mixed operators in the list of element children");
664                 }
665               else if (c == '(')
666                 {
667                   xml_inc(ctx);
668                   struct xml_dtd_elem_node *son = mp_alloc_zero(dtd->pool, sizeof(*son));
669                   son->parent = parent;
670                   slist_add_tail(&parent->sons, &son->n);
671                   parent = son->parent;
672                   son->type = XML_DTD_ELEM_MIXED;
673                 }
674               else
675                 xml_unget_char(ctx);
676
677               /* Before name */
678               xml_parse_dtd_white(ctx, 0);
679 first:;
680               struct xml_dtd_elem *son_elem = xml_dtd_elems_lookup(dtd->tab_elems, xml_parse_name(ctx, dtd->pool));
681               // FIXME: duplicates, occurance
682               //struct xml_dtd_elem_node *son = xml_dtd_enodes_new(dtd->tab_enodes, parent, son_elem);
683               struct xml_dtd_elem_node *son = mp_alloc_zero(dtd->pool, sizeof(*son));
684               son->parent = parent;
685               son->elem = son_elem;
686               slist_add_tail(&parent->sons, &son->n);
687             }
688         }
689     }
690   else
691     xml_fatal(ctx, "Expected element content specification");
692
693   xml_parse_dtd_white(ctx, 0);
694   xml_parse_char(ctx, '>');
695   xml_dec(ctx);
696 }
697
698 void
699 xml_parse_attr_list_decl(struct xml_context *ctx)
700 {
701   /* AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
702    * AttDef ::= S Name S AttType S DefaultDecl
703    * Already parsed: '<!ATTLIST' */
704   struct xml_dtd *dtd = ctx->dtd;
705   xml_parse_dtd_white(ctx, 1);
706   struct xml_dtd_elem *elem = xml_dtd_elems_lookup(ctx->dtd->tab_elems, xml_parse_name(ctx, dtd->pool));
707
708   while (xml_parse_dtd_white(ctx, 0) && xml_peek_char(ctx) != '>')
709     {
710       char *name = xml_parse_name(ctx, dtd->pool);
711       struct xml_dtd_attr *attr = xml_dtd_attrs_find(dtd->tab_attrs, elem, name);
712       uns ignored = 0;
713       if (attr)
714         {
715           xml_warn(ctx, "Duplicate attribute definition");
716           ignored++;
717         }
718       else
719         attr = xml_dtd_attrs_new(ctx->dtd->tab_attrs, elem, name);
720       xml_parse_dtd_white(ctx, 1);
721       if (xml_peek_char(ctx) == '(')
722         {
723           xml_skip_char(ctx); // FIXME: xml_inc/dec ?
724           if (!ignored)
725             attr->type = XML_ATTR_ENUM;
726           do
727             {
728               xml_parse_dtd_white(ctx, 0);
729               char *value = xml_parse_nmtoken(ctx, dtd->pool);
730               if (!ignored)
731                 if (xml_dtd_evals_find(ctx->dtd->tab_evals, attr, value))
732                   xml_error(ctx, "Duplicate enumeration value");
733                 else
734                   xml_dtd_evals_new(ctx->dtd->tab_evals, attr, value);
735               xml_parse_dtd_white(ctx, 0);
736             }
737           while (xml_get_char(ctx) == '|');
738           xml_unget_char(ctx);
739           xml_parse_char(ctx, ')');
740         }
741       else
742         {
743           char *type = xml_parse_name(ctx, dtd->pool);
744           enum xml_dtd_attribute_type t = XML_ATTR_CDATA;
745           if (!strcmp(type, "CDATA"))
746             t = XML_ATTR_CDATA;
747           else if (!strcmp(type, "ID"))
748             t = XML_ATTR_ID;
749           else if (!strcmp(type, "IDREF"))
750             t = XML_ATTR_IDREF;
751           else if (!strcmp(type, "IDREFS"))
752             t = XML_ATTR_IDREFS;
753           else if (!strcmp(type, "ENTITY"))
754             t = XML_ATTR_ENTITY;
755           else if (!strcmp(type, "ENTITIES"))
756             t = XML_ATTR_ENTITIES;
757           else if (!strcmp(type, "NMTOKEN"))
758             t = XML_ATTR_NMTOKEN;
759           else if (!strcmp(type, "NMTOKENS"))
760             t = XML_ATTR_NMTOKENS;
761           else if (!strcmp(type, "NOTATION"))
762             {
763               if (elem->type == XML_DTD_ELEM_EMPTY)
764                 xml_fatal(ctx, "Empty element must not have notation attribute");
765               // FIXME: An element type MUST NOT have more than one NOTATION attribute specified.
766               t = XML_ATTR_NOTATION;
767               xml_parse_dtd_white(ctx, 1);
768               xml_parse_char(ctx, '(');
769               do
770                 {
771                   xml_parse_dtd_white(ctx, 0);
772                   struct xml_dtd_notn *n = xml_dtd_notns_lookup(ctx->dtd->tab_notns, xml_parse_name(ctx, dtd->pool));
773                   if (!ignored)
774                     if (xml_dtd_enotns_find(ctx->dtd->tab_enotns, attr, n))
775                       xml_error(ctx, "Duplicate enumerated notation");
776                     else
777                       xml_dtd_enotns_new(ctx->dtd->tab_enotns, attr, n);
778                   xml_parse_dtd_white(ctx, 0);
779                 }
780               while (xml_get_char(ctx) == '|');
781               xml_unget_char(ctx);
782               xml_parse_char(ctx, ')');
783             }
784           else
785             xml_fatal(ctx, "Unknown attribute type");
786           if (!ignored)
787             attr->type = t;
788         }
789       xml_parse_dtd_white(ctx, 1);
790       enum xml_dtd_attribute_default def = XML_ATTR_NONE;
791       if (xml_get_char(ctx) == '#')
792         switch (xml_peek_char(ctx))
793           {
794             case 'R':
795               xml_parse_seq(ctx, "REQUIRED");
796               def = XML_ATTR_REQUIRED;
797               break;
798             case 'I':
799               xml_parse_seq(ctx, "IMPLIED");
800               def = XML_ATTR_IMPLIED;
801               break;
802             case 'F':
803               xml_parse_seq(ctx, "FIXED");
804               def = XML_ATTR_FIXED;
805               xml_parse_dtd_white(ctx, 1);
806               break;
807             default:
808               xml_fatal(ctx, "Expected a modifier for default attribute value");
809           }
810       else
811         xml_unget_char(ctx);
812       if (def != XML_ATTR_REQUIRED && def != XML_ATTR_IMPLIED)
813         {
814           char *v = xml_parse_attr_value(ctx, attr);
815           if (!ignored)
816             attr->default_value = v;
817         }
818       if (!ignored)
819         attr->default_mode = def;
820     }
821   xml_skip_char(ctx);
822   xml_dec(ctx);
823 }