xref: /dragonfly/contrib/nvi2/cl/cl_term.c (revision b1ac2ebb)
1e0b8e63eSJohn Marino /*-
2e0b8e63eSJohn Marino  * Copyright (c) 1993, 1994
3e0b8e63eSJohn Marino  *	The Regents of the University of California.  All rights reserved.
4e0b8e63eSJohn Marino  * Copyright (c) 1993, 1994, 1995, 1996
5e0b8e63eSJohn Marino  *	Keith Bostic.  All rights reserved.
6e0b8e63eSJohn Marino  *
7e0b8e63eSJohn Marino  * See the LICENSE file for redistribution information.
8e0b8e63eSJohn Marino  */
9e0b8e63eSJohn Marino 
10e0b8e63eSJohn Marino #include "config.h"
11e0b8e63eSJohn Marino 
12e0b8e63eSJohn Marino #include <sys/types.h>
13e0b8e63eSJohn Marino #include <sys/ioctl.h>
14e0b8e63eSJohn Marino #include <sys/queue.h>
15e0b8e63eSJohn Marino #include <sys/stat.h>
16e0b8e63eSJohn Marino 
17e0b8e63eSJohn Marino #include <bitstring.h>
18e0b8e63eSJohn Marino #include <errno.h>
19e0b8e63eSJohn Marino #include <limits.h>
20e0b8e63eSJohn Marino #include <signal.h>
21e0b8e63eSJohn Marino #include <stdio.h>
22e0b8e63eSJohn Marino #include <stdlib.h>
23e0b8e63eSJohn Marino #include <string.h>
24e0b8e63eSJohn Marino #ifdef HAVE_TERM_H
25e0b8e63eSJohn Marino #include <term.h>
26e0b8e63eSJohn Marino #endif
27e0b8e63eSJohn Marino #include <termios.h>
28e0b8e63eSJohn Marino #include <unistd.h>
29e0b8e63eSJohn Marino 
30e0b8e63eSJohn Marino #include "../common/common.h"
31e0b8e63eSJohn Marino #include "cl.h"
32e0b8e63eSJohn Marino 
33e0b8e63eSJohn Marino static int cl_pfmap(SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t);
34*b1ac2ebbSDaniel Fojt static size_t atoz_or(const char *, size_t);
35e0b8e63eSJohn Marino 
36e0b8e63eSJohn Marino /*
37e0b8e63eSJohn Marino  * XXX
38e0b8e63eSJohn Marino  * THIS REQUIRES THAT ALL SCREENS SHARE A TERMINAL TYPE.
39e0b8e63eSJohn Marino  */
40e0b8e63eSJohn Marino typedef struct _tklist {
41e0b8e63eSJohn Marino 	char	*ts;			/* Key's termcap string. */
42e0b8e63eSJohn Marino 	char	*output;		/* Corresponding vi command. */
43e0b8e63eSJohn Marino 	char	*name;			/* Name. */
44e0b8e63eSJohn Marino 	u_char	 value;			/* Special value (for lookup). */
45e0b8e63eSJohn Marino } TKLIST;
46e0b8e63eSJohn Marino static TKLIST const c_tklist[] = {	/* Command mappings. */
47e0b8e63eSJohn Marino 	{"kil1",	"O",	"insert line"},
48e0b8e63eSJohn Marino 	{"kdch1",	"x",	"delete character"},
49e0b8e63eSJohn Marino 	{"kcud1",	"j",	"cursor down"},
50e0b8e63eSJohn Marino 	{"kel",		"D",	"delete to eol"},
51e0b8e63eSJohn Marino 	{"kind",     "\004",	"scroll down"},			/* ^D */
52e0b8e63eSJohn Marino 	{"kll",		"$",	"go to eol"},
53e0b8e63eSJohn Marino 	{"kend",	"$",	"go to eol"},
54e0b8e63eSJohn Marino 	{"khome",	"^",	"go to sol"},
55e0b8e63eSJohn Marino 	{"kich1",	"i",	"insert at cursor"},
56e0b8e63eSJohn Marino 	{"kdl1",       "dd",	"delete line"},
57e0b8e63eSJohn Marino 	{"kcub1",	"h",	"cursor left"},
58e0b8e63eSJohn Marino 	{"knp",	     "\006",	"page down"},			/* ^F */
59e0b8e63eSJohn Marino 	{"kpp",	     "\002",	"page up"},			/* ^B */
60e0b8e63eSJohn Marino 	{"kri",	     "\025",	"scroll up"},			/* ^U */
61e0b8e63eSJohn Marino 	{"ked",	       "dG",	"delete to end of screen"},
62e0b8e63eSJohn Marino 	{"kcuf1",	"l",	"cursor right"},
63e0b8e63eSJohn Marino 	{"kcuu1",	"k",	"cursor up"},
64e0b8e63eSJohn Marino 	{NULL},
65e0b8e63eSJohn Marino };
66e0b8e63eSJohn Marino static TKLIST const m1_tklist[] = {	/* Input mappings (lookup). */
67e0b8e63eSJohn Marino 	{NULL},
68e0b8e63eSJohn Marino };
69e0b8e63eSJohn Marino static TKLIST const m2_tklist[] = {	/* Input mappings (set or delete). */
70e0b8e63eSJohn Marino 	{"kcud1",  "\033ja",	"cursor down"},			/* ^[ja */
71e0b8e63eSJohn Marino 	{"kcub1",  "\033ha",	"cursor left"},			/* ^[ha */
72e0b8e63eSJohn Marino 	{"kcuu1",  "\033ka",	"cursor up"},			/* ^[ka */
73e0b8e63eSJohn Marino 	{"kcuf1",  "\033la",	"cursor right"},		/* ^[la */
74e0b8e63eSJohn Marino 	{NULL},
75e0b8e63eSJohn Marino };
76e0b8e63eSJohn Marino 
77e0b8e63eSJohn Marino /*
78e0b8e63eSJohn Marino  * cl_term_init --
79e0b8e63eSJohn Marino  *	Initialize the special keys defined by the termcap/terminfo entry.
80e0b8e63eSJohn Marino  *
81e0b8e63eSJohn Marino  * PUBLIC: int cl_term_init(SCR *);
82e0b8e63eSJohn Marino  */
83e0b8e63eSJohn Marino int
cl_term_init(SCR * sp)84e0b8e63eSJohn Marino cl_term_init(SCR *sp)
85e0b8e63eSJohn Marino {
86e0b8e63eSJohn Marino 	KEYLIST *kp;
87e0b8e63eSJohn Marino 	SEQ *qp;
88e0b8e63eSJohn Marino 	TKLIST const *tkp;
89e0b8e63eSJohn Marino 	char *t;
90e0b8e63eSJohn Marino 	CHAR_T name[60];
91e0b8e63eSJohn Marino 	CHAR_T output[5];
92e0b8e63eSJohn Marino 	CHAR_T ts[20];
93e0b8e63eSJohn Marino 	CHAR_T *wp;
94e0b8e63eSJohn Marino 	size_t wlen;
95e0b8e63eSJohn Marino 
96e0b8e63eSJohn Marino 	/* Command mappings. */
97e0b8e63eSJohn Marino 	for (tkp = c_tklist; tkp->name != NULL; ++tkp) {
98e0b8e63eSJohn Marino 		if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
99e0b8e63eSJohn Marino 			continue;
100e0b8e63eSJohn Marino 		CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
101e0b8e63eSJohn Marino 		MEMCPY(name, wp, wlen);
102e0b8e63eSJohn Marino 		CHAR2INT(sp, t, strlen(t), wp, wlen);
103e0b8e63eSJohn Marino 		MEMCPY(ts, wp, wlen);
104e0b8e63eSJohn Marino 		CHAR2INT(sp, tkp->output, strlen(tkp->output), wp, wlen);
105e0b8e63eSJohn Marino 		MEMCPY(output, wp, wlen);
106e0b8e63eSJohn Marino 		if (seq_set(sp, name, strlen(tkp->name), ts, strlen(t),
107e0b8e63eSJohn Marino 		    output, strlen(tkp->output), SEQ_COMMAND,
108e0b8e63eSJohn Marino 		    SEQ_NOOVERWRITE | SEQ_SCREEN))
109e0b8e63eSJohn Marino 			return (1);
110e0b8e63eSJohn Marino 	}
111e0b8e63eSJohn Marino 
112e0b8e63eSJohn Marino 	/* Input mappings needing to be looked up. */
113e0b8e63eSJohn Marino 	for (tkp = m1_tklist; tkp->name != NULL; ++tkp) {
114e0b8e63eSJohn Marino 		if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
115e0b8e63eSJohn Marino 			continue;
116e0b8e63eSJohn Marino 		for (kp = keylist;; ++kp)
117e0b8e63eSJohn Marino 			if (kp->value == tkp->value)
118e0b8e63eSJohn Marino 				break;
119e0b8e63eSJohn Marino 		if (kp == NULL)
120e0b8e63eSJohn Marino 			continue;
121e0b8e63eSJohn Marino 		CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
122e0b8e63eSJohn Marino 		MEMCPY(name, wp, wlen);
123e0b8e63eSJohn Marino 		CHAR2INT(sp, t, strlen(t), wp, wlen);
124e0b8e63eSJohn Marino 		MEMCPY(ts, wp, wlen);
125e0b8e63eSJohn Marino 		output[0] = (UCHAR_T)kp->ch;
126e0b8e63eSJohn Marino 		if (seq_set(sp, name, strlen(tkp->name), ts, strlen(t),
127e0b8e63eSJohn Marino 		    output, 1, SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN))
128e0b8e63eSJohn Marino 			return (1);
129e0b8e63eSJohn Marino 	}
130e0b8e63eSJohn Marino 
131e0b8e63eSJohn Marino 	/* Input mappings that are already set or are text deletions. */
132e0b8e63eSJohn Marino 	for (tkp = m2_tklist; tkp->name != NULL; ++tkp) {
133e0b8e63eSJohn Marino 		if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1)
134e0b8e63eSJohn Marino 			continue;
135e0b8e63eSJohn Marino 		/*
136e0b8e63eSJohn Marino 		 * !!!
137e0b8e63eSJohn Marino 		 * Some terminals' <cursor_left> keys send single <backspace>
138e0b8e63eSJohn Marino 		 * characters.  This is okay in command mapping, but not okay
139e0b8e63eSJohn Marino 		 * in input mapping.  That combination is the only one we'll
140e0b8e63eSJohn Marino 		 * ever see, hopefully, so kluge it here for now.
141e0b8e63eSJohn Marino 		 */
142e0b8e63eSJohn Marino 		if (!strcmp(t, "\b"))
143e0b8e63eSJohn Marino 			continue;
144e0b8e63eSJohn Marino 		if (tkp->output == NULL) {
145e0b8e63eSJohn Marino 			CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
146e0b8e63eSJohn Marino 			MEMCPY(name, wp, wlen);
147e0b8e63eSJohn Marino 			CHAR2INT(sp, t, strlen(t), wp, wlen);
148e0b8e63eSJohn Marino 			MEMCPY(ts, wp, wlen);
149e0b8e63eSJohn Marino 			if (seq_set(sp, name, strlen(tkp->name),
150e0b8e63eSJohn Marino 			    ts, strlen(t), NULL, 0,
151e0b8e63eSJohn Marino 			    SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN))
152e0b8e63eSJohn Marino 				return (1);
153e0b8e63eSJohn Marino 		} else {
154e0b8e63eSJohn Marino 			CHAR2INT(sp, tkp->name, strlen(tkp->name), wp, wlen);
155e0b8e63eSJohn Marino 			MEMCPY(name, wp, wlen);
156e0b8e63eSJohn Marino 			CHAR2INT(sp, t, strlen(t), wp, wlen);
157e0b8e63eSJohn Marino 			MEMCPY(ts, wp, wlen);
158e0b8e63eSJohn Marino 			CHAR2INT(sp, tkp->output, strlen(tkp->output), wp, wlen);
159e0b8e63eSJohn Marino 			MEMCPY(output, wp, wlen);
160e0b8e63eSJohn Marino 			if (seq_set(sp, name, strlen(tkp->name),
161e0b8e63eSJohn Marino 			    ts, strlen(t), output, strlen(tkp->output),
162e0b8e63eSJohn Marino 			    SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN))
163e0b8e63eSJohn Marino 				return (1);
164e0b8e63eSJohn Marino 		}
165e0b8e63eSJohn Marino 	}
166e0b8e63eSJohn Marino 
167e0b8e63eSJohn Marino 	/*
168e0b8e63eSJohn Marino 	 * Rework any function key mappings that were set before the
169e0b8e63eSJohn Marino 	 * screen was initialized.
170e0b8e63eSJohn Marino 	 */
171e0b8e63eSJohn Marino 	SLIST_FOREACH(qp, sp->gp->seqq, q)
172e0b8e63eSJohn Marino 		if (F_ISSET(qp, SEQ_FUNCMAP))
173e0b8e63eSJohn Marino 			(void)cl_pfmap(sp, qp->stype,
174e0b8e63eSJohn Marino 			    qp->input, qp->ilen, qp->output, qp->olen);
175e0b8e63eSJohn Marino 	return (0);
176e0b8e63eSJohn Marino }
177e0b8e63eSJohn Marino 
178e0b8e63eSJohn Marino /*
179e0b8e63eSJohn Marino  * cl_term_end --
180e0b8e63eSJohn Marino  *	End the special keys defined by the termcap/terminfo entry.
181e0b8e63eSJohn Marino  *
182e0b8e63eSJohn Marino  * PUBLIC: int cl_term_end(GS *);
183e0b8e63eSJohn Marino  */
184e0b8e63eSJohn Marino int
cl_term_end(GS * gp)185e0b8e63eSJohn Marino cl_term_end(GS *gp)
186e0b8e63eSJohn Marino {
187e0b8e63eSJohn Marino 	SEQ *qp, *nqp, *pre_qp = NULL;
188e0b8e63eSJohn Marino 
189e0b8e63eSJohn Marino 	/* Delete screen specific mappings. */
190e0b8e63eSJohn Marino 	SLIST_FOREACH_MUTABLE(qp, gp->seqq, q, nqp)
191e0b8e63eSJohn Marino 		if (F_ISSET(qp, SEQ_SCREEN)) {
192e0b8e63eSJohn Marino 			if (qp == SLIST_FIRST(gp->seqq))
193e0b8e63eSJohn Marino 				SLIST_REMOVE_HEAD(gp->seqq, q);
194e0b8e63eSJohn Marino 			else
195e0b8e63eSJohn Marino 				SLIST_REMOVE_AFTER(pre_qp, q);
196e0b8e63eSJohn Marino 			(void)seq_free(qp);
197e0b8e63eSJohn Marino 		} else
198e0b8e63eSJohn Marino 			pre_qp = qp;
199e0b8e63eSJohn Marino 	return (0);
200e0b8e63eSJohn Marino }
201e0b8e63eSJohn Marino 
202e0b8e63eSJohn Marino /*
203e0b8e63eSJohn Marino  * cl_fmap --
204e0b8e63eSJohn Marino  *	Map a function key.
205e0b8e63eSJohn Marino  *
206e0b8e63eSJohn Marino  * PUBLIC: int cl_fmap(SCR *, seq_t, CHAR_T *, size_t, CHAR_T *, size_t);
207e0b8e63eSJohn Marino  */
208e0b8e63eSJohn Marino int
cl_fmap(SCR * sp,seq_t stype,CHAR_T * from,size_t flen,CHAR_T * to,size_t tlen)209e0b8e63eSJohn Marino cl_fmap(SCR *sp, seq_t stype, CHAR_T *from, size_t flen, CHAR_T *to, size_t tlen)
210e0b8e63eSJohn Marino {
211e0b8e63eSJohn Marino 	/* Ignore until the screen is running, do the real work then. */
212e0b8e63eSJohn Marino 	if (F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_SCR_VI))
213e0b8e63eSJohn Marino 		return (0);
214e0b8e63eSJohn Marino 	if (F_ISSET(sp, SC_EX) && !F_ISSET(sp, SC_SCR_EX))
215e0b8e63eSJohn Marino 		return (0);
216e0b8e63eSJohn Marino 
217e0b8e63eSJohn Marino 	return (cl_pfmap(sp, stype, from, flen, to, tlen));
218e0b8e63eSJohn Marino }
219e0b8e63eSJohn Marino 
220e0b8e63eSJohn Marino /*
221e0b8e63eSJohn Marino  * cl_pfmap --
222e0b8e63eSJohn Marino  *	Map a function key (private version).
223e0b8e63eSJohn Marino  */
224e0b8e63eSJohn Marino static int
cl_pfmap(SCR * sp,seq_t stype,CHAR_T * from,size_t flen,CHAR_T * to,size_t tlen)225e0b8e63eSJohn Marino cl_pfmap(SCR *sp, seq_t stype, CHAR_T *from, size_t flen, CHAR_T *to, size_t tlen)
226e0b8e63eSJohn Marino {
227e0b8e63eSJohn Marino 	size_t nlen;
228e0b8e63eSJohn Marino 	char *p;
229e0b8e63eSJohn Marino 	char name[64];
230e0b8e63eSJohn Marino 	CHAR_T keyname[64];
231e0b8e63eSJohn Marino 	CHAR_T ts[20];
232e0b8e63eSJohn Marino 	CHAR_T *wp;
233e0b8e63eSJohn Marino 	size_t wlen;
234e0b8e63eSJohn Marino 
235e0b8e63eSJohn Marino 	(void)snprintf(name, sizeof(name), "kf%d",
236e0b8e63eSJohn Marino 			(int)STRTOL(from+1,NULL,10));
237e0b8e63eSJohn Marino 	if ((p = tigetstr(name)) == NULL ||
238e0b8e63eSJohn Marino 	    p == (char *)-1 || strlen(p) == 0)
239e0b8e63eSJohn Marino 		p = NULL;
240e0b8e63eSJohn Marino 	if (p == NULL) {
241e0b8e63eSJohn Marino 		msgq_wstr(sp, M_ERR, from, "233|This terminal has no %s key");
242e0b8e63eSJohn Marino 		return (1);
243e0b8e63eSJohn Marino 	}
244e0b8e63eSJohn Marino 
245e0b8e63eSJohn Marino 	nlen = SPRINTF(keyname,
246e0b8e63eSJohn Marino 	    SIZE(keyname), L("function key %d"),
247e0b8e63eSJohn Marino 			(int)STRTOL(from+1,NULL,10));
248e0b8e63eSJohn Marino 	CHAR2INT(sp, p, strlen(p), wp, wlen);
249e0b8e63eSJohn Marino 	MEMCPY(ts, wp, wlen);
250e0b8e63eSJohn Marino 	return (seq_set(sp, keyname, nlen,
251e0b8e63eSJohn Marino 	    ts, strlen(p), to, tlen, stype, SEQ_NOOVERWRITE | SEQ_SCREEN));
252e0b8e63eSJohn Marino }
253e0b8e63eSJohn Marino 
254e0b8e63eSJohn Marino /*
255e0b8e63eSJohn Marino  * cl_optchange --
256e0b8e63eSJohn Marino  *	Curses screen specific "option changed" routine.
257e0b8e63eSJohn Marino  *
258e0b8e63eSJohn Marino  * PUBLIC: int cl_optchange(SCR *, int, char *, u_long *);
259e0b8e63eSJohn Marino  */
260e0b8e63eSJohn Marino int
cl_optchange(SCR * sp,int opt,char * str,u_long * valp)261e0b8e63eSJohn Marino cl_optchange(SCR *sp, int opt, char *str, u_long *valp)
262e0b8e63eSJohn Marino {
263e0b8e63eSJohn Marino 	CL_PRIVATE *clp;
264e0b8e63eSJohn Marino 
265e0b8e63eSJohn Marino 	clp = CLP(sp);
266e0b8e63eSJohn Marino 
267e0b8e63eSJohn Marino 	switch (opt) {
268e0b8e63eSJohn Marino 	case O_TERM:
269e0b8e63eSJohn Marino 		F_CLR(sp, SC_SCR_EX | SC_SCR_VI);
270e0b8e63eSJohn Marino 		/* FALLTHROUGH */
271e0b8e63eSJohn Marino 	case O_COLUMNS:
272e0b8e63eSJohn Marino 	case O_LINES:
273e0b8e63eSJohn Marino 		/*
274e0b8e63eSJohn Marino 		 * Changing the terminal type requires that we reinitialize
275e0b8e63eSJohn Marino 		 * curses, while resizing does not.
276e0b8e63eSJohn Marino 		 */
277e0b8e63eSJohn Marino 		F_SET(sp->gp, G_SRESTART);
278e0b8e63eSJohn Marino 		break;
279e0b8e63eSJohn Marino 	case O_MESG:
280e0b8e63eSJohn Marino 		(void)cl_omesg(sp, clp, *valp);
281e0b8e63eSJohn Marino 		break;
282e0b8e63eSJohn Marino 	case O_WINDOWNAME:
283e0b8e63eSJohn Marino 		if (*valp) {
284e0b8e63eSJohn Marino 			F_SET(clp, CL_RENAME_OK);
285e0b8e63eSJohn Marino 
286e0b8e63eSJohn Marino 			/*
287e0b8e63eSJohn Marino 			 * If the screen is live, i.e. we're not reading the
288e0b8e63eSJohn Marino 			 * .exrc file, update the window.
289e0b8e63eSJohn Marino 			 */
290e0b8e63eSJohn Marino 			if (sp->frp != NULL && sp->frp->name != NULL)
291e0b8e63eSJohn Marino 				(void)cl_rename(sp, sp->frp->name, 1);
292e0b8e63eSJohn Marino 		} else {
293e0b8e63eSJohn Marino 			F_CLR(clp, CL_RENAME_OK);
294e0b8e63eSJohn Marino 
295e0b8e63eSJohn Marino 			(void)cl_rename(sp, NULL, 0);
296e0b8e63eSJohn Marino 		}
297e0b8e63eSJohn Marino 		break;
298e0b8e63eSJohn Marino 	}
299e0b8e63eSJohn Marino 	return (0);
300e0b8e63eSJohn Marino }
301e0b8e63eSJohn Marino 
302e0b8e63eSJohn Marino /*
303e0b8e63eSJohn Marino  * cl_omesg --
304e0b8e63eSJohn Marino  *	Turn the tty write permission on or off.
305e0b8e63eSJohn Marino  *
306e0b8e63eSJohn Marino  * PUBLIC: int cl_omesg(SCR *, CL_PRIVATE *, int);
307e0b8e63eSJohn Marino  */
308e0b8e63eSJohn Marino int
cl_omesg(SCR * sp,CL_PRIVATE * clp,int on)309e0b8e63eSJohn Marino cl_omesg(SCR *sp, CL_PRIVATE *clp, int on)
310e0b8e63eSJohn Marino {
311e0b8e63eSJohn Marino 	struct stat sb;
312e0b8e63eSJohn Marino 	char *tty;
313e0b8e63eSJohn Marino 
314e0b8e63eSJohn Marino 	/* Find the tty, get the current permissions. */
315e0b8e63eSJohn Marino 	if ((tty = ttyname(STDERR_FILENO)) == NULL) {
316e0b8e63eSJohn Marino 		if (sp != NULL)
317e0b8e63eSJohn Marino 			msgq(sp, M_SYSERR, "stderr");
318e0b8e63eSJohn Marino 		return (1);
319e0b8e63eSJohn Marino 	}
320e0b8e63eSJohn Marino 	if (stat(tty, &sb) < 0) {
321e0b8e63eSJohn Marino 		if (sp != NULL)
322e0b8e63eSJohn Marino 			msgq(sp, M_SYSERR, "%s", tty);
323e0b8e63eSJohn Marino 		return (1);
324e0b8e63eSJohn Marino 	}
325e0b8e63eSJohn Marino 
326e0b8e63eSJohn Marino 	/* Save the original status if it's unknown. */
327e0b8e63eSJohn Marino 	if (clp->tgw == TGW_UNKNOWN)
328e0b8e63eSJohn Marino 		clp->tgw = sb.st_mode & S_IWGRP ? TGW_SET : TGW_UNSET;
329e0b8e63eSJohn Marino 
330e0b8e63eSJohn Marino 	/* Toggle the permissions. */
331e0b8e63eSJohn Marino 	if (on) {
332e0b8e63eSJohn Marino 		if (chmod(tty, sb.st_mode | S_IWGRP) < 0) {
333e0b8e63eSJohn Marino 			if (sp != NULL)
334e0b8e63eSJohn Marino 				msgq(sp, M_SYSERR,
335e0b8e63eSJohn Marino 				    "046|messages not turned on: %s", tty);
336e0b8e63eSJohn Marino 			return (1);
337e0b8e63eSJohn Marino 		}
338e0b8e63eSJohn Marino 	} else
339e0b8e63eSJohn Marino 		if (chmod(tty, sb.st_mode & ~S_IWGRP) < 0) {
340e0b8e63eSJohn Marino 			if (sp != NULL)
341e0b8e63eSJohn Marino 				msgq(sp, M_SYSERR,
342e0b8e63eSJohn Marino 				    "045|messages not turned off: %s", tty);
343e0b8e63eSJohn Marino 			return (1);
344e0b8e63eSJohn Marino 		}
345e0b8e63eSJohn Marino 	return (0);
346e0b8e63eSJohn Marino }
347e0b8e63eSJohn Marino 
348e0b8e63eSJohn Marino /*
349e0b8e63eSJohn Marino  * cl_ssize --
350e0b8e63eSJohn Marino  *	Return the terminal size.
351e0b8e63eSJohn Marino  *
352e0b8e63eSJohn Marino  * PUBLIC: int cl_ssize(SCR *, int, size_t *, size_t *, int *);
353e0b8e63eSJohn Marino  */
354e0b8e63eSJohn Marino int
cl_ssize(SCR * sp,int sigwinch,size_t * rowp,size_t * colp,int * changedp)355e0b8e63eSJohn Marino cl_ssize(SCR *sp, int sigwinch, size_t *rowp, size_t *colp, int *changedp)
356e0b8e63eSJohn Marino {
357e0b8e63eSJohn Marino 	struct winsize win;
358e0b8e63eSJohn Marino 	size_t col, row;
359e0b8e63eSJohn Marino 	int rval;
360e0b8e63eSJohn Marino 	char *p;
361e0b8e63eSJohn Marino 
362e0b8e63eSJohn Marino 	/* Assume it's changed. */
363e0b8e63eSJohn Marino 	if (changedp != NULL)
364e0b8e63eSJohn Marino 		*changedp = 1;
365e0b8e63eSJohn Marino 
366e0b8e63eSJohn Marino 	/*
367e0b8e63eSJohn Marino 	 * !!!
368e0b8e63eSJohn Marino 	 * sp may be NULL.
369e0b8e63eSJohn Marino 	 *
370e0b8e63eSJohn Marino 	 * Get the screen rows and columns.  If the values are wrong, it's
371e0b8e63eSJohn Marino 	 * not a big deal -- as soon as the user sets them explicitly the
372e0b8e63eSJohn Marino 	 * environment will be set and the screen package will use the new
373e0b8e63eSJohn Marino 	 * values.
374e0b8e63eSJohn Marino 	 *
375e0b8e63eSJohn Marino 	 * Try TIOCGWINSZ.
376e0b8e63eSJohn Marino 	 */
377e0b8e63eSJohn Marino 	row = col = 0;
378e0b8e63eSJohn Marino 	if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) != -1) {
379e0b8e63eSJohn Marino 		row = win.ws_row;
380e0b8e63eSJohn Marino 		col = win.ws_col;
381e0b8e63eSJohn Marino 	}
382e0b8e63eSJohn Marino 	/* If here because of suspend or a signal, only trust TIOCGWINSZ. */
383e0b8e63eSJohn Marino 	if (sigwinch) {
384e0b8e63eSJohn Marino 		/*
385e0b8e63eSJohn Marino 		 * Somebody didn't get TIOCGWINSZ right, or has suspend
386e0b8e63eSJohn Marino 		 * without window resizing support.  The user just lost,
387e0b8e63eSJohn Marino 		 * but there's nothing we can do.
388e0b8e63eSJohn Marino 		 */
389e0b8e63eSJohn Marino 		if (row == 0 || col == 0) {
390e0b8e63eSJohn Marino 			if (changedp != NULL)
391e0b8e63eSJohn Marino 				*changedp = 0;
392e0b8e63eSJohn Marino 			return (0);
393e0b8e63eSJohn Marino 		}
394e0b8e63eSJohn Marino 
395e0b8e63eSJohn Marino 		/*
396e0b8e63eSJohn Marino 		 * SunOS systems deliver SIGWINCH when windows are uncovered
397e0b8e63eSJohn Marino 		 * as well as when they change size.  In addition, we call
398e0b8e63eSJohn Marino 		 * here when continuing after being suspended since the window
399e0b8e63eSJohn Marino 		 * may have changed size.  Since we don't want to background
400e0b8e63eSJohn Marino 		 * all of the screens just because the window was uncovered,
401e0b8e63eSJohn Marino 		 * ignore the signal if there's no change.
402e0b8e63eSJohn Marino 		 */
403e0b8e63eSJohn Marino 		if (sp != NULL &&
404e0b8e63eSJohn Marino 		    row == O_VAL(sp, O_LINES) && col == O_VAL(sp, O_COLUMNS)) {
405e0b8e63eSJohn Marino 			if (changedp != NULL)
406e0b8e63eSJohn Marino 				*changedp = 0;
407e0b8e63eSJohn Marino 			return (0);
408e0b8e63eSJohn Marino 		}
409e0b8e63eSJohn Marino 
410e0b8e63eSJohn Marino 		if (rowp != NULL)
411e0b8e63eSJohn Marino 			*rowp = row;
412e0b8e63eSJohn Marino 		if (colp != NULL)
413e0b8e63eSJohn Marino 			*colp = col;
414e0b8e63eSJohn Marino 		return (0);
415e0b8e63eSJohn Marino 	}
416e0b8e63eSJohn Marino 
417e0b8e63eSJohn Marino 	/*
418e0b8e63eSJohn Marino 	 * !!!
419e0b8e63eSJohn Marino 	 * If TIOCGWINSZ failed, or had entries of 0, try termcap.  This
420e0b8e63eSJohn Marino 	 * routine is called before any termcap or terminal information
421e0b8e63eSJohn Marino 	 * has been set up.  If there's no TERM environmental variable set,
422e0b8e63eSJohn Marino 	 * let it go, at least ex can run.
423e0b8e63eSJohn Marino 	 */
424e0b8e63eSJohn Marino 	if (row == 0 || col == 0) {
425e0b8e63eSJohn Marino 		if ((p = getenv("TERM")) == NULL)
426e0b8e63eSJohn Marino 			goto noterm;
427e0b8e63eSJohn Marino 		if (row == 0)
428e0b8e63eSJohn Marino 			if ((rval = tigetnum("lines")) < 0)
429e0b8e63eSJohn Marino 				msgq(sp, M_SYSERR, "tigetnum: lines");
430e0b8e63eSJohn Marino 			else
431e0b8e63eSJohn Marino 				row = rval;
432e0b8e63eSJohn Marino 		if (col == 0)
433e0b8e63eSJohn Marino 			if ((rval = tigetnum("cols")) < 0)
434e0b8e63eSJohn Marino 				msgq(sp, M_SYSERR, "tigetnum: cols");
435e0b8e63eSJohn Marino 			else
436e0b8e63eSJohn Marino 				col = rval;
437e0b8e63eSJohn Marino 	}
438e0b8e63eSJohn Marino 
439e0b8e63eSJohn Marino 	/* If nothing else, well, it's probably a VT100. */
440e0b8e63eSJohn Marino noterm:	if (row == 0)
441e0b8e63eSJohn Marino 		row = 24;
442e0b8e63eSJohn Marino 	if (col == 0)
443e0b8e63eSJohn Marino 		col = 80;
444e0b8e63eSJohn Marino 
445e0b8e63eSJohn Marino 	/*
446e0b8e63eSJohn Marino 	 * !!!
447e0b8e63eSJohn Marino 	 * POSIX 1003.2 requires the environment to override everything.
448e0b8e63eSJohn Marino 	 * Often, people can get nvi to stop messing up their screen by
449e0b8e63eSJohn Marino 	 * deleting the LINES and COLUMNS environment variables from their
450e0b8e63eSJohn Marino 	 * dot-files.
451e0b8e63eSJohn Marino 	 */
452e0b8e63eSJohn Marino 	if ((p = getenv("LINES")) != NULL)
453*b1ac2ebbSDaniel Fojt 		row = atoz_or(p, row);
454e0b8e63eSJohn Marino 	if ((p = getenv("COLUMNS")) != NULL)
455*b1ac2ebbSDaniel Fojt 		col = atoz_or(p, col);
456e0b8e63eSJohn Marino 
457e0b8e63eSJohn Marino 	if (rowp != NULL)
458e0b8e63eSJohn Marino 		*rowp = row;
459e0b8e63eSJohn Marino 	if (colp != NULL)
460e0b8e63eSJohn Marino 		*colp = col;
461e0b8e63eSJohn Marino 	return (0);
462e0b8e63eSJohn Marino }
463e0b8e63eSJohn Marino 
464e0b8e63eSJohn Marino /*
465*b1ac2ebbSDaniel Fojt  * atoz_or --
466*b1ac2ebbSDaniel Fojt  *	Parse non-zero positive decimal with a fallback.
467*b1ac2ebbSDaniel Fojt  */
468*b1ac2ebbSDaniel Fojt static size_t
atoz_or(const char * s,size_t y)469*b1ac2ebbSDaniel Fojt atoz_or(const char *s, size_t y)
470*b1ac2ebbSDaniel Fojt {
471*b1ac2ebbSDaniel Fojt 	char *ep;
472*b1ac2ebbSDaniel Fojt 	long x = strtol(s, &ep, 10);
473*b1ac2ebbSDaniel Fojt 
474*b1ac2ebbSDaniel Fojt 	if (*ep == '\0' && (0 < x && x < INT_MAX))
475*b1ac2ebbSDaniel Fojt 		return (size_t)x;
476*b1ac2ebbSDaniel Fojt 	else
477*b1ac2ebbSDaniel Fojt 		return y;
478*b1ac2ebbSDaniel Fojt }
479*b1ac2ebbSDaniel Fojt 
480*b1ac2ebbSDaniel Fojt /*
481e0b8e63eSJohn Marino  * cl_putchar --
482e0b8e63eSJohn Marino  *	Function version of putchar, for tputs.
483e0b8e63eSJohn Marino  *
484e0b8e63eSJohn Marino  * PUBLIC: int cl_putchar(int);
485e0b8e63eSJohn Marino  */
486e0b8e63eSJohn Marino int
cl_putchar(int ch)487e0b8e63eSJohn Marino cl_putchar(int ch)
488e0b8e63eSJohn Marino {
489e0b8e63eSJohn Marino 	return (putchar(ch));
490e0b8e63eSJohn Marino }
491