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