[gnumeric] use better conventions for MS's ODF formulae
- From: Andreas J. Guelzow <guelzow src gnome org>
- To: svn-commits-list gnome org
- Subject: [gnumeric] use better conventions for MS's ODF formulae
- Date: Sun, 10 May 2009 18:43:10 -0400 (EDT)
commit 4a14183a172d1a051bb509c75cc66250c1b54f1a
Author: Andreas J. Guelzow <aguelzow pyrshep ca>
Date: Sun May 10 16:42:36 2009 -0600
use better conventions for MS's ODF formulae
2009-05-10 Andreas J. Guelzow <aguelzow pyrshep ca>
* openoffice-read.c (OOParseState): use an array of conventions
(oo_expr_parse_str): use oo_expr_parse_str
(oo_load_convention): new
(openoffice_file_open): initialize conv array members to NULL and free
at end
---
plugins/openoffice/ChangeLog | 8 +
plugins/openoffice/openoffice-read.c | 305 ++++++++++++++++++----------------
2 files changed, 173 insertions(+), 140 deletions(-)
diff --git a/plugins/openoffice/ChangeLog b/plugins/openoffice/ChangeLog
index ce3b9b3..ad8dbf4 100644
--- a/plugins/openoffice/ChangeLog
+++ b/plugins/openoffice/ChangeLog
@@ -1,5 +1,13 @@
2009-05-10 Andreas J. Guelzow <aguelzow pyrshep ca>
+ * openoffice-read.c (OOParseState): use an array of conventions
+ (oo_expr_parse_str): use oo_expr_parse_str
+ (oo_load_convention): new
+ (openoffice_file_open): initialize conv array members to NULL and free
+ at end
+
+2009-05-10 Andreas J. Guelzow <aguelzow pyrshep ca>
+
* openoffice-read.c (oo_expr_parse_str): use Gnumeric's conventions when
parsing MS's formulas
diff --git a/plugins/openoffice/openoffice-read.c b/plugins/openoffice/openoffice-read.c
index 0bd0f33..a4d53fb 100644
--- a/plugins/openoffice/openoffice-read.c
+++ b/plugins/openoffice/openoffice-read.c
@@ -47,6 +47,7 @@
#include <print-info.h>
#include <command-context.h>
#include <gutils.h>
+#include <xml-io.h>
#include <goffice/app/io-context.h>
#include <goffice/app/go-doc.h>
#include <goffice/utils/go-units.h>
@@ -104,7 +105,8 @@ static struct {
/* Formula Type */
typedef enum {
FORMULA_OPENFORMULA = 0,
- FORMULA_MICROSOFT
+ FORMULA_MICROSOFT,
+ NUM_FORMULAE_SUPPORTED
} OOFormula;
#define OD_BORDER_THIN 1
@@ -225,7 +227,7 @@ typedef struct {
char *fmt_name;
GnmFilter *filter;
- GnmConventions *convs;
+ GnmConventions *convs[NUM_FORMULAE_SUPPORTED];
struct {
GnmPageBreaks *h, *v;
} page_breaks;
@@ -477,6 +479,158 @@ oo_attr_enum (GsfXMLIn *xin, xmlChar const * const *attrs,
name, attrs[1]);
}
+static char const *
+oo_cellref_parse (GnmCellRef *ref, char const *start, GnmParsePos const *pp)
+{
+ char const *tmp1, *tmp2, *ptr = start;
+ GnmSheetSize const *ss;
+
+ if (*ptr != '.') {
+ char *name, *accum;
+
+ /* ignore abs vs rel for sheets */
+ if (*ptr == '$')
+ ptr++;
+
+ /* From the spec :
+ * SheetName ::= [^\. ']+ | "'" ([^'] | "''")+ "'" */
+ if ('\'' == *ptr) {
+ tmp1 = ++ptr;
+two_quotes :
+ /* missing close paren */
+ if (NULL == (tmp1 = strchr (tmp1, '\'')))
+ return start;
+
+ /* two in a row is the escape for a single */
+ if (tmp1[1] == '\'') {
+ tmp1 += 2;
+ goto two_quotes;
+ }
+
+ /* If a name is quoted the entire named must be quoted */
+ if (tmp1[1] != '.')
+ return start;
+
+ accum = name = g_alloca (tmp1-ptr+1);
+ while (ptr != tmp1)
+ if ('\'' == (*accum++ = *ptr++))
+ ptr++;
+ *accum = '\0';
+ ptr += 2;
+ } else {
+ if (NULL == (tmp1 = strchr (ptr, '.')))
+ return start;
+ name = g_alloca (tmp1-ptr+1);
+ strncpy (name, ptr, tmp1-ptr);
+ name[tmp1-ptr] = '\0';
+ ptr = tmp1 + 1;
+ }
+
+ if (name[0] == 0)
+ return start;
+
+ /* OpenCalc does not pre-declare its sheets, but it does have a
+ * nice unambiguous format. So if we find a name that has not
+ * been added yet add it. Reorder below. */
+ ref->sheet = workbook_sheet_by_name (pp->wb, name);
+ if (ref->sheet == NULL) {
+ if (strcmp (name, "#REF!") == 0) {
+ g_warning ("Ignoring reference to sheet %s", name);
+ ref->sheet = NULL;
+ } else {
+ Sheet *old_sheet = workbook_sheet_by_index (pp->wb, 0);
+ ref->sheet = sheet_new (pp->wb, name,
+ gnm_sheet_get_max_cols (old_sheet),
+ gnm_sheet_get_max_rows (old_sheet));
+ workbook_sheet_attach (pp->wb, ref->sheet);
+ }
+ }
+ } else {
+ ptr++; /* local ref */
+ ref->sheet = NULL;
+ }
+
+ ss = gnm_sheet_get_size (eval_sheet (ref->sheet, pp->sheet));
+
+ tmp1 = col_parse (ptr, ss, &ref->col, &ref->col_relative);
+ if (!tmp1)
+ return start;
+ tmp2 = row_parse (tmp1, ss, &ref->row, &ref->row_relative);
+ if (!tmp2)
+ return start;
+
+ if (ref->col_relative)
+ ref->col -= pp->eval.col;
+ if (ref->row_relative)
+ ref->row -= pp->eval.row;
+ return tmp2;
+}
+
+static char const *
+oo_rangeref_parse (GnmRangeRef *ref, char const *start, GnmParsePos const *pp)
+{
+ char const *ptr = oo_cellref_parse (&ref->a, start, pp);
+ if (*ptr == ':')
+ ptr = oo_cellref_parse (&ref->b, ptr+1, pp);
+ else
+ ref->b = ref->a;
+ return ptr;
+}
+
+static char const *
+oo_expr_rangeref_parse (GnmRangeRef *ref, char const *start, GnmParsePos const *pp,
+ G_GNUC_UNUSED GnmConventions const *convs)
+{
+ char const *ptr;
+ if (*start == '[') {
+ ptr = oo_rangeref_parse (ref, start+1, pp);
+ if (*ptr == ']')
+ return ptr + 1;
+ }
+ return start;
+}
+
+static GnmExpr const *
+oo_func_map_in (GnmConventions const *convs, Workbook *scope,
+ char const *name, GnmExprList *args);
+
+static GnmConventions *
+oo_conventions_new (void)
+{
+ GnmConventions *conv = gnm_conventions_new ();
+
+ conv->decode_ampersands = TRUE;
+
+ conv->intersection_char = '!';
+ conv->decimal_sep_dot = TRUE;
+ conv->range_sep_colon = TRUE;
+ conv->arg_sep = ';';
+ conv->array_col_sep = ';';
+ conv->array_row_sep = '|';
+ conv->input.func = oo_func_map_in;
+ conv->input.range_ref = oo_expr_rangeref_parse;
+
+ return conv;
+}
+
+static void
+oo_load_convention (OOParseState *state, OOFormula type)
+{
+ g_return_if_fail (state->convs[type] == NULL);
+
+ switch (type) {
+ case FORMULA_MICROSOFT:
+ state->convs[type] = gnm_xml_io_conventions ();
+ break;
+ case FORMULA_OPENFORMULA:
+ default:
+ state->convs[type] = oo_conventions_new ();
+ break;
+ }
+
+
+}
+
static GnmExprTop const *
oo_expr_parse_str (GsfXMLIn *xin, char const *str,
GnmParsePos const *pp, GnmExprParseFlags flags,
@@ -486,14 +640,11 @@ oo_expr_parse_str (GsfXMLIn *xin, char const *str,
GnmExprTop const *texpr;
GnmParseError perr;
+ if (state->convs[type] == NULL)
+ oo_load_convention (state, type);
parse_error_init (&perr);
- if (type == FORMULA_OPENFORMULA)
- texpr = gnm_expr_parse_str (str, pp, flags,
- state->convs, &perr);
- else
- texpr = gnm_expr_parse_str (str, pp, flags,
- gnm_conventions_default, &perr);
-
+ texpr = gnm_expr_parse_str (str, pp, flags,
+ state->convs[type], &perr);
if (texpr == NULL) {
oo_warning (xin, _("Unable to parse\n\t'%s'\nbecause '%s'"),
str, perr.err->message);
@@ -819,116 +970,6 @@ oo_row_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
state->pos.eval.row += state->row_inc;
}
-static char const *
-oo_cellref_parse (GnmCellRef *ref, char const *start, GnmParsePos const *pp)
-{
- char const *tmp1, *tmp2, *ptr = start;
- GnmSheetSize const *ss;
-
- if (*ptr != '.') {
- char *name, *accum;
-
- /* ignore abs vs rel for sheets */
- if (*ptr == '$')
- ptr++;
-
- /* From the spec :
- * SheetName ::= [^\. ']+ | "'" ([^'] | "''")+ "'" */
- if ('\'' == *ptr) {
- tmp1 = ++ptr;
-two_quotes :
- /* missing close paren */
- if (NULL == (tmp1 = strchr (tmp1, '\'')))
- return start;
-
- /* two in a row is the escape for a single */
- if (tmp1[1] == '\'') {
- tmp1 += 2;
- goto two_quotes;
- }
-
- /* If a name is quoted the entire named must be quoted */
- if (tmp1[1] != '.')
- return start;
-
- accum = name = g_alloca (tmp1-ptr+1);
- while (ptr != tmp1)
- if ('\'' == (*accum++ = *ptr++))
- ptr++;
- *accum = '\0';
- ptr += 2;
- } else {
- if (NULL == (tmp1 = strchr (ptr, '.')))
- return start;
- name = g_alloca (tmp1-ptr+1);
- strncpy (name, ptr, tmp1-ptr);
- name[tmp1-ptr] = '\0';
- ptr = tmp1 + 1;
- }
-
- if (name[0] == 0)
- return start;
-
- /* OpenCalc does not pre-declare its sheets, but it does have a
- * nice unambiguous format. So if we find a name that has not
- * been added yet add it. Reorder below. */
- ref->sheet = workbook_sheet_by_name (pp->wb, name);
- if (ref->sheet == NULL) {
- if (strcmp (name, "#REF!") == 0) {
- g_warning ("Ignoring reference to sheet %s", name);
- ref->sheet = NULL;
- } else {
- Sheet *old_sheet = workbook_sheet_by_index (pp->wb, 0);
- ref->sheet = sheet_new (pp->wb, name,
- gnm_sheet_get_max_cols (old_sheet),
- gnm_sheet_get_max_rows (old_sheet));
- workbook_sheet_attach (pp->wb, ref->sheet);
- }
- }
- } else {
- ptr++; /* local ref */
- ref->sheet = NULL;
- }
-
- ss = gnm_sheet_get_size (eval_sheet (ref->sheet, pp->sheet));
-
- tmp1 = col_parse (ptr, ss, &ref->col, &ref->col_relative);
- if (!tmp1)
- return start;
- tmp2 = row_parse (tmp1, ss, &ref->row, &ref->row_relative);
- if (!tmp2)
- return start;
-
- if (ref->col_relative)
- ref->col -= pp->eval.col;
- if (ref->row_relative)
- ref->row -= pp->eval.row;
- return tmp2;
-}
-
-static char const *
-oo_rangeref_parse (GnmRangeRef *ref, char const *start, GnmParsePos const *pp)
-{
- char const *ptr = oo_cellref_parse (&ref->a, start, pp);
- if (*ptr == ':')
- ptr = oo_cellref_parse (&ref->b, ptr+1, pp);
- else
- ref->b = ref->a;
- return ptr;
-}
-
-static char const *
-oo_expr_rangeref_parse (GnmRangeRef *ref, char const *start, GnmParsePos const *pp,
- G_GNUC_UNUSED GnmConventions const *convs)
-{
- char const *ptr;
- if (*start == '[') {
- ptr = oo_rangeref_parse (ref, start+1, pp);
- if (*ptr == ']')
- return ptr + 1;
- }
- return start;
-}
static void
oo_cell_start (GsfXMLIn *xin, xmlChar const **attrs)
@@ -2925,25 +2966,6 @@ oo_func_map_in (GnmConventions const *convs, Workbook *scope,
return gnm_expr_new_funcall (f, args);
}
-static GnmConventions *
-oo_conventions_new (void)
-{
- GnmConventions *conv = gnm_conventions_new ();
-
- conv->decode_ampersands = TRUE;
-
- conv->intersection_char = '!';
- conv->decimal_sep_dot = TRUE;
- conv->range_sep_colon = TRUE;
- conv->arg_sep = ';';
- conv->array_col_sep = ';';
- conv->array_row_sep = '|';
- conv->input.func = oo_func_map_in;
- conv->input.range_ref = oo_expr_rangeref_parse;
-
- return conv;
-}
-
static OOVer
determine_oo_version (GsfInfile *zip, OOVer def)
{
@@ -3061,7 +3083,8 @@ openoffice_file_open (GOFileOpener const *fo, IOContext *io_context,
state.default_style_cell = NULL;
state.cur_style_type = OO_STYLE_UNKNOWN;
state.sheet_order = NULL;
- state.convs = oo_conventions_new ();
+ for (i = 0; i<NUM_FORMULAE_SUPPORTED; i++)
+ state.convs[i] = NULL;
state.accum_fmt = NULL;
state.filter = NULL;
state.page_breaks.h = state.page_breaks.v = NULL;
@@ -3154,7 +3177,9 @@ openoffice_file_open (GOFileOpener const *fo, IOContext *io_context,
while (i-- > 0)
sheet_flag_recompute_spans (workbook_sheet_by_index (state.pos.wb, i));
- gnm_conventions_free (state.convs);
+ for (i = 0; i<NUM_FORMULAE_SUPPORTED; i++)
+ if (state.convs[i] != NULL)
+ gnm_conventions_free (state.convs[i]);
gnm_pop_C_locale (locale);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]