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

3661 lines
112 KiB
C++

// Copyright (c) 1994, 1995 James Clark
// See the file COPYING for copying permission.
// Prolog, dtd and declaration parsing.
#include "splib.h"
#include "Parser.h"
#include "Param.h"
#include "Markup.h"
#include "ParserMessages.h"
#include "MessageArg.h"
#include "TokenMessageArg.h"
#include "token.h"
#include "macros.h"
#include <stdio.h>
#ifdef SP_NAMESPACE
namespace SP_NAMESPACE {
#endif
static const AllowedParams allowMdc(Param::mdc);
static const AllowedParams allowName(Param::name);
static const AllowedParams allowParamLiteral(Param::paramLiteral);
static const AllowedParams allowNameNameGroup(Param::name, Param::nameGroup);
static const AllowedParams allowDsoMdc(Param::dso, Param::mdc);
static AllowedParams allowNameMdc(Param::name, Param::mdc);
static AllowedParams
allowExplicitLinkRuleMdc(Param::mdc,
Param::name,
Param::nameGroup,
Param::indicatedReservedName + Syntax::rIMPLIED);
static AllowedParams
allowNameNameGroupMdc(Param::name, Param::nameGroup, Param::mdc);
static const AllowedParams
allowLinkSetSpec(Param::name,
Param::indicatedReservedName + Syntax::rINITIAL,
Param::indicatedReservedName + Syntax::rEMPTY,
Param::indicatedReservedName + Syntax::rRESTORE);
void Parser::doProlog()
{
const unsigned maxTries = 10;
unsigned tries = 0;
do {
if (cancelled()) {
allDone();
return;
}
Token token = getToken(proMode);
switch (token) {
case tokenUnrecognized:
if (reportNonSgmlCharacter())
break;
if (hadDtd()) {
currentInput()->ungetToken();
endProlog();
return;
}
{
StringC gi;
if (lookingAtStartTag(gi)) {
currentInput()->ungetToken();
implyDtd(gi);
return;
}
}
if (++tries >= maxTries) {
message(ParserMessages::notSgml);
giveUp();
return;
}
message(ParserMessages::prologCharacter, StringMessageArg(currentToken()));
prologRecover();
break;
case tokenEe:
if (hadDtd()) {
endProlog();
return;
}
message(ParserMessages::documentEndProlog);
allDone();
return;
case tokenMdoMdc:
// empty comment
emptyCommentDecl();
break;
case tokenMdoCom:
if (!parseCommentDecl())
prologRecover();
break;
case tokenMdoNameStart:
setPass2Start();
if (startMarkup(eventsWanted().wantPrologMarkup(), currentLocation()))
currentMarkup()->addDelim(Syntax::dMDO);
Syntax::ReservedName name;
if (parseDeclarationName(&name)) {
switch (name) {
case Syntax::rDOCTYPE:
if (!parseDoctypeDeclStart())
giveUp();
return;
case Syntax::rLINKTYPE:
if (!parseLinktypeDeclStart())
giveUp();
return;
case Syntax::rELEMENT:
case Syntax::rATTLIST:
case Syntax::rENTITY:
case Syntax::rNOTATION:
case Syntax::rSHORTREF:
case Syntax::rUSEMAP:
case Syntax::rUSELINK:
case Syntax::rLINK:
case Syntax::rIDLINK:
message(ParserMessages::prologDeclaration,
StringMessageArg(syntax().reservedName(name)));
if (!hadDtd())
tries++;
prologRecover();
break;
default:
message(ParserMessages::noSuchDeclarationType,
StringMessageArg(syntax().reservedName(name)));
prologRecover();
break;
}
}
else
prologRecover();
break;
case tokenPio:
if (!parseProcessingInstruction())
prologRecover();
break;
case tokenS:
if (eventsWanted().wantPrologMarkup()) {
extendS();
eventHandler().sSep(new (eventAllocator())
SSepEvent(currentInput()->currentTokenStart(),
currentInput()->currentTokenLength(),
currentLocation(),
1));
}
break;
default:
CANNOT_HAPPEN();
}
} while (eventQueueEmpty());
}
void Parser::endProlog()
{
if (baseDtd().isNull()
#if 0
|| baseDtd()->documentElementType()->definition()->undefined()
#endif
) {
// We could continue, but there's not a lot of point.
giveUp();
return;
}
if (maybeStartPass2())
setPhase(prologPhase);
else {
if (inputLevel() == 0) {
allDone();
return;
}
if (pass2())
checkEntityStability();
setPhase(instanceStartPhase);
startInstance();
ConstPtr<ComplexLpd> lpd;
Vector<AttributeList> simpleLinkAtts;
Vector<StringC> simpleLinkNames;
for (size_t i = 0; i < nActiveLink(); i++)
if (activeLpd(i).type() == Lpd::simpleLink) {
const SimpleLpd &lpd = (SimpleLpd &)activeLpd(i);
simpleLinkNames.push_back(lpd.name());
simpleLinkAtts.resize(simpleLinkAtts.size() + 1);
simpleLinkAtts.back().init(lpd.attributeDef());
simpleLinkAtts.back().finish(*this);
}
else
lpd = (ComplexLpd *)&activeLpd(i);
eventHandler().endProlog(new (eventAllocator())
EndPrologEvent(currentDtdPointer(),
lpd,
simpleLinkNames,
simpleLinkAtts,
currentLocation()));
}
}
void Parser::prologRecover()
{
unsigned skipCount = 0;
const unsigned skipMax = 250;
for (;;) {
Token token = getToken(proMode);
skipCount++;
if (token == tokenUnrecognized) {
token = getToken(mdMode);
if (token == tokenMdc) {
token = getToken(proMode);
if (token == tokenS)
return;
}
}
switch (token) {
case tokenUnrecognized:
(void)getChar();
break;
case tokenEe:
return;
case tokenMdoMdc:
case tokenMdoCom:
case tokenMdoNameStart:
case tokenPio:
currentInput()->ungetToken();
return;
case tokenS:
if (currentChar() == syntax().standardFunction(Syntax::fRE)
&& skipCount >= skipMax)
return;
default:
break;
}
}
}
void Parser::doDeclSubset()
{
do {
if (cancelled()) {
allDone();
return;
}
Token token = getToken(currentMode());
unsigned startLevel = inputLevel();
Boolean inDtd = !haveDefLpd();
switch (token) {
case tokenUnrecognized:
if (reportNonSgmlCharacter())
break;
message(ParserMessages::declSubsetCharacter, StringMessageArg(currentToken()));
declSubsetRecover(startLevel);
break;
case tokenEe:
if (inputLevel() == specialParseInputLevel()) {
// FIXME have separate messages for each type of special parse
message(ParserMessages::specialParseEntityEnd);
}
if (eventsWanted().wantPrologMarkup())
eventHandler().entityEnd(new (eventAllocator())
EntityEndEvent(currentLocation()));
if (inputLevel() == 2) {
const EntityDecl *e
= currentLocation().origin()->entityDecl();
if (e
&& (e->declType() == EntityDecl::doctype
|| e->declType() == EntityDecl::linktype)) {
// popInputStack may destroy e
Boolean fake = e->defLocation().origin().isNull();
popInputStack();
if (!(inDtd
? parseDoctypeDeclEnd(fake)
: parseLinktypeDeclEnd()))
; // FIXME recover
setPhase(prologPhase);
return;
}
}
if (inputLevel() == 1) {
if (finalPhase() == declSubsetPhase) {
checkDtd(defDtd());
endDtd();
}
else
// Give message before popping stack.
message(inDtd
? ParserMessages::documentEndDtdSubset
: ParserMessages::documentEndLpdSubset);
popInputStack();
allDone();
}
else
popInputStack();
return;
case tokenDsc: // end of declaration subset
// FIXME what's the right location?
if (!referenceDsEntity(currentLocation())) {
if (!(inDtd ? parseDoctypeDeclEnd() : parseLinktypeDeclEnd()))
; // FIXME recover
setPhase(prologPhase);
}
return;
case tokenMdoNameStart: // named markup declaration
if (startMarkup(eventsWanted().wantPrologMarkup(), currentLocation()))
currentMarkup()->addDelim(Syntax::dMDO);
Syntax::ReservedName name;
Boolean result;
if (parseDeclarationName(&name,
inDtd && !options().errorAfdr)) {
switch (name) {
case Syntax::rANY: // used for <!AFDR
result = parseAfdrDecl();
break;
case Syntax::rELEMENT:
if (inDtd)
result = parseElementDecl();
else {
message(ParserMessages::lpdSubsetDeclaration,
StringMessageArg(syntax().reservedName(name)));
result = 0;
}
break;
case Syntax::rATTLIST:
result = parseAttlistDecl();
break;
case Syntax::rENTITY:
result = parseEntityDecl();
break;
case Syntax::rNOTATION:
result = parseNotationDecl();
if (!inDtd && !sd().www())
message(ParserMessages::lpdSubsetDeclaration,
StringMessageArg(syntax().reservedName(name)));
break;
case Syntax::rSHORTREF:
if (inDtd)
result = parseShortrefDecl();
else {
message(ParserMessages::lpdSubsetDeclaration,
StringMessageArg(syntax().reservedName(name)));
result = 0;
}
break;
case Syntax::rUSEMAP:
if (inDtd)
result = parseUsemapDecl();
else {
message(ParserMessages::lpdSubsetDeclaration,
StringMessageArg(syntax().reservedName(name)));
result = 0;
}
break;
case Syntax::rLINK:
if (inDtd) {
message(ParserMessages::dtdSubsetDeclaration,
StringMessageArg(syntax().reservedName(name)));
result = 0;
}
else
result = parseLinkDecl();
break;
case Syntax::rIDLINK:
if (inDtd) {
message(ParserMessages::dtdSubsetDeclaration,
StringMessageArg(syntax().reservedName(name)));
result = 0;
}
else
result = parseIdlinkDecl();
break;
case Syntax::rDOCTYPE:
case Syntax::rLINKTYPE:
case Syntax::rUSELINK:
result = 0;
message(inDtd
? ParserMessages::dtdSubsetDeclaration
: ParserMessages::lpdSubsetDeclaration,
StringMessageArg(syntax().reservedName(name)));
break;
default:
result = 0;
message(ParserMessages::noSuchDeclarationType,
StringMessageArg(syntax().reservedName(name)));
break;
}
}
else
result = 0;
if (!result)
declSubsetRecover(startLevel);
break;
case tokenMdoMdc: // empty comment declaration
// empty comment
emptyCommentDecl();
break;
case tokenMdoCom: // comment declaration
if (!parseCommentDecl())
declSubsetRecover(startLevel);
break;
case tokenMdoDso: // marked section declaration
if (!parseMarkedSectionDeclStart())
declSubsetRecover(startLevel);
break;
case tokenMscMdc:
handleMarkedSectionEnd();
break;
case tokenPeroGrpo: // parameter entity reference with name group
message(ParserMessages::peroGrpoProlog);
// fall through
case tokenPeroNameStart: // parameter entity reference
{
ConstPtr<Entity> entity;
Ptr<EntityOrigin> origin;
if (parseEntityReference(1, token == tokenPeroGrpo, entity, origin)) {
if (!entity.isNull())
entity->dsReference(*this, origin);
}
else
declSubsetRecover(startLevel);
}
break;
case tokenPio: // processing instruction
if (!parseProcessingInstruction())
declSubsetRecover(startLevel);
break;
case tokenS: // white space
if (eventsWanted().wantPrologMarkup()) {
extendS();
eventHandler().sSep(new (eventAllocator())
SSepEvent(currentInput()->currentTokenStart(),
currentInput()->currentTokenLength(),
currentLocation(),
1));
}
break;
case tokenIgnoredChar:
// from an ignored marked section
if (eventsWanted().wantPrologMarkup())
eventHandler().ignoredChars(new (eventAllocator())
IgnoredCharsEvent(currentInput()->currentTokenStart(),
currentInput()->currentTokenLength(),
currentLocation(),
1));
break;
case tokenRe:
case tokenRs:
case tokenCroNameStart:
case tokenCroDigit:
case tokenHcroHexDigit:
case tokenEroNameStart:
case tokenEroGrpo:
case tokenChar:
// these can occur in a cdata or rcdata marked section
message(ParserMessages::dataMarkedSectionDeclSubset);
declSubsetRecover(startLevel);
break;
default:
CANNOT_HAPPEN();
}
} while (eventQueueEmpty());
}
void Parser::declSubsetRecover(unsigned startLevel)
{
for (;;) {
Token token = getToken(currentMode());
switch (token) {
case tokenUnrecognized:
(void)getChar();
break;
case tokenEe:
if (inputLevel() <= startLevel)
return;
popInputStack();
break;
case tokenMdoCom:
case tokenDsc:
case tokenMdoNameStart:
case tokenMdoMdc:
case tokenMdoDso:
case tokenMscMdc:
case tokenPio:
if (inputLevel() == startLevel) {
currentInput()->ungetToken();
return;
}
break;
default:
break;
}
}
}
Boolean Parser::lookingAtStartTag(StringC &gi)
{
// This is harder than might be expected since we may not have compiled
// the recognizers for the instance yet.
const StringC &stago = instanceSyntax().delimGeneral(Syntax::dSTAGO);
for (size_t i = currentInput()->currentTokenLength();
i < stago.size();
i++)
if (currentInput()->tokenChar(messenger()) == InputSource::eE)
return 0;
StringC delim;
getCurrentToken(instanceSyntax().generalSubstTable(), delim);
if (delim != stago)
return 0;
Xchar c = currentInput()->tokenChar(messenger());
if (!instanceSyntax().isNameStartCharacter(c))
return 0;
do {
gi += (*instanceSyntax().generalSubstTable())[(Char)c];
c = currentInput()->tokenChar(messenger());
} while (instanceSyntax().isNameCharacter(c));
return 1;
}
Boolean Parser::parseDeclarationName(Syntax::ReservedName *result,
Boolean allowAfdr)
{
currentInput()->discardInitial();
extendNameToken(syntax().namelen(), ParserMessages::nameLength);
StringC &name = nameBuffer();
getCurrentToken(syntax().generalSubstTable(), name);
if (!syntax().lookupReservedName(name, result)) {
if (allowAfdr && name == sd().execToInternal("AFDR")) {
*result = Syntax::rANY;
if (currentMarkup())
currentMarkup()->addName(currentInput());
}
else {
message(ParserMessages::noSuchDeclarationType, StringMessageArg(name));
return 0;
}
}
else if (currentMarkup())
currentMarkup()->addReservedName(*result, currentInput());
return 1;
}
Boolean Parser::parseElementDecl()
{
unsigned declInputLevel = inputLevel();
Param parm;
if (!parseParam(allowNameNameGroup, declInputLevel, parm))
return 0;
Vector<NameToken> nameVector;
if (parm.type == Param::nameGroup) {
parm.nameTokenVector.swap(nameVector);
if (options().warnElementGroupDecl)
message(ParserMessages::elementGroupDecl);
}
else {
nameVector.resize(1);
parm.token.swap(nameVector[0].name);
parm.origToken.swap(nameVector[0].origName);
}
static AllowedParams
allowRankOmissionContent(Param::number,
Param::reservedName + Syntax::rO,
Param::minus,
Param::reservedName + Syntax::rCDATA,
Param::reservedName + Syntax::rRCDATA,
Param::reservedName + Syntax::rEMPTY,
Param::reservedName + Syntax::rANY,
Param::modelGroup);
if (!parseParam(allowRankOmissionContent, declInputLevel, parm))
return 0;
StringC rankSuffix;
Vector<ElementType *> elements(nameVector.size());
Vector<RankStem *> rankStems;
Vector<const RankStem *> constRankStems;
size_t i;
if (parm.type == Param::number) {
if (options().warnRank)
message(ParserMessages::rank);
parm.token.swap(rankSuffix);
rankStems.resize(nameVector.size());
constRankStems.resize(nameVector.size());
for (i = 0; i < elements.size(); i++) {
StringC name(nameVector[i].name);
name += rankSuffix;
if (name.size() > syntax().namelen()
&& nameVector[i].name.size() <= syntax().namelen())
message(ParserMessages::genericIdentifierLength,
NumberMessageArg(syntax().namelen()));
elements[i] = lookupCreateElement(name);
rankStems[i] = lookupCreateRankStem(nameVector[i].name);
constRankStems[i] = rankStems[i];
}
static AllowedParams
allowOmissionContent(Param::reservedName + Syntax::rO,
Param::minus,
Param::reservedName + Syntax::rCDATA,
Param::reservedName + Syntax::rRCDATA,
Param::reservedName + Syntax::rEMPTY,
Param::reservedName + Syntax::rANY,
Param::modelGroup);
Token token = getToken(mdMinusMode);
if (token == tokenNameStart)
message(ParserMessages::psRequired);
currentInput()->ungetToken();
if (!parseParam(allowOmissionContent, declInputLevel, parm))
return 0;
}
else {
for (i = 0; i < elements.size(); i++) {
// StringC *origName;
// origName = new StringC(nameVector[i].origName);
elements[i] = lookupCreateElement(nameVector[i].name);
elements[i]->setOrigName(nameVector[i].origName);
}
}
for (i = 0; i < elements.size(); i++)
if (defDtd().lookupRankStem(elements[i]->name()) && validate())
message(ParserMessages::rankStemGenericIdentifier,
StringMessageArg(elements[i]->name()));
unsigned char omitFlags = 0;
if (parm.type == Param::minus
|| parm.type == Param::reservedName + Syntax::rO) {
if (options().warnMinimizationParam)
message(ParserMessages::minimizationParam);
omitFlags |= ElementDefinition::omitSpec;
if (parm.type != Param::minus)
omitFlags |= ElementDefinition::omitStart;
static AllowedParams allowOmission(Param::reservedName + Syntax::rO,
Param::minus);
if (!parseParam(allowOmission, declInputLevel, parm))
return 0;
if (parm.type != Param::minus)
omitFlags |= ElementDefinition::omitEnd;
static AllowedParams allowContent(Param::reservedName + Syntax::rCDATA,
Param::reservedName + Syntax::rRCDATA,
Param::reservedName + Syntax::rEMPTY,
Param::reservedName + Syntax::rANY,
Param::modelGroup);
if (!parseParam(allowContent, declInputLevel, parm))
return 0;
}
else {
if (sd().omittag())
message(ParserMessages::missingTagMinimization);
}
Ptr<ElementDefinition> def;
switch (parm.type) {
case Param::reservedName + Syntax::rCDATA:
def = new ElementDefinition(markupLocation(),
defDtd().allocElementDefinitionIndex(),
omitFlags,
ElementDefinition::cdata);
if (!parseParam(allowMdc, declInputLevel, parm))
return 0;
if (options().warnCdataContent)
message(ParserMessages::cdataContent);
break;
case Param::reservedName + Syntax::rRCDATA:
def = new ElementDefinition(markupLocation(),
defDtd().allocElementDefinitionIndex(),
omitFlags,
ElementDefinition::rcdata);
if (!parseParam(allowMdc, declInputLevel, parm))
return 0;
if (options().warnRcdataContent)
message(ParserMessages::rcdataContent);
break;
case Param::reservedName + Syntax::rEMPTY:
def = new ElementDefinition(markupLocation(),
defDtd().allocElementDefinitionIndex(),
omitFlags,
ElementDefinition::empty);
if ((omitFlags & ElementDefinition::omitSpec)
&& !(omitFlags & ElementDefinition::omitEnd)
&& options().warnShould)
message(ParserMessages::emptyOmitEndTag);
if (!parseParam(allowMdc, declInputLevel, parm))
return 0;
break;
case Param::reservedName + Syntax::rANY:
def = new ElementDefinition(markupLocation(),
defDtd().allocElementDefinitionIndex(),
omitFlags,
ElementDefinition::any);
if (!parseExceptions(declInputLevel, def))
return 0;
break;
case Param::modelGroup:
{
unsigned long cnt = parm.modelGroupPtr->grpgtcnt();
// The outermost model group isn't formally a content token.
if (cnt - 1 > syntax().grpgtcnt())
message(ParserMessages::grpgtcnt, NumberMessageArg(syntax().grpgtcnt()));
Owner<CompiledModelGroup>
modelGroup(new CompiledModelGroup(parm.modelGroupPtr));
Vector<ContentModelAmbiguity> ambiguities;
Boolean pcdataUnreachable;
modelGroup->compile(currentDtd().nElementTypeIndex(), ambiguities,
pcdataUnreachable);
if (pcdataUnreachable && options().warnMixedContent)
message(ParserMessages::pcdataUnreachable);
if (validate()) {
for (i = 0; i < ambiguities.size(); i++) {
const ContentModelAmbiguity &a = ambiguities[i];
reportAmbiguity(a.from, a.to1, a.to2, a.andDepth);
}
}
def = new ElementDefinition(markupLocation(),
defDtd().allocElementDefinitionIndex(),
omitFlags,
ElementDefinition::modelGroup,
modelGroup);
if (!parseExceptions(declInputLevel, def))
return 0;
}
break;
}
if (rankSuffix.size() > 0)
def->setRank(rankSuffix, constRankStems);
ConstPtr<ElementDefinition> constDef(def);
for (i = 0; i < elements.size(); i++) {
if (elements[i]->definition() != 0) {
if (validate())
message(ParserMessages::duplicateElementDefinition,
StringMessageArg(elements[i]->name()));
}
else {
elements[i]->setElementDefinition(constDef, i);
if (!elements[i]->attributeDef().isNull())
checkElementAttribute(elements[i]);
}
if (rankStems.size() > 0)
rankStems[i]->addDefinition(constDef);
}
if (currentMarkup()) {
Vector<const ElementType *> v(elements.size());
for (i = 0; i < elements.size(); i++)
v[i] = elements[i];
eventHandler().elementDecl(new (eventAllocator())
ElementDeclEvent(v, currentDtdPointer(),
markupLocation(),
currentMarkup()));
}
return 1;
}
void Parser::reportAmbiguity(const LeafContentToken *from,
const LeafContentToken *to1,
const LeafContentToken *to2,
unsigned ambigAndDepth)
{
StringC toName;
const ElementType *toType = to1->elementType();
if (toType)
toName = toType->name();
else {
toName = syntax().delimGeneral(Syntax::dRNI);
toName += syntax().reservedName(Syntax::rPCDATA);
}
unsigned to1Index = to1->typeIndex() + 1;
unsigned to2Index = to2->typeIndex() + 1;
if (from->isInitial())
message(ParserMessages::ambiguousModelInitial,
StringMessageArg(toName),
OrdinalMessageArg(to1Index),
OrdinalMessageArg(to2Index));
else {
StringC fromName;
const ElementType *fromType = from->elementType();
if (fromType)
fromName = fromType->name();
else {
fromName = syntax().delimGeneral(Syntax::dRNI);
fromName += syntax().reservedName(Syntax::rPCDATA);
}
unsigned fromIndex = from->typeIndex() + 1;
unsigned andMatches = from->andDepth() - ambigAndDepth;
if (andMatches == 0)
message(ParserMessages::ambiguousModel,
StringMessageArg(fromName),
OrdinalMessageArg(fromIndex),
StringMessageArg(toName),
OrdinalMessageArg(to1Index),
OrdinalMessageArg(to2Index));
else if (andMatches == 1)
message(ParserMessages::ambiguousModelSingleAnd,
StringMessageArg(fromName),
OrdinalMessageArg(fromIndex),
StringMessageArg(toName),
OrdinalMessageArg(to1Index),
OrdinalMessageArg(to2Index));
else
message(ParserMessages::ambiguousModelMultipleAnd,
StringMessageArg(fromName),
OrdinalMessageArg(fromIndex),
NumberMessageArg(andMatches),
StringMessageArg(toName),
OrdinalMessageArg(to1Index),
OrdinalMessageArg(to2Index));
}
}
// Check the compatibility of the attribute definition with
// the element definition.
void Parser::checkElementAttribute(const ElementType *e, size_t checkFrom)
{
if (!validate())
return;
const AttributeDefinitionList *attDef = e->attributeDef().pointer();
Boolean conref = 0;
ASSERT(e != 0);
const ElementDefinition *edef = e->definition();
ASSERT(edef != 0);
ASSERT(attDef != 0);
size_t attDefLength = attDef->size();
for (size_t i = checkFrom; i < attDefLength; i++) {
const AttributeDefinition *p = attDef->def(i);
if (p->isConref())
conref = 1;
if (p->isNotation()
&& edef->declaredContent() == ElementDefinition::empty)
message(ParserMessages::notationEmpty, StringMessageArg(e->name()));
}
if (conref) {
#if 0
if (edef->omittedTagSpec() && !edef->canOmitEndTag()
&& options().warnShould)
message(ParserMessages::conrefOmitEndTag, StringMessageArg(e->name()));
#endif
if (edef->declaredContent() == ElementDefinition::empty)
message(ParserMessages::conrefEmpty, StringMessageArg(e->name()));
}
}
ElementType *Parser::lookupCreateElement(const StringC &name)
{
ElementType *e = defDtd().lookupElementType(name);
if (!e) {
if (haveDefLpd())
message(ParserMessages::noSuchSourceElement, StringMessageArg(name));
else {
e = new ElementType(name, defDtd().allocElementTypeIndex());
defDtd().insertElementType(e);
}
}
return e;
}
RankStem *Parser::lookupCreateRankStem(const StringC &name)
{
RankStem *r = defDtd().lookupRankStem(name);
if (!r) {
r = new RankStem(name, defDtd().nRankStem());
defDtd().insertRankStem(r);
const ElementType *e = defDtd().lookupElementType(name);
if (e && e->definition() != 0)
message(ParserMessages::rankStemGenericIdentifier, StringMessageArg(name));
}
return r;
}
Boolean Parser::parseExceptions(unsigned declInputLevel,
Ptr<ElementDefinition> &def)
{
Param parm;
static AllowedParams
allowExceptionsMdc(Param::mdc, Param::exclusions, Param::inclusions);
if (!parseParam(allowExceptionsMdc, declInputLevel, parm))
return 0;
if (parm.type == Param::exclusions) {
if (options().warnExclusion)
message(ParserMessages::exclusion);
def->setExclusions(parm.elementVector);
static AllowedParams allowInclusionsMdc(Param::mdc, Param::inclusions);
if (!parseParam(allowInclusionsMdc, declInputLevel, parm))
return 0;
}
if (parm.type == Param::inclusions) {
if (options().warnInclusion)
message(ParserMessages::inclusion);
def->setInclusions(parm.elementVector);
size_t nI = def->nInclusions();
size_t nE = def->nExclusions();
if (nE) {
for (size_t i = 0; i < nI; i++) {
const ElementType *e = def->inclusion(i);
for (size_t j = 0; j < nE; j++)
if (def->exclusion(j) == e)
message(ParserMessages::excludeIncludeSame,
StringMessageArg(e->name()));
}
}
if (!parseParam(allowMdc, declInputLevel, parm))
return 0;
}
return 1;
}
Boolean Parser::parseAttlistDecl()
{
unsigned declInputLevel = inputLevel();
Param parm;
size_t attcnt = 0;
size_t idIndex = size_t(-1);
size_t notationIndex = size_t(-1);
Boolean anyCurrent = 0;
Boolean isNotation;
Vector<Attributed *> attributed;
if (!parseAttributed(declInputLevel, parm, attributed, isNotation))
return 0;
Vector<CopyOwner<AttributeDefinition> > defs;
if (!parseParam(sd().www() ? allowNameMdc : allowName, declInputLevel, parm))
return 0;
while (parm.type != Param::mdc) {
StringC attributeName;
StringC origAttributeName;
parm.token.swap(attributeName);
parm.origToken.swap(origAttributeName);
attcnt++;
Boolean duplicate = 0;
size_t i;
for (i = 0; i < defs.size(); i++)
if (defs[i]->name() == attributeName) {
message(ParserMessages::duplicateAttributeDef,
StringMessageArg(attributeName));
duplicate = 1;
break;
}
Owner<DeclaredValue> declaredValue;
if (!parseDeclaredValue(declInputLevel, isNotation, parm, declaredValue))
return 0;
if (!duplicate) {
if (declaredValue->isId()) {
if (idIndex != size_t(-1))
message(ParserMessages::multipleIdAttributes,
StringMessageArg(defs[idIndex]->name()));
idIndex = defs.size();
}
else if (declaredValue->isNotation()) {
if (notationIndex != size_t(-1))
message(ParserMessages::multipleNotationAttributes,
StringMessageArg(defs[notationIndex]->name()));
notationIndex = defs.size();
}
}
const Vector<StringC> *tokensPtr = declaredValue->getTokens();
if (tokensPtr) {
size_t nTokens = tokensPtr->size();
if (!sd().www()) {
Vector<StringC>::const_iterator tokens = tokensPtr->begin();
for (i = 0; i < nTokens; i++) {
for (size_t j = 0; j < defs.size(); j++)
if (defs[j]->containsToken(tokens[i])) {
message(ParserMessages::duplicateAttributeToken,
StringMessageArg(tokens[i]));
break;
}
}
}
attcnt += nTokens;
}
Owner<AttributeDefinition> def;
if (!parseDefaultValue(declInputLevel, isNotation, parm, attributeName,
declaredValue, def, anyCurrent))
return 0;
if (haveDefLpd() && defLpd().type() == Lpd::simpleLink && !def->isFixed())
message(ParserMessages::simpleLinkFixedAttribute);
def->setOrigName(origAttributeName);
if (!duplicate) {
defs.resize(defs.size() + 1);
defs.back() = def.extract();
}
static AllowedParams allowNameMdc(Param::name, Param::mdc);
if (!parseParam(allowNameMdc, declInputLevel, parm))
return 0;
}
if (attcnt > syntax().attcnt())
message(ParserMessages::attcnt,
NumberMessageArg(attcnt),
NumberMessageArg(syntax().attcnt()));
if (haveDefLpd() && !isNotation) {
if (defLpd().type() == Lpd::simpleLink) {
for (size_t i = 0; i < attributed.size(); i++) {
const ElementType *e = (const ElementType *)attributed[i];
if (e) {
if (e->name() == defLpd().sourceDtd()->name()) {
SimpleLpd &lpd = (SimpleLpd &)defLpd();
if (lpd.attributeDef().isNull())
lpd.setAttributeDef(new AttributeDefinitionList(defs, 0));
else
message(ParserMessages::duplicateAttlistElement,
StringMessageArg(e->name()));
}
else
message(ParserMessages::simpleLinkAttlistElement,
StringMessageArg(e->name()));
}
}
}
else {
Ptr<AttributeDefinitionList>
adl(new AttributeDefinitionList(defs,
defComplexLpd()
.allocAttributeDefinitionListIndex()));
for (size_t i = 0; i < attributed.size(); i++) {
const ElementType *e = (const ElementType *)attributed[i];
if (e) {
if (defComplexLpd().attributeDef(e).isNull())
defComplexLpd().setAttributeDef(e, adl);
else
message(ParserMessages::duplicateAttlistElement,
StringMessageArg(e->name()));
}
}
}
}
else {
Ptr<AttributeDefinitionList>
adl(new AttributeDefinitionList(defs,
defDtd()
.allocAttributeDefinitionListIndex(),
anyCurrent,
idIndex,
notationIndex));
for (size_t i = 0; i < attributed.size(); i++) {
if (attributed[i]->attributeDef().isNull()) {
attributed[i]->setAttributeDef(adl);
if (!isNotation) {
ElementType *e = (ElementType *)attributed[i];
if (e->definition() != 0)
checkElementAttribute(e);
}
}
else if (options().errorAfdr && !sd().www()) {
if (isNotation)
message(ParserMessages::duplicateAttlistNotation,
StringMessageArg(((Notation *)attributed[i])->name()));
else
message(ParserMessages::duplicateAttlistElement,
StringMessageArg(((ElementType *)attributed[i])->name()));
}
else {
if (!hadAfdrDecl() && !sd().www()) {
message(ParserMessages::missingAfdrDecl);
setHadAfdrDecl();
}
AttributeDefinitionList *curAdl;
{
// Use block to make sure temporary gets destroyed.
curAdl = attributed[i]->attributeDef().pointer();
}
size_t oldSize = curAdl->size();
if (curAdl->count() != 1) {
Vector<CopyOwner<AttributeDefinition> > copy(oldSize);
for (size_t j = 0; j < oldSize; j++)
copy[j] = curAdl->def(j)->copy();
Ptr<AttributeDefinitionList> adlCopy
= new AttributeDefinitionList(copy,
defDtd().allocAttributeDefinitionListIndex(),
curAdl->anyCurrent(),
curAdl->idIndex(),
curAdl->notationIndex());
attributed[i]->setAttributeDef(adlCopy);
curAdl = adlCopy.pointer();
}
for (size_t j = 0; j < adl->size(); j++) {
unsigned index;
if (!curAdl->attributeIndex(adl->def(j)->name(), index)) {
index = curAdl->idIndex();
if (index != -1 && adl->def(j)->isId())
message(ParserMessages::multipleIdAttributes,
StringMessageArg(curAdl->def(index)->name()));
index = curAdl->notationIndex();
if (index != -1 && adl->def(j)->isNotation())
message(ParserMessages::multipleNotationAttributes,
StringMessageArg(curAdl->def(index)->name()));
curAdl->append(adl->def(j)->copy());
}
else {
Boolean tem;
if (curAdl->def(index)->isSpecified(tem))
message(ParserMessages::specifiedAttributeRedeclared,
StringMessageArg(adl->def(j)->name()));
}
}
if (!isNotation) {
ElementType *e = (ElementType *)attributed[i];
if (e->definition() != 0)
checkElementAttribute(e, oldSize);
}
}
}
}
if (currentMarkup()) {
if (isNotation) {
Vector<ConstPtr<Notation> > v(attributed.size());
for (size_t i = 0; i < attributed.size(); i++)
v[i] = (Notation *)attributed[i];
eventHandler()
.attlistNotationDecl(new (eventAllocator())
AttlistNotationDeclEvent(v,
markupLocation(),
currentMarkup()));
}
else {
Vector<const ElementType *> v(attributed.size());
for (size_t i = 0; i < attributed.size(); i++)
v[i] = (ElementType *)attributed[i];
if (haveDefLpd())
eventHandler()
.linkAttlistDecl(new (eventAllocator())
LinkAttlistDeclEvent(v,
defLpdPointer(),
markupLocation(),
currentMarkup()));
else
eventHandler().attlistDecl(new (eventAllocator())
AttlistDeclEvent(v,
currentDtdPointer(),
markupLocation(),
currentMarkup()));
}
}
if (isNotation) {
Dtd::EntityIter entityIter(defDtd().generalEntityIter());
for (;;) {
Ptr<Entity> entity(entityIter.next());
if (entity.isNull())
break;
const ExternalDataEntity *external = entity->asExternalDataEntity();
if (external) {
const Notation *entityNotation = external->notation();
for (size_t i = 0; i < attributed.size(); i++)
if ((Notation *)attributed[i] == entityNotation) {
AttributeList attributes(entityNotation->attributeDef());
attributes.finish(*this);
((ExternalDataEntity *)entity.pointer())
->setNotation((Notation *)attributed[i], attributes);
}
}
}
}
return 1;
}
Boolean Parser::parseAttributed(unsigned declInputLevel,
Param &parm,
Vector<Attributed *> &attributed,
Boolean &isNotation)
{
static AllowedParams
allowNameGroupNotation(Param::name,
Param::nameGroup,
Param::indicatedReservedName + Syntax::rNOTATION);
static AllowedParams
allowNameGroupNotationAll(Param::name,
Param::nameGroup,
Param::indicatedReservedName
+ Syntax::rNOTATION,
Param::indicatedReservedName
+ Syntax::rALL,
Param::indicatedReservedName
+ Syntax::rIMPLICIT);
if (!parseParam(haveDefLpd()
? allowNameGroupNotation
: allowNameGroupNotationAll,
declInputLevel, parm))
return 0;
if (parm.type == Param::indicatedReservedName + Syntax::rNOTATION) {
if (options().warnDataAttributes)
message(ParserMessages::dataAttributes);
isNotation = 1;
static AllowedParams
allowNameGroupAll(Param::name,
Param::nameGroup,
Param::indicatedReservedName + Syntax::rALL,
Param::indicatedReservedName + Syntax::rIMPLICIT);
if (!parseParam(haveDefLpd()
? allowNameNameGroup
: allowNameGroupAll,
declInputLevel, parm))
return 0;
if (parm.type == Param::nameGroup) {
attributed.resize(parm.nameTokenVector.size());
for (size_t i = 0; i < attributed.size(); i++)
attributed[i] = lookupCreateNotation(parm.nameTokenVector[i].name);
}
else {
if (parm.type != Param::name && !hadAfdrDecl() && !sd().www()) {
message(ParserMessages::missingAfdrDecl);
setHadAfdrDecl();
}
attributed.resize(1);
attributed[0]
= lookupCreateNotation(parm.type == Param::name
? parm.token
: syntax().rniReservedName(Syntax::ReservedName(parm.type - Param::indicatedReservedName)));
}
}
else {
isNotation = 0;
if (parm.type == Param::nameGroup) {
if (options().warnAttlistGroupDecl)
message(ParserMessages::attlistGroupDecl);
attributed.resize(parm.nameTokenVector.size());
for (size_t i = 0; i < attributed.size(); i++)
attributed[i] = lookupCreateElement(parm.nameTokenVector[i].name);
}
else {
if (parm.type != Param::name && !hadAfdrDecl() && !sd().www()) {
message(ParserMessages::missingAfdrDecl);
setHadAfdrDecl();
}
attributed.resize(1);
attributed[0]
= lookupCreateElement(parm.type == Param::name
? parm.token
: syntax().rniReservedName(Syntax::ReservedName(parm.type - Param::indicatedReservedName)));
}
}
return 1;
}
Boolean Parser::parseDeclaredValue(unsigned declInputLevel,
Boolean isNotation,
Param &parm,
Owner<DeclaredValue> &declaredValue)
{
static Param::Type declaredValues[] = {
Param::reservedName + Syntax::rCDATA,
Param::reservedName + Syntax::rENTITY,
Param::reservedName + Syntax::rENTITIES,
Param::reservedName + Syntax::rID,
Param::reservedName + Syntax::rIDREF,
Param::reservedName + Syntax::rIDREFS,
Param::reservedName + Syntax::rNAME,
Param::reservedName + Syntax::rNAMES,
Param::reservedName + Syntax::rNMTOKEN,
Param::reservedName + Syntax::rNMTOKENS,
Param::reservedName + Syntax::rNUMBER,
Param::reservedName + Syntax::rNUMBERS,
Param::reservedName + Syntax::rNUTOKEN,
Param::reservedName + Syntax::rNUTOKENS,
Param::reservedName + Syntax::rNOTATION,
Param::nameTokenGroup,
Param::reservedName + Syntax::rDATA
};
static AllowedParams allowDeclaredValue(declaredValues,
SIZEOF(declaredValues) - 1);
static AllowedParams allowDeclaredValueData(declaredValues,
SIZEOF(declaredValues));
if (!parseParam(sd().www() ? allowDeclaredValueData : allowDeclaredValue,
declInputLevel, parm))
return 0;
enum { asDataAttribute = 01, asLinkAttribute = 02 };
unsigned allowedFlags = asDataAttribute|asLinkAttribute;
switch (parm.type) {
case Param::reservedName + Syntax::rCDATA:
declaredValue = new CdataDeclaredValue;
break;
case Param::reservedName + Syntax::rENTITY:
declaredValue = new EntityDeclaredValue(0);
allowedFlags = asLinkAttribute;
break;
case Param::reservedName + Syntax::rENTITIES:
declaredValue = new EntityDeclaredValue(1);
allowedFlags = asLinkAttribute;
break;
case Param::reservedName + Syntax::rID:
declaredValue = new IdDeclaredValue;
allowedFlags = 0;
break;
case Param::reservedName + Syntax::rIDREF:
declaredValue = new IdrefDeclaredValue(0);
allowedFlags = 0;
break;
case Param::reservedName + Syntax::rIDREFS:
declaredValue = new IdrefDeclaredValue(1);
allowedFlags = 0;
break;
case Param::reservedName + Syntax::rNAME:
declaredValue
= new TokenizedDeclaredValue(TokenizedDeclaredValue::name, 0);
if (options().warnNameDeclaredValue)
message(ParserMessages::nameDeclaredValue);
break;
case Param::reservedName + Syntax::rNAMES:
declaredValue
= new TokenizedDeclaredValue(TokenizedDeclaredValue::name, 1);
if (options().warnNameDeclaredValue)
message(ParserMessages::nameDeclaredValue);
break;
case Param::reservedName + Syntax::rNMTOKEN:
declaredValue
= new TokenizedDeclaredValue(TokenizedDeclaredValue::nameToken, 0);
break;
case Param::reservedName + Syntax::rNMTOKENS:
declaredValue
= new TokenizedDeclaredValue(TokenizedDeclaredValue::nameToken, 1);
break;
case Param::reservedName + Syntax::rNUMBER:
declaredValue
= new TokenizedDeclaredValue(TokenizedDeclaredValue::number, 0);
if (options().warnNumberDeclaredValue)
message(ParserMessages::numberDeclaredValue);
break;
case Param::reservedName + Syntax::rNUMBERS:
declaredValue
= new TokenizedDeclaredValue(TokenizedDeclaredValue::number, 1);
if (options().warnNumberDeclaredValue)
message(ParserMessages::numberDeclaredValue);
break;
case Param::reservedName + Syntax::rNUTOKEN:
declaredValue
= new TokenizedDeclaredValue(TokenizedDeclaredValue::numberToken, 0);
if (options().warnNutokenDeclaredValue)
message(ParserMessages::nutokenDeclaredValue);
break;
case Param::reservedName + Syntax::rNUTOKENS:
declaredValue
= new TokenizedDeclaredValue(TokenizedDeclaredValue::numberToken, 1);
if (options().warnNutokenDeclaredValue)
message(ParserMessages::nutokenDeclaredValue);
break;
case Param::reservedName + Syntax::rNOTATION:
{
static AllowedParams allowNameGroup(Param::nameGroup);
if (!parseParam(allowNameGroup, declInputLevel, parm))
return 0;
Vector<StringC> group(parm.nameTokenVector.size());
for (size_t i = 0; i < group.size(); i++)
parm.nameTokenVector[i].name.swap(group[i]);
declaredValue = new NotationDeclaredValue(group);
allowedFlags = 0;
}
break;
case Param::nameTokenGroup:
{
Vector<StringC> group(parm.nameTokenVector.size());
Vector<StringC> origGroup(parm.nameTokenVector.size());
for (size_t i = 0; i < group.size(); i++) {
parm.nameTokenVector[i].name.swap(group[i]);
parm.nameTokenVector[i].origName.swap(origGroup[i]);
}
GroupDeclaredValue *grpVal = new NameTokenGroupDeclaredValue(group);
grpVal->setOrigAllowedValues(origGroup);
declaredValue = grpVal;
}
break;
case Param::reservedName + Syntax::rDATA:
{
if (!parseParam(allowName, declInputLevel, parm))
return 0;
Ptr<Notation> notation(lookupCreateNotation(parm.token));
static AllowedParams allowDsoSilentValue(Param::dso, Param::silent);
AttributeList attributes(notation->attributeDef());
if (parseParam(allowDsoSilentValue, declInputLevel, parm)
&& parm.type == Param::dso) {
if (attributes.size() == 0 && !sd().www())
message(ParserMessages::notationNoAttributes,
StringMessageArg(notation->name()));
Boolean netEnabling;
Ptr<AttributeDefinitionList> newAttDef;
if (!parseAttributeSpec(asMode, attributes, netEnabling, newAttDef))
return 0;
if (!newAttDef.isNull()) {
newAttDef->setIndex(defDtd().allocAttributeDefinitionListIndex());
notation->setAttributeDef(newAttDef);
}
if (attributes.nSpec() == 0)
message(ParserMessages::emptyDataAttributeSpec);
}
else {
attributes.finish(*this);
// unget the first token of the default value
currentInput()->ungetToken();
}
ConstPtr<Notation> nt(notation.pointer());
declaredValue = new DataDeclaredValue(nt, attributes);
}
break;
default:
CANNOT_HAPPEN();
}
if (isNotation) {
if (!(allowedFlags & asDataAttribute))
message(ParserMessages::dataAttributeDeclaredValue);
}
else if (haveDefLpd() && !isNotation && !(allowedFlags & asLinkAttribute))
message(ParserMessages::linkAttributeDeclaredValue);
return 1;
}
Boolean Parser::parseDefaultValue(unsigned declInputLevel,
Boolean isNotation,
Param &parm,
const StringC &attributeName,
Owner<DeclaredValue> &declaredValue,
Owner<AttributeDefinition> &def,
Boolean &anyCurrent)
{
// default value
static AllowedParams
allowDefaultValue(Param::indicatedReservedName + Syntax::rFIXED,
Param::indicatedReservedName + Syntax::rREQUIRED,
Param::indicatedReservedName + Syntax::rCURRENT,
Param::indicatedReservedName + Syntax::rCONREF,
Param::indicatedReservedName + Syntax::rIMPLIED,
Param::attributeValue,
Param::attributeValueLiteral);
static AllowedParams
allowTokenDefaultValue(Param::indicatedReservedName + Syntax::rFIXED,
Param::indicatedReservedName + Syntax::rREQUIRED,
Param::indicatedReservedName + Syntax::rCURRENT,
Param::indicatedReservedName + Syntax::rCONREF,
Param::indicatedReservedName + Syntax::rIMPLIED,
Param::attributeValue,
Param::tokenizedAttributeValueLiteral);
if (!parseParam(declaredValue->tokenized()
? allowTokenDefaultValue
: allowDefaultValue, declInputLevel, parm))
return 0;
switch (parm.type) {
case Param::indicatedReservedName + Syntax::rFIXED:
{
static AllowedParams allowValue(Param::attributeValue,
Param::attributeValueLiteral);
static AllowedParams
allowTokenValue(Param::attributeValue,
Param::tokenizedAttributeValueLiteral);
if (!parseParam(declaredValue->tokenized()
? allowTokenValue
: allowValue, declInputLevel, parm))
return 0;
unsigned specLength = 0;
AttributeValue *value = declaredValue->makeValue(parm.literalText,
*this,
attributeName,
specLength);
if (declaredValue->isId())
message(ParserMessages::idDeclaredValue);
def = new FixedAttributeDefinition(attributeName,
declaredValue.extract(),
value);
}
break;
case Param::attributeValue:
if (options().warnAttributeValueNotLiteral)
message(ParserMessages::attributeValueNotLiteral);
// fall through
case Param::attributeValueLiteral:
case Param::tokenizedAttributeValueLiteral:
{
unsigned specLength = 0;
AttributeValue *value = declaredValue->makeValue(parm.literalText,
*this,
attributeName,
specLength);
if (declaredValue->isId())
message(ParserMessages::idDeclaredValue);
def = new DefaultAttributeDefinition(attributeName,
declaredValue.extract(),
value);
}
break;
case Param::indicatedReservedName + Syntax::rREQUIRED:
def = new RequiredAttributeDefinition(attributeName,
declaredValue.extract());
break;
case Param::indicatedReservedName + Syntax::rCURRENT:
anyCurrent = 1;
if (declaredValue->isId())
message(ParserMessages::idDeclaredValue);
def = new CurrentAttributeDefinition(attributeName,
declaredValue.extract(),
defDtd().allocCurrentAttributeIndex());
if (isNotation)
message(ParserMessages::dataAttributeDefaultValue);
else if (haveDefLpd())
message(ParserMessages::linkAttributeDefaultValue);
else if (options().warnCurrent)
message(ParserMessages::currentAttribute);
break;
case Param::indicatedReservedName + Syntax::rCONREF:
if (declaredValue->isId())
message(ParserMessages::idDeclaredValue);
if (declaredValue->isNotation())
message(ParserMessages::notationConref);
def = new ConrefAttributeDefinition(attributeName,
declaredValue.extract());
if (isNotation)
message(ParserMessages::dataAttributeDefaultValue);
else if (haveDefLpd())
message(ParserMessages::linkAttributeDefaultValue);
else if (options().warnConref)
message(ParserMessages::conrefAttribute);
break;
case Param::indicatedReservedName + Syntax::rIMPLIED:
def = new ImpliedAttributeDefinition(attributeName,
declaredValue.extract());
break;
default:
CANNOT_HAPPEN();
}
return 1;
}
// parm contains either system or public
Boolean Parser::parseExternalId(const AllowedParams &sysidAllow,
const AllowedParams &endAllow,
Boolean maybeWarnMissingSystemId,
unsigned declInputLevel,
Param &parm,
ExternalId &id)
{
id.setLocation(currentLocation());
if (parm.type == Param::reservedName + Syntax::rPUBLIC) {
static AllowedParams allowMinimumLiteral(Param::minimumLiteral);
if (!parseParam(allowMinimumLiteral, declInputLevel, parm))
return 0;
const MessageType1 *fpierr;
const MessageType1 *urnerr;
switch (id.setPublic(parm.literalText, sd().internalCharset(),
syntax().space(), fpierr, urnerr)) {
case PublicId::fpi:
{
PublicId::TextClass textClass;
if (sd().formal() && id.publicId()->getTextClass(textClass) && textClass == PublicId::SD)
message(ParserMessages::wwwRequired);
if (sd().urn() && !sd().formal())
message(*urnerr, StringMessageArg(*id.publicIdString()));
}
break;
case PublicId::urn:
if (sd().formal() && !sd().urn())
message(*fpierr, StringMessageArg(*id.publicIdString()));
break;
case PublicId::informal:
if (sd().formal())
message(*fpierr, StringMessageArg(*id.publicIdString()));
if (sd().urn())
message(*urnerr, StringMessageArg(*id.publicIdString()));
break;
}
}
if (!parseParam(sysidAllow, declInputLevel, parm))
return 0;
if (parm.type == Param::systemIdentifier) {
id.setSystem(parm.literalText);
if (!parseParam(endAllow, declInputLevel, parm))
return 0;
}
else if (options().warnMissingSystemId && maybeWarnMissingSystemId)
message(ParserMessages::missingSystemId);
return 1;
}
Boolean Parser::parseNotationDecl()
{
unsigned declInputLevel = inputLevel();
Param parm;
if (!parseParam(allowName, declInputLevel, parm))
return 0;
Notation *nt = lookupCreateNotation(parm.token);
if (validate() && nt->defined())
message(ParserMessages::duplicateNotationDeclaration,
StringMessageArg(parm.token));
AttributeDefinitionList *atts = nt->attributeDef().pointer();
if (atts)
for (size_t i = 0; i < atts->size(); i++) {
Boolean implicit;
if (atts->def(i)->isSpecified(implicit) && implicit) {
message(ParserMessages::notationMustNotBeDeclared,
StringMessageArg(parm.token));
break;
}
}
static AllowedParams
allowPublicSystem(Param::reservedName + Syntax::rPUBLIC,
Param::reservedName + Syntax::rSYSTEM);
if (!parseParam(allowPublicSystem, declInputLevel, parm))
return 0;
static AllowedParams allowSystemIdentifierMdc(Param::systemIdentifier,
Param::mdc);
ExternalId id;
if (!parseExternalId(allowSystemIdentifierMdc, allowMdc,
parm.type == Param::reservedName + Syntax::rSYSTEM,
declInputLevel, parm, id))
return 0;
if (validate() && sd().formal()) {
PublicId::TextClass textClass;
const PublicId *publicId = id.publicId();
if (publicId
&& publicId->getTextClass(textClass)
&& textClass != PublicId::NOTATION)
message(ParserMessages::notationIdentifierTextClass);
}
if (!nt->defined()) {
nt->setExternalId(id, markupLocation());
nt->generateSystemId(*this);
if (currentMarkup())
eventHandler().notationDecl(new (eventAllocator())
NotationDeclEvent(nt, markupLocation(),
currentMarkup()));
}
return 1;
}
Boolean Parser::parseEntityDecl()
{
unsigned declInputLevel = inputLevel();
Param parm;
static AllowedParams
allowEntityNamePero(Param::entityName,
Param::indicatedReservedName + Syntax::rDEFAULT,
Param::pero);
if (!parseParam(allowEntityNamePero, declInputLevel, parm))
return 0;
Entity::DeclType declType;
StringC name; // empty for default entity
if (parm.type == Param::pero) {
declType = Entity::parameterEntity;
static AllowedParams allowParamEntityName(Param::paramEntityName);
if (!parseParam(allowParamEntityName, declInputLevel, parm))
return 0;
parm.token.swap(name);
}
else {
declType = Entity::generalEntity;
if (parm.type == Param::entityName)
parm.token.swap(name);
else if (sd().implydefEntity())
message(ParserMessages::implydefEntityDefault);
else if (options().warnDefaultEntityDecl)
message(ParserMessages::defaultEntityDecl);
}
static AllowedParams
allowEntityTextType(Param::paramLiteral,
Param::reservedName + Syntax::rCDATA,
Param::reservedName + Syntax::rSDATA,
Param::reservedName + Syntax::rPI,
Param::reservedName + Syntax::rSTARTTAG,
Param::reservedName + Syntax::rENDTAG,
Param::reservedName + Syntax::rMS,
Param::reservedName + Syntax::rMD,
Param::reservedName + Syntax::rSYSTEM,
Param::reservedName + Syntax::rPUBLIC);
if (!parseParam(allowEntityTextType, declInputLevel, parm))
return 0;
Location typeLocation(currentLocation());
Entity::DataType dataType = Entity::sgmlText;
InternalTextEntity::Bracketed bracketed = InternalTextEntity::none;
switch (parm.type) {
case Param::reservedName + Syntax::rSYSTEM:
case Param::reservedName + Syntax::rPUBLIC:
return parseExternalEntity(name, declType, declInputLevel, parm);
case Param::reservedName + Syntax::rCDATA:
dataType = Entity::cdata;
if (options().warnInternalCdataEntity)
message(ParserMessages::internalCdataEntity);
break;
case Param::reservedName + Syntax::rSDATA:
dataType = Entity::sdata;
if (options().warnInternalSdataEntity)
message(ParserMessages::internalSdataEntity);
break;
case Param::reservedName + Syntax::rPI:
dataType = Entity::pi;
if (options().warnPiEntity)
message(ParserMessages::piEntity);
break;
case Param::reservedName + Syntax::rSTARTTAG:
bracketed = InternalTextEntity::starttag;
if (options().warnBracketEntity)
message(ParserMessages::bracketEntity);
break;
case Param::reservedName + Syntax::rENDTAG:
bracketed = InternalTextEntity::endtag;
if (options().warnBracketEntity)
message(ParserMessages::bracketEntity);
break;
case Param::reservedName + Syntax::rMS:
bracketed = InternalTextEntity::ms;
if (options().warnBracketEntity)
message(ParserMessages::bracketEntity);
break;
case Param::reservedName + Syntax::rMD:
bracketed = InternalTextEntity::md;
if (options().warnBracketEntity)
message(ParserMessages::bracketEntity);
break;
}
if (parm.type != Param::paramLiteral) {
if (!parseParam(allowParamLiteral, declInputLevel, parm))
return 0;
}
Text text;
parm.literalText.swap(text);
if (bracketed != InternalTextEntity::none) {
StringC open;
StringC close;
switch (bracketed) {
case InternalTextEntity::starttag:
open = instanceSyntax().delimGeneral(Syntax::dSTAGO);
close = instanceSyntax().delimGeneral(Syntax::dTAGC);
break;
case InternalTextEntity::endtag:
open = instanceSyntax().delimGeneral(Syntax::dETAGO);
close = instanceSyntax().delimGeneral(Syntax::dTAGC);
break;
case InternalTextEntity::ms: {
const Syntax &syn =
(declType == Entity::parameterEntity) ? syntax() : instanceSyntax();
open = syn.delimGeneral(Syntax::dMDO);
open += syn.delimGeneral(Syntax::dDSO);
close = syn.delimGeneral(Syntax::dMSC);
close += syn.delimGeneral(Syntax::dMDC);
break;
}
case InternalTextEntity::md: {
const Syntax &syn =
(declType == Entity::parameterEntity) ? syntax() : instanceSyntax();
open = syn.delimGeneral(Syntax::dMDO);
close = syn.delimGeneral(Syntax::dMDC);
break;
}
default:
CANNOT_HAPPEN();
}
text.insertChars(open, Location(new BracketOrigin(typeLocation,
BracketOrigin::open),
0));
text.addChars(close, Location(new BracketOrigin(typeLocation,
BracketOrigin::close),
0));
if (text.size() > syntax().litlen()
&& text.size() - open.size() - close.size() <= syntax().litlen())
message(ParserMessages::bracketedLitlen,
NumberMessageArg(syntax().litlen()));
}
if (!parseParam(allowMdc, declInputLevel, parm))
return 0;
if (declType == Entity::parameterEntity
&& (dataType == Entity::cdata || dataType == Entity::sdata)) {
message(ParserMessages::internalParameterDataEntity,
StringMessageArg(name));
return 1;
}
Ptr<Entity> entity;
switch (dataType) {
case Entity::cdata:
entity = new InternalCdataEntity(name, markupLocation(), text);
break;
case Entity::sdata:
entity = new InternalSdataEntity(name, markupLocation(), text);
break;
case Entity::pi:
entity = new PiEntity(name, declType, markupLocation(), text);
break;
case Entity::sgmlText:
entity = new InternalTextEntity(name, declType, markupLocation(), text, bracketed);
break;
default:
CANNOT_HAPPEN();
break;
}
maybeDefineEntity(entity);
return 1;
}
Boolean Parser::parseExternalEntity(StringC &name,
Entity::DeclType declType,
unsigned declInputLevel,
Param &parm)
{
static AllowedParams
allowSystemIdentifierEntityTypeMdc(Param::systemIdentifier,
Param::reservedName + Syntax::rSUBDOC,
Param::reservedName + Syntax::rCDATA,
Param::reservedName + Syntax::rSDATA,
Param::reservedName + Syntax::rNDATA,
Param::mdc);
static AllowedParams
allowEntityTypeMdc(Param::reservedName + Syntax::rSUBDOC,
Param::reservedName + Syntax::rCDATA,
Param::reservedName + Syntax::rSDATA,
Param::reservedName + Syntax::rNDATA,
Param::mdc);
ExternalId id;
if (!parseExternalId(allowSystemIdentifierEntityTypeMdc, allowEntityTypeMdc,
1, declInputLevel, parm, id))
return 0;
if (parm.type == Param::mdc) {
maybeDefineEntity(new ExternalTextEntity(name, declType, markupLocation(),
id));
return 1;
}
Ptr<Entity> entity;
if (parm.type == Param::reservedName + Syntax::rSUBDOC) {
if (sd().subdoc() == 0)
message(ParserMessages::subdocEntity, StringMessageArg(name));
if (!parseParam(allowMdc, declInputLevel, parm))
return 0;
entity = new SubdocEntity(name, markupLocation(), id);
}
else {
Entity::DataType dataType;
switch (parm.type) {
case Param::reservedName + Syntax::rCDATA:
dataType = Entity::cdata;
if (options().warnExternalCdataEntity)
message(ParserMessages::externalCdataEntity);
break;
case Param::reservedName + Syntax::rSDATA:
dataType = Entity::sdata;
if (options().warnExternalSdataEntity)
message(ParserMessages::externalSdataEntity);
break;
case Param::reservedName + Syntax::rNDATA:
dataType = Entity::ndata;
break;
default:
CANNOT_HAPPEN();
}
if (!parseParam(allowName, declInputLevel, parm))
return 0;
Ptr<Notation> notation(lookupCreateNotation(parm.token));
if (!parseParam(allowDsoMdc, declInputLevel, parm))
return 0;
AttributeList attributes(notation->attributeDef());
if (parm.type == Param::dso) {
if (attributes.size() == 0 && !sd().www())
message(ParserMessages::notationNoAttributes,
StringMessageArg(notation->name()));
Boolean netEnabling;
Ptr<AttributeDefinitionList> newAttDef;
if (!parseAttributeSpec(asMode, attributes, netEnabling, newAttDef))
return 0;
if (!newAttDef.isNull()) {
newAttDef->setIndex(defDtd().allocAttributeDefinitionListIndex());
notation->setAttributeDef(newAttDef);
}
if (attributes.nSpec() == 0)
message(ParserMessages::emptyDataAttributeSpec);
if (!parseParam(allowMdc, declInputLevel, parm))
return 0;
}
else
attributes.finish(*this);
entity = new ExternalDataEntity(name, dataType, markupLocation(), id,
notation, attributes,
declType == Entity::parameterEntity
? Entity::parameterEntity
: Entity::generalEntity);
}
if (declType == Entity::parameterEntity && !sd().www()) {
message(ParserMessages::externalParameterDataSubdocEntity,
StringMessageArg(name));
return 1;
}
maybeDefineEntity(entity);
return 1;
}
Notation *Parser::lookupCreateNotation(const StringC &name)
{
Ptr<Notation> nt = defDtd().lookupNotation(name);
if (nt.isNull()) {
nt = new Notation(name, defDtd().namePointer(), defDtd().isBase());
defDtd().insertNotation(nt);
}
return nt.pointer();
}
void Parser::maybeDefineEntity(const Ptr<Entity> &entity)
{
Dtd &dtd = defDtd();
if (haveDefLpd())
entity->setDeclIn(dtd.namePointer(),
dtd.isBase(),
defLpd().namePointer(),
defLpd().active());
else
entity->setDeclIn(dtd.namePointer(), dtd.isBase());
Boolean ignored = 0;
if (entity->name().size() == 0) {
const Entity *oldEntity = dtd.defaultEntity().pointer();
if (oldEntity == 0
|| (!oldEntity->declInActiveLpd() && entity->declInActiveLpd()))
dtd.setDefaultEntity(entity, *this);
else {
ignored = 1;
if (options().warnDuplicateEntity)
message(ParserMessages::duplicateEntityDeclaration,
StringMessageArg(syntax().rniReservedName(Syntax::rDEFAULT)));
}
}
else {
Ptr<Entity> oldEntity = dtd.insertEntity(entity);
if (oldEntity.isNull())
entity->generateSystemId(*this);
else if (oldEntity->defaulted()) {
dtd.insertEntity(entity, 1);
message(ParserMessages::defaultedEntityDefined,
StringMessageArg(entity->name()));
entity->generateSystemId(*this);
}
else {
if (entity->declInActiveLpd() && !oldEntity->declInActiveLpd()) {
dtd.insertEntity(entity, 1);
entity->generateSystemId(*this);
}
else {
ignored = 1;
if (options().warnDuplicateEntity)
message(entity->declType() == Entity::parameterEntity
? ParserMessages::duplicateParameterEntityDeclaration
: ParserMessages::duplicateEntityDeclaration,
StringMessageArg(entity->name()));
}
}
}
if (currentMarkup())
eventHandler().entityDecl(new (eventAllocator())
EntityDeclEvent(entity, ignored,
markupLocation(),
currentMarkup()));
}
Boolean Parser::parseShortrefDecl()
{
if (!defDtd().isBase())
message(ParserMessages::shortrefOnlyInBaseDtd);
unsigned declInputLevel = inputLevel();
Param parm;
if (!parseParam(allowName, declInputLevel, parm))
return 0;
ShortReferenceMap *map = lookupCreateMap(parm.token);
int valid = 1;
if (map->defined()) {
message(ParserMessages::duplicateShortrefDeclaration,
StringMessageArg(parm.token),
map->defLocation());
valid = 0;
}
else
map->setDefLocation(markupLocation());
if (!parseParam(allowParamLiteral, declInputLevel, parm))
return 0;
Vector<StringC> vec;
do {
StringC delim(parm.literalText.string());
instanceSyntax().generalSubstTable()->subst(delim);
size_t srIndex;
if (!defDtd().shortrefIndex(delim, instanceSyntax(), srIndex)) {
message(ParserMessages::unknownShortrefDelim,
StringMessageArg(prettifyDelim(delim)));
valid = 0;
}
static AllowedParams allowEntityName(Param::entityName);
if (!parseParam(allowEntityName, declInputLevel, parm))
return 0;
if (valid) {
if (srIndex >= vec.size())
vec.resize(srIndex + 1);
if (vec[srIndex].size() > 0) {
message(ParserMessages::delimDuplicateMap,
StringMessageArg(prettifyDelim(delim)));
valid = 0;
}
else
parm.token.swap(vec[srIndex]);
}
static AllowedParams allowParamLiteralMdc(Param::paramLiteral, Param::mdc);
if (!parseParam(allowParamLiteralMdc, declInputLevel, parm))
return 0;
} while (parm.type != Param::mdc);
if (valid) {
map->setNameMap(vec);
if (currentMarkup())
eventHandler().shortrefDecl(new (eventAllocator())
ShortrefDeclEvent(map,
currentDtdPointer(),
markupLocation(),
currentMarkup()));
}
return 1;
}
StringC Parser::prettifyDelim(const StringC &delim)
{
StringC prettyDelim;
for (size_t i = 0; i < delim.size(); i++) {
const StringC *nameP;
if (syntax().charFunctionName(delim[i], nameP)) {
prettyDelim += syntax().delimGeneral(Syntax::dCRO);
prettyDelim += *nameP;
prettyDelim += syntax().delimGeneral(Syntax::dREFC);
}
else
prettyDelim += delim[i];
}
return prettyDelim;
}
ShortReferenceMap *Parser::lookupCreateMap(const StringC &name)
{
ShortReferenceMap *map = defDtd().lookupShortReferenceMap(name);
if (!map) {
map = new ShortReferenceMap(name);
defDtd().insertShortReferenceMap(map);
}
return map;
}
Boolean Parser::parseUsemapDecl()
{
if (!inInstance() && !defDtd().isBase())
message(ParserMessages::usemapOnlyInBaseDtd);
unsigned declInputLevel = inputLevel();
Param parm;
static AllowedParams
allowNameEmpty(Param::name,
Param::indicatedReservedName + Syntax::rEMPTY);
if (!parseParam(allowNameEmpty, declInputLevel, parm))
return 0;
const ShortReferenceMap *map;
if (parm.type == Param::name) {
if (inInstance()) {
map = currentDtd().lookupShortReferenceMap(parm.token);
if (!map)
message(ParserMessages::undefinedShortrefMapInstance,
StringMessageArg(parm.token));
}
else {
ShortReferenceMap *tem = lookupCreateMap(parm.token);
tem->setUsed();
map = tem;
}
}
else
map = &theEmptyMap;
static AllowedParams
allowNameNameGroupMdc(Param::name, Param::nameGroup, Param::mdc);
if (!parseParam(allowNameNameGroupMdc, declInputLevel, parm))
return 0;
if (parm.type != Param::mdc) {
if (inInstance()) {
message(ParserMessages::usemapAssociatedElementTypeInstance);
if (!parseParam(allowMdc, declInputLevel, parm))
return 0;
}
else {
Vector<const ElementType *> v;
if (parm.type == Param::name) {
ElementType *e = lookupCreateElement(parm.token);
v.push_back(e);
if (!e->map())
e->setMap(map);
}
else {
v.resize(parm.nameTokenVector.size());
for (size_t i = 0; i < parm.nameTokenVector.size(); i++) {
ElementType *e
= lookupCreateElement(parm.nameTokenVector[i].name);
v[i] = e;
if (!e->map())
e->setMap(map);
}
}
if (!parseParam(allowMdc, declInputLevel, parm))
return 0;
if (currentMarkup())
eventHandler().usemap(new (eventAllocator())
UsemapEvent(map, v,
currentDtdPointer(),
markupLocation(),
currentMarkup()));
}
}
else {
if (!inInstance())
message(ParserMessages::usemapAssociatedElementTypeDtd);
else if (map) {
if (map != &theEmptyMap && !map->defined())
message(ParserMessages::undefinedShortrefMapInstance,
StringMessageArg(map->name()));
else {
if (currentMarkup()) {
Vector<const ElementType *> v;
eventHandler().usemap(new (eventAllocator())
UsemapEvent(map, v,
currentDtdPointer(),
markupLocation(),
currentMarkup()));
}
currentElement().setMap(map);
}
}
}
return 1;
}
Boolean Parser::parseDoctypeDeclStart()
{
if (hadDtd() && !sd().concur() && !sd().explicitLink())
message(ParserMessages::multipleDtds);
if (hadLpd())
message(ParserMessages::dtdAfterLpd);
unsigned declInputLevel = inputLevel();
Param parm;
static AllowedParams
allowImpliedName(Param::indicatedReservedName + Syntax::rIMPLIED,
Param::name);
if (!parseParam(sd().www() ? allowImpliedName : allowName, declInputLevel, parm))
return 0;
if (parm.type == Param::indicatedReservedName + Syntax::rIMPLIED) {
if (sd().concur() > 0 || sd().explicitLink() > 0)
message(ParserMessages::impliedDoctypeConcurLink);
message(ParserMessages::sorryImpliedDoctype);
return 0;
}
StringC name;
parm.token.swap(name);
if (!lookupDtd(name).isNull())
message(ParserMessages::duplicateDtd, StringMessageArg(name));
static AllowedParams
allowPublicSystemDsoMdc(Param::reservedName + Syntax::rPUBLIC,
Param::reservedName + Syntax::rSYSTEM,
Param::dso,
Param::mdc);
if (!parseParam(allowPublicSystemDsoMdc, declInputLevel, parm))
return 0;
ConstPtr<Entity> entity;
StringC notation;
EntityDecl::DataType data;
ExternalId id;
if (parm.type == Param::reservedName + Syntax::rPUBLIC
|| parm.type == Param::reservedName + Syntax::rSYSTEM) {
static AllowedParams allowSystemIdentifierDsoMdc(Param::systemIdentifier,
Param::dso, Param::mdc);
static AllowedParams
allowSystemIdentifierDsoMdcData(Param::systemIdentifier,
Param::dso, Param::mdc,
Param::reservedName + Syntax::rCDATA,
Param::reservedName + Syntax::rSDATA,
Param::reservedName + Syntax::rNDATA);
static AllowedParams allowDsoMdcData(Param::dso, Param::mdc,
Param::reservedName + Syntax::rCDATA,
Param::reservedName + Syntax::rSDATA,
Param::reservedName + Syntax::rNDATA);
if (!parseExternalId(sd().www() ? allowSystemIdentifierDsoMdcData :
allowSystemIdentifierDsoMdc,
sd().www() ? allowDsoMdcData : allowDsoMdc,
1, declInputLevel, parm, id))
return 0;
switch (parm.type) {
case Param::reservedName + Syntax::rCDATA:
data = Entity::cdata;
break;
case Param::reservedName + Syntax::rSDATA:
data = Entity::sdata;
break;
case Param::reservedName + Syntax::rNDATA:
data = Entity::ndata;
break;
default:
data = Entity::sgmlText;
break;
}
if (data == Entity::sgmlText) {
Ptr<Entity> tem
= new ExternalTextEntity(name, Entity::doctype, markupLocation(), id);
tem->generateSystemId(*this);
entity = tem;
}
#if 0
eventHandler()
.externalEntityDecl(new (eventAllocator())
ExternalEntityDeclEvent(entity, 0));
#endif
else {
// external subset uses some DTD notation
if (!parseParam(allowName, declInputLevel, parm))
return 0;
parm.token.swap(notation);
if (!parseParam(allowDsoMdc, declInputLevel, parm))
return 0;
}
}
else
// no external subset specified
if (sd().implydefDoctype()) {
// FIXME this fails for #IMPLIED, since name isn't yet known
Ptr<Entity> tem
= new ExternalTextEntity(name, Entity::doctype, markupLocation(), id);
tem->generateSystemId(*this);
entity = tem;
}
else if (parm.type == Param::mdc) {
if (sd().implydefElement() == Sd::implydefElementNo) {
message(ParserMessages::noDtdSubset);
enableImplydef();
}
}
// Discard mdc or dso
if (currentMarkup())
currentMarkup()->resize(currentMarkup()->size() - 1);
eventHandler().startDtd(new (eventAllocator())
StartDtdEvent(name, entity, parm.type == Param::dso,
markupLocation(),
currentMarkup()));
startDtd(name);
if (notation.size() > 0) {
// FIXME this case has the wrong entity in the event
// this should be fixed by moving startDtd() call and this code up
ConstPtr<Notation> nt(lookupCreateNotation(notation));
AttributeList attrs(nt->attributeDef());
attrs.finish(*this);
Ptr<Entity> tem
= new ExternalDataEntity(name, data, markupLocation(), id, nt, attrs,
Entity::doctype);
tem->generateSystemId(*this);
// FIXME This is a hack; we need the entity to have the doctype name to
// have generateSytemId() work properly, but have an empty name to add
// it as a parameter entity, which is needed to check the notation
StringC entname;
tem->setName(entname);
defDtd().insertEntity(tem);
entity = tem;
}
if (parm.type == Param::mdc) {
// unget the mdc
currentInput()->ungetToken();
if (entity.isNull()) {
(void)parseDoctypeDeclEnd();
return 1;
}
// reference the entity
Ptr<EntityOrigin> origin
= EntityOrigin::make(internalAllocator(), entity, currentLocation());
entity->dsReference(*this, origin);
if (inputLevel() == 1) { // reference failed
(void)parseDoctypeDeclEnd();
return 1;
}
}
else if (!entity.isNull())
setDsEntity(entity);
setPhase(declSubsetPhase);
return 1;
}
void Parser::implyDtd(const StringC &gi)
{
startMarkup(eventsWanted().wantPrologMarkup(), currentLocation());
#if 0
if (currentMarkup()) {
currentMarkup()->addDelim(Syntax::dMDO);
currentMarkup()->addReservedName(Syntax::rDOCTYPE,
syntax().reservedName(Syntax::rDOCTYPE));
currentMarkup()->addS(syntax().space());
currentMarkup()->addName(gi.data(), gi.size());
}
#endif
if (sd().concur() > 0 || sd().explicitLink() > 0
|| (sd().implydefElement() == Sd::implydefElementNo
&& !sd().implydefDoctype()))
message(ParserMessages::omittedProlog);
if ((sd().implydefElement() != Sd::implydefElementNo) && !sd().implydefDoctype()) {
eventHandler().startDtd(new (eventAllocator())
StartDtdEvent(gi, ConstPtr<Entity>(), 0,
markupLocation(),
currentMarkup()));
startDtd(gi);
parseDoctypeDeclEnd(1);
return;
}
ExternalId id;
// The null location indicates that this is a fake entity.
Entity *tem = new ExternalTextEntity(gi, Entity::doctype, Location(), id);
ConstPtr<Entity> entity(tem);
if (sd().implydefDoctype())
tem->generateSystemId(*this);
else {
// Don't use Entity::generateSystemId because we don't want an error
// if it fails.
StringC str;
if (!entityCatalog().lookup(*entity, syntax(), sd().internalCharset(),
messenger(), str)) {
message(ParserMessages::noDtd);
enableImplydef();
eventHandler().startDtd(new (eventAllocator())
StartDtdEvent(gi, ConstPtr<Entity>(), 0,
markupLocation(),
currentMarkup()));
startDtd(gi);
parseDoctypeDeclEnd(1);
return;
}
id.setEffectiveSystem(str);
#if 0
if (currentMarkup()) {
currentMarkup()->addS(syntax().space());
currentMarkup()->addReservedName(Syntax::rSYSTEM,
syntax().reservedName(Syntax::rSYSTEM));
}
#endif
entity = new ExternalTextEntity(gi,
Entity::doctype,
Location(),
id);
StringC declStr;
declStr += syntax().delimGeneral(Syntax::dMDO);
declStr += syntax().reservedName(Syntax::rDOCTYPE);
declStr += syntax().space();
declStr += gi;
declStr += syntax().space();
declStr += syntax().reservedName(Syntax::rSYSTEM);
declStr += syntax().delimGeneral(Syntax::dMDC);
message(ParserMessages::implyingDtd, StringMessageArg(declStr));
}
Ptr<EntityOrigin> origin
= EntityOrigin::make(internalAllocator(), entity, currentLocation());
eventHandler().startDtd(new (eventAllocator())
StartDtdEvent(gi, entity, 0,
markupLocation(),
currentMarkup()));
startDtd(gi);
entity->dsReference(*this, origin);
if (inputLevel() == 1)
parseDoctypeDeclEnd(1);
else
setPhase(declSubsetPhase);
}
Boolean Parser::parseDoctypeDeclEnd(Boolean fake)
{
checkDtd(defDtd());
Ptr<Dtd> tem(defDtdPointer());
endDtd();
if (fake) {
startMarkup(eventsWanted().wantPrologMarkup(), currentLocation());
#if 0
if (currentMarkup())
currentMarkup()->addDelim(Syntax::dMDC);
#endif
}
else {
startMarkup(eventsWanted().wantPrologMarkup(), currentLocation());
Param parm;
// End DTD before parsing final param so parameter entity reference
// not allowed between ] and >.
if (!parseParam(allowMdc, inputLevel(), parm))
return 0;
}
eventHandler().endDtd(new (eventAllocator()) EndDtdEvent(tem,
markupLocation(),
currentMarkup()));
#if 0
if (fake) {
Char c = syntax().standardFunction(Syntax::fRE);
eventHandler().sSep(new (eventAllocator())
SSepEvent(&c, 1, Location(), 1));
}
#endif
return 1;
}
void Parser::checkDtd(Dtd &dtd)
{
if (dtd.isBase())
addNeededShortrefs(dtd, instanceSyntax());
if (sd().www() || !options().errorAfdr)
addCommonAttributes(dtd);
Dtd::ElementTypeIter elementIter(dtd.elementTypeIter());
ElementType *p;
ConstPtr<ElementDefinition> def;
int i = 0;
while ((p = elementIter.next()) != 0) {
if (p->definition() == 0) {
if (p->name() == dtd.name()) {
if (validate() && (implydefElement() == Sd::implydefElementNo))
message(ParserMessages::documentElementUndefined);
}
else if (options().warnUndefinedElement)
message(ParserMessages::dtdUndefinedElement, StringMessageArg(p->name()));
if (def.isNull())
def = new ElementDefinition(currentLocation(),
size_t(ElementDefinition::undefinedIndex),
ElementDefinition::omitEnd,
ElementDefinition::any,
(implydefElement() != Sd::implydefElementAnyother));
p->setElementDefinition(def, i++);
}
const ShortReferenceMap *map = p->map();
if (map != 0 && map != &theEmptyMap && !map->defined()) {
if (validate())
message(ParserMessages::undefinedShortrefMapDtd,
StringMessageArg(map->name()),
StringMessageArg(p->name()));
p->setMap(0);
}
}
Dtd::ShortReferenceMapIter mapIter(dtd.shortReferenceMapIter());
int nShortref = dtd.nShortref();
for (;;) {
ShortReferenceMap *map = mapIter.next();
if (!map)
break;
Vector<ConstPtr<Entity> > entityMap(nShortref);
for (i = 0; i < nShortref; i++) {
const StringC *entityName = map->entityName(i);
if (entityName) {
ConstPtr<Entity> entity
= lookupEntity(0, *entityName, map->defLocation(), 0);
if (entity.isNull()) {
setNextLocation(map->defLocation());
message(ParserMessages::mapEntityUndefined,
StringMessageArg(*entityName),
StringMessageArg(map->name()));
}
else {
if (entity->defaulted() && options().warnDefaultEntityReference) {
setNextLocation(map->defLocation());
message(ParserMessages::mapDefaultEntity,
StringMessageArg(*entityName),
StringMessageArg(map->name()));
}
entityMap[i] = entity;
}
}
}
map->setEntityMap(entityMap);
if (options().warnUnusedMap && !map->used()) {
setNextLocation(map->defLocation());
message(ParserMessages::unusedMap, StringMessageArg(map->name()));
}
}
if (options().warnUnusedParam) {
Dtd::ConstEntityIter entityIter(((const Dtd &)dtd).parameterEntityIter());
for (;;) {
ConstPtr<Entity> entity(entityIter.next());
if (entity.isNull())
break;
if (!entity->used() && !maybeStatusKeyword(*entity)) {
setNextLocation(entity->defLocation());
message(ParserMessages::unusedParamEntity,
StringMessageArg(entity->name()));
}
}
}
Dtd::ConstEntityIter gEntityIter(((const Dtd &)dtd).generalEntityIter());
Dtd::ConstEntityIter pEntityIter(((const Dtd &)dtd).parameterEntityIter());
for (i = 0; i < (sd().www() ? 2 : 1); i++) {
for (;;) {
ConstPtr<Entity> entity(i == 0 ? gEntityIter.next() : pEntityIter.next());
if (entity.isNull())
break;
const ExternalDataEntity *external = entity->asExternalDataEntity();
if (external) {
Notation *notation = (Notation *)external->notation();
if (!notation->defined()) {
if (sd().implydefNotation()) {
ExternalId id;
notation->setExternalId(id, Location());
notation->generateSystemId(*this);
}
else if (validate()) {
setNextLocation(external->defLocation());
switch (external->declType()) {
case Entity::parameterEntity:
message(ParserMessages::parameterEntityNotationUndefined,
StringMessageArg(notation->name()),
StringMessageArg(external->name()));
break;
case Entity::doctype:
message(ParserMessages::dsEntityNotationUndefined,
StringMessageArg(notation->name()));
break;
default:
message(ParserMessages::entityNotationUndefined,
StringMessageArg(notation->name()),
StringMessageArg(external->name()));
break;
}
}
}
}
}
}
Dtd::NotationIter notationIter(dtd.notationIter());
for (;;) {
Ptr<Notation> notation(notationIter.next());
if (notation.isNull())
break;
if (!notation->defined() && !notation->attributeDef().isNull()) {
if (sd().implydefNotation()) {
ExternalId id;
notation->setExternalId(id, Location());
notation->generateSystemId(*this);
}
else if (validate())
message(ParserMessages::attlistNotationUndefined,
StringMessageArg(notation->name()));
}
}
}
#if 0
void Parser::addCommonAttributes(Dtd &dtd)
{
Ptr<AttributeDefinitionList> commonAdl[2];
{
ElementType *e = dtd.removeElementType(syntax()
.rniReservedName(Syntax::rALL));
if (e) {
commonAdl[0] = e->attributeDef();
delete e;
lookupCreateElement(syntax().rniReservedName(Syntax::rIMPLICIT));
}
}
{
Ptr<Notation> allNotation
= dtd.removeNotation(syntax().rniReservedName(Syntax::rALL));
if (!allNotation.isNull()) {
commonAdl[1] = allNotation->attributeDef();
lookupCreateNotation(syntax().rniReservedName(Syntax::rIMPLICIT));
}
}
Dtd::ElementTypeIter elementIter(dtd.elementTypeIter());
Dtd::NotationIter notationIter(dtd.notationIter());
Vector<PackedBoolean> doneAdl(dtd.nAttributeDefinitionList(),
PackedBoolean(0));
for (int isNotation = 0; isNotation < 2; isNotation++) {
if (!commonAdl[isNotation].isNull()) {
doneAdl[commonAdl[isNotation]->index()] = 1;
for (;;) {
Attributed *a;
if (!isNotation)
a = elementIter.next();
else
a = notationIter.next().pointer();
if (!a)
break;
Ptr<AttributeDefinitionList> adl = a->attributeDef();
if (adl.isNull())
a->setAttributeDef(commonAdl[isNotation]);
else if (!doneAdl[adl->index()]) {
doneAdl[adl->index()] = 1;
for (size_t j = 0; j < commonAdl[isNotation]->size(); j++) {
unsigned tem;
if (!adl->attributeIndex(commonAdl[isNotation]->def(j)->name(),
tem))
adl->append(commonAdl[isNotation]->def(j)->copy());
}
}
}
}
}
{
ElementType *e = dtd.removeElementType(syntax()
.rniReservedName(Syntax::rIMPLICIT));
if (e)
dtd.setImplicitElementAttributeDef(e->attributeDef());
delete e;
}
{
Ptr<Notation> n
= dtd.removeNotation(syntax().rniReservedName(Syntax::rIMPLICIT));
if (!n.isNull())
dtd.setImplicitNotationAttributeDef(n->attributeDef());
}
}
#else
void Parser::addCommonAttributes(Dtd &dtd)
{
// These are #implicit, #all, #notation #implicit, #notation #all
Ptr<AttributeDefinitionList> commonAdl[4];
{
ElementType *e = lookupCreateElement(syntax()
.rniReservedName(Syntax::rIMPLICIT));
commonAdl[0] = e->attributeDef();
e = dtd.removeElementType(syntax().rniReservedName(Syntax::rALL));
if (e)
commonAdl[1] = e->attributeDef();
delete e;
}
{
Ptr<Notation> nt
= lookupCreateNotation(syntax().rniReservedName(Syntax::rIMPLICIT));
commonAdl[2] = nt->attributeDef();
nt = dtd.removeNotation(syntax().rniReservedName(Syntax::rALL));
if (!nt.isNull())
commonAdl[3] = nt->attributeDef();
}
Dtd::ElementTypeIter elementIter(dtd.elementTypeIter());
Dtd::ElementTypeIter element2Iter(dtd.elementTypeIter());
Dtd::NotationIter notationIter(dtd.notationIter());
Dtd::NotationIter notation2Iter(dtd.notationIter());
Vector<PackedBoolean> done1Adl(dtd.nAttributeDefinitionList(),
PackedBoolean(0));
Vector<PackedBoolean> done2Adl(dtd.nAttributeDefinitionList(),
PackedBoolean(0));
// we do 2 passes over element types and notations,
// first merging #implicit attributes for implicit element types/notations
// next merging #all attributes for all element types/notations
for (int i = 0; i < 4; i++) {
if (!commonAdl[i].isNull()) {
if (i % 2)
done1Adl[commonAdl[i]->index()] = 1;
else
done2Adl[commonAdl[i]->index()] = 1;
for (;;) {
Boolean skip;
Attributed *a;
switch (i) {
case 0:
{
ElementType *e = elementIter.next();
a = e;
skip = (e && e->definition()); // don't merge #implicit
// attributes if e is defined
}
break;
case 1:
a = element2Iter.next();
skip = 0; // always merge #all attributes
break;
case 2:
{
Notation *nt = notationIter.next().pointer();
a = nt;
skip = (nt && nt->defined()); // don't merge #implicit
// attributes if nt is defined
}
break;
case 3:
a = notation2Iter.next().pointer();
skip = 0; // always merge #all attributes
break;
default:
CANNOT_HAPPEN();
}
if (!a)
break;
Ptr<AttributeDefinitionList> adl = a->attributeDef();
if (adl.isNull()) {
if (!skip)
a->setAttributeDef(commonAdl[i]);
}
else if (((i % 2) && !done1Adl[adl->index()])
||(!(i % 2) && !done2Adl[adl->index()])) {
if (i % 2)
done1Adl[adl->index()] = 1;
else
done2Adl[adl->index()] = 1;
if (!skip)
for (size_t j = 0; j < commonAdl[i]->size(); j++) {
unsigned index;
if (!adl->attributeIndex(commonAdl[i]->def(j)->name(),
index))
adl->append(commonAdl[i]->def(j)->copy());
else if (i == 2) {
// Give an error if an #ALL data attribute was
// specified and is later redeclared as #IMPLICIT
Boolean implicit;
if (adl->def(index)->isSpecified(implicit) && !implicit)
message(ParserMessages::specifiedAttributeRedeclared,
StringMessageArg(adl->def(index)->name()));
}
}
}
}
}
}
{
ElementType *e = dtd.removeElementType(syntax()
.rniReservedName(Syntax::rIMPLICIT));
if (e)
dtd.setImplicitElementAttributeDef(e->attributeDef());
delete e;
}
{
Ptr<Notation> n
= dtd.removeNotation(syntax().rniReservedName(Syntax::rIMPLICIT));
if (!n.isNull())
dtd.setImplicitNotationAttributeDef(n->attributeDef());
}
}
#endif
Boolean Parser::maybeStatusKeyword(const Entity &entity)
{
const InternalEntity *internal = entity.asInternalEntity();
if (!internal)
return 0;
const StringC &text = internal->string();
static const Syntax::ReservedName statusKeywords[] = {
Syntax::rINCLUDE, Syntax::rIGNORE
};
for (size_t i = 0; i < SIZEOF(statusKeywords); i++) {
const StringC &keyword = instanceSyntax().reservedName(statusKeywords[i]);
size_t j = 0;
while (j < text.size() && instanceSyntax().isS(text[j]))
j++;
size_t k = 0;
while (j < text.size()
&& k < keyword.size()
&& ((*instanceSyntax().generalSubstTable())[text[j]]
== keyword[k]))
j++, k++;
if (k == keyword.size()) {
while (j < text.size() && instanceSyntax().isS(text[j]))
j++;
if (j == text.size())
return 1;
}
}
return 0;
}
Boolean Parser::parseLinktypeDeclStart()
{
if (baseDtd().isNull())
message(ParserMessages::lpdBeforeBaseDtd);
unsigned declInputLevel = inputLevel();
Param parm;
if (!parseParam(allowName, declInputLevel, parm))
return 0;
StringC name;
parm.token.swap(name);
if (!lookupDtd(name).isNull())
message(ParserMessages::duplicateDtdLpd, StringMessageArg(name));
else if (!lookupLpd(name).isNull())
message(ParserMessages::duplicateLpd, StringMessageArg(name));
static AllowedParams
allowSimpleName(Param::indicatedReservedName + Syntax::rSIMPLE,
Param::name);
if (!parseParam(allowSimpleName, declInputLevel, parm))
return 0;
Boolean simple;
Ptr<Dtd> sourceDtd;
if (parm.type == Param::indicatedReservedName + Syntax::rSIMPLE) {
simple = 1;
sourceDtd = baseDtd();
if (sourceDtd.isNull())
sourceDtd = new Dtd(StringC(), 1);
}
else {
simple = 0;
sourceDtd = lookupDtd(parm.token);
if (sourceDtd.isNull()) {
message(ParserMessages::noSuchDtd, StringMessageArg(parm.token));
sourceDtd = new Dtd(parm.token, 0);
}
}
static AllowedParams
allowImpliedName(Param::indicatedReservedName + Syntax::rIMPLIED,
Param::name);
if (!parseParam(allowImpliedName, declInputLevel, parm))
return 0;
Ptr<Dtd> resultDtd;
Boolean implied = 0;
if (parm.type == Param::indicatedReservedName + Syntax::rIMPLIED) {
if (simple) {
if (!sd().simpleLink())
message(ParserMessages::simpleLinkFeature);
}
else {
implied = 1;
if (!sd().implicitLink())
message(ParserMessages::implicitLinkFeature);
}
}
else {
if (simple)
message(ParserMessages::simpleLinkResultNotImplied);
else {
if (!sd().explicitLink())
message(ParserMessages::explicitLinkFeature);
resultDtd = lookupDtd(parm.token);
if (resultDtd.isNull())
message(ParserMessages::noSuchDtd, StringMessageArg(parm.token));
}
}
static AllowedParams
allowPublicSystemDsoMdc(Param::reservedName + Syntax::rPUBLIC,
Param::reservedName + Syntax::rSYSTEM,
Param::dso,
Param::mdc);
if (!parseParam(allowPublicSystemDsoMdc, declInputLevel, parm))
return 0;
ConstPtr<Entity> entity;
if (parm.type == Param::reservedName + Syntax::rPUBLIC
|| parm.type == Param::reservedName + Syntax::rSYSTEM) {
static AllowedParams allowSystemIdentifierDsoMdc(Param::systemIdentifier,
Param::dso, Param::mdc);
ExternalId id;
if (!parseExternalId(allowSystemIdentifierDsoMdc, allowDsoMdc,
1, declInputLevel, parm, id))
return 0;
Ptr<Entity> tem
= new ExternalTextEntity(name, Entity::linktype, markupLocation(), id);
tem->generateSystemId(*this);
entity = tem;
#if 0
eventHandler()
.externalEntityDecl(new (eventAllocator())
ExternalEntityDeclEvent(entity, 0));
#endif
}
Ptr<Lpd> lpd;
if (simple)
lpd = new SimpleLpd(name, markupLocation(), sourceDtd);
else
lpd = new ComplexLpd(name,
implied ? Lpd::implicitLink : Lpd::explicitLink,
markupLocation(),
syntax(),
sourceDtd,
resultDtd);
if (!baseDtd().isNull() && shouldActivateLink(name)) {
size_t nActive = nActiveLink();
if (simple) {
size_t nSimple = 0;
for (size_t i = 0; i < nActive; i++)
if (activeLpd(i).type() == Lpd::simpleLink)
nSimple++;
if (nSimple == sd().simpleLink())
message(ParserMessages::simpleLinkCount,
NumberMessageArg(sd().simpleLink()));
lpd->activate();
}
else {
Boolean haveImplicit = 0;
Boolean haveExplicit = 0;
size_t i;
for (i = 0; i < nActive; i++) {
if (activeLpd(i).type() == Lpd::implicitLink)
haveImplicit = 1;
else if (activeLpd(i).type() == Lpd::explicitLink)
haveExplicit = 1;
}
const Dtd *sourceDtd = lpd->sourceDtd().pointer();
if (implied && haveImplicit)
message(ParserMessages::oneImplicitLink);
else if (sd().explicitLink() <= 1 && sourceDtd != baseDtd().pointer())
message(sd().explicitLink() == 0
? ParserMessages::explicitNoRequiresSourceTypeBase
: ParserMessages::explicit1RequiresSourceTypeBase,
StringMessageArg(lpd->name()));
else if (sd().explicitLink() == 1 && haveExplicit && !implied)
message(ParserMessages::duplicateExplicitChain);
else if (haveExplicit || haveImplicit
|| sourceDtd != baseDtd().pointer())
message(ParserMessages::sorryLink, StringMessageArg(lpd->name()));
else
lpd->activate();
}
}
// Discard mdc or dso
if (currentMarkup())
currentMarkup()->resize(currentMarkup()->size() - 1);
eventHandler().startLpd(new (eventAllocator())
StartLpdEvent(lpd->active(),
name,
entity,
parm.type == Param::dso,
markupLocation(),
currentMarkup()));
startLpd(lpd);
if (parm.type == Param::mdc) {
// unget the mdc
currentInput()->ungetToken();
if (entity.isNull()) {
message(ParserMessages::noLpdSubset, StringMessageArg(name));
(void)parseLinktypeDeclEnd();
return 1;
}
// reference the entity
Ptr<EntityOrigin> origin
= EntityOrigin::make(internalAllocator(), entity, currentLocation());
entity->dsReference(*this, origin);
if (inputLevel() == 1) { // reference failed
(void)parseLinktypeDeclEnd();
return 1;
}
}
else if (!entity.isNull())
setDsEntity(entity);
setPhase(declSubsetPhase);
return 1;
}
Boolean Parser::parseLinktypeDeclEnd()
{
if (defLpd().type() != Lpd::simpleLink) {
if (!defComplexLpd().initialLinkSet()->defined())
message(ParserMessages::noInitialLinkSet,
StringMessageArg(defLpd().name()));
ComplexLpd::ConstLinkSetIter iter = defComplexLpd().linkSetIter();
const LinkSet *linkSet;
while ((linkSet = iter.next()) != 0)
if (!linkSet->defined())
message(ParserMessages::undefinedLinkSet, StringMessageArg(linkSet->name()));
}
ConstPtr<Lpd> tem(defLpdPointer());
endLpd();
startMarkup(eventsWanted().wantPrologMarkup(), currentLocation());
Param parm;
Boolean result = parseParam(allowMdc, inputLevel(), parm);
eventHandler().endLpd(new (eventAllocator()) EndLpdEvent(tem,
markupLocation(),
currentMarkup()));
return result;
}
Boolean Parser::parseLinkDecl()
{
return parseLinkSet(0);
}
Boolean Parser::parseIdlinkDecl()
{
return parseLinkSet(1);
}
// This will only get called if we're defining a complex lpd.
Boolean Parser::parseLinkSet(Boolean idlink)
{
if (defLpd().type() == Lpd::simpleLink) {
message(idlink ? ParserMessages::idlinkDeclSimple : ParserMessages::linkDeclSimple);
return 0;
}
if (idlink) {
if (defComplexLpd().hadIdLinkSet())
message(ParserMessages::duplicateIdLinkSet);
else
defComplexLpd().setHadIdLinkSet();
}
unsigned declInputLevel = inputLevel();
Param parm;
Boolean isExplicit = (defLpd().type() == Lpd::explicitLink);
LinkSet *linkSet;
if (idlink) {
if (!parseParam(allowName, declInputLevel, parm))
return 0;
linkSet = 0;
}
else {
static AllowedParams
allowNameInitial(Param::name,
Param::indicatedReservedName + Syntax::rINITIAL);
if (!parseParam(allowNameInitial, declInputLevel, parm))
return 0;
if (parm.type == Param::name)
linkSet = lookupCreateLinkSet(parm.token);
else
linkSet = defComplexLpd().initialLinkSet();
if (linkSet->defined())
message(ParserMessages::duplicateLinkSet, StringMessageArg(linkSet->name()));
static AllowedParams
allowExplicitLinkRule(Param::name,
Param::nameGroup,
Param::indicatedReservedName + Syntax::rIMPLIED);
if (!parseParam(isExplicit ? allowExplicitLinkRule : allowNameNameGroup,
declInputLevel, parm))
return 0;
}
do {
StringC id;
if (idlink) {
parm.token.swap(id);
if (!parseParam(isExplicit ? allowExplicitLinkRuleMdc : allowNameNameGroupMdc,
declInputLevel, parm))
return 0;
}
if (parm.type == Param::indicatedReservedName + Syntax::rIMPLIED) {
if (!parseParam(allowName, declInputLevel, parm))
return 0;
Boolean resultImplied;
const ElementType *resultType;
AttributeList resultAttributes;
if (!parseResultElementSpec(declInputLevel,
parm,
idlink,
resultImplied,
resultType,
resultAttributes))
return 0;
if (resultType) {
const AttributeList *dummy;
if (linkSet->impliedResultAttributes(resultType, dummy))
message(ParserMessages::duplicateImpliedResult,
StringMessageArg(resultType->name()));
else
linkSet->addImplied(resultType, resultAttributes);
}
}
else {
SourceLinkRule *linkRule = 0;
IdLinkRule idLinkRule;
Ptr<SourceLinkRuleResource> linkRuleResource;
if (idlink)
linkRule = &idLinkRule;
else {
linkRuleResource = new SourceLinkRuleResource;
linkRule = linkRuleResource.pointer();
}
Vector<const ElementType *> assocElementTypes;
if (parm.type == Param::name) {
assocElementTypes.resize(1);
assocElementTypes[0] = lookupCreateElement(parm.token);
}
else {
assocElementTypes.resize(parm.nameTokenVector.size());
for (size_t i = 0; i < assocElementTypes.size(); i++)
assocElementTypes[i]
= lookupCreateElement(parm.nameTokenVector[i].name);
}
static AllowedParams
allow2i(Param::indicatedReservedName + Syntax::rUSELINK,
Param::indicatedReservedName + Syntax::rPOSTLINK,
Param::dso,
Param::mdc,
Param::name,
Param::nameGroup);
static AllowedParams
allow2id(Param::indicatedReservedName + Syntax::rUSELINK,
Param::indicatedReservedName + Syntax::rPOSTLINK,
Param::dso,
Param::mdc,
Param::name);
static AllowedParams
allow2e(Param::indicatedReservedName + Syntax::rUSELINK,
Param::indicatedReservedName + Syntax::rPOSTLINK,
Param::dso,
Param::name,
Param::indicatedReservedName + Syntax::rIMPLIED);
if (!parseParam(isExplicit
? allow2e
: (idlink ? allow2id : allow2i), declInputLevel, parm))
return 0;
if (parm.type == Param::indicatedReservedName + Syntax::rUSELINK) {
static AllowedParams
allowLinkSetEmpty(Param::name,
Param::indicatedReservedName + Syntax::rINITIAL,
Param::indicatedReservedName + Syntax::rEMPTY);
if (!parseParam(allowLinkSetEmpty, declInputLevel, parm))
return 0;
const LinkSet *uselink;
if (parm.type == Param::name)
uselink = lookupCreateLinkSet(parm.token);
else if (parm.type == Param::indicatedReservedName + Syntax::rINITIAL)
uselink = defComplexLpd().initialLinkSet();
else
uselink = defComplexLpd().emptyLinkSet();
linkRule->setUselink(uselink);
static AllowedParams
allow3i(Param::indicatedReservedName + Syntax::rPOSTLINK,
Param::dso,
Param::mdc,
Param::name,
Param::nameGroup);
static AllowedParams
allow3id(Param::indicatedReservedName + Syntax::rPOSTLINK,
Param::dso,
Param::mdc,
Param::name);
static AllowedParams
allow3e(Param::indicatedReservedName + Syntax::rPOSTLINK,
Param::dso,
Param::name,
Param::indicatedReservedName + Syntax::rIMPLIED);
if (!parseParam(isExplicit
? allow3e
: (idlink ? allow3id : allow3i),
declInputLevel, parm))
return 0;
}
if (parm.type == Param::indicatedReservedName + Syntax::rPOSTLINK) {
if (!parseParam(allowLinkSetSpec, declInputLevel, parm))
return 0;
const LinkSet *postlink;
if (parm.type == Param::indicatedReservedName + Syntax::rRESTORE)
linkRule->setPostlinkRestore();
else {
if (parm.type == Param::name)
postlink = lookupCreateLinkSet(parm.token);
else if (parm.type
== Param::indicatedReservedName + Syntax::rINITIAL)
postlink = defComplexLpd().initialLinkSet();
else
postlink = defComplexLpd().emptyLinkSet();
linkRule->setPostlink(postlink);
}
static AllowedParams
allow4i(Param::dso,
Param::mdc,
Param::name,
Param::nameGroup);
static AllowedParams
allow4id(Param::dso,
Param::mdc,
Param::name);
static AllowedParams
allow4e(Param::dso,
Param::name,
Param::indicatedReservedName + Syntax::rIMPLIED);
if (!parseParam(isExplicit
? allow4e
: (idlink ? allow4id : allow4i),
declInputLevel, parm))
return 0;
}
AttributeList attributes;
ConstPtr<AttributeDefinitionList> attDef;
for (size_t i = 0; i < assocElementTypes.size(); i++) {
const ElementType *e = assocElementTypes[i];
if (e) {
if (i == 0)
attDef = defComplexLpd().attributeDef(e);
else if (attDef != defComplexLpd().attributeDef(e))
message(ParserMessages::assocElementDifferentAtts);
// FIXME recover from this
}
}
attributes.init(attDef);
if (parm.type == Param::dso) {
Boolean netEnabling;
Ptr<AttributeDefinitionList> newAttDef;
if (!parseAttributeSpec(asMode, attributes, netEnabling, newAttDef))
return 0;
if (!newAttDef.isNull()) {
newAttDef->setIndex(defComplexLpd().allocAttributeDefinitionListIndex());
for (size_t i = 0; i < assocElementTypes.size(); i++) {
const ElementType *e = assocElementTypes[i];
if (e && defComplexLpd().attributeDef(e) == attDef)
defComplexLpd().setAttributeDef(e, newAttDef);
}
}
static AllowedParams
allow5e(Param::name,
Param::indicatedReservedName + Syntax::rIMPLIED);
if (!parseParam(isExplicit
? allow5e
: (idlink ? allowNameMdc : allowNameNameGroupMdc),
declInputLevel, parm))
return 0;
}
else
attributes.finish(*this);
linkRule->setLinkAttributes(attributes);
if (isExplicit) {
Boolean resultImplied;
const ElementType *resultType;
AttributeList resultAttributes;
if (!parseResultElementSpec(declInputLevel,
parm,
idlink,
resultImplied,
resultType,
resultAttributes))
return 0;
if (!resultImplied)
linkRule->setResult(resultType, resultAttributes);
}
// Install the link rule.
if (idlink) {
idLinkRule.setAssocElementTypes(assocElementTypes);
addIdLinkRule(id, idLinkRule);
}
else {
if (!linkSet->defined()) {
for (size_t i = 0; i < assocElementTypes.size(); i++)
if (assocElementTypes[i])
addLinkRule(linkSet, assocElementTypes[i], linkRuleResource);
}
}
}
} while (parm.type != Param::mdc);
if (linkSet)
linkSet->setDefined();
if (currentMarkup()) {
if (idlink)
eventHandler().idLinkDecl(new (eventAllocator())
IdLinkDeclEvent(defComplexLpdPointer(),
markupLocation(),
currentMarkup()));
else
eventHandler().linkDecl(new (eventAllocator())
LinkDeclEvent(linkSet,
defComplexLpdPointer(),
markupLocation(),
currentMarkup()));
}
return 1;
}
void Parser::addIdLinkRule(const StringC &id,
IdLinkRule &rule)
{
IdLinkRuleGroup *group = defComplexLpd().lookupCreateIdLink(id);
size_t nRules = group->nLinkRules();
if ((nRules == 1 && group->linkRule(0).attributes().nSpec() == 0)
|| nRules >= 1 && rule.attributes().nSpec() == 0)
message(ParserMessages::multipleIdLinkRuleAttribute,
StringMessageArg(id));
group->addLinkRule(rule);
}
void Parser::addLinkRule(LinkSet *linkSet,
const ElementType *sourceElement,
const ConstPtr<SourceLinkRuleResource> &linkRule)
{
size_t nRules = linkSet->nLinkRules(sourceElement);
if ((nRules == 1
&& linkSet->linkRule(sourceElement, 0).attributes().nSpec() == 0)
|| nRules >= 1 && linkRule->attributes().nSpec() == 0)
message(ParserMessages::multipleLinkRuleAttribute,
StringMessageArg(sourceElement->name()));
linkSet->addLinkRule(sourceElement, linkRule);
}
class ResultAttributeSpecModeSetter {
public:
ResultAttributeSpecModeSetter(ParserState *state) : state_(state) {
state_->setResultAttributeSpecMode();
}
~ResultAttributeSpecModeSetter() { clear(); }
void clear() {
if (state_) {
state_->clearResultAttributeSpecMode();
state_ = 0;
}
}
private:
ParserState *state_;
};
Boolean Parser::parseResultElementSpec(unsigned declInputLevel,
Param &parm,
Boolean idlink,
Boolean &implied,
const ElementType *&resultType,
AttributeList &attributes)
{
if (parm.type == Param::indicatedReservedName + Syntax::rIMPLIED) {
if (!parseParam(idlink ? allowNameMdc : allowExplicitLinkRuleMdc,
declInputLevel, parm))
return 0;
implied = 1;
}
else {
implied = 0;
ElementType *e = lookupResultElementType(parm.token);
resultType = e;
static AllowedParams
allow(Param::dso,
Param::mdc,
Param::name,
Param::nameGroup,
Param::indicatedReservedName + Syntax::rIMPLIED);
static AllowedParams
allowNameDsoMdc(Param::dso,
Param::mdc,
Param::name);
if (!parseParam(idlink ? allowNameDsoMdc : allow,
declInputLevel, parm))
return 0;
ConstPtr<AttributeDefinitionList> attDef;
if (e)
attDef = e->attributeDef();
attributes.init(attDef);
if (parm.type == Param::dso) {
ResultAttributeSpecModeSetter modeSetter(this);
Boolean netEnabling;
Ptr<AttributeDefinitionList> newAttDef;
if (!parseAttributeSpec(asMode, attributes, netEnabling, newAttDef))
return 0;
if (!newAttDef.isNull()) {
Ptr<Dtd> r(defComplexLpd().resultDtd());
if (!r.isNull()) {
newAttDef->setIndex(r->allocAttributeDefinitionListIndex());
if (e)
e->setAttributeDef(newAttDef);
}
}
modeSetter.clear();
if (attributes.nSpec() == 0)
message(ParserMessages::emptyResultAttributeSpec);
if (!parseParam(idlink ? allowNameMdc : allowExplicitLinkRuleMdc,
declInputLevel, parm))
return 0;
}
else {
// For entity and notation attributes.
ResultAttributeSpecModeSetter modeSetter(this);
attributes.finish(*this);
modeSetter.clear();
}
}
return 1;
}
ElementType *Parser::lookupResultElementType(const StringC &name)
{
Dtd *dtd = defComplexLpd().resultDtd().pointer();
if (!dtd)
return 0;
ElementType *e = dtd->lookupElementType(name);
if (!e)
message(ParserMessages::noSuchResultElement, StringMessageArg(name));
return e;
}
Boolean Parser::parseUselinkDecl()
{
unsigned declInputLevel = inputLevel();
Param parm;
if (!parseParam(allowLinkSetSpec, declInputLevel, parm))
return 0;
Param parm2;
if (!parseParam(allowName, declInputLevel, parm2))
return 0;
StringC linkType;
parm2.token.swap(linkType);
if (!parseParam(allowMdc, declInputLevel, parm2))
return 0;
ConstPtr<Lpd> lpd = lookupLpd(linkType);
if (lpd.isNull())
message(ParserMessages::uselinkBadLinkType, StringMessageArg(linkType));
else if (lpd->type() == Lpd::simpleLink)
message(ParserMessages::uselinkSimpleLpd, StringMessageArg(linkType));
else {
const ComplexLpd *complexLpd = (const ComplexLpd *)lpd.pointer();
const LinkSet *linkSet;
Boolean restore = 0;
if (parm.type == Param::name) {
linkSet = complexLpd->lookupLinkSet(parm.token);
if (!linkSet) {
message(ParserMessages::uselinkBadLinkSet,
StringMessageArg(complexLpd->name()),
StringMessageArg(parm.token));
return 1;
}
}
else if (parm.type == Param::indicatedReservedName + Syntax::rINITIAL)
linkSet = complexLpd->initialLinkSet();
else if (parm.type == Param::indicatedReservedName + Syntax::rEMPTY)
linkSet = complexLpd->emptyLinkSet();
else {
linkSet = 0;
restore = 1;
}
if (lpd->active())
eventHandler().uselink(new (eventAllocator())
UselinkEvent(lpd, linkSet,
restore, markupLocation(),
currentMarkup()));
else
eventHandler().ignoredMarkup(new (eventAllocator())
IgnoredMarkupEvent(markupLocation(),
currentMarkup()));
}
return 1;
}
LinkSet *Parser::lookupCreateLinkSet(const StringC &name)
{
LinkSet *linkSet = defComplexLpd().lookupLinkSet(name);
if (!linkSet) {
linkSet = new LinkSet(name, defComplexLpd().sourceDtd().pointer());
defComplexLpd().insertLinkSet(linkSet);
}
return linkSet;
}
Boolean Parser::parseMarkedSectionDeclStart()
{
if (markedSectionLevel() == syntax().taglvl())
message(ParserMessages::markedSectionLevel,
NumberMessageArg(syntax().taglvl()));
if (!inInstance()
&& options().warnInternalSubsetMarkedSection
&& inputLevel() == 1)
message(ParserMessages::internalSubsetMarkedSection);
if (markedSectionSpecialLevel() > 0) {
startMarkedSection(markupLocation());
if (inInstance()
? eventsWanted().wantMarkedSections()
: eventsWanted().wantPrologMarkup())
eventHandler().ignoredChars(new (eventAllocator())
IgnoredCharsEvent(currentInput()->currentTokenStart(),
currentInput()->currentTokenLength(),
currentLocation(),
0));
return 1;
}
Boolean discardMarkup;
if (startMarkup(inInstance()
? eventsWanted().wantMarkedSections()
: eventsWanted().wantPrologMarkup(),
currentLocation())) {
currentMarkup()->addDelim(Syntax::dMDO);
currentMarkup()->addDelim(Syntax::dDSO);
discardMarkup = 0;
}
else if (options().warnInstanceStatusKeywordSpecS && inInstance()) {
startMarkup(1, currentLocation());
discardMarkup = 1;
}
unsigned declInputLevel = inputLevel();
static AllowedParams allowStatusDso(Param::dso,
Param::reservedName + Syntax::rCDATA,
Param::reservedName + Syntax::rRCDATA,
Param::reservedName + Syntax::rIGNORE,
Param::reservedName + Syntax::rINCLUDE,
Param::reservedName + Syntax::rTEMP);
Param parm;
MarkedSectionEvent::Status status = MarkedSectionEvent::include;
if (!parseParam(allowStatusDso, declInputLevel, parm))
return 0;
if (options().warnMissingStatusKeyword && parm.type == Param::dso)
message(ParserMessages::missingStatusKeyword);
while (parm.type != Param::dso) {
switch (parm.type) {
case Param::reservedName + Syntax::rCDATA:
if (status < MarkedSectionEvent::cdata)
status = MarkedSectionEvent::cdata;
break;
case Param::reservedName + Syntax::rRCDATA:
if (status < MarkedSectionEvent::rcdata)
status = MarkedSectionEvent::rcdata;
if (options().warnRcdataMarkedSection)
message(ParserMessages::rcdataMarkedSection);
break;
case Param::reservedName + Syntax::rIGNORE:
if (status < MarkedSectionEvent::ignore)
status = MarkedSectionEvent::ignore;
if (inInstance() && options().warnInstanceIgnoreMarkedSection)
message(ParserMessages::instanceIgnoreMarkedSection);
break;
case Param::reservedName + Syntax::rINCLUDE:
if (inInstance() && options().warnInstanceIncludeMarkedSection)
message(ParserMessages::instanceIncludeMarkedSection);
break;
case Param::reservedName + Syntax::rTEMP:
if (options().warnTempMarkedSection)
message(ParserMessages::tempMarkedSection);
break;
}
if (!parseParam(allowStatusDso, declInputLevel, parm))
return 0;
if (options().warnMultipleStatusKeyword
&& parm.type != Param::dso)
message(ParserMessages::multipleStatusKeyword);
}
// FIXME this disallows
// <!entity % e "include [ stuff ">
// ...
// <![ %e; ]]>
// which I think is legal.
if (inputLevel() > declInputLevel)
message(ParserMessages::parameterEntityNotEnded);
switch (status) {
case MarkedSectionEvent::include:
startMarkedSection(markupLocation());
break;
case MarkedSectionEvent::cdata:
startSpecialMarkedSection(cmsMode, markupLocation());
break;
case MarkedSectionEvent::rcdata:
startSpecialMarkedSection(rcmsMode, markupLocation());
break;
case MarkedSectionEvent::ignore:
startSpecialMarkedSection(imsMode, markupLocation());
break;
}
if (currentMarkup()) {
if (options().warnInstanceStatusKeywordSpecS && inInstance()) {
Location loc(markupLocation());
for (MarkupIter iter(*currentMarkup()); iter.valid(); iter.advance(loc, syntaxPointer())) {
if (iter.type() == Markup::s) {
setNextLocation(loc);
message(ParserMessages::instanceStatusKeywordSpecS);
}
}
if (discardMarkup)
startMarkup(0, markupLocation());
}
eventHandler().markedSectionStart(new (eventAllocator())
MarkedSectionStartEvent(status,
markupLocation(),
currentMarkup()));
}
return 1;
}
void Parser::handleMarkedSectionEnd()
{
if (markedSectionLevel() == 0)
message(ParserMessages::markedSectionEnd);
else {
if (inInstance()
? eventsWanted().wantMarkedSections()
: eventsWanted().wantPrologMarkup()) {
if (markedSectionSpecialLevel() > 1)
eventHandler().ignoredChars(new (eventAllocator())
IgnoredCharsEvent(currentInput()->currentTokenStart(),
currentInput()->currentTokenLength(),
currentLocation(),
0));
else {
MarkedSectionEvent::Status status;
switch (currentMode()) {
case cmsMode:
status = MarkedSectionEvent::cdata;
break;
case rcmsMode:
status = MarkedSectionEvent::rcdata;
break;
case imsMode:
status = MarkedSectionEvent::ignore;
break;
default:
status = MarkedSectionEvent::include;
break;
}
startMarkup(1, currentLocation());
currentMarkup()->addDelim(Syntax::dMSC);
currentMarkup()->addDelim(Syntax::dMDC);
eventHandler().markedSectionEnd(new (eventAllocator())
MarkedSectionEndEvent(status,
markupLocation(),
currentMarkup()));
}
}
endMarkedSection();
}
}
void Parser::emptyCommentDecl()
{
if (startMarkup(eventsWanted().wantCommentDecls(), currentLocation())) {
currentMarkup()->addDelim(Syntax::dMDO);
currentMarkup()->addDelim(Syntax::dMDC);
eventHandler().commentDecl(new (eventAllocator())
CommentDeclEvent(markupLocation(),
currentMarkup()));
}
if (options().warnEmptyCommentDecl)
message(ParserMessages::emptyCommentDecl);
}
Boolean Parser::parseCommentDecl()
{
if (startMarkup(inInstance()
? eventsWanted().wantCommentDecls()
: eventsWanted().wantPrologMarkup(),
currentLocation()))
currentMarkup()->addDelim(Syntax::dMDO);
if (!parseComment(comMode))
return 0;
for (;;) {
Token token = getToken(mdMode);
switch (token) {
case tokenS:
if (currentMarkup())
currentMarkup()->addS(currentChar());
if (options().warnCommentDeclS)
message(ParserMessages::commentDeclS);
break;
case tokenCom:
if (!parseComment(comMode))
return 0;
if (options().warnCommentDeclMultiple)
message(ParserMessages::commentDeclMultiple);
break;
case tokenMdc:
if (currentMarkup())
currentMarkup()->addDelim(Syntax::dMDC);
goto done;
case tokenEe:
message(ParserMessages::declarationLevel);
return 0;
case tokenUnrecognized:
if (reportNonSgmlCharacter())
break;
// braces to work round Sun C++ 4.0 bug
{
message(ParserMessages::commentDeclarationCharacter,
StringMessageArg(currentToken()),
markupLocation());
}
return 0;
default:
// braces to work round Sun C++ 4.0 bug
{
message(ParserMessages::commentDeclInvalidToken,
TokenMessageArg(token, mdMode, syntaxPointer(), sdPointer()),
markupLocation());
}
return 0;
}
}
done:
if (currentMarkup())
eventHandler().commentDecl(new (eventAllocator())
CommentDeclEvent(markupLocation(),
currentMarkup()));
return 1;
}
Boolean Parser::parseAfdrDecl()
{
unsigned declInputLevel = inputLevel();
static AllowedParams allowMinimumLiteral(Param::minimumLiteral);
Param parm;
setHadAfdrDecl();
if (!parseParam(allowMinimumLiteral, declInputLevel, parm))
return 0;
if (parm.literalText.string() != sd().execToInternal("ISO/IEC 10744:1997"))
message(ParserMessages::afdrVersion,
StringMessageArg(parm.literalText.string()));
if (!parseParam(allowMdc, declInputLevel, parm))
return 0;
eventHandler().ignoredMarkup(new (eventAllocator())
IgnoredMarkupEvent(markupLocation(),
currentMarkup()));
return 1;
}
#ifdef SP_NAMESPACE
}
#endif