[gnumeric: 1/9] ssdiff: new utility to compare two spreadsheets.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric: 1/9] ssdiff: new utility to compare two spreadsheets.
- Date: Mon, 24 Dec 2012 18:26:05 +0000 (UTC)
commit 77c4f4fb94c43fd347542cedb85996f434b5614e
Author: Morten Welinder <terra gnome org>
Date: Sat Dec 15 11:36:19 2012 -0500
ssdiff: new utility to compare two spreadsheets.
This is a rough first cut.
src/.gitignore | 2 +
src/Makefile.am | 5 +
src/ssdiff.c | 271 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 278 insertions(+), 0 deletions(-)
---
diff --git a/src/.gitignore b/src/.gitignore
index 5391b59..6053a1e 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -22,6 +22,8 @@ ssgrep
ssgrep.exe
sstest
sstest.exe
+ssdiff
+ssdiff.exe
test-pango
test-pango.exe
GNOME_Gnumeric-gtk.xml
diff --git a/src/Makefile.am b/src/Makefile.am
index d326b0f..5bd810c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -37,6 +37,7 @@ endif
if ENABLE_SSGREP
bin_PROGRAMS += ssgrep
endif
+bin_PROGRAMS += ssdiff
AM_CPPFLAGS = \
-I$(top_srcdir) \
@@ -363,6 +364,10 @@ sstest_LDADD = $(gnumeric_LDADD)
sstest_LDFLAGS = -export-dynamic
sstest_SOURCES = \
sstest.c
+ssdiff_LDADD = $(gnumeric_LDADD)
+ssdiff_LDFLAGS = -export-dynamic
+ssdiff_SOURCES = \
+ ssdiff.c
test_pango_LDADD = $(gnumeric_LDADD)
test_pango_LDFLAGS = -export-dynamic
diff --git a/src/ssdiff.c b/src/ssdiff.c
new file mode 100644
index 0000000..54cad03
--- /dev/null
+++ b/src/ssdiff.c
@@ -0,0 +1,271 @@
+/*
+ * ssdiff.c: A diff program for spreadsheets.
+ *
+ * Author:
+ * Morten Welinder <terra gnome org>
+ *
+ * Copyright (C) 2012 Morten Welinder (terra gnome org)
+ */
+
+#include <gnumeric-config.h>
+#include <glib/gi18n.h>
+#include "gnumeric.h"
+#include <goffice/goffice.h>
+#include "libgnumeric.h"
+#include "gutils.h"
+#include "command-context.h"
+#include "command-context-stderr.h"
+#include "gnm-plugin.h"
+#include "workbook-view.h"
+#include "workbook.h"
+#include "sheet.h"
+#include "cell.h"
+#include "value.h"
+
+static gboolean ssdiff_show_version = FALSE;
+
+static const GOptionEntry ssdiff_options [] = {
+ {
+ "version", 'v',
+ 0, G_OPTION_ARG_NONE, &ssdiff_show_version,
+ N_("Display program version"),
+ NULL
+ },
+
+ /* ---------------------------------------- */
+
+ { NULL }
+};
+
+typedef struct GnmDiffHandler_ {
+ GOIOContext *ioc;
+ struct {
+ char *url;
+ Workbook *wb;
+ WorkbookView *wbv;
+ } old, new;
+} GnmDiffHandler;
+
+static gint
+cell_ordering (gconstpointer a_, gconstpointer b_)
+{
+ GnmCell const *a = *(GnmCell **)a_;
+ GnmCell const *b = *(GnmCell **)b_;
+
+ if (a->pos.row != b->pos.row)
+ return a->pos.row - b->pos.row;
+
+ return a->pos.col - b->pos.col;
+}
+
+static gboolean
+compare_cells (GnmCell const *co, GnmCell const *cn)
+{
+ gboolean has_expr = gnm_cell_has_expr (co);
+ gboolean has_value = co->value != NULL;
+
+ if (has_expr != gnm_cell_has_expr (cn))
+ return TRUE;
+ if (has_expr) {
+ char *eo = gnm_cell_get_entered_text (co);
+ char *en = gnm_cell_get_entered_text (cn);
+ gboolean changed = !g_str_equal (co, cn);
+ g_free (eo);
+ g_free (en);
+ return changed;
+ }
+
+ if (has_value != (cn->value != NULL))
+ return TRUE;
+ if (has_value)
+ return !value_equal (co->value, cn->value);
+
+ return FALSE;
+}
+
+
+static void
+diff_sheets_cells (GnmDiffHandler *state, Sheet *old_sheet, Sheet *new_sheet)
+{
+ GPtrArray *old_cells = sheet_cells (old_sheet, NULL);
+ GPtrArray *new_cells = sheet_cells (new_sheet, NULL);
+ size_t io = 0, in = 0;
+
+ /* Make code below simpler. */
+ g_ptr_array_add (old_cells, NULL);
+ g_ptr_array_add (new_cells, NULL);
+
+ while (TRUE) {
+ GnmCell const *co = g_ptr_array_index (old_cells, io);
+ GnmCell const *cn = g_ptr_array_index (new_cells, in);
+
+ if (co && cn) {
+ int order = cell_ordering (&co, &cn);
+ if (order < 0)
+ cn = NULL;
+ else if (order > 0)
+ co = NULL;
+ else {
+ if (compare_cells (co, cn)) {
+ g_printerr ("Contents of %s!%s has changed.\n",
+ old_sheet->name_quoted,
+ cell_name (co));
+ }
+
+ io++, in++;
+ continue;
+ }
+ }
+
+ if (co) {
+ g_printerr ("Cell %s!%s removed.\n",
+ old_sheet->name_quoted, cell_name (co));
+ io++;
+ } else if (cn) {
+ g_printerr ("Cell %s!%s added.\n",
+ new_sheet->name_quoted, cell_name (cn));
+ in++;
+ } else
+ break;
+ }
+
+ g_ptr_array_free (old_cells, TRUE);
+ g_ptr_array_free (new_cells, TRUE);
+}
+
+static void
+diff_sheets (GnmDiffHandler *state, Sheet *old_sheet, Sheet *new_sheet)
+{
+ /* Compare sheet attributes and sizes */
+
+ diff_sheets_cells (state, old_sheet, new_sheet);
+
+ /* Compare style */
+}
+
+static int
+diff (char const *oldfilename, char const *newfilename, GOIOContext *ioc)
+{
+ GnmDiffHandler state;
+ int res = 0;
+ int i, count;
+
+ memset (&state, 0, sizeof (state));
+ state.ioc = ioc;
+
+ state.old.url = go_shell_arg_to_uri (oldfilename);
+ state.new.url = go_shell_arg_to_uri (newfilename);
+
+ state.old.wbv = workbook_view_new_from_uri (state.old.url, NULL,
+ ioc, NULL);
+ if (!state.old.wbv)
+ goto error;
+ state.old.wb = wb_view_get_workbook (state.old.wbv);
+
+ state.new.wbv = workbook_view_new_from_uri (state.new.url, NULL,
+ ioc, NULL);
+ if (!state.new.wbv)
+ goto error;
+ state.new.wb = wb_view_get_workbook (state.new.wbv);
+
+ count = workbook_sheet_count (state.old.wb);
+ for (i = 0; i < count; i++) {
+ Sheet *old_sheet = workbook_sheet_by_index (state.old.wb, i);
+ Sheet *new_sheet = workbook_sheet_by_name (state.new.wb,
+ old_sheet->name_unquoted);
+ if (new_sheet)
+ diff_sheets (&state, old_sheet, new_sheet);
+ else {
+ g_printerr ("Sheet %s removed.\n",
+ old_sheet->name_quoted);
+ }
+ }
+
+ count = workbook_sheet_count (state.new.wb);
+ for (i = 0; i < count; i++) {
+ Sheet *new_sheet = workbook_sheet_by_index (state.new.wb, i);
+ Sheet *old_sheet = workbook_sheet_by_name (state.old.wb,
+ new_sheet->name_unquoted);
+ if (old_sheet)
+ ; /* Nothing */
+ else {
+ g_printerr ("Sheet %s added.\n",
+ new_sheet->name_quoted);
+ }
+ }
+
+out:
+ g_free (state.old.url);
+ g_free (state.new.url);
+ if (state.old.wb)
+ g_object_unref (state.old.wb);
+ if (state.new.wb)
+ g_object_unref (state.new.wb);
+ return res;
+
+error:
+ res = 1;
+ goto out;
+}
+
+int
+main (int argc, char const **argv)
+{
+ GOErrorInfo *plugin_errs;
+ int res = 0;
+ GOCmdContext *cc;
+ GOptionContext *ocontext;
+ GError *error = NULL;
+
+ /* No code before here, we need to init threads */
+ argv = gnm_pre_parse_init (argc, argv);
+
+ ocontext = g_option_context_new (_("OLDFILE NEWFILE"));
+ g_option_context_add_main_entries (ocontext, ssdiff_options, GETTEXT_PACKAGE);
+ g_option_context_add_group (ocontext, gnm_get_option_group ());
+ g_option_context_parse (ocontext, &argc, (char ***)&argv, &error);
+ g_option_context_free (ocontext);
+
+ if (error) {
+ g_printerr (_("%s\nRun '%s --help' to see a full list of available command line options.\n"),
+ error->message, argv[0]);
+ g_error_free (error);
+ return 1;
+ }
+
+ if (ssdiff_show_version) {
+ g_print (_("ssdiff version '%s'\ndatadir := '%s'\nlibdir := '%s'\n"),
+ GNM_VERSION_FULL, gnm_sys_data_dir (), gnm_sys_lib_dir ());
+ return 0;
+ }
+
+ gnm_init ();
+
+ cc = cmd_context_stderr_new ();
+ gnm_plugins_init (GO_CMD_CONTEXT (cc));
+ go_plugin_db_activate_plugin_list (
+ go_plugins_get_available_plugins (), &plugin_errs);
+ if (plugin_errs) {
+ /* FIXME: What do we want to do here? */
+ go_error_info_free (plugin_errs);
+ }
+ go_component_set_default_command_context (cc);
+
+ if (argc == 3) {
+ GOIOContext *ioc = go_io_context_new (cc);
+ res = diff (argv[1], argv[2], ioc);
+ g_object_unref (ioc);
+ } else {
+ g_printerr (_("Usage: %s [OPTION...] %s\n"),
+ g_get_prgname (),
+ _("OLDFILE NEWFILE"));
+ res = 1;
+ }
+
+ go_component_set_default_command_context (NULL);
+ g_object_unref (cc);
+ gnm_shutdown ();
+ gnm_pre_parse_shutdown ();
+
+ return res;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]