|
|
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 distributed in the hope that it will be useful,
7: but WITHOUT ANY WARRANTY. No author or distributor
8: accepts responsibility to anyone for the consequences of using it
9: or for whether it serves any particular purpose or works at all,
10: unless he says so in writing. Refer to the GNU Emacs General Public
11: License for full details.
12:
13: Everyone is granted permission to copy, modify and redistribute
14: GNU Emacs, but only under the conditions described in the
15: GNU Emacs General Public License. A copy of this license is
16: supposed to have been given to you along with GNU Emacs so you
17: can know your rights and responsibilities. It should be in a
18: file named COPYING. Among other things, the copyright notice
19: and this notice must be preserved on all copies. */
20:
21:
22: #include <stdio.h>
23: #include <ctype.h>
24: #include "config.h"
25: #include "termhooks.h"
26: #include "termchar.h"
27: #include "termopts.h"
28: #include "cm.h"
29:
30: #define max(a, b) ((a) > (b) ? (a) : (b))
31: #define min(a, b) ((a) < (b) ? (a) : (b))
32:
33: #define OUTPUT(a) tputs (a, screen_height - curY, cmputc)
34: #define OUTPUT1(a) tputs (a, 1, cmputc)
35: #define OUTPUTL(a, lines) tputs (a, lines, cmputc)
36: #define OUTPUT_IF(a) { if (a) tputs (a, screen_height - curY, cmputc); }
37: #define OUTPUT1_IF(a) { if (a) tputs (a, 1, cmputc); }
38:
39: /* Terminal charateristics that higher levels want to look at.
40: These are all extern'd in termchar.h */
41:
42: int screen_width; /* Number of usable columns */
43: int screen_height; /* Number of lines */
44: int must_write_spaces; /* Nonzero means spaces in the text
45: must actually be output; can't just skip
46: over some columns to leave them blank. */
47: int min_padding_speed; /* Speed below which no padding necessary */
48:
49: int line_ins_del_ok; /* Terminal can insert and delete lines */
50: int char_ins_del_ok; /* Terminal can insert and delete chars */
51: int scroll_region_ok; /* Terminal supports setting the scroll window */
52: int memory_below_screen; /* Terminal remembers lines scrolled off bottom */
53: int fast_clear_end_of_line; /* Terminal has a `ce' string */
54:
55: int dont_calculate_costs; /* Nonzero means don't bother computing */
56: /* various cost tables; we won't use them. */
57:
58: /* Nonzero means no need to redraw the entire screen on resuming
59: a suspended Emacs. This is useful on terminals with multiple pages,
60: where one page is used for Emacs and another for all else. */
61: int no_redraw_on_reenter;
62:
63: /* DCICcost[n] is cost of inserting N characters.
64: DCICcost[-n] is cost of deleting N characters. */
65:
66: #define DCICcost (&DC_ICcost[MScreenWidth])
67: int DC_ICcost[1 + 2 * MScreenWidth];
68:
69:
70: /* Hook functions that you can set to snap out the functions in this file.
71: These are all extern'd in termhooks.h */
72:
73: int (*topos_hook) ();
74: int (*raw_topos_hook) ();
75:
76: int (*clear_to_end_hook) ();
77: int (*clear_screen_hook) ();
78: int (*clear_end_of_line_hook) ();
79:
80: int (*ins_del_lines_hook) ();
81:
82: int (*change_line_highlight_hook) ();
83: int (*reassert_line_highlight_hook) ();
84:
85: int (*insert_chars_hook) ();
86: int (*write_chars_hook) ();
87: int (*delete_chars_hook) ();
88:
89: int (*ring_bell_hook) ();
90:
91: int (*reset_terminal_modes_hook) ();
92: int (*set_terminal_modes_hook) ();
93: int (*update_begin_hook) ();
94: int (*update_end_hook) ();
95: int (*set_terminal_window_hook) ();
96:
97: int (*read_socket_hook) ();
98: int (*fix_screen_hook) ();
99:
100: /* Strings, numbers and flags taken from the termcap entry. */
101:
102: char *TS_ins_line; /* termcap "al" */
103: char *TS_ins_multi_lines; /* "AL" (one parameter, # lines to insert) */
104: char *TS_bell; /* "bl" */
105: char *TS_clr_to_bottom; /* "cd" */
106: char *TS_clr_line; /* "ce", clear to end of line */
107: char *TS_clr_screen; /* "cl" */
108: char *TS_set_scroll_region; /* "cs" (2 params, first line and last line) */
109: char *TS_set_scroll_region_1; /* "cS" (4 params: total lines,
110: lines above scroll region, lines below it,
111: total lines again) */
112: char *TS_del_char; /* "dc" */
113: char *TS_del_multi_chars; /* "DC" (one parameter, # chars to delete) */
114: char *TS_del_line; /* "dl" */
115: char *TS_del_multi_lines; /* "DL" (one parameter, # lines to delete) */
116: char *TS_delete_mode; /* "dm", enter character-delete mode */
117: char *TS_end_delete_mode; /* "ed", leave character-delete mode */
118: char *TS_end_insert_mode; /* "ei", leave character-insert mode */
119: char *TS_ins_char; /* "ic" */
120: char *TS_ins_multi_chars; /* "IC" (one parameter, # chars to insert) */
121: char *TS_insert_mode; /* "im", enter character-insert mode */
122: char *TS_pad_inserted_char; /* "ip". Just padding, no commands. */
123: char *TS_end_keypad_mode; /* "ke" */
124: char *TS_keypad_mode; /* "ks" */
125: char *TS_pad_char; /* "pc", char to use as padding */
126: char *TS_repeat; /* "rp" (2 params, # times to repeat
127: and character to be repeated) */
128: char *TS_end_standout_mode; /* "se" */
129: char *TS_fwd_scroll; /* "sf" */
130: char *TS_standout_mode; /* "so" */
131: char *TS_rev_scroll; /* "sr" */
132: char *TS_end_termcap_modes; /* "te" */
133: char *TS_termcap_modes; /* "ti" */
134: char *TS_visible_bell; /* "vb" */
135: char *TS_end_visual_mode; /* "ve" */
136: char *TS_visual_mode; /* "vi" */
137: char *TS_set_window; /* "wi" (4 params, start and end of window,
138: each as vpos and hpos) */
139:
140: int TF_hazeltine; /* termcap hz flag. */
141: int TF_insmode_motion; /* termcap mi flag: can move while in insert mode. */
142: int TF_standout_motion; /* termcap mi flag: can move while in standout mode. */
143: int TF_underscore; /* termcap ul flag: _ underlines if overstruck on
144: nonblank position. Must clear before writing _. */
145: int TF_teleray; /* termcap xt flag: many weird consequences. For t1061. */
146:
147: int TF_xs; /* Nonzero for "xs". If set together with
148: TN_standout_width == 0, it means don't bother
149: to write any end-standout cookies. */
150:
151: int TN_standout_width; /* termcap sg number: width occupied by standout markers */
152:
153: static int RPov; /* # chars to start a TS_repeat */
154:
155: static int delete_in_insert_mode; /* delete mode == insert mode */
156:
157: static int se_is_so; /* 1 if same string both enters and leaves standout mode */
158:
159: /* internal state */
160:
161: /* Number of chars of space used for standout marker at beginning of line,
162: or'd with 0100. Zero if no standout marker at all. */
163: /* used iff TN_standout_width >= 0. */
164: char chars_wasted[MScreenLength];
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: topos (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: topos (row, col)
428: {
429: col += chars_wasted[row] & 077;
430: if (topos_hook)
431: {
432: (*topos_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_topos (row, col)
447: {
448: if (raw_topos_hook)
449: {
450: (*raw_topos_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: topos (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: topos (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: write_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: write_chars (start, len)
568: register char *start;
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 (write_chars_hook)
578: {
579: (*write_chars_hook) (start, 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 = start;
595:
596: if (RPov > len && !TF_underscore && !TF_hazeltine)
597: {
598: fwrite (start, 1, len, stdout);
599: if (ferror (stdout))
600: clearerr (stdout);
601: if (termscript)
602: fwrite (start, 1, len, termscript);
603: }
604: else
605: while (--len >= 0)
606: {
607: if (RPov + 1 < len && start >= first_check && *start == start[1])
608: {
609: p = start + 2;
610:
611: /* Now, len is number of chars left starting at p */
612: while (*p++ == *start);
613: --p;
614: /* n is number of identical chars in this run */
615: n = p - start;
616: if (n > RPov)
617: {
618: buf = tparam (TS_repeat, 0, 0, *start, n);
619: tputs (buf, n, cmputc);
620: free (buf);
621: start = p;
622: len -= n - 1;
623: continue;
624: }
625: else
626: /* If all N identical chars are too few,
627: don't even consider the last N-1, the last N-2,... */
628: first_check = p;
629: }
630: c = *start++;
631: if (c == '_' && TF_underscore)
632: {
633: if (termscript)
634: fputc (' ', termscript);
635: putchar (' ');
636: OUTPUT (Left);
637: }
638: if (TF_hazeltine && c == '~')
639: c = '`';
640: if (termscript)
641: fputc (c, termscript);
642: putchar (c);
643: }
644: }
645:
646: /* If start is zero, insert blanks instead of a string at start */
647:
648: insert_chars (start, len)
649: register char *start;
650: int len;
651: {
652: register char *buf;
653: register int c;
654:
655: if (insert_chars_hook)
656: {
657: (*insert_chars_hook) (start, len);
658: return;
659: }
660: highlight_if_desired ();
661:
662: if (TS_ins_multi_chars)
663: {
664: buf = tparam (TS_ins_multi_chars, 0, 0, len);
665: OUTPUT1 (buf);
666: free (buf);
667: if (start)
668: write_chars (start, len);
669: return;
670: }
671:
672: turn_on_insert ();
673: cmplus (len);
674:
675: if (!TF_underscore && !TF_hazeltine && start
676: && TS_pad_inserted_char == 0 && TS_ins_char == 0)
677: {
678: fwrite (start, 1, len, stdout);
679: if (termscript)
680: fwrite (start, 1, len, termscript);
681: }
682: else
683: while (--len >= 0)
684: {
685: OUTPUT1_IF (TS_ins_char);
686: if (!start)
687: c = ' ';
688: else
689: {
690: c = *start++;
691: if (TF_hazeltine && c == '~')
692: c = '`';
693: }
694: if (termscript)
695: fputc (c, termscript);
696: putchar (c);
697: OUTPUT1_IF (TS_pad_inserted_char);
698: }
699: }
700:
701: delete_chars (n)
702: register int n;
703: {
704: char *buf;
705: register int i;
706:
707: if (delete_chars_hook)
708: {
709: (*delete_chars_hook) (n);
710: return;
711: }
712:
713: if (delete_in_insert_mode)
714: {
715: turn_on_insert ();
716: }
717: else
718: {
719: turn_off_insert ();
720: OUTPUT_IF (TS_delete_mode);
721: }
722:
723: if (TS_del_multi_chars)
724: {
725: buf = tparam (TS_del_multi_chars, 0, 0, n);
726: OUTPUT1 (buf);
727: free (buf);
728: }
729: else
730: for (i = 0; i < n; i++)
731: OUTPUT1 (TS_del_char);
732: if (!delete_in_insert_mode)
733: OUTPUT_IF (TS_end_delete_mode);
734: }
735:
736: /* Insert N lines at vpos VPOS. If N is negative, delete -N lines. */
737:
738: ins_del_lines (vpos, n)
739: int vpos, n;
740: {
741: char *multi = n > 0 ? TS_ins_multi_lines : TS_del_multi_lines;
742: char *single = n > 0 ? TS_ins_line : TS_del_line;
743: char *scroll = n > 0 ? TS_rev_scroll : TS_fwd_scroll;
744:
745: register int i = n > 0 ? n : -n;
746: register char *buf;
747: char copybuf[MScreenWidth];
748:
749: if (ins_del_lines_hook)
750: {
751: (*ins_del_lines_hook) (vpos, n);
752: return;
753: }
754:
755: /* If the lines below the insertion are being pushed
756: into the end of the window, this is the same as clearing;
757: and we know the lines are already clear, since the matching
758: deletion has already been done. So can ignore this. */
759: /* If the lines below the deletion are blank lines coming
760: out of the end of the window, don't bother,
761: as there will be a matching inslines later that will flush them. */
762: if (scroll_region_ok && vpos + i >= specified_window)
763: return;
764: if (!memory_below_screen && vpos + i >= screen_height)
765: return;
766:
767: if (multi)
768: {
769: raw_topos (vpos, 0);
770: background_highlight ();
771: buf = tparam (multi, 0, 0, i);
772: OUTPUT (buf);
773: free (buf);
774: }
775: else if (single)
776: {
777: raw_topos (vpos, 0);
778: background_highlight ();
779: while (--i >= 0)
780: OUTPUT (single);
781: if (TF_teleray)
782: curX = 0;
783: }
784: else
785: {
786: set_scroll_region (vpos, specified_window);
787: if (n < 0)
788: raw_topos (specified_window - 1, 0);
789: else
790: raw_topos (vpos, 0);
791: background_highlight ();
792: while (--i >= 0)
793: OUTPUTL (scroll, specified_window - vpos);
794: set_scroll_region (0, specified_window);
795: }
796:
797: if (TN_standout_width >= 0)
798: {
799: if (n < 0)
800: {
801: bcopy (&chars_wasted[curY - n], &chars_wasted[curY], screen_height - curY + n);
802: bzero (&chars_wasted[screen_height + n], - n);
803: }
804: else
805: {
806: bcopy (&chars_wasted[curY], ©buf[curY], screen_height - curY - n);
807: bcopy (©buf[curY], &chars_wasted[curY + n], screen_height - curY - n);
808: bzero (&chars_wasted[curY], n);
809: }
810: }
811: if (!scroll_region_ok && memory_below_screen && n < 0)
812: {
813: topos (screen_height + n, 0);
814: clear_to_end ();
815: }
816: }
817:
818: extern int cost; /* In cm.c */
819: extern evalcost ();
820:
821: /* Compute cost of sending "str", in characters,
822: not counting any line-dependent padding. */
823: string_cost (str)
824: char *str;
825: {
826: cost = 0;
827: if (str)
828: tputs (str, 0, evalcost);
829: return cost;
830: }
831:
832: /* Compute cost of sending "str", in characters,
833: counting any line-dependent padding at one line. */
834: string_cost_one_line (str)
835: char *str;
836: {
837: cost = 0;
838: if (str)
839: tputs (str, 1, evalcost);
840: return cost;
841: }
842:
843: /* Compute per line amount of line-dependent padding,
844: in tenths of characters. */
845: per_line_cost (str)
846: register char *str;
847: {
848: cost = 0;
849: if (str)
850: tputs (str, 0, evalcost);
851: cost = - cost;
852: if (str)
853: tputs (str, 10, evalcost);
854: return cost;
855: }
856:
857: /* ARGSUSED */
858: calculate_ins_del_char_costs ()
859: {
860: int ins_startup_cost, del_startup_cost;
861: int ins_cost_per_char, del_cost_per_char;
862: register int i;
863: register int *p;
864:
865: if (TS_ins_multi_chars)
866: {
867: ins_cost_per_char = 0;
868: ins_startup_cost = string_cost_one_line (TS_ins_multi_chars);
869: }
870: else if (TS_ins_char || TS_pad_inserted_char
871: || (TS_insert_mode && TS_end_insert_mode))
872: {
873: ins_startup_cost = (30 * (string_cost (TS_insert_mode) + string_cost (TS_end_insert_mode))) / 100;
874: ins_cost_per_char = (string_cost_one_line (TS_ins_char)
875: + string_cost_one_line (TS_pad_inserted_char));
876: }
877: else
878: {
879: ins_startup_cost = 9999;
880: ins_cost_per_char = 0;
881: }
882:
883: if (TS_del_multi_chars)
884: {
885: del_cost_per_char = 0;
886: del_startup_cost = string_cost_one_line (TS_del_multi_chars);
887: }
888: else if (TS_del_char)
889: {
890: del_startup_cost = (string_cost (TS_delete_mode)
891: + string_cost (TS_end_delete_mode));
892: if (delete_in_insert_mode)
893: del_startup_cost /= 2;
894: del_cost_per_char = string_cost_one_line (TS_del_char);
895: }
896: else
897: {
898: del_startup_cost = 9999;
899: del_cost_per_char = 0;
900: }
901:
902: /* Delete costs are at negative offsets */
903: p = &DCICcost[0];
904: for (i = screen_width; --i >= 0;)
905: *--p = (del_startup_cost += del_cost_per_char);
906:
907: /* Doing nothing is free */
908: p = &DCICcost[0];
909: *p++ = 0;
910:
911: /* Insert costs are at positive offsets */
912: for (i = screen_width; --i >= 0;)
913: *p++ = (ins_startup_cost += ins_cost_per_char);
914: }
915:
916: calculate_costs ()
917: {
918: register char *s
919: = TS_set_scroll_region ? TS_set_scroll_region : TS_set_scroll_region_1;
920:
921: if (dont_calculate_costs)
922: return;
923:
924: if (s && (!TS_ins_line && !TS_del_line))
925: CalcIDCosts (TS_rev_scroll, TS_ins_multi_lines,
926: TS_fwd_scroll, TS_del_multi_lines,
927: s, s);
928: else
929: CalcIDCosts (TS_ins_line, TS_ins_multi_lines,
930: TS_del_line, TS_del_multi_lines,
931: 0, 0);
932:
933: calculate_ins_del_char_costs ();
934:
935: /* Don't use TS_repeat if its padding is worse than sending the chars */
936: if (TS_repeat && per_line_cost (TS_repeat) * baud_rate < 9000)
937: RPov = string_cost (TS_repeat);
938: else
939: RPov = MScreenWidth;
940:
941: cmcostinit (); /* set up cursor motion costs */
942: }
943:
944: term_init (terminal_type)
945: char *terminal_type;
946: {
947: char *combuf;
948: char *fill;
949: char tbuf[2044];
950: register char *p;
951: int status;
952:
953: extern char *tgetstr ();
954:
955: Wcm_clear ();
956: dont_calculate_costs = 0;
957:
958: status = tgetent (tbuf, terminal_type);
959: if (status < 0)
960: fatal ("Cannot open termcap database file.\n");
961: if (status == 0)
962: fatal ("Terminal type %s is not defined.\n", terminal_type);
963:
964: #ifdef TERMINFO
965: combuf = (char *) malloc (2044);
966: #else
967: combuf = (char *) malloc (strlen (tbuf));
968: #endif /* not TERMINFO */
969: if (combuf == 0)
970: abort ();
971: fill = combuf;
972:
973: TS_ins_line = tgetstr ("al", &fill);
974: TS_ins_multi_lines = tgetstr ("AL", &fill);
975: TS_bell = tgetstr ("bl", &fill);
976: TS_clr_to_bottom = tgetstr ("cd", &fill);
977: TS_clr_line = tgetstr ("ce", &fill);
978: TS_clr_screen = tgetstr ("cl", &fill);
979: ColPosition = tgetstr ("ch", &fill);
980: AbsPosition = tgetstr ("cm", &fill);
981: CR = tgetstr ("cr", &fill);
982: TS_set_scroll_region = tgetstr ("cs", &fill);
983: TS_set_scroll_region_1 = tgetstr ("cS", &fill);
984: RowPosition = tgetstr ("cv", &fill);
985: TS_del_char = tgetstr ("dc", &fill);
986: TS_del_multi_chars = tgetstr ("DC", &fill);
987: TS_del_line = tgetstr ("dl", &fill);
988: TS_del_multi_lines = tgetstr ("DL", &fill);
989: TS_delete_mode = tgetstr ("dm", &fill);
990: TS_end_delete_mode = tgetstr ("ed", &fill);
991: TS_end_insert_mode = tgetstr ("ei", &fill);
992: Home = tgetstr ("ho", &fill);
993: TS_ins_char = tgetstr ("ic", &fill);
994: TS_ins_multi_chars = tgetstr ("IC", &fill);
995: TS_insert_mode = tgetstr ("im", &fill);
996: TS_pad_inserted_char = tgetstr ("ip", &fill);
997: TS_end_keypad_mode = tgetstr ("ke", &fill);
998: TS_keypad_mode = tgetstr ("ks", &fill);
999: LastLine = tgetstr ("ll", &fill);
1000: Right = tgetstr ("nd", &fill);
1001: Down = tgetstr ("do", &fill);
1002: if (!Down)
1003: Down = tgetstr ("nl", &fill); /* Obsolete name for "do" */
1004: #ifdef VMS
1005: /* VMS puts a carriage return before each linefeed,
1006: so it is not safe to use linefeeds. */
1007: if (Down && Down[0] == '\n' && Down[1] == '\0')
1008: Down = 0;
1009: #endif /* VMS */
1010: if (tgetflag ("bs"))
1011: Left = "\b"; /* can't possibly be longer! */
1012: else /* (Actually, "bs" is obsolete...) */
1013: Left = tgetstr ("le", &fill);
1014: if (!Left)
1015: Left = tgetstr ("bc", &fill); /* Obsolete name for "le" */
1016: TS_pad_char = tgetstr ("pc", &fill);
1017: TS_repeat = tgetstr ("rp", &fill);
1018: TS_end_standout_mode = tgetstr ("se", &fill);
1019: TS_fwd_scroll = tgetstr ("sf", &fill);
1020: TS_standout_mode = tgetstr ("so", &fill);
1021: TS_rev_scroll = tgetstr ("sr", &fill);
1022: Wcm.cm_tab = tgetstr ("ta", &fill);
1023: TS_end_termcap_modes = tgetstr ("te", &fill);
1024: TS_termcap_modes = tgetstr ("ti", &fill);
1025: Up = tgetstr ("up", &fill);
1026: TS_visible_bell = tgetstr ("vb", &fill);
1027: TS_end_visual_mode = tgetstr ("ve", &fill);
1028: TS_visual_mode = tgetstr ("vs", &fill);
1029: TS_set_window = tgetstr ("wi", &fill);
1030:
1031: AutoWrap = tgetflag ("am");
1032: memory_below_screen = tgetflag ("db");
1033: TF_hazeltine = tgetflag ("hz");
1034: must_write_spaces = tgetflag ("in");
1035: MetaFlag = tgetflag ("km") || tgetflag ("MT");
1036: TF_insmode_motion = tgetflag ("mi");
1037: TF_standout_motion = tgetflag ("ms");
1038: TF_underscore = tgetflag ("ul");
1039: MagicWrap = tgetflag ("xn");
1040: TF_xs = tgetflag ("xs");
1041: TF_teleray = tgetflag ("xt");
1042:
1043: /* Get screen size from system, or else from termcap. */
1044: get_screen_size (&screen_width, &screen_height);
1045: if (screen_width <= 0)
1046: screen_width = tgetnum ("co");
1047: if (screen_height <= 0)
1048: screen_height = tgetnum ("li");
1049:
1050: min_padding_speed = tgetnum ("pb");
1051: TN_standout_width = tgetnum ("sg");
1052: TabWidth = tgetnum ("tw");
1053:
1054: #ifdef VMS
1055: /* These capabilities commonly use ^J.
1056: I don't know why, but sending them on VMS does not work;
1057: it causes following spaces to be lost, sometimes.
1058: For now, the simplest fix is to avoid using these capabilities ever. */
1059: if (Down && Down[0] == '\n')
1060: Down = 0;
1061: #endif /* VMS */
1062:
1063: if (!TS_bell)
1064: TS_bell = "\07";
1065:
1066: if (!TS_fwd_scroll)
1067: TS_fwd_scroll = Down;
1068:
1069: PC = TS_pad_char ? *TS_pad_char : 0;
1070:
1071: if (TabWidth < 0)
1072: TabWidth = 8;
1073:
1074: /* Turned off since /etc/termcap seems to have :ta= for most terminals
1075: and newer termcap doc does not seem to say there is a default.
1076: if (!Wcm.cm_tab)
1077: Wcm.cm_tab = "\t";
1078: */
1079:
1080: if (TS_standout_mode == 0)
1081: {
1082: TN_standout_width = tgetnum ("ug");
1083: TS_end_standout_mode = tgetstr ("ue", &fill);
1084: TS_standout_mode = tgetstr ("us", &fill);
1085: }
1086:
1087: if (TF_teleray)
1088: {
1089: Wcm.cm_tab = 0;
1090: /* Teleray: most programs want a space in front of TS_standout_mode,
1091: but Emacs can do without it (and give one extra column). */
1092: TS_standout_mode = "\033RD";
1093: TN_standout_width = 1;
1094: /* But that means we cannot rely on ^M to go to column zero! */
1095: CR = 0;
1096: /* LF can't be trusted either -- can alter hpos */
1097: /* if move at column 0 thru a line with TS_standout_mode */
1098: Down = 0;
1099: }
1100:
1101: /* Special handling for certain terminal types known to need it */
1102:
1103: if (!strcmp (terminal_type, "supdup"))
1104: {
1105: memory_below_screen = 1;
1106: Wcm.cm_losewrap = 1;
1107: }
1108: if (!strncmp (terminal_type, "c10", 3)
1109: || !strcmp (terminal_type, "perq"))
1110: {
1111: /* Supply a makeshift :wi string.
1112: This string is not valid in general since it works only
1113: for windows starting at the upper left corner;
1114: but that is all Emacs uses.
1115:
1116: This string works only if the screen is using
1117: the top of the video memory, because addressing is memory-relative.
1118: So first check the :ti string to see if that is true.
1119:
1120: It would be simpler if the :wi string could go in the termcap
1121: entry, but it can't because it is not fully valid.
1122: If it were in the termcap entry, it would confuse other programs. */
1123: if (!TS_set_window)
1124: {
1125: p = TS_termcap_modes;
1126: while (*p && strcmp (p, "\033v "))
1127: p++;
1128: if (*p)
1129: TS_set_window = "\033v%C %C %C %C ";
1130: }
1131: /* Termcap entry often fails to have :in: flag */
1132: must_write_spaces = 1;
1133: /* :ti string typically fails to have \E^G! in it */
1134: /* This limits scope of insert-char to one line. */
1135: strcpy (fill, TS_termcap_modes);
1136: strcat (fill, "\033\007!");
1137: TS_termcap_modes = fill;
1138: fill += strlen (fill) + 1;
1139: p = combuf;
1140: /* Change all %+ parameters to %C, to handle
1141: values above 96 correctly for the C100. */
1142: while (p != fill)
1143: {
1144: if (p[0] == '%' && p[1] == '+')
1145: p[1] = 'C';
1146: p++;
1147: }
1148: }
1149:
1150: screen_height = min (screen_height, MScreenLength);
1151: screen_width = min (screen_width, MScreenWidth);
1152:
1153: ScreenRows = screen_height;
1154: ScreenCols = screen_width;
1155: specified_window = screen_height;
1156:
1157: if (Wcm_init ()) /* can't do cursor motion */
1158: #ifdef VMS
1159: fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
1160: It lacks the ability to position the cursor.\n\
1161: If that is not the actual type of terminal you have, use either the\n\
1162: DCL command `SET TERMINAL/DEVICE= ...' for DEC-compatible terminals,\n\
1163: or `define EMACS_TERM \"terminal type\"' for non-DEC terminals.\n",
1164: terminal_type);
1165: #else
1166: fatal ("Terminal type \"%s\" is not powerful enough to run Emacs.\n\
1167: It lacks the ability to position the cursor.\n\
1168: If that is not the actual type of terminal you have,\n\
1169: use the C-shell command `setenv TERM ...' to specify the correct type.\n\
1170: It may be necessary to do `unsetenv TERMCAP' as well.\n",
1171: terminal_type);
1172: #endif
1173:
1174: delete_in_insert_mode
1175: = TS_delete_mode && TS_insert_mode
1176: && !strcmp (TS_delete_mode, TS_insert_mode);
1177:
1178: se_is_so = TS_standout_mode && TS_end_standout_mode
1179: && !strcmp (TS_standout_mode, TS_end_standout_mode);
1180:
1181: /* Remove width of standout marker from usable width of line */
1182: if (TN_standout_width > 0)
1183: screen_width -= TN_standout_width;
1184:
1185: UseTabs = tabs_safe_p () && TabWidth == 8;
1186:
1187: scroll_region_ok = TS_set_window || TS_set_scroll_region
1188: || TS_set_scroll_region_1;
1189:
1190: line_ins_del_ok = (((TS_ins_line || TS_ins_multi_lines)
1191: && (TS_del_line || TS_del_multi_lines))
1192: || (scroll_region_ok
1193: && TS_fwd_scroll
1194: && TS_rev_scroll));
1195:
1196: char_ins_del_ok = ((TS_ins_char || TS_insert_mode ||
1197: TS_pad_inserted_char || TS_ins_multi_chars)
1198: && (TS_del_char || TS_del_multi_chars));
1199:
1200: fast_clear_end_of_line = TS_clr_line != 0;
1201:
1202: init_baud_rate ();
1203: if (read_socket_hook) /* Baudrate is somewhat */
1204: /* meaningless in this case */
1205: baud_rate = 9600;
1206:
1207: calculate_costs ();
1208: }
1209:
1210: /* VARARGS 1 */
1211: fatal (str, arg1, arg2)
1212: {
1213: fprintf (stderr, "emacs: ");
1214: fprintf (stderr, str, arg1, arg2);
1215: fflush (stderr);
1216: exit (1);
1217: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.