*** empty log message ***
[emacs.git] / src / term.c
blob1f8d463bfc818441e4f02d32110053025afc1254
1 /* terminal control module for terminals described by TERMCAP
2 Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs 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 1, or (at your option)
9 any later version.
11 GNU Emacs 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.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21 #include <stdio.h>
22 #include <ctype.h>
23 #include "config.h"
24 #include "termchar.h"
25 #include "termopts.h"
26 #include "cm.h"
27 #undef NULL
28 #include "lisp.h"
29 #include "screen.h"
30 #include "disptab.h"
31 #include "termhooks.h"
33 #define max(a, b) ((a) > (b) ? (a) : (b))
34 #define min(a, b) ((a) < (b) ? (a) : (b))
36 #define OUTPUT(a) tputs (a, SCREEN_HEIGHT (selected_screen) - curY, cmputc)
37 #define OUTPUT1(a) tputs (a, 1, cmputc)
38 #define OUTPUTL(a, lines) tputs (a, lines, cmputc)
39 #define OUTPUT_IF(a) { if (a) tputs (a, SCREEN_HEIGHT (selected_screen) - curY, cmputc); }
40 #define OUTPUT1_IF(a) { if (a) tputs (a, 1, cmputc); }
42 /* Terminal charateristics that higher levels want to look at.
43 These are all extern'd in termchar.h */
45 #ifndef MULTI_SCREEN
46 int screen_width; /* Number of usable columns */
47 int screen_height; /* Number of lines */
48 #endif
50 int must_write_spaces; /* Nonzero means spaces in the text
51 must actually be output; can't just skip
52 over some columns to leave them blank. */
53 int min_padding_speed; /* Speed below which no padding necessary */
55 int line_ins_del_ok; /* Terminal can insert and delete lines */
56 int char_ins_del_ok; /* Terminal can insert and delete chars */
57 int scroll_region_ok; /* Terminal supports setting the
58 scroll window */
59 int memory_below_screen; /* Terminal remembers lines
60 scrolled off bottom */
61 int fast_clear_end_of_line; /* Terminal has a `ce' string */
63 int dont_calculate_costs; /* Nonzero means don't bother computing */
64 /* various cost tables; we won't use them. */
66 /* Nonzero means no need to redraw the entire screen on resuming
67 a suspended Emacs. This is useful on terminals with multiple pages,
68 where one page is used for Emacs and another for all else. */
69 int no_redraw_on_reenter;
71 /* Hook functions that you can set to snap out the functions in this file.
72 These are all extern'd in termhooks.h */
74 int (*cursor_to_hook) ();
75 int (*raw_cursor_to_hook) ();
77 int (*clear_to_end_hook) ();
78 int (*clear_screen_hook) ();
79 int (*clear_end_of_line_hook) ();
81 int (*ins_del_lines_hook) ();
83 int (*change_line_highlight_hook) ();
84 int (*reassert_line_highlight_hook) ();
86 int (*insert_glyphs_hook) ();
87 int (*write_glyphs_hook) ();
88 int (*delete_glyphs_hook) ();
90 int (*ring_bell_hook) ();
92 int (*reset_terminal_modes_hook) ();
93 int (*set_terminal_modes_hook) ();
94 int (*update_begin_hook) ();
95 int (*update_end_hook) ();
96 int (*set_terminal_window_hook) ();
98 int (*read_socket_hook) ();
100 /* Return the current position of the mouse. This should clear
101 mouse_moved until the next motion event arrives. */
102 void (*mouse_position_hook) ( /* SCREEN_PTR *s,
103 Lisp_Object *x,
104 Lisp_Object *y,
105 Lisp_Object *time */ );
107 /* When reading from a minibuffer in a different screen, Emacs wants
108 to shift the highlight from the selected screen to the minibuffer's
109 screen; under X, this means it lies about where the focus is.
110 This hook tells the window system code to re-decide where to put
111 the highlight. */
112 void (*screen_rehighlight_hook) ( /* SCREEN_PTR s */ );
114 /* Strings, numbers and flags taken from the termcap entry. */
116 char *TS_ins_line; /* termcap "al" */
117 char *TS_ins_multi_lines; /* "AL" (one parameter, # lines to insert) */
118 char *TS_bell; /* "bl" */
119 char *TS_clr_to_bottom; /* "cd" */
120 char *TS_clr_line; /* "ce", clear to end of line */
121 char *TS_clr_screen; /* "cl" */
122 char *TS_set_scroll_region; /* "cs" (2 params, first line and last line) */
123 char *TS_set_scroll_region_1; /* "cS" (4 params: total lines,
124 lines above scroll region, lines below it,
125 total lines again) */
126 char *TS_del_char; /* "dc" */
127 char *TS_del_multi_chars; /* "DC" (one parameter, # chars to delete) */
128 char *TS_del_line; /* "dl" */
129 char *TS_del_multi_lines; /* "DL" (one parameter, # lines to delete) */
130 char *TS_delete_mode; /* "dm", enter character-delete mode */
131 char *TS_end_delete_mode; /* "ed", leave character-delete mode */
132 char *TS_end_insert_mode; /* "ei", leave character-insert mode */
133 char *TS_ins_char; /* "ic" */
134 char *TS_ins_multi_chars; /* "IC" (one parameter, # chars to insert) */
135 char *TS_insert_mode; /* "im", enter character-insert mode */
136 char *TS_pad_inserted_char; /* "ip". Just padding, no commands. */
137 char *TS_end_keypad_mode; /* "ke" */
138 char *TS_keypad_mode; /* "ks" */
139 char *TS_pad_char; /* "pc", char to use as padding */
140 char *TS_repeat; /* "rp" (2 params, # times to repeat
141 and character to be repeated) */
142 char *TS_end_standout_mode; /* "se" */
143 char *TS_fwd_scroll; /* "sf" */
144 char *TS_standout_mode; /* "so" */
145 char *TS_rev_scroll; /* "sr" */
146 char *TS_end_termcap_modes; /* "te" */
147 char *TS_termcap_modes; /* "ti" */
148 char *TS_visible_bell; /* "vb" */
149 char *TS_end_visual_mode; /* "ve" */
150 char *TS_visual_mode; /* "vi" */
151 char *TS_set_window; /* "wi" (4 params, start and end of window,
152 each as vpos and hpos) */
154 int TF_hazeltine; /* termcap hz flag. */
155 int TF_insmode_motion; /* termcap mi flag: can move while in insert mode. */
156 int TF_standout_motion; /* termcap mi flag: can move while in standout mode. */
157 int TF_underscore; /* termcap ul flag: _ underlines if overstruck on
158 nonblank position. Must clear before writing _. */
159 int TF_teleray; /* termcap xt flag: many weird consequences.
160 For t1061. */
162 int TF_xs; /* Nonzero for "xs". If set together with
163 TN_standout_width == 0, it means don't bother
164 to write any end-standout cookies. */
166 int TN_standout_width; /* termcap sg number: width occupied by standout
167 markers */
169 static int RPov; /* # chars to start a TS_repeat */
171 static int delete_in_insert_mode; /* delete mode == insert mode */
173 static int se_is_so; /* 1 if same string both enters and leaves
174 standout mode */
176 /* internal state */
178 /* Number of chars of space used for standout marker at beginning of line,
179 or'd with 0100. Zero if no standout marker at all.
181 Used IFF TN_standout_width >= 0. */
183 static char *chars_wasted;
184 static char *copybuf;
186 /* nonzero means supposed to write text in standout mode. */
187 int standout_requested;
189 int insert_mode; /* Nonzero when in insert mode. */
190 int standout_mode; /* Nonzero when in standout mode. */
192 /* Size of window specified by higher levels.
193 This is the number of lines, from the top of screen downwards,
194 which can participate in insert-line/delete-line operations.
196 Effectively it excludes the bottom screen_height - specified_window_size
197 lines from those operations. */
199 int specified_window;
201 /* Screen currently being redisplayed; 0 if not currently redisplaying.
202 (Direct output does not count). */
204 SCREEN_PTR updating_screen;
206 char *tparam ();
208 ring_bell ()
210 if (! SCREEN_IS_TERMCAP (selected_screen))
212 (*ring_bell_hook) ();
213 return;
215 OUTPUT (TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell);
218 set_terminal_modes ()
220 if (! SCREEN_IS_TERMCAP (selected_screen))
222 (*set_terminal_modes_hook) ();
223 return;
225 OUTPUT_IF (TS_termcap_modes);
226 OUTPUT_IF (TS_visual_mode);
227 OUTPUT_IF (TS_keypad_mode);
228 losecursor ();
231 reset_terminal_modes ()
233 if (! SCREEN_IS_TERMCAP (selected_screen))
235 (*reset_terminal_modes_hook) ();
236 return;
238 if (TN_standout_width < 0)
239 turn_off_highlight ();
240 turn_off_insert ();
241 OUTPUT_IF (TS_end_keypad_mode);
242 OUTPUT_IF (TS_end_visual_mode);
243 OUTPUT_IF (TS_end_termcap_modes);
244 /* Output raw CR so kernel can track the cursor hpos. */
245 /* But on magic-cookie terminals this can erase an end-standout marker and
246 cause the rest of the screen to be in standout, so move down first. */
247 if (TN_standout_width >= 0)
248 cmputc ('\n');
249 cmputc ('\r');
252 update_begin (s)
253 SCREEN_PTR s;
255 updating_screen = s;
256 if (! SCREEN_IS_TERMCAP (updating_screen))
257 (*update_begin_hook) (s);
260 update_end (s)
261 SCREEN_PTR s;
263 if (! SCREEN_IS_TERMCAP (updating_screen))
265 (*update_end_hook) (s);
266 updating_screen = 0;
267 return;
269 turn_off_insert ();
270 background_highlight ();
271 standout_requested = 0;
272 updating_screen = 0;
275 set_terminal_window (size)
276 int size;
278 if (! SCREEN_IS_TERMCAP (updating_screen))
280 (*set_terminal_window_hook) (size);
281 return;
283 specified_window = size ? size : SCREEN_HEIGHT (selected_screen);
284 if (!scroll_region_ok)
285 return;
286 set_scroll_region (0, specified_window);
289 set_scroll_region (start, stop)
290 int start, stop;
292 char *buf;
293 if (TS_set_scroll_region)
295 buf = tparam (TS_set_scroll_region, 0, 0, start, stop - 1);
297 else if (TS_set_scroll_region_1)
299 buf = tparam (TS_set_scroll_region_1, 0, 0,
300 SCREEN_HEIGHT (selected_screen), start,
301 SCREEN_HEIGHT (selected_screen) - stop,
302 SCREEN_HEIGHT (selected_screen));
304 else
306 buf = tparam (TS_set_window, 0, 0, start, 0, stop, SCREEN_WIDTH (selected_screen));
308 OUTPUT (buf);
309 free (buf);
310 losecursor ();
313 turn_on_insert ()
315 if (!insert_mode)
316 OUTPUT (TS_insert_mode);
317 insert_mode = 1;
320 turn_off_insert ()
322 if (insert_mode)
323 OUTPUT (TS_end_insert_mode);
324 insert_mode = 0;
327 /* Handle highlighting when TN_standout_width (termcap sg) is not specified.
328 In these terminals, output is affected by the value of standout
329 mode when the output is written.
331 These functions are called on all terminals, but do nothing
332 on terminals whose standout mode does not work that way. */
334 turn_off_highlight ()
336 if (TN_standout_width < 0)
338 if (standout_mode)
339 OUTPUT_IF (TS_end_standout_mode);
340 standout_mode = 0;
344 turn_on_highlight ()
346 if (TN_standout_width < 0)
348 if (!standout_mode)
349 OUTPUT_IF (TS_standout_mode);
350 standout_mode = 1;
354 /* Set standout mode to the state it should be in for
355 empty space inside windows. What this is,
356 depends on the user option inverse-video. */
358 background_highlight ()
360 if (TN_standout_width >= 0)
361 return;
362 if (inverse_video)
363 turn_on_highlight ();
364 else
365 turn_off_highlight ();
368 /* Set standout mode to the mode specified for the text to be output. */
370 static
371 highlight_if_desired ()
373 if (TN_standout_width >= 0)
374 return;
375 if (!inverse_video == !standout_requested)
376 turn_off_highlight ();
377 else
378 turn_on_highlight ();
381 /* Handle standout mode for terminals in which TN_standout_width >= 0.
382 On these terminals, standout is controlled by markers that
383 live inside the screen memory. TN_standout_width is the width
384 that the marker occupies in memory. Standout runs from the marker
385 to the end of the line on some terminals, or to the next
386 turn-off-standout marker (TS_end_standout_mode) string
387 on other terminals. */
389 /* Write a standout marker or end-standout marker at the front of the line
390 at vertical position vpos. */
392 write_standout_marker (flag, vpos)
393 int flag, vpos;
395 if (flag || (TS_end_standout_mode && !TF_teleray && !se_is_so
396 && !(TF_xs && TN_standout_width == 0)))
398 cmgoto (vpos, 0);
399 cmplus (TN_standout_width);
400 OUTPUT (flag ? TS_standout_mode : TS_end_standout_mode);
401 chars_wasted[curY] = TN_standout_width | 0100;
405 /* External interface to control of standout mode.
406 Call this when about to modify line at position VPOS
407 and not change whether it is highlighted. */
409 reassert_line_highlight (highlight, vpos)
410 int highlight;
411 int vpos;
413 if (! SCREEN_IS_TERMCAP ((updating_screen ? updating_screen : selected_screen)))
415 (*reassert_line_highlight_hook) (highlight, vpos);
416 return;
418 if (TN_standout_width < 0)
419 /* Handle terminals where standout takes affect at output time */
420 standout_requested = highlight;
421 else if (chars_wasted[vpos] == 0)
422 /* For terminals with standout markers, write one on this line
423 if there isn't one already. */
424 write_standout_marker (highlight, vpos);
427 /* Call this when about to modify line at position VPOS
428 and change whether it is highlighted. */
430 change_line_highlight (new_highlight, vpos, first_unused_hpos)
431 int new_highlight, vpos, first_unused_hpos;
433 standout_requested = new_highlight;
434 if (! SCREEN_IS_TERMCAP (updating_screen))
436 (*change_line_highlight_hook) (new_highlight, vpos, first_unused_hpos);
437 return;
440 cursor_to (vpos, 0);
442 if (TN_standout_width < 0)
443 background_highlight ();
444 /* If line starts with a marker, delete the marker */
445 else if (TS_clr_line && chars_wasted[curY])
447 turn_off_insert ();
448 /* On Teleray, make sure to erase the SO marker. */
449 if (TF_teleray)
451 cmgoto (curY - 1, SCREEN_WIDTH (selected_screen) - 4);
452 OUTPUT ("\033S");
453 curY++; /* ESC S moves to next line where the TS_standout_mode was */
454 curX = 0;
456 else
457 cmgoto (curY, 0); /* reposition to kill standout marker */
459 clear_end_of_line_raw (first_unused_hpos);
460 reassert_line_highlight (new_highlight, curY);
464 /* Move to absolute position, specified origin 0 */
466 cursor_to (row, col)
468 if (! SCREEN_IS_TERMCAP ((updating_screen
469 ? updating_screen
470 : selected_screen))
471 && cursor_to_hook)
473 (*cursor_to_hook) (row, col);
474 return;
477 col += chars_wasted[row] & 077;
478 if (curY == row && curX == col)
479 return;
480 if (!TF_standout_motion)
481 background_highlight ();
482 if (!TF_insmode_motion)
483 turn_off_insert ();
484 cmgoto (row, col);
487 /* Similar but don't take any account of the wasted characters. */
489 raw_cursor_to (row, col)
491 if (! SCREEN_IS_TERMCAP ((updating_screen ? updating_screen : selected_screen)))
493 (*raw_cursor_to_hook) (row, col);
494 return;
496 if (curY == row && curX == col)
497 return;
498 if (!TF_standout_motion)
499 background_highlight ();
500 if (!TF_insmode_motion)
501 turn_off_insert ();
502 cmgoto (row, col);
505 /* Erase operations */
507 /* clear from cursor to end of screen */
508 clear_to_end ()
510 register int i;
512 if (clear_to_end_hook && SCREEN_IS_TERMCAP (updating_screen))
514 (*clear_to_end_hook) ();
515 return;
517 if (TS_clr_to_bottom)
519 background_highlight ();
520 OUTPUT (TS_clr_to_bottom);
521 bzero (chars_wasted + curY, SCREEN_HEIGHT (selected_screen) - curY);
523 else
525 for (i = curY; i < SCREEN_HEIGHT (selected_screen); i++)
527 cursor_to (i, 0);
528 clear_end_of_line_raw (SCREEN_WIDTH (selected_screen));
533 /* Clear entire screen */
535 clear_screen ()
537 if (clear_screen_hook
538 && ! SCREEN_IS_TERMCAP ((updating_screen ? updating_screen : selected_screen)))
540 (*clear_screen_hook) ();
541 return;
543 if (TS_clr_screen)
545 background_highlight ();
546 OUTPUT (TS_clr_screen);
547 bzero (chars_wasted, SCREEN_HEIGHT (selected_screen));
548 cmat (0, 0);
550 else
552 cursor_to (0, 0);
553 clear_to_end ();
557 /* Clear to end of line, but do not clear any standout marker.
558 Assumes that the cursor is positioned at a character of real text,
559 which implies it cannot be before a standout marker
560 unless the marker has zero width.
562 Note that the cursor may be moved. */
564 clear_end_of_line (first_unused_hpos)
565 int first_unused_hpos;
567 static GLYPH buf[1] = {SPACEGLYPH};
568 if (SCREEN_IS_TERMCAP (selected_screen)
569 && TN_standout_width == 0 && curX == 0 && chars_wasted[curY] != 0)
570 write_glyphs (buf, 1);
571 clear_end_of_line_raw (first_unused_hpos);
574 /* Clear from cursor to end of line.
575 Assume that the line is already clear starting at column first_unused_hpos.
576 If the cursor is at a standout marker, erase the marker.
578 Note that the cursor may be moved, on terminals lacking a `ce' string. */
580 clear_end_of_line_raw (first_unused_hpos)
581 int first_unused_hpos;
583 register int i;
585 if (clear_end_of_line_hook
586 && ! SCREEN_IS_TERMCAP ((updating_screen
587 ? updating_screen
588 : selected_screen)))
590 (*clear_end_of_line_hook) (first_unused_hpos);
591 return;
594 first_unused_hpos += chars_wasted[curY] & 077;
595 if (curX >= first_unused_hpos)
596 return;
597 /* Notice if we are erasing a magic cookie */
598 if (curX == 0)
599 chars_wasted[curY] = 0;
600 background_highlight ();
601 if (TS_clr_line)
603 OUTPUT1 (TS_clr_line);
605 else
606 { /* have to do it the hard way */
607 turn_off_insert ();
609 /* Do not write in last row last col with Autowrap on. */
610 if (AutoWrap && curY == SCREEN_HEIGHT (selected_screen) - 1
611 && first_unused_hpos == SCREEN_WIDTH (selected_screen))
612 first_unused_hpos--;
614 for (i = curX; i < first_unused_hpos; i++)
616 if (termscript)
617 fputc (' ', termscript);
618 putchar (' ');
620 cmplus (first_unused_hpos - curX);
625 write_glyphs (string, len)
626 register GLYPH *string;
627 register int len;
629 register GLYPH g;
630 register int tlen = GLYPH_TABLE_LENGTH;
631 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
633 if (write_glyphs_hook
634 && ! SCREEN_IS_TERMCAP ((updating_screen ? updating_screen : selected_screen)))
636 (*write_glyphs_hook) (string, len);
637 return;
640 highlight_if_desired ();
641 turn_off_insert ();
643 /* Don't dare write in last column of bottom line, if AutoWrap,
644 since that would scroll the whole screen on some terminals. */
646 if (AutoWrap
647 && curY + 1 == SCREEN_HEIGHT (selected_screen)
648 && (curX + len - (chars_wasted[curY] & 077)
649 == SCREEN_WIDTH (selected_screen)))
650 len --;
652 cmplus (len);
653 while (--len >= 0)
655 g = *string++;
656 /* Check quickly for G beyond length of table.
657 That implies it isn't an alias and is simple. */
658 if (g >= tlen)
660 simple:
661 putc (g & 0xff, stdout);
662 if (ferror (stdout))
663 clearerr (stdout);
664 if (termscript)
665 putc (g & 0xff, termscript);
667 else
669 /* G has an entry in Vglyph_table,
670 so process any alias and then test for simpleness. */
671 while (GLYPH_ALIAS_P (tbase, tlen, g))
672 g = GLYPH_ALIAS (tbase, g);
673 if (GLYPH_SIMPLE_P (tbase, tlen, g))
674 goto simple;
675 else
677 /* Here if G (or its definition as an alias) is not simple. */
678 fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g),
679 stdout);
680 if (ferror (stdout))
681 clearerr (stdout);
682 if (termscript)
683 fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g),
684 termscript);
690 /* If start is zero, insert blanks instead of a string at start */
692 insert_glyphs (start, len)
693 register GLYPH *start;
694 register int len;
696 char *buf;
697 register GLYPH g;
698 register int tlen = GLYPH_TABLE_LENGTH;
699 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
701 if (insert_glyphs_hook && ! SCREEN_IS_TERMCAP (updating_screen))
703 (*insert_glyphs_hook) (start, len);
704 return;
706 highlight_if_desired ();
708 if (TS_ins_multi_chars)
710 buf = tparam (TS_ins_multi_chars, 0, 0, len);
711 OUTPUT1 (buf);
712 free (buf);
713 if (start)
714 write_glyphs (start, len);
715 return;
718 turn_on_insert ();
719 cmplus (len);
720 while (--len >= 0)
722 OUTPUT1_IF (TS_ins_char);
723 if (!start)
724 g = SPACEGLYPH;
725 else
726 g = *start++;
728 if (GLYPH_SIMPLE_P (tbase, tlen, g))
730 putc (g & 0xff, stdout);
731 if (ferror (stdout))
732 clearerr (stdout);
733 if (termscript)
734 putc (g & 0xff, termscript);
736 else
738 fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g), stdout);
739 if (ferror (stdout))
740 clearerr (stdout);
741 if (termscript)
742 fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g),
743 termscript);
746 OUTPUT1_IF (TS_pad_inserted_char);
750 delete_glyphs (n)
751 register int n;
753 char *buf;
754 register int i;
756 if (delete_glyphs_hook && ! SCREEN_IS_TERMCAP (updating_screen))
758 (*delete_glyphs_hook) (n);
759 return;
762 if (delete_in_insert_mode)
764 turn_on_insert ();
766 else
768 turn_off_insert ();
769 OUTPUT_IF (TS_delete_mode);
772 if (TS_del_multi_chars)
774 buf = tparam (TS_del_multi_chars, 0, 0, n);
775 OUTPUT1 (buf);
776 free (buf);
778 else
779 for (i = 0; i < n; i++)
780 OUTPUT1 (TS_del_char);
781 if (!delete_in_insert_mode)
782 OUTPUT_IF (TS_end_delete_mode);
785 /* Insert N lines at vpos VPOS. If N is negative, delete -N lines. */
787 ins_del_lines (vpos, n)
788 int vpos, n;
790 char *multi = n > 0 ? TS_ins_multi_lines : TS_del_multi_lines;
791 char *single = n > 0 ? TS_ins_line : TS_del_line;
792 char *scroll = n > 0 ? TS_rev_scroll : TS_fwd_scroll;
794 register int i = n > 0 ? n : -n;
795 register char *buf;
797 if (ins_del_lines_hook && ! SCREEN_IS_TERMCAP (updating_screen))
799 (*ins_del_lines_hook) (vpos, n);
800 return;
803 /* If the lines below the insertion are being pushed
804 into the end of the window, this is the same as clearing;
805 and we know the lines are already clear, since the matching
806 deletion has already been done. So can ignore this. */
807 /* If the lines below the deletion are blank lines coming
808 out of the end of the window, don't bother,
809 as there will be a matching inslines later that will flush them. */
810 if (scroll_region_ok && vpos + i >= specified_window)
811 return;
812 if (!memory_below_screen && vpos + i >= SCREEN_HEIGHT (selected_screen))
813 return;
815 if (multi)
817 raw_cursor_to (vpos, 0);
818 background_highlight ();
819 buf = tparam (multi, 0, 0, i);
820 OUTPUT (buf);
821 free (buf);
823 else if (single)
825 raw_cursor_to (vpos, 0);
826 background_highlight ();
827 while (--i >= 0)
828 OUTPUT (single);
829 if (TF_teleray)
830 curX = 0;
832 else
834 set_scroll_region (vpos, specified_window);
835 if (n < 0)
836 raw_cursor_to (specified_window - 1, 0);
837 else
838 raw_cursor_to (vpos, 0);
839 background_highlight ();
840 while (--i >= 0)
841 OUTPUTL (scroll, specified_window - vpos);
842 set_scroll_region (0, specified_window);
845 if (TN_standout_width >= 0)
847 register lower_limit
848 = (scroll_region_ok
849 ? specified_window
850 : SCREEN_HEIGHT (selected_screen));
852 if (n < 0)
854 bcopy (&chars_wasted[vpos - n], &chars_wasted[vpos],
855 lower_limit - vpos + n);
856 bzero (&chars_wasted[lower_limit + n], - n);
858 else
860 bcopy (&chars_wasted[vpos], &copybuf[vpos], lower_limit - vpos - n);
861 bcopy (&copybuf[vpos], &chars_wasted[vpos + n],
862 lower_limit - vpos - n);
863 bzero (&chars_wasted[vpos], n);
866 if (!scroll_region_ok && memory_below_screen && n < 0)
868 cursor_to (SCREEN_HEIGHT (selected_screen) + n, 0);
869 clear_to_end ();
873 /* Compute cost of sending "str", in characters,
874 not counting any line-dependent padding. */
877 string_cost (str)
878 char *str;
880 cost = 0;
881 if (str)
882 tputs (str, 0, evalcost);
883 return cost;
886 /* Compute cost of sending "str", in characters,
887 counting any line-dependent padding at one line. */
889 static int
890 string_cost_one_line (str)
891 char *str;
893 cost = 0;
894 if (str)
895 tputs (str, 1, evalcost);
896 return cost;
899 /* Compute per line amount of line-dependent padding,
900 in tenths of characters. */
903 per_line_cost (str)
904 register char *str;
906 cost = 0;
907 if (str)
908 tputs (str, 0, evalcost);
909 cost = - cost;
910 if (str)
911 tputs (str, 10, evalcost);
912 return cost;
915 #ifndef old
916 /* char_ins_del_cost[n] is cost of inserting N characters.
917 char_ins_del_cost[-n] is cost of deleting N characters. */
919 int *char_ins_del_vector;
921 #define char_ins_del_cost(s) (&char_ins_del_vector[SCREEN_WIDTH ((s))])
922 #endif
924 /* ARGSUSED */
925 static void
926 calculate_ins_del_char_costs (screen)
927 SCREEN_PTR screen;
929 int ins_startup_cost, del_startup_cost;
930 int ins_cost_per_char, del_cost_per_char;
931 register int i;
932 register int *p;
934 if (TS_ins_multi_chars)
936 ins_cost_per_char = 0;
937 ins_startup_cost = string_cost_one_line (TS_ins_multi_chars);
939 else if (TS_ins_char || TS_pad_inserted_char
940 || (TS_insert_mode && TS_end_insert_mode))
942 ins_startup_cost = (30 * (string_cost (TS_insert_mode)
943 + string_cost (TS_end_insert_mode))) / 100;
944 ins_cost_per_char = (string_cost_one_line (TS_ins_char)
945 + string_cost_one_line (TS_pad_inserted_char));
947 else
949 ins_startup_cost = 9999;
950 ins_cost_per_char = 0;
953 if (TS_del_multi_chars)
955 del_cost_per_char = 0;
956 del_startup_cost = string_cost_one_line (TS_del_multi_chars);
958 else if (TS_del_char)
960 del_startup_cost = (string_cost (TS_delete_mode)
961 + string_cost (TS_end_delete_mode));
962 if (delete_in_insert_mode)
963 del_startup_cost /= 2;
964 del_cost_per_char = string_cost_one_line (TS_del_char);
966 else
968 del_startup_cost = 9999;
969 del_cost_per_char = 0;
972 /* Delete costs are at negative offsets */
973 p = &char_ins_del_cost (screen)[0];
974 for (i = SCREEN_WIDTH (selected_screen); --i >= 0;)
975 *--p = (del_startup_cost += del_cost_per_char);
977 /* Doing nothing is free */
978 p = &char_ins_del_cost (screen)[0];
979 *p++ = 0;
981 /* Insert costs are at positive offsets */
982 for (i = SCREEN_WIDTH (screen); --i >= 0;)
983 *p++ = (ins_startup_cost += ins_cost_per_char);
986 #ifdef HAVE_X_WINDOWS
987 extern int x_screen_planes;
988 #endif
990 calculate_costs (screen)
991 SCREEN_PTR screen;
993 register char *s = TS_set_scroll_region ?
994 TS_set_scroll_region
995 : TS_set_scroll_region_1;
997 if (dont_calculate_costs)
998 return;
1000 #ifdef HAVE_X_WINDOWS
1001 if (SCREEN_IS_X (screen))
1003 do_line_insertion_deletion_costs (screen, 0, ".5*", 0, ".5*",
1004 0, 0, x_screen_planes);
1005 return;
1007 #endif
1009 /* These variables are only used for terminal stuff. They are allocated
1010 once for the terminal screen of X-windows emacs, but not used afterwards.
1012 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1013 X turns off char_ins_del_ok.
1015 chars_wasted and copybuf are only used here in term.c in cases where
1016 the term hook isn't called. */
1018 if (chars_wasted != 0)
1019 chars_wasted = (char *) xrealloc (chars_wasted, SCREEN_HEIGHT (screen));
1020 else
1021 chars_wasted = (char *) xmalloc (SCREEN_HEIGHT (screen));
1023 if (copybuf != 0)
1024 copybuf = (char *) xrealloc (copybuf, SCREEN_HEIGHT (screen));
1025 else
1026 copybuf = (char *) xmalloc (SCREEN_HEIGHT (screen));
1028 if (char_ins_del_vector != 0)
1029 char_ins_del_vector
1030 = (int *) xrealloc (char_ins_del_vector,
1031 (sizeof (int)
1032 + 2 * SCREEN_WIDTH (screen) * sizeof (int)));
1033 else
1034 char_ins_del_vector
1035 = (int *) xmalloc (sizeof (int)
1036 + 2 * SCREEN_WIDTH (screen) * sizeof (int));
1038 bzero (chars_wasted, SCREEN_HEIGHT (screen));
1039 bzero (copybuf, SCREEN_HEIGHT (screen));
1040 bzero (char_ins_del_vector, (sizeof (int)
1041 + 2 * SCREEN_WIDTH (screen) * sizeof (int)));
1043 if (s && (!TS_ins_line && !TS_del_line))
1044 do_line_insertion_deletion_costs (screen,
1045 TS_rev_scroll, TS_ins_multi_lines,
1046 TS_fwd_scroll, TS_del_multi_lines,
1047 s, s, 1);
1048 else
1049 do_line_insertion_deletion_costs (screen,
1050 TS_ins_line, TS_ins_multi_lines,
1051 TS_del_line, TS_del_multi_lines,
1052 0, 0, 1);
1054 calculate_ins_del_char_costs (screen);
1056 /* Don't use TS_repeat if its padding is worse than sending the chars */
1057 if (TS_repeat && per_line_cost (TS_repeat) * baud_rate < 9000)
1058 RPov = string_cost (TS_repeat);
1059 else
1060 RPov = SCREEN_WIDTH (screen) * 2;
1062 cmcostinit (); /* set up cursor motion costs */
1065 term_init (terminal_type)
1066 char *terminal_type;
1068 char *area;
1069 char **address = &area;
1070 char buffer[2044];
1071 register char *p;
1072 int status;
1074 extern char *tgetstr ();
1076 Wcm_clear ();
1077 dont_calculate_costs = 0;
1079 status = tgetent (buffer, terminal_type);
1080 if (status < 0)
1081 fatal ("Cannot open termcap database file.\n");
1082 if (status == 0)
1083 fatal ("Terminal type %s is not defined.\n", terminal_type);
1085 #ifdef TERMINFO
1086 area = (char *) malloc (2044);
1087 #else
1088 area = (char *) malloc (strlen (buffer));
1089 #endif /* not TERMINFO */
1090 if (area == 0)
1091 abort ();
1093 TS_ins_line = tgetstr ("al", address);
1094 TS_ins_multi_lines = tgetstr ("AL", address);
1095 TS_bell = tgetstr ("bl", address);
1096 BackTab = tgetstr ("bt", address);
1097 TS_clr_to_bottom = tgetstr ("cd", address);
1098 TS_clr_line = tgetstr ("ce", address);
1099 TS_clr_screen = tgetstr ("cl", address);
1100 ColPosition = tgetstr ("ch", address);
1101 AbsPosition = tgetstr ("cm", address);
1102 CR = tgetstr ("cr", address);
1103 TS_set_scroll_region = tgetstr ("cs", address);
1104 TS_set_scroll_region_1 = tgetstr ("cS", address);
1105 RowPosition = tgetstr ("cv", address);
1106 TS_del_char = tgetstr ("dc", address);
1107 TS_del_multi_chars = tgetstr ("DC", address);
1108 TS_del_line = tgetstr ("dl", address);
1109 TS_del_multi_lines = tgetstr ("DL", address);
1110 TS_delete_mode = tgetstr ("dm", address);
1111 TS_end_delete_mode = tgetstr ("ed", address);
1112 TS_end_insert_mode = tgetstr ("ei", address);
1113 Home = tgetstr ("ho", address);
1114 TS_ins_char = tgetstr ("ic", address);
1115 TS_ins_multi_chars = tgetstr ("IC", address);
1116 TS_insert_mode = tgetstr ("im", address);
1117 TS_pad_inserted_char = tgetstr ("ip", address);
1118 TS_end_keypad_mode = tgetstr ("ke", address);
1119 TS_keypad_mode = tgetstr ("ks", address);
1120 LastLine = tgetstr ("ll", address);
1121 Right = tgetstr ("nd", address);
1122 Down = tgetstr ("do", address);
1123 if (!Down)
1124 Down = tgetstr ("nl", address); /* Obsolete name for "do" */
1125 #ifdef VMS
1126 /* VMS puts a carriage return before each linefeed,
1127 so it is not safe to use linefeeds. */
1128 if (Down && Down[0] == '\n' && Down[1] == '\0')
1129 Down = 0;
1130 #endif /* VMS */
1131 if (tgetflag ("bs"))
1132 Left = "\b"; /* can't possibly be longer! */
1133 else /* (Actually, "bs" is obsolete...) */
1134 Left = tgetstr ("le", address);
1135 if (!Left)
1136 Left = tgetstr ("bc", address); /* Obsolete name for "le" */
1137 TS_pad_char = tgetstr ("pc", address);
1138 TS_repeat = tgetstr ("rp", address);
1139 TS_end_standout_mode = tgetstr ("se", address);
1140 TS_fwd_scroll = tgetstr ("sf", address);
1141 TS_standout_mode = tgetstr ("so", address);
1142 TS_rev_scroll = tgetstr ("sr", address);
1143 Wcm.cm_tab = tgetstr ("ta", address);
1144 TS_end_termcap_modes = tgetstr ("te", address);
1145 TS_termcap_modes = tgetstr ("ti", address);
1146 Up = tgetstr ("up", address);
1147 TS_visible_bell = tgetstr ("vb", address);
1148 TS_end_visual_mode = tgetstr ("ve", address);
1149 TS_visual_mode = tgetstr ("vs", address);
1150 TS_set_window = tgetstr ("wi", address);
1151 MultiUp = tgetstr ("UP", address);
1152 MultiDown = tgetstr ("DO", address);
1153 MultiLeft = tgetstr ("LE", address);
1154 MultiRight = tgetstr ("RI", address);
1156 AutoWrap = tgetflag ("am");
1157 memory_below_screen = tgetflag ("db");
1158 TF_hazeltine = tgetflag ("hz");
1159 must_write_spaces = tgetflag ("in");
1160 meta_key = tgetflag ("km") || tgetflag ("MT");
1161 TF_insmode_motion = tgetflag ("mi");
1162 TF_standout_motion = tgetflag ("ms");
1163 TF_underscore = tgetflag ("ul");
1164 MagicWrap = tgetflag ("xn");
1165 TF_xs = tgetflag ("xs");
1166 TF_teleray = tgetflag ("xt");
1168 /* Get screen size from system, or else from termcap. */
1169 get_screen_size (&SCREEN_WIDTH (selected_screen),
1170 &SCREEN_HEIGHT (selected_screen));
1171 if (SCREEN_WIDTH (selected_screen) <= 0)
1172 SCREEN_WIDTH (selected_screen) = tgetnum ("co");
1173 if (SCREEN_HEIGHT (selected_screen) <= 0)
1174 SCREEN_HEIGHT (selected_screen) = tgetnum ("li");
1176 min_padding_speed = tgetnum ("pb");
1177 TN_standout_width = tgetnum ("sg");
1178 TabWidth = tgetnum ("tw");
1180 #ifdef VMS
1181 /* These capabilities commonly use ^J.
1182 I don't know why, but sending them on VMS does not work;
1183 it causes following spaces to be lost, sometimes.
1184 For now, the simplest fix is to avoid using these capabilities ever. */
1185 if (Down && Down[0] == '\n')
1186 Down = 0;
1187 #endif /* VMS */
1189 if (!TS_bell)
1190 TS_bell = "\07";
1192 if (!TS_fwd_scroll)
1193 TS_fwd_scroll = Down;
1195 PC = TS_pad_char ? *TS_pad_char : 0;
1197 if (TabWidth < 0)
1198 TabWidth = 8;
1200 /* Turned off since /etc/termcap seems to have :ta= for most terminals
1201 and newer termcap doc does not seem to say there is a default.
1202 if (!Wcm.cm_tab)
1203 Wcm.cm_tab = "\t";
1206 if (TS_standout_mode == 0)
1208 TN_standout_width = tgetnum ("ug");
1209 TS_end_standout_mode = tgetstr ("ue", address);
1210 TS_standout_mode = tgetstr ("us", address);
1213 if (TF_teleray)
1215 Wcm.cm_tab = 0;
1216 /* Teleray: most programs want a space in front of TS_standout_mode,
1217 but Emacs can do without it (and give one extra column). */
1218 TS_standout_mode = "\033RD";
1219 TN_standout_width = 1;
1220 /* But that means we cannot rely on ^M to go to column zero! */
1221 CR = 0;
1222 /* LF can't be trusted either -- can alter hpos */
1223 /* if move at column 0 thru a line with TS_standout_mode */
1224 Down = 0;
1227 /* Special handling for certain terminal types known to need it */
1229 if (!strcmp (terminal_type, "supdup"))
1231 memory_below_screen = 1;
1232 Wcm.cm_losewrap = 1;
1234 if (!strncmp (terminal_type, "c10", 3)
1235 || !strcmp (terminal_type, "perq"))
1237 /* Supply a makeshift :wi string.
1238 This string is not valid in general since it works only
1239 for windows starting at the upper left corner;
1240 but that is all Emacs uses.
1242 This string works only if the screen is using
1243 the top of the video memory, because addressing is memory-relative.
1244 So first check the :ti string to see if that is true.
1246 It would be simpler if the :wi string could go in the termcap
1247 entry, but it can't because it is not fully valid.
1248 If it were in the termcap entry, it would confuse other programs. */
1249 if (!TS_set_window)
1251 p = TS_termcap_modes;
1252 while (*p && strcmp (p, "\033v "))
1253 p++;
1254 if (*p)
1255 TS_set_window = "\033v%C %C %C %C ";
1257 /* Termcap entry often fails to have :in: flag */
1258 must_write_spaces = 1;
1259 /* :ti string typically fails to have \E^G! in it */
1260 /* This limits scope of insert-char to one line. */
1261 strcpy (area, TS_termcap_modes);
1262 strcat (area, "\033\007!");
1263 TS_termcap_modes = area;
1264 area += strlen (area) + 1;
1265 p = AbsPosition;
1266 /* Change all %+ parameters to %C, to handle
1267 values above 96 correctly for the C100. */
1268 while (*p)
1270 if (p[0] == '%' && p[1] == '+')
1271 p[1] = 'C';
1272 p++;
1276 ScreenRows = SCREEN_HEIGHT (selected_screen);
1277 ScreenCols = SCREEN_WIDTH (selected_screen);
1278 specified_window = SCREEN_HEIGHT (selected_screen);
1280 if (Wcm_init () == -1) /* can't do cursor motion */
1281 #ifdef VMS
1282 fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
1283 It lacks the ability to position the cursor.\n\
1284 If that is not the actual type of terminal you have, use either the\n\
1285 DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\
1286 or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.\n",
1287 terminal_type);
1288 #else
1289 fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
1290 It lacks the ability to position the cursor.\n\
1291 If that is not the actual type of terminal you have,\n\
1292 use the C-shell command `setenv TERM ...' to specify the correct type.\n\
1293 It may be necessary to do `unsetenv TERMCAP' as well.\n",
1294 terminal_type);
1295 #endif
1296 if (SCREEN_HEIGHT (selected_screen) <= 0
1297 || SCREEN_WIDTH (selected_screen) <= 0)
1298 fatal ("The screen size has not been specified.");
1300 delete_in_insert_mode
1301 = TS_delete_mode && TS_insert_mode
1302 && !strcmp (TS_delete_mode, TS_insert_mode);
1304 se_is_so = (TS_standout_mode
1305 && TS_end_standout_mode
1306 && !strcmp (TS_standout_mode, TS_end_standout_mode));
1308 /* Remove width of standout marker from usable width of line */
1309 if (TN_standout_width > 0)
1310 SCREEN_WIDTH (selected_screen) -= TN_standout_width;
1312 UseTabs = tabs_safe_p () && TabWidth == 8;
1314 scroll_region_ok
1315 = (Wcm.cm_abs
1316 && (TS_set_window || TS_set_scroll_region || TS_set_scroll_region_1));
1318 line_ins_del_ok = (((TS_ins_line || TS_ins_multi_lines)
1319 && (TS_del_line || TS_del_multi_lines))
1320 || (scroll_region_ok && TS_fwd_scroll && TS_rev_scroll));
1322 char_ins_del_ok = ((TS_ins_char || TS_insert_mode
1323 || TS_pad_inserted_char || TS_ins_multi_chars)
1324 && (TS_del_char || TS_del_multi_chars));
1326 fast_clear_end_of_line = TS_clr_line != 0;
1328 init_baud_rate ();
1329 if (read_socket_hook) /* Baudrate is somewhat */
1330 /* meaningless in this case */
1331 baud_rate = 9600;
1334 /* VARARGS 1 */
1335 fatal (str, arg1, arg2)
1337 fprintf (stderr, "emacs: ");
1338 fprintf (stderr, str, arg1, arg2);
1339 fflush (stderr);
1340 exit (1);