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