Commit f3bd2a8f authored by Jody Goldberg's avatar Jody Goldberg Committed by Jody Goldberg

move here and privatize.


2002-10-10  Jody Goldberg <jody@gnome.org>

	* src/expr-sheet.c (value_intersection) : move here and privatize.

	* src/func.c (function_call_with_list) : fence post error.  The first
	  missing arg can be empty.  While we're here fix the precedence error
	  that was breaking missing default args.  Remove use of
	  value_intersection.  gnm_expr_eval handles it (I hope)

	* src/expr.c (gnm_expr_eval) : support depends for constructed ranges too.

2002-10-10  Jody Goldberg <jody@gnome.org>

	* src/value-sheet.c (value_intersection) : move here and rework to
	  support singletons.

	* src/parser.y (parser_simple_val_or_name) : rename from
	  parser_lookup_name and restore some of the value matching semantics
	  so that we handle booleans again.  I'm not sure the error handling
	  will kick in but it too is good.  the duble and int comparisons
	  should be useless.  We can optimize things a bit by making a
	  special case routine and removing those.

	* src/expr.c (gnm_expr_eval) : handle dynamic depends and intersection
	  for the the results.
	NOTE WARNING WARNING WARNING : change of semantics
	  In the permit_non_scalar case we do _not_ ensure that the content of
	  the range has been evaluated.  The user is required to.  We only
	  handle that in the intersection case.
	For constant cellranges we now use value_intersection too.

	* src/dependent.c (dependent_types_init) : register DynamicDep
	(dependent_queue_recalc_list) : when we find a dynamic depend queue
	  its container.
	(dependent_queue_recalc) : rename from cb_dependent_queue_recalc and
	  remove the ignored argument the compiler can handle it.
	(dynamic_dep_debug_name) : new.
	(dependent_add_dynamic_dep) : new.
	(dynamic_dep_free) : new.
	(dependent_clear_dynamic_deps) : new.
	(dependent_unlink) : clear dynamic depends if they exist.
	(cell_eval_content) : clear dynamic depends before we start to
	  evaluate.  They get regenerated by evaluation and we are already know
	  that we need to recalc, so there is no need to keep them.
	(dependent_eval) : ditto.  duplicate the code to keep the semantics of
	  cell_eval_content tidy.
	(do_deps_destroy) : drop the dynamic depend table.
	(gnm_dep_container_new) : initialize it here.
parent 29c8882e
......@@ -8,6 +8,8 @@ Release Critical
----------------
- figure out why error dialogs at startup get forced behind workbook
- validate expression names to ensure that they are not simple values (eg TRUE)
- check the implementation of seriessum returning NULL seems bad
1.2 Targets
-----------
......@@ -49,7 +51,6 @@ UTF-8 :
Pending Patches
---------------
- regexp based accounting format characterization
- ?? more work on D&D based sheet reorg ?
Probably Post 1.2 Targets
......
2002-10-10 Jody Goldberg <jody@gnome.org>
* src/expr-sheet.c (value_intersection) : move here and privatize.
* src/func.c (function_call_with_list) : fence post error. The first
missing arg can be empty. While we're here fix the precedence error
that was breaking missing default args. Remove use of
value_intersection. gnm_expr_eval handles it (I hope)
* src/expr.c (gnm_expr_eval) : support depends for constructed ranges too.
2002-10-10 Jody Goldberg <jody@gnome.org>
* src/value-sheet.c (value_intersection) : move here and rework to
support singletons.
* src/parser.y (parser_simple_val_or_name) : rename from
parser_lookup_name and restore some of the value matching semantics
so that we handle booleans again. I'm not sure the error handling
will kick in but it too is good. the duble and int comparisons
should be useless. We can optimize things a bit by making a
special case routine and removing those.
* src/expr.c (gnm_expr_eval) : handle dynamic depends and intersection
for the the results.
NOTE WARNING WARNING WARNING : change of semantics
In the permit_non_scalar case we do _not_ ensure that the content of
the range has been evaluated. The user is required to. We only
handle that in the intersection case.
For constant cellranges we now use value_intersection too.
* src/dependent.c (dependent_types_init) : register DynamicDep
(dependent_queue_recalc_list) : when we find a dynamic depend queue
its container.
(dependent_queue_recalc) : rename from cb_dependent_queue_recalc and
remove the ignored argument the compiler can handle it.
(dynamic_dep_debug_name) : new.
(dependent_add_dynamic_dep) : new.
(dynamic_dep_free) : new.
(dependent_clear_dynamic_deps) : new.
(dependent_unlink) : clear dynamic depends if they exist.
(cell_eval_content) : clear dynamic depends before we start to
evaluate. They get regenerated by evaluation and we are already know
that we need to recalc, so there is no need to keep them.
(dependent_eval) : ditto. duplicate the code to keep the semantics of
cell_eval_content tidy.
(do_deps_destroy) : drop the dynamic depend table.
(gnm_dep_container_new) : initialize it here.
2002-10-10 Morten Welinder <terra@diku.dk>
* src/rangefunc.c (product_helper): New function.
......
......@@ -33,6 +33,7 @@ Jody:
* More cleanup after the big parser rework
* Esoteric XL number formats #,,##0,,
* Simplify some dialog code
* Support Dynamic Depends (eg INDIRECT)
Morten:
* Port search center from gal's e-table to gtk's treeview.
......
2002-10-10 Jody Goldberg <jody@gnome.org>
* src/expr-sheet.c (value_intersection) : move here and privatize.
* src/func.c (function_call_with_list) : fence post error. The first
missing arg can be empty. While we're here fix the precedence error
that was breaking missing default args. Remove use of
value_intersection. gnm_expr_eval handles it (I hope)
* src/expr.c (gnm_expr_eval) : support depends for constructed ranges too.
2002-10-10 Jody Goldberg <jody@gnome.org>
* src/value-sheet.c (value_intersection) : move here and rework to
support singletons.
* src/parser.y (parser_simple_val_or_name) : rename from
parser_lookup_name and restore some of the value matching semantics
so that we handle booleans again. I'm not sure the error handling
will kick in but it too is good. the duble and int comparisons
should be useless. We can optimize things a bit by making a
special case routine and removing those.
* src/expr.c (gnm_expr_eval) : handle dynamic depends and intersection
for the the results.
NOTE WARNING WARNING WARNING : change of semantics
In the permit_non_scalar case we do _not_ ensure that the content of
the range has been evaluated. The user is required to. We only
handle that in the intersection case.
For constant cellranges we now use value_intersection too.
* src/dependent.c (dependent_types_init) : register DynamicDep
(dependent_queue_recalc_list) : when we find a dynamic depend queue
its container.
(dependent_queue_recalc) : rename from cb_dependent_queue_recalc and
remove the ignored argument the compiler can handle it.
(dynamic_dep_debug_name) : new.
(dependent_add_dynamic_dep) : new.
(dynamic_dep_free) : new.
(dependent_clear_dynamic_deps) : new.
(dependent_unlink) : clear dynamic depends if they exist.
(cell_eval_content) : clear dynamic depends before we start to
evaluate. They get regenerated by evaluation and we are already know
that we need to recalc, so there is no need to keep them.
(dependent_eval) : ditto. duplicate the code to keep the semantics of
cell_eval_content tidy.
(do_deps_destroy) : drop the dynamic depend table.
(gnm_dep_container_new) : initialize it here.
2002-10-10 Morten Welinder <terra@diku.dk>
* src/rangefunc.c (product_helper): New function.
......
2002-10-10 Jody Goldberg <jody@gnome.org>
* src/expr-sheet.c (value_intersection) : move here and privatize.
* src/func.c (function_call_with_list) : fence post error. The first
missing arg can be empty. While we're here fix the precedence error
that was breaking missing default args. Remove use of
value_intersection. gnm_expr_eval handles it (I hope)
* src/expr.c (gnm_expr_eval) : support depends for constructed ranges too.
2002-10-10 Jody Goldberg <jody@gnome.org>
* src/value-sheet.c (value_intersection) : move here and rework to
support singletons.
* src/parser.y (parser_simple_val_or_name) : rename from
parser_lookup_name and restore some of the value matching semantics
so that we handle booleans again. I'm not sure the error handling
will kick in but it too is good. the duble and int comparisons
should be useless. We can optimize things a bit by making a
special case routine and removing those.
* src/expr.c (gnm_expr_eval) : handle dynamic depends and intersection
for the the results.
NOTE WARNING WARNING WARNING : change of semantics
In the permit_non_scalar case we do _not_ ensure that the content of
the range has been evaluated. The user is required to. We only
handle that in the intersection case.
For constant cellranges we now use value_intersection too.
* src/dependent.c (dependent_types_init) : register DynamicDep
(dependent_queue_recalc_list) : when we find a dynamic depend queue
its container.
(dependent_queue_recalc) : rename from cb_dependent_queue_recalc and
remove the ignored argument the compiler can handle it.
(dynamic_dep_debug_name) : new.
(dependent_add_dynamic_dep) : new.
(dynamic_dep_free) : new.
(dependent_clear_dynamic_deps) : new.
(dependent_unlink) : clear dynamic depends if they exist.
(cell_eval_content) : clear dynamic depends before we start to
evaluate. They get regenerated by evaluation and we are already know
that we need to recalc, so there is no need to keep them.
(dependent_eval) : ditto. duplicate the code to keep the semantics of
cell_eval_content tidy.
(do_deps_destroy) : drop the dynamic depend table.
(gnm_dep_container_new) : initialize it here.
2002-10-10 Morten Welinder <terra@diku.dk>
* src/rangefunc.c (product_helper): New function.
......
......@@ -117,7 +117,7 @@ to features that already work.
* Excel Import
+ Localise sheet/workbook Name import.
1.1
1.3
==========
These section lists features that are for post 1.0 versions
and are mostly just ideas or things that can't be implemented
......
A discussion of the new dependency code, version 0.2
by Michael Meeks <mmeeks@gnu.org>
The dependency code is a comparatively conceptualy simple part of the gnumeric
code. The code is designed to determine which objects depend on which cells.
The main use of this is triggering recomputation for things that depend on
something that has changed.
A discussion of the new dependency code, version 0.3
by Michael Meeks <mmeeks@gnu.org> and Jody Goldberg <jody@gnome.org>
1. Overview of the Dependencies
The majority of the code related to dependencies can be found in module
dependent.c, and this should be the first reference for functions.
The dependency code is designed to determine which objects depend on
which cells, or regions. The main use of this is triggering recomputation for
things that depend on something that has changed. The majority of the code
related to dependencies can be found in module dependent.c.
1.1 Data structures and their meaning
The main dependency data is anchored on a per-sheet basis using the
structure GnmDepContainer. This stores all the dependencies for the sheet
in two hash tables. In the future other objects may also become containers,
such as graphs in their own tab.
Dependency data is anchored on a per-sheet basis using GnmDepContainer.
This stores all the dependencies for the sheet in two hash tables. In the
future other objects may also become containers, such as graphs in their own
tab.
There are two types of dependencies, single and range. Loosely these
describe single (ie. = A1 ) cell references vs. large ( ie. = SUM (A1:Z500) )
range references. The two hash tables store DependencyRange structures in the
'range_hash' member, and DependencySingle structures in the 'single_hash'
member.
The two main types of dependencies, are single and range. Loosely
these describe single cells (ie. = A1 ) vs. regions ( ie. = SUM (A1:Z500) )
The range_hash and single_hash tables use DependencyRange and DependencySingle
to store lists of Dependents (not necesssarilly in this container) that depend
on things in the container. The range_hash table is hashed on the normalized
range, and the other hashes on the CellPos of the singleton. Sheet does not
come into play because it is implicit in the container.
The DependencyRange structure defines a range reference. This lists the
Dependencies ( not neccessarily in this sheet ), that depend on the range
specified. Hence to find the dependents that rely on a cell you must search
all the range structures in the range_hash for that container.
The DependencySingle structure mapping stores the degenerate case of
a DependencyRange. Essentialy it stores the cells that depend on a unit range.
This allows for extremely fast constant time hashed lookup. This contrasts with
the Range hash, all of which has to be traversed per dependency calculation.
NB. the DependencySingle has to use CellPos' since there is no garentee that
a cell will exist at a given position in the sheet that is depended on.
DependencySingle stores stores the dependents that rely on individual
cells. This makes lookup easy. Only 1 DependencySingle will exist for a given
cell. We can find that quickly via the hash.
DependencyRange can not be searched via the hash. A target cell may be
contained by several regions. Finding which regions requires traversing the
list of regions looking for intersections. See below.
2. Dependent Evaluation
......@@ -44,8 +37,8 @@ a cell will exist at a given position in the sheet that is depended on.
changes it will queue cells that depend on it, these are obtained via
cell_forech_dep, which looks up in the single_hash and tranverses the
range_hash to obtain its result. Often cell recalculation happens through
workbook_recalc which works through the workbook's eval_queue re-evaluating
the cells there.
workbook_recalc which works through each sheets dependents, re-evaluating
any that are marked for calculation.
2.1 Evaluation queue vs. recursion
......@@ -55,8 +48,6 @@ evaluated. Essentialy each dereference in the GnmExpr ( eg. =A1 ) will cause
the re-calculation of A1's GnmExpr before we can continue ( recursively ).
This is actually fairly expensive when the expression contains a reference like
=sum(a1:a65535)
Each dependent can be in two states
3. Dependencies the bottleneck
......@@ -87,6 +78,19 @@ in the sheet as a dependency ( eg. cutting and pasting = SUM($A$1:$A$100) ). In
this case there is a single depedency range entry with many cells listed as its
dependancies.
3.1.1 bucketing range depends
Searching the list of range depends is still expensive if there are
alot of them. eg in the situation where an expression like
=sum(b1:d1)
is duplicated for the entire 1st column. We end up with a huge number of
non-overlapping regions to search through. That can be ameliorated by
bucketing the range depends. Giving only a few columns to each bucket.
FUTURE : it would be useful to notice that a larger range contains a smaller
one, and to build up a tree as necessary. This would also decrease the size of
the list.
3.2 Inter-sheet dependencies
Inter sheet dependencies are managed simply by inserting the dependency
......@@ -126,6 +130,31 @@ was replaced with a 'microHash'. A simple hash table that looks like a list
for small sizes. It is derived from GHashTable in glib, but simplified to make
it lighter wieght.
3.4 3D dependencies
Some expressions depend on the order of the sheets in a workbook.
When linking the expressions we notice this and flag the dependent before
adding it to a collection in the workbook. The workbook is reposnsible of
linking and unlinking those dependents when the sheet order changes.
3.5 Named expressions
Named expressions are special. In the current implementation we do not
differentiate between names that use relative references and those that don't.
Names can not be dependents because relative references change value depending
on where they are evaluated. However, if a sheet is removed we need to know to
invalidate a name that references it. The 'referencing_names' member of the
collection tracks that.
3.6 Dynamic depends
Functions like INDEX, INDIRECT and some of the range operators produce
new ranges at run time. As a result these are not registed when an dependent
is linked. The DynamicDep structure is a special form of Dependent that is
used to collect and remove the dependencies as they get generated. When a
dependent with dynamic depends is evaluated or unlinked the list is cleared.
The process of evaluation then repopulates the set.
4. The lifecycle of dependency records
A Dependent is 'linked' if it's dependencies on other things have been
......@@ -145,21 +174,15 @@ to an adjacent single reference under certain circumstances.
stored is identical in each cell, the cells may all depend on the corner cell
using a fast single mapping.
4.3.3 The INDIRECT function and calculated depends
This is rather a special case; this function returns a value that
references a different cell, hence the dependency has to be treated rather
differently. This is yet to be implemented.
5 Future Expansion
There are several avenues open for future expansion.
5.1 Future Expansion
5.1 DependencyRange trees or quadtrees
There are several avenues open for future expansion. Clearly further
accelerating the range search will give big speedups on large sheets. This
could be done by clipping the dependency ranges several times against smaller
ranges homing in on the cell of interest, and storing the results for future
reference. Clearly many of the MStyle range related optimizations would be
useful here as well.
Accelerating the range search will give big speedups on large sheets.
The current row based bucketing approach seems to work nicely, but could be
augmented by using trees or quad trees to handle containment better.
5.2 Multi-threading,
......
......@@ -1066,8 +1066,8 @@ typedef struct
} networkdays_holiday_closure;
static Value *
networkdays_holiday_callback(EvalPos const *ep,
Value const *v, void *user_data)
networkdays_holiday_callback (Value const *v, EvalPos const *ep,
void *user_data)
{
Value *res = NULL;
networkdays_holiday_closure * close =
......@@ -1135,11 +1135,10 @@ gnumeric_networkdays (FunctionEvalInfo *ei, Value **argv)
res = end_serial - start_serial;
res -= ((res/7)*2); /* Remove weekends */
if (argv[2] != NULL) {
value_area_foreach (ei->pos, argv[2],
if (argv[2] != NULL)
value_area_foreach (argv[2], ei->pos,
&networkdays_holiday_callback,
&close);
}
res = res - start_offset + end_offset - close.res;
......
......@@ -37,6 +37,7 @@
#include <parse-util.h>
#include <cell.h>
#include <str.h>
#include <ranges.h>
#include <sheet.h>
#include <workbook.h>
#include <format.h>
......@@ -1214,11 +1215,15 @@ cb_countblank (Sheet *sheet, int col, int row,
static Value *
gnumeric_countblank (FunctionEvalInfo *ei, Value **args)
{
/* FIXME : This does not handle 3D references */
int count =
value_area_get_height (ei->pos, args[0]) *
value_area_get_width (ei->pos, args[0]);
Sheet *start_sheet, *end_sheet;
Range r;
int count;
rangeref_normalize (&args[0]->v_range.cell, ei->pos,
&start_sheet, &end_sheet, &r);
count = range_width (&r) * range_height (&r);
if (start_sheet != end_sheet && end_sheet != NULL)
count *= 1 + abs (end_sheet->index_in_wb - start_sheet->index_in_wb);
workbook_foreach_cell_in_range (ei->pos, args[0],
CELL_ITER_IGNORE_BLANK,
&cb_countblank, &count);
......
......@@ -281,7 +281,7 @@ gnumeric_if (FunctionEvalInfo *ei, GnmExprList *expr_node_list)
_("Invalid number of arguments"));
/* Compute the if part */
value = gnm_expr_eval (expr_node_list->data, ei->pos, 0);
value = gnm_expr_eval (expr_node_list->data, ei->pos, GNM_EXPR_EVAL_SCALAR_NON_EMPTY);
if (VALUE_IS_EMPTY_OR_ERROR(value))
return value;
......
2002-10-10 Jody Goldberg <jody@gnome.org>
* functions.c (gnumeric_indirect) : always return a cell_range and use
the convenience routine gnm_expr_get_range. The core is now strong
enough to handle the intersection and dependencies properly.
2002-09-30 Jody Goldberg <jody@gnome.org>
* Release 1.1.9
......
......@@ -145,26 +145,23 @@ find_index_linear (FunctionEvalInfo *ei, Value *find, Value *data,
ValueCompare comp;
int length, lp, index = -1;
if (height) {
length = value_area_get_height (ei->pos, data);
} else {
length = value_area_get_width (ei->pos, data);
}
if (height)
length = value_area_get_height (data, ei->pos);
else
length = value_area_get_width (data, ei->pos);
for (lp = 0; lp < length; lp++){
const Value *v;
if (height) {
v = value_area_fetch_x_y (ei->pos, data, 0, lp);
} else {
v = value_area_fetch_x_y (ei->pos, data, lp, 0);
}
if (height)
v = value_area_fetch_x_y (data, 0, lp, ei->pos);
else
v = value_area_fetch_x_y (data, lp, 0, ei->pos);
g_return_val_if_fail (v != NULL, -1);
if (!find_compare_type_valid (find, v)) {
if (!find_compare_type_valid (find, v))
continue;
}
comp = value_compare (find, v, FALSE);
......@@ -207,11 +204,10 @@ find_index_bisection (FunctionEvalInfo *ei, Value *find, Value *data,
ValueCompare comp = TYPE_MISMATCH;
int high, low = 0, prev = -1, mid = -1;
if (height) {
high = value_area_get_height (ei->pos, data);
} else {
high = value_area_get_width (ei->pos, data);
}
if (height)
high = value_area_get_height (data, ei->pos);
else
high = value_area_get_width (data, ei->pos);
high--;
if (high < low) {
......@@ -241,17 +237,13 @@ find_index_bisection (FunctionEvalInfo *ei, Value *find, Value *data,
while (!find_compare_type_valid (find, v) && mid != -1) {
gboolean rev = FALSE;
if (height) {
v = value_area_get_x_y (ei->pos,
data, 0, mid);
} else {
v = value_area_get_x_y (ei->pos,
data, mid, 0);
}
if (height)
v = value_area_get_x_y (data, 0, mid, ei->pos);
else
v = value_area_get_x_y (data, mid, 0, ei->pos);
if (find_compare_type_valid (find, v)) {
if (find_compare_type_valid (find, v))
break;
}
mid = find_bound_walk (0, 0, 0, FALSE, FALSE);
......@@ -301,26 +293,19 @@ find_index_bisection (FunctionEvalInfo *ei, Value *find, Value *data,
adj = mid - 1;
}
if (height) {
v = value_area_fetch_x_y (ei->pos,
data,
0, adj);
} else {
v = value_area_fetch_x_y (ei->pos,
data,
adj, 0);
}
if (height)
v = value_area_fetch_x_y (data, 0, adj, ei->pos);
else
v = value_area_fetch_x_y (data, adj, 0, ei->pos);
g_return_val_if_fail (v != NULL, -1);
if (!find_compare_type_valid (find, v)) {
if (!find_compare_type_valid (find, v))
break;
}
comp = value_compare (find, v, FALSE);
if (comp != IS_EQUAL) {
if (comp != IS_EQUAL)
break;
}
mid = adj;
}
......@@ -472,7 +457,7 @@ gnumeric_choose (FunctionEvalInfo *ei, GnmExprList *l)
if (argc < 1 || !l->data)
return value_new_error (ei->pos, gnumeric_err_VALUE);
v = gnm_expr_eval (l->data, ei->pos, 0);
v = gnm_expr_eval (l->data, ei->pos, GNM_EXPR_EVAL_SCALAR_NON_EMPTY);
if (!v)
return NULL;
......@@ -528,7 +513,7 @@ gnumeric_vlookup (FunctionEvalInfo *ei, Value **args)
return value_new_error (ei->pos, gnumeric_err_NA);
if (col_idx <= 0)
return value_new_error (ei->pos, gnumeric_err_VALUE);
if (col_idx > value_area_get_width (ei->pos, args [1]))
if (col_idx > value_area_get_width (args [1], ei->pos))
return value_new_error (ei->pos, gnumeric_err_REF);
approx = (args[3] != NULL)
......@@ -542,7 +527,7 @@ gnumeric_vlookup (FunctionEvalInfo *ei, Value **args)
if (index >= 0) {
const Value *v;
v = value_area_fetch_x_y (ei->pos, args [1], col_idx-1, index);
v = value_area_fetch_x_y (args [1], col_idx-1, index, ei->pos);
g_return_val_if_fail (v != NULL, NULL);
return value_duplicate (v);
}
......@@ -586,7 +571,7 @@ gnumeric_hlookup (FunctionEvalInfo *ei, Value **args)
return value_new_error (ei->pos, gnumeric_err_NA);
if (row_idx <= 0)
return value_new_error (ei->pos, gnumeric_err_VALUE);
if (row_idx > value_area_get_height (ei->pos, args [1]))
if (row_idx > value_area_get_height (args [1], ei->pos))
return value_new_error (ei->pos, gnumeric_err_REF);
approx = (args[3] != NULL)
......@@ -600,7 +585,7 @@ gnumeric_hlookup (FunctionEvalInfo *ei, Value **args)
if (index >= 0) {
const Value *v;
v = value_area_fetch_x_y (ei->pos, args[1], index, row_idx-1);
v = value_area_fetch_x_y (args[1], index, row_idx-1, ei->pos);
g_return_val_if_fail (v != NULL, NULL);
return value_duplicate (v);
}
......@@ -635,16 +620,15 @@ gnumeric_lookup (FunctionEvalInfo *ei, Value **args)
{
int index = -1;
Value *result = args[2];
int width = value_area_get_width (ei->pos, args[1]);
int height = value_area_get_height (ei->pos, args[1]);
int width = value_area_get_width (args[1], ei->pos);
int height = value_area_get_height (args[1], ei->pos);
if (!find_type_valid (args[0])) {
if (!find_type_valid (args[0]))
return value_new_error (ei->pos, gnumeric_err_NA);
}
if (result) {
int width = value_area_get_width (ei->pos, result);
int height = value_area_get_height (ei->pos, result);
int width = value_area_get_width (result, ei->pos);
int height = value_area_get_height (result, ei->pos);
if (width > 1 && height > 1) {
return value_new_error (ei->pos, gnumeric_err_NA);
......@@ -658,16 +642,13 @@ gnumeric_lookup (FunctionEvalInfo *ei, Value **args)
if (index >= 0) {
const Value *v = NULL;
int width = value_area_get_width (ei->pos, result);
int height = value_area_get_height (ei->pos, result);
if (width > height) {
v = value_area_fetch_x_y (ei->pos, result,
index, height - 1);
} else {
v = value_area_fetch_x_y (ei->pos, result,
width - 1, index);
}
int width = value_area_get_width (result, ei->pos);
int height = value_area_get_height (result, ei->pos);
if (width > height)
v = value_area_fetch_x_y (result, index, height - 1, ei->pos);
else
v = value_area_fetch_x_y (result, width - 1, index, ei->pos);
return value_duplicate (v);
}
......@@ -705,8 +686,8 @@ static Value *
gnumeric_match (FunctionEvalInfo *ei, Value **args)
{
int type, index = -1;
int width = value_area_get_width (ei->pos, args[1]);
int height = value_area_get_height (ei->pos, args[1]);
int width = value_area_get_width (args[1], ei->pos);
int height = value_area_get_height (args[1], ei->pos);
if (!find_type_valid (args[0])) {
return value_new_error (ei->pos, gnumeric_err_NA);
......@@ -765,30 +746,13 @@ gnumeric_indirect (FunctionEvalInfo *ei, Value **args)
char const *text = value_peek_string (args[0]);
GnmExpr const *expr = gnm_expr_parse_str_simple (text,
parse_pos_init_evalpos (&pp, ei->pos));
Value *res = NULL;
/* We need to parse from the current cell then normalize just in case
* the expression is in R[-1]C[-1] format.
*/
if (expr != NULL) {
if (expr->any.oper == GNM_EXPR_OP_NAME &&
!expr->name.name->builtin) {
GnmExpr const *tmp = expr->name.name->t.expr_tree;
gnm_expr_ref (tmp);
gnm_expr_unref (expr);
expr = tmp;
}
if (expr->any.oper == GNM_EXPR_OP_CELLREF) {
Value *res = gnm_expr_eval (expr, ei->pos, 0);
gnm_expr_unref (expr);
return res;
} else if (expr->any.oper == GNM_EXPR_OP_CONSTANT) {
Value *res = value_duplicate (expr->constant.value);
gnm_expr_unref (expr);
return res;
}
res = gnm_expr_get_range (expr);
gnm_expr_unref (expr);
}
return value_new_error (ei->pos, gnumeric_err_REF);
return (res != NULL) ? res : value_new_error (ei->pos, gnumeric_err_REF);
}
/*****************************************************************************/
......@@ -829,7 +793,7 @@ gnumeric_index (FunctionEvalInfo *ei, GnmExprList *l)
for (i = 0; l != NULL && i < G_N_ELEMENTS (elem) ; i++, l = l->next) {
v = value_coerce_to_number (
gnm_expr_eval (l->data, ei->pos, 0),
gnm_expr_eval (l->data, ei->pos, GNM_EXPR_EVAL_SCALAR_NON_EMPTY),
&valid, ei->pos);
if (!valid)
return v;
......@@ -847,14 +811,14 @@ gnumeric_index (FunctionEvalInfo *ei, GnmExprList *l)
v = gnm_expr_eval (source, ei->pos, GNM_EXPR_EVAL_PERMIT_NON_SCALAR);
if (elem[1] < 0 ||
elem[1] >= value_area_get_width (ei->pos, v) ||
elem[1] >= value_area_get_width (v, ei->pos) ||
elem[0] < 0 ||
elem[0] >= value_area_get_height (ei->pos, v)) {
elem[0] >= value_area_get_height (v, ei->pos)) {
value_release (v);
return value_new_error (ei->pos, gnumeric_err_REF);
}
res = value_duplicate (value_area_fetch_x_y (ei->pos, v, elem[1], elem[0]));
res = value_duplicate (value_area_fetch_x_y (v, elem[1], elem[0], ei->pos));
value_release (v);
return res;
}
......@@ -888,8 +852,8 @@ gnumeric_column (FunctionEvalInfo *ei, Value **args)
switch (ref->type) {
case VALUE_CELLRANGE: {
int width = value_area_get_width (ei->pos, ref);
int height = value_area_get_height (ei->pos, ref);
int width = value_area_get_width (ref, ei->pos);
int height = value_area_get_height (ref, ei->pos);
CellRef const *const refa = &ref->v_range.cell.a;
int col = cellref_get_abs_col (refa, ei->pos) + 1;
int i, j;
......@@ -930,11 +894,10 @@ static const char *help_columns = {
"@SEEALSO=COLUMN,ROW,ROWS")
};