ms-formula-read.c 55.9 KB
Newer Older
1
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
/*
3
 * ms-formula-read.c: MS Excel -> Gnumeric formula conversion
4
 *
5
 * Authors:
6
 *    Jody Goldberg (jody@gnome.org)
7
 *    Michael Meeks (michael@ximian.com)
8
 *
9 10
 * (C) 1998-2001 Michael Meeks
 * (C) 2002-2005 Jody Goldberg
11
 */
12
#include <gnumeric-config.h>
13
#include <glib/gi18n.h>
14
#include <gnumeric.h>
15
#include "ms-formula-read.h"
16 17
#include "excel.h"
#include "ms-biff.h"
18
#include "formula-types.h"
19 20 21 22
#include "boot.h"
#include <gutils.h>
#include <func.h>
#include <value.h>
23
#include <expr-impl.h>
24 25 26 27
#include <expr-name.h>
#include <str.h>
#include <parse-util.h>
#include <sheet.h>
28
#include <workbook.h>
29
#include <gsf/gsf-utils.h>
30

31 32
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "gnumeric:read_expr"
33 34 35 36 37 38 39
/* #define NO_DEBUG_EXCEL */
#ifndef NO_DEBUG_EXCEL
#define d(level, code)	do { if (ms_excel_formula_debug > level) { code } } while (0)
#else
#define d(level, code)
#endif

40
ExcelFuncDesc const excel_func_desc [] = {
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
/* 0 */	  { "COUNT",		 0, 30, XL_STD, 1, 'V', "R" },
/* 1 */	  { "IF",		 2,  3, XL_STD, 3, 'V', "VRR" },
/* 2 */	  { "ISNA",		 1,  1, XL_STD,  1, 'V', "V" },
/* 3 */	  { "ISERROR",		 1,  1, XL_STD,  1, 'V', "V" },
/* 4 */	  { "SUM",		 0, 30, XL_STD, 1, 'V', "R" },
/* 5 */	  { "AVERAGE",		 1, 30, XL_STD, 1, 'V', "R" },
/* 6 */	  { "MIN",		 1, 30, XL_STD, 1, 'V', "R" },
/* 7 */	  { "MAX",		 1, 30, XL_STD, 1, 'V', "R" },
/* 8 */	  { "ROW",		 0,  1, XL_STD, 1, 'V', "R" },
/* 9 */	  { "COLUMN",		 0,  1, XL_STD, 1, 'V', "R" },

/* 10 */  { "NA",		 0,  0, XL_STD,  0, 'V', 0 },
/* 11 */  { "NPV",		 2, 30, XL_STD, 2, 'V', "VR" },
/* 12 */  { "STDEV",		 1, 30, XL_STD, 1, 'V', "R" },
/* 13 */  { "DOLLAR",		 1,  2, XL_STD, 1, 'V', "V" },
/* 14 */  { "FIXED",		 2,  3, XL_STD, 3, 'V', "VVV" }, /*pre biff4 VV and fixed */
/* 15 */  { "SIN",		 1,  1, XL_STD,  1, 'V', "V" },
/* 16 */  { "COS",		 1,  1, XL_STD,  1, 'V', "V" },
/* 17 */  { "TAN",		 1,  1, XL_STD,  1, 'V', "V" },
/* 18 */  { "ATAN",		 1,  1, XL_STD,  1, 'V', "V" },
/* 19 */  { "PI",		 0,  0, XL_STD,  0, 'V', 0 },

/* 20 */  { "SQRT",		 1,  1, XL_STD,  1, 'V', "V" },
/* 21 */  { "EXP",		 1,  1, XL_STD,  1, 'V', "V" },
/* 22 */  { "LN",		 1,  1, XL_STD,  1, 'V', "V" },
/* 23 */  { "LOG10",		 1,  1, XL_STD,  1, 'V', "V" },
/* 24 */  { "ABS",		 1,  1, XL_STD,  1, 'V', "V" },
/* 25 */  { "INT",		 1,  1, XL_STD,  1, 'V', "V" },
/* 26 */  { "SIGN",		 1,  1, XL_STD,  1, 'V', "V" },
/* 27 */  { "ROUND",		 2,  2, XL_STD,  2, 'V', "VV" },
/* 28 */  { "LOOKUP",		 2,  3, XL_STD, 2, 'V', "VR" },
/* 29 */  { "INDEX", 		 2,  4, XL_VOLATILE, 4, 'R', "RVVV" },	/* array form has only 3 */

/* 30 */  { "REPT",		 2,  2, XL_STD,  2, 'V', "VV" },
/* 31 */  { "MID",		 3,  3, XL_STD,  3, 'V', "VVV" },
/* 32 */  { "LEN",		 1,  1, XL_STD,  1, 'V', "V" },
/* 33 */  { "VALUE",		 1,  1, XL_STD,  1, 'V', "V" },
/* 34 */  { "TRUE",		 0,  0, XL_STD,  0, 'V', 0 },
/* 35 */  { "FALSE",		 0,  0, XL_STD,  0, 'V', 0 },
/* 36 */  { "AND",		 1, 30, XL_STD, 1, 'V', "R" },
/* 37 */  { "OR",		 1, 30, XL_STD, 1, 'V', "R" },
/* 38 */  { "NOT",		 1,  1, XL_STD,  1, 'V', "V" },
/* 39 */  { "MOD",		 2,  2, XL_STD,  2, 'V', "VV" },

/* 40 */  { "DCOUNT",		 3,  3, XL_STD,  3, 'V', "RRR" },
/* 41 */  { "DSUM",		 3,  3, XL_STD,  3, 'V', "RRR" },
/* 42 */  { "DAVERAGE",		 3,  3, XL_STD,  3, 'V', "RRR" },
/* 43 */  { "DMIN",		 3,  3, XL_STD,  3, 'V', "RRR" },
/* 44 */  { "DMAX",		 3,  3, XL_STD,  3, 'V', "RRR" },
/* 45 */  { "DSTDEV",		 3,  3, XL_STD,  3, 'V', "RRR" },
/* 46 */  { "VAR",		 1, 30, XL_STD, 1, 'V', "R" },
/* 47 */  { "DVAR",		 3,  3, XL_STD,  3, 'V', "RRR" },
/* 48 */  { "TEXT",		 2,  2, XL_STD,  2, 'V', "VV" },
/* 49 */  { "LINEST",		 1,  4, XL_STD, 4, 'A', "RRVV" },	/*pre biff3 RR */

/* 50 */  { "TREND",		 1,  4, XL_STD, 4, 'A', "RRRV" },	/*pre biff3 RRR */
/* 51 */  { "LOGEST",		 1,  4, XL_STD, 4, 'A', "RRVV" },	/*pre biff3 RR */
/* 52 */  { "GROWTH",		 1,  4, XL_STD, 4, 'A', "RRRV" },	/*pre biff3 RRR */
Jody Goldberg's avatar
Jody Goldberg committed
99 100 101
/* 53 */  { "GOTO",		-1, -1, XL_XLM },
/* 54 */  { "HALT",		-1, -1, XL_XLM },
/* 55 */  { "RETURN",		-1, -1, XL_XLM },
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
/* 56 */  { "PV",		 3,  5, XL_STD, 5, 'V', "VVVVV" },	/* type is optional */
/* 57 */  { "FV",		 3,  5, XL_STD, 5, 'V', "VVVVV" },	/* type is optional */
/* 58 */  { "NPER",		 3,  5, XL_STD, 5, 'V', "VVVVV" },	/* type is optional */
/* 59 */  { "PMT",		 3,  5, XL_STD, 5, 'V', "VVVVV" },	/* type is optional */

/* 60 */  { "RATE",		 3,  6, XL_STD, 6, 'V', "VVVVVV" },	/* guess is optional */
/* 61 */  { "MIRR",		 3,  3, XL_STD,  3, 'V', "RVV" },
/* 62 */  { "IRR",		 1,  2, XL_STD, 2, 'V', "RV" },	/* guess is optional */
/* 63 */  { "RAND", 		 0,  0, XL_VOLATILE,  0, 'V',  0 },
/* 64 */  { "MATCH",		 2,  3, XL_STD, 3, 'V', "VRR" },	/* match_type is optional */
/* 65 */  { "DATE",		 3,  3, XL_STD,  3, 'V', "VVV" },
/* 66 */  { "TIME",		 3,  3, XL_STD,  3, 'V', "VVV" },
/* 67 */  { "DAY",		 1,  1, XL_STD,  1, 'V', "V" },
/* 68 */  { "MONTH",		 1,  1, XL_STD,  1, 'V', "V" },
/* 69 */  { "YEAR",		 1,  1, XL_STD,  1, 'V', "V" },

/* 70 */  { "WEEKDAY",		 1,  2, XL_STD, 2, 'V', "VV" }, /* Return type added in biff5/7 */
/* 71 */  { "HOUR",		 1,  1, XL_STD,  1, 'V', "V" },
/* 72 */  { "MINUTE",		 1,  1, XL_STD,  1, 'V', "V" },
/* 73 */  { "SECOND",		 1,  1, XL_STD,  1, 'V', "V" },
/* 74 */  { "NOW",  		 0,  0, XL_VOLATILE,  0, 'V',  0 },
/* 75 */  { "AREAS",		 1,  1, XL_STD,  1, 'V', "R" },
/* 76 */  { "ROWS",		 1,  1, XL_STD,  1, 'V', "R" },
/* 77 */  { "COLUMNS",		 1,  1, XL_STD,  1, 'V', "R" },
/* 78 */  { "OFFSET",		 3,  5, XL_STD, 5, 'R', "RVVVV" },
Jody Goldberg's avatar
Jody Goldberg committed
127 128 129 130
/* 79 */  { "ABSREF",		-1, -1, XL_XLM,	   2 },

/* 80 */  { "RELREF",		-1, -1, XL_XLM },
/* 81 */  { "ARGUMENT",		-1, -1, XL_XLM },
131 132
/* 82 */  { "SEARCH",		 2,  3, XL_STD, 3, 'V', "VVV" },	/* Start_num is optional */
/* 83 */  { "TRANSPOSE",	 1,  1, XL_STD,  1, 'A', "A" },
Jody Goldberg's avatar
Jody Goldberg committed
133 134
/* 84 */  { "ERROR",		-1, -1, XL_XLM },
/* 85 */  { "STEP",		-1, -1, XL_XLM },
135
/* 86 */  { "TYPE",		 1,  1, XL_STD,  1, 'V', "V" },
Jody Goldberg's avatar
Jody Goldberg committed
136 137 138 139 140 141
/* 87 */  { "ECHO",		-1, -1, XL_XLM },
/* 88 */  { "SETNAME",		-1, -1, XL_XLM },
/* 89 */  { "CALLER",		-1, -1, XL_XLM },

/* 90 */  { "DEREF",		-1, -1, XL_XLM },
/* 91 */  { "WINDOWS",		-1, -1, XL_XLM },
142
/* 92 */  { "SERIESSUM",	 4,  4, XL_STD,  4, 'V', "VVVA" },	/* Renamed from SERIES */
Jody Goldberg's avatar
Jody Goldberg committed
143 144 145 146
/* 93 */  { "DOCUMENTS",	-1, -1, XL_XLM },
/* 94 */  { "ACTIVE.CELL",	-1, -1, XL_XLM },
/* 95 */  { "SELECTION",	-1, -1, XL_XLM },
/* 96 */  { "RESULT",		-1, -1, XL_XLM },
147 148 149
/* 97 */  { "ATAN2",		 2,  2, XL_STD,  2, 'V', "VV" },
/* 98 */  { "ASIN",		 1,  1, XL_STD,  1, 'V', "V" },
/* 99 */  { "ACOS",		 1,  1, XL_STD,  1, 'V', "V" },
Jody Goldberg's avatar
Jody Goldberg committed
150

151 152 153
/* 100 */ { "CHOOSE",		 2, 30, XL_STD, 2, 'V', "VR" },
/* 101 */ { "HLOOKUP",		 3,  4, XL_STD, 4, 'V', "VRRV" },	/* pre biff5/7 it was VRR */
/* 102 */ { "VLOOKUP",		 3,  4, XL_STD, 4, 'V', "VRRV" },	/* pre biff5/7 it was VRR */
Jody Goldberg's avatar
Jody Goldberg committed
154 155
/* 103 */ { "LINKS",		-1, -1, XL_XLM },
/* 104 */ { "INPUT",		-1, -1, XL_XLM },
156
/* 105 */ { "ISREF",		 1,  1, XL_STD,  1, 'V', "R" },	/* This a guess */
Jody Goldberg's avatar
Jody Goldberg committed
157 158 159
/* 106 */ { "GET.FORMULA",	-1, -1, XL_XLM },
/* 107 */ { "GET.NAME",		-1, -1, XL_XLM },
/* 108 */ { "SET.VALUE",	-1, -1, XL_XLM },
160
/* 109 */ { "LOG",		 1,  2, XL_STD, 2, 'V', "VV" },	/* Base is optional */
Jody Goldberg's avatar
Jody Goldberg committed
161 162

/* 110 */ { "EXEC",		-1, -1, XL_XLM },
163 164 165 166 167 168 169 170 171 172 173 174
/* 111 */ { "CHAR",		 1,  1, XL_STD,  1, 'V', "V" },
/* 112 */ { "LOWER",		 1,  1, XL_STD,  1, 'V', "V" },
/* 113 */ { "UPPER",		 1,  1, XL_STD,  1, 'V', "V" },
/* 114 */ { "PROPER",		 1,  1, XL_STD,  1, 'V', "V" },
/* 115 */ { "LEFT",		 1,  2, XL_STD, 2, 'V', "VV" },    /* Num_chars is optional */
/* 116 */ { "RIGHT",		 1,  2, XL_STD, 2, 'V', "VV" },    /* Num_chars is optional */
/* 117 */ { "EXACT",		 2,  2, XL_STD,  2, 'V', "VV" },
/* 118 */ { "TRIM",		 1,  1, XL_STD,  1, 'V', "V" },
/* 119 */ { "REPLACE",		 4,  4, XL_STD,  4, 'V', "VVVV" },

/* 120 */ { "SUBSTITUTE",	 3,  4, XL_STD, 4, 'V', "VVVV" },    /* Instance num is optional */
/* 121 */ { "CODE",		 1,  1, XL_STD,  1, 'V', "V" },
Jody Goldberg's avatar
Jody Goldberg committed
175 176
/* 122 */ { "NAMES",		-1, -1, XL_XLM },
/* 123 */ { "DIRECTORY",	-1, -1, XL_XLM },
177 178 179 180 181 182 183 184 185
/* 124 */ { "FIND",		 2,  3, XL_STD, 3, 'V', "VVV" },/* start_num is optional */
/* 125 */ { "CELL",		 1,  2, XL_VOLATILE, 2, 'V', "VR" },
/* 126 */ { "ISERR",		 1,  1, XL_STD,  1, 'V', "V" },
/* 127 */ { "ISTEXT",		 1,  1, XL_STD,  1, 'V', "V" },
/* 128 */ { "ISNUMBER",		 1,  1, XL_STD,  1, 'V', "V" },
/* 129 */ { "ISBLANK",		 1,  1, XL_STD,  1, 'V', "V" },

/* 130 */ { "T",		 1,  1, XL_STD,  1, 'V', "R" },
/* 131 */ { "N",		 1,  1, XL_STD,  1, 'V', "R" },
Jody Goldberg's avatar
Jody Goldberg committed
186 187 188 189 190 191 192 193 194
/* 132 */ { "FOPEN",		-1, -1, XL_XLM },
/* 133 */ { "FCLOSE",		-1, -1, XL_XLM },
/* 134 */ { "FSIZE",		-1, -1, XL_XLM },
/* 135 */ { "FREADLN",		-1, -1, XL_XLM },
/* 136 */ { "FREAD",		-1, -1, XL_XLM },
/* 137 */ { "FWRITELN",		-1, -1, XL_XLM },
/* 138 */ { "FWRITE",		-1, -1, XL_XLM },
/* 139 */ { "FPOS",		-1, -1, XL_XLM },

195 196 197 198 199
/* 140 */ { "DATEVALUE",	 1,  1, XL_STD,  1, 'V', "V" },
/* 141 */ { "TIMEVALUE",	 1,  1, XL_STD,  1, 'V', "V" },
/* 142 */ { "SLN",		 3,  3, XL_STD,  3, 'V', "VVV" },
/* 143 */ { "SYD",		 4,  4, XL_STD,  4, 'V', "VVVV" },
/* 144 */ { "DDB",		 4,  5, XL_STD, 5, 'V', "VVVVV" },	/* Factor is optional */
Jody Goldberg's avatar
Jody Goldberg committed
200 201 202
/* 145 */ { "GET.DEF",		-1, -1, XL_XLM },
/* 146 */ { "REFTEXT",		-1, -1, XL_XLM },
/* 147 */ { "TEXTREF",		-1, -1, XL_XLM },
203
/* 148 */ { "INDIRECT", 	 1,  2, XL_VOLATILE, 2, 'R', "VV" },	/* ai is optional */
Jody Goldberg's avatar
Jody Goldberg committed
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
/* 149 */ { "REGISTER",		-1, -1, XL_XLM },

/* 150 */ { "CALL",		-1, -1, XL_XLM },
/* 151 */ { "ADD.BAR",		-1, -1, XL_XLM },
/* 152 */ { "ADD.MENU",		-1, -1, XL_XLM },
/* 153 */ { "ADD.COMMAND",	-1, -1, XL_XLM },
/* 154 */ { "ENABLE.COMMAND",	-1, -1, XL_XLM },
/* 155 */ { "CHECK.COMMAND",	-1, -1, XL_XLM },
/* 156 */ { "RENAME.COMMAND",	-1, -1, XL_XLM },
/* 157 */ { "SHOW.BAR",		-1, -1, XL_XLM },
/* 158 */ { "DELETE.MENU",	-1, -1, XL_XLM },
/* 159 */ { "DELETE.COMMAND",	-1, -1, XL_XLM },

/* 160 */ { "GET.CHART.ITEM",	-1, -1, XL_XLM },
/* 161 */ { "DIALOG.BOX",	-1, -1, XL_XLM },
219 220 221 222
/* 162 */ { "CLEAN",		 1,  1, XL_STD,  1, 'V', "V" },
/* 163 */ { "MDETERM",		 1,  1, XL_STD,  1, 'V', "A" },
/* 164 */ { "MINVERSE",		 1,  1, XL_STD,  1, 'A', "A" },
/* 165 */ { "MMULT",		 2,  2, XL_STD,  2, 'A', "AA" },
Jody Goldberg's avatar
Jody Goldberg committed
223
/* 166 */ { "FILES",		-1, -1, XL_XLM },
224 225 226
/* 167 */ { "IPMT",		 4,  6, XL_STD, 6, 'V', "VVVVVV" },	/* Type is optional */
/* 168 */ { "PPMT",		 4,  6, XL_STD, 6, 'V', "VVVVVV" },
/* 169 */ { "COUNTA",		 0, 30, XL_STD, 1, 'V', "R" },
Jody Goldberg's avatar
Jody Goldberg committed
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241

/* 170 */ { "CANCELKEY", 	-1, -1, XL_XLM },
/* 171 */ { "FOR",		-1, -1, XL_XLM },
/* 172 */ { "WHILE",		-1, -1, XL_XLM },
/* 173 */ { "BREAK",		-1, -1, XL_XLM },
/* 174 */ { "NEXT",		-1, -1, XL_XLM },
/* 175 */ { "INITIATE",		-1, -1, XL_XLM },
/* 176 */ { "REQUEST",		-1, -1, XL_XLM },
/* 177 */ { "POKE",		-1, -1, XL_XLM },
/* 178 */ { "EXECUTE",		-1, -1, XL_XLM },
/* 179 */ { "TERMINATE",	-1, -1, XL_XLM },

/* 180 */ { "RESTART",		-1, -1, XL_XLM },
/* 181 */ { "HELP",		-1, -1, XL_XLM },
/* 182 */ { "GET.BAR",		-1, -1, XL_XLM },
242 243
/* 183 */ { "PRODUCT",		 0, 30, XL_STD, 1, 'V', "R" },
/* 184 */ { "FACT",		 1,  1, XL_STD,  1, 'V', "V" },
Jody Goldberg's avatar
Jody Goldberg committed
244 245 246 247
/* 185 */ { "GET.CELL",		-1, -1, XL_XLM },
/* 186 */ { "GET.WORKSPACE",	-1, -1, XL_XLM },
/* 187 */ { "GET.WINDOW",	-1, -1, XL_XLM },
/* 188 */ { "GET.DOCUMENT",	-1, -1, XL_XLM },
248
/* 189 */ { "DPRODUCT",		 3,  3, XL_STD,  3, 'V', "RRR" },
Jody Goldberg's avatar
Jody Goldberg committed
249

250
/* 190 */ { "ISNONTEXT",	 1,  1, XL_STD,  1, 'V', "V" },
Jody Goldberg's avatar
Jody Goldberg committed
251 252
/* 191 */ { "GET.NOTE",		-1, -1, XL_XLM },
/* 192 */ { "NOTE",		-1, -1, XL_XLM },
253 254 255 256 257 258 259
/* 193 */ { "STDEVP",		 1, 30, XL_STD, 1, 'V', "R" },
/* 194 */ { "VARP",		 1, 30, XL_STD, 1, 'V', "R" },
/* 195 */ { "DSTDEVP",		 3,  3, XL_STD,  3, 'V', "RRR" },
/* 196 */ { "DVARP",		 3,  3, XL_STD,  3, 'V', "RRR" },
/* 197 */ { "TRUNC",		 1,  2, XL_STD, 2, 'V', "VV" },      /* pre-biff3 it was 'V' */
/* 198 */ { "ISLOGICAL",	 1,  1, XL_STD,  1, 'V', "V" },
/* 199 */ { "DCOUNTA",		 3,  3, XL_STD,  3, 'V', "RRR" },
Jody Goldberg's avatar
Jody Goldberg committed
260 261 262 263 264

/* 200 */ { "DELETE.BAR",	-1, -1, XL_XLM },
/* 201 */ { "UNREGISTER",	-1, -1, XL_XLM },
/* 202 */ { "EXCELFUNC202",	-1, -1, XL_UNKNOWN },
/* 203 */ { "EXCELFUNC203",	-1, -1, XL_UNKNOWN },
265 266 267 268 269 270 271 272 273 274 275 276 277 278
/* 204 */ { "USDOLLAR",		 1,  2, XL_STD, 2, 'V', "VV" },
/* 205 */ { "FINDB",		 2,  3, XL_STD, 3, 'V', "VVV" },	/* start_num is optional */
/* 206 */ { "SEARCHB",		 2,  3, XL_STD, 3, 'V', "VVV" },	/* Start_num is optional */
/* 207 */ { "REPLACEB",		 4,  4, XL_STD,  4, 'V', "VVVV" },
/* 208 */ { "LEFTB",		 1,  2, XL_STD, 2, 'V', "VV" },	/* Num_chars is optional */
/* 209 */ { "RIGHTB",		 1,  2, XL_STD, 2, 'V', "VV" },	/* Num_chars is optional */

/* 210 */ { "MIDB",		 3,  3, XL_STD,  3, 'V', "VVV" },
/* 211 */ { "LENB",		 1,  1, XL_STD,  1, 'V', "V" },
/* 212 */ { "ROUNDUP",		 2,  2, XL_STD,  2, 'V', "VV" },
/* 213 */ { "ROUNDDOWN",	 2,  2, XL_STD,  2, 'V', "VV" },
/* 214 */ { "ASC",		 1,  1, XL_STD,  1, 'V', "V" },
/* 215 */ { "DBCS",		 1,  1, XL_STD,  1, 'V', "V" },
/* 216 */ { "RANK",		 2,  3, XL_STD, 3, 'V', "VRV" },	/* OOo claims added in biff4 */
Jody Goldberg's avatar
Jody Goldberg committed
279 280 281 282
/* 217 */ { "EXCELFUNC217",	-1, -1, XL_UNKNOWN },
/* 218 */ { "EXCELFUNC218",	-1, -1, XL_UNKNOWN },

/* added in biff3 */
283
/* 219 */ { "ADDRESS",		 2,  5, XL_STD, 5, 'V', "VVVVV" },
Jody Goldberg's avatar
Jody Goldberg committed
284

285 286 287
/* 220 */ { "DAYS360",		 2,  3, XL_STD, 3, 'V', "VVV" },	/* pre-biff5/7 VV */
/* 221 */ { "TODAY", 		 0,  0, XL_VOLATILE,  0, 'V', 0 },
/* 222 */ { "VDB",		 5,  7, XL_STD, 7, 'V', "VVVVVVV" },
Jody Goldberg's avatar
Jody Goldberg committed
288 289 290 291
/* 223 */ { "ELSE",		-1, -1, XL_XLM },
/* 224 */ { "ELSE.IF",		-1, -1, XL_XLM },
/* 225 */ { "END.IF",		-1, -1, XL_XLM },
/* 226 */ { "FOR.CELL",		-1, -1, XL_XLM },
292 293 294 295 296 297 298 299 300 301
/* 227 */ { "MEDIAN",		 1, 30, XL_STD, 1, 'V', "R" },
/* 228 */ { "SUMPRODUCT",	 1, 30, XL_STD, 1, 'V', "A" },
/* 229 */ { "SINH",		 1,  1, XL_STD,  1, 'V', "V" },

/* 230 */ { "COSH",		 1,  1, XL_STD,  1, 'V', "V" },
/* 231 */ { "TANH",		 1,  1, XL_STD,  1, 'V', "V" },
/* 232 */ { "ASINH",		 1,  1, XL_STD,  1, 'V', "V" },
/* 233 */ { "ACOSH",		 1,  1, XL_STD,  1, 'V', "V" },
/* 234 */ { "ATANH",		 1,  1, XL_STD,  1, 'V', "V" },
/* 235 */ { "DGET",		 3,  3, XL_STD,  3, 'V', "RRR" },
Jody Goldberg's avatar
Jody Goldberg committed
302 303 304 305 306 307 308 309 310
/* 236 */ { "CREATE.OBJECT",	-1, -1, XL_XLM },
/* 237 */ { "VOLATILE", 	-1, -1, XL_XLM },
/* 238 */ { "LAST.ERROR", 	-1, -1, XL_XLM },
/* 239 */ { "CUSTOM.UNDO",	-1, -1, XL_XLM },

/* 240 */ { "CUSTOM.REPEAT",	-1, -1, XL_XLM },
/* 241 */ { "FORMULA.CONVERT",	-1, -1, XL_XLM },
/* 242 */ { "GET.LINK.INFO",	-1, -1, XL_XLM },
/* 243 */ { "TEXT.BOX", 	-1, -1, XL_XLM },
311
/* 244 */ { "INFO",		 1,  1, XL_STD, 1, 'V', "V" },
Jody Goldberg's avatar
Jody Goldberg committed
312 313 314 315
/* 245 */ { "GROUP",		-1, -1, XL_XLM },
/* 246 */ { "GET.OBJECT",	-1, -1, XL_XLM },

/* added in biff4 */
316
/* 247 */ { "DB",		 4,  5, XL_STD, 5, 'V',"VVVVV" },	/* month is optional */
Jody Goldberg's avatar
Jody Goldberg committed
317 318 319 320 321
/* 248 */ { "PAUSE",		-1, -1, XL_XLM },
/* 249 */ { "EXCELFUNC249",	-1, -1, XL_UNKNOWN },

/* 250 */ { "EXCELFUNC250",	-1, -1, XL_UNKNOWN },
/* 251 */ { "RESUME",		-1, -1, XL_XLM },
322
/* 252 */ { "FREQUENCY",	 2,  2, XL_STD,  2, 'A',"RR" },
Jody Goldberg's avatar
Jody Goldberg committed
323 324 325 326 327 328 329 330 331
/* 253 */ { "ADD.TOOLBAR",	-1, -1, XL_XLM },
/* 254 */ { "DELETE.TOOLBAR",	-1, -1, XL_XLM },
/* 255 */ { "extension slot",	-1, -1, XL_MAGIC },
/* 256 */ { "RESET.TOOLBAR",	-1, -1, XL_XLM },
/* 257 */ { "EVALUATE", 	-1, -1, XL_XLM },
/* 258 */ { "GET.TOOLBAR",	-1, -1, XL_XLM },
/* 259 */ { "GET.TOOL",		-1, -1, XL_XLM },

/* 260 */ { "SPELLING.CHECK",	-1, -1, XL_XLM },
332
/* 261 */ { "ERROR.TYPE",	 1,  1, XL_STD,  1, 'V', "V" },
Jody Goldberg's avatar
Jody Goldberg committed
333 334 335 336 337 338 339
/* 262 */ { "APP.TITLE",	-1, -1, XL_XLM },
/* 263 */ { "WINDOW.TITLE",	-1, -1, XL_XLM },
/* 264 */ { "SAVE.TOOLBAR",	-1, -1, XL_XLM },
/* 265 */ { "ENABLE.TOOL",	-1, -1, XL_XLM },
/* 266 */ { "PRESS.TOOL",	-1, -1, XL_XLM },
/* 267 */ { "REGISTER.ID", 	-1, -1, XL_XLM },
/* 268 */ { "GET.WORKBOOK",	-1, -1, XL_XLM },
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
/* 269 */ { "AVEDEV",		 1, 30, XL_STD, 1, 'V', "R" },

/* 270 */ { "BETADIST",		 3,  5, XL_STD, 1, 'V', "V" },
/* 271 */ { "GAMMALN",		 1,  1, XL_STD,  1, 'V', "V" },
/* 272 */ { "BETAINV",		 3,  5, XL_STD, 1, 'V', "V" },
/* 273 */ { "BINOMDIST",	 4,  4, XL_STD,  4, 'V', "VVVV" },
/* 274 */ { "CHIDIST",		 2,  2, XL_STD,  2, 'V', "VV" },
/* 275 */ { "CHIINV",		 2,  2, XL_STD,  2, 'V', "VV" },
/* 276 */ { "COMBIN",		 2,  2, XL_STD,  2, 'V', "VV" },
/* 277 */ { "CONFIDENCE",	 3,  3, XL_STD,  3, 'V', "VVV" },
/* 278 */ { "CRITBINOM",	 3,  3, XL_STD,  3, 'V', "VVV" },
/* 279 */ { "EVEN",		 1,  1, XL_STD,  1, 'V', "V" },

/* 280 */ { "EXPONDIST",	 3,  3, XL_STD,  3, 'V', "VVV" },
/* 281 */ { "FDIST",		 3,  3, XL_STD,  3, 'V', "VVV" },
/* 282 */ { "FINV",		 3,  3, XL_STD,  3, 'V', "VVV" },
/* 283 */ { "FISHER",		 1,  1, XL_STD,  1, 'V', "V" },
/* 284 */ { "FISHERINV",	 1,  1, XL_STD,  1, 'V', "V" },
/* 285 */ { "FLOOR",		 2,  2, XL_STD,  2, 'V', "VV" },
/* 286 */ { "GAMMADIST",	 4,  4, XL_STD,  4, 'V', "VVVV" },
/* 287 */ { "GAMMAINV",		 3,  3, XL_STD,  3, 'V', "VVV" },
/* 288 */ { "CEILING",		 2,  2, XL_STD,  2, 'V', "VV" },
/* 289 */ { "HYPGEOMDIST",	 4,  4, XL_STD,  4, 'V', "VVVV" },

/* 290 */ { "LOGNORMDIST",	 3,  3, XL_STD,  3, 'V', "VVV" },
/* 291 */ { "LOGINV",		 3,  3, XL_STD,  3, 'V', "VVV" },
/* 292 */ { "NEGBINOMDIST",	 3,  3, XL_STD,  3, 'V', "VVV" },
/* 293 */ { "NORMDIST",		 4,  4, XL_STD,  4, 'V', "VVVV" },
/* 294 */ { "NORMSDIST",	 1,  1, XL_STD,  1, 'V', "V" },
/* 295 */ { "NORMINV",		 3,  3, XL_STD,  3, 'V', "VVV" },
/* 296 */ { "NORMSINV",		 1,  1, XL_STD,  1, 'V', "V" },
/* 297 */ { "STANDARDIZE",	 3,  3, XL_STD,  3, 'V', "VVV" },
/* 298 */ { "ODD",		 1,  1, XL_STD,  1, 'V', "V" },
/* 299 */ { "PERMUT",		 2,  2, XL_STD,  2, 'V', "VV" },

/* 300 */ { "POISSON",		 3,  3, XL_STD,  3, 'V', "VVV" },
/* 301 */ { "TDIST",		 3,  3, XL_STD,  3, 'V', "VVV" },
/* 302 */ { "WEIBULL",		 4,  4, XL_STD,  4, 'V', "VVVV" },
/* 303 */ { "SUMXMY2",		 2,  2, XL_STD,  2, 'V', "AA" },
/* 304 */ { "SUMX2MY2",		 2,  2, XL_STD,  2, 'V', "AA" },
/* 305 */ { "SUMX2PY2",		 2,  2, XL_STD,  2, 'V', "AA" },
/* 306 */ { "CHITEST",		 2,  2, XL_STD,  2, 'V', "AA" },
/* 307 */ { "CORREL",		 2,  2, XL_STD,  2, 'V', "AA" },
/* 308 */ { "COVAR",		 2,  2, XL_STD,  2, 'V', "AA" },
/* 309 */ { "FORECAST",		 3,  3, XL_STD,  3, 'V', "VAA" },
Jody Goldberg's avatar
Jody Goldberg committed
385
                                      
386 387 388 389 390 391 392 393 394 395
/* 310 */ { "FTEST",		 2,  2, XL_STD,  2, 'V', "AA" },
/* 311 */ { "INTERCEPT",	 2,  2, XL_STD,  2, 'V', "AA" },
/* 312 */ { "PEARSON",		 2,  2, XL_STD,  2, 'V', "AA" },
/* 313 */ { "RSQ",		 2,  2, XL_STD,  2, 'V', "AA" },
/* 314 */ { "STEYX",		 2,  2, XL_STD,  2, 'V', "AA" },
/* 315 */ { "SLOPE",		 2,  2, XL_STD,  2, 'V', "AA" },
/* 316 */ { "TTEST",		 4,  4, XL_STD,  4, 'V', "AAVV" },
/* 317 */ { "PROB",		 3,  4, XL_STD, 3, 'V', "AAV" },	/* upper_limit is optional */
/* 318 */ { "DEVSQ",		 1, 30, XL_STD, 1, 'V', "R" },
/* 319 */ { "GEOMEAN",		 1, 30, XL_STD, 1, 'V', "R" },
Jody Goldberg's avatar
Jody Goldberg committed
396
                                      
397 398 399 400 401 402 403 404 405 406 407 408 409 410
/* 320 */ { "HARMEAN",		 1, 30, XL_STD, 1, 'V', "R" },
/* 321 */ { "SUMSQ",		 0, 30, XL_STD, 1, 'V', "R" },
/* 322 */ { "KURT",		 1, 30, XL_STD, 1, 'V', "R" },
/* 323 */ { "SKEW",		 1, 30, XL_STD, 1, 'V', "R" },
/* 324 */ { "ZTEST",		 2,  3, XL_STD, 2, 'V', "RV" },	/* sigma is optional */
/* 325 */ { "LARGE",		 2,  2, XL_STD,  2, 'V', "RV" },
/* 326 */ { "SMALL",		 2,  2, XL_STD,  2, 'V', "RV" },
/* 327 */ { "QUARTILE",		 2,  2, XL_STD,  2, 'V', "RV" },
/* 328 */ { "PERCENTILE",	 2,  2, XL_STD,  2, 'V', "RV" },
/* 329 */ { "PERCENTRANK",	 2,  3, XL_STD, 2, 'V', "RV" },	/* Significance is optional */

/* 330 */ { "MODE",		 1, 30, XL_STD, 1, 'V', "A" },
/* 331 */ { "TRIMMEAN",		 2,  2, XL_STD,  2, 'V', "RV" },
/* 332 */ { "TINV",		 2,  2, XL_STD,  2, 'V', "VV" },
Jody Goldberg's avatar
Jody Goldberg committed
411 412 413 414 415
/* 333 */ { "EXCELFUNC333",	-1, -1, XL_UNKNOWN },
/* 334 */ { "MOVIE.COMMAND",	-1, -1, XL_XLM },
/* 335 */ { "GET.MOVIE",	-1, -1, XL_XLM },

/* Added in biff5/7 */
416 417
/* 336 */ { "CONCATENATE",	 0, 30, XL_STD, 1, 'V', "V" },
/* 337 */ { "POWER",		 2,  2, XL_STD,  2, 'V', "VV" },
Jody Goldberg's avatar
Jody Goldberg committed
418 419 420 421 422
/* 338 */ { "PIVOT.ADD.DATA",	-1, -1, XL_XLM },
/* 339 */ { "GET.PIVOT.TABLE",	-1, -1, XL_XLM },

/* 340 */ { "GET.PIVOT.FIELD",	-1, -1, XL_XLM },
/* 341 */ { "GET.PIVOT.ITEM",	-1, -1, XL_XLM },
423 424 425 426 427 428
/* 342 */ { "RADIANS",		 1,  1, XL_STD,  1, 'V', "V" },
/* 343 */ { "DEGREES",		 1,  1, XL_STD,  1, 'V', "V" },
/* 344 */ { "SUBTOTAL",		 2, 30, XL_STD, 2, 'V', "VR" },
/* 345 */ { "SUMIF",		 2,  3, XL_STD, 3, 'V', "RVR" },	/* Actual range is optional */
/* 346 */ { "COUNTIF",		 2,  2, XL_STD,  2, 'V', "RV" },
/* 347 */ { "COUNTBLANK",	 1,  1, XL_STD,  1, 'V', "R" },
Jody Goldberg's avatar
Jody Goldberg committed
429 430 431
/* 348 */ { "SCENARIO.GET",	-1, -1, XL_XLM },
/* 349 */ { "OPTIONS.LISTS.GET",-1, -1, XL_XLM },

432 433 434 435 436
/* 350 */ { "ISPMT",		 4,  4, XL_STD,  4, 'V', "VVVV" },
/* 351 */ { "DATEDIF",		 3,  3, XL_STD,  3, 'V', "VVV" },
/* 352 */ { "DATESTRING",	 1,  1, XL_STD,  1, 'V', "V" },
/* 353 */ { "NUMBERSTRING",	 2,  2, XL_STD,  2, 'V', "VV" },
/* 354 */ { "ROMAN",		 1,  2, XL_STD, 2, 'V', "VV" },
Jody Goldberg's avatar
Jody Goldberg committed
437 438 439 440
/* 355 */ { "OPEN.DIALOG",	-1, -1, XL_XLM },
/* 356 */ { "SAVE.DIALOG",	-1, -1, XL_XLM },
/* 357 */ { "VIEW.GET",		-1, -1, XL_XLM },

441 442
/* 358 */ { "GETPIVOTDATA",	 2, 30, XL_STD, 2, 'V', "RVV" },	/* changed in biff8 */

Jody Goldberg's avatar
Jody Goldberg committed
443
/* Added in Biff8 */
444 445 446 447 448 449 450 451 452 453
/* 359 */ { "HYPERLINK",	 1,  2, XL_STD, 2, 'V', "VV" },	/* cell_contents is optional */

/* 360 */ { "PHONETIC",		 1,  1, XL_STD,  1, 'V', "V" },
/* 361 */ { "AVERAGEA",		 1, 30, XL_STD, 1, 'V', "R" },
/* 362 */ { "MAXA",		 1, 30, XL_STD, 1, 'V', "R" },
/* 363 */ { "MINA",		 1, 30, XL_STD, 1, 'V', "R" },
/* 364 */ { "STDEVPA",		 1, 30, XL_STD, 1, 'V', "R" },
/* 365 */ { "VARPA",		 1, 30, XL_STD, 1, 'V', "R" },
/* 366 */ { "STDEVA",		 1, 30, XL_STD, 1, 'V', "R" },
/* 367 */ { "VARA",		 1, 30, XL_STD, 1, 'V', "R" },
Jody Goldberg's avatar
Jody Goldberg committed
454 455

/* New in XP ? imports strangely */
456 457 458 459 460 461 462 463 464 465 466 467 468 469
/* 368 */ { "BAHTTEXT",		 1,  1, XL_STD, 1, 'V', "V" },
/* 369 */ { "THAIDAYOFWEEK",	 1,  1, XL_STD, 1, 'V', "V" },

/* 370 */ { "THAIDIGIT",	 1,  1, XL_STD, 1, 'V', "V" },
/* 371 */ { "THAIMONTHOFYEAR",	 1,  1, XL_STD, 1, 'V', "V" },
/* 372 */ { "THAINUMSOUND",	 1,  1, XL_STD, 1, 'V', "V" },
/* 373 */ { "THAINUMSTRING",	 1,  1, XL_STD, 1, 'V', "V" },
/* 374 */ { "THAISTRINGLENGTH",	 1,  1, XL_STD, 1, 'V', "V" },
/* 375 */ { "ISTHAIDIGIT",	 1,  1, XL_STD, 1, 'V', "V" },
/* 376 */ { "ROUNDBAHTDOWN",	 1,  1, XL_STD, 1, 'V', "V" },
/* 377 */ { "ROUNDBAHTUP",	 1,  1, XL_STD, 1, 'V', "V" },
/* 378 */ { "THAIYEAR",		 1,  1, XL_STD, 1, 'V', "V" },
/* 379 */ { "RTD",		 2,  5, XL_STD, 1, 'V', "V" },
/* 380 */ { "ISHYPERLINK",       1,  1, XL_STD, 1, 'V', "V" }
470 471 472 473
};

int excel_func_desc_size = G_N_ELEMENTS (excel_func_desc);

474
static GnmExpr const *
475 476
xl_expr_err (ExcelReadSheet const *esheet, int col, int row,
	     char const *msg, char const *str)
477
{
478
	if (esheet != NULL && esheet->sheet != NULL) {
479
		g_warning ("%s!%s : %s",
480
			   esheet->sheet->name_unquoted,
481 482 483 484 485 486 487 488 489
			   cell_coord_name (col, row), msg);
	} else if (col >= 0 && row >= 0) {
		g_warning ("%s : %s", cell_coord_name (col, row), msg);
	} else {
		g_warning ("%s", msg);
	}

	return gnm_expr_new_constant (value_new_error (NULL, str));
}
490

491 492 493 494
/**
 *  A useful routine for extracting data from a common
 * storage structure.
 **/
495
static void
Jody Goldberg's avatar
Jody Goldberg committed
496
getRefV7 (GnmCellRef *cr,
497
	  guint8 col, guint16 gbitrw, int curcol, int currow,
498
	  gboolean const shared)
499
{
500
	guint16 const row = (guint16)(gbitrw & 0x3fff);
501

502
	d (2, fprintf (stderr, "7In : 0x%x, 0x%x  at %s%s\n", col, gbitrw,
503
		      cell_coord_name (curcol, currow), (shared?" (shared)":"")););
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532

	cr->sheet = NULL;

	cr->row_relative = (gbitrw & 0x8000) != 0;
	if (cr->row_relative) {
		if (shared) {
			/* ICK ! XL is storing signed numbers without storing
			 * the sign bit.  we need to assume that if the 13th
			 * bit is set it is meant to be negative.  then we
			 * reinstate the sign bit and allow compiler to handle
			 * sign extension.
			 */
			if (row & 0x2000)
				cr->row = (gint16)(row | 0xc000);
			else
				cr->row = row;
		} else
			cr->row = row - currow;
	} else
		cr->row = row;

	cr->col_relative = (gbitrw & 0x4000) != 0;
	if (cr->col_relative) {
		if (shared)
			cr->col = (gint8)col;
		else
			cr->col = col - curcol;
	} else
		cr->col = col;
533
}
534

535 536 537 538
/**
 *  A useful routine for extracting data from a common
 * storage structure.
 **/
539
static void
Jody Goldberg's avatar
Jody Goldberg committed
540
getRefV8 (GnmCellRef *cr,
541
	  guint16 row, guint16 gbitcl, int curcol, int currow,
542
	  gboolean const shared)
543
{
544 545
	guint8 const col = (guint8)(gbitcl & 0xff);

546
	d (2, fprintf (stderr, "8In : 0x%x, 0x%x  at %s%s\n", row, gbitcl,
547
		      cell_coord_name (curcol, currow), (shared?" (shared)":"")););
548

549
	cr->sheet = NULL;
550

551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
	cr->row_relative = (gbitcl & 0x8000) != 0;
	if (cr->row_relative) {
		if (shared)
			cr->row = (gint16)row;
		else
			cr->row = row - currow;
	} else
		cr->row = row;

	cr->col_relative = (gbitcl & 0x4000) != 0;
	if (cr->col_relative) {
		if (shared)
			cr->col = (gint8)col;
		else
			cr->col = col - curcol;
	} else
		cr->col = col;
568 569
}

570
static void
571
parse_list_push (GnmExprList **list, GnmExpr const *pd)
572
{
573 574 575
	d (5, fprintf (stderr, "Push 0x%p\n", pd););
	if (pd == NULL) {
		g_warning ("FIXME: Pushing nothing onto excel function stack");
576
		pd = xl_expr_err (NULL, -1, -1,
577
			"Incorrect number of parsed formula arguments",
578
			"#WrongArgs!");
579
	}
580
	*list = gnm_expr_list_prepend (*list, pd);
581
}
582

583
static void
Jody Goldberg's avatar
Jody Goldberg committed
584
parse_list_push_raw (GnmExprList **list, GnmValue *v)
585
{
586
	parse_list_push (list, gnm_expr_new_constant (v));
587 588
}

589 590
static GnmExpr const *
parse_list_pop (GnmExprList **list)
591
{
592
	/* Get the head */
593 594
	GnmExprList *tmp = *list;
	if (tmp != NULL) {
595
		GnmExpr const *ans = tmp->data;
596
		*list = g_slist_remove (*list, ans);
597
		d (5, fprintf (stderr, "Pop 0x%x\n", (int)ans););
Jody Goldberg's avatar
Jody Goldberg committed
598
		return ans;
599 600
	}

601
	return xl_expr_err (NULL, -1, -1,
602
		"Incorrect number of parsed formula arguments",
603
		"#WrongArgs!");
604 605 606
}

/**
607
 * Returns a new list composed of the last n items pop'd off the list.
608
 **/
609 610
static GnmExprList *
parse_list_last_n (GnmExprList **list, gint n)
611
{
612
	GnmExprList *l = NULL;
613
	while (n-->0)
614
		l = gnm_expr_list_prepend (l, parse_list_pop(list));
615
	return l;
616 617 618
}


619
static void
620
parse_list_free (GnmExprList **list)
621 622
{
	while (*list)
623
		gnm_expr_unref (parse_list_pop(list));
624 625
}

626
static gboolean
627
make_function (GnmExprList **stack, int fn_idx, int numargs, Workbook *wb)
628
{
629
	GnmFunc *name = NULL;
630

631
	if (fn_idx == 0xff) {
632 633 634 635 636
		/*
		 * This is undocumented.
		 * function 0xff seems to indicate an external function whose
		 * name should be on top of the stack.
		 */
637
		/* FIXME FIXME FIXME : How to handle missing trailing args ?? */
638 639
		GnmExprList *args = parse_list_last_n (stack, numargs-1);
		GnmExpr const *tmp = parse_list_pop (stack);
640 641 642
		char const *f_name = NULL;

		if (tmp != NULL) {
643
			if (tmp->any.oper == GNM_EXPR_OP_CONSTANT &&
644 645
			    tmp->constant.value->type == VALUE_STRING)
				f_name = tmp->constant.value->v_str.val->str;
646
			else if (tmp->any.oper == GNM_EXPR_OP_NAME)
647
				f_name = tmp->name.name->name->str;
648 649 650
		}

		if (f_name == NULL) {
651
			if (tmp)
652
				gnm_expr_unref (tmp);
Morten Welinder's avatar
Morten Welinder committed
653
			parse_list_free (&args);
654
			parse_list_push_raw (stack,
655
				value_new_error (NULL, _("Broken function")));
656
			g_warning ("So much for that theory.");
657
			return FALSE;
658
		}
659

660
		name = gnm_func_lookup (f_name, wb);
Jody Goldberg's avatar
Jody Goldberg committed
661
		if (name == NULL)
662
			name = gnm_func_add_placeholder (wb, f_name, "UNKNOWN", TRUE);
663

664 665
		gnm_expr_unref (tmp);
		parse_list_push (stack, gnm_expr_new_funcall (name, args));
Jody Goldberg's avatar
Jody Goldberg committed
666
		return TRUE;
667 668
	} else if (fn_idx >= 0 && fn_idx < excel_func_desc_size) {
		ExcelFuncDesc const *fd = excel_func_desc + fn_idx;
669
		GnmExprList *args;
Morten Welinder's avatar
Morten Welinder committed
670

671 672
		d (2, fprintf (stderr, "Function '%s', %d, max args: %d flags = 0x%x\n",
			       fd->name, numargs, fd->max_args, fd->flags););
673

674
		if (numargs < 0) { /* fixed, use the built in */
675
			int const available_args =
676
				(*stack != NULL) ? g_slist_length (*stack) : 0;
677
			/* handle missing trailing arguments */
678
			numargs = fd->max_args;
679 680
			if (numargs > available_args)
				numargs = available_args;
681
		}
682 683

		if (fd->flags & XL_UNKNOWN)
684 685 686 687 688
			g_warning("This sheet uses an Excel function "
				  "('%s') for which we do \n"
				  "not have adequate documentation.  "
				  "Please forward a copy (if possible) to\n"
				  "gnumeric-list@gnome.org.  Thanks",
689
				  fd->name);
Morten Welinder's avatar
Morten Welinder committed
690

691
		args = parse_list_last_n (stack, numargs);
692
		if (fd->name) {
693
			name = gnm_func_lookup (fd->name, wb);
Jody Goldberg's avatar
Jody Goldberg committed
694
			if (name == NULL)
695
				name = gnm_func_add_placeholder (wb, fd->name, "0NKNOWN", TRUE);
Jody Goldberg's avatar
Jody Goldberg committed
696
		}
697
		/* This should not happen */
698 699
		if (!name) {
			char *txt;
700
			txt = g_strdup_printf ("[Function '%s']",
701
					       fd->name ? fd->name : "?");
702
			g_warning ("Unknown %s", txt);
703
			parse_list_push_raw (stack, value_new_error (NULL, txt));
704 705 706 707 708
			g_free (txt);

			parse_list_free (&args);
			return FALSE;
		}
709
		parse_list_push (stack, gnm_expr_new_funcall (name, args));
Jody Goldberg's avatar
Jody Goldberg committed
710
		return TRUE;
711
	} else
712
		g_warning ("FIXME, unimplemented fn 0x%x, with %d args",
Jody Goldberg's avatar
Jody Goldberg committed
713 714
			fn_idx, numargs);
	return FALSE;
715 716
}

717 718 719 720
/**
 * ms_excel_dump_cellname : internal utility to dump the current location safely.
 */
static void
721
ms_excel_dump_cellname (ExcelWorkbook const *ewb, ExcelReadSheet const *esheet,
722
			int fn_col, int fn_row)
723
{
724 725
	if (esheet && esheet->sheet && esheet->sheet->name_unquoted)
		fprintf (stderr, "%s!", esheet->sheet->name_unquoted);
Jody Goldberg's avatar
Jody Goldberg committed
726 727
	else if (ewb && ewb->wb && workbook_get_uri (ewb->wb)) {
		fprintf (stderr, "[%s]", workbook_get_uri (ewb->wb));
728 729 730
		return;
	}
	fprintf (stderr, "%s%d : ", col_name(fn_col), fn_row+1);
731 732
}

Jody Goldberg's avatar
Jody Goldberg committed
733
/* Binary operator tokens */
734 735 736 737 738 739 740
static GnmExprOp const binary_ops [] = {
	GNM_EXPR_OP_ADD,	/* 0x03, ptgAdd */
	GNM_EXPR_OP_SUB,	/* 0x04, ptgSub */
	GNM_EXPR_OP_MULT,	/* 0x05, ptgMul */
	GNM_EXPR_OP_DIV,	/* 0x06, ptgDiv */
	GNM_EXPR_OP_EXP,	/* 0x07, ptgPower */
	GNM_EXPR_OP_CAT,	/* 0x08, ptgConcat */
741
	GNM_EXPR_OP_LT,		/* 0x09, ptgLT */
742 743 744
	GNM_EXPR_OP_LTE,	/* 0x0a, ptgLTE */
	GNM_EXPR_OP_EQUAL,	/* 0x0b, ptgEQ */
	GNM_EXPR_OP_GTE,	/* 0x0c, ptgGTE */
745
	GNM_EXPR_OP_GT,		/* 0x0d, ptgGT */
746
	GNM_EXPR_OP_NOT_EQUAL,	/* 0x0e, ptgNE */
Jody Goldberg's avatar
Jody Goldberg committed
747

748
	GNM_EXPR_OP_INTERSECT,	/* 0x0f, ptgIsect : Intersection */
749
	0, /* handled elsewhere	   0x10, ptgUnion : Union */
750
	GNM_EXPR_OP_RANGE_CTOR	/* 0x11, ptgRange : Range */
Jody Goldberg's avatar
Jody Goldberg committed
751 752
};

753 754 755 756
static GnmExprOp const unary_ops [] = {
	GNM_EXPR_OP_UNARY_PLUS,/* 0x12, ptgU_PLUS  */
	GNM_EXPR_OP_UNARY_NEG,	/* 0x13, ptgU_MINUS */
	GNM_EXPR_OP_PERCENTAGE,	/* 0x14, ptgPERCENT */
Jody Goldberg's avatar
Jody Goldberg committed
757 758
};

Jody Goldberg's avatar
Jody Goldberg committed
759 760 761 762 763 764 765 766 767
static gboolean
excel_formula_parses_ref_sheets (MSContainer const *container, guint8 const *data,
				 Sheet **first, Sheet **last)
{
	if (container->ver >= MS_BIFF_V8) {
		ExcelExternSheetV8 const *es =
			excel_externsheet_v8 (container->ewb, GSF_LE_GET_GUINT16 (data));

		if (es != NULL) {
768
			if (es->first == (Sheet *)2 || es->last == (Sheet *)2) /* deleted sheets */
Jody Goldberg's avatar
Jody Goldberg committed
769 770 771 772 773 774 775 776 777 778 779 780
				return TRUE;
			*first = es->first;
			*last = es->last;
		}
	} else {
		gint16 ixals = GSF_LE_GET_GINT16 (data);
		gint16 a = GSF_LE_GET_GINT16 (data + 10);
		gint16 b = GSF_LE_GET_GINT16 (data + 12);

		if (a < 0 || b < 0) /* deleted sheets */
			return TRUE;

781
		d (1, fprintf (stderr, " : 0x%hx : 0x%hx : 0x%hx\n", ixals, a, b););
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797

		/* ixals < 0 == reference within the current workbook
		 *    ixals == negative one based index into containers externsheet table
		 *    a and b
		 *    < 0 refers to a deleted sheet
		 *    ==0 refers to the current sheet (should not occur in global names)
		 *    > 0  1 based indicies to the sheets in the workbook
		 *    a is always the same as ixals
		 *    3d references use -ixals and b.  Since global names
		 *    precede the BOUNDSHEET records and b refers to their
		 *    content XL cheated and just spews an externsheet for
		 *    every sheet if there are any 3d references.
		 *
		 *    see pivot.xls as an example of expressions with a&b as
		 *    sheet indicies before the boundsheets.
		 **/
Jody Goldberg's avatar
Jody Goldberg committed
798
		if (ixals < 0) {
799 800 801 802 803
			*first = excel_externsheet_v7 (container, -ixals);
			*last = (a == b) ? *first
				: ((b > 0)
				   ? excel_externsheet_v7 (container, b)
				   : ms_container_sheet (container));
Jody Goldberg's avatar
Jody Goldberg committed
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
		} else {
			*first = excel_externsheet_v7 (container, ixals);
			*last  = excel_externsheet_v7 (container, b);
		}
	}

	if (*first == (Sheet *)1) {
		*first = *last = NULL;
		g_warning ("So much for that theory.  Please send us a copy of this workbook");
	} else if (*last == (Sheet *)1) {
		*last = *first;
		g_warning ("so much for that theory.  Please send us a copy of this workbook");
	} else if (*first != NULL && *last == NULL)
		*last = *first;

	return FALSE;
}

822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
static char const *ptg_name[] = {
	"PTG ZERO ???",	"PTG_EXPR",	"PTG_TBL",	"PTG_ADD",
	"PTG_SUB",	"PTG_MULT",	"PTG_DIV",	"PTG_EXP",
	"PTG_CONCAT",	"PTG_LT",	"PTG_LTE",	"PTG_EQUAL",
	"PTG_GTE",	"PTG_GT",	"PTG_NOT_EQUAL", "PTG_INTERSECT",

	"PTG_UNION",	"PTG_RANGE",	"PTG_U_PLUS",	"PTG_U_MINUS",
	"PTG_PERCENT",	"PTG_PAREN",	"PTG_MISSARG",	"PTG_STR",
	"PTG_EXTENDED", "PTG_ATTR",	"PTG_SHEET",	"PTG_SHEET_END",
	"PTG_ERR",	"PTG_BOOL",	"PTG_INT",	"PTG_NUM",

	"PTG_ARRAY",	"PTG_FUNC",	"PTG_FUNC_VAR", "PTG_NAME",
	"PTG_REF",	"PTG_AREA",	"PTG_MEM_AREA", "PTG_MEM_ERR",
	"PTG_MEM_NO_MEM", "PTG_MEM_FUNC", "PTG_REF_ERR", "PTG_AREA_ERR",
	"PTG_REFN",	"PTG_AREAN",	"PTG_MEM_AREAN", "PTG_NO_MEMN",

	"PTG_30",	"PTG_31",	"PTG_32",	"PTG_33",
	"PTG_34",	"PTG_35",	"PTG_36",	"PTG_37",

	"PTG_FUNC_CE",	"PTG_NAME_X",	"PTG_REF_3D",	"PTG_AREA_3D",
	"PTG_REF_ERR_3D", "PTG_AREA_ERR_3D", "PTG_3E",	"PTG_3F"
};

845 846
/**
 * Parse that RP Excel formula, see S59E2B.HTM
847
 * Return a dynamicly allocated GnmExpr containing the formula, or NULL
848
 **/
849
GnmExpr const *
850
excel_parse_formula (MSContainer const *container,
851
		     ExcelReadSheet const *esheet,
852 853 854 855
		     int fn_col, int fn_row,
		     guint8 const *mem, guint16 length,
		     gboolean shared,
		     gboolean *array_element)
856
{
857
	MsBiffVersion const ver = container->ver;
Jody Goldberg's avatar
Jody Goldberg committed
858

859
	/* so that the offsets and lengths match the documentation */
Jody Goldberg's avatar
Jody Goldberg committed
860
	guint8 const *cur = mem + 1;
861 862 863 864

	/* Array sizes and values are stored at the end of the stream */
	guint8 const *array_data = mem + length;

Jody Goldberg's avatar
Jody Goldberg committed
865
	int len_left = length;
866
	GnmExprList *stack = NULL;
Jody Goldberg's avatar
Jody Goldberg committed
867
	gboolean error = FALSE;
868
	int ptg_length, ptg, ptgbase;
869
	guint8 eptg;
870

871 872 873
	if (array_element != NULL)
		*array_element = FALSE;

874
#ifndef NO_DEBUG_EXCEL
875
	if (ms_excel_formula_debug > 1) {
876
		ms_excel_dump_cellname (container->ewb, esheet, fn_col, fn_row);
Jody Goldberg's avatar
Jody Goldberg committed
877
		fprintf (stderr, "\n");
878
		if (ms_excel_formula_debug > 1) {
879
			gsf_mem_dump (mem, length);
Jody Goldberg's avatar
Jody Goldberg committed
880
		}
881 882 883
	}
#endif

Jody Goldberg's avatar
Jody Goldberg committed
884
	while (len_left > 0 && !error) {
885 886 887
		ptg_length = 0;
		ptg = GSF_LE_GET_GUINT8 (cur-1);
		ptgbase = ((ptg & 0x40) ? (ptg | 0x20): ptg) & 0x3F;
888
		if (ptg > FORMULA_PTG_MAX)
Jody Goldberg's avatar
Jody Goldberg committed
889
			break;
890
		d (2, {
891
			fprintf (stderr, "Ptg : %s 0x%02x", ptg_name [ptgbase], ptg);
892
			if (ptg != ptgbase)
893 894
				fprintf (stderr, "(0x%02x)", ptgbase);
			fprintf (stderr, "\n");
895
		});
896

Jody Goldberg's avatar
Jody Goldberg committed
897
		switch (ptgbase) {
Jody Goldberg's avatar
Jody Goldberg committed
898
		case FORMULA_PTG_EXPR: {
899
			GnmExpr const *expr;
900
			XLSharedFormula *sf;
Jody Goldberg's avatar
Jody Goldberg committed
901
			GnmCellPos top_left;
902

903 904
			top_left.row = GSF_LE_GET_GUINT16 (cur+0);
			top_left.col = GSF_LE_GET_GUINT16 (cur+2);
905
			sf = excel_sheet_shared_formula (esheet, &top_left);
Jody Goldberg's avatar
Jody Goldberg committed
906 907

			if (sf == NULL) {
908 909
				if (top_left.col != fn_col || top_left.row != fn_row) {
					g_warning ("Unknown shared formula (key = %s) in ", cellpos_as_string (&top_left));
910
					ms_excel_dump_cellname (container->ewb, esheet, fn_col, fn_row);
911
				}
Morten Welinder's avatar
Morten Welinder committed
912
				parse_list_free (&stack);
913 914 915
				return NULL;
			}

Jody Goldberg's avatar
Jody Goldberg committed
916
			if (sf->is_array) {
917 918 919
				if (array_element != NULL)
					*array_element = TRUE;
				else
920
					g_warning ("EXCEL : unexpected array\n");
921

Morten Welinder's avatar
Morten Welinder committed
922
				parse_list_free (&stack);
923 924 925 926
				return NULL;
			}

#ifndef NO_DEBUG_EXCEL
927
			if (ms_excel_formula_debug > 0) {
928
				fprintf (stderr, "Parse shared formula\n");
Michael Meeks's avatar
Michael Meeks committed
929 930
			}
#endif
931
			expr = excel_parse_formula (container, esheet, fn_col, fn_row,
932
				sf->data, sf->data_len, TRUE, array_element);
933 934 935

			parse_list_push (&stack, expr);
			ptg_length = length; /* Force it to be the only token */
936
			break;
Jody Goldberg's avatar
Jody Goldberg committed
937
		}
938

939 940 941 942
		case FORMULA_PTG_TBL :
			ptg_length = 4;
			break;

Jody Goldberg's avatar
Jody Goldberg committed
943 944 945 946 947 948 949 950
		case FORMULA_PTG_ADD :  case FORMULA_PTG_SUB :
		case FORMULA_PTG_MULT : case FORMULA_PTG_DIV :
		case FORMULA_PTG_EXP :
		case FORMULA_PTG_CONCAT :
		case FORMULA_PTG_LT : case FORMULA_PTG_LTE :
		case FORMULA_PTG_EQUAL :
		case FORMULA_PTG_GTE : case FORMULA_PTG_GT :
		case FORMULA_PTG_NOT_EQUAL :
951
		case FORMULA_PTG_INTERSECT :
Jody Goldberg's avatar
Jody Goldberg committed
952
		case FORMULA_PTG_RANGE : {
953 954 955
			GnmExpr const *r = parse_list_pop (&stack);
			GnmExpr const *l = parse_list_pop (&stack);
			parse_list_push (&stack, gnm_expr_new_binary (
Jody Goldberg's avatar
Jody Goldberg committed
956 957 958
				l,
				binary_ops [ptgbase - FORMULA_PTG_ADD],
				r));
959
			break;
Jody Goldberg's avatar
Jody Goldberg committed
960
		}
961

962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979
		case FORMULA_PTG_UNION : {
			GnmExpr const *r = parse_list_pop (&stack);
			GnmExpr const *l = parse_list_pop (&stack);

			/* not exactly legal, but should be reasonable
			 * XL has union operator we have sets.
			 */
			if (l->any.oper != GNM_EXPR_OP_SET) {
				GnmExprList *args = gnm_expr_list_prepend (NULL, r);
				args = gnm_expr_list_prepend (args, l);
				parse_list_push (&stack, gnm_expr_new_set (args));
			} else {
				gnm_expr_list_append (l->set.set, r);
				parse_list_push (&stack, l);
			}
			break;
		}

Jody Goldberg's avatar
Jody Goldberg committed
980 981 982
		case FORMULA_PTG_U_PLUS :
		case FORMULA_PTG_U_MINUS :
		case FORMULA_PTG_PERCENT :
983
			parse_list_push (&stack, gnm_expr_new_unary (
Jody Goldberg's avatar
Jody Goldberg committed
984 985
				unary_ops [ptgbase - FORMULA_PTG_U_PLUS],
				parse_list_pop (&stack)));
986 987
			break;

988
		case FORMULA_PTG_PAREN:
989
/*	  fprintf (stderr, "Ignoring redundant parenthesis ptg\n"); */
Jody Goldberg's avatar
Jody Goldberg committed
990 991
			ptg_length = 0;
			break;
992

993 994
		case FORMULA_PTG_MISSARG:
			parse_list_push_raw (&stack, value_new_empty ());
Jody Goldberg's avatar
Jody Goldberg committed
995 996
			ptg_length = 0;
			break;
997

Jody Goldberg's avatar
Jody Goldberg committed
998
		case FORMULA_PTG_ATTR : { /* FIXME: not fully implemented */
999
			guint8  grbit = GSF_LE_GET_GUINT8(cur);
1000 1001 1002 1003 1004 1005 1006 1007
			guint16 w;
			if (ver >= MS_BIFF_V3) {
				w = GSF_LE_GET_GUINT16(cur+1);
				ptg_length = 3;
			} else {
				w = GSF_LE_GET_GUINT8(cur+1);
				ptg_length = 2;
			}
1008
			if (grbit == 0x00) {
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
				static gboolean warned_a = FALSE;
				static gboolean warned_3 = FALSE;
				if (w == 0xa) {
					if (warned_a)
						break;
					warned_a = TRUE;
				} else if (w == 3) {
					if (warned_3)
						break;
					warned_3 = TRUE;
				} /* else always warn */

1021
				ms_excel_dump_cellname (container->ewb, esheet, fn_col, fn_row);
1022
				fprintf (stderr, "Hmm, ptgAttr of type 0 ??\n"
1023 1024 1025
					"I've seen a case where an instance of this with flag A and another with flag 3\n"
					"bracket a 1x1 array formula.  please send us this file.\n"
					"Flags = 0x%X\n", w);
1026
			} else if (grbit & 0x01) {
1027
#ifndef NO_DEBUG_EXCEL
1028
				if (ms_excel_formula_debug > 0) {
1029
					fprintf (stderr, "A volatile function: so what\n");
1030 1031
				}
#endif
1032 1033
			} else if (grbit & 0x02) { /* AttrIf: 'optimised' IF function */
				/* Who cares if the TRUE expr has a goto at the end */
1034
				GnmExpr const *tr;
1035
#ifndef NO_DEBUG_EXCEL
1036
				if (ms_excel_formula_debug > 2) {
1037
					fprintf (stderr, "Optimised IF 0x%x 0x%x\n", grbit, w);
1038
					gsf_mem_dump (mem, length);
1039
				}
1040
#endif
1041
				tr = w ? excel_parse_formula (container, esheet, fn_col, fn_row,
1042
					   cur+ptg_length, w, shared, NULL)
1043
					: gnm_expr_new_constant (value_new_string (""));
1044
				parse_list_push (&stack, tr);
Jody Goldberg's avatar
Jody Goldberg committed
1045
				ptg_length += w;
1046 1047 1048
			} else if (grbit & 0x04) { /* AttrChoose 'optimised' my foot. */
				guint16 len, lp;
				guint32 offset=0;
1049
				guint8 const *data=cur+3;
1050
				GnmExpr const *tr;
1051

1052
#ifndef NO_DEBUG_EXCEL
1053
				if (ms_excel_formula_debug > 1) {
1054
					fprintf (stderr, "'Optimised' choose\n");
1055
					gsf_mem_dump (mem,length);
1056
				}
1057
#endif
1058
				for (lp=0;lp<w;lp++) { /* w = wCases */
1059 1060
					offset= GSF_LE_GET_GUINT16(data);
					len = GSF_LE_GET_GUINT16(data+2) - offset;
1061
#ifndef NO_DEBUG_EXCEL
1062
					if (ms_excel_formula_debug > 1) {
1063
						fprintf (stderr, "Get from %d len %d [ = 0x%x ]\n",
1064 1065 1066 1067
							ptg_length+offset, len,
							*(cur+ptg_length+offset));
					}
#endif
1068
					tr = excel_parse_formula (container, esheet, fn_col, fn_row,
1069 1070
						cur+ptg_length+offset, len, shared, NULL);
					data += 2;
1071
					parse_list_push (&stack, tr);
1072
				}
1073
				ptg_length+=GSF_LE_GET_GUINT16(data);
1074
			} else if (grbit & 0x08) { /* AttrGoto */
1075
#ifndef NO_DEBUG_EXCEL
1076
				if (ms_excel_formula_debug > 2) {
1077
					fprintf (stderr, "Goto %d: cur = 0x%x\n", w,
Jody Goldberg's avatar
Jody Goldberg committed
1078
						(int)(cur-mem));
1079
					gsf_mem_dump (mem, length);
1080
				}
1081
#endif
1082 1083
				/* Not right prior to Excel 4.0 ? */
				if (ver <= MS_BIFF_V3) break;
Jody Goldberg's avatar
Jody Goldberg committed
1084
				ptg_length = w;
1085
			} else if (grbit & 0x10) { /* AttrSum: 'optimised' SUM function */
Jody Goldberg's avatar
Jody Goldberg committed
1086
				if (!make_function (&stack, 0x04, 1, container->ewb->wb)) {
Jody Goldberg's avatar
Jody Goldberg committed
1087
					error = TRUE;
Jody Goldberg's avatar
Jody Goldberg committed
1088
					fprintf (stderr, "Error in optimised SUM\n");
Michael Meeks's avatar
Michael Meeks committed
1089
				}
1090
			} else if (grbit & 0x40) { /* AttrSpace */
1091 1092
				guint8 num_space = GSF_LE_GET_GUINT8(cur+2);
				guint8 attrs     = GSF_LE_GET_GUINT8(cur+1);
1093
				if (attrs == 00) /* bitFSpace : ignore it */
Jody Goldberg's avatar
Jody Goldberg committed
1094
				/* Could perhaps pop top arg & append space ? */;
1095
				else
1096
#ifndef NO_DEBUG_EXCEL
1097
					if (ms_excel_formula_debug > 1) {
1098
						fprintf (stderr, "Redundant whitespace in formula 0x%x count %d\n", attrs, num_space);
1099
					}
1100 1101 1102
#else
				;
#endif
1103
			} else {
1104
				ms_excel_dump_cellname (container->ewb, esheet, fn_col, fn_row);
1105
				fprintf (stderr, "Unknown PTG Attr gr = 0x%x, w = 0x%x ptg = 0x%x\n", grbit, w, ptg);
Jody Goldberg's avatar
Jody Goldberg committed
1106
				error = TRUE;
1107
			}
1108
		}
Jody Goldberg's avatar
Jody Goldberg committed
1109
		break;
1110

Jody Goldberg's avatar
Jody Goldberg committed
1111 1112
		case FORMULA_PTG_SHEET:
			g_warning ("PTG_SHEET! please send us a copy of this file.");
1113 1114 1115
			ptg_length = 10;
			break;

Jody Goldberg's avatar
Jody Goldberg committed
1116 1117
		case FORMULA_PTG_SHEET_END:
			g_warning ("PTG_SHEET_END! please send us a copy of this file.");
1118 1119 1120
			ptg_length = 4;
			break;

Jody Goldberg's avatar
Jody Goldberg committed
1121
		case FORMULA_PTG_ERR:
1122
			parse_list_push_raw (&stack, biff_get_error (NULL, GSF_LE_GET_GUINT8 (cur)));
Jody Goldberg's avatar
Jody Goldberg committed
1123 1124
			ptg_length = 1;
			break;
Jody Goldberg's avatar
Jody Goldberg committed
1125 1126 1127

		case FORMULA_PTG_INT:
			parse_list_push_raw (&stack, value_new_int (GSF_LE_GET_GUINT16(cur)));
Jody Goldberg's avatar
Jody Goldberg committed
1128
			ptg_length = 2;
1129
			break;
Jody Goldberg's avatar
Jody Goldberg committed
1130

Jody Goldberg's avatar
Jody Goldberg committed
1131
		case FORMULA_PTG_BOOL:
1132
			parse_list_push_raw (&stack, value_new_bool (GSF_LE_GET_GUINT8(cur)));
Jody Goldberg's avatar
Jody Goldberg committed
1133 1134
			ptg_length = 1;
			break;
Jody Goldberg's avatar
Jody Goldberg committed
1135

Jody Goldberg's avatar
Jody Goldberg committed
1136 1137
		case FORMULA_PTG_NUM:
			parse_list_push_raw (&stack, value_new_float (gsf_le_get_double (cur)));
Jody Goldberg's avatar
Jody Goldberg committed
1138 1139
			ptg_length = 8;
			break;
Jody Goldberg's avatar
Jody Goldberg committed
1140

Jody Goldberg's avatar
Jody Goldberg committed
1141
		case FORMULA_PTG_STR: {
1142 1143 1144 1145 1146 1147 1148 1149 1150
			char *str;
			int len = GSF_LE_GET_GUINT8 (cur);

			if (len <= len_left) {
				str = biff_get_text (cur+1, len, &len, ver);
				ptg_length = 1 + len;
			} else {
				str = NULL;

1151
#if 0
1152 1153 1154 1155 1156
				/* we can not flag this because some versions of gnumeric
				 * produced invalid output where "" was stored as
				 * PTG_STR with no length **/
				g_warning ("invalid string of len %d, larger than remaining space %d",
					   len, len_left);
1157
#endif
1158
			}
1159

1160
			if (str != NULL) {
1161
				d (2, fprintf (stderr, "   -> '%s'\n", str););
1162
				parse_list_push_raw (&stack, value_new_string_nocopy (str));
1163 1164
			} else {
				d (2, fprintf (stderr, "   -> \'\'\n"););
1165
				parse_list_push_raw (&stack, value_new_string (""));
1166
			}
Jody Goldberg's avatar
Jody Goldberg committed
1167
			break;