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