1 /*
2  * $Id: io-curses.c,v 1.20 2001/02/13 23:38:06 danny Exp $
3  *
4  * Copyright � 1992, 1993, 1999, 2001 Free Software Foundation, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this software; see the file COPYING.  If not, write to
18  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #ifdef	WITH_DMALLOC
27 #include <dmalloc.h>
28 #endif
29 
30 #include "proto.h"
31 #include "funcdef.h"
32 #include <stdio.h>
33 
34 #if defined(HAVE_LIBNCURSES) && defined(HAVE_NCURSES_H)
35 #include <ncurses.h>
36 #else
37 #include <curses.h>
38 #endif
39 
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <ctype.h>
43 #include <signal.h>
44 #undef NULL
45 #include "sysdef.h"
46 #include "global.h"
47 #include "cell.h"
48 #include "cmd.h"
49 #include "line.h"
50 #include "io-generic.h"
51 #include "io-edit.h"
52 #include "io-term.h"
53 #include "io-abstract.h"
54 #include "io-utils.h"
55 #include "lists.h"
56 #include "regions.h"
57 #include "window.h"
58 #include "key.h"
59 #include "input.h"
60 #include "info.h"
61 #include <term.h>
62 
63 #define MIN_WIN_HEIGHT	(cwin->flags&WIN_EDGES ? 2 : 1)
64 #define MIN_WIN_WIDTH	(cwin->flags&WIN_EDGES ? 6 : 1)
65 
66 static int redrew = 0;
67 static int textout = 0;
68 static int term_cursor_claimed = 0;
69 
70 static void move_cursor_to (struct window *, CELLREF, CELLREF, int);
71 
72 static int
curses_metric(char * str,int len)73 curses_metric (char * str, int len)
74 {
75   return len;
76 }
77 
78 static struct input_view input_view
79   = {0, curses_metric, curses_metric, 0, 0, 0, 0, 0, 0, 0, 0, 0};
80 
81 static void
_io_redraw_input(void)82 _io_redraw_input (void)
83 {
84   int pos;
85   int row = (input_view.current_info ? 0 : Global->input);
86 
87   if (input_view.info_redraw_needed)
88     {
89       input_view.info_redraw_needed = 0;
90       io_repaint ();
91       return;
92     }
93 
94   if (input_view.redraw_needed == NO_REDRAW)
95     return;
96 
97   if (input_view.redraw_needed == FULL_REDRAW)
98     {
99       /* Redraw	the prompt. */
100       move (row, 0);
101       if (input_view.expanded_keymap_prompt)
102 	{
103 	  addstr (input_view.expanded_keymap_prompt);
104 	  clrtoeol ();
105 	  input_view.redraw_needed = NO_REDRAW;
106 	  return;
107 	}
108       if (input_view.prompt_wid)
109 	addstr (input_view.prompt);
110       pos = input_view.visibility_begin;
111     }
112   else
113     {
114       pos = input_view.redraw_needed;
115       move (row,
116 	    input_view.prompt_wid + pos - input_view.visibility_begin);
117     }
118 
119   if (   input_view.input_area
120       && (input_view.visibility_end >= input_view.visibility_begin)
121       && (input_view.visibility_begin < strlen (input_view.input_area->buf)))
122     {
123       int x;
124       for (x = pos; x <= input_view.visibility_end; ++x)
125 	addch (input_view.input_area->buf[x]);
126     }
127   clrtoeol ();
128   input_view.redraw_needed = NO_REDRAW;
129 }
130 
131 
132 #undef MIN
133 #define MIN(A,B) (((A) < (B)) ? (A) : (B))
134 
135 void
redraw_info(void)136 redraw_info (void)
137 {
138   if (!input_view.current_info)
139     return;
140   {
141     int ipos = input_view.info_pos;
142     int stop = MIN (input_view.current_info->len, Global->scr_lines - 1 + ipos);
143     while (ipos < stop)
144       {
145 	move (1 + ipos - input_view.info_pos, 0);
146 	addstr (input_view.current_info->text[ipos]);
147 	clrtoeol ();
148 	++ipos;
149       }
150   }
151   _io_redraw_input ();
152 }
153 
154 
155 static void
_io_fix_input(void)156 _io_fix_input (void)
157 {
158   iv_fix_input (&input_view);
159 }
160 
161 static void
_io_move_cursor(void)162 _io_move_cursor (void)
163 {
164   iv_move_cursor (&input_view);
165 }
166 
167 static void
_io_erase(int len)168 _io_erase (int len)
169 {
170   iv_erase (&input_view, len);
171 }
172 
173 static void
_io_insert(int len)174 _io_insert (int len)
175 {
176   iv_insert (&input_view, len);
177 }
178 
179 static void
_io_over(char * str,int len)180 _io_over (char * str, int len)
181 {
182   iv_over (&input_view, len);
183 }
184 
185 static void
_io_display_cell_cursor(void)186 _io_display_cell_cursor (void)
187 {
188   int cell_cursor_row;
189   int cell_cursor_col;
190   int cc;
191   int rr;
192   int cwid;
193   int n;
194   int x, y;
195 
196   if (input_view.current_info)
197     return;
198 
199   if (   (curow < cwin->screen.lr)
200       || (cucol < cwin->screen.lc)
201       || (curow > cwin->screen.hr)
202       || (cucol > cwin->screen.hc))
203     return;
204 
205   getyx (stdscr, y, x);
206   cell_cursor_col = cwin->win_over;
207   for (cc = cwin->screen.lc; cc < cucol; cc++)
208     cell_cursor_col += get_width (cc);
209   cell_cursor_row = cwin->win_down;
210   for (rr = cwin->screen.lr; rr < curow; rr++)
211     cell_cursor_row += get_height (rr);
212   cwid = get_width (cucol);
213   if (cwid > cwin->numc)
214     cwid = cwin->numc;
215   move (cell_cursor_row, cell_cursor_col);
216   standout ();
217   for (n = cwid; n; n--)
218 #ifdef A_STANDOUT
219     addch (inch () | A_STANDOUT);
220 #else
221     addch (inch ());
222 #endif
223   standend ();
224   move (y, x);
225 }
226 
227 static void
_io_hide_cell_cursor(void)228 _io_hide_cell_cursor (void)
229 {
230   int cc;
231   int rr;
232   int cell_cursor_row;
233   int cell_cursor_col;
234   int cwid;
235   int n;
236   int x, y;
237 
238   if (input_view.current_info)
239     return;
240   if (   (curow < cwin->screen.lr)
241       || (cucol < cwin->screen.lc)
242       || (curow > cwin->screen.hr)
243       || (cucol > cwin->screen.hc))
244     return;
245   getyx (stdscr, y, x);
246   cell_cursor_col = cwin->win_over;
247   for (cc = cwin->screen.lc; cc < cucol; cc++)
248     cell_cursor_col += get_width (cc);
249   cell_cursor_row = cwin->win_down;
250   for (rr = cwin->screen.lr; rr < curow; rr++)
251     cell_cursor_row += get_height (rr);
252   cwid = get_width (cucol);
253   if (cwid > cwin->numc)
254     cwid = cwin->numc;
255   move (cell_cursor_row, cell_cursor_col);
256   for (n = cwid; n; n--)
257 #ifdef A_STANDOUT
258     addch (inch () & ~A_STANDOUT);
259 #else
260     addch (inch ());
261 #endif
262   move (y, x);
263 }
264 
265 /* Functions, etc for dealing with cell contents being displayed
266 	on top of other cells. */
267 
268 struct slops
269 {
270   int s_alloc, s_used;
271   struct s
272     {
273       CELLREF row, clo, chi;
274     } s_b[1];
275 };
276 
277 static void
flush_slops(VOIDSTAR where)278 flush_slops (VOIDSTAR where)
279 {
280   struct slops *s;
281 
282   s = where;
283   if (s)
284     s->s_used = 0;
285 }
286 
287 static int
find_slop(VOIDSTAR where,CELLREF r,CELLREF c,CELLREF * cclp,CELLREF * cchp)288 find_slop (VOIDSTAR where, CELLREF r, CELLREF c, CELLREF *cclp, CELLREF *cchp)
289 {
290   int n;
291   struct slops *s;
292 
293   s = where;
294   if (!s)
295     return 0;
296   for (n = 0; n < s->s_used; n++)
297     {
298       if (s->s_b[n].row == r && s->s_b[n].clo <= c && s->s_b[n].chi >= c)
299 	{
300 	  *cclp = s->s_b[n].clo;
301 	  *cchp = s->s_b[n].chi;
302 	  return 1;
303 	}
304     }
305   return 0;
306 }
307 
308 static void
kill_slop(VOIDSTAR where,CELLREF r,CELLREF clo,CELLREF chi)309 kill_slop (VOIDSTAR where, CELLREF r, CELLREF clo, CELLREF chi)
310 {
311   int n;
312   struct slops *s;
313 
314   s = where;
315   for (n = 0; n < s->s_used; n++)
316     {
317       if (s->s_b[n].row == r && s->s_b[n].clo == clo && s->s_b[n].chi == chi)
318 	{
319 	  --(s->s_used);
320 	  s->s_b[n] = s->s_b[s->s_used];
321 	  return;
322 	}
323     }
324 }
325 
326 static void
set_slop(VOIDSTAR * wherep,CELLREF r,CELLREF clo,CELLREF chi)327 set_slop (VOIDSTAR *wherep, CELLREF r, CELLREF clo, CELLREF chi)
328 {
329   int n;
330   struct slops **sp;
331 
332   sp = (struct slops **) wherep;
333   if (!*sp)
334     {
335       (*sp) = ck_malloc (sizeof (struct slops) + 2 * sizeof (struct s));
336       (*sp)->s_alloc = 2;
337       (*sp)->s_used = 1;
338       n = 0;
339     }
340   else
341     {
342       n = (*sp)->s_used++;
343       if ((*sp)->s_alloc == n)
344 	{
345 	  (*sp)->s_alloc = n * 2;
346 	  (*sp) = ck_realloc ((*sp), sizeof (struct slops) + n * 2 * sizeof (struct s));
347 	}
348     }
349   (*sp)->s_b[n].row = r;
350   (*sp)->s_b[n].clo = clo;
351   (*sp)->s_b[n].chi = chi;
352 }
353 
354 static void
change_slop(VOIDSTAR where,CELLREF r,CELLREF olo,CELLREF ohi,CELLREF lo,CELLREF hi)355 change_slop (VOIDSTAR where,
356 	     CELLREF r, CELLREF olo, CELLREF ohi, CELLREF lo, CELLREF hi)
357 {
358   int n;
359   struct slops *s;
360 
361   s = where;
362   for (n = 0; n < s->s_used; n++)
363     {
364       if (s->s_b[n].row == r && s->s_b[n].clo == olo && s->s_b[n].chi == ohi)
365 	{
366 	  s->s_b[n].clo = lo;
367 	  s->s_b[n].chi = hi;
368 	  return;
369 	}
370     }
371 }
372 
373 static void
_io_open_display(void)374 _io_open_display (void)
375 {
376   initscr ();
377   scrollok (stdscr, 0);
378 #ifdef HAVE_CBREAK
379   cbreak ();
380 #else
381   crmode ();
382 #endif
383   raw ();
384   noecho ();
385   nonl ();
386   /* Must be after initscr() */
387   io_init_windows (LINES, COLS, 1, 2, 1, 1, 1, 1);
388   // io_init_windows (Global->scr_lines, Global->scr_cols, 1, 2, 1, 1, 1, 1);
389   info_rows = 1;
390   print_width = columns;		/* Make ascii print width == terminal width. */
391 }
392 
393 void
cont_curses(void)394 cont_curses(void)
395 {
396 #ifdef HAVE_CBREAK
397   cbreak ();
398 #else
399   crmode ();
400 #endif
401   raw ();
402   noecho ();
403   nonl ();
404 }
405 
406 
407 void
stop_curses(void)408 stop_curses(void)
409 {
410 #ifdef HAVE_CBREAK
411   nocbreak ();
412 #else
413   nocrmode ();
414 #endif
415   noraw ();
416   echo ();
417   nl ();
418   io_redisp ();
419 }
420 
421 static void
_io_cellize_cursor(void)422 _io_cellize_cursor (void)
423 {
424 }
425 
426 static void
_io_inputize_cursor(void)427 _io_inputize_cursor (void)
428 {
429 }
430 
431 static void
_io_redisp(void)432 _io_redisp (void)
433 {
434   if (!term_cursor_claimed)
435     {
436       _io_redraw_input ();
437       if (!(input_view.current_info || input_active ||
438 	    input_view.expanded_keymap_prompt))
439 	move_cursor_to (cwin, curow, cucol, 0);
440       else
441 	move ((input_view.current_info ? 0 : Global->input),
442 	      input_view.prompt_wid + input_view.input_cursor -
443 	      input_view.visibility_begin);
444     }
445   {
446     struct rng * rng = &cwin->screen;
447     if (   (curow > rng->hr)
448 	|| (curow < rng->lr)
449 	|| (cucol > rng->hc)
450 	|| (cucol < rng->lc))
451       io_recenter_cur_win ();
452   }
453   refresh ();
454 }
455 
456 static void
_io_repaint_win(struct window * win)457 _io_repaint_win (struct window *win)
458 {
459   io_repaint ();
460 }
461 
462 static void
_io_repaint(void)463 _io_repaint (void)
464 {
465   CELLREF cc, rr;
466   int n, n1;
467   CELL *cp;
468   struct window *win;
469 
470   clear ();
471   io_fix_input ();
472   redrew++;
473   if (input_view.current_info)
474     {
475       redraw_info ();
476       input_view.redraw_needed = FULL_REDRAW;
477       _io_redraw_input ();
478       return;
479     }
480 
481   for (win = wins; win < &wins[nwin]; win++)
482     {
483       if (win->lh_wid)
484 	{
485 	  move (win->win_down - 1, win->win_over - win->lh_wid);
486 	  printw ("#%*d ", win->lh_wid - 2, 1 + win - wins);
487 	  if (win->flags & WIN_EDGE_REV)
488 	    standout ();
489 	  cc = win->screen.lc;
490 	  do
491 	    {
492 	      n = get_width (cc);
493 	      if (n > win->numc)
494 		n = win->numc;
495 	      if (n > 1)
496 		{
497 		  char *ptr;
498 		  char buf[30];
499 
500 		  if (Global->a0)
501 		    ptr = col_to_str (cc);
502 		  else
503 		    {
504 		      sprintf (buf, "C%u", cc);
505 		      ptr = buf;
506 		    }
507 		  --n;
508 		  n1 = strlen (ptr);
509 		  if (n < n1)
510 		    printw ("%.*s ", n, "###############");
511 		  else
512 		    {
513 		      n1 = (n - n1) / 2;
514 		      printw ("%*s%-*s ", n1, "", n - n1, ptr);
515 		    }
516 		}
517 	      else if (n == 1)
518 		addstr ("#");
519 	    }
520 	  while (cc++ < win->screen.hc);
521 
522 	  rr = win->screen.lr;
523 	  n = win->win_down;
524 	  do
525 	    {
526 	      n1 = get_height (rr);
527 	      if (n1)
528 		{
529 		  move (n, win->win_over - win->lh_wid);
530 		  if (Global->a0)
531 		    printw ("%-*d ", win->lh_wid - 1, rr);
532 		  else
533 		    printw ("R%-*d", win->lh_wid - 1, rr);
534 		  n += n1;
535 		}
536 	    }
537 	  while (rr++ < win->screen.hr);
538 
539 	  if (win->flags & WIN_EDGE_REV)
540 	    standend ();
541 	}
542       flush_slops (win->win_slops);
543       find_cells_in_range (&(win->screen));
544       while ((cp = next_row_col_in_range (&rr, &cc)))
545 	if (GET_TYP (cp))
546 	  io_pr_cell_win (win, rr, cc, cp);
547     }
548   if (!(cp = find_cell (curow, cucol)) || !GET_TYP (cp))
549     io_display_cell_cursor ();
550   input_view.redraw_needed = FULL_REDRAW;
551   _io_redraw_input ();
552   io_update_status ();
553 }
554 
555 static void
_io_close_display(int e)556 _io_close_display (int e)
557 {
558 	if (e == 0) {
559 		clear ();
560 		refresh ();
561 	}
562 
563 	(void) endwin ();
564 }
565 
566 static int
_io_input_avail(void)567 _io_input_avail (void)
568 {
569   return (FD_ISSET (0, &read_pending_fd_set)
570 	  || FD_ISSET (0, &exception_pending_fd_set));
571 }
572 
573 static void
_io_scan_for_input(int block)574 _io_scan_for_input (int block)
575 {
576   /* This function only exists because X kbd events don't generate
577    * SIGIO. Under curses, the SIGIO hander does the work of this
578    * function.
579    * Attempt to have the curses mode be somewhat responsive even in
580    * the presence of an endless loop by explicitly looking for events
581    * here.
582    */
583   struct timeval tv;
584 
585   tv.tv_sec = 0;
586   tv.tv_usec = 1000;
587   block_until_excitement(&tv);
588 }
589 
590 static void
_io_wait_for_input(void)591 _io_wait_for_input (void)
592 {
593   pause ();
594 }
595 
596 static int
_io_read_kbd(char * buf,int size)597 _io_read_kbd (char *buf, int size)
598 {
599   int r = read (0, buf, size);
600   FD_CLR (0, &read_pending_fd_set);
601   FD_CLR (0, &exception_pending_fd_set);
602   return r;
603 }
604 
605 
606 #if defined(SIGIO)
607 
608 
609 static void
_io_nodelay(int delayp)610 _io_nodelay (int delayp)
611 {
612   panic ("Trying to curses nodelay on a system with SIGIO.");
613 }
614 
615 #else
616 
617 static void
_io_nodelay(int delayp)618 _io_nodelay (int delayp)
619 {
620   nodelay (stdscr, delayp);
621 }
622 
623 #endif
624 
625 static int
_io_getch(void)626 _io_getch (void)
627 {
628   char ch;
629   return ((io_read_kbd (&ch, 1) != 1)
630 	  ? EOF
631 	  : ch);
632 }
633 
634 static int
_io_get_chr(char * prompt)635 _io_get_chr (char *prompt)
636 {
637   int x;
638   mvaddstr (Global->input, 0, prompt);
639   clrtoeol ();
640   Global->topclear = 2;
641   refresh ();
642   ++term_cursor_claimed;
643   x = get_chr ();
644   --term_cursor_claimed;
645   return x;
646 }
647 
648 #define BUFFER 10
649 
650 static void
_io_bell(void)651 _io_bell (void)
652 {
653 #ifndef HAVE_GETCAP
654   putchar ('\007');
655 #else
656   static char *vb;
657   static int called = 0;
658 
659   if (!called)
660     {
661       called++;
662       vb = getcap ("vb");
663     }
664   if (vb)
665     {
666       local_puts (vb);
667     }
668   else
669     {
670       local_putchar ('\007');
671     }
672 #endif
673 }
674 
675 static void
move_cursor_to(struct window * win,CELLREF r,CELLREF c,int dn)676 move_cursor_to (struct window *win, CELLREF r, CELLREF c, int dn)
677 {
678   int cc;
679   int cell_cursor_col;
680   int rr;
681   int cell_cursor_row;
682 
683   cell_cursor_col = win->win_over;
684   for (cc = win->screen.lc; cc < c; cc++)
685     cell_cursor_col += get_width (cc);
686   cell_cursor_row = win->win_down + dn;
687   for (rr = win->screen.lr; rr < r; rr++)
688     cell_cursor_row += get_height (rr);
689   move (cell_cursor_row, cell_cursor_col);
690 }
691 
692 static void
_io_update_status(void)693 _io_update_status (void)
694 {
695   CELL *cp;
696   char *dec;
697   char *ptr;
698   static char hmbuf[40];
699   int wid;
700   int plen;
701   int dlen;
702   int yy, xx;
703 
704   if (!user_status || input_view.current_info)
705     return;
706   getyx (stdscr, yy, xx);
707   move (Global->status, 0);
708   wid = columns - 2;
709 
710   if (mkrow != NON_ROW)
711     {
712       struct rng r;
713 
714       addch ('*');
715       --wid;
716       set_rng (&r, curow, cucol, mkrow, mkcol);
717       ptr = range_name (&r);
718     }
719   else
720     ptr = cell_name (curow, cucol);
721 
722   addstr (ptr);
723   wid -= strlen (ptr);
724 
725   if (how_many != 1)
726     {
727       sprintf (hmbuf, " {%d}", how_many);
728       addstr (hmbuf);
729       wid -= strlen (hmbuf);
730     }
731 
732   if ((cp = find_cell (curow, cucol)) && cp->cell_formula)
733     {
734       dec = decomp (curow, cucol, cp);
735       dlen = strlen (dec);
736     }
737   else
738     {
739       dec = 0;
740       dlen = 0;
741     }
742 
743   ptr = cell_value_string (curow, cucol, 1);
744   plen = strlen (ptr);
745 
746   if (dec)
747     {
748       wid -= 4;
749       if (dlen + plen > wid)
750 	{
751 	  if (plen + 3 > wid)
752 	    printw (" %.*s... [...]", wid - 6, ptr);
753 	  else
754 	    printw (" %s [%.*s...]", ptr, wid - plen - 3, dec);
755 	}
756       else
757 	printw (" %s [%s]", ptr, dec);
758       decomp_free ();
759     }
760   else if (plen)
761     {
762       --wid;
763       if (plen > wid)
764 	printw (" %.*s...", wid - 3, ptr);
765       else
766 	printw (" %s", ptr);
767     }
768 
769   clrtoeol ();
770   move (yy, xx);
771 }
772 
773 extern int auto_recalc;
774 
775 static void
_io_clear_input_before(void)776 _io_clear_input_before (void)
777 {
778   textout = 0;
779   if (Global->topclear == 2)
780     {
781       move (Global->input, 0);
782       clrtoeol ();
783       Global->topclear = 0;
784     }
785   move (0, 0);
786 }
787 
788 static void
_io_clear_input_after(void)789 _io_clear_input_after (void)
790 {
791   if (Global->topclear)
792     {
793       move (Global->input, 0);
794       clrtoeol ();
795       Global->topclear = 0;
796     }
797 }
798 
799 
800 static void
_io_pr_cell_win(struct window * win,CELLREF r,CELLREF c,CELL * cp)801 _io_pr_cell_win (struct window *win, CELLREF r, CELLREF c, CELL *cp)
802 {
803   int glowing;
804   int lenstr;
805   int j;
806   int wid, wwid;
807   int hgt;
808   char *ptr;
809   int yy, xx;
810 
811   if (input_view.current_info)
812     return;
813 
814   wid = get_width (c);
815   if (!wid)
816     return;
817   if (wid > win->numc)
818     wid = win->numc;
819   hgt = get_height (r);
820   if (!hgt)
821     return;
822   if (hgt > win->numr)
823     hgt = win->numr;
824 
825   getyx (stdscr, yy, xx);
826   glowing = (r == curow && c == cucol && win == cwin);
827   ptr = print_cell (cp);
828   move_cursor_to (win, r, c, 0);
829   if (glowing)
830     standout ();
831   j = GET_JST (cp);
832   if (j == JST_DEF)
833     j = default_jst;
834   lenstr = strlen (ptr);
835 
836   if (lenstr <= wid - 1)
837     {
838       CELLREF ccl, cch;
839 
840       if (j == JST_LFT)
841 	printw ("%-*.*s", wid, wid - 1, ptr);
842       else if (j == JST_RGT)
843 	printw ("%*.*s ", wid - 1, wid - 1, ptr);
844       else if (j == JST_CNT)
845 	{
846 	  wwid = (wid - 1) - lenstr;
847 	  printw ("%*s%*s ", (wwid + 1) / 2 + lenstr, ptr, wwid / 2, "");
848 	}
849 #ifdef TEST
850       else
851 	panic ("Unknown justification");
852 #endif
853       if (glowing)
854 	standend ();
855 
856       if (lenstr == 0 && c > win->screen.lc
857 	  && find_slop (win->win_slops, r, c - 1, &ccl, &cch))
858 	{
859 	  CELLREF ccdl, ccdh;
860 
861 	  if (find_slop (win->win_slops, r, c, &ccdl, &ccdh) && ccdl == c)
862 	    {
863 	      kill_slop (win->win_slops, r, ccdl, ccdh);
864 	      for (; ccdh != ccdl; --ccdh)
865 		if (ccdh != c && (wwid = get_width (ccdh)))
866 		  {
867 		    move_cursor_to (win, r, ccdh, 0);
868 		    printw ("%*s", wwid, "");
869 		  }
870 	    }
871 	  kill_slop (win->win_slops, r, ccl, cch);
872 	  io_pr_cell (r, ccl, find_cell (r, ccl));
873 	}
874       else if (find_slop (win->win_slops, r, c, &ccl, &cch))
875 	{
876 	  kill_slop (win->win_slops, r, ccl, cch);
877 	  for (; cch != ccl; --cch)
878 	    if (cch != c && (wwid = get_width (cch)))
879 	      {
880 		move_cursor_to (win, r, cch, 0);
881 		printw ("%*s", wwid, "");
882 	      }
883 	  io_pr_cell (r, ccl, find_cell (r, ccl));
884 	}
885     }
886   else
887     {
888       CELLREF cc = c;
889       CELL *ccp;
890       CELLREF ccl, cch;
891 
892       for (wwid = wid; lenstr > wwid - 1; wwid += get_width (cc))
893 	{
894 	  if (++cc > win->screen.hc
895 	      || ((ccp = find_cell (r, cc))
896 		  && GET_TYP (ccp)
897 		  && (GET_FORMAT (ccp) != FMT_HID
898 		      || (GET_FORMAT (ccp) == FMT_DEF
899 			  && default_fmt != FMT_HID))))
900 	    {
901 	      --cc;
902 	      break;
903 	    }
904 	}
905 
906       if (lenstr > wwid - 1) {  /* FIXME: This construct needs to be checked */
907 	if (GET_TYP (cp) == TYP_FLT)
908 	  ptr = adjust_prc (ptr, cp, wwid - 1, wid - 1, j);
909 	else if (GET_TYP (cp) == TYP_INT)
910 	  ptr = (char *) numb_oflo;
911       }
912 
913       if (wwid == 1)
914 	{
915 	  addch (' ');
916 	  if (glowing)
917 	    standend ();
918 	}
919       else if (wwid == wid)
920 	{
921 	  printw ("%-*.*s ", wwid - 1, wwid - 1, ptr);
922 	  if (glowing)
923 	    standend ();
924 	}
925       else if (glowing)
926 	{
927 	  printw ("%.*s", wid, ptr);
928 	  standend ();
929 	  printw ("%-*.*s ", wwid - wid - 1, wwid - wid - 1, ptr + wid);
930 	}
931       else if (r == curow && (cucol > c && cucol <= cc))
932 	{
933 	  CELLREF ctmp;
934 	  int w_left;
935 	  int w_here;
936 
937 	  w_left = wid;
938 	  for (ctmp = c + 1; ctmp < cucol; ctmp++)
939 	    w_left += get_width (ctmp);
940 	  printw ("%.*s", w_left, ptr);
941 	  standout ();
942 	  w_here = get_width (cucol);
943 	  if (wwid > w_left + w_here)
944 	    {
945 	      printw ("%-*.*s", w_here, w_here, ptr + w_left);
946 	      standend ();
947 	      printw ("%-*.*s ",
948 		      wwid - (w_left + w_here) - 1, wwid - (w_left + w_here) - 1,
949 		      ptr + w_left + w_here);
950 	    }
951 	  else
952 	    {
953 	      printw ("%-*.*s", w_here, w_here - 1, ptr + w_left);
954 	      standend ();
955 	    }
956 	}
957       else
958 	printw ("%-*.*s ", wwid - 1, wwid - 1, ptr);
959 
960       if (find_slop (win->win_slops, r, c, &ccl, &cch))
961 	{
962 	  change_slop (win->win_slops, r, ccl, cch, c, cc);
963 	  for (; cch > cc; --cch)
964 	    if ((wwid = get_width (cch)))
965 	      {
966 		move_cursor_to (win, r, cch, 0);
967 		printw ("%*s", wwid, "");
968 	      }
969 	  for (cch = c - 1; cch > ccl; --cch)
970 	    if ((wwid = get_width (cch)))
971 	      {
972 		move_cursor_to (win, r, cch, 0);
973 		printw ("%*s", wwid, "");
974 	      }
975 	  if (ccl != c)
976 	    io_pr_cell (r, ccl, find_cell (r, ccl));
977 	}
978       else
979 	set_slop ((VOIDSTAR *) (&(win->win_slops)), r, c, cc);
980     }
981   if ((hgt > 1) && Global->display_formula_mode)
982     {
983       move_cursor_to (win, r, c, 1);
984       ptr = decomp (r, c, cp);
985       printw ("%.*s ", wid - 1, ptr);
986       decomp_free ();
987     }
988   if (glowing)
989     io_update_status ();
990   move (yy, xx);
991 }
992 
993 
994 static void
_io_flush(void)995 _io_flush (void)
996 {
997   refresh ();
998 }
999 
1000 void
_io_command_loop(int a)1001 _io_command_loop (int a)
1002 {
1003 	command_loop (a, 0);
1004 }
1005 
1006 void
tty_graphics(void)1007 tty_graphics (void)
1008 {
1009   FD_SET (0, &read_fd_set);
1010   FD_SET (0, &exception_fd_set);
1011   io_command_loop = _io_command_loop;
1012   io_open_display = _io_open_display;
1013   io_redisp = _io_redisp;
1014   io_repaint = _io_repaint;
1015   io_repaint_win = _io_repaint_win;
1016   io_close_display = _io_close_display;
1017   io_input_avail = _io_input_avail;
1018   io_scan_for_input = _io_scan_for_input;
1019   io_wait_for_input = _io_wait_for_input;
1020   io_read_kbd = _io_read_kbd;
1021   io_nodelay = _io_nodelay;
1022   io_getch = _io_getch;
1023   io_bell = _io_bell;
1024   io_get_chr = _io_get_chr;
1025   io_update_status = _io_update_status;
1026   io_fix_input = _io_fix_input;
1027   io_move_cursor = _io_move_cursor;
1028   io_erase = _io_erase;
1029   io_insert = _io_insert;
1030   io_over = _io_over;
1031   io_flush = _io_flush;
1032   io_clear_input_before = _io_clear_input_before;
1033   io_clear_input_after = _io_clear_input_after;
1034   io_pr_cell_win = _io_pr_cell_win;
1035   io_hide_cell_cursor = _io_hide_cell_cursor;
1036   io_cellize_cursor = _io_cellize_cursor;
1037   io_inputize_cursor = _io_inputize_cursor;
1038   io_display_cell_cursor = _io_display_cell_cursor;
1039 }
1040