actual/packages/node-libofx/OpenSP-1.5.2/lib/MessageReporter.cxx
2022-04-28 22:44:38 -04:00

532 lines
15 KiB
C++

// Copyright (c) 1994, 1995 James Clark
// See the file COPYING for copying permission.
#ifdef __GNUG__
#pragma implementation
#endif
#include "splib.h"
#include "MessageReporter.h"
#include "MessageReporterMessages.h"
#include "ExtendEntityManager.h"
#include "StorageManager.h"
#include "macros.h"
#include <string.h>
#ifdef SP_NAMESPACE
namespace SP_NAMESPACE {
#endif
const OutputCharStream::Newline nl = OutputCharStream::newline;
MessageReporter::MessageReporter(OutputCharStream *os)
: os_(os), options_(0)
{
}
XMLMessageReporter::XMLMessageReporter(OutputCharStream* os) :
MessageReporter(os) , id(0) , msgmode(SP_MESSAGES_TRADITIONAL) {
char* fmt = getenv("SP_MESSAGE_FORMAT") ;
if ( fmt )
if ( !strcmp(fmt, "XML") )
msgmode = SP_MESSAGES_XML ;
else if ( !strcmp(fmt, "NONE") )
msgmode = SP_MESSAGES_NONE ;
}
MessageReporter::~MessageReporter()
{
delete os_;
}
void MessageReporter::setMessageStream(OutputCharStream *os)
{
if (os != os_) {
delete os_;
os_ = os;
}
}
void MessageReporter::addOption(Option option)
{
options_ |= option;
}
void XMLMessageReporter::dispatchMessage(const Message& message) {
switch ( msgmode ) {
case SP_MESSAGES_TRADITIONAL:
MessageReporter::dispatchMessage(message) ;
case SP_MESSAGES_NONE:
return ;
case SP_MESSAGES_XML:
break ;
}
Offset off ;
const ExternalInfo *externalInfo = locationHeader(message.loc, off);
os() << "<sp:message sp:id=\"mid" << id++ << '"' ;
if (externalInfo)
printLocation(externalInfo, off);
switch (message.type->severity()) {
case MessageType::info:
XMLformatFragment(MessageReporterMessages::infoTag, os());
break;
case MessageType::warning:
XMLformatFragment(MessageReporterMessages::warningTag, os());
break;
case MessageType::quantityError:
XMLformatFragment(MessageReporterMessages::quantityErrorTag, os());
break;
case MessageType::idrefError:
XMLformatFragment(MessageReporterMessages::idrefErrorTag, os());
break;
case MessageType::error:
XMLformatFragment(MessageReporterMessages::errorTag, os());
break;
default:
CANNOT_HAPPEN();
}
formatMessage(*message.type, message.args, os());
if (options_ & openEntities)
showOpenEntities(message.loc, off) ;
if ((options_ & clauses) && message.type->clauses() != 0) {
os() << "\n <sp:clause> " << message.type->clauses()
<< " </sp:clause>" ;
}
if (!message.auxLoc.origin().isNull()) {
os() << "\n <sp:reference " ;
Offset off;
const ExternalInfo *externalInfo = locationHeader(message.auxLoc, off);
if (externalInfo) {
printLocation(externalInfo, off);
}
formatMessage(message.type->auxFragment(), message.args, os());
os() << "\n </sp:reference>" ;
}
if ((options_ & openElements) && message.openElementInfo.size() > 0) {
formatOpenElements(message.openElementInfo, os());
}
os() << "\n</sp:message>\n" ;
os().flush();
}
void MessageReporter::dispatchMessage(const Message &message)
{
Offset off;
const ExternalInfo *externalInfo = locationHeader(message.loc, off);
if (programName_.size())
os() << programName_ << ':';
if (externalInfo) {
printLocation(externalInfo, off);
os() << ':';
}
if (options_ & messageNumbers)
os() << (unsigned long)message.type->module() << "."
<< (unsigned long)message.type->number() << ":";
switch (message.type->severity()) {
case MessageType::info:
formatFragment(MessageReporterMessages::infoTag, os());
break;
case MessageType::warning:
formatFragment(MessageReporterMessages::warningTag, os());
break;
case MessageType::quantityError:
formatFragment(MessageReporterMessages::quantityErrorTag, os());
break;
case MessageType::idrefError:
formatFragment(MessageReporterMessages::idrefErrorTag, os());
break;
case MessageType::error:
formatFragment(MessageReporterMessages::errorTag, os());
break;
default:
CANNOT_HAPPEN();
}
os() << ": ";
formatMessage(*message.type, message.args, os());
os() << nl;
if ((options_ & clauses) && message.type->clauses() != 0) {
if (programName_.size())
os() << programName_ << ':';
if (externalInfo) {
printLocation(externalInfo, off);
os() << ": ";
}
formatFragment(MessageReporterMessages::relevantClauses, os());
os() << " " << message.type->clauses() << nl;
}
if (!message.auxLoc.origin().isNull()) {
Offset off;
const ExternalInfo *externalInfo = locationHeader(message.auxLoc, off);
if (programName_.size())
os() << programName_ << ':';
if (externalInfo) {
printLocation(externalInfo, off);
os() << ": ";
}
formatMessage(message.type->auxFragment(), message.args, os());
os() << nl;
}
if ((options_ & openElements) && message.openElementInfo.size() > 0) {
if (programName_.size())
os() << programName_ << ':';
if (externalInfo) {
printLocation(externalInfo, off);
os() << ": ";
}
formatFragment(MessageReporterMessages::openElements, os());
os() << ':';
formatOpenElements(message.openElementInfo, os());
os() << nl;
}
os().flush();
}
// Note this is written so as not to change any reference counts.
const ExternalInfo *MessageReporter::locationHeader(const Location &loc,
Offset &off)
{
return locationHeader(loc.origin().pointer(), loc.index(), off);
}
const ExternalInfo* XMLMessageReporter::locationHeader(
const Origin *origin, Index index, Offset &off) {
switch ( msgmode ) {
case SP_MESSAGES_TRADITIONAL:
return MessageReporter::locationHeader(origin, index, off) ;
case SP_MESSAGES_NONE:
return 0 ;
case SP_MESSAGES_XML:
break ;
}
// take out the context printing 'cos we'll do that later
while (origin) {
const ExternalInfo *externalInfo = origin->externalInfo();
if (externalInfo) {
off = origin->startOffset(index);
return externalInfo;
}
const Location &loc = origin->parent();
if (loc.origin().isNull()) {
if (!origin->defLocation(origin->startOffset(index), origin, index))
break;
}
else {
if (origin->asEntityOrigin())
index = loc.index() + origin->refLength();
else
// Must be re-running the parser over something using
// something like PiAttspecParser.
index += loc.index();
origin = loc.origin().pointer();
}
}
return 0 ;
}
void XMLMessageReporter::showOpenEntities(
const Origin *origin, Index index, Offset &off) {
/* this function is XMLMessageReporter-only */
while (origin) {
if (origin->entityName() || origin->parent().origin().isNull()) {
Offset parentOff;
const Location &parentLoc = origin->parent();
const ExternalInfo *parentInfo
= locationHeader(parentLoc.origin().pointer(),
parentLoc.index() + origin->refLength(), parentOff);
if ( parentInfo ) {
os() << "\n <sp:context" ;
printLocation(parentInfo, parentOff);
os() << "\n sp:entity=\"" << *origin->entityName()
<< "\" />" ;
}
break ;
} else {
const Location &loc = origin->parent();
if (origin->asEntityOrigin())
index = loc.index() + origin->refLength();
else
// Must be re-running the parser over something using
// something like PiAttspecParser.
index += loc.index();
origin = loc.origin().pointer();
}
}
}
const ExternalInfo *MessageReporter::locationHeader(const Origin *origin,
Index index,
Offset &off)
{
if (!(options_ & openEntities)) {
while (origin) {
const ExternalInfo *externalInfo = origin->externalInfo();
if (externalInfo) {
off = origin->startOffset(index);
return externalInfo;
}
const Location &loc = origin->parent();
if (loc.origin().isNull()) {
if (!origin->defLocation(origin->startOffset(index), origin, index))
break;
}
else {
if (origin->asEntityOrigin())
index = loc.index() + origin->refLength();
else
// Must be re-running the parser over something using
// something like PiAttspecParser.
index += loc.index();
origin = loc.origin().pointer();
}
}
}
else {
Boolean doneHeader = 0;
while (origin) {
if (origin->entityName() || origin->parent().origin().isNull()) {
if (!doneHeader) {
Offset parentOff;
const Location &parentLoc = origin->parent();
const ExternalInfo *parentInfo
= locationHeader(parentLoc.origin().pointer(),
parentLoc.index() + origin->refLength(),
parentOff);
if (parentInfo) {
StringC text;
if (getMessageText(origin->entityName()
? MessageReporterMessages::inNamedEntity
: MessageReporterMessages::inUnnamedEntity,
text)) {
for (size_t i = 0; i < text.size(); i++) {
if (text[i] == '%') {
if (i + 1 < text.size()) {
i++;
if (text[i] == '1')
os() << *origin->entityName();
else if (text[i] == '2')
printLocation(parentInfo, parentOff);
else if (text[i] >= '3' && text[i] <= '9')
;
else
os().put(text[i]);
}
}
else
os().put(text[i]);
}
os() << nl;
}
}
doneHeader = 1;
}
off = origin->startOffset(index);
const ExternalInfo *externalInfo = origin->externalInfo();
if (externalInfo)
return externalInfo;
if (!origin->defLocation(off, origin, index))
break;
}
else {
const Location &loc = origin->parent();
if (origin->asEntityOrigin())
index = loc.index() + origin->refLength();
else
// Must be re-running the parser over something using
// something like PiAttspecParser.
index += loc.index();
origin = loc.origin().pointer();
}
}
}
return 0;
}
void XMLMessageReporter::printLocation(const ExternalInfo *externalInfo,
Offset off)
{
switch ( msgmode ) {
case SP_MESSAGES_TRADITIONAL:
MessageReporter::printLocation(externalInfo, off) ;
case SP_MESSAGES_NONE:
return ;
case SP_MESSAGES_XML:
break ;
}
if (!externalInfo) {
return;
}
StorageObjectLocation soLoc;
if (!ExtendEntityManager::externalize(externalInfo, off, soLoc)) {
return;
}
/* Ugly hack to suppress full pathnames for local files
on general principles for security for Site Valet
Since jjc's String class is rather primitive, we have to do the work here
*/
if ( soLoc.actualStorageId[0] == '/' ) {
StringC filename ;
StringC nullname ;
for (int i=0; i<soLoc.actualStorageId.size(); ++i) {
if ( soLoc.actualStorageId[i] == '/' )
filename = nullname ;
else
filename += soLoc.actualStorageId[i] ;
}
os() << "\n sp:location=\"" << filename << '"' ;
} else {
os() << "\n sp:location=\"" << soLoc.actualStorageId << '"' ;
}
if (soLoc.lineNumber == (unsigned long)-1) {
formatFragment(MessageReporterMessages::offset, os());
os() << soLoc.storageObjectOffset;
} else {
os() << "\n sp:line=\"" << soLoc.lineNumber << '"' ;
if (soLoc.columnNumber != 0 && soLoc.columnNumber != (unsigned long)-1)
os() << "\n sp:column=\"" << soLoc.columnNumber - 1 << '"' ;
}
}
void MessageReporter::printLocation(const ExternalInfo *externalInfo,
Offset off)
{
if (!externalInfo) {
formatFragment(MessageReporterMessages::invalidLocation, os());
return;
}
StorageObjectLocation soLoc;
if (!ExtendEntityManager::externalize(externalInfo, off, soLoc)) {
formatFragment(MessageReporterMessages::invalidLocation, os());
return;
}
if (strcmp(soLoc.storageObjectSpec->storageManager->type(), "OSFILE") != 0)
os() << '<' << soLoc.storageObjectSpec->storageManager->type() << '>';
os() << soLoc.actualStorageId;
if (soLoc.lineNumber == (unsigned long)-1) {
os() << ": ";
formatFragment(MessageReporterMessages::offset, os());
os() << soLoc.storageObjectOffset;
}
else {
os() << ':' << soLoc.lineNumber;
if (soLoc.columnNumber != 0 && soLoc.columnNumber != (unsigned long)-1)
os() << ':' << soLoc.columnNumber - 1;
}
#if 0
if (soLoc.byteIndex != (unsigned long)-1)
os() << ':' << soLoc.byteIndex;
#endif
}
Boolean MessageReporter::getMessageText(const MessageFragment &frag,
StringC &str)
{
const char *p = frag.text();
if (!p)
return 0;
str.resize(0);
for (; *p; p++)
str += Char((unsigned char)*p);
return 1;
}
Boolean XMLMessageReporter::XMLformatFragment(const MessageFragment &frag,
OutputCharStream &os) {
/* This function is XMLMessageReporter only */
switch ( msgmode ) {
case SP_MESSAGES_TRADITIONAL:
return MessageReporter::formatFragment(frag, os) ;
case SP_MESSAGES_NONE:
return 1 ;
case SP_MESSAGES_XML:
break ;
}
StringC text;
if (!getMessageText(frag, text))
return 0 ;
os << "\n sp:severity=\"" << text << '"' ;
return 1 ;
}
void XMLMessageReporter::formatMessage(const MessageFragment &frag,
const Vector<CopyOwner<MessageArg> > &args,
OutputCharStream &os, bool noquote) {
switch ( msgmode ) {
case SP_MESSAGES_TRADITIONAL:
MessageReporter::formatMessage(frag, args, os, noquote) ;
case SP_MESSAGES_NONE:
return ;
case SP_MESSAGES_XML:
break ;
}
StringC text;
if (!getMessageText(frag, text)) {
// XMLformatFragment(MessageFormatterMessages::invalidMessage, os);
os << "\n>(Invalid Message)\n" ;
return;
}
os << "\n>\n" ;
Builder builder(this, os, noquote || (text.size() == 2));
size_t i = 0;
while (i < text.size()) {
if (text[i] == '%') {
i++;
if (i >= text.size())
break;
if (text[i] >= '1' && text[i] <= '9') {
if (unsigned(text[i] - '1') < args.size())
args[text[i] - '1']->append(builder);
}
else
os.put(text[i]);
i++;
}
else {
os.put(text[i]);
i++;
}
}
}
void XMLMessageReporter::formatOpenElements(
const Vector<OpenElementInfo> &openElementInfo ,
OutputCharStream &os) {
switch ( msgmode ) {
case SP_MESSAGES_TRADITIONAL:
MessageReporter::formatOpenElements(openElementInfo, os) ;
case SP_MESSAGES_NONE:
return ;
case SP_MESSAGES_XML:
break ;
}
unsigned nOpenElements = openElementInfo.size();
for (unsigned i = 0;; i++) {
if (i > 0
&& (i == nOpenElements || openElementInfo[i].included)) {
// describe last match in previous open element
const OpenElementInfo &prevInfo = openElementInfo[i - 1];
if (prevInfo.matchType.size() != 0) {
os << "\n <sp:prevelement" ;
int n = prevInfo.matchIndex ;
if (n != 0)
os << " sp:matchindex=\"" << n << '"' ;
os << "> " << prevInfo.matchType;
os << " </sp:prevelement>" ;
}
}
if (i == nOpenElements)
break;
const OpenElementInfo &e = openElementInfo[i];
os << "\n <sp:openelement" ;
if (i > 0 && !e.included) {
unsigned long n = openElementInfo[i - 1].matchIndex;
if (n != 0)
os << " sp:matchindex=\"" << n << '"' ;
}
os << "> " << e.gi << " </sp:openelement>" ;
}
}
#ifdef SP_NAMESPACE
}
#endif