/*
* $Id: io-utils.c,v 1.39 2001/02/13 23:38:06 danny Exp $
*
* Copyright © 1990, 1992, 1993, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of Oleo, the GNU Spreadsheet.
*
* Oleo is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* Oleo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* Oleo; see the file COPYING. If not, write to the Free Software Foundation, 675
* Mass Ave, Cambridge, MA 02139, USA.
*/
static char *rcsid = "$Id: ";
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WITH_DMALLOC
#include <dstdlib.h>
#endif
#include <stdio.h>
#include <ctype.h>
#include "sysdef.h"
#include "io-utils.h"
#include "cell.h"
#include "ref.h"
#include "decompile.h"
#include "io-generic.h"
#include "io-abstract.h"
#include "lists.h"
#include "io-term.h"
#include "cmd.h"
#include "sylk.h"
#ifdef HAVE_MOTIF
#include "io-motif.h"
#endif
#include "basic.h"
#include "oleofile.h"
#include "sc.h"
#include "list.h"
#ifdef HAVE_TIME_H
#include <time.h>
#endif
/* Routines for formatting cell values */
struct user_fmt;
static char *pr_flt (double, struct user_fmt *, int);
static char *pr_int (long, struct user_fmt *, int);
/* Constants */
char *bname[] =
{
"#FALSE", "#TRUE"
};
char numb_oflo[] = "########################################";
double __plinf;
double __neinf;
double ___nan;
char nname[] = "#NOT_A_NUMBER";
char iname[] = "#INFINITY";
char mname[] = "#MINUS_INFINITY";
char *date_formats[] = {
"%Y/%m/%d", /* YYYY/MM/DD */
"%Y-%m-%d", /* YYYY-MM-DD */
"%d/%m/%Y", /* European style */
"%m/%d/%Y", /* American style */
"%d/%m",
"%Y%m",
"%m%Y",
"%B %d, %Y", /* Month, day, year */
"%d %B %Y", /* Day, month, year */
"%b %d, %Y", /* Mon, day, year */
"%d %b %Y", /* Day, mon, year */
NULL
};
static double
divide (a, b)
double a;
double b;
{
return a / b;
}
static RETSIGTYPE
ignore_sig (sig)
int sig;
{
(void) signal (SIGFPE, ignore_sig);
}
/* It's ok of this fails and generates signals. In that case,
* the same signal will occur when evaluating formulas and a
* (less informative) error value substituted. Note that this
* should be called before init_eval.
*/
void
init_infinity (void)
{
#ifdef MAXFLOAT
__plinf = MAXFLOAT;
__neinf = - MAXFLOAT;
#else
(void) signal (SIGFPE, ignore_sig);
__plinf = divide (1., 0.);
(void) signal (SIGFPE, ignore_sig);
__neinf = divide (-1., 0.);
(void) signal (SIGFPE, ignore_sig);
#endif
___nan = __plinf + __neinf;
}
/* Slightly larger than the maximum exponent we ever expect to see */
#define BIGFLT 309
#ifdef TEST
char print_buf[1024 * 8];
#else
char print_buf[BIGFLT + 20];
#endif
/* Structures/vars/functions for dealing with formatting floating-point
numbers, etc */
struct user_fmt {
char *name, /* Format name */
*p_hdr, /* Positive header */
*n_hdr, /* Negative header */
*p_trl, /* Positive trailer */
*n_trl, /* Negative trailer */
*zero, /* How to represent a 0 */
*comma, /* Thousands separator */
*decpt; /* Decimal point */
unsigned char prec; /* Precision */
double scale; /* Scale */
};
struct user_fmt dol =
{ "dollar", "$", "($", 0, ")", "$0", ",", ".", FLOAT_PRECISION, 1};
struct user_fmt cma =
{ "comma", 0, "(", 0, ")", "0", ",", ".", FLOAT_PRECISION, 1};
struct user_fmt pct =
#if 0
{ "percent", 0, "-", "%", "%", "0%", 0, ".", 3, 100};
#else
{ "percent", 0, "-", "%", "%", "0%", 0, ".", FLOAT_PRECISION, 100};
#endif
struct user_fmt fxt =
{ "fixed", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1};
/* Variables */
#define NUM_USER_FMT (16)
struct user_fmt u[NUM_USER_FMT] =
{
{"user1", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user2", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user3", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user4", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user5", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user6", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user7", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user8", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user9", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user10", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user11", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user12", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user13", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user14", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user15", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
{"user16", 0, "-", 0, 0, "0", 0, ".", FLOAT_PRECISION, 1},
};
/* Turn a floating-point number into the canonical text form. This scribbles
on print_buf */
char *
flt_to_str (double val)
{
double f;
if (val == __plinf)
return iname;
if (val == __neinf)
return mname;
f = fabs (val);
if (f >= 1e6 || (f > 0 && f <= 9.9999e-6))
{
sprintf (print_buf, "%e", val);
return print_buf;
}
return pr_flt (val, &fxt, FLOAT_PRECISION);
}
/* This is used to return a formatted float for editing.
* It is called as an alternative to flt_to_str, but
* requires the cell array instead of the value to
* do its work. POSSIBLY this could be merged with
* flt_to_str, if the cell arraw cp is available wherever
* flt_to_str is used. For now, though, this does the job.
*/
char *
flt_to_str_fmt (CELL *cp)
{
int j = GET_FORMAT(cp); /* Only format, not precision */
int p;
double f;
if (j == FMT_DEF)
j = default_fmt;
p = GET_PRECISION(cp);
if (cp->cell_flt == __plinf)
return iname;
if (cp->cell_flt == __neinf)
return mname;
f = fabs (cp->cell_flt);
if (f >= 1e6 || (f > 0 && f <= 9.9999e-6))
{
sprintf (print_buf, "%e", cp->cell_flt);
return print_buf;
}
switch (j)
{
case FMT_FXT:
case FMT_DOL:
case FMT_PCT:
return pr_flt (cp->cell_flt, &fxt, p);
default:
return flt_to_str (cp->cell_flt);
}
}
char *
long_to_str (long val)
{
sprintf (print_buf, "%ld", val);
return print_buf;
}
/* create the human-readable version of the contents of a cell
This scribbles on print-buf bigtime */
char *
print_cell (CELL * cp)
{
int j;
int p;
long num;
static char zeroes[] = "000000000000000";
if (!cp)
return "";
j = GET_FORMAT (cp);
p = GET_PRECISION (cp);
if (j == FMT_DEF) {
j = default_fmt;
p = default_prc;
}
if (j == FMT_HID || GET_TYP (cp) == 0)
return "";
if (GET_TYP (cp) == TYP_STR)
return cp->cell_str;
if (GET_TYP (cp) == TYP_BOL) {
#ifdef TEST
if (cp->cell_bol < 0 || cp->cell_bol > 1)
panic ("Bool %d out of range", cp->cell_bol);
#endif
return bname[cp->cell_bol];
}
if (GET_TYP (cp) == TYP_ERR) {
#ifdef TEST
if (cp->cell_err > ERR_MAX || cp->cell_err < 0)
panic ("Error %d out of range", cp->cell_err);
#endif
return ename[cp->cell_err];
}
if (GET_TYP (cp) == TYP_FLT) {
switch (j)
{
case FMT_GPH:
if (cp->cell_flt < 0)
{
j = '-';
num = -(cp->cell_flt);
}
else if (cp->cell_flt >= 1)
{
j = '+';
num = (cp->cell_flt);
}
else
{
j = '0';
num = 1;
}
graph:
if (num >= sizeof (print_buf))
{
io_error_msg ("Cannot graph %d '%c'", p, j);
num = sizeof (print_buf) - 1;
}
print_buf[num] = '\0';
while (--num >= 0)
print_buf[num] = j;
return print_buf;
case FMT_USR:
return pr_flt (cp->cell_flt, &u[p], u[p].prec);
case FMT_GEN:
{
double f;
f = fabs (cp->cell_flt);
if (f >= 1e6 || (f > 0 && f <= 9.9999e-6))
goto handle_exp;
return pr_flt (cp->cell_flt, &fxt, p);
}
case FMT_DOL:
return pr_flt (cp->cell_flt, &dol, p);
case FMT_CMA:
return pr_flt (cp->cell_flt, &cma, p);
case FMT_PCT:
return pr_flt (cp->cell_flt, &pct, p);
case FMT_FXT:
return pr_flt (cp->cell_flt, &fxt, p);
case FMT_EXP:
handle_exp:
if (cp->cell_flt == __plinf)
return iname;
if (cp->cell_flt == __neinf)
return mname;
if (p == FLOAT_PRECISION)
sprintf (print_buf, "%e", cp->cell_flt);
else
sprintf (print_buf, "%.*e", p, cp->cell_flt);
return print_buf;
#ifdef TEST
default:
panic ("Unknown format %d", j);
return 0;
#endif
}
}
if (GET_TYP (cp) == TYP_INT) {
p = GET_PRECISION (cp);
switch (j)
{
case FMT_GPH:
if (cp->cell_int < 0)
{
j = '-';
num = -(cp->cell_int);
}
else if (cp->cell_int >= 1)
{
j = '+';
num = (cp->cell_int);
}
else
{
j = '0';
num = 1;
}
goto graph;
#ifdef FMT_DATE /* Still depends on new style cell_flags */
case FMT_DATE:
{
time_t t = cp->cell_int;
int f = GET_PRECISION(cp); /* Determines date format */
struct tm *tmp = localtime(&t);
#ifdef HAVE_STRFTIME
(void)strftime(print_buf, sizeof(print_buf),
date_formats[f], tmp);
#else
sprintf(print_buf,
"%04d/%02d/%02d",
tmp->tm_year + 1900,
tmp->tm_mon + 1,
tmp->tm_mday);
#endif
return print_buf;
}
#endif
case FMT_USR:
return pr_int (cp->cell_int, &u[p], u[p].prec);
case FMT_GEN:
sprintf (print_buf, "%ld", cp->cell_int);
return print_buf;
case FMT_DOL:
return pr_int (cp->cell_int, &dol, p);
case FMT_CMA:
return pr_int (cp->cell_int, &cma, p);
case FMT_PCT:
return pr_int (cp->cell_int, &pct, p);
case FMT_FXT:
if (p != FLOAT_PRECISION && p != 0)
sprintf (print_buf, "%ld.%.*s", cp->cell_int, p, zeroes);
else
sprintf (print_buf, "%ld", cp->cell_int);
return print_buf;
case FMT_EXP:
if (p != FLOAT_PRECISION)
sprintf (print_buf, "%.*e", p, (double) (cp->cell_int));
else
sprintf (print_buf, "%e", (double) (cp->cell_int));
return print_buf;
#ifdef TEST
default:
panic ("Unknown format %d", j);
return 0;
#endif
}
}
#ifdef TEST
panic ("Unknown cell type %d", GET_TYP (cp));
#endif
return 0;
}
/* Return the value of ROW,COL in a human-readable fashion
* In particular, strings are \\ed, and if add_quote is true,
* they will have "" around them.
*/
char *
cell_value_string (CELLREF row, CELLREF col, int add_quote)
{
CELL *cp;
cp = find_cell (row, col);
if (!cp || !GET_TYP (cp))
return "";
switch (GET_TYP (cp))
{
case TYP_FLT:
return flt_to_str (cp->cell_flt);
case TYP_INT:
sprintf (print_buf, "%ld", cp->cell_int);
return print_buf;
case TYP_STR:
return backslash_a_string (cp->cell_str, add_quote);
case TYP_BOL:
return bname[cp->cell_bol];
case TYP_ERR:
return ename[cp->cell_err];
#ifdef TEST
default:
panic ("unknown type %d in cell_value_string", GET_TYP (cp));
#endif
}
return 0;
}
static char *
pr_int (val, fmt, prec)
long val;
struct user_fmt *fmt;
int prec;
{
char *pf, *pff, *pt;
long int n;
int nn = 0;
pt = &print_buf[sizeof (print_buf) - 1];
*pt = '\0';
n = fmt->scale * ((val < 0) ? -val : val);
if (n == 0)
return fmt->zero ? fmt->zero : "";
pf = pff = (val < 0) ? fmt->n_trl : fmt->p_trl;
if (pf && *pf)
{
while (*pf)
pf++;
do
*--pt = *--pf;
while (pf != pff);
}
if (prec != FLOAT_PRECISION && prec != 0)
{
while (prec-- > 0)
*--pt = '0';
pf = pff = fmt->decpt;
if (pf)
{
while (*pf)
pf++;
do
*--pt = *--pf;
while (pf != pff);
}
/* *--pt='.'; */
}
do
{
*--pt = (n % 10) + '0';
n /= 10;
if (nn++ == 2 && n > 0)
{
if (fmt->comma && *(fmt->comma))
{
for (pf = pff = fmt->comma; *pf; pf++)
;
do
*--pt = *--pf;
while (pf != pff);
}
nn = 0;
}
}
while (n > 0);
pf = pff = (val < 0) ? fmt->n_hdr : fmt->p_hdr;
if (pf && *pf)
{
while (*pf)
pf++;
do
*--pt = *--pf;
while (pf != pff);
}
return pt;
}
static char *
pr_flt (val, fmt, prec)
double val;
struct user_fmt *fmt;
int prec;
{
char *iptr;
char *fptr;
char *pptr;
char *pf, *pff;
double fract, integer, tmpval;
int n;
int isneg;
int comlen;
val *= fmt->scale;
if (val == __plinf)
return iname;
if (val == __neinf)
return mname;
if (val != val)
return nname;
iptr = &print_buf[BIGFLT];
fptr = &print_buf[BIGFLT];
if (val == 0)
return fmt->zero ? fmt->zero : "";
if (val < 0)
{
isneg = 1;
val = -val;
}
else
isneg = 0;
comlen = 0;
if (fmt->comma && *(fmt->comma))
for (pf = fmt->comma; *pf; comlen++, pf++)
;
fract = modf (val, &integer);
n = 0;
do
{
if (iptr < &print_buf[comlen])
return numb_oflo;
tmpval = modf (integer / 10, &integer);
*--iptr = '0' + (int) ((tmpval + .01) * 10);
if (comlen && n++ == 2 && integer)
{
n = 0;
pff = fmt->comma;
pf = pff + comlen;
do
*--iptr = *--pf;
while (pf != pff);
}
}
while (integer);
if (prec)
{
int p1;
p1 = (prec == FLOAT_PRECISION) ? 15 : (prec > 0) ? prec : -prec;
pf = fmt->decpt;
while (pf && *pf)
*fptr++ = *pf++;
/* *fptr++='.'; */
if (fract)
{
do
{
fract = modf (fract * 10, &tmpval);
*fptr++ = '0' + (int) tmpval;
}
while (--p1 && fract);
}
if (prec > 0 && prec != FLOAT_PRECISION)
while (p1--)
*fptr++ = '0';
else
{
fract = 0;
while (fptr[-1] == '0')
--fptr;
while (!isdigit (fptr[-1]))
--fptr;
*fptr = '\0';
}
}
if (fract)
{
(void) modf (fract * 10, &tmpval);
if (tmpval > 4)
{
iptr[-1] = '0';
for (pptr = fptr - 1;; --pptr)
{
if (!isdigit (*pptr))
continue;
else if (*pptr == '9')
{
if (pptr == fptr - 1 && pptr > &print_buf[BIGFLT] && (prec < 0 || prec == FLOAT_PRECISION))
{
--fptr;
while (!isdigit (pptr[-1]))
{
--fptr;
--pptr;
}
*pptr = '\0';
}
else
*pptr = '0';
}
else
{
(*pptr)++;
break;
}
}
if (pptr < iptr)
{
--iptr;
if (n == 3)
{
char tmpch;
tmpch = *iptr++;
for (pf = pff = fmt->comma; *pf; pf++)
;
do
*--iptr = *--pf;
while (pf != pff);
*--iptr = tmpch;
}
}
}
}
pf = pff = (isneg) ? fmt->n_hdr : fmt->p_hdr;
if (pf && *pf)
{
while (*pf)
pf++;
do
*--iptr = *--pf;
while (pf != pff);
}
pf = (isneg) ? fmt->n_trl : fmt->p_trl;
while (pf && *pf)
*fptr++ = *pf++;
*fptr = 0;
return iptr;
}
char *
adjust_prc (char *oldp, CELL * cp, int width, int smallwid, int just)
{
int fmt;
int prc;
struct user_fmt *ufmt;
char *bptr;
char *eptr;
int len;
fmt = GET_FORMAT (cp);
if (fmt == FMT_DEF)
fmt = default_fmt;
prc = GET_PRECISION (cp);
switch (fmt)
{
case FMT_GPH:
case FMT_HID:
return numb_oflo;
case FMT_DOL:
ufmt = &dol;
goto deal_fmt;
case FMT_CMA:
ufmt = &cma;
goto deal_fmt;
case FMT_PCT:
ufmt = &cma;
goto deal_fmt;
case FMT_FXT:
ufmt = &fxt;
goto deal_fmt;
case FMT_USR:
ufmt = &u[prc];
prc = ufmt->prec;
goto deal_fmt;
case FMT_GEN:
if (prc != FLOAT_PRECISION)
return numb_oflo;
if (index (oldp, 'e') || !index (oldp, '.'))
goto handle_exp;
ufmt = &fxt;
prc = FLOAT_PRECISION;
goto deal_fmt;
deal_fmt:
if (prc != FLOAT_PRECISION)
return numb_oflo;
len = strlen (oldp);
bptr = (char *) strstr (oldp, ufmt->decpt);
if (!bptr)
return numb_oflo;
while ((eptr = (char *) strstr (bptr + 1, ufmt->decpt)))
bptr = eptr;
if (width < bptr - oldp)
return numb_oflo;
if (bptr - oldp + strlen (ufmt->decpt) >= width)
prc = 0;
else
{
prc = width - (strlen (ufmt->decpt) + bptr - oldp);
}
bptr = pr_flt (cp->cell_flt, ufmt, -prc);
len = strlen (bptr);
if (len > width && prc > 0)
{
bptr = pr_flt (cp->cell_flt, ufmt, -(prc - 1));
len = strlen (bptr);
}
if (len > width)
return numb_oflo;
break;
case FMT_EXP:
handle_exp:
{
double f;
f = fabs (cp->cell_flt);
if (f > 9.99999e99 || f < 1e-99)
len = width - 7;
else /* if(f>9.9999999e9 || f<1e-9) */
len = width - 6;
/* else
len=width-5; */
if (cp->cell_flt < 0)
--len;
if (len > 0)
{
sprintf (oldp, "%.*e", len, cp->cell_flt);
len = strlen (oldp);
if (len <= width)
{
bptr = oldp;
break;
}
}
}
return numb_oflo;
default:
bptr = 0;
len = 0;
#ifdef TEST
panic ("Unknown format %d in adjust_prc()", fmt);
#endif
break;
}
/* If we get here, bptr points to a a string of len characters
(len<=width) that we want to output */
if (len < smallwid)
{
if (just == JST_RGT || just == JST_CNT)
{
int n;
n = (just == JST_RGT) ? smallwid - len : (1 + smallwid - len) / 2;
for (;;)
{
bptr[len + n] = bptr[len];
if (len-- == 0)
break;
}
while (n-- >= 0)
bptr[n] = ' ';
}
}
return bptr;
}
void
set_usr_stats (int usr_n, char **usr_buf)
{
int len;
int i;
char *p_in, *p_out;
len = 0;
for (i = 0; i < 7; i++)
len += strlen (usr_buf[i]);
u[usr_n].p_hdr = ck_malloc (len + 7);
p_out = u[usr_n].p_hdr;
if (usr_buf[0][0])
{
p_in = usr_buf[0];
while ((*p_out++ = *p_in++))
;
}
else
*p_out++ = '\0';
if (usr_buf[1][0])
{
p_in = usr_buf[1];
u[usr_n].n_hdr = p_out;
while ((*p_out++ = *p_in++))
;
}
else
u[usr_n].n_hdr = 0;
if (usr_buf[2][0])
{
p_in = usr_buf[2];
u[usr_n].p_trl = p_out;
while ((*p_out++ = *p_in++))
;
}
else
u[usr_n].p_trl = 0;
if (usr_buf[3][0])
{
p_in = usr_buf[3];
u[usr_n].n_trl = p_out;
while ((*p_out++ = *p_in++))
;
}
else
u[usr_n].n_trl = 0;
if (usr_buf[4][0])
{
p_in = usr_buf[4];
u[usr_n].zero = p_out;
while ((*p_out++ = *p_in++))
;
}
else
u[usr_n].zero = 0;
if (usr_buf[5][0])
{
p_in = usr_buf[5];
u[usr_n].comma = p_out;
while ((*p_out++ = *p_in++))
;
}
else
u[usr_n].comma = 0;
if (usr_buf[6][0])
{
p_in = usr_buf[6];
u[usr_n].decpt = p_out;
while ((*p_out++ = *p_in++))
;
}
else
u[usr_n].decpt = 0;
if (!stricmp (usr_buf[7], "float") || !stricmp (usr_buf[7], "f"))
u[usr_n].prec = 15;
else
u[usr_n].prec = astol (&usr_buf[7]);
u[usr_n].scale = astof (&usr_buf[8]);
}
int
usr_set_fmts (void)
{
int n;
int ret = 0;
for (n = 0; n < NUM_USER_FMT; n++)
if (u[n].p_hdr)
ret |= 1 << n;
return ret;
}
void
get_usr_stats (int usr_num, char **usr_buf)
{
static char buf1[30];
static char buf2[30];
static char NullStr[] = "";
usr_buf[0] = u[usr_num].p_hdr ? u[usr_num].p_hdr : NullStr;
usr_buf[1] = u[usr_num].n_hdr ? u[usr_num].n_hdr : NullStr;
usr_buf[2] = u[usr_num].p_trl ? u[usr_num].p_trl : NullStr;
usr_buf[3] = u[usr_num].n_trl ? u[usr_num].n_trl : NullStr;
usr_buf[4] = u[usr_num].zero ? u[usr_num].zero : NullStr;
usr_buf[5] = u[usr_num].comma ? u[usr_num].comma : NullStr;
usr_buf[6] = u[usr_num].decpt ? u[usr_num].decpt : NullStr;
if (u[usr_num].prec == 15)
usr_buf[7] = "float";
else
{
sprintf (buf1, "%u", u[usr_num].prec);
usr_buf[7] = buf1;
}
sprintf (buf2, "%.12g", u[usr_num].scale);
usr_buf[8] = buf2;
}
/* Functions for printing out the names of cells and ranges */
char *
cell_name (CELLREF rr, CELLREF cc)
{
static char strs[2][20];
static int num = 0;
char *ptr;
num = num ? 0 : 1;
if (Global->a0)
{
ptr = &strs[num][9];
sprintf (ptr, "%u", rr);
if (cc < MIN_COL + 26)
*--ptr = 'A' - MIN_COL + cc;
#if MAX_COL>702
else if (cc < MIN_COL + 702)
{
cc -= MIN_COL + 26;
*--ptr = 'A' + cc % 26;
*--ptr = 'A' + cc / 26;
}
else if (cc < MIN_COL + 18278)
{
cc -= MIN_COL + 702;
*--ptr = 'A' + cc % 26;
cc /= 26;
*--ptr = 'A' + cc % 26;
*--ptr = 'A' + cc / 26;
}
else
{
cc -= MIN_COL + 18278;
*--ptr = 'A' + cc % 26;
cc /= 26;
*--ptr = 'A' + cc % 26;
cc /= 26;
*--ptr = 'A' + cc % 26;
*--ptr = 'A' + cc / 26;
}
#else
else
{
cc -= MIN_COL + 26;
*--ptr = 'A' + cc % 26;
*--ptr = 'A' + cc / 26;
}
#endif
}
else
{
ptr = &strs[num][0];
sprintf (ptr, "r%uc%u", rr, cc);
}
return ptr;
}
char *
range_name (struct rng *rng)
{
CELLREF lr, lc, hr, hc;
static char buf[2][40];
static int num;
char *ptr;
ptr = &buf[num][0];
num = num ? 0 : 1;
lr = rng->lr;
lc = rng->lc;
hr = rng->hr;
hc = rng->hc;
/* Return empty string when invalid */
if (lr == 0 || lc == 0 || hc == 0 || hr == 0 ||
lr >= MAX_ROW || lc >= MAX_COL || hc >= MAX_COL || hr >= MAX_ROW) {
ptr[0] = '\0';
return ptr;
}
if ((lr == hr) && (lc == hc)) {
sprintf (ptr, "%s", cell_name (lr, lc));
} else {
if (Global->a0)
sprintf (ptr, "%s:%s", cell_name (lr, lc), cell_name (hr, hc));
else {
if (lr == hr && lc != hc)
sprintf (ptr, "r%uc%u:%u", lr, lc, hc);
else if (lr != hr && lc == hc)
sprintf (ptr, "r%u:%uc%u", lr, hr, lc);
else
sprintf (ptr, "r%u:%uc%u:%u", lr, hr, lc, hc);
}
}
return ptr;
}
/* Parse a range, allowing variable names.
* Return 1 on failure, 0 on succes.
*/
int
get_abs_rng (char **pptr, struct rng *retp)
{
unsigned char n;
struct rng ignored;
if (!retp)
retp = &ignored;
while (**pptr == ' ')
(*pptr)++;
if (!**pptr)
return 1;
cur_row = curow;
cur_col = cucol;
n = parse_cell_or_range (pptr, retp);
if (!n)
{
struct var *v;
char *ptr;
ptr = *pptr;
while (ptr[n] && ptr[n] != ' ')
n++;
v = find_var (ptr, n);
if (!v)
return 1;
(*pptr) += n;
*retp = v->v_rng;
}
return 0;
}
char *
col_to_str (CELLREF col)
{
static char strs[2][10];
static int num;
char *ptr;
ptr = &strs[num][9];
num = num ? 0 : 1;
if (col < MIN_COL + 26)
*--ptr = 'A' - MIN_COL + col;
#if MAX_COL>702
else if (col < MIN_COL + 702)
{
col -= MIN_COL + 26;
*--ptr = 'A' + col % 26;
*--ptr = 'A' + col / 26;
}
else if (col < MIN_COL + 18278)
{
col -= MIN_COL + 702;
*--ptr = 'A' + col % 26;
col /= 26;
*--ptr = 'A' + col % 26;
*--ptr = 'A' + col / 26;
}
else
{
col -= MIN_COL + 18278;
*--ptr = 'A' + col % 26;
col /= 26;
*--ptr = 'A' + col % 26;
col /= 26;
*--ptr = 'A' + col % 26;
*--ptr = 'A' + col / 26;
}
#else
else
{
col -= MIN_COL + 26;
*--ptr = 'A' + col % 26;
*--ptr = 'A' + col / 26;
}
#endif
return ptr;
}
void
clear_spreadsheet (void)
{
int n;
flush_everything ();
/* flush_widths(); */
flush_all_timers ();
for (n = 0; n < NUM_USER_FMT; n++)
{
if (u[n].p_hdr)
{
free (u[n].p_hdr);
u[n].p_hdr = 0;
u[n].prec = FLOAT_PRECISION;
u[n].scale = 1;
}
}
default_width = saved_default_width;
default_height = saved_default_height;
default_jst = JST_LFT;
default_fmt = FMT_GEN;
default_lock = LCK_UNL;
}
char *ename[] =
{
"#WHAT?",
"#ERROR", "#BAD_INPUT", "#NON_NUMBER", "#NON_STRING",
"#NON_BOOL", "#NON_RANGE", "#OUT_OF_RANGE", "#NO_VALUES",
"#DIV_BY_ZERO", "#BAD_NAME", "#NOT_AVAIL", "#PARSE_ERROR",
"#NEED_OPEN", "#NEED_CLOSE", "#NEED_QUOTE", "#UNK_CHAR",
"#UNK_FUNC",
0
};
char tname[] = "#TRUE";
char fname[] = "#FALSE";
int
words_imatch (char **ptr, char *key)
{
char *str = *ptr;
while (isspace (*str))
++str;
while (isspace (*key))
++key;
while (1)
{
while (*str && *key && (toupper (*str) == toupper (*key)))
{
++str;
++key;
}
/* If we're not at word breaks in both strings... */
if (!((!*str || isspace (*str)) && (!*key || isspace (*key))))
return 0;
else
{
while (isspace (*key))
++key;
while (isspace (*str))
++str;
if (!*key)
{
*ptr = str;
return 1;
}
}
}
}
int
parray_len (char **array)
{
int x;
for (x = 0; array[x]; ++x);
return x;
}
/* Return the index of CHECK in KEYS or -1. Case and whitespeace insenstive.
*/
int
words_member (char **keys, int len, char *check)
{
int x;
for (x = 0; x < len; ++x)
{
char *ch = check;
if (words_imatch (&ch, keys[x]))
if (!*ch)
return x;
}
return -1;
}
int
prompt_len (char *prompt)
{
char *pos;
if (!prompt)
return 0;
for (pos = prompt; *pos && (*pos != '\n'); ++pos)
;
return pos - prompt;
}
int
says_default (char *str)
{
char *key = "ault";
if (strincmp (str, "def", 3))
return 0;
str += 3;
while (*str && *key)
{
int c = isupper (*str) ? tolower (*str) : *str;
if (c != *key)
return 0;
++key;
++str;
}
while (isspace (*str))
++str;
return !*str;
}
static char *defaultformat = NULL;
void
file_set_default_format(char *s)
{
if (defaultformat)
free(defaultformat);
if (s == NULL)
defaultformat = strdup("oleo");
else
defaultformat = s;
}
char *
file_get_default_format(void)
{
return defaultformat;
}
int
write_file_generic_2(FILE *fp, struct rng *rng, char *format)
{
if (!stricmp ("oleo", format)) {
oleo_write_file(fp, rng);
} else if (!stricmp ("sylk", format)) {
Global->sylk_a0 = 1;
sylk_write_file(fp, rng);
} else if (!stricmp ("sylk-noa0", format)) {
Global->sylk_a0 = 0;
sylk_write_file(fp, rng);
} else if (!stricmp ("sc", format)) {
sc_write_file(fp, rng);
#ifdef HAVE_PANIC_SAVE
} else if (!stricmp ("panic", format)) {
panic_write_file(fp, rng);
#endif
} else if (!stricmp ("list", format)) {
list_write_file(fp, rng);
} else {
return -1;
}
return 0;
}
void
write_file_generic(FILE *fp, struct rng *rng, char *format)
{
if (format == NULL) {
if (defaultformat)
(void) write_file_generic_2(fp, rng, defaultformat);
else
oleo_write_file(fp, rng);
return;
}
#if 0
fprintf(stderr, PACKAGE " write_file_generic : format %s\n", format);
#endif
if (write_file_generic_2(fp, rng, format) != 0) {
if (write_file_generic_2(fp, rng, defaultformat) != 0)
oleo_write_file(fp, rng);
}
}
int
read_file_generic_2(FILE *fp, int ismerge, char *format, char *name)
{
if (stricmp ("oleo", format) == 0) {
oleo_read_file(fp, ismerge);
} else if (stricmp ("sylk", format) == 0 || stricmp ("slk", format) == 0) {
Global->sylk_a0 = 0; /* FIX ME */
sylk_read_file(fp, ismerge);
} else if (stricmp ("sylk-noa0", format) == 0) {
Global->sylk_a0 = 0;
sylk_read_file(fp, ismerge);
} else if (stricmp ("sc", format) == 0) {
sc_read_file(fp, ismerge);
#ifdef HAVE_PANIC_SAVE
} else if (stricmp ("panic", format) == 0) {
panic_read_file(fp, ismerge);
#endif
} else if (stricmp ("list", format) == 0) {
list_read_file(fp, ismerge);
} else if (stricmp("csv", format) == 0) {
list_set_separator(',');
list_read_file(fp, ismerge);
} else if (stricmp("dbf", format) == 0) {
#if defined(HAVE_LIBXBASE) || defined(HAVE_LIBXDB)
ReadXbaseFile(name, ismerge);
#else
io_error_msg ("Cannot read XBASE file (xbase not compiled into " PACKAGE ")");
return -1;
#endif
} else {
return -1;
}
return 0;
}
static struct file_formats_s {
char *name;
char *format;
} file_formats[] = {
{ "oleo", "oleo" },
{ "sylk", "[sS]*[lL][kK]" },
{ "sc", "sc" },
{ "list", "list" },
{ "csv", "[cC][sS][vV]" },
{ "dbf", "[dD][bB][fF]" },
#ifdef HAVE_PANIC_SAVE
{ "panic", "panic" },
#endif
{ "sylk-noa0", "sylk" },
{ NULL, NULL }
};
char *
file_get_format(int i)
{
int m = sizeof(file_formats) / sizeof(struct file_formats_s) - 1;
if (i > m || i <= 0)
return NULL;
return file_formats[i-1].name;
}
char *
file_get_pattern(char *fmt)
{
int i, m = sizeof(file_formats) / sizeof(struct file_formats_s) - 1;
for (i=0; i<m; i++) {
if (strcmp(fmt, file_formats[i].name) == 0)
return file_formats[i].format;
}
return NULL;
}
void
read_file_generic(FILE *fp, int ismerge, char *format, char *name)
{
if (format == NULL) {
if (defaultformat)
(void) read_file_generic_2(fp, ismerge, defaultformat, name);
else
oleo_read_file(fp, ismerge);
return;
}
#if 0
fprintf(stderr, PACKAGE " read_file_generic : format %s\n", format);
#endif
if (read_file_generic_2(fp, ismerge, format, name) != 0) {
if (defaultformat && read_file_generic_2(fp, ismerge, defaultformat, name) != 0)
oleo_read_file(fp, ismerge);
}
recalculate(1);
}
void
fmt_set_format()
{
}
void
fmt_get_format()
{
}
void FileSetCurrentFileName(const char *s)
{
if (Global->FileName)
free(Global->FileName);
Global->FileName = NULL;
if (s)
Global->FileName = strdup(s);
#if HAVE_MOTIF
if (using_motif)
MotifSetWindowName(Global->FileName);
#endif
}
char *FileGetCurrentFileName(void)
{
return Global->FileName;
}
void FileCloseCurrentFile(void)
{
if (Global->FileName)
free(Global->FileName);
Global->FileName = NULL;
#if HAVE_MOTIF
if (using_motif)
MotifSetWindowName("");
#endif
}
void OleoSetEncoding(char *s)
{
extern void PrintSetEncoding(char *encoding); /* in print.c */
if (Global && Global->encoding)
free(Global->encoding);
Global->encoding = strdup(s);
PrintSetEncoding(s);
}
char *OleoGetEncoding(void)
{
return Global->encoding;
}
void OleoUserPrefEncoding(char *s)
{
char *p = s + 9; /* Get past "encoding" */
for (; *p && isspace(*p); p++) ;
OleoSetEncoding(p);
}
syntax highlighted by Code2HTML, v. 0.9.1