mirror of
https://github.com/loot/yaml-cpp.git
synced 2026-07-27 14:13:42 -07:00
Merged emitter branch into trunk, changes r105:r151
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
#include "emittermanip.h"
|
||||
#include "ostream.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
class EmitterState;
|
||||
|
||||
class Emitter
|
||||
{
|
||||
public:
|
||||
Emitter();
|
||||
~Emitter();
|
||||
|
||||
bool WriteToStream(std::ostream& out) const;
|
||||
bool WriteToFile(const std::string& fileName) const;
|
||||
|
||||
// state checking
|
||||
bool good() const;
|
||||
const std::string GetLastError() const;
|
||||
|
||||
// global setters
|
||||
bool SetStringFormat(EMITTER_MANIP value);
|
||||
bool SetBoolFormat(EMITTER_MANIP value);
|
||||
bool SetIntBase(EMITTER_MANIP value);
|
||||
bool SetSeqFormat(EMITTER_MANIP value);
|
||||
bool SetMapFormat(EMITTER_MANIP value);
|
||||
bool SetIndent(unsigned n);
|
||||
bool SetPreCommentIndent(unsigned n);
|
||||
bool SetPostCommentIndent(unsigned n);
|
||||
|
||||
// local setters
|
||||
Emitter& SetLocalValue(EMITTER_MANIP value);
|
||||
Emitter& SetLocalIndent(const _Indent& indent);
|
||||
|
||||
// overloads of write
|
||||
Emitter& Write(const std::string& str);
|
||||
Emitter& Write(const char *str);
|
||||
Emitter& Write(int i);
|
||||
Emitter& Write(bool b);
|
||||
Emitter& Write(float f);
|
||||
Emitter& Write(double d);
|
||||
Emitter& Write(const _Alias& alias);
|
||||
Emitter& Write(const _Anchor& anchor);
|
||||
Emitter& Write(const _Comment& comment);
|
||||
|
||||
private:
|
||||
enum ATOMIC_TYPE { AT_SCALAR, AT_SEQ, AT_BLOCK_SEQ, AT_FLOW_SEQ, AT_MAP, AT_BLOCK_MAP, AT_FLOW_MAP };
|
||||
|
||||
void PreAtomicWrite();
|
||||
bool GotoNextPreAtomicState();
|
||||
void PostAtomicWrite();
|
||||
void EmitSeparationIfNecessary();
|
||||
|
||||
void EmitBeginSeq();
|
||||
void EmitEndSeq();
|
||||
void EmitBeginMap();
|
||||
void EmitEndMap();
|
||||
void EmitKey();
|
||||
void EmitValue();
|
||||
|
||||
private:
|
||||
ostream m_stream;
|
||||
std::auto_ptr <EmitterState> m_pState;
|
||||
};
|
||||
|
||||
// overloads of insertion
|
||||
template <typename T>
|
||||
inline Emitter& operator << (Emitter& emitter, T v) {
|
||||
return emitter.Write(v);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline Emitter& operator << (Emitter& emitter, EMITTER_MANIP value) {
|
||||
return emitter.SetLocalValue(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline Emitter& operator << (Emitter& emitter, _Indent indent) {
|
||||
return emitter.SetLocalIndent(indent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
enum EMITTER_MANIP {
|
||||
// general manipulators
|
||||
Auto,
|
||||
|
||||
// string manipulators
|
||||
// Auto, // duplicate
|
||||
SingleQuoted,
|
||||
DoubleQuoted,
|
||||
Literal,
|
||||
|
||||
// bool manipulators
|
||||
YesNoBool, // yes, no
|
||||
TrueFalseBool, // true, false
|
||||
OnOffBool, // on, off
|
||||
UpperCase, // TRUE, N
|
||||
LowerCase, // f, yes
|
||||
CamelCase, // No, Off
|
||||
LongBool, // yes, On
|
||||
ShortBool, // y, t
|
||||
|
||||
// int manipulators
|
||||
Dec,
|
||||
Hex,
|
||||
Oct,
|
||||
|
||||
// sequence manipulators
|
||||
BeginSeq,
|
||||
EndSeq,
|
||||
Flow,
|
||||
Block,
|
||||
|
||||
// map manipulators
|
||||
BeginMap,
|
||||
EndMap,
|
||||
Key,
|
||||
Value,
|
||||
// Flow, // duplicate
|
||||
// Block, // duplicate
|
||||
// Auto, // duplicate
|
||||
LongKey,
|
||||
};
|
||||
|
||||
struct _Indent {
|
||||
_Indent(int value_): value(value_) {}
|
||||
int value;
|
||||
};
|
||||
|
||||
inline _Indent Indent(int value) {
|
||||
return _Indent(value);
|
||||
}
|
||||
|
||||
struct _Alias {
|
||||
_Alias(const std::string& content_): content(content_) {}
|
||||
std::string content;
|
||||
};
|
||||
|
||||
inline _Alias Alias(const std::string content) {
|
||||
return _Alias(content);
|
||||
}
|
||||
|
||||
struct _Anchor {
|
||||
_Anchor(const std::string& content_): content(content_) {}
|
||||
std::string content;
|
||||
};
|
||||
|
||||
inline _Anchor Anchor(const std::string content) {
|
||||
return _Anchor(content);
|
||||
}
|
||||
|
||||
struct _Comment {
|
||||
_Comment(const std::string& content_): content(content_) {}
|
||||
std::string content;
|
||||
};
|
||||
|
||||
inline _Comment Comment(const std::string content) {
|
||||
return _Comment(content);
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,17 @@ namespace YAML
|
||||
const std::string INVALID_SCALAR = "invalid scalar";
|
||||
const std::string KEY_NOT_FOUND = "key not found";
|
||||
const std::string BAD_DEREFERENCE = "bad dereference";
|
||||
|
||||
const std::string UNMATCHED_GROUP_TAG = "unmatched group tag";
|
||||
const std::string UNEXPECTED_END_SEQ = "unexpected end sequence token";
|
||||
const std::string UNEXPECTED_END_MAP = "unexpected end map token";
|
||||
const std::string SINGLE_QUOTED_CHAR = "invalid character in single-quoted string";
|
||||
const std::string INVALID_ANCHOR = "invalid anchor";
|
||||
const std::string INVALID_ALIAS = "invalid alias";
|
||||
const std::string EXPECTED_KEY_TOKEN = "expected key token";
|
||||
const std::string EXPECTED_VALUE_TOKEN = "expected value token";
|
||||
const std::string UNEXPECTED_KEY_TOKEN = "unexpected key token";
|
||||
const std::string UNEXPECTED_VALUE_TOKEN = "unexpected value token";
|
||||
}
|
||||
|
||||
class Exception: public std::exception {
|
||||
@@ -101,4 +112,10 @@ namespace YAML
|
||||
BadDereference()
|
||||
: RepresentationException(-1, -1, ErrorMsg::BAD_DEREFERENCE) {}
|
||||
};
|
||||
|
||||
class EmitterException: public Exception {
|
||||
public:
|
||||
EmitterException(const std::string& msg_)
|
||||
: Exception(-1, -1, msg_) {}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
// this is basically boost::noncopyable
|
||||
class noncopyable
|
||||
{
|
||||
protected:
|
||||
noncopyable() {}
|
||||
~noncopyable() {}
|
||||
|
||||
private:
|
||||
noncopyable(const noncopyable&);
|
||||
const noncopyable& operator = (const noncopyable&);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
class ostream
|
||||
{
|
||||
public:
|
||||
ostream();
|
||||
~ostream();
|
||||
|
||||
void reserve(unsigned size);
|
||||
void put(char ch);
|
||||
const char *str() const { return m_buffer; }
|
||||
|
||||
unsigned row() const { return m_row; }
|
||||
unsigned col() const { return m_col; }
|
||||
|
||||
private:
|
||||
char *m_buffer;
|
||||
unsigned m_pos;
|
||||
unsigned m_size;
|
||||
|
||||
unsigned m_row, m_col;
|
||||
};
|
||||
|
||||
ostream& operator << (ostream& out, const char *str);
|
||||
ostream& operator << (ostream& out, const std::string& str);
|
||||
ostream& operator << (ostream& out, char ch);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <typename T>
|
||||
inline Emitter& operator << (Emitter& emitter, const std::vector <T>& v) {
|
||||
typedef typename std::vector <T> vec;
|
||||
emitter << BeginSeq;
|
||||
for(typename vec::const_iterator it=v.begin();it!=v.end();++it)
|
||||
emitter << *it;
|
||||
emitter << EndSeq;
|
||||
return emitter;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Emitter& operator << (Emitter& emitter, const std::list <T>& v) {
|
||||
typedef typename std::list <T> list;
|
||||
emitter << BeginSeq;
|
||||
for(typename list::const_iterator it=v.begin();it!=v.end();++it)
|
||||
emitter << *it;
|
||||
emitter << EndSeq;
|
||||
return emitter;
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
inline Emitter& operator << (Emitter& emitter, const std::map <K, V>& m) {
|
||||
typedef typename std::map <K, V> map;
|
||||
emitter << BeginMap;
|
||||
for(typename map::const_iterator it=m.begin();it!=m.end();++it)
|
||||
emitter << Key << it->first << Value << it->second;
|
||||
emitter << EndMap;
|
||||
return emitter;
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -1,7 +1,9 @@
|
||||
set(FILES alias.cpp content.cpp iterator.cpp node.cpp parserstate.cpp
|
||||
scalar.cpp scanscalar.cpp sequence.cpp stream.cpp
|
||||
exp.cpp map.cpp parser.cpp regex.cpp scanner.cpp
|
||||
scantoken.cpp simplekey.cpp)
|
||||
scantoken.cpp simplekey.cpp
|
||||
emitter.cpp emitterstate.h emitterstate.cpp emitterutils.h emitterutils.cpp
|
||||
ostream.cpp)
|
||||
|
||||
include_directories(${YAML_CPP_SOURCE_DIR}/include)
|
||||
add_library(yaml-cpp ${FILES})
|
||||
|
||||
+697
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,263 @@
|
||||
#include "emitterstate.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
EmitterState::EmitterState(): m_isGood(true), m_curIndent(0), m_requiresSeparation(false)
|
||||
{
|
||||
// start up
|
||||
m_stateStack.push(ES_WAITING_FOR_DOC);
|
||||
|
||||
// set default global manipulators
|
||||
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);
|
||||
}
|
||||
|
||||
EmitterState::~EmitterState()
|
||||
{
|
||||
while(!m_groups.empty())
|
||||
_PopGroup();
|
||||
}
|
||||
|
||||
std::auto_ptr <EmitterState::Group> EmitterState::_PopGroup()
|
||||
{
|
||||
if(m_groups.empty())
|
||||
return std::auto_ptr <Group> (0);
|
||||
|
||||
std::auto_ptr <Group> pGroup(m_groups.top());
|
||||
m_groups.pop();
|
||||
return pGroup;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void EmitterState::BeginGroup(GROUP_TYPE type)
|
||||
{
|
||||
unsigned lastIndent = (m_groups.empty() ? 0 : m_groups.top()->indent);
|
||||
m_curIndent += lastIndent;
|
||||
|
||||
std::auto_ptr <Group> pGroup(new Group(type));
|
||||
|
||||
// transfer settings (which last until this group is done)
|
||||
pGroup->modifiedSettings = m_modifiedSettings;
|
||||
|
||||
// set up group
|
||||
pGroup->flow = GetFlowType(type);
|
||||
pGroup->indent = GetIndent();
|
||||
pGroup->usingLongKey = (GetMapKeyFormat() == LongKey ? true : false);
|
||||
|
||||
m_groups.push(pGroup.release());
|
||||
}
|
||||
|
||||
void EmitterState::EndGroup(GROUP_TYPE type)
|
||||
{
|
||||
if(m_groups.empty())
|
||||
return SetError(ErrorMsg::UNMATCHED_GROUP_TAG);
|
||||
|
||||
// get rid of the current group
|
||||
{
|
||||
std::auto_ptr <Group> pFinishedGroup = _PopGroup();
|
||||
if(pFinishedGroup->type != type)
|
||||
return SetError(ErrorMsg::UNMATCHED_GROUP_TAG);
|
||||
}
|
||||
|
||||
// reset old settings
|
||||
unsigned 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();
|
||||
}
|
||||
|
||||
GROUP_TYPE EmitterState::GetCurGroupType() const
|
||||
{
|
||||
if(m_groups.empty())
|
||||
return GT_NONE;
|
||||
|
||||
return m_groups.top()->type;
|
||||
}
|
||||
|
||||
FLOW_TYPE EmitterState::GetCurGroupFlowType() 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;
|
||||
}
|
||||
|
||||
void EmitterState::ClearModifiedSettings()
|
||||
{
|
||||
m_modifiedSettings.clear();
|
||||
}
|
||||
|
||||
bool EmitterState::SetStringFormat(EMITTER_MANIP value, FMT_SCOPE 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, FMT_SCOPE 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, FMT_SCOPE scope)
|
||||
{
|
||||
switch(value) {
|
||||
case LongBool:
|
||||
case ShortBool:
|
||||
_Set(m_boolLengthFmt, value, scope);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetBoolCaseFormat(EMITTER_MANIP value, FMT_SCOPE 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, FMT_SCOPE scope)
|
||||
{
|
||||
switch(value) {
|
||||
case Dec:
|
||||
case Hex:
|
||||
case Oct:
|
||||
_Set(m_intFmt, value, scope);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetIndent(unsigned value, FMT_SCOPE scope)
|
||||
{
|
||||
if(value == 0)
|
||||
return false;
|
||||
|
||||
_Set(m_indent, value, scope);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitterState::SetPreCommentIndent(unsigned value, FMT_SCOPE scope)
|
||||
{
|
||||
if(value == 0)
|
||||
return false;
|
||||
|
||||
_Set(m_preCommentIndent, value, scope);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitterState::SetPostCommentIndent(unsigned value, FMT_SCOPE scope)
|
||||
{
|
||||
if(value == 0)
|
||||
return false;
|
||||
|
||||
_Set(m_postCommentIndent, value, scope);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitterState::SetFlowType(GROUP_TYPE groupType, EMITTER_MANIP value, FMT_SCOPE scope)
|
||||
{
|
||||
switch(value) {
|
||||
case Block:
|
||||
case Flow:
|
||||
_Set(groupType == GT_SEQ ? m_seqFmt : m_mapFmt, value, scope);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
EMITTER_MANIP EmitterState::GetFlowType(GROUP_TYPE groupType) const
|
||||
{
|
||||
// force flow style if we're currently in a flow
|
||||
FLOW_TYPE flowType = GetCurGroupFlowType();
|
||||
if(flowType == FT_FLOW)
|
||||
return Flow;
|
||||
|
||||
// otherwise, go with what's asked of use
|
||||
return (groupType == GT_SEQ ? m_seqFmt.get() : m_mapFmt.get());
|
||||
}
|
||||
|
||||
bool EmitterState::SetMapKeyFormat(EMITTER_MANIP value, FMT_SCOPE scope)
|
||||
{
|
||||
switch(value) {
|
||||
case Auto:
|
||||
case LongKey:
|
||||
_Set(m_mapKeyFmt, value, scope);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
#pragma once
|
||||
|
||||
#include "setting.h"
|
||||
#include "emittermanip.h"
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
class EmitterState
|
||||
{
|
||||
public:
|
||||
EmitterState();
|
||||
~EmitterState();
|
||||
|
||||
// basic state checking
|
||||
bool good() const { return m_isGood; }
|
||||
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();
|
||||
|
||||
bool RequiresSeparation() const { return m_requiresSeparation; }
|
||||
void RequireSeparation() { m_requiresSeparation = true; }
|
||||
void UnsetSeparation() { m_requiresSeparation = false; }
|
||||
|
||||
void ClearModifiedSettings();
|
||||
|
||||
// formatters
|
||||
bool SetStringFormat(EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
EMITTER_MANIP GetStringFormat() const { return m_strFmt.get(); }
|
||||
|
||||
bool SetBoolFormat(EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
EMITTER_MANIP GetBoolFormat() const { return m_boolFmt.get(); }
|
||||
|
||||
bool SetBoolLengthFormat(EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
EMITTER_MANIP GetBoolLengthFormat() const { return m_boolLengthFmt.get(); }
|
||||
|
||||
bool SetBoolCaseFormat(EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
EMITTER_MANIP GetBoolCaseFormat() const { return m_boolCaseFmt.get(); }
|
||||
|
||||
bool SetIntFormat(EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
EMITTER_MANIP GetIntFormat() const { return m_intFmt.get(); }
|
||||
|
||||
bool SetIndent(unsigned value, FMT_SCOPE scope);
|
||||
int GetIndent() const { return m_indent.get(); }
|
||||
|
||||
bool SetPreCommentIndent(unsigned value, FMT_SCOPE scope);
|
||||
int GetPreCommentIndent() const { return m_preCommentIndent.get(); }
|
||||
bool SetPostCommentIndent(unsigned value, FMT_SCOPE 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 SetMapKeyFormat(EMITTER_MANIP value, FMT_SCOPE scope);
|
||||
EMITTER_MANIP GetMapKeyFormat() const { return m_mapKeyFmt.get(); }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void _Set(Setting<T>& fmt, T value, FMT_SCOPE scope);
|
||||
|
||||
private:
|
||||
// basic state ok?
|
||||
bool m_isGood;
|
||||
std::string m_lastError;
|
||||
|
||||
// other state
|
||||
std::stack <EMITTER_STATE> m_stateStack;
|
||||
|
||||
Setting <EMITTER_MANIP> m_strFmt;
|
||||
Setting <EMITTER_MANIP> m_boolFmt;
|
||||
Setting <EMITTER_MANIP> m_boolLengthFmt;
|
||||
Setting <EMITTER_MANIP> m_boolCaseFmt;
|
||||
Setting <EMITTER_MANIP> m_intFmt;
|
||||
Setting <unsigned> m_indent;
|
||||
Setting <unsigned> m_preCommentIndent, m_postCommentIndent;
|
||||
Setting <EMITTER_MANIP> m_seqFmt;
|
||||
Setting <EMITTER_MANIP> m_mapFmt;
|
||||
Setting <EMITTER_MANIP> m_mapKeyFmt;
|
||||
|
||||
SettingChanges m_modifiedSettings;
|
||||
SettingChanges m_globalModifiedSettings;
|
||||
|
||||
struct Group {
|
||||
Group(GROUP_TYPE type_): type(type_), usingLongKey(false), indent(0) {}
|
||||
|
||||
GROUP_TYPE type;
|
||||
EMITTER_MANIP flow;
|
||||
bool usingLongKey;
|
||||
int indent;
|
||||
|
||||
SettingChanges modifiedSettings;
|
||||
};
|
||||
|
||||
std::auto_ptr <Group> _PopGroup();
|
||||
|
||||
std::stack <Group *> m_groups;
|
||||
unsigned m_curIndent;
|
||||
bool m_requiresSeparation;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void EmitterState::_Set(Setting<T>& fmt, T value, FMT_SCOPE scope) {
|
||||
switch(scope) {
|
||||
case LOCAL:
|
||||
m_modifiedSettings.push(fmt.set(value));
|
||||
break;
|
||||
case 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
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
#include "emitterutils.h"
|
||||
#include "exp.h"
|
||||
#include "indentation.h"
|
||||
#include "exceptions.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
namespace Utils
|
||||
{
|
||||
namespace {
|
||||
bool IsPrintable(char ch) {
|
||||
return (0x20 <= ch && ch <= 0x7E);
|
||||
}
|
||||
|
||||
bool IsValidPlainScalar(const std::string& str, bool inFlow) {
|
||||
// first check the start
|
||||
const RegEx& start = (inFlow ? Exp::PlainScalarInFlow : Exp::PlainScalar);
|
||||
if(!start.Matches(str))
|
||||
return false;
|
||||
|
||||
// and check the end for plain whitespace (which can't be faithfully kept in a plain scalar)
|
||||
if(!str.empty() && *str.rbegin() == ' ')
|
||||
return false;
|
||||
|
||||
// then check until something is disallowed
|
||||
const RegEx& disallowed = (inFlow ? Exp::EndScalarInFlow : Exp::EndScalar)
|
||||
|| (Exp::BlankOrBreak + Exp::Comment)
|
||||
|| (!Exp::Printable)
|
||||
|| Exp::Break
|
||||
|| Exp::Tab;
|
||||
Buffer buffer(&str[0], str.size());
|
||||
while(buffer.size) {
|
||||
if(disallowed.Matches(buffer))
|
||||
return false;
|
||||
++buffer;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool WriteString(ostream& out, const std::string& str, bool inFlow)
|
||||
{
|
||||
if(IsValidPlainScalar(str, inFlow)) {
|
||||
out << str;
|
||||
return true;
|
||||
} else
|
||||
return WriteDoubleQuotedString(out, str);
|
||||
}
|
||||
|
||||
bool WriteSingleQuotedString(ostream& out, const std::string& str)
|
||||
{
|
||||
out << "'";
|
||||
for(unsigned i=0;i<str.size();i++) {
|
||||
char ch = str[i];
|
||||
if(!IsPrintable(ch))
|
||||
return false;
|
||||
|
||||
if(ch == '\'')
|
||||
out << "''";
|
||||
else
|
||||
out << ch;
|
||||
}
|
||||
out << "'";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteDoubleQuotedString(ostream& out, const std::string& str)
|
||||
{
|
||||
out << "\"";
|
||||
for(unsigned i=0;i<str.size();i++) {
|
||||
char ch = str[i];
|
||||
if(IsPrintable(ch)) {
|
||||
if(ch == '\"')
|
||||
out << "\\\"";
|
||||
else if(ch == '\\')
|
||||
out << "\\\\";
|
||||
else
|
||||
out << ch;
|
||||
} else {
|
||||
// TODO: for the common escaped characters, give their usual symbol
|
||||
std::stringstream str;
|
||||
str << "\\x" << std::hex << static_cast <int>(ch);
|
||||
out << str.str();
|
||||
}
|
||||
}
|
||||
out << "\"";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteLiteralString(ostream& out, const std::string& str, int indent)
|
||||
{
|
||||
out << "|\n";
|
||||
out << IndentTo(indent);
|
||||
for(unsigned i=0;i<str.size();i++) {
|
||||
if(str[i] == '\n')
|
||||
out << "\n" << IndentTo(indent);
|
||||
else
|
||||
out << str[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteComment(ostream& out, const std::string& str, int postCommentIndent)
|
||||
{
|
||||
unsigned curIndent = out.col();
|
||||
out << "#" << Indentation(postCommentIndent);
|
||||
for(unsigned i=0;i<str.size();i++) {
|
||||
if(str[i] == '\n')
|
||||
out << "\n" << IndentTo(curIndent) << "#" << Indentation(postCommentIndent);
|
||||
else
|
||||
out << str[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteAlias(ostream& out, const std::string& str)
|
||||
{
|
||||
out << "*";
|
||||
for(unsigned i=0;i<str.size();i++) {
|
||||
if(!IsPrintable(str[i]) || str[i] == ' ' || str[i] == '\t' || str[i] == '\n' || str[i] == '\r')
|
||||
return false;
|
||||
|
||||
out << str[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteAnchor(ostream& out, const std::string& str)
|
||||
{
|
||||
out << "&";
|
||||
for(unsigned i=0;i<str.size();i++) {
|
||||
if(!IsPrintable(str[i]) || str[i] == ' ' || str[i] == '\t' || str[i] == '\n' || str[i] == '\r')
|
||||
return false;
|
||||
|
||||
out << str[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "ostream.h"
|
||||
#include <string>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
namespace Utils
|
||||
{
|
||||
bool WriteString(ostream& out, const std::string& str, bool inFlow);
|
||||
bool WriteSingleQuotedString(ostream& out, const std::string& str);
|
||||
bool WriteDoubleQuotedString(ostream& out, const std::string& str);
|
||||
bool WriteLiteralString(ostream& out, const std::string& str, int indent);
|
||||
bool WriteComment(ostream& out, const std::string& str, int postCommentIndent);
|
||||
bool WriteAlias(ostream& out, const std::string& str);
|
||||
bool WriteAnchor(ostream& out, const std::string& str);
|
||||
}
|
||||
}
|
||||
@@ -13,13 +13,16 @@ namespace YAML
|
||||
namespace Exp
|
||||
{
|
||||
// misc
|
||||
const RegEx Blank = RegEx(' ') || RegEx('\t');
|
||||
const RegEx Space = RegEx(' ');
|
||||
const RegEx Tab = RegEx('\t');
|
||||
const RegEx Blank = Space || Tab;
|
||||
const RegEx Break = RegEx('\n') || RegEx("\r\n");
|
||||
const RegEx BlankOrBreak = Blank || Break;
|
||||
const RegEx Digit = RegEx('0', '9');
|
||||
const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z');
|
||||
const RegEx AlphaNumeric = Alpha || Digit;
|
||||
const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f');
|
||||
const RegEx Printable = RegEx(0x20, 0x7E);
|
||||
|
||||
// actual tags
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "ostream.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
struct Indentation {
|
||||
Indentation(unsigned n_): n(n_) {}
|
||||
unsigned n;
|
||||
};
|
||||
|
||||
inline ostream& operator << (ostream& out, const Indentation& indent) {
|
||||
for(unsigned i=0;i<indent.n;i++)
|
||||
out << ' ';
|
||||
return out;
|
||||
}
|
||||
|
||||
struct IndentTo {
|
||||
IndentTo(unsigned n_): n(n_) {}
|
||||
unsigned n;
|
||||
};
|
||||
|
||||
inline ostream& operator << (ostream& out, const IndentTo& indent) {
|
||||
while(out.col() < indent.n)
|
||||
out << ' ';
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "ostream.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
ostream::ostream(): m_buffer(0), m_pos(0), m_size(0), m_row(0), m_col(0)
|
||||
{
|
||||
reserve(1024);
|
||||
}
|
||||
|
||||
ostream::~ostream()
|
||||
{
|
||||
delete [] m_buffer;
|
||||
}
|
||||
|
||||
void ostream::reserve(unsigned size)
|
||||
{
|
||||
if(size <= m_size)
|
||||
return;
|
||||
|
||||
char *newBuffer = new char[size];
|
||||
std::memset(newBuffer, 0, size * sizeof(char));
|
||||
std::memcpy(newBuffer, m_buffer, m_size * sizeof(char));
|
||||
delete [] m_buffer;
|
||||
m_buffer = newBuffer;
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
void ostream::put(char ch)
|
||||
{
|
||||
if(m_pos >= m_size - 1) // an extra space for the NULL terminator
|
||||
reserve(m_size * 2);
|
||||
|
||||
m_buffer[m_pos] = ch;
|
||||
m_pos++;
|
||||
|
||||
if(ch == '\n') {
|
||||
m_row++;
|
||||
m_col = 0;
|
||||
} else
|
||||
m_col++;
|
||||
}
|
||||
|
||||
ostream& operator << (ostream& out, const char *str)
|
||||
{
|
||||
unsigned length = std::strlen(str);
|
||||
for(unsigned i=0;i<length;i++)
|
||||
out.put(str[i]);
|
||||
return out;
|
||||
}
|
||||
|
||||
ostream& operator << (ostream& out, const std::string& str)
|
||||
{
|
||||
out << str.c_str();
|
||||
return out;
|
||||
}
|
||||
|
||||
ostream& operator << (ostream& out, char ch)
|
||||
{
|
||||
out.put(ch);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "noncopyable.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
class SettingChangeBase;
|
||||
|
||||
template <typename T>
|
||||
class Setting
|
||||
{
|
||||
public:
|
||||
Setting(): m_value() {}
|
||||
|
||||
const T get() const { return m_value; }
|
||||
std::auto_ptr <SettingChangeBase> set(const T& value);
|
||||
void restore(const Setting<T>& oldSetting) {
|
||||
m_value = oldSetting.get();
|
||||
}
|
||||
|
||||
private:
|
||||
T m_value;
|
||||
};
|
||||
|
||||
class SettingChangeBase
|
||||
{
|
||||
public:
|
||||
virtual ~SettingChangeBase() {}
|
||||
virtual void pop() = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SettingChange: public SettingChangeBase
|
||||
{
|
||||
public:
|
||||
SettingChange(Setting<T> *pSetting): m_pCurSetting(pSetting) {
|
||||
// copy old setting to save its state
|
||||
m_oldSetting = *pSetting;
|
||||
}
|
||||
|
||||
virtual void pop() {
|
||||
m_pCurSetting->restore(m_oldSetting);
|
||||
}
|
||||
|
||||
private:
|
||||
Setting<T> *m_pCurSetting;
|
||||
Setting<T> m_oldSetting;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline std::auto_ptr <SettingChangeBase> Setting<T>::set(const T& value) {
|
||||
std::auto_ptr <SettingChangeBase> pChange(new SettingChange<T> (this));
|
||||
m_value = value;
|
||||
return pChange;
|
||||
}
|
||||
|
||||
class SettingChanges: private noncopyable
|
||||
{
|
||||
public:
|
||||
SettingChanges() {}
|
||||
~SettingChanges() { clear(); }
|
||||
|
||||
void clear() {
|
||||
restore();
|
||||
|
||||
for(setting_changes::const_iterator it=m_settingChanges.begin();it!=m_settingChanges.end();++it)
|
||||
delete *it;
|
||||
m_settingChanges.clear();
|
||||
}
|
||||
|
||||
void restore() {
|
||||
for(setting_changes::const_iterator it=m_settingChanges.begin();it!=m_settingChanges.end();++it)
|
||||
(*it)->pop();
|
||||
}
|
||||
|
||||
void push(std::auto_ptr <SettingChangeBase> pSettingChange) {
|
||||
m_settingChanges.push_back(pSettingChange.release());
|
||||
}
|
||||
|
||||
// like std::auto_ptr - assignment is transfer of ownership
|
||||
SettingChanges& operator = (SettingChanges& rhs) {
|
||||
if(this == &rhs)
|
||||
return *this;
|
||||
|
||||
clear();
|
||||
m_settingChanges = rhs.m_settingChanges;
|
||||
rhs.m_settingChanges.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::vector <SettingChangeBase *> setting_changes;
|
||||
setting_changes m_settingChanges;
|
||||
};
|
||||
}
|
||||
+3
-2
@@ -7,14 +7,15 @@ namespace YAML
|
||||
{
|
||||
// a simple buffer wrapper that knows how big it is
|
||||
struct Buffer {
|
||||
Buffer(char *b, int s): buffer(b), size(s) {}
|
||||
Buffer(const char *b, int s): buffer(b), size(s) {}
|
||||
|
||||
operator bool() const { return size > 0; }
|
||||
bool operator !() const { return !static_cast <bool> (*this); }
|
||||
char operator [] (int i) const { return buffer[i]; }
|
||||
const Buffer operator + (int offset) const { return Buffer(buffer + offset, size - offset); }
|
||||
Buffer& operator ++ () { ++buffer; --size; return *this; }
|
||||
|
||||
char *buffer;
|
||||
const char *buffer;
|
||||
int size;
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
#include "emitter.h"
|
||||
#include "stlemitter.h"
|
||||
|
||||
void run()
|
||||
{
|
||||
std::ifstream fin("tests/test.yaml");
|
||||
@@ -15,6 +18,9 @@ void run()
|
||||
parser.GetNextDocument(doc);
|
||||
std::cout << doc;
|
||||
}
|
||||
|
||||
// try some output
|
||||
YAML::Emitter out;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,55 @@
|
||||
#include <string>
|
||||
|
||||
namespace YAML { class Emitter; }
|
||||
|
||||
namespace Test {
|
||||
void RunAll(bool verbose);
|
||||
bool Inout(const std::string& file, bool verbose);
|
||||
|
||||
bool RunEmitterTests();
|
||||
|
||||
namespace Emitter {
|
||||
// correct emitting
|
||||
void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void SimpleFlowSeq(YAML::Emitter& ouptut, std::string& desiredOutput);
|
||||
void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void SimpleMap(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void MapAndList(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void ListAndMap(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void MapListMix(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void STLContainers(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void SimpleComment(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void ComplexComments(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void Indentation(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput);
|
||||
void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput);
|
||||
|
||||
// incorrect emitting
|
||||
void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError);
|
||||
void ExtraEndMap(YAML::Emitter& out, std::string& desiredError);
|
||||
void BadSingleQuoted(YAML::Emitter& out, std::string& desiredError);
|
||||
void InvalidAnchor(YAML::Emitter& out, std::string& desiredError);
|
||||
void InvalidAlias(YAML::Emitter& out, std::string& desiredError);
|
||||
void MissingKey(YAML::Emitter& out, std::string& desiredError);
|
||||
void MissingValue(YAML::Emitter& out, std::string& desiredError);
|
||||
void UnexpectedKey(YAML::Emitter& out, std::string& desiredError);
|
||||
void UnexpectedValue(YAML::Emitter& out, std::string& desiredError);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user