[gnumeric] xls: fix saving of IFERROR and other XL97 functions.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] xls: fix saving of IFERROR and other XL97 functions.
- Date: Wed, 10 Apr 2013 15:55:56 +0000 (UTC)
commit b8ce7050e700eece8b5674bc035de69f9f7df62b
Author: Morten Welinder <terra gnome org>
Date: Wed Apr 10 11:55:18 2013 -0400
xls: fix saving of IFERROR and other XL97 functions.
NEWS | 3 +-
plugins/excel/ms-excel-read.c | 37 ++++++++++++++++
plugins/excel/ms-formula-write.c | 85 ++++++++++++++++++++------------------
3 files changed, 84 insertions(+), 41 deletions(-)
---
diff --git a/NEWS b/NEWS
index 1eb43a5..14b9598 100644
--- a/NEWS
+++ b/NEWS
@@ -25,12 +25,13 @@ Morten:
* Fix problems with R.PSNORM. [#697293]
* New function OWENT.
* New function POCHHAMMER.
- * Fix import of IFERROR from xls.
+ * Fix import of XL97 functions like IFERROR from xls.
* Add test sheet for complex number parsing.
* Improve complex number parsing.
* Fix error codes for complex number functions.
* Fix import of non-Excel functions from LO's xls files.
* Fix problem with xls saving of externnames.
+ * Fix saving of certain XL97 functions like IFERROR.
--------------------------------------------------------------------------
Gnumeric 1.12.1
diff --git a/plugins/excel/ms-excel-read.c b/plugins/excel/ms-excel-read.c
index f935c85..1d0312f 100644
--- a/plugins/excel/ms-excel-read.c
+++ b/plugins/excel/ms-excel-read.c
@@ -7225,6 +7225,26 @@ excel_read_workbook (GOIOContext *context, WorkbookView *wb_view,
static GSList *formats;
+/*
+ * These are special in that they appear to be saved as macros.
+ * Excel will only recognize them when saved as macros: neither
+ * externname as "IFERROR" nor "_xlfn.IFERROR" will work.
+ */
+static const ExcelFuncDesc excel97_func_desc[] = {
+ { 0xff, "_xlfn.AVERAGEIF", -1, -1, XL_XLM },
+ { 0xff, "_xlfn.AVERAGEIFS", -1, -1, XL_XLM },
+ { 0xff, "_xlfn.CUBEKPIMEMBER", -1, -1, XL_XLM },
+ { 0xff, "_xlfn.CUBEMEMBER", -1, -1, XL_XLM },
+ { 0xff, "_xlfn.CUBEMEMBERPROPERTY", -1, -1, XL_XLM },
+ { 0xff, "_xlfn.CUBERANKEDMEMBER", -1, -1, XL_XLM },
+ { 0xff, "_xlfn.CUBESET", -1, -1, XL_XLM },
+ { 0xff, "_xlfn.CUBESETCOUNT", -1, -1, XL_XLM },
+ { 0xff, "_xlfn.CUBEVALUE", -1, -1, XL_XLM },
+ { 0xff, "_xlfn.COUNTIFS", -1, -1, XL_XLM },
+ { 0xff, "_xlfn.IFERROR", 2, 2, XL_XLM, 2, 'V', "VV" },
+ { 0xff, "_xlfn.SUMIFS", -1, -1, XL_XLM }
+};
+
void
excel_read_init (void)
{
@@ -7263,6 +7283,23 @@ excel_read_init (void)
(gpointer)name,
(gpointer)efd);
}
+
+ for (i = 0; i < (int)G_N_ELEMENTS(excel97_func_desc); i++) {
+ const ExcelFuncDesc *efd = excel97_func_desc + i;
+ const char *excel_name = efd->name;
+ const char *gnm_name = strchr (excel_name, '.') + 1;
+ GnmFunc *func = gnm_func_lookup (gnm_name, NULL);
+
+ /* Fix case. */
+ if (func)
+ gnm_name = gnm_func_get_name (func, FALSE);
+
+ g_assert (g_hash_table_lookup (excel_func_by_name, gnm_name) ==
+ NULL);
+ g_hash_table_insert (excel_func_by_name,
+ (gpointer)gnm_name,
+ (gpointer)efd);
+ }
}
void
diff --git a/plugins/excel/ms-formula-write.c b/plugins/excel/ms-formula-write.c
index 0c8b32d..6f43d3f 100644
--- a/plugins/excel/ms-formula-write.c
+++ b/plugins/excel/ms-formula-write.c
@@ -110,7 +110,7 @@ do_excel_write_prep_expr (ExcelWriteState *ewb, GnmExpr const *expr)
*/
ef = g_hash_table_lookup (ewb->function_map, func);
if (ef != NULL)
- return;
+ break;
ef = g_new (ExcelFunc, 1);
ef->efunc = (func->flags & (GNM_FUNC_IS_PLACEHOLDER |
@@ -119,15 +119,20 @@ do_excel_write_prep_expr (ExcelWriteState *ewb, GnmExpr const *expr)
: g_hash_table_lookup (excel_func_by_name,
func->name);
- if (ef->efunc) {
- ef->idx = ef->efunc - excel_func_desc;
+ if (ef->efunc && ef->efunc->idx == 0xff) {
+ /* These functions appear to be saved as macros! */
+ ef->macro_name = g_strdup (ef->efunc->name);
+ ef->idx = -1;
+ } else if (ef->efunc) {
ef->macro_name = NULL;
+ ef->idx = ef->efunc->idx;
} else if (func->flags & GNM_FUNC_IS_WORKBOOK_LOCAL) {
ef->macro_name = g_strdup (func->name);
ef->idx = -1;
} else {
- g_ptr_array_add (ewb->externnames,
- g_utf8_strup (gnm_func_get_name (func, FALSE), -1));
+ char *fname =
+ g_utf8_strup (gnm_func_get_name (func, FALSE), -1);
+ g_ptr_array_add (ewb->externnames, fname);
ef->macro_name = NULL;
ef->idx = ewb->externnames->len;
}
@@ -523,7 +528,7 @@ write_funcall (PolishData *pd, GnmExpr const *expr,
{
static guint8 const zeros [12];
- int arg;
+ int arg, min_args, max_args, name_arg = 0;
gboolean prompt = FALSE;
gboolean cmdequiv = FALSE;
char const *arg_types = NULL;
@@ -531,10 +536,25 @@ write_funcall (PolishData *pd, GnmExpr const *expr,
GnmFunc *func = expr->func.func;
ExcelFunc *ef = g_hash_table_lookup (pd->ewb->function_map, func);
XLOpType arg_type = XL_VAL; /* default */
+ XLOpType func_type;
+ int func_idx;
+ guint8 op_class;
g_return_if_fail (ef != NULL);
- if (ef->efunc == NULL) {
+ if (ef->efunc) {
+ min_args = ef->efunc->min_args;
+ max_args = ef->efunc->max_args;
+ func_idx = ef->efunc->idx;
+ func_type = xl_map_char_to_type (ef->efunc->type);
+ arg_types = ef->efunc->known_args;
+ } else {
+ min_args = max_args = expr->func.argc;
+ func_idx = 0xff;
+ func_type = XL_VAL; /*Assumption */
+ }
+
+ if (ef->efunc == NULL || ef->efunc->idx == 0xff) {
if (ef->macro_name != NULL) {
push_guint8 (pd, FORMULA_PTG_NAME);
push_guint16 (pd, ef->idx);
@@ -556,14 +576,13 @@ write_funcall (PolishData *pd, GnmExpr const *expr,
push_guint16 (pd, ef->idx);
push_guint16 (pd, 0); /* reserved */
}
-
- arg_types_holder = guess_arg_types (func);
- arg_types = arg_types_holder;
}
- } else
- arg_types = ef->efunc->known_args;
+ name_arg = 1;
+ }
- for (arg = 0; arg < expr->func.argc; arg++)
+ if (!arg_types)
+ arg_types = arg_types_holder = guess_arg_types (func);
+ for (arg = 0; arg < expr->func.argc; arg++) {
if (ef->efunc != NULL && arg >= ef->efunc->max_args) {
go_io_warning (pd->ewb->io_context,
_("Too many arguments for function '%s', MS Excel can only handle %d not %d"),
@@ -577,35 +596,21 @@ write_funcall (PolishData *pd, GnmExpr const *expr,
}
write_node (pd, expr->func.argv[arg], 0, arg_type);
}
+ }
+ /* If XL requires more arguments than we do
+ * pad the remainder with missing args */
+ for ( ; arg < min_args ; arg++)
+ push_guint8 (pd, FORMULA_PTG_MISSARG);
g_free (arg_types_holder);
- if (ef->efunc != NULL) {
- guint8 op_class = xl_get_op_class (pd,
- xl_map_char_to_type (ef->efunc->type), target_type);
-
-#if FORMULA_DEBUG > 1
- g_printerr ("Writing function '%s' as idx %d, args %d\n",
- name, ef->u.std.idx, fce->u.std.efunc->num_known_args);
-#endif
-
- /* If XL requires more arguments than we do
- * pad the remainder with missing args */
- for ( ; arg < ef->efunc->min_args ; arg++)
- push_guint8 (pd, FORMULA_PTG_MISSARG);
-
- if (ef->efunc->min_args != ef->efunc->max_args) {
- push_guint8 (pd, FORMULA_PTG_FUNC_VAR + op_class);
- push_guint8 (pd, arg | (prompt ? 0x80 : 0));
- push_guint16 (pd, ef->idx | (cmdequiv ? 0x8000 : 0));
- } else {
- push_guint8 (pd, FORMULA_PTG_FUNC + op_class);
- push_guint16 (pd, ef->idx);
- }
- } else { /* Undocumented, assume result is XL_VAL */
- push_guint8 (pd, FORMULA_PTG_FUNC_VAR +
- xl_get_op_class (pd, XL_VAL, target_type));
- push_guint8 (pd, (arg + 1) | (prompt ? 0x80 : 0));
- push_guint16 (pd, 0xff | (cmdequiv ? 0x8000 : 0));
+ op_class = xl_get_op_class (pd, func_type, target_type);
+ if (name_arg || min_args != max_args) {
+ push_guint8 (pd, FORMULA_PTG_FUNC_VAR + op_class);
+ push_guint8 (pd, (arg + name_arg) | (prompt ? 0x80 : 0));
+ push_guint16 (pd, func_idx | (cmdequiv ? 0x8000 : 0));
+ } else {
+ push_guint8 (pd, FORMULA_PTG_FUNC + op_class);
+ push_guint16 (pd, func_idx);
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]