2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: RastEventHandler.C /main/1 1996/07/29 17:02:26 cde-hp $ */
24 // Copyright (c) 1994,1995 James Clark
25 // See the file COPYING for copying permission.
28 #pragma implementation
32 #include "RastEventHandler.h"
33 #include "SgmlParser.h"
34 #include "ParserOptions.h"
37 #include "Attribute.h"
40 #include "MessageArg.h"
42 #include "RastEventHandlerMessages.h"
47 // This is based on ISO/IEC 13673, Intermediate Editor's Draft, 1994/8/29,
48 // together with editing instructions in ISO/IEC JTC1/SC18/WG8 N1777.
51 namespace SP_NAMESPACE {
54 const OutputCharStream::Newline nl = OutputCharStream::newline;
56 class EventHandlerMessenger : public Messenger {
58 EventHandlerMessenger(EventHandler *eh) : eh_(eh) { }
59 void dispatchMessage(const Message &message) {
60 eh_->message(new MessageEvent(message));
62 void dispatchMessage(Message &message) {
63 eh_->message(new MessageEvent(message));
72 RastPrintable RastEventHandler::printable;
74 RastPrintable::RastPrintable()
76 static const char s[] =
77 " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
79 for (i = 0; i < sizeof(v_); i++)
81 for (i = 0; s[i] != '\0'; i++)
82 v_[(unsigned char)s[i]] = 32 + i;
86 void RastEventHandler::flushLine(LineType type)
88 if (lineLength_ > 0) {
89 os() << char(type) << nl;
94 RastSubdocState::RastSubdocState()
99 RastSubdocState::RastSubdocState(SgmlParser *parser, RastEventHandler *rast)
104 void RastSubdocState::init(SgmlParser *parser, RastEventHandler *rast)
107 hadActiveLpdOrDtd_ = 0;
108 activeLinkTypes_.clear();
109 hadDocumentElement_ = 0;
110 linkProcess_.clear();
111 linkProcess_.setHandler(rast);
112 haveLinkProcess_ = 0;
113 endPrologEvent_.clear();
114 parseSubdocQueue_.clear();
115 linkRuleQueue_.clear();
116 for (int i = 0; i < nAttributeType; i++)
117 attributeSortOrder_[i].clear();
120 void RastSubdocState::swap(RastSubdocState &to)
123 SgmlParser *tem = to.parser_;
124 to.parser_ = parser_;
128 Boolean tem = to.hadActiveLpdOrDtd_;
129 to.hadActiveLpdOrDtd_ = hadActiveLpdOrDtd_;
130 hadActiveLpdOrDtd_ = tem;
133 Boolean tem = to.hadDocumentElement_;
134 to.hadDocumentElement_ = hadDocumentElement_;
135 hadDocumentElement_ = tem;
137 activeLpdOrDtdLocation_.swap(to.activeLpdOrDtdLocation_);
138 activeLinkTypes_.swap(to.activeLinkTypes_);
139 linkProcess_.swap(to.linkProcess_);
140 endPrologEvent_.swap(to.endPrologEvent_);
141 parseSubdocQueue_.swap(to.parseSubdocQueue_);
142 linkRuleQueue_.swap(to.linkRuleQueue_);
143 for (int i = 0; i < nAttributeType; i++)
144 attributeSortOrder_[i].swap(to.attributeSortOrder_[i]);
147 RastEventHandler::RastEventHandler(SgmlParser *parser, Messenger *mgr)
151 RastSubdocState(parser, this),
154 RastSubdocState::init(parser, this);
157 void RastEventHandler::end()
159 if (errorCount() != 0) {
161 os() << (piErrorCount_ != 0
168 void RastEventHandler::truncateOutput()
170 // This must be handled by derived classes to get conforming output.
173 void RastEventHandler::sgmlDecl(SgmlDeclEvent *event)
175 rastParseSubdocYesString_ = event->sd().execToDoc("rast-parse-subdoc:yes");
176 rastParseSubdocNoString_ = event->sd().execToDoc("rast-parse-subdoc:no");
177 rastActiveLpdString_ = event->sd().execToDoc("rast-active-lpd:");
178 rastLinkRuleString_ = event->sd().execToDoc("rast-link-rule:");
182 void RastEventHandler::startElement(StartElementEvent *event)
185 if (!hadDocumentElement_) {
186 if (activeLinkTypes_.size() > 0) {
190 hadDocumentElement_ = 1;
192 os() << '[' << event->name();
194 if (event->attributes().size() > 0) {
197 attributeInfo(event->attributes(), dtdAttribute);
201 if (haveLinkProcess_) {
202 const AttributeList *linkAttributes;
203 const ResultElementSpec *resultElementSpec;
204 EventHandlerMessenger messenger(this);
205 linkProcess_.startElement(event->elementType(),
211 if (linkProcess_.nImpliedLinkRules() > 0) {
216 os() << "#LINK-SET-INFO" << nl;
217 impliedSourceLinkRules();
219 if (linkAttributes) {
224 os() << "#LINK-RULE" << nl;
225 attributeInfo(*linkAttributes, linkAttribute);
226 if (linkProcess_.isExplicit()) {
228 if (resultElementSpec && resultElementSpec->elementType) {
229 os() << resultElementSpec->elementType->name() << nl;
230 attributeInfo(resultElementSpec->attributeList, resultAttribute);
233 os() << "#IMPLIED" << nl;
243 void RastEventHandler::activeLinks()
245 for (size_t i = 0; i < activeLinkTypes_.size(); i++) {
246 os() << "#ACTIVE-LINK=" << activeLinkTypes_[i] << nl;
248 if (haveLinkProcess_ && linkProcess_.name() == activeLinkTypes_[i]) {
250 if (linkProcess_.nImpliedLinkRules() > 0) {
251 os() << "#INITIAL" << nl;
252 impliedSourceLinkRules();
256 if (endPrologEvent_) {
257 for (size_t j = 0; j < endPrologEvent_->simpleLinkNames().size(); j++)
258 if (endPrologEvent_->simpleLinkNames()[j] == activeLinkTypes_[i]) {
264 setNextLocation(activeLpdOrDtdLocation_);
265 Messenger::message(RastEventHandlerMessages::invalidActiveLinkType,
266 StringMessageArg(activeLinkTypes_[i]));
269 os() << "#END-ACTIVE-LINK" << nl;
273 void RastEventHandler::simpleLinkInfo()
275 if (!endPrologEvent_)
277 for (size_t i = 0; i < activeLinkTypes_.size(); i++) {
278 for (size_t j = 0; j < endPrologEvent_->simpleLinkNames().size(); j++) {
279 const StringC &name = endPrologEvent_->simpleLinkNames()[j];
280 if (name == activeLinkTypes_[i]) {
281 os() << "#SIMPLE-LINK=" << name << nl;
282 if (endPrologEvent_->simpleLinkAttributes()[j].size() > 0)
283 attributeInfo(endPrologEvent_->simpleLinkAttributes()[j],
285 os() << "#END-SIMPLE-LINK" << nl;
292 void RastEventHandler::impliedSourceLinkRules()
294 size_t n = linkProcess_.nImpliedLinkRules();
295 Vector<size_t> sortOrder(n);
297 for (i = 0; i < n; i++)
299 for (i = 1; i < n; i++) {
300 size_t tem = sortOrder[i];
302 = linkProcess_.impliedLinkRule(tem).elementType->name();
304 for (j = i; j > 0; j--) {
305 if (lexCmp(linkProcess_.impliedLinkRule(j - 1).elementType->name(),
308 sortOrder[j] = sortOrder[j - 1];
312 for (i = 0; i < n; i++) {
313 const ResultElementSpec &result
314 = linkProcess_.impliedLinkRule(sortOrder[i]);
315 os() << '[' << result.elementType->name();
316 if (result.attributeList.size() > 0) {
318 attributeInfo(result.attributeList, resultAttribute);
324 void RastEventHandler::endElement(EndElementEvent *event)
326 if (haveLinkProcess_)
327 linkProcess_.endElement();
329 os() << "[/" << event->name() << ']' << nl;
330 if (haveLinkProcess_ && linkProcess_.nImpliedLinkRules() > 0) {
331 os() << "#LINK-SET-INFO" << nl;
332 impliedSourceLinkRules();
333 os() << "#END-LINK-SET-INFO" << nl;
338 void RastEventHandler::data(DataEvent *event)
340 lines(dataLine, event->data(), event->dataLength());
344 void RastEventHandler::pi(PiEvent *event)
348 size_t dataLength = event->dataLength();
349 if (dataLength > 0) {
350 const Char *data = event->data();
353 rastParseSubdocYesString_.data(),
355 && !interpretRastPi(data, dataLength, event->location())) {
356 setNextLocation(event->location());
357 Messenger::message(RastEventHandlerMessages::invalidRastPiError);
360 lines(dataLine, event->data(), dataLength);
368 Boolean equal(const Char *s1, size_t n1, const StringC &s2)
370 return (n1 == s2.size()
372 || memcmp(s1, s2.data(), n1*sizeof(Char)) == 0));
375 // Is s2 a prefix of s1 of length n1?
378 Boolean prefix(const Char *s1, size_t n1, const StringC &s2)
380 return (n1 >= s2.size()
382 || memcmp(s1, s2.data(), s2.size()*sizeof(Char)) == 0));
385 Boolean RastEventHandler::interpretRastPi(const Char *data,
389 if (equal(data, dataLength, rastParseSubdocNoString_)) {
393 if (equal(data, dataLength, rastParseSubdocYesString_)) {
397 if (prefix(data, dataLength, rastActiveLpdString_)) {
398 if (hadActiveLpdOrDtd_)
400 hadActiveLpdOrDtd_ = 1;
401 activeLpdOrDtdLocation_ = loc;
402 const Char *p = data + rastActiveLpdString_.size();
403 size_t n = dataLength - rastActiveLpdString_.size();
406 if (n == 0 || *p == ',') {
407 if (name.size() == 0)
409 for (size_t i = 0; i < activeLinkTypes_.size(); i++)
410 if (name == activeLinkTypes_[i]) {
411 setNextLocation(activeLpdOrDtdLocation_);
412 Messenger::message(RastEventHandlerMessages::duplicateActiveLinkType,
413 StringMessageArg(name));
415 activeLinkTypes_.resize(activeLinkTypes_.size() + 1);
416 name.swap(activeLinkTypes_.back());
425 for (size_t i = 0; i < activeLinkTypes_.size(); i++)
426 parser_->activateLinkType(activeLinkTypes_[i]);
429 if (prefix(data, dataLength, rastLinkRuleString_)) {
430 LinkRulePi *p = new LinkRulePi;
431 p->pi.assign(data + rastLinkRuleString_.size(),
432 dataLength - rastLinkRuleString_.size());
434 linkRuleQueue_.append(p);
440 void RastEventHandler::sdataEntity(SdataEntityEvent *event)
443 os() << "#SDATA-TEXT" << nl;
444 lines(markupLine, event->data(), event->dataLength());
445 flushLine(markupLine);
446 os() << "#END-SDATA" << nl;
450 void RastEventHandler::externalDataEntity(ExternalDataEntityEvent *event)
452 const ExternalDataEntity *entity = event->entity();
456 os() << "[&" << entity->name() << nl;
457 externalEntityInfo(entity, dtdAttribute);
462 void RastEventHandler::externalEntityInfo(const ExternalDataEntity *entity,
463 AttributeType attributeType)
466 switch (entity->dataType()) {
479 os() << '#' << c << "DATA-EXTERNAL" << nl;
480 externalIdInfo(entity->externalId());
481 os() << "#NOTATION=" << entity->notation()->name() << nl;
482 externalIdInfo(entity->notation()->externalId());
483 attributeInfo(entity->attributes(),
484 (attributeType == resultAttribute
489 void RastEventHandler::subdocEntity(SubdocEntityEvent *event)
491 const SubdocEntity *entity = event->entity();
495 os() << "[&" << entity->name() << nl;
496 Ptr<InputSourceOrigin> origin(event->entityOrigin()->copy());
497 subdocEntityInfo(entity, origin, 1);
502 void RastEventHandler::subdocEntityInfo(const SubdocEntity *entity,
503 const Ptr<InputSourceOrigin> &entityOrigin,
506 os() << "#SUBDOC" << nl;
507 externalIdInfo(entity->externalId());
508 if (parseNextSubdoc()) {
509 // FIXME subdocuments in entity attributes shouldn't count against
510 // SUBDOC quantity limit.
511 os() << "#PARSED-SUBDOCUMENT" << nl;
512 SgmlParser::Params params;
513 params.entityType = SgmlParser::Params::subdoc;
514 params.subdocInheritActiveLinkTypes = 0;
515 params.subdocReferenced = referenced;
516 params.parent = parser_;
517 params.sysid = entity->externalId().effectiveSystemId();
518 params.origin = entityOrigin;
519 SgmlParser parser(params);
520 RastSubdocState oldSubdocState;
521 RastSubdocState::swap(oldSubdocState);
522 RastSubdocState::init(&parser, this);
523 parser.parseAll(*this);
524 oldSubdocState.swap(*this);
528 void RastEventHandler::queueParseSubdoc(Boolean parseSubdoc)
530 parseSubdocQueue_.push_back(PackedBoolean(parseSubdoc));
533 Boolean RastEventHandler::parseNextSubdoc()
535 if (parseSubdocQueue_.size() == 0)
537 Boolean result = parseSubdocQueue_[0];
538 if (parseSubdocQueue_.size() > 1) {
539 for (size_t i = 1; i < parseSubdocQueue_.size(); i++)
540 parseSubdocQueue_[i - 1] = parseSubdocQueue_[i];
542 parseSubdocQueue_.resize(parseSubdocQueue_.size() - 1);
547 void RastEventHandler::externalIdInfo(const ExternalId &id)
549 const StringC *systemId = id.systemIdString();
550 const StringC *publicId = id.publicIdString();
552 os() << "#PUBLIC" << nl;
553 if (publicId->size() == 0)
554 os() << "#EMPTY" << nl;
556 lines(markupLine, publicId->data(), publicId->size());
557 flushLine(markupLine);
560 if (systemId || !publicId) {
561 os() << "#SYSTEM" << nl;
563 os() << "#NONE" << nl;
564 else if (systemId->size() == 0)
565 os() << "#EMPTY" << nl;
567 lines(markupLine, systemId->data(), systemId->size());
568 flushLine(markupLine);
573 void RastEventHandler::lines(LineType type, const Char *p, size_t length)
575 // This needs to be fast.
576 while (length != 0) {
579 switch (lineLength_) {
581 os() << char(type) << nl;
589 lim = maxLineLength - lineLength_;
600 if (!printable(*p)) {
609 // *p is an unprintable character print it
619 os() << "#TAB" << nl;
622 os() << '#' << (unsigned long)*p << nl;
631 int RastEventHandler::lexCmp(const StringC &s1, const StringC &s2)
633 const Char *p1 = s1.data();
634 size_t n1 = s1.size();
635 const Char *p2 = s2.data();
636 size_t n2 = s2.size();
639 return n2 == 0 ? 0 : -1;
643 // printable characters precede non-printable characters;
644 // printable characters are in ASCII order
645 // non-printable characters are in document character set order
646 int a1 = printable(*p1);
647 int a2 = printable(*p2);
650 return *p1 < *p2 ? -1 : 1;
666 void RastEventHandler::attributeInfo(const AttributeList &attributes,
667 AttributeType attributeType)
669 size_t length = attributes.size();
672 size_t defIndex = attributes.defIndex();
673 if (defIndex >= attributeSortOrder_[attributeType].size())
674 attributeSortOrder_[attributeType].resize(defIndex + 1);
675 Vector<size_t> &sortOrder = attributeSortOrder_[attributeType][defIndex];
676 if (sortOrder.size() == 0
677 || attributeType == simpleAttribute) {
678 sortOrder.resize(length);
680 for (i = 0; i < length; i++)
683 for (i = 1; i < length; i++) {
684 size_t tem = sortOrder[i];
686 for (j = i; j > 0; j--) {
687 if (lexCmp(attributes.name(sortOrder[j - 1]),
688 attributes.name(tem)) <= 0)
690 sortOrder[j] = sortOrder[j - 1];
695 for (size_t j = 0; j < length; j++) {
696 // Don't use sortOrder because attributeSortOrder_ may be grown
697 // because of data attributes.
698 size_t i = attributeSortOrder_[attributeType][defIndex][j];
699 os() << attributes.name(i) << '=' << nl;
701 const StringC *string;
702 const AttributeValue *value = attributes.value(i);
704 switch (value->info(text, string)) {
705 case AttributeValue::implied:
706 os() << "#IMPLIED" << nl;
708 case AttributeValue::tokenized:
709 lines(markupLine, string->data(), string->size());
710 flushLine(markupLine);
712 case AttributeValue::cdata:
714 TextIter iter(*text);
719 while (iter.next(type, p, length, loc))
722 case TextItem::cdata:
723 lines(markupLine, p, length);
725 case TextItem::sdata:
726 flushLine(markupLine);
727 os() << "#SDATA-TEXT" << nl;
728 lines(markupLine, p, length);
729 flushLine(markupLine);
730 os() << "#END-SDATA" << nl;
735 flushLine(markupLine);
740 const AttributeSemantics *semantics = attributes.semantics(i);
742 ConstPtr<Notation> notation
743 = semantics->notation();
744 if (!notation.isNull())
745 externalIdInfo(notation->externalId());
746 size_t nEntities = semantics->nEntities();
747 for (size_t i = 0; i < nEntities; i++) {
748 ConstPtr<Entity> entity
749 = semantics->entity(i);
750 if (!entity.isNull()) {
751 const ExternalDataEntity *externalDataEntity
752 = entity->asExternalDataEntity();
753 if (externalDataEntity)
754 externalEntityInfo(externalDataEntity,
755 (attributeType == resultAttribute
759 const SubdocEntity *subdocEntity = entity->asSubdocEntity();
761 Ptr<InputSourceOrigin> entityOrigin
762 = new EntityOrigin(entity,
763 ((TokenizedAttributeValue *)value)
765 subdocEntityInfo(subdocEntity, entityOrigin, 0);
768 const InternalEntity *internalEntity = entity->asInternalEntity();
770 internalEntityInfo(internalEntity);
774 os() << "#END-ENTITY" << nl;
780 void RastEventHandler::internalEntityInfo(const InternalEntity *entity)
785 << char(entity->dataType() == Entity::cdata ? 'C' : 'S')
786 << "DATA-INTERNAL" << nl;
787 const StringC &str = entity->string();
788 lines(markupLine, str.data(), str.size());
789 flushLine(markupLine);
792 void RastEventHandler::endProlog(EndPrologEvent *event)
794 if (!event->lpdPointer().isNull()) {
795 linkProcess_.init(event->lpdPointer());
796 haveLinkProcess_ = 1;
798 if (event->simpleLinkNames().size() > 0)
799 endPrologEvent_ = event;
804 void RastEventHandler::uselink(UselinkEvent *event)
806 linkProcess_.uselink(event->linkSet(),
808 event->lpd().pointer());
809 if (haveLinkProcess_ && linkProcess_.nImpliedLinkRules() > 0) {
811 os() << "#LINK-SET-INFO" << nl;
812 impliedSourceLinkRules();
813 os() << "#END-LINK-SET-INFO" << nl;
818 void RastEventHandler::initMessage(Message &msg)
820 mgr_->initMessage(msg);
823 void RastEventHandler::dispatchMessage(Message &msg)
825 dispatchMessage((const Message &) msg);
828 void RastEventHandler::dispatchMessage(const Message &msg)
834 mgr_->dispatchMessage(msg);
838 RastLinkProcess::RastLinkProcess()
843 void RastLinkProcess::setHandler(RastEventHandler *rast)
848 // Always return 1. 0 means not ready.
850 Boolean RastLinkProcess::selectLinkRule(const Vector<const AttributeList *> &linkAttributes,
851 const Location &location,
854 if (!rast_->linkRuleQueue_.empty()) {
855 LinkRulePi *p = rast_->linkRuleQueue_.get();
856 if (!selectLinkRulePi(p->pi, p->loc, linkAttributes, selected))
860 if (linkAttributes.size() > 0) {
861 rast_->setNextLocation(location);
862 rast_->Messenger::message(RastEventHandlerMessages::multipleLinkRules);
869 // Return zero for failure (RAST-PI-ERROR).
871 Boolean RastLinkProcess::selectLinkRulePi(const StringC &value,
873 const Vector<const AttributeList *> &linkAttributes,
876 Boolean haveSelection = 0;
878 for (i = 0; i < linkAttributes.size(); i++) {
879 const AttributeList &a = *linkAttributes[i];
880 Boolean matchValue = 0;
881 for (size_t j = 0; j < a.size(); j++) {
884 switch (a.value(j)->info(textp, strp)) {
885 case AttributeValue::cdata:
886 // What if it contains SDATA entities?
887 if (textp->string() == value)
890 case AttributeValue::tokenized:
902 rast_->setNextLocation(loc);
903 rast_->Messenger::message(RastEventHandlerMessages::multipleLinkRuleMatch);
910 if (!haveSelection) {
911 rast_->setNextLocation(loc);
912 rast_->Messenger::message(RastEventHandlerMessages::noLinkRuleMatch);
918 void RastLinkProcess::swap(RastLinkProcess &to)
920 LinkProcess::swap(to);
921 RastEventHandler *tem = to.rast_;