Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / nsgmls / RastEventHandler.C
1 /* $XConsortium: RastEventHandler.C /main/1 1996/07/29 17:02:26 cde-hp $ */
2 // Copyright (c) 1994,1995 James Clark
3 // See the file COPYING for copying permission.
4
5 #ifdef __GNUG__
6 #pragma implementation
7 #endif
8
9 #include "config.h"
10 #include "RastEventHandler.h"
11 #include "SgmlParser.h"
12 #include "ParserOptions.h"
13 #include "Entity.h"
14 #include "Notation.h"
15 #include "Attribute.h"
16 #include "Vector.h"
17 #include "Vector.h"
18 #include "MessageArg.h"
19
20 #include "RastEventHandlerMessages.h"
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 // This is based on ISO/IEC 13673, Intermediate Editor's Draft, 1994/8/29,
26 // together with editing instructions in ISO/IEC JTC1/SC18/WG8 N1777.
27
28 #ifdef SP_NAMESPACE
29 namespace SP_NAMESPACE {
30 #endif
31
32 const OutputCharStream::Newline nl = OutputCharStream::newline;
33
34 class EventHandlerMessenger : public Messenger {
35 public:
36   EventHandlerMessenger(EventHandler *eh) : eh_(eh) { }
37   void dispatchMessage(const Message &message) {
38     eh_->message(new MessageEvent(message));
39   }
40   void dispatchMessage(Message &message) {
41     eh_->message(new MessageEvent(message));
42   }
43 private:
44   EventHandler *eh_;
45 };
46
47 #if 0
48 const 
49 #endif
50 RastPrintable RastEventHandler::printable;
51
52 RastPrintable::RastPrintable()
53 {
54   static const char s[] =
55     " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
56   size_t i;
57   for (i = 0; i < sizeof(v_); i++)
58     v_[i] = 0;
59   for (i = 0; s[i] != '\0'; i++)
60     v_[(unsigned char)s[i]] = 32 + i;
61 }
62
63 // inline
64 void RastEventHandler::flushLine(LineType type)
65 {
66   if (lineLength_ > 0) {
67     os() << char(type) << nl;
68     lineLength_ = 0;
69   }
70 }
71
72 RastSubdocState::RastSubdocState()
73 {
74   init(0, 0);
75 }
76
77 RastSubdocState::RastSubdocState(SgmlParser *parser, RastEventHandler *rast)
78 {
79   init(parser, rast);
80 }
81
82 void RastSubdocState::init(SgmlParser *parser, RastEventHandler *rast)
83 {
84   parser_ = parser;
85   hadActiveLpdOrDtd_ = 0;
86   activeLinkTypes_.clear();
87   hadDocumentElement_ = 0;
88   linkProcess_.clear();
89   linkProcess_.setHandler(rast);
90   haveLinkProcess_ = 0;
91   endPrologEvent_.clear();
92   parseSubdocQueue_.clear();
93   linkRuleQueue_.clear();
94   for (int i = 0; i < nAttributeType; i++)
95     attributeSortOrder_[i].clear();
96 }
97
98 void RastSubdocState::swap(RastSubdocState &to)
99 {
100   {
101     SgmlParser *tem = to.parser_;
102     to.parser_ = parser_;
103     parser_ = tem;
104   }
105   {
106     Boolean tem = to.hadActiveLpdOrDtd_;
107     to.hadActiveLpdOrDtd_ = hadActiveLpdOrDtd_;
108     hadActiveLpdOrDtd_ = tem;
109   }
110   {
111     Boolean tem = to.hadDocumentElement_;
112     to.hadDocumentElement_ = hadDocumentElement_;
113     hadDocumentElement_ = tem;
114   }
115   activeLpdOrDtdLocation_.swap(to.activeLpdOrDtdLocation_);
116   activeLinkTypes_.swap(to.activeLinkTypes_);
117   linkProcess_.swap(to.linkProcess_);
118   endPrologEvent_.swap(to.endPrologEvent_);
119   parseSubdocQueue_.swap(to.parseSubdocQueue_);
120   linkRuleQueue_.swap(to.linkRuleQueue_);
121   for (int i = 0; i < nAttributeType; i++)
122     attributeSortOrder_[i].swap(to.attributeSortOrder_[i]);
123 }
124
125 RastEventHandler::RastEventHandler(SgmlParser *parser, Messenger *mgr)
126 : lineLength_(0),
127   os_(0),
128   piErrorCount_(0),
129   RastSubdocState(parser, this),
130   mgr_(mgr)
131 {
132   RastSubdocState::init(parser, this);
133 }
134
135 void RastEventHandler::end()
136 {
137   if (errorCount() != 0) {
138     truncateOutput();
139     os() << (piErrorCount_ != 0
140              ? "#RAST-PI-ERROR"
141              : "#ERROR")
142          << nl;
143   }
144 }
145
146 void RastEventHandler::truncateOutput()
147 {
148   // This must be handled by derived classes to get conforming output.
149 }
150
151 void RastEventHandler::sgmlDecl(SgmlDeclEvent *event)
152 {
153   rastParseSubdocYesString_ = event->sd().execToDoc("rast-parse-subdoc:yes");
154   rastParseSubdocNoString_ = event->sd().execToDoc("rast-parse-subdoc:no");
155   rastActiveLpdString_ = event->sd().execToDoc("rast-active-lpd:");
156   rastLinkRuleString_ = event->sd().execToDoc("rast-link-rule:");
157   delete event;
158 }
159
160 void RastEventHandler::startElement(StartElementEvent *event)
161 {
162   flushLine(dataLine);
163   if (!hadDocumentElement_) {
164     if (activeLinkTypes_.size() > 0) {
165       activeLinks();
166       simpleLinkInfo();
167     }
168     hadDocumentElement_ = 1;
169   }
170   os() << '[' << event->name();
171   Boolean hadNewline;
172   if (event->attributes().size() > 0) {
173     hadNewline = 1;
174     os() << nl;
175     attributeInfo(event->attributes(), dtdAttribute);
176   }
177   else
178     hadNewline = 0;
179   if (haveLinkProcess_) {
180     const AttributeList *linkAttributes;
181     const ResultElementSpec *resultElementSpec;
182     EventHandlerMessenger messenger(this);
183     linkProcess_.startElement(event->elementType(),
184                               event->attributes(),
185                               event->location(),
186                               messenger,
187                               linkAttributes,
188                               resultElementSpec);
189     if (linkProcess_.nImpliedLinkRules() > 0) {
190       if (!hadNewline) {
191         os() << nl;
192         hadNewline = 1;
193       }
194       os() << "#LINK-SET-INFO" << nl;
195       impliedSourceLinkRules();
196     }
197     if (linkAttributes) {
198       if (!hadNewline) {
199         os() << nl;
200         hadNewline = 1;
201       }
202       os() << "#LINK-RULE" << nl;
203       attributeInfo(*linkAttributes, linkAttribute);
204       if (linkProcess_.isExplicit()) {
205         os() << "#RESULT=";
206         if (resultElementSpec && resultElementSpec->elementType) {
207           os() << resultElementSpec->elementType->name() << nl;
208           attributeInfo(resultElementSpec->attributeList, resultAttribute);
209         }
210         else
211           os() << "#IMPLIED" << nl;
212       }
213     }
214     else
215       hadNewline = 0;
216   }
217   os() << ']' << nl;
218   delete event;
219 }
220
221 void RastEventHandler::activeLinks()
222 {
223   for (size_t i = 0; i < activeLinkTypes_.size(); i++) {
224     os() << "#ACTIVE-LINK=" << activeLinkTypes_[i] << nl;
225     Boolean found = 0;
226     if (haveLinkProcess_ && linkProcess_.name() == activeLinkTypes_[i]) {
227       found = 1;
228       if (linkProcess_.nImpliedLinkRules() > 0) {
229         os() << "#INITIAL" << nl;
230         impliedSourceLinkRules();
231       }
232     }
233     if (!found) {
234       if (endPrologEvent_) {
235         for (size_t j = 0; j < endPrologEvent_->simpleLinkNames().size(); j++)
236           if (endPrologEvent_->simpleLinkNames()[j] == activeLinkTypes_[i]) {
237             found = 1;
238             break;
239           }
240       }
241       if (!found) {
242         setNextLocation(activeLpdOrDtdLocation_);
243         Messenger::message(RastEventHandlerMessages::invalidActiveLinkType,
244                            StringMessageArg(activeLinkTypes_[i]));
245       }
246     }
247     os() << "#END-ACTIVE-LINK" << nl;
248   }
249 }
250
251 void RastEventHandler::simpleLinkInfo()
252 {
253   if (!endPrologEvent_)
254     return;
255   for (size_t i = 0; i < activeLinkTypes_.size(); i++) {
256     for (size_t j = 0; j < endPrologEvent_->simpleLinkNames().size(); j++) {
257       const StringC &name = endPrologEvent_->simpleLinkNames()[j];
258       if (name == activeLinkTypes_[i]) {
259         os() << "#SIMPLE-LINK=" << name << nl;
260         if (endPrologEvent_->simpleLinkAttributes()[j].size() > 0)
261           attributeInfo(endPrologEvent_->simpleLinkAttributes()[j],
262                         simpleAttribute);
263         os() << "#END-SIMPLE-LINK" << nl;
264         break;
265       }
266     }
267   }
268 }
269
270 void RastEventHandler::impliedSourceLinkRules()
271 {
272   size_t n = linkProcess_.nImpliedLinkRules();
273   Vector<size_t> sortOrder(n);
274   size_t i;
275   for (i = 0; i < n; i++)
276     sortOrder[i] = i;
277   for (i = 1; i < n; i++) {
278     size_t tem = sortOrder[i];
279     const StringC &name
280       = linkProcess_.impliedLinkRule(tem).elementType->name();
281     size_t j;
282     for (j = i; j > 0; j--) {
283       if (lexCmp(linkProcess_.impliedLinkRule(j - 1).elementType->name(),
284                  name) <= 0)
285         break;
286       sortOrder[j] = sortOrder[j - 1];
287     }
288     sortOrder[j] = tem;
289   }
290   for (i = 0; i < n; i++) {
291     const ResultElementSpec &result
292       = linkProcess_.impliedLinkRule(sortOrder[i]);
293     os() << '[' << result.elementType->name();
294     if (result.attributeList.size() > 0) {
295       os() << nl;
296       attributeInfo(result.attributeList, resultAttribute);
297     }
298     os() << ']' << nl;
299   }
300 }
301
302 void RastEventHandler::endElement(EndElementEvent *event)
303 {
304   if (haveLinkProcess_)
305     linkProcess_.endElement();
306   flushLine(dataLine);
307   os() << "[/" << event->name() << ']' << nl;
308   if (haveLinkProcess_ && linkProcess_.nImpliedLinkRules() > 0) {
309     os() << "#LINK-SET-INFO" << nl;
310     impliedSourceLinkRules();
311     os() << "#END-LINK-SET-INFO" << nl;
312   }
313   delete event;
314 }
315
316 void RastEventHandler::data(DataEvent *event)
317 {
318   lines(dataLine, event->data(), event->dataLength());
319   delete event;
320 }
321
322 void RastEventHandler::pi(PiEvent *event)
323 {
324   flushLine(dataLine);
325   os() << "[?";
326   size_t dataLength = event->dataLength();
327   if (dataLength > 0) {
328     const Char *data = event->data();
329     if (dataLength >= 4
330         && memcmp(data,
331                   rastParseSubdocYesString_.data(),
332                   4*sizeof(Char)) == 0
333         && !interpretRastPi(data, dataLength, event->location())) {
334       setNextLocation(event->location());
335       Messenger::message(RastEventHandlerMessages::invalidRastPiError);
336     }
337     os() << nl;
338     lines(dataLine, event->data(), dataLength);
339     flushLine(dataLine);
340   }
341   os() << ']' << nl;
342   delete event;
343 }
344
345 inline
346 Boolean equal(const Char *s1, size_t n1, const StringC &s2)
347 {
348   return (n1 == s2.size()
349           && (n1 == 0
350               || memcmp(s1, s2.data(), n1*sizeof(Char)) == 0));
351 }
352
353 // Is s2 a prefix of s1 of length n1?
354
355 inline
356 Boolean prefix(const Char *s1, size_t n1, const StringC &s2)
357 {
358   return (n1 >= s2.size()
359           && (n1 == 0
360               || memcmp(s1, s2.data(), s2.size()*sizeof(Char)) == 0));
361 }
362
363 Boolean RastEventHandler::interpretRastPi(const Char *data,
364                                           size_t dataLength,
365                                           const Location &loc)
366 {
367   if (equal(data, dataLength, rastParseSubdocNoString_)) {
368     queueParseSubdoc(0);
369     return 1;
370   }
371   if (equal(data, dataLength, rastParseSubdocYesString_)) {
372     queueParseSubdoc(1);
373     return 1;
374   }
375   if (prefix(data, dataLength, rastActiveLpdString_)) {
376     if (hadActiveLpdOrDtd_)
377       return 1;
378     hadActiveLpdOrDtd_ = 1;
379     activeLpdOrDtdLocation_ = loc;
380     const Char *p = data + rastActiveLpdString_.size();
381     size_t n = dataLength - rastActiveLpdString_.size();
382     StringC name;
383     for (;;) {
384       if (n == 0 || *p == ',') {
385         if (name.size() == 0)
386           return 0;
387         for (size_t i = 0; i < activeLinkTypes_.size(); i++)
388           if (name == activeLinkTypes_[i]) {
389             setNextLocation(activeLpdOrDtdLocation_);
390             Messenger::message(RastEventHandlerMessages::duplicateActiveLinkType,
391                                StringMessageArg(name));
392           }
393         activeLinkTypes_.resize(activeLinkTypes_.size() + 1);
394         name.swap(activeLinkTypes_.back());
395         if (n == 0)
396           break;
397       }
398       else
399         name += *p;
400       p++;
401       n--;
402     }
403     for (size_t i = 0; i < activeLinkTypes_.size(); i++)
404       parser_->activateLinkType(activeLinkTypes_[i]);
405     return 1;
406   }
407   if (prefix(data, dataLength, rastLinkRuleString_)) {
408     LinkRulePi *p = new LinkRulePi;
409     p->pi.assign(data + rastLinkRuleString_.size(),
410                  dataLength - rastLinkRuleString_.size());
411     p->loc = loc;
412     linkRuleQueue_.append(p);
413     return 1;
414   }
415   return 0;
416 }
417
418 void RastEventHandler::sdataEntity(SdataEntityEvent *event)
419 {
420   flushLine(dataLine);
421   os() << "#SDATA-TEXT" << nl;
422   lines(markupLine, event->data(), event->dataLength());
423   flushLine(markupLine);
424   os() << "#END-SDATA" << nl;
425   delete event;
426 }
427
428 void RastEventHandler::externalDataEntity(ExternalDataEntityEvent *event)
429 {
430   const ExternalDataEntity *entity = event->entity();
431   if (!entity)
432     return;
433   flushLine(dataLine);
434   os() << "[&" << entity->name() << nl;
435   externalEntityInfo(entity, dtdAttribute);
436   os() << ']' << nl;
437   delete event;
438 }
439
440 void RastEventHandler::externalEntityInfo(const ExternalDataEntity *entity,
441                                           AttributeType attributeType)
442 {
443   char c;
444   switch (entity->dataType()) {
445   case Entity::cdata:
446     c = 'C';
447     break;
448   case Entity::sdata:
449     c = 'S';
450     break;
451   case Entity::ndata:
452     c = 'N';
453     break;
454   default:
455     return;
456   }
457   os() << '#' << c << "DATA-EXTERNAL" << nl;
458   externalIdInfo(entity->externalId());
459   os() << "#NOTATION=" << entity->notation()->name() << nl;
460   externalIdInfo(entity->notation()->externalId());
461   attributeInfo(entity->attributes(),
462                 (attributeType == resultAttribute
463                  ? resultAttribute
464                  : dtdAttribute));
465 }
466
467 void RastEventHandler::subdocEntity(SubdocEntityEvent *event)
468 {
469   const SubdocEntity *entity = event->entity();
470   if (!entity)
471     return;
472   flushLine(dataLine);
473   os() << "[&" << entity->name() << nl;
474   Ptr<InputSourceOrigin> origin(event->entityOrigin()->copy());
475   subdocEntityInfo(entity, origin, 1);
476   os() << ']' << nl;
477   delete event;
478 }
479
480 void RastEventHandler::subdocEntityInfo(const SubdocEntity *entity,
481                                         const Ptr<InputSourceOrigin> &entityOrigin,
482                                         Boolean referenced)
483 {
484   os() << "#SUBDOC" << nl;
485   externalIdInfo(entity->externalId());
486   if (parseNextSubdoc()) {
487     // FIXME subdocuments in entity attributes shouldn't count against
488     // SUBDOC quantity limit.
489     os() << "#PARSED-SUBDOCUMENT" << nl;
490     SgmlParser::Params params;
491     params.entityType = SgmlParser::Params::subdoc;
492     params.subdocInheritActiveLinkTypes = 0;
493     params.subdocReferenced = referenced;
494     params.parent = parser_;
495     params.sysid = entity->externalId().effectiveSystemId();
496     params.origin = entityOrigin;
497     SgmlParser parser(params);
498     RastSubdocState oldSubdocState;
499     RastSubdocState::swap(oldSubdocState);
500     RastSubdocState::init(&parser, this);
501     parser.parseAll(*this);
502     oldSubdocState.swap(*this);
503   }
504 }
505
506 void RastEventHandler::queueParseSubdoc(Boolean parseSubdoc)
507 {
508   parseSubdocQueue_.push_back(PackedBoolean(parseSubdoc));
509 }
510
511 Boolean RastEventHandler::parseNextSubdoc()
512 {
513   if (parseSubdocQueue_.size() == 0)
514     return 0;
515   Boolean result = parseSubdocQueue_[0];
516   if (parseSubdocQueue_.size() > 1) {
517     for (size_t i = 1; i < parseSubdocQueue_.size(); i++)
518       parseSubdocQueue_[i - 1] = parseSubdocQueue_[i];
519   }
520   parseSubdocQueue_.resize(parseSubdocQueue_.size() - 1);
521   return result;
522 }
523
524
525 void RastEventHandler::externalIdInfo(const ExternalId &id)
526 {
527   const StringC *systemId = id.systemIdString();
528   const StringC *publicId = id.publicIdString();
529   if (publicId) {
530     os() << "#PUBLIC" << nl;
531     if (publicId->size() == 0)
532       os() << "#EMPTY" << nl;
533     else {
534       lines(markupLine, publicId->data(), publicId->size());
535       flushLine(markupLine);
536     }
537   }
538   if (systemId || !publicId) {
539     os() << "#SYSTEM" << nl;
540     if (!systemId)
541       os() << "#NONE" << nl;
542     else if (systemId->size() == 0)
543       os() << "#EMPTY" << nl;
544     else {
545       lines(markupLine, systemId->data(), systemId->size());
546       flushLine(markupLine);
547     }
548   }
549 }
550
551 void RastEventHandler::lines(LineType type, const Char *p, size_t length)
552 {
553   // This needs to be fast.
554   while (length != 0) {
555     if (printable(*p)) {
556       size_t lim;
557       switch (lineLength_) {
558       case maxLineLength:
559         os() << char(type) << nl;
560         lineLength_ = 0;
561         // fall through
562       case 0:
563         os() << char(type);
564         lim = maxLineLength;
565         break;
566       default:
567         lim = maxLineLength - lineLength_;
568         break;
569       }
570       if (lim > length)
571         lim = length;
572       size_t n = lim;
573       for (;;) {
574         os().put(*p);
575         p++;
576         if (--n == 0)
577           break;
578         if (!printable(*p)) {
579           lim -= n;
580           break;
581         }
582       }
583       length -= lim;
584       lineLength_ += lim;
585     }
586     else {
587       // *p is an unprintable character print it
588       flushLine(type);
589       switch (*p) {
590       case RS:
591         os() << "#RS" << nl;
592         break;
593       case RE:
594         os() << "#RE" << nl;
595         break;
596       case TAB:
597         os() << "#TAB" << nl;
598         break;
599       default:
600         os() << '#' << (unsigned long)*p << nl;
601         break;
602       }
603       p++;
604       length--;
605     }
606   }
607 }
608
609 int RastEventHandler::lexCmp(const StringC &s1, const StringC &s2)
610 {
611   const Char *p1 = s1.data();
612   size_t n1 = s1.size();
613   const Char *p2 = s2.data();
614   size_t n2 = s2.size();
615   for (;;) {
616     if (n1 == 0)
617       return n2 == 0 ? 0 : -1;
618     if (n2 == 0)
619       return 1;
620     if (*p1 != *p2) {
621       // printable characters precede non-printable characters;
622       // printable characters are in ASCII order
623       // non-printable characters are in document character set order
624       int a1 = printable(*p1);
625       int a2 = printable(*p2);
626       if (a1 == 0) {
627         if (a2 == 0)
628           return *p1 < *p2 ? -1 : 1;
629         else
630           return 1;
631       }
632       else if (a2 == 0)
633         return -1;
634       else
635         return a1 - a2;
636     }
637     p1++;
638     p2++;
639     n1--;
640     n2--;
641   }
642 }
643
644 void RastEventHandler::attributeInfo(const AttributeList &attributes,
645                                      AttributeType attributeType)
646 {
647   size_t length = attributes.size();
648   if (length == 0)
649     return;
650   size_t defIndex = attributes.defIndex();
651   if (defIndex >= attributeSortOrder_[attributeType].size())
652     attributeSortOrder_[attributeType].resize(defIndex + 1);
653   Vector<size_t> &sortOrder = attributeSortOrder_[attributeType][defIndex];
654   if (sortOrder.size() == 0
655       || attributeType == simpleAttribute) {
656     sortOrder.resize(length);
657     size_t i;
658     for (i = 0; i < length; i++)
659       sortOrder[i] = i;
660     // insertion sort
661     for (i = 1; i < length; i++) {
662       size_t tem = sortOrder[i];
663       size_t j;
664       for (j = i; j > 0; j--) {
665         if (lexCmp(attributes.name(sortOrder[j - 1]),
666                    attributes.name(tem)) <= 0)
667           break;
668         sortOrder[j] = sortOrder[j - 1];
669       }
670       sortOrder[j] = tem;
671     }
672   }
673   for (size_t j = 0; j < length; j++) {
674     // Don't use sortOrder because attributeSortOrder_ may be grown
675     // because of data attributes.
676     size_t i = attributeSortOrder_[attributeType][defIndex][j];
677     os() << attributes.name(i) << '=' << nl;
678     const Text *text;
679     const StringC *string;
680     const AttributeValue *value = attributes.value(i);
681     if (value) {
682       switch (value->info(text, string)) {
683       case AttributeValue::implied:
684         os() << "#IMPLIED" << nl;
685         break;
686       case AttributeValue::tokenized:
687         lines(markupLine, string->data(), string->size());
688         flushLine(markupLine);
689         break;
690       case AttributeValue::cdata:
691         {
692           TextIter iter(*text);
693           TextItem::Type type;
694           const Char *p;
695           size_t length;
696           const Location *loc;
697           while (iter.next(type, p, length, loc))
698             switch (type) {
699             case TextItem::data:
700             case TextItem::cdata:
701               lines(markupLine, p, length);
702               break;
703             case TextItem::sdata:
704               flushLine(markupLine);
705               os() << "#SDATA-TEXT" << nl;
706               lines(markupLine, p, length);
707               flushLine(markupLine);
708               os() << "#END-SDATA" << nl;
709               break;
710             default:
711               break;
712             }
713           flushLine(markupLine);
714         }
715         break;
716       }
717     }
718     const AttributeSemantics *semantics = attributes.semantics(i);
719     if (semantics) {
720       ConstPtr<Notation> notation
721         = semantics->notation();
722       if (!notation.isNull())
723         externalIdInfo(notation->externalId());
724       size_t nEntities = semantics->nEntities();
725       for (size_t i = 0; i < nEntities; i++) {
726         ConstPtr<Entity> entity
727           = semantics->entity(i);
728         if (!entity.isNull()) {
729           const ExternalDataEntity *externalDataEntity
730             = entity->asExternalDataEntity();
731           if (externalDataEntity)
732             externalEntityInfo(externalDataEntity,
733                                (attributeType == resultAttribute
734                                 ? resultAttribute
735                                 : dtdAttribute));
736           else {
737             const SubdocEntity *subdocEntity = entity->asSubdocEntity();
738             if (subdocEntity) {
739               Ptr<InputSourceOrigin> entityOrigin
740                 = new EntityOrigin(entity,
741                                    ((TokenizedAttributeValue *)value)
742                                    ->tokenLocation(i));
743               subdocEntityInfo(subdocEntity, entityOrigin, 0);
744             }
745             else {
746               const InternalEntity *internalEntity = entity->asInternalEntity();
747               if (internalEntity)
748                 internalEntityInfo(internalEntity);
749             }
750           }
751         }
752         os() << "#END-ENTITY" << nl;
753       }
754     }
755   }
756 }
757
758 void RastEventHandler::internalEntityInfo(const InternalEntity *entity)
759 {
760   if (!entity)
761     return;
762   os() << '#'
763        << char(entity->dataType() == Entity::cdata ? 'C' : 'S')
764        << "DATA-INTERNAL" << nl;
765   const StringC &str = entity->string();
766   lines(markupLine, str.data(), str.size());
767   flushLine(markupLine);
768 }
769
770 void RastEventHandler::endProlog(EndPrologEvent *event)
771 {
772   if (!event->lpdPointer().isNull()) {
773     linkProcess_.init(event->lpdPointer());
774     haveLinkProcess_ = 1;
775   }
776   if (event->simpleLinkNames().size() > 0)
777     endPrologEvent_ = event;
778   else
779     delete event;
780 }
781
782 void RastEventHandler::uselink(UselinkEvent *event)
783 {
784   linkProcess_.uselink(event->linkSet(),
785                        event->restore(),
786                        event->lpd().pointer());
787   if (haveLinkProcess_ && linkProcess_.nImpliedLinkRules() > 0) {
788     flushLine(dataLine);
789     os() << "#LINK-SET-INFO" << nl;
790     impliedSourceLinkRules();
791     os() << "#END-LINK-SET-INFO" << nl;
792   }
793   delete event;
794 }
795
796 void RastEventHandler::initMessage(Message &msg)
797 {
798   mgr_->initMessage(msg);
799 }
800
801 void RastEventHandler::dispatchMessage(Message &msg)
802 {
803   dispatchMessage((const Message &) msg);
804 }
805
806 void RastEventHandler::dispatchMessage(const Message &msg)
807 {
808   if (msg.isError())
809     piErrorCount_++;
810   if (!cancelled()) {
811     noteMessage(msg);
812     mgr_->dispatchMessage(msg);
813   }
814 }
815
816 RastLinkProcess::RastLinkProcess()
817 : rast_(0)
818 {
819 }
820
821 void RastLinkProcess::setHandler(RastEventHandler *rast)
822 {
823   rast_ = rast;
824 }
825
826 // Always return 1. 0 means not ready.
827
828 Boolean RastLinkProcess::selectLinkRule(const Vector<const AttributeList *> &linkAttributes,
829                                         const Location &location,
830                                         size_t &selected)
831 {
832   if (!rast_->linkRuleQueue_.empty()) {
833     LinkRulePi *p = rast_->linkRuleQueue_.get();
834     if (!selectLinkRulePi(p->pi, p->loc, linkAttributes, selected))
835       selected = 0;
836   }
837   else {
838     if (linkAttributes.size() > 0) {
839       rast_->setNextLocation(location);
840       rast_->Messenger::message(RastEventHandlerMessages::multipleLinkRules);
841     }
842     selected = 0;
843   }
844   return 1;
845 }
846
847 // Return zero for failure (RAST-PI-ERROR).
848
849 Boolean RastLinkProcess::selectLinkRulePi(const StringC &value,
850                                           const Location &loc,
851                                           const Vector<const AttributeList *> &linkAttributes,
852                                           size_t &selected)
853 {
854   Boolean haveSelection = 0;
855   size_t i;
856   for (i = 0; i < linkAttributes.size(); i++) {
857     const AttributeList &a = *linkAttributes[i];
858     Boolean matchValue = 0;
859     for (size_t j = 0; j < a.size(); j++) {
860       const Text *textp;
861       const StringC *strp;
862       switch (a.value(j)->info(textp, strp)) {
863       case AttributeValue::cdata:
864         // What if it contains SDATA entities?
865         if (textp->string() == value)
866           matchValue = 1;
867         break;
868       case AttributeValue::tokenized:
869         if (*strp == value)
870           matchValue = 1;
871         break;
872       default:
873         break;
874       }
875       if (matchValue)
876         break;
877     }
878     if (matchValue) {
879       if (haveSelection) {
880         rast_->setNextLocation(loc);
881         rast_->Messenger::message(RastEventHandlerMessages::multipleLinkRuleMatch);
882         return 0;
883       }
884       haveSelection = 1;
885       selected = i;
886     }
887   }
888   if (!haveSelection) {
889     rast_->setNextLocation(loc);
890     rast_->Messenger::message(RastEventHandlerMessages::noLinkRuleMatch);
891     return 0;
892   }
893   return 1;
894 }
895
896 void RastLinkProcess::swap(RastLinkProcess &to)
897 {
898   LinkProcess::swap(to);
899   RastEventHandler *tem = to.rast_;
900   to.rast_ = rast_;
901   rast_ = tem;
902 }
903
904 #ifdef SP_NAMESPACE
905 }
906 #endif