1/*
2 * ed.term.c: Low level terminal interface
3 */
4/*-
5 * Copyright (c) 1980, 1991 The Regents of the University of California.
6 * All rights reserved.
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. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32#include "sh.h"
33#ifndef WINNT_NATIVE
34#include <assert.h>
35#include "ed.h"
36
37int didsetty = 0;
38ttyperm_t ttylist = {
39    {
40#if defined(POSIX) || defined(TERMIO)
41	{ "iflag:", ICRNL, (INLCR|IGNCR) },
42	{ "oflag:", (OPOST|ONLCR), ONLRET },
43	{ "cflag:", 0, 0 },
44	{ "lflag:", (ISIG|ICANON|ECHO|ECHOE|ECHOCTL|IEXTEN),
45		    (NOFLSH|ECHONL|EXTPROC|FLUSHO|IDEFAULT) },
46#else /* GSTTY */
47	{ "nrmal:", (ECHO|CRMOD|ANYP), (CBREAK|RAW|LCASE|VTDELAY|ALLDELAY) },
48	{ "local:", (LCRTBS|LCRTERA|LCRTKIL), (LPRTERA|LFLUSHO) },
49#endif /* POSIX || TERMIO */
50	{ "chars:", 	0, 0 },
51    },
52    {
53#if defined(POSIX) || defined(TERMIO)
54	{ "iflag:", (INLCR|ICRNL), IGNCR },
55	{ "oflag:", (OPOST|ONLCR), ONLRET },
56	{ "cflag:", 0, 0 },
57	{ "lflag:", ISIG,
58		    (NOFLSH|ICANON|ECHO|ECHOK|ECHONL|EXTPROC|IEXTEN|FLUSHO|
59		     IDEFAULT) },
60#else /* GSTTY */
61	{ "nrmal:", (CBREAK|CRMOD|ANYP), (RAW|ECHO|LCASE|VTDELAY|ALLDELAY) },
62	{ "local:", (LCRTBS|LCRTERA|LCRTKIL), (LPRTERA|LFLUSHO) },
63#endif /* POSIX || TERMIO */
64	{ "chars:", (C_SH(C_MIN)|C_SH(C_TIME)|C_SH(C_SWTCH)|C_SH(C_DSWTCH)|
65		     C_SH(C_WERASE)|C_SH(C_REPRINT)|C_SH(C_SUSP)|C_SH(C_DSUSP)|
66		     C_SH(C_EOF)|C_SH(C_EOL)|C_SH(C_DISCARD)|C_SH(C_PGOFF)|
67		     C_SH(C_KILL2)|C_SH(C_PAGE)|C_SH(C_STATUS)|C_SH(C_LNEXT)),
68		     0 }
69    },
70    {
71#if defined(POSIX) || defined(TERMIO)
72	{ "iflag:", 0, IXON | IXOFF },
73	{ "oflag:", 0, 0 },
74	{ "cflag:", 0, 0 },
75	{ "lflag:", 0, ISIG | IEXTEN },
76#else /* GSTTY */
77	{ "nrmal:", RAW, CBREAK },
78	{ "local:", 0, 0 },
79#endif /* POSIX || TERMIO */
80	{ "chars:", 0, 0 },
81    }
82};
83
84static const struct tcshmodes {
85    const char *m_name;
86#ifdef SOLARIS2
87    unsigned long m_value;
88#else /* !SOLARIS2 */
89    int   m_value;
90#endif /* SOLARIS2 */
91    int   m_type;
92} modelist[] = {
93#if defined(POSIX) || defined(TERMIO)
94
95# ifdef	IGNBRK
96    { "ignbrk",	IGNBRK,	M_INPUT },
97# endif /* IGNBRK */
98# ifdef	BRKINT
99    { "brkint",	BRKINT,	M_INPUT },
100# endif /* BRKINT */
101# ifdef	IGNPAR
102    { "ignpar",	IGNPAR,	M_INPUT },
103# endif /* IGNPAR */
104# ifdef	PARMRK
105    { "parmrk",	PARMRK,	M_INPUT },
106# endif /* PARMRK */
107# ifdef	INPCK
108    { "inpck",	INPCK,	M_INPUT },
109# endif /* INPCK */
110# ifdef	ISTRIP
111    { "istrip",	ISTRIP,	M_INPUT },
112# endif /* ISTRIP */
113# ifdef	INLCR
114    { "inlcr",	INLCR,	M_INPUT },
115# endif /* INLCR */
116# ifdef	IGNCR
117    { "igncr",	IGNCR,	M_INPUT },
118# endif /* IGNCR */
119# ifdef	ICRNL
120    { "icrnl",	ICRNL,	M_INPUT },
121# endif /* ICRNL */
122# ifdef	IUCLC
123    { "iuclc",	IUCLC,	M_INPUT },
124# endif /* IUCLC */
125# ifdef	IXON
126    { "ixon",	IXON,	M_INPUT },
127# endif /* IXON */
128# ifdef	IXANY
129    { "ixany",	IXANY,	M_INPUT },
130# endif /* IXANY */
131# ifdef	IXOFF
132    { "ixoff",	IXOFF,	M_INPUT },
133# endif /* IXOFF */
134# ifdef  IMAXBEL
135    { "imaxbel",IMAXBEL,M_INPUT },
136# endif /* IMAXBEL */
137# ifdef  IDELETE
138    { "idelete",IDELETE,M_INPUT },
139# endif /* IDELETE */
140
141# ifdef	OPOST
142    { "opost",	OPOST,	M_OUTPUT },
143# endif /* OPOST */
144# ifdef	OLCUC
145    { "olcuc",	OLCUC,	M_OUTPUT },
146# endif /* OLCUC */
147# ifdef	ONLCR
148    { "onlcr",	ONLCR,	M_OUTPUT },
149# endif /* ONLCR */
150# ifdef	OCRNL
151    { "ocrnl",	OCRNL,	M_OUTPUT },
152# endif /* OCRNL */
153# ifdef	ONOCR
154    { "onocr",	ONOCR,	M_OUTPUT },
155# endif /* ONOCR */
156# ifdef ONOEOT
157    { "onoeot",	ONOEOT,	M_OUTPUT },
158# endif /* ONOEOT */
159# ifdef	ONLRET
160    { "onlret",	ONLRET,	M_OUTPUT },
161# endif /* ONLRET */
162# ifdef	OFILL
163    { "ofill",	OFILL,	M_OUTPUT },
164# endif /* OFILL */
165# ifdef	OFDEL
166    { "ofdel",	OFDEL,	M_OUTPUT },
167# endif /* OFDEL */
168# ifdef	NLDLY
169    { "nldly",	NLDLY,	M_OUTPUT },
170# endif /* NLDLY */
171# ifdef	CRDLY
172    { "crdly",	CRDLY,	M_OUTPUT },
173# endif /* CRDLY */
174# ifdef	TABDLY
175    { "tabdly",	TABDLY,	M_OUTPUT },
176# endif /* TABDLY */
177# ifdef	XTABS
178    { "xtabs",	XTABS,	M_OUTPUT },
179# endif /* XTABS */
180# ifdef	BSDLY
181    { "bsdly",	BSDLY,	M_OUTPUT },
182# endif /* BSDLY */
183# ifdef	VTDLY
184    { "vtdly",	VTDLY,	M_OUTPUT },
185# endif /* VTDLY */
186# ifdef	FFDLY
187    { "ffdly",	FFDLY,	M_OUTPUT },
188# endif /* FFDLY */
189# ifdef	PAGEOUT
190    { "pageout",PAGEOUT,M_OUTPUT },
191# endif /* PAGEOUT */
192# ifdef	WRAP
193    { "wrap",	WRAP,	M_OUTPUT },
194# endif /* WRAP */
195
196# ifdef	CIGNORE
197    { "cignore",CIGNORE,M_CONTROL },
198# endif /* CBAUD */
199# ifdef	CBAUD
200    { "cbaud",	CBAUD,	M_CONTROL },
201# endif /* CBAUD */
202# ifdef	CSTOPB
203    { "cstopb",	CSTOPB,	M_CONTROL },
204# endif /* CSTOPB */
205# ifdef	CREAD
206    { "cread",	CREAD,	M_CONTROL },
207# endif /* CREAD */
208# ifdef	PARENB
209    { "parenb",	PARENB,	M_CONTROL },
210# endif /* PARENB */
211# ifdef	PARODD
212    { "parodd",	PARODD,	M_CONTROL },
213# endif /* PARODD */
214# ifdef	HUPCL
215    { "hupcl",	HUPCL,	M_CONTROL },
216# endif /* HUPCL */
217# ifdef	CLOCAL
218    { "clocal",	CLOCAL,	M_CONTROL },
219# endif /* CLOCAL */
220# ifdef	LOBLK
221    { "loblk",	LOBLK,	M_CONTROL },
222# endif /* LOBLK */
223# ifdef	CIBAUD
224    { "cibaud",	CIBAUD,	M_CONTROL },
225# endif /* CIBAUD */
226# ifdef CRTSCTS
227#  ifdef CCTS_OFLOW
228    { "ccts_oflow",CCTS_OFLOW,M_CONTROL },
229#  else
230    { "crtscts",CRTSCTS,M_CONTROL },
231#  endif /* CCTS_OFLOW */
232# endif /* CRTSCTS */
233# ifdef CRTS_IFLOW
234    { "crts_iflow",CRTS_IFLOW,M_CONTROL },
235# endif /* CRTS_IFLOW */
236# ifdef MDMBUF
237    { "mdmbuf",	MDMBUF,	M_CONTROL },
238# endif /* MDMBUF */
239# ifdef RCV1EN
240    { "rcv1en",	RCV1EN,	M_CONTROL },
241# endif /* RCV1EN */
242# ifdef XMT1EN
243    { "xmt1en",	XMT1EN,	M_CONTROL },
244# endif /* XMT1EN */
245
246# ifdef	ISIG
247    { "isig",	ISIG,	M_LINED },
248# endif /* ISIG */
249# ifdef	ICANON
250    { "icanon",	ICANON,	M_LINED },
251# endif /* ICANON */
252# ifdef	XCASE
253    { "xcase",	XCASE,	M_LINED },
254# endif /* XCASE */
255# ifdef	ECHO
256    { "echo",	ECHO,	M_LINED },
257# endif /* ECHO */
258# ifdef	ECHOE
259    { "echoe",	ECHOE,	M_LINED },
260# endif /* ECHOE */
261# ifdef	ECHOK
262    { "echok",	ECHOK,	M_LINED },
263# endif /* ECHOK */
264# ifdef	ECHONL
265    { "echonl",	ECHONL,	M_LINED },
266# endif /* ECHONL */
267# ifdef	NOFLSH
268    { "noflsh",	NOFLSH,	M_LINED },
269# endif /* NOFLSH */
270# ifdef	TOSTOP
271    { "tostop",	TOSTOP,	M_LINED },
272# endif /* TOSTOP */
273# ifdef	ECHOCTL
274    { "echoctl",ECHOCTL,M_LINED },
275# endif /* ECHOCTL */
276# ifdef	ECHOPRT
277    { "echoprt",ECHOPRT,M_LINED },
278# endif /* ECHOPRT */
279# ifdef	ECHOKE
280    { "echoke",	ECHOKE,	M_LINED },
281# endif /* ECHOKE */
282# ifdef	DEFECHO
283    { "defecho",DEFECHO,M_LINED },
284# endif /* DEFECHO */
285# ifdef	FLUSHO
286    { "flusho",	FLUSHO,	M_LINED },
287# endif /* FLUSHO */
288# ifdef	PENDIN
289    { "pendin",	PENDIN,	M_LINED },
290# endif /* PENDIN */
291# ifdef	IEXTEN
292    { "iexten",	IEXTEN,	M_LINED },
293# endif /* IEXTEN */
294# ifdef	NOKERNINFO
295    { "nokerninfo",NOKERNINFO,M_LINED },
296# endif /* NOKERNINFO */
297# ifdef	ALTWERASE
298    { "altwerase",ALTWERASE,M_LINED },
299# endif /* ALTWERASE */
300# ifdef	EXTPROC
301    { "extproc",EXTPROC,M_LINED },
302# endif /* EXTPROC */
303# ifdef IDEFAULT
304    { "idefault",IDEFAULT,M_LINED },
305# endif /* IDEFAULT */
306
307#else /* GSTTY */
308
309# ifdef	TANDEM
310    { "tandem",	TANDEM,	M_CONTROL },
311# endif /* TANDEM */
312# ifdef	CBREAK
313    { "cbreak",	CBREAK,	M_CONTROL },
314# endif /* CBREAK */
315# ifdef	LCASE
316    { "lcase",	LCASE,	M_CONTROL },
317# endif /* LCASE */
318# ifdef	ECHO
319    { "echo",	ECHO,	M_CONTROL },
320# endif /* ECHO */
321# ifdef	CRMOD
322    { "crmod",	CRMOD,	M_CONTROL },
323# endif /* CRMOD */
324# ifdef	RAW
325    { "raw",	RAW,	M_CONTROL },
326# endif /* RAW */
327# ifdef	ODDP
328    { "oddp",	ODDP,	M_CONTROL },
329# endif /* ODDP */
330# ifdef	EVENP
331    { "evenp",	EVENP,	M_CONTROL },
332# endif /* EVENP */
333# ifdef	ANYP
334    { "anyp",	ANYP,	M_CONTROL },
335# endif /* ANYP */
336# ifdef	NLDELAY
337    { "nldelay",NLDELAY,M_CONTROL },
338# endif /* NLDELAY */
339# ifdef	TBDELAY
340    { "tbdelay",TBDELAY,M_CONTROL },
341# endif /* TBDELAY */
342# ifdef	XTABS
343    { "xtabs",	XTABS,	M_CONTROL },
344# endif /* XTABS */
345# ifdef	CRDELAY
346    { "crdelay",CRDELAY,M_CONTROL },
347# endif /* CRDELAY */
348# ifdef	VTDELAY
349    { "vtdelay",VTDELAY,M_CONTROL },
350# endif /* VTDELAY */
351# ifdef	BSDELAY
352    { "bsdelay",BSDELAY,M_CONTROL },
353# endif /* BSDELAY */
354# ifdef	CRTBS
355    { "crtbs",	CRTBS,	M_CONTROL },
356# endif /* CRTBS */
357# ifdef	PRTERA
358    { "prtera",	PRTERA,	M_CONTROL },
359# endif /* PRTERA */
360# ifdef	CRTERA
361    { "crtera",	CRTERA,	M_CONTROL },
362# endif /* CRTERA */
363# ifdef	TILDE
364    { "tilde",	TILDE,	M_CONTROL },
365# endif /* TILDE */
366# ifdef	MDMBUF
367    { "mdmbuf",	MDMBUF,	M_CONTROL },
368# endif /* MDMBUF */
369# ifdef	LITOUT
370    { "litout",	LITOUT,	M_CONTROL },
371# endif /* LITOUT */
372# ifdef	TOSTOP
373    { "tostop",	TOSTOP,	M_CONTROL },
374# endif /* TOSTOP */
375# ifdef	FLUSHO
376    { "flusho",	FLUSHO,	M_CONTROL },
377# endif /* FLUSHO */
378# ifdef	NOHANG
379    { "nohang",	NOHANG,	M_CONTROL },
380# endif /* NOHANG */
381# ifdef	L001000
382    { "l001000",L001000,M_CONTROL },
383# endif /* L001000 */
384# ifdef	CRTKIL
385    { "crtkil",	CRTKIL,	M_CONTROL },
386# endif /* CRTKIL */
387# ifdef	PASS8
388    { "pass8",	PASS8,	M_CONTROL },
389# endif /* PASS8 */
390# ifdef	CTLECH
391    { "ctlech",	CTLECH,	M_CONTROL },
392# endif /* CTLECH */
393# ifdef	PENDIN
394    { "pendin",	PENDIN,	M_CONTROL },
395# endif /* PENDIN */
396# ifdef	DECCTQ
397    { "decctq",	DECCTQ,	M_CONTROL },
398# endif /* DECCTQ */
399# ifdef	NOFLSH
400    { "noflsh",	NOFLSH,	M_CONTROL },
401# endif /* NOFLSH */
402
403# ifdef	LCRTBS
404    { "lcrtbs",	LCRTBS,	M_LOCAL },
405# endif /* LCRTBS */
406# ifdef	LPRTERA
407    { "lprtera",LPRTERA,M_LOCAL },
408# endif /* LPRTERA */
409# ifdef	LCRTERA
410    { "lcrtera",LCRTERA,M_LOCAL },
411# endif /* LCRTERA */
412# ifdef	LTILDE
413    { "ltilde",	LTILDE,	M_LOCAL },
414# endif /* LTILDE */
415# ifdef	LMDMBUF
416    { "lmdmbuf",LMDMBUF,M_LOCAL },
417# endif /* LMDMBUF */
418# ifdef	LLITOUT
419    { "llitout",LLITOUT,M_LOCAL },
420# endif /* LLITOUT */
421# ifdef	LTOSTOP
422    { "ltostop",LTOSTOP,M_LOCAL },
423# endif /* LTOSTOP */
424# ifdef	LFLUSHO
425    { "lflusho",LFLUSHO,M_LOCAL },
426# endif /* LFLUSHO */
427# ifdef	LNOHANG
428    { "lnohang",LNOHANG,M_LOCAL },
429# endif /* LNOHANG */
430# ifdef	LCRTKIL
431    { "lcrtkil",LCRTKIL,M_LOCAL },
432# endif /* LCRTKIL */
433# ifdef	LPASS8
434    { "lpass8",	LPASS8,	M_LOCAL },
435# endif /* LPASS8 */
436# ifdef	LCTLECH
437    { "lctlech",LCTLECH,M_LOCAL },
438# endif /* LCTLECH */
439# ifdef	LPENDIN
440    { "lpendin",LPENDIN,M_LOCAL },
441# endif /* LPENDIN */
442# ifdef	LDECCTQ
443    { "ldecctq",LDECCTQ,M_LOCAL },
444# endif /* LDECCTQ */
445# ifdef	LNOFLSH
446    { "lnoflsh",LNOFLSH,M_LOCAL },
447# endif /* LNOFLSH */
448
449#endif /* POSIX || TERMIO */
450# if defined(VINTR) || defined(TIOCGETC)
451    { "intr",		C_SH(C_INTR), 	M_CHAR },
452# endif /* VINTR */
453# if defined(VQUIT) || defined(TIOCGETC)
454    { "quit",		C_SH(C_QUIT), 	M_CHAR },
455# endif /* VQUIT */
456# if defined(VERASE) || defined(TIOCGETP)
457    { "erase",		C_SH(C_ERASE), 	M_CHAR },
458# endif /* VERASE */
459# if defined(VKILL) || defined(TIOCGETP)
460    { "kill",		C_SH(C_KILL), 	M_CHAR },
461# endif /* VKILL */
462# if defined(VEOF) || defined(TIOCGETC)
463    { "eof",		C_SH(C_EOF), 	M_CHAR },
464# endif /* VEOF */
465# if defined(VEOL)
466    { "eol",		C_SH(C_EOL), 	M_CHAR },
467# endif /* VEOL */
468# if defined(VEOL2)
469    { "eol2",		C_SH(C_EOL2), 	M_CHAR },
470# endif  /* VEOL2 */
471# if defined(VSWTCH)
472    { "swtch",		C_SH(C_SWTCH), 	M_CHAR },
473# endif /* VSWTCH */
474# if defined(VDSWTCH)
475    { "dswtch",		C_SH(C_DSWTCH),	M_CHAR },
476# endif /* VDSWTCH */
477# if defined(VERASE2)
478    { "erase2",		C_SH(C_ERASE2),	M_CHAR },
479# endif /* VERASE2 */
480# if defined(VSTART) || defined(TIOCGETC)
481    { "start",		C_SH(C_START), 	M_CHAR },
482# endif /* VSTART */
483# if defined(VSTOP) || defined(TIOCGETC)
484    { "stop",		C_SH(C_STOP), 	M_CHAR },
485# endif /* VSTOP */
486# if defined(VWERASE) || defined(TIOCGLTC)
487    { "werase",		C_SH(C_WERASE),	M_CHAR },
488# endif /* VWERASE */
489# if defined(VSUSP) || defined(TIOCGLTC)
490    { "susp",		C_SH(C_SUSP), 	M_CHAR },
491# endif /* VSUSP */
492# if defined(VDSUSP) || defined(TIOCGLTC)
493    { "dsusp",		C_SH(C_DSUSP), 	M_CHAR },
494# endif /* VDSUSP */
495# if defined(VREPRINT) || defined(TIOCGLTC)
496    { "reprint",	C_SH(C_REPRINT),M_CHAR },
497# endif /* WREPRINT */
498# if defined(VDISCARD) || defined(TIOCGLTC)
499    { "discard",	C_SH(C_DISCARD),M_CHAR },
500# endif /* VDISCARD */
501# if defined(VLNEXT) || defined(TIOCGLTC)
502    { "lnext",		C_SH(C_LNEXT), 	M_CHAR },
503# endif /* VLNEXT */
504# if defined(VSTATUS) || defined(TIOCGPAGE)
505    { "status",		C_SH(C_STATUS),	M_CHAR },
506# endif /* VSTATUS */
507# if defined(VPAGE) || defined(TIOCGPAGE)
508    { "page",		C_SH(C_PAGE), 	M_CHAR },
509# endif /* VPAGE */
510# if defined(VPGOFF) || defined(TIOCGPAGE)
511    { "pgoff",		C_SH(C_PGOFF), 	M_CHAR },
512# endif /* VPGOFF */
513# if defined(VKILL2)
514    { "kill2",		C_SH(C_KILL2), 	M_CHAR },
515# endif /* VKILL2 */
516# if defined(VBRK) || defined(TIOCGETC)
517    { "brk",		C_SH(C_BRK), 	M_CHAR },
518# endif /* VBRK */
519# if defined(VMIN)
520    { "min",		C_SH(C_MIN), 	M_CHAR },
521# endif /* VMIN */
522# if defined(VTIME)
523    { "time",		C_SH(C_TIME), 	M_CHAR },
524# endif /* VTIME */
525    { NULL, 0, -1 },
526};
527
528/*
529 * If EAGAIN and/or EWOULDBLOCK are defined, we can't just return -1 in all
530 * situations where ioctl() does.
531 *
532 * On AIX 4.1.5 (and presumably some other versions and OSes), as you
533 * perform the manual test suite in the README, if you 'bg' vi immediately
534 * after suspending it, all is well, but if you wait a few seconds,
535 * usually ioctl() will return -1, which previously caused tty_setty() to
536 * return -1, causing Rawmode() to return -1, causing Inputl() to return
537 * 0, causing bgetc() to return -1, causing readc() to set doneinp to 1,
538 * causing process() to break out of the main loop, causing tcsh to exit
539 * prematurely.
540 *
541 * If ioctl()'s errno is EAGAIN/EWOULDBLOCK ("Resource temporarily
542 * unavailable"), apparently the tty is being messed with by the OS and we
543 * need to try again.  In my testing, ioctl() was never called more than
544 * twice in a row.
545 *
546 * -- Dan Harkless <dan@wave.eng.uci.edu>
547 *
548 * So, I retry all ioctl's in case others happen to fail too (christos)
549 */
550
551#if defined(EAGAIN) && defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
552# define OKERROR(e) (((e) == EAGAIN) || ((e) == EWOULDBLOCK) || ((e) == EINTR))
553#elif defined(EAGAIN)
554# define OKERROR(e) (((e) == EAGAIN) || ((e) == EINTR))
555#elif defined(EWOULDBLOCK)
556# define OKERROR(e) (((e) == EWOULDBLOCK) || ((e) == EINTR))
557#else
558# define OKERROR(e) ((e) == EINTR)
559#endif
560
561#ifdef __NetBSD__
562#define KLUDGE (errno == ENOTTY && count < 10)
563#else
564#define KLUDGE 0
565#endif
566
567/* Retry a system call */
568#define RETRY(x)				\
569do {						\
570    int count;					\
571						\
572    for (count = 0;; count++)			\
573	if ((x) == -1) {			\
574	    if (OKERROR(errno) || KLUDGE)	\
575		continue;			\
576	    else				\
577		return -1;			\
578	}					\
579	else					\
580	    break;				\
581} while (0)
582
583/*ARGSUSED*/
584void
585dosetty(Char **v, struct command *t)
586{
587    const struct tcshmodes *m;
588    char x, *d, *cmdname;
589    int aflag = 0;
590    Char *s;
591    int z = EX_IO;
592
593    USE(t);
594    cmdname = strsave(short2str(*v++));
595    cleanup_push(cmdname, xfree);
596    setname(cmdname);
597
598    while (v && *v && v[0][0] == '-' && v[0][2] == '\0')
599	switch (v[0][1]) {
600	case 'a':
601	    aflag++;
602	    v++;
603	    break;
604	case 'd':
605	    v++;
606	    z = ED_IO;
607	    break;
608	case 'x':
609	    v++;
610	    z = EX_IO;
611	    break;
612	case 'q':
613	    v++;
614	    z = QU_IO;
615	    break;
616	default:
617	    stderror(ERR_NAME | ERR_SYSTEM, short2str(v[0]),
618		     CGETS(8, 1, "Unknown switch"));
619	    break;
620	}
621
622    didsetty = 1;
623    if (!v || !*v) {
624	int i = -1;
625	int len = 0, st = 0, cu;
626	for (m = modelist; m->m_name; m++) {
627	    if (m->m_type != i) {
628		xprintf("%s%s", i != -1 ? "\n" : "",
629			ttylist[z][m->m_type].t_name);
630		i = m->m_type;
631		st = len = strlen(ttylist[z][m->m_type].t_name);
632	    }
633	    assert(i != -1);
634
635	    x = (ttylist[z][i].t_setmask & m->m_value) ? '+' : '\0';
636	    x = (ttylist[z][i].t_clrmask & m->m_value) ? '-' : x;
637
638	    if (x != '\0' || aflag) {
639		cu = strlen(m->m_name) + (x != '\0') + 1;
640		if (len + cu >= TermH) {
641		    xprintf("\n%*s", st, "");
642		    len = st + cu;
643		}
644		else
645		    len += cu;
646		if (x != '\0')
647		    xprintf("%c%s ", x, m->m_name);
648		else
649		    xprintf("%s ", m->m_name);
650	    }
651	}
652	xputchar('\n');
653	cleanup_until(cmdname);
654	return;
655    }
656    while (v && (s = *v++)) {
657	switch (*s) {
658	case '+':
659	case '-':
660	    x = *s++;
661	    break;
662	default:
663	    x = '\0';
664	    break;
665	}
666	d = short2str(s);
667	for (m = modelist; m->m_name; m++)
668	    if (strcmp(m->m_name, d) == 0)
669		break;
670	if (!m->m_name)
671	    stderror(ERR_NAME | ERR_SYSTEM, d, CGETS(8, 2, "Invalid argument"));
672
673	switch (x) {
674	case '+':
675	    ttylist[z][m->m_type].t_setmask |= m->m_value;
676	    ttylist[z][m->m_type].t_clrmask &= ~m->m_value;
677	    break;
678	case '-':
679	    ttylist[z][m->m_type].t_setmask &= ~m->m_value;
680	    ttylist[z][m->m_type].t_clrmask |= m->m_value;
681	    break;
682	default:
683	    ttylist[z][m->m_type].t_setmask &= ~m->m_value;
684	    ttylist[z][m->m_type].t_clrmask &= ~m->m_value;
685	    break;
686	}
687    }
688    cleanup_until(cmdname);
689} /* end dosetty */
690
691int
692tty_getty(int fd, ttydata_t *td)
693{
694#ifdef POSIX
695    RETRY(tcgetattr(fd, &td->d_t));
696#else /* TERMIO || GSTTY */
697# ifdef TERMIO
698    RETRY(ioctl(fd, TCGETA,    (ioctl_t) &td->d_t));
699# else /* GSTTY */
700#  ifdef TIOCGETP
701    RETRY(ioctl(fd, TIOCGETP,  (ioctl_t) &td->d_t));
702#  endif /* TIOCGETP */
703#  ifdef TIOCGETC
704    RETRY(ioctl(fd, TIOCGETC,  (ioctl_t) &td->d_tc));
705#  endif /* TIOCGETC */
706#  ifdef TIOCGPAGE
707    RETRY(ioctl(fd, TIOCGPAGE, (ioctl_t) &td->d_pc));
708#  endif /* TIOCGPAGE */
709#  ifdef TIOCLGET
710    RETRY(ioctl(fd, TIOCLGET,  (ioctl_t) &td->d_lb));
711#  endif /* TIOCLGET */
712# endif /* TERMIO */
713#endif /* POSIX */
714
715#ifdef TIOCGLTC
716    RETRY(ioctl(fd, TIOCGLTC,  (ioctl_t) &td->d_ltc));
717#endif /* TIOCGLTC */
718
719    return 0;
720}
721
722int
723tty_setty(int fd, ttydata_t *td)
724{
725#ifdef POSIX
726    RETRY(xtcsetattr(fd, TCSADRAIN, &td->d_t));
727#else
728# ifdef TERMIO
729    RETRY(ioctl(fd, TCSETAW,    (ioctl_t) &td->d_t));
730# else
731#  ifdef TIOCSETN
732    RETRY(ioctl(fd, TIOCSETN,  (ioctl_t) &td->d_t));
733#  endif /* TIOCSETN */
734#  ifdef TIOCGETC
735    RETRY(ioctl(fd, TIOCSETC,  (ioctl_t) &td->d_tc));
736#  endif /* TIOCGETC */
737#  ifdef TIOCGPAGE
738    RETRY(ioctl(fd, TIOCSPAGE, (ioctl_t) &td->d_pc));
739#  endif /* TIOCGPAGE */
740#  ifdef TIOCLGET
741    RETRY(ioctl(fd, TIOCLSET,  (ioctl_t) &td->d_lb));
742#  endif /* TIOCLGET */
743# endif /* TERMIO */
744#endif /* POSIX */
745
746#ifdef TIOCGLTC
747    RETRY(ioctl(fd, TIOCSLTC,  (ioctl_t) &td->d_ltc));
748#endif /* TIOCGLTC */
749
750    return 0;
751}
752
753void
754tty_getchar(ttydata_t *td, unsigned char *s)
755{
756#ifdef TIOCGLTC
757    {
758	struct ltchars *n = &td->d_ltc;
759
760	s[C_SUSP]	= n->t_suspc;
761	s[C_DSUSP]	= n->t_dsuspc;
762	s[C_REPRINT]	= n->t_rprntc;
763	s[C_DISCARD]	= n->t_flushc;
764	s[C_WERASE]	= n->t_werasc;
765	s[C_LNEXT]	= n->t_lnextc;
766    }
767#endif /* TIOCGLTC */
768
769#if defined(POSIX) || defined(TERMIO)
770    {
771# ifdef POSIX
772	struct termios *n = &td->d_t;
773# else
774	struct termio *n = &td->d_t;
775# endif /* POSIX */
776
777# ifdef VINTR
778	s[C_INTR]	= n->c_cc[VINTR];
779# endif /* VINTR */
780# ifdef VQUIT
781	s[C_QUIT]	= n->c_cc[VQUIT];
782# endif /* VQUIT */
783# ifdef VERASE
784	s[C_ERASE]	= n->c_cc[VERASE];
785# endif /* VERASE */
786# ifdef VKILL
787	s[C_KILL]	= n->c_cc[VKILL];
788# endif /* VKILL */
789# ifdef VEOF
790	s[C_EOF]	= n->c_cc[VEOF];
791# endif /* VEOF */
792# ifdef VEOL
793	s[C_EOL]	= n->c_cc[VEOL];
794# endif /* VEOL */
795# ifdef VEOL2
796	s[C_EOL2]	= n->c_cc[VEOL2];
797# endif  /* VEOL2 */
798# ifdef VSWTCH
799	s[C_SWTCH]	= n->c_cc[VSWTCH];
800# endif /* VSWTCH */
801# ifdef VDSWTCH
802	s[C_DSWTCH]	= n->c_cc[VDSWTCH];
803# endif /* VDSWTCH */
804# ifdef VERASE2
805	s[C_ERASE2]	= n->c_cc[VERASE2];
806# endif /* VERASE2 */
807# ifdef VSTART
808	s[C_START]	= n->c_cc[VSTART];
809# endif /* VSTART */
810# ifdef VSTOP
811	s[C_STOP]	= n->c_cc[VSTOP];
812# endif /* VSTOP */
813# ifdef VWERASE
814	s[C_WERASE]	= n->c_cc[VWERASE];
815# endif /* VWERASE */
816# ifdef VSUSP
817	s[C_SUSP]	= n->c_cc[VSUSP];
818# endif /* VSUSP */
819# ifdef VDSUSP
820	s[C_DSUSP]	= n->c_cc[VDSUSP];
821# endif /* VDSUSP */
822# ifdef VREPRINT
823	s[C_REPRINT]	= n->c_cc[VREPRINT];
824# endif /* WREPRINT */
825# ifdef VDISCARD
826	s[C_DISCARD]	= n->c_cc[VDISCARD];
827# endif /* VDISCARD */
828# ifdef VLNEXT
829	s[C_LNEXT]	= n->c_cc[VLNEXT];
830# endif /* VLNEXT */
831# ifdef VSTATUS
832	s[C_STATUS]	= n->c_cc[VSTATUS];
833# endif /* VSTATUS */
834# ifdef VPAGE
835	s[C_PAGE]	= n->c_cc[VPAGE];
836# endif /* VPAGE */
837# ifdef VPGOFF
838	s[C_PGOFF]	= n->c_cc[VPGOFF];
839# endif /* VPGOFF */
840# ifdef VKILL2
841	s[C_KILL2]	= n->c_cc[VKILL2];
842# endif /* KILL2 */
843# ifdef VMIN
844	s[C_MIN]	= n->c_cc[VMIN];
845# endif /* VMIN */
846# ifdef VTIME
847	s[C_TIME]	= n->c_cc[VTIME];
848# endif /* VTIME */
849    }
850
851#else /* SGTTY */
852
853# ifdef TIOCGPAGE
854    {
855	struct ttypagestat *n = &td->d_pc;
856
857	s[C_STATUS]	= n->tps_statc;
858	s[C_PAGE]	= n->tps_pagec;
859	s[C_PGOFF]	= n->tps_pgoffc;
860    }
861# endif /* TIOCGPAGE */
862
863# ifdef TIOCGETC
864    {
865	struct tchars *n = &td->d_tc;
866
867	s[C_INTR]	= n->t_intrc;
868	s[C_QUIT]	= n->t_quitc;
869	s[C_START]	= n->t_startc;
870	s[C_STOP]	= n->t_stopc;
871	s[C_EOF]	= n->t_eofc;
872	s[C_BRK]	= n->t_brkc;
873    }
874# endif /* TIOCGETC */
875
876# ifdef TIOCGETP
877    {
878	struct sgttyb *n = &td->d_t;
879
880	s[C_ERASE]	= n->sg_erase;
881	s[C_KILL]	= n->sg_kill;
882    }
883# endif /* TIOCGETP */
884#endif /* !POSIX || TERMIO */
885
886} /* tty_getchar */
887
888
889void
890tty_setchar(ttydata_t *td, unsigned char *s)
891{
892#ifdef TIOCGLTC
893    {
894	struct ltchars *n = &td->d_ltc;
895
896	n->t_suspc 		= s[C_SUSP];
897	n->t_dsuspc		= s[C_DSUSP];
898	n->t_rprntc		= s[C_REPRINT];
899	n->t_flushc		= s[C_DISCARD];
900	n->t_werasc		= s[C_WERASE];
901	n->t_lnextc		= s[C_LNEXT];
902    }
903#endif /* TIOCGLTC */
904
905#if defined(POSIX) || defined(TERMIO)
906    {
907# ifdef POSIX
908	struct termios *n = &td->d_t;
909# else
910	struct termio *n = &td->d_t;
911# endif /* POSIX */
912
913# ifdef VINTR
914	n->c_cc[VINTR]		= s[C_INTR];
915# endif /* VINTR */
916# ifdef VQUIT
917	n->c_cc[VQUIT]		= s[C_QUIT];
918# endif /* VQUIT */
919# ifdef VERASE
920	n->c_cc[VERASE]		= s[C_ERASE];
921# endif /* VERASE */
922# ifdef VKILL
923	n->c_cc[VKILL]		= s[C_KILL];
924# endif /* VKILL */
925# ifdef VEOF
926	n->c_cc[VEOF]		= s[C_EOF];
927# endif /* VEOF */
928# ifdef VEOL
929	n->c_cc[VEOL]		= s[C_EOL];
930# endif /* VEOL */
931# ifdef VEOL2
932	n->c_cc[VEOL2]		= s[C_EOL2];
933# endif  /* VEOL2 */
934# ifdef VSWTCH
935	n->c_cc[VSWTCH]		= s[C_SWTCH];
936# endif /* VSWTCH */
937# ifdef VDSWTCH
938	n->c_cc[VDSWTCH]	= s[C_DSWTCH];
939# endif /* VDSWTCH */
940# ifdef VERASE2
941	n->c_cc[VERASE2]	= s[C_ERASE2];
942# endif /* VERASE2 */
943# ifdef VSTART
944	n->c_cc[VSTART]		= s[C_START];
945# endif /* VSTART */
946# ifdef VSTOP
947	n->c_cc[VSTOP]		= s[C_STOP];
948# endif /* VSTOP */
949# ifdef VWERASE
950	n->c_cc[VWERASE]	= s[C_WERASE];
951# endif /* VWERASE */
952# ifdef VSUSP
953	n->c_cc[VSUSP]		= s[C_SUSP];
954# endif /* VSUSP */
955# ifdef VDSUSP
956	n->c_cc[VDSUSP]		= s[C_DSUSP];
957# endif /* VDSUSP */
958# ifdef VREPRINT
959	n->c_cc[VREPRINT]	= s[C_REPRINT];
960# endif /* WREPRINT */
961# ifdef VDISCARD
962	n->c_cc[VDISCARD]	= s[C_DISCARD];
963# endif /* VDISCARD */
964# ifdef VLNEXT
965	n->c_cc[VLNEXT]		= s[C_LNEXT];
966# endif /* VLNEXT */
967# ifdef VSTATUS
968	n->c_cc[VSTATUS]	= s[C_STATUS];
969# endif /* VSTATUS */
970# ifdef VPAGE
971	n->c_cc[VPAGE]		= s[C_PAGE];
972# endif /* VPAGE */
973# ifdef VPGOFF
974	n->c_cc[VPGOFF]		= s[C_PGOFF];
975# endif /* VPGOFF */
976# ifdef VKILL2
977	n->c_cc[VKILL2]		= s[C_KILL2];
978# endif /* VKILL2 */
979# ifdef VMIN
980	n->c_cc[VMIN]		= s[C_MIN];
981# endif /* VMIN */
982# ifdef VTIME
983	n->c_cc[VTIME]		= s[C_TIME];
984# endif /* VTIME */
985    }
986
987#else /* GSTTY */
988
989# ifdef TIOCGPAGE
990    {
991	struct ttypagestat *n = &td->d_pc;
992
993	n->tps_length		= 0;
994	n->tps_lpos		= 0;
995	n->tps_statc		= s[C_STATUS];
996	n->tps_pagec		= s[C_PAGE];
997	n->tps_pgoffc		= s[C_PGOFF];
998	n->tps_flag		= 0;
999    }
1000# endif /* TIOCGPAGE */
1001
1002# ifdef TIOCGETC
1003    {
1004	struct tchars *n = &td->d_tc;
1005	n->t_intrc		= s[C_INTR];
1006	n->t_quitc		= s[C_QUIT];
1007	n->t_startc		= s[C_START];
1008	n->t_stopc		= s[C_STOP];
1009	n->t_eofc		= s[C_EOF];
1010	n->t_brkc		= s[C_BRK];
1011    }
1012# endif /* TIOCGETC */
1013
1014# ifdef TIOCGETP
1015    {
1016	struct sgttyb *n = &td->d_t;
1017
1018	n->sg_erase		= s[C_ERASE];
1019	n->sg_kill		= s[C_KILL];
1020    }
1021# endif /* TIOCGETP */
1022#endif /* !POSIX || TERMIO */
1023
1024} /* tty_setchar */
1025
1026speed_t
1027tty_getspeed(ttydata_t *td)
1028{
1029    speed_t spd;
1030
1031#ifdef POSIX
1032    if ((spd = cfgetispeed(&td->d_t)) == 0)
1033	spd = cfgetospeed(&td->d_t);
1034#else /* ! POSIX */
1035# ifdef TERMIO
1036#  ifdef CBAUD
1037    spd = td->d_t.c_cflag & CBAUD;
1038#  else
1039    spd = 0;
1040#  endif
1041# else /* SGTTY */
1042    spd = td->d_t.sg_ispeed;
1043# endif /* TERMIO */
1044#endif /* POSIX */
1045
1046    return spd;
1047} /* end tty_getspeed */
1048
1049int
1050tty_gettabs(ttydata_t *td)
1051{
1052#if defined(POSIX) || defined(TERMIO)
1053    return ((td->d_t.c_oflag & TAB3) == TAB3) ? 0 : 1;
1054#else /* SGTTY */
1055    return (td->d_t.sg_flags & XTABS) == XTABS ? 0 : 1;
1056#endif /* POSIX || TERMIO */
1057} /* end tty_gettabs */
1058
1059int
1060tty_geteightbit(ttydata_t *td)
1061{
1062#if defined(POSIX) || defined(TERMIO)
1063    return (td->d_t.c_cflag & CSIZE) == CS8;
1064#else /* SGTTY */
1065    return td->d_lb & (LPASS8 | LLITOUT);
1066#endif /* POSIX || TERMIO */
1067} /* end tty_geteightbit */
1068
1069int
1070tty_cooked_mode(ttydata_t *td)
1071{
1072#if defined(POSIX) || defined(TERMIO)
1073    return (td->d_t.c_lflag & ICANON);
1074#else /* SGTTY */
1075    return !(td->d_t.sg_flags & (RAW | CBREAK));
1076#endif /* POSIX || TERMIO */
1077} /* end tty_cooked_mode */
1078
1079#ifdef _IBMR2
1080void
1081tty_setdisc(int fd, int dis)
1082{
1083    static int edit_discipline = 0;
1084    static union txname tx_disc;
1085    extern char strPOSIX[];
1086
1087    switch (dis) {
1088    case EX_IO:
1089	if (edit_discipline) {
1090	    if (ioctl(fd, TXSETLD, (ioctl_t) & tx_disc) == -1)
1091		return;
1092	    edit_discipline = 0;
1093	}
1094	return;
1095
1096    case ED_IO:
1097	tx_disc.tx_which = 0;
1098	if (ioctl(fd, TXGETLD, (ioctl_t) & tx_disc) == -1)
1099	    return;
1100	if (strcmp(tx_disc.tx_name, strPOSIX) != 0) {
1101	    edit_discipline = 1;
1102	    if (ioctl(fd, TXSETLD, (ioctl_t) strPOSIX) == -1)
1103	    return;
1104	}
1105	return;
1106
1107    default:
1108	return;
1109    }
1110} /* end tty_setdisc */
1111#endif /* _IBMR2 */
1112
1113#ifdef DEBUG_TTY
1114static void
1115tty_printchar(unsigned char *s)
1116{
1117    struct tcshmodes *m;
1118    int i;
1119
1120    for (i = 0; i < C_NCC; i++) {
1121	for (m = modelist; m->m_name; m++)
1122	    if (m->m_type == M_CHAR && C_SH(i) == m->m_value)
1123		break;
1124	if (m->m_name)
1125	    xprintf("%s ^%c ", m->m_name, s[i] + 'A' - 1);
1126	if (i % 5 == 0)
1127	    xputchar('\n');
1128    }
1129    xputchar('\n');
1130}
1131#endif /* DEBUG_TTY */
1132#else /* WINNT_NATIVE */
1133int
1134tty_cooked_mode(void *td)
1135{
1136    return do_nt_check_cooked_mode();
1137}
1138#endif /* !WINNT_NATIVE */
1139