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