summaryrefslogtreecommitdiff
path: root/src/term.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/term.c')
-rw-r--r--src/term.c1240
1 files changed, 1240 insertions, 0 deletions
diff --git a/src/term.c b/src/term.c
new file mode 100644
index 00000000000..c8a1ed0659a
--- /dev/null
+++ b/src/term.c
@@ -0,0 +1,1240 @@
+/* terminal control module for terminals described by TERMCAP
+ Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include "config.h"
+#include "termhooks.h"
+#include "termchar.h"
+#include "termopts.h"
+#include "cm.h"
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+#define OUTPUT(a) tputs (a, screen_height - curY, cmputc)
+#define OUTPUT1(a) tputs (a, 1, cmputc)
+#define OUTPUTL(a, lines) tputs (a, lines, cmputc)
+#define OUTPUT_IF(a) { if (a) tputs (a, screen_height - curY, cmputc); }
+#define OUTPUT1_IF(a) { if (a) tputs (a, 1, cmputc); }
+
+/* Terminal charateristics that higher levels want to look at.
+ These are all extern'd in termchar.h */
+
+int screen_width; /* Number of usable columns */
+int screen_height; /* Number of lines */
+int must_write_spaces; /* Nonzero means spaces in the text
+ must actually be output; can't just skip
+ over some columns to leave them blank. */
+int min_padding_speed; /* Speed below which no padding necessary */
+
+int line_ins_del_ok; /* Terminal can insert and delete lines */
+int char_ins_del_ok; /* Terminal can insert and delete chars */
+int scroll_region_ok; /* Terminal supports setting the scroll window */
+int memory_below_screen; /* Terminal remembers lines scrolled off bottom */
+int fast_clear_end_of_line; /* Terminal has a `ce' string */
+
+int dont_calculate_costs; /* Nonzero means don't bother computing */
+ /* various cost tables; we won't use them. */
+
+/* Nonzero means no need to redraw the entire screen on resuming
+ a suspended Emacs. This is useful on terminals with multiple pages,
+ where one page is used for Emacs and another for all else. */
+int no_redraw_on_reenter;
+
+/* DCICcost[n] is cost of inserting N characters.
+ DCICcost[-n] is cost of deleting N characters. */
+
+#define DCICcost (&DC_ICcost[screen_width])
+int *DC_ICcost;
+
+/* Hook functions that you can set to snap out the functions in this file.
+ These are all extern'd in termhooks.h */
+
+int (*move_cursor_hook) ();
+int (*raw_move_cursor_hook) ();
+
+int (*clear_to_end_hook) ();
+int (*clear_screen_hook) ();
+int (*clear_end_of_line_hook) ();
+
+int (*ins_del_lines_hook) ();
+
+int (*change_line_highlight_hook) ();
+int (*reassert_line_highlight_hook) ();
+
+int (*insert_chars_hook) ();
+int (*output_chars_hook) ();
+int (*delete_chars_hook) ();
+
+int (*ring_bell_hook) ();
+
+int (*reset_terminal_modes_hook) ();
+int (*set_terminal_modes_hook) ();
+int (*update_begin_hook) ();
+int (*update_end_hook) ();
+int (*set_terminal_window_hook) ();
+
+int (*read_socket_hook) ();
+int (*fix_screen_hook) ();
+int (*calculate_costs_hook) ();
+
+/* Strings, numbers and flags taken from the termcap entry. */
+
+char *TS_ins_line; /* termcap "al" */
+char *TS_ins_multi_lines; /* "AL" (one parameter, # lines to insert) */
+char *TS_bell; /* "bl" */
+char *TS_clr_to_bottom; /* "cd" */
+char *TS_clr_line; /* "ce", clear to end of line */
+char *TS_clr_screen; /* "cl" */
+char *TS_set_scroll_region; /* "cs" (2 params, first line and last line) */
+char *TS_set_scroll_region_1; /* "cS" (4 params: total lines,
+ lines above scroll region, lines below it,
+ total lines again) */
+char *TS_del_char; /* "dc" */
+char *TS_del_multi_chars; /* "DC" (one parameter, # chars to delete) */
+char *TS_del_line; /* "dl" */
+char *TS_del_multi_lines; /* "DL" (one parameter, # lines to delete) */
+char *TS_delete_mode; /* "dm", enter character-delete mode */
+char *TS_end_delete_mode; /* "ed", leave character-delete mode */
+char *TS_end_insert_mode; /* "ei", leave character-insert mode */
+char *TS_ins_char; /* "ic" */
+char *TS_ins_multi_chars; /* "IC" (one parameter, # chars to insert) */
+char *TS_insert_mode; /* "im", enter character-insert mode */
+char *TS_pad_inserted_char; /* "ip". Just padding, no commands. */
+char *TS_end_keypad_mode; /* "ke" */
+char *TS_keypad_mode; /* "ks" */
+char *TS_pad_char; /* "pc", char to use as padding */
+char *TS_repeat; /* "rp" (2 params, # times to repeat
+ and character to be repeated) */
+char *TS_end_standout_mode; /* "se" */
+char *TS_fwd_scroll; /* "sf" */
+char *TS_standout_mode; /* "so" */
+char *TS_rev_scroll; /* "sr" */
+char *TS_end_termcap_modes; /* "te" */
+char *TS_termcap_modes; /* "ti" */
+char *TS_visible_bell; /* "vb" */
+char *TS_end_visual_mode; /* "ve" */
+char *TS_visual_mode; /* "vi" */
+char *TS_set_window; /* "wi" (4 params, start and end of window,
+ each as vpos and hpos) */
+
+int TF_hazeltine; /* termcap hz flag. */
+int TF_insmode_motion; /* termcap mi flag: can move while in insert mode. */
+int TF_standout_motion; /* termcap mi flag: can move while in standout mode. */
+int TF_underscore; /* termcap ul flag: _ underlines if overstruck on
+ nonblank position. Must clear before writing _. */
+int TF_teleray; /* termcap xt flag: many weird consequences. For t1061. */
+
+int TF_xs; /* Nonzero for "xs". If set together with
+ TN_standout_width == 0, it means don't bother
+ to write any end-standout cookies. */
+
+int TN_standout_width; /* termcap sg number: width occupied by standout markers */
+
+static int RPov; /* # chars to start a TS_repeat */
+
+static int delete_in_insert_mode; /* delete mode == insert mode */
+
+static int se_is_so; /* 1 if same string both enters and leaves standout mode */
+
+/* internal state */
+
+/* Number of chars of space used for standout marker at beginning of line,
+ or'd with 0100. Zero if no standout marker at all. */
+/* used iff TN_standout_width >= 0. */
+char *chars_wasted;
+static char *copybuf;
+
+/* nonzero means supposed to write text in standout mode. */
+int standout_requested;
+
+int insert_mode; /* Nonzero when in insert mode. */
+int standout_mode; /* Nonzero when in standout mode. */
+
+/* Size of window specified by higher levels.
+ This is the number of lines, starting from top of screen,
+ to participate in ins/del line operations.
+ Effectively it excludes the bottom
+ screen_height - specified_window_size
+ lines from those operations. */
+
+int specified_window;
+
+char *tparam ();
+
+ring_bell ()
+{
+ if (ring_bell_hook)
+ {
+ (*ring_bell_hook) ();
+ return;
+ }
+ OUTPUT (TS_visible_bell && visible_bell ? TS_visible_bell : TS_bell);
+}
+
+set_terminal_modes ()
+{
+ if (set_terminal_modes_hook)
+ {
+ (*set_terminal_modes_hook) ();
+ return;
+ }
+ OUTPUT_IF (TS_termcap_modes);
+ OUTPUT_IF (TS_visual_mode);
+ OUTPUT_IF (TS_keypad_mode);
+ losecursor ();
+}
+
+reset_terminal_modes ()
+{
+ if (reset_terminal_modes_hook)
+ {
+ (*reset_terminal_modes_hook) ();
+ return;
+ }
+ if (TN_standout_width < 0)
+ turn_off_highlight ();
+ turn_off_insert ();
+ OUTPUT_IF (TS_end_keypad_mode);
+ OUTPUT_IF (TS_end_visual_mode);
+ OUTPUT_IF (TS_end_termcap_modes);
+}
+
+update_begin ()
+{
+ if (update_begin_hook)
+ (*update_begin_hook) ();
+}
+
+update_end ()
+{
+ if (update_end_hook)
+ {
+ (*update_end_hook) ();
+ return;
+ }
+ turn_off_insert ();
+ background_highlight ();
+ standout_requested = 0;
+}
+
+set_terminal_window (size)
+ int size;
+{
+ if (set_terminal_window_hook)
+ {
+ (*set_terminal_window_hook) (size);
+ return;
+ }
+ specified_window = size ? size : screen_height;
+ if (!scroll_region_ok)
+ return;
+ set_scroll_region (0, specified_window);
+}
+
+set_scroll_region (start, stop)
+ int start, stop;
+{
+ char *buf;
+ if (TS_set_scroll_region)
+ {
+ buf = tparam (TS_set_scroll_region, 0, 0, start, stop - 1);
+ }
+ else if (TS_set_scroll_region_1)
+ {
+ buf = tparam (TS_set_scroll_region_1, 0, 0,
+ screen_height, start, screen_height - stop, screen_height);
+ }
+ else
+ {
+ buf = tparam (TS_set_window, 0, 0, start, 0, stop, screen_width);
+ }
+ OUTPUT (buf);
+ free (buf);
+ losecursor ();
+}
+
+turn_on_insert ()
+{
+ if (!insert_mode)
+ OUTPUT (TS_insert_mode);
+ insert_mode = 1;
+}
+
+turn_off_insert ()
+{
+ if (insert_mode)
+ OUTPUT (TS_end_insert_mode);
+ insert_mode = 0;
+}
+
+/* Handle highlighting when TN_standout_width (termcap sg) is not specified.
+ In these terminals, output is affected by the value of standout
+ mode when the output is written.
+
+ These functions are called on all terminals, but do nothing
+ on terminals whose standout mode does not work that way. */
+
+turn_off_highlight ()
+{
+ if (TN_standout_width < 0)
+ {
+ if (standout_mode)
+ OUTPUT_IF (TS_end_standout_mode);
+ standout_mode = 0;
+ }
+}
+
+turn_on_highlight ()
+{
+ if (TN_standout_width < 0)
+ {
+ if (!standout_mode)
+ OUTPUT_IF (TS_standout_mode);
+ standout_mode = 1;
+ }
+}
+
+/* Set standout mode to the state it should be in for
+ empty space inside windows. What this is,
+ depends on the user option inverse-video. */
+
+background_highlight ()
+{
+ if (TN_standout_width >= 0)
+ return;
+ if (inverse_video)
+ turn_on_highlight ();
+ else
+ turn_off_highlight ();
+}
+
+/* Set standout mode to the mode specified for the text to be output. */
+
+static
+highlight_if_desired ()
+{
+ if (TN_standout_width >= 0)
+ return;
+ if (!inverse_video == !standout_requested)
+ turn_off_highlight ();
+ else
+ turn_on_highlight ();
+}
+
+/* Handle standout mode for terminals in which TN_standout_width >= 0.
+ On these terminals, standout is controlled by markers that
+ live inside the screen memory. TN_standout_width is the width
+ that the marker occupies in memory. Standout runs from the marker
+ to the end of the line on some terminals, or to the next
+ turn-off-standout marker (TS_end_standout_mode) string
+ on other terminals. */
+
+/* Write a standout marker or end-standout marker at the front of the line
+ at vertical position vpos. */
+
+write_standout_marker (flag, vpos)
+ int flag, vpos;
+{
+ if (flag || (TS_end_standout_mode && !TF_teleray && !se_is_so
+ && !(TF_xs && TN_standout_width == 0)))
+ {
+ cmgoto (vpos, 0);
+ cmplus (TN_standout_width);
+ OUTPUT (flag ? TS_standout_mode : TS_end_standout_mode);
+ chars_wasted[curY] = TN_standout_width | 0100;
+ }
+}
+
+/* External interface to control of standout mode.
+ Call this when about to modify line at position VPOS
+ and not change whether it is highlighted. */
+
+reassert_line_highlight (highlight, vpos)
+ int highlight;
+ int vpos;
+{
+ if (reassert_line_highlight_hook)
+ {
+ (*reassert_line_highlight_hook) (highlight, vpos);
+ return;
+ }
+ if (TN_standout_width < 0)
+ /* Handle terminals where standout takes affect at output time */
+ standout_requested = highlight;
+ else if (chars_wasted[vpos] == 0)
+ /* For terminals with standout markers, write one on this line
+ if there isn't one already. */
+ write_standout_marker (highlight, vpos);
+}
+
+/* Call this when about to modify line at position VPOS
+ and change whether it is highlighted. */
+
+change_line_highlight (new_highlight, vpos, first_unused_hpos)
+ int new_highlight, vpos, first_unused_hpos;
+{
+ standout_requested = new_highlight;
+ if (change_line_highlight_hook)
+ {
+ (*change_line_highlight_hook) (new_highlight, vpos, first_unused_hpos);
+ return;
+ }
+
+ move_cursor (vpos, 0);
+
+ if (TN_standout_width < 0)
+ background_highlight ();
+ /* If line starts with a marker, delete the marker */
+ else if (TS_clr_line && chars_wasted[curY])
+ {
+ turn_off_insert ();
+ /* On Teleray, make sure to erase the SO marker. */
+ if (TF_teleray)
+ {
+ cmgoto (curY - 1, screen_width - 4);
+ OUTPUT ("\033S");
+ curY++; /* ESC S moves to next line where the TS_standout_mode was */
+ curX = 0;
+ }
+ else
+ cmgoto (curY, 0); /* reposition to kill standout marker */
+ }
+ clear_end_of_line_raw (first_unused_hpos);
+ reassert_line_highlight (new_highlight, curY);
+}
+
+/* Move to absolute position, specified origin 0 */
+
+move_cursor (row, col)
+{
+ col += chars_wasted[row] & 077;
+ if (move_cursor_hook)
+ {
+ (*move_cursor_hook) (row, col);
+ return;
+ }
+ if (curY == row && curX == col)
+ return;
+ if (!TF_standout_motion)
+ background_highlight ();
+ if (!TF_insmode_motion)
+ turn_off_insert ();
+ cmgoto (row, col);
+}
+
+/* Similar but don't take any account of the wasted characters. */
+
+raw_move_cursor (row, col)
+{
+ if (raw_move_cursor_hook)
+ {
+ (*raw_move_cursor_hook) (row, col);
+ return;
+ }
+ if (curY == row && curX == col)
+ return;
+ if (!TF_standout_motion)
+ background_highlight ();
+ if (!TF_insmode_motion)
+ turn_off_insert ();
+ cmgoto (row, col);
+}
+
+/* Erase operations */
+
+/* clear from cursor to end of screen */
+clear_to_end ()
+{
+ register int i;
+
+ if (clear_to_end_hook)
+ {
+ (*clear_to_end_hook) ();
+ return;
+ }
+ if (TS_clr_to_bottom)
+ {
+ background_highlight ();
+ OUTPUT (TS_clr_to_bottom);
+ bzero (chars_wasted + curY, screen_height - curY);
+ }
+ else
+ {
+ for (i = curY; i < screen_height; i++)
+ {
+ move_cursor (i, 0);
+ clear_end_of_line_raw (screen_width);
+ }
+ }
+}
+
+/* Clear entire screen */
+
+clear_screen ()
+{
+ if (clear_screen_hook)
+ {
+ (*clear_screen_hook) ();
+ return;
+ }
+ if (TS_clr_screen)
+ {
+ background_highlight ();
+ OUTPUT (TS_clr_screen);
+ bzero (chars_wasted, screen_height);
+ cmat (0, 0);
+ }
+ else
+ {
+ move_cursor (0, 0);
+ clear_to_end ();
+ }
+}
+
+/* Clear to end of line, but do not clear any standout marker.
+ Assumes that the cursor is positioned at a character of real text,
+ which implies it cannot be before a standout marker
+ unless the marker has zero width.
+
+ Note that the cursor may be moved. */
+
+clear_end_of_line (first_unused_hpos)
+ int first_unused_hpos;
+{
+ if (TN_standout_width == 0 && curX == 0 && chars_wasted[curY] != 0)
+ output_chars (" ", 1);
+ clear_end_of_line_raw (first_unused_hpos);
+}
+
+/* Clear from cursor to end of line.
+ Assume that the line is already clear starting at column first_unused_hpos.
+ If the cursor is at a standout marker, erase the marker.
+
+ Note that the cursor may be moved, on terminals lacking a `ce' string. */
+
+clear_end_of_line_raw (first_unused_hpos)
+ int first_unused_hpos;
+{
+ register int i;
+ first_unused_hpos += chars_wasted[curY] & 077;
+ if (clear_end_of_line_hook)
+ {
+ (*clear_end_of_line_hook) (first_unused_hpos);
+ return;
+ }
+ if (curX >= first_unused_hpos)
+ return;
+ /* Notice if we are erasing a magic cookie */
+ if (curX == 0)
+ chars_wasted[curY] = 0;
+ background_highlight ();
+ if (TS_clr_line)
+ {
+ OUTPUT1 (TS_clr_line);
+ }
+ else
+ { /* have to do it the hard way */
+ turn_off_insert ();
+ for (i = curX; i < first_unused_hpos; i++)
+ {
+ if (termscript)
+ fputc (' ', termscript);
+ putchar (' ');
+ }
+ cmplus (first_unused_hpos - curX);
+ }
+}
+
+output_chars (string, len)
+ register char *string;
+ int len;
+{
+ register char *p;
+ register int n;
+ register char *buf;
+ register int c;
+ char *first_check;
+
+ if (output_chars_hook)
+ {
+ (*output_chars_hook) (string, len);
+ return;
+ }
+ highlight_if_desired ();
+ turn_off_insert ();
+
+ /* Don't dare write in last column of bottom line, if AutoWrap,
+ since that would scroll the whole screen on some terminals. */
+
+ if (AutoWrap && curY + 1 == screen_height
+ && curX + len - (chars_wasted[curY] & 077) == screen_width)
+ len --;
+
+ cmplus (len);
+
+ first_check = string;
+
+ if (RPov > len && !TF_underscore && !TF_hazeltine)
+ {
+ fwrite (string, 1, len, stdout);
+ if (ferror (stdout))
+ clearerr (stdout);
+ if (termscript)
+ fwrite (string, 1, len, termscript);
+ }
+ else
+ while (--len >= 0)
+ {
+ c = *string;
+ if (RPov + 1 < len && string >= first_check)
+ {
+ int repeat_count;
+
+ p = string + 1;
+
+ /* Now, len is number of chars left starting at p */
+ while (*p++ == c);
+ p--;
+
+ repeat_count = p - string;
+ if (repeat_count > RPov)
+ {
+ buf = tparam (TS_repeat, 0, 0, *string, repeat_count);
+ tputs (buf, repeat_count, cmputc);
+ free (buf);
+ string = p;
+ len -= repeat_count - 1;
+ continue;
+ }
+ else
+ /* If all N identical chars are too few,
+ don't even consider the last N-1, the last N-2,... */
+ first_check = p;
+ }
+ if (c == '_' && TF_underscore)
+ {
+ if (termscript)
+ fputc (' ', termscript);
+ putchar (' ');
+ OUTPUT (Left);
+ }
+ if (TF_hazeltine && c == '~')
+ c = '`';
+ if (termscript)
+ fputc (c, termscript);
+ putchar (c);
+ string++;
+ }
+}
+
+/* If start is zero, insert blanks instead of a string at start */
+
+insert_chars (start, len)
+ register char *start;
+ int len;
+{
+ register char *buf;
+ register int c;
+
+ if (insert_chars_hook)
+ {
+ (*insert_chars_hook) (start, len);
+ return;
+ }
+ highlight_if_desired ();
+
+ if (TS_ins_multi_chars)
+ {
+ buf = tparam (TS_ins_multi_chars, 0, 0, len);
+ OUTPUT1 (buf);
+ free (buf);
+ if (start)
+ output_chars (start, len);
+ return;
+ }
+
+ turn_on_insert ();
+ cmplus (len);
+
+ if (!TF_underscore && !TF_hazeltine && start
+ && TS_pad_inserted_char == 0 && TS_ins_char == 0)
+ {
+ fwrite (start, 1, len, stdout);
+ if (termscript)
+ fwrite (start, 1, len, termscript);
+ }
+ else
+ while (--len >= 0)
+ {
+ OUTPUT1_IF (TS_ins_char);
+ if (!start)
+ c = ' ';
+ else
+ {
+ c = *start++;
+ if (TF_hazeltine && c == '~')
+ c = '`';
+ }
+ if (termscript)
+ fputc (c, termscript);
+ putchar (c);
+ OUTPUT1_IF (TS_pad_inserted_char);
+ }
+}
+
+delete_chars (n)
+ register int n;
+{
+ char *buf;
+ register int i;
+
+ if (delete_chars_hook)
+ {
+ (*delete_chars_hook) (n);
+ return;
+ }
+
+ if (delete_in_insert_mode)
+ {
+ turn_on_insert ();
+ }
+ else
+ {
+ turn_off_insert ();
+ OUTPUT_IF (TS_delete_mode);
+ }
+
+ if (TS_del_multi_chars)
+ {
+ buf = tparam (TS_del_multi_chars, 0, 0, n);
+ OUTPUT1 (buf);
+ free (buf);
+ }
+ else
+ for (i = 0; i < n; i++)
+ OUTPUT1 (TS_del_char);
+ if (!delete_in_insert_mode)
+ OUTPUT_IF (TS_end_delete_mode);
+}
+
+/* Insert N lines at vpos VPOS. If N is negative, delete -N lines. */
+
+ins_del_lines (vpos, n)
+ int vpos, n;
+{
+ char *multi = n > 0 ? TS_ins_multi_lines : TS_del_multi_lines;
+ char *single = n > 0 ? TS_ins_line : TS_del_line;
+ char *scroll = n > 0 ? TS_rev_scroll : TS_fwd_scroll;
+
+ register int i = n > 0 ? n : -n;
+ register char *buf;
+
+ if (ins_del_lines_hook)
+ {
+ (*ins_del_lines_hook) (vpos, n);
+ return;
+ }
+
+ /* If the lines below the insertion are being pushed
+ into the end of the window, this is the same as clearing;
+ and we know the lines are already clear, since the matching
+ deletion has already been done. So can ignore this. */
+ /* If the lines below the deletion are blank lines coming
+ out of the end of the window, don't bother,
+ as there will be a matching inslines later that will flush them. */
+ if (scroll_region_ok && vpos + i >= specified_window)
+ return;
+ if (!memory_below_screen && vpos + i >= screen_height)
+ return;
+
+ if (multi)
+ {
+ raw_move_cursor (vpos, 0);
+ background_highlight ();
+ buf = tparam (multi, 0, 0, i);
+ OUTPUT (buf);
+ free (buf);
+ }
+ else if (single)
+ {
+ raw_move_cursor (vpos, 0);
+ background_highlight ();
+ while (--i >= 0)
+ OUTPUT (single);
+ if (TF_teleray)
+ curX = 0;
+ }
+ else
+ {
+ set_scroll_region (vpos, specified_window);
+ if (n < 0)
+ raw_move_cursor (specified_window - 1, 0);
+ else
+ raw_move_cursor (vpos, 0);
+ background_highlight ();
+ while (--i >= 0)
+ OUTPUTL (scroll, specified_window - vpos);
+ set_scroll_region (0, specified_window);
+ }
+
+ if (TN_standout_width >= 0)
+ {
+ register lower_limit
+ = scroll_region_ok ? specified_window : screen_height;
+ if (n < 0)
+ {
+ bcopy (&chars_wasted[vpos - n], &chars_wasted[vpos],
+ lower_limit - vpos + n);
+ bzero (&chars_wasted[lower_limit + n], - n);
+ }
+ else
+ {
+ bcopy (&chars_wasted[vpos], &copybuf[vpos], lower_limit - vpos - n);
+ bcopy (&copybuf[vpos], &chars_wasted[vpos + n],
+ lower_limit - vpos - n);
+ bzero (&chars_wasted[vpos], n);
+ }
+ }
+ if (!scroll_region_ok && memory_below_screen && n < 0)
+ {
+ move_cursor (screen_height + n, 0);
+ clear_to_end ();
+ }
+}
+
+extern int cost; /* In cm.c */
+extern evalcost ();
+
+/* Compute cost of sending "str", in characters,
+ not counting any line-dependent padding. */
+string_cost (str)
+ char *str;
+{
+ cost = 0;
+ if (str)
+ tputs (str, 0, evalcost);
+ return cost;
+}
+
+/* Compute cost of sending "str", in characters,
+ counting any line-dependent padding at one line. */
+string_cost_one_line (str)
+ char *str;
+{
+ cost = 0;
+ if (str)
+ tputs (str, 1, evalcost);
+ return cost;
+}
+
+/* Compute per line amount of line-dependent padding,
+ in tenths of characters. */
+per_line_cost (str)
+ register char *str;
+{
+ cost = 0;
+ if (str)
+ tputs (str, 0, evalcost);
+ cost = - cost;
+ if (str)
+ tputs (str, 10, evalcost);
+ return cost;
+}
+
+/* ARGSUSED */
+calculate_ins_del_char_costs ()
+{
+ int ins_startup_cost, del_startup_cost;
+ int ins_cost_per_char, del_cost_per_char;
+ register int i;
+ register int *p;
+
+ if (TS_ins_multi_chars)
+ {
+ ins_cost_per_char = 0;
+ ins_startup_cost = string_cost_one_line (TS_ins_multi_chars);
+ }
+ else if (TS_ins_char || TS_pad_inserted_char
+ || (TS_insert_mode && TS_end_insert_mode))
+ {
+ ins_startup_cost = (30 * (string_cost (TS_insert_mode) + string_cost (TS_end_insert_mode))) / 100;
+ ins_cost_per_char = (string_cost_one_line (TS_ins_char)
+ + string_cost_one_line (TS_pad_inserted_char));
+ }
+ else
+ {
+ ins_startup_cost = 9999;
+ ins_cost_per_char = 0;
+ }
+
+ if (TS_del_multi_chars)
+ {
+ del_cost_per_char = 0;
+ del_startup_cost = string_cost_one_line (TS_del_multi_chars);
+ }
+ else if (TS_del_char)
+ {
+ del_startup_cost = (string_cost (TS_delete_mode)
+ + string_cost (TS_end_delete_mode));
+ if (delete_in_insert_mode)
+ del_startup_cost /= 2;
+ del_cost_per_char = string_cost_one_line (TS_del_char);
+ }
+ else
+ {
+ del_startup_cost = 9999;
+ del_cost_per_char = 0;
+ }
+
+ /* Delete costs are at negative offsets */
+ p = &DCICcost[0];
+ for (i = screen_width; --i >= 0;)
+ *--p = (del_startup_cost += del_cost_per_char);
+
+ /* Doing nothing is free */
+ p = &DCICcost[0];
+ *p++ = 0;
+
+ /* Insert costs are at positive offsets */
+ for (i = screen_width; --i >= 0;)
+ *p++ = (ins_startup_cost += ins_cost_per_char);
+}
+
+calculate_costs ()
+{
+ register char *s
+ = TS_set_scroll_region ? TS_set_scroll_region : TS_set_scroll_region_1;
+
+ if (chars_wasted != 0)
+ chars_wasted = (char *) xrealloc (chars_wasted, screen_height);
+ else
+ chars_wasted = (char *) xmalloc (screen_height);
+ bzero (chars_wasted, screen_height);
+
+ if (copybuf != 0)
+ copybuf = (char *) xrealloc (copybuf, screen_height);
+ else
+ copybuf = (char *) xmalloc (screen_height);
+
+ if (DC_ICcost != 0)
+ DC_ICcost = (int *) xrealloc (DC_ICcost,
+ (2 * screen_width + 1) * sizeof (int));
+ else
+ DC_ICcost = (int *) xmalloc ((2 * screen_width + 1) * sizeof (int));
+
+ /* Always call CalcIDCosts because it allocates some vectors.
+ That function handles dont_calculate_costs. */
+ if (s && (!TS_ins_line && !TS_del_line))
+ CalcIDCosts (TS_rev_scroll, TS_ins_multi_lines,
+ TS_fwd_scroll, TS_del_multi_lines,
+ s, s);
+ else
+ CalcIDCosts (TS_ins_line, TS_ins_multi_lines,
+ TS_del_line, TS_del_multi_lines,
+ 0, 0);
+
+ if (dont_calculate_costs)
+ {
+ bzero (DC_ICcost, 2 * screen_width * sizeof (int));
+ return;
+ }
+
+ calculate_ins_del_char_costs ();
+
+ /* Don't use TS_repeat if its padding is worse than sending the chars */
+ if (TS_repeat && per_line_cost (TS_repeat) * baud_rate < 9000)
+ RPov = string_cost (TS_repeat);
+ else
+ RPov = screen_width * 2;
+
+ cmcostinit (); /* set up cursor motion costs */
+}
+
+term_init (terminal_type)
+ char *terminal_type;
+{
+ char *area;
+ char **address = &area;
+ char buffer[4092];
+ register char *p;
+ int status;
+
+ extern char *tgetstr ();
+
+ Wcm_clear ();
+ dont_calculate_costs = 0;
+
+ status = tgetent (buffer, terminal_type);
+ if (status < 0)
+ fatal ("Cannot open termcap database file.\n");
+ if (status == 0)
+ fatal ("Terminal type %s is not defined.\n", terminal_type);
+
+#ifdef TERMINFO
+ area = (char *) malloc (4092);
+#else
+ area = (char *) malloc (strlen (buffer));
+#endif /* not TERMINFO */
+ if (area == 0)
+ abort ();
+
+ TS_ins_line = tgetstr ("al", address);
+ TS_ins_multi_lines = tgetstr ("AL", address);
+ TS_bell = tgetstr ("bl", address);
+ TS_clr_to_bottom = tgetstr ("cd", address);
+ TS_clr_line = tgetstr ("ce", address);
+ TS_clr_screen = tgetstr ("cl", address);
+ ColPosition = tgetstr ("ch", address);
+ AbsPosition = tgetstr ("cm", address);
+ CR = tgetstr ("cr", address);
+ TS_set_scroll_region = tgetstr ("cs", address);
+ TS_set_scroll_region_1 = tgetstr ("cS", address);
+ RowPosition = tgetstr ("cv", address);
+ TS_del_char = tgetstr ("dc", address);
+ TS_del_multi_chars = tgetstr ("DC", address);
+ TS_del_line = tgetstr ("dl", address);
+ TS_del_multi_lines = tgetstr ("DL", address);
+ TS_delete_mode = tgetstr ("dm", address);
+ TS_end_delete_mode = tgetstr ("ed", address);
+ TS_end_insert_mode = tgetstr ("ei", address);
+ Home = tgetstr ("ho", address);
+ TS_ins_char = tgetstr ("ic", address);
+ TS_ins_multi_chars = tgetstr ("IC", address);
+ TS_insert_mode = tgetstr ("im", address);
+ TS_pad_inserted_char = tgetstr ("ip", address);
+ TS_end_keypad_mode = tgetstr ("ke", address);
+ TS_keypad_mode = tgetstr ("ks", address);
+ LastLine = tgetstr ("ll", address);
+ Right = tgetstr ("nd", address);
+ Down = tgetstr ("do", address);
+ if (!Down)
+ Down = tgetstr ("nl", address); /* Obsolete name for "do" */
+#ifdef VMS
+ /* VMS puts a carriage return before each linefeed,
+ so it is not safe to use linefeeds. */
+ if (Down && Down[0] == '\n' && Down[1] == '\0')
+ Down = 0;
+#endif /* VMS */
+ if (tgetflag ("bs"))
+ Left = "\b"; /* can't possibly be longer! */
+ else /* (Actually, "bs" is obsolete...) */
+ Left = tgetstr ("le", address);
+ if (!Left)
+ Left = tgetstr ("bc", address); /* Obsolete name for "le" */
+ TS_pad_char = tgetstr ("pc", address);
+ TS_repeat = tgetstr ("rp", address);
+ TS_end_standout_mode = tgetstr ("se", address);
+ TS_fwd_scroll = tgetstr ("sf", address);
+ TS_standout_mode = tgetstr ("so", address);
+ TS_rev_scroll = tgetstr ("sr", address);
+ Wcm.cm_tab = tgetstr ("ta", address);
+ TS_end_termcap_modes = tgetstr ("te", address);
+ TS_termcap_modes = tgetstr ("ti", address);
+ Up = tgetstr ("up", address);
+ TS_visible_bell = tgetstr ("vb", address);
+ TS_end_visual_mode = tgetstr ("ve", address);
+ TS_visual_mode = tgetstr ("vs", address);
+ TS_set_window = tgetstr ("wi", address);
+
+ AutoWrap = tgetflag ("am");
+ memory_below_screen = tgetflag ("db");
+ TF_hazeltine = tgetflag ("hz");
+ must_write_spaces = tgetflag ("in");
+ meta_key = tgetflag ("km") || tgetflag ("MT");
+ TF_insmode_motion = tgetflag ("mi");
+ TF_standout_motion = tgetflag ("ms");
+ TF_underscore = tgetflag ("ul");
+ MagicWrap = tgetflag ("xn");
+ TF_xs = tgetflag ("xs");
+ TF_teleray = tgetflag ("xt");
+
+ /* Get screen size from system, or else from termcap. */
+ get_screen_size (&screen_width, &screen_height);
+ if (screen_width <= 0)
+ screen_width = tgetnum ("co");
+ if (screen_height <= 0)
+ screen_height = tgetnum ("li");
+
+ min_padding_speed = tgetnum ("pb");
+ TN_standout_width = tgetnum ("sg");
+ TabWidth = tgetnum ("tw");
+
+#ifdef VMS
+ /* These capabilities commonly use ^J.
+ I don't know why, but sending them on VMS does not work;
+ it causes following spaces to be lost, sometimes.
+ For now, the simplest fix is to avoid using these capabilities ever. */
+ if (Down && Down[0] == '\n')
+ Down = 0;
+#endif /* VMS */
+
+ if (!TS_bell)
+ TS_bell = "\07";
+
+ if (!TS_fwd_scroll)
+ TS_fwd_scroll = Down;
+
+ PC = TS_pad_char ? *TS_pad_char : 0;
+
+ if (TabWidth < 0)
+ TabWidth = 8;
+
+/* Turned off since /etc/termcap seems to have :ta= for most terminals
+ and newer termcap doc does not seem to say there is a default.
+ if (!Wcm.cm_tab)
+ Wcm.cm_tab = "\t";
+*/
+
+ if (TS_standout_mode == 0)
+ {
+ TN_standout_width = tgetnum ("ug");
+ TS_end_standout_mode = tgetstr ("ue", address);
+ TS_standout_mode = tgetstr ("us", address);
+ }
+
+ if (TF_teleray)
+ {
+ Wcm.cm_tab = 0;
+ /* Teleray: most programs want a space in front of TS_standout_mode,
+ but Emacs can do without it (and give one extra column). */
+ TS_standout_mode = "\033RD";
+ TN_standout_width = 1;
+ /* But that means we cannot rely on ^M to go to column zero! */
+ CR = 0;
+ /* LF can't be trusted either -- can alter hpos */
+ /* if move at column 0 thru a line with TS_standout_mode */
+ Down = 0;
+ }
+
+ /* Special handling for certain terminal types known to need it */
+
+ if (!strcmp (terminal_type, "supdup"))
+ {
+ memory_below_screen = 1;
+ Wcm.cm_losewrap = 1;
+ }
+ if (!strncmp (terminal_type, "c10", 3)
+ || !strcmp (terminal_type, "perq"))
+ {
+ /* Supply a makeshift :wi string.
+ This string is not valid in general since it works only
+ for windows starting at the upper left corner;
+ but that is all Emacs uses.
+
+ This string works only if the screen is using
+ the top of the video memory, because addressing is memory-relative.
+ So first check the :ti string to see if that is true.
+
+ It would be simpler if the :wi string could go in the termcap
+ entry, but it can't because it is not fully valid.
+ If it were in the termcap entry, it would confuse other programs. */
+ if (!TS_set_window)
+ {
+ p = TS_termcap_modes;
+ while (*p && strcmp (p, "\033v "))
+ p++;
+ if (*p)
+ TS_set_window = "\033v%C %C %C %C ";
+ }
+ /* Termcap entry often fails to have :in: flag */
+ must_write_spaces = 1;
+ /* :ti string typically fails to have \E^G! in it */
+ /* This limits scope of insert-char to one line. */
+ strcpy (area, TS_termcap_modes);
+ strcat (area, "\033\007!");
+ TS_termcap_modes = area;
+ area += strlen (area) + 1;
+ p = AbsPosition;
+ /* Change all %+ parameters to %C, to handle
+ values above 96 correctly for the C100. */
+ while (*p)
+ {
+ if (p[0] == '%' && p[1] == '+')
+ p[1] = 'C';
+ p++;
+ }
+ }
+
+ ScreenRows = screen_height;
+ ScreenCols = screen_width;
+ specified_window = screen_height;
+
+ if (Wcm_init ()) /* can't do cursor motion */
+#ifdef VMS
+ fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
+It lacks the ability to position the cursor.\n\
+If that is not the actual type of terminal you have, use either the\n\
+DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\
+or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.\n",
+ terminal_type);
+#else
+ fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
+It lacks the ability to position the cursor.\n\
+If that is not the actual type of terminal you have,\n\
+use the C-shell command `setenv TERM ...' to specify the correct type.\n\
+It may be necessary to do `unsetenv TERMCAP' as well.\n",
+ terminal_type);
+#endif
+
+ delete_in_insert_mode
+ = TS_delete_mode && TS_insert_mode
+ && !strcmp (TS_delete_mode, TS_insert_mode);
+
+ se_is_so = TS_standout_mode && TS_end_standout_mode
+ && !strcmp (TS_standout_mode, TS_end_standout_mode);
+
+ /* Remove width of standout marker from usable width of line */
+ if (TN_standout_width > 0)
+ screen_width -= TN_standout_width;
+
+ UseTabs = tabs_safe_p () && TabWidth == 8;
+
+ scroll_region_ok = TS_set_window || TS_set_scroll_region
+ || TS_set_scroll_region_1;
+
+ line_ins_del_ok = (((TS_ins_line || TS_ins_multi_lines)
+ && (TS_del_line || TS_del_multi_lines))
+ || (scroll_region_ok
+ && TS_fwd_scroll
+ && TS_rev_scroll));
+
+ char_ins_del_ok = ((TS_ins_char || TS_insert_mode ||
+ TS_pad_inserted_char || TS_ins_multi_chars)
+ && (TS_del_char || TS_del_multi_chars));
+
+ fast_clear_end_of_line = TS_clr_line != 0;
+
+ init_baud_rate ();
+ if (read_socket_hook) /* Baudrate is somewhat */
+ /* meaningless in this case */
+ baud_rate = 9600;
+}
+
+/* VARARGS 1 */
+fatal (str, arg1, arg2)
+ char *str;
+{
+ fprintf (stderr, "emacs: ");
+ fprintf (stderr, str, arg1, arg2);
+ fflush (stderr);
+ exit (1);
+}