diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index bc3a31c..0e1ca26 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -75,6 +75,8 @@ namespace YAML void PostAtomicWrite(); void EmitSeparationIfNecessary(); + void EmitBeginDoc(); + void EmitEndDoc(); void EmitBeginSeq(); void EmitEndSeq(); void EmitBeginMap(); diff --git a/include/yaml-cpp/emittermanip.h b/include/yaml-cpp/emittermanip.h index 28e88be..1dc5766 100644 --- a/include/yaml-cpp/emittermanip.h +++ b/include/yaml-cpp/emittermanip.h @@ -41,6 +41,10 @@ namespace YAML Hex, Oct, + // document manipulators + BeginDoc, + EndDoc, + // sequence manipulators BeginSeq, EndSeq, diff --git a/src/emitter.cpp b/src/emitter.cpp index a60e849..8ae2f2e 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -102,6 +102,12 @@ namespace YAML return *this; switch(value) { + case BeginDoc: + EmitBeginDoc(); + break; + case EndDoc: + EmitEndDoc(); + break; case BeginSeq: EmitBeginSeq(); break; @@ -157,8 +163,8 @@ namespace YAML case ES_WRITING_DOC: return true; case ES_DONE_WITH_DOC: - m_pState->SetError("Write called on finished document"); - return true; + EmitBeginDoc(); + return false; // block sequence case ES_WAITING_FOR_BLOCK_SEQ_ENTRY: @@ -320,6 +326,47 @@ namespace YAML m_pState->UnsetSeparation(); } + // EmitBeginDoc + void Emitter::EmitBeginDoc() + { + if(!good()) + return; + + EMITTER_STATE curState = m_pState->GetCurState(); + if(curState != ES_WAITING_FOR_DOC && curState != ES_WRITING_DOC && curState != ES_DONE_WITH_DOC) { + m_pState->SetError("Unexpected begin document"); + return; + } + + if(curState == ES_WRITING_DOC || curState == ES_DONE_WITH_DOC) + m_stream << '\n'; + m_stream << "---\n"; + + m_pState->UnsetSeparation(); + m_pState->SwitchState(ES_WAITING_FOR_DOC); + } + + // EmitEndDoc + void Emitter::EmitEndDoc() + { + if(!good()) + return; + + + EMITTER_STATE curState = m_pState->GetCurState(); + if(curState != ES_WAITING_FOR_DOC && curState != ES_WRITING_DOC && curState != ES_DONE_WITH_DOC) { + m_pState->SetError("Unexpected end document"); + return; + } + + if(curState == ES_WRITING_DOC || curState == ES_DONE_WITH_DOC) + m_stream << '\n'; + m_stream << "...\n"; + + m_pState->UnsetSeparation(); + m_pState->SwitchState(ES_WAITING_FOR_DOC); + } + // EmitBeginSeq void Emitter::EmitBeginSeq() { diff --git a/test/emittertests.cpp b/test/emittertests.cpp index d7ee307..c3e0be7 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -776,6 +776,28 @@ namespace Test "- ON\n- On\n- on\n- OFF\n- Off\n- off\n" "- Y\n- Y\n- y\n- N\n- N\n- n"; } + + void DocStartAndEnd(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginDoc; + out << YAML::BeginSeq << 1 << 2 << 3 << YAML::EndSeq; + out << YAML::BeginDoc; + out << "Hi there!"; + out << YAML::EndDoc; + out << YAML::EndDoc; + out << YAML::EndDoc; + out << YAML::BeginDoc; + out << YAML::VerbatimTag("foo") << "bar"; + desiredOutput = "---\n- 1\n- 2\n- 3\n---\nHi there!\n...\n...\n...\n---\n! bar"; + } + + void ImplicitDocStart(YAML::Emitter& out, std::string& desiredOutput) + { + out << "Hi"; + out << "Bye"; + out << "Oops"; + desiredOutput = "Hi\n---\nBye\n---\nOops"; + } //////////////////////////////////////////////////////////////////////////////////////////////////////// // incorrect emitting @@ -870,6 +892,7 @@ namespace Test std::string desiredOutput; test(out, desiredOutput); std::string output = out.c_str(); + std::string lastError = out.GetLastError(); if(output == desiredOutput) { try { @@ -888,6 +911,8 @@ namespace Test std::cout << output << "<<<\n"; std::cout << "Desired output:\n"; std::cout << desiredOutput << "<<<\n"; + if(!out.good()) + std::cout << "Emitter error: " << lastError << "\n"; } total++; } @@ -978,6 +1003,8 @@ namespace Test RunEmitterTest(&Emitter::ColonAtEndOfScalar, "colon at end of scalar", passed, total); RunEmitterTest(&Emitter::ColonAsScalar, "colon as scalar", passed, total); RunEmitterTest(&Emitter::BoolFormatting, "bool formatting", passed, total); + RunEmitterTest(&Emitter::DocStartAndEnd, "doc start and end", passed, total); + RunEmitterTest(&Emitter::ImplicitDocStart, "implicit doc start", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total);