1 /*
2  * $Id: io-utils.c,v 1.39 2001/02/13 23:38:06 danny Exp $
3  *
4  * Copyright � 1990, 1992, 1993, 2000, 2001 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 along with
19  * Oleo; see the file COPYING.  If not, write to the Free Software Foundation, 675
20  * Mass Ave, Cambridge, MA 02139, USA.
21  */
22 
23 static char *rcsid = "$Id: ";
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #ifdef	WITH_DMALLOC
30 #include <dmalloc.h>
31 #endif
32 
33 #include <stdio.h>
34 #include <ctype.h>
35 #include "sysdef.h"
36 #include "io-utils.h"
37 #include "cell.h"
38 #include "ref.h"
39 #include "decompile.h"
40 #include "io-generic.h"
41 #include "io-abstract.h"
42 #include "lists.h"
43 #include "io-term.h"
44 #include "cmd.h"
45 #include "sylk.h"
46 #ifdef	HAVE_MOTIF
47 #include "io-motif.h"
48 #endif
49 #include "basic.h"
50 #include "oleofile.h"
51 #include "sc.h"
52 #include "list.h"
53 
54 #ifdef	HAVE_TIME_H
55 #include <time.h>
56 #endif
57 
58 
59 /* Routines for formatting cell values */
60 struct user_fmt;
61 static char *pr_flt (double, struct user_fmt *, int);
62 static char *pr_int (long, struct user_fmt *, int);
63 
64 /* Constants */
65 char *bname[] =
66 {
67   "#FALSE", "#TRUE"
68 };
69 
70 char numb_oflo[] = "########################################";
71 
72 double __plinf;
73 double __neinf;
74 double ___nan;
75 
76 char nname[] = "#NOT_A_NUMBER";
77 char iname[] = "#INFINITY";
78 char mname[] = "#MINUS_INFINITY";
79 
80 char *date_formats[] = {
81 	"%Y/%m/%d",			/* YYYY/MM/DD */
82 	"%Y-%m-%d",			/* YYYY-MM-DD */
83 	"%d/%m/%Y",			/* European style */
84 	"%m/%d/%Y",			/* American style */
85 	"%d/%m",
86 	"%Y%m",
87 	"%m%Y",
88 	"%B %d, %Y",			/* Month, day, year */
89 	"%d %B %Y",			/* Day, month, year */
90 	"%b %d, %Y",			/* Mon, day, year */
91 	"%d %b %Y",			/* Day, mon, year */
92 	NULL
93 };
94 
95 static double
divide(a,b)96 divide (a, b)
97      double a;
98      double b;
99 {
100   return a / b;
101 }
102 
103 static RETSIGTYPE
ignore_sig(sig)104 ignore_sig (sig)
105      int sig;
106 {
107   (void) signal (SIGFPE, ignore_sig);
108 }
109 
110 /* It's ok of this fails and generates signals.  In that case,
111  * the same signal will occur when evaluating formulas and a
112  * (less informative) error value substituted.  Note that this
113  * should be called before init_eval.
114  */
115 void
init_infinity(void)116 init_infinity (void)
117 {
118 #ifdef	MAXFLOAT
119   __plinf = MAXFLOAT;
120   __neinf = - MAXFLOAT;
121 #else
122   (void) signal (SIGFPE, ignore_sig);
123   __plinf = divide (1., 0.);
124   (void) signal (SIGFPE, ignore_sig);
125   __neinf = divide (-1., 0.);
126   (void) signal (SIGFPE, ignore_sig);
127 #endif
128   ___nan = __plinf + __neinf;
129 }
130 
131 
132 
133 /* Slightly larger than the maximum exponent we ever expect to see */
134 #define BIGFLT 309
135 #ifdef TEST
136 char print_buf[1024 * 8];
137 #else
138 char print_buf[BIGFLT + 20];
139 #endif
140 
141 
142 
143 /* Structures/vars/functions for dealing with formatting floating-point
144    numbers, etc */
145 
146 struct user_fmt {
147     char *name,		/* Format name */
148 	*p_hdr,		/* Positive header */
149 	*n_hdr,		/* Negative header */
150 	*p_trl,		/* Positive trailer */
151 	*n_trl,		/* Negative trailer */
152 	*zero,		/* How to represent a 0 */
153 	*comma,		/* Thousands separator */
154 	*decpt;		/* Decimal point */
155     unsigned char prec;	/* Precision */
156     double scale;	/* Scale */
157 };
158 
159 
160 struct user_fmt dol =
161 { "dollar", "$", "($", 0, ")", "$0", ",", ".", FLOAT_PRECISION, 1};
162 
163 struct user_fmt cma =
164 { "comma", 0, "(", 0, ")", "0", ",", ".", FLOAT_PRECISION, 1};
165 
166 struct user_fmt pct =
167 #if 0
168 { "percent", 0, "-", "%", "%", "0%", 0, ".", 3, 100};
169 #else
170 { "percent", 0, "-", "%", "%", "0%", 0, ".", FLOAT_PRECISION, 100};
171 #endif
172 
173 struct user_fmt fxt =
174 { "fixed", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1};
175 
176 /* Variables */
177 
178 #define NUM_USER_FMT (16)
179 struct user_fmt u[NUM_USER_FMT] =
180 {
181   {"user1", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
182   {"user2", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
183   {"user3", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
184   {"user4", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
185   {"user5", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
186   {"user6", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
187   {"user7", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
188   {"user8", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
189   {"user9", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
190   {"user10", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
191   {"user11", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
192   {"user12", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
193   {"user13", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
194   {"user14", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
195   {"user15", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
196   {"user16", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
197 };
198 
199 
200 /* Turn a floating-point number into the canonical text form.  This scribbles
201    on print_buf */
202 
203 char *
flt_to_str(double val)204 flt_to_str (double val)
205 {
206   double f;
207 
208   if (val == __plinf)
209     return iname;
210   if (val == __neinf)
211     return mname;
212   f = fabs (val);
213   if (f >= 1e6 || (f > 0 && f <= 9.9999e-6))
214     {
215       sprintf (print_buf, "%e", val);
216       return print_buf;
217     }
218   return pr_flt (val, &fxt, FLOAT_PRECISION);
219 }
220 
221 /* This is used to return a formatted float for editing.
222  * It is called as an alternative to flt_to_str, but
223  * requires the cell array instead of the value to
224  * do its work.  POSSIBLY this could be merged with
225  * flt_to_str, if the cell arraw cp is available wherever
226  * flt_to_str is used.  For now, though, this does the job.
227  */
228 
229 char *
flt_to_str_fmt(CELL * cp)230 flt_to_str_fmt (CELL *cp)
231 {
232   int j = GET_FORMAT(cp);	/* Only format, not precision */
233   int p;
234   double f;
235 
236   if (j == FMT_DEF)
237     j = default_fmt;
238 
239   p = GET_PRECISION(cp);
240 
241   if (cp->cell_flt == __plinf)
242     return iname;
243   if (cp->cell_flt == __neinf)
244     return mname;
245   f = fabs (cp->cell_flt);
246   if (f >= 1e6 || (f > 0 && f <= 9.9999e-6))
247     {
248       sprintf (print_buf, "%e", cp->cell_flt);
249       return print_buf;
250     }
251   switch (j)
252     {
253       case FMT_FXT:
254       case FMT_DOL:
255       case FMT_PCT:
256         return pr_flt (cp->cell_flt, &fxt, p);
257       default:
258         return flt_to_str (cp->cell_flt);
259     }
260 }
261 
262 char *
long_to_str(long val)263 long_to_str (long val)
264 {
265   sprintf (print_buf, "%ld", val);
266   return print_buf;
267 }
268 
269 /* create the human-readable version of the contents of a cell
270    This scribbles on print-buf bigtime */
271 
272 char *
print_cell(CELL * cp)273 print_cell (CELL * cp)
274 {
275   int j;
276   int p;
277   long num;
278   static char zeroes[] = "000000000000000";
279 
280   if (!cp)
281     return "";
282 
283   j = GET_FORMAT (cp);
284 
285   p = GET_PRECISION (cp);
286   if (j == FMT_DEF) {
287     j = default_fmt;
288     p = default_prc;
289   }
290   if (j == FMT_HID || GET_TYP (cp) == 0)
291     return "";
292 
293   if (GET_TYP (cp) == TYP_STR)
294     return cp->cell_str;
295 
296   if (GET_TYP (cp) == TYP_BOL) {
297 #ifdef TEST
298       if (cp->cell_bol < 0 || cp->cell_bol > 1)
299 	panic ("Bool %d out of range", cp->cell_bol);
300 #endif
301       return bname[cp->cell_bol];
302     }
303   if (GET_TYP (cp) == TYP_ERR) {
304 #ifdef TEST
305       if (cp->cell_err > ERR_MAX || cp->cell_err < 0)
306 	panic ("Error %d out of range", cp->cell_err);
307 #endif
308       return ename[cp->cell_err];
309     }
310   if (GET_TYP (cp) == TYP_FLT) {
311       switch (j)
312 	{
313 	case FMT_GPH:
314 	  if (cp->cell_flt < 0)
315 	    {
316 	      j = '-';
317 	      num = -(cp->cell_flt);
318 	    }
319 	  else if (cp->cell_flt >= 1)
320 	    {
321 	      j = '+';
322 	      num = (cp->cell_flt);
323 	    }
324 	  else
325 	    {
326 	      j = '0';
327 	      num = 1;
328 	    }
329 	graph:
330 	  if (num >= sizeof (print_buf))
331 	    {
332 	      io_error_msg ("Cannot graph %d '%c'", p, j);
333 	      num = sizeof (print_buf) - 1;
334 	    }
335 	  print_buf[num] = '\0';
336 	  while (--num >= 0)
337 	    print_buf[num] = j;
338 	  return print_buf;
339 
340 	case FMT_USR:
341 	  return pr_flt (cp->cell_flt, &u[p], u[p].prec);
342 
343 	case FMT_GEN:
344 	  {
345 	    double f;
346 
347 	    f = fabs (cp->cell_flt);
348 
349 	    if (f >= 1e6 || (f > 0 && f <= 9.9999e-6))
350 	      goto handle_exp;
351 	    return pr_flt (cp->cell_flt, &fxt, p);
352 	  }
353 
354 	case FMT_DOL:
355 	  return pr_flt (cp->cell_flt, &dol, p);
356 
357 	case FMT_CMA:
358 	  return pr_flt (cp->cell_flt, &cma, p);
359 
360 	case FMT_PCT:
361 	  return pr_flt (cp->cell_flt, &pct, p);
362 
363 	case FMT_FXT:
364 	  return pr_flt (cp->cell_flt, &fxt, p);
365 
366 	case FMT_EXP:
367 	handle_exp:
368 	  if (cp->cell_flt == __plinf)
369 	    return iname;
370 	  if (cp->cell_flt == __neinf)
371 	    return mname;
372 	  if (p == FLOAT_PRECISION)
373 	    sprintf (print_buf, "%e", cp->cell_flt);
374 	  else
375 	    sprintf (print_buf, "%.*e", p, cp->cell_flt);
376 	  return print_buf;
377 #ifdef TEST
378 	default:
379 	  panic ("Unknown format %d", j);
380 	  return 0;
381 #endif
382 	}
383     }
384 
385   if (GET_TYP (cp) == TYP_INT) {
386       p = GET_PRECISION (cp);
387       switch (j)
388 	{
389 	case FMT_GPH:
390 	  if (cp->cell_int < 0)
391 	    {
392 	      j = '-';
393 	      num = -(cp->cell_int);
394 	    }
395 	  else if (cp->cell_int >= 1)
396 	    {
397 	      j = '+';
398 	      num = (cp->cell_int);
399 	    }
400 	  else
401 	    {
402 	      j = '0';
403 	      num = 1;
404 	    }
405 	  goto graph;
406 
407 #ifdef	FMT_DATE	/* Still depends on new style cell_flags */
408 	case FMT_DATE:
409 		{
410 		    time_t t = cp->cell_int;
411 		    int	f = GET_PRECISION(cp);		/* Determines date format */
412 		    struct tm *tmp = localtime(&t);
413 
414 #ifdef	HAVE_STRFTIME
415 		    (void)strftime(print_buf, sizeof(print_buf),
416 			date_formats[f], tmp);
417 #else
418 		    sprintf(print_buf,
419 			"%04d/%02d/%02d",
420 			tmp->tm_year + 1900,
421 			tmp->tm_mon + 1,
422 			tmp->tm_mday);
423 #endif
424 		    return print_buf;
425 		}
426 #endif
427 
428 	case FMT_USR:
429 	  return pr_int (cp->cell_int, &u[p], u[p].prec);
430 
431 	case FMT_GEN:
432 	  sprintf (print_buf, "%ld", cp->cell_int);
433 	  return print_buf;
434 
435 	case FMT_DOL:
436 	  return pr_int (cp->cell_int, &dol, p);
437 
438 	case FMT_CMA:
439 	  return pr_int (cp->cell_int, &cma, p);
440 
441 	case FMT_PCT:
442 	  return pr_int (cp->cell_int, &pct, p);
443 
444 	case FMT_FXT:
445 	  if (p != FLOAT_PRECISION && p != 0)
446 	    sprintf (print_buf, "%ld.%.*s", cp->cell_int, p, zeroes);
447 	  else
448 	    sprintf (print_buf, "%ld", cp->cell_int);
449 	  return print_buf;
450 
451 	case FMT_EXP:
452 	  if (p != FLOAT_PRECISION)
453 	    sprintf (print_buf, "%.*e", p, (double) (cp->cell_int));
454 	  else
455 	    sprintf (print_buf, "%e", (double) (cp->cell_int));
456 	  return print_buf;
457 #ifdef TEST
458 	default:
459 	  panic ("Unknown format %d", j);
460 	  return 0;
461 #endif
462 	}
463     }
464 #ifdef TEST
465   panic ("Unknown cell type %d", GET_TYP (cp));
466 #endif
467   return 0;
468 }
469 
470 /* Return the value of ROW,COL in a human-readable fashion
471  * In particular, strings are \\ed, and if add_quote is true,
472  * they will have "" around them.
473  */
474 char *
cell_value_string(CELLREF row,CELLREF col,int add_quote)475 cell_value_string (CELLREF row, CELLREF col, int add_quote)
476 {
477   CELL *cp;
478 
479   cp = find_cell (row, col);
480   if (!cp || !GET_TYP (cp))
481     return "";
482   switch (GET_TYP (cp))
483     {
484     case TYP_FLT:
485       return flt_to_str (cp->cell_flt);
486 
487     case TYP_INT:
488       sprintf (print_buf, "%ld", cp->cell_int);
489       return print_buf;
490 
491     case TYP_STR:
492       return backslash_a_string (cp->cell_str, add_quote);
493 
494     case TYP_BOL:
495       return bname[cp->cell_bol];
496 
497     case TYP_ERR:
498       return ename[cp->cell_err];
499 #ifdef TEST
500     default:
501       panic ("unknown type %d in cell_value_string", GET_TYP (cp));
502 #endif
503     }
504   return 0;
505 }
506 
507 static char *
pr_int(val,fmt,prec)508 pr_int (val, fmt, prec)
509      long val;
510      struct user_fmt *fmt;
511      int prec;
512 {
513   char *pf, *pff, *pt;
514   long int n;
515   int nn = 0;
516 
517   pt = &print_buf[sizeof (print_buf) - 1];
518   *pt = '\0';
519 
520   n = fmt->scale * ((val < 0) ? -val : val);
521   if (n == 0)
522     return fmt->zero ? fmt->zero : "";
523 
524   pf = pff = (val < 0) ? fmt->n_trl : fmt->p_trl;
525   if (pf && *pf)
526     {
527       while (*pf)
528 	pf++;
529       do
530 	*--pt = *--pf;
531       while (pf != pff);
532     }
533 
534   if (prec != FLOAT_PRECISION && prec != 0)
535     {
536       while (prec-- > 0)
537 	*--pt = '0';
538       pf = pff = fmt->decpt;
539       if (pf)
540 	{
541 	  while (*pf)
542 	    pf++;
543 	  do
544 	    *--pt = *--pf;
545 	  while (pf != pff);
546 	}
547       /* *--pt='.'; */
548     }
549   do
550     {
551       *--pt = (n % 10) + '0';
552       n /= 10;
553       if (nn++ == 2 && n > 0)
554 	{
555 	  if (fmt->comma && *(fmt->comma))
556 	    {
557 	      for (pf = pff = fmt->comma; *pf; pf++)
558 		;
559 	      do
560 		*--pt = *--pf;
561 	      while (pf != pff);
562 	    }
563 	  nn = 0;
564 	}
565     }
566   while (n > 0);
567 
568   pf = pff = (val < 0) ? fmt->n_hdr : fmt->p_hdr;
569   if (pf && *pf)
570     {
571       while (*pf)
572 	pf++;
573       do
574 	*--pt = *--pf;
575       while (pf != pff);
576     }
577   return pt;
578 }
579 
580 static char *
pr_flt(val,fmt,prec)581 pr_flt (val, fmt, prec)
582      double val;
583      struct user_fmt *fmt;
584      int prec;
585 {
586   char *iptr;
587   char *fptr;
588   char *pptr;
589   char *pf, *pff;
590   double fract, integer, tmpval;
591   int n;
592   int isneg;
593   int comlen;
594 
595   val *= fmt->scale;
596 
597   if (val == __plinf)
598     return iname;
599   if (val == __neinf)
600     return mname;
601   if (val != val)
602     return nname;
603 
604   iptr = &print_buf[BIGFLT];
605   fptr = &print_buf[BIGFLT];
606 
607 
608   if (val == 0)
609     return fmt->zero ? fmt->zero : "";
610 
611   if (val < 0)
612     {
613       isneg = 1;
614       val = -val;
615     }
616   else
617     isneg = 0;
618 
619   comlen = 0;
620   if (fmt->comma && *(fmt->comma))
621     for (pf = fmt->comma; *pf; comlen++, pf++)
622       ;
623 
624   fract = modf (val, &integer);
625   n = 0;
626   do
627     {
628       if (iptr < &print_buf[comlen])
629 	return numb_oflo;
630       tmpval = modf (integer / 10, &integer);
631       *--iptr = '0' + (int) ((tmpval + .01) * 10);
632       if (comlen && n++ == 2 && integer)
633 	{
634 	  n = 0;
635 	  pff = fmt->comma;
636 	  pf = pff + comlen;
637 	  do
638 	    *--iptr = *--pf;
639 	  while (pf != pff);
640 	}
641     }
642   while (integer);
643 
644   if (prec)
645     {
646       int p1;
647 
648       p1 = (prec == FLOAT_PRECISION) ? 15 : (prec > 0) ? prec : -prec;
649       pf = fmt->decpt;
650       while (pf && *pf)
651 	*fptr++ = *pf++;
652       /* *fptr++='.'; */
653       if (fract)
654 	{
655 	  do
656 	    {
657 	      fract = modf (fract * 10, &tmpval);
658 	      *fptr++ = '0' + (int) tmpval;
659 	    }
660 	  while (--p1 && fract);
661 	}
662       if (prec > 0 && prec != FLOAT_PRECISION)
663 	while (p1--)
664 	  *fptr++ = '0';
665       else
666 	{
667 	  fract = 0;
668 	  while (fptr[-1] == '0')
669 	    --fptr;
670 	  while (!isdigit (fptr[-1]))
671 	    --fptr;
672 	  *fptr = '\0';
673 	}
674     }
675   if (fract)
676     {
677       (void) modf (fract * 10, &tmpval);
678       if (tmpval > 4)
679 	{
680 	  iptr[-1] = '0';
681 	  for (pptr = fptr - 1;; --pptr)
682 	    {
683 	      if (!isdigit (*pptr))
684 		continue;
685 	      else if (*pptr == '9')
686 		{
687 		  if (pptr == fptr - 1 && pptr > &print_buf[BIGFLT] && (prec < 0 || prec == FLOAT_PRECISION))
688 		    {
689 		      --fptr;
690 		      while (!isdigit (pptr[-1]))
691 			{
692 			  --fptr;
693 			  --pptr;
694 			}
695 		      *pptr = '\0';
696 		    }
697 		  else
698 		    *pptr = '0';
699 		}
700 	      else
701 		{
702 		  (*pptr)++;
703 		  break;
704 		}
705 	    }
706 	  if (pptr < iptr)
707 	    {
708 	      --iptr;
709 	      if (n == 3)
710 		{
711 		  char tmpch;
712 
713 		  tmpch = *iptr++;
714 		  for (pf = pff = fmt->comma; *pf; pf++)
715 		    ;
716 		  do
717 		    *--iptr = *--pf;
718 		  while (pf != pff);
719 		  *--iptr = tmpch;
720 		}
721 	    }
722 	}
723     }
724   pf = pff = (isneg) ? fmt->n_hdr : fmt->p_hdr;
725   if (pf && *pf)
726     {
727       while (*pf)
728 	pf++;
729       do
730 	*--iptr = *--pf;
731       while (pf != pff);
732     }
733 
734   pf = (isneg) ? fmt->n_trl : fmt->p_trl;
735   while (pf && *pf)
736     *fptr++ = *pf++;
737   *fptr = 0;
738   return iptr;
739 }
740 
741 char *
adjust_prc(char * oldp,CELL * cp,int width,int smallwid,int just)742 adjust_prc (char *oldp, CELL * cp, int width, int smallwid, int just)
743 {
744   int fmt;
745   int prc;
746   struct user_fmt *ufmt;
747   char *bptr;
748   char *eptr;
749   int len;
750 
751   fmt = GET_FORMAT (cp);
752   if (fmt == FMT_DEF)
753     fmt = default_fmt;
754   prc = GET_PRECISION (cp);
755   switch (fmt)
756     {
757     case FMT_GPH:
758     case FMT_HID:
759       return numb_oflo;
760     case FMT_DOL:
761       ufmt = &dol;
762       goto deal_fmt;
763 
764     case FMT_CMA:
765       ufmt = &cma;
766       goto deal_fmt;
767 
768     case FMT_PCT:
769       ufmt = &cma;
770       goto deal_fmt;
771 
772     case FMT_FXT:
773       ufmt = &fxt;
774       goto deal_fmt;
775 
776     case FMT_USR:
777       ufmt = &u[prc];
778       prc = ufmt->prec;
779       goto deal_fmt;
780 
781     case FMT_GEN:
782       if (prc != FLOAT_PRECISION)
783 	return numb_oflo;
784       if (index (oldp, 'e') || !index (oldp, '.'))
785 	goto handle_exp;
786 
787       ufmt = &fxt;
788       prc = FLOAT_PRECISION;
789       goto deal_fmt;
790 
791     deal_fmt:
792       if (prc != FLOAT_PRECISION)
793 	return numb_oflo;
794       len = strlen (oldp);
795       bptr = (char *) strstr (oldp, ufmt->decpt);
796       if (!bptr)
797 	return numb_oflo;
798       while ((eptr = (char *) strstr (bptr + 1, ufmt->decpt)))
799 	bptr = eptr;
800 
801       if (width < bptr - oldp)
802 	return numb_oflo;
803       if (bptr - oldp + strlen (ufmt->decpt) >= width)
804 	prc = 0;
805       else
806 	{
807 	  prc = width - (strlen (ufmt->decpt) + bptr - oldp);
808 	}
809       bptr = pr_flt (cp->cell_flt, ufmt, -prc);
810       len = strlen (bptr);
811       if (len > width && prc > 0)
812 	{
813 	  bptr = pr_flt (cp->cell_flt, ufmt, -(prc - 1));
814 	  len = strlen (bptr);
815 	}
816       if (len > width)
817 	return numb_oflo;
818       break;
819 
820     case FMT_EXP:
821     handle_exp:
822       {
823 	double f;
824 
825 	f = fabs (cp->cell_flt);
826 	if (f > 9.99999e99 || f < 1e-99)
827 	  len = width - 7;
828 	else			/* if(f>9.9999999e9 || f<1e-9) */
829 	  len = width - 6;
830 	/* else
831 	   len=width-5; */
832 	if (cp->cell_flt < 0)
833 	  --len;
834 	if (len > 0)
835 	  {
836 	    sprintf (oldp, "%.*e", len, cp->cell_flt);
837 	    len = strlen (oldp);
838 	    if (len <= width)
839 	      {
840 		bptr = oldp;
841 		break;
842 	      }
843 	  }
844       }
845       return numb_oflo;
846     default:
847       bptr = 0;
848       len = 0;
849 #ifdef TEST
850       panic ("Unknown format %d in adjust_prc()", fmt);
851 #endif
852       break;
853     }
854 
855   /* If we get here, bptr points to a a string of len characters
856      (len<=width) that we want to output */
857   if (len < smallwid)
858     {
859       if (just == JST_RGT || just == JST_CNT)
860 	{
861 	  int n;
862 
863 	  n = (just == JST_RGT) ? smallwid - len : (1 + smallwid - len) / 2;
864 	  for (;;)
865 	    {
866 	      bptr[len + n] = bptr[len];
867 	      if (len-- == 0)
868 		break;
869 	    }
870 	  while (n-- >= 0)
871 	    bptr[n] = ' ';
872 	}
873     }
874   return bptr;
875 }
876 
877 
878 void
set_usr_stats(int usr_n,char ** usr_buf)879 set_usr_stats (int usr_n, char **usr_buf)
880 {
881   int len;
882   int i;
883   char *p_in, *p_out;
884 
885   len = 0;
886   for (i = 0; i < 7; i++)
887     len += strlen (usr_buf[i]);
888   u[usr_n].p_hdr = ck_malloc (len + 7);
889   p_out = u[usr_n].p_hdr;
890   if (usr_buf[0][0])
891     {
892       p_in = usr_buf[0];
893       while ((*p_out++ = *p_in++))
894 	;
895     }
896   else
897     *p_out++ = '\0';
898 
899   if (usr_buf[1][0])
900     {
901       p_in = usr_buf[1];
902       u[usr_n].n_hdr = p_out;
903       while ((*p_out++ = *p_in++))
904 	;
905     }
906   else
907     u[usr_n].n_hdr = 0;
908 
909   if (usr_buf[2][0])
910     {
911       p_in = usr_buf[2];
912       u[usr_n].p_trl = p_out;
913       while ((*p_out++ = *p_in++))
914 	;
915     }
916   else
917     u[usr_n].p_trl = 0;
918 
919   if (usr_buf[3][0])
920     {
921       p_in = usr_buf[3];
922       u[usr_n].n_trl = p_out;
923       while ((*p_out++ = *p_in++))
924 	;
925     }
926   else
927     u[usr_n].n_trl = 0;
928 
929   if (usr_buf[4][0])
930     {
931       p_in = usr_buf[4];
932       u[usr_n].zero = p_out;
933       while ((*p_out++ = *p_in++))
934 	;
935     }
936   else
937     u[usr_n].zero = 0;
938 
939   if (usr_buf[5][0])
940     {
941       p_in = usr_buf[5];
942       u[usr_n].comma = p_out;
943       while ((*p_out++ = *p_in++))
944 	;
945     }
946   else
947     u[usr_n].comma = 0;
948 
949   if (usr_buf[6][0])
950     {
951       p_in = usr_buf[6];
952       u[usr_n].decpt = p_out;
953       while ((*p_out++ = *p_in++))
954 	;
955     }
956   else
957     u[usr_n].decpt = 0;
958 
959   if (!stricmp (usr_buf[7], "float") || !stricmp (usr_buf[7], "f"))
960     u[usr_n].prec = 15;
961   else
962     u[usr_n].prec = astol (&usr_buf[7]);
963 
964   u[usr_n].scale = astof (&usr_buf[8]);
965 }
966 
967 int
usr_set_fmts(void)968 usr_set_fmts (void)
969 {
970   int n;
971   int ret = 0;
972 
973   for (n = 0; n < NUM_USER_FMT; n++)
974     if (u[n].p_hdr)
975       ret |= 1 << n;
976   return ret;
977 }
978 
979 void
get_usr_stats(int usr_num,char ** usr_buf)980 get_usr_stats (int usr_num, char **usr_buf)
981 {
982   static char buf1[30];
983   static char buf2[30];
984   static char NullStr[] = "";
985 
986   usr_buf[0] = u[usr_num].p_hdr ? u[usr_num].p_hdr : NullStr;
987   usr_buf[1] = u[usr_num].n_hdr ? u[usr_num].n_hdr : NullStr;
988   usr_buf[2] = u[usr_num].p_trl ? u[usr_num].p_trl : NullStr;
989   usr_buf[3] = u[usr_num].n_trl ? u[usr_num].n_trl : NullStr;
990   usr_buf[4] = u[usr_num].zero ? u[usr_num].zero : NullStr;
991   usr_buf[5] = u[usr_num].comma ? u[usr_num].comma : NullStr;
992   usr_buf[6] = u[usr_num].decpt ? u[usr_num].decpt : NullStr;
993   if (u[usr_num].prec == 15)
994     usr_buf[7] = "float";
995   else
996     {
997       sprintf (buf1, "%u", u[usr_num].prec);
998       usr_buf[7] = buf1;
999     }
1000   sprintf (buf2, "%.12g", u[usr_num].scale);
1001   usr_buf[8] = buf2;
1002 }
1003 
1004 /* Functions for printing out the names of cells and ranges */
1005 
1006 char *
cell_name(CELLREF rr,CELLREF cc)1007 cell_name (CELLREF rr, CELLREF cc)
1008 {
1009   static char strs[2][20];
1010   static int num = 0;
1011   char *ptr;
1012 
1013   num = num ? 0 : 1;
1014 
1015   if (Global->a0)
1016     {
1017       ptr = &strs[num][9];
1018       sprintf (ptr, "%u", rr);
1019       if (cc < MIN_COL + 26)
1020 	*--ptr = 'A' - MIN_COL + cc;
1021 #if MAX_COL>702
1022       else if (cc < MIN_COL + 702)
1023 	{
1024 	  cc -= MIN_COL + 26;
1025 	  *--ptr = 'A' + cc % 26;
1026 	  *--ptr = 'A' + cc / 26;
1027 	}
1028       else if (cc < MIN_COL + 18278)
1029 	{
1030 	  cc -= MIN_COL + 702;
1031 	  *--ptr = 'A' + cc % 26;
1032 	  cc /= 26;
1033 	  *--ptr = 'A' + cc % 26;
1034 	  *--ptr = 'A' + cc / 26;
1035 	}
1036       else
1037 	{
1038 	  cc -= MIN_COL + 18278;
1039 	  *--ptr = 'A' + cc % 26;
1040 	  cc /= 26;
1041 	  *--ptr = 'A' + cc % 26;
1042 	  cc /= 26;
1043 	  *--ptr = 'A' + cc % 26;
1044 	  *--ptr = 'A' + cc / 26;
1045 	}
1046 #else
1047       else
1048 	{
1049 	  cc -= MIN_COL + 26;
1050 	  *--ptr = 'A' + cc % 26;
1051 	  *--ptr = 'A' + cc / 26;
1052 	}
1053 #endif
1054     }
1055   else
1056     {
1057       ptr = &strs[num][0];
1058       sprintf (ptr, "r%uc%u", rr, cc);
1059     }
1060   return ptr;
1061 }
1062 
1063 char *
range_name(struct rng * rng)1064 range_name (struct rng *rng)
1065 {
1066   CELLREF lr, lc, hr, hc;
1067   static char buf[2][40];
1068   static int num;
1069   char *ptr;
1070 
1071   ptr = &buf[num][0];
1072   num = num ? 0 : 1;
1073 
1074   lr = rng->lr;
1075   lc = rng->lc;
1076   hr = rng->hr;
1077   hc = rng->hc;
1078 
1079   /* Return empty string when invalid */
1080   if (lr == 0 || lc == 0 || hc == 0 || hr == 0 ||
1081       lr >= MAX_ROW || lc >= MAX_COL || hc >= MAX_COL || hr >= MAX_ROW) {
1082 	ptr[0] = '\0';
1083 	return ptr;
1084   }
1085 
1086   if ((lr == hr) && (lc == hc)) {
1087       sprintf (ptr, "%s", cell_name (lr, lc));
1088   } else {
1089       if (Global->a0)
1090         sprintf (ptr, "%s:%s", cell_name (lr, lc), cell_name (hr, hc));
1091       else {
1092           if (lr == hr && lc != hc)
1093             sprintf (ptr, "r%uc%u:%u", lr, lc, hc);
1094           else if (lr != hr && lc == hc)
1095             sprintf (ptr, "r%u:%uc%u", lr, hr, lc);
1096           else
1097             sprintf (ptr, "r%u:%uc%u:%u", lr, hr, lc, hc);
1098       }
1099   }
1100   return ptr;
1101 }
1102 
1103 
1104 /* Parse a range, allowing variable names.
1105  * Return 1 on failure, 0 on succes.
1106  */
1107 int
get_abs_rng(char ** pptr,struct rng * retp)1108 get_abs_rng (char **pptr, struct rng *retp)
1109 {
1110   unsigned char n;
1111   struct rng ignored;
1112 
1113   if (!retp)
1114     retp = &ignored;
1115 
1116   while (**pptr == ' ')
1117     (*pptr)++;
1118   if (!**pptr)
1119     return 1;
1120   cur_row = curow;
1121   cur_col = cucol;
1122   n = parse_cell_or_range (pptr, retp);
1123   if (!n)
1124     {
1125       struct var *v;
1126       char *ptr;
1127 
1128       ptr = *pptr;
1129       while (ptr[n] && ptr[n] != ' ')
1130 	n++;
1131       v = find_var (ptr, n);
1132       if (!v)
1133 	return 1;
1134       (*pptr) += n;
1135       *retp = v->v_rng;
1136     }
1137   return 0;
1138 }
1139 
1140 
1141 char *
col_to_str(CELLREF col)1142 col_to_str (CELLREF col)
1143 {
1144   static char strs[2][10];
1145   static int num;
1146   char *ptr;
1147 
1148   ptr = &strs[num][9];
1149   num = num ? 0 : 1;
1150 
1151   if (col < MIN_COL + 26)
1152     *--ptr = 'A' - MIN_COL + col;
1153 #if MAX_COL>702
1154   else if (col < MIN_COL + 702)
1155     {
1156       col -= MIN_COL + 26;
1157       *--ptr = 'A' + col % 26;
1158       *--ptr = 'A' + col / 26;
1159     }
1160   else if (col < MIN_COL + 18278)
1161     {
1162       col -= MIN_COL + 702;
1163       *--ptr = 'A' + col % 26;
1164       col /= 26;
1165       *--ptr = 'A' + col % 26;
1166       *--ptr = 'A' + col / 26;
1167     }
1168   else
1169     {
1170       col -= MIN_COL + 18278;
1171       *--ptr = 'A' + col % 26;
1172       col /= 26;
1173       *--ptr = 'A' + col % 26;
1174       col /= 26;
1175       *--ptr = 'A' + col % 26;
1176       *--ptr = 'A' + col / 26;
1177     }
1178 #else
1179   else
1180     {
1181       col -= MIN_COL + 26;
1182       *--ptr = 'A' + col % 26;
1183       *--ptr = 'A' + col / 26;
1184     }
1185 #endif
1186   return ptr;
1187 }
1188 
1189 void
clear_spreadsheet(void)1190 clear_spreadsheet (void)
1191 {
1192   int n;
1193 
1194   flush_everything ();
1195   /* flush_widths(); */
1196   flush_all_timers ();
1197   for (n = 0; n < NUM_USER_FMT; n++)
1198     {
1199       if (u[n].p_hdr)
1200 	{
1201 	  free (u[n].p_hdr);
1202 	  u[n].p_hdr = 0;
1203 	  u[n].prec = FLOAT_PRECISION;
1204 	  u[n].scale = 1;
1205 	}
1206     }
1207   default_width = saved_default_width;
1208   default_height = saved_default_height;
1209   default_jst = JST_LFT;
1210   default_fmt = FMT_GEN;
1211   default_lock = LCK_UNL;
1212 }
1213 
1214 char *ename[] =
1215 {
1216   "#WHAT?",
1217   "#ERROR", "#BAD_INPUT", "#NON_NUMBER", "#NON_STRING",
1218   "#NON_BOOL", "#NON_RANGE", "#OUT_OF_RANGE", "#NO_VALUES",
1219   "#DIV_BY_ZERO", "#BAD_NAME", "#NOT_AVAIL", "#PARSE_ERROR",
1220   "#NEED_OPEN", "#NEED_CLOSE", "#NEED_QUOTE", "#UNK_CHAR",
1221   "#UNK_FUNC",
1222   0
1223 };
1224 
1225 char tname[] = "#TRUE";
1226 char fname[] = "#FALSE";
1227 
1228 
1229 int
words_imatch(char ** ptr,char * key)1230 words_imatch (char **ptr, char *key)
1231 {
1232   char *str = *ptr;
1233 
1234   while (isspace (*str))
1235     ++str;
1236   while (isspace (*key))
1237     ++key;
1238 
1239   while (1)
1240     {
1241       while (*str && *key && (toupper (*str) == toupper (*key)))
1242 	{
1243 	  ++str;
1244 	  ++key;
1245 	}
1246       /* If we're not at word breaks in both strings... */
1247       if (!((!*str || isspace (*str)) && (!*key || isspace (*key))))
1248 	return 0;
1249       else
1250 	{
1251 	  while (isspace (*key))
1252 	    ++key;
1253 	  while (isspace (*str))
1254 	    ++str;
1255 	  if (!*key)
1256 	    {
1257 	      *ptr = str;
1258 	      return 1;
1259 	    }
1260 	}
1261     }
1262 }
1263 
1264 int
parray_len(char ** array)1265 parray_len (char **array)
1266 {
1267   int x;
1268   for (x = 0; array[x]; ++x);
1269   return x;
1270 }
1271 
1272 
1273 /* Return the index of CHECK in KEYS or -1.  Case and whitespeace insenstive.
1274  */
1275 
1276 int
words_member(char ** keys,int len,char * check)1277 words_member (char **keys, int len, char *check)
1278 {
1279   int x;
1280   for (x = 0; x < len; ++x)
1281     {
1282       char *ch = check;
1283       if (words_imatch (&ch, keys[x]))
1284 	if (!*ch)
1285 	  return x;
1286     }
1287   return -1;
1288 }
1289 
1290 int
prompt_len(char * prompt)1291 prompt_len (char *prompt)
1292 {
1293   char *pos;
1294   if (!prompt)
1295     return 0;
1296   for (pos = prompt; *pos && (*pos != '\n'); ++pos)
1297     ;
1298   return pos - prompt;
1299 }
1300 
1301 
1302 int
says_default(char * str)1303 says_default (char *str)
1304 {
1305   char *key = "ault";
1306   if (strincmp (str, "def", 3))
1307     return 0;
1308   str += 3;
1309   while (*str && *key)
1310     {
1311       int c = isupper (*str) ? tolower (*str) : *str;
1312       if (c != *key)
1313 	return 0;
1314       ++key;
1315       ++str;
1316     }
1317   while (isspace (*str))
1318     ++str;
1319   return !*str;
1320 }
1321 
1322 static char *defaultformat = NULL;
1323 
1324 void
file_set_default_format(char * s)1325 file_set_default_format(char *s)
1326 {
1327 	if (defaultformat)
1328 		free(defaultformat);
1329 
1330 	if (s == NULL)
1331 		defaultformat = strdup("oleo");
1332 	else
1333 		defaultformat = s;
1334 }
1335 
1336 char *
file_get_default_format(void)1337 file_get_default_format(void)
1338 {
1339 	return defaultformat;
1340 }
1341 
1342 int
write_file_generic_2(FILE * fp,struct rng * rng,char * format)1343 write_file_generic_2(FILE *fp, struct rng *rng, char *format)
1344 {
1345 	if (!stricmp ("oleo", format)) {
1346 		oleo_write_file(fp, rng);
1347 	} else if (!stricmp ("sylk", format)) {
1348 		Global->sylk_a0 = 1;
1349 		sylk_write_file(fp, rng);
1350 	} else if (!stricmp ("sylk-noa0", format)) {
1351 		Global->sylk_a0 = 0;
1352 		sylk_write_file(fp, rng);
1353 	} else if (!stricmp ("sc", format)) {
1354 		sc_write_file(fp, rng);
1355 #ifdef	HAVE_PANIC_SAVE
1356 	} else if (!stricmp ("panic", format)) {
1357 		panic_write_file(fp, rng);
1358 #endif
1359 	} else if (!stricmp ("list", format)) {
1360 		list_write_file(fp, rng);
1361 	} else {
1362 		return -1;
1363 	}
1364 
1365 	return 0;
1366 }
1367 
1368 void
write_file_generic(FILE * fp,struct rng * rng,char * format)1369 write_file_generic(FILE *fp, struct rng *rng, char *format)
1370 {
1371 	if (format == NULL) {
1372 		if (defaultformat)
1373 			(void) write_file_generic_2(fp, rng, defaultformat);
1374 		else
1375 			oleo_write_file(fp, rng);
1376 
1377 		return;
1378 	}
1379 #if 0
1380 	fprintf(stderr, PACKAGE " write_file_generic : format %s\n", format);
1381 #endif
1382 	if (write_file_generic_2(fp, rng, format) != 0) {
1383 		if (write_file_generic_2(fp, rng, defaultformat) != 0)
1384 			oleo_write_file(fp, rng);
1385 	}
1386 }
1387 
1388 int
read_file_generic_2(FILE * fp,int ismerge,char * format,char * name)1389 read_file_generic_2(FILE *fp, int ismerge, char *format, char *name)
1390 {
1391 	if (stricmp ("oleo", format) == 0) {
1392 		oleo_read_file(fp, ismerge);
1393 	} else if (stricmp ("sylk", format) == 0 || stricmp ("slk", format) == 0) {
1394 		Global->sylk_a0 = 0;	/* FIX ME */
1395 		sylk_read_file(fp, ismerge);
1396 	} else if (stricmp ("sylk-noa0", format) == 0) {
1397 		Global->sylk_a0 = 0;
1398 		sylk_read_file(fp, ismerge);
1399 	} else if (stricmp ("sc", format) == 0) {
1400 		sc_read_file(fp, ismerge);
1401 #ifdef	HAVE_PANIC_SAVE
1402 	} else if (stricmp ("panic", format) == 0) {
1403 		panic_read_file(fp, ismerge);
1404 #endif
1405 	} else if (stricmp ("list", format) == 0) {
1406 		list_read_file(fp, ismerge);
1407 	} else if (stricmp("csv", format) == 0) {
1408 		list_set_separator(',');
1409 		list_read_file(fp, ismerge);
1410 	} else if (stricmp("dbf", format) == 0) {
1411 #if defined(HAVE_LIBXBASE) || defined(HAVE_LIBXDB)
1412 		ReadXbaseFile(name, ismerge);
1413 #else
1414 		io_error_msg ("Cannot read XBASE file (xbase not compiled into " PACKAGE ")");
1415 		return -1;
1416 #endif
1417 	} else {
1418 		return -1;
1419 	}
1420 	return 0;
1421 }
1422 
1423 static struct file_formats_s {
1424 	char	*name;
1425 	char	*format;
1426 } file_formats[] = {
1427 	{ "oleo",	"oleo" },
1428 	{ "sylk",	"[sS]*[lL][kK]" },
1429 	{ "sc",		"sc" },
1430 	{ "list",	"list" },
1431 	{ "csv",	"[cC][sS][vV]" },
1432 	{ "dbf",	"[dD][bB][fF]" },
1433 #ifdef	HAVE_PANIC_SAVE
1434 	{ "panic",	"panic" },
1435 #endif
1436 	{ "sylk-noa0",	"sylk" },
1437 	{ NULL,	NULL }
1438 };
1439 
1440 char *
file_get_format(int i)1441 file_get_format(int i)
1442 {
1443 	int	m = sizeof(file_formats) / sizeof(struct file_formats_s) - 1;
1444 
1445 	if (i > m || i <= 0)
1446 		return NULL;
1447 
1448 	return file_formats[i-1].name;
1449 }
1450 
1451 char *
file_get_pattern(char * fmt)1452 file_get_pattern(char *fmt)
1453 {
1454 	int	i, m = sizeof(file_formats) / sizeof(struct file_formats_s) - 1;
1455 
1456 	for (i=0; i<m; i++) {
1457 		if (strcmp(fmt, file_formats[i].name) == 0)
1458 			return file_formats[i].format;
1459 	}
1460 	return NULL;
1461 }
1462 
1463 void
read_file_generic(FILE * fp,int ismerge,char * format,char * name)1464 read_file_generic(FILE *fp, int ismerge, char *format, char *name)
1465 {
1466 	if (format == NULL) {
1467 		if (defaultformat)
1468 			(void) read_file_generic_2(fp, ismerge, defaultformat, name);
1469 		else
1470 			oleo_read_file(fp, ismerge);
1471 
1472 		return;
1473 	}
1474 #if 0
1475 	fprintf(stderr, PACKAGE " read_file_generic : format %s\n", format);
1476 #endif
1477 	if (read_file_generic_2(fp, ismerge, format, name) != 0) {
1478 		if (defaultformat && read_file_generic_2(fp, ismerge, defaultformat, name) != 0)
1479 			oleo_read_file(fp, ismerge);
1480 	}
1481 
1482 	recalculate(1);
1483 }
1484 
1485 void
fmt_set_format()1486 fmt_set_format()
1487 {
1488 }
1489 
1490 void
fmt_get_format()1491 fmt_get_format()
1492 {
1493 }
1494 
FileSetCurrentFileName(const char * s)1495 void FileSetCurrentFileName(const char *s)
1496 {
1497 	if (Global->FileName)
1498 		free(Global->FileName);
1499 	Global->FileName = NULL;
1500 	if (s)
1501 		Global->FileName = strdup(s);
1502 
1503 #if HAVE_MOTIF
1504 	if (using_motif)
1505 		MotifSetWindowName(Global->FileName);
1506 #endif
1507 }
1508 
FileGetCurrentFileName(void)1509 char *FileGetCurrentFileName(void)
1510 {
1511 	return Global->FileName;
1512 }
1513 
FileCloseCurrentFile(void)1514 void FileCloseCurrentFile(void)
1515 {
1516 	if (Global->FileName)
1517 		free(Global->FileName);
1518 	Global->FileName = NULL;
1519 
1520 #if HAVE_MOTIF
1521 	if (using_motif)
1522 		MotifSetWindowName("");
1523 #endif
1524 }
1525 
OleoSetEncoding(char * s)1526 void OleoSetEncoding(char *s)
1527 {
1528 	extern void PrintSetEncoding(char *encoding);  /* in print.c */
1529 
1530 	if (Global && Global->encoding)
1531 		free(Global->encoding);
1532 	Global->encoding = strdup(s);
1533 
1534 	PrintSetEncoding(s);
1535 }
1536 
OleoGetEncoding(void)1537 char *OleoGetEncoding(void)
1538 {
1539 	return Global->encoding;
1540 }
1541 
OleoUserPrefEncoding(char * s)1542 void OleoUserPrefEncoding(char *s)
1543 {
1544 	char	*p = s + 9;	/* Get past "encoding" */
1545 
1546 	for (; *p && isspace(*p); p++) ;
1547 	OleoSetEncoding(p);
1548 }
1549