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