2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: ParserState.C /main/1 1996/07/29 17:01:20 cde-hp $ */
24 // Copyright (c) 1994 James Clark
25 // See the file COPYING for copying permission.
28 #pragma implementation
31 #include "ParserState.h"
32 #include "InternalInputSource.h"
33 #include "MessageArg.h"
35 #include "SgmlParser.h"
36 #include "IListIter.h"
37 #include "ParserMessages.h"
41 namespace SP_NAMESPACE {
44 const Location ParserState::nullLocation_;
45 sig_atomic_t ParserState::dummyCancel_ = 0;
47 static const size_t eventSizes[] = {
48 #define EVENT(c, f) sizeof(c),
53 static const size_t internalSizes[] = {
54 sizeof(InternalInputSource),
59 sizeof(UndoTransition)
63 size_t maxSize(const size_t *v, size_t n)
66 for (size_t i = 0; i < n; i++) {
73 ParserState::ParserState(const Ptr<EntityManager> &em,
74 const ParserOptions &opt,
81 eventAllocator_(maxSize(eventSizes, SIZEOF(eventSizes)), 50),
82 internalAllocator_(maxSize(internalSizes, SIZEOF(internalSizes)), 50),
83 handler_(&eventQueue_),
84 subdocLevel_(subdocLevel),
86 specialParseInputLevel_(0),
87 markedSectionLevel_(0),
88 markedSectionSpecialLevel_(0),
89 currentMode_(proMode),
91 resultAttributeSpecMode_(0),
93 activeLinkTypesSubsted_(0),
98 cancelPtr_(&dummyCancel_),
99 finalPhase_(finalPhase),
101 pass2StartOffset_(0),
107 void ParserState::inheritActiveLinkTypes(const ParserState &parent)
109 activeLinkTypes_ = parent.activeLinkTypes_;
110 activeLinkTypesSubsted_ = parent.activeLinkTypesSubsted_;
113 void ParserState::allDone()
118 void ParserState::setPass2Start()
120 ASSERT(inputLevel_ == 1);
124 if (!pass2() && sd().link() && activeLinkTypes_.size() > 0) {
126 pass1Handler_.init(handler_);
127 handler_ = &pass1Handler_;
128 const InputSourceOrigin *p
129 = currentLocation().origin()->asInputSourceOrigin();
130 pass2StartOffset_= p->startOffset(currentLocation().index());
134 currentInput()->willNotRewind();
138 void ParserState::allLinkTypesActivated()
140 if (activeLinkTypes_.size() == 0 && inputLevel_ == 1)
141 currentInput()->willNotRewind();
144 Boolean ParserState::maybeStartPass2()
146 if (pass2_ || !allowPass2_)
148 handler_ = pass1Handler_.origHandler();
149 if (!nActiveLink() || pass1Handler_.hadError()) {
150 while (!pass1Handler_.empty()) {
153 pass1Handler_.get()->handle(*handler_);
155 InputSource *top = 0;
156 for (IListIter<InputSource> iter(inputStack_);
161 top->willNotRewind();
164 pass1Handler_.clear();
165 while (inputLevel_ > 1) {
166 InputSource *p = inputStack_.get();
170 // Caller will call allDone() if inputLevel_ is 0.
171 if (inputLevel_ == 0)
173 if (!inputStack_.head()->rewind(*this)) {
175 delete inputStack_.get();
178 inputStack_.head()->willNotRewind();
179 for (; pass2StartOffset_ > 0; pass2StartOffset_--)
180 if (inputStack_.head()->get(messenger()) == InputSource::eE) {
181 message(ParserMessages::pass2Ee);
183 delete inputStack_.get();
186 specialParseInputLevel_ = 0;
187 markedSectionLevel_ = 0;
188 markedSectionSpecialLevel_ = 0;
189 currentMode_ = proMode;
198 dtd_[0].swap(pass1Dtd_);
209 Boolean ParserState::referenceDsEntity(const Location &loc)
211 if (dsEntity_.isNull())
213 Ptr<EntityOrigin> origin
214 = new (internalAllocator()) EntityOrigin(dsEntity_, loc);
215 dsEntity_->dsReference(*this, origin);
217 return inputLevel() > 1;
220 void ParserState::startDtd(const StringC &name)
222 defDtd_ = new Dtd(name, dtd_.size() == 0);
224 for (size_t i = 0; i < options().includes.size(); i++) {
225 StringC name = options().includes[i];
226 const SubstTable<Char> *subst = syntax().entitySubstTable();
227 for (size_t j = 0; j < name.size(); j++)
228 subst->subst(name[j]);
230 text.addChars(syntax().reservedName(Syntax::rINCLUDE), Location());
232 = new InternalTextEntity(name,
233 Entity::parameterEntity,
236 InternalTextEntity::none);
238 defDtd_->insertEntity(entity);
240 currentDtd_ = defDtd_;
241 currentMode_ = dsMode;
244 void ParserState::endDtd()
246 dtd_.push_back(defDtd_);
249 currentMode_ = proMode;
252 void ParserState::startLpd(Ptr<Lpd> &lpd)
255 defDtd_ = defLpd_->sourceDtd();
256 currentDtd_ = defLpd_->sourceDtd();
257 currentMode_ = dsMode;
260 void ParserState::endLpd()
263 if (defLpd_->active())
264 lpd_.push_back(defLpd_);
265 allLpd_.push_back(defLpd_);
268 currentMode_ = proMode;
271 void ParserState::popInputStack()
273 ASSERT(inputLevel_ > 0);
274 InputSource *p = inputStack_.get();
277 if (specialParseInputLevel_ > 0 && inputLevel_ == specialParseInputLevel_)
278 currentMode_ = specialParseMode_;
279 if (currentMode_ == dsiMode
281 && markedSectionLevel_ == 0)
282 currentMode_ = dsMode;
285 void ParserState::setSd(ConstPtr<Sd> sd)
288 mayDefaultAttribute_ = (sd_->omittag() || sd_->shorttag());
291 void ParserState::setSyntax(ConstPtr<Syntax> syntax)
294 prologSyntax_ = syntax;
295 instanceSyntax_ = syntax;
298 void ParserState::setSyntaxes(ConstPtr<Syntax> prologSyntax,
299 ConstPtr<Syntax> instanceSyntax)
301 syntax_ = prologSyntax;
302 prologSyntax_ = prologSyntax;
303 instanceSyntax_ = instanceSyntax;
306 void ParserState::pushInput(InputSource *in)
310 if (!syntax_.isNull() && syntax_->multicode())
311 in->setMarkupScanTable(syntax_->markupScanTable());
312 inputStack_.insert(in);
314 if (specialParseInputLevel_ > 0 && inputLevel_ > specialParseInputLevel_)
315 currentMode_ = rcconeMode; // mode for rcdata in an entity
316 else if (currentMode_ == dsMode)
317 currentMode_ = dsiMode;
320 void ParserState::startMarkedSection(const Location &loc)
322 markedSectionLevel_++;
323 markedSectionStartLocation_.push_back(loc);
324 if (currentMode_ == dsMode)
325 currentMode_ = dsiMode;
326 if (markedSectionSpecialLevel_)
327 markedSectionSpecialLevel_++;
330 void ParserState::startSpecialMarkedSection(Mode mode, const Location &loc)
332 markedSectionLevel_++;
333 markedSectionStartLocation_.push_back(loc);
334 specialParseInputLevel_ = inputLevel_;
335 markedSectionSpecialLevel_ = 1;
336 specialParseMode_ = currentMode_ = mode;
339 void ParserState::endMarkedSection()
341 ASSERT(markedSectionLevel_ > 0);
342 markedSectionLevel_--;
343 markedSectionStartLocation_.resize(markedSectionStartLocation_.size()
345 if (markedSectionSpecialLevel_ > 0) {
346 markedSectionSpecialLevel_--;
347 if (markedSectionSpecialLevel_ > 0)
348 return; // remain in imsMode
349 specialParseInputLevel_ = 0;
351 currentMode_ = contentMode();
353 currentMode_ = dsiMode;
355 if (currentMode_ == dsiMode
357 && markedSectionLevel_ == 0)
358 currentMode_ = dsMode;
361 void ParserState::pushElement(OpenElement *e)
363 ContentState::pushElement(e);
364 pcdataRecovering_ = 0;
365 // the start tag of this element may have been implied by data
366 // inside a cdata or rcdata marked section
367 if (markedSectionSpecialLevel_ == 0) {
368 currentMode_ = contentMode();
369 if (e->requiresSpecialParse()) {
370 specialParseMode_ = currentMode_;
371 specialParseInputLevel_ = inputLevel_;
376 // PCDATA was encountered somewhere where it was not allowed.
377 // Change the current mode to improve recovery.
379 void ParserState::pcdataRecover()
381 switch (currentMode_) {
383 currentMode_ = mconMode;
386 currentMode_ = mconnetMode;
391 pcdataRecovering_ = 1;
394 OpenElement *ParserState::popSaveElement()
396 OpenElement *e = ContentState::popSaveElement();
397 // the end tag of this element may have been implied by data
398 // inside a cdata or rcdata marked section
399 if (markedSectionSpecialLevel_ == 0) {
400 currentMode_ = contentMode();
401 specialParseInputLevel_ = 0;
403 pcdataRecovering_ = 0;
407 void ParserState::popElement()
409 delete popSaveElement();
412 Boolean ParserState::entityIsOpen(const Entity *entity) const
414 for (IListIter<InputSource> iter(inputStack_); !iter.done(); iter.next()) {
415 const EntityOrigin *eo
416 = iter.cur()->currentLocation().origin()->asEntityOrigin();
417 if (eo && eo->entity().pointer() == entity)
423 void ParserState::startInstance()
425 if (!instanceSyntax_.isNull())
426 syntax_ = instanceSyntax_;
427 currentMode_ = econMode;
428 currentDtd_ = dtd_[0];
429 startContent(currentDtd());
432 currentRank_.assign(currentDtd().nRankStem(), StringC());
433 currentAttributes_.clear();
434 currentAttributes_.resize(currentDtd().nCurrentAttribute());
438 Id *ParserState::lookupCreateId(const StringC &name)
440 Id *id = idTable_.lookup(name);
449 ParserState::lookupEntity(Boolean isParameter,
451 const Location &useLocation,
455 if (resultAttributeSpecMode_)
456 dtd = defComplexLpd().resultDtd().pointer();
458 dtd = (Dtd *)currentDtd_.pointer();
460 Ptr<Entity> entity(dtd->lookupEntity(isParameter, name));
461 // Did we find it in pass1Dtd?
462 // Did we look at the defaultEntity?
463 if (!inInstance_ && pass2() && dtd->isBase()
464 && !resultAttributeSpecMode_
465 && (entity.isNull() || !entity->declInActiveLpd())) {
466 ConstPtr<Entity> entity1
467 = pass1Dtd_->lookupEntity(isParameter, name);
468 if (!entity1.isNull() && entity1->declInActiveLpd()
469 && !entity1->defaulted()) {
471 noteReferencedEntity(entity1, 1, 0);
474 else if (!entity.isNull()) {
476 noteReferencedEntity(entity, 0, 0);
481 else if (!entity.isNull()) {
486 ConstPtr<Entity> entity(dtd->defaultEntity());
488 Boolean usedPass1 = 0;
489 if (!inInstance_ && pass2() && dtd->isBase()
490 && !resultAttributeSpecMode_
491 && (entity.isNull() || !entity->declInActiveLpd())) {
494 ConstPtr<Entity> entity1 = pass1Dtd_->defaultEntity();
495 if (!entity1.isNull() && entity1->declInActiveLpd()) {
500 if (!entity.isNull()) {
501 Boolean mustCopy = 1;
504 = instanceDefaultedEntityTable_.lookupConst(name);
511 Ptr<Entity> p(entity->copy());
513 p->generateSystemId(*this);
517 instanceDefaultedEntityTable_.insert(p);
518 eventHandler().entityDefaulted(new (eventAllocator())
519 EntityDefaultedEvent(entity,
523 dtd->insertEntity(p);
526 noteReferencedEntity(entity, usedPass1, 1);
534 void ParserState::noteReferencedEntity(const ConstPtr<Entity> &entity,
535 Boolean foundInPass1Dtd,
536 Boolean lookedAtDefault)
540 ref.lookedAtDefault = lookedAtDefault;
541 ref.foundInPass1Dtd = foundInPass1Dtd;
542 LpdEntityRef *old = lpdEntityRefs_.lookup(ref);
544 lpdEntityRefs_.insert(new LpdEntityRef(ref));
547 // Compare entity definitions.
548 // e1 is the original (will not be an external non-text entity).
549 // FIXME should look at generated sysids as well.
551 Boolean sameEntityDef(const Entity *e1, const Entity *e2)
553 if (e1->dataType() != e2->dataType())
555 const InternalEntity *i1 = e1->asInternalEntity();
556 const InternalEntity *i2 = e2->asInternalEntity();
560 if (i1->string() != i2->string())
566 const ExternalEntity *x1 = e1->asExternalEntity();
567 const ExternalEntity *x2 = e2->asExternalEntity();
568 const StringC *s1 = x1->externalId().systemIdString();
569 const StringC *s2 = x2->externalId().systemIdString();
578 s1 = x1->externalId().publicIdString();
579 s2 = x2->externalId().publicIdString();
591 void ParserState::checkEntityStability()
593 LpdEntityRefSetIter iter(lpdEntityRefs_);
595 while ((ref = iter.next()) != 0) {
596 ConstPtr<Entity> entity
597 = dtd_[0]->lookupEntity(ref->entity->declType()
598 == Entity::parameterEntity,
599 ref->entity->name());
600 if (entity.isNull() && ref->lookedAtDefault)
601 entity = dtd_[0]->defaultEntity();
603 ? ref->foundInPass1Dtd
604 : !sameEntityDef(ref->entity.pointer(), entity.pointer()))
605 message(((ref->entity->declType()
606 == Entity::parameterEntity)
607 ? ParserMessages::unstableLpdParameterEntity
608 : ParserMessages::unstableLpdGeneralEntity),
609 StringMessageArg(ref->entity->name()));
612 // Ensure that the memory is released.
614 lpdEntityRefs_.swap(tem);
618 Boolean ParserState::appendCurrentRank(StringC &str, const RankStem *stem)
621 const StringC &suffix = currentRank_[stem->index()];
622 if (suffix.size() > 0) {
629 void ParserState::setCurrentRank(const RankStem *stem, const StringC &suffix)
631 currentRank_[stem->index()] = suffix;
634 void ParserState::getCurrentToken(const SubstTable<Char> *subst,
637 InputSource *in = currentInput();
638 const Char *p = in->currentTokenStart();
639 size_t count = in->currentTokenLength();
641 StringC::iterator s = str.begin();
642 for (; count > 0; --count)
643 *s++ = (*subst)[*p++];
646 void ParserState::queueMessage(MessageEvent *event)
652 if (keepingMessages_)
653 keptMessages_.append(event);
655 handler_->message(event);
658 void ParserState::releaseKeptMessages()
660 keepingMessages_ = 0;
661 while (!keptMessages_.empty()) {
666 handler_->message(keptMessages_.get());
670 void ParserState::discardKeptMessages()
672 keepingMessages_ = 0;
673 keptMessages_.clear();
676 void ParserState::initMessage(Message &msg)
679 StringC rniPcdata = syntax().delimGeneral(Syntax::dRNI);
680 rniPcdata += syntax().reservedName(Syntax::rPCDATA);
681 getOpenElementInfo(msg.openElementInfo, rniPcdata);
683 msg.loc = currentLocation();
686 void ParserState::dispatchMessage(Message &msg)
688 queueMessage(new MessageEvent(msg));
691 void ParserState::dispatchMessage(const Message &msg)
693 queueMessage(new MessageEvent(msg));
697 ParserState::allocAttributeList(const ConstPtr<AttributeDefinitionList> &def,
700 if (i < attributeLists_.size())
701 attributeLists_[i]->init(def);
703 attributeLists_.resize(i + 1);
704 attributeLists_[i] = new AttributeList(def);
706 return attributeLists_[i].pointer();
709 void ParserState::activateLinkType(const StringC &name)
711 if (!hadPass2Start_ && !pass2_)
712 activeLinkTypes_.push_back(name);
714 message(ParserMessages::linkActivateTooLate);
717 Boolean ParserState::shouldActivateLink(const StringC &name) const
719 if (!activeLinkTypesSubsted_) {
721 ParserState *state = (ParserState *)this;
722 for (size_t i = 0; i < activeLinkTypes_.size(); i++)
723 for (size_t j = 0; j < activeLinkTypes_[i].size(); j++)
724 syntax().generalSubstTable()->subst(state->activeLinkTypes_[i][j]);
725 state->activeLinkTypesSubsted_ = 1;
727 for (size_t i = 0; i < activeLinkTypes_.size(); i++)
728 if (name == activeLinkTypes_[i])
733 Ptr<Dtd> ParserState::lookupDtd(const StringC &name)
735 for (size_t i = 0; i < dtd_.size(); i++)
736 if (dtd_[i]->name() == name)
741 ConstPtr<Lpd> ParserState::lookupLpd(const StringC &name) const
743 for (size_t i = 0; i < allLpd_.size(); i++)
744 if (allLpd_[i]->name() == name)
746 return ConstPtr<Lpd>();
749 ConstPtr<Notation> ParserState::getAttributeNotation(const StringC &name,
752 ConstPtr<Notation> notation;
753 if (haveCurrentDtd())
754 notation = currentDtd().lookupNotation(name);
755 else if (resultAttributeSpecMode_) {
756 const Dtd *resultDtd = defComplexLpd().resultDtd().pointer();
759 notation = resultDtd->lookupNotation(name);
764 ConstPtr<Entity> ParserState::getAttributeEntity(const StringC &str,
767 ConstPtr<Entity> entity = lookupEntity(0, str, loc, 0);
769 && entity->defaulted()
770 && options().warnDefaultEntityReference) {
771 setNextLocation(loc);
772 message(ParserMessages::defaultEntityInAttribute,
773 StringMessageArg(str));
778 Boolean ParserState::defineId(const StringC &str, const Location &loc,
783 Id *id = lookupCreateId(str);
785 prevLoc = id->defLocation();
792 void ParserState::noteIdref(const StringC &str, const Location &loc)
794 if (!inInstance() || !options().errorIdref)
796 Id *id = lookupCreateId(str);
798 id->addPendingRef(loc);
801 void ParserState::noteCurrentAttribute(size_t i, AttributeValue *value)
804 currentAttributes_[i] = value;
807 ConstPtr<AttributeValue> ParserState::getCurrentAttribute(size_t i) const
809 return currentAttributes_[i];
812 const Syntax &ParserState::attributeSyntax() const