1 /* $XConsortium: ParserState.C /main/1 1996/07/29 17:01:20 cde-hp $ */
2 // Copyright (c) 1994 James Clark
3 // See the file COPYING for copying permission.
9 #include "ParserState.h"
10 #include "InternalInputSource.h"
11 #include "MessageArg.h"
13 #include "SgmlParser.h"
14 #include "IListIter.h"
15 #include "ParserMessages.h"
19 namespace SP_NAMESPACE {
22 const Location ParserState::nullLocation_;
23 sig_atomic_t ParserState::dummyCancel_ = 0;
25 static const size_t eventSizes[] = {
26 #define EVENT(c, f) sizeof(c),
31 static const size_t internalSizes[] = {
32 sizeof(InternalInputSource),
37 sizeof(UndoTransition)
41 size_t maxSize(const size_t *v, size_t n)
44 for (size_t i = 0; i < n; i++) {
51 ParserState::ParserState(const Ptr<EntityManager> &em,
52 const ParserOptions &opt,
59 eventAllocator_(maxSize(eventSizes, SIZEOF(eventSizes)), 50),
60 internalAllocator_(maxSize(internalSizes, SIZEOF(internalSizes)), 50),
61 handler_(&eventQueue_),
62 subdocLevel_(subdocLevel),
64 specialParseInputLevel_(0),
65 markedSectionLevel_(0),
66 markedSectionSpecialLevel_(0),
67 currentMode_(proMode),
69 resultAttributeSpecMode_(0),
71 activeLinkTypesSubsted_(0),
76 cancelPtr_(&dummyCancel_),
77 finalPhase_(finalPhase),
82 void ParserState::inheritActiveLinkTypes(const ParserState &parent)
84 activeLinkTypes_ = parent.activeLinkTypes_;
85 activeLinkTypesSubsted_ = parent.activeLinkTypesSubsted_;
88 void ParserState::allDone()
93 void ParserState::setPass2Start()
95 ASSERT(inputLevel_ == 1);
99 if (!pass2() && sd().link() && activeLinkTypes_.size() > 0) {
101 pass1Handler_.init(handler_);
102 handler_ = &pass1Handler_;
103 const InputSourceOrigin *p
104 = currentLocation().origin()->asInputSourceOrigin();
105 pass2StartOffset_= p->startOffset(currentLocation().index());
109 currentInput()->willNotRewind();
113 void ParserState::allLinkTypesActivated()
115 if (activeLinkTypes_.size() == 0 && inputLevel_ == 1)
116 currentInput()->willNotRewind();
119 Boolean ParserState::maybeStartPass2()
121 if (pass2_ || !allowPass2_)
123 handler_ = pass1Handler_.origHandler();
124 if (!nActiveLink() || pass1Handler_.hadError()) {
125 while (!pass1Handler_.empty()) {
128 pass1Handler_.get()->handle(*handler_);
130 InputSource *top = 0;
131 for (IListIter<InputSource> iter(inputStack_);
136 top->willNotRewind();
139 pass1Handler_.clear();
140 while (inputLevel_ > 1) {
141 InputSource *p = inputStack_.get();
145 // Caller will call allDone() if inputLevel_ is 0.
146 if (inputLevel_ == 0)
148 if (!inputStack_.head()->rewind(*this)) {
150 delete inputStack_.get();
153 inputStack_.head()->willNotRewind();
154 for (; pass2StartOffset_ > 0; pass2StartOffset_--)
155 if (inputStack_.head()->get(messenger()) == InputSource::eE) {
156 message(ParserMessages::pass2Ee);
158 delete inputStack_.get();
161 specialParseInputLevel_ = 0;
162 markedSectionLevel_ = 0;
163 markedSectionSpecialLevel_ = 0;
164 currentMode_ = proMode;
173 dtd_[0].swap(pass1Dtd_);
184 Boolean ParserState::referenceDsEntity(const Location &loc)
186 if (dsEntity_.isNull())
188 Ptr<EntityOrigin> origin
189 = new (internalAllocator()) EntityOrigin(dsEntity_, loc);
190 dsEntity_->dsReference(*this, origin);
192 return inputLevel() > 1;
195 void ParserState::startDtd(const StringC &name)
197 defDtd_ = new Dtd(name, dtd_.size() == 0);
199 for (size_t i = 0; i < options().includes.size(); i++) {
200 StringC name = options().includes[i];
201 const SubstTable<Char> *subst = syntax().entitySubstTable();
202 for (size_t j = 0; j < name.size(); j++)
203 subst->subst(name[j]);
205 text.addChars(syntax().reservedName(Syntax::rINCLUDE), Location());
207 = new InternalTextEntity(name,
208 Entity::parameterEntity,
211 InternalTextEntity::none);
213 defDtd_->insertEntity(entity);
215 currentDtd_ = defDtd_;
216 currentMode_ = dsMode;
219 void ParserState::endDtd()
221 dtd_.push_back(defDtd_);
224 currentMode_ = proMode;
227 void ParserState::startLpd(Ptr<Lpd> &lpd)
230 defDtd_ = defLpd_->sourceDtd();
231 currentDtd_ = defLpd_->sourceDtd();
232 currentMode_ = dsMode;
235 void ParserState::endLpd()
238 if (defLpd_->active())
239 lpd_.push_back(defLpd_);
240 allLpd_.push_back(defLpd_);
243 currentMode_ = proMode;
246 void ParserState::popInputStack()
248 ASSERT(inputLevel_ > 0);
249 InputSource *p = inputStack_.get();
252 if (specialParseInputLevel_ > 0 && inputLevel_ == specialParseInputLevel_)
253 currentMode_ = specialParseMode_;
254 if (currentMode_ == dsiMode
256 && markedSectionLevel_ == 0)
257 currentMode_ = dsMode;
260 void ParserState::setSd(ConstPtr<Sd> sd)
263 mayDefaultAttribute_ = (sd_->omittag() || sd_->shorttag());
266 void ParserState::setSyntax(ConstPtr<Syntax> syntax)
269 prologSyntax_ = syntax;
270 instanceSyntax_ = syntax;
273 void ParserState::setSyntaxes(ConstPtr<Syntax> prologSyntax,
274 ConstPtr<Syntax> instanceSyntax)
276 syntax_ = prologSyntax;
277 prologSyntax_ = prologSyntax;
278 instanceSyntax_ = instanceSyntax;
281 void ParserState::pushInput(InputSource *in)
285 if (!syntax_.isNull() && syntax_->multicode())
286 in->setMarkupScanTable(syntax_->markupScanTable());
287 inputStack_.insert(in);
289 if (specialParseInputLevel_ > 0 && inputLevel_ > specialParseInputLevel_)
290 currentMode_ = rcconeMode; // mode for rcdata in an entity
291 else if (currentMode_ == dsMode)
292 currentMode_ = dsiMode;
295 void ParserState::startMarkedSection(const Location &loc)
297 markedSectionLevel_++;
298 markedSectionStartLocation_.push_back(loc);
299 if (currentMode_ == dsMode)
300 currentMode_ = dsiMode;
301 if (markedSectionSpecialLevel_)
302 markedSectionSpecialLevel_++;
305 void ParserState::startSpecialMarkedSection(Mode mode, const Location &loc)
307 markedSectionLevel_++;
308 markedSectionStartLocation_.push_back(loc);
309 specialParseInputLevel_ = inputLevel_;
310 markedSectionSpecialLevel_ = 1;
311 specialParseMode_ = currentMode_ = mode;
314 void ParserState::endMarkedSection()
316 ASSERT(markedSectionLevel_ > 0);
317 markedSectionLevel_--;
318 markedSectionStartLocation_.resize(markedSectionStartLocation_.size()
320 if (markedSectionSpecialLevel_ > 0) {
321 markedSectionSpecialLevel_--;
322 if (markedSectionSpecialLevel_ > 0)
323 return; // remain in imsMode
324 specialParseInputLevel_ = 0;
326 currentMode_ = contentMode();
328 currentMode_ = dsiMode;
330 if (currentMode_ == dsiMode
332 && markedSectionLevel_ == 0)
333 currentMode_ = dsMode;
336 void ParserState::pushElement(OpenElement *e)
338 ContentState::pushElement(e);
339 pcdataRecovering_ = 0;
340 // the start tag of this element may have been implied by data
341 // inside a cdata or rcdata marked section
342 if (markedSectionSpecialLevel_ == 0) {
343 currentMode_ = contentMode();
344 if (e->requiresSpecialParse()) {
345 specialParseMode_ = currentMode_;
346 specialParseInputLevel_ = inputLevel_;
351 // PCDATA was encountered somewhere where it was not allowed.
352 // Change the current mode to improve recovery.
354 void ParserState::pcdataRecover()
356 switch (currentMode_) {
358 currentMode_ = mconMode;
361 currentMode_ = mconnetMode;
366 pcdataRecovering_ = 1;
369 OpenElement *ParserState::popSaveElement()
371 OpenElement *e = ContentState::popSaveElement();
372 // the end tag of this element may have been implied by data
373 // inside a cdata or rcdata marked section
374 if (markedSectionSpecialLevel_ == 0) {
375 currentMode_ = contentMode();
376 specialParseInputLevel_ = 0;
378 pcdataRecovering_ = 0;
382 void ParserState::popElement()
384 delete popSaveElement();
387 Boolean ParserState::entityIsOpen(const Entity *entity) const
389 for (IListIter<InputSource> iter(inputStack_); !iter.done(); iter.next()) {
390 const EntityOrigin *eo
391 = iter.cur()->currentLocation().origin()->asEntityOrigin();
392 if (eo && eo->entity().pointer() == entity)
398 void ParserState::startInstance()
400 if (!instanceSyntax_.isNull())
401 syntax_ = instanceSyntax_;
402 currentMode_ = econMode;
403 currentDtd_ = dtd_[0];
404 startContent(currentDtd());
407 currentRank_.assign(currentDtd().nRankStem(), StringC());
408 currentAttributes_.clear();
409 currentAttributes_.resize(currentDtd().nCurrentAttribute());
413 Id *ParserState::lookupCreateId(const StringC &name)
415 Id *id = idTable_.lookup(name);
424 ParserState::lookupEntity(Boolean isParameter,
426 const Location &useLocation,
430 if (resultAttributeSpecMode_)
431 dtd = defComplexLpd().resultDtd().pointer();
433 dtd = (Dtd *)currentDtd_.pointer();
435 Ptr<Entity> entity(dtd->lookupEntity(isParameter, name));
436 // Did we find it in pass1Dtd?
437 // Did we look at the defaultEntity?
438 if (!inInstance_ && pass2() && dtd->isBase()
439 && !resultAttributeSpecMode_
440 && (entity.isNull() || !entity->declInActiveLpd())) {
441 ConstPtr<Entity> entity1
442 = pass1Dtd_->lookupEntity(isParameter, name);
443 if (!entity1.isNull() && entity1->declInActiveLpd()
444 && !entity1->defaulted()) {
446 noteReferencedEntity(entity1, 1, 0);
449 else if (!entity.isNull()) {
451 noteReferencedEntity(entity, 0, 0);
456 else if (!entity.isNull()) {
461 ConstPtr<Entity> entity(dtd->defaultEntity());
463 Boolean usedPass1 = 0;
464 if (!inInstance_ && pass2() && dtd->isBase()
465 && !resultAttributeSpecMode_
466 && (entity.isNull() || !entity->declInActiveLpd())) {
469 ConstPtr<Entity> entity1 = pass1Dtd_->defaultEntity();
470 if (!entity1.isNull() && entity1->declInActiveLpd()) {
475 if (!entity.isNull()) {
476 Boolean mustCopy = 1;
479 = instanceDefaultedEntityTable_.lookupConst(name);
486 Ptr<Entity> p(entity->copy());
488 p->generateSystemId(*this);
492 instanceDefaultedEntityTable_.insert(p);
493 eventHandler().entityDefaulted(new (eventAllocator())
494 EntityDefaultedEvent(entity,
498 dtd->insertEntity(p);
501 noteReferencedEntity(entity, usedPass1, 1);
509 void ParserState::noteReferencedEntity(const ConstPtr<Entity> &entity,
510 Boolean foundInPass1Dtd,
511 Boolean lookedAtDefault)
515 ref.lookedAtDefault = lookedAtDefault;
516 ref.foundInPass1Dtd = foundInPass1Dtd;
517 LpdEntityRef *old = lpdEntityRefs_.lookup(ref);
519 lpdEntityRefs_.insert(new LpdEntityRef(ref));
522 // Compare entity definitions.
523 // e1 is the original (will not be an external non-text entity).
524 // FIXME should look at generated sysids as well.
526 Boolean sameEntityDef(const Entity *e1, const Entity *e2)
528 if (e1->dataType() != e2->dataType())
530 const InternalEntity *i1 = e1->asInternalEntity();
531 const InternalEntity *i2 = e2->asInternalEntity();
535 if (i1->string() != i2->string())
541 const ExternalEntity *x1 = e1->asExternalEntity();
542 const ExternalEntity *x2 = e2->asExternalEntity();
543 const StringC *s1 = x1->externalId().systemIdString();
544 const StringC *s2 = x2->externalId().systemIdString();
553 s1 = x1->externalId().publicIdString();
554 s2 = x2->externalId().publicIdString();
566 void ParserState::checkEntityStability()
568 LpdEntityRefSetIter iter(lpdEntityRefs_);
570 while ((ref = iter.next()) != 0) {
571 ConstPtr<Entity> entity
572 = dtd_[0]->lookupEntity(ref->entity->declType()
573 == Entity::parameterEntity,
574 ref->entity->name());
575 if (entity.isNull() && ref->lookedAtDefault)
576 entity = dtd_[0]->defaultEntity();
578 ? ref->foundInPass1Dtd
579 : !sameEntityDef(ref->entity.pointer(), entity.pointer()))
580 message(((ref->entity->declType()
581 == Entity::parameterEntity)
582 ? ParserMessages::unstableLpdParameterEntity
583 : ParserMessages::unstableLpdGeneralEntity),
584 StringMessageArg(ref->entity->name()));
587 // Ensure that the memory is released.
589 lpdEntityRefs_.swap(tem);
593 Boolean ParserState::appendCurrentRank(StringC &str, const RankStem *stem)
596 const StringC &suffix = currentRank_[stem->index()];
597 if (suffix.size() > 0) {
604 void ParserState::setCurrentRank(const RankStem *stem, const StringC &suffix)
606 currentRank_[stem->index()] = suffix;
609 void ParserState::getCurrentToken(const SubstTable<Char> *subst,
612 InputSource *in = currentInput();
613 const Char *p = in->currentTokenStart();
614 size_t count = in->currentTokenLength();
616 StringC::iterator s = str.begin();
617 for (; count > 0; --count)
618 *s++ = (*subst)[*p++];
621 void ParserState::queueMessage(MessageEvent *event)
627 if (keepingMessages_)
628 keptMessages_.append(event);
630 handler_->message(event);
633 void ParserState::releaseKeptMessages()
635 keepingMessages_ = 0;
636 while (!keptMessages_.empty()) {
641 handler_->message(keptMessages_.get());
645 void ParserState::discardKeptMessages()
647 keepingMessages_ = 0;
648 keptMessages_.clear();
651 void ParserState::initMessage(Message &msg)
654 StringC rniPcdata = syntax().delimGeneral(Syntax::dRNI);
655 rniPcdata += syntax().reservedName(Syntax::rPCDATA);
656 getOpenElementInfo(msg.openElementInfo, rniPcdata);
658 msg.loc = currentLocation();
661 void ParserState::dispatchMessage(Message &msg)
663 queueMessage(new MessageEvent(msg));
666 void ParserState::dispatchMessage(const Message &msg)
668 queueMessage(new MessageEvent(msg));
672 ParserState::allocAttributeList(const ConstPtr<AttributeDefinitionList> &def,
675 if (i < attributeLists_.size())
676 attributeLists_[i]->init(def);
678 attributeLists_.resize(i + 1);
679 attributeLists_[i] = new AttributeList(def);
681 return attributeLists_[i].pointer();
684 void ParserState::activateLinkType(const StringC &name)
686 if (!hadPass2Start_ && !pass2_)
687 activeLinkTypes_.push_back(name);
689 message(ParserMessages::linkActivateTooLate);
692 Boolean ParserState::shouldActivateLink(const StringC &name) const
694 if (!activeLinkTypesSubsted_) {
696 ParserState *state = (ParserState *)this;
697 for (size_t i = 0; i < activeLinkTypes_.size(); i++)
698 for (size_t j = 0; j < activeLinkTypes_[i].size(); j++)
699 syntax().generalSubstTable()->subst(state->activeLinkTypes_[i][j]);
700 state->activeLinkTypesSubsted_ = 1;
702 for (size_t i = 0; i < activeLinkTypes_.size(); i++)
703 if (name == activeLinkTypes_[i])
708 Ptr<Dtd> ParserState::lookupDtd(const StringC &name)
710 for (size_t i = 0; i < dtd_.size(); i++)
711 if (dtd_[i]->name() == name)
716 ConstPtr<Lpd> ParserState::lookupLpd(const StringC &name) const
718 for (size_t i = 0; i < allLpd_.size(); i++)
719 if (allLpd_[i]->name() == name)
721 return ConstPtr<Lpd>();
724 ConstPtr<Notation> ParserState::getAttributeNotation(const StringC &name,
727 ConstPtr<Notation> notation;
728 if (haveCurrentDtd())
729 notation = currentDtd().lookupNotation(name);
730 else if (resultAttributeSpecMode_) {
731 const Dtd *resultDtd = defComplexLpd().resultDtd().pointer();
734 notation = resultDtd->lookupNotation(name);
739 ConstPtr<Entity> ParserState::getAttributeEntity(const StringC &str,
742 ConstPtr<Entity> entity = lookupEntity(0, str, loc, 0);
744 && entity->defaulted()
745 && options().warnDefaultEntityReference) {
746 setNextLocation(loc);
747 message(ParserMessages::defaultEntityInAttribute,
748 StringMessageArg(str));
753 Boolean ParserState::defineId(const StringC &str, const Location &loc,
758 Id *id = lookupCreateId(str);
760 prevLoc = id->defLocation();
767 void ParserState::noteIdref(const StringC &str, const Location &loc)
769 if (!inInstance() || !options().errorIdref)
771 Id *id = lookupCreateId(str);
773 id->addPendingRef(loc);
776 void ParserState::noteCurrentAttribute(size_t i, AttributeValue *value)
779 currentAttributes_[i] = value;
782 ConstPtr<AttributeValue> ParserState::getCurrentAttribute(size_t i) const
784 return currentAttributes_[i];
787 const Syntax &ParserState::attributeSyntax() const