Commit cee9b219 authored by Jukka-Pekka Iivonen's avatar Jukka-Pekka Iivonen Committed by jpekka

Database functions accept now string criterias too. In addition, the

1999-05-12  Jukka-Pekka Iivonen  <iivonen@iki.fi>

        * src/fn-database.c: Database functions accept now string
        criterias too.  In addition, the parsing of criterias and the test
        functions are now public (src/fn-math.c uses these for now on).

        * src/func.h: Added type definitions and function prototypes for
        internal functions that parse and test criterias.

        * src/fn-math.c: Added LN().  Changed LOG() to take an optional
        second parameter.  LOG() returns the logarithm in base 10 if the
        optional argument is not given, otherwise it returns the logarithm
        in the given base.

        * src/fn-math.c: Added COUNTIF() and SUMIF().

        * src/fn-eng.c: Added IMLOG10() and IMLOG2().

        * src/fn-eng.c (complex_ln): Fixed a bug.  Imaginary coefficient
        was calculated incorrectly.
parent 30abbf75
1999-05-12 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/fn-database.c: Database functions accept now string
criterias too. In addition, the parsing of criterias and the test
functions are now public (src/fn-math.c uses these for now on).
* src/func.h: Added type definitions and function prototypes for
internal functions that parse and test criterias.
* src/fn-math.c: Added LN(). Changed LOG() to take an optional
second parameter. LOG() returns the logarithm in base 10 if the
optional argument is not given, otherwise it returns the logarithm
in the given base.
* src/fn-math.c: Added COUNTIF() and SUMIF().
* src/fn-eng.c: Added IMLOG10() and IMLOG2().
* src/fn-eng.c (complex_ln): Fixed a bug. Imaginary coefficient
was calculated incorrectly.
1999-05-11 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/fn-eng.c: Added CONVERT(). All translations should work.
......
1999-05-12 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/fn-database.c: Database functions accept now string
criterias too. In addition, the parsing of criterias and the test
functions are now public (src/fn-math.c uses these for now on).
* src/func.h: Added type definitions and function prototypes for
internal functions that parse and test criterias.
* src/fn-math.c: Added LN(). Changed LOG() to take an optional
second parameter. LOG() returns the logarithm in base 10 if the
optional argument is not given, otherwise it returns the logarithm
in the given base.
* src/fn-math.c: Added COUNTIF() and SUMIF().
* src/fn-eng.c: Added IMLOG10() and IMLOG2().
* src/fn-eng.c (complex_ln): Fixed a bug. Imaginary coefficient
was calculated incorrectly.
1999-05-11 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/fn-eng.c: Added CONVERT(). All translations should work.
......
1999-05-12 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/fn-database.c: Database functions accept now string
criterias too. In addition, the parsing of criterias and the test
functions are now public (src/fn-math.c uses these for now on).
* src/func.h: Added type definitions and function prototypes for
internal functions that parse and test criterias.
* src/fn-math.c: Added LN(). Changed LOG() to take an optional
second parameter. LOG() returns the logarithm in base 10 if the
optional argument is not given, otherwise it returns the logarithm
in the given base.
* src/fn-math.c: Added COUNTIF() and SUMIF().
* src/fn-eng.c: Added IMLOG10() and IMLOG2().
* src/fn-eng.c (complex_ln): Fixed a bug. Imaginary coefficient
was calculated incorrectly.
1999-05-11 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/fn-eng.c: Added CONVERT(). All translations should work.
......
1999-05-12 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/fn-database.c: Database functions accept now string
criterias too. In addition, the parsing of criterias and the test
functions are now public (src/fn-math.c uses these for now on).
* src/func.h: Added type definitions and function prototypes for
internal functions that parse and test criterias.
* src/fn-math.c: Added LN(). Changed LOG() to take an optional
second parameter. LOG() returns the logarithm in base 10 if the
optional argument is not given, otherwise it returns the logarithm
in the given base.
* src/fn-math.c: Added COUNTIF() and SUMIF().
* src/fn-eng.c: Added IMLOG10() and IMLOG2().
* src/fn-eng.c (complex_ln): Fixed a bug. Imaginary coefficient
was calculated incorrectly.
1999-05-11 Jukka-Pekka Iivonen <iivonen@iki.fi>
* src/fn-eng.c: Added CONVERT(). All translations should work.
......
......@@ -16,13 +16,6 @@
/* Type definitions */
typedef (*condition_test_fun_t) (float_t x, float_t y);
typedef struct {
condition_test_fun_t fun;
float_t x;
} condition_t;
typedef struct {
int column;
GSList *conditions;
......@@ -31,56 +24,80 @@ typedef struct {
/* Callback functions */
static int
test_equal(float_t x, float_t y)
int
criteria_test_equal(Value *x, Value *y)
{
if (x == y)
if (VALUE_IS_NUMBER(x) && VALUE_IS_NUMBER(y))
if (value_get_as_double(x) == value_get_as_double(y))
return 1;
else
return 0;
else if (x->type == VALUE_STRING && y->type == VALUE_STRING
&& strcmp(x->v.str->str, y->v.str->str) == 0)
return 1;
else
return 0;
}
static int
test_unequal(float_t x, float_t y)
int
criteria_test_unequal(Value *x, Value *y)
{
if (x != y)
if (VALUE_IS_NUMBER(x) && VALUE_IS_NUMBER(y))
if (value_get_as_double(x) != value_get_as_double(y))
return 1;
else
return 0;
else if (x->type == VALUE_STRING && y->type == VALUE_STRING
&& strcmp(x->v.str->str, y->v.str->str) != 0)
return 1;
else
return 0;
}
static int
test_less(float_t x, float_t y)
int
criteria_test_less(Value *x, Value *y)
{
if (x < y)
return 1;
if (VALUE_IS_NUMBER(x) && VALUE_IS_NUMBER(y))
if (value_get_as_double(x) < value_get_as_double(y))
return 1;
else
return 0;
else
return 0;
}
static int
test_greater(float_t x, float_t y)
int
criteria_test_greater(Value *x, Value *y)
{
if (x > y)
return 1;
if (VALUE_IS_NUMBER(x) && VALUE_IS_NUMBER(y))
if (value_get_as_double(x) > value_get_as_double(y))
return 1;
else
return 0;
else
return 0;
}
static int
test_less_or_equal(float_t x, float_t y)
int
criteria_test_less_or_equal(Value *x, Value *y)
{
if (x <= y)
return 1;
if (VALUE_IS_NUMBER(x) && VALUE_IS_NUMBER(y))
if (value_get_as_double(x) <= value_get_as_double(y))
return 1;
else
return 0;
else
return 0;
}
static int
test_greater_or_equal(float_t x, float_t y)
int
criteria_test_greater_or_equal(Value *x, Value *y)
{
if (x >= y)
return 1;
if (VALUE_IS_NUMBER(x) && VALUE_IS_NUMBER(y))
if (value_get_as_double(x) >= value_get_as_double(y))
return 1;
else
return 0;
else
return 0;
}
......@@ -144,17 +161,62 @@ free_criterias(GSList *criterias)
g_slist_free(list);
}
void
parse_criteria(char *criteria, criteria_test_fun_t *fun, Value **test_value)
{
char *p;
float_t tmp;
int len;
if (strncmp(criteria, "<=", 2) == 0) {
*fun = (criteria_test_fun_t)
criteria_test_less_or_equal;
len=2;
} else if (strncmp(criteria, ">=", 2) == 0) {
*fun = (criteria_test_fun_t)
criteria_test_greater_or_equal;
len=2;
} else if (strncmp(criteria, "<>", 2) == 0) {
*fun = (criteria_test_fun_t)
criteria_test_unequal;
len=2;
} else if (*criteria == '<') {
*fun = (criteria_test_fun_t)
criteria_test_less;
len=1;
} else if (*criteria == '=') {
*fun = (criteria_test_fun_t)
criteria_test_equal;
len=1;
} else if (*criteria == '>') {
*fun = (criteria_test_fun_t)
criteria_test_greater;
len=1;
} else {
*fun = (criteria_test_fun_t)
criteria_test_equal;
len=0;
}
tmp = strtod(criteria+len, &p);
if (p == criteria+len || *p != '\0')
*test_value = value_str(criteria+len);
else
*test_value = value_float(tmp);
}
/* Parses the criteria cell range.
*/
static GSList *
parse_criteria(Value *database, Value *criteria)
parse_database_criteria(Value *database, Value *criteria)
{
Sheet *sheet;
database_criteria_t *new_criteria;
GSList *criterias;
GSList *conditions;
Cell *cell;
int i, j;
int b_col, b_row, e_col, e_row;
int field_ind;
......@@ -182,56 +244,29 @@ parse_criteria(Value *database, Value *criteria)
conditions = NULL;
for (j=b_row+1; j<=e_row; j++) {
condition_t *cond;
int len;
func_criteria_t *cond;
gchar *cell_str;
cell = sheet_cell_get(sheet, i, j);
if (cell == NULL || cell->value == NULL)
continue;
cond = g_new(condition_t, 1);
cond = g_new(func_criteria_t, 1);
if (VALUE_IS_NUMBER(cell->value)) {
cond->x = value_get_as_double (cell->value);
cond->x = cell->value;
cond->fun =
(condition_test_fun_t) test_equal;
(criteria_test_fun_t) criteria_test_equal;
conditions = g_slist_append(conditions, cond);
continue;
}
cell_str = cell_get_text(cell);
if (strncmp(cell_str, "<=", 2) == 0) {
cond->fun =
(condition_test_fun_t) test_less_or_equal;
len=2;
} else if (strncmp(cell_str, ">=", 2) == 0) {
cond->fun =
(condition_test_fun_t) test_greater_or_equal;
len=2;
} else if (strncmp(cell_str, "<>", 2) == 0) {
cond->fun =
(condition_test_fun_t) test_unequal;
len=2;
} else if (*cell_str == '<') {
cond->fun = (condition_test_fun_t) test_less;
len=1;
} else if (*cell_str == '=') {
cond->fun = (condition_test_fun_t) test_equal;
len=1;
} else if (*cell_str == '>') {
cond->fun = (condition_test_fun_t) test_greater;
len=1;
} else {
free_criterias(criterias);
g_free(cond);
g_slist_free(conditions);
return NULL;
}
parse_criteria(cell_str, &cond->fun, &cond->x);
cond->x = atof(cell_str+len);
conditions = g_slist_append(conditions, cond);
}
new_criteria->conditions = conditions;
criterias = g_slist_append(criterias, new_criteria);
}
return criterias;
}
......@@ -260,7 +295,6 @@ find_cells_that_match(Value *database, int field, GSList *criterias)
for (current = criterias; current != NULL;
current=current->next) {
database_criteria_t *current_criteria;
float_t y;
current_criteria = current->data;
test_cell = sheet_cell_get(sheet,
......@@ -268,13 +302,12 @@ find_cells_that_match(Value *database, int field, GSList *criterias)
row);
if (test_cell == NULL || test_cell->value == NULL)
continue;
y = value_get_as_double(test_cell->value);
conditions = current_criteria->conditions;
add_flag = 0;
while (conditions != NULL) {
condition_t *cond = conditions->data;
func_criteria_t *cond = conditions->data;
if (cond->fun(y, cond->x)) {
if (cond->fun(test_cell->value, cond->x)) {
add_flag = 1;
break;
}
......@@ -334,7 +367,7 @@ gnumeric_daverage (struct FunctionDefinition *i,
*error_string = _("#NUM!");
return NULL;
}
criterias = parse_criteria(database, criteria);
criterias = parse_database_criteria(database, criteria);
if (criterias == NULL) {
*error_string = _("#NUM!");
return NULL;
......@@ -401,7 +434,7 @@ gnumeric_dcount (struct FunctionDefinition *i,
*error_string = _("#NUM!");
return NULL;
}
criterias = parse_criteria(database, criteria);
criterias = parse_database_criteria(database, criteria);
if (criterias == NULL) {
*error_string = _("#NUM!");
return NULL;
......@@ -467,7 +500,7 @@ gnumeric_dcounta (struct FunctionDefinition *i,
*error_string = _("#NUM!");
return NULL;
}
criterias = parse_criteria(database, criteria);
criterias = parse_database_criteria(database, criteria);
if (criterias == NULL) {
*error_string = _("#NUM!");
return NULL;
......@@ -538,7 +571,7 @@ gnumeric_dget (struct FunctionDefinition *i,
return NULL;
}
criterias = parse_criteria(database, criteria);
criterias = parse_database_criteria(database, criteria);
if (criterias == NULL) {
*error_string = _("#NUM!");
......@@ -614,7 +647,7 @@ gnumeric_dmax (struct FunctionDefinition *i,
*error_string = _("#NUM!");
return NULL;
}
criterias = parse_criteria(database, criteria);
criterias = parse_database_criteria(database, criteria);
if (criterias == NULL) {
*error_string = _("#NUM!");
return NULL;
......@@ -687,7 +720,7 @@ gnumeric_dmin (struct FunctionDefinition *i,
*error_string = _("#NUM!");
return NULL;
}
criterias = parse_criteria(database, criteria);
criterias = parse_database_criteria(database, criteria);
if (criterias == NULL) {
*error_string = _("#NUM!");
return NULL;
......@@ -760,7 +793,7 @@ gnumeric_dproduct (struct FunctionDefinition *i,
*error_string = _("#NUM!");
return NULL;
}
criterias = parse_criteria(database, criteria);
criterias = parse_database_criteria(database, criteria);
if (criterias == NULL) {
*error_string = _("#NUM!");
return NULL;
......@@ -833,7 +866,7 @@ gnumeric_dstdev (struct FunctionDefinition *i,
*error_string = _("#NUM!");
return NULL;
}
criterias = parse_criteria(database, criteria);
criterias = parse_database_criteria(database, criteria);
if (criterias == NULL) {
*error_string = _("#NUM!");
return NULL;
......@@ -909,7 +942,7 @@ gnumeric_dstdevp (struct FunctionDefinition *i,
*error_string = _("#NUM!");
return NULL;
}
criterias = parse_criteria(database, criteria);
criterias = parse_database_criteria(database, criteria);
if (criterias == NULL) {
*error_string = _("#NUM!");
return NULL;
......@@ -984,7 +1017,7 @@ gnumeric_dsum (struct FunctionDefinition *i,
*error_string = _("#NUM!");
return NULL;
}
criterias = parse_criteria(database, criteria);
criterias = parse_database_criteria(database, criteria);
if (criterias == NULL) {
*error_string = _("#NUM!");
return NULL;
......@@ -1057,7 +1090,7 @@ gnumeric_dvar (struct FunctionDefinition *i,
*error_string = _("#NUM!");
return NULL;
}
criterias = parse_criteria(database, criteria);
criterias = parse_database_criteria(database, criteria);
if (criterias == NULL) {
*error_string = _("#NUM!");
return NULL;
......@@ -1133,7 +1166,7 @@ gnumeric_dvarp (struct FunctionDefinition *i,
*error_string = _("#NUM!");
return NULL;
}
criterias = parse_criteria(database, criteria);
criterias = parse_database_criteria(database, criteria);
if (criterias == NULL) {
*error_string = _("#NUM!");
return NULL;
......
......@@ -878,8 +878,12 @@ static char *help_imln = {
static void
complex_ln(float_t *real, float_t *im)
{
*real = log(sqrt(*real * *real + *im * *im));
*im = atan(*im / *real);
float_t r, i;
r = log(sqrt(*real * *real + *im * *im));
i = atan(*im / *real);
*real = r;
*im = i;
}
static Value *
......@@ -911,6 +915,86 @@ gnumeric_imln (struct FunctionDefinition *fd,
return create_inumber (real, im, suffix);
}
static char *help_imlog2 = {
N_("@FUNCTION=IMLOG2\n"
"@SYNTAX=IMLOG2(inumber)\n"
"@DESCRIPTION="
"IMLOG2 returns the logarithm of a complex number in base 2. "
"\n"
"@SEEALSO=IMLN,IMLOG10")
};
static Value *
gnumeric_imlog2 (struct FunctionDefinition *fd,
Value *argv [], char **error_string)
{
float_t real, im;
float_t ln_2;
char *suffix;
if (VALUE_IS_NUMBER(argv[0])) {
real = value_get_as_double (argv[0]);
im = 0;
} else if (argv[0]->type != VALUE_STRING) {
*error_string = _("#VALUE!");
return NULL;
} else if (get_real_and_imaginary(argv[0]->v.str->str,
&real, &im, &suffix)) {
*error_string = _("#NUM!");
return NULL;
}
if (real == 0) {
*error_string = _("#DIV/0!");
return NULL;
}
complex_ln(&real, &im);
ln_2 = log(2);
return create_inumber (real/ln_2, im/ln_2, suffix);
}
static char *help_imlog10 = {
N_("@FUNCTION=IMLOG10\n"
"@SYNTAX=IMLOG10(inumber)\n"
"@DESCRIPTION="
"IMLOG10 returns the logarithm of a complex number in base 10. "
"\n"
"@SEEALSO=IMLN,IMLOG2")
};
static Value *
gnumeric_imlog10 (struct FunctionDefinition *fd,
Value *argv [], char **error_string)
{
float_t real, im;
float_t ln_10;
char *suffix;
if (VALUE_IS_NUMBER(argv[0])) {
real = value_get_as_double (argv[0]);
im = 0;
} else if (argv[0]->type != VALUE_STRING) {
*error_string = _("#VALUE!");
return NULL;
} else if (get_real_and_imaginary(argv[0]->v.str->str,
&real, &im, &suffix)) {
*error_string = _("#NUM!");
return NULL;
}
if (real == 0) {
*error_string = _("#DIV/0!");
return NULL;
}
complex_ln(&real, &im);
ln_10 = log(10);
return create_inumber (real/ln_10, im/ln_10, suffix);
}
static char *help_impower = {
N_("@FUNCTION=IMPOWER\n"
"@SYNTAX=IMPOWER(inumber,number)\n"
......@@ -1854,6 +1938,10 @@ FunctionDefinition eng_functions [] = {
NULL, gnumeric_imexp },
{ "imln", "?", "inumber", &help_imln,
NULL, gnumeric_imln },
{ "imlog10", "?", "inumber", &help_imlog10,
NULL, gnumeric_imlog10 },
{ "imlog2", "?", "inumber", &help_imlog2,
NULL, gnumeric_imlog2 },
{ "impower", "?f", "inumber,number", &help_impower,
NULL, gnumeric_impower },
{ "improduct", "??", "inumber,inumber", &help_improduct,
......
......@@ -36,6 +36,85 @@ static char *help_ = {
#endif
typedef struct {
GSList *list;
int num;
} math_sums_t;
static int
callback_function_sumxy (Sheet *sheet, int col, int row,
Cell *cell, void *user_data)
{
math_sums_t *mm = user_data;
float_t x;
gpointer p;
if (cell == NULL || cell->value == NULL)
return TRUE;
switch (cell->value->type) {
case VALUE_INTEGER:
x = cell->value->v.v_int;
break;
case VALUE_FLOAT:
x = cell->value->v.v_float;
break;
default:
return TRUE;
}
p = g_new(float_t, 1);
*((float_t *) p) = x;
mm->list = g_slist_append(mm->list, p);
mm->num++;
return TRUE;
}
typedef struct {
GSList *list;
criteria_test_fun_t fun;
Value *test_value;
int num;
} math_criteria_t;
static int
callback_function_criteria (Sheet *sheet, int col, int row,
Cell *cell, void *user_data)
{
math_criteria_t *mm = user_data;
Value *v;
gpointer p;
if (cell == NULL || cell->value == NULL)
return TRUE;
switch (cell->value->type) {
case VALUE_INTEGER:
v = value_int(cell->value->v.v_int);
break;
case VALUE_FLOAT:
v = value_float(cell->value->v.v_float);
break;
case VALUE_STRING:
v = value_str(cell->value->v.str->str);
break;
default:
return TRUE;
}
if (mm->fun(v, mm->test_value)) {
p = g_new(Value, 1);
*((Value **) p) = v;
mm->list = g_slist_append(mm->list, p);
mm->num++;
} else
value_release(v);
return TRUE;
}
static char *help_abs = {
N_("@FUNCTION=ABS\n"
"@SYNTAX=ABS(b1)\n"
......@@ -267,6 +346,136 @@ gnumeric_ceil (struct FunctionDefinition *i,
return value_float (ceil (value_get_as_double (argv [0])));
}
static char *help_countif = {
N_("@FUNCTION=COUNTIF\n"
"@SYNTAX=COUNTIF(range,criteria)\n"
"@DESCRIPTION="
"COUNTIF function counts the number of cells in the given range "
"that meet the given criteria. "
"\n"
"@SEEALSO=COUNT,SUMIF")
};
static Value *
gnumeric_countif (struct FunctionDefinition *i,
Value *argv [], char **error_string)
{
Value *range = argv[0];
math_criteria_t items;
int ret;
GSList *list;
items.num = 0;
items.list = NULL;
if ((!VALUE_IS_NUMBER(argv[1]) && argv[1]->type != VALUE_STRING)
|| (range->type != VALUE_CELLRANGE)) {
*error_string = _("#VALUE!");
return NULL;
}
if (VALUE_IS_NUMBER(argv[1])) {
items.fun = (criteria_test_fun_t) criteria_test_equal;
items.test_value = argv[1];
} else
parse_criteria(argv[1]->v.str->str,
&items.fun, &items.test_value);
ret = sheet_cell_foreach_range (
range->v.cell_range.cell_a.sheet, TRUE,
range->v.cell_range.cell_a.col,
range->v.cell_range.cell_a.row,
range->v.cell_range.cell_b.col,
range->v.cell_range.cell_b.row,
callback_function_criteria,
&items);
if (ret == FALSE) {
*error_string = _("#VALUE!");
return NULL;
}
list = items.list;
while (list != NULL) {
g_free(list->data);
list = list->next;
}
g_slist_free(items.list);
return value_int (items.num);
}