summaryrefslogtreecommitdiffstats
path: root/src/spreadsheet/check_dumper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/spreadsheet/check_dumper.cpp')
-rw-r--r--src/spreadsheet/check_dumper.cpp209
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: */