#include #include "emitterstate.h" #include "yaml-cpp/exceptions.h" // IWYU pragma: keep namespace YAML { EmitterState::EmitterState() : m_isGood(true), m_curIndent(0), m_hasAnchor(false), m_hasTag(false), m_hasNonContent(false), m_docCount(0) { // set default global manipulators m_charset.set(EmitNonAscii); m_strFmt.set(Auto); m_boolFmt.set(TrueFalseBool); m_boolLengthFmt.set(LongBool); m_boolCaseFmt.set(LowerCase); m_intFmt.set(Dec); m_indent.set(2); m_preCommentIndent.set(2); m_postCommentIndent.set(1); m_seqFmt.set(Block); m_mapFmt.set(Block); m_mapKeyFmt.set(Auto); m_floatPrecision.set(std::numeric_limits::digits10 + 1); m_doublePrecision.set(std::numeric_limits::digits10 + 1); } EmitterState::~EmitterState() {} // 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); 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::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.top().type == GroupType::Map); m_groups.top().longKey = true; } void EmitterState::ForceFlow() { assert(!m_groups.empty()); if (m_groups.empty()) return; m_groups.top().flowType = FlowType::Flow; } void EmitterState::StartedNode() { if (m_groups.empty()) { m_docCount++; } else { m_groups.top().childCount++; if (m_groups.top().childCount % 2 == 0) m_groups.top().longKey = false; } m_hasAnchor = 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; else return EmitterNodeType::FlowSeq; } else { if (GetFlowType(type) == Block) return EmitterNodeType::BlockMap; else 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 int lastGroupIndent = (m_groups.empty() ? 0 : m_groups.top().indent); m_curIndent += lastGroupIndent; std::auto_ptr pGroup(new Group(type)); // transfer settings (which last until this group is done) pGroup->modifiedSettings = m_modifiedSettings; // set up group if (GetFlowType(type) == Block) pGroup->flowType = FlowType::Block; else pGroup->flowType = FlowType::Flow; pGroup->indent = GetIndent(); m_groups.push(pGroup); } void EmitterState::EndedGroup(GroupType::value type) { if (m_groups.empty()) { if (type == GroupType::Seq) return SetError(ErrorMsg::UNEXPECTED_END_SEQ); else return SetError(ErrorMsg::UNEXPECTED_END_MAP); } // get rid of the current group { std::auto_ptr pFinishedGroup = m_groups.pop(); if (pFinishedGroup->type != type) return SetError(ErrorMsg::UNMATCHED_GROUP_TAG); } // reset old settings std::size_t lastIndent = (m_groups.empty() ? 0 : m_groups.top().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(); } EmitterNodeType::value EmitterState::CurGroupNodeType() const { if (m_groups.empty()) return EmitterNodeType::NoType; return m_groups.top().NodeType(); } GroupType::value EmitterState::CurGroupType() const { return m_groups.empty() ? GroupType::NoType : m_groups.top().type; } FlowType::value EmitterState::CurGroupFlowType() const { return m_groups.empty() ? FlowType::NoType : m_groups.top().flowType; } int EmitterState::CurGroupIndent() const { return m_groups.empty() ? 0 : m_groups.top().indent; } std::size_t EmitterState::CurGroupChildCount() const { return m_groups.empty() ? m_docCount : m_groups.top().childCount; } bool EmitterState::CurGroupLongKey() const { return m_groups.empty() ? false : m_groups.top().longKey; } int EmitterState::LastIndent() const { if (m_groups.size() <= 1) return 0; return m_curIndent - m_groups.top(-1).indent; } void EmitterState::ClearModifiedSettings() { m_modifiedSettings.clear(); } bool EmitterState::SetOutputCharset(EMITTER_MANIP value, FmtScope::value scope) { switch (value) { case EmitNonAscii: case EscapeNonAscii: _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::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(int value, FmtScope::value scope) { if (value < 0 || value > std::numeric_limits::digits10 + 1) return false; _Set(m_floatPrecision, value, scope); return true; } bool EmitterState::SetDoublePrecision(int value, FmtScope::value scope) { if (value < 0 || value > std::numeric_limits::digits10 + 1) return false; _Set(m_doublePrecision, value, scope); return true; } }