mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-09 12:41:17 +00:00
Merged emitter branch into trunk, changes r105:r151
This commit is contained in:
85
include/emitter.h
Normal file
85
include/emitter.h
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
84
include/emittermanip.h
Normal file
84
include/emittermanip.h
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
@@ -8,42 +8,53 @@ namespace YAML
|
|||||||
// error messages
|
// error messages
|
||||||
namespace ErrorMsg
|
namespace ErrorMsg
|
||||||
{
|
{
|
||||||
const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument";
|
const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument";
|
||||||
const std::string YAML_VERSION = "bad YAML version: ";
|
const std::string YAML_VERSION = "bad YAML version: ";
|
||||||
const std::string YAML_MAJOR_VERSION = "YAML major version too large";
|
const std::string YAML_MAJOR_VERSION = "YAML major version too large";
|
||||||
const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments";
|
const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments";
|
||||||
const std::string END_OF_MAP = "end of map not found";
|
const std::string END_OF_MAP = "end of map not found";
|
||||||
const std::string END_OF_MAP_FLOW = "end of map flow not found";
|
const std::string END_OF_MAP_FLOW = "end of map flow not found";
|
||||||
const std::string END_OF_SEQ = "end of sequence not found";
|
const std::string END_OF_SEQ = "end of sequence not found";
|
||||||
const std::string END_OF_SEQ_FLOW = "end of sequence flow not found";
|
const std::string END_OF_SEQ_FLOW = "end of sequence flow not found";
|
||||||
const std::string MULTIPLE_TAGS = "cannot assign multiple tags to the same node";
|
const std::string MULTIPLE_TAGS = "cannot assign multiple tags to the same node";
|
||||||
const std::string MULTIPLE_ANCHORS = "cannot assign multiple anchors to the same node";
|
const std::string MULTIPLE_ANCHORS = "cannot assign multiple anchors to the same node";
|
||||||
const std::string MULTIPLE_ALIASES = "cannot assign multiple aliases to the same node";
|
const std::string MULTIPLE_ALIASES = "cannot assign multiple aliases to the same node";
|
||||||
const std::string ALIAS_CONTENT = "aliases can't have any content, *including* tags";
|
const std::string ALIAS_CONTENT = "aliases can't have any content, *including* tags";
|
||||||
const std::string INVALID_HEX = "bad character found while scanning hex number";
|
const std::string INVALID_HEX = "bad character found while scanning hex number";
|
||||||
const std::string INVALID_UNICODE = "invalid unicode: ";
|
const std::string INVALID_UNICODE = "invalid unicode: ";
|
||||||
const std::string INVALID_ESCAPE = "unknown escape character: ";
|
const std::string INVALID_ESCAPE = "unknown escape character: ";
|
||||||
const std::string UNKNOWN_TOKEN = "unknown token";
|
const std::string UNKNOWN_TOKEN = "unknown token";
|
||||||
const std::string DOC_IN_SCALAR = "illegal document indicator in scalar";
|
const std::string DOC_IN_SCALAR = "illegal document indicator in scalar";
|
||||||
const std::string EOF_IN_SCALAR = "illegal EOF in scalar";
|
const std::string EOF_IN_SCALAR = "illegal EOF in scalar";
|
||||||
const std::string CHAR_IN_SCALAR = "illegal character in scalar";
|
const std::string CHAR_IN_SCALAR = "illegal character in scalar";
|
||||||
const std::string TAB_IN_INDENTATION = "illegal tab when looking for indentation";
|
const std::string TAB_IN_INDENTATION = "illegal tab when looking for indentation";
|
||||||
const std::string FLOW_END = "illegal flow end";
|
const std::string FLOW_END = "illegal flow end";
|
||||||
const std::string BLOCK_ENTRY = "illegal block entry";
|
const std::string BLOCK_ENTRY = "illegal block entry";
|
||||||
const std::string MAP_KEY = "illegal map key";
|
const std::string MAP_KEY = "illegal map key";
|
||||||
const std::string MAP_VALUE = "illegal map value";
|
const std::string MAP_VALUE = "illegal map value";
|
||||||
const std::string ALIAS_NOT_FOUND = "alias not found after *";
|
const std::string ALIAS_NOT_FOUND = "alias not found after *";
|
||||||
const std::string ANCHOR_NOT_FOUND = "anchor not found after &";
|
const std::string ANCHOR_NOT_FOUND = "anchor not found after &";
|
||||||
const std::string CHAR_IN_ALIAS = "illegal character found while scanning alias";
|
const std::string CHAR_IN_ALIAS = "illegal character found while scanning alias";
|
||||||
const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor";
|
const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor";
|
||||||
const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar";
|
const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar";
|
||||||
const std::string CHAR_IN_BLOCK = "unexpected character in block scalar";
|
const std::string CHAR_IN_BLOCK = "unexpected character in block scalar";
|
||||||
const std::string AMBIGUOUS_ANCHOR = "cannot assign the same alias to multiple nodes";
|
const std::string AMBIGUOUS_ANCHOR = "cannot assign the same alias to multiple nodes";
|
||||||
const std::string UNKNOWN_ANCHOR = "the referenced anchor is not defined";
|
const std::string UNKNOWN_ANCHOR = "the referenced anchor is not defined";
|
||||||
|
|
||||||
const std::string INVALID_SCALAR = "invalid scalar";
|
const std::string INVALID_SCALAR = "invalid scalar";
|
||||||
const std::string KEY_NOT_FOUND = "key not found";
|
const std::string KEY_NOT_FOUND = "key not found";
|
||||||
const std::string BAD_DEREFERENCE = "bad dereference";
|
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 {
|
class Exception: public std::exception {
|
||||||
@@ -101,4 +112,10 @@ namespace YAML
|
|||||||
BadDereference()
|
BadDereference()
|
||||||
: RepresentationException(-1, -1, ErrorMsg::BAD_DEREFERENCE) {}
|
: RepresentationException(-1, -1, ErrorMsg::BAD_DEREFERENCE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EmitterException: public Exception {
|
||||||
|
public:
|
||||||
|
EmitterException(const std::string& msg_)
|
||||||
|
: Exception(-1, -1, msg_) {}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
16
include/noncopyable.h
Normal file
16
include/noncopyable.h
Normal file
@@ -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&);
|
||||||
|
};
|
||||||
|
}
|
31
include/ostream.h
Normal file
31
include/ostream.h
Normal file
@@ -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);
|
||||||
|
}
|
38
include/stlemitter.h
Normal file
38
include/stlemitter.h
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,9 @@
|
|||||||
set(FILES alias.cpp content.cpp iterator.cpp node.cpp parserstate.cpp
|
set(FILES alias.cpp content.cpp iterator.cpp node.cpp parserstate.cpp
|
||||||
scalar.cpp scanscalar.cpp sequence.cpp stream.cpp
|
scalar.cpp scanscalar.cpp sequence.cpp stream.cpp
|
||||||
exp.cpp map.cpp parser.cpp regex.cpp scanner.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)
|
include_directories(${YAML_CPP_SOURCE_DIR}/include)
|
||||||
add_library(yaml-cpp ${FILES})
|
add_library(yaml-cpp ${FILES})
|
||||||
|
697
src/emitter.cpp
Normal file
697
src/emitter.cpp
Normal file
@@ -0,0 +1,697 @@
|
|||||||
|
#include "emitter.h"
|
||||||
|
#include "emitterstate.h"
|
||||||
|
#include "emitterutils.h"
|
||||||
|
#include "indentation.h"
|
||||||
|
#include "exceptions.h"
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace YAML
|
||||||
|
{
|
||||||
|
Emitter::Emitter(): m_pState(new EmitterState)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Emitter::~Emitter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Emitter::WriteToStream(std::ostream& out) const
|
||||||
|
{
|
||||||
|
out << m_stream.str();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Emitter::WriteToFile(const std::string& fileName) const
|
||||||
|
{
|
||||||
|
std::ofstream fout(fileName.c_str());
|
||||||
|
if(!fout)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return WriteToStream(fout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// state checking
|
||||||
|
bool Emitter::good() const
|
||||||
|
{
|
||||||
|
return m_pState->good();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string Emitter::GetLastError() const
|
||||||
|
{
|
||||||
|
return m_pState->GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// global setters
|
||||||
|
bool Emitter::SetStringFormat(EMITTER_MANIP value)
|
||||||
|
{
|
||||||
|
return m_pState->SetStringFormat(value, GLOBAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Emitter::SetBoolFormat(EMITTER_MANIP value)
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
if(m_pState->SetBoolFormat(value, GLOBAL))
|
||||||
|
ok = true;
|
||||||
|
if(m_pState->SetBoolCaseFormat(value, GLOBAL))
|
||||||
|
ok = true;
|
||||||
|
if(m_pState->SetBoolLengthFormat(value, GLOBAL))
|
||||||
|
ok = true;
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Emitter::SetIntBase(EMITTER_MANIP value)
|
||||||
|
{
|
||||||
|
return m_pState->SetIntFormat(value, GLOBAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Emitter::SetSeqFormat(EMITTER_MANIP value)
|
||||||
|
{
|
||||||
|
return m_pState->SetFlowType(GT_SEQ, value, GLOBAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Emitter::SetMapFormat(EMITTER_MANIP value)
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
if(m_pState->SetFlowType(GT_MAP, value, GLOBAL))
|
||||||
|
ok = true;
|
||||||
|
if(m_pState->SetMapKeyFormat(value, GLOBAL))
|
||||||
|
ok = true;
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Emitter::SetIndent(unsigned n)
|
||||||
|
{
|
||||||
|
return m_pState->SetIndent(n, GLOBAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Emitter::SetPreCommentIndent(unsigned n)
|
||||||
|
{
|
||||||
|
return m_pState->SetPreCommentIndent(n, GLOBAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Emitter::SetPostCommentIndent(unsigned n)
|
||||||
|
{
|
||||||
|
return m_pState->SetPostCommentIndent(n, GLOBAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLocalValue
|
||||||
|
// . Either start/end a group, or set a modifier locally
|
||||||
|
Emitter& Emitter::SetLocalValue(EMITTER_MANIP value)
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
switch(value) {
|
||||||
|
case BeginSeq:
|
||||||
|
EmitBeginSeq();
|
||||||
|
break;
|
||||||
|
case EndSeq:
|
||||||
|
EmitEndSeq();
|
||||||
|
break;
|
||||||
|
case BeginMap:
|
||||||
|
EmitBeginMap();
|
||||||
|
break;
|
||||||
|
case EndMap:
|
||||||
|
EmitEndMap();
|
||||||
|
break;
|
||||||
|
case Key:
|
||||||
|
EmitKey();
|
||||||
|
break;
|
||||||
|
case Value:
|
||||||
|
EmitValue();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_pState->SetLocalValue(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Emitter& Emitter::SetLocalIndent(const _Indent& indent)
|
||||||
|
{
|
||||||
|
m_pState->SetIndent(indent.value, LOCAL);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GotoNextPreAtomicState
|
||||||
|
// . Runs the state machine, emitting if necessary, and returns 'true' if done (i.e., ready to emit an atom)
|
||||||
|
bool Emitter::GotoNextPreAtomicState()
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
unsigned curIndent = m_pState->GetCurIndent();
|
||||||
|
|
||||||
|
EMITTER_STATE curState = m_pState->GetCurState();
|
||||||
|
switch(curState) {
|
||||||
|
// document-level
|
||||||
|
case ES_WAITING_FOR_DOC:
|
||||||
|
std::cerr << "waiting for doc (pre)\n";
|
||||||
|
m_pState->SwitchState(ES_WRITING_DOC);
|
||||||
|
return true;
|
||||||
|
case ES_WRITING_DOC:
|
||||||
|
std::cerr << "writing doc (pre)\n";
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// block sequence
|
||||||
|
case ES_WAITING_FOR_BLOCK_SEQ_ENTRY:
|
||||||
|
std::cerr << "waiting for block seq entry (pre)\n";
|
||||||
|
m_stream << IndentTo(curIndent) << "-";
|
||||||
|
m_pState->RequireSeparation();
|
||||||
|
m_pState->SwitchState(ES_WRITING_BLOCK_SEQ_ENTRY);
|
||||||
|
return true;
|
||||||
|
case ES_WRITING_BLOCK_SEQ_ENTRY:
|
||||||
|
std::cerr << "writing block seq entry (pre)\n";
|
||||||
|
return true;
|
||||||
|
case ES_DONE_WITH_BLOCK_SEQ_ENTRY:
|
||||||
|
std::cerr << "done with block seq entry (pre)\n";
|
||||||
|
m_stream << '\n';
|
||||||
|
m_pState->SwitchState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY);
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// flow sequence
|
||||||
|
case ES_WAITING_FOR_FLOW_SEQ_ENTRY:
|
||||||
|
std::cerr << "waiting for flow seq entry (pre)\n";
|
||||||
|
m_pState->SwitchState(ES_WRITING_FLOW_SEQ_ENTRY);
|
||||||
|
return true;
|
||||||
|
case ES_WRITING_FLOW_SEQ_ENTRY:
|
||||||
|
std::cerr << "writing flow seq entry (pre)\n";
|
||||||
|
return true;
|
||||||
|
case ES_DONE_WITH_FLOW_SEQ_ENTRY:
|
||||||
|
std::cerr << "done with flow seq entry (pre)\n";
|
||||||
|
m_stream << ',';
|
||||||
|
m_pState->RequireSeparation();
|
||||||
|
m_pState->SwitchState(ES_WAITING_FOR_FLOW_SEQ_ENTRY);
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// block map
|
||||||
|
case ES_WAITING_FOR_BLOCK_MAP_ENTRY:
|
||||||
|
std::cerr << "waiting for block map entry (pre)\n";
|
||||||
|
m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN);
|
||||||
|
return true;
|
||||||
|
case ES_WAITING_FOR_BLOCK_MAP_KEY:
|
||||||
|
std::cerr << "waiting for block map key (pre)\n";
|
||||||
|
if(m_pState->CurrentlyInLongKey()) {
|
||||||
|
m_stream << IndentTo(curIndent) << '?';
|
||||||
|
m_pState->RequireSeparation();
|
||||||
|
}
|
||||||
|
m_pState->SwitchState(ES_WRITING_BLOCK_MAP_KEY);
|
||||||
|
return true;
|
||||||
|
case ES_WRITING_BLOCK_MAP_KEY:
|
||||||
|
std::cerr << "writing block map key (pre)\n";
|
||||||
|
return true;
|
||||||
|
case ES_DONE_WITH_BLOCK_MAP_KEY:
|
||||||
|
std::cerr << "done with block map key (pre)\n";
|
||||||
|
m_pState->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN);
|
||||||
|
return true;
|
||||||
|
case ES_WAITING_FOR_BLOCK_MAP_VALUE:
|
||||||
|
std::cerr << "waiting for block map value (pre)\n";
|
||||||
|
if(m_pState->CurrentlyInLongKey())
|
||||||
|
m_stream << IndentTo(curIndent);
|
||||||
|
m_stream << ':';
|
||||||
|
m_pState->RequireSeparation();
|
||||||
|
m_pState->SwitchState(ES_WRITING_BLOCK_MAP_VALUE);
|
||||||
|
return true;
|
||||||
|
case ES_WRITING_BLOCK_MAP_VALUE:
|
||||||
|
std::cerr << "writing block map value (pre)\n";
|
||||||
|
return true;
|
||||||
|
case ES_DONE_WITH_BLOCK_MAP_VALUE:
|
||||||
|
std::cerr << "done with block map value (pre)\n";
|
||||||
|
m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// flow map
|
||||||
|
case ES_WAITING_FOR_FLOW_MAP_ENTRY:
|
||||||
|
std::cerr << "waiting for flow map entry (pre)\n";
|
||||||
|
m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN);
|
||||||
|
return true;
|
||||||
|
case ES_WAITING_FOR_FLOW_MAP_KEY:
|
||||||
|
std::cerr << "waiting for flow map key (pre)\n";
|
||||||
|
m_pState->SwitchState(ES_WRITING_FLOW_MAP_KEY);
|
||||||
|
if(m_pState->CurrentlyInLongKey()) {
|
||||||
|
EmitSeparationIfNecessary();
|
||||||
|
m_stream << '?';
|
||||||
|
m_pState->RequireSeparation();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case ES_WRITING_FLOW_MAP_KEY:
|
||||||
|
std::cerr << "writing flow map key (pre)\n";
|
||||||
|
return true;
|
||||||
|
case ES_DONE_WITH_FLOW_MAP_KEY:
|
||||||
|
std::cerr << "done with flow map key (pre)\n";
|
||||||
|
m_pState->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN);
|
||||||
|
return true;
|
||||||
|
case ES_WAITING_FOR_FLOW_MAP_VALUE:
|
||||||
|
std::cerr << "waiting for flow map value (pre)\n";
|
||||||
|
m_stream << ':';
|
||||||
|
m_pState->RequireSeparation();
|
||||||
|
m_pState->SwitchState(ES_WRITING_FLOW_MAP_VALUE);
|
||||||
|
return true;
|
||||||
|
case ES_WRITING_FLOW_MAP_VALUE:
|
||||||
|
std::cerr << "writing flow map value (pre)\n";
|
||||||
|
return true;
|
||||||
|
case ES_DONE_WITH_FLOW_MAP_VALUE:
|
||||||
|
std::cerr << "done with flow map value (pre)\n";
|
||||||
|
m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN);
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreAtomicWrite
|
||||||
|
// . Depending on the emitter state, write to the stream to get it
|
||||||
|
// in position to do an atomic write (e.g., scalar, sequence, or map)
|
||||||
|
void Emitter::PreAtomicWrite()
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return;
|
||||||
|
|
||||||
|
while(!GotoNextPreAtomicState())
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostAtomicWrite
|
||||||
|
// . Clean up
|
||||||
|
void Emitter::PostAtomicWrite()
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return;
|
||||||
|
|
||||||
|
EMITTER_STATE curState = m_pState->GetCurState();
|
||||||
|
switch(curState) {
|
||||||
|
// document-level
|
||||||
|
case ES_WRITING_DOC:
|
||||||
|
m_pState->SwitchState(ES_DONE_WITH_DOC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// block seq
|
||||||
|
case ES_WRITING_BLOCK_SEQ_ENTRY:
|
||||||
|
m_pState->SwitchState(ES_DONE_WITH_BLOCK_SEQ_ENTRY);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// flow seq
|
||||||
|
case ES_WRITING_FLOW_SEQ_ENTRY:
|
||||||
|
m_pState->SwitchState(ES_DONE_WITH_FLOW_SEQ_ENTRY);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// block map
|
||||||
|
case ES_WRITING_BLOCK_MAP_KEY:
|
||||||
|
m_pState->SwitchState(ES_DONE_WITH_BLOCK_MAP_KEY);
|
||||||
|
break;
|
||||||
|
case ES_WRITING_BLOCK_MAP_VALUE:
|
||||||
|
m_pState->SwitchState(ES_DONE_WITH_BLOCK_MAP_VALUE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// flow map
|
||||||
|
case ES_WRITING_FLOW_MAP_KEY:
|
||||||
|
m_pState->SwitchState(ES_DONE_WITH_FLOW_MAP_KEY);
|
||||||
|
break;
|
||||||
|
case ES_WRITING_FLOW_MAP_VALUE:
|
||||||
|
m_pState->SwitchState(ES_DONE_WITH_FLOW_MAP_VALUE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
m_pState->ClearModifiedSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmitSeparationIfNecessary
|
||||||
|
void Emitter::EmitSeparationIfNecessary()
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(m_pState->RequiresSeparation())
|
||||||
|
m_stream << ' ';
|
||||||
|
m_pState->UnsetSeparation();
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmitBeginSeq
|
||||||
|
void Emitter::EmitBeginSeq()
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// must have a long key if we're emitting a sequence
|
||||||
|
m_pState->StartLongKey();
|
||||||
|
|
||||||
|
PreAtomicWrite();
|
||||||
|
|
||||||
|
EMITTER_STATE curState = m_pState->GetCurState();
|
||||||
|
EMITTER_MANIP flowType = m_pState->GetFlowType(GT_SEQ);
|
||||||
|
if(flowType == Block) {
|
||||||
|
if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE) {
|
||||||
|
m_stream << "\n";
|
||||||
|
m_pState->UnsetSeparation();
|
||||||
|
}
|
||||||
|
m_pState->PushState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY);
|
||||||
|
} else if(flowType == Flow) {
|
||||||
|
EmitSeparationIfNecessary();
|
||||||
|
m_stream << "[";
|
||||||
|
m_pState->PushState(ES_WAITING_FOR_FLOW_SEQ_ENTRY);
|
||||||
|
} else
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
m_pState->BeginGroup(GT_SEQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmitEndSeq
|
||||||
|
void Emitter::EmitEndSeq()
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(m_pState->GetCurGroupType() != GT_SEQ)
|
||||||
|
return m_pState->SetError(ErrorMsg::UNEXPECTED_END_SEQ);
|
||||||
|
|
||||||
|
EMITTER_STATE curState = m_pState->GetCurState();
|
||||||
|
FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
|
||||||
|
if(flowType == FT_BLOCK)
|
||||||
|
assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY);
|
||||||
|
else if(flowType == FT_FLOW) {
|
||||||
|
m_stream << "]";
|
||||||
|
// Note: flow sequences are allowed to be empty
|
||||||
|
assert(curState == ES_DONE_WITH_FLOW_SEQ_ENTRY || curState == ES_WAITING_FOR_FLOW_SEQ_ENTRY);
|
||||||
|
} else
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
m_pState->PopState();
|
||||||
|
m_pState->EndGroup(GT_SEQ);
|
||||||
|
|
||||||
|
PostAtomicWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmitBeginMap
|
||||||
|
void Emitter::EmitBeginMap()
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// must have a long key if we're emitting a map
|
||||||
|
m_pState->StartLongKey();
|
||||||
|
|
||||||
|
PreAtomicWrite();
|
||||||
|
|
||||||
|
EMITTER_STATE curState = m_pState->GetCurState();
|
||||||
|
EMITTER_MANIP flowType = m_pState->GetFlowType(GT_MAP);
|
||||||
|
if(flowType == Block) {
|
||||||
|
if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE) {
|
||||||
|
m_stream << "\n";
|
||||||
|
m_pState->UnsetSeparation();
|
||||||
|
}
|
||||||
|
m_pState->PushState(ES_WAITING_FOR_BLOCK_MAP_ENTRY);
|
||||||
|
} else if(flowType == Flow) {
|
||||||
|
EmitSeparationIfNecessary();
|
||||||
|
m_stream << "{";
|
||||||
|
m_pState->PushState(ES_WAITING_FOR_FLOW_MAP_ENTRY);
|
||||||
|
} else
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
m_pState->BeginGroup(GT_MAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmitEndMap
|
||||||
|
void Emitter::EmitEndMap()
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(m_pState->GetCurGroupType() != GT_MAP)
|
||||||
|
return m_pState->SetError(ErrorMsg::UNEXPECTED_END_MAP);
|
||||||
|
|
||||||
|
EMITTER_STATE curState = m_pState->GetCurState();
|
||||||
|
FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
|
||||||
|
if(flowType == FT_BLOCK)
|
||||||
|
assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE);
|
||||||
|
else if(flowType == FT_FLOW) {
|
||||||
|
m_stream << "}";
|
||||||
|
// Note: flow maps are allowed to be empty
|
||||||
|
assert(curState == ES_DONE_WITH_FLOW_MAP_VALUE || curState == ES_WAITING_FOR_FLOW_MAP_ENTRY);
|
||||||
|
} else
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
m_pState->PopState();
|
||||||
|
m_pState->EndGroup(GT_MAP);
|
||||||
|
|
||||||
|
PostAtomicWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmitKey
|
||||||
|
void Emitter::EmitKey()
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return;
|
||||||
|
|
||||||
|
EMITTER_STATE curState = m_pState->GetCurState();
|
||||||
|
FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
|
||||||
|
if(curState != ES_WAITING_FOR_BLOCK_MAP_ENTRY && curState != ES_DONE_WITH_BLOCK_MAP_VALUE
|
||||||
|
&& curState != ES_WAITING_FOR_FLOW_MAP_ENTRY && curState != ES_DONE_WITH_FLOW_MAP_VALUE)
|
||||||
|
return m_pState->SetError(ErrorMsg::UNEXPECTED_KEY_TOKEN);
|
||||||
|
|
||||||
|
if(flowType == FT_BLOCK) {
|
||||||
|
if(curState == ES_DONE_WITH_BLOCK_MAP_VALUE)
|
||||||
|
m_stream << '\n';
|
||||||
|
unsigned curIndent = m_pState->GetCurIndent();
|
||||||
|
m_stream << IndentTo(curIndent);
|
||||||
|
m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_KEY);
|
||||||
|
} else if(flowType == FT_FLOW) {
|
||||||
|
if(curState == ES_DONE_WITH_FLOW_MAP_VALUE) {
|
||||||
|
m_stream << ',';
|
||||||
|
m_pState->RequireSeparation();
|
||||||
|
}
|
||||||
|
m_pState->SwitchState(ES_WAITING_FOR_FLOW_MAP_KEY);
|
||||||
|
} else
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
if(m_pState->GetMapKeyFormat() == LongKey)
|
||||||
|
m_pState->StartLongKey();
|
||||||
|
else if(m_pState->GetMapKeyFormat() == Auto)
|
||||||
|
m_pState->StartSimpleKey();
|
||||||
|
else
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmitValue
|
||||||
|
void Emitter::EmitValue()
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return;
|
||||||
|
|
||||||
|
EMITTER_STATE curState = m_pState->GetCurState();
|
||||||
|
FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
|
||||||
|
if(curState != ES_DONE_WITH_BLOCK_MAP_KEY && curState != ES_DONE_WITH_FLOW_MAP_KEY)
|
||||||
|
return m_pState->SetError(ErrorMsg::UNEXPECTED_VALUE_TOKEN);
|
||||||
|
|
||||||
|
if(flowType == FT_BLOCK) {
|
||||||
|
if(m_pState->CurrentlyInLongKey())
|
||||||
|
m_stream << '\n';
|
||||||
|
m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_VALUE);
|
||||||
|
} else if(flowType == FT_FLOW) {
|
||||||
|
m_pState->SwitchState(ES_WAITING_FOR_FLOW_MAP_VALUE);
|
||||||
|
} else
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// *******************************************************************************************
|
||||||
|
// overloads of Write
|
||||||
|
|
||||||
|
Emitter& Emitter::Write(const std::string& str)
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
// literal scalars must use long keys
|
||||||
|
if(m_pState->GetStringFormat() == Literal && m_pState->GetCurGroupFlowType() != FT_FLOW)
|
||||||
|
m_pState->StartLongKey();
|
||||||
|
|
||||||
|
PreAtomicWrite();
|
||||||
|
EmitSeparationIfNecessary();
|
||||||
|
|
||||||
|
EMITTER_MANIP strFmt = m_pState->GetStringFormat();
|
||||||
|
FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
|
||||||
|
unsigned curIndent = m_pState->GetCurIndent();
|
||||||
|
|
||||||
|
switch(strFmt) {
|
||||||
|
case Auto:
|
||||||
|
Utils::WriteString(m_stream, str, flowType == FT_FLOW);
|
||||||
|
break;
|
||||||
|
case SingleQuoted:
|
||||||
|
if(!Utils::WriteSingleQuotedString(m_stream, str)) {
|
||||||
|
m_pState->SetError(ErrorMsg::SINGLE_QUOTED_CHAR);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DoubleQuoted:
|
||||||
|
Utils::WriteDoubleQuotedString(m_stream, str);
|
||||||
|
break;
|
||||||
|
case Literal:
|
||||||
|
if(flowType == FT_FLOW)
|
||||||
|
Utils::WriteString(m_stream, str, flowType == FT_FLOW);
|
||||||
|
else
|
||||||
|
Utils::WriteLiteralString(m_stream, str, curIndent + m_pState->GetIndent());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
PostAtomicWrite();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Emitter& Emitter::Write(const char *str)
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
return Write(std::string(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
Emitter& Emitter::Write(int i)
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
PreAtomicWrite();
|
||||||
|
EmitSeparationIfNecessary();
|
||||||
|
|
||||||
|
EMITTER_MANIP intFmt = m_pState->GetIntFormat();
|
||||||
|
std::stringstream str;
|
||||||
|
switch(intFmt) {
|
||||||
|
case Dec:
|
||||||
|
str << std::dec;
|
||||||
|
break;
|
||||||
|
case Hex:
|
||||||
|
str << std::hex;
|
||||||
|
break;
|
||||||
|
case Oct:
|
||||||
|
str << std::oct;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
str << i;
|
||||||
|
m_stream << str.str();
|
||||||
|
|
||||||
|
PostAtomicWrite();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Emitter& Emitter::Write(bool b)
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
PreAtomicWrite();
|
||||||
|
EmitSeparationIfNecessary();
|
||||||
|
|
||||||
|
// set up all possible bools to write
|
||||||
|
struct BoolName { std::string trueName, falseName; };
|
||||||
|
struct BoolFormatNames { BoolName upper, lower, camel; };
|
||||||
|
struct BoolTypes { BoolFormatNames yesNo, trueFalse, onOff; };
|
||||||
|
|
||||||
|
static const BoolTypes boolTypes = {
|
||||||
|
{ { "YES", "NO" }, { "yes", "no" }, { "Yes", "No" } },
|
||||||
|
{ { "TRUE", "FALSE" }, { "true", "false" }, { "True", "False" } },
|
||||||
|
{ { "ON", "OFF" }, { "on", "off" }, { "On", "Off" } }
|
||||||
|
};
|
||||||
|
|
||||||
|
// select the right one
|
||||||
|
EMITTER_MANIP boolFmt = m_pState->GetBoolFormat();
|
||||||
|
EMITTER_MANIP boolLengthFmt = m_pState->GetBoolLengthFormat();
|
||||||
|
EMITTER_MANIP boolCaseFmt = m_pState->GetBoolCaseFormat();
|
||||||
|
|
||||||
|
const BoolFormatNames& fmtNames = (boolFmt == YesNoBool ? boolTypes.yesNo : boolFmt == TrueFalseBool ? boolTypes.trueFalse : boolTypes.onOff);
|
||||||
|
const BoolName& boolName = (boolCaseFmt == UpperCase ? fmtNames.upper : boolCaseFmt == LowerCase ? fmtNames.lower : fmtNames.camel);
|
||||||
|
const std::string& name = (b ? boolName.trueName : boolName.falseName);
|
||||||
|
|
||||||
|
// and say it!
|
||||||
|
// TODO: should we disallow writing OnOffBool with ShortBool? (it'll just print "o" for both, which is silly)
|
||||||
|
if(boolLengthFmt == ShortBool)
|
||||||
|
m_stream << name[0];
|
||||||
|
else
|
||||||
|
m_stream << name;
|
||||||
|
|
||||||
|
PostAtomicWrite();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Emitter& Emitter::Write(float f)
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
PreAtomicWrite();
|
||||||
|
EmitSeparationIfNecessary();
|
||||||
|
|
||||||
|
std::stringstream str;
|
||||||
|
str << f;
|
||||||
|
m_stream << str.str();
|
||||||
|
|
||||||
|
PostAtomicWrite();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Emitter& Emitter::Write(double d)
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
PreAtomicWrite();
|
||||||
|
EmitSeparationIfNecessary();
|
||||||
|
|
||||||
|
std::stringstream str;
|
||||||
|
str << d;
|
||||||
|
m_stream << str.str();
|
||||||
|
|
||||||
|
PostAtomicWrite();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Emitter& Emitter::Write(const _Alias& alias)
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
PreAtomicWrite();
|
||||||
|
EmitSeparationIfNecessary();
|
||||||
|
if(!Utils::WriteAlias(m_stream, alias.content)) {
|
||||||
|
m_pState->SetError(ErrorMsg::INVALID_ALIAS);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
PostAtomicWrite();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Emitter& Emitter::Write(const _Anchor& anchor)
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
PreAtomicWrite();
|
||||||
|
EmitSeparationIfNecessary();
|
||||||
|
if(!Utils::WriteAnchor(m_stream, anchor.content)) {
|
||||||
|
m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
m_pState->RequireSeparation();
|
||||||
|
// Note: no PostAtomicWrite() because we need another value for this node
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Emitter& Emitter::Write(const _Comment& comment)
|
||||||
|
{
|
||||||
|
if(!good())
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
m_stream << Indentation(m_pState->GetPreCommentIndent());
|
||||||
|
Utils::WriteComment(m_stream, comment.content, m_pState->GetPostCommentIndent());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
}
|
263
src/emitterstate.cpp
Normal file
263
src/emitterstate.cpp
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
195
src/emitterstate.h
Normal file
195
src/emitterstate.h
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
143
src/emitterutils.cpp
Normal file
143
src/emitterutils.cpp
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
18
src/emitterutils.h
Normal file
18
src/emitterutils.h
Normal file
@@ -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
|
namespace Exp
|
||||||
{
|
{
|
||||||
// misc
|
// 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 Break = RegEx('\n') || RegEx("\r\n");
|
||||||
const RegEx BlankOrBreak = Blank || Break;
|
const RegEx BlankOrBreak = Blank || Break;
|
||||||
const RegEx Digit = RegEx('0', '9');
|
const RegEx Digit = RegEx('0', '9');
|
||||||
const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z');
|
const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z');
|
||||||
const RegEx AlphaNumeric = Alpha || Digit;
|
const RegEx AlphaNumeric = Alpha || Digit;
|
||||||
const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f');
|
const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f');
|
||||||
|
const RegEx Printable = RegEx(0x20, 0x7E);
|
||||||
|
|
||||||
// actual tags
|
// actual tags
|
||||||
|
|
||||||
|
30
src/indentation.h
Normal file
30
src/indentation.h
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
63
src/ostream.cpp
Normal file
63
src/ostream.cpp
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
97
src/setting.h
Normal file
97
src/setting.h
Normal file
@@ -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;
|
||||||
|
};
|
||||||
|
}
|
@@ -7,14 +7,15 @@ namespace YAML
|
|||||||
{
|
{
|
||||||
// a simple buffer wrapper that knows how big it is
|
// a simple buffer wrapper that knows how big it is
|
||||||
struct Buffer {
|
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; }
|
operator bool() const { return size > 0; }
|
||||||
bool operator !() const { return !static_cast <bool> (*this); }
|
bool operator !() const { return !static_cast <bool> (*this); }
|
||||||
char operator [] (int i) const { return buffer[i]; }
|
char operator [] (int i) const { return buffer[i]; }
|
||||||
const Buffer operator + (int offset) const { return Buffer(buffer + offset, size - offset); }
|
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;
|
int size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -4,6 +4,9 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "emitter.h"
|
||||||
|
#include "stlemitter.h"
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
std::ifstream fin("tests/test.yaml");
|
std::ifstream fin("tests/test.yaml");
|
||||||
@@ -15,6 +18,9 @@ void run()
|
|||||||
parser.GetNextDocument(doc);
|
parser.GetNextDocument(doc);
|
||||||
std::cout << doc;
|
std::cout << doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// try some output
|
||||||
|
YAML::Emitter out;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
#include "yaml.h"
|
#include "yaml.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "emitter.h"
|
||||||
|
#include "stlemitter.h"
|
||||||
|
#include "exceptions.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -26,6 +29,9 @@ namespace Test
|
|||||||
} else
|
} else
|
||||||
std::cout << "Inout test passed: " << files[i] << "\n";
|
std::cout << "Inout test passed: " << files[i] << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!RunEmitterTests())
|
||||||
|
passed = false;
|
||||||
|
|
||||||
if(passed)
|
if(passed)
|
||||||
std::cout << "All tests passed!\n";
|
std::cout << "All tests passed!\n";
|
||||||
@@ -86,4 +92,601 @@ namespace Test
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Emitter tests
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void RunTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, bool& passed) {
|
||||||
|
YAML::Emitter out;
|
||||||
|
std::string desiredOutput;
|
||||||
|
test(out, desiredOutput);
|
||||||
|
std::stringstream output;
|
||||||
|
out.WriteToStream(output);
|
||||||
|
|
||||||
|
if(output.str() == desiredOutput) {
|
||||||
|
std::cout << "Test passed: " << name << "\n";
|
||||||
|
} else {
|
||||||
|
passed = false;
|
||||||
|
std::cout << "Test failed: " << name << "\n";
|
||||||
|
std::cout << "Output:\n";
|
||||||
|
std::cout << output.str() << "<<<\n";
|
||||||
|
std::cout << "Desired output:\n";
|
||||||
|
std::cout << desiredOutput << "<<<\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunErrorTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, bool& passed) {
|
||||||
|
YAML::Emitter out;
|
||||||
|
std::string desiredError;
|
||||||
|
test(out, desiredError);
|
||||||
|
std::string lastError = out.GetLastError();
|
||||||
|
if(!out.good() && lastError == desiredError) {
|
||||||
|
std::cout << "Test passed: " << name << "\n";
|
||||||
|
} else {
|
||||||
|
passed = false;
|
||||||
|
std::cout << "Test failed: " << name << "\n";
|
||||||
|
if(out.good())
|
||||||
|
std::cout << "No error detected\n";
|
||||||
|
else
|
||||||
|
std::cout << "Detected error: " << lastError << "\n";
|
||||||
|
std::cout << "Expected error: " << desiredError << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RunEmitterTests()
|
||||||
|
{
|
||||||
|
bool passed = true;
|
||||||
|
RunTest(&Emitter::SimpleScalar, "simple scalar", passed);
|
||||||
|
RunTest(&Emitter::SimpleSeq, "simple seq", passed);
|
||||||
|
RunTest(&Emitter::SimpleFlowSeq, "simple flow seq", passed);
|
||||||
|
RunTest(&Emitter::EmptyFlowSeq, "empty flow seq", passed);
|
||||||
|
RunTest(&Emitter::NestedBlockSeq, "nested block seq", passed);
|
||||||
|
RunTest(&Emitter::NestedFlowSeq, "nested flow seq", passed);
|
||||||
|
RunTest(&Emitter::SimpleMap, "simple map", passed);
|
||||||
|
RunTest(&Emitter::SimpleFlowMap, "simple flow map", passed);
|
||||||
|
RunTest(&Emitter::MapAndList, "map and list", passed);
|
||||||
|
RunTest(&Emitter::ListAndMap, "list and map", passed);
|
||||||
|
RunTest(&Emitter::NestedBlockMap, "nested block map", passed);
|
||||||
|
RunTest(&Emitter::NestedFlowMap, "nested flow map", passed);
|
||||||
|
RunTest(&Emitter::MapListMix, "map list mix", passed);
|
||||||
|
RunTest(&Emitter::SimpleLongKey, "simple long key", passed);
|
||||||
|
RunTest(&Emitter::SingleLongKey, "single long key", passed);
|
||||||
|
RunTest(&Emitter::ComplexLongKey, "complex long key", passed);
|
||||||
|
RunTest(&Emitter::AutoLongKey, "auto long key", passed);
|
||||||
|
RunTest(&Emitter::ScalarFormat, "scalar format", passed);
|
||||||
|
RunTest(&Emitter::AutoLongKeyScalar, "auto long key scalar", passed);
|
||||||
|
RunTest(&Emitter::LongKeyFlowMap, "long key flow map", passed);
|
||||||
|
RunTest(&Emitter::BlockMapAsKey, "block map as key", passed);
|
||||||
|
RunTest(&Emitter::AliasAndAnchor, "alias and anchor", passed);
|
||||||
|
RunTest(&Emitter::ComplexDoc, "complex doc", passed);
|
||||||
|
RunTest(&Emitter::STLContainers, "STL containers", passed);
|
||||||
|
RunTest(&Emitter::SimpleComment, "simple comment", passed);
|
||||||
|
RunTest(&Emitter::MultiLineComment, "multi-line comment", passed);
|
||||||
|
RunTest(&Emitter::ComplexComments, "complex comments", passed);
|
||||||
|
RunTest(&Emitter::Indentation, "indentation", passed);
|
||||||
|
RunTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed);
|
||||||
|
RunTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed);
|
||||||
|
|
||||||
|
RunErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed);
|
||||||
|
RunErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed);
|
||||||
|
RunErrorTest(&Emitter::BadSingleQuoted, "bad single quoted string", passed);
|
||||||
|
RunErrorTest(&Emitter::InvalidAnchor, "invalid anchor", passed);
|
||||||
|
RunErrorTest(&Emitter::InvalidAlias, "invalid alias", passed);
|
||||||
|
RunErrorTest(&Emitter::MissingKey, "missing key", passed);
|
||||||
|
RunErrorTest(&Emitter::MissingValue, "missing value", passed);
|
||||||
|
RunErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed);
|
||||||
|
RunErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed);
|
||||||
|
return passed;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Emitter {
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// correct emitting
|
||||||
|
|
||||||
|
void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput) {
|
||||||
|
out << "Hello, World!";
|
||||||
|
desiredOutput = "Hello, World!";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput) {
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << "eggs";
|
||||||
|
out << "bread";
|
||||||
|
out << "milk";
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "- eggs\n- bread\n- milk";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleFlowSeq(YAML::Emitter& out, std::string& desiredOutput) {
|
||||||
|
out << YAML::Flow;
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << "Larry";
|
||||||
|
out << "Curly";
|
||||||
|
out << "Moe";
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "[Larry, Curly, Moe]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput) {
|
||||||
|
out << YAML::Flow;
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "[]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput) {
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << "item 1";
|
||||||
|
out << YAML::BeginSeq << "subitem 1" << "subitem 2" << YAML::EndSeq;
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "- item 1\n-\n - subitem 1\n - subitem 2";
|
||||||
|
}
|
||||||
|
|
||||||
|
void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput) {
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << "one";
|
||||||
|
out << YAML::Flow << YAML::BeginSeq << "two" << "three" << YAML::EndSeq;
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "- one\n- [two, three]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleMap(YAML::Emitter& out, std::string& desiredOutput) {
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "name";
|
||||||
|
out << YAML::Value << "Ryan Braun";
|
||||||
|
out << YAML::Key << "position";
|
||||||
|
out << YAML::Value << "3B";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "name: Ryan Braun\nposition: 3B";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput) {
|
||||||
|
out << YAML::Flow;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "shape";
|
||||||
|
out << YAML::Value << "square";
|
||||||
|
out << YAML::Key << "color";
|
||||||
|
out << YAML::Value << "blue";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "{shape: square, color: blue}";
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapAndList(YAML::Emitter& out, std::string& desiredOutput) {
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "name";
|
||||||
|
out << YAML::Value << "Barack Obama";
|
||||||
|
out << YAML::Key << "children";
|
||||||
|
out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "name: Barack Obama\nchildren:\n - Sasha\n - Malia";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListAndMap(YAML::Emitter& out, std::string& desiredOutput) {
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << "item 1";
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "pens" << YAML::Value << 8;
|
||||||
|
out << YAML::Key << "pencils" << YAML::Value << 14;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << "item 2";
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "- item 1\n-\n pens: 8\n pencils: 14\n- item 2";
|
||||||
|
}
|
||||||
|
|
||||||
|
void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) {
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "name";
|
||||||
|
out << YAML::Value << "Fred";
|
||||||
|
out << YAML::Key << "grades";
|
||||||
|
out << YAML::Value;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "algebra" << YAML::Value << "A";
|
||||||
|
out << YAML::Key << "physics" << YAML::Value << "C+";
|
||||||
|
out << YAML::Key << "literature" << YAML::Value << "B";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "name: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B";
|
||||||
|
}
|
||||||
|
|
||||||
|
void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput) {
|
||||||
|
out << YAML::Flow;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "name";
|
||||||
|
out << YAML::Value << "Fred";
|
||||||
|
out << YAML::Key << "grades";
|
||||||
|
out << YAML::Value;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "algebra" << YAML::Value << "A";
|
||||||
|
out << YAML::Key << "physics" << YAML::Value << "C+";
|
||||||
|
out << YAML::Key << "literature" << YAML::Value << "B";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "{name: Fred, grades: {algebra: A, physics: C+, literature: B}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapListMix(YAML::Emitter& out, std::string& desiredOutput) {
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "name";
|
||||||
|
out << YAML::Value << "Bob";
|
||||||
|
out << YAML::Key << "position";
|
||||||
|
out << YAML::Value;
|
||||||
|
out << YAML::Flow << YAML::BeginSeq << 2 << 4 << YAML::EndSeq;
|
||||||
|
out << YAML::Key << "invincible" << YAML::Value << YAML::OnOffBool << false;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "name: Bob\nposition: [2, 4]\ninvincible: off";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::LongKey;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "height";
|
||||||
|
out << YAML::Value << "5'9\"";
|
||||||
|
out << YAML::Key << "weight";
|
||||||
|
out << YAML::Value << 145;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "? height\n: 5'9\"\n? weight\n: 145";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "age";
|
||||||
|
out << YAML::Value << "24";
|
||||||
|
out << YAML::LongKey << YAML::Key << "height";
|
||||||
|
out << YAML::Value << "5'9\"";
|
||||||
|
out << YAML::Key << "weight";
|
||||||
|
out << YAML::Value << 145;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "age: 24\n? height\n: 5'9\"\nweight: 145";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::LongKey;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq;
|
||||||
|
out << YAML::Value << "monster";
|
||||||
|
out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq;
|
||||||
|
out << YAML::Value << "demon";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon";
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq;
|
||||||
|
out << YAML::Value << "monster";
|
||||||
|
out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq;
|
||||||
|
out << YAML::Value << "demon";
|
||||||
|
out << YAML::Key << "the origin";
|
||||||
|
out << YAML::Value << "angel";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << "simple scalar";
|
||||||
|
out << YAML::SingleQuoted << "explicit single-quoted scalar";
|
||||||
|
out << YAML::DoubleQuoted << "explicit double-quoted scalar";
|
||||||
|
out << "auto-detected\ndouble-quoted scalar";
|
||||||
|
out << "a non-\"auto-detected\" double-quoted scalar";
|
||||||
|
out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like";
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\xadouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like";
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << YAML::Literal << "multi-line\nscalar";
|
||||||
|
out << YAML::Value << "and its value";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "? |\n multi-line\n scalar\n: and its value";
|
||||||
|
}
|
||||||
|
|
||||||
|
void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::Flow;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "simple key";
|
||||||
|
out << YAML::Value << "and value";
|
||||||
|
out << YAML::LongKey << YAML::Key << "long key";
|
||||||
|
out << YAML::Value << "and its value";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "{simple key: and value, ? long key: and its value}";
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "key" << YAML::Value << "value";
|
||||||
|
out << YAML::Key << "next key" << YAML::Value << "next value";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::Value;
|
||||||
|
out << "total value";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "?\n key: value\n next key: next value\n: total value";
|
||||||
|
}
|
||||||
|
|
||||||
|
void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << YAML::Anchor("fred");
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "name" << YAML::Value << "Fred";
|
||||||
|
out << YAML::Key << "age" << YAML::Value << 42;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::Alias("fred");
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "- &fred\n name: Fred\n age: 42\n- *fred";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "receipt";
|
||||||
|
out << YAML::Value << "Oz-Ware Purchase Invoice";
|
||||||
|
out << YAML::Key << "date";
|
||||||
|
out << YAML::Value << "2007-08-06";
|
||||||
|
out << YAML::Key << "customer";
|
||||||
|
out << YAML::Value;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "given";
|
||||||
|
out << YAML::Value << "Dorothy";
|
||||||
|
out << YAML::Key << "family";
|
||||||
|
out << YAML::Value << "Gale";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::Key << "items";
|
||||||
|
out << YAML::Value;
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "part_no";
|
||||||
|
out << YAML::Value << "A4786";
|
||||||
|
out << YAML::Key << "descrip";
|
||||||
|
out << YAML::Value << "Water Bucket (Filled)";
|
||||||
|
out << YAML::Key << "price";
|
||||||
|
out << YAML::Value << 1.47;
|
||||||
|
out << YAML::Key << "quantity";
|
||||||
|
out << YAML::Value << 4;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "part_no";
|
||||||
|
out << YAML::Value << "E1628";
|
||||||
|
out << YAML::Key << "descrip";
|
||||||
|
out << YAML::Value << "High Heeled \"Ruby\" Slippers";
|
||||||
|
out << YAML::Key << "price";
|
||||||
|
out << YAML::Value << 100.27;
|
||||||
|
out << YAML::Key << "quantity";
|
||||||
|
out << YAML::Value << 1;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
out << YAML::Key << "bill-to";
|
||||||
|
out << YAML::Value << YAML::Anchor("id001");
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "street";
|
||||||
|
out << YAML::Value << YAML::Literal << "123 Tornado Alley\nSuite 16";
|
||||||
|
out << YAML::Key << "city";
|
||||||
|
out << YAML::Value << "East Westville";
|
||||||
|
out << YAML::Key << "state";
|
||||||
|
out << YAML::Value << "KS";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::Key << "ship-to";
|
||||||
|
out << YAML::Value << YAML::Alias("id001");
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "receipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001";
|
||||||
|
}
|
||||||
|
|
||||||
|
void STLContainers(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
std::vector <int> primes;
|
||||||
|
primes.push_back(2);
|
||||||
|
primes.push_back(3);
|
||||||
|
primes.push_back(5);
|
||||||
|
primes.push_back(7);
|
||||||
|
primes.push_back(11);
|
||||||
|
primes.push_back(13);
|
||||||
|
out << YAML::Flow << primes;
|
||||||
|
std::map <std::string, int> ages;
|
||||||
|
ages["Daniel"] = 26;
|
||||||
|
ages["Jesse"] = 24;
|
||||||
|
out << ages;
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleComment(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "method";
|
||||||
|
out << YAML::Value << "least squares" << YAML::Comment("should we change this method?");
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "method: least squares # should we change this method?";
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << "item 1" << YAML::Comment("really really long\ncomment that couldn't possibly\nfit on one line");
|
||||||
|
out << "item 2";
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComplexComments(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::LongKey << YAML::Key << "long key" << YAML::Comment("long key");
|
||||||
|
out << YAML::Value << "value";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
desiredOutput = "? long key # long key\n: value";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Indentation(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::Indent(4);
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "key 1" << YAML::Value << "value 1";
|
||||||
|
out << YAML::Key << "key 2" << YAML::Value << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "-\n key 1: value 1\n key 2:\n - a\n - b\n - c";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out.SetIndent(4);
|
||||||
|
out.SetMapFormat(YAML::LongKey);
|
||||||
|
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "key 1" << YAML::Value << "value 1";
|
||||||
|
out << YAML::Key << "key 2" << YAML::Value << YAML::Flow << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << YAML::Block;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "key 1" << YAML::Value << "value 1";
|
||||||
|
out << YAML::Key << "key 2" << YAML::Value;
|
||||||
|
out.SetSeqFormat(YAML::Flow);
|
||||||
|
out << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << YAML::BeginSeq << 1 << 2 << YAML::EndSeq;
|
||||||
|
out << YAML::Value << YAML::BeginMap << YAML::Key << "a" << YAML::Value << "b" << YAML::EndMap;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b";
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// incorrect emitting
|
||||||
|
|
||||||
|
void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError)
|
||||||
|
{
|
||||||
|
desiredError = YAML::ErrorMsg::UNEXPECTED_END_SEQ;
|
||||||
|
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << "Hello";
|
||||||
|
out << "World";
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtraEndMap(YAML::Emitter& out, std::string& desiredError)
|
||||||
|
{
|
||||||
|
desiredError = YAML::ErrorMsg::UNEXPECTED_END_MAP;
|
||||||
|
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "Hello" << YAML::Value << "World";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BadSingleQuoted(YAML::Emitter& out, std::string& desiredError)
|
||||||
|
{
|
||||||
|
desiredError = YAML::ErrorMsg::SINGLE_QUOTED_CHAR;
|
||||||
|
|
||||||
|
out << YAML::SingleQuoted << "Hello\nWorld";
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvalidAnchor(YAML::Emitter& out, std::string& desiredError)
|
||||||
|
{
|
||||||
|
desiredError = YAML::ErrorMsg::INVALID_ANCHOR;
|
||||||
|
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << YAML::Anchor("new\nline") << "Test";
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvalidAlias(YAML::Emitter& out, std::string& desiredError)
|
||||||
|
{
|
||||||
|
desiredError = YAML::ErrorMsg::INVALID_ALIAS;
|
||||||
|
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << YAML::Alias("new\nline");
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MissingKey(YAML::Emitter& out, std::string& desiredError)
|
||||||
|
{
|
||||||
|
desiredError = YAML::ErrorMsg::EXPECTED_KEY_TOKEN;
|
||||||
|
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "key" << YAML::Value << "value";
|
||||||
|
out << "missing key" << YAML::Value << "value";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MissingValue(YAML::Emitter& out, std::string& desiredError)
|
||||||
|
{
|
||||||
|
desiredError = YAML::ErrorMsg::EXPECTED_VALUE_TOKEN;
|
||||||
|
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "key" << "value";
|
||||||
|
out << YAML::EndMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnexpectedKey(YAML::Emitter& out, std::string& desiredError)
|
||||||
|
{
|
||||||
|
desiredError = YAML::ErrorMsg::UNEXPECTED_KEY_TOKEN;
|
||||||
|
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << YAML::Key << "hi";
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnexpectedValue(YAML::Emitter& out, std::string& desiredError)
|
||||||
|
{
|
||||||
|
desiredError = YAML::ErrorMsg::UNEXPECTED_VALUE_TOKEN;
|
||||||
|
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << YAML::Value << "hi";
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,55 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
namespace YAML { class Emitter; }
|
||||||
|
|
||||||
namespace Test {
|
namespace Test {
|
||||||
void RunAll(bool verbose);
|
void RunAll(bool verbose);
|
||||||
bool Inout(const std::string& file, 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