1*54235Sbostic /*- 2*54235Sbostic * Copyright (c) 1992 The Regents of the University of California. 3*54235Sbostic * All rights reserved. 4*54235Sbostic * 5*54235Sbostic * This code is derived from software contributed to Berkeley by 6*54235Sbostic * Christos Zoulas of Cornell University. 7*54235Sbostic * 8*54235Sbostic * %sccs.include.redist.c% 9*54235Sbostic */ 10*54235Sbostic 11*54235Sbostic #ifndef lint 12*54235Sbostic static char sccsid[] = "@(#)term.c 5.1 (Berkeley) 06/22/92"; 13*54235Sbostic #endif /* not lint */ 14*54235Sbostic 15*54235Sbostic /* 16*54235Sbostic * el.term.c: Editor/termcap-curses interface 17*54235Sbostic * We have to declare a static variable here, since the 18*54235Sbostic * termcap putchar routine does not take an argument! 19*54235Sbostic * To do: Add the settc echotc and gettc functions 20*54235Sbostic */ 21*54235Sbostic #include "sys.h" 22*54235Sbostic #include <stdio.h> 23*54235Sbostic #include <signal.h> 24*54235Sbostic #include <string.h> 25*54235Sbostic #include <stdlib.h> 26*54235Sbostic #include <unistd.h> 27*54235Sbostic #include "termcap.h" /* XXX: should be <termcap.h> */ 28*54235Sbostic #include <sys/types.h> 29*54235Sbostic 30*54235Sbostic #include "el.h" 31*54235Sbostic 32*54235Sbostic /* 33*54235Sbostic * IMPORTANT NOTE: these routines are allowed to look at the current screen 34*54235Sbostic * and the current possition assuming that it is correct. If this is not 35*54235Sbostic * true, then the update will be WRONG! This is (should be) a valid 36*54235Sbostic * assumption... 37*54235Sbostic */ 38*54235Sbostic 39*54235Sbostic #define TC_BUFSIZE 2048 40*54235Sbostic 41*54235Sbostic #define GoodStr(a) (el->el_term.t_str[a] != NULL && \ 42*54235Sbostic el->el_term.t_str[a][0] != '\0') 43*54235Sbostic #define Str(a) el->el_term.t_str[a] 44*54235Sbostic #define Val(a) el->el_term.t_val[a] 45*54235Sbostic 46*54235Sbostic private struct { 47*54235Sbostic char *b_name; 48*54235Sbostic int b_rate; 49*54235Sbostic } baud_rate[] = { 50*54235Sbostic #ifdef B0 51*54235Sbostic { "0", B0 }, 52*54235Sbostic #endif 53*54235Sbostic #ifdef B50 54*54235Sbostic { "50", B50 }, 55*54235Sbostic #endif 56*54235Sbostic #ifdef B75 57*54235Sbostic { "75", B75 }, 58*54235Sbostic #endif 59*54235Sbostic #ifdef B110 60*54235Sbostic { "110", B110 }, 61*54235Sbostic #endif 62*54235Sbostic #ifdef B134 63*54235Sbostic { "134", B134 }, 64*54235Sbostic #endif 65*54235Sbostic #ifdef B150 66*54235Sbostic { "150", B150 }, 67*54235Sbostic #endif 68*54235Sbostic #ifdef B200 69*54235Sbostic { "200", B200 }, 70*54235Sbostic #endif 71*54235Sbostic #ifdef B300 72*54235Sbostic { "300", B300 }, 73*54235Sbostic #endif 74*54235Sbostic #ifdef B600 75*54235Sbostic { "600", B600 }, 76*54235Sbostic #endif 77*54235Sbostic #ifdef B900 78*54235Sbostic { "900", B900 }, 79*54235Sbostic #endif 80*54235Sbostic #ifdef B1200 81*54235Sbostic { "1200", B1200 }, 82*54235Sbostic #endif 83*54235Sbostic #ifdef B1800 84*54235Sbostic { "1800", B1800 }, 85*54235Sbostic #endif 86*54235Sbostic #ifdef B2400 87*54235Sbostic { "2400", B2400 }, 88*54235Sbostic #endif 89*54235Sbostic #ifdef B3600 90*54235Sbostic { "3600", B3600 }, 91*54235Sbostic #endif 92*54235Sbostic #ifdef B4800 93*54235Sbostic { "4800", B4800 }, 94*54235Sbostic #endif 95*54235Sbostic #ifdef B7200 96*54235Sbostic { "7200", B7200 }, 97*54235Sbostic #endif 98*54235Sbostic #ifdef B9600 99*54235Sbostic { "9600", B9600 }, 100*54235Sbostic #endif 101*54235Sbostic #ifdef EXTA 102*54235Sbostic { "19200", EXTA }, 103*54235Sbostic #endif 104*54235Sbostic #ifdef B19200 105*54235Sbostic { "19200", B19200 }, 106*54235Sbostic #endif 107*54235Sbostic #ifdef EXTB 108*54235Sbostic { "38400", EXTB }, 109*54235Sbostic #endif 110*54235Sbostic #ifdef B38400 111*54235Sbostic { "38400", B38400 }, 112*54235Sbostic #endif 113*54235Sbostic { NULL, 0 } 114*54235Sbostic }; 115*54235Sbostic 116*54235Sbostic private struct termcapstr { 117*54235Sbostic char *name; 118*54235Sbostic char *long_name; 119*54235Sbostic } tstr[] = { 120*54235Sbostic 121*54235Sbostic #define T_al 0 122*54235Sbostic { "al", "add new blank line" }, 123*54235Sbostic #define T_bl 1 124*54235Sbostic { "bl", "audible bell" }, 125*54235Sbostic #define T_cd 2 126*54235Sbostic { "cd", "clear to bottom" }, 127*54235Sbostic #define T_ce 3 128*54235Sbostic { "ce", "clear to end of line" }, 129*54235Sbostic #define T_ch 4 130*54235Sbostic { "ch", "cursor to horiz pos" }, 131*54235Sbostic #define T_cl 5 132*54235Sbostic { "cl", "clear screen" }, 133*54235Sbostic #define T_dc 6 134*54235Sbostic { "dc", "delete a character" }, 135*54235Sbostic #define T_dl 7 136*54235Sbostic { "dl", "delete a line" }, 137*54235Sbostic #define T_dm 8 138*54235Sbostic { "dm", "start delete mode" }, 139*54235Sbostic #define T_ed 9 140*54235Sbostic { "ed", "end delete mode" }, 141*54235Sbostic #define T_ei 10 142*54235Sbostic { "ei", "end insert mode" }, 143*54235Sbostic #define T_fs 11 144*54235Sbostic { "fs", "cursor from status line" }, 145*54235Sbostic #define T_ho 12 146*54235Sbostic { "ho", "home cursor" }, 147*54235Sbostic #define T_ic 13 148*54235Sbostic { "ic", "insert character" }, 149*54235Sbostic #define T_im 14 150*54235Sbostic { "im", "start insert mode" }, 151*54235Sbostic #define T_ip 15 152*54235Sbostic { "ip", "insert padding" }, 153*54235Sbostic #define T_kd 16 154*54235Sbostic { "kd", "sends cursor down" }, 155*54235Sbostic #define T_kl 17 156*54235Sbostic { "kl", "sends cursor left" }, 157*54235Sbostic #define T_kr 18 158*54235Sbostic { "kr", "sends cursor right" }, 159*54235Sbostic #define T_ku 19 160*54235Sbostic { "ku", "sends cursor up" }, 161*54235Sbostic #define T_md 20 162*54235Sbostic { "md", "begin bold" }, 163*54235Sbostic #define T_me 21 164*54235Sbostic { "me", "end attributes" }, 165*54235Sbostic #define T_nd 22 166*54235Sbostic { "nd", "non destructive space" }, 167*54235Sbostic #define T_se 23 168*54235Sbostic { "se", "end standout" }, 169*54235Sbostic #define T_so 24 170*54235Sbostic { "so", "begin standout" }, 171*54235Sbostic #define T_ts 25 172*54235Sbostic { "ts", "cursor to status line" }, 173*54235Sbostic #define T_up 26 174*54235Sbostic { "up", "cursor up one" }, 175*54235Sbostic #define T_us 27 176*54235Sbostic { "us", "begin underline" }, 177*54235Sbostic #define T_ue 28 178*54235Sbostic { "ue", "end underline" }, 179*54235Sbostic #define T_vb 29 180*54235Sbostic { "vb", "visible bell" }, 181*54235Sbostic #define T_DC 30 182*54235Sbostic { "DC", "delete multiple chars" }, 183*54235Sbostic #define T_DO 31 184*54235Sbostic { "DO", "cursor down multiple" }, 185*54235Sbostic #define T_IC 32 186*54235Sbostic { "IC", "insert multiple chars" }, 187*54235Sbostic #define T_LE 33 188*54235Sbostic { "LE", "cursor left multiple" }, 189*54235Sbostic #define T_RI 34 190*54235Sbostic { "RI", "cursor right multiple" }, 191*54235Sbostic #define T_UP 35 192*54235Sbostic { "UP", "cursor up multiple" }, 193*54235Sbostic #define T_str 36 194*54235Sbostic { NULL, NULL } 195*54235Sbostic }; 196*54235Sbostic 197*54235Sbostic private struct termcapval { 198*54235Sbostic char *name; 199*54235Sbostic char *long_name; 200*54235Sbostic } tval[] = { 201*54235Sbostic #define T_pt 0 202*54235Sbostic { "pt", "has physical tabs" }, 203*54235Sbostic #define T_li 1 204*54235Sbostic { "li", "Number of lines" }, 205*54235Sbostic #define T_co 2 206*54235Sbostic { "co", "Number of columns" }, 207*54235Sbostic #define T_km 3 208*54235Sbostic { "km", "Has meta key" }, 209*54235Sbostic #define T_xt 4 210*54235Sbostic { "xt", "Tab chars destructive" }, 211*54235Sbostic #define T_MT 5 212*54235Sbostic { "MT", "Has meta key" }, /* XXX? */ 213*54235Sbostic #define T_val 6 214*54235Sbostic { NULL, NULL, } 215*54235Sbostic }; 216*54235Sbostic 217*54235Sbostic /* do two or more of the attributes use me */ 218*54235Sbostic 219*54235Sbostic private void term_rebuffer_display __P((EditLine *)); 220*54235Sbostic private void term_free_display __P((EditLine *)); 221*54235Sbostic private void term_alloc_display __P((EditLine *)); 222*54235Sbostic private void term_alloc __P((EditLine *, 223*54235Sbostic struct termcapstr *, char *)); 224*54235Sbostic private void term_get_termcap __P((EditLine *, char *)); 225*54235Sbostic 226*54235Sbostic 227*54235Sbostic private FILE *term_outfile = NULL; /* XXX: How do we fix that? */ 228*54235Sbostic 229*54235Sbostic 230*54235Sbostic /* term_setflags(): 231*54235Sbostic * Set the terminal capability flags 232*54235Sbostic */ 233*54235Sbostic private void 234*54235Sbostic term_setflags(el) 235*54235Sbostic EditLine *el; 236*54235Sbostic { 237*54235Sbostic EL_FLAGS = 0; 238*54235Sbostic if (el->el_tty.t_tabs) 239*54235Sbostic EL_FLAGS |= (Val(T_pt) && !Val(T_xt)) ? TERM_CAN_TAB : 0; 240*54235Sbostic 241*54235Sbostic EL_FLAGS |= (Val(T_km) || Val(T_MT)) ? TERM_HAS_META : 0; 242*54235Sbostic EL_FLAGS |= GoodStr(T_ce) ? TERM_CAN_CEOL : 0; 243*54235Sbostic EL_FLAGS |= (GoodStr(T_dc) || GoodStr(T_DC)) ? TERM_CAN_DELETE : 0; 244*54235Sbostic EL_FLAGS |= (GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC)) ? 245*54235Sbostic TERM_CAN_INSERT : 0; 246*54235Sbostic EL_FLAGS |= (GoodStr(T_up) || GoodStr(T_UP)) ? TERM_CAN_UP : 0; 247*54235Sbostic 248*54235Sbostic if (GoodStr(T_me) && GoodStr(T_ue)) 249*54235Sbostic EL_FLAGS |= (strcmp(Str(T_me), Str(T_ue)) == 0) ? TERM_CAN_ME : 0; 250*54235Sbostic else 251*54235Sbostic EL_FLAGS &= ~TERM_CAN_ME; 252*54235Sbostic if (GoodStr(T_me) && GoodStr(T_se)) 253*54235Sbostic EL_FLAGS |= (strcmp(Str(T_me), Str(T_se)) == 0) ? TERM_CAN_ME : 0; 254*54235Sbostic 255*54235Sbostic 256*54235Sbostic #ifdef DEBUG_SCREEN 257*54235Sbostic if (!EL_CAN_UP) { 258*54235Sbostic (void) fprintf(el->el_errfile, "WARNING: Your terminal cannot move up.\n"); 259*54235Sbostic (void) fprintf(el->el_errfile, "Editing may be odd for long lines.\n"); 260*54235Sbostic } 261*54235Sbostic if (!EL_CAN_CEOL) 262*54235Sbostic (void) fprintf(el->el_errfile, "no clear EOL capability.\n"); 263*54235Sbostic if (!EL_CAN_DELETE) 264*54235Sbostic (void) fprintf(el->el_errfile, "no delete char capability.\n"); 265*54235Sbostic if (!EL_CAN_INSERT) 266*54235Sbostic (void) fprintf(el->el_errfile, "no insert char capability.\n"); 267*54235Sbostic #endif /* DEBUG_SCREEN */ 268*54235Sbostic } 269*54235Sbostic 270*54235Sbostic 271*54235Sbostic /* term_init(): 272*54235Sbostic * Initialize the terminal stuff 273*54235Sbostic */ 274*54235Sbostic protected int 275*54235Sbostic term_init(el) 276*54235Sbostic EditLine *el; 277*54235Sbostic { 278*54235Sbostic el->el_term.t_buf = (char *) el_malloc(TC_BUFSIZE); 279*54235Sbostic el->el_term.t_cap = (char *) el_malloc(TC_BUFSIZE); 280*54235Sbostic el->el_term.t_loc = 0; 281*54235Sbostic el->el_term.t_str = (char **) el_malloc(T_str * sizeof(char*)); 282*54235Sbostic (void) memset(el->el_term.t_str, 0, T_str * sizeof(char*)); 283*54235Sbostic el->el_term.t_val = (int *) el_malloc(T_val * sizeof(int)); 284*54235Sbostic (void) memset(el->el_term.t_val, 0, T_val * sizeof(char*)); 285*54235Sbostic term_outfile = el->el_outfile; 286*54235Sbostic term_get_termcap(el, NULL); 287*54235Sbostic return 0; 288*54235Sbostic } 289*54235Sbostic 290*54235Sbostic /* term_end(): 291*54235Sbostic * Clean up the terminal stuff 292*54235Sbostic */ 293*54235Sbostic protected void 294*54235Sbostic term_end(el) 295*54235Sbostic EditLine *el; 296*54235Sbostic { 297*54235Sbostic el_free((ptr_t) el->el_term.t_buf); 298*54235Sbostic el->el_term.t_buf = NULL; 299*54235Sbostic el_free((ptr_t) el->el_term.t_cap); 300*54235Sbostic el->el_term.t_cap = NULL; 301*54235Sbostic el->el_term.t_loc = 0; 302*54235Sbostic el_free((ptr_t) el->el_term.t_str); 303*54235Sbostic el->el_term.t_str = NULL; 304*54235Sbostic el_free((ptr_t) el->el_term.t_val); 305*54235Sbostic el->el_term.t_val = NULL; 306*54235Sbostic term_free_display(el); 307*54235Sbostic } 308*54235Sbostic 309*54235Sbostic 310*54235Sbostic /* term_alloc(): 311*54235Sbostic * Maintain a string pool for termcap strings 312*54235Sbostic */ 313*54235Sbostic private void 314*54235Sbostic term_alloc(el, t, cap) 315*54235Sbostic EditLine *el; 316*54235Sbostic struct termcapstr *t; 317*54235Sbostic char *cap; 318*54235Sbostic { 319*54235Sbostic char termbuf[TC_BUFSIZE]; 320*54235Sbostic int tlen, clen; 321*54235Sbostic char **tlist = el->el_term.t_str; 322*54235Sbostic char **tmp, **str = &tlist[t - tstr]; 323*54235Sbostic 324*54235Sbostic if (cap == NULL || *cap == '\0') { 325*54235Sbostic *str = NULL; 326*54235Sbostic return; 327*54235Sbostic } 328*54235Sbostic else 329*54235Sbostic clen = strlen(cap); 330*54235Sbostic 331*54235Sbostic tlen = *str == NULL ? 0 : strlen(*str); 332*54235Sbostic 333*54235Sbostic /* 334*54235Sbostic * New string is shorter; no need to allocate space 335*54235Sbostic */ 336*54235Sbostic if (clen <= tlen) { 337*54235Sbostic (void) strcpy(*str, cap); 338*54235Sbostic return; 339*54235Sbostic } 340*54235Sbostic 341*54235Sbostic /* 342*54235Sbostic * New string is longer; see if we have enough space to append 343*54235Sbostic */ 344*54235Sbostic if (el->el_term.t_loc + 3 < TC_BUFSIZE) { 345*54235Sbostic (void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], cap); 346*54235Sbostic el->el_term.t_loc += clen + 1; /* one for \0 */ 347*54235Sbostic return; 348*54235Sbostic } 349*54235Sbostic 350*54235Sbostic /* 351*54235Sbostic * Compact our buffer; no need to check compaction, cause we know it 352*54235Sbostic * fits... 353*54235Sbostic */ 354*54235Sbostic tlen = 0; 355*54235Sbostic for (tmp = tlist; tmp < &tlist[T_str]; tmp++) 356*54235Sbostic if (*tmp != NULL && *tmp != '\0' && *tmp != *str) { 357*54235Sbostic char *ptr; 358*54235Sbostic 359*54235Sbostic for (ptr = *tmp; *ptr != '\0'; termbuf[tlen++] = *ptr++) 360*54235Sbostic continue; 361*54235Sbostic termbuf[tlen++] = '\0'; 362*54235Sbostic } 363*54235Sbostic memcpy(el->el_term.t_buf, termbuf, TC_BUFSIZE); 364*54235Sbostic el->el_term.t_loc = tlen; 365*54235Sbostic if (el->el_term.t_loc + 3 >= TC_BUFSIZE) { 366*54235Sbostic (void) fprintf(el->el_errfile, "Out of termcap string space.\n"); 367*54235Sbostic return; 368*54235Sbostic } 369*54235Sbostic (void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], cap); 370*54235Sbostic el->el_term.t_loc += clen + 1; /* one for \0 */ 371*54235Sbostic return; 372*54235Sbostic } /* end term_alloc */ 373*54235Sbostic 374*54235Sbostic 375*54235Sbostic /* term_rebuffer_display(): 376*54235Sbostic * Rebuffer the display after the screen changed size 377*54235Sbostic */ 378*54235Sbostic private void 379*54235Sbostic term_rebuffer_display(el) 380*54235Sbostic EditLine *el; 381*54235Sbostic { 382*54235Sbostic coord_t *c = &el->el_term.t_size; 383*54235Sbostic 384*54235Sbostic term_free_display(el); 385*54235Sbostic 386*54235Sbostic /* make this public, -1 to avoid wraps */ 387*54235Sbostic c->h = Val(T_co) - 1; 388*54235Sbostic c->v = (EL_BUFSIZ * 4) / c->h + 1; 389*54235Sbostic 390*54235Sbostic term_alloc_display(el); 391*54235Sbostic } /* end term_rebuffer_display */ 392*54235Sbostic 393*54235Sbostic 394*54235Sbostic /* term_alloc_display(): 395*54235Sbostic * Allocate a new display. 396*54235Sbostic */ 397*54235Sbostic private void 398*54235Sbostic term_alloc_display(el) 399*54235Sbostic EditLine *el; 400*54235Sbostic { 401*54235Sbostic int i; 402*54235Sbostic char **b; 403*54235Sbostic coord_t *c = &el->el_term.t_size; 404*54235Sbostic 405*54235Sbostic b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1))); 406*54235Sbostic for (i = 0; i < c->v; i++) 407*54235Sbostic b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); 408*54235Sbostic b[c->v] = NULL; 409*54235Sbostic el->el_display = b; 410*54235Sbostic 411*54235Sbostic b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1))); 412*54235Sbostic for (i = 0; i < c->v; i++) 413*54235Sbostic b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); 414*54235Sbostic b[c->v] = NULL; 415*54235Sbostic el->el_vdisplay = b; 416*54235Sbostic 417*54235Sbostic } /* end term_alloc_display */ 418*54235Sbostic 419*54235Sbostic 420*54235Sbostic /* term_free_display(): 421*54235Sbostic * Free the display buffers 422*54235Sbostic */ 423*54235Sbostic private void 424*54235Sbostic term_free_display(el) 425*54235Sbostic EditLine *el; 426*54235Sbostic { 427*54235Sbostic char **b; 428*54235Sbostic char **bufp; 429*54235Sbostic 430*54235Sbostic b = el->el_display; 431*54235Sbostic el->el_display = NULL; 432*54235Sbostic if (b != NULL) { 433*54235Sbostic for (bufp = b; *bufp != NULL; bufp++) 434*54235Sbostic el_free((ptr_t) *bufp); 435*54235Sbostic el_free((ptr_t) b); 436*54235Sbostic } 437*54235Sbostic b = el->el_vdisplay; 438*54235Sbostic el->el_vdisplay = NULL; 439*54235Sbostic if (b != NULL) { 440*54235Sbostic for (bufp = b; *bufp != NULL; bufp++) 441*54235Sbostic el_free((ptr_t) * bufp); 442*54235Sbostic el_free((ptr_t) b); 443*54235Sbostic } 444*54235Sbostic } /* end term_free_display */ 445*54235Sbostic 446*54235Sbostic 447*54235Sbostic /* term_move_to_line(): 448*54235Sbostic * move to line <where> (first line == 0) 449*54235Sbostic * as efficiently as possible 450*54235Sbostic */ 451*54235Sbostic protected void 452*54235Sbostic term_move_to_line(el, where) 453*54235Sbostic EditLine *el; 454*54235Sbostic int where; 455*54235Sbostic { 456*54235Sbostic int del, i; 457*54235Sbostic 458*54235Sbostic if (where == el->el_cursor.v) 459*54235Sbostic return; 460*54235Sbostic 461*54235Sbostic if (where > el->el_term.t_size.v) { 462*54235Sbostic #ifdef DEBUG_SCREEN 463*54235Sbostic (void) fprintf(el->el_errfile, 464*54235Sbostic "term_move_to_line: where is ridiculous: %d\r\n", where); 465*54235Sbostic #endif /* DEBUG_SCREEN */ 466*54235Sbostic return; 467*54235Sbostic } 468*54235Sbostic 469*54235Sbostic if ((del = where - el->el_cursor.v) > 0) { 470*54235Sbostic if ((del > 1) && GoodStr(T_DO)) 471*54235Sbostic (void) tputs(tgoto(Str(T_DO), del, del), del, term__putc); 472*54235Sbostic else { 473*54235Sbostic for (i = 0; i < del; i++) 474*54235Sbostic term__putc('\n'); 475*54235Sbostic el->el_cursor.h = 0; /* because the \n will become \r\n */ 476*54235Sbostic } 477*54235Sbostic } 478*54235Sbostic else { /* del < 0 */ 479*54235Sbostic if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) 480*54235Sbostic (void) tputs(tgoto(Str(T_UP), -del, -del), -del, term__putc); 481*54235Sbostic else { 482*54235Sbostic if (GoodStr(T_up)) 483*54235Sbostic for (i = 0; i < -del; i++) 484*54235Sbostic (void) tputs(Str(T_up), 1, term__putc); 485*54235Sbostic } 486*54235Sbostic } 487*54235Sbostic el->el_cursor.v = where; /* now where is here */ 488*54235Sbostic } /* end term_move_to_line */ 489*54235Sbostic 490*54235Sbostic 491*54235Sbostic /* term_move_to_char(): 492*54235Sbostic * Move to the character position specified 493*54235Sbostic */ 494*54235Sbostic protected void 495*54235Sbostic term_move_to_char(el, where) 496*54235Sbostic EditLine *el; 497*54235Sbostic int where; 498*54235Sbostic { 499*54235Sbostic int del, i; 500*54235Sbostic 501*54235Sbostic mc_again: 502*54235Sbostic if (where == el->el_cursor.h) 503*54235Sbostic return; 504*54235Sbostic 505*54235Sbostic if (where > (el->el_term.t_size.h + 1)) { 506*54235Sbostic #ifdef DEBUG_SCREEN 507*54235Sbostic (void) fprintf(el->el_errfile, 508*54235Sbostic "term_move_to_char: where is riduculous: %d\r\n", where); 509*54235Sbostic #endif /* DEBUG_SCREEN */ 510*54235Sbostic return; 511*54235Sbostic } 512*54235Sbostic 513*54235Sbostic if (!where) { /* if where is first column */ 514*54235Sbostic term__putc('\r'); /* do a CR */ 515*54235Sbostic el->el_cursor.h = 0; 516*54235Sbostic return; 517*54235Sbostic } 518*54235Sbostic 519*54235Sbostic del = where - el->el_cursor.h; 520*54235Sbostic 521*54235Sbostic if ((del < -4 || del > 4) && GoodStr(T_ch)) 522*54235Sbostic /* go there directly */ 523*54235Sbostic (void) tputs(tgoto(Str(T_ch), where, where), where, term__putc); 524*54235Sbostic else { 525*54235Sbostic if (del > 0) { /* moving forward */ 526*54235Sbostic if ((del > 4) && GoodStr(T_RI)) 527*54235Sbostic (void) tputs(tgoto(Str(T_RI), del, del), del, term__putc); 528*54235Sbostic else { 529*54235Sbostic if (EL_CAN_TAB) { /* if I can do tabs, use them */ 530*54235Sbostic if ((el->el_cursor.h & 0370) != (where & 0370)) { 531*54235Sbostic /* if not within tab stop */ 532*54235Sbostic for (i = (el->el_cursor.h & 0370); 533*54235Sbostic i < (where & 0370); i += 8) 534*54235Sbostic term__putc('\t'); /* then tab over */ 535*54235Sbostic el->el_cursor.h = where & 0370; 536*54235Sbostic } 537*54235Sbostic } 538*54235Sbostic /* it's usually cheaper to just write the chars, so we do. */ 539*54235Sbostic 540*54235Sbostic /* NOTE THAT term_overwrite() WILL CHANGE el->el_cursor.h!!! */ 541*54235Sbostic term_overwrite(el, 542*54235Sbostic &el->el_display[el->el_cursor.v][el->el_cursor.h], 543*54235Sbostic where - el->el_cursor.h); 544*54235Sbostic 545*54235Sbostic } 546*54235Sbostic } 547*54235Sbostic else { /* del < 0 := moving backward */ 548*54235Sbostic if ((-del > 4) && GoodStr(T_LE)) 549*54235Sbostic (void) tputs(tgoto(Str(T_LE), -del, -del), -del, term__putc); 550*54235Sbostic else { /* can't go directly there */ 551*54235Sbostic /* if the "cost" is greater than the "cost" from col 0 */ 552*54235Sbostic if (EL_CAN_TAB ? (-del > ((where >> 3) + (where & 07))) 553*54235Sbostic : (-del > where)) { 554*54235Sbostic term__putc('\r'); /* do a CR */ 555*54235Sbostic el->el_cursor.h = 0; 556*54235Sbostic goto mc_again; /* and try again */ 557*54235Sbostic } 558*54235Sbostic for (i = 0; i < -del; i++) 559*54235Sbostic term__putc('\b'); 560*54235Sbostic } 561*54235Sbostic } 562*54235Sbostic } 563*54235Sbostic el->el_cursor.h = where; /* now where is here */ 564*54235Sbostic } /* end term_move_to_char */ 565*54235Sbostic 566*54235Sbostic 567*54235Sbostic /* term_overwrite(): 568*54235Sbostic * Overstrike num characters 569*54235Sbostic */ 570*54235Sbostic protected void 571*54235Sbostic term_overwrite(el, cp, n) 572*54235Sbostic EditLine *el; 573*54235Sbostic char *cp; 574*54235Sbostic int n; 575*54235Sbostic { 576*54235Sbostic if (n <= 0) 577*54235Sbostic return; /* catch bugs */ 578*54235Sbostic 579*54235Sbostic if (n > (el->el_term.t_size.h + 1)) { 580*54235Sbostic #ifdef DEBUG_SCREEN 581*54235Sbostic (void) fprintf(el->el_errfile, "term_overwrite: n is riduculous: %d\r\n", n); 582*54235Sbostic #endif /* DEBUG_SCREEN */ 583*54235Sbostic return; 584*54235Sbostic } 585*54235Sbostic 586*54235Sbostic do { 587*54235Sbostic term__putc(*cp++); 588*54235Sbostic el->el_cursor.h++; 589*54235Sbostic } while (--n); 590*54235Sbostic } /* end term_overwrite */ 591*54235Sbostic 592*54235Sbostic 593*54235Sbostic /* term_deletechars(): 594*54235Sbostic * Delete num characters 595*54235Sbostic */ 596*54235Sbostic protected void 597*54235Sbostic term_deletechars(el, num) 598*54235Sbostic EditLine *el; 599*54235Sbostic int num; 600*54235Sbostic { 601*54235Sbostic if (num <= 0) 602*54235Sbostic return; 603*54235Sbostic 604*54235Sbostic if (!EL_CAN_DELETE) { 605*54235Sbostic #ifdef DEBUG_EDIT 606*54235Sbostic (void) fprintf(el->el_errfile, " ERROR: cannot delete \n"); 607*54235Sbostic #endif /* DEBUG_EDIT */ 608*54235Sbostic return; 609*54235Sbostic } 610*54235Sbostic 611*54235Sbostic if (num > el->el_term.t_size.h) { 612*54235Sbostic #ifdef DEBUG_SCREEN 613*54235Sbostic (void) fprintf(el->el_errfile, 614*54235Sbostic "term_deletechars: num is riduculous: %d\r\n", num); 615*54235Sbostic #endif /* DEBUG_SCREEN */ 616*54235Sbostic return; 617*54235Sbostic } 618*54235Sbostic 619*54235Sbostic if (GoodStr(T_DC)) /* if I have multiple delete */ 620*54235Sbostic if ((num > 1) || !GoodStr(T_dc)) { /* if dc would be more expen. */ 621*54235Sbostic (void) tputs(tgoto(Str(T_DC), num, num), num, term__putc); 622*54235Sbostic return; 623*54235Sbostic } 624*54235Sbostic 625*54235Sbostic if (GoodStr(T_dm)) /* if I have delete mode */ 626*54235Sbostic (void) tputs(Str(T_dm), 1, term__putc); 627*54235Sbostic 628*54235Sbostic if (GoodStr(T_dc)) /* else do one at a time */ 629*54235Sbostic while (num--) 630*54235Sbostic (void) tputs(Str(T_dc), 1, term__putc); 631*54235Sbostic 632*54235Sbostic if (GoodStr(T_ed)) /* if I have delete mode */ 633*54235Sbostic (void) tputs(Str(T_ed), 1, term__putc); 634*54235Sbostic } /* end term_deletechars */ 635*54235Sbostic 636*54235Sbostic 637*54235Sbostic /* term_insertwrite(): 638*54235Sbostic * Puts terminal in insert character mode or inserts num 639*54235Sbostic * characters in the line 640*54235Sbostic */ 641*54235Sbostic protected void 642*54235Sbostic term_insertwrite(el, cp, num) 643*54235Sbostic EditLine *el; 644*54235Sbostic char *cp; 645*54235Sbostic int num; 646*54235Sbostic { 647*54235Sbostic if (num <= 0) 648*54235Sbostic return; 649*54235Sbostic if (!EL_CAN_INSERT) { 650*54235Sbostic #ifdef DEBUG_EDIT 651*54235Sbostic (void) fprintf(el->el_errfile, " ERROR: cannot insert \n"); 652*54235Sbostic #endif /* DEBUG_EDIT */ 653*54235Sbostic return; 654*54235Sbostic } 655*54235Sbostic 656*54235Sbostic if (num > el->el_term.t_size.h) { 657*54235Sbostic #ifdef DEBUG_SCREEN 658*54235Sbostic (void) fprintf(el->el_errfile, "StartInsert: num is riduculous: %d\r\n", num); 659*54235Sbostic #endif /* DEBUG_SCREEN */ 660*54235Sbostic return; 661*54235Sbostic } 662*54235Sbostic 663*54235Sbostic if (GoodStr(T_IC)) /* if I have multiple insert */ 664*54235Sbostic if ((num > 1) || !GoodStr(T_ic)) { /* if ic would be more expen. */ 665*54235Sbostic (void) tputs(tgoto(Str(T_IC), num, num), num, term__putc); 666*54235Sbostic term_overwrite(el, cp, num); /* this updates el_cursor.h */ 667*54235Sbostic return; 668*54235Sbostic } 669*54235Sbostic 670*54235Sbostic if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */ 671*54235Sbostic (void) tputs(Str(T_im), 1, term__putc); 672*54235Sbostic 673*54235Sbostic el->el_cursor.h += num; 674*54235Sbostic do 675*54235Sbostic term__putc(*cp++); 676*54235Sbostic while (--num); 677*54235Sbostic 678*54235Sbostic if (GoodStr(T_ip)) /* have to make num chars insert */ 679*54235Sbostic (void) tputs(Str(T_ip), 1, term__putc); 680*54235Sbostic 681*54235Sbostic (void) tputs(Str(T_ei), 1, term__putc); 682*54235Sbostic return; 683*54235Sbostic } 684*54235Sbostic 685*54235Sbostic do { 686*54235Sbostic if (GoodStr(T_ic)) /* have to make num chars insert */ 687*54235Sbostic (void) tputs(Str(T_ic), 1, term__putc); /* insert a char */ 688*54235Sbostic 689*54235Sbostic term__putc(*cp++); 690*54235Sbostic 691*54235Sbostic el->el_cursor.h++; 692*54235Sbostic 693*54235Sbostic if (GoodStr(T_ip)) /* have to make num chars insert */ 694*54235Sbostic (void) tputs(Str(T_ip), 1, term__putc);/* pad the inserted char */ 695*54235Sbostic 696*54235Sbostic } while (--num); 697*54235Sbostic } /* end term_insertwrite */ 698*54235Sbostic 699*54235Sbostic 700*54235Sbostic /* term_clear_EOL(): 701*54235Sbostic * clear to end of line. There are num characters to clear 702*54235Sbostic */ 703*54235Sbostic protected void 704*54235Sbostic term_clear_EOL(el, num) 705*54235Sbostic EditLine *el; 706*54235Sbostic int num; 707*54235Sbostic { 708*54235Sbostic int i; 709*54235Sbostic 710*54235Sbostic if (EL_CAN_CEOL && GoodStr(T_ce)) 711*54235Sbostic (void) tputs(Str(T_ce), 1, term__putc); 712*54235Sbostic else { 713*54235Sbostic for (i = 0; i < num; i++) 714*54235Sbostic term__putc(' '); 715*54235Sbostic el->el_cursor.h += num; /* have written num spaces */ 716*54235Sbostic } 717*54235Sbostic } /* end term_clear_EOL */ 718*54235Sbostic 719*54235Sbostic 720*54235Sbostic /* term_clear_screen(): 721*54235Sbostic * Clear the screen 722*54235Sbostic */ 723*54235Sbostic protected void 724*54235Sbostic term_clear_screen(el) 725*54235Sbostic EditLine *el; 726*54235Sbostic { /* clear the whole screen and home */ 727*54235Sbostic if (GoodStr(T_cl)) 728*54235Sbostic /* send the clear screen code */ 729*54235Sbostic (void) tputs(Str(T_cl), Val(T_li), term__putc); 730*54235Sbostic else if (GoodStr(T_ho) && GoodStr(T_cd)) { 731*54235Sbostic (void) tputs(Str(T_ho), Val(T_li), term__putc); /* home */ 732*54235Sbostic /* clear to bottom of screen */ 733*54235Sbostic (void) tputs(Str(T_cd), Val(T_li), term__putc); 734*54235Sbostic } 735*54235Sbostic else { 736*54235Sbostic term__putc('\r'); 737*54235Sbostic term__putc('\n'); 738*54235Sbostic } 739*54235Sbostic } /* end term_clear_screen */ 740*54235Sbostic 741*54235Sbostic 742*54235Sbostic /* term_beep(): 743*54235Sbostic * Beep the way the terminal wants us 744*54235Sbostic */ 745*54235Sbostic protected void 746*54235Sbostic term_beep(el) 747*54235Sbostic EditLine *el; 748*54235Sbostic { 749*54235Sbostic if (GoodStr(T_vb)) 750*54235Sbostic (void) tputs(Str(T_vb), 1, term__putc); /* visible bell */ 751*54235Sbostic else if (GoodStr(T_bl)) 752*54235Sbostic /* what termcap says we should use */ 753*54235Sbostic (void) tputs(Str(T_bl), 1, term__putc); 754*54235Sbostic else 755*54235Sbostic term__putc('\007'); /* an ASCII bell; ^G */ 756*54235Sbostic } /* end term_beep */ 757*54235Sbostic 758*54235Sbostic 759*54235Sbostic #ifdef notdef 760*54235Sbostic /* term_clear_to_bottom(): 761*54235Sbostic * Clear to the bottom of the screen 762*54235Sbostic */ 763*54235Sbostic protected void 764*54235Sbostic term_clear_to_bottom(el) 765*54235Sbostic EditLine *el; 766*54235Sbostic { 767*54235Sbostic if (GoodStr(T_cd)) 768*54235Sbostic (void) tputs(Str(T_cd), Val(T_li), term__putc); 769*54235Sbostic else if (GoodStr(T_ce)) 770*54235Sbostic (void) tputs(Str(T_ce), Val(T_li), term__putc); 771*54235Sbostic } /* end term_clear_to_bottom */ 772*54235Sbostic #endif 773*54235Sbostic 774*54235Sbostic 775*54235Sbostic /* term_get_termcap(): 776*54235Sbostic * Read in the terminal capabilities 777*54235Sbostic */ 778*54235Sbostic private void 779*54235Sbostic term_get_termcap(el, term) 780*54235Sbostic EditLine *el; 781*54235Sbostic char *term; 782*54235Sbostic { 783*54235Sbostic int i; 784*54235Sbostic char buf[TC_BUFSIZE]; 785*54235Sbostic char *area; 786*54235Sbostic struct termcapstr *t; 787*54235Sbostic sigset_t oset, nset; 788*54235Sbostic int lins, cols; 789*54235Sbostic 790*54235Sbostic (void) sigemptyset(&nset); 791*54235Sbostic (void) sigaddset(&nset, SIGWINCH); 792*54235Sbostic (void) sigprocmask(SIG_BLOCK, &nset, &oset); 793*54235Sbostic 794*54235Sbostic area = buf; 795*54235Sbostic 796*54235Sbostic 797*54235Sbostic if (term == NULL) 798*54235Sbostic term = getenv("TERM"); 799*54235Sbostic 800*54235Sbostic if (!term || !term[0]) 801*54235Sbostic term = "dumb"; 802*54235Sbostic 803*54235Sbostic memset(el->el_term.t_cap, 0, TC_BUFSIZE); 804*54235Sbostic 805*54235Sbostic i = tgetent(el->el_term.t_cap, term); 806*54235Sbostic 807*54235Sbostic if (i <= 0) { 808*54235Sbostic if (i == -1) 809*54235Sbostic (void) fprintf(el->el_errfile, "Cannot open /etc/termcap.\n"); 810*54235Sbostic else if (i == 0) 811*54235Sbostic (void) fprintf(el->el_errfile, 812*54235Sbostic "No entry for terminal type \"%s\"\n", term); 813*54235Sbostic (void) fprintf(el->el_errfile, "using dumb terminal settings.\n"); 814*54235Sbostic Val(T_co) = 80; /* do a dumb terminal */ 815*54235Sbostic Val(T_pt) = Val(T_km) = Val(T_li) = 0; 816*54235Sbostic Val(T_xt) = Val(T_MT); 817*54235Sbostic for (t = tstr; t->name != NULL; t++) 818*54235Sbostic term_alloc(el, t, NULL); 819*54235Sbostic } 820*54235Sbostic else { 821*54235Sbostic /* Can we tab */ 822*54235Sbostic Val(T_pt) = tgetflag("pt"); 823*54235Sbostic Val(T_xt) = tgetflag("xt"); 824*54235Sbostic /* do we have a meta? */ 825*54235Sbostic Val(T_km) = tgetflag("km"); 826*54235Sbostic Val(T_MT) = tgetflag("MT"); 827*54235Sbostic /* Get the size */ 828*54235Sbostic Val(T_co) = tgetnum("co"); 829*54235Sbostic Val(T_li) = tgetnum("li"); 830*54235Sbostic for (t = tstr; t->name != NULL; t++) 831*54235Sbostic term_alloc(el, t, tgetstr(t->name, &area)); 832*54235Sbostic } 833*54235Sbostic 834*54235Sbostic if (Val(T_co) < 2) 835*54235Sbostic Val(T_co) = 80; /* just in case */ 836*54235Sbostic if (Val(T_li) < 1) 837*54235Sbostic Val(T_li) = 24; 838*54235Sbostic 839*54235Sbostic el->el_term.t_size.v = Val(T_co); 840*54235Sbostic el->el_term.t_size.h = Val(T_li); 841*54235Sbostic 842*54235Sbostic term_setflags(el); 843*54235Sbostic 844*54235Sbostic (void) term_get_size(el, &lins, &cols);/* get the correct window size */ 845*54235Sbostic term_change_size(el, lins, cols); 846*54235Sbostic (void) sigprocmask(SIG_SETMASK, &oset, NULL); 847*54235Sbostic term_bind_arrows(el); 848*54235Sbostic } /* end term_get_termcap */ 849*54235Sbostic 850*54235Sbostic 851*54235Sbostic /* term_get_size(): 852*54235Sbostic * Return the new window size in lines and cols, and 853*54235Sbostic * true if the size was changed. 854*54235Sbostic */ 855*54235Sbostic protected int 856*54235Sbostic term_get_size(el, lins, cols) 857*54235Sbostic EditLine *el; 858*54235Sbostic int *lins, *cols; 859*54235Sbostic { 860*54235Sbostic 861*54235Sbostic *cols = Val(T_co); 862*54235Sbostic *lins = Val(T_li); 863*54235Sbostic 864*54235Sbostic #ifdef TIOCGWINSZ 865*54235Sbostic { 866*54235Sbostic struct winsize ws; 867*54235Sbostic if (ioctl(el->el_infd, TIOCGWINSZ, (ioctl_t) &ws) != -1) { 868*54235Sbostic if (ws.ws_col) 869*54235Sbostic *cols = ws.ws_col; 870*54235Sbostic if (ws.ws_row) 871*54235Sbostic *lins = ws.ws_row; 872*54235Sbostic } 873*54235Sbostic } 874*54235Sbostic #endif 875*54235Sbostic #ifdef TIOCGSIZE 876*54235Sbostic { 877*54235Sbostic struct ttysize ts; 878*54235Sbostic if (ioctl(el->el_infd, TIOCGSIZE, (ioctl_t) &ts) != -1) { 879*54235Sbostic if (ts.ts_cols) 880*54235Sbostic *cols = ts.ts_cols; 881*54235Sbostic if (ts.ts_lines) 882*54235Sbostic *lins = ts.ts_lines; 883*54235Sbostic } 884*54235Sbostic } 885*54235Sbostic #endif 886*54235Sbostic return (Val(T_co) != *cols || Val(T_li) != *lins); 887*54235Sbostic } /* end term_get_size */ 888*54235Sbostic 889*54235Sbostic 890*54235Sbostic /* term_change_size(): 891*54235Sbostic * Change the size of the terminal 892*54235Sbostic */ 893*54235Sbostic protected void 894*54235Sbostic term_change_size(el, lins, cols) 895*54235Sbostic EditLine *el; 896*54235Sbostic int lins, cols; 897*54235Sbostic { 898*54235Sbostic /* 899*54235Sbostic * Just in case 900*54235Sbostic */ 901*54235Sbostic Val(T_co) = (cols < 2) ? 80 : cols; 902*54235Sbostic Val(T_li) = (lins < 1) ? 24 : lins; 903*54235Sbostic 904*54235Sbostic term_rebuffer_display(el); /* re-make display buffers */ 905*54235Sbostic re_clear_display(el); 906*54235Sbostic } /* end term_change_size */ 907*54235Sbostic 908*54235Sbostic 909*54235Sbostic /* term_bind_arrows(): 910*54235Sbostic * Bind the arrow keys 911*54235Sbostic */ 912*54235Sbostic protected void 913*54235Sbostic term_bind_arrows(el) 914*54235Sbostic EditLine *el; 915*54235Sbostic { 916*54235Sbostic el_action_t *map, *dmap; 917*54235Sbostic int i, j; 918*54235Sbostic char *p; 919*54235Sbostic static struct { 920*54235Sbostic int key, fun; 921*54235Sbostic } ar[] = 922*54235Sbostic { 923*54235Sbostic { T_kd, ED_NEXT_HISTORY }, 924*54235Sbostic { T_ku, ED_PREV_HISTORY }, 925*54235Sbostic { T_kl, ED_PREV_CHAR }, 926*54235Sbostic { T_kr, ED_NEXT_CHAR } 927*54235Sbostic }; 928*54235Sbostic 929*54235Sbostic /* Check if the components needed are initialized */ 930*54235Sbostic if (el->el_term.t_buf == NULL || el->el_map.key == NULL) 931*54235Sbostic return; 932*54235Sbostic 933*54235Sbostic map = el->el_map.type == MAP_VI ? el->el_map.alt : el->el_map.key; 934*54235Sbostic dmap = el->el_map.type == MAP_VI ? el->el_map.vic : el->el_map.emacs; 935*54235Sbostic 936*54235Sbostic for (i = 0; i < 4; i++) { 937*54235Sbostic p = el->el_term.t_str[ar[i].key]; 938*54235Sbostic if (p && *p) { 939*54235Sbostic j = (unsigned char) *p; 940*54235Sbostic /* 941*54235Sbostic * Assign the arrow keys only if: 942*54235Sbostic * 943*54235Sbostic * 1. They are multi-character arrow keys and the user 944*54235Sbostic * has not re-assigned the leading character, or 945*54235Sbostic * has re-assigned the leading character to be 946*54235Sbostic * ED_SEQUENCE_LEAD_IN 947*54235Sbostic * 2. They are single arrow keys pointing to an unassigned key. 948*54235Sbostic */ 949*54235Sbostic if (p[1] && (dmap[j] == map[j] || map[j] == ED_SEQUENCE_LEAD_IN)) { 950*54235Sbostic key_add(el, p, key_map_cmd(el, ar[i].fun), XK_CMD); 951*54235Sbostic map[j] = ED_SEQUENCE_LEAD_IN; 952*54235Sbostic } 953*54235Sbostic else if (map[j] == ED_UNASSIGNED) { 954*54235Sbostic key_clear(el, map, p); 955*54235Sbostic map[j] = ar[i].fun; 956*54235Sbostic } 957*54235Sbostic } 958*54235Sbostic } 959*54235Sbostic } 960*54235Sbostic 961*54235Sbostic 962*54235Sbostic /* term__putc(): 963*54235Sbostic * Add a character 964*54235Sbostic */ 965*54235Sbostic protected void 966*54235Sbostic term__putc(c) 967*54235Sbostic int c; 968*54235Sbostic { 969*54235Sbostic (void) fputc(c, term_outfile); 970*54235Sbostic } /* end term__putc */ 971*54235Sbostic 972*54235Sbostic 973*54235Sbostic /* term__flush(): 974*54235Sbostic * Flush output 975*54235Sbostic */ 976*54235Sbostic protected void 977*54235Sbostic term__flush() 978*54235Sbostic { 979*54235Sbostic (void) fflush(term_outfile); 980*54235Sbostic } /* end term__flush */ 981*54235Sbostic 982*54235Sbostic 983*54235Sbostic /* term_telltc(): 984*54235Sbostic * Print the current termcap characteristics 985*54235Sbostic */ 986*54235Sbostic protected int 987*54235Sbostic /*ARGSUSED*/ 988*54235Sbostic term_telltc(el, argc, argv) 989*54235Sbostic EditLine *el; 990*54235Sbostic int argc; 991*54235Sbostic char **argv; 992*54235Sbostic { 993*54235Sbostic struct termcapstr *t; 994*54235Sbostic char **ts; 995*54235Sbostic char upbuf[EL_BUFSIZ]; 996*54235Sbostic 997*54235Sbostic (void) fprintf(el->el_outfile, "\n\tYour terminal has the\n"); 998*54235Sbostic (void) fprintf(el->el_outfile, "\tfollowing characteristics:\n\n"); 999*54235Sbostic (void) fprintf(el->el_outfile, "\tIt has %d columns and %d lines\n", 1000*54235Sbostic Val(T_co), Val(T_li)); 1001*54235Sbostic (void) fprintf(el->el_outfile, 1002*54235Sbostic "\tIt has %s meta key\n", EL_HAS_META ? "a" : "no"); 1003*54235Sbostic (void) fprintf(el->el_outfile, 1004*54235Sbostic "\tIt can%suse tabs\n", EL_CAN_TAB ? " " : "not "); 1005*54235Sbostic #ifdef notyet 1006*54235Sbostic (void) fprintf(el->el_outfile, "\tIt %s automatic margins\n", 1007*54235Sbostic (T_Margin&MARGIN_AUTO)? "has": "does not have"); 1008*54235Sbostic if (T_Margin & MARGIN_AUTO) 1009*54235Sbostic (void) fprintf(el->el_outfile, "\tIt %s magic margins\n", 1010*54235Sbostic (T_Margin&MARGIN_MAGIC)?"has":"does not have"); 1011*54235Sbostic #endif 1012*54235Sbostic 1013*54235Sbostic for (t = tstr, ts = el->el_term.t_str; t->name != NULL; t++, ts++) 1014*54235Sbostic (void) fprintf(el->el_outfile, "\t%25s (%s) == %s\n", t->long_name, 1015*54235Sbostic t->name, *ts && **ts ? 1016*54235Sbostic key__decode_str(*ts, upbuf, "") : "(empty)"); 1017*54235Sbostic (void) fputc('\n', el->el_outfile); 1018*54235Sbostic return 0; 1019*54235Sbostic } 1020*54235Sbostic 1021*54235Sbostic 1022*54235Sbostic /* term_settc(): 1023*54235Sbostic * Change the current terminal characteristics 1024*54235Sbostic */ 1025*54235Sbostic protected int 1026*54235Sbostic /*ARGSUSED*/ 1027*54235Sbostic term_settc(el, argc, argv) 1028*54235Sbostic EditLine *el; 1029*54235Sbostic int argc; 1030*54235Sbostic char **argv; 1031*54235Sbostic { 1032*54235Sbostic struct termcapstr *ts; 1033*54235Sbostic struct termcapval *tv; 1034*54235Sbostic char *what, *how; 1035*54235Sbostic 1036*54235Sbostic if (argv == NULL || argv[1] == NULL || argv[2] == NULL) 1037*54235Sbostic return -1; 1038*54235Sbostic 1039*54235Sbostic what = argv[1]; 1040*54235Sbostic how = argv[2]; 1041*54235Sbostic 1042*54235Sbostic /* 1043*54235Sbostic * Do the strings first 1044*54235Sbostic */ 1045*54235Sbostic for (ts = tstr; ts->name != NULL; ts++) 1046*54235Sbostic if (strcmp(ts->name, what) == 0) 1047*54235Sbostic break; 1048*54235Sbostic 1049*54235Sbostic if (ts->name != NULL) { 1050*54235Sbostic term_alloc(el, ts, how); 1051*54235Sbostic term_setflags(el); 1052*54235Sbostic return 0; 1053*54235Sbostic } 1054*54235Sbostic 1055*54235Sbostic /* 1056*54235Sbostic * Do the numeric ones second 1057*54235Sbostic */ 1058*54235Sbostic for (tv = tval; tv->name != NULL; tv++) 1059*54235Sbostic if (strcmp(tv->name, what) == 0) 1060*54235Sbostic break; 1061*54235Sbostic 1062*54235Sbostic if (tv->name != NULL) { 1063*54235Sbostic if (tv == &tval[T_pt] || tv == &tval[T_km] 1064*54235Sbostic #ifdef notyet 1065*54235Sbostic || tv == &tval[T_am] || tv == &tval[T_xn] 1066*54235Sbostic #endif 1067*54235Sbostic ) { 1068*54235Sbostic if (strcmp(how, "yes") == 0) 1069*54235Sbostic el->el_term.t_val[tv - tval] = 1; 1070*54235Sbostic else if (strcmp(how, "no") == 0) 1071*54235Sbostic el->el_term.t_val[tv - tval] = 0; 1072*54235Sbostic else { 1073*54235Sbostic (void) fprintf(el->el_errfile, "settc: Bad value `%s'.\n", how); 1074*54235Sbostic return -1; 1075*54235Sbostic } 1076*54235Sbostic term_setflags(el); 1077*54235Sbostic term_change_size(el, Val(T_li), Val(T_co)); 1078*54235Sbostic return 0; 1079*54235Sbostic } 1080*54235Sbostic else { 1081*54235Sbostic el->el_term.t_val[tv - tval] = atoi(how); 1082*54235Sbostic el->el_term.t_size.v = Val(T_co); 1083*54235Sbostic el->el_term.t_size.h = Val(T_li); 1084*54235Sbostic if (tv == &tval[T_co] || tv == &tval[T_li]) 1085*54235Sbostic term_change_size(el, Val(T_li), Val(T_co)); 1086*54235Sbostic return 0; 1087*54235Sbostic } 1088*54235Sbostic } 1089*54235Sbostic return -1; 1090*54235Sbostic } 1091*54235Sbostic 1092*54235Sbostic 1093*54235Sbostic /* term_echotc(): 1094*54235Sbostic * Print the termcap string out with variable substitution 1095*54235Sbostic */ 1096*54235Sbostic protected int 1097*54235Sbostic /*ARGSUSED*/ 1098*54235Sbostic term_echotc(el, argc, argv) 1099*54235Sbostic EditLine *el; 1100*54235Sbostic int argc; 1101*54235Sbostic char **argv; 1102*54235Sbostic { 1103*54235Sbostic char *cap, *scap; 1104*54235Sbostic int arg_need, arg_cols, arg_rows; 1105*54235Sbostic int verbose = 0, silent = 0; 1106*54235Sbostic char *area; 1107*54235Sbostic static char *fmts = "%s\n", *fmtd = "%d\n"; 1108*54235Sbostic struct termcapstr *t; 1109*54235Sbostic char buf[TC_BUFSIZE]; 1110*54235Sbostic 1111*54235Sbostic area = buf; 1112*54235Sbostic 1113*54235Sbostic if (argv == NULL || argv[1] == NULL) 1114*54235Sbostic return -1; 1115*54235Sbostic argv++; 1116*54235Sbostic 1117*54235Sbostic if (argv[0][0] == '-') { 1118*54235Sbostic switch (argv[0][1]) { 1119*54235Sbostic case 'v': 1120*54235Sbostic verbose = 1; 1121*54235Sbostic break; 1122*54235Sbostic case 's': 1123*54235Sbostic silent = 1; 1124*54235Sbostic break; 1125*54235Sbostic default: 1126*54235Sbostic /* stderror(ERR_NAME | ERR_TCUSAGE); */ 1127*54235Sbostic break; 1128*54235Sbostic } 1129*54235Sbostic argv++; 1130*54235Sbostic } 1131*54235Sbostic if (!*argv || *argv[0] == '\0') 1132*54235Sbostic return 0; 1133*54235Sbostic if (strcmp(*argv, "tabs") == 0) { 1134*54235Sbostic (void) fprintf(el->el_outfile, fmts, EL_CAN_TAB ? "yes" : "no"); 1135*54235Sbostic return 0; 1136*54235Sbostic } 1137*54235Sbostic else if (strcmp(*argv, "meta") == 0) { 1138*54235Sbostic (void) fprintf(el->el_outfile, fmts, Val(T_km) ? "yes" : "no"); 1139*54235Sbostic return 0; 1140*54235Sbostic } 1141*54235Sbostic #ifdef notyet 1142*54235Sbostic else if (strcmp(*argv, "xn") == 0) { 1143*54235Sbostic (void) fprintf(el->el_outfile, fmts, T_Margin & MARGIN_MAGIC ? 1144*54235Sbostic "yes" : "no"); 1145*54235Sbostic return 0; 1146*54235Sbostic } 1147*54235Sbostic else if (strcmp(*argv, "am") == 0) { 1148*54235Sbostic (void) fprintf(el->el_outfile, fmts, T_Margin & MARGIN_AUTO ? 1149*54235Sbostic "yes" : "no"); 1150*54235Sbostic return 0; 1151*54235Sbostic } 1152*54235Sbostic #endif 1153*54235Sbostic else if (strcmp(*argv, "baud") == 0) { 1154*54235Sbostic int i; 1155*54235Sbostic 1156*54235Sbostic for (i = 0; baud_rate[i].b_name != NULL; i++) 1157*54235Sbostic if (el->el_tty.t_speed == baud_rate[i].b_rate) { 1158*54235Sbostic (void) fprintf(el->el_outfile, fmts, baud_rate[i].b_name); 1159*54235Sbostic return 0; 1160*54235Sbostic } 1161*54235Sbostic (void) fprintf(el->el_outfile, fmtd, 0); 1162*54235Sbostic return 0; 1163*54235Sbostic } 1164*54235Sbostic else if (strcmp(*argv, "rows") == 0 || strcmp(*argv, "lines") == 0) { 1165*54235Sbostic (void) fprintf(el->el_outfile, fmtd, Val(T_li)); 1166*54235Sbostic return 0; 1167*54235Sbostic } 1168*54235Sbostic else if (strcmp(*argv, "cols") == 0) { 1169*54235Sbostic (void) fprintf(el->el_outfile, fmtd, Val(T_co)); 1170*54235Sbostic return 0; 1171*54235Sbostic } 1172*54235Sbostic 1173*54235Sbostic /* 1174*54235Sbostic * Try to use our local definition first 1175*54235Sbostic */ 1176*54235Sbostic scap = NULL; 1177*54235Sbostic for (t = tstr; t->name != NULL; t++) 1178*54235Sbostic if (strcmp(t->name, *argv) == 0) { 1179*54235Sbostic scap = el->el_term.t_str[t - tstr]; 1180*54235Sbostic break; 1181*54235Sbostic } 1182*54235Sbostic if (t->name == NULL) 1183*54235Sbostic scap = tgetstr(*argv, &area); 1184*54235Sbostic if (!scap || scap[0] == '\0') { 1185*54235Sbostic if (!silent) 1186*54235Sbostic (void) fprintf(el->el_errfile, 1187*54235Sbostic "echotc: Termcap parameter `%s' not found.\n", *argv); 1188*54235Sbostic return -1; 1189*54235Sbostic } 1190*54235Sbostic 1191*54235Sbostic /* 1192*54235Sbostic * Count home many values we need for this capability. 1193*54235Sbostic */ 1194*54235Sbostic for (cap = scap, arg_need = 0; *cap; cap++) 1195*54235Sbostic if (*cap == '%') 1196*54235Sbostic switch (*++cap) { 1197*54235Sbostic case 'd': 1198*54235Sbostic case '2': 1199*54235Sbostic case '3': 1200*54235Sbostic case '.': 1201*54235Sbostic case '+': 1202*54235Sbostic arg_need++; 1203*54235Sbostic break; 1204*54235Sbostic case '%': 1205*54235Sbostic case '>': 1206*54235Sbostic case 'i': 1207*54235Sbostic case 'r': 1208*54235Sbostic case 'n': 1209*54235Sbostic case 'B': 1210*54235Sbostic case 'D': 1211*54235Sbostic break; 1212*54235Sbostic default: 1213*54235Sbostic /* 1214*54235Sbostic * hpux has lot's of them... 1215*54235Sbostic */ 1216*54235Sbostic if (verbose) 1217*54235Sbostic (void) fprintf(el->el_errfile, 1218*54235Sbostic "echotc: Warning: unknown termcap %% `%c'.\n", *cap); 1219*54235Sbostic /* This is bad, but I won't complain */ 1220*54235Sbostic break; 1221*54235Sbostic } 1222*54235Sbostic 1223*54235Sbostic switch (arg_need) { 1224*54235Sbostic case 0: 1225*54235Sbostic argv++; 1226*54235Sbostic if (*argv && *argv[0]) { 1227*54235Sbostic if (!silent) 1228*54235Sbostic (void) fprintf(el->el_errfile, 1229*54235Sbostic "echotc: Warning: Extra argument `%s'.\n", *argv); 1230*54235Sbostic return -1; 1231*54235Sbostic } 1232*54235Sbostic (void) tputs(scap, 1, term__putc); 1233*54235Sbostic break; 1234*54235Sbostic case 1: 1235*54235Sbostic argv++; 1236*54235Sbostic if (!*argv || *argv[0] == '\0') { 1237*54235Sbostic if (!silent) 1238*54235Sbostic (void) fprintf(el->el_errfile, 1239*54235Sbostic "echotc: Warning: Missing argument.\n"); 1240*54235Sbostic return -1; 1241*54235Sbostic } 1242*54235Sbostic arg_cols = 0; 1243*54235Sbostic arg_rows = atoi(*argv); 1244*54235Sbostic argv++; 1245*54235Sbostic if (*argv && *argv[0]) { 1246*54235Sbostic if (!silent) 1247*54235Sbostic (void) fprintf(el->el_errfile, 1248*54235Sbostic "echotc: Warning: Extra argument `%s'.\n", *argv); 1249*54235Sbostic return -1; 1250*54235Sbostic } 1251*54235Sbostic (void) tputs(tgoto(scap, arg_cols, arg_rows), 1, term__putc); 1252*54235Sbostic break; 1253*54235Sbostic default: 1254*54235Sbostic /* This is wrong, but I will ignore it... */ 1255*54235Sbostic if (verbose) 1256*54235Sbostic (void) fprintf(el->el_errfile, 1257*54235Sbostic "echotc: Warning: Too many required arguments (%d).\n", 1258*54235Sbostic arg_need); 1259*54235Sbostic /*FALLTHROUGH*/ 1260*54235Sbostic case 2: 1261*54235Sbostic argv++; 1262*54235Sbostic if (!*argv || *argv[0] == '\0') { 1263*54235Sbostic if (!silent) 1264*54235Sbostic (void) fprintf(el->el_errfile, 1265*54235Sbostic "echotc: Warning: Missing argument.\n"); 1266*54235Sbostic return -1; 1267*54235Sbostic } 1268*54235Sbostic arg_cols = atoi(*argv); 1269*54235Sbostic argv++; 1270*54235Sbostic if (!*argv || *argv[0] == '\0') { 1271*54235Sbostic if (!silent) 1272*54235Sbostic (void) fprintf(el->el_errfile, 1273*54235Sbostic "echotc: Warning: Missing argument.\n"); 1274*54235Sbostic return -1; 1275*54235Sbostic } 1276*54235Sbostic arg_rows = atoi(*argv); 1277*54235Sbostic argv++; 1278*54235Sbostic if (*argv && *argv[0]) { 1279*54235Sbostic if (!silent) 1280*54235Sbostic (void) fprintf(el->el_errfile, 1281*54235Sbostic "echotc: Warning: Extra argument `%s'.\n", *argv); 1282*54235Sbostic return -1; 1283*54235Sbostic } 1284*54235Sbostic (void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows, term__putc); 1285*54235Sbostic break; 1286*54235Sbostic } 1287*54235Sbostic return 0; 1288*54235Sbostic } 1289