home *** CD-ROM | disk | FTP | other *** search
/ pc.louisiana.edu/pub/unix/ / Louisiana_UNIX.tar / Louisiana_UNIX / xspread3.0.zoo / interp.c < prev    next >
C/C++ Source or Header  |  1994-06-02  |  63KB  |  2,660 lines

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