mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-09 12:41:17 +00:00
Merged emitter refactor from core
This commit is contained in:
1121
src/emitter.cpp
1121
src/emitter.cpp
File diff suppressed because it is too large
Load Diff
@@ -4,11 +4,8 @@
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
EmitterState::EmitterState(): m_isGood(true), m_curIndent(0), m_requiresSoftSeparation(false), m_requiresHardSeparation(false)
|
||||
EmitterState::EmitterState(): m_isGood(true), m_curIndent(0), m_hasAnchor(false), m_hasTag(false), m_hasNonContent(false), m_docCount(0)
|
||||
{
|
||||
// start up
|
||||
m_stateStack.push(ES_WAITING_FOR_DOC);
|
||||
|
||||
// set default global manipulators
|
||||
m_charset.set(EmitNonAscii);
|
||||
m_strFmt.set(Auto);
|
||||
@@ -35,21 +32,111 @@ namespace YAML
|
||||
// . Only the ones that make sense will be accepted
|
||||
void EmitterState::SetLocalValue(EMITTER_MANIP value)
|
||||
{
|
||||
SetOutputCharset(value, LOCAL);
|
||||
SetStringFormat(value, LOCAL);
|
||||
SetBoolFormat(value, LOCAL);
|
||||
SetBoolCaseFormat(value, LOCAL);
|
||||
SetBoolLengthFormat(value, LOCAL);
|
||||
SetIntFormat(value, LOCAL);
|
||||
SetFlowType(GT_SEQ, value, LOCAL);
|
||||
SetFlowType(GT_MAP, value, LOCAL);
|
||||
SetMapKeyFormat(value, LOCAL);
|
||||
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::BeginGroup(GROUP_TYPE type)
|
||||
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::None;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
unsigned lastIndent = (m_groups.empty() ? 0 : m_groups.top().indent);
|
||||
m_curIndent += lastIndent;
|
||||
StartedNode();
|
||||
|
||||
const int lastGroupIndent = (m_groups.empty() ? 0 : m_groups.top().indent);
|
||||
m_curIndent += lastGroupIndent;
|
||||
|
||||
std::auto_ptr<Group> pGroup(new Group(type));
|
||||
|
||||
@@ -57,17 +144,23 @@ namespace YAML
|
||||
pGroup->modifiedSettings = m_modifiedSettings;
|
||||
|
||||
// set up group
|
||||
pGroup->flow = GetFlowType(type);
|
||||
if(GetFlowType(type) == Block)
|
||||
pGroup->flowType = FlowType::Block;
|
||||
else
|
||||
pGroup->flowType = FlowType::Flow;
|
||||
pGroup->indent = GetIndent();
|
||||
pGroup->usingLongKey = (GetMapKeyFormat() == LongKey ? true : false);
|
||||
|
||||
m_groups.push(pGroup);
|
||||
}
|
||||
|
||||
void EmitterState::EndGroup(GROUP_TYPE type)
|
||||
void EmitterState::EndedGroup(GroupType::value type)
|
||||
{
|
||||
if(m_groups.empty())
|
||||
return SetError(ErrorMsg::UNMATCHED_GROUP_TAG);
|
||||
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
|
||||
{
|
||||
@@ -84,49 +177,57 @@ namespace YAML
|
||||
// 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();
|
||||
}
|
||||
|
||||
GROUP_TYPE EmitterState::GetCurGroupType() const
|
||||
|
||||
EmitterNodeType::value EmitterState::CurGroupNodeType() const
|
||||
{
|
||||
if(m_groups.empty())
|
||||
return EmitterNodeType::None;
|
||||
|
||||
return m_groups.top().NodeType();
|
||||
}
|
||||
|
||||
GroupType::value EmitterState::CurGroupType() const
|
||||
{
|
||||
if(m_groups.empty())
|
||||
return GT_NONE;
|
||||
|
||||
return m_groups.top().type;
|
||||
return m_groups.empty() ? GroupType::None : m_groups.top().type;
|
||||
}
|
||||
|
||||
FLOW_TYPE EmitterState::GetCurGroupFlowType() const
|
||||
FlowType::value EmitterState::CurGroupFlowType() const
|
||||
{
|
||||
if(m_groups.empty())
|
||||
return FT_NONE;
|
||||
|
||||
return (m_groups.top().flow == Flow ? FT_FLOW : FT_BLOCK);
|
||||
}
|
||||
|
||||
bool EmitterState::CurrentlyInLongKey()
|
||||
{
|
||||
if(m_groups.empty())
|
||||
return false;
|
||||
return m_groups.top().usingLongKey;
|
||||
}
|
||||
|
||||
void EmitterState::StartLongKey()
|
||||
{
|
||||
if(!m_groups.empty())
|
||||
m_groups.top().usingLongKey = true;
|
||||
}
|
||||
|
||||
void EmitterState::StartSimpleKey()
|
||||
{
|
||||
if(!m_groups.empty())
|
||||
m_groups.top().usingLongKey = false;
|
||||
return m_groups.empty() ? FlowType::None : 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, FMT_SCOPE scope)
|
||||
bool EmitterState::SetOutputCharset(EMITTER_MANIP value, FmtScope::value scope)
|
||||
{
|
||||
switch(value) {
|
||||
case EmitNonAscii:
|
||||
@@ -138,7 +239,7 @@ namespace YAML
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetStringFormat(EMITTER_MANIP value, FMT_SCOPE scope)
|
||||
bool EmitterState::SetStringFormat(EMITTER_MANIP value, FmtScope::value scope)
|
||||
{
|
||||
switch(value) {
|
||||
case Auto:
|
||||
@@ -152,7 +253,7 @@ namespace YAML
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetBoolFormat(EMITTER_MANIP value, FMT_SCOPE scope)
|
||||
bool EmitterState::SetBoolFormat(EMITTER_MANIP value, FmtScope::value scope)
|
||||
{
|
||||
switch(value) {
|
||||
case OnOffBool:
|
||||
@@ -165,7 +266,7 @@ namespace YAML
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetBoolLengthFormat(EMITTER_MANIP value, FMT_SCOPE scope)
|
||||
bool EmitterState::SetBoolLengthFormat(EMITTER_MANIP value, FmtScope::value scope)
|
||||
{
|
||||
switch(value) {
|
||||
case LongBool:
|
||||
@@ -177,7 +278,7 @@ namespace YAML
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetBoolCaseFormat(EMITTER_MANIP value, FMT_SCOPE scope)
|
||||
bool EmitterState::SetBoolCaseFormat(EMITTER_MANIP value, FmtScope::value scope)
|
||||
{
|
||||
switch(value) {
|
||||
case UpperCase:
|
||||
@@ -190,7 +291,7 @@ namespace YAML
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetIntFormat(EMITTER_MANIP value, FMT_SCOPE scope)
|
||||
bool EmitterState::SetIntFormat(EMITTER_MANIP value, FmtScope::value scope)
|
||||
{
|
||||
switch(value) {
|
||||
case Dec:
|
||||
@@ -203,16 +304,16 @@ namespace YAML
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetIndent(unsigned value, FMT_SCOPE scope)
|
||||
bool EmitterState::SetIndent(unsigned value, FmtScope::value scope)
|
||||
{
|
||||
if(value == 0)
|
||||
if(value <= 1)
|
||||
return false;
|
||||
|
||||
_Set(m_indent, value, scope);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitterState::SetPreCommentIndent(unsigned value, FMT_SCOPE scope)
|
||||
bool EmitterState::SetPreCommentIndent(unsigned value, FmtScope::value scope)
|
||||
{
|
||||
if(value == 0)
|
||||
return false;
|
||||
@@ -221,7 +322,7 @@ namespace YAML
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitterState::SetPostCommentIndent(unsigned value, FMT_SCOPE scope)
|
||||
bool EmitterState::SetPostCommentIndent(unsigned value, FmtScope::value scope)
|
||||
{
|
||||
if(value == 0)
|
||||
return false;
|
||||
@@ -230,30 +331,29 @@ namespace YAML
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitterState::SetFlowType(GROUP_TYPE groupType, EMITTER_MANIP value, FMT_SCOPE scope)
|
||||
bool EmitterState::SetFlowType(GroupType::value groupType, EMITTER_MANIP value, FmtScope::value scope)
|
||||
{
|
||||
switch(value) {
|
||||
case Block:
|
||||
case Flow:
|
||||
_Set(groupType == GT_SEQ ? m_seqFmt : m_mapFmt, value, scope);
|
||||
_Set(groupType == GroupType::Seq ? m_seqFmt : m_mapFmt, value, scope);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
EMITTER_MANIP EmitterState::GetFlowType(GROUP_TYPE groupType) const
|
||||
EMITTER_MANIP EmitterState::GetFlowType(GroupType::value groupType) const
|
||||
{
|
||||
// force flow style if we're currently in a flow
|
||||
FLOW_TYPE flowType = GetCurGroupFlowType();
|
||||
if(flowType == FT_FLOW)
|
||||
if(CurGroupFlowType() == FlowType::Flow)
|
||||
return Flow;
|
||||
|
||||
// otherwise, go with what's asked of use
|
||||
return (groupType == GT_SEQ ? m_seqFmt.get() : m_mapFmt.get());
|
||||
// otherwise, go with what's asked of us
|
||||
return (groupType == GroupType::Seq ? m_seqFmt.get() : m_mapFmt.get());
|
||||
}
|
||||
|
||||
bool EmitterState::SetMapKeyFormat(EMITTER_MANIP value, FMT_SCOPE scope)
|
||||
bool EmitterState::SetMapKeyFormat(EMITTER_MANIP value, FmtScope::value scope)
|
||||
{
|
||||
switch(value) {
|
||||
case Auto:
|
||||
@@ -265,7 +365,7 @@ namespace YAML
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetFloatPrecision(int value, FMT_SCOPE scope)
|
||||
bool EmitterState::SetFloatPrecision(int value, FmtScope::value scope)
|
||||
{
|
||||
if(value < 0 || value > std::numeric_limits<float>::digits10)
|
||||
return false;
|
||||
@@ -273,7 +373,7 @@ namespace YAML
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitterState::SetDoublePrecision(int value, FMT_SCOPE scope)
|
||||
bool EmitterState::SetDoublePrecision(int value, FmtScope::value scope)
|
||||
{
|
||||
if(value < 0 || value > std::numeric_limits<double>::digits10)
|
||||
return false;
|
||||
|
@@ -8,71 +8,20 @@
|
||||
|
||||
#include "ptr_stack.h"
|
||||
#include "setting.h"
|
||||
#include "yaml-cpp/emitterdef.h"
|
||||
#include "yaml-cpp/emittermanip.h"
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
enum FMT_SCOPE {
|
||||
LOCAL,
|
||||
GLOBAL
|
||||
};
|
||||
|
||||
enum GROUP_TYPE {
|
||||
GT_NONE,
|
||||
GT_SEQ,
|
||||
GT_MAP
|
||||
};
|
||||
|
||||
enum FLOW_TYPE {
|
||||
FT_NONE,
|
||||
FT_FLOW,
|
||||
FT_BLOCK
|
||||
};
|
||||
|
||||
enum NODE_STATE {
|
||||
NS_START,
|
||||
NS_READY_FOR_ATOM,
|
||||
NS_END
|
||||
};
|
||||
|
||||
enum EMITTER_STATE {
|
||||
ES_WAITING_FOR_DOC,
|
||||
ES_WRITING_DOC,
|
||||
ES_DONE_WITH_DOC,
|
||||
|
||||
// block seq
|
||||
ES_WAITING_FOR_BLOCK_SEQ_ENTRY,
|
||||
ES_WRITING_BLOCK_SEQ_ENTRY,
|
||||
ES_DONE_WITH_BLOCK_SEQ_ENTRY,
|
||||
|
||||
// flow seq
|
||||
ES_WAITING_FOR_FLOW_SEQ_ENTRY,
|
||||
ES_WRITING_FLOW_SEQ_ENTRY,
|
||||
ES_DONE_WITH_FLOW_SEQ_ENTRY,
|
||||
|
||||
// block map
|
||||
ES_WAITING_FOR_BLOCK_MAP_ENTRY,
|
||||
ES_WAITING_FOR_BLOCK_MAP_KEY,
|
||||
ES_WRITING_BLOCK_MAP_KEY,
|
||||
ES_DONE_WITH_BLOCK_MAP_KEY,
|
||||
ES_WAITING_FOR_BLOCK_MAP_VALUE,
|
||||
ES_WRITING_BLOCK_MAP_VALUE,
|
||||
ES_DONE_WITH_BLOCK_MAP_VALUE,
|
||||
|
||||
// flow map
|
||||
ES_WAITING_FOR_FLOW_MAP_ENTRY,
|
||||
ES_WAITING_FOR_FLOW_MAP_KEY,
|
||||
ES_WRITING_FLOW_MAP_KEY,
|
||||
ES_DONE_WITH_FLOW_MAP_KEY,
|
||||
ES_WAITING_FOR_FLOW_MAP_VALUE,
|
||||
ES_WRITING_FLOW_MAP_VALUE,
|
||||
ES_DONE_WITH_FLOW_MAP_VALUE
|
||||
};
|
||||
|
||||
struct FmtScope { enum value { Local, Global }; };
|
||||
struct GroupType { enum value { None, Seq, Map }; };
|
||||
struct FlowType { enum value { None, Flow, Block }; };
|
||||
|
||||
class EmitterState
|
||||
{
|
||||
public:
|
||||
@@ -84,76 +33,81 @@ namespace YAML
|
||||
const std::string GetLastError() const { return m_lastError; }
|
||||
void SetError(const std::string& error) { m_isGood = false; m_lastError = error; }
|
||||
|
||||
// main state of the machine
|
||||
EMITTER_STATE GetCurState() const { return m_stateStack.top(); }
|
||||
void SwitchState(EMITTER_STATE state) { PopState(); PushState(state); }
|
||||
void PushState(EMITTER_STATE state) { m_stateStack.push(state); }
|
||||
void PopState() { m_stateStack.pop(); }
|
||||
|
||||
void SetLocalValue(EMITTER_MANIP value);
|
||||
|
||||
// group handling
|
||||
void BeginGroup(GROUP_TYPE type);
|
||||
void EndGroup(GROUP_TYPE type);
|
||||
|
||||
GROUP_TYPE GetCurGroupType() const;
|
||||
FLOW_TYPE GetCurGroupFlowType() const;
|
||||
int GetCurIndent() const { return m_curIndent; }
|
||||
|
||||
bool CurrentlyInLongKey();
|
||||
void StartLongKey();
|
||||
void StartSimpleKey();
|
||||
// node handling
|
||||
void SetAnchor();
|
||||
void SetTag();
|
||||
void SetNonContent();
|
||||
void SetLongKey();
|
||||
void ForceFlow();
|
||||
void StartedDoc();
|
||||
void EndedDoc();
|
||||
void StartedScalar();
|
||||
void StartedGroup(GroupType::value type);
|
||||
void EndedGroup(GroupType::value type);
|
||||
|
||||
bool RequiresSoftSeparation() const { return m_requiresSoftSeparation; }
|
||||
bool RequiresHardSeparation() const { return m_requiresHardSeparation; }
|
||||
void RequireSoftSeparation() { m_requiresSoftSeparation = true; }
|
||||
void RequireHardSeparation() { m_requiresSoftSeparation = true; m_requiresHardSeparation = true; }
|
||||
void ForceHardSeparation() { m_requiresSoftSeparation = false; }
|
||||
void UnsetSeparation() { m_requiresSoftSeparation = false; m_requiresHardSeparation = false; }
|
||||
EmitterNodeType::value NextGroupType(GroupType::value type) const;
|
||||
EmitterNodeType::value CurGroupNodeType() const;
|
||||
|
||||
GroupType::value CurGroupType() const;
|
||||
FlowType::value CurGroupFlowType() const;
|
||||
int CurGroupIndent() const;
|
||||
std::size_t CurGroupChildCount() const;
|
||||
bool CurGroupLongKey() const;
|
||||
|
||||
int LastIndent() const;
|
||||
int CurIndent() const { return m_curIndent; }
|
||||
bool HasAnchor() const { return m_hasAnchor; }
|
||||
bool HasTag() const { return m_hasTag; }
|
||||
bool HasBegunNode() const { return m_hasAnchor || m_hasTag || m_hasNonContent; }
|
||||
bool HasBegunContent() const { return m_hasAnchor || m_hasTag; }
|
||||
|
||||
void ClearModifiedSettings();
|
||||
|
||||
// formatters
|
||||
bool SetOutputCharset(EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
void SetLocalValue(EMITTER_MANIP value);
|
||||
|
||||
bool SetOutputCharset(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetOutputCharset() const { return m_charset.get(); }
|
||||
|
||||
bool SetStringFormat(EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
bool SetStringFormat(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetStringFormat() const { return m_strFmt.get(); }
|
||||
|
||||
bool SetBoolFormat(EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
bool SetBoolFormat(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetBoolFormat() const { return m_boolFmt.get(); }
|
||||
|
||||
bool SetBoolLengthFormat(EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
bool SetBoolLengthFormat(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetBoolLengthFormat() const { return m_boolLengthFmt.get(); }
|
||||
|
||||
bool SetBoolCaseFormat(EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
bool SetBoolCaseFormat(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetBoolCaseFormat() const { return m_boolCaseFmt.get(); }
|
||||
|
||||
bool SetIntFormat(EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
bool SetIntFormat(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetIntFormat() const { return m_intFmt.get(); }
|
||||
|
||||
bool SetIndent(unsigned value, FMT_SCOPE scope);
|
||||
bool SetIndent(unsigned value, FmtScope::value scope);
|
||||
int GetIndent() const { return m_indent.get(); }
|
||||
|
||||
bool SetPreCommentIndent(unsigned value, FMT_SCOPE scope);
|
||||
bool SetPreCommentIndent(unsigned value, FmtScope::value scope);
|
||||
int GetPreCommentIndent() const { return m_preCommentIndent.get(); }
|
||||
bool SetPostCommentIndent(unsigned value, FMT_SCOPE scope);
|
||||
bool SetPostCommentIndent(unsigned value, FmtScope::value scope);
|
||||
int GetPostCommentIndent() const { return m_postCommentIndent.get(); }
|
||||
|
||||
bool SetFlowType(GROUP_TYPE groupType, EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
EMITTER_MANIP GetFlowType(GROUP_TYPE groupType) const;
|
||||
bool SetFlowType(GroupType::value groupType, EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetFlowType(GroupType::value groupType) const;
|
||||
|
||||
bool SetMapKeyFormat(EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
bool SetMapKeyFormat(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetMapKeyFormat() const { return m_mapKeyFmt.get(); }
|
||||
|
||||
bool SetFloatPrecision(int value, FMT_SCOPE scope);
|
||||
bool SetFloatPrecision(int value, FmtScope::value scope);
|
||||
unsigned GetFloatPrecision() const { return m_floatPrecision.get(); }
|
||||
bool SetDoublePrecision(int value, FMT_SCOPE scope);
|
||||
bool SetDoublePrecision(int value, FmtScope::value scope);
|
||||
unsigned GetDoublePrecision() const { return m_doublePrecision.get(); }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void _Set(Setting<T>& fmt, T value, FMT_SCOPE scope);
|
||||
void _Set(Setting<T>& fmt, T value, FmtScope::value scope);
|
||||
|
||||
void StartedNode();
|
||||
|
||||
private:
|
||||
// basic state ok?
|
||||
@@ -161,8 +115,6 @@ namespace YAML
|
||||
std::string m_lastError;
|
||||
|
||||
// other state
|
||||
std::stack<EMITTER_STATE> m_stateStack;
|
||||
|
||||
Setting<EMITTER_MANIP> m_charset;
|
||||
Setting<EMITTER_MANIP> m_strFmt;
|
||||
Setting<EMITTER_MANIP> m_boolFmt;
|
||||
@@ -181,29 +133,50 @@ namespace YAML
|
||||
SettingChanges m_globalModifiedSettings;
|
||||
|
||||
struct Group {
|
||||
Group(GROUP_TYPE type_): type(type_), usingLongKey(false), indent(0) {}
|
||||
explicit Group(GroupType::value type_): type(type_), indent(0), childCount(0), longKey(false) {}
|
||||
|
||||
GROUP_TYPE type;
|
||||
EMITTER_MANIP flow;
|
||||
bool usingLongKey;
|
||||
GroupType::value type;
|
||||
FlowType::value flowType;
|
||||
int indent;
|
||||
std::size_t childCount;
|
||||
bool longKey;
|
||||
|
||||
SettingChanges modifiedSettings;
|
||||
|
||||
EmitterNodeType::value NodeType() const {
|
||||
if(type == GroupType::Seq) {
|
||||
if(flowType == FlowType::Flow)
|
||||
return EmitterNodeType::FlowSeq;
|
||||
else
|
||||
return EmitterNodeType::BlockSeq;
|
||||
} else {
|
||||
if(flowType == FlowType::Flow)
|
||||
return EmitterNodeType::FlowMap;
|
||||
else
|
||||
return EmitterNodeType::BlockMap;
|
||||
}
|
||||
|
||||
// can't get here
|
||||
assert(false);
|
||||
return EmitterNodeType::None;
|
||||
}
|
||||
};
|
||||
|
||||
ptr_stack<Group> m_groups;
|
||||
unsigned m_curIndent;
|
||||
bool m_requiresSoftSeparation;
|
||||
bool m_requiresHardSeparation;
|
||||
bool m_hasAnchor;
|
||||
bool m_hasTag;
|
||||
bool m_hasNonContent;
|
||||
std::size_t m_docCount;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void EmitterState::_Set(Setting<T>& fmt, T value, FMT_SCOPE scope) {
|
||||
void EmitterState::_Set(Setting<T>& fmt, T value, FmtScope::value scope) {
|
||||
switch(scope) {
|
||||
case LOCAL:
|
||||
case FmtScope::Local:
|
||||
m_modifiedSettings.push(fmt.set(value));
|
||||
break;
|
||||
case GLOBAL:
|
||||
case FmtScope::Global:
|
||||
fmt.set(value);
|
||||
m_globalModifiedSettings.push(fmt.set(value)); // this pushes an identity set, so when we restore,
|
||||
// it restores to the value here, and not the previous one
|
||||
|
@@ -128,12 +128,12 @@ namespace YAML
|
||||
}
|
||||
}
|
||||
|
||||
bool IsValidPlainScalar(const std::string& str, bool inFlow, bool allowOnlyAscii) {
|
||||
bool IsValidPlainScalar(const std::string& str, FlowType::value flowType, bool allowOnlyAscii) {
|
||||
if(str.empty())
|
||||
return false;
|
||||
|
||||
// first check the start
|
||||
const RegEx& start = (inFlow ? Exp::PlainScalarInFlow() : Exp::PlainScalar());
|
||||
const RegEx& start = (flowType == FlowType::Flow ? Exp::PlainScalarInFlow() : Exp::PlainScalar());
|
||||
if(!start.Matches(str))
|
||||
return false;
|
||||
|
||||
@@ -142,7 +142,7 @@ namespace YAML
|
||||
return false;
|
||||
|
||||
// then check until something is disallowed
|
||||
const RegEx& disallowed = (inFlow ? Exp::EndScalarInFlow() : Exp::EndScalar())
|
||||
const RegEx& disallowed = (flowType == FlowType::Flow ? Exp::EndScalarInFlow() : Exp::EndScalar())
|
||||
|| (Exp::BlankOrBreak() + Exp::Comment())
|
||||
|| Exp::NotPrintable()
|
||||
|| Exp::Utf8_ByteOrderMark()
|
||||
@@ -152,7 +152,7 @@ namespace YAML
|
||||
while(buffer) {
|
||||
if(disallowed.Matches(buffer))
|
||||
return false;
|
||||
if(allowOnlyAscii && (0x7F < static_cast<unsigned char>(buffer[0])))
|
||||
if(allowOnlyAscii && (0x80 <= static_cast<unsigned char>(buffer[0])))
|
||||
return false;
|
||||
++buffer;
|
||||
}
|
||||
@@ -160,7 +160,32 @@ namespace YAML
|
||||
return true;
|
||||
}
|
||||
|
||||
void WriteDoubleQuoteEscapeSequence(ostream& out, int codePoint) {
|
||||
bool IsValidSingleQuotedScalar(const std::string& str, bool escapeNonAscii)
|
||||
{
|
||||
// TODO: check for non-printable characters?
|
||||
for(std::size_t i=0;i<str.size();i++) {
|
||||
if(escapeNonAscii && (0x80 <= static_cast<unsigned char>(str[i])))
|
||||
return false;
|
||||
if(str[i] == '\n')
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsValidLiteralScalar(const std::string& str, FlowType::value flowType, bool escapeNonAscii)
|
||||
{
|
||||
if(flowType == FlowType::Flow)
|
||||
return false;
|
||||
|
||||
// TODO: check for non-printable characters?
|
||||
for(std::size_t i=0;i<str.size();i++) {
|
||||
if(escapeNonAscii && (0x80 <= static_cast<unsigned char>(str[i])))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void WriteDoubleQuoteEscapeSequence(ostream& out, int codePoint) {
|
||||
static const char hexDigits[] = "0123456789abcdef";
|
||||
|
||||
char escSeq[] = "\\U00000000";
|
||||
@@ -198,15 +223,30 @@ namespace YAML
|
||||
}
|
||||
}
|
||||
|
||||
bool WriteString(ostream& out, const std::string& str, bool inFlow, bool escapeNonAscii)
|
||||
{
|
||||
if(IsValidPlainScalar(str, inFlow, escapeNonAscii)) {
|
||||
out << str;
|
||||
return true;
|
||||
} else
|
||||
return WriteDoubleQuotedString(out, str, escapeNonAscii);
|
||||
}
|
||||
|
||||
StringFormat::value ComputeStringFormat(const std::string& str, EMITTER_MANIP strFormat, FlowType::value flowType, bool escapeNonAscii)
|
||||
{
|
||||
switch(strFormat) {
|
||||
case Auto:
|
||||
if(IsValidPlainScalar(str, flowType, escapeNonAscii))
|
||||
return StringFormat::Plain;
|
||||
return StringFormat::DoubleQuoted;
|
||||
case SingleQuoted:
|
||||
if(IsValidSingleQuotedScalar(str, escapeNonAscii))
|
||||
return StringFormat::SingleQuoted;
|
||||
return StringFormat::DoubleQuoted;
|
||||
case DoubleQuoted:
|
||||
return StringFormat::DoubleQuoted;
|
||||
case Literal:
|
||||
if(IsValidLiteralScalar(str, flowType, escapeNonAscii))
|
||||
return StringFormat::Literal;
|
||||
return StringFormat::DoubleQuoted;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return StringFormat::DoubleQuoted;
|
||||
}
|
||||
|
||||
bool WriteSingleQuotedString(ostream& out, const std::string& str)
|
||||
{
|
||||
out << "'";
|
||||
@@ -235,18 +275,23 @@ namespace YAML
|
||||
GetNextCodePointAndAdvance(codePoint, i, str.end());
|
||||
)
|
||||
{
|
||||
if (codePoint == '\"')
|
||||
out << "\\\"";
|
||||
else if (codePoint == '\\')
|
||||
out << "\\\\";
|
||||
else if (codePoint < 0x20 || (codePoint >= 0x80 && codePoint <= 0xA0)) // Control characters and non-breaking space
|
||||
WriteDoubleQuoteEscapeSequence(out, codePoint);
|
||||
else if (codePoint == 0xFEFF) // Byte order marks (ZWNS) should be escaped (YAML 1.2, sec. 5.2)
|
||||
WriteDoubleQuoteEscapeSequence(out, codePoint);
|
||||
else if (escapeNonAscii && codePoint > 0x7E)
|
||||
WriteDoubleQuoteEscapeSequence(out, codePoint);
|
||||
else
|
||||
WriteCodePoint(out, codePoint);
|
||||
switch(codePoint) {
|
||||
case '\"': out << "\\\""; break;
|
||||
case '\\': out << "\\\\"; break;
|
||||
case '\n': out << "\\n"; break;
|
||||
case '\t': out << "\\t"; break;
|
||||
case '\r': out << "\\r"; break;
|
||||
case '\b': out << "\\b"; break;
|
||||
default:
|
||||
if(codePoint < 0x20 || (codePoint >= 0x80 && codePoint <= 0xA0)) // Control characters and non-breaking space
|
||||
WriteDoubleQuoteEscapeSequence(out, codePoint);
|
||||
else if (codePoint == 0xFEFF) // Byte order marks (ZWNS) should be escaped (YAML 1.2, sec. 5.2)
|
||||
WriteDoubleQuoteEscapeSequence(out, codePoint);
|
||||
else if (escapeNonAscii && codePoint > 0x7E)
|
||||
WriteDoubleQuoteEscapeSequence(out, codePoint);
|
||||
else
|
||||
WriteCodePoint(out, codePoint);
|
||||
}
|
||||
}
|
||||
out << "\"";
|
||||
return true;
|
||||
@@ -293,15 +338,18 @@ namespace YAML
|
||||
{
|
||||
const unsigned curIndent = out.col();
|
||||
out << "#" << Indentation(postCommentIndent);
|
||||
out.set_comment();
|
||||
int codePoint;
|
||||
for(std::string::const_iterator i = str.begin();
|
||||
GetNextCodePointAndAdvance(codePoint, i, str.end());
|
||||
)
|
||||
{
|
||||
if(codePoint == '\n')
|
||||
if(codePoint == '\n') {
|
||||
out << "\n" << IndentTo(curIndent) << "#" << Indentation(postCommentIndent);
|
||||
else
|
||||
out.set_comment();
|
||||
} else {
|
||||
WriteCodePoint(out, codePoint);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@
|
||||
#endif
|
||||
|
||||
|
||||
#include "emitterstate.h"
|
||||
#include "yaml-cpp/ostream.h"
|
||||
#include <string>
|
||||
|
||||
@@ -13,9 +14,12 @@ namespace YAML
|
||||
{
|
||||
class Binary;
|
||||
|
||||
struct StringFormat { enum value { Plain, SingleQuoted, DoubleQuoted, Literal }; };
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
bool WriteString(ostream& out, const std::string& str, bool inFlow, bool escapeNonAscii);
|
||||
StringFormat::value ComputeStringFormat(const std::string& str, EMITTER_MANIP strFormat, FlowType::value flowType, bool escapeNonAscii);
|
||||
|
||||
bool WriteSingleQuotedString(ostream& out, const std::string& str);
|
||||
bool WriteDoubleQuotedString(ostream& out, const std::string& str, bool escapeNonAscii);
|
||||
bool WriteLiteralString(ostream& out, const std::string& str, int indent);
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
ostream::ostream(): m_buffer(0), m_pos(0), m_size(0), m_row(0), m_col(0)
|
||||
ostream::ostream(): m_buffer(0), m_pos(0), m_size(0), m_row(0), m_col(0), m_comment(false)
|
||||
{
|
||||
reserve(1024);
|
||||
}
|
||||
@@ -37,6 +37,7 @@ namespace YAML
|
||||
if(ch == '\n') {
|
||||
m_row++;
|
||||
m_col = 0;
|
||||
m_comment = false;
|
||||
} else
|
||||
m_col++;
|
||||
}
|
||||
|
@@ -38,7 +38,10 @@ public:
|
||||
}
|
||||
T& top() { return *m_data.back(); }
|
||||
const T& top() const { return *m_data.back(); }
|
||||
|
||||
|
||||
T& top(std::ptrdiff_t diff) { return **(m_data.end() - 1 + diff); }
|
||||
const T& top(std::ptrdiff_t diff) const { return **(m_data.end() - 1 + diff); }
|
||||
|
||||
private:
|
||||
std::vector<T*> m_data;
|
||||
};
|
||||
|
Reference in New Issue
Block a user