yaml-cpp

FORK: A YAML parser and emitter in C++
git clone https://git.neptards.moe/neptards/yaml-cpp.git
Log | Files | Refs | README | LICENSE

emitter.cpp (23875B)


      1 #include <sstream>
      2 
      3 #include "emitterutils.h"
      4 #include "indentation.h"  // IWYU pragma: keep
      5 #include "yaml-cpp/emitter.h"
      6 #include "yaml-cpp/emitterdef.h"
      7 #include "yaml-cpp/emittermanip.h"
      8 #include "yaml-cpp/exceptions.h"  // IWYU pragma: keep
      9 
     10 namespace YAML {
     11 class Binary;
     12 struct _Null;
     13 
     14 Emitter::Emitter() : m_pState(new EmitterState), m_stream{} {}
     15 
     16 Emitter::Emitter(std::ostream& stream)
     17     : m_pState(new EmitterState), m_stream(stream) {}
     18 
     19 Emitter::~Emitter() = default;
     20 
     21 const char* Emitter::c_str() const { return m_stream.str(); }
     22 
     23 std::size_t Emitter::size() const { return m_stream.pos(); }
     24 
     25 // state checking
     26 bool Emitter::good() const { return m_pState->good(); }
     27 
     28 const std::string Emitter::GetLastError() const {
     29   return m_pState->GetLastError();
     30 }
     31 
     32 // global setters
     33 bool Emitter::SetOutputCharset(EMITTER_MANIP value) {
     34   return m_pState->SetOutputCharset(value, FmtScope::Global);
     35 }
     36 
     37 bool Emitter::SetStringFormat(EMITTER_MANIP value) {
     38   return m_pState->SetStringFormat(value, FmtScope::Global);
     39 }
     40 
     41 bool Emitter::SetBoolFormat(EMITTER_MANIP value) {
     42   bool ok = false;
     43   if (m_pState->SetBoolFormat(value, FmtScope::Global))
     44     ok = true;
     45   if (m_pState->SetBoolCaseFormat(value, FmtScope::Global))
     46     ok = true;
     47   if (m_pState->SetBoolLengthFormat(value, FmtScope::Global))
     48     ok = true;
     49   return ok;
     50 }
     51 
     52 bool Emitter::SetNullFormat(EMITTER_MANIP value) {
     53   return m_pState->SetNullFormat(value, FmtScope::Global);
     54 }
     55 
     56 bool Emitter::SetIntBase(EMITTER_MANIP value) {
     57   return m_pState->SetIntFormat(value, FmtScope::Global);
     58 }
     59 
     60 bool Emitter::SetSeqFormat(EMITTER_MANIP value) {
     61   return m_pState->SetFlowType(GroupType::Seq, value, FmtScope::Global);
     62 }
     63 
     64 bool Emitter::SetMapFormat(EMITTER_MANIP value) {
     65   bool ok = false;
     66   if (m_pState->SetFlowType(GroupType::Map, value, FmtScope::Global))
     67     ok = true;
     68   if (m_pState->SetMapKeyFormat(value, FmtScope::Global))
     69     ok = true;
     70   return ok;
     71 }
     72 
     73 bool Emitter::SetIndent(std::size_t n) {
     74   return m_pState->SetIndent(n, FmtScope::Global);
     75 }
     76 
     77 bool Emitter::SetPreCommentIndent(std::size_t n) {
     78   return m_pState->SetPreCommentIndent(n, FmtScope::Global);
     79 }
     80 
     81 bool Emitter::SetPostCommentIndent(std::size_t n) {
     82   return m_pState->SetPostCommentIndent(n, FmtScope::Global);
     83 }
     84 
     85 bool Emitter::SetFloatPrecision(std::size_t n) {
     86   return m_pState->SetFloatPrecision(n, FmtScope::Global);
     87 }
     88 
     89 bool Emitter::SetDoublePrecision(std::size_t n) {
     90   return m_pState->SetDoublePrecision(n, FmtScope::Global);
     91 }
     92 
     93 void Emitter::RestoreGlobalModifiedSettings() {
     94   m_pState->RestoreGlobalModifiedSettings();
     95 }
     96 
     97 // SetLocalValue
     98 // . Either start/end a group, or set a modifier locally
     99 Emitter& Emitter::SetLocalValue(EMITTER_MANIP value) {
    100   if (!good())
    101     return *this;
    102 
    103   switch (value) {
    104     case BeginDoc:
    105       EmitBeginDoc();
    106       break;
    107     case EndDoc:
    108       EmitEndDoc();
    109       break;
    110     case BeginSeq:
    111       EmitBeginSeq();
    112       break;
    113     case EndSeq:
    114       EmitEndSeq();
    115       break;
    116     case BeginMap:
    117       EmitBeginMap();
    118       break;
    119     case EndMap:
    120       EmitEndMap();
    121       break;
    122     case Key:
    123     case Value:
    124       // deprecated (these can be deduced by the parity of nodes in a map)
    125       break;
    126     case TagByKind:
    127       EmitKindTag();
    128       break;
    129     case Newline:
    130       EmitNewline();
    131       break;
    132     default:
    133       m_pState->SetLocalValue(value);
    134       break;
    135   }
    136   return *this;
    137 }
    138 
    139 Emitter& Emitter::SetLocalIndent(const _Indent& indent) {
    140   m_pState->SetIndent(indent.value, FmtScope::Local);
    141   return *this;
    142 }
    143 
    144 Emitter& Emitter::SetLocalPrecision(const _Precision& precision) {
    145   if (precision.floatPrecision >= 0)
    146     m_pState->SetFloatPrecision(precision.floatPrecision, FmtScope::Local);
    147   if (precision.doublePrecision >= 0)
    148     m_pState->SetDoublePrecision(precision.doublePrecision, FmtScope::Local);
    149   return *this;
    150 }
    151 
    152 // EmitBeginDoc
    153 void Emitter::EmitBeginDoc() {
    154   if (!good())
    155     return;
    156 
    157   if (m_pState->CurGroupType() != GroupType::NoType) {
    158     m_pState->SetError("Unexpected begin document");
    159     return;
    160   }
    161 
    162   if (m_pState->HasAnchor() || m_pState->HasTag()) {
    163     m_pState->SetError("Unexpected begin document");
    164     return;
    165   }
    166 
    167   if (m_stream.col() > 0)
    168     m_stream << "\n";
    169   m_stream << "---\n";
    170 
    171   m_pState->StartedDoc();
    172 }
    173 
    174 // EmitEndDoc
    175 void Emitter::EmitEndDoc() {
    176   if (!good())
    177     return;
    178 
    179   if (m_pState->CurGroupType() != GroupType::NoType) {
    180     m_pState->SetError("Unexpected begin document");
    181     return;
    182   }
    183 
    184   if (m_pState->HasAnchor() || m_pState->HasTag()) {
    185     m_pState->SetError("Unexpected begin document");
    186     return;
    187   }
    188 
    189   if (m_stream.col() > 0)
    190     m_stream << "\n";
    191   m_stream << "...\n";
    192 }
    193 
    194 // EmitBeginSeq
    195 void Emitter::EmitBeginSeq() {
    196   if (!good())
    197     return;
    198 
    199   PrepareNode(m_pState->NextGroupType(GroupType::Seq));
    200 
    201   m_pState->StartedGroup(GroupType::Seq);
    202 }
    203 
    204 // EmitEndSeq
    205 void Emitter::EmitEndSeq() {
    206   if (!good())
    207     return;
    208   FlowType::value originalType = m_pState->CurGroupFlowType();
    209 
    210   if (m_pState->CurGroupChildCount() == 0)
    211     m_pState->ForceFlow();
    212 
    213   if (m_pState->CurGroupFlowType() == FlowType::Flow) {
    214     if (m_stream.comment())
    215       m_stream << "\n";
    216     m_stream << IndentTo(m_pState->CurIndent());
    217     if (originalType == FlowType::Block) {
    218       m_stream << "[";
    219     } else {
    220       if (m_pState->CurGroupChildCount() == 0 && !m_pState->HasBegunNode())
    221         m_stream << "[";
    222     }
    223     m_stream << "]";
    224   }
    225 
    226   m_pState->EndedGroup(GroupType::Seq);
    227 }
    228 
    229 // EmitBeginMap
    230 void Emitter::EmitBeginMap() {
    231   if (!good())
    232     return;
    233 
    234   PrepareNode(m_pState->NextGroupType(GroupType::Map));
    235 
    236   m_pState->StartedGroup(GroupType::Map);
    237 }
    238 
    239 // EmitEndMap
    240 void Emitter::EmitEndMap() {
    241   if (!good())
    242     return;
    243   FlowType::value originalType = m_pState->CurGroupFlowType();
    244 
    245   if (m_pState->CurGroupChildCount() == 0)
    246     m_pState->ForceFlow();
    247 
    248   if (m_pState->CurGroupFlowType() == FlowType::Flow) {
    249     if (m_stream.comment())
    250       m_stream << "\n";
    251     m_stream << IndentTo(m_pState->CurIndent());
    252     if (originalType == FlowType::Block) {
    253       m_stream << "{";
    254     } else {
    255       if (m_pState->CurGroupChildCount() == 0 && !m_pState->HasBegunNode())
    256         m_stream << "{";
    257     }
    258     m_stream << "}";
    259   }
    260 
    261   m_pState->EndedGroup(GroupType::Map);
    262 }
    263 
    264 // EmitNewline
    265 void Emitter::EmitNewline() {
    266   if (!good())
    267     return;
    268 
    269   PrepareNode(EmitterNodeType::NoType);
    270   m_stream << "\n";
    271   m_pState->SetNonContent();
    272 }
    273 
    274 bool Emitter::CanEmitNewline() const { return true; }
    275 
    276 // Put the stream in a state so we can simply write the next node
    277 // E.g., if we're in a sequence, write the "- "
    278 void Emitter::PrepareNode(EmitterNodeType::value child) {
    279   switch (m_pState->CurGroupNodeType()) {
    280     case EmitterNodeType::NoType:
    281       PrepareTopNode(child);
    282       break;
    283     case EmitterNodeType::FlowSeq:
    284       FlowSeqPrepareNode(child);
    285       break;
    286     case EmitterNodeType::BlockSeq:
    287       BlockSeqPrepareNode(child);
    288       break;
    289     case EmitterNodeType::FlowMap:
    290       FlowMapPrepareNode(child);
    291       break;
    292     case EmitterNodeType::BlockMap:
    293       BlockMapPrepareNode(child);
    294       break;
    295     case EmitterNodeType::Property:
    296     case EmitterNodeType::Scalar:
    297       assert(false);
    298       break;
    299   }
    300 }
    301 
    302 void Emitter::PrepareTopNode(EmitterNodeType::value child) {
    303   if (child == EmitterNodeType::NoType)
    304     return;
    305 
    306   if (m_pState->CurGroupChildCount() > 0 && m_stream.col() > 0)
    307     EmitBeginDoc();
    308 
    309   switch (child) {
    310     case EmitterNodeType::NoType:
    311       break;
    312     case EmitterNodeType::Property:
    313     case EmitterNodeType::Scalar:
    314     case EmitterNodeType::FlowSeq:
    315     case EmitterNodeType::FlowMap:
    316       // TODO: if we were writing null, and
    317       // we wanted it blank, we wouldn't want a space
    318       SpaceOrIndentTo(m_pState->HasBegunContent(), 0);
    319       break;
    320     case EmitterNodeType::BlockSeq:
    321     case EmitterNodeType::BlockMap:
    322       if (m_pState->HasBegunNode())
    323         m_stream << "\n";
    324       break;
    325   }
    326 }
    327 
    328 void Emitter::FlowSeqPrepareNode(EmitterNodeType::value child) {
    329   const std::size_t lastIndent = m_pState->LastIndent();
    330 
    331   if (!m_pState->HasBegunNode()) {
    332     if (m_stream.comment())
    333       m_stream << "\n";
    334     m_stream << IndentTo(lastIndent);
    335     if (m_pState->CurGroupChildCount() == 0)
    336       m_stream << "[";
    337     else
    338       m_stream << ",";
    339   }
    340 
    341   switch (child) {
    342     case EmitterNodeType::NoType:
    343       break;
    344     case EmitterNodeType::Property:
    345     case EmitterNodeType::Scalar:
    346     case EmitterNodeType::FlowSeq:
    347     case EmitterNodeType::FlowMap:
    348       SpaceOrIndentTo(
    349           m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0,
    350           lastIndent);
    351       break;
    352     case EmitterNodeType::BlockSeq:
    353     case EmitterNodeType::BlockMap:
    354       assert(false);
    355       break;
    356   }
    357 }
    358 
    359 void Emitter::BlockSeqPrepareNode(EmitterNodeType::value child) {
    360   const std::size_t curIndent = m_pState->CurIndent();
    361   const std::size_t nextIndent = curIndent + m_pState->CurGroupIndent();
    362 
    363   if (child == EmitterNodeType::NoType)
    364     return;
    365 
    366   if (!m_pState->HasBegunContent()) {
    367     if (m_pState->CurGroupChildCount() > 0 || m_stream.comment()) {
    368       m_stream << "\n";
    369     }
    370     m_stream << IndentTo(curIndent);
    371     m_stream << "-";
    372   }
    373 
    374   switch (child) {
    375     case EmitterNodeType::NoType:
    376       break;
    377     case EmitterNodeType::Property:
    378     case EmitterNodeType::Scalar:
    379     case EmitterNodeType::FlowSeq:
    380     case EmitterNodeType::FlowMap:
    381       SpaceOrIndentTo(m_pState->HasBegunContent(), nextIndent);
    382       break;
    383     case EmitterNodeType::BlockSeq:
    384       m_stream << "\n";
    385       break;
    386     case EmitterNodeType::BlockMap:
    387       if (m_pState->HasBegunContent() || m_stream.comment())
    388         m_stream << "\n";
    389       break;
    390   }
    391 }
    392 
    393 void Emitter::FlowMapPrepareNode(EmitterNodeType::value child) {
    394   if (m_pState->CurGroupChildCount() % 2 == 0) {
    395     if (m_pState->GetMapKeyFormat() == LongKey)
    396       m_pState->SetLongKey();
    397 
    398     if (m_pState->CurGroupLongKey())
    399       FlowMapPrepareLongKey(child);
    400     else
    401       FlowMapPrepareSimpleKey(child);
    402   } else {
    403     if (m_pState->CurGroupLongKey())
    404       FlowMapPrepareLongKeyValue(child);
    405     else
    406       FlowMapPrepareSimpleKeyValue(child);
    407   }
    408 }
    409 
    410 void Emitter::FlowMapPrepareLongKey(EmitterNodeType::value child) {
    411   const std::size_t lastIndent = m_pState->LastIndent();
    412 
    413   if (!m_pState->HasBegunNode()) {
    414     if (m_stream.comment())
    415       m_stream << "\n";
    416     m_stream << IndentTo(lastIndent);
    417     if (m_pState->CurGroupChildCount() == 0)
    418       m_stream << "{ ?";
    419     else
    420       m_stream << ", ?";
    421   }
    422 
    423   switch (child) {
    424     case EmitterNodeType::NoType:
    425       break;
    426     case EmitterNodeType::Property:
    427     case EmitterNodeType::Scalar:
    428     case EmitterNodeType::FlowSeq:
    429     case EmitterNodeType::FlowMap:
    430       SpaceOrIndentTo(
    431           m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0,
    432           lastIndent);
    433       break;
    434     case EmitterNodeType::BlockSeq:
    435     case EmitterNodeType::BlockMap:
    436       assert(false);
    437       break;
    438   }
    439 }
    440 
    441 void Emitter::FlowMapPrepareLongKeyValue(EmitterNodeType::value child) {
    442   const std::size_t lastIndent = m_pState->LastIndent();
    443 
    444   if (!m_pState->HasBegunNode()) {
    445     if (m_stream.comment())
    446       m_stream << "\n";
    447     m_stream << IndentTo(lastIndent);
    448     m_stream << ":";
    449   }
    450 
    451   switch (child) {
    452     case EmitterNodeType::NoType:
    453       break;
    454     case EmitterNodeType::Property:
    455     case EmitterNodeType::Scalar:
    456     case EmitterNodeType::FlowSeq:
    457     case EmitterNodeType::FlowMap:
    458       SpaceOrIndentTo(
    459           m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0,
    460           lastIndent);
    461       break;
    462     case EmitterNodeType::BlockSeq:
    463     case EmitterNodeType::BlockMap:
    464       assert(false);
    465       break;
    466   }
    467 }
    468 
    469 void Emitter::FlowMapPrepareSimpleKey(EmitterNodeType::value child) {
    470   const std::size_t lastIndent = m_pState->LastIndent();
    471 
    472   if (!m_pState->HasBegunNode()) {
    473     if (m_stream.comment())
    474       m_stream << "\n";
    475     m_stream << IndentTo(lastIndent);
    476     if (m_pState->CurGroupChildCount() == 0)
    477       m_stream << "{";
    478     else
    479       m_stream << ",";
    480   }
    481 
    482   switch (child) {
    483     case EmitterNodeType::NoType:
    484       break;
    485     case EmitterNodeType::Property:
    486     case EmitterNodeType::Scalar:
    487     case EmitterNodeType::FlowSeq:
    488     case EmitterNodeType::FlowMap:
    489       SpaceOrIndentTo(
    490           m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0,
    491           lastIndent);
    492       break;
    493     case EmitterNodeType::BlockSeq:
    494     case EmitterNodeType::BlockMap:
    495       assert(false);
    496       break;
    497   }
    498 }
    499 
    500 void Emitter::FlowMapPrepareSimpleKeyValue(EmitterNodeType::value child) {
    501   const std::size_t lastIndent = m_pState->LastIndent();
    502 
    503   if (!m_pState->HasBegunNode()) {
    504     if (m_stream.comment())
    505       m_stream << "\n";
    506     m_stream << IndentTo(lastIndent);
    507     if (m_pState->HasAlias()) {
    508       m_stream << " ";
    509     }
    510     m_stream << ":";
    511   }
    512 
    513   switch (child) {
    514     case EmitterNodeType::NoType:
    515       break;
    516     case EmitterNodeType::Property:
    517     case EmitterNodeType::Scalar:
    518     case EmitterNodeType::FlowSeq:
    519     case EmitterNodeType::FlowMap:
    520       SpaceOrIndentTo(
    521           m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0,
    522           lastIndent);
    523       break;
    524     case EmitterNodeType::BlockSeq:
    525     case EmitterNodeType::BlockMap:
    526       assert(false);
    527       break;
    528   }
    529 }
    530 
    531 void Emitter::BlockMapPrepareNode(EmitterNodeType::value child) {
    532   if (m_pState->CurGroupChildCount() % 2 == 0) {
    533     if (m_pState->GetMapKeyFormat() == LongKey)
    534       m_pState->SetLongKey();
    535     if (child == EmitterNodeType::BlockSeq ||
    536         child == EmitterNodeType::BlockMap)
    537       m_pState->SetLongKey();
    538 
    539     if (m_pState->CurGroupLongKey())
    540       BlockMapPrepareLongKey(child);
    541     else
    542       BlockMapPrepareSimpleKey(child);
    543   } else {
    544     if (m_pState->CurGroupLongKey())
    545       BlockMapPrepareLongKeyValue(child);
    546     else
    547       BlockMapPrepareSimpleKeyValue(child);
    548   }
    549 }
    550 
    551 void Emitter::BlockMapPrepareLongKey(EmitterNodeType::value child) {
    552   const std::size_t curIndent = m_pState->CurIndent();
    553   const std::size_t childCount = m_pState->CurGroupChildCount();
    554 
    555   if (child == EmitterNodeType::NoType)
    556     return;
    557 
    558   if (!m_pState->HasBegunContent()) {
    559     if (childCount > 0) {
    560       m_stream << "\n";
    561     }
    562     if (m_stream.comment()) {
    563       m_stream << "\n";
    564     }
    565     m_stream << IndentTo(curIndent);
    566     m_stream << "?";
    567   }
    568 
    569   switch (child) {
    570     case EmitterNodeType::NoType:
    571       break;
    572     case EmitterNodeType::Property:
    573     case EmitterNodeType::Scalar:
    574     case EmitterNodeType::FlowSeq:
    575     case EmitterNodeType::FlowMap:
    576       SpaceOrIndentTo(true, curIndent + 1);
    577       break;
    578     case EmitterNodeType::BlockSeq:
    579     case EmitterNodeType::BlockMap:
    580       if (m_pState->HasBegunContent())
    581         m_stream << "\n";
    582       break;
    583   }
    584 }
    585 
    586 void Emitter::BlockMapPrepareLongKeyValue(EmitterNodeType::value child) {
    587   const std::size_t curIndent = m_pState->CurIndent();
    588 
    589   if (child == EmitterNodeType::NoType)
    590     return;
    591 
    592   if (!m_pState->HasBegunContent()) {
    593     m_stream << "\n";
    594     m_stream << IndentTo(curIndent);
    595     m_stream << ":";
    596   }
    597 
    598   switch (child) {
    599     case EmitterNodeType::NoType:
    600       break;
    601     case EmitterNodeType::Property:
    602     case EmitterNodeType::Scalar:
    603     case EmitterNodeType::FlowSeq:
    604     case EmitterNodeType::FlowMap:
    605       SpaceOrIndentTo(true, curIndent + 1);
    606       break;
    607     case EmitterNodeType::BlockSeq:
    608     case EmitterNodeType::BlockMap:
    609       if (m_pState->HasBegunContent())
    610         m_stream << "\n";
    611       SpaceOrIndentTo(true, curIndent + 1);
    612       break;
    613   }
    614 }
    615 
    616 void Emitter::BlockMapPrepareSimpleKey(EmitterNodeType::value child) {
    617   const std::size_t curIndent = m_pState->CurIndent();
    618   const std::size_t childCount = m_pState->CurGroupChildCount();
    619 
    620   if (child == EmitterNodeType::NoType)
    621     return;
    622 
    623   if (!m_pState->HasBegunNode()) {
    624     if (childCount > 0) {
    625       m_stream << "\n";
    626     }
    627   }
    628 
    629   switch (child) {
    630     case EmitterNodeType::NoType:
    631       break;
    632     case EmitterNodeType::Property:
    633     case EmitterNodeType::Scalar:
    634     case EmitterNodeType::FlowSeq:
    635     case EmitterNodeType::FlowMap:
    636       SpaceOrIndentTo(m_pState->HasBegunContent(), curIndent);
    637       break;
    638     case EmitterNodeType::BlockSeq:
    639     case EmitterNodeType::BlockMap:
    640       break;
    641   }
    642 }
    643 
    644 void Emitter::BlockMapPrepareSimpleKeyValue(EmitterNodeType::value child) {
    645   const std::size_t curIndent = m_pState->CurIndent();
    646   const std::size_t nextIndent = curIndent + m_pState->CurGroupIndent();
    647 
    648   if (!m_pState->HasBegunNode()) {
    649     if (m_pState->HasAlias()) {
    650       m_stream << " ";
    651     }
    652     m_stream << ":";
    653   }
    654 
    655   switch (child) {
    656     case EmitterNodeType::NoType:
    657       break;
    658     case EmitterNodeType::Property:
    659     case EmitterNodeType::Scalar:
    660     case EmitterNodeType::FlowSeq:
    661     case EmitterNodeType::FlowMap:
    662       SpaceOrIndentTo(true, nextIndent);
    663       break;
    664     case EmitterNodeType::BlockSeq:
    665     case EmitterNodeType::BlockMap:
    666       m_stream << "\n";
    667       break;
    668   }
    669 }
    670 
    671 // SpaceOrIndentTo
    672 // . Prepares for some more content by proper spacing
    673 void Emitter::SpaceOrIndentTo(bool requireSpace, std::size_t indent) {
    674   if (m_stream.comment())
    675     m_stream << "\n";
    676   if (m_stream.col() > 0 && requireSpace)
    677     m_stream << " ";
    678   m_stream << IndentTo(indent);
    679 }
    680 
    681 void Emitter::PrepareIntegralStream(std::stringstream& stream) const {
    682 
    683   switch (m_pState->GetIntFormat()) {
    684     case Dec:
    685       stream << std::dec;
    686       break;
    687     case Hex:
    688       stream << "0x";
    689       stream << std::hex;
    690       break;
    691     case Oct:
    692       stream << "0";
    693       stream << std::oct;
    694       break;
    695     default:
    696       assert(false);
    697   }
    698 }
    699 
    700 void Emitter::StartedScalar() { m_pState->StartedScalar(); }
    701 
    702 // *******************************************************************************************
    703 // overloads of Write
    704 
    705 StringEscaping::value GetStringEscapingStyle(const EMITTER_MANIP emitterManip) {
    706   switch (emitterManip) {
    707     case EscapeNonAscii:
    708       return StringEscaping::NonAscii;
    709     case EscapeAsJson:
    710       return StringEscaping::JSON;
    711     default:
    712       return StringEscaping::None;
    713       break;
    714   }
    715 }
    716 
    717 Emitter& Emitter::Write(const std::string& str) {
    718   if (!good())
    719     return *this;
    720 
    721   StringEscaping::value stringEscaping = GetStringEscapingStyle(m_pState->GetOutputCharset());
    722 
    723   const StringFormat::value strFormat =
    724       Utils::ComputeStringFormat(str, m_pState->GetStringFormat(),
    725                                  m_pState->CurGroupFlowType(), stringEscaping == StringEscaping::NonAscii);
    726 
    727   if (strFormat == StringFormat::Literal || str.size() > 1024)
    728     m_pState->SetMapKeyFormat(YAML::LongKey, FmtScope::Local);
    729 
    730   PrepareNode(EmitterNodeType::Scalar);
    731 
    732   switch (strFormat) {
    733     case StringFormat::Plain:
    734       m_stream << str;
    735       break;
    736     case StringFormat::SingleQuoted:
    737       Utils::WriteSingleQuotedString(m_stream, str);
    738       break;
    739     case StringFormat::DoubleQuoted:
    740       Utils::WriteDoubleQuotedString(m_stream, str, stringEscaping);
    741       break;
    742     case StringFormat::Literal:
    743       Utils::WriteLiteralString(m_stream, str,
    744                                 m_pState->CurIndent() + m_pState->GetIndent());
    745       break;
    746   }
    747 
    748   StartedScalar();
    749 
    750   return *this;
    751 }
    752 
    753 std::size_t Emitter::GetFloatPrecision() const {
    754   return m_pState->GetFloatPrecision();
    755 }
    756 
    757 std::size_t Emitter::GetDoublePrecision() const {
    758   return m_pState->GetDoublePrecision();
    759 }
    760 
    761 const char* Emitter::ComputeFullBoolName(bool b) const {
    762   const EMITTER_MANIP mainFmt = (m_pState->GetBoolLengthFormat() == ShortBool
    763                                      ? YesNoBool
    764                                      : m_pState->GetBoolFormat());
    765   const EMITTER_MANIP caseFmt = m_pState->GetBoolCaseFormat();
    766   switch (mainFmt) {
    767     case YesNoBool:
    768       switch (caseFmt) {
    769         case UpperCase:
    770           return b ? "YES" : "NO";
    771         case CamelCase:
    772           return b ? "Yes" : "No";
    773         case LowerCase:
    774           return b ? "yes" : "no";
    775         default:
    776           break;
    777       }
    778       break;
    779     case OnOffBool:
    780       switch (caseFmt) {
    781         case UpperCase:
    782           return b ? "ON" : "OFF";
    783         case CamelCase:
    784           return b ? "On" : "Off";
    785         case LowerCase:
    786           return b ? "on" : "off";
    787         default:
    788           break;
    789       }
    790       break;
    791     case TrueFalseBool:
    792       switch (caseFmt) {
    793         case UpperCase:
    794           return b ? "TRUE" : "FALSE";
    795         case CamelCase:
    796           return b ? "True" : "False";
    797         case LowerCase:
    798           return b ? "true" : "false";
    799         default:
    800           break;
    801       }
    802       break;
    803     default:
    804       break;
    805   }
    806   return b ? "y" : "n";  // should never get here, but it can't hurt to give
    807                          // these answers
    808 }
    809 
    810 const char* Emitter::ComputeNullName() const {
    811   switch (m_pState->GetNullFormat()) {
    812     case LowerNull:
    813       return "null";
    814     case UpperNull:
    815       return "NULL";
    816     case CamelNull:
    817       return "Null";
    818     case TildeNull:
    819       // fallthrough
    820     default:
    821       return "~";
    822   }
    823 }
    824 
    825 Emitter& Emitter::Write(bool b) {
    826   if (!good())
    827     return *this;
    828 
    829   PrepareNode(EmitterNodeType::Scalar);
    830 
    831   const char* name = ComputeFullBoolName(b);
    832   if (m_pState->GetBoolLengthFormat() == ShortBool)
    833     m_stream << name[0];
    834   else
    835     m_stream << name;
    836 
    837   StartedScalar();
    838 
    839   return *this;
    840 }
    841 
    842 Emitter& Emitter::Write(char ch) {
    843   if (!good())
    844     return *this;
    845 
    846 
    847 
    848   PrepareNode(EmitterNodeType::Scalar);
    849   Utils::WriteChar(m_stream, ch, GetStringEscapingStyle(m_pState->GetOutputCharset()));
    850   StartedScalar();
    851 
    852   return *this;
    853 }
    854 
    855 Emitter& Emitter::Write(const _Alias& alias) {
    856   if (!good())
    857     return *this;
    858 
    859   if (m_pState->HasAnchor() || m_pState->HasTag()) {
    860     m_pState->SetError(ErrorMsg::INVALID_ALIAS);
    861     return *this;
    862   }
    863 
    864   PrepareNode(EmitterNodeType::Scalar);
    865 
    866   if (!Utils::WriteAlias(m_stream, alias.content)) {
    867     m_pState->SetError(ErrorMsg::INVALID_ALIAS);
    868     return *this;
    869   }
    870 
    871   StartedScalar();
    872 
    873   m_pState->SetAlias();
    874 
    875   return *this;
    876 }
    877 
    878 Emitter& Emitter::Write(const _Anchor& anchor) {
    879   if (!good())
    880     return *this;
    881 
    882   if (m_pState->HasAnchor()) {
    883     m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
    884     return *this;
    885   }
    886 
    887   PrepareNode(EmitterNodeType::Property);
    888 
    889   if (!Utils::WriteAnchor(m_stream, anchor.content)) {
    890     m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
    891     return *this;
    892   }
    893 
    894   m_pState->SetAnchor();
    895 
    896   return *this;
    897 }
    898 
    899 Emitter& Emitter::Write(const _Tag& tag) {
    900   if (!good())
    901     return *this;
    902 
    903   if (m_pState->HasTag()) {
    904     m_pState->SetError(ErrorMsg::INVALID_TAG);
    905     return *this;
    906   }
    907 
    908   PrepareNode(EmitterNodeType::Property);
    909 
    910   bool success = false;
    911   if (tag.type == _Tag::Type::Verbatim)
    912     success = Utils::WriteTag(m_stream, tag.content, true);
    913   else if (tag.type == _Tag::Type::PrimaryHandle)
    914     success = Utils::WriteTag(m_stream, tag.content, false);
    915   else
    916     success = Utils::WriteTagWithPrefix(m_stream, tag.prefix, tag.content);
    917 
    918   if (!success) {
    919     m_pState->SetError(ErrorMsg::INVALID_TAG);
    920     return *this;
    921   }
    922 
    923   m_pState->SetTag();
    924 
    925   return *this;
    926 }
    927 
    928 void Emitter::EmitKindTag() { Write(LocalTag("")); }
    929 
    930 Emitter& Emitter::Write(const _Comment& comment) {
    931   if (!good())
    932     return *this;
    933 
    934   PrepareNode(EmitterNodeType::NoType);
    935 
    936   if (m_stream.col() > 0)
    937     m_stream << Indentation(m_pState->GetPreCommentIndent());
    938   Utils::WriteComment(m_stream, comment.content,
    939                       m_pState->GetPostCommentIndent());
    940 
    941   m_pState->SetNonContent();
    942 
    943   return *this;
    944 }
    945 
    946 Emitter& Emitter::Write(const _Null& /*null*/) {
    947   if (!good())
    948     return *this;
    949 
    950   PrepareNode(EmitterNodeType::Scalar);
    951 
    952   m_stream << ComputeNullName();
    953 
    954   StartedScalar();
    955 
    956   return *this;
    957 }
    958 
    959 Emitter& Emitter::Write(const Binary& binary) {
    960   Write(SecondaryTag("binary"));
    961 
    962   if (!good())
    963     return *this;
    964 
    965   PrepareNode(EmitterNodeType::Scalar);
    966   Utils::WriteBinary(m_stream, binary);
    967   StartedScalar();
    968 
    969   return *this;
    970 }
    971 }  // namespace YAML