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