2 * Sherlock Library -- A simple XML parser
4 * (c) 2007 Pavel Charvat <pchar@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
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"
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
31 #include "lib/hashtable.h"
33 /* General entities */
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
45 #include "lib/hashtable.h"
47 static struct xml_dtd_ent *
48 xml_dtd_declare_trivial_gent(struct xml_context *ctx, char *name, char *text)
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)
54 xml_warn(ctx, "Entity &%s; already declared", name);
57 slist_add_tail(&dtd->gents, &ent->n);
58 ent->flags = XML_DTD_ENT_DECLARED | XML_DTD_ENT_TRIVIAL;
60 ent->len = strlen(text);
65 xml_dtd_declare_default_gents(struct xml_context *ctx)
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", "\"");
75 xml_dtd_find_gent(struct xml_context *ctx, char *name)
77 struct xml_dtd *dtd = ctx->dtd;
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;
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, "\"");
91 if (!strcmp(name, "lt"))
95 if (!strcmp(name, "gt"))
99 if (!strcmp(name, "amp"))
101 if (!strcmp(name, "apos"))
105 if (!strcmp(name, "quot"))
113 /* Parameter entities */
115 static struct xml_dtd_ent *
116 xml_dtd_find_pent(struct xml_context *ctx, char *name)
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;
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
134 #include "lib/hashtable.h"
138 struct xml_dtd_enodes_table;
141 xml_dtd_enodes_hash(struct xml_dtd_enodes_table *tab UNUSED, struct xml_dtd_elem_node *parent, struct xml_dtd_elem *elem)
143 return hash_pointer(parent) ^ hash_pointer(elem);
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)
149 return (parent1 == parent2) && (elem1 == elem2);
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)
155 node->parent = parent;
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
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
173 #include "lib/hashtable.h"
175 /* Element attributes */
177 struct xml_dtd_attrs_table;
180 xml_dtd_attrs_hash(struct xml_dtd_attrs_table *tab UNUSED, struct xml_dtd_elem *elem, char *name)
182 return hash_pointer(elem) ^ hash_string(name);
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)
188 return (elem1 == elem2) && !strcmp(name1, name2);
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)
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
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
212 #include "lib/hashtable.h"
214 /* Enumerated attribute values */
216 struct xml_dtd_evals_table;
219 xml_dtd_evals_hash(struct xml_dtd_evals_table *tab UNUSED, struct xml_dtd_attr *attr, char *val)
221 return hash_pointer(attr) ^ hash_string(val);
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)
227 return (attr1 == attr2) && !strcmp(val1, val2);
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)
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
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
250 #include "lib/hashtable.h"
252 /* Enumerated attribute notations */
254 struct xml_dtd_enotns_table;
257 xml_dtd_enotns_hash(struct xml_dtd_enotns_table *tab UNUSED, struct xml_dtd_attr *attr, struct xml_dtd_notn *notn)
259 return hash_pointer(attr) ^ hash_pointer(notn);
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)
265 return (attr1 == attr2) && (notn1 == notn2);
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)
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
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
288 #include "lib/hashtable.h"
290 /* DTD initialization/cleanup */
293 xml_dtd_init(struct xml_context *ctx)
297 struct mempool *pool = mp_new(4096);
298 struct xml_dtd *dtd = ctx->dtd = mp_alloc_zero(pool, sizeof(*ctx->dtd));
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);
312 xml_dtd_cleanup(struct xml_context *ctx)
316 mp_delete(ctx->dtd->pool);
321 xml_dtd_finish(struct xml_context *ctx)
325 // FIXME: validity checks
328 /*** Parsing functions ***/
330 /* References to parameter entities */
333 xml_parse_pe_ref(struct xml_context *ctx)
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);
343 xml_error(ctx, "Unknown entity %%%s;", name);
346 TRACE(ctx, "Pushed entity %%%s;", name);
347 mp_restore(ctx->stack, &state);
349 xml_push_entity(ctx, ent);
352 mp_restore(ctx->stack, &state);
357 xml_parse_dtd_pe(struct xml_context *ctx)
363 while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
365 xml_parse_pe_ref(ctx);
367 while (xml_peek_char(ctx) != '%');
371 xml_parse_dtd_white(struct xml_context *ctx, uns mandatory)
373 /* Whitespace or parameter entity */
375 while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
380 if (xml_peek_char(ctx) == '%')
382 xml_parse_dtd_pe(ctx);
385 else if (unlikely(mandatory && !cnt))
386 xml_fatal_expected_white(ctx);
391 xml_dtd_parse_external_id(struct xml_context *ctx, struct xml_ext_id *eid, uns allow_public)
393 struct xml_dtd *dtd = ctx->dtd;
394 bzero(eid, sizeof(*eid));
395 uns c = xml_peek_char(ctx);
398 xml_parse_seq(ctx, "SYSTEM");
399 xml_parse_dtd_white(ctx, 1);
400 eid->system_id = xml_parse_system_literal(ctx, dtd->pool);
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);
412 xml_fatal(ctx, "Expected an external ID");
415 /* DTD: <!NOTATION ...> */
418 xml_parse_notation_decl(struct xml_context *ctx)
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);
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, '>');
433 if (notn->flags & XML_DTD_NOTN_DECLARED)
434 xml_warn(ctx, "Notation %s already declared", notn->name);
437 notn->flags = XML_DTD_NOTN_DECLARED;
439 slist_add_tail(&dtd->notns, ¬n->n);
444 /* DTD: <!ENTITY ...> */
447 xml_parse_entity_decl(struct xml_context *ctx)
449 /* Already parsed: '<!ENTITY' */
450 TRACE(ctx, "parse_entity_decl");
451 struct xml_dtd *dtd = ctx->dtd;
452 xml_parse_dtd_white(ctx, 1);
454 uns flags = (xml_get_char(ctx) == '%') ? XML_DTD_ENT_PARAMETER : 0;
456 xml_parse_dtd_white(ctx, 1);
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)
465 xml_fatal(ctx, "Entity &%s; already declared, skipping not implemented", ent->name);
466 // FIXME: should be only warning
469 uns c, sep = xml_get_char(ctx);
470 if (sep == '\'' || sep == '"')
473 * EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | "'" ([^%&'] | PEReference | Reference)* "'" */
474 char *p = mp_start_noalign(dtd->pool, 1);
477 if ((c = xml_get_char(ctx)) == sep)
483 //xml_parse_parameter_ref(ctx);
489 if (xml_peek_char(ctx) != '#')
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, ';');
498 p = mp_spread(dtd->pool, p, 3 + l);
502 mp_restore(ctx->stack, &state);
508 c = xml_parse_char_ref(ctx);
511 p = mp_spread(dtd->pool, p, 5);
512 p = utf8_32_put(p, c);
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;
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) != '>')
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));
536 slist_add_tail(list, &ent->n);
537 ent->flags = flags | XML_DTD_ENT_DECLARED | XML_DTD_ENT_EXTERNAL;
541 xml_parse_dtd_white(ctx, 0);
542 xml_parse_char(ctx, '>');
546 /* DTD: <!ELEMENT ...> */
549 xml_parse_element_decl(struct xml_context *ctx)
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);
561 /* contentspec ::= 'EMPTY' | 'ANY' | Mixed | children */
562 uns c = xml_peek_char(ctx);
565 xml_parse_seq(ctx, "EMPTY");
566 elem->type = XML_DTD_ELEM_EMPTY;
570 xml_parse_seq(ctx, "ANY");
571 elem->type = XML_DTD_ELEM_ANY;
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) == '#')
581 /* Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')' */
583 xml_parse_seq(ctx, "PCDATA");
584 elem->type = XML_DTD_ELEM_MIXED;
585 parent->type = XML_DTD_ELEM_PCDATA;
588 xml_parse_dtd_white(ctx, 0);
589 if ((c = xml_get_char(ctx)) == ')')
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);
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);
604 if (xml_peek_char(ctx) == '*')
607 parent->occur = XML_DTD_ELEM_OCCUR_MULT;
609 else if (!slist_head(&parent->sons))
610 parent->occur = XML_DTD_ELEM_OCCUR_ONCE;
612 xml_fatal_expected(ctx, '*');
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? ')' */
621 elem->type = XML_DTD_ELEM_CHILDREN;
622 parent->type = XML_DTD_ELEM_PCDATA;
629 xml_parse_dtd_white(ctx, 0);
630 if ((c = xml_get_char(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;
638 parent->occur = XML_DTD_ELEM_OCCUR_MULT;
640 parent->occur = XML_DTD_ELEM_OCCUR_PLUS;
644 parent->occur = XML_DTD_ELEM_OCCUR_ONCE;
648 parent = parent->parent;
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");
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");
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;
678 xml_parse_dtd_white(ctx, 0);
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);
691 xml_fatal(ctx, "Expected element content specification");
693 xml_parse_dtd_white(ctx, 0);
694 xml_parse_char(ctx, '>');
699 xml_parse_attr_list_decl(struct xml_context *ctx)
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));
708 while (xml_parse_dtd_white(ctx, 0) && xml_peek_char(ctx) != '>')
710 char *name = xml_parse_name(ctx, dtd->pool);
711 struct xml_dtd_attr *attr = xml_dtd_attrs_find(dtd->tab_attrs, elem, name);
715 xml_warn(ctx, "Duplicate attribute definition");
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) == '(')
723 xml_skip_char(ctx); // FIXME: xml_inc/dec ?
725 attr->type = XML_ATTR_ENUM;
728 xml_parse_dtd_white(ctx, 0);
729 char *value = xml_parse_nmtoken(ctx, dtd->pool);
731 if (xml_dtd_evals_find(ctx->dtd->tab_evals, attr, value))
732 xml_error(ctx, "Duplicate enumeration value");
734 xml_dtd_evals_new(ctx->dtd->tab_evals, attr, value);
735 xml_parse_dtd_white(ctx, 0);
737 while (xml_get_char(ctx) == '|');
739 xml_parse_char(ctx, ')');
743 char *type = xml_parse_name(ctx, dtd->pool);
744 enum xml_dtd_attribute_type t = XML_ATTR_CDATA;
745 if (!strcmp(type, "CDATA"))
747 else if (!strcmp(type, "ID"))
749 else if (!strcmp(type, "IDREF"))
751 else if (!strcmp(type, "IDREFS"))
753 else if (!strcmp(type, "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"))
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, '(');
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));
774 if (xml_dtd_enotns_find(ctx->dtd->tab_enotns, attr, n))
775 xml_error(ctx, "Duplicate enumerated notation");
777 xml_dtd_enotns_new(ctx->dtd->tab_enotns, attr, n);
778 xml_parse_dtd_white(ctx, 0);
780 while (xml_get_char(ctx) == '|');
782 xml_parse_char(ctx, ')');
785 xml_fatal(ctx, "Unknown attribute type");
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))
795 xml_parse_seq(ctx, "REQUIRED");
796 def = XML_ATTR_REQUIRED;
799 xml_parse_seq(ctx, "IMPLIED");
800 def = XML_ATTR_IMPLIED;
803 xml_parse_seq(ctx, "FIXED");
804 def = XML_ATTR_FIXED;
805 xml_parse_dtd_white(ctx, 1);
808 xml_fatal(ctx, "Expected a modifier for default attribute value");
812 if (def != XML_ATTR_REQUIRED && def != XML_ATTR_IMPLIED)
814 char *v = xml_parse_attr_value(ctx, attr);
816 attr->default_value = v;
819 attr->default_mode = def;