* readline.c (_rl_output_character_function), display.c:
[external/binutils.git] / readline / display.c
1 /* display.c -- readline redisplay facility. */
2
3 /* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
4
5    This file is part of the GNU Readline Library, a library for
6    reading lines of text with interactive input and history editing.
7
8    The GNU Readline Library is free software; you can redistribute it
9    and/or modify it under the terms of the GNU General Public License
10    as published by the Free Software Foundation; either version 1, or
11    (at your option) any later version.
12
13    The GNU Readline Library is distributed in the hope that it will be
14    useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    The GNU General Public License is often shipped with GNU software, and
19    is generally kept in a file called COPYING or LICENSE.  If you do not
20    have a copy of the license, write to the Free Software Foundation,
21    675 Mass Ave, Cambridge, MA 02139, USA. */
22
23 #include <stdio.h>
24 #include <sys/types.h>
25
26 /* System-specific feature definitions and include files. */
27 #include "rldefs.h"
28
29 /* Some standard library routines. */
30 #include "readline.h"
31 #include "history.h"
32
33 #if !defined (strrchr)
34 extern char *strrchr ();
35 #endif /* !strchr */
36
37 /* Global and pseudo-global variables and functions
38    imported from readline.c. */
39 extern char *rl_prompt;
40 extern int readline_echoing_p;
41 extern char *term_clreol, *term_im, *term_ic,  *term_ei, *term_DC;
42 /* Termcap variables. */
43 extern char *term_up, *term_dc, *term_cr, *term_IC;
44 extern int screenheight, screenwidth, terminal_can_insert, term_xn;
45
46 extern void _rl_output_some_chars ();
47 extern int _rl_output_character_function ();
48
49 extern int _rl_convert_meta_chars_to_ascii;
50 extern int _rl_horizontal_scroll_mode;
51 extern int _rl_mark_modified_lines;
52 extern int _rl_prefer_visible_bell;
53
54 /* Pseudo-global functions (local to the readline library) exported
55    by this file. */
56 void _rl_move_cursor_relative (), _rl_output_some_chars ();
57 void _rl_move_vert ();
58
59 static void update_line (), clear_to_eol ();
60 static void delete_chars (), insert_some_chars ();
61
62 extern char *xmalloc (), *xrealloc ();
63
64 /* **************************************************************** */
65 /*                                                                  */
66 /*                      Display stuff                               */
67 /*                                                                  */
68 /* **************************************************************** */
69
70 /* This is the stuff that is hard for me.  I never seem to write good
71    display routines in C.  Let's see how I do this time. */
72
73 /* (PWP) Well... Good for a simple line updater, but totally ignores
74    the problems of input lines longer than the screen width.
75
76    update_line and the code that calls it makes a multiple line,
77    automatically wrapping line update.  Carefull attention needs
78    to be paid to the vertical position variables. */
79
80 /* Keep two buffers; one which reflects the current contents of the
81    screen, and the other to draw what we think the new contents should
82    be.  Then compare the buffers, and make whatever changes to the
83    screen itself that we should.  Finally, make the buffer that we
84    just drew into be the one which reflects the current contents of the
85    screen, and place the cursor where it belongs.
86
87    Commands that want to can fix the display themselves, and then let
88    this function know that the display has been fixed by setting the
89    RL_DISPLAY_FIXED variable.  This is good for efficiency. */
90
91 /* What YOU turn on when you have handled all redisplay yourself. */
92 int rl_display_fixed = 0;
93
94 /* The stuff that gets printed out before the actual text of the line.
95    This is usually pointing to rl_prompt. */
96 char *rl_display_prompt = (char *)NULL;
97
98 /* Pseudo-global variables declared here. */
99 /* The visible cursor position.  If you print some text, adjust this. */
100 int _rl_last_c_pos = 0;
101 int _rl_last_v_pos = 0;
102
103 /* Number of lines currently on screen minus 1. */
104 int _rl_vis_botlin = 0;
105
106 /* Variables used only in this file. */
107 /* The last left edge of text that was displayed.  This is used when
108    doing horizontal scrolling.  It shifts in thirds of a screenwidth. */
109 static int last_lmargin = 0;
110
111 /* The line display buffers.  One is the line currently displayed on
112    the screen.  The other is the line about to be displayed. */
113 static char *visible_line = (char *)NULL;
114 static char *invisible_line = (char *)NULL;
115
116 /* A buffer for `modeline' messages. */
117 static char msg_buf[128];
118
119 /* Non-zero forces the redisplay even if we thought it was unnecessary. */
120 static int forced_display = 0;
121
122 /* Default and initial buffer size.  Can grow. */
123 static int line_size = 1024;
124
125 /* Basic redisplay algorithm. */
126 rl_redisplay ()
127 {
128   register int in, out, c, linenum;
129   register char *line = invisible_line;
130   char *prompt_this_line;
131   int c_pos = 0;
132   int inv_botlin = 0;           /* Number of lines in newly drawn buffer. */
133
134   if (!readline_echoing_p)
135     return;
136
137   if (!rl_display_prompt)
138     rl_display_prompt = "";
139
140   if (!invisible_line)
141     {
142       visible_line = (char *)xmalloc (line_size);
143       invisible_line = (char *)xmalloc (line_size);
144       line = invisible_line;
145       for (in = 0; in < line_size; in++)
146         {
147           visible_line[in] = 0;
148           invisible_line[in] = 1;
149         }
150       rl_on_new_line ();
151     }
152
153   /* Draw the line into the buffer. */
154   c_pos = -1;
155
156   /* Mark the line as modified or not.  We only do this for history
157      lines. */
158   out = 0;
159   if (_rl_mark_modified_lines && current_history () && rl_undo_list)
160     {
161       line[out++] = '*';
162       line[out] = '\0';
163     }
164
165   /* If someone thought that the redisplay was handled, but the currently
166      visible line has a different modification state than the one about
167      to become visible, then correct the caller's misconception. */
168   if (visible_line[0] != invisible_line[0])
169     rl_display_fixed = 0;
170
171   prompt_this_line = strrchr (rl_display_prompt, '\n');
172   if (!prompt_this_line)
173     prompt_this_line = rl_display_prompt;
174   else
175     {
176       prompt_this_line++;
177       if (forced_display)
178         _rl_output_some_chars
179           (rl_display_prompt, prompt_this_line - rl_display_prompt);
180     }
181
182   strncpy (line + out,  prompt_this_line, strlen (prompt_this_line));
183   out += strlen (prompt_this_line);
184   line[out] = '\0';
185
186   for (in = 0; in < rl_end; in++)
187     {
188       c = (unsigned char)rl_line_buffer[in];
189
190       if (out + 8 >= line_size)         /* XXX - 8 for \t */
191         {
192           line_size *= 2;
193           visible_line = (char *)xrealloc (visible_line, line_size);
194           invisible_line = (char *)xrealloc (invisible_line, line_size);
195           line = invisible_line;
196         }
197
198       if (in == rl_point)
199         c_pos = out;
200
201       if (META_CHAR (c))
202         {
203           if (_rl_convert_meta_chars_to_ascii)
204             {
205               sprintf (line + out, "\\%o", c);
206               out += 4;
207             }
208           else
209             line[out++] = c;      
210         }
211 #define DISPLAY_TABS
212 #if defined (DISPLAY_TABS)
213       else if (c == '\t')
214         {
215           register int newout = (out | (int)7) + 1;
216           while (out < newout)
217             line[out++] = ' ';
218         }
219 #endif
220       else if (c < ' ')
221         {
222           line[out++] = '^';
223           line[out++] = UNCTRL (c);     /* XXX was c ^ 0x40 */
224         }
225       else if (c == 127)
226         {
227           line[out++] = '^';
228           line[out++] = '?';
229         }
230       else
231         line[out++] = c;
232     }
233   line[out] = '\0';
234   if (c_pos < 0)
235     c_pos = out;
236
237   /* PWP: now is when things get a bit hairy.  The visible and invisible
238      line buffers are really multiple lines, which would wrap every
239      screenwidth characters.  Go through each in turn, finding
240      the changed region and updating it.  The line order is top to bottom. */
241
242   /* If we can move the cursor up and down, then use multiple lines,
243      otherwise, let long lines display in a single terminal line, and
244      horizontally scroll it. */
245
246   if (!_rl_horizontal_scroll_mode && term_up && *term_up)
247     {
248       int total_screen_chars = (screenwidth * screenheight);
249
250       if (!rl_display_fixed || forced_display)
251         {
252           forced_display = 0;
253
254           /* If we have more than a screenful of material to display, then
255              only display a screenful.  We should display the last screen,
256              not the first.  I'll fix this in a minute. */
257           if (out >= total_screen_chars)
258             out = total_screen_chars - 1;
259
260           /* Number of screen lines to display. */
261           inv_botlin = out / screenwidth;
262
263           /* For each line in the buffer, do the updating display. */
264           for (linenum = 0; linenum <= inv_botlin; linenum++)
265             update_line (linenum > _rl_vis_botlin ? ""
266                          : &visible_line[linenum * screenwidth],
267                          &invisible_line[linenum * screenwidth],
268                          linenum);
269
270           /* We may have deleted some lines.  If so, clear the left over
271              blank ones at the bottom out. */
272           if (_rl_vis_botlin > inv_botlin)
273             {
274               char *tt;
275               for (; linenum <= _rl_vis_botlin; linenum++)
276                 {
277                   tt = &visible_line[linenum * screenwidth];
278                   _rl_move_vert (linenum);
279                   _rl_move_cursor_relative (0, tt);
280                   clear_to_eol
281                     ((linenum == _rl_vis_botlin) ? strlen (tt) : screenwidth);
282                 }
283             }
284           _rl_vis_botlin = inv_botlin;
285
286           /* Move the cursor where it should be. */
287           _rl_move_vert (c_pos / screenwidth);
288           _rl_move_cursor_relative (c_pos % screenwidth,
289                                 &invisible_line[(c_pos / screenwidth) * screenwidth]);
290         }
291     }
292   else                          /* Do horizontal scrolling. */
293     {
294       int lmargin;
295
296       /* Always at top line. */
297       _rl_last_v_pos = 0;
298
299       /* If the display position of the cursor would be off the edge
300          of the screen, start the display of this line at an offset that
301          leaves the cursor on the screen. */
302       if (c_pos - last_lmargin > screenwidth - 2)
303         lmargin = (c_pos / (screenwidth / 3) - 2) * (screenwidth / 3);
304       else if (c_pos - last_lmargin < 1)
305         lmargin = ((c_pos - 1) / (screenwidth / 3)) * (screenwidth / 3);
306       else
307         lmargin = last_lmargin;
308
309       /* If the first character on the screen isn't the first character
310          in the display line, indicate this with a special character. */
311       if (lmargin > 0)
312         line[lmargin] = '<';
313
314       if (lmargin + screenwidth < out)
315         line[lmargin + screenwidth - 1] = '>';
316
317       if (!rl_display_fixed || forced_display || lmargin != last_lmargin)
318         {
319           forced_display = 0;
320           update_line (&visible_line[last_lmargin],
321                        &invisible_line[lmargin], 0);
322
323           _rl_move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]);
324           last_lmargin = lmargin;
325         }
326     }
327   fflush (rl_outstream);
328
329   /* Swap visible and non-visible lines. */
330   {
331     char *temp = visible_line;
332     visible_line = invisible_line;
333     invisible_line = temp;
334     rl_display_fixed = 0;
335   }
336 }
337
338 /* PWP: update_line() is based on finding the middle difference of each
339    line on the screen; vis:
340
341                              /old first difference
342         /beginning of line   |              /old last same       /old EOL
343         v                    v              v                    v
344 old:    eddie> Oh, my little gruntle-buggy is to me, as lurgid as
345 new:    eddie> Oh, my little buggy says to me, as lurgid as
346         ^                    ^        ^                    ^
347         \beginning of line   |        \new last same       \new end of line
348                              \new first difference
349
350    All are character pointers for the sake of speed.  Special cases for
351    no differences, as well as for end of line additions must be handeled.
352
353    Could be made even smarter, but this works well enough */
354 static void
355 update_line (old, new, current_line)
356      register char *old, *new;
357      int current_line;
358 {
359   register char *ofd, *ols, *oe, *nfd, *nls, *ne;
360   int lendiff, wsatend;
361
362   if (_rl_last_c_pos == screenwidth && term_xn && new[0])
363     {
364       putc (new[0], rl_outstream);
365       _rl_last_c_pos = 1;
366       _rl_last_v_pos++;
367       if (old[0])
368         old[0] = new[0];
369     }
370
371   /* Find first difference. */
372   for (ofd = old, nfd = new;
373        (ofd - old < screenwidth) && *ofd && (*ofd == *nfd);
374        ofd++, nfd++)
375     ;
376
377   /* Move to the end of the screen line. */
378   for (oe = ofd; ((oe - old) < screenwidth) && *oe; oe++);
379   for (ne = nfd; ((ne - new) < screenwidth) && *ne; ne++);
380
381   /* If no difference, continue to next line. */
382   if (ofd == oe && nfd == ne)
383     return;
384
385   wsatend = 1;                  /* flag for trailing whitespace */
386   ols = oe - 1;                 /* find last same */
387   nls = ne - 1;
388   while ((ols > ofd) && (nls > nfd) && (*ols == *nls))
389     {
390       if (*ols != ' ')
391         wsatend = 0;
392       ols--;
393       nls--;
394     }
395
396   if (wsatend)
397     {
398       ols = oe;
399       nls = ne;
400     }
401   else if (*ols != *nls)
402     {
403       if (*ols)                 /* don't step past the NUL */
404         ols++;
405       if (*nls)
406         nls++;
407     }
408
409   _rl_move_vert (current_line);
410   _rl_move_cursor_relative (ofd - old, old);
411
412   /* if (len (new) > len (old)) */
413   lendiff = (nls - nfd) - (ols - ofd);
414
415   /* Insert (diff (len (old), len (new)) ch. */
416   if (lendiff > 0)
417     {
418       if (terminal_can_insert)
419         {
420           /* Sometimes it is cheaper to print the characters rather than
421              use the terminal's capabilities. */
422           if ((2 * (ne - nfd)) < lendiff && !term_IC)
423             {
424               _rl_output_some_chars (nfd, (ne - nfd));
425               _rl_last_c_pos += (ne - nfd);
426             }
427           else
428             {
429               if (*ols)
430                 {
431                   insert_some_chars (nfd, lendiff);
432                   _rl_last_c_pos += lendiff;
433                 }
434               else
435                 {
436                   /* At the end of a line the characters do not have to
437                      be "inserted".  They can just be placed on the screen. */
438                   _rl_output_some_chars (nfd, lendiff);
439                   _rl_last_c_pos += lendiff;
440                 }
441               /* Copy (new) chars to screen from first diff to last match. */
442               if (((nls - nfd) - lendiff) > 0)
443                 {
444                   _rl_output_some_chars (&nfd[lendiff], ((nls - nfd) - lendiff));
445                   _rl_last_c_pos += ((nls - nfd) - lendiff);
446                 }
447             }
448         }
449       else
450         {               /* cannot insert chars, write to EOL */
451           _rl_output_some_chars (nfd, (ne - nfd));
452           _rl_last_c_pos += (ne - nfd);
453         }
454     }
455   else                          /* Delete characters from line. */
456     {
457       /* If possible and inexpensive to use terminal deletion, then do so. */
458       if (term_dc && (2 * (ne - nfd)) >= (-lendiff))
459         {
460           if (lendiff)
461             delete_chars (-lendiff); /* delete (diff) characters */
462
463           /* Copy (new) chars to screen from first diff to last match */
464           if ((nls - nfd) > 0)
465             {
466               _rl_output_some_chars (nfd, (nls - nfd));
467               _rl_last_c_pos += (nls - nfd);
468             }
469         }
470       /* Otherwise, print over the existing material. */
471       else
472         {
473           _rl_output_some_chars (nfd, (ne - nfd));
474           _rl_last_c_pos += (ne - nfd);
475           clear_to_eol ((oe - old) - (ne - new));
476         }
477     }
478 }
479
480 /* Tell the update routines that we have moved onto a new (empty) line. */
481 rl_on_new_line ()
482 {
483   if (visible_line)
484     visible_line[0] = '\0';
485
486   _rl_last_c_pos = _rl_last_v_pos = 0;
487   _rl_vis_botlin = last_lmargin = 0;
488 }
489
490 /* Actually update the display, period. */
491 rl_forced_update_display ()
492 {
493   if (visible_line)
494     {
495       register char *temp = visible_line;
496
497       while (*temp) *temp++ = '\0';
498     }
499   rl_on_new_line ();
500   forced_display++;
501   rl_redisplay ();
502 }
503
504 /* Move the cursor from _rl_last_c_pos to NEW, which are buffer indices.
505    DATA is the contents of the screen line of interest; i.e., where
506    the movement is being done. */
507 void
508 _rl_move_cursor_relative (new, data)
509      int new;
510      char *data;
511 {
512   register int i;
513
514   /* It may be faster to output a CR, and then move forwards instead
515      of moving backwards. */
516   if (new + 1 < _rl_last_c_pos - new)
517     {
518 #ifdef __MSDOS__
519       putc('\r', rl_outstream);
520 #else
521       tputs (term_cr, 1, _rl_output_character_function);
522 #endif
523       _rl_last_c_pos = 0;
524     }
525
526   if (_rl_last_c_pos == new) return;
527
528   if (_rl_last_c_pos < new)
529     {
530       /* Move the cursor forward.  We do it by printing the command
531          to move the cursor forward if there is one, else print that
532          portion of the output buffer again.  Which is cheaper? */
533
534       /* The above comment is left here for posterity.  It is faster
535          to print one character (non-control) than to print a control
536          sequence telling the terminal to move forward one character.
537          That kind of control is for people who don't know what the
538          data is underneath the cursor. */
539 #if defined (HACK_TERMCAP_MOTION)
540       extern char *term_forward_char;
541
542       if (term_forward_char)
543         for (i = _rl_last_c_pos; i < new; i++)
544           tputs (term_forward_char, 1, _rl_output_character_function);
545       else
546         for (i = _rl_last_c_pos; i < new; i++)
547           putc (data[i], rl_outstream);
548 #else
549       for (i = _rl_last_c_pos; i < new; i++)
550         putc (data[i], rl_outstream);
551 #endif                          /* HACK_TERMCAP_MOTION */
552     }
553   else
554     backspace (_rl_last_c_pos - new);
555   _rl_last_c_pos = new;
556 }
557
558 /* PWP: move the cursor up or down. */
559 void
560 _rl_move_vert (to)
561      int to;
562 {
563   register int delta, i;
564
565   if (_rl_last_v_pos == to || to > screenheight)
566     return;
567
568 #ifdef __GO32__
569   {
570     int row, col;
571     ScreenGetCursor (&row, &col);
572     ScreenSetCursor ((row + to - _rl_last_v_pos), col);
573   }
574 #else /* __GO32__ */
575   if ((delta = to - _rl_last_v_pos) > 0)
576     {
577       for (i = 0; i < delta; i++)
578         putc ('\n', rl_outstream);
579       tputs (term_cr, 1, _rl_output_character_function);
580       _rl_last_c_pos = 0;
581     }
582   else
583     {                   /* delta < 0 */
584       if (term_up && *term_up)
585         for (i = 0; i < -delta; i++)
586           tputs (term_up, 1, _rl_output_character_function);
587     }
588 #endif /* !__GO32__ */
589   _rl_last_v_pos = to;          /* Now TO is here */
590 }
591
592 /* Physically print C on rl_outstream.  This is for functions which know
593    how to optimize the display. */
594 rl_show_char (c)
595      int c;
596 {
597   if (META_CHAR (c) && _rl_convert_meta_chars_to_ascii)
598     {
599       fprintf (rl_outstream, "M-");
600       c = UNMETA (c);
601     }
602
603 #if defined (DISPLAY_TABS)
604   if (c < 32 && c != '\t')
605 #else
606   if (c < 32)
607 #endif /* !DISPLAY_TABS */
608     {
609
610       c += 64;
611     }
612
613   putc (c, rl_outstream);
614   fflush (rl_outstream);
615 }
616
617 int
618 rl_character_len (c, pos)
619      register int c, pos;
620 {
621   if (META_CHAR (c))
622     return (_rl_convert_meta_chars_to_ascii ? 4 : 1);
623
624   if (c == '\t')
625     {
626 #if defined (DISPLAY_TABS)
627       return (((pos | (int)7) + 1) - pos);
628 #else
629       return (2);
630 #endif /* !DISPLAY_TABS */
631     }
632
633   if (isprint (c))
634     return (1);
635   else
636     return (2);
637 }
638
639 /* How to print things in the "echo-area".  The prompt is treated as a
640    mini-modeline. */
641
642 #if defined (HAVE_VARARGS_H)
643 rl_message (va_alist)
644      va_dcl
645 {
646   char *format;
647   va_list args;
648
649   va_start (args);
650   format = va_arg (args, char *);
651   vsprintf (msg_buf, format, args);
652   va_end (args);
653
654   rl_display_prompt = msg_buf;
655   rl_redisplay ();
656 }
657 #else /* !HAVE_VARARGS_H */
658 rl_message (format, arg1, arg2)
659      char *format;
660 {
661   sprintf (msg_buf, format, arg1, arg2);
662   rl_display_prompt = msg_buf;
663   rl_redisplay ();
664 }
665 #endif /* !HAVE_VARARGS_H */
666
667 /* How to clear things from the "echo-area". */
668 rl_clear_message ()
669 {
670   rl_display_prompt = rl_prompt;
671   rl_redisplay ();
672 }
673
674 rl_reset_line_state ()
675 {
676   rl_on_new_line ();
677
678   rl_display_prompt = rl_prompt ? rl_prompt : "";
679   forced_display = 1;
680 }
681
682 /* Quick redisplay hack when erasing characters at the end of the line. */
683 void
684 _rl_erase_at_end_of_line (l)
685      int l;
686 {
687   register int i;
688
689   backspace (l);
690   for (i = 0; i < l; i++)
691     putc (' ', rl_outstream);
692   backspace (l);
693   for (i = 0; i < l; i++)
694     visible_line[--_rl_last_c_pos] = '\0';
695   rl_display_fixed++;
696 }
697
698 /* Clear to the end of the line.  COUNT is the minimum
699    number of character spaces to clear, */
700 static void
701 clear_to_eol (count)
702      int count;
703 {
704 #ifndef __GO32__
705   if (term_clreol)
706     {
707       tputs (term_clreol, 1, _rl_output_character_function);
708     }
709   else
710 #endif /* !__GO32__ */
711     {
712       register int i;
713
714       /* Do one more character space. */
715       count++;
716
717       for (i = 0; i < count; i++)
718         putc (' ', rl_outstream);
719
720       backspace (count);
721     }
722 }
723 /* Insert COUNT characters from STRING to the output stream. */
724 static void
725 insert_some_chars (string, count)
726      char *string;
727      int count;
728 {
729 #ifdef __GO32__
730   int row, col, width;
731   char *row_start;
732
733   ScreenGetCursor (&row, &col);
734   width = ScreenCols ();
735   row_start = ScreenPrimary + (row * width);
736   memcpy (row_start + col + count, row_start + col, width - col - count);
737   /* Place the text on the screen. */
738   _rl_output_some_chars (string, count);
739 #else /* __GO32__ */
740   /* If IC is defined, then we do not have to "enter" insert mode. */
741   if (term_IC)
742     {
743       char *tgoto (), *buffer;
744       buffer = tgoto (term_IC, 0, count);
745       tputs (buffer, 1, _rl_output_character_function);
746       _rl_output_some_chars (string, count);
747     }
748   else
749     {
750       register int i;
751
752       /* If we have to turn on insert-mode, then do so. */
753       if (term_im && *term_im)
754         tputs (term_im, 1, _rl_output_character_function);
755
756       /* If there is a special command for inserting characters, then
757          use that first to open up the space. */
758       if (term_ic && *term_ic)
759         {
760           for (i = count; i--; )
761             tputs (term_ic, 1, _rl_output_character_function);
762         }
763
764       /* Print the text. */
765       _rl_output_some_chars (string, count);
766
767       /* If there is a string to turn off insert mode, we had best use
768          it now. */
769       if (term_ei && *term_ei)
770         tputs (term_ei, 1, _rl_output_character_function);
771     }
772 #endif /* __GO32__ */
773 }
774
775 /* Delete COUNT characters from the display line. */
776 static void
777 delete_chars (count)
778      int count;
779 {
780 #if defined (__GO32__)
781   int row, col, width;
782   char *row_start;
783
784   ScreenGetCursor (&row, &col);
785   width = ScreenCols ();
786   row_start = ScreenPrimary + (row * width);
787   memcpy (row_start + col, row_start + col + count, width - col - count);
788   memset (row_start + width - count, 0, count * 2);
789 #else /* !__GO32__ */
790   if (count > screenwidth)
791     return;
792
793   if (term_DC && *term_DC)
794     {
795       char *tgoto (), *buffer;
796       buffer = tgoto (term_DC, 0, count);
797       tputs (buffer, 1, _rl_output_character_function);
798     }
799   else
800     {
801       if (term_dc && *term_dc)
802         while (count--)
803           tputs (term_dc, 1, _rl_output_character_function);
804     }
805 #endif /* !__GO32__ */
806 }