Link with C++ linker
[oweals/cde.git] / cde / programs / nsgmls / ParserState.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: 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.
26
27 #ifdef __GNUG__
28 #pragma implementation
29 #endif
30 #include "splib.h"
31 #include "ParserState.h"
32 #include "InternalInputSource.h"
33 #include "MessageArg.h"
34 #include "macros.h"
35 #include "SgmlParser.h"
36 #include "IListIter.h"
37 #include "ParserMessages.h"
38 #include "Undo.h"
39
40 #ifdef SP_NAMESPACE
41 namespace SP_NAMESPACE {
42 #endif
43
44 const Location ParserState::nullLocation_;
45 sig_atomic_t ParserState::dummyCancel_ = 0;
46
47 static const size_t eventSizes[] = {
48 #define EVENT(c, f) sizeof(c),
49 #include "events.h"
50 #undef EVENT
51 };
52
53 static const size_t internalSizes[] = {
54   sizeof(InternalInputSource),
55   sizeof(EntityOrigin),
56   sizeof(OpenElement),
57   sizeof(UndoStartTag),
58   sizeof(UndoEndTag),
59   sizeof(UndoTransition)
60 };
61
62 static
63 size_t maxSize(const size_t *v, size_t n)
64 {
65   size_t max = 0;
66   for (size_t i = 0; i < n; i++) {
67     if (v[i] > max)
68       max = v[i];
69   }
70   return max;
71 }
72
73 ParserState::ParserState(const Ptr<EntityManager> &em,
74                          const ParserOptions &opt,
75                          unsigned subdocLevel,
76                          Phase finalPhase)
77 : entityManager_(em),
78   options_(opt),
79   inInstance_(0),
80   keepingMessages_(0),
81   eventAllocator_(maxSize(eventSizes, SIZEOF(eventSizes)), 50),
82   internalAllocator_(maxSize(internalSizes, SIZEOF(internalSizes)), 50),
83   handler_(&eventQueue_),
84   subdocLevel_(subdocLevel),
85   inputLevel_(0),
86   specialParseInputLevel_(0),
87   markedSectionLevel_(0),
88   markedSectionSpecialLevel_(0),
89   currentMode_(proMode),
90   hadLpd_(0),
91   resultAttributeSpecMode_(0),
92   pass2_(0),
93   activeLinkTypesSubsted_(0),
94   allowPass2_(0),
95   hadPass2Start_(0),
96   pcdataRecovering_(0),
97   currentMarkup_(0),
98   cancelPtr_(&dummyCancel_),
99   finalPhase_(finalPhase),
100   hadAfdrDecl_(0)
101 {
102 }
103
104 void ParserState::inheritActiveLinkTypes(const ParserState &parent)
105 {
106   activeLinkTypes_ = parent.activeLinkTypes_;
107   activeLinkTypesSubsted_ = parent.activeLinkTypesSubsted_;
108 }
109
110 void ParserState::allDone()
111 {
112   phase_ = noPhase;
113 }
114
115 void ParserState::setPass2Start()
116 {
117   ASSERT(inputLevel_ == 1);
118   if (hadPass2Start_)
119     return;
120   hadPass2Start_ = 1;
121   if (!pass2() && sd().link() && activeLinkTypes_.size() > 0) {
122     allowPass2_ = 1;
123     pass1Handler_.init(handler_);
124     handler_ = &pass1Handler_;
125     const InputSourceOrigin *p
126       = currentLocation().origin()->asInputSourceOrigin();
127     pass2StartOffset_= p->startOffset(currentLocation().index());
128   }
129   else {
130     allowPass2_ = 0;
131     currentInput()->willNotRewind();
132   }
133 }
134
135 void ParserState::allLinkTypesActivated()
136 {
137   if (activeLinkTypes_.size() == 0 && inputLevel_ == 1)
138     currentInput()->willNotRewind();
139 }
140
141 Boolean ParserState::maybeStartPass2()
142 {
143   if (pass2_ || !allowPass2_)
144     return 0;
145   handler_ = pass1Handler_.origHandler();
146   if (!nActiveLink() || pass1Handler_.hadError()) {
147     while (!pass1Handler_.empty()) {
148       if (cancelled())
149         return 0;
150       pass1Handler_.get()->handle(*handler_);
151     }
152     InputSource *top = 0;
153     for (IListIter<InputSource> iter(inputStack_);
154          !iter.done();
155          iter.next())
156       top = iter.cur();
157     if (top)
158       top->willNotRewind();
159     return 0;
160   }
161   pass1Handler_.clear();
162   while (inputLevel_ > 1) {
163     InputSource *p = inputStack_.get();
164     inputLevel_--;
165     delete p;
166   }
167   // Caller will call allDone() if inputLevel_ is 0.
168   if (inputLevel_ == 0)
169     return 0;
170   if (!inputStack_.head()->rewind(*this)) {
171     inputLevel_ = 0;
172     delete inputStack_.get();
173     return 0;
174   }
175   inputStack_.head()->willNotRewind();
176   for (; pass2StartOffset_ > 0; pass2StartOffset_--)
177     if (inputStack_.head()->get(messenger()) == InputSource::eE) {
178       message(ParserMessages::pass2Ee);
179       inputLevel_ = 0;
180       delete inputStack_.get();
181       return 0;
182     }
183   specialParseInputLevel_ = 0;
184   markedSectionLevel_ = 0;
185   markedSectionSpecialLevel_ = 0;
186   currentMode_ = proMode;
187   hadLpd_ = 0;
188   allowPass2_ = 0;
189   hadPass2Start_ = 0;
190   currentMarkup_ = 0;
191   inputLevel_ = 1;
192   inInstance_ = 0;
193   defDtd_.clear();
194   defLpd_.clear();
195   dtd_[0].swap(pass1Dtd_);
196   dtd_.clear();
197   dsEntity_.clear();
198   currentDtd_.clear();
199   phase_ = noPhase;
200   pass2_ = 1;
201   lpd_.clear();
202   allLpd_.clear();
203   return 1;
204 }
205
206 Boolean ParserState::referenceDsEntity(const Location &loc)
207 {
208   if (dsEntity_.isNull())
209     return 0;
210   Ptr<EntityOrigin> origin
211     = new (internalAllocator()) EntityOrigin(dsEntity_, loc);
212   dsEntity_->dsReference(*this, origin);
213   dsEntity_.clear();
214   return inputLevel() > 1;
215 }
216
217 void ParserState::startDtd(const StringC &name)
218 {
219   defDtd_ = new Dtd(name, dtd_.size() == 0);
220   defLpd_.clear();
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]);
226     Text text;
227     text.addChars(syntax().reservedName(Syntax::rINCLUDE), Location());
228     Entity *entity
229       = new InternalTextEntity(name,
230                                Entity::parameterEntity,
231                                Location(),
232                                text,
233                                InternalTextEntity::none);
234     entity->setUsed();
235     defDtd_->insertEntity(entity);
236   }
237   currentDtd_ = defDtd_;
238   currentMode_ = dsMode;
239 }
240
241 void ParserState::endDtd()
242 {
243   dtd_.push_back(defDtd_);
244   defDtd_.clear();
245   currentDtd_.clear();
246   currentMode_ = proMode;
247 }
248
249 void ParserState::startLpd(Ptr<Lpd> &lpd)
250 {
251   defLpd_ = lpd;
252   defDtd_ = defLpd_->sourceDtd();
253   currentDtd_ = defLpd_->sourceDtd();
254   currentMode_ = dsMode;
255 }
256
257 void ParserState::endLpd()
258 {
259   hadLpd_ = 1;
260   if (defLpd_->active())
261     lpd_.push_back(defLpd_);
262   allLpd_.push_back(defLpd_);
263   defLpd_.clear();
264   currentDtd_.clear();
265   currentMode_ = proMode;
266 }
267
268 void ParserState::popInputStack()
269 {
270   ASSERT(inputLevel_ > 0);
271   InputSource *p = inputStack_.get();
272   inputLevel_--;
273   delete p;
274   if (specialParseInputLevel_ > 0 && inputLevel_ == specialParseInputLevel_)
275     currentMode_ = specialParseMode_;
276   if (currentMode_ == dsiMode
277       && inputLevel_ == 1
278       && markedSectionLevel_ == 0)
279     currentMode_ = dsMode;
280 }
281
282 void ParserState::setSd(ConstPtr<Sd> sd)
283 {
284   sd_ = sd;
285   mayDefaultAttribute_ = (sd_->omittag() || sd_->shorttag());
286 }
287
288 void ParserState::setSyntax(ConstPtr<Syntax> syntax)
289 {
290   syntax_ = syntax;
291   prologSyntax_ = syntax;
292   instanceSyntax_ = syntax;
293 }
294
295 void ParserState::setSyntaxes(ConstPtr<Syntax> prologSyntax,
296                               ConstPtr<Syntax> instanceSyntax)
297 {
298   syntax_ = prologSyntax;
299   prologSyntax_ = prologSyntax;
300   instanceSyntax_ = instanceSyntax;
301 }
302
303 void ParserState::pushInput(InputSource *in)
304 {
305   if (!in)
306     return;
307   if (!syntax_.isNull() && syntax_->multicode())
308     in->setMarkupScanTable(syntax_->markupScanTable());
309   inputStack_.insert(in);
310   inputLevel_++;
311   if (specialParseInputLevel_ > 0 && inputLevel_ > specialParseInputLevel_)
312     currentMode_ = rcconeMode;  // mode for rcdata in an entity
313   else if (currentMode_ == dsMode)
314     currentMode_ = dsiMode;
315 }
316
317 void ParserState::startMarkedSection(const Location &loc)
318 {
319   markedSectionLevel_++;
320   markedSectionStartLocation_.push_back(loc);
321   if (currentMode_ == dsMode)
322     currentMode_ = dsiMode;
323   if (markedSectionSpecialLevel_)
324     markedSectionSpecialLevel_++;
325 }
326
327 void ParserState::startSpecialMarkedSection(Mode mode, const Location &loc)
328 {
329   markedSectionLevel_++;
330   markedSectionStartLocation_.push_back(loc);
331   specialParseInputLevel_ = inputLevel_;
332   markedSectionSpecialLevel_ = 1;
333   specialParseMode_ = currentMode_ = mode;
334 }
335
336 void ParserState::endMarkedSection()
337 {
338   ASSERT(markedSectionLevel_ > 0);
339   markedSectionLevel_--;
340   markedSectionStartLocation_.resize(markedSectionStartLocation_.size()
341                                         - 1);
342   if (markedSectionSpecialLevel_ > 0) {
343     markedSectionSpecialLevel_--;
344     if (markedSectionSpecialLevel_ > 0)
345       return;                   // remain in imsMode
346     specialParseInputLevel_ = 0;
347     if (inInstance_)
348       currentMode_ = contentMode();
349     else
350       currentMode_ = dsiMode;
351   }
352   if (currentMode_ == dsiMode
353       && inputLevel_ == 1
354       && markedSectionLevel_ == 0)
355     currentMode_ = dsMode;
356 }
357
358 void ParserState::pushElement(OpenElement *e)
359 {
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_;
369     }
370   }
371 }
372
373 // PCDATA was encountered somewhere where it was not allowed.
374 // Change the current mode to improve recovery.
375
376 void ParserState::pcdataRecover()
377 {
378   switch (currentMode_) {
379   case econMode:
380     currentMode_ = mconMode;
381     break;
382   case econnetMode:
383     currentMode_ = mconnetMode;
384     break;
385   default:
386     break;
387   }
388   pcdataRecovering_ = 1;
389 }
390
391 OpenElement *ParserState::popSaveElement()
392 {
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;
399   }
400   pcdataRecovering_ = 0;
401   return e;
402 }
403
404 void ParserState::popElement()
405 {
406   delete popSaveElement();
407 }
408                               
409 Boolean ParserState::entityIsOpen(const Entity *entity) const
410 {
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)
415       return 1;
416   }
417   return 0;
418 }
419
420 void ParserState::startInstance()
421 {
422   if (!instanceSyntax_.isNull())
423     syntax_ = instanceSyntax_;
424   currentMode_ = econMode;
425   currentDtd_ = dtd_[0];
426   startContent(currentDtd());
427   inInstance_ = 1;
428   if (sd().rank())
429     currentRank_.assign(currentDtd().nRankStem(), StringC());
430   currentAttributes_.clear();
431   currentAttributes_.resize(currentDtd().nCurrentAttribute());
432   idTable_.clear();
433 }
434
435 Id *ParserState::lookupCreateId(const StringC &name)
436 {
437   Id *id = idTable_.lookup(name);
438   if (!id) {
439     id = new Id(name);
440     idTable_.insert(id);
441   }
442   return id;
443 }
444
445 ConstPtr<Entity>
446 ParserState::lookupEntity(Boolean isParameter,
447                           const StringC &name,
448                           const Location &useLocation,
449                           Boolean referenced)
450 {
451   Dtd *dtd;
452   if (resultAttributeSpecMode_)
453     dtd = defComplexLpd().resultDtd().pointer();
454   else
455     dtd = (Dtd *)currentDtd_.pointer();
456   if (dtd) {
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()) {
467         if (referenced)
468           noteReferencedEntity(entity1, 1, 0);
469         return entity1;
470       }
471       else if (!entity.isNull()) {
472         if (referenced)
473           noteReferencedEntity(entity, 0, 0);
474         entity->setUsed();
475         return entity;
476       }
477     }
478     else if (!entity.isNull()) {
479       entity->setUsed();
480       return entity;
481     }
482     if (!isParameter) {
483       ConstPtr<Entity> entity(dtd->defaultEntity());
484       Boolean note = 0;
485       Boolean usedPass1 = 0;
486       if (!inInstance_ && pass2() && dtd->isBase()
487           && !resultAttributeSpecMode_
488           && (entity.isNull() || !entity->declInActiveLpd())) {
489         if (referenced)
490           note = 1;
491         ConstPtr<Entity> entity1 = pass1Dtd_->defaultEntity();
492         if (!entity1.isNull() && entity1->declInActiveLpd()) {
493           usedPass1 = 1;
494           entity = entity1;
495         }
496       }
497       if (!entity.isNull()) {
498         Boolean mustCopy = 1;
499         if (inInstance_) {
500           ConstPtr<Entity> tem 
501             = instanceDefaultedEntityTable_.lookupConst(name);
502           if (!tem.isNull()) {
503             entity = tem;
504             mustCopy = 0;
505           }
506         }
507         if (mustCopy) {
508           Ptr<Entity> p(entity->copy());
509           p->setName(name);
510           p->generateSystemId(*this);
511           p->setDefaulted();
512           entity = p;
513           if (inInstance_) {
514             instanceDefaultedEntityTable_.insert(p);
515             eventHandler().entityDefaulted(new (eventAllocator())
516                                            EntityDefaultedEvent(entity,
517                                                                 useLocation));
518           }
519           else
520             dtd->insertEntity(p);
521         }
522         if (note)
523           noteReferencedEntity(entity, usedPass1, 1);
524       }
525       return entity;
526     }
527   }
528   return (Entity *)0;
529 }
530
531 void ParserState::noteReferencedEntity(const ConstPtr<Entity> &entity,
532                                        Boolean foundInPass1Dtd,
533                                        Boolean lookedAtDefault)
534 {
535   LpdEntityRef ref;
536   ref.entity = entity;
537   ref.lookedAtDefault = lookedAtDefault;
538   ref.foundInPass1Dtd = foundInPass1Dtd;
539   LpdEntityRef *old = lpdEntityRefs_.lookup(ref);
540   if (!old)
541     lpdEntityRefs_.insert(new LpdEntityRef(ref));
542 }
543
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.
547 static
548 Boolean sameEntityDef(const Entity *e1, const Entity *e2)
549 {
550   if (e1->dataType() != e2->dataType())
551     return 0;
552   const InternalEntity *i1 = e1->asInternalEntity();
553   const InternalEntity *i2 = e2->asInternalEntity();
554   if (i1) {
555     if (!i2)
556       return 0;
557     if (i1->string() != i2->string())
558       return 0;
559     return 1;
560   }
561   else if (i2)
562     return 0;
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();
567   if (s1) {
568     if (!s2)
569       return 0;
570     if (*s1 != *s2)
571       return 0;
572   }
573   else if (s2)
574     return 0;
575   s1 = x1->externalId().publicIdString();
576   s2 = x2->externalId().publicIdString();
577   if (s1) {
578     if (!s2)
579       return 0;
580     if (*s1 != *s2)
581       return 0;
582   }
583   else if (s2)
584     return 0;
585   return 1;
586 }
587
588 void ParserState::checkEntityStability()
589 {
590   LpdEntityRefSetIter iter(lpdEntityRefs_);
591   LpdEntityRef *ref;
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();
599     if (entity.isNull()
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()));
607   }
608   {
609     // Ensure that the memory is released.
610     LpdEntityRefSet tem;
611     lpdEntityRefs_.swap(tem);
612   }
613 }    
614
615 Boolean ParserState::appendCurrentRank(StringC &str, const RankStem *stem)
616      const
617 {
618   const StringC &suffix = currentRank_[stem->index()];
619   if (suffix.size() > 0) {
620     str += suffix;
621     return 1;
622   }
623   return 0;
624 }
625
626 void ParserState::setCurrentRank(const RankStem *stem, const StringC &suffix)
627 {
628   currentRank_[stem->index()] = suffix;
629 }
630
631 void ParserState::getCurrentToken(const SubstTable<Char> *subst,
632                                   StringC &str) const
633 {
634   InputSource *in = currentInput();
635   const Char *p = in->currentTokenStart();
636   size_t count = in->currentTokenLength();
637   str.resize(count);
638   StringC::iterator s = str.begin();
639   for (; count > 0; --count)
640     *s++ = (*subst)[*p++];
641 }
642
643 void ParserState::queueMessage(MessageEvent *event)
644 {
645   if (cancelled()) {
646     delete event;
647     return;
648   }
649   if (keepingMessages_)
650     keptMessages_.append(event);
651   else
652     handler_->message(event);
653 }
654
655 void ParserState::releaseKeptMessages()
656 {
657   keepingMessages_ = 0;
658   while (!keptMessages_.empty()) {
659     if (cancelled()) {
660       allDone();
661       return;
662     }
663     handler_->message(keptMessages_.get());
664   }
665 }
666
667 void ParserState::discardKeptMessages()
668 {
669   keepingMessages_ = 0;
670   keptMessages_.clear();
671 }
672
673 void ParserState::initMessage(Message &msg)
674 {
675   if (inInstance()) {
676     StringC rniPcdata = syntax().delimGeneral(Syntax::dRNI);
677     rniPcdata += syntax().reservedName(Syntax::rPCDATA);
678     getOpenElementInfo(msg.openElementInfo, rniPcdata);
679   }
680   msg.loc = currentLocation();
681 }
682
683 void ParserState::dispatchMessage(Message &msg)
684 {
685   queueMessage(new MessageEvent(msg));
686 }
687
688 void ParserState::dispatchMessage(const Message &msg)
689 {
690   queueMessage(new MessageEvent(msg));
691 }
692
693 AttributeList *
694 ParserState::allocAttributeList(const ConstPtr<AttributeDefinitionList> &def,
695                                 unsigned i)
696 {
697   if (i < attributeLists_.size())
698     attributeLists_[i]->init(def);
699   else {
700     attributeLists_.resize(i + 1);
701     attributeLists_[i] = new AttributeList(def);
702   }
703   return attributeLists_[i].pointer();
704 }
705
706 void ParserState::activateLinkType(const StringC &name)
707 {
708   if (!hadPass2Start_ && !pass2_)
709     activeLinkTypes_.push_back(name);
710   else
711     message(ParserMessages::linkActivateTooLate);
712 }
713
714 Boolean ParserState::shouldActivateLink(const StringC &name) const
715 {
716   if (!activeLinkTypesSubsted_) {
717     // FIXME use mutable
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;
723   }
724   for (size_t i = 0; i < activeLinkTypes_.size(); i++)
725     if (name == activeLinkTypes_[i])
726       return 1;
727   return 0;
728 }
729
730 Ptr<Dtd> ParserState::lookupDtd(const StringC &name)
731 {
732   for (size_t i = 0; i < dtd_.size(); i++)
733     if (dtd_[i]->name() == name)
734       return dtd_[i];
735   return Ptr<Dtd>();
736 }
737
738 ConstPtr<Lpd> ParserState::lookupLpd(const StringC &name) const
739 {
740   for (size_t i = 0; i < allLpd_.size(); i++)
741     if (allLpd_[i]->name() == name)
742       return allLpd_[i];
743   return ConstPtr<Lpd>();
744 }
745
746 ConstPtr<Notation> ParserState::getAttributeNotation(const StringC &name,
747                                                      const Location &)
748 {
749   ConstPtr<Notation> notation;
750   if (haveCurrentDtd())
751     notation = currentDtd().lookupNotation(name);
752   else if (resultAttributeSpecMode_) {
753     const Dtd *resultDtd = defComplexLpd().resultDtd().pointer();
754     if (!resultDtd)
755       return 0;
756     notation = resultDtd->lookupNotation(name);
757   }
758   return notation; 
759 }
760
761 ConstPtr<Entity> ParserState::getAttributeEntity(const StringC &str,
762                                                  const Location &loc)
763 {
764   ConstPtr<Entity> entity = lookupEntity(0, str, loc, 0);
765   if (!entity.isNull()
766       && entity->defaulted()
767       && options().warnDefaultEntityReference) {
768     setNextLocation(loc);
769     message(ParserMessages::defaultEntityInAttribute,
770             StringMessageArg(str));
771   }
772   return entity;
773 }
774
775 Boolean ParserState::defineId(const StringC &str, const Location &loc,
776                               Location &prevLoc)
777 {
778   if (!inInstance())
779     return 1;
780   Id *id = lookupCreateId(str);
781   if (id->defined()) {
782     prevLoc = id->defLocation();
783     return 0;
784   }
785   id->define(loc);
786   return 1;
787 }
788
789 void ParserState::noteIdref(const StringC &str, const Location &loc)
790 {
791   if (!inInstance() || !options().errorIdref)
792     return;
793   Id *id = lookupCreateId(str);
794   if (!id->defined())
795     id->addPendingRef(loc);
796 }
797
798 void ParserState::noteCurrentAttribute(size_t i, AttributeValue *value)
799 {
800   if (inInstance())
801     currentAttributes_[i] = value;
802 }
803
804 ConstPtr<AttributeValue> ParserState::getCurrentAttribute(size_t i) const
805 {
806   return currentAttributes_[i];
807 }
808
809 const Syntax &ParserState::attributeSyntax() const
810 {
811   return syntax();
812 }
813
814 #ifdef SP_NAMESPACE
815 }
816 #endif