|  | // Copyright 2019 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef SRC_LIB_FIDL_CODEC_PRINTER_H_ | 
|  | #define SRC_LIB_FIDL_CODEC_PRINTER_H_ | 
|  |  | 
|  | #include <zircon/system/public/zircon/rights.h> | 
|  | #include <zircon/system/public/zircon/syscalls/exception.h> | 
|  | #include <zircon/system/public/zircon/syscalls/object.h> | 
|  | #include <zircon/system/public/zircon/syscalls/resource.h> | 
|  | #include <zircon/system/public/zircon/types.h> | 
|  |  | 
|  | #include <cinttypes> | 
|  | #include <cstdint> | 
|  | #include <ostream> | 
|  |  | 
|  | #include "src/lib/fxl/logging.h" | 
|  | #include "zircon/system/public/zircon/syscalls/debug.h" | 
|  |  | 
|  | namespace fidl_codec { | 
|  |  | 
|  | constexpr int kTabSize = 2; | 
|  |  | 
|  | struct Colors { | 
|  | Colors(const char* new_reset, const char* new_red, const char* new_green, const char* new_blue, | 
|  | const char* new_white_on_magenta, const char* new_yellow_background) | 
|  | : reset(new_reset), | 
|  | red(new_red), | 
|  | green(new_green), | 
|  | blue(new_blue), | 
|  | white_on_magenta(new_white_on_magenta), | 
|  | yellow_background(new_yellow_background) {} | 
|  |  | 
|  | const char* const reset; | 
|  | const char* const red; | 
|  | const char* const green; | 
|  | const char* const blue; | 
|  | const char* const white_on_magenta; | 
|  | const char* const yellow_background; | 
|  | }; | 
|  |  | 
|  | extern const Colors WithoutColors; | 
|  | extern const Colors WithColors; | 
|  |  | 
|  | class PrettyPrinter { | 
|  | public: | 
|  | PrettyPrinter(std::ostream& os, const Colors& colors, std::string_view line_header, | 
|  | int max_line_size, bool header_on_every_line, int tabulations = 0); | 
|  |  | 
|  | std::ostream& os() const { return os_; } | 
|  | const Colors& colors() const { return colors_; } | 
|  | int max_line_size() const { return max_line_size_; } | 
|  | int remaining_size() const { return remaining_size_; } | 
|  |  | 
|  | bool LineEmpty() const { return need_to_print_header_; } | 
|  |  | 
|  | // Displays a handle. This allows the caller to also display some infered data we have inferered | 
|  | // for this handle (if any). | 
|  | virtual void DisplayHandle(const zx_handle_info_t& handle); | 
|  |  | 
|  | void IncrementTabulations(); | 
|  | void DecrementTabulations(); | 
|  | void NeedHeader(); | 
|  | void PrintHeader(char first_character); | 
|  |  | 
|  | PrettyPrinter& operator<<(char data) { | 
|  | if (need_to_print_header_) { | 
|  | PrintHeader(data); | 
|  | } | 
|  | os_ << data; | 
|  | if (data == '\n') { | 
|  | NeedHeader(); | 
|  | } else { | 
|  | --remaining_size_; | 
|  | } | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | PrettyPrinter& operator<<(int32_t data) { | 
|  | FXL_DCHECK((os_.flags() & os_.basefield) == os_.dec); | 
|  | *this << std::to_string(data); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | PrettyPrinter& operator<<(uint32_t data) { | 
|  | if (((os_.flags() & os_.basefield) == os_.dec) || (data == 0)) { | 
|  | *this << std::to_string(data); | 
|  | } else { | 
|  | os_ << data; | 
|  | int data_size = 0; | 
|  | while (data > 0) { | 
|  | data /= 16; | 
|  | data_size++; | 
|  | } | 
|  | remaining_size_ -= data_size; | 
|  | } | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | PrettyPrinter& operator<<(uint64_t data) { | 
|  | if (((os_.flags() & os_.basefield) == os_.dec) || (data == 0)) { | 
|  | *this << std::to_string(data); | 
|  | } else { | 
|  | os_ << data; | 
|  | int data_size = 0; | 
|  | while (data > 0) { | 
|  | data /= 16; | 
|  | data_size++; | 
|  | } | 
|  | remaining_size_ -= data_size; | 
|  | } | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | PrettyPrinter& operator<<(std::string_view data); | 
|  |  | 
|  | // Used by the color functions. | 
|  | PrettyPrinter& operator<<(PrettyPrinter& (*pf)(PrettyPrinter& printer)) { | 
|  | if (need_to_print_header_) { | 
|  | PrintHeader(' '); | 
|  | } | 
|  | return pf(*this); | 
|  | } | 
|  |  | 
|  | // Used by std::hex, std::dec. | 
|  | PrettyPrinter& operator<<(std::ios_base& (*pf)(std::ios_base&)) { | 
|  | pf(os_); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::ostream& os_; | 
|  | const Colors& colors_; | 
|  | const std::string_view line_header_; | 
|  | const int max_line_size_; | 
|  | const bool header_on_every_line_ = false; | 
|  | bool need_to_print_header_ = true; | 
|  | int line_header_size_ = 0; | 
|  | int tabulations_; | 
|  | int remaining_size_ = 0; | 
|  | }; | 
|  |  | 
|  | inline PrettyPrinter& ResetColor(PrettyPrinter& printer) { | 
|  | printer.os() << printer.colors().reset; | 
|  | return printer; | 
|  | } | 
|  |  | 
|  | inline PrettyPrinter& Red(PrettyPrinter& printer) { | 
|  | printer.os() << printer.colors().red; | 
|  | return printer; | 
|  | } | 
|  |  | 
|  | inline PrettyPrinter& Green(PrettyPrinter& printer) { | 
|  | printer.os() << printer.colors().green; | 
|  | return printer; | 
|  | } | 
|  |  | 
|  | inline PrettyPrinter& Blue(PrettyPrinter& printer) { | 
|  | printer.os() << printer.colors().blue; | 
|  | return printer; | 
|  | } | 
|  |  | 
|  | inline PrettyPrinter& WhiteOnMagenta(PrettyPrinter& printer) { | 
|  | printer.os() << printer.colors().white_on_magenta; | 
|  | return printer; | 
|  | } | 
|  |  | 
|  | inline PrettyPrinter& YellowBackground(PrettyPrinter& printer) { | 
|  | printer.os() << printer.colors().yellow_background; | 
|  | return printer; | 
|  | } | 
|  |  | 
|  | // Scope which increments the indentation. | 
|  | class Indent { | 
|  | public: | 
|  | explicit Indent(PrettyPrinter& printer) : printer_(printer) { printer.IncrementTabulations(); } | 
|  | ~Indent() { printer_.DecrementTabulations(); } | 
|  |  | 
|  | private: | 
|  | PrettyPrinter& printer_; | 
|  | }; | 
|  |  | 
|  | }  // namespace fidl_codec | 
|  |  | 
|  | #endif  // SRC_LIB_FIDL_CODEC_PRINTER_H_ |