1 /*
2  * ms-formula-write.c: export GnmExpr to xls
3  *
4  * Authors:
5  *    Jody Goldberg (jody@gnome.org)
6  *    Michael Meeks (michael@ximian.com)
7  *
8  * (C) 1998-2001 Michael Meeks
9  * (C) 2002-2005 Jody Goldberg
10  */
11 
12 #include <gnumeric-config.h>
13 #include <gnumeric.h>
14 #include "ms-formula-write.h"
15 #include "ms-excel-write.h"
16 #include "formula-types.h"
17 #include "excel.h"
18 #include "ms-biff.h"
19 #include "formula-types.h"
20 #include "boot.h"
21 
22 #include <sheet.h>
23 #include <gutils.h>
24 #include <workbook.h>
25 #include <func.h>
26 #include <value.h>
27 #include <cell.h>
28 #include <expr.h>
29 #include <expr-impl.h>
30 #include <expr-name.h>
31 #include <parse-util.h>
32 #include <goffice/goffice.h>
33 
34 #include <gsf/gsf-utils.h>
35 #include <glib/gi18n-lib.h>
36 #include <string.h>
37 
38 #define FORMULA_DEBUG 0
39 
40 static guint
sheet_pair_hash(ExcelSheetPair const * sp)41 sheet_pair_hash (ExcelSheetPair const *sp)
42 {
43 	return ((GPOINTER_TO_UINT(sp->a) >> 2) & 0xffff) | ((GPOINTER_TO_UINT(sp->b) << 14) & 0xffff0000);
44 }
45 
46 static gint
sheet_pair_cmp(ExcelSheetPair const * a,ExcelSheetPair const * b)47 sheet_pair_cmp (ExcelSheetPair const *a, ExcelSheetPair const *b)
48 {
49 	return a->a == b->a && a->b == b->b;
50 }
51 
52 static void
sheet_pair_add_if_unknown(GHashTable * hash,ExcelSheetPair const * pair)53 sheet_pair_add_if_unknown (GHashTable *hash, ExcelSheetPair const *pair)
54 {
55 	if (NULL == g_hash_table_lookup (hash, pair)) {
56 		ExcelSheetPair *new_pair = g_new (ExcelSheetPair, 1);
57 		new_pair->a = pair->a;
58 		new_pair->b = pair->b;
59 		new_pair->idx_a = new_pair->idx_b = 0;
60 		g_hash_table_insert (hash, new_pair, new_pair);
61 		/* g_printerr ("Adding %p:%p\n", pair->a, pair->b); */
62 	}
63 }
64 
65 void
excel_write_prep_sheet(ExcelWriteState * ewb,Sheet const * sheet)66 excel_write_prep_sheet (ExcelWriteState *ewb, Sheet const *sheet)
67 {
68 	ExcelSheetPair pair;
69 	pair.a = pair.b = sheet;
70 	if (pair.a != NULL)
71 		sheet_pair_add_if_unknown (ewb->sheet_pairs, &pair);
72 }
73 
74 static GnmExpr const *
cb_excel_write_prep_expr(GnmExpr const * expr,GnmExprWalk * data)75 cb_excel_write_prep_expr (GnmExpr const *expr, GnmExprWalk *data)
76 {
77 	ExcelWriteState *ewb = data->user;
78 
79 	switch (GNM_EXPR_GET_OPER (expr)) {
80 	case GNM_EXPR_OP_FUNCALL: {
81 		GnmFunc *func = expr->func.func;
82 		GnmFuncFlags flags = gnm_func_get_flags (func);
83 		ExcelFunc *ef = g_hash_table_lookup (ewb->function_map, func);
84 		if (ef != NULL)
85 			break;
86 
87 		ef = g_new (ExcelFunc, 1);
88 		ef->efunc = (flags & (GNM_FUNC_IS_PLACEHOLDER |
89 				      GNM_FUNC_IS_WORKBOOK_LOCAL))
90 			? NULL
91 			: g_hash_table_lookup (excel_func_by_name,
92 					       func->name);
93 
94 		if (ef->efunc && ef->efunc->idx == 0xff) {
95 			/* These functions appear to be saved as macros! */
96 			ef->macro_name = g_strdup (ef->efunc->name);
97 			ef->idx = -1;
98 		} else if (ef->efunc) {
99 			ef->macro_name = NULL;
100 			ef->idx = ef->efunc->idx;
101 		} else if (flags & GNM_FUNC_IS_WORKBOOK_LOCAL) {
102 			ef->macro_name = g_strdup (func->name);
103 			ef->idx = -1;
104 		} else {
105 			char *fname =
106 				g_utf8_strup (gnm_func_get_name (func, FALSE), -1);
107 			g_ptr_array_add (ewb->externnames, fname);
108 			ef->macro_name = NULL;
109 			ef->idx = ewb->externnames->len;
110 		}
111 		g_hash_table_insert (ewb->function_map, func, ef);
112 		break;
113 	}
114 
115 	case GNM_EXPR_OP_CELLREF:
116 		excel_write_prep_sheet (ewb, expr->cellref.ref.sheet);
117 		break;
118 
119 	case GNM_EXPR_OP_CONSTANT: {
120 		GnmValue const *v = expr->constant.value;
121 		if (VALUE_IS_CELLRANGE (v)) {
122 			ExcelSheetPair pair;
123 			pair.a = v->v_range.cell.a.sheet;
124 			pair.b = v->v_range.cell.b.sheet;
125 			if (pair.a != NULL) {
126 				if (pair.b == NULL)
127 					pair.b = pair.a;
128 				sheet_pair_add_if_unknown (ewb->sheet_pairs, &pair);
129 			}
130 		}
131 		break;
132 	}
133 
134 	default:
135 		break;
136 	}
137 
138 	return NULL;
139 }
140 
141 /**
142  * excel_write_prep_expr :
143  * @ewb:
144  * @texpr:
145  *
146  * Searches for interesting functions, names, or sheets.
147  * and builds a database of things to write out later.
148  **/
149 void
excel_write_prep_expr(ExcelWriteState * ewb,GnmExprTop const * texpr)150 excel_write_prep_expr (ExcelWriteState *ewb, GnmExprTop const *texpr)
151 {
152 	gnm_expr_walk (texpr->expr, cb_excel_write_prep_expr, ewb);
153 }
154 
155 /**
156  * excel_write_prep_expressions :
157  * @ewb: state
158  *
159  * Initialize the data structures for exporting functions
160  **/
161 void
excel_write_prep_expressions(ExcelWriteState * ewb)162 excel_write_prep_expressions (ExcelWriteState *ewb)
163 {
164 	g_return_if_fail (ewb != NULL);
165 
166 	ewb->sheet_pairs = g_hash_table_new_full (
167 		(GHashFunc) sheet_pair_hash, (GEqualFunc) sheet_pair_cmp,
168 		NULL, g_free);
169 }
170 
171 /****************************************************************************/
172 
173 typedef enum {
174 	XL_REF		= 0,	/* R */
175 	XL_VAL		= 1,	/* V */
176 	XL_ARRAY	= 2,	/* A */
177 	XL_ROOT		= 3,	/* v */
178 	NUM_XL_TYPES	= 3
179 } XLOpType;
180 typedef enum {
181 	CTXT_CELL = 0,
182 	CTXT_ARRAY = 1,
183 	CTXT_NAME_OBJ = 2,
184 	NUM_CTXTS
185 } XLContextType;
186 
187 typedef struct {
188 	ExcelWriteState *ewb;
189 	Sheet		*sheet;
190 	int		 col, row;
191 	gboolean	 use_name_variant;
192 	gboolean         allow_sheetless_ref;
193 	XLContextType	 context;
194 
195 	/* Accumulator for storing arrays after the expression */
196 	GSList		*arrays;
197 	GnmExprTop const *array_texpr;
198 } PolishData;
199 
200 static void write_node (PolishData *pd, GnmExpr const *expr,
201 			int paren_level, XLOpType target_type);
202 
203 #define CLASS_REF	0x00
204 #define CLASS_VAL	0x20
205 #define CLASS_ARRAY	0x40
206 static const guint8 xl_op_class[NUM_CTXTS][NUM_XL_TYPES][NUM_XL_TYPES+1] = {
207 	{ /* CELL | Wants REF	Wants VAL	Wants ARR	From Root */
208 /* From REF */	 { CLASS_REF,	CLASS_VAL,	CLASS_ARRAY,	CLASS_VAL },
209 /* From VAL */	 { CLASS_VAL,	CLASS_VAL,	CLASS_VAL,	CLASS_VAL },
210 /* From ARRAY */ { CLASS_ARRAY,	CLASS_VAL,	CLASS_ARRAY,	CLASS_VAL },
211 	},
212 	{ /* ARR  | Wants REF	Wants VAL	Wants ARR	From Root */
213 /* From REF */	 { CLASS_REF,	CLASS_VAL,	CLASS_ARRAY,	CLASS_VAL },
214 /* From VAL */	 { CLASS_ARRAY,	CLASS_VAL,	CLASS_ARRAY,	CLASS_VAL },
215 /* From ARRAY */ { CLASS_ARRAY,	CLASS_VAL,	CLASS_ARRAY,	CLASS_ARRAY },
216 	},
217 	{ /* NAME | Wants REF	Wants VAL	Wants ARR	From Root */
218 /* From REF */	 { CLASS_REF,	CLASS_ARRAY,	CLASS_ARRAY,	CLASS_REF },
219 /* From VAL */	 { CLASS_ARRAY,	CLASS_ARRAY,	CLASS_ARRAY,	CLASS_ARRAY },
220 /* From ARRAY */ { CLASS_ARRAY,	CLASS_ARRAY,	CLASS_ARRAY,	CLASS_ARRAY },
221 	}
222 };
223 
224 static XLOpType
xl_map_char_to_type(char t)225 xl_map_char_to_type (char t)
226 {
227 	if (t == 'V')
228 		return XL_VAL;
229 	if (t == 'R')
230 		return XL_REF;
231 	if (t == 'A')
232 		return XL_ARRAY;
233 	if (t == 'v')
234 		return XL_ROOT;
235 	g_warning ("unknown op class '%c' assuming val", t ? t : '-');
236 	return XL_VAL;
237 }
238 
239 static guint8
xl_get_op_class(PolishData * pd,XLOpType src_type,XLOpType target_type)240 xl_get_op_class (PolishData *pd, XLOpType src_type, XLOpType target_type)
241 {
242 	return xl_op_class[pd->context][src_type][target_type];
243 }
244 
245 static void
push_guint8(PolishData * pd,guint8 b)246 push_guint8 (PolishData *pd, guint8 b)
247 {
248 	ms_biff_put_var_write (pd->ewb->bp, &b, sizeof(guint8));
249 }
250 
251 static void
push_guint16(PolishData * pd,guint16 b)252 push_guint16 (PolishData *pd, guint16 b)
253 {
254 	guint8 data[2];
255 	GSF_LE_SET_GUINT16 (data, b);
256 	ms_biff_put_var_write (pd->ewb->bp, data, sizeof(data));
257 }
258 
259 static void
push_gint16(PolishData * pd,gint16 b)260 push_gint16 (PolishData *pd, gint16 b)
261 {
262 	guint8 data[2];
263 	GSF_LE_SET_GINT16 (data, b);
264 	ms_biff_put_var_write (pd->ewb->bp, data, sizeof(data));
265 }
266 
267 static void
push_guint32(PolishData * pd,guint32 b)268 push_guint32 (PolishData *pd, guint32 b)
269 {
270 	guint8 data[4];
271 	GSF_LE_SET_GUINT32 (data, b);
272 	ms_biff_put_var_write (pd->ewb->bp, data, sizeof(data));
273 }
274 
275 static void
write_cellref_v7(PolishData * pd,GnmCellRef const * ref,guint8 * out_col,guint8 * out_row)276 write_cellref_v7 (PolishData *pd, GnmCellRef const *ref,
277 		  guint8 *out_col, guint8 *out_row)
278 {
279 	guint    row, col;
280 
281 	if (pd->use_name_variant)
282 		col = ref->col & 0xff;
283 	else if (ref->col_relative)
284 		col = ref->col + pd->col;
285 	else
286 		col = ref->col;
287 
288 	if (ref->row_relative && !pd->use_name_variant)
289 		row = ref->row + pd->row;
290 	else
291 		row = ref->row;
292 
293 	if (ref->col_relative)
294 		row |= 0x4000;
295 	if (ref->row_relative)
296 		row |= 0x8000;
297 
298 	GSF_LE_SET_GUINT16 (out_row, row);
299 	GSF_LE_SET_GUINT8  (out_col, col);
300 }
301 
302 static void
write_cellref_v8(PolishData * pd,GnmCellRef const * ref,guint8 * out_col,guint8 * out_row)303 write_cellref_v8 (PolishData *pd, GnmCellRef const *ref,
304 		  guint8 *out_col, guint8 *out_row)
305 {
306 	guint    row, col;
307 
308 	if (pd->use_name_variant)
309 		col = ref->col & 0xff;
310 	else if (ref->col_relative)
311 		col = ref->col + pd->col;
312 	else
313 		col = ref->col;
314 
315 	if (ref->row_relative && !pd->use_name_variant)
316 		row = ref->row + pd->row;
317 	else
318 		row = ref->row;
319 
320 	if (ref->col_relative)
321 		col |= 0x4000;
322 	if (ref->row_relative)
323 		col |= 0x8000;
324 
325 	GSF_LE_SET_GUINT16 (out_row, row);
326 	GSF_LE_SET_GUINT16 (out_col, col);
327 }
328 
329 static void
write_string1(PolishData * pd,gchar const * txt)330 write_string1 (PolishData *pd, gchar const *txt)
331 {
332 	push_guint8 (pd, FORMULA_PTG_STR);
333 	excel_write_string (pd->ewb->bp, STR_ONE_BYTE_LENGTH, txt);
334 }
335 
336 static void
write_string(PolishData * pd,gchar const * txt)337 write_string (PolishData *pd, gchar const *txt)
338 {
339 	size_t i, n = 0, len = g_utf8_strlen (txt, -1);
340 	const char *p = txt;
341 	const size_t CHUNK_LEN = 255;
342 
343 	/*
344 	 * The xls format only handles strings up to 255 characters
345 	 * in formulae.  To make up for that, we create expressions
346 	 * like ("s1"&"s2"&...).  Note, that the parentheses are
347 	 * explicitly present in the file.
348 	 */
349 	for (i = 0; n == 0 || i < len; ) {
350 		if (len - i <= CHUNK_LEN) {
351 			write_string1 (pd, p);
352 			i = len;
353 		} else {
354 			const char *endcut = g_utf8_offset_to_pointer (p, CHUNK_LEN);
355 			size_t cutlen = endcut - p;
356 			char *cut = g_memdup (p, cutlen + 1);
357 			cut[cutlen] = 0;
358 			write_string1 (pd, cut);
359 			g_free (cut);
360 
361 			p = endcut;
362 			i += CHUNK_LEN;
363 		}
364 
365 		if (n > 0)
366 			push_guint8 (pd, FORMULA_PTG_CONCAT);
367 		n++;
368 	}
369 
370 	if (n > 1)
371 		push_guint8 (pd, FORMULA_PTG_PAREN);
372 }
373 
374 static void
excel_formula_write_CELLREF(PolishData * pd,GnmCellRef const * ref,Sheet * sheet_b,XLOpType target_type)375 excel_formula_write_CELLREF (PolishData *pd, GnmCellRef const *ref,
376 			     Sheet *sheet_b, XLOpType target_type)
377 {
378 	guint8 data[24];
379 	guint8 ptg;
380 	guint8 op_class = xl_get_op_class (pd, XL_REF, target_type);
381 
382 	g_return_if_fail (pd);
383 	g_return_if_fail (ref);
384 
385 	if (ref->sheet == NULL) {
386 
387 		g_return_if_fail (sheet_b == NULL);
388 
389 		if (!pd->allow_sheetless_ref) {
390 			g_warning ("XL does not support unqualified references in global names");
391 		}
392 
393 		ptg = (pd->use_name_variant && (ref->col_relative || ref->row_relative))
394 			? FORMULA_PTG_REFN : FORMULA_PTG_REF;
395 		push_guint8 (pd, ptg + op_class);
396 		if (pd->ewb->bp->version <= MS_BIFF_V7) {
397 			write_cellref_v7 (pd, ref, data + 2, data);
398 			ms_biff_put_var_write (pd->ewb->bp, data, 3);
399 		} else {
400 			write_cellref_v8 (pd, ref, data + 2, data);
401 			ms_biff_put_var_write (pd->ewb->bp, data, 4);
402 		}
403 	} else {
404 		push_guint8 (pd, FORMULA_PTG_REF_3D + op_class);
405 		if (pd->ewb->bp->version <= MS_BIFF_V7) {
406 			guint16 idx_a, idx_b;
407 			gint16 ixals;
408 
409 			/* FIXME no external references for now */
410 			g_return_if_fail (pd->ewb->base.wb == ref->sheet->workbook);
411 
412 			idx_a = ref->sheet->index_in_wb;
413 			idx_b = (sheet_b != NULL) ? sheet_b->index_in_wb : idx_a;
414 			ixals = -(idx_a+1);
415 			GSF_LE_SET_GUINT16 (data, ixals);
416 			GSF_LE_SET_GUINT32 (data +  2, 0x0);
417 			GSF_LE_SET_GUINT32 (data +  6, 0x0);
418 			GSF_LE_SET_GUINT16 (data + 10, idx_a);
419 			GSF_LE_SET_GUINT16 (data + 12, idx_b);
420 			write_cellref_v7 (pd, ref, data + 16, data + 14);
421 			ms_biff_put_var_write (pd->ewb->bp, data, 17);
422 		} else {
423 			guint16 extn_idx = excel_write_get_externsheet_idx (
424 						pd->ewb, ref->sheet, sheet_b);
425 			GSF_LE_SET_GUINT16 (data, extn_idx);
426 			write_cellref_v8 (pd, ref, data + 4, data + 2);
427 			ms_biff_put_var_write (pd->ewb->bp, data, 6);
428 		}
429 	}
430 }
431 
432 static void
excel_formula_write_AREA(PolishData * pd,GnmCellRef const * a,GnmCellRef const * b,XLOpType target_type)433 excel_formula_write_AREA (PolishData *pd, GnmCellRef const *a, GnmCellRef const *b,
434 			  XLOpType target_type)
435 {
436 	guint8 data[24];
437 	guint8 ptg;
438 	guint8 op_class = xl_get_op_class (pd, XL_REF, target_type);
439 
440 	if (a->sheet == NULL && b->sheet == NULL) {
441 
442 		if (!pd->allow_sheetless_ref) {
443 			g_warning ("XL does not support unqualified references in global names");
444 		}
445 
446 		ptg = (pd->use_name_variant &&
447 		       (a->col_relative || a->row_relative ||
448 			b->col_relative || b->row_relative))
449 			? FORMULA_PTG_AREAN : FORMULA_PTG_AREA;
450 		push_guint8 (pd, ptg + op_class);
451 		if (pd->ewb->bp->version <= MS_BIFF_V7) {
452 			write_cellref_v7 (pd, a, data + 4, data);
453 			write_cellref_v7 (pd, b, data + 5, data + 2);
454 			ms_biff_put_var_write (pd->ewb->bp, data, 6);
455 		} else {
456 			write_cellref_v8 (pd, a, data + 4, data + 0);
457 			write_cellref_v8 (pd, b, data + 6, data + 2);
458 			ms_biff_put_var_write (pd->ewb->bp, data, 8);
459 		}
460 		return;
461 	}
462 
463 	g_return_if_fail (a->sheet != NULL);
464 
465 	if (a->col != b->col || a->row != b->row ||
466 	    a->col_relative != b->col_relative ||
467 	    a->row_relative != b->row_relative) {
468 		g_return_if_fail (a->sheet != NULL);
469 
470 		push_guint8 (pd, FORMULA_PTG_AREA_3D + op_class);
471 		if (pd->ewb->bp->version <= MS_BIFF_V7) {
472 			guint16 idx_a, idx_b;
473 			gint16 ixals;
474 
475 			/* FIXME no external references for now */
476 			g_return_if_fail (pd->ewb->base.wb == a->sheet->workbook);
477 
478 			idx_a = a->sheet->index_in_wb;
479 			idx_b = (b->sheet != NULL)
480 				? b->sheet->index_in_wb : idx_a;
481 
482 			ixals = -(idx_a+1);
483 
484 			GSF_LE_SET_GUINT16 (data, ixals);
485 			GSF_LE_SET_GUINT32 (data +  2, 0x0);
486 			GSF_LE_SET_GUINT32 (data +  6, 0x0);
487 			GSF_LE_SET_GUINT16 (data + 10, idx_a);
488 			GSF_LE_SET_GUINT16 (data + 12, idx_b);
489 			write_cellref_v7 (pd, a, data + 18, data + 14);
490 			write_cellref_v7 (pd, b, data + 19, data + 16);
491 			ms_biff_put_var_write (pd->ewb->bp, data, 20);
492 		} else {
493 			guint16 extn_idx = excel_write_get_externsheet_idx (
494 						pd->ewb, a->sheet, b->sheet);
495 			GSF_LE_SET_GUINT16 (data, extn_idx);
496 			write_cellref_v8 (pd, a, data + 6, data + 2);
497 			write_cellref_v8 (pd, b, data + 8, data + 4);
498 			ms_biff_put_var_write (pd->ewb->bp, data, 10);
499 		}
500 	} else
501 		excel_formula_write_CELLREF (pd, a, b->sheet, target_type);
502 }
503 
504 static char *
guess_arg_types(GnmFunc * func)505 guess_arg_types (GnmFunc *func)
506 {
507 	char *res;
508 	int i, min, max;
509 
510 	if (!gnm_func_is_fixargs (func))
511 		return NULL;
512 
513 	gnm_func_count_args (func, &min, &max);
514 
515 	res = g_new (char, max + 1);
516 	res[max] = 0;
517 
518 	for (i = 0; i < max; i++) {
519 		char t = gnm_func_get_arg_type (func, i);
520 		if (t == 'r' || t == 'A')
521 			res[i] = 'A';
522 		else
523 			res[i] = 'V';
524 	}
525 
526 #if FORMULA_DEBUG > 1
527 	g_printerr ("Coming up with arg types for %s: %s\n",
528 		    func->name, res);
529 #endif
530 
531 	return res;
532 }
533 
534 static void
write_funcall(PolishData * pd,GnmExpr const * expr,XLOpType target_type)535 write_funcall (PolishData *pd, GnmExpr const *expr,
536 	       XLOpType target_type)
537 {
538 	static guint8 const zeros [12];
539 
540 	int arg, min_args, max_args, name_arg = 0;
541 	gboolean prompt   = FALSE;
542 	gboolean cmdequiv = FALSE;
543 	char const *arg_types = NULL;
544 	char *arg_types_holder = NULL;
545 	GnmFunc *func = expr->func.func;
546 	ExcelFunc *ef = g_hash_table_lookup (pd->ewb->function_map, func);
547 	XLOpType arg_type = XL_VAL; /* default */
548 	XLOpType func_type;
549 	int func_idx;
550 	guint8 op_class;
551 
552 	g_return_if_fail (ef != NULL);
553 
554 	if (ef->efunc) {
555 		min_args = ef->efunc->min_args;
556 		max_args = ef->efunc->max_args;
557 		func_idx = ef->efunc->idx;
558 		func_type = ef->efunc->type
559 			? xl_map_char_to_type (ef->efunc->type)
560 			: XL_VAL; // Assumption
561 		arg_types = ef->efunc->known_args;
562 	} else {
563 		min_args = max_args = expr->func.argc;
564 		func_idx = 0xff;
565 		func_type = XL_VAL;  /*Assumption */
566 	}
567 
568 	if (ef->efunc == NULL || ef->efunc->idx == 0xff) {
569 		if (ef->macro_name != NULL) {
570 			push_guint8 (pd, FORMULA_PTG_NAME);
571 			push_guint16 (pd, ef->idx);
572 			ms_biff_put_var_write (pd->ewb->bp, zeros,
573 				(pd->ewb->bp->version <= MS_BIFF_V7) ? 12 : 2);
574 		} else {
575 			push_guint8 (pd, FORMULA_PTG_NAME_X);
576 			if (pd->ewb->bp->version <= MS_BIFF_V7) {
577 				/* The Magic Addin entry is after the real sheets
578 				 * for globals (names that call addins) and
579 				 * for locals (fomulas that call addins) */
580 				push_gint16  (pd, pd->ewb->esheets->len + 1);
581 				ms_biff_put_var_write (pd->ewb->bp, zeros, 8);
582 				push_guint16 (pd, ef->idx);
583 				ms_biff_put_var_write (pd->ewb->bp, zeros, 12);
584 			} else {
585 				/* I write the Addin Magic entry 1st */
586 				push_guint16 (pd, 0);
587 				push_guint16 (pd, ef->idx);
588 				push_guint16 (pd, 0); /* reserved */
589 			}
590 		}
591 		name_arg = 1;
592 	}
593 
594 	if (!arg_types)
595 		arg_types = arg_types_holder = guess_arg_types (func);
596 	for (arg = 0; arg < expr->func.argc; arg++) {
597 		if (ef->efunc != NULL && arg >= ef->efunc->max_args) {
598 			go_io_warning (pd->ewb->io_context,
599 				_("Too many arguments for function '%s', MS Excel can only handle %d not %d"),
600 				ef->efunc->name, ef->efunc->max_args, expr->func.argc);
601 			break;
602 		} else { /* convert the args */
603 			if (arg_types != NULL && *arg_types) {
604 				arg_type = xl_map_char_to_type (*arg_types);
605 				if (arg_types[1])
606 					arg_types++;
607 			}
608 			write_node (pd, expr->func.argv[arg], 0, arg_type);
609 		}
610 	}
611 	/* If XL requires more arguments than we do
612 	 * pad the remainder with missing args */
613 	for ( ; arg < min_args ; arg++)
614 		push_guint8 (pd, FORMULA_PTG_MISSARG);
615 	g_free (arg_types_holder);
616 
617 	op_class = xl_get_op_class (pd, func_type, target_type);
618 	if (name_arg || min_args != max_args) {
619 		push_guint8  (pd, FORMULA_PTG_FUNC_VAR + op_class);
620 		push_guint8  (pd, (arg + name_arg) | (prompt ? 0x80 : 0));
621 		push_guint16 (pd, func_idx         | (cmdequiv ? 0x8000 : 0));
622 	} else {
623 		push_guint8  (pd, FORMULA_PTG_FUNC + op_class);
624 		push_guint16 (pd, func_idx);
625 	}
626 }
627 
628 static void
excel_formula_write_NAME_v8(PolishData * pd,GnmExpr const * expr,XLOpType target_type)629 excel_formula_write_NAME_v8 (PolishData *pd, GnmExpr const *expr,
630 			     XLOpType target_type)
631 {
632 	guint8 data [7];
633 	gpointer tmp;
634 	unsigned name_idx;
635 
636 	memset (data, 0, sizeof data);
637 
638 	tmp = g_hash_table_lookup (pd->ewb->names,
639 				   (gpointer)expr->name.name);
640 	g_return_if_fail (tmp != NULL);
641 
642 	name_idx = GPOINTER_TO_UINT (tmp);
643 	if (expr->name.optional_scope == NULL) {
644 		GSF_LE_SET_GUINT8  (data + 0, FORMULA_PTG_NAME +
645 			xl_get_op_class (pd, XL_REF, target_type));
646 		GSF_LE_SET_GUINT16 (data + 1, name_idx);
647 		ms_biff_put_var_write (pd->ewb->bp, data, 5);
648 	} else {
649 		guint16 extn_idx = excel_write_get_externsheet_idx (pd->ewb,
650 			expr->name.optional_scope, NULL);
651 		GSF_LE_SET_GUINT8  (data + 0, FORMULA_PTG_NAME_X +
652 			xl_get_op_class (pd, XL_REF, target_type));
653 		GSF_LE_SET_GUINT16 (data + 1, extn_idx);
654 		GSF_LE_SET_GUINT16 (data + 3, name_idx);
655 		ms_biff_put_var_write (pd->ewb->bp, data, 7);
656 	}
657 }
658 
659 static void
excel_formula_write_NAME_v7(PolishData * pd,GnmExpr const * expr,XLOpType target_type)660 excel_formula_write_NAME_v7 (PolishData *pd, GnmExpr const *expr,
661 			     XLOpType target_type)
662 {
663 	guint8 data [25];
664 	gpointer tmp;
665 	unsigned name_idx;
666 
667 	memset (data, 0, sizeof data);
668 
669 	tmp = g_hash_table_lookup (pd->ewb->names,
670 				   (gpointer)expr->name.name);
671 	g_return_if_fail (tmp != NULL);
672 
673 	name_idx = GPOINTER_TO_UINT (tmp);
674 	if (expr->name.optional_scope == NULL) {
675 		GSF_LE_SET_GUINT8  (data + 0, FORMULA_PTG_NAME +
676 			xl_get_op_class (pd, XL_REF, target_type));
677 		GSF_LE_SET_GUINT16 (data + 1, name_idx);
678 		ms_biff_put_var_write (pd->ewb->bp, data, 15);
679 	} else {
680 		int externsheet = (pd->sheet == expr->name.optional_scope)
681 			? (int) (pd->ewb->esheets->len + 1)
682 			: expr->name.optional_scope->index_in_wb;
683 		guint32 id = ++(pd->ewb->unique_name_id);
684 
685 		GSF_LE_SET_GUINT8  (data +  0, FORMULA_PTG_NAME_X +
686 			xl_get_op_class (pd, XL_REF, target_type));
687 		GSF_LE_SET_GUINT16 (data +  1, -(externsheet+1));
688 		GSF_LE_SET_GUINT16 (data + 11, name_idx);
689 		GSF_LE_SET_GUINT16 (data +  9,   1); /* undocumented marked 'reserved' */
690 		GSF_LE_SET_GUINT16 (data + 19, 0xf); /* undocumented marked 'reserved' */
691 		GSF_LE_SET_GUINT32 (data + 21, id); /* undocumented marked 'reserved' */
692 		ms_biff_put_var_write (pd->ewb->bp, data, 25);
693 	}
694 }
695 
696 static void
write_node(PolishData * pd,GnmExpr const * expr,int paren_level,XLOpType target_type)697 write_node (PolishData *pd, GnmExpr const *expr, int paren_level,
698 	    XLOpType target_type)
699 {
700 	static struct {
701 		guint8 xl_op;
702 		int prec;		      /* Precedences -- should match parser.y  */
703 		int assoc_left, assoc_right;  /* 0: no, 1: yes.  */
704 	} const operations [] = {
705 		{ FORMULA_PTG_PAREN,	 0, 0, 0 }, /* Parentheses for clarity  */
706 		{ FORMULA_PTG_EQUAL,	 1, 1, 0 },
707 		{ FORMULA_PTG_GT,	 1, 1, 0 },
708 		{ FORMULA_PTG_LT,	 1, 1, 0 },
709 		{ FORMULA_PTG_GTE,	 1, 1, 0 },
710 		{ FORMULA_PTG_LTE,	 1, 1, 0 },
711 		{ FORMULA_PTG_NOT_EQUAL, 1, 1, 0 },
712 		{ FORMULA_PTG_ADD,	 3, 1, 0 },
713 		{ FORMULA_PTG_SUB,	 3, 1, 0 },
714 		{ FORMULA_PTG_MULT,	 4, 1, 0 },
715 		{ FORMULA_PTG_DIV,	 4, 1, 0 },
716 		{ FORMULA_PTG_EXP,	 5, 0, 1 },
717 		{ FORMULA_PTG_CONCAT,	 2, 1, 0 },
718 		{ 0, 0, 0, 0 }, /* Funcall  */
719 		{ 0, 0, 0, 0 }, /* Name     */
720 		{ 0, 0, 0, 0 }, /* Constant */
721 		{ 0, 0, 0, 0 }, /* Var      */
722 		{ FORMULA_PTG_U_MINUS,	 7, 0, 0 }, /* Unary - */
723 		{ FORMULA_PTG_U_PLUS,	 7, 0, 0 }, /* Unary + */
724 		{ FORMULA_PTG_PERCENT,	 6, 0, 0 }, /* Percentage (NOT MODULO) */
725 		{ 0, 0, 0, 0 },	/* Array Corner   */
726 		{ 0, 0, 0, 0 },	/* Array Element  */
727 		{ 0, 8, 1, 0 }, /* Set      */
728 		{ FORMULA_PTG_RANGE,	 10, 1, 0 },
729 		{ FORMULA_PTG_INTERSECT, 9, 1, 0 }
730 	};
731 	const GnmExprOp op = GNM_EXPR_GET_OPER (expr);
732 
733 	switch (op) {
734 	case GNM_EXPR_OP_ANY_BINARY :
735 		if (target_type != XL_ARRAY)
736 			target_type = XL_VAL;
737 		/* Fall through.  */
738 	case GNM_EXPR_OP_RANGE_CTOR:
739 	case GNM_EXPR_OP_INTERSECT: {
740 		int const prec = operations[op].prec;
741 
742 		write_node (pd, expr->binary.value_a,
743 			    prec - operations[op].assoc_left,
744 			    target_type);
745 		write_node (pd, expr->binary.value_b,
746 			    prec - operations[op].assoc_right,
747 			    target_type);
748 		push_guint8 (pd, operations[op].xl_op);
749 		if (prec <= paren_level)
750 			push_guint8 (pd, FORMULA_PTG_PAREN);
751 		break;
752 	}
753 
754 	case GNM_EXPR_OP_FUNCALL :
755 		write_funcall (pd, expr, target_type);
756 		break;
757 
758         case GNM_EXPR_OP_CONSTANT : {
759 		GnmValue const *v = expr->constant.value;
760 		switch (v->v_any.type) {
761 
762 		case VALUE_FLOAT: {
763 			guint8 data[10];
764 			gnm_float f = value_get_as_float (v);
765 			int i;
766 
767 			if (f >= 0 && f <= 0xffff && f == (i = (int)f)) {
768 				GSF_LE_SET_GUINT8  (data, FORMULA_PTG_INT);
769 				GSF_LE_SET_GUINT16 (data + 1, i);
770 				ms_biff_put_var_write (pd->ewb->bp, data, 3);
771 			} else {
772 				GSF_LE_SET_GUINT8 (data, FORMULA_PTG_NUM);
773 				gsf_le_set_double (data + 1, f);
774 				ms_biff_put_var_write (pd->ewb->bp, data, 9);
775 			}
776 			break;
777 		}
778 		case VALUE_BOOLEAN : {
779 			guint8 data[2];
780 			GSF_LE_SET_GUINT8 (data, FORMULA_PTG_BOOL);
781 			GSF_LE_SET_GUINT8 (data+1, value_get_as_int (v));
782 			ms_biff_put_var_write (pd->ewb->bp, data, 2);
783 			break;
784 		}
785 
786 		case VALUE_ERROR : {
787 			guint8 data[2];
788 			GSF_LE_SET_GUINT8 (data, FORMULA_PTG_ERR);
789 			GSF_LE_SET_GUINT8 (data+1, excel_write_map_errcode (v));
790 			ms_biff_put_var_write (pd->ewb->bp, data, 2);
791 			break;
792 		}
793 
794 		case VALUE_EMPTY : {
795 			guint8 data = FORMULA_PTG_MISSARG;
796 			ms_biff_put_var_write (pd->ewb->bp, &data, 1);
797 			break;
798 		}
799 
800 		case VALUE_STRING:
801 			write_string (pd, value_peek_string (v));
802 			break;
803 
804 		case VALUE_CELLRANGE:
805 			excel_formula_write_AREA (pd,
806 				&v->v_range.cell.a, &v->v_range.cell.b,
807 				target_type);
808 			break;
809 
810 		case VALUE_ARRAY : {
811 			guint8 data[8];
812 
813 			if (v->v_array.x > 256 || v->v_array.y > 65536)
814 				g_warning ("Array far too big");
815 
816 			/* Class is A or V
817 			 * name == A
818 			 * target_type == 'V' ? 'V' : 'A'
819 			 **/
820 			GSF_LE_SET_GUINT8  (data + 0, FORMULA_PTG_ARRAY +
821 				xl_get_op_class (pd, XL_ARRAY, target_type));
822 			GSF_LE_SET_GUINT8  (data + 1, v->v_array.x - 1);
823 			GSF_LE_SET_GUINT16 (data + 2, v->v_array.y - 1);
824 			GSF_LE_SET_GUINT16 (data + 4, 0x0); /* ? */
825 			GSF_LE_SET_GUINT16 (data + 6, 0x0); /* ? */
826 			ms_biff_put_var_write (pd->ewb->bp, data, 8);
827 
828 			pd->arrays = g_slist_prepend (pd->arrays, (gpointer)v);
829 			break;
830 		}
831 
832 		default : {
833 			write_string (pd, "(Unknown value)");
834 			g_warning ("Unhandled value type %d", v->v_any.type);
835 			break;
836 		}
837 		}
838 		break;
839 	}
840 	case GNM_EXPR_OP_ANY_UNARY : {
841 		int const prec = operations[op].prec;
842 
843 		write_node (pd, expr->unary.value, operations[op].prec,
844 			(target_type != XL_ARRAY) ? XL_VAL : XL_ARRAY);
845 		push_guint8 (pd, operations[op].xl_op);
846 		if (op != GNM_EXPR_OP_PAREN && prec <= paren_level)
847 			push_guint8 (pd, FORMULA_PTG_PAREN);
848 		break;
849 	}
850 
851 	case GNM_EXPR_OP_CELLREF :
852 		excel_formula_write_CELLREF (pd,
853 			&expr->cellref.ref, NULL, target_type);
854 		break;
855 
856 	case GNM_EXPR_OP_NAME :
857 		if (pd->ewb->bp->version >= MS_BIFF_V8)
858 			excel_formula_write_NAME_v8 (pd, expr, target_type);
859 		else
860 			excel_formula_write_NAME_v7 (pd, expr, target_type);
861 		break;
862 
863 	case GNM_EXPR_OP_ARRAY_CORNER :
864 	case GNM_EXPR_OP_ARRAY_ELEM : {
865 		guint8 data[5];
866 		int x, y, ptg;
867 
868 		if (!gnm_expr_top_is_array_elem (pd->array_texpr, &x, &y))
869 			x = y = 0;
870 
871 		ptg = FORMULA_PTG_EXPR;
872 		if (pd->sheet != NULL) {
873 			GnmCell const *ccell =
874 				sheet_cell_get (pd->sheet, pd->col - x, pd->row - y);
875 			if (ccell &&
876 			    gnm_expr_top_is_array_corner (ccell->base.texpr) &&
877 			    gnm_expr_is_data_table (gnm_expr_top_get_array_expr (ccell->base.texpr), NULL, NULL))
878 				ptg = FORMULA_PTG_TBL;
879 		}
880 
881 		GSF_LE_SET_GUINT8 (data, ptg);
882 		GSF_LE_SET_GUINT16 (data+1, pd->row - y);
883 		GSF_LE_SET_GUINT16 (data+3, pd->col - x);
884 		ms_biff_put_var_write (pd->ewb->bp, data, 5);
885 
886 		/* Be anal */
887 		g_return_if_fail (paren_level == 0);
888 		break;
889 	}
890 
891 	case GNM_EXPR_OP_SET:
892 		if (expr->set.argc > 0) {
893 			int const prec = operations[op].prec;
894 			int i;
895 
896 			write_node (pd, expr->set.argv[0],
897 				    operations[op].assoc_left,
898 				    target_type);
899 
900 			for (i = 1; i < expr->set.argc; i++) {
901 				write_node (pd, expr->set.argv[i],
902 					    operations[op].assoc_right,
903 					    target_type);
904 				push_guint8 (pd, FORMULA_PTG_UNION);
905 			}
906 			if (prec <= paren_level)
907 				push_guint8 (pd, FORMULA_PTG_PAREN);
908 			break;
909 		}
910 		/* Fall through for now.  */
911 
912 	default : {
913 		gchar *err = g_strdup_printf ("Unknown Operator %d",
914 					      GNM_EXPR_GET_OPER (expr));
915 		write_string (pd, err);
916 		g_free (err);
917 		g_warning ("Unhandled expr type %d", GNM_EXPR_GET_OPER (expr));
918 		break;
919 	}
920 	}
921 }
922 
923 /* Writes the array and moves to next one */
924 /* See S59E2B.HTM for some really duff docs */
925 static void
write_arrays(PolishData * pd)926 write_arrays (PolishData *pd)
927 {
928 	GnmValue const *array;
929 	GSList  *ptr;
930 	int	 x, y;
931 	guint8   data[8];
932 	WriteStringFlags string_flags;
933 
934 	string_flags = (pd->ewb->bp->version >= MS_BIFF_V8)
935 		? STR_TWO_BYTE_LENGTH : STR_ONE_BYTE_LENGTH;
936 	pd->arrays = g_slist_reverse (pd->arrays);
937 	for (ptr = pd->arrays ; ptr != NULL ; ptr = ptr->next) {
938 		array = ptr->data;
939 		if (pd->ewb->bp->version >= MS_BIFF_V8) {
940 			push_guint8  (pd, array->v_array.x - 1);
941 			push_guint16 (pd, array->v_array.y - 1);
942 		} else {
943 			push_guint8  (pd, (array->v_array.x == 256)
944 				      ? 0 : array->v_array.x);
945 			push_guint16 (pd, array->v_array.y);
946 		}
947 
948 		for (y = 0; y < array->v_array.y; y++) {
949 			for (x = 0; x < array->v_array.x; x++) {
950 				GnmValue const *v = array->v_array.vals[x][y];
951 
952 				if (VALUE_IS_EMPTY (v)) {
953 					push_guint8 (pd, 0);
954 					push_guint32 (pd, 0);
955 					push_guint32 (pd, 0);
956 				} else if (VALUE_IS_BOOLEAN (v)) {
957 					push_guint8 (pd, 4);
958 					push_guint32 (pd, value_get_as_int (v));
959 					push_guint32 (pd, 0);
960 				} else if (VALUE_IS_ERROR (v)) {
961 					push_guint8 (pd, 16);
962 					push_guint32 (pd, excel_write_map_errcode (v));
963 					push_guint32 (pd, 0);
964 				} else if (VALUE_IS_FLOAT (v)) {
965 					push_guint8 (pd, 1);
966 					gsf_le_set_double (data, value_get_as_float (v));
967 					ms_biff_put_var_write (pd->ewb->bp, data, 8);
968 				} else { /* Can only be a string */
969 					push_guint8 (pd, 2);
970 					excel_write_string (pd->ewb->bp, string_flags,
971 						value_peek_string (v));
972 				}
973 			}
974 		}
975 	}
976 
977 	g_slist_free (pd->arrays);
978 	pd->arrays = NULL;
979 }
980 
981 guint32
excel_write_array_formula(ExcelWriteState * ewb,GnmExprTop const * texpr,Sheet * sheet,int fn_col,int fn_row)982 excel_write_array_formula (ExcelWriteState *ewb,
983 			   GnmExprTop const *texpr,
984 			   Sheet *sheet, int fn_col, int fn_row)
985 {
986 	PolishData pd;
987 	unsigned start;
988 	guint32 len;
989 
990 	g_return_val_if_fail (ewb, 0);
991 	g_return_val_if_fail (texpr, 0);
992 
993 	pd.col     = fn_col;
994 	pd.row     = fn_row;
995 	pd.sheet   = sheet;
996 	pd.ewb     = ewb;
997 	pd.arrays  = NULL;
998 	pd.array_texpr = texpr;
999 	pd.context = CTXT_ARRAY;
1000 	pd.use_name_variant = FALSE;
1001 	pd.allow_sheetless_ref = TRUE;
1002 
1003 	start = ewb->bp->curpos;
1004 	write_node (&pd, gnm_expr_top_get_array_expr (texpr), 0, XL_ROOT);
1005 	len = ewb->bp->curpos - start;
1006 
1007 	write_arrays (&pd);
1008 
1009 	return len;
1010 }
1011 
1012 /*
1013  * This is called for all expressions, including array expressions.
1014  * (But write_node will not write the inner expression for arrays.)
1015  */
1016 guint32
excel_write_formula(ExcelWriteState * ewb,GnmExprTop const * texpr,Sheet * sheet,int fn_col,int fn_row,ExcelFuncContext context)1017 excel_write_formula (ExcelWriteState *ewb, GnmExprTop const *texpr,
1018 		     Sheet *sheet, int fn_col, int fn_row,
1019 		     ExcelFuncContext context)
1020 {
1021 	PolishData pd;
1022 	unsigned start;
1023 	guint32 len;
1024 	XLOpType target = XL_ROOT;
1025 
1026 	g_return_val_if_fail (ewb, 0);
1027 	g_return_val_if_fail (texpr, 0);
1028 
1029 	pd.col     = fn_col;
1030 	pd.row     = fn_row;
1031 	pd.sheet   = sheet;
1032 	pd.ewb     = ewb;
1033 	pd.arrays  = NULL;
1034 	pd.allow_sheetless_ref = TRUE;
1035 
1036 	if (gnm_expr_top_is_array_corner (texpr) ||
1037 	    gnm_expr_top_is_array_elem (texpr, NULL, NULL))
1038 		pd.array_texpr = texpr;
1039 	else
1040 		pd.array_texpr = NULL;
1041 
1042 	switch (context) {
1043 	case EXCEL_CALLED_FROM_CELL:
1044 		pd.context = CTXT_CELL;
1045 		pd.use_name_variant = FALSE;
1046 		break;
1047 	case EXCEL_CALLED_FROM_SHARED:
1048 		pd.context = CTXT_CELL;
1049 		pd.use_name_variant = TRUE;
1050 		break;
1051 	case EXCEL_CALLED_FROM_NAME:
1052 		pd.context = CTXT_NAME_OBJ;
1053 		pd.use_name_variant = TRUE;
1054 		pd.allow_sheetless_ref = FALSE;
1055 		break;
1056 	case EXCEL_CALLED_FROM_OBJ:
1057 		pd.context = CTXT_NAME_OBJ;
1058 		pd.use_name_variant = TRUE;
1059 		break;
1060 	case EXCEL_CALLED_FROM_VALIDATION_LIST:
1061 		pd.context = CTXT_ARRAY;
1062 		pd.use_name_variant = TRUE;
1063 		target = XL_REF;
1064 		break;
1065 	case EXCEL_CALLED_FROM_CONDITION:
1066 	case EXCEL_CALLED_FROM_VALIDATION:
1067 	default:
1068 		pd.context = CTXT_ARRAY; /* What???  */
1069 		pd.use_name_variant = TRUE;
1070 	}
1071 
1072 	start = ewb->bp->curpos;
1073 	write_node (&pd, texpr->expr, 0, target);
1074 	len = ewb->bp->curpos - start;
1075 
1076 	write_arrays (&pd);
1077 
1078 	return len;
1079 }
1080