home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / EFFO / pd7.lzh / SRC / cmds.c < prev    next >
Text File  |  1990-04-01  |  34KB  |  1,422 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.1 $
  11.  */
  12.  
  13. #ifdef OSK
  14. extern char fmt[];
  15. extern int os9forkc();
  16. extern char **environ;
  17. #endif
  18.  
  19. #include <curses.h>
  20. #include "sc.h"
  21. #include <signal.h>
  22.  
  23. #if defined(BSD42) || defined(OSK)
  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. #define DEFCOLDELIM ':'
  38.  
  39. void syncref();
  40. void copyent();
  41.  
  42. void duprow()
  43. {
  44.     if (currow >= MAXROWS - 1 || maxrow >= MAXROWS - 1) {
  45.         error ("The table can't be any bigger");
  46.         return;
  47.     }
  48.     modflg++;
  49.     currow++;
  50.     openrow (currow);
  51.     for (curcol = 0; curcol <= maxcol; curcol++) {
  52.         register struct ent *p = tbl[currow - 1][curcol];
  53.         if (p) {
  54.             register struct ent *n;
  55.             n = lookat (currow, curcol);
  56.             copyent ( n, p, 1, 0);
  57.         }
  58.     }
  59.     for (curcol = 0; curcol <= maxcol; curcol++) {
  60.         register struct ent *p = 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 dupcol()
  69. {
  70.     if (curcol >= MAXCOLS - 1 || maxcol >= MAXCOLS - 1) {
  71.         error ("The table can't be any wider");
  72.         return;
  73.     }
  74.     modflg++;
  75.     curcol++;
  76.     opencol (curcol);
  77.     for (currow = 0; currow <= maxrow; currow++) {
  78.         register struct ent *p = tbl[currow][curcol - 1];
  79.         if (p) {
  80.             register struct ent *n;
  81.             n = lookat (currow, curcol);
  82.             copyent ( n, p, 0, 1);
  83.         }
  84.     }
  85.     for (currow = 0; currow <= maxrow; currow++) {
  86.         register struct ent *p = tbl[currow][curcol];
  87.         if (p && (p -> flags & is_valid) && !p -> expr)
  88.             break;
  89.     }
  90.     if (currow > maxrow)
  91.         currow = 0;
  92. }
  93.  
  94. insertrow(arg)
  95. register int arg;
  96. {
  97.     while (--arg>=0) openrow (currow);
  98. }
  99.  
  100. deleterow(arg)
  101. register int arg;
  102. {
  103.     flush_saved();
  104.     erase_area(currow, 0, currow + arg - 1, maxcol);
  105.     currow += arg;
  106.     while (--arg>=0) closerow (--currow);
  107.     sync_refs();
  108. }
  109.  
  110. insertcol(arg)
  111. register int arg;
  112. {
  113.     while (--arg>=0) opencol(curcol);
  114. }
  115.  
  116. deletecol(arg)
  117. register int arg;
  118. {
  119.     flush_saved();
  120.     erase_area(0, curcol, maxrow, curcol + arg - 1);
  121.     curcol += arg;
  122.     while (--arg>=0) closecol (--curcol);
  123.     sync_refs();
  124. }
  125.  
  126. rowvalueize(arg)
  127. register int arg;
  128. {
  129.     valueize_area(currow, 0, currow + arg - 1, maxcol);
  130. }
  131.  
  132. colvalueize(arg)
  133. register int arg;
  134. {
  135.     valueize_area(0, curcol, maxrow, curcol + arg - 1);
  136. }
  137.  
  138. erase_area(sr, sc, er, ec)
  139. int sr, sc, er, ec;
  140. {
  141.     register int r, c;
  142.     register struct ent **p;
  143.  
  144.     if (sr > er) {
  145.         r = sr; sr = er; er= r;
  146.     }
  147.  
  148.     if (sc > ec) {
  149.         c = sc; sc = ec; ec= c;
  150.     }
  151.  
  152.     if (sr < 0)
  153.         sr = 0;
  154.     if (sc < 0)
  155.         sc = 0;
  156.     if (er >= MAXROWS)
  157.         er = MAXROWS-1;
  158.     if (ec >= MAXCOLS)
  159.         ec = MAXCOLS-1;
  160.  
  161.     for (r = sr; r <= er; r++) {
  162.         for (c = sc; c <= ec; c++) {
  163.             p = &tbl[r][c];
  164.             if (*p) {
  165.                 free_ent(*p);
  166.                 *p = 0;
  167.             }
  168.         }
  169.     }
  170.  
  171. }
  172.  
  173. valueize_area(sr, sc, er, ec)
  174. int sr, sc, er, ec;
  175. {
  176.     register int r, c;
  177.     register struct ent *p;
  178.  
  179.     if (sr > er) {
  180.         r = sr; sr = er; er= r;
  181.     }
  182.  
  183.     if (sc > ec) {
  184.         c = sc; sc = ec; ec= c;
  185.     }
  186.  
  187.     if (sr < 0)
  188.         sr = 0;
  189.     if (sc < 0)
  190.         sc = 0;
  191.     if (er >= MAXROWS)
  192.         er = MAXROWS-1;
  193.     if (ec >= MAXCOLS)
  194.         ec = MAXCOLS-1;
  195.  
  196.     for (r = sr; r <= er; r++) {
  197.         for (c = sc; c <= ec; c++) {
  198.             p = tbl[r][c];
  199.             if (p && p->expr) {
  200.                 efree(p->expr);
  201.                 p->expr = 0;
  202.                 p->flags &= ~is_strexpr;
  203.             }
  204.         }
  205.     }
  206.  
  207. }
  208.  
  209. void pullcells(to_insert)
  210. int to_insert;
  211. {
  212.     register struct ent *p, *n;
  213.     register int deltar, deltac;
  214.     int minrow, mincol;
  215.     int mxrow, mxcol;
  216.     int numrows, numcols;
  217.  
  218.     if (! to_fix)
  219.     {
  220.         error ("No data to pull");
  221.         return;
  222.     }
  223.  
  224.     minrow = MAXROWS;
  225.     mincol = MAXCOLS;
  226.     mxrow = 0;
  227.     mxcol = 0;
  228.  
  229.     for (p = to_fix; p; p = p->next) {
  230.         if (p->row < minrow)
  231.             minrow = p->row;
  232.         if (p->row > mxrow)
  233.             mxrow = p->row;
  234.         if (p->col < mincol)
  235.             mincol = p->col;
  236.         if (p->col > mxcol)
  237.             mxcol = p->col;
  238.     }
  239.  
  240.     numrows = mxrow - minrow + 1;
  241.     numcols = mxcol - mincol + 1;
  242.     deltar = currow - minrow;
  243.     deltac = curcol - mincol;
  244.  
  245.     if (to_insert == 'r') {
  246.         insertrow(numrows);
  247.         deltac = 0;
  248.     } else if (to_insert == 'c') {
  249.         insertcol(numcols);
  250.         deltar = 0;
  251.     }
  252.  
  253.     FullUpdate++;
  254.     modflg++;
  255.  
  256.     for (p = to_fix; p; p = p->next) {
  257.         n = lookat (p->row + deltar, p->col + deltac);
  258.         (void) clearent(n);
  259.         copyent( n, p, deltar, deltac);
  260.         n -> flags = p -> flags & ~is_deleted;
  261.     }
  262. }
  263.  
  264. colshow_op()
  265. {
  266.     register int i,j;
  267.     for (i=0; i<MAXCOLS; i++)
  268.         if (col_hidden[i])
  269.             break;
  270.     for(j=i; j<MAXCOLS; j++)
  271.         if (!col_hidden[j])
  272.             break;
  273.     j--;
  274.     if (i>=MAXCOLS)
  275.         error ("No hidden columns to show");
  276.     else {
  277.         (void) sprintf(line,"show %s:", coltoa(i));
  278.         (void) sprintf(line + strlen(line),"%s",coltoa(j));
  279.         linelim = strlen (line);
  280.     }
  281. }
  282.  
  283. rowshow_op()
  284. {
  285.     register int i,j;
  286.     for (i=0; i<MAXROWS; i++)
  287.         if (row_hidden[i])
  288.             break;
  289.     for(j=i; j<MAXROWS; j++)
  290.         if (!row_hidden[j]) {
  291.             break;
  292.         }
  293.     j--;
  294.  
  295.     if (i>=MAXROWS)
  296.         error ("No hidden rows to show");
  297.     else {
  298.         (void) sprintf(line,"show %d:%d", i, j);
  299.         linelim = strlen (line);
  300.     }
  301. }
  302.  
  303. /*
  304.  * Given a row/column command letter, emit a small menu, then read a qualifier
  305.  * character for a row/column command and convert it to 'r' (row), 'c'
  306.  * (column), or 0 (unknown).  If ch is 'p', an extra qualifier 'm' is allowed.
  307.  */
  308.  
  309. get_rcqual (ch)
  310.     int ch;
  311. {
  312.     error ("%sow/column:  r: row  c: column%s",
  313.  
  314.             (ch == 'i') ? "Insert r" :
  315.             (ch == 'a') ? "Append r" :
  316.             (ch == 'd') ? "Delete r" :
  317.             (ch == 'p') ? "Pull r" :
  318.             (ch == 'v') ? "Values r" :
  319.             (ch == 'z') ? "Zap r" :
  320.             (ch == 's') ? "Show r" : "R",
  321.  
  322.             (ch == 'p') ? "  m: merge" : "");
  323.  
  324.     (void) refresh();
  325.  
  326.     switch (nmgetch())
  327.     {
  328.         case 'r':
  329.         case 'l':
  330.         case 'h':
  331.         case ctl(f):
  332.         case ctl(b):    return ('r');
  333.  
  334.         case 'c':
  335.         case 'j':
  336.         case 'k':
  337.         case ctl(p):
  338.         case ctl(n):    return ('c');
  339.  
  340.         case 'm':       return ((ch == 'p') ? 'm' : 0);
  341.  
  342.         case ESC:
  343.         case ctl (g):   return (ESC);
  344.  
  345.         default:        return (0);
  346.     }
  347.     /*NOTREACHED*/
  348. }
  349.  
  350. openrow (rs)
  351. int rs;
  352. {
  353.     register    r;
  354.     register struct ent **p;
  355.     register    c;
  356.     register    i;
  357.  
  358.     if (rs > maxrow) maxrow = rs;
  359.     if (maxrow >= MAXROWS - 1 || rs > MAXROWS - 1) {
  360.         error ("The table can't be any longer");
  361.         return(0);
  362.     }
  363.     for (i = maxrow+1; i > rs; i--) {
  364.         row_hidden[i] = row_hidden[i-1];
  365.     }
  366.     for (r = ++maxrow; r > rs; r--)
  367.         for (c = maxcol + 1, p = &tbl[r][0]; --c >= 0; p++)
  368.             if (p[0] = p[-MAXCOLS])
  369.                 p[0] -> row++;
  370.     p = &tbl[rs][0];
  371.     for (c = maxcol + 1; --c >= 0;)
  372.         *p++ = 0;
  373.     FullUpdate++;
  374.     modflg++;
  375. }
  376.  
  377. closerow (r)
  378. register r;
  379. {
  380.     register struct ent **p;
  381.     register c;
  382.     register int i;
  383.  
  384.     if (r > maxrow) return(0);
  385.  
  386.     p = &tbl[r][0];
  387.     for (c=maxcol+1; --c>=0; ) {
  388.         if (*p)
  389.             free_ent(*p);
  390.         *p++ = 0;
  391.     }
  392.  
  393.     for (i = r; i < MAXROWS - 1; i++) {
  394.         row_hidden[i] = row_hidden[i+1];
  395.     }
  396.  
  397.     while (r<maxrow) {
  398.         for (c = maxcol+1, p = &tbl[r][0]; --c>=0; p++)
  399.             if (p[0] = p[MAXCOLS])
  400.                 p[0]->row--;
  401.         r++;
  402.     }
  403.  
  404.     p = &tbl[maxrow][0];
  405.     for (c=maxcol+1; --c>=0; ) *p++ = 0;
  406.     maxrow--;
  407.     FullUpdate++;
  408.     modflg++;
  409. }
  410.  
  411. opencol (cs)
  412. int cs;
  413. {
  414.     register r;
  415.     register struct ent **p;
  416.     register c;
  417.     register lim = maxcol-cs+1;
  418.     int i;
  419.  
  420.     if (cs > maxcol) maxcol = cs;
  421.     if (maxcol >= MAXCOLS - 1 || cs > MAXCOLS - 1) {
  422.         error ("The table can't be any wider");
  423.         return(0);
  424.     }
  425.     for (i = maxcol+1; i > cs; i--) {
  426.         fwidth[i] = fwidth[i-1];
  427.         precision[i] = precision[i-1];
  428.         col_hidden[i] = col_hidden[i-1];
  429.     }
  430.     /* fwidth[cs] = DEFWIDTH;
  431.     precision[i] =  DEFPREC;  */
  432.  
  433.     for (r=0; r<=maxrow; r++) {
  434.         p = &tbl[r][maxcol+1];
  435.         for (c=lim; --c>=0; p--)
  436.             if (p[0] = p[-1])
  437.                 p[0]->col++;
  438.         p[0] = 0;
  439.     }
  440.     maxcol++;
  441.     FullUpdate++;
  442.     modflg++;
  443. }
  444.  
  445. closecol (cs)
  446. int cs;
  447. {
  448.     register r;
  449.     register struct ent **p;
  450.     register struct ent *q;
  451.     register c;
  452.     register lim = maxcol-cs;
  453.     int i;
  454.  
  455.     if (lim < 0) return(0);
  456.  
  457.     for (r=0; r<=maxrow; r++)
  458.         if (q = tbl[r][cs]) {
  459.             free_ent(q);
  460.         }
  461.  
  462.     for (r=0; r<=maxrow; r++) {
  463.         p = &tbl[r][cs];
  464.         for (c=lim; --c>=0; p++)
  465.             if (p[0] = p[1])
  466.                 p[0]->col--;
  467.         p[0] = 0;
  468.     }
  469.  
  470.     for (i = cs; i < MAXCOLS - 1; i++) {
  471.         fwidth[i] = fwidth[i+1];
  472.         precision[i] = precision[i+1];
  473.         col_hidden[i] = col_hidden[i+1];
  474.     }
  475.  
  476.     maxcol--;
  477.     FullUpdate++;
  478.     modflg++;
  479. }
  480.  
  481. void doend(rowinc, colinc)
  482. int rowinc, colinc;
  483. {
  484.     register struct ent *p;
  485.     int r, c;
  486.  
  487.     if (VALID_CELL(p, currow, curcol)) {
  488.         r = currow + rowinc;
  489.         c = curcol + colinc;
  490.         if (r >= 0 && r < MAXROWS &&
  491.             c >= 0 && c < MAXCOLS &&
  492.             !VALID_CELL(p, r, c)) {
  493.                 currow = r;
  494.                 curcol = c;
  495.         }
  496.     }
  497.  
  498.     if (!VALID_CELL(p, currow, curcol)) {
  499.         switch (rowinc) {
  500.         case -1:
  501.             while (!VALID_CELL(p, currow, curcol) && currow > 0)
  502.                 currow--;
  503.             break;
  504.         case  1:
  505.             while (!VALID_CELL(p, currow, curcol) && currow < MAXROWS-1)
  506.                 currow++;
  507.             break;
  508.         case  0:
  509.             switch (colinc) {
  510.             case -1:
  511.                 while (!VALID_CELL(p, currow, curcol) && curcol > 0)
  512.                     curcol--;
  513.                 break;
  514.             case  1:
  515.                 while (!VALID_CELL(p, currow, curcol) && curcol < MAXCOLS-1)
  516.                     curcol++;
  517.                 break;
  518.             }
  519.             break;
  520.         }
  521.  
  522.         error ("");     /* clear line */
  523.         return;
  524.     }
  525.  
  526.     switch (rowinc) {
  527.     case -1:
  528.         while (VALID_CELL(p, currow, curcol) && currow > 0)
  529.             currow--;
  530.         break;
  531.     case  1:
  532.         while (VALID_CELL(p, currow, curcol) && currow < MAXROWS-1)
  533.             currow++;
  534.         break;
  535.     case  0:
  536.         switch (colinc) {
  537.         case -1:
  538.             while (VALID_CELL(p, currow, curcol) && curcol > 0)
  539.                 curcol--;
  540.             break;
  541.         case  1:
  542.             while (VALID_CELL(p, currow, curcol) && curcol < MAXCOLS-1)
  543.                 curcol++;
  544.             break;
  545.         }
  546.         break;
  547.     }
  548.     if (!VALID_CELL(p, currow, curcol)) {
  549.         currow -= rowinc;
  550.         curcol -= colinc;
  551.     }
  552. }
  553.  
  554. doformat(c1,c2,w,p)
  555. int c1,c2,w,p;
  556. {
  557.     register int i;
  558.  
  559.     if (w > COLS - RESCOL - 2) {
  560.         error("Format too large - Maximum = %d", COLS - RESCOL - 2);
  561.         w = COLS-RESCOL-2;
  562.     }
  563.  
  564.     if (p > w) {
  565.         error("Precision too large");
  566.         p = w;
  567.     }
  568.  
  569.     for(i = c1; i<=c2; i++)
  570.         fwidth[i] = w, precision[i] = p;
  571.  
  572.     FullUpdate++;
  573.     modflg++;
  574. }
  575.  
  576. void print_options(f)
  577. FILE* f;
  578. {
  579.     if(
  580.        autocalc &&
  581.        propagation == 10 &&
  582.        calc_order == BYROWS &&
  583.        !numeric &&
  584.        prescale == 1.0 &&
  585.        !extfunc &&
  586.        showcell &&
  587.        showtop &&
  588.        tbl_style == 0
  589.       )
  590.                 return;         /* No reason to do this */
  591.  
  592.     (void) fprintf(f, "set");
  593.     if(!autocalc)
  594.         (void) fprintf(f," !autocalc");
  595.     if(propagation != 10)
  596.         (void) fprintf(f, " iterations = %d", propagation);
  597.     if(calc_order != BYROWS )
  598.         (void) fprintf(f, " bycols");
  599.     if (numeric)
  600.         (void) fprintf(f, " numeric");
  601.     if (prescale != 1.0)
  602.         (void) fprintf(f, " prescale");
  603.     if (extfunc)
  604.         (void) fprintf(f, " extfun");
  605.     if (!showcell)
  606.         (void) fprintf(f, " !cellcur");
  607.     if (!showtop)
  608.         (void) fprintf(f, " !toprow");
  609.     if (tbl_style)
  610.         (void) fprintf(f, " tblstyle = %s", tbl_style == TBL ? "tbl" :
  611.                                         tbl_style == LATEX ? "latex" :
  612.                                         tbl_style == TEX ? "tex" : "0" );
  613.     (void) fprintf(f, "\n");
  614. }
  615.  
  616. void printfile (fname, r0, c0, rn, cn)
  617. char *fname;
  618. int r0, c0, rn, cn;
  619. {
  620.     FILE *f;
  621.     char pline[1000];
  622.     int plinelim;
  623.     int pid;
  624.     int fieldlen, nextcol;
  625.     register row, col;
  626.     register struct ent **p;
  627.     char ch, lin[100];
  628.  
  629.     if (strcmp(fname, curfile) == 0) {
  630.         (void) move (0, 0);
  631.         (void) clrtoeol ();
  632.         (void) sprintf (lin,
  633.                 "Confirm that you want to destroy the data base: (y,n)");
  634.         (void) addstr (lin);
  635.         (void) refresh();
  636.         ch = nmgetch();
  637.         if (ch != 'y' && ch != 'Y')
  638.             return;
  639.     }
  640.  
  641.     f = openout(fname, &pid);
  642.  
  643.     if (f==0) {
  644.         error ("Can't create file \"%s\"", fname);
  645.         return;
  646.     }
  647.     for (row=r0;row<=rn; row++) {
  648.         register c = 0;
  649.  
  650.         if (row_hidden[row])
  651.             continue;
  652.  
  653.         pline[plinelim=0] = '\0';
  654.         for (p = &tbl[row][col=c0]; col<=cn;
  655.                 p += nextcol-col, col = nextcol, c += fieldlen) {
  656.  
  657.             nextcol = col+1;
  658.             if (col_hidden[col]) {
  659.                 fieldlen = 0;
  660.                 continue;
  661.             }
  662.  
  663.             fieldlen = fwidth[col];
  664.             if (*p) {
  665.                 char *s;
  666.  
  667.                 while (plinelim<c) pline[plinelim++] = ' ';
  668.                 plinelim = c;
  669.                 if ((*p)->flags&is_valid) {
  670. #ifdef OSK
  671.                     sprintf(fmt,"%%%d.%df",fwidth[col],precision[col]);
  672.                     (void)sprintf (pline+plinelim,fmt, (*p)->v);
  673. #else
  674.                     (void)sprintf (pline+plinelim,"%*.*f",fwidth[col],
  675.                                                 precision[col], (*p)->v);
  676. #endif
  677.                     plinelim += strlen (pline+plinelim);
  678.                 }
  679.                 if (s = (*p)->label) {
  680.                     int slen;
  681.                     char *start, *last;
  682.                     register char *fp;
  683.                     struct ent *nc;
  684.  
  685.                     /* Figure out if the label slops over to a blank field */
  686.                     slen = strlen(s);
  687.                     while (slen > fieldlen && nextcol <= cn &&
  688.                             !((nc = lookat(row,nextcol))->flags & is_valid) &&
  689.                             !(nc->label)) {
  690.  
  691.                         if (!col_hidden[nextcol])
  692.                             fieldlen += fwidth[nextcol];
  693.  
  694.                         nextcol++;
  695.                     }
  696.                     if (slen > fieldlen)
  697.                         slen = fieldlen;
  698.  
  699.                     /* Now justify and print */
  700.                     start = (*p)->flags & is_leftflush ? pline + c
  701.                                         : pline + c + fieldlen - slen;
  702.                     last = pline + c + fieldlen;
  703.                     fp = plinelim < c ? pline + plinelim : pline + c;
  704.                     while (fp < start)
  705.                         *fp++ = ' ';
  706.                     while (slen--)
  707.                         *fp++ = *s++;
  708.                     if (!((*p)->flags & is_valid) || fieldlen != fwidth[col])
  709.                         while(fp < last)
  710.                             *fp++ = ' ';
  711.                     if (plinelim < fp - pline)
  712.                         plinelim = fp - pline;
  713.                 }
  714.             }
  715.         }
  716.         pline[plinelim++] = '\n';
  717.         pline[plinelim] = 0;
  718.         (void) fputs (pline, f);
  719.     }
  720.  
  721.     closeout(f, pid);
  722. }
  723.  
  724. void tblprintfile (fname, r0, c0, rn, cn)
  725. char *fname;
  726. int r0, c0, rn, cn;
  727. {
  728.     FILE *f;
  729.     int pid;
  730.     register row, col;
  731.     register struct ent **p;
  732.     char coldelim = DEFCOLDELIM;
  733.     char ch, lin[100];
  734.  
  735.     if (strcmp(fname, curfile) == 0) {
  736.         (void) move (0, 0);
  737.         (void) clrtoeol ();
  738.         (void) sprintf (lin,
  739.                 "Confirm that you want to destroy the data base: (y,n)");
  740.         (void) addstr (lin);
  741.         (void) refresh();
  742.         ch = nmgetch();
  743.         if (ch != 'y' && ch != 'Y')
  744.             return;
  745.     }
  746.  
  747.     f = openout(fname, &pid);
  748.  
  749.     if (f==0) {
  750.         error ("Can't create file \"%s\"", fname);
  751.         return;
  752.     }
  753.  
  754.     if ( tbl_style == TBL ) {
  755.         fprintf(f,".\\\" ** %s spreadsheet output \n.TS\n",progname);
  756.         fprintf(f,"tab(%c);\n",coldelim);
  757.         for (col=c0;col<=cn; col++) fprintf(f," n");
  758.         fprintf(f, ".\n");
  759.         }
  760.     else if ( tbl_style == LATEX ) {
  761.         fprintf(f,"%% ** %s spreadsheet output\n\\begin{tabular}{",progname);
  762.         for (col=c0;col<=cn; col++) fprintf(f,"c");
  763.         fprintf(f, "}\n");
  764.         coldelim = '&';
  765.         }
  766.     else if ( tbl_style == TEX ) {
  767.         fprintf(f,"{\t%% ** %s spreadsheet output\n\\settabs %d \\columns\n",
  768.                 progname, cn-c0+1);
  769.         coldelim = '&';
  770.         }
  771.  
  772.     for (row=r0; row<=rn; row++) {
  773.         if ( tbl_style == TEX )
  774.             (void) fprintf (f, "\\+");
  775.  
  776.         for (p = &tbl[row][col=c0]; col<=cn; col++, p++) {
  777.             if (*p) {
  778.                 char *s;
  779.                 if ((*p)->flags&is_valid) {
  780. #ifdef OSK
  781.                     sprintf(fmt,"%%.%df",precision[col]);
  782.                     (void) fprintf (f,fmt,(*p)->v);
  783. #else
  784.                     (void) fprintf (f,"%.*f",precision[col],(*p)->v);
  785. #endif
  786.                 }
  787.                 if (s = (*p)->label) {
  788.                     (void) fprintf (f,"%s",s);
  789.                 }
  790.             }
  791.             if ( col < cn )
  792.                 (void) fprintf(f,"%c",coldelim);
  793.         }
  794.         if ( tbl_style == LATEX ) {
  795.             if ( row < rn ) (void) fprintf (f, "\\\\");
  796.             }
  797.         else if ( tbl_style == TEX ) {
  798.             (void) fprintf (f, "\\cr");
  799.             }
  800.         (void) fprintf (f,"\n");
  801.     }
  802.  
  803.     if ( tbl_style == TBL )
  804.     (void) fprintf (f,".TE\n.\\\" ** end of %s spreadsheet output\n", progname);
  805.     else if ( tbl_style == LATEX )
  806.     (void) fprintf (f,"\\end{tabular}\n%% ** end of %s spreadsheet output\n", progname);
  807.     else if ( tbl_style == TEX )
  808.     (void) fprintf (f,"}\n%% ** end of %s spreadsheet output\n", progname);
  809.  
  810.     closeout(f, pid);
  811. }
  812.  
  813. struct enode *
  814. copye (e, Rdelta, Cdelta)
  815. register struct enode *e;
  816. int Rdelta, Cdelta;
  817. {
  818.     register struct enode *ret;
  819.     if (e==0) {
  820.         ret = 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 = 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.  
  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=tbl[i][j]) && p->expr)
  887.                 syncref(p->expr);
  888. }
  889.  
  890.  
  891. void syncref(e)
  892. register struct enode *e;
  893. {
  894.     if (e==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 hiderow(arg)
  917. int arg;
  918. {
  919.     register int r1;
  920.     register int r2;
  921.  
  922.     r1 = currow;
  923.     r2 = r1 + arg - 1;
  924.     if (r1 < 0 || r1 > r2) {
  925.         error ("Invalid range");
  926.         return;
  927.     }
  928.     if (r2 > MAXROWS-2) {
  929.         error ("You can't hide the last row");
  930.         return;
  931.     }
  932.     FullUpdate++;
  933.     while (r1 <= r2)
  934.         row_hidden[r1++] = 1;
  935. }
  936.  
  937. void hidecol(arg)
  938. int arg;
  939. {
  940.     register int c1;
  941.     register int c2;
  942.  
  943.     c1 = curcol;
  944.     c2 = c1 + arg - 1;
  945.     if (c1 < 0 || c1 > c2) {
  946.         error ("Invalid range");
  947.         return;
  948.     }
  949.     if (c2 > MAXCOLS-2) {
  950.         error ("You can't hide the last column");
  951.         return;
  952.     }
  953.     FullUpdate++;
  954.     while (c1 <= c2)
  955.         col_hidden[c1++] = 1;
  956. }
  957.  
  958. void showrow(r1, r2)
  959. int r1, r2;
  960. {
  961.     if (r1 < 0 || r1 > r2) {
  962.         error ("Invalid range");
  963.         return;
  964.     }
  965.     if (r2 > MAXROWS-1) {
  966.         r2 = MAXROWS-1;
  967.     }
  968.     FullUpdate++;
  969.     while (r1 <= r2)
  970.         row_hidden[r1++] = 0;
  971. }
  972.  
  973. void showcol(c1, c2)
  974. int c1, c2;
  975. {
  976.     if (c1 < 0 || c1 > c2) {
  977.         error ("Invalid range");
  978.         return;
  979.     }
  980.     if (c2 > MAXCOLS-1) {
  981.         c2 = MAXCOLS-1;
  982.     }
  983.     FullUpdate++;
  984.     while (c1 <= c2)
  985.         col_hidden[c1++] = 0;
  986. }
  987.  
  988. /* Open the output file, setting up a pipe if needed */
  989.  
  990. FILE *
  991. openout(fname, rpid)
  992. char *fname;
  993. int *rpid;
  994. {
  995.     int pipefd[2];
  996.     int pid;
  997.     FILE *f;
  998. #ifdef OSK
  999.     int save_stdin;
  1000.     char *argblk[4];
  1001.     int pipe;
  1002. #endif
  1003.  
  1004.     while (*fname && (*fname == ' '))  /* Skip leading blanks */
  1005.         fname++;
  1006.  
  1007.     if ((*fname != '|') && (*fname != '!')) {  /* Open file if not pipe */
  1008.         *rpid = 0;
  1009.         return(fopen(fname, "w"));
  1010.     }
  1011.  
  1012.     fname++;                            /* Skip |/! */
  1013. #ifndef OSK
  1014.     if ( pipe (pipefd) < 0) {
  1015. #else
  1016.     if ((f = fopen("/pipe","w+")) == (FILE *) -1) {
  1017. #endif
  1018.         error("Can't make pipe to child");
  1019.         *rpid = 0;
  1020.         return(0);
  1021.     }
  1022.     deraw();
  1023. #ifdef VMS
  1024.     fprintf(stderr, "No son tasks available yet under VMS--sorry\n");
  1025. #else /* VMS */
  1026. #ifdef OSK
  1027.     pipe = f->_fd;
  1028.     save_stdin = dup(0);
  1029.     close(0);
  1030.     dup(pipe);
  1031.     argblk[0] = "shell";
  1032.     argblk[1] = "ex";
  1033.     argblk[2] = fname;
  1034.     argblk[3] = 0;
  1035.     pid = os9exec(os9forkc,argblk[0],argblk,environ,0,0,3);
  1036.     close(0);
  1037.     dup(save_stdin);
  1038.     close(save_stdin);
  1039.     if (pid < 0) {
  1040.       error ("Can't fork child");
  1041.       (void) fclose (f);
  1042.       *rpid = 0;
  1043.       return(0);
  1044.     }
  1045.     else {
  1046.       *rpid = pid;
  1047.     }
  1048. #else /* OSK */
  1049.  
  1050.     if ((pid=fork()) == 0)                        /* if child  */
  1051.     {
  1052.         (void) close (0);                         /* close stdin */
  1053.         (void) close (pipefd[1]);
  1054.         (void) dup (pipefd[0]);           /* connect to pipe input */
  1055.         (void) signal (SIGINT, SIG_DFL);          /* reset */
  1056.         (void) execl ("/bin/sh", "sh", "-c", fname, 0);
  1057.         exit (-127);
  1058.     }
  1059.     else                                  /* else parent */
  1060.     {
  1061.         *rpid = pid;
  1062.         f = fdopen (pipefd[1], "w");
  1063.         if (f == 0)
  1064.         {
  1065.             (void) kill (pid, -9);
  1066.             error ("Can't fdopen output");
  1067.             (void) close (pipefd[1]);
  1068.             *rpid = 0;
  1069.             return(0);
  1070.         }
  1071.     }
  1072. #endif /* OSK */
  1073. #endif /* VMS */
  1074.     return(f);
  1075. }
  1076.  
  1077. closeout(f, pid)
  1078. FILE *f;
  1079. int pid;
  1080. {
  1081.     int temp;
  1082.  
  1083.     (void) fclose (f);
  1084.     if (pid) {
  1085.          while (pid != wait(&temp)) /**/;
  1086.          (void) printf("Press RETURN to continue ");
  1087.          (void) fflush(stdout);
  1088.          (void) nmgetch();
  1089.          goraw();
  1090.     }
  1091. }
  1092.  
  1093. void copyent(n,p,dr,dc)
  1094.             register struct ent *n, *p;
  1095.             int dr, dc;
  1096. {
  1097.     if(!n||!p){error("internal error");return;}
  1098.     n -> v = p -> v;
  1099.     n -> flags = p -> flags;
  1100.     n -> expr = copye (p -> expr, dr, dc);
  1101.     n -> label = 0;
  1102.     if (p -> label) {
  1103.         n -> label = (char *)
  1104.                 xmalloc  ((unsigned) (strlen (p -> label) + 1));
  1105.         (void) strcpy (n -> label, p -> label);
  1106.     }
  1107. }
  1108.  
  1109. write_fd (f, r0, c0, rn, cn)
  1110. register FILE *f;
  1111. int r0, c0, rn, cn;
  1112. {
  1113.     register struct ent **p;
  1114.     register r, c;
  1115.  
  1116.     (void) fprintf (f, "# This data file was generated by the Spreadsheet ");
  1117.     (void) fprintf (f, "Calculator.\n");
  1118.     (void) fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
  1119.     print_options(f);
  1120.     for (c=0; c<MAXCOLS; c++)
  1121.         if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
  1122.             (void) fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
  1123.     for (c=c0; c<cn; c++) {
  1124.         if (col_hidden[c]) {
  1125.             (void) fprintf(f, "hide %s\n", coltoa(c));
  1126.         }
  1127.     }
  1128.     for (r=r0; r<=rn; r++) {
  1129.         if (row_hidden[r]) {
  1130.             (void) fprintf(f, "hide %d\n", r);
  1131.         }
  1132.     }
  1133.  
  1134.     write_range(f);
  1135.  
  1136.     if (mdir)
  1137.             (void) fprintf(f, "mdir \"%s\"\n", mdir);
  1138.     for (r=r0; r<=rn; r++) {
  1139.         p = &tbl[r][c0];
  1140.         for (c=c0; c<=cn; c++, p++)
  1141.             if (*p) {
  1142.                 if ((*p)->label) {
  1143.                     edits(r,c);
  1144.                     (void) fprintf(f, "%s\n",line);
  1145.                 }
  1146.                 if ((*p)->flags&is_valid) {
  1147.                     editv (r, c);
  1148.                     (void) fprintf (f, "%s\n",line);
  1149.                 }
  1150.             }
  1151.     }
  1152. }
  1153.  
  1154. writefile (fname, r0, c0, rn, cn)
  1155. char *fname;
  1156. int r0, c0, rn, cn;
  1157. {
  1158.     register FILE *f;
  1159.     char save[1024];
  1160.     int pid;
  1161.  
  1162. #if !defined(VMS) && !defined(OSK)
  1163.     if (Crypt) {
  1164.         return (cwritefile(fname, r0, c0, rn, cn));
  1165.     }
  1166. #endif /* VMS */
  1167.  
  1168.     if (*fname == 0) fname = &curfile[0];
  1169.  
  1170.     (void) strcpy(save,fname);
  1171.  
  1172.     f = openout(fname, &pid);
  1173.     if (f == 0) {
  1174.         error ("Can't create file \"%s\"", fname);
  1175.         return (-1);
  1176.     }
  1177.  
  1178.     write_fd(f, r0, c0, rn, cn);
  1179.  
  1180.     closeout(f, pid);
  1181.  
  1182.     if (!pid) {
  1183.         (void) strcpy(curfile, save);
  1184.         modflg = 0;
  1185.         error("File \"%s\" written.",curfile);
  1186.     }
  1187.  
  1188.     return (0);
  1189. }
  1190.  
  1191. void readfile (fname,eraseflg)
  1192. char *fname;
  1193. int eraseflg;
  1194. {
  1195.     register FILE *f;
  1196.     char save[1024];
  1197.  
  1198.     if (*fname == '*' && mdir) {
  1199.        (void) strcpy(save, mdir);
  1200.        *fname = '/';
  1201.        (void) strcat(save, fname);
  1202.     } else {
  1203.         if (*fname == 0)
  1204.             fname = &curfile[0];
  1205.         (void) strcpy(save,fname);
  1206.     }
  1207.  
  1208. #if !defined(VMS) && !defined(OSK)
  1209.     if (Crypt)  {
  1210.         creadfile(save, eraseflg);
  1211.         return;
  1212.     }
  1213. #endif /* VMS */
  1214.  
  1215.     if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;
  1216.  
  1217.     f = fopen (save, "r");
  1218.     if (f==0) {
  1219.         error ("Can't read file \"%s\"", save);
  1220.         return;
  1221.     }
  1222.  
  1223.     if (eraseflg) erasedb ();
  1224.  
  1225.     loading++;
  1226.     while (fgets(line,sizeof line,f)) {
  1227.         linelim = 0;
  1228.         if (line[0] != '#') (void) yyparse ();
  1229.     }
  1230.     --loading;
  1231.     (void) fclose (f);
  1232.     linelim = -1;
  1233.     modflg++;
  1234.     if (eraseflg) {
  1235.         (void) strcpy(curfile,save);
  1236.         modflg = 0;
  1237.     }
  1238.     EvalAll();
  1239. }
  1240.  
  1241. erasedb ()
  1242. {
  1243.     register r, c;
  1244.     for (c = 0; c<=maxcol; c++) {
  1245.         fwidth[c] = DEFWIDTH;
  1246.         precision[c] = DEFPREC;
  1247.     }
  1248.  
  1249.     for (r = 0; r<=maxrow; r++) {
  1250.         register struct ent **p = &tbl[r][0];
  1251.         for (c=0; c++<=maxcol; p++)
  1252.             if (*p) {
  1253.                 if ((*p)->expr) efree ((*p) -> expr);
  1254.                 if ((*p)->label) xfree ((char *)((*p) -> label));
  1255.                 xfree ((char *)(*p));
  1256.                 *p = 0;
  1257.             }
  1258.     }
  1259.     maxrow = 0;
  1260.     maxcol = 0;
  1261.     clean_range();
  1262.     FullUpdate++;
  1263. }
  1264.  
  1265. backcol(arg)
  1266.         int arg;
  1267. {
  1268.     while (--arg>=0) {
  1269.         if (curcol)
  1270.             curcol--;
  1271.         else
  1272.             {error ("At column A"); break;}
  1273.         while(col_hidden[curcol] && curcol)
  1274.             curcol--;
  1275.     }
  1276. }
  1277.  
  1278. forwcol(arg)
  1279.         int arg;
  1280. {
  1281.     while (--arg>=0) {
  1282.         if (curcol < MAXCOLS - 1)
  1283.             curcol++;
  1284.         else
  1285.             {error ("The table can't be any wider"); break;}
  1286.         while(col_hidden[curcol]&&(curcol<MAXCOLS-1))
  1287.             curcol++;
  1288.     }
  1289. }
  1290.  
  1291. forwrow(arg)
  1292.         int arg;
  1293. {
  1294.     while (--arg>=0) {
  1295.         if (currow < MAXROWS - 1)
  1296.             currow++;
  1297.         else
  1298.             {error ("The table can't be any longer"); break;}
  1299.         while (row_hidden[currow]&&(currow<MAXROWS-1))
  1300.             currow++;
  1301.     }
  1302. }
  1303.  
  1304. backrow(arg)
  1305.         int arg;
  1306. {
  1307.     while (--arg>=0) {
  1308.         if (currow)
  1309.             currow--;
  1310.         else
  1311.             {error ("At row zero"); break;}
  1312.         while (row_hidden[currow] && currow)
  1313.             currow--;
  1314.     }
  1315. }
  1316.  
  1317.  
  1318. /*
  1319.  * Show a cell's label string or expression value.  May overwrite value if
  1320.  * there is one already displayed in the cell.  Created from old code in
  1321.  * update(), copied with minimal changes.
  1322.  */
  1323.  
  1324. showstring (string, leftflush, hasvalue, row, col, nextcolp, mxcol, fieldlenp, r, c)
  1325.     char *string;       /* to display */
  1326.     int leftflush;      /* or rightflush */
  1327.     int hasvalue;       /* is there a numeric value? */
  1328.     int row, col;       /* spreadsheet location */
  1329.     int *nextcolp;      /* value returned through it */
  1330.     int mxcol;          /* last column displayed? */
  1331.     int *fieldlenp;     /* value returned through it */
  1332.     int r, c;           /* screen row and column */
  1333. {
  1334.     register int nextcol  = *nextcolp;
  1335.     register int fieldlen = *fieldlenp;
  1336.  
  1337.     char field[1024];
  1338.     int  slen;
  1339.     char *start, *last;
  1340.     register char *fp;
  1341.     struct ent *nc;
  1342.  
  1343.     /* This figures out if the label is allowed to
  1344.        slop over into the next blank field */
  1345.  
  1346.     slen = strlen (string);
  1347.     while ((slen > fieldlen) && (nextcol <= mxcol) &&
  1348.            !((nc = lookat (row, nextcol)) -> flags & is_valid) &&
  1349.            !(nc->label)) {
  1350.  
  1351.         if (! col_hidden [nextcol])
  1352.             fieldlen += fwidth [nextcol];
  1353.  
  1354.         nextcol++;
  1355.     }
  1356.     if (slen > fieldlen)
  1357.         slen = fieldlen;
  1358.  
  1359.     /* Now justify and print */
  1360.     start = leftflush ? field : field + fieldlen - slen;
  1361.     last = field+fieldlen;
  1362.     fp = field;
  1363.     while (fp < start)
  1364.         *fp++ = ' ';
  1365.     while (slen--)
  1366.         *fp++ = *string++;
  1367.     if ((! hasvalue) || fieldlen != fwidth[col])
  1368.         while (fp < last)
  1369.             *fp++ = ' ';
  1370.     *fp = 0;
  1371. #ifdef VMS
  1372.     mvaddstr(r, c, field);      /* this is a macro */
  1373. #else
  1374.     (void) mvaddstr(r, c, field);
  1375. #endif
  1376.  
  1377.     *nextcolp  = nextcol;
  1378.     *fieldlenp = fieldlen;
  1379. }
  1380. etype(e)
  1381. register struct enode *e;
  1382. {
  1383.  
  1384.     if (e==0) return 0;
  1385.     switch (e->op) {
  1386.     case '+': case '-': case '*': case '/': case '%': case '^':
  1387.     case '<': case '=': case '>': case '&': case '|': case 'm':
  1388.     case '~': case 'k': case INDEX:
  1389.     case REDUCE | '+': case REDUCE | '*': case REDUCE | 'a':
  1390.     case REDUCE | 's': case REDUCE | MAX: case REDUCE | MIN:
  1391.     case ACOS: case ASIN: case ATAN: case ATAN2: case CEIL:
  1392.     case COS: case EXP: case FABS: case FLOOR: case HYPOT:
  1393.     case LOG: case LOG10: case POW: case SIN: case SQRT:
  1394.     case TAN: case DTR: case RTD: case RND: case FV: case PV:
  1395.     case PMT: case HOUR: case MINUTE: case SECOND: case MONTH:
  1396.     case DAY: case YEAR: case NOW: case STON: case EQS:
  1397.     case LMAX: case LMIN: case NVAL: case LOOKUP:
  1398.         return (NUM);
  1399.  
  1400.     case O_SCONST: case '#': case DATE: case FMT: case STINDEX:
  1401.     case EXT: case SVAL: case SUBSTR:
  1402.         return (STR);
  1403.  
  1404.     case 'f':  case '?':
  1405.         return(etype(e->e.o.left));
  1406.  
  1407.     case O_VAR: {
  1408.         register struct ent *p;
  1409.         p = e->e.v.vp;
  1410.         if (p->expr)
  1411.             return(p->flags & is_strexpr ? STR : NUM);
  1412.         else if (p->label)
  1413.             return(STR);
  1414.         else
  1415.             return(NUM);
  1416.         }
  1417.  
  1418.     default:
  1419.         return(NUM);
  1420.     }
  1421. }
  1422.