summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES8
-rwxr-xr-xsrc/debug.sh2
-rwxr-xr-xsrc/gdb.gdb2
-rw-r--r--src/interp.c1471
-rw-r--r--src/interp.h35
5 files changed, 137 insertions, 1381 deletions
diff --git a/CHANGES b/CHANGES
index 6430771..7702eed 100644
--- a/CHANGES
+++ b/CHANGES
@@ -20,10 +20,12 @@ removed --sheet and --filename_with_mode configuration variables
For v0.8.3 release
-------------------
-calc_mobile_cols/rows invalid read with l1.csv and l2.csv examples
-+ reeval in multiple sheets: graph should keep track of the different sheets
++ reeval in multiple sheets: graph should keep track of the different sheets -> GraphIsReachable()
++ fix circular references in eval/seval (for instance it shows circular when
+ referencing sheet!A2 from current_sheet!A2) -> would be done doing the previous item.
+ UNDO should save reference to the sheet where the action took place
-fix circular references in eval/seval (for instance it shows circular when referencing sheet!A2 from current_sheet!A2)
+
+calc_mobile_cols/rows invalid read with l1.csv and l2.csv examples
rearrange file loading and saving functions
+ Show range detail in inputwin as A0:C3
diff --git a/src/debug.sh b/src/debug.sh
index d27cda8..ed9e122 100755
--- a/src/debug.sh
+++ b/src/debug.sh
@@ -1,4 +1,4 @@
#!/bin/bash
-tmux splitw -h -p 35 "gdbserver :12345 ./sc-im --xlsx_readformulas a.sc"
+tmux splitw -h -p 35 "gdbserver :12345 ./sc-im"
tmux selectp -t 0
cgdb -x gdb.gdb
diff --git a/src/gdb.gdb b/src/gdb.gdb
index 9194328..6a0fa87 100755
--- a/src/gdb.gdb
+++ b/src/gdb.gdb
@@ -1,2 +1,2 @@
target remote localhost:12345
-b cmds.c:584
+b interp.c:243
diff --git a/src/interp.c b/src/interp.c
index 7cb1c26..ba5f764 100644
--- a/src/interp.c
+++ b/src/interp.c
@@ -2,10 +2,10 @@
* Copyright (c) 2013-2021, Andrés Martinelli <andmarti@gmail.com> *
* All rights reserved. *
* *
- * This file is a part of SC-IM *
+ * This file is a part of sc-im *
* *
- * SC-IM is a spreadsheet program that is based on SC. The original authors *
- * of SC are James Gosling and Mark Weiser, and mods were later added by *
+ * sc-im is a spreadsheet program that is based on sc. The original authors *
+ * of sc are James Gosling and Mark Weiser, and mods were later added by *
* Chuck Martin. *
* *
* Redistribution and use in source and binary forms, with or without *
@@ -36,21 +36,20 @@
*******************************************************************************/
/**
- * \file intrep.c
+ * \file interp.c
* \author Andrés Martinelli <andmarti@gmail.com>
- * \date 2021-04-28
- * \brief TODO Write a tbrief file description.
+ * \date 24/05/2021
+ * \brief source file that implements the eval seval functions
+ * Based on SC
*
* \details Expression interpreter and assorted support routines
- * Based on SC
* \details Original by James Gosling, September 1982
* \details Modified by Mark Weiser and Bruce Israel, University of Maryland
* \details More mods Robert Bond, 12/86
- * \details More mods by Alan Silverstein, 3-4/88, see list of changes.
+ * \details More mods by Alan Silverstein, 3-4/88.
*/
#include <sys/types.h>
-#include <math.h>
#include <signal.h>
#include <setjmp.h>
#include <ctype.h>
@@ -60,7 +59,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <regex.h>
-
#ifdef IEEE_MATH
#include <ieeefp.h>
#endif
@@ -74,19 +72,17 @@
#include "range.h"
#include "xmalloc.h" // for scxfree
#include "lex.h" // for atocol
+#include "function.h"
#include "interp.h"
#include "utils/string.h"
#include "trigger.h"
-
#ifdef XLUA
#include "lua.h"
#endif
-
#ifdef UNDO
#include "undo.h"
#endif
-
-void exit_app();
+#include "dep_graph.h"
/* g_type can be: */
#define G_NONE 0 /* Starting value - must be 0 */
@@ -96,24 +92,13 @@ void exit_app();
#define G_XSTR 4
#define G_CELL 5
-/* Use this structure to save the last 'g' command */
-struct go_save gs = { .g_type = G_NONE } ;
-
-#define ISVALID(s,r,c) ((r)>=0 && (r) < s->maxrows && (c) >=0 && (c) < s->maxcols)
-
-int exprerr; /* Set by eval() and seval() if expression errors */
-double prescale = 1.0; /* Prescale for constants in let() */
-//int loading = 0; /* Set when readfile() is active */
-int gmyrow = -1, gmycol = -1; /* globals used to implement @myrow, @mycol cmds */
-int rowoffset = 0, coloffset = 0; /* row & col offsets for range functions */
-jmp_buf fpe_save;
-
+extern int find_range(char * name, int len, struct ent * lmatch, struct ent * rmatch, struct range ** rng);
extern bool decimal; /* Set if there was a decimal point in the number */
extern struct session * session;
+extern graphADT graph;
+extern WINDOW * input_win;
-/* a linked list of free [struct enodes]'s, uses .e.o.left as the pointer */
-
-double dolookup (struct enode * val, int minr, int minc, int maxr, int maxc, int offr, int offc);
+void exit_app();
double fn1_eval (double (* fn)(), double arg);
double fn2_eval (double (* fn)(), double arg1, double arg2);
int constant (struct enode * e);
@@ -126,860 +111,17 @@ void range_arg (char * s, struct enode * e);
void three_arg (char * s, struct enode * e);
void two_arg (char * s, struct enode * e);
void two_arg_index (char * s, struct enode * e);
-double rint (double d);
-int cellerror = CELLOK; /**< is there an error in this cell */
-
-#ifndef M_PI
- #define M_PI (double)3.14159265358979323846
-#endif
-
-#define dtr(x) ((x)*(M_PI/(double)180.0))
-#define rtd(x) ((x)*(180.0/(double)M_PI))
-
-extern int find_range(char * name, int len, struct ent * lmatch, struct ent * rmatch, struct range ** rng);
-
-#include "dep_graph.h"
-extern graphADT graph;
-
-extern WINDOW * input_win;
-
-
-
-/**
- * \brief finfunc()
- *
- * \param[in] fun
- * \param[in] v1
- * \param[in] v2
- * \param[in] v3
- *
- * \return double
- */
-double finfunc(int fun, double v1, double v2, double v3) {
- double answer,p;
-
- p = fn2_eval(pow, 1 + v2, v3);
-
- switch (fun) {
- case PV:
- if (v2)
- answer = v1 * (1 - 1/p) / v2;
- else {
- cellerror = CELLERROR;
- answer = (double)0;
- }
- break;
- case FV:
- if (v2)
- answer = v1 * (p - 1) / v2;
- else {
- cellerror = CELLERROR;
- answer = (double)0;
- }
- break;
- case PMT:
- /* CHECK IF ~= 1 - 1/1 */
- if (p && p != (double)1)
- answer = v1 * v2 / (1 - 1/p);
- else {
- cellerror = CELLERROR;
- answer = (double)0;
- }
- break;
- default:
- sc_error("Unknown function in finfunc");
- cellerror = CELLERROR;
- return ((double)0);
- }
- return (answer);
-}
-
-/**
- * \brief dostindex()
- *
- * \param[in] minr
- * \param[in] minc
- * \param[in] maxr
- * \param[in] maxc
- * \param[in] val
- *
- * \return char *
- */
-char * dostindex(int minr, int minc, int maxr, int maxc, struct enode * val) {
- struct roman * roman = session->cur_doc;
- struct sheet * sh = roman->cur_sh;
- int r, c;
- struct ent * p;
- char * pr;
-
- p = (struct ent *) 0;
- if (minr == maxr) { /* look along the row */
- r = minr;
- c = minc + (int) eval(NULL, val) - 1;
- } else if (minc == maxc) { /* look down the column */
- r = minr + (int) eval(NULL, val) - 1;
- c = minc;
- } else {
- r = minr + (int) eval(NULL, val->e.o.left) - 1;
- c = minc + (int) eval(NULL, val->e.o.right) - 1;
- }
- if (c <= maxc && c >=minc && r <= maxr && r >=minr)
- p = *ATBL(sh, sh->tbl, r, c);
-
- if (p && p->label) {
- pr = scxmalloc((size_t) (strlen(p->label) + 1));
- (void) strcpy(pr, p->label);
- if (p->cellerror)
- cellerror = CELLINVALID;
- return (pr);
- } else
- return ((char *) 0);
-}
-
-
-/**
- * \brief doascii()
- * \param[in] s
- * \return double
- */
-double doascii(char * s) {
- double v = 0.;
- int i ;
- if ( !s ) return ((double) 0);
-
- for (i = 0; s[i] != '\0' ; v = v*256 + (unsigned char)(s[i++]) ) ;
- scxfree(s);
- return(v);
-}
-
-
-/**
- * \brief doindex()
- *
- * \param[in] minr
- * \param[in] minc
- * \param[in] maxr
- * \param[in] maxc
- * \param[in] val
- *
- * \return double
- */
-double doindex(int minr, int minc, int maxr, int maxc, struct enode * val) {
- struct roman * roman = session->cur_doc;
- struct sheet * sh = roman->cur_sh;
- int r, c;
- struct ent * p;
-
- if (val->op == ',') { /* index by both row and column */
- r = minr + (int) eval(NULL, val->e.o.left) - 1;
- c = minc + (int) eval(NULL, val->e.o.right) - 1;
- } else if (minr == maxr) { /* look along the row */
- r = minr;
- c = minc + (int) eval(NULL, val) - 1;
- } else if (minc == maxc) { /* look down the column */
- r = minr + (int) eval(NULL, val) - 1;
- c = minc;
- } else {
- sc_error("Improper indexing operation");
- return (double) 0;
- }
-
- if (c <= maxc && c >=minc && r <= maxr && r >=minr &&
- (p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) {
- if (p->cellerror)
- cellerror = CELLINVALID;
- return p->v;
- } else
- return (double) 0;
-}
-
-/**
- * \brief dolookup()
- *
- * \param[in] val
- * \param[in] minr
- * \param[in] minc
- * \param[in] maxr
- * \param[in] maxc
- * \param[in] offset
- * \param[in] vflag
- *
- * \return double
- */
-double dolookup(struct enode * val, int minr, int minc, int maxr, int maxc, int offset, int vflag) {
- struct roman * roman = session->cur_doc;
- struct sheet * sh = roman->cur_sh;
- double v, ret = (double) 0;
- int r, c;
- struct ent * p = (struct ent *) 0;
- int incr, incc, fndr, fndc;
- char * s;
-
- incr = vflag; incc = 1 - vflag;
- if (etype(val) == NUM) {
- cellerror = CELLOK;
- v = eval(NULL, val);
- for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) {
- if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) {
- if (p->v <= v) {
- fndr = incc ? (minr + offset) : r;
- fndc = incr ? (minc + offset) : c;
- if (ISVALID(sh, fndr, fndc))
- if (p == NULL) // three lines added
- cellerror = CELLINVALID;
- else // useful when the lookup ends up in a cell with no value
- p = *ATBL(sh, sh->tbl, fndr, fndc);
- else {
- sc_error(" range specified to @[hv]lookup");
- cellerror = CELLERROR;
- }
- if (p && p->flags & is_valid) {
- if (p->cellerror)
- cellerror = CELLINVALID;
- ret = p->v;
- }
- } else break;
- }
- }
- } else {
- cellerror = CELLOK;
- s = seval(NULL, val);
- for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) {
- if ((p = *ATBL(sh, sh->tbl, r, c)) && p->label) {
- if (s && strcmp(p->label,s) == 0) {
- fndr = incc ? (minr + offset) : r;
- fndc = incr ? (minc + offset) : c;
- if (ISVALID(sh, fndr,fndc)) {
- p = *ATBL(sh, sh->tbl, fndr, fndc);
- if (p->cellerror)
- cellerror = CELLINVALID;
- } else {
- sc_error(" range specified to @[hv]lookup");
- cellerror = CELLERROR;
- }
- break;
- }
- }
- }
- if (p && p->flags & is_valid)
- ret = p->v;
- if (s != NULL) scxfree(s);
- }
- return ret;
-}
-
-
-/**
- * \brief docount()
- *
- * \param[in] minr
- * \param[in] minc
- * \param[in] maxr
- * \param[in] maxc
- * \param[in] e
- *
- * \return double
- */
-double docount(int minr, int minc, int maxr, int maxc, struct enode * e) {
- struct roman * roman = session->cur_doc;
- struct sheet * sh = roman->cur_sh;
- int v;
- int r, c;
- int cellerr = CELLOK;
- struct ent *p;
-
- v = 0;
- for (r = minr; r <= maxr; r++)
- for (c = minc; c <= maxc; c++) {
- if (e) {
- rowoffset = r - minr;
- coloffset = c - minc;
- }
- if (!e || eval(NULL, e))
- // the following changed for #430. docount should also count cells with strings. not just numbers
- // TODO: create @counta to count both, and leave @count for just numbers
- if ((p = *ATBL(sh, sh->tbl, r, c)) && (p->flags & is_valid || p->label) ) {
- if (p->cellerror) cellerr = CELLINVALID;
- v++;
- }
- }
- cellerror = cellerr;
- rowoffset = coloffset = 0;
- return v;
-}
-
-
-/**
- * \brief dosum()
- * \param[in] minr
- * \param[in] minc
- * \param[in] maxr
- * \param[in] maxc
- * \param[in] e
- * \return double
- */
-double dosum(int minr, int minc, int maxr, int maxc, struct enode * e) {
- struct roman * roman = session->cur_doc;
- struct sheet * sh = roman->cur_sh;
- double v;
- int r, c;
- int cellerr = CELLOK;
- struct ent * p;
-
- v = (double)0;
- for (r = minr; r <= maxr; r++)
- for (c = minc; c <= maxc; c++) {
- if (e) {
- rowoffset = r - minr;
- coloffset = c - minc;
- }
- if ( !e || eval(NULL, e))
- if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) {
- if (p->cellerror)
- cellerr = CELLINVALID;
- v += p->v;
- }
- }
- cellerror = cellerr;
- rowoffset = coloffset = 0;
- return v;
-}
-
-/**
- * \brief doprod()
- *
- * \param[in] minr
- * \param[in] minc
- * \param[in] maxr
- * \param[in] maxc
- * \param[in] e
- *
- * \return double
- */
-double doprod(int minr, int minc, int maxr, int maxc, struct enode * e) {
- struct roman * roman = session->cur_doc;
- struct sheet * sh = roman->cur_sh;
- double v;
- int r, c;
- int cellerr = CELLOK;
- struct ent * p;
-
- v = 1;
- for (r = minr; r <= maxr; r++)
- for (c = minc; c <= maxc; c++) {
- if (e) {
- rowoffset = r - minr;
- coloffset = c - minc;
- }
- if ( !e || eval(NULL, e))
- if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) {
- if (p->cellerror) cellerr = CELLINVALID;
- v *= p->v;
- }
- }
- cellerror = cellerr;
- rowoffset = coloffset = 0;
- return v;
-}
-
-
-/**
- * \brief doavg()
- *
- * \param[in] minr
- * \param[in] minc
- * \param[in] maxr
- * \param[in] maxc
- * \param[in] e
- *
- * \return double
- */
-double doavg(int minr, int minc, int maxr, int maxc, struct enode * e) {
- struct roman * roman = session->cur_doc;
- struct sheet * sh = roman->cur_sh;
- double v;
- int r, c;
- int count;
- int cellerr = CELLOK;
- struct ent * p;
-
- v = (double) 0;
- count = 0;
- for (r = minr; r <= maxr; r++)
- for (c = minc; c <= maxc; c++) {
- if (e) {
- rowoffset = r - minr;
- coloffset = c - minc;
- }
- if (!e || eval(NULL, e))
- if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) {
- if (p->cellerror) cellerr = CELLINVALID;
- v += p->v;
- count++;
- }
- }
- cellerror = cellerr;
- rowoffset = coloffset = 0;
-
- if (count == 0) return ((double)0);
-
- return (v / (double)count);
-}
-
-/**
- * \brief dostddev()
- *
- * \param[in] minr
- * \param[in] minc
- * \param[in] maxr
- * \param[in] maxc
- * \param[in] e
- *
- * \return double
- */
-double dostddev(int minr, int minc, int maxr, int maxc, struct enode * e) {
- struct roman * roman = session->cur_doc;
- struct sheet * sh = roman->cur_sh;
- double lp, rp, v, nd;
- int r, c;
- int n;
- int cellerr = CELLOK;
- struct ent * p;
-
- n = 0;
- lp = 0;
- rp = 0;
- for (r = minr; r <= maxr; r++)
- for (c = minc; c <= maxc; c++) {
- if (e) {
- rowoffset = r - minr;
- coloffset = c - minc;
- }
- if (!e || eval(NULL, e))
- if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) {
- if (p->cellerror) cellerr = CELLINVALID;
- v = p->v;
- lp += v*v;
- rp += v;
- n++;
- }
- }
- cellerror = cellerr;
- rowoffset = coloffset = 0;
-
- if ((n == 0) || (n == 1)) return ((double)0);
- nd = (double) n;
- return ( sqrt((nd*lp-rp*rp) / (nd*(nd-1))) );
-}
-
-/**
- * \brief domax()
- *
- * \param[in] minr
- * \param[in] minc
- * \param[in] maxr
- * \param[in] maxc
- * \param[in] e
- *
- * \return double
- */
-double domax(int minr, int minc, int maxr, int maxc, struct enode * e) {
- struct roman * roman = session->cur_doc;
- struct sheet * sh = roman->cur_sh;
- double v = (double) 0;
- int r, c;
- int count;
- int cellerr = CELLOK;
- struct ent * p;
-
- count = 0;
- for (r = minr; r <= maxr; r++)
- for (c = minc; c <= maxc; c++) {
- if (e) {
- rowoffset = r - minr;
- coloffset = c - minc;
- }
- if (!e || eval(NULL, e))
- if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) {
- if (p->cellerror) cellerr = CELLINVALID;
-
- if (! count) {
- v = p->v;
- count++;
- } else if (p->v > v)
- v = p->v;
- }
- }
- cellerror = cellerr;
- rowoffset = coloffset = 0;
-
- if (count == 0) return ((double)0);
-
- return (v);
-}
-
-
-/**
- * \brief domin()
- *
- * \param[in] minr
- * \param[in] minc
- * \param[in] maxr
- * \param[in] maxc
- * \param[in] e
- *
- * \return double
- */
-double domin(int minr, int minc, int maxr, int maxc, struct enode * e) {
- struct roman * roman = session->cur_doc;
- struct sheet * sh = roman->cur_sh;
- double v = (double)0;
- int r, c;
- int count;
- int cellerr = CELLOK;
- struct ent * p;
-
- count = 0;
- for (r = minr; r <= maxr; r++)
- for (c = minc; c <= maxc; c++) {
- if (e) {
- rowoffset = r - minr;
- coloffset = c - minc;
- }
- if (!e || eval(NULL, e))
- if ((p = *ATBL(sh, sh->tbl, r, c)) && p->flags & is_valid) {
- if (p->cellerror) cellerr = CELLINVALID;
- if (! count) {
- v = p->v;
- count++;
- } else if (p->v < v)
- v = p->v;
- }
- }
- cellerror = cellerr;
- rowoffset = coloffset = 0;
-
- if (count == 0) return ((double) 0);
-
- return (v);
-}
-
-
-int mdays[12]={ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
-
-/**
- * \brief dodts()
- * \param[in] e1
- * \param[in] e2
- * \param[in] e3
- * \return double
- */
-double dodts(int e1, int e2, int e3) {
- int yr, mo, day;
- time_t secs;
- struct tm t;
-
- if (e2 > 12 || e3 > 31) {
- mo = e1;
- day = e2;
- yr = e3;
- } else {
- yr = e1;
- mo = e2;
- day = e3;
- }
- mdays[1] = 28 + (yr % 4 == 0) - (yr % 100 == 0) + (yr % 400 == 0);
-
- t.tm_hour = t.tm_min = t.tm_sec = 0;
- t.tm_mon = --mo;
- t.tm_mday = day;
- t.tm_year = yr -= 1900;
- t.tm_isdst = -1;
-
- if (mo < 0 || mo > 11 || day < 1 || day > mdays[mo] || (secs = mktime(&t)) == -1) {
- sc_error("@dts: invalid argument or date out of range");
- cellerror = CELLERROR;
- return (0.0);
- }
-
- return ((double) secs);
-}
-
-
-/**
- * \brief dotts()
- * \param[in] hr
- * \param[in] min
- * \param[in] sec
- * \return double
- */
-double dotts(int hr, int min, int sec) {
- if (hr < 0 || hr > 23 || min < 0 || min > 59 || sec < 0 || sec > 59) {
- sc_error ("@tts: Invalid argument");
- cellerror = CELLERROR;
- return ((double) 0);
- }
- return ((double) (sec + min * 60 + hr * 3600));
-}
-
-
-/**
- * \brief dorow()
- * \param[in] ep
- * \return double
- */
-double dorow(struct enode * ep) {
- return (double) ep->e.v.vp->row;
-}
-
-
-/**
- * \brief docol()
- *
- * \param[in] ep
- *
- * \return double
- */
-double docol(struct enode * ep) {
- return (double) ep->e.v.vp->col;
-}
-
-
-/**
- * \brief dotime()
- *
- * \param[in] which
- * \param[in] when
- *
- * \return double
- */
-double dotime(int which, double when) {
- static time_t t_cache;
- static struct tm tm_cache;
- struct tm *tp;
- time_t tloc;
-
- if (which == NOW)
- return (double) time(NULL);
-
- tloc = (time_t)when;
-
- if (tloc != t_cache) {
- tp = localtime(&tloc);
- tm_cache = *tp;
- tm_cache.tm_mon += 1;
- tm_cache.tm_year += 1900;
- t_cache = tloc;
- }
-
- switch (which) {
- case HOUR: return ((double)(tm_cache.tm_hour));
- case MINUTE: return ((double)(tm_cache.tm_min));
- case SECOND: return ((double)(tm_cache.tm_sec));
- case MONTH: return ((double)(tm_cache.tm_mon));
- case DAY: return ((double)(tm_cache.tm_mday));
- case YEAR: return ((double)(tm_cache.tm_year));
- }
- /* Safety net */
- cellerror = CELLERROR;
- return ((double)0);
-}
-
-
-/**
- * \brief doston()
- * \param[in] s
- * \return double
- */
-double doston(char * s) {
- double v;
-
- if ( !s ) return ((double)0);
-
- v = strtod(s, NULL);
- scxfree(s);
- return(v);
-}
-
-
-/**
- * \brief doevaluate(): take a char * with a formula and eval it
- * \param[in] s
- * \return double
- */
-double doevaluate(char * s) {
- if ( !s) return ((double)0);
- wchar_t cline [BUFFERSIZE];
- swprintf(cline, BUFFERSIZE, L"eval %s", s);
- send_to_interp(cline);
- double d = eval_result;
- scxfree(s);
- return (double) d;
-}
-
-
-/**
- * \brief doslen()
- * \param[in] s
- * \return int
- */
-int doslen(char * s) {
- if (!s) return 0;
-
- //int i = strlen(s);
- int i = 0;
-
- wchar_t widestring[BUFFERSIZE] = { L'\0' };
- const char * mbsptr = s;
- size_t result = mbsrtowcs(widestring, &mbsptr, BUFFERSIZE, NULL);
- if ( result != (size_t) -1 ) i = wcslen(widestring);
- scxfree(s);
- return i;
-}
-
-
-/**
- * \brief doeqs()
- *
- * \param[in] s1
- * \param[in] s2
- *
- * \return double
- */
-double doeqs(char * s1, char * s2) {
- double v;
-
- if ( !s1 && !s2 ) return ((double)1.0);
-
- if ( !s1 || !s2 )
- v = 0.0;
- else if (strcmp(s1, s2) == 0)
- v = 1.0;
- else
- v = 0.0;
-
- if (s1) scxfree(s1);
-
- if (s2) scxfree(s2);
-
- return(v);
-}
-
-
-/**
- * \brief getent()
- *
- * \details Given a string representing a column name and a value which
- * is a row number, return a pointer to the selected cell's entry.
- * if alloc == 0 and no cell is alloc, return NULL.
- * Use only the integer part of the column number. Always
- * free the string
- *
- * \param[in] colstr
- * \param[in] rwodoub
- *
- * \return struct ent *
- */
-struct ent * getent(char *colstr, double rowdoub, int alloc) {
- struct roman * roman = session->cur_doc;
- struct sheet * sh = roman->cur_sh;
- int collen; /* length of string */
- int row, col; /* integer values */
- struct ent *p = (struct ent *) 0; /* selected entry */
-
- if (!colstr) {
- cellerror = CELLERROR;
- return ((struct ent *) 0);
- }
- collen = strlen(colstr);
- col = atocol(colstr, collen);
- row = (int) floor(rowdoub);
-
- if (row >= 0
- && (row < sh->maxrows) /* in range */
- && (collen <= 2) /* not too long */
- && (col >= 0)
- && (col < sh->maxcols)) { /* in range */
- if (alloc) p = lookat(sh, row, col);
- else p = *ATBL(sh, sh->tbl, row, col);
- if ((p != NULL) && p->cellerror) cellerror = CELLINVALID;
- }
- scxfree(colstr);
- return (p);
-}
-
-
-/**
- * \brief donval()
- *
- * \details Given a string representing a column name and a value which is a
- * column number, return the selected cell's numeric value, if any.
- *
- * \param[in] colstr
- * \param[in] rowdoub
- *
- * \return double
- */
-double donval(char * colstr, double rowdoub) {
- struct ent * ep;
- return (((ep = getent(colstr, rowdoub, 0)) && ((ep->flags) & is_valid)) ? (ep->v) : (double)0);
-}
+int exprerr; /* Set by eval() and seval() if expression errors */
+double prescale = 1.0; /* Prescale for constants in let() */
+int gmyrow = -1, gmycol = -1; /* globals used to implement @myrow, @mycol cmds */
+int rowoffset = 0, coloffset = 0; /* row & col offsets for range functions */
+jmp_buf fpe_save;
+int cellerror = CELLOK; /**< is there an error in this cell */
-/**
- * \brief dolmax()
- *
- * \details The list routines (e.g. dolmax) are called with an LMAX
- * enode. The left pointer is a chain of ELIST nodes, the right
- * pointer is a value.
- *
- * \param[in] e
- * \param[in] ep
- *
- * \return double
- */
-double dolmax(struct ent * e, struct enode * ep) {
- int count = 0;
- double maxval = 0; /* Assignment to shut up lint */
- struct enode * p;
- double v;
-
- cellerror = CELLOK;
- for (p = ep; p; p = p->e.o.left) {
- v = eval(e, p->e.o.right);
- if ( !count || v > maxval) {
- maxval = v;
- count++;
- }
- }
- if (count) return maxval;
- else return (double)0;
-}
+struct go_save gs = { .g_type = G_NONE }; /* Use this structure to save the last 'g' command */
-/**
- * \brief dolmin()
- * \param[in] e
- * \param[in] ep
- * \return double
- */
-double dolmin(struct ent * e, struct enode * ep) {
- int count = 0;
- double minval = 0; /* Assignment to shut up lint */
- struct enode * p;
- double v;
-
- cellerror = CELLOK;
- for (p = ep; p; p = p->e.o.left) {
- v = eval(e, p->e.o.right);
- if ( !count || v < minval) {
- minval = v;
- count++;
- }
- }
- if (count) return minval;
- else return (double)0;
-}
+/***********************************************************************************************/
/**
* \brief eval()
@@ -991,10 +133,10 @@ double eval(struct ent * ent, struct enode * e) {
struct roman * roman = session->cur_doc;
struct sheet * sh = roman->cur_sh;
-// //if (cellerror == CELLERROR || (ent && ent->cellerror == CELLERROR)) {
-// if (cellerror == CELLERROR) {
-// return (double) 0;
-// }
+// if (cellerror == CELLERROR || (ent && ent->cellerror == CELLERROR)) {
+// if (cellerror == CELLERROR) {
+// return (double) 0;
+// }
if (e == (struct enode *) 0) {
cellerror = CELLINVALID;
return (double) 0;
@@ -1099,20 +241,23 @@ double eval(struct ent * ent, struct enode * e) {
case O_VAR: {
struct ent * vp = e->e.v.vp;
+ struct sheet * sh_vp = e->e.v.sheet;
+ if (sh_vp == NULL) sh_vp = sh;
//sc_debug("var %d %d", vp->row, vp->col);
- if (vp && ent && vp->row == ent->row && vp->col == ent->col && !(vp->flags & is_deleted) ) {
+ //if (vp && ent && vp->row == ent->row && vp->col == ent->col && !(vp->flags & is_deleted) ) {
+ if (vp && ent && vp == ent && !(vp->flags & is_deleted) ) {
sc_error("Circular reference in eval (cell %s%d)", coltoa(vp->col), vp->row);
//ERR propagates. comment to make it not to.
cellerror = CELLERROR;
//ent->cellerror = CELLERROR;
- GraphAddEdge( getVertex(graph, lookat(sh, ent->row, ent->col), 1), getVertex(graph, lookat(sh, vp->row, vp->col), 1) ) ;
+ GraphAddEdge( getVertex(graph, lookat(sh, ent->row, ent->col), 1), getVertex(graph, lookat(sh_vp, vp->row, vp->col), 1) ) ;
return (double) 0;
}
if (vp && vp->cellerror == CELLERROR && !(vp->flags & is_deleted)) {
// here we store the dependences in a graph
if (ent && vp) GraphAddEdge( getVertex(graph, lookat(sh, ent->row, ent->col), 1),
- getVertex(graph, lookat(sh, vp->row, vp->col), 1) ) ;
+ getVertex(graph, lookat(sh_vp, vp->row, vp->col), 1) ) ;
//does not change reference to @err in expression
//uncomment to do so
@@ -1128,7 +273,7 @@ double eval(struct ent * ent, struct enode * e) {
row = e->e.v.vf & FIX_ROW ? vp->row : vp->row + rowoffset;
col = e->e.v.vf & FIX_COL ? vp->col : vp->col + coloffset;
checkbounds(sh, &row, &col);
- vp = *ATBL(sh, sh->tbl, row, col);
+ vp = *ATBL(sh_vp, sh_vp->tbl, row, col);
}
@@ -1149,7 +294,7 @@ double eval(struct ent * ent, struct enode * e) {
// here we store the dependences in a graph
if (ent && vp) {
vertexT * v_ent = getVertex(graph, lookat(sh, ent->row, ent->col), 0);
- vertexT * v_vp = getVertex(graph, lookat(sh, vp->row, vp->col), 0);
+ vertexT * v_vp = getVertex(graph, lookat(sh_vp, vp->row, vp->col), 0);
if (v_ent != NULL && v_vp != NULL && GraphIsReachable(v_ent, v_vp, 1)) {
sc_error("Circular reference in eval (cell %s%d)", coltoa(vp->col), vp->row);
e->op = ERR_;
@@ -1158,7 +303,7 @@ double eval(struct ent * ent, struct enode * e) {
cellerror = CELLERROR;
return (double) 0;
}
- GraphAddEdge( getVertex(graph, lookat(sh, ent->row, ent->col), 1), getVertex(graph, lookat(sh, vp->row, vp->col), 1) ) ;
+ GraphAddEdge( getVertex(graph, lookat(sh, ent->row, ent->col), 1), getVertex(graph, lookat(sh_vp, vp->row, vp->col), 1) ) ;
}
if (vp->cellerror) {
@@ -1192,9 +337,8 @@ double eval(struct ent * ent, struct enode * e) {
if (minr>maxr) r = maxr, maxr = minr, minr = r;
if (minc>maxc) c = maxc, maxc = minc, minc = c;
- for (row=minr; row <= maxr; row++) {
+ for (row=minr; ent != NULL && row <= maxr; row++) {
for (col=minc; col <= maxc; col++) {
- if (ent == NULL) continue;
if (ent->row == row && ent->col == col) {
sc_error("Circular reference in eval (cell %s%d)", coltoa(col), row);
e->op = ERR_;
@@ -1416,401 +560,11 @@ double eval(struct ent * ent, struct enode * e) {
return ((double) 0.0);
}
-/*
- * \brief TODO Document eval_fpe()
- * \return none
- */
-void eval_fpe() { /* Trap for FPE errors in eval */
-#if defined(i386)
- sc_debug("eval_fpe i386");
- asm(" fnclex");
- asm(" fwait");
-#else
- #ifdef IEEE_MATH
- (void)fpsetsticky((fp_except)0); /* Clear exception */
- #endif /* IEEE_MATH */
-#endif
- /* re-establish signal handler for next time */
- (void) signal(SIGFPE, eval_fpe);
- longjmp(fpe_save, 1);
-}
-
-/**
- * \brief fn1_eval()
- * \param[in] fn
- * \param[in] arg
- * \return double
- */
-double fn1_eval(double (*fn)(), double arg) {
- double res;
- errno = 0;
- res = (*fn) (arg);
- if (errno) cellerror = CELLERROR;
-
- return res;
-}