*** empty log message ***
[emacs.git] / src / term.c
blob103577870208949d7bb9d57699a87fc22ea61d29
1 /* terminal control module for terminals described by TERMCAP
2 Copyright (C) 1985, 1986, 1987, 1992 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 2, 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 "frame.h"
30 #include "disptab.h"
31 #include "termhooks.h"
32 #include "keyboard.h"
34 #define max(a, b) ((a) > (b) ? (a) : (b))
35 #define min(a, b) ((a) < (b) ? (a) : (b))
37 #define OUTPUT(a) tputs (a, FRAME_HEIGHT (selected_frame) - curY, cmputc)
38 #define OUTPUT1(a) tputs (a, 1, cmputc)
39 #define OUTPUTL(a, lines) tputs (a, lines, cmputc)
40 #define OUTPUT_IF(a) { if (a) tputs (a, FRAME_HEIGHT (selected_frame) - curY, cmputc); }
41 #define OUTPUT1_IF(a) { if (a) tputs (a, 1, cmputc); }
43 /* Terminal charateristics that higher levels want to look at.
44 These are all extern'd in termchar.h */
46 int must_write_spaces; /* Nonzero means spaces in the text
47 must actually be output; can't just skip
48 over some columns to leave them blank. */
49 int min_padding_speed; /* Speed below which no padding necessary */
51 int line_ins_del_ok; /* Terminal can insert and delete lines */
52 int char_ins_del_ok; /* Terminal can insert and delete chars */
53 int scroll_region_ok; /* Terminal supports setting the
54 scroll window */
55 int memory_below_frame; /* Terminal remembers lines
56 scrolled off bottom */
57 int fast_clear_end_of_line; /* Terminal has a `ce' string */
59 int dont_calculate_costs; /* Nonzero means don't bother computing */
60 /* various cost tables; we won't use them. */
62 /* Nonzero means no need to redraw the entire frame on resuming
63 a suspended Emacs. This is useful on terminals with multiple pages,
64 where one page is used for Emacs and another for all else. */
65 int no_redraw_on_reenter;
67 /* Hook functions that you can set to snap out the functions in this file.
68 These are all extern'd in termhooks.h */
70 int (*cursor_to_hook) ();
71 int (*raw_cursor_to_hook) ();
73 int (*clear_to_end_hook) ();
74 int (*clear_frame_hook) ();
75 int (*clear_end_of_line_hook) ();
77 int (*ins_del_lines_hook) ();
79 int (*change_line_highlight_hook) ();
80 int (*reassert_line_highlight_hook) ();
82 int (*insert_glyphs_hook) ();
83 int (*write_glyphs_hook) ();
84 int (*delete_glyphs_hook) ();
86 int (*ring_bell_hook) ();
88 int (*reset_terminal_modes_hook) ();
89 int (*set_terminal_modes_hook) ();
90 int (*update_begin_hook) ();
91 int (*update_end_hook) ();
92 int (*set_terminal_window_hook) ();
94 int (*read_socket_hook) ();
96 /* Return the current position of the mouse. This should clear
97 mouse_moved until the next motion event arrives. */
98 void (*mouse_position_hook) ( /* FRAME_PTR *f,
99 Lisp_Object *x,
100 Lisp_Object *y,
101 unsigned long *time */ );
103 /* When reading from a minibuffer in a different frame, Emacs wants
104 to shift the highlight from the selected frame to the minibuffer's
105 frame; under X, this means it lies about where the focus is.
106 This hook tells the window system code to re-decide where to put
107 the highlight. */
108 void (*frame_rehighlight_hook) ( /* FRAME_PTR f */ );
110 /* Strings, numbers and flags taken from the termcap entry. */
112 char *TS_ins_line; /* termcap "al" */
113 char *TS_ins_multi_lines; /* "AL" (one parameter, # lines to insert) */
114 char *TS_bell; /* "bl" */
115 char *TS_clr_to_bottom; /* "cd" */
116 char *TS_clr_line; /* "ce", clear to end of line */
117 char *TS_clr_frame; /* "cl" */
118 char *TS_set_scroll_region; /* "cs" (2 params, first line and last line) */
119 char *TS_set_scroll_region_1; /* "cS" (4 params: total lines,
120 lines above scroll region, lines below it,
121 total lines again) */
122 char *TS_del_char; /* "dc" */
123 char *TS_del_multi_chars; /* "DC" (one parameter, # chars to delete) */
124 char *TS_del_line; /* "dl" */
125 char *TS_del_multi_lines; /* "DL" (one parameter, # lines to delete) */
126 char *TS_delete_mode; /* "dm", enter character-delete mode */
127 char *TS_end_delete_mode; /* "ed", leave character-delete mode */
128 char *TS_end_insert_mode; /* "ei", leave character-insert mode */
129 char *TS_ins_char; /* "ic" */
130 char *TS_ins_multi_chars; /* "IC" (one parameter, # chars to insert) */
131 char *TS_insert_mode; /* "im", enter character-insert mode */
132 char *TS_pad_inserted_char; /* "ip". Just padding, no commands. */
133 char *TS_end_keypad_mode; /* "ke" */
134 char *TS_keypad_mode; /* "ks" */
135 char *TS_pad_char; /* "pc", char to use as padding */
136 char *TS_repeat; /* "rp" (2 params, # times to repeat
137 and character to be repeated) */
138 char *TS_end_standout_mode; /* "se" */
139 char *TS_fwd_scroll; /* "sf" */
140 char *TS_standout_mode; /* "so" */
141 char *TS_rev_scroll; /* "sr" */
142 char *TS_end_termcap_modes; /* "te" */
143 char *TS_termcap_modes; /* "ti" */
144 char *TS_visible_bell; /* "vb" */
145 char *TS_end_visual_mode; /* "ve" */
146 char *TS_visual_mode; /* "vi" */
147 char *TS_set_window; /* "wi" (4 params, start and end of window,
148 each as vpos and hpos) */
150 int TF_hazeltine; /* termcap hz flag. */
151 int TF_insmode_motion; /* termcap mi flag: can move while in insert mode. */
152 int TF_standout_motion; /* termcap mi flag: can move while in standout mode. */
153 int TF_underscore; /* termcap ul flag: _ underlines if overstruck on
154 nonblank position. Must clear before writing _. */
155 int TF_teleray; /* termcap xt flag: many weird consequences.
156 For t1061. */
158 int TF_xs; /* Nonzero for "xs". If set together with
159 TN_standout_width == 0, it means don't bother
160 to write any end-standout cookies. */
162 int TN_standout_width; /* termcap sg number: width occupied by standout
163 markers */
165 static int RPov; /* # chars to start a TS_repeat */
167 static int delete_in_insert_mode; /* delete mode == insert mode */
169 static int se_is_so; /* 1 if same string both enters and leaves
170 standout mode */
172 /* internal state */
174 /* Number of chars of space used for standout marker at beginning of line,
175 or'd with 0100. Zero if no standout marker at all.
177 Used IFF TN_standout_width >= 0. */
179 static char *chars_wasted;
180 static char *copybuf;
182 /* nonzero means supposed to write text in standout mode. */
183 int standout_requested;
185 int insert_mode; /* Nonzero when in insert mode. */
186 int standout_mode; /* Nonzero when in standout mode. */
188 /* Size of window specified by higher levels.
189 This is the number of lines, from the top of frame downwards,
190 which can participate in insert-line/delete-line operations.
192 Effectively it excludes the bottom frame_height - specified_window_size
193 lines from those operations. */
195 int specified_window;
197 /* Frame currently being redisplayed; 0 if not currently redisplaying.
198 (Direct output does not count). */
200 FRAME_PTR updating_frame;
202 char *tparam ();
204 ring_bell ()
206 if (! FRAME_IS_TERMCAP (selected_frame))
208 (*ring_bell_hook) ();
209 return;
211 OUTPUT (TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell);
214 set_terminal_modes ()
216 if (! FRAME_IS_TERMCAP (selected_frame))
218 (*set_terminal_modes_hook) ();
219 return;
221 OUTPUT_IF (TS_termcap_modes);
222 OUTPUT_IF (TS_visual_mode);
223 OUTPUT_IF (TS_keypad_mode);
224 losecursor ();
227 reset_terminal_modes ()
229 if (! FRAME_IS_TERMCAP (selected_frame))
231 (*reset_terminal_modes_hook) ();
232 return;
234 if (TN_standout_width < 0)
235 turn_off_highlight ();
236 turn_off_insert ();
237 OUTPUT_IF (TS_end_keypad_mode);
238 OUTPUT_IF (TS_end_visual_mode);
239 OUTPUT_IF (TS_end_termcap_modes);
240 /* Output raw CR so kernel can track the cursor hpos. */
241 /* But on magic-cookie terminals this can erase an end-standout marker and
242 cause the rest of the frame to be in standout, so move down first. */
243 if (TN_standout_width >= 0)
244 cmputc ('\n');
245 cmputc ('\r');
248 update_begin (f)
249 FRAME_PTR f;
251 updating_frame = f;
252 if (! FRAME_IS_TERMCAP (updating_frame))
253 (*update_begin_hook) (f);
256 update_end (f)
257 FRAME_PTR f;
259 if (! FRAME_IS_TERMCAP (updating_frame))
261 (*update_end_hook) (f);
262 updating_frame = 0;
263 return;
265 turn_off_insert ();
266 background_highlight ();
267 standout_requested = 0;
268 updating_frame = 0;
271 set_terminal_window (size)
272 int size;
274 if (! FRAME_IS_TERMCAP (updating_frame))
276 (*set_terminal_window_hook) (size);
277 return;
279 specified_window = size ? size : FRAME_HEIGHT (selected_frame);
280 if (!scroll_region_ok)
281 return;
282 set_scroll_region (0, specified_window);
285 set_scroll_region (start, stop)
286 int start, stop;
288 char *buf;
289 if (TS_set_scroll_region)
291 buf = tparam (TS_set_scroll_region, 0, 0, start, stop - 1);
293 else if (TS_set_scroll_region_1)
295 buf = tparam (TS_set_scroll_region_1, 0, 0,
296 FRAME_HEIGHT (selected_frame), start,
297 FRAME_HEIGHT (selected_frame) - stop,
298 FRAME_HEIGHT (selected_frame));
300 else
302 buf = tparam (TS_set_window, 0, 0, start, 0, stop, FRAME_WIDTH (selected_frame));
304 OUTPUT (buf);
305 free (buf);
306 losecursor ();
309 turn_on_insert ()
311 if (!insert_mode)
312 OUTPUT (TS_insert_mode);
313 insert_mode = 1;
316 turn_off_insert ()
318 if (insert_mode)
319 OUTPUT (TS_end_insert_mode);
320 insert_mode = 0;
323 /* Handle highlighting when TN_standout_width (termcap sg) is not specified.
324 In these terminals, output is affected by the value of standout
325 mode when the output is written.
327 These functions are called on all terminals, but do nothing
328 on terminals whose standout mode does not work that way. */
330 turn_off_highlight ()
332 if (TN_standout_width < 0)
334 if (standout_mode)
335 OUTPUT_IF (TS_end_standout_mode);
336 standout_mode = 0;
340 turn_on_highlight ()
342 if (TN_standout_width < 0)
344 if (!standout_mode)
345 OUTPUT_IF (TS_standout_mode);
346 standout_mode = 1;
350 /* Set standout mode to the state it should be in for
351 empty space inside windows. What this is,
352 depends on the user option inverse-video. */
354 background_highlight ()
356 if (TN_standout_width >= 0)
357 return;
358 if (inverse_video)
359 turn_on_highlight ();
360 else
361 turn_off_highlight ();
364 /* Set standout mode to the mode specified for the text to be output. */
366 static
367 highlight_if_desired ()
369 if (TN_standout_width >= 0)
370 return;
371 if (!inverse_video == !standout_requested)
372 turn_off_highlight ();
373 else
374 turn_on_highlight ();
377 /* Handle standout mode for terminals in which TN_standout_width >= 0.
378 On these terminals, standout is controlled by markers that
379 live inside the terminal's memory. TN_standout_width is the width
380 that the marker occupies in memory. Standout runs from the marker
381 to the end of the line on some terminals, or to the next
382 turn-off-standout marker (TS_end_standout_mode) string
383 on other terminals. */
385 /* Write a standout marker or end-standout marker at the front of the line
386 at vertical position vpos. */
388 write_standout_marker (flag, vpos)
389 int flag, vpos;
391 if (flag || (TS_end_standout_mode && !TF_teleray && !se_is_so
392 && !(TF_xs && TN_standout_width == 0)))
394 cmgoto (vpos, 0);
395 cmplus (TN_standout_width);
396 OUTPUT (flag ? TS_standout_mode : TS_end_standout_mode);
397 chars_wasted[curY] = TN_standout_width | 0100;
401 /* External interface to control of standout mode.
402 Call this when about to modify line at position VPOS
403 and not change whether it is highlighted. */
405 reassert_line_highlight (highlight, vpos)
406 int highlight;
407 int vpos;
409 if (! FRAME_IS_TERMCAP ((updating_frame ? updating_frame : selected_frame)))
411 (*reassert_line_highlight_hook) (highlight, vpos);
412 return;
414 if (TN_standout_width < 0)
415 /* Handle terminals where standout takes affect at output time */
416 standout_requested = highlight;
417 else if (chars_wasted[vpos] == 0)
418 /* For terminals with standout markers, write one on this line
419 if there isn't one already. */
420 write_standout_marker (highlight, vpos);
423 /* Call this when about to modify line at position VPOS
424 and change whether it is highlighted. */
426 change_line_highlight (new_highlight, vpos, first_unused_hpos)
427 int new_highlight, vpos, first_unused_hpos;
429 standout_requested = new_highlight;
430 if (! FRAME_IS_TERMCAP (updating_frame))
432 (*change_line_highlight_hook) (new_highlight, vpos, first_unused_hpos);
433 return;
436 cursor_to (vpos, 0);
438 if (TN_standout_width < 0)
439 background_highlight ();
440 /* If line starts with a marker, delete the marker */
441 else if (TS_clr_line && chars_wasted[curY])
443 turn_off_insert ();
444 /* On Teleray, make sure to erase the SO marker. */
445 if (TF_teleray)
447 cmgoto (curY - 1, FRAME_WIDTH (selected_frame) - 4);
448 OUTPUT ("\033S");
449 curY++; /* ESC S moves to next line where the TS_standout_mode was */
450 curX = 0;
452 else
453 cmgoto (curY, 0); /* reposition to kill standout marker */
455 clear_end_of_line_raw (first_unused_hpos);
456 reassert_line_highlight (new_highlight, curY);
460 /* Move to absolute position, specified origin 0 */
462 cursor_to (row, col)
463 int row, col;
465 if (! FRAME_IS_TERMCAP ((updating_frame
466 ? updating_frame
467 : selected_frame))
468 && cursor_to_hook)
470 (*cursor_to_hook) (row, col);
471 return;
474 col += chars_wasted[row] & 077;
475 if (curY == row && curX == col)
476 return;
477 if (!TF_standout_motion)
478 background_highlight ();
479 if (!TF_insmode_motion)
480 turn_off_insert ();
481 cmgoto (row, col);
484 /* Similar but don't take any account of the wasted characters. */
486 raw_cursor_to (row, col)
487 int row, col;
489 if (! FRAME_IS_TERMCAP ((updating_frame ? updating_frame : selected_frame)))
491 (*raw_cursor_to_hook) (row, col);
492 return;
494 if (curY == row && curX == col)
495 return;
496 if (!TF_standout_motion)
497 background_highlight ();
498 if (!TF_insmode_motion)
499 turn_off_insert ();
500 cmgoto (row, col);
503 /* Erase operations */
505 /* clear from cursor to end of frame */
506 clear_to_end ()
508 register int i;
510 if (clear_to_end_hook && FRAME_IS_TERMCAP (updating_frame))
512 (*clear_to_end_hook) ();
513 return;
515 if (TS_clr_to_bottom)
517 background_highlight ();
518 OUTPUT (TS_clr_to_bottom);
519 bzero (chars_wasted + curY, FRAME_HEIGHT (selected_frame) - curY);
521 else
523 for (i = curY; i < FRAME_HEIGHT (selected_frame); i++)
525 cursor_to (i, 0);
526 clear_end_of_line_raw (FRAME_WIDTH (selected_frame));
531 /* Clear entire frame */
533 clear_frame ()
535 if (clear_frame_hook
536 && ! FRAME_IS_TERMCAP ((updating_frame ? updating_frame : selected_frame)))
538 (*clear_frame_hook) ();
539 return;
541 if (TS_clr_frame)
543 background_highlight ();
544 OUTPUT (TS_clr_frame);
545 bzero (chars_wasted, FRAME_HEIGHT (selected_frame));
546 cmat (0, 0);
548 else
550 cursor_to (0, 0);
551 clear_to_end ();
555 /* Clear to end of line, but do not clear any standout marker.
556 Assumes that the cursor is positioned at a character of real text,
557 which implies it cannot be before a standout marker
558 unless the marker has zero width.
560 Note that the cursor may be moved. */
562 clear_end_of_line (first_unused_hpos)
563 int first_unused_hpos;
565 static GLYPH buf[1] = {SPACEGLYPH};
566 if (FRAME_IS_TERMCAP (selected_frame)
567 && TN_standout_width == 0 && curX == 0 && chars_wasted[curY] != 0)
568 write_glyphs (buf, 1);
569 clear_end_of_line_raw (first_unused_hpos);
572 /* Clear from cursor to end of line.
573 Assume that the line is already clear starting at column first_unused_hpos.
574 If the cursor is at a standout marker, erase the marker.
576 Note that the cursor may be moved, on terminals lacking a `ce' string. */
578 clear_end_of_line_raw (first_unused_hpos)
579 int first_unused_hpos;
581 register int i;
583 if (clear_end_of_line_hook
584 && ! FRAME_IS_TERMCAP ((updating_frame
585 ? updating_frame
586 : selected_frame)))
588 (*clear_end_of_line_hook) (first_unused_hpos);
589 return;
592 first_unused_hpos += chars_wasted[curY] & 077;
593 if (curX >= first_unused_hpos)
594 return;
595 /* Notice if we are erasing a magic cookie */
596 if (curX == 0)
597 chars_wasted[curY] = 0;
598 background_highlight ();
599 if (TS_clr_line)
601 OUTPUT1 (TS_clr_line);
603 else
604 { /* have to do it the hard way */
605 turn_off_insert ();
607 /* Do not write in last row last col with Autowrap on. */
608 if (AutoWrap && curY == FRAME_HEIGHT (selected_frame) - 1
609 && first_unused_hpos == FRAME_WIDTH (selected_frame))
610 first_unused_hpos--;
612 for (i = curX; i < first_unused_hpos; i++)
614 if (termscript)
615 fputc (' ', termscript);
616 putchar (' ');
618 cmplus (first_unused_hpos - curX);
623 write_glyphs (string, len)
624 register GLYPH *string;
625 register int len;
627 register GLYPH g;
628 register int tlen = GLYPH_TABLE_LENGTH;
629 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
631 if (write_glyphs_hook
632 && ! FRAME_IS_TERMCAP ((updating_frame ? updating_frame : selected_frame)))
634 (*write_glyphs_hook) (string, len);
635 return;
638 highlight_if_desired ();
639 turn_off_insert ();
641 /* Don't dare write in last column of bottom line, if AutoWrap,
642 since that would scroll the whole frame on some terminals. */
644 if (AutoWrap
645 && curY + 1 == FRAME_HEIGHT (selected_frame)
646 && (curX + len - (chars_wasted[curY] & 077)
647 == FRAME_WIDTH (selected_frame)))
648 len --;
650 cmplus (len);
651 while (--len >= 0)
653 g = *string++;
654 /* Check quickly for G beyond length of table.
655 That implies it isn't an alias and is simple. */
656 if (g >= tlen)
658 simple:
659 putc (g & 0xff, stdout);
660 if (ferror (stdout))
661 clearerr (stdout);
662 if (termscript)
663 putc (g & 0xff, termscript);
665 else
667 /* G has an entry in Vglyph_table,
668 so process any alias and then test for simpleness. */
669 while (GLYPH_ALIAS_P (tbase, tlen, g))
670 g = GLYPH_ALIAS (tbase, g);
671 if (GLYPH_SIMPLE_P (tbase, tlen, g))
672 goto simple;
673 else
675 /* Here if G (or its definition as an alias) is not simple. */
676 fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g),
677 stdout);
678 if (ferror (stdout))
679 clearerr (stdout);
680 if (termscript)
681 fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g),
682 termscript);
688 /* If start is zero, insert blanks instead of a string at start */
690 insert_glyphs (start, len)
691 register GLYPH *start;
692 register int len;
694 char *buf;
695 register GLYPH g;
696 register int tlen = GLYPH_TABLE_LENGTH;
697 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
699 if (insert_glyphs_hook && ! FRAME_IS_TERMCAP (updating_frame))
701 (*insert_glyphs_hook) (start, len);
702 return;
704 highlight_if_desired ();
706 if (TS_ins_multi_chars)
708 buf = tparam (TS_ins_multi_chars, 0, 0, len);
709 OUTPUT1 (buf);
710 free (buf);
711 if (start)
712 write_glyphs (start, len);
713 return;
716 turn_on_insert ();
717 cmplus (len);
718 while (--len >= 0)
720 OUTPUT1_IF (TS_ins_char);
721 if (!start)
722 g = SPACEGLYPH;
723 else
724 g = *start++;
726 if (GLYPH_SIMPLE_P (tbase, tlen, g))
728 putc (g & 0xff, stdout);
729 if (ferror (stdout))
730 clearerr (stdout);
731 if (termscript)
732 putc (g & 0xff, termscript);
734 else
736 fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g), stdout);
737 if (ferror (stdout))
738 clearerr (stdout);
739 if (termscript)
740 fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g),
741 termscript);
744 OUTPUT1_IF (TS_pad_inserted_char);
748 delete_glyphs (n)
749 register int n;
751 char *buf;
752 register int i;
754 if (delete_glyphs_hook && ! FRAME_IS_TERMCAP (updating_frame))
756 (*delete_glyphs_hook) (n);
757 return;
760 if (delete_in_insert_mode)
762 turn_on_insert ();
764 else
766 turn_off_insert ();
767 OUTPUT_IF (TS_delete_mode);
770 if (TS_del_multi_chars)
772 buf = tparam (TS_del_multi_chars, 0, 0, n);
773 OUTPUT1 (buf);
774 free (buf);
776 else
777 for (i = 0; i < n; i++)
778 OUTPUT1 (TS_del_char);
779 if (!delete_in_insert_mode)
780 OUTPUT_IF (TS_end_delete_mode);
783 /* Insert N lines at vpos VPOS. If N is negative, delete -N lines. */
785 ins_del_lines (vpos, n)
786 int vpos, n;
788 char *multi = n > 0 ? TS_ins_multi_lines : TS_del_multi_lines;
789 char *single = n > 0 ? TS_ins_line : TS_del_line;
790 char *scroll = n > 0 ? TS_rev_scroll : TS_fwd_scroll;
792 register int i = n > 0 ? n : -n;
793 register char *buf;
795 if (ins_del_lines_hook && ! FRAME_IS_TERMCAP (updating_frame))
797 (*ins_del_lines_hook) (vpos, n);
798 return;
801 /* If the lines below the insertion are being pushed
802 into the end of the window, this is the same as clearing;
803 and we know the lines are already clear, since the matching
804 deletion has already been done. So can ignore this. */
805 /* If the lines below the deletion are blank lines coming
806 out of the end of the window, don't bother,
807 as there will be a matching inslines later that will flush them. */
808 if (scroll_region_ok && vpos + i >= specified_window)
809 return;
810 if (!memory_below_frame && vpos + i >= FRAME_HEIGHT (selected_frame))
811 return;
813 if (multi)
815 raw_cursor_to (vpos, 0);
816 background_highlight ();
817 buf = tparam (multi, 0, 0, i);
818 OUTPUT (buf);
819 free (buf);
821 else if (single)
823 raw_cursor_to (vpos, 0);
824 background_highlight ();
825 while (--i >= 0)
826 OUTPUT (single);
827 if (TF_teleray)
828 curX = 0;
830 else
832 set_scroll_region (vpos, specified_window);
833 if (n < 0)
834 raw_cursor_to (specified_window - 1, 0);
835 else
836 raw_cursor_to (vpos, 0);
837 background_highlight ();
838 while (--i >= 0)
839 OUTPUTL (scroll, specified_window - vpos);
840 set_scroll_region (0, specified_window);
843 if (TN_standout_width >= 0)
845 register lower_limit
846 = (scroll_region_ok
847 ? specified_window
848 : FRAME_HEIGHT (selected_frame));
850 if (n < 0)
852 bcopy (&chars_wasted[vpos - n], &chars_wasted[vpos],
853 lower_limit - vpos + n);
854 bzero (&chars_wasted[lower_limit + n], - n);
856 else
858 bcopy (&chars_wasted[vpos], &copybuf[vpos], lower_limit - vpos - n);
859 bcopy (&copybuf[vpos], &chars_wasted[vpos + n],
860 lower_limit - vpos - n);
861 bzero (&chars_wasted[vpos], n);
864 if (!scroll_region_ok && memory_below_frame && n < 0)
866 cursor_to (FRAME_HEIGHT (selected_frame) + n, 0);
867 clear_to_end ();
871 /* Compute cost of sending "str", in characters,
872 not counting any line-dependent padding. */
875 string_cost (str)
876 char *str;
878 cost = 0;
879 if (str)
880 tputs (str, 0, evalcost);
881 return cost;
884 /* Compute cost of sending "str", in characters,
885 counting any line-dependent padding at one line. */
887 static int
888 string_cost_one_line (str)
889 char *str;
891 cost = 0;
892 if (str)
893 tputs (str, 1, evalcost);
894 return cost;
897 /* Compute per line amount of line-dependent padding,
898 in tenths of characters. */
901 per_line_cost (str)
902 register char *str;
904 cost = 0;
905 if (str)
906 tputs (str, 0, evalcost);
907 cost = - cost;
908 if (str)
909 tputs (str, 10, evalcost);
910 return cost;
913 #ifndef old
914 /* char_ins_del_cost[n] is cost of inserting N characters.
915 char_ins_del_cost[-n] is cost of deleting N characters. */
917 int *char_ins_del_vector;
919 #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_WIDTH ((f))])
920 #endif
922 /* ARGSUSED */
923 static void
924 calculate_ins_del_char_costs (frame)
925 FRAME_PTR frame;
927 int ins_startup_cost, del_startup_cost;
928 int ins_cost_per_char, del_cost_per_char;
929 register int i;
930 register int *p;
932 if (TS_ins_multi_chars)
934 ins_cost_per_char = 0;
935 ins_startup_cost = string_cost_one_line (TS_ins_multi_chars);
937 else if (TS_ins_char || TS_pad_inserted_char
938 || (TS_insert_mode && TS_end_insert_mode))
940 ins_startup_cost = (30 * (string_cost (TS_insert_mode)
941 + string_cost (TS_end_insert_mode))) / 100;
942 ins_cost_per_char = (string_cost_one_line (TS_ins_char)
943 + string_cost_one_line (TS_pad_inserted_char));
945 else
947 ins_startup_cost = 9999;
948 ins_cost_per_char = 0;
951 if (TS_del_multi_chars)
953 del_cost_per_char = 0;
954 del_startup_cost = string_cost_one_line (TS_del_multi_chars);
956 else if (TS_del_char)
958 del_startup_cost = (string_cost (TS_delete_mode)
959 + string_cost (TS_end_delete_mode));
960 if (delete_in_insert_mode)
961 del_startup_cost /= 2;
962 del_cost_per_char = string_cost_one_line (TS_del_char);
964 else
966 del_startup_cost = 9999;
967 del_cost_per_char = 0;
970 /* Delete costs are at negative offsets */
971 p = &char_ins_del_cost (frame)[0];
972 for (i = FRAME_WIDTH (selected_frame); --i >= 0;)
973 *--p = (del_startup_cost += del_cost_per_char);
975 /* Doing nothing is free */
976 p = &char_ins_del_cost (frame)[0];
977 *p++ = 0;
979 /* Insert costs are at positive offsets */
980 for (i = FRAME_WIDTH (frame); --i >= 0;)
981 *p++ = (ins_startup_cost += ins_cost_per_char);
984 #ifdef HAVE_X_WINDOWS
985 extern int x_screen_planes;
986 #endif
988 calculate_costs (frame)
989 FRAME_PTR frame;
991 register char *f = TS_set_scroll_region ?
992 TS_set_scroll_region
993 : TS_set_scroll_region_1;
995 if (dont_calculate_costs)
996 return;
998 #ifdef HAVE_X_WINDOWS
999 if (FRAME_IS_X (frame))
1001 do_line_insertion_deletion_costs (frame, 0, ".5*", 0, ".5*",
1002 0, 0, x_screen_planes);
1003 return;
1005 #endif
1007 /* These variables are only used for terminal stuff. They are allocated
1008 once for the terminal frame of X-windows emacs, but not used afterwards.
1010 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1011 X turns off char_ins_del_ok.
1013 chars_wasted and copybuf are only used here in term.c in cases where
1014 the term hook isn't called. */
1016 if (chars_wasted != 0)
1017 chars_wasted = (char *) xrealloc (chars_wasted, FRAME_HEIGHT (frame));
1018 else
1019 chars_wasted = (char *) xmalloc (FRAME_HEIGHT (frame));
1021 if (copybuf != 0)
1022 copybuf = (char *) xrealloc (copybuf, FRAME_HEIGHT (frame));
1023 else
1024 copybuf = (char *) xmalloc (FRAME_HEIGHT (frame));
1026 if (char_ins_del_vector != 0)
1027 char_ins_del_vector
1028 = (int *) xrealloc (char_ins_del_vector,
1029 (sizeof (int)
1030 + 2 * FRAME_WIDTH (frame) * sizeof (int)));
1031 else
1032 char_ins_del_vector
1033 = (int *) xmalloc (sizeof (int)
1034 + 2 * FRAME_WIDTH (frame) * sizeof (int));
1036 bzero (chars_wasted, FRAME_HEIGHT (frame));
1037 bzero (copybuf, FRAME_HEIGHT (frame));
1038 bzero (char_ins_del_vector, (sizeof (int)
1039 + 2 * FRAME_WIDTH (frame) * sizeof (int)));
1041 if (f && (!TS_ins_line && !TS_del_line))
1042 do_line_insertion_deletion_costs (frame,
1043 TS_rev_scroll, TS_ins_multi_lines,
1044 TS_fwd_scroll, TS_del_multi_lines,
1045 f, f, 1);
1046 else
1047 do_line_insertion_deletion_costs (frame,
1048 TS_ins_line, TS_ins_multi_lines,
1049 TS_del_line, TS_del_multi_lines,
1050 0, 0, 1);
1052 calculate_ins_del_char_costs (frame);
1054 /* Don't use TS_repeat if its padding is worse than sending the chars */
1055 if (TS_repeat && per_line_cost (TS_repeat) * baud_rate < 9000)
1056 RPov = string_cost (TS_repeat);
1057 else
1058 RPov = FRAME_WIDTH (frame) * 2;
1060 cmcostinit (); /* set up cursor motion costs */
1063 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1064 This function scans the termcap function key sequence entries, and
1065 adds entries to Vfunction_key_map for each function key it finds. */
1067 void
1068 term_get_fkeys (address)
1069 char **address;
1071 extern char *tgetstr ();
1072 struct fkey_table {
1073 char *cap, *name;
1075 static struct fkey_table keys[] = {
1076 "kl", "left",
1077 "kr", "right",
1078 "ku", "up",
1079 "kd", "down",
1080 "kh", "home",
1081 "k1", "f1",
1082 "k2", "f2",
1083 "k3", "f3",
1084 "k4", "f4",
1085 "k5", "f5",
1086 "k6", "f6",
1087 "k7", "f7",
1088 "k8", "f8",
1089 "k9", "f9",
1090 "k0", "f10",
1091 "kH", "home-down",
1092 "ka", "clear-tabs",
1093 "kt", "clear-tab",
1094 "kT", "set-tab",
1095 "kC", "clear",
1096 "kL", "deleteline",
1097 "kM", "exit-insert",
1098 "kE", "clear-eol",
1099 "kS", "clear-eos",
1100 "kI", "insert",
1101 "kA", "insertline",
1102 "kN", "next",
1103 "kP", "prior",
1104 "kF", "scroll-forward",
1105 "kR", "scroll-reverse"
1107 int i;
1109 for (i = 0; i < (sizeof (keys)/sizeof (keys[0])); i++)
1111 char *sequence = tgetstr (keys[i].cap, address);
1112 if (sequence)
1113 Fdefine_key (Vfunction_key_map,
1114 build_string (sequence),
1115 Fmake_vector (make_number (1), intern (keys[i].name)));
1120 term_init (terminal_type)
1121 char *terminal_type;
1123 char *area;
1124 char **address = &area;
1125 char buffer[2044];
1126 register char *p;
1127 int status;
1129 extern char *tgetstr ();
1131 Wcm_clear ();
1132 dont_calculate_costs = 0;
1134 status = tgetent (buffer, terminal_type);
1135 if (status < 0)
1136 fatal ("Cannot open termcap database file.\n");
1137 if (status == 0)
1138 fatal ("Terminal type %s is not defined.\n", terminal_type);
1140 #ifdef TERMINFO
1141 area = (char *) malloc (2044);
1142 #else
1143 area = (char *) malloc (strlen (buffer));
1144 #endif /* not TERMINFO */
1145 if (area == 0)
1146 abort ();
1148 TS_ins_line = tgetstr ("al", address);
1149 TS_ins_multi_lines = tgetstr ("AL", address);
1150 TS_bell = tgetstr ("bl", address);
1151 BackTab = tgetstr ("bt", address);
1152 TS_clr_to_bottom = tgetstr ("cd", address);
1153 TS_clr_line = tgetstr ("ce", address);
1154 TS_clr_frame = tgetstr ("cl", address);
1155 ColPosition = tgetstr ("ch", address);
1156 AbsPosition = tgetstr ("cm", address);
1157 CR = tgetstr ("cr", address);
1158 TS_set_scroll_region = tgetstr ("cs", address);
1159 TS_set_scroll_region_1 = tgetstr ("cS", address);
1160 RowPosition = tgetstr ("cv", address);
1161 TS_del_char = tgetstr ("dc", address);
1162 TS_del_multi_chars = tgetstr ("DC", address);
1163 TS_del_line = tgetstr ("dl", address);
1164 TS_del_multi_lines = tgetstr ("DL", address);
1165 TS_delete_mode = tgetstr ("dm", address);
1166 TS_end_delete_mode = tgetstr ("ed", address);
1167 TS_end_insert_mode = tgetstr ("ei", address);
1168 Home = tgetstr ("ho", address);
1169 TS_ins_char = tgetstr ("ic", address);
1170 TS_ins_multi_chars = tgetstr ("IC", address);
1171 TS_insert_mode = tgetstr ("im", address);
1172 TS_pad_inserted_char = tgetstr ("ip", address);
1173 TS_end_keypad_mode = tgetstr ("ke", address);
1174 TS_keypad_mode = tgetstr ("ks", address);
1175 LastLine = tgetstr ("ll", address);
1176 Right = tgetstr ("nd", address);
1177 Down = tgetstr ("do", address);
1178 if (!Down)
1179 Down = tgetstr ("nl", address); /* Obsolete name for "do" */
1180 #ifdef VMS
1181 /* VMS puts a carriage return before each linefeed,
1182 so it is not safe to use linefeeds. */
1183 if (Down && Down[0] == '\n' && Down[1] == '\0')
1184 Down = 0;
1185 #endif /* VMS */
1186 if (tgetflag ("bs"))
1187 Left = "\b"; /* can't possibly be longer! */
1188 else /* (Actually, "bs" is obsolete...) */
1189 Left = tgetstr ("le", address);
1190 if (!Left)
1191 Left = tgetstr ("bc", address); /* Obsolete name for "le" */
1192 TS_pad_char = tgetstr ("pc", address);
1193 TS_repeat = tgetstr ("rp", address);
1194 TS_end_standout_mode = tgetstr ("se", address);
1195 TS_fwd_scroll = tgetstr ("sf", address);
1196 TS_standout_mode = tgetstr ("so", address);
1197 TS_rev_scroll = tgetstr ("sr", address);
1198 Wcm.cm_tab = tgetstr ("ta", address);
1199 TS_end_termcap_modes = tgetstr ("te", address);
1200 TS_termcap_modes = tgetstr ("ti", address);
1201 Up = tgetstr ("up", address);
1202 TS_visible_bell = tgetstr ("vb", address);
1203 TS_end_visual_mode = tgetstr ("ve", address);
1204 TS_visual_mode = tgetstr ("vs", address);
1205 TS_set_window = tgetstr ("wi", address);
1206 MultiUp = tgetstr ("UP", address);
1207 MultiDown = tgetstr ("DO", address);
1208 MultiLeft = tgetstr ("LE", address);
1209 MultiRight = tgetstr ("RI", address);
1211 AutoWrap = tgetflag ("am");
1212 memory_below_frame = tgetflag ("db");
1213 TF_hazeltine = tgetflag ("hz");
1214 must_write_spaces = tgetflag ("in");
1215 meta_key = tgetflag ("km") || tgetflag ("MT");
1216 TF_insmode_motion = tgetflag ("mi");
1217 TF_standout_motion = tgetflag ("ms");
1218 TF_underscore = tgetflag ("ul");
1219 MagicWrap = tgetflag ("xn");
1220 TF_xs = tgetflag ("xs");
1221 TF_teleray = tgetflag ("xt");
1223 term_get_fkeys (address);
1225 /* Get frame size from system, or else from termcap. */
1226 get_frame_size (&FRAME_WIDTH (selected_frame),
1227 &FRAME_HEIGHT (selected_frame));
1228 if (FRAME_WIDTH (selected_frame) <= 0)
1229 FRAME_WIDTH (selected_frame) = tgetnum ("co");
1230 if (FRAME_HEIGHT (selected_frame) <= 0)
1231 FRAME_HEIGHT (selected_frame) = tgetnum ("li");
1233 min_padding_speed = tgetnum ("pb");
1234 TN_standout_width = tgetnum ("sg");
1235 TabWidth = tgetnum ("tw");
1237 #ifdef VMS
1238 /* These capabilities commonly use ^J.
1239 I don't know why, but sending them on VMS does not work;
1240 it causes following spaces to be lost, sometimes.
1241 For now, the simplest fix is to avoid using these capabilities ever. */
1242 if (Down && Down[0] == '\n')
1243 Down = 0;
1244 #endif /* VMS */
1246 if (!TS_bell)
1247 TS_bell = "\07";
1249 if (!TS_fwd_scroll)
1250 TS_fwd_scroll = Down;
1252 PC = TS_pad_char ? *TS_pad_char : 0;
1254 if (TabWidth < 0)
1255 TabWidth = 8;
1257 /* Turned off since /etc/termcap seems to have :ta= for most terminals
1258 and newer termcap doc does not seem to say there is a default.
1259 if (!Wcm.cm_tab)
1260 Wcm.cm_tab = "\t";
1263 if (TS_standout_mode == 0)
1265 TN_standout_width = tgetnum ("ug");
1266 TS_end_standout_mode = tgetstr ("ue", address);
1267 TS_standout_mode = tgetstr ("us", address);
1270 if (TF_teleray)
1272 Wcm.cm_tab = 0;
1273 /* Teleray: most programs want a space in front of TS_standout_mode,
1274 but Emacs can do without it (and give one extra column). */
1275 TS_standout_mode = "\033RD";
1276 TN_standout_width = 1;
1277 /* But that means we cannot rely on ^M to go to column zero! */
1278 CR = 0;
1279 /* LF can't be trusted either -- can alter hpos */
1280 /* if move at column 0 thru a line with TS_standout_mode */
1281 Down = 0;
1284 /* Special handling for certain terminal types known to need it */
1286 if (!strcmp (terminal_type, "supdup"))
1288 memory_below_frame = 1;
1289 Wcm.cm_losewrap = 1;
1291 if (!strncmp (terminal_type, "c10", 3)
1292 || !strcmp (terminal_type, "perq"))
1294 /* Supply a makeshift :wi string.
1295 This string is not valid in general since it works only
1296 for windows starting at the upper left corner;
1297 but that is all Emacs uses.
1299 This string works only if the frame is using
1300 the top of the video memory, because addressing is memory-relative.
1301 So first check the :ti string to see if that is true.
1303 It would be simpler if the :wi string could go in the termcap
1304 entry, but it can't because it is not fully valid.
1305 If it were in the termcap entry, it would confuse other programs. */
1306 if (!TS_set_window)
1308 p = TS_termcap_modes;
1309 while (*p && strcmp (p, "\033v "))
1310 p++;
1311 if (*p)
1312 TS_set_window = "\033v%C %C %C %C ";
1314 /* Termcap entry often fails to have :in: flag */
1315 must_write_spaces = 1;
1316 /* :ti string typically fails to have \E^G! in it */
1317 /* This limits scope of insert-char to one line. */
1318 strcpy (area, TS_termcap_modes);
1319 strcat (area, "\033\007!");
1320 TS_termcap_modes = area;
1321 area += strlen (area) + 1;
1322 p = AbsPosition;
1323 /* Change all %+ parameters to %C, to handle
1324 values above 96 correctly for the C100. */
1325 while (*p)
1327 if (p[0] == '%' && p[1] == '+')
1328 p[1] = 'C';
1329 p++;
1333 FrameRows = FRAME_HEIGHT (selected_frame);
1334 FrameCols = FRAME_WIDTH (selected_frame);
1335 specified_window = FRAME_HEIGHT (selected_frame);
1337 if (Wcm_init () == -1) /* can't do cursor motion */
1338 #ifdef VMS
1339 fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
1340 It lacks the ability to position the cursor.\n\
1341 If that is not the actual type of terminal you have, use either the\n\
1342 DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\
1343 or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.\n",
1344 terminal_type);
1345 #else
1346 fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
1347 It lacks the ability to position the cursor.\n\
1348 If that is not the actual type of terminal you have,\n\
1349 use the C-shell command `setenv TERM ...' to specify the correct type.\n\
1350 It may be necessary to do `unsetenv TERMCAP' as well.\n",
1351 terminal_type);
1352 #endif
1353 if (FRAME_HEIGHT (selected_frame) <= 0
1354 || FRAME_WIDTH (selected_frame) <= 0)
1355 fatal ("The frame size has not been specified.");
1357 delete_in_insert_mode
1358 = TS_delete_mode && TS_insert_mode
1359 && !strcmp (TS_delete_mode, TS_insert_mode);
1361 se_is_so = (TS_standout_mode
1362 && TS_end_standout_mode
1363 && !strcmp (TS_standout_mode, TS_end_standout_mode));
1365 /* Remove width of standout marker from usable width of line */
1366 if (TN_standout_width > 0)
1367 FRAME_WIDTH (selected_frame) -= TN_standout_width;
1369 UseTabs = tabs_safe_p () && TabWidth == 8;
1371 scroll_region_ok
1372 = (Wcm.cm_abs
1373 && (TS_set_window || TS_set_scroll_region || TS_set_scroll_region_1));
1375 line_ins_del_ok = (((TS_ins_line || TS_ins_multi_lines)
1376 && (TS_del_line || TS_del_multi_lines))
1377 || (scroll_region_ok && TS_fwd_scroll && TS_rev_scroll));
1379 char_ins_del_ok = ((TS_ins_char || TS_insert_mode
1380 || TS_pad_inserted_char || TS_ins_multi_chars)
1381 && (TS_del_char || TS_del_multi_chars));
1383 fast_clear_end_of_line = TS_clr_line != 0;
1385 init_baud_rate ();
1386 if (read_socket_hook) /* Baudrate is somewhat */
1387 /* meaningless in this case */
1388 baud_rate = 9600;
1391 /* VARARGS 1 */
1392 fatal (str, arg1, arg2)
1393 char *str, *arg1, *arg2;
1395 fprintf (stderr, "emacs: ");
1396 fprintf (stderr, str, arg1, arg2);
1397 fflush (stderr);
1398 exit (1);