Edinburgh Speech Tools 2.4-release
dtd.c
1/*************************************************************************/
2/* */
3/* Copyright (c) 1997-98 Richard Tobin, Language Technology Group, HCRC, */
4/* University of Edinburgh. */
5/* */
6/* THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, */
7/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
8/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
9/* IN NO EVENT SHALL THE AUTHOR OR THE UNIVERSITY OF EDINBURGH BE LIABLE */
10/* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF */
11/* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION */
12/* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
13/* */
14/*************************************************************************/
15#include <string.h>
16
17#ifdef FOR_LT
18
19#include "lt-memory.h"
20#include "nsllib.h"
21
22#define Malloc salloc
23#define Realloc srealloc
24#define Free sfree
25
26#else
27
28#include "system.h"
29
30#endif
31
32#include "charset.h"
33#include "string16.h"
34#include "dtd.h"
35#include "url.h"
36
37const char8 *DefaultTypeName[DT_enum_count] = {
38 "#required",
39 "bogus1",
40 "#implied",
41 "bogus2"
42 "none",
43 "#fixed",
44};
45
46const char8 *ContentTypeName[CT_enum_count] = {
47 "mixed",
48 "any",
49 "bogus1",
50 "bogus2",
51 "empty",
52 "element"
53};
54
55const char8 *AttributeTypeName[AT_enum_count] = {
56 "cdata",
57 "bogus1",
58 "bogus2",
59 "nmtoken",
60 "bogus3",
61 "entity",
62 "idref",
63 "bogus4",
64 "bogus5",
65 "nmtokens",
66 "bogus6",
67 "entities",
68 "idrefs",
69 "id",
70 "notation",
71 "enumeration"
72};
73
74const char8 *StandaloneDeclarationName[SDD_enum_count] = {
75 "unspecified", "no", "yes"
76};
77
78static Char *Strndup(const Char *old, int len)
79{
80 Char *new = Malloc((len+1) * sizeof(Char));
81
82 if(!new)
83 return 0;
84
85 memcpy(new, old, len * sizeof(Char));
86 new[len] = 0;
87
88 return new;
89}
90
91/* DTDs */
92
93Dtd NewDtd(void)
94{
95 Dtd d;
96
97 if(!(d = Malloc(sizeof(*d))))
98 return 0;
99
100 d->name = 0;
101 d->internal_part = 0;
102 d->external_part = 0;
103 d->entities = 0;
104 d->parameter_entities = 0;
105 d->predefined_entities = 0;
106#ifdef FOR_LT
107 d->doctype = 0;
108#else
109 d->elements = 0;
110#endif
111 d->notations = 0;
112
113 return d;
114}
115
116/* Free a DTD and everything in it */
117
118void FreeDtd(Dtd dtd)
119{
120 Entity ent, ent1;
121#ifndef FOR_LT
122 ElementDefinition elem, elem1;
123#endif
124 NotationDefinition not, not1;
125
126 if(!dtd)
127 return;
128
129 /* Free the name */
130
131 Free((Char *)dtd->name); /* cast is to get rid of const */
132
133 /* Free the entities */
134
135 FreeEntity(dtd->internal_part);
136 FreeEntity(dtd->external_part);
137
138 for(ent = dtd->entities; ent; ent = ent1)
139 {
140 ent1 = ent->next; /* get it before we free ent! */
141 FreeEntity(ent);
142 }
143
144 for(ent = dtd->parameter_entities; ent; ent = ent1)
145 {
146 ent1 = ent->next;
147 FreeEntity(ent);
148 }
149
150 /* The predefined entities are shared, so we don't free them */
151
152#ifndef FOR_LT
153 /* Free the elements (kept elsewhere in NSL) */
154
155 for(elem = dtd->elements; elem; elem = elem1)
156 {
157 elem1 = elem->next;
158 FreeElementDefinition(elem); /* Frees the attributes too */
159 }
160#endif
161
162 /* Free the notations */
163
164 for(not = dtd->notations; not; not = not1)
165 {
166 not1 = not->next;
167 FreeNotationDefinition(not);
168 }
169
170 /* Free the dtd itself */
171
172 Free(dtd);
173}
174
175/* Entities */
176
177/*
178 * Make a new entity. The name is copied, none of the other
179 * arguments are, but they are freed when the entity is freed!
180 */
181
182Entity NewExternalEntityN(const Char *name, int namelen, const char8 *publicid,
183 const char8 *systemid, NotationDefinition notation,
184 Entity parent)
185{
186 Entity e;
187
188 if(!(e = Malloc(sizeof(*e))))
189 return 0;
190 if(name && !(name = Strndup(name, namelen)))
191 return 0;
192
193 e->type = ET_external;
194 e->name = name;
195 e->base_url = 0;
196 e->encoding = CE_unknown;
197 e->next = 0;
198 e->parent = parent;
199
200 e->publicid = publicid;
201 e->systemid = systemid;
202 e->notation = notation;
203
204 e->version_decl = 0;
205 e->encoding_decl = CE_unknown;
206 e->standalone_decl = SDD_unspecified;
207 e->ddb_filename = 0;
208
209 e->url = 0;
210
211 return (Entity)e;
212}
213
214Entity NewInternalEntityN(const Char *name, int namelen,
215 const Char *text, Entity parent,
216 int line_offset, int line1_char_offset,
217 int matches_parent_text)
218{
219 Entity e;
220
221 if(!(e = Malloc(sizeof(*e))))
222 return 0;
223 if(name)
224 if(!(name = Strndup(name, namelen)))
225 return 0;
226
227 e->type = ET_internal;
228 e->name = name;
229 e->base_url = 0;
230 e->encoding = InternalCharacterEncoding;
231 e->next = 0;
232 e->parent = parent;
233
234 e->text = text;
235 e->line_offset = line_offset;
236 e->line1_char_offset = line1_char_offset;
237 e->matches_parent_text = matches_parent_text;
238
239 e->url = 0;
240
241 return (Entity)e;
242}
243
244void FreeEntity(Entity e)
245{
246 if(!e)
247 return;
248
249 Free((void *)e->name); /* The casts are to get rid of the const */
250 Free((void *)e->base_url);
251 Free((void *)e->url);
252
253 switch(e->type)
254 {
255 case ET_internal:
256 Free((void *)e->text);
257 break;
258 case ET_external:
259 Free((void *)e->systemid);
260 Free((void *)e->publicid);
261 Free((void *)e->version_decl);
262 Free((void *)e->ddb_filename);
263 break;
264 }
265
266 Free(e);
267}
268
269const char8 *EntityURL(Entity e)
270{
271 /* Have we already determined the URL? */
272
273 if(e->url)
274 return e->url;
275
276 if(e->type == ET_internal)
277 {
278 if(e->parent)
279 {
280 const char8 *url = EntityURL(e->parent);
281 if(url)
282 e->url = strdup8(url);
283 }
284 }
285 else
286 e->url = url_merge(e->systemid,
287 e->parent ? EntityBaseURL(e->parent) : 0,
288 0, 0, 0, 0);
289
290 return e->url;
291}
292
293/* Returns the URL of the entity if it has one, otherwise the system ID.
294 It will certainly have a URL if it was successfully opened by EntityOpen.
295 Intended for error messages, so never returns NULL. */
296
297const char8 *EntityDescription(Entity e)
298{
299 if(e->url)
300 return e->url;
301
302 if(e->type == ET_external)
303 return e->systemid;
304
305 if(e->parent)
306 return EntityDescription(e->parent);
307
308 return "<unknown>";
309}
310
311void EntitySetBaseURL(Entity e, const char8 *url)
312{
313 e->base_url = url;
314}
315
316const char8 *EntityBaseURL(Entity e)
317{
318 if(e->base_url)
319 return e->base_url;
320
321 if(e->type == ET_internal)
322 {
323 if(e->parent)
324 return EntityBaseURL(e->parent);
325 else
326 return 0;
327 }
328
329 return EntityURL(e);
330}
331
332Entity DefineEntity(Dtd dtd, Entity e, int pe)
333{
334 if(pe)
335 {
336 e->next = dtd->parameter_entities;
337 dtd->parameter_entities = e;
338 }
339 else
340 {
341 e->next = dtd->entities;
342 dtd->entities = e;
343 }
344
345 return e;
346}
347
348Entity FindEntityN(Dtd dtd, const Char *name, int namelen, int pe)
349{
350 Entity e;
351
352 if(!pe)
353 for(e = dtd->predefined_entities; e; e = e->next)
354 if(Strncmp(name, e->name, namelen) == 0 && e->name[namelen] == 0)
355 return e;
356
357
358 for(e = pe ? dtd->parameter_entities : dtd->entities; e; e=e->next)
359 if(Strncmp(name, e->name, namelen) == 0 && e->name[namelen] == 0)
360 return e;
361
362 return 0;
363}
364
365/* Elements */
366
367/*
368 * Define a new element. The name is copied, the content model is not,
369 * but it is freed when the element definition is freed!
370 */
371
372ElementDefinition DefineElementN(Dtd dtd, const Char *name, int namelen,
373 ContentType type, Char *content)
374{
375#ifdef FOR_LT
376 static struct element_definition e;
377 RHTEntry *entry;
378 struct element_content *c;
379
380 if (!(entry = DeclareElement(dtd->doctype, name, namelen, 0,
381 (ctVals)type))) {
382 return NULL;
383 };
384
385 e.doctype = dtd->doctype;
386 e.name = (Char *)dtd->doctype->elements+entry->keyptr;
387 e.elsum = (NSL_ElementSummary_I *)(dtd->doctype->permanentBase+entry->eval);
388
389 if(type == CT_element || type == CT_mixed)
390 {
391 if(!(c = Malloc(sizeof(*c))))
392 return 0;
393 c->elsum = e.elsum;
394 c->content = content;
395 c->next = e.doctype->element_content;
396 e.doctype->element_content = c;
397 }
398
399 return &e;
400#else
401 ElementDefinition e;
402
403 if(!(e = Malloc(sizeof(*e))) || !(name = Strndup(name, namelen)))
404 return 0;
405
406 e->tentative = 0;
407 e->name = name;
408 e->namelen = namelen;
409 e->type = type;
410 e->content = content;
411 e->attributes = 0;
412 e->next = dtd->elements;
413 dtd->elements = e;
414
415 return e;
416#endif
417}
418
419ElementDefinition TentativelyDefineElementN(Dtd dtd,
420 const Char *name, int namelen)
421{
422#ifdef FOR_LT
423 static struct element_definition e;
424 RHTEntry *entry;
425
426 if (!(entry = DeclareElement(dtd->doctype, name, namelen, 0, (ctVals)CT_any))) {
427 return NULL;
428 };
429 e.doctype = dtd->doctype;
430 e.name = (Char *)dtd->doctype->elements+entry->keyptr;
431 e.elsum = (NSL_ElementSummary_I *)(dtd->doctype->permanentBase+entry->eval);
432 /* XXX use the omitStart field to note that it's tentative. */
433 e.elsum->omitStart |= 2;
434 return &e;
435#else
436 ElementDefinition e;
437
438 if(!(e = Malloc(sizeof(*e))) || !(name = Strndup(name, namelen)))
439 return 0;
440
441 e->tentative = 1;
442 e->name = name;
443 e->namelen = namelen;
444 e->type = CT_any;
445 e->content = 0;
446 e->attributes = 0;
447 e->next = dtd->elements;
448 dtd->elements = e;
449
450 return e;
451#endif
452}
453
454ElementDefinition RedefineElement(ElementDefinition e, ContentType type,
455 Char *content)
456{
457#ifdef FOR_LT
458 struct element_content *c;
459
460 e->elsum->contentType = type;
461 e->elsum->omitStart &= ~2;
462 if(type == CT_element)
463 {
464 if(!(c = Malloc(sizeof(*c))))
465 return 0;
466 c->elsum = e->elsum;
467 c->content = content;
468 c->next = e->doctype->element_content;
469 e->doctype->element_content = c;
470 }
471#else
472 e->tentative = 0;
473 e->type = type;
474 e->content = content;
475#endif
476 return e;
477}
478
479ElementDefinition FindElementN(Dtd dtd, const Char *name, int namelen)
480{
481#ifdef FOR_LT
482 /* Derived from FindElementAndName */
483
484 static struct element_definition e;
485 RHTEntry *entry;
486 NSL_ElementSummary_I *elsum;
487
488 if(!dtd->doctype)
489 return 0;
490
491 entry = rsearch(name, namelen, dtd->doctype->elements);
492 if(!entry)
493 return 0;
494
495 elsum = (NSL_ElementSummary_I *)(dtd->doctype->permanentBase+entry->eval);
496
497 e.doctype = dtd->doctype;
498 e.name = (Char *)dtd->doctype->elements+entry->keyptr;
499#if 0
500 /* We don't use this so don't waste time on it XXX */
501 e.namelen = Strlen(e.name);
502#endif
503 e.elsum = elsum;
504 e.tentative = ((e.elsum->omitStart & 2) != 0);
505
506 return &e;
507#else
508 ElementDefinition e, *p;
509
510 for(p = &dtd->elements, e = *p; e; p = &e->next, e = *p)
511 if(namelen == e->namelen && *name == *e->name &&
512 memcmp(name, e->name, namelen*sizeof(Char)) == 0)
513 {
514 *p = e->next;
515 e->next = dtd->elements;
516 dtd->elements = e;
517 return e;
518 }
519
520 return 0;
521#endif
522}
523
524/* Free an element definition and its attribute definitions */
525
526void FreeElementDefinition(ElementDefinition e)
527{
528#ifndef FOR_LT
529 AttributeDefinition a, a1;
530#endif
531
532 if(!e)
533 return;
534
535 /* Free the element name */
536
537 Free((void *)e->name);
538
539#ifndef FOR_LT
540 /* Free the content model (kept elsewhere in NSL) */
541
542 Free(e->content);
543
544 /* Free the attributes (kept elsewhere in NSL) */
545
546 for(a = e->attributes; a; a = a1)
547 {
548 a1 = a->next;
549 FreeAttributeDefinition(a);
550 }
551
552 /* Free the ElementDefinition itself */
553#endif
554
555 Free(e);
556}
557
558/* Attributes */
559
560/*
561 * Define a new attribute. The name is copied, the allowed values and
562 * default are not, but they are freed when the attribute definition is freed!
563 */
564
565AttributeDefinition
566 DefineAttributeN(ElementDefinition element, const Char *name, int namelen,
567 AttributeType type, Char **allowed_values,
568 DefaultType default_type, const Char *default_value)
569{
570#ifdef FOR_LT
571 int nav = 0;
572 Char *av = allowed_values ? allowed_values[0] : 0;
573 Char **avp;
574 NSL_Doctype_I *doctype = element->doctype;
575
576 if(!doctype)
577 return 0;
578
579 if(allowed_values)
580 {
581 for(avp = allowed_values; *avp; avp++)
582 nav++;
583 Free(allowed_values);
584 }
585
586 if (!(name = DeclareAttr(doctype, name, namelen,
587 (NSL_Attr_Declared_Value)type,
588 av, nav,
589 (NSL_ADefType)default_type, default_value,
590 &element->elsum, element->name))) {
591 return 0;
592 };
593
594 return (AttributeDefinition)FindAttrSpec(element->elsum,
595 doctype,
596 name);
597#else
598 AttributeDefinition a;
599
600 if(!(a= Malloc(sizeof(*a))) || !(name = Strndup(name, namelen)))
601 return 0;
602
603 a->name = name;
604 a->namelen = namelen;
605 a->type = type;
606 a->allowed_values = allowed_values;
607 a->default_type = default_type;
608 a->default_value = default_value;
609 a->next = element->attributes;
610 element->attributes = a;
611
612 return a;
613#endif
614}
615
616AttributeDefinition FindAttributeN(ElementDefinition element,
617 const Char *name, int namelen)
618{
619#ifdef FOR_LT
620 if(!element->doctype)
621 return 0;
622
623 if(!(name = AttrUniqueName(element->doctype, name, namelen)))
624 return 0;
625 return (AttributeDefinition)FindAttrSpec(element->elsum,
626 element->doctype,
627 name);
628#else
629 AttributeDefinition a;
630
631 for(a = element->attributes; a; a = a->next)
632 if(namelen == a->namelen &&
633 memcmp(name, a->name, namelen * sizeof(Char)) == 0)
634 return a;
635
636 return 0;
637#endif
638}
639
640AttributeDefinition NextAttributeDefinition(ElementDefinition element,
641 AttributeDefinition previous)
642{
643#ifdef FOR_LT
644 return 0; /* not implemented */
645#else
646 if(previous)
647 return previous->next;
648 else
649 return element->attributes;
650#endif
651}
652
653/* Free an attribute definition */
654
655void FreeAttributeDefinition(AttributeDefinition a)
656{
657#ifndef FOR_LT
658 /* We don't keep anything in the NSL case */
659
660 if(!a)
661 return;
662
663 /* Free the name */
664
665 Free((void *)a->name);
666
667 /* Free the allowed values - we rely on them being allocated as in
668 xmlparser.c: the Char * pointers point into one single block. */
669
670 if(a->allowed_values)
671 Free(a->allowed_values[0]);
672 Free(a->allowed_values);
673
674 /* Free the default value */
675
676 Free((void *)a->default_value);
677
678 /* Free the attribute definition itself */
679
680 Free(a);
681#endif
682}
683
684/* Notations */
685
686/*
687 * Define a new notation. The name is copied, the system and public ids are
688 * not, but they are freed when the notation definition is freed!
689 */
690
691NotationDefinition DefineNotationN(Dtd dtd, const Char *name, int namelen,
692 const char8 *publicid, const char8 *systemid)
693{
694 NotationDefinition n;
695
696 if(!(n = Malloc(sizeof(*n))) || !(name = Strndup(name, namelen)))
697 return 0;
698
699 n->name = name;
700 n->tentative = 1;
701 n->systemid = systemid;
702 n->publicid = publicid;
703 n->next = dtd->notations;
704 dtd->notations = n;
705
706 return n;
707}
708
709NotationDefinition TentativelyDefineNotationN(Dtd dtd,
710 const Char *name, int namelen)
711{
712 NotationDefinition n;
713
714 if(!(n = Malloc(sizeof(*n))) || !(name = Strndup(name, namelen)))
715 return 0;
716
717 n->name = name;
718 n->tentative = 1;
719 n->systemid = 0;
720 n->publicid = 0;
721 n->next = dtd->notations;
722 dtd->notations = n;
723
724 return n;
725}
726
727NotationDefinition RedefineNotation(NotationDefinition n,
728 const char8 *publicid, const char8 *systemid)
729{
730 n->tentative = 0;
731 n->systemid = systemid;
732 n->publicid = publicid;
733
734 return n;
735}
736
737NotationDefinition FindNotationN(Dtd dtd, const Char *name, int namelen)
738{
739 NotationDefinition n;
740
741 for(n = dtd->notations; n; n = n->next)
742 if(Strncmp(name, n->name, namelen) == 0 && n->name[namelen] == 0)
743 return n;
744
745 return 0;
746}
747
748void FreeNotationDefinition(NotationDefinition n)
749{
750 if(!n)
751 return;
752
753 /* Free the name */
754
755 Free((void *)n->name);
756
757 /* Free the ids */
758
759 Free((void *)n->systemid);
760 Free((void *)n->publicid);
761
762 /* Free the notation definition itself */
763
764 Free(n);
765}
Definition: dtd.h:40