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.
10 #include "RastEventHandler.h"
11 #include "SgmlParser.h"
12 #include "ParserOptions.h"
15 #include "Attribute.h"
18 #include "MessageArg.h"
20 #include "RastEventHandlerMessages.h"
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.
29 namespace SP_NAMESPACE {
32 const OutputCharStream::Newline nl = OutputCharStream::newline;
34 class EventHandlerMessenger : public Messenger {
36 EventHandlerMessenger(EventHandler *eh) : eh_(eh) { }
37 void dispatchMessage(const Message &message) {
38 eh_->message(new MessageEvent(message));
40 void dispatchMessage(Message &message) {
41 eh_->message(new MessageEvent(message));
50 RastPrintable RastEventHandler::printable;
52 RastPrintable::RastPrintable()
54 static const char s[] =
55 " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
57 for (i = 0; i < sizeof(v_); i++)
59 for (i = 0; s[i] != '\0'; i++)
60 v_[(unsigned char)s[i]] = 32 + i;
64 void RastEventHandler::flushLine(LineType type)
66 if (lineLength_ > 0) {
67 os() << char(type) << nl;
72 RastSubdocState::RastSubdocState()
77 RastSubdocState::RastSubdocState(SgmlParser *parser, RastEventHandler *rast)
82 void RastSubdocState::init(SgmlParser *parser, RastEventHandler *rast)
85 hadActiveLpdOrDtd_ = 0;
86 activeLinkTypes_.clear();
87 hadDocumentElement_ = 0;
89 linkProcess_.setHandler(rast);
91 endPrologEvent_.clear();
92 parseSubdocQueue_.clear();
93 linkRuleQueue_.clear();
94 for (int i = 0; i < nAttributeType; i++)
95 attributeSortOrder_[i].clear();
98 void RastSubdocState::swap(RastSubdocState &to)
101 SgmlParser *tem = to.parser_;
102 to.parser_ = parser_;
106 Boolean tem = to.hadActiveLpdOrDtd_;
107 to.hadActiveLpdOrDtd_ = hadActiveLpdOrDtd_;
108 hadActiveLpdOrDtd_ = tem;
111 Boolean tem = to.hadDocumentElement_;
112 to.hadDocumentElement_ = hadDocumentElement_;
113 hadDocumentElement_ = tem;
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]);
125 RastEventHandler::RastEventHandler(SgmlParser *parser, Messenger *mgr)
129 RastSubdocState(parser, this),
132 RastSubdocState::init(parser, this);
135 void RastEventHandler::end()
137 if (errorCount() != 0) {
139 os() << (piErrorCount_ != 0
146 void RastEventHandler::truncateOutput()
148 // This must be handled by derived classes to get conforming output.
151 void RastEventHandler::sgmlDecl(SgmlDeclEvent *event)
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:");
160 void RastEventHandler::startElement(StartElementEvent *event)
163 if (!hadDocumentElement_) {
164 if (activeLinkTypes_.size() > 0) {
168 hadDocumentElement_ = 1;
170 os() << '[' << event->name();
172 if (event->attributes().size() > 0) {
175 attributeInfo(event->attributes(), dtdAttribute);
179 if (haveLinkProcess_) {
180 const AttributeList *linkAttributes;
181 const ResultElementSpec *resultElementSpec;
182 EventHandlerMessenger messenger(this);
183 linkProcess_.startElement(event->elementType(),
189 if (linkProcess_.nImpliedLinkRules() > 0) {
194 os() << "#LINK-SET-INFO" << nl;
195 impliedSourceLinkRules();
197 if (linkAttributes) {
202 os() << "#LINK-RULE" << nl;
203 attributeInfo(*linkAttributes, linkAttribute);
204 if (linkProcess_.isExplicit()) {
206 if (resultElementSpec && resultElementSpec->elementType) {
207 os() << resultElementSpec->elementType->name() << nl;
208 attributeInfo(resultElementSpec->attributeList, resultAttribute);
211 os() << "#IMPLIED" << nl;
221 void RastEventHandler::activeLinks()
223 for (size_t i = 0; i < activeLinkTypes_.size(); i++) {
224 os() << "#ACTIVE-LINK=" << activeLinkTypes_[i] << nl;
226 if (haveLinkProcess_ && linkProcess_.name() == activeLinkTypes_[i]) {
228 if (linkProcess_.nImpliedLinkRules() > 0) {
229 os() << "#INITIAL" << nl;
230 impliedSourceLinkRules();
234 if (endPrologEvent_) {
235 for (size_t j = 0; j < endPrologEvent_->simpleLinkNames().size(); j++)
236 if (endPrologEvent_->simpleLinkNames()[j] == activeLinkTypes_[i]) {
242 setNextLocation(activeLpdOrDtdLocation_);
243 Messenger::message(RastEventHandlerMessages::invalidActiveLinkType,
244 StringMessageArg(activeLinkTypes_[i]));
247 os() << "#END-ACTIVE-LINK" << nl;
251 void RastEventHandler::simpleLinkInfo()
253 if (!endPrologEvent_)
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],
263 os() << "#END-SIMPLE-LINK" << nl;
270 void RastEventHandler::impliedSourceLinkRules()
272 size_t n = linkProcess_.nImpliedLinkRules();
273 Vector<size_t> sortOrder(n);
275 for (i = 0; i < n; i++)
277 for (i = 1; i < n; i++) {
278 size_t tem = sortOrder[i];
280 = linkProcess_.impliedLinkRule(tem).elementType->name();
282 for (j = i; j > 0; j--) {
283 if (lexCmp(linkProcess_.impliedLinkRule(j - 1).elementType->name(),
286 sortOrder[j] = sortOrder[j - 1];
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) {
296 attributeInfo(result.attributeList, resultAttribute);
302 void RastEventHandler::endElement(EndElementEvent *event)
304 if (haveLinkProcess_)
305 linkProcess_.endElement();
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;
316 void RastEventHandler::data(DataEvent *event)
318 lines(dataLine, event->data(), event->dataLength());
322 void RastEventHandler::pi(PiEvent *event)
326 size_t dataLength = event->dataLength();
327 if (dataLength > 0) {
328 const Char *data = event->data();
331 rastParseSubdocYesString_.data(),
333 && !interpretRastPi(data, dataLength, event->location())) {
334 setNextLocation(event->location());
335 Messenger::message(RastEventHandlerMessages::invalidRastPiError);
338 lines(dataLine, event->data(), dataLength);
346 Boolean equal(const Char *s1, size_t n1, const StringC &s2)
348 return (n1 == s2.size()
350 || memcmp(s1, s2.data(), n1*sizeof(Char)) == 0));
353 // Is s2 a prefix of s1 of length n1?
356 Boolean prefix(const Char *s1, size_t n1, const StringC &s2)
358 return (n1 >= s2.size()
360 || memcmp(s1, s2.data(), s2.size()*sizeof(Char)) == 0));
363 Boolean RastEventHandler::interpretRastPi(const Char *data,
367 if (equal(data, dataLength, rastParseSubdocNoString_)) {
371 if (equal(data, dataLength, rastParseSubdocYesString_)) {
375 if (prefix(data, dataLength, rastActiveLpdString_)) {
376 if (hadActiveLpdOrDtd_)
378 hadActiveLpdOrDtd_ = 1;
379 activeLpdOrDtdLocation_ = loc;
380 const Char *p = data + rastActiveLpdString_.size();
381 size_t n = dataLength - rastActiveLpdString_.size();
384 if (n == 0 || *p == ',') {
385 if (name.size() == 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));
393 activeLinkTypes_.resize(activeLinkTypes_.size() + 1);
394 name.swap(activeLinkTypes_.back());
403 for (size_t i = 0; i < activeLinkTypes_.size(); i++)
404 parser_->activateLinkType(activeLinkTypes_[i]);
407 if (prefix(data, dataLength, rastLinkRuleString_)) {
408 LinkRulePi *p = new LinkRulePi;
409 p->pi.assign(data + rastLinkRuleString_.size(),
410 dataLength - rastLinkRuleString_.size());
412 linkRuleQueue_.append(p);
418 void RastEventHandler::sdataEntity(SdataEntityEvent *event)
421 os() << "#SDATA-TEXT" << nl;
422 lines(markupLine, event->data(), event->dataLength());
423 flushLine(markupLine);
424 os() << "#END-SDATA" << nl;
428 void RastEventHandler::externalDataEntity(ExternalDataEntityEvent *event)
430 const ExternalDataEntity *entity = event->entity();
434 os() << "[&" << entity->name() << nl;
435 externalEntityInfo(entity, dtdAttribute);
440 void RastEventHandler::externalEntityInfo(const ExternalDataEntity *entity,
441 AttributeType attributeType)
444 switch (entity->dataType()) {
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
467 void RastEventHandler::subdocEntity(SubdocEntityEvent *event)
469 const SubdocEntity *entity = event->entity();
473 os() << "[&" << entity->name() << nl;
474 Ptr<InputSourceOrigin> origin(event->entityOrigin()->copy());
475 subdocEntityInfo(entity, origin, 1);
480 void RastEventHandler::subdocEntityInfo(const SubdocEntity *entity,
481 const Ptr<InputSourceOrigin> &entityOrigin,
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);
506 void RastEventHandler::queueParseSubdoc(Boolean parseSubdoc)
508 parseSubdocQueue_.push_back(PackedBoolean(parseSubdoc));
511 Boolean RastEventHandler::parseNextSubdoc()
513 if (parseSubdocQueue_.size() == 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];
520 parseSubdocQueue_.resize(parseSubdocQueue_.size() - 1);
525 void RastEventHandler::externalIdInfo(const ExternalId &id)
527 const StringC *systemId = id.systemIdString();
528 const StringC *publicId = id.publicIdString();
530 os() << "#PUBLIC" << nl;
531 if (publicId->size() == 0)
532 os() << "#EMPTY" << nl;
534 lines(markupLine, publicId->data(), publicId->size());
535 flushLine(markupLine);
538 if (systemId || !publicId) {
539 os() << "#SYSTEM" << nl;
541 os() << "#NONE" << nl;
542 else if (systemId->size() == 0)
543 os() << "#EMPTY" << nl;
545 lines(markupLine, systemId->data(), systemId->size());
546 flushLine(markupLine);
551 void RastEventHandler::lines(LineType type, const Char *p, size_t length)
553 // This needs to be fast.
554 while (length != 0) {
557 switch (lineLength_) {
559 os() << char(type) << nl;
567 lim = maxLineLength - lineLength_;
578 if (!printable(*p)) {
587 // *p is an unprintable character print it
597 os() << "#TAB" << nl;
600 os() << '#' << (unsigned long)*p << nl;
609 int RastEventHandler::lexCmp(const StringC &s1, const StringC &s2)
611 const Char *p1 = s1.data();
612 size_t n1 = s1.size();
613 const Char *p2 = s2.data();
614 size_t n2 = s2.size();
617 return n2 == 0 ? 0 : -1;
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);
628 return *p1 < *p2 ? -1 : 1;
644 void RastEventHandler::attributeInfo(const AttributeList &attributes,
645 AttributeType attributeType)
647 size_t length = attributes.size();
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);
658 for (i = 0; i < length; i++)
661 for (i = 1; i < length; i++) {
662 size_t tem = sortOrder[i];
664 for (j = i; j > 0; j--) {
665 if (lexCmp(attributes.name(sortOrder[j - 1]),
666 attributes.name(tem)) <= 0)
668 sortOrder[j] = sortOrder[j - 1];
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;
679 const StringC *string;
680 const AttributeValue *value = attributes.value(i);
682 switch (value->info(text, string)) {
683 case AttributeValue::implied:
684 os() << "#IMPLIED" << nl;
686 case AttributeValue::tokenized:
687 lines(markupLine, string->data(), string->size());
688 flushLine(markupLine);
690 case AttributeValue::cdata:
692 TextIter iter(*text);
697 while (iter.next(type, p, length, loc))
700 case TextItem::cdata:
701 lines(markupLine, p, length);
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;
713 flushLine(markupLine);
718 const AttributeSemantics *semantics = attributes.semantics(i);
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
737 const SubdocEntity *subdocEntity = entity->asSubdocEntity();
739 Ptr<InputSourceOrigin> entityOrigin
740 = new EntityOrigin(entity,
741 ((TokenizedAttributeValue *)value)
743 subdocEntityInfo(subdocEntity, entityOrigin, 0);
746 const InternalEntity *internalEntity = entity->asInternalEntity();
748 internalEntityInfo(internalEntity);
752 os() << "#END-ENTITY" << nl;
758 void RastEventHandler::internalEntityInfo(const InternalEntity *entity)
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);
770 void RastEventHandler::endProlog(EndPrologEvent *event)
772 if (!event->lpdPointer().isNull()) {
773 linkProcess_.init(event->lpdPointer());
774 haveLinkProcess_ = 1;
776 if (event->simpleLinkNames().size() > 0)
777 endPrologEvent_ = event;
782 void RastEventHandler::uselink(UselinkEvent *event)
784 linkProcess_.uselink(event->linkSet(),
786 event->lpd().pointer());
787 if (haveLinkProcess_ && linkProcess_.nImpliedLinkRules() > 0) {
789 os() << "#LINK-SET-INFO" << nl;
790 impliedSourceLinkRules();
791 os() << "#END-LINK-SET-INFO" << nl;
796 void RastEventHandler::initMessage(Message &msg)
798 mgr_->initMessage(msg);
801 void RastEventHandler::dispatchMessage(Message &msg)
803 dispatchMessage((const Message &) msg);
806 void RastEventHandler::dispatchMessage(const Message &msg)
812 mgr_->dispatchMessage(msg);
816 RastLinkProcess::RastLinkProcess()
821 void RastLinkProcess::setHandler(RastEventHandler *rast)
826 // Always return 1. 0 means not ready.
828 Boolean RastLinkProcess::selectLinkRule(const Vector<const AttributeList *> &linkAttributes,
829 const Location &location,
832 if (!rast_->linkRuleQueue_.empty()) {
833 LinkRulePi *p = rast_->linkRuleQueue_.get();
834 if (!selectLinkRulePi(p->pi, p->loc, linkAttributes, selected))
838 if (linkAttributes.size() > 0) {
839 rast_->setNextLocation(location);
840 rast_->Messenger::message(RastEventHandlerMessages::multipleLinkRules);
847 // Return zero for failure (RAST-PI-ERROR).
849 Boolean RastLinkProcess::selectLinkRulePi(const StringC &value,
851 const Vector<const AttributeList *> &linkAttributes,
854 Boolean haveSelection = 0;
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++) {
862 switch (a.value(j)->info(textp, strp)) {
863 case AttributeValue::cdata:
864 // What if it contains SDATA entities?
865 if (textp->string() == value)
868 case AttributeValue::tokenized:
880 rast_->setNextLocation(loc);
881 rast_->Messenger::message(RastEventHandlerMessages::multipleLinkRuleMatch);
888 if (!haveSelection) {
889 rast_->setNextLocation(loc);
890 rast_->Messenger::message(RastEventHandlerMessages::noLinkRuleMatch);
896 void RastLinkProcess::swap(RastLinkProcess &to)
898 LinkProcess::swap(to);
899 RastEventHandler *tem = to.rast_;