1 #include "yaml-cpp/emitter.h"
2 #include "emitterstate.h"
3 #include "emitterutils.h"
4 #include "indentation.h"
5 #include "yaml-cpp/exceptions.h"
10 Emitter::Emitter(): m_pState(new EmitterState
)
18 const char *Emitter::c_str() const
20 return m_stream
.str();
23 unsigned Emitter::size() const
25 return m_stream
.pos();
29 bool Emitter::good() const
31 return m_pState
->good();
34 const std::string
Emitter::GetLastError() const
36 return m_pState
->GetLastError();
40 bool Emitter::SetOutputCharset(EMITTER_MANIP value
)
42 return m_pState
->SetOutputCharset(value
, GLOBAL
);
45 bool Emitter::SetStringFormat(EMITTER_MANIP value
)
47 return m_pState
->SetStringFormat(value
, GLOBAL
);
50 bool Emitter::SetBoolFormat(EMITTER_MANIP value
)
53 if(m_pState
->SetBoolFormat(value
, GLOBAL
))
55 if(m_pState
->SetBoolCaseFormat(value
, GLOBAL
))
57 if(m_pState
->SetBoolLengthFormat(value
, GLOBAL
))
62 bool Emitter::SetIntBase(EMITTER_MANIP value
)
64 return m_pState
->SetIntFormat(value
, GLOBAL
);
67 bool Emitter::SetSeqFormat(EMITTER_MANIP value
)
69 return m_pState
->SetFlowType(GT_SEQ
, value
, GLOBAL
);
72 bool Emitter::SetMapFormat(EMITTER_MANIP value
)
75 if(m_pState
->SetFlowType(GT_MAP
, value
, GLOBAL
))
77 if(m_pState
->SetMapKeyFormat(value
, GLOBAL
))
82 bool Emitter::SetIndent(unsigned n
)
84 return m_pState
->SetIndent(n
, GLOBAL
);
87 bool Emitter::SetPreCommentIndent(unsigned n
)
89 return m_pState
->SetPreCommentIndent(n
, GLOBAL
);
92 bool Emitter::SetPostCommentIndent(unsigned n
)
94 return m_pState
->SetPostCommentIndent(n
, GLOBAL
);
97 bool Emitter::SetFloatPrecision(unsigned n
)
99 return m_pState
->SetFloatPrecision(n
, GLOBAL
);
102 bool Emitter::SetDoublePrecision(unsigned n
)
104 return m_pState
->SetDoublePrecision(n
, GLOBAL
);
108 // . Either start/end a group, or set a modifier locally
109 Emitter
& Emitter::SetLocalValue(EMITTER_MANIP value
)
146 m_pState
->SetLocalValue(value
);
152 Emitter
& Emitter::SetLocalIndent(const _Indent
& indent
)
154 m_pState
->SetIndent(indent
.value
, LOCAL
);
158 Emitter
& Emitter::SetLocalPrecision(const _Precision
& precision
)
160 if(precision
.floatPrecision
>= 0)
161 m_pState
->SetFloatPrecision(precision
.floatPrecision
, LOCAL
);
162 if(precision
.doublePrecision
>= 0)
163 m_pState
->SetDoublePrecision(precision
.doublePrecision
, LOCAL
);
167 // GotoNextPreAtomicState
168 // . Runs the state machine, emitting if necessary, and returns 'true' if done (i.e., ready to emit an atom)
169 bool Emitter::GotoNextPreAtomicState()
174 unsigned curIndent
= m_pState
->GetCurIndent();
176 EMITTER_STATE curState
= m_pState
->GetCurState();
179 case ES_WAITING_FOR_DOC
:
180 m_pState
->SwitchState(ES_WRITING_DOC
);
184 case ES_DONE_WITH_DOC
:
189 case ES_WAITING_FOR_BLOCK_SEQ_ENTRY
:
190 m_stream
<< IndentTo(curIndent
) << "-";
191 m_pState
->RequireSoftSeparation();
192 m_pState
->SwitchState(ES_WRITING_BLOCK_SEQ_ENTRY
);
194 case ES_WRITING_BLOCK_SEQ_ENTRY
:
196 case ES_DONE_WITH_BLOCK_SEQ_ENTRY
:
198 m_pState
->SwitchState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY
);
202 case ES_WAITING_FOR_FLOW_SEQ_ENTRY
:
203 m_pState
->SwitchState(ES_WRITING_FLOW_SEQ_ENTRY
);
205 case ES_WRITING_FLOW_SEQ_ENTRY
:
207 case ES_DONE_WITH_FLOW_SEQ_ENTRY
:
208 EmitSeparationIfNecessary();
210 m_pState
->RequireSoftSeparation();
211 m_pState
->SwitchState(ES_WAITING_FOR_FLOW_SEQ_ENTRY
);
215 case ES_WAITING_FOR_BLOCK_MAP_ENTRY
:
216 m_pState
->SetError(ErrorMsg::EXPECTED_KEY_TOKEN
);
218 case ES_WAITING_FOR_BLOCK_MAP_KEY
:
219 if(m_pState
->CurrentlyInLongKey()) {
220 m_stream
<< IndentTo(curIndent
) << '?';
221 m_pState
->RequireSoftSeparation();
223 m_pState
->SwitchState(ES_WRITING_BLOCK_MAP_KEY
);
225 case ES_WRITING_BLOCK_MAP_KEY
:
227 case ES_DONE_WITH_BLOCK_MAP_KEY
:
228 m_pState
->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN
);
230 case ES_WAITING_FOR_BLOCK_MAP_VALUE
:
231 m_pState
->SwitchState(ES_WRITING_BLOCK_MAP_VALUE
);
233 case ES_WRITING_BLOCK_MAP_VALUE
:
235 case ES_DONE_WITH_BLOCK_MAP_VALUE
:
236 m_pState
->SetError(ErrorMsg::EXPECTED_KEY_TOKEN
);
240 case ES_WAITING_FOR_FLOW_MAP_ENTRY
:
241 m_pState
->SetError(ErrorMsg::EXPECTED_KEY_TOKEN
);
243 case ES_WAITING_FOR_FLOW_MAP_KEY
:
244 EmitSeparationIfNecessary();
245 m_pState
->SwitchState(ES_WRITING_FLOW_MAP_KEY
);
246 if(m_pState
->CurrentlyInLongKey()) {
248 m_pState
->RequireSoftSeparation();
251 case ES_WRITING_FLOW_MAP_KEY
:
253 case ES_DONE_WITH_FLOW_MAP_KEY
:
254 m_pState
->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN
);
256 case ES_WAITING_FOR_FLOW_MAP_VALUE
:
257 EmitSeparationIfNecessary();
259 m_pState
->RequireSoftSeparation();
260 m_pState
->SwitchState(ES_WRITING_FLOW_MAP_VALUE
);
262 case ES_WRITING_FLOW_MAP_VALUE
:
264 case ES_DONE_WITH_FLOW_MAP_VALUE
:
265 m_pState
->SetError(ErrorMsg::EXPECTED_KEY_TOKEN
);
276 // . Depending on the emitter state, write to the stream to get it
277 // in position to do an atomic write (e.g., scalar, sequence, or map)
278 void Emitter::PreAtomicWrite()
283 while(!GotoNextPreAtomicState())
289 void Emitter::PostAtomicWrite()
294 EMITTER_STATE curState
= m_pState
->GetCurState();
298 m_pState
->SwitchState(ES_DONE_WITH_DOC
);
302 case ES_WRITING_BLOCK_SEQ_ENTRY
:
303 m_pState
->SwitchState(ES_DONE_WITH_BLOCK_SEQ_ENTRY
);
307 case ES_WRITING_FLOW_SEQ_ENTRY
:
308 m_pState
->SwitchState(ES_DONE_WITH_FLOW_SEQ_ENTRY
);
312 case ES_WRITING_BLOCK_MAP_KEY
:
313 if(!m_pState
->CurrentlyInLongKey()) {
315 m_pState
->RequireSoftSeparation();
317 m_pState
->SwitchState(ES_DONE_WITH_BLOCK_MAP_KEY
);
319 case ES_WRITING_BLOCK_MAP_VALUE
:
320 m_pState
->SwitchState(ES_DONE_WITH_BLOCK_MAP_VALUE
);
324 case ES_WRITING_FLOW_MAP_KEY
:
325 m_pState
->SwitchState(ES_DONE_WITH_FLOW_MAP_KEY
);
327 case ES_WRITING_FLOW_MAP_VALUE
:
328 m_pState
->SwitchState(ES_DONE_WITH_FLOW_MAP_VALUE
);
334 m_pState
->ClearModifiedSettings();
337 // EmitSeparationIfNecessary
338 void Emitter::EmitSeparationIfNecessary()
343 if(m_pState
->RequiresSoftSeparation())
345 else if(m_pState
->RequiresHardSeparation())
347 m_pState
->UnsetSeparation();
351 void Emitter::EmitBeginDoc()
356 EMITTER_STATE curState
= m_pState
->GetCurState();
357 if(curState
!= ES_WAITING_FOR_DOC
&& curState
!= ES_WRITING_DOC
&& curState
!= ES_DONE_WITH_DOC
) {
358 m_pState
->SetError("Unexpected begin document");
362 if(curState
== ES_WRITING_DOC
|| curState
== ES_DONE_WITH_DOC
)
366 m_pState
->UnsetSeparation();
367 m_pState
->SwitchState(ES_WAITING_FOR_DOC
);
371 void Emitter::EmitEndDoc()
377 EMITTER_STATE curState
= m_pState
->GetCurState();
378 if(curState
!= ES_WAITING_FOR_DOC
&& curState
!= ES_WRITING_DOC
&& curState
!= ES_DONE_WITH_DOC
) {
379 m_pState
->SetError("Unexpected end document");
383 if(curState
== ES_WRITING_DOC
|| curState
== ES_DONE_WITH_DOC
)
387 m_pState
->UnsetSeparation();
388 m_pState
->SwitchState(ES_WAITING_FOR_DOC
);
392 void Emitter::EmitBeginSeq()
397 // must have a long key if we're emitting a sequence
398 m_pState
->StartLongKey();
402 EMITTER_STATE curState
= m_pState
->GetCurState();
403 EMITTER_MANIP flowType
= m_pState
->GetFlowType(GT_SEQ
);
404 if(flowType
== Block
) {
405 if(curState
== ES_WRITING_BLOCK_SEQ_ENTRY
||
406 curState
== ES_WRITING_BLOCK_MAP_KEY
|| curState
== ES_WRITING_BLOCK_MAP_VALUE
||
407 curState
== ES_WRITING_DOC
409 if(m_pState
->RequiresHardSeparation() || curState
!= ES_WRITING_DOC
) {
411 m_pState
->UnsetSeparation();
414 m_pState
->PushState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY
);
415 } else if(flowType
== Flow
) {
416 EmitSeparationIfNecessary();
418 m_pState
->PushState(ES_WAITING_FOR_FLOW_SEQ_ENTRY
);
422 m_pState
->BeginGroup(GT_SEQ
);
426 void Emitter::EmitEndSeq()
431 if(m_pState
->GetCurGroupType() != GT_SEQ
)
432 return m_pState
->SetError(ErrorMsg::UNEXPECTED_END_SEQ
);
434 EMITTER_STATE curState
= m_pState
->GetCurState();
435 FLOW_TYPE flowType
= m_pState
->GetCurGroupFlowType();
436 if(flowType
== FT_BLOCK
) {
437 // Note: block sequences are *not* allowed to be empty, but we convert it
438 // to a flow sequence if it is
439 assert(curState
== ES_DONE_WITH_BLOCK_SEQ_ENTRY
|| curState
== ES_WAITING_FOR_BLOCK_SEQ_ENTRY
);
440 if(curState
== ES_WAITING_FOR_BLOCK_SEQ_ENTRY
) {
441 // Note: only one of these will actually output anything for a given situation
442 EmitSeparationIfNecessary();
443 unsigned curIndent
= m_pState
->GetCurIndent();
444 m_stream
<< IndentTo(curIndent
);
448 } else if(flowType
== FT_FLOW
) {
449 // Note: flow sequences are allowed to be empty
450 assert(curState
== ES_DONE_WITH_FLOW_SEQ_ENTRY
|| curState
== ES_WAITING_FOR_FLOW_SEQ_ENTRY
);
455 m_pState
->PopState();
456 m_pState
->EndGroup(GT_SEQ
);
462 void Emitter::EmitBeginMap()
467 // must have a long key if we're emitting a map
468 m_pState
->StartLongKey();
472 EMITTER_STATE curState
= m_pState
->GetCurState();
473 EMITTER_MANIP flowType
= m_pState
->GetFlowType(GT_MAP
);
474 if(flowType
== Block
) {
475 if(curState
== ES_WRITING_BLOCK_SEQ_ENTRY
||
476 curState
== ES_WRITING_BLOCK_MAP_KEY
|| curState
== ES_WRITING_BLOCK_MAP_VALUE
||
477 curState
== ES_WRITING_DOC
479 if(m_pState
->RequiresHardSeparation() || (curState
!= ES_WRITING_DOC
&& curState
!= ES_WRITING_BLOCK_SEQ_ENTRY
)) {
481 m_pState
->UnsetSeparation();
484 m_pState
->PushState(ES_WAITING_FOR_BLOCK_MAP_ENTRY
);
485 } else if(flowType
== Flow
) {
486 EmitSeparationIfNecessary();
488 m_pState
->PushState(ES_WAITING_FOR_FLOW_MAP_ENTRY
);
492 m_pState
->BeginGroup(GT_MAP
);
496 void Emitter::EmitEndMap()
501 if(m_pState
->GetCurGroupType() != GT_MAP
)
502 return m_pState
->SetError(ErrorMsg::UNEXPECTED_END_MAP
);
504 EMITTER_STATE curState
= m_pState
->GetCurState();
505 FLOW_TYPE flowType
= m_pState
->GetCurGroupFlowType();
506 if(flowType
== FT_BLOCK
) {
507 // Note: block sequences are *not* allowed to be empty, but we convert it
508 // to a flow sequence if it is
509 assert(curState
== ES_DONE_WITH_BLOCK_MAP_VALUE
|| curState
== ES_WAITING_FOR_BLOCK_MAP_ENTRY
);
510 if(curState
== ES_WAITING_FOR_BLOCK_MAP_ENTRY
) {
511 // Note: only one of these will actually output anything for a given situation
512 EmitSeparationIfNecessary();
513 unsigned curIndent
= m_pState
->GetCurIndent();
514 m_stream
<< IndentTo(curIndent
);
517 } else if(flowType
== FT_FLOW
) {
518 // Note: flow maps are allowed to be empty
519 assert(curState
== ES_DONE_WITH_FLOW_MAP_VALUE
|| curState
== ES_WAITING_FOR_FLOW_MAP_ENTRY
);
520 EmitSeparationIfNecessary();
525 m_pState
->PopState();
526 m_pState
->EndGroup(GT_MAP
);
532 void Emitter::EmitKey()
537 EMITTER_STATE curState
= m_pState
->GetCurState();
538 FLOW_TYPE flowType
= m_pState
->GetCurGroupFlowType();
539 if(curState
!= ES_WAITING_FOR_BLOCK_MAP_ENTRY
&& curState
!= ES_DONE_WITH_BLOCK_MAP_VALUE
540 && curState
!= ES_WAITING_FOR_FLOW_MAP_ENTRY
&& curState
!= ES_DONE_WITH_FLOW_MAP_VALUE
)
541 return m_pState
->SetError(ErrorMsg::UNEXPECTED_KEY_TOKEN
);
543 if(flowType
== FT_BLOCK
) {
544 if(curState
== ES_DONE_WITH_BLOCK_MAP_VALUE
)
546 unsigned curIndent
= m_pState
->GetCurIndent();
547 m_stream
<< IndentTo(curIndent
);
548 m_pState
->UnsetSeparation();
549 m_pState
->SwitchState(ES_WAITING_FOR_BLOCK_MAP_KEY
);
550 } else if(flowType
== FT_FLOW
) {
551 EmitSeparationIfNecessary();
552 if(curState
== ES_DONE_WITH_FLOW_MAP_VALUE
) {
554 m_pState
->RequireSoftSeparation();
556 m_pState
->SwitchState(ES_WAITING_FOR_FLOW_MAP_KEY
);
560 if(m_pState
->GetMapKeyFormat() == LongKey
)
561 m_pState
->StartLongKey();
562 else if(m_pState
->GetMapKeyFormat() == Auto
)
563 m_pState
->StartSimpleKey();
569 void Emitter::EmitValue()
574 EMITTER_STATE curState
= m_pState
->GetCurState();
575 FLOW_TYPE flowType
= m_pState
->GetCurGroupFlowType();
576 if(curState
!= ES_DONE_WITH_BLOCK_MAP_KEY
&& curState
!= ES_DONE_WITH_FLOW_MAP_KEY
)
577 return m_pState
->SetError(ErrorMsg::UNEXPECTED_VALUE_TOKEN
);
579 if(flowType
== FT_BLOCK
) {
580 if(m_pState
->CurrentlyInLongKey()) {
582 m_stream
<< IndentTo(m_pState
->GetCurIndent());
584 m_pState
->RequireSoftSeparation();
586 m_pState
->SwitchState(ES_WAITING_FOR_BLOCK_MAP_VALUE
);
587 } else if(flowType
== FT_FLOW
) {
588 m_pState
->SwitchState(ES_WAITING_FOR_FLOW_MAP_VALUE
);
594 void Emitter::EmitNewline()
599 if(CanEmitNewline()) {
601 m_pState
->UnsetSeparation();
605 bool Emitter::CanEmitNewline() const
607 FLOW_TYPE flowType
= m_pState
->GetCurGroupFlowType();
608 if(flowType
== FT_BLOCK
&& m_pState
->CurrentlyInLongKey())
611 EMITTER_STATE curState
= m_pState
->GetCurState();
612 return curState
!= ES_DONE_WITH_BLOCK_MAP_KEY
&& curState
!= ES_WAITING_FOR_BLOCK_MAP_VALUE
&& curState
!= ES_WRITING_BLOCK_MAP_VALUE
;
615 // *******************************************************************************************
616 // overloads of Write
618 Emitter
& Emitter::Write(const std::string
& str
)
623 // literal scalars must use long keys
624 if(m_pState
->GetStringFormat() == Literal
&& m_pState
->GetCurGroupFlowType() != FT_FLOW
)
625 m_pState
->StartLongKey();
628 EmitSeparationIfNecessary();
630 bool escapeNonAscii
= m_pState
->GetOutputCharset() == EscapeNonAscii
;
631 EMITTER_MANIP strFmt
= m_pState
->GetStringFormat();
632 FLOW_TYPE flowType
= m_pState
->GetCurGroupFlowType();
633 unsigned curIndent
= m_pState
->GetCurIndent();
637 Utils::WriteString(m_stream
, str
, flowType
== FT_FLOW
, escapeNonAscii
);
640 if(!Utils::WriteSingleQuotedString(m_stream
, str
)) {
641 m_pState
->SetError(ErrorMsg::SINGLE_QUOTED_CHAR
);
646 Utils::WriteDoubleQuotedString(m_stream
, str
, escapeNonAscii
);
649 if(flowType
== FT_FLOW
)
650 Utils::WriteString(m_stream
, str
, flowType
== FT_FLOW
, escapeNonAscii
);
652 Utils::WriteLiteralString(m_stream
, str
, curIndent
+ m_pState
->GetIndent());
662 void Emitter::PreWriteIntegralType(std::stringstream
& str
)
665 EmitSeparationIfNecessary();
667 EMITTER_MANIP intFmt
= m_pState
->GetIntFormat();
685 void Emitter::PreWriteStreamable(std::stringstream
&)
688 EmitSeparationIfNecessary();
691 unsigned Emitter::GetFloatPrecision() const
693 return m_pState
->GetFloatPrecision();
696 unsigned Emitter::GetDoublePrecision() const
698 return m_pState
->GetDoublePrecision();
701 void Emitter::PostWriteIntegralType(const std::stringstream
& str
)
703 m_stream
<< str
.str();
707 void Emitter::PostWriteStreamable(const std::stringstream
& str
)
709 m_stream
<< str
.str();
713 const char *Emitter::ComputeFullBoolName(bool b
) const
715 const EMITTER_MANIP mainFmt
= (m_pState
->GetBoolLengthFormat() == ShortBool
? YesNoBool
: m_pState
->GetBoolFormat());
716 const EMITTER_MANIP caseFmt
= m_pState
->GetBoolCaseFormat();
720 case UpperCase
: return b
? "YES" : "NO";
721 case CamelCase
: return b
? "Yes" : "No";
722 case LowerCase
: return b
? "yes" : "no";
728 case UpperCase
: return b
? "ON" : "OFF";
729 case CamelCase
: return b
? "On" : "Off";
730 case LowerCase
: return b
? "on" : "off";
736 case UpperCase
: return b
? "TRUE" : "FALSE";
737 case CamelCase
: return b
? "True" : "False";
738 case LowerCase
: return b
? "true" : "false";
745 return b
? "y" : "n"; // should never get here, but it can't hurt to give these answers
748 Emitter
& Emitter::Write(bool b
)
754 EmitSeparationIfNecessary();
756 const char *name
= ComputeFullBoolName(b
);
757 if(m_pState
->GetBoolLengthFormat() == ShortBool
)
766 Emitter
& Emitter::Write(char ch
)
772 EmitSeparationIfNecessary();
774 Utils::WriteChar(m_stream
, ch
);
780 Emitter
& Emitter::Write(const _Alias
& alias
)
786 EmitSeparationIfNecessary();
787 if(!Utils::WriteAlias(m_stream
, alias
.content
)) {
788 m_pState
->SetError(ErrorMsg::INVALID_ALIAS
);
795 Emitter
& Emitter::Write(const _Anchor
& anchor
)
801 EmitSeparationIfNecessary();
802 if(!Utils::WriteAnchor(m_stream
, anchor
.content
)) {
803 m_pState
->SetError(ErrorMsg::INVALID_ANCHOR
);
806 m_pState
->RequireHardSeparation();
807 // Note: no PostAtomicWrite() because we need another value for this node
811 Emitter
& Emitter::Write(const _Tag
& tag
)
817 EmitSeparationIfNecessary();
819 bool success
= false;
820 if(tag
.type
== _Tag::Type::Verbatim
)
821 success
= Utils::WriteTag(m_stream
, tag
.content
, true);
822 else if(tag
.type
== _Tag::Type::PrimaryHandle
)
823 success
= Utils::WriteTag(m_stream
, tag
.content
, false);
825 success
= Utils::WriteTagWithPrefix(m_stream
, tag
.prefix
, tag
.content
);
828 m_pState
->SetError(ErrorMsg::INVALID_TAG
);
832 m_pState
->RequireHardSeparation();
833 // Note: no PostAtomicWrite() because we need another value for this node
837 void Emitter::EmitKindTag()
842 Emitter
& Emitter::Write(const _Comment
& comment
)
847 if(m_stream
.col() > 0)
848 m_stream
<< Indentation(m_pState
->GetPreCommentIndent());
849 Utils::WriteComment(m_stream
, comment
.content
, m_pState
->GetPostCommentIndent());
850 m_pState
->RequireHardSeparation();
851 m_pState
->ForceHardSeparation();
856 Emitter
& Emitter::Write(const _Null
& /*null*/)
862 EmitSeparationIfNecessary();
868 Emitter
& Emitter::Write(const Binary
& binary
)
870 Write(SecondaryTag("binary"));
876 EmitSeparationIfNecessary();
877 Utils::WriteBinary(m_stream
, binary
);