1 /* SC A Spreadsheet Calculator
2 * Curses based Screen 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 * $Revision: 7.16 $
11 *
12 */
13
14
15 #include <curses.h>
16 #include <time.h>
17 #include "sc.h"
18
19 #ifndef MSDOS
20 #include <unistd.h>
21 #endif
22
23 #ifdef VMS
24 extern int VMS_read_raw; /*sigh*/
25 VMS_read_raw = 1;
26 #endif
27
28 #ifdef BROKENCURSES
29 /* nl/nonl bug fix */
30 #undef nl
31 #undef nonl
32 #define nl() (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty))
33 #define nonl() (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty))
34 #endif
35
36 void repaint(int x, int y, int len, int attron, int attroff);
37
38 char under_cursor = ' '; /* Data under the < cursor */
39 char mode_ind = 'i';
40 char search_ind = ' ';
41 extern char revmsg[];
42
43 int lines, cols;
44 int rows, lcols;
45 int lastmx, lastmy; /* Screen address of the cursor */
46 int lastrow = -1; /* Spreadsheet Row the cursor was in last */
47 int lastcol = -1; /* Spreadsheet Column the cursor was in last */
48 int lastendrow = -1; /* Last bottom row of screen */
49 int lastftoprows = 0; /* Rows in top of frame cursor was in last */
50 int lastfbottomrows = 0; /* Rows in bottom of frame cursor was in last */
51 int lastfleftcols = 0; /* Columns in left side of frame cursor was
52 in last */
53 int lastfrightcols = 0;
54 struct frange *lastfr = 0; /* Last framed range we were in */
55 bool frTooLarge = 0; /* If set, either too many rows or too many columns
56 exist in frame to allow room for the scrolling
57 portion of the framed range */
58 int framerows; /* Rows in current frame */
59 int framecols; /* Columns in current frame */
60 int rescol = 4; /* Columns reserved for row numbers */
61 extern int *fwidth;
62 extern int showneed; /* Causes cells needing values to be highlighted */
63 extern int showexpr; /* Causes cell exprs to be displayed, highlighted */
64 extern int shownote; /* Causes cells with attached notes to be highlighted */
65 #ifdef RIGHT_CBUG
66 extern int wasforw; /* Causes screen to be redisplay if on lastcol */
67 #endif
68 extern struct go_save gs;
69
70 /*
71 * update() does general screen update
72 *
73 * standout last time in update()?
74 * At this point we will let curses do work
75 */
76 int standlast = FALSE;
77
78 void
update(int anychanged)79 update(int anychanged) /* did any cell really change in value? */
80 {
81 int row, col;
82 struct ent **pp;
83 int mxrow, mxcol;
84 int minsr = 0, minsc = 0, maxsr = 0, maxsc = 0;
85 int r, i;
86 struct frange *fr;
87 struct crange *cr;
88 int ftoprows, fbottomrows, fleftcols, frightcols;
89 int ftrows, fbrows, flcols, frcols;
90 bool message;
91
92 #ifndef MSDOS
93 /*
94 * If receiving input from a pipeline, don't display spreadsheet data
95 * on screen.
96 */
97 if (!usecurses) return;
98 #endif
99
100 getmaxyx(stdscr, lines, cols);
101 fr = lastfr;
102 if (!(fr && fr->or_left->row <= currow && /* If we've left the */
103 fr->or_left->col <= curcol && /* previous framed range... */
104 fr->or_right->row >= currow &&
105 fr->or_right->col >= curcol)) {
106 fr = find_frange(currow, curcol);
107 if (fr != lastfr)
108 FullUpdate++;
109 }
110 if (fr) {
111 ftoprows = fr->ir_left->row - fr->or_left->row;
112 fbottomrows = fr->or_right->row - fr->ir_right->row;
113 fleftcols = fr->ir_left->col - fr->or_left->col;
114 frightcols = fr->or_right->col - fr->ir_right->col;
115 framerows = RESROW + ftoprows + fbottomrows;
116 framecols = rescol;
117 for (r = fr->or_left->row - 1, i = ftoprows; i; i--)
118 if (row_hidden[r+i])
119 framerows--;
120 for (r = fr->or_right->row - 1, i = fbottomrows; i; i--)
121 if (row_hidden[r-i])
122 framerows--;
123 for (r = fr->or_left->col - 1, i = fleftcols; i; i--) {
124 if (col_hidden[r+i])
125 continue;
126 framecols += fwidth[r+i];
127 }
128 for (r = fr->or_right->col - 1, i = frightcols; i; i--) {
129 if (col_hidden[r-i])
130 continue;
131 framecols += fwidth[r-i];
132 }
133 if (framerows >= lines || framecols >= cols) {
134 frTooLarge = TRUE;
135 if (FullUpdate) {
136 error("Frame too large for screen size - ignoring");
137 }
138 ftoprows = fbottomrows = fleftcols = frightcols = 0;
139 strow -= lastftoprows;
140 stcol -= lastfleftcols;
141 } else {
142 frTooLarge = FALSE;
143 if (strow >= fr->or_left->row) {
144 if (fr == lastfr && strow < fr->or_left->row + ftoprows)
145 strow = fr->or_left->row;
146 else if (strow > fr->ir_right->row) {
147 strow = fr->ir_right->row;
148 FullUpdate++;
149 }
150 }
151 if (stcol >= fr->or_left->col) {
152 if (stcol < fr->or_left->col + fleftcols)
153 stcol = fr->or_left->col;
154 else if (stcol > fr->ir_right->col) {
155 stcol = fr->ir_right->col;
156 FullUpdate++;
157 }
158 }
159 if (fr == lastfr && currow == lastrow)
160 fbottomrows = lastfbottomrows;
161 else if (currow < fr->ir_right->row)
162 fbottomrows = fr->or_right->row - fr->ir_right->row;
163 else
164 fbottomrows = fr->or_right->row - currow;
165 if (fr == lastfr && curcol == lastcol)
166 frightcols = lastfrightcols;
167 else if (curcol < fr->ir_right->col)
168 frightcols = fr->or_right->col - fr->ir_right->col;
169 else
170 frightcols = fr->or_right->col - curcol;
171 }
172 } else {
173 ftoprows = fbottomrows = fleftcols = frightcols = 0;
174 framerows = framecols = 0;
175 }
176 if (fr != lastfr && !gs.stflag && lastfr) {
177 if (strow >= lastfr->ir_left->row)
178 strow -= lastftoprows;
179 if (stcol >= lastfr->ir_left->col)
180 stcol -= lastfleftcols;
181 }
182
183 ftrows = ftoprows;
184 fbrows = fbottomrows;
185 flcols = frcols = 0;
186 if (fr) {
187 for (r = fr->or_left->row - 1, i = ftrows; i; i--)
188 if (row_hidden[r+i])
189 ftrows--;
190 for (r = fr->or_right->row + 1, i = fbrows; i; i--)
191 if (row_hidden[r-i])
192 fbrows--;
193 for (r = fr->or_left->col - 1, i = fleftcols; i; i--) {
194 if (col_hidden[r+i])
195 continue;
196 flcols += fwidth[r+i];
197 }
198 for (r = fr->or_right->col + 1, i = frightcols; i; i--) {
199 if (col_hidden[r-i])
200 continue;
201 frcols += fwidth[r-i];
202 }
203 }
204
205 /*
206 * Place the cursor on the screen. Set col, curcol, stcol, lastcol as
207 * needed. If strow and stcol are negative, centering is forced.
208 */
209 if ((curcol != lastcol) || FullUpdate) {
210 while (col_hidden[curcol]) /* You can't hide the last row or col */
211 curcol++;
212 if (fwidth[curcol] > cols - rescol - 2) {
213 error("column %s too wide - resizing", coltoa(curcol));
214 doformat(curcol, curcol, cols - rescol - 2,
215 precision[curcol], realfmt[curcol]);
216 }
217
218 /* First see if the last display still covers curcol */
219 if (stcol >= 0 && stcol <= curcol) {
220 int c = 0;
221
222 if (fr) {
223 if (fr != lastfr) {
224 if (stcol == fr->or_left->col)
225 stcol += fleftcols;
226 else if (stcol >= fr->or_left->col && !gs.stflag) {
227 stcol += fleftcols;
228 if (stcol > fr->ir_right->col)
229 stcol = fr->ir_right->col + 1;
230 }
231 } else if (stcol == fr->or_left->col)
232 stcol += fleftcols;
233 }
234 i = stcol;
235 lcols = 0;
236 col = rescol + frcols;
237 if (fr && stcol >= fr->or_left->col)
238 if (stcol < fr->ir_left->col)
239 i = fr->or_left->col;
240 else
241 col += flcols;
242 for (; (col + fwidth[i] < cols-1 || col_hidden[i] || i < curcol) &&
243 i < maxcols; i++) {
244 lcols++;
245 if (fr && i == fr->ir_right->col + 1) {
246 col -= frcols;
247 frcols = frightcols = 0;
248 }
249 if (col_hidden[i])
250 continue;
251
252 /* If there isn't room for more columns, and we haven't yet
253 * reached the current column, start removing columns from
254 * the left.
255 */
256 while (col + fwidth[i] > cols - 2) {
257 lcols--;
258 col -= fwidth[stcol];
259 while (col_hidden[++stcol]) /**/ ;
260 FullUpdate++;
261 c++;
262 }
263 col += fwidth[i];
264 }
265 if (!frTooLarge && fr && curcol <= stcol + lcols &&
266 fr->ir_left->col >= stcol + lcols) {
267 while (stcol + lcols < fr->ir_left->col) {
268 col -= fwidth[stcol];
269 lcols--;
270 while (col_hidden[++stcol])
271 lcols--;
272 while (col + fwidth[stcol + lcols] < cols - 1) {
273 col += fwidth[stcol + lcols];
274 lcols++;
275 }
276 }
277 } else if (c)
278 stcol = -1;
279 }
280
281 while (stcol < 0 || curcol < stcol || stcol + lcols - 1 < curcol ||
282 (colsinrange != fwidth[curcol] && stcol != curcol &&
283 stcol + lcols - 1 < gs.g_lastcol)) {
284
285 FullUpdate++;
286
287 /* How about back one? */
288 if (stcol - 1 == curcol) {
289 stcol--;
290 /* Forward one? */
291 } else if (stcol >= 0 && stcol + lcols == curcol) {
292 stcol++;
293 } else if (stcol >= 0 && fr && curcol >= fr->or_left->col &&
294 curcol <= fr->ir_left->col && stcol < curcol &&
295 curcol <= stcol + lcols + fr->ir_left->col -
296 fr->or_left->col) {
297 while ((stcol + lcols < fr->ir_left->col && !frTooLarge) ||
298 (colsinrange != fwidth[curcol] && stcol != curcol &&
299 stcol + lcols - 1 < gs.g_lastcol)) {
300 if (col_hidden[++stcol]) lcols--;
301 }
302 } else {
303 /* Try to put the cursor in the center of the screen.
304 * If we've just jumped to a range using the goto command,
305 * center the range instead.
306 */
307 colsinrange = (colsinrange > cols - rescol -
308 flcols - frcols - 2 ?
309 cols - rescol - flcols - frcols - 2 : colsinrange);
310 col = (cols - rescol - flcols - frcols - colsinrange)/2;
311 stcol = curcol;
312 for (i = curcol - 1;
313 i >= (fr ? fr->or_left->col + fleftcols : 0) &&
314 (col - fwidth[i] > 0 || col_hidden[i]);
315 i--) {
316 stcol--;
317 if (col_hidden[i])
318 continue;
319 col -= fwidth[i];
320 }
321 if (fr && stcol < fr->or_left->col + fleftcols) {
322 stcol = fr->or_left->col + fleftcols;
323 if (curcol < stcol)
324 stcol = curcol;
325 }
326 }
327 /* Now pick up the counts again */
328 i = stcol;
329 lcols = 0;
330 col = rescol + frcols;
331 if (fr && stcol >= fr->or_left->col)
332 if (stcol < fr->ir_left->col)
333 i = fr->or_left->col;
334 else
335 col += flcols;
336 for (; (col + fwidth[i] < cols-1 || col_hidden[i] || i < curcol) &&
337 i < maxcols; i++) {
338 lcols++;
339 if (fr && i == fr->ir_right->col + 1) {
340 col -= frcols;
341 frcols = frightcols = 0;
342 }
343 if (col_hidden[i])
344 continue;
345
346 col += fwidth[i];
347 }
348 }
349 }
350 if (fleftcols && stcol >= fr->or_left->col &&
351 stcol < fr->or_left->col + fleftcols) {
352 lcols += (fr->or_left->col - stcol);
353 stcol = fr->or_left->col + fleftcols;
354 if (curcol < stcol)
355 stcol = curcol;
356 }
357
358 /* Now - same process on the rows as the columns */
359 if ((currow != lastrow) || FullUpdate) {
360 while (row_hidden[currow]) /* You can't hide the last row or col */
361 currow++;
362 if (strow >= 0 && strow <= currow) {
363 int c = 0;
364
365 if (fr) {
366 if (fr != lastfr) {
367 if (strow == fr->or_left->row)
368 strow += ftoprows;
369 else if (strow >= fr->or_left->row && !gs.stflag) {
370 strow += ftoprows;
371 if (strow > fr->ir_right->row)
372 strow = fr->ir_right->row + 1;
373 }
374 } else if (strow == fr->or_left->row)
375 strow += ftoprows;
376 }
377 i = strow;
378 rows = 0;
379 row = RESROW + fbrows;
380 if (fr && strow >= fr->or_left->row)
381 if (strow < fr->ir_left->row)
382 i = fr->or_left->row;
383 else
384 row += ftrows;
385 for (; (row < lines || row_hidden[i] || i < currow) && i < maxrows;
386 i++) {
387 rows++;
388 if (fr && i == fr->ir_right->row + 1) {
389 row -= fbrows;
390 fbrows = fbottomrows = 0;
391 }
392 if (row_hidden[i])
393 continue;
394
395 /* If there isn't room for more rows, and we haven't yet
396 * reached the current row, start removing rows from the
397 * top.
398 */
399 if (row >= lines) {
400 rows--;
401 row--;
402 while (row_hidden[++strow]) /**/;
403 FullUpdate++;
404 c++;
405 }
406 row++;
407 }
408 if (!frTooLarge && fr && currow <= strow + rows &&
409 fr->ir_left->row >= strow + rows) {
410 while (strow + rows < fr->ir_left->row) {
411 while (row_hidden[++strow]) /**/;
412 }
413 } else if (c && currow > lastendrow)
414 strow = -1;
415 }
416
417 while (strow < 0 || currow < strow || strow + rows - 1 < currow ||
418 strow + rows < currow + rowsinrange) {
419
420 FullUpdate++;
421
422 /* How about up one? */
423 if (strow - 1 == currow) {
424 strow--;
425 /* Down one? */
426 } else if (strow >= 0 && strow + rows == currow) {
427 strow++;
428 } else if (strow >= 0 && fr && currow >= fr->or_left->row &&
429 currow <= fr->ir_left->row && strow < currow &&
430 currow <= strow + rows + fr->ir_left->row -
431 fr->or_left->row) {
432 while ((strow + rows < fr->ir_left->row && !frTooLarge) ||
433 (rowsinrange > 1 && strow != currow &&
434 strow + rows - 1 < gs.g_lastrow)) {
435 if (row_hidden[++strow]) rows--;
436 }
437 } else {
438 /* Try to put the cursor in the center of the screen.
439 * If we've just jumped to a range using the goto command,
440 * center the range instead.
441 */
442 rowsinrange = (rowsinrange > lines - RESROW - ftrows - fbrows ?
443 lines - RESROW - ftrows - fbrows : rowsinrange);
444 row = (lines - RESROW - ftrows - fbrows - rowsinrange)/2;
445 strow = currow;
446 for (i = currow - 1;
447 i >= (fr ? fr->or_left->row + ftoprows : 0) &&
448 (row > 0 || row_hidden[i]); i--) {
449 strow--;
450 if (row_hidden[i])
451 continue;
452 row--;
453 }
454 if (fr && strow < fr->or_left->row + ftoprows)
455 strow = fr->or_left->row + ftoprows;
456 if (currow < strow)
457 strow = currow;
458 }
459 /* Now pick up the counts again */
460 i = strow;
461 rows = 0;
462 row = RESROW + fbrows;
463 if (fr && strow >= fr->or_left->row)
464 if (strow < fr->ir_left->row)
465 i = fr->or_left->row;
466 else
467 row += ftrows;
468 for (; (row < lines || row_hidden[i] || i < currow) && i < maxrows;
469 i++) {
470 rows++;
471 if (fr && i == fr->ir_right->row + 1) {
472 row -= fbrows;
473 fbrows = fbottomrows = 0;
474 }
475 if (row_hidden[i])
476 continue;
477
478 row++;
479 }
480 }
481 }
482 if (ftoprows && strow >= fr->or_left->row &&
483 strow < fr->or_left->row + ftoprows) {
484 rows += (fr->or_left->row - strow);
485 strow = fr->or_left->row + ftoprows;
486 if (currow < strow)
487 strow = currow;
488 }
489
490 mxcol = frightcols ? fr->or_right->col : stcol + lcols - 1;
491 mxrow = fbottomrows ? fr->or_right->row : strow + rows - 1;
492 gs.stflag = 0;
493 lastfr = fr;
494 lastftoprows = ftoprows;
495 lastfbottomrows = fbottomrows;
496 lastfleftcols = fleftcols;
497 lastfrightcols = frightcols;
498
499 /* Get rid of cursor standout on the cell at previous cursor position */
500 if (!FullUpdate) {
501 if (showcell) {
502 pp = ATBL(tbl, lastrow, lastcol);
503 if (color && has_colors()) {
504 if ((cr = find_crange(lastrow, lastcol)))
505 color_set(cr->r_color, NULL);
506 else
507 color_set(1, NULL);
508 if (*pp) {
509 if (colorneg && (*pp)->flags & is_valid && (*pp)->v < 0) {
510 if (cr)
511 color_set(((cr->r_color) % CPAIRS) + 1, NULL);
512 else
513 color_set(2, NULL);
514 }
515 else if (colorerr && (*pp)->cellerror)
516 color_set(3, NULL);
517 }
518 }
519 repaint(lastmx, lastmy, fwidth[lastcol], 0, A_STANDOUT);
520 }
521
522 (void) move(lastmy, lastmx+fwidth[lastcol]);
523
524 if ((inch() & A_CHARTEXT) == '<')
525 (void) addch(under_cursor | (inch() & A_ATTRIBUTES));
526
527 repaint(lastmx, RESROW - 1, fwidth[lastcol], A_STANDOUT, 0);
528 repaint(0, lastmy, rescol - 1, A_STANDOUT, 0);
529 if (color && has_colors())
530 color_set(1, NULL);
531 }
532 lastrow = currow;
533 lastcol = curcol;
534 lastendrow = strow + rows;
535
536 /* where is the the cursor now? */
537 lastmy = RESROW;
538 if (fr && strow >= fr->or_left->row)
539 if (strow < fr->ir_left->row)
540 row = fr->or_left->row;
541 else {
542 row = strow;
543 lastmy += ftrows;
544 }
545 else
546 row = strow;
547 for (; row < currow; row++)
548 if (!row_hidden[row])
549 lastmy++;
550
551 lastmx = rescol;
552 if (fr && stcol >= fr->or_left->col)
553 if (stcol < fr->ir_left->col)
554 col = fr->or_left->col;
555 else {
556 col = stcol;
557 lastmx += flcols;
558 }
559 else
560 col = stcol;
561 for (; col < curcol; col++)
562 if (!col_hidden[col])
563 lastmx += fwidth[col];
564
565 if (color && has_colors())
566 color_set(1, NULL);
567
568 if (FullUpdate || standlast) {
569 (void) move(2, 0);
570 (void) clrtobot();
571 (void) standout();
572
573 for (row = RESROW, i = (ftoprows && strow >= fr->or_left->row ?
574 fr->or_left->row : strow);
575 i <= mxrow; i++) {
576 if (ftoprows && strow >= fr->or_left->row &&
577 row == RESROW + ftrows)
578 i = (strow < i ? i : strow);
579 if (fbottomrows && row == lines - fbrows)
580 i = fr->or_right->row - fbottomrows + 1;
581 if (row_hidden[i])
582 continue;
583 (void) move(row, 0);
584 (void) printw("%*d", rescol - 1, i);
585 row++;
586 }
587 #ifdef RIGHT_CBUG
588 if (wasforw) {
589 clearok(stdscr, TRUE);
590 wasforw = 0;
591 }
592 #endif
593 (void) move(2, 0);
594 (void) printw("%*s", rescol, " ");
595
596 for (col = rescol, i = (fleftcols && stcol >= fr->or_left->col ?
597 fr->or_left->col : stcol);
598 i <= mxcol; i++) {
599 register int k;
600 if (fleftcols && stcol >= fr->or_left->col &&
601 col == rescol + flcols)
602 i = (stcol < i ? i : stcol);
603 if (frightcols && col + fwidth[i] >= cols - 1 - frcols &&
604 i < fr->or_right->col - frightcols + 1)
605 i = fr->or_right->col - frightcols + 1;
606 if (col_hidden[i])
607 continue;
608 (void) move(2, col);
609 k = (fwidth[i] - strlen(coltoa(i)))/2;
610 if (fwidth[i] == 1)
611 (void) printw("%1s", coltoa(i%26));
612 else if (braille)
613 (void) printw("%-*s", fwidth[i], coltoa(i));
614 else
615 (void) printw("%*s%-*s", k, "", fwidth[i]-k, coltoa(i));
616 col += fwidth[i];
617 }
618 (void) standend();
619 }
620
621 (void) move(1, 0);
622 message = (inch() & A_CHARTEXT) != ' ';
623 if (showrange) {
624 if (showrange == SHOWROWS) {
625 minsr = showsr < currow ? showsr : currow;
626 minsc = fr ? fr->or_left->col : 0;
627 maxsr = showsr > currow ? showsr : currow;
628 maxsc = fr ? fr->or_right->col : maxcols;
629
630 if (showtop && !message) {
631 (void) clrtoeol();
632 (void) printw("Default range: %d:%d", minsr, maxsr);
633 }
634 } else if (showrange == SHOWCOLS) {
635 minsr = 0;
636 minsc = showsc < curcol ? showsc : curcol;
637 maxsr = maxrows;
638 maxsc = showsc > curcol ? showsc : curcol;
639
640 if (showtop && !message) {
641 char r[6];
642
643 strcpy(r, coltoa(minsc));
644 strcat(r, ":");
645 strcat(r, coltoa(maxsc));
646 (void) clrtoeol();
647 (void) printw("Default range: %s", r);
648 }
649 } else {
650 minsr = showsr < currow ? showsr : currow;
651 minsc = showsc < curcol ? showsc : curcol;
652 maxsr = showsr > currow ? showsr : currow;
653 maxsc = showsc > curcol ? showsc : curcol;
654
655 if (showtop && !message) {
656 (void) clrtoeol();
657 (void) printw("Default range: %s",
658 r_name(minsr, minsc, maxsr, maxsc));
659 }
660 }
661 } else if (braille && braillealt && !message && mode_ind == 'v') {
662 (void) clrtoeol();
663 (void) printw("Current cell: %s%d ", coltoa(curcol), currow);
664 }
665
666 /* Repaint the visible screen */
667 if (showrange || anychanged || FullUpdate || standlast) {
668 /* may be reset in loop, if not next time we will do a FullUpdate */
669 if (standlast) {
670 FullUpdate = TRUE;
671 standlast = FALSE;
672 }
673
674 for (row = (ftoprows && strow >= fr->or_left->row ?
675 fr->or_left->row : strow), r = RESROW;
676 row <= mxrow; row++) {
677 int c = rescol;
678 int do_stand = 0;
679 int fieldlen;
680 int nextcol;
681
682 if (row_hidden[row])
683 continue;
684 if (ftoprows && strow >= fr->or_left->row && r == RESROW + ftrows)
685 row = (strow < row ? row : strow);
686 if (fbottomrows && r == lines - fbrows)
687 row = fr->or_right->row - fbottomrows + 1;
688 for (pp = ATBL(tbl, row, col = (fleftcols && stcol >= fr->or_left->col ?
689 fr->or_left->col : stcol));
690 col <= mxcol;
691 pp += nextcol - col, col = nextcol, c += fieldlen) {
692
693 if (fleftcols && stcol >= fr->or_left->col &&
694 c == rescol + flcols) {
695 col = (stcol < col ? col : stcol);
696 pp = ATBL(tbl, row, col);
697 }
698 if (frightcols && c + fwidth[col] >= cols - 1 - frcols &&
699 col < fr->or_right->col - frightcols + 1) {
700 col = fr->or_right->col - frightcols + 1;
701 pp = ATBL(tbl, row, col);
702 }
703 nextcol = col + 1;
704 if (col_hidden[col]) {
705 fieldlen = 0;
706 continue;
707 }
708
709 fieldlen = fwidth[col];
710
711 /*
712 * Set standout if:
713 *
714 * - showing ranges, and not showing cells which need to be filled
715 * in, and not showing cell expressions, and in a range, OR
716 *
717 * - showing cells which need to be filled in and this one is
718 * of that type (has a value and doesn't have an expression,
719 * or it is a string expression), OR
720 *
721 * - showing cells which have expressions and this one does.
722 */
723 if ((showrange && (!showneed) && (!showexpr)
724 && (row >= minsr) && (row <= maxsr)
725 && (col >= minsc) && (col <= maxsc))
726 || (showneed && (*pp) && ((*pp)->flags & is_valid) &&
727 (((*pp)->flags & is_strexpr) || !((*pp)->expr)))
728 || (showexpr && (*pp) && ((*pp)->expr))
729 || (shownote && (*pp) && ((*pp)->nrow >= 0))) {
730
731 (void) move(r, c);
732 (void) standout();
733 if (color && has_colors() && (cr = find_crange(row, col)))
734 color_set(cr->r_color, NULL);
735 standlast++;
736 if (!*pp) { /* no cell, but standing out */
737 (void) printw("%*s", fwidth[col], " ");
738 (void) standend();
739 if (color && has_colors())
740 color_set(1, NULL);
741 continue;
742 } else
743 do_stand = 1;
744 } else
745 do_stand = 0;
746
747 if ((cr = find_crange(row, col)) && color && has_colors())
748 color_set(cr->r_color, NULL);
749
750 if ((*pp) && (((*pp)->flags & is_changed || FullUpdate) ||
751 do_stand)) {
752 if (do_stand) {
753 (*pp)->flags |= is_changed;
754 } else {
755 (void) move(r, c);
756 (*pp)->flags &= ~is_changed;
757 }
758
759 /*
760 * Show expression; takes priority over other displays:
761 */
762
763 if ((*pp)->cellerror) {
764 if (color && colorerr && has_colors())
765 color_set(3, NULL);
766 (void) printw("%*.*s", fwidth[col], fwidth[col],
767 (*pp)->cellerror == CELLERROR ? "ERROR" : "INVALID");
768 } else
769 if (showexpr && ((*pp)->expr)) {
770 linelim = 0;
771 editexp(row, col); /* set line to expr */
772 linelim = -1;
773 showstring(line, /* leftflush = */ 1, /* hasvalue = */ 0,
774 row, col, &nextcol, mxcol, &fieldlen, r, c,
775 fr, frightcols, flcols, frcols);
776 } else {
777 /*
778 * Show cell's numeric value:
779 */
780
781 if ((*pp)->flags & is_valid) {
782 char field[FBUFLEN];
783 char *cfmt;
784 int note;
785
786 *field = '\0';
787 note = (*pp)->nrow >= 0 ? 1 : 0;
788 cfmt = (*pp)->format ? (*pp)->format :
789 (realfmt[col] >= 0 && realfmt[col] < COLFORMATS &&
790 colformat[realfmt[col]]) ?
791 colformat[realfmt[col]] : NULL;
792 if (color && has_colors() && colorneg && (*pp)->v < 0) {
793 if (cr)
794 color_set(((cr->r_color) % CPAIRS) + 1, NULL);
795 else
796 color_set(2, NULL);
797 }
798 if (cfmt) {
799 if (*cfmt == ctl('d')) {
800 time_t v = (time_t) ((*pp)->v);
801 strftime(field, sizeof(field),
802 cfmt + 1, localtime(&v));
803 } else
804 (void) format(cfmt, precision[col], (*pp)->v,
805 field, sizeof(field));
806 } else {
807 (void) engformat(realfmt[col], fwidth[col] - note,
808 precision[col], (*pp)->v,
809 field, sizeof(field));
810 }
811 if (strlen(field) > fwidth[col]) {
812 for (i = 0; i < fwidth[col]; i++) {
813 if (note) {
814 attr_t attr;
815 short curcolor;
816 if (!i && color && has_colors()) {
817 attr_get(&attr, &curcolor, NULL);
818 color_set(4, NULL);
819 }
820 (void)addch('*');
821 i++;
822 if (!i && color && has_colors())
823 color_set(curcolor, NULL);
824 }
825 (void)addch('*');
826 }
827 } else {
828 if (cfmt && *cfmt != ctl('d'))
829 for (i = 0;
830 i < fwidth[col] - strlen(field) - note;
831 i++)
832 (void)addch(' ');
833 if (note) {
834 attr_t attr;
835 short curcolor;
836 if (color && has_colors()) {
837 attr_get(&attr, &curcolor, NULL);
838 color_set(4, NULL);
839 }
840 (void)addch('*');
841 if (color && has_colors())
842 color_set(curcolor, NULL);
843 }
844 (void)addstr(field);
845 if (cfmt && *cfmt == ctl('d'))
846 for (i = 0;
847 i < fwidth[col] - strlen(field) - note;
848 i++)
849 (void)addch(' ');
850 }
851 }
852
853 /*
854 * Show cell's label string:
855 */
856
857 if ((*pp)->label) {
858 showstring((*pp)->label,
859 (*pp)->flags & (is_leftflush|is_label),
860 (*pp)->flags & is_valid,
861 row, col, &nextcol, mxcol, &fieldlen,
862 r, c, fr, frightcols, flcols, frcols);
863 } else /* repaint a blank cell: */
864 if ((((do_stand || !FullUpdate) &&
865 ((*pp)->flags & is_changed)) ||
866 (color && has_colors() &&
867 cr && cr->r_color != 1)) &&
868 !((*pp)->flags & is_valid) && !(*pp)->label) {
869 (void) printw("%*s", fwidth[col], " ");
870 }
871 } /* else */
872 } else
873 if (!*pp && color && has_colors && cr && cr->r_color != 1) {
874 move(r, c);
875 color_set(cr->r_color, NULL);
876 printw("%*s", fwidth[col], " ");
877 }
878 if (color && has_colors())
879 color_set(1, NULL);
880 if (do_stand) {
881 (void) standend();
882 do_stand = 0;
883 }
884 }
885 r++;
886 }
887 }
888
889 /* place 'cursor marker' */
890 if (showcell && (!showneed) && (!showexpr) && (!shownote)) {
891 (void) move(lastmy, lastmx);
892 pp = ATBL(tbl, currow, curcol);
893 if (color && has_colors()) {
894 if ((cr = find_crange(currow, curcol)))
895 color_set(cr->r_color, NULL);
896 else
897 color_set(1, NULL);
898 if (*pp) {
899 if (colorneg && (*pp)->flags & is_valid && (*pp)->v < 0) {
900 if (cr)
901 color_set(((cr->r_color) % CPAIRS) + 1, NULL);
902 else
903 color_set(2, NULL);
904 } else if (colorerr && (*pp)->cellerror)
905 color_set(3, NULL);
906 }
907 }
908 repaint(lastmx, lastmy, fwidth[lastcol], A_STANDOUT, 0);
909 if (color && has_colors())
910 color_set(1, NULL);
911 }
912
913 repaint(lastmx, RESROW - 1, fwidth[lastcol], 0, A_STANDOUT);
914 repaint(0, lastmy, rescol - 1, 0, A_STANDOUT);
915
916 (void) move(lastmy, lastmx+fwidth[lastcol]);
917 under_cursor = (inch() & A_CHARTEXT);
918 if (!showcell)
919 (void) addch('<' | (inch() & A_ATTRIBUTES));
920
921 (void) move(0, 0);
922 (void) clrtoeol();
923
924 if (linelim >= 0) {
925 int ctlchars;
926
927 for (i = ctlchars = 0; i < linelim; i++)
928 if ((unsigned char) line[i] < ' ')
929 ctlchars++;
930 (void) addch(mode_ind);
931 (void) addch('>');
932 (void) addch(search_ind);
933 (void) addstr(line);
934 if (!braille || (!message && mode_ind != 'v'))
935 (void) move((linelim+3+ctlchars)/cols, (linelim+3+ctlchars)%cols);
936 else if (message)
937 move(1, 0);
938 else if (braillealt)
939 move(1, 16);
940 else
941 move(lastmy, lastmx);
942 } else {
943 if (showtop) { /* show top line */
944 register struct ent *p1;
945 int printed = 0; /* printed something? */
946
947 (void) printw("%s%d ", coltoa(curcol), currow);
948
949 if ((p1 = *ATBL(tbl, currow, curcol)) && p1->nrow > -1)
950 printw("{*%s} ", r_name(p1->nrow, p1->ncol,
951 p1->nlastrow, p1->nlastcol));
952
953 /* show the current cell's format */
954 if ((p1) && p1->format)
955 printw("(%s) ", p1->format);
956 else
957 printw("(%d %d %d) ", fwidth[curcol], precision[curcol],
958 realfmt[curcol]);
959
960 if (p1) {
961 if (p1->expr) {
962 /* has expr of some type */
963 linelim = 0;
964 editexp(currow, curcol); /* set line to expr */
965 linelim = -1;
966 }
967
968 /*
969 * Display string part of cell:
970 */
971
972 if ((p1->expr) && (p1->flags & is_strexpr)) {
973 if (p1->flags & is_label)
974 (void) addstr("|{");
975 else
976 (void) addstr((p1->flags & is_leftflush) ? "<{" : ">{");
977 (void) addstr(line);
978 (void) addstr("} "); /* and this '}' is for vi % */
979 printed = 1;
980
981 } else if (p1->label) {
982 /* has constant label only */
983 if (p1->flags & is_label)
984 (void) addstr("|\"");
985 else
986 (void) addstr((p1->flags & is_leftflush) ? "<\"" : ">\"");
987 (void) addstr(p1->label);
988 (void) addstr("\" ");
989 printed = 1;
990 }
991
992 /*
993 * Display value part of cell:
994 */
995
996 if (p1->flags & is_valid) {
997 /* has value or num expr */
998 if ((!(p1->expr)) || (p1->flags & is_strexpr))
999 (void) sprintf(line, "%.15g", p1->v);
1000
1001 (void) addch('[');
1002 (void) addstr(line);
1003 (void) addch(']');
1004 *line = '\0'; /* this is the input buffer ! */
1005 printed = 1;
1006 }
1007 }
1008 if (!printed)
1009 (void) addstr("[]");
1010 /* Display if cell is locked */
1011 if (p1 && p1->flags&is_locked)
1012 (void) addstr(" locked");
1013 }
1014 if (braille)
1015 if (message)
1016 move(1, 0);
1017 else if (braillealt)
1018 move(0, 0);
1019 else
1020 move(lastmy, lastmx);
1021 else if (showcell)
1022 move(lines - 1, cols - 1);
1023 else
1024 (void) move(lastmy, lastmx+fwidth[lastcol]);
1025 }
1026
1027 if (color && has_colors())
1028 color_set(1, NULL);
1029
1030 if (revmsg[0]) {
1031 (void) move(0, 0);
1032 (void) clrtoeol(); /* get rid of topline display */
1033 (void) printw(revmsg);
1034 *revmsg = '\0'; /* don't show it again */
1035 if (braille)
1036 if (message)
1037 move(1, 0);
1038 else if (braillealt)
1039 move(0, 0);
1040 else
1041 move(lastmy, lastmx);
1042 else if (showcell)
1043 move(lines - 1, cols - 1);
1044 else
1045 (void) move(lastmy, lastmx+fwidth[lastcol]);
1046 }
1047
1048 if (color && has_colors())
1049 color_set(1, NULL);
1050
1051 if (revmsg[0]) {
1052 (void) move(0, 0);
1053 (void) clrtoeol(); /* get rid of topline display */
1054 (void) printw(revmsg);
1055 *revmsg = '\0'; /* don't show it again */
1056 if (braille)
1057 if (message)
1058 move(1, 0);
1059 else
1060 move(lastmy, lastmx);
1061 else if (showcell)
1062 move(lines - 1, cols - 1);
1063 else
1064 (void) move(lastmy, lastmx + fwidth[lastcol]);
1065 }
1066
1067 FullUpdate = FALSE;
1068 }
1069
1070 /* redraw what is under the cursor from curses' idea of the screen */
1071 void
repaint(int x,int y,int len,int attron,int attroff)1072 repaint(int x, int y, int len, int attron, int attroff)
1073 {
1074 while (len-- > 0) {
1075 (void) move(y, x);
1076 addch((inch() | attron) & ~attroff);
1077 x++;
1078 }
1079 }
1080
1081 int seenerr;
1082
1083 /* error routine for yacc (gram.y) */
1084 void
yyerror(char * err)1085 yyerror(char *err)
1086 {
1087 if (usecurses) {
1088 if (seenerr) return;
1089 seenerr++;
1090 (void) move(1, 0);
1091 (void) clrtoeol();
1092 (void) printw("%s: %.*s<=%s", err, linelim, line, line + linelim);
1093 } else
1094 (void) fprintf(stderr, "%s: %.*s<=%s\n", err, linelim, line,
1095 line + linelim);
1096 }
1097
1098 #ifdef XENIX2_3
1099 struct termio tmio;
1100 #endif
1101
1102 void
startdisp()1103 startdisp()
1104 {
1105 #if sun
1106 int fd;
1107 fd = dup(0);
1108 #endif
1109 #ifndef MSDOS
1110 if (usecurses) {
1111 #endif
1112 int i;
1113 #ifdef TIOCGSIZE
1114 { struct ttysize size;
1115 if (ioctl(0, TIOCGSIZE, &size) == 0) {
1116 lines = size.ts_lines;
1117 cols = size.ts_cols;
1118 }
1119 }
1120 #endif
1121
1122 #ifdef XENIX2_3
1123 (void) ioctl(fileno(stdin), TCGETA, & tmio);
1124 #endif
1125 (void) initscr();
1126 start_color();
1127 for (i = 0; i < 8; i++)
1128 if (cpairs[i])
1129 init_pair(i + 1, cpairs[i]->fg, cpairs[i]->bg);
1130 if (color && has_colors())
1131 bkgdset(COLOR_PAIR(1) | ' ');
1132 #if sun
1133 close(0);
1134 dup(fd);
1135 close(fd);
1136 #endif
1137 (void) clear();
1138 #ifdef VMS
1139 VMS_read_raw = 1;
1140 #else
1141 nonl();
1142 noecho();
1143 cbreak();
1144 #endif
1145 initkbd();
1146 scrollok(stdscr, 1);
1147
1148 #if defined(SYSV3) && !defined(NOIDLOK)
1149 # ifndef IDLOKBAD
1150 /*
1151 * turn hardware insert/delete on, if possible.
1152 * turn on scrolling for systems with SYSVr3.{1,2} (SYSVr3.0 has
1153 * this set as the default)
1154 */
1155 idlok(stdscr,TRUE);
1156 # else /*
1157 * This seems to fix (with an empty spreadsheet):
1158 * a) Redrawing the bottom half of the screen when you
1159 * move between row 9 <-> 10
1160 * b) the highlighted row labels being trash when you
1161 * move between row 9 <-> 10
1162 * c) On an xterm on Esix Rev. D+ from eating lines
1163 * -goto (or move) a few lines (or more) past the bottom
1164 * of the screen, goto (or move) to the top line on the
1165 * screen, move upward and the current line is deleted, the
1166 * others move up even when they should not, check by
1167 * noticing the rows become 2, 3, 40, 41, 42... (etc).
1168 */
1169 idlok(stdscr,FALSE);
1170 # endif
1171 #endif
1172
1173 FullUpdate++;
1174 #ifndef MSDOS
1175 }
1176 #endif
1177 }
1178
1179 void
stopdisp()1180 stopdisp()
1181 {
1182 #ifndef MSDOS
1183 if (usecurses) {
1184 #endif
1185 deraw(1);
1186 resetkbd();
1187 endwin();
1188 #ifdef XENIX2_3
1189 (void) ioctl(fileno(stdin), TCSETAW, & tmio);
1190 #endif
1191 #ifndef MSDOS
1192 }
1193 #endif
1194 }
1195
1196 /* init curses */
1197 #ifdef VMS
1198
1199 void
goraw()1200 goraw()
1201 {
1202 if (usecurses) {
1203 VMS_read_raw = 1;
1204 if (color && has_colors())
1205 bkgdset(COLOR_PAIR(1) | ' ');
1206 FullUpdate++;
1207 }
1208 }
1209
1210 void
deraw(int ClearLastLine)1211 deraw(int ClearLastLine)
1212 {
1213 if (usecurses) {
1214 if (ClearLastLine) {
1215 if (color && has_colors())
1216 bkgdset(COLOR_PAIR(0) | ' ');
1217 (void) move(lines - 1, 0);
1218 (void) clrtoeol();
1219 (void) refresh();
1220 }
1221 VMS_read_raw = 0;
1222 }
1223 }
1224
1225 #else /* VMS */
1226 void
goraw()1227 goraw()
1228 {
1229 if (usecurses) {
1230 #if SYSV2 || SYSV3
1231 fixterm();
1232 #else /* SYSV2 || SYSV3 */
1233 cbreak();
1234 nonl();
1235 noecho ();
1236 #endif /* SYSV2 || SYSV3 */
1237 kbd_again();
1238 if (color && has_colors())
1239 bkgdset(COLOR_PAIR(1) | ' ');
1240 FullUpdate++;
1241 }
1242 }
1243
1244 /* clean up curses */
1245 void
deraw(int ClearLastLine)1246 deraw(int ClearLastLine)
1247 {
1248 if (usecurses) {
1249 if (ClearLastLine) {
1250 if (color && has_colors())
1251 bkgdset(COLOR_PAIR(0) | ' ');
1252 (void) move(lines - 1, 0);
1253 (void) clrtoeol();
1254 (void) refresh();
1255 }
1256 #if SYSV2 || SYSV3
1257 resetterm();
1258 #else
1259 nocbreak();
1260 nl();
1261 echo();
1262 #endif
1263 resetkbd();
1264 }
1265 }
1266
1267 #endif /* VMS */
1268