diff options
Diffstat (limited to 'src/spreadsheet/check_dumper.cpp')
-rw-r--r-- | src/spreadsheet/check_dumper.cpp | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/src/spreadsheet/check_dumper.cpp b/src/spreadsheet/check_dumper.cpp new file mode 100644 index 0000000..191b5a0 --- /dev/null +++ b/src/spreadsheet/check_dumper.cpp @@ -0,0 +1,209 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "check_dumper.hpp" +#include "sheet_impl.hpp" +#include "number_format.hpp" +#include "orcus/spreadsheet/document.hpp" + +#include <ixion/model_context.hpp> +#include <ixion/cell.hpp> +#include <ixion/formula.hpp> +#include <ixion/formula_name_resolver.hpp> +#include <ixion/formula_result.hpp> + +#include <string> +#include <algorithm> + +namespace orcus { namespace spreadsheet { namespace detail { + +namespace { + +void write_cell_position(std::ostream& os, std::string_view sheet_name, row_t row, col_t col) +{ + os << sheet_name << '/' << row << '/' << col << ':'; +} + +std::string escape_chars(const std::string& str) +{ + if (str.empty()) + return str; + + std::string ret; + const char* p = &str[0]; + const char* p_end = p + str.size(); + for (; p != p_end; ++p) + { + if (*p == '"') + ret.push_back('\\'); + ret.push_back(*p); + } + return ret; +} + +} + +check_dumper::check_dumper(const detail::sheet_impl& sheet, std::string_view sheet_name) : + m_sheet(sheet), m_sheet_name(sheet_name) +{ +} + +void check_dumper::dump(std::ostream& os) const +{ + dump_cell_values(os); + dump_merged_cell_info(os); +} + +void check_dumper::dump_cell_values(std::ostream& os) const +{ + ixion::abs_range_t range = m_sheet.get_data_range(); + if (!range.valid()) + // Sheet is empty. Nothing to print. + return; + + const ixion::model_context& cxt = m_sheet.doc.get_model_context(); + const ixion::formula_name_resolver* resolver = + m_sheet.doc.get_formula_name_resolver(spreadsheet::formula_ref_context_t::global); + + size_t row_count = range.last.row + 1; + size_t col_count = range.last.column + 1; + + for (size_t row = 0; row < row_count; ++row) + { + for (size_t col = 0; col < col_count; ++col) + { + ixion::abs_address_t pos(m_sheet.sheet_id, row, col); + switch (cxt.get_celltype(pos)) + { + case ixion::celltype_t::string: + { + write_cell_position(os, m_sheet_name, row, col); + size_t sindex = cxt.get_string_identifier(pos); + const std::string* p = cxt.get_string(sindex); + assert(p); + os << "string:\"" << escape_chars(*p) << '"' << std::endl; + break; + } + case ixion::celltype_t::numeric: + { + write_cell_position(os, m_sheet_name, row, col); + os << "numeric:"; + detail::format_to_file_output(os, cxt.get_numeric_value(pos)); + os << std::endl; + break; + } + case ixion::celltype_t::boolean: + { + write_cell_position(os, m_sheet_name, row, col); + os << "boolean:" << (cxt.get_boolean_value(pos) ? "true" : "false") << std::endl; + break; + } + case ixion::celltype_t::formula: + { + write_cell_position(os, m_sheet_name, row, col); + os << "formula"; + + // print the formula and the formula result. + const ixion::formula_cell* cell = cxt.get_formula_cell(pos); + assert(cell); + const ixion::formula_tokens_store_ptr_t& ts = cell->get_tokens(); + if (ts) + { + const ixion::formula_tokens_t& tokens = ts->get(); + std::string formula; + if (resolver) + { + pos = cell->get_parent_position(pos); + formula = ixion::print_formula_tokens( + m_sheet.doc.get_model_context(), pos, *resolver, tokens); + } + else + formula = "???"; + + os << ':'; + + ixion::formula_group_t fg = cell->get_group_properties(); + + if (fg.grouped) + os << '{' << formula << '}'; + else + os << formula; + + try + { + ixion::formula_result res = cell->get_result_cache( + ixion::formula_result_wait_policy_t::throw_exception); + os << ':' << res.str(m_sheet.doc.get_model_context()); + } + catch (const std::exception&) + { + os << ":#RES!"; + } + } + + os << std::endl; + break; + } + default: + ; + } + } + } +} + +void check_dumper::dump_merged_cell_info(std::ostream& os) const +{ + // Sort by rows first then by columns. + + struct _entry + { + row_t row; + col_t col; + const merge_size* ms; + + _entry(row_t _row, col_t _col, const merge_size* _ms) : + row(_row), col(_col), ms(_ms) {} + }; + + std::vector<_entry> entries; + + for (const auto& col_entry : m_sheet.merge_ranges) + { + col_t col = col_entry.first; + + for (const auto& row_entry : *col_entry.second) + { + row_t row = row_entry.first; + const merge_size& ms = row_entry.second; + + entries.emplace_back(row, col, &ms); + } + } + + std::sort(entries.begin(), entries.end(), + [](const _entry& left, const _entry& right) -> bool + { + if (left.row != right.row) + return left.row < right.row; + + if (left.col != right.col) + return left.col < right.col; + + return left.ms < right.ms; + } + ); + + for (const _entry e : entries) + { + os << m_sheet_name << '/' << e.row << '/' << e.col << ":merge-width:" << e.ms->width << std::endl; + os << m_sheet_name << '/' << e.row << '/' << e.col << ":merge-height:" << e.ms->height << std::endl; + } +} + +}}} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |