1 /*
2 * $Id: sylk.c,v 1.18 2000/08/10 21:02:51 danny Exp $
3 *
4 * Copyright � 1990, 1992, 1993 Free Software Foundation, Inc.
5 *
6 * This file is part of Oleo, the GNU Spreadsheet.
7 *
8 * Oleo is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * Oleo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Oleo; see the file COPYING. If not, write to
20 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #ifdef WITH_DMALLOC
28 #include <dmalloc.h>
29 #endif
30
31 #include "funcdef.h"
32 #include <stdio.h>
33 #include <ctype.h>
34 #include "sysdef.h"
35 #include "io-generic.h"
36 #include "io-abstract.h"
37 #include "global.h"
38 #include "cell.h"
39 #include "line.h"
40 #include "io-term.h"
41 #include "lists.h"
42 #include "io-utils.h"
43 #include "ref.h"
44 #include "regions.h"
45 #include "window.h"
46 #include "info.h"
47 #include "cmd.h"
48
49
50 /* Forward declaration */
51 static char * sylk_to_oleo_functions(char *f);
52
53 #define SYLK_LEN 1024
54
55 /* FIX ME Where does this variable belong ?? */
56 static int nformat = 0; /* We've already read this many formats */
57 /*
58 * These functions read and write Microsoft Multiplan SYLK style files
59 * as well as SYLK-NOA0 files. SYLK-NOA0 is the same as SYLK except that
60 * cell references are in rc format instead of a0 format.
61 */
62
63 void
sylk_read_file(fp,ismerge)64 sylk_read_file (fp, ismerge)
65 FILE *fp;
66 int ismerge;
67 {
68 char *ptr;
69 CELLREF crow = 0, ccol = 0, czrow = 0, czcol = 0;
70 int lineno;
71 char cbuf[SYLK_LEN];
72 char expbuf[SYLK_LEN];
73 char *vname, *vval;
74 int vlen = 0;
75 int cprot;
76 char *cexp, *cval;
77 CELL *cp;
78 struct rng rng;
79 int fmt = 0, prc = 0;
80 int jst = 0;
81 long mx_row = MAX_ROW, mx_col = MAX_COL;
82 int next_a0;
83 int old_a0;
84 int num;
85
86 old_a0 = Global->a0;
87 next_a0 = old_a0;
88 Global->a0 = Global->sylk_a0;
89
90 lineno = 0;
91 if (!ismerge)
92 clear_spreadsheet ();
93 while (fgets (cbuf, sizeof (cbuf), fp))
94 {
95 lineno++;
96 #if 0
97 if (lineno % 50 == 0)
98 io_info_msg ("Line %d", lineno);
99 #endif
100
101 /* Remove newline */
102 if ((ptr = (char *)index (cbuf, '\n')))
103 *ptr = '\0';
104
105 /* Also remove DOS style newline */
106 if ((ptr = (char *)index (cbuf, '\r')))
107 *ptr = '\0';
108
109 ptr = cbuf;
110
111 /*
112 * The first character on each line
113 */
114 switch (*ptr) {
115 /* First character on the line */
116 case 'I': /* ID field, ignored */
117 if (ptr[1] != 'D' || ptr[2] != ';')
118 goto bad_field;
119 if (strcmp(ptr+4, "OLEO") != 0) {
120 if (strncmp(ptr+4, "WXL", 3) == 0)
121 io_info_msg("Reading SYLK file from Windows Excel\n");
122 else
123 io_info_msg("Reading SYLK file from '%s'\n", ptr+4);
124 }
125 break;
126
127 /* First character on the line */
128 case 'F': /* Format field */
129 vlen = 0;
130 ptr++;
131 while (*ptr) {
132 if (*ptr != ';')
133 goto bad_field;
134 ptr++;
135
136 /* Format field, second code
137 * F;P0;DG0G8;M264
138 * ^
139 */
140 switch (*ptr++) {
141 int clo, chi, cwid;
142 /* Format next field code */
143 case 'C': /* Column from rows 1 to 255 */
144 czcol = astol (&ptr);
145 vlen = 2;
146 break;
147
148 /* Format next field code */
149 case 'D': /* Default format */
150 switch (*ptr++) {
151 case 'G':
152 default_fmt = FMT_GEN;
153 break;
154 case 'E':
155 default_fmt = FMT_EXP;
156 break;
157 case 'F':
158 default_fmt = FMT_FXT;
159 break;
160 case '$':
161 default_fmt = FMT_DOL;
162 break;
163 case '*': /* * format implemented as +- format */
164 default_fmt = FMT_GPH;
165 break;
166 case ',': /* JF */
167 default_fmt = FMT_CMA;
168 break;
169 case 'U':
170 default_fmt = FMT_USR;
171 break;
172 case '%':
173 default_fmt = FMT_PCT;
174 break;
175 case 'H':
176 default_fmt = FMT_HID;
177 break;
178 /* End of JF */
179 case 'C': /* Continuous not supported */
180 default:
181 io_error_msg ("Line %d: format %c not supported", lineno, ptr[-1]);
182 break;
183 }
184
185 if (*ptr == 'F')
186 {
187 default_prc = FLOAT_PRECISION;
188 ptr++;
189 }
190 else
191 default_prc = astol (&ptr);
192
193 /* Justification */
194 switch (*ptr++) {
195 case 'C':
196 default_jst = JST_CNT;
197 break;
198 case 'L':
199 default_jst = JST_LFT;
200 break;
201 case 'R':
202 default_jst = JST_RGT;
203 break;
204 case 'G': /* General format not supported */
205 /* FIX ME this is also in Excel */
206 break;
207 default:
208 io_error_msg ("Line %d: Alignment %c not supported\n", lineno, ptr[-1]);
209 break;
210 }
211 default_width = astol (&ptr);
212 break;
213
214 /* Format next field code */
215 case 'F':
216 switch (*ptr++)
217 {
218 case 'D':
219 fmt = FMT_DEF;
220 break;
221 case 'G':
222 fmt = FMT_GEN;
223 break;
224 case 'E':
225 fmt = FMT_EXP;
226 break;
227 case 'F':
228 fmt = FMT_FXT;
229 break;
230 case '$':
231 fmt = FMT_DOL;
232 break;
233 case '*': /* JF implemented as +- format */
234 fmt = FMT_GPH;
235 break;
236 case ',': /* JF */
237 fmt = FMT_CMA;
238 break;
239 case 'U':
240 fmt = FMT_USR;
241 break;
242 case '%':
243 fmt = FMT_PCT;
244 break;
245 case 'H':
246 fmt = FMT_HID;
247 break; /* END of JF */
248 case 'C':
249 default:
250 io_error_msg ("Line %d: format %c not supported", lineno, ptr[-1]);
251 fmt = FMT_DEF;
252 break;
253 }
254
255 if (*ptr == 'F')
256 {
257 prc = FLOAT_PRECISION;
258 ptr++;
259 }
260 else
261 prc = astol (&ptr);
262
263 switch (*ptr++)
264 {
265 case 'C':
266 jst = JST_CNT;
267 break;
268 case 'L':
269 jst = JST_LFT;
270 break;
271 case 'R':
272 jst = JST_RGT;
273 break;
274 case 'D':
275 jst = JST_DEF;
276 break;
277 case 'G':
278 break;
279 default:
280 io_error_msg ("Line %d: Alignment %c not supported", lineno, ptr[-1]);
281 jst = JST_DEF;
282 break;
283 }
284 vlen = 1;
285 break;
286
287 /* Format next field code */
288 case 'R': /* Row from cols 1 to 63 */
289 czrow = astol (&ptr);
290 vlen = 4;
291 break;
292
293 /* Format next field code */
294 case 'W': /* Width of clo to chi is cwid */
295 clo = astol (&ptr);
296 chi = astol (&ptr);
297 cwid = astol (&ptr) + 1;
298 for (; clo <= chi; clo++)
299 set_width (clo, cwid);
300 break;
301
302 /* Format next field code */
303 case 'H': /* JF: extension */
304 clo = astol (&ptr);
305 chi = astol (&ptr);
306 cwid = astol (&ptr) + 1;
307 for (; clo <= chi; clo++)
308 set_height (clo, cwid);
309 break;
310
311 /* Format next field code */
312 case 'X':
313 ccol = astol (&ptr);
314 break;
315
316 /* Format next field code */
317 case 'Y':
318 crow = astol (&ptr);
319 break;
320
321 default:
322 goto bad_field;
323
324 case 'P': /* FIX ME Excel */
325 num = 0;
326 while (*ptr && *ptr != ';') {
327 if (isdigit(*ptr))
328 num = num * 10 + *ptr - '0'; /* ASCII */
329 ptr++;
330 }
331 break;
332
333 case 'M': /* FIX ME Excel */
334 while (*ptr && *ptr != ';') ptr++;
335 break;
336
337 case 'S': /* FIX ME Excel */
338 while (*ptr && *ptr != ';') ptr++;
339 break;
340 }
341 }
342
343 switch (vlen)
344 {
345 case 1:
346 cp = find_or_make_cell (crow, ccol);
347 SET_FORMAT (cp, fmt);
348 SET_PRECISION(cp, prc);
349 SET_JST (cp, jst);
350 break;
351 case 2:
352 rng.lr = MIN_ROW;
353 rng.lc = czcol;
354 rng.hr = mx_row;
355 rng.hc = czcol;
356 make_cells_in_range (&rng);
357 while ((cp = next_cell_in_range ()))
358 {
359 SET_FORMAT (cp, fmt);
360 SET_PRECISION(cp, prc);
361 SET_JST (cp, jst);
362 }
363 break;
364 case 4:
365 rng.lr = czrow;
366 rng.lc = MIN_COL;
367 rng.hr = czrow;
368 rng.hc = mx_col;
369 make_cells_in_range (&rng);
370 while ((cp = next_cell_in_range ()))
371 {
372 SET_FORMAT (cp, fmt);
373 SET_PRECISION(cp, prc);
374 SET_JST (cp, jst);
375 }
376 break;
377 default:
378 break;
379 }
380
381 break;
382
383 /* First character on the line */
384 case 'B': /* Boundry field, ignored */
385 ptr++;
386 while (*ptr) {
387 if (*ptr != ';')
388 goto bad_field;
389 ptr++;
390 switch (*ptr++) {
391 case 'X':
392 mx_col = astol (&ptr);
393 if (mx_col > MAX_COL)
394 {
395 io_error_msg ("Boundry column %lu too large!", mx_col);
396 mx_col = MAX_COL;
397 }
398 break;
399 case 'Y':
400 mx_row = astol (&ptr);
401 if (mx_row > MAX_ROW)
402 {
403 io_error_msg ("Boundry row %lu too large!", mx_row);
404 mx_row = MAX_ROW;
405 }
406 break;
407 case 'D': /* FIX ME Excel */
408 while (*ptr && *ptr != ';') ptr++;
409 break;
410 default:
411 goto bad_field;
412 }
413 }
414 break;
415
416 /* First character on the line */
417 case 'N': /* A Name field */
418 if (ptr[1] != 'N')
419 goto bad_field;
420 ptr += 2;
421 vname = 0;
422 vval = 0;
423 while (*ptr)
424 {
425 if (*ptr != ';')
426 goto bad_field;
427 *ptr++ = '\0';
428 switch (*ptr++)
429 {
430 case 'N': /* Name is */
431 vname = ptr;
432 while (*ptr && *ptr != ';')
433 ptr++;
434 vlen = ptr - vname;
435 break;
436 case 'E': /* Expression is */
437 vval = ptr;
438 while (*ptr && *ptr != ';')
439 ptr++;
440 break;
441 default:
442 --ptr;
443 goto bad_field;
444 }
445 }
446 if (!vname || !vval)
447 goto bad_field;
448 *ptr = '\0';
449 ptr = old_new_var_value (vname, vlen, vval);
450 if (ptr)
451 io_error_msg ("Line %d: Couldn't set %.*s to %s: %s", lineno, vlen, vname, vval, ptr);
452 break;
453
454 /* First character on the line */
455 case 'C': /* A Cell entry */
456 cprot = 0;
457 cval = 0;
458 cexp = 0;
459 cval = 0;
460 ptr++;
461 while (*ptr)
462 {
463 int quotes;
464
465 if (*ptr != ';')
466 goto bad_field;
467 *ptr++ = '\0';
468 switch (*ptr++)
469 {
470 case 'X':
471 ccol = astol (&ptr);
472 break;
473 case 'Y':
474 crow = astol (&ptr);
475 break;
476 case 'R':
477 czrow = astol (&ptr);
478 break;
479 case 'C':
480 czcol = astol (&ptr);
481 break;
482 case 'P': /* This cell is Protected */
483 cprot++;
484 break;
485 case 'K': /* This cell's Konstant value */
486 cval = ptr;
487 quotes = 0;
488 while (*ptr && (*ptr != ';' || quotes > 0))
489 if (*ptr++ == '"')
490 quotes = !quotes;
491 break;
492 case 'E': /* This cell's Expression */
493 cexp = ptr;
494 quotes = 0;
495 while (*ptr && (*ptr != ';' || quotes > 0))
496 if (*ptr++ == '"')
497 quotes = !quotes;
498
499 break;
500 case 'G':
501 strcpy (expbuf, cval);
502 break;
503 case 'D':
504 strcpy (expbuf, cexp);
505 break;
506 case 'S':
507 cexp = expbuf;
508 break;
509 default:
510 --ptr;
511 goto bad_field;
512 }
513 }
514 *ptr = '\0';
515 if (cexp && cval && strcmp (cexp, cval))
516 {
517 cexp = sylk_to_oleo_functions(cexp);
518 ptr = read_new_value (crow, ccol, cexp, cval);
519 if (ptr)
520 {
521 io_error_msg ("Line %d: %d,%d: Read '%s' %s", lineno, crow, ccol, cexp, ptr);
522 break;
523 }
524 }
525 else if (cval)
526 {
527 ptr = read_new_value (crow, ccol, 0, cval);
528 if (ptr)
529 {
530 io_error_msg ("Line %d: %d,%d: Val '%s' %s", lineno, crow, ccol, cexp, ptr);
531 break;
532 }
533 }
534 else if (cexp)
535 {
536 cexp = sylk_to_oleo_functions(cexp);
537 ptr = read_new_value (crow, ccol, cexp, 0);
538 if (ptr)
539 {
540 io_error_msg ("Line %d: %d,%d: Exp '%s' %s", lineno, crow, ccol, cexp, ptr);
541 break;
542 }
543 }
544 if (cprot)
545 SET_LCK (find_or_make_cell (crow, ccol), LCK_LCK);
546 if (ismerge)
547 push_cell (crow, ccol);
548 /* ... */
549 break;
550
551 /* First character on the line */
552 case 'E':
553 break;
554
555 /* First character on the line */
556 case 'W':
557 io_read_window_config (ptr + 2);
558 break;
559
560 /* First character on the line */
561 case 'U':
562 /* JF extension: read user-defined formats */
563 read_mp_usr_fmt (ptr + 1);
564 break;
565
566 /* First character on the line */
567 case 'O':
568 /* JF extension: read uset-settable options */
569 Global->a0 = next_a0;
570
571 #if 0
572 /* FIX ME
573 This is madness; options from SYLK should be translated into Oleo
574 internals before passing them to general option processing.
575 */
576 read_mp_options (ptr + 2);
577 #endif
578 next_a0 = Global->a0;
579 Global->a0 = Global->sylk_a0;
580 break;
581
582 /* First character on the line */
583 default:
584 bad_field:
585 Global->a0 = old_a0;
586 if (!ismerge)
587 clear_spreadsheet ();
588 io_recenter_all_win ();
589 io_error_msg ("Line %d: Unknown SYLK line \"%s\" (field %c)", lineno, cbuf, *ptr);
590 return;
591
592 /* First character on the line */
593 case 'P': /* FIX ME Excel */
594 /* Probably define a format */
595 nformat++;
596 fprintf(stderr, "Format %d is %s\n", nformat, ptr);
597 break;
598 }
599 }
600 Global->a0 = next_a0;
601 io_recenter_all_win ();
602 }
603
604
605
606 static char *
sylk_fmt_to_str(int f1,int p1)607 sylk_fmt_to_str (int f1, int p1)
608 {
609 static char p_buf[40];
610
611 p_buf[1] = '\0';
612 switch (f1)
613 {
614 case FMT_DEF:
615 p_buf[0] = 'D';
616 break;
617 case FMT_HID:
618 p_buf[0] = 'H';
619 break;
620 case FMT_GPH:
621 p_buf[0] = '*';
622 break;
623 default:
624 if (p1 == FLOAT_PRECISION)
625 {
626 p_buf[1] = 'F';
627 p_buf[2] = '\0';
628 }
629 else
630 sprintf (&p_buf[1], "%d", p1);
631
632 switch (f1)
633 {
634 case FMT_USR:
635 p_buf[0] = 'U';
636 break;
637 case FMT_GEN:
638 p_buf[0] = 'G';
639 break;
640 case FMT_DOL:
641 p_buf[0] = '$';
642 break;
643 case FMT_PCT:
644 p_buf[0] = '%';
645 break;
646 case FMT_FXT:
647 p_buf[0] = 'F';
648 break;
649 case FMT_CMA:
650 p_buf[0] = ',';
651 break;
652 case FMT_EXP:
653 p_buf[0] = 'E';
654 break;
655 default:
656 p_buf[0] = '?';
657 break;
658 }
659 break;
660 }
661 return p_buf;
662 }
663
664 static char
jst_to_chr(just)665 jst_to_chr (just)
666 int just;
667 {
668 switch (just)
669 {
670 case JST_DEF:
671 return 'D';
672 case JST_LFT:
673 return 'L';
674 case JST_RGT:
675 return 'R';
676 case JST_CNT:
677 return 'C';
678 default:
679 return '?';
680 }
681 }
682
683 static FILE *sylk_fp;
684 static struct rng *sylk_rng;
685
686 static void
sylk_write_var(name,var)687 sylk_write_var (name, var)
688 char *name;
689 struct var *var;
690 {
691 if (var->var_flags == VAR_UNDEF && (!var->var_ref_fm || var->var_ref_fm->refs_used == 0))
692 return;
693 switch (var->var_flags)
694 {
695 case VAR_UNDEF:
696 break;
697 case VAR_CELL:
698 if (var->v_rng.lr >= sylk_rng->lr && var->v_rng.lr <= sylk_rng->hr && var->v_rng.lc >= sylk_rng->lc && var->v_rng.lc <= sylk_rng->hc)
699 (void) fprintf (sylk_fp, "NN;N%s;E%s\n", var->var_name, cell_name (var->v_rng.lr, var->v_rng.lc));
700 break;
701 case VAR_RANGE:
702 if (var->v_rng.lr < sylk_rng->lr || var->v_rng.hr > sylk_rng->hr || var->v_rng.lc < sylk_rng->lc || var->v_rng.hc > sylk_rng->hc)
703 break;
704
705 (void) fprintf (sylk_fp, "NN;N%s;E%s\n", var->var_name, range_name (&(var->v_rng)));
706 break;
707 #ifdef TEST
708 default:
709 panic ("Unknown var type %d", var->var_flags);
710 #endif
711 }
712 }
713
714 static void
write_mp_windows(fp)715 write_mp_windows (fp)
716 FILE *fp;
717 {
718 struct line line;
719 line.alloc = 0;
720 line.buf = 0;
721 io_write_window_config (&line);
722 fputs (line.buf, fp);
723 free (line.buf);
724 }
725
726 void
sylk_write_file(fp,rng)727 sylk_write_file (fp, rng)
728 FILE *fp;
729 struct rng *rng;
730 {
731 CELLREF r, c;
732 CELL *cp;
733 CELLREF crow = 0, ccol = 0;
734 unsigned short w;
735
736 /* struct var *var; */
737 int old_a0;
738
739 (void) fprintf (fp, "ID;POLEO\n");
740
741 /* If no range given, write the entire file */
742 if (!rng)
743 {
744 int n;
745 int fmts;
746 char *data[9];
747
748 rng = &all_rng;
749
750 (void) fprintf (fp, "F;D%s%c%u\n", sylk_fmt_to_str (default_fmt, default_prc),
751 jst_to_chr (default_jst), default_width);
752
753 fmts = usr_set_fmts ();
754 for (n = 0; n < 16; n++)
755 {
756 if (fmts & (1 << n))
757 {
758 get_usr_stats (n, data);
759 fprintf (fp, "U;N%u;P%s;S%s", n + 1, data[7], data[8]);
760 if (data[0][0])
761 fprintf (fp, ";HP%s", data[0]);
762 if (data[1][0])
763 fprintf (fp, ";HN%s", data[1]);
764 if (data[2][0])
765 fprintf (fp, ";TP%s", data[2]);
766 if (data[3][0])
767 fprintf (fp, ";TN%s", data[3]);
768 if (data[4][0])
769 fprintf (fp, ";Z%s", data[4]);
770 if (data[5][0])
771 fprintf (fp, ";C%s", data[5]);
772 if (data[6])
773 fprintf (fp, ";D%s", data[6]);
774 putc ('\n', fp);
775 }
776 }
777 write_mp_options (fp);
778
779 (void) fprintf (fp, "B;Y%u;X%u\n", highest_row (), highest_col ());
780
781 }
782
783 old_a0 = Global->a0;
784 Global->a0 = Global->sylk_a0;
785
786 find_widths (rng->lc, rng->hc);
787 w = next_width (&c);
788 while (w)
789 {
790 CELLREF cc, ccc;
791 unsigned short ww;
792 cc = c;
793 do
794 ww = next_width (&ccc);
795 while (ccc == ++cc && ww == w);
796 (void) fprintf (fp, "F;W%u %u %u\n", c, cc - 1, w - 1);
797 c = ccc;
798 w = ww;
799 }
800
801 find_heights (rng->lr, rng->hr);
802 w = next_height (&c);
803 while (w)
804 {
805 CELLREF rr, rrr;
806 unsigned short ww;
807
808 rr = r;
809 do
810 ww = next_height (&rrr);
811 while (rrr == ++rr && ww == w);
812 (void) fprintf (fp, "F;H%u %u %u\n", r, rr - 1, w - 1);
813 r = rrr;
814 w = ww;
815 }
816
817 sylk_fp = fp;
818 sylk_rng = rng;
819 for_all_vars (sylk_write_var);
820 find_cells_in_range (rng);
821 while ((cp = next_row_col_in_range (&r, &c)))
822 {
823 char *ptr;
824 int f1, j1;
825 char p_buf[40];
826
827 f1 = GET_FORMAT (cp);
828 j1 = GET_JST (cp);
829 if (f1 != FMT_DEF || j1 != JST_DEF)
830 {
831 (void) fprintf (fp, "F;");
832 if (c != ccol)
833 {
834 (void) fprintf (fp, "X%u;", c);
835 ccol = c;
836 }
837 if (r != crow)
838 {
839 (void) fprintf (fp, "Y%u;", r);
840 crow = r;
841 }
842 (void) fprintf (fp, "F%s%c\n", sylk_fmt_to_str (f1, GET_PRECISION(cp)), jst_to_chr (j1));
843 }
844
845 if (!GET_TYP (cp) && !cp->cell_formula)
846 continue;
847
848 (void) fprintf (fp, "C;");
849 if (c != ccol)
850 {
851 (void) fprintf (fp, "X%u;", c);
852 ccol = c;
853 }
854 if (r != crow)
855 {
856 (void) fprintf (fp, "Y%u;", r);
857 crow = r;
858 }
859
860 if (cp->cell_formula)
861 {
862 (void) fprintf (fp, "E%s", decomp (r, c, cp));
863 decomp_free ();
864 }
865
866 switch (GET_TYP (cp))
867 {
868 case 0:
869 ptr = 0;
870 break;
871 case TYP_STR:
872 ptr = 0;
873 if (cp->cell_formula)
874 putc (';', fp);
875 (void) fprintf (fp, "K\"%s\"", cp->cell_str);
876 break;
877 case TYP_FLT:
878 ptr = flt_to_str (cp->cell_flt);
879 break;
880 case TYP_INT:
881 sprintf (p_buf, "%ld", cp->cell_int);
882 ptr = p_buf;
883 break;
884 case TYP_BOL:
885 ptr = bname[cp->cell_bol];
886 break;
887 case TYP_ERR:
888 ptr = ename[cp->cell_err];
889 break;
890 default:
891 ptr = 0;
892 #ifdef TEST
893 panic ("What cell type %d", GET_TYP (cp));
894 #endif
895 }
896
897 if (ptr)
898 {
899 if (cp->cell_formula)
900 putc (';', fp);
901 (void) fprintf (fp, "K%s", ptr);
902 }
903 if (GET_LCK (cp) == LCK_LCK)
904 (void) fprintf (fp, ";P");
905
906 putc ('\n', fp);
907 }
908
909 if (rng == &all_rng)
910 write_mp_windows (fp);
911
912 (void) fprintf (fp, "E\n");
913 Global->a0 = old_a0;
914 }
915
916 int
sylk_set_options(set_opt,option)917 sylk_set_options (set_opt, option)
918 int set_opt;
919 char *option;
920 {
921 return -1;
922 }
923
924 void
sylk_show_options()925 sylk_show_options ()
926 {
927 io_text_line ("File format: sylk (Microsoft Multiplan interchange format)");
928 }
929
930 /*
931 * Function mapping table
932 *
933 * This table contains the conversion from SYLK to Oleo functions.
934 *
935 * FIX ME this is far from complete
936 */
937 static struct {
938 char *sylk,
939 *oleo;
940 } sylk2oleo [] = {
941 { "SUM", "sum" },
942 { "PRODUCT", "prod" },
943 { "AVERAGE", "avg" },
944 { "AVERAGE", "std" },
945 { "MAX", "max" },
946 { "MIN", "min" },
947 { "COUNT", "count" },
948 { "COUNT", "var" },
949 { "ABS", "abs" },
950 { NULL, NULL }
951 };
952
953 static char *
sylk_to_oleo_functions(char * f)954 sylk_to_oleo_functions(char *f)
955 {
956 static char buf[SYLK_LEN];
957 char *p, *q;
958 int i, j, done;
959
960 for (p=f, q=buf; *p; p++) {
961 done = 0;
962 for (i=0; sylk2oleo[i].sylk; i++) {
963 int ls = strlen(sylk2oleo[i].sylk);
964 if (strncmp(p, sylk2oleo[i].sylk, ls) == 0) {
965 int lo = strlen(sylk2oleo[i].oleo);
966
967 p += ls - 1;
968 for (j=0; j<lo; j++)
969 *(q++) = sylk2oleo[i].oleo[j];
970 done = 1;
971 break;
972 }
973 }
974
975 if (! done)
976 *(q++) = *p;
977 *q = '\0';
978 }
979 #if 0
980 fprintf(stderr, "Sylk2Oleo(%s) -> '%s'\n", f, buf);
981 #endif
982 return buf;
983 }
984