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