(term_init) [WINDOWSNT]: Do some Windows-specific
[bpt/emacs.git] / src / term.c
1 /* terminal control module for terminals described by TERMCAP
2 Copyright (C) 1985, 1986, 1987, 1993, 1994 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <ctype.h>
24 #include "termchar.h"
25 #include "termopts.h"
26 #include "cm.h"
27 #undef NULL
28 #include "lisp.h"
29 #include "frame.h"
30 #include "disptab.h"
31 #include "termhooks.h"
32 #include "keyboard.h"
33
34 extern Lisp_Object Fmake_sparse_keymap ();
35
36 #define max(a, b) ((a) > (b) ? (a) : (b))
37 #define min(a, b) ((a) < (b) ? (a) : (b))
38
39 #define OUTPUT(a) tputs (a, FRAME_HEIGHT (selected_frame) - curY, cmputc)
40 #define OUTPUT1(a) tputs (a, 1, cmputc)
41 #define OUTPUTL(a, lines) tputs (a, lines, cmputc)
42 #define OUTPUT_IF(a) { if (a) tputs (a, FRAME_HEIGHT (selected_frame) - curY, cmputc); }
43 #define OUTPUT1_IF(a) { if (a) tputs (a, 1, cmputc); }
44
45 /* Terminal characteristics that higher levels want to look at.
46 These are all extern'd in termchar.h */
47
48 int must_write_spaces; /* Nonzero means spaces in the text
49 must actually be output; can't just skip
50 over some columns to leave them blank. */
51 int min_padding_speed; /* Speed below which no padding necessary */
52
53 int line_ins_del_ok; /* Terminal can insert and delete lines */
54 int char_ins_del_ok; /* Terminal can insert and delete chars */
55 int scroll_region_ok; /* Terminal supports setting the
56 scroll window */
57 int memory_below_frame; /* Terminal remembers lines
58 scrolled off bottom */
59 int fast_clear_end_of_line; /* Terminal has a `ce' string */
60
61 int dont_calculate_costs; /* Nonzero means don't bother computing */
62 /* various cost tables; we won't use them. */
63
64 /* Nonzero means no need to redraw the entire frame on resuming
65 a suspended Emacs. This is useful on terminals with multiple pages,
66 where one page is used for Emacs and another for all else. */
67 int no_redraw_on_reenter;
68
69 /* Hook functions that you can set to snap out the functions in this file.
70 These are all extern'd in termhooks.h */
71
72 int (*cursor_to_hook) ();
73 int (*raw_cursor_to_hook) ();
74
75 int (*clear_to_end_hook) ();
76 int (*clear_frame_hook) ();
77 int (*clear_end_of_line_hook) ();
78
79 int (*ins_del_lines_hook) ();
80
81 int (*change_line_highlight_hook) ();
82 int (*reassert_line_highlight_hook) ();
83
84 int (*insert_glyphs_hook) ();
85 int (*write_glyphs_hook) ();
86 int (*delete_glyphs_hook) ();
87
88 int (*ring_bell_hook) ();
89
90 int (*reset_terminal_modes_hook) ();
91 int (*set_terminal_modes_hook) ();
92 int (*update_begin_hook) ();
93 int (*update_end_hook) ();
94 int (*set_terminal_window_hook) ();
95
96 int (*read_socket_hook) ();
97
98 int (*frame_up_to_date_hook) ();
99
100 /* Return the current position of the mouse.
101
102 Set *f to the frame the mouse is in, or zero if the mouse is in no
103 Emacs frame. If it is set to zero, all the other arguments are
104 garbage.
105
106 If the motion started in a scroll bar, set *bar_window to the
107 scroll bar's window, *part to the part the mouse is currently over,
108 *x to the position of the mouse along the scroll bar, and *y to the
109 overall length of the scroll bar.
110
111 Otherwise, set *bar_window to Qnil, and *x and *y to the column and
112 row of the character cell the mouse is over.
113
114 Set *time to the time the mouse was at the returned position.
115
116 This should clear mouse_moved until the next motion
117 event arrives. */
118 void (*mouse_position_hook) ( /* FRAME_PTR *f,
119 Lisp_Object *bar_window,
120 enum scroll_bar_part *part,
121 Lisp_Object *x,
122 Lisp_Object *y,
123 unsigned long *time */ );
124
125 /* When reading from a minibuffer in a different frame, Emacs wants
126 to shift the highlight from the selected frame to the minibuffer's
127 frame; under X, this means it lies about where the focus is.
128 This hook tells the window system code to re-decide where to put
129 the highlight. */
130 void (*frame_rehighlight_hook) ( /* FRAME_PTR f */ );
131
132 /* If we're displaying frames using a window system that can stack
133 frames on top of each other, this hook allows you to bring a frame
134 to the front, or bury it behind all the other windows. If this
135 hook is zero, that means the device we're displaying on doesn't
136 support overlapping frames, so there's no need to raise or lower
137 anything.
138
139 If RAISE is non-zero, F is brought to the front, before all other
140 windows. If RAISE is zero, F is sent to the back, behind all other
141 windows. */
142 void (*frame_raise_lower_hook) ( /* FRAME_PTR f, int raise */ );
143
144 /* Set the vertical scroll bar for WINDOW to have its upper left corner
145 at (TOP, LEFT), and be LENGTH rows high. Set its handle to
146 indicate that we are displaying PORTION characters out of a total
147 of WHOLE characters, starting at POSITION. If WINDOW doesn't yet
148 have a scroll bar, create one for it. */
149 void (*set_vertical_scroll_bar_hook)
150 ( /* struct window *window,
151 int portion, int whole, int position */ );
152
153
154 /* The following three hooks are used when we're doing a thorough
155 redisplay of the frame. We don't explicitly know which scroll bars
156 are going to be deleted, because keeping track of when windows go
157 away is a real pain - can you say set-window-configuration?
158 Instead, we just assert at the beginning of redisplay that *all*
159 scroll bars are to be removed, and then save scroll bars from the
160 firey pit when we actually redisplay their window. */
161
162 /* Arrange for all scroll bars on FRAME to be removed at the next call
163 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
164 `*redeem_scroll_bar_hook' is applied to its window before the judgement.
165
166 This should be applied to each frame each time its window tree is
167 redisplayed, even if it is not displaying scroll bars at the moment;
168 if the HAS_SCROLL_BARS flag has just been turned off, only calling
169 this and the judge_scroll_bars_hook will get rid of them.
170
171 If non-zero, this hook should be safe to apply to any frame,
172 whether or not it can support scroll bars, and whether or not it is
173 currently displaying them. */
174 void (*condemn_scroll_bars_hook)( /* FRAME_PTR *frame */ );
175
176 /* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
177 Note that it's okay to redeem a scroll bar that is not condemned. */
178 void (*redeem_scroll_bar_hook)( /* struct window *window */ );
179
180 /* Remove all scroll bars on FRAME that haven't been saved since the
181 last call to `*condemn_scroll_bars_hook'.
182
183 This should be applied to each frame after each time its window
184 tree is redisplayed, even if it is not displaying scroll bars at the
185 moment; if the HAS_SCROLL_BARS flag has just been turned off, only
186 calling this and condemn_scroll_bars_hook will get rid of them.
187
188 If non-zero, this hook should be safe to apply to any frame,
189 whether or not it can support scroll bars, and whether or not it is
190 currently displaying them. */
191 void (*judge_scroll_bars_hook)( /* FRAME_PTR *FRAME */ );
192
193
194 /* Strings, numbers and flags taken from the termcap entry. */
195
196 char *TS_ins_line; /* termcap "al" */
197 char *TS_ins_multi_lines; /* "AL" (one parameter, # lines to insert) */
198 char *TS_bell; /* "bl" */
199 char *TS_clr_to_bottom; /* "cd" */
200 char *TS_clr_line; /* "ce", clear to end of line */
201 char *TS_clr_frame; /* "cl" */
202 char *TS_set_scroll_region; /* "cs" (2 params, first line and last line) */
203 char *TS_set_scroll_region_1; /* "cS" (4 params: total lines,
204 lines above scroll region, lines below it,
205 total lines again) */
206 char *TS_del_char; /* "dc" */
207 char *TS_del_multi_chars; /* "DC" (one parameter, # chars to delete) */
208 char *TS_del_line; /* "dl" */
209 char *TS_del_multi_lines; /* "DL" (one parameter, # lines to delete) */
210 char *TS_delete_mode; /* "dm", enter character-delete mode */
211 char *TS_end_delete_mode; /* "ed", leave character-delete mode */
212 char *TS_end_insert_mode; /* "ei", leave character-insert mode */
213 char *TS_ins_char; /* "ic" */
214 char *TS_ins_multi_chars; /* "IC" (one parameter, # chars to insert) */
215 char *TS_insert_mode; /* "im", enter character-insert mode */
216 char *TS_pad_inserted_char; /* "ip". Just padding, no commands. */
217 char *TS_end_keypad_mode; /* "ke" */
218 char *TS_keypad_mode; /* "ks" */
219 char *TS_pad_char; /* "pc", char to use as padding */
220 char *TS_repeat; /* "rp" (2 params, # times to repeat
221 and character to be repeated) */
222 char *TS_end_standout_mode; /* "se" */
223 char *TS_fwd_scroll; /* "sf" */
224 char *TS_standout_mode; /* "so" */
225 char *TS_rev_scroll; /* "sr" */
226 char *TS_end_termcap_modes; /* "te" */
227 char *TS_termcap_modes; /* "ti" */
228 char *TS_visible_bell; /* "vb" */
229 char *TS_end_visual_mode; /* "ve" */
230 char *TS_visual_mode; /* "vi" */
231 char *TS_set_window; /* "wi" (4 params, start and end of window,
232 each as vpos and hpos) */
233
234 int TF_hazeltine; /* termcap hz flag. */
235 int TF_insmode_motion; /* termcap mi flag: can move while in insert mode. */
236 int TF_standout_motion; /* termcap mi flag: can move while in standout mode. */
237 int TF_underscore; /* termcap ul flag: _ underlines if overstruck on
238 nonblank position. Must clear before writing _. */
239 int TF_teleray; /* termcap xt flag: many weird consequences.
240 For t1061. */
241
242 int TF_xs; /* Nonzero for "xs". If set together with
243 TN_standout_width == 0, it means don't bother
244 to write any end-standout cookies. */
245
246 int TN_standout_width; /* termcap sg number: width occupied by standout
247 markers */
248
249 static int RPov; /* # chars to start a TS_repeat */
250
251 static int delete_in_insert_mode; /* delete mode == insert mode */
252
253 static int se_is_so; /* 1 if same string both enters and leaves
254 standout mode */
255
256 /* internal state */
257
258 /* Number of chars of space used for standout marker at beginning of line,
259 or'd with 0100. Zero if no standout marker at all.
260
261 Used IFF TN_standout_width >= 0. */
262
263 static char *chars_wasted;
264 static char *copybuf;
265
266 /* nonzero means supposed to write text in standout mode. */
267 int standout_requested;
268
269 int insert_mode; /* Nonzero when in insert mode. */
270 int standout_mode; /* Nonzero when in standout mode. */
271
272 /* Size of window specified by higher levels.
273 This is the number of lines, from the top of frame downwards,
274 which can participate in insert-line/delete-line operations.
275
276 Effectively it excludes the bottom frame_height - specified_window_size
277 lines from those operations. */
278
279 int specified_window;
280
281 /* Frame currently being redisplayed; 0 if not currently redisplaying.
282 (Direct output does not count). */
283
284 FRAME_PTR updating_frame;
285
286 /* Provided for lisp packages. */
287 static int system_uses_terminfo;
288
289 char *tparam ();
290
291 extern char *tgetstr ();
292 \f
293
294 #ifdef WINDOWSNT
295 /* We aren't X windows, but we aren't termcap either. This makes me
296 uncertain as to what value to use for frame.output_method. For
297 this file, we'll define FRAME_TERMCAP_P to be zero so that our
298 output hooks get called instead of the termcap functions. Probably
299 the best long-term solution is to define an output_windows_nt... */
300
301 #undef FRAME_TERMCAP_P
302 #define FRAME_TERMCAP_P(_f_) 0
303 #endif /* WINDOWSNT */
304
305 ring_bell ()
306 {
307 if (! FRAME_TERMCAP_P (selected_frame))
308 {
309 (*ring_bell_hook) ();
310 return;
311 }
312 OUTPUT (TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell);
313 }
314
315 set_terminal_modes ()
316 {
317 if (! FRAME_TERMCAP_P (selected_frame))
318 {
319 (*set_terminal_modes_hook) ();
320 return;
321 }
322 OUTPUT_IF (TS_termcap_modes);
323 OUTPUT_IF (TS_visual_mode);
324 OUTPUT_IF (TS_keypad_mode);
325 losecursor ();
326 }
327
328 reset_terminal_modes ()
329 {
330 if (! FRAME_TERMCAP_P (selected_frame))
331 {
332 (*reset_terminal_modes_hook) ();
333 return;
334 }
335 if (TN_standout_width < 0)
336 turn_off_highlight ();
337 turn_off_insert ();
338 OUTPUT_IF (TS_end_keypad_mode);
339 OUTPUT_IF (TS_end_visual_mode);
340 OUTPUT_IF (TS_end_termcap_modes);
341 /* Output raw CR so kernel can track the cursor hpos. */
342 /* But on magic-cookie terminals this can erase an end-standout marker and
343 cause the rest of the frame to be in standout, so move down first. */
344 if (TN_standout_width >= 0)
345 cmputc ('\n');
346 cmputc ('\r');
347 }
348
349 update_begin (f)
350 FRAME_PTR f;
351 {
352 updating_frame = f;
353 if (! FRAME_TERMCAP_P (updating_frame))
354 (*update_begin_hook) (f);
355 }
356
357 update_end (f)
358 FRAME_PTR f;
359 {
360 if (! FRAME_TERMCAP_P (updating_frame))
361 {
362 (*update_end_hook) (f);
363 updating_frame = 0;
364 return;
365 }
366 turn_off_insert ();
367 background_highlight ();
368 standout_requested = 0;
369 updating_frame = 0;
370 }
371
372 set_terminal_window (size)
373 int size;
374 {
375 if (! FRAME_TERMCAP_P (updating_frame))
376 {
377 (*set_terminal_window_hook) (size);
378 return;
379 }
380 specified_window = size ? size : FRAME_HEIGHT (selected_frame);
381 if (!scroll_region_ok)
382 return;
383 set_scroll_region (0, specified_window);
384 }
385
386 set_scroll_region (start, stop)
387 int start, stop;
388 {
389 char *buf;
390 if (TS_set_scroll_region)
391 {
392 buf = tparam (TS_set_scroll_region, 0, 0, start, stop - 1);
393 }
394 else if (TS_set_scroll_region_1)
395 {
396 buf = tparam (TS_set_scroll_region_1, 0, 0,
397 FRAME_HEIGHT (selected_frame), start,
398 FRAME_HEIGHT (selected_frame) - stop,
399 FRAME_HEIGHT (selected_frame));
400 }
401 else
402 {
403 buf = tparam (TS_set_window, 0, 0, start, 0, stop, FRAME_WIDTH (selected_frame));
404 }
405 OUTPUT (buf);
406 xfree (buf);
407 losecursor ();
408 }
409 \f
410 turn_on_insert ()
411 {
412 if (!insert_mode)
413 OUTPUT (TS_insert_mode);
414 insert_mode = 1;
415 }
416
417 turn_off_insert ()
418 {
419 if (insert_mode)
420 OUTPUT (TS_end_insert_mode);
421 insert_mode = 0;
422 }
423 \f
424 /* Handle highlighting when TN_standout_width (termcap sg) is not specified.
425 In these terminals, output is affected by the value of standout
426 mode when the output is written.
427
428 These functions are called on all terminals, but do nothing
429 on terminals whose standout mode does not work that way. */
430
431 turn_off_highlight ()
432 {
433 if (TN_standout_width < 0)
434 {
435 if (standout_mode)
436 OUTPUT_IF (TS_end_standout_mode);
437 standout_mode = 0;
438 }
439 }
440
441 turn_on_highlight ()
442 {
443 if (TN_standout_width < 0)
444 {
445 if (!standout_mode)
446 OUTPUT_IF (TS_standout_mode);
447 standout_mode = 1;
448 }
449 }
450
451 /* Set standout mode to the state it should be in for
452 empty space inside windows. What this is,
453 depends on the user option inverse-video. */
454
455 background_highlight ()
456 {
457 if (TN_standout_width >= 0)
458 return;
459 if (inverse_video)
460 turn_on_highlight ();
461 else
462 turn_off_highlight ();
463 }
464
465 /* Set standout mode to the mode specified for the text to be output. */
466
467 static
468 highlight_if_desired ()
469 {
470 if (TN_standout_width >= 0)
471 return;
472 if (!inverse_video == !standout_requested)
473 turn_off_highlight ();
474 else
475 turn_on_highlight ();
476 }
477 \f
478 /* Handle standout mode for terminals in which TN_standout_width >= 0.
479 On these terminals, standout is controlled by markers that
480 live inside the terminal's memory. TN_standout_width is the width
481 that the marker occupies in memory. Standout runs from the marker
482 to the end of the line on some terminals, or to the next
483 turn-off-standout marker (TS_end_standout_mode) string
484 on other terminals. */
485
486 /* Write a standout marker or end-standout marker at the front of the line
487 at vertical position vpos. */
488
489 write_standout_marker (flag, vpos)
490 int flag, vpos;
491 {
492 if (flag || (TS_end_standout_mode && !TF_teleray && !se_is_so
493 && !(TF_xs && TN_standout_width == 0)))
494 {
495 cmgoto (vpos, 0);
496 cmplus (TN_standout_width);
497 OUTPUT (flag ? TS_standout_mode : TS_end_standout_mode);
498 chars_wasted[curY] = TN_standout_width | 0100;
499 }
500 }
501 \f
502 /* External interface to control of standout mode.
503 Call this when about to modify line at position VPOS
504 and not change whether it is highlighted. */
505
506 reassert_line_highlight (highlight, vpos)
507 int highlight;
508 int vpos;
509 {
510 if (! FRAME_TERMCAP_P ((updating_frame ? updating_frame : selected_frame)))
511 {
512 (*reassert_line_highlight_hook) (highlight, vpos);
513 return;
514 }
515 if (TN_standout_width < 0)
516 /* Handle terminals where standout takes affect at output time */
517 standout_requested = highlight;
518 else if (chars_wasted[vpos] == 0)
519 /* For terminals with standout markers, write one on this line
520 if there isn't one already. */
521 write_standout_marker (highlight, vpos);
522 }
523
524 /* Call this when about to modify line at position VPOS
525 and change whether it is highlighted. */
526
527 change_line_highlight (new_highlight, vpos, first_unused_hpos)
528 int new_highlight, vpos, first_unused_hpos;
529 {
530 standout_requested = new_highlight;
531 if (! FRAME_TERMCAP_P (updating_frame))
532 {
533 (*change_line_highlight_hook) (new_highlight, vpos, first_unused_hpos);
534 return;
535 }
536
537 cursor_to (vpos, 0);
538
539 if (TN_standout_width < 0)
540 background_highlight ();
541 /* If line starts with a marker, delete the marker */
542 else if (TS_clr_line && chars_wasted[curY])
543 {
544 turn_off_insert ();
545 /* On Teleray, make sure to erase the SO marker. */
546 if (TF_teleray)
547 {
548 cmgoto (curY - 1, FRAME_WIDTH (selected_frame) - 4);
549 OUTPUT ("\033S");
550 curY++; /* ESC S moves to next line where the TS_standout_mode was */
551 curX = 0;
552 }
553 else
554 cmgoto (curY, 0); /* reposition to kill standout marker */
555 }
556 clear_end_of_line_raw (first_unused_hpos);
557 reassert_line_highlight (new_highlight, curY);
558 }
559 \f
560
561 /* Move to absolute position, specified origin 0 */
562
563 cursor_to (row, col)
564 int row, col;
565 {
566 if (! FRAME_TERMCAP_P ((updating_frame
567 ? updating_frame
568 : selected_frame))
569 && cursor_to_hook)
570 {
571 (*cursor_to_hook) (row, col);
572 return;
573 }
574
575 col += chars_wasted[row] & 077;
576 if (curY == row && curX == col)
577 return;
578 if (!TF_standout_motion)
579 background_highlight ();
580 if (!TF_insmode_motion)
581 turn_off_insert ();
582 cmgoto (row, col);
583 }
584
585 /* Similar but don't take any account of the wasted characters. */
586
587 raw_cursor_to (row, col)
588 int row, col;
589 {
590 if (! FRAME_TERMCAP_P ((updating_frame ? updating_frame : selected_frame)))
591 {
592 (*raw_cursor_to_hook) (row, col);
593 return;
594 }
595 if (curY == row && curX == col)
596 return;
597 if (!TF_standout_motion)
598 background_highlight ();
599 if (!TF_insmode_motion)
600 turn_off_insert ();
601 cmgoto (row, col);
602 }
603 \f
604 /* Erase operations */
605
606 /* clear from cursor to end of frame */
607 clear_to_end ()
608 {
609 register int i;
610
611 if (clear_to_end_hook && ! FRAME_TERMCAP_P (updating_frame))
612 {
613 (*clear_to_end_hook) ();
614 return;
615 }
616 if (TS_clr_to_bottom)
617 {
618 background_highlight ();
619 OUTPUT (TS_clr_to_bottom);
620 bzero (chars_wasted + curY, FRAME_HEIGHT (selected_frame) - curY);
621 }
622 else
623 {
624 for (i = curY; i < FRAME_HEIGHT (selected_frame); i++)
625 {
626 cursor_to (i, 0);
627 clear_end_of_line_raw (FRAME_WIDTH (selected_frame));
628 }
629 }
630 }
631
632 /* Clear entire frame */
633
634 clear_frame ()
635 {
636 if (clear_frame_hook
637 && ! FRAME_TERMCAP_P ((updating_frame ? updating_frame : selected_frame)))
638 {
639 (*clear_frame_hook) ();
640 return;
641 }
642 if (TS_clr_frame)
643 {
644 background_highlight ();
645 OUTPUT (TS_clr_frame);
646 bzero (chars_wasted, FRAME_HEIGHT (selected_frame));
647 cmat (0, 0);
648 }
649 else
650 {
651 cursor_to (0, 0);
652 clear_to_end ();
653 }
654 }
655
656 /* Clear to end of line, but do not clear any standout marker.
657 Assumes that the cursor is positioned at a character of real text,
658 which implies it cannot be before a standout marker
659 unless the marker has zero width.
660
661 Note that the cursor may be moved. */
662
663 clear_end_of_line (first_unused_hpos)
664 int first_unused_hpos;
665 {
666 static GLYPH buf = SPACEGLYPH;
667 if (FRAME_TERMCAP_P (selected_frame)
668 && TN_standout_width == 0 && curX == 0 && chars_wasted[curY] != 0)
669 write_glyphs (&buf, 1);
670 clear_end_of_line_raw (first_unused_hpos);
671 }
672
673 /* Clear from cursor to end of line.
674 Assume that the line is already clear starting at column first_unused_hpos.
675 If the cursor is at a standout marker, erase the marker.
676
677 Note that the cursor may be moved, on terminals lacking a `ce' string. */
678
679 clear_end_of_line_raw (first_unused_hpos)
680 int first_unused_hpos;
681 {
682 register int i;
683
684 if (clear_end_of_line_hook
685 && ! FRAME_TERMCAP_P ((updating_frame
686 ? updating_frame
687 : selected_frame)))
688 {
689 (*clear_end_of_line_hook) (first_unused_hpos);
690 return;
691 }
692
693 first_unused_hpos += chars_wasted[curY] & 077;
694 if (curX >= first_unused_hpos)
695 return;
696 /* Notice if we are erasing a magic cookie */
697 if (curX == 0)
698 chars_wasted[curY] = 0;
699 background_highlight ();
700 if (TS_clr_line)
701 {
702 OUTPUT1 (TS_clr_line);
703 }
704 else
705 { /* have to do it the hard way */
706 turn_off_insert ();
707
708 /* Do not write in last row last col with Autowrap on. */
709 if (AutoWrap && curY == FRAME_HEIGHT (selected_frame) - 1
710 && first_unused_hpos == FRAME_WIDTH (selected_frame))
711 first_unused_hpos--;
712
713 for (i = curX; i < first_unused_hpos; i++)
714 {
715 if (termscript)
716 fputc (' ', termscript);
717 putchar (' ');
718 }
719 cmplus (first_unused_hpos - curX);
720 }
721 }
722 \f
723
724 write_glyphs (string, len)
725 register GLYPH *string;
726 register int len;
727 {
728 register GLYPH g;
729 register int tlen = GLYPH_TABLE_LENGTH;
730 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
731
732 if (write_glyphs_hook
733 && ! FRAME_TERMCAP_P ((updating_frame ? updating_frame : selected_frame)))
734 {
735 (*write_glyphs_hook) (string, len);
736 return;
737 }
738
739 highlight_if_desired ();
740 turn_off_insert ();
741
742 /* Don't dare write in last column of bottom line, if AutoWrap,
743 since that would scroll the whole frame on some terminals. */
744
745 if (AutoWrap
746 && curY + 1 == FRAME_HEIGHT (selected_frame)
747 && (curX + len - (chars_wasted[curY] & 077)
748 == FRAME_WIDTH (selected_frame)))
749 len --;
750
751 cmplus (len);
752 while (--len >= 0)
753 {
754 g = *string++;
755 /* Check quickly for G beyond length of table.
756 That implies it isn't an alias and is simple. */
757 if (g >= tlen)
758 {
759 simple:
760 putc (g & 0xff, stdout);
761 if (ferror (stdout))
762 clearerr (stdout);
763 if (termscript)
764 putc (g & 0xff, termscript);
765 }
766 else
767 {
768 /* G has an entry in Vglyph_table,
769 so process any alias and then test for simpleness. */
770 while (GLYPH_ALIAS_P (tbase, tlen, g))
771 g = GLYPH_ALIAS (tbase, g);
772 if (GLYPH_SIMPLE_P (tbase, tlen, g))
773 goto simple;
774 else
775 {
776 /* Here if G (or its definition as an alias) is not simple. */
777 fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g),
778 stdout);
779 if (ferror (stdout))
780 clearerr (stdout);
781 if (termscript)
782 fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g),
783 termscript);
784 }
785 }
786 }
787 }
788
789 /* If start is zero, insert blanks instead of a string at start */
790
791 insert_glyphs (start, len)
792 register GLYPH *start;
793 register int len;
794 {
795 char *buf;
796 register GLYPH g;
797 register int tlen = GLYPH_TABLE_LENGTH;
798 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
799
800 if (insert_glyphs_hook && ! FRAME_TERMCAP_P (updating_frame))
801 {
802 (*insert_glyphs_hook) (start, len);
803 return;
804 }
805 highlight_if_desired ();
806
807 if (TS_ins_multi_chars)
808 {
809 buf = tparam (TS_ins_multi_chars, 0, 0, len);
810 OUTPUT1 (buf);
811 xfree (buf);
812 if (start)
813 write_glyphs (start, len);
814 return;
815 }
816
817 turn_on_insert ();
818 cmplus (len);
819 while (--len >= 0)
820 {
821 OUTPUT1_IF (TS_ins_char);
822 if (!start)
823 g = SPACEGLYPH;
824 else
825 g = *start++;
826
827 if (GLYPH_SIMPLE_P (tbase, tlen, g))
828 {
829 putc (g & 0xff, stdout);
830 if (ferror (stdout))
831 clearerr (stdout);
832 if (termscript)
833 putc (g & 0xff, termscript);
834 }
835 else
836 {
837 fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g), stdout);
838 if (ferror (stdout))
839 clearerr (stdout);
840 if (termscript)
841 fwrite (GLYPH_STRING (tbase, g), 1, GLYPH_LENGTH (tbase, g),
842 termscript);
843 }
844
845 OUTPUT1_IF (TS_pad_inserted_char);
846 }
847 }
848
849 delete_glyphs (n)
850 register int n;
851 {
852 char *buf;
853 register int i;
854
855 if (delete_glyphs_hook && ! FRAME_TERMCAP_P (updating_frame))
856 {
857 (*delete_glyphs_hook) (n);
858 return;
859 }
860
861 if (delete_in_insert_mode)
862 {
863 turn_on_insert ();
864 }
865 else
866 {
867 turn_off_insert ();
868 OUTPUT_IF (TS_delete_mode);
869 }
870
871 if (TS_del_multi_chars)
872 {
873 buf = tparam (TS_del_multi_chars, 0, 0, n);
874 OUTPUT1 (buf);
875 xfree (buf);
876 }
877 else
878 for (i = 0; i < n; i++)
879 OUTPUT1 (TS_del_char);
880 if (!delete_in_insert_mode)
881 OUTPUT_IF (TS_end_delete_mode);
882 }
883 \f
884 /* Insert N lines at vpos VPOS. If N is negative, delete -N lines. */
885
886 ins_del_lines (vpos, n)
887 int vpos, n;
888 {
889 char *multi = n > 0 ? TS_ins_multi_lines : TS_del_multi_lines;
890 char *single = n > 0 ? TS_ins_line : TS_del_line;
891 char *scroll = n > 0 ? TS_rev_scroll : TS_fwd_scroll;
892
893 register int i = n > 0 ? n : -n;
894 register char *buf;
895
896 if (ins_del_lines_hook && ! FRAME_TERMCAP_P (updating_frame))
897 {
898 (*ins_del_lines_hook) (vpos, n);
899 return;
900 }
901
902 /* If the lines below the insertion are being pushed
903 into the end of the window, this is the same as clearing;
904 and we know the lines are already clear, since the matching
905 deletion has already been done. So can ignore this. */
906 /* If the lines below the deletion are blank lines coming
907 out of the end of the window, don't bother,
908 as there will be a matching inslines later that will flush them. */
909 if (scroll_region_ok && vpos + i >= specified_window)
910 return;
911 if (!memory_below_frame && vpos + i >= FRAME_HEIGHT (selected_frame))
912 return;
913
914 if (multi)
915 {
916 raw_cursor_to (vpos, 0);
917 background_highlight ();
918 buf = tparam (multi, 0, 0, i);
919 OUTPUT (buf);
920 xfree (buf);
921 }
922 else if (single)
923 {
924 raw_cursor_to (vpos, 0);
925 background_highlight ();
926 while (--i >= 0)
927 OUTPUT (single);
928 if (TF_teleray)
929 curX = 0;
930 }
931 else
932 {
933 set_scroll_region (vpos, specified_window);
934 if (n < 0)
935 raw_cursor_to (specified_window - 1, 0);
936 else
937 raw_cursor_to (vpos, 0);
938 background_highlight ();
939 while (--i >= 0)
940 OUTPUTL (scroll, specified_window - vpos);
941 set_scroll_region (0, specified_window);
942 }
943
944 if (TN_standout_width >= 0)
945 {
946 register lower_limit
947 = (scroll_region_ok
948 ? specified_window
949 : FRAME_HEIGHT (selected_frame));
950
951 if (n < 0)
952 {
953 bcopy (&chars_wasted[vpos - n], &chars_wasted[vpos],
954 lower_limit - vpos + n);
955 bzero (&chars_wasted[lower_limit + n], - n);
956 }
957 else
958 {
959 bcopy (&chars_wasted[vpos], &copybuf[vpos], lower_limit - vpos - n);
960 bcopy (&copybuf[vpos], &chars_wasted[vpos + n],
961 lower_limit - vpos - n);
962 bzero (&chars_wasted[vpos], n);
963 }
964 }
965 if (!scroll_region_ok && memory_below_frame && n < 0)
966 {
967 cursor_to (FRAME_HEIGHT (selected_frame) + n, 0);
968 clear_to_end ();
969 }
970 }
971 \f
972 /* Compute cost of sending "str", in characters,
973 not counting any line-dependent padding. */
974
975 int
976 string_cost (str)
977 char *str;
978 {
979 cost = 0;
980 if (str)
981 tputs (str, 0, evalcost);
982 return cost;
983 }
984
985 /* Compute cost of sending "str", in characters,
986 counting any line-dependent padding at one line. */
987
988 static int
989 string_cost_one_line (str)
990 char *str;
991 {
992 cost = 0;
993 if (str)
994 tputs (str, 1, evalcost);
995 return cost;
996 }
997
998 /* Compute per line amount of line-dependent padding,
999 in tenths of characters. */
1000
1001 int
1002 per_line_cost (str)
1003 register char *str;
1004 {
1005 cost = 0;
1006 if (str)
1007 tputs (str, 0, evalcost);
1008 cost = - cost;
1009 if (str)
1010 tputs (str, 10, evalcost);
1011 return cost;
1012 }
1013
1014 #ifndef old
1015 /* char_ins_del_cost[n] is cost of inserting N characters.
1016 char_ins_del_cost[-n] is cost of deleting N characters. */
1017
1018 int *char_ins_del_vector;
1019
1020 #define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_WIDTH ((f))])
1021 #endif
1022
1023 /* ARGSUSED */
1024 static void
1025 calculate_ins_del_char_costs (frame)
1026 FRAME_PTR frame;
1027 {
1028 int ins_startup_cost, del_startup_cost;
1029 int ins_cost_per_char, del_cost_per_char;
1030 register int i;
1031 register int *p;
1032
1033 if (TS_ins_multi_chars)
1034 {
1035 ins_cost_per_char = 0;
1036 ins_startup_cost = string_cost_one_line (TS_ins_multi_chars);
1037 }
1038 else if (TS_ins_char || TS_pad_inserted_char
1039 || (TS_insert_mode && TS_end_insert_mode))
1040 {
1041 ins_startup_cost = (30 * (string_cost (TS_insert_mode)
1042 + string_cost (TS_end_insert_mode))) / 100;
1043 ins_cost_per_char = (string_cost_one_line (TS_ins_char)
1044 + string_cost_one_line (TS_pad_inserted_char));
1045 }
1046 else
1047 {
1048 ins_startup_cost = 9999;
1049 ins_cost_per_char = 0;
1050 }
1051
1052 if (TS_del_multi_chars)
1053 {
1054 del_cost_per_char = 0;
1055 del_startup_cost = string_cost_one_line (TS_del_multi_chars);
1056 }
1057 else if (TS_del_char)
1058 {
1059 del_startup_cost = (string_cost (TS_delete_mode)
1060 + string_cost (TS_end_delete_mode));
1061 if (delete_in_insert_mode)
1062 del_startup_cost /= 2;
1063 del_cost_per_char = string_cost_one_line (TS_del_char);
1064 }
1065 else
1066 {
1067 del_startup_cost = 9999;
1068 del_cost_per_char = 0;
1069 }
1070
1071 /* Delete costs are at negative offsets */
1072 p = &char_ins_del_cost (frame)[0];
1073 for (i = FRAME_WIDTH (selected_frame); --i >= 0;)
1074 *--p = (del_startup_cost += del_cost_per_char);
1075
1076 /* Doing nothing is free */
1077 p = &char_ins_del_cost (frame)[0];
1078 *p++ = 0;
1079
1080 /* Insert costs are at positive offsets */
1081 for (i = FRAME_WIDTH (frame); --i >= 0;)
1082 *p++ = (ins_startup_cost += ins_cost_per_char);
1083 }
1084
1085 extern do_line_insertion_deletion_costs ();
1086
1087 calculate_costs (frame)
1088 FRAME_PTR frame;
1089 {
1090 register char *f = TS_set_scroll_region ?
1091 TS_set_scroll_region
1092 : TS_set_scroll_region_1;
1093
1094 if (dont_calculate_costs)
1095 return;
1096
1097 #ifdef HAVE_X_WINDOWS
1098 if (FRAME_X_P (frame))
1099 {
1100 do_line_insertion_deletion_costs (frame, 0, ".5*", 0, ".5*",
1101 0, 0,
1102 x_screen_planes (frame));
1103 return;
1104 }
1105 #endif
1106
1107 /* These variables are only used for terminal stuff. They are allocated
1108 once for the terminal frame of X-windows emacs, but not used afterwards.
1109
1110 char_ins_del_vector (i.e., char_ins_del_cost) isn't used because
1111 X turns off char_ins_del_ok.
1112
1113 chars_wasted and copybuf are only used here in term.c in cases where
1114 the term hook isn't called. */
1115
1116 if (chars_wasted != 0)
1117 chars_wasted = (char *) xrealloc (chars_wasted, FRAME_HEIGHT (frame));
1118 else
1119 chars_wasted = (char *) xmalloc (FRAME_HEIGHT (frame));
1120
1121 if (copybuf != 0)
1122 copybuf = (char *) xrealloc (copybuf, FRAME_HEIGHT (frame));
1123 else
1124 copybuf = (char *) xmalloc (FRAME_HEIGHT (frame));
1125
1126 if (char_ins_del_vector != 0)
1127 char_ins_del_vector
1128 = (int *) xrealloc (char_ins_del_vector,
1129 (sizeof (int)
1130 + 2 * FRAME_WIDTH (frame) * sizeof (int)));
1131 else
1132 char_ins_del_vector
1133 = (int *) xmalloc (sizeof (int)
1134 + 2 * FRAME_WIDTH (frame) * sizeof (int));
1135
1136 bzero (chars_wasted, FRAME_HEIGHT (frame));
1137 bzero (copybuf, FRAME_HEIGHT (frame));
1138 bzero (char_ins_del_vector, (sizeof (int)
1139 + 2 * FRAME_WIDTH (frame) * sizeof (int)));
1140
1141 if (f && (!TS_ins_line && !TS_del_line))
1142 do_line_insertion_deletion_costs (frame,
1143 TS_rev_scroll, TS_ins_multi_lines,
1144 TS_fwd_scroll, TS_del_multi_lines,
1145 f, f, 1);
1146 else
1147 do_line_insertion_deletion_costs (frame,
1148 TS_ins_line, TS_ins_multi_lines,
1149 TS_del_line, TS_del_multi_lines,
1150 0, 0, 1);
1151
1152 calculate_ins_del_char_costs (frame);
1153
1154 /* Don't use TS_repeat if its padding is worse than sending the chars */
1155 if (TS_repeat && per_line_cost (TS_repeat) * baud_rate < 9000)
1156 RPov = string_cost (TS_repeat);
1157 else
1158 RPov = FRAME_WIDTH (frame) * 2;
1159
1160 cmcostinit (); /* set up cursor motion costs */
1161 }
1162 \f
1163 struct fkey_table {
1164 char *cap, *name;
1165 };
1166
1167 /* Termcap capability names that correspond directly to X keysyms.
1168 Some of these (marked "terminfo") aren't supplied by old-style
1169 (Berkeley) termcap entries. They're listed in X keysym order;
1170 except we put the keypad keys first, so that if they clash with
1171 other keys (as on the IBM PC keyboard) they get overridden.
1172 */
1173
1174 static struct fkey_table keys[] = {
1175 "kh", "home", /* termcap */
1176 "kl", "left", /* termcap */
1177 "ku", "up", /* termcap */
1178 "kr", "right", /* termcap */
1179 "kd", "down", /* termcap */
1180 "%8", "prior", /* terminfo */
1181 "%5", "next", /* terminfo */
1182 "@7", "end", /* terminfo */
1183 "@1", "begin", /* terminfo */
1184 "*6", "select", /* terminfo */
1185 "%9", "print", /* terminfo */
1186 "@4", "execute", /* terminfo --- actually the `command' key */
1187 /*
1188 * "insert" --- see below
1189 */
1190 "&8", "undo", /* terminfo */
1191 "%0", "redo", /* terminfo */
1192 "%7", "menu", /* terminfo --- actually the `options' key */
1193 "@0", "find", /* terminfo */
1194 "@2", "cancel", /* terminfo */
1195 "%1", "help", /* terminfo */
1196 /*
1197 * "break" goes here, but can't be reliably intercepted with termcap
1198 */
1199 "&4", "reset", /* terminfo --- actually `restart' */
1200 /*
1201 * "system" and "user" --- no termcaps
1202 */
1203 "kE", "clearline", /* terminfo */
1204 "kA", "insertline", /* terminfo */
1205 "kL", "deleteline", /* terminfo */
1206 "kI", "insertchar", /* terminfo */
1207 "kD", "deletechar", /* terminfo */
1208 "kB", "backtab", /* terminfo */
1209 /*
1210 * "kp_backtab", "kp-space", "kp-tab" --- no termcaps
1211 */
1212 "@8", "kp-enter", /* terminfo */
1213 /*
1214 * "kp-f1", "kp-f2", "kp-f3" "kp-f4",
1215 * "kp-multiply", "kp-add", "kp-separator",
1216 * "kp-subtract", "kp-decimal", "kp-divide", "kp-0";
1217 * --- no termcaps for any of these.
1218 */
1219 "K4", "kp-1", /* terminfo */
1220 /*
1221 * "kp-2" --- no termcap
1222 */
1223 "K5", "kp-3", /* terminfo */
1224 /*
1225 * "kp-4" --- no termcap
1226 */
1227 "K2", "kp-5", /* terminfo */
1228 /*
1229 * "kp-6" --- no termcap
1230 */
1231 "K1", "kp-7", /* terminfo */
1232 /*
1233 * "kp-8" --- no termcap
1234 */
1235 "K3", "kp-9", /* terminfo */
1236 /*
1237 * "kp-equal" --- no termcap
1238 */
1239 "k1", "f1",
1240 "k2", "f2",
1241 "k3", "f3",
1242 "k4", "f4",
1243 "k5", "f5",
1244 "k6", "f6",
1245 "k7", "f7",
1246 "k8", "f8",
1247 "k9", "f9",
1248 };
1249
1250 static char **term_get_fkeys_arg;
1251 static Lisp_Object term_get_fkeys_1 ();
1252
1253 /* Find the escape codes sent by the function keys for Vfunction_key_map.
1254 This function scans the termcap function key sequence entries, and
1255 adds entries to Vfunction_key_map for each function key it finds. */
1256
1257 void
1258 term_get_fkeys (address)
1259 char **address;
1260 {
1261 /* We run the body of the function (term_get_fkeys_1) and ignore all Lisp
1262 errors during the call. The only errors should be from Fdefine_key
1263 when given a key sequence containing an invalid prefix key. If the
1264 termcap defines function keys which use a prefix that is already bound
1265 to a command by the default bindings, we should silently ignore that
1266 function key specification, rather than giving the user an error and
1267 refusing to run at all on such a terminal. */
1268
1269 extern Lisp_Object Fidentity ();
1270 term_get_fkeys_arg = address;
1271 internal_condition_case (term_get_fkeys_1, Qerror, Fidentity);
1272 }
1273
1274 static Lisp_Object
1275 term_get_fkeys_1 ()
1276 {
1277 int i;
1278
1279 char **address = term_get_fkeys_arg;
1280
1281 /* This can happen if CANNOT_DUMP or with strange options. */
1282 if (!initialized)
1283 Vfunction_key_map = Fmake_sparse_keymap (Qnil);
1284
1285 for (i = 0; i < (sizeof (keys)/sizeof (keys[0])); i++)
1286 {
1287 char *sequence = tgetstr (keys[i].cap, address);
1288 if (sequence)
1289 Fdefine_key (Vfunction_key_map, build_string (sequence),
1290 Fmake_vector (make_number (1),
1291 intern (keys[i].name)));
1292 }
1293
1294 /* The uses of the "k0" capability are inconsistent; sometimes it
1295 describes F10, whereas othertimes it describes F0 and "k;" describes F10.
1296 We will attempt to politely accommodate both systems by testing for
1297 "k;", and if it is present, assuming that "k0" denotes F0, otherwise F10.
1298 */
1299 {
1300 char *k_semi = tgetstr ("k;", address);
1301 char *k0 = tgetstr ("k0", address);
1302 char *k0_name = "f10";
1303
1304 if (k_semi)
1305 {
1306 Fdefine_key (Vfunction_key_map, build_string (k_semi),
1307 Fmake_vector (make_number (1), intern ("f10")));
1308 k0_name = "f0";
1309 }
1310
1311 if (k0)
1312 Fdefine_key (Vfunction_key_map, build_string (k0),
1313 Fmake_vector (make_number (1), intern (k0_name)));
1314 }
1315
1316 /* Set up cookies for numbered function keys above f10. */
1317 {
1318 char fcap[3], fkey[4];
1319
1320 fcap[0] = 'F'; fcap[2] = '\0';
1321 for (i = 11; i < 64; i++)
1322 {
1323 if (i <= 19)
1324 fcap[1] = '1' + i - 11;
1325 else if (i <= 45)
1326 fcap[1] = 'A' + i - 11;
1327 else
1328 fcap[1] = 'a' + i - 11;
1329
1330 {
1331 char *sequence = tgetstr (fcap, address);
1332 if (sequence)
1333 {
1334 sprintf (fkey, "f%d", i);
1335 Fdefine_key (Vfunction_key_map, build_string (sequence),
1336 Fmake_vector (make_number (1),
1337 intern (fkey)));
1338 }
1339 }
1340 }
1341 }
1342
1343 /*
1344 * Various mappings to try and get a better fit.
1345 */
1346 {
1347 #define CONDITIONAL_REASSIGN(cap1, cap2, sym) \
1348 if (!tgetstr (cap1, address)) \
1349 { \
1350 char *sequence = tgetstr (cap2, address); \
1351 if (sequence) \
1352 Fdefine_key (Vfunction_key_map, build_string (sequence), \
1353 Fmake_vector (make_number (1), \
1354 intern (sym))); \
1355 }
1356
1357 /* if there's no key_next keycap, map key_npage to `next' keysym */
1358 CONDITIONAL_REASSIGN ("%5", "kN", "next");
1359 /* if there's no key_prev keycap, map key_ppage to `previous' keysym */
1360 CONDITIONAL_REASSIGN ("%8", "kP", "prior");
1361 /* if there's no key_dc keycap, map key_ic to `insert' keysym */
1362 CONDITIONAL_REASSIGN ("kD", "kI", "insert");
1363
1364 /* IBM has their own non-standard dialect of terminfo.
1365 If the standard name isn't found, try the IBM name. */
1366 CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
1367 CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
1368 CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
1369 CONDITIONAL_REASSIGN ("%7", "ki", "menu");
1370 CONDITIONAL_REASSIGN ("@7", "kw", "end");
1371 CONDITIONAL_REASSIGN ("F1", "k<", "f11");
1372 CONDITIONAL_REASSIGN ("F2", "k>", "f12");
1373 CONDITIONAL_REASSIGN ("%1", "kq", "help");
1374 CONDITIONAL_REASSIGN ("*6", "kU", "select");
1375 #undef CONDITIONAL_REASSIGN
1376 }
1377 }
1378
1379 \f
1380 term_init (terminal_type)
1381 char *terminal_type;
1382 {
1383 char *area;
1384 char **address = &area;
1385 char buffer[2044];
1386 register char *p;
1387 int status;
1388
1389 #ifdef WINDOWSNT
1390 initialize_win_nt_display ();
1391
1392 Wcm_clear ();
1393 dont_calculate_costs = 0;
1394
1395 area = (char *) malloc (2044);
1396
1397 if (area == 0)
1398 abort ();
1399
1400 FrameRows = FRAME_HEIGHT (selected_frame);
1401 FrameCols = FRAME_WIDTH (selected_frame);
1402 specified_window = FRAME_HEIGHT (selected_frame);
1403
1404 delete_in_insert_mode = 1;
1405
1406 UseTabs = 0;
1407 scroll_region_ok = 0;
1408
1409 /* Seems to insert lines when it's not supposed to, messing
1410 up the display. In doing a trace, it didn't seem to be
1411 called much, so I don't think we're losing anything by
1412 turning it off. */
1413
1414 line_ins_del_ok = 0;
1415 char_ins_del_ok = 1;
1416
1417 baud_rate = 19200;
1418
1419 FRAME_CAN_HAVE_SCROLL_BARS (selected_frame) = 0;
1420 FRAME_HAS_VERTICAL_SCROLL_BARS (selected_frame) = 0;
1421
1422 return;
1423 #endif /* WINDOWSNT */
1424
1425 Wcm_clear ();
1426 dont_calculate_costs = 0;
1427
1428 status = tgetent (buffer, terminal_type);
1429 if (status < 0)
1430 fatal ("Cannot open termcap database file.\n");
1431 if (status == 0)
1432 fatal ("Terminal type %s is not defined.\n\
1433 If that is not the actual type of terminal you have,\n\
1434 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
1435 `setenv TERM ...') to specify the correct type. It may be necessary\n\
1436 to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.\n",
1437 terminal_type);
1438
1439 #ifdef TERMINFO
1440 area = (char *) malloc (2044);
1441 #else
1442 area = (char *) malloc (strlen (buffer));
1443 #endif /* not TERMINFO */
1444 if (area == 0)
1445 abort ();
1446
1447 TS_ins_line = tgetstr ("al", address);
1448 TS_ins_multi_lines = tgetstr ("AL", address);
1449 TS_bell = tgetstr ("bl", address);
1450 BackTab = tgetstr ("bt", address);
1451 TS_clr_to_bottom = tgetstr ("cd", address);
1452 TS_clr_line = tgetstr ("ce", address);
1453 TS_clr_frame = tgetstr ("cl", address);
1454 ColPosition = tgetstr ("ch", address);
1455 AbsPosition = tgetstr ("cm", address);
1456 CR = tgetstr ("cr", address);
1457 TS_set_scroll_region = tgetstr ("cs", address);
1458 TS_set_scroll_region_1 = tgetstr ("cS", address);
1459 RowPosition = tgetstr ("cv", address);
1460 TS_del_char = tgetstr ("dc", address);
1461 TS_del_multi_chars = tgetstr ("DC", address);
1462 TS_del_line = tgetstr ("dl", address);
1463 TS_del_multi_lines = tgetstr ("DL", address);
1464 TS_delete_mode = tgetstr ("dm", address);
1465 TS_end_delete_mode = tgetstr ("ed", address);
1466 TS_end_insert_mode = tgetstr ("ei", address);
1467 Home = tgetstr ("ho", address);
1468 TS_ins_char = tgetstr ("ic", address);
1469 TS_ins_multi_chars = tgetstr ("IC", address);
1470 TS_insert_mode = tgetstr ("im", address);
1471 TS_pad_inserted_char = tgetstr ("ip", address);
1472 TS_end_keypad_mode = tgetstr ("ke", address);
1473 TS_keypad_mode = tgetstr ("ks", address);
1474 LastLine = tgetstr ("ll", address);
1475 Right = tgetstr ("nd", address);
1476 Down = tgetstr ("do", address);
1477 if (!Down)
1478 Down = tgetstr ("nl", address); /* Obsolete name for "do" */
1479 #ifdef VMS
1480 /* VMS puts a carriage return before each linefeed,
1481 so it is not safe to use linefeeds. */
1482 if (Down && Down[0] == '\n' && Down[1] == '\0')
1483 Down = 0;
1484 #endif /* VMS */
1485 if (tgetflag ("bs"))
1486 Left = "\b"; /* can't possibly be longer! */
1487 else /* (Actually, "bs" is obsolete...) */
1488 Left = tgetstr ("le", address);
1489 if (!Left)
1490 Left = tgetstr ("bc", address); /* Obsolete name for "le" */
1491 TS_pad_char = tgetstr ("pc", address);
1492 TS_repeat = tgetstr ("rp", address);
1493 TS_end_standout_mode = tgetstr ("se", address);
1494 TS_fwd_scroll = tgetstr ("sf", address);
1495 TS_standout_mode = tgetstr ("so", address);
1496 TS_rev_scroll = tgetstr ("sr", address);
1497 Wcm.cm_tab = tgetstr ("ta", address);
1498 TS_end_termcap_modes = tgetstr ("te", address);
1499 TS_termcap_modes = tgetstr ("ti", address);
1500 Up = tgetstr ("up", address);
1501 TS_visible_bell = tgetstr ("vb", address);
1502 TS_end_visual_mode = tgetstr ("ve", address);
1503 TS_visual_mode = tgetstr ("vs", address);
1504 TS_set_window = tgetstr ("wi", address);
1505 MultiUp = tgetstr ("UP", address);
1506 MultiDown = tgetstr ("DO", address);
1507 MultiLeft = tgetstr ("LE", address);
1508 MultiRight = tgetstr ("RI", address);
1509
1510 AutoWrap = tgetflag ("am");
1511 memory_below_frame = tgetflag ("db");
1512 TF_hazeltine = tgetflag ("hz");
1513 must_write_spaces = tgetflag ("in");
1514 meta_key = tgetflag ("km") || tgetflag ("MT");
1515 TF_insmode_motion = tgetflag ("mi");
1516 TF_standout_motion = tgetflag ("ms");
1517 TF_underscore = tgetflag ("ul");
1518 MagicWrap = tgetflag ("xn");
1519 TF_xs = tgetflag ("xs");
1520 TF_teleray = tgetflag ("xt");
1521
1522 term_get_fkeys (address);
1523
1524 /* Get frame size from system, or else from termcap. */
1525 get_frame_size (&FRAME_WIDTH (selected_frame),
1526 &FRAME_HEIGHT (selected_frame));
1527 if (FRAME_WIDTH (selected_frame) <= 0)
1528 FRAME_WIDTH (selected_frame) = tgetnum ("co");
1529 if (FRAME_HEIGHT (selected_frame) <= 0)
1530 FRAME_HEIGHT (selected_frame) = tgetnum ("li");
1531
1532 min_padding_speed = tgetnum ("pb");
1533 TN_standout_width = tgetnum ("sg");
1534 TabWidth = tgetnum ("tw");
1535
1536 #ifdef VMS
1537 /* These capabilities commonly use ^J.
1538 I don't know why, but sending them on VMS does not work;
1539 it causes following spaces to be lost, sometimes.
1540 For now, the simplest fix is to avoid using these capabilities ever. */
1541 if (Down && Down[0] == '\n')
1542 Down = 0;
1543 #endif /* VMS */
1544
1545 if (!TS_bell)
1546 TS_bell = "\07";
1547
1548 if (!TS_fwd_scroll)
1549 TS_fwd_scroll = Down;
1550
1551 PC = TS_pad_char ? *TS_pad_char : 0;
1552
1553 if (TabWidth < 0)
1554 TabWidth = 8;
1555
1556 /* Turned off since /etc/termcap seems to have :ta= for most terminals
1557 and newer termcap doc does not seem to say there is a default.
1558 if (!Wcm.cm_tab)
1559 Wcm.cm_tab = "\t";
1560 */
1561
1562 if (TS_standout_mode == 0)
1563 {
1564 TN_standout_width = tgetnum ("ug");
1565 TS_end_standout_mode = tgetstr ("ue", address);
1566 TS_standout_mode = tgetstr ("us", address);
1567 }
1568
1569 /* If no `se' string, try using a `me' string instead.
1570 If that fails, we can't use standout mode at all. */
1571 if (TS_end_standout_mode == 0)
1572 {
1573 char *s = tgetstr ("me", address);
1574 if (s != 0)
1575 TS_end_standout_mode = s;
1576 else
1577 TS_standout_mode = 0;
1578 }
1579
1580 if (TF_teleray)
1581 {
1582 Wcm.cm_tab = 0;
1583 /* Teleray: most programs want a space in front of TS_standout_mode,
1584 but Emacs can do without it (and give one extra column). */
1585 TS_standout_mode = "\033RD";
1586 TN_standout_width = 1;
1587 /* But that means we cannot rely on ^M to go to column zero! */
1588 CR = 0;
1589 /* LF can't be trusted either -- can alter hpos */
1590 /* if move at column 0 thru a line with TS_standout_mode */
1591 Down = 0;
1592 }
1593
1594 /* Special handling for certain terminal types known to need it */
1595
1596 if (!strcmp (terminal_type, "supdup"))
1597 {
1598 memory_below_frame = 1;
1599 Wcm.cm_losewrap = 1;
1600 }
1601 if (!strncmp (terminal_type, "c10", 3)
1602 || !strcmp (terminal_type, "perq"))
1603 {
1604 /* Supply a makeshift :wi string.
1605 This string is not valid in general since it works only
1606 for windows starting at the upper left corner;
1607 but that is all Emacs uses.
1608
1609 This string works only if the frame is using
1610 the top of the video memory, because addressing is memory-relative.
1611 So first check the :ti string to see if that is true.
1612
1613 It would be simpler if the :wi string could go in the termcap
1614 entry, but it can't because it is not fully valid.
1615 If it were in the termcap entry, it would confuse other programs. */
1616 if (!TS_set_window)
1617 {
1618 p = TS_termcap_modes;
1619 while (*p && strcmp (p, "\033v "))
1620 p++;
1621 if (*p)
1622 TS_set_window = "\033v%C %C %C %C ";
1623 }
1624 /* Termcap entry often fails to have :in: flag */
1625 must_write_spaces = 1;
1626 /* :ti string typically fails to have \E^G! in it */
1627 /* This limits scope of insert-char to one line. */
1628 strcpy (area, TS_termcap_modes);
1629 strcat (area, "\033\007!");
1630 TS_termcap_modes = area;
1631 area += strlen (area) + 1;
1632 p = AbsPosition;
1633 /* Change all %+ parameters to %C, to handle
1634 values above 96 correctly for the C100. */
1635 while (*p)
1636 {
1637 if (p[0] == '%' && p[1] == '+')
1638 p[1] = 'C';
1639 p++;
1640 }
1641 }
1642
1643 FrameRows = FRAME_HEIGHT (selected_frame);
1644 FrameCols = FRAME_WIDTH (selected_frame);
1645 specified_window = FRAME_HEIGHT (selected_frame);
1646
1647 if (Wcm_init () == -1) /* can't do cursor motion */
1648 #ifdef VMS
1649 fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
1650 It lacks the ability to position the cursor.\n\
1651 If that is not the actual type of terminal you have, use either the\n\
1652 DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\
1653 or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.\n",
1654 terminal_type);
1655 #else
1656 fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
1657 It lacks the ability to position the cursor.\n\
1658 If that is not the actual type of terminal you have,\n\
1659 use the Bourne shell command `TERM=... export TERM' (C-shell:\n\
1660 `setenv TERM ...') to specify the correct type. It may be necessary\n\
1661 to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.\n",
1662 terminal_type);
1663 #endif
1664 if (FRAME_HEIGHT (selected_frame) <= 0
1665 || FRAME_WIDTH (selected_frame) <= 0)
1666 fatal ("The frame size has not been specified.");
1667
1668 delete_in_insert_mode
1669 = TS_delete_mode && TS_insert_mode
1670 && !strcmp (TS_delete_mode, TS_insert_mode);
1671
1672 se_is_so = (TS_standout_mode
1673 && TS_end_standout_mode
1674 && !strcmp (TS_standout_mode, TS_end_standout_mode));
1675
1676 /* Remove width of standout marker from usable width of line */
1677 if (TN_standout_width > 0)
1678 FRAME_WIDTH (selected_frame) -= TN_standout_width;
1679
1680 UseTabs = tabs_safe_p () && TabWidth == 8;
1681
1682 scroll_region_ok
1683 = (Wcm.cm_abs
1684 && (TS_set_window || TS_set_scroll_region || TS_set_scroll_region_1));
1685
1686 line_ins_del_ok = (((TS_ins_line || TS_ins_multi_lines)
1687 && (TS_del_line || TS_del_multi_lines))
1688 || (scroll_region_ok && TS_fwd_scroll && TS_rev_scroll));
1689
1690 char_ins_del_ok = ((TS_ins_char || TS_insert_mode
1691 || TS_pad_inserted_char || TS_ins_multi_chars)
1692 && (TS_del_char || TS_del_multi_chars));
1693
1694 fast_clear_end_of_line = TS_clr_line != 0;
1695
1696 init_baud_rate ();
1697 if (read_socket_hook) /* Baudrate is somewhat */
1698 /* meaningless in this case */
1699 baud_rate = 9600;
1700
1701 FRAME_CAN_HAVE_SCROLL_BARS (selected_frame) = 0;
1702 FRAME_HAS_VERTICAL_SCROLL_BARS (selected_frame) = 0;
1703 }
1704
1705 /* VARARGS 1 */
1706 fatal (str, arg1, arg2)
1707 char *str, *arg1, *arg2;
1708 {
1709 fprintf (stderr, "emacs: ");
1710 fprintf (stderr, str, arg1, arg2);
1711 fflush (stderr);
1712 exit (1);
1713 }
1714
1715 syms_of_term ()
1716 {
1717 DEFVAR_BOOL ("system-uses-terminfo", &system_uses_terminfo,
1718 "Non-nil means the system uses terminfo rather than termcap.\n\
1719 This variable can be used by terminal emulator packages.");
1720 #ifdef TERMINFO
1721 system_uses_terminfo = 1;
1722 #else
1723 system_uses_terminfo = 0;
1724 #endif
1725 }