1 //===-- ValueObjectPrinter.cpp -------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/DataFormatters/ValueObjectPrinter.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Core/Debugger.h" 17 #include "lldb/DataFormatters/DataVisualization.h" 18 #include "lldb/Interpreter/CommandInterpreter.h" 19 #include "lldb/Target/Target.h" 20 21 using namespace lldb; 22 using namespace lldb_private; 23 24 DumpValueObjectOptions::DumpValueObjectOptions (ValueObject& valobj) : 25 DumpValueObjectOptions() 26 { 27 m_use_dynamic = valobj.GetDynamicValueType(); 28 m_use_synthetic = valobj.IsSynthetic(); 29 m_varformat_language = valobj.GetPreferredDisplayLanguage(); 30 } 31 32 ValueObjectPrinter::ValueObjectPrinter (ValueObject* valobj, 33 Stream* s) 34 { 35 if (valobj) 36 { 37 DumpValueObjectOptions options(*valobj); 38 Init (valobj,s,options,options.m_max_ptr_depth,0); 39 } 40 else 41 { 42 DumpValueObjectOptions options; 43 Init (valobj,s,options,options.m_max_ptr_depth,0); 44 } 45 } 46 47 ValueObjectPrinter::ValueObjectPrinter (ValueObject* valobj, 48 Stream* s, 49 const DumpValueObjectOptions& options) 50 { 51 Init(valobj,s,options,options.m_max_ptr_depth,0); 52 } 53 54 ValueObjectPrinter::ValueObjectPrinter (ValueObject* valobj, 55 Stream* s, 56 const DumpValueObjectOptions& options, 57 const DumpValueObjectOptions::PointerDepth& ptr_depth, 58 uint32_t curr_depth) 59 { 60 Init(valobj,s,options,ptr_depth,curr_depth); 61 } 62 63 void 64 ValueObjectPrinter::Init (ValueObject* valobj, 65 Stream* s, 66 const DumpValueObjectOptions& options, 67 const DumpValueObjectOptions::PointerDepth& ptr_depth, 68 uint32_t curr_depth) 69 { 70 m_orig_valobj = valobj; 71 m_valobj = nullptr; 72 m_stream = s; 73 this->options = options; 74 m_ptr_depth = ptr_depth; 75 m_curr_depth = curr_depth; 76 assert (m_orig_valobj && "cannot print a NULL ValueObject"); 77 assert (m_stream && "cannot print to a NULL Stream"); 78 m_should_print = eLazyBoolCalculate; 79 m_is_nil = eLazyBoolCalculate; 80 m_is_ptr = eLazyBoolCalculate; 81 m_is_ref = eLazyBoolCalculate; 82 m_is_aggregate = eLazyBoolCalculate; 83 m_summary_formatter = {nullptr,false}; 84 m_value.assign(""); 85 m_summary.assign(""); 86 m_error.assign(""); 87 } 88 89 bool 90 ValueObjectPrinter::PrintValueObject () 91 { 92 if (!GetMostSpecializedValue () || m_valobj == nullptr) 93 return false; 94 95 if (ShouldPrintValueObject()) 96 { 97 PrintValidationMarkerIfNeeded(); 98 99 PrintLocationIfNeeded(); 100 m_stream->Indent(); 101 102 bool show_type = PrintTypeIfNeeded(); 103 104 PrintNameIfNeeded(show_type); 105 } 106 107 bool value_printed = false; 108 bool summary_printed = false; 109 110 bool val_summary_ok = PrintValueAndSummaryIfNeeded (value_printed,summary_printed); 111 112 if (val_summary_ok) 113 PrintChildrenIfNeeded (value_printed, summary_printed); 114 else 115 m_stream->EOL(); 116 117 PrintValidationErrorIfNeeded(); 118 119 return true; 120 } 121 122 bool 123 ValueObjectPrinter::GetMostSpecializedValue () 124 { 125 if (m_valobj) 126 return true; 127 bool update_success = m_orig_valobj->UpdateValueIfNeeded (true); 128 if (!update_success) 129 { 130 m_valobj = m_orig_valobj; 131 } 132 else 133 { 134 if (m_orig_valobj->IsDynamic()) 135 { 136 if (options.m_use_dynamic == eNoDynamicValues) 137 { 138 ValueObject *static_value = m_orig_valobj->GetStaticValue().get(); 139 if (static_value) 140 m_valobj = static_value; 141 else 142 m_valobj = m_orig_valobj; 143 } 144 else 145 m_valobj = m_orig_valobj; 146 } 147 else 148 { 149 if (options.m_use_dynamic != eNoDynamicValues) 150 { 151 ValueObject *dynamic_value = m_orig_valobj->GetDynamicValue(options.m_use_dynamic).get(); 152 if (dynamic_value) 153 m_valobj = dynamic_value; 154 else 155 m_valobj = m_orig_valobj; 156 } 157 else 158 m_valobj = m_orig_valobj; 159 } 160 161 if (m_valobj->IsSynthetic()) 162 { 163 if (options.m_use_synthetic == false) 164 { 165 ValueObject *non_synthetic = m_valobj->GetNonSyntheticValue().get(); 166 if (non_synthetic) 167 m_valobj = non_synthetic; 168 } 169 } 170 else 171 { 172 if (options.m_use_synthetic == true) 173 { 174 ValueObject *synthetic = m_valobj->GetSyntheticValue().get(); 175 if (synthetic) 176 m_valobj = synthetic; 177 } 178 } 179 } 180 m_compiler_type = m_valobj->GetCompilerType(); 181 m_type_flags = m_compiler_type.GetTypeInfo (); 182 return true; 183 } 184 185 const char* 186 ValueObjectPrinter::GetDescriptionForDisplay () 187 { 188 const char* str = m_valobj->GetObjectDescription(); 189 if (!str) 190 str = m_valobj->GetSummaryAsCString(); 191 if (!str) 192 str = m_valobj->GetValueAsCString(); 193 return str; 194 } 195 196 const char* 197 ValueObjectPrinter::GetRootNameForDisplay (const char* if_fail) 198 { 199 const char *root_valobj_name = options.m_root_valobj_name.empty() ? 200 m_valobj->GetName().AsCString() : 201 options.m_root_valobj_name.c_str(); 202 return root_valobj_name ? root_valobj_name : if_fail; 203 } 204 205 bool 206 ValueObjectPrinter::ShouldPrintValueObject () 207 { 208 if (m_should_print == eLazyBoolCalculate) 209 m_should_print = (options.m_flat_output == false || m_type_flags.Test (eTypeHasValue)) ? eLazyBoolYes : eLazyBoolNo; 210 return m_should_print == eLazyBoolYes; 211 } 212 213 bool 214 ValueObjectPrinter::IsNil () 215 { 216 if (m_is_nil == eLazyBoolCalculate) 217 m_is_nil = m_valobj->IsObjCNil() ? eLazyBoolYes : eLazyBoolNo; 218 return m_is_nil == eLazyBoolYes; 219 } 220 221 bool 222 ValueObjectPrinter::IsPtr () 223 { 224 if (m_is_ptr == eLazyBoolCalculate) 225 m_is_ptr = m_type_flags.Test (eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo; 226 return m_is_ptr == eLazyBoolYes; 227 } 228 229 bool 230 ValueObjectPrinter::IsRef () 231 { 232 if (m_is_ref == eLazyBoolCalculate) 233 m_is_ref = m_type_flags.Test (eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo; 234 return m_is_ref == eLazyBoolYes; 235 } 236 237 bool 238 ValueObjectPrinter::IsAggregate () 239 { 240 if (m_is_aggregate == eLazyBoolCalculate) 241 m_is_aggregate = m_type_flags.Test (eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo; 242 return m_is_aggregate == eLazyBoolYes; 243 } 244 245 bool 246 ValueObjectPrinter::PrintLocationIfNeeded () 247 { 248 if (options.m_show_location) 249 { 250 m_stream->Printf("%s: ", m_valobj->GetLocationAsCString()); 251 return true; 252 } 253 return false; 254 } 255 256 bool 257 ValueObjectPrinter::PrintTypeIfNeeded () 258 { 259 bool show_type = true; 260 // if we are at the root-level and been asked to hide the root's type, then hide it 261 if (m_curr_depth == 0 && options.m_hide_root_type) 262 show_type = false; 263 else 264 // otherwise decide according to the usual rules (asked to show types - always at the root level) 265 show_type = options.m_show_types || (m_curr_depth == 0 && !options.m_flat_output); 266 267 if (show_type) 268 { 269 // Some ValueObjects don't have types (like registers sets). Only print 270 // the type if there is one to print 271 ConstString type_name; 272 if (options.m_use_type_display_name) 273 type_name = m_valobj->GetDisplayTypeName(); 274 else 275 type_name = m_valobj->GetQualifiedTypeName(); 276 if (type_name) 277 m_stream->Printf("(%s) ", type_name.GetCString()); 278 else 279 show_type = false; 280 } 281 return show_type; 282 } 283 284 bool 285 ValueObjectPrinter::PrintNameIfNeeded (bool show_type) 286 { 287 if (options.m_flat_output) 288 { 289 // If we are showing types, also qualify the C++ base classes 290 const bool qualify_cxx_base_classes = show_type; 291 if (!options.m_hide_name) 292 { 293 m_valobj->GetExpressionPath(*m_stream, qualify_cxx_base_classes); 294 m_stream->PutCString(" ="); 295 return true; 296 } 297 } 298 else if (!options.m_hide_name) 299 { 300 const char *name_cstr = GetRootNameForDisplay(""); 301 m_stream->Printf ("%s =", name_cstr); 302 return true; 303 } 304 return false; 305 } 306 307 bool 308 ValueObjectPrinter::CheckScopeIfNeeded () 309 { 310 if (options.m_scope_already_checked) 311 return true; 312 return m_valobj->IsInScope(); 313 } 314 315 TypeSummaryImpl* 316 ValueObjectPrinter::GetSummaryFormatter () 317 { 318 if (m_summary_formatter.second == false) 319 { 320 TypeSummaryImpl* entry = options.m_summary_sp ? options.m_summary_sp.get() : m_valobj->GetSummaryFormat().get(); 321 322 if (options.m_omit_summary_depth > 0) 323 entry = NULL; 324 m_summary_formatter.first = entry; 325 m_summary_formatter.second = true; 326 } 327 return m_summary_formatter.first; 328 } 329 330 void 331 ValueObjectPrinter::GetValueSummaryError (std::string& value, 332 std::string& summary, 333 std::string& error) 334 { 335 if (options.m_format != eFormatDefault && options.m_format != m_valobj->GetFormat()) 336 { 337 m_valobj->GetValueAsCString(options.m_format, 338 value); 339 } 340 else 341 { 342 const char* val_cstr = m_valobj->GetValueAsCString(); 343 if (val_cstr) 344 value.assign(val_cstr); 345 } 346 const char* err_cstr = m_valobj->GetError().AsCString(); 347 if (err_cstr) 348 error.assign(err_cstr); 349 350 if (ShouldPrintValueObject()) 351 { 352 if (IsNil()) 353 summary.assign("nil"); 354 else if (options.m_omit_summary_depth == 0) 355 { 356 TypeSummaryImpl* entry = GetSummaryFormatter(); 357 if (entry) 358 m_valobj->GetSummaryAsCString(entry, summary, options.m_varformat_language); 359 else 360 { 361 const char* sum_cstr = m_valobj->GetSummaryAsCString(options.m_varformat_language); 362 if (sum_cstr) 363 summary.assign(sum_cstr); 364 } 365 } 366 } 367 } 368 369 bool 370 ValueObjectPrinter::PrintValueAndSummaryIfNeeded (bool& value_printed, 371 bool& summary_printed) 372 { 373 bool error_printed = false; 374 if (ShouldPrintValueObject()) 375 { 376 if (!CheckScopeIfNeeded()) 377 m_error.assign("out of scope"); 378 if (m_error.empty()) 379 { 380 GetValueSummaryError(m_value, m_summary, m_error); 381 } 382 if (m_error.size()) 383 { 384 error_printed = true; 385 m_stream->Printf (" <%s>\n", m_error.c_str()); 386 } 387 else 388 { 389 // Make sure we have a value and make sure the summary didn't 390 // specify that the value should not be printed - and do not print 391 // the value if this thing is nil 392 // (but show the value if the user passes a format explicitly) 393 TypeSummaryImpl* entry = GetSummaryFormatter(); 394 if (!IsNil() && !m_value.empty() && (entry == NULL || (entry->DoesPrintValue(m_valobj) || options.m_format != eFormatDefault) || m_summary.empty()) && !options.m_hide_value) 395 { 396 m_stream->Printf(" %s", m_value.c_str()); 397 value_printed = true; 398 } 399 400 if (m_summary.size()) 401 { 402 m_stream->Printf(" %s", m_summary.c_str()); 403 summary_printed = true; 404 } 405 } 406 } 407 return !error_printed; 408 } 409 410 bool 411 ValueObjectPrinter::PrintObjectDescriptionIfNeeded (bool value_printed, 412 bool summary_printed) 413 { 414 if (ShouldPrintValueObject()) 415 { 416 // let's avoid the overly verbose no description error for a nil thing 417 if (options.m_use_objc && !IsNil()) 418 { 419 if (!options.m_hide_value || !options.m_hide_name) 420 m_stream->Printf(" "); 421 const char *object_desc = nullptr; 422 if (value_printed || summary_printed) 423 object_desc = m_valobj->GetObjectDescription(); 424 else 425 object_desc = GetDescriptionForDisplay(); 426 if (object_desc && *object_desc) 427 { 428 m_stream->Printf("%s\n", object_desc); 429 return true; 430 } 431 else if (value_printed == false && summary_printed == false) 432 return true; 433 else 434 return false; 435 } 436 } 437 return true; 438 } 439 440 bool 441 DumpValueObjectOptions::PointerDepth::CanAllowExpansion (bool is_root, 442 TypeSummaryImpl* entry, 443 ValueObject *valobj, 444 const std::string& summary) 445 { 446 switch (m_mode) 447 { 448 case Mode::Always: 449 return (m_count > 0); 450 case Mode::Never: 451 return false; 452 case Mode::Default: 453 if (is_root) 454 m_count = std::min<decltype(m_count)>(m_count,1); 455 return m_count > 0; 456 case Mode::Formatters: 457 if (!entry || entry->DoesPrintChildren(valobj) || summary.empty()) 458 return m_count > 0; 459 return false; 460 } 461 return false; 462 } 463 464 bool 465 DumpValueObjectOptions::PointerDepth::CanAllowExpansion () const 466 { 467 switch (m_mode) 468 { 469 case Mode::Always: 470 case Mode::Default: 471 case Mode::Formatters: 472 return (m_count > 0); 473 case Mode::Never: 474 return false; 475 } 476 return false; 477 } 478 479 bool 480 ValueObjectPrinter::ShouldPrintChildren (bool is_failed_description, 481 DumpValueObjectOptions::PointerDepth& curr_ptr_depth) 482 { 483 const bool is_ref = IsRef (); 484 const bool is_ptr = IsPtr (); 485 486 TypeSummaryImpl* entry = GetSummaryFormatter(); 487 488 if (is_failed_description || m_curr_depth < options.m_max_depth) 489 { 490 // We will show children for all concrete types. We won't show 491 // pointer contents unless a pointer depth has been specified. 492 // We won't reference contents unless the reference is the 493 // root object (depth of zero). 494 495 // Use a new temporary pointer depth in case we override the 496 // current pointer depth below... 497 498 if (is_ptr || is_ref) 499 { 500 // We have a pointer or reference whose value is an address. 501 // Make sure that address is not NULL 502 AddressType ptr_address_type; 503 if (m_valobj->GetPointerValue (&ptr_address_type) == 0) 504 return false; 505 506 const bool is_root_level = m_curr_depth == 0; 507 508 if (is_ref && 509 is_root_level) 510 { 511 // If this is the root object (depth is zero) that we are showing 512 // and it is a reference, and no pointer depth has been supplied 513 // print out what it references. Don't do this at deeper depths 514 // otherwise we can end up with infinite recursion... 515 return true; 516 } 517 518 return curr_ptr_depth.CanAllowExpansion(false, entry, m_valobj, m_summary); 519 } 520 521 return (!entry || entry->DoesPrintChildren(m_valobj) || m_summary.empty()); 522 } 523 return false; 524 } 525 526 bool 527 ValueObjectPrinter::ShouldExpandEmptyAggregates () 528 { 529 TypeSummaryImpl* entry = GetSummaryFormatter(); 530 531 if (!entry) 532 return true; 533 534 return entry->DoesPrintEmptyAggregates(); 535 } 536 537 ValueObject* 538 ValueObjectPrinter::GetValueObjectForChildrenGeneration () 539 { 540 return m_valobj; 541 } 542 543 void 544 ValueObjectPrinter::PrintChildrenPreamble () 545 { 546 if (options.m_flat_output) 547 { 548 if (ShouldPrintValueObject()) 549 m_stream->EOL(); 550 } 551 else 552 { 553 if (ShouldPrintValueObject()) 554 m_stream->PutCString(IsRef () ? ": {\n" : " {\n"); 555 m_stream->IndentMore(); 556 } 557 } 558 559 void 560 ValueObjectPrinter::PrintChild (ValueObjectSP child_sp, 561 const DumpValueObjectOptions::PointerDepth& curr_ptr_depth) 562 { 563 DumpValueObjectOptions child_options(options); 564 child_options.SetFormat(options.m_format).SetSummary().SetRootValueObjectName(); 565 child_options.SetScopeChecked(true).SetHideName(options.m_hide_name).SetHideValue(options.m_hide_value) 566 .SetOmitSummaryDepth(child_options.m_omit_summary_depth > 1 ? child_options.m_omit_summary_depth - 1 : 0); 567 if (child_sp.get()) 568 { 569 ValueObjectPrinter child_printer(child_sp.get(), 570 m_stream, 571 child_options, 572 (IsPtr() || IsRef()) ? --curr_ptr_depth : curr_ptr_depth, 573 m_curr_depth + 1); 574 child_printer.PrintValueObject(); 575 } 576 } 577 578 uint32_t 579 ValueObjectPrinter::GetMaxNumChildrenToPrint (bool& print_dotdotdot) 580 { 581 ValueObject* synth_m_valobj = GetValueObjectForChildrenGeneration(); 582 583 size_t num_children = synth_m_valobj->GetNumChildren(); 584 print_dotdotdot = false; 585 if (num_children) 586 { 587 const size_t max_num_children = m_valobj->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); 588 589 if (num_children > max_num_children && !options.m_ignore_cap) 590 { 591 print_dotdotdot = true; 592 return max_num_children; 593 } 594 } 595 return num_children; 596 } 597 598 void 599 ValueObjectPrinter::PrintChildrenPostamble (bool print_dotdotdot) 600 { 601 if (!options.m_flat_output) 602 { 603 if (print_dotdotdot) 604 { 605 m_valobj->GetTargetSP()->GetDebugger().GetCommandInterpreter().ChildrenTruncated(); 606 m_stream->Indent("...\n"); 607 } 608 m_stream->IndentLess(); 609 m_stream->Indent("}\n"); 610 } 611 } 612 613 void 614 ValueObjectPrinter::PrintChildren (bool value_printed, 615 bool summary_printed, 616 const DumpValueObjectOptions::PointerDepth& curr_ptr_depth) 617 { 618 ValueObject* synth_m_valobj = GetValueObjectForChildrenGeneration(); 619 620 bool print_dotdotdot = false; 621 size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot); 622 if (num_children) 623 { 624 PrintChildrenPreamble (); 625 626 for (size_t idx=0; idx<num_children; ++idx) 627 { 628 ValueObjectSP child_sp(synth_m_valobj->GetChildAtIndex(idx, true)); 629 PrintChild (child_sp, curr_ptr_depth); 630 } 631 632 PrintChildrenPostamble (print_dotdotdot); 633 } 634 else if (IsAggregate()) 635 { 636 // Aggregate, no children... 637 if (ShouldPrintValueObject()) 638 { 639 // if it has a synthetic value, then don't print {}, the synthetic children are probably only being used to vend a value 640 if (m_valobj->DoesProvideSyntheticValue() || !ShouldExpandEmptyAggregates()) 641 m_stream->PutCString( "\n"); 642 else 643 m_stream->PutCString(" {}\n"); 644 } 645 } 646 else 647 { 648 if (ShouldPrintValueObject()) 649 m_stream->EOL(); 650 } 651 } 652 653 bool 654 ValueObjectPrinter::PrintChildrenOneLiner (bool hide_names) 655 { 656 if (!GetMostSpecializedValue () || m_valobj == nullptr) 657 return false; 658 659 ValueObject* synth_m_valobj = GetValueObjectForChildrenGeneration(); 660 661 bool print_dotdotdot = false; 662 size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot); 663 664 if (num_children) 665 { 666 m_stream->PutChar('('); 667 668 for (uint32_t idx=0; idx<num_children; ++idx) 669 { 670 lldb::ValueObjectSP child_sp(synth_m_valobj->GetChildAtIndex(idx, true)); 671 if (child_sp) 672 child_sp = child_sp->GetQualifiedRepresentationIfAvailable(options.m_use_dynamic, options.m_use_synthetic); 673 if (child_sp) 674 { 675 if (idx) 676 m_stream->PutCString(", "); 677 if (!hide_names) 678 { 679 const char* name = child_sp.get()->GetName().AsCString(); 680 if (name && *name) 681 { 682 m_stream->PutCString(name); 683 m_stream->PutCString(" = "); 684 } 685 } 686 child_sp->DumpPrintableRepresentation(*m_stream, 687 ValueObject::eValueObjectRepresentationStyleSummary, 688 lldb::eFormatInvalid, 689 ValueObject::ePrintableRepresentationSpecialCasesDisable); 690 } 691 } 692 693 if (print_dotdotdot) 694 m_stream->PutCString(", ...)"); 695 else 696 m_stream->PutChar(')'); 697 } 698 return true; 699 } 700 701 void 702 ValueObjectPrinter::PrintChildrenIfNeeded (bool value_printed, 703 bool summary_printed) 704 { 705 // this flag controls whether we tried to display a description for this object and failed 706 // if that happens, we want to display the children, if any 707 bool is_failed_description = !PrintObjectDescriptionIfNeeded(value_printed, summary_printed); 708 709 auto curr_ptr_depth = m_ptr_depth; 710 bool print_children = ShouldPrintChildren (is_failed_description,curr_ptr_depth); 711 bool print_oneline = (curr_ptr_depth.CanAllowExpansion() || 712 options.m_show_types || 713 !options.m_allow_oneliner_mode || 714 options.m_flat_output || 715 options.m_show_location) ? false : DataVisualization::ShouldPrintAsOneLiner(*m_valobj); 716 717 if (print_children) 718 { 719 if (print_oneline) 720 { 721 m_stream->PutChar(' '); 722 PrintChildrenOneLiner (false); 723 m_stream->EOL(); 724 } 725 else 726 PrintChildren (value_printed, summary_printed, curr_ptr_depth); 727 } 728 else if (m_curr_depth >= options.m_max_depth && IsAggregate() && ShouldPrintValueObject()) 729 { 730 m_stream->PutCString("{...}\n"); 731 } 732 else 733 m_stream->EOL(); 734 } 735 736 bool 737 ValueObjectPrinter::ShouldPrintValidation () 738 { 739 return options.m_run_validator; 740 } 741 742 bool 743 ValueObjectPrinter::PrintValidationMarkerIfNeeded () 744 { 745 if (!ShouldPrintValidation()) 746 return false; 747 748 m_validation = m_valobj->GetValidationStatus(); 749 750 if (TypeValidatorResult::Failure == m_validation.first) 751 { 752 m_stream->Printf("! "); 753 return true; 754 } 755 756 return false; 757 } 758 759 bool 760 ValueObjectPrinter::PrintValidationErrorIfNeeded () 761 { 762 if (!ShouldPrintValidation()) 763 return false; 764 765 if (TypeValidatorResult::Success == m_validation.first) 766 return false; 767 768 if (m_validation.second.empty()) 769 m_validation.second.assign("unknown error"); 770 771 m_stream->Printf(" ! validation error: %s", m_validation.second.c_str()); 772 m_stream->EOL(); 773 774 return true; 775 } 776