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