/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* $XConsortium: SgmlsEventHandler.C /main/1 1996/07/29 17:04:20 cde-hp $ */ // Copyright (c) 1994 James Clark // See the file COPYING for copying permission. #include "config.h" #include "SgmlsEventHandler.h" #include "SgmlParser.h" #include "ParserOptions.h" #include "Entity.h" #include "Notation.h" #include "Attribute.h" #include "ExtendEntityManager.h" #include "StorageManager.h" #include "macros.h" #ifdef SP_NAMESPACE namespace SP_NAMESPACE { #endif const char dataCode = '-'; const char piCode = '?'; const char conformingCode = 'C'; const char appinfoCode = '#'; const char startElementCode = '('; const char endElementCode = ')'; const char referenceEntityCode = '&'; const char attributeCode = 'A'; const char dataAttributeCode = 'D'; const char linkAttributeCode = 'a'; const char defineNotationCode = 'N'; const char defineExternalEntityCode = 'E'; const char defineInternalEntityCode = 'I'; const char defineSubdocEntityCode = 'S'; const char defineExternalTextEntityCode = 'T'; const char pubidCode = 'p'; const char sysidCode = 's'; const char startSubdocCode = '{'; const char endSubdocCode = '}'; const char fileCode = 'f'; const char locationCode = 'L'; const char includedElementCode = 'i'; const OutputCharStream::Newline nl = OutputCharStream::newline; const char space = ' '; const Char re = '\r'; inline void SgmlsEventHandler::startData() { if (!haveData_) { os() << dataCode; haveData_ = 1; } } inline void SgmlsEventHandler::flushData() { if (haveData_) { os() << nl; haveData_ = 0; } } inline void SgmlsEventHandler::outputLocation(const Location &loc) { if (outputLine_) outputLocation1(loc); } SgmlsEventHandler::SgmlsEventHandler(const SgmlParser *parser, OutputCharStream *os, Messenger *messenger, unsigned outputFlags) : SgmlsSubdocState(parser), os_(os), messenger_(messenger), outputLine_((outputFlags & outputLine) != 0), outputEntity_((outputFlags & outputEntity) != 0), outputId_((outputFlags & outputId) != 0), outputNotationSysid_((outputFlags & outputNotationSysid) != 0), outputIncluded_((outputFlags & outputIncluded) != 0), haveData_(0), lastSos_(0) { os_->setEscaper(escape); } SgmlsEventHandler::~SgmlsEventHandler() { flushData(); if (errorCount() == 0) os() << conformingCode << nl; delete os_; } void SgmlsEventHandler::message(MessageEvent *event) { messenger_->dispatchMessage(event->message()); ErrorCountEventHandler::message(event); } void SgmlsEventHandler::appinfo(AppinfoEvent *event) { const StringC *str; if (event->literal(str)) { outputLocation(event->location()); flushData(); os() << appinfoCode; outputString(*str); os() << nl; } delete event; } void SgmlsEventHandler::endProlog(EndPrologEvent *event) { if (outputEntity_) { flushData(); const Dtd &dtd = event->dtd(); Dtd::ConstEntityIter iter(dtd.generalEntityIter()); for (;;) { const Entity *entity = iter.next().pointer(); if (!entity) break; defineEntity(entity); } } if (!event->lpdPointer().isNull()) { linkProcess_.init(event->lpdPointer()); haveLinkProcess_ = 1; flushData(); } for (size_t i = 0; i < event->simpleLinkNames().size(); i++) { flushData(); attributes(event->simpleLinkAttributes()[i], linkAttributeCode, &event->simpleLinkNames()[i]); } delete event; } void SgmlsEventHandler::entityDefaulted(EntityDefaultedEvent *event) { if (outputEntity_) { flushData(); defineEntity(event->entityPointer().pointer()); } delete event; } void SgmlsEventHandler::uselink(UselinkEvent *event) { linkProcess_.uselink(event->linkSet(), event->restore(), event->lpd().pointer()); delete event; } void SgmlsEventHandler::sgmlDecl(SgmlDeclEvent *event) { sd_ = event->sdPointer(); syntax_ = event->instanceSyntaxPointer(); // FIXME which syntax? delete event; } void SgmlsEventHandler::data(DataEvent *event) { outputLocation(event->location()); startData(); outputString(event->data(), event->dataLength()); delete event; } void SgmlsEventHandler::sdataEntity(SdataEntityEvent *event) { outputLocation(event->location()); startData(); os() << "\\|"; outputString(event->data(), event->dataLength()); os() << "\\|"; delete event; } void SgmlsEventHandler::pi(PiEvent *event) { outputLocation(event->location()); flushData(); os() << piCode; outputString(event->data(), event->dataLength()); os() << nl; delete event; } void SgmlsEventHandler::startElement(StartElementEvent *event) { flushData(); currentLocation_ = event->location(); if (haveLinkProcess_) { const AttributeList *linkAttributes; const ResultElementSpec *resultElementSpec; linkProcess_.startElement(event->elementType(), event->attributes(), event->location(), *this, // Messenger & linkAttributes, resultElementSpec); if (linkAttributes) attributes(*linkAttributes, linkAttributeCode, &linkProcess_.name()); } attributes(event->attributes(), attributeCode, 0); currentLocation_.clear(); if (outputIncluded_ && event->included()) os() << includedElementCode << nl; outputLocation(event->location()); os() << startElementCode << event->name() << nl; delete event; } void SgmlsEventHandler::attributes(const AttributeList &attributes, char code, const StringC *ownerName) { size_t nAttributes = attributes.size(); for (size_t i = 0; i < nAttributes; i++) { const Text *text; const StringC *string; const AttributeValue *value = attributes.value(i); if (value) { switch (value->info(text, string)) { case AttributeValue::implied: startAttribute(attributes.name(i), code, ownerName); os() << "IMPLIED" << nl; break; case AttributeValue::tokenized: { const char *typeString = "TOKEN"; const AttributeSemantics *semantics = attributes.semantics(i); if (semantics) { ConstPtr notation = semantics->notation(); if (!notation.isNull()) { defineNotation(notation.pointer()); typeString = "NOTATION"; } else { size_t nEntities = semantics->nEntities(); if (nEntities) { typeString = "ENTITY"; if (!outputEntity_) for (size_t i = 0; i < nEntities; i++) { const Entity *entity = semantics->entity(i).pointer(); if (!markEntity(entity)) defineEntity(entity); } } } } if (outputId_ && attributes.id(i)) typeString = "ID"; startAttribute(attributes.name(i), code, ownerName); os() << typeString << space << *string << nl; } break; case AttributeValue::cdata: { startAttribute(attributes.name(i), code, ownerName); os() << "CDATA "; TextIter iter(*text); TextItem::Type type; const Char *p; size_t length; const Location *loc; while (iter.next(type, p, length, loc)) switch (type) { case TextItem::data: case TextItem::cdata: outputString(p, length); break; case TextItem::sdata: os() << "\\|"; outputString(p, length); os() << "\\|"; break; default: break; } os() << nl; } break; } } } } void SgmlsEventHandler::startAttribute(const StringC &name, char code, const StringC *ownerName) { os() << code; if (ownerName) os() << *ownerName << space; os() << name << space; } void SgmlsEventHandler::endElement(EndElementEvent *event) { flushData(); if (haveLinkProcess_) linkProcess_.endElement(); outputLocation(event->location()); os() << endElementCode << event->name() << nl; delete event; } void SgmlsEventHandler::externalDataEntity(ExternalDataEntityEvent *event) { currentLocation_ = event->location(); outputLocation(event->location()); flushData(); if (!outputEntity_ && !markEntity(event->entity())) defineExternalDataEntity(event->entity()); currentLocation_.clear(); os() << referenceEntityCode << event->entity()->name() << nl; delete event; } void SgmlsEventHandler::subdocEntity(SubdocEntityEvent *event) { currentLocation_ = event->location(); outputLocation(event->location()); flushData(); const SubdocEntity *entity = event->entity(); if (!outputEntity_ && !markEntity(entity)) defineSubdocEntity(entity); currentLocation_.clear(); os() << startSubdocCode << entity->name() << nl; SgmlParser::Params params; params.subdocInheritActiveLinkTypes = 1; params.subdocReferenced = 1; params.origin = event->entityOrigin()->copy(); params.parent = parser_; params.sysid = entity->externalId().effectiveSystemId(); params.entityType = SgmlParser::Params::subdoc; SgmlParser parser(params); SgmlsSubdocState oldState; SgmlsSubdocState::swap(oldState); SgmlsSubdocState::init(&parser); parser.parseAll(*this); oldState.swap(*this); os() << endSubdocCode << entity->name() << nl; delete event; } void SgmlsEventHandler::defineEntity(const Entity *entity) { const InternalEntity *internalEntity = entity->asInternalEntity(); if (internalEntity) defineInternalEntity(internalEntity); else { switch (entity->dataType()) { case Entity::cdata: case Entity::sdata: case Entity::ndata: defineExternalDataEntity(entity->asExternalDataEntity()); break; case Entity::subdoc: defineSubdocEntity(entity->asSubdocEntity()); break; case Entity::sgmlText: defineExternalTextEntity(entity->asExternalEntity()); break; default: CANNOT_HAPPEN(); } } } void SgmlsEventHandler::defineExternalDataEntity(const ExternalDataEntity *entity) { const Notation *notation = entity->notation(); defineNotation(notation); externalId(entity->externalId()); const char *typeString; switch (entity->dataType()) { case Entity::cdata: typeString = "CDATA"; break; case Entity::sdata: typeString = "SDATA"; break; case Entity::ndata: typeString = "NDATA"; break; default: CANNOT_HAPPEN(); } os() << defineExternalEntityCode << entity->name() << space << typeString << space << notation->name() << nl; attributes(entity->attributes(), dataAttributeCode, &entity->name()); } void SgmlsEventHandler::defineSubdocEntity(const SubdocEntity *entity) { externalId(entity->externalId()); os() << defineSubdocEntityCode << entity->name() << nl; } void SgmlsEventHandler::defineExternalTextEntity(const ExternalEntity *entity) { externalId(entity->externalId()); os() << defineExternalTextEntityCode << entity->name() << nl; } void SgmlsEventHandler::defineInternalEntity(const InternalEntity *entity) { os() << defineInternalEntityCode << entity->name() << space; const char *s; switch (entity->dataType()) { case Entity::sdata: s = "SDATA"; break; case Entity::cdata: s = "CDATA"; break; case Entity::sgmlText: s = "TEXT"; break; case Entity::pi: s = "PI"; break; default: CANNOT_HAPPEN(); } os() << s << space; outputString(entity->string()); os() << nl; } void SgmlsEventHandler::defineNotation(const Notation *notation) { if (markNotation(notation)) return; externalId(notation->externalId(), outputNotationSysid_); os() << defineNotationCode << notation->name() << nl; } void SgmlsEventHandler::externalId(const ExternalId &id, Boolean outputFile) { const StringC *str = id.publicIdString(); if (str) { os() << pubidCode; outputString(*str); os() << nl; } str = id.systemIdString(); if (str) { os() << sysidCode; outputString(*str); os() << nl; } if (outputFile && id.effectiveSystemId().size()) { os() << fileCode; outputString(id.effectiveSystemId()); os() << nl; } } Boolean SgmlsEventHandler::markEntity(const Entity *entity) { return definedEntities_.add(entity->name()); } Boolean SgmlsEventHandler::markNotation(const Notation *notation) { return definedNotations_.add(notation->name()); } void SgmlsEventHandler::outputString(const Char *p, size_t n) { for (; n > 0; p++, n--) { switch (*p) { case '\\': // FIXME we're punning Chars and chars os() << "\\\\"; break; case re: os() << "\\n"; if (outputLine_ && haveData_) lastLineno_++; break; default: // FIXME not clear what to do here given possibility of wide characters if (*p < 040) { static const char digits[] = "0123456789"; os() << "\\0" << digits[*p / 8] << digits[*p % 8]; } else os().put(*p); break; } } } void SgmlsEventHandler::escape(OutputCharStream &s, Char c) { s << "\\#" << (unsigned long)c << ";"; } void SgmlsEventHandler::outputLocation1(const Location &loc) { const Origin *origin = loc.origin().pointer(); const InputSourceOrigin *inputSourceOrigin; const ExternalInfo *info; Index index = loc.index(); for (;;) { if (!origin) return; inputSourceOrigin = origin->asInputSourceOrigin(); if (inputSourceOrigin) { info = inputSourceOrigin->externalInfo(); if (info) break; } const Location &loc = origin->parent(); index = loc.index(); origin = loc.origin().pointer(); } Offset off = inputSourceOrigin->startOffset(index); StorageObjectLocation soLoc; if (!ExtendEntityManager::externalize(info, off, soLoc)) return; if (soLoc.lineNumber == (unsigned long)-1) return; if (soLoc.storageObjectSpec == lastSos_) { if (soLoc.lineNumber == lastLineno_) return; flushData(); os() << locationCode << soLoc.lineNumber << nl; lastLineno_ = soLoc.lineNumber; } else { flushData(); os() << locationCode << soLoc.lineNumber << space; outputString(soLoc.storageObjectSpec->id); os() << nl; lastLineno_ = soLoc.lineNumber; lastSos_ = soLoc.storageObjectSpec; lastLoc_ = loc; // make sure lastSos_ doesn't get freed } } void SgmlsEventHandler::dispatchMessage(Message &msg) { dispatchMessage((const Message &) msg); } void SgmlsEventHandler::dispatchMessage(const Message &msg) { if (!cancelled()) { noteMessage(msg); messenger_->dispatchMessage(msg); } } void SgmlsEventHandler::initMessage(Message &msg) { msg.loc = currentLocation_; } SgmlsSubdocState::SgmlsSubdocState() : haveLinkProcess_(0), parser_(0) { } SgmlsSubdocState::SgmlsSubdocState(const SgmlParser *parser) : haveLinkProcess_(0), parser_(parser) { } void SgmlsSubdocState::init(const SgmlParser *parser) { parser_ = parser; definedNotations_.clear(); definedEntities_.clear(); haveLinkProcess_ = 0; linkProcess_.clear(); } void SgmlsSubdocState::swap(SgmlsSubdocState &to) { { const SgmlParser *tem = to.parser_; to.parser_ = parser_; parser_ = tem; } { Boolean tem = to.haveLinkProcess_; to.haveLinkProcess_ = haveLinkProcess_; haveLinkProcess_ = tem; } linkProcess_.swap(to.linkProcess_); definedNotations_.swap(to.definedNotations_); definedEntities_.swap(to.definedEntities_); } #ifdef SP_NAMESPACE } #endif