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