diff options
-rw-r--r-- | CHANGES | 8 | ||||
-rwxr-xr-x | src/debug.sh | 2 | ||||
-rwxr-xr-x | src/gdb.gdb | 2 | ||||
-rw-r--r-- | src/interp.c | 1471 | ||||
-rw-r--r-- | src/interp.h | 35 |
5 files changed, 137 insertions, 1381 deletions
@@ -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; -} |