Link with C++ linker
[oweals/cde.git] / cde / programs / nsgmls / parseDecl.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: parseDecl.C /main/1 1996/07/29 17:09:16 cde-hp $ */
24 // Copyright (c) 1994, 1995 James Clark
25 // See the file COPYING for copying permission.
26
27 // Prolog, dtd and declaration parsing.
28
29 #include "splib.h"
30 #include "Parser.h"
31 #include "Param.h"
32 #include "Markup.h"
33 #include "ParserMessages.h"
34 #include "MessageArg.h"
35 #include "TokenMessageArg.h"
36 #include "token.h"
37 #include "macros.h"
38
39 #ifdef SP_NAMESPACE
40 namespace SP_NAMESPACE {
41 #endif
42
43 static const AllowedParams allowMdc(Param::mdc);
44 static const AllowedParams allowName(Param::name);
45 static const AllowedParams allowParamLiteral(Param::paramLiteral);
46 static const AllowedParams allowNameNameGroup(Param::name, Param::nameGroup);
47 static const AllowedParams allowDsoMdc(Param::dso, Param::mdc);
48 static AllowedParams allowNameMdc(Param::name, Param::mdc);
49 static AllowedParams
50   allowExplicitLinkRuleMdc(Param::mdc,
51                            Param::name,
52                            Param::nameGroup,
53                            Param::indicatedReservedName + Syntax::rIMPLIED);
54 static AllowedParams
55   allowNameNameGroupMdc(Param::name, Param::nameGroup, Param::mdc);
56
57 static const AllowedParams
58   allowLinkSetSpec(Param::name,
59                    Param::indicatedReservedName + Syntax::rINITIAL,
60                    Param::indicatedReservedName + Syntax::rEMPTY,
61                    Param::indicatedReservedName + Syntax::rRESTORE);
62
63 void Parser::doProlog()
64 {
65   const unsigned maxTries = 10;
66   unsigned tries = 0;
67   do {
68     if (cancelled()) {
69       allDone();
70       return;
71     }
72     Token token = getToken(proMode);
73     switch (token) {
74     case tokenUnrecognized:
75       if (reportNonSgmlCharacter())
76         break;
77       if (hadDtd()) {
78         currentInput()->ungetToken();
79         endProlog();
80         return;
81       }
82       {
83         StringC gi;
84         if (lookingAtStartTag(gi)) {
85           currentInput()->ungetToken();
86           if (!implyDtd(gi)) {
87             message(ParserMessages::noDtd);
88             giveUp();
89           }
90           return;
91         }
92       }
93             
94       if (++tries >= maxTries) {
95         message(ParserMessages::noDtd);
96         giveUp();
97         return;
98       }
99       message(ParserMessages::prologCharacter, StringMessageArg(currentToken()));
100       prologRecover();
101       break;
102     case tokenEe:
103       if (hadDtd()) {
104         endProlog();
105         return;
106       }
107       message(ParserMessages::documentEndProlog);
108       allDone();
109       return;
110     case tokenMdoMdc:
111       // empty comment
112       emptyCommentDecl();
113       break;
114     case tokenMdoCom:
115       if (!parseCommentDecl())
116         prologRecover();
117       break;
118     case tokenMdoNameStart:
119       setPass2Start();
120       if (startMarkup(eventsWanted().wantPrologMarkup(), currentLocation()))
121         currentMarkup()->addDelim(Syntax::dMDO);
122       Syntax::ReservedName name;
123       if (parseDeclarationName(&name)) {
124         switch (name) {
125         case Syntax::rDOCTYPE:
126           if (!parseDoctypeDeclStart())
127             giveUp();
128           return;
129         case Syntax::rLINKTYPE:
130           if (!parseLinktypeDeclStart())
131             giveUp();
132           return;
133         case Syntax::rELEMENT:
134         case Syntax::rATTLIST:
135         case Syntax::rENTITY:
136         case Syntax::rNOTATION:
137         case Syntax::rSHORTREF:
138         case Syntax::rUSEMAP:
139         case Syntax::rUSELINK:
140         case Syntax::rLINK:
141         case Syntax::rIDLINK:
142           message(ParserMessages::prologDeclaration,
143                   StringMessageArg(syntax().reservedName(name)));
144           if (!hadDtd())
145             tries++;
146           prologRecover();
147           break;
148         default:
149           message(ParserMessages::noSuchDeclarationType,
150                   StringMessageArg(syntax().reservedName(name)));
151           prologRecover();
152           break;
153         }
154       }
155       else
156         prologRecover();
157       break;
158     case tokenPio:
159       if (!parseProcessingInstruction())
160         prologRecover();
161       break;
162     case tokenS:
163       if (eventsWanted().wantPrologMarkup()) {
164         extendS();
165         eventHandler().sSep(new (eventAllocator())
166                             SSepEvent(currentInput()->currentTokenStart(),
167                                       currentInput()->currentTokenLength(),
168                                       currentLocation(),
169                                       1));
170       }
171       break;
172     default:
173       CANNOT_HAPPEN();
174     }
175   } while (eventQueueEmpty());
176 }
177
178 void Parser::endProlog()
179 {
180   if (baseDtd().isNull()
181       || baseDtd()->documentElementType()->definition()->undefined()) {
182     // We could continue, but there's not a lot of point.
183     giveUp();
184     return;
185   }
186   if (maybeStartPass2())
187     setPhase(prologPhase);
188   else {
189     if (inputLevel() == 0) {
190       allDone();
191       return;
192     }
193     if (pass2())
194       checkEntityStability();
195     setPhase(instanceStartPhase);
196     startInstance();
197     ConstPtr<ComplexLpd> lpd;
198     Vector<AttributeList> simpleLinkAtts;
199     Vector<StringC> simpleLinkNames;
200     for (size_t i = 0; i < nActiveLink(); i++)
201       if (activeLpd(i).type() == Lpd::simpleLink) {
202         const SimpleLpd &lpd = (SimpleLpd &)activeLpd(i);
203         simpleLinkNames.push_back(lpd.name());
204         simpleLinkAtts.resize(simpleLinkAtts.size() + 1);
205         simpleLinkAtts.back().init(lpd.attributeDef());
206         simpleLinkAtts.back().finish(*this);
207       }
208       else 
209         lpd = (ComplexLpd *)&activeLpd(i);
210     eventHandler().endProlog(new (eventAllocator())
211                              EndPrologEvent(baseDtd(),
212                                             lpd,
213                                             simpleLinkNames,
214                                             simpleLinkAtts,
215                                             currentLocation()));
216   }
217 }
218
219 void Parser::prologRecover()
220 {
221   unsigned skipCount = 0;
222   const unsigned skipMax = 250;
223   for (;;) {
224     Token token = getToken(proMode);
225     skipCount++;
226     if (token == tokenUnrecognized) {
227       token = getToken(mdMode);
228       if (token == tokenMdc) {
229         token = getToken(proMode);
230         if (token == tokenS)
231           return;
232       }
233     }
234     switch (token) {
235     case tokenUnrecognized:
236       (void)getChar();
237       break;
238     case tokenEe:
239       return;
240     case tokenMdoMdc:
241     case tokenMdoCom:
242     case tokenMdoNameStart:
243     case tokenPio:
244       currentInput()->ungetToken();
245       return;
246     case tokenS:
247       if (currentChar() == syntax().standardFunction(Syntax::fRE)
248           && skipCount >= skipMax)
249         return;
250     default:
251       break;
252     }
253   }
254 }
255
256 void Parser::doDeclSubset()
257 {
258   do {
259     if (cancelled()) {
260       allDone();
261       return;
262     }
263     Token token = getToken(currentMode());
264     unsigned startLevel = inputLevel();
265     Boolean inDtd = !haveDefLpd();
266     switch (token) {
267     case tokenUnrecognized:
268       if (reportNonSgmlCharacter())
269         break;
270       message(ParserMessages::declSubsetCharacter, StringMessageArg(currentToken()));
271       declSubsetRecover(startLevel);
272       break;
273     case tokenEe:
274       if (inputLevel() == specialParseInputLevel()) {
275         // FIXME have separate messages for each type of special parse
276         message(ParserMessages::specialParseEntityEnd);
277       }
278       if (eventsWanted().wantPrologMarkup())
279         eventHandler().entityEnd(new (eventAllocator())
280                                  EntityEndEvent(currentLocation()));
281       if (inputLevel() == 2) {
282         ConstPtr<Entity> e
283           = currentLocation().origin()->asEntityOrigin()->entity();
284         if (!e.isNull()
285             && (e->declType() == Entity::doctype
286                 || e->declType() == Entity::linktype)) {
287           popInputStack();
288           if (!(inDtd
289                 ? parseDoctypeDeclEnd(e->defLocation().origin().isNull())
290                 : parseLinktypeDeclEnd()))
291             ;                   // FIXME recover
292           setPhase(prologPhase);
293           return;
294         }
295       }
296       if (inputLevel() == 1) {
297         if (finalPhase() == declSubsetPhase) {
298           checkDtd(defDtd());
299           endDtd();
300         }
301         else
302           // Give message before popping stack.
303           message(inDtd
304                   ? ParserMessages::documentEndDtdSubset
305                   : ParserMessages::documentEndLpdSubset);
306         popInputStack();
307         allDone();
308       }
309       else
310         popInputStack();
311       return;
312     case tokenDsc:              // end of declaration subset
313       // FIXME what's the right location?
314       if (!referenceDsEntity(currentLocation())) {
315         if (!(inDtd ? parseDoctypeDeclEnd() : parseLinktypeDeclEnd()))
316           ;                     // FIXME recover
317         setPhase(prologPhase);
318       }
319       return;
320     case tokenMdoNameStart:     // named markup declaration
321       if (startMarkup(eventsWanted().wantPrologMarkup(), currentLocation()))
322         currentMarkup()->addDelim(Syntax::dMDO);
323       Syntax::ReservedName name;
324       Boolean result;
325       if (parseDeclarationName(&name,
326                                inDtd && !options().errorAfdr)) {
327         switch (name) {
328         case Syntax::rANY:      // used for <!AFDR
329           result = parseAfdrDecl();
330           break;
331         case Syntax::rELEMENT:
332           if (inDtd)
333             result = parseElementDecl();
334           else {
335             message(ParserMessages::lpdSubsetDeclaration,
336                     StringMessageArg(syntax().reservedName(name)));
337             result = 0;
338           }
339           break;
340         case Syntax::rATTLIST:
341           result = parseAttlistDecl();
342           break;
343         case Syntax::rENTITY:
344           result = parseEntityDecl();
345           break;
346         case Syntax::rNOTATION:
347           result = parseNotationDecl();
348           if (!inDtd && options().errorLpdNotation)
349             message(ParserMessages::lpdSubsetDeclaration,
350                     StringMessageArg(syntax().reservedName(name)));
351           break;
352         case Syntax::rSHORTREF:
353           if (inDtd)
354             result = parseShortrefDecl();
355           else {
356             message(ParserMessages::lpdSubsetDeclaration,
357                     StringMessageArg(syntax().reservedName(name)));
358             result = 0;
359           }
360           break;
361         case Syntax::rUSEMAP:
362           if (inDtd)
363             result = parseUsemapDecl();
364           else {
365             message(ParserMessages::lpdSubsetDeclaration,
366                     StringMessageArg(syntax().reservedName(name)));
367             result = 0;
368           }
369           break;
370         case Syntax::rLINK:
371           if (inDtd) {
372             message(ParserMessages::dtdSubsetDeclaration,
373                     StringMessageArg(syntax().reservedName(name)));
374             result = 0;
375           }
376           else
377             result = parseLinkDecl();
378           break;
379         case Syntax::rIDLINK:
380           if (inDtd) {
381             message(ParserMessages::dtdSubsetDeclaration,
382                     StringMessageArg(syntax().reservedName(name)));
383             result = 0;
384           }
385           else
386             result = parseIdlinkDecl();
387           break;
388         case Syntax::rDOCTYPE:
389         case Syntax::rLINKTYPE:
390         case Syntax::rUSELINK:
391           result = 0;
392           message(inDtd
393                   ? ParserMessages::dtdSubsetDeclaration
394                   : ParserMessages::lpdSubsetDeclaration,
395                   StringMessageArg(syntax().reservedName(name)));
396           break;
397         default:
398           result = 0;
399           message(ParserMessages::noSuchDeclarationType,
400                   StringMessageArg(syntax().reservedName(name)));
401           break;
402         }
403       }
404       else
405         result = 0;
406       if (!result)
407         declSubsetRecover(startLevel);
408       break;
409     case tokenMdoMdc:           // empty comment declaration
410       // empty comment
411       emptyCommentDecl();
412       break;
413     case tokenMdoCom:           // comment declaration
414       if (!parseCommentDecl())
415         declSubsetRecover(startLevel);
416       break;
417     case tokenMdoDso:           // marked section declaration
418       if (!parseMarkedSectionDeclStart())
419         declSubsetRecover(startLevel);
420       break;
421     case tokenMscMdc:
422       handleMarkedSectionEnd();
423       break;
424     case tokenPeroGrpo:         // parameter entity reference with name group
425       message(ParserMessages::peroGrpoProlog);
426       // fall through
427     case tokenPeroNameStart:    // parameter entity reference
428       {
429         ConstPtr<Entity> entity;
430         Ptr<EntityOrigin> origin;
431         if (parseEntityReference(1, token == tokenPeroGrpo, entity, origin)) {
432           if (!entity.isNull())
433             entity->dsReference(*this, origin);
434         }
435         else
436           declSubsetRecover(startLevel);
437       }
438       break;
439     case tokenPio:              // processing instruction
440       if (!parseProcessingInstruction())
441         declSubsetRecover(startLevel);
442       break;
443     case tokenS:                // white space
444       if (eventsWanted().wantPrologMarkup()) {
445         extendS();
446         eventHandler().sSep(new (eventAllocator())
447                             SSepEvent(currentInput()->currentTokenStart(),
448                                       currentInput()->currentTokenLength(),
449                                       currentLocation(),
450                                       1));
451       }
452       break;
453     case tokenIgnoredChar:
454       // from an ignored marked section
455       if (eventsWanted().wantPrologMarkup())
456         eventHandler().ignoredChars(new (eventAllocator())
457                                     IgnoredCharsEvent(currentInput()->currentTokenStart(),
458                                                       currentInput()->currentTokenLength(),
459                                                       currentLocation(),
460                                                       1));
461       break;
462     case tokenRe:
463     case tokenRs:
464     case tokenCroDigit:
465     case tokenCroNameStart:
466     case tokenEroNameStart:
467     case tokenEroGrpo:
468     case tokenChar:
469       // these can occur in a cdata or rcdata marked section
470       message(ParserMessages::dataMarkedSectionDeclSubset);
471       declSubsetRecover(startLevel);
472       break;
473     default:
474       CANNOT_HAPPEN();
475     }
476   } while (eventQueueEmpty());
477 }
478
479 void Parser::declSubsetRecover(unsigned startLevel)
480 {
481   for (;;) {
482     Token token = getToken(currentMode());
483     switch (token) {
484     case tokenUnrecognized:
485       (void)getChar();
486       break;
487     case tokenEe:
488       if (inputLevel() <= startLevel)
489         return;
490       popInputStack();
491       break;
492     case tokenMdoCom:
493     case tokenDsc:
494     case tokenMdoNameStart:
495     case tokenMdoMdc:
496     case tokenMdoDso:
497     case tokenMscMdc:
498     case tokenPio:
499       if (inputLevel() == startLevel) {
500         currentInput()->ungetToken();
501         return;
502       }
503       break;
504     default:
505       break;
506     }
507   }
508 }
509
510 Boolean Parser::lookingAtStartTag(StringC &gi)
511 {
512   // This is harder than might be expected since we may not have compiled
513   // the recognizers for the instance yet.
514   const StringC &stago = instanceSyntax().delimGeneral(Syntax::dSTAGO);
515   for (size_t i = currentInput()->currentTokenLength();
516        i < stago.size();
517        i++)
518     if (currentInput()->tokenChar(messenger()) == InputSource::eE)
519       return 0;
520   StringC delim;
521   getCurrentToken(instanceSyntax().generalSubstTable(), delim);
522   if (delim != stago)
523     return 0;
524   Xchar c = currentInput()->tokenChar(messenger());
525   if (!instanceSyntax().isNameStartCharacter(c))
526     return 0;
527   do {
528     gi += Char(c);
529     c = currentInput()->tokenChar(messenger());
530   } while (instanceSyntax().isNameCharacter(c));
531   return 1;
532 }
533
534 Boolean Parser::parseDeclarationName(Syntax::ReservedName *result,
535                                      Boolean allowAfdr)
536 {
537   currentInput()->discardInitial();
538   extendNameToken(syntax().namelen(), ParserMessages::nameLength);
539   StringC &name = nameBuffer();
540   getCurrentToken(syntax().generalSubstTable(), name);
541   if (!syntax().lookupReservedName(name, result)) {
542     if (allowAfdr && name == sd().execToDoc("AFDR")) {
543       *result = Syntax::rANY;
544       if (currentMarkup())
545         currentMarkup()->addName(currentInput());
546     }
547     else {
548       message(ParserMessages::noSuchDeclarationType, StringMessageArg(name));
549       return 0;
550     }
551   }
552   else if (currentMarkup())
553     currentMarkup()->addReservedName(*result, currentInput());
554   return 1;
555 }
556
557 Boolean Parser::parseElementDecl()
558 {
559   unsigned declInputLevel = inputLevel();
560   Param parm;
561   if (!parseParam(allowNameNameGroup, declInputLevel, parm))
562     return 0;
563   Vector<NameToken> nameVector;
564   if (parm.type == Param::nameGroup)
565     parm.nameTokenVector.swap(nameVector);
566   else {
567     nameVector.resize(1);
568     parm.token.swap(nameVector[0].name);
569   }
570   static AllowedParams
571     allowRankOmissionContent(Param::number,
572                              Param::reservedName + Syntax::rO,
573                              Param::minus,
574                              Param::reservedName + Syntax::rCDATA,
575                              Param::reservedName + Syntax::rRCDATA,
576                              Param::reservedName + Syntax::rEMPTY,
577                              Param::reservedName + Syntax::rANY,
578                              Param::modelGroup);
579   if (!parseParam(allowRankOmissionContent, declInputLevel, parm))
580     return 0;
581   StringC rankSuffix;
582   Vector<ElementType *> elements(nameVector.size());
583   Vector<RankStem *> rankStems;
584   Vector<const RankStem *> constRankStems;
585   size_t i;
586   if (parm.type == Param::number) {
587     parm.token.swap(rankSuffix);
588     rankStems.resize(nameVector.size());
589     constRankStems.resize(nameVector.size());
590     for (i = 0; i < elements.size(); i++) {
591       StringC name(nameVector[i].name);
592       name += rankSuffix;
593       if (name.size() > syntax().namelen()
594           && nameVector[i].name.size() <= syntax().namelen())
595         message(ParserMessages::genericIdentifierLength,
596                 NumberMessageArg(syntax().namelen()));
597       elements[i] = lookupCreateElement(name);
598       rankStems[i] = lookupCreateRankStem(nameVector[i].name);
599       constRankStems[i] = rankStems[i];
600     }
601     static AllowedParams
602       allowOmissionContent(Param::reservedName + Syntax::rO,
603                            Param::minus,
604                            Param::reservedName + Syntax::rCDATA,
605                            Param::reservedName + Syntax::rRCDATA,
606                            Param::reservedName + Syntax::rEMPTY,
607                            Param::reservedName + Syntax::rANY,
608                            Param::modelGroup);
609     Token token = getToken(mdMinusMode);
610     if (token == tokenNameStart)
611       message(ParserMessages::psRequired);
612     currentInput()->ungetToken();
613     if (!parseParam(allowOmissionContent, declInputLevel, parm))
614       return 0;
615   }
616   else {
617     for (i = 0; i < elements.size(); i++)
618       elements[i] = lookupCreateElement(nameVector[i].name);
619   }
620   for (i = 0; i < elements.size(); i++)
621     if (defDtd().lookupRankStem(elements[i]->name()))
622       message(ParserMessages::rankStemGenericIdentifier,
623               StringMessageArg(elements[i]->name()));
624   unsigned char omitFlags = 0;
625   if (parm.type == Param::minus
626       || parm.type == Param::reservedName + Syntax::rO) {
627     omitFlags |= ElementDefinition::omitSpec;
628     if (parm.type != Param::minus)
629       omitFlags |= ElementDefinition::omitStart;
630     static AllowedParams allowOmission(Param::reservedName + Syntax::rO,
631                                        Param::minus);
632     if (!parseParam(allowOmission, declInputLevel, parm))
633       return 0;
634     if (parm.type != Param::minus)
635       omitFlags |= ElementDefinition::omitEnd;
636     static AllowedParams allowContent(Param::reservedName + Syntax::rCDATA,
637                                       Param::reservedName + Syntax::rRCDATA,
638                                       Param::reservedName + Syntax::rEMPTY,
639                                       Param::reservedName + Syntax::rANY,
640                                       Param::modelGroup);
641     if (!parseParam(allowContent, declInputLevel, parm))
642       return 0;
643   }
644   else {
645     if (sd().omittag())
646       message(ParserMessages::missingTagMinimization);
647   }
648   Ptr<ElementDefinition> def;
649   switch (parm.type) {
650   case Param::reservedName + Syntax::rCDATA:
651     def = new ElementDefinition(markupLocation(),
652                                 defDtd().allocElementDefinitionIndex(),
653                                 omitFlags,
654                                 ElementDefinition::cdata);
655     if (!parseParam(allowMdc, declInputLevel, parm))
656       return 0;
657     break;
658   case Param::reservedName + Syntax::rRCDATA:
659     def = new ElementDefinition(markupLocation(),
660                                 defDtd().allocElementDefinitionIndex(),
661                                 omitFlags,
662                                 ElementDefinition::rcdata);
663     if (!parseParam(allowMdc, declInputLevel, parm))
664       return 0;
665     break;
666   case Param::reservedName + Syntax::rEMPTY:
667     def = new ElementDefinition(markupLocation(),
668                                 defDtd().allocElementDefinitionIndex(),
669                                 omitFlags,
670                                 ElementDefinition::empty);
671     if ((omitFlags & ElementDefinition::omitSpec)
672         && !(omitFlags & ElementDefinition::omitEnd)
673         && options().warnShould)
674       message(ParserMessages::emptyOmitEndTag);
675     if (!parseParam(allowMdc, declInputLevel, parm))
676       return 0;
677     break;
678   case Param::reservedName + Syntax::rANY:
679     def = new ElementDefinition(markupLocation(),
680                                 defDtd().allocElementDefinitionIndex(),
681                                 omitFlags,
682                                 ElementDefinition::any);
683     if (!parseExceptions(declInputLevel, def))
684       return 0;
685     break;
686   case Param::modelGroup:
687     {
688       unsigned long cnt = parm.modelGroupPtr->grpgtcnt();
689       // The outermost model group isn't formally a content token.
690       if (cnt - 1 > syntax().grpgtcnt())
691         message(ParserMessages::grpgtcnt, NumberMessageArg(syntax().grpgtcnt()));
692       Owner<CompiledModelGroup>
693         modelGroup(new CompiledModelGroup(parm.modelGroupPtr));
694       Vector<ContentModelAmbiguity> ambiguities;
695       Boolean pcdataUnreachable;
696       modelGroup->compile(currentDtd().nElementTypeIndex(), ambiguities,
697                           pcdataUnreachable);
698       if (pcdataUnreachable && options().warnMixedContent)
699         message(ParserMessages::pcdataUnreachable);
700       for (i = 0; i < ambiguities.size(); i++) {
701         const ContentModelAmbiguity &a = ambiguities[i];
702         reportAmbiguity(a.from, a.to1, a.to2, a.andDepth);
703       }
704       def = new ElementDefinition(markupLocation(),
705                                   defDtd().allocElementDefinitionIndex(),
706                                   omitFlags,
707                                   ElementDefinition::modelGroup,
708                                   modelGroup);
709       if (!parseExceptions(declInputLevel, def))
710         return 0;
711     }
712     break;
713   }
714   if (rankSuffix.size() > 0)
715     def->setRank(rankSuffix, constRankStems);
716   ConstPtr<ElementDefinition> constDef(def);
717   for (i = 0; i < elements.size(); i++) {
718     if (elements[i]->definition() != 0)
719       message(ParserMessages::duplicateElementDefinition,
720               StringMessageArg(elements[i]->name()));
721     else {
722       elements[i]->setElementDefinition(constDef, i);
723       if (!elements[i]->attributeDef().isNull())
724         checkElementAttribute(elements[i]);
725     }
726     if (rankStems.size() > 0)
727       rankStems[i]->addDefinition(constDef);
728   }
729   if (currentMarkup()) {
730     Vector<const ElementType *> v(elements.size());
731     for (i = 0; i < elements.size(); i++)
732       v[i] = elements[i];
733     eventHandler().elementDecl(new (eventAllocator())
734                                ElementDeclEvent(v, currentDtdPointer(),
735                                                 markupLocation(),
736                                                 currentMarkup()));
737   }
738   return 1;
739 }
740
741 void Parser::reportAmbiguity(const LeafContentToken *from,
742                              const LeafContentToken *to1,
743                              const LeafContentToken *to2,
744                              unsigned ambigAndDepth)
745 {
746   StringC toName;
747   const ElementType *toType = to1->elementType();
748   if (toType)
749     toName = toType->name();
750   else {
751     toName = syntax().delimGeneral(Syntax::dRNI);
752     toName += syntax().reservedName(Syntax::rPCDATA);
753   }
754   unsigned to1Index = to1->typeIndex() + 1;
755   unsigned to2Index = to2->typeIndex() + 1;
756   if (from->isInitial())
757     message(ParserMessages::ambiguousModelInitial,
758             StringMessageArg(toName),
759             OrdinalMessageArg(to1Index),
760             OrdinalMessageArg(to2Index));
761   else {
762     StringC fromName;
763     const ElementType *fromType = from->elementType();
764     if (fromType)
765       fromName = fromType->name();
766     else {
767       fromName = syntax().delimGeneral(Syntax::dRNI);
768       fromName += syntax().reservedName(Syntax::rPCDATA);
769     }
770     unsigned fromIndex = from->typeIndex() + 1;
771     unsigned andMatches = from->andDepth() - ambigAndDepth;
772     if (andMatches == 0)
773       message(ParserMessages::ambiguousModel,
774               StringMessageArg(fromName),
775               OrdinalMessageArg(fromIndex),
776               StringMessageArg(toName),
777               OrdinalMessageArg(to1Index),
778               OrdinalMessageArg(to2Index));
779     else if (andMatches == 1)
780       message(ParserMessages::ambiguousModelSingleAnd,
781               StringMessageArg(fromName),
782               OrdinalMessageArg(fromIndex),
783               StringMessageArg(toName),
784               OrdinalMessageArg(to1Index),
785               OrdinalMessageArg(to2Index));
786     else
787       message(ParserMessages::ambiguousModelMultipleAnd,
788               StringMessageArg(fromName),
789               OrdinalMessageArg(fromIndex),
790               NumberMessageArg(andMatches),
791               StringMessageArg(toName),
792               OrdinalMessageArg(to1Index),
793               OrdinalMessageArg(to2Index));
794   }
795 }
796
797
798 // Check the compatibility of the attribute definition with
799 // the element definition.
800
801 void Parser::checkElementAttribute(const ElementType *e, size_t checkFrom)
802 {
803   const AttributeDefinitionList *attDef = e->attributeDef().pointer();
804   Boolean conref = 0;
805   ASSERT(e != 0);
806   const ElementDefinition *edef = e->definition();
807   ASSERT(edef != 0);
808   ASSERT(attDef != 0);
809   size_t attDefLength = attDef->size();
810   for (size_t i = checkFrom; i < attDefLength; i++) {
811     const AttributeDefinition *p = attDef->def(i);
812     if (p->isConref())
813       conref = 1;
814     if (p->isNotation()
815         && edef->declaredContent() == ElementDefinition::empty)
816       message(ParserMessages::notationEmpty, StringMessageArg(e->name()));
817   }
818   if (conref) {
819 #if 0
820     if (edef->omittedTagSpec() && !edef->canOmitEndTag()
821         && options().warnShould)
822       message(ParserMessages::conrefOmitEndTag, StringMessageArg(e->name()));
823 #endif
824     if (edef->declaredContent() == ElementDefinition::empty)
825       message(ParserMessages::conrefEmpty, StringMessageArg(e->name()));
826   }
827 }
828
829 ElementType *Parser::lookupCreateElement(const StringC &name)
830 {
831   ElementType *e = defDtd().lookupElementType(name);
832   if (!e) {
833     if (haveDefLpd()) 
834       message(ParserMessages::noSuchSourceElement, StringMessageArg(name));
835     else {
836       e = new ElementType(name, defDtd().nElementTypeIndex());
837       defDtd().insertElementType(e);
838     }
839   }
840   return e;
841 }
842
843 RankStem *Parser::lookupCreateRankStem(const StringC &name)
844 {
845   RankStem *r = defDtd().lookupRankStem(name);
846   if (!r) {
847     r = new RankStem(name, defDtd().nRankStem());
848     defDtd().insertRankStem(r);
849     const ElementType *e = defDtd().lookupElementType(name);
850     if (e && e->definition() != 0)
851       message(ParserMessages::rankStemGenericIdentifier, StringMessageArg(name));
852   }
853   return r;
854 }
855
856 Boolean Parser::parseExceptions(unsigned declInputLevel,
857                                 Ptr<ElementDefinition> &def)
858 {
859   Param parm;
860   static AllowedParams
861     allowExceptionsMdc(Param::mdc, Param::exclusions, Param::inclusions);
862   if (!parseParam(allowExceptionsMdc, declInputLevel, parm))
863     return 0;
864   if (parm.type == Param::exclusions) {
865     def->setExclusions(parm.elementVector);
866     static AllowedParams allowInclusionsMdc(Param::mdc, Param::inclusions);
867     if (!parseParam(allowInclusionsMdc, declInputLevel, parm))
868       return 0;
869   }
870   if (parm.type == Param::inclusions) {
871     def->setInclusions(parm.elementVector);
872     size_t nI = def->nInclusions();
873     size_t nE = def->nExclusions();
874     if (nE) {
875       for (size_t i = 0; i < nI; i++) {
876         const ElementType *e = def->inclusion(i);
877         for (size_t j = 0; j < nE; j++)
878           if (def->exclusion(j) == e)
879             message(ParserMessages::excludeIncludeSame,
880                     StringMessageArg(e->name()));
881       }
882     }
883     if (!parseParam(allowMdc, declInputLevel, parm))
884       return 0;
885   }
886   return 1;
887 }
888
889 Boolean Parser::parseAttlistDecl()
890 {
891   unsigned declInputLevel = inputLevel();
892   Param parm;
893   size_t attcnt = 0;
894   size_t idIndex = size_t(-1);
895   size_t notationIndex = size_t(-1);
896   Boolean anyCurrent = 0;
897   
898   Boolean isNotation;
899   Vector<Attributed *> attributed;
900   if (!parseAttributed(declInputLevel, parm, attributed, isNotation))
901     return 0;
902   Vector<CopyOwner<AttributeDefinition> > defs;
903   if (!parseParam(allowName, declInputLevel, parm))
904     return 0;
905   do {
906     StringC attributeName;
907     parm.token.swap(attributeName);
908     attcnt++;
909     Boolean duplicate = 0;
910     size_t i;
911     for (i = 0; i < defs.size(); i++)
912       if (defs[i]->name() == attributeName) {
913         message(ParserMessages::duplicateAttributeDef,
914                 StringMessageArg(attributeName));
915         duplicate = 1;
916         break;
917       }
918     Owner<DeclaredValue> declaredValue;
919     if (!parseDeclaredValue(declInputLevel, isNotation, parm, declaredValue))
920       return 0;
921     if (!duplicate) {
922       if (declaredValue->isId()) {
923         if (idIndex != size_t(-1))
924           message(ParserMessages::multipleIdAttributes,
925                   StringMessageArg(defs[idIndex]->name()));
926         idIndex = defs.size();
927       }
928       else if (declaredValue->isNotation()) {
929         if (notationIndex != size_t(-1))
930           message(ParserMessages::multipleNotationAttributes,
931                   StringMessageArg(defs[notationIndex]->name()));
932         notationIndex = defs.size();
933       }
934     }
935     const Vector<StringC> *tokensPtr = declaredValue->getTokens();
936     if (tokensPtr) {
937       size_t nTokens = tokensPtr->size();
938       Vector<StringC>::const_iterator tokens = tokensPtr->begin();
939       for (i = 0; i < nTokens; i++) {
940         for (size_t j = 0; j < defs.size(); j++)
941           if (defs[j]->containsToken(tokens[i])) {
942             message(ParserMessages::duplicateAttributeToken,
943                     StringMessageArg(tokens[i]));
944             break;
945           }
946       }
947       attcnt += nTokens;
948     }
949     Owner<AttributeDefinition> def;
950     if (!parseDefaultValue(declInputLevel, isNotation, parm, attributeName,
951                            declaredValue, def, anyCurrent))
952       return 0;
953     if (haveDefLpd() && defLpd().type() == Lpd::simpleLink && !def->isFixed())
954       message(ParserMessages::simpleLinkFixedAttribute);
955     if (!duplicate) {
956       defs.resize(defs.size() + 1);
957       defs.back() = def.extract();
958     }
959     static AllowedParams allowNameMdc(Param::name, Param::mdc);
960     if (!parseParam(allowNameMdc, declInputLevel, parm))
961       return 0;
962   } while (parm.type != Param::mdc);
963   if (attcnt > syntax().attcnt())
964     message(ParserMessages::attcnt,
965             NumberMessageArg(attcnt),
966             NumberMessageArg(syntax().attcnt()));
967   if (haveDefLpd() && !isNotation) {
968     if (defLpd().type() == Lpd::simpleLink) {
969       for (size_t i = 0; i < attributed.size(); i++) {
970         const ElementType *e = (const ElementType *)attributed[i];
971         if (e) {
972           if (e->name() == defLpd().sourceDtd()->name()) {
973             SimpleLpd &lpd = (SimpleLpd &)defLpd();
974             if (lpd.attributeDef().isNull())
975               lpd.setAttributeDef(new AttributeDefinitionList(defs, 0));
976             else
977               message(ParserMessages::duplicateAttlistElement,
978                       StringMessageArg(e->name()));
979           }
980           else
981             message(ParserMessages::simpleLinkAttlistElement,
982                     StringMessageArg(e->name()));
983         }
984       }
985     }
986     else {
987       Ptr<AttributeDefinitionList>
988         adl(new AttributeDefinitionList(defs,
989                                         defComplexLpd()
990                                         .allocAttributeDefinitionListIndex()));
991       for (size_t i = 0; i < attributed.size(); i++) {
992         const ElementType *e = (const ElementType *)attributed[i];
993         if (e) {
994           if (defComplexLpd().attributeDef(e).isNull())
995             defComplexLpd().setAttributeDef(e, adl);
996           else
997             message(ParserMessages::duplicateAttlistElement,
998                     StringMessageArg(e->name()));
999         }
1000       }
1001     }
1002   }
1003   else {
1004     Ptr<AttributeDefinitionList>
1005       adl(new AttributeDefinitionList(defs,
1006                                       defDtd()
1007                                       .allocAttributeDefinitionListIndex(),
1008                                       anyCurrent,
1009                                       idIndex,
1010                                       notationIndex));
1011     for (size_t i = 0; i < attributed.size(); i++) {
1012       if (attributed[i]->attributeDef().isNull()) {
1013         attributed[i]->setAttributeDef(adl);
1014         if (!isNotation) {
1015           ElementType *e = (ElementType *)attributed[i];
1016           if (e->definition() != 0)
1017             checkElementAttribute(e);
1018         }
1019       }
1020       else if (options().errorAfdr) {
1021         if (!hadAfdrDecl()) {
1022           message(ParserMessages::missingAfdrDecl);
1023           setHadAfdrDecl();
1024         }
1025         if (isNotation)
1026           message(ParserMessages::duplicateAttlistNotation,
1027                   StringMessageArg(((Notation *)attributed[i])->name()));
1028         else
1029           message(ParserMessages::duplicateAttlistElement,
1030                   StringMessageArg(((ElementType *)attributed[i])->name()));
1031       }
1032       else {
1033         AttributeDefinitionList *curAdl;
1034         {
1035           // Use block to make sure temporary gets destroyed.
1036           curAdl = attributed[i]->attributeDef().pointer();
1037         }
1038         size_t oldSize = curAdl->size();
1039         if (curAdl->count() != 1) {
1040           Vector<CopyOwner<AttributeDefinition> > copy(oldSize);
1041           for (size_t j = 0; j < oldSize; j++)
1042             copy[j] = curAdl->def(j)->copy();
1043           Ptr<AttributeDefinitionList> adlCopy
1044             = new AttributeDefinitionList(copy,
1045                                           defDtd().allocAttributeDefinitionListIndex(),
1046                                           curAdl->anyCurrent(),
1047                                           curAdl->idIndex(),
1048                                           curAdl->notationIndex());
1049           attributed[i]->setAttributeDef(adlCopy);
1050           curAdl = adlCopy.pointer();
1051         }
1052         // FIXME check for multiple ID and NOTATION attributes
1053         for (size_t j = 0; j < adl->size(); j++) {
1054           unsigned tem;
1055           if (!curAdl->attributeIndex(adl->def(j)->name(), tem))
1056             curAdl->append(adl->def(j)->copy());
1057         }
1058         if (!isNotation) {
1059           ElementType *e = (ElementType *)attributed[i];
1060           if (e->definition() != 0)
1061             checkElementAttribute(e, oldSize);
1062         }
1063       }
1064     }
1065   }
1066   if (currentMarkup()) {
1067     if (isNotation) {
1068       Vector<ConstPtr<Notation> > v(attributed.size());
1069       for (size_t i = 0; i < attributed.size(); i++)
1070         v[i] = (Notation *)attributed[i];
1071       eventHandler()
1072         .attlistNotationDecl(new (eventAllocator())
1073                              AttlistNotationDeclEvent(v,
1074                                                       markupLocation(),
1075                                                       currentMarkup()));
1076     }
1077     else {
1078       Vector<const ElementType *> v(attributed.size());
1079       for (size_t i = 0; i < attributed.size(); i++)
1080         v[i] = (ElementType *)attributed[i];
1081       if (haveDefLpd())
1082         eventHandler()
1083           .linkAttlistDecl(new (eventAllocator())
1084                            LinkAttlistDeclEvent(v,
1085                                                 defLpdPointer(),
1086                                                 markupLocation(),
1087                                                 currentMarkup()));
1088       else
1089         eventHandler().attlistDecl(new (eventAllocator())
1090                                    AttlistDeclEvent(v,
1091                                                     currentDtdPointer(),
1092                                                     markupLocation(),
1093                                                     currentMarkup()));
1094     }
1095   }
1096   if (isNotation) {
1097     Dtd::EntityIter entityIter(defDtd().generalEntityIter());
1098     for (;;) {
1099       Ptr<Entity> entity(entityIter.next());
1100       if (entity.isNull())
1101         break;
1102       const ExternalDataEntity *external = entity->asExternalDataEntity();
1103       if (external) {
1104         const Notation *entityNotation = external->notation();
1105         for (size_t  i = 0; i < attributed.size(); i++)
1106           if ((Notation *)attributed[i] == entityNotation) {
1107             AttributeList attributes(entityNotation->attributeDef());
1108             attributes.finish(*this);
1109             ((ExternalDataEntity *)entity.pointer())
1110               ->setNotation((Notation *)attributed[i], attributes);
1111           }
1112       }
1113     }
1114   }
1115   return 1;
1116 }
1117
1118
1119 Boolean Parser::parseAttributed(unsigned declInputLevel,
1120                                 Param &parm,
1121                                 Vector<Attributed *> &attributed,
1122                                 Boolean &isNotation)
1123 {
1124   // There's a hack in getIndicatedReservedName allows #ALL as #ANY.
1125   static AllowedParams
1126     allowNameGroupNotation(Param::name,
1127                            Param::nameGroup,
1128                            Param::indicatedReservedName + Syntax::rNOTATION);
1129   static AllowedParams
1130     allowNameGroupNotationAll(Param::name,
1131                               Param::nameGroup,
1132                               Param::indicatedReservedName
1133                               + Syntax::rNOTATION,
1134                               Param::indicatedReservedName
1135                               + Syntax::rANY);
1136   if (!parseParam(options().errorAfdr || haveDefLpd()
1137                   ? allowNameGroupNotation
1138                   : allowNameGroupNotationAll,
1139                   declInputLevel, parm))
1140     return 0;
1141   if (parm.type == Param::indicatedReservedName + Syntax::rNOTATION) {
1142     isNotation = 1;
1143     static AllowedParams
1144       allowNameGroupAll(Param::name,
1145                         Param::nameGroup,
1146                         Param::indicatedReservedName + Syntax::rANY);
1147     if (!parseParam(options().errorAfdr || haveDefLpd()
1148                     ? allowNameNameGroup
1149                     : allowNameGroupAll,
1150                     declInputLevel, parm))
1151       return 0;
1152     if (parm.type == Param::nameGroup) {
1153       attributed.resize(parm.nameTokenVector.size());
1154       for (size_t i = 0; i < attributed.size(); i++)
1155         attributed[i] = lookupCreateNotation(parm.nameTokenVector[i].name);
1156     }
1157     else {
1158       if (parm.type != Param::name && !hadAfdrDecl()) {
1159         message(ParserMessages::missingAfdrDecl);
1160         setHadAfdrDecl();
1161       }
1162       attributed.resize(1);
1163       attributed[0]
1164         = lookupCreateNotation(parm.type == Param::name
1165                                ? parm.token
1166                                : syntax().rniReservedName(Syntax::rANY));
1167     }
1168   }
1169   else {
1170     isNotation = 0;
1171     if (parm.type == Param::nameGroup) {
1172       attributed.resize(parm.nameTokenVector.size());
1173       for (size_t i = 0; i < attributed.size(); i++)
1174         attributed[i] = lookupCreateElement(parm.nameTokenVector[i].name);
1175     }
1176     else {
1177       if (parm.type != Param::name && !hadAfdrDecl()) {
1178         message(ParserMessages::missingAfdrDecl);
1179         setHadAfdrDecl();
1180       }
1181       attributed.resize(1);
1182       attributed[0]
1183         = lookupCreateElement(parm.type == Param::name
1184                               ? parm.token
1185                               : syntax().rniReservedName(Syntax::rANY));
1186     }
1187   }
1188   return 1;
1189 }
1190
1191 Boolean Parser::parseDeclaredValue(unsigned declInputLevel,
1192                                    Boolean isNotation,
1193                                    Param &parm,
1194                                    Owner<DeclaredValue> &declaredValue)
1195 {
1196   static Param::Type declaredValues[] = {
1197     Param::reservedName + Syntax::rCDATA,
1198     Param::reservedName + Syntax::rENTITY,
1199     Param::reservedName + Syntax::rENTITIES,
1200     Param::reservedName + Syntax::rID,
1201     Param::reservedName + Syntax::rIDREF,
1202     Param::reservedName + Syntax::rIDREFS,
1203     Param::reservedName + Syntax::rNAME,
1204     Param::reservedName + Syntax::rNAMES,
1205     Param::reservedName + Syntax::rNMTOKEN,
1206     Param::reservedName + Syntax::rNMTOKENS,
1207     Param::reservedName + Syntax::rNUMBER,
1208     Param::reservedName + Syntax::rNUMBERS,
1209     Param::reservedName + Syntax::rNUTOKEN,
1210     Param::reservedName + Syntax::rNUTOKENS,
1211     Param::reservedName + Syntax::rNOTATION,
1212     Param::nameTokenGroup
1213     };
1214   static AllowedParams allowDeclaredValue(declaredValues,
1215                                           SIZEOF(declaredValues));
1216   if (!parseParam(allowDeclaredValue, declInputLevel, parm))
1217     return 0;
1218   enum { asDataAttribute = 01, asLinkAttribute = 02 };
1219   unsigned allowedFlags = asDataAttribute|asLinkAttribute;
1220   switch (parm.type) {
1221   case Param::reservedName + Syntax::rCDATA:
1222     declaredValue = new CdataDeclaredValue;
1223     break;
1224   case Param::reservedName + Syntax::rENTITY:
1225     declaredValue = new EntityDeclaredValue(0);
1226     allowedFlags = asLinkAttribute;
1227     break;
1228   case Param::reservedName + Syntax::rENTITIES:
1229     declaredValue = new EntityDeclaredValue(1);
1230     allowedFlags = asLinkAttribute;
1231     break;
1232   case Param::reservedName + Syntax::rID:
1233     declaredValue = new IdDeclaredValue;
1234     allowedFlags = 0;
1235     break;
1236   case Param::reservedName + Syntax::rIDREF:
1237     declaredValue = new IdrefDeclaredValue(0);
1238     allowedFlags = 0;
1239     break;
1240   case Param::reservedName + Syntax::rIDREFS:
1241     declaredValue = new IdrefDeclaredValue(1);
1242     allowedFlags = 0;
1243     break;
1244   case Param::reservedName + Syntax::rNAME:
1245     declaredValue
1246       = new TokenizedDeclaredValue(TokenizedDeclaredValue::name, 0);
1247     break;
1248   case Param::reservedName + Syntax::rNAMES:
1249     declaredValue
1250       = new TokenizedDeclaredValue(TokenizedDeclaredValue::name, 1);
1251     break;
1252   case Param::reservedName + Syntax::rNMTOKEN:
1253     declaredValue
1254       = new TokenizedDeclaredValue(TokenizedDeclaredValue::nameToken, 0);
1255     break;
1256   case Param::reservedName + Syntax::rNMTOKENS:
1257     declaredValue
1258       = new TokenizedDeclaredValue(TokenizedDeclaredValue::nameToken, 1);
1259     break;
1260   case Param::reservedName + Syntax::rNUMBER:
1261     declaredValue
1262       = new TokenizedDeclaredValue(TokenizedDeclaredValue::number, 0);
1263     break;
1264   case Param::reservedName + Syntax::rNUMBERS:
1265     declaredValue
1266       = new TokenizedDeclaredValue(TokenizedDeclaredValue::number, 1);
1267     break;
1268   case Param::reservedName + Syntax::rNUTOKEN:
1269     declaredValue
1270       = new TokenizedDeclaredValue(TokenizedDeclaredValue::numberToken, 0);
1271     break;
1272   case Param::reservedName + Syntax::rNUTOKENS:
1273     declaredValue
1274       = new TokenizedDeclaredValue(TokenizedDeclaredValue::numberToken, 1);
1275     break;
1276   case Param::reservedName + Syntax::rNOTATION:
1277     {
1278       static AllowedParams allowNameGroup(Param::nameGroup);
1279       if (!parseParam(allowNameGroup, declInputLevel, parm))
1280         return 0;
1281       Vector<StringC> group(parm.nameTokenVector.size());
1282       for (size_t i = 0; i < group.size(); i++)
1283         parm.nameTokenVector[i].name.swap(group[i]);
1284       declaredValue = new NotationDeclaredValue(group);
1285       allowedFlags = 0;
1286     }
1287     break;
1288   case Param::nameTokenGroup:
1289     {
1290       Vector<StringC> group(parm.nameTokenVector.size());
1291       for (size_t i = 0; i < group.size(); i++)
1292         parm.nameTokenVector[i].name.swap(group[i]);
1293       declaredValue = new NameTokenGroupDeclaredValue(group);
1294     }
1295     break;
1296   default:
1297     CANNOT_HAPPEN();
1298   }
1299   if (isNotation) {
1300     if (!(allowedFlags & asDataAttribute))
1301       message(ParserMessages::dataAttributeDeclaredValue);
1302   }
1303   else if (haveDefLpd() && !isNotation && !(allowedFlags & asLinkAttribute))
1304     message(ParserMessages::linkAttributeDeclaredValue);
1305   return 1;
1306 }
1307
1308 Boolean Parser::parseDefaultValue(unsigned declInputLevel,
1309                                   Boolean isNotation,
1310                                   Param &parm,
1311                                   const StringC &attributeName,
1312                                   Owner<DeclaredValue> &declaredValue,
1313                                   Owner<AttributeDefinition> &def,
1314                                   Boolean &anyCurrent)
1315 {
1316   // default value
1317   static AllowedParams
1318     allowDefaultValue(Param::indicatedReservedName + Syntax::rFIXED,
1319                       Param::indicatedReservedName + Syntax::rREQUIRED,
1320                       Param::indicatedReservedName + Syntax::rCURRENT,
1321                       Param::indicatedReservedName + Syntax::rCONREF,
1322                       Param::indicatedReservedName + Syntax::rIMPLIED,
1323                       Param::attributeValue,
1324                       Param::attributeValueLiteral);
1325   static AllowedParams
1326     allowTokenDefaultValue(Param::indicatedReservedName + Syntax::rFIXED,
1327                       Param::indicatedReservedName + Syntax::rREQUIRED,
1328                       Param::indicatedReservedName + Syntax::rCURRENT,
1329                       Param::indicatedReservedName + Syntax::rCONREF,
1330                       Param::indicatedReservedName + Syntax::rIMPLIED,
1331                       Param::attributeValue,
1332                       Param::tokenizedAttributeValueLiteral);
1333   if (!parseParam(declaredValue->tokenized()
1334                   ? allowTokenDefaultValue
1335                   : allowDefaultValue, declInputLevel, parm))
1336     return 0;
1337   switch (parm.type) {
1338   case Param::indicatedReservedName + Syntax::rFIXED:
1339     {
1340       static AllowedParams allowValue(Param::attributeValue,
1341                                       Param::attributeValueLiteral);
1342       static AllowedParams
1343         allowTokenValue(Param::attributeValue,
1344                         Param::tokenizedAttributeValueLiteral);
1345       if (!parseParam(declaredValue->tokenized()
1346                       ? allowTokenValue
1347                       : allowValue, declInputLevel, parm))
1348         return 0;
1349       unsigned specLength = 0;
1350       AttributeValue *value = declaredValue->makeValue(parm.literalText,
1351                                                        *this,
1352                                                        attributeName,
1353                                                        specLength);
1354       if (declaredValue->isId())
1355         message(ParserMessages::idDeclaredValue);
1356       def = new FixedAttributeDefinition(attributeName,
1357                                          declaredValue.extract(),
1358                                          value);
1359     }
1360     break;
1361   case Param::attributeValue:
1362   case Param::attributeValueLiteral:
1363   case Param::tokenizedAttributeValueLiteral:
1364     {
1365       unsigned specLength = 0;
1366       AttributeValue *value = declaredValue->makeValue(parm.literalText,
1367                                                        *this,
1368                                                        attributeName,
1369                                                        specLength);
1370       if (declaredValue->isId())
1371         message(ParserMessages::idDeclaredValue);
1372       def = new DefaultAttributeDefinition(attributeName,
1373                                            declaredValue.extract(),
1374                                            value);
1375     }
1376     break;
1377   case Param::indicatedReservedName + Syntax::rREQUIRED:
1378     def = new RequiredAttributeDefinition(attributeName,
1379                                           declaredValue.extract());
1380     break;
1381   case Param::indicatedReservedName + Syntax::rCURRENT:
1382     anyCurrent = 1;            
1383     if (declaredValue->isId())
1384       message(ParserMessages::idDeclaredValue);
1385     def = new CurrentAttributeDefinition(attributeName,
1386                                          declaredValue.extract(),
1387                                          defDtd().allocCurrentAttributeIndex());
1388     if (isNotation)
1389       message(ParserMessages::dataAttributeDefaultValue);
1390     else if (haveDefLpd())
1391       message(ParserMessages::linkAttributeDefaultValue);
1392     break;
1393   case Param::indicatedReservedName + Syntax::rCONREF:
1394     if (declaredValue->isId())
1395       message(ParserMessages::idDeclaredValue);
1396     def = new ConrefAttributeDefinition(attributeName,
1397                                         declaredValue.extract());
1398     if (isNotation)
1399       message(ParserMessages::dataAttributeDefaultValue);
1400     else if (haveDefLpd())
1401       message(ParserMessages::linkAttributeDefaultValue);
1402     break;
1403   case Param::indicatedReservedName + Syntax::rIMPLIED:
1404     def = new ImpliedAttributeDefinition(attributeName,
1405                                          declaredValue.extract());
1406     break;
1407   default:
1408     CANNOT_HAPPEN();
1409   }
1410   return 1;
1411 }
1412
1413 // parm contains either system or public
1414
1415 Boolean Parser::parseExternalId(const AllowedParams &sysidAllow,
1416                                 const AllowedParams &endAllow,
1417                                 unsigned declInputLevel,
1418                                 Param &parm,
1419                                 ExternalId &id)
1420 {
1421   id.setLocation(currentLocation());
1422   if (parm.type == Param::reservedName + Syntax::rPUBLIC) {
1423     static AllowedParams allowMinimumLiteral(Param::minimumLiteral);
1424     if (!parseParam(allowMinimumLiteral, declInputLevel, parm))
1425       return 0;
1426     const MessageType1 *err;
1427     if (!id.setPublic(parm.literalText, sd().docCharset(), syntax().space(),
1428                       err)
1429         && sd().formal())
1430       message(*err,
1431               StringMessageArg(*id.publicIdString()));
1432   }
1433   if (!parseParam(sysidAllow, declInputLevel, parm))
1434     return 0;
1435   if (parm.type == Param::systemIdentifier) {
1436     id.setSystem(parm.literalText);
1437     if (!parseParam(endAllow, declInputLevel, parm))
1438       return 0;
1439   }
1440   return 1;
1441 }
1442
1443 Boolean Parser::parseNotationDecl()
1444 {
1445   unsigned declInputLevel = inputLevel();
1446   Param parm;
1447   if (!parseParam(allowName, declInputLevel, parm))
1448     return 0;
1449   Notation *nt = lookupCreateNotation(parm.token);
1450   if (nt->defined())
1451     message(ParserMessages::duplicateNotationDeclaration,
1452             StringMessageArg(parm.token));
1453   static AllowedParams
1454     allowPublicSystem(Param::reservedName + Syntax::rPUBLIC,
1455                       Param::reservedName + Syntax::rSYSTEM);
1456   if (!parseParam(allowPublicSystem, declInputLevel, parm))
1457     return 0;
1458
1459
1460   static AllowedParams allowSystemIdentifierMdc(Param::systemIdentifier,
1461                                                 Param::mdc);
1462
1463   ExternalId id;
1464   if (!parseExternalId(allowSystemIdentifierMdc, allowMdc,
1465                        declInputLevel, parm, id))
1466     return 0;
1467   if (sd().formal()) {
1468     PublicId::TextClass textClass;
1469     const PublicId *publicId = id.publicId();
1470     if (publicId
1471         && publicId->getTextClass(textClass)
1472         && textClass != PublicId::NOTATION)
1473       message(ParserMessages::notationIdentifierTextClass);
1474   }
1475   if (!nt->defined()) {
1476     nt->setExternalId(id, markupLocation());
1477     nt->generateSystemId(*this);
1478     if (currentMarkup())
1479       eventHandler().notationDecl(new (eventAllocator())
1480                                   NotationDeclEvent(nt, markupLocation(),
1481                                                     currentMarkup()));
1482   }
1483   return 1;
1484 }
1485
1486 Boolean Parser::parseEntityDecl()
1487 {
1488   unsigned declInputLevel = inputLevel();
1489   Param parm;
1490
1491   static AllowedParams
1492     allowEntityNamePero(Param::entityName,
1493                         Param::indicatedReservedName + Syntax::rDEFAULT,
1494                         Param::pero);
1495
1496   if (!parseParam(allowEntityNamePero, declInputLevel, parm))
1497     return 0;
1498
1499   Entity::DeclType declType;
1500   StringC name;                 // empty for default entity
1501   if (parm.type == Param::pero) {
1502     declType = Entity::parameterEntity;
1503     static AllowedParams allowParamEntityName(Param::paramEntityName);
1504     if (!parseParam(allowParamEntityName, declInputLevel, parm))
1505       return 0;
1506     parm.token.swap(name);
1507   }
1508   else {
1509     declType = Entity::generalEntity;
1510     if (parm.type == Param::entityName)
1511       parm.token.swap(name);
1512   }
1513   static AllowedParams
1514     allowEntityTextType(Param::paramLiteral,
1515                         Param::reservedName + Syntax::rCDATA,
1516                         Param::reservedName + Syntax::rSDATA,
1517                         Param::reservedName + Syntax::rPI,
1518                         Param::reservedName + Syntax::rSTARTTAG,
1519                         Param::reservedName + Syntax::rENDTAG,
1520                         Param::reservedName + Syntax::rMS,
1521                         Param::reservedName + Syntax::rMD,
1522                         Param::reservedName + Syntax::rSYSTEM,
1523                         Param::reservedName + Syntax::rPUBLIC);
1524
1525   if (!parseParam(allowEntityTextType, declInputLevel, parm))
1526     return 0;
1527   Location typeLocation(currentLocation());
1528   Entity::DataType dataType = Entity::sgmlText;
1529   InternalTextEntity::Bracketed bracketed = InternalTextEntity::none;
1530   switch (parm.type) {
1531   case Param::reservedName + Syntax::rSYSTEM:
1532   case Param::reservedName + Syntax::rPUBLIC:
1533     return parseExternalEntity(name, declType, declInputLevel, parm);
1534   case Param::reservedName + Syntax::rCDATA:
1535     dataType = Entity::cdata;
1536     break;
1537   case Param::reservedName + Syntax::rSDATA:
1538     dataType = Entity::sdata;
1539     break;
1540   case Param::reservedName + Syntax::rPI:
1541     dataType = Entity::pi;
1542     break;
1543   case Param::reservedName + Syntax::rSTARTTAG:
1544     bracketed = InternalTextEntity::starttag;
1545     break;
1546   case Param::reservedName + Syntax::rENDTAG:
1547     bracketed = InternalTextEntity::endtag;
1548     break;
1549   case Param::reservedName + Syntax::rMS:
1550     bracketed = InternalTextEntity::ms;
1551     break;
1552   case Param::reservedName + Syntax::rMD:
1553     bracketed = InternalTextEntity::md;
1554     break;
1555   }
1556   if (parm.type != Param::paramLiteral) {
1557     if (!parseParam(allowParamLiteral, declInputLevel, parm))
1558       return 0;
1559   }
1560   Text text;
1561   parm.literalText.swap(text);
1562   if (bracketed != InternalTextEntity::none) {
1563     StringC open;
1564     StringC close;
1565     switch (bracketed) {
1566     case InternalTextEntity::starttag:
1567       open = syntax().delimGeneral(Syntax::dSTAGO);
1568       close = syntax().delimGeneral(Syntax::dTAGC);
1569       break;
1570     case InternalTextEntity::endtag:
1571       open = syntax().delimGeneral(Syntax::dETAGO);
1572       close = syntax().delimGeneral(Syntax::dTAGC);
1573       break;
1574     case InternalTextEntity::ms:
1575       open = syntax().delimGeneral(Syntax::dMDO);
1576       open += syntax().delimGeneral(Syntax::dDSO);
1577       close = syntax().delimGeneral(Syntax::dMSC);
1578       close += syntax().delimGeneral(Syntax::dMDC);
1579       break;
1580     case InternalTextEntity::md:
1581       open = syntax().delimGeneral(Syntax::dMDO);
1582       close = syntax().delimGeneral(Syntax::dMDC);
1583       break;
1584     default:
1585       CANNOT_HAPPEN();
1586     }
1587     text.insertChars(open, Location(new BracketOrigin(typeLocation,
1588                                                       BracketOrigin::open),
1589                                     0));
1590     text.addChars(close, Location(new BracketOrigin(typeLocation,
1591                                                     BracketOrigin::close),
1592                                   0));
1593     if (text.size() > syntax().litlen()
1594         && text.size() - open.size() - close.size() <= syntax().litlen())
1595       message(ParserMessages::bracketedLitlen,
1596               NumberMessageArg(syntax().litlen()));
1597   }
1598   if (!parseParam(allowMdc, declInputLevel, parm))
1599     return 0;
1600   if (declType == Entity::parameterEntity
1601       && (dataType == Entity::cdata || dataType == Entity::sdata)) {
1602     message(ParserMessages::internalParameterDataEntity,
1603             StringMessageArg(name));
1604     return 1;
1605   }
1606   Ptr<Entity> entity;
1607   switch (dataType) {
1608   case Entity::cdata:
1609     entity = new InternalCdataEntity(name, markupLocation(), text);
1610     break;
1611   case Entity::sdata:
1612     entity = new InternalSdataEntity(name, markupLocation(), text);
1613     break;
1614   case Entity::pi:
1615     entity = new PiEntity(name, declType, markupLocation(), text);
1616     break;
1617   case Entity::sgmlText:
1618     entity = new InternalTextEntity(name, declType, markupLocation(), text, bracketed);
1619     break;
1620   default:
1621     CANNOT_HAPPEN();
1622     break;
1623   }
1624   maybeDefineEntity(entity);
1625   return 1;
1626 }
1627
1628 Boolean Parser::parseExternalEntity(StringC &name,
1629                                     Entity::DeclType declType,
1630                                     unsigned declInputLevel,
1631                                     Param &parm)
1632 {
1633   static AllowedParams
1634     allowSystemIdentifierEntityTypeMdc(Param::systemIdentifier,
1635                                        Param::reservedName + Syntax::rSUBDOC,
1636                                        Param::reservedName + Syntax::rCDATA,
1637                                        Param::reservedName + Syntax::rSDATA,
1638                                        Param::reservedName + Syntax::rNDATA,
1639                                        Param::mdc);
1640   static AllowedParams
1641     allowEntityTypeMdc(Param::reservedName + Syntax::rSUBDOC,
1642                        Param::reservedName + Syntax::rCDATA,
1643                        Param::reservedName + Syntax::rSDATA,
1644                        Param::reservedName + Syntax::rNDATA,
1645                        Param::mdc);
1646   
1647   ExternalId id;
1648   if (!parseExternalId(allowSystemIdentifierEntityTypeMdc, allowEntityTypeMdc,
1649                        declInputLevel, parm, id))
1650     return 0;
1651   if (parm.type == Param::mdc) {
1652     maybeDefineEntity(new ExternalTextEntity(name, declType, markupLocation(),
1653                                              id));
1654     return 1;
1655   }
1656   Ptr<Entity> entity;
1657   if (parm.type == Param::reservedName + Syntax::rSUBDOC) {
1658     if (sd().subdoc() == 0)
1659       message(ParserMessages::subdocEntity, StringMessageArg(name));
1660     if (!parseParam(allowMdc, declInputLevel, parm))
1661       return 0;
1662     entity = new SubdocEntity(name, markupLocation(), id);
1663   }
1664   else {
1665     Entity::DataType dataType;
1666     switch (parm.type) {
1667     case Param::reservedName + Syntax::rCDATA:
1668       dataType = Entity::cdata;
1669       break;
1670     case Param::reservedName + Syntax::rSDATA:
1671       dataType = Entity::sdata;
1672       break;
1673     case Param::reservedName + Syntax::rNDATA:
1674       dataType = Entity::ndata;
1675       break;
1676     default:
1677       CANNOT_HAPPEN();
1678     }
1679     if (!parseParam(allowName, declInputLevel, parm))
1680       return 0;
1681     ConstPtr<Notation> notation(lookupCreateNotation(parm.token));
1682     if (!parseParam(allowDsoMdc, declInputLevel, parm))
1683       return 0;
1684     AttributeList attributes(notation->attributeDef());
1685     if (parm.type == Param::dso) {
1686       if (attributes.size() == 0)
1687         message(ParserMessages::notationNoAttributes,
1688                 StringMessageArg(notation->name()));
1689       Boolean netEnabling;
1690       if (!parseAttributeSpec(1, attributes, netEnabling))
1691         return 0;
1692       if (attributes.nSpec() == 0)
1693         message(ParserMessages::emptyDataAttributeSpec);
1694       if (!parseParam(allowMdc, declInputLevel, parm))
1695         return 0;
1696     }
1697     else
1698       attributes.finish(*this);
1699     entity = new ExternalDataEntity(name, dataType, markupLocation(), id, notation,
1700                                     attributes);
1701   }
1702   if (declType == Entity::parameterEntity) {
1703     message(ParserMessages::externalParameterDataSubdocEntity,
1704             StringMessageArg(name));
1705     return 1;
1706   }
1707   maybeDefineEntity(entity);
1708   return 1;
1709 }
1710
1711 Notation *Parser::lookupCreateNotation(const StringC &name)
1712 {
1713   Ptr<Notation> nt = defDtd().lookupNotation(name);
1714   if (nt.isNull()) {
1715     nt = new Notation(name, defDtd().namePointer(), defDtd().isBase());
1716     defDtd().insertNotation(nt);
1717   }
1718   return nt.pointer();
1719 }
1720
1721 void Parser::maybeDefineEntity(const Ptr<Entity> &entity)
1722 {
1723   Dtd &dtd = defDtd();
1724   if (haveDefLpd())
1725     entity->setDeclIn(dtd.namePointer(),
1726                       dtd.isBase(),
1727                       defLpd().namePointer(),
1728                       defLpd().active());
1729   else
1730     entity->setDeclIn(dtd.namePointer(), dtd.isBase());
1731   Boolean ignored = 0;
1732   if (entity->name().size() == 0) {
1733     const Entity *oldEntity = dtd.defaultEntity().pointer();
1734     if (oldEntity == 0
1735         || (!oldEntity->declInActiveLpd() && entity->declInActiveLpd()))
1736       dtd.setDefaultEntity(entity, *this);
1737     else {
1738       ignored = 1;
1739       if (options().warnDuplicateEntity)
1740         message(ParserMessages::duplicateEntityDeclaration,
1741                 StringMessageArg(syntax().rniReservedName(Syntax::rDEFAULT)));
1742     }
1743   }
1744   else {
1745     Ptr<Entity> oldEntity = dtd.insertEntity(entity);
1746     if (oldEntity.isNull())
1747       entity->generateSystemId(*this);
1748     else if (oldEntity->defaulted()) {
1749       dtd.insertEntity(entity, 1);
1750       message(ParserMessages::defaultedEntityDefined,
1751               StringMessageArg(entity->name()));
1752       entity->generateSystemId(*this);
1753     }
1754     else {
1755       if (entity->declInActiveLpd() && !oldEntity->declInActiveLpd()) {
1756         dtd.insertEntity(entity, 1);
1757         entity->generateSystemId(*this);
1758       }
1759       else {
1760         ignored = 1;
1761         if (options().warnDuplicateEntity)
1762           message(entity->declType() == Entity::parameterEntity
1763                   ? ParserMessages::duplicateParameterEntityDeclaration
1764                   : ParserMessages::duplicateEntityDeclaration,
1765                   StringMessageArg(entity->name()));
1766       }
1767     }
1768   }
1769   if (currentMarkup())
1770     eventHandler().entityDecl(new (eventAllocator())
1771                               EntityDeclEvent(entity, ignored,
1772                                               markupLocation(),
1773                                               currentMarkup()));
1774 }
1775
1776 Boolean Parser::parseShortrefDecl()
1777 {
1778   if (!defDtd().isBase())
1779     message(ParserMessages::shortrefOnlyInBaseDtd);
1780
1781   unsigned declInputLevel = inputLevel();
1782   Param parm;
1783
1784   if (!parseParam(allowName, declInputLevel, parm))
1785     return 0;
1786   ShortReferenceMap *map = lookupCreateMap(parm.token);
1787   int valid = 1;
1788   if (map->defined()) {
1789     message(ParserMessages::duplicateShortrefDeclaration,
1790             StringMessageArg(parm.token),
1791             map->defLocation());
1792     valid = 0;
1793   }
1794   else
1795     map->setDefLocation(markupLocation());
1796   if (!parseParam(allowParamLiteral, declInputLevel, parm))
1797     return 0;
1798   Vector<StringC> vec;
1799   do {
1800     StringC delim(parm.literalText.string());
1801     const SubstTable<Char> *table = instanceSyntax().generalSubstTable();
1802     for (size_t i = 0; i < delim.size(); i++)
1803       table->subst(delim[i]);
1804     size_t srIndex;
1805     if (!defDtd().shortrefIndex(delim, instanceSyntax(), srIndex)) {
1806       message(ParserMessages::unknownShortrefDelim,
1807               StringMessageArg(prettifyDelim(delim)));
1808       valid = 0;
1809     }
1810     static AllowedParams allowEntityName(Param::entityName);
1811     if (!parseParam(allowEntityName, declInputLevel, parm))
1812       return 0;
1813     if (valid) {
1814       if (srIndex >= vec.size())
1815         vec.resize(srIndex + 1);
1816       if (vec[srIndex].size() > 0) {
1817         message(ParserMessages::delimDuplicateMap,
1818                 StringMessageArg(prettifyDelim(delim)));
1819         valid = 0;
1820       }
1821       else
1822         parm.token.swap(vec[srIndex]);
1823     }
1824     static AllowedParams allowParamLiteralMdc(Param::paramLiteral, Param::mdc);
1825     if (!parseParam(allowParamLiteralMdc, declInputLevel, parm))
1826       return 0;
1827   } while (parm.type != Param::mdc);
1828   if (valid) {
1829     map->setNameMap(vec);
1830     if (currentMarkup())
1831       eventHandler().shortrefDecl(new (eventAllocator())
1832                                   ShortrefDeclEvent(map,
1833                                                     currentDtdPointer(),
1834                                                     markupLocation(),
1835                                                     currentMarkup()));
1836   }
1837   return 1;
1838 }
1839
1840 StringC Parser::prettifyDelim(const StringC &delim)
1841 {
1842   StringC prettyDelim;
1843   for (size_t i = 0; i < delim.size(); i++) {
1844     const StringC *nameP;
1845     if (syntax().charFunctionName(delim[i], nameP)) {
1846       prettyDelim += syntax().delimGeneral(Syntax::dCRO);
1847       prettyDelim += *nameP;
1848       prettyDelim += syntax().delimGeneral(Syntax::dREFC);
1849     }
1850     else
1851       prettyDelim += delim[i];
1852   }
1853   return prettyDelim;
1854 }
1855
1856 ShortReferenceMap *Parser::lookupCreateMap(const StringC &name)
1857 {
1858   ShortReferenceMap *map = defDtd().lookupShortReferenceMap(name);
1859   if (!map) {
1860     map = new ShortReferenceMap(name);
1861     defDtd().insertShortReferenceMap(map);
1862   }
1863   return map;
1864 }
1865
1866 Boolean Parser::parseUsemapDecl()
1867 {
1868   if (!inInstance() && !defDtd().isBase())
1869     message(ParserMessages::usemapOnlyInBaseDtd);
1870
1871   unsigned declInputLevel = inputLevel();
1872   Param parm;
1873   static AllowedParams
1874     allowNameEmpty(Param::name,
1875                    Param::indicatedReservedName + Syntax::rEMPTY);
1876   if (!parseParam(allowNameEmpty, declInputLevel, parm))
1877     return 0;
1878   const ShortReferenceMap *map;
1879   if (parm.type == Param::name) {
1880     if (inInstance()) {
1881       map = currentDtd().lookupShortReferenceMap(parm.token);
1882       if (!map)
1883         message(ParserMessages::undefinedShortrefMapInstance,
1884                 StringMessageArg(parm.token));
1885     }
1886     else {
1887       ShortReferenceMap *tem = lookupCreateMap(parm.token);
1888       tem->setUsed();
1889       map = tem;
1890     }
1891   }
1892   else
1893     map = &theEmptyMap;
1894   static AllowedParams
1895     allowNameNameGroupMdc(Param::name, Param::nameGroup, Param::mdc);
1896   if (!parseParam(allowNameNameGroupMdc, declInputLevel, parm))
1897     return 0;
1898   if (parm.type != Param::mdc) {
1899     if (inInstance()) {
1900       message(ParserMessages::usemapAssociatedElementTypeInstance);
1901       if (!parseParam(allowMdc, declInputLevel, parm))
1902         return 0;
1903     }
1904     else {
1905       Vector<const ElementType *> v;
1906       if (parm.type == Param::name) {
1907         ElementType *e = lookupCreateElement(parm.token);
1908         v.push_back(e);
1909         if (!e->map())
1910           e->setMap(map);
1911       }
1912       else {
1913         v.resize(parm.nameTokenVector.size());
1914         for (size_t i = 0; i < parm.nameTokenVector.size(); i++) {
1915           ElementType *e
1916             = lookupCreateElement(parm.nameTokenVector[i].name);
1917           v[i] = e;
1918           if (!e->map())
1919             e->setMap(map);
1920         }
1921       }
1922       if (!parseParam(allowMdc, declInputLevel, parm))
1923         return 0;
1924       if (currentMarkup())
1925         eventHandler().usemap(new (eventAllocator())
1926                               UsemapEvent(map, v,
1927                                           currentDtdPointer(),
1928                                           markupLocation(),
1929                                           currentMarkup()));
1930     }
1931   }
1932   else {
1933     if (!inInstance())
1934       message(ParserMessages::usemapAssociatedElementTypeDtd);
1935     else if (map) {
1936       if (map != &theEmptyMap && !map->defined())
1937         message(ParserMessages::undefinedShortrefMapInstance,
1938                 StringMessageArg(map->name()));
1939       else {
1940         if (currentMarkup()) {
1941           Vector<const ElementType *> v;
1942           eventHandler().usemap(new (eventAllocator())
1943                                 UsemapEvent(map, v,
1944                                             currentDtdPointer(),
1945                                             markupLocation(),
1946                                             currentMarkup()));
1947         }
1948         currentElement().setMap(map);
1949       }
1950     }
1951   }
1952   return 1;
1953 }
1954
1955 Boolean Parser::parseDoctypeDeclStart()
1956 {
1957   if (hadDtd() && !sd().concur() && !sd().explicitLink())
1958     message(ParserMessages::multipleDtds);
1959   if (hadLpd())
1960     message(ParserMessages::dtdAfterLpd);
1961   unsigned declInputLevel = inputLevel();
1962   Param parm;
1963   
1964   if (!parseParam(allowName, declInputLevel, parm))
1965     return 0;
1966   StringC name;
1967   parm.token.swap(name);
1968   if (!lookupDtd(name).isNull())
1969     message(ParserMessages::duplicateDtd, StringMessageArg(name));
1970   static AllowedParams
1971     allowPublicSystemDsoMdc(Param::reservedName + Syntax::rPUBLIC,
1972                             Param::reservedName + Syntax::rSYSTEM,
1973                             Param::dso,
1974                             Param::mdc);
1975   if (!parseParam(allowPublicSystemDsoMdc, declInputLevel, parm))
1976     return 0;
1977   ConstPtr<Entity> entity;
1978   if (parm.type == Param::reservedName + Syntax::rPUBLIC
1979       || parm.type == Param::reservedName + Syntax::rSYSTEM) {
1980     static AllowedParams allowSystemIdentifierDsoMdc(Param::systemIdentifier,
1981                                                      Param::dso, Param::mdc);
1982     ExternalId id;
1983     if (!parseExternalId(allowSystemIdentifierDsoMdc, allowDsoMdc,
1984                          declInputLevel, parm, id))
1985       return 0;
1986     Ptr<Entity> tem
1987       = new ExternalTextEntity(name, Entity::doctype, markupLocation(), id);
1988     tem->generateSystemId(*this);
1989     entity = tem;
1990 #if 0
1991     eventHandler()
1992       .externalEntityDecl(new (eventAllocator())
1993                           ExternalEntityDeclEvent(entity, 0));
1994 #endif
1995   }
1996   else if (parm.type == Param::mdc) {
1997     message(ParserMessages::noDtdSubset, StringMessageArg(name));
1998     return 1;
1999   }
2000   // Discard mdc or dso
2001   if (currentMarkup())
2002     currentMarkup()->resize(currentMarkup()->size() - 1);
2003   eventHandler().startDtd(new (eventAllocator())
2004                           StartDtdEvent(name, entity, parm.type == Param::dso,
2005                                         markupLocation(),
2006                                         currentMarkup()));
2007   startDtd(name);
2008   if (parm.type == Param::mdc) {
2009     // unget the mdc
2010     currentInput()->ungetToken();
2011     // reference the entity
2012     Ptr<EntityOrigin> origin
2013       = new (internalAllocator()) EntityOrigin(entity, currentLocation());
2014     entity->dsReference(*this, origin);
2015     if (inputLevel() == 1) {    // reference failed
2016       (void)parseDoctypeDeclEnd();
2017       return 1;
2018     }
2019   }
2020   else if (!entity.isNull())
2021     setDsEntity(entity);
2022   setPhase(declSubsetPhase);
2023   return 1;
2024 }
2025
2026 Boolean Parser::implyDtd(const StringC &gi)
2027 {
2028   ExternalId id;
2029   // The null location indicates that this is a fake entity.
2030   ConstPtr<Entity> entity(new ExternalTextEntity(gi,
2031                                                  Entity::doctype,
2032                                                  Location(),
2033                                                  id));
2034   // Don't use Entity::generateSystemId because we don't want an error
2035   // if it fails.
2036   StringC str;
2037   StringC name;
2038   if (!entityCatalog().lookup(*entity, syntax(), sd().docCharset(),
2039                               messenger(), str)) {
2040     if (!entityCatalog().defaultDoctype(sd().docCharset(),
2041                                         messenger(),
2042                                         name,
2043                                         str))
2044       return 0;
2045     for (size_t i = 0; i < name.size(); i++)
2046       syntax().generalSubstTable()->subst(name[i]);
2047   }
2048   else
2049     name = gi;
2050   id.setEffectiveSystem(str);
2051   entity = new ExternalTextEntity(name,
2052                                   Entity::doctype,
2053                                   Location(),
2054                                   id);
2055   StringC declStr;
2056   declStr += syntax().delimGeneral(Syntax::dMDO);
2057   declStr += syntax().reservedName(Syntax::rDOCTYPE);
2058   declStr += syntax().space();
2059   declStr += name;
2060   declStr += syntax().space();
2061   declStr += syntax().reservedName(Syntax::rSYSTEM);
2062   declStr += syntax().delimGeneral(Syntax::dMDC);
2063   message(ParserMessages::implyingDtd, StringMessageArg(declStr));
2064   Ptr<EntityOrigin> origin
2065     = new (internalAllocator()) EntityOrigin(entity, currentLocation());
2066   startMarkup(eventsWanted().wantPrologMarkup(), Location());
2067   if (currentMarkup()) {
2068     currentMarkup()->addDelim(Syntax::dMDO);
2069     currentMarkup()->addReservedName(Syntax::rDOCTYPE,
2070                                      syntax().reservedName(Syntax::rDOCTYPE));
2071     currentMarkup()->addS(syntax().space());
2072     currentMarkup()->addName(name.data(), name.size());
2073     currentMarkup()->addS(syntax().space());
2074     currentMarkup()->addReservedName(Syntax::rSYSTEM,
2075                                      syntax().reservedName(Syntax::rSYSTEM));
2076   }
2077   eventHandler().startDtd(new (eventAllocator())
2078                           StartDtdEvent(name, entity, 0,
2079                                         markupLocation(),
2080                                         currentMarkup()));
2081   startDtd(name);
2082   entity->dsReference(*this, origin);
2083   if (inputLevel() == 1) {
2084     parseDoctypeDeclEnd(1);
2085     return 1;
2086   }
2087   setPhase(declSubsetPhase);
2088   return 1;
2089 }
2090
2091 Boolean Parser::parseDoctypeDeclEnd(Boolean fake)
2092 {
2093   checkDtd(defDtd());
2094   Ptr<Dtd> tem(defDtdPointer());
2095   endDtd();
2096   if (fake) {
2097     startMarkup(eventsWanted().wantPrologMarkup(), Location());
2098     if (currentMarkup())
2099       currentMarkup()->addDelim(Syntax::dMDC);
2100   }
2101   else {
2102     startMarkup(eventsWanted().wantPrologMarkup(), currentLocation());
2103     Param parm;
2104     // End DTD before parsing final param so parameter entity reference
2105     // not allowed between ] and >.
2106     if (!parseParam(allowMdc, inputLevel(), parm))
2107       return 0;
2108   }
2109   eventHandler().endDtd(new (eventAllocator()) EndDtdEvent(tem,
2110                                                            markupLocation(),
2111                                                            currentMarkup()));
2112   if (fake) {
2113     Char c = syntax().standardFunction(Syntax::fRE);
2114     eventHandler().sSep(new (eventAllocator())
2115                         SSepEvent(&c, 1, Location(), 1));
2116   }
2117   return 1;
2118 }
2119
2120 void Parser::checkDtd(Dtd &dtd)
2121 {
2122   if (dtd.isBase())
2123     addNeededShortrefs(dtd, instanceSyntax());
2124   if (!options().errorAfdr)
2125     addCommonAttributes(dtd);
2126   Dtd::ElementTypeIter elementIter(dtd.elementTypeIter());
2127   ElementType *p;
2128   ConstPtr<ElementDefinition> def;
2129   int i = 0;
2130   while ((p = elementIter.next()) != 0) {
2131     if (p->definition() == 0) {
2132       if (p->name() == dtd.name())
2133         message(ParserMessages::documentElementUndefined);
2134       else if (options().warnUndefinedElement)
2135         message(ParserMessages::dtdUndefinedElement, StringMessageArg(p->name()));
2136       if (def.isNull())
2137         def = new ElementDefinition(currentLocation(),
2138                                     ElementDefinition::undefinedIndex,
2139                                     (ElementDefinition::omitStart
2140                                      |ElementDefinition::omitEnd),
2141                                     ElementDefinition::any);
2142       p->setElementDefinition(def, i++);
2143     }
2144     const ShortReferenceMap *map = p->map();
2145     if (map != 0 && map != &theEmptyMap && !map->defined()) {
2146       message(ParserMessages::undefinedShortrefMapDtd,
2147               StringMessageArg(map->name()),
2148               StringMessageArg(p->name()));
2149       p->setMap(0);
2150     }
2151   }
2152   Dtd::ConstEntityIter entityIter(((const Dtd &)dtd).generalEntityIter());
2153   for (;;) {
2154     ConstPtr<Entity> entity(entityIter.next());
2155     if (entity.isNull())
2156       break;
2157     const ExternalDataEntity *external = entity->asExternalDataEntity();
2158     if (external) {
2159       const Notation *notation = external->notation();
2160       if (!notation->defined()) {
2161         setNextLocation(external->defLocation());
2162         message(ParserMessages::entityNotationUndefined,
2163                 StringMessageArg(notation->name()),
2164                 StringMessageArg(external->name()));
2165       }
2166     }
2167   }
2168   Dtd::NotationIter notationIter(dtd.notationIter());
2169   for (;;) {
2170     ConstPtr<Notation> notation(notationIter.next());
2171     if (notation.isNull())
2172       break;
2173     if (!notation->defined() && !notation->attributeDef().isNull())
2174       message(ParserMessages::attlistNotationUndefined,
2175               StringMessageArg(notation->name()));
2176   }
2177   Dtd::ShortReferenceMapIter mapIter(dtd.shortReferenceMapIter());
2178   int nShortref = dtd.nShortref();
2179   for (;;) {
2180     ShortReferenceMap *map = mapIter.next();
2181     if (!map)
2182       break;
2183     Vector<ConstPtr<Entity> > entityMap(nShortref);
2184     for (i = 0; i < nShortref; i++) {
2185       const StringC *entityName = map->entityName(i);
2186       if (entityName) {
2187         ConstPtr<Entity> entity
2188           = lookupEntity(0, *entityName, map->defLocation(), 0);
2189         if (entity.isNull()) {
2190           setNextLocation(map->defLocation());
2191           message(ParserMessages::mapEntityUndefined,
2192                   StringMessageArg(*entityName),
2193                   StringMessageArg(map->name()));
2194         }
2195         else {
2196           if (entity->defaulted() && options().warnDefaultEntityReference) {
2197             setNextLocation(map->defLocation());
2198             message(ParserMessages::mapDefaultEntity,
2199                     StringMessageArg(*entityName),
2200                     StringMessageArg(map->name()));
2201           }
2202           entityMap[i] = entity;
2203         }
2204       }
2205     }
2206     map->setEntityMap(entityMap);
2207     if (options().warnUnusedMap && !map->used()) {
2208       setNextLocation(map->defLocation());
2209       message(ParserMessages::unusedMap, StringMessageArg(map->name()));
2210     }
2211   }
2212   if (options().warnUnusedParam) {
2213     Dtd::ConstEntityIter entityIter(((const Dtd &)dtd).parameterEntityIter());
2214     for (;;) {
2215       ConstPtr<Entity> entity(entityIter.next());
2216       if (entity.isNull())
2217         break;
2218       if (!entity->used() && !maybeStatusKeyword(*entity)) {
2219         setNextLocation(entity->defLocation());
2220         message(ParserMessages::unusedParamEntity,
2221                 StringMessageArg(entity->name()));
2222       }
2223     }
2224   }
2225 }
2226
2227 void Parser::addCommonAttributes(Dtd &dtd)
2228 {
2229   Ptr<AttributeDefinitionList> commonAdl[2];
2230   {
2231     ElementType *e = dtd.removeElementType(syntax()
2232                                            .rniReservedName(Syntax::rANY));
2233     if (e) {
2234       commonAdl[0] = e->attributeDef();
2235       delete e;
2236     }
2237   }
2238   {
2239     Ptr<Notation> allNotation
2240       = dtd.removeNotation(syntax().rniReservedName(Syntax::rANY));
2241     if (!allNotation.isNull())
2242       commonAdl[1] = allNotation->attributeDef();
2243   }
2244   Dtd::ElementTypeIter elementIter(dtd.elementTypeIter());
2245   Dtd::NotationIter notationIter(dtd.notationIter());
2246   Vector<PackedBoolean> doneAdl(dtd.nAttributeDefinitionList(),
2247                                 PackedBoolean(0));
2248   for (int isNotation = 0; isNotation < 2; isNotation++) {
2249     if (!commonAdl[isNotation].isNull()) {
2250       doneAdl[commonAdl[isNotation]->index()] = 1;
2251       for (;;) {
2252         Attributed *a;
2253         if (!isNotation)
2254           a = elementIter.next();
2255         else
2256           a = notationIter.next().pointer();
2257         if (!a)
2258           break;
2259         Ptr<AttributeDefinitionList> adl = a->attributeDef();
2260         if (adl.isNull())
2261           a->setAttributeDef(commonAdl[isNotation]);
2262         else if (!doneAdl[adl->index()]) {
2263           doneAdl[adl->index()] = 1;
2264           for (size_t j = 0; j < commonAdl[isNotation]->size(); j++) {
2265             unsigned tem;
2266             if (!adl->attributeIndex(commonAdl[isNotation]->def(j)->name(),
2267                                      tem))
2268               adl->append(commonAdl[isNotation]->def(j)->copy());
2269           }
2270         }
2271       }
2272     }
2273   }
2274 }
2275
2276 Boolean Parser::maybeStatusKeyword(const Entity &entity)
2277 {
2278   const InternalEntity *internal = entity.asInternalEntity();
2279   if (!internal)
2280     return 0;
2281   const StringC &text = internal->string();
2282   static const Syntax::ReservedName statusKeywords[] = {
2283     Syntax::rINCLUDE, Syntax::rIGNORE
2284     };
2285   for (size_t i = 0; i < SIZEOF(statusKeywords); i++) {
2286     const StringC &keyword = instanceSyntax().reservedName(statusKeywords[i]);
2287     size_t j = 0;
2288     while (j < text.size() && instanceSyntax().isS(text[j]))
2289       j++;
2290     size_t k = 0;
2291     while (j < text.size()
2292            && k < keyword.size()
2293            && ((*instanceSyntax().generalSubstTable())[text[j]]
2294                == keyword[k]))
2295       j++, k++;
2296     if (k == keyword.size()) {
2297       while (j < text.size() && instanceSyntax().isS(text[j]))
2298         j++;
2299       if (j == text.size())
2300         return 1;
2301     }
2302   }
2303   return 0;
2304 }
2305
2306 Boolean Parser::parseLinktypeDeclStart()
2307 {
2308   if (baseDtd().isNull())
2309     message(ParserMessages::lpdBeforeBaseDtd);
2310   unsigned declInputLevel = inputLevel();
2311   Param parm;
2312   
2313   if (!parseParam(allowName, declInputLevel, parm))
2314     return 0;
2315   StringC name;
2316   parm.token.swap(name);
2317   if (!lookupDtd(name).isNull())
2318     message(ParserMessages::duplicateDtdLpd, StringMessageArg(name));
2319   else if (!lookupLpd(name).isNull())
2320     message(ParserMessages::duplicateLpd, StringMessageArg(name));
2321   static AllowedParams
2322     allowSimpleName(Param::indicatedReservedName + Syntax::rSIMPLE,
2323                     Param::name);
2324   if (!parseParam(allowSimpleName, declInputLevel, parm))
2325     return 0;
2326   Boolean simple;
2327   Ptr<Dtd> sourceDtd;
2328   if (parm.type == Param::indicatedReservedName + Syntax::rSIMPLE) {
2329     simple = 1;
2330     sourceDtd = baseDtd();
2331     if (sourceDtd.isNull())
2332       sourceDtd = new Dtd(StringC(), 1);
2333   }
2334   else {
2335     simple = 0;
2336     sourceDtd = lookupDtd(parm.token);
2337     if (sourceDtd.isNull()) {
2338       message(ParserMessages::noSuchDtd, StringMessageArg(parm.token));
2339       sourceDtd = new Dtd(parm.token, 0);
2340     }
2341   }
2342   static AllowedParams
2343     allowImpliedName(Param::indicatedReservedName + Syntax::rIMPLIED,
2344                      Param::name);
2345   if (!parseParam(allowImpliedName, declInputLevel, parm))
2346     return 0;
2347   Ptr<Dtd> resultDtd;
2348   Boolean implied = 0;
2349   if (parm.type == Param::indicatedReservedName + Syntax::rIMPLIED) {
2350     if (simple) {
2351       if (!sd().simpleLink())
2352         message(ParserMessages::simpleLinkFeature);
2353     }
2354     else {
2355       implied = 1;
2356       if (!sd().implicitLink())
2357         message(ParserMessages::implicitLinkFeature);
2358     }
2359   }
2360   else {
2361     if (simple)
2362       message(ParserMessages::simpleLinkResultNotImplied);
2363     else {
2364       if (!sd().explicitLink())
2365         message(ParserMessages::explicitLinkFeature);
2366       resultDtd = lookupDtd(parm.token);
2367       if (resultDtd.isNull())
2368         message(ParserMessages::noSuchDtd, StringMessageArg(parm.token));
2369     }
2370   }
2371   static AllowedParams
2372     allowPublicSystemDsoMdc(Param::reservedName + Syntax::rPUBLIC,
2373                             Param::reservedName + Syntax::rSYSTEM,
2374                             Param::dso,
2375                             Param::mdc);
2376   if (!parseParam(allowPublicSystemDsoMdc, declInputLevel, parm))
2377     return 0;
2378   ConstPtr<Entity> entity;
2379   if (parm.type == Param::reservedName + Syntax::rPUBLIC
2380       || parm.type == Param::reservedName + Syntax::rSYSTEM) {
2381     static AllowedParams allowSystemIdentifierDsoMdc(Param::systemIdentifier,
2382                                                      Param::dso, Param::mdc);
2383     ExternalId id;
2384     if (!parseExternalId(allowSystemIdentifierDsoMdc, allowDsoMdc,
2385                          declInputLevel, parm, id))
2386       return 0;
2387     Ptr<Entity> tem
2388       = new ExternalTextEntity(name, Entity::linktype, markupLocation(), id);
2389     tem->generateSystemId(*this);
2390     entity = tem;
2391 #if 0
2392     eventHandler()
2393       .externalEntityDecl(new (eventAllocator())
2394                           ExternalEntityDeclEvent(entity, 0));
2395 #endif
2396   }
2397   Ptr<Lpd> lpd;
2398   if (simple)
2399     lpd = new SimpleLpd(name, markupLocation(), sourceDtd);
2400   else
2401     lpd = new ComplexLpd(name,
2402                          implied ? Lpd::implicitLink : Lpd::explicitLink,
2403                          markupLocation(),
2404                          syntax(),
2405                          sourceDtd,
2406                          resultDtd);
2407   if (!baseDtd().isNull() && shouldActivateLink(name)) {
2408     size_t nActive = nActiveLink();
2409     if (simple) {
2410       size_t nSimple = 0;
2411       for (size_t i = 0; i < nActive; i++)
2412         if (activeLpd(i).type() == Lpd::simpleLink)
2413           nSimple++;
2414       if (nSimple == sd().simpleLink())
2415         message(ParserMessages::simpleLinkCount,
2416                 NumberMessageArg(sd().simpleLink()));
2417       lpd->activate();
2418     }
2419     else {
2420       Boolean haveImplicit = 0;
2421       Boolean haveExplicit = 0;
2422       size_t i;
2423       for (i = 0; i < nActive; i++) {
2424         if (activeLpd(i).type() == Lpd::implicitLink)
2425           haveImplicit = 1;
2426         else if (activeLpd(i).type() == Lpd::explicitLink)
2427           haveExplicit = 1;
2428       }
2429       const Dtd *sourceDtd = lpd->sourceDtd().pointer();
2430       if (implied && haveImplicit)
2431         message(ParserMessages::oneImplicitLink);
2432       else if (sd().explicitLink() <= 1 && sourceDtd != baseDtd().pointer())
2433         message(sd().explicitLink() == 0
2434                 ? ParserMessages::explicitNoRequiresSourceTypeBase
2435                 : ParserMessages::explicit1RequiresSourceTypeBase,
2436                 StringMessageArg(lpd->name()));
2437       else if (sd().explicitLink() == 1 && haveExplicit && !implied)
2438         message(ParserMessages::duplicateExplicitChain);
2439       else if (haveExplicit || haveImplicit
2440                || sourceDtd != baseDtd().pointer())
2441         message(ParserMessages::sorryLink, StringMessageArg(lpd->name()));
2442       else
2443         lpd->activate();
2444     }
2445   }
2446   // Discard mdc or dso
2447   if (currentMarkup())
2448     currentMarkup()->resize(currentMarkup()->size() - 1);
2449   eventHandler().startLpd(new (eventAllocator())
2450                           StartLpdEvent(lpd->active(),
2451                                         name,
2452                                         entity,
2453                                         parm.type == Param::dso,
2454                                         markupLocation(),
2455                                         currentMarkup()));
2456   startLpd(lpd);
2457   if (parm.type == Param::mdc) {
2458     // unget the mdc
2459     currentInput()->ungetToken();
2460     if (entity.isNull()) {
2461       message(ParserMessages::noLpdSubset, StringMessageArg(name));
2462       (void)parseLinktypeDeclEnd();
2463       return 1;
2464     }
2465     // reference the entity
2466     Ptr<EntityOrigin> origin
2467       = new (internalAllocator()) EntityOrigin(entity, currentLocation());
2468     entity->dsReference(*this, origin);
2469     if (inputLevel() == 1) {    // reference failed
2470       (void)parseLinktypeDeclEnd();
2471       return 1;
2472     }
2473   }
2474   else if (!entity.isNull())
2475     setDsEntity(entity);
2476   setPhase(declSubsetPhase);
2477   return 1;
2478 }
2479
2480 Boolean Parser::parseLinktypeDeclEnd()
2481 {
2482
2483   if (defLpd().type() != Lpd::simpleLink) {
2484     if (!defComplexLpd().initialLinkSet()->defined())
2485       message(ParserMessages::noInitialLinkSet,
2486               StringMessageArg(defLpd().name()));
2487     ComplexLpd::ConstLinkSetIter iter = defComplexLpd().linkSetIter();
2488     const LinkSet *linkSet;
2489     while ((linkSet = iter.next()) != 0)
2490       if (!linkSet->defined())
2491         message(ParserMessages::undefinedLinkSet, StringMessageArg(linkSet->name()));
2492   }
2493   ConstPtr<Lpd> tem(defLpdPointer());
2494   endLpd();
2495   startMarkup(eventsWanted().wantPrologMarkup(), currentLocation());
2496   Param parm;
2497   Boolean result = parseParam(allowMdc, inputLevel(), parm);
2498   eventHandler().endLpd(new (eventAllocator()) EndLpdEvent(tem,
2499                                                            markupLocation(),
2500                                                            currentMarkup()));
2501   return result;
2502 }
2503
2504 Boolean Parser::parseLinkDecl()
2505 {
2506   return parseLinkSet(0);
2507 }
2508
2509 Boolean Parser::parseIdlinkDecl()
2510 {
2511   return parseLinkSet(1);
2512 }
2513
2514 // This will only get called if we're defining a complex lpd.
2515
2516 Boolean Parser::parseLinkSet(Boolean idlink)
2517 {
2518   if (defLpd().type() == Lpd::simpleLink) {
2519     message(idlink ? ParserMessages::idlinkDeclSimple : ParserMessages::linkDeclSimple);
2520     return 0;
2521   }
2522   if (idlink) {
2523     if (defComplexLpd().hadIdLinkSet())
2524       message(ParserMessages::duplicateIdLinkSet);
2525     else
2526       defComplexLpd().setHadIdLinkSet();
2527   }
2528   unsigned declInputLevel = inputLevel();
2529   Param parm;
2530   
2531   Boolean isExplicit = (defLpd().type() == Lpd::explicitLink);
2532   LinkSet *linkSet;
2533   if (idlink) {
2534     if (!parseParam(allowName, declInputLevel, parm))
2535       return 0;
2536     linkSet = 0;
2537   }
2538   else {
2539     static AllowedParams
2540       allowNameInitial(Param::name,
2541                        Param::indicatedReservedName + Syntax::rINITIAL);
2542     if (!parseParam(allowNameInitial, declInputLevel, parm))
2543       return 0;
2544     if (parm.type == Param::name)
2545       linkSet = lookupCreateLinkSet(parm.token);
2546     else
2547       linkSet = defComplexLpd().initialLinkSet();
2548     if (linkSet->defined())
2549       message(ParserMessages::duplicateLinkSet, StringMessageArg(linkSet->name()));
2550     static AllowedParams
2551       allowExplicitLinkRule(Param::name,
2552                             Param::nameGroup,
2553                             Param::indicatedReservedName + Syntax::rIMPLIED);
2554     if (!parseParam(isExplicit ? allowExplicitLinkRule : allowNameNameGroup,
2555                     declInputLevel, parm))
2556       return 0;
2557   }
2558
2559   do {
2560     StringC id;
2561     if (idlink) {
2562       parm.token.swap(id);
2563       if (!parseParam(isExplicit ? allowExplicitLinkRuleMdc : allowNameNameGroupMdc,
2564                       declInputLevel, parm))
2565         return 0;
2566     }
2567     if (parm.type == Param::indicatedReservedName + Syntax::rIMPLIED) {
2568       if (!parseParam(allowName, declInputLevel, parm))
2569         return 0;
2570       Boolean resultImplied;
2571       const ElementType *resultType;
2572       AttributeList resultAttributes;
2573       if (!parseResultElementSpec(declInputLevel,
2574                                   parm,
2575                                   idlink,
2576                                   resultImplied,
2577                                   resultType,
2578                                   resultAttributes))
2579         return 0;
2580       if (resultType) {
2581         const AttributeList *dummy;
2582         if (linkSet->impliedResultAttributes(resultType, dummy))
2583           message(ParserMessages::duplicateImpliedResult,
2584                   StringMessageArg(resultType->name()));
2585         else
2586           linkSet->addImplied(resultType, resultAttributes);
2587       }
2588     }
2589     else {
2590       SourceLinkRule *linkRule = 0;
2591       IdLinkRule idLinkRule;
2592       Ptr<SourceLinkRuleResource> linkRuleResource;
2593       if (idlink)
2594         linkRule = &idLinkRule;
2595       else {
2596         linkRuleResource = new SourceLinkRuleResource;
2597         linkRule = linkRuleResource.pointer();
2598       }
2599       Vector<const ElementType *> assocElementTypes;
2600       if (parm.type == Param::name) {
2601         assocElementTypes.resize(1);
2602         assocElementTypes[0] = lookupCreateElement(parm.token);
2603       }
2604       else {
2605         assocElementTypes.resize(parm.nameTokenVector.size());
2606         for (size_t i = 0; i < assocElementTypes.size(); i++)
2607           assocElementTypes[i]
2608             = lookupCreateElement(parm.nameTokenVector[i].name);
2609       }
2610       static AllowedParams
2611         allow2i(Param::indicatedReservedName + Syntax::rUSELINK,
2612                 Param::indicatedReservedName + Syntax::rPOSTLINK,
2613                 Param::dso,
2614                 Param::mdc,
2615                 Param::name,
2616                 Param::nameGroup);
2617       static AllowedParams
2618         allow2id(Param::indicatedReservedName + Syntax::rUSELINK,
2619                  Param::indicatedReservedName + Syntax::rPOSTLINK,
2620                  Param::dso,
2621                  Param::mdc,
2622                  Param::name);
2623       static AllowedParams
2624         allow2e(Param::indicatedReservedName + Syntax::rUSELINK,
2625                 Param::indicatedReservedName + Syntax::rPOSTLINK,
2626                 Param::dso,
2627                 Param::name,
2628                 Param::indicatedReservedName + Syntax::rIMPLIED);
2629
2630       if (!parseParam(isExplicit
2631                       ? allow2e
2632                       : (idlink ? allow2id : allow2i), declInputLevel, parm))
2633         return 0;
2634       if (parm.type == Param::indicatedReservedName + Syntax::rUSELINK) {
2635         static AllowedParams
2636           allowLinkSetEmpty(Param::name,
2637                             Param::indicatedReservedName + Syntax::rINITIAL,
2638                             Param::indicatedReservedName + Syntax::rEMPTY);
2639         if (!parseParam(allowLinkSetEmpty, declInputLevel, parm))
2640           return 0;
2641         const LinkSet *uselink;
2642         if (parm.type == Param::name)
2643           uselink = lookupCreateLinkSet(parm.token);
2644         else if (parm.type == Param::indicatedReservedName + Syntax::rINITIAL)
2645           uselink = defComplexLpd().initialLinkSet();
2646         else
2647           uselink = defComplexLpd().emptyLinkSet();
2648         linkRule->setUselink(uselink);
2649         static AllowedParams
2650           allow3i(Param::indicatedReservedName + Syntax::rPOSTLINK,
2651                   Param::dso,
2652                   Param::mdc,
2653                   Param::name,
2654                   Param::nameGroup);
2655         static AllowedParams
2656           allow3id(Param::indicatedReservedName + Syntax::rPOSTLINK,
2657                    Param::dso,
2658                    Param::mdc,
2659                    Param::name);
2660         static AllowedParams
2661           allow3e(Param::indicatedReservedName + Syntax::rPOSTLINK,
2662                   Param::dso,
2663                   Param::name,
2664                   Param::indicatedReservedName + Syntax::rIMPLIED);
2665         
2666         if (!parseParam(isExplicit
2667                         ? allow3e
2668                         : (idlink ? allow3id : allow3i),
2669                         declInputLevel, parm))
2670           return 0;
2671       }
2672       if (parm.type == Param::indicatedReservedName + Syntax::rPOSTLINK) {
2673         if (!parseParam(allowLinkSetSpec, declInputLevel, parm))
2674           return 0;
2675         const LinkSet *postlink;
2676         if (parm.type == Param::indicatedReservedName + Syntax::rRESTORE)
2677           linkRule->setPostlinkRestore();
2678         else {
2679           if (parm.type == Param::name)
2680             postlink = lookupCreateLinkSet(parm.token);
2681           else if (parm.type
2682                    == Param::indicatedReservedName + Syntax::rINITIAL)
2683             postlink = defComplexLpd().initialLinkSet();
2684           else
2685             postlink = defComplexLpd().emptyLinkSet();
2686           linkRule->setPostlink(postlink);
2687         }
2688         static AllowedParams
2689           allow4i(Param::dso,
2690                   Param::mdc,
2691                   Param::name,
2692                   Param::nameGroup);
2693         static AllowedParams
2694           allow4id(Param::dso,
2695                    Param::mdc,
2696                    Param::name);
2697         static AllowedParams
2698           allow4e(Param::dso,
2699                   Param::name,
2700                   Param::indicatedReservedName + Syntax::rIMPLIED);
2701         if (!parseParam(isExplicit
2702                         ? allow4e
2703                         : (idlink ? allow4id : allow4i),
2704                         declInputLevel, parm))
2705           return 0;
2706       }
2707       AttributeList attributes;
2708       ConstPtr<AttributeDefinitionList> attDef;
2709       for (size_t i = 0; i < assocElementTypes.size(); i++) {
2710         const ElementType *e = assocElementTypes[i];
2711         if (e) {
2712           if (i == 0)
2713             attDef = defComplexLpd().attributeDef(e);
2714           else if (attDef != defComplexLpd().attributeDef(e))
2715             message(ParserMessages::assocElementDifferentAtts);
2716           // FIXME recover from this
2717         }
2718       }
2719       attributes.init(attDef);
2720       
2721       if (parm.type == Param::dso) {
2722         Boolean netEnabling;
2723         if (!parseAttributeSpec(1, attributes, netEnabling))
2724           return 0;
2725         static AllowedParams
2726           allow5e(Param::name,
2727                   Param::indicatedReservedName + Syntax::rIMPLIED);
2728         if (!parseParam(isExplicit
2729                         ? allow5e
2730                         : (idlink ? allowNameMdc : allowNameNameGroupMdc),
2731                         declInputLevel, parm))
2732           return 0;
2733       }
2734       else
2735         attributes.finish(*this);
2736       linkRule->setLinkAttributes(attributes);
2737       if (isExplicit) {
2738         Boolean resultImplied;
2739         const ElementType *resultType;
2740         AttributeList resultAttributes;
2741         if (!parseResultElementSpec(declInputLevel,
2742                                     parm,
2743                                     idlink,
2744                                     resultImplied,
2745                                     resultType,
2746                                     resultAttributes))
2747           return 0;
2748         if (!resultImplied)
2749           linkRule->setResult(resultType, resultAttributes);
2750       }
2751       // Install the link rule.
2752       if (idlink) {
2753         idLinkRule.setAssocElementTypes(assocElementTypes);
2754         addIdLinkRule(id, idLinkRule);
2755       }
2756       else {
2757         if (!linkSet->defined()) {
2758           for (size_t i = 0; i < assocElementTypes.size(); i++)
2759             if (assocElementTypes[i])
2760               addLinkRule(linkSet, assocElementTypes[i], linkRuleResource);
2761         }
2762       }
2763     }
2764   } while (parm.type != Param::mdc);
2765   if (linkSet)
2766     linkSet->setDefined();
2767   if (currentMarkup()) {
2768     if (idlink)
2769       eventHandler().idLinkDecl(new (eventAllocator())
2770                                 IdLinkDeclEvent(defComplexLpdPointer(),
2771                                                 markupLocation(),
2772                                                 currentMarkup()));
2773     else
2774       eventHandler().linkDecl(new (eventAllocator())
2775                               LinkDeclEvent(linkSet,
2776                                             defComplexLpdPointer(),
2777                                             markupLocation(),
2778                                             currentMarkup()));
2779   }
2780   return 1;
2781 }
2782
2783 void Parser::addIdLinkRule(const StringC &id,
2784                            IdLinkRule &rule)
2785 {
2786   IdLinkRuleGroup *group = defComplexLpd().lookupCreateIdLink(id);
2787   size_t nRules = group->nLinkRules();
2788   if ((nRules == 1 && group->linkRule(0).attributes().nSpec() == 0)
2789       || nRules >= 1 && rule.attributes().nSpec() == 0)
2790     message(ParserMessages::multipleIdLinkRuleAttribute,
2791             StringMessageArg(id));
2792   group->addLinkRule(rule);
2793 }
2794
2795 void Parser::addLinkRule(LinkSet *linkSet,
2796                          const ElementType *sourceElement,
2797                          const ConstPtr<SourceLinkRuleResource> &linkRule)
2798 {
2799   size_t nRules = linkSet->nLinkRules(sourceElement);
2800   if ((nRules == 1
2801        && linkSet->linkRule(sourceElement, 0).attributes().nSpec() == 0)
2802       || nRules >= 1 && linkRule->attributes().nSpec() == 0)
2803     message(ParserMessages::multipleLinkRuleAttribute,
2804             StringMessageArg(sourceElement->name()));
2805   linkSet->addLinkRule(sourceElement, linkRule);
2806 }
2807
2808 class ResultAttributeSpecModeSetter {
2809 public:
2810   ResultAttributeSpecModeSetter(ParserState *state) : state_(state) {
2811     state_->setResultAttributeSpecMode();
2812   }
2813   ~ResultAttributeSpecModeSetter() { clear(); }
2814   void clear() {
2815     if (state_) {
2816       state_->clearResultAttributeSpecMode();
2817       state_ = 0;
2818     }
2819   }
2820 private:
2821   ParserState *state_;
2822 };
2823
2824 Boolean Parser::parseResultElementSpec(unsigned declInputLevel,
2825                                        Param &parm,
2826                                        Boolean idlink,
2827                                        Boolean &implied,
2828                                        const ElementType *&resultType,
2829                                        AttributeList &attributes)
2830 {
2831   if (parm.type == Param::indicatedReservedName + Syntax::rIMPLIED) {
2832     if (!parseParam(idlink ? allowNameMdc : allowExplicitLinkRuleMdc,
2833                     declInputLevel, parm))
2834       return 0;
2835     implied = 1;
2836   }
2837   else {
2838     implied = 0;
2839     resultType = lookupResultElementType(parm.token);
2840     static AllowedParams
2841       allow(Param::dso,
2842             Param::mdc,
2843             Param::name,
2844             Param::nameGroup,
2845             Param::indicatedReservedName + Syntax::rIMPLIED);
2846     static AllowedParams
2847       allowNameDsoMdc(Param::dso,
2848                       Param::mdc,
2849                       Param::name);
2850     if (!parseParam(idlink ? allowNameDsoMdc : allow,
2851                     declInputLevel, parm))
2852       return 0;
2853     ConstPtr<AttributeDefinitionList> attDef;
2854     if (resultType)
2855       attDef = resultType->attributeDef();
2856     attributes.init(attDef);
2857     if (parm.type == Param::dso) {
2858       ResultAttributeSpecModeSetter modeSetter(this);
2859       Boolean netEnabling;
2860       if (!parseAttributeSpec(1, attributes, netEnabling))
2861         return 0;
2862       modeSetter.clear();
2863       if (attributes.nSpec() == 0)
2864         message(ParserMessages::emptyResultAttributeSpec);
2865       if (!parseParam(idlink ? allowNameMdc : allowExplicitLinkRuleMdc,
2866                       declInputLevel, parm))
2867         return 0;
2868     }
2869     else {
2870       // For entity and notation attributes.
2871       ResultAttributeSpecModeSetter modeSetter(this);
2872       attributes.finish(*this);
2873       modeSetter.clear();
2874     }
2875   }
2876   return 1;
2877 }
2878
2879 const ElementType *Parser::lookupResultElementType(const StringC &name)
2880 {
2881   const Dtd *dtd = defComplexLpd().resultDtd().pointer();
2882   if (!dtd)
2883     return 0;
2884   const ElementType *e = dtd->lookupElementType(name);
2885   if (!e)
2886     message(ParserMessages::noSuchResultElement, StringMessageArg(name));
2887   return e;
2888 }
2889
2890 Boolean Parser::parseUselinkDecl()
2891 {
2892   unsigned declInputLevel = inputLevel();
2893   Param parm;
2894   if (!parseParam(allowLinkSetSpec, declInputLevel, parm))
2895     return 0;
2896   Param parm2;
2897   if (!parseParam(allowName, declInputLevel, parm2))
2898     return 0;
2899   StringC linkType;
2900   parm2.token.swap(linkType);
2901   if (!parseParam(allowMdc, declInputLevel, parm2))
2902     return 0;
2903   ConstPtr<Lpd> lpd = lookupLpd(linkType);
2904   if (lpd.isNull()) 
2905     message(ParserMessages::uselinkBadLinkType, StringMessageArg(linkType));
2906   else if (lpd->type() == Lpd::simpleLink)
2907     message(ParserMessages::uselinkSimpleLpd, StringMessageArg(linkType));
2908   else {
2909     const ComplexLpd *complexLpd = (const ComplexLpd *)lpd.pointer();
2910     const LinkSet *linkSet;
2911     Boolean restore = 0;
2912     if (parm.type == Param::name) {
2913       linkSet = complexLpd->lookupLinkSet(parm.token);
2914       if (!linkSet) {
2915         message(ParserMessages::uselinkBadLinkSet,
2916                 StringMessageArg(complexLpd->name()),
2917                 StringMessageArg(parm.token));
2918         return 1;
2919       }
2920     }
2921     else if (parm.type == Param::indicatedReservedName + Syntax::rINITIAL)
2922       linkSet = complexLpd->initialLinkSet();
2923     else if (parm.type == Param::indicatedReservedName + Syntax::rEMPTY)
2924       linkSet = complexLpd->emptyLinkSet();
2925     else {
2926       linkSet = 0;
2927       restore = 1;
2928     }
2929     if (lpd->active())
2930       eventHandler().uselink(new (eventAllocator())
2931                              UselinkEvent(lpd, linkSet,
2932                                           restore, markupLocation(),
2933                                           currentMarkup()));
2934     else
2935       eventHandler().ignoredMarkup(new (eventAllocator())
2936                                    IgnoredMarkupEvent(markupLocation(),
2937                                                       currentMarkup()));
2938   }
2939   return 1;
2940 }
2941
2942 LinkSet *Parser::lookupCreateLinkSet(const StringC &name)
2943 {
2944   LinkSet *linkSet = defComplexLpd().lookupLinkSet(name);
2945   if (!linkSet) {
2946     linkSet = new LinkSet(name, defComplexLpd().sourceDtd().pointer());
2947     defComplexLpd().insertLinkSet(linkSet);
2948   }
2949   return linkSet;
2950 }
2951
2952 Boolean Parser::parseMarkedSectionDeclStart()
2953 {
2954   if (markedSectionLevel() == syntax().taglvl())
2955     message(ParserMessages::markedSectionLevel,
2956             NumberMessageArg(syntax().taglvl()));
2957   if (markedSectionSpecialLevel() > 0) {
2958     startMarkedSection(markupLocation());
2959     if (inInstance()
2960         ? eventsWanted().wantMarkedSections()
2961         : eventsWanted().wantPrologMarkup())
2962       eventHandler().ignoredChars(new (eventAllocator())
2963                                   IgnoredCharsEvent(currentInput()->currentTokenStart(),
2964                                                     currentInput()->currentTokenLength(),
2965                                                     currentLocation(),
2966                                                     0));
2967                                   
2968     return 1;
2969   }
2970   if (startMarkup(inInstance()
2971                   ? eventsWanted().wantMarkedSections()
2972                   : eventsWanted().wantPrologMarkup(),
2973                   currentLocation())) {
2974     currentMarkup()->addDelim(Syntax::dMDO);
2975     currentMarkup()->addDelim(Syntax::dDSO);
2976   }
2977   unsigned declInputLevel = inputLevel();
2978   static AllowedParams allowStatusDso(Param::dso,
2979                                       Param::reservedName + Syntax::rCDATA,
2980                                       Param::reservedName + Syntax::rRCDATA,
2981                                       Param::reservedName + Syntax::rIGNORE,
2982                                       Param::reservedName + Syntax::rINCLUDE,
2983                                       Param::reservedName + Syntax::rTEMP);
2984   Param parm;
2985   MarkedSectionEvent::Status status = MarkedSectionEvent::include;
2986   for (;;) {
2987     if (!parseParam(allowStatusDso, declInputLevel, parm))
2988       return 0;
2989     if (parm.type == Param::dso)
2990       break;
2991     switch (parm.type) {
2992     case Param::reservedName + Syntax::rCDATA:
2993       if (status < MarkedSectionEvent::cdata)
2994         status = MarkedSectionEvent::cdata;
2995       break;
2996     case Param::reservedName + Syntax::rRCDATA:
2997       if (status < MarkedSectionEvent::rcdata)
2998         status = MarkedSectionEvent::rcdata;
2999       break;
3000     case Param::reservedName + Syntax::rIGNORE:
3001       if (status < MarkedSectionEvent::ignore)
3002         status = MarkedSectionEvent::ignore;
3003       break;
3004     }
3005   }
3006   // FIXME this disallows
3007   // <!entity % e "include [ stuff ">
3008   // ...
3009   // <![ %e; ]]>
3010   // which I think is legal.
3011
3012   if (inputLevel() > declInputLevel)
3013     message(ParserMessages::parameterEntityNotEnded);
3014   switch (status) {
3015   case MarkedSectionEvent::include:
3016     startMarkedSection(markupLocation());
3017     break;
3018   case MarkedSectionEvent::cdata:
3019     startSpecialMarkedSection(cmsMode, markupLocation());
3020     break;
3021   case MarkedSectionEvent::rcdata:
3022     startSpecialMarkedSection(rcmsMode, markupLocation());
3023     break;
3024   case MarkedSectionEvent::ignore:
3025     startSpecialMarkedSection(imsMode, markupLocation());
3026     break;
3027   }
3028   if (currentMarkup())
3029     eventHandler().markedSectionStart(new (eventAllocator())
3030                                       MarkedSectionStartEvent(status,
3031                                                               markupLocation(),
3032                                                               currentMarkup()));
3033   return 1;
3034 }
3035
3036 void Parser::handleMarkedSectionEnd()
3037 {
3038   if (markedSectionLevel() == 0)
3039     message(ParserMessages::markedSectionEnd);
3040   else {
3041     if (inInstance()
3042         ? eventsWanted().wantMarkedSections()
3043         : eventsWanted().wantPrologMarkup()) {
3044       if (markedSectionSpecialLevel() > 1)
3045         eventHandler().ignoredChars(new (eventAllocator())
3046                                     IgnoredCharsEvent(currentInput()->currentTokenStart(),
3047                                                       currentInput()->currentTokenLength(),
3048                                                       currentLocation(),
3049                                                       0));
3050       else {
3051         MarkedSectionEvent::Status status;
3052         switch (currentMode()) {
3053         case cmsMode:
3054           status = MarkedSectionEvent::cdata;
3055           break;
3056         case rcmsMode:
3057           status = MarkedSectionEvent::rcdata;
3058           break;
3059         case imsMode:
3060           status = MarkedSectionEvent::ignore;
3061           break;
3062         default:
3063           status = MarkedSectionEvent::include;
3064           break;
3065         }
3066         startMarkup(1, currentLocation());
3067         currentMarkup()->addDelim(Syntax::dMSC);
3068         currentMarkup()->addDelim(Syntax::dMDC);
3069         eventHandler().markedSectionEnd(new (eventAllocator())
3070                                         MarkedSectionEndEvent(status,
3071                                                               markupLocation(),
3072                                                               currentMarkup()));
3073       }
3074     }
3075     endMarkedSection();
3076   }
3077 }
3078
3079 void Parser::emptyCommentDecl()
3080 {
3081   if (startMarkup(eventsWanted().wantCommentDecls(), currentLocation())) {
3082     currentMarkup()->addDelim(Syntax::dMDO);
3083     currentMarkup()->addDelim(Syntax::dMDC);
3084     eventHandler().commentDecl(new (eventAllocator())
3085                                CommentDeclEvent(markupLocation(),
3086                                                 currentMarkup()));
3087   }
3088 }
3089
3090 Boolean Parser::parseCommentDecl()
3091 {
3092   if (startMarkup(inInstance()
3093                   ? eventsWanted().wantCommentDecls()
3094                   : eventsWanted().wantPrologMarkup(),
3095                   currentLocation()))
3096     currentMarkup()->addDelim(Syntax::dMDO);
3097   if (!parseComment(comMode))
3098     return 0;
3099   for (;;) {
3100     Token token = getToken(mdMode);
3101     switch (token) {
3102     case tokenS:
3103       if (currentMarkup())
3104         currentMarkup()->addS(currentChar());
3105       break;
3106     case tokenCom:
3107       if (!parseComment(comMode))
3108         return 0;
3109       break;
3110     case tokenMdc:
3111       if (currentMarkup())
3112         currentMarkup()->addDelim(Syntax::dMDC);
3113       goto done;
3114     case tokenEe:
3115       message(ParserMessages::declarationLevel);
3116       return 0;
3117     case tokenUnrecognized:
3118       if (reportNonSgmlCharacter())
3119         break;
3120       // braces to work round Sun C++ 4.0 bug
3121       {
3122         message(ParserMessages::commentDeclarationCharacter,
3123                 StringMessageArg(currentToken()),
3124                 markupLocation());
3125       }
3126       return 0;
3127     default:
3128       // braces to work round Sun C++ 4.0 bug
3129       {
3130         message(ParserMessages::commentDeclInvalidToken,
3131                 TokenMessageArg(token, mdMode, syntaxPointer(), sdPointer()),
3132                 markupLocation());
3133       }
3134       return 0;
3135     }
3136   }
3137  done:
3138   if (currentMarkup())
3139     eventHandler().commentDecl(new (eventAllocator())
3140                                CommentDeclEvent(markupLocation(),
3141                                                 currentMarkup()));
3142   return 1;
3143 }
3144
3145 Boolean Parser::parseAfdrDecl()
3146 {
3147   unsigned declInputLevel = inputLevel();
3148   static AllowedParams allowMinimumLiteral(Param::minimumLiteral);
3149   Param parm;
3150   setHadAfdrDecl();
3151   if (!parseParam(allowMinimumLiteral, declInputLevel, parm))
3152     return 0;
3153   if (parm.literalText.string() != sd().execToDoc("ISO/IEC 10744:1992"))
3154     message(ParserMessages::afdrVersion,
3155             StringMessageArg(parm.literalText.string()));
3156   if (!parseParam(allowMdc, declInputLevel, parm))
3157     return 0;
3158   eventHandler().ignoredMarkup(new (eventAllocator())
3159                                IgnoredMarkupEvent(markupLocation(),
3160                                                   currentMarkup()));
3161   return 1;
3162 }
3163
3164 #ifdef SP_NAMESPACE
3165 }
3166 #endif