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