teapot-spreadsheet/src/common/sc.c

346 lines
8.2 KiB
C

/* #includes */ /*{{{C}}}*//*{{{*/
#ifndef NO_POSIX_SOURCE
#undef _POSIX_SOURCE
#define _POSIX_SOURCE 1
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 2
#endif
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "eval.h"
#include "parser.h"
#include "main.h"
#include "sheet.h"
#include "sc.h"
/*}}}*/
static const char *s2t_s;
static char *s2t_t;
static int s2t_term(Sheet *sheet);
/* s2t_loc */ /*{{{*/
static int s2t_loc(Sheet *sheet, const char **s, char **t)
{
int x,y;
Location tmp;
char label[10],*l;
l=label;
if (**s>='A' && **s<='Z')
{
*l++=**s;
*(*t)++=**s;
x=*(*s)++-'A';
}
else return 0;
if (**s>='A' && **s<='Z')
{
*l++=**s;
*(*t)++=**s;
x=x*26+(*(*s)++-'A');
}
if (**s>='0' && **s<='9')
{
*l++=**s;
y=**s-'0';
*(*t)++=*(*s)++;
}
else return 0;
while (**s>='0' && **s<='9')
{
*l++=**s;
y=y*10+(**s-'0');
*(*t)++=*(*s)++;
}
*l='\0';
tmp[X] = x; tmp[Y] = y; tmp[Z] = 0;
if (*getlabel(CELL_AT(sheet, tmp))=='\0') setlabel(sheet, tmp, label, 0);
return 1;
}
/*}}}*/
/* s2t_range */ /*{{{*/
static int s2t_range(Sheet *sheet)
{
if (s2t_loc(sheet,&s2t_s,&s2t_t)==0) return 0;
if (*s2t_s==':')
{
s2t_s++; *s2t_t++=',';
if (s2t_loc(sheet,&s2t_s,&s2t_t)==0) return 0;
return 1;
}
else return 0;
}
/*}}}*/
/* s2t_primary */ /*{{{*/
static int s2t_primary(Sheet *sheet)
{
if (*s2t_s=='@')
/* @function */ /*{{{*/
{
++s2t_s;
if (strncmp(s2t_s,"sum(",4)==0)
/* @sum(range) -> sum(range) */ /*{{{*/
{
s2t_s+=4;
*s2t_t++='s'; *s2t_t++='u'; *s2t_t++='m'; *s2t_t++='(';
if (s2t_range(sheet)==0) return 0;
*s2t_t++=')';
return 1;
}
/*}}}*/
else if (strncmp(s2t_s,"rnd(",4)==0)
/* @rnd(e) -> int(e,-1,1) */ /*{{{*/
{
s2t_s+=4;
*s2t_t++='i'; *s2t_t++='n'; *s2t_t++='t'; *s2t_t++='(';
if (s2t_term(sheet)==0) return 0;
*s2t_t++=','; *s2t_t++='-'; *s2t_t++='1'; *s2t_t++=','; *s2t_t++='1'; *s2t_t++=')';
return 1;
}
/*}}}*/
else if (strncmp(s2t_s,"floor(",6)==0)
/* @floor(e) -> int(e,-2,-2) */ /*{{{*/
{
s2t_s+=6;
*s2t_t++='i'; *s2t_t++='n'; *s2t_t++='t'; *s2t_t++='(';
if (s2t_term(sheet)==0) return 0;
*s2t_t++=','; *s2t_t++='-'; *s2t_t++='2'; *s2t_t++=','; *s2t_t++='-'; *s2t_t++='2'; *s2t_t++=')';
return 1;
}
/*}}}*/
else if (strncmp(s2t_s,"ceil(",5)==0)
/* @ceil(e) -> int(e,2,2) */ /*{{{*/
{
s2t_s+=5;
*s2t_t++='i'; *s2t_t++='n'; *s2t_t++='t'; *s2t_t++='(';
if (s2t_term(sheet)==0) return 0;
*s2t_t++=','; *s2t_t++='2'; *s2t_t++=','; *s2t_t++='2'; *s2t_t++=')';
return 1;
}
/*}}}*/
else return 0;
}
/*}}}*/
else if ((*s2t_s>='0' && *s2t_s<='9') || *s2t_s=='.')
/* number */ /*{{{*/
{
if (*s2t_s=='.') *s2t_t++='0'; else *s2t_t++=*s2t_s++;
while (*s2t_s>='0' && *s2t_s<='9') *s2t_t++=*s2t_s++;
if (*s2t_s=='.')
{
*s2t_t++=*s2t_s++;
while (*s2t_s>='0' && *s2t_s<='9') *s2t_t++=*s2t_s++;
}
else
{
*s2t_t++='.'; *s2t_t++='0';
}
return 1;
}
/*}}}*/
else if (*s2t_s>='A' && *s2t_s<='Z')
/* cell value */ /*{{{*/
{
*s2t_t++='@'; *s2t_t++='(';
if (s2t_loc(sheet,&s2t_s,&s2t_t)==0) return 0;
*s2t_t++=')';
return 1;
}
/*}}}*/
else if (*s2t_s) return 0;
else return 1;
}
/*}}}*/
/* s2t_powterm */ /*{{{*/
static int s2t_powterm(Sheet *sheet)
{
if (s2t_primary(sheet)==0) return 0;
while (*s2t_s=='^')
{
*s2t_t++=*s2t_s++;
if (s2t_primary(sheet)==0) return 0;
}
return 1;
}
/*}}}*/
/* s2t_piterm */ /*{{{*/
static int s2t_piterm(Sheet *sheet)
{
if (s2t_powterm(sheet)==0) return 0;
while (*s2t_s=='*' || *s2t_s=='/')
{
*s2t_t++=*s2t_s++;
if (s2t_powterm(sheet)==0) return 0;
}
return 1;
}
/*}}}*/
/* s2t_term */ /*{{{*/
static int s2t_term(Sheet *sheet)
{
if (s2t_piterm(sheet)==0) return 0;
while (*s2t_s=='+' || *s2t_s=='-')
{
*s2t_t++=*s2t_s++;
if (s2t_piterm(sheet)==0) return 0;
}
return 1;
}
/*}}}*/
/* loadsc */ /*{{{*/
const char *loadsc(Sheet *sheet, const char *name)
{
/* variables */ /*{{{*/
static char errbuf[80];
FILE *fp;
char buf[256];
int line;
size_t width;
const char *err;
Cell *cell;
Location tmp;
int x,y;
/*}}}*/
if ((fp=fopen(name,"r"))==(FILE*)0) return strerror(errno);
freesheet(sheet,0);
err=(const char*)0;
line=1;
while (fgets(buf,sizeof(buf),fp)!=(char*)0)
{
/* remove nl */ /*{{{*/
width=strlen(buf);
if (width>0 && buf[width-1]=='\n') buf[width-1]='\0';
/*}}}*/
if (buf[0] && buf[0] != '#')
{
if (strncmp(buf,"format ",7)==0) /* format col width precision whoknows */ /*{{{*/
{
char colstr[3];
int col,colwidth,precision,whoknows;
sscanf(buf+7,"%s %d %d %d",colstr,&colwidth,&precision,&whoknows);
col=(colstr[0]-'A'); if (colstr[1]) col=col*26+(colstr[1]-'A');
OLOCATION(tmp);
tmp[X] = col;
cell = initcellofsheet(sheet, tmp, NULL);
cell->adjust = RIGHT;
cell->precision = precision;
setwidth(sheet, col, 0, colwidth);
}
/*}}}*/
else if (strncmp(buf, "leftstring ", 11) == 0
|| strncmp(buf, "rightstring ", 12) == 0) /* rightstring/leftstring cell = "string" */ /*{{{*/
{
int x,y;
char *s;
Token **contents;
if (strncmp(buf, "leftstring ", 11) == 0) s = buf+11; else s = buf+12;
x = *s++ - 'A';
if (*s >= 'A' && *s <= 'Z' ) x = x*26 + (*s++ - 'A');
y = *s++ - '0';
while (*s >= '0' && *s <= '9') y = 10*y + (*s++-'0');
s+=3;
contents = scan(&s);
if (contents == EMPTY_TVEC)
{
tvecfree(contents);
sprintf(errbuf, _("Expression syntax error in line %d"), line);
err = errbuf;
goto eek;
}
tmp[X] = x; tmp[Y] = y; tmp[Z] = 0;
cell = initcellofsheet(sheet, tmp, NULL);
cell->adjust = strncmp(buf, "leftstring ", 11) ? RIGHT : LEFT;
cell->tok[BASE_CONT] = eval_safe(contents, LITERAL);
tvecfree(contents);
if (cell->tok[BASE_CONT].type == EEK)
{
sprintf(errbuf, _("Parse error in line %d: %s"),
line, cell->tok[BASE_CONT].u.err);
tfree(&(cell->tok[BASE_CONT]));
err = errbuf;
goto eek;
}
}
/*}}}*/
else if (strncmp(buf,"let ",4)==0) /* let cell = expression */ /*{{{*/
{
char newbuf[512];
char *s = buf+4;
x = *s++-'A'; if (*s >= 'A' && *s <= 'Z') x = x*26 + (*s++-'A');
y = *s++-'0'; while (*s >= '0' && *s <= '9') y = 10*y + (*s++-'0');
tmp[X] = x; tmp[Y] = y; tmp[Z] = 0;
if (gettok(CELL_ATC(sheet,x,y,0), BASE_CONT).type == EMPTY)
{
s += 3;
s2t_s = s; s2t_t = newbuf;
if (s2t_term(sheet) == 0)
{
*s2t_t = '\0';
if (err == (const char*)0)
{
sprintf(errbuf, _("Unimplemented SC feature in line %d"),line);
err = errbuf;
}
}
*s2t_t = '\0';
s = newbuf;
Token **contents = scan(&s);
if (contents == EMPTY_TVEC)
{
tvecfree(contents);
sprintf(errbuf,_("Expression syntax error in line %d"),line);
err=errbuf;
goto eek;
}
tmp[X] = x; tmp[Y] = y; tmp[Z] = 0;
cell = initcellofsheet(sheet, tmp, NULL);
cell->adjust = RIGHT;
cell->tok[BASE_CONT] = eval_safe(contents, LITERAL);
tvecfree(contents);
if (cell->tok[BASE_CONT].type == EEK)
{
sprintf(errbuf, _("Parse error in line %d: %s"),
line, cell->tok[BASE_CONT].u.err);
tfree(&(cell->tok[BASE_CONT]));
err = errbuf;
goto eek;
}
}
}
/*}}}*/
}
++line;
}
/* set precisions for each column */ /*{{{*/
for (x=0; x<sheet->dimx; ++x)
{
int prec;
prec=getprecision(CELL_ATC(sheet,x,0,0))==def_precision ? 2 : getprecision(CELL_ATC(sheet,x,0,0));
for (y=1; y<sheet->dimy; ++y) if (CELL_ATC(sheet,x,y,0)) CELL_ATC(sheet,x,y,0)->precision=prec;
}
/*}}}*/
eek:
if (fclose(fp)==EOF && err==(const char*)0) err=strerror(errno);
sheet->changed=0;
cachelabels(sheet);
forceupdate(sheet);
return err;
}
/*}}}*/