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