fn-lookup.c 16.8 KB
Newer Older
1 2 3
/*
 * fn-lookup.c:  Built in lookup functions and functions registration
 *
4
 * Authors:
5
 *  Michael Meeks <michael@imaginator.com>
6
 *  Jukka-Pekka Iivonen <iivonen@iki.fi>
7
 */
8

9 10 11 12 13
#include <config.h>
#include "numbers.h"
#include "utils.h"
#include "func.h"

14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

static char *help_address = {
	N_("@FUNCTION=ADDRESS\n"
	   "@SYNTAX=ADDRESS(row_num,col_num[,abs_num,a1,text])\n"

	   "@DESCRIPTION="
	   "ADDRESS returns a cell address as text for specified row "
	   "and column numbers. "
	   "\n"
	   "If abs_num is 1 or omitted, ADDRESS returns absolute reference. "
	   "If abs_num is 2 ADDRESS returns absolute row and relative column. "
	   "If abs_num is 3 ADDRESS returns relative row and absolute column. "
	   "If abs_num is 4 ADDRESS returns relative reference. "
	   "If abs_num is greater than 4 ADDRESS returns #NUM! error. "
	   "\n"
	   "@a1 is a logical value that specifies the reference style.  If "
	   "@a1 is TRUE or omitted, ADDRESS returns an A1-style reference, "
	   "i.e. $D$4.  Otherwise ADDRESS returns an R1C1-style reference, "
	   "i.e. R4C4. "
	   "\n"
	   "@text specifies the name of the worksheet to be used as the "
	   "external reference.  "
	   "\n"
	   "If @row_num or @col_num is less than one, ADDRESS returns #NUM! "
	   "error. "
39
	   "\n"
40 41 42 43
	   "@SEEALSO=")
};

static Value *
44
gnumeric_address (FunctionEvalInfo *ei, Value **args)
45 46 47 48 49
{
        int   row, col, abs_num, a1, err;
	gchar *text, *buf;
	Value *v;

50 51
	row = value_get_as_int (args[0]);
	col = value_get_as_int (args[1]);
52

53 54
	if (row < 1 || col < 1)
	        return function_error (ei, gnumeric_err_NUM);
55

56
	if (args[2] == NULL)
57 58
	        abs_num = 1;
	else
59
	        abs_num = value_get_as_int (args [2]);
60

61
	if (args[3] == NULL)
62 63
	        a1 = 1;
	else {
64 65 66
	        a1 = value_get_as_bool (args[3], &err);
		if (err)
		        return function_error (ei, gnumeric_err_VALUE);
67 68
	}

69
	if (args[4] == NULL) {
70 71 72
	        text = g_new(gchar, 1);
	        text[0] = '\0';
	} else {
73
	        gchar *p = args[4]->v.str->str;
74
		int   space = 0;
75 76 77 78 79 80

		text = g_new(gchar, strlen(p) + 3);
		while (*p)
			if (*p++ == ' ')
			        space = 1;
		if (space)
81
		        sprintf(text, "'%s'", args[4]->v.str->str);
82
		else
83
		        strcpy(text, args[4]->v.str->str);
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
		strcat(text, "!");
	}

	buf = g_new(gchar, strlen(text) + 50);

	switch (abs_num) {
	case 1:
	        if (a1)
		        sprintf(buf, "%s$%s$%d", text, col_name(col-1), row);
		else
		        sprintf(buf, "%sR%dC%d", text, row, col);
		break;
	case 2:
	        if (a1)
		        sprintf(buf, "%s%s$%d", text, col_name(col-1), row);
		else
		        sprintf(buf, "%sR%dC[%d]", text, row, col);
		break;
	case 3:
	        if (a1)
		        sprintf(buf, "%s$%s%d", text, col_name(col-1), row);
		else
		        sprintf(buf, "%sR[%d]C%d", text, row, col);
		break;
	case 4:
	        if (a1)
		        sprintf(buf, "%s%s%d", text, col_name(col-1), row);
		else
		        sprintf(buf, "%sR[%d]C[%d]", text, row, col);
		break;
	default:
	        g_free(text);
	        g_free(buf);
117
		return function_error (ei, gnumeric_err_NUM);
118 119 120 121 122 123 124 125
	}
	v = value_new_string (buf);
	g_free(text);
	g_free(buf);

	return v;
}

Michael Meeks's avatar
Michael Meeks committed
126 127 128 129 130
static char *help_choose = {
	N_("@FUNCTION=CHOOSE\n"
	   "@SYNTAX=CHOOSE(index[,value1][,value2]...)\n"

	   "@DESCRIPTION="
Michael Meeks's avatar
Michael Meeks committed
131
	   "CHOOSE returns the value of index @index."
Michael Meeks's avatar
Michael Meeks committed
132 133 134 135
	   "index is rounded to an integer if it is not."
	   "\n"
	   "if index < 1 or index > number of values: returns #VAL!."
	   "\n"
Michael Meeks's avatar
Michael Meeks committed
136
	   "@SEEALSO=IF")
Michael Meeks's avatar
Michael Meeks committed
137 138 139
};

static Value *
140
gnumeric_choose (FunctionEvalInfo *ei, GList *l)
Michael Meeks's avatar
Michael Meeks committed
141 142 143 144 145
{
	int     index;
	int     argc;
	Value  *v;

146 147
	argc =  g_list_length (l);

148 149
	if (argc < 1 || !l->data)
		return function_error (ei, _("#ARG!"));
150

Morten Welinder's avatar
Morten Welinder committed
151
	v = eval_expr (ei, l->data);
152 153 154
	if (!v)
		return NULL;

155
	if ((v->type != VALUE_INTEGER) && (v->type != VALUE_FLOAT)) {
Morten Welinder's avatar
Morten Welinder committed
156
		value_release (v);
157
		return function_error (ei, gnumeric_err_VALUE);
Michael Meeks's avatar
Michael Meeks committed
158
	}
159

Michael Meeks's avatar
Michael Meeks committed
160 161 162
	index = value_get_as_int(v);
	value_release (v);
	l = g_list_next (l);
163 164

	while (l){
Michael Meeks's avatar
Michael Meeks committed
165 166
		index--;
		if (!index)
167
			return eval_expr (ei, l->data);
Michael Meeks's avatar
Michael Meeks committed
168 169
		l = g_list_next (l);
	}
170
	return function_error (ei, gnumeric_err_VALUE);
Michael Meeks's avatar
Michael Meeks committed
171 172
}

173 174 175 176 177
static char *help_vlookup = {
	N_("@FUNCTION=VLOOKUP\n"
	   "@SYNTAX=VLOOKUP(value,range,column,[approximate])\n"

	   "@DESCRIPTION="
178 179 180 181 182 183 184
	   "The VLOOKUP function finds the row in range that has a first "
	   "column similar to value.  If approximate is not true it finds "
	   "the row with an exact equivilance.  If approximate is true, "
	   "then the values must be sorted in order of ascending value for "
	   "correct function; in this case it finds the row with value less "
	   "than value.  it returns the value in the row found at a 1 based "
	   "offset in column columns into the range."
185 186 187 188 189 190 191 192
	   "\n"
	   "Returns #NUM! if column < 0."
	   "Returns #REF! if column falls outside range."
	   "\n"
	   "@SEEALSO=HLOOKUP")
};

static int
193 194
lookup_similar (const Value *data, const Value *templ,
		const Value *next_largest, int approx)
195
{
196
	int ans;
197

198 199
	g_return_val_if_fail (data != NULL, 0);
	g_return_val_if_fail (templ != NULL, 0);
200

201
	switch (templ->type){
202 203
	case VALUE_INTEGER:
	case VALUE_FLOAT:
204 205 206 207 208 209 210 211 212 213 214 215 216 217
	{
		float_t a, b;
		
		a = value_get_as_float (data);
		b = value_get_as_float (templ);
		
		if (a == b)
			return 1;
		
		else if (approx && a < b){
			if (!next_largest)
				return -1;
			else if (value_get_as_float (next_largest) <= a)
				return -1;
218
		}
219 220 221
		return 0;
		break;
	}
222 223
	case VALUE_STRING:
	default:
224 225 226 227 228 229 230 231 232 233
	{
		char *a, *b;

		a = value_get_as_string (data);
		b = value_get_as_string (templ);

		if (approx){
			ans = strcasecmp (a,b);
			if (approx && ans < 0){
				if (next_largest){
234 235
					char *c = value_get_as_string
					        (next_largest);
236 237 238
					int cmp = strcasecmp (a,c);
					g_free (c);
					if (cmp >= 0) {
Morten Welinder's avatar
Morten Welinder committed
239 240
						g_free (a);
						g_free (b);
241
						return -1;
Morten Welinder's avatar
Morten Welinder committed
242
					}
243 244 245 246
				} else {
					g_free (a);
					g_free (b);
					return -1;
247 248 249
				}
			}
		}
250 251 252 253 254 255 256
		else
			ans = strcmp (a, b);
		g_free (a);
		g_free (b);
		return (ans == 0);
		break;
	}
257
	}
258
	return 0;
259 260 261
}

static Value *
262
gnumeric_vlookup (FunctionEvalInfo *ei, Value **args)
263
{
264 265
	const Value *next_largest = NULL;
	int height, lp, approx, col_idx, next_largest_row = 0;
266
	
Michael Meeks's avatar
Michael Meeks committed
267
	height = value_area_get_height (&ei->pos, args[1]);
268
	col_idx = value_get_as_int (args[2]);
269

270 271 272
	if (col_idx <= 0)
		return function_error (ei, gnumeric_err_NUM);

Michael Meeks's avatar
Michael Meeks committed
273
	if (col_idx > value_area_get_width (&ei->pos, args [1]))
274
		return function_error (ei, gnumeric_err_REF);
275

276
	if (args [3]){
277 278
		int err;

279
		approx = value_get_as_bool (args [3], &err);
280

281 282
		if (err)
			return function_error (ei, gnumeric_err_VALUE);
283 284
	} else
		approx = 1;
285

286
	for (lp = 0; lp < height; lp++){
287
		int compare;
288 289
		const Value *v;

Michael Meeks's avatar
Michael Meeks committed
290
		v = value_area_get_at_x_y (&ei->pos, args[1], 0, lp);
291

292
		g_return_val_if_fail (v != NULL, NULL);
293

294
		compare = lookup_similar (v, args[0], next_largest, approx);
295 296 297 298

		if (compare == 1){
			const Value *v;

Michael Meeks's avatar
Michael Meeks committed
299
			v = value_area_get_at_x_y (&ei->pos, args [1], col_idx-1, lp);
300
			g_return_val_if_fail (v != NULL, NULL);
301

302
			return value_duplicate (v);
303
		}
304 305 306
		if (compare < 0){
			next_largest = v;
			next_largest_row = lp;
307 308
		}
	}
309 310 311
	if (approx && next_largest){
	        const Value *v;

Michael Meeks's avatar
Michael Meeks committed
312
		v = value_area_get_at_x_y (&ei->pos, args [1], col_idx-1,
313
					   next_largest_row);
314 315
		g_return_val_if_fail (v != NULL, NULL);
		return value_duplicate (v);
316 317
	}
	else
318
		return function_error (ei, gnumeric_err_NA);
319

320
	return NULL;
321 322 323 324 325 326 327
}

static char *help_hlookup = {
	N_("@FUNCTION=HLOOKUP\n"
	   "@SYNTAX=HLOOKUP(value,range,row,[approximate])\n"

	   "@DESCRIPTION="
328 329 330 331 332 333 334
	   "The HLOOKUP function finds the col in range that has a first "
	   "row cell similar to value.  If approximate is not true it finds "
	   "the col with an exact equivilance.  If approximate is true, "
	   "then the values must be sorted in order of ascending value for "
	   "correct function; in this case it finds the col with value less "
	   "than value it returns the value in the col found at a 1 based "
	   "offset in row rows into the range."
335 336 337 338 339 340 341 342
	   "\n"
	   "Returns #NUM! if row < 0."
	   "Returns #REF! if row falls outside range."
	   "\n"
	   "@SEEALSO=VLOOKUP")
};

static Value *
343
gnumeric_hlookup (FunctionEvalInfo *ei, Value **args) 
344
{
345 346
	const Value *next_largest = NULL;
	int height, lp, approx, row_idx, next_largest_col = 0;
347
	
348
	row_idx = value_get_as_int (args [2]);
Michael Meeks's avatar
Michael Meeks committed
349
	height  = value_area_get_width (&ei->pos, args [1]);
350

351 352 353
	if (row_idx <= 0)
		return function_error (ei, gnumeric_err_NUM);

Michael Meeks's avatar
Michael Meeks committed
354
	if (row_idx > value_area_get_height (&ei->pos, args [1]))
355
		return function_error (ei, gnumeric_err_REF);
356

357
	if (args [3]){
358
		int err;
359
		approx = value_get_as_bool (args [3], &err);
360

361 362
		if (err)
			return function_error (ei, gnumeric_err_VALUE);
363 364
	} else
		approx = 1;
365

366
	for (lp = 0; lp < height; lp++){
367
		int compare;
368 369
		const Value *v;

Michael Meeks's avatar
Michael Meeks committed
370
		v = value_area_get_at_x_y (&ei->pos, args[1],lp, 0);
371 372 373

		g_return_val_if_fail (v != NULL, NULL);

374
		compare = lookup_similar (v, args[0], next_largest, approx);
375

376 377
		if (compare == 1){
			const Value *v;
378

Michael Meeks's avatar
Michael Meeks committed
379
			v = value_area_get_at_x_y (&ei->pos, args [1], lp, row_idx-1);
380 381 382
			g_return_val_if_fail (v != NULL, NULL);

			return value_duplicate (v);
383
		}
384 385 386 387

		if (compare < 0){
			next_largest = v;
			next_largest_col = lp;
388 389
		}
	}
390 391 392
	if (approx && next_largest){
		const Value *v;

Michael Meeks's avatar
Michael Meeks committed
393
		v = value_area_get_at_x_y (&ei->pos, args [1],
394
					   next_largest_col, row_idx-1);
395 396 397
		g_return_val_if_fail (v != NULL, NULL);

		return value_duplicate (v);
398 399
	}
	else
400
		return function_error (ei, gnumeric_err_NA);
401

402
	return NULL;
403 404
}

Michael Meeks's avatar
Michael Meeks committed
405 406 407 408 409
static char *help_lookup = {
	N_("@FUNCTION=LOOKUP\n"
	   "@SYNTAX=LOOKUP(value,vector1,vector2)\n"

	   "@DESCRIPTION="
410 411 412 413
	   "The LOOKUP function finds the row index of 'value' in vector1 "
	   "and returns the contents of value2 at that row index. "
	   "If the area is longer than it is wide then the sense of the "
	   "search is rotated. Alternatively a single array can be used."
Michael Meeks's avatar
Michael Meeks committed
414
	   "\n"
415 416 417
	   "If LOOKUP can't find value it uses the next largest value less "
	   "than value. "
	   "The data must be sorted. "
Michael Meeks's avatar
Michael Meeks committed
418 419 420 421 422 423 424 425
	   "\n"
	   "If value is smaller than the first value it returns #N/A"
	   "\n"
	   "@SEEALSO=VLOOKUP,HLOOKUP")
};

/* Not very efficient ! */
static Value *
426
gnumeric_lookup (FunctionEvalInfo *ei, Value **args)
Michael Meeks's avatar
Michael Meeks committed
427 428 429 430 431 432
{
	int height, width;
	const Value *next_largest = NULL;
	int next_largest_x = 0;
	int next_largest_y = 0;
	
Michael Meeks's avatar
Michael Meeks committed
433 434
	height  = value_area_get_height (&ei->pos, args[1]);
	width   = value_area_get_width  (&ei->pos, args[1]);
Michael Meeks's avatar
Michael Meeks committed
435

436 437 438 439 440 441 442 443 444 445
	if ((args[1]->type == VALUE_ARRAY)) {
		if (args[2])
			return function_error (ei, _("Type Mismatch"));

	} else if (args[1]->type == VALUE_CELLRANGE) {
		if (!args[2])
			return function_error (ei, _("Invalid number of arguments"));

	} else
		return function_error (ei, _("Type Mismatch"));
Michael Meeks's avatar
Michael Meeks committed
446 447 448 449 450 451
	
	{
		Value *src, *dest;
		int    x_offset=0, y_offset=0, lpx, lpy, maxx, maxy;
		int    tmp, compare, touched;

452 453
		if (args[1]->type == VALUE_ARRAY) {
			src = dest = args[1];
Michael Meeks's avatar
Michael Meeks committed
454 455 456 457 458
			if (width>height)
				y_offset = 1;
			else
				x_offset = 1;
		} else {
459 460
			src = args[1];
			dest = args[2];
Michael Meeks's avatar
Michael Meeks committed
461
		}
Michael Meeks's avatar
Michael Meeks committed
462 463 464
		maxy  = value_area_get_height (&ei->pos, src);
		maxx  = value_area_get_width  (&ei->pos, dest);
		if ((tmp=value_area_get_height (&ei->pos, src))<maxy)
Michael Meeks's avatar
Michael Meeks committed
465
			maxy=tmp;
Michael Meeks's avatar
Michael Meeks committed
466
		if ((tmp=value_area_get_width (&ei->pos, src))<maxx)
Michael Meeks's avatar
Michael Meeks committed
467 468 469 470
			maxx=tmp;

		touched = 0;
		for (lpx=0,lpy=0;lpx<maxx && lpy<maxy;) {
Michael Meeks's avatar
Michael Meeks committed
471
			const Value *v = value_area_get_at_x_y (&ei->pos, src, lpx, lpy);
472
			compare = lookup_similar (v, args[0], next_largest, 1);
Michael Meeks's avatar
Michael Meeks committed
473
			if (compare == 1)
Michael Meeks's avatar
Michael Meeks committed
474
				return value_duplicate (value_duplicate (value_area_get_at_x_y (&ei->pos, dest, next_largest_x+x_offset,
475
													  next_largest_y+y_offset)));
Michael Meeks's avatar
Michael Meeks committed
476 477 478 479 480 481 482 483 484 485 486 487
			if (compare < 0) {
				next_largest = v;
				next_largest_x = lpx;
				next_largest_y = lpy;
			} else
				break;

			if (width>height)
				lpx++;
			else
				lpy++;
		}
488 489 490 491

		if (!next_largest)
			return function_error (ei, gnumeric_err_NA);

Michael Meeks's avatar
Michael Meeks committed
492
		return value_duplicate (value_area_get_at_x_y (&ei->pos, dest,
493
							       next_largest_x+x_offset,
Michael Meeks's avatar
Michael Meeks committed
494 495 496 497 498 499
							       next_largest_y+y_offset));
	}
}



500 501 502 503 504
static char *help_column = {
	N_("@FUNCTION=COLUMN\n"
	   "@SYNTAX=COLUMN([reference])\n"

	   "@DESCRIPTION="
505 506
	   "The COLUMN function returns an array of the column numbers "
	   "taking a default argument of the containing cell position."
507
	   "\n"
508 509
	   "If reference is neither an array nor a reference nor a range "
	   "returns #VALUE!."
510 511 512 513 514 515
	   "\n"
	   "@SEEALSO=COLUMNS,ROW,ROWS")
};

/* FIXME: Needs Array support to be enven slightly meaningful */
static Value *
516
gnumeric_column (FunctionEvalInfo *ei, GList *nodes)
517
{
518
	Value *v;
519

520 521
	if (!nodes || !nodes->data)
		return value_new_int (ei->pos.eval_col+1);
522

Morten Welinder's avatar
Morten Welinder committed
523
	v = eval_expr (ei, nodes->data);
524
	if (!v)
525 526 527
		return NULL;

	switch (v->type){
528
	case VALUE_CELLRANGE:
Morten Welinder's avatar
Morten Welinder committed
529
		value_release (v);
530
		return function_error (ei, _("Arrays not yet supported"));
531
	case VALUE_ARRAY:
Morten Welinder's avatar
Morten Welinder committed
532
		value_release (v);
533
		return function_error (ei, _("Unimplemented"));
534
	default:
Morten Welinder's avatar
Morten Welinder committed
535
		value_release (v);
536
		return function_error (ei, gnumeric_err_VALUE);
537 538 539 540 541 542 543 544
	}
}

static char *help_columns = {
	N_("@FUNCTION=COLUMNS\n"
	   "@SYNTAX=COLUMNS(reference)\n"

	   "@DESCRIPTION="
545 546
	   "The COLUMNS function returns the number of columns in area or "
	   "array reference."
547
	   "\n"
548 549
	   "If reference is neither an array nor a reference nor a range "
	   "returns #VALUE!."
550 551 552 553 554 555
	   "\n"
	   "@SEEALSO=COLUMN,ROW,ROWS")
};

/* FIXME: Needs Array support to be enven slightly meaningful */
static Value *
556
gnumeric_columns (FunctionEvalInfo *ei, Value **args)
557
{
Michael Meeks's avatar
Michael Meeks committed
558
	return value_new_int (value_area_get_width (&ei->pos, args [0]));
559 560
}

561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
static char *help_offset = {
	N_("@FUNCTION=OFFSET\n"
	   "@SYNTAX=OFFSET(range,row,col,height,width)\n"

	   "@DESCRIPTION="
	   "The OFFSET function returns a cell range."
	   "The cell range starts at offset (col,row) from range, "
	   "and is of height @height and width @width."
	   "\n"
	   "If range is neither a reference nor a range returns #VALUE!."
	   "\n"
	   "@SEEALSO=COLUMN,COLUMNS,ROWS")
};

static Value *
576
gnumeric_offset (FunctionEvalInfo *ei, Value **args)
577 578 579 580 581
{
	CellRef a;
	CellRef b;
	int tw, th;

582
	g_return_val_if_fail (args [0]->type == VALUE_CELLRANGE, NULL);
583

584
	memcpy (&a, &args[0]->v.cell_range.cell_a, sizeof (CellRef));
585

586 587
	a.row += value_get_as_int (args[1]);
	a.col += value_get_as_int (args[2]);
588

589
	memcpy (&b, &a, sizeof(CellRef));
590

591 592
	tw = value_get_as_int (args[3]);
	th = value_get_as_int (args[4]);
593

594 595 596 597
	if (tw < 0 || th < 0)
		return function_error (ei, gnumeric_err_VALUE);
	else if (a.row < 0 || a.col < 0)
		return function_error (ei, gnumeric_err_REF);
598

599 600
	b.row += tw;
	b.col += th;
Michael Meeks's avatar
Michael Meeks committed
601
	return value_new_cellrange (&a, &b);
602 603
}

604 605 606 607 608
static char *help_row = {
	N_("@FUNCTION=ROW\n"
	   "@SYNTAX=ROW([reference])\n"

	   "@DESCRIPTION="
609 610
	   "The ROW function returns an array of the row numbers taking "
	   "a default argument of the containing cell position."
611
	   "\n"
612 613
	   "If reference is neither an array nor a reference nor a range "
	   "returns #VALUE!."
614 615 616 617 618 619
	   "\n"
	   "@SEEALSO=COLUMN,COLUMNS,ROWS")
};

/* FIXME: Needs Array support to be enven slightly meaningful */
static Value *
620
gnumeric_row (FunctionEvalInfo *ei, GList *nodes)
621
{
622
	Value *v;
623

624 625
	if (!nodes || !nodes->data)
		return value_new_int (ei->pos.eval_row+1);
626

Morten Welinder's avatar
Morten Welinder committed
627
	v = eval_expr (ei, nodes->data);
628
	if (!v)
629 630 631
		return NULL;

	switch (v->type){
632
	case VALUE_CELLRANGE:
Morten Welinder's avatar
Morten Welinder committed
633
		value_release (v);
634
		return function_error (ei, _("Arrays not yet supported"));
635

636
	case VALUE_ARRAY:
Morten Welinder's avatar
Morten Welinder committed
637
		value_release (v);
638
		return function_error (ei, _("Unimplemented"));
639
	default:
Morten Welinder's avatar
Morten Welinder committed
640
		value_release (v);
641
		return function_error (ei, gnumeric_err_VALUE);
642 643 644 645 646 647 648 649
	}
}

static char *help_rows = {
	N_("@FUNCTION=ROWS\n"
	   "@SYNTAX=ROWS(reference)\n"

	   "@DESCRIPTION="
650 651
	   "The ROWS function returns the number of rows in area or array "
	   "reference."
652
	   "\n"
653 654
	   "If reference is neither an array nor a reference nor a range "
	   "returns #VALUE!."
655 656 657 658 659 660
	   "\n"
	   "@SEEALSO=COLUMN,ROW,ROWS")
};

/* FIXME: Needs Array support to be enven slightly meaningful */
static Value *
661
gnumeric_rows (FunctionEvalInfo *ei, Value **args)
662
{
Michael Meeks's avatar
Michael Meeks committed
663
	return value_new_int (value_area_get_height (&ei->pos, args [0]));
664 665
}

666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
void lookup_functions_init()
{
	FunctionCategory *cat = function_get_category (_("Data / Lookup"));

	function_add_args  (cat, "address",   "ff|ffs", "row_num,col_num,abs_num,a1,text",
			   &help_address,  gnumeric_address);
        function_add_nodes (cat, "choose",     0,     "index,value...",
			    &help_choose,  gnumeric_choose);
	function_add_nodes (cat, "column",    "?",    "ref",
			    &help_column,  gnumeric_column);
	function_add_args  (cat, "columns",   "A",    "ref",
			    &help_columns, gnumeric_columns);
	function_add_args  (cat, "hlookup",   "?Af|b","val,range,col_idx,approx",
			    &help_hlookup, gnumeric_hlookup);
	function_add_args  (cat, "lookup",    "?A|r", "val,range,range",
			    &help_lookup,  gnumeric_lookup);
	function_add_args  (cat, "offset",    "rffff","ref,row,col,hight,width",
			    &help_offset,  gnumeric_offset);
	function_add_nodes (cat, "row",       "?",    "ref",
			    &help_row,     gnumeric_row);
	function_add_args  (cat, "rows",      "A",    "ref",
			    &help_rows,    gnumeric_rows);
	function_add_args  (cat, "vlookup",   "?Af|b","val,range,col_idx,approx",
			    &help_vlookup, gnumeric_vlookup);
}