1 #include <string.h>
2 
3 #ifdef FOR_LT
4 
5 #include "lt-memory.h"
6 #include "nsllib.h"
7 
8 #define Malloc salloc
9 #define Realloc srealloc
10 #define Free sfree
11 
12 #else
13 
14 #include "system.h"
15 
16 #endif
17 
18 #include "charset.h"
19 #include "string16.h"
20 #include "dtd.h"
21 #include "url.h"
22 
23 extern void FreeFSM(FSM fsm);	/* XXX should be in header */
24 
25 const char8 *DefaultTypeName[DT_enum_count] = {
26     "#REQUIRED",
27     "bogus1",
28     "#IMPLIED",
29     "bogus2",
30     "NONE",
31     "#FIXED",
32 };
33 
34 const char8 *ContentParticleTypeName[CP_enum_count] = {
35     "#PCDATA",
36     "NAME",
37     "SEQUENCE",
38     "CHOICE"
39 };
40 
41 const char8 *ContentTypeName[CT_enum_count] = {
42     "MIXED",
43     "ANY",
44     "bogus1",
45     "bogus2",
46     "EMPTY",
47     "ELEMENT"
48 };
49 
50 const char8 *AttributeTypeName[AT_enum_count] = {
51     "CDATA",
52     "bogus1",
53     "bogus2",
54     "NMTOKEN",
55     "bogus3",
56     "ENTITY",
57     "IDREF",
58     "bogus4",
59     "bogus5",
60     "NMTOKENS",
61     "bogus6",
62     "ENTITIES",
63     "IDREFS",
64     "ID",
65     "NOTATION",
66     "ENUMERATION"
67 };
68 
69 const char8 *StandaloneDeclarationName[SDD_enum_count] = {
70     "unspecified", "no", "yes"
71 };
72 
Strndup(const Char * old,int len)73 static Char *Strndup(const Char *old, int len)
74 {
75     Char *new = Malloc((len+1) * sizeof(Char));
76 
77     if(!new)
78 	return 0;
79 
80     memcpy(new, old, len * sizeof(Char));
81     new[len] = 0;
82 
83     return new;
84 }
85 
86 /* DTDs */
87 
NewDtd(void)88 Dtd NewDtd(void)
89 {
90     Dtd d;
91 
92     if(!(d = Malloc(sizeof(*d))))
93 	return 0;
94 
95     d->name = 0;
96     d->internal_part = 0;
97     d->external_part = 0;
98     d->entities = 0;
99     d->parameter_entities = 0;
100     d->predefined_entities = 0;
101 #ifdef FOR_LT
102     d->doctype = 0;
103 #endif
104     d->nelements = 0;
105     d->neltalloc = 20;
106     d->elements = Malloc(d->neltalloc * sizeof(ElementDefinition));
107     if(!d->elements)
108 	return 0;
109     d->notations = 0;
110     d->namespace_universe = 0;	/* the global universe */
111 
112     return d;
113 }
114 
115 /* Free a DTD and everything in it */
116 
FreeDtd(Dtd dtd)117 void FreeDtd(Dtd dtd)
118 {
119     Entity ent, ent1;
120     int i;
121     NotationDefinition not, not1;
122 
123     if(!dtd)
124 	return;
125 
126     /* Free the name */
127 
128     Free((Char *)dtd->name);	/* cast is to get rid of const */
129 
130     /* Free the entities */
131 
132     FreeEntity(dtd->internal_part);
133     FreeEntity(dtd->external_part);
134 
135     for(ent = dtd->entities; ent; ent = ent1)
136     {
137 	ent1 = ent->next;	/* get it before we free ent! */
138 	FreeEntity(ent);
139     }
140 
141     for(ent = dtd->parameter_entities; ent; ent = ent1)
142     {
143 	ent1 = ent->next;
144 	FreeEntity(ent);
145     }
146 
147     /* The predefined entities are shared, so we don't free them */
148 
149     /* Free the elements */
150 
151     for(i=0; i<dtd->nelements; i++)
152 	FreeElementDefinition(dtd->elements[i]); /* Frees the attributes too */
153 
154     Free(dtd->elements);
155 
156     /* Free the notations */
157 
158     for(not = dtd->notations; not; not = not1)
159     {
160 	not1 = not->next;
161 	FreeNotationDefinition(not);
162     }
163 
164     /* Free the dtd itself */
165 
166     Free(dtd);
167 }
168 
169 /* Entities */
170 
171 /*
172  * Make a new entity.  The name and IDs are copied.
173  */
174 
NewExternalEntity(const Char * name,char8 * publicid,const char8 * systemid,NotationDefinition notation,Entity parent)175 Entity NewExternalEntity(const Char *name, char8 *publicid,
176 			 const char8 *systemid, NotationDefinition notation,
177 			 Entity parent)
178 {
179     if(publicid && !(publicid = strdup8(publicid))) {
180 	return 0;
181     }
182     return NewExternalEntityN(name, name ? Strlen(name) : 0, publicid,
183 			      systemid, notation, parent);
184 }
185 
186 /* NB doesn't copy IDs */
187 
NewExternalEntityN(const Char * name,int namelen,char8 * publicid,const char8 * systemid,NotationDefinition notation,Entity parent)188 Entity NewExternalEntityN(const Char *name, int namelen, char8 *publicid,
189 			  const char8 *systemid, NotationDefinition notation,
190 			  Entity parent)
191 {
192     Entity e;
193 
194     if (!(e = Malloc(sizeof(*e))))
195 	return NULL;
196     if (name) {
197 	if (!(e->name = Strndup(name, namelen)))
198 	    return NULL;
199     } else
200     	e->name = NULL;
201 
202     e->type = ET_external;
203     e->base_url = 0;
204     e->encoding = CE_unknown;
205     e->next = 0;
206     e->parent = parent;
207 
208     e->publicid = publicid;
209     e->systemid = systemid;
210     e->notation = notation;
211 
212     e->ml_decl = ML_unspecified;
213     e->version_decl = 0;
214     e->encoding_decl = CE_unknown;
215     e->standalone_decl = SDD_unspecified;
216     e->ddb_filename = 0;
217     e->xml_version = XV_1_0;	/* 1.0 unless otherwise specified */
218 
219     e->url = 0;
220 
221     e->is_externally_declared = 0;
222     e->is_internal_subset = 0;
223 
224     return (Entity)e;
225 }
226 
NewInternalEntityN(const Char * name,int namelen,const Char * text,Entity parent,int line_offset,int line1_char_offset,int matches_parent_text)227 Entity NewInternalEntityN(const Char *name, int namelen,
228 			  const Char *text, Entity parent,
229 			  int line_offset, int line1_char_offset,
230 			  int matches_parent_text)
231 {
232     Entity e;
233 
234     if(!(e = Malloc(sizeof(*e))))
235 	return 0;
236     if(name) {
237 	if(!(e->name = Strndup(name, namelen)))
238 	    return NULL;
239     } else
240         e->name = NULL;
241 
242     e->type = ET_internal;
243     e->base_url = 0;
244     e->encoding = InternalCharacterEncoding;
245     e->next = 0;
246     e->parent = parent;
247 
248     e->text = text;
249     e->line_offset = line_offset;
250     e->line1_char_offset = line1_char_offset;
251     e->matches_parent_text = matches_parent_text;
252 
253     e->url = 0;
254 
255     e->is_externally_declared = 0;
256     e->is_internal_subset = 0;
257 
258     /* These should not really be accessed for an internal entity, but
259        because the NSL layer uses internal entities to implement reading
260        from strings, sometimes they are. */
261 
262     e->publicid = 0;
263     e->systemid = 0;
264     e->notation = 0;
265 
266     e->ml_decl = ML_unspecified;
267     e->version_decl = 0;
268     e->encoding_decl = CE_unknown;
269     e->standalone_decl = SDD_unspecified;
270     e->ddb_filename = 0;
271 
272     return (Entity)e;
273 }
274 
FreeEntity(Entity e)275 void FreeEntity(Entity e)
276 {
277     if(!e)
278 	return;
279 
280     if (e->name)
281 	Free(e->name);
282     Free(e->base_url);
283     Free(e->url);
284 
285     switch(e->type)
286     {
287     case ET_internal:
288 	Free((void *)e->atext);
289 	break;
290     case ET_external:
291 	/* Free((void *)e->systemid); XXX const string passed by client */
292 	Free(e->publicid);
293 	Free(e->version_decl);
294 	Free(e->ddb_filename);
295 	break;
296     }
297 
298     Free(e);
299 }
300 
EntityURL(Entity e)301 const char8 *EntityURL(Entity e)
302 {
303     /* Have we already determined the URL? */
304 
305     if(e->url)
306 	return e->url;
307 
308     if(e->type == ET_internal)
309     {
310 	if(e->parent)
311 	{
312 	    const char8 *url = EntityURL(e->parent);
313 	    if(url)
314 		e->url = strdup8(url);
315 	}
316     }
317     else
318 	e->url = url_merge(e->systemid,
319 			   e->parent ? EntityBaseURL(e->parent) : 0,
320 			   0, 0, 0, 0);
321 
322     return e->url;
323 }
324 
325 /* Returns the URL of the entity if it has one, otherwise the system ID.
326    It will certainly have a URL if it was successfully opened by EntityOpen.
327    Intended for error messages, so never returns NULL. */
328 
EntityDescription(Entity e)329 const char8 *EntityDescription(Entity e)
330 {
331     if(e->url)
332 	return e->url;
333 
334     if(e->type == ET_external)
335 	return e->systemid;
336 
337     if(e->parent)
338 	return EntityDescription(e->parent);
339 
340     return "<unknown>";
341 }
342 
EntitySetBaseURL(Entity e,const char8 * url)343 void EntitySetBaseURL(Entity e, const char8 *url)
344 {
345     if(e->base_url)
346 	Free((void *)e->base_url);
347     e->base_url = strdup8(url);
348 }
349 
EntityBaseURL(Entity e)350 const char8 *EntityBaseURL(Entity e)
351 {
352     if(e->base_url)
353 	return e->base_url;
354 
355     if(e->type == ET_internal)
356     {
357 	if(e->parent)
358 	    return EntityBaseURL(e->parent);
359 	else
360 	    return 0;
361     }
362 
363     return EntityURL(e);
364 }
365 
DefineEntity(Dtd dtd,Entity e,int pe)366 Entity DefineEntity(Dtd dtd, Entity e, int pe)
367 {
368     if(pe)
369     {
370 	e->next = dtd->parameter_entities;
371 	dtd->parameter_entities = e;
372     }
373     else
374     {
375 	e->next = dtd->entities;
376 	dtd->entities = e;
377     }
378 
379     return e;
380 }
381 
FindEntityN(Dtd dtd,const Char * name,int namelen,int pe)382 Entity FindEntityN(Dtd dtd, const Char *name, int namelen, int pe)
383 {
384     Entity e;
385 
386     if(!pe)
387 	for(e = dtd->predefined_entities; e; e = e->next)
388 	    if(Strncmp(name, e->name, namelen) == 0 && e->name[namelen] == 0)
389 		return e;
390 
391 
392     for(e = pe ? dtd->parameter_entities : dtd->entities; e; e=e->next)
393 	if(Strncmp(name, e->name, namelen) == 0 && e->name[namelen] == 0)
394 	    return e;
395 
396     return 0;
397 }
398 
NextEntity(Dtd dtd,Entity previous)399 Entity NextEntity(Dtd dtd, Entity previous)
400 {
401     return previous ? previous->next : dtd->entities;
402 }
403 
NextParameterEntity(Dtd dtd,Entity previous)404 Entity NextParameterEntity(Dtd dtd, Entity previous)
405 {
406     return previous ? previous->next : dtd->parameter_entities;
407 }
408 
409 /* Elements */
410 
411 /*
412  * Define a new element.  The name is copied, the content model is not,
413  * but it is freed when the element definition is freed!
414  */
415 
DefineElementN(Dtd dtd,const Char * name,int namelen,ContentType type,Char * content,ContentParticle particle,int declared)416 ElementDefinition DefineElementN(Dtd dtd, const Char *name, int namelen,
417 				 ContentType type, Char *content,
418 				 ContentParticle particle, int declared)
419 {
420     ElementDefinition e;
421     const Char *t;
422 #ifdef FOR_LT
423     RHTEntry *entry;
424 #endif
425 
426     if(!(e = Malloc(sizeof(*e))))
427 	return 0;
428 
429     e->eltnum = dtd->nelements++;
430     if(e->eltnum >= dtd->neltalloc)
431     {
432 	dtd->neltalloc *= 2;
433 	dtd->elements =
434 	   Realloc(dtd->elements, dtd->neltalloc * sizeof(ElementDefinition));
435 	if(!dtd->elements)
436 	    return 0;
437     }
438     dtd->elements[e->eltnum] = e;
439 
440 #ifdef FOR_LT
441     entry = DeclareElement(dtd->doctype, name, namelen, 0, (ctVals)type);
442     if (!entry)
443 	return 0;
444 
445     e->doctype = dtd->doctype;
446     e->eltsum =
447 	(NSL_ElementSummary_I *)(dtd->doctype->permanentBase+entry->eval);
448 
449     *(short *)&(e->eltsum->omitEnd) = e->eltnum;
450 
451     name = (Char *)dtd->doctype->elements+entry->keyptr;
452 #else
453     if(!(e->name = Strndup(name, namelen)))
454 	return 0;
455 #endif
456 
457     e->tentative = 0;
458     e->namelen = namelen;
459     e->type = type;
460     e->content = content;
461     e->particle = particle;
462     e->declared = declared;
463     e->has_attlist = 0;
464     e->fsm = 0;
465     e->nattributes = 0;
466     e->nattralloc = 20;
467     e->attributes = Malloc(e->nattralloc * sizeof(AttributeDefinition));
468     if(!e->attributes)
469 	return 0;
470     e->id_attribute = 0;
471     e->xml_space_attribute = 0;
472     e->xml_lang_attribute = 0;
473     e->xml_id_attribute = 0;
474     e->notation_attribute = 0;
475     e->cached_nsdef = 0;
476     e->is_externally_declared = 0;
477 
478     if((t = Strchr(name, ':')))
479     {
480 	if(!(e->prefix = Strndup(name, t - name)))
481 	    return 0;
482 	e->local = t+1;
483     }
484     else
485     {
486 	e->local = name;
487 	e->prefix = 0;
488     }
489 
490     return e;
491 }
492 
TentativelyDefineElementN(Dtd dtd,const Char * name,int namelen)493 ElementDefinition TentativelyDefineElementN(Dtd dtd,
494 					    const Char *name, int namelen)
495 {
496     ElementDefinition e;
497 
498     if(!(e = DefineElementN(dtd, name, namelen, CT_any, 0, 0, 1)))
499 	return 0;
500 
501     e->tentative = 1;
502 
503     return e;
504 }
505 
RedefineElement(ElementDefinition e,ContentType type,Char * content,ContentParticle particle,int declared)506 ElementDefinition RedefineElement(ElementDefinition e, ContentType type,
507 				  Char *content, ContentParticle particle, int declared)
508 {
509 #ifdef FOR_LT
510     e->eltsum->contentType = type;
511 #endif
512 
513     e->tentative = 0;
514     e->type = type;
515     e->content = content;
516     e->particle = particle;
517     e->declared = declared;
518 
519     return e;
520 }
521 
FindElementN(Dtd dtd,const Char * name,int namelen)522 ElementDefinition FindElementN(Dtd dtd, const Char *name, int namelen)
523 {
524     ElementDefinition e;
525 
526 #ifdef FOR_LT
527     /* Derived from FindElementAndName */
528 
529     RHTEntry *entry;
530     NSL_ElementSummary_I *eltsum;
531 
532     if(!dtd->doctype)
533 	return 0;
534 
535     entry = rsearch(name, namelen, dtd->doctype->elements);
536     if(!entry)
537 	return 0;
538     eltsum = (NSL_ElementSummary_I *)(dtd->doctype->permanentBase+entry->eval);
539 
540     if(!dtd->doctype->XMLMode)
541     {
542 	/* NSL mode - we have to fake a structure */
543 
544 	e = &dtd->fake_elt;
545 	e->doctype = dtd->doctype;
546 	e->name = (Char *)dtd->doctype->elements+entry->keyptr;
547 	e->eltsum = eltsum;
548 	e->tentative = 0;
549 
550 	return e;
551     }
552 
553     return dtd->elements[*(short *)&(eltsum->omitEnd)];
554 #else
555     int i;
556 
557     for(i=dtd->nelements-1; i>=0; i--)
558     {
559 	e = dtd->elements[i];
560 	if(namelen == e->namelen && *name == *e->name &&
561 	   memcmp(name, e->name, namelen*sizeof(Char)) == 0)
562 	    return e;
563     }
564 
565     return 0;
566 #endif
567 }
568 
NamespacifyElementDefinition(ElementDefinition element,Namespace ns)569 NSElementDefinition NamespacifyElementDefinition(ElementDefinition element,
570 						 Namespace ns)
571 {
572     if(element->cached_nsdef && element->cached_nsdef->namespace == ns)
573 	return element->cached_nsdef;
574 
575     element->cached_nsdef = FindNSElementDefinition(ns, element->local, 1);
576     return element->cached_nsdef;
577 }
578 
NextElementDefinition(Dtd dtd,ElementDefinition previous)579 ElementDefinition NextElementDefinition(Dtd dtd, ElementDefinition previous)
580 {
581     int next = previous ? previous->eltnum+1 : 0;
582     return next < dtd->nelements ? dtd->elements[next] : 0;
583 }
584 
585 /* Free an element definition and its attribute definitions */
586 
FreeElementDefinition(ElementDefinition e)587 void FreeElementDefinition(ElementDefinition e)
588 {
589     int i;
590 
591     if(!e)
592 	return;
593 
594     /* Free the attributes */
595 
596     for(i=0; i<e->nattributes; i++)
597 	FreeAttributeDefinition(e->attributes[i]);
598     Free(e->attributes);
599 
600 
601 #ifndef FOR_LT
602     /* Free the element name (kept elsewhere in NSL) */
603 
604     Free((void *)e->name);
605 #endif
606 
607     Free((void *)e->prefix);
608 
609     /* Free the content model */
610     Free(e->content);
611     FreeContentParticle(e->particle);
612     FreeFSM(e->fsm);
613 
614     /* Free the ElementDefinition itself */
615     Free(e);
616 }
617 
618 /* Attributes */
619 
620 /*
621  * Define a new attribute.  The name is copied, the allowed values and
622  * default are not, but they are freed when the attribute definition is freed!
623  */
624 
625 AttributeDefinition
DefineAttributeN(ElementDefinition element,const Char * name,int namelen,AttributeType type,Char ** allowed_values,DefaultType default_type,Char * default_value,int declared)626     DefineAttributeN(ElementDefinition element, const Char *name, int namelen,
627 		     AttributeType type, Char **allowed_values,
628 		     DefaultType default_type, Char *default_value,
629 		     int declared)
630 {
631 #ifdef FOR_LT
632     int nav = 0;
633     Char **avp;
634     NSL_Doctype_I *doctype = element->doctype;
635 #endif
636     AttributeDefinition a;
637     static Char xml_space[] = {'x','m','l',':','s','p','a','c','e',0};
638     static Char xml_lang[] = {'x','m','l',':','l','a','n','g',0};
639     static Char xml_id[] = {'x','m','l',':','i','d',0};
640     static Char xmlns[] = {'x','m','l','n','s',0};
641     const Char *t;
642 
643     if(!(a= Malloc(sizeof(*a))))
644 	return 0;
645 
646     a->attrnum = element->nattributes++;
647     if(a->attrnum >= element->nattralloc)
648     {
649 	element->nattralloc *= 2;
650 	element->attributes =
651 	   Realloc(element->attributes,
652 		   element->nattralloc * sizeof(AttributeDefinition));
653 	if(!element->attributes)
654 	    return 0;
655     }
656     element->attributes[a->attrnum] = a;
657 
658 #ifdef FOR_LT
659     if(allowed_values)
660     {
661 	for(avp = allowed_values; *avp; avp++)
662 	    nav++;
663     }
664 
665     if (!(name = DeclareAttr(doctype, name, namelen,
666 			     (NSL_Attr_Declared_Value)type,
667 			     allowed_values?allowed_values[0]:0, nav,
668 			     (NSL_ADefType)default_type, default_value,
669 			     &element->eltsum, element->name)))
670 	return 0;
671 
672     a->attrsum = FindAttrSpec(element->eltsum, doctype, name);
673 #else
674     if(!(a->name = Strndup(name, namelen)))
675 	return 0;
676 #endif
677 
678     a->namelen = namelen;
679     a->type = type;
680     a->allowed_values = allowed_values;
681     a->default_type = default_type;
682     a->default_value = default_value;
683     a->declared = declared;
684     if(declared)
685 	element->has_attlist = 1;
686     a->is_externally_declared = 0;
687 
688     if(a->type == AT_id && !element->id_attribute)
689 	element->id_attribute = a;
690     else if(a->type == AT_notation && !element->notation_attribute)
691 	element->notation_attribute = a;
692 
693     if(Strcmp(name, xml_space) == 0)
694 	element->xml_space_attribute = a;
695     else if(Strcmp(name, xml_lang) == 0)
696 	element->xml_lang_attribute = a;
697     else if(Strcmp(name, xml_id) == 0)
698 	element->xml_id_attribute = a;
699 
700     a->cached_nsdef = 0;
701 
702     if((t = Strchr(name, ':')))
703     {
704 	if(!(a->prefix = Strndup(name, t - name)))
705 	    return 0;
706 	a->local = t+1;
707 	if(Strcmp(a->prefix, xmlns) == 0)
708 	    a->ns_attr_prefix = a->local;
709 	else
710 	    a->ns_attr_prefix = 0;
711     }
712     else
713     {
714 	a->local = name;
715 	a->prefix = 0;
716 	if(Strcmp(name, xmlns) == 0)
717 	    a->ns_attr_prefix = name+5; /* point to the null */
718 	else
719 	    a->ns_attr_prefix = 0;
720     }
721 
722     return a;
723 }
724 
FindAttributeN(ElementDefinition element,const Char * name,int namelen)725 AttributeDefinition FindAttributeN(ElementDefinition element,
726 				   const Char *name, int namelen)
727 {
728     int i;
729 
730 #ifdef FOR_LT
731     if(!(name = AttrUniqueName(element->doctype, name, namelen)))
732 	return 0;
733     if(!element->doctype->XMLMode)
734 	/* XXX Hack for NSL documents.
735 	   Return the attribute summary itself.
736 	   Nothing in the RXP layer had better look at it! */
737 	return (AttributeDefinition)FindAttrSpec(element->eltsum,
738 						 element->doctype,
739 						 name);
740     if(!FindAttrSpecAndNumber(element->eltsum, element->doctype, name, &i))
741 	return 0;
742     if(i < 0)
743 	i = element->nattributes + i;
744 
745     return element->attributes[i];
746 #else
747     for(i=element->nattributes-1; i>=0; i--)
748     {
749 	AttributeDefinition a = element->attributes[i];
750 
751 	if(namelen == a->namelen &&
752 	   memcmp(name, a->name, namelen * sizeof(Char)) == 0)
753 	    return a;
754     }
755 
756     return 0;
757 #endif
758 }
759 
760 NSAttributeDefinition
NamespacifyGlobalAttributeDefinition(AttributeDefinition attribute,Namespace ns)761     NamespacifyGlobalAttributeDefinition(AttributeDefinition attribute,
762 					 Namespace ns)
763 {
764     if(attribute->cached_nsdef &&
765        !attribute->cached_nsdef->element &&
766        attribute->cached_nsdef->namespace == ns)
767 	return attribute->cached_nsdef;
768 
769     attribute->cached_nsdef =
770 	FindNSGlobalAttributeDefinition(ns, attribute->local, 1);
771     return attribute->cached_nsdef;
772 }
773 
774 NSAttributeDefinition
NamespacifyElementAttributeDefinition(AttributeDefinition attribute,NSElementDefinition nselt)775     NamespacifyElementAttributeDefinition(AttributeDefinition attribute,
776 					  NSElementDefinition nselt)
777 {
778     if(attribute->cached_nsdef &&
779        attribute->cached_nsdef->element &&
780        attribute->cached_nsdef->element == nselt)
781 	return attribute->cached_nsdef;
782 
783     attribute->cached_nsdef =
784 	FindNSElementAttributeDefinition(nselt, attribute->local, 1);
785     return attribute->cached_nsdef;
786 }
787 
NextAttributeDefinition(ElementDefinition element,AttributeDefinition previous)788 AttributeDefinition NextAttributeDefinition(ElementDefinition element,
789 					    AttributeDefinition previous)
790 {
791     int next = previous ? previous->attrnum+1 : 0;
792     return next < element->nattributes ? element->attributes[next] : 0;
793 }
794 
795 /* Free an attribute definition */
796 
FreeAttributeDefinition(AttributeDefinition a)797 void FreeAttributeDefinition(AttributeDefinition a)
798 {
799     if(!a)
800 	return;
801 
802 #ifndef FOR_LT
803     /* These things are stored elsewhere in NSL */
804 
805     /* Free the name */
806 
807     Free((void *)a->name);
808 
809     /* Free the allowed values - we rely on them being allocated as in
810        xmlparser.c: the Char * pointers point into one single block. */
811 
812     if(a->allowed_values)
813 	Free(a->allowed_values[0]);
814 
815     /* Free the default value */
816 
817     Free((void *)a->default_value);
818 
819 #endif
820     /* NSL doesn't ever get its hands on this */
821 
822     Free(a->allowed_values);
823 
824     Free((void *)a->prefix);
825 
826     /* Free the attribute definition itself */
827 
828     Free(a);
829 }
830 
831 /* Notations */
832 
833 /*
834  * Define a new notation.  The name is copied, the system and public ids are
835  * not, but they are freed when the notation definition is freed!
836  */
837 
DefineNotationN(Dtd dtd,const Char * name,int namelen,char8 * publicid,char8 * systemid,Entity parent)838 NotationDefinition DefineNotationN(Dtd dtd, const Char *name, int namelen,
839 				   char8 *publicid, char8 *systemid,
840 				   Entity parent)
841 {
842     NotationDefinition n;
843 
844     if(!(n = Malloc(sizeof(*n))) || !(n->name = Strndup(name, namelen)))
845 	return 0;
846 
847     n->tentative = 0;
848     n->systemid = systemid;
849     n->publicid = publicid;
850     n->url = 0;
851     n->parent = parent;
852     n->next = dtd->notations;
853     dtd->notations = n;
854 
855     return n;
856 }
857 
TentativelyDefineNotationN(Dtd dtd,const Char * name,int namelen)858 NotationDefinition TentativelyDefineNotationN(Dtd dtd,
859 					      const Char *name, int namelen)
860 {
861     NotationDefinition n;
862 
863     if(!(n = DefineNotationN(dtd, name, namelen, 0, 0, 0)))
864 	return 0;
865 
866     n->tentative = 1;
867 
868     return n;
869 }
870 
RedefineNotation(NotationDefinition n,char8 * publicid,char8 * systemid,Entity parent)871 NotationDefinition RedefineNotation(NotationDefinition n,
872 				    char8 *publicid, char8 *systemid,
873 				    Entity parent)
874 {
875     n->tentative = 0;
876     n->systemid = systemid;
877     n->publicid = publicid;
878     n->parent = parent;
879 
880     return n;
881 }
882 
FindNotationN(Dtd dtd,const Char * name,int namelen)883 NotationDefinition FindNotationN(Dtd dtd, const Char *name, int namelen)
884 {
885     NotationDefinition n;
886 
887     for(n = dtd->notations; n; n = n->next)
888 	if(Strncmp(name, n->name, namelen) == 0 && n->name[namelen] == 0)
889 	    return n;
890 
891     return 0;
892 }
893 
NextNotationDefinition(Dtd dtd,NotationDefinition previous)894 NotationDefinition NextNotationDefinition(Dtd dtd, NotationDefinition previous)
895 {
896     return previous ? previous->next : dtd->notations;
897 }
898 
NotationURL(NotationDefinition n)899 const char8 *NotationURL(NotationDefinition n)
900 {
901     if(n->url)
902 	return n->url;
903 
904     n->url = url_merge(n->systemid,
905 		       n->parent ? EntityBaseURL(n->parent) : 0,
906 		       0, 0, 0, 0);
907 
908     return n->url;
909 }
910 
FreeNotationDefinition(NotationDefinition n)911 void FreeNotationDefinition(NotationDefinition n)
912 {
913     if(!n)
914 	return;
915 
916     /* Free the name */
917 
918     Free((void *)n->name);
919 
920     /* Free the ids */
921 
922     Free((void *)n->systemid);
923     Free((void *)n->publicid);
924     Free((void *)n->url);
925 
926     /* Free the notation definition itself */
927 
928     Free(n);
929 }
930