home *** CD-ROM | disk | FTP | other *** search
/ pc.louisiana.edu/pub/unix/ / Louisiana_UNIX.tar / Louisiana_UNIX / xspread3.0.zoo / sc.c < prev    next >
C/C++ Source or Header  |  1994-04-27  |  49KB  |  2,274 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 gator!sawmill!buhrt (Jeff Buhrt)
  11.  *        $Revision: 6.21 A $
  12.  *
  13.  *        More mods by Dan Coppersmith, 5/94
  14.  */
  15.  
  16. #include <sys/types.h>
  17. #include <signal.h>
  18. #include "config.h"
  19. #ifdef DOINGX
  20. #include <X11/Xlib.h>
  21. #include <X11/Xutil.h>
  22. #include <X11/keysym.h>
  23. #else
  24. #include <curses.h>
  25. #endif
  26. #include <ctype.h>
  27.  
  28. #if defined(BSD42) || defined(BSD43)
  29. #include <strings.h>
  30. #else
  31. #ifndef SYSIII
  32. #include <string.h>
  33. #endif
  34. #endif
  35.  
  36. #include <stdio.h>
  37. #include "sc.h"
  38.  
  39. #ifdef DOINGX
  40. #include "scXstuff.h"
  41. #endif
  42.  
  43. #ifndef SAVENAME
  44. #define    SAVENAME "SC.SAVE" /* file name to use for emergency saves */
  45. #endif /* SAVENAME */
  46.  
  47. #ifndef DFLT_PAGER
  48. #define    DFLT_PAGER "more"    /* more is probably more widespread than less */
  49. #endif /* DFLT_PAGER */
  50.  
  51. #define MAXCMD 160    /* for ! command below */
  52.  
  53. #ifdef DOINGX
  54. char    laststring[1024];    /* string at position lastmx,lastmy */
  55. int    lstringstart = -1,      /* table column laststring starts in */
  56.     lstringend = -1;        /*  ... and column it ends in */
  57. /* FIXME- all three above */
  58. #endif
  59.  
  60. #ifdef __STDC__
  61. static void    File_Menu(int);
  62. static void    Option_Menu1(int);
  63. static void    Option_Menu2(int);
  64. void    Main_Menu(void);
  65. static void    Row_Col_Menu(int);
  66. static void    Range_Menu(int);
  67. #else
  68. static void    File_Menu();
  69. static void    Option_Menu1();
  70. static void    Option_Menu2();
  71. void    Main_Menu();
  72. void    Matrix_Menu();
  73. static void    Row_Col_Menu();
  74. static void    Range_Menu();
  75. #endif
  76.  
  77. /* Globals defined in sc.h */
  78.  
  79. struct ent ***tbl;
  80. int strow = 0, stcol = 0;
  81. int currow = 0, curcol = 0;
  82. int savedrow, savedcol;
  83. int FullUpdate = 0;
  84. int ClearScreen = 0;    /* don't try to be smart */
  85. int maxrow, maxcol;
  86. int maxrows, maxcols;
  87. int *fwidth;
  88. int *precision;
  89. int *realfmt;
  90. char *col_hidden;
  91. char *row_hidden;
  92. char line[FBUFLEN];
  93. int changed;
  94. struct ent *to_fix;
  95. int modflg;
  96. char *mdir;
  97. int showsc, showsr;    /* Starting cell for highlighted range */
  98. #ifdef RIGHT_CBUG
  99. int    wasforw    = FALSE;
  100. #endif
  101. int        maintextrows,    /* text rows in main window */
  102.        maintextcols;    /* text cols in main window */
  103.  
  104. char    stringbuf[1024];     /* build misc. strings for display on screen */
  105.  
  106. char    curfile[PATHLEN];
  107. char    revmsg[80];
  108.  
  109. int  linelim = -1;
  110.  
  111. int  showtop   = 1;    /* Causes current cell value display in top line  */
  112. int  showcell  = 1;    /* Causes current cell to be highlighted      */
  113. int  showrange = 0;    /* Causes ranges to be highlighted          */
  114. int  showneed  = 0;    /* Causes cells needing values to be highlighted  */
  115. int  showexpr  = 0;    /* Causes cell exprs to be displayed, highlighted */
  116.  
  117. int  numeric;        /* data entry mode: 1 for numeric                 */ /* Peter Doemel, 11-Feb-1993 */
  118. int  autocalc;        /* 1 to calculate after each update               */
  119. int  calc_order;    /* order of calculation: BYROWS or BYCOLS         */
  120. int  craction = 0;    /* CRCOLS for down, CRROWS for right              */
  121.  
  122. int  autolabel = 1;     /* If room, causes label to be created after a define*/
  123. int  showcursor = SHOWCURSOR;    /* Causes cursor to be displayed */
  124. int  tbl_style = 0;    /* headers for T command output */
  125. int  rndinfinity = 0;
  126. int  numeric_field = 0; /* Started the line editing with a number */
  127. int  rowlimit = -1;
  128. int  collimit = -1;
  129. #if !defined(DOINGX) && defined(SIGWINCH)
  130. int  hitwinch = 0;    /* got a SIGWINCH? */
  131. #endif
  132.  
  133. extern    int lastmx, lastmy;    /* Screen address of the cursor */
  134. extern    int lastcol, lcols;    /* Spreadsheet Column the cursor was in last */
  135.  
  136. /* a linked list of free [struct ent]'s, uses .next as the pointer */
  137. struct ent *freeents = NULL;
  138.  
  139. extern    int    seenerr;
  140. extern    char    *rev;
  141. int    anychanged = FALSE;
  142.  
  143. #ifdef VMS
  144. int VMS_read_raw = 0;
  145. #endif
  146.  
  147. /* return a pointer to a cell's [struct ent *], creating if needed */
  148. struct ent *
  149. lookat(row,col)
  150. int    row, col;
  151. {
  152.     register struct ent **pp;
  153.  
  154.     checkbounds(&row, &col);
  155.     pp = ATBL(tbl, row, col);
  156.     if (*pp == (struct ent *)0) {
  157.         if (freeents != NULL)
  158.     {    *pp = freeents;
  159.         freeents = freeents->next;
  160.     }
  161.     else
  162.         *pp = (struct ent *) scxmalloc((unsigned)sizeof(struct ent));
  163.     if (row>maxrow) maxrow = row;
  164.     if (col>maxcol) maxcol = col;
  165.     (*pp)->label = (char *)0;
  166.     (*pp)->row = row;
  167.     (*pp)->col = col;
  168.     (*pp)->flags = 0;
  169.     (*pp)->expr = (struct enode *)0;
  170.     (*pp)->v = (double) 0.0;
  171.     (*pp)->format = (char *)0;
  172.     (*pp)->cellerror = CELLOK;
  173.     (*pp)->next = NULL;
  174.     }
  175.     return *pp;
  176. }
  177.  
  178. /*
  179.  * This structure is used to keep ent structs around before they
  180.  * are deleted to allow the sync_refs routine a chance to fix the
  181.  * variable references.
  182.  * We also use it as a last-deleted buffer for the 'p' command.
  183.  */
  184. void
  185. free_ent(p)
  186. register struct ent *p;
  187. {
  188.     p->next = to_fix;
  189.     to_fix = p;
  190.     p->flags |= is_deleted;
  191.     p->flags &= ~is_locked;
  192. }
  193.  
  194. /* free deleted cells */
  195. void
  196. flush_saved()
  197. {
  198.     register struct ent *p;
  199.     register struct ent *q;
  200.  
  201.     if (!(p = to_fix))
  202.     return;
  203.     while (p) {
  204.     (void) clearent(p);
  205.     q = p->next;
  206.     p->next = freeents;    /* put this ent on the front of freeents */
  207.     freeents = p;
  208.     p = q;
  209.     }
  210.     to_fix = NULL;
  211. }
  212.  
  213. char    *progname;
  214. static    int    arg = 1;
  215. int    running = TRUE;
  216.  
  217. int
  218. main (argc, argv)
  219. int argc;
  220. char  **argv;
  221. {
  222. #ifdef DOINGX
  223.     /* The following is the XSpread event structure and input buffer for key events */
  224.     XEvent event;
  225.     KeySym  key;
  226.     char buffer[8];
  227.     int count;
  228.     int done;
  229.     int complete;
  230.     int pixel; 
  231. #endif
  232.     int     inloop = 1;
  233.     register int   c;
  234.     int     edistate = -1;
  235.     int     narg;
  236.     int     nedistate;
  237.     char    *revi;
  238.  
  239.     /*
  240.      * Keep command line options around until the file is read so the
  241.      * command line overrides file options
  242.      */
  243.  
  244.     int Mopt = 0;
  245.     int Nopt = 0;
  246.     int Copt = 0; 
  247. /*    int Ropt = 0; */    /* commented by Peter Doemel, 11-Feb-1993 */
  248.     char **copyv = argv;      /*  Added to change font size with  -fn */
  249.     int copyc = argc;
  250.  
  251.     int tempx, tempy;     /* Temp versions of curx, cury */
  252.  
  253.     userfont = NULL;
  254.  
  255. #if defined(MSDOS)
  256.     if ((revi = strrchr(argv[0], '\\')) != NULL)
  257. #else
  258. #ifdef VMS
  259.     if ((revi = strrchr(argv[0], ']')) != NULL)
  260. #else
  261.     if ((revi = strrchr(argv[0], '/')) != NULL)
  262. #endif
  263. #endif
  264.     progname = revi+1;
  265.     else
  266.     progname = argv[0];
  267.  
  268.  
  269.     while (argc > 1 && argv[1][0] == '-') {
  270.     argv++;
  271.     argc--;
  272.         switch (argv[0][1]) {
  273.         case 'x':
  274. #if defined(VMS) || defined(MSDOS) || !defined(CRYPT_PATH)
  275.             (void) fprintf(stderr, "Crypt not available\n");
  276.             exit(1);
  277. #else 
  278.             Crypt = 1;
  279. #endif
  280.             break;
  281.         case 'm':
  282.             Mopt = 1;
  283.             break;
  284.         case 'n':
  285.             Nopt = 1;
  286.             break;
  287.         case 'c':
  288.             Copt = 1;
  289.             break;
  290. /*        case 'r':
  291.             Ropt = 1;
  292.             break; */    /* commented by Peter Doemel, 11-Feb-1993 */
  293.         case 'f':         /*  -fn font size */
  294.                 if (argv[0][2] != 'n') goto ILLEGALOPTION;
  295.             argv++;
  296.             argc--;
  297.             /*userfont = strdup(argv[0]);*/
  298.             userfont = argv[0];
  299.             break;
  300.         case 'N':
  301.             showcursor = !SHOWCURSOR;
  302.             break;
  303.         case 'C':
  304.             craction = CRCOLS;
  305.             break;
  306.         case 'R':
  307.             craction = CRROWS;
  308.             break;
  309.             case 'h':
  310.             print_help();
  311.                     exit(1);
  312.         default:
  313. ILLEGALOPTION:        (void) fprintf(stderr,"%s: unrecognized option: \"%c\"\n",
  314.             progname,argv[0][1]);
  315.             print_help();
  316.             exit(1);
  317.     }
  318.     }
  319.  
  320.     sc_Xinit(copyc, copyv);
  321.  
  322.     *curfile ='\0';
  323.  
  324. #ifdef DOINGX
  325.     graphic_init();  /* initialize graphing parameters */
  326. #else
  327.     maintextrows = LINES;
  328.     maintextcols = COLS;
  329.     startdisp();
  330. #endif
  331.  
  332.     signals();
  333.  
  334.     /* setup the spreadsheet arrays, initscr() will get the screen size */
  335.     if (!growtbl(GROWNEW, 0, 0))
  336.     {    stopdisp();
  337.     exit(1);
  338.     }
  339.  
  340.     /*
  341.      * Build revision message for later use:
  342.      */
  343.  
  344.     (void) strcpy (revmsg, progname);
  345.     for (revi = rev; (*revi++) != ':'; );    /* copy after colon */
  346.     (void) strcat (revmsg, revi);
  347.     revmsg [strlen (revmsg) - 2] = 0;        /* erase last character */
  348.     (void) strcat (revmsg, ":  Type '?' for help.");
  349.  
  350. #if 0 /* original code was: */
  351.     if (argc > 1) {
  352.     (void) strcpy(curfile,argv[1]);
  353.     readfile (argv[1], 0);
  354.     }
  355.  
  356.     if (Mopt)
  357.     autocalc = 0;
  358.     if (Nopt)
  359.     numeric = 0;    /* now according to documentation, Peter Doemel, 11-Feb-1993 */
  360.     if (Copt)
  361.     calc_order = BYCOLS;
  362.     if (Ropt)
  363.     calc_order = BYROWS;
  364. #else    /* Peter Doemel, 11-Feb-1993 */
  365.     autocalc = Mopt ? 0 : 1;
  366.     numeric = Nopt ? 0 : 1;
  367.     calc_order = Copt ? BYCOLS : BYROWS;
  368.  
  369.     if (argc > 1) {    /* moved here by Peter Doemel, 25-Feb-1993 */
  370.     (void) strcpy(curfile,argv[1]);
  371.     readfile (argv[1], 0);
  372.     }
  373. #endif
  374. #ifdef VENIX
  375.     setbuf (stdin, NULL);
  376. #endif
  377.     modflg = 0;
  378.     FullUpdate++;
  379.  
  380.     while (inloop) { running = TRUE;
  381.     while (running) {
  382.     nedistate = -1;
  383.     narg = 1;
  384.     if (edistate < 0 && linelim < 0 && autocalc && (changed || FullUpdate))
  385.     {    EvalAll ();
  386.          if (changed)        /* if EvalAll changed or was before */
  387.         anychanged = TRUE;
  388.          changed = 0;
  389.     }
  390.     else        /* any cells change? */
  391.     if (changed)
  392.          anychanged = TRUE;
  393.  
  394. #if !defined(DOINGX) && defined(SIGWINCH)
  395.     /* got a SIGWINCH? */
  396.     if (hitwinch)
  397.     {    hitwinch = 0;
  398.         stopdisp();
  399.         startdisp();
  400.         FullUpdate++;
  401.     }
  402. #endif
  403.     update(anychanged);
  404.     anychanged = FALSE;
  405.  
  406.     showneed = 0;    /* reset after each update */
  407.     showexpr = 0;
  408. #ifdef DOINGX
  409.     if (!seenerr)
  410.         clearlines(1,1);
  411.     seenerr = 0;    /* note, this is here (vs below ifdef DOINGX),
  412.                 because in X nmgetch() may set seenerr */
  413.  
  414.     c = nmgetch();
  415.     if (!running)    /* nmgetch would set this in Main_Menu() */
  416.         break;
  417. #else
  418.     seenerr = 0;
  419. # ifndef SYSV3    /* HP/Ux 3.1 this may not be wanted */
  420.     (void) refresh(); /* 5.3 does a refresh in getch */ 
  421. # endif
  422.     c = nmgetch();
  423.     getyx(stdscr, tempy, tempx);
  424.     clearlines(1,1);
  425.     (void) move(tempy, tempx);
  426. #endif
  427.  
  428.     /*
  429.      * there seems to be some question about what to do w/ the iscntrl
  430.      * some BSD systems are reportedly broken as well
  431.      */
  432.     /* if ((c < ' ') || ( c == DEL ))   how about international here ? PB */
  433. #if    pyr
  434.        if ( iscntrl(c) || (c >= 011 && c <= 015) )    /* iscntrl broken in OSx4.1 */
  435. #else
  436.        if (isascii(c) && (iscntrl(c) || (c == 020)) )    /* iscntrl broken in OSx4.1 */
  437. #endif
  438.       {   switch (c) {
  439. #if !defined(DOINGX) && defined(SIGTSTP)
  440.         case ctl('z'):
  441.             (void) deraw();
  442.             (void) kill(0, SIGTSTP); /* Nail process group */
  443.  
  444.             /* the pc stops here */
  445.             (void) goraw();
  446.             break;
  447. #endif
  448.         case ctl('r'):
  449.             showneed = 1;
  450.         case ctl('l'):
  451.             FullUpdate++;
  452.             ClearScreen++;
  453. #ifndef DOINGX
  454.             (void) clearok(stdscr,1);
  455. #endif
  456.             /* Centering the display with cursor for middle */
  457.             if(currow > (maintextrows - RESROW)/2)
  458.             strow = currow - ((maintextrows - RESROW) / 2);
  459.             break;
  460.         case ctl('x'):
  461.             FullUpdate++;
  462.             showexpr = 1;
  463. #ifndef DOINGX
  464.             (void) clearok(stdscr,1);
  465. #endif
  466.             break;
  467.         default:
  468.             sprintf(stringbuf, "No such command (^%c)", c + 0100);
  469.             error(stringbuf);
  470.             break;
  471.         case ctl('b'):
  472.             if (numeric_field) {
  473.             write_line(ctl('m'));
  474.             numeric_field = 0;
  475.             }
  476.             backcol(arg);
  477.             break;
  478.         case ctl('c'):
  479.             running = FALSE;
  480.             break;
  481.  
  482.         case ctl('e'):
  483.  
  484.             switch (nmgetch()) {
  485.             case ctl('p'): case 'k':    doend (-1, 0);    break;
  486.             case ctl('n'): case 'j':    doend ( 1, 0);    break;
  487.             case ctl('b'): case 'h':
  488.             case ctl('h'):        doend ( 0,-1);    break;
  489.             case ctl('f'): case 'l':
  490.             case ctl('i'): case ' ':    doend ( 0, 1);    break;
  491.  
  492.             case ESC:
  493.             case ctl('g'):
  494.             break;
  495.  
  496.             default:
  497.             error("Invalid ^E command");
  498.             break;
  499.             }
  500.             break;
  501.  
  502.         case ctl('f'):
  503.             if (numeric_field) {
  504.             write_line(ctl('m'));
  505.             numeric_field = 0;
  506.             }
  507.             forwcol(arg);
  508. #ifdef RIGHT_CBUG
  509.             wasforw++;
  510. #endif
  511.             break;
  512.  
  513.         case ctl('g'):
  514.             showrange = 0;
  515.             linelim = -1;
  516.             clearlines(1,1);
  517.             break;
  518.  
  519.         case ESC:    /* ctl('[') */
  520.             write_line(ESC);
  521.             break;
  522.  
  523.         case ctl('d'):
  524.             write_line(ctl('d'));
  525.             break;
  526.  
  527.         case DEL:
  528.         case ctl('h'):
  529.             if (linelim < 0) {    /* not editing line */
  530.             backcol(arg);    /* treat like ^B    */
  531.             break;
  532.             }
  533.             write_line(ctl('h'));
  534.             break;
  535.  
  536.         case ctl('i'):         /* tab */
  537.             if (linelim < 0) {    /* not editing line */
  538.             forwcol(arg);
  539.             break;
  540.             }
  541.             if (!showrange) {
  542.             startshow();
  543.             } else {
  544.             showdr();
  545.             linelim = strlen(line);
  546.             line[linelim++] = ' ';
  547.             line[linelim] = '\0';
  548.             showrange = 0;
  549.             }
  550.             linelim = strlen (line);
  551.             break;
  552.  
  553.         case ctl('m'):
  554.         case ctl('j'):
  555.             numeric_field = 0;
  556.             write_line(ctl('m'));
  557.             switch(craction) {
  558.               case CRCOLS:
  559.             if ((rowlimit >= 0) && (currow >= rowlimit)) {
  560.                 forwcol(1);
  561.                 currow = 0;
  562.             }
  563.             else {
  564.                 forwrow(1);
  565.             }
  566.             break;
  567.               case CRROWS:
  568.             if ((collimit >= 0) && (curcol >= collimit)) {
  569.                 forwrow(1);
  570.                 curcol = 0;
  571.             }
  572.             else {
  573.                 forwcol(1);
  574.             }
  575.             break;
  576.               default:
  577.             break;
  578.               }
  579.             break;
  580.  
  581.         case ctl('n'):
  582.             if (numeric_field) {
  583.             write_line(ctl('m'));
  584.             numeric_field = 0;
  585.             }
  586.             forwrow(arg);
  587.             break;
  588.  
  589.         case ctl('p'):
  590.             if (numeric_field) {
  591.             write_line(ctl('m'));
  592.             numeric_field = 0;
  593.             }
  594.             backrow(arg);
  595.             break;
  596.  
  597.         case ctl('q'):
  598.             break;    /* ignore flow control */
  599.  
  600.         case ctl('s'):
  601.             break;    /* ignore flow control */
  602.  
  603.         case ctl('t'):
  604. #if !defined(VMS) && !defined(MSDOS)
  605.             error(
  606. "Toggle: a:auto,e:ext funcs,n:numeric,t:top,x:encrypt,$:pre-scale,<MORE>");
  607. #else                 /* no encryption available */
  608.             error(
  609. "Toggle: a:auto, e:ext funcs, n:numeric, t:top, $:pre-scale, <MORE>");
  610. #endif
  611.  
  612. #ifndef DOINGX
  613.             (void) refresh();
  614. #endif
  615.             switch (nmgetch()) {
  616.             case 'a': case 'A':
  617.             case 'm': case 'M':    /* Auto */
  618.                 Option_Menu1(1); break;
  619.             case 'n': case 'N':    /* Numeric */
  620.                 Option_Menu1(2); break;
  621.             case 't': case 'T':    /* Top */
  622.                 Option_Menu1(3); break;
  623.             /* not working well, not usefull anyways */
  624.             /* case 'c': case 'C':    */  /* Cell */
  625.                 /* Option_Menu1(4); break;  */
  626.             case 'x': case 'X':    /* Encrypt */
  627.                 Option_Menu1(5); break;
  628.             case 'l': case 'L':    /* Auto-Label */
  629.                 Option_Menu1(6); break;
  630.             case '$':        /* Pre-scale */
  631.                 Option_Menu2(1); break;
  632.             case 'e': case 'E':    /* Ext-funcs */
  633.                 Option_Menu2(2); break;
  634.             case 'r': case 'R':    /* NL-action */
  635.                 Option_Menu2(3); break;
  636.             case 'z': case 'Z':    /* Row/Col-Limits */
  637.                 Option_Menu2(4); break;
  638.             default:
  639.                 error ("Invalid toggle command");
  640.                 /* note fall thru */
  641.             case ESC:
  642.             case ctl('g'):
  643.                 --modflg;    /* negate the modflg++ */
  644.             }
  645.             FullUpdate++;
  646.             modflg++;
  647.             break;
  648.  
  649.         case ctl('u'):
  650.             narg = arg * 4;
  651.             nedistate = 1;
  652.             break;
  653.  
  654.         case ctl('v'):    /* insert variable name */
  655.             if (linelim > 0)
  656.                 ins_string(v_name(currow, curcol));
  657.             break;
  658.  
  659.         case ctl('w'):    /* insert variable expression */
  660.             if (linelim > 0)  {
  661.             static    char *temp = NULL, *temp1 = NULL;
  662.             static    unsigned    templen = 0;
  663.             int templim;
  664.  
  665.             /* scxrealloc will scxmalloc if needed */
  666.             if (strlen(line)+1 > templen)
  667.             {    templen = strlen(line)+40;
  668.  
  669.                 temp = scxrealloc(temp, templen);
  670.                 temp1= scxrealloc(temp1, templen);
  671.             }
  672.             strcpy(temp, line);
  673.             templim = linelim;
  674.             linelim = 0;        /* reset line to empty    */
  675.             editexp(currow,curcol);
  676.             strcpy(temp1, line);
  677.             strcpy(line, temp);
  678.             linelim = templim;
  679.             ins_string(temp1);
  680.             }
  681.             break;
  682.  
  683.         case ctl('a'):    /* insert variable value */
  684.             if (linelim > 0) {
  685.             struct ent *p = *ATBL(tbl, currow, curcol);
  686.             char temp[100];
  687.  
  688.             if (p && p -> flags & is_valid) {
  689.                 (void) sprintf (temp, "%.*f",
  690.                     precision[curcol],p -> v);
  691.                 ins_string(temp);
  692.             }
  693.             }
  694.             break;
  695.  
  696.         } /* End of the control char switch stmt */
  697.         }
  698.     else if (isascii(c) && isdigit(c) && ((numeric && edistate >= 0) ||
  699.             (!numeric && (linelim < 0 || edistate >= 0)))) {
  700.         /* we got a leading number */
  701.         if (edistate != 0) {
  702.         /* First char of the count */
  703.         if (c == '0')      /* just a '0' goes to left col */
  704.             curcol = 0;
  705.         else {
  706.             nedistate = 0;
  707.             narg = c - '0';
  708.         }
  709.         } else {
  710.         /* Succeeding count chars */
  711.         nedistate = 0;
  712.         narg = arg * 10 + (c - '0');
  713.         }
  714.     } else if (linelim >= 0) {
  715.         /* Editing line */
  716.         switch(c) {
  717.         case ')':
  718.         if (showrange) {
  719.             showdr();
  720.             showrange = 0;
  721.             linelim = strlen (line);
  722.         }
  723.         break;
  724.         default:
  725.         break;
  726.         }
  727.         write_line(c);
  728.  
  729.     } else if (!numeric && ( c == '+' || c == '-' ) ) {
  730.         /* increment/decrement ops */
  731.         register struct ent *p = *ATBL(tbl, currow, curcol);
  732.         if (!p)
  733.         continue;
  734.         if (p->expr && !(p->flags & is_strexpr)) {
  735.         error("Can't increment/decrement a formula\n");
  736.         continue;
  737.         }
  738.         FullUpdate++;
  739.         modflg++;
  740.         if( c == '+' )
  741.             p -> v += (double) arg;
  742.         else
  743.         p -> v -= (double) arg;
  744.     } else
  745.     {    /* switch on a normal command character */
  746.         switch (c) {
  747.         case ':':
  748.             break;    /* Be nice to vi users */
  749.  
  750.         case '@':
  751.             EvalAll ();
  752.             changed = 0;
  753.             anychanged = TRUE;
  754.             break;
  755.  
  756.         case '0': case '1': case '2': case '3': case '4':
  757.         case '5': case '6': case '7': case '8': case '9':
  758.         case '-': case '.': case '+':
  759.             if (locked_cell(currow, curcol))
  760.             break;
  761.             numeric_field = 1;
  762.             (void) sprintf(line,"let %s = %c",
  763.                 v_name(currow, curcol), c);
  764.             linelim = strlen (line);
  765.             insert_mode();
  766.             break;
  767.  
  768.         case '=':
  769.             if (locked_cell(currow, curcol))
  770.             break;
  771.             (void) sprintf(line,"let %s = ",
  772.                     v_name(currow, curcol));
  773.             linelim = strlen (line);
  774.             insert_mode();
  775.             break;
  776.  
  777.         case '!':
  778.             {
  779.             /*
  780.              *  "! command"  executes command
  781.              *  "!"    forks a shell
  782.              *  "!!" repeats last command
  783.              */
  784. #if VMS || MSDOS
  785.             error("Not implemented on VMS or MS-DOS");
  786. #else /* VMS */
  787.             char *shl;
  788.             int pid, temp;
  789.             char cmd[MAXCMD];
  790.             static char lastcmd[MAXCMD];
  791.  
  792.             if (!(shl = getenv("SHELL")))
  793.             shl = "/bin/sh";
  794.  
  795. #ifndef DOINGX
  796.             deraw();
  797. #endif
  798.             (void) fputs("! ", stdout);
  799.             (void) fflush(stdout);
  800.             (void) fgets(cmd, MAXCMD, stdin);
  801.             cmd[strlen(cmd) - 1] = '\0';    /* clobber \n */
  802.             if(strcmp(cmd,"!") == 0)        /* repeat? */
  803.                 (void) strcpy(cmd, lastcmd);
  804.             else
  805.                 (void) strcpy(lastcmd, cmd);
  806.  
  807.             if (modflg)
  808.             {
  809.             (void) puts ("[No write since last change]");
  810.             (void) fflush (stdout);
  811.             }
  812.  
  813.             if (!(pid = fork()))
  814.             {
  815.             (void) signal (SIGINT, SIG_DFL);  /* reset */
  816.             if(strlen(cmd))
  817.                 (void)execl(shl,shl,"-c",cmd,(char *)0);
  818.             else
  819.                 (void) execl(shl, shl, (char *)0);
  820.             exit(-127);
  821.             }
  822.  
  823.             while (pid != wait(&temp));
  824.  
  825.             (void) printf("Press RETURN to continue ");
  826.             fflush(stdout);
  827. #ifndef notdef
  828.             (void)nmgetch();
  829. #ifndef DOINGX
  830.             goraw();
  831. #endif
  832. #endif
  833. #endif /* VMS */
  834.             break;
  835.             }
  836.  
  837.         /*
  838.          * Range commands:
  839.          */
  840.  
  841.         case 'r':
  842.             error (
  843. "Range: x:erase v:value c:copy f:fill d:def u:undef s:show l:lock U:unlock F:fmt");
  844. #ifndef DOINGX
  845.             (void) refresh();
  846. #endif
  847.  
  848.             switch (nmgetch()) {
  849.             case 'x': Range_Menu(1); break;
  850.             case 'v': Range_Menu(2); break;
  851.             case 'c': Range_Menu(3); break;
  852.             case 'f': Range_Menu(4); break;
  853.             case 'd': Range_Menu(5); break;
  854.             case 'u': Range_Menu(6); break;
  855.             case 's': Range_Menu(7); break;
  856.             case 'l': Range_Menu(8); break;
  857.             case 'U': Range_Menu(9); break;
  858.             case 'F': Range_Menu(10); break;
  859.             case ESC:
  860.             case ctl('g'):
  861.                 clearlines(1,1);
  862.                 break;
  863.             default:
  864.                 error("Invalid region command");
  865.                 break;
  866.             }
  867.             break;
  868.  
  869.         /*
  870.          * Row/column commands:
  871.          */
  872.         case 'i': Row_Col_Menu(1); break;    /* insert */
  873.         case 'a': Row_Col_Menu(2); break;    /* append */
  874.         case 'd': Row_Col_Menu(3); break;    /* delete */
  875.         case 'p': Row_Col_Menu(4); break;    /* pull */
  876.         case 'v': Row_Col_Menu(5); break;    /* valueize */
  877.         case 'z': Row_Col_Menu(6); break;    /* hide */
  878.         case 's': Row_Col_Menu(7); break;    /* show */
  879.  
  880.         case '$':
  881.             {
  882.             register struct ent *p;
  883.  
  884.             curcol = maxcols - 1;
  885.             while (!VALID_CELL(p, currow, curcol) && curcol > 0)
  886.             curcol--;
  887.             break;
  888.             }
  889.         case '#':
  890.             {
  891.             register struct ent *p;
  892.  
  893.             currow = maxrows - 1;
  894.             while (!VALID_CELL(p, currow, curcol) && currow > 0)
  895.             currow--;
  896.             break;
  897.             }
  898.         case 'w':
  899.             {
  900.             register struct ent *p;
  901.  
  902.             while (--arg>=0) {
  903.             do {
  904.                 if (curcol < maxcols - 1)
  905.                 curcol++;
  906.                 else {
  907.                 if (currow < maxrows - 1) {
  908.                     while(++currow < maxrows - 1 &&
  909.                         row_hidden[currow]) /* */;
  910.                     curcol = 0;
  911.                 } else {
  912.                     error("At end of table");
  913.                     break;
  914.                 }
  915.                 }
  916.             } while(col_hidden[curcol] ||
  917.                 !VALID_CELL(p, currow, curcol));
  918.             }
  919.             break;
  920.             }
  921.         case 'b':
  922.             {
  923.             register struct ent *p;
  924.  
  925.             while (--arg>=0) {
  926.             do {
  927.                 if (curcol) 
  928.                 curcol--;
  929.                 else {
  930.                 if (currow) {
  931.                     while(--currow &&
  932.                     row_hidden[currow]) /* */;
  933.                     curcol = maxcols - 1;
  934.                 } else {
  935.                     error ("At start of table");
  936.                     break;
  937.                 }
  938.                 }
  939.             } while(col_hidden[curcol] ||
  940.                 !VALID_CELL(p, currow, curcol));
  941.             }
  942.             break;
  943.             }
  944.         case '^':
  945.             currow = 0;
  946.             break;
  947. #ifdef XK_Help
  948.         case XK_Help:
  949. #endif
  950.         case '?':
  951.             help();
  952.             break;
  953.         case '"':
  954.             if (!locked_cell(currow, curcol)) {
  955.                (void) sprintf (line, "label %s = \"",
  956.                        v_name(currow, curcol));
  957.                linelim = strlen (line);
  958.                insert_mode();
  959.             }
  960.             break;
  961.  
  962.         case '<':
  963.             if (!locked_cell(currow, curcol)) {
  964.                (void) sprintf (line, "leftstring %s = \"",
  965.                    v_name(currow, curcol));
  966.                linelim = strlen (line);
  967.                insert_mode();
  968.             }
  969.             break;
  970.  
  971.         case '>':
  972.             if (!locked_cell(currow, curcol)) {
  973.                (void) sprintf (line, "rightstring %s = \"",
  974.                   v_name(currow, curcol));
  975.                linelim = strlen (line);
  976.                insert_mode();
  977.             }
  978.             break;
  979.         case 'e':
  980.             if (!locked_cell(currow, curcol)) {
  981.                editv (currow, curcol);
  982.                edit_mode();
  983.             }
  984.             break;
  985.         case 'E':
  986.             if (!locked_cell(currow, curcol)) {
  987.                edits (currow, curcol);
  988.                edit_mode();
  989.             }
  990.             break;
  991.         case 'f':
  992.             if (arg == 1)
  993.             (void) sprintf (line, "format [for column] %s ",
  994.                 coltoa(curcol));
  995.             else {
  996.             (void) sprintf(line, "format [for columns] %s:",
  997.                 coltoa(curcol));
  998.             (void) sprintf(line+strlen(line), "%s ",
  999.                 coltoa(curcol+arg-1));
  1000.             }
  1001.             sprintf(stringbuf, "Current format is %d %d %d",
  1002.             fwidth[curcol],precision[curcol],realfmt[curcol]);
  1003.             error(stringbuf);
  1004.             linelim = strlen (line);
  1005.             insert_mode();
  1006.             break;
  1007.         case 'F': {
  1008.             register struct ent *p = *ATBL(tbl, currow, curcol);
  1009.             if (p && p->format)
  1010.             {    (void) sprintf(line, "fmt [format] %s \"%s",
  1011.                    v_name(currow, curcol), p->format);
  1012.             edit_mode();
  1013.             }
  1014.             else
  1015.             {    (void) sprintf(line, "fmt [format] %s \"",
  1016.                    v_name(currow, curcol));
  1017.             insert_mode();
  1018.             }
  1019.             linelim = strlen(line);
  1020.             break;
  1021.         }
  1022.         case 'g':
  1023.             (void) sprintf (line, "goto [v] ");
  1024.             linelim = strlen (line);
  1025.             insert_mode();
  1026.             break;
  1027.  
  1028.         case 'G': File_Menu(1); break;    /* Get "file" */
  1029.         case 'P': File_Menu(2); break;    /* Put "file" */
  1030.         case 'W': File_Menu(3); break;    /* Write "file" range */
  1031.         case 'T': File_Menu(4); break;    /* Tbl "file" range */
  1032.         case 'M': File_Menu(5); break;    /* Merge "file" */
  1033.         case 'R': File_Menu(6); break;    /* Merge "macrofile" */
  1034.         case 'D': File_Menu(7); break;    /* mdir "macrodir" */
  1035.  
  1036.         case 'S':    /* set options */
  1037.             (void) sprintf (line, "set ");
  1038.             error("Options:byrows,bycols,iterations=n,tblstyle=(0|tbl|latex|slatex|tex|frame),<MORE>");
  1039.             linelim = strlen (line);
  1040.             insert_mode();
  1041.             break;
  1042.         case 'x':
  1043.             {
  1044.             register struct ent **pp;
  1045.             register int c1;
  1046.  
  1047.             flush_saved();
  1048.             if(calc_order == BYROWS) {
  1049.               for (c1 = curcol; arg-- && c1 < maxcols; c1++) {
  1050.             pp = ATBL(tbl, currow, c1);
  1051.                 if ((*pp) && !locked_cell(currow, curcol)) {
  1052.                if (*pp) {
  1053.                    free_ent(*pp);
  1054.                    *pp = (struct ent *)0;
  1055.                }
  1056.                 }
  1057.               }
  1058.             }
  1059.             else {
  1060.               for (c1 = currow; arg-- && c1 < maxrows; c1++) {
  1061.             pp = ATBL(tbl, c1, curcol);
  1062.                 if ((*pp) && !locked_cell(currow, curcol)) {
  1063.                if (*pp) {
  1064.                    free_ent(*pp);
  1065.                    *pp = (struct ent *)0;
  1066.                }
  1067.                 }
  1068.               }
  1069.             }
  1070.             sync_refs();
  1071.             modflg++;
  1072.             FullUpdate++;
  1073.             }
  1074.             break;
  1075.         case 'Q':
  1076.         case 'q':
  1077.             running = FALSE;
  1078.             break;
  1079.         case 'h':
  1080.             backcol(arg);
  1081.             break;
  1082.         case 'j':
  1083.             forwrow(arg);
  1084.             break;
  1085.         case 'k':
  1086.             backrow(arg);
  1087.             break;
  1088.         case 'H':
  1089.             backcol((curcol-stcol+1)+1);
  1090.             break;
  1091. #ifdef XK_Next
  1092.         case XK_Next:
  1093. #endif
  1094. #ifdef KEY_NPAGE
  1095.         case KEY_NPAGE:            /* page precedente */
  1096. #endif
  1097.         case 'J':
  1098.             forwrow(maintextrows - RESROW - (currow-strow) + 1);
  1099.             break;
  1100. #ifdef XK_Prior
  1101.         case XK_Prior:
  1102. #endif
  1103. #ifdef    KEY_PPAGE
  1104.         case KEY_PPAGE:            /* page suivante */
  1105. #endif
  1106.         case 'K':
  1107.             backrow((currow-strow+1)+3);
  1108.             break;
  1109. #if defined(KEY_HOME) || defined(XK_Home)
  1110. #ifdef XK_Home
  1111.         case XK_Home:
  1112. #endif
  1113. #ifdef KEY_HOME
  1114.         case KEY_HOME:
  1115. #endif
  1116.             currow = 0;
  1117.             curcol = 0;
  1118.             FullUpdate++;
  1119.             break;
  1120. #endif
  1121.         case 'L':
  1122.             forwcol(lcols -(curcol-stcol)+1);
  1123.             break;
  1124.         case ' ':
  1125.         case 'l':
  1126.             forwcol(arg);
  1127.             break;
  1128.         case 'm':
  1129.             savedrow = currow;
  1130.             savedcol = curcol;
  1131.             break;
  1132.         case 'c': {
  1133.             register struct ent *p = *ATBL(tbl, savedrow, savedcol);
  1134.             register c1;
  1135.             register struct ent *n;
  1136.             if (!p)
  1137.             break;
  1138.             FullUpdate++;
  1139.             modflg++;
  1140.             for (c1 = curcol; arg-- && c1 < maxcols; c1++) {
  1141.             n = lookat (currow, c1);
  1142.             (void) clearent(n);
  1143.             copyent( n, p, currow - savedrow, c1 - savedcol);
  1144.             }
  1145.             break;
  1146.         }
  1147.         case '/': Main_Menu(); break;
  1148.         default:
  1149.             if ((toascii(c)) != c)
  1150.             sprintf(stringbuf, "Weird character, decimal %d\n",
  1151.                 (int) c);
  1152.             else
  1153.                 sprintf(stringbuf, "No such command (%c)", c);
  1154.             error(stringbuf);
  1155.             break;
  1156.         }
  1157.         }
  1158.     edistate = nedistate;
  1159.     arg = narg;
  1160.     }                /* while (running) */
  1161.     inloop = modcheck(" before exiting");
  1162.     }                /*  while (inloop) */
  1163.     stopdisp();
  1164. #ifdef VMS    /* Until VMS "fixes" exit we should say 1 here */
  1165.     exit(1);
  1166. #else
  1167.     exit(0);
  1168. #endif
  1169.     /*NOTREACHED*/
  1170. }
  1171.  
  1172. /* show the current range (see ^I), we are moving around to define a range */
  1173. void
  1174. startshow()
  1175. {
  1176.     showrange = 1;
  1177.     showsr = currow;
  1178.     showsc = curcol;
  1179. }
  1180.  
  1181. /* insert the range we defined by moving around the screen, see startshow() */
  1182. void
  1183. showdr()
  1184. {
  1185.     int     minsr, minsc, maxsr, maxsc;
  1186.  
  1187.     minsr = showsr < currow ? showsr : currow;
  1188.     minsc = showsc < curcol ? showsc : curcol;
  1189.     maxsr = showsr > currow ? showsr : currow;
  1190.     maxsc = showsc > curcol ? showsc : curcol;
  1191.     (void) sprintf (line+linelim,"%s", r_name(minsr, minsc, maxsr, maxsc));
  1192. }
  1193.  
  1194. /* set the calculation order */
  1195. void
  1196. setorder(i)
  1197. int i;
  1198. {
  1199.     if((i == BYROWS)||(i == BYCOLS))
  1200.         calc_order = i;
  1201. }
  1202.  
  1203. void
  1204. setauto(i)
  1205. int i;
  1206. {
  1207.     autocalc = i;
  1208. }
  1209.  
  1210. void
  1211. signals()
  1212. {
  1213. #ifdef __STDC__
  1214.  
  1215. sig_type doquit(int);
  1216. sig_type dump_me(int);
  1217. #if !defined(DOINGX) && defined(SIGWINCH)
  1218. sig_type winchg(int);
  1219. #endif
  1220.  
  1221. #else    /* __STDC__ */
  1222.  
  1223. sig_type doquit();
  1224. sig_type dump_me();
  1225. #if !defined(DOINGX) && defined(SIGWINCH)
  1226. sig_type winchg();
  1227. #endif
  1228.  
  1229. #endif    /* __STDC__ */
  1230.  
  1231.     (void) signal(SIGINT, SIG_IGN);
  1232. #if !defined(MSDOS)
  1233.     (void) signal(SIGQUIT, dump_me);
  1234.     (void) signal(SIGPIPE, doquit);
  1235. #ifndef DOINGX
  1236.     (void) signal(SIGALRM, time_out);
  1237. #endif
  1238.     (void) signal(SIGBUS, doquit);
  1239. #endif
  1240.     (void) signal(SIGTERM, doquit);
  1241.     (void) signal(SIGFPE, doquit);
  1242. #if !defined(DOINGX) && defined(SIGWINCH)
  1243.     (void) signal(SIGWINCH, winchg);
  1244. #endif
  1245. }
  1246.  
  1247. #if !defined(DOINGX) && defined(SIGWINCH)
  1248. sig_type
  1249. winchg(sig)
  1250. int    sig;
  1251. {    hitwinch++;
  1252.     (void) signal(SIGWINCH, winchg);
  1253. }
  1254. #endif
  1255.  
  1256. sig_type
  1257. doquit(arg)
  1258. int    arg;
  1259. {
  1260.     diesave();
  1261.     stopdisp();
  1262.     exit(1);
  1263. }
  1264.  
  1265. sig_type
  1266. dump_me(arg)
  1267. int    arg;
  1268. {
  1269.     diesave();
  1270. #ifndef DOINGX
  1271.     deraw();
  1272. #endif
  1273.     abort();
  1274. }
  1275.  
  1276. /* try to save the current spreadsheet if we can */
  1277. void
  1278. diesave()
  1279. {   char    path[PATHLEN];
  1280.  
  1281.     if (modcheck(" before Spreadsheet dies") == 1)
  1282.     {    (void) sprintf(path, "~/%s", SAVENAME);
  1283.     if (writefile(path, 0, 0, maxrow, maxcol) < 0)
  1284.     {
  1285.         (void) sprintf(path, "/tmp/%s", SAVENAME);
  1286.         if (writefile(path, 0, 0, maxrow, maxcol) < 0)
  1287.         error("Couldn't save current spreadsheet, Sorry");
  1288.     }
  1289.     }
  1290. }
  1291.  
  1292. /* check if tbl was modified and ask to save
  1293.  * returning 0 if the user wants to quit (don't keep running), or 1 if 
  1294.  * the program should keep running
  1295.  */
  1296. int
  1297. modcheck(endstr)
  1298. char *endstr;
  1299. {
  1300.     if (modflg && curfile[0]) {
  1301.     int    yn_ans;
  1302.     char    lin[100];
  1303.  
  1304.     (void) sprintf (lin,"File \"%s\" is modified, save%s? ",curfile,endstr);
  1305.     if ((yn_ans = yn_ask(lin)) < 0)
  1306.         return(1);
  1307.     else
  1308.     if (yn_ans == 1)
  1309.     {    if (writefile(curfile, 0, 0, maxrow, maxcol) < 0)
  1310.          return (1);
  1311.     }
  1312.     } else if (modflg) {
  1313.     int    yn_ans;
  1314.  
  1315.     if ((yn_ans = yn_ask("Do you want a chance to save the data? ")) < 0)
  1316.         return(1);
  1317.     else
  1318.         return(yn_ans);
  1319.     }
  1320.     return(0);
  1321. }
  1322.  
  1323. /* Returns 1 if cell is locked, 0 otherwise */
  1324. int
  1325. locked_cell (r, c)
  1326.     int r, c;
  1327. {
  1328.     struct ent *p = *ATBL(tbl, r, c);
  1329.     if (p && (p->flags & is_locked)) {
  1330.         sprintf(stringbuf, "Cell %s%d is locked", coltoa(c), r);
  1331.         error(stringbuf);
  1332.         return(1);
  1333.     }
  1334.     return(0);
  1335. }
  1336.  
  1337. /* Check if area contains locked cells */
  1338. int
  1339. any_locked_cells(r1, c1, r2, c2)
  1340.     int r1, c1, r2, c2 ;
  1341. {
  1342.     int r, c;
  1343.     struct ent *p ;
  1344.  
  1345.     for (r=r1; r<=r2; r++)
  1346.         for (c=c1; c<=c2; c++) {
  1347.             p = *ATBL(tbl, r, c);
  1348.             if (p && (p->flags & is_locked))
  1349.                 return(1);
  1350.         }
  1351.     return(0);
  1352. }
  1353.  
  1354. /*===========================================================================
  1355.  *
  1356.  * The following funtions were writen to implement the cursor style menu
  1357.  *
  1358.  *                                 by SWLin, 8/90
  1359.  */
  1360.  
  1361. unsigned int
  1362. menu(item_no, item, help_prompt)
  1363.    unsigned int item_no;
  1364.    char         *item[], *help_prompt[]; 
  1365.  
  1366. {  int  i, choice, done;
  1367.    char c;
  1368.    int show_screen;
  1369. #ifdef DOINGX
  1370.    int cursor_temp, choice_temp, TempX_Loc, col;
  1371.    XEvent event;
  1372.    KeySym key;
  1373.    char buffer[8];
  1374. #endif
  1375.  
  1376.    choice = 1;
  1377.    done = 0;
  1378.    show_screen = 1;
  1379.  
  1380.    clearlines(1,1);
  1381.  
  1382.    while (!done) {
  1383. #ifdef DOINGX
  1384.     TempX_Loc = event.xbutton.x;
  1385. #endif
  1386.     if (show_screen)
  1387.     {
  1388. #ifdef DOINGX
  1389.     for (i=0, col=0; i < item_no; i++) {
  1390.         XDrawImageString(dpy, mainwin,
  1391.             (i== choice-1) ? maingcreversed : maingc,
  1392.             textcol(col), textrow(1),
  1393.             item[i], strlen(item[i]));
  1394.         col = col + strlen(item[i]) + 2;
  1395.     }
  1396. #else
  1397.     (void) move(1, 0);
  1398.     for (i=0; i < item_no; i++) {
  1399.         if (i == choice-1)
  1400.             standout();
  1401.         addstr(item[i]);
  1402.         if (i == choice-1)
  1403.             standend();
  1404.         addstr("  ");
  1405.     }
  1406.     clrtoeol();
  1407. #endif
  1408.     clearlines(2,2);
  1409. #ifdef DOINGX
  1410.     XDrawImageString(dpy,mainwin,maingc,
  1411.            textcol(0), textrow(2),
  1412.            help_prompt[choice - 1], strlen(help_prompt[choice - 1]));
  1413. #else
  1414.     move(2, 0);
  1415.     addstr(help_prompt[choice - 1]);
  1416.     clrtoeol();
  1417. #endif
  1418.     show_screen = 0;
  1419.     }
  1420.  
  1421.     /*** HACK COURTESY OF MIKE ***/
  1422. #ifdef DOINGX
  1423.     XNextEvent(dpy,&event);
  1424.  
  1425.     switch(event.type)
  1426.     {
  1427.     case MotionNotify:
  1428.         if ( (event.xbutton.y >= 10) && 
  1429.              (event.xbutton.y <= 2 * curfontheight)  )
  1430.         {
  1431.             choice_temp = 1;
  1432.             cursor_temp = ((strlen(item[0])+2) * curfontwidth);
  1433.             while (cursor_temp < event.xbutton.x) {
  1434.                 if (choice_temp < item_no) {
  1435.                     cursor_temp += ( (strlen(
  1436.                               item[choice_temp++])
  1437.                               + 2) * curfontwidth);
  1438.                 } else
  1439.                     break;
  1440.             }
  1441.  
  1442.             if (choice_temp <= item_no)
  1443.             {    if (choice_temp != choice)
  1444.                 {    choice = choice_temp;
  1445.                     show_screen = 1;
  1446.                 } /* end of if choice_temp */
  1447.             } /* only if choice_temp is within bounds */
  1448.         }
  1449.         break;
  1450.  
  1451.        case ButtonPress:
  1452.         if ((event.xbutton.y > 2 * curfontheight))
  1453.         {    choice=0;
  1454.             done=1;
  1455.         }
  1456.         else /* Let the mouse select the exact choice */
  1457.             show_screen = done = 1;
  1458.         break;
  1459.      
  1460.        case Expose:
  1461.         FullUpdate++;
  1462.         update(FALSE);
  1463.         show_screen = 1;
  1464.         break;
  1465.  
  1466.        case MappingNotify:
  1467.         XRefreshKeyboardMapping (&(event.xmapping));
  1468.         break;
  1469.  
  1470.        case ConfigureNotify:
  1471.         sc_handleresize(&event);
  1472.         break;
  1473.  
  1474.        /***** NEEDS TO BE FIXED *****/
  1475.  
  1476.        case KeyPress:
  1477.         if((XLookupString (&(event.xkey),buffer,8,&key,0)) ||
  1478.            (IsCursorKey(key)))
  1479.         { 
  1480.             show_screen = 1;
  1481.             if (!IsCursorKey(key))
  1482.             {
  1483.             c = buffer[0];
  1484.  
  1485. #else
  1486.             show_screen = 1;
  1487.             c = nmgetch();
  1488. #endif
  1489.             switch (c) {
  1490.                 case ctl ('f'):
  1491.                 case 'l': 
  1492.                 case 'L': 
  1493.                     choice++;
  1494.                     if (choice == item_no + 1)
  1495.                         choice = 1;
  1496.                     break; 
  1497.                 case ctl ('b'):
  1498.                 case ' ':
  1499.                 case 'h':
  1500.                 case 'H':
  1501.                     choice--;
  1502.                     if (choice == 0)
  1503.                         choice = item_no;
  1504.                     break;
  1505.                 case ctl ('p'):
  1506.                 case 'k':
  1507.                 case 'K':
  1508.                     choice = 1;
  1509.                     break;
  1510.                 case ctl ('n'):
  1511.                 case 'j':
  1512.                 case 'J':
  1513.                     choice = item_no;
  1514.                     break;
  1515.                 case 27:
  1516.                 case ctl ('g'):
  1517.                     choice = 0;
  1518.                     done = 1;
  1519.                     break;
  1520.                 case 13:
  1521.                 case 10:
  1522.                     done = 1;
  1523.                     break;
  1524.                 default:
  1525.                     for (i=0; i < item_no; i++) {
  1526.                         if ((c == *item[i]) || ((c > 91)
  1527.                         && (c == *item[i] + 32))) {
  1528.                             choice = i+1;
  1529.                             done = 1;
  1530.                             break;
  1531.                         }
  1532.                     }
  1533.                     if (!done) { 
  1534.                         fprintf(stderr, "\7");
  1535.                     }     
  1536.                 break;
  1537.             } /* switch(c) */
  1538. #ifdef DOINGX
  1539.             } /* if !IsCursorKey(key) */
  1540.             else switch(key) {
  1541.             case XK_Up :
  1542.                 choice = 1;
  1543.                 break;
  1544.             case XK_Down:
  1545.                 choice = item_no;
  1546.                 break;
  1547.             case XK_Left:
  1548.                 choice--;
  1549.                 if (choice == 0)
  1550.                     choice = item_no;
  1551.                 break;
  1552.             case XK_Right:
  1553.                 choice++;
  1554.                 if (choice == item_no + 1)
  1555.                     choice = 1;
  1556.                 break; 
  1557.             }
  1558.             break;
  1559.         } /* if XLookupString(..) */
  1560.     } /* switch (event.type) */
  1561. #endif
  1562.    } /* while (!done) */
  1563.    clearlines(1,2);
  1564.    return choice;
  1565. }
  1566.  
  1567.  
  1568. /*
  1569.  *============================================================================
  1570.  */
  1571.  
  1572.  
  1573. static void
  1574. Range_Menu(opt)
  1575. int    opt;
  1576. {   int    doneok;
  1577.  
  1578.     static char *item[] = { 
  1579.             "Erase",
  1580.             "Value",
  1581.             "Copy",
  1582.             "Fill",
  1583.             "Define",
  1584.             "Undefine",
  1585.             "Show",
  1586.             "Lock",
  1587.             "Unlock",
  1588.             "Fmt"
  1589.     };
  1590.  
  1591.     static char *help_prompt[] = {
  1592.             "Clear a range", 
  1593.             "Remove the expressions from a range, leaving just the values",
  1594.             "Copy a source range to a destination range",
  1595.             "Fill a range with constant values",
  1596.             "Assign a name to a cell or a range of cells",
  1597.             "Use this command to undefine a previously defined range name",
  1598.             "Shows the currently defined range names",
  1599.             "Lock a range of cells (disallow input)",
  1600.             "Unlock a range of cells (allow input)",
  1601.             "Format a range of cells",
  1602.     };
  1603.  
  1604.     doneok = FALSE;
  1605.     switch (opt >= 0 ? opt : menu(10, item, help_prompt)) {
  1606.     case 0:
  1607.         if (opt < 0)
  1608.             Main_Menu();
  1609.         break;
  1610.     case 1: /* Erase */
  1611.         (void) sprintf(line,"erase [range] ");
  1612.         doneok = TRUE;
  1613.         break;
  1614.     case 2: /* Value */
  1615.         (void) sprintf(line, "value [range] ");
  1616.         doneok = TRUE;
  1617.         break;
  1618.     case 3: /* Copy */
  1619.         (void) sprintf(line,"copy [dest_range src_range] ");
  1620.         doneok = TRUE;
  1621.         break;
  1622.     case 4: /* Fill */
  1623.         (void) sprintf(line,"fill [range start inc] ");
  1624.         doneok = TRUE;
  1625.         break;
  1626.     case 5: /* Define */
  1627.         (void) sprintf(line,"define [string range] \"");
  1628.         doneok = TRUE;
  1629.         modflg++;
  1630.         break;
  1631.     case 6: /* Undefine */
  1632.         (void) sprintf(line,"undefine [range] ");
  1633.         doneok = TRUE;
  1634.         break;
  1635.     case 7: /* Show */
  1636.         if(are_ranges()) {
  1637.             FILE *f;
  1638.             int pid;
  1639.             char px[MAXCMD] ;
  1640.             char *pager;
  1641.       
  1642.             (void) strcpy(px, "| sort | ");
  1643.             if (!(pager = getenv("PAGER")))
  1644.                 pager = DFLT_PAGER;
  1645.             (void) strcat(px,pager);
  1646.             f = openout(px, &pid);
  1647.             if (!f) {
  1648.                 error("Can't open pipe to sort");
  1649.                 break;
  1650.             }
  1651.             list_range(f);
  1652.             closeout(f, pid);
  1653.         }
  1654.         else
  1655.             error("No ranges defined");
  1656.         break;
  1657.     case 8: /* Lock */
  1658.         (void) sprintf(line,"lock [range] ");
  1659.         doneok = TRUE;
  1660.         break;
  1661.     case 9: /* Unlock */
  1662.         (void) sprintf(line,"unlock [range] ");
  1663.         doneok = TRUE;
  1664.         break;
  1665.     case 10: /* Fmt */
  1666.         (void) sprintf(line, "fmt [range \"format\"] ");
  1667.         doneok = TRUE;
  1668.     default:
  1669.         error("Invalid region command");
  1670.         break;
  1671.     }
  1672.  
  1673.     if (doneok)    /* wrote something to edit */
  1674.     {    linelim = strlen (line);
  1675.     startshow();
  1676.     insert_mode();
  1677.     show_top_line();
  1678.     }
  1679. }
  1680.  
  1681. /*
  1682.  *============================================================================
  1683.  */
  1684.  
  1685. static void
  1686. Row_Col_Menu(opt)
  1687. int    opt;
  1688. {
  1689.     static char *item[] = { 
  1690.             "Insert",
  1691.             "Append",
  1692.             "Delete", 
  1693.             "Pull", 
  1694.             "Remove", 
  1695.             "Hide", 
  1696.             "Show",
  1697.             "Format"
  1698.     };
  1699.  
  1700.     static  char *help_prompt[] = {
  1701.             "Insert a new, empty row (column)",
  1702.             "Append a new copy of the current row (column)",
  1703.             "Delete the current row (column)",
  1704.             "Pull deleted cells back into the spreadsheet",
  1705.             "Remove/Valuize expressions from the affected rows (columns)",
  1706.             "Hide (``zap'') the current row (column)",
  1707.             "Show hidden rows (columns)",
  1708.             "Set the output format"
  1709.     };
  1710.  
  1711.     static char *item_1[] = {"Row", "Column"};
  1712.  
  1713.     static char *help_promt_1[] = {"Make change to rows",
  1714.                 "Make change to columns"};
  1715.  
  1716.     switch (opt >= 0 ? opt : menu(8, item, help_prompt)) {
  1717.  
  1718.     case 0: 
  1719.         if (opt < 0)
  1720.             Main_Menu();
  1721.         break;
  1722.  
  1723.     case 1: /* Insert */
  1724.         switch(menu(2, item_1, help_promt_1) ) {
  1725.             case 0: Row_Col_Menu(-1);  break;
  1726.             case 1: insertrow (arg); break;
  1727.             case 2: opencol (curcol, arg); break;
  1728.         }
  1729.         break;
  1730.  
  1731.     case 2: /* Append */
  1732.         switch(menu(2, item_1, help_promt_1)) {
  1733.             case 0:    Row_Col_Menu(-1);  break;
  1734.             case 1: while (arg--) duprow(); break;
  1735.             case 2: while (arg--) dupcol(); break;
  1736.         }
  1737.         break;
  1738.  
  1739.     case 3: /* Delete */
  1740.         switch(menu(2, item_1, help_promt_1)) {
  1741.             case 0: Row_Col_Menu(-1);  break;
  1742.             case 1: deleterow (arg); break;
  1743.             case 2: closecol (curcol, arg); break;
  1744.         }
  1745.         break;
  1746.  
  1747.     case 4: /* Pull */
  1748.         switch(menu(2, item_1, help_promt_1)) {
  1749.             case 0: Row_Col_Menu(-1);  break;
  1750.             case 1: while (arg--)
  1751.                     pullcells ('r');
  1752.                 break;
  1753.             case 2: while (arg--)
  1754.                     pullcells ('c');
  1755.                 break;
  1756.         }
  1757.         break;
  1758.  
  1759.     case 5: /*
  1760.          * Remove
  1761.          * -turn an area starting at currow/curcol into
  1762.          * constants vs expressions - not reversable
  1763.          */
  1764.         switch(menu(2, item_1, help_promt_1)){ 
  1765.             case 0: Row_Col_Menu(-1);  break;
  1766.             case 1:    valueize_area(currow, 0, currow + arg - 1, maxcol);
  1767.                 modflg = 1;
  1768.                 break;
  1769.             case 2: valueize_area(0, curcol, maxrow, curcol + arg - 1);
  1770.                 modflg = 1;
  1771.                 break;
  1772.         }
  1773.         break;
  1774.  
  1775.     case 6: /* Hide */
  1776.         switch (menu(2, item_1, help_promt_1)) {
  1777.             case 0: Row_Col_Menu(-1);  break;
  1778.             case 1: hiderow (arg); break;
  1779.             case 2: hidecol (arg); break;
  1780.         }
  1781.         modflg++;
  1782.         break;
  1783.  
  1784.     case 7:   /* Show: special case; no repeat count */
  1785.         switch(menu(2, item_1, help_promt_1)) {
  1786.             case 0: Row_Col_Menu(-1);  break;
  1787.             case 1: rowshow_op(); break;
  1788.             case 2: colshow_op(); break;
  1789.         }
  1790.         break;
  1791.     case 8:   /* Format */
  1792.         if (arg == 1)
  1793.             (void) sprintf (line, "format [for column] %s ",
  1794.                 coltoa(curcol));
  1795.         else {
  1796.             (void) sprintf(line, "format [for columns] %s:",
  1797.                        coltoa(curcol));
  1798.             (void) sprintf(line+strlen(line), "%s ",
  1799.                        coltoa(curcol+arg-1));
  1800.         }
  1801.         sprintf(stringbuf,"Current format is %d %d",
  1802.                     fwidth[curcol],precision[curcol]);
  1803.         clearlines(1,1);
  1804. #ifdef DOINGX
  1805.         XDrawImageString(dpy,mainwin,maingc,
  1806.                  textcol(0), textrow(1),
  1807.                  stringbuf, strlen(stringbuf));
  1808.         XFlush(dpy);
  1809. #else
  1810.         addstr(stringbuf);
  1811.         refresh();
  1812. #endif
  1813.         seenerr = 1;
  1814.         linelim = strlen (line);
  1815.         break;
  1816.     }
  1817. }
  1818.  
  1819.                
  1820.  
  1821. /*
  1822.  *============================================================================
  1823.  */
  1824.  
  1825. static void
  1826. Option_Menu1(opt)
  1827. int    opt;
  1828. {
  1829.     int    doneok;
  1830.     static char *item[] = {
  1831.             "Auto",
  1832.             "Numeric",
  1833.             "Top",
  1834.             "Cell", /* currently commented out */
  1835.             "Encrypt",
  1836.             "Auto-Label",
  1837.             "Set",
  1838.             "MORE_OPTIONS"
  1839.     };
  1840.  
  1841.     static char *help_prompt[] = {
  1842.             "Recalculate automatically or on ``@'' commands",
  1843.             "Make a digit starts a numeric value",  
  1844.             "Top line display enable/disable", 
  1845.             "Current cell highlighting enable/disable",
  1846.             "Encrypt/decrypt database and listing files",
  1847.             "Auto-Label cells",
  1848.             "Set other options",
  1849.             "NEXT OPTION MENU"
  1850.     };
  1851.  
  1852.     doneok = FALSE;
  1853.     switch (opt >= 0 ? opt : menu(8, item, help_prompt)) {
  1854.     case 0:
  1855.         if (opt < 0)
  1856.             Main_Menu();
  1857.         break; 
  1858.     case 1:
  1859.         autocalc = (! autocalc);
  1860.         sprintf(stringbuf, "Automatic recalculation %sabled.",
  1861.             autocalc ? "en":"dis"); 
  1862.         error(stringbuf);
  1863.         doneok = TRUE;
  1864.         break;
  1865.     case 2:
  1866.         numeric = (! numeric);
  1867.         sprintf(stringbuf,"Numeric input %sabled.",
  1868.             numeric ? "en" : "dis");
  1869.         error(stringbuf);
  1870.         doneok = TRUE;
  1871.         break;
  1872.     case 3:
  1873.         showtop = (! showtop);
  1874. #ifdef DOINGX
  1875.         redraw_current(maingc);
  1876. #else
  1877.         repaint(lastmx, lastmy, fwidth[lastcol]);
  1878. #endif
  1879.         sprintf(stringbuf,"Top line %sabled.", showtop ? "en" : "dis");
  1880.         error(stringbuf);
  1881.         doneok = TRUE;
  1882.         break;
  1883.     case 4: 
  1884.         showcell = (! showcell);
  1885. #ifdef DOINGX
  1886.         redraw_current(maingc);
  1887. #else
  1888.         repaint(lastmx, lastmy, fwidth[lastcol]);
  1889. #endif
  1890.         sprintf(stringbuf,"Cell highlighting %sabled.",
  1891.             showcell ? "en" : "dis");
  1892.         error(stringbuf);
  1893.         doneok = TRUE;
  1894.         break;
  1895.     case 5:
  1896. #if defined(VMS) || defined(MSDOS) || !defined(CRYPT_PATH)
  1897.         error ("Encryption not available.");
  1898. #else 
  1899.         Crypt = (! Crypt);
  1900.         sprintf(stringbuf,"Encryption %sabled.", Crypt? "en" : "dis");
  1901.         error(stringbuf);
  1902. #endif
  1903.         doneok = TRUE;
  1904.         break;
  1905.     case 6:
  1906.         autolabel = (! autolabel);
  1907.         sprintf(stringbuf, "Autolabel %sabled.",
  1908.             autolabel ? "en" : "dis");
  1909.         error(stringbuf);
  1910.         doneok = TRUE;
  1911.         break;
  1912.     case 7:
  1913.         (void) sprintf (line, "set ");
  1914.     error("Options: byrows, bycols, iterations=n, tblstyle=(0|tbl|latex|tex)");
  1915.         linelim = strlen (line);
  1916.         break;
  1917.     case 8:
  1918.         Option_Menu2(-1);
  1919.         break;
  1920.     }
  1921.     if (doneok)
  1922.     {    FullUpdate++;
  1923.     modflg++;
  1924.     }
  1925. }
  1926.  
  1927. static void
  1928. Option_Menu2(opt)
  1929. int    opt;
  1930. {
  1931.     int    doneok;
  1932.     static char *item[] = {
  1933.             "Pre-scale",
  1934.             "Ext-funcs",
  1935.             "NL-action",
  1936.             "Row/Col-Limits",
  1937.             "Set"
  1938.     };
  1939.  
  1940.     static char *help_prompt[] = {
  1941.             "Numeric constants entered are multipled by 0.01",
  1942.             "External function execution enable/disable",
  1943.             "Newline action (direction)",
  1944.             "Set the current cell to the limit for NL-Limit",
  1945.             "Set other options"
  1946.     };
  1947.  
  1948.     doneok = FALSE;
  1949.     switch (opt >= 0 ? opt : menu(5, item, help_prompt)) {
  1950.     case 0:
  1951.         if (opt < 0)
  1952.             Main_Menu();
  1953.         break; 
  1954.     case 1:
  1955.         if (prescale == 1.0) {
  1956.             error ("Prescale enabled.");
  1957.             prescale = 0.01;
  1958.         } else {
  1959.             prescale = 1.0;
  1960.             error ("Prescale disabled.");
  1961.         }
  1962.         doneok = TRUE;
  1963.         break;
  1964.     case 2: 
  1965.         extfunc = (! extfunc);
  1966.         sprintf(stringbuf,"External functions %sabled.",
  1967.             extfunc? "en" : "dis");
  1968.         error(stringbuf);
  1969.         doneok = TRUE;
  1970.         break;
  1971.     case 3:
  1972.         ++craction;
  1973.         if (craction >= 3)
  1974.             craction = 0;
  1975.         switch(craction) {
  1976.             case CRCOLS:
  1977.                 error("Down row after new line");
  1978.                 break;
  1979.             case CRROWS:
  1980.                 error("Right column after new line");
  1981.                 break;
  1982.             default:
  1983.                 craction = 0; /* fall through */
  1984.             case 0:
  1985.                 error("No action after new line");
  1986.                 break;
  1987.         }
  1988.         doneok = TRUE;
  1989.         break;
  1990.     case 4:
  1991.         rowlimit = currow;
  1992.         collimit = curcol;
  1993.         error("Row and column limits set");
  1994.         doneok = TRUE;
  1995.         break;
  1996.     case 5:
  1997.         (void) sprintf (line, "set ");
  1998.     error("Options: byrows, bycols, iterations=n, tblstyle=(0|tbl|latex|tex)");
  1999.         linelim = strlen (line);
  2000.         break;
  2001.     }
  2002.     if (doneok)
  2003.     {    FullUpdate++;
  2004.     modflg++;
  2005.     }
  2006. }
  2007.  
  2008.  
  2009. /*
  2010.  *============================================================================
  2011.  */
  2012.  
  2013. static void
  2014. File_Menu(opt)
  2015. int    opt;
  2016. {
  2017.     int    doneok, length;
  2018.     static char tmp[PATHLEN];
  2019.     static char *item[] = {
  2020.             "Get",
  2021.             "Put",
  2022.             "Write",
  2023.             "Table",
  2024.             "Merge",
  2025.             "Combine",
  2026.             "Directory"
  2027.     };
  2028.  
  2029.     static char *help_prompt[] = {
  2030.         "Get a new database from a file",
  2031.         "Put the current database into a file",
  2032.         "Write the current database into a file in its screen format",
  2033.         "Write the current database to a file in table format",
  2034.         "Merge files",
  2035.         "Combine macro files",
  2036.         "Set directory"
  2037.     };
  2038.  
  2039.     doneok = FALSE;
  2040.     switch (opt >= 0 ? opt : menu(7, item, help_prompt)) {
  2041.     case 0:
  2042.         if (opt < 0)
  2043.             Main_Menu();
  2044.         break;
  2045.     case 1:        /* Get */
  2046.         get_default_path(tmp);
  2047.         (void) sprintf(line, "get [\"source\"] \"%s", tmp);
  2048.         doneok = TRUE;
  2049.         break;
  2050.     case 2:        /* Put */
  2051.         get_default_path(tmp);
  2052.         (void) sprintf(line, "put [\"dest\" range] \"%s", tmp);
  2053.         doneok = TRUE;
  2054.         break;
  2055.     case 3:        /* Write */
  2056.         get_default_path(tmp);
  2057.         if (*curfile)
  2058.         {     char    *defwfile;
  2059.  
  2060.             defwfile = fsuffix(tmp, ".asc");
  2061.                 sprintf(line, "write [\"dest\" range] \"%s", 
  2062.                 defwfile);
  2063.         }
  2064.         else
  2065.             sprintf(line, "write [\"dest\" range] \"%s", tmp);
  2066.         doneok = TRUE;
  2067.         break;
  2068.  
  2069.     case 4:    /* tbl output */
  2070.         get_default_path(tmp);
  2071.         if (*curfile)
  2072.         {    char     *deftfile;
  2073.             char     *suffix;
  2074.             if (tbl_style == 0)
  2075.                   suffix = ".cln";
  2076.             else if (tbl_style == TBL)
  2077.                 suffix = ".tbl";
  2078.             else if (tbl_style == LATEX)
  2079.                 suffix = ".lat";
  2080.             else if (tbl_style == SLATEX)
  2081.                 suffix = ".stx";
  2082.             else if (tbl_style == TEX)
  2083.                 suffix = ".tex";
  2084.             else
  2085.                 suffix = NULL;
  2086.  
  2087.             if (suffix != NULL)
  2088.             {   deftfile = fsuffix(tmp, suffix);
  2089.                 sprintf(line, "tbl [\"dest\" range] \"%s", 
  2090.                     deftfile);
  2091.                 scxfree(deftfile);
  2092.             }     
  2093.         }
  2094.         else
  2095.             (void) sprintf(line, "tbl [\"dest\" range] \"%s", tmp);
  2096.         doneok = TRUE;
  2097.         break;
  2098.  
  2099.     case 5:    /* Merge */
  2100.         get_default_dir(tmp);
  2101.         (void) sprintf(line,"merge [\"merge_file\"] \"%s", tmp);
  2102.         doneok = TRUE;
  2103.         break;
  2104.  
  2105.     case 6:    /* Combine */
  2106.         get_default_dir(tmp);
  2107.         (void)sprintf(line,"merge [\"macro_file\"] \"%s", tmp);
  2108.         doneok = TRUE;
  2109.         break;
  2110.  
  2111.     case 7:    /* Directory */
  2112.         get_default_dir(tmp);
  2113.         (void) sprintf(line, "mdir [\"macro_dir\"] \"%s", tmp);
  2114.         doneok = TRUE;
  2115.         break;
  2116.     } /* switch */
  2117.  
  2118.     if (doneok)    /* wrote something to edit */
  2119.     {    linelim = strlen (line);
  2120.     insert_mode();
  2121.     show_top_line();
  2122.     }
  2123. }
  2124.  
  2125.  
  2126. /*
  2127.  *===========================================================================
  2128.  */
  2129. /****************************************************************************/
  2130. /*                                                                          */
  2131. /* The follwing function displays the Matrix_Menu                           */
  2132. /*                                                                          */
  2133. /*                                           - Fang Wang     12/91          */
  2134. /****************************************************************************/
  2135.  
  2136. void Matrix_Menu()
  2137. {   int    doneok;
  2138.  
  2139.     static char *item[] = {
  2140.             "Transpose",
  2141.             "Addition",
  2142.             "Subtraction",
  2143.             "Multiplication",
  2144.             "Invert"
  2145.     };
  2146.     static char *help_prompt[] = {
  2147.             "Transpose the matrix",
  2148.             "Add two matrices",
  2149.             "Subtract the 2nd matrix from the 1st one",
  2150.             "Multiply the 1st matrix by the 2nd one",
  2151.             "Invert the matrix"
  2152.     };
  2153.  
  2154.     doneok = FALSE;
  2155.     switch (menu(5, item, help_prompt)) {
  2156.     case 0:
  2157.         Main_Menu();
  2158.         break;
  2159.     case 1:
  2160.         get_trans();
  2161.         break;
  2162.     case 2:
  2163.         get_add();
  2164.         break;
  2165.     case 3:
  2166.         get_sub();
  2167.         break;
  2168.     case 4:
  2169.                 get_mult();
  2170.         break;
  2171.     case 5:
  2172.     /*(void) sprintf(line,"matrix_inv [dest_range source_range] ");*/
  2173.         /*doneok = TRUE;*/
  2174.         get_invert();
  2175.         break;
  2176.     default:
  2177.         error("Invalid region command");
  2178.         break;
  2179.     }
  2180.  
  2181.     /*if (doneok)     wrote something to edit 
  2182.     {    linelim = strlen (line);
  2183.     startshow();
  2184.     insert_mode();
  2185.     show_top_line();
  2186.     }*/
  2187. }
  2188.  
  2189. /*============================================================================
  2190. */
  2191.  
  2192. void
  2193. Main_Menu()
  2194. {
  2195.     static char *item[] = {
  2196.             "Range",
  2197.             "Column/Row",
  2198.             "Option",
  2199.             "File",
  2200.             "Graph",
  2201.             "Matrix",
  2202.             "Quit"
  2203.     };
  2204.  
  2205.     static char *help_prompt[] = {
  2206.     "Erase  Value  Copy  Fill  Define  Show  Undefine Lock Unlock Fmt",
  2207.     "Insert  Append  Delete  Pull  Remove  Hide  Show  Format",
  2208.     "Auto  Numeric  Top  Cell  Encrypt  Pre-scale  Ext-funcs  Set",
  2209.     "Get  Put  Write  Table  Merge  Combine  Directory",
  2210.     "Type  A  B  C  D  E  F  Reset  View  Option",
  2211.     "Transpose  Addition  Substraction  Multiplication  Invert ",
  2212.     "Quit this spreadsheet"
  2213.     };
  2214.  
  2215.       switch(menu(7, item, help_prompt)) {
  2216.     case 0:
  2217.         show_top_line();
  2218.         break;
  2219.     case 1:
  2220.         Range_Menu(-1);
  2221.         break;
  2222.     case 2:
  2223.         Row_Col_Menu(-1);
  2224.         break;
  2225.     case 3:
  2226.         Option_Menu1(-1);
  2227.         break;
  2228.     case 4:
  2229.         File_Menu(-1);
  2230.         break;
  2231.     case 5:
  2232. #ifdef DOINGX
  2233.         Graph_Menu();
  2234. #else
  2235.         error("Graphing is not yet supported in curses");
  2236. #endif
  2237.         break;
  2238.     case 6:
  2239.         Matrix_Menu();
  2240.         break;
  2241.     case 7:
  2242.         running = FALSE;
  2243.         break;
  2244.       }
  2245. }
  2246.  
  2247. #ifdef DOINGX
  2248. /*** B. Backman 7-27-91
  2249.  * redraw_current will redraw the cell at the cursor, using the graphics
  2250.  * context specified by the argument gc.  The current cursor position on 
  2251.  * the screen must be stored in lastmx and lastmy (the col. and row), the 
  2252.  * string containing the cursor is stored in laststring and covers table
  2253.  * columns lstringstart through lstringend.  Since the cursor is in there,
  2254.  * we must, therefore have:  lstrinstart <= lastcol <= lstringend. 
  2255.  ***/
  2256. redraw_current(gc)
  2257.   GC gc;
  2258. {
  2259.     int i;
  2260.     int skip = 0;
  2261.  
  2262.     XDrawImageString(dpy, mainwin, gc, 0, 0, "curr", 4);
  2263. /* FIXME
  2264.     for (i=lstringstart; i<curcol; i++)
  2265.         skip += fwidth[i];
  2266.     XDrawImageString(dpy, mainwin, gc,
  2267.              textcol(lastmx+skip), textrow(lastmy),
  2268.              laststring+skip,
  2269.              ((fwidth[curcol] < (int)strlen(laststring+skip)) 
  2270.                 ? fwidth[curcol] : strlen(laststring+skip)));
  2271. */
  2272. }
  2273. #endif
  2274.