ed.screen.c revision 167465
1184610Salfred/* $Header: /p/tcsh/cvsroot/tcsh/ed.screen.c,v 3.75 2006/08/24 20:56:31 christos Exp $ */ 2184610Salfred/* 3184610Salfred * ed.screen.c: Editor/termcap-curses interface 4184610Salfred */ 5184610Salfred/*- 6184610Salfred * Copyright (c) 1980, 1991 The Regents of the University of California. 7184610Salfred * All rights reserved. 8184610Salfred * 9184610Salfred * Redistribution and use in source and binary forms, with or without 10184610Salfred * modification, are permitted provided that the following conditions 11184610Salfred * are met: 12184610Salfred * 1. Redistributions of source code must retain the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer. 14184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 15184610Salfred * notice, this list of conditions and the following disclaimer in the 16184610Salfred * documentation and/or other materials provided with the distribution. 17184610Salfred * 3. Neither the name of the University nor the names of its contributors 18184610Salfred * may be used to endorse or promote products derived from this software 19184610Salfred * without specific prior written permission. 20184610Salfred * 21184610Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29185290Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30185290Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31185290Salfred * SUCH DAMAGE. 32185290Salfred */ 33185290Salfred#include "sh.h" 34185290Salfred 35185290SalfredRCSID("$tcsh: ed.screen.c,v 3.75 2006/08/24 20:56:31 christos Exp $") 36185290Salfred 37185290Salfred#include "ed.h" 38185290Salfred#include "tc.h" 39184610Salfred#include "ed.defns.h" 40184610Salfred 41184610Salfred/* #define DEBUG_LITERAL */ 42188942Sthompsa 43184610Salfred/* 44184610Salfred * IMPORTANT NOTE: these routines are allowed to look at the current screen 45184610Salfred * and the current possition assuming that it is correct. If this is not 46184610Salfred * true, then the update will be WRONG! This is (should be) a valid 47184610Salfred * assumption... 48184610Salfred */ 49184610Salfred 50184610Salfred#define TC_BUFSIZE 2048 51186730Salfred 52186730Salfred#define GoodStr(a) (tstr[a].str != NULL && tstr[a].str[0] != '\0') 53186730Salfred#define Str(a) tstr[a].str 54186730Salfred#define Val(a) tval[a].val 55186730Salfred 56186730Salfredstatic const struct { 57186730Salfred const char *b_name; 58184610Salfred speed_t b_rate; 59184610Salfred} baud_rate[] = { 60184610Salfred 61184610Salfred#ifdef B0 62184610Salfred { "0", B0 }, 63184610Salfred#endif 64186730Salfred#ifdef B50 65184610Salfred { "50", B50 }, 66184610Salfred#endif 67184610Salfred#ifdef B75 68184610Salfred { "75", B75 }, 69184610Salfred#endif 70184610Salfred#ifdef B110 71184610Salfred { "110", B110 }, 72184610Salfred#endif 73184610Salfred#ifdef B134 74184610Salfred { "134", B134 }, 75184610Salfred#endif 76186730Salfred#ifdef B150 77184610Salfred { "150", B150 }, 78184610Salfred#endif 79184610Salfred#ifdef B200 80184610Salfred { "200", B200 }, 81184610Salfred#endif 82184610Salfred#ifdef B300 83184610Salfred { "300", B300 }, 84184610Salfred#endif 85184610Salfred#ifdef B600 86184610Salfred { "600", B600 }, 87184610Salfred#endif 88184610Salfred#ifdef B900 89184610Salfred { "900", B900 }, 90184610Salfred#endif 91184610Salfred#ifdef B1200 92184610Salfred { "1200", B1200 }, 93184610Salfred#endif 94184610Salfred#ifdef B1800 95184610Salfred { "1800", B1800 }, 96184610Salfred#endif 97184610Salfred#ifdef B2400 98184610Salfred { "2400", B2400 }, 99184610Salfred#endif 100184610Salfred#ifdef B3600 101184610Salfred { "3600", B3600 }, 102184610Salfred#endif 103184610Salfred#ifdef B4800 104184610Salfred { "4800", B4800 }, 105192984Sthompsa#endif 106184610Salfred#ifdef B7200 107184610Salfred { "7200", B7200 }, 108184610Salfred#endif 109184610Salfred#ifdef B9600 110184610Salfred { "9600", B9600 }, 111184610Salfred#endif 112192984Sthompsa#ifdef EXTA 113184610Salfred { "19200", EXTA }, 114184610Salfred#endif 115184610Salfred#ifdef B19200 116184610Salfred { "19200", B19200 }, 117184610Salfred#endif 118184610Salfred#ifdef EXTB 119184610Salfred { "38400", EXTB }, 120184610Salfred#endif 121184610Salfred#ifdef B38400 122184610Salfred { "38400", B38400 }, 123184610Salfred#endif 124184610Salfred { NULL, 0 } 125184610Salfred}; 126184610Salfred 127184610Salfred#define T_at7 0 128184610Salfred#define T_al 1 129184610Salfred#define T_bl 2 130184610Salfred#define T_cd 3 131184610Salfred#define T_ce 4 132184610Salfred#define T_ch 5 133184610Salfred#define T_cl 6 134184610Salfred#define T_dc 7 135184610Salfred#define T_dl 8 136184610Salfred#define T_dm 9 137184610Salfred#define T_ed 10 138184610Salfred#define T_ei 11 139184610Salfred#define T_fs 12 140184610Salfred#define T_ho 13 141184610Salfred#define T_ic 14 142184610Salfred#define T_im 15 143184610Salfred#define T_ip 16 144184610Salfred#define T_kd 17 145184610Salfred#define T_kh 18 146184610Salfred#define T_kl 19 147184610Salfred#define T_kr 20 148184610Salfred#define T_ku 21 149184610Salfred#define T_md 22 150184610Salfred#define T_me 23 151184610Salfred#define T_mr 24 152184610Salfred#define T_nd 25 153184610Salfred#define T_se 26 154184610Salfred#define T_so 27 155184610Salfred#define T_ts 28 156185290Salfred#define T_up 29 157185290Salfred#define T_us 30 158184610Salfred#define T_ue 31 159184610Salfred#define T_vb 32 160184610Salfred#define T_DC 33 161184610Salfred#define T_DO 34 162184610Salfred#define T_IC 35 163185290Salfred#define T_LE 36 164185290Salfred#define T_RI 37 165185290Salfred#define T_UP 38 166185290Salfred#define T_str 39 167185290Salfred 168185290Salfredstatic struct termcapstr { 169185290Salfred const char *name; 170184610Salfred const char *long_name; 171184610Salfred char *str; 172184610Salfred} tstr[T_str + 1]; 173185290Salfred 174184610Salfred 175184610Salfred#define T_am 0 176184610Salfred#define T_pt 1 177184610Salfred#define T_li 2 178184610Salfred#define T_co 3 179184610Salfred#define T_km 4 180185290Salfred#define T_xn 5 181185290Salfred#define T_val 6 182184610Salfredstatic struct termcapval { 183184610Salfred const char *name; 184184610Salfred const char *long_name; 185184610Salfred int val; 186184610Salfred} tval[T_val + 1]; 187184610Salfred 188184610Salfredvoid 189185290Salfredterminit(void) 190185290Salfred{ 191184610Salfred#ifdef NLS_CATALOGS 192184610Salfred int i; 193184610Salfred 194184610Salfred for (i = 0; i < T_str + 1; i++) 195184610Salfred xfree((ptr_t)(intptr_t)tstr[i].long_name); 196185290Salfred 197185290Salfred for (i = 0; i < T_val + 1; i++) 198185290Salfred xfree((ptr_t)(intptr_t)tval[i].long_name); 199184610Salfred#endif 200184610Salfred 201184610Salfred tstr[T_al].name = "al"; 202184610Salfred tstr[T_al].long_name = CSAVS(4, 1, "add new blank line"); 203184610Salfred 204184610Salfred tstr[T_bl].name = "bl"; 205184610Salfred tstr[T_bl].long_name = CSAVS(4, 2, "audible bell"); 206184610Salfred 207184610Salfred tstr[T_cd].name = "cd"; 208185290Salfred tstr[T_cd].long_name = CSAVS(4, 3, "clear to bottom"); 209184610Salfred 210184610Salfred tstr[T_ce].name = "ce"; 211184610Salfred tstr[T_ce].long_name = CSAVS(4, 4, "clear to end of line"); 212184610Salfred 213184610Salfred tstr[T_ch].name = "ch"; 214184610Salfred tstr[T_ch].long_name = CSAVS(4, 5, "cursor to horiz pos"); 215184610Salfred 216184610Salfred tstr[T_cl].name = "cl"; 217184610Salfred tstr[T_cl].long_name = CSAVS(4, 6, "clear screen"); 218184610Salfred 219185290Salfred tstr[T_dc].name = "dc"; 220185290Salfred tstr[T_dc].long_name = CSAVS(4, 7, "delete a character"); 221185290Salfred 222185290Salfred tstr[T_dl].name = "dl"; 223185290Salfred tstr[T_dl].long_name = CSAVS(4, 8, "delete a line"); 224185290Salfred 225185290Salfred tstr[T_dm].name = "dm"; 226185290Salfred tstr[T_dm].long_name = CSAVS(4, 9, "start delete mode"); 227185290Salfred 228185290Salfred tstr[T_ed].name = "ed"; 229192984Sthompsa tstr[T_ed].long_name = CSAVS(4, 10, "end delete mode"); 230184610Salfred 231184610Salfred tstr[T_ei].name = "ei"; 232184610Salfred tstr[T_ei].long_name = CSAVS(4, 11, "end insert mode"); 233184610Salfred 234192984Sthompsa tstr[T_fs].name = "fs"; 235184610Salfred tstr[T_fs].long_name = CSAVS(4, 12, "cursor from status line"); 236192984Sthompsa 237184610Salfred tstr[T_ho].name = "ho"; 238184610Salfred tstr[T_ho].long_name = CSAVS(4, 13, "home cursor"); 239184610Salfred 240184610Salfred tstr[T_ic].name = "ic"; 241185290Salfred tstr[T_ic].long_name = CSAVS(4, 14, "insert character"); 242185290Salfred 243185290Salfred tstr[T_im].name = "im"; 244184610Salfred tstr[T_im].long_name = CSAVS(4, 15, "start insert mode"); 245184610Salfred 246184610Salfred tstr[T_ip].name = "ip"; 247184610Salfred tstr[T_ip].long_name = CSAVS(4, 16, "insert padding"); 248184610Salfred 249184610Salfred tstr[T_kd].name = "kd"; 250184610Salfred tstr[T_kd].long_name = CSAVS(4, 17, "sends cursor down"); 251184610Salfred 252184610Salfred tstr[T_kl].name = "kl"; 253184610Salfred tstr[T_kl].long_name = CSAVS(4, 18, "sends cursor left"); 254184610Salfred 255184610Salfred tstr[T_kr].name = "kr"; 256184610Salfred tstr[T_kr].long_name = CSAVS(4, 19, "sends cursor right"); 257192984Sthompsa 258184610Salfred tstr[T_ku].name = "ku"; 259185290Salfred tstr[T_ku].long_name = CSAVS(4, 20, "sends cursor up"); 260192984Sthompsa 261185290Salfred tstr[T_md].name = "md"; 262185290Salfred tstr[T_md].long_name = CSAVS(4, 21, "begin bold"); 263185290Salfred 264185290Salfred tstr[T_me].name = "me"; 265185290Salfred tstr[T_me].long_name = CSAVS(4, 22, "end attributes"); 266192984Sthompsa 267185290Salfred tstr[T_nd].name = "nd"; 268185290Salfred tstr[T_nd].long_name = CSAVS(4, 23, "non destructive space"); 269192984Sthompsa 270185290Salfred tstr[T_se].name = "se"; 271185290Salfred tstr[T_se].long_name = CSAVS(4, 24, "end standout"); 272185290Salfred 273185290Salfred tstr[T_so].name = "so"; 274185290Salfred tstr[T_so].long_name = CSAVS(4, 25, "begin standout"); 275185290Salfred 276185290Salfred tstr[T_ts].name = "ts"; 277185290Salfred tstr[T_ts].long_name = CSAVS(4, 26, "cursor to status line"); 278185290Salfred 279185290Salfred tstr[T_up].name = "up"; 280192984Sthompsa tstr[T_up].long_name = CSAVS(4, 27, "cursor up one"); 281185290Salfred 282192984Sthompsa tstr[T_us].name = "us"; 283185290Salfred tstr[T_us].long_name = CSAVS(4, 28, "begin underline"); 284185290Salfred 285185290Salfred tstr[T_ue].name = "ue"; 286185290Salfred tstr[T_ue].long_name = CSAVS(4, 29, "end underline"); 287185290Salfred 288185290Salfred tstr[T_vb].name = "vb"; 289192984Sthompsa tstr[T_vb].long_name = CSAVS(4, 30, "visible bell"); 290185290Salfred 291192984Sthompsa tstr[T_DC].name = "DC"; 292185290Salfred tstr[T_DC].long_name = CSAVS(4, 31, "delete multiple chars"); 293185290Salfred 294185290Salfred tstr[T_DO].name = "DO"; 295185290Salfred tstr[T_DO].long_name = CSAVS(4, 32, "cursor down multiple"); 296185290Salfred 297185290Salfred tstr[T_IC].name = "IC"; 298185290Salfred tstr[T_IC].long_name = CSAVS(4, 33, "insert multiple chars"); 299185290Salfred 300185290Salfred tstr[T_LE].name = "LE"; 301192984Sthompsa tstr[T_LE].long_name = CSAVS(4, 34, "cursor left multiple"); 302185290Salfred 303192984Sthompsa tstr[T_RI].name = "RI"; 304185290Salfred tstr[T_RI].long_name = CSAVS(4, 35, "cursor right multiple"); 305185290Salfred 306185290Salfred tstr[T_UP].name = "UP"; 307185290Salfred tstr[T_UP].long_name = CSAVS(4, 36, "cursor up multiple"); 308185290Salfred 309185290Salfred tstr[T_kh].name = "kh"; 310192984Sthompsa tstr[T_kh].long_name = CSAVS(4, 43, "send cursor home"); 311188947Sthompsa 312185290Salfred tstr[T_at7].name = "@7"; 313184610Salfred tstr[T_at7].long_name = CSAVS(4, 44, "send cursor end"); 314184610Salfred 315184610Salfred tstr[T_mr].name = "mr"; 316184610Salfred tstr[T_mr].long_name = CSAVS(4, 45, "begin reverse video"); 317184610Salfred 318184610Salfred tstr[T_str].name = NULL; 319184610Salfred tstr[T_str].long_name = NULL; 320184610Salfred 321184610Salfred 322184610Salfred tval[T_am].name = "am"; 323184610Salfred tval[T_am].long_name = CSAVS(4, 37, "Has automatic margins"); 324184610Salfred 325184610Salfred tval[T_pt].name = "pt"; 326184610Salfred tval[T_pt].long_name = CSAVS(4, 38, "Can use physical tabs"); 327192984Sthompsa 328184610Salfred tval[T_li].name = "li"; 329184610Salfred tval[T_li].long_name = CSAVS(4, 39, "Number of lines"); 330184610Salfred 331184610Salfred tval[T_co].name = "co"; 332184610Salfred tval[T_co].long_name = CSAVS(4, 40, "Number of columns"); 333184610Salfred 334184610Salfred tval[T_km].name = "km"; 335184610Salfred tval[T_km].long_name = CSAVS(4, 41, "Has meta key"); 336184610Salfred 337184610Salfred tval[T_xn].name = "xn"; 338184610Salfred tval[T_xn].long_name = CSAVS(4, 42, "Newline ignored at right margin"); 339184610Salfred 340184610Salfred tval[T_val].name = NULL; 341184610Salfred tval[T_val].long_name = NULL; 342192984Sthompsa} 343184610Salfred 344192984Sthompsa/* 345184610Salfred * A very useful table from justin@crim.ca (Justin Bur) :-) 346184610Salfred * (Modified by per@erix.ericsson.se (Per Hedeland) 347184610Salfred * - first (and second:-) case fixed) 348184610Salfred * 349184610Salfred * Description Termcap variables tcsh behavior 350184610Salfred * am xn UseRightmost SendCRLF 351184610Salfred * -------------- ------- ------- ------------ ------------ 352184610Salfred * Automargins yes no yes no 353184610Salfred * Magic Margins yes yes yes no 354184610Salfred * No Wrap no -- yes yes 355192984Sthompsa */ 356184610Salfred 357192984Sthompsastatic int me_all = 0; /* does two or more of the attributes use me */ 358185290Salfred 359185290Salfredstatic void ReBufferDisplay (void); 360185290Salfredstatic void TCset (struct termcapstr *, const char *); 361185290Salfred 362185290Salfred 363185290Salfredstatic void 364185290SalfredTCset(struct termcapstr *t, const char *cap) 365185290Salfred{ 366185290Salfred if (cap == NULL || *cap == '\0') { 367192984Sthompsa xfree(t->str); 368185290Salfred t->str = NULL; 369184610Salfred } else { 370184610Salfred size_t size; 371184610Salfred 372184610Salfred size = strlen(cap) + 1; 373184610Salfred t->str = xrealloc(t->str, size); 374184610Salfred memcpy(t->str, cap, size); 375184610Salfred } 376184610Salfred} 377184610Salfred 378184610Salfred 379184610Salfred/*ARGSUSED*/ 380184610Salfredvoid 381184610SalfredTellTC(void) 382184610Salfred{ 383184610Salfred struct termcapstr *t; 384184610Salfred char *first, *s; 385184610Salfred 386184610Salfred xprintf(CGETS(7, 1, "\n\tTcsh thinks your terminal has the\n")); 387184610Salfred xprintf(CGETS(7, 2, "\tfollowing characteristics:\n\n")); 388184610Salfred xprintf(CGETS(7, 3, "\tIt has %d columns and %d lines\n"), 389184610Salfred Val(T_co), Val(T_li)); 390184610Salfred s = strsave(T_HasMeta ? CGETS(7, 5, "a") : CGETS(7, 6, "no")); 391184610Salfred cleanup_push(s, xfree); 392184610Salfred first = s; 393184610Salfred xprintf(CGETS(7, 4, "\tIt has %s meta key\n"), s); 394184610Salfred s = strsave(T_Tabs ? "" : CGETS(7, 8, " not")); 395184610Salfred cleanup_push(s, xfree); 396184610Salfred xprintf(CGETS(7, 7, "\tIt can%s use tabs\n"), s); 397184610Salfred s = strsave((T_Margin&MARGIN_AUTO) ? 398184610Salfred CGETS(7, 10, "has") : CGETS(7, 11, "does not have")); 399184610Salfred cleanup_push(s, xfree); 400184610Salfred xprintf(CGETS(7, 9, "\tIt %s automatic margins\n"), s); 401184610Salfred if (T_Margin & MARGIN_AUTO) { 402184610Salfred s = strsave((T_Margin & MARGIN_MAGIC) ? 403184610Salfred CGETS(7, 10, "has") : CGETS(7, 11, "does not have")); 404184610Salfred cleanup_push(s, xfree); 405184610Salfred xprintf(CGETS(7, 12, "\tIt %s magic margins\n"), s); 406184610Salfred } 407184610Salfred for (t = tstr; t->name != NULL; t++) { 408184610Salfred s = strsave(t->str && *t->str ? t->str : CGETS(7, 13, "(empty)")); 409184610Salfred cleanup_push(s, xfree); 410184610Salfred xprintf("\t%36s (%s) == %s\n", t->long_name, t->name, s); 411184610Salfred cleanup_until(s); 412184610Salfred } 413184610Salfred xputchar('\n'); 414184610Salfred cleanup_until(first); 415184610Salfred} 416184610Salfred 417184610Salfred 418184610Salfredstatic void 419184610SalfredReBufferDisplay(void) 420184610Salfred{ 421184610Salfred int i; 422184610Salfred Char **b; 423184610Salfred 424184610Salfred b = Display; 425184610Salfred Display = NULL; 426184610Salfred blkfree(b); 427184610Salfred b = Vdisplay; 428184610Salfred Vdisplay = NULL; 429184610Salfred blkfree(b); 430184610Salfred TermH = Val(T_co); 431184610Salfred TermV = (INBUFSIZE * 4) / TermH + 1;/*FIXBUF*/ 432184610Salfred b = xmalloc(sizeof(*b) * (TermV + 1)); 433184610Salfred for (i = 0; i < TermV; i++) 434184610Salfred b[i] = xmalloc(sizeof(*b[i]) * (TermH + 1)); 435184610Salfred b[TermV] = NULL; 436184610Salfred Display = b; 437184610Salfred b = xmalloc(sizeof(*b) * (TermV + 1)); 438184610Salfred for (i = 0; i < TermV; i++) 439184610Salfred b[i] = xmalloc(sizeof(*b[i]) * (TermH + 1)); 440184610Salfred b[TermV] = NULL; 441184610Salfred Vdisplay = b; 442184610Salfred} 443184610Salfred 444184610Salfredvoid 445184610SalfredSetTC(char *what, char *how) 446184610Salfred{ 447184610Salfred struct termcapstr *ts; 448184610Salfred struct termcapval *tv; 449184610Salfred 450184610Salfred /* 451184610Salfred * Do the strings first 452184610Salfred */ 453184610Salfred setname("settc"); 454184610Salfred for (ts = tstr; ts->name != NULL; ts++) 455184610Salfred if (strcmp(ts->name, what) == 0) 456184610Salfred break; 457184610Salfred if (ts->name != NULL) { 458192984Sthompsa TCset(ts, how); 459184610Salfred /* 460184610Salfred * Reset variables 461184610Salfred */ 462184610Salfred if (GoodStr(T_me) && GoodStr(T_ue)) 463184610Salfred me_all = (strcmp(Str(T_me), Str(T_ue)) == 0); 464190732Sthompsa else 465190732Sthompsa me_all = 0; 466190732Sthompsa if (GoodStr(T_me) && GoodStr(T_se)) 467190732Sthompsa me_all |= (strcmp(Str(T_me), Str(T_se)) == 0); 468184610Salfred 469184610Salfred T_CanCEOL = GoodStr(T_ce); 470184610Salfred T_CanDel = GoodStr(T_dc) || GoodStr(T_DC); 471184610Salfred T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC); 472184610Salfred T_CanUP = GoodStr(T_up) || GoodStr(T_UP); 473184610Salfred return; 474184610Salfred } 475184610Salfred 476184610Salfred /* 477184610Salfred * Do the numeric ones second 478184610Salfred */ 479184610Salfred for (tv = tval; tv->name != NULL; tv++) 480184610Salfred if (strcmp(tv->name, what) == 0) 481184610Salfred break; 482184610Salfred 483184610Salfred if (tv->name != NULL) { 484184610Salfred if (tv == &tval[T_pt] || tv == &tval[T_km] || 485184610Salfred tv == &tval[T_am] || tv == &tval[T_xn]) { 486184610Salfred if (strcmp(how, "yes") == 0) 487184610Salfred tv->val = 1; 488184610Salfred else if (strcmp(how, "no") == 0) 489184610Salfred tv->val = 0; 490192984Sthompsa else { 491184610Salfred stderror(ERR_SETTCUS, tv->name); 492192984Sthompsa return; 493185290Salfred } 494185290Salfred T_Tabs = Val(T_pt); 495185290Salfred T_HasMeta = Val(T_km); 496185290Salfred T_Margin = Val(T_am) ? MARGIN_AUTO : 0; 497185290Salfred T_Margin |= Val(T_xn) ? MARGIN_MAGIC : 0; 498185290Salfred if (tv == &tval[T_am] || tv == &tval[T_xn]) 499192984Sthompsa ChangeSize(Val(T_li), Val(T_co)); 500188947Sthompsa return; 501185290Salfred } 502192984Sthompsa else { 503184610Salfred tv->val = atoi(how); 504184610Salfred T_Cols = (Char) Val(T_co); 505184610Salfred T_Lines = (Char) Val(T_li); 506184610Salfred if (tv == &tval[T_co] || tv == &tval[T_li]) 507184610Salfred ChangeSize(Val(T_li), Val(T_co)); 508192984Sthompsa return; 509184610Salfred } 510184610Salfred } 511184610Salfred stderror(ERR_NAME | ERR_TCCAP, what); 512184610Salfred return; 513184610Salfred} 514184610Salfred 515184610Salfred 516184610Salfred/* 517184610Salfred * Print the termcap string out with variable substitution 518184610Salfred */ 519184610Salfredvoid 520184610SalfredEchoTC(Char **v) 521184610Salfred{ 522192984Sthompsa char *cap, *scap, *cv; 523184610Salfred int arg_need, arg_cols, arg_rows; 524184610Salfred int verbose = 0, silent = 0; 525184610Salfred char *area; 526184610Salfred static const char fmts[] = "%s\n", fmtd[] = "%d\n"; 527184610Salfred struct termcapstr *t; 528184610Salfred char buf[TC_BUFSIZE]; 529184610Salfred Char **globbed; 530184610Salfred 531184610Salfred area = buf; 532184610Salfred 533184610Salfred setname("echotc"); 534184610Salfred 535184610Salfred v = glob_all_or_error(v); 536184610Salfred globbed = v; 537184610Salfred cleanup_push(globbed, blk_cleanup); 538184610Salfred 539184610Salfred if (!*v || *v[0] == '\0') 540184610Salfred goto end; 541184610Salfred if (v[0][0] == '-') { 542184610Salfred switch (v[0][1]) { 543184610Salfred case 'v': 544184610Salfred verbose = 1; 545184610Salfred break; 546184610Salfred case 's': 547184610Salfred silent = 1; 548185290Salfred break; 549184610Salfred default: 550192984Sthompsa stderror(ERR_NAME | ERR_TCUSAGE); 551184610Salfred break; 552192984Sthompsa } 553185290Salfred v++; 554185290Salfred } 555185290Salfred if (!*v || *v[0] == '\0') 556185290Salfred goto end; 557185290Salfred cv = strsave(short2str(*v)); 558185290Salfred cleanup_push(cv, xfree); 559185290Salfred if (strcmp(cv, "tabs") == 0) { 560185290Salfred xprintf(fmts, T_Tabs ? CGETS(7, 14, "yes") : 561185290Salfred CGETS(7, 15, "no")); 562185290Salfred goto end_flush; 563192984Sthompsa } 564185290Salfred else if (strcmp(cv, "meta") == 0) { 565184610Salfred xprintf(fmts, Val(T_km) ? CGETS(7, 14, "yes") : 566192984Sthompsa CGETS(7, 15, "no")); 567184610Salfred goto end_flush; 568184610Salfred } 569184610Salfred else if (strcmp(cv, "xn") == 0) { 570184610Salfred xprintf(fmts, T_Margin & MARGIN_MAGIC ? CGETS(7, 14, "yes") : 571184610Salfred CGETS(7, 15, "no")); 572184610Salfred goto end_flush; 573184610Salfred } 574184610Salfred else if (strcmp(cv, "am") == 0) { 575184610Salfred xprintf(fmts, T_Margin & MARGIN_AUTO ? CGETS(7, 14, "yes") : 576192984Sthompsa CGETS(7, 15, "no")); 577184610Salfred goto end_flush; 578192984Sthompsa } 579184610Salfred else if (strcmp(cv, "baud") == 0) { 580184610Salfred int i; 581184610Salfred 582184610Salfred for (i = 0; baud_rate[i].b_name != NULL; i++) 583184610Salfred if (T_Speed == baud_rate[i].b_rate) { 584184610Salfred xprintf(fmts, baud_rate[i].b_name); 585184610Salfred goto end_flush; 586184610Salfred } 587184610Salfred xprintf(fmtd, 0); 588184610Salfred goto end_flush; 589192984Sthompsa } 590184610Salfred else if (strcmp(cv, "rows") == 0 || strcmp(cv, "lines") == 0 || 591192984Sthompsa strcmp(cv, "li") == 0) { 592184610Salfred xprintf(fmtd, Val(T_li)); 593184610Salfred goto end_flush; 594184610Salfred } 595184610Salfred else if (strcmp(cv, "cols") == 0 || strcmp(cv, "co") == 0) { 596184610Salfred xprintf(fmtd, Val(T_co)); 597184610Salfred goto end_flush; 598192984Sthompsa } 599184610Salfred 600184610Salfred /* 601184610Salfred * Try to use our local definition first 602184610Salfred */ 603184610Salfred scap = NULL; 604184610Salfred for (t = tstr; t->name != NULL; t++) 605192984Sthompsa if (strcmp(t->name, cv) == 0) { 606184610Salfred scap = t->str; 607184610Salfred break; 608184610Salfred } 609184610Salfred if (t->name == NULL) 610184610Salfred scap = tgetstr(cv, &area); 611184610Salfred if (!scap || scap[0] == '\0') { 612184610Salfred if (tgetflag(cv)) { 613192984Sthompsa xprintf(CGETS(7, 14, "yes\n")); 614184610Salfred goto end; 615192984Sthompsa } 616184610Salfred if (silent) 617184610Salfred goto end; 618184610Salfred else 619184610Salfred stderror(ERR_NAME | ERR_TCCAP, cv); 620184610Salfred } 621192984Sthompsa 622184610Salfred /* 623192984Sthompsa * Count home many values we need for this capability. 624184610Salfred */ 625184610Salfred for (cap = scap, arg_need = 0; *cap; cap++) 626184610Salfred if (*cap == '%') 627184610Salfred switch (*++cap) { 628184610Salfred case 'd': 629184610Salfred case '2': 630184610Salfred case '3': 631184610Salfred case '.': 632184610Salfred case '+': 633184610Salfred arg_need++; 634184610Salfred break; 635187180Sthompsa case '%': 636184610Salfred case '>': 637184610Salfred case 'i': 638184610Salfred case 'r': 639184610Salfred case 'n': 640184610Salfred case 'B': 641184610Salfred case 'D': 642184610Salfred break; 643192984Sthompsa default: 644184610Salfred /* 645184610Salfred * hpux has lot's of them... 646 */ 647 if (verbose) 648 stderror(ERR_NAME | ERR_TCPARM, *cap); 649 /* This is bad, but I won't complain */ 650 break; 651 } 652 653 switch (arg_need) { 654 case 0: 655 v++; 656 if (*v && *v[0]) { 657 if (silent) 658 goto end; 659 else 660 stderror(ERR_NAME | ERR_TCARGS, cv, arg_need); 661 } 662 (void) tputs(scap, 1, PUTRAW); 663 break; 664 case 1: 665 v++; 666 if (!*v || *v[0] == '\0') 667 stderror(ERR_NAME | ERR_TCNARGS, cv, 1); 668 arg_cols = 0; 669 arg_rows = atoi(short2str(*v)); 670 v++; 671 if (*v && *v[0]) { 672 if (silent) 673 goto end; 674 else 675 stderror(ERR_NAME | ERR_TCARGS, cv, arg_need); 676 } 677 (void) tputs(tgoto(scap, arg_cols, arg_rows), 1, PUTRAW); 678 break; 679 default: 680 /* This is wrong, but I will ignore it... */ 681 if (verbose) 682 stderror(ERR_NAME | ERR_TCARGS, cv, arg_need); 683 /*FALLTHROUGH*/ 684 case 2: 685 v++; 686 if (!*v || *v[0] == '\0') { 687 if (silent) 688 goto end; 689 else 690 stderror(ERR_NAME | ERR_TCNARGS, cv, 2); 691 } 692 arg_cols = atoi(short2str(*v)); 693 v++; 694 if (!*v || *v[0] == '\0') { 695 if (silent) 696 goto end; 697 else 698 stderror(ERR_NAME | ERR_TCNARGS, cv, 2); 699 } 700 arg_rows = atoi(short2str(*v)); 701 v++; 702 if (*v && *v[0]) { 703 if (silent) 704 goto end; 705 else 706 stderror(ERR_NAME | ERR_TCARGS, cv, arg_need); 707 } 708 (void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows, PUTRAW); 709 break; 710 } 711 end_flush: 712 flush(); 713 end: 714 cleanup_until(globbed); 715} 716 717int GotTermCaps = 0; 718 719static struct { 720 Char *name; 721 int key; 722 XmapVal fun; 723 int type; 724} arrow[] = { 725#define A_K_DN 0 726 { STRdown, T_kd, { 0 }, 0 }, 727#define A_K_UP 1 728 { STRup, T_ku, { 0 }, 0 }, 729#define A_K_LT 2 730 { STRleft, T_kl, { 0 }, 0 }, 731#define A_K_RT 3 732 { STRright, T_kr, { 0 }, 0 }, 733#define A_K_HO 4 734 { STRhome, T_kh, { 0 }, 0 }, 735#define A_K_EN 5 736 { STRend, T_at7, { 0 }, 0} 737}; 738#define A_K_NKEYS 6 739 740void 741ResetArrowKeys(void) 742{ 743 arrow[A_K_DN].fun.cmd = F_DOWN_HIST; 744 arrow[A_K_DN].type = XK_CMD; 745 746 arrow[A_K_UP].fun.cmd = F_UP_HIST; 747 arrow[A_K_UP].type = XK_CMD; 748 749 arrow[A_K_LT].fun.cmd = F_CHARBACK; 750 arrow[A_K_LT].type = XK_CMD; 751 752 arrow[A_K_RT].fun.cmd = F_CHARFWD; 753 arrow[A_K_RT].type = XK_CMD; 754 755 arrow[A_K_HO].fun.cmd = F_TOBEG; 756 arrow[A_K_HO].type = XK_CMD; 757 758 arrow[A_K_EN].fun.cmd = F_TOEND; 759 arrow[A_K_EN].type = XK_CMD; 760} 761 762void 763DefaultArrowKeys(void) 764{ 765 static Char strA[] = {033, '[', 'A', '\0'}; 766 static Char strB[] = {033, '[', 'B', '\0'}; 767 static Char strC[] = {033, '[', 'C', '\0'}; 768 static Char strD[] = {033, '[', 'D', '\0'}; 769 static Char strH[] = {033, '[', 'H', '\0'}; 770 static Char strF[] = {033, '[', 'F', '\0'}; 771 static Char stOA[] = {033, 'O', 'A', '\0'}; 772 static Char stOB[] = {033, 'O', 'B', '\0'}; 773 static Char stOC[] = {033, 'O', 'C', '\0'}; 774 static Char stOD[] = {033, 'O', 'D', '\0'}; 775 static Char stOH[] = {033, 'O', 'H', '\0'}; 776 static Char stOF[] = {033, 'O', 'F', '\0'}; 777 778 CStr cs; 779#ifndef IS_ASCII 780 if (strA[0] == 033) 781 { 782 strA[0] = CTL_ESC('\033'); 783 strB[0] = CTL_ESC('\033'); 784 strC[0] = CTL_ESC('\033'); 785 strD[0] = CTL_ESC('\033'); 786 strH[0] = CTL_ESC('\033'); 787 strF[0] = CTL_ESC('\033'); 788 stOA[0] = CTL_ESC('\033'); 789 stOB[0] = CTL_ESC('\033'); 790 stOC[0] = CTL_ESC('\033'); 791 stOD[0] = CTL_ESC('\033'); 792 stOH[0] = CTL_ESC('\033'); 793 stOF[0] = CTL_ESC('\033'); 794 } 795#endif 796 797 cs.len = 3; 798 799 cs.buf = strA; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 800 cs.buf = strB; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 801 cs.buf = strC; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 802 cs.buf = strD; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 803 cs.buf = strH; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 804 cs.buf = strF; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 805 cs.buf = stOA; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 806 cs.buf = stOB; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 807 cs.buf = stOC; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 808 cs.buf = stOD; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 809 cs.buf = stOH; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 810 cs.buf = stOF; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 811 812 if (VImode) { 813 cs.len = 2; 814 cs.buf = &strA[1]; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 815 cs.buf = &strB[1]; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 816 cs.buf = &strC[1]; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 817 cs.buf = &strD[1]; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 818 cs.buf = &strH[1]; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 819 cs.buf = &strF[1]; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 820 cs.buf = &stOA[1]; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 821 cs.buf = &stOB[1]; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 822 cs.buf = &stOC[1]; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 823 cs.buf = &stOD[1]; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 824 cs.buf = &stOH[1]; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 825 cs.buf = &stOF[1]; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 826 } 827} 828 829 830int 831SetArrowKeys(const CStr *name, XmapVal *fun, int type) 832{ 833 int i; 834 for (i = 0; i < A_K_NKEYS; i++) 835 if (Strcmp(name->buf, arrow[i].name) == 0) { 836 arrow[i].fun = *fun; 837 arrow[i].type = type; 838 return 0; 839 } 840 return -1; 841} 842 843int 844IsArrowKey(Char *name) 845{ 846 int i; 847 for (i = 0; i < A_K_NKEYS; i++) 848 if (Strcmp(name, arrow[i].name) == 0) 849 return 1; 850 return 0; 851} 852 853int 854ClearArrowKeys(const CStr *name) 855{ 856 int i; 857 for (i = 0; i < A_K_NKEYS; i++) 858 if (Strcmp(name->buf, arrow[i].name) == 0) { 859 arrow[i].type = XK_NOD; 860 return 0; 861 } 862 return -1; 863} 864 865void 866PrintArrowKeys(const CStr *name) 867{ 868 int i; 869 870 for (i = 0; i < A_K_NKEYS; i++) 871 if (name->len == 0 || Strcmp(name->buf, arrow[i].name) == 0) 872 if (arrow[i].type != XK_NOD) 873 printOne(arrow[i].name, &arrow[i].fun, arrow[i].type); 874} 875 876 877void 878BindArrowKeys(void) 879{ 880 KEYCMD *map, *dmap; 881 int i, j; 882 char *p; 883 CStr cs; 884 885 if (!GotTermCaps) 886 return; 887 map = VImode ? CcAltMap : CcKeyMap; 888 dmap = VImode ? CcViCmdMap : CcEmacsMap; 889 890 DefaultArrowKeys(); 891 892 for (i = 0; i < A_K_NKEYS; i++) { 893 p = tstr[arrow[i].key].str; 894 if (p && *p) { 895 j = (unsigned char) *p; 896 cs.buf = str2short(p); 897 cs.len = Strlen(cs.buf); 898 /* 899 * Assign the arrow keys only if: 900 * 901 * 1. They are multi-character arrow keys and the user 902 * has not re-assigned the leading character, or 903 * has re-assigned the leading character to be F_XKEY 904 * 2. They are single arrow keys pointing to an unassigned key. 905 */ 906 if (arrow[i].type == XK_NOD) { 907 ClearXkey(map, &cs); 908 } 909 else { 910 if (p[1] && (dmap[j] == map[j] || map[j] == F_XKEY)) { 911 AddXkey(&cs, &arrow[i].fun, arrow[i].type); 912 map[j] = F_XKEY; 913 } 914 else if (map[j] == F_UNASSIGNED) { 915 ClearXkey(map, &cs); 916 if (arrow[i].type == XK_CMD) 917 map[j] = arrow[i].fun.cmd; 918 else 919 AddXkey(&cs, &arrow[i].fun, arrow[i].type); 920 } 921 } 922 } 923 } 924} 925 926static Char cur_atr = 0; /* current attributes */ 927 928void 929SetAttributes(Char atr) 930{ 931 atr &= ATTRIBUTES; 932 if (atr != cur_atr) { 933 if (me_all && GoodStr(T_me)) { 934 if (((cur_atr & BOLD) && !(atr & BOLD)) || 935 ((cur_atr & UNDER) && !(atr & UNDER)) || 936 ((cur_atr & STANDOUT) && !(atr & STANDOUT))) { 937 (void) tputs(Str(T_me), 1, PUTPURE); 938 cur_atr = 0; 939 } 940 } 941 if ((atr & BOLD) != (cur_atr & BOLD)) { 942 if (atr & BOLD) { 943 if (GoodStr(T_md) && GoodStr(T_me)) { 944 (void) tputs(Str(T_md), 1, PUTPURE); 945 cur_atr |= BOLD; 946 } 947 } 948 else { 949 if (GoodStr(T_md) && GoodStr(T_me)) { 950 (void) tputs(Str(T_me), 1, PUTPURE); 951 if ((cur_atr & STANDOUT) && GoodStr(T_se)) { 952 (void) tputs(Str(T_se), 1, PUTPURE); 953 cur_atr &= ~STANDOUT; 954 } 955 if ((cur_atr & UNDER) && GoodStr(T_ue)) { 956 (void) tputs(Str(T_ue), 1, PUTPURE); 957 cur_atr &= ~UNDER; 958 } 959 cur_atr &= ~BOLD; 960 } 961 } 962 } 963 if ((atr & STANDOUT) != (cur_atr & STANDOUT)) { 964 if (atr & STANDOUT) { 965 if (GoodStr(T_so) && GoodStr(T_se)) { 966 (void) tputs(Str(T_so), 1, PUTPURE); 967 cur_atr |= STANDOUT; 968 } 969 } 970 else { 971 if (GoodStr(T_se)) { 972 (void) tputs(Str(T_se), 1, PUTPURE); 973 cur_atr &= ~STANDOUT; 974 } 975 } 976 } 977 if ((atr & UNDER) != (cur_atr & UNDER)) { 978 if (atr & UNDER) { 979 if (GoodStr(T_us) && GoodStr(T_ue)) { 980 (void) tputs(Str(T_us), 1, PUTPURE); 981 cur_atr |= UNDER; 982 } 983 } 984 else { 985 if (GoodStr(T_ue)) { 986 (void) tputs(Str(T_ue), 1, PUTPURE); 987 cur_atr &= ~UNDER; 988 } 989 } 990 } 991 } 992} 993 994int highlighting = 0; 995 996void 997StartHighlight() 998{ 999 (void) tputs(Str(T_mr), 1, PUTPURE); 1000 highlighting = 1; 1001} 1002 1003void 1004StopHighlight() 1005{ 1006 (void) tputs(Str(T_me), 1, PUTPURE); 1007 highlighting = 0; 1008} 1009 1010/* PWP 6-27-88 -- if the tty driver thinks that we can tab, we ask termcap */ 1011int 1012CanWeTab(void) 1013{ 1014 return (Val(T_pt)); 1015} 1016 1017/* move to line <where> (first line == 0) as efficiently as possible; */ 1018void 1019MoveToLine(int where) 1020{ 1021 int del; 1022 1023 if (where == CursorV) 1024 return; 1025 1026 if (where > TermV) { 1027#ifdef DEBUG_SCREEN 1028 xprintf("MoveToLine: where is ridiculous: %d\r\n", where); 1029 flush(); 1030#endif /* DEBUG_SCREEN */ 1031 return; 1032 } 1033 1034 del = where - CursorV; 1035 1036 if (del > 0) { 1037 while (del > 0) { 1038 if ((T_Margin & MARGIN_AUTO) && Display[CursorV][0] != '\0') { 1039 size_t h; 1040 1041 for (h = TermH - 1; h > 0 && Display[CursorV][h] == CHAR_DBWIDTH; 1042 h--) 1043 ; 1044 /* move without newline */ 1045 MoveToChar(h); 1046 so_write(&Display[CursorV][CursorH], TermH - CursorH); /* updates CursorH/V*/ 1047 del--; 1048 } 1049 else { 1050 if ((del > 1) && GoodStr(T_DO)) { 1051 (void) tputs(tgoto(Str(T_DO), del, del), del, PUTPURE); 1052 del = 0; 1053 } 1054 else { 1055 for ( ; del > 0; del--) 1056 (void) putraw('\n'); 1057 CursorH = 0; /* because the \n will become \r\n */ 1058 } 1059 } 1060 } 1061 } 1062 else { /* del < 0 */ 1063 if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) 1064 (void) tputs(tgoto(Str(T_UP), -del, -del), -del, PUTPURE); 1065 else { 1066 int i; 1067 if (GoodStr(T_up)) 1068 for (i = 0; i < -del; i++) 1069 (void) tputs(Str(T_up), 1, PUTPURE); 1070 } 1071 } 1072 CursorV = where; /* now where is here */ 1073} 1074 1075void 1076MoveToChar(int where) /* move to character position (where) */ 1077{ /* as efficiently as possible */ 1078 int del; 1079 1080mc_again: 1081 if (where == CursorH) 1082 return; 1083 1084 if (where >= TermH) { 1085#ifdef DEBUG_SCREEN 1086 xprintf("MoveToChar: where is riduculous: %d\r\n", where); 1087 flush(); 1088#endif /* DEBUG_SCREEN */ 1089 return; 1090 } 1091 1092 if (!where) { /* if where is first column */ 1093 (void) putraw('\r'); /* do a CR */ 1094 CursorH = 0; 1095 return; 1096 } 1097 1098 del = where - CursorH; 1099 1100 if ((del < -4 || del > 4) && GoodStr(T_ch)) 1101 /* go there directly */ 1102 (void) tputs(tgoto(Str(T_ch), where, where), where, PUTPURE); 1103 else { 1104 int i; 1105 if (del > 0) { /* moving forward */ 1106 if ((del > 4) && GoodStr(T_RI)) 1107 (void) tputs(tgoto(Str(T_RI), del, del), del, PUTPURE); 1108 else { 1109 /* if I can do tabs, use them */ 1110 if (T_Tabs) { 1111 if ((CursorH & 0370) != (where & ~0x7) 1112 && Display[CursorV][where & ~0x7] != CHAR_DBWIDTH) { 1113 /* if not within tab stop */ 1114 for (i = (CursorH & 0370); i < (where & ~0x7); i += 8) 1115 (void) putraw('\t'); /* then tab over */ 1116 CursorH = where & ~0x7; 1117 /* Note: considering that we often want to go to 1118 TermH - 1 for the wrapping, it would be nice to 1119 optimize this case by tabbing to the last column 1120 - but this doesn't work for all terminals! */ 1121 } 1122 } 1123 /* it's usually cheaper to just write the chars, so we do. */ 1124 1125 /* NOTE THAT so_write() WILL CHANGE CursorH!!! */ 1126 so_write(&Display[CursorV][CursorH], where - CursorH); 1127 1128 } 1129 } 1130 else { /* del < 0 := moving backward */ 1131 if ((-del > 4) && GoodStr(T_LE)) 1132 (void) tputs(tgoto(Str(T_LE), -del, -del), -del, PUTPURE); 1133 else { /* can't go directly there */ 1134 /* if the "cost" is greater than the "cost" from col 0 */ 1135 if (T_Tabs ? (-del > ((where >> 3) + (where & 07))) 1136 : (-del > where)) { 1137 (void) putraw('\r'); /* do a CR */ 1138 CursorH = 0; 1139 goto mc_again; /* and try again */ 1140 } 1141 for (i = 0; i < -del; i++) 1142 (void) putraw('\b'); 1143 } 1144 } 1145 } 1146 CursorH = where; /* now where is here */ 1147} 1148 1149void 1150so_write(Char *cp, int n) 1151{ 1152 int cur_pos, prompt_len = 0, region_start = 0, region_end = 0; 1153 1154 if (n <= 0) 1155 return; /* catch bugs */ 1156 1157 if (n > TermH) { 1158#ifdef DEBUG_SCREEN 1159 xprintf("so_write: n is riduculous: %d\r\n", n); 1160 flush(); 1161#endif /* DEBUG_SCREEN */ 1162 return; 1163 } 1164 1165 if (adrof(STRhighlight)) { 1166 /* find length of prompt */ 1167 Char *promptc; 1168 for (promptc = Prompt; *promptc; promptc++); 1169 prompt_len = promptc - Prompt; 1170 1171 /* find region start and end points */ 1172 if (IncMatchLen) { 1173 region_start = (Cursor - InputBuf) + prompt_len; 1174 region_end = region_start + IncMatchLen; 1175 } else if (MarkIsSet) { 1176 region_start = (min(Cursor, Mark) - InputBuf) + prompt_len; 1177 region_end = (max(Cursor, Mark) - InputBuf) + prompt_len; 1178 } 1179 } 1180 1181 do { 1182 if (adrof(STRhighlight)) { 1183 cur_pos = CursorV * TermH + CursorH; 1184 if (!highlighting && 1185 cur_pos >= region_start && cur_pos < region_end) 1186 StartHighlight(); 1187 else if (highlighting && cur_pos >= region_end) 1188 StopHighlight(); 1189 1190 /* don't highlight over the cursor. the highlighting's reverse 1191 * video would cancel it out. :P */ 1192 if (highlighting && cur_pos == (Cursor - InputBuf) + prompt_len) 1193 StopHighlight(); 1194 } 1195 1196 if (*cp != CHAR_DBWIDTH) { 1197 if (*cp & LITERAL) { 1198 Char *d; 1199#ifdef DEBUG_LITERAL 1200 xprintf("so: litnum %d\r\n", (int)(*cp & ~LITERAL)); 1201#endif /* DEBUG_LITERAL */ 1202 for (d = litptr + (*cp & ~LITERAL) * LIT_FACTOR; *d; d++) 1203 (void) putwraw(*d); 1204 } 1205 else 1206 (void) putwraw(*cp); 1207 } 1208 cp++; 1209 CursorH++; 1210 } while (--n); 1211 1212 if (adrof(STRhighlight) && highlighting) 1213 StopHighlight(); 1214 1215 if (CursorH >= TermH) { /* wrap? */ 1216 if (T_Margin & MARGIN_AUTO) { /* yes */ 1217 CursorH = 0; 1218 CursorV++; 1219 if (T_Margin & MARGIN_MAGIC) { 1220 /* force the wrap to avoid the "magic" situation */ 1221 Char xc; 1222 if ((xc = Display[CursorV][CursorH]) != '\0') { 1223 so_write(&xc, 1); 1224 while(Display[CursorV][CursorH] == CHAR_DBWIDTH) 1225 CursorH++; 1226 } 1227 else { 1228 (void) putraw(' '); 1229 CursorH = 1; 1230 } 1231 } 1232 } 1233 else /* no wrap, but cursor stays on screen */ 1234 CursorH = TermH - 1; 1235 } 1236} 1237 1238 1239void 1240DeleteChars(int num) /* deletes <num> characters */ 1241{ 1242 if (num <= 0) 1243 return; 1244 1245 if (!T_CanDel) { 1246#ifdef DEBUG_EDIT 1247 xprintf(CGETS(7, 16, "ERROR: cannot delete\r\n")); 1248#endif /* DEBUG_EDIT */ 1249 flush(); 1250 return; 1251 } 1252 1253 if (num > TermH) { 1254#ifdef DEBUG_SCREEN 1255 xprintf(CGETS(7, 17, "DeleteChars: num is riduculous: %d\r\n"), num); 1256 flush(); 1257#endif /* DEBUG_SCREEN */ 1258 return; 1259 } 1260 1261 if (GoodStr(T_DC)) /* if I have multiple delete */ 1262 if ((num > 1) || !GoodStr(T_dc)) { /* if dc would be more expen. */ 1263 (void) tputs(tgoto(Str(T_DC), num, num), num, PUTPURE); 1264 return; 1265 } 1266 1267 if (GoodStr(T_dm)) /* if I have delete mode */ 1268 (void) tputs(Str(T_dm), 1, PUTPURE); 1269 1270 if (GoodStr(T_dc)) /* else do one at a time */ 1271 while (num--) 1272 (void) tputs(Str(T_dc), 1, PUTPURE); 1273 1274 if (GoodStr(T_ed)) /* if I have delete mode */ 1275 (void) tputs(Str(T_ed), 1, PUTPURE); 1276} 1277 1278/* Puts terminal in insert character mode, or inserts num characters in the 1279 line */ 1280void 1281Insert_write(Char *cp, int num) 1282{ 1283 if (num <= 0) 1284 return; 1285 if (!T_CanIns) { 1286#ifdef DEBUG_EDIT 1287 xprintf(CGETS(7, 18, "ERROR: cannot insert\r\n")); 1288#endif /* DEBUG_EDIT */ 1289 flush(); 1290 return; 1291 } 1292 1293 if (num > TermH) { 1294#ifdef DEBUG_SCREEN 1295 xprintf(CGETS(7, 19, "StartInsert: num is riduculous: %d\r\n"), num); 1296 flush(); 1297#endif /* DEBUG_SCREEN */ 1298 return; 1299 } 1300 1301 if (GoodStr(T_IC)) /* if I have multiple insert */ 1302 if ((num > 1) || !GoodStr(T_ic)) { /* if ic would be more expen. */ 1303 (void) tputs(tgoto(Str(T_IC), num, num), num, PUTPURE); 1304 so_write(cp, num); /* this updates CursorH/V */ 1305 return; 1306 } 1307 1308 if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */ 1309 (void) tputs(Str(T_im), 1, PUTPURE); 1310 1311 so_write(cp, num); /* this updates CursorH/V */ 1312 1313 if (GoodStr(T_ip)) /* have to make num chars insert */ 1314 (void) tputs(Str(T_ip), 1, PUTPURE); 1315 1316 (void) tputs(Str(T_ei), 1, PUTPURE); 1317 return; 1318 } 1319 1320 do { 1321 if (GoodStr(T_ic)) /* have to make num chars insert */ 1322 (void) tputs(Str(T_ic), 1, PUTPURE); /* insert a char */ 1323 1324 so_write(cp++, 1); /* this updates CursorH/V */ 1325 1326 if (GoodStr(T_ip)) /* have to make num chars insert */ 1327 (void) tputs(Str(T_ip), 1, PUTPURE);/* pad the inserted char */ 1328 1329 } while (--num); 1330 1331} 1332 1333/* clear to end of line. There are num characters to clear */ 1334void 1335ClearEOL(int num) 1336{ 1337 int i; 1338 1339 if (num <= 0) 1340 return; 1341 1342 if (T_CanCEOL && GoodStr(T_ce)) 1343 (void) tputs(Str(T_ce), 1, PUTPURE); 1344 else { 1345 for (i = 0; i < num; i++) 1346 (void) putraw(' '); 1347 CursorH += num; /* have written num spaces */ 1348 } 1349} 1350 1351void 1352ClearScreen(void) 1353{ /* clear the whole screen and home */ 1354 if (GoodStr(T_cl)) 1355 /* send the clear screen code */ 1356 (void) tputs(Str(T_cl), Val(T_li), PUTPURE); 1357 else if (GoodStr(T_ho) && GoodStr(T_cd)) { 1358 (void) tputs(Str(T_ho), Val(T_li), PUTPURE); /* home */ 1359 /* clear to bottom of screen */ 1360 (void) tputs(Str(T_cd), Val(T_li), PUTPURE); 1361 } 1362 else { 1363 (void) putraw('\r'); 1364 (void) putraw('\n'); 1365 } 1366} 1367 1368void 1369SoundBeep(void) 1370{ /* produce a sound */ 1371 beep_cmd (); 1372 if (adrof(STRnobeep)) 1373 return; 1374 1375 if (GoodStr(T_vb) && adrof(STRvisiblebell)) 1376 (void) tputs(Str(T_vb), 1, PUTPURE); /* visible bell */ 1377 else if (GoodStr(T_bl)) 1378 /* what termcap says we should use */ 1379 (void) tputs(Str(T_bl), 1, PUTPURE); 1380 else 1381 (void) putraw(CTL_ESC('\007')); /* an ASCII bell; ^G */ 1382} 1383 1384void 1385ClearToBottom(void) 1386{ /* clear to the bottom of the screen */ 1387 if (GoodStr(T_cd)) 1388 (void) tputs(Str(T_cd), Val(T_li), PUTPURE); 1389 else if (GoodStr(T_ce)) 1390 (void) tputs(Str(T_ce), Val(T_li), PUTPURE); 1391} 1392 1393void 1394GetTermCaps(void) 1395{ /* read in the needed terminal capabilites */ 1396 int i; 1397 const char *ptr; 1398 char buf[TC_BUFSIZE]; 1399 static char bp[TC_BUFSIZE]; 1400 char *area; 1401 struct termcapstr *t; 1402 1403 1404#ifdef SIG_WINDOW 1405 sigset_t oset, set; 1406 int lins, cols; 1407 1408 /* don't want to confuse things here */ 1409 sigemptyset(&set); 1410 sigaddset(&set, SIG_WINDOW); 1411 (void)sigprocmask(SIG_BLOCK, &set, &oset); 1412 cleanup_push(&oset, sigprocmask_cleanup); 1413#endif /* SIG_WINDOW */ 1414 area = buf; 1415 1416 GotTermCaps = 1; 1417 1418 setname("gettermcaps"); 1419 ptr = getenv("TERM"); 1420 1421#ifdef apollo 1422 /* 1423 * If we are on a pad, we pretend that we are dumb. Otherwise the termcap 1424 * library will put us in a weird screen mode, thinking that we are going 1425 * to use curses 1426 */ 1427 if (isapad()) 1428 ptr = "dumb"; 1429#endif /* apollo */ 1430 1431 if (!ptr || !ptr[0] || !strcmp(ptr, "wm") || !strcmp(ptr,"dmx")) 1432 ptr = "dumb"; 1433 1434 setzero(bp, TC_BUFSIZE); 1435 1436 i = tgetent(bp, ptr); 1437 if (i <= 0) { 1438 if (i == -1) { 1439#if (SYSVREL == 0) || defined(IRIS3D) 1440 xprintf(CGETS(7, 20, "%s: Cannot open /etc/termcap.\n"), progname); 1441 } 1442 else if (i == 0) { 1443#endif /* SYSVREL */ 1444 xprintf(CGETS(7, 21, 1445 "%s: No entry for terminal type \"%s\"\n"), progname, 1446 getenv("TERM")); 1447 } 1448 xprintf(CGETS(7, 22, "%s: using dumb terminal settings.\n"), progname); 1449 Val(T_co) = 80; /* do a dumb terminal */ 1450 Val(T_pt) = Val(T_km) = Val(T_li) = 0; 1451 for (t = tstr; t->name != NULL; t++) 1452 TCset(t, NULL); 1453 } 1454 else { 1455 /* Can we tab */ 1456 Val(T_pt) = tgetflag("pt") && !tgetflag("xt"); 1457 /* do we have a meta? */ 1458 Val(T_km) = (tgetflag("km") || tgetflag("MT")); 1459 Val(T_am) = tgetflag("am"); 1460 Val(T_xn) = tgetflag("xn"); 1461 Val(T_co) = tgetnum("co"); 1462 Val(T_li) = tgetnum("li"); 1463 for (t = tstr; t->name != NULL; t++) 1464 TCset(t, tgetstr(t->name, &area)); 1465 } 1466 if (Val(T_co) < 2) 1467 Val(T_co) = 80; /* just in case */ 1468 if (Val(T_li) < 1) 1469 Val(T_li) = 24; 1470 1471 T_Cols = (Char) Val(T_co); 1472 T_Lines = (Char) Val(T_li); 1473 if (T_Tabs) 1474 T_Tabs = Val(T_pt); 1475 T_HasMeta = Val(T_km); 1476 T_Margin = Val(T_am) ? MARGIN_AUTO : 0; 1477 T_Margin |= Val(T_xn) ? MARGIN_MAGIC : 0; 1478 T_CanCEOL = GoodStr(T_ce); 1479 T_CanDel = GoodStr(T_dc) || GoodStr(T_DC); 1480 T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC); 1481 T_CanUP = GoodStr(T_up) || GoodStr(T_UP); 1482 if (GoodStr(T_me) && GoodStr(T_ue)) 1483 me_all = (strcmp(Str(T_me), Str(T_ue)) == 0); 1484 else 1485 me_all = 0; 1486 if (GoodStr(T_me) && GoodStr(T_se)) 1487 me_all |= (strcmp(Str(T_me), Str(T_se)) == 0); 1488 1489 1490#ifdef DEBUG_SCREEN 1491 if (!T_CanUP) { 1492 xprintf(CGETS(7, 23, "%s: WARNING: Your terminal cannot move up.\n", 1493 progname)); 1494 xprintf(CGETS(7, 24, "Editing may be odd for long lines.\n")); 1495 } 1496 if (!T_CanCEOL) 1497 xprintf(CGETS(7, 25, "no clear EOL capability.\n")); 1498 if (!T_CanDel) 1499 xprintf(CGETS(7, 26, "no delete char capability.\n")); 1500 if (!T_CanIns) 1501 xprintf(CGETS(7, 27, "no insert char capability.\n")); 1502#endif /* DEBUG_SCREEN */ 1503 1504 1505 1506#ifdef SIG_WINDOW 1507 (void) GetSize(&lins, &cols); /* get the correct window size */ 1508 ChangeSize(lins, cols); 1509 1510 cleanup_until(&oset); /* can change it again */ 1511#else /* SIG_WINDOW */ 1512 ChangeSize(Val(T_li), Val(T_co)); 1513#endif /* SIG_WINDOW */ 1514 1515 BindArrowKeys(); 1516} 1517 1518#ifdef SIG_WINDOW 1519/* GetSize(): 1520 * Return the new window size in lines and cols, and 1521 * true if the size was changed. This can fail if SHIN 1522 * is not a tty, but it will work in most cases. 1523 */ 1524int 1525GetSize(int *lins, int *cols) 1526{ 1527 *cols = Val(T_co); 1528 *lins = Val(T_li); 1529 1530#ifdef TIOCGWINSZ 1531# define KNOWsize 1532# ifndef lint 1533 { 1534 struct winsize ws; /* from 4.3 */ 1535 1536 if (ioctl(SHIN, TIOCGWINSZ, (ioctl_t) &ws) != -1) { 1537 if (ws.ws_col) 1538 *cols = ws.ws_col; 1539 if (ws.ws_row) 1540 *lins = ws.ws_row; 1541 } 1542 } 1543# endif /* !lint */ 1544#else /* TIOCGWINSZ */ 1545# ifdef TIOCGSIZE 1546# define KNOWsize 1547 { 1548 struct ttysize ts; /* from Sun */ 1549 1550 if (ioctl(SHIN, TIOCGSIZE, (ioctl_t) &ts) != -1) { 1551 if (ts.ts_cols) 1552 *cols = ts.ts_cols; 1553 if (ts.ts_lines) 1554 *lins = ts.ts_lines; 1555 } 1556 } 1557# endif /* TIOCGSIZE */ 1558#endif /* TIOCGWINSZ */ 1559 1560 return (Val(T_co) != *cols || Val(T_li) != *lins); 1561} 1562 1563#endif /* SIG_WINDOW */ 1564 1565void 1566ChangeSize(int lins, int cols) 1567{ 1568 /* 1569 * Just in case 1570 */ 1571 Val(T_co) = (cols < 2) ? 80 : cols; 1572 Val(T_li) = (lins < 1) ? 24 : lins; 1573 1574#ifdef KNOWsize 1575 /* 1576 * We want to affect the environment only when we have a valid 1577 * setup, not when we get bad settings. Consider the following scenario: 1578 * We just logged in, and we have not initialized the editor yet. 1579 * We reset termcap with tset, and not $TERMCAP has the right 1580 * terminal size. But since the editor is not initialized yet, and 1581 * the kernel's notion of the terminal size might be wrong we arrive 1582 * here with lines = columns = 0. If we reset the environment we lose 1583 * our only chance to get the window size right. 1584 */ 1585 if (Val(T_co) == cols && Val(T_li) == lins) { 1586 Char *p; 1587 char *tptr; 1588 1589 if (getenv("COLUMNS")) { 1590 p = Itoa(Val(T_co), 0, 0); 1591 cleanup_push(p, xfree); 1592 tsetenv(STRCOLUMNS, p); 1593 cleanup_until(p); 1594 } 1595 1596 if (getenv("LINES")) { 1597 p = Itoa(Val(T_li), 0, 0); 1598 cleanup_push(p, xfree); 1599 tsetenv(STRLINES, p); 1600 cleanup_until(p); 1601 } 1602 1603 if ((tptr = getenv("TERMCAP")) != NULL) { 1604 /* Leave 64 characters slop in case we enlarge the termcap string */ 1605 Char termcap[TC_BUFSIZE+64], backup[TC_BUFSIZE+64], *ptr; 1606 Char buf[4]; 1607 1608 ptr = str2short(tptr); 1609 (void) Strncpy(termcap, ptr, TC_BUFSIZE); 1610 termcap[TC_BUFSIZE-1] = '\0'; 1611 1612 /* update termcap string; first do columns */ 1613 buf[0] = 'c'; 1614 buf[1] = 'o'; 1615 buf[2] = '#'; 1616 buf[3] = '\0'; 1617 if ((ptr = Strstr(termcap, buf)) == NULL) { 1618 (void) Strcpy(backup, termcap); 1619 } 1620 else { 1621 size_t len = (ptr - termcap) + Strlen(buf); 1622 (void) Strncpy(backup, termcap, len); 1623 backup[len] = '\0'; 1624 p = Itoa(Val(T_co), 0, 0); 1625 (void) Strcat(backup + len, p); 1626 xfree(p); 1627 ptr = Strchr(ptr, ':'); 1628 (void) Strcat(backup, ptr); 1629 } 1630 1631 /* now do lines */ 1632 buf[0] = 'l'; 1633 buf[1] = 'i'; 1634 buf[2] = '#'; 1635 buf[3] = '\0'; 1636 if ((ptr = Strstr(backup, buf)) == NULL) { 1637 (void) Strcpy(termcap, backup); 1638 } 1639 else { 1640 size_t len = (ptr - backup) + Strlen(buf); 1641 (void) Strncpy(termcap, backup, len); 1642 termcap[len] = '\0'; 1643 p = Itoa(Val(T_li), 0, 0); 1644 (void) Strcat(termcap, p); 1645 xfree(p); 1646 ptr = Strchr(ptr, ':'); 1647 (void) Strcat(termcap, ptr); 1648 } 1649 /* 1650 * Chop the termcap string at TC_BUFSIZE-1 characters to avoid 1651 * core-dumps in the termcap routines 1652 */ 1653 termcap[TC_BUFSIZE - 1] = '\0'; 1654 tsetenv(STRTERMCAP, termcap); 1655 } 1656 } 1657#endif /* KNOWsize */ 1658 1659 ReBufferDisplay(); /* re-make display buffers */ 1660 ClearDisp(); 1661} 1662