1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Edward Wang at The University of California, Berkeley.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 static char sccsid[] = "@(#)wwinit.c	8.1 (Berkeley) 6/6/93";
39 static char rcsid[] =
40   "$FreeBSD: head/usr.bin/window/wwinit.c 188828 2009-02-19 20:07:59Z imp $";
41 #endif /* not lint */
42 
43 #include "ww.h"
44 #include "tt.h"
45 #include <signal.h>
46 #include <stdio.h>
47 #include <fcntl.h>
48 #include <termcap.h>
49 #include "char.h"
50 
51 struct ww wwhead;
52 struct ww *wwindex[NWW + 1];		/* last location is for wwnobody */
53 struct ww wwnobody;
54 
55 extern char *wwterm;			/* the terminal name */
56 extern char wwtermcap[1024];		/* place for the termcap */
57 
58 int wwnrow, wwncol;		/* the screen size */
59 char wwavailmodes;		/* actually supported modes */
60 char wwcursormodes;		/* the modes for the fake cursor */
61 char wwwrap;			/* terminal has auto wrap around */
62 int wwdtablesize;		/* result of getdtablesize() call */
63 char **wwsmap;			/* the screen map */
64 union ww_char **wwos;		/* the old (current) screen */
65 union ww_char **wwns;		/* the new (desired) screen */
66 union ww_char **wwcs;		/* the checkpointed screen */
67 char *wwtouched;		/* wwns changed flags */
68 struct ww_update *wwupd;	/* for display update */
69 int wwospeed;			/* output baud rate, copied from wwoldtty */
70 int wwbaud;			/* wwospeed converted into actual number */
71 int wwcursorrow, wwcursorcol;	/* where we want the cursor to be */
72 int wwerrno;			/* error number */
73 
74 int wwnflush, wwnwr, wwnwre, wwnwrz, wwnwrc;
75 int wwnwwr, wwnwwra, wwnwwrc;
76 int wwntokdef, wwntokuse, wwntokbad, wwntoksave, wwntokc;
77 int wwnupdate, wwnupdline, wwnupdmiss;
78 int wwnupdscan, wwnupdclreol, wwnupdclreos, wwnupdclreosmiss, wwnupdclreosline;
79 int wwnread, wwnreade, wwnreadz;
80 int wwnreadc, wwnreadack, wwnreadnack, wwnreadstat, wwnreadec;
81 int wwnwread, wwnwreade, wwnwreadz, wwnwreadd, wwnwreadc, wwnwreadp;
82 int wwnselect, wwnselecte, wwnselectz;
83 
84 struct ww_tty wwoldtty;		/* the old (saved) terminal settings */
85 struct ww_tty wwnewtty;		/* the new (current) terminal settings */
86 struct ww_tty wwwintty;		/* the terminal settings for windows */
87 char *wwterm;
88 char wwtermcap[1024];
89 char wwwintermcap[1024];
90 
91 struct ww *wwcurwin;	/* window to copy input into */
92 char *wwib;		/* input (keyboard) buffer */
93 char *wwibe;		/* wwib + sizeof buffer */
94 char *wwibp;		/* current read position in buffer */
95 char *wwibq;		/* current write position in buffer */
96 
97 char wwintr;
98 char wwsetjmp;
99 jmp_buf wwjmpbuf;
100 
101 int wwdocheckpoint;
102 
wwinit()103 wwinit()
104 {
105 	register i, j;
106 	char *kp;
107 	int s;
108 
109 	wwdtablesize = getdtablesize();
110 	wwhead.ww_forw = &wwhead;
111 	wwhead.ww_back = &wwhead;
112 
113 	s = sigblock(sigmask(SIGIO) | sigmask(SIGCHLD) | sigmask(SIGALRM) |
114 		sigmask(SIGHUP) | sigmask(SIGTERM));
115 	if (signal(SIGIO, wwrint) == BADSIG ||
116 	    signal(SIGCHLD, wwchild) == BADSIG ||
117 	    signal(SIGHUP, wwquit) == BADSIG ||
118 	    signal(SIGTERM, wwquit) == BADSIG ||
119 	    signal(SIGPIPE, SIG_IGN) == BADSIG) {
120 		wwerrno = WWE_SYS;
121 		return -1;
122 	}
123 
124 	if (wwgettty(0, &wwoldtty) < 0)
125 		return -1;
126 	wwwintty = wwoldtty;
127 #ifdef OLD_TTY
128 	wwwintty.ww_sgttyb.sg_flags &= ~XTABS;
129 	wwnewtty.ww_sgttyb = wwoldtty.ww_sgttyb;
130 	wwnewtty.ww_sgttyb.sg_erase = -1;
131 	wwnewtty.ww_sgttyb.sg_kill = -1;
132 	wwnewtty.ww_sgttyb.sg_flags |= CBREAK;
133 	wwnewtty.ww_sgttyb.sg_flags &= ~(ECHO|CRMOD);
134 	wwnewtty.ww_tchars.t_intrc = -1;
135 	wwnewtty.ww_tchars.t_quitc = -1;
136 	wwnewtty.ww_tchars.t_startc = -1;
137 	wwnewtty.ww_tchars.t_stopc = -1;
138 	wwnewtty.ww_tchars.t_eofc = -1;
139 	wwnewtty.ww_tchars.t_brkc = -1;
140 	wwnewtty.ww_ltchars.t_suspc = -1;
141 	wwnewtty.ww_ltchars.t_dsuspc = -1;
142 	wwnewtty.ww_ltchars.t_rprntc = -1;
143 	wwnewtty.ww_ltchars.t_flushc = -1;
144 	wwnewtty.ww_ltchars.t_werasc = -1;
145 	wwnewtty.ww_ltchars.t_lnextc = -1;
146 	wwnewtty.ww_lmode = wwoldtty.ww_lmode | LLITOUT;
147 	wwnewtty.ww_ldisc = wwoldtty.ww_ldisc;
148 #else
149 #ifndef OXTABS
150 #define OXTABS XTABS
151 #endif
152 #ifndef _POSIX_VDISABLE
153 #define _POSIX_VDISABLE -1
154 #endif
155 	wwwintty.ww_termios.c_oflag &= ~OXTABS;
156 	wwnewtty.ww_termios = wwoldtty.ww_termios;
157 	wwnewtty.ww_termios.c_iflag &=
158 		~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IMAXBEL);
159 	wwnewtty.ww_termios.c_oflag = 0;
160 	wwnewtty.ww_termios.c_cflag &= ~(CSIZE | PARENB);
161 	wwnewtty.ww_termios.c_cflag |= CS8;
162 	wwnewtty.ww_termios.c_lflag = 0;
163 	for (i = 0; i < NCCS; i++)
164 		wwnewtty.ww_termios.c_cc[i] = _POSIX_VDISABLE;
165 	wwnewtty.ww_termios.c_cc[VMIN] = 0;
166 	wwnewtty.ww_termios.c_cc[VTIME] = 0;
167 #endif
168 	wwnewtty.ww_fflags = wwoldtty.ww_fflags | FASYNC;
169 	if (wwsettty(0, &wwnewtty) < 0)
170 		goto bad;
171 
172 	if ((wwterm = getenv("TERM")) == 0) {
173 		wwerrno = WWE_BADTERM;
174 		goto bad;
175 	}
176 	if (tgetent(wwtermcap, wwterm) != 1) {
177 		wwerrno = WWE_BADTERM;
178 		goto bad;
179 	}
180 #ifdef OLD_TTY
181 	ospeed = wwoldtty.ww_sgttyb.sg_ospeed;
182 	switch (ospeed) {
183 	default:
184 	case B0:
185 		goto bad;
186 	case B50:
187 		wwbaud = 50;
188 		break;
189 	case B75:
190 		wwbaud = 75;
191 		break;
192 	case B110:
193 		wwbaud = 110;
194 		break;
195 	case B134:
196 		wwbaud = 134;
197 		break;
198 	case B150:
199 		wwbaud = 150;
200 		break;
201 	case B200:
202 		wwbaud = 200;
203 		break;
204 	case B300:
205 		wwbaud = 300;
206 		break;
207 	case B600:
208 		wwbaud = 600;
209 		break;
210 	case B1200:
211 		wwbaud = 1200;
212 		break;
213 	case B1800:
214 		wwbaud = 1800;
215 		break;
216 	case B2400:
217 		wwbaud = 2400;
218 		break;
219 	case B4800:
220 		wwbaud = 4800;
221 		break;
222 	case B9600:
223 		wwbaud = 9600;
224 		break;
225 #ifdef B19200
226 	case B19200:
227 #else
228 	case EXTA:
229 #endif
230 		wwbaud = 19200;
231 		break;
232 #ifdef B38400
233 	case B38400:
234 #else
235 	case EXTB:
236 #endif
237 		wwbaud = 38400;
238 		break;
239 #ifdef B57600
240 	case B57600:
241 		wwbaud = 57600;
242 		break;
243 #endif
244 #ifdef B115200
245 	case B115200:
246 		wwbaud = 115200;
247 		break;
248 #endif
249 	}
250 #else
251 	if ((wwbaud = cfgetospeed(&wwoldtty.ww_termios)) == B0)
252 		goto bad;
253 #endif
254 	wwospeed = ospeed;
255 
256 	if (xxinit() < 0)
257 		goto bad;
258 	wwnrow = tt.tt_nrow;
259 	wwncol = tt.tt_ncol;
260 	wwavailmodes = tt.tt_availmodes;
261 	wwwrap = tt.tt_wrap;
262 
263 	if (wwavailmodes & WWM_REV)
264 		wwcursormodes = WWM_REV | wwavailmodes & WWM_BLK;
265 	else if (wwavailmodes & WWM_UL)
266 		wwcursormodes = WWM_UL;
267 
268 	if ((wwib = malloc((unsigned) 512)) == 0)
269 		goto bad;
270 	wwibe = wwib + 512;
271 	wwibq = wwibp = wwib;
272 
273 	if ((wwsmap = wwalloc(0, 0, wwnrow, wwncol, sizeof (char))) == 0)
274 		goto bad;
275 	for (i = 0; i < wwnrow; i++)
276 		for (j = 0; j < wwncol; j++)
277 			wwsmap[i][j] = WWX_NOBODY;
278 
279 	wwos = (union ww_char **)
280 		wwalloc(0, 0, wwnrow, wwncol, sizeof (union ww_char));
281 	if (wwos == 0)
282 		goto bad;
283 	/* wwos is cleared in wwstart1() */
284 	wwns = (union ww_char **)
285 		wwalloc(0, 0, wwnrow, wwncol, sizeof (union ww_char));
286 	if (wwns == 0)
287 		goto bad;
288 	for (i = 0; i < wwnrow; i++)
289 		for (j = 0; j < wwncol; j++)
290 			wwns[i][j].c_w = ' ';
291 	if (tt.tt_checkpoint) {
292 		/* wwcs is also cleared in wwstart1() */
293 		wwcs = (union ww_char **)
294 			wwalloc(0, 0, wwnrow, wwncol, sizeof (union ww_char));
295 		if (wwcs == 0)
296 			goto bad;
297 	}
298 
299 	wwtouched = malloc((unsigned) wwnrow);
300 	if (wwtouched == 0) {
301 		wwerrno = WWE_NOMEM;
302 		goto bad;
303 	}
304 	for (i = 0; i < wwnrow; i++)
305 		wwtouched[i] = 0;
306 
307 	wwupd = (struct ww_update *) malloc((unsigned) wwnrow * sizeof *wwupd);
308 	if (wwupd == 0) {
309 		wwerrno = WWE_NOMEM;
310 		goto bad;
311 	}
312 
313 	wwindex[WWX_NOBODY] = &wwnobody;
314 	wwnobody.ww_order = NWW;
315 
316 	kp = wwwintermcap;
317 	if (wwavailmodes & WWM_REV)
318 		wwaddcap1(WWT_REV, &kp);
319 	if (wwavailmodes & WWM_BLK)
320 		wwaddcap1(WWT_BLK, &kp);
321 	if (wwavailmodes & WWM_UL)
322 		wwaddcap1(WWT_UL, &kp);
323 	if (wwavailmodes & WWM_GRP)
324 		wwaddcap1(WWT_GRP, &kp);
325 	if (wwavailmodes & WWM_DIM)
326 		wwaddcap1(WWT_DIM, &kp);
327 	if (wwavailmodes & WWM_USR)
328 		wwaddcap1(WWT_USR, &kp);
329 	if (tt.tt_insline && tt.tt_delline || tt.tt_setscroll)
330 		wwaddcap1(WWT_ALDL, &kp);
331 	if (tt.tt_inschar)
332 		wwaddcap1(WWT_IMEI, &kp);
333 	if (tt.tt_insspace)
334 		wwaddcap1(WWT_IC, &kp);
335 	if (tt.tt_delchar)
336 		wwaddcap1(WWT_DC, &kp);
337 	wwaddcap("kb", &kp);
338 	wwaddcap2("ku", &kp);
339 	wwaddcap2("kd", &kp);
340 	wwaddcap2("kl", &kp);
341 	wwaddcap2("kr", &kp);
342 	wwaddcap("kh", &kp);
343 	if ((j = tgetnum("kn")) >= 0) {
344 		char cap[32];
345 
346 		(void) sprintf(kp, "kn#%d:", j);
347 		for (; *kp; kp++)
348 			;
349 		for (i = 1; i <= j; i++) {
350 			(void) sprintf(cap, "k%d", i);
351 			wwaddcap(cap, &kp);
352 			cap[0] = 'l';
353 			wwaddcap(cap, &kp);
354 		}
355 	}
356 	/*
357 	 * It's ok to do this here even if setenv() is destructive
358 	 * since tt_init() has already made its own copy of it and
359 	 * wwterm now points to the copy.
360 	 */
361 	(void) setenv("TERM", WWT_TERM, 1);
362 #ifdef TERMINFO
363 	if (wwterminfoinit() < 0)
364 		goto bad;
365 #endif
366 
367 	if (tt.tt_checkpoint)
368 		if (signal(SIGALRM, wwalarm) == BADSIG) {
369 			wwerrno = WWE_SYS;
370 			goto bad;
371 		}
372 	fcntl(0, F_SETOWN, getpid());
373 	/* catch typeahead before ASYNC was set */
374 	(void) kill(getpid(), SIGIO);
375 	wwstart1();
376 	(void) sigsetmask(s);
377 	return 0;
378 bad:
379 	/*
380 	 * Don't bother to free storage.  We're supposed
381 	 * to exit when wwinit fails anyway.
382 	 */
383 	(void) signal(SIGIO, SIG_DFL);
384 	(void) wwsettty(0, &wwoldtty);
385 	(void) sigsetmask(s);
386 	return -1;
387 }
388 
wwaddcap(cap,kp)389 wwaddcap(cap, kp)
390 	register char *cap;
391 	register char **kp;
392 {
393 	char tbuf[512];
394 	char *tp = tbuf;
395 	register char *str, *p;
396 
397 	if ((str = tgetstr(cap, &tp)) != 0) {
398 		while (*(*kp)++ = *cap++)
399 			;
400 		(*kp)[-1] = '=';
401 		while (*str) {
402 			for (p = unctrl(*str++); *(*kp)++ = *p++;)
403 				;
404 			(*kp)--;
405 		}
406 		*(*kp)++ = ':';
407 		**kp = 0;
408 	}
409 }
410 
wwaddcap1(cap,kp)411 wwaddcap1(cap, kp)
412 	register char *cap;
413 	register char **kp;
414 {
415 	while (*(*kp)++ = *cap++)
416 		;
417 	(*kp)--;
418 }
419 
wwaddcap2(cap,kp)420 wwaddcap2(cap, kp)
421 	register char *cap;
422 	register char **kp;
423 {
424 	char tbuf[512];
425 	char *tp = tbuf;
426 	register char *str, *p;
427 
428 	if ((str = tgetstr(cap, &tp)) != 0) {
429 		/* we don't support vt100's application key mode, remap */
430 		if (str[0] == ctrl('[') && str[1] == 'O')
431 			str[1] = '[';
432 		while (*(*kp)++ = *cap++)
433 			;
434 		(*kp)[-1] = '=';
435 		while (*str) {
436 			for (p = unctrl(*str++); *(*kp)++ = *p++;)
437 				;
438 			(*kp)--;
439 		}
440 		*(*kp)++ = ':';
441 		**kp = 0;
442 	}
443 }
444 
wwstart()445 wwstart()
446 {
447 	register i;
448 
449 	(void) wwsettty(0, &wwnewtty);
450 	signal(SIGIO, wwrint);
451 	for (i = 0; i < wwnrow; i++)
452 		wwtouched[i] = WWU_TOUCHED;
453 	wwstart1();
454 }
455 
wwstart1()456 wwstart1()
457 {
458 	register i, j;
459 
460 	for (i = 0; i < wwnrow; i++)
461 		for (j = 0; j < wwncol; j++) {
462 			wwos[i][j].c_w = ' ';
463 			if (tt.tt_checkpoint)
464 				wwcs[i][j].c_w = ' ';
465 		}
466 	xxstart();
467 	if (tt.tt_checkpoint)
468 		wwdocheckpoint = 1;
469 }
470 
471 /*
472  * Reset data structures and terminal from an unknown state.
473  * Restoring wwos has been taken care of elsewhere.
474  */
wwreset()475 wwreset()
476 {
477 	register i;
478 
479 	xxreset();
480 	for (i = 0; i < wwnrow; i++)
481 		wwtouched[i] = WWU_TOUCHED;
482 }
483