home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume23 / sc6.8 / part03 / sc.c < prev   
Encoding:
C/C++ Source or Header  |  1990-10-09  |  33.0 KB  |  1,596 lines

  1. /*    SC    A Spreadsheet Calculator
  2.  *        Main driver
  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.  *        More mods by Alan Silverstein, 3-4/88, see list of changes.
  10.  *        Currently supported by pur-phy!sawmill!buhrt (Jeff Buhrt)
  11.  *        $Revision: 6.8 $
  12.  *
  13.  */
  14.  
  15.  
  16. #include <signal.h>
  17. #include <curses.h>
  18. #include <ctype.h>
  19.  
  20. #ifdef BSD42
  21. #include <strings.h>
  22. #else
  23. #ifndef SYSIII
  24. #include <string.h>
  25. #endif
  26. #endif
  27.  
  28. #include <stdio.h>
  29. #include "sc.h"
  30.  
  31. char *getenv();
  32.  
  33. #ifdef SYSV3
  34. void exit();
  35. #endif
  36.  
  37. #ifndef DFLT_PAGER
  38. #define    DFLT_PAGER "more"    /* more is probably more widespread than less */
  39. #endif /* DFLT_PAGER */
  40.  
  41. #define MAXCMD 160    /* for ! command below */
  42.  
  43. extern    char    *rev;
  44.  
  45. /* Globals defined in sc.h */
  46.  
  47. struct ent ***tbl;
  48. int strow, stcol;
  49. int currow, curcol;
  50. int savedrow, savedcol;
  51. int FullUpdate;
  52. int maxrow, maxcol;
  53. int maxrows, maxcols;
  54. int *fwidth;
  55. int *precision;
  56. char *col_hidden;
  57. char *row_hidden;
  58. char line[FBUFLEN];
  59. int changed;
  60. struct ent *to_fix;
  61. int modflg;
  62. int numeric;
  63. char *mdir;
  64. int showsc, showsr;    /* Starting cell for highlighted range */
  65. char mode_ind = '.';
  66.  
  67. char curfile[PATHLEN];
  68. char    revmsg[80];
  69.  
  70. int  linelim = -1;
  71.  
  72. int  showtop   = 1;    /* Causes current cell value display in top line  */
  73. int  showcell  = 1;    /* Causes current cell to be highlighted      */
  74. int  showrange = 0;    /* Causes ranges to be highlighted          */
  75. int  showneed  = 0;    /* Causes cells needing values to be highlighted  */
  76. int  showexpr  = 0;    /* Causes cell exprs to be displayed, highlighted */
  77.  
  78. int  autocalc = 1 ;    /* 1 to calculate after each update */
  79. int  calc_order = BYROWS;
  80. int  tbl_style = 0;    /* headers for T command output */
  81.  
  82. int  lastmx, lastmy;    /* Screen address of the cursor */
  83. int  lastcol;        /* Spreadsheet Column the cursor was in last */
  84. char under_cursor[] = " "; /* Data under the < cursor */
  85.  
  86. #ifdef VMS
  87. int VMS_read_raw = 0;
  88. #endif
  89.  
  90. int seenerr;
  91.  
  92. void
  93. yyerror(err)
  94. char *err; {
  95.     if (seenerr) return;
  96.     seenerr++;
  97.     (void) move(1,0);
  98.     (void) clrtoeol();
  99.     (void) printw("%s: %.*s<=%s",err,linelim,line,line+linelim);
  100. }
  101.  
  102. struct ent *
  103. lookat(row,col)
  104. int    row, col;
  105. {
  106.     register struct ent **pp;
  107.  
  108.     checkbounds(&row, &col);
  109.     pp = ATBL(tbl, row, col);
  110.     if (*pp == (struct ent *)0) {
  111.     *pp = (struct ent *) xmalloc((unsigned)sizeof(struct ent));
  112.     if (row>maxrow) maxrow = row;
  113.     if (col>maxcol) maxcol = col;
  114.     (*pp)->label = (char *)0;
  115.     (*pp)->row = row;
  116.     (*pp)->col = col;
  117.     (*pp)->flags = 0;
  118.     (*pp)->expr = (struct enode *)0;
  119.     (*pp)->v = (double) 0.0;
  120.     (*pp)->evnext = (struct ent *)0;
  121.     }
  122.     return *pp;
  123. }
  124.  
  125. /*
  126.  * This structure is used to keep ent structs around before they
  127.  * are deleted to allow the sync_refs routine a chance to fix the
  128.  * variable references.
  129.  * We also use it as a last-deleted buffer for the 'p' command.
  130.  */
  131.  
  132. void
  133. free_ent(p)
  134. register struct ent *p;
  135. {
  136.     p->next = to_fix;
  137.     to_fix = p;
  138.     p->flags |= is_deleted;
  139. }
  140.  
  141. void
  142. flush_saved()
  143. {
  144.     register struct ent *p;
  145.     register struct ent *q;
  146.  
  147.     if (!(p = to_fix))
  148.     return;
  149.     while (p) {
  150.     (void) clearent(p);
  151.     q = p->next;
  152.     xfree((char *)p);
  153.     p = q;
  154.     }
  155.     to_fix = 0;
  156. }
  157.  
  158. /*
  159.  * standout last time in update()?
  160.  *    At this point we will let curses do work
  161.  */
  162. int    standlast    = FALSE;
  163.  
  164. void
  165. update (anychanged)
  166. int    anychanged;    /* did any cell really change in value? */
  167. {
  168.     register    row,
  169.                 col;
  170.     register struct ent **pp;
  171.     int     mxcol;
  172.     int     mxrow;
  173.     int     rows;
  174.     int     cols;
  175.     int     minsr, minsc, maxsr, maxsc;
  176.     register r;
  177.     register i;
  178.  
  179.     while (row_hidden[currow])   /* You can't hide the last row or col */
  180.     currow++;
  181.     while (col_hidden[curcol])
  182.     curcol++;
  183.     /* First see if the last display still covers curcol */
  184.     if (stcol <= curcol) { 
  185.     for (i = stcol, cols = 0, col = RESCOL;
  186.             (col + fwidth[i]) < COLS-1 && i < maxcols; i++) {
  187.         cols++;
  188.         if (col_hidden[i])
  189.         continue;
  190.         col += fwidth[i];
  191.     }
  192.     }
  193.     while (stcol + cols - 1 < curcol || curcol < stcol) {
  194.     FullUpdate++;
  195.     if (stcol - 1 == curcol) {    /* How about back one? */
  196.         stcol--;
  197.     } else if (stcol + cols == curcol) {   /* Forward one? */
  198.         stcol++;
  199.     } else {
  200.         /* Try to put the cursor in the center of the screen */
  201.         col = (COLS - RESCOL - fwidth[curcol]) / 2 + RESCOL; 
  202.         stcol = curcol;
  203.         for (i=curcol-1; i >= 0 && col-fwidth[i] > RESCOL; i--) {
  204.         stcol--;
  205.         if (col_hidden[i])
  206.             continue;
  207.         col -= fwidth[i];
  208.         }
  209.     }
  210.     /* Now pick up the counts again */
  211.     for (i = stcol, cols = 0, col = RESCOL;
  212.             (col + fwidth[i]) < COLS-1 && i < maxcols; i++) {
  213.         cols++;
  214.         if (col_hidden[i])
  215.         continue;
  216.         col += fwidth[i];
  217.     }
  218.     }
  219.     /* Now - same process on the rows */
  220.     if (strow <= currow) { 
  221.     for (i = strow, rows = 0, row=RESROW; row<LINES && i<maxrows; i++) {
  222.         rows++;
  223.         if (row_hidden[i])
  224.         continue;
  225.         row++;
  226.     }
  227.     }
  228.     while (strow + rows - 1 < currow || currow < strow) {
  229.     FullUpdate++;
  230.     if (strow - 1 == currow) {    /* How about up one? */
  231.         strow--;
  232.     } else if (strow + rows == currow) {   /* Down one? */
  233.         strow++;
  234.     } else {
  235.         /* Try to put the cursor in the center of the screen */
  236.         row = (LINES - RESROW) / 2 + RESROW; 
  237.         strow = currow;
  238.         for (i=currow-1; i >= 0 && row-1 > RESROW; i--) {
  239.         strow--;
  240.         if (row_hidden[i])
  241.             continue;
  242.         row--;
  243.         }
  244.     }
  245.     /* Now pick up the counts again */
  246.     for (i = strow, rows = 0, row=RESROW; row<LINES && i<maxrows; i++) {
  247.         rows++;
  248.         if (row_hidden[i])
  249.         continue;
  250.         row++;
  251.     }
  252.     }
  253.     mxcol = stcol + cols - 1;
  254.     mxrow = strow + rows - 1;
  255.     if (FullUpdate || standlast) {
  256.     (void) move(2, 0);
  257.     (void) clrtobot();
  258.     (void) standout();
  259.     for (row=RESROW, i=strow; i <= mxrow; i++) {
  260.         if (row_hidden[i]) 
  261.         continue;
  262.         (void) move(row,0);
  263.         if (maxrows < 1000)
  264.         (void) printw("%-*d", RESCOL-1, i);
  265.         else
  266.         (void) printw("%-*d", RESCOL, i);
  267.         row++;
  268.     }
  269.     (void) move(2,0);
  270.     (void) printw("%*s", RESCOL, " ");
  271.  
  272.     for (col=RESCOL, i = stcol; i <= mxcol; i++) {
  273.         register int k;
  274.         if (col_hidden[i])
  275.         continue;
  276.         (void) move(2, col);
  277.         k = fwidth[i]/2;
  278.         if (k == 0)
  279.         (void) printw("%1s", coltoa(i));
  280.         else
  281.             (void) printw("%*s%-*s", k, " ", fwidth[i]-k, coltoa(i));
  282.         col += fwidth[i];
  283.     }
  284.     (void) standend();
  285.     }
  286.  
  287.     /* Get rid of cursor standout on the cell at previous cursor position */
  288.     if (showcell)
  289.     {    (void) move(lastmx, lastmy);
  290.         repaint(lastmx, lastmy, fwidth[lastcol]);
  291.     }
  292.  
  293.     if (showrange) {
  294.     minsr = showsr < currow ? showsr : currow;
  295.     minsc = showsc < curcol ? showsc : curcol;
  296.     maxsr = showsr > currow ? showsr : currow;
  297.     maxsc = showsc > curcol ? showsc : curcol;
  298.  
  299.     if (showtop) {
  300.         (void) move(1,0);
  301.         (void) clrtoeol();
  302.         (void) printw("Default range:  %s",
  303.                 r_name(minsr, minsc, maxsr, maxsc));
  304.     }
  305.     }
  306.  
  307.     /* Repaint the visible screen */
  308.     if (showrange || anychanged || FullUpdate || standlast)
  309.     {
  310.     /* may be reset in loop, if not next time we will do a FullUpdate */
  311.       if (standlast)
  312.       {    FullUpdate = TRUE;
  313.     standlast = FALSE;
  314.       }
  315.       for (row = strow, r = RESROW; row <= mxrow; row++) {
  316.     register c = RESCOL;
  317.     int do_stand = 0;
  318.     int fieldlen;
  319.     int nextcol;
  320.  
  321.     if (row_hidden[row])
  322.         continue;
  323.     for (pp = ATBL(tbl, row, col = stcol); col <= mxcol;
  324.              pp += nextcol - col,  col = nextcol, c += fieldlen) {
  325.  
  326.         nextcol = col+1;
  327.         if (col_hidden[col]) {
  328.         fieldlen = 0;
  329.         continue;
  330.         }
  331.  
  332.         fieldlen = fwidth[col];
  333.  
  334.         /*
  335.          * Set standout if:
  336.          *
  337.          * - showing ranges, and not showing cells which need to be filled
  338.          *     in, and not showing cell expressions, and in a range, OR
  339.          *
  340.          * - if showing cells which need to be filled in and this one is
  341.          *     of that type (has a value and doesn't have an expression,
  342.          *     or it is a string expression), OR
  343.          *
  344.          * - if showing cells which have expressions and this one does.
  345.          */
  346.  
  347.         if ((showrange && (! showneed) && (! showexpr)
  348.                && (row >= minsr) && (row <= maxsr)
  349.                && (col >= minsc) && (col <= maxsc))
  350.             || (showneed && (*pp) && ((*pp) -> flags & is_valid)
  351.             && (((*pp) -> flags & is_strexpr) || !((*pp) -> expr)))
  352.             || (showexpr && (*pp) && ((*pp) -> expr)))
  353.         {
  354.         (void) move(r, c);
  355.         (void) standout();
  356.         standlast++;
  357.         if (!*pp)    /* no cell, but standing out */
  358.         {    (void) printw("%*s", fwidth[col], " ");
  359.             (void) standend();
  360.             continue;
  361.         }
  362.         else
  363.             do_stand = 1;
  364.         }
  365.         else
  366.         do_stand = 0;
  367.  
  368.         if ((*pp) && ((*pp) -> flags & is_changed || FullUpdate) || do_stand) {
  369.         if (do_stand) {
  370.             (*pp) -> flags |= is_changed; 
  371.         } else {
  372.             (void) move(r, c);
  373.             (*pp) -> flags &= ~is_changed;
  374.         }
  375.  
  376.         /*
  377.          * Show expression; takes priority over other displays:
  378.          */
  379.  
  380.         if (showexpr && ((*pp) -> expr)) {
  381.             linelim = 0;
  382.             editexp(row, col);        /* set line to expr */
  383.             linelim = -1;
  384.             showstring(line, /* leftflush = */ 1, /* hasvalue = */ 0,
  385.                 row, col, & nextcol, mxcol, & fieldlen, r, c);
  386.         }
  387.         else {
  388.  
  389.             /*
  390.              * Show cell's numeric value:
  391.              */
  392.  
  393.             if ((*pp) -> flags & is_valid) {
  394.             char field[FBUFLEN];
  395.             (void)sprintf(field,"%*.*f", fwidth[col], precision[col], (*pp)->v);
  396.             if(strlen(field) > fwidth[col]) {
  397.                 for(i = 0; i<fwidth[col]; i++)
  398.                 (void)addch('*');
  399.             } else {
  400.                 (void)addstr(field);
  401.             }
  402.             }
  403.  
  404.             /*
  405.              * Show cell's label string:
  406.              */
  407.  
  408.             if ((*pp) -> label) {
  409.             showstring((*pp) -> label,
  410.                     (*pp) -> flags & is_leftflush,
  411.                     (*pp) -> flags & is_valid,
  412.                     row, col, & nextcol, mxcol,
  413.                     & fieldlen, r, c);
  414.             }
  415.             else    /* repaint a blank cell: */
  416.             if ((do_stand || !FullUpdate) &&
  417.                 ((*pp)->flags & is_changed) &&
  418.                 !((*pp)->flags & is_valid) && !(*pp)->label) {
  419.             (void) printw("%*s", fwidth[col], " ");
  420.             }
  421.         } /* else */
  422.  
  423.         if (do_stand) {
  424.             (void) standend();
  425.             do_stand = 0;
  426.         }
  427.         }
  428.     }
  429.     r++;
  430.       }
  431.     }
  432.         
  433.     (void) move(lastmy, lastmx+fwidth[lastcol]);
  434.     if((inch() & A_CHARTEXT ) == '<')
  435.         (void) addstr(under_cursor);
  436.  
  437.     lastmy =  RESROW;
  438.     for (row = strow; row < currow; row++)
  439.     if (!row_hidden[row])
  440.         lastmy += 1;
  441.     lastmx = RESCOL;
  442.     for (col = stcol; col < curcol; col++)
  443.     if (!col_hidden[col])
  444.         lastmx += fwidth[col];
  445.     lastcol = curcol;
  446.     if (showcell && (! showneed) && (! showexpr)) {
  447.     (void) move(lastmy, lastmx);
  448.         (void) standout();
  449.         repaint(lastmx, lastmy, fwidth[lastcol]);
  450.         (void) standend();
  451.     }
  452.     (void) move(lastmy, lastmx+fwidth[lastcol]);
  453.     *under_cursor = (inch() & A_CHARTEXT );
  454.     (void) addstr("<");
  455.  
  456.     (void) move(0, 0);
  457.     (void) clrtoeol();
  458.     if (linelim >= 0) {
  459.     (void) addch(mode_ind);
  460.     (void) addstr("> ");
  461.     (void) addstr(line);
  462.     (void) move(0, linelim+3);
  463.     } else {
  464.     if (showtop) {            /* show top line */
  465.         register struct ent *p1;
  466.         int printed = 0;        /* printed something? */
  467.  
  468.             (void) printw("%s%d ", coltoa(curcol), currow);
  469.  
  470.         if (p1 = *ATBL(tbl, currow, curcol)) {
  471.         if (p1 -> expr) {
  472.             /* has expr of some type */
  473.             linelim = 0;
  474.             editexp(currow, curcol);    /* set line to expr */
  475.             linelim = -1;
  476.         }
  477.  
  478.         /*
  479.          * Display string part of cell:
  480.          */
  481.  
  482.         if ((p1 -> expr) && (p1 -> flags & is_strexpr)) {
  483.             (void) addstr((p1 -> flags & is_leftflush) ? "<{" : ">{");
  484.             (void) addstr(line);
  485.             (void) addstr("} ");    /* and this '}' is for vi % */
  486.             printed = 1;
  487.  
  488.         } else if (p1 -> label) {
  489.             /* has constant label only */
  490.             (void) addstr ((p1 -> flags & is_leftflush) ? "<\"" : ">\"");
  491.             (void) addstr (p1 -> label);
  492.             (void) addstr ("\" ");
  493.             printed = 1;
  494.         }
  495.  
  496.         /*
  497.          * Display value part of cell:
  498.          */
  499.  
  500.         if (p1 -> flags & is_valid) {
  501.             /* has value or num expr */
  502.             if ((! (p1 -> expr)) || (p1 -> flags & is_strexpr))
  503.             (void) sprintf (line, "%.15g", p1 -> v);
  504.  
  505.             (void) addstr ("[");
  506.             (void) addstr (line);
  507.             (void) addstr ("]");
  508.             printed = 1;
  509.         }
  510.         }
  511.         if (! printed)
  512.         (void) addstr ("[]");
  513.     }
  514.     (void) move (lastmy, lastmx + fwidth[lastcol]);
  515.     }
  516.     if (revmsg[0]) {
  517.     (void) move(0, 0);
  518.     (void) clrtoeol ();    /* get rid of topline display */
  519.     (void) printw(revmsg);
  520.     revmsg[0] = '\0';    /* don't show it again */
  521.     (void) move (lastmy, lastmx + fwidth[lastcol]);
  522.     }
  523.     FullUpdate = FALSE;
  524. }
  525.  
  526. void
  527. repaint(x, y, len)
  528. int x, y, len;
  529. {
  530.     int c;
  531.  
  532.     while(len-- > 0) {
  533.     (void) move(y,x);
  534.     c = inch() & A_CHARTEXT;
  535.     (void) addch(c);
  536.     x++;
  537.     }
  538. }
  539.  
  540. char    *progname;
  541.  
  542. int
  543. main (argc, argv)
  544. int argc;
  545. char  **argv;
  546. {
  547.     int     inloop = 1;
  548.     register int   c;
  549.     int     edistate = -1;
  550.     int     arg = 1;
  551.     int     narg;
  552.     int     nedistate;
  553.     int        running;
  554.     char    *revi;
  555.     int        anychanged = FALSE;
  556.  
  557.     /*
  558.      * Keep command line options around until the file is read so the
  559.      * command line overrides file options
  560.      */
  561.  
  562.     int Mopt = 0;
  563.     int Nopt = 0;
  564.     int Copt = 0; 
  565.     int Ropt = 0;
  566.  
  567.     int tempx, tempy;     /* Temp versions of curx, cury */
  568.  
  569.     if ((revi = strrchr(argv[0], '/')) != NULL)
  570.     progname = revi+1;
  571.     else
  572.     progname = argv[0];
  573.  
  574.     while (argc > 1 && argv[1][0] == '-') {
  575.     argv++;
  576.     argc--;
  577.         switch (argv[0][1]) {
  578.         case 'x':
  579. #ifdef VMS
  580.             (void) fprintf(stderr, "Crypt not available for VMS\n");
  581.             exit(1);
  582. #else 
  583.             Crypt = 1;
  584. #endif
  585.             break;
  586.         case 'm':
  587.             Mopt = 1;
  588.             break;
  589.         case 'n':
  590.             Nopt = 1;
  591.             break;
  592.         case 'c':
  593.             Copt = 1;
  594.             break;
  595.         case 'r':
  596.             Ropt = 1;
  597.             break;
  598.         default:
  599.             (void) fprintf(stderr,"%s: unrecognized option: \"%c\"\n",
  600.             progname,argv[0][1]);
  601.             exit(1);
  602.     }
  603.     }
  604.  
  605.     *curfile ='\0';
  606.  
  607.     signals();
  608.     (void) initscr();
  609.  
  610.     /* setup the spreadsheet arrays, initscr() will get the screen size */
  611.     if (!growtbl(GROWNEW, 0, 0))
  612.     {    endwin();
  613.     exit(1);
  614.     }
  615.  
  616.     (void) clear();
  617. #ifdef VMS
  618.     VMS_read_raw = 1;
  619. #else
  620.     nonl();
  621.     noecho ();
  622.     cbreak();
  623. #endif
  624.     initkbd();
  625.     scrollok(stdscr, 1);
  626.  
  627.     /*
  628.      * Build revision message for later use:
  629.      */
  630.  
  631.     (void) strcpy (revmsg, progname);
  632.     for (revi = rev; (*revi++) != ':'; );    /* copy after colon */
  633.     (void) strcat (revmsg, revi);
  634.     revmsg [strlen (revmsg) - 2] = 0;        /* erase last character */
  635.     (void) strcat (revmsg, ":  Type '?' for help.");
  636.  
  637.     if (argc > 1) {
  638.     (void) strcpy(curfile,argv[1]);
  639.     readfile (argv[1], 0);
  640.     }
  641.  
  642.     if (Mopt)
  643.     autocalc = 0;
  644.     if (Nopt)
  645.     numeric = 1;
  646.     if (Copt)
  647.     calc_order = BYCOLS;
  648.     if (Ropt)
  649.     calc_order = BYROWS;
  650.  
  651.     modflg = 0;
  652. #ifdef VENIX
  653.     setbuf (stdin, NULL);
  654. #endif
  655.     FullUpdate++;
  656.     while (inloop) { running = 1;
  657.     while (running) {
  658.     nedistate = -1;
  659.     narg = 1;
  660.     if (edistate < 0 && linelim < 0 && autocalc && (changed || FullUpdate))
  661.     {    EvalAll ();
  662.          if (changed)        /* if EvalAll changed or was before */
  663.         anychanged = TRUE;
  664.          changed = 0;
  665.     }
  666.     else        /* any cells change? */
  667.     if (changed)
  668.          anychanged = TRUE;
  669.  
  670.     update(anychanged);
  671.     anychanged = FALSE;
  672. #ifndef SYSV3
  673.     (void) refresh(); /* 5.3 does a refresh in getch */ 
  674. #endif
  675.     c = nmgetch();
  676.     getyx(stdscr, tempy, tempx);
  677.     (void) move (1, 0);
  678.     (void) clrtoeol ();
  679.     (void) move(tempy, tempx);
  680.     (void) fflush (stdout);
  681.     seenerr = 0;
  682.     showneed = 0;    /* reset after each update */
  683.     showexpr = 0;
  684.  
  685.     /* if ((c < ' ') || ( c == DEL ))   how about international here ? PB */
  686.        if ( iscntrl(c) )
  687.         switch (c) {
  688. #ifdef SIGTSTP
  689.         case ctl('z'):
  690.             (void) deraw();
  691.             (void) kill(0, SIGTSTP); /* Nail process group */
  692.  
  693.             /* the pc stops here */
  694.  
  695.             (void) goraw();
  696.             break;
  697. #endif
  698.         case ctl('r'):
  699.             showneed = 1;
  700.         case ctl('l'):
  701.             FullUpdate++;
  702.             (void) clearok(stdscr,1);
  703.             break;
  704.         case ctl('x'):
  705.             FullUpdate++;
  706.             showexpr = 1;
  707.             (void) clearok(stdscr,1);
  708.             break;
  709.         default:
  710.             error ("No such command (^%c)", c + 0100);
  711.             break;
  712.         case ctl('b'):
  713.             backcol(arg);
  714.             break;
  715.         case ctl('c'):
  716.             running = 0;
  717.             break;
  718.  
  719.         case ctl('e'):
  720.  
  721.             switch (nmgetch()) {
  722.             case ctl('p'): case 'k':    doend (-1, 0);    break;
  723.             case ctl('n'): case 'j':    doend ( 1, 0);    break;
  724.             case ctl('b'): case 'h':
  725.             case ctl('h'):        doend ( 0,-1);    break;
  726.             case ctl('f'): case 'l':
  727.             case ctl('i'): case ' ':    doend ( 0, 1);    break;
  728.  
  729.             case ESC:
  730.             case ctl('g'):
  731.             break;
  732.  
  733.             default:
  734.             error("Invalid ^E command");
  735.             break;
  736.             }
  737.  
  738.             break;
  739.  
  740.         case ctl('f'):
  741.             forwcol(arg);
  742.             break;
  743.  
  744.         case ctl('g'):
  745.             showrange = 0;
  746.             linelim = -1;
  747.             (void) move (1, 0);
  748.             (void) clrtoeol ();
  749.             break;
  750.  
  751.         case ESC:    /* ctl('[') */
  752.             write_line(ESC);
  753.             break;
  754.  
  755.         case ctl('d'):
  756.             write_line(ctl('d'));
  757.             break;
  758.  
  759.         case DEL:
  760.         case ctl('h'):
  761.             if (linelim < 0) {    /* not editing line */
  762.             backcol(arg);    /* treat like ^B    */
  763.             break;
  764.             }
  765.             write_line(ctl('h'));
  766.             break;
  767.  
  768.         case ctl('i'):         /* tab */
  769.             if (linelim < 0) {    /* not editing line */
  770.             forwcol(arg);
  771.             break;
  772.             }
  773.             if (!showrange) {
  774.             startshow();
  775.             } else {
  776.             showdr();
  777.             linelim = strlen(line);
  778.             line[linelim++] = ' ';
  779.             line[linelim] = 0;
  780.             showrange = 0;
  781.             }
  782.             linelim = strlen (line);
  783.             break;
  784.  
  785.         case ctl('m'):
  786.         case ctl('j'):
  787.             write_line(ctl('m'));
  788.             break;
  789.  
  790.         case ctl('n'):
  791.             forwrow(arg);
  792.             break;
  793.  
  794.         case ctl('p'):
  795.             backrow(arg);
  796.             break;
  797.  
  798.         case ctl('q'):
  799.             break;    /* ignore flow control */
  800.  
  801.         case ctl('s'):
  802.             break;    /* ignore flow control */
  803.  
  804.         case ctl('t'):
  805.             error(
  806. "Toggle:  a:auto  c:cell  e:ext funcs  n:numeric  t:top  x:encrypt  $:pre-scale");
  807.             (void) refresh();
  808.  
  809.             switch (nmgetch()) {
  810.             case 'a': case 'A':
  811.             case 'm': case 'M':
  812.                 autocalc ^= 1;
  813.                 error("Automatic recalculation %sabled.",
  814.                 autocalc ? "en":"dis");
  815.                 break;
  816.             case 'n': case 'N':
  817.                 numeric = (! numeric);
  818.                 error ("Numeric input %sabled.",
  819.                     numeric ? "en" : "dis");
  820.                 break;
  821.             case 't': case 'T':
  822.                 showtop = (! showtop);
  823.                 repaint(lastmx, lastmy, fwidth[lastcol]);
  824.                 error ("Top line %sabled.", showtop ? "en" : "dis");
  825.                 break;
  826.             case 'c': case 'C':
  827.                 showcell = (! showcell);
  828.                 repaint(lastmx, lastmy, fwidth[lastcol]);
  829.                 error ("Cell highlighting %sabled.",
  830.                     showcell ? "en" : "dis");
  831.                 break;
  832.             case 'x': case 'X':
  833.                 Crypt = (! Crypt);
  834.                 error ("Encryption %sabled.", Crypt? "en" : "dis");
  835.                 break;
  836.             case '$':
  837.                 if (prescale == 1.0) {
  838.                 error ("Prescale enabled.");
  839.                 prescale = 0.01;
  840.                 } else {
  841.                 prescale = 1.0;
  842.                 error ("Prescale disabled.");
  843.                 }
  844.                 break;
  845.             case 'e': case 'E':
  846.                 extfunc = (! extfunc);
  847.                 error ("External functions %sabled.",
  848.                     extfunc? "en" : "dis");
  849.                 break;
  850.             case ESC:
  851.             case ctl('g'):
  852.                 --modflg;    /* negate the modflg++ */
  853.                 break;
  854.             default:
  855.                 error ("Invalid toggle command");
  856.                 --modflg;    /* negate the modflg++ */
  857.             }
  858.             FullUpdate++;
  859.             modflg++;
  860.             break;
  861.  
  862.         case ctl('u'):
  863.             narg = arg * 4;
  864.             nedistate = 1;
  865.             break;
  866.  
  867.         case ctl('v'):    /* insert variable name */
  868.             if (linelim > 0)
  869.                 ins_string(v_name(currow, curcol));
  870.             break;
  871.  
  872.         case ctl('w'):    /* insert variable expression */
  873.             if (linelim > 0)  {
  874.             char *temp, *temp1;
  875.             int templim;
  876.  
  877.             temp = strcpy(xmalloc((unsigned)(strlen(line)+1)),line);
  878.             templim = linelim;
  879.             editexp(currow,curcol);
  880.             temp1= strcpy(xmalloc((unsigned)(strlen(line)+1)),line);
  881.             strcpy(line, temp);
  882.             linelim = templim;
  883.             ins_string(temp1);
  884.             xfree(temp);
  885.             xfree(temp1);
  886.             }
  887.             break;
  888.  
  889.         case ctl('a'):    /* insert variable value */
  890.             if (linelim > 0) {
  891.             struct ent *p = *ATBL(tbl, currow, curcol);
  892.             char temp[100];
  893.  
  894.             if (p && p -> flags & is_valid) {
  895.                 (void) sprintf (temp, "%.*f",
  896.                     precision[curcol],p -> v);
  897.                 ins_string(temp);
  898.             }
  899.             }
  900.             break;
  901.  
  902.         } /* End of the control char switch stmt */
  903.     else if (isdigit(c) && ((numeric && edistate >= 0) ||
  904.             (!numeric && (linelim < 0 || edistate >= 0)))) {
  905.         /* we got a leading number */
  906.         if (edistate != 0) {
  907.         /* First char of the count */
  908.         if (c == '0')      /* just a '0' goes to left col */
  909.             curcol = 0;
  910.         else {
  911.             nedistate = 0;
  912.             narg = c - '0';
  913.         }
  914.         } else {
  915.         /* Succeeding count chars */
  916.         nedistate = 0;
  917.         narg = arg * 10 + (c - '0');
  918.         }
  919.     } else if (linelim >= 0) {
  920.         /* Editing line */
  921.         switch(c) {
  922.         case ')':
  923.         if (showrange) {
  924.             showdr();
  925.             showrange = 0;
  926.             linelim = strlen (line);
  927.         }
  928.         break;
  929.         default:
  930.         break;
  931.         }
  932.         write_line(c);
  933.  
  934.     } else if (!numeric && ( c == '+' || c == '-' ) ) {
  935.         /* increment/decrement ops */
  936.         register struct ent *p = *ATBL(tbl, currow, curcol);
  937.         if (!p)
  938.         continue;
  939.         if (p->expr && !(p->flags & is_strexpr)) {
  940.         error("Can't increment/decrement a formula\n");
  941.         continue;
  942.         }
  943.         FullUpdate++;
  944.         modflg++;
  945.         if( c == '+' )
  946.             p -> v += (double) arg;
  947.         else
  948.         p -> v -= (double) arg;
  949.     } else
  950.         /* switch on a normal command character */
  951.         switch (c) {
  952.         case ':':
  953.             break;    /* Be nice to vi users */
  954.  
  955.         case '@':
  956.             EvalAll ();
  957.             changed = 0;
  958.             anychanged = TRUE;
  959.             break;
  960.  
  961.         case '0': case '1': case '2': case '3': case '4':
  962.         case '5': case '6': case '7': case '8': case '9':
  963.         case '-': case '.': case '+':
  964.             (void) sprintf(line,"let %s = %c",
  965.                 v_name(currow, curcol), c);
  966.             linelim = strlen (line);
  967.             insert_mode();
  968.             break;
  969.  
  970.         case '=':
  971.             (void) sprintf(line,"let %s = ",
  972.                     v_name(currow, curcol));
  973.             linelim = strlen (line);
  974.             insert_mode();
  975.             break;
  976.  
  977.         case '!':
  978.             {
  979.             /*
  980.              *  "! command"  executes command
  981.              *  "!"    forks a shell
  982.              *  "!!" repeats last command
  983.              */
  984. #ifdef VMS
  985.             error("Not implemented on VMS");
  986. #else /* VMS */
  987.             char *shl;
  988.             int pid, temp;
  989.             char cmd[MAXCMD];
  990.             static char lastcmd[MAXCMD];
  991.  
  992.             if (!(shl = getenv("SHELL")))
  993.             shl = "/bin/sh";
  994.  
  995.             deraw();
  996.             (void) fputs("! ", stdout);
  997.             (void) fflush(stdout);
  998.             (void) fgets(cmd, MAXCMD, stdin);
  999.             cmd[strlen(cmd) - 1] = '\0';    /* clobber \n */
  1000.             if(strcmp(cmd,"!") == 0)        /* repeat? */
  1001.                 (void) strcpy(cmd, lastcmd);
  1002.             else
  1003.                 (void) strcpy(lastcmd, cmd);
  1004.  
  1005.             if (modflg)
  1006.             {
  1007.             (void) puts ("[No write since last change]");
  1008.             (void) fflush (stdout);
  1009.             }
  1010.  
  1011.             if (!(pid = fork()))
  1012.             {
  1013.             (void) signal (SIGINT, SIG_DFL);  /* reset */
  1014.             if(strlen(cmd))
  1015.                 (void)execl(shl,shl,"-c",cmd,(char *)0);
  1016.             else
  1017.                 (void) execl(shl, shl, (char *)0);
  1018.             exit(-127);
  1019.             }
  1020.  
  1021.             while (pid != wait(&temp));
  1022.  
  1023.             (void) printf("Press RETURN to continue ");
  1024.             (void)nmgetch();
  1025.             goraw();
  1026. #endif /* VMS */
  1027.             break;
  1028.             }
  1029.  
  1030.         /*
  1031.          * Range commands:
  1032.          */
  1033.  
  1034.         case '/':
  1035.             error (
  1036. "Range:  x:erase  v:value  c:copy  f:fill  d:define  s:show  u:undefine");
  1037.             (void) refresh();
  1038.  
  1039.             switch (nmgetch()) {
  1040.             case 'c':
  1041.             (void) sprintf(line,"copy [dest_range src_range] ");
  1042.             linelim = strlen(line);
  1043.             startshow();
  1044.             insert_mode();
  1045.             break;
  1046.             case 'x':
  1047.             (void) sprintf(line,"erase [range] ");
  1048.             linelim = strlen(line);
  1049.             startshow();
  1050.             insert_mode();
  1051.             break;
  1052.             case 'v':
  1053.             (void) sprintf(line, "value [range] ");
  1054.             linelim = strlen(line);
  1055.             startshow();
  1056.             insert_mode();
  1057.             break;
  1058.             case 'f':
  1059.             (void) sprintf(line,"fill [range start inc] ");
  1060.             linelim = strlen(line);
  1061.             startshow();
  1062.             insert_mode();
  1063.             break;
  1064.             case 'd':
  1065.             (void) sprintf(line,"define [string range] \"");
  1066.             linelim = strlen(line);
  1067.             startshow();
  1068.             insert_mode();
  1069.             modflg++;
  1070.             break;
  1071.             case 'u':
  1072.             (void) sprintf(line,"undefine [range] ");
  1073.             linelim = strlen(line);
  1074.             insert_mode();
  1075.             modflg++;
  1076.             break;
  1077.             case 's':
  1078.             if(are_ranges())
  1079.             {
  1080.             FILE *f;
  1081.             int pid;
  1082.             char px[MAXCMD] ;
  1083.             char *pager;
  1084.  
  1085.             (void) strcpy(px, "| sort | ");
  1086.             if(!(pager = getenv("PAGER")))
  1087.                 pager = DFLT_PAGER;
  1088.             (void) strcat(px,pager);
  1089.             f = openout(px, &pid);
  1090.             if (!f) {
  1091.                 error("Can't open pipe to sort");
  1092.                 break;
  1093.             }
  1094.             list_range(f);
  1095.             closeout(f, pid);
  1096.             }
  1097.             else error("No ranges defined");
  1098.             break;
  1099.             
  1100.             case ESC:
  1101.             case ctl('g'):
  1102.             break;
  1103.            default:
  1104.             error("Invalid region command");
  1105.             break;
  1106.            }
  1107.            break;
  1108.  
  1109.         /*
  1110.          * Row/column commands:
  1111.          */
  1112.  
  1113.         case 'i':
  1114.         case 'a':
  1115.         case 'd':
  1116.         case 'p':
  1117.         case 'v':
  1118.         case 'z':
  1119.         case 's':
  1120.             {
  1121.             register rcqual;
  1122.  
  1123.             if (! (rcqual = get_rcqual (c))) {
  1124.                 error ("Invalid row/column command");
  1125.                 break;
  1126.             }
  1127.  
  1128.             error ("");    /* clear line */
  1129.  
  1130.             if ( rcqual == ESC || rcqual == ctl('g'))
  1131.                 break;
  1132.  
  1133.             switch (c) {
  1134.  
  1135.             case 'i':
  1136.                 if (rcqual == 'r')    insertrow(arg);
  1137.                 else        opencol(curcol, arg);
  1138.                 break;
  1139.  
  1140.             case 'a':
  1141.                 if (rcqual == 'r')    while (arg--) duprow();
  1142.                 else        while (arg--) dupcol();
  1143.                 break;
  1144.  
  1145.             case 'd':
  1146.                 if (rcqual == 'r')    deleterow(arg);
  1147.                 else        closecol(curcol, arg);
  1148.                 break;
  1149.  
  1150.             case 'p':
  1151.                 while (arg--)    pullcells(rcqual);
  1152.                 break;
  1153.  
  1154.             case 'v':
  1155.                 if (rcqual == 'r')    rowvalueize(arg);
  1156.                 else        colvalueize(arg);
  1157.                 modflg = 1;
  1158.                 break;
  1159.  
  1160.             case 'z':
  1161.                 if (rcqual == 'r')    hiderow(arg);
  1162.                 else        hidecol(arg);
  1163.                 break;
  1164.  
  1165.             case 's':
  1166.                 /* special case; no repeat count */
  1167.  
  1168.                 if (rcqual == 'r')    rowshow_op();
  1169.                 else        colshow_op();
  1170.                 break;
  1171.             }
  1172.             break;
  1173.             }
  1174.  
  1175.         case '$':
  1176.             {
  1177.             register struct ent *p;
  1178.  
  1179.             curcol = maxcols - 1;
  1180.             while (!VALID_CELL(p, currow, curcol) && curcol > 0)
  1181.             curcol--;
  1182.             break;
  1183.             }
  1184.         case '#':
  1185.             {
  1186.             register struct ent *p;
  1187.  
  1188.             currow = maxrows - 1;
  1189.             while (!VALID_CELL(p, currow, curcol) && currow > 0)
  1190.             currow--;
  1191.             break;
  1192.             }
  1193.         case 'w':
  1194.             {
  1195.             register struct ent *p;
  1196.  
  1197.             while (--arg>=0) {
  1198.             do {
  1199.                 if (curcol < maxcols - 1)
  1200.                 curcol++;
  1201.                 else {
  1202.                 if (currow < maxrows - 1) {
  1203.                     while(++currow < maxrows - 1 &&
  1204.                         row_hidden[currow]) /* */;
  1205.                     curcol = 0;
  1206.                 } else {
  1207.                     error("At end of table");
  1208.                     break;
  1209.                 }
  1210.                 }
  1211.             } while(col_hidden[curcol] ||
  1212.                 !VALID_CELL(p, currow, curcol));
  1213.             }
  1214.             break;
  1215.             }
  1216.         case 'b':
  1217.             {
  1218.             register struct ent *p;
  1219.  
  1220.             while (--arg>=0) {
  1221.             do {
  1222.                 if (curcol) 
  1223.                 curcol--;
  1224.                 else {
  1225.                 if (currow) {
  1226.                     while(--currow &&
  1227.                     row_hidden[currow]) /* */;
  1228.                     curcol = maxcols - 1;
  1229.                 } else {
  1230.                     error ("At start of table");
  1231.                     break;
  1232.                 }
  1233.                 }
  1234.             } while(col_hidden[curcol] ||
  1235.                 !VALID_CELL(p, currow, curcol));
  1236.             }
  1237.             break;
  1238.             }
  1239.         case '^':
  1240.             currow = 0;
  1241.             break;
  1242.         case '?':
  1243.             help();
  1244.             break;
  1245.         case '"':
  1246.             (void) sprintf (line, "label %s = \"",
  1247.                     v_name(currow, curcol));
  1248.             linelim = strlen (line);
  1249.             insert_mode();
  1250.             break;
  1251.         case '<':
  1252.             (void) sprintf (line, "leftstring %s = \"",
  1253.                 v_name(currow, curcol));
  1254.             linelim = strlen (line);
  1255.             insert_mode();
  1256.             break;
  1257.         case '>':
  1258.             (void) sprintf (line, "rightstring %s = \"",
  1259.                v_name(currow, curcol));
  1260.             linelim = strlen (line);
  1261.             insert_mode();
  1262.             break;
  1263.         case 'e':
  1264.             editv (currow, curcol);
  1265.             edit_mode();
  1266.             break;
  1267.         case 'E':
  1268.             edits (currow, curcol);
  1269.             edit_mode();
  1270.             break;
  1271.         case 'f':
  1272.             if (arg == 1)
  1273.             (void) sprintf (line, "format [for column] %s ",
  1274.                 coltoa(curcol));
  1275.             else {
  1276.             (void) sprintf(line, "format [for columns] %s:",
  1277.                 coltoa(curcol));
  1278.             (void) sprintf(line+strlen(line), "%s ",
  1279.                 coltoa(curcol+arg-1));
  1280.             }
  1281.             error("Current format is %d %d",
  1282.                 fwidth[curcol],precision[curcol]);
  1283.             linelim = strlen (line);
  1284.             insert_mode();
  1285.             break;
  1286.         case 'g':
  1287.             (void) sprintf (line, "goto [v] ");
  1288.             linelim = strlen (line);
  1289.             insert_mode();
  1290.             break;
  1291.         case 'P':
  1292.             (void) sprintf (line, "put [\"dest\" range] \"");
  1293.             if (*curfile)
  1294.             error ("Default path is \"%s\"",curfile);
  1295.             linelim = strlen (line);
  1296.             insert_mode();
  1297.             break;
  1298.         case 'M':
  1299.             (void) sprintf (line, "merge [\"source\"] \"");
  1300.             linelim = strlen (line);
  1301.             insert_mode();
  1302.             break;
  1303.         case 'R':
  1304.             if (mdir)
  1305.             (void) sprintf (line,"merge [\"macro_file\"] \"%s/", mdir);
  1306.             else
  1307.             (void) sprintf (line,"merge [\"macro_file\"] \"");
  1308.             linelim = strlen (line);
  1309.             insert_mode();
  1310.             break;
  1311.         case 'D':
  1312.             (void) sprintf (line, "mdir [\"macro_directory\"] \"");
  1313.             linelim = strlen (line);
  1314.             insert_mode();
  1315.             break;
  1316.         case 'G':
  1317.             (void) sprintf (line, "get [\"source\"] \"");
  1318.             if (*curfile)
  1319.             error ("Default file is \"%s\"",curfile);
  1320.             linelim = strlen (line);
  1321.             insert_mode();
  1322.             break;
  1323.         case 'W':
  1324.             (void) sprintf (line, "write [\"dest\" range] \"");
  1325.             linelim = strlen (line);
  1326.             insert_mode();
  1327.             break;
  1328.         case 'S':    /* set options */
  1329.             (void) sprintf (line, "set ");
  1330.             error("Options: byrows, bycols, iterations=n, tblstyle=(0|tbl|latex|tex)");
  1331.             linelim = strlen (line);
  1332.             insert_mode();
  1333.             break;
  1334.         case 'T':    /* tbl output */
  1335.             (void) sprintf (line, "tbl [\"dest\" range] \"");
  1336.             linelim = strlen (line);
  1337.             insert_mode();
  1338.             break;
  1339.         case 'x':
  1340.             {
  1341.             register struct ent **pp;
  1342.             register int c1;
  1343.  
  1344.             flush_saved();
  1345.             if(calc_order == BYROWS) {
  1346.             for (c1 = curcol; arg-- && c1 < maxcols; c1++) {
  1347.             pp = ATBL(tbl, currow, c1);
  1348.             if (*pp) {
  1349.                 free_ent(*pp);
  1350.                 *pp = (struct ent *)0;
  1351.             }
  1352.             }
  1353.             }
  1354.             else {
  1355.             for (c1 = currow; arg-- && c1 < maxrows; c1++) {
  1356.             pp = ATBL(tbl, c1, curcol);
  1357.             if (*pp) {
  1358.                 free_ent(*pp);
  1359.                 *pp = (struct ent *)0;
  1360.             }
  1361.             }
  1362.             }
  1363.             sync_refs();
  1364.             modflg++;
  1365.             FullUpdate++;
  1366.             }
  1367.             break;
  1368.         case 'Q':
  1369.         case 'q':
  1370.             running = 0;
  1371.             break;
  1372.         case 'h':
  1373.             backcol(arg);
  1374.             break;
  1375.         case 'j':
  1376.             forwrow(arg);
  1377.             break;
  1378.         case 'k':
  1379.             backrow(arg);
  1380.             break;
  1381.         case ' ':
  1382.         case 'l':
  1383.             forwcol(arg);
  1384.             break;
  1385.         case 'm':
  1386.             savedrow = currow;
  1387.             savedcol = curcol;
  1388.             break;
  1389.         case 'c': {
  1390.             register struct ent *p = *ATBL(tbl, savedrow, savedcol);
  1391.             register c1;
  1392.             register struct ent *n;
  1393.             if (!p)
  1394.             break;
  1395.             FullUpdate++;
  1396.             modflg++;
  1397.             for (c1 = curcol; arg-- && c1 < maxcols; c1++) {
  1398.             n = lookat (currow, c1);
  1399.             (void) clearent(n);
  1400.             copyent( n, p, currow - savedrow, c1 - savedcol);
  1401.             }
  1402.             break;
  1403.         }
  1404.         default:
  1405.             if ((toascii(c)) != c)
  1406.             error ("Weird character, decimal %d\n",
  1407.                 (int) c);
  1408.             else
  1409.                 error ("No such command (%c)", c);
  1410.             break;
  1411.         }
  1412.     edistate = nedistate;
  1413.     arg = narg;
  1414.     }                /* while (running) */
  1415.     inloop = modcheck(" before exiting");
  1416.     }                /*  while (inloop) */
  1417.     deraw();
  1418.     endwin();
  1419. #ifdef VMS    /* Unit VMS "fixes" exit we should say 1 here */
  1420.     exit(1);
  1421. #else
  1422.     exit(0);
  1423. #endif
  1424.     /*NOTREACHED*/
  1425. }
  1426.  
  1427. void
  1428. startshow()
  1429. {
  1430.     showrange = 1;
  1431.     showsr = currow;
  1432.     showsc = curcol;
  1433. }
  1434.  
  1435. void
  1436. showdr()
  1437. {
  1438.     int     minsr, minsc, maxsr, maxsc;
  1439.  
  1440.     minsr = showsr < currow ? showsr : currow;
  1441.     minsc = showsc < curcol ? showsc : curcol;
  1442.     maxsr = showsr > currow ? showsr : currow;
  1443.     maxsc = showsc > curcol ? showsc : curcol;
  1444.     (void) sprintf (line+linelim,"%s", r_name(minsr, minsc, maxsr, maxsc));
  1445. }
  1446.  
  1447. void
  1448. setorder(i)
  1449. int i;
  1450. {
  1451.     if((i == BYROWS)||(i == BYCOLS))
  1452.         calc_order = i;
  1453.     else
  1454.         error("Not yet implemented");
  1455. }
  1456.  
  1457. void
  1458. setauto(i)
  1459. int i;
  1460. {
  1461.     autocalc = i;
  1462. }
  1463.  
  1464.  
  1465. #ifdef VMS
  1466.  
  1467. goraw()
  1468. {
  1469.     VMS_read_raw = 1;
  1470.     FullUpdate++;
  1471. }
  1472.  
  1473. deraw()
  1474. {
  1475.     (void) move (LINES - 1, 0);
  1476.     (void) clrtoeol();
  1477.     (void) refresh();
  1478.     VMS_read_raw = 0;
  1479. }
  1480.  
  1481. #else /* VMS */
  1482. void
  1483. goraw()
  1484. {
  1485. #if SYSV2 || SYSV3
  1486.     fixterm();
  1487. #else /* SYSV2 || SYSV3 */
  1488.     cbreak();
  1489.     nonl();
  1490.     noecho ();
  1491. #endif /* SYSV2 || SYSV3 */
  1492.     kbd_again();
  1493.     (void) clear();
  1494.     FullUpdate++;
  1495. }
  1496.  
  1497. void
  1498. deraw()
  1499. {
  1500.     (void) move (LINES - 1, 0);
  1501.     (void) clrtoeol();
  1502.     (void) refresh();
  1503. #if SYSV2 || SYSV3
  1504.     resetterm();
  1505. #else
  1506.     nocbreak();
  1507.     nl();
  1508.     echo();
  1509. #endif
  1510.     resetkbd();
  1511. }
  1512.  
  1513. #endif /* VMS */
  1514.  
  1515. void
  1516. signals()
  1517. {
  1518. #ifdef SIGVOID
  1519.     void quit();
  1520.     void time_out();
  1521.     void dump_me();
  1522. #else
  1523.     int quit();
  1524.     int time_out();
  1525.     int dump_me();
  1526. #endif
  1527.  
  1528.     (void) signal(SIGINT, SIG_IGN);
  1529.     (void) signal(SIGQUIT, dump_me);
  1530.     (void) signal(SIGPIPE, quit);
  1531.     (void) signal(SIGTERM, quit);
  1532.     (void) signal(SIGALRM, time_out);
  1533.     (void) signal(SIGFPE, quit);
  1534.     (void) signal(SIGBUS, quit);
  1535. }
  1536.  
  1537. #ifdef SIGVOID
  1538. void
  1539. #endif
  1540. quit()
  1541. {
  1542.     diesave();
  1543.     deraw();
  1544.     resetkbd();
  1545.     endwin();
  1546.     exit(1);
  1547. }
  1548.  
  1549. #ifdef SIGVOID
  1550. void
  1551. #endif
  1552. dump_me()
  1553. {
  1554.     diesave();
  1555.     deraw();
  1556.     abort();
  1557. }
  1558.  
  1559. /* try to save the current spreadsheet if we can */
  1560. diesave()
  1561. {   char    path[PATHLEN];
  1562.     if (modcheck(" before Spreadsheet dies") == 1)
  1563.     {    sprintf(path, "~/SC.SAVE");
  1564.     if (writefile(path, 0, 0, maxrow, maxcol) < 0)
  1565.         if (writefile("/tmp/SC.SAVE", 0, 0, maxrow, maxcol) < 0)
  1566.         error("Couldn't save current spreadsheet, Sorry");
  1567.     }
  1568. }
  1569.  
  1570. int
  1571. modcheck(endstr)
  1572. char *endstr;
  1573. {
  1574.     if (modflg && curfile[0]) {
  1575.     int    yn_ans;
  1576.     char    lin[100];
  1577.  
  1578.     (void) sprintf (lin,"File \"%s\" is modified, save%s? ",curfile,endstr);
  1579.     if ((yn_ans = yn_ask(lin)) < 0)
  1580.         return(1);
  1581.     else
  1582.     if (yn_ans == 1)
  1583.     {    if (writefile(curfile, 0, 0, maxrow, maxcol) < 0)
  1584.          return (1);
  1585.     }
  1586.     } else if (modflg) {
  1587.     int    yn_ans;
  1588.  
  1589.     if ((yn_ans = yn_ask("Do you want a chance to save the data? ")) < 0)
  1590.         return(1);
  1591.     else
  1592.         return(yn_ans);
  1593.     }
  1594.     return(0);
  1595. }
  1596.