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