void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const { bool first = true; s << "{"; if (pretty_print) { s << "\n"; s.IndentMore(); } for (const auto &pair : m_dict) { if (first) first = false; else { s << ","; if (pretty_print) s << "\n"; } if (pretty_print) s.Indent(); s << "\"" << pair.first.AsCString() << "\" : "; pair.second->Dump(s, pretty_print); } if (pretty_print) { s.IndentLess(); s.EOL(); s.Indent(); } s << "}"; }
void StructuredData::Array::Dump(Stream &s, bool pretty_print) const { bool first = true; s << "["; if (pretty_print) { s << "\n"; s.IndentMore(); } for (const auto &item_sp : m_items) { if (first) { first = false; } else { s << ","; if (pretty_print) s << "\n"; } if (pretty_print) s.Indent(); item_sp->Dump(s, pretty_print); } if (pretty_print) { s.IndentLess(); s.EOL(); s.Indent(); } s << "]"; }
size_t StackFrameList::GetStatus (Stream& strm, uint32_t first_frame, uint32_t num_frames, bool show_frame_info, uint32_t num_frames_with_source, const char *selected_frame_marker) { size_t num_frames_displayed = 0; if (num_frames == 0) return 0; StackFrameSP frame_sp; uint32_t frame_idx = 0; uint32_t last_frame; // Don't let the last frame wrap around... if (num_frames == UINT32_MAX) last_frame = UINT32_MAX; else last_frame = first_frame + num_frames; StackFrameSP selected_frame_sp = m_thread.GetSelectedFrame(); const char *unselected_marker = NULL; std::string buffer; if (selected_frame_marker) { size_t len = strlen(selected_frame_marker); buffer.insert(buffer.begin(), len, ' '); unselected_marker = buffer.c_str(); } const char *marker = NULL; for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx) { frame_sp = GetFrameAtIndex(frame_idx); if (frame_sp.get() == NULL) break; if (selected_frame_marker != NULL) { if (frame_sp == selected_frame_sp) marker = selected_frame_marker; else marker = unselected_marker; } if (!frame_sp->GetStatus (strm, show_frame_info, num_frames_with_source > (first_frame - frame_idx), marker)) break; ++num_frames_displayed; } strm.IndentLess(); return num_frames_displayed; }
void OptionValueDictionary::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) { const Type dict_type = ConvertTypeMaskToType (m_type_mask); if (dump_mask & eDumpOptionType) { if (m_type_mask != eTypeInvalid) strm.Printf ("(%s of %ss)", GetTypeAsCString(), GetBuiltinTypeAsCString(dict_type)); else strm.Printf ("(%s)", GetTypeAsCString()); } if (dump_mask & eDumpOptionValue) { if (dump_mask & eDumpOptionType) strm.PutCString (" ="); collection::iterator pos, end = m_values.end(); strm.IndentMore(); for (pos = m_values.begin(); pos != end; ++pos) { OptionValue *option_value = pos->second.get(); strm.EOL(); strm.Indent(pos->first.GetCString()); const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0; switch (dict_type) { default: case eTypeArray: case eTypeDictionary: case eTypeProperties: case eTypeFileSpecList: case eTypePathMap: strm.PutChar (' '); option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options); break; case eTypeBoolean: case eTypeChar: case eTypeEnum: case eTypeFileSpec: case eTypeFormat: case eTypeSInt64: case eTypeString: case eTypeUInt64: case eTypeUUID: // No need to show the type for dictionaries of simple items strm.PutCString("="); option_value->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) | extra_dump_options); break; } } strm.IndentLess(); } }
void OptionValueArray::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) { const Type array_element_type = ConvertTypeMaskToType (m_type_mask); if (dump_mask & eDumpOptionType) { if ((GetType() == eTypeArray) && (m_type_mask != eTypeInvalid)) strm.Printf ("(%s of %ss)", GetTypeAsCString(), GetBuiltinTypeAsCString(array_element_type)); else strm.Printf ("(%s)", GetTypeAsCString()); } if (dump_mask & eDumpOptionValue) { if (dump_mask & eDumpOptionType) strm.Printf (" =%s", (m_values.size() > 0) ? "\n" : ""); strm.IndentMore(); const uint32_t size = m_values.size(); for (uint32_t i = 0; i<size; ++i) { strm.Indent(); strm.Printf("[%u]: ", i); const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0; switch (array_element_type) { default: case eTypeArray: case eTypeDictionary: case eTypeProperties: case eTypeFileSpecList: case eTypePathMap: m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options); break; case eTypeBoolean: case eTypeChar: case eTypeEnum: case eTypeFileSpec: case eTypeFormat: case eTypeSInt64: case eTypeString: case eTypeUInt64: case eTypeUUID: // No need to show the type for dictionaries of simple items m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) | extra_dump_options); break; } if (i < (size - 1)) strm.EOL(); } strm.IndentLess(); } }
size_t Thread::GetStatus (Stream &strm, uint32_t start_frame, uint32_t num_frames, uint32_t num_frames_with_source) { ExecutionContext exe_ctx (shared_from_this()); Target *target = exe_ctx.GetTargetPtr(); Process *process = exe_ctx.GetProcessPtr(); size_t num_frames_shown = 0; strm.Indent(); bool is_selected = false; if (process) { if (process->GetThreadList().GetSelectedThread().get() == this) is_selected = true; } strm.Printf("%c ", is_selected ? '*' : ' '); if (target && target->GetDebugger().GetUseExternalEditor()) { StackFrameSP frame_sp = GetStackFrameAtIndex(start_frame); if (frame_sp) { SymbolContext frame_sc(frame_sp->GetSymbolContext (eSymbolContextLineEntry)); if (frame_sc.line_entry.line != 0 && frame_sc.line_entry.file) { Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line); } } } DumpUsingSettingsFormat (strm, start_frame); if (num_frames > 0) { strm.IndentMore(); const bool show_frame_info = true; strm.IndentMore (); num_frames_shown = GetStackFrameList ()->GetStatus (strm, start_frame, num_frames, show_frame_info, num_frames_with_source); strm.IndentLess(); strm.IndentLess(); } return num_frames_shown; }
void OptionValueFileSpecList::DumpValue(const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) { if (dump_mask & eDumpOptionType) strm.Printf("(%s)", GetTypeAsCString()); if (dump_mask & eDumpOptionValue) { if (dump_mask & eDumpOptionType) strm.Printf(" =%s", m_current_value.GetSize() > 0 ? "\n" : ""); strm.IndentMore(); const uint32_t size = m_current_value.GetSize(); for (uint32_t i = 0; i < size; ++i) { strm.Indent(); strm.Printf("[%u]: ", i); m_current_value.GetFileSpecAtIndex(i).Dump(&strm); } strm.IndentLess(); } }
bool DumpRegisterSet (const ExecutionContext &exe_ctx, Stream &strm, RegisterContext *reg_ctx, size_t set_idx, bool primitive_only=false) { uint32_t unavailable_count = 0; uint32_t available_count = 0; if (!reg_ctx) return false; // thread has no registers (i.e. core files are corrupt, incomplete crash logs...) const RegisterSet * const reg_set = reg_ctx->GetRegisterSet(set_idx); if (reg_set) { strm.Printf ("%s:\n", reg_set->name); strm.IndentMore (); const size_t num_registers = reg_set->num_registers; for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) { const uint32_t reg = reg_set->registers[reg_idx]; const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg); // Skip the dumping of derived register if primitive_only is true. if (primitive_only && reg_info && reg_info->value_regs) continue; if (DumpRegister (exe_ctx, strm, reg_ctx, reg_info)) ++available_count; else ++unavailable_count; } strm.IndentLess (); if (unavailable_count) { strm.Indent (); strm.Printf("%u registers were unavailable.\n", unavailable_count); } strm.EOL(); } return available_count > 0; }
void StructuredData::Dictionary::Dump (Stream &s) const { bool first = true; s << "{\n"; s.IndentMore(); for (const auto &pair : m_dict) { if (first) first = false; else s << ",\n"; s.Indent(); s << "\"" << pair.first.AsCString() << "\" : "; pair.second->Dump(s); } s.IndentLess(); s.EOL(); s.Indent(); s << "}"; }
void StructuredData::Array::Dump(Stream &s) const { bool first = true; s << "[\n"; s.IndentMore(); for (const auto &item_sp : m_items) { if (first) first = false; else s << ",\n"; s.Indent(); item_sp->Dump(s); } s.IndentLess(); s.EOL(); s.Indent(); s << "]"; }
//---------------------------------------------------------------------- // DumpCallback // // A callback function for the static DWARFDebugInfo::Parse() function // that gets called each time a compile unit header or debug information // entry is successfully parsed. // // This function dump DWARF information and obey recurse depth and // whether a single DIE is to be dumped (or all of the data). //---------------------------------------------------------------------- static dw_offset_t DumpCallback(SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, DWARFDebugInfoEntry *die, const dw_offset_t next_offset, const uint32_t curr_depth, void *userData) { DumpInfo *dumpInfo = (DumpInfo *)userData; Stream *s = dumpInfo->strm; bool show_parents = s->GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowAncestors); if (die) { // Are we dumping everything? if (dumpInfo->die_offset == DW_INVALID_OFFSET) { // Yes we are dumping everything. Obey our recurse level though if (curr_depth < dumpInfo->recurse_depth) die->Dump(dwarf2Data, cu, *s, 0); } else { // We are dumping a specific DIE entry by offset if (dumpInfo->die_offset == die->GetOffset()) { // We found the DIE we were looking for, dump it! if (show_parents) { s->SetIndentLevel(0); const uint32_t num_ancestors = dumpInfo->ancestors.size(); if (num_ancestors > 0) { for (uint32_t i = 0; i < num_ancestors - 1; ++i) { dumpInfo->ancestors[i].Dump(dwarf2Data, cu, *s, 0); s->IndentMore(); } } } dumpInfo->found_depth = curr_depth; die->Dump(dwarf2Data, cu, *s, 0); // Note that we found the DIE we were looking for dumpInfo->found_die = true; // Since we are dumping a single DIE, if there are no children we are // done! if (!die->HasChildren() || dumpInfo->recurse_depth == 0) return DW_INVALID_OFFSET; // Return an invalid address to end parsing } else if (dumpInfo->found_die) { // Are we done with all the children? if (curr_depth <= dumpInfo->found_depth) return DW_INVALID_OFFSET; // We have already found our DIE and are printing it's children. Obey // our recurse depth and return an invalid offset if we get done // dumping all of the children if (dumpInfo->recurse_depth == UINT32_MAX || curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth) die->Dump(dwarf2Data, cu, *s, 0); } else if (dumpInfo->die_offset > die->GetOffset()) { if (show_parents) dumpInfo->ancestors.back() = *die; } } // Keep up with our indent level if (die->IsNULL()) { if (show_parents) dumpInfo->ancestors.pop_back(); if (curr_depth <= 1) return cu->GetNextCompileUnitOffset(); else s->IndentLess(); } else if (die->HasChildren()) { if (show_parents) { DWARFDebugInfoEntry null_die; dumpInfo->ancestors.push_back(null_die); } s->IndentMore(); } } else { if (cu == NULL) s->PutCString("NULL - cu"); // We have a compile unit, reset our indent level to zero just in case s->SetIndentLevel(0); // See if we are dumping everything? if (dumpInfo->die_offset == DW_INVALID_OFFSET) { // We are dumping everything if (cu) { cu->Dump(s); return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this // Compile Unit } else { return DW_INVALID_OFFSET; } } else { if (show_parents) { dumpInfo->ancestors.clear(); dumpInfo->ancestors.resize(1); } // We are dumping only a single DIE possibly with it's children and // we must find it's compile unit before we can dump it properly if (cu && dumpInfo->die_offset < cu->GetFirstDIEOffset()) { // Not found, maybe the DIE offset provided wasn't correct? // *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " // was not found." << endl; return DW_INVALID_OFFSET; } else { // See if the DIE is in this compile unit? if (cu && dumpInfo->die_offset < cu->GetNextCompileUnitOffset()) { return next_offset; // // We found our compile unit that contains our DIE, just skip to // dumping the requested DIE... // return dumpInfo->die_offset; } else { // Skip to the next compile unit as the DIE isn't in the current one! if (cu) { return cu->GetNextCompileUnitOffset(); } else { return DW_INVALID_OFFSET; } } } } } // Just return the current offset to parse the next CU or DIE entry return next_offset; }
void CommandInterpreter::OutputFormattedHelpText (Stream &strm, const char *word_text, const char *separator, const char *help_text, uint32_t max_word_len) { StateVariable *var = GetStateVariable ("term-width"); int max_columns = var->GetIntValue(); // Sanity check max_columns, to cope with emacs shell mode with TERM=dumb // (0 rows; 0 columns;). if (max_columns <= 0) max_columns = 80; int indent_size = max_word_len + strlen (separator) + 2; strm.IndentMore (indent_size); int len = indent_size + strlen (help_text) + 1; char *text = (char *) malloc (len); sprintf (text, "%-*s %s %s", max_word_len, word_text, separator, help_text); if (text[len - 1] == '\n') text[--len] = '\0'; if (len < max_columns) { // Output it as a single line. strm.Printf ("%s", text); } else { // We need to break it up into multiple lines. bool first_line = true; int text_width; int start = 0; int end = start; int final_end = strlen (text); int sub_len; while (end < final_end) { if (first_line) text_width = max_columns - 1; else text_width = max_columns - indent_size - 1; // Don't start the 'text' on a space, since we're already outputting the indentation. if (!first_line) { while ((start < final_end) && (text[start] == ' ')) start++; } end = start + text_width; if (end > final_end) end = final_end; else { // If we're not at the end of the text, make sure we break the line on white space. while (end > start && text[end] != ' ' && text[end] != '\t' && text[end] != '\n') end--; } sub_len = end - start; if (start != 0) strm.EOL(); if (!first_line) strm.Indent(); else first_line = false; assert (start <= final_end); assert (start + sub_len <= final_end); if (sub_len > 0) strm.Write (text + start, sub_len); start = end + 1; } } strm.EOL(); strm.IndentLess(indent_size); free (text); }
void Options::GenerateOptionUsage(Stream &strm, CommandObject *cmd, uint32_t screen_width) { const bool only_print_args = cmd->IsDashDashCommand(); auto opt_defs = GetDefinitions(); const uint32_t save_indent_level = strm.GetIndentLevel(); llvm::StringRef name; StreamString arguments_str; if (cmd) { name = cmd->GetCommandName(); cmd->GetFormattedCommandArguments(arguments_str); } else name = ""; strm.PutCString("\nCommand Options Usage:\n"); strm.IndentMore(2); // First, show each usage level set of options, e.g. <cmd> // [options-for-level-0] // <cmd> // [options-for-level-1] // etc. const uint32_t num_options = NumCommandOptions(); if (num_options == 0) return; uint32_t num_option_sets = GetRequiredOptions().size(); uint32_t i; if (!only_print_args) { for (uint32_t opt_set = 0; opt_set < num_option_sets; ++opt_set) { uint32_t opt_set_mask; opt_set_mask = 1 << opt_set; if (opt_set > 0) strm.Printf("\n"); strm.Indent(name); // Different option sets may require different args. StreamString args_str; if (cmd) cmd->GetFormattedCommandArguments(args_str, opt_set_mask); // First go through and print all options that take no arguments as // a single string. If a command has "-a" "-b" and "-c", this will show // up as [-abc] std::set<int> options; std::set<int>::const_iterator options_pos, options_end; for (auto &def : opt_defs) { if (def.usage_mask & opt_set_mask && isprint8(def.short_option)) { // Add current option to the end of out_stream. if (def.required && def.option_has_arg == OptionParser::eNoArgument) { options.insert(def.short_option); } } } if (options.empty() == false) { // We have some required options with no arguments strm.PutCString(" -"); for (i = 0; i < 2; ++i) for (options_pos = options.begin(), options_end = options.end(); options_pos != options_end; ++options_pos) { if (i == 0 && ::islower(*options_pos)) continue; if (i == 1 && ::isupper(*options_pos)) continue; strm << (char)*options_pos; } } options.clear(); for (auto &def : opt_defs) { if (def.usage_mask & opt_set_mask && isprint8(def.short_option)) { // Add current option to the end of out_stream. if (def.required == false && def.option_has_arg == OptionParser::eNoArgument) { options.insert(def.short_option); } } } if (options.empty() == false) { // We have some required options with no arguments strm.PutCString(" [-"); for (i = 0; i < 2; ++i) for (options_pos = options.begin(), options_end = options.end(); options_pos != options_end; ++options_pos) { if (i == 0 && ::islower(*options_pos)) continue; if (i == 1 && ::isupper(*options_pos)) continue; strm << (char)*options_pos; } strm.PutChar(']'); } // First go through and print the required options (list them up front). for (auto &def : opt_defs) { if (def.usage_mask & opt_set_mask && isprint8(def.short_option)) { if (def.required && def.option_has_arg != OptionParser::eNoArgument) PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm); } } // Now go through again, and this time only print the optional options. for (auto &def : opt_defs) { if (def.usage_mask & opt_set_mask) { // Add current option to the end of out_stream. if (!def.required && def.option_has_arg != OptionParser::eNoArgument) PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm); } } if (args_str.GetSize() > 0) { if (cmd->WantsRawCommandString() && !only_print_args) strm.Printf(" --"); strm << " " << args_str.GetString(); if (only_print_args) break; } } } if (cmd && (only_print_args || cmd->WantsRawCommandString()) && arguments_str.GetSize() > 0) { if (!only_print_args) strm.PutChar('\n'); strm.Indent(name); strm << " " << arguments_str.GetString(); } strm.Printf("\n\n"); if (!only_print_args) { // Now print out all the detailed information about the various options: // long form, short form and help text: // -short <argument> ( --long_name <argument> ) // help text // This variable is used to keep track of which options' info we've printed // out, because some options can be in // more than one usage level, but we only want to print the long form of its // information once. std::multimap<int, uint32_t> options_seen; strm.IndentMore(5); // Put the unique command options in a vector & sort it, so we can output // them alphabetically (by short_option) // when writing out detailed help for each option. i = 0; for (auto &def : opt_defs) options_seen.insert(std::make_pair(def.short_option, i++)); // Go through the unique'd and alphabetically sorted vector of options, find // the table entry for each option // and write out the detailed help information for that option. bool first_option_printed = false; for (auto pos : options_seen) { i = pos.second; // Print out the help information for this option. // Put a newline separation between arguments if (first_option_printed) strm.EOL(); else first_option_printed = true; CommandArgumentType arg_type = opt_defs[i].argument_type; StreamString arg_name_str; arg_name_str.Printf("<%s>", CommandObject::GetArgumentName(arg_type)); strm.Indent(); if (opt_defs[i].short_option && isprint8(opt_defs[i].short_option)) { PrintOption(opt_defs[i], eDisplayShortOption, nullptr, nullptr, false, strm); PrintOption(opt_defs[i], eDisplayLongOption, " ( ", " )", false, strm); } else { // Short option is not printable, just print long option PrintOption(opt_defs[i], eDisplayLongOption, nullptr, nullptr, false, strm); } strm.EOL(); strm.IndentMore(5); if (opt_defs[i].usage_text) OutputFormattedUsageText(strm, opt_defs[i], screen_width); if (opt_defs[i].enum_values != nullptr) { strm.Indent(); strm.Printf("Values: "); for (int k = 0; opt_defs[i].enum_values[k].string_value != nullptr; k++) { if (k == 0) strm.Printf("%s", opt_defs[i].enum_values[k].string_value); else strm.Printf(" | %s", opt_defs[i].enum_values[k].string_value); } strm.EOL(); } strm.IndentLess(5); } } // Restore the indent level strm.SetIndentLevel(save_indent_level); }
bool Disassembler::Disassemble ( Debugger &debugger, const ArchSpec &arch, const ExecutionContext &exe_ctx, const AddressRange &disasm_range, uint32_t num_mixed_context_lines, bool show_bytes, Stream &strm ) { if (disasm_range.GetByteSize()) { Disassembler *disassembler = Disassembler::FindPlugin(arch); if (disassembler) { AddressRange range(disasm_range); Process *process = exe_ctx.process; // If we weren't passed in a section offset address range, // try and resolve it to something if (range.GetBaseAddress().IsSectionOffset() == false) { if (process && process->IsAlive()) { process->ResolveLoadAddress (range.GetBaseAddress().GetOffset(), range.GetBaseAddress()); } else if (exe_ctx.target) { exe_ctx.target->GetImages().ResolveFileAddress (range.GetBaseAddress().GetOffset(), range.GetBaseAddress()); } } DataExtractor data; size_t bytes_disassembled = disassembler->ParseInstructions (&exe_ctx, range, data); if (bytes_disassembled == 0) { return false; } else { // We got some things disassembled... size_t num_instructions = disassembler->GetInstructionList().GetSize(); uint32_t offset = 0; SymbolContext sc; SymbolContext prev_sc; AddressRange sc_range; if (num_mixed_context_lines) strm.IndentMore (); Address addr(range.GetBaseAddress()); // We extract the section to make sure we don't transition out // of the current section when disassembling const Section *addr_section = addr.GetSection(); Module *range_module = range.GetBaseAddress().GetModule(); for (size_t i=0; i<num_instructions; ++i) { Disassembler::Instruction *inst = disassembler->GetInstructionList().GetInstructionAtIndex (i); if (inst) { addr_t file_addr = addr.GetFileAddress(); if (addr_section == NULL || addr_section->ContainsFileAddress (file_addr) == false) { if (range_module) range_module->ResolveFileAddress (file_addr, addr); else if (exe_ctx.target) exe_ctx.target->GetImages().ResolveFileAddress (file_addr, addr); addr_section = addr.GetSection(); } prev_sc = sc; if (addr_section) { Module *module = addr_section->GetModule(); uint32_t resolved_mask = module->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc); if (resolved_mask) { if (prev_sc.function != sc.function || prev_sc.symbol != sc.symbol) { if (prev_sc.function || prev_sc.symbol) strm.EOL(); strm << sc.module_sp->GetFileSpec().GetFilename(); if (sc.function) strm << '`' << sc.function->GetMangled().GetName(); else if (sc.symbol) strm << '`' << sc.symbol->GetMangled().GetName(); strm << ":\n"; } if (num_mixed_context_lines && !sc_range.ContainsFileAddress (addr)) { sc.GetAddressRange (eSymbolContextEverything, sc_range); if (sc != prev_sc) { if (offset != 0) strm.EOL(); sc.DumpStopContext(&strm, process, addr); if (sc.comp_unit && sc.line_entry.IsValid()) { debugger.GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.line_entry.file, sc.line_entry.line, num_mixed_context_lines, num_mixed_context_lines, num_mixed_context_lines ? "->" : "", &strm); } } } } else { sc.Clear(); } } if (num_mixed_context_lines) strm.IndentMore (); strm.Indent(); size_t inst_byte_size = inst->GetByteSize(); inst->Dump(&strm, &addr, show_bytes ? &data : NULL, offset, exe_ctx, show_bytes); strm.EOL(); offset += inst_byte_size; addr.SetOffset (addr.GetOffset() + inst_byte_size); if (num_mixed_context_lines) strm.IndentLess (); } else { break; } } if (num_mixed_context_lines) strm.IndentLess (); } } return true; } return false; }