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