ed.screen.c revision 145479
1204076Spjd/* $Header: /src/pub/tcsh/ed.screen.c,v 3.63 2005/01/18 20:43:30 christos Exp $ */ 2204076Spjd/* 3211877Spjd * ed.screen.c: Editor/termcap-curses interface 4204076Spjd */ 5204076Spjd/*- 6204076Spjd * Copyright (c) 1980, 1991 The Regents of the University of California. 7204076Spjd * All rights reserved. 8204076Spjd * 9204076Spjd * Redistribution and use in source and binary forms, with or without 10204076Spjd * modification, are permitted provided that the following conditions 11204076Spjd * are met: 12204076Spjd * 1. Redistributions of source code must retain the above copyright 13204076Spjd * notice, this list of conditions and the following disclaimer. 14204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 15204076Spjd * notice, this list of conditions and the following disclaimer in the 16204076Spjd * documentation and/or other materials provided with the distribution. 17204076Spjd * 3. Neither the name of the University nor the names of its contributors 18204076Spjd * may be used to endorse or promote products derived from this software 19204076Spjd * without specific prior written permission. 20204076Spjd * 21204076Spjd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31204076Spjd * SUCH DAMAGE. 32204076Spjd */ 33204076Spjd#include "sh.h" 34204076Spjd 35204076SpjdRCSID("$Id: ed.screen.c,v 3.63 2005/01/18 20:43:30 christos Exp $") 36204076Spjd 37204076Spjd#include "ed.h" 38204076Spjd#include "tc.h" 39204076Spjd#include "ed.defns.h" 40204076Spjd 41204076Spjd/* #define DEBUG_LITERAL */ 42204076Spjd 43204076Spjd/* 44204076Spjd * IMPORTANT NOTE: these routines are allowed to look at the current screen 45213009Spjd * and the current possition assuming that it is correct. If this is not 46204076Spjd * true, then the update will be WRONG! This is (should be) a valid 47204076Spjd * assumption... 48204076Spjd */ 49204076Spjd 50204076Spjd#define TC_BUFSIZE 2048 51204076Spjd 52204076Spjd#define GoodStr(a) (tstr[a].str != NULL && tstr[a].str[0] != '\0') 53204076Spjd#define Str(a) tstr[a].str 54204076Spjd#define Val(a) tval[a].val 55204076Spjd 56204076Spjdstatic struct { 57212038Spjd const char *b_name; 58204076Spjd speed_t b_rate; 59204076Spjd} baud_rate[] = { 60204076Spjd 61211977Spjd#ifdef B0 62204076Spjd { "0", B0 }, 63204076Spjd#endif 64204076Spjd#ifdef B50 65204076Spjd { "50", B50 }, 66204076Spjd#endif 67204076Spjd#ifdef B75 68219864Spjd { "75", B75 }, 69219864Spjd#endif 70204076Spjd#ifdef B110 71204076Spjd { "110", B110 }, 72204076Spjd#endif 73204076Spjd#ifdef B134 74246922Spjd { "134", B134 }, 75204076Spjd#endif 76204076Spjd#ifdef B150 77204076Spjd { "150", B150 }, 78211984Spjd#endif 79211984Spjd#ifdef B200 80204076Spjd { "200", B200 }, 81204076Spjd#endif 82204076Spjd#ifdef B300 83204076Spjd { "300", B300 }, 84204076Spjd#endif 85257155Strociny#ifdef B600 86204076Spjd { "600", B600 }, 87204076Spjd#endif 88204076Spjd#ifdef B900 89255717Strociny { "900", B900 }, 90204076Spjd#endif 91204076Spjd#ifdef B1200 92257155Strociny { "1200", B1200 }, 93204076Spjd#endif 94204076Spjd#ifdef B1800 95204076Spjd { "1800", B1800 }, 96255717Strociny#endif 97204076Spjd#ifdef B2400 98204076Spjd { "2400", B2400 }, 99257155Strociny#endif 100204076Spjd#ifdef B3600 101204076Spjd { "3600", B3600 }, 102204076Spjd#endif 103204076Spjd#ifdef B4800 104204076Spjd { "4800", B4800 }, 105204076Spjd#endif 106204076Spjd#ifdef B7200 107204076Spjd { "7200", B7200 }, 108204076Spjd#endif 109204076Spjd#ifdef B9600 110204076Spjd { "9600", B9600 }, 111204076Spjd#endif 112211877Spjd#ifdef EXTA 113211877Spjd { "19200", EXTA }, 114259195Strociny#endif 115259195Strociny#ifdef B19200 116211877Spjd { "19200", B19200 }, 117257155Strociny#endif 118211877Spjd#ifdef EXTB 119211877Spjd { "38400", EXTB }, 120211877Spjd#endif 121211877Spjd#ifdef B38400 122211877Spjd { "38400", B38400 }, 123211877Spjd#endif 124211877Spjd { NULL, 0 } 125211877Spjd}; 126257155Strociny 127257155Strociny#define T_al 0 128211877Spjd#define T_bl 1 129211877Spjd#define T_cd 2 130211877Spjd#define T_ce 3 131226861Spjd#define T_ch 4 132226854Spjd#define T_cl 5 133257155Strociny#define T_dc 6 134257155Strociny#define T_dl 7 135257155Strociny#define T_dm 8 136257155Strociny#define T_ed 9 137257155Strociny#define T_ei 10 138257155Strociny#define T_fs 11 139257155Strociny#define T_ho 12 140257155Strociny#define T_ic 13 141257155Strociny#define T_im 14 142226854Spjd#define T_ip 15 143226854Spjd#define T_kd 16 144211877Spjd#define T_kl 17 145226854Spjd#define T_kr 18 146226854Spjd#define T_ku 19 147226854Spjd#define T_md 20 148226854Spjd#define T_me 21 149226854Spjd#define T_nd 22 150246922Spjd#define T_se 23 151226854Spjd#define T_so 24 152226854Spjd#define T_ts 25 153204076Spjd#define T_up 26 154246922Spjd#define T_us 27 155246922Spjd#define T_ue 28 156246922Spjd#define T_vb 29 157246922Spjd#define T_DC 30 158246922Spjd#define T_DO 31 159246922Spjd#define T_IC 32 160246922Spjd#define T_LE 33 161246922Spjd#define T_RI 34 162246922Spjd#define T_UP 35 163246922Spjd#define T_kh 36 164246922Spjd#define T_at7 37 165246922Spjd#define T_str 38 166246922Spjdstatic struct termcapstr { 167246922Spjd const char *name; 168246922Spjd const char *long_name; 169204076Spjd char *str; 170204076Spjd} tstr[T_str + 1]; 171204076Spjd 172204076Spjd 173204076Spjd#define T_am 0 174204076Spjd#define T_pt 1 175204076Spjd#define T_li 2 176204076Spjd#define T_co 3 177204076Spjd#define T_km 4 178204076Spjd#define T_xn 5 179204076Spjd#define T_val 6 180204076Spjdstatic struct termcapval { 181204076Spjd const char *name; 182204076Spjd const char *long_name; 183204076Spjd int val; 184204076Spjd} tval[T_val + 1]; 185204076Spjd 186204076Spjdvoid 187204076Spjdterminit() 188204076Spjd{ 189204076Spjd#ifdef NLS_CATALOGS 190204076Spjd int i; 191204076Spjd 192204076Spjd for (i = 0; i < T_str + 1; i++) 193210879Spjd xfree((ptr_t) tstr[i].long_name); 194210879Spjd 195210879Spjd for (i = 0; i < T_val + 1; i++) 196204076Spjd xfree((ptr_t) tval[i].long_name); 197204076Spjd#endif 198204076Spjd 199210879Spjd tstr[T_al].name = "al"; 200210879Spjd tstr[T_al].long_name = CSAVS(4, 1, "add new blank line"); 201210879Spjd 202204076Spjd tstr[T_bl].name = "bl"; 203226854Spjd tstr[T_bl].long_name = CSAVS(4, 2, "audible bell"); 204204076Spjd 205257155Strociny tstr[T_cd].name = "cd"; 206204076Spjd tstr[T_cd].long_name = CSAVS(4, 3, "clear to bottom"); 207204076Spjd 208204076Spjd tstr[T_ce].name = "ce"; 209204076Spjd tstr[T_ce].long_name = CSAVS(4, 4, "clear to end of line"); 210204076Spjd 211204076Spjd tstr[T_ch].name = "ch"; 212204076Spjd tstr[T_ch].long_name = CSAVS(4, 5, "cursor to horiz pos"); 213229945Spjd 214204076Spjd tstr[T_cl].name = "cl"; 215204076Spjd tstr[T_cl].long_name = CSAVS(4, 6, "clear screen"); 216204076Spjd 217204076Spjd tstr[T_dc].name = "dc"; 218204076Spjd tstr[T_dc].long_name = CSAVS(4, 7, "delete a character"); 219204076Spjd 220204076Spjd tstr[T_dl].name = "dl"; 221204076Spjd tstr[T_dl].long_name = CSAVS(4, 8, "delete a line"); 222204076Spjd 223204076Spjd tstr[T_dm].name = "dm"; 224204076Spjd tstr[T_dm].long_name = CSAVS(4, 9, "start delete mode"); 225223181Strociny 226220271Spjd tstr[T_ed].name = "ed"; 227220271Spjd tstr[T_ed].long_name = CSAVS(4, 10, "end delete mode"); 228220271Spjd 229223181Strociny tstr[T_ei].name = "ei"; 230220271Spjd tstr[T_ei].long_name = CSAVS(4, 11, "end insert mode"); 231204076Spjd 232204076Spjd tstr[T_fs].name = "fs"; 233204076Spjd tstr[T_fs].long_name = CSAVS(4, 12, "cursor from status line"); 234204076Spjd 235204076Spjd tstr[T_ho].name = "ho"; 236204076Spjd tstr[T_ho].long_name = CSAVS(4, 13, "home cursor"); 237204076Spjd 238204076Spjd tstr[T_ic].name = "ic"; 239204076Spjd tstr[T_ic].long_name = CSAVS(4, 14, "insert character"); 240204076Spjd 241204076Spjd tstr[T_im].name = "im"; 242204076Spjd tstr[T_im].long_name = CSAVS(4, 15, "start insert mode"); 243204076Spjd 244204076Spjd tstr[T_ip].name = "ip"; 245204076Spjd tstr[T_ip].long_name = CSAVS(4, 16, "insert padding"); 246204076Spjd 247204076Spjd tstr[T_kd].name = "kd"; 248204076Spjd tstr[T_kd].long_name = CSAVS(4, 17, "sends cursor down"); 249204076Spjd 250204076Spjd tstr[T_kl].name = "kl"; 251204076Spjd tstr[T_kl].long_name = CSAVS(4, 18, "sends cursor left"); 252204076Spjd 253204076Spjd tstr[T_kr].name = "kr"; 254204076Spjd tstr[T_kr].long_name = CSAVS(4, 19, "sends cursor right"); 255204076Spjd 256204076Spjd tstr[T_ku].name = "ku"; 257204076Spjd tstr[T_ku].long_name = CSAVS(4, 20, "sends cursor up"); 258204076Spjd 259204076Spjd tstr[T_md].name = "md"; 260204076Spjd tstr[T_md].long_name = CSAVS(4, 21, "begin bold"); 261204076Spjd 262204076Spjd tstr[T_me].name = "me"; 263204076Spjd tstr[T_me].long_name = CSAVS(4, 22, "end attributes"); 264204076Spjd 265204076Spjd tstr[T_nd].name = "nd"; 266204076Spjd tstr[T_nd].long_name = CSAVS(4, 23, "non destructive space"); 267204076Spjd 268204076Spjd tstr[T_se].name = "se"; 269204076Spjd tstr[T_se].long_name = CSAVS(4, 24, "end standout"); 270204076Spjd 271204076Spjd tstr[T_so].name = "so"; 272204076Spjd tstr[T_so].long_name = CSAVS(4, 25, "begin standout"); 273204076Spjd 274204076Spjd tstr[T_ts].name = "ts"; 275204076Spjd tstr[T_ts].long_name = CSAVS(4, 26, "cursor to status line"); 276204076Spjd 277204076Spjd tstr[T_up].name = "up"; 278204076Spjd tstr[T_up].long_name = CSAVS(4, 27, "cursor up one"); 279204076Spjd 280204076Spjd tstr[T_us].name = "us"; 281204076Spjd tstr[T_us].long_name = CSAVS(4, 28, "begin underline"); 282204076Spjd 283204076Spjd tstr[T_ue].name = "ue"; 284204076Spjd tstr[T_ue].long_name = CSAVS(4, 29, "end underline"); 285204076Spjd 286204076Spjd tstr[T_vb].name = "vb"; 287214284Spjd tstr[T_vb].long_name = CSAVS(4, 30, "visible bell"); 288214284Spjd 289214284Spjd tstr[T_DC].name = "DC"; 290214284Spjd tstr[T_DC].long_name = CSAVS(4, 31, "delete multiple chars"); 291204076Spjd 292218138Spjd tstr[T_DO].name = "DO"; 293204076Spjd tstr[T_DO].long_name = CSAVS(4, 32, "cursor down multiple"); 294229945Spjd 295204076Spjd tstr[T_IC].name = "IC"; 296214284Spjd tstr[T_IC].long_name = CSAVS(4, 33, "insert multiple chars"); 297214284Spjd 298214284Spjd tstr[T_LE].name = "LE"; 299214284Spjd tstr[T_LE].long_name = CSAVS(4, 34, "cursor left multiple"); 300214284Spjd 301214284Spjd tstr[T_RI].name = "RI"; 302214284Spjd tstr[T_RI].long_name = CSAVS(4, 35, "cursor right multiple"); 303220865Spjd 304204076Spjd tstr[T_UP].name = "UP"; 305219830Spjd tstr[T_UP].long_name = CSAVS(4, 36, "cursor up multiple"); 306219830Spjd 307219830Spjd tstr[T_kh].name = "kh"; 308226854Spjd tstr[T_kh].long_name = CSAVS(4, 37, "send cursor home"); 309219830Spjd 310219830Spjd tstr[T_at7].name = "@7"; 311219830Spjd tstr[T_at7].long_name = CSAVS(4, 38, "send cursor end"); 312219830Spjd 313219830Spjd tstr[T_str].name = NULL; 314230092Spjd tstr[T_str].long_name = NULL; 315230092Spjd 316230092Spjd 317230092Spjd tval[T_am].name = "am"; 318219830Spjd tval[T_am].long_name = CSAVS(4, 37, "Has automatic margins"); 319219830Spjd 320219831Spjd tval[T_pt].name = "pt"; 321219830Spjd tval[T_pt].long_name = CSAVS(4, 38, "Can use physical tabs"); 322204076Spjd 323226842Spjd tval[T_li].name = "li"; 324204076Spjd tval[T_li].long_name = CSAVS(4, 39, "Number of lines"); 325204076Spjd 326226842Spjd tval[T_co].name = "co"; 327204076Spjd tval[T_co].long_name = CSAVS(4, 40, "Number of columns"); 328204076Spjd 329226842Spjd tval[T_km].name = "km"; 330204076Spjd tval[T_km].long_name = CSAVS(4, 41, "Has meta key"); 331204076Spjd 332204076Spjd tval[T_xn].name = "xn"; 333204076Spjd tval[T_xn].long_name = CSAVS(4, 42, "Newline ignored at right margin"); 334204076Spjd 335204076Spjd tval[T_val].name = NULL; 336204076Spjd tval[T_val].long_name = NULL; 337204076Spjd} 338204076Spjd 339204076Spjd/* 340204076Spjd * A very useful table from justin@crim.ca (Justin Bur) :-) 341204076Spjd * (Modified by per@erix.ericsson.se (Per Hedeland) 342204076Spjd * - first (and second:-) case fixed) 343204076Spjd * 344204076Spjd * Description Termcap variables tcsh behavior 345204076Spjd * am xn UseRightmost SendCRLF 346204076Spjd * -------------- ------- ------- ------------ ------------ 347204076Spjd * Automargins yes no yes no 348204076Spjd * Magic Margins yes yes yes no 349204076Spjd * No Wrap no -- yes yes 350204076Spjd */ 351204076Spjd 352204076Spjdstatic int me_all = 0; /* does two or more of the attributes use me */ 353204076Spjd 354204076Spjdstatic void ReBufferDisplay __P((void)); 355204076Spjdstatic void TCalloc __P((struct termcapstr *, char *)); 356204076Spjd 357204076Spjd 358226854Spjdstatic void 359204076SpjdTCalloc(t, cap) 360204076Spjd struct termcapstr *t; 361230092Spjd char *cap; 362230092Spjd{ 363230092Spjd static char termcap_alloc[TC_BUFSIZE]; 364230092Spjd char termbuf[TC_BUFSIZE]; 365226854Spjd struct termcapstr *ts; 366226854Spjd static int tloc = 0; 367226854Spjd int tlen, clen; 368226854Spjd 369226854Spjd if (cap == NULL || *cap == '\0') { 370226854Spjd t->str = NULL; 371204076Spjd return; 372204076Spjd } 373204076Spjd else 374204076Spjd clen = strlen(cap); 375204076Spjd 376204076Spjd if (t->str == NULL) 377218138Spjd tlen = 0; 378204076Spjd else 379204076Spjd tlen = strlen(t->str); 380204076Spjd 381204076Spjd /* 382204076Spjd * New string is shorter; no need to allocate space 383204076Spjd */ 384204076Spjd if (clen <= tlen) { 385204076Spjd (void) strcpy(t->str, cap); 386204076Spjd return; 387204076Spjd } 388204076Spjd 389204076Spjd /* 390204076Spjd * New string is longer; see if we have enough space to append 391204076Spjd */ 392204076Spjd if (tloc + 3 < TC_BUFSIZE) { 393204076Spjd (void) strcpy(t->str = &termcap_alloc[tloc], cap); 394204076Spjd tloc += clen + 1; /* one for \0 */ 395204076Spjd return; 396220007Spjd } 397229945Spjd 398214276Spjd /* 399204076Spjd * Compact our buffer; no need to check compaction, cause we know it 400204076Spjd * fits... 401214275Spjd */ 402214275Spjd tlen = 0; 403209182Spjd for (ts = tstr; ts->name != NULL; ts++) 404223181Strociny if (t != ts && ts->str != NULL && ts->str[0] != '\0') { 405220271Spjd char *ptr; 406220271Spjd 407220271Spjd for (ptr = ts->str; *ptr != '\0'; termbuf[tlen++] = *ptr++) 408223181Strociny continue; 409204076Spjd termbuf[tlen++] = '\0'; 410204076Spjd } 411204076Spjd (void) memmove((ptr_t) termcap_alloc, (ptr_t) termbuf, (size_t) TC_BUFSIZE); 412204076Spjd tloc = tlen; 413204076Spjd if (tloc + 3 >= TC_BUFSIZE) { 414213009Spjd stderror(ERR_NAME | ERR_TCNOSTR); 415204076Spjd return; 416204076Spjd } 417219482Strociny (void) strcpy(t->str = &termcap_alloc[tloc], cap); 418204076Spjd tloc += clen + 1; /* one for \0 */ 419204076Spjd return; 420204076Spjd} 421204076Spjd 422229945Spjd 423204076Spjd/*ARGSUSED*/ 424204076Spjdvoid 425204076SpjdTellTC() 426204076Spjd{ 427212038Spjd struct termcapstr *t; 428212038Spjd char *s; 429212038Spjd 430229945Spjd xprintf(CGETS(7, 1, "\n\tTcsh thinks your terminal has the\n")); 431212038Spjd xprintf(CGETS(7, 2, "\tfollowing characteristics:\n\n")); 432212038Spjd xprintf(CGETS(7, 3, "\tIt has %d columns and %d lines\n"), 433212038Spjd Val(T_co), Val(T_li)); 434212038Spjd s = strsave(T_HasMeta ? CGETS(7, 5, "a") : CGETS(7, 6, "no")); 435204076Spjd xprintf(CGETS(7, 4, "\tIt has %s meta key\n"), s); 436204076Spjd xfree(s); 437229744Spjd s = strsave(T_Tabs ? "" : CGETS(7, 8, " not")); 438204076Spjd xprintf(CGETS(7, 7, "\tIt can%s use tabs\n"), s); 439204076Spjd xfree(s); 440204076Spjd s = strsave((T_Margin&MARGIN_AUTO) ? 441204076Spjd CGETS(7, 10, "has") : CGETS(7, 11, "does not have")); 442204076Spjd xprintf(CGETS(7, 9, "\tIt %s automatic margins\n"), s); 443204076Spjd xfree(s); 444204076Spjd if (T_Margin & MARGIN_AUTO) { 445204076Spjd s = strsave((T_Margin & MARGIN_MAGIC) ? 446204076Spjd CGETS(7, 10, "has") : CGETS(7, 11, "does not have")); 447204076Spjd xprintf(CGETS(7, 12, "\tIt %s magic margins\n"), s); 448212038Spjd xfree(s); 449212038Spjd } 450218043Spjd for (t = tstr; t->name != NULL; t++) { 451218043Spjd s = strsave(t->str && *t->str ? t->str : CGETS(7, 13, "(empty)")); 452204076Spjd xprintf("\t%36s (%s) == %s\n", t->long_name, t->name, s); 453204076Spjd xfree(s); 454204076Spjd } 455211977Spjd xputchar('\n'); 456211984Spjd} 457257155Strociny 458218043Spjd 459219482Strocinystatic void 460211984SpjdReBufferDisplay() 461218043Spjd{ 462218043Spjd int i; 463218043Spjd Char **b; 464218043Spjd Char **bufp; 465218043Spjd 466204076Spjd b = Display; 467218045Spjd Display = NULL; 468218045Spjd if (b != NULL) { 469218043Spjd for (bufp = b; *bufp != NULL; bufp++) 470219482Strociny xfree((ptr_t) * bufp); 471218043Spjd xfree((ptr_t) b); 472220005Spjd } 473204076Spjd b = Vdisplay; 474213009Spjd Vdisplay = NULL; 475213009Spjd if (b != NULL) { 476210880Spjd for (bufp = b; *bufp != NULL; bufp++) 477207371Spjd xfree((ptr_t) * bufp); 478229945Spjd xfree((ptr_t) b); 479207371Spjd } 480229945Spjd TermH = Val(T_co); 481207371Spjd TermV = (INBUFSIZE * 4) / TermH + 1; 482207371Spjd b = (Char **) xmalloc((size_t) (sizeof(*b) * (TermV + 1))); 483204076Spjd for (i = 0; i < TermV; i++) 484213007Spjd b[i] = (Char *) xmalloc((size_t) (sizeof(*b[i]) * (TermH + 1))); 485213007Spjd b[TermV] = NULL; 486221899Spjd Display = b; 487218049Spjd b = (Char **) xmalloc((size_t) (sizeof(*b) * (TermV + 1))); 488218214Spjd for (i = 0; i < TermV; i++) 489218049Spjd b[i] = (Char *) xmalloc((size_t) (sizeof(*b[i]) * (TermH + 1))); 490213007Spjd b[TermV] = NULL; 491213007Spjd Vdisplay = b; 492213007Spjd} 493213007Spjd 494213007Spjdvoid 495213007SpjdSetTC(what, how) 496213007Spjd char *what, *how; 497213007Spjd{ 498213007Spjd struct termcapstr *ts; 499218138Spjd struct termcapval *tv; 500213007Spjd 501204076Spjd /* 502212038Spjd * Do the strings first 503204076Spjd */ 504204076Spjd setname("settc"); 505218138Spjd for (ts = tstr; ts->name != NULL; ts++) 506204076Spjd if (strcmp(ts->name, what) == 0) 507218138Spjd break; 508213007Spjd if (ts->name != NULL) { 509204076Spjd TCalloc(ts, how); 510204076Spjd /* 511204076Spjd * Reset variables 512230092Spjd */ 513230092Spjd if (GoodStr(T_me) && GoodStr(T_ue)) 514204076Spjd me_all = (strcmp(Str(T_me), Str(T_ue)) == 0); 515204076Spjd else 516204076Spjd me_all = 0; 517204076Spjd if (GoodStr(T_me) && GoodStr(T_se)) 518204076Spjd me_all |= (strcmp(Str(T_me), Str(T_se)) == 0); 519204076Spjd 520204076Spjd T_CanCEOL = GoodStr(T_ce); 521204076Spjd T_CanDel = GoodStr(T_dc) || GoodStr(T_DC); 522204076Spjd T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC); 523204076Spjd T_CanUP = GoodStr(T_up) || GoodStr(T_UP); 524204076Spjd return; 525204076Spjd } 526204076Spjd 527204076Spjd /* 528204076Spjd * Do the numeric ones second 529204076Spjd */ 530204076Spjd for (tv = tval; tv->name != NULL; tv++) 531204076Spjd if (strcmp(tv->name, what) == 0) 532204076Spjd break; 533204076Spjd 534204076Spjd if (tv->name != NULL) { 535204076Spjd if (tv == &tval[T_pt] || tv == &tval[T_km] || 536204076Spjd tv == &tval[T_am] || tv == &tval[T_xn]) { 537204076Spjd if (strcmp(how, "yes") == 0) 538204076Spjd tv->val = 1; 539204076Spjd else if (strcmp(how, "no") == 0) 540204076Spjd tv->val = 0; 541204076Spjd else { 542211882Spjd stderror(ERR_SETTCUS, tv->name); 543211882Spjd return; 544211882Spjd } 545204076Spjd T_Tabs = (Char) Val(T_pt); 546204076Spjd T_HasMeta = (Char) Val(T_km); 547204076Spjd T_Margin = (Char) Val(T_am) ? MARGIN_AUTO : 0; 548204076Spjd T_Margin |= (Char) Val(T_xn) ? MARGIN_MAGIC : 0; 549204076Spjd if (tv == &tval[T_am] || tv == &tval[T_xn]) 550204076Spjd ChangeSize(Val(T_li), Val(T_co)); 551204076Spjd return; 552204076Spjd } 553204076Spjd else { 554204076Spjd tv->val = atoi(how); 555226854Spjd T_Cols = (Char) Val(T_co); 556204076Spjd T_Lines = (Char) Val(T_li); 557204076Spjd if (tv == &tval[T_co] || tv == &tval[T_li]) 558226854Spjd ChangeSize(Val(T_li), Val(T_co)); 559204076Spjd return; 560204076Spjd } 561204076Spjd } 562204076Spjd stderror(ERR_NAME | ERR_TCCAP, what); 563204076Spjd return; 564226854Spjd} 565226854Spjd 566226854Spjd 567226854Spjd/* 568226854Spjd * Print the termcap string out with variable substitution 569226854Spjd */ 570226854Spjdvoid 571226854SpjdEchoTC(v) 572204076Spjd Char **v; 573222164Spjd{ 574211882Spjd char *cap, *scap, cv[BUFSIZE]; 575211882Spjd int arg_need, arg_cols, arg_rows; 576246922Spjd int verbose = 0, silent = 0; 577246922Spjd char *area; 578246922Spjd static const char *fmts = "%s\n", *fmtd = "%d\n"; 579204076Spjd struct termcapstr *t; 580204076Spjd char buf[TC_BUFSIZE]; 581226854Spjd 582226854Spjd area = buf; 583204076Spjd 584204076Spjd setname("echotc"); 585204076Spjd 586204076Spjd tglob(v); 587226854Spjd if (gflag) { 588226854Spjd v = globall(v); 589204076Spjd if (v == 0) 590204076Spjd stderror(ERR_NAME | ERR_NOMATCH); 591204076Spjd } 592204076Spjd else 593204076Spjd v = gargv = saveblk(v); 594204076Spjd trim(v); 595204076Spjd 596204076Spjd if (!*v || *v[0] == '\0') 597204076Spjd return; 598248294Spjd if (v[0][0] == '-') { 599204076Spjd switch (v[0][1]) { 600204076Spjd case 'v': 601204076Spjd verbose = 1; 602204076Spjd break; 603204076Spjd case 's': 604204076Spjd silent = 1; 605204076Spjd break; 606204076Spjd default: 607204076Spjd stderror(ERR_NAME | ERR_TCUSAGE); 608204076Spjd break; 609204076Spjd } 610204076Spjd v++; 611204076Spjd } 612204076Spjd if (!*v || *v[0] == '\0') 613204076Spjd return; 614204076Spjd (void) strcpy(cv, short2str(*v)); 615204076Spjd if (strcmp(cv, "tabs") == 0) { 616204076Spjd xprintf(fmts, T_Tabs ? CGETS(7, 14, "yes") : 617204076Spjd CGETS(7, 15, "no")); 618204076Spjd flush(); 619204076Spjd return; 620204076Spjd } 621204076Spjd else if (strcmp(cv, "meta") == 0) { 622204076Spjd xprintf(fmts, Val(T_km) ? CGETS(7, 14, "yes") : 623204076Spjd CGETS(7, 15, "no")); 624204076Spjd flush(); 625204076Spjd return; 626204076Spjd } 627204076Spjd else if (strcmp(cv, "xn") == 0) { 628204076Spjd xprintf(fmts, T_Margin & MARGIN_MAGIC ? CGETS(7, 14, "yes") : 629204076Spjd CGETS(7, 15, "no")); 630204076Spjd flush(); 631204076Spjd return; 632204076Spjd } 633204076Spjd else if (strcmp(cv, "am") == 0) { 634204076Spjd xprintf(fmts, T_Margin & MARGIN_AUTO ? CGETS(7, 14, "yes") : 635204076Spjd CGETS(7, 15, "no")); 636212899Spjd flush(); 637211984Spjd return; 638211984Spjd } 639211984Spjd else if (strcmp(cv, "baud") == 0) { 640211984Spjd int i; 641218138Spjd 642211984Spjd for (i = 0; baud_rate[i].b_name != NULL; i++) 643211984Spjd if (T_Speed == baud_rate[i].b_rate) { 644211984Spjd xprintf(fmts, baud_rate[i].b_name); 645212038Spjd flush(); 646211984Spjd return; 647211984Spjd } 648211984Spjd xprintf(fmtd, 0); 649204076Spjd flush(); 650204076Spjd return; 651204076Spjd } 652204076Spjd else if (strcmp(cv, "rows") == 0 || strcmp(cv, "lines") == 0) { 653204076Spjd xprintf(fmtd, Val(T_li)); 654204076Spjd flush(); 655204076Spjd return; 656246922Spjd } 657226854Spjd else if (strcmp(cv, "cols") == 0) { 658204076Spjd xprintf(fmtd, Val(T_co)); 659204076Spjd flush(); 660204076Spjd return; 661211877Spjd } 662204076Spjd 663229945Spjd /* 664211984Spjd * Try to use our local definition first 665204076Spjd */ 666204076Spjd scap = NULL; 667226854Spjd for (t = tstr; t->name != NULL; t++) 668226854Spjd if (strcmp(t->name, cv) == 0) { 669211877Spjd scap = t->str; 670211877Spjd break; 671211877Spjd } 672211877Spjd if (t->name == NULL) 673211877Spjd scap = tgetstr(cv, &area); 674211877Spjd if (!scap || scap[0] == '\0') { 675222228Spjd if (tgetflag(cv)) { 676222228Spjd xprintf(CGETS(7, 14, "yes\n")); 677222228Spjd return; 678222228Spjd } 679222228Spjd if (silent) 680222228Spjd return; 681222228Spjd else 682222228Spjd stderror(ERR_NAME | ERR_TCCAP, cv); 683222228Spjd } 684222228Spjd 685222228Spjd /* 686222228Spjd * Count home many values we need for this capability. 687222228Spjd */ 688226854Spjd for (cap = scap, arg_need = 0; *cap; cap++) 689226854Spjd if (*cap == '%') 690226854Spjd switch (*++cap) { 691226854Spjd case 'd': 692226854Spjd case '2': 693222228Spjd case '3': 694204076Spjd case '.': 695204076Spjd case '+': 696211882Spjd arg_need++; 697226854Spjd break; 698211882Spjd case '%': 699211882Spjd case '>': 700211882Spjd case 'i': 701226854Spjd case 'r': 702211882Spjd case 'n': 703211882Spjd case 'B': 704211882Spjd case 'D': 705226854Spjd break; 706229945Spjd default: 707211984Spjd /* 708212051Spjd * hpux has lot's of them... 709204076Spjd */ 710246922Spjd if (verbose) 711246922Spjd stderror(ERR_NAME | ERR_TCPARM, *cap); 712246922Spjd /* This is bad, but I won't complain */ 713246922Spjd break; 714246922Spjd } 715246922Spjd 716246922Spjd switch (arg_need) { 717246922Spjd case 0: 718246922Spjd v++; 719246922Spjd if (*v && *v[0]) { 720246922Spjd if (silent) 721246922Spjd return; 722246922Spjd else 723246922Spjd stderror(ERR_NAME | ERR_TCARGS, cv, arg_need); 724246922Spjd } 725246922Spjd (void) tputs(scap, 1, PUTRAW); 726246922Spjd break; 727246922Spjd case 1: 728246922Spjd v++; 729246922Spjd if (!*v || *v[0] == '\0') 730246922Spjd stderror(ERR_NAME | ERR_TCNARGS, cv, 1); 731204076Spjd arg_cols = 0; 732226854Spjd arg_rows = atoi(short2str(*v)); 733204076Spjd v++; 734204076Spjd if (*v && *v[0]) { 735211877Spjd if (silent) 736204076Spjd return; 737204076Spjd else 738204076Spjd stderror(ERR_NAME | ERR_TCARGS, cv, arg_need); 739204076Spjd } 740204076Spjd (void) tputs(tgoto(scap, arg_cols, arg_rows), 1, PUTRAW); 741204076Spjd break; 742204076Spjd default: 743204076Spjd /* This is wrong, but I will ignore it... */ 744204076Spjd if (verbose) 745204076Spjd stderror(ERR_NAME | ERR_TCARGS, cv, arg_need); 746204076Spjd /*FALLTHROUGH*/ 747204076Spjd case 2: 748204076Spjd v++; 749204076Spjd if (!*v || *v[0] == '\0') { 750204076Spjd if (silent) 751225832Spjd return; 752204076Spjd else 753204076Spjd stderror(ERR_NAME | ERR_TCNARGS, cv, 2); 754204076Spjd } 755204076Spjd arg_cols = atoi(short2str(*v)); 756204076Spjd v++; 757211877Spjd if (!*v || *v[0] == '\0') { 758204076Spjd if (silent) 759204076Spjd return; 760204076Spjd else 761204076Spjd stderror(ERR_NAME | ERR_TCNARGS, cv, 2); 762204076Spjd } 763204076Spjd arg_rows = atoi(short2str(*v)); 764204076Spjd v++; 765204076Spjd if (*v && *v[0]) { 766204076Spjd if (silent) 767204076Spjd return; 768204076Spjd else 769204076Spjd stderror(ERR_NAME | ERR_TCARGS, cv, arg_need); 770204076Spjd } 771204076Spjd (void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows, PUTRAW); 772204076Spjd break; 773204076Spjd } 774204076Spjd flush(); 775204076Spjd if (gargv) { 776204076Spjd blkfree(gargv); 777204076Spjd gargv = 0; 778204076Spjd } 779204076Spjd} 780204076Spjd 781247281Strocinyint GotTermCaps = 0; 782204076Spjd 783204076Spjdstatic struct { 784204076Spjd Char *name; 785204076Spjd int key; 786204076Spjd XmapVal fun; 787225831Spjd int type; 788204076Spjd} arrow[] = { 789204076Spjd#define A_K_DN 0 790225832Spjd { STRdown, T_kd, { 0 }, 0 }, 791204076Spjd#define A_K_UP 1 792204076Spjd { STRup, T_ku, { 0 }, 0 }, 793204076Spjd#define A_K_LT 2 794204076Spjd { STRleft, T_kl, { 0 }, 0 }, 795204076Spjd#define A_K_RT 3 796204076Spjd { STRright, T_kr, { 0 }, 0 }, 797229945Spjd#define A_K_HO 4 798204076Spjd { STRhome, T_kh, { 0 }, 0 }, 799204076Spjd#define A_K_EN 5 800204076Spjd { STRend, T_at7, { 0 }, 0} 801204076Spjd}; 802204076Spjd#define A_K_NKEYS 6 803204076Spjd 804204076Spjdvoid 805204076SpjdResetArrowKeys() 806204076Spjd{ 807204076Spjd arrow[A_K_DN].fun.cmd = F_DOWN_HIST; 808229945Spjd arrow[A_K_DN].type = XK_CMD; 809204076Spjd 810204076Spjd arrow[A_K_UP].fun.cmd = F_UP_HIST; 811204076Spjd arrow[A_K_UP].type = XK_CMD; 812204076Spjd 813204076Spjd arrow[A_K_LT].fun.cmd = F_CHARBACK; 814204076Spjd arrow[A_K_LT].type = XK_CMD; 815204076Spjd 816204076Spjd arrow[A_K_RT].fun.cmd = F_CHARFWD; 817204076Spjd arrow[A_K_RT].type = XK_CMD; 818204076Spjd 819229945Spjd arrow[A_K_HO].fun.cmd = F_TOBEG; 820204076Spjd arrow[A_K_HO].type = XK_CMD; 821204076Spjd 822204076Spjd arrow[A_K_EN].fun.cmd = F_TOEND; 823204076Spjd arrow[A_K_EN].type = XK_CMD; 824204076Spjd} 825225832Spjd 826225832Spjdvoid 827225832SpjdDefaultArrowKeys() 828225832Spjd{ 829225832Spjd static Char strA[] = {033, '[', 'A', '\0'}; 830225832Spjd static Char strB[] = {033, '[', 'B', '\0'}; 831204076Spjd static Char strC[] = {033, '[', 'C', '\0'}; 832229945Spjd static Char strD[] = {033, '[', 'D', '\0'}; 833225832Spjd static Char strH[] = {033, '[', 'H', '\0'}; 834225832Spjd static Char strF[] = {033, '[', 'F', '\0'}; 835204076Spjd static Char stOA[] = {033, 'O', 'A', '\0'}; 836225832Spjd static Char stOB[] = {033, 'O', 'B', '\0'}; 837204076Spjd static Char stOC[] = {033, 'O', 'C', '\0'}; 838225832Spjd static Char stOD[] = {033, 'O', 'D', '\0'}; 839204076Spjd static Char stOH[] = {033, 'O', 'H', '\0'}; 840226854Spjd static Char stOF[] = {033, 'O', 'F', '\0'}; 841226854Spjd 842226854Spjd CStr cs; 843204076Spjd#ifndef IS_ASCII 844225832Spjd if (strA[0] == 033) 845204076Spjd { 846204076Spjd strA[0] = CTL_ESC('\033'); 847204076Spjd strB[0] = CTL_ESC('\033'); 848204076Spjd strC[0] = CTL_ESC('\033'); 849204076Spjd strD[0] = CTL_ESC('\033'); 850211877Spjd strH[0] = CTL_ESC('\033'); 851204076Spjd strF[0] = CTL_ESC('\033'); 852204076Spjd stOA[0] = CTL_ESC('\033'); 853204076Spjd stOB[0] = CTL_ESC('\033'); 854204076Spjd stOC[0] = CTL_ESC('\033'); 855204076Spjd stOD[0] = CTL_ESC('\033'); 856204076Spjd stOH[0] = CTL_ESC('\033'); 857204076Spjd stOF[0] = CTL_ESC('\033'); 858204076Spjd } 859204076Spjd#endif 860204076Spjd 861204076Spjd cs.len = 3; 862204076Spjd 863204076Spjd cs.buf = strA; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 864204076Spjd cs.buf = strB; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 865204076Spjd cs.buf = strC; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 866204076Spjd cs.buf = strD; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 867204076Spjd cs.buf = strH; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 868204076Spjd cs.buf = strF; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 869204076Spjd cs.buf = stOA; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 870211877Spjd cs.buf = stOB; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 871204076Spjd cs.buf = stOC; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 872204076Spjd cs.buf = stOD; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 873204076Spjd cs.buf = stOH; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 874226854Spjd cs.buf = stOF; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 875246922Spjd 876246922Spjd if (VImode) { 877246922Spjd cs.len = 2; 878246922Spjd cs.buf = &strA[1]; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 879204076Spjd cs.buf = &strB[1]; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 880204076Spjd cs.buf = &strC[1]; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 881204076Spjd cs.buf = &strD[1]; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 882204076Spjd cs.buf = &strH[1]; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 883204076Spjd cs.buf = &strF[1]; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 884204076Spjd cs.buf = &stOA[1]; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 885204076Spjd cs.buf = &stOB[1]; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 886204076Spjd cs.buf = &stOC[1]; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 887204076Spjd cs.buf = &stOD[1]; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 888204076Spjd cs.buf = &stOH[1]; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 889204076Spjd cs.buf = &stOF[1]; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 890204076Spjd } 891204076Spjd} 892204076Spjd 893204076Spjd 894204076Spjdint 895204076SpjdSetArrowKeys(name, fun, type) 896204076Spjd CStr *name; 897225782Spjd XmapVal *fun; 898225782Spjd int type; 899204076Spjd{ 900247281Strociny int i; 901247281Strociny for (i = 0; i < A_K_NKEYS; i++) 902247281Strociny if (Strcmp(name->buf, arrow[i].name) == 0) { 903247281Strociny arrow[i].fun = *fun; 904247281Strociny arrow[i].type = type; 905247281Strociny return 0; 906247281Strociny } 907247281Strociny return -1; 908247281Strociny} 909247281Strociny 910247281Strocinyint 911247281StrocinyIsArrowKey(name) 912247281Strociny Char *name; 913247281Strociny{ 914247281Strociny int i; 915204076Spjd for (i = 0; i < A_K_NKEYS; i++) 916247281Strociny if (Strcmp(name, arrow[i].name) == 0) 917204076Spjd return 1; 918229945Spjd return 0; 919230092Spjd} 920204076Spjd 921204076Spjdint 922209185SpjdClearArrowKeys(name) 923204076Spjd CStr *name; 924226854Spjd{ 925211877Spjd int i; 926204076Spjd for (i = 0; i < A_K_NKEYS; i++) 927204076Spjd if (Strcmp(name->buf, arrow[i].name) == 0) { 928204076Spjd arrow[i].type = XK_NOD; 929204076Spjd return 0; 930 } 931 return -1; 932} 933 934void 935PrintArrowKeys(name) 936 CStr *name; 937{ 938 int i; 939 940 for (i = 0; i < A_K_NKEYS; i++) 941 if (name->len == 0 || Strcmp(name->buf, arrow[i].name) == 0) 942 if (arrow[i].type != XK_NOD) { 943 CStr cs; 944 cs.buf = arrow[i].name; 945 cs.len = Strlen(cs.buf); 946 (void) printOne(&cs, &arrow[i].fun, arrow[i].type); 947 } 948} 949 950 951void 952BindArrowKeys() 953{ 954 KEYCMD *map, *dmap; 955 int i, j; 956 char *p; 957 CStr cs; 958 959 if (!GotTermCaps) 960 return; 961 map = VImode ? CcAltMap : CcKeyMap; 962 dmap = VImode ? CcViCmdMap : CcEmacsMap; 963 964 DefaultArrowKeys(); 965 966 for (i = 0; i < A_K_NKEYS; i++) { 967 p = tstr[arrow[i].key].str; 968 if (p && *p) { 969 j = (unsigned char) *p; 970 cs.buf = str2short(p); 971 cs.len = Strlen(cs.buf); 972 /* 973 * Assign the arrow keys only if: 974 * 975 * 1. They are multi-character arrow keys and the user 976 * has not re-assigned the leading character, or 977 * has re-assigned the leading character to be F_XKEY 978 * 2. They are single arrow keys pointing to an unassigned key. 979 */ 980 if (arrow[i].type == XK_NOD) { 981 ClearXkey(map, &cs); 982 } 983 else { 984 if (p[1] && (dmap[j] == map[j] || map[j] == F_XKEY)) { 985 AddXkey(&cs, &arrow[i].fun, arrow[i].type); 986 map[j] = F_XKEY; 987 } 988 else if (map[j] == F_UNASSIGNED) { 989 ClearXkey(map, &cs); 990 if (arrow[i].type == XK_CMD) 991 map[j] = arrow[i].fun.cmd; 992 else 993 AddXkey(&cs, &arrow[i].fun, arrow[i].type); 994 } 995 } 996 } 997 } 998} 999 1000static Char cur_atr = 0; /* current attributes */ 1001 1002void 1003SetAttributes(atr) 1004 Char atr; 1005{ 1006 atr &= ATTRIBUTES; 1007 if (atr != cur_atr) { 1008 if (me_all && GoodStr(T_me)) { 1009 if (((cur_atr & BOLD) && !(atr & BOLD)) || 1010 ((cur_atr & UNDER) && !(atr & UNDER)) || 1011 ((cur_atr & STANDOUT) && !(atr & STANDOUT))) { 1012 (void) tputs(Str(T_me), 1, PUTPURE); 1013 cur_atr = 0; 1014 } 1015 } 1016 if ((atr & BOLD) != (cur_atr & BOLD)) { 1017 if (atr & BOLD) { 1018 if (GoodStr(T_md) && GoodStr(T_me)) { 1019 (void) tputs(Str(T_md), 1, PUTPURE); 1020 cur_atr |= BOLD; 1021 } 1022 } 1023 else { 1024 if (GoodStr(T_md) && GoodStr(T_me)) { 1025 (void) tputs(Str(T_me), 1, PUTPURE); 1026 if ((cur_atr & STANDOUT) && GoodStr(T_se)) { 1027 (void) tputs(Str(T_se), 1, PUTPURE); 1028 cur_atr &= ~STANDOUT; 1029 } 1030 if ((cur_atr & UNDER) && GoodStr(T_ue)) { 1031 (void) tputs(Str(T_ue), 1, PUTPURE); 1032 cur_atr &= ~UNDER; 1033 } 1034 cur_atr &= ~BOLD; 1035 } 1036 } 1037 } 1038 if ((atr & STANDOUT) != (cur_atr & STANDOUT)) { 1039 if (atr & STANDOUT) { 1040 if (GoodStr(T_so) && GoodStr(T_se)) { 1041 (void) tputs(Str(T_so), 1, PUTPURE); 1042 cur_atr |= STANDOUT; 1043 } 1044 } 1045 else { 1046 if (GoodStr(T_se)) { 1047 (void) tputs(Str(T_se), 1, PUTPURE); 1048 cur_atr &= ~STANDOUT; 1049 } 1050 } 1051 } 1052 if ((atr & UNDER) != (cur_atr & UNDER)) { 1053 if (atr & UNDER) { 1054 if (GoodStr(T_us) && GoodStr(T_ue)) { 1055 (void) tputs(Str(T_us), 1, PUTPURE); 1056 cur_atr |= UNDER; 1057 } 1058 } 1059 else { 1060 if (GoodStr(T_ue)) { 1061 (void) tputs(Str(T_ue), 1, PUTPURE); 1062 cur_atr &= ~UNDER; 1063 } 1064 } 1065 } 1066 } 1067} 1068 1069/* PWP 6-27-88 -- if the tty driver thinks that we can tab, we ask termcap */ 1070int 1071CanWeTab() 1072{ 1073 return (Val(T_pt)); 1074} 1075 1076void 1077MoveToLine(where) /* move to line <where> (first line == 0) */ 1078 int where; /* as efficiently as possible; */ 1079{ 1080 int del; 1081 1082 if (where == CursorV) 1083 return; 1084 1085 if (where > TermV) { 1086#ifdef DEBUG_SCREEN 1087 xprintf("MoveToLine: where is ridiculous: %d\r\n", where); 1088 flush(); 1089#endif /* DEBUG_SCREEN */ 1090 return; 1091 } 1092 1093 del = where - CursorV; 1094 1095 if (del > 0) { 1096 while (del > 0) { 1097 if ((T_Margin & MARGIN_AUTO) && Display[CursorV][0] != '\0') { 1098 size_t h; 1099 1100 for (h = TermH - 1; h > 0 && Display[CursorV][h] == CHAR_DBWIDTH; 1101 h--) 1102 ; 1103 /* move without newline */ 1104 MoveToChar(h); 1105 so_write(&Display[CursorV][CursorH], TermH - CursorH); /* updates CursorH/V*/ 1106 del--; 1107 } 1108 else { 1109 if ((del > 1) && GoodStr(T_DO)) { 1110 (void) tputs(tgoto(Str(T_DO), del, del), del, PUTPURE); 1111 del = 0; 1112 } 1113 else { 1114 for ( ; del > 0; del--) 1115 (void) putraw('\n'); 1116 CursorH = 0; /* because the \n will become \r\n */ 1117 } 1118 } 1119 } 1120 } 1121 else { /* del < 0 */ 1122 if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) 1123 (void) tputs(tgoto(Str(T_UP), -del, -del), -del, PUTPURE); 1124 else { 1125 int i; 1126 if (GoodStr(T_up)) 1127 for (i = 0; i < -del; i++) 1128 (void) tputs(Str(T_up), 1, PUTPURE); 1129 } 1130 } 1131 CursorV = where; /* now where is here */ 1132} 1133 1134void 1135MoveToChar(where) /* move to character position (where) */ 1136 int where; 1137{ /* as efficiently as possible */ 1138 int del; 1139 1140mc_again: 1141 if (where == CursorH) 1142 return; 1143 1144 if (where >= TermH) { 1145#ifdef DEBUG_SCREEN 1146 xprintf("MoveToChar: where is riduculous: %d\r\n", where); 1147 flush(); 1148#endif /* DEBUG_SCREEN */ 1149 return; 1150 } 1151 1152 if (!where) { /* if where is first column */ 1153 (void) putraw('\r'); /* do a CR */ 1154 CursorH = 0; 1155 return; 1156 } 1157 1158 del = where - CursorH; 1159 1160 if ((del < -4 || del > 4) && GoodStr(T_ch)) 1161 /* go there directly */ 1162 (void) tputs(tgoto(Str(T_ch), where, where), where, PUTPURE); 1163 else { 1164 int i; 1165 if (del > 0) { /* moving forward */ 1166 if ((del > 4) && GoodStr(T_RI)) 1167 (void) tputs(tgoto(Str(T_RI), del, del), del, PUTPURE); 1168 else { 1169 /* if I can do tabs, use them */ 1170 if (T_Tabs) { 1171 if ((CursorH & 0370) != (where & ~0x7) 1172 && Display[CursorV][where & ~0x7] != CHAR_DBWIDTH) { 1173 /* if not within tab stop */ 1174 for (i = (CursorH & 0370); i < (where & ~0x7); i += 8) 1175 (void) putraw('\t'); /* then tab over */ 1176 CursorH = where & ~0x7; 1177 /* Note: considering that we often want to go to 1178 TermH - 1 for the wrapping, it would be nice to 1179 optimize this case by tabbing to the last column 1180 - but this doesn't work for all terminals! */ 1181 } 1182 } 1183 /* it's usually cheaper to just write the chars, so we do. */ 1184 1185 /* NOTE THAT so_write() WILL CHANGE CursorH!!! */ 1186 so_write(&Display[CursorV][CursorH], where - CursorH); 1187 1188 } 1189 } 1190 else { /* del < 0 := moving backward */ 1191 if ((-del > 4) && GoodStr(T_LE)) 1192 (void) tputs(tgoto(Str(T_LE), -del, -del), -del, PUTPURE); 1193 else { /* can't go directly there */ 1194 /* if the "cost" is greater than the "cost" from col 0 */ 1195 if (T_Tabs ? (-del > ((where >> 3) + (where & 07))) 1196 : (-del > where)) { 1197 (void) putraw('\r'); /* do a CR */ 1198 CursorH = 0; 1199 goto mc_again; /* and try again */ 1200 } 1201 for (i = 0; i < -del; i++) 1202 (void) putraw('\b'); 1203 } 1204 } 1205 } 1206 CursorH = where; /* now where is here */ 1207} 1208 1209void 1210so_write(cp, n) 1211 Char *cp; 1212 int n; 1213{ 1214 if (n <= 0) 1215 return; /* catch bugs */ 1216 1217 if (n > TermH) { 1218#ifdef DEBUG_SCREEN 1219 xprintf("so_write: n is riduculous: %d\r\n", n); 1220 flush(); 1221#endif /* DEBUG_SCREEN */ 1222 return; 1223 } 1224 1225 do { 1226 if (*cp != CHAR_DBWIDTH) { 1227 if (*cp & LITERAL) { 1228 Char *d; 1229#ifdef DEBUG_LITERAL 1230 xprintf("so: litnum %d\r\n", (int)(*cp & ~LITERAL)); 1231#endif /* DEBUG_LITERAL */ 1232 for (d = litptr + (*cp & ~LITERAL) * LIT_FACTOR; *d; d++) 1233 (void) putwraw(*d); 1234 } 1235 else 1236 (void) putwraw(*cp); 1237 } 1238 cp++; 1239 CursorH++; 1240 } while (--n); 1241 1242 if (CursorH >= TermH) { /* wrap? */ 1243 if (T_Margin & MARGIN_AUTO) { /* yes */ 1244 CursorH = 0; 1245 CursorV++; 1246 if (T_Margin & MARGIN_MAGIC) { 1247 /* force the wrap to avoid the "magic" situation */ 1248 Char c; 1249 if ((c = Display[CursorV][CursorH]) != '\0') { 1250 so_write(&c, 1); 1251 while(Display[CursorV][CursorH] == CHAR_DBWIDTH) 1252 CursorH++; 1253 } 1254 else { 1255 (void) putraw(' '); 1256 CursorH = 1; 1257 } 1258 } 1259 } 1260 else /* no wrap, but cursor stays on screen */ 1261 CursorH = TermH - 1; 1262 } 1263} 1264 1265 1266void 1267DeleteChars(num) /* deletes <num> characters */ 1268 int num; 1269{ 1270 if (num <= 0) 1271 return; 1272 1273 if (!T_CanDel) { 1274#ifdef DEBUG_EDIT 1275 xprintf(CGETS(7, 16, "ERROR: cannot delete\r\n")); 1276#endif /* DEBUG_EDIT */ 1277 flush(); 1278 return; 1279 } 1280 1281 if (num > TermH) { 1282#ifdef DEBUG_SCREEN 1283 xprintf(CGETS(7, 17, "DeleteChars: num is riduculous: %d\r\n"), num); 1284 flush(); 1285#endif /* DEBUG_SCREEN */ 1286 return; 1287 } 1288 1289 if (GoodStr(T_DC)) /* if I have multiple delete */ 1290 if ((num > 1) || !GoodStr(T_dc)) { /* if dc would be more expen. */ 1291 (void) tputs(tgoto(Str(T_DC), num, num), num, PUTPURE); 1292 return; 1293 } 1294 1295 if (GoodStr(T_dm)) /* if I have delete mode */ 1296 (void) tputs(Str(T_dm), 1, PUTPURE); 1297 1298 if (GoodStr(T_dc)) /* else do one at a time */ 1299 while (num--) 1300 (void) tputs(Str(T_dc), 1, PUTPURE); 1301 1302 if (GoodStr(T_ed)) /* if I have delete mode */ 1303 (void) tputs(Str(T_ed), 1, PUTPURE); 1304} 1305 1306void 1307Insert_write(cp, num) /* Puts terminal in insert character mode, */ 1308 Char *cp; 1309 int num; /* or inserts num characters in the line */ 1310{ 1311 if (num <= 0) 1312 return; 1313 if (!T_CanIns) { 1314#ifdef DEBUG_EDIT 1315 xprintf(CGETS(7, 18, "ERROR: cannot insert\r\n")); 1316#endif /* DEBUG_EDIT */ 1317 flush(); 1318 return; 1319 } 1320 1321 if (num > TermH) { 1322#ifdef DEBUG_SCREEN 1323 xprintf(CGETS(7, 19, "StartInsert: num is riduculous: %d\r\n"), num); 1324 flush(); 1325#endif /* DEBUG_SCREEN */ 1326 return; 1327 } 1328 1329 if (GoodStr(T_IC)) /* if I have multiple insert */ 1330 if ((num > 1) || !GoodStr(T_ic)) { /* if ic would be more expen. */ 1331 (void) tputs(tgoto(Str(T_IC), num, num), num, PUTPURE); 1332 so_write(cp, num); /* this updates CursorH/V */ 1333 return; 1334 } 1335 1336 if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */ 1337 (void) tputs(Str(T_im), 1, PUTPURE); 1338 1339 so_write(cp, num); /* this updates CursorH/V */ 1340 1341 if (GoodStr(T_ip)) /* have to make num chars insert */ 1342 (void) tputs(Str(T_ip), 1, PUTPURE); 1343 1344 (void) tputs(Str(T_ei), 1, PUTPURE); 1345 return; 1346 } 1347 1348 do { 1349 if (GoodStr(T_ic)) /* have to make num chars insert */ 1350 (void) tputs(Str(T_ic), 1, PUTPURE); /* insert a char */ 1351 1352 so_write(cp++, 1); /* this updates CursorH/V */ 1353 1354 if (GoodStr(T_ip)) /* have to make num chars insert */ 1355 (void) tputs(Str(T_ip), 1, PUTPURE);/* pad the inserted char */ 1356 1357 } while (--num); 1358 1359} 1360 1361void 1362ClearEOL(num) /* clear to end of line. There are num */ 1363 int num; /* characters to clear */ 1364{ 1365 int i; 1366 1367 if (num <= 0) 1368 return; 1369 1370 if (T_CanCEOL && GoodStr(T_ce)) 1371 (void) tputs(Str(T_ce), 1, PUTPURE); 1372 else { 1373 for (i = 0; i < num; i++) 1374 (void) putraw(' '); 1375 CursorH += num; /* have written num spaces */ 1376 } 1377} 1378 1379void 1380ClearScreen() 1381{ /* clear the whole screen and home */ 1382 if (GoodStr(T_cl)) 1383 /* send the clear screen code */ 1384 (void) tputs(Str(T_cl), Val(T_li), PUTPURE); 1385 else if (GoodStr(T_ho) && GoodStr(T_cd)) { 1386 (void) tputs(Str(T_ho), Val(T_li), PUTPURE); /* home */ 1387 /* clear to bottom of screen */ 1388 (void) tputs(Str(T_cd), Val(T_li), PUTPURE); 1389 } 1390 else { 1391 (void) putraw('\r'); 1392 (void) putraw('\n'); 1393 } 1394} 1395 1396void 1397SoundBeep() 1398{ /* produce a sound */ 1399 beep_cmd (); 1400 if (adrof(STRnobeep)) 1401 return; 1402 1403 if (GoodStr(T_vb) && adrof(STRvisiblebell)) 1404 (void) tputs(Str(T_vb), 1, PUTPURE); /* visible bell */ 1405 else if (GoodStr(T_bl)) 1406 /* what termcap says we should use */ 1407 (void) tputs(Str(T_bl), 1, PUTPURE); 1408 else 1409 (void) putraw(CTL_ESC('\007')); /* an ASCII bell; ^G */ 1410} 1411 1412void 1413ClearToBottom() 1414{ /* clear to the bottom of the screen */ 1415 if (GoodStr(T_cd)) 1416 (void) tputs(Str(T_cd), Val(T_li), PUTPURE); 1417 else if (GoodStr(T_ce)) 1418 (void) tputs(Str(T_ce), Val(T_li), PUTPURE); 1419} 1420 1421void 1422GetTermCaps() 1423{ /* read in the needed terminal capabilites */ 1424 int i; 1425 const char *ptr; 1426 char buf[TC_BUFSIZE]; 1427 static char bp[TC_BUFSIZE]; 1428 char *area; 1429 struct termcapstr *t; 1430 1431 1432#ifdef SIG_WINDOW 1433# ifdef BSDSIGS 1434 sigmask_t omask; 1435# endif /* BSDSIGS */ 1436 int lins, cols; 1437 1438 /* don't want to confuse things here */ 1439# ifdef BSDSIGS 1440 omask = sigblock(sigmask(SIG_WINDOW)) & ~sigmask(SIG_WINDOW); 1441# else /* BSDSIGS */ 1442 (void) sighold(SIG_WINDOW); 1443# endif /* BSDSIGS */ 1444#endif /* SIG_WINDOW */ 1445 area = buf; 1446 1447 GotTermCaps = 1; 1448 1449 setname("gettermcaps"); 1450 ptr = getenv("TERM"); 1451 1452#ifdef apollo 1453 /* 1454 * If we are on a pad, we pretend that we are dumb. Otherwise the termcap 1455 * library will put us in a weird screen mode, thinking that we are going 1456 * to use curses 1457 */ 1458 if (isapad()) 1459 ptr = "dumb"; 1460#endif /* apollo */ 1461 1462 if (!ptr || !ptr[0] || !strcmp(ptr, "wm") || !strcmp(ptr,"dmx")) 1463 ptr = "dumb"; 1464 1465 setzero(bp, TC_BUFSIZE); 1466 1467 i = tgetent(bp, ptr); 1468 if (i <= 0) { 1469 if (i == -1) { 1470#if (SYSVREL == 0) || defined(IRIS3D) 1471 xprintf(CGETS(7, 20, "%s: Cannot open /etc/termcap.\n"), progname); 1472 } 1473 else if (i == 0) { 1474#endif /* SYSVREL */ 1475 xprintf(CGETS(7, 21, 1476 "%s: No entry for terminal type \"%s\"\n"), progname, 1477 getenv("TERM")); 1478 } 1479 xprintf(CGETS(7, 22, "%s: using dumb terminal settings.\n"), progname); 1480 Val(T_co) = 80; /* do a dumb terminal */ 1481 Val(T_pt) = Val(T_km) = Val(T_li) = 0; 1482 for (t = tstr; t->name != NULL; t++) 1483 TCalloc(t, NULL); 1484 } 1485 else { 1486 /* Can we tab */ 1487 Val(T_pt) = tgetflag("pt") && !tgetflag("xt"); 1488 /* do we have a meta? */ 1489 Val(T_km) = (tgetflag("km") || tgetflag("MT")); 1490 Val(T_am) = tgetflag("am"); 1491 Val(T_xn) = tgetflag("xn"); 1492 Val(T_co) = tgetnum("co"); 1493 Val(T_li) = tgetnum("li"); 1494 for (t = tstr; t->name != NULL; t++) 1495 TCalloc(t, tgetstr(t->name, &area)); 1496 } 1497 if (Val(T_co) < 2) 1498 Val(T_co) = 80; /* just in case */ 1499 if (Val(T_li) < 1) 1500 Val(T_li) = 24; 1501 1502 T_Cols = (Char) Val(T_co); 1503 T_Lines = (Char) Val(T_li); 1504 if (T_Tabs) 1505 T_Tabs = (Char) Val(T_pt); 1506 T_HasMeta = (Char) Val(T_km); 1507 T_Margin = (Char) Val(T_am) ? MARGIN_AUTO : 0; 1508 T_Margin |= (Char) Val(T_xn) ? MARGIN_MAGIC : 0; 1509 T_CanCEOL = GoodStr(T_ce); 1510 T_CanDel = GoodStr(T_dc) || GoodStr(T_DC); 1511 T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC); 1512 T_CanUP = GoodStr(T_up) || GoodStr(T_UP); 1513 if (GoodStr(T_me) && GoodStr(T_ue)) 1514 me_all = (strcmp(Str(T_me), Str(T_ue)) == 0); 1515 else 1516 me_all = 0; 1517 if (GoodStr(T_me) && GoodStr(T_se)) 1518 me_all |= (strcmp(Str(T_me), Str(T_se)) == 0); 1519 1520 1521#ifdef DEBUG_SCREEN 1522 if (!T_CanUP) { 1523 xprintf(CGETS(7, 23, "%s: WARNING: Your terminal cannot move up.\n", 1524 progname)); 1525 xprintf(CGETS(7, 24, "Editing may be odd for long lines.\n")); 1526 } 1527 if (!T_CanCEOL) 1528 xprintf(CGETS(7, 25, "no clear EOL capability.\n")); 1529 if (!T_CanDel) 1530 xprintf(CGETS(7, 26, "no delete char capability.\n")); 1531 if (!T_CanIns) 1532 xprintf(CGETS(7, 27, "no insert char capability.\n")); 1533#endif /* DEBUG_SCREEN */ 1534 1535 1536 1537#ifdef SIG_WINDOW 1538 (void) GetSize(&lins, &cols); /* get the correct window size */ 1539 ChangeSize(lins, cols); 1540 1541# ifdef BSDSIGS 1542 (void) sigsetmask(omask); /* can change it again */ 1543# else /* BSDSIGS */ 1544 (void) sigrelse(SIG_WINDOW); 1545# endif /* BSDSIGS */ 1546#else /* SIG_WINDOW */ 1547 ChangeSize(Val(T_li), Val(T_co)); 1548#endif /* SIG_WINDOW */ 1549 1550 BindArrowKeys(); 1551} 1552 1553#ifdef SIG_WINDOW 1554/* GetSize(): 1555 * Return the new window size in lines and cols, and 1556 * true if the size was changed. This can fail if SHIN 1557 * is not a tty, but it will work in most cases. 1558 */ 1559int 1560GetSize(lins, cols) 1561 int *lins, *cols; 1562{ 1563 *cols = Val(T_co); 1564 *lins = Val(T_li); 1565 1566#ifdef TIOCGWINSZ 1567# define KNOWsize 1568# ifndef lint 1569 { 1570 struct winsize ws; /* from 4.3 */ 1571 1572 if (ioctl(SHIN, TIOCGWINSZ, (ioctl_t) &ws) != -1) { 1573 if (ws.ws_col) 1574 *cols = ws.ws_col; 1575 if (ws.ws_row) 1576 *lins = ws.ws_row; 1577 } 1578 } 1579# endif /* !lint */ 1580#else /* TIOCGWINSZ */ 1581# ifdef TIOCGSIZE 1582# define KNOWsize 1583 { 1584 struct ttysize ts; /* from Sun */ 1585 1586 if (ioctl(SHIN, TIOCGSIZE, (ioctl_t) &ts) != -1) { 1587 if (ts.ts_cols) 1588 *cols = ts.ts_cols; 1589 if (ts.ts_lines) 1590 *lins = ts.ts_lines; 1591 } 1592 } 1593# endif /* TIOCGSIZE */ 1594#endif /* TIOCGWINSZ */ 1595 1596 return (Val(T_co) != *cols || Val(T_li) != *lins); 1597} 1598 1599#endif /* SIGWINDOW */ 1600 1601void 1602ChangeSize(lins, cols) 1603 int lins, cols; 1604{ 1605 /* 1606 * Just in case 1607 */ 1608 Val(T_co) = (cols < 2) ? 80 : cols; 1609 Val(T_li) = (lins < 1) ? 24 : lins; 1610 1611#ifdef KNOWsize 1612 /* 1613 * We want to affect the environment only when we have a valid 1614 * setup, not when we get bad settings. Consider the following scenario: 1615 * We just logged in, and we have not initialized the editor yet. 1616 * We reset termcap with tset, and not $TERMCAP has the right 1617 * terminal size. But since the editor is not initialized yet, and 1618 * the kernel's notion of the terminal size might be wrong we arrive 1619 * here with lines = columns = 0. If we reset the environment we lose 1620 * our only chance to get the window size right. 1621 */ 1622 if (Val(T_co) == cols && Val(T_li) == lins) { 1623 Char buf[10]; 1624 char *tptr; 1625 1626 if (getenv("COLUMNS")) { 1627 (void) Itoa(Val(T_co), buf, 0, 0); 1628 tsetenv(STRCOLUMNS, buf); 1629 } 1630 1631 if (getenv("LINES")) { 1632 (void) Itoa(Val(T_li), buf, 0, 0); 1633 tsetenv(STRLINES, buf); 1634 } 1635 1636 if ((tptr = getenv("TERMCAP")) != NULL) { 1637 /* Leave 64 characters slop in case we enlarge the termcap string */ 1638 Char termcap[1024+64], backup[1024+64], *ptr; 1639 1640 ptr = str2short(tptr); 1641 (void) Strncpy(termcap, ptr, 1024); 1642 termcap[1023] = '\0'; 1643 1644 /* update termcap string; first do columns */ 1645 buf[0] = 'c'; 1646 buf[1] = 'o'; 1647 buf[2] = '#'; 1648 buf[3] = '\0'; 1649 if ((ptr = Strstr(termcap, buf)) == NULL) { 1650 (void) Strcpy(backup, termcap); 1651 } 1652 else { 1653 size_t len = (ptr - termcap) + Strlen(buf); 1654 (void) Strncpy(backup, termcap, len); 1655 backup[len] = '\0'; 1656 (void) Itoa(Val(T_co), buf, 0, 0); 1657 (void) Strcat(backup + len, buf); 1658 ptr = Strchr(ptr, ':'); 1659 (void) Strcat(backup, ptr); 1660 } 1661 1662 /* now do lines */ 1663 buf[0] = 'l'; 1664 buf[1] = 'i'; 1665 buf[2] = '#'; 1666 buf[3] = '\0'; 1667 if ((ptr = Strstr(backup, buf)) == NULL) { 1668 (void) Strcpy(termcap, backup); 1669 } 1670 else { 1671 size_t len = (ptr - backup) + Strlen(buf); 1672 (void) Strncpy(termcap, backup, len); 1673 termcap[len] = '\0'; 1674 (void) Itoa(Val(T_li), buf, 0, 0); 1675 (void) Strcat(termcap, buf); 1676 ptr = Strchr(ptr, ':'); 1677 (void) Strcat(termcap, ptr); 1678 } 1679 /* 1680 * Chop the termcap string at 1024 characters to avoid core-dumps 1681 * in the termcap routines 1682 */ 1683 termcap[1023] = '\0'; 1684 tsetenv(STRTERMCAP, termcap); 1685 } 1686 } 1687#endif /* KNOWsize */ 1688 1689 ReBufferDisplay(); /* re-make display buffers */ 1690 ClearDisp(); 1691} 1692