diff --git a/backend/Makefile.am b/backend/Makefile.am index a4f1566d9..4283261ed 100644 --- a/backend/Makefile.am +++ b/backend/Makefile.am @@ -510,8 +510,8 @@ libgenesys_la_SOURCES = genesys/genesys.cpp genesys/genesys.h \ genesys/register_cache.h \ genesys/scanner_interface.h genesys/scanner_interface.cpp \ genesys/scanner_interface_usb.h genesys/scanner_interface_usb.cpp \ - genesys/sensor.h \ - genesys/settings.h \ + genesys/sensor.h genesys/sensor.cpp \ + genesys/settings.h genesys/settings.cpp \ genesys/serialize.h \ genesys/tables_frontend.cpp \ genesys/tables_gpo.cpp \ diff --git a/backend/genesys/enums.cpp b/backend/genesys/enums.cpp index 155c87b80..66238648c 100644 --- a/backend/genesys/enums.cpp +++ b/backend/genesys/enums.cpp @@ -95,4 +95,17 @@ ScanColorMode option_string_to_scan_color_mode(const std::string& str) throw SaneException("Unknown scan color mode %s", str.c_str()); } + +std::ostream& operator<<(std::ostream& out, ColorFilter mode) +{ + switch (mode) { + case ColorFilter::RED: out << "RED"; break; + case ColorFilter::GREEN: out << "GREEN"; break; + case ColorFilter::BLUE: out << "BLUE"; break; + case ColorFilter::NONE: out << "NONE"; break; + default: out << static_cast(mode); break; + } + return out; +} + } // namespace genesys diff --git a/backend/genesys/enums.h b/backend/genesys/enums.h index f825e31c5..0ceb93c34 100644 --- a/backend/genesys/enums.h +++ b/backend/genesys/enums.h @@ -58,6 +58,16 @@ enum class ScanMethod : unsigned { TRANSPARENCY_INFRARED = 2 }; +inline std::ostream& operator<<(std::ostream& out, ScanMethod mode) +{ + switch (mode) { + case ScanMethod::FLATBED: out << "FLATBED"; return out; + case ScanMethod::TRANSPARENCY: out << "TRANSPARENCY"; return out; + case ScanMethod::TRANSPARENCY_INFRARED: out << "TRANSPARENCY_INFRARED"; return out; + } + return out; +} + inline void serialize(std::istream& str, ScanMethod& x) { unsigned value; @@ -81,6 +91,17 @@ enum class ScanColorMode : unsigned { COLOR_SINGLE_PASS }; +inline std::ostream& operator<<(std::ostream& out, ScanColorMode mode) +{ + switch (mode) { + case ScanColorMode::LINEART: out << "LINEART"; return out; + case ScanColorMode::HALFTONE: out << "HALFTONE"; return out; + case ScanColorMode::GRAY: out << "GRAY"; return out; + case ScanColorMode::COLOR_SINGLE_PASS: out << "COLOR_SINGLE_PASS"; return out; + } + return out; +} + inline void serialize(std::istream& str, ScanColorMode& x) { unsigned value; @@ -104,6 +125,8 @@ enum class ColorFilter : unsigned { NONE }; +std::ostream& operator<<(std::ostream& out, ColorFilter mode); + inline void serialize(std::istream& str, ColorFilter& x) { unsigned value; diff --git a/backend/genesys/low.cpp b/backend/genesys/low.cpp index 84926c966..c4217f050 100644 --- a/backend/genesys/low.cpp +++ b/backend/genesys/low.cpp @@ -2014,140 +2014,4 @@ void run_functions_at_backend_exit() s_functions_run_at_backend_exit.reset(); } -void debug_dump(unsigned level, const Genesys_Settings& settings) -{ - DBG(level, "Genesys_Settings:\n" - "Resolution X/Y : %u / %u dpi\n" - "Lines : %u\n" - "Pixels per line : %u\n" - "Pixels per line (requested) : %u\n" - "Depth : %u\n" - "Start position X/Y : %.3f/%.3f\n" - "Scan mode : %d\n\n", - settings.xres, settings.yres, - settings.lines, settings.pixels, settings.requested_pixels, settings.depth, - settings.tl_x, settings.tl_y, - static_cast(settings.scan_mode)); -} - -void debug_dump(unsigned level, const SetupParams& params) -{ - DBG(level, "SetupParams:\n" - "Resolution X/Y : %u / %u dpi\n" - "Lines : %u\n" - "Pixels per line : %u\n" - "Pixels per line (requested) : %u\n" - "Depth : %u\n" - "Channels : %u\n" - "Start position X/Y : %u / %u\n" - "Scan mode : %d\n" - "Color filter : %d\n" - "Flags : %x\n", - params.xres, params.yres, - params.lines, params.pixels, params.requested_pixels, - params.depth, params.channels, - params.startx, params.starty, - static_cast(params.scan_mode), - static_cast(params.color_filter), - params.flags); -} - -void debug_dump(unsigned level, const ScanSession& session) -{ - DBG(level, "session:\n"); - DBG(level, " computed : %d\n", session.computed); - DBG(level, " hwdpi_divisor : %d\n", session.hwdpi_divisor); - DBG(level, " ccd_size_divisor : %d\n", session.ccd_size_divisor); - DBG(level, " optical_resolution : %d\n", session.optical_resolution); - DBG(level, " optical_pixels : %d\n", session.optical_pixels); - DBG(level, " optical_pixels_raw : %d\n", session.optical_pixels_raw); - DBG(level, " output_resolution : %d\n", session.output_resolution); - DBG(level, " output_pixels : %d\n", session.output_pixels); - DBG(level, " output_line_bytes : %d\n", session.output_line_bytes); - DBG(level, " output_line_bytes_raw : %d\n", session.output_line_bytes_raw); - DBG(level, " output_line_count : %d\n", session.output_line_count); - DBG(level, " num_staggered_lines : %d\n", session.num_staggered_lines); - DBG(level, " max_color_shift_lines : %d\n", session.max_color_shift_lines); - DBG(level, " enable_ledadd : %d\n", session.enable_ledadd); - DBG(level, " segment_count : %d\n", session.segment_count); - DBG(level, " pixel_startx : %d\n", session.pixel_startx); - DBG(level, " pixel_endx : %d\n", session.pixel_endx); - DBG(level, " conseq_pixel_dist : %d\n", session.conseq_pixel_dist); - DBG(level, " output_segment_pixel_group_count : %d\n", - session.output_segment_pixel_group_count); - DBG(level, " buffer_size_read : %zu\n", session.buffer_size_read); - DBG(level, " buffer_size_read : %zu\n", session.buffer_size_lines); - DBG(level, " buffer_size_shrink : %zu\n", session.buffer_size_shrink); - DBG(level, " buffer_size_out : %zu\n", session.buffer_size_out); - DBG(level, " filters:%s%s%s\n", - session.pipeline_needs_reorder ? " reorder" : "", - session.pipeline_needs_ccd ? " ccd" : "", - session.pipeline_needs_shrink ? " shrink" : ""); - debug_dump(level, session.params); -} - -void debug_dump(unsigned level, const Genesys_Register_Set& regs) -{ - DBG(level, "register_set:\n"); - for (const auto& reg : regs) { - DBG(level, " %04x=%02x\n", reg.address, reg.value); - } -} - -void debug_dump(unsigned level, const GenesysRegisterSettingSet& regs) -{ - DBG(level, "register_setting_set:\n"); - for (const auto& reg : regs) { - DBG(level, " %04x=%02x & %02x\n", reg.address, reg.value, reg.mask); - } -} - -void debug_dump(unsigned level, const Genesys_Sensor& sensor) -{ - DBG(level, "sensor:\n"); - DBG(level, " sensor_id : %d\n", static_cast(sensor.sensor_id)); - DBG(level, " optical_res : %d\n", sensor.optical_res); - - DBG(level, " resolutions :"); - if (sensor.resolutions.matches_any()) { - DBG(level, " ANY\n"); - } else { - for (unsigned resolution : sensor.resolutions.resolutions()) { - DBG(level, " %d", resolution); - } - DBG(level, "\n"); - } - - DBG(level, " method : %d\n", static_cast(sensor.method)); - DBG(level, " ccd_size_divisor : %d\n", sensor.ccd_size_divisor); - DBG(level, " black_pixels : %d\n", sensor.black_pixels); - DBG(level, " dummy_pixel : %d\n", sensor.dummy_pixel); - DBG(level, " ccd_start_xoffset : %d\n", sensor.ccd_start_xoffset); - DBG(level, " sensor_pixels : %d\n", sensor.sensor_pixels); - DBG(level, " fau_gain_white_ref : %d\n", sensor.fau_gain_white_ref); - DBG(level, " gain_white_ref : %d\n", sensor.gain_white_ref); - DBG(level, " exposure.red : %d\n", sensor.exposure.red); - DBG(level, " exposure.green : %d\n", sensor.exposure.green); - DBG(level, " exposure.blue : %d\n", sensor.exposure.blue); - DBG(level, " exposure_lperiod : %d\n", sensor.exposure_lperiod); - DBG(level, " custom_regs\n"); - debug_dump(level, sensor.custom_regs); - DBG(level, " custom_fe_regs\n"); - debug_dump(level, sensor.custom_fe_regs); - DBG(level, " gamma.red : %f\n", sensor.gamma[0]); - DBG(level, " gamma.green : %f\n", sensor.gamma[1]); - DBG(level, " gamma.blue : %f\n", sensor.gamma[2]); -} - -void debug_dump(unsigned level, const SANE_Parameters& params) -{ - DBG(level, "params:\n"); - DBG(level, " format: %d:\n", static_cast(params.format)); - DBG(level, " last_frame: %d:\n", params.last_frame); - DBG(level, " bytes_per_line: %d:\n", params.bytes_per_line); - DBG(level, " pixels_per_line: %d:\n", params.pixels_per_line); - DBG(level, " lines: %d:\n", params.lines); - DBG(level, " depth: %d:\n", params.depth); -} - } // namespace genesys diff --git a/backend/genesys/low.h b/backend/genesys/low.h index 9774aa670..ab1e5b759 100644 --- a/backend/genesys/low.h +++ b/backend/genesys/low.h @@ -57,7 +57,6 @@ #include #include #include -#include #include #include #include @@ -96,6 +95,7 @@ #include #include #include +#include #include #include #include @@ -577,13 +577,13 @@ void genesys_init_gpo_tables(); void genesys_init_motor_tables(); void genesys_init_usb_device_tables(); -void debug_dump(unsigned level, const Genesys_Settings& settings); -void debug_dump(unsigned level, const SetupParams& params); -void debug_dump(unsigned level, const ScanSession& session); -void debug_dump(unsigned level, const Genesys_Register_Set& regs); -void debug_dump(unsigned level, const GenesysRegisterSettingSet& regs); -void debug_dump(unsigned level, const Genesys_Sensor& sensor); -void debug_dump(unsigned level, const SANE_Parameters& params); +template +void debug_dump(unsigned level, const T& value) +{ + std::stringstream out; + out << value; + DBG(level, "%s\n", out.str().c_str()); +} } // namespace genesys diff --git a/backend/genesys/register.h b/backend/genesys/register.h index d7c1ea580..ee9fc388f 100644 --- a/backend/genesys/register.h +++ b/backend/genesys/register.h @@ -44,10 +44,13 @@ #ifndef BACKEND_GENESYS_REGISTER_H #define BACKEND_GENESYS_REGISTER_H +#include "utilities.h" + #include #include #include #include +#include #include #include @@ -190,6 +193,26 @@ private: std::vector registers_; }; +template +std::ostream& operator<<(std::ostream& out, const RegisterContainer& container) +{ + StreamStateSaver state_saver{out}; + + out << "RegisterContainer{\n"; + out << std::hex; + out.fill('0'); + + for (const auto& reg : container) { + unsigned address_width = sizeof(reg.address) * 2; + unsigned value_width = sizeof(reg.value) * 2; + + out << " 0x" << std::setw(address_width) << static_cast(reg.address) + << " = 0x" << std::setw(value_width) << static_cast(reg.value) << '\n'; + } + out << "}"; + return out; +} + class Genesys_Register_Set { public: @@ -218,6 +241,11 @@ public: registers_.reserve(MAX_REGS); } + const ContainerType& registers() const + { + return registers_; + } + void init_reg(std::uint16_t address, std::uint8_t default_value) { registers_.init_reg(address, default_value); @@ -303,6 +331,12 @@ private: ContainerType registers_; }; +inline std::ostream& operator<<(std::ostream& out, const Genesys_Register_Set& regs) +{ + out << regs.registers(); + return out; +} + template struct RegisterSetting { @@ -443,6 +477,28 @@ private: using GenesysRegisterSettingSet = RegisterSettingSet; using GenesysRegisterSettingSet16 = RegisterSettingSet; +template +std::ostream& operator<<(std::ostream& out, const RegisterSettingSet& container) +{ + StreamStateSaver state_saver{out}; + + out << "RegisterSettingSet{\n"; + out << std::hex; + out.fill('0'); + + for (const auto& reg : container) { + unsigned address_width = sizeof(reg.address) * 2; + unsigned value_width = sizeof(reg.value) * 2; + unsigned mask_width = sizeof(reg.mask) * 2; + + out << " 0x" << std::setw(address_width) << static_cast(reg.address) + << " = 0x" << std::setw(value_width) << static_cast(reg.value) + << " & 0x" << std::setw(mask_width) << static_cast(reg.mask) << '\n'; + } + out << "}"; + return out; +} + template inline void serialize(std::istream& str, RegisterSettingSet& reg) { diff --git a/backend/genesys/sensor.cpp b/backend/genesys/sensor.cpp new file mode 100644 index 000000000..068b8a532 --- /dev/null +++ b/backend/genesys/sensor.cpp @@ -0,0 +1,87 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + This file is part of the SANE package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "sensor.h" +#include "utilities.h" +#include + +namespace genesys { + +std::ostream& operator<<(std::ostream& out, const Genesys_Sensor& sensor) +{ + out << "Genesys_Sensor{\n" + << " sensor_id: " << static_cast(sensor.sensor_id) << '\n' + << " optical_res: " << sensor.optical_res << '\n'; + if (sensor.resolutions.matches_any()) { + out << " resolutions: ANY\n"; + } else { + out << " resolutions: {\n"; + for (unsigned resolution : sensor.resolutions.resolutions()) { + out << " " << resolution << ",\n"; + } + out << " }\n"; + } + out << " method: " << sensor.method << '\n' + << " ccd_size_divisor: " << sensor.ccd_size_divisor << '\n' + << " black_pixels: " << sensor.black_pixels << '\n' + << " dummy_pixel: " << sensor.dummy_pixel << '\n' + << " ccd_start_xoffset: " << sensor.ccd_start_xoffset << '\n' + << " sensor_pixels: " << sensor.sensor_pixels << '\n' + << " fau_gain_white_ref: " << sensor.fau_gain_white_ref << '\n' + << " gain_white_ref: " << sensor.gain_white_ref << '\n' + << " exposure.red: " << sensor.exposure.red << '\n' + << " exposure.green: " << sensor.exposure.green << '\n' + << " exposure.blue: " << sensor.exposure.blue << '\n' + << " exposure_lperiod: " << sensor.exposure_lperiod << '\n' + << " custom_regs: " << format_indent_braced_list(4, sensor.custom_regs) << '\n' + << " custom_fe_regs: " << format_indent_braced_list(4, sensor.custom_fe_regs) << '\n' + << " gamma.red: " << sensor.gamma[0] << '\n' + << " gamma.green: " << sensor.gamma[1] << '\n' + << " gamma.blue: " << sensor.gamma[2] << '\n' + << "}"; + return out; +} + +} // namespace genesys diff --git a/backend/genesys/sensor.h b/backend/genesys/sensor.h index 675002e56..c593b8219 100644 --- a/backend/genesys/sensor.h +++ b/backend/genesys/sensor.h @@ -450,6 +450,8 @@ void serialize(Stream& str, Genesys_Sensor& x) serialize(str, x.sensor_profiles); } +std::ostream& operator<<(std::ostream& out, const Genesys_Sensor& sensor); + } // namespace genesys #endif // BACKEND_GENESYS_SENSOR_H diff --git a/backend/genesys/settings.cpp b/backend/genesys/settings.cpp new file mode 100644 index 000000000..7e52f28b2 --- /dev/null +++ b/backend/genesys/settings.cpp @@ -0,0 +1,142 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + This file is part of the SANE package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "settings.h" +#include "utilities.h" +#include + +namespace genesys { + +std::ostream& operator<<(std::ostream& out, const Genesys_Settings& settings) +{ + StreamStateSaver state_saver{out}; + + out << "Genesys_Settings{\n" + << " xres: " << settings.xres << " yres: " << settings.yres << '\n' + << " lines: " << settings.lines << '\n' + << " pixels per line (actual): " << settings.pixels << '\n' + << " pixels per line (requested): " << settings.requested_pixels << '\n' + << " depth: " << settings.depth << '\n'; + auto prec = out.precision(); + out.precision(3); + out << " tl_x: " << settings.tl_x << " tl_y: " << settings.tl_y << '\n'; + out.precision(prec); + out << " scan_mode: " << settings.scan_mode << '\n' + << '}'; + return out; +} + +std::ostream& operator<<(std::ostream& out, const SetupParams& params) +{ + StreamStateSaver state_saver{out}; + + out << "SetupParams{\n" + << " xres: " << params.xres << " yres: " << params.yres << '\n' + << " lines: " << params.lines << '\n' + << " pixels per line (actual): " << params.pixels << '\n' + << " pixels per line (requested): " << params.requested_pixels << '\n' + << " depth: " << params.depth << '\n' + << " channels: " << params.channels << '\n' + << " startx: " << params.startx << " starty: " << params.starty << '\n' + << " scan_mode: " << params.scan_mode << '\n' + << " color_filter: " << params.color_filter << '\n' + << " flags: 0x" << std::hex << params.flags << std::dec << '\n' + << "}"; + return out; +} + +std::ostream& operator<<(std::ostream& out, const ScanSession& session) +{ + out << "ScanSession{\n" + << " computed: " << session.computed << '\n' + << " hwdpi_divisor: " << session.hwdpi_divisor << '\n' + << " ccd_size_divisor: " << session.ccd_size_divisor << '\n' + << " optical_resolution: " << session.optical_resolution << '\n' + << " optical_pixels: " << session.optical_pixels << '\n' + << " optical_pixels_raw: " << session.optical_pixels_raw << '\n' + << " output_resolution: " << session.output_resolution << '\n' + << " output_pixels: " << session.output_pixels << '\n' + << " output_line_bytes: " << session.output_line_bytes << '\n' + << " output_line_bytes_raw: " << session.output_line_bytes_raw << '\n' + << " output_line_count: " << session.output_line_count << '\n' + << " num_staggered_lines: " << session.num_staggered_lines << '\n' + << " color_shift_lines_r: " << session.color_shift_lines_r << '\n' + << " color_shift_lines_g: " << session.color_shift_lines_g << '\n' + << " color_shift_lines_b: " << session.color_shift_lines_b << '\n' + << " max_color_shift_lines: " << session.max_color_shift_lines << '\n' + << " enable_ledadd: " << session.enable_ledadd << '\n' + << " segment_count: " << session.segment_count << '\n' + << " pixel_startx: " << session.pixel_startx << '\n' + << " pixel_endx: " << session.pixel_endx << '\n' + << " conseq_pixel_dist: " << session.conseq_pixel_dist << '\n' + << " output_segment_pixel_group_count: " + << session.output_segment_pixel_group_count << '\n' + << " buffer_size_read: " << session.buffer_size_read << '\n' + << " buffer_size_read: " << session.buffer_size_lines << '\n' + << " buffer_size_shrink: " << session.buffer_size_shrink << '\n' + << " buffer_size_out: " << session.buffer_size_out << '\n' + << " filters: " + << (session.pipeline_needs_reorder ? " reorder": "") + << (session.pipeline_needs_ccd ? " ccd": "") + << (session.pipeline_needs_shrink ? " shrink": "") << '\n' + << " params: " << format_indent_braced_list(4, session.params) << '\n' + << "}"; + return out; +} + +std::ostream& operator<<(std::ostream& out, const SANE_Parameters& params) +{ + out << "SANE_Parameters{\n" + << " format: " << static_cast(params.format) << '\n' + << " last_frame: " << params.last_frame << '\n' + << " bytes_per_line: " << params.bytes_per_line << '\n' + << " pixels_per_line: " << params.pixels_per_line << '\n' + << " lines: " << params.lines << '\n' + << " depth: " << params.depth << '\n' + << '}'; + return out; +} + +} // namespace genesys diff --git a/backend/genesys/settings.h b/backend/genesys/settings.h index ab07a2d67..1cb83e60c 100644 --- a/backend/genesys/settings.h +++ b/backend/genesys/settings.h @@ -105,6 +105,9 @@ struct Genesys_Settings } }; +std::ostream& operator<<(std::ostream& out, const Genesys_Settings& settings); + + struct SetupParams { static constexpr unsigned NOT_SET = std::numeric_limits::max(); @@ -182,6 +185,8 @@ struct SetupParams { } }; +std::ostream& operator<<(std::ostream& out, const SetupParams& params); + template void serialize(Stream& str, SetupParams& x) { @@ -315,6 +320,10 @@ struct ScanSession { } }; +std::ostream& operator<<(std::ostream& out, const ScanSession& session); + +std::ostream& operator<<(std::ostream& out, const SANE_Parameters& params); + } // namespace genesys #endif // BACKEND_GENESYS_SETTINGS_H diff --git a/backend/genesys/utilities.h b/backend/genesys/utilities.h index ffd0263d4..39a2766cd 100644 --- a/backend/genesys/utilities.h +++ b/backend/genesys/utilities.h @@ -47,6 +47,7 @@ #include "error.h" #include #include +#include #include namespace genesys { @@ -118,6 +119,31 @@ private: using StreamStateSaver = BasicStreamStateSaver>; +template +std::string format_indent_braced_list(unsigned indent, const T& x) +{ + std::string indent_str(indent, ' '); + std::ostringstream out; + out << x; + auto formatted_str = out.str(); + if (formatted_str.empty()) { + return formatted_str; + } + + std::string out_str; + for (std::size_t i = 0; i < formatted_str.size(); ++i) { + out_str += formatted_str[i]; + + if (formatted_str[i] == '\n' && + i < formatted_str.size() - 1 && + formatted_str[i + 1] != '\n') + { + out_str += indent_str; + } + } + return out_str; +} + } // namespace genesys #endif // BACKEND_GENESYS_UTILITIES_H