1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/ed.screen.c,v 3.78 2011/02/27 00:14:38 christos Exp $ */
259243Sobrien/*
359243Sobrien * ed.screen.c: Editor/termcap-curses interface
459243Sobrien */
559243Sobrien/*-
659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
759243Sobrien * All rights reserved.
859243Sobrien *
959243Sobrien * Redistribution and use in source and binary forms, with or without
1059243Sobrien * modification, are permitted provided that the following conditions
1159243Sobrien * are met:
1259243Sobrien * 1. Redistributions of source code must retain the above copyright
1359243Sobrien *    notice, this list of conditions and the following disclaimer.
1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1559243Sobrien *    notice, this list of conditions and the following disclaimer in the
1659243Sobrien *    documentation and/or other materials provided with the distribution.
17100616Smp * 3. Neither the name of the University nor the names of its contributors
1859243Sobrien *    may be used to endorse or promote products derived from this software
1959243Sobrien *    without specific prior written permission.
2059243Sobrien *
2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2459243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3159243Sobrien * SUCH DAMAGE.
3259243Sobrien */
3359243Sobrien#include "sh.h"
3459243Sobrien
35232633SmpRCSID("$tcsh: ed.screen.c,v 3.78 2011/02/27 00:14:38 christos Exp $")
3659243Sobrien
3759243Sobrien#include "ed.h"
3859243Sobrien#include "tc.h"
3959243Sobrien#include "ed.defns.h"
4059243Sobrien
4159243Sobrien/* #define DEBUG_LITERAL */
4259243Sobrien
4359243Sobrien/*
4459243Sobrien * IMPORTANT NOTE: these routines are allowed to look at the current screen
4559243Sobrien * and the current possition assuming that it is correct.  If this is not
4659243Sobrien * true, then the update will be WRONG!  This is (should be) a valid
4759243Sobrien * assumption...
4859243Sobrien */
4959243Sobrien
5059243Sobrien#define TC_BUFSIZE 2048
5159243Sobrien
5259243Sobrien#define GoodStr(a) (tstr[a].str != NULL && tstr[a].str[0] != '\0')
5359243Sobrien#define Str(a) tstr[a].str
5459243Sobrien#define Val(a) tval[a].val
5559243Sobrien
56167465Smpstatic const struct {
57145479Smp    const char   *b_name;
58145479Smp    speed_t b_rate;
5959243Sobrien}       baud_rate[] = {
6059243Sobrien
6159243Sobrien#ifdef B0
6259243Sobrien    { "0", B0 },
6359243Sobrien#endif
6459243Sobrien#ifdef B50
6559243Sobrien    { "50", B50 },
6659243Sobrien#endif
6759243Sobrien#ifdef B75
6859243Sobrien    { "75", B75 },
6959243Sobrien#endif
7059243Sobrien#ifdef B110
7159243Sobrien    { "110", B110 },
7259243Sobrien#endif
7359243Sobrien#ifdef B134
7459243Sobrien    { "134", B134 },
7559243Sobrien#endif
7659243Sobrien#ifdef B150
7759243Sobrien    { "150", B150 },
7859243Sobrien#endif
7959243Sobrien#ifdef B200
8059243Sobrien    { "200", B200 },
8159243Sobrien#endif
8259243Sobrien#ifdef B300
8359243Sobrien    { "300", B300 },
8459243Sobrien#endif
8559243Sobrien#ifdef B600
8659243Sobrien    { "600", B600 },
8759243Sobrien#endif
8859243Sobrien#ifdef B900
8959243Sobrien    { "900", B900 },
9059243Sobrien#endif
9159243Sobrien#ifdef B1200
9259243Sobrien    { "1200", B1200 },
9359243Sobrien#endif
9459243Sobrien#ifdef B1800
9559243Sobrien    { "1800", B1800 },
9659243Sobrien#endif
9759243Sobrien#ifdef B2400
9859243Sobrien    { "2400", B2400 },
9959243Sobrien#endif
10059243Sobrien#ifdef B3600
10159243Sobrien    { "3600", B3600 },
10259243Sobrien#endif
10359243Sobrien#ifdef B4800
10459243Sobrien    { "4800", B4800 },
10559243Sobrien#endif
10659243Sobrien#ifdef B7200
10759243Sobrien    { "7200", B7200 },
10859243Sobrien#endif
10959243Sobrien#ifdef B9600
11059243Sobrien    { "9600", B9600 },
11159243Sobrien#endif
11259243Sobrien#ifdef EXTA
11359243Sobrien    { "19200", EXTA },
11459243Sobrien#endif
11559243Sobrien#ifdef B19200
11659243Sobrien    { "19200", B19200 },
11759243Sobrien#endif
11859243Sobrien#ifdef EXTB
11959243Sobrien    { "38400", EXTB },
12059243Sobrien#endif
12159243Sobrien#ifdef B38400
12259243Sobrien    { "38400", B38400 },
12359243Sobrien#endif
12459243Sobrien    { NULL, 0 }
12559243Sobrien};
12659243Sobrien
127167465Smp#define T_at7   0
128167465Smp#define T_al	1
129167465Smp#define T_bl	2
130167465Smp#define T_cd	3
131167465Smp#define T_ce	4
132167465Smp#define T_ch	5
133167465Smp#define T_cl	6
134167465Smp#define	T_dc	7
135167465Smp#define	T_dl	8
136167465Smp#define	T_dm	9
137167465Smp#define	T_ed	10
138167465Smp#define	T_ei	11
139167465Smp#define	T_fs	12
140167465Smp#define	T_ho	13
141167465Smp#define	T_ic	14
142167465Smp#define	T_im	15
143167465Smp#define	T_ip	16
144167465Smp#define	T_kd	17
145167465Smp#define T_kh    18
146167465Smp#define	T_kl	19
147167465Smp#define T_kr	20
148167465Smp#define T_ku	21
149167465Smp#define T_md	22
150167465Smp#define T_me	23
151167465Smp#define T_mr    24
152167465Smp#define T_nd	25
153167465Smp#define T_se	26
154167465Smp#define T_so	27
155167465Smp#define T_ts	28
156167465Smp#define T_up	29
157167465Smp#define T_us	30
158167465Smp#define T_ue	31
159167465Smp#define T_vb	32
160167465Smp#define T_DC	33
161167465Smp#define T_DO	34
162167465Smp#define T_IC	35
163167465Smp#define T_LE	36
164167465Smp#define T_RI	37
165167465Smp#define T_UP	38
166167465Smp#define T_str   39
167167465Smp
16859243Sobrienstatic struct termcapstr {
169145479Smp    const char   *name;
170145479Smp    const char   *long_name;
17159243Sobrien    char   *str;
17259243Sobrien} tstr[T_str + 1];
17359243Sobrien
17459243Sobrien
17559243Sobrien#define T_am	0
17659243Sobrien#define T_pt	1
17759243Sobrien#define T_li	2
17859243Sobrien#define T_co	3
17959243Sobrien#define T_km	4
18059243Sobrien#define T_xn	5
18159243Sobrien#define T_val	6
18259243Sobrienstatic struct termcapval {
183145479Smp    const char   *name;
184145479Smp    const char   *long_name;
18559243Sobrien    int     val;
18659243Sobrien} tval[T_val + 1];
18759243Sobrien
18859243Sobrienvoid
189167465Smpterminit(void)
19059243Sobrien{
19159243Sobrien#ifdef NLS_CATALOGS
19259243Sobrien    int i;
19359243Sobrien
19459243Sobrien    for (i = 0; i < T_str + 1; i++)
195167465Smp	xfree((ptr_t)(intptr_t)tstr[i].long_name);
19659243Sobrien
19759243Sobrien    for (i = 0; i < T_val + 1; i++)
198167465Smp	xfree((ptr_t)(intptr_t)tval[i].long_name);
19959243Sobrien#endif
20059243Sobrien
20159243Sobrien    tstr[T_al].name = "al";
20259243Sobrien    tstr[T_al].long_name = CSAVS(4, 1, "add new blank line");
20359243Sobrien
20459243Sobrien    tstr[T_bl].name = "bl";
20559243Sobrien    tstr[T_bl].long_name = CSAVS(4, 2, "audible bell");
20659243Sobrien
20759243Sobrien    tstr[T_cd].name = "cd";
20859243Sobrien    tstr[T_cd].long_name = CSAVS(4, 3, "clear to bottom");
20959243Sobrien
21059243Sobrien    tstr[T_ce].name = "ce";
21159243Sobrien    tstr[T_ce].long_name = CSAVS(4, 4, "clear to end of line");
21259243Sobrien
21359243Sobrien    tstr[T_ch].name = "ch";
21459243Sobrien    tstr[T_ch].long_name = CSAVS(4, 5, "cursor to horiz pos");
21559243Sobrien
21659243Sobrien    tstr[T_cl].name = "cl";
21759243Sobrien    tstr[T_cl].long_name = CSAVS(4, 6, "clear screen");
21859243Sobrien
21959243Sobrien    tstr[T_dc].name = "dc";
22059243Sobrien    tstr[T_dc].long_name = CSAVS(4, 7, "delete a character");
22159243Sobrien
22259243Sobrien    tstr[T_dl].name = "dl";
22359243Sobrien    tstr[T_dl].long_name = CSAVS(4, 8, "delete a line");
22459243Sobrien
22559243Sobrien    tstr[T_dm].name = "dm";
22659243Sobrien    tstr[T_dm].long_name = CSAVS(4, 9, "start delete mode");
22759243Sobrien
22859243Sobrien    tstr[T_ed].name = "ed";
22959243Sobrien    tstr[T_ed].long_name = CSAVS(4, 10, "end delete mode");
23059243Sobrien
23159243Sobrien    tstr[T_ei].name = "ei";
23259243Sobrien    tstr[T_ei].long_name = CSAVS(4, 11, "end insert mode");
23359243Sobrien
23459243Sobrien    tstr[T_fs].name = "fs";
23559243Sobrien    tstr[T_fs].long_name = CSAVS(4, 12, "cursor from status line");
23659243Sobrien
23759243Sobrien    tstr[T_ho].name = "ho";
23859243Sobrien    tstr[T_ho].long_name = CSAVS(4, 13, "home cursor");
23959243Sobrien
24059243Sobrien    tstr[T_ic].name = "ic";
24159243Sobrien    tstr[T_ic].long_name = CSAVS(4, 14, "insert character");
24259243Sobrien
24359243Sobrien    tstr[T_im].name = "im";
24459243Sobrien    tstr[T_im].long_name = CSAVS(4, 15, "start insert mode");
24559243Sobrien
24659243Sobrien    tstr[T_ip].name = "ip";
24759243Sobrien    tstr[T_ip].long_name = CSAVS(4, 16, "insert padding");
24859243Sobrien
24959243Sobrien    tstr[T_kd].name = "kd";
25059243Sobrien    tstr[T_kd].long_name = CSAVS(4, 17, "sends cursor down");
25159243Sobrien
25259243Sobrien    tstr[T_kl].name = "kl";
25359243Sobrien    tstr[T_kl].long_name = CSAVS(4, 18, "sends cursor left");
25459243Sobrien
25559243Sobrien    tstr[T_kr].name = "kr";
25659243Sobrien    tstr[T_kr].long_name = CSAVS(4, 19, "sends cursor right");
25759243Sobrien
25859243Sobrien    tstr[T_ku].name = "ku";
25959243Sobrien    tstr[T_ku].long_name = CSAVS(4, 20, "sends cursor up");
26059243Sobrien
26159243Sobrien    tstr[T_md].name = "md";
26259243Sobrien    tstr[T_md].long_name = CSAVS(4, 21, "begin bold");
26359243Sobrien
26459243Sobrien    tstr[T_me].name = "me";
26559243Sobrien    tstr[T_me].long_name = CSAVS(4, 22, "end attributes");
26659243Sobrien
26759243Sobrien    tstr[T_nd].name = "nd";
26859243Sobrien    tstr[T_nd].long_name = CSAVS(4, 23, "non destructive space");
26959243Sobrien
27059243Sobrien    tstr[T_se].name = "se";
27159243Sobrien    tstr[T_se].long_name = CSAVS(4, 24, "end standout");
27259243Sobrien
27359243Sobrien    tstr[T_so].name = "so";
27459243Sobrien    tstr[T_so].long_name = CSAVS(4, 25, "begin standout");
27559243Sobrien
27659243Sobrien    tstr[T_ts].name = "ts";
27759243Sobrien    tstr[T_ts].long_name = CSAVS(4, 26, "cursor to status line");
27859243Sobrien
27959243Sobrien    tstr[T_up].name = "up";
28059243Sobrien    tstr[T_up].long_name = CSAVS(4, 27, "cursor up one");
28159243Sobrien
28259243Sobrien    tstr[T_us].name = "us";
28359243Sobrien    tstr[T_us].long_name = CSAVS(4, 28, "begin underline");
28459243Sobrien
28559243Sobrien    tstr[T_ue].name = "ue";
28659243Sobrien    tstr[T_ue].long_name = CSAVS(4, 29, "end underline");
28759243Sobrien
28859243Sobrien    tstr[T_vb].name = "vb";
28959243Sobrien    tstr[T_vb].long_name = CSAVS(4, 30, "visible bell");
29059243Sobrien
29159243Sobrien    tstr[T_DC].name = "DC";
29259243Sobrien    tstr[T_DC].long_name = CSAVS(4, 31, "delete multiple chars");
29359243Sobrien
29459243Sobrien    tstr[T_DO].name = "DO";
29559243Sobrien    tstr[T_DO].long_name = CSAVS(4, 32, "cursor down multiple");
29659243Sobrien
29759243Sobrien    tstr[T_IC].name = "IC";
29859243Sobrien    tstr[T_IC].long_name = CSAVS(4, 33, "insert multiple chars");
29959243Sobrien
30059243Sobrien    tstr[T_LE].name = "LE";
30159243Sobrien    tstr[T_LE].long_name = CSAVS(4, 34, "cursor left multiple");
30259243Sobrien
30359243Sobrien    tstr[T_RI].name = "RI";
30459243Sobrien    tstr[T_RI].long_name = CSAVS(4, 35, "cursor right multiple");
30559243Sobrien
30659243Sobrien    tstr[T_UP].name = "UP";
30759243Sobrien    tstr[T_UP].long_name = CSAVS(4, 36, "cursor up multiple");
30859243Sobrien
30969408Sache    tstr[T_kh].name = "kh";
310167465Smp    tstr[T_kh].long_name = CSAVS(4, 43, "send cursor home");
31169408Sache
31269408Sache    tstr[T_at7].name = "@7";
313167465Smp    tstr[T_at7].long_name = CSAVS(4, 44, "send cursor end");
31469408Sache
315167465Smp    tstr[T_mr].name = "mr";
316167465Smp    tstr[T_mr].long_name = CSAVS(4, 45, "begin reverse video");
317167465Smp
31859243Sobrien    tstr[T_str].name = NULL;
31959243Sobrien    tstr[T_str].long_name = NULL;
32059243Sobrien
32159243Sobrien
32259243Sobrien    tval[T_am].name = "am";
32359243Sobrien    tval[T_am].long_name = CSAVS(4, 37, "Has automatic margins");
32459243Sobrien
32559243Sobrien    tval[T_pt].name = "pt";
32659243Sobrien    tval[T_pt].long_name = CSAVS(4, 38, "Can use physical tabs");
32759243Sobrien
32859243Sobrien    tval[T_li].name = "li";
32959243Sobrien    tval[T_li].long_name = CSAVS(4, 39, "Number of lines");
33059243Sobrien
33159243Sobrien    tval[T_co].name = "co";
33259243Sobrien    tval[T_co].long_name = CSAVS(4, 40, "Number of columns");
33359243Sobrien
33459243Sobrien    tval[T_km].name = "km";
33559243Sobrien    tval[T_km].long_name = CSAVS(4, 41, "Has meta key");
33659243Sobrien
33759243Sobrien    tval[T_xn].name = "xn";
33859243Sobrien    tval[T_xn].long_name = CSAVS(4, 42, "Newline ignored at right margin");
33959243Sobrien
34059243Sobrien    tval[T_val].name = NULL;
34159243Sobrien    tval[T_val].long_name = NULL;
34259243Sobrien}
34359243Sobrien
34459243Sobrien/*
34559243Sobrien * A very useful table from justin@crim.ca (Justin Bur) :-)
34659243Sobrien * (Modified by per@erix.ericsson.se (Per Hedeland)
34759243Sobrien *  - first (and second:-) case fixed)
34859243Sobrien *
34959243Sobrien * Description     Termcap variables       tcsh behavior
35059243Sobrien * 		   am      xn              UseRightmost    SendCRLF
35159243Sobrien * --------------  ------- -------         ------------    ------------
35259243Sobrien * Automargins     yes     no              yes             no
35359243Sobrien * Magic Margins   yes     yes             yes             no
35459243Sobrien * No Wrap         no      --              yes             yes
35559243Sobrien */
35659243Sobrien
357145479Smpstatic int me_all = 0;		/* does two or more of the attributes use me */
35859243Sobrien
359167465Smpstatic	void	ReBufferDisplay	(void);
360167465Smpstatic	void	TCset		(struct termcapstr *, const char *);
36159243Sobrien
36259243Sobrien
36359243Sobrienstatic void
364167465SmpTCset(struct termcapstr *t, const char *cap)
36559243Sobrien{
36659243Sobrien    if (cap == NULL || *cap == '\0') {
367167465Smp	xfree(t->str);
36859243Sobrien	t->str = NULL;
369167465Smp    } else {
370167465Smp	size_t size;
37159243Sobrien
372167465Smp	size = strlen(cap) + 1;
373167465Smp	t->str = xrealloc(t->str, size);
374167465Smp	memcpy(t->str, cap, size);
37559243Sobrien    }
37659243Sobrien}
37759243Sobrien
37859243Sobrien
37959243Sobrien/*ARGSUSED*/
38059243Sobrienvoid
381167465SmpTellTC(void)
38259243Sobrien{
38359243Sobrien    struct termcapstr *t;
384167465Smp    char *first, *s;
38559243Sobrien
386195609Smp    xprintf("%s", CGETS(7, 1, "\n\tTcsh thinks your terminal has the\n"));
387195609Smp    xprintf("%s", CGETS(7, 2, "\tfollowing characteristics:\n\n"));
38859243Sobrien    xprintf(CGETS(7, 3, "\tIt has %d columns and %d lines\n"),
38959243Sobrien	    Val(T_co), Val(T_li));
390145479Smp    s = strsave(T_HasMeta ? CGETS(7, 5, "a") : CGETS(7, 6, "no"));
391167465Smp    cleanup_push(s, xfree);
392167465Smp    first = s;
393145479Smp    xprintf(CGETS(7, 4, "\tIt has %s meta key\n"), s);
394145479Smp    s = strsave(T_Tabs ? "" : CGETS(7, 8, " not"));
395167465Smp    cleanup_push(s, xfree);
396145479Smp    xprintf(CGETS(7, 7, "\tIt can%s use tabs\n"), s);
397145479Smp    s = strsave((T_Margin&MARGIN_AUTO) ?
398145479Smp		CGETS(7, 10, "has") : CGETS(7, 11, "does not have"));
399167465Smp    cleanup_push(s, xfree);
400145479Smp    xprintf(CGETS(7, 9, "\tIt %s automatic margins\n"), s);
401145479Smp    if (T_Margin & MARGIN_AUTO) {
402145479Smp        s = strsave((T_Margin & MARGIN_MAGIC) ?
403145479Smp			CGETS(7, 10, "has") : CGETS(7, 11, "does not have"));
404167465Smp	cleanup_push(s, xfree);
405145479Smp	xprintf(CGETS(7, 12, "\tIt %s magic margins\n"), s);
406145479Smp    }
407145479Smp    for (t = tstr; t->name != NULL; t++) {
408145479Smp        s = strsave(t->str && *t->str ? t->str : CGETS(7, 13, "(empty)"));
409167465Smp	cleanup_push(s, xfree);
410145479Smp	xprintf("\t%36s (%s) == %s\n", t->long_name, t->name, s);
411167465Smp	cleanup_until(s);
412145479Smp    }
41359243Sobrien    xputchar('\n');
414167465Smp    cleanup_until(first);
41559243Sobrien}
41659243Sobrien
41759243Sobrien
41859243Sobrienstatic void
419167465SmpReBufferDisplay(void)
42059243Sobrien{
421145479Smp    int i;
422145479Smp    Char **b;
42359243Sobrien
42459243Sobrien    b = Display;
42559243Sobrien    Display = NULL;
426167465Smp    blkfree(b);
42759243Sobrien    b = Vdisplay;
42859243Sobrien    Vdisplay = NULL;
429167465Smp    blkfree(b);
43059243Sobrien    TermH = Val(T_co);
431167465Smp    TermV = (INBUFSIZE * 4) / TermH + 1;/*FIXBUF*/
432167465Smp    b = xmalloc(sizeof(*b) * (TermV + 1));
43359243Sobrien    for (i = 0; i < TermV; i++)
434167465Smp	b[i] = xmalloc(sizeof(*b[i]) * (TermH + 1));
43559243Sobrien    b[TermV] = NULL;
43659243Sobrien    Display = b;
437167465Smp    b = xmalloc(sizeof(*b) * (TermV + 1));
43859243Sobrien    for (i = 0; i < TermV; i++)
439167465Smp	b[i] = xmalloc(sizeof(*b[i]) * (TermH + 1));
44059243Sobrien    b[TermV] = NULL;
44159243Sobrien    Vdisplay = b;
44259243Sobrien}
44359243Sobrien
44459243Sobrienvoid
445167465SmpSetTC(char *what, char *how)
44659243Sobrien{
44759243Sobrien    struct termcapstr *ts;
44859243Sobrien    struct termcapval *tv;
44959243Sobrien
45059243Sobrien    /*
45159243Sobrien     * Do the strings first
45259243Sobrien     */
45359243Sobrien    setname("settc");
45459243Sobrien    for (ts = tstr; ts->name != NULL; ts++)
45559243Sobrien	if (strcmp(ts->name, what) == 0)
45659243Sobrien	    break;
45759243Sobrien    if (ts->name != NULL) {
458167465Smp	TCset(ts, how);
45959243Sobrien	/*
46059243Sobrien	 * Reset variables
46159243Sobrien	 */
46259243Sobrien	if (GoodStr(T_me) && GoodStr(T_ue))
46359243Sobrien	    me_all = (strcmp(Str(T_me), Str(T_ue)) == 0);
46459243Sobrien	else
46559243Sobrien	    me_all = 0;
46659243Sobrien	if (GoodStr(T_me) && GoodStr(T_se))
46759243Sobrien	    me_all |= (strcmp(Str(T_me), Str(T_se)) == 0);
46859243Sobrien
46959243Sobrien	T_CanCEOL = GoodStr(T_ce);
47059243Sobrien	T_CanDel = GoodStr(T_dc) || GoodStr(T_DC);
47159243Sobrien	T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC);
47259243Sobrien	T_CanUP = GoodStr(T_up) || GoodStr(T_UP);
47359243Sobrien	return;
47459243Sobrien    }
47559243Sobrien
47659243Sobrien    /*
47759243Sobrien     * Do the numeric ones second
47859243Sobrien     */
47959243Sobrien    for (tv = tval; tv->name != NULL; tv++)
48059243Sobrien	if (strcmp(tv->name, what) == 0)
48159243Sobrien	    break;
48259243Sobrien
48359243Sobrien    if (tv->name != NULL) {
48459243Sobrien	if (tv == &tval[T_pt] || tv == &tval[T_km] ||
48559243Sobrien	    tv == &tval[T_am] || tv == &tval[T_xn]) {
48659243Sobrien	    if (strcmp(how, "yes") == 0)
48759243Sobrien		tv->val = 1;
48859243Sobrien	    else if (strcmp(how, "no") == 0)
48959243Sobrien		tv->val = 0;
49059243Sobrien	    else {
49159243Sobrien		stderror(ERR_SETTCUS, tv->name);
49259243Sobrien		return;
49359243Sobrien	    }
494167465Smp	    T_Tabs = Val(T_pt);
495167465Smp	    T_HasMeta = Val(T_km);
496167465Smp	    T_Margin = Val(T_am) ? MARGIN_AUTO : 0;
497167465Smp	    T_Margin |= Val(T_xn) ? MARGIN_MAGIC : 0;
49859243Sobrien	    if (tv == &tval[T_am] || tv == &tval[T_xn])
49959243Sobrien		ChangeSize(Val(T_li), Val(T_co));
50059243Sobrien	    return;
50159243Sobrien	}
50259243Sobrien	else {
50359243Sobrien	    tv->val = atoi(how);
50459243Sobrien	    T_Cols = (Char) Val(T_co);
50559243Sobrien	    T_Lines = (Char) Val(T_li);
50659243Sobrien	    if (tv == &tval[T_co] || tv == &tval[T_li])
50759243Sobrien		ChangeSize(Val(T_li), Val(T_co));
50859243Sobrien	    return;
50959243Sobrien	}
51059243Sobrien    }
51159243Sobrien    stderror(ERR_NAME | ERR_TCCAP, what);
51259243Sobrien    return;
51359243Sobrien}
51459243Sobrien
51559243Sobrien
51659243Sobrien/*
51759243Sobrien * Print the termcap string out with variable substitution
51859243Sobrien */
51959243Sobrienvoid
520167465SmpEchoTC(Char **v)
52159243Sobrien{
522167465Smp    char   *cap, *scap, *cv;
52359243Sobrien    int     arg_need, arg_cols, arg_rows;
52459243Sobrien    int     verbose = 0, silent = 0;
52559243Sobrien    char   *area;
526167465Smp    static const char fmts[] = "%s\n", fmtd[] = "%d\n";
52759243Sobrien    struct termcapstr *t;
52859243Sobrien    char    buf[TC_BUFSIZE];
529167465Smp    Char **globbed;
53059243Sobrien
53159243Sobrien    area = buf;
53259243Sobrien
53359243Sobrien    setname("echotc");
53459243Sobrien
535167465Smp    v = glob_all_or_error(v);
536167465Smp    globbed = v;
537167465Smp    cleanup_push(globbed, blk_cleanup);
53859243Sobrien
53959243Sobrien    if (!*v || *v[0] == '\0')
540167465Smp	goto end;
54159243Sobrien    if (v[0][0] == '-') {
54259243Sobrien	switch (v[0][1]) {
54359243Sobrien	case 'v':
54459243Sobrien	    verbose = 1;
54559243Sobrien	    break;
54659243Sobrien	case 's':
54759243Sobrien	    silent = 1;
54859243Sobrien	    break;
54959243Sobrien	default:
55059243Sobrien	    stderror(ERR_NAME | ERR_TCUSAGE);
55159243Sobrien	    break;
55259243Sobrien	}
55359243Sobrien	v++;
55459243Sobrien    }
55559243Sobrien    if (!*v || *v[0] == '\0')
556167465Smp	goto end;
557167465Smp    cv = strsave(short2str(*v));
558167465Smp    cleanup_push(cv, xfree);
55959243Sobrien    if (strcmp(cv, "tabs") == 0) {
56059243Sobrien	xprintf(fmts, T_Tabs ? CGETS(7, 14, "yes") :
56159243Sobrien		CGETS(7, 15, "no"));
562167465Smp	goto end_flush;
56359243Sobrien    }
56459243Sobrien    else if (strcmp(cv, "meta") == 0) {
56559243Sobrien	xprintf(fmts, Val(T_km) ? CGETS(7, 14, "yes") :
56659243Sobrien		CGETS(7, 15, "no"));
567167465Smp	goto end_flush;
56859243Sobrien    }
56959243Sobrien    else if (strcmp(cv, "xn") == 0) {
57059243Sobrien	xprintf(fmts, T_Margin & MARGIN_MAGIC ? CGETS(7, 14, "yes") :
57159243Sobrien		CGETS(7, 15,  "no"));
572167465Smp	goto end_flush;
57359243Sobrien    }
57459243Sobrien    else if (strcmp(cv, "am") == 0) {
57559243Sobrien	xprintf(fmts, T_Margin & MARGIN_AUTO ? CGETS(7, 14, "yes") :
57659243Sobrien		CGETS(7, 15, "no"));
577167465Smp	goto end_flush;
57859243Sobrien    }
57959243Sobrien    else if (strcmp(cv, "baud") == 0) {
58059243Sobrien	int     i;
58159243Sobrien
58259243Sobrien	for (i = 0; baud_rate[i].b_name != NULL; i++)
58359243Sobrien	    if (T_Speed == baud_rate[i].b_rate) {
58459243Sobrien		xprintf(fmts, baud_rate[i].b_name);
585167465Smp		goto end_flush;
58659243Sobrien	    }
58759243Sobrien	xprintf(fmtd, 0);
588167465Smp	goto end_flush;
58959243Sobrien    }
590167465Smp    else if (strcmp(cv, "rows") == 0 || strcmp(cv, "lines") == 0 ||
591167465Smp	strcmp(cv, "li") == 0) {
59259243Sobrien	xprintf(fmtd, Val(T_li));
593167465Smp	goto end_flush;
59459243Sobrien    }
595167465Smp    else if (strcmp(cv, "cols") == 0 || strcmp(cv, "co") == 0) {
59659243Sobrien	xprintf(fmtd, Val(T_co));
597167465Smp	goto end_flush;
59859243Sobrien    }
59959243Sobrien
60059243Sobrien    /*
60159243Sobrien     * Try to use our local definition first
60259243Sobrien     */
60359243Sobrien    scap = NULL;
60459243Sobrien    for (t = tstr; t->name != NULL; t++)
60559243Sobrien	if (strcmp(t->name, cv) == 0) {
60659243Sobrien	    scap = t->str;
60759243Sobrien	    break;
60859243Sobrien	}
60959243Sobrien    if (t->name == NULL)
61059243Sobrien	scap = tgetstr(cv, &area);
61159243Sobrien    if (!scap || scap[0] == '\0') {
61259243Sobrien	if (tgetflag(cv)) {
613195609Smp	    xprintf("%s", CGETS(7, 14, "yes\n"));
614167465Smp	    goto end;
61559243Sobrien	}
61659243Sobrien	if (silent)
617167465Smp	    goto end;
61859243Sobrien	else
61959243Sobrien	    stderror(ERR_NAME | ERR_TCCAP, cv);
62059243Sobrien    }
62159243Sobrien
62259243Sobrien    /*
62359243Sobrien     * Count home many values we need for this capability.
62459243Sobrien     */
62559243Sobrien    for (cap = scap, arg_need = 0; *cap; cap++)
62659243Sobrien	if (*cap == '%')
62759243Sobrien	    switch (*++cap) {
62859243Sobrien	    case 'd':
62959243Sobrien	    case '2':
63059243Sobrien	    case '3':
63159243Sobrien	    case '.':
63259243Sobrien	    case '+':
63359243Sobrien		arg_need++;
63459243Sobrien		break;
63559243Sobrien	    case '%':
63659243Sobrien	    case '>':
63759243Sobrien	    case 'i':
63859243Sobrien	    case 'r':
63959243Sobrien	    case 'n':
64059243Sobrien	    case 'B':
64159243Sobrien	    case 'D':
64259243Sobrien		break;
64359243Sobrien	    default:
64459243Sobrien		/*
64559243Sobrien		 * hpux has lot's of them...
64659243Sobrien		 */
64759243Sobrien		if (verbose)
64859243Sobrien		    stderror(ERR_NAME | ERR_TCPARM, *cap);
64959243Sobrien		/* This is bad, but I won't complain */
65059243Sobrien		break;
65159243Sobrien	    }
65259243Sobrien
65359243Sobrien    switch (arg_need) {
65459243Sobrien    case 0:
65559243Sobrien	v++;
65659243Sobrien	if (*v && *v[0]) {
65759243Sobrien	    if (silent)
658167465Smp		goto end;
65959243Sobrien	    else
66059243Sobrien		stderror(ERR_NAME | ERR_TCARGS, cv, arg_need);
66159243Sobrien	}
66259243Sobrien	(void) tputs(scap, 1, PUTRAW);
66359243Sobrien	break;
66459243Sobrien    case 1:
66559243Sobrien	v++;
66659243Sobrien	if (!*v || *v[0] == '\0')
66759243Sobrien	    stderror(ERR_NAME | ERR_TCNARGS, cv, 1);
66859243Sobrien	arg_cols = 0;
66959243Sobrien	arg_rows = atoi(short2str(*v));
67059243Sobrien	v++;
67159243Sobrien	if (*v && *v[0]) {
67259243Sobrien	    if (silent)
673167465Smp		goto end;
67459243Sobrien	    else
67559243Sobrien		stderror(ERR_NAME | ERR_TCARGS, cv, arg_need);
67659243Sobrien	}
67759243Sobrien	(void) tputs(tgoto(scap, arg_cols, arg_rows), 1, PUTRAW);
67859243Sobrien	break;
67959243Sobrien    default:
68059243Sobrien	/* This is wrong, but I will ignore it... */
68159243Sobrien	if (verbose)
68259243Sobrien	    stderror(ERR_NAME | ERR_TCARGS, cv, arg_need);
68359243Sobrien	/*FALLTHROUGH*/
68459243Sobrien    case 2:
68559243Sobrien	v++;
68659243Sobrien	if (!*v || *v[0] == '\0') {
68759243Sobrien	    if (silent)
688167465Smp		goto end;
68959243Sobrien	    else
69059243Sobrien		stderror(ERR_NAME | ERR_TCNARGS, cv, 2);
69159243Sobrien	}
69259243Sobrien	arg_cols = atoi(short2str(*v));
69359243Sobrien	v++;
69459243Sobrien	if (!*v || *v[0] == '\0') {
69559243Sobrien	    if (silent)
696167465Smp		goto end;
69759243Sobrien	    else
69859243Sobrien		stderror(ERR_NAME | ERR_TCNARGS, cv, 2);
69959243Sobrien	}
70059243Sobrien	arg_rows = atoi(short2str(*v));
70159243Sobrien	v++;
70259243Sobrien	if (*v && *v[0]) {
70359243Sobrien	    if (silent)
704167465Smp		goto end;
70559243Sobrien	    else
70659243Sobrien		stderror(ERR_NAME | ERR_TCARGS, cv, arg_need);
70759243Sobrien	}
70859243Sobrien	(void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows, PUTRAW);
70959243Sobrien	break;
71059243Sobrien    }
711167465Smp end_flush:
71259243Sobrien    flush();
713167465Smp end:
714167465Smp    cleanup_until(globbed);
71559243Sobrien}
71659243Sobrien
717145479Smpint    GotTermCaps = 0;
71859243Sobrien
71959243Sobrienstatic struct {
72059243Sobrien    Char   *name;
72159243Sobrien    int     key;
72259243Sobrien    XmapVal fun;
72359243Sobrien    int	    type;
72459243Sobrien} arrow[] = {
72559243Sobrien#define A_K_DN	0
726145479Smp    { STRdown,	T_kd, { 0 }, 0 },
72759243Sobrien#define A_K_UP	1
728145479Smp    { STRup,	T_ku, { 0 }, 0 },
72959243Sobrien#define A_K_LT	2
730145479Smp    { STRleft,	T_kl, { 0 }, 0 },
73159243Sobrien#define A_K_RT	3
732145479Smp    { STRright, T_kr, { 0 }, 0 },
73369408Sache#define A_K_HO  4
734145479Smp    { STRhome,  T_kh, { 0 }, 0 },
73569408Sache#define A_K_EN  5
736145479Smp    { STRend,   T_at7, { 0 }, 0}
73759243Sobrien};
73869408Sache#define A_K_NKEYS 6
73959243Sobrien
74059243Sobrienvoid
741167465SmpResetArrowKeys(void)
74259243Sobrien{
74359243Sobrien    arrow[A_K_DN].fun.cmd = F_DOWN_HIST;
74459243Sobrien    arrow[A_K_DN].type    = XK_CMD;
74559243Sobrien
74659243Sobrien    arrow[A_K_UP].fun.cmd = F_UP_HIST;
74759243Sobrien    arrow[A_K_UP].type    = XK_CMD;
74859243Sobrien
74959243Sobrien    arrow[A_K_LT].fun.cmd = F_CHARBACK;
75059243Sobrien    arrow[A_K_LT].type    = XK_CMD;
75159243Sobrien
75259243Sobrien    arrow[A_K_RT].fun.cmd = F_CHARFWD;
75359243Sobrien    arrow[A_K_RT].type    = XK_CMD;
75459243Sobrien
75569408Sache    arrow[A_K_HO].fun.cmd = F_TOBEG;
75669408Sache    arrow[A_K_HO].type    = XK_CMD;
75769408Sache
75869408Sache    arrow[A_K_EN].fun.cmd = F_TOEND;
75969408Sache    arrow[A_K_EN].type    = XK_CMD;
76059243Sobrien}
76159243Sobrien
76259243Sobrienvoid
763167465SmpDefaultArrowKeys(void)
76459243Sobrien{
76559243Sobrien    static Char strA[] = {033, '[', 'A', '\0'};
76659243Sobrien    static Char strB[] = {033, '[', 'B', '\0'};
76759243Sobrien    static Char strC[] = {033, '[', 'C', '\0'};
76859243Sobrien    static Char strD[] = {033, '[', 'D', '\0'};
76969408Sache    static Char strH[] = {033, '[', 'H', '\0'};
77069408Sache    static Char strF[] = {033, '[', 'F', '\0'};
77159243Sobrien    static Char stOA[] = {033, 'O', 'A', '\0'};
77259243Sobrien    static Char stOB[] = {033, 'O', 'B', '\0'};
77359243Sobrien    static Char stOC[] = {033, 'O', 'C', '\0'};
77459243Sobrien    static Char stOD[] = {033, 'O', 'D', '\0'};
77569408Sache    static Char stOH[] = {033, 'O', 'H', '\0'};
77669408Sache    static Char stOF[] = {033, 'O', 'F', '\0'};
77759243Sobrien
77859243Sobrien    CStr cs;
77969408Sache#ifndef IS_ASCII
78059243Sobrien    if (strA[0] == 033)
78159243Sobrien    {
78259243Sobrien	strA[0] = CTL_ESC('\033');
78359243Sobrien	strB[0] = CTL_ESC('\033');
78459243Sobrien	strC[0] = CTL_ESC('\033');
78559243Sobrien	strD[0] = CTL_ESC('\033');
78669408Sache	strH[0] = CTL_ESC('\033');
78769408Sache	strF[0] = CTL_ESC('\033');
78859243Sobrien	stOA[0] = CTL_ESC('\033');
78959243Sobrien	stOB[0] = CTL_ESC('\033');
79059243Sobrien	stOC[0] = CTL_ESC('\033');
79159243Sobrien	stOD[0] = CTL_ESC('\033');
79269408Sache	stOH[0] = CTL_ESC('\033');
79369408Sache	stOF[0] = CTL_ESC('\033');
79459243Sobrien    }
79559243Sobrien#endif
79659243Sobrien
79759243Sobrien    cs.len = 3;
79859243Sobrien
79959243Sobrien    cs.buf = strA; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
80059243Sobrien    cs.buf = strB; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
80159243Sobrien    cs.buf = strC; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
80259243Sobrien    cs.buf = strD; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
80369408Sache    cs.buf = strH; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
80469408Sache    cs.buf = strF; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
80559243Sobrien    cs.buf = stOA; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
80659243Sobrien    cs.buf = stOB; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
80759243Sobrien    cs.buf = stOC; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
80859243Sobrien    cs.buf = stOD; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
80969408Sache    cs.buf = stOH; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
81069408Sache    cs.buf = stOF; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
81169408Sache
81259243Sobrien    if (VImode) {
81359243Sobrien	cs.len = 2;
81459243Sobrien	cs.buf = &strA[1]; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
81559243Sobrien	cs.buf = &strB[1]; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
81659243Sobrien	cs.buf = &strC[1]; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
81759243Sobrien	cs.buf = &strD[1]; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
81869408Sache	cs.buf = &strH[1]; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
81969408Sache	cs.buf = &strF[1]; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
82059243Sobrien	cs.buf = &stOA[1]; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
82159243Sobrien	cs.buf = &stOB[1]; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
82259243Sobrien	cs.buf = &stOC[1]; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
82359243Sobrien	cs.buf = &stOD[1]; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
82469408Sache	cs.buf = &stOH[1]; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
82569408Sache	cs.buf = &stOF[1]; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
82659243Sobrien    }
82759243Sobrien}
82859243Sobrien
82959243Sobrien
83059243Sobrienint
831167465SmpSetArrowKeys(const CStr *name, XmapVal *fun, int type)
83259243Sobrien{
83359243Sobrien    int i;
83469408Sache    for (i = 0; i < A_K_NKEYS; i++)
83559243Sobrien	if (Strcmp(name->buf, arrow[i].name) == 0) {
83659243Sobrien	    arrow[i].fun  = *fun;
83759243Sobrien	    arrow[i].type = type;
83859243Sobrien	    return 0;
83959243Sobrien	}
84059243Sobrien    return -1;
84159243Sobrien}
84259243Sobrien
84359243Sobrienint
844167465SmpIsArrowKey(Char *name)
84559243Sobrien{
84659243Sobrien    int i;
84769408Sache    for (i = 0; i < A_K_NKEYS; i++)
84859243Sobrien	if (Strcmp(name, arrow[i].name) == 0)
84959243Sobrien	    return 1;
85059243Sobrien    return 0;
85159243Sobrien}
85259243Sobrien
85359243Sobrienint
854167465SmpClearArrowKeys(const CStr *name)
85559243Sobrien{
85659243Sobrien    int i;
85769408Sache    for (i = 0; i < A_K_NKEYS; i++)
85859243Sobrien	if (Strcmp(name->buf, arrow[i].name) == 0) {
85959243Sobrien	    arrow[i].type = XK_NOD;
86059243Sobrien	    return 0;
86159243Sobrien	}
86259243Sobrien    return -1;
86359243Sobrien}
86459243Sobrien
86559243Sobrienvoid
866167465SmpPrintArrowKeys(const CStr *name)
86759243Sobrien{
86859243Sobrien    int i;
86959243Sobrien
87069408Sache    for (i = 0; i < A_K_NKEYS; i++)
87159243Sobrien	if (name->len == 0 || Strcmp(name->buf, arrow[i].name) == 0)
872167465Smp	    if (arrow[i].type != XK_NOD)
873167465Smp		printOne(arrow[i].name, &arrow[i].fun, arrow[i].type);
87459243Sobrien}
87559243Sobrien
87659243Sobrien
87759243Sobrienvoid
878167465SmpBindArrowKeys(void)
87959243Sobrien{
88059243Sobrien    KEYCMD *map, *dmap;
88159243Sobrien    int     i, j;
88259243Sobrien    char   *p;
88359243Sobrien    CStr    cs;
88459243Sobrien
88559243Sobrien    if (!GotTermCaps)
88659243Sobrien	return;
88759243Sobrien    map = VImode ? CcAltMap : CcKeyMap;
88859243Sobrien    dmap = VImode ? CcViCmdMap : CcEmacsMap;
88959243Sobrien
89059243Sobrien    DefaultArrowKeys();
89159243Sobrien
89269408Sache    for (i = 0; i < A_K_NKEYS; i++) {
89359243Sobrien	p = tstr[arrow[i].key].str;
89459243Sobrien	if (p && *p) {
89559243Sobrien	    j = (unsigned char) *p;
89659243Sobrien	    cs.buf = str2short(p);
89759243Sobrien	    cs.len = Strlen(cs.buf);
89859243Sobrien	    /*
89959243Sobrien	     * Assign the arrow keys only if:
90059243Sobrien	     *
90159243Sobrien	     * 1. They are multi-character arrow keys and the user
90259243Sobrien	     *    has not re-assigned the leading character, or
90359243Sobrien	     *    has re-assigned the leading character to be F_XKEY
90459243Sobrien	     * 2. They are single arrow keys pointing to an unassigned key.
90559243Sobrien	     */
90659243Sobrien	    if (arrow[i].type == XK_NOD) {
90759243Sobrien		ClearXkey(map, &cs);
90859243Sobrien	    }
90959243Sobrien	    else {
91059243Sobrien		if (p[1] && (dmap[j] == map[j] || map[j] == F_XKEY)) {
91159243Sobrien		    AddXkey(&cs, &arrow[i].fun, arrow[i].type);
91259243Sobrien		    map[j] = F_XKEY;
91359243Sobrien		}
91459243Sobrien		else if (map[j] == F_UNASSIGNED) {
91559243Sobrien		    ClearXkey(map, &cs);
91659243Sobrien		    if (arrow[i].type == XK_CMD)
91759243Sobrien			map[j] = arrow[i].fun.cmd;
91859243Sobrien		    else
91959243Sobrien			AddXkey(&cs, &arrow[i].fun, arrow[i].type);
92059243Sobrien		}
92159243Sobrien	    }
92259243Sobrien	}
92359243Sobrien    }
92459243Sobrien}
92559243Sobrien
92659243Sobrienstatic Char cur_atr = 0;	/* current attributes */
92759243Sobrien
92859243Sobrienvoid
929167465SmpSetAttributes(Char atr)
93059243Sobrien{
93159243Sobrien    atr &= ATTRIBUTES;
93259243Sobrien    if (atr != cur_atr) {
93359243Sobrien	if (me_all && GoodStr(T_me)) {
93459243Sobrien	    if (((cur_atr & BOLD) && !(atr & BOLD)) ||
93559243Sobrien		((cur_atr & UNDER) && !(atr & UNDER)) ||
93659243Sobrien		((cur_atr & STANDOUT) && !(atr & STANDOUT))) {
93759243Sobrien		(void) tputs(Str(T_me), 1, PUTPURE);
93859243Sobrien		cur_atr = 0;
93959243Sobrien	    }
94059243Sobrien	}
94159243Sobrien	if ((atr & BOLD) != (cur_atr & BOLD)) {
94259243Sobrien	    if (atr & BOLD) {
94359243Sobrien		if (GoodStr(T_md) && GoodStr(T_me)) {
94459243Sobrien		    (void) tputs(Str(T_md), 1, PUTPURE);
94559243Sobrien		    cur_atr |= BOLD;
94659243Sobrien		}
94759243Sobrien	    }
94859243Sobrien	    else {
94959243Sobrien		if (GoodStr(T_md) && GoodStr(T_me)) {
95059243Sobrien		    (void) tputs(Str(T_me), 1, PUTPURE);
95159243Sobrien		    if ((cur_atr & STANDOUT) && GoodStr(T_se)) {
95259243Sobrien			(void) tputs(Str(T_se), 1, PUTPURE);
95359243Sobrien			cur_atr &= ~STANDOUT;
95459243Sobrien		    }
95559243Sobrien		    if ((cur_atr & UNDER) && GoodStr(T_ue)) {
95659243Sobrien			(void) tputs(Str(T_ue), 1, PUTPURE);
95759243Sobrien			cur_atr &= ~UNDER;
95859243Sobrien		    }
95959243Sobrien		    cur_atr &= ~BOLD;
96059243Sobrien		}
96159243Sobrien	    }
96259243Sobrien	}
96359243Sobrien	if ((atr & STANDOUT) != (cur_atr & STANDOUT)) {
96459243Sobrien	    if (atr & STANDOUT) {
96559243Sobrien		if (GoodStr(T_so) && GoodStr(T_se)) {
96659243Sobrien		    (void) tputs(Str(T_so), 1, PUTPURE);
96759243Sobrien		    cur_atr |= STANDOUT;
96859243Sobrien		}
96959243Sobrien	    }
97059243Sobrien	    else {
97159243Sobrien		if (GoodStr(T_se)) {
97259243Sobrien		    (void) tputs(Str(T_se), 1, PUTPURE);
97359243Sobrien		    cur_atr &= ~STANDOUT;
97459243Sobrien		}
97559243Sobrien	    }
97659243Sobrien	}
97759243Sobrien	if ((atr & UNDER) != (cur_atr & UNDER)) {
97859243Sobrien	    if (atr & UNDER) {
97959243Sobrien		if (GoodStr(T_us) && GoodStr(T_ue)) {
98059243Sobrien		    (void) tputs(Str(T_us), 1, PUTPURE);
98159243Sobrien		    cur_atr |= UNDER;
98259243Sobrien		}
98359243Sobrien	    }
98459243Sobrien	    else {
98559243Sobrien		if (GoodStr(T_ue)) {
98659243Sobrien		    (void) tputs(Str(T_ue), 1, PUTPURE);
98759243Sobrien		    cur_atr &= ~UNDER;
98859243Sobrien		}
98959243Sobrien	    }
99059243Sobrien	}
99159243Sobrien    }
99259243Sobrien}
99359243Sobrien
994167465Smpint highlighting = 0;
995167465Smp
996167465Smpvoid
997167465SmpStartHighlight()
998167465Smp{
999167465Smp    (void) tputs(Str(T_mr), 1, PUTPURE);
1000167465Smp    highlighting = 1;
1001167465Smp}
1002167465Smp
1003167465Smpvoid
1004167465SmpStopHighlight()
1005167465Smp{
1006167465Smp    (void) tputs(Str(T_me), 1, PUTPURE);
1007167465Smp    highlighting = 0;
1008167465Smp}
1009167465Smp
101059243Sobrien/* PWP 6-27-88 -- if the tty driver thinks that we can tab, we ask termcap */
101159243Sobrienint
1012167465SmpCanWeTab(void)
101359243Sobrien{
101459243Sobrien    return (Val(T_pt));
101559243Sobrien}
101659243Sobrien
1017167465Smp/* move to line <where> (first line == 0) as efficiently as possible; */
101859243Sobrienvoid
1019167465SmpMoveToLine(int where)
102059243Sobrien{
102159243Sobrien    int     del;
102259243Sobrien
102359243Sobrien    if (where == CursorV)
102459243Sobrien	return;
102559243Sobrien
102659243Sobrien    if (where > TermV) {
102759243Sobrien#ifdef DEBUG_SCREEN
102859243Sobrien	xprintf("MoveToLine: where is ridiculous: %d\r\n", where);
102959243Sobrien	flush();
103059243Sobrien#endif /* DEBUG_SCREEN */
103159243Sobrien	return;
103259243Sobrien    }
103359243Sobrien
103459243Sobrien    del = where - CursorV;
103559243Sobrien
103659243Sobrien    if (del > 0) {
103759243Sobrien	while (del > 0) {
103859243Sobrien	    if ((T_Margin & MARGIN_AUTO) && Display[CursorV][0] != '\0') {
1039145479Smp		size_t h;
1040145479Smp
1041145479Smp		for (h = TermH - 1; h > 0 && Display[CursorV][h] == CHAR_DBWIDTH;
1042145479Smp		     h--)
1043145479Smp		    ;
104459243Sobrien		/* move without newline */
1045145479Smp		MoveToChar(h);
1046145479Smp		so_write(&Display[CursorV][CursorH], TermH - CursorH); /* updates CursorH/V*/
104759243Sobrien		del--;
104859243Sobrien	    }
104959243Sobrien	    else {
105059243Sobrien		if ((del > 1) && GoodStr(T_DO)) {
105159243Sobrien		    (void) tputs(tgoto(Str(T_DO), del, del), del, PUTPURE);
105259243Sobrien		    del = 0;
105359243Sobrien		}
105459243Sobrien		else {
105559243Sobrien		    for ( ; del > 0; del--)
105659243Sobrien			(void) putraw('\n');
105759243Sobrien		    CursorH = 0;	/* because the \n will become \r\n */
105859243Sobrien		}
105959243Sobrien	    }
106059243Sobrien	}
106159243Sobrien    }
106259243Sobrien    else {			/* del < 0 */
106359243Sobrien	if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up)))
106459243Sobrien	    (void) tputs(tgoto(Str(T_UP), -del, -del), -del, PUTPURE);
106559243Sobrien	else {
106659243Sobrien	    int i;
106759243Sobrien	    if (GoodStr(T_up))
106859243Sobrien		for (i = 0; i < -del; i++)
106959243Sobrien		    (void) tputs(Str(T_up), 1, PUTPURE);
107059243Sobrien	}
107159243Sobrien    }
107259243Sobrien    CursorV = where;		/* now where is here */
107359243Sobrien}
107459243Sobrien
107559243Sobrienvoid
1076167465SmpMoveToChar(int where)		/* move to character position (where) */
107759243Sobrien{				/* as efficiently as possible */
107859243Sobrien    int     del;
107959243Sobrien
108059243Sobrienmc_again:
108159243Sobrien    if (where == CursorH)
108259243Sobrien	return;
108359243Sobrien
108459243Sobrien    if (where >= TermH) {
108559243Sobrien#ifdef DEBUG_SCREEN
108659243Sobrien	xprintf("MoveToChar: where is riduculous: %d\r\n", where);
108759243Sobrien	flush();
108859243Sobrien#endif /* DEBUG_SCREEN */
108959243Sobrien	return;
109059243Sobrien    }
109159243Sobrien
109259243Sobrien    if (!where) {		/* if where is first column */
109359243Sobrien	(void) putraw('\r');	/* do a CR */
109459243Sobrien	CursorH = 0;
109559243Sobrien	return;
109659243Sobrien    }
109759243Sobrien
109859243Sobrien    del = where - CursorH;
109959243Sobrien
110059243Sobrien    if ((del < -4 || del > 4) && GoodStr(T_ch))
110159243Sobrien	/* go there directly */
110259243Sobrien	(void) tputs(tgoto(Str(T_ch), where, where), where, PUTPURE);
110359243Sobrien    else {
110459243Sobrien	int i;
110559243Sobrien	if (del > 0) {		/* moving forward */
110659243Sobrien	    if ((del > 4) && GoodStr(T_RI))
110759243Sobrien		(void) tputs(tgoto(Str(T_RI), del, del), del, PUTPURE);
110859243Sobrien	    else {
110969408Sache		/* if I can do tabs, use them */
1110145479Smp		if (T_Tabs) {
1111145479Smp		    if ((CursorH & 0370) != (where & ~0x7)
1112145479Smp			&& Display[CursorV][where & ~0x7] != CHAR_DBWIDTH) {
111359243Sobrien			/* if not within tab stop */
1114145479Smp			for (i = (CursorH & 0370); i < (where & ~0x7); i += 8)
111559243Sobrien			    (void) putraw('\t');	/* then tab over */
1116145479Smp			CursorH = where & ~0x7;
111759243Sobrien			/* Note: considering that we often want to go to
111859243Sobrien			   TermH - 1 for the wrapping, it would be nice to
111959243Sobrien			   optimize this case by tabbing to the last column
112059243Sobrien			   - but this doesn't work for all terminals! */
112159243Sobrien		    }
112259243Sobrien		}
112359243Sobrien		/* it's usually cheaper to just write the chars, so we do. */
112459243Sobrien
112559243Sobrien		/* NOTE THAT so_write() WILL CHANGE CursorH!!! */
112659243Sobrien		so_write(&Display[CursorV][CursorH], where - CursorH);
112759243Sobrien
112859243Sobrien	    }
112959243Sobrien	}
113059243Sobrien	else {			/* del < 0 := moving backward */
113159243Sobrien	    if ((-del > 4) && GoodStr(T_LE))
113259243Sobrien		(void) tputs(tgoto(Str(T_LE), -del, -del), -del, PUTPURE);
113359243Sobrien	    else {		/* can't go directly there */
113459243Sobrien		/* if the "cost" is greater than the "cost" from col 0 */
113559243Sobrien		if (T_Tabs ? (-del > ((where >> 3) + (where & 07)))
113659243Sobrien		    : (-del > where)) {
113759243Sobrien		    (void) putraw('\r');	/* do a CR */
113859243Sobrien		    CursorH = 0;
113959243Sobrien		    goto mc_again;	/* and try again */
114059243Sobrien		}
114159243Sobrien		for (i = 0; i < -del; i++)
114259243Sobrien		    (void) putraw('\b');
114359243Sobrien	    }
114459243Sobrien	}
114559243Sobrien    }
114659243Sobrien    CursorH = where;		/* now where is here */
114759243Sobrien}
114859243Sobrien
114959243Sobrienvoid
1150167465Smpso_write(Char *cp, int n)
115159243Sobrien{
1152167465Smp    int cur_pos, prompt_len = 0, region_start = 0, region_end = 0;
1153167465Smp
115459243Sobrien    if (n <= 0)
115559243Sobrien	return;			/* catch bugs */
115659243Sobrien
115759243Sobrien    if (n > TermH) {
115859243Sobrien#ifdef DEBUG_SCREEN
115959243Sobrien	xprintf("so_write: n is riduculous: %d\r\n", n);
116059243Sobrien	flush();
116159243Sobrien#endif /* DEBUG_SCREEN */
116259243Sobrien	return;
116359243Sobrien    }
116459243Sobrien
1165167465Smp    if (adrof(STRhighlight)) {
1166167465Smp	/* find length of prompt */
1167167465Smp	Char *promptc;
1168167465Smp	for (promptc = Prompt; *promptc; promptc++);
1169167465Smp	prompt_len = promptc - Prompt;
1170167465Smp
1171167465Smp	/* find region start and end points */
1172167465Smp	if (IncMatchLen) {
1173167465Smp	    region_start = (Cursor - InputBuf) + prompt_len;
1174167465Smp	    region_end = region_start + IncMatchLen;
1175167465Smp	} else if (MarkIsSet) {
1176167465Smp	    region_start = (min(Cursor, Mark) - InputBuf) + prompt_len;
1177167465Smp	    region_end   = (max(Cursor, Mark) - InputBuf) + prompt_len;
1178167465Smp	}
1179167465Smp    }
1180167465Smp
118159243Sobrien    do {
1182167465Smp	if (adrof(STRhighlight)) {
1183167465Smp	    cur_pos = CursorV * TermH + CursorH;
1184167465Smp	    if (!highlighting &&
1185167465Smp		cur_pos >= region_start && cur_pos < region_end)
1186167465Smp		StartHighlight();
1187167465Smp	    else if (highlighting && cur_pos >= region_end)
1188167465Smp		StopHighlight();
1189167465Smp
1190167465Smp	    /* don't highlight over the cursor. the highlighting's reverse
1191167465Smp	     * video would cancel it out. :P */
1192167465Smp	    if (highlighting && cur_pos == (Cursor - InputBuf) + prompt_len)
1193167465Smp		StopHighlight();
1194167465Smp	}
1195167465Smp
1196145479Smp	if (*cp != CHAR_DBWIDTH) {
1197145479Smp	    if (*cp & LITERAL) {
1198145479Smp		Char   *d;
119959243Sobrien#ifdef DEBUG_LITERAL
1200145479Smp		xprintf("so: litnum %d\r\n", (int)(*cp & ~LITERAL));
120159243Sobrien#endif /* DEBUG_LITERAL */
1202145479Smp		for (d = litptr + (*cp & ~LITERAL) * LIT_FACTOR; *d; d++)
1203145479Smp		    (void) putwraw(*d);
1204145479Smp	    }
1205145479Smp	    else
1206145479Smp		(void) putwraw(*cp);
120759243Sobrien	}
1208145479Smp	cp++;
120959243Sobrien	CursorH++;
121059243Sobrien    } while (--n);
121159243Sobrien
1212167465Smp    if (adrof(STRhighlight) && highlighting)
1213167465Smp	StopHighlight();
1214167465Smp
121559243Sobrien    if (CursorH >= TermH) { /* wrap? */
121659243Sobrien	if (T_Margin & MARGIN_AUTO) { /* yes */
121759243Sobrien	    CursorH = 0;
121859243Sobrien	    CursorV++;
121959243Sobrien	    if (T_Margin & MARGIN_MAGIC) {
122059243Sobrien		/* force the wrap to avoid the "magic" situation */
1221167465Smp		Char xc;
1222167465Smp		if ((xc = Display[CursorV][CursorH]) != '\0') {
1223167465Smp		    so_write(&xc, 1);
1224145479Smp		    while(Display[CursorV][CursorH] == CHAR_DBWIDTH)
1225145479Smp			CursorH++;
1226145479Smp		}
1227145479Smp		else {
122859243Sobrien		    (void) putraw(' ');
1229145479Smp		    CursorH = 1;
1230145479Smp		}
123159243Sobrien	    }
123259243Sobrien	}
123359243Sobrien	else			/* no wrap, but cursor stays on screen */
123459243Sobrien	    CursorH = TermH - 1;
123559243Sobrien    }
123659243Sobrien}
123759243Sobrien
123859243Sobrien
123959243Sobrienvoid
1240167465SmpDeleteChars(int num)		/* deletes <num> characters */
124159243Sobrien{
124259243Sobrien    if (num <= 0)
124359243Sobrien	return;
124459243Sobrien
124559243Sobrien    if (!T_CanDel) {
124659243Sobrien#ifdef DEBUG_EDIT
124759243Sobrien	xprintf(CGETS(7, 16, "ERROR: cannot delete\r\n"));
124859243Sobrien#endif /* DEBUG_EDIT */
124959243Sobrien	flush();
125059243Sobrien	return;
125159243Sobrien    }
125259243Sobrien
125359243Sobrien    if (num > TermH) {
125459243Sobrien#ifdef DEBUG_SCREEN
125559243Sobrien	xprintf(CGETS(7, 17, "DeleteChars: num is riduculous: %d\r\n"), num);
125659243Sobrien	flush();
125759243Sobrien#endif /* DEBUG_SCREEN */
125859243Sobrien	return;
125959243Sobrien    }
126059243Sobrien
126159243Sobrien    if (GoodStr(T_DC))		/* if I have multiple delete */
126259243Sobrien	if ((num > 1) || !GoodStr(T_dc)) {	/* if dc would be more expen. */
126359243Sobrien	    (void) tputs(tgoto(Str(T_DC), num, num), num, PUTPURE);
126459243Sobrien	    return;
126559243Sobrien	}
126659243Sobrien
126759243Sobrien    if (GoodStr(T_dm))		/* if I have delete mode */
126859243Sobrien	(void) tputs(Str(T_dm), 1, PUTPURE);
126959243Sobrien
127059243Sobrien    if (GoodStr(T_dc))		/* else do one at a time */
127159243Sobrien	while (num--)
127259243Sobrien	    (void) tputs(Str(T_dc), 1, PUTPURE);
127359243Sobrien
127459243Sobrien    if (GoodStr(T_ed))		/* if I have delete mode */
127559243Sobrien	(void) tputs(Str(T_ed), 1, PUTPURE);
127659243Sobrien}
127759243Sobrien
1278167465Smp/* Puts terminal in insert character mode, or inserts num characters in the
1279167465Smp   line */
128059243Sobrienvoid
1281167465SmpInsert_write(Char *cp, int num)
128259243Sobrien{
128359243Sobrien    if (num <= 0)
128459243Sobrien	return;
128559243Sobrien    if (!T_CanIns) {
128659243Sobrien#ifdef DEBUG_EDIT
128759243Sobrien	xprintf(CGETS(7, 18, "ERROR: cannot insert\r\n"));
128859243Sobrien#endif /* DEBUG_EDIT */
128959243Sobrien	flush();
129059243Sobrien	return;
129159243Sobrien    }
129259243Sobrien
129359243Sobrien    if (num > TermH) {
129459243Sobrien#ifdef DEBUG_SCREEN
129559243Sobrien	xprintf(CGETS(7, 19, "StartInsert: num is riduculous: %d\r\n"), num);
129659243Sobrien	flush();
129759243Sobrien#endif /* DEBUG_SCREEN */
129859243Sobrien	return;
129959243Sobrien    }
130059243Sobrien
130159243Sobrien    if (GoodStr(T_IC))		/* if I have multiple insert */
130259243Sobrien	if ((num > 1) || !GoodStr(T_ic)) {	/* if ic would be more expen. */
130359243Sobrien	    (void) tputs(tgoto(Str(T_IC), num, num), num, PUTPURE);
130459243Sobrien	    so_write(cp, num);	/* this updates CursorH/V */
130559243Sobrien	    return;
130659243Sobrien	}
130759243Sobrien
130859243Sobrien    if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */
130959243Sobrien	(void) tputs(Str(T_im), 1, PUTPURE);
131059243Sobrien
1311145479Smp	so_write(cp, num);	/* this updates CursorH/V */
131259243Sobrien
131359243Sobrien	if (GoodStr(T_ip))	/* have to make num chars insert */
131459243Sobrien	    (void) tputs(Str(T_ip), 1, PUTPURE);
131559243Sobrien
131659243Sobrien	(void) tputs(Str(T_ei), 1, PUTPURE);
131759243Sobrien	return;
131859243Sobrien    }
131959243Sobrien
132059243Sobrien    do {
132159243Sobrien	if (GoodStr(T_ic))	/* have to make num chars insert */
132259243Sobrien	    (void) tputs(Str(T_ic), 1, PUTPURE);	/* insert a char */
132359243Sobrien
1324145479Smp	so_write(cp++, 1);	/* this updates CursorH/V */
132559243Sobrien
132659243Sobrien	if (GoodStr(T_ip))	/* have to make num chars insert */
132759243Sobrien	    (void) tputs(Str(T_ip), 1, PUTPURE);/* pad the inserted char */
132859243Sobrien
132959243Sobrien    } while (--num);
133059243Sobrien
133159243Sobrien}
133259243Sobrien
1333167465Smp/* clear to end of line.  There are num characters to clear */
133459243Sobrienvoid
1335167465SmpClearEOL(int num)
133659243Sobrien{
1337145479Smp    int i;
133859243Sobrien
133959243Sobrien    if (num <= 0)
134059243Sobrien	return;
134159243Sobrien
134259243Sobrien    if (T_CanCEOL && GoodStr(T_ce))
134359243Sobrien	(void) tputs(Str(T_ce), 1, PUTPURE);
134459243Sobrien    else {
134559243Sobrien	for (i = 0; i < num; i++)
134659243Sobrien	    (void) putraw(' ');
134759243Sobrien	CursorH += num;		/* have written num spaces */
134859243Sobrien    }
134959243Sobrien}
135059243Sobrien
135159243Sobrienvoid
1352167465SmpClearScreen(void)
135359243Sobrien{				/* clear the whole screen and home */
135459243Sobrien    if (GoodStr(T_cl))
135559243Sobrien	/* send the clear screen code */
135659243Sobrien	(void) tputs(Str(T_cl), Val(T_li), PUTPURE);
135759243Sobrien    else if (GoodStr(T_ho) && GoodStr(T_cd)) {
135859243Sobrien	(void) tputs(Str(T_ho), Val(T_li), PUTPURE);	/* home */
135959243Sobrien	/* clear to bottom of screen */
136059243Sobrien	(void) tputs(Str(T_cd), Val(T_li), PUTPURE);
136159243Sobrien    }
136259243Sobrien    else {
136359243Sobrien	(void) putraw('\r');
136459243Sobrien	(void) putraw('\n');
136559243Sobrien    }
136659243Sobrien}
136759243Sobrien
136859243Sobrienvoid
1369167465SmpSoundBeep(void)
137059243Sobrien{				/* produce a sound */
137159243Sobrien    beep_cmd ();
137259243Sobrien    if (adrof(STRnobeep))
137359243Sobrien	return;
137459243Sobrien
137559243Sobrien    if (GoodStr(T_vb) && adrof(STRvisiblebell))
137659243Sobrien	(void) tputs(Str(T_vb), 1, PUTPURE);	/* visible bell */
137759243Sobrien    else if (GoodStr(T_bl))
137859243Sobrien	/* what termcap says we should use */
137959243Sobrien	(void) tputs(Str(T_bl), 1, PUTPURE);
138059243Sobrien    else
138159243Sobrien	(void) putraw(CTL_ESC('\007'));	/* an ASCII bell; ^G */
138259243Sobrien}
138359243Sobrien
138459243Sobrienvoid
1385167465SmpClearToBottom(void)
138659243Sobrien{				/* clear to the bottom of the screen */
138759243Sobrien    if (GoodStr(T_cd))
138859243Sobrien	(void) tputs(Str(T_cd), Val(T_li), PUTPURE);
138959243Sobrien    else if (GoodStr(T_ce))
139059243Sobrien	(void) tputs(Str(T_ce), Val(T_li), PUTPURE);
139159243Sobrien}
139259243Sobrien
139359243Sobrienvoid
1394167465SmpGetTermCaps(void)
139559243Sobrien{				/* read in the needed terminal capabilites */
1396145479Smp    int i;
1397145479Smp    const char   *ptr;
139859243Sobrien    char    buf[TC_BUFSIZE];
139959243Sobrien    static char bp[TC_BUFSIZE];
140059243Sobrien    char   *area;
140159243Sobrien    struct termcapstr *t;
140259243Sobrien
140359243Sobrien
140459243Sobrien#ifdef SIG_WINDOW
1405167465Smp    sigset_t oset, set;
140659243Sobrien    int     lins, cols;
140759243Sobrien
140859243Sobrien    /* don't want to confuse things here */
1409167465Smp    sigemptyset(&set);
1410167465Smp    sigaddset(&set, SIG_WINDOW);
1411167465Smp    (void)sigprocmask(SIG_BLOCK, &set, &oset);
1412167465Smp    cleanup_push(&oset, sigprocmask_cleanup);
141359243Sobrien#endif /* SIG_WINDOW */
141459243Sobrien    area = buf;
141559243Sobrien
141659243Sobrien    GotTermCaps = 1;
141759243Sobrien
141859243Sobrien    setname("gettermcaps");
141959243Sobrien    ptr = getenv("TERM");
142059243Sobrien
142159243Sobrien#ifdef apollo
142259243Sobrien    /*
142359243Sobrien     * If we are on a pad, we pretend that we are dumb. Otherwise the termcap
142459243Sobrien     * library will put us in a weird screen mode, thinking that we are going
142559243Sobrien     * to use curses
142659243Sobrien     */
142759243Sobrien    if (isapad())
142859243Sobrien	ptr = "dumb";
142959243Sobrien#endif /* apollo */
143059243Sobrien
143159243Sobrien    if (!ptr || !ptr[0] || !strcmp(ptr, "wm") || !strcmp(ptr,"dmx"))
143259243Sobrien	ptr = "dumb";
143359243Sobrien
143459243Sobrien    setzero(bp, TC_BUFSIZE);
143559243Sobrien
143659243Sobrien    i = tgetent(bp, ptr);
143759243Sobrien    if (i <= 0) {
143859243Sobrien	if (i == -1) {
143959243Sobrien#if (SYSVREL == 0) || defined(IRIS3D)
144059243Sobrien	    xprintf(CGETS(7, 20, "%s: Cannot open /etc/termcap.\n"), progname);
144159243Sobrien	}
144259243Sobrien	else if (i == 0) {
144359243Sobrien#endif /* SYSVREL */
144459243Sobrien	    xprintf(CGETS(7, 21,
144559243Sobrien			  "%s: No entry for terminal type \"%s\"\n"), progname,
144659243Sobrien		    getenv("TERM"));
144759243Sobrien	}
144859243Sobrien	xprintf(CGETS(7, 22, "%s: using dumb terminal settings.\n"), progname);
144959243Sobrien	Val(T_co) = 80;		/* do a dumb terminal */
145059243Sobrien	Val(T_pt) = Val(T_km) = Val(T_li) = 0;
145159243Sobrien	for (t = tstr; t->name != NULL; t++)
1452167465Smp	    TCset(t, NULL);
145359243Sobrien    }
145459243Sobrien    else {
145559243Sobrien	/* Can we tab */
145659243Sobrien	Val(T_pt) = tgetflag("pt") && !tgetflag("xt");
145759243Sobrien	/* do we have a meta? */
145859243Sobrien	Val(T_km) = (tgetflag("km") || tgetflag("MT"));
145959243Sobrien	Val(T_am) = tgetflag("am");
146059243Sobrien	Val(T_xn) = tgetflag("xn");
146159243Sobrien	Val(T_co) = tgetnum("co");
146259243Sobrien	Val(T_li) = tgetnum("li");
146359243Sobrien	for (t = tstr; t->name != NULL; t++)
1464167465Smp	    TCset(t, tgetstr(t->name, &area));
146559243Sobrien    }
146659243Sobrien    if (Val(T_co) < 2)
146759243Sobrien	Val(T_co) = 80;		/* just in case */
146859243Sobrien    if (Val(T_li) < 1)
146959243Sobrien	Val(T_li) = 24;
147059243Sobrien
147159243Sobrien    T_Cols = (Char) Val(T_co);
147259243Sobrien    T_Lines = (Char) Val(T_li);
147359243Sobrien    if (T_Tabs)
1474167465Smp	T_Tabs = Val(T_pt);
1475167465Smp    T_HasMeta = Val(T_km);
1476167465Smp    T_Margin = Val(T_am) ? MARGIN_AUTO : 0;
1477167465Smp    T_Margin |= Val(T_xn) ? MARGIN_MAGIC : 0;
147859243Sobrien    T_CanCEOL = GoodStr(T_ce);
147959243Sobrien    T_CanDel = GoodStr(T_dc) || GoodStr(T_DC);
148059243Sobrien    T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC);
148159243Sobrien    T_CanUP = GoodStr(T_up) || GoodStr(T_UP);
148259243Sobrien    if (GoodStr(T_me) && GoodStr(T_ue))
148359243Sobrien	me_all = (strcmp(Str(T_me), Str(T_ue)) == 0);
148459243Sobrien    else
148559243Sobrien	me_all = 0;
148659243Sobrien    if (GoodStr(T_me) && GoodStr(T_se))
148759243Sobrien	me_all |= (strcmp(Str(T_me), Str(T_se)) == 0);
148859243Sobrien
148959243Sobrien
149059243Sobrien#ifdef DEBUG_SCREEN
149159243Sobrien    if (!T_CanUP) {
149259243Sobrien	xprintf(CGETS(7, 23, "%s: WARNING: Your terminal cannot move up.\n",
149359243Sobrien		progname));
149459243Sobrien	xprintf(CGETS(7, 24, "Editing may be odd for long lines.\n"));
149559243Sobrien    }
149659243Sobrien    if (!T_CanCEOL)
149759243Sobrien	xprintf(CGETS(7, 25, "no clear EOL capability.\n"));
149859243Sobrien    if (!T_CanDel)
149959243Sobrien	xprintf(CGETS(7, 26, "no delete char capability.\n"));
150059243Sobrien    if (!T_CanIns)
150159243Sobrien	xprintf(CGETS(7, 27, "no insert char capability.\n"));
150259243Sobrien#endif /* DEBUG_SCREEN */
150359243Sobrien
150459243Sobrien
150559243Sobrien
150659243Sobrien#ifdef SIG_WINDOW
150759243Sobrien    (void) GetSize(&lins, &cols);	/* get the correct window size */
150859243Sobrien    ChangeSize(lins, cols);
150959243Sobrien
1510167465Smp    cleanup_until(&oset);		/* can change it again */
151159243Sobrien#else /* SIG_WINDOW */
151259243Sobrien    ChangeSize(Val(T_li), Val(T_co));
151359243Sobrien#endif /* SIG_WINDOW */
151459243Sobrien
151559243Sobrien    BindArrowKeys();
151659243Sobrien}
151759243Sobrien
151859243Sobrien#ifdef SIG_WINDOW
151959243Sobrien/* GetSize():
152059243Sobrien *	Return the new window size in lines and cols, and
152159243Sobrien *	true if the size was changed. This can fail if SHIN
152259243Sobrien *	is not a tty, but it will work in most cases.
152359243Sobrien */
152459243Sobrienint
1525167465SmpGetSize(int *lins, int *cols)
152659243Sobrien{
152759243Sobrien    *cols = Val(T_co);
152859243Sobrien    *lins = Val(T_li);
152959243Sobrien
153059243Sobrien#ifdef TIOCGWINSZ
153159243Sobrien# define KNOWsize
153259243Sobrien# ifndef lint
153359243Sobrien    {
153459243Sobrien	struct winsize ws;	/* from 4.3 */
153559243Sobrien
153659243Sobrien	if (ioctl(SHIN, TIOCGWINSZ, (ioctl_t) &ws) != -1) {
153759243Sobrien	    if (ws.ws_col)
153859243Sobrien		*cols = ws.ws_col;
153959243Sobrien	    if (ws.ws_row)
154059243Sobrien		*lins = ws.ws_row;
154159243Sobrien	}
154259243Sobrien    }
154359243Sobrien# endif /* !lint */
154459243Sobrien#else /* TIOCGWINSZ */
154559243Sobrien# ifdef TIOCGSIZE
154659243Sobrien#  define KNOWsize
154759243Sobrien    {
154859243Sobrien	struct ttysize ts;	/* from Sun */
154959243Sobrien
155059243Sobrien	if (ioctl(SHIN, TIOCGSIZE, (ioctl_t) &ts) != -1) {
155159243Sobrien	    if (ts.ts_cols)
155259243Sobrien		*cols = ts.ts_cols;
155359243Sobrien	    if (ts.ts_lines)
155459243Sobrien		*lins = ts.ts_lines;
155559243Sobrien	}
155659243Sobrien    }
155759243Sobrien# endif /* TIOCGSIZE */
155859243Sobrien#endif /* TIOCGWINSZ */
155959243Sobrien
156059243Sobrien    return (Val(T_co) != *cols || Val(T_li) != *lins);
156159243Sobrien}
156259243Sobrien
1563167465Smp#endif /* SIG_WINDOW */
156459243Sobrien
1565232633Smp#ifdef KNOWsize
1566232633Smpstatic void
1567232633SmpUpdateVal(const Char *tag, int value, Char *termcap, Char *backup)
1568232633Smp{
1569232633Smp    Char *ptr, *p;
1570232633Smp    if ((ptr = Strstr(termcap, tag)) == NULL) {
1571232633Smp	(void)Strcpy(backup, termcap);
1572232633Smp	return;
1573232633Smp    } else {
1574232633Smp	size_t len = (ptr - termcap) + Strlen(tag);
1575232633Smp	(void)Strncpy(backup, termcap, len);
1576232633Smp	backup[len] = '\0';
1577232633Smp	p = Itoa(value, 0, 0);
1578232633Smp	(void) Strcat(backup + len, p);
1579232633Smp	xfree(p);
1580232633Smp	ptr = Strchr(ptr, ':');
1581232633Smp	if (ptr)
1582232633Smp	    (void) Strcat(backup, ptr);
1583232633Smp    }
1584232633Smp}
1585232633Smp#endif
1586232633Smp
158759243Sobrienvoid
1588167465SmpChangeSize(int lins, int cols)
158959243Sobrien{
159059243Sobrien    /*
159159243Sobrien     * Just in case
159259243Sobrien     */
159359243Sobrien    Val(T_co) = (cols < 2) ? 80 : cols;
159459243Sobrien    Val(T_li) = (lins < 1) ? 24 : lins;
159559243Sobrien
159659243Sobrien#ifdef KNOWsize
159759243Sobrien    /*
159859243Sobrien     * We want to affect the environment only when we have a valid
159959243Sobrien     * setup, not when we get bad settings. Consider the following scenario:
160059243Sobrien     * We just logged in, and we have not initialized the editor yet.
160159243Sobrien     * We reset termcap with tset, and not $TERMCAP has the right
160259243Sobrien     * terminal size. But since the editor is not initialized yet, and
160359243Sobrien     * the kernel's notion of the terminal size might be wrong we arrive
160459243Sobrien     * here with lines = columns = 0. If we reset the environment we lose
160559243Sobrien     * our only chance to get the window size right.
160659243Sobrien     */
160759243Sobrien    if (Val(T_co) == cols && Val(T_li) == lins) {
1608167465Smp	Char   *p;
160959243Sobrien	char   *tptr;
161059243Sobrien
161159243Sobrien	if (getenv("COLUMNS")) {
1612167465Smp	    p = Itoa(Val(T_co), 0, 0);
1613167465Smp	    cleanup_push(p, xfree);
1614167465Smp	    tsetenv(STRCOLUMNS, p);
1615167465Smp	    cleanup_until(p);
161659243Sobrien	}
161759243Sobrien
161859243Sobrien	if (getenv("LINES")) {
1619167465Smp	    p = Itoa(Val(T_li), 0, 0);
1620167465Smp	    cleanup_push(p, xfree);
1621167465Smp	    tsetenv(STRLINES, p);
1622167465Smp	    cleanup_until(p);
162359243Sobrien	}
162459243Sobrien
162559243Sobrien	if ((tptr = getenv("TERMCAP")) != NULL) {
162659243Sobrien	    /* Leave 64 characters slop in case we enlarge the termcap string */
1627167465Smp	    Char    termcap[TC_BUFSIZE+64], backup[TC_BUFSIZE+64], *ptr;
1628167465Smp	    Char buf[4];
162959243Sobrien
163059243Sobrien	    ptr = str2short(tptr);
1631167465Smp	    (void) Strncpy(termcap, ptr, TC_BUFSIZE);
1632167465Smp	    termcap[TC_BUFSIZE-1] = '\0';
163359243Sobrien
1634232633Smp	    UpdateVal(STRco, Val(T_co), termcap, backup);
1635232633Smp	    UpdateVal(STRli, Val(T_li), termcap, backup);
163659243Sobrien
163759243Sobrien	    /*
1638167465Smp	     * Chop the termcap string at TC_BUFSIZE-1 characters to avoid
1639167465Smp	     * core-dumps in the termcap routines
164059243Sobrien	     */
1641167465Smp	    termcap[TC_BUFSIZE - 1] = '\0';
164259243Sobrien	    tsetenv(STRTERMCAP, termcap);
164359243Sobrien	}
164459243Sobrien    }
164559243Sobrien#endif /* KNOWsize */
164659243Sobrien
164759243Sobrien    ReBufferDisplay();		/* re-make display buffers */
164859243Sobrien    ClearDisp();
164959243Sobrien}
1650