|
|
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.