home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume35 / ss / part02 < prev    next >
Encoding:
Text File  |  1993-03-02  |  60.4 KB  |  2,637 lines

  1. Newsgroups: comp.sources.misc
  2. From: art@cs.ualberta.ca (Art Mulder)
  3. Subject: v35i088:  ss - Simple Spreadsheet program, v1.2b, Part02/11
  4. Message-ID: <1993Feb22.152326.21284@sparky.imd.sterling.com>
  5. X-Md4-Signature: 1c73db2cc7d4b58e03f24f033df360f3
  6. Date: Mon, 22 Feb 1993 15:23:26 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: art@cs.ualberta.ca (Art Mulder)
  10. Posting-number: Volume 35, Issue 88
  11. Archive-name: ss/part02
  12. Environment: curses, sunos, sysv, ultrix, sgi, dec, mips, sun
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  ss_12b/interp.c ss_12b/xmalloc.c
  19. # Wrapped by kent@sparky on Sat Feb 20 16:01:01 1993
  20. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  21. echo If this archive is complete, you will see the following message:
  22. echo '          "shar: End of archive 2 (of 11)."'
  23. if test -f 'ss_12b/interp.c' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'ss_12b/interp.c'\"
  25. else
  26.   echo shar: Extracting \"'ss_12b/interp.c'\" \(55653 characters\)
  27.   sed "s/^X//" >'ss_12b/interp.c' <<'END_OF_FILE'
  28. X/*    SC    A Spreadsheet Calculator
  29. X *        Expression interpreter and assorted support routines.
  30. X *
  31. X *        original by James Gosling, September 1982
  32. X *        modified by Mark Weiser and Bruce Israel, 
  33. X *            University of Maryland
  34. X *
  35. X *              More mods Robert Bond, 12/86
  36. X *        More mods by Alan Silverstein, 3-4/88, see list of changes.
  37. X *        $Revision: 6.21 $
  38. X */
  39. X
  40. X#ifndef lint
  41. X  static char Sccsid[] = "%W% %G%";
  42. X#endif
  43. X
  44. X#define DEBUGDTS 1        /* REMOVE ME */
  45. X     
  46. X#include <sys/types.h>
  47. X#ifdef aiws
  48. X#undef _C_func            /* Fixes for undefined symbols on AIX */
  49. X#endif
  50. X
  51. X#ifdef IEEE_MATH
  52. X#include <ieeefp.h>
  53. X#endif /* IEEE_MATH */
  54. X
  55. X#include <math.h>
  56. X#include <signal.h>
  57. X#include <setjmp.h>
  58. X#include <stdio.h>
  59. X#include <ctype.h>
  60. X
  61. Xextern int errno;        /* set by math functions */
  62. X#ifdef BSD42
  63. X#include <strings.h>
  64. X#include <sys/time.h>
  65. X#ifndef strchr
  66. X#define strchr index
  67. X#endif
  68. X#else
  69. X#include <time.h>
  70. X#ifndef SYSIII
  71. X#include <string.h>
  72. X#endif
  73. X#endif
  74. X
  75. X#include "curses_stuff.h"
  76. X#include "ss.h"
  77. X
  78. X#if defined(RE_COMP)
  79. Xchar *re_comp();
  80. X#endif
  81. X#if defined(REGCMP)
  82. Xchar *regcmp();
  83. Xchar *regex();
  84. X#endif
  85. X
  86. XVOID_OR_INT doquit();
  87. X
  88. X/* Use this structure to save the the last 'g' command */
  89. Xstruct go_save {
  90. X    int g_type;
  91. X    double g_n;
  92. X    char *g_s;
  93. X    int  g_row;
  94. X    int  g_col;
  95. X    int  errsearch;
  96. X} gs;
  97. X
  98. X/* g_type can be: */
  99. X#define G_NONE 0            /* Starting value - must be 0*/
  100. X#define G_NUM 1
  101. X#define G_STR 2
  102. X#define G_CELL 3
  103. X
  104. X#define ISVALID(r,c)    ((r)>=0 && (r)<maxrows && (c)>=0 && (c)<maxcols)
  105. X
  106. Xextern FILE *popen();
  107. X
  108. Xjmp_buf fpe_save;
  109. Xint    exprerr;    /* Set by eval() and seval() if expression errors */
  110. Xdouble  prescale = 1.0;    /* Prescale for constants in let() */
  111. Xint    extfunc  = 0;    /* Enable/disable external functions */
  112. Xint     loading = 0;    /* Set when readfile() is active */
  113. Xint    gmyrow, gmycol;    /* globals used to implement @myrow, @mycol cmds */
  114. X
  115. X/* a linked list of free [struct enodes]'s, uses .e.o.left as the pointer */
  116. Xstruct enode *freeenodes = NULL;
  117. X
  118. Xchar    *seval();
  119. Xdouble    dolookup();
  120. Xdouble    eval();
  121. Xdouble    fn1_eval();
  122. Xdouble    fn1_seval();
  123. Xdouble    fn2_eval();
  124. Xint    RealEvalAll();
  125. Xint    constant();
  126. Xvoid    RealEvalOne();
  127. Xvoid    copyrtv();
  128. Xvoid    decompile();
  129. Xvoid    index_arg();
  130. Xvoid    list_arg();
  131. Xvoid    one_arg();
  132. Xvoid    range_arg();
  133. Xvoid    three_arg();
  134. Xvoid    two_arg();
  135. Xvoid    two_arg_index();
  136. X
  137. Xint     repct = 1;        /* Make repct a global variable so that the 
  138. X                   function @numiter can access it */
  139. X
  140. Xdouble    rint();
  141. Xint    cellerror = CELLOK;    /* is there an error in this cell */
  142. X
  143. X#ifndef PI
  144. X#define PI (double)3.14159265358979323846
  145. X#endif
  146. X#define dtr(x) ((x)*(PI/(double)180.0))
  147. X#define rtd(x) ((x)*(180.0/(double)PI))
  148. X
  149. Xdouble finfunc(fun,v1,v2,v3)
  150. Xint fun;
  151. Xdouble v1,v2,v3;
  152. X{
  153. X     double answer,p;
  154. X     p = fn2_eval(pow, 1 + v2, v3);
  155. X     switch(fun)
  156. X     {
  157. X     case PV:
  158. X        if (v2)
  159. X            answer = v1 * (1 - 1/p) / v2;
  160. X        else
  161. X        {    cellerror = CELLERROR;
  162. X            answer = (double)0;
  163. X        }
  164. X         break;
  165. X     case FV:
  166. X        if (v2)
  167. X            answer = v1 * (p - 1) / v2;
  168. X        else
  169. X        {    cellerror = CELLERROR;
  170. X            answer = (double)0;
  171. X        }
  172. X         break;
  173. X     case PMT:
  174. X        /* CHECK IF ~= 1 - 1/1 */
  175. X        if (p && p != (double)1)
  176. X            answer = v1 * v2 / (1 - 1/p);
  177. X        else
  178. X        {    cellerror = CELLERROR;
  179. X            answer = (double)0;
  180. X        }
  181. X        
  182. X         break;
  183. X    default:
  184. X        error("Unknown function in finfunc");
  185. X        cellerror = CELLERROR;
  186. X        return((double)0);
  187. X    }
  188. X    return(answer);
  189. X}
  190. X
  191. Xchar *
  192. Xdostindex( val, minr, minc, maxr, maxc)
  193. Xdouble val;
  194. Xint minr, minc, maxr, maxc;
  195. X{
  196. X    register r,c;
  197. X    register struct ent *p;
  198. X    char *pr;
  199. X    int x;
  200. X
  201. X    x = (int) val;
  202. X    r = minr; c = minc;
  203. X    p = (struct ent *)0;
  204. X    if ( minr == maxr ) { /* look along the row */
  205. X    c = minc + x - 1;
  206. X    if (c <= maxc && c >=minc)
  207. X        p = *ATBL(tbl, r, c);
  208. X    } else if ( minc == maxc ) { /* look down the column */
  209. X    r = minr + x - 1;
  210. X    if (r <= maxr && r >=minr)
  211. X        p = *ATBL(tbl, r, c);
  212. X    } else {
  213. X    error ("range specified to @stindex");
  214. X    cellerror = CELLERROR;
  215. X    return((char *)0);
  216. X    }
  217. X
  218. X    if (p && p->label) {
  219. X    pr = Malloc((unsigned)(strlen(p->label)+1));
  220. X    Strcpy(pr, p->label);
  221. X    if (p->cellerror)
  222. X        cellerror = CELLINVALID;
  223. X    return (pr);
  224. X     } else
  225. X    return((char *)0);
  226. X}
  227. X
  228. Xdouble
  229. Xdoindex( val, minr, minc, maxr, maxc)
  230. Xdouble val;
  231. Xint minr, minc, maxr, maxc;
  232. X{
  233. X    double v;
  234. X    register r,c;
  235. X    register struct ent *p;
  236. X    int x;
  237. X
  238. X    x = (int) val;
  239. X    v = (double)0;
  240. X    r = minr; c = minc;
  241. X    if ( minr == maxr ) { /* look along the row */
  242. X    c = minc + x - 1;
  243. X    if (c <= maxc && c >=minc 
  244. X        && (p = *ATBL(tbl, r, c)) && p->flags&is_valid )
  245. X    {    if (p->cellerror)
  246. X            cellerror = CELLINVALID;
  247. X        return p->v;
  248. X    }
  249. X    }
  250. X    else if ( minc == maxc ){ /* look down the column */
  251. X    r = minr + x - 1;
  252. X    if (r <= maxr && r >=minr 
  253. X        && (p = *ATBL(tbl, r, c)) && p->flags&is_valid )
  254. X    {    if (p->cellerror)
  255. X            cellerror = CELLINVALID;
  256. X        return p->v;
  257. X    }
  258. X    }
  259. X    else {
  260. X    error(" range specified to @index");
  261. X    cellerror = CELLERROR;
  262. X    }
  263. X    return v;
  264. X}
  265. X
  266. Xdouble
  267. Xdolookup( val, minr, minc, maxr, maxc, offr, offc)
  268. Xstruct enode * val;
  269. Xint minr, minc, maxr, maxc, offr, offc;
  270. X{
  271. X    double v, ret = (double)0;
  272. X    register r,c;
  273. X    register struct ent *p = (struct ent *)0;
  274. X    int incr,incc,fndr,fndc;
  275. X    char *s;
  276. X
  277. X    incr = (offc != 0); incc = (offr != 0);
  278. X    if (etype(val) == NUM) {
  279. X    cellerror = CELLOK;
  280. X    v = eval(val);
  281. X    for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) {
  282. X        if ( (p = *ATBL(tbl, r, c)) && p->flags&is_valid ) {
  283. X        if (p->v <= v) {
  284. X            fndr = incc ? (minr + offr) : r;
  285. X            fndc = incr ? (minc + offc) : c;
  286. X            if (ISVALID(fndr,fndc))
  287. X            p = *ATBL(tbl, fndr, fndc);
  288. X            else {
  289. X            error(" range specified to @[hv]lookup");
  290. X            cellerror = CELLERROR;
  291. X            }
  292. X            if ( p && p->flags&is_valid)
  293. X            {    if (p->cellerror)
  294. X                cellerror = CELLINVALID;
  295. X            ret = p->v;
  296. X            }
  297. X        } else break;
  298. X        }
  299. X    }
  300. X    } else {
  301. X    cellerror = CELLOK;
  302. X    s = seval(val);
  303. X    for (r = minr, c = minc; r <= maxr && c <= maxc; r+=incr, c+=incc) {
  304. X        if ( (p = *ATBL(tbl, r, c)) && p->label ) {
  305. X        if (strcmp(p->label,s) == 0) {
  306. X            fndr = incc ? (minr + offr) : r;
  307. X            fndc = incr ? (minc + offc) : c;
  308. X            if (ISVALID(fndr,fndc))
  309. X            {    p = *ATBL(tbl, fndr, fndc);
  310. X            if (p->cellerror)
  311. X                cellerror = CELLINVALID;
  312. X            }
  313. X            else {
  314. X            error(" range specified to @[hv]lookup");
  315. X            cellerror = CELLERROR;
  316. X            }
  317. X            break;
  318. X        }
  319. X        }
  320. X    }
  321. X    if ( p && p->flags&is_valid)
  322. X        ret = p->v;
  323. X    Free(s);
  324. X    }
  325. X    return ret;
  326. X}
  327. X
  328. Xdouble
  329. Xdocount(minr, minc, maxr, maxc)
  330. Xint minr, minc, maxr, maxc;
  331. X{
  332. X    int v;
  333. X    register r,c;
  334. X    register struct ent *p;
  335. X
  336. X    v = 0;
  337. X    for (r = minr; r<=maxr; r++)
  338. X    for (c = minc; c<=maxc; c++)
  339. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
  340. X        {    if (p->cellerror)
  341. X            cellerror = CELLINVALID;
  342. X        v++;
  343. X        }
  344. X    return v;
  345. X}
  346. X
  347. Xdouble
  348. Xdosum(minr, minc, maxr, maxc)
  349. Xint minr, minc, maxr, maxc;
  350. X{
  351. X    double v;
  352. X    register r,c;
  353. X    register struct ent *p;
  354. X
  355. X    v = (double)0;
  356. X    for (r = minr; r<=maxr; r++)
  357. X    for (c = minc; c<=maxc; c++)
  358. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
  359. X        {    if (p->cellerror)
  360. X            cellerror = CELLINVALID;
  361. X        v += p->v;
  362. X        }
  363. X    return v;
  364. X}
  365. X
  366. Xdouble
  367. Xdoprod(minr, minc, maxr, maxc)
  368. Xint minr, minc, maxr, maxc;
  369. X{
  370. X    double v;
  371. X    register r,c;
  372. X    register struct ent *p;
  373. X
  374. X    v = 1;
  375. X    for (r = minr; r<=maxr; r++)
  376. X    for (c = minc; c<=maxc; c++)
  377. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid)
  378. X        {    if (p->cellerror)
  379. X            cellerror = CELLINVALID;
  380. X        v *= p->v;
  381. X        }
  382. X    return v;
  383. X}
  384. X
  385. Xdouble
  386. Xdoavg(minr, minc, maxr, maxc)
  387. Xint minr, minc, maxr, maxc;
  388. X{
  389. X    double v;
  390. X    register r,c,count;
  391. X    register struct ent *p;
  392. X
  393. X    v = (double)0;
  394. X    count = 0;
  395. X    for (r = minr; r<=maxr; r++)
  396. X    for (c = minc; c<=maxc; c++)
  397. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
  398. X        if (p->cellerror)
  399. X            cellerror = CELLINVALID;
  400. X
  401. X        v += p->v;
  402. X        count++;
  403. X        }
  404. X
  405. X    if (count == 0) 
  406. X    return ((double) 0);
  407. X
  408. X    return (v / (double)count);
  409. X}
  410. X
  411. Xdouble
  412. Xdostddev(minr, minc, maxr, maxc)
  413. Xint minr, minc, maxr, maxc;
  414. X{
  415. X    double lp, rp, v, nd;
  416. X    register r,c,n;
  417. X    register struct ent *p;
  418. X
  419. X    n = 0;
  420. X    lp = 0;
  421. X    rp = 0;
  422. X    for (r = minr; r<=maxr; r++)
  423. X    for (c = minc; c<=maxc; c++)
  424. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
  425. X        if (p->cellerror)
  426. X            cellerror = CELLINVALID;
  427. X
  428. X        v = p->v;
  429. X        lp += v*v;
  430. X        rp += v;
  431. X        n++;
  432. X        }
  433. X
  434. X    if ((n == 0) || (n == 1)) 
  435. X    return ((double) 0);
  436. X    nd = (double)n;
  437. X    return (sqrt((nd*lp-rp*rp)/(nd*(nd-1))));
  438. X}
  439. X
  440. Xdouble
  441. Xdomax(minr, minc, maxr, maxc)
  442. Xint minr, minc, maxr, maxc;
  443. X{
  444. X    double v = (double)0;
  445. X    register r,c,count;
  446. X    register struct ent *p;
  447. X
  448. X    count = 0;
  449. X    for (r = minr; r<=maxr; r++)
  450. X    for (c = minc; c<=maxc; c++)
  451. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
  452. X        if (p->cellerror)
  453. X            cellerror = CELLINVALID;
  454. X
  455. X        if (!count) {
  456. X            v = p->v;
  457. X            count++;
  458. X        } else if (p->v > v)
  459. X            v = p->v;
  460. X        }
  461. X
  462. X    if (count == 0) 
  463. X    return ((double) 0);
  464. X
  465. X    return (v);
  466. X}
  467. X
  468. Xdouble
  469. Xdomin(minr, minc, maxr, maxc)
  470. Xint minr, minc, maxr, maxc;
  471. X{
  472. X    double v = (double)0;
  473. X    register r,c,count;
  474. X    register struct ent *p;
  475. X
  476. X    count = 0;
  477. X    for (r = minr; r<=maxr; r++)
  478. X    for (c = minc; c<=maxc; c++)
  479. X        if ((p = *ATBL(tbl, r, c)) && p->flags&is_valid) {
  480. X        if (p->cellerror)
  481. X            cellerror = CELLINVALID;
  482. X
  483. X        if (!count) {
  484. X            v = p->v;
  485. X            count++;
  486. X        } else if (p->v < v)
  487. X            v = p->v;
  488. X        }
  489. X
  490. X    if (count == 0) 
  491. X    return ((double) 0);
  492. X
  493. X    return (v);
  494. X}
  495. X
  496. X#define sec_min 60
  497. X#define sec_hr  3600L
  498. X#define sec_day 86400L
  499. X#define sec_yr  31471200L     /* 364.25 days/yr */
  500. X#define sec_mo  2622600L       /* sec_yr/12: sort of an average */
  501. Xint mdays[12]={ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  502. X
  503. Xdouble
  504. Xdodts(mo, day, yr)
  505. Xint mo, day, yr;
  506. X{
  507. X    long trial;
  508. X    register struct tm *tp; 
  509. X    register int i;
  510. X    register long jdate;
  511. X
  512. X    mdays[1] = 28 + (yr%4 == 0);
  513. X
  514. X    if (mo < 1 || mo > 12 || day < 1 || day > mdays[--mo] ||
  515. X        yr > 1999 || yr < 1970) {
  516. X    error("@dts: invalid argument");
  517. X    cellerror = CELLERROR;
  518. X    return(0.0);
  519. X    }
  520. X
  521. X    jdate = day-1;
  522. X    for (i=0; i<mo; i++)
  523. X        jdate += mdays[i];
  524. X    for (i = 1970; i < yr; i++)
  525. X        jdate += 365 + (i%4 == 0);
  526. X
  527. X    trial = jdate * sec_day; 
  528. X
  529. X    yr -= 1900;
  530. X
  531. X    tp = localtime(&trial);
  532. X
  533. X    if (tp->tm_year != yr) {
  534. X        /*
  535. X        * We may fail this test once a year because of time zone
  536. X         * and daylight savings time errors.  This bounces the
  537. X         * trial time past the boundary.  The error introduced is
  538. X         * corrected below.
  539. X         */
  540. X        trial += sec_day*(yr - tp->tm_year);
  541. X        tp = localtime(&trial);
  542. X    }
  543. X    if (tp->tm_mon != mo) {
  544. X        /* We may fail this test once a month.  */
  545. X        trial += sec_day*(mo - tp->tm_mon);
  546. X        tp = localtime(&trial);
  547. X    }
  548. X    if (tp->tm_mday + tp->tm_hour + tp->tm_min + tp->tm_sec != day) {
  549. X    trial -= (tp->tm_mday - day)*sec_day +  tp->tm_hour*sec_hr
  550. X         + tp->tm_min*sec_min + tp->tm_sec;
  551. X    }
  552. X
  553. X#ifdef DEBUGDTS
  554. X    tp = localtime(&trial);
  555. X    if (tp->tm_mday + tp->tm_hour + tp->tm_min + tp->tm_sec + 
  556. X    tp->tm_year + tp->tm_mon != yr+mo+day)
  557. X    {    error("Dts broke down");
  558. X        cellerror = CELLERROR;
  559. X    }
  560. X#endif
  561. X
  562. X    return ((double)trial);
  563. X}
  564. X
  565. Xdouble
  566. Xdotts(hr, min, sec)
  567. Xint hr, min, sec;
  568. X{
  569. X    if (hr < 0 || hr > 23 || min < 0 || min > 59 || sec < 0 || sec > 59) {
  570. X    error ("@tts: Invalid argument");
  571. X    cellerror = CELLERROR;
  572. X    return ((double)0);
  573. X    }
  574. X    return ((double)(sec+min*60+hr*3600));
  575. X}
  576. X
  577. Xdouble
  578. Xdotime(which, when)
  579. Xint which;
  580. Xdouble when;
  581. X{
  582. X    long time();
  583. X
  584. X    static long t_cache;
  585. X    static struct tm tm_cache;
  586. X    struct tm *tp;
  587. X    long tloc;
  588. X
  589. X    if (which == NOW) 
  590. X        return (double)time((long *)0);
  591. X
  592. X    tloc = (long)when;
  593. X
  594. X    if (tloc != t_cache) {
  595. X        tp = localtime(&tloc);
  596. X        tm_cache = *tp;
  597. X        tm_cache.tm_mon += 1;
  598. X        tm_cache.tm_year += 1900;
  599. X        t_cache = tloc;
  600. X    }
  601. X
  602. X    switch (which) {
  603. X        case HOUR: return((double)(tm_cache.tm_hour));
  604. X        case MINUTE: return((double)(tm_cache.tm_min));
  605. X        case SECOND: return((double)(tm_cache.tm_sec));
  606. X        case MONTH: return((double)(tm_cache.tm_mon));
  607. X        case DAY: return((double)(tm_cache.tm_mday));
  608. X        case YEAR: return((double)(tm_cache.tm_year));
  609. X    }
  610. X    /* Safety net */
  611. X    cellerror = CELLERROR;
  612. X    return ((double)0);
  613. X}
  614. X
  615. Xdouble
  616. Xdoston(s)
  617. Xchar *s;
  618. X{
  619. X#ifndef _AIX
  620. X      char *strtof();
  621. X#endif
  622. X    double v;
  623. X
  624. X    if (!s)
  625. X    return((double)0);
  626. X
  627. X    Strtof(s, &v);
  628. X    Free(s);
  629. X    return(v);
  630. X}
  631. X
  632. Xdouble
  633. Xdoeqs(s1, s2)
  634. Xchar *s1, *s2;
  635. X{
  636. X    double v;
  637. X
  638. X    if (!s1 && !s2)
  639. X    return((double)1.0);
  640. X
  641. X    if (!s1 || !s2)
  642. X    v = 0.0;
  643. X    else if (strcmp(s1, s2) == 0)
  644. X    v = 1.0;
  645. X    else
  646. X    v = 0.0;
  647. X
  648. X    if (s1)
  649. X        Free(s1);
  650. X
  651. X    if (s2)
  652. X        Free(s2);
  653. X
  654. X    return(v);
  655. X}
  656. X
  657. X
  658. X/*
  659. X * Given a string representing a column name and a value which is a column
  660. X * number, return a pointer to the selected cell's entry, if any, else NULL.
  661. X * Use only the integer part of the column number.  Always free the string.
  662. X */
  663. X
  664. Xstruct ent *
  665. Xgetent (colstr, rowdoub)
  666. X    char *colstr;
  667. X    double rowdoub;
  668. X{
  669. X    int collen;        /* length of string */
  670. X    int row, col;    /* integer values   */
  671. X    struct ent *p = (struct ent *)0;    /* selected entry   */
  672. X
  673. X    if (!colstr)
  674. X    {    cellerror = CELLERROR;
  675. X    return((struct ent *)0);
  676. X    }
  677. X
  678. X    if (((row = (int) floor (rowdoub)) >= 0)
  679. X     && (row < maxrows)                /* in range */
  680. X     && ((collen = strlen (colstr)) <= 2)    /* not too long */
  681. X     && ((col = atocol (colstr, collen)) >= 0)
  682. X     && (col < maxcols))            /* in range */
  683. X    {
  684. X    p = *ATBL(tbl, row, col);
  685. X    if ((p != NULL) && p->cellerror)
  686. X        cellerror = CELLINVALID;
  687. X    }
  688. X    Free (colstr);
  689. X    return (p);
  690. X}
  691. X
  692. X
  693. X/*
  694. X * Given a string representing a column name and a value which is a column
  695. X * number, return the selected cell's numeric value, if any.
  696. X */
  697. X
  698. Xdouble
  699. Xdonval (colstr, rowdoub)
  700. X    char *colstr;
  701. X    double rowdoub;
  702. X{
  703. X    struct ent *ep;
  704. X
  705. X    return (((ep = getent (colstr, rowdoub)) && ((ep -> flags) & is_valid)) ?
  706. X        (ep -> v) : (double)0);
  707. X}
  708. X
  709. X
  710. X/*
  711. X *    The list routines (e.g. dolmax) are called with an LMAX enode.
  712. X *    The left pointer is a chain of ELIST nodes, the right pointer
  713. X *    is a value.
  714. X */
  715. Xdouble
  716. Xdolmax(ep)
  717. Xstruct enode *ep;
  718. X{
  719. X    register int count = 0;
  720. X    register double maxval = 0; /* Assignment to shut up lint */
  721. X    register struct enode *p;
  722. X    register double v;
  723. X
  724. X    cellerror = CELLOK;
  725. X    for (p = ep; p; p = p->e.o.left) {
  726. X        v = eval(p->e.o.right);
  727. X        if (!count || v > maxval) {
  728. X            maxval = v; count++;
  729. X        }
  730. X    }
  731. X    if (count) return maxval;
  732. X    else return (double)0;
  733. X}
  734. X
  735. Xdouble
  736. Xdolmin(ep)
  737. Xstruct enode *ep;
  738. X{
  739. X    register int count = 0;
  740. X    register double minval = 0; /* Assignment to shut up lint */
  741. X    register struct enode *p;
  742. X    register double v;
  743. X
  744. X    cellerror = CELLOK;
  745. X    for (p = ep; p; p = p->e.o.left) {
  746. X        v = eval(p->e.o.right);
  747. X        if (!count || v < minval) {
  748. X            minval = v; count++;
  749. X        }
  750. X    }
  751. X    if (count) return minval;
  752. X    else return (double)0;
  753. X}
  754. X
  755. Xdouble 
  756. Xeval(e)
  757. Xregister struct enode *e;
  758. X{
  759. X    if (e == (struct enode *)0)
  760. X    {    cellerror = CELLINVALID;
  761. X    return (double)0;
  762. X    }
  763. X    switch (e->op) {
  764. X    case '+':    return (eval(e->e.o.left) + eval(e->e.o.right));
  765. X    case '-':    return (eval(e->e.o.left) - eval(e->e.o.right));
  766. X    case '*':    return (eval(e->e.o.left) * eval(e->e.o.right));
  767. X    case '/':     { double num, denom;
  768. X            num = eval(e->e.o.left);
  769. X            denom = eval(e->e.o.right);
  770. X            if (denom)
  771. X/*            if (1)    /* to test num div 0 */
  772. X                return(num/denom);
  773. X            else
  774. X            {    cellerror = CELLERROR;
  775. X                return((double) 0);
  776. X            }
  777. X    }
  778. X    case '%':     {    double num, denom;
  779. X            num = floor(eval(e->e.o.left));
  780. X            denom = floor(eval (e->e.o.right));
  781. X            if (denom)
  782. X                return(num - floor(num/denom)*denom);
  783. X            else
  784. X            {    cellerror = CELLERROR;
  785. X                return((double) 0);
  786. X            }
  787. X    }
  788. X    case '^':    return (fn2_eval(pow,eval(e->e.o.left),eval(e->e.o.right)));
  789. X    case '<':    return (eval(e->e.o.left) < eval(e->e.o.right));
  790. X    case '=':    return (eval(e->e.o.left) == eval(e->e.o.right));
  791. X    case '>':    return (eval(e->e.o.left) > eval(e->e.o.right));
  792. X    case '&':    return (eval(e->e.o.left) && eval(e->e.o.right));
  793. X    case '|':    return (eval(e->e.o.left) || eval(e->e.o.right));
  794. X    case IF:
  795. X    case '?':    return eval(e->e.o.left) ? eval(e->e.o.right->e.o.left)
  796. X                        : eval(e->e.o.right->e.o.right);
  797. X    case 'm':    return (-eval(e->e.o.right));
  798. X    case 'f':    return (eval(e->e.o.right));
  799. X    case '~':    return (eval(e->e.o.right) == 0.0);
  800. X    case O_CONST:    return (e->e.k);
  801. X    case O_VAR:    if (e->e.v.vp->cellerror)
  802. X                cellerror = CELLINVALID;
  803. X            return (e->e.v.vp->v);
  804. X    case INDEX:
  805. X    case LOOKUP:
  806. X    case HLOOKUP:
  807. X    case VLOOKUP:
  808. X        {    register r,c;
  809. X        register maxr, maxc;
  810. X        register minr, minc;
  811. X        maxr = e->e.o.right->e.r.right.vp -> row;
  812. X        maxc = e->e.o.right->e.r.right.vp -> col;
  813. X        minr = e->e.o.right->e.r.left.vp -> row;
  814. X        minc = e->e.o.right->e.r.left.vp -> col;
  815. X        if (minr>maxr) r = maxr, maxr = minr, minr = r;
  816. X        if (minc>maxc) c = maxc, maxc = minc, minc = c;
  817. X        switch(e->op){
  818. X        case LOOKUP:
  819. X            return dolookup(e->e.o.left, minr, minc, maxr, maxc,
  820. X                     minr==maxr, minc==maxc);
  821. X        case HLOOKUP:
  822. X                return dolookup(e->e.o.left->e.o.left, minr,minc,maxr,maxc,
  823. X            (int) eval(e->e.o.left->e.o.right), 0);
  824. X        case VLOOKUP:
  825. X                return dolookup(e->e.o.left->e.o.left, minr,minc,maxr,maxc,
  826. X            0, (int) eval(e->e.o.left->e.o.right));
  827. X        case INDEX:
  828. X            return doindex(eval(e->e.o.left), minr, minc, maxr, maxc);
  829. X        }
  830. X        }
  831. X      case (REDUCE | '+') :
  832. X       case (REDUCE | '*') :
  833. X       case (REDUCE | 'a') :
  834. X       case (REDUCE | 'c') :
  835. X       case (REDUCE | 's') :
  836. X      case (REDUCE | MAX) :
  837. X      case (REDUCE | MIN) :
  838. X        {    register r,c;
  839. X        register maxr, maxc;
  840. X        register minr, minc;
  841. X        maxr = e->e.r.right.vp -> row;
  842. X        maxc = e->e.r.right.vp -> col;
  843. X        minr = e->e.r.left.vp -> row;
  844. X        minc = e->e.r.left.vp -> col;
  845. X        if (minr>maxr) r = maxr, maxr = minr, minr = r;
  846. X        if (minc>maxc) c = maxc, maxc = minc, minc = c;
  847. X            switch (e->op) {
  848. X                case REDUCE | '+': return dosum(minr, minc, maxr, maxc);
  849. X                 case REDUCE | '*': return doprod(minr, minc, maxr, maxc);
  850. X                 case REDUCE | 'a': return doavg(minr, minc, maxr, maxc);
  851. X                 case REDUCE | 'c': return docount(minr, minc, maxr, maxc);
  852. X                 case REDUCE | 's': return dostddev(minr, minc, maxr, maxc);
  853. X                 case REDUCE | MAX: return domax(minr, minc, maxr, maxc);
  854. X                 case REDUCE | MIN: return domin(minr, minc, maxr, maxc);
  855. X        }
  856. X        }
  857. X    case ABS:     return (fn1_eval( fabs, eval(e->e.o.right)));
  858. X    case ACOS:     return (fn1_eval( acos, eval(e->e.o.right)));
  859. X    case ASIN:     return (fn1_eval( asin, eval(e->e.o.right)));
  860. X    case ATAN:     return (fn1_eval( atan, eval(e->e.o.right)));
  861. X    case ATAN2:     return (fn2_eval( atan2, eval(e->e.o.left), eval(e->e.o.right)));
  862. X    case CEIL:     return (fn1_eval( ceil, eval(e->e.o.right)));
  863. X    case COS:     return (fn1_eval( cos, eval(e->e.o.right)));
  864. X    case EXP:     return (fn1_eval( exp, eval(e->e.o.right)));
  865. X    case FABS:     return (fn1_eval( fabs, eval(e->e.o.right)));
  866. X    case FLOOR:     return (fn1_eval( floor, eval(e->e.o.right)));
  867. X    case HYPOT:     return (fn2_eval( hypot, eval(e->e.o.left), eval(e->e.o.right)));
  868. X    case LOG:     return (fn1_eval( log, eval(e->e.o.right)));
  869. X    case LOG10:     return (fn1_eval( log10, eval(e->e.o.right)));
  870. X    case POW:     return (fn2_eval( pow, eval(e->e.o.left), eval(e->e.o.right)));
  871. X    case SIN:     return (fn1_eval( sin, eval(e->e.o.right)));
  872. X    case SQRT:     return (fn1_eval( sqrt, eval(e->e.o.right)));
  873. X    case TAN:     return (fn1_eval( tan, eval(e->e.o.right)));
  874. X    case DTR:     return (dtr(eval(e->e.o.right)));
  875. X    case RTD:     return (rtd(eval(e->e.o.right)));
  876. X    case RND:
  877. X        if (rndinfinity)
  878. X        {    double temp = eval(e->e.o.right);
  879. X            return(temp-floor(temp) < 0.5 ?
  880. X                    floor(temp) : ceil(temp));
  881. X        }
  882. X        else
  883. X            return rint(eval(e->e.o.right));
  884. X     case ROUND:
  885. X        {    int prec = (int) eval(e->e.o.right);
  886. X            double    scal = 1;
  887. X            if (0 < prec)
  888. X                do scal *= 10; while (0 < --prec);
  889. X            else if (prec < 0)
  890. X                do scal /= 10; while (++prec < 0);
  891. X
  892. X            if (rndinfinity)
  893. X            {    double temp = eval(e->e.o.left);
  894. X                temp *= scal;
  895. X                temp = ((temp-floor(temp)) < 0.5 ?
  896. X                        floor(temp) : ceil(temp));
  897. X                return(temp / scal);
  898. X            }
  899. X            else
  900. X                return(rint(eval(e->e.o.left) * scal) / scal);
  901. X        }
  902. X    case FV:
  903. X    case PV:
  904. X    case PMT:    return(finfunc(e->op,eval(e->e.o.left),
  905. X                   eval(e->e.o.right->e.o.left),
  906. X                      eval(e->e.o.right->e.o.right)));
  907. X    case HOUR:    return (dotime(HOUR, eval(e->e.o.right)));
  908. X    case MINUTE:    return (dotime(MINUTE, eval(e->e.o.right)));
  909. X    case SECOND:    return (dotime(SECOND, eval(e->e.o.right)));
  910. X    case MONTH:    return (dotime(MONTH, eval(e->e.o.right)));
  911. X    case DAY:    return (dotime(DAY, eval(e->e.o.right)));
  912. X    case YEAR:    return (dotime(YEAR, eval(e->e.o.right)));
  913. X    case NOW:    return (dotime(NOW, (double)0.0));
  914. X    case DTS:    return (dodts((int)eval(e->e.o.left),
  915. X                 (int)eval(e->e.o.right->e.o.left),
  916. X                 (int)eval(e->e.o.right->e.o.right)));
  917. X    case TTS:    return (dotts((int)eval(e->e.o.left),
  918. X                 (int)eval(e->e.o.right->e.o.left),
  919. X                 (int)eval(e->e.o.right->e.o.right)));
  920. X    case STON:    return (doston(seval(e->e.o.right)));
  921. X    case EQS:       return (doeqs(seval(e->e.o.right),seval(e->e.o.left)));
  922. X    case LMAX:    return dolmax(e);
  923. X    case LMIN:    return dolmin(e);
  924. X    case NVAL:      return (donval(seval(e->e.o.left),eval(e->e.o.right)));
  925. X    case MYROW:    return ((double) gmyrow);
  926. X    case MYCOL:    return ((double) gmycol);
  927. X    case NUMITER:    return ((double) repct);
  928. X    default:    error ("Illegal numeric expression");
  929. X            exprerr = 1;
  930. X    }
  931. X    cellerror = CELLERROR;
  932. X    return((double)0.0);
  933. X}
  934. X
  935. XVOID_OR_INT eval_fpe() /* Trap for FPE errors in eval */
  936. X{
  937. X#if defined(i386) && !defined(M_XENIX)
  938. X    asm("    fnclex");
  939. X    asm("    fwait");
  940. X#else
  941. X#ifdef IEEE_MATH
  942. X    (void)fpsetsticky((fp_except)0);    /* Clear exception */
  943. X#endif /* IEEE_MATH */
  944. X#ifdef PC
  945. X    _fpreset();
  946. X#endif
  947. X#endif
  948. X    /* re-establish signal handler for next time */
  949. X    Signal(SIGFPE, eval_fpe);
  950. X    longjmp(fpe_save, 1);
  951. X}
  952. X
  953. Xdouble fn1_eval(fn, arg)
  954. Xdouble (*fn)();
  955. Xdouble arg;
  956. X{
  957. X    double res;
  958. X    errno = 0;
  959. X    res = (*fn)(arg);
  960. X    if(errno)
  961. X        cellerror = CELLERROR;
  962. X
  963. X    return res;
  964. X}
  965. X
  966. Xdouble fn2_eval(fn, arg1, arg2)
  967. Xdouble (*fn)();
  968. Xdouble arg1, arg2;
  969. X{
  970. X    double res;
  971. X    errno = 0;
  972. X    res = (*fn)(arg1, arg2);
  973. X    if(errno)
  974. X        cellerror = CELLERROR;
  975. X
  976. X    return res;
  977. X}
  978. X
  979. X/* 
  980. X * Rules for string functions:
  981. X * Take string arguments which they Free.
  982. X * All returned strings are assumed to be xalloced.
  983. X */
  984. X
  985. Xchar *
  986. Xdocat(s1, s2)
  987. Xregister char *s1, *s2;
  988. X{
  989. X    register char *p;
  990. X    char *arg1, *arg2;
  991. X
  992. X    if (!s1 && !s2)
  993. X    return((char *)0);
  994. X    arg1 = s1 ? s1 : "";
  995. X    arg2 = s2 ? s2 : "";
  996. X    p = Malloc((unsigned)(strlen(arg1)+strlen(arg2)+1));
  997. X    Strcpy(p, arg1);
  998. X    Strcat(p, arg2);
  999. X    if (s1)
  1000. X        Free(s1);
  1001. X    if (s2)
  1002. X        Free(s2);
  1003. X    return(p);
  1004. X}
  1005. X
  1006. Xchar *
  1007. Xdodate(tloc)
  1008. Xlong tloc;
  1009. X{
  1010. X    char *tp;
  1011. X    char *p;
  1012. X
  1013. X    tp = ctime(&tloc);
  1014. X    tp[24] = '\0';
  1015. X    p = Malloc((unsigned)25);
  1016. X    Strcpy(p, tp);
  1017. X    return(p);
  1018. X}
  1019. X
  1020. X
  1021. Xchar *
  1022. Xdofmt(fmtstr, v)
  1023. Xchar *fmtstr;
  1024. Xdouble v;
  1025. X{
  1026. X    char buff[FBUFLEN];
  1027. X    char *p;
  1028. X
  1029. X    if (!fmtstr)
  1030. X    return((char *)0);
  1031. X    Sprintf(buff, fmtstr, v);
  1032. X    p = Malloc((unsigned)(strlen(buff)+1));
  1033. X    Strcpy(p, buff);
  1034. X    Free(fmtstr);
  1035. X    return(p);
  1036. X}
  1037. X
  1038. X
  1039. X/*
  1040. X * Given a command name and a value, run the command with the given value and
  1041. X * read and return its first output line (only) as an allocated string, always
  1042. X * a copy of prevstr, which is set appropriately first unless external
  1043. X * functions are disabled, in which case the previous value is used.  The
  1044. X * handling of prevstr and freeing of command is tricky.  Returning an
  1045. X * allocated string in all cases, even if null, insures cell expressions are
  1046. X * written to files, etc.
  1047. X */
  1048. X
  1049. X#if defined(VMS) || defined(MSDOS)
  1050. Xchar *
  1051. Xdoext(command, value)
  1052. Xchar *command;
  1053. Xdouble value;
  1054. X{
  1055. X    error("Warning: External functions unavailable on VMS");
  1056. X    cellerror = CELLERROR;    /* not sure if this should be a cellerror */
  1057. X    if (command)
  1058. X    Free(command);
  1059. X    return (strcpy (Malloc((unsigned) 1), "\0"));
  1060. X}
  1061. X
  1062. X#else /* VMS */
  1063. X
  1064. Xchar *
  1065. Xdoext (command, value)
  1066. Xchar   *command;
  1067. Xdouble value;
  1068. X{
  1069. X    static char *prevstr = (char *)0;    /* previous result */
  1070. X    static unsigned    prevlen = 0;
  1071. X    char buff[FBUFLEN];        /* command line/return, not permanently alloc */
  1072. X    extern char *strchr();
  1073. X
  1074. X    if (!extfunc)    {
  1075. X    error ("Warning: external functions disabled; using %s value",
  1076. X        ((prevstr == NULL) || (*prevstr == '\0')) ?
  1077. X            "null" : "previous");
  1078. X
  1079. X    if (command) Free (command);
  1080. X    } else {
  1081. X    if ((! command) || (! *command)) {
  1082. X        error ("Warning: external function given null command name");
  1083. X        cellerror = CELLERROR;
  1084. X        if (command) Free (command);
  1085. X    } else {
  1086. X        FILE *pp;
  1087. X
  1088. X        Sprintf (buff, "%s %g", command, value); /* build cmd line */
  1089. X        Free (command);
  1090. X
  1091. X        error ("Running external function...");
  1092. X        Refresh();
  1093. X
  1094. X        if ((pp = popen (buff, "r")) == (FILE *) NULL) {    /* run it */
  1095. X        error ("Warning: running \"%s\" failed", buff);
  1096. X        cellerror = CELLERROR;
  1097. X        }
  1098. X        else {
  1099. X        if (fgets (buff, sizeof(buff)-1, pp) == NULL)    /* one line */
  1100. X            error ("Warning: external function returned nothing");
  1101. X        else {
  1102. X            char *cp;
  1103. X
  1104. X            error ("");                /* erase notice */
  1105. X            buff[sizeof(buff)-1] = '\0';
  1106. X
  1107. X            if (cp = strchr (buff, '\n'))    /* contains newline */
  1108. X            *cp = '\0';            /* end string there */
  1109. X
  1110. X            if (strlen(buff) + 1 > prevlen)
  1111. X            {    prevlen = strlen(buff) + 40;
  1112. X            prevstr = Realloc(prevstr, prevlen);
  1113. X            }
  1114. X            Strcpy (prevstr, buff);
  1115. X             /* save alloc'd copy */
  1116. X        }
  1117. X        (void) pclose (pp);
  1118. X
  1119. X        } /* else */
  1120. X    } /* else */
  1121. X    } /* else */
  1122. X    if (prevstr)
  1123. X    return (strcpy (Malloc ((unsigned) (strlen (prevstr) + 1)), prevstr));
  1124. X    else
  1125. X    return (strcpy(Malloc((unsigned)1), ""));
  1126. X}
  1127. X
  1128. X#endif /* VMS */
  1129. X
  1130. X
  1131. X/*
  1132. X * Given a string representing a column name and a value which is a column
  1133. X * number, return the selected cell's string value, if any.  Even if none,
  1134. X * still allocate and return a null string so the cell has a label value so
  1135. X * the expression is saved in a file, etc.
  1136. X */
  1137. X
  1138. Xchar *
  1139. Xdosval (colstr, rowdoub)
  1140. X    char *colstr;
  1141. X    double rowdoub;
  1142. X{
  1143. X    struct ent *ep;
  1144. X    char *llabel;
  1145. X
  1146. X    llabel = (ep = getent (colstr, rowdoub)) ? (ep -> label) : "";
  1147. X    return (strcpy (Malloc ((unsigned) (strlen (llabel) + 1)), llabel));
  1148. X}
  1149. X
  1150. X
  1151. X/*
  1152. X * Substring:  Note that v1 and v2 are one-based to users, but zero-based
  1153. X * when calling this routine.
  1154. X */
  1155. X
  1156. Xchar *
  1157. Xdosubstr(s, v1, v2)
  1158. Xchar *s;
  1159. Xregister int v1,v2;
  1160. X{
  1161. X    register char *s1, *s2;
  1162. X    char *p;
  1163. X
  1164. X    if (!s)
  1165. X    return((char *)0);
  1166. X
  1167. X    if (v2 >= strlen (s))        /* past end */
  1168. X    v2 =  strlen (s) - 1;        /* to end   */
  1169. X
  1170. X    if (v1 < 0 || v1 > v2) {        /* out of range, return null string */
  1171. X    Free(s);
  1172. X    p = Malloc((unsigned)1);
  1173. X    p[0] = '\0';
  1174. X    return(p);
  1175. X    }
  1176. X    s2 = p = Malloc((unsigned)(v2-v1+2));
  1177. X    s1 = &s[v1];
  1178. X    for(; v1 <= v2; s1++, s2++, v1++)
  1179. X    *s2 = *s1;
  1180. X    *s2 = '\0';
  1181. X    Free(s);
  1182. X    return(p);
  1183. X}
  1184. X
  1185. X/*
  1186. X * character casing: make upper case, make lower case
  1187. X */
  1188. X
  1189. Xchar *
  1190. Xdocase( acase, s)
  1191. Xint acase;
  1192. Xchar *s;
  1193. X{
  1194. X    char *p = s;
  1195. X
  1196. X    if (s == NULL)
  1197. X    return(NULL);
  1198. X
  1199. X    if( acase == UPPER ) {
  1200. X        while( *p != '\0' ) {
  1201. X           if( islower(*p) )
  1202. X        *p = toupper(*p);
  1203. X       p++;
  1204. X    }
  1205. X    }
  1206. X    else if ( acase == LOWER ) {
  1207. X    while( *p != '\0' ) {
  1208. X        if (isupper(*p))
  1209. X        *p = tolower(*p);
  1210. X        p++;
  1211. X    }
  1212. X    }
  1213. X    return (s);
  1214. X}
  1215. X
  1216. X/*
  1217. X * make proper capitals of every word in a string
  1218. X * if the string has mixed case we say the string is lower
  1219. X *    and we will upcase only first letters of words
  1220. X * if the string is all upper we will lower rest of words.
  1221. X */
  1222. X
  1223. Xchar *
  1224. Xdocapital( s )
  1225. Xchar *s;
  1226. X{
  1227. X    char *p;
  1228. X    int skip = 1;
  1229. X    int AllUpper = 1;
  1230. X
  1231. X    if (s == NULL)
  1232. X    return(NULL);
  1233. X    for( p = s; *p != '\0' && AllUpper != 0; p++ )
  1234. X    if( isalpha(*p) && islower(*p) )  AllUpper = 0;
  1235. X    for (p = s; *p != '\0'; p++) {
  1236. X    if (!isalnum(*p))
  1237. X        skip = 1;
  1238. X    else
  1239. X    if (skip == 1) {
  1240. X        skip = 0;
  1241. X        if (islower(*p))
  1242. X            *p = toupper(*p);
  1243. X    }
  1244. X    else    /* if the string was all upper before */
  1245. X        if (isupper(*p) && AllUpper != 0)
  1246. X        *p = tolower(*p);
  1247. X    }
  1248. X    return(s);
  1249. X}
  1250. X
  1251. Xchar *
  1252. Xseval(se)
  1253. Xregister struct enode *se;
  1254. X{
  1255. X    register char *p;
  1256. X
  1257. X    if (se == (struct enode *)0) return (char *)0;
  1258. X    switch (se->op) {
  1259. X    case O_SCONST: p = Malloc((unsigned)(strlen(se->e.s)+1));
  1260. X             Strcpy(p, se->e.s);
  1261. X             return(p);
  1262. X    case O_VAR:    {
  1263. X            struct ent *ep;
  1264. X            ep = se->e.v.vp;
  1265. X
  1266. X            if (!ep->label)
  1267. X                return((char *)0);
  1268. X            p = Malloc((unsigned)(strlen(ep->label)+1));
  1269. X            Strcpy(p, ep->label);
  1270. X            return(p);
  1271. X             }
  1272. X    case '#':    return(docat(seval(se->e.o.left), seval(se->e.o.right)));
  1273. X    case 'f':    return(seval(se->e.o.right));
  1274. X    case IF:
  1275. X    case '?':    return(eval(se->e.o.left) ? seval(se->e.o.right->e.o.left)
  1276. X                         : seval(se->e.o.right->e.o.right));
  1277. X    case DATE:   return(dodate((long)(eval(se->e.o.right))));
  1278. X    case FMT:    return(dofmt(seval(se->e.o.left), eval(se->e.o.right)));
  1279. X    case UPPER:  return(docase(UPPER, seval(se->e.o.right)));
  1280. X    case LOWER:  return(docase(LOWER, seval(se->e.o.right)));
  1281. X    case CAPITAL:return(docapital(seval(se->e.o.right)));
  1282. X     case STINDEX:
  1283. X         {    register r,c;
  1284. X         register maxr, maxc;
  1285. X         register minr, minc;
  1286. X         maxr = se->e.o.right->e.r.right.vp -> row;
  1287. X         maxc = se->e.o.right->e.r.right.vp -> col;
  1288. X         minr = se->e.o.right->e.r.left.vp -> row;
  1289. X         minc = se->e.o.right->e.r.left.vp -> col;
  1290. X         if (minr>maxr) r = maxr, maxr = minr, minr = r;
  1291. X         if (minc>maxc) c = maxc, maxc = minc, minc = c;
  1292. X             return dostindex(eval(se->e.o.left), minr, minc, maxr, maxc);
  1293. X        }
  1294. X    case EXT:    return(doext(seval(se->e.o.left), eval(se->e.o.right)));
  1295. X    case SVAL:   return(dosval(seval(se->e.o.left), eval(se->e.o.right)));
  1296. X    case SUBSTR: return(dosubstr(seval(se->e.o.left),
  1297. X                (int)eval(se->e.o.right->e.o.left) - 1,
  1298. X                (int)eval(se->e.o.right->e.o.right) - 1));
  1299. X    case COLTOA: return(strcpy(Malloc((unsigned)10),
  1300. X                   coltoa((int)eval(se->e.o.right)+1)));
  1301. X    default:
  1302. X             error ("Illegal string expression");
  1303. X             exprerr = 1;
  1304. X             return(NULL);
  1305. X    }
  1306. X}
  1307. X
  1308. X/*
  1309. X * The graph formed by cell expressions which use other cells's values is not
  1310. X * evaluated "bottom up".  The whole table is merely re-evaluated cell by cell,
  1311. X * top to bottom, left to right, in RealEvalAll().  Each cell's expression uses
  1312. X * constants in other cells.  However, RealEvalAll() notices when a cell gets a
  1313. X * new numeric or string value, and reports if this happens for any cell.
  1314. X * EvalAll() repeats calling RealEvalAll() until there are no changes or the
  1315. X * evaluation count expires.
  1316. X */
  1317. X
  1318. Xint propagation = 10;    /* max number of times to try calculation */
  1319. X
  1320. Xvoid
  1321. Xsetiterations(i)
  1322. Xint i;
  1323. X{
  1324. X    if(i<1) {
  1325. X        error("iteration count must be at least 1");
  1326. X        propagation = 1;
  1327. X        }
  1328. X    else propagation = i;
  1329. X}
  1330. X
  1331. Xvoid
  1332. XEvalAll () {
  1333. X     int lastcnt;
  1334. X  
  1335. X     repct = 1;
  1336. X     Signal(SIGFPE, eval_fpe);
  1337. X
  1338. X     while ((lastcnt = RealEvalAll()) && (++repct <= propagation));
  1339. X     if((propagation>1)&& (lastcnt >0 ))
  1340. X         error("Still changing after %d iterations",propagation-1);
  1341. X
  1342. X    Signal(SIGFPE, doquit);
  1343. X}
  1344. X
  1345. X/*
  1346. X * Evaluate all cells which have expressions and alter their numeric or string
  1347. X * values.  Return the number of cells which changed.
  1348. X */
  1349. X
  1350. Xint 
  1351. XRealEvalAll () {
  1352. X    register int i,j;
  1353. X    int chgct = 0;
  1354. X    register struct ent *p;
  1355. X
  1356. X    if(calc_order == BYROWS ) {
  1357. X    for (i=0; i<=maxrow; i++)
  1358. X        for (j=0; j<=maxcol; j++)
  1359. X        if ((p = *ATBL(tbl,i,j)) && !(p->flags&is_locked) && p->expr) RealEvalOne(p,i,j,&chgct);
  1360. X    }
  1361. X    else if ( calc_order == BYCOLS ) {
  1362. X    for (j=0; j<=maxcol; j++)
  1363. X    {   for (i=0; i<=maxrow; i++)
  1364. X        if ((p = *ATBL(tbl,i,j)) && !(p->flags&is_locked) && p->expr) RealEvalOne(p,i,j,&chgct);
  1365. X    }
  1366. X    }
  1367. X    else error("Internal error calc_order");
  1368. X    return(chgct);
  1369. X}
  1370. X
  1371. Xvoid
  1372. XRealEvalOne(p, i, j, chgct)
  1373. Xregister struct ent *p;
  1374. Xint i, j, *chgct;
  1375. X{
  1376. X    if (p->flags & is_strexpr) {
  1377. X        char *v;
  1378. X        if (setjmp(fpe_save)) {
  1379. X        error("Floating point exception %s", v_name(i, j));
  1380. X        cellerror = CELLERROR;
  1381. X        v = "";
  1382. X        } else {
  1383. X        cellerror = CELLOK;
  1384. X        v = seval(p->expr);
  1385. X        }
  1386. X        p->cellerror = cellerror;
  1387. X        if (!v && !p->label) /* Everything's fine */
  1388. X        return;
  1389. X        if (!p->label || !v || strcmp(v, p->label) != 0 || cellerror) {
  1390. X        (*chgct)++;
  1391. X        p->flags |= is_changed;
  1392. X        changed++;
  1393. X        }
  1394. X        if(p->label)
  1395. X        Free(p->label);
  1396. X        p->label = v;
  1397. X    } else {
  1398. X        double v;
  1399. X        if (setjmp(fpe_save)) {
  1400. X        error("Floating point exception %s", v_name(i, j));
  1401. X        cellerror = CELLERROR;
  1402. X        v = (double)0.0;
  1403. X        } else {
  1404. X        cellerror = CELLOK;
  1405. X        gmyrow=i; gmycol=j;
  1406. X        v = eval (p->expr);
  1407. X        }
  1408. X        if ((p->cellerror = cellerror) || (v != p->v)) {
  1409. X        p->v = v;
  1410. X        if (!cellerror)        /* don't keep eval'ing a error */
  1411. X            (*chgct)++;
  1412. X        p->flags |= is_changed|is_valid;
  1413. X        changed++;
  1414. X        }
  1415. X    }
  1416. X}
  1417. X
  1418. Xstruct enode *
  1419. Xnew(op, a1, a2)
  1420. Xint    op;
  1421. Xstruct enode *a1, *a2;
  1422. X{
  1423. X    register struct enode *p;
  1424. X    if (freeenodes)
  1425. X    {    p = freeenodes;
  1426. X    freeenodes = p->e.o.left;
  1427. X    }
  1428. X    else
  1429. X    p = (struct enode *) Malloc ((unsigned)sizeof (struct enode));
  1430. X    p->op = op;
  1431. X    p->e.o.left = a1;
  1432. X    p->e.o.right = a2;
  1433. X    return p;
  1434. X}
  1435. X
  1436. Xstruct enode *
  1437. Xnew_var(op, a1)
  1438. Xint    op;
  1439. Xstruct ent_ptr a1;
  1440. X{
  1441. X    register struct enode *p;
  1442. X    if (freeenodes)
  1443. X    {    p = freeenodes;
  1444. X    freeenodes = p->e.o.left;
  1445. X    }
  1446. X    else
  1447. X    p = (struct enode *) Malloc ((unsigned)sizeof (struct enode));
  1448. X    p->op = op;
  1449. X    p->e.v = a1;
  1450. X    return p;
  1451. X}
  1452. X
  1453. Xstruct enode *
  1454. Xnew_range(op, a1)
  1455. Xint    op;
  1456. Xstruct range_s a1;
  1457. X{
  1458. X    register struct enode *p;
  1459. X    if (freeenodes)
  1460. X    {    p = freeenodes;
  1461. X    freeenodes = p->e.o.left;
  1462. X    }
  1463. X    else
  1464. X    p = (struct enode *) Malloc ((unsigned)sizeof (struct enode));
  1465. X    p->op = op;
  1466. X    p->e.r = a1;
  1467. X    return p;
  1468. X}
  1469. X
  1470. Xstruct enode *
  1471. Xnew_const(op, a1)
  1472. Xint    op;
  1473. Xdouble a1;
  1474. X{
  1475. X    register struct enode *p;
  1476. X    if (freeenodes)    /* reuse an already free'd enode */
  1477. X    {    p = freeenodes;
  1478. X    freeenodes = p->e.o.left;
  1479. X    }
  1480. X    else
  1481. X    p = (struct enode *) Malloc ((unsigned)sizeof (struct enode));
  1482. X    p->op = op;
  1483. X    p->e.k = a1;
  1484. X    return p;
  1485. X}
  1486. X
  1487. Xstruct enode *
  1488. Xnew_str(s)
  1489. Xchar *s;
  1490. X{
  1491. X    register struct enode *p;
  1492. X
  1493. X    if (freeenodes)    /* reuse an already free'd enode */
  1494. X    {    p = freeenodes;
  1495. X    freeenodes = p->e.o.left;
  1496. X    }
  1497. X    else
  1498. X    p = (struct enode *) Malloc ((unsigned)sizeof(struct enode));
  1499. X    p->op = O_SCONST;
  1500. X    p->e.s = s;
  1501. X    return(p);
  1502. X}
  1503. X
  1504. Xvoid
  1505. Xcopy(dv1, dv2, v1, v2)
  1506. Xstruct ent *dv1, *dv2, *v1, *v2;
  1507. X{
  1508. X    int minsr, minsc;
  1509. X    int maxsr, maxsc;
  1510. X    int mindr, mindc;
  1511. X    int maxdr, maxdc;
  1512. X    int vr, vc;
  1513. X    int r, c;
  1514. X
  1515. X    mindr = dv1->row;
  1516. X    mindc = dv1->col;
  1517. X    maxdr = dv2->row;
  1518. X    maxdc = dv2->col;
  1519. X    if (mindr>maxdr) r = maxdr, maxdr = mindr, mindr = r;
  1520. X    if (mindc>maxdc) c = maxdc, maxdc = mindc, mindc = c;
  1521. X    maxsr = v2->row;
  1522. X    maxsc = v2->col;
  1523. X    minsr = v1->row;
  1524. X    minsc = v1->col;
  1525. X    if (minsr>maxsr) r = maxsr, maxsr = minsr, minsr = r;
  1526. X    if (minsc>maxsc) c = maxsc, maxsc = minsc, minsc = c;
  1527. X    checkbounds(&maxdr, &maxdc);
  1528. X
  1529. X    erase_area(mindr, mindc, maxdr, maxdc);
  1530. X    if (minsr == maxsr && minsc == maxsc) {
  1531. X    /* Source is a single cell */
  1532. X    for(vr = mindr; vr <= maxdr; vr++)
  1533. X        for (vc = mindc; vc <= maxdc; vc++)
  1534. X        copyrtv(vr, vc, minsr, minsc, maxsr, maxsc);
  1535. X    } else if (minsr == maxsr) {
  1536. X    /* Source is a single row */
  1537. X    for (vr = mindr; vr <= maxdr; vr++)
  1538. X        copyrtv(vr, mindc, minsr, minsc, maxsr, maxsc);
  1539. X    } else if (minsc == maxsc) {
  1540. X    /* Source is a single column */
  1541. X    for (vc = mindc; vc <= maxdc; vc++)
  1542. X        copyrtv(mindr, vc, minsr, minsc, maxsr, maxsc);
  1543. X    } else {
  1544. X    /* Everything else */
  1545. X    copyrtv(mindr, mindc, minsr, minsc, maxsr, maxsc);
  1546. X    }
  1547. X    sync_refs();
  1548. X}
  1549. X
  1550. Xvoid
  1551. Xcopyrtv(vr, vc, minsr, minsc, maxsr, maxsc)
  1552. Xint vr, vc, minsr, minsc, maxsr, maxsc;
  1553. X{
  1554. X    register struct ent *p;
  1555. X    register struct ent *n;
  1556. X    register int sr, sc;
  1557. X    register int dr, dc;
  1558. X
  1559. X    for (dr=vr, sr=minsr; sr<=maxsr; sr++, dr++)
  1560. X    for (dc=vc, sc=minsc; sc<=maxsc; sc++, dc++) {
  1561. X        if (p = *ATBL(tbl, sr, sc))
  1562. X        {    n = lookat (dr, dc);
  1563. X        if (n->flags&is_locked) continue;
  1564. X        clearent(n);
  1565. X        copyent( n, p, dr - sr, dc - sc);
  1566. X        }
  1567. X        else
  1568. X        if (n = *ATBL(tbl, dr, dc))
  1569. X        clearent(n);
  1570. X    }
  1571. X}
  1572. X
  1573. X/* ERASE a Range of cells */
  1574. Xvoid
  1575. Xeraser(v1, v2)
  1576. Xstruct ent *v1, *v2;
  1577. X{
  1578. X    FullUpdate++;
  1579. X    flush_saved();
  1580. X    erase_area(v1->row, v1->col, v2->row, v2->col);
  1581. X    sync_refs();
  1582. X}
  1583. X
  1584. X/* Goto subroutines */
  1585. X
  1586. Xvoid
  1587. Xg_free()
  1588. X{
  1589. X    switch (gs.g_type) {
  1590. X    case G_STR: Free(gs.g_s); break;
  1591. X    default: break;
  1592. X    }
  1593. X    gs.g_type = G_NONE;
  1594. X    gs.errsearch = 0;
  1595. X}
  1596. X
  1597. X/* repeat the last goto command */
  1598. Xvoid
  1599. Xgo_last()
  1600. X{
  1601. X    switch (gs.g_type) {
  1602. X    case G_NONE:
  1603. X        error("Nothing to repeat"); break;
  1604. X    case G_NUM:
  1605. X        num_search(gs.g_n, gs.errsearch);
  1606. X        break;
  1607. X    case  G_CELL:
  1608. X        moveto(gs.g_row, gs.g_col);
  1609. X            break;
  1610. X    case  G_STR: 
  1611. X        gs.g_type = G_NONE;    /* Don't free the string */
  1612. X               str_search(gs.g_s); 
  1613. X           break;
  1614. X
  1615. X    default: error("go_last: internal error");
  1616. X    }
  1617. X}
  1618. X
  1619. X/* place the cursor on a given cell */
  1620. Xvoid
  1621. Xmoveto(row, col)
  1622. Xint row, col;
  1623. X{
  1624. X    currow = row;
  1625. X    curcol = col;
  1626. X    g_free();
  1627. X    gs.g_type = G_CELL;
  1628. X    gs.g_row = currow;
  1629. X    gs.g_col = curcol;
  1630. X}
  1631. X
  1632. X/*
  1633. X * 'goto' either a given number,'error', or 'invalid' starting at currow,curcol
  1634. X */
  1635. Xvoid
  1636. Xnum_search(n, errsearch)
  1637. Xdouble n;
  1638. Xint    errsearch;
  1639. X{
  1640. X    register struct ent *p;
  1641. X    register int r,c;
  1642. X    int    endr, endc;
  1643. X
  1644. X    g_free();
  1645. X    gs.g_type = G_NUM;
  1646. X    gs.g_n = n;
  1647. X    gs.errsearch = errsearch;
  1648. X
  1649. X    if (currow > maxrow)
  1650. X    endr = maxrow ? maxrow-1 : 0;
  1651. X    else
  1652. X    endr = currow;
  1653. X    if (curcol > maxcol)
  1654. X    endc = maxcol ? maxcol-1 : 0;
  1655. X    else
  1656. X    endc = curcol;
  1657. X    r = endr;
  1658. X    c = endc;
  1659. X    do {
  1660. X    if (c < maxcol)
  1661. X        c++;
  1662. X    else {
  1663. X        if (r < maxrow) {
  1664. X        while(++r < maxrow && row_hidden[r]) /* */;
  1665. X        c = 0;
  1666. X        } else {
  1667. X        r = 0;
  1668. X        c = 0;
  1669. X        }
  1670. X    }
  1671. X    if (r == endr && c == endc) {
  1672. X        if (errsearch)
  1673. X        error("no %s cell found", errsearch == CELLERROR ? "ERROR" :
  1674. X              "INVALID");
  1675. X        else
  1676. X        error("Number not found");
  1677. X        return;
  1678. X    }
  1679. X    p = *ATBL(tbl, r, c);
  1680. X    } while (col_hidden[c] || !p || !(p->flags & is_valid)
  1681. X    || (!errsearch && (p->v != n))
  1682. X    || (errsearch && !((p->cellerror == errsearch) ||
  1683. X        (p->cellerror == errsearch))));    /* CELLERROR vs CELLINVALID */
  1684. X        
  1685. X    currow = r;
  1686. X    curcol = c;
  1687. X}
  1688. X
  1689. X/* 'goto' a cell containing a matching string */
  1690. Xvoid
  1691. Xstr_search(s)
  1692. Xchar *s;
  1693. X{
  1694. X    register struct ent *p;
  1695. X    register int r,c;
  1696. X    int    endr, endc;
  1697. X    char *tmp;
  1698. X
  1699. X#if defined(RE_COMP)
  1700. X    if ((tmp = re_comp(s)) != (char *)0) {
  1701. X    Free(s);
  1702. X    error(tmp);
  1703. X    return;
  1704. X    }
  1705. X#endif
  1706. X#if defined(REGCMP)
  1707. X    if ((tmp = regcmp(s, (char *)0)) == (char *)0) {
  1708. X    Free(s);
  1709. X    cellerror = CELLERROR;
  1710. X    error("Invalid search string");
  1711. X    return;
  1712. X    }
  1713. X#endif
  1714. X    g_free();
  1715. X    gs.g_type = G_STR;
  1716. X    gs.g_s = s;
  1717. X    if (currow > maxrow)
  1718. X    endr = maxrow ? maxrow-1 : 0;
  1719. X    else
  1720. X    endr = currow;
  1721. X    if (curcol > maxcol)
  1722. X    endc = maxcol ? maxcol-1 : 0;
  1723. X    else
  1724. X    endc = curcol;
  1725. X    r = endr;
  1726. X    c = endc;
  1727. X    do {
  1728. X    if (c < maxcol)
  1729. X        c++;
  1730. X    else {
  1731. X        if (r < maxrow) {
  1732. X        while(++r < maxrow && row_hidden[r]) /* */;
  1733. X        c = 0;
  1734. X        } else {
  1735. X        r = 0;
  1736. X        c = 0;
  1737. X        }
  1738. X    }
  1739. X    if (r == endr && c == endc) {
  1740. X        error("String not found");
  1741. X#if defined(REGCMP)
  1742. X        free(tmp);
  1743. X#endif
  1744. X        return;
  1745. X    }
  1746. X    p = *ATBL(tbl, r, c);
  1747. X    } while(col_hidden[c] || !p || !(p->label)
  1748. X#if defined(RE_COMP)
  1749. X                      || (re_exec(p->label) == 0));
  1750. X#else
  1751. X#if defined(REGCMP)
  1752. X                || (regex(tmp, p->label) == (char *)0));
  1753. X#else
  1754. X                    || (strcmp(s, p->label) != 0));
  1755. X#endif
  1756. X#endif
  1757. X    currow = r;
  1758. X    curcol = c;
  1759. X#if defined(REGCMP)
  1760. X    free(tmp);
  1761. X#endif
  1762. X}
  1763. X
  1764. X/* fill a range with constants */
  1765. Xvoid
  1766. Xfill (v1, v2, start, inc)
  1767. Xstruct ent *v1, *v2;
  1768. Xdouble start, inc;
  1769. X{
  1770. X    register r,c;
  1771. X    register struct ent *n;
  1772. X    int maxr, maxc;
  1773. X    int minr, minc;
  1774. X
  1775. X    maxr = v2->row;
  1776. X    maxc = v2->col;
  1777. X    minr = v1->row;
  1778. X    minc = v1->col;
  1779. X    if (minr>maxr) r = maxr, maxr = minr, minr = r;
  1780. X    if (minc>maxc) c = maxc, maxc = minc, minc = c;
  1781. X    checkbounds(&maxr, &maxc);
  1782. X    if (minr < 0) minr = 0;
  1783. X    if (minc < 0) minc = 0;
  1784. X
  1785. X    FullUpdate++;
  1786. X    if( calc_order == BYROWS ) {
  1787. X    for (r = minr; r<=maxr; r++)
  1788. X    for (c = minc; c<=maxc; c++) {
  1789. X        n = lookat (r, c);
  1790. X        if (n->flags&is_locked) continue;
  1791. X        clearent(n);
  1792. X        n->v = start;
  1793. X        start += inc;
  1794. X        n->flags |= (is_changed|is_valid);
  1795. X    }
  1796. X    }
  1797. X    else if ( calc_order == BYCOLS ) {
  1798. X    for (c = minc; c<=maxc; c++)
  1799. X    for (r = minr; r<=maxr; r++) {
  1800. X        n = lookat (r, c);
  1801. X        clearent(n);
  1802. X        n->v = start;
  1803. X        start += inc;
  1804. X        n->flags |= (is_changed|is_valid);
  1805. X    }
  1806. X    }
  1807. X    else error(" Internal error calc_order");
  1808. X    changed++;
  1809. X}
  1810. X
  1811. X/* lock a range of cells */
  1812. X
  1813. Xvoid
  1814. Xlock_cells (v1, v2)
  1815. Xstruct ent *v1, *v2;
  1816. X{
  1817. X    register r,c;
  1818. X    register struct ent *n;
  1819. X    int maxr, maxc;
  1820. X    int minr, minc;
  1821. X
  1822. X    maxr = v2->row;
  1823. X    maxc = v2->col;
  1824. X    minr = v1->row;
  1825. X    minc = v1->col;
  1826. X    if (minr>maxr) r = maxr, maxr = minr, minr = r;
  1827. X    if (minc>maxc) c = maxc, maxc = minc, minc = c;
  1828. X    checkbounds(&maxr, &maxc);
  1829. X    if (minr < 0) minr = 0;
  1830. X    if (minc < 0) minc = 0;
  1831. X
  1832. X    for (r = minr; r<=maxr; r++)
  1833. X    for (c = minc; c<=maxc; c++) {
  1834. X        n = lookat (r, c);
  1835. X        n->flags |= is_locked;
  1836. X    }
  1837. X}
  1838. X
  1839. X/* unlock a range of cells */
  1840. X
  1841. Xvoid
  1842. Xunlock_cells (v1, v2)
  1843. Xstruct ent *v1, *v2;
  1844. X{
  1845. X    register r,c;
  1846. X    register struct ent *n;
  1847. X    int maxr, maxc;
  1848. X    int minr, minc;
  1849. X
  1850. X    maxr = v2->row;
  1851. X    maxc = v2->col;
  1852. X    minr = v1->row;
  1853. X    minc = v1->col;
  1854. X    if (minr>maxr) r = maxr, maxr = minr, minr = r;
  1855. X    if (minc>maxc) c = maxc, maxc = minc, minc = c;
  1856. X    checkbounds(&maxr, &maxc);
  1857. X    if (minr < 0) minr = 0;
  1858. X    if (minc < 0) minc = 0;
  1859. X
  1860. X    for (r = minr; r<=maxr; r++)
  1861. X    for (c = minc; c<=maxc; c++) {
  1862. X        n = lookat (r, c);
  1863. X        n->flags &= ~is_locked;
  1864. X    }
  1865. X}
  1866. X
  1867. X/* set the numeric part of a cell */
  1868. Xvoid
  1869. Xlet (v, e)
  1870. Xstruct ent *v;
  1871. Xstruct enode *e;
  1872. X{
  1873. X    double val;
  1874. X    unsigned isconstant = constant(e);
  1875. X
  1876. X    if (loading && !isconstant)
  1877. X    val = (double)0.0;
  1878. X    else
  1879. X    {
  1880. X    exprerr = 0;
  1881. X    Signal(SIGFPE, eval_fpe);
  1882. X    if (setjmp(fpe_save)) {
  1883. X        error ("Floating point exception in cell %s", v_name(v->row, v->col));
  1884. X        val = (double)0.0;
  1885. X        cellerror = CELLERROR;
  1886. X    } else {
  1887. X        cellerror = CELLOK;
  1888. X        val = eval(e);
  1889. X    }
  1890. X    if (v->cellerror != cellerror)
  1891. X    {    v->flags |= is_changed;
  1892. X        changed++;    modflg++;
  1893. X        FullUpdate++;
  1894. X        v->cellerror = cellerror;
  1895. X    }
  1896. X    Signal(SIGFPE, doquit);
  1897. X    if (exprerr) {
  1898. X        efree(e);
  1899. X        return;
  1900. X    }
  1901. X    }
  1902. X
  1903. X    if (isconstant) {
  1904. X    /* prescale input unless it has a decimal */
  1905. X#if defined(IEEE_MATH) && !defined(NO_FMOD)
  1906. X    if (!loading && (prescale < (double)0.9999999) &&
  1907. X                (fmod(val, (double)1.0) == (double)0))
  1908. X#else
  1909. X    if (!loading && (prescale < (double)0.9999999) &&
  1910. X            ((val - floor(val)) == (double)0))
  1911. X#endif
  1912. X        val *= prescale;
  1913. X
  1914. X    v->v = val;
  1915. X
  1916. X    if (!(v->flags & is_strexpr)) {
  1917. X            efree(v->expr);
  1918. X        v->expr = (struct enode *)0;
  1919. X    }
  1920. X    efree(e);
  1921. X    }
  1922. X    else
  1923. X    {
  1924. X    efree(v->expr);
  1925. X    v->expr = e;
  1926. X    v->flags &= ~is_strexpr;
  1927. X    }
  1928. X
  1929. X    changed++; modflg++;
  1930. X    v->flags |= (is_changed|is_valid);
  1931. X}
  1932. X
  1933. Xvoid
  1934. Xslet (v, se, flushdir)
  1935. Xstruct ent *v;
  1936. Xstruct enode *se;
  1937. Xint flushdir;
  1938. X{
  1939. X    char *p;
  1940. X
  1941. X    exprerr = 0;
  1942. X    Signal(SIGFPE, eval_fpe);
  1943. X    if (setjmp(fpe_save)) {
  1944. X    error ("Floating point exception in cell %s", v_name(v->row, v->col));
  1945. X    cellerror = CELLERROR;
  1946. X    p = "";
  1947. X    } else {
  1948. X    cellerror = CELLOK;
  1949. X    p = seval(se);
  1950. X    }
  1951. X    if (v->cellerror != cellerror)
  1952. X    {    v->flags |= is_changed;
  1953. X    changed++;    modflg++;
  1954. X    FullUpdate++;
  1955. X    v->cellerror = cellerror;
  1956. X    }
  1957. X    Signal(SIGFPE, doquit);
  1958. X    if (exprerr) {
  1959. X    efree(se);
  1960. X    return;
  1961. X    }
  1962. X    if (constant(se)) {
  1963. X    label(v, p, flushdir);
  1964. X    if (p)
  1965. X        Free(p);
  1966. X    efree(se);
  1967. X    if (v->flags & is_strexpr) {
  1968. X            efree(v->expr);
  1969. X        v->expr = (struct enode *)0;
  1970. X        v->flags &= ~is_strexpr;
  1971. X    }
  1972. X    return;
  1973. X    }
  1974. X    efree(v->expr);
  1975. X    v->expr = se;
  1976. X    v->flags |= (is_changed|is_strexpr);
  1977. X    if (flushdir<0) v->flags |= is_leftflush;
  1978. X
  1979. X    if (flushdir==0)
  1980. X    v->flags |= is_label;
  1981. X    else v->flags &= ~is_label;
  1982. X
  1983. X    FullUpdate++;
  1984. X    changed++;
  1985. X    modflg++;
  1986. X}
  1987. X
  1988. Xvoid
  1989. Xformat_cell(v1, v2, s)
  1990. Xstruct ent *v1, *v2;
  1991. Xchar *s;
  1992. X{
  1993. X    register r,c;
  1994. X    register struct ent *n;
  1995. X    int maxr, maxc;
  1996. X    int minr, minc;
  1997. X
  1998. X    maxr = v2->row;
  1999. X    maxc = v2->col;
  2000. X    minr = v1->row;
  2001. X    minc = v1->col;
  2002. X    if (minr>maxr) r = maxr, maxr = minr, minr = r;
  2003. X    if (minc>maxc) c = maxc, maxc = minc, minc = c;
  2004. X    checkbounds(&maxr, &maxc);
  2005. X    if (minr < 0) minr = 0;
  2006. X    if (minc < 0) minc = 0;
  2007. X
  2008. X    FullUpdate++;
  2009. X    modflg++;
  2010. X    for (r = minr; r <= maxr; r++)
  2011. X    for (c = minc; c <= maxc; c++) {
  2012. X        n = lookat (r, c);
  2013. X        if (n->flags&is_locked) {
  2014. X        error("Cell %s%d is locked", coltoa(n->col), n->row);
  2015. X        continue;
  2016. X        }
  2017. X        if (n->format)
  2018. X        Free(n->format);
  2019. X        n->format = 0;
  2020. X        if (s && *s != '\0')
  2021. X        n->format = strcpy(Malloc((unsigned)(strlen(s)+1)), s);
  2022. X        n->flags |= is_changed;
  2023. X       }
  2024. X}
  2025. X
  2026. Xvoid
  2027. Xhide_row(arg)
  2028. Xint arg;
  2029. X{
  2030. X    if (arg < 0) {
  2031. X    error("Invalid Range");
  2032. X    return;
  2033. X    }
  2034. X    if (arg >= maxrows-1)
  2035. X    {
  2036. X    if (!growtbl(GROWROW, arg+1, 0))
  2037. X    {    error("You can't hide the last row");
  2038. X        return;
  2039. X    }
  2040. X    }
  2041. X    FullUpdate++;
  2042. X    row_hidden[arg] = 1;
  2043. X}
  2044. X
  2045. Xvoid
  2046. Xhide_col(arg)
  2047. Xint arg;
  2048. X{
  2049. X    if (arg < 0) {
  2050. X    error("Invalid Range");
  2051. X    return;
  2052. X    }
  2053. X    if (arg >= maxcols-1)
  2054. X    {    if ((arg >= ABSMAXCOLS-1) || !growtbl(GROWCOL, 0, arg+1))
  2055. X    {    error("You can't hide the last col");
  2056. X        return;
  2057. X    }
  2058. X    }
  2059. X    FullUpdate++;
  2060. X    col_hidden[arg] = TRUE;
  2061. X}
  2062. X
  2063. Xvoid
  2064. Xclearent (v)
  2065. Xstruct ent *v;
  2066. X{
  2067. X    if (!v)
  2068. X    return;
  2069. X    label(v,"",-1);
  2070. X    v->v = (double)0;
  2071. X    if (v->expr)
  2072. X    efree(v->expr);
  2073. X    v->expr = (struct enode *)0;
  2074. X    if (v->format)
  2075. X    Free(v->format);
  2076. X    v->format = (char *)0;
  2077. X    v->flags |= (is_changed);
  2078. X    v->flags &= ~(is_valid);
  2079. X    changed++;
  2080. X    modflg++;
  2081. X}
  2082. X
  2083. X/*
  2084. X * Say if an expression is a constant (return 1) or not.
  2085. X */
  2086. Xint
  2087. Xconstant (e)
  2088. X    register struct enode *e;
  2089. X{
  2090. X    return (
  2091. X     e == (struct enode *)0
  2092. X     || e -> op == O_CONST
  2093. X     || e -> op == O_SCONST
  2094. X     || (
  2095. X         e -> op != O_VAR
  2096. X         && (e -> op & REDUCE) != REDUCE
  2097. X         && constant (e -> e.o.left)
  2098. X         && constant (e -> e.o.right)
  2099. X         && e -> op != EXT     /* functions look like constants but aren't */
  2100. X         && e -> op != NVAL
  2101. X         && e -> op != SVAL
  2102. X         && e -> op != NOW
  2103. X         && e -> op != MYROW
  2104. X         && e -> op != MYCOL
  2105. X         && e -> op != NUMITER
  2106. X    )
  2107. X    );
  2108. X}
  2109. X
  2110. Xvoid
  2111. Xefree (e)
  2112. Xstruct enode *e;
  2113. X{
  2114. X    if (e) {
  2115. X    if (e->op != O_VAR && e->op !=O_CONST && e->op != O_SCONST
  2116. X        && (e->op & REDUCE) != REDUCE) {
  2117. X        efree(e->e.o.left);
  2118. X        efree(e->e.o.right);
  2119. X    }
  2120. X    if (e->op == O_SCONST && e->e.s)
  2121. X        Free(e->e.s);
  2122. X    e->e.o.left = freeenodes;
  2123. X    freeenodes = e;
  2124. X    }
  2125. X}
  2126. X
  2127. Xvoid
  2128. Xlabel (v, s, flushdir)
  2129. Xregister struct ent *v;
  2130. Xregister char *s;
  2131. Xint    flushdir;
  2132. X{
  2133. X    if (v) {
  2134. X    if (flushdir==0 && v->flags&is_valid) {
  2135. X        register struct ent *tv;
  2136. X        if (v->col>0 && ((tv=lookat(v->row,v->col-1))->flags&is_valid)==0)
  2137. X        v = tv, flushdir = 1;
  2138. X        else if (((tv=lookat (v->row,v->col+1))->flags&is_valid)==0)
  2139. X        v = tv, flushdir = -1;
  2140. X        else flushdir = -1;
  2141. X    }
  2142. X    if (v->label) Free((char *)(v->label));
  2143. X    if (s && s[0]) {
  2144. X        v->label = Malloc ((unsigned)(strlen(s)+1));
  2145. X        Strcpy (v->label, s);
  2146. X    } else
  2147. X        v->label = (char *)0;
  2148. X    if (flushdir<0) v->flags |= is_leftflush;
  2149. X    else v->flags &= ~is_leftflush;
  2150. X    if (flushdir==0) v->flags |= is_label;
  2151. X    else v->flags &= ~is_label;
  2152. X    FullUpdate++;
  2153. X    modflg++;
  2154. X    }
  2155. X}
  2156. X
  2157. Xvoid
  2158. Xdecodev (v)
  2159. Xstruct ent_ptr v; 
  2160. X{
  2161. X    register struct range *r;
  2162. X
  2163. X    if (!v.vp) Sprintf (line+linelim,"VAR?");
  2164. X    else if ((r = find_range((char *)0, 0, v.vp, v.vp)) && !r->r_is_range)
  2165. X        Sprintf(line+linelim, "%s", r->r_name);
  2166. X    else
  2167. X        Sprintf (line+linelim, "%s%s%s%d",
  2168. X            v.vf & FIX_COL ? "$" : "",
  2169. X            coltoa(v.vp->col),
  2170. X            v.vf & FIX_ROW ? "$" : "",
  2171. X            v.vp->row);
  2172. X    linelim += strlen (line+linelim);
  2173. X}
  2174. X
  2175. Xchar *
  2176. Xcoltoa(col)
  2177. Xint col;
  2178. X{
  2179. X    static char rname[3];
  2180. X    register char *p = rname;
  2181. X
  2182. X    if (col > 25) {
  2183. X    *p++ = col/26 + 'A' - 1;
  2184. X    col %= 26;
  2185. X    }
  2186. X    *p++ = col+'A';
  2187. X    *p = '\0';
  2188. X    return(rname);
  2189. X}
  2190. X
  2191. X/*
  2192. X *    To make list elements come out in the same order
  2193. X *    they were entered, we must do a depth-first eval
  2194. X *    of the ELIST tree
  2195. X */
  2196. Xstatic void
  2197. Xdecompile_list(p)
  2198. Xstruct enode *p;
  2199. X{
  2200. X    if (!p) return;
  2201. X    decompile_list(p->e.o.left);    /* depth first */
  2202. X        decompile(p->e.o.right, 0);
  2203. X    line[linelim++] = ',';
  2204. X}
  2205. X
  2206. Xvoid
  2207. Xdecompile(e, priority)
  2208. Xregister struct enode *e;
  2209. Xint    priority;
  2210. X{
  2211. X    register char *s;
  2212. X    if (e) {
  2213. X    int mypriority;
  2214. X    switch (e->op) {
  2215. X    default: mypriority = 99; break;
  2216. X    case '?': mypriority = 1; break;
  2217. X    case ':': mypriority = 2; break;
  2218. X    case '|': mypriority = 3; break;
  2219. X    case '&': mypriority = 4; break;
  2220. X    case '<': case '=': case '>': mypriority = 6; break;
  2221. X    case '+': case '-': case '#': mypriority = 8; break;
  2222. X    case '*': case '/': case '%': mypriority = 10; break;
  2223. X    case '^': mypriority = 12; break;
  2224. X    }
  2225. X    if (mypriority<priority) line[linelim++] = '(';
  2226. X    switch (e->op) {
  2227. X    case 'f':    for (s="fixed "; line[linelim++] = *s++;);
  2228. X            linelim--;
  2229. X            decompile (e->e.o.right, 30);
  2230. X            break;
  2231. X    case 'm':    line[linelim++] = '-';
  2232. X            decompile (e->e.o.right, 30);
  2233. X            break;
  2234. X    case '~':    line[linelim++] = '~';
  2235. X            decompile (e->e.o.right, 30);
  2236. X            break;
  2237. X    case O_VAR:    decodev (e->e.v);
  2238. X            break;
  2239. X    case O_CONST:    Sprintf (line+linelim,"%.15g",e->e.k);
  2240. X            linelim += strlen (line+linelim);
  2241. X            break;
  2242. X    case O_SCONST:    Sprintf (line+linelim, "\"%s\"", e->e.s);
  2243. X            linelim += strlen(line+linelim);
  2244. X            break;
  2245. X
  2246. X    case REDUCE | '+': range_arg( "@sum(", e); break;
  2247. X    case REDUCE | '*': range_arg( "@prod(", e); break;
  2248. X    case REDUCE | 'a': range_arg( "@avg(", e); break;
  2249. X    case REDUCE | 'c': range_arg( "@count(", e); break;
  2250. X    case REDUCE | 's': range_arg( "@stddev(", e); break;
  2251. X    case REDUCE | MAX: range_arg( "@max(", e); break;
  2252. X    case REDUCE | MIN: range_arg( "@min(", e); break;
  2253. X
  2254. X    case ABS:        one_arg( "@abs(", e); break;
  2255. X    case ACOS:    one_arg( "@acos(", e); break;
  2256. X    case ASIN:    one_arg( "@asin(", e); break;
  2257. X    case ATAN:    one_arg( "@atan(", e); break;
  2258. X    case ATAN2:    two_arg( "@atan2(", e); break;
  2259. X    case CEIL:    one_arg( "@ceil(", e); break;
  2260. X    case COS:    one_arg( "@cos(", e); break;
  2261. X    case EXP:    one_arg( "@exp(", e); break;
  2262. X    case FABS:    one_arg( "@fabs(", e); break;
  2263. X    case FLOOR:    one_arg( "@floor(", e); break;
  2264. X    case HYPOT:    two_arg( "@hypot(", e); break;
  2265. X    case LOG:    one_arg( "@ln(", e); break;
  2266. X    case LOG10:    one_arg( "@log(", e); break;
  2267. X    case POW:    two_arg( "@pow(", e); break;
  2268. X    case SIN:    one_arg( "@sin(", e); break;
  2269. X    case SQRT:    one_arg( "@sqrt(", e); break;
  2270. X    case TAN:    one_arg( "@tan(", e); break;
  2271. X    case DTR:    one_arg( "@dtr(", e); break;
  2272. X    case RTD:    one_arg( "@rtd(", e); break;
  2273. X    case RND:    one_arg( "@rnd(", e); break;
  2274. X    case ROUND:    two_arg( "@round(", e); break;
  2275. X    case HOUR:    one_arg( "@hour(", e); break;
  2276. X    case MINUTE:    one_arg( "@minute(", e); break;
  2277. X    case SECOND:    one_arg( "@second(", e); break;
  2278. X    case MONTH:    one_arg( "@month(", e); break;
  2279. X    case DAY:    one_arg( "@day(", e); break;
  2280. X    case YEAR:    one_arg( "@year(", e); break;
  2281. X    case DATE:    one_arg( "@date(", e); break;
  2282. X    case UPPER:    one_arg( "@upper(", e); break;
  2283. X    case LOWER:    one_arg( "@lower(", e); break;
  2284. X    case CAPITAL:    one_arg( "@capital(", e); break;
  2285. X    case DTS:    three_arg( "@dts(", e); break;
  2286. X    case TTS:    three_arg( "@tts(", e); break;
  2287. X    case STON:    one_arg( "@ston(", e); break;
  2288. X    case FMT:    two_arg( "@fmt(", e); break;
  2289. X    case EQS:    two_arg( "@eqs(", e); break;
  2290. X    case NOW:    for ( s = "@now"; line[linelim++] = *s++;);
  2291. X            linelim--;
  2292. X            break;
  2293. X    case LMAX:    list_arg("@max(", e); break;
  2294. X    case LMIN:     list_arg("@min(", e); break;
  2295. X    case FV:    three_arg("@fv(", e); break;
  2296. X    case PV:    three_arg("@pv(", e); break;
  2297. X    case PMT:    three_arg("@pmt(", e); break;
  2298. X    case NVAL:    two_arg("@nval(", e); break;
  2299. X    case SVAL:    two_arg("@sval(", e); break;
  2300. X    case EXT:    two_arg("@ext(", e); break;
  2301. X    case SUBSTR:    three_arg("@substr(", e); break;
  2302. X    case STINDEX:    index_arg("@stindex(", e); break;
  2303. X    case INDEX:    index_arg("@index(", e); break;
  2304. X    case LOOKUP:    index_arg("@lookup(", e); break;
  2305. X    case HLOOKUP:    two_arg_index("@hlookup(", e); break;
  2306. X    case VLOOKUP:    two_arg_index("@vlookup(", e); break;
  2307. X    case IF:    three_arg("@if(", e); break;
  2308. X    case MYROW:    for ( s = "@myrow"; line[linelim++] = *s++;);
  2309. X            linelim--;
  2310. X            break;
  2311. X    case MYCOL:    for ( s = "@mycol"; line[linelim++] = *s++;);
  2312. X            linelim--;
  2313. X            break;
  2314. X    case COLTOA:    one_arg( "@coltoa(", e); break;
  2315. X    case NUMITER:    for ( s = "@numiter"; line[linelim++] = *s++;);
  2316. X                        linelim--;
  2317. X                        break;
  2318. X    default:    decompile (e->e.o.left, mypriority);
  2319. X            line[linelim++] = e->op;
  2320. X            decompile (e->e.o.right, mypriority+1);
  2321. X            break;
  2322. X    }
  2323. X    if (mypriority<priority) line[linelim++] = ')';
  2324. X    } else line[linelim++] = '?';
  2325. X}
  2326. X
  2327. Xvoid
  2328. Xindex_arg(s, e)
  2329. Xchar *s;
  2330. Xstruct enode *e;
  2331. X{
  2332. X    for (; line[linelim++] = *s++;);
  2333. X    linelim--;
  2334. X    decompile( e-> e.o.left, 0 );
  2335. X    range_arg(", ", e->e.o.right);
  2336. X}
  2337. X
  2338. Xvoid
  2339. Xtwo_arg_index(s, e)
  2340. Xchar *s;
  2341. Xstruct enode *e;
  2342. X{
  2343. X    for (; line[linelim++] = *s++;);
  2344. X    linelim--;
  2345. X    decompile( e->e.o.left->e.o.left, 0 );
  2346. X    range_arg(",", e->e.o.right);
  2347. X    linelim--;
  2348. X    line[linelim++] = ',';
  2349. X    decompile( e->e.o.left->e.o.right, 0 );
  2350. X    line[linelim++] = ')';
  2351. X}
  2352. X
  2353. Xvoid
  2354. Xlist_arg(s, e)
  2355. Xchar *s;
  2356. Xstruct enode *e;
  2357. X{
  2358. X    for (; line[linelim++] = *s++;);
  2359. X    linelim--;
  2360. X
  2361. X    decompile (e->e.o.right, 0);
  2362. X    line[linelim++] = ',';
  2363. X    decompile_list(e->e.o.left);
  2364. X    line[linelim - 1] = ')';
  2365. X}
  2366. X
  2367. Xvoid
  2368. Xone_arg(s, e)
  2369. Xchar *s;
  2370. Xstruct enode *e;
  2371. X{
  2372. X    for (; line[linelim++] = *s++;);
  2373. X    linelim--;
  2374. X    decompile (e->e.o.right, 0);
  2375. X    line[linelim++] = ')';
  2376. X}
  2377. X
  2378. Xvoid
  2379. Xtwo_arg(s,e)
  2380. Xchar *s;
  2381. Xstruct enode *e;
  2382. X{
  2383. X    for (; line[linelim++] = *s++;);
  2384. X    linelim--;
  2385. X    decompile (e->e.o.left, 0);
  2386. X    line[linelim++] = ',';
  2387. X    decompile (e->e.o.right, 0);
  2388. X    line[linelim++] = ')';
  2389. X}
  2390. X
  2391. Xvoid
  2392. Xthree_arg(s,e)
  2393. Xchar *s;
  2394. Xstruct enode *e;
  2395. X{
  2396. X    for (; line[linelim++] = *s++;);
  2397. X    linelim--;
  2398. X    decompile (e->e.o.left, 0);
  2399. X    line[linelim++] = ',';
  2400. X    decompile (e->e.o.right->e.o.left, 0);
  2401. X    line[linelim++] = ',';
  2402. X    decompile (e->e.o.right->e.o.right, 0);
  2403. X    line[linelim++] = ')';
  2404. X}
  2405. X
  2406. Xvoid
  2407. Xrange_arg(s,e)
  2408. Xchar *s;
  2409. Xstruct enode *e;
  2410. X{
  2411. X    struct range *r;
  2412. X
  2413. X    for (; line[linelim++] = *s++;);
  2414. X    linelim--;
  2415. X    if ((r = find_range((char *)0, 0, e->e.r.left.vp,
  2416. X                 e->e.r.right.vp)) && r->r_is_range) {
  2417. X    Sprintf(line+linelim, "%s", r->r_name);
  2418. X    linelim += strlen(line+linelim);
  2419. X    } else {
  2420. X    decodev (e->e.r.left);
  2421. X    line[linelim++] = ':';
  2422. X    decodev (e->e.r.right);
  2423. X    }
  2424. X    line[linelim++] = ')';
  2425. X}
  2426. X
  2427. Xvoid
  2428. Xeditfmt (row, col)
  2429. Xint row, col;
  2430. X{
  2431. X    register struct ent *p;
  2432. X
  2433. X    p = lookat (row, col);
  2434. X    if (p->format) {
  2435. X        Sprintf (line, "fmt %s \"%s\"", v_name(row, col), p->format);
  2436. X    linelim = strlen(line);
  2437. X    }
  2438. X}
  2439. X
  2440. Xvoid
  2441. Xeditv (row, col)
  2442. Xint row, col;
  2443. X{
  2444. X    register struct ent *p;
  2445. X
  2446. X    p = lookat (row, col);
  2447. X    Sprintf (line, "let %s = ", v_name(row, col));
  2448. X    linelim = strlen(line);
  2449. X    if (p->flags & is_strexpr || p->expr == 0) {
  2450. X    Sprintf (line+linelim, "%.15g", p->v);
  2451. X    linelim += strlen (line+linelim);
  2452. X    } else {
  2453. X        editexp(row,col);
  2454. X    }
  2455. X}
  2456. X
  2457. Xvoid
  2458. Xeditexp(row,col)
  2459. Xint row, col;
  2460. X{
  2461. X    register struct ent *p;
  2462. X
  2463. X    p = lookat (row, col);
  2464. X    decompile (p->expr, 0);
  2465. X    line[linelim] = '\0';
  2466. X}
  2467. X
  2468. Xvoid
  2469. Xedits (row, col)
  2470. Xint row, col;
  2471. X{
  2472. X    register struct ent *p;
  2473. X
  2474. X    p = lookat (row, col);
  2475. X    if( p->flags&is_label )
  2476. X    Sprintf( line, "label %s = ", v_name(row, col));
  2477. X    else
  2478. X    Sprintf (line, "%sstring %s = ",
  2479. X            ((p->flags&is_leftflush) ? "left" : "right"),
  2480. X            v_name(row, col));
  2481. X    linelim = strlen(line);
  2482. X    if (p->flags & is_strexpr && p->expr) {
  2483. X    editexp(row, col);
  2484. X    } else if (p->label) {
  2485. X        Sprintf (line+linelim, "\"%s\"", p->label);
  2486. X        linelim += strlen (line+linelim);
  2487. X    } else {
  2488. X        Sprintf (line+linelim, "\"");
  2489. X        linelim += 1;
  2490. X    }
  2491. X}
  2492. X
  2493. X#ifdef RINT
  2494. X/*    round-to-even, also known as ``banker's rounding''.
  2495. X    With round-to-even, a number exactly halfway between two values is
  2496. X    rounded to whichever is even; e.g. rnd(0.5)=0, rnd(1.5)=2,
  2497. X    rnd(2.5)=2, rnd(3.5)=4.  This is the default rounding mode for
  2498. X    IEEE floating point, for good reason: it has better numeric
  2499. X    properties.  For example, if X+Y is an integer,
  2500. X    then X+Y = rnd(X)+rnd(Y) with round-to-even,
  2501. X    but not always with sc's rounding (which is
  2502. X    round-to-positive-infinity).  I ran into this problem when trying to
  2503. X    split interest in an account to two people fairly.
  2504. X*/
  2505. Xdouble rint(d) double d;
  2506. X{
  2507. X    /* as sent */
  2508. X    double fl = floor(d),  fr = d-fl;
  2509. X    return
  2510. X        fr<0.5  ||  fr==0.5 && fl==floor(fl/2)*2   ?   fl   :   ceil(d);
  2511. X}
  2512. X#endif
  2513. END_OF_FILE
  2514.   if test 55653 -ne `wc -c <'ss_12b/interp.c'`; then
  2515.     echo shar: \"'ss_12b/interp.c'\" unpacked with wrong size!
  2516.   fi
  2517.   # end of 'ss_12b/interp.c'
  2518. fi
  2519. if test -f 'ss_12b/xmalloc.c' -a "${1}" != "-c" ; then 
  2520.   echo shar: Will not clobber existing file \"'ss_12b/xmalloc.c'\"
  2521. else
  2522.   echo shar: Extracting \"'ss_12b/xmalloc.c'\" \(1434 characters\)
  2523.   sed "s/^X//" >'ss_12b/xmalloc.c' <<'END_OF_FILE'
  2524. X/*
  2525. X * A safer saner malloc, for careless programmers
  2526. X * $Revision: 6.21 $
  2527. X */
  2528. X
  2529. X#ifndef lint
  2530. X  static char Sccsid[] = "%W% %G%";
  2531. X#endif
  2532. X
  2533. X#include <stdio.h>
  2534. X#include "curses_stuff.h"
  2535. X#include "ss.h"
  2536. X
  2537. Xextern    char *malloc();
  2538. Xextern    char *realloc();
  2539. Xextern    void free();
  2540. Xvoid    fatal();
  2541. X
  2542. X#ifdef SYSV3
  2543. Xextern void free();
  2544. Xextern void exit();
  2545. X#endif
  2546. X
  2547. X#define    MAGIC    (double)1234567890.12344
  2548. X
  2549. Xchar *
  2550. Xscxmalloc(n)
  2551. Xunsigned n;
  2552. X{
  2553. X    register char *ptr;
  2554. X
  2555. X    if ((ptr = malloc(n + sizeof(double))) == NULL)
  2556. X        fatal("scxmalloc: no memory");
  2557. X    *((double *) ptr) = MAGIC;        /* magic number */
  2558. X    return(ptr + sizeof(double));
  2559. X}
  2560. X
  2561. X/* we make sure realloc will do a malloc if needed */
  2562. Xchar *
  2563. Xscxrealloc(ptr, n)
  2564. Xchar    *ptr;
  2565. Xunsigned n;
  2566. X{
  2567. X    if (ptr == NULL)
  2568. X        return(scxmalloc(n));
  2569. X
  2570. X    ptr -= sizeof(double);
  2571. X    if (*((double *) ptr) != MAGIC)
  2572. X        fatal("scxrealloc: storage not scxmalloc'ed");
  2573. X
  2574. X    if ((ptr = realloc(ptr, n + sizeof(double))) == NULL)
  2575. X        fatal("scxmalloc: no memory");
  2576. X    *((double *) ptr) = MAGIC;        /* magic number */
  2577. X    return(ptr + sizeof(double));
  2578. X}
  2579. X
  2580. Xvoid
  2581. Xscxfree(p)
  2582. Xchar *p;
  2583. X{
  2584. X    if (p == NULL)
  2585. X        fatal("scxfree: NULL");
  2586. X    p -= sizeof(double);
  2587. X    if (*((double *) p) != MAGIC)
  2588. X        fatal("scxfree: storage not malloc'ed");
  2589. X    free(p);
  2590. X}
  2591. X
  2592. X#ifdef PSC
  2593. Xvoid
  2594. Xfatal(str)
  2595. Xchar *str;
  2596. X{
  2597. X    (void) fprintf(stderr,"%s\n", str);
  2598. X    exit(1);
  2599. X}
  2600. X#else
  2601. Xvoid
  2602. Xfatal(str)
  2603. Xchar *str;
  2604. X{
  2605. X    deraw();
  2606. X    (void) fprintf(stderr,"%s\n", str);
  2607. X    diesave();
  2608. X    exit(1);
  2609. X}
  2610. X#endif /* PSC */
  2611. END_OF_FILE
  2612.   if test 1434 -ne `wc -c <'ss_12b/xmalloc.c'`; then
  2613.     echo shar: \"'ss_12b/xmalloc.c'\" unpacked with wrong size!
  2614.   fi
  2615.   # end of 'ss_12b/xmalloc.c'
  2616. fi
  2617. echo shar: End of archive 2 \(of 11\).
  2618. cp /dev/null ark2isdone
  2619. MISSING=""
  2620. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  2621.     if test ! -f ark${I}isdone ; then
  2622.     MISSING="${MISSING} ${I}"
  2623.     fi
  2624. done
  2625. if test "${MISSING}" = "" ; then
  2626.     echo You have unpacked all 11 archives.
  2627.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2628. else
  2629.     echo You still must unpack the following archives:
  2630.     echo "        " ${MISSING}
  2631. fi
  2632. exit 0
  2633. exit 0 # Just in case...
  2634.