*** empty log message ***
[bpt/emacs.git] / src / term.c
CommitLineData
08a24c47 1/* terminal control module for terminals described by TERMCAP
4746118a 2 Copyright (C) 1985, 1986, 1987, 1992 Free Software Foundation, Inc.
08a24c47
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
4746118a 8the Free Software Foundation; either version 2, or (at your option)
08a24c47
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
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"
5c2c7893 32#include "keyboard.h"
08a24c47
JB
33
34#define max(a, b) ((a) > (b) ? (a) : (b))
35#define min(a, b) ((a) < (b) ? (a) : (b))
36
37#define OUTPUT(a) tputs (a, SCREEN_HEIGHT (selected_screen) - 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, SCREEN_HEIGHT (selected_screen) - curY, cmputc); }
41#define OUTPUT1_IF(a) { if (a) tputs (a, 1, cmputc); }
42
43/* Terminal charateristics that higher levels want to look at.
44 These are all extern'd in termchar.h */
45
08a24c47
JB
46int 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. */
49int min_padding_speed; /* Speed below which no padding necessary */
50
51int line_ins_del_ok; /* Terminal can insert and delete lines */
52int char_ins_del_ok; /* Terminal can insert and delete chars */
53int scroll_region_ok; /* Terminal supports setting the
54 scroll window */
55int memory_below_screen; /* Terminal remembers lines
56 scrolled off bottom */
57int fast_clear_end_of_line; /* Terminal has a `ce' string */
58
59int dont_calculate_costs; /* Nonzero means don't bother computing */
60 /* various cost tables; we won't use them. */
61
62/* Nonzero means no need to redraw the entire screen 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. */
65int no_redraw_on_reenter;
66
67/* Hook functions that you can set to snap out the functions in this file.
68 These are all extern'd in termhooks.h */
69
70int (*cursor_to_hook) ();
71int (*raw_cursor_to_hook) ();
72
73int (*clear_to_end_hook) ();
74int (*clear_screen_hook) ();
75int (*clear_end_of_line_hook) ();
76
77int (*ins_del_lines_hook) ();
78
79int (*change_line_highlight_hook) ();
80int (*reassert_line_highlight_hook) ();
81
82int (*insert_glyphs_hook) ();
83int (*write_glyphs_hook) ();
84int (*delete_glyphs_hook) ();
85
86int (*ring_bell_hook) ();
87
88int (*reset_terminal_modes_hook) ();
89int (*set_terminal_modes_hook) ();
90int (*update_begin_hook) ();
91int (*update_end_hook) ();
92int (*set_terminal_window_hook) ();
93
94int (*read_socket_hook) ();
95
69a46d1c
JB
96/* Return the current position of the mouse. This should clear
97 mouse_moved until the next motion event arrives. */
98void (*mouse_position_hook) ( /* SCREEN_PTR *s,
99 Lisp_Object *x,
100 Lisp_Object *y,
e5d77022 101 unsigned long *time */ );
08a24c47 102
2e146aa4
JB
103/* When reading from a minibuffer in a different screen, Emacs wants
104 to shift the highlight from the selected screen to the minibuffer's
105 screen; 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. */
fcb764df 108void (*screen_rehighlight_hook) ( /* SCREEN_PTR s */ );
2e146aa4 109
08a24c47
JB
110/* Strings, numbers and flags taken from the termcap entry. */
111
112char *TS_ins_line; /* termcap "al" */
113char *TS_ins_multi_lines; /* "AL" (one parameter, # lines to insert) */
114char *TS_bell; /* "bl" */
115char *TS_clr_to_bottom; /* "cd" */
116char *TS_clr_line; /* "ce", clear to end of line */
117char *TS_clr_screen; /* "cl" */
118char *TS_set_scroll_region; /* "cs" (2 params, first line and last line) */
119char *TS_set_scroll_region_1; /* "cS" (4 params: total lines,
120 lines above scroll region, lines below it,
121 total lines again) */
122char *TS_del_char; /* "dc" */
123char *TS_del_multi_chars; /* "DC" (one parameter, # chars to delete) */
124char *TS_del_line; /* "dl" */
125char *TS_del_multi_lines; /* "DL" (one parameter, # lines to delete) */
126char *TS_delete_mode; /* "dm", enter character-delete mode */
127char *TS_end_delete_mode; /* "ed", leave character-delete mode */
128char *TS_end_insert_mode; /* "ei", leave character-insert mode */
129char *TS_ins_char; /* "ic" */
130char *TS_ins_multi_chars; /* "IC" (one parameter, # chars to insert) */
131char *TS_insert_mode; /* "im", enter character-insert mode */
132char *TS_pad_inserted_char; /* "ip". Just padding, no commands. */
133char *TS_end_keypad_mode; /* "ke" */
134char *TS_keypad_mode; /* "ks" */
135char *TS_pad_char; /* "pc", char to use as padding */
136char *TS_repeat; /* "rp" (2 params, # times to repeat
137 and character to be repeated) */
138char *TS_end_standout_mode; /* "se" */
139char *TS_fwd_scroll; /* "sf" */
140char *TS_standout_mode; /* "so" */
141char *TS_rev_scroll; /* "sr" */
142char *TS_end_termcap_modes; /* "te" */
143char *TS_termcap_modes; /* "ti" */
144char *TS_visible_bell; /* "vb" */
145char *TS_end_visual_mode; /* "ve" */
146char *TS_visual_mode; /* "vi" */
147char *TS_set_window; /* "wi" (4 params, start and end of window,
148 each as vpos and hpos) */
149
150int TF_hazeltine; /* termcap hz flag. */
151int TF_insmode_motion; /* termcap mi flag: can move while in insert mode. */
152int TF_standout_motion; /* termcap mi flag: can move while in standout mode. */
153int TF_underscore; /* termcap ul flag: _ underlines if overstruck on
154 nonblank position. Must clear before writing _. */
155int TF_teleray; /* termcap xt flag: many weird consequences.
156 For t1061. */
157
158int 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. */
161
162int TN_standout_width; /* termcap sg number: width occupied by standout
163 markers */
164
165static int RPov; /* # chars to start a TS_repeat */
166
167static int delete_in_insert_mode; /* delete mode == insert mode */
168
169static int se_is_so; /* 1 if same string both enters and leaves
170 standout mode */
171
172/* internal state */
173
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.
176
177 Used IFF TN_standout_width >= 0. */
178
179static char *chars_wasted;
180static char *copybuf;
181
182/* nonzero means supposed to write text in standout mode. */
183int standout_requested;
184
185int insert_mode; /* Nonzero when in insert mode. */
186int standout_mode; /* Nonzero when in standout mode. */
187
188/* Size of window specified by higher levels.
189 This is the number of lines, from the top of screen downwards,
190 which can participate in insert-line/delete-line operations.
191
192 Effectively it excludes the bottom screen_height - specified_window_size
193 lines from those operations. */
194
195int specified_window;
196
197/* Screen currently being redisplayed; 0 if not currently redisplaying.
198 (Direct output does not count). */
199
200SCREEN_PTR updating_screen;
201
202char *tparam ();
203\f
204ring_bell ()
205{
206 if (! SCREEN_IS_TERMCAP (selected_screen))
207 {
208 (*ring_bell_hook) ();
209 return;
210 }
211 OUTPUT (TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell);
212}
213
214set_terminal_modes ()
215{
216 if (! SCREEN_IS_TERMCAP (selected_screen))
217 {
218 (*set_terminal_modes_hook) ();
219 return;
220 }
221 OUTPUT_IF (TS_termcap_modes);
222 OUTPUT_IF (TS_visual_mode);
223 OUTPUT_IF (TS_keypad_mode);
224 losecursor ();
225}
226
227reset_terminal_modes ()
228{
229 if (! SCREEN_IS_TERMCAP (selected_screen))
230 {
231 (*reset_terminal_modes_hook) ();
232 return;
233 }
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 screen to be in standout, so move down first. */
243 if (TN_standout_width >= 0)
244 cmputc ('\n');
245 cmputc ('\r');
246}
247
248update_begin (s)
249 SCREEN_PTR s;
250{
251 updating_screen = s;
252 if (! SCREEN_IS_TERMCAP (updating_screen))
253 (*update_begin_hook) (s);
254}
255
256update_end (s)
257 SCREEN_PTR s;
258{
259 if (! SCREEN_IS_TERMCAP (updating_screen))
260 {
261 (*update_end_hook) (s);
262 updating_screen = 0;
263 return;
264 }
265 turn_off_insert ();
266 background_highlight ();
267 standout_requested = 0;
268 updating_screen = 0;
269}
270
271set_terminal_window (size)
272 int size;
273{
274 if (! SCREEN_IS_TERMCAP (updating_screen))
275 {
276 (*set_terminal_window_hook) (size);
277 return;
278 }
279 specified_window = size ? size : SCREEN_HEIGHT (selected_screen);
280 if (!scroll_region_ok)
281 return;
282 set_scroll_region (0, specified_window);
283}
284
285set_scroll_region (start, stop)
286 int start, stop;
287{
288 char *buf;
289 if (TS_set_scroll_region)
290 {
291 buf = tparam (TS_set_scroll_region, 0, 0, start, stop - 1);
292 }
293 else if (TS_set_scroll_region_1)
294 {
295 buf = tparam (TS_set_scroll_region_1, 0, 0,
296 SCREEN_HEIGHT (selected_screen), start,
297 SCREEN_HEIGHT (selected_screen) - stop,
298 SCREEN_HEIGHT (selected_screen));
299 }
300 else
301 {
302 buf = tparam (TS_set_window, 0, 0, start, 0, stop, SCREEN_WIDTH (selected_screen));
303 }
304 OUTPUT (buf);
305 free (buf);
306 losecursor ();
307}
308\f
309turn_on_insert ()
310{
311 if (!insert_mode)
312 OUTPUT (TS_insert_mode);
313 insert_mode = 1;
314}
315
316turn_off_insert ()
317{
318 if (insert_mode)
319 OUTPUT (TS_end_insert_mode);
320 insert_mode = 0;
321}
322\f
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.
326
327 These functions are called on all terminals, but do nothing
328 on terminals whose standout mode does not work that way. */
329
330turn_off_highlight ()
331{
332 if (TN_standout_width < 0)
333 {
334 if (standout_mode)
335 OUTPUT_IF (TS_end_standout_mode);
336 standout_mode = 0;
337 }
338}
339
340turn_on_highlight ()
341{
342 if (TN_standout_width < 0)
343 {
344 if (!standout_mode)
345 OUTPUT_IF (TS_standout_mode);
346 standout_mode = 1;
347 }
348}
349
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. */
353
354background_highlight ()
355{
356 if (TN_standout_width >= 0)
357 return;
358 if (inverse_video)
359 turn_on_highlight ();
360 else
361 turn_off_highlight ();
362}
363
364/* Set standout mode to the mode specified for the text to be output. */
365
366static
367highlight_if_desired ()
368{
369 if (TN_standout_width >= 0)
370 return;
371 if (!inverse_video == !standout_requested)
372 turn_off_highlight ();
373 else
374 turn_on_highlight ();
375}
376\f
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 screen 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. */
384
385/* Write a standout marker or end-standout marker at the front of the line
386 at vertical position vpos. */
387
388write_standout_marker (flag, vpos)
389 int flag, vpos;
390{
391 if (flag || (TS_end_standout_mode && !TF_teleray && !se_is_so
392 && !(TF_xs && TN_standout_width == 0)))
393 {
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;
398 }
399}
400\f
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. */
404
405reassert_line_highlight (highlight, vpos)
406 int highlight;
407 int vpos;
408{
409 if (! SCREEN_IS_TERMCAP ((updating_screen ? updating_screen : selected_screen)))
410 {
411 (*reassert_line_highlight_hook) (highlight, vpos);
412 return;
413 }
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);
421}
422
423/* Call this when about to modify line at position VPOS
424 and change whether it is highlighted. */
425
426change_line_highlight (new_highlight, vpos, first_unused_hpos)
427 int new_highlight, vpos, first_unused_hpos;
428{
429 standout_requested = new_highlight;
430 if (! SCREEN_IS_TERMCAP (updating_screen))
431 {
432 (*change_line_highlight_hook) (new_highlight, vpos, first_unused_hpos);
433 return;
434 }
435
436 cursor_to (vpos, 0);
437
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])
442 {
443 turn_off_insert ();
444 /* On Teleray, make sure to erase the SO marker. */
445 if (TF_teleray)
446 {
447 cmgoto (curY - 1, SCREEN_WIDTH (selected_screen) - 4);
448 OUTPUT ("\033S");
449 curY++; /* ESC S moves to next line where the TS_standout_mode was */
450 curX = 0;
451 }
452 else
453 cmgoto (curY, 0); /* reposition to kill standout marker */
454 }
455 clear_end_of_line_raw (first_unused_hpos);
456 reassert_line_highlight (new_highlight, curY);
457}
458\f
459
460/* Move to absolute position, specified origin 0 */
461
462cursor_to (row, col)
4746118a 463 int row, col;
08a24c47
JB
464{
465 if (! SCREEN_IS_TERMCAP ((updating_screen
466 ? updating_screen
467 : selected_screen))
468 && cursor_to_hook)
469 {
470 (*cursor_to_hook) (row, col);
471 return;
472 }
473
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);
482}
483
484/* Similar but don't take any account of the wasted characters. */
485
486raw_cursor_to (row, col)
4746118a 487 int row, col;
08a24c47
JB
488{
489 if (! SCREEN_IS_TERMCAP ((updating_screen ? updating_screen : selected_screen)))
490 {
491 (*raw_cursor_to_hook) (row, col);
492 return;
493 }
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);
501}
502\f
503/* Erase operations */
504
505/* clear from cursor to end of screen */
506clear_to_end ()
507{
508 register int i;
509
510 if (clear_to_end_hook && SCREEN_IS_TERMCAP (updating_screen))
511 {
512 (*clear_to_end_hook) ();
513 return;
514 }
515 if (TS_clr_to_bottom)
516 {
517 background_highlight ();
518 OUTPUT (TS_clr_to_bottom);
519 bzero (chars_wasted + curY, SCREEN_HEIGHT (selected_screen) - curY);
520 }
521 else
522 {
523 for (i = curY; i < SCREEN_HEIGHT (selected_screen); i++)
524 {
525 cursor_to (i, 0);
526 clear_end_of_line_raw (SCREEN_WIDTH (selected_screen));
527 }
528 }
529}
530
531/* Clear entire screen */
532
533clear_screen ()
534{
535 if (clear_screen_hook
536 && ! SCREEN_IS_TERMCAP ((updating_screen ? updating_screen : selected_screen)))
537 {
538 (*clear_screen_hook) ();
539 return;
540 }
541 if (TS_clr_screen)
542 {
543 background_highlight ();
544 OUTPUT (TS_clr_screen);
545 bzero (chars_wasted, SCREEN_HEIGHT (selected_screen));
546 cmat (0, 0);
547 }
548 else
549 {
550 cursor_to (0, 0);
551 clear_to_end ();
552 }
553}
554
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.
559
560 Note that the cursor may be moved. */
561
562clear_end_of_line (first_unused_hpos)
563 int first_unused_hpos;
564{
565 static GLYPH buf[1] = {SPACEGLYPH};
566 if (SCREEN_IS_TERMCAP (selected_screen)
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);
570}
571
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.
575
576 Note that the cursor may be moved, on terminals lacking a `ce' string. */
577
578clear_end_of_line_raw (first_unused_hpos)
579 int first_unused_hpos;
580{
581 register int i;
582
583 if (clear_end_of_line_hook
584 && ! SCREEN_IS_TERMCAP ((updating_screen
585 ? updating_screen
586 : selected_screen)))
587 {
588 (*clear_end_of_line_hook) (first_unused_hpos);
589 return;
590 }
591
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)
600 {
601 OUTPUT1 (TS_clr_line);
602 }
603 else
604 { /* have to do it the hard way */
605 turn_off_insert ();
606
607 /* Do not write in last row last col with Autowrap on. */
608 if (AutoWrap && curY == SCREEN_HEIGHT (selected_screen) - 1
609 && first_unused_hpos == SCREEN_WIDTH (selected_screen))
610 first_unused_hpos--;
611
612 for (i = curX; i < first_unused_hpos; i++)
613 {
614 if (termscript)
615 fputc (' ', termscript);
616 putchar (' ');
617 }
618 cmplus (first_unused_hpos - curX);
619 }
620}
621\f
622
623write_glyphs (string, len)
624 register GLYPH *string;
625 register int len;
626{
627 register GLYPH g;
628 register int tlen = GLYPH_TABLE_LENGTH;
629 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
630
631 if (write_glyphs_hook
632 && ! SCREEN_IS_TERMCAP ((updating_screen ? updating_screen : selected_screen)))
633 {
634 (*write_glyphs_hook) (string, len);
635 return;
636 }
637
638 highlight_if_desired ();
639 turn_off_insert ();
640
641 /* Don't dare write in last column of bottom line, if AutoWrap,
642 since that would scroll the whole screen on some terminals. */
643
644 if (AutoWrap
645 && curY + 1 == SCREEN_HEIGHT (selected_screen)
646 && (curX + len - (chars_wasted[curY] & 077)
647 == SCREEN_WIDTH (selected_screen)))
648 len --;
649
650 cmplus (len);
651 while (--len >= 0)
652 {
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)
657 {
658 simple:
659 putc (g & 0xff, stdout);
660 if (ferror (stdout))
661 clearerr (stdout);
662 if (termscript)
663 putc (g & 0xff, termscript);
664 }
665 else
666 {
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
674 {
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);
683 }
684 }
685 }
686}
687
688/* If start is zero, insert blanks instead of a string at start */
689
690insert_glyphs (start, len)
691 register GLYPH *start;
692 register int len;
693{
694 char *buf;
695 register GLYPH g;
696 register int tlen = GLYPH_TABLE_LENGTH;
697 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
698
699 if (insert_glyphs_hook && ! SCREEN_IS_TERMCAP (updating_screen))
700 {
701 (*insert_glyphs_hook) (start, len);
702 return;
703 }
704 highlight_if_desired ();
705
706 if (TS_ins_multi_chars)
707 {
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;
714 }
715
716 turn_on_insert ();
717 cmplus (len);
718 while (--len >= 0)
719 {
720 OUTPUT1_IF (TS_ins_char);
721 if (!start)
722 g = SPACEGLYPH;
723 else
724 g = *start++;
725
726 if (GLYPH_SIMPLE_P (tbase, tlen, g))
727 {
728 putc (g & 0xff, stdout);
729 if (ferror (stdout))
730 clearerr (stdout);
731 if (termscript)
732 putc (g & 0xff, termscript);
733 }
734 else
735 {
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);
742 }
743
744 OUTPUT1_IF (TS_pad_inserted_char);
745 }
746}
747
748delete_glyphs (n)
749 register int n;
750{
751 char *buf;
752 register int i;
753
754 if (delete_glyphs_hook && ! SCREEN_IS_TERMCAP (updating_screen))
755 {
756 (*delete_glyphs_hook) (n);
757 return;
758 }
759
760 if (delete_in_insert_mode)
761 {
762 turn_on_insert ();
763 }
764 else
765 {
766 turn_off_insert ();
767 OUTPUT_IF (TS_delete_mode);
768 }
769
770 if (TS_del_multi_chars)
771 {
772 buf = tparam (TS_del_multi_chars, 0, 0, n);
773 OUTPUT1 (buf);
774 free (buf);
775 }
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);
781}
782\f
783/* Insert N lines at vpos VPOS. If N is negative, delete -N lines. */
784
785ins_del_lines (vpos, n)
786 int vpos, n;
787{
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;
791
792 register int i = n > 0 ? n : -n;
793 register char *buf;
794
795 if (ins_del_lines_hook && ! SCREEN_IS_TERMCAP (updating_screen))
796 {
797 (*ins_del_lines_hook) (vpos, n);
798 return;
799 }
800
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_screen && vpos + i >= SCREEN_HEIGHT (selected_screen))
811 return;
812
813 if (multi)
814 {
815 raw_cursor_to (vpos, 0);
816 background_highlight ();
817 buf = tparam (multi, 0, 0, i);
818 OUTPUT (buf);
819 free (buf);
820 }
821 else if (single)
822 {
823 raw_cursor_to (vpos, 0);
824 background_highlight ();
825 while (--i >= 0)
826 OUTPUT (single);
827 if (TF_teleray)
828 curX = 0;
829 }
830 else
831 {
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);
841 }
842
843 if (TN_standout_width >= 0)
844 {
845 register lower_limit
846 = (scroll_region_ok
847 ? specified_window
848 : SCREEN_HEIGHT (selected_screen));
849
850 if (n < 0)
851 {
852 bcopy (&chars_wasted[vpos - n], &chars_wasted[vpos],
853 lower_limit - vpos + n);
854 bzero (&chars_wasted[lower_limit + n], - n);
855 }
856 else
857 {
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);
862 }
863 }
864 if (!scroll_region_ok && memory_below_screen && n < 0)
865 {
866 cursor_to (SCREEN_HEIGHT (selected_screen) + n, 0);
867 clear_to_end ();
868 }
869}
870\f
871/* Compute cost of sending "str", in characters,
872 not counting any line-dependent padding. */
873
874int
875string_cost (str)
876 char *str;
877{
878 cost = 0;
879 if (str)
880 tputs (str, 0, evalcost);
881 return cost;
882}
883
884/* Compute cost of sending "str", in characters,
885 counting any line-dependent padding at one line. */
886
887static int
888string_cost_one_line (str)
889 char *str;
890{
891 cost = 0;
892 if (str)
893 tputs (str, 1, evalcost);
894 return cost;
895}
896
897/* Compute per line amount of line-dependent padding,
898 in tenths of characters. */
899
900int
901per_line_cost (str)
902 register char *str;
903{
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;
911}
912
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. */
916
917int *char_ins_del_vector;
918
919#define char_ins_del_cost(s) (&char_ins_del_vector[SCREEN_WIDTH ((s))])
920#endif
921
922/* ARGSUSED */
923static void
924calculate_ins_del_char_costs (screen)
925 SCREEN_PTR screen;
926{
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;
931
932 if (TS_ins_multi_chars)
933 {
934 ins_cost_per_char = 0;
935 ins_startup_cost = string_cost_one_line (TS_ins_multi_chars);
936 }
937 else if (TS_ins_char || TS_pad_inserted_char
938 || (TS_insert_mode && TS_end_insert_mode))
939 {
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));
944 }
945 else
946 {
947 ins_startup_cost = 9999;
948 ins_cost_per_char = 0;
949 }
950
951 if (TS_del_multi_chars)
952 {
953 del_cost_per_char = 0;
954 del_startup_cost = string_cost_one_line (TS_del_multi_chars);
955 }
956 else if (TS_del_char)
957 {
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);
963 }
964 else
965 {
966 del_startup_cost = 9999;
967 del_cost_per_char = 0;
968 }
969
970 /* Delete costs are at negative offsets */
971 p = &char_ins_del_cost (screen)[0];
972 for (i = SCREEN_WIDTH (selected_screen); --i >= 0;)
973 *--p = (del_startup_cost += del_cost_per_char);
974
975 /* Doing nothing is free */
976 p = &char_ins_del_cost (screen)[0];
977 *p++ = 0;
978
979 /* Insert costs are at positive offsets */
980 for (i = SCREEN_WIDTH (screen); --i >= 0;)
981 *p++ = (ins_startup_cost += ins_cost_per_char);
982}
983
984#ifdef HAVE_X_WINDOWS
985extern int x_screen_planes;
986#endif
987
988calculate_costs (screen)
989 SCREEN_PTR screen;
990{
991 register char *s = TS_set_scroll_region ?
992 TS_set_scroll_region
993 : TS_set_scroll_region_1;
994
995 if (dont_calculate_costs)
996 return;
997
998#ifdef HAVE_X_WINDOWS
999 if (SCREEN_IS_X (screen))
1000 {
1001 do_line_insertion_deletion_costs (screen, 0, ".5*", 0, ".5*",
1002 0, 0, x_screen_planes);
1003 return;
1004 }
1005#endif
1006
1007 /* These variables are only used for terminal stuff. They are allocated
1008 once for the terminal screen of X-windows emacs, but not used afterwards.
1009
1010 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1011 X turns off char_ins_del_ok.
1012
1013 chars_wasted and copybuf are only used here in term.c in cases where
1014 the term hook isn't called. */
1015
1016 if (chars_wasted != 0)
1017 chars_wasted = (char *) xrealloc (chars_wasted, SCREEN_HEIGHT (screen));
1018 else
1019 chars_wasted = (char *) xmalloc (SCREEN_HEIGHT (screen));
1020
1021 if (copybuf != 0)
1022 copybuf = (char *) xrealloc (copybuf, SCREEN_HEIGHT (screen));
1023 else
1024 copybuf = (char *) xmalloc (SCREEN_HEIGHT (screen));
1025
1026 if (char_ins_del_vector != 0)
1027 char_ins_del_vector
1028 = (int *) xrealloc (char_ins_del_vector,
1029 (sizeof (int)
1030 + 2 * SCREEN_WIDTH (screen) * sizeof (int)));
1031 else
1032 char_ins_del_vector
1033 = (int *) xmalloc (sizeof (int)
1034 + 2 * SCREEN_WIDTH (screen) * sizeof (int));
1035
1036 bzero (chars_wasted, SCREEN_HEIGHT (screen));
1037 bzero (copybuf, SCREEN_HEIGHT (screen));
1038 bzero (char_ins_del_vector, (sizeof (int)
1039 + 2 * SCREEN_WIDTH (screen) * sizeof (int)));
1040
1041 if (s && (!TS_ins_line && !TS_del_line))
1042 do_line_insertion_deletion_costs (screen,
1043 TS_rev_scroll, TS_ins_multi_lines,
1044 TS_fwd_scroll, TS_del_multi_lines,
1045 s, s, 1);
1046 else
1047 do_line_insertion_deletion_costs (screen,
1048 TS_ins_line, TS_ins_multi_lines,
1049 TS_del_line, TS_del_multi_lines,
1050 0, 0, 1);
1051
1052 calculate_ins_del_char_costs (screen);
1053
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 = SCREEN_WIDTH (screen) * 2;
1059
1060 cmcostinit (); /* set up cursor motion costs */
1061}
1062\f
5c2c7893
JB
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. */
1066
1067void
1068term_get_fkeys (address)
1069 char **address;
1070{
1071 extern char *tgetstr ();
1072 struct fkey_table {
1073 char *cap, *name;
1074 };
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"
1106 };
1107 int i;
1108
1109 for (i = 0; i < (sizeof (keys)/sizeof (keys[0])); i++)
1110 {
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)));
1116 }
1117}
1118
1119\f
08a24c47
JB
1120term_init (terminal_type)
1121 char *terminal_type;
1122{
1123 char *area;
1124 char **address = &area;
1125 char buffer[2044];
1126 register char *p;
1127 int status;
1128
1129 extern char *tgetstr ();
1130
1131 Wcm_clear ();
1132 dont_calculate_costs = 0;
1133
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);
1139
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 ();
1147
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_screen = 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);
1210
1211 AutoWrap = tgetflag ("am");
1212 memory_below_screen = 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");
1222
5c2c7893
JB
1223 term_get_fkeys (address);
1224
08a24c47
JB
1225 /* Get screen size from system, or else from termcap. */
1226 get_screen_size (&SCREEN_WIDTH (selected_screen),
1227 &SCREEN_HEIGHT (selected_screen));
1228 if (SCREEN_WIDTH (selected_screen) <= 0)
1229 SCREEN_WIDTH (selected_screen) = tgetnum ("co");
1230 if (SCREEN_HEIGHT (selected_screen) <= 0)
1231 SCREEN_HEIGHT (selected_screen) = tgetnum ("li");
1232
1233 min_padding_speed = tgetnum ("pb");
1234 TN_standout_width = tgetnum ("sg");
1235 TabWidth = tgetnum ("tw");
1236
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 */
1245
1246 if (!TS_bell)
1247 TS_bell = "\07";
1248
1249 if (!TS_fwd_scroll)
1250 TS_fwd_scroll = Down;
1251
1252 PC = TS_pad_char ? *TS_pad_char : 0;
1253
1254 if (TabWidth < 0)
1255 TabWidth = 8;
1256
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";
1261*/
1262
1263 if (TS_standout_mode == 0)
1264 {
1265 TN_standout_width = tgetnum ("ug");
1266 TS_end_standout_mode = tgetstr ("ue", address);
1267 TS_standout_mode = tgetstr ("us", address);
1268 }
1269
1270 if (TF_teleray)
1271 {
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;
1282 }
1283
1284 /* Special handling for certain terminal types known to need it */
1285
1286 if (!strcmp (terminal_type, "supdup"))
1287 {
1288 memory_below_screen = 1;
1289 Wcm.cm_losewrap = 1;
1290 }
1291 if (!strncmp (terminal_type, "c10", 3)
1292 || !strcmp (terminal_type, "perq"))
1293 {
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.
1298
1299 This string works only if the screen 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.
1302
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)
1307 {
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 ";
1313 }
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)
1326 {
1327 if (p[0] == '%' && p[1] == '+')
1328 p[1] = 'C';
1329 p++;
1330 }
1331 }
1332
1333 ScreenRows = SCREEN_HEIGHT (selected_screen);
1334 ScreenCols = SCREEN_WIDTH (selected_screen);
1335 specified_window = SCREEN_HEIGHT (selected_screen);
1336
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\
1340It lacks the ability to position the cursor.\n\
1341If that is not the actual type of terminal you have, use either the\n\
1342DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\
1343or `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\
1347It lacks the ability to position the cursor.\n\
1348If that is not the actual type of terminal you have,\n\
1349use the C-shell command `setenv TERM ...' to specify the correct type.\n\
1350It may be necessary to do `unsetenv TERMCAP' as well.\n",
1351 terminal_type);
1352#endif
1353 if (SCREEN_HEIGHT (selected_screen) <= 0
1354 || SCREEN_WIDTH (selected_screen) <= 0)
1355 fatal ("The screen size has not been specified.");
1356
1357 delete_in_insert_mode
1358 = TS_delete_mode && TS_insert_mode
1359 && !strcmp (TS_delete_mode, TS_insert_mode);
1360
1361 se_is_so = (TS_standout_mode
1362 && TS_end_standout_mode
1363 && !strcmp (TS_standout_mode, TS_end_standout_mode));
1364
1365 /* Remove width of standout marker from usable width of line */
1366 if (TN_standout_width > 0)
1367 SCREEN_WIDTH (selected_screen) -= TN_standout_width;
1368
1369 UseTabs = tabs_safe_p () && TabWidth == 8;
1370
1371 scroll_region_ok
1372 = (Wcm.cm_abs
1373 && (TS_set_window || TS_set_scroll_region || TS_set_scroll_region_1));
1374
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));
1378
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));
1382
1383 fast_clear_end_of_line = TS_clr_line != 0;
1384
1385 init_baud_rate ();
1386 if (read_socket_hook) /* Baudrate is somewhat */
1387 /* meaningless in this case */
1388 baud_rate = 9600;
1389}
1390
1391/* VARARGS 1 */
1392fatal (str, arg1, arg2)
4746118a 1393 char *str, *arg1, *arg2;
08a24c47
JB
1394{
1395 fprintf (stderr, "emacs: ");
1396 fprintf (stderr, str, arg1, arg2);
1397 fflush (stderr);
1398 exit (1);
1399}