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_LOOKUP
27 #define HASH_GIVE_ALLOC
28 #define HASH_TABLE_ALLOC
30 #include "lib/hashtable.h"
32 /* General entities */
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
44 #include "lib/hashtable.h"
46 static struct xml_dtd_ent *
47 xml_dtd_declare_trivial_ent(struct xml_context *ctx, char *name, char *text)
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)
53 xml_warn(ctx, "Entity &%s; already declared", name);
56 slist_add_tail(&dtd->ents, &ent->n);
57 ent->flags = XML_DTD_ENT_DECLARED | XML_DTD_ENT_TRIVIAL;
59 ent->len = strlen(text);
64 xml_dtd_declare_default_ents(struct xml_context *ctx)
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", "\"");
74 xml_dtd_find_ent(struct xml_context *ctx, char *name)
76 struct xml_dtd *dtd = ctx->dtd;
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;
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, "\"");
90 if (!strcmp(name, "lt"))
94 if (!strcmp(name, "gt"))
98 if (!strcmp(name, "amp"))
100 if (!strcmp(name, "apos"))
104 if (!strcmp(name, "quot"))
112 /* Parameter entities */
114 static struct xml_dtd_ent *
115 xml_dtd_find_pent(struct xml_context *ctx, char *name)
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;
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
134 #include "lib/hashtable.h"
136 struct xml_dtd_elem *
137 xml_dtd_find_elem(struct xml_context *ctx, char *name)
139 return ctx->dtd ? xml_dtd_elems_find(ctx->dtd->tab_elems, name) : NULL;
144 struct xml_dtd_enodes_table;
147 xml_dtd_enodes_hash(struct xml_dtd_enodes_table *tab UNUSED, struct xml_dtd_elem_node *parent, struct xml_dtd_elem *elem)
149 return hash_pointer(parent) ^ hash_pointer(elem);
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)
155 return (parent1 == parent2) && (elem1 == elem2);
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)
161 node->parent = parent;
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
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
179 #include "lib/hashtable.h"
181 /* Element attributes */
183 struct xml_dtd_attrs_table;
186 xml_dtd_attrs_hash(struct xml_dtd_attrs_table *tab UNUSED, struct xml_dtd_elem *elem, char *name)
188 return hash_pointer(elem) ^ hash_string(name);
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)
194 return (elem1 == elem2) && !strcmp(name1, name2);
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)
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
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
218 #include "lib/hashtable.h"
220 struct xml_dtd_attr *
221 xml_dtd_find_attr(struct xml_context *ctx, struct xml_dtd_elem *elem, char *name)
223 return ctx->dtd ? xml_dtd_attrs_find(ctx->dtd->tab_attrs, elem, name) : NULL;
226 /* Enumerated attribute values */
228 struct xml_dtd_evals_table;
231 xml_dtd_evals_hash(struct xml_dtd_evals_table *tab UNUSED, struct xml_dtd_attr *attr, char *val)
233 return hash_pointer(attr) ^ hash_string(val);
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)
239 return (attr1 == attr2) && !strcmp(val1, val2);
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)
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
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
262 #include "lib/hashtable.h"
264 /* Enumerated attribute notations */
266 struct xml_dtd_enotns_table;
269 xml_dtd_enotns_hash(struct xml_dtd_enotns_table *tab UNUSED, struct xml_dtd_attr *attr, struct xml_dtd_notn *notn)
271 return hash_pointer(attr) ^ hash_pointer(notn);
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)
277 return (attr1 == attr2) && (notn1 == notn2);
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)
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
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
300 #include "lib/hashtable.h"
302 /* DTD initialization/cleanup */
305 xml_dtd_init(struct xml_context *ctx)
309 struct mempool *pool = mp_new(4096);
310 struct xml_dtd *dtd = ctx->dtd = mp_alloc_zero(pool, sizeof(*ctx->dtd));
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);
324 xml_dtd_cleanup(struct xml_context *ctx)
328 mp_delete(ctx->dtd->pool);
333 xml_dtd_finish(struct xml_context *ctx)
337 // FIXME: validity checks
340 /*** Parsing functions ***/
342 /* References to parameter entities */
345 xml_parse_pe_ref(struct xml_context *ctx)
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);
355 xml_error(ctx, "Unknown entity %%%s;", name);
358 TRACE(ctx, "Pushed entity %%%s;", name);
359 mp_restore(ctx->stack, &state);
361 xml_push_entity(ctx, ent);
364 mp_restore(ctx->stack, &state);
369 xml_parse_dtd_pe(struct xml_context *ctx)
375 while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
377 xml_parse_pe_ref(ctx);
379 while (xml_peek_char(ctx) != '%');
383 xml_parse_dtd_white(struct xml_context *ctx, uns mandatory)
385 /* Whitespace or parameter entity */
387 while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
392 if (xml_peek_char(ctx) == '%')
394 xml_parse_dtd_pe(ctx);
397 else if (unlikely(mandatory && !cnt))
398 xml_fatal_expected_white(ctx);
403 xml_dtd_parse_external_id(struct xml_context *ctx, struct xml_ext_id *eid, uns allow_public)
405 struct xml_dtd *dtd = ctx->dtd;
406 bzero(eid, sizeof(*eid));
407 uns c = xml_peek_char(ctx);
410 xml_parse_seq(ctx, "SYSTEM");
411 xml_parse_dtd_white(ctx, 1);
412 eid->system_id = xml_parse_system_literal(ctx, dtd->pool);
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);
424 xml_fatal(ctx, "Expected an external ID");
427 /* DTD: <!NOTATION ...> */
430 xml_parse_notation_decl(struct xml_context *ctx)
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);
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, '>');
445 if (notn->flags & XML_DTD_NOTN_DECLARED)
446 xml_warn(ctx, "Notation %s already declared", notn->name);
449 notn->flags = XML_DTD_NOTN_DECLARED;
451 slist_add_tail(&dtd->notns, ¬n->n);
456 /* DTD: <!ENTITY ...> */
459 xml_parse_entity_decl(struct xml_context *ctx)
461 /* Already parsed: '<!ENTITY' */
462 TRACE(ctx, "parse_entity_decl");
463 struct xml_dtd *dtd = ctx->dtd;
464 xml_parse_dtd_white(ctx, 1);
466 uns flags = (xml_get_char(ctx) == '%') ? XML_DTD_ENT_PARAMETER : 0;
468 xml_parse_dtd_white(ctx, 1);
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)
477 xml_fatal(ctx, "Entity &%s; already declared, skipping not implemented", ent->name);
478 // FIXME: should be only warning
481 uns c, sep = xml_get_char(ctx);
482 if (sep == '\'' || sep == '"')
485 * EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | "'" ([^%&'] | PEReference | Reference)* "'" */
486 char *p = mp_start_noalign(dtd->pool, 1);
489 if ((c = xml_get_char(ctx)) == sep)
495 //xml_parse_parameter_ref(ctx);
501 if (xml_peek_char(ctx) != '#')
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, ';');
510 p = mp_spread(dtd->pool, p, 3 + l);
514 mp_restore(ctx->stack, &state);
520 c = xml_parse_char_ref(ctx);
523 p = mp_spread(dtd->pool, p, 5);
524 p = utf8_32_put(p, c);
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;
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) != '>')
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));
548 slist_add_tail(list, &ent->n);
549 ent->flags = flags | XML_DTD_ENT_DECLARED | XML_DTD_ENT_EXTERNAL;
553 xml_parse_dtd_white(ctx, 0);
554 xml_parse_char(ctx, '>');
558 /* DTD: <!ELEMENT ...> */
561 xml_parse_element_decl(struct xml_context *ctx)
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);
573 /* contentspec ::= 'EMPTY' | 'ANY' | Mixed | children */
574 uns c = xml_peek_char(ctx);
577 xml_parse_seq(ctx, "EMPTY");
578 elem->type = XML_DTD_ELEM_EMPTY;
582 xml_parse_seq(ctx, "ANY");
583 elem->type = XML_DTD_ELEM_ANY;
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) == '#')
593 /* Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')' */
595 xml_parse_seq(ctx, "PCDATA");
596 elem->type = XML_DTD_ELEM_MIXED;
597 parent->type = XML_DTD_ELEM_PCDATA;
600 xml_parse_dtd_white(ctx, 0);
601 if ((c = xml_get_char(ctx)) == ')')
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);
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);
616 if (xml_peek_char(ctx) == '*')
619 parent->occur = XML_DTD_ELEM_OCCUR_MULT;
621 else if (!slist_head(&parent->sons))
622 parent->occur = XML_DTD_ELEM_OCCUR_ONCE;
624 xml_fatal_expected(ctx, '*');
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? ')' */
633 elem->type = XML_DTD_ELEM_CHILDREN;
634 parent->type = XML_DTD_ELEM_PCDATA;
641 xml_parse_dtd_white(ctx, 0);
642 if ((c = xml_get_char(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;
650 parent->occur = XML_DTD_ELEM_OCCUR_MULT;
652 parent->occur = XML_DTD_ELEM_OCCUR_PLUS;
656 parent->occur = XML_DTD_ELEM_OCCUR_ONCE;
660 parent = parent->parent;
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");
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");
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;
690 xml_parse_dtd_white(ctx, 0);
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);
703 xml_fatal(ctx, "Expected element content specification");
705 xml_parse_dtd_white(ctx, 0);
706 xml_parse_char(ctx, '>');
711 xml_parse_attr_list_decl(struct xml_context *ctx)
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));
720 while (xml_parse_dtd_white(ctx, 0) && xml_peek_char(ctx) != '>')
722 char *name = xml_parse_name(ctx, dtd->pool);
723 struct xml_dtd_attr *attr = xml_dtd_attrs_find(dtd->tab_attrs, elem, name);
727 xml_warn(ctx, "Duplicate attribute definition");
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) == '(')
735 xml_skip_char(ctx); // FIXME: xml_inc/dec ?
737 attr->type = XML_ATTR_ENUM;
740 xml_parse_dtd_white(ctx, 0);
741 char *value = xml_parse_nmtoken(ctx, dtd->pool);
743 if (xml_dtd_evals_find(ctx->dtd->tab_evals, attr, value))
744 xml_error(ctx, "Duplicate enumeration value");
746 xml_dtd_evals_new(ctx->dtd->tab_evals, attr, value);
747 xml_parse_dtd_white(ctx, 0);
749 while (xml_get_char(ctx) == '|');
751 xml_parse_char(ctx, ')');
755 char *type = xml_parse_name(ctx, dtd->pool);
756 enum xml_dtd_attribute_type t = XML_ATTR_CDATA;
757 if (!strcmp(type, "CDATA"))
759 else if (!strcmp(type, "ID"))
761 else if (!strcmp(type, "IDREF"))
763 else if (!strcmp(type, "IDREFS"))
765 else if (!strcmp(type, "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"))
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, '(');
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));
786 if (xml_dtd_enotns_find(ctx->dtd->tab_enotns, attr, n))
787 xml_error(ctx, "Duplicate enumerated notation");
789 xml_dtd_enotns_new(ctx->dtd->tab_enotns, attr, n);
790 xml_parse_dtd_white(ctx, 0);
792 while (xml_get_char(ctx) == '|');
794 xml_parse_char(ctx, ')');
797 xml_fatal(ctx, "Unknown attribute type");
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))
807 xml_parse_seq(ctx, "REQUIRED");
808 def = XML_ATTR_REQUIRED;
811 xml_parse_seq(ctx, "IMPLIED");
812 def = XML_ATTR_IMPLIED;
815 xml_parse_seq(ctx, "FIXED");
816 def = XML_ATTR_FIXED;
817 xml_parse_dtd_white(ctx, 1);
820 xml_fatal(ctx, "Expected a modifier for default attribute value");
824 if (def != XML_ATTR_REQUIRED && def != XML_ATTR_IMPLIED)
826 char *v = xml_parse_attr_value(ctx, attr);
828 attr->default_value = v;
831 attr->default_mode = def;