1 /*
2  * $Id: oleofile.c,v 1.26 2001/02/13 23:38:06 danny Exp $
3  *
4  * Copyright � 1990-2000, 2001 Free Software Foundation, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this software; see the file COPYING.  If not, write to
18  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #ifdef	WITH_DMALLOC
26 #include <dmalloc.h>
27 #endif
28 
29 #include "funcdef.h"
30 #include <stdio.h>
31 #include <ctype.h>
32 #include "sysdef.h"
33 #include "io-generic.h"
34 #include "io-abstract.h"
35 #include "io-utils.h"
36 #include "io-term.h"
37 #include "font.h"
38 #include "global.h"
39 #include "cell.h"
40 #include "line.h"
41 #include "sylk.h"
42 #include "lists.h"
43 #include "ref.h"
44 #include "regions.h"
45 #include "window.h"
46 #include "info.h"
47 #include "cmd.h"
48 
49 #include "graph.h"
50 
51 #include "oleosql.h"
52 
53 /* These functions read and write OLEO style files. */
54 
55 void
oleo_read_file(fp,ismerge)56 oleo_read_file (fp, ismerge)
57      FILE *fp;
58      int ismerge;
59 {
60   char *ptr;
61   CELLREF crow = 0, ccol = 0, czrow = 0, czcol = 0;
62   int lineno;
63   char cbuf[1024];
64   char expbuf[1024];
65   char *vname, *vval;
66   int vlen = 0;
67   int cprot;
68   char *cexp, *cval;
69   CELL *cp;
70   struct rng rng;
71   int fmt = 0, prc = 0;
72   int jst = 0;
73   struct font_memo * fnt = 0;
74   struct font_memo ** fnt_map = 0;
75   int fnt_map_size = 0;
76   int fnt_map_alloc = 0;
77   int font_spec_in_format = 1;	/* Reset if we discover this is a v1.1 file. */
78 
79   long mx_row = MAX_ROW, mx_col = MAX_COL;
80   int old_a0;
81   int next_a0;
82 
83   Global->return_from_error = 1;
84 
85   old_a0 = Global->a0;
86   next_a0 = old_a0;
87   Global->a0 = 0;
88   lineno = 0;
89   if (!ismerge)
90     clear_spreadsheet ();
91   while (fgets (cbuf, sizeof (cbuf), fp))
92     {
93       lineno++;
94 
95 #if 0
96       if (lineno % 50 == 0)
97 	io_info_msg ("Line %d", lineno);
98 #endif
99       if ((ptr = (char *)index (cbuf, '\n')))
100 	*ptr = '\0';
101 
102       ptr = cbuf;
103       switch (*ptr)
104 	{
105 	case '#':		/* comment line -- ignored */
106 	  break;
107 	case '%':		/* Font or pixel size data. */
108 	  ptr++;
109 	  switch (*ptr) {
110 	    case 'F':		/* %F font-name */
111 	      if (fnt_map_size == fnt_map_alloc)
112 		{
113 		  fnt_map_alloc = (fnt_map_alloc + 1) * 2;
114 		  fnt_map =
115 		    ((struct font_memo **)
116 		     ck_remalloc
117 		     (fnt_map, fnt_map_alloc * sizeof (struct font_memo *)));
118 		}
119 	      fnt_map[fnt_map_size++] = parsed_matching_font (ptr + 1);
120 	      break;
121 	    case 'f':		/* %f range font-name */
122 	      {
123 		struct rng rng;
124 		/* This field only occurs in files written by 1.1
125 		 * oleo.  It's presense indicates that when parsing
126 		 * format fields, we should *not* reset cell fonts to 0.
127 		 */
128 		font_spec_in_format = 0;
129 		++ptr;
130 		while (isspace (*ptr))
131 		  ++ptr;
132 		if (!parse_cell_or_range (&ptr, &rng))
133 		  goto bad_field;
134 		while (isspace (*ptr))
135 		  ++ptr;
136 		{
137 		  struct font_memo * fm = parsed_matching_font (ptr);
138 		  set_region_font (&rng, fm->names->oleo_name, fm->scale);
139 		}
140 		break;
141 	      }
142 	    default:		/* % with something invalid */
143 	      goto bad_field;
144 	    }
145 	  break;
146 	case 'F':		/* Format field */
147 	  vlen = 0;
148 	  ptr++;
149 	  fnt = 0;	/* The font must be explicitly overriden for a cell. */
150 	  while (*ptr)
151 	    {
152 	      if (*ptr != ';')
153 		goto bad_field;
154 	      ptr++;
155 	      switch (*ptr++) {
156 		  int clo, chi, cwid;
157 		case 'C':	/* Column from rows 1 to 255 */
158 		  czcol = astol (&ptr);
159 		  vlen = 2;
160 		  break;
161 
162 		case 'D':	/* Default format */
163 		  switch (*ptr++)
164 		    {
165 		    case 'G':
166 		      default_fmt = FMT_GEN;
167 		      break;
168 		    case 'E':
169 		      default_fmt = FMT_EXP;
170 		      break;
171 		    case 'F':
172 		      default_fmt = FMT_FXT;
173 		      break;
174 		    case '$':
175 		      default_fmt = FMT_DOL;
176 		      break;
177 		    case '*':	/* * format implemented as +- format */
178 		      default_fmt = FMT_GPH;
179 		      break;
180 		    case ',':	/* JF */
181 		      default_fmt = FMT_CMA;
182 		      break;
183 		    case 'U':
184 		      default_fmt = FMT_USR;
185 		      break;
186 		    case '%':
187 		      default_fmt = FMT_PCT;
188 		      break;
189 		    case 'H':
190 		      default_fmt = FMT_HID;
191 		      break;
192 		    case 'd':	/* Date */
193 			default_fmt = FMT_DATE;
194 			break;
195 		      /* End of JF */
196 		    default:
197 		      io_error_msg ("Line %d: format %c not supported", lineno, ptr[-1]);
198 		      break;
199 		    }
200 		  if (*ptr == 'F')
201 		    {
202 		      prc = default_prc = FLOAT_PRECISION;
203 		      ptr++;
204 		    }
205 		  else
206 		    default_prc = prc = astol (&ptr);
207 
208 		  switch (*ptr++)
209 		    {
210 		    case 'C':
211 		      default_jst = JST_CNT;
212 		      break;
213 		    case 'L':
214 		      default_jst = JST_LFT;
215 		      break;
216 		    case 'R':
217 		      default_jst = JST_RGT;
218 		      break;
219 		    case 'G':	/* General format not supported */
220 		    default:
221 		      io_error_msg ("Line %d: Alignment %c not supported", lineno, ptr[-1]);
222 		      break;
223 		    }
224 		  default_width = astol (&ptr);
225 		  break;
226 
227 		case 'f': /* Font specification */
228 		  {
229 		    int id;
230 		    id = astol(&ptr);
231 		    if (id < 0 || id >= fnt_map_size)
232 		      {
233 			io_error_msg ("Line %d: Undefined font (%d)\n",
234 				      lineno, id);
235 			break;
236 		      }
237 		    fnt = fnt_map[id];
238 		    break;
239 		  }
240 
241 		case 'F':
242 		  switch (*ptr++)
243 		    {
244 		    case 'D':
245 		      fmt = FMT_DEF;
246 		      break;
247 		    case 'G':
248 		      fmt = FMT_GEN;
249 		      break;
250 		    case 'E':
251 		      fmt = FMT_EXP;
252 		      break;
253 		    case 'F':
254 		      fmt = FMT_FXT;
255 		      break;
256 		    case '$':
257 		      fmt = FMT_DOL;
258 		      break;
259 		    case '*':	/* JF implemented as +- format */
260 		      fmt = FMT_GPH;
261 		      break;
262 		    case ',':	/* JF */
263 		      fmt = FMT_CMA;
264 		      break;
265 		    case 'U':
266 		      fmt = FMT_USR;
267 		      break;
268 		    case '%':
269 		      fmt = FMT_PCT;
270 		      break;
271 		    case 'H':
272 		      fmt = FMT_HID;
273 		      break;	/* END of JF */
274 		    case 'd':
275 			fmt = FMT_DATE;
276 			break;
277 		    case 'C':
278 		    default:
279 		      io_error_msg ("Line %d: format %c not supported", lineno, ptr[-1]);
280 		      fmt = FMT_DEF;
281 		      break;
282 		    }
283 		  if (*ptr == 'F') {
284 		      prc = FLOAT_PRECISION;
285 		      ptr++;
286 		  } else {
287 		    prc = astol(&ptr);
288 		  }
289 		  switch (*ptr++)
290 		    {
291 		    case 'C':
292 		      jst = JST_CNT;
293 		      break;
294 		    case 'L':
295 		      jst = JST_LFT;
296 		      break;
297 		    case 'R':
298 		      jst = JST_RGT;
299 		      break;
300 		    case 'D':
301 		      jst = JST_DEF;
302 		      break;
303 		    default:
304 		      io_error_msg ("Line %d: Alignment %c not supported", lineno, ptr[-1]);
305 		      jst = JST_DEF;
306 		      break;
307 		    }
308 		  vlen = 1;
309 		  break;
310 		case 'R':	/* Row from cols 1 to 63 */
311 		  czrow = astol (&ptr);
312 		  vlen = 4;
313 		  break;
314 
315 		case 'W':	/* Width of clo to chi is cwid */
316 		  clo = astol (&ptr);
317 		  chi = astol (&ptr);
318 		  cwid = astol (&ptr) + 1;
319 		  for (; clo <= chi; clo++) {
320 			set_width (clo, cwid);
321 		    }
322 		  break;
323 
324 		case 'H':	/* JF: extension */
325 		  clo = astol (&ptr);
326 		  chi = astol (&ptr);
327 		  cwid = astol (&ptr) + 1;
328 		  for (; clo <= chi; clo++)
329 		    set_height (clo, cwid);
330 		  break;
331 		case 'c':
332 		  ccol = astol (&ptr);
333 		  break;
334 		case 'r':
335 		  crow = astol (&ptr);
336 		  break;
337 
338 		default:
339 		  goto bad_field;
340 		}
341 	    }
342 	  switch (vlen)
343 	    {
344 	    case 1:
345 	      cp = find_or_make_cell (crow, ccol);
346 	      SET_FORMAT (cp, fmt);
347 		  SET_PRECISION(cp, prc);
348 	      SET_JST (cp, jst);
349 	      if (font_spec_in_format)
350 		cp->cell_font = fnt;
351 	      break;
352 	    case 2:
353 	      rng.lr = MIN_ROW;
354 	      rng.lc = czcol;
355 	      rng.hr = mx_row;
356 	      rng.hc = czcol;
357 	      make_cells_in_range (&rng);
358 	      while ((cp = next_cell_in_range ()))
359 		{
360 		  SET_FORMAT (cp, fmt);
361 		  SET_PRECISION(cp, prc);
362 		  SET_JST (cp, jst);
363 		  if (font_spec_in_format)
364 		    cp->cell_font = fnt;
365 		}
366 	      break;
367 	    case 4:
368 	      rng.lr = czrow;
369 	      rng.lc = MIN_COL;
370 	      rng.hr = czrow;
371 	      rng.hc = mx_col;
372 	      make_cells_in_range (&rng);
373 	      while ((cp = next_cell_in_range ()))
374 		{
375 		  SET_FORMAT (cp, fmt);
376 		  SET_JST (cp, jst);
377 		  if (font_spec_in_format)
378 		    cp->cell_font = fnt;
379 		}
380 	      break;
381 	    default:
382 	      break;
383 	    }
384 	  break;
385 
386 	case 'B':		/* Boundry field, ignored */
387 	  ptr++;
388 	  while (*ptr)
389 	    {
390 	      if (*ptr != ';')
391 		goto bad_field;
392 	      ptr++;
393 	      switch (*ptr++)
394 		{
395 		case 'c':
396 		  mx_col = astol (&ptr);
397 		  if (mx_col > MAX_COL)
398 		    {
399 		      io_error_msg ("Boundry column %lu too large!", mx_col);
400 		      mx_col = MAX_COL;
401 		    }
402 		  break;
403 		case 'r':
404 		  mx_row = astol (&ptr);
405 		  if (mx_row > MAX_ROW)
406 		    {
407 		      io_error_msg ("Boundry row %lu too large!", mx_row);
408 		      mx_row = MAX_ROW;
409 		    }
410 		  break;
411 		default:
412 		  goto bad_field;
413 		}
414 	    }
415 	  break;
416 
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 	case 'C':		/* A Cell entry */
455 	  cprot = 0;
456 	  cval = 0;
457 	  cexp = 0;
458 	  cval = 0;
459 	  ptr++;
460 	  while (*ptr)
461 	    {
462 	      int quotes;
463 
464 	      if (*ptr != ';')
465 		goto bad_field;
466 	      *ptr++ = '\0';
467 	      switch (*ptr++)
468 		{
469 		case 'c':
470 		  ccol = astol (&ptr);
471 		  break;
472 		case 'r':
473 		  crow = astol (&ptr);
474 		  break;
475 		case 'R':
476 		  czrow = astol (&ptr);
477 		  break;
478 		case 'C':
479 		  czcol = astol (&ptr);
480 		  break;
481 		case 'P':	/* This cell is Protected */
482 		  cprot++;
483 		  break;
484 		case 'K':	/* This cell's Konstant value */
485 		  cval = ptr;
486 		  quotes = 0;
487 		  while (*ptr && (*ptr != ';' || quotes > 0))
488 		    if (*ptr++ == '"')
489 		      quotes = !quotes;
490 		  break;
491 		case 'E':	/* This cell's Expression */
492 		  cexp = ptr;
493 		  quotes = 0;
494 		  while (*ptr && (*ptr != ';' || quotes > 0))
495 		    if (*ptr++ == '"')
496 		      quotes = !quotes;
497 
498 		  break;
499 		case 'G':
500 		  strcpy (expbuf, cval);
501 		  break;
502 		case 'D':
503 		  strcpy (expbuf, cexp);
504 		  break;
505 		case 'S':
506 		  cexp = expbuf;
507 		  break;
508 		default:
509 		  --ptr;
510 		  goto bad_field;
511 		}
512 	    }
513 	  *ptr = '\0';
514 	  if (cexp && cval && strcmp (cexp, cval))
515 	    {
516 	      ptr = read_new_value (crow, ccol, cexp, cval);
517 	      if (ptr)
518 		{
519 		  io_error_msg ("Line %d: %d,%d: Read '%s' %s", lineno, crow, ccol, cexp, ptr);
520 		  break;
521 		}
522 	    }
523 	  else if (cval)
524 	    {
525 	      ptr = read_new_value (crow, ccol, 0, cval);
526 	      if (ptr)
527 		{
528 		  io_error_msg ("Line %d: %d,%d: Val '%s' %s", lineno, crow, ccol, cexp, ptr);
529 		  break;
530 		}
531 	    }
532 	  else if (cexp)
533 	    {
534 	      ptr = read_new_value (crow, ccol, cexp, 0);
535 	      if (ptr)
536 		{
537 		  io_error_msg ("Line %d: %d,%d: Exp '%s' %s", lineno, crow, ccol, cexp, ptr);
538 		  break;
539 		}
540 	    }
541 	  if (cprot)
542 	    SET_LCK (find_or_make_cell (crow, ccol), LCK_LCK);
543 	  if (ismerge)
544 	    push_cell (crow, ccol);
545 	  /* ... */
546 	  break;
547 	case 'E':	/* End of input ?? */
548 	  break;
549 	case 'W':
550 	  io_read_window_config (ptr + 2);
551 	  break;
552 	case 'U':
553 	  /* JF extension:  read user-defined formats */
554 	  read_mp_usr_fmt (ptr + 1);
555 	  break;
556 	  /* JF extension: read uset-settable options */
557 	case 'O':
558 	  Global->a0 = next_a0;
559 	  read_mp_options (ptr + 2);
560 	  next_a0 = Global->a0;
561 	  Global->a0 = 0;
562 	  break;
563 	case 'G':	/* Graph data */
564 /*	  fprintf(stderr, "Graph input line '%s'\n", cbuf);	*/
565 	  switch (*(ptr+1)) {
566 	  case 'T':	/* Graph Title */
567 	    graph_set_title(cbuf+2);
568 	    break;
569 	  case 'D':	/* Axis title : GDxtitle */
570 	    graph_set_axis_title(cbuf[2], cbuf+3);
571 	    break;
572 	  case 't':	/* Graph data title : Gtxtitle */
573 	    graph_set_data_title(cbuf[2] - '0', cbuf+3);
574 	    break;
575 	  case 'a':	/* Automatic axis setting : Gax0 or Gax1 */
576 	    graph_set_axis_auto(cbuf[2] - '0', cbuf[3] == '1');
577 	    break;
578 	  case 'o':	/* Whether to draw line to offscreen data points */
579 	    graph_set_linetooffscreen(cbuf[2] == '1');
580 	    break;
581 	  case 'r':	/* Axis range : GrxlVALUE , l = 0 for low, 1 for high */
582 	    if (cbuf[3] == '0')
583 		graph_set_axis_lo('x' + cbuf[2] - '0', &cbuf[4]);
584 	    else if (cbuf[3] == '1')
585 		graph_set_axis_hi('x' + cbuf[2] - '0', &cbuf[4]);
586 	    break;
587 	  case 'L':	/* Axis logness GLx0 or GLx1 */
588 	    graph_set_logness(cbuf[2], 1, cbuf[3] == '1');
589 	    break;
590 	  case '0': case '1': case '2': case '3':
591 	  case '4': case '5': case '6': case '7':
592 	  case '8': case '9':
593             {
594 	      int	i, a, b, c, d;
595 	      struct rng r;
596 	      sscanf(cbuf, "G%d,%d,%d,%d,%d", &i, &a, &b, &c, &d);
597 	      r.lc = a;
598 	      r.lr = b;
599 	      r.hc = c;
600 	      r.hr = d;
601 	      graph_set_data(i, &r);
602 	    }
603 	    break;
604 	  case 'm':	/* Tick marks Gmxts, x = 0 or 1, t = 0 .. 4 (the tick type),
605 			 * s is the format string, if any.
606 			 */
607 	    {
608 		int	axis, tp;
609 
610 		axis = cbuf[2] - '0';
611 		tp = cbuf[3] - '0';
612 
613 		graph_set_axis_ticks(axis, tp, strdup(&cbuf[4]));
614 	    }
615 		break;
616 	  default:
617 	    fprintf(stderr, "Graph: invalid line '%s'\n", cbuf);
618 	  }
619 	  break;
620 	case 'D':	/* Database Access */
621 		ptr++;
622 		switch (*ptr) {
623 		case 'u':
624 			DatabaseSetUser(ptr+1);
625 			break;
626 		case 'h':
627 			DatabaseSetHost(ptr+1);
628 			break;
629 		case 'n':
630 			DatabaseSetName(ptr+1);
631 			break;
632 		default:
633 			io_error_msg("Line %d - unknown code %s\n", lineno, cbuf);
634 		}
635 		break;
636 	default:
637 	bad_field:
638 	  Global->a0 = old_a0;
639 	  if (!ismerge)
640 	    clear_spreadsheet ();
641 	  io_recenter_all_win ();
642 	  io_error_msg ("Line %d: Unknown OLEO line \"%s\"", lineno, cbuf);
643 	  Global->return_from_error = 0;
644 	  return;
645 	}	/* End of switch */
646     }
647   if (!feof (fp)) {
648 	if (!ismerge)
649 		clear_spreadsheet ();
650 	io_recenter_all_win ();
651 	io_error_msg ("read-file: read-error near line %d.", lineno);
652 	Global->return_from_error = 0;
653 	return;
654     }
655   Global->a0 = next_a0;
656   io_recenter_all_win ();
657 
658   Global->return_from_error = 0;
659 }
660 
661 static char *
oleo_fmt_to_str(int f1,int p1)662 oleo_fmt_to_str (int f1, int p1)
663 {
664   static char p_buf[40];
665 
666   p_buf[1] = '\0';
667   switch (f1)
668     {
669     case FMT_DEF:
670       p_buf[0] = 'D';
671       break;
672     case FMT_HID:
673       p_buf[0] = 'H';
674       break;
675     case FMT_GPH:
676       p_buf[0] = '*';
677       break;
678     default:
679       if (p1 == FLOAT_PRECISION)
680 	{
681 	  p_buf[1] = 'F';
682 	  p_buf[2] = '\0';
683 	}
684       else
685 	sprintf (&p_buf[1], "%d", p1);
686 
687       switch (f1)
688 	{
689 	case FMT_USR:
690 	  p_buf[0] = 'U';
691 	  break;
692 	case FMT_GEN:
693 	  p_buf[0] = 'G';
694 	  break;
695 	case FMT_DOL:
696 	  p_buf[0] = '$';
697 	  break;
698 	case FMT_PCT:
699 	  p_buf[0] = '%';
700 	  break;
701 	case FMT_FXT:
702 	  p_buf[0] = 'F';
703 	  break;
704 	case FMT_CMA:
705 	  p_buf[0] = ',';
706 	  break;
707 	case FMT_EXP:
708 	  p_buf[0] = 'E';
709 	  break;
710 	case FMT_DATE:
711 	  p_buf[0] = 'd';
712 	  break;
713 	default:
714 	  p_buf[0] = '?';
715 #if 0
716 	  fprintf(stderr, "OleoWrite: format %d not supported\n", f1);
717 #endif
718 	  break;
719 	}
720       break;
721     }
722   return p_buf;
723 }
724 
725 static char
jst_to_chr(just)726 jst_to_chr (just)
727      int just;
728 {
729   switch (just)
730     {
731     case JST_DEF:
732       return 'D';
733     case JST_LFT:
734       return 'L';
735     case JST_RGT:
736       return 'R';
737     case JST_CNT:
738       return 'C';
739     default:
740       return '?';
741     }
742 }
743 
744 static FILE *oleo_fp;
745 static struct rng *oleo_rng;
746 
747 static void
oleo_write_var(name,var)748 oleo_write_var (name, var)
749      char *name;
750      struct var *var;
751 {
752   if (var->var_flags == VAR_UNDEF
753 	&& (!var->var_ref_fm || var->var_ref_fm->refs_used == 0))
754     return;
755 
756   switch (var->var_flags) {
757     case VAR_UNDEF:
758       break;
759     case VAR_CELL:
760       if (var->v_rng.lr >= oleo_rng->lr && var->v_rng.lr <= oleo_rng->hr
761 		&& var->v_rng.lc >= oleo_rng->lc && var->v_rng.lc <= oleo_rng->hc)
762 	(void) fprintf(oleo_fp, "NN;N%s;E%s\n",
763 		var->var_name, cell_name(var->v_rng.lr, var->v_rng.lc));
764       break;
765     case VAR_RANGE:
766       if (var->v_rng.lr < oleo_rng->lr || var->v_rng.hr > oleo_rng->hr
767 		|| var->v_rng.lc < oleo_rng->lc || var->v_rng.hc > oleo_rng->hc)
768 	break;
769 
770       (void) fprintf(oleo_fp, "NN;N%s;E%s\n", var->var_name, range_name (&(var->v_rng)));
771       break;
772 #ifdef TEST
773     default:
774       panic ("Unknown var type %d", var->var_flags);
775 #endif
776     }
777 }
778 
779 static void
write_mp_windows(fp)780 write_mp_windows (fp)
781      FILE *fp;
782 {
783   struct line line;
784 
785   line.alloc = 0;
786   line.buf = 0;
787   io_write_window_config (&line);
788   fputs (line.buf, fp);
789   free (line.buf);
790 }
791 
792 void
oleo_write_file(fp,rng)793 oleo_write_file (fp, rng)
794      FILE *fp;
795      struct rng *rng;
796 {
797   CELLREF r, c;
798   CELL *cp;
799   CELLREF crow = 0, ccol = 0;
800   unsigned short w;
801   /* struct var *var; */
802   int old_a0, i, fnt_map_size = 0;
803   char	*s;
804 
805   (void) fprintf (fp, "# This file was created by GNU Oleo\n");
806 
807   /* All versions of the oleo file format should have a
808    * version cookie on the second line.
809    */
810   (void) fprintf (fp, "# format 2.1 (requires Oleo 1.99.9 or higher)\n");
811 
812   /* If no range given, write the entire file */
813   if (!rng)
814     {
815       int n;
816       int fmts;
817       char *data[9];
818 
819       rng = &all_rng;
820 
821       (void) fprintf (fp, "F;D%s%c%u\n",
822 		oleo_fmt_to_str (default_fmt, default_prc),
823 		jst_to_chr (default_jst),
824 		default_width);
825 
826       fmts = usr_set_fmts ();
827       for (n = 0; n < 16; n++)
828 	{
829 	  if (fmts & (1 << n))
830 	    {
831 	      get_usr_stats (n, data);
832 	      fprintf (fp, "U;N%u;P%s;S%s", n + 1, data[7], data[8]);
833 	      if (data[0][0])
834 		fprintf (fp, ";HP%s", data[0]);
835 	      if (data[1][0])
836 		fprintf (fp, ";HN%s", data[1]);
837 	      if (data[2][0])
838 		fprintf (fp, ";TP%s", data[2]);
839 	      if (data[3][0])
840 		fprintf (fp, ";TN%s", data[3]);
841 	      if (data[4][0])
842 		fprintf (fp, ";Z%s", data[4]);
843 	      if (data[5][0])
844 		fprintf (fp, ";C%s", data[5]);
845 	      if (data[6])
846 		fprintf (fp, ";D%s", data[6]);
847 	      putc ('\n', fp);
848 	    }
849 	}
850       write_mp_options (fp);
851     }
852 
853   old_a0 = Global->a0;
854   Global->a0 = 0;
855 
856   find_widths (rng->lc, rng->hc);
857   w = next_width (&c);
858   while (w)
859     {
860       CELLREF cc, ccc;
861       unsigned short ww;
862       cc = c;
863       do
864 	ww = next_width (&ccc);
865       while (ccc == ++cc && ww == w);
866       (void) fprintf (fp, "F;W%u %u %u\n", c, cc - 1, w - 1);
867       c = ccc;
868       w = ww;
869     }
870 
871   find_heights (rng->lr, rng->hr);
872   w = next_height (&r);
873   while (w)
874     {
875       CELLREF rr, rrr;
876       unsigned short ww;
877 
878       rr = r;
879       do
880 	ww = next_height (&rrr);
881       while (rrr == ++rr && ww == w);
882       (void) fprintf (fp, "F;H%u %u %u\n", r, rr - 1, w - 1);
883       r = rrr;
884       w = ww;
885     }
886 
887   oleo_fp = fp;
888   oleo_rng = rng;
889   for_all_vars (oleo_write_var);
890   find_cells_in_range (rng);
891 
892   {
893     struct font_memo * fm;
894     for (fm = font_list; fm; fm = fm->next)
895       fm->id_memo = -1;
896   }
897   while ((cp = next_row_col_in_range (&r, &c)))
898     {
899       char *ptr;
900       int f1, j1;
901       char p_buf[40];
902 
903       f1 = GET_FORMAT (cp);
904       j1 = GET_JST (cp);
905       if (f1 != FMT_DEF || j1 != JST_DEF || cp->cell_font)
906 	{
907 	  if (cp->cell_font)
908 	    {
909 	      if (cp->cell_font->id_memo < 0)
910 		{
911 		  cp->cell_font->id_memo = fnt_map_size++;
912 		  if (isnan(cp->cell_font->scale))
913 			fprintf (fp, "%%F%s,%s,%f\n",
914 			   cp->cell_font->names->x_name,
915 			   cp->cell_font->names->ps_name,
916 			   cp->cell_font->scale);
917 		  else
918 			fprintf (fp, "%%F%s,%s,%f\n",
919 			   cp->cell_font->names->x_name,
920 			   cp->cell_font->names->ps_name,
921 			   1.0);
922 		}
923 	    }
924 	  (void) fprintf (fp, "F;");
925 	  if (c != ccol)
926 	    {
927 	      (void) fprintf (fp, "c%u;", c);
928 	      ccol = c;
929 	    }
930 	  if (r != crow)
931 	    {
932 	      (void) fprintf (fp, "r%u;", r);
933 	      crow = r;
934 	    }
935 	  if (cp->cell_font)
936 	    (void) fprintf (fp, "f%d;", cp->cell_font->id_memo);
937 	    (void) fprintf (fp, "F%s%c\n",
938 			  oleo_fmt_to_str (f1, GET_PRECISION(cp)), jst_to_chr (j1));
939 	}
940 
941       if (!GET_TYP (cp) && !cp->cell_formula)
942 	continue;
943 
944       (void) fprintf (fp, "C;");
945       if (c != ccol)
946 	{
947 	  (void) fprintf (fp, "c%u;", c);
948 	  ccol = c;
949 	}
950       if (r != crow)
951 	{
952 	  (void) fprintf (fp, "r%u;", r);
953 	  crow = r;
954 	}
955 
956       if (cp->cell_formula)
957 	{
958 	  (void) fprintf (fp, "E%s", decomp(r, c, cp));
959 	  decomp_free();
960 	}
961 
962       switch (GET_TYP (cp))
963 	{
964 	case 0:
965 	  ptr = 0;
966 	  break;
967 	case TYP_STR:
968 	  ptr = 0;
969 	  if (cp->cell_formula)
970 	    putc (';', fp);
971 	  (void) fprintf (fp, "K\"%s\"", cp->cell_str);
972 	  break;
973 	case TYP_FLT:
974 	  ptr = flt_to_str (cp->cell_flt);
975 	  break;
976 	case TYP_INT:
977 	  sprintf (p_buf, "%ld", cp->cell_int);
978 	  ptr = p_buf;
979 	  break;
980 	case TYP_BOL:
981 	  ptr = bname[cp->cell_bol];
982 	  break;
983 	case TYP_ERR:
984 	  ptr = ename[cp->cell_err];
985 	  break;
986 	default:
987 	  ptr = 0;
988 #ifdef TEST
989 	  panic ("What cell type %d", GET_TYP (cp));
990 #endif
991 	}
992 
993       if (ptr)
994 	{
995 	  if (cp->cell_formula)
996 	    putc (';', fp);
997 	  (void) fprintf (fp, "K%s", ptr);
998 	}
999       if (GET_LCK (cp) == LCK_LCK)
1000 	(void) fprintf (fp, ";P");
1001 
1002       putc ('\n', fp);
1003     }
1004 
1005   if (rng == &all_rng)
1006     write_mp_windows (fp);
1007 
1008   /* Graphs */
1009   for (i=0; i<NUM_DATASETS; i++) {
1010 	struct rng	r;
1011 	int		a, b, c, d;
1012 
1013 	r = graph_get_data(i);
1014 	if (r.lc == 0 && r.lr == 0 && r.hc == 0 && r.hr == 0)
1015 		continue;
1016 
1017 	/* Write this thing */
1018 	a = r.lc;
1019 	b = r.lr;
1020 	c = r.hc;
1021 	d = r.hr;
1022 	fprintf(fp, "G%d,%d,%d,%d,%d\n", i, a, b, c, d);
1023   }
1024   /* Graph title */
1025   s = graph_get_title();
1026   if (s && strlen(s)) {
1027     fprintf(fp, "GT%s\n", s);
1028   }
1029 
1030   s = graph_get_axis_title('x');
1031   if (s && strlen(s)) {
1032     fprintf(fp, "GDx%s\n", s);
1033   }
1034 
1035   s = graph_get_axis_title('y');
1036   if (s && strlen(s)) {
1037     fprintf(fp, "GDy%s\n", s);
1038   }
1039 
1040   for (i=0; i<NUM_DATASETS; i++) {
1041 	if (graph_get_data_title(i))
1042 		fprintf(fp, "Gt%c%s\n", i + '0', graph_get_data_title(i));
1043   }
1044 
1045   /* Axis range : GrxlVALUE , l = 0 for low, 1 for high */
1046   for (i=0; i< 2; i++) {
1047 	double	d;
1048 	d = graph_get_axis_lo(i);
1049 	if (! isnan(d))
1050 		fprintf(fp, "Gr%c0%f\n", '0' + i, d);
1051 	d = graph_get_axis_hi(i);
1052 	if (! isnan(d))
1053 		fprintf(fp, "Gr%c1%f\n", '0' + i, d);
1054   }
1055 
1056   /* Automatic axis setting : Gax0 or Gax1 */
1057   fprintf(fp, "Ga0%c\n", graph_get_axis_auto(0) ? '1' : '0');	/* X axis */
1058   fprintf(fp, "Ga1%c\n", graph_get_axis_auto(1) ? '1' : '0');	/* Y axis */
1059 
1060   /* Draw line to offscreen data points */
1061   fprintf(fp, "Go%c\n", graph_get_linetooffscreen() ? '1' : '0');
1062 
1063   /* Axis tick marks */
1064   fprintf(fp, "Gm0%c%s\n",
1065 	'0' + graph_get_axis_ticktype(0),
1066 	graph_get_axis_tickformat(0) ? graph_get_axis_tickformat(0) : "(null)");
1067   fprintf(fp, "Gm1%c%s\n",
1068 	'0' + graph_get_axis_ticktype(1),
1069 	graph_get_axis_tickformat(1) ? graph_get_axis_tickformat(1) : "(null)");
1070 
1071   /* Database stuff */
1072   if (DatabaseInitialised()) {
1073 	fprintf(fp, "Dn%s\n", DatabaseGetName() ? DatabaseGetName() : "");
1074 	fprintf(fp, "Dh%s\n", DatabaseGetHost() ? DatabaseGetHost() : "");
1075 	fprintf(fp, "Du%s\n", DatabaseGetUser() ? DatabaseGetUser() : "");
1076   }
1077 
1078   /* End of writing */
1079   (void) fprintf (fp, "E\n");
1080   Global->a0 = old_a0;
1081 }
1082 
1083 int
oleo_set_options(set_opt,option)1084 oleo_set_options
1085   (set_opt, option)
1086      int set_opt;
1087      char *option;
1088 {
1089   return -1;
1090 }
1091 
1092 void
oleo_show_options()1093 oleo_show_options ()
1094 {
1095   io_text_line ("File format: oleo.");
1096 }
1097 
1098 
1099 #if 0
1100 This was used in releases 1.0 and 1.1 to write fonts.
1101 It is no longer used but is kept here for reference since 1.2 and later
1102 versions should continue to understand the older file format for a while.
1103 
1104 static int
1105 oleo_write_fonts (rng, font, ignore)
1106      struct rng *rng;
1107      struct font_memo *font;
1108      void *ignore;
1109 {
1110   struct rng r;
1111   char *rname;
1112   r = *rng;
1113   if (r.lr < oleo_rng->lr)
1114     r.lr = oleo_rng->lr;
1115   if (r.lc < oleo_rng->lc)
1116     r.lc = oleo_rng->lc;
1117   if (r.hr > oleo_rng->hr)
1118     r.hr = oleo_rng->hr;
1119   if (r.hc > oleo_rng->hc)
1120     r.hc = oleo_rng->hc;
1121   rname = range_name (&r);
1122   fprintf (oleo_fp, "%%f %s %s,%s,%f\n",
1123 	   rname, font->name, font->psname, font->scale);
1124   return 1;
1125 }
1126 
1127 
1128 #endif
1129 
1130