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 librararies 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),
104 void ParserState::inheritActiveLinkTypes(const ParserState &parent)
106 activeLinkTypes_ = parent.activeLinkTypes_;
107 activeLinkTypesSubsted_ = parent.activeLinkTypesSubsted_;
110 void ParserState::allDone()
115 void ParserState::setPass2Start()
117 ASSERT(inputLevel_ == 1);
121 if (!pass2() && sd().link() && activeLinkTypes_.size() > 0) {
123 pass1Handler_.init(handler_);
124 handler_ = &pass1Handler_;
125 const InputSourceOrigin *p
126 = currentLocation().origin()->asInputSourceOrigin();
127 pass2StartOffset_= p->startOffset(currentLocation().index());
131 currentInput()->willNotRewind();
135 void ParserState::allLinkTypesActivated()
137 if (activeLinkTypes_.size() == 0 && inputLevel_ == 1)
138 currentInput()->willNotRewind();
141 Boolean ParserState::maybeStartPass2()
143 if (pass2_ || !allowPass2_)
145 handler_ = pass1Handler_.origHandler();
146 if (!nActiveLink() || pass1Handler_.hadError()) {
147 while (!pass1Handler_.empty()) {
150 pass1Handler_.get()->handle(*handler_);
152 InputSource *top = 0;
153 for (IListIter<InputSource> iter(inputStack_);
158 top->willNotRewind();
161 pass1Handler_.clear();
162 while (inputLevel_ > 1) {
163 InputSource *p = inputStack_.get();
167 // Caller will call allDone() if inputLevel_ is 0.
168 if (inputLevel_ == 0)
170 if (!inputStack_.head()->rewind(*this)) {
172 delete inputStack_.get();
175 inputStack_.head()->willNotRewind();
176 for (; pass2StartOffset_ > 0; pass2StartOffset_--)
177 if (inputStack_.head()->get(messenger()) == InputSource::eE) {
178 message(ParserMessages::pass2Ee);
180 delete inputStack_.get();
183 specialParseInputLevel_ = 0;
184 markedSectionLevel_ = 0;
185 markedSectionSpecialLevel_ = 0;
186 currentMode_ = proMode;
195 dtd_[0].swap(pass1Dtd_);
206 Boolean ParserState::referenceDsEntity(const Location &loc)
208 if (dsEntity_.isNull())
210 Ptr<EntityOrigin> origin
211 = new (internalAllocator()) EntityOrigin(dsEntity_, loc);
212 dsEntity_->dsReference(*this, origin);
214 return inputLevel() > 1;
217 void ParserState::startDtd(const StringC &name)
219 defDtd_ = new Dtd(name, dtd_.size() == 0);
221 for (size_t i = 0; i < options().includes.size(); i++) {
222 StringC name = options().includes[i];
223 const SubstTable<Char> *subst = syntax().entitySubstTable();
224 for (size_t j = 0; j < name.size(); j++)
225 subst->subst(name[j]);
227 text.addChars(syntax().reservedName(Syntax::rINCLUDE), Location());
229 = new InternalTextEntity(name,
230 Entity::parameterEntity,
233 InternalTextEntity::none);
235 defDtd_->insertEntity(entity);
237 currentDtd_ = defDtd_;
238 currentMode_ = dsMode;
241 void ParserState::endDtd()
243 dtd_.push_back(defDtd_);
246 currentMode_ = proMode;
249 void ParserState::startLpd(Ptr<Lpd> &lpd)
252 defDtd_ = defLpd_->sourceDtd();
253 currentDtd_ = defLpd_->sourceDtd();
254 currentMode_ = dsMode;
257 void ParserState::endLpd()
260 if (defLpd_->active())
261 lpd_.push_back(defLpd_);
262 allLpd_.push_back(defLpd_);
265 currentMode_ = proMode;
268 void ParserState::popInputStack()
270 ASSERT(inputLevel_ > 0);
271 InputSource *p = inputStack_.get();
274 if (specialParseInputLevel_ > 0 && inputLevel_ == specialParseInputLevel_)
275 currentMode_ = specialParseMode_;
276 if (currentMode_ == dsiMode
278 && markedSectionLevel_ == 0)
279 currentMode_ = dsMode;
282 void ParserState::setSd(ConstPtr<Sd> sd)
285 mayDefaultAttribute_ = (sd_->omittag() || sd_->shorttag());
288 void ParserState::setSyntax(ConstPtr<Syntax> syntax)
291 prologSyntax_ = syntax;
292 instanceSyntax_ = syntax;
295 void ParserState::setSyntaxes(ConstPtr<Syntax> prologSyntax,
296 ConstPtr<Syntax> instanceSyntax)
298 syntax_ = prologSyntax;
299 prologSyntax_ = prologSyntax;
300 instanceSyntax_ = instanceSyntax;
303 void ParserState::pushInput(InputSource *in)
307 if (!syntax_.isNull() && syntax_->multicode())
308 in->setMarkupScanTable(syntax_->markupScanTable());
309 inputStack_.insert(in);
311 if (specialParseInputLevel_ > 0 && inputLevel_ > specialParseInputLevel_)
312 currentMode_ = rcconeMode; // mode for rcdata in an entity
313 else if (currentMode_ == dsMode)
314 currentMode_ = dsiMode;
317 void ParserState::startMarkedSection(const Location &loc)
319 markedSectionLevel_++;
320 markedSectionStartLocation_.push_back(loc);
321 if (currentMode_ == dsMode)
322 currentMode_ = dsiMode;
323 if (markedSectionSpecialLevel_)
324 markedSectionSpecialLevel_++;
327 void ParserState::startSpecialMarkedSection(Mode mode, const Location &loc)
329 markedSectionLevel_++;
330 markedSectionStartLocation_.push_back(loc);
331 specialParseInputLevel_ = inputLevel_;
332 markedSectionSpecialLevel_ = 1;
333 specialParseMode_ = currentMode_ = mode;
336 void ParserState::endMarkedSection()
338 ASSERT(markedSectionLevel_ > 0);
339 markedSectionLevel_--;
340 markedSectionStartLocation_.resize(markedSectionStartLocation_.size()
342 if (markedSectionSpecialLevel_ > 0) {
343 markedSectionSpecialLevel_--;
344 if (markedSectionSpecialLevel_ > 0)
345 return; // remain in imsMode
346 specialParseInputLevel_ = 0;
348 currentMode_ = contentMode();
350 currentMode_ = dsiMode;
352 if (currentMode_ == dsiMode
354 && markedSectionLevel_ == 0)
355 currentMode_ = dsMode;
358 void ParserState::pushElement(OpenElement *e)
360 ContentState::pushElement(e);
361 pcdataRecovering_ = 0;
362 // the start tag of this element may have been implied by data
363 // inside a cdata or rcdata marked section
364 if (markedSectionSpecialLevel_ == 0) {
365 currentMode_ = contentMode();
366 if (e->requiresSpecialParse()) {
367 specialParseMode_ = currentMode_;
368 specialParseInputLevel_ = inputLevel_;
373 // PCDATA was encountered somewhere where it was not allowed.
374 // Change the current mode to improve recovery.
376 void ParserState::pcdataRecover()
378 switch (currentMode_) {
380 currentMode_ = mconMode;
383 currentMode_ = mconnetMode;
388 pcdataRecovering_ = 1;
391 OpenElement *ParserState::popSaveElement()
393 OpenElement *e = ContentState::popSaveElement();
394 // the end tag of this element may have been implied by data
395 // inside a cdata or rcdata marked section
396 if (markedSectionSpecialLevel_ == 0) {
397 currentMode_ = contentMode();
398 specialParseInputLevel_ = 0;
400 pcdataRecovering_ = 0;
404 void ParserState::popElement()
406 delete popSaveElement();
409 Boolean ParserState::entityIsOpen(const Entity *entity) const
411 for (IListIter<InputSource> iter(inputStack_); !iter.done(); iter.next()) {
412 const EntityOrigin *eo
413 = iter.cur()->currentLocation().origin()->asEntityOrigin();
414 if (eo && eo->entity().pointer() == entity)
420 void ParserState::startInstance()
422 if (!instanceSyntax_.isNull())
423 syntax_ = instanceSyntax_;
424 currentMode_ = econMode;
425 currentDtd_ = dtd_[0];
426 startContent(currentDtd());
429 currentRank_.assign(currentDtd().nRankStem(), StringC());
430 currentAttributes_.clear();
431 currentAttributes_.resize(currentDtd().nCurrentAttribute());
435 Id *ParserState::lookupCreateId(const StringC &name)
437 Id *id = idTable_.lookup(name);
446 ParserState::lookupEntity(Boolean isParameter,
448 const Location &useLocation,
452 if (resultAttributeSpecMode_)
453 dtd = defComplexLpd().resultDtd().pointer();
455 dtd = (Dtd *)currentDtd_.pointer();
457 Ptr<Entity> entity(dtd->lookupEntity(isParameter, name));
458 // Did we find it in pass1Dtd?
459 // Did we look at the defaultEntity?
460 if (!inInstance_ && pass2() && dtd->isBase()
461 && !resultAttributeSpecMode_
462 && (entity.isNull() || !entity->declInActiveLpd())) {
463 ConstPtr<Entity> entity1
464 = pass1Dtd_->lookupEntity(isParameter, name);
465 if (!entity1.isNull() && entity1->declInActiveLpd()
466 && !entity1->defaulted()) {
468 noteReferencedEntity(entity1, 1, 0);
471 else if (!entity.isNull()) {
473 noteReferencedEntity(entity, 0, 0);
478 else if (!entity.isNull()) {
483 ConstPtr<Entity> entity(dtd->defaultEntity());
485 Boolean usedPass1 = 0;
486 if (!inInstance_ && pass2() && dtd->isBase()
487 && !resultAttributeSpecMode_
488 && (entity.isNull() || !entity->declInActiveLpd())) {
491 ConstPtr<Entity> entity1 = pass1Dtd_->defaultEntity();
492 if (!entity1.isNull() && entity1->declInActiveLpd()) {
497 if (!entity.isNull()) {
498 Boolean mustCopy = 1;
501 = instanceDefaultedEntityTable_.lookupConst(name);
508 Ptr<Entity> p(entity->copy());
510 p->generateSystemId(*this);
514 instanceDefaultedEntityTable_.insert(p);
515 eventHandler().entityDefaulted(new (eventAllocator())
516 EntityDefaultedEvent(entity,
520 dtd->insertEntity(p);
523 noteReferencedEntity(entity, usedPass1, 1);
531 void ParserState::noteReferencedEntity(const ConstPtr<Entity> &entity,
532 Boolean foundInPass1Dtd,
533 Boolean lookedAtDefault)
537 ref.lookedAtDefault = lookedAtDefault;
538 ref.foundInPass1Dtd = foundInPass1Dtd;
539 LpdEntityRef *old = lpdEntityRefs_.lookup(ref);
541 lpdEntityRefs_.insert(new LpdEntityRef(ref));
544 // Compare entity definitions.
545 // e1 is the original (will not be an external non-text entity).
546 // FIXME should look at generated sysids as well.
548 Boolean sameEntityDef(const Entity *e1, const Entity *e2)
550 if (e1->dataType() != e2->dataType())
552 const InternalEntity *i1 = e1->asInternalEntity();
553 const InternalEntity *i2 = e2->asInternalEntity();
557 if (i1->string() != i2->string())
563 const ExternalEntity *x1 = e1->asExternalEntity();
564 const ExternalEntity *x2 = e2->asExternalEntity();
565 const StringC *s1 = x1->externalId().systemIdString();
566 const StringC *s2 = x2->externalId().systemIdString();
575 s1 = x1->externalId().publicIdString();
576 s2 = x2->externalId().publicIdString();
588 void ParserState::checkEntityStability()
590 LpdEntityRefSetIter iter(lpdEntityRefs_);
592 while ((ref = iter.next()) != 0) {
593 ConstPtr<Entity> entity
594 = dtd_[0]->lookupEntity(ref->entity->declType()
595 == Entity::parameterEntity,
596 ref->entity->name());
597 if (entity.isNull() && ref->lookedAtDefault)
598 entity = dtd_[0]->defaultEntity();
600 ? ref->foundInPass1Dtd
601 : !sameEntityDef(ref->entity.pointer(), entity.pointer()))
602 message(((ref->entity->declType()
603 == Entity::parameterEntity)
604 ? ParserMessages::unstableLpdParameterEntity
605 : ParserMessages::unstableLpdGeneralEntity),
606 StringMessageArg(ref->entity->name()));
609 // Ensure that the memory is released.
611 lpdEntityRefs_.swap(tem);
615 Boolean ParserState::appendCurrentRank(StringC &str, const RankStem *stem)
618 const StringC &suffix = currentRank_[stem->index()];
619 if (suffix.size() > 0) {
626 void ParserState::setCurrentRank(const RankStem *stem, const StringC &suffix)
628 currentRank_[stem->index()] = suffix;
631 void ParserState::getCurrentToken(const SubstTable<Char> *subst,
634 InputSource *in = currentInput();
635 const Char *p = in->currentTokenStart();
636 size_t count = in->currentTokenLength();
638 StringC::iterator s = str.begin();
639 for (; count > 0; --count)
640 *s++ = (*subst)[*p++];
643 void ParserState::queueMessage(MessageEvent *event)
649 if (keepingMessages_)
650 keptMessages_.append(event);
652 handler_->message(event);
655 void ParserState::releaseKeptMessages()
657 keepingMessages_ = 0;
658 while (!keptMessages_.empty()) {
663 handler_->message(keptMessages_.get());
667 void ParserState::discardKeptMessages()
669 keepingMessages_ = 0;
670 keptMessages_.clear();
673 void ParserState::initMessage(Message &msg)
676 StringC rniPcdata = syntax().delimGeneral(Syntax::dRNI);
677 rniPcdata += syntax().reservedName(Syntax::rPCDATA);
678 getOpenElementInfo(msg.openElementInfo, rniPcdata);
680 msg.loc = currentLocation();
683 void ParserState::dispatchMessage(Message &msg)
685 queueMessage(new MessageEvent(msg));
688 void ParserState::dispatchMessage(const Message &msg)
690 queueMessage(new MessageEvent(msg));
694 ParserState::allocAttributeList(const ConstPtr<AttributeDefinitionList> &def,
697 if (i < attributeLists_.size())
698 attributeLists_[i]->init(def);
700 attributeLists_.resize(i + 1);
701 attributeLists_[i] = new AttributeList(def);
703 return attributeLists_[i].pointer();
706 void ParserState::activateLinkType(const StringC &name)
708 if (!hadPass2Start_ && !pass2_)
709 activeLinkTypes_.push_back(name);
711 message(ParserMessages::linkActivateTooLate);
714 Boolean ParserState::shouldActivateLink(const StringC &name) const
716 if (!activeLinkTypesSubsted_) {
718 ParserState *state = (ParserState *)this;
719 for (size_t i = 0; i < activeLinkTypes_.size(); i++)
720 for (size_t j = 0; j < activeLinkTypes_[i].size(); j++)
721 syntax().generalSubstTable()->subst(state->activeLinkTypes_[i][j]);
722 state->activeLinkTypesSubsted_ = 1;
724 for (size_t i = 0; i < activeLinkTypes_.size(); i++)
725 if (name == activeLinkTypes_[i])
730 Ptr<Dtd> ParserState::lookupDtd(const StringC &name)
732 for (size_t i = 0; i < dtd_.size(); i++)
733 if (dtd_[i]->name() == name)
738 ConstPtr<Lpd> ParserState::lookupLpd(const StringC &name) const
740 for (size_t i = 0; i < allLpd_.size(); i++)
741 if (allLpd_[i]->name() == name)
743 return ConstPtr<Lpd>();
746 ConstPtr<Notation> ParserState::getAttributeNotation(const StringC &name,
749 ConstPtr<Notation> notation;
750 if (haveCurrentDtd())
751 notation = currentDtd().lookupNotation(name);
752 else if (resultAttributeSpecMode_) {
753 const Dtd *resultDtd = defComplexLpd().resultDtd().pointer();
756 notation = resultDtd->lookupNotation(name);
761 ConstPtr<Entity> ParserState::getAttributeEntity(const StringC &str,
764 ConstPtr<Entity> entity = lookupEntity(0, str, loc, 0);
766 && entity->defaulted()
767 && options().warnDefaultEntityReference) {
768 setNextLocation(loc);
769 message(ParserMessages::defaultEntityInAttribute,
770 StringMessageArg(str));
775 Boolean ParserState::defineId(const StringC &str, const Location &loc,
780 Id *id = lookupCreateId(str);
782 prevLoc = id->defLocation();
789 void ParserState::noteIdref(const StringC &str, const Location &loc)
791 if (!inInstance() || !options().errorIdref)
793 Id *id = lookupCreateId(str);
795 id->addPendingRef(loc);
798 void ParserState::noteCurrentAttribute(size_t i, AttributeValue *value)
801 currentAttributes_[i] = value;
804 ConstPtr<AttributeValue> ParserState::getCurrentAttribute(size_t i) const
806 return currentAttributes_[i];
809 const Syntax &ParserState::attributeSyntax() const