home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume20 / sc / part01 / cmds.c next >
Encoding:
C/C++ Source or Header  |  1991-06-05  |  35.8 KB  |  1,732 lines

  1. /*    SC    A Spreadsheet Calculator
  2.  *        Command routines
  3.  *
  4.  *        original by James Gosling, September 1982
  5.  *        modifications by Mark Weiser and Bruce Israel,
  6.  *            University of Maryland
  7.  *
  8.  *              More mods Robert Bond, 12/86
  9.  *
  10.  *        $Revision: 6.16 $
  11.  */
  12.  
  13. #include <sys/types.h>
  14. #if defined(BSD42) || defined(BSD43)
  15. #include <strings.h>
  16. #else
  17. #ifndef SYSIII
  18. #include <string.h>
  19. #endif
  20. #endif
  21.  
  22. #include <curses.h>
  23. #if defined(BSD42) || defined(BSD43)
  24. #include <sys/file.h>
  25. #else
  26. #include <fcntl.h>
  27. #endif
  28. #include "sc.h"
  29. #include <signal.h>
  30. #include <errno.h>
  31.  
  32. #ifdef SYSV3
  33. extern void exit();
  34. #else
  35. extern int exit();
  36. #endif
  37.  
  38. void    openrow();
  39. void    syncref();
  40. void    unspecial();
  41.  
  42. extern    int    errno;
  43.  
  44. /* a linked list of free [struct ent]'s, uses .next as the pointer */
  45. extern    struct ent *freeents;
  46.  
  47. /* a linked list of free [struct enodes]'s, uses .e.o.left as the pointer */
  48. extern    struct enode *freeenodes;
  49.  
  50. #define DEFCOLDELIM ':'
  51.  
  52. /* copy the current row (currow) and place the cursor in the new row */
  53. void
  54. duprow()
  55. {
  56.     if (currow >= maxrows - 1 || maxrow >= maxrows - 1) {
  57.     if (!growtbl(GROWROW, 0, 0))
  58.         return;
  59.     }
  60.     modflg++;
  61.     currow++;
  62.     openrow (currow);
  63.     for (curcol = 0; curcol <= maxcol; curcol++) {
  64.     register struct ent *p = *ATBL(tbl, currow - 1, curcol);
  65.     if (p) {
  66.         register struct ent *n;
  67.         n = lookat (currow, curcol);
  68.         (void)copyent ( n, p, 1, 0);
  69.     }
  70.     }
  71.     for (curcol = 0; curcol <= maxcol; curcol++) {
  72.     register struct ent *p = *ATBL(tbl, currow, curcol);
  73.     if (p && (p -> flags & is_valid) && !p -> expr)
  74.         break;
  75.     }
  76.     if (curcol > maxcol)
  77.     curcol = 0;
  78. }
  79.  
  80. /* copy the current column (curcol) and place the cursor in the new column */
  81. void
  82. dupcol() 
  83. {
  84.     if (curcol >= maxcols - 1 || maxcol >= maxcols - 1) {
  85.     if (!growtbl(GROWCOL, 0, 0))
  86.         return;
  87.     }
  88.     modflg++;
  89.     curcol++;
  90.     opencol (curcol, 1);
  91.     for (currow = 0; currow <= maxrow; currow++) {
  92.     register struct ent *p = *ATBL(tbl, currow, curcol - 1);
  93.     if (p) {
  94.         register struct ent *n;
  95.         n = lookat (currow, curcol);
  96.         copyent ( n, p, 0, 1);
  97.     }
  98.     }
  99.     for (currow = 0; currow <= maxrow; currow++) {
  100.     register struct ent *p = *ATBL(tbl, currow, curcol);
  101.     if (p && (p -> flags & is_valid) && !p -> expr)
  102.         break;
  103.     }
  104.     if (currow > maxrow)
  105.     currow = 0;
  106. }
  107.  
  108. /* insert 'arg' rows before currow */
  109. void
  110. insertrow(arg)
  111. register int arg;
  112. {
  113.     while (--arg>=0) openrow (currow);
  114. }
  115.  
  116. /* delete 'arg' rows starting at currow (deletes from currow downward) */
  117. void
  118. deleterow(arg)
  119. register int arg;
  120. {
  121.     flush_saved();
  122.     erase_area(currow, 0, currow + arg - 1, maxcol);
  123.     currow += arg;
  124.     while (--arg>=0) closerow (--currow);
  125.     sync_refs();
  126. }
  127.  
  128. void
  129. erase_area(sr, sc, er, ec)
  130. int sr, sc, er, ec;
  131. {
  132.     register int r, c;
  133.     register struct ent **pp;
  134.  
  135.     if (sr > er) {
  136.     r = sr; sr = er; er= r;    
  137.     }
  138.  
  139.     if (sc > ec) {
  140.     c = sc; sc = ec; ec= c;    
  141.     }
  142.  
  143.     if (sr < 0)
  144.     sr = 0; 
  145.     if (sc < 0)
  146.     sc = 0;
  147.     checkbounds(&er, &ec);
  148.  
  149.     for (r = sr; r <= er; r++) {
  150.     for (c = sc; c <= ec; c++) {
  151.         pp = ATBL(tbl, r, c);
  152.         if (*pp) {
  153.         free_ent(*pp);
  154.         *pp = (struct ent *)0;
  155.         }
  156.     }
  157.     }
  158. }
  159.  
  160. /*
  161.  * deletes the expression associated w/ a cell and turns it into a constant
  162.  * containing whatever was on the screen
  163.  */
  164. void
  165. valueize_area(sr, sc, er, ec)
  166. int sr, sc, er, ec;
  167. {
  168.     register int r, c;
  169.     register struct ent *p;
  170.  
  171.     if (sr > er) {
  172.     r = sr; sr = er; er= r;    
  173.     }
  174.  
  175.     if (sc > ec) {
  176.     c = sc; sc = ec; ec= c;    
  177.     }
  178.  
  179.     if (sr < 0)
  180.     sr = 0; 
  181.     if (sc < 0)
  182.     sc = 0;
  183.     checkbounds(&er, &ec);
  184.  
  185.     for (r = sr; r <= er; r++) {
  186.     for (c = sc; c <= ec; c++) {
  187.         p = *ATBL(tbl, r, c);
  188.         if (p && p->expr) {
  189.         efree(p->expr);
  190.         p->expr = (struct enode *)0;
  191.         p->flags &= ~is_strexpr;
  192.         }
  193.     }
  194.     }
  195.  
  196. }
  197.  
  198. void
  199. pullcells(to_insert)
  200. int to_insert;
  201. {
  202.     register struct ent *p, *n;
  203.     register int deltar, deltac;
  204.     int minrow, mincol;
  205.     int mxrow, mxcol;
  206.     int numrows, numcols;
  207.  
  208.     if (! to_fix)
  209.     {
  210.     error ("No data to pull");
  211.     return;
  212.     }
  213.  
  214.     minrow = maxrows; 
  215.     mincol = maxcols;
  216.     mxrow = 0;
  217.     mxcol = 0;
  218.  
  219.     for (p = to_fix; p; p = p->next) {
  220.     if (p->row < minrow)
  221.         minrow = p->row;
  222.     if (p->row > mxrow)
  223.         mxrow = p->row;
  224.     if (p->col < mincol)
  225.         mincol = p->col;
  226.     if (p->col > mxcol)
  227.         mxcol = p->col;
  228.     }
  229.  
  230.     numrows = mxrow - minrow + 1;
  231.     numcols = mxcol - mincol + 1;
  232.     deltar = currow - minrow;
  233.     deltac = curcol - mincol;
  234.  
  235.     if (to_insert == 'r') {
  236.     insertrow(numrows);
  237.     deltac = 0;
  238.     } else if (to_insert == 'c') {
  239.     opencol(curcol, numcols);
  240.     deltar = 0;
  241.     }
  242.  
  243.     FullUpdate++;
  244.     modflg++;
  245.  
  246.     for (p = to_fix; p; p = p->next) {
  247.     n = lookat (p->row + deltar, p->col + deltac);
  248.     (void) clearent(n);
  249.     copyent( n, p, deltar, deltac);
  250.     n -> flags = p -> flags & ~is_deleted;
  251.     }
  252. }
  253.  
  254. void
  255. colshow_op()
  256. {
  257.     register int i,j;
  258.     for (i=0; i<maxcols; i++)
  259.     if (col_hidden[i]) 
  260.         break;
  261.     for(j=i; j<maxcols; j++)
  262.     if (!col_hidden[j])
  263.         break;
  264.     j--;
  265.     if (i>=maxcols)
  266.     error ("No hidden columns to show");
  267.     else {
  268.     (void) sprintf(line,"show %s:", coltoa(i));
  269.     (void) sprintf(line + strlen(line),"%s",coltoa(j));
  270.     linelim = strlen (line);
  271.     }
  272. }
  273.  
  274. void
  275. rowshow_op()
  276. {
  277.     register int i,j;
  278.     for (i=0; i<maxrows; i++)
  279.     if (row_hidden[i]) 
  280.         break;
  281.     for(j=i; j<maxrows; j++)
  282.     if (!row_hidden[j]) {
  283.         break;
  284.     }
  285.     j--;
  286.  
  287.     if (i>=maxrows)
  288.     error ("No hidden rows to show");
  289.     else {
  290.     (void) sprintf(line,"show %d:%d", i, j);
  291.         linelim = strlen (line);
  292.     }
  293. }
  294.  
  295. /*
  296.  * Given a row/column command letter, emit a small menu, then read a qualifier
  297.  * character for a row/column command and convert it to 'r' (row), 'c'
  298.  * (column), or 0 (unknown).  If ch is 'p', an extra qualifier 'm' is allowed.
  299.  */
  300.  
  301. int
  302. get_rcqual (ch)
  303.     int ch;
  304. {
  305.     error ("%sow/column:  r: row  c: column%s",
  306.  
  307.         (ch == 'i') ? "Insert r" :
  308.         (ch == 'a') ? "Append r" :
  309.         (ch == 'd') ? "Delete r" :
  310.         (ch == 'p') ? "Pull r" :
  311.         (ch == 'v') ? "Values r" :
  312.         (ch == 'z') ? "Zap r" :
  313.         (ch == 's') ? "Show r" : "R",
  314.  
  315.         (ch == 'p') ? "  m: merge" : "");
  316.  
  317.     (void) refresh();
  318.  
  319.     switch (nmgetch())
  320.     {
  321.     case 'r':
  322.     case 'l':
  323.     case 'h':
  324.     case ctl('f'):
  325.     case ctl('b'):    return ('r');
  326.  
  327.     case 'c':
  328.     case 'j':
  329.     case 'k':
  330.     case ctl('p'):
  331.     case ctl('n'):    return ('c');
  332.  
  333.     case 'm':    return ((ch == 'p') ? 'm' : 0);
  334.  
  335.     case ESC:
  336.     case ctl('g'):    return (ESC);
  337.  
  338.     default:    return (0);
  339.     }
  340.     /*NOTREACHED*/
  341. }
  342.  
  343. void
  344. openrow (rs)
  345. int    rs;
  346. {
  347.     register    r, c;
  348.     struct ent    **tmprow, **pp;
  349.  
  350.     if (rs > maxrow) maxrow = rs;
  351.     if (maxrow >= maxrows - 1 || rs > maxrows - 1) {
  352.     if (!growtbl(GROWROW, rs, 0))
  353.         return;
  354.     }
  355.     /*
  356.      * save the last active row+1, shift the rows downward, put the last
  357.      * row in place of the first
  358.      */
  359.     tmprow = tbl[++maxrow];
  360.     for (r = maxrow; r > rs; r--) {
  361.     row_hidden[r] = row_hidden[r-1];
  362.     tbl[r] = tbl[r-1];
  363.     pp = ATBL(tbl, r, 0);
  364.     for (c = 0; c < maxcols; c++, pp++)
  365.         if (*pp)
  366.             (*pp)->row = r;
  367.     }
  368.     tbl[r] = tmprow;    /* the last row was never used.... */
  369.     FullUpdate++;
  370.     modflg++;
  371. }
  372.  
  373. /* delete row r */
  374. void
  375. closerow (r)
  376. register r;
  377. {
  378.     register struct ent **pp;
  379.     register c;
  380.     struct ent    **tmprow;
  381.  
  382.     if (r > maxrow) return;
  383.  
  384.     /* save the row and empty it out */
  385.     tmprow = tbl[r];
  386.     pp = ATBL(tbl, r, 0);
  387.     for (c=maxcol+1; --c>=0; pp++) {
  388.     if (*pp)
  389.     {    free_ent(*pp);
  390.         *pp = (struct ent *)0;
  391.     }
  392.     }
  393.  
  394.     /* move the rows, put the deleted, but now empty, row at the end */
  395.     for (; r < maxrows - 1; r++) {
  396.     row_hidden[r] = row_hidden[r+1];
  397.     tbl[r] = tbl[r+1];
  398.     pp = ATBL(tbl, r, 0);
  399.     for (c = 0; c < maxcols; c++, pp++)
  400.         if (*pp)
  401.             (*pp)->row = r;
  402.     }
  403.     tbl[r] = tmprow;
  404.  
  405.     maxrow--;
  406.     FullUpdate++;
  407.     modflg++;
  408. }
  409.  
  410. void
  411. opencol (cs, numcol)
  412. int    cs;
  413. int    numcol;
  414. {
  415.     register r;
  416.     register struct ent **pp;
  417.     register c;
  418.     register lim = maxcol-cs+1;
  419.     int i;
  420.  
  421.     if (cs > maxcol)
  422.     maxcol = cs;
  423.     maxcol += numcol;
  424.  
  425.     if ((maxcol >= maxcols - 1) && !growtbl(GROWCOL, 0, maxcol))
  426.         return;
  427.  
  428.     for (i = maxcol; i > cs; i--) {
  429.     fwidth[i] = fwidth[i-numcol];
  430.     precision[i] = precision[i-numcol];
  431.     realfmt[i] = realfmt[i-numcol];
  432.     col_hidden[i] = col_hidden[i-numcol];
  433.     }
  434.     for (c = cs; c - cs < numcol; c++)
  435.     {    fwidth[c] = DEFWIDTH;
  436.     precision[c] =  DEFPREC;
  437.     realfmt[c] = DEFREFMT;
  438.     }
  439.     
  440.     for (r=0; r<=maxrow; r++) {
  441.     pp = ATBL(tbl, r, maxcol);
  442.     for (c=lim; --c>=0; pp--)
  443.         if (pp[0] = pp[-numcol])
  444.         pp[0]->col += numcol;
  445.  
  446.     pp = ATBL(tbl, r, cs);
  447.     for (c = cs; c - cs < numcol; c++, pp++)
  448.         *pp = (struct ent *)0;
  449.     }
  450.     FullUpdate++;
  451.     modflg++;
  452. }
  453.  
  454. void
  455. closecol (cs, numcol)
  456. int cs;
  457. int    numcol;
  458. {
  459.     register r;
  460.     register struct ent **pp;
  461.     register struct ent *q;
  462.     register c;
  463.     register lim = maxcol-cs;
  464.     int i;
  465.     char buf[50];
  466.  
  467.     if (lim - numcol < -1)
  468.     {    (void) sprintf(buf, "Can't delete %d column%s %d columns left", numcol,
  469.             (numcol > 1 ? "s," : ","), lim+1);
  470.     error(buf);
  471.     return;
  472.     }
  473.     flush_saved();
  474.     erase_area(0, curcol, maxrow, curcol + numcol - 1);
  475.     sync_refs();
  476.  
  477.     /* clear then copy the block left */
  478.     lim = maxcols - numcol - 1;
  479.     for (r=0; r<=maxrow; r++) {
  480.     for (c = cs; c - cs < numcol; c++)
  481.         if (q = *ATBL(tbl, r, c))
  482.             free_ent(q);
  483.  
  484.     pp = ATBL(tbl, r, cs);
  485.     for (c=cs; c <= lim; c++, pp++)
  486.     {   if (c > lim)
  487.         *pp = (struct ent *)0;
  488.         else
  489.         if (pp[0] = pp[numcol])
  490.         pp[0]->col -= numcol;
  491.     }
  492.  
  493.     c = numcol;
  494.     for (; --c >= 0; pp++)        
  495.         *pp = (struct ent *)0;
  496.     }
  497.  
  498.     for (i = cs; i < maxcols - numcol - 1; i++) {
  499.     fwidth[i] = fwidth[i+numcol];
  500.     precision[i] = precision[i+numcol];
  501.     realfmt[i] = realfmt[i+numcol];
  502.     col_hidden[i] = col_hidden[i+numcol];
  503.     }
  504.     for (; i < maxcols - 1; i++) {
  505.     fwidth[i] = DEFWIDTH;
  506.     precision[i] = DEFPREC;
  507.     realfmt[i] = DEFREFMT;
  508.     col_hidden[i] = 0;
  509.     }
  510.  
  511.     maxcol -= numcol;
  512.     FullUpdate++;
  513.     modflg++;
  514. }
  515.  
  516. void
  517. doend(rowinc, colinc)
  518. int rowinc, colinc;
  519. {
  520.     register struct ent *p;
  521.     int r, c;
  522.  
  523.     if (VALID_CELL(p, currow, curcol)) {
  524.     r = currow + rowinc;
  525.     c = curcol + colinc;
  526.     if (r >= 0 && r < maxrows && 
  527.         c >= 0 && c < maxcols &&
  528.         !VALID_CELL(p, r, c)) {
  529.         currow = r;
  530.         curcol = c;
  531.     }
  532.     }
  533.  
  534.     if (!VALID_CELL(p, currow, curcol)) {
  535.         switch (rowinc) {
  536.         case -1:
  537.         while (!VALID_CELL(p, currow, curcol) && currow > 0)
  538.         currow--;
  539.         break;
  540.         case  1:
  541.         while (!VALID_CELL(p, currow, curcol) && currow < maxrows-1)
  542.         currow++;
  543.         break;
  544.         case  0:
  545.             switch (colinc) {
  546.          case -1:
  547.             while (!VALID_CELL(p, currow, curcol) && curcol > 0)
  548.             curcol--;
  549.             break;
  550.          case  1:
  551.             while (!VALID_CELL(p, currow, curcol) && curcol < maxcols-1)
  552.             curcol++;
  553.             break;
  554.         }
  555.             break;
  556.         }
  557.  
  558.     error ("");    /* clear line */
  559.     return;
  560.     }
  561.  
  562.     switch (rowinc) {
  563.     case -1:
  564.     while (VALID_CELL(p, currow, curcol) && currow > 0)
  565.         currow--;
  566.     break;
  567.     case  1:
  568.     while (VALID_CELL(p, currow, curcol) && currow < maxrows-1)
  569.         currow++;
  570.     break;
  571.     case  0:
  572.     switch (colinc) {
  573.     case -1:
  574.         while (VALID_CELL(p, currow, curcol) && curcol > 0)
  575.         curcol--;
  576.         break;
  577.     case  1:
  578.         while (VALID_CELL(p, currow, curcol) && curcol < maxcols-1)
  579.         curcol++;
  580.         break;
  581.     }
  582.     break;
  583.     }
  584.     if (!VALID_CELL(p, currow, curcol)) {
  585.         currow -= rowinc;
  586.         curcol -= colinc;
  587.     }
  588. }
  589.  
  590. /* Modified 9/17/90 THA to handle more formats */
  591. void
  592. doformat(c1,c2,w,p,r)
  593. int c1,c2,w,p,r;
  594. {
  595.     register int i;
  596.     int crows = 0;
  597.     int ccols = c2;
  598.  
  599.     if (c1 >= maxcols && !growtbl(GROWCOL, 0, c1)) c1 = maxcols-1 ;
  600.     if (c2 >= maxcols && !growtbl(GROWCOL, 0, c2)) c2 = maxcols-1 ;
  601.  
  602.     if (w > COLS - RESCOL - 2) {
  603.     error("Format too large - Maximum = %d", COLS - RESCOL - 2);
  604.     w = COLS-RESCOL-2;
  605.     }
  606.  
  607.     if (p > w) {
  608.     error("Precision too large");
  609.     p = w;
  610.     }
  611.     /* format statement may record format of an as yet unused column
  612.      * which causes it to run off the end of fwidth and precision --
  613.      * causing a bus error later
  614.      */
  615.     checkbounds(&crows, &ccols);
  616.     if (ccols < c2) {
  617.     error("Format statement failed to create implied column %d", c2);
  618.     return;
  619.     }
  620.  
  621.     for(i = c1; i<=c2; i++)
  622.     fwidth[i] = w, precision[i] = p, realfmt[i] = r;
  623.  
  624.     FullUpdate++;
  625.     modflg++;
  626. }
  627.  
  628. void
  629. print_options(f)
  630. FILE *f;
  631. {
  632.     if(
  633.        autocalc &&
  634.        propagation == 10 &&
  635.        calc_order == BYROWS &&
  636.        !numeric &&
  637.        prescale == 1.0 &&
  638.        !extfunc &&
  639.        showcell &&
  640.        showtop &&
  641.        tbl_style == 0
  642.       )
  643.         return;        /* No reason to do this */
  644.  
  645.     (void) fprintf(f, "set");
  646.     if(!autocalc) 
  647.     (void) fprintf(f," !autocalc");
  648.     if(propagation != 10)
  649.     (void) fprintf(f, " iterations = %d", propagation);
  650.     if(calc_order != BYROWS )
  651.     (void) fprintf(f, " bycols");
  652.     if (numeric)
  653.     (void) fprintf(f, " numeric");
  654.     if (prescale != 1.0)
  655.     (void) fprintf(f, " prescale");
  656.     if (extfunc)
  657.     (void) fprintf(f, " extfun");
  658.     if (!showcell)
  659.     (void) fprintf(f, " !cellcur");
  660.     if (!showtop)
  661.     (void) fprintf(f, " !toprow");
  662.     if (tbl_style)
  663.     (void) fprintf(f, " tblstyle = %s", tbl_style == TBL ? "tbl" :
  664.                     tbl_style == LATEX ? "latex" :
  665.                     tbl_style == SLATEX ? "slatex" :
  666.                     tbl_style == TEX ? "tex" : "0" );
  667.     (void) fprintf(f, "\n");
  668. }
  669.  
  670. void
  671. printfile (fname, r0, c0, rn, cn)
  672. char *fname;
  673. int r0, c0, rn, cn;
  674. {
  675.     FILE *f;
  676.     static char *pline = NULL;        /* only malloc once, malloc is slow */
  677.     static unsigned fbufs_allocated = 0;
  678.     int plinelim;
  679.     int pid;
  680.     int fieldlen, nextcol;
  681.     register row, col;
  682.     register struct ent **pp;
  683.     char *xmalloc();
  684.     char *xrealloc();
  685.  
  686.     if ((strcmp(fname, curfile) == 0) &&
  687.     !yn_ask("Confirm that you want to destroy the data base: (y,n)")) {
  688.     return;
  689.     }
  690.  
  691.     if (!pline && (pline = xmalloc((unsigned)(FBUFLEN *
  692.                     ++fbufs_allocated))) == (char *)NULL)
  693.     {   error("Malloc failed in printfile()");
  694.         return;
  695.     }
  696.  
  697.     if ((f = openout(fname, &pid)) == (FILE *)0)
  698.     {    error ("Can't create file \"%s\"", fname);
  699.     return;
  700.     }
  701.     for (row=r0;row<=rn; row++) {
  702.     register c = 0;
  703.  
  704.     if (row_hidden[row])
  705.         continue;
  706.  
  707.     pline[plinelim=0] = '\0';
  708.     for (pp = ATBL(tbl, row, col=c0); col<=cn;
  709.             pp += nextcol-col, col = nextcol, c += fieldlen) {
  710.  
  711.         nextcol = col+1;
  712.         if (col_hidden[col]) {
  713.         fieldlen = 0;
  714.         continue;
  715.         }
  716.  
  717.         fieldlen = fwidth[col];
  718.         if (*pp) {
  719.         char *s;
  720.  
  721.         /* 
  722.          * dynamically allocate pline, making sure we are not 
  723.          * attempting to write 'out of bounds'.
  724.          */
  725.         while(c > (fbufs_allocated * FBUFLEN)) {
  726.           if((pline = xrealloc
  727.                    ((char *)pline, 
  728.                 (unsigned)(FBUFLEN * ++fbufs_allocated)))
  729.              == NULL) {
  730.             error ("Realloc failed in printfile()");
  731.             return;
  732.           }
  733.         }          
  734.         while (plinelim<c) pline[plinelim++] = ' ';
  735.         plinelim = c;
  736.         if ((*pp)->flags&is_valid) {
  737.             while(plinelim + fwidth[col] > 
  738.               (fbufs_allocated * FBUFLEN)) {
  739.               if((pline = ((char *)xrealloc
  740.                    ((char *)pline, 
  741.                     (unsigned)(FBUFLEN * ++fbufs_allocated))))
  742.              == NULL) {
  743.             error ("Realloc failed in printfile()");
  744.             return;
  745.               }
  746.             }
  747.             if ((*pp)->cellerror)
  748.             (void) sprintf (pline+plinelim, "%*s",
  749.                 fwidth[col],
  750.             ((*pp)->cellerror == CELLERROR ? "ERROR" : "INVALID"));
  751.             else
  752.             {
  753.               if ((*pp)->format) {
  754.                    char field[FBUFLEN];
  755.             format ((*pp)->format, (*pp)->v, field,
  756.                        sizeof(field));
  757.             (void) sprintf (pline+plinelim, "%*s", fwidth[col],
  758.                     field);
  759.               } else {
  760.                    char field[FBUFLEN];
  761.             (void) engformat(realfmt[col], fwidth[col],
  762.                                              precision[col], (*pp) -> v,
  763.                                              field, sizeof(field));
  764.             (void) sprintf (pline+plinelim, "%*s", fwidth[col],
  765.                        field);
  766.               }
  767.             }
  768.             plinelim += strlen (pline+plinelim);
  769.         }
  770.         if (s = (*pp)->label) {
  771.             int slen;
  772.             char *start, *last;
  773.             register char *fp;
  774.             struct ent *nc;
  775.  
  776.             /* Figure out if the label slops over to a blank field */
  777.             slen = strlen(s);
  778.             while (slen > fieldlen && nextcol <= cn &&
  779.                 !((nc = lookat(row,nextcol))->flags & is_valid) &&
  780.                 !(nc->label)) {
  781.             
  782.                     if (!col_hidden[nextcol])
  783.                  fieldlen += fwidth[nextcol];
  784.  
  785.             nextcol++;
  786.             }
  787.             if (slen > fieldlen)
  788.             slen = fieldlen;
  789.             
  790.             while(c + fieldlen + 2 > (fbufs_allocated * FBUFLEN)) {
  791.               if((pline = ((char *)xrealloc
  792.                    ((char *)pline, 
  793.                     (unsigned)(FBUFLEN * ++fbufs_allocated))))
  794.              == NULL) {
  795.             error ("xrealloc failed in printfile()");
  796.             return;
  797.               }
  798.             }          
  799.  
  800.             /* Now justify and print */
  801.             start = (*pp)->flags & is_leftflush ? pline + c
  802.                     : pline + c + fieldlen - slen;
  803.             last = pline + c + fieldlen;
  804.             fp = plinelim < c ? pline + plinelim : pline + c;
  805.             while (fp < start)
  806.             *fp++ = ' ';
  807.             while (slen--)
  808.             *fp++ = *s++;
  809.             if (!((*pp)->flags & is_valid) || fieldlen != fwidth[col])
  810.             while(fp < last)
  811.                 *fp++ = ' ';
  812.             if (plinelim < fp - pline)
  813.             plinelim = fp - pline;
  814.         }
  815.         }
  816.     }
  817.     pline[plinelim++] = '\n';
  818.     pline[plinelim] = '\0';
  819.     (void) fputs (pline, f);
  820.     }
  821.  
  822.     closeout(f, pid);
  823. }
  824.  
  825. void
  826. tblprintfile (fname, r0, c0, rn, cn)
  827. char *fname;
  828. int r0, c0, rn, cn;
  829. {
  830.     FILE *f;
  831.     int pid;
  832.     register row, col;
  833.     register struct ent **pp;
  834.     char coldelim = DEFCOLDELIM;
  835.  
  836.     if ((strcmp(fname, curfile) == 0) &&
  837.     !yn_ask("Confirm that you want to destroy the data base: (y,n)"))
  838.         return;
  839.  
  840.     if ((f = openout(fname, &pid)) == (FILE *)0)
  841.     {    error ("Can't create file \"%s\"", fname);
  842.     return;
  843.     }
  844.  
  845.     if ( tbl_style == TBL ) {
  846.     fprintf(f,".\\\" ** %s spreadsheet output \n.TS\n",progname);
  847.     fprintf(f,"tab(%c);\n",coldelim);
  848.     for (col=c0;col<=cn; col++) fprintf(f," n");
  849.     fprintf(f, ".\n");
  850.     }
  851.     else if ( tbl_style == LATEX ) {
  852.     fprintf(f,"%% ** %s spreadsheet output\n\\begin{tabular}{",progname);
  853.     for (col=c0;col<=cn; col++) fprintf(f,"c");
  854.     fprintf(f, "}\n");
  855.     coldelim = '&';
  856.     }
  857.     else if ( tbl_style == SLATEX ) {
  858.     fprintf(f,"%% ** %s spreadsheet output\n!begin<tabular><",progname);
  859.     for (col=c0;col<=cn; col++) fprintf(f,"c");
  860.     fprintf(f, ">\n");
  861.     coldelim = '&';
  862.     }
  863.     else if ( tbl_style == TEX ) {
  864.     fprintf(f,"{\t%% ** %s spreadsheet output\n\\settabs %d \\columns\n",
  865.         progname, cn-c0+1);
  866.     coldelim = '&';
  867.     }
  868.  
  869.     for (row=r0; row<=rn; row++) {
  870.     if ( tbl_style == TEX )
  871.         (void) fprintf (f, "\\+");
  872.     
  873.     for (pp = ATBL(tbl, row, col=c0); col<=cn; col++, pp++) {
  874.         if (*pp) {
  875.         char *s;
  876.         if ((*pp)->flags&is_valid) {
  877.             if ((*pp)->cellerror) {
  878.             (void) fprintf (f, "%*s",
  879.                     fwidth[col],
  880.             ((*pp)->cellerror == CELLERROR ? "ERROR" : "INVALID"));
  881.             }
  882.             else
  883.             if ((*pp)->format) {
  884.                 char field[FBUFLEN];
  885.             
  886.             (void) format ((*pp)->format, (*pp)->v, field,
  887.                        sizeof(field));
  888.             unspecial (f, field, coldelim);
  889.             } else {
  890.                 char field[FBUFLEN];
  891.                         (void) engformat(realfmt[col], fwidth[col],
  892.                                              precision[col], (*pp) -> v,
  893.                                              field, sizeof(field));
  894.             unspecial (f, field, coldelim);
  895.             }
  896.         }
  897.         if (s = (*pp)->label) {
  898.                 unspecial (f, s, coldelim);
  899.         }
  900.         }
  901.         if ( col < cn )
  902.         (void) fprintf(f,"%c", coldelim);
  903.     }
  904.     if ( tbl_style == LATEX ) {
  905.         if ( row < rn ) (void) fprintf (f, "\\\\");
  906.     }
  907.     else if ( tbl_style == SLATEX ) {
  908.         if ( row < rn ) (void) fprintf (f, "!!");
  909.     }
  910.     else if ( tbl_style == TEX ) {
  911.         (void) fprintf (f, "\\cr");
  912.     }
  913.     (void) fprintf (f,"\n");
  914.     }
  915.  
  916.     if ( tbl_style == TBL )
  917.     (void) fprintf (f,".TE\n.\\\" ** end of %s spreadsheet output\n", progname);
  918.     else if ( tbl_style == LATEX )
  919.     (void) fprintf (f,"\\end{tabular}\n%% ** end of %s spreadsheet output\n", progname);
  920.     else if ( tbl_style == SLATEX )
  921.     (void) fprintf (f,"!end<tabular>\n%% ** end of %s spreadsheet output\n", progname);
  922.     else if ( tbl_style == TEX )
  923.     (void) fprintf (f,"}\n%% ** end of %s spreadsheet output\n", progname);
  924.  
  925.     closeout(f, pid);
  926. }
  927.  
  928. /* unspecial (backquote) things that are special chars in a table */
  929. void
  930. unspecial(f, str, delim)
  931. FILE    *f;
  932. char    *str;
  933. int    delim;
  934. {
  935.     while (*str)
  936.     {    if (((tbl_style == LATEX) || (tbl_style == SLATEX) ||
  937.             (tbl_style == TEX)) &&
  938.             ((*str == delim) || (*str == '$') || (*str == '#') ||
  939.             (*str == '%') || (*str == '{') || (*str == '}') ||
  940.             (*str == '[') || (*str == ']') || (*str == '&')))
  941.             putc('\\', f);
  942.         putc(*str, f);
  943.         str++;
  944.     }
  945. }
  946.  
  947. struct enode *
  948. copye (e, Rdelta, Cdelta)
  949. register struct enode *e;
  950. int Rdelta, Cdelta;
  951. {
  952.     register struct enode *ret;
  953.  
  954.     if (e == (struct enode *)0) {
  955.         ret = (struct enode *)0;
  956.     } else if (e->op & REDUCE) {
  957.     int newrow, newcol;
  958.     if (freeenodes)
  959.     {    ret = freeenodes;
  960.         freeenodes = ret->e.o.left;
  961.     }
  962.     else
  963.         ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
  964.     ret->op = e->op;
  965.     newrow=e->e.r.left.vf & FIX_ROW ? e->e.r.left.vp->row :
  966.                       e->e.r.left.vp->row+Rdelta;
  967.     newcol=e->e.r.left.vf & FIX_COL ? e->e.r.left.vp->col :
  968.                       e->e.r.left.vp->col+Cdelta;
  969.     ret->e.r.left.vp = lookat (newrow, newcol);
  970.     ret->e.r.left.vf = e->e.r.left.vf;
  971.     newrow=e->e.r.right.vf & FIX_ROW ? e->e.r.right.vp->row :
  972.                        e->e.r.right.vp->row+Rdelta;
  973.     newcol=e->e.r.right.vf & FIX_COL ? e->e.r.right.vp->col :
  974.                        e->e.r.right.vp->col+Cdelta;
  975.     ret->e.r.right.vp = lookat (newrow, newcol);
  976.     ret->e.r.right.vf = e->e.r.right.vf;
  977.     } else {
  978.     if (freeenodes)
  979.     {    ret = freeenodes;
  980.         freeenodes = ret->e.o.left;
  981.     }
  982.     else
  983.         ret = (struct enode *) xmalloc ((unsigned) sizeof (struct enode));
  984.     ret->op = e->op;
  985.     switch (ret->op) {
  986.     case 'v':
  987.         {
  988.             int newrow, newcol;
  989.             newrow=e->e.v.vf & FIX_ROW ? e->e.v.vp->row :
  990.                          e->e.v.vp->row+Rdelta;
  991.             newcol=e->e.v.vf & FIX_COL ? e->e.v.vp->col :
  992.                          e->e.v.vp->col+Cdelta;
  993.             ret->e.v.vp = lookat (newrow, newcol);
  994.             ret->e.v.vf = e->e.v.vf;
  995.             break;
  996.         }
  997.     case 'k':
  998.         ret->e.k = e->e.k;
  999.         break;
  1000.     case 'f':
  1001.         ret->e.o.right = copye (e->e.o.right,0,0);
  1002.         ret->e.o.left = (struct enode *)0;
  1003.          break;
  1004.     case '$':
  1005.         ret->e.s = xmalloc((unsigned) strlen(e->e.s)+1);
  1006.         (void) strcpy(ret->e.s, e->e.s);
  1007.         break;
  1008.     default:
  1009.         ret->e.o.right = copye (e->e.o.right,Rdelta,Cdelta);
  1010.         ret->e.o.left = copye (e->e.o.left,Rdelta,Cdelta);
  1011.         break;
  1012.     }
  1013.     }
  1014.     return ret;
  1015. }
  1016.  
  1017. /*
  1018.  
  1019.  * sync_refs and syncref are used to remove references to
  1020.  * deleted struct ents.  Note that the deleted structure must still
  1021.  * be hanging around before the call, but not referenced by an entry
  1022.  * in tbl.  Thus the free_ent, fix_ent calls in sc.c
  1023.  */
  1024. void
  1025. sync_refs ()
  1026. {
  1027.     register i,j;
  1028.     register struct ent *p;
  1029.     sync_ranges();
  1030.     for (i=0; i<=maxrow; i++)
  1031.     for (j=0; j<=maxcol; j++)
  1032.         if ((p = *ATBL(tbl, i, j)) && p->expr)
  1033.         syncref(p->expr);
  1034. }
  1035.  
  1036. void
  1037. syncref(e)
  1038. register struct enode *e;
  1039. {
  1040.     if (e == (struct enode *)0)
  1041.     return;
  1042.     else if (e->op & REDUCE) {
  1043.      e->e.r.right.vp = lookat(e->e.r.right.vp->row, e->e.r.right.vp->col);
  1044.      e->e.r.left.vp = lookat(e->e.r.left.vp->row, e->e.r.left.vp->col);
  1045.     } else {
  1046.     switch (e->op) {
  1047.     case 'v':
  1048.         e->e.v.vp = lookat(e->e.v.vp->row, e->e.v.vp->col);
  1049.         break;
  1050.     case 'k':
  1051.         break;
  1052.     case '$':
  1053.         break;
  1054.     default:
  1055.         syncref(e->e.o.right);
  1056.         syncref(e->e.o.left);
  1057.         break;
  1058.     }
  1059.     }
  1060. }
  1061.  
  1062. /* mark a row as hidden */
  1063. void
  1064. hiderow(arg)
  1065. int arg;
  1066. {
  1067.     register int r1;
  1068.     register int r2;
  1069.  
  1070.     r1 = currow;
  1071.     r2 = r1 + arg - 1;
  1072.     if (r1 < 0 || r1 > r2) {
  1073.     error ("Invalid range");
  1074.     return;
  1075.     }
  1076.     if (r2 >= maxrows-1)
  1077.     {    if (!growtbl(GROWROW, arg+1, 0))
  1078.     {    error("You can't hide the last row");
  1079.         return;
  1080.     }
  1081.     }
  1082.     FullUpdate++;
  1083.     modflg++;
  1084.     while (r1 <= r2)
  1085.     row_hidden[r1++] = 1;
  1086. }
  1087.  
  1088. /* mark a column as hidden */
  1089. void
  1090. hidecol(arg)
  1091. int arg;
  1092. {
  1093.     register int c1;
  1094.     register int c2;
  1095.  
  1096.     c1 = curcol;
  1097.     c2 = c1 + arg - 1;
  1098.     if (c1 < 0 || c1 > c2) {
  1099.     error ("Invalid range");
  1100.     return;
  1101.     }
  1102.     if (c2 >= maxcols-1)
  1103.     {    if ((arg >= ABSMAXCOLS-1) || !growtbl(GROWCOL, 0, arg+1))
  1104.     {    error("You can't hide the last col");
  1105.         return;
  1106.     }
  1107.     }
  1108.     FullUpdate++;
  1109.     modflg++;
  1110.     while (c1 <= c2)
  1111.     col_hidden[c1++] = 1;
  1112. }
  1113.  
  1114. /* mark a row as not-hidden */
  1115. void
  1116. showrow(r1, r2)
  1117. int r1, r2;
  1118. {
  1119.     if (r1 < 0 || r1 > r2) {
  1120.     error ("Invalid range");
  1121.     return;
  1122.     }
  1123.     if (r2 > maxrows-1) {
  1124.     r2 = maxrows-1;
  1125.     }
  1126.     FullUpdate++;
  1127.     modflg++;
  1128.     while (r1 <= r2)
  1129.     row_hidden[r1++] = 0;
  1130. }
  1131.  
  1132. /* mark a column as not-hidden */
  1133. void
  1134. showcol(c1, c2)
  1135. int c1, c2;
  1136. {
  1137.     if (c1 < 0 || c1 > c2) {
  1138.     error ("Invalid range");
  1139.     return;
  1140.     }
  1141.     if (c2 > maxcols-1) {
  1142.     c2 = maxcols-1;
  1143.     }
  1144.     FullUpdate++;
  1145.     modflg++;
  1146.     while (c1 <= c2)
  1147.     col_hidden[c1++] = 0;
  1148. }
  1149.  
  1150. /* Open the output file, setting up a pipe if needed */
  1151. FILE *
  1152. openout(fname, rpid)
  1153. char *fname;
  1154. int *rpid;
  1155. {
  1156.     int pipefd[2];
  1157.     int pid;
  1158.     FILE *f;
  1159.     char *efname;
  1160.  
  1161.     while (*fname && (*fname == ' '))  /* Skip leading blanks */
  1162.     fname++;
  1163.  
  1164.     if (*fname != '|') {        /* Open file if not pipe */
  1165.     *rpid = 0;
  1166.     
  1167.     efname = findhome(fname);
  1168. #ifdef DOBACKUPS
  1169.     if (!backup_file(efname) &&
  1170.         (yn_ask("Could not create backup copy, Save anyhow?: (y,n)") != 1))
  1171.         return(0);
  1172. #endif
  1173.     return(fopen(efname, "w"));
  1174.     }
  1175.  
  1176.     fname++;                /* Skip | */
  1177.     if ( pipe (pipefd) < 0) {
  1178.     error("Can't make pipe to child");
  1179.     *rpid = 0;
  1180.     return(0);
  1181.     }
  1182.  
  1183.     deraw();
  1184. #ifdef VMS
  1185.     fprintf(stderr, "No son tasks available yet under VMS--sorry\n");
  1186. #else /* VMS */
  1187.  
  1188.     if ((pid=fork()) == 0)              /* if child  */
  1189.     {
  1190.     (void) close (0);              /* close stdin */
  1191.     (void) close (pipefd[1]);
  1192.     (void) dup (pipefd[0]);          /* connect to pipe input */
  1193.     (void) signal (SIGINT, SIG_DFL);      /* reset */
  1194.     (void) execl ("/bin/sh", "sh", "-c", fname, 0);
  1195.     exit (-127);
  1196.     }
  1197.     else                  /* else parent */
  1198.     {
  1199.     *rpid = pid;
  1200.     if ((f = fdopen (pipefd[1], "w")) == (FILE *)0)
  1201.     {
  1202.         (void) kill (pid, -9);
  1203.         error ("Can't fdopen output");
  1204.         (void) close (pipefd[1]);
  1205.         *rpid = 0;
  1206.         return(0);
  1207.     }
  1208.     }
  1209. #endif /* VMS */
  1210.     return(f);
  1211. }
  1212.  
  1213. /* close a file opened by openout(), if process wait for return */
  1214. void
  1215. closeout(f, pid)
  1216. FILE *f;
  1217. int pid;
  1218. {
  1219.     int temp;
  1220.  
  1221.     (void) fclose (f);
  1222.     if (pid) {
  1223.          while (pid != wait(&temp)) /**/;
  1224.      (void) printf("Press RETURN to continue ");
  1225.      (void) fflush(stdout);
  1226.      (void) nmgetch();
  1227.      goraw();
  1228.     }
  1229. }
  1230.  
  1231. void
  1232. copyent(n,p,dr,dc)
  1233.         register struct ent *n, *p;
  1234.         int dr, dc;
  1235. {
  1236.     if(!n||!p){error("internal error");return;}
  1237.     n -> v = p -> v;
  1238.     n -> flags = p -> flags;
  1239.     n -> expr = copye (p -> expr, dr, dc);
  1240.     n -> label = (char *)0;
  1241.     if (p -> label) {
  1242.     n -> label = xmalloc ((unsigned) (strlen (p -> label) + 1));
  1243.     (void) strcpy (n -> label, p -> label);
  1244.     }
  1245.     n -> format = 0;
  1246.     if (p -> format) {
  1247.         n -> format = xmalloc ((unsigned) (strlen (p -> format) + 1));
  1248.     (void) strcpy (n -> format, p -> format);
  1249.     }
  1250. }
  1251.  
  1252. void
  1253. write_fd (f, r0, c0, rn, cn)
  1254. register FILE *f;
  1255. int r0, c0, rn, cn;
  1256. {
  1257.     register struct ent **pp;
  1258.     register r, c;
  1259.  
  1260.     (void) fprintf (f, "# This data file was generated by the Spreadsheet ");
  1261.     (void) fprintf (f, "Calculator.\n");
  1262.     (void) fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
  1263.     print_options(f);
  1264.     for (c=0; c<maxcols; c++)
  1265.     if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC || realfmt[c] != DEFREFMT )
  1266.         (void) fprintf (f, "format %s %d %d %d\n",coltoa(c),fwidth[c],precision[c],realfmt[c]);
  1267.     for (c=c0; c<cn; c++) {
  1268.         if (col_hidden[c]) {
  1269.             (void) fprintf(f, "hide %s\n", coltoa(c));
  1270.         }
  1271.     }
  1272.     for (r=r0; r<=rn; r++) {
  1273.     if (row_hidden[r]) {
  1274.         (void) fprintf(f, "hide %d\n", r);
  1275.     }
  1276.     }
  1277.  
  1278.     write_range(f);
  1279.  
  1280.     if (mdir) 
  1281.         (void) fprintf(f, "mdir \"%s\"\n", mdir);
  1282.     for (r=r0; r<=rn; r++) {
  1283.     pp = ATBL(tbl, r, c0);
  1284.     for (c=c0; c<=cn; c++, pp++)
  1285.         if (*pp) {
  1286.         if ((*pp)->label) {
  1287.             edits(r,c);
  1288.             (void) fprintf(f, "%s\n",line);
  1289.         }
  1290.         if ((*pp)->flags&is_valid) {
  1291.             editv (r, c);
  1292.             (void) fprintf (f, "%s\n",line);
  1293.         }
  1294.         if ((*pp)->format) {
  1295.             editfmt (r, c);
  1296.             (void) fprintf (f, "%s\n",line);
  1297.         }
  1298.         }
  1299.     }
  1300.     if (rndinfinity)
  1301.     fprintf(f, "set rndinfinity\n");
  1302. }
  1303.  
  1304. int
  1305. writefile (fname, r0, c0, rn, cn)
  1306. char *fname;
  1307. int r0, c0, rn, cn;
  1308. {
  1309.     register FILE *f;
  1310.     char save[PATHLEN];
  1311.     int pid;
  1312.  
  1313. #ifndef VMS
  1314.     if (Crypt) {
  1315.     return (cwritefile(fname, r0, c0, rn, cn));
  1316.     }
  1317. #endif /* VMS */
  1318.  
  1319.     if (*fname == '\0') fname = curfile;
  1320.  
  1321.     (void) strcpy(save,fname);
  1322.  
  1323.     if ((f= openout(fname, &pid)) == (FILE *)0)
  1324.     {    error ("Can't create file \"%s\"", fname);
  1325.     return (-1);
  1326.     }
  1327.  
  1328.     write_fd(f, r0, c0, rn, cn);
  1329.     
  1330.     closeout(f, pid);
  1331.  
  1332.     if (!pid) {
  1333.         (void) strcpy(curfile, save);
  1334.         modflg = 0;
  1335.         error("File \"%s\" written.",curfile);
  1336.     }
  1337.  
  1338.     return (0);
  1339. }
  1340.  
  1341. void
  1342. readfile (fname,eraseflg)
  1343. char *fname;
  1344. int eraseflg;
  1345. {
  1346.     register FILE *f;
  1347.     char save[PATHLEN];
  1348.     int tempautolabel;
  1349.  
  1350.     tempautolabel = autolabel;        /* turn off auto label when */
  1351.     autolabel = 0;            /* when reading a file  */
  1352.  
  1353.     if (*fname == '*' && mdir) { 
  1354.        (void) strcpy(save, mdir);
  1355.        *fname = '/';
  1356.        (void) strcat(save, fname);
  1357.     } else {
  1358.         if (*fname == '\0')
  1359.         fname = curfile;
  1360.         (void) strcpy(save,fname);
  1361.     }
  1362.  
  1363. #ifndef VMS
  1364.     if (Crypt)  {
  1365.     creadfile(save, eraseflg);
  1366.     return;
  1367.     }
  1368. #endif /* VMS */
  1369.  
  1370.     if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;
  1371.  
  1372.     if ((f = fopen(findhome(save), "r")) == (FILE *)0)
  1373.     {    error ("Can't read file \"%s\"", save);
  1374.     return;
  1375.     }
  1376.  
  1377.     if (eraseflg) erasedb ();
  1378.  
  1379.     loading++;
  1380.     while (fgets(line, sizeof(line), f)) {
  1381.     linelim = 0;
  1382.     if (line[0] != '#') (void) yyparse ();
  1383.     }
  1384.     --loading;
  1385.     (void) fclose (f);
  1386.     linelim = -1;
  1387.     modflg++;
  1388.     if (eraseflg) {
  1389.     (void) strcpy(curfile,save);
  1390.     modflg = 0;
  1391.     }
  1392.     autolabel = tempautolabel;
  1393.     EvalAll();
  1394. }
  1395.  
  1396. /* erase the database (tbl, etc.) */
  1397. void
  1398. erasedb ()
  1399. {
  1400.     register r, c;
  1401.     for (c = 0; c<=maxcol; c++) {
  1402.     fwidth[c] = DEFWIDTH;
  1403.     precision[c] = DEFPREC;
  1404.     realfmt[c] = DEFREFMT;
  1405.     }
  1406.  
  1407.     for (r = 0; r<=maxrow; r++) {
  1408.     register struct ent **pp = ATBL(tbl, r, 0);
  1409.     for (c=0; c++<=maxcol; pp++)
  1410.         if (*pp) {
  1411.         if ((*pp)->expr)  efree ((*pp) -> expr);
  1412.         if ((*pp)->label) xfree ((char *)((*pp) -> label));
  1413.         (*pp)->next = freeents;    /* save [struct ent] for reuse */
  1414.         freeents = *pp;
  1415.         *pp = (struct ent *)0;
  1416.         }
  1417.     }
  1418.     maxrow = 0;
  1419.     maxcol = 0;
  1420.     clean_range();
  1421.     FullUpdate++;
  1422. }
  1423.  
  1424. /* moves curcol back one displayed column */
  1425. void
  1426. backcol(arg)
  1427.     int arg;
  1428. {
  1429.     while (--arg>=0) {
  1430.     if (curcol)
  1431.         curcol--;
  1432.     else
  1433.         {error ("At column A"); break;}
  1434.     while(col_hidden[curcol] && curcol)
  1435.         curcol--;
  1436.     }
  1437. }
  1438.  
  1439. /* moves curcol forward one displayed column */
  1440. void
  1441. forwcol(arg)
  1442.     int arg;
  1443. {
  1444.     while (--arg>=0) {
  1445.     if (curcol < maxcols - 1)
  1446.         curcol++;
  1447.     else
  1448.     if (!growtbl(GROWCOL, 0, arg))    /* get as much as needed */
  1449.         break;
  1450.     else
  1451.         curcol++;
  1452.     while(col_hidden[curcol]&&(curcol<maxcols-1))
  1453.         curcol++;
  1454.     }
  1455. }
  1456.  
  1457. /* moves currow forward one displayed row */
  1458. void
  1459. forwrow(arg)
  1460.     int arg;
  1461. {
  1462.     while (--arg>=0) {
  1463.     if (currow < maxrows - 1)
  1464.         currow++;
  1465.     else
  1466.     if (!growtbl(GROWROW, arg, 0))    /* get as much as needed */
  1467.         break;
  1468.     else
  1469.         currow++;
  1470.     while (row_hidden[currow]&&(currow<maxrows-1))
  1471.         currow++;
  1472.     }
  1473. }
  1474.  
  1475. /* moves currow backward one displayed row */
  1476. void
  1477. backrow(arg)
  1478.     int arg;
  1479. {
  1480.     while (--arg>=0) {
  1481.     if (currow)
  1482.         currow--;
  1483.     else
  1484.         {error ("At row zero"); break;}
  1485.     while (row_hidden[currow] && currow)
  1486.         currow--;
  1487.     }
  1488. }
  1489.  
  1490.  
  1491. /*
  1492.  * Show a cell's label string or expression value.  May overwrite value if
  1493.  * there is one already displayed in the cell.  Created from old code in
  1494.  * update(), copied with minimal changes.
  1495.  */
  1496.  
  1497. void
  1498. showstring (string, leftflush, hasvalue, row, col, nextcolp, mxcol, fieldlenp, r, c)
  1499.     char *string;    /* to display */
  1500.     int leftflush;    /* or rightflush */
  1501.     int hasvalue;    /* is there a numeric value? */
  1502.     int row, col;    /* spreadsheet location */
  1503.     int *nextcolp;    /* value returned through it */
  1504.     int mxcol;        /* last column displayed? */
  1505.     int *fieldlenp;    /* value returned through it */
  1506.     int r, c;        /* screen row and column */
  1507. {
  1508.     register int nextcol  = *nextcolp;
  1509.     register int fieldlen = *fieldlenp;
  1510.  
  1511.     char field[FBUFLEN];
  1512.     int  slen;
  1513.     char *start, *last;
  1514.     register char *fp;
  1515.     struct ent *nc;
  1516.  
  1517.     /* This figures out if the label is allowed to
  1518.        slop over into the next blank field */
  1519.  
  1520.     slen = strlen (string);
  1521.     while ((slen > fieldlen) && (nextcol <= mxcol) &&
  1522.        !((nc = lookat (row, nextcol)) -> flags & is_valid) &&
  1523.        !(nc->label)) {
  1524.  
  1525.     if (! col_hidden [nextcol])
  1526.         fieldlen += fwidth [nextcol];
  1527.  
  1528.     nextcol++;
  1529.     }
  1530.     if (slen > fieldlen)
  1531.     slen = fieldlen;
  1532.  
  1533.     /* Now justify and print */
  1534.     start = leftflush ? field : field + fieldlen - slen;
  1535.     last = field+fieldlen;
  1536.     fp = field;
  1537.     while (fp < start)
  1538.     *fp++ = ' ';
  1539.     while (slen--)
  1540.     *fp++ = *string++;
  1541.     if ((! hasvalue) || fieldlen != fwidth[col]) 
  1542.     while (fp < last)
  1543.         *fp++ = ' ';
  1544.     *fp = '\0';
  1545. #ifdef VMS
  1546.     mvaddstr(r, c, field);    /* this is a macro */
  1547. #else
  1548.     (void) mvaddstr(r, c, field);
  1549. #endif
  1550.  
  1551.     *nextcolp  = nextcol;
  1552.     *fieldlenp = fieldlen;
  1553. }
  1554.  
  1555. int
  1556. etype(e)
  1557. register struct enode *e;
  1558. {
  1559.     if (e == (struct enode *)0)
  1560.     return NUM;
  1561.     switch (e->op) {
  1562.     case O_SCONST: case '#': case DATE: case FMT: case STINDEX:
  1563.     case EXT: case SVAL: case SUBSTR:
  1564.         return (STR);
  1565.  
  1566.     case '?':
  1567.     case IF:
  1568.         return(etype(e->e.o.right->e.o.left));
  1569.  
  1570.     case 'f':
  1571.         return(etype(e->e.o.right));
  1572.  
  1573.     case O_VAR: {
  1574.     register struct ent *p;
  1575.     p = e->e.v.vp;
  1576.     if (p->expr) 
  1577.         return(p->flags & is_strexpr ? STR : NUM);
  1578.     else if (p->label)
  1579.         return(STR);
  1580.     else
  1581.         return(NUM);
  1582.     }
  1583.  
  1584.     default:
  1585.     return(NUM);
  1586.     }
  1587. }
  1588.  
  1589. /* return 1 if yes given, 0 otherwise */
  1590. int
  1591. yn_ask(msg)
  1592. char    *msg;
  1593. {    char ch;
  1594.  
  1595.     (void) move (0, 0);
  1596.     (void) clrtoeol ();
  1597.     (void) addstr (msg);
  1598.     (void) refresh();
  1599.     ch = nmgetch();
  1600.     if ( ch != 'y' && ch != 'Y' && ch != 'n' && ch != 'N' ) {
  1601.         if (ch == ctl('g') || ch == ESC)
  1602.             return(-1);
  1603.         error("y or n response required");
  1604.         return (-1);
  1605.     }
  1606.     if (ch == 'y' || ch == 'Y')
  1607.         return(1);
  1608.     else
  1609.         return(0);
  1610. }
  1611.  
  1612. /* expand a ~ in a path to your home directory */
  1613. #include <pwd.h>
  1614. char    *
  1615. findhome(path)
  1616. char    *path;
  1617. {
  1618.     static    char    *HomeDir = NULL;
  1619.     extern    char    *getenv();
  1620.  
  1621.     if (*path == '~')
  1622.     {    char    *pathptr;
  1623.         char    tmppath[PATHLEN];
  1624.  
  1625.         if (HomeDir == NULL)
  1626.         {    HomeDir = getenv("HOME");
  1627.             if (HomeDir == NULL)
  1628.                 HomeDir = "/";
  1629.         }
  1630.         pathptr = path + 1;
  1631.         if ((*pathptr == '/') || (*pathptr == '\0'))
  1632.         {    strcpy(tmppath, HomeDir);
  1633.         }
  1634.         else
  1635.         {    struct    passwd *pwent;
  1636.             extern    struct    passwd *getpwnam();
  1637.             char    *namep;
  1638.             char    name[50];
  1639.  
  1640.             namep = name;
  1641.             while ((*pathptr != '\0') && (*pathptr != '/'))
  1642.                 *(namep++) = *(pathptr++);
  1643.             *namep = '\0';
  1644.             if ((pwent = getpwnam(name)) == NULL)
  1645.             {    (void) sprintf(path, "Can't find user %s", name);
  1646.                 return(NULL);
  1647.             }
  1648.             strcpy(tmppath, pwent->pw_dir);
  1649.         }
  1650.  
  1651.         strcat(tmppath, pathptr);
  1652.         strcpy(path, tmppath);
  1653.     }
  1654.     return(path);
  1655. }
  1656.  
  1657. #ifdef DOBACKUPS
  1658. #include <sys/stat.h>
  1659.  
  1660. /*
  1661.  * make a backup copy of a file, use the same mode and name in the format
  1662.  * [path/]#file~
  1663.  * return 1 if we were successful, 0 otherwise
  1664.  */
  1665. int
  1666. backup_file(path)
  1667. char    *path;
  1668. {
  1669.     struct    stat    statbuf;
  1670.     char    fname[PATHLEN];
  1671.     char    tpath[PATHLEN];
  1672. #ifdef sequent
  1673.     static    char    *buf = NULL;
  1674.     static    unsigned buflen = 0;
  1675. #else
  1676.     char    buf[BUFSIZ];
  1677. #endif
  1678.     char    *tpp;
  1679.     int    infd, outfd;
  1680.     int    count;
  1681.  
  1682.     /* tpath will be the [path/]file ---> [path/]#file~ */
  1683.     strcpy(tpath, path);
  1684.     if ((tpp = strrchr(tpath, '/')) == NULL)
  1685.         tpp = tpath;
  1686.     else
  1687.         tpp++;
  1688.     strcpy(fname, tpp);
  1689.     (void) sprintf(tpp, "#%s~", fname);
  1690.  
  1691.     if (stat(path, &statbuf) == 0)
  1692.     {
  1693.         /* if we know the optimum block size, use it */
  1694. #ifdef sequent
  1695.         if ((statbuf.st_blksize > buflen) || (buf == NULL))
  1696.         {    buflen = statbuf.st_blksize;
  1697.             if ((buf = xrealloc(buf, buflen)) == (char *)0)
  1698.             {    buflen = 0;
  1699.                 return(0);
  1700.             }
  1701.         }
  1702. #endif
  1703.  
  1704.         if ((infd = open(path, O_RDONLY, 0)) < 0)
  1705.             return(0);
  1706.  
  1707.         if ((outfd = open(tpath, O_TRUNC|O_WRONLY|O_CREAT,
  1708.                     statbuf.st_mode)) < 0)
  1709.             return(0);
  1710.  
  1711. #ifdef sequent
  1712.         while((count = read(infd, buf, statbuf.st_blksize)) > 0)
  1713. #else
  1714.         while((count = read(infd, buf, sizeof(buf))) > 0)
  1715. #endif
  1716.         {    if (write(outfd, buf, count) != count)
  1717.             {    count = -1;
  1718.                 break;
  1719.             }
  1720.         }
  1721.         close(infd);
  1722.         close(outfd);
  1723.  
  1724.         return((count < 0) ? 0 : 1);
  1725.     }
  1726.     else
  1727.     if (errno == ENOENT)
  1728.         return(1);
  1729.     return(0);
  1730. }
  1731. #endif
  1732.