159243Sobrien/*
259243Sobrien * ed.screen.c: Editor/termcap-curses interface
359243Sobrien */
459243Sobrien/*-
559243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
659243Sobrien * All rights reserved.
759243Sobrien *
859243Sobrien * Redistribution and use in source and binary forms, with or without
959243Sobrien * modification, are permitted provided that the following conditions
1059243Sobrien * are met:
1159243Sobrien * 1. Redistributions of source code must retain the above copyright
1259243Sobrien *    notice, this list of conditions and the following disclaimer.
1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1459243Sobrien *    notice, this list of conditions and the following disclaimer in the
1559243Sobrien *    documentation and/or other materials provided with the distribution.
16100616Smp * 3. Neither the name of the University nor the names of its contributors
1759243Sobrien *    may be used to endorse or promote products derived from this software
1859243Sobrien *    without specific prior written permission.
1959243Sobrien *
2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2359243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3059243Sobrien * SUCH DAMAGE.
3159243Sobrien */
3259243Sobrien#include "sh.h"
3359243Sobrien#include "ed.h"
3459243Sobrien#include "tc.h"
3559243Sobrien#include "ed.defns.h"
3659243Sobrien
3759243Sobrien/* #define DEBUG_LITERAL */
3859243Sobrien
3959243Sobrien/*
4059243Sobrien * IMPORTANT NOTE: these routines are allowed to look at the current screen
4159243Sobrien * and the current possition assuming that it is correct.  If this is not
4259243Sobrien * true, then the update will be WRONG!  This is (should be) a valid
4359243Sobrien * assumption...
4459243Sobrien */
4559243Sobrien
4659243Sobrien#define TC_BUFSIZE 2048
4759243Sobrien
4859243Sobrien#define GoodStr(a) (tstr[a].str != NULL && tstr[a].str[0] != '\0')
4959243Sobrien#define Str(a) tstr[a].str
5059243Sobrien#define Val(a) tval[a].val
5159243Sobrien
52167465Smpstatic const struct {
53145479Smp    const char   *b_name;
54145479Smp    speed_t b_rate;
5559243Sobrien}       baud_rate[] = {
5659243Sobrien
5759243Sobrien#ifdef B0
5859243Sobrien    { "0", B0 },
5959243Sobrien#endif
6059243Sobrien#ifdef B50
6159243Sobrien    { "50", B50 },
6259243Sobrien#endif
6359243Sobrien#ifdef B75
6459243Sobrien    { "75", B75 },
6559243Sobrien#endif
6659243Sobrien#ifdef B110
6759243Sobrien    { "110", B110 },
6859243Sobrien#endif
6959243Sobrien#ifdef B134
7059243Sobrien    { "134", B134 },
7159243Sobrien#endif
7259243Sobrien#ifdef B150
7359243Sobrien    { "150", B150 },
7459243Sobrien#endif
7559243Sobrien#ifdef B200
7659243Sobrien    { "200", B200 },
7759243Sobrien#endif
7859243Sobrien#ifdef B300
7959243Sobrien    { "300", B300 },
8059243Sobrien#endif
8159243Sobrien#ifdef B600
8259243Sobrien    { "600", B600 },
8359243Sobrien#endif
8459243Sobrien#ifdef B900
8559243Sobrien    { "900", B900 },
8659243Sobrien#endif
8759243Sobrien#ifdef B1200
8859243Sobrien    { "1200", B1200 },
8959243Sobrien#endif
9059243Sobrien#ifdef B1800
9159243Sobrien    { "1800", B1800 },
9259243Sobrien#endif
9359243Sobrien#ifdef B2400
9459243Sobrien    { "2400", B2400 },
9559243Sobrien#endif
9659243Sobrien#ifdef B3600
9759243Sobrien    { "3600", B3600 },
9859243Sobrien#endif
9959243Sobrien#ifdef B4800
10059243Sobrien    { "4800", B4800 },
10159243Sobrien#endif
10259243Sobrien#ifdef B7200
10359243Sobrien    { "7200", B7200 },
10459243Sobrien#endif
10559243Sobrien#ifdef B9600
10659243Sobrien    { "9600", B9600 },
10759243Sobrien#endif
10859243Sobrien#ifdef EXTA
10959243Sobrien    { "19200", EXTA },
11059243Sobrien#endif
11159243Sobrien#ifdef B19200
11259243Sobrien    { "19200", B19200 },
11359243Sobrien#endif
11459243Sobrien#ifdef EXTB
11559243Sobrien    { "38400", EXTB },
11659243Sobrien#endif
11759243Sobrien#ifdef B38400
11859243Sobrien    { "38400", B38400 },
11959243Sobrien#endif
12059243Sobrien    { NULL, 0 }
12159243Sobrien};
12259243Sobrien
123167465Smp#define T_at7   0
124167465Smp#define T_al	1
125167465Smp#define T_bl	2
126167465Smp#define T_cd	3
127167465Smp#define T_ce	4
128167465Smp#define T_ch	5
129167465Smp#define T_cl	6
130167465Smp#define	T_dc	7
131167465Smp#define	T_dl	8
132167465Smp#define	T_dm	9
133167465Smp#define	T_ed	10
134167465Smp#define	T_ei	11
135167465Smp#define	T_fs	12
136167465Smp#define	T_ho	13
137167465Smp#define	T_ic	14
138167465Smp#define	T_im	15
139167465Smp#define	T_ip	16
140167465Smp#define	T_kd	17
141167465Smp#define T_kh    18
142167465Smp#define	T_kl	19
143167465Smp#define T_kr	20
144167465Smp#define T_ku	21
145167465Smp#define T_md	22
146167465Smp#define T_me	23
147167465Smp#define T_mr    24
148167465Smp#define T_nd	25
149167465Smp#define T_se	26
150167465Smp#define T_so	27
151167465Smp#define T_ts	28
152167465Smp#define T_up	29
153167465Smp#define T_us	30
154167465Smp#define T_ue	31
155167465Smp#define T_vb	32
156167465Smp#define T_DC	33
157167465Smp#define T_DO	34
158167465Smp#define T_IC	35
159167465Smp#define T_LE	36
160167465Smp#define T_RI	37
161167465Smp#define T_UP	38
162167465Smp#define T_str   39
163167465Smp
16459243Sobrienstatic struct termcapstr {
165145479Smp    const char   *name;
166145479Smp    const char   *long_name;
16759243Sobrien    char   *str;
16859243Sobrien} tstr[T_str + 1];
16959243Sobrien
17059243Sobrien
17159243Sobrien#define T_am	0
17259243Sobrien#define T_pt	1
17359243Sobrien#define T_li	2
17459243Sobrien#define T_co	3
17559243Sobrien#define T_km	4
17659243Sobrien#define T_xn	5
17759243Sobrien#define T_val	6
17859243Sobrienstatic struct termcapval {
179145479Smp    const char   *name;
180145479Smp    const char   *long_name;
18159243Sobrien    int     val;
18259243Sobrien} tval[T_val + 1];
18359243Sobrien
18459243Sobrienvoid
185167465Smpterminit(void)
18659243Sobrien{
18759243Sobrien#ifdef NLS_CATALOGS
18859243Sobrien    int i;
18959243Sobrien
19059243Sobrien    for (i = 0; i < T_str + 1; i++)
191167465Smp	xfree((ptr_t)(intptr_t)tstr[i].long_name);
19259243Sobrien
19359243Sobrien    for (i = 0; i < T_val + 1; i++)
194167465Smp	xfree((ptr_t)(intptr_t)tval[i].long_name);
19559243Sobrien#endif
19659243Sobrien
19759243Sobrien    tstr[T_al].name = "al";
19859243Sobrien    tstr[T_al].long_name = CSAVS(4, 1, "add new blank line");
19959243Sobrien
20059243Sobrien    tstr[T_bl].name = "bl";
20159243Sobrien    tstr[T_bl].long_name = CSAVS(4, 2, "audible bell");
20259243Sobrien
20359243Sobrien    tstr[T_cd].name = "cd";
20459243Sobrien    tstr[T_cd].long_name = CSAVS(4, 3, "clear to bottom");
20559243Sobrien
20659243Sobrien    tstr[T_ce].name = "ce";
20759243Sobrien    tstr[T_ce].long_name = CSAVS(4, 4, "clear to end of line");
20859243Sobrien
20959243Sobrien    tstr[T_ch].name = "ch";
21059243Sobrien    tstr[T_ch].long_name = CSAVS(4, 5, "cursor to horiz pos");
21159243Sobrien
21259243Sobrien    tstr[T_cl].name = "cl";
21359243Sobrien    tstr[T_cl].long_name = CSAVS(4, 6, "clear screen");
21459243Sobrien
21559243Sobrien    tstr[T_dc].name = "dc";
21659243Sobrien    tstr[T_dc].long_name = CSAVS(4, 7, "delete a character");
21759243Sobrien
21859243Sobrien    tstr[T_dl].name = "dl";
21959243Sobrien    tstr[T_dl].long_name = CSAVS(4, 8, "delete a line");
22059243Sobrien
22159243Sobrien    tstr[T_dm].name = "dm";
22259243Sobrien    tstr[T_dm].long_name = CSAVS(4, 9, "start delete mode");
22359243Sobrien
22459243Sobrien    tstr[T_ed].name = "ed";
22559243Sobrien    tstr[T_ed].long_name = CSAVS(4, 10, "end delete mode");
22659243Sobrien
22759243Sobrien    tstr[T_ei].name = "ei";
22859243Sobrien    tstr[T_ei].long_name = CSAVS(4, 11, "end insert mode");
22959243Sobrien
23059243Sobrien    tstr[T_fs].name = "fs";
23159243Sobrien    tstr[T_fs].long_name = CSAVS(4, 12, "cursor from status line");
23259243Sobrien
23359243Sobrien    tstr[T_ho].name = "ho";
23459243Sobrien    tstr[T_ho].long_name = CSAVS(4, 13, "home cursor");
23559243Sobrien
23659243Sobrien    tstr[T_ic].name = "ic";
23759243Sobrien    tstr[T_ic].long_name = CSAVS(4, 14, "insert character");
23859243Sobrien
23959243Sobrien    tstr[T_im].name = "im";
24059243Sobrien    tstr[T_im].long_name = CSAVS(4, 15, "start insert mode");
24159243Sobrien
24259243Sobrien    tstr[T_ip].name = "ip";
24359243Sobrien    tstr[T_ip].long_name = CSAVS(4, 16, "insert padding");
24459243Sobrien
24559243Sobrien    tstr[T_kd].name = "kd";
24659243Sobrien    tstr[T_kd].long_name = CSAVS(4, 17, "sends cursor down");
24759243Sobrien
24859243Sobrien    tstr[T_kl].name = "kl";
24959243Sobrien    tstr[T_kl].long_name = CSAVS(4, 18, "sends cursor left");
25059243Sobrien
25159243Sobrien    tstr[T_kr].name = "kr";
25259243Sobrien    tstr[T_kr].long_name = CSAVS(4, 19, "sends cursor right");
25359243Sobrien
25459243Sobrien    tstr[T_ku].name = "ku";
25559243Sobrien    tstr[T_ku].long_name = CSAVS(4, 20, "sends cursor up");
25659243Sobrien
25759243Sobrien    tstr[T_md].name = "md";
25859243Sobrien    tstr[T_md].long_name = CSAVS(4, 21, "begin bold");
25959243Sobrien
26059243Sobrien    tstr[T_me].name = "me";
26159243Sobrien    tstr[T_me].long_name = CSAVS(4, 22, "end attributes");
26259243Sobrien
26359243Sobrien    tstr[T_nd].name = "nd";
26459243Sobrien    tstr[T_nd].long_name = CSAVS(4, 23, "non destructive space");
26559243Sobrien
26659243Sobrien    tstr[T_se].name = "se";
26759243Sobrien    tstr[T_se].long_name = CSAVS(4, 24, "end standout");
26859243Sobrien
26959243Sobrien    tstr[T_so].name = "so";
27059243Sobrien    tstr[T_so].long_name = CSAVS(4, 25, "begin standout");
27159243Sobrien
27259243Sobrien    tstr[T_ts].name = "ts";
27359243Sobrien    tstr[T_ts].long_name = CSAVS(4, 26, "cursor to status line");
27459243Sobrien
27559243Sobrien    tstr[T_up].name = "up";
27659243Sobrien    tstr[T_up].long_name = CSAVS(4, 27, "cursor up one");
27759243Sobrien
27859243Sobrien    tstr[T_us].name = "us";
27959243Sobrien    tstr[T_us].long_name = CSAVS(4, 28, "begin underline");
28059243Sobrien
28159243Sobrien    tstr[T_ue].name = "ue";
28259243Sobrien    tstr[T_ue].long_name = CSAVS(4, 29, "end underline");
28359243Sobrien
28459243Sobrien    tstr[T_vb].name = "vb";
28559243Sobrien    tstr[T_vb].long_name = CSAVS(4, 30, "visible bell");
28659243Sobrien
28759243Sobrien    tstr[T_DC].name = "DC";
28859243Sobrien    tstr[T_DC].long_name = CSAVS(4, 31, "delete multiple chars");
28959243Sobrien
29059243Sobrien    tstr[T_DO].name = "DO";
29159243Sobrien    tstr[T_DO].long_name = CSAVS(4, 32, "cursor down multiple");
29259243Sobrien
29359243Sobrien    tstr[T_IC].name = "IC";
29459243Sobrien    tstr[T_IC].long_name = CSAVS(4, 33, "insert multiple chars");
29559243Sobrien
29659243Sobrien    tstr[T_LE].name = "LE";
29759243Sobrien    tstr[T_LE].long_name = CSAVS(4, 34, "cursor left multiple");
29859243Sobrien
29959243Sobrien    tstr[T_RI].name = "RI";
30059243Sobrien    tstr[T_RI].long_name = CSAVS(4, 35, "cursor right multiple");
30159243Sobrien
30259243Sobrien    tstr[T_UP].name = "UP";
30359243Sobrien    tstr[T_UP].long_name = CSAVS(4, 36, "cursor up multiple");
30459243Sobrien
30569408Sache    tstr[T_kh].name = "kh";
306167465Smp    tstr[T_kh].long_name = CSAVS(4, 43, "send cursor home");
30769408Sache
30869408Sache    tstr[T_at7].name = "@7";
309167465Smp    tstr[T_at7].long_name = CSAVS(4, 44, "send cursor end");
31069408Sache
311167465Smp    tstr[T_mr].name = "mr";
312167465Smp    tstr[T_mr].long_name = CSAVS(4, 45, "begin reverse video");
313167465Smp
31459243Sobrien    tstr[T_str].name = NULL;
31559243Sobrien    tstr[T_str].long_name = NULL;
31659243Sobrien
31759243Sobrien
31859243Sobrien    tval[T_am].name = "am";
31959243Sobrien    tval[T_am].long_name = CSAVS(4, 37, "Has automatic margins");
32059243Sobrien
32159243Sobrien    tval[T_pt].name = "pt";
32259243Sobrien    tval[T_pt].long_name = CSAVS(4, 38, "Can use physical tabs");
32359243Sobrien
32459243Sobrien    tval[T_li].name = "li";
32559243Sobrien    tval[T_li].long_name = CSAVS(4, 39, "Number of lines");
32659243Sobrien
32759243Sobrien    tval[T_co].name = "co";
32859243Sobrien    tval[T_co].long_name = CSAVS(4, 40, "Number of columns");
32959243Sobrien
33059243Sobrien    tval[T_km].name = "km";
33159243Sobrien    tval[T_km].long_name = CSAVS(4, 41, "Has meta key");
33259243Sobrien
33359243Sobrien    tval[T_xn].name = "xn";
33459243Sobrien    tval[T_xn].long_name = CSAVS(4, 42, "Newline ignored at right margin");
33559243Sobrien
33659243Sobrien    tval[T_val].name = NULL;
33759243Sobrien    tval[T_val].long_name = NULL;
33859243Sobrien}
33959243Sobrien
34059243Sobrien/*
34159243Sobrien * A very useful table from justin@crim.ca (Justin Bur) :-)
34259243Sobrien * (Modified by per@erix.ericsson.se (Per Hedeland)
34359243Sobrien *  - first (and second:-) case fixed)
34459243Sobrien *
34559243Sobrien * Description     Termcap variables       tcsh behavior
34659243Sobrien * 		   am      xn              UseRightmost    SendCRLF
34759243Sobrien * --------------  ------- -------         ------------    ------------
34859243Sobrien * Automargins     yes     no              yes             no
34959243Sobrien * Magic Margins   yes     yes             yes             no
35059243Sobrien * No Wrap         no      --              yes             yes
35159243Sobrien */
35259243Sobrien
353145479Smpstatic int me_all = 0;		/* does two or more of the attributes use me */
35459243Sobrien
355167465Smpstatic	void	ReBufferDisplay	(void);
356167465Smpstatic	void	TCset		(struct termcapstr *, const char *);
35759243Sobrien
35859243Sobrien
35959243Sobrienstatic void
360167465SmpTCset(struct termcapstr *t, const char *cap)
36159243Sobrien{
36259243Sobrien    if (cap == NULL || *cap == '\0') {
363167465Smp	xfree(t->str);
36459243Sobrien	t->str = NULL;
365167465Smp    } else {
366167465Smp	size_t size;
36759243Sobrien
368167465Smp	size = strlen(cap) + 1;
369167465Smp	t->str = xrealloc(t->str, size);
370167465Smp	memcpy(t->str, cap, size);
37159243Sobrien    }
37259243Sobrien}
37359243Sobrien
37459243Sobrien
37559243Sobrien/*ARGSUSED*/
37659243Sobrienvoid
377167465SmpTellTC(void)
37859243Sobrien{
37959243Sobrien    struct termcapstr *t;
380167465Smp    char *first, *s;
38159243Sobrien
382195609Smp    xprintf("%s", CGETS(7, 1, "\n\tTcsh thinks your terminal has the\n"));
383195609Smp    xprintf("%s", CGETS(7, 2, "\tfollowing characteristics:\n\n"));
38459243Sobrien    xprintf(CGETS(7, 3, "\tIt has %d columns and %d lines\n"),
38559243Sobrien	    Val(T_co), Val(T_li));
386145479Smp    s = strsave(T_HasMeta ? CGETS(7, 5, "a") : CGETS(7, 6, "no"));
387167465Smp    cleanup_push(s, xfree);
388167465Smp    first = s;
389145479Smp    xprintf(CGETS(7, 4, "\tIt has %s meta key\n"), s);
390145479Smp    s = strsave(T_Tabs ? "" : CGETS(7, 8, " not"));
391167465Smp    cleanup_push(s, xfree);
392145479Smp    xprintf(CGETS(7, 7, "\tIt can%s use tabs\n"), s);
393145479Smp    s = strsave((T_Margin&MARGIN_AUTO) ?
394145479Smp		CGETS(7, 10, "has") : CGETS(7, 11, "does not have"));
395167465Smp    cleanup_push(s, xfree);
396145479Smp    xprintf(CGETS(7, 9, "\tIt %s automatic margins\n"), s);
397145479Smp    if (T_Margin & MARGIN_AUTO) {
398145479Smp        s = strsave((T_Margin & MARGIN_MAGIC) ?
399145479Smp			CGETS(7, 10, "has") : CGETS(7, 11, "does not have"));
400167465Smp	cleanup_push(s, xfree);
401145479Smp	xprintf(CGETS(7, 12, "\tIt %s magic margins\n"), s);
402145479Smp    }
403145479Smp    for (t = tstr; t->name != NULL; t++) {
404145479Smp        s = strsave(t->str && *t->str ? t->str : CGETS(7, 13, "(empty)"));
405167465Smp	cleanup_push(s, xfree);
406145479Smp	xprintf("\t%36s (%s) == %s\n", t->long_name, t->name, s);
407167465Smp	cleanup_until(s);
408145479Smp    }
40959243Sobrien    xputchar('\n');
410167465Smp    cleanup_until(first);
41159243Sobrien}
41259243Sobrien
41359243Sobrien
41459243Sobrienstatic void
415167465SmpReBufferDisplay(void)
41659243Sobrien{
417145479Smp    int i;
418145479Smp    Char **b;
41959243Sobrien
42059243Sobrien    b = Display;
42159243Sobrien    Display = NULL;
422167465Smp    blkfree(b);
42359243Sobrien    b = Vdisplay;
42459243Sobrien    Vdisplay = NULL;
425167465Smp    blkfree(b);
42659243Sobrien    TermH = Val(T_co);
427167465Smp    TermV = (INBUFSIZE * 4) / TermH + 1;/*FIXBUF*/
428167465Smp    b = xmalloc(sizeof(*b) * (TermV + 1));
42959243Sobrien    for (i = 0; i < TermV; i++)
430167465Smp	b[i] = xmalloc(sizeof(*b[i]) * (TermH + 1));
43159243Sobrien    b[TermV] = NULL;
43259243Sobrien    Display = b;
433167465Smp    b = xmalloc(sizeof(*b) * (TermV + 1));
43459243Sobrien    for (i = 0; i < TermV; i++)
435167465Smp	b[i] = xmalloc(sizeof(*b[i]) * (TermH + 1));
43659243Sobrien    b[TermV] = NULL;
43759243Sobrien    Vdisplay = b;
43859243Sobrien}
43959243Sobrien
44059243Sobrienvoid
441167465SmpSetTC(char *what, char *how)
44259243Sobrien{
44359243Sobrien    struct termcapstr *ts;
44459243Sobrien    struct termcapval *tv;
44559243Sobrien
44659243Sobrien    /*
44759243Sobrien     * Do the strings first
44859243Sobrien     */
44959243Sobrien    setname("settc");
45059243Sobrien    for (ts = tstr; ts->name != NULL; ts++)
45159243Sobrien	if (strcmp(ts->name, what) == 0)
45259243Sobrien	    break;
45359243Sobrien    if (ts->name != NULL) {
454167465Smp	TCset(ts, how);
45559243Sobrien	/*
45659243Sobrien	 * Reset variables
45759243Sobrien	 */
45859243Sobrien	if (GoodStr(T_me) && GoodStr(T_ue))
45959243Sobrien	    me_all = (strcmp(Str(T_me), Str(T_ue)) == 0);
46059243Sobrien	else
46159243Sobrien	    me_all = 0;
46259243Sobrien	if (GoodStr(T_me) && GoodStr(T_se))
46359243Sobrien	    me_all |= (strcmp(Str(T_me), Str(T_se)) == 0);
46459243Sobrien
46559243Sobrien	T_CanCEOL = GoodStr(T_ce);
46659243Sobrien	T_CanDel = GoodStr(T_dc) || GoodStr(T_DC);
46759243Sobrien	T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC);
46859243Sobrien	T_CanUP = GoodStr(T_up) || GoodStr(T_UP);
46959243Sobrien	return;
47059243Sobrien    }
47159243Sobrien
47259243Sobrien    /*
47359243Sobrien     * Do the numeric ones second
47459243Sobrien     */
47559243Sobrien    for (tv = tval; tv->name != NULL; tv++)
47659243Sobrien	if (strcmp(tv->name, what) == 0)
47759243Sobrien	    break;
47859243Sobrien
47959243Sobrien    if (tv->name != NULL) {
48059243Sobrien	if (tv == &tval[T_pt] || tv == &tval[T_km] ||
48159243Sobrien	    tv == &tval[T_am] || tv == &tval[T_xn]) {
48259243Sobrien	    if (strcmp(how, "yes") == 0)
48359243Sobrien		tv->val = 1;
48459243Sobrien	    else if (strcmp(how, "no") == 0)
48559243Sobrien		tv->val = 0;
48659243Sobrien	    else {
48759243Sobrien		stderror(ERR_SETTCUS, tv->name);
48859243Sobrien		return;
48959243Sobrien	    }
490167465Smp	    T_Tabs = Val(T_pt);
491167465Smp	    T_HasMeta = Val(T_km);
492167465Smp	    T_Margin = Val(T_am) ? MARGIN_AUTO : 0;
493167465Smp	    T_Margin |= Val(T_xn) ? MARGIN_MAGIC : 0;
49459243Sobrien	    if (tv == &tval[T_am] || tv == &tval[T_xn])
49559243Sobrien		ChangeSize(Val(T_li), Val(T_co));
49659243Sobrien	    return;
49759243Sobrien	}
49859243Sobrien	else {
49959243Sobrien	    tv->val = atoi(how);
50059243Sobrien	    T_Cols = (Char) Val(T_co);
50159243Sobrien	    T_Lines = (Char) Val(T_li);
50259243Sobrien	    if (tv == &tval[T_co] || tv == &tval[T_li])
50359243Sobrien		ChangeSize(Val(T_li), Val(T_co));
50459243Sobrien	    return;
50559243Sobrien	}
50659243Sobrien    }
50759243Sobrien    stderror(ERR_NAME | ERR_TCCAP, what);
50859243Sobrien    return;
50959243Sobrien}
51059243Sobrien
51159243Sobrien
51259243Sobrien/*
51359243Sobrien * Print the termcap string out with variable substitution
51459243Sobrien */
51559243Sobrienvoid
516167465SmpEchoTC(Char **v)
51759243Sobrien{
518167465Smp    char   *cap, *scap, *cv;
51959243Sobrien    int     arg_need, arg_cols, arg_rows;
52059243Sobrien    int     verbose = 0, silent = 0;
52159243Sobrien    char   *area;
522167465Smp    static const char fmts[] = "%s\n", fmtd[] = "%d\n";
52359243Sobrien    struct termcapstr *t;
52459243Sobrien    char    buf[TC_BUFSIZE];
525167465Smp    Char **globbed;
52659243Sobrien
52759243Sobrien    area = buf;
52859243Sobrien
52959243Sobrien    setname("echotc");
53059243Sobrien
531167465Smp    v = glob_all_or_error(v);
532167465Smp    globbed = v;
533167465Smp    cleanup_push(globbed, blk_cleanup);
53459243Sobrien
53559243Sobrien    if (!*v || *v[0] == '\0')
536167465Smp	goto end;
53759243Sobrien    if (v[0][0] == '-') {
53859243Sobrien	switch (v[0][1]) {
53959243Sobrien	case 'v':
54059243Sobrien	    verbose = 1;
54159243Sobrien	    break;
54259243Sobrien	case 's':
54359243Sobrien	    silent = 1;
54459243Sobrien	    break;
54559243Sobrien	default:
54659243Sobrien	    stderror(ERR_NAME | ERR_TCUSAGE);
54759243Sobrien	    break;
54859243Sobrien	}
54959243Sobrien	v++;
55059243Sobrien    }
55159243Sobrien    if (!*v || *v[0] == '\0')
552167465Smp	goto end;
553167465Smp    cv = strsave(short2str(*v));
554167465Smp    cleanup_push(cv, xfree);
55559243Sobrien    if (strcmp(cv, "tabs") == 0) {
55659243Sobrien	xprintf(fmts, T_Tabs ? CGETS(7, 14, "yes") :
55759243Sobrien		CGETS(7, 15, "no"));
558167465Smp	goto end_flush;
55959243Sobrien    }
56059243Sobrien    else if (strcmp(cv, "meta") == 0) {
56159243Sobrien	xprintf(fmts, Val(T_km) ? CGETS(7, 14, "yes") :
56259243Sobrien		CGETS(7, 15, "no"));
563167465Smp	goto end_flush;
56459243Sobrien    }
56559243Sobrien    else if (strcmp(cv, "xn") == 0) {
56659243Sobrien	xprintf(fmts, T_Margin & MARGIN_MAGIC ? CGETS(7, 14, "yes") :
56759243Sobrien		CGETS(7, 15,  "no"));
568167465Smp	goto end_flush;
56959243Sobrien    }
57059243Sobrien    else if (strcmp(cv, "am") == 0) {
57159243Sobrien	xprintf(fmts, T_Margin & MARGIN_AUTO ? CGETS(7, 14, "yes") :
57259243Sobrien		CGETS(7, 15, "no"));
573167465Smp	goto end_flush;
57459243Sobrien    }
57559243Sobrien    else if (strcmp(cv, "baud") == 0) {
57659243Sobrien	int     i;
57759243Sobrien
57859243Sobrien	for (i = 0; baud_rate[i].b_name != NULL; i++)
57959243Sobrien	    if (T_Speed == baud_rate[i].b_rate) {
58059243Sobrien		xprintf(fmts, baud_rate[i].b_name);
581167465Smp		goto end_flush;
58259243Sobrien	    }
58359243Sobrien	xprintf(fmtd, 0);
584167465Smp	goto end_flush;
58559243Sobrien    }
586167465Smp    else if (strcmp(cv, "rows") == 0 || strcmp(cv, "lines") == 0 ||
587167465Smp	strcmp(cv, "li") == 0) {
58859243Sobrien	xprintf(fmtd, Val(T_li));
589167465Smp	goto end_flush;
59059243Sobrien    }
591167465Smp    else if (strcmp(cv, "cols") == 0 || strcmp(cv, "co") == 0) {
59259243Sobrien	xprintf(fmtd, Val(T_co));
593167465Smp	goto end_flush;
59459243Sobrien    }
59559243Sobrien
59659243Sobrien    /*
59759243Sobrien     * Try to use our local definition first
59859243Sobrien     */
59959243Sobrien    scap = NULL;
60059243Sobrien    for (t = tstr; t->name != NULL; t++)
60159243Sobrien	if (strcmp(t->name, cv) == 0) {
60259243Sobrien	    scap = t->str;
60359243Sobrien	    break;
60459243Sobrien	}
60559243Sobrien    if (t->name == NULL)
60659243Sobrien	scap = tgetstr(cv, &area);
60759243Sobrien    if (!scap || scap[0] == '\0') {
60859243Sobrien	if (tgetflag(cv)) {
609195609Smp	    xprintf("%s", CGETS(7, 14, "yes\n"));
610167465Smp	    goto end;
61159243Sobrien	}
61259243Sobrien	if (silent)
613167465Smp	    goto end;
61459243Sobrien	else
61559243Sobrien	    stderror(ERR_NAME | ERR_TCCAP, cv);
61659243Sobrien    }
61759243Sobrien
61859243Sobrien    /*
61959243Sobrien     * Count home many values we need for this capability.
62059243Sobrien     */
62159243Sobrien    for (cap = scap, arg_need = 0; *cap; cap++)
62259243Sobrien	if (*cap == '%')
62359243Sobrien	    switch (*++cap) {
62459243Sobrien	    case 'd':
62559243Sobrien	    case '2':
62659243Sobrien	    case '3':
62759243Sobrien	    case '.':
62859243Sobrien	    case '+':
62959243Sobrien		arg_need++;
63059243Sobrien		break;
63159243Sobrien	    case '%':
63259243Sobrien	    case '>':
63359243Sobrien	    case 'i':
63459243Sobrien	    case 'r':
63559243Sobrien	    case 'n':
63659243Sobrien	    case 'B':
63759243Sobrien	    case 'D':
63859243Sobrien		break;
63959243Sobrien	    default:
64059243Sobrien		/*
64159243Sobrien		 * hpux has lot's of them...
64259243Sobrien		 */
64359243Sobrien		if (verbose)
64459243Sobrien		    stderror(ERR_NAME | ERR_TCPARM, *cap);
64559243Sobrien		/* This is bad, but I won't complain */
64659243Sobrien		break;
64759243Sobrien	    }
64859243Sobrien
64959243Sobrien    switch (arg_need) {
65059243Sobrien    case 0:
65159243Sobrien	v++;
65259243Sobrien	if (*v && *v[0]) {
65359243Sobrien	    if (silent)
654167465Smp		goto end;
65559243Sobrien	    else
65659243Sobrien		stderror(ERR_NAME | ERR_TCARGS, cv, arg_need);
65759243Sobrien	}
65859243Sobrien	(void) tputs(scap, 1, PUTRAW);
65959243Sobrien	break;
66059243Sobrien    case 1:
66159243Sobrien	v++;
66259243Sobrien	if (!*v || *v[0] == '\0')
66359243Sobrien	    stderror(ERR_NAME | ERR_TCNARGS, cv, 1);
66459243Sobrien	arg_cols = 0;
66559243Sobrien	arg_rows = atoi(short2str(*v));
66659243Sobrien	v++;
66759243Sobrien	if (*v && *v[0]) {
66859243Sobrien	    if (silent)
669167465Smp		goto end;
67059243Sobrien	    else
67159243Sobrien		stderror(ERR_NAME | ERR_TCARGS, cv, arg_need);
67259243Sobrien	}
67359243Sobrien	(void) tputs(tgoto(scap, arg_cols, arg_rows), 1, PUTRAW);
67459243Sobrien	break;
67559243Sobrien    default:
67659243Sobrien	/* This is wrong, but I will ignore it... */
67759243Sobrien	if (verbose)
67859243Sobrien	    stderror(ERR_NAME | ERR_TCARGS, cv, arg_need);
67959243Sobrien	/*FALLTHROUGH*/
68059243Sobrien    case 2:
68159243Sobrien	v++;
68259243Sobrien	if (!*v || *v[0] == '\0') {
68359243Sobrien	    if (silent)
684167465Smp		goto end;
68559243Sobrien	    else
68659243Sobrien		stderror(ERR_NAME | ERR_TCNARGS, cv, 2);
68759243Sobrien	}
68859243Sobrien	arg_cols = atoi(short2str(*v));
68959243Sobrien	v++;
69059243Sobrien	if (!*v || *v[0] == '\0') {
69159243Sobrien	    if (silent)
692167465Smp		goto end;
69359243Sobrien	    else
69459243Sobrien		stderror(ERR_NAME | ERR_TCNARGS, cv, 2);
69559243Sobrien	}
69659243Sobrien	arg_rows = atoi(short2str(*v));
69759243Sobrien	v++;
69859243Sobrien	if (*v && *v[0]) {
69959243Sobrien	    if (silent)
700167465Smp		goto end;
70159243Sobrien	    else
70259243Sobrien		stderror(ERR_NAME | ERR_TCARGS, cv, arg_need);
70359243Sobrien	}
70459243Sobrien	(void) tputs(tgoto(scap, arg_cols, arg_rows), arg_rows, PUTRAW);
70559243Sobrien	break;
70659243Sobrien    }
707167465Smp end_flush:
70859243Sobrien    flush();
709167465Smp end:
710167465Smp    cleanup_until(globbed);
71159243Sobrien}
71259243Sobrien
713145479Smpint    GotTermCaps = 0;
71459243Sobrien
71559243Sobrienstatic struct {
71659243Sobrien    Char   *name;
71759243Sobrien    int     key;
71859243Sobrien    XmapVal fun;
71959243Sobrien    int	    type;
72059243Sobrien} arrow[] = {
72159243Sobrien#define A_K_DN	0
722145479Smp    { STRdown,	T_kd, { 0 }, 0 },
72359243Sobrien#define A_K_UP	1
724145479Smp    { STRup,	T_ku, { 0 }, 0 },
72559243Sobrien#define A_K_LT	2
726145479Smp    { STRleft,	T_kl, { 0 }, 0 },
72759243Sobrien#define A_K_RT	3
728145479Smp    { STRright, T_kr, { 0 }, 0 },
72969408Sache#define A_K_HO  4
730145479Smp    { STRhome,  T_kh, { 0 }, 0 },
73169408Sache#define A_K_EN  5
732145479Smp    { STRend,   T_at7, { 0 }, 0}
73359243Sobrien};
73469408Sache#define A_K_NKEYS 6
73559243Sobrien
73659243Sobrienvoid
737167465SmpResetArrowKeys(void)
73859243Sobrien{
73959243Sobrien    arrow[A_K_DN].fun.cmd = F_DOWN_HIST;
74059243Sobrien    arrow[A_K_DN].type    = XK_CMD;
74159243Sobrien
74259243Sobrien    arrow[A_K_UP].fun.cmd = F_UP_HIST;
74359243Sobrien    arrow[A_K_UP].type    = XK_CMD;
74459243Sobrien
74559243Sobrien    arrow[A_K_LT].fun.cmd = F_CHARBACK;
74659243Sobrien    arrow[A_K_LT].type    = XK_CMD;
74759243Sobrien
74859243Sobrien    arrow[A_K_RT].fun.cmd = F_CHARFWD;
74959243Sobrien    arrow[A_K_RT].type    = XK_CMD;
75059243Sobrien
75169408Sache    arrow[A_K_HO].fun.cmd = F_TOBEG;
75269408Sache    arrow[A_K_HO].type    = XK_CMD;
75369408Sache
75469408Sache    arrow[A_K_EN].fun.cmd = F_TOEND;
75569408Sache    arrow[A_K_EN].type    = XK_CMD;
75659243Sobrien}
75759243Sobrien
75859243Sobrienvoid
759167465SmpDefaultArrowKeys(void)
76059243Sobrien{
76159243Sobrien    static Char strA[] = {033, '[', 'A', '\0'};
76259243Sobrien    static Char strB[] = {033, '[', 'B', '\0'};
76359243Sobrien    static Char strC[] = {033, '[', 'C', '\0'};
76459243Sobrien    static Char strD[] = {033, '[', 'D', '\0'};
76569408Sache    static Char strH[] = {033, '[', 'H', '\0'};
76669408Sache    static Char strF[] = {033, '[', 'F', '\0'};
76759243Sobrien    static Char stOA[] = {033, 'O', 'A', '\0'};
76859243Sobrien    static Char stOB[] = {033, 'O', 'B', '\0'};
76959243Sobrien    static Char stOC[] = {033, 'O', 'C', '\0'};
77059243Sobrien    static Char stOD[] = {033, 'O', 'D', '\0'};
77169408Sache    static Char stOH[] = {033, 'O', 'H', '\0'};
77269408Sache    static Char stOF[] = {033, 'O', 'F', '\0'};
77359243Sobrien
77459243Sobrien    CStr cs;
77569408Sache#ifndef IS_ASCII
77659243Sobrien    if (strA[0] == 033)
77759243Sobrien    {
77859243Sobrien	strA[0] = CTL_ESC('\033');
77959243Sobrien	strB[0] = CTL_ESC('\033');
78059243Sobrien	strC[0] = CTL_ESC('\033');
78159243Sobrien	strD[0] = CTL_ESC('\033');
78269408Sache	strH[0] = CTL_ESC('\033');
78369408Sache	strF[0] = CTL_ESC('\033');
78459243Sobrien	stOA[0] = CTL_ESC('\033');
78559243Sobrien	stOB[0] = CTL_ESC('\033');
78659243Sobrien	stOC[0] = CTL_ESC('\033');
78759243Sobrien	stOD[0] = CTL_ESC('\033');
78869408Sache	stOH[0] = CTL_ESC('\033');
78969408Sache	stOF[0] = CTL_ESC('\033');
79059243Sobrien    }
79159243Sobrien#endif
79259243Sobrien
79359243Sobrien    cs.len = 3;
79459243Sobrien
79559243Sobrien    cs.buf = strA; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
79659243Sobrien    cs.buf = strB; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
79759243Sobrien    cs.buf = strC; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
79859243Sobrien    cs.buf = strD; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
79969408Sache    cs.buf = strH; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
80069408Sache    cs.buf = strF; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
80159243Sobrien    cs.buf = stOA; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
80259243Sobrien    cs.buf = stOB; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
80359243Sobrien    cs.buf = stOC; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
80459243Sobrien    cs.buf = stOD; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
80569408Sache    cs.buf = stOH; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
80669408Sache    cs.buf = stOF; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
80769408Sache
80859243Sobrien    if (VImode) {
80959243Sobrien	cs.len = 2;
81059243Sobrien	cs.buf = &strA[1]; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
81159243Sobrien	cs.buf = &strB[1]; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
81259243Sobrien	cs.buf = &strC[1]; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
81359243Sobrien	cs.buf = &strD[1]; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
81469408Sache	cs.buf = &strH[1]; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
81569408Sache	cs.buf = &strF[1]; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
81659243Sobrien	cs.buf = &stOA[1]; AddXkey(&cs, &arrow[A_K_UP].fun, arrow[A_K_UP].type);
81759243Sobrien	cs.buf = &stOB[1]; AddXkey(&cs, &arrow[A_K_DN].fun, arrow[A_K_DN].type);
81859243Sobrien	cs.buf = &stOC[1]; AddXkey(&cs, &arrow[A_K_RT].fun, arrow[A_K_RT].type);
81959243Sobrien	cs.buf = &stOD[1]; AddXkey(&cs, &arrow[A_K_LT].fun, arrow[A_K_LT].type);
82069408Sache	cs.buf = &stOH[1]; AddXkey(&cs, &arrow[A_K_HO].fun, arrow[A_K_HO].type);
82169408Sache	cs.buf = &stOF[1]; AddXkey(&cs, &arrow[A_K_EN].fun, arrow[A_K_EN].type);
82259243Sobrien    }
82359243Sobrien}
82459243Sobrien
82559243Sobrien
82659243Sobrienint
827167465SmpSetArrowKeys(const CStr *name, XmapVal *fun, int type)
82859243Sobrien{
82959243Sobrien    int i;
83069408Sache    for (i = 0; i < A_K_NKEYS; i++)
83159243Sobrien	if (Strcmp(name->buf, arrow[i].name) == 0) {
83259243Sobrien	    arrow[i].fun  = *fun;
83359243Sobrien	    arrow[i].type = type;
83459243Sobrien	    return 0;
83559243Sobrien	}
83659243Sobrien    return -1;
83759243Sobrien}
83859243Sobrien
83959243Sobrienint
840167465SmpIsArrowKey(Char *name)
84159243Sobrien{
84259243Sobrien    int i;
84369408Sache    for (i = 0; i < A_K_NKEYS; i++)
84459243Sobrien	if (Strcmp(name, arrow[i].name) == 0)
84559243Sobrien	    return 1;
84659243Sobrien    return 0;
84759243Sobrien}
84859243Sobrien
84959243Sobrienint
850167465SmpClearArrowKeys(const CStr *name)
85159243Sobrien{
85259243Sobrien    int i;
85369408Sache    for (i = 0; i < A_K_NKEYS; i++)
85459243Sobrien	if (Strcmp(name->buf, arrow[i].name) == 0) {
85559243Sobrien	    arrow[i].type = XK_NOD;
85659243Sobrien	    return 0;
85759243Sobrien	}
85859243Sobrien    return -1;
85959243Sobrien}
86059243Sobrien
86159243Sobrienvoid
862167465SmpPrintArrowKeys(const CStr *name)
86359243Sobrien{
86459243Sobrien    int i;
86559243Sobrien
86669408Sache    for (i = 0; i < A_K_NKEYS; i++)
86759243Sobrien	if (name->len == 0 || Strcmp(name->buf, arrow[i].name) == 0)
868167465Smp	    if (arrow[i].type != XK_NOD)
869167465Smp		printOne(arrow[i].name, &arrow[i].fun, arrow[i].type);
87059243Sobrien}
87159243Sobrien
87259243Sobrien
87359243Sobrienvoid
874167465SmpBindArrowKeys(void)
87559243Sobrien{
87659243Sobrien    KEYCMD *map, *dmap;
87759243Sobrien    int     i, j;
87859243Sobrien    char   *p;
87959243Sobrien    CStr    cs;
88059243Sobrien
88159243Sobrien    if (!GotTermCaps)
88259243Sobrien	return;
88359243Sobrien    map = VImode ? CcAltMap : CcKeyMap;
88459243Sobrien    dmap = VImode ? CcViCmdMap : CcEmacsMap;
88559243Sobrien
88659243Sobrien    DefaultArrowKeys();
88759243Sobrien
88869408Sache    for (i = 0; i < A_K_NKEYS; i++) {
88959243Sobrien	p = tstr[arrow[i].key].str;
89059243Sobrien	if (p && *p) {
89159243Sobrien	    j = (unsigned char) *p;
89259243Sobrien	    cs.buf = str2short(p);
89359243Sobrien	    cs.len = Strlen(cs.buf);
89459243Sobrien	    /*
89559243Sobrien	     * Assign the arrow keys only if:
89659243Sobrien	     *
89759243Sobrien	     * 1. They are multi-character arrow keys and the user
89859243Sobrien	     *    has not re-assigned the leading character, or
89959243Sobrien	     *    has re-assigned the leading character to be F_XKEY
90059243Sobrien	     * 2. They are single arrow keys pointing to an unassigned key.
90159243Sobrien	     */
90259243Sobrien	    if (arrow[i].type == XK_NOD) {
90359243Sobrien		ClearXkey(map, &cs);
90459243Sobrien	    }
90559243Sobrien	    else {
90659243Sobrien		if (p[1] && (dmap[j] == map[j] || map[j] == F_XKEY)) {
90759243Sobrien		    AddXkey(&cs, &arrow[i].fun, arrow[i].type);
90859243Sobrien		    map[j] = F_XKEY;
90959243Sobrien		}
91059243Sobrien		else if (map[j] == F_UNASSIGNED) {
91159243Sobrien		    ClearXkey(map, &cs);
91259243Sobrien		    if (arrow[i].type == XK_CMD)
91359243Sobrien			map[j] = arrow[i].fun.cmd;
91459243Sobrien		    else
91559243Sobrien			AddXkey(&cs, &arrow[i].fun, arrow[i].type);
91659243Sobrien		}
91759243Sobrien	    }
91859243Sobrien	}
91959243Sobrien    }
92059243Sobrien}
92159243Sobrien
92259243Sobrienstatic Char cur_atr = 0;	/* current attributes */
92359243Sobrien
92459243Sobrienvoid
925167465SmpSetAttributes(Char atr)
92659243Sobrien{
92759243Sobrien    atr &= ATTRIBUTES;
92859243Sobrien    if (atr != cur_atr) {
92959243Sobrien	if (me_all && GoodStr(T_me)) {
93059243Sobrien	    if (((cur_atr & BOLD) && !(atr & BOLD)) ||
93159243Sobrien		((cur_atr & UNDER) && !(atr & UNDER)) ||
93259243Sobrien		((cur_atr & STANDOUT) && !(atr & STANDOUT))) {
93359243Sobrien		(void) tputs(Str(T_me), 1, PUTPURE);
93459243Sobrien		cur_atr = 0;
93559243Sobrien	    }
93659243Sobrien	}
93759243Sobrien	if ((atr & BOLD) != (cur_atr & BOLD)) {
93859243Sobrien	    if (atr & BOLD) {
93959243Sobrien		if (GoodStr(T_md) && GoodStr(T_me)) {
94059243Sobrien		    (void) tputs(Str(T_md), 1, PUTPURE);
94159243Sobrien		    cur_atr |= BOLD;
94259243Sobrien		}
94359243Sobrien	    }
94459243Sobrien	    else {
94559243Sobrien		if (GoodStr(T_md) && GoodStr(T_me)) {
94659243Sobrien		    (void) tputs(Str(T_me), 1, PUTPURE);
94759243Sobrien		    if ((cur_atr & STANDOUT) && GoodStr(T_se)) {
94859243Sobrien			(void) tputs(Str(T_se), 1, PUTPURE);
94959243Sobrien			cur_atr &= ~STANDOUT;
95059243Sobrien		    }
95159243Sobrien		    if ((cur_atr & UNDER) && GoodStr(T_ue)) {
95259243Sobrien			(void) tputs(Str(T_ue), 1, PUTPURE);
95359243Sobrien			cur_atr &= ~UNDER;
95459243Sobrien		    }
95559243Sobrien		    cur_atr &= ~BOLD;
95659243Sobrien		}
95759243Sobrien	    }
95859243Sobrien	}
95959243Sobrien	if ((atr & STANDOUT) != (cur_atr & STANDOUT)) {
96059243Sobrien	    if (atr & STANDOUT) {
96159243Sobrien		if (GoodStr(T_so) && GoodStr(T_se)) {
96259243Sobrien		    (void) tputs(Str(T_so), 1, PUTPURE);
96359243Sobrien		    cur_atr |= STANDOUT;
96459243Sobrien		}
96559243Sobrien	    }
96659243Sobrien	    else {
96759243Sobrien		if (GoodStr(T_se)) {
96859243Sobrien		    (void) tputs(Str(T_se), 1, PUTPURE);
96959243Sobrien		    cur_atr &= ~STANDOUT;
97059243Sobrien		}
97159243Sobrien	    }
97259243Sobrien	}
97359243Sobrien	if ((atr & UNDER) != (cur_atr & UNDER)) {
97459243Sobrien	    if (atr & UNDER) {
97559243Sobrien		if (GoodStr(T_us) && GoodStr(T_ue)) {
97659243Sobrien		    (void) tputs(Str(T_us), 1, PUTPURE);
97759243Sobrien		    cur_atr |= UNDER;
97859243Sobrien		}
97959243Sobrien	    }
98059243Sobrien	    else {
98159243Sobrien		if (GoodStr(T_ue)) {
98259243Sobrien		    (void) tputs(Str(T_ue), 1, PUTPURE);
98359243Sobrien		    cur_atr &= ~UNDER;
98459243Sobrien		}
98559243Sobrien	    }
98659243Sobrien	}
98759243Sobrien    }
98859243Sobrien}
98959243Sobrien
990167465Smpint highlighting = 0;
991167465Smp
992167465Smpvoid
993316957SdchaginStartHighlight(void)
994167465Smp{
995167465Smp    (void) tputs(Str(T_mr), 1, PUTPURE);
996167465Smp    highlighting = 1;
997167465Smp}
998167465Smp
999167465Smpvoid
1000316957SdchaginStopHighlight(void)
1001167465Smp{
1002167465Smp    (void) tputs(Str(T_me), 1, PUTPURE);
1003167465Smp    highlighting = 0;
1004167465Smp}
1005167465Smp
100659243Sobrien/* PWP 6-27-88 -- if the tty driver thinks that we can tab, we ask termcap */
100759243Sobrienint
1008167465SmpCanWeTab(void)
100959243Sobrien{
101059243Sobrien    return (Val(T_pt));
101159243Sobrien}
101259243Sobrien
1013167465Smp/* move to line <where> (first line == 0) as efficiently as possible; */
101459243Sobrienvoid
1015167465SmpMoveToLine(int where)
101659243Sobrien{
101759243Sobrien    int     del;
101859243Sobrien
101959243Sobrien    if (where == CursorV)
102059243Sobrien	return;
102159243Sobrien
102259243Sobrien    if (where > TermV) {
102359243Sobrien#ifdef DEBUG_SCREEN
102459243Sobrien	xprintf("MoveToLine: where is ridiculous: %d\r\n", where);
102559243Sobrien	flush();
102659243Sobrien#endif /* DEBUG_SCREEN */
102759243Sobrien	return;
102859243Sobrien    }
102959243Sobrien
103059243Sobrien    del = where - CursorV;
103159243Sobrien
103259243Sobrien    if (del > 0) {
103359243Sobrien	while (del > 0) {
103459243Sobrien	    if ((T_Margin & MARGIN_AUTO) && Display[CursorV][0] != '\0') {
1035145479Smp		size_t h;
1036145479Smp
1037145479Smp		for (h = TermH - 1; h > 0 && Display[CursorV][h] == CHAR_DBWIDTH;
1038145479Smp		     h--)
1039145479Smp		    ;
104059243Sobrien		/* move without newline */
1041145479Smp		MoveToChar(h);
1042145479Smp		so_write(&Display[CursorV][CursorH], TermH - CursorH); /* updates CursorH/V*/
104359243Sobrien		del--;
104459243Sobrien	    }
104559243Sobrien	    else {
104659243Sobrien		if ((del > 1) && GoodStr(T_DO)) {
104759243Sobrien		    (void) tputs(tgoto(Str(T_DO), del, del), del, PUTPURE);
104859243Sobrien		    del = 0;
104959243Sobrien		}
105059243Sobrien		else {
105159243Sobrien		    for ( ; del > 0; del--)
105259243Sobrien			(void) putraw('\n');
105359243Sobrien		    CursorH = 0;	/* because the \n will become \r\n */
105459243Sobrien		}
105559243Sobrien	    }
105659243Sobrien	}
105759243Sobrien    }
105859243Sobrien    else {			/* del < 0 */
105959243Sobrien	if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up)))
106059243Sobrien	    (void) tputs(tgoto(Str(T_UP), -del, -del), -del, PUTPURE);
106159243Sobrien	else {
106259243Sobrien	    int i;
106359243Sobrien	    if (GoodStr(T_up))
106459243Sobrien		for (i = 0; i < -del; i++)
106559243Sobrien		    (void) tputs(Str(T_up), 1, PUTPURE);
106659243Sobrien	}
106759243Sobrien    }
106859243Sobrien    CursorV = where;		/* now where is here */
106959243Sobrien}
107059243Sobrien
107159243Sobrienvoid
1072167465SmpMoveToChar(int where)		/* move to character position (where) */
107359243Sobrien{				/* as efficiently as possible */
107459243Sobrien    int     del;
107559243Sobrien
107659243Sobrienmc_again:
107759243Sobrien    if (where == CursorH)
107859243Sobrien	return;
107959243Sobrien
108059243Sobrien    if (where >= TermH) {
108159243Sobrien#ifdef DEBUG_SCREEN
108259243Sobrien	xprintf("MoveToChar: where is riduculous: %d\r\n", where);
108359243Sobrien	flush();
108459243Sobrien#endif /* DEBUG_SCREEN */
108559243Sobrien	return;
108659243Sobrien    }
108759243Sobrien
108859243Sobrien    if (!where) {		/* if where is first column */
108959243Sobrien	(void) putraw('\r');	/* do a CR */
109059243Sobrien	CursorH = 0;
109159243Sobrien	return;
109259243Sobrien    }
109359243Sobrien
109459243Sobrien    del = where - CursorH;
109559243Sobrien
109659243Sobrien    if ((del < -4 || del > 4) && GoodStr(T_ch))
109759243Sobrien	/* go there directly */
109859243Sobrien	(void) tputs(tgoto(Str(T_ch), where, where), where, PUTPURE);
109959243Sobrien    else {
110059243Sobrien	int i;
110159243Sobrien	if (del > 0) {		/* moving forward */
110259243Sobrien	    if ((del > 4) && GoodStr(T_RI))
110359243Sobrien		(void) tputs(tgoto(Str(T_RI), del, del), del, PUTPURE);
110459243Sobrien	    else {
110569408Sache		/* if I can do tabs, use them */
1106145479Smp		if (T_Tabs) {
1107145479Smp		    if ((CursorH & 0370) != (where & ~0x7)
1108145479Smp			&& Display[CursorV][where & ~0x7] != CHAR_DBWIDTH) {
110959243Sobrien			/* if not within tab stop */
1110145479Smp			for (i = (CursorH & 0370); i < (where & ~0x7); i += 8)
111159243Sobrien			    (void) putraw('\t');	/* then tab over */
1112145479Smp			CursorH = where & ~0x7;
111359243Sobrien			/* Note: considering that we often want to go to
111459243Sobrien			   TermH - 1 for the wrapping, it would be nice to
111559243Sobrien			   optimize this case by tabbing to the last column
111659243Sobrien			   - but this doesn't work for all terminals! */
111759243Sobrien		    }
111859243Sobrien		}
111959243Sobrien		/* it's usually cheaper to just write the chars, so we do. */
112059243Sobrien
112159243Sobrien		/* NOTE THAT so_write() WILL CHANGE CursorH!!! */
112259243Sobrien		so_write(&Display[CursorV][CursorH], where - CursorH);
112359243Sobrien
112459243Sobrien	    }
112559243Sobrien	}
112659243Sobrien	else {			/* del < 0 := moving backward */
112759243Sobrien	    if ((-del > 4) && GoodStr(T_LE))
112859243Sobrien		(void) tputs(tgoto(Str(T_LE), -del, -del), -del, PUTPURE);
112959243Sobrien	    else {		/* can't go directly there */
113059243Sobrien		/* if the "cost" is greater than the "cost" from col 0 */
113159243Sobrien		if (T_Tabs ? (-del > ((where >> 3) + (where & 07)))
113259243Sobrien		    : (-del > where)) {
113359243Sobrien		    (void) putraw('\r');	/* do a CR */
113459243Sobrien		    CursorH = 0;
113559243Sobrien		    goto mc_again;	/* and try again */
113659243Sobrien		}
113759243Sobrien		for (i = 0; i < -del; i++)
113859243Sobrien		    (void) putraw('\b');
113959243Sobrien	    }
114059243Sobrien	}
114159243Sobrien    }
114259243Sobrien    CursorH = where;		/* now where is here */
114359243Sobrien}
114459243Sobrien
114559243Sobrienvoid
1146167465Smpso_write(Char *cp, int n)
114759243Sobrien{
1148167465Smp    int cur_pos, prompt_len = 0, region_start = 0, region_end = 0;
1149167465Smp
115059243Sobrien    if (n <= 0)
115159243Sobrien	return;			/* catch bugs */
115259243Sobrien
115359243Sobrien    if (n > TermH) {
115459243Sobrien#ifdef DEBUG_SCREEN
115559243Sobrien	xprintf("so_write: n is riduculous: %d\r\n", n);
115659243Sobrien	flush();
115759243Sobrien#endif /* DEBUG_SCREEN */
115859243Sobrien	return;
115959243Sobrien    }
116059243Sobrien
1161167465Smp    if (adrof(STRhighlight)) {
1162167465Smp	/* find length of prompt */
1163167465Smp	Char *promptc;
1164167465Smp	for (promptc = Prompt; *promptc; promptc++);
1165167465Smp	prompt_len = promptc - Prompt;
1166167465Smp
1167167465Smp	/* find region start and end points */
1168167465Smp	if (IncMatchLen) {
1169167465Smp	    region_start = (Cursor - InputBuf) + prompt_len;
1170167465Smp	    region_end = region_start + IncMatchLen;
1171167465Smp	} else if (MarkIsSet) {
1172167465Smp	    region_start = (min(Cursor, Mark) - InputBuf) + prompt_len;
1173167465Smp	    region_end   = (max(Cursor, Mark) - InputBuf) + prompt_len;
1174167465Smp	}
1175167465Smp    }
1176167465Smp
117759243Sobrien    do {
1178167465Smp	if (adrof(STRhighlight)) {
1179167465Smp	    cur_pos = CursorV * TermH + CursorH;
1180167465Smp	    if (!highlighting &&
1181167465Smp		cur_pos >= region_start && cur_pos < region_end)
1182167465Smp		StartHighlight();
1183167465Smp	    else if (highlighting && cur_pos >= region_end)
1184167465Smp		StopHighlight();
1185167465Smp
1186167465Smp	    /* don't highlight over the cursor. the highlighting's reverse
1187167465Smp	     * video would cancel it out. :P */
1188167465Smp	    if (highlighting && cur_pos == (Cursor - InputBuf) + prompt_len)
1189167465Smp		StopHighlight();
1190167465Smp	}
1191167465Smp
1192145479Smp	if (*cp != CHAR_DBWIDTH) {
1193145479Smp	    if (*cp & LITERAL) {
1194145479Smp		Char   *d;
119559243Sobrien#ifdef DEBUG_LITERAL
1196145479Smp		xprintf("so: litnum %d\r\n", (int)(*cp & ~LITERAL));
119759243Sobrien#endif /* DEBUG_LITERAL */
1198145479Smp		for (d = litptr + (*cp & ~LITERAL) * LIT_FACTOR; *d; d++)
1199145479Smp		    (void) putwraw(*d);
1200145479Smp	    }
1201145479Smp	    else
1202145479Smp		(void) putwraw(*cp);
120359243Sobrien	}
1204145479Smp	cp++;
120559243Sobrien	CursorH++;
120659243Sobrien    } while (--n);
120759243Sobrien
1208167465Smp    if (adrof(STRhighlight) && highlighting)
1209167465Smp	StopHighlight();
1210167465Smp
121159243Sobrien    if (CursorH >= TermH) { /* wrap? */
121259243Sobrien	if (T_Margin & MARGIN_AUTO) { /* yes */
121359243Sobrien	    CursorH = 0;
121459243Sobrien	    CursorV++;
121559243Sobrien	    if (T_Margin & MARGIN_MAGIC) {
121659243Sobrien		/* force the wrap to avoid the "magic" situation */
1217167465Smp		Char xc;
1218167465Smp		if ((xc = Display[CursorV][CursorH]) != '\0') {
1219167465Smp		    so_write(&xc, 1);
1220145479Smp		    while(Display[CursorV][CursorH] == CHAR_DBWIDTH)
1221145479Smp			CursorH++;
1222145479Smp		}
1223145479Smp		else {
122459243Sobrien		    (void) putraw(' ');
1225145479Smp		    CursorH = 1;
1226145479Smp		}
122759243Sobrien	    }
122859243Sobrien	}
122959243Sobrien	else			/* no wrap, but cursor stays on screen */
123059243Sobrien	    CursorH = TermH - 1;
123159243Sobrien    }
123259243Sobrien}
123359243Sobrien
123459243Sobrien
123559243Sobrienvoid
1236167465SmpDeleteChars(int num)		/* deletes <num> characters */
123759243Sobrien{
123859243Sobrien    if (num <= 0)
123959243Sobrien	return;
124059243Sobrien
124159243Sobrien    if (!T_CanDel) {
124259243Sobrien#ifdef DEBUG_EDIT
124359243Sobrien	xprintf(CGETS(7, 16, "ERROR: cannot delete\r\n"));
124459243Sobrien#endif /* DEBUG_EDIT */
124559243Sobrien	flush();
124659243Sobrien	return;
124759243Sobrien    }
124859243Sobrien
124959243Sobrien    if (num > TermH) {
125059243Sobrien#ifdef DEBUG_SCREEN
125159243Sobrien	xprintf(CGETS(7, 17, "DeleteChars: num is riduculous: %d\r\n"), num);
125259243Sobrien	flush();
125359243Sobrien#endif /* DEBUG_SCREEN */
125459243Sobrien	return;
125559243Sobrien    }
125659243Sobrien
125759243Sobrien    if (GoodStr(T_DC))		/* if I have multiple delete */
125859243Sobrien	if ((num > 1) || !GoodStr(T_dc)) {	/* if dc would be more expen. */
125959243Sobrien	    (void) tputs(tgoto(Str(T_DC), num, num), num, PUTPURE);
126059243Sobrien	    return;
126159243Sobrien	}
126259243Sobrien
126359243Sobrien    if (GoodStr(T_dm))		/* if I have delete mode */
126459243Sobrien	(void) tputs(Str(T_dm), 1, PUTPURE);
126559243Sobrien
126659243Sobrien    if (GoodStr(T_dc))		/* else do one at a time */
126759243Sobrien	while (num--)
126859243Sobrien	    (void) tputs(Str(T_dc), 1, PUTPURE);
126959243Sobrien
127059243Sobrien    if (GoodStr(T_ed))		/* if I have delete mode */
127159243Sobrien	(void) tputs(Str(T_ed), 1, PUTPURE);
127259243Sobrien}
127359243Sobrien
1274167465Smp/* Puts terminal in insert character mode, or inserts num characters in the
1275167465Smp   line */
127659243Sobrienvoid
1277167465SmpInsert_write(Char *cp, int num)
127859243Sobrien{
127959243Sobrien    if (num <= 0)
128059243Sobrien	return;
128159243Sobrien    if (!T_CanIns) {
128259243Sobrien#ifdef DEBUG_EDIT
128359243Sobrien	xprintf(CGETS(7, 18, "ERROR: cannot insert\r\n"));
128459243Sobrien#endif /* DEBUG_EDIT */
128559243Sobrien	flush();
128659243Sobrien	return;
128759243Sobrien    }
128859243Sobrien
128959243Sobrien    if (num > TermH) {
129059243Sobrien#ifdef DEBUG_SCREEN
129159243Sobrien	xprintf(CGETS(7, 19, "StartInsert: num is riduculous: %d\r\n"), num);
129259243Sobrien	flush();
129359243Sobrien#endif /* DEBUG_SCREEN */
129459243Sobrien	return;
129559243Sobrien    }
129659243Sobrien
129759243Sobrien    if (GoodStr(T_IC))		/* if I have multiple insert */
129859243Sobrien	if ((num > 1) || !GoodStr(T_ic)) {	/* if ic would be more expen. */
129959243Sobrien	    (void) tputs(tgoto(Str(T_IC), num, num), num, PUTPURE);
130059243Sobrien	    so_write(cp, num);	/* this updates CursorH/V */
130159243Sobrien	    return;
130259243Sobrien	}
130359243Sobrien
130459243Sobrien    if (GoodStr(T_im) && GoodStr(T_ei)) { /* if I have insert mode */
130559243Sobrien	(void) tputs(Str(T_im), 1, PUTPURE);
130659243Sobrien
1307145479Smp	so_write(cp, num);	/* this updates CursorH/V */
130859243Sobrien
130959243Sobrien	if (GoodStr(T_ip))	/* have to make num chars insert */
131059243Sobrien	    (void) tputs(Str(T_ip), 1, PUTPURE);
131159243Sobrien
131259243Sobrien	(void) tputs(Str(T_ei), 1, PUTPURE);
131359243Sobrien	return;
131459243Sobrien    }
131559243Sobrien
131659243Sobrien    do {
131759243Sobrien	if (GoodStr(T_ic))	/* have to make num chars insert */
131859243Sobrien	    (void) tputs(Str(T_ic), 1, PUTPURE);	/* insert a char */
131959243Sobrien
1320145479Smp	so_write(cp++, 1);	/* this updates CursorH/V */
132159243Sobrien
132259243Sobrien	if (GoodStr(T_ip))	/* have to make num chars insert */
132359243Sobrien	    (void) tputs(Str(T_ip), 1, PUTPURE);/* pad the inserted char */
132459243Sobrien
132559243Sobrien    } while (--num);
132659243Sobrien
132759243Sobrien}
132859243Sobrien
1329167465Smp/* clear to end of line.  There are num characters to clear */
133059243Sobrienvoid
1331167465SmpClearEOL(int num)
133259243Sobrien{
1333145479Smp    int i;
133459243Sobrien
133559243Sobrien    if (num <= 0)
133659243Sobrien	return;
133759243Sobrien
133859243Sobrien    if (T_CanCEOL && GoodStr(T_ce))
133959243Sobrien	(void) tputs(Str(T_ce), 1, PUTPURE);
134059243Sobrien    else {
134159243Sobrien	for (i = 0; i < num; i++)
134259243Sobrien	    (void) putraw(' ');
134359243Sobrien	CursorH += num;		/* have written num spaces */
134459243Sobrien    }
134559243Sobrien}
134659243Sobrien
134759243Sobrienvoid
1348167465SmpClearScreen(void)
134959243Sobrien{				/* clear the whole screen and home */
135059243Sobrien    if (GoodStr(T_cl))
135159243Sobrien	/* send the clear screen code */
135259243Sobrien	(void) tputs(Str(T_cl), Val(T_li), PUTPURE);
135359243Sobrien    else if (GoodStr(T_ho) && GoodStr(T_cd)) {
135459243Sobrien	(void) tputs(Str(T_ho), Val(T_li), PUTPURE);	/* home */
135559243Sobrien	/* clear to bottom of screen */
135659243Sobrien	(void) tputs(Str(T_cd), Val(T_li), PUTPURE);
135759243Sobrien    }
135859243Sobrien    else {
135959243Sobrien	(void) putraw('\r');
136059243Sobrien	(void) putraw('\n');
136159243Sobrien    }
136259243Sobrien}
136359243Sobrien
136459243Sobrienvoid
1365167465SmpSoundBeep(void)
136659243Sobrien{				/* produce a sound */
136759243Sobrien    beep_cmd ();
136859243Sobrien    if (adrof(STRnobeep))
136959243Sobrien	return;
137059243Sobrien
137159243Sobrien    if (GoodStr(T_vb) && adrof(STRvisiblebell))
137259243Sobrien	(void) tputs(Str(T_vb), 1, PUTPURE);	/* visible bell */
137359243Sobrien    else if (GoodStr(T_bl))
137459243Sobrien	/* what termcap says we should use */
137559243Sobrien	(void) tputs(Str(T_bl), 1, PUTPURE);
137659243Sobrien    else
137759243Sobrien	(void) putraw(CTL_ESC('\007'));	/* an ASCII bell; ^G */
137859243Sobrien}
137959243Sobrien
138059243Sobrienvoid
1381167465SmpClearToBottom(void)
138259243Sobrien{				/* clear to the bottom of the screen */
138359243Sobrien    if (GoodStr(T_cd))
138459243Sobrien	(void) tputs(Str(T_cd), Val(T_li), PUTPURE);
138559243Sobrien    else if (GoodStr(T_ce))
138659243Sobrien	(void) tputs(Str(T_ce), Val(T_li), PUTPURE);
138759243Sobrien}
138859243Sobrien
138959243Sobrienvoid
1390167465SmpGetTermCaps(void)
139159243Sobrien{				/* read in the needed terminal capabilites */
1392145479Smp    int i;
1393145479Smp    const char   *ptr;
139459243Sobrien    char    buf[TC_BUFSIZE];
139559243Sobrien    static char bp[TC_BUFSIZE];
139659243Sobrien    char   *area;
139759243Sobrien    struct termcapstr *t;
139859243Sobrien
139959243Sobrien
140059243Sobrien#ifdef SIG_WINDOW
1401167465Smp    sigset_t oset, set;
140259243Sobrien    int     lins, cols;
140359243Sobrien
140459243Sobrien    /* don't want to confuse things here */
1405167465Smp    sigemptyset(&set);
1406167465Smp    sigaddset(&set, SIG_WINDOW);
1407167465Smp    (void)sigprocmask(SIG_BLOCK, &set, &oset);
1408167465Smp    cleanup_push(&oset, sigprocmask_cleanup);
140959243Sobrien#endif /* SIG_WINDOW */
141059243Sobrien    area = buf;
141159243Sobrien
141259243Sobrien    GotTermCaps = 1;
141359243Sobrien
141459243Sobrien    setname("gettermcaps");
141559243Sobrien    ptr = getenv("TERM");
141659243Sobrien
141759243Sobrien#ifdef apollo
141859243Sobrien    /*
141959243Sobrien     * If we are on a pad, we pretend that we are dumb. Otherwise the termcap
142059243Sobrien     * library will put us in a weird screen mode, thinking that we are going
142159243Sobrien     * to use curses
142259243Sobrien     */
142359243Sobrien    if (isapad())
142459243Sobrien	ptr = "dumb";
142559243Sobrien#endif /* apollo */
142659243Sobrien
142759243Sobrien    if (!ptr || !ptr[0] || !strcmp(ptr, "wm") || !strcmp(ptr,"dmx"))
142859243Sobrien	ptr = "dumb";
142959243Sobrien
143059243Sobrien    setzero(bp, TC_BUFSIZE);
143159243Sobrien
143259243Sobrien    i = tgetent(bp, ptr);
143359243Sobrien    if (i <= 0) {
143459243Sobrien	if (i == -1) {
143559243Sobrien#if (SYSVREL == 0) || defined(IRIS3D)
1436316957Sdchagin	    xprintf(CGETS(7, 20,
1437316957Sdchagin		"%s: The terminal database could not be opened.\n"), progname);
143859243Sobrien	}
143959243Sobrien	else if (i == 0) {
144059243Sobrien#endif /* SYSVREL */
144159243Sobrien	    xprintf(CGETS(7, 21,
144259243Sobrien			  "%s: No entry for terminal type \"%s\"\n"), progname,
144359243Sobrien		    getenv("TERM"));
144459243Sobrien	}
144559243Sobrien	xprintf(CGETS(7, 22, "%s: using dumb terminal settings.\n"), progname);
144659243Sobrien	Val(T_co) = 80;		/* do a dumb terminal */
144759243Sobrien	Val(T_pt) = Val(T_km) = Val(T_li) = 0;
144859243Sobrien	for (t = tstr; t->name != NULL; t++)
1449167465Smp	    TCset(t, NULL);
145059243Sobrien    }
145159243Sobrien    else {
145259243Sobrien	/* Can we tab */
145359243Sobrien	Val(T_pt) = tgetflag("pt") && !tgetflag("xt");
145459243Sobrien	/* do we have a meta? */
145559243Sobrien	Val(T_km) = (tgetflag("km") || tgetflag("MT"));
145659243Sobrien	Val(T_am) = tgetflag("am");
145759243Sobrien	Val(T_xn) = tgetflag("xn");
145859243Sobrien	Val(T_co) = tgetnum("co");
145959243Sobrien	Val(T_li) = tgetnum("li");
146059243Sobrien	for (t = tstr; t->name != NULL; t++)
1461167465Smp	    TCset(t, tgetstr(t->name, &area));
146259243Sobrien    }
146359243Sobrien    if (Val(T_co) < 2)
146459243Sobrien	Val(T_co) = 80;		/* just in case */
146559243Sobrien    if (Val(T_li) < 1)
146659243Sobrien	Val(T_li) = 24;
146759243Sobrien
146859243Sobrien    T_Cols = (Char) Val(T_co);
146959243Sobrien    T_Lines = (Char) Val(T_li);
147059243Sobrien    if (T_Tabs)
1471167465Smp	T_Tabs = Val(T_pt);
1472167465Smp    T_HasMeta = Val(T_km);
1473167465Smp    T_Margin = Val(T_am) ? MARGIN_AUTO : 0;
1474167465Smp    T_Margin |= Val(T_xn) ? MARGIN_MAGIC : 0;
147559243Sobrien    T_CanCEOL = GoodStr(T_ce);
147659243Sobrien    T_CanDel = GoodStr(T_dc) || GoodStr(T_DC);
147759243Sobrien    T_CanIns = GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC);
147859243Sobrien    T_CanUP = GoodStr(T_up) || GoodStr(T_UP);
147959243Sobrien    if (GoodStr(T_me) && GoodStr(T_ue))
148059243Sobrien	me_all = (strcmp(Str(T_me), Str(T_ue)) == 0);
148159243Sobrien    else
148259243Sobrien	me_all = 0;
148359243Sobrien    if (GoodStr(T_me) && GoodStr(T_se))
148459243Sobrien	me_all |= (strcmp(Str(T_me), Str(T_se)) == 0);
148559243Sobrien
148659243Sobrien
148759243Sobrien#ifdef DEBUG_SCREEN
148859243Sobrien    if (!T_CanUP) {
148959243Sobrien	xprintf(CGETS(7, 23, "%s: WARNING: Your terminal cannot move up.\n",
149059243Sobrien		progname));
149159243Sobrien	xprintf(CGETS(7, 24, "Editing may be odd for long lines.\n"));
149259243Sobrien    }
149359243Sobrien    if (!T_CanCEOL)
149459243Sobrien	xprintf(CGETS(7, 25, "no clear EOL capability.\n"));
149559243Sobrien    if (!T_CanDel)
149659243Sobrien	xprintf(CGETS(7, 26, "no delete char capability.\n"));
149759243Sobrien    if (!T_CanIns)
149859243Sobrien	xprintf(CGETS(7, 27, "no insert char capability.\n"));
149959243Sobrien#endif /* DEBUG_SCREEN */
150059243Sobrien
150159243Sobrien
150259243Sobrien
150359243Sobrien#ifdef SIG_WINDOW
150459243Sobrien    (void) GetSize(&lins, &cols);	/* get the correct window size */
150559243Sobrien    ChangeSize(lins, cols);
150659243Sobrien
1507167465Smp    cleanup_until(&oset);		/* can change it again */
150859243Sobrien#else /* SIG_WINDOW */
150959243Sobrien    ChangeSize(Val(T_li), Val(T_co));
151059243Sobrien#endif /* SIG_WINDOW */
151159243Sobrien
151259243Sobrien    BindArrowKeys();
151359243Sobrien}
151459243Sobrien
151559243Sobrien#ifdef SIG_WINDOW
151659243Sobrien/* GetSize():
151759243Sobrien *	Return the new window size in lines and cols, and
151859243Sobrien *	true if the size was changed. This can fail if SHIN
151959243Sobrien *	is not a tty, but it will work in most cases.
152059243Sobrien */
152159243Sobrienint
1522167465SmpGetSize(int *lins, int *cols)
152359243Sobrien{
152459243Sobrien    *cols = Val(T_co);
152559243Sobrien    *lins = Val(T_li);
152659243Sobrien
152759243Sobrien#ifdef TIOCGWINSZ
152859243Sobrien# define KNOWsize
152959243Sobrien# ifndef lint
153059243Sobrien    {
153159243Sobrien	struct winsize ws;	/* from 4.3 */
153259243Sobrien
153359243Sobrien	if (ioctl(SHIN, TIOCGWINSZ, (ioctl_t) &ws) != -1) {
153459243Sobrien	    if (ws.ws_col)
153559243Sobrien		*cols = ws.ws_col;
153659243Sobrien	    if (ws.ws_row)
153759243Sobrien		*lins = ws.ws_row;
153859243Sobrien	}
153959243Sobrien    }
154059243Sobrien# endif /* !lint */
154159243Sobrien#else /* TIOCGWINSZ */
154259243Sobrien# ifdef TIOCGSIZE
154359243Sobrien#  define KNOWsize
154459243Sobrien    {
154559243Sobrien	struct ttysize ts;	/* from Sun */
154659243Sobrien
154759243Sobrien	if (ioctl(SHIN, TIOCGSIZE, (ioctl_t) &ts) != -1) {
154859243Sobrien	    if (ts.ts_cols)
154959243Sobrien		*cols = ts.ts_cols;
155059243Sobrien	    if (ts.ts_lines)
155159243Sobrien		*lins = ts.ts_lines;
155259243Sobrien	}
155359243Sobrien    }
155459243Sobrien# endif /* TIOCGSIZE */
155559243Sobrien#endif /* TIOCGWINSZ */
155659243Sobrien
155759243Sobrien    return (Val(T_co) != *cols || Val(T_li) != *lins);
155859243Sobrien}
155959243Sobrien
1560167465Smp#endif /* SIG_WINDOW */
156159243Sobrien
1562231990Smp#ifdef KNOWsize
1563316957Sdchaginstatic int
1564231990SmpUpdateVal(const Char *tag, int value, Char *termcap, Char *backup)
1565231990Smp{
1566231990Smp    Char *ptr, *p;
1567231990Smp    if ((ptr = Strstr(termcap, tag)) == NULL) {
1568231990Smp	(void)Strcpy(backup, termcap);
1569316957Sdchagin	return 0;
1570231990Smp    } else {
1571231990Smp	size_t len = (ptr - termcap) + Strlen(tag);
1572231990Smp	(void)Strncpy(backup, termcap, len);
1573231990Smp	backup[len] = '\0';
1574231990Smp	p = Itoa(value, 0, 0);
1575231990Smp	(void) Strcat(backup + len, p);
1576231990Smp	xfree(p);
1577231990Smp	ptr = Strchr(ptr, ':');
1578231990Smp	if (ptr)
1579231990Smp	    (void) Strcat(backup, ptr);
1580316957Sdchagin	return 1;
1581231990Smp    }
1582231990Smp}
1583231990Smp#endif
1584231990Smp
158559243Sobrienvoid
1586167465SmpChangeSize(int lins, int cols)
158759243Sobrien{
158859243Sobrien    /*
158959243Sobrien     * Just in case
159059243Sobrien     */
159159243Sobrien    Val(T_co) = (cols < 2) ? 80 : cols;
159259243Sobrien    Val(T_li) = (lins < 1) ? 24 : lins;
159359243Sobrien
159459243Sobrien#ifdef KNOWsize
159559243Sobrien    /*
159659243Sobrien     * We want to affect the environment only when we have a valid
159759243Sobrien     * setup, not when we get bad settings. Consider the following scenario:
159859243Sobrien     * We just logged in, and we have not initialized the editor yet.
159959243Sobrien     * We reset termcap with tset, and not $TERMCAP has the right
160059243Sobrien     * terminal size. But since the editor is not initialized yet, and
160159243Sobrien     * the kernel's notion of the terminal size might be wrong we arrive
160259243Sobrien     * here with lines = columns = 0. If we reset the environment we lose
160359243Sobrien     * our only chance to get the window size right.
160459243Sobrien     */
160559243Sobrien    if (Val(T_co) == cols && Val(T_li) == lins) {
1606167465Smp	Char   *p;
160759243Sobrien	char   *tptr;
160859243Sobrien
160959243Sobrien	if (getenv("COLUMNS")) {
1610167465Smp	    p = Itoa(Val(T_co), 0, 0);
1611167465Smp	    cleanup_push(p, xfree);
1612167465Smp	    tsetenv(STRCOLUMNS, p);
1613167465Smp	    cleanup_until(p);
161459243Sobrien	}
161559243Sobrien
161659243Sobrien	if (getenv("LINES")) {
1617167465Smp	    p = Itoa(Val(T_li), 0, 0);
1618167465Smp	    cleanup_push(p, xfree);
1619167465Smp	    tsetenv(STRLINES, p);
1620167465Smp	    cleanup_until(p);
162159243Sobrien	}
162259243Sobrien
162359243Sobrien	if ((tptr = getenv("TERMCAP")) != NULL) {
162459243Sobrien	    /* Leave 64 characters slop in case we enlarge the termcap string */
1625167465Smp	    Char    termcap[TC_BUFSIZE+64], backup[TC_BUFSIZE+64], *ptr;
1626316957Sdchagin	    int changed;
162759243Sobrien
162859243Sobrien	    ptr = str2short(tptr);
1629167465Smp	    (void) Strncpy(termcap, ptr, TC_BUFSIZE);
1630167465Smp	    termcap[TC_BUFSIZE-1] = '\0';
163159243Sobrien
1632316957Sdchagin	    changed = UpdateVal(STRco, Val(T_co), termcap, backup);
1633316957Sdchagin	    changed |= UpdateVal(STRli, Val(T_li), termcap, backup);
163459243Sobrien
1635316957Sdchagin	    if (changed) {
1636316957Sdchagin		/*
1637316957Sdchagin		 * Chop the termcap string at TC_BUFSIZE-1 characters to avoid
1638316957Sdchagin		 * core-dumps in the termcap routines
1639316957Sdchagin		 */
1640316957Sdchagin		termcap[TC_BUFSIZE - 1] = '\0';
1641316957Sdchagin		tsetenv(STRTERMCAP, termcap);
1642316957Sdchagin	    }
164359243Sobrien	}
164459243Sobrien    }
164559243Sobrien#endif /* KNOWsize */
164659243Sobrien
164759243Sobrien    ReBufferDisplay();		/* re-make display buffers */
164859243Sobrien    ClearDisp();
164959243Sobrien}
1650