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