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