Attribute.cxx revision 7c478bd95313f5f23a4c958a745db2134aa03244
// Copyright (c) 1994 James Clark
// See the file COPYING for copying permission.
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __GNUG__
#pragma implementation
#endif
#include "splib.h"
#include "Attribute.h"
#include "MessageArg.h"
#include "macros.h"
#include "ParserMessages.h"
#include "StringVectorMessageArg.h"
#include "Syntax.h"
#include "Entity.h"
#include "Notation.h"
#ifdef SP_NAMESPACE
namespace SP_NAMESPACE {
#endif
DeclaredValue::DeclaredValue()
{
}
DeclaredValue::~DeclaredValue()
{
}
AttributeValue *DeclaredValue::makeValueFromToken(Text &text,
AttributeContext &context,
const StringC &name,
unsigned &specLength) const
{
return makeValue(text, context, name, specLength);
}
AttributeSemantics *DeclaredValue::makeSemantics(const TokenizedAttributeValue &,
AttributeContext &,
const StringC &,
unsigned &,
unsigned &) const
{
return 0;
}
Boolean DeclaredValue::containsToken(const StringC &) const
{
return 0;
}
Boolean DeclaredValue::isNotation() const
{
return 0;
}
Boolean DeclaredValue::isEntity() const
{
return 0;
}
Boolean DeclaredValue::isId() const
{
return 0;
}
Boolean DeclaredValue::isIdref() const
{
return 0;
}
const Vector<StringC> *DeclaredValue::getTokens() const
{
return 0;
}
CdataDeclaredValue::CdataDeclaredValue()
{
}
Boolean CdataDeclaredValue::tokenized() const
{
return 0;
}
AttributeValue *CdataDeclaredValue::makeValue(Text &text, AttributeContext &context,
const StringC &,
unsigned &specLength) const
{
const Syntax &syntax = context.attributeSyntax();
size_t normsep = syntax.normsep();
size_t normalizedLength = text.normalizedLength(normsep);
specLength += normalizedLength;
size_t litlen = syntax.litlen();
// A length error will already have been given if
// length > litlen - normsep.
if (litlen >= normsep && text.size() <= litlen - normsep
&& normalizedLength > litlen)
context.message(ParserMessages::normalizedAttributeValueLength,
NumberMessageArg(litlen),
NumberMessageArg(normalizedLength));
return new CdataAttributeValue(text);
}
void CdataDeclaredValue::buildDesc(AttributeDefinitionDesc &desc) const
{
desc.declaredValue = AttributeDefinitionDesc::cdata;
}
DeclaredValue *CdataDeclaredValue::copy() const
{
return new CdataDeclaredValue(*this);
}
TokenizedDeclaredValue::TokenizedDeclaredValue(TokenType type,
Boolean isList)
: type_(type), isList_(isList)
{
switch (type) {
case name:
case entityName:
initialCategories_ = Syntax::nameStartCategory;
subsequentCategories_ = (Syntax::nameStartCategory|Syntax::digitCategory
| Syntax::otherNameCategory);
break;
case number:
initialCategories_ = Syntax::digitCategory;
subsequentCategories_ = Syntax::digitCategory;
break;
case nameToken:
initialCategories_ = (Syntax::nameStartCategory|Syntax::digitCategory
| Syntax::otherNameCategory);
subsequentCategories_ = initialCategories_;
break;
case numberToken:
initialCategories_ = Syntax::digitCategory;
subsequentCategories_ = (Syntax::nameStartCategory|Syntax::digitCategory
| Syntax::otherNameCategory);
break;
}
}
Boolean TokenizedDeclaredValue::tokenized() const
{
return 1;
}
AttributeValue *TokenizedDeclaredValue::makeValue(Text &text,
AttributeContext &context,
const StringC &str,
unsigned &specLength) const
{
return makeTokenizedValue(text, context, str, specLength);
}
TokenizedAttributeValue *
TokenizedDeclaredValue::makeTokenizedValue(Text &text,
AttributeContext &context,
const StringC &LOCALname,
unsigned &specLength) const
{
Vector<size_t> spaceIndex;
const Syntax &syntax = context.attributeSyntax();
Char space = syntax.space();
text.subst(*(type_ == entityName
? syntax.entitySubstTable()
: syntax.generalSubstTable()),
space);
const StringC &value = text.string();
size_t i = 0;
size_t length = value.size();
for (;;) {
if (i >= length) {
// ends with a space (which would have to have been entered
// via a numeric character reference)
if (context.validate())
context.message(ParserMessages::attributeValueSyntax);
break;
}
size_t startIndex = i;
if (context.validate()) {
if (!(syntax.charCategory(value[i]) & initialCategories_)) {
context.Messenger::setNextLocation(text.charLocation(i));
Char c = value[i];
if (!(syntax.charCategory(value[i]) & subsequentCategories_))
context.message(ParserMessages::attributeValueChar,
StringMessageArg(StringC(&c, 1)),
StringMessageArg(LOCALname));
else if (initialCategories_ == Syntax::digitCategory)
context.message(ParserMessages::attributeValueNumberToken,
StringMessageArg(StringC(&c, 1)),
StringMessageArg(LOCALname));
else
context.message(ParserMessages::attributeValueName,
StringMessageArg(StringC(&c, 1)),
StringMessageArg(LOCALname));
}
else {
for (++i;
i < length
&& (syntax.charCategory(value[i]) & subsequentCategories_);
i++)
;
if (i < length && value[i] != space) {
Char c = value[i];
// character value[i] is not allowed anywhere in the value
context.Messenger::setNextLocation(text.charLocation(i));
context.message(ParserMessages::attributeValueChar,
StringMessageArg(StringC(&c, 1)),
StringMessageArg(LOCALname));
}
}
}
while (i < length && value[i] != space)
i++;
if (i - startIndex > syntax.namelen()) {
context.Messenger::setNextLocation(text.charLocation(i));
context.message(ParserMessages::nameTokenLength,
NumberMessageArg(syntax.namelen()));
}
if (i == length)
break;
if (!isList_ && context.validate() && spaceIndex.size() == 0) {
context.Messenger::setNextLocation(text.charLocation(i));
context.message(ParserMessages::attributeValueMultiple,
StringMessageArg(LOCALname));
}
spaceIndex.push_back(i);
i++;
}
size_t normsep = syntax.normsep();
size_t litlen = syntax.litlen();
size_t normalizedLength = normsep + length;
// should we count CDATA and SDATA entities here?
if (isList_) {
normalizedLength += 1;
// length is now the number of characters in each token in the list
// + 1 for each token in the list; so add normsep - 1 for each
// token in the list.
if (normsep > 0)
normalizedLength += (normsep - 1)*(spaceIndex.size() + 1);
else
normalizedLength -= spaceIndex.size() + 1;
}
specLength += normalizedLength;
// A length error will already have been given if
// length > litlen - normsep.
if (litlen >= normsep && length <= litlen - normsep
&& normalizedLength > litlen)
context.message(ParserMessages::normalizedAttributeValueLength,
NumberMessageArg(litlen),
NumberMessageArg(normalizedLength));
return new TokenizedAttributeValue(text, spaceIndex);
}
Boolean TokenizedAttributeValue::recoverUnquoted(const StringC &str,
const Location &strLoc,
AttributeContext &context,
const StringC &name)
{
TextIter iter(text_);
TextItem::Type type;
const Char *s;
size_t len;
const Location *loc;
if (iter.next(type, s, len, loc)
&& type == TextItem::data
&& len == text_.size()
&& loc->origin().pointer() == strLoc.origin().pointer()
&& loc->index() + len == strLoc.index()
&& !iter.next(type, s, len, loc)) {
context.Messenger::setNextLocation(strLoc);
context.message(ParserMessages::attributeValueChar,
StringMessageArg(StringC(str.data(), 1)),
StringMessageArg(name));
return 1;
}
return 0;
}
void TokenizedDeclaredValue::buildDesc(AttributeDefinitionDesc &desc) const
{
desc.declaredValue = AttributeDefinitionDesc::DeclaredValue(
type_ - name + (isList_
? AttributeDefinitionDesc::names
: AttributeDefinitionDesc::name));
}
DeclaredValue *TokenizedDeclaredValue::copy() const
{
return new TokenizedDeclaredValue(*this);
}
GroupDeclaredValue::GroupDeclaredValue(TokenType type,
Vector<StringC> &vec)
: TokenizedDeclaredValue(type, 0)
{
vec.swap(allowedValues_);
}
void GroupDeclaredValue::buildDesc(AttributeDefinitionDesc &desc) const
{
desc.allowedValues = allowedValues_;
}
DeclaredValue *GroupDeclaredValue::copy() const
{
return new GroupDeclaredValue(*this);
}
AttributeValue *GroupDeclaredValue::makeValue(Text &text,
AttributeContext &context,
const StringC &LOCALname,
unsigned &specLength) const
{
TokenizedAttributeValue *val = makeTokenizedValue(text, context, LOCALname,
specLength);
if (!val || !context.validate())
return val;
for (size_t i = 0; i < allowedValues_.size(); i++)
if (val->string() == allowedValues_[i])
return val;
context.message(ParserMessages::attributeValueNotInGroup,
StringMessageArg(val->string()),
StringMessageArg(LOCALname),
StringVectorMessageArg(allowedValues_));
return val;
}
AttributeValue *GroupDeclaredValue::makeValueFromToken(Text &text,
AttributeContext &context,
const StringC &,
unsigned &specLength)
const
{
const Syntax &syntax = context.attributeSyntax();
size_t litlen = syntax.litlen();
size_t normsep = syntax.normsep();
if (normsep > litlen || text.size() > litlen - normsep)
context.message(ParserMessages::normalizedAttributeValueLength,
NumberMessageArg(litlen),
NumberMessageArg(text.size() + normsep));
specLength += text.size() + normsep;
return new TokenizedAttributeValue(text, Vector<size_t>());
}
Boolean GroupDeclaredValue::containsToken(const StringC &token) const
{
for (size_t i = 0; i < allowedValues_.size(); i++)
if (allowedValues_[i] == token)
return 1;
return 0;
}
const Vector<StringC> *GroupDeclaredValue::getTokens() const
{
return &allowedValues_;
}
NameTokenGroupDeclaredValue::NameTokenGroupDeclaredValue(Vector<StringC> &vec)
: GroupDeclaredValue(nameToken, vec)
{
}
void NameTokenGroupDeclaredValue::buildDesc(AttributeDefinitionDesc &desc) const
{
GroupDeclaredValue::buildDesc(desc);
desc.declaredValue = AttributeDefinitionDesc::nameTokenGroup;
}
DeclaredValue *NameTokenGroupDeclaredValue::copy() const
{
return new NameTokenGroupDeclaredValue(*this);
}
NotationDeclaredValue::NotationDeclaredValue(Vector<StringC> &vec)
: GroupDeclaredValue(name, vec)
{
}
Boolean NotationDeclaredValue::isNotation() const
{
return 1;
}
AttributeSemantics *
NotationDeclaredValue::makeSemantics(const TokenizedAttributeValue &value,
AttributeContext &context,
const StringC &,
unsigned &,
unsigned &) const
{
ConstPtr<Notation> notation
= context.getAttributeNotation(value.string(),
value.tokenLocation(0));
if (notation.isNull()) {
if (context.validate()) {
context.setNextLocation(value.tokenLocation(0));
context.message(ParserMessages::invalidNotationAttribute,
StringMessageArg(value.string()));
}
return 0;
}
return new NotationAttributeSemantics(notation);
}
void NotationDeclaredValue::buildDesc(AttributeDefinitionDesc &desc) const
{
GroupDeclaredValue::buildDesc(desc);
desc.declaredValue = AttributeDefinitionDesc::notation;
}
DeclaredValue *NotationDeclaredValue::copy() const
{
return new NotationDeclaredValue(*this);
}
EntityDeclaredValue::EntityDeclaredValue(Boolean isList)
: TokenizedDeclaredValue(entityName, isList)
{
}
Boolean EntityDeclaredValue::isEntity() const
{
return 1;
}
AttributeSemantics *
EntityDeclaredValue::makeSemantics(const TokenizedAttributeValue &value,
AttributeContext &context,
const StringC &,
unsigned &,
unsigned &nEntityNames) const
{
Boolean valid = 1;
size_t nTokens = value.nTokens();
nEntityNames += nTokens;
Vector<ConstPtr<Entity> > entities(nTokens);
for (size_t i = 0; i < nTokens; i++) {
entities[i] = context.getAttributeEntity(value.token(i),
value.tokenLocation(i));
if (entities[i].isNull()) {
if (context.validate()) {
context.setNextLocation(value.tokenLocation(i));
context.message(ParserMessages::invalidEntityAttribute,
StringMessageArg(value.token(i)));
}
valid = 0;
}
else if (!entities[i]->isDataOrSubdoc()) {
if (context.validate()) {
context.Messenger::setNextLocation(value.tokenLocation(i));
context.message(ParserMessages::notDataOrSubdocEntity,
StringMessageArg(value.token(i)));
}
valid = 0;
}
}
if (valid)
return new EntityAttributeSemantics(entities);
else
return 0;
}
DeclaredValue *EntityDeclaredValue::copy() const
{
return new EntityDeclaredValue(*this);
}
IdDeclaredValue::IdDeclaredValue()
: TokenizedDeclaredValue(name, 0)
{
}
Boolean IdDeclaredValue::isId() const
{
return 1;
}
AttributeSemantics *
IdDeclaredValue::makeSemantics(const TokenizedAttributeValue &value,
AttributeContext &context,
const StringC &,
unsigned &,
unsigned &) const
{
Location prevLoc;
if (!context.defineId(value.string(), value.tokenLocation(0), prevLoc)) {
context.setNextLocation(value.tokenLocation(0));
context.message(ParserMessages::duplicateId,
StringMessageArg(value.string()),
prevLoc);
}
return 0;
}
void IdDeclaredValue::buildDesc(AttributeDefinitionDesc &desc) const
{
desc.declaredValue = AttributeDefinitionDesc::id;
}
DeclaredValue *IdDeclaredValue::copy() const
{
return new IdDeclaredValue(*this);
}
IdrefDeclaredValue::IdrefDeclaredValue(Boolean isList)
: TokenizedDeclaredValue(name, isList)
{
}
AttributeSemantics *
IdrefDeclaredValue::makeSemantics(const TokenizedAttributeValue &value,
AttributeContext &context,
const StringC &,
unsigned &nIdrefs,
unsigned &) const
{
size_t nTokens = value.nTokens();
nIdrefs += nTokens;
for (size_t i = 0; i < nTokens; i++)
context.noteIdref(value.token(i), value.tokenLocation(i));
return 0;
}
Boolean IdrefDeclaredValue::isIdref() const
{
return 1;
}
void IdrefDeclaredValue::buildDesc(AttributeDefinitionDesc &desc) const
{
TokenizedDeclaredValue::buildDesc(desc);
if (desc.declaredValue == AttributeDefinitionDesc::name)
desc.declaredValue = AttributeDefinitionDesc::idref;
else
desc.declaredValue = AttributeDefinitionDesc::idrefs;
}
DeclaredValue *IdrefDeclaredValue::copy() const
{
return new IdrefDeclaredValue(*this);
}
AttributeDefinition::AttributeDefinition(const StringC &name,
DeclaredValue *value)
: name_(name), declaredValue_(value)
{
}
AttributeDefinition::~AttributeDefinition()
{
}
AttributeValue *AttributeDefinition::checkValue(AttributeValue *p,
AttributeContext &) const
{
return p;
}
Boolean AttributeDefinition::missingValueWouldMatch(const Text &,
const AttributeContext &) const
{
return 0;
}
const AttributeValue *
AttributeDefinition::defaultValue(const AttributeValue *) const
{
return 0;
}
void AttributeDefinition::getDesc(AttributeDefinitionDesc &desc) const
{
desc.allowedValues.clear();
desc.defaultValue.clear();
desc.currentIndex = 0;
buildDesc(desc);
declaredValue_->buildDesc(desc);
}
Boolean AttributeDefinition::isConref() const
{
return 0;
}
Boolean AttributeDefinition::isCurrent() const
{
return 0;
}
Boolean AttributeDefinition::isFixed() const
{
return 0;
}
RequiredAttributeDefinition::RequiredAttributeDefinition(const StringC &name,
DeclaredValue *value)
: AttributeDefinition(name, value)
{
}
ConstPtr<AttributeValue>
RequiredAttributeDefinition::makeMissingValue(AttributeContext &context) const
{
if (context.validate())
context.message(ParserMessages::requiredAttributeMissing,
StringMessageArg(name()));
return 0;
}
void RequiredAttributeDefinition::buildDesc(AttributeDefinitionDesc &desc) const
{
desc.defaultValueType = AttributeDefinitionDesc::required;
}
AttributeDefinition *RequiredAttributeDefinition::copy() const
{
return new RequiredAttributeDefinition(*this);
}
CurrentAttributeDefinition::CurrentAttributeDefinition(const StringC &name, DeclaredValue *value, size_t index)
: AttributeDefinition(name, value), currentIndex_(index)
{
}
ConstPtr<AttributeValue>
CurrentAttributeDefinition::makeMissingValue(AttributeContext &context) const
{
if (context.mayDefaultAttribute()) {
ConstPtr<AttributeValue> currentValue
= context.getCurrentAttribute(currentIndex_);
if (currentValue.isNull() && context.validate())
context.message(ParserMessages::currentAttributeMissing,
StringMessageArg(name()));
return currentValue;
}
if (context.validate())
context.message(ParserMessages::attributeMissing,
StringMessageArg(name()));
return 0;
}
Boolean CurrentAttributeDefinition::missingValueWouldMatch(const Text &text,
const AttributeContext &context) const
{
if (!context.mayDefaultAttribute())
return 0;
ConstPtr<AttributeValue> currentValue
= context.getCurrentAttribute(currentIndex_);
if (currentValue.isNull())
return 0;
return text.fixedEqual(*currentValue->text());
}
AttributeValue *
CurrentAttributeDefinition::checkValue(AttributeValue *value,
AttributeContext &context) const
{
context.noteCurrentAttribute(currentIndex_, value);
return value;
}
void CurrentAttributeDefinition::buildDesc(AttributeDefinitionDesc &desc) const
{
desc.defaultValueType = AttributeDefinitionDesc::current;
desc.currentIndex = currentIndex_;
}
AttributeDefinition *CurrentAttributeDefinition::copy() const
{
return new CurrentAttributeDefinition(*this);
}
Boolean CurrentAttributeDefinition::isCurrent() const
{
return 1;
}
ImpliedAttributeDefinition::ImpliedAttributeDefinition(const StringC &name,
DeclaredValue *value)
: AttributeDefinition(name, value)
{
}
ConstPtr<AttributeValue>
ImpliedAttributeDefinition::makeMissingValue(AttributeContext &context) const
{
return context.makeImpliedAttributeValue();
}
void ImpliedAttributeDefinition::buildDesc(AttributeDefinitionDesc &desc) const
{
desc.defaultValueType = AttributeDefinitionDesc::implied;
}
AttributeDefinition *ImpliedAttributeDefinition::copy() const
{
return new ImpliedAttributeDefinition(*this);
}
const AttributeValue *
ImpliedAttributeDefinition::defaultValue(const AttributeValue *impliedValue)
const
{
return impliedValue;
}
ConrefAttributeDefinition::ConrefAttributeDefinition(const StringC &name,
DeclaredValue *value)
: ImpliedAttributeDefinition(name, value)
{
}
Boolean ConrefAttributeDefinition::isConref() const
{
return 1;
}
void ConrefAttributeDefinition::buildDesc(AttributeDefinitionDesc &desc) const
{
desc.defaultValueType = AttributeDefinitionDesc::conref;
}
AttributeDefinition *ConrefAttributeDefinition::copy() const
{
return new ConrefAttributeDefinition(*this);
}
DefaultAttributeDefinition::DefaultAttributeDefinition(const StringC &name,
DeclaredValue *declaredValue,
AttributeValue *defaultValue)
: AttributeDefinition(name, declaredValue),
value_(defaultValue)
{
}
ConstPtr<AttributeValue>
DefaultAttributeDefinition::makeMissingValue(AttributeContext &context) const
{
if (context.mayDefaultAttribute())
return value_;
if (context.validate())
context.message(ParserMessages::attributeMissing,
StringMessageArg(name()));
return 0;
}
Boolean DefaultAttributeDefinition::missingValueWouldMatch(const Text &text,
const AttributeContext &context) const
{
return context.mayDefaultAttribute() && text.fixedEqual(*value_->text());
}
void DefaultAttributeDefinition::buildDesc(AttributeDefinitionDesc &desc) const
{
desc.defaultValueType = AttributeDefinitionDesc::defaulted;
desc.defaultValue = value_;
}
AttributeDefinition *DefaultAttributeDefinition::copy() const
{
return new DefaultAttributeDefinition(*this);
}
FixedAttributeDefinition:: FixedAttributeDefinition(const StringC &name,
DeclaredValue *declaredValue,
AttributeValue *defaultValue)
: DefaultAttributeDefinition(name, declaredValue, defaultValue)
{
}
Boolean FixedAttributeDefinition::isFixed() const
{
return 1;
}
AttributeValue *FixedAttributeDefinition::checkValue(AttributeValue *value,
AttributeContext &context)
const
{
const AttributeValue *fixedValue
= DefaultAttributeDefinition::defaultValue(0);
if (value && fixedValue && context.validate()) {
const Text *text;
const StringC *str;
const Text *fixedText;
const StringC *fixedStr;
switch (value->info(text, str)) {
case AttributeValue::implied:
CANNOT_HAPPEN();
case AttributeValue::cdata:
if (fixedValue->info(fixedText, fixedStr) == AttributeValue::cdata) {
if (!text->fixedEqual(*fixedText))
context.message(ParserMessages::notFixedValue, StringMessageArg(name()));
}
break;
case AttributeValue::tokenized:
if (fixedValue->info(fixedText, fixedStr) == AttributeValue::tokenized) {
if (*str != *fixedStr)
context.message(ParserMessages::notFixedValue, StringMessageArg(name()));
}
break;
}
}
return value;
}
void FixedAttributeDefinition::buildDesc(AttributeDefinitionDesc &desc) const
{
// get the fixed value
DefaultAttributeDefinition::buildDesc(desc);
desc.defaultValueType = AttributeDefinitionDesc::fixed;
}
AttributeDefinition *FixedAttributeDefinition::copy() const
{
return new FixedAttributeDefinition(*this);
}
AttributeDefinitionList
::AttributeDefinitionList(Vector<CopyOwner<AttributeDefinition> > &vec,
size_t index,
Boolean anyCurrent,
size_t idIndex,
size_t notationIndex)
: index_(index), anyCurrent_(anyCurrent), idIndex_(idIndex),
notationIndex_(notationIndex)
{
defs_.swap(vec);
}
AttributeDefinitionList:: AttributeDefinitionList(const ConstPtr<AttributeDefinitionList> &def)
: prev_(def), index_(size_t(-1))
{
if (def.isNull()) {
anyCurrent_ = 0;
notationIndex_ = size_t(-1);
idIndex_ = size_t(-1);
}
else {
anyCurrent_ = def->anyCurrent_;
notationIndex_ = def->notationIndex_;
idIndex_ = def->idIndex_;
defs_ = def->defs_;
}
}
Boolean AttributeDefinitionList::tokenIndex(const StringC &token, unsigned &index) const
{
for (size_t i = 0; i < defs_.size(); i++)
if (defs_[i]->containsToken(token)) {
index = i;
return 1;
}
return 0;
}
Boolean AttributeDefinitionList::tokenIndexUnique(const StringC &token, unsigned i) const
{
for (++i; i < defs_.size(); i++)
if (defs_[i]->containsToken(token))
return 0;
return 1;
}
Boolean AttributeDefinitionList::attributeIndex(const StringC &name,
unsigned &index) const
{
for (size_t i = 0; i < defs_.size(); i++)
if (defs_[i]->name() == name) {
index = i;
return 1;
}
return 0;
}
void AttributeDefinitionList::append(AttributeDefinition *def)
{
if (def->isId() && idIndex_ == size_t(-1))
idIndex_ = defs_.size();
if (def->isNotation() && notationIndex_ == size_t(-1))
notationIndex_ = defs_.size();
if (def->isCurrent())
anyCurrent_ = 1;
defs_.resize(defs_.size() + 1);
defs_.back() = def;
}
AttributeSemantics::AttributeSemantics()
{
}
AttributeSemantics::~AttributeSemantics()
{
}
size_t AttributeSemantics::nEntities() const
{
return 0;
}
ConstPtr<Entity> AttributeSemantics::entity(size_t) const
{
return 0;
}
ConstPtr<Notation> AttributeSemantics::notation() const
{
return 0;
}
NotationAttributeSemantics::NotationAttributeSemantics(const ConstPtr<Notation> &notation)
: notation_(notation)
{
}
ConstPtr<Notation> NotationAttributeSemantics::notation() const
{
return notation_;
}
AttributeSemantics *NotationAttributeSemantics::copy() const
{
return new NotationAttributeSemantics(*this);
}
EntityAttributeSemantics::EntityAttributeSemantics(Vector<ConstPtr<Entity> > &entity)
{
entity.swap(entity_);
}
size_t EntityAttributeSemantics::nEntities() const
{
return entity_.size();
}
ConstPtr<Entity> EntityAttributeSemantics::entity(size_t i) const
{
return entity_[i];
}
AttributeSemantics *EntityAttributeSemantics::copy() const
{
return new EntityAttributeSemantics(*this);
}
AttributeValue::AttributeValue()
{
}
AttributeValue::~AttributeValue()
{
}
AttributeSemantics *AttributeValue::makeSemantics(const DeclaredValue *,
AttributeContext &,
const StringC &,
unsigned &,
unsigned &) const
{
return 0;
}
const Text *AttributeValue::text() const
{
return 0;
}
Boolean AttributeValue::recoverUnquoted(const StringC &, const Location &,
AttributeContext &, const StringC &)
{
return 0;
}
ImpliedAttributeValue::ImpliedAttributeValue()
{
}
AttributeValue::Type ImpliedAttributeValue::info(const Text *&,
const StringC *&) const
{
return implied;
}
TokenizedAttributeValue::TokenizedAttributeValue(Text &text,
const Vector<size_t> &spaceIndex)
: spaceIndex_(spaceIndex)
{
text.swap(text_);
}
AttributeValue::Type TokenizedAttributeValue::info(const Text *&,
const StringC *&string) const
{
string = &text_.string();
return tokenized;
}
const Text *TokenizedAttributeValue::text() const
{
return &text_;
}
AttributeSemantics *
TokenizedAttributeValue::makeSemantics(const DeclaredValue *value,
AttributeContext &context,
const StringC &name,
unsigned &nIdrefs,
unsigned &nEntityNames) const
{
if (text_.size() == 0)
return 0;
return value->makeSemantics(*this, context, name, nIdrefs, nEntityNames);
}
CdataAttributeValue::CdataAttributeValue(Text &text)
{
text.swap(text_);
}
AttributeValue::Type CdataAttributeValue::info(const Text *&text,
const StringC *&) const
{
text = &text_;
return cdata;
}
const Text *CdataAttributeValue::text() const
{
return &text_;
}
Boolean CdataAttributeValue::recoverUnquoted(const StringC &str,
const Location &strLoc,
AttributeContext &context,
const StringC &)
{
TextIter iter(text_);
TextItem::Type type;
const Char *s;
size_t len;
const Location *loc;
if (iter.next(type, s, len, loc)
&& type == TextItem::data
&& len == text_.size()
&& loc->origin().pointer() == strLoc.origin().pointer()
&& loc->index() + len == strLoc.index()
&& !iter.next(type, s, len, loc)) {
text_.addChars(str, strLoc);
context.Messenger::setNextLocation(strLoc);
context.message(ParserMessages::unquotedAttributeValue);
return 1;
}
return 0;
}
Attribute::Attribute()
: specIndexPlus_(0)
{
}
void Attribute::clear()
{
specIndexPlus_ = 0;
value_.clear();
semantics_.clear();
}
AttributeList::AttributeList(const ConstPtr<AttributeDefinitionList> &def)
: def_(def), vec_(def.isNull() ? 0 : def->size()), nSpec_(0), conref_(0),
nIdrefs_(0), nEntityNames_(0)
{
}
AttributeList::AttributeList()
: nSpec_(0), conref_(0)
{
}
void AttributeList::init(const ConstPtr<AttributeDefinitionList> &def)
{
def_ = def;
nSpec_ = 0;
conref_ = 0;
nIdrefs_ = 0;
nEntityNames_ = 0;
if (def_.isNull())
vec_.resize(0);
else {
size_t newLength = def_->size();
size_t clearLim = vec_.size();
if (clearLim > newLength)
clearLim = newLength;
vec_.resize(newLength);
for (size_t i = 0; i < clearLim; i++)
vec_[i].clear();
}
}
void AttributeList::changeDef(const ConstPtr<AttributeDefinitionList> &def)
{
vec_.resize(def.isNull() ? 0 : def->size());
def_ = def;
}
void AttributeList::swap(AttributeList &to)
{
vec_.swap(to.vec_);
def_.swap(to.def_);
{
unsigned tem = to.nIdrefs_;
to.nIdrefs_ = nIdrefs_;
nIdrefs_ = tem;
}
{
unsigned tem = to.nEntityNames_;
to.nEntityNames_ = nEntityNames_;
nEntityNames_ = tem;
}
{
size_t tem = to.nSpec_;
to.nSpec_ = nSpec_;
nSpec_ = tem;
}
{
PackedBoolean tem = to.conref_;
to.conref_ = conref_;
conref_ = tem;
}
}
void AttributeList::finish(AttributeContext &context)
{
for (size_t i = 0; i < vec_.size(); i++)
if (!vec_[i].specified()) {
ConstPtr<AttributeValue> value
= def(i)->makeMissingValue(context);
vec_[i].setValue(value);
if (!value.isNull())
vec_[i].setSemantics(def(i)->makeSemantics(value.pointer(),
context,
nIdrefs_,
nEntityNames_));
}
const Syntax &syntax = context.attributeSyntax();
if (nIdrefs_ > syntax.grpcnt())
context.message(ParserMessages::idrefGrpcnt,
NumberMessageArg(syntax.grpcnt()));
if (nEntityNames_ > syntax.grpcnt())
context.message(ParserMessages::entityNameGrpcnt,
NumberMessageArg(syntax.grpcnt()));
if (context.validate()
&& conref_
&& def_->notationIndex() != size_t(-1)
&& specified(def_->notationIndex()))
context.message(ParserMessages::conrefNotation);
}
void AttributeList::setSpec(unsigned i, AttributeContext &context)
{
if (vec_[i].specified())
context.message(ParserMessages::duplicateAttributeSpec,
StringMessageArg(def(i)->name()));
else
vec_[i].setSpec(nSpec_++);
}
void AttributeList::noteInvalidSpec()
{
// This is needed for error recovery.
// We don't want nSpec_ to be > 0, if there is no attribute definition.
if (nSpec_)
nSpec_++;
}
Boolean AttributeList::setValue(unsigned i, Text &text,
AttributeContext &context,
unsigned &specLength)
{
AttributeValue *value = def(i)->makeValue(text, context, specLength);
if (def(i)->isConref())
conref_ = 1;
vec_[i].setValue(value);
if (value)
vec_[i].setSemantics(def(i)->makeSemantics(value, context,
nIdrefs_, nEntityNames_));
else if (AttributeValue::handleAsUnterminated(text, context))
return 0;
return 1;
}
void AttributeList::setValueToken(unsigned i, Text &text,
AttributeContext &context,
unsigned &specLength)
{
AttributeValue *value = def(i)->makeValueFromToken(text, context,
specLength);
if (def(i)->isConref())
conref_ = 1;
vec_[i].setValue(value);
if (value)
vec_[i].setSemantics(def(i)->makeSemantics(value, context,
nIdrefs_, nEntityNames_));
}
const StringC *AttributeList::getId() const
{
// Check for no attributes
if (def_.isNull())
return 0;
// Check for no ID declared
size_t i = def_->idIndex();
if (i == size_t(-1))
return 0;
// Check for invalid value
const AttributeValue *v = value(i);
if (!v)
return 0;
// Check for implied value
const Text *t = v->text();
if (!t)
return 0;
return &t->string();
}
Boolean AttributeList::recoverUnquoted(const StringC &str,
const Location &strLoc,
AttributeContext &context)
{
if (nSpec_ > 0) {
for (size_t i = 0; i < vec_.size(); i++)
if (vec_[i].specified() && vec_[i].specIndex() == nSpec_ - 1) {
const AttributeValue *val = vec_[i].value();
if (val)
// I wish I could avoid casting away const here.
return ((AttributeValue *)val)->recoverUnquoted(str, strLoc, context,
name(i));
break;
}
return 1;
}
return 0;
}
Boolean AttributeList::handleAsUnterminated(AttributeContext &context)
{
if (nSpec_ > 0) {
for (size_t i = 0; i < vec_.size(); i++) {
if (vec_[i].specified() && vec_[i].specIndex() == nSpec_ - 1) {
const AttributeValue *val = vec_[i].value();
const Text *ptr;
if (val && (ptr = val->text()) != 0
&& AttributeValue::handleAsUnterminated(*ptr, context))
return 1;
break;
}
}
}
return 0;
}
// This tries to guess this attribute value looks like if it had
// a missing ending quote.
Boolean AttributeValue::handleAsUnterminated(const Text &text,
AttributeContext &context)
{
TextIter iter(text);
const Char *lastStr = 0;
size_t lastLen;
Location startLoc;
const Location *loc;
TextItem::Type type;
const Char *str;
size_t len;
while (iter.next(type, str, len, loc)) {
if (startLoc.origin().isNull() && !loc->origin().isNull())
startLoc = *loc;
switch (type) {
case TextItem::data:
if (len != 1 || *str != context.attributeSyntax().space()) {
lastStr = str;
lastLen = len;
}
break;
case TextItem::endDelim:
case TextItem::endDelimA:
case TextItem::ignore:
break;
default:
lastStr = 0;
break;
}
}
if (lastStr) {
while (lastLen > 0
&& lastStr[lastLen - 1] == context.attributeSyntax().space())
lastLen--;
const StringC &vi = context.attributeSyntax().delimGeneral(Syntax::dVI);
if (lastLen >= vi.size()
&& (vi
== StringC(lastStr + (lastLen - vi.size()), vi.size()))) {
context.Messenger::setNextLocation(startLoc);
context.message(ParserMessages::literalClosingDelimiter);
return 1;
}
}
return 0;
}
AttributeContext::AttributeContext()
: mayDefaultAttribute_(0), validate_(1)
{
}
AttributeContext::~AttributeContext()
{
}
Boolean AttributeContext::defineId(const StringC &, const Location &,
Location &)
{
return 1;
}
void AttributeContext::noteIdref(const StringC &, const Location &)
{
}
void AttributeContext::noteCurrentAttribute(size_t, AttributeValue *)
{
}
ConstPtr<AttributeValue> AttributeContext::getCurrentAttribute(size_t) const
{
return 0;
}
ConstPtr<Entity> AttributeContext::getAttributeEntity(const StringC &,
const Location &)
{
return 0;
}
ConstPtr<Notation> AttributeContext::getAttributeNotation(const StringC &,
const Location &)
{
return 0;
}
ConstPtr<AttributeValue> AttributeContext::makeImpliedAttributeValue()
{
if (impliedAttributeValue_.isNull())
impliedAttributeValue_ = new ImpliedAttributeValue;
return impliedAttributeValue_;
}
#ifdef SP_NAMESPACE
}
#endif