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