You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
400 lines
9.8 KiB
400 lines
9.8 KiB
#include <limits>
|
|
|
|
#include "emitterstate.h"
|
|
#include "yaml-cpp/exceptions.h" // IWYU pragma: keep
|
|
|
|
namespace YAML {
|
|
EmitterState::EmitterState()
|
|
: m_isGood(true),
|
|
m_lastError{},
|
|
// default global manipulators
|
|
m_charset(EmitNonAscii),
|
|
m_strFmt(Auto),
|
|
m_boolFmt(TrueFalseBool),
|
|
m_boolLengthFmt(LongBool),
|
|
m_boolCaseFmt(LowerCase),
|
|
m_nullFmt(TildeNull),
|
|
m_intFmt(Dec),
|
|
m_indent(2),
|
|
m_preCommentIndent(2),
|
|
m_postCommentIndent(1),
|
|
m_seqFmt(Block),
|
|
m_mapFmt(Block),
|
|
m_mapKeyFmt(Auto),
|
|
m_floatPrecision(std::numeric_limits<float>::max_digits10),
|
|
m_doublePrecision(std::numeric_limits<double>::max_digits10),
|
|
//
|
|
m_modifiedSettings{},
|
|
m_globalModifiedSettings{},
|
|
m_groups{},
|
|
m_curIndent(0),
|
|
m_hasAnchor(false),
|
|
m_hasAlias(false),
|
|
m_hasTag(false),
|
|
m_hasNonContent(false),
|
|
m_docCount(0) {}
|
|
|
|
EmitterState::~EmitterState() = default;
|
|
|
|
// SetLocalValue
|
|
// . We blindly tries to set all possible formatters to this value
|
|
// . Only the ones that make sense will be accepted
|
|
void EmitterState::SetLocalValue(EMITTER_MANIP value) {
|
|
SetOutputCharset(value, FmtScope::Local);
|
|
SetStringFormat(value, FmtScope::Local);
|
|
SetBoolFormat(value, FmtScope::Local);
|
|
SetBoolCaseFormat(value, FmtScope::Local);
|
|
SetBoolLengthFormat(value, FmtScope::Local);
|
|
SetNullFormat(value, FmtScope::Local);
|
|
SetIntFormat(value, FmtScope::Local);
|
|
SetFlowType(GroupType::Seq, value, FmtScope::Local);
|
|
SetFlowType(GroupType::Map, value, FmtScope::Local);
|
|
SetMapKeyFormat(value, FmtScope::Local);
|
|
}
|
|
|
|
void EmitterState::SetAnchor() { m_hasAnchor = true; }
|
|
|
|
void EmitterState::SetAlias() { m_hasAlias = true; }
|
|
|
|
void EmitterState::SetTag() { m_hasTag = true; }
|
|
|
|
void EmitterState::SetNonContent() { m_hasNonContent = true; }
|
|
|
|
void EmitterState::SetLongKey() {
|
|
assert(!m_groups.empty());
|
|
if (m_groups.empty()) {
|
|
return;
|
|
}
|
|
|
|
assert(m_groups.back()->type == GroupType::Map);
|
|
m_groups.back()->longKey = true;
|
|
}
|
|
|
|
void EmitterState::ForceFlow() {
|
|
assert(!m_groups.empty());
|
|
if (m_groups.empty()) {
|
|
return;
|
|
}
|
|
|
|
m_groups.back()->flowType = FlowType::Flow;
|
|
}
|
|
|
|
void EmitterState::StartedNode() {
|
|
if (m_groups.empty()) {
|
|
m_docCount++;
|
|
} else {
|
|
m_groups.back()->childCount++;
|
|
if (m_groups.back()->childCount % 2 == 0) {
|
|
m_groups.back()->longKey = false;
|
|
}
|
|
}
|
|
|
|
m_hasAnchor = false;
|
|
m_hasAlias = false;
|
|
m_hasTag = false;
|
|
m_hasNonContent = false;
|
|
}
|
|
|
|
EmitterNodeType::value EmitterState::NextGroupType(
|
|
GroupType::value type) const {
|
|
if (type == GroupType::Seq) {
|
|
if (GetFlowType(type) == Block)
|
|
return EmitterNodeType::BlockSeq;
|
|
return EmitterNodeType::FlowSeq;
|
|
}
|
|
|
|
if (GetFlowType(type) == Block)
|
|
return EmitterNodeType::BlockMap;
|
|
return EmitterNodeType::FlowMap;
|
|
|
|
// can't happen
|
|
assert(false);
|
|
return EmitterNodeType::NoType;
|
|
}
|
|
|
|
void EmitterState::StartedDoc() {
|
|
m_hasAnchor = false;
|
|
m_hasTag = false;
|
|
m_hasNonContent = false;
|
|
}
|
|
|
|
void EmitterState::EndedDoc() {
|
|
m_hasAnchor = false;
|
|
m_hasTag = false;
|
|
m_hasNonContent = false;
|
|
}
|
|
|
|
void EmitterState::StartedScalar() {
|
|
StartedNode();
|
|
ClearModifiedSettings();
|
|
}
|
|
|
|
void EmitterState::StartedGroup(GroupType::value type) {
|
|
StartedNode();
|
|
|
|
const std::size_t lastGroupIndent =
|
|
(m_groups.empty() ? 0 : m_groups.back()->indent);
|
|
m_curIndent += lastGroupIndent;
|
|
|
|
// TODO: Create move constructors for settings types to simplify transfer
|
|
std::unique_ptr<Group> pGroup(new Group(type));
|
|
|
|
// transfer settings (which last until this group is done)
|
|
//
|
|
// NB: if pGroup->modifiedSettings == m_modifiedSettings,
|
|
// m_modifiedSettings is not changed!
|
|
pGroup->modifiedSettings = std::move(m_modifiedSettings);
|
|
|
|
// set up group
|
|
if (GetFlowType(type) == Block) {
|
|
pGroup->flowType = FlowType::Block;
|
|
} else {
|
|
pGroup->flowType = FlowType::Flow;
|
|
}
|
|
pGroup->indent = GetIndent();
|
|
|
|
m_groups.push_back(std::move(pGroup));
|
|
}
|
|
|
|
void EmitterState::EndedGroup(GroupType::value type) {
|
|
if (m_groups.empty()) {
|
|
if (type == GroupType::Seq) {
|
|
return SetError(ErrorMsg::UNEXPECTED_END_SEQ);
|
|
}
|
|
return SetError(ErrorMsg::UNEXPECTED_END_MAP);
|
|
}
|
|
|
|
if (m_hasTag) {
|
|
SetError(ErrorMsg::INVALID_TAG);
|
|
}
|
|
if (m_hasAnchor) {
|
|
SetError(ErrorMsg::INVALID_ANCHOR);
|
|
}
|
|
|
|
// get rid of the current group
|
|
{
|
|
std::unique_ptr<Group> pFinishedGroup = std::move(m_groups.back());
|
|
m_groups.pop_back();
|
|
if (pFinishedGroup->type != type) {
|
|
return SetError(ErrorMsg::UNMATCHED_GROUP_TAG);
|
|
}
|
|
}
|
|
|
|
// reset old settings
|
|
std::size_t lastIndent = (m_groups.empty() ? 0 : m_groups.back()->indent);
|
|
assert(m_curIndent >= lastIndent);
|
|
m_curIndent -= lastIndent;
|
|
|
|
// some global settings that we changed may have been overridden
|
|
// by a local setting we just popped, so we need to restore them
|
|
m_globalModifiedSettings.restore();
|
|
|
|
ClearModifiedSettings();
|
|
m_hasAnchor = false;
|
|
m_hasTag = false;
|
|
m_hasNonContent = false;
|
|
}
|
|
|
|
EmitterNodeType::value EmitterState::CurGroupNodeType() const {
|
|
if (m_groups.empty()) {
|
|
return EmitterNodeType::NoType;
|
|
}
|
|
|
|
return m_groups.back()->NodeType();
|
|
}
|
|
|
|
GroupType::value EmitterState::CurGroupType() const {
|
|
return m_groups.empty() ? GroupType::NoType : m_groups.back()->type;
|
|
}
|
|
|
|
FlowType::value EmitterState::CurGroupFlowType() const {
|
|
return m_groups.empty() ? FlowType::NoType : m_groups.back()->flowType;
|
|
}
|
|
|
|
std::size_t EmitterState::CurGroupIndent() const {
|
|
return m_groups.empty() ? 0 : m_groups.back()->indent;
|
|
}
|
|
|
|
std::size_t EmitterState::CurGroupChildCount() const {
|
|
return m_groups.empty() ? m_docCount : m_groups.back()->childCount;
|
|
}
|
|
|
|
bool EmitterState::CurGroupLongKey() const {
|
|
return m_groups.empty() ? false : m_groups.back()->longKey;
|
|
}
|
|
|
|
std::size_t EmitterState::LastIndent() const {
|
|
if (m_groups.size() <= 1) {
|
|
return 0;
|
|
}
|
|
|
|
return m_curIndent - m_groups[m_groups.size() - 2]->indent;
|
|
}
|
|
|
|
void EmitterState::ClearModifiedSettings() { m_modifiedSettings.clear(); }
|
|
|
|
void EmitterState::RestoreGlobalModifiedSettings() {
|
|
m_globalModifiedSettings.restore();
|
|
}
|
|
|
|
bool EmitterState::SetOutputCharset(EMITTER_MANIP value,
|
|
FmtScope::value scope) {
|
|
switch (value) {
|
|
case EmitNonAscii:
|
|
case EscapeNonAscii:
|
|
case EscapeAsJson:
|
|
_Set(m_charset, value, scope);
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool EmitterState::SetStringFormat(EMITTER_MANIP value, FmtScope::value scope) {
|
|
switch (value) {
|
|
case Auto:
|
|
case SingleQuoted:
|
|
case DoubleQuoted:
|
|
case Literal:
|
|
_Set(m_strFmt, value, scope);
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool EmitterState::SetBoolFormat(EMITTER_MANIP value, FmtScope::value scope) {
|
|
switch (value) {
|
|
case OnOffBool:
|
|
case TrueFalseBool:
|
|
case YesNoBool:
|
|
_Set(m_boolFmt, value, scope);
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool EmitterState::SetBoolLengthFormat(EMITTER_MANIP value,
|
|
FmtScope::value scope) {
|
|
switch (value) {
|
|
case LongBool:
|
|
case ShortBool:
|
|
_Set(m_boolLengthFmt, value, scope);
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool EmitterState::SetBoolCaseFormat(EMITTER_MANIP value,
|
|
FmtScope::value scope) {
|
|
switch (value) {
|
|
case UpperCase:
|
|
case LowerCase:
|
|
case CamelCase:
|
|
_Set(m_boolCaseFmt, value, scope);
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool EmitterState::SetNullFormat(EMITTER_MANIP value, FmtScope::value scope) {
|
|
switch (value) {
|
|
case LowerNull:
|
|
case UpperNull:
|
|
case CamelNull:
|
|
case TildeNull:
|
|
_Set(m_nullFmt, value, scope);
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool EmitterState::SetIntFormat(EMITTER_MANIP value, FmtScope::value scope) {
|
|
switch (value) {
|
|
case Dec:
|
|
case Hex:
|
|
case Oct:
|
|
_Set(m_intFmt, value, scope);
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool EmitterState::SetIndent(std::size_t value, FmtScope::value scope) {
|
|
if (value <= 1)
|
|
return false;
|
|
|
|
_Set(m_indent, value, scope);
|
|
return true;
|
|
}
|
|
|
|
bool EmitterState::SetPreCommentIndent(std::size_t value,
|
|
FmtScope::value scope) {
|
|
if (value == 0)
|
|
return false;
|
|
|
|
_Set(m_preCommentIndent, value, scope);
|
|
return true;
|
|
}
|
|
|
|
bool EmitterState::SetPostCommentIndent(std::size_t value,
|
|
FmtScope::value scope) {
|
|
if (value == 0)
|
|
return false;
|
|
|
|
_Set(m_postCommentIndent, value, scope);
|
|
return true;
|
|
}
|
|
|
|
bool EmitterState::SetFlowType(GroupType::value groupType, EMITTER_MANIP value,
|
|
FmtScope::value scope) {
|
|
switch (value) {
|
|
case Block:
|
|
case Flow:
|
|
_Set(groupType == GroupType::Seq ? m_seqFmt : m_mapFmt, value, scope);
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
EMITTER_MANIP EmitterState::GetFlowType(GroupType::value groupType) const {
|
|
// force flow style if we're currently in a flow
|
|
if (CurGroupFlowType() == FlowType::Flow)
|
|
return Flow;
|
|
|
|
// otherwise, go with what's asked of us
|
|
return (groupType == GroupType::Seq ? m_seqFmt.get() : m_mapFmt.get());
|
|
}
|
|
|
|
bool EmitterState::SetMapKeyFormat(EMITTER_MANIP value, FmtScope::value scope) {
|
|
switch (value) {
|
|
case Auto:
|
|
case LongKey:
|
|
_Set(m_mapKeyFmt, value, scope);
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool EmitterState::SetFloatPrecision(std::size_t value, FmtScope::value scope) {
|
|
if (value > std::numeric_limits<float>::max_digits10)
|
|
return false;
|
|
_Set(m_floatPrecision, value, scope);
|
|
return true;
|
|
}
|
|
|
|
bool EmitterState::SetDoublePrecision(std::size_t value,
|
|
FmtScope::value scope) {
|
|
if (value > std::numeric_limits<double>::max_digits10)
|
|
return false;
|
|
_Set(m_doublePrecision, value, scope);
|
|
return true;
|
|
}
|
|
} // namespace YAML
|