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