functions.c 23.9 KB
Newer Older
Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
1 2 3
/*
 * fn-information.c:  Information built-in functions
 *
Morten Welinder's avatar
Morten Welinder committed
4
 * Authors:
Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
5
 *  Jukka-Pekka Iivonen (iivonen@iki.fi)
Morten Welinder's avatar
Morten Welinder committed
6
 *  Jody Goldberg (jgoldberg@home.com)
7
 *  Morten Welinder (terra@diku.dk)
8
 *  Almer S. Tigelaar (almer@gnome.org)
Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
9 10 11
 */
#include <config.h>
#include "func.h"
Jody Goldberg's avatar
Jody Goldberg committed
12
#include "parse-util.h"
13
#include "cell.h"
Jody Goldberg's avatar
Jody Goldberg committed
14 15
#include "str.h"
#include "sheet.h"
16
#include "workbook.h"
Jody Goldberg's avatar
Jody Goldberg committed
17
#include "format.h"
18
#include "formats.h"
19
#include "style.h"
Jody Goldberg's avatar
Jody Goldberg committed
20
#include "sheet-style.h"
21
#include "number-match.h"
Jody Goldberg's avatar
Jody Goldberg committed
22

23
#include <sys/utsname.h>
24
#include <math.h>
25 26
#include <stdlib.h>
#include <string.h>
27 28

enum Value_Class {
Miguel de Icaza's avatar
Miguel de Icaza committed
29 30 31
	VALUE_CLASS_NUMBER  = 1,
	VALUE_CLASS_TEXT    = 2,
	VALUE_CLASS_BOOL    = 4,
32
	VALUE_CLASS_FORMULA = 8,
Miguel de Icaza's avatar
Miguel de Icaza committed
33 34 35
	VALUE_CLASS_ERROR   = 16,
	VALUE_CLASS_ARRAY   = 64,
	VALUE_CLASS_BOGUS   = -1,
36 37 38 39
};


static enum Value_Class
40
get_value_class (FunctionEvalInfo *ei, ExprTree *expr)
41 42 43 44
{
	Value *value;
	enum Value_Class res;

45 46
	value = eval_expr (ei->pos, expr,
			   EVAL_PERMIT_NON_SCALAR|EVAL_PERMIT_EMPTY);
47 48 49 50 51 52 53 54 55
	if (value) {
		switch (value->type) {
		case VALUE_INTEGER:
		case VALUE_FLOAT:
			res = VALUE_CLASS_NUMBER;
			break;
		case VALUE_STRING:
			res = VALUE_CLASS_TEXT;
			break;
56 57 58 59 60 61
		case VALUE_BOOLEAN:
			res = VALUE_CLASS_BOOL;
			break;
		case VALUE_ERROR:
			res = VALUE_CLASS_ERROR;
			break;
62 63 64
		case VALUE_ARRAY:
			res = VALUE_CLASS_ARRAY;
			break;
65
		case VALUE_EMPTY:
66 67 68 69
		default:
			res = VALUE_CLASS_BOGUS;
			break;
		}
Morten Welinder's avatar
Morten Welinder committed
70
		value_release (value);
71 72 73 74 75
	} else
		res = VALUE_CLASS_ERROR;

	return res;
}
Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
76

77
/***************************************************************************/
Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
78

Morten Welinder's avatar
Morten Welinder committed
79 80
static char *help_cell = {
	N_("@FUNCTION=CELL\n"
81
	   "@SYNTAX=CELL(ref)\n"
Morten Welinder's avatar
Morten Welinder committed
82 83

	   "@DESCRIPTION="
84 85
	   "CELL returns information about the formatting, location, or "
	   "contents of a cell. "
Morten Welinder's avatar
Morten Welinder committed
86
	   "\n"
87 88
	   "@EXAMPLES=\n"
	   "\n"
Morten Welinder's avatar
Morten Welinder committed
89 90 91
	   "@SEEALSO=")
};

92 93 94 95 96
typedef struct {
	char *format;
	char *output;
} translate_t;
static translate_t translate_table[] = {
97
	{ "General", "G" },
98 99 100 101
	{ "0", "F0" },
	{ "#,##0", ",0" },
	{ "0.00", "F2" },
	{ "#,##0.00", ",2" },
102 103 104 105
	{ "\"$\"#,##0_);\\(\"$\"#,##0\\)", "C0" },
	{ "\"$\"#,##0_);[Red]\\(\"$\"#,##0\\)", "C0-" },
	{ "\"$\"#,##0.00_);\\(\"$\"#,##0.00\\)", "C2" },
	{ "\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)", "C2-" },
106 107 108 109
	{ "0%", "P0" },
	{ "0.00%", "P2" },
	{ "0.00e+00", "S2" },
	{ "# ?/?", "G" },
110
	{ "# ?" "?/?" "?", "G" },   /* Don't accidentally use trigraphs here.  */
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
	{ "m/d/yy", "D4" },
	{ "m/d/yy h:mm", "D4" },
	{ "mm/dd/yy", "D4" },
	{ "d-mmm-yy", "D1" },
	{ "dd-mmm-yy", "D1" },
	{ "d-mmm", "D2" },
	{ "dd-mmm", "D2" },
	{ "mmm-yy", "D3" },
	{ "mm/dd", "D5" },
	{ "h:mm am/pm", "D7" },
	{ "h:mm:ss am/pm", "D6" },
	{ "h:mm", "D9" },
	{ "h:mm:ss", "D8" }
};

static Value *
Jody Goldberg's avatar
Jody Goldberg committed
127
translate_cell_format (StyleFormat const *format)
128 129
{
	int i;
Jody Goldberg's avatar
Jody Goldberg committed
130
	char *fmt;
Morten Welinder's avatar
Morten Welinder committed
131
	const int translate_table_count = sizeof (translate_table) / sizeof(translate_t);
132

Jody Goldberg's avatar
Jody Goldberg committed
133
	if (format == NULL)
134 135
		return value_new_string ("G");

Jody Goldberg's avatar
Jody Goldberg committed
136 137 138 139 140
	fmt = style_format_as_XL (format, FALSE);

	/*
	 * TODO : What does this do in different locales ??
	 */
Morten Welinder's avatar
Morten Welinder committed
141
	for (i = 0; i < translate_table_count; i++) {
142
		const translate_t *t = &translate_table[i];
143
		
Jody Goldberg's avatar
Jody Goldberg committed
144 145
		if (!g_strcasecmp (fmt, t->format)) {
			g_free (fmt);
146
			return value_new_string (t->output);
Jody Goldberg's avatar
Jody Goldberg committed
147
		}
148
	}
Jody Goldberg's avatar
Jody Goldberg committed
149 150

	g_free (fmt);
151 152 153
	return value_new_string ("G");
}

154 155 156 157 158 159 160 161 162 163 164 165 166 167
static FormatCharacteristics
retrieve_format_info (Sheet *sheet, int col, int row)
{
	MStyle *mstyle = sheet_style_get (sheet, col, row);
	StyleFormat *format = mstyle_get_format (mstyle);
	char *fmt = style_format_as_XL (format, FALSE);
	FormatCharacteristics info;

	cell_format_classify (fmt, &info);
	g_free (fmt);

	return info;
}

Morten Welinder's avatar
Morten Welinder committed
168
static Value *
169
gnumeric_cell (FunctionEvalInfo *ei, Value **argv)
Morten Welinder's avatar
Morten Welinder committed
170
{
Morten Welinder's avatar
Morten Welinder committed
171
	const char *info_type = value_peek_string (argv[0]);
172
	CellRef ref = argv [1]->v_range.cell.a;
173
	
174
	if (!g_strcasecmp(info_type, "address")) {
Morten Welinder's avatar
Morten Welinder committed
175
		/* Reference of the first cell in reference, as text. */
176
		return value_new_string (cell_coord_name (ref.col, ref.row));
177 178 179
	} else if (!g_strcasecmp (info_type, "col")) {
		return value_new_int (ref.col + 1);
	} else if (!g_strcasecmp (info_type, "color")) {
180 181 182 183
		FormatCharacteristics info = retrieve_format_info (ei->pos->sheet, ref.col, ref.row);

		/* 0x01 = first bit (1) indicating negative colors */
		return (info.negative_fmt & 0x01) ? value_new_int (1) : value_new_int (0);
184
	} else if (!g_strcasecmp (info_type, "contents")) {
185
		Cell *cell = sheet_cell_get (ei->pos->sheet, ref.col, ref.row);
186
		
187 188
		if (cell && cell->value)
			return value_duplicate (cell->value);
189
		return value_new_empty ();
190
	} else if (!g_strcasecmp (info_type, "filename"))	{
191 192 193 194 195 196
		char *name = ei->pos->sheet->workbook->filename;

		if (name == NULL)
			return value_new_string ("");
		else
			return value_new_string (name);
197
	} else if (!g_strcasecmp (info_type, "format")) {
198
		MStyle *mstyle = sheet_style_get (ei->pos->sheet, ref.col, ref.row);
199
		
200
		return translate_cell_format (mstyle_get_format (mstyle));
201 202 203 204 205
	} else if (!g_strcasecmp (info_type, "parentheses")) {
		FormatCharacteristics info = retrieve_format_info (ei->pos->sheet, ref.col, ref.row);

		/* 0x02 = second bit (2) indicating parentheses */
		return (info.negative_fmt & 0x02) ? value_new_int (1) : value_new_int (0);
206
	} else if (!g_strcasecmp (info_type, "prefix")) {
207 208 209 210 211 212 213 214 215 216 217 218 219 220
		MStyle *mstyle = sheet_style_get (ei->pos->sheet, ref.col, ref.row);
		Cell *cell = sheet_cell_get (ei->pos->sheet, ref.col, ref.row);
		
		if (cell && cell->value && cell->value->type == VALUE_STRING) {
			switch (mstyle_get_align_h (mstyle)) {
			case HALIGN_GENERAL: return value_new_string ("'");
			case HALIGN_LEFT:    return value_new_string ("'");
			case HALIGN_RIGHT:   return value_new_string ("\"");
			case HALIGN_CENTER:  return value_new_string ("^");
			case HALIGN_FILL:    return value_new_string ("\\");
			default : 	     return value_new_string ("");
			}
		}
		return value_new_string ("");
221
	} else if (!g_strcasecmp (info_type, "protect")) {
222 223 224 225 226
		/*
		 * FIXME: We can only implement this when we have proper
		 * cell locking in place. For now we will ALWAYS return 0
		 * this is correct as no cell can ever be locked.
		 */
Morten Welinder's avatar
Morten Welinder committed
227
		/* 0 if the cell is not locked, and 1 if the cell is locked. */
228
		return value_new_int (0);
229 230 231 232 233
	} else if (!g_strcasecmp (info_type, "row")) {
		return value_new_int (ref.row + 1);
	} else if (!g_strcasecmp (info_type, "type")) {
		Cell *cell;

234
		cell = sheet_cell_get (ei->pos->sheet, ref.col, ref.row);
235 236 237 238 239 240 241 242
		if (cell && cell->value) {
			if (cell->value->type == VALUE_STRING)
				return value_new_string ("l");
			else
				return value_new_string ("v");
		}
		return value_new_string ("b");
	} else if (!g_strcasecmp (info_type, "width")) {
243 244 245 246 247 248 249 250
		ColRowInfo *info = sheet_col_get_info (ei->pos->sheet, ref.col);
		double charwidth;
		int    cellwidth;

		charwidth = style_font_get_width (gnumeric_default_font);
		cellwidth = info->size_pts;

		return value_new_int (rint (cellwidth / charwidth));
Morten Welinder's avatar
Morten Welinder committed
251 252
	}

253
	return value_new_error (ei->pos, _("Unknown info_type"));
Morten Welinder's avatar
Morten Welinder committed
254 255
}

256
/***************************************************************************/
Morten Welinder's avatar
Morten Welinder committed
257

Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
258 259 260 261 262
static char *help_countblank = {
        N_("@FUNCTION=COUNTBLANK\n"
           "@SYNTAX=COUNTBLANK(range)\n"

           "@DESCRIPTION="
263
           "COUNTBLANK returns the number of blank cells in a @range. "
264
	   "This function is Excel compatible. "
Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
265
           "\n"
266 267
	   "@EXAMPLES=\n"
	   "\n"
Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
268 269 270
           "@SEEALSO=COUNT")
};

271 272 273 274 275 276 277 278 279
static Value *
cb_countblank (Sheet *sheet, int col, int row,
	       Cell *cell, void *user_data)
{
	if (!cell_is_blank (cell))
		*((int *)user_data) -= 1;
	return NULL;
}

Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
280
static Value *
281
gnumeric_countblank (FunctionEvalInfo *ei, Value **args)
Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
282
{
283
	RangeRef const * const r = &args[0]->v_range.cell;
Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
284

285 286
	/* FIXME : This does not handle 3D references */
	int count = (abs(r->a.col - r->b.col) + 1) *
287
		    (abs(r->a.row - r->b.row) + 1);
Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
288

289 290
	workbook_foreach_cell_in_range (ei->pos, args[0], TRUE,
					&cb_countblank, &count);
Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
291

Michael Meeks's avatar
Michael Meeks committed
292
	return value_new_int (count);
Jukka-Pekka Iivonen's avatar
Jukka-Pekka Iivonen committed
293 294
}

295 296
/***************************************************************************/

Morten Welinder's avatar
Morten Welinder committed
297 298 299 300 301
static char *help_info = {
	N_("@FUNCTION=INFO\n"
	   "@SYNTAX=INFO()\n"

	   "@DESCRIPTION="
302
	   "INFO returns information about the current operating environment. "
303
	   "This function is Excel compatible. "
Morten Welinder's avatar
Morten Welinder committed
304
	   "\n"
305 306
	   "@EXAMPLES=\n"
	   "\n"
Morten Welinder's avatar
Morten Welinder committed
307 308 309
	   "@SEEALSO=")
};

310

Morten Welinder's avatar
Morten Welinder committed
311
static Value *
312
gnumeric_info (FunctionEvalInfo *ei, Value **argv)
Morten Welinder's avatar
Morten Welinder committed
313
{
Morten Welinder's avatar
Morten Welinder committed
314
	char const * const info_type = value_peek_string (argv[0]);
315
	if (!g_strcasecmp (info_type, "directory")) {
Morten Welinder's avatar
Morten Welinder committed
316
		/* Path of the current directory or folder.  */
317
		return value_new_error (ei->pos, _("Unimplemented"));
318
	} else if (!g_strcasecmp (info_type, "memavail")) {
319 320
		/* Amount of memory available, in bytes.  */
		return value_new_int (15 << 20);  /* Good enough... */
321
	} else if (!g_strcasecmp (info_type, "memused")) {
322 323
		/* Amount of memory being used for data.  */
		return value_new_int (1 << 20);  /* Good enough... */
324
	} else if (!g_strcasecmp (info_type, "numfile")) {
325 326
		/* Number of active worksheets.  */
		return value_new_int (1);  /* Good enough... */
327
	} else if (!g_strcasecmp (info_type, "origin")) {
328 329 330 331
		/* Absolute A1-style reference, as text, prepended with "$A:"
		 * for Lotus 1-2-3 release 3.x compatibility. Returns the cell
		 * reference of the top and leftmost cell visible in the
		 * window, based on the current scrolling position.
332
		 */
333
		return value_new_error (ei->pos, _("Unimplemented"));
334
	} else if (!g_strcasecmp (info_type, "osversion")) {
335
		/* Current operating system version, as text.  */
336
		struct utsname unamedata;
337

338
		if (uname (&unamedata) == -1)
339
			return value_new_error (ei->pos,
340
						_("Unknown version"));
341
		else {
342
			char *tmp = g_strdup_printf (_("%s version %s"),
343 344 345
						     unamedata.sysname,
						     unamedata.release);
			Value *res = value_new_string (tmp);
346
			g_free (tmp);
347
			return res;
348
		}
349
	} else if (!g_strcasecmp (info_type, "recalc")) {
350 351
		/* Current recalculation mode; returns "Automatic" or "Manual".  */
		return value_new_string (_("Automatic"));
352
	} else if (!g_strcasecmp (info_type, "release")) {
353 354
		/* Version of Gnumeric (Well, Microsoft Excel), as text.  */
		return value_new_string (GNUMERIC_VERSION);
355
	} else if (!g_strcasecmp (info_type, "system")) {
356
		/* Name of the operating environment.  */
357 358
		struct utsname unamedata;

359
		if (uname (&unamedata) == -1)
360
			return value_new_error (ei->pos, _("Unknown system"));
361
		else
362
			return value_new_string (unamedata.sysname);
363
	} else if (!g_strcasecmp (info_type, "totmem")) {
364 365 366 367
		/* Total memory available, including memory already in use, in
		 * bytes.
		 */
		return value_new_int (16 << 20);  /* Good enough... */
Morten Welinder's avatar
Morten Welinder committed
368 369
	}

370
	return value_new_error (ei->pos, _("Unknown info_type"));
Morten Welinder's avatar
Morten Welinder committed
371 372
}

373
/***************************************************************************/
Morten Welinder's avatar
Morten Welinder committed
374

375 376
static char *help_iserror = {
	N_("@FUNCTION=ISERROR\n"
377
	   "@SYNTAX=ISERROR(value)\n"
378 379 380 381 382 383 384 385 386 387 388

	   "@DESCRIPTION="
	   "ISERROR returns a TRUE value if the expression has an error\n"
	   "This function is Excel compatible. "
	   "\n"
	   "@EXAMPLES=\n"
	   "\n"
	   "@SEEALSO=ERROR")
};

/* A utility routine to evaluate a single argument and return any errors
389
 * directly
390 391
 */
static Value *
392
gnumeric_check_for_err (FunctionEvalInfo *ei, GList *expr_node_list,
393 394 395 396 397
			Value ** err)
{
	Value * tmp;

	if (g_list_length (expr_node_list) != 1) {
398
		*err = value_new_error(ei->pos,
399 400 401
				       _("Argument mismatch"));
		return NULL;
	}
402
	tmp = eval_expr (ei->pos, (ExprTree *) expr_node_list->data, EVAL_STRICT);
403 404 405 406 407 408 409 410 411 412

	if (tmp != NULL) {
		if (tmp->type == VALUE_ERROR)
			return tmp;
		value_release (tmp);
	}
	return NULL;
}

static Value *
413
gnumeric_iserror (FunctionEvalInfo *ei, GList *expr_node_list)
414 415
{
	Value * res, *err = NULL;
416
	res = gnumeric_check_for_err (ei, expr_node_list, &err);
417 418 419 420 421 422 423 424 425 426 427 428 429 430
	if (err != NULL)
		return err;

	if (res) {
		value_release (res);
		return value_new_bool (TRUE);
	} else
		return value_new_bool (FALSE);
}

/***************************************************************************/

static char *help_isna = {
	N_("@FUNCTION=ISNA\n"
431
	   "@SYNTAX=ISNA(value)\n"
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446

	   "@DESCRIPTION="
	   "ISNA returns TRUE if the value is the #N/A error value. "
	   "This function is Excel compatible. "
	   "\n"
	   "@EXAMPLES=\n"
	   "\n"
	   "@SEEALSO=")
};

/*
 * We need to operator directly in the input expression in order to bypass
 * the error handling mechanism
 */
static Value *
447
gnumeric_isna (FunctionEvalInfo *ei, GList *expr_node_list)
448 449 450 451
{
	Value * res, *err = NULL;
	gboolean b;

452
	res = gnumeric_check_for_err (ei, expr_node_list, &err);
453 454 455
	if (err != NULL)
		return err;

456
	b = (res && !strcmp (gnumeric_err_NA, res->v_err.mesg->str));
457 458 459 460 461 462 463 464
	if (res) value_release (res);
	return value_new_bool (b);
}

/***************************************************************************/

static char *help_iserr = {
	N_("@FUNCTION=ISERR\n"
465
	   "@SYNTAX=ISERR(value)\n"
466 467 468 469 470 471 472 473 474 475 476

	   "@DESCRIPTION="
	   "ISERR returns TRUE if the value is any error value except #N/A. "
	   "This function is Excel compatible. "
	   "\n"
	   "@EXAMPLES=\n"
	   "\n"
	   "@SEEALSO=")
};

static Value *
477
gnumeric_iserr (FunctionEvalInfo *ei, GList *expr_node_list)
478 479 480 481
{
	Value * res, *err = NULL;
	gboolean b;

482
	res = gnumeric_check_for_err (ei, expr_node_list, &err);
483 484 485
	if (err != NULL)
		return err;

486
	b = (res && strcmp (gnumeric_err_NA, res->v_err.mesg->str));
487 488 489 490 491 492 493 494
	if (res) value_release (res);
	return value_new_bool (b);
}

/***************************************************************************/

static char *help_error_type = {
	N_("@FUNCTION=ERROR.TYPE\n"
495
	   "@SYNTAX=ERROR(value)\n"
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514

	   "@DESCRIPTION="
	   "ERROR.TYPE returns an error number corresponding to the given "
	   "error value.  The error numbers for error values are\n"
	   "#DIV/0!    2\n"
	   "#VALUE!    3\n"
	   "#REF!      4\n"
	   "#NAME!     5\n"
	   "#NUM!      6\n"
	   "#NA!       7\n"
	   "This function is Excel compatible. "
	   "\n"
	   "@EXAMPLES=\n"
	   "ERROR.TYPE(NA()) equals 7.\n"
	   "\n"
	   "@SEEALSO=ISERROR")
};

static Value *
515
gnumeric_error_type (FunctionEvalInfo *ei, GList *expr_node_list)
516 517 518 519
{
	int retval = -1;
	char const * mesg;
	Value * res, *err = NULL;
520
	res = gnumeric_check_for_err (ei, expr_node_list, &err);
521 522 523
	if (err != NULL)
		return err;
	if (res == NULL)
524
		return value_new_error (ei->pos, gnumeric_err_NA);
525

526
	mesg = res->v_err.mesg->str;
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
	if (!strcmp (gnumeric_err_NULL, mesg))
		retval = 1;
	else if (!strcmp (gnumeric_err_DIV0, mesg))
		retval = 2;
	else if (!strcmp (gnumeric_err_VALUE, mesg))
		retval = 3;
	else if (!strcmp (gnumeric_err_REF, mesg))
		retval = 4;
	else if (!strcmp (gnumeric_err_NAME, mesg))
		retval = 5;
	else if (!strcmp (gnumeric_err_NUM, mesg))
		retval = 6;
	else if (!strcmp (gnumeric_err_NA, mesg))
		retval = 7;
	else {
		value_release (res);
543
		return value_new_error (ei->pos, gnumeric_err_NA);
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
	}

	value_release (res);
	return value_new_int (retval);
}

/***************************************************************************/

static char *help_na = {
	N_("@FUNCTION=NA\n"
	   "@SYNTAX=NA()\n"

	   "@DESCRIPTION="
	   "NA returns the error value #N/A. "
	   "This function is Excel compatible. "
	   "\n"
	   "@EXAMPLES=\n"
	   "\n"
	   "@SEEALSO=")
};

static Value *
566
gnumeric_na (FunctionEvalInfo *ei, Value **argv)
567
{
568
	return value_new_error (ei->pos, gnumeric_err_NA);
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
}

/***************************************************************************/

static char *help_error = {
	N_("@FUNCTION=ERROR\n"
	   "@SYNTAX=ERROR(text)\n"

	   "@DESCRIPTION="
	   "ERROR return the specified error\n"
	   "\n"
	   "@EXAMPLES=\n"
	   "\n"
	   "@SEEALSO=ISERROR")
};

static Value *
586
gnumeric_error (FunctionEvalInfo *ei, Value *argv[])
587
{
Morten Welinder's avatar
Morten Welinder committed
588
	return value_new_error (ei->pos, value_peek_string (argv[0]));
589 590 591 592
}

/***************************************************************************/

Morten Welinder's avatar
Morten Welinder committed
593 594
static char *help_isblank = {
	N_("@FUNCTION=ISBLANK\n"
595
	   "@SYNTAX=ISBLANK(value)\n"
Morten Welinder's avatar
Morten Welinder committed
596 597

	   "@DESCRIPTION="
598
	   "ISBLANK returns TRUE if the value is blank. "
599
	   "This function is Excel compatible. "
Morten Welinder's avatar
Morten Welinder committed
600
	   "\n"
601 602
	   "@EXAMPLES=\n"
	   "\n"
Morten Welinder's avatar
Morten Welinder committed
603 604 605 606
	   "@SEEALSO=")
};

static Value *
607
gnumeric_isblank (FunctionEvalInfo *ei, GList *expr_node_list)
Morten Welinder's avatar
Morten Welinder committed
608
{
609 610 611
	gboolean result = FALSE;
	ExprTree *expr;
	if (g_list_length (expr_node_list) != 1)
612
		return value_new_error (ei->pos,
613
					_("Invalid number of arguments"));
614 615 616 617 618 619 620 621

	expr = expr_node_list->data;

	/* How can this happen ? */
	if (expr == NULL)
		return value_new_bool (FALSE);

	/* Handle pointless arrays */
622 623
	if (expr->any.oper == OPER_ARRAY) {
		if (expr->array.rows != 1 || expr->array.cols != 1)
624
			return value_new_bool (FALSE);
625
		expr = expr->array.corner.expr;
626 627
	}

628 629
	if (expr->any.oper == OPER_VAR) {
		CellRef const *ref = &expr->var.ref;
630
		Sheet const *sheet = eval_sheet (ref->sheet, ei->pos->sheet);
631
		int row, col;
632
		cell_get_abs_col_row(ref, &ei->pos->eval, &col, &row);
633 634
		result = cell_is_blank(sheet_cell_get(sheet, col, row));
	}
635
	return value_new_bool (result);
Morten Welinder's avatar
Morten Welinder committed
636 637
}

638
/***************************************************************************/
Morten Welinder's avatar
Morten Welinder committed
639 640 641

static char *help_iseven = {
	N_("@FUNCTION=ISEVEN\n"
642
	   "@SYNTAX=ISEVEN(value)\n"
Morten Welinder's avatar
Morten Welinder committed
643 644

	   "@DESCRIPTION="
645
	   "ISEVEN returns TRUE if the number is even. "
646
	   "This function is Excel compatible. "
Morten Welinder's avatar
Morten Welinder committed
647
	   "\n"
648 649
	   "@EXAMPLES=\n"
	   "\n"
650
	   "@SEEALSO=ISODD")
Morten Welinder's avatar
Morten Welinder committed
651 652 653
};

static Value *
654
gnumeric_iseven (FunctionEvalInfo *ei, Value **argv)
Morten Welinder's avatar
Morten Welinder committed
655
{
656
	return value_new_bool (!(value_get_as_int (argv[0]) & 1));
Morten Welinder's avatar
Morten Welinder committed
657 658
}

659
/***************************************************************************/
Morten Welinder's avatar
Morten Welinder committed
660 661 662

static char *help_islogical = {
	N_("@FUNCTION=ISLOGICAL\n"
663
	   "@SYNTAX=ISLOGICAL(value)\n"
Morten Welinder's avatar
Morten Welinder committed
664 665

	   "@DESCRIPTION="
666
	   "ISLOGICAL returns TRUE if the value is a logical value. "
667
	   "This function is Excel compatible. "
Morten Welinder's avatar
Morten Welinder committed
668
	   "\n"
669 670
	   "@EXAMPLES=\n"
	   "\n"
Morten Welinder's avatar
Morten Welinder committed
671 672 673 674
	   "@SEEALSO=")
};

static Value *
675
gnumeric_islogical (FunctionEvalInfo *ei, GList *expr_node_list)
Morten Welinder's avatar
Morten Welinder committed
676
{
677 678
	enum Value_Class cl;

679
	if (g_list_length (expr_node_list) != 1)
680
		return value_new_error (ei->pos,
681
					_("Invalid number of arguments"));
682

683
	cl = get_value_class (ei, expr_node_list->data);
684 685

	return value_new_bool (cl == VALUE_CLASS_BOOL);
Morten Welinder's avatar
Morten Welinder committed
686 687
}

688
/***************************************************************************/
Morten Welinder's avatar
Morten Welinder committed
689 690 691

static char *help_isnontext = {
	N_("@FUNCTION=ISNONTEXT\n"
692
	   "@SYNTAX=ISNONTEXT(value)\n"
Morten Welinder's avatar
Morten Welinder committed
693 694 695

	   "@DESCRIPTION="
	   "ISNONTEXT Returns TRUE if the value is not text. "
696
	   "This function is Excel compatible. "
Morten Welinder's avatar
Morten Welinder committed
697
	   "\n"
698 699
	   "@EXAMPLES=\n"
	   "\n"
700
	   "@SEEALSO=ISTEXT")
Morten Welinder's avatar
Morten Welinder committed
701 702 703
};

static Value *
704
gnumeric_isnontext (FunctionEvalInfo *ei, GList *expr_node_list)
Morten Welinder's avatar
Morten Welinder committed
705
{
706
	if (g_list_length (expr_node_list) != 1)
707
		return value_new_error (ei->pos,
708
					_("Invalid number of arguments"));
709

710 711
	return value_new_bool (get_value_class (ei, expr_node_list->data)
			       != VALUE_CLASS_TEXT);
Morten Welinder's avatar
Morten Welinder committed
712 713
}

714
/***************************************************************************/
Morten Welinder's avatar
Morten Welinder committed
715 716 717

static char *help_isnumber = {
	N_("@FUNCTION=ISNUMBER\n"
718
	   "@SYNTAX=ISNUMBER(value)\n"
Morten Welinder's avatar
Morten Welinder committed
719 720

	   "@DESCRIPTION="
721
	   "ISNUMBER returns TRUE if the value is a number. "
722
	   "This function is Excel compatible. "
Morten Welinder's avatar
Morten Welinder committed
723
	   "\n"
724 725
	   "@EXAMPLES=\n"
	   "\n"
Morten Welinder's avatar
Morten Welinder committed
726 727 728 729
	   "@SEEALSO=")
};

static Value *
730
gnumeric_isnumber (FunctionEvalInfo *ei, GList *expr_node_list)
Morten Welinder's avatar
Morten Welinder committed
731
{
732
	if (g_list_length (expr_node_list) != 1)
733
		return value_new_error (ei->pos,
734
					_("Invalid number of arguments"));
735

736 737
	return value_new_bool (get_value_class (ei, expr_node_list->data)
			       == VALUE_CLASS_NUMBER);
Morten Welinder's avatar
Morten Welinder committed
738 739
}

740
/***************************************************************************/
Morten Welinder's avatar
Morten Welinder committed
741 742 743

static char *help_isodd = {
	N_("@FUNCTION=ISODD\n"
744
	   "@SYNTAX=ISODD(value)\n"
Morten Welinder's avatar
Morten Welinder committed
745 746

	   "@DESCRIPTION="
747
	   "ISODD returns TRUE if the number is odd. "
748
	   "This function is Excel compatible. "
Morten Welinder's avatar
Morten Welinder committed
749
	   "\n"
750 751
	   "@EXAMPLES=\n"
	   "\n"
752
	   "@SEEALSO=ISEVEN")
Morten Welinder's avatar
Morten Welinder committed
753 754 755
};

static Value *
756
gnumeric_isodd (FunctionEvalInfo *ei, Value **argv)
Morten Welinder's avatar
Morten Welinder committed
757
{
758
	return value_new_bool (value_get_as_int (argv[0]) & 1);
Morten Welinder's avatar
Morten Welinder committed
759 760
}

761
/***************************************************************************/
Morten Welinder's avatar
Morten Welinder committed
762 763 764

static char *help_isref = {
	N_("@FUNCTION=ISREF\n"
765
	   "@SYNTAX=ISREF(value)\n"
Morten Welinder's avatar
Morten Welinder committed
766 767

	   "@DESCRIPTION="
768
	   "ISREF returns TRUE if the value is a reference. "
769
	   "This function is Excel compatible. "
Morten Welinder's avatar
Morten Welinder committed
770
	   "\n"
771 772
	   "@EXAMPLES=\n"
	   "\n"
Morten Welinder's avatar
Morten Welinder committed
773 774 775 776
	   "@SEEALSO=")
};

static Value *
777
gnumeric_isref (FunctionEvalInfo *ei, GList *expr_node_list)
Morten Welinder's avatar
Morten Welinder committed
778
{
779 780 781
	ExprTree *t;

	if (g_list_length (expr_node_list) != 1)
782
		return value_new_error (ei->pos,
783
					_("Invalid number of arguments"));
784 785 786 787 788

	t = expr_node_list->data;
	if (!t)
		return NULL;

789
	return value_new_bool (t->any.oper == OPER_VAR);
Morten Welinder's avatar
Morten Welinder committed
790 791
}

792
/***************************************************************************/
Morten Welinder's avatar
Morten Welinder committed
793 794 795

static char *help_istext = {
	N_("@FUNCTION=ISTEXT\n"
796
	   "@SYNTAX=ISTEXT(value)\n"
Morten Welinder's avatar
Morten Welinder committed
797 798

	   "@DESCRIPTION="
799
	   "ISTEXT returns TRUE if the value is text. "
800
	   "This function is Excel compatible. "
Morten Welinder's avatar
Morten Welinder committed
801
	   "\n"
802 803
	   "@EXAMPLES=\n"
	   "\n"
804
	   "@SEEALSO=ISNONTEXT")
Morten Welinder's avatar
Morten Welinder committed
805 806 807
};

static Value *
808
gnumeric_istext (FunctionEvalInfo *ei, GList *expr_node_list)
Morten Welinder's avatar
Morten Welinder committed
809
{
810
	if (g_list_length (expr_node_list) != 1)
811
		return value_new_error (ei->pos,
812
					_("Invalid number of arguments"));
813

814 815
	return value_new_bool (get_value_class (ei, expr_node_list->data)
			       == VALUE_CLASS_TEXT);
Morten Welinder's avatar
Morten Welinder committed
816 817
}

818
/***************************************************************************/
Morten Welinder's avatar
Morten Welinder committed
819 820 821

static char *help_n = {
	N_("@FUNCTION=N\n"
822
	   "@SYNTAX=N(value)\n"
Morten Welinder's avatar
Morten Welinder committed
823 824

	   "@DESCRIPTION="
825
	   "N returns a value converted to a number.  Strings containing "
826
	   "text are converted to the zero value. "
827
	   "This function is Excel compatible. "
Morten Welinder's avatar
Morten Welinder committed
828
	   "\n"
829 830
	   "@EXAMPLES=\n"
	   "\n"
Morten Welinder's avatar
Morten Welinder committed
831 832 833 834
	   "@SEEALSO=")
};

static Value *
835
gnumeric_n (FunctionEvalInfo *ei, Value **argv)
Morten Welinder's avatar
Morten Welinder committed
836
{
837
	const char *str;
838
	Value *v;
839

840 841 842
	if (argv[0]->type == VALUE_BOOLEAN)
		return value_new_int (value_get_as_int(argv[0]));

843 844 845
	if (VALUE_IS_NUMBER (argv[0]))
		return value_duplicate (argv[0]);

846
	if (argv[0]->type != VALUE_STRING)
847
		return value_new_error (ei->pos, gnumeric_err_NUM);
848

Morten Welinder's avatar
Morten Welinder committed
849
	str = value_peek_string (argv[0]);
850
	if (NULL != (v = format_match (str, NULL, NULL)))
851 852
		return v;
	return value_new_float (0);
Morten Welinder's avatar
Morten Welinder committed
853 854
}

855
/***************************************************************************/
Morten Welinder's avatar
Morten Welinder committed
856 857 858

static char *help_type = {
	N_("@FUNCTION=TYPE\n"
859
	   "@SYNTAX=TYPE(value)\n"
Morten Welinder's avatar
Morten Welinder committed
860 861

	   "@DESCRIPTION="
862
	   "TYPE returns a number indicating the data type of a value. "
863
	   "This function is Excel compatible. "
Morten Welinder's avatar
Morten Welinder committed
864
	   "\n"
865 866
	   "@EXAMPLES=\n"
	   "\n"
Morten Welinder's avatar
Morten Welinder committed
867 868 869 870
	   "@SEEALSO=")
};

static Value *
871
gnumeric_type (FunctionEvalInfo *ei, GList *expr_node_list)
Morten Welinder's avatar
Morten Welinder committed
872
{
873
	if (g_list_length (expr_node_list) != 1)
874
		return value_new_error (ei->pos,
875
					_("Invalid number of arguments"));
876

877
	return value_new_int (get_value_class (ei, expr_node_list->data));