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