xref: /csrg-svn/lib/libedit/tty.c (revision 54624)
1 /*-
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Christos Zoulas of Cornell University.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #if !defined(lint) && !defined(SCCSID)
12 static char sccsid[] = "@(#)tty.c	5.2 (Berkeley) 07/03/92";
13 #endif /* not lint && not SCCSID */
14 
15 /*
16  * tty.c: tty interface stuff
17  */
18 #include "sys.h"
19 #include "tty.h"
20 #include "el.h"
21 
22 private ttyperm_t ttyperm = {
23     {
24 	{ "iflag:", ICRNL, (INLCR|IGNCR) },
25 	{ "oflag:", (OPOST|ONLCR), ONLRET },
26 	{ "cflag:", 0, 0 },
27 	{ "lflag:", (ISIG|ICANON|ECHO|ECHOE|ECHOCTL|IEXTEN),
28 		    (NOFLSH|ECHONL|EXTPROC|FLUSHO) },
29 	{ "chars:", 	0, 0 },
30     },
31     {
32 	{ "iflag:", (INLCR|ICRNL), IGNCR },
33 	{ "oflag:", (OPOST|ONLCR), ONLRET },
34 	{ "cflag:", 0, 0 },
35 	{ "lflag:", ISIG,
36 		    (NOFLSH|ICANON|ECHO|ECHOK|ECHONL|EXTPROC|IEXTEN|FLUSHO) },
37 	{ "chars:", (C_SH(C_MIN)|C_SH(C_TIME)|C_SH(C_SWTCH)|C_SH(C_DSWTCH)|
38 		     C_SH(C_WERASE)|C_SH(C_REPRINT)|C_SH(C_SUSP)|C_SH(C_DSUSP)|
39 		     C_SH(C_EOF)|C_SH(C_EOL)|C_SH(C_DISCARD)|C_SH(C_PGOFF)|
40 		     C_SH(C_KILL2)|C_SH(C_PAGE)|C_SH(C_STATUS)|C_SH(C_LNEXT)),
41 		     0 }
42     },
43     {
44 	{ "iflag:", 0, IXON | IXOFF },
45 	{ "oflag:", 0, 0 },
46 	{ "cflag:", 0, 0 },
47 	{ "lflag:", 0, ISIG | IEXTEN },
48 	{ "chars:", 0, 0 },
49     }
50 };
51 
52 private ttychar_t ttychar = {
53     {
54 	CINTR,		 CQUIT, 	 CERASE, 	   CKILL,
55 	CEOF, 		 CEOL, 		 CEOL2, 	   CSWTCH,
56 	CDSWTCH,	 CERASE2,	 CSTART, 	   CSTOP,
57 	CWERASE, 	 CSUSP, 	 CDSUSP, 	   CREPRINT,
58 	CDISCARD, 	 CLNEXT,	 CSTATUS,	   CPAGE,
59 	CPGOFF,		 CKILL2, 	 CBRK, 		   CMIN,
60 	CTIME
61     },
62     {
63 	CINTR, 		 CQUIT, 	  CERASE, 	   CKILL,
64 	_POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
65 	_POSIX_VDISABLE, CERASE2,	  CSTART, 	   CSTOP,
66 	_POSIX_VDISABLE, CSUSP,           _POSIX_VDISABLE, _POSIX_VDISABLE,
67 	CDISCARD, 	 _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
68 	_POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1,
69 	0
70     },
71     {
72 	0,		 0,		  0,		   0,
73 	0,		 0,		  0,		   0,
74 	0,		 0,		  0,		   0,
75 	0,		 0,		  0,		   0,
76 	0,		 0,		  0,		   0,
77 	0,		 0,		  0,		   0,
78 	0
79     }
80 };
81 
82 typedef struct ttymodes_t {
83     char *m_name;
84     int   m_value;
85     int   m_type;
86 } ttymodes_t;
87 
88 private ttymodes_t ttymodes[] = {
89 # ifdef	IGNBRK
90     { "ignbrk",	IGNBRK,	M_INP },
91 # endif /* IGNBRK */
92 # ifdef	BRKINT
93     { "brkint",	BRKINT,	M_INP },
94 # endif /* BRKINT */
95 # ifdef	IGNPAR
96     { "ignpar",	IGNPAR,	M_INP },
97 # endif /* IGNPAR */
98 # ifdef	PARMRK
99     { "parmrk",	PARMRK,	M_INP },
100 # endif /* PARMRK */
101 # ifdef	INPCK
102     { "inpck",	INPCK,	M_INP },
103 # endif /* INPCK */
104 # ifdef	ISTRIP
105     { "istrip",	ISTRIP,	M_INP },
106 # endif /* ISTRIP */
107 # ifdef	INLCR
108     { "inlcr",	INLCR,	M_INP },
109 # endif /* INLCR */
110 # ifdef	IGNCR
111     { "igncr",	IGNCR,	M_INP },
112 # endif /* IGNCR */
113 # ifdef	ICRNL
114     { "icrnl",	ICRNL,	M_INP },
115 # endif /* ICRNL */
116 # ifdef	IUCLC
117     { "iuclc",	IUCLC,	M_INP },
118 # endif /* IUCLC */
119 # ifdef	IXON
120     { "ixon",	IXON,	M_INP },
121 # endif /* IXON */
122 # ifdef	IXANY
123     { "ixany",	IXANY,	M_INP },
124 # endif /* IXANY */
125 # ifdef	IXOFF
126     { "ixoff",	IXOFF,	M_INP },
127 # endif /* IXOFF */
128 # ifdef  IMAXBEL
129     { "imaxbel",IMAXBEL,M_INP },
130 # endif /* IMAXBEL */
131 
132 # ifdef	OPOST
133     { "opost",	OPOST,	M_OUT },
134 # endif /* OPOST */
135 # ifdef	OLCUC
136     { "olcuc",	OLCUC,	M_OUT },
137 # endif /* OLCUC */
138 # ifdef	ONLCR
139     { "onlcr",	ONLCR,	M_OUT },
140 # endif /* ONLCR */
141 # ifdef	OCRNL
142     { "ocrnl",	OCRNL,	M_OUT },
143 # endif /* OCRNL */
144 # ifdef	ONOCR
145     { "onocr",	ONOCR,	M_OUT },
146 # endif /* ONOCR */
147 # ifdef ONOEOT
148     { "onoeot",	ONOEOT,	M_OUT },
149 # endif /* ONOEOT */
150 # ifdef	ONLRET
151     { "onlret",	ONLRET,	M_OUT },
152 # endif /* ONLRET */
153 # ifdef	OFILL
154     { "ofill",	OFILL,	M_OUT },
155 # endif /* OFILL */
156 # ifdef	OFDEL
157     { "ofdel",	OFDEL,	M_OUT },
158 # endif /* OFDEL */
159 # ifdef	NLDLY
160     { "nldly",	NLDLY,	M_OUT },
161 # endif /* NLDLY */
162 # ifdef	CRDLY
163     { "crdly",	CRDLY,	M_OUT },
164 # endif /* CRDLY */
165 # ifdef	TABDLY
166     { "tabdly",	TABDLY,	M_OUT },
167 # endif /* TABDLY */
168 # ifdef	XTABS
169     { "xtabs",	XTABS,	M_OUT },
170 # endif /* XTABS */
171 # ifdef	BSDLY
172     { "bsdly",	BSDLY,	M_OUT },
173 # endif /* BSDLY */
174 # ifdef	VTDLY
175     { "vtdly",	VTDLY,	M_OUT },
176 # endif /* VTDLY */
177 # ifdef	FFDLY
178     { "ffdly",	FFDLY,	M_OUT },
179 # endif /* FFDLY */
180 # ifdef	PAGEOUT
181     { "pageout",PAGEOUT,M_OUT },
182 # endif /* PAGEOUT */
183 # ifdef	WRAP
184     { "wrap",	WRAP,	M_OUT },
185 # endif /* WRAP */
186 
187 # ifdef	CIGNORE
188     { "cignore",CIGNORE,M_CTL },
189 # endif /* CBAUD */
190 # ifdef	CBAUD
191     { "cbaud",	CBAUD,	M_CTL },
192 # endif /* CBAUD */
193 # ifdef	CSTOPB
194     { "cstopb",	CSTOPB,	M_CTL },
195 # endif /* CSTOPB */
196 # ifdef	CREAD
197     { "cread",	CREAD,	M_CTL },
198 # endif /* CREAD */
199 # ifdef	PARENB
200     { "parenb",	PARENB,	M_CTL },
201 # endif /* PARENB */
202 # ifdef	PARODD
203     { "parodd",	PARODD,	M_CTL },
204 # endif /* PARODD */
205 # ifdef	HUPCL
206     { "hupcl",	HUPCL,	M_CTL },
207 # endif /* HUPCL */
208 # ifdef	CLOCAL
209     { "clocal",	CLOCAL,	M_CTL },
210 # endif /* CLOCAL */
211 # ifdef	LOBLK
212     { "loblk",	LOBLK,	M_CTL },
213 # endif /* LOBLK */
214 # ifdef	CIBAUD
215     { "cibaud",	CIBAUD,	M_CTL },
216 # endif /* CIBAUD */
217 # ifdef CRTSCTS
218 #  ifdef CCTS_OFLOW
219     { "ccts_oflow",CCTS_OFLOW,M_CTL },
220 #  else
221     { "crtscts",CRTSCTS,M_CTL },
222 #  endif /* CCTS_OFLOW */
223 # endif /* CRTSCTS */
224 # ifdef CRTS_IFLOW
225     { "crts_iflow",CRTS_IFLOW,M_CTL },
226 # endif /* CRTS_IFLOW */
227 # ifdef MDMBUF
228     { "mdmbuf",	MDMBUF,	M_CTL },
229 # endif /* MDMBUF */
230 # ifdef RCV1EN
231     { "rcv1en",	RCV1EN,	M_CTL },
232 # endif /* RCV1EN */
233 # ifdef XMT1EN
234     { "xmt1en",	XMT1EN,	M_CTL },
235 # endif /* XMT1EN */
236 
237 # ifdef	ISIG
238     { "isig",	ISIG,	M_LIN },
239 # endif /* ISIG */
240 # ifdef	ICANON
241     { "icanon",	ICANON,	M_LIN },
242 # endif /* ICANON */
243 # ifdef	XCASE
244     { "xcase",	XCASE,	M_LIN },
245 # endif /* XCASE */
246 # ifdef	ECHO
247     { "echo",	ECHO,	M_LIN },
248 # endif /* ECHO */
249 # ifdef	ECHOE
250     { "echoe",	ECHOE,	M_LIN },
251 # endif /* ECHOE */
252 # ifdef	ECHOK
253     { "echok",	ECHOK,	M_LIN },
254 # endif /* ECHOK */
255 # ifdef	ECHONL
256     { "echonl",	ECHONL,	M_LIN },
257 # endif /* ECHONL */
258 # ifdef	NOFLSH
259     { "noflsh",	NOFLSH,	M_LIN },
260 # endif /* NOFLSH */
261 # ifdef	TOSTOP
262     { "tostop",	TOSTOP,	M_LIN },
263 # endif /* TOSTOP */
264 # ifdef	ECHOCTL
265     { "echoctl",ECHOCTL,M_LIN },
266 # endif /* ECHOCTL */
267 # ifdef	ECHOPRT
268     { "echoprt",ECHOPRT,M_LIN },
269 # endif /* ECHOPRT */
270 # ifdef	ECHOKE
271     { "echoke",	ECHOKE,	M_LIN },
272 # endif /* ECHOKE */
273 # ifdef	DEFECHO
274     { "defecho",DEFECHO,M_LIN },
275 # endif /* DEFECHO */
276 # ifdef	FLUSHO
277     { "flusho",	FLUSHO,	M_LIN },
278 # endif /* FLUSHO */
279 # ifdef	PENDIN
280     { "pendin",	PENDIN,	M_LIN },
281 # endif /* PENDIN */
282 # ifdef	IEXTEN
283     { "iexten",	IEXTEN,	M_LIN },
284 # endif /* IEXTEN */
285 # ifdef	NOKERNINFO
286     { "nokerninfo",NOKERNINFO,M_LIN },
287 # endif /* NOKERNINFO */
288 # ifdef	ALTWERASE
289     { "altwerase",ALTWERASE,M_LIN },
290 # endif /* ALTWERASE */
291 # ifdef	EXTPROC
292     { "extproc",EXTPROC, M_LIN },
293 # endif /* EXTPROC */
294 
295 # if defined(VINTR)
296     { "intr",		C_SH(C_INTR), 	M_CHAR },
297 # endif /* VINTR */
298 # if defined(VQUIT)
299     { "quit",		C_SH(C_QUIT), 	M_CHAR },
300 # endif /* VQUIT */
301 # if defined(VERASE)
302     { "erase",		C_SH(C_ERASE), 	M_CHAR },
303 # endif /* VERASE */
304 # if defined(VKILL)
305     { "kill",		C_SH(C_KILL), 	M_CHAR },
306 # endif /* VKILL */
307 # if defined(VEOF)
308     { "eof",		C_SH(C_EOF), 	M_CHAR },
309 # endif /* VEOF */
310 # if defined(VEOL)
311     { "eol",		C_SH(C_EOL), 	M_CHAR },
312 # endif /* VEOL */
313 # if defined(VEOL2)
314     { "eol2",		C_SH(C_EOL2), 	M_CHAR },
315 # endif  /* VEOL2 */
316 # if defined(VSWTCH)
317     { "swtch",		C_SH(C_SWTCH), 	M_CHAR },
318 # endif /* VSWTCH */
319 # if defined(VDSWTCH)
320     { "dswtch",		C_SH(C_DSWTCH),	M_CHAR },
321 # endif /* VDSWTCH */
322 # if defined(VERASE2)
323     { "erase2",		C_SH(C_ERASE2),	M_CHAR },
324 # endif /* VERASE2 */
325 # if defined(VSTART)
326     { "start",		C_SH(C_START), 	M_CHAR },
327 # endif /* VSTART */
328 # if defined(VSTOP)
329     { "stop",		C_SH(C_STOP), 	M_CHAR },
330 # endif /* VSTOP */
331 # if defined(VWERASE)
332     { "werase",		C_SH(C_WERASE),	M_CHAR },
333 # endif /* VWERASE */
334 # if defined(VSUSP)
335     { "susp",		C_SH(C_SUSP), 	M_CHAR },
336 # endif /* VSUSP */
337 # if defined(VDSUSP)
338     { "dsusp",		C_SH(C_DSUSP), 	M_CHAR },
339 # endif /* VDSUSP */
340 # if defined(VREPRINT)
341     { "reprint",	C_SH(C_REPRINT),M_CHAR },
342 # endif /* WREPRINT */
343 # if defined(VDISCARD)
344     { "discard",	C_SH(C_DISCARD),M_CHAR },
345 # endif /* VDISCARD */
346 # if defined(VLNEXT)
347     { "lnext",		C_SH(C_LNEXT), 	M_CHAR },
348 # endif /* VLNEXT */
349 # if defined(VSTATUS)
350     { "status",		C_SH(C_STATUS),	M_CHAR },
351 # endif /* VSTATUS */
352 # if defined(VPAGE)
353     { "page",		C_SH(C_PAGE), 	M_CHAR },
354 # endif /* VPAGE */
355 # if defined(VPGOFF)
356     { "pgoff",		C_SH(C_PGOFF), 	M_CHAR },
357 # endif /* VPGOFF */
358 # if defined(VKILL2)
359     { "kill2",		C_SH(C_KILL2), 	M_CHAR },
360 # endif /* VKILL2 */
361 # if defined(VBRK)
362     { "brk",		C_SH(C_BRK), 	M_CHAR },
363 # endif /* VBRK */
364 # if defined(VMIN)
365     { "min",		C_SH(C_MIN), 	M_CHAR },
366 # endif /* VMIN */
367 # if defined(VTIME)
368     { "time",		C_SH(C_TIME), 	M_CHAR },
369 # endif /* VTIME */
370     { NULL, 0, -1 },
371 };
372 
373 
374 
375 #define tty_getty(el, td) tcgetattr((el)->el_infd, (td))
376 #define tty_setty(el, td) tcsetattr((el)->el_infd, TCSADRAIN, (td))
377 
378 #define tty__gettabs(td)     ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
379 #define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8)
380 #define tty__cooked_mode(td) ((td)->c_lflag & ICANON)
381 
382 private void    tty__getchar	__P((struct termios *, unsigned char *));
383 private void    tty__setchar	__P((struct termios *, unsigned char *));
384 private speed_t tty__getspeed	__P((struct termios *));
385 private int     tty_setup	__P((EditLine *));
386 
387 #define t_qu t_ts
388 
389 
390 /* tty_setup():
391  *	Get the tty parameters and initialize the editing state
392  */
393 private int
394 tty_setup(el)
395     EditLine *el;
396 {
397     int rst = 1;
398     if (tty_getty(el, &el->el_tty.t_ed) == -1) {
399 #ifdef DEBUG_TTY
400 	(void) fprintf(el->el_errfile,
401 		       "tty_setup: tty_getty: %s\n", strerror(errno));
402 #endif /* DEBUG_TTY */
403 	return(-1);
404     }
405     el->el_tty.t_ts    = el->el_tty.t_ex = el->el_tty.t_ed;
406 
407     el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
408     el->el_tty.t_tabs  = tty__gettabs(&el->el_tty.t_ex);
409     el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
410 
411     el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][M_INP].t_clrmask;
412     el->el_tty.t_ex.c_iflag |=  el->el_tty.t_t[EX_IO][M_INP].t_setmask;
413 
414     el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][M_OUT].t_clrmask;
415     el->el_tty.t_ex.c_oflag |=  el->el_tty.t_t[EX_IO][M_OUT].t_setmask;
416 
417     el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][M_CTL].t_clrmask;
418     el->el_tty.t_ex.c_cflag |=  el->el_tty.t_t[EX_IO][M_CTL].t_setmask;
419 
420     el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][M_LIN].t_clrmask;
421     el->el_tty.t_ex.c_lflag |=  el->el_tty.t_t[EX_IO][M_LIN].t_setmask;
422 
423     /*
424      * Reset the tty chars to reasonable defaults
425      * If they are disabled, then enable them.
426      */
427     if (rst) {
428         if (tty__cooked_mode(&el->el_tty.t_ts)) {
429             tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
430             /*
431              * Don't affect CMIN and CTIME for the editor mode
432              */
433             for (rst = 0; rst < C_NCC - 2; rst++)
434                 if (el->el_tty.t_c[TS_IO][rst] != el->el_tty.t_vdisable &&
435                     el->el_tty.t_c[ED_IO][rst] != el->el_tty.t_vdisable)
436                     el->el_tty.t_c[ED_IO][rst]  = el->el_tty.t_c[TS_IO][rst];
437             for (rst = 0; rst < C_NCC; rst++)
438                 if (el->el_tty.t_c[TS_IO][rst] != el->el_tty.t_vdisable &&
439                     el->el_tty.t_c[EX_IO][rst] != el->el_tty.t_vdisable)
440                     el->el_tty.t_c[EX_IO][rst]  = el->el_tty.t_c[TS_IO][rst];
441         }
442         tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
443         if (tty_setty(el, &el->el_tty.t_ex) == -1) {
444 #ifdef DEBUG_TTY
445             (void) fprintf(el->el_errfile, "tty_setup: tty_setty: %s\n",
446 			   strerror(errno));
447 #endif /* DEBUG_TTY */
448             return(-1);
449         }
450     }
451     else
452         tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
453 
454     el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][M_INP].t_clrmask;
455     el->el_tty.t_ed.c_iflag |=  el->el_tty.t_t[ED_IO][M_INP].t_setmask;
456 
457     el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][M_OUT].t_clrmask;
458     el->el_tty.t_ed.c_oflag |=  el->el_tty.t_t[ED_IO][M_OUT].t_setmask;
459 
460     el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][M_CTL].t_clrmask;
461     el->el_tty.t_ed.c_cflag |=  el->el_tty.t_t[ED_IO][M_CTL].t_setmask;
462 
463     el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][M_LIN].t_clrmask;
464     el->el_tty.t_ed.c_lflag |=  el->el_tty.t_t[ED_IO][M_LIN].t_setmask;
465 
466     tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
467     return 0;
468 }
469 
470 protected int
471 tty_init(el)
472     EditLine *el;
473 {
474     el->el_tty.t_mode     = EX_IO;
475     el->el_tty.t_vdisable = _POSIX_VDISABLE;
476     (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
477     (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
478     return tty_setup(el);
479 } /* end tty_init */
480 
481 
482 /* tty_end():
483  *	Restore the tty to its original settings
484  */
485 protected void
486 /*ARGSUSED*/
487 tty_end(el)
488     EditLine *el;
489 {
490     /* XXX: Maybe reset to an initial state? */
491 }
492 
493 
494 /* tty__getspeed():
495  *	Get the tty speed
496  */
497 private speed_t
498 tty__getspeed(td)
499     struct termios *td;
500 {
501     speed_t spd;
502 
503     if ((spd = cfgetispeed(td)) == 0)
504 	spd = cfgetospeed(td);
505     return spd;
506 } /* end tty__getspeed */
507 
508 
509 /* tty__getchar():
510  *	Get the tty characters
511  */
512 private void
513 tty__getchar(td, s)
514     struct termios *td;
515     unsigned char *s;
516 {
517 # ifdef VINTR
518     s[C_INTR]	= td->c_cc[VINTR];
519 # endif /* VINTR */
520 # ifdef VQUIT
521     s[C_QUIT]	= td->c_cc[VQUIT];
522 # endif /* VQUIT */
523 # ifdef VERASE
524     s[C_ERASE]	= td->c_cc[VERASE];
525 # endif /* VERASE */
526 # ifdef VKILL
527     s[C_KILL]	= td->c_cc[VKILL];
528 # endif /* VKILL */
529 # ifdef VEOF
530     s[C_EOF]	= td->c_cc[VEOF];
531 # endif /* VEOF */
532 # ifdef VEOL
533     s[C_EOL]	= td->c_cc[VEOL];
534 # endif /* VEOL */
535 # ifdef VEOL2
536     s[C_EOL2]	= td->c_cc[VEOL2];
537 # endif  /* VEOL2 */
538 # ifdef VSWTCH
539     s[C_SWTCH]	= td->c_cc[VSWTCH];
540 # endif /* VSWTCH */
541 # ifdef VDSWTCH
542     s[C_DSWTCH]	= td->c_cc[VDSWTCH];
543 # endif /* VDSWTCH */
544 # ifdef VERASE2
545     s[C_ERASE2]	= td->c_cc[VERASE2];
546 # endif /* VERASE2 */
547 # ifdef VSTART
548     s[C_START]	= td->c_cc[VSTART];
549 # endif /* VSTART */
550 # ifdef VSTOP
551     s[C_STOP]	= td->c_cc[VSTOP];
552 # endif /* VSTOP */
553 # ifdef VWERASE
554     s[C_WERASE]	= td->c_cc[VWERASE];
555 # endif /* VWERASE */
556 # ifdef VSUSP
557     s[C_SUSP]	= td->c_cc[VSUSP];
558 # endif /* VSUSP */
559 # ifdef VDSUSP
560     s[C_DSUSP]	= td->c_cc[VDSUSP];
561 # endif /* VDSUSP */
562 # ifdef VREPRINT
563     s[C_REPRINT]= td->c_cc[VREPRINT];
564 # endif /* WREPRINT */
565 # ifdef VDISCARD
566     s[C_DISCARD]= td->c_cc[VDISCARD];
567 # endif /* VDISCARD */
568 # ifdef VLNEXT
569     s[C_LNEXT]	= td->c_cc[VLNEXT];
570 # endif /* VLNEXT */
571 # ifdef VSTATUS
572     s[C_STATUS]	= td->c_cc[VSTATUS];
573 # endif /* VSTATUS */
574 # ifdef VPAGE
575     s[C_PAGE]	= td->c_cc[VPAGE];
576 # endif /* VPAGE */
577 # ifdef VPGOFF
578     s[C_PGOFF]	= td->c_cc[VPGOFF];
579 # endif /* VPGOFF */
580 # ifdef VKILL2
581     s[C_KILL2]	= td->c_cc[VKILL2];
582 # endif /* KILL2 */
583 # ifdef VMIN
584     s[C_MIN]	= td->c_cc[VMIN];
585 # endif /* VMIN */
586 # ifdef VTIME
587     s[C_TIME]	= td->c_cc[VTIME];
588 # endif /* VTIME */
589 } /* tty__getchar */
590 
591 
592 /* tty__setchar():
593  *	Set the tty characters
594  */
595 private void
596 tty__setchar(td, s)
597     struct termios *td;
598     unsigned char *s;
599 {
600 # ifdef VINTR
601     td->c_cc[VINTR]	= s[C_INTR];
602 # endif /* VINTR */
603 # ifdef VQUIT
604     td->c_cc[VQUIT]	= s[C_QUIT];
605 # endif /* VQUIT */
606 # ifdef VERASE
607     td->c_cc[VERASE]	= s[C_ERASE];
608 # endif /* VERASE */
609 # ifdef VKILL
610     td->c_cc[VKILL]	= s[C_KILL];
611 # endif /* VKILL */
612 # ifdef VEOF
613     td->c_cc[VEOF]	= s[C_EOF];
614 # endif /* VEOF */
615 # ifdef VEOL
616     td->c_cc[VEOL]	= s[C_EOL];
617 # endif /* VEOL */
618 # ifdef VEOL2
619     td->c_cc[VEOL2]	= s[C_EOL2];
620 # endif  /* VEOL2 */
621 # ifdef VSWTCH
622     td->c_cc[VSWTCH]	= s[C_SWTCH];
623 # endif /* VSWTCH */
624 # ifdef VDSWTCH
625     td->c_cc[VDSWTCH]	= s[C_DSWTCH];
626 # endif /* VDSWTCH */
627 # ifdef VERASE2
628     td->c_cc[VERASE2]	= s[C_ERASE2];
629 # endif /* VERASE2 */
630 # ifdef VSTART
631     td->c_cc[VSTART]	= s[C_START];
632 # endif /* VSTART */
633 # ifdef VSTOP
634     td->c_cc[VSTOP]	= s[C_STOP];
635 # endif /* VSTOP */
636 # ifdef VWERASE
637     td->c_cc[VWERASE]	= s[C_WERASE];
638 # endif /* VWERASE */
639 # ifdef VSUSP
640     td->c_cc[VSUSP]	= s[C_SUSP];
641 # endif /* VSUSP */
642 # ifdef VDSUSP
643     td->c_cc[VDSUSP]	= s[C_DSUSP];
644 # endif /* VDSUSP */
645 # ifdef VREPRINT
646     td->c_cc[VREPRINT]	= s[C_REPRINT];
647 # endif /* WREPRINT */
648 # ifdef VDISCARD
649     td->c_cc[VDISCARD]	= s[C_DISCARD];
650 # endif /* VDISCARD */
651 # ifdef VLNEXT
652     td->c_cc[VLNEXT]	= s[C_LNEXT];
653 # endif /* VLNEXT */
654 # ifdef VSTATUS
655     td->c_cc[VSTATUS]	= s[C_STATUS];
656 # endif /* VSTATUS */
657 # ifdef VPAGE
658     td->c_cc[VPAGE]	= s[C_PAGE];
659 # endif /* VPAGE */
660 # ifdef VPGOFF
661     td->c_cc[VPGOFF]	= s[C_PGOFF];
662 # endif /* VPGOFF */
663 # ifdef VKILL2
664     td->c_cc[VKILL2]	= s[C_KILL2];
665 # endif /* VKILL2 */
666 # ifdef VMIN
667     td->c_cc[VMIN]	= s[C_MIN];
668 # endif /* VMIN */
669 # ifdef VTIME
670     td->c_cc[VTIME]	= s[C_TIME];
671 # endif /* VTIME */
672 } /* tty__setchar */
673 
674 
675 /* tty_rawmode():
676  * 	Set terminal into 1 character at a time mode.
677  */
678 protected int
679 tty_rawmode(el)
680     EditLine *el;
681 {
682     if (el->el_tty.t_mode == ED_IO)
683 	return (0);
684 
685     if (tty_getty(el, &el->el_tty.t_ts) == -1) {
686 #ifdef DEBUG_TTY
687 	(void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n", strerror(errno));
688 #endif /* DEBUG_TTY */
689 	return(-1);
690     }
691 
692     /*
693      * We always keep up with the eight bit setting and the speed of the
694      * tty. But only we only believe changes that are made to cooked mode!
695      */
696     el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
697     el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
698 
699     if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
700 	tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
701 	(void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
702 	(void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
703 	(void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
704 	(void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
705     }
706 
707     if (tty__cooked_mode(&el->el_tty.t_ts)) {
708 	if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) {
709 	    el->el_tty.t_ex.c_cflag  = el->el_tty.t_ts.c_cflag;
710 	    el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][M_CTL].t_clrmask;
711 	    el->el_tty.t_ex.c_cflag |=  el->el_tty.t_t[EX_IO][M_CTL].t_setmask;
712 
713 	    el->el_tty.t_ed.c_cflag  = el->el_tty.t_ts.c_cflag;
714 	    el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][M_CTL].t_clrmask;
715 	    el->el_tty.t_ed.c_cflag |=  el->el_tty.t_t[ED_IO][M_CTL].t_setmask;
716 	}
717 
718 	if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
719 	    (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
720 	    el->el_tty.t_ex.c_lflag = el->el_tty.t_ts.c_lflag;
721 	    el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][M_LIN].t_clrmask;
722 	    el->el_tty.t_ex.c_lflag |=  el->el_tty.t_t[EX_IO][M_LIN].t_setmask;
723 
724 	    el->el_tty.t_ed.c_lflag = el->el_tty.t_ts.c_lflag;
725 	    el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][M_LIN].t_clrmask;
726 	    el->el_tty.t_ed.c_lflag |=  el->el_tty.t_t[ED_IO][M_LIN].t_setmask;
727 	}
728 
729 	if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
730 	    (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
731 	    el->el_tty.t_ex.c_iflag = el->el_tty.t_ts.c_iflag;
732 	    el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][M_INP].t_clrmask;
733 	    el->el_tty.t_ex.c_iflag |=  el->el_tty.t_t[EX_IO][M_INP].t_setmask;
734 
735 	    el->el_tty.t_ed.c_iflag = el->el_tty.t_ts.c_iflag;
736 	    el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][M_INP].t_clrmask;
737 	    el->el_tty.t_ed.c_iflag |=  el->el_tty.t_t[ED_IO][M_INP].t_setmask;
738 	}
739 
740 	if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
741 	    (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
742 	    el->el_tty.t_ex.c_oflag = el->el_tty.t_ts.c_oflag;
743 	    el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][M_OUT].t_clrmask;
744 	    el->el_tty.t_ex.c_oflag |=  el->el_tty.t_t[EX_IO][M_OUT].t_setmask;
745 
746 	    el->el_tty.t_ed.c_oflag = el->el_tty.t_ts.c_oflag;
747 	    el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][M_OUT].t_clrmask;
748 	    el->el_tty.t_ed.c_oflag |=  el->el_tty.t_t[ED_IO][M_OUT].t_setmask;
749 	}
750 
751 	if (tty__gettabs(&el->el_tty.t_ex) == 0)
752 	    el->el_tty.t_tabs = 0;
753 	else
754 	    el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
755 
756 	{
757 	    int i;
758 
759 	    tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
760 	    /*
761 	     * Check if the user made any changes.
762 	     * If he did, then propagate the changes to the
763 	     * edit and execute data structures.
764 	     */
765 	    for (i = 0; i < C_NCC; i++)
766 		if (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])
767 		    break;
768 
769 	    if (i != C_NCC) {
770 		/*
771 		 * Propagate changes only to the unprotected chars
772 		 * that have been modified just now.
773 		 */
774 		for (i = 0; i < C_NCC; i++) {
775 		    if (!((el->el_tty.t_t[ED_IO][M_CHAR].t_setmask & C_SH(i)))
776 		      && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
777 			el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
778 		    if (el->el_tty.t_t[ED_IO][M_CHAR].t_clrmask & C_SH(i))
779 			el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
780 		}
781 		tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
782 
783 		for (i = 0; i < C_NCC; i++) {
784 		    if (!((el->el_tty.t_t[EX_IO][M_CHAR].t_setmask & C_SH(i)))
785 		      && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
786 			el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
787 		    if (el->el_tty.t_t[EX_IO][M_CHAR].t_clrmask & C_SH(i))
788 			el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
789 		}
790 		tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
791 	    }
792 
793 	}
794     }
795 
796     if (tty_setty(el, &el->el_tty.t_ed) == -1) {
797 #ifdef DEBUG_TTY
798 	(void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
799 		       strerror(errno));
800 #endif /* DEBUG_TTY */
801 	return -1;
802     }
803     el->el_tty.t_mode = ED_IO;
804     return (0);
805 } /* end tty_rawmode */
806 
807 
808 /* tty_cookedmode():
809  *	Set the tty back to normal mode
810  */
811 protected int
812 tty_cookedmode(el)
813     EditLine *el;
814 {				/* set tty in normal setup */
815     if (el->el_tty.t_mode == EX_IO)
816 	return (0);
817 
818     if (tty_setty(el, &el->el_tty.t_ex) == -1) {
819 #ifdef DEBUG_TTY
820 	(void) fprintf(el->el_errfile, "tty_cookedmode: tty_setty: %s\n",
821 		       strerror(errno));
822 #endif /* DEBUG_TTY */
823 	return -1;
824     }
825     el->el_tty.t_mode = EX_IO;
826     return (0);
827 } /* end tty_cookedmode */
828 
829 
830 /* tty_quotemode():
831  *	Turn on quote mode
832  */
833 protected int
834 tty_quotemode(el)
835     EditLine *el;
836 {
837     if (el->el_tty.t_mode == QU_IO)
838 	return 0;
839 
840     el->el_tty.t_qu = el->el_tty.t_ed;
841 
842     el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][M_INP].t_clrmask;
843     el->el_tty.t_qu.c_iflag |=  el->el_tty.t_t[QU_IO][M_INP].t_setmask;
844 
845     el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][M_OUT].t_clrmask;
846     el->el_tty.t_qu.c_oflag |=  el->el_tty.t_t[QU_IO][M_OUT].t_setmask;
847 
848     el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][M_CTL].t_clrmask;
849     el->el_tty.t_qu.c_cflag |=  el->el_tty.t_t[QU_IO][M_CTL].t_setmask;
850 
851     el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][M_LIN].t_clrmask;
852     el->el_tty.t_qu.c_lflag |=  el->el_tty.t_t[QU_IO][M_LIN].t_setmask;
853 
854     if (tty_setty(el, &el->el_tty.t_qu) == -1) {
855 #ifdef DEBUG_TTY
856 	(void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
857 		       strerror(errno));
858 #endif /* DEBUG_TTY */
859 	return -1;
860     }
861     el->el_tty.t_mode = QU_IO;
862     return 0;
863 } /* end tty_quotemode */
864 
865 
866 /* tty_noquotemode():
867  *	Turn off quote mode
868  */
869 protected int
870 tty_noquotemode(el)
871     EditLine *el;
872 {
873     if (el->el_tty.t_mode != QU_IO)
874 	return 0;
875     if (tty_setty(el, &el->el_tty.t_ed) == -1) {
876 #ifdef DEBUG_TTY
877 	(void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
878 		       strerror(errno));
879 #endif /* DEBUG_TTY */
880 	return -1;
881     }
882     el->el_tty.t_mode = ED_IO;
883     return 0;
884 }
885 
886 /* tty_stty():
887  *	Stty builtin
888  */
889 protected int
890 /*ARGSUSED*/
891 tty_stty(el, argc, argv)
892     EditLine *el;
893     int argc;
894     char **argv;
895 {
896     ttymodes_t *m;
897     char x, *d;
898     int aflag = 0;
899     char *s;
900     char *name;
901     int z = EX_IO;
902 
903     if (argv == NULL)
904 	return -1;
905     name = *argv++;
906 
907     while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
908 	switch (argv[0][1]) {
909 	case 'a':
910 	    aflag++;
911 	    argv++;
912 	    break;
913 	case 'd':
914 	    argv++;
915 	    z = ED_IO;
916 	    break;
917 	case 'x':
918 	    argv++;
919 	    z = EX_IO;
920 	    break;
921 	case 'q':
922 	    argv++;
923 	    z = QU_IO;
924 	    break;
925 	default:
926 	    (void) fprintf(el->el_errfile, "%s: Unknown switch `%c'.\n",
927 			   name, argv[0][1]);
928 	    return -1;
929 	}
930 
931     if (!argv || !*argv) {
932 	int i = -1;
933 	int len = 0, st = 0, cu;
934 	for (m = ttymodes; m->m_name; m++) {
935 	    if (m->m_type != i) {
936 		(void) fprintf(el->el_outfile, "%s%s", i != -1 ? "\n" : "",
937 			el->el_tty.t_t[z][m->m_type].t_name);
938 		i = m->m_type;
939 		st = len = strlen(el->el_tty.t_t[z][m->m_type].t_name);
940 	    }
941 
942 	    x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) ? '+' : '\0';
943 	    x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value) ? '-' : x;
944 
945 	    if (x != '\0' || aflag) {
946 
947 		cu = strlen(m->m_name) + (x != '\0') + 1;
948 
949 		if (len + cu >= el->el_term.t_size.h) {
950 		    (void) fprintf(el->el_outfile, "\n%*s", st, "");
951 		    len = st + cu;
952 		}
953 		else
954 		    len += cu;
955 
956 		if (x != '\0')
957 		    (void) fprintf(el->el_outfile, "%c%s ", x, m->m_name);
958 		else
959 		    (void) fprintf(el->el_outfile, "%s ", m->m_name);
960 	    }
961 	}
962 	(void) fprintf(el->el_outfile, "\n");
963 	return 0;
964     }
965 
966     while (argv && (s = *argv++)) {
967 	switch (*s) {
968 	case '+':
969 	case '-':
970 	    x = *s++;
971 	    break;
972 	default:
973 	    x = '\0';
974 	    break;
975 	}
976 	d = s;
977 	for (m = ttymodes; m->m_name; m++)
978 	    if (strcmp(m->m_name, d) == 0)
979 		break;
980 
981 	if (!m->m_name)  {
982 	    (void) fprintf(el->el_errfile, "%s: Invalid argument `%s'.\n",
983 			   name, d);
984 	    return -1;
985 	}
986 
987 	switch (x) {
988 	case '+':
989 	    el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
990 	    el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
991 	    break;
992 	case '-':
993 	    el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
994 	    el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
995 	    break;
996 	default:
997 	    el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
998 	    el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
999 	    break;
1000 	}
1001     }
1002     return 0;
1003 } /* end tty_stty */
1004 
1005 
1006 #ifdef notyet
1007 /* tty_printchar():
1008  *	DEbugging routine to print the tty characters
1009  */
1010 private void
1011 tty_printchar(el, s)
1012     EditLine *el;
1013     unsigned char *s;
1014 {
1015     ttyperm_t *m;
1016     int i;
1017 
1018     for (i = 0; i < C_NCC; i++) {
1019 	for (m = el->el_tty.t_t; m->m_name; m++)
1020 	    if (m->m_type == M_CHAR && C_SH(i) == m->m_value)
1021 		break;
1022 	if (m->m_name)
1023 	    (void) fprintf(el->el_errfile, "%s ^%c ", m->m_name, s[i] + 'A'-1);
1024 	if (i % 5 == 0)
1025 	    (void) fprintf(el->el_errfile, "\n");
1026     }
1027     (void) fprintf(el->el_errfile, "\n");
1028 }
1029 #endif /* notyet */
1030