11573Srgrimes/*- 21573Srgrimes * Copyright (c) 1992, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * This code is derived from software contributed to Berkeley by 61573Srgrimes * Christos Zoulas of Cornell University. 71573Srgrimes * 81573Srgrimes * Redistribution and use in source and binary forms, with or without 91573Srgrimes * modification, are permitted provided that the following conditions 101573Srgrimes * are met: 111573Srgrimes * 1. Redistributions of source code must retain the above copyright 121573Srgrimes * notice, this list of conditions and the following disclaimer. 131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141573Srgrimes * notice, this list of conditions and the following disclaimer in the 151573Srgrimes * documentation and/or other materials provided with the distribution. 16148834Sstefanf * 3. Neither the name of the University nor the names of its contributors 171573Srgrimes * may be used to endorse or promote products derived from this software 181573Srgrimes * without specific prior written permission. 191573Srgrimes * 201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301573Srgrimes * SUCH DAMAGE. 3184260Sobrien * 32237448Spfg * $NetBSD: term.c,v 1.56 2009/12/28 21:54:21 christos Exp $ 331573Srgrimes */ 341573Srgrimes 351573Srgrimes#if !defined(lint) && !defined(SCCSID) 3611678Sbdestatic char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95"; 371573Srgrimes#endif /* not lint && not SCCSID */ 3884260Sobrien#include <sys/cdefs.h> 3984260Sobrien__FBSDID("$FreeBSD$"); 401573Srgrimes 411573Srgrimes/* 421573Srgrimes * term.c: Editor/termcap-curses interface 431573Srgrimes * We have to declare a static variable here, since the 441573Srgrimes * termcap putchar routine does not take an argument! 451573Srgrimes */ 461573Srgrimes#include <stdio.h> 471573Srgrimes#include <signal.h> 481573Srgrimes#include <string.h> 491573Srgrimes#include <stdlib.h> 501573Srgrimes#include <unistd.h> 519898Sache#include <termcap.h> 52148834Sstefanf#include <curses.h> 53148834Sstefanf#include <ncurses.h> 54148834Sstefanf#include <term.h> 551573Srgrimes#include <sys/types.h> 5617141Sjkh#include <sys/ioctl.h> 571573Srgrimes 581573Srgrimes#include "el.h" 591573Srgrimes 601573Srgrimes/* 611573Srgrimes * IMPORTANT NOTE: these routines are allowed to look at the current screen 621573Srgrimes * and the current possition assuming that it is correct. If this is not 631573Srgrimes * true, then the update will be WRONG! This is (should be) a valid 641573Srgrimes * assumption... 651573Srgrimes */ 661573Srgrimes 6784260Sobrien#define TC_BUFSIZE 2048 681573Srgrimes 6984260Sobrien#define GoodStr(a) (el->el_term.t_str[a] != NULL && \ 7084260Sobrien el->el_term.t_str[a][0] != '\0') 7184260Sobrien#define Str(a) el->el_term.t_str[a] 7284260Sobrien#define Val(a) el->el_term.t_val[a] 731573Srgrimes 7484260Sobrien#ifdef notdef 7584260Sobrienprivate const struct { 7684260Sobrien const char *b_name; 7784260Sobrien int b_rate; 7884260Sobrien} baud_rate[] = { 7984260Sobrien#ifdef B0 8084260Sobrien { "0", B0 }, 8184260Sobrien#endif 8284260Sobrien#ifdef B50 8384260Sobrien { "50", B50 }, 8484260Sobrien#endif 8584260Sobrien#ifdef B75 8684260Sobrien { "75", B75 }, 8784260Sobrien#endif 8884260Sobrien#ifdef B110 8984260Sobrien { "110", B110 }, 9084260Sobrien#endif 9184260Sobrien#ifdef B134 9284260Sobrien { "134", B134 }, 9384260Sobrien#endif 9484260Sobrien#ifdef B150 9584260Sobrien { "150", B150 }, 9684260Sobrien#endif 9784260Sobrien#ifdef B200 9884260Sobrien { "200", B200 }, 9984260Sobrien#endif 10084260Sobrien#ifdef B300 10184260Sobrien { "300", B300 }, 10284260Sobrien#endif 10384260Sobrien#ifdef B600 10484260Sobrien { "600", B600 }, 10584260Sobrien#endif 10684260Sobrien#ifdef B900 10784260Sobrien { "900", B900 }, 10884260Sobrien#endif 10984260Sobrien#ifdef B1200 11084260Sobrien { "1200", B1200 }, 11184260Sobrien#endif 11284260Sobrien#ifdef B1800 11384260Sobrien { "1800", B1800 }, 11484260Sobrien#endif 11584260Sobrien#ifdef B2400 11684260Sobrien { "2400", B2400 }, 11784260Sobrien#endif 11884260Sobrien#ifdef B3600 11984260Sobrien { "3600", B3600 }, 12084260Sobrien#endif 12184260Sobrien#ifdef B4800 12284260Sobrien { "4800", B4800 }, 12384260Sobrien#endif 12484260Sobrien#ifdef B7200 12584260Sobrien { "7200", B7200 }, 12684260Sobrien#endif 12784260Sobrien#ifdef B9600 12884260Sobrien { "9600", B9600 }, 12984260Sobrien#endif 13084260Sobrien#ifdef EXTA 13184260Sobrien { "19200", EXTA }, 13284260Sobrien#endif 13384260Sobrien#ifdef B19200 13484260Sobrien { "19200", B19200 }, 13584260Sobrien#endif 13684260Sobrien#ifdef EXTB 13784260Sobrien { "38400", EXTB }, 13884260Sobrien#endif 13984260Sobrien#ifdef B38400 14084260Sobrien { "38400", B38400 }, 14184260Sobrien#endif 14284260Sobrien { NULL, 0 } 14384260Sobrien}; 14484260Sobrien#endif 14584260Sobrien 14684260Sobrienprivate const struct termcapstr { 14784260Sobrien const char *name; 14884260Sobrien const char *long_name; 1491573Srgrimes} tstr[] = { 15084260Sobrien#define T_al 0 15184260Sobrien { "al", "add new blank line" }, 15284260Sobrien#define T_bl 1 15384260Sobrien { "bl", "audible bell" }, 15484260Sobrien#define T_cd 2 15584260Sobrien { "cd", "clear to bottom" }, 15684260Sobrien#define T_ce 3 15784260Sobrien { "ce", "clear to end of line" }, 15884260Sobrien#define T_ch 4 15984260Sobrien { "ch", "cursor to horiz pos" }, 16084260Sobrien#define T_cl 5 16184260Sobrien { "cl", "clear screen" }, 1621573Srgrimes#define T_dc 6 16384260Sobrien { "dc", "delete a character" }, 1641573Srgrimes#define T_dl 7 16584260Sobrien { "dl", "delete a line" }, 1661573Srgrimes#define T_dm 8 16784260Sobrien { "dm", "start delete mode" }, 1681573Srgrimes#define T_ed 9 16984260Sobrien { "ed", "end delete mode" }, 1701573Srgrimes#define T_ei 10 17184260Sobrien { "ei", "end insert mode" }, 1721573Srgrimes#define T_fs 11 17384260Sobrien { "fs", "cursor from status line" }, 1741573Srgrimes#define T_ho 12 17584260Sobrien { "ho", "home cursor" }, 1761573Srgrimes#define T_ic 13 17784260Sobrien { "ic", "insert character" }, 1788870Srgrimes#define T_im 14 17984260Sobrien { "im", "start insert mode" }, 1801573Srgrimes#define T_ip 15 18184260Sobrien { "ip", "insert padding" }, 1821573Srgrimes#define T_kd 16 18384260Sobrien { "kd", "sends cursor down" }, 1841573Srgrimes#define T_kl 17 18584260Sobrien { "kl", "sends cursor left" }, 18684260Sobrien#define T_kr 18 18784260Sobrien { "kr", "sends cursor right" }, 18884260Sobrien#define T_ku 19 18984260Sobrien { "ku", "sends cursor up" }, 19084260Sobrien#define T_md 20 19184260Sobrien { "md", "begin bold" }, 19284260Sobrien#define T_me 21 19384260Sobrien { "me", "end attributes" }, 19484260Sobrien#define T_nd 22 19584260Sobrien { "nd", "non destructive space" }, 19684260Sobrien#define T_se 23 19784260Sobrien { "se", "end standout" }, 19884260Sobrien#define T_so 24 19984260Sobrien { "so", "begin standout" }, 20084260Sobrien#define T_ts 25 20184260Sobrien { "ts", "cursor to status line" }, 20284260Sobrien#define T_up 26 20384260Sobrien { "up", "cursor up one" }, 20484260Sobrien#define T_us 27 20584260Sobrien { "us", "begin underline" }, 20684260Sobrien#define T_ue 28 20784260Sobrien { "ue", "end underline" }, 20884260Sobrien#define T_vb 29 20984260Sobrien { "vb", "visible bell" }, 21084260Sobrien#define T_DC 30 21184260Sobrien { "DC", "delete multiple chars" }, 21284260Sobrien#define T_DO 31 21384260Sobrien { "DO", "cursor down multiple" }, 21484260Sobrien#define T_IC 32 21584260Sobrien { "IC", "insert multiple chars" }, 21684260Sobrien#define T_LE 33 21784260Sobrien { "LE", "cursor left multiple" }, 21884260Sobrien#define T_RI 34 21984260Sobrien { "RI", "cursor right multiple" }, 22084260Sobrien#define T_UP 35 22184260Sobrien { "UP", "cursor up multiple" }, 22284260Sobrien#define T_kh 36 22384260Sobrien { "kh", "send cursor home" }, 22484260Sobrien#define T_at7 37 22584260Sobrien { "@7", "send cursor end" }, 226212235Sjilles#define T_kD 38 227212235Sjilles { "kD", "send cursor delete" }, 228212235Sjilles#define T_str 39 22984260Sobrien { NULL, NULL } 2301573Srgrimes}; 2311573Srgrimes 23284260Sobrienprivate const struct termcapval { 23384260Sobrien const char *name; 23484260Sobrien const char *long_name; 2351573Srgrimes} tval[] = { 23684260Sobrien#define T_am 0 23784260Sobrien { "am", "has automatic margins" }, 23884260Sobrien#define T_pt 1 23984260Sobrien { "pt", "has physical tabs" }, 24084260Sobrien#define T_li 2 24184260Sobrien { "li", "Number of lines" }, 24284260Sobrien#define T_co 3 24384260Sobrien { "co", "Number of columns" }, 24484260Sobrien#define T_km 4 24584260Sobrien { "km", "Has meta key" }, 24684260Sobrien#define T_xt 5 24784260Sobrien { "xt", "Tab chars destructive" }, 24884260Sobrien#define T_xn 6 24984260Sobrien { "xn", "newline ignored at right margin" }, 25084260Sobrien#define T_MT 7 25184260Sobrien { "MT", "Has meta key" }, /* XXX? */ 25284260Sobrien#define T_val 8 25384260Sobrien { NULL, NULL, } 2541573Srgrimes}; 2551573Srgrimes/* do two or more of the attributes use me */ 2561573Srgrimes 25784260Sobrienprivate void term_setflags(EditLine *); 25884260Sobrienprivate int term_rebuffer_display(EditLine *); 25984260Sobrienprivate void term_free_display(EditLine *); 26084260Sobrienprivate int term_alloc_display(EditLine *); 261148834Sstefanfprivate void term_alloc(EditLine *, const struct termcapstr *, const char *); 26284260Sobrienprivate void term_init_arrow(EditLine *); 26384260Sobrienprivate void term_reset_arrow(EditLine *); 264237448Spfgprivate int term_putc(int); 265237448Spfgprivate void term_tputs(EditLine *, const char *, int); 2661573Srgrimes 267237448Spfg#ifdef _REENTRANT 268237448Spfgprivate pthread_mutex_t term_mutex = PTHREAD_MUTEX_INITIALIZER; 269237448Spfg#endif 270237448Spfgprivate FILE *term_outfile = NULL; 2711573Srgrimes 2721573Srgrimes 2731573Srgrimes/* term_setflags(): 2741573Srgrimes * Set the terminal capability flags 2751573Srgrimes */ 2761573Srgrimesprivate void 27784260Sobrienterm_setflags(EditLine *el) 2781573Srgrimes{ 27984260Sobrien EL_FLAGS = 0; 28084260Sobrien if (el->el_tty.t_tabs) 28184260Sobrien EL_FLAGS |= (Val(T_pt) && !Val(T_xt)) ? TERM_CAN_TAB : 0; 2821573Srgrimes 28384260Sobrien EL_FLAGS |= (Val(T_km) || Val(T_MT)) ? TERM_HAS_META : 0; 28484260Sobrien EL_FLAGS |= GoodStr(T_ce) ? TERM_CAN_CEOL : 0; 28584260Sobrien EL_FLAGS |= (GoodStr(T_dc) || GoodStr(T_DC)) ? TERM_CAN_DELETE : 0; 28684260Sobrien EL_FLAGS |= (GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC)) ? 28784260Sobrien TERM_CAN_INSERT : 0; 28884260Sobrien EL_FLAGS |= (GoodStr(T_up) || GoodStr(T_UP)) ? TERM_CAN_UP : 0; 28984260Sobrien EL_FLAGS |= Val(T_am) ? TERM_HAS_AUTO_MARGINS : 0; 29084260Sobrien EL_FLAGS |= Val(T_xn) ? TERM_HAS_MAGIC_MARGINS : 0; 2911573Srgrimes 29284260Sobrien if (GoodStr(T_me) && GoodStr(T_ue)) 29384260Sobrien EL_FLAGS |= (strcmp(Str(T_me), Str(T_ue)) == 0) ? 29484260Sobrien TERM_CAN_ME : 0; 29584260Sobrien else 29684260Sobrien EL_FLAGS &= ~TERM_CAN_ME; 29784260Sobrien if (GoodStr(T_me) && GoodStr(T_se)) 29884260Sobrien EL_FLAGS |= (strcmp(Str(T_me), Str(T_se)) == 0) ? 29984260Sobrien TERM_CAN_ME : 0; 3001573Srgrimes 3011573Srgrimes 3021573Srgrimes#ifdef DEBUG_SCREEN 30384260Sobrien if (!EL_CAN_UP) { 30484260Sobrien (void) fprintf(el->el_errfile, 30584260Sobrien "WARNING: Your terminal cannot move up.\n"); 30684260Sobrien (void) fprintf(el->el_errfile, 30784260Sobrien "Editing may be odd for long lines.\n"); 30884260Sobrien } 30984260Sobrien if (!EL_CAN_CEOL) 31084260Sobrien (void) fprintf(el->el_errfile, "no clear EOL capability.\n"); 31184260Sobrien if (!EL_CAN_DELETE) 31284260Sobrien (void) fprintf(el->el_errfile, "no delete char capability.\n"); 31384260Sobrien if (!EL_CAN_INSERT) 31484260Sobrien (void) fprintf(el->el_errfile, "no insert char capability.\n"); 3151573Srgrimes#endif /* DEBUG_SCREEN */ 3161573Srgrimes} 3171573Srgrimes 3181573Srgrimes/* term_init(): 3191573Srgrimes * Initialize the terminal stuff 3201573Srgrimes */ 3211573Srgrimesprotected int 32284260Sobrienterm_init(EditLine *el) 3231573Srgrimes{ 32484260Sobrien 32584260Sobrien el->el_term.t_buf = (char *) el_malloc(TC_BUFSIZE); 32684260Sobrien if (el->el_term.t_buf == NULL) 32784260Sobrien return (-1); 32884260Sobrien el->el_term.t_cap = (char *) el_malloc(TC_BUFSIZE); 32984260Sobrien if (el->el_term.t_cap == NULL) 33084260Sobrien return (-1); 33184260Sobrien el->el_term.t_fkey = (fkey_t *) el_malloc(A_K_NKEYS * sizeof(fkey_t)); 33284260Sobrien if (el->el_term.t_fkey == NULL) 33384260Sobrien return (-1); 33484260Sobrien el->el_term.t_loc = 0; 33584260Sobrien el->el_term.t_str = (char **) el_malloc(T_str * sizeof(char *)); 33684260Sobrien if (el->el_term.t_str == NULL) 33784260Sobrien return (-1); 33884260Sobrien (void) memset(el->el_term.t_str, 0, T_str * sizeof(char *)); 33984260Sobrien el->el_term.t_val = (int *) el_malloc(T_val * sizeof(int)); 34084260Sobrien if (el->el_term.t_val == NULL) 34184260Sobrien return (-1); 34284260Sobrien (void) memset(el->el_term.t_val, 0, T_val * sizeof(int)); 343238810Spfg (void) term_set(el, NULL); 34489735Sobrien term_init_arrow(el); 34584260Sobrien return (0); 3461573Srgrimes} 347148834Sstefanf 3481573Srgrimes/* term_end(): 3491573Srgrimes * Clean up the terminal stuff 3501573Srgrimes */ 3511573Srgrimesprotected void 35284260Sobrienterm_end(EditLine *el) 3531573Srgrimes{ 35484260Sobrien 35584260Sobrien el_free((ptr_t) el->el_term.t_buf); 35684260Sobrien el->el_term.t_buf = NULL; 35784260Sobrien el_free((ptr_t) el->el_term.t_cap); 35884260Sobrien el->el_term.t_cap = NULL; 35984260Sobrien el->el_term.t_loc = 0; 36084260Sobrien el_free((ptr_t) el->el_term.t_str); 36184260Sobrien el->el_term.t_str = NULL; 36284260Sobrien el_free((ptr_t) el->el_term.t_val); 36384260Sobrien el->el_term.t_val = NULL; 364148834Sstefanf el_free((ptr_t) el->el_term.t_fkey); 365148834Sstefanf el->el_term.t_fkey = NULL; 36684260Sobrien term_free_display(el); 3671573Srgrimes} 3681573Srgrimes 3691573Srgrimes 3701573Srgrimes/* term_alloc(): 3711573Srgrimes * Maintain a string pool for termcap strings 3721573Srgrimes */ 3731573Srgrimesprivate void 374148834Sstefanfterm_alloc(EditLine *el, const struct termcapstr *t, const char *cap) 3751573Srgrimes{ 37684260Sobrien char termbuf[TC_BUFSIZE]; 377237448Spfg size_t tlen, clen; 37884260Sobrien char **tlist = el->el_term.t_str; 37984260Sobrien char **tmp, **str = &tlist[t - tstr]; 3801573Srgrimes 38184260Sobrien if (cap == NULL || *cap == '\0') { 38284260Sobrien *str = NULL; 38384260Sobrien return; 38484260Sobrien } else 38584260Sobrien clen = strlen(cap); 3861573Srgrimes 38784260Sobrien tlen = *str == NULL ? 0 : strlen(*str); 3881573Srgrimes 38984260Sobrien /* 39084260Sobrien * New string is shorter; no need to allocate space 39184260Sobrien */ 39284260Sobrien if (clen <= tlen) { 393167457Sstefanf if (*str) 394167457Sstefanf (void) strcpy(*str, cap); /* XXX strcpy is safe */ 39584260Sobrien return; 39684260Sobrien } 39784260Sobrien /* 39884260Sobrien * New string is longer; see if we have enough space to append 39984260Sobrien */ 40084260Sobrien if (el->el_term.t_loc + 3 < TC_BUFSIZE) { 40184260Sobrien /* XXX strcpy is safe */ 40284260Sobrien (void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], 40384260Sobrien cap); 404237448Spfg el->el_term.t_loc += (int)clen + 1; /* one for \0 */ 40584260Sobrien return; 40684260Sobrien } 40784260Sobrien /* 40884260Sobrien * Compact our buffer; no need to check compaction, cause we know it 40984260Sobrien * fits... 41084260Sobrien */ 41184260Sobrien tlen = 0; 41284260Sobrien for (tmp = tlist; tmp < &tlist[T_str]; tmp++) 41384260Sobrien if (*tmp != NULL && *tmp != '\0' && *tmp != *str) { 41484260Sobrien char *ptr; 4151573Srgrimes 41684260Sobrien for (ptr = *tmp; *ptr != '\0'; termbuf[tlen++] = *ptr++) 41784260Sobrien continue; 41884260Sobrien termbuf[tlen++] = '\0'; 41984260Sobrien } 42084260Sobrien memcpy(el->el_term.t_buf, termbuf, TC_BUFSIZE); 421237448Spfg el->el_term.t_loc = (int)tlen; 42284260Sobrien if (el->el_term.t_loc + 3 >= TC_BUFSIZE) { 42384260Sobrien (void) fprintf(el->el_errfile, 42484260Sobrien "Out of termcap string space.\n"); 42584260Sobrien return; 42684260Sobrien } 42784260Sobrien /* XXX strcpy is safe */ 42884260Sobrien (void) strcpy(*str = &el->el_term.t_buf[el->el_term.t_loc], cap); 429237448Spfg el->el_term.t_loc += (int)clen + 1; /* one for \0 */ 4301573Srgrimes return; 43184260Sobrien} 4321573Srgrimes 4331573Srgrimes 4341573Srgrimes/* term_rebuffer_display(): 4351573Srgrimes * Rebuffer the display after the screen changed size 4361573Srgrimes */ 43784260Sobrienprivate int 43884260Sobrienterm_rebuffer_display(EditLine *el) 4391573Srgrimes{ 44084260Sobrien coord_t *c = &el->el_term.t_size; 4411573Srgrimes 44284260Sobrien term_free_display(el); 4431573Srgrimes 44484260Sobrien c->h = Val(T_co); 44584260Sobrien c->v = Val(T_li); 4461573Srgrimes 44784260Sobrien if (term_alloc_display(el) == -1) 44884260Sobrien return (-1); 44984260Sobrien return (0); 45084260Sobrien} 4511573Srgrimes 4521573Srgrimes 4531573Srgrimes/* term_alloc_display(): 4541573Srgrimes * Allocate a new display. 4551573Srgrimes */ 45684260Sobrienprivate int 45784260Sobrienterm_alloc_display(EditLine *el) 4581573Srgrimes{ 45984260Sobrien int i; 46084260Sobrien char **b; 46184260Sobrien coord_t *c = &el->el_term.t_size; 4621573Srgrimes 46384260Sobrien b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1))); 46484260Sobrien if (b == NULL) 46584260Sobrien return (-1); 46684260Sobrien for (i = 0; i < c->v; i++) { 46784260Sobrien b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); 468167457Sstefanf if (b[i] == NULL) { 469167457Sstefanf while (--i >= 0) 470167457Sstefanf el_free((ptr_t) b[i]); 471167457Sstefanf el_free((ptr_t) b); 47284260Sobrien return (-1); 473167457Sstefanf } 47484260Sobrien } 47584260Sobrien b[c->v] = NULL; 47684260Sobrien el->el_display = b; 4771573Srgrimes 47884260Sobrien b = (char **) el_malloc((size_t) (sizeof(char *) * (c->v + 1))); 47984260Sobrien if (b == NULL) 48084260Sobrien return (-1); 48184260Sobrien for (i = 0; i < c->v; i++) { 48284260Sobrien b[i] = (char *) el_malloc((size_t) (sizeof(char) * (c->h + 1))); 483167457Sstefanf if (b[i] == NULL) { 484167457Sstefanf while (--i >= 0) 485167457Sstefanf el_free((ptr_t) b[i]); 486167457Sstefanf el_free((ptr_t) b); 48784260Sobrien return (-1); 488167457Sstefanf } 48984260Sobrien } 49084260Sobrien b[c->v] = NULL; 49184260Sobrien el->el_vdisplay = b; 49284260Sobrien return (0); 49384260Sobrien} 4941573Srgrimes 4951573Srgrimes 4961573Srgrimes/* term_free_display(): 4971573Srgrimes * Free the display buffers 4981573Srgrimes */ 4991573Srgrimesprivate void 50084260Sobrienterm_free_display(EditLine *el) 5011573Srgrimes{ 50284260Sobrien char **b; 50384260Sobrien char **bufp; 5041573Srgrimes 50584260Sobrien b = el->el_display; 50684260Sobrien el->el_display = NULL; 50784260Sobrien if (b != NULL) { 50884260Sobrien for (bufp = b; *bufp != NULL; bufp++) 50984260Sobrien el_free((ptr_t) * bufp); 51084260Sobrien el_free((ptr_t) b); 51184260Sobrien } 51284260Sobrien b = el->el_vdisplay; 51384260Sobrien el->el_vdisplay = NULL; 51484260Sobrien if (b != NULL) { 51584260Sobrien for (bufp = b; *bufp != NULL; bufp++) 51684260Sobrien el_free((ptr_t) * bufp); 51784260Sobrien el_free((ptr_t) b); 51884260Sobrien } 51984260Sobrien} 5201573Srgrimes 5211573Srgrimes 5221573Srgrimes/* term_move_to_line(): 5231573Srgrimes * move to line <where> (first line == 0) 5241573Srgrimes * as efficiently as possible 5251573Srgrimes */ 5261573Srgrimesprotected void 52784260Sobrienterm_move_to_line(EditLine *el, int where) 5281573Srgrimes{ 52984260Sobrien int del; 5301573Srgrimes 53184260Sobrien if (where == el->el_cursor.v) 53284260Sobrien return; 5331573Srgrimes 53484260Sobrien if (where > el->el_term.t_size.v) { 5351573Srgrimes#ifdef DEBUG_SCREEN 53684260Sobrien (void) fprintf(el->el_errfile, 53784260Sobrien "term_move_to_line: where is ridiculous: %d\r\n", where); 5381573Srgrimes#endif /* DEBUG_SCREEN */ 53984260Sobrien return; 5401573Srgrimes } 54184260Sobrien if ((del = where - el->el_cursor.v) > 0) { 54284260Sobrien while (del > 0) { 54384260Sobrien if (EL_HAS_AUTO_MARGINS && 54484260Sobrien el->el_display[el->el_cursor.v][0] != '\0') { 54584260Sobrien /* move without newline */ 54684260Sobrien term_move_to_char(el, el->el_term.t_size.h - 1); 547237448Spfg term_overwrite(el, &el->el_display 548237448Spfg [el->el_cursor.v][el->el_cursor.h], 549237448Spfg (size_t)(el->el_term.t_size.h - 550237448Spfg el->el_cursor.h)); 55184260Sobrien /* updates Cursor */ 55284260Sobrien del--; 55384260Sobrien } else { 55484260Sobrien if ((del > 1) && GoodStr(T_DO)) { 555237448Spfg term_tputs(el, tgoto(Str(T_DO), del, 556237448Spfg del), del); 55784260Sobrien del = 0; 55884260Sobrien } else { 55984260Sobrien for (; del > 0; del--) 560237448Spfg term__putc(el, '\n'); 56184260Sobrien /* because the \n will become \r\n */ 56284260Sobrien el->el_cursor.h = 0; 56384260Sobrien } 56484260Sobrien } 56584260Sobrien } 56684260Sobrien } else { /* del < 0 */ 56784260Sobrien if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up))) 568237448Spfg term_tputs(el, tgoto(Str(T_UP), -del, -del), -del); 56984260Sobrien else { 57084260Sobrien if (GoodStr(T_up)) 57184260Sobrien for (; del < 0; del++) 572237448Spfg term_tputs(el, Str(T_up), 1); 57384260Sobrien } 5741573Srgrimes } 57584260Sobrien el->el_cursor.v = where;/* now where is here */ 57684260Sobrien} 5771573Srgrimes 5781573Srgrimes 5791573Srgrimes/* term_move_to_char(): 5801573Srgrimes * Move to the character position specified 5811573Srgrimes */ 5821573Srgrimesprotected void 58384260Sobrienterm_move_to_char(EditLine *el, int where) 5841573Srgrimes{ 58584260Sobrien int del, i; 5861573Srgrimes 5871573Srgrimesmc_again: 58884260Sobrien if (where == el->el_cursor.h) 58984260Sobrien return; 5901573Srgrimes 59184260Sobrien if (where > el->el_term.t_size.h) { 5921573Srgrimes#ifdef DEBUG_SCREEN 59384260Sobrien (void) fprintf(el->el_errfile, 59484260Sobrien "term_move_to_char: where is riduculous: %d\r\n", where); 5951573Srgrimes#endif /* DEBUG_SCREEN */ 59684260Sobrien return; 59784260Sobrien } 59884260Sobrien if (!where) { /* if where is first column */ 599237448Spfg term__putc(el, '\r'); /* do a CR */ 60084260Sobrien el->el_cursor.h = 0; 60184260Sobrien return; 60284260Sobrien } 60384260Sobrien del = where - el->el_cursor.h; 6041573Srgrimes 60584260Sobrien if ((del < -4 || del > 4) && GoodStr(T_ch)) 60684260Sobrien /* go there directly */ 607237448Spfg term_tputs(el, tgoto(Str(T_ch), where, where), where); 60884260Sobrien else { 60984260Sobrien if (del > 0) { /* moving forward */ 61084260Sobrien if ((del > 4) && GoodStr(T_RI)) 611237448Spfg term_tputs(el, tgoto(Str(T_RI), del, del), del); 61284260Sobrien else { 61384260Sobrien /* if I can do tabs, use them */ 61484260Sobrien if (EL_CAN_TAB) { 61584260Sobrien if ((el->el_cursor.h & 0370) != 616237448Spfg (where & ~0x7)) { 61784260Sobrien /* if not within tab stop */ 61884260Sobrien for (i = 61984260Sobrien (el->el_cursor.h & 0370); 620237448Spfg i < (where & ~0x7); 62184260Sobrien i += 8) 622237448Spfg term__putc(el, '\t'); 62384260Sobrien /* then tab over */ 624237448Spfg el->el_cursor.h = where & ~0x7; 62584260Sobrien } 62684260Sobrien } 62784260Sobrien /* 62884260Sobrien * it's usually cheaper to just write the 62984260Sobrien * chars, so we do. 63084260Sobrien */ 63184260Sobrien /* 63284260Sobrien * NOTE THAT term_overwrite() WILL CHANGE 63384260Sobrien * el->el_cursor.h!!! 63484260Sobrien */ 635237448Spfg term_overwrite(el, &el->el_display[ 636237448Spfg el->el_cursor.v][el->el_cursor.h], 637237448Spfg (size_t)(where - el->el_cursor.h)); 6381573Srgrimes 63984260Sobrien } 64084260Sobrien } else { /* del < 0 := moving backward */ 64184260Sobrien if ((-del > 4) && GoodStr(T_LE)) 642237448Spfg term_tputs(el, tgoto(Str(T_LE), -del, -del), 643237448Spfg -del); 64484260Sobrien else { /* can't go directly there */ 64584260Sobrien /* 64684260Sobrien * if the "cost" is greater than the "cost" 64784260Sobrien * from col 0 64884260Sobrien */ 64984260Sobrien if (EL_CAN_TAB ? 650148834Sstefanf ((unsigned int)-del > 651148834Sstefanf (((unsigned int) where >> 3) + 65284260Sobrien (where & 07))) 65384260Sobrien : (-del > where)) { 654237448Spfg term__putc(el, '\r'); /* do a CR */ 65584260Sobrien el->el_cursor.h = 0; 65684260Sobrien goto mc_again; /* and try again */ 65784260Sobrien } 65884260Sobrien for (i = 0; i < -del; i++) 659237448Spfg term__putc(el, '\b'); 66084260Sobrien } 6611573Srgrimes } 6621573Srgrimes } 66384260Sobrien el->el_cursor.h = where; /* now where is here */ 66484260Sobrien} 6651573Srgrimes 6661573Srgrimes 6671573Srgrimes/* term_overwrite(): 6681573Srgrimes * Overstrike num characters 6691573Srgrimes */ 6701573Srgrimesprotected void 671237448Spfgterm_overwrite(EditLine *el, const char *cp, size_t n) 6721573Srgrimes{ 673237448Spfg if (n == 0) 674237448Spfg return; 6751573Srgrimes 676237448Spfg if (n > (size_t)el->el_term.t_size.h) { 6771573Srgrimes#ifdef DEBUG_SCREEN 67884260Sobrien (void) fprintf(el->el_errfile, 67984260Sobrien "term_overwrite: n is riduculous: %d\r\n", n); 6801573Srgrimes#endif /* DEBUG_SCREEN */ 68184260Sobrien return; 68284260Sobrien } 683237448Spfg 68484260Sobrien do { 685237448Spfg term__putc(el, *cp++); 68684260Sobrien el->el_cursor.h++; 68784260Sobrien } while (--n); 6881573Srgrimes 68984260Sobrien if (el->el_cursor.h >= el->el_term.t_size.h) { /* wrap? */ 69084260Sobrien if (EL_HAS_AUTO_MARGINS) { /* yes */ 69184260Sobrien el->el_cursor.h = 0; 69284260Sobrien el->el_cursor.v++; 69384260Sobrien if (EL_HAS_MAGIC_MARGINS) { 69484260Sobrien /* force the wrap to avoid the "magic" 69584260Sobrien * situation */ 69684260Sobrien char c; 69784260Sobrien if ((c = el->el_display[el->el_cursor.v][el->el_cursor.h]) 69884260Sobrien != '\0') 69984260Sobrien term_overwrite(el, &c, 1); 700237448Spfg else { 701237448Spfg term__putc(el, ' '); 702237448Spfg el->el_cursor.h = 1; 703237448Spfg } 70484260Sobrien } 70584260Sobrien } else /* no wrap, but cursor stays on screen */ 706237448Spfg el->el_cursor.h = el->el_term.t_size.h - 1; 70784260Sobrien } 70884260Sobrien} 7091573Srgrimes 7101573Srgrimes 7111573Srgrimes/* term_deletechars(): 7121573Srgrimes * Delete num characters 7131573Srgrimes */ 7141573Srgrimesprotected void 71584260Sobrienterm_deletechars(EditLine *el, int num) 7161573Srgrimes{ 71784260Sobrien if (num <= 0) 71884260Sobrien return; 7191573Srgrimes 72084260Sobrien if (!EL_CAN_DELETE) { 7211573Srgrimes#ifdef DEBUG_EDIT 72284260Sobrien (void) fprintf(el->el_errfile, " ERROR: cannot delete \n"); 7231573Srgrimes#endif /* DEBUG_EDIT */ 72484260Sobrien return; 72584260Sobrien } 72684260Sobrien if (num > el->el_term.t_size.h) { 7271573Srgrimes#ifdef DEBUG_SCREEN 72884260Sobrien (void) fprintf(el->el_errfile, 72984260Sobrien "term_deletechars: num is riduculous: %d\r\n", num); 7301573Srgrimes#endif /* DEBUG_SCREEN */ 73184260Sobrien return; 7321573Srgrimes } 73384260Sobrien if (GoodStr(T_DC)) /* if I have multiple delete */ 73484260Sobrien if ((num > 1) || !GoodStr(T_dc)) { /* if dc would be more 73584260Sobrien * expen. */ 736237448Spfg term_tputs(el, tgoto(Str(T_DC), num, num), num); 73784260Sobrien return; 73884260Sobrien } 73984260Sobrien if (GoodStr(T_dm)) /* if I have delete mode */ 740237448Spfg term_tputs(el, Str(T_dm), 1); 7411573Srgrimes 74284260Sobrien if (GoodStr(T_dc)) /* else do one at a time */ 74384260Sobrien while (num--) 744237448Spfg term_tputs(el, Str(T_dc), 1); 7451573Srgrimes 74684260Sobrien if (GoodStr(T_ed)) /* if I have delete mode */ 747237448Spfg term_tputs(el, Str(T_ed), 1); 74884260Sobrien} 7491573Srgrimes 7501573Srgrimes 7511573Srgrimes/* term_insertwrite(): 7528870Srgrimes * Puts terminal in insert character mode or inserts num 7538870Srgrimes * characters in the line 7541573Srgrimes */ 7551573Srgrimesprotected void 75684260Sobrienterm_insertwrite(EditLine *el, char *cp, int num) 7571573Srgrimes{ 75884260Sobrien if (num <= 0) 75984260Sobrien return; 76084260Sobrien if (!EL_CAN_INSERT) { 7611573Srgrimes#ifdef DEBUG_EDIT 76284260Sobrien (void) fprintf(el->el_errfile, " ERROR: cannot insert \n"); 7631573Srgrimes#endif /* DEBUG_EDIT */ 76484260Sobrien return; 76584260Sobrien } 76684260Sobrien if (num > el->el_term.t_size.h) { 7671573Srgrimes#ifdef DEBUG_SCREEN 76884260Sobrien (void) fprintf(el->el_errfile, 76984260Sobrien "StartInsert: num is riduculous: %d\r\n", num); 7701573Srgrimes#endif /* DEBUG_SCREEN */ 77184260Sobrien return; 7721573Srgrimes } 77384260Sobrien if (GoodStr(T_IC)) /* if I have multiple insert */ 77484260Sobrien if ((num > 1) || !GoodStr(T_ic)) { 77584260Sobrien /* if ic would be more expensive */ 776237448Spfg term_tputs(el, tgoto(Str(T_IC), num, num), num); 777237448Spfg term_overwrite(el, cp, (size_t)num); 77884260Sobrien /* this updates el_cursor.h */ 77984260Sobrien return; 78084260Sobrien } 78184260Sobrien if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */ 782237448Spfg term_tputs(el, Str(T_im), 1); 7831573Srgrimes 78484260Sobrien el->el_cursor.h += num; 78584260Sobrien do 786237448Spfg term__putc(el, *cp++); 78784260Sobrien while (--num); 7881573Srgrimes 78984260Sobrien if (GoodStr(T_ip)) /* have to make num chars insert */ 790237448Spfg term_tputs(el, Str(T_ip), 1); 7911573Srgrimes 792237448Spfg term_tputs(el, Str(T_ei), 1); 79384260Sobrien return; 79484260Sobrien } 79584260Sobrien do { 79684260Sobrien if (GoodStr(T_ic)) /* have to make num chars insert */ 797237448Spfg term_tputs(el, Str(T_ic), 1); 7981573Srgrimes 799237448Spfg term__putc(el, *cp++); 8001573Srgrimes 80184260Sobrien el->el_cursor.h++; 8021573Srgrimes 80384260Sobrien if (GoodStr(T_ip)) /* have to make num chars insert */ 804237448Spfg term_tputs(el, Str(T_ip), 1); 80584260Sobrien /* pad the inserted char */ 8061573Srgrimes 80784260Sobrien } while (--num); 80884260Sobrien} 8091573Srgrimes 8101573Srgrimes 8111573Srgrimes/* term_clear_EOL(): 8128870Srgrimes * clear to end of line. There are num characters to clear 8131573Srgrimes */ 8141573Srgrimesprotected void 81584260Sobrienterm_clear_EOL(EditLine *el, int num) 8161573Srgrimes{ 81784260Sobrien int i; 8181573Srgrimes 81984260Sobrien if (EL_CAN_CEOL && GoodStr(T_ce)) 820237448Spfg term_tputs(el, Str(T_ce), 1); 82184260Sobrien else { 82284260Sobrien for (i = 0; i < num; i++) 823237448Spfg term__putc(el, ' '); 82484260Sobrien el->el_cursor.h += num; /* have written num spaces */ 82584260Sobrien } 82684260Sobrien} 8271573Srgrimes 8281573Srgrimes 8291573Srgrimes/* term_clear_screen(): 8308870Srgrimes * Clear the screen 8311573Srgrimes */ 8321573Srgrimesprotected void 83384260Sobrienterm_clear_screen(EditLine *el) 8341573Srgrimes{ /* clear the whole screen and home */ 8351573Srgrimes 83684260Sobrien if (GoodStr(T_cl)) 83784260Sobrien /* send the clear screen code */ 838237448Spfg term_tputs(el, Str(T_cl), Val(T_li)); 83984260Sobrien else if (GoodStr(T_ho) && GoodStr(T_cd)) { 840237448Spfg term_tputs(el, Str(T_ho), Val(T_li)); /* home */ 84184260Sobrien /* clear to bottom of screen */ 842237448Spfg term_tputs(el, Str(T_cd), Val(T_li)); 84384260Sobrien } else { 844237448Spfg term__putc(el, '\r'); 845237448Spfg term__putc(el, '\n'); 84684260Sobrien } 84784260Sobrien} 8481573Srgrimes 84984260Sobrien 8501573Srgrimes/* term_beep(): 8511573Srgrimes * Beep the way the terminal wants us 8521573Srgrimes */ 8531573Srgrimesprotected void 85484260Sobrienterm_beep(EditLine *el) 8551573Srgrimes{ 85684260Sobrien if (GoodStr(T_bl)) 85784260Sobrien /* what termcap says we should use */ 858237448Spfg term_tputs(el, Str(T_bl), 1); 85984260Sobrien else 860237448Spfg term__putc(el, '\007'); /* an ASCII bell; ^G */ 86184260Sobrien} 8621573Srgrimes 8631573Srgrimes 8641573Srgrimes#ifdef notdef 8651573Srgrimes/* term_clear_to_bottom(): 8661573Srgrimes * Clear to the bottom of the screen 8671573Srgrimes */ 8681573Srgrimesprotected void 86984260Sobrienterm_clear_to_bottom(EditLine *el) 8701573Srgrimes{ 87184260Sobrien if (GoodStr(T_cd)) 872237448Spfg term_tputs(el, Str(T_cd), Val(T_li)); 87384260Sobrien else if (GoodStr(T_ce)) 874237448Spfg term_tputs(el, Str(T_ce), Val(T_li)); 87584260Sobrien} 8761573Srgrimes#endif 8771573Srgrimes 878148834Sstefanfprotected void 879148834Sstefanfterm_get(EditLine *el, const char **term) 880148834Sstefanf{ 881148834Sstefanf *term = el->el_term.t_name; 882148834Sstefanf} 8831573Srgrimes 884148834Sstefanf 8851573Srgrimes/* term_set(): 8861573Srgrimes * Read in the terminal capabilities from the requested terminal 8871573Srgrimes */ 8881573Srgrimesprotected int 889148834Sstefanfterm_set(EditLine *el, const char *term) 8901573Srgrimes{ 89184260Sobrien int i; 89284260Sobrien char buf[TC_BUFSIZE]; 89384260Sobrien char *area; 89484260Sobrien const struct termcapstr *t; 89584260Sobrien sigset_t oset, nset; 89684260Sobrien int lins, cols; 8971573Srgrimes 89884260Sobrien (void) sigemptyset(&nset); 89984260Sobrien (void) sigaddset(&nset, SIGWINCH); 90084260Sobrien (void) sigprocmask(SIG_BLOCK, &nset, &oset); 9011573Srgrimes 90284260Sobrien area = buf; 9031573Srgrimes 9041573Srgrimes 90584260Sobrien if (term == NULL) 90684260Sobrien term = getenv("TERM"); 9071573Srgrimes 90884260Sobrien if (!term || !term[0]) 90984260Sobrien term = "dumb"; 9101573Srgrimes 91184260Sobrien if (strcmp(term, "emacs") == 0) 91284260Sobrien el->el_flags |= EDIT_DISABLED; 9131573Srgrimes 91484260Sobrien memset(el->el_term.t_cap, 0, TC_BUFSIZE); 9151573Srgrimes 91684260Sobrien i = tgetent(el->el_term.t_cap, term); 9171573Srgrimes 91884260Sobrien if (i <= 0) { 91984260Sobrien if (i == -1) 92084260Sobrien (void) fprintf(el->el_errfile, 92184260Sobrien "Cannot read termcap database;\n"); 92284260Sobrien else if (i == 0) 92384260Sobrien (void) fprintf(el->el_errfile, 92484260Sobrien "No entry for terminal type \"%s\";\n", term); 92584260Sobrien (void) fprintf(el->el_errfile, 92684260Sobrien "using dumb terminal settings.\n"); 92784260Sobrien Val(T_co) = 80; /* do a dumb terminal */ 92884260Sobrien Val(T_pt) = Val(T_km) = Val(T_li) = 0; 92984260Sobrien Val(T_xt) = Val(T_MT); 93084260Sobrien for (t = tstr; t->name != NULL; t++) 93184260Sobrien term_alloc(el, t, NULL); 93284260Sobrien } else { 93384260Sobrien /* auto/magic margins */ 93484260Sobrien Val(T_am) = tgetflag("am"); 93584260Sobrien Val(T_xn) = tgetflag("xn"); 93684260Sobrien /* Can we tab */ 93784260Sobrien Val(T_pt) = tgetflag("pt"); 93884260Sobrien Val(T_xt) = tgetflag("xt"); 93984260Sobrien /* do we have a meta? */ 94084260Sobrien Val(T_km) = tgetflag("km"); 94184260Sobrien Val(T_MT) = tgetflag("MT"); 94284260Sobrien /* Get the size */ 94384260Sobrien Val(T_co) = tgetnum("co"); 94484260Sobrien Val(T_li) = tgetnum("li"); 945148834Sstefanf for (t = tstr; t->name != NULL; t++) { 946148848Sstefanf /* XXX: some systems' tgetstr needs non const */ 947148834Sstefanf term_alloc(el, t, tgetstr(strchr(t->name, *t->name), 948148834Sstefanf &area)); 949148834Sstefanf } 95084260Sobrien } 9511573Srgrimes 95284260Sobrien if (Val(T_co) < 2) 95384260Sobrien Val(T_co) = 80; /* just in case */ 95484260Sobrien if (Val(T_li) < 1) 95584260Sobrien Val(T_li) = 24; 9561573Srgrimes 95784260Sobrien el->el_term.t_size.v = Val(T_co); 95884260Sobrien el->el_term.t_size.h = Val(T_li); 9591573Srgrimes 96084260Sobrien term_setflags(el); 9611573Srgrimes 96284260Sobrien /* get the correct window size */ 96384260Sobrien (void) term_get_size(el, &lins, &cols); 96484260Sobrien if (term_change_size(el, lins, cols) == -1) 96584260Sobrien return (-1); 96684260Sobrien (void) sigprocmask(SIG_SETMASK, &oset, NULL); 96784260Sobrien term_bind_arrow(el); 968148834Sstefanf el->el_term.t_name = term; 96984260Sobrien return (i <= 0 ? -1 : 0); 97084260Sobrien} 9711573Srgrimes 97284260Sobrien 9731573Srgrimes/* term_get_size(): 9741573Srgrimes * Return the new window size in lines and cols, and 9758870Srgrimes * true if the size was changed. 9761573Srgrimes */ 9771573Srgrimesprotected int 97884260Sobrienterm_get_size(EditLine *el, int *lins, int *cols) 9791573Srgrimes{ 9801573Srgrimes 98184260Sobrien *cols = Val(T_co); 98284260Sobrien *lins = Val(T_li); 9831573Srgrimes 9841573Srgrimes#ifdef TIOCGWINSZ 98584260Sobrien { 98684260Sobrien struct winsize ws; 98784260Sobrien if (ioctl(el->el_infd, TIOCGWINSZ, (ioctl_t) & ws) != -1) { 98884260Sobrien if (ws.ws_col) 98984260Sobrien *cols = ws.ws_col; 99084260Sobrien if (ws.ws_row) 99184260Sobrien *lins = ws.ws_row; 99284260Sobrien } 9931573Srgrimes } 9941573Srgrimes#endif 9951573Srgrimes#ifdef TIOCGSIZE 99684260Sobrien { 99784260Sobrien struct ttysize ts; 99884260Sobrien if (ioctl(el->el_infd, TIOCGSIZE, (ioctl_t) & ts) != -1) { 99984260Sobrien if (ts.ts_cols) 100084260Sobrien *cols = ts.ts_cols; 100184260Sobrien if (ts.ts_lines) 100284260Sobrien *lins = ts.ts_lines; 100384260Sobrien } 10041573Srgrimes } 10051573Srgrimes#endif 100684260Sobrien return (Val(T_co) != *cols || Val(T_li) != *lins); 100784260Sobrien} 10081573Srgrimes 10091573Srgrimes 10101573Srgrimes/* term_change_size(): 10111573Srgrimes * Change the size of the terminal 10121573Srgrimes */ 101384260Sobrienprotected int 101484260Sobrienterm_change_size(EditLine *el, int lins, int cols) 10151573Srgrimes{ 101684260Sobrien /* 101784260Sobrien * Just in case 101884260Sobrien */ 101984260Sobrien Val(T_co) = (cols < 2) ? 80 : cols; 102084260Sobrien Val(T_li) = (lins < 1) ? 24 : lins; 10211573Srgrimes 102284260Sobrien /* re-make display buffers */ 102384260Sobrien if (term_rebuffer_display(el) == -1) 102484260Sobrien return (-1); 102584260Sobrien re_clear_display(el); 102684260Sobrien return (0); 102784260Sobrien} 10281573Srgrimes 10291573Srgrimes 10301573Srgrimes/* term_init_arrow(): 10311573Srgrimes * Initialize the arrow key bindings from termcap 10321573Srgrimes */ 10331573Srgrimesprivate void 103484260Sobrienterm_init_arrow(EditLine *el) 10351573Srgrimes{ 103684260Sobrien fkey_t *arrow = el->el_term.t_fkey; 10371573Srgrimes 103884260Sobrien arrow[A_K_DN].name = "down"; 103984260Sobrien arrow[A_K_DN].key = T_kd; 104084260Sobrien arrow[A_K_DN].fun.cmd = ED_NEXT_HISTORY; 104184260Sobrien arrow[A_K_DN].type = XK_CMD; 10421573Srgrimes 104384260Sobrien arrow[A_K_UP].name = "up"; 104484260Sobrien arrow[A_K_UP].key = T_ku; 104584260Sobrien arrow[A_K_UP].fun.cmd = ED_PREV_HISTORY; 104684260Sobrien arrow[A_K_UP].type = XK_CMD; 10471573Srgrimes 104884260Sobrien arrow[A_K_LT].name = "left"; 104984260Sobrien arrow[A_K_LT].key = T_kl; 105084260Sobrien arrow[A_K_LT].fun.cmd = ED_PREV_CHAR; 105184260Sobrien arrow[A_K_LT].type = XK_CMD; 10521573Srgrimes 105384260Sobrien arrow[A_K_RT].name = "right"; 105484260Sobrien arrow[A_K_RT].key = T_kr; 105584260Sobrien arrow[A_K_RT].fun.cmd = ED_NEXT_CHAR; 105684260Sobrien arrow[A_K_RT].type = XK_CMD; 10571573Srgrimes 105884260Sobrien arrow[A_K_HO].name = "home"; 105984260Sobrien arrow[A_K_HO].key = T_kh; 106084260Sobrien arrow[A_K_HO].fun.cmd = ED_MOVE_TO_BEG; 106184260Sobrien arrow[A_K_HO].type = XK_CMD; 106263948Sache 106384260Sobrien arrow[A_K_EN].name = "end"; 106484260Sobrien arrow[A_K_EN].key = T_at7; 106584260Sobrien arrow[A_K_EN].fun.cmd = ED_MOVE_TO_END; 106684260Sobrien arrow[A_K_EN].type = XK_CMD; 1067212235Sjilles 1068212235Sjilles arrow[A_K_DE].name = "delete"; 1069212235Sjilles arrow[A_K_DE].key = T_kD; 1070212235Sjilles arrow[A_K_DE].fun.cmd = ED_DELETE_NEXT_CHAR; 1071212235Sjilles arrow[A_K_DE].type = XK_CMD; 10721573Srgrimes} 10731573Srgrimes 10741573Srgrimes 10751573Srgrimes/* term_reset_arrow(): 10761573Srgrimes * Reset arrow key bindings 10771573Srgrimes */ 10781573Srgrimesprivate void 107984260Sobrienterm_reset_arrow(EditLine *el) 10801573Srgrimes{ 108184260Sobrien fkey_t *arrow = el->el_term.t_fkey; 108284260Sobrien static const char strA[] = {033, '[', 'A', '\0'}; 108384260Sobrien static const char strB[] = {033, '[', 'B', '\0'}; 108484260Sobrien static const char strC[] = {033, '[', 'C', '\0'}; 108584260Sobrien static const char strD[] = {033, '[', 'D', '\0'}; 108684260Sobrien static const char strH[] = {033, '[', 'H', '\0'}; 108784260Sobrien static const char strF[] = {033, '[', 'F', '\0'}; 108884260Sobrien static const char str1[] = {033, '[', '1', '~', '\0'}; 108984260Sobrien static const char str4[] = {033, '[', '4', '~', '\0'}; 109084260Sobrien static const char stOA[] = {033, 'O', 'A', '\0'}; 109184260Sobrien static const char stOB[] = {033, 'O', 'B', '\0'}; 109284260Sobrien static const char stOC[] = {033, 'O', 'C', '\0'}; 109384260Sobrien static const char stOD[] = {033, 'O', 'D', '\0'}; 109484260Sobrien static const char stOH[] = {033, 'O', 'H', '\0'}; 109584260Sobrien static const char stOF[] = {033, 'O', 'F', '\0'}; 10961573Srgrimes 109784260Sobrien key_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 109884260Sobrien key_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 109984260Sobrien key_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 110084260Sobrien key_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 110184260Sobrien key_add(el, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 110284260Sobrien key_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 110384260Sobrien key_add(el, str1, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 110484260Sobrien key_add(el, str4, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 110584260Sobrien key_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); 110684260Sobrien key_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); 110784260Sobrien key_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); 110884260Sobrien key_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); 110984260Sobrien key_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); 111084260Sobrien key_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); 11111573Srgrimes 111284260Sobrien if (el->el_map.type == MAP_VI) { 111384260Sobrien key_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); 111484260Sobrien key_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); 111584260Sobrien key_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); 111684260Sobrien key_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); 111784260Sobrien key_add(el, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); 111884260Sobrien key_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); 111984260Sobrien key_add(el, &str1[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); 112084260Sobrien key_add(el, &str4[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); 112184260Sobrien key_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); 112284260Sobrien key_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); 112384260Sobrien key_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); 112484260Sobrien key_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); 112584260Sobrien key_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); 112684260Sobrien key_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); 112784260Sobrien } 11281573Srgrimes} 11291573Srgrimes 11301573Srgrimes 11311573Srgrimes/* term_set_arrow(): 11321573Srgrimes * Set an arrow key binding 11331573Srgrimes */ 11341573Srgrimesprotected int 1135148834Sstefanfterm_set_arrow(EditLine *el, const char *name, key_value_t *fun, int type) 11361573Srgrimes{ 113784260Sobrien fkey_t *arrow = el->el_term.t_fkey; 113884260Sobrien int i; 11391573Srgrimes 114084260Sobrien for (i = 0; i < A_K_NKEYS; i++) 114184260Sobrien if (strcmp(name, arrow[i].name) == 0) { 114284260Sobrien arrow[i].fun = *fun; 114384260Sobrien arrow[i].type = type; 114484260Sobrien return (0); 114584260Sobrien } 114684260Sobrien return (-1); 11471573Srgrimes} 11481573Srgrimes 11491573Srgrimes 11501573Srgrimes/* term_clear_arrow(): 11511573Srgrimes * Clear an arrow key binding 11521573Srgrimes */ 11531573Srgrimesprotected int 1154148834Sstefanfterm_clear_arrow(EditLine *el, const char *name) 11551573Srgrimes{ 115684260Sobrien fkey_t *arrow = el->el_term.t_fkey; 115784260Sobrien int i; 11581573Srgrimes 115984260Sobrien for (i = 0; i < A_K_NKEYS; i++) 116084260Sobrien if (strcmp(name, arrow[i].name) == 0) { 116184260Sobrien arrow[i].type = XK_NOD; 116284260Sobrien return (0); 116384260Sobrien } 116484260Sobrien return (-1); 11651573Srgrimes} 11661573Srgrimes 11671573Srgrimes 11681573Srgrimes/* term_print_arrow(): 11691573Srgrimes * Print the arrow key bindings 11701573Srgrimes */ 11711573Srgrimesprotected void 1172148834Sstefanfterm_print_arrow(EditLine *el, const char *name) 11731573Srgrimes{ 117484260Sobrien int i; 117584260Sobrien fkey_t *arrow = el->el_term.t_fkey; 11761573Srgrimes 117784260Sobrien for (i = 0; i < A_K_NKEYS; i++) 117884260Sobrien if (*name == '\0' || strcmp(name, arrow[i].name) == 0) 117984260Sobrien if (arrow[i].type != XK_NOD) 118084260Sobrien key_kprint(el, arrow[i].name, &arrow[i].fun, 118184260Sobrien arrow[i].type); 11821573Srgrimes} 11831573Srgrimes 11841573Srgrimes 11851573Srgrimes/* term_bind_arrow(): 11861573Srgrimes * Bind the arrow keys 11871573Srgrimes */ 11881573Srgrimesprotected void 118984260Sobrienterm_bind_arrow(EditLine *el) 11901573Srgrimes{ 119184260Sobrien el_action_t *map; 119284260Sobrien const el_action_t *dmap; 119384260Sobrien int i, j; 119484260Sobrien char *p; 119584260Sobrien fkey_t *arrow = el->el_term.t_fkey; 11961573Srgrimes 119784260Sobrien /* Check if the components needed are initialized */ 119884260Sobrien if (el->el_term.t_buf == NULL || el->el_map.key == NULL) 119984260Sobrien return; 12001573Srgrimes 120184260Sobrien map = el->el_map.type == MAP_VI ? el->el_map.alt : el->el_map.key; 120284260Sobrien dmap = el->el_map.type == MAP_VI ? el->el_map.vic : el->el_map.emacs; 12031573Srgrimes 120484260Sobrien term_reset_arrow(el); 12051573Srgrimes 120684260Sobrien for (i = 0; i < A_K_NKEYS; i++) { 120784260Sobrien p = el->el_term.t_str[arrow[i].key]; 120884260Sobrien if (p && *p) { 120984260Sobrien j = (unsigned char) *p; 121084260Sobrien /* 121184260Sobrien * Assign the arrow keys only if: 121284260Sobrien * 121384260Sobrien * 1. They are multi-character arrow keys and the user 121484260Sobrien * has not re-assigned the leading character, or 121584260Sobrien * has re-assigned the leading character to be 121684260Sobrien * ED_SEQUENCE_LEAD_IN 121784260Sobrien * 2. They are single arrow keys pointing to an 121884260Sobrien * unassigned key. 121984260Sobrien */ 122084260Sobrien if (arrow[i].type == XK_NOD) 122184260Sobrien key_clear(el, map, p); 122284260Sobrien else { 122384260Sobrien if (p[1] && (dmap[j] == map[j] || 122484260Sobrien map[j] == ED_SEQUENCE_LEAD_IN)) { 122584260Sobrien key_add(el, p, &arrow[i].fun, 122684260Sobrien arrow[i].type); 122784260Sobrien map[j] = ED_SEQUENCE_LEAD_IN; 122884260Sobrien } else if (map[j] == ED_UNASSIGNED) { 122984260Sobrien key_clear(el, map, p); 123084260Sobrien if (arrow[i].type == XK_CMD) 123184260Sobrien map[j] = arrow[i].fun.cmd; 123284260Sobrien else 123384260Sobrien key_add(el, p, &arrow[i].fun, 123484260Sobrien arrow[i].type); 123584260Sobrien } 123684260Sobrien } 12371573Srgrimes } 12381573Srgrimes } 12391573Srgrimes} 12401573Srgrimes 1241237448Spfg/* term_putc(): 1242237448Spfg * Add a character 1243237448Spfg */ 1244237448Spfgprivate int 1245237448Spfgterm_putc(int c) 1246237448Spfg{ 12471573Srgrimes 1248237448Spfg if (term_outfile == NULL) 1249237448Spfg return -1; 1250237448Spfg return fputc(c, term_outfile); 1251237448Spfg} 1252237448Spfg 1253237448Spfgprivate void 1254237448Spfgterm_tputs(EditLine *el, const char *cap, int affcnt) 1255237448Spfg{ 1256237448Spfg#ifdef _REENTRANT 1257237448Spfg pthread_mutex_lock(&term_mutex); 1258237448Spfg#endif 1259237448Spfg term_outfile = el->el_outfile; 1260237448Spfg (void)tputs(cap, affcnt, term_putc); 1261237448Spfg#ifdef _REENTRANT 1262237448Spfg pthread_mutex_unlock(&term_mutex); 1263237448Spfg#endif 1264237448Spfg} 1265237448Spfg 12661573Srgrimes/* term__putc(): 12671573Srgrimes * Add a character 12681573Srgrimes */ 12699898Sacheprotected int 1270237448Spfgterm__putc(EditLine *el, int c) 12711573Srgrimes{ 12721573Srgrimes 1273237448Spfg return fputc(c, el->el_outfile); 127484260Sobrien} 12751573Srgrimes 12761573Srgrimes/* term__flush(): 12771573Srgrimes * Flush output 12781573Srgrimes */ 12791573Srgrimesprotected void 1280237448Spfgterm__flush(EditLine *el) 12811573Srgrimes{ 12821573Srgrimes 1283237448Spfg (void) fflush(el->el_outfile); 128484260Sobrien} 12851573Srgrimes 1286167457Sstefanf/* term_writec(): 1287167457Sstefanf * Write the given character out, in a human readable form 1288167457Sstefanf */ 1289167457Sstefanfprotected void 1290167457Sstefanfterm_writec(EditLine *el, int c) 1291167457Sstefanf{ 1292167457Sstefanf char buf[8]; 1293237448Spfg size_t cnt = key__decode_char(buf, sizeof(buf), 0, c); 1294167457Sstefanf buf[cnt] = '\0'; 1295237448Spfg term_overwrite(el, buf, (size_t)cnt); 1296237448Spfg term__flush(el); 1297167457Sstefanf} 129884260Sobrien 1299167457Sstefanf 13001573Srgrimes/* term_telltc(): 13011573Srgrimes * Print the current termcap characteristics 13021573Srgrimes */ 13031573Srgrimesprotected int 13041573Srgrimes/*ARGSUSED*/ 1305148834Sstefanfterm_telltc(EditLine *el, int argc __unused, 1306148834Sstefanf const char **argv __unused) 13071573Srgrimes{ 130884260Sobrien const struct termcapstr *t; 130984260Sobrien char **ts; 131084260Sobrien char upbuf[EL_BUFSIZ]; 13111573Srgrimes 131284260Sobrien (void) fprintf(el->el_outfile, "\n\tYour terminal has the\n"); 131384260Sobrien (void) fprintf(el->el_outfile, "\tfollowing characteristics:\n\n"); 131484260Sobrien (void) fprintf(el->el_outfile, "\tIt has %d columns and %d lines\n", 13151573Srgrimes Val(T_co), Val(T_li)); 131684260Sobrien (void) fprintf(el->el_outfile, 131784260Sobrien "\tIt has %s meta key\n", EL_HAS_META ? "a" : "no"); 131884260Sobrien (void) fprintf(el->el_outfile, 131984260Sobrien "\tIt can%suse tabs\n", EL_CAN_TAB ? " " : "not "); 132084260Sobrien (void) fprintf(el->el_outfile, "\tIt %s automatic margins\n", 132184260Sobrien EL_HAS_AUTO_MARGINS ? "has" : "does not have"); 132284260Sobrien if (EL_HAS_AUTO_MARGINS) 132384260Sobrien (void) fprintf(el->el_outfile, "\tIt %s magic margins\n", 132484260Sobrien EL_HAS_MAGIC_MARGINS ? "has" : "does not have"); 13251573Srgrimes 1326167457Sstefanf for (t = tstr, ts = el->el_term.t_str; t->name != NULL; t++, ts++) { 1327167457Sstefanf const char *ub; 1328167457Sstefanf if (*ts && **ts) { 1329167457Sstefanf (void) key__decode_str(*ts, upbuf, sizeof(upbuf), ""); 1330167457Sstefanf ub = upbuf; 1331167457Sstefanf } else { 1332167457Sstefanf ub = "(empty)"; 1333167457Sstefanf } 133484260Sobrien (void) fprintf(el->el_outfile, "\t%25s (%s) == %s\n", 1335167457Sstefanf t->long_name, t->name, ub); 1336167457Sstefanf } 133784260Sobrien (void) fputc('\n', el->el_outfile); 133884260Sobrien return (0); 13391573Srgrimes} 13401573Srgrimes 13411573Srgrimes 13421573Srgrimes/* term_settc(): 13431573Srgrimes * Change the current terminal characteristics 13441573Srgrimes */ 13451573Srgrimesprotected int 13461573Srgrimes/*ARGSUSED*/ 1347148834Sstefanfterm_settc(EditLine *el, int argc __unused, 1348148834Sstefanf const char **argv) 13491573Srgrimes{ 135084260Sobrien const struct termcapstr *ts; 135184260Sobrien const struct termcapval *tv; 1352148834Sstefanf const char *what, *how; 13531573Srgrimes 135484260Sobrien if (argv == NULL || argv[1] == NULL || argv[2] == NULL) 1355170511Sstefanf return -1; 13561573Srgrimes 135784260Sobrien what = argv[1]; 135884260Sobrien how = argv[2]; 13591573Srgrimes 136084260Sobrien /* 136184260Sobrien * Do the strings first 136284260Sobrien */ 136384260Sobrien for (ts = tstr; ts->name != NULL; ts++) 136484260Sobrien if (strcmp(ts->name, what) == 0) 136584260Sobrien break; 13661573Srgrimes 136784260Sobrien if (ts->name != NULL) { 136884260Sobrien term_alloc(el, ts, how); 136984260Sobrien term_setflags(el); 1370170511Sstefanf return 0; 137184260Sobrien } 137284260Sobrien /* 137384260Sobrien * Do the numeric ones second 137484260Sobrien */ 137584260Sobrien for (tv = tval; tv->name != NULL; tv++) 137684260Sobrien if (strcmp(tv->name, what) == 0) 137784260Sobrien break; 13781573Srgrimes 1379170511Sstefanf if (tv->name != NULL) 1380170511Sstefanf return -1; 13811573Srgrimes 1382170511Sstefanf if (tv == &tval[T_pt] || tv == &tval[T_km] || 1383170511Sstefanf tv == &tval[T_am] || tv == &tval[T_xn]) { 1384170511Sstefanf if (strcmp(how, "yes") == 0) 1385170511Sstefanf el->el_term.t_val[tv - tval] = 1; 1386170511Sstefanf else if (strcmp(how, "no") == 0) 1387170511Sstefanf el->el_term.t_val[tv - tval] = 0; 1388170511Sstefanf else { 1389170511Sstefanf (void) fprintf(el->el_errfile, 1390170511Sstefanf "%s: Bad value `%s'.\n", argv[0], how); 1391170511Sstefanf return -1; 139284260Sobrien } 1393170511Sstefanf term_setflags(el); 1394170511Sstefanf if (term_change_size(el, Val(T_li), Val(T_co)) == -1) 1395170511Sstefanf return -1; 1396170511Sstefanf return 0; 1397170511Sstefanf } else { 1398170511Sstefanf long i; 1399170511Sstefanf char *ep; 1400170511Sstefanf 1401170511Sstefanf i = strtol(how, &ep, 10); 1402170511Sstefanf if (*ep != '\0') { 1403170511Sstefanf (void) fprintf(el->el_errfile, 1404170511Sstefanf "%s: Bad value `%s'.\n", argv[0], how); 1405170511Sstefanf return -1; 1406170511Sstefanf } 1407170511Sstefanf el->el_term.t_val[tv - tval] = (int) i; 1408170511Sstefanf el->el_term.t_size.v = Val(T_co); 1409170511Sstefanf el->el_term.t_size.h = Val(T_li); 1410170511Sstefanf if (tv == &tval[T_co] || tv == &tval[T_li]) 1411170511Sstefanf if (term_change_size(el, Val(T_li), Val(T_co)) 1412170511Sstefanf == -1) 1413170511Sstefanf return -1; 1414170511Sstefanf return 0; 14151573Srgrimes } 14161573Srgrimes} 14171573Srgrimes 14181573Srgrimes 1419170511Sstefanf/* term_gettc(): 1420170511Sstefanf * Get the current terminal characteristics 1421170511Sstefanf */ 1422170511Sstefanfprotected int 1423170511Sstefanf/*ARGSUSED*/ 1424170511Sstefanfterm_gettc(EditLine *el, int argc __unused, char **argv) 1425170511Sstefanf{ 1426170511Sstefanf const struct termcapstr *ts; 1427170511Sstefanf const struct termcapval *tv; 1428170511Sstefanf char *what; 1429170511Sstefanf void *how; 1430170511Sstefanf 1431170511Sstefanf if (argv == NULL || argv[1] == NULL || argv[2] == NULL) 1432170511Sstefanf return (-1); 1433170511Sstefanf 1434170511Sstefanf what = argv[1]; 1435170511Sstefanf how = argv[2]; 1436170511Sstefanf 1437170511Sstefanf /* 1438170511Sstefanf * Do the strings first 1439170511Sstefanf */ 1440170511Sstefanf for (ts = tstr; ts->name != NULL; ts++) 1441170511Sstefanf if (strcmp(ts->name, what) == 0) 1442170511Sstefanf break; 1443170511Sstefanf 1444170511Sstefanf if (ts->name != NULL) { 1445170511Sstefanf *(char **)how = el->el_term.t_str[ts - tstr]; 1446170511Sstefanf return 0; 1447170511Sstefanf } 1448170511Sstefanf /* 1449170511Sstefanf * Do the numeric ones second 1450170511Sstefanf */ 1451170511Sstefanf for (tv = tval; tv->name != NULL; tv++) 1452170511Sstefanf if (strcmp(tv->name, what) == 0) 1453170511Sstefanf break; 1454170511Sstefanf 1455170511Sstefanf if (tv->name == NULL) 1456170511Sstefanf return -1; 1457170511Sstefanf 1458170511Sstefanf if (tv == &tval[T_pt] || tv == &tval[T_km] || 1459170511Sstefanf tv == &tval[T_am] || tv == &tval[T_xn]) { 1460170511Sstefanf static char yes[] = "yes"; 1461170511Sstefanf static char no[] = "no"; 1462170511Sstefanf if (el->el_term.t_val[tv - tval]) 1463170511Sstefanf *(char **)how = yes; 1464170511Sstefanf else 1465170511Sstefanf *(char **)how = no; 1466170511Sstefanf return 0; 1467170511Sstefanf } else { 1468170511Sstefanf *(int *)how = el->el_term.t_val[tv - tval]; 1469170511Sstefanf return 0; 1470170511Sstefanf } 1471170511Sstefanf} 1472170511Sstefanf 14731573Srgrimes/* term_echotc(): 14741573Srgrimes * Print the termcap string out with variable substitution 14751573Srgrimes */ 14761573Srgrimesprotected int 14771573Srgrimes/*ARGSUSED*/ 1478148834Sstefanfterm_echotc(EditLine *el, int argc __unused, 1479148834Sstefanf const char **argv) 14801573Srgrimes{ 148184260Sobrien char *cap, *scap, *ep; 148284260Sobrien int arg_need, arg_cols, arg_rows; 148384260Sobrien int verbose = 0, silent = 0; 148484260Sobrien char *area; 148584260Sobrien static const char fmts[] = "%s\n", fmtd[] = "%d\n"; 148684260Sobrien const struct termcapstr *t; 148784260Sobrien char buf[TC_BUFSIZE]; 148884260Sobrien long i; 14891573Srgrimes 149084260Sobrien area = buf; 14911573Srgrimes 149284260Sobrien if (argv == NULL || argv[1] == NULL) 149384260Sobrien return (-1); 149484260Sobrien argv++; 14951573Srgrimes 149684260Sobrien if (argv[0][0] == '-') { 149784260Sobrien switch (argv[0][1]) { 149884260Sobrien case 'v': 149984260Sobrien verbose = 1; 150084260Sobrien break; 150184260Sobrien case 's': 150284260Sobrien silent = 1; 150384260Sobrien break; 150484260Sobrien default: 150584260Sobrien /* stderror(ERR_NAME | ERR_TCUSAGE); */ 150684260Sobrien break; 150784260Sobrien } 150884260Sobrien argv++; 15091573Srgrimes } 151084260Sobrien if (!*argv || *argv[0] == '\0') 151184260Sobrien return (0); 151284260Sobrien if (strcmp(*argv, "tabs") == 0) { 151384260Sobrien (void) fprintf(el->el_outfile, fmts, EL_CAN_TAB ? "yes" : "no"); 151484260Sobrien return (0); 151584260Sobrien } else if (strcmp(*argv, "meta") == 0) { 151684260Sobrien (void) fprintf(el->el_outfile, fmts, Val(T_km) ? "yes" : "no"); 151784260Sobrien return (0); 151884260Sobrien } else if (strcmp(*argv, "xn") == 0) { 151984260Sobrien (void) fprintf(el->el_outfile, fmts, EL_HAS_MAGIC_MARGINS ? 152084260Sobrien "yes" : "no"); 152184260Sobrien return (0); 152284260Sobrien } else if (strcmp(*argv, "am") == 0) { 152384260Sobrien (void) fprintf(el->el_outfile, fmts, EL_HAS_AUTO_MARGINS ? 152484260Sobrien "yes" : "no"); 152584260Sobrien return (0); 152684260Sobrien } else if (strcmp(*argv, "baud") == 0) { 152784260Sobrien#ifdef notdef 152884260Sobrien int i; 152984260Sobrien 153084260Sobrien for (i = 0; baud_rate[i].b_name != NULL; i++) 153184260Sobrien if (el->el_tty.t_speed == baud_rate[i].b_rate) { 153284260Sobrien (void) fprintf(el->el_outfile, fmts, 153384260Sobrien baud_rate[i].b_name); 153484260Sobrien return (0); 153584260Sobrien } 153684260Sobrien (void) fprintf(el->el_outfile, fmtd, 0); 153784260Sobrien#else 1538148834Sstefanf (void) fprintf(el->el_outfile, fmtd, (int)el->el_tty.t_speed); 15391573Srgrimes#endif 154084260Sobrien return (0); 154184260Sobrien } else if (strcmp(*argv, "rows") == 0 || strcmp(*argv, "lines") == 0) { 154284260Sobrien (void) fprintf(el->el_outfile, fmtd, Val(T_li)); 154384260Sobrien return (0); 154484260Sobrien } else if (strcmp(*argv, "cols") == 0) { 154584260Sobrien (void) fprintf(el->el_outfile, fmtd, Val(T_co)); 154684260Sobrien return (0); 15471573Srgrimes } 154884260Sobrien /* 154984260Sobrien * Try to use our local definition first 155084260Sobrien */ 155184260Sobrien scap = NULL; 155284260Sobrien for (t = tstr; t->name != NULL; t++) 155384260Sobrien if (strcmp(t->name, *argv) == 0) { 155484260Sobrien scap = el->el_term.t_str[t - tstr]; 155584260Sobrien break; 155684260Sobrien } 1557148834Sstefanf if (t->name == NULL) { 1558148848Sstefanf /* XXX: some systems' tgetstr needs non const */ 1559148834Sstefanf scap = tgetstr(strchr(*argv, **argv), &area); 1560148834Sstefanf } 156184260Sobrien if (!scap || scap[0] == '\0') { 156284260Sobrien if (!silent) 156384260Sobrien (void) fprintf(el->el_errfile, 156484260Sobrien "echotc: Termcap parameter `%s' not found.\n", 156584260Sobrien *argv); 156684260Sobrien return (-1); 156784260Sobrien } 156884260Sobrien /* 156984260Sobrien * Count home many values we need for this capability. 157084260Sobrien */ 157184260Sobrien for (cap = scap, arg_need = 0; *cap; cap++) 157284260Sobrien if (*cap == '%') 157384260Sobrien switch (*++cap) { 157484260Sobrien case 'd': 157584260Sobrien case '2': 157684260Sobrien case '3': 157784260Sobrien case '.': 157884260Sobrien case '+': 157984260Sobrien arg_need++; 158084260Sobrien break; 158184260Sobrien case '%': 158284260Sobrien case '>': 158384260Sobrien case 'i': 158484260Sobrien case 'r': 158584260Sobrien case 'n': 158684260Sobrien case 'B': 158784260Sobrien case 'D': 158884260Sobrien break; 158984260Sobrien default: 159084260Sobrien /* 159184260Sobrien * hpux has lot's of them... 159284260Sobrien */ 159384260Sobrien if (verbose) 159484260Sobrien (void) fprintf(el->el_errfile, 159584260Sobrien "echotc: Warning: unknown termcap %% `%c'.\n", 159684260Sobrien *cap); 159784260Sobrien /* This is bad, but I won't complain */ 159884260Sobrien break; 159984260Sobrien } 16001573Srgrimes 160184260Sobrien switch (arg_need) { 160284260Sobrien case 0: 160384260Sobrien argv++; 160484260Sobrien if (*argv && *argv[0]) { 160584260Sobrien if (!silent) 160684260Sobrien (void) fprintf(el->el_errfile, 160784260Sobrien "echotc: Warning: Extra argument `%s'.\n", 160884260Sobrien *argv); 160984260Sobrien return (-1); 161084260Sobrien } 1611237448Spfg term_tputs(el, scap, 1); 16121573Srgrimes break; 161384260Sobrien case 1: 161484260Sobrien argv++; 161584260Sobrien if (!*argv || *argv[0] == '\0') { 161684260Sobrien if (!silent) 161784260Sobrien (void) fprintf(el->el_errfile, 161884260Sobrien "echotc: Warning: Missing argument.\n"); 161984260Sobrien return (-1); 162084260Sobrien } 162184260Sobrien arg_cols = 0; 162284260Sobrien i = strtol(*argv, &ep, 10); 162384260Sobrien if (*ep != '\0' || i < 0) { 162484260Sobrien if (!silent) 162584260Sobrien (void) fprintf(el->el_errfile, 162684260Sobrien "echotc: Bad value `%s' for rows.\n", 162784260Sobrien *argv); 162884260Sobrien return (-1); 162984260Sobrien } 163084260Sobrien arg_rows = (int) i; 163184260Sobrien argv++; 163284260Sobrien if (*argv && *argv[0]) { 163384260Sobrien if (!silent) 163484260Sobrien (void) fprintf(el->el_errfile, 163584260Sobrien "echotc: Warning: Extra argument `%s'.\n", 163684260Sobrien *argv); 163784260Sobrien return (-1); 163884260Sobrien } 1639237448Spfg term_tputs(el, tgoto(scap, arg_cols, arg_rows), 1); 16401573Srgrimes break; 164184260Sobrien default: 164284260Sobrien /* This is wrong, but I will ignore it... */ 16431573Srgrimes if (verbose) 164484260Sobrien (void) fprintf(el->el_errfile, 164584260Sobrien "echotc: Warning: Too many required arguments (%d).\n", 164684260Sobrien arg_need); 164784260Sobrien /* FALLTHROUGH */ 164884260Sobrien case 2: 164984260Sobrien argv++; 165084260Sobrien if (!*argv || *argv[0] == '\0') { 165184260Sobrien if (!silent) 165284260Sobrien (void) fprintf(el->el_errfile, 165384260Sobrien "echotc: Warning: Missing argument.\n"); 165484260Sobrien return (-1); 165584260Sobrien } 165684260Sobrien i = strtol(*argv, &ep, 10); 165784260Sobrien if (*ep != '\0' || i < 0) { 165884260Sobrien if (!silent) 165984260Sobrien (void) fprintf(el->el_errfile, 166084260Sobrien "echotc: Bad value `%s' for cols.\n", 166184260Sobrien *argv); 166284260Sobrien return (-1); 166384260Sobrien } 166484260Sobrien arg_cols = (int) i; 166584260Sobrien argv++; 166684260Sobrien if (!*argv || *argv[0] == '\0') { 166784260Sobrien if (!silent) 166884260Sobrien (void) fprintf(el->el_errfile, 166984260Sobrien "echotc: Warning: Missing argument.\n"); 167084260Sobrien return (-1); 167184260Sobrien } 167284260Sobrien i = strtol(*argv, &ep, 10); 167384260Sobrien if (*ep != '\0' || i < 0) { 167484260Sobrien if (!silent) 167584260Sobrien (void) fprintf(el->el_errfile, 167684260Sobrien "echotc: Bad value `%s' for rows.\n", 167784260Sobrien *argv); 167884260Sobrien return (-1); 167984260Sobrien } 168084260Sobrien arg_rows = (int) i; 168184260Sobrien if (*ep != '\0') { 168284260Sobrien if (!silent) 168384260Sobrien (void) fprintf(el->el_errfile, 168484260Sobrien "echotc: Bad value `%s'.\n", *argv); 168584260Sobrien return (-1); 168684260Sobrien } 168784260Sobrien argv++; 168884260Sobrien if (*argv && *argv[0]) { 168984260Sobrien if (!silent) 169084260Sobrien (void) fprintf(el->el_errfile, 169184260Sobrien "echotc: Warning: Extra argument `%s'.\n", 169284260Sobrien *argv); 169384260Sobrien return (-1); 169484260Sobrien } 1695237448Spfg term_tputs(el, tgoto(scap, arg_cols, arg_rows), arg_rows); 16961573Srgrimes break; 16971573Srgrimes } 169884260Sobrien return (0); 16991573Srgrimes} 1700