From d86cfc1c630c27e0e08796933ead4313fa8c99e0 Mon Sep 17 00:00:00 2001 From: Jesse Beder Date: Mon, 21 May 2012 19:07:56 -0500 Subject: [PATCH] Implemented the Write for scalars (including checking which type of scalar it should be) --- src/emitter.cpp | 29 +++++++++++++++++++ src/emitterutils.cpp | 68 +++++++++++++++++++++++++++++++++++--------- src/emitterutils.h | 6 +++- 3 files changed, 88 insertions(+), 15 deletions(-) diff --git a/src/emitter.cpp b/src/emitter.cpp index 6ef9d2a..62bf5b9 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -293,6 +293,17 @@ namespace YAML void Emitter::PrepareTopNode() { + const bool hasAnchor = m_pState->HasAnchor(); + const bool hasTag = m_pState->HasTag(); + + if(!hasAnchor && !hasTag && m_stream.pos() > 0) { + EmitBeginDoc(); + } + + // TODO: if we were writing null, and + // we wanted it blank, we wouldn't want a space + if(hasAnchor || hasTag) + m_stream << " "; } void Emitter::FlowSeqPrepareNode() @@ -321,6 +332,24 @@ namespace YAML PrepareNode(); + const bool escapeNonAscii = m_pState->GetOutputCharset() == EscapeNonAscii; + const StringFormat::value strFormat = Utils::ComputeStringFormat(str, m_pState->GetStringFormat(), m_pState->CurGroupFlowType(), escapeNonAscii); + + switch(strFormat) { + case StringFormat::Plain: + m_stream << str; + break; + case StringFormat::SingleQuoted: + Utils::WriteSingleQuotedString(m_stream, str); + break; + case StringFormat::DoubleQuoted: + Utils::WriteDoubleQuotedString(m_stream, str, escapeNonAscii); + break; + case StringFormat::Literal: + Utils::WriteLiteralString(m_stream, str, m_pState->CurIndent() + m_pState->GetIndent()); + break; + } + m_pState->BeginScalar(); return *this; diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index 3d184d6..c54d9be 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -128,12 +128,12 @@ namespace YAML } } - bool IsValidPlainScalar(const std::string& str, bool inFlow, bool allowOnlyAscii) { + bool IsValidPlainScalar(const std::string& str, FlowType::value flowType, bool allowOnlyAscii) { if(str.empty()) return false; // first check the start - const RegEx& start = (inFlow ? Exp::PlainScalarInFlow() : Exp::PlainScalar()); + const RegEx& start = (flowType == FlowType::Flow ? Exp::PlainScalarInFlow() : Exp::PlainScalar()); if(!start.Matches(str)) return false; @@ -142,7 +142,7 @@ namespace YAML return false; // then check until something is disallowed - const RegEx& disallowed = (inFlow ? Exp::EndScalarInFlow() : Exp::EndScalar()) + const RegEx& disallowed = (flowType == FlowType::Flow ? Exp::EndScalarInFlow() : Exp::EndScalar()) || (Exp::BlankOrBreak() + Exp::Comment()) || Exp::NotPrintable() || Exp::Utf8_ByteOrderMark() @@ -152,7 +152,7 @@ namespace YAML while(buffer) { if(disallowed.Matches(buffer)) return false; - if(allowOnlyAscii && (0x7F < static_cast(buffer[0]))) + if(allowOnlyAscii && (0x80 <= static_cast(buffer[0]))) return false; ++buffer; } @@ -160,7 +160,32 @@ namespace YAML return true; } - void WriteDoubleQuoteEscapeSequence(ostream& out, int codePoint) { + bool IsValidSingleQuotedScalar(const std::string& str, bool escapeNonAscii) + { + // TODO: check for non-printable characters? + for(std::size_t i=0;i(str[i]))) + return false; + if(str[i] == '\n') + return false; + } + return true; + } + + bool IsValidLiteralScalar(const std::string& str, FlowType::value flowType, bool escapeNonAscii) + { + if(flowType == FlowType::Flow) + return false; + + // TODO: check for non-printable characters? + for(std::size_t i=0;i(str[i]))) + return false; + } + return true; + } + + void WriteDoubleQuoteEscapeSequence(ostream& out, int codePoint) { static const char hexDigits[] = "0123456789abcdef"; char escSeq[] = "\\U00000000"; @@ -198,15 +223,30 @@ namespace YAML } } - bool WriteString(ostream& out, const std::string& str, bool inFlow, bool escapeNonAscii) - { - if(IsValidPlainScalar(str, inFlow, escapeNonAscii)) { - out << str; - return true; - } else - return WriteDoubleQuotedString(out, str, escapeNonAscii); - } - + StringFormat::value ComputeStringFormat(const std::string& str, EMITTER_MANIP strFormat, FlowType::value flowType, bool escapeNonAscii) + { + switch(strFormat) { + case Auto: + if(IsValidPlainScalar(str, flowType, escapeNonAscii)) + return StringFormat::Plain; + return StringFormat::DoubleQuoted; + case SingleQuoted: + if(IsValidSingleQuotedScalar(str, escapeNonAscii)) + return StringFormat::SingleQuoted; + return StringFormat::DoubleQuoted; + case DoubleQuoted: + return StringFormat::DoubleQuoted; + case Literal: + if(IsValidLiteralScalar(str, flowType, escapeNonAscii)) + return StringFormat::Literal; + return StringFormat::DoubleQuoted; + default: + break; + } + + return StringFormat::DoubleQuoted; + } + bool WriteSingleQuotedString(ostream& out, const std::string& str) { out << "'"; diff --git a/src/emitterutils.h b/src/emitterutils.h index 0e270d6..67200f8 100644 --- a/src/emitterutils.h +++ b/src/emitterutils.h @@ -6,6 +6,7 @@ #endif +#include "emitterstate.h" #include "yaml-cpp/ostream.h" #include @@ -13,9 +14,12 @@ namespace YAML { class Binary; + struct StringFormat { enum value { Plain, SingleQuoted, DoubleQuoted, Literal }; }; + namespace Utils { - bool WriteString(ostream& out, const std::string& str, bool inFlow, bool escapeNonAscii); + StringFormat::value ComputeStringFormat(const std::string& str, EMITTER_MANIP strFormat, FlowType::value flowType, bool escapeNonAscii); + bool WriteSingleQuotedString(ostream& out, const std::string& str); bool WriteDoubleQuotedString(ostream& out, const std::string& str, bool escapeNonAscii); bool WriteLiteralString(ostream& out, const std::string& str, int indent);