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