MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
tty.c
1 /* $NetBSD: tty.c,v 1.41 2011/10/04 15:27:04 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 1992, 1993
5  * The Regents of the University of California. All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Christos Zoulas of Cornell University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  * may be used to endorse or promote products derived from this software
20  * without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "config.h"
36 #if !defined(lint) && !defined(SCCSID)
37 #if 0
38 static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93";
39 #else
40 #endif
41 #endif /* not lint && not SCCSID */
42 
43 /*
44  * tty.c: tty interface stuff
45  */
46 #include <assert.h>
47 #include <errno.h>
48 #include <unistd.h> /* for isatty */
49 #include <strings.h> /* for ffs */
50 #include "el.h"
51 #include "tty.h"
52 
53 typedef struct ttymodes_t {
54  const char *m_name;
55  unsigned int m_value;
56  int m_type;
57 } ttymodes_t;
58 
59 typedef struct ttymap_t {
60  Int nch, och; /* Internal and termio rep of chars */
61  el_action_t bind[3]; /* emacs, vi, and vi-cmd */
62 } ttymap_t;
63 
64 
65 private const ttyperm_t ttyperm = {
66  {
67  {"iflag:", ICRNL, (INLCR | IGNCR)},
68  {"oflag:", (OPOST | ONLCR), ONLRET},
69  {"cflag:", 0, 0},
70  {"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN),
71  (NOFLSH | ECHONL | EXTPROC | FLUSHO)},
72  {"chars:", 0, 0},
73  },
74  {
75  {"iflag:", (INLCR | ICRNL), IGNCR},
76  {"oflag:", (OPOST | ONLCR), ONLRET},
77  {"cflag:", 0, 0},
78  {"lflag:", ISIG,
79  (NOFLSH | ICANON | ECHO | ECHOK | ECHONL | EXTPROC | IEXTEN | FLUSHO)},
80  {"chars:", (C_SH(C_MIN) | C_SH(C_TIME) | C_SH(C_SWTCH) | C_SH(C_DSWTCH) |
81  C_SH(C_SUSP) | C_SH(C_DSUSP) | C_SH(C_EOL) | C_SH(C_DISCARD) |
82  C_SH(C_PGOFF) | C_SH(C_PAGE) | C_SH(C_STATUS)), 0}
83  },
84  {
85  {"iflag:", 0, IXON | IXOFF | INLCR | ICRNL},
86  {"oflag:", 0, 0},
87  {"cflag:", 0, 0},
88  {"lflag:", 0, ISIG | IEXTEN},
89  {"chars:", 0, 0},
90  }
91 };
92 
93 private const ttychar_t ttychar = {
94  {
95  CINTR, CQUIT, CERASE, CKILL,
96  CEOF, CEOL, CEOL2, CSWTCH,
97  CDSWTCH, CERASE2, CSTART, CSTOP,
98  CWERASE, CSUSP, CDSUSP, CREPRINT,
99  CDISCARD, CLNEXT, CSTATUS, CPAGE,
100  CPGOFF, CKILL2, CBRK, CMIN,
101  CTIME
102  },
103  {
104  CINTR, CQUIT, CERASE, CKILL,
105  _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
106  _POSIX_VDISABLE, CERASE2, CSTART, CSTOP,
107  _POSIX_VDISABLE, CSUSP, _POSIX_VDISABLE, _POSIX_VDISABLE,
108  CDISCARD, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
109  _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1,
110  0
111  },
112  {
113  0, 0, 0, 0,
114  0, 0, 0, 0,
115  0, 0, 0, 0,
116  0, 0, 0, 0,
117  0, 0, 0, 0,
118  0, 0, 0, 0,
119  0
120  }
121 };
122 
123 private const ttymap_t tty_map[] = {
124 #ifdef VERASE
125  {C_ERASE, VERASE,
126  {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
127 #endif /* VERASE */
128 #ifdef VERASE2
129  {C_ERASE2, VERASE2,
130  {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
131 #endif /* VERASE2 */
132 #ifdef VKILL
133  {C_KILL, VKILL,
134  {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
135 #endif /* VKILL */
136 #ifdef VKILL2
137  {C_KILL2, VKILL2,
138  {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
139 #endif /* VKILL2 */
140 #ifdef VEOF
141  {C_EOF, VEOF,
142  {EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}},
143 #endif /* VEOF */
144 #ifdef VWERASE
145  {C_WERASE, VWERASE,
146  {ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}},
147 #endif /* VWERASE */
148 #ifdef VREPRINT
149  {C_REPRINT, VREPRINT,
150  {ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}},
151 #endif /* VREPRINT */
152 #ifdef VLNEXT
153  {C_LNEXT, VLNEXT,
154  {ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}},
155 #endif /* VLNEXT */
156  {(Int)-1, (Int)-1,
157  {ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}}
158 };
159 
160 private const ttymodes_t ttymodes[] = {
161 #ifdef IGNBRK
162  {"ignbrk", IGNBRK, MD_INP},
163 #endif /* IGNBRK */
164 #ifdef BRKINT
165  {"brkint", BRKINT, MD_INP},
166 #endif /* BRKINT */
167 #ifdef IGNPAR
168  {"ignpar", IGNPAR, MD_INP},
169 #endif /* IGNPAR */
170 #ifdef PARMRK
171  {"parmrk", PARMRK, MD_INP},
172 #endif /* PARMRK */
173 #ifdef INPCK
174  {"inpck", INPCK, MD_INP},
175 #endif /* INPCK */
176 #ifdef ISTRIP
177  {"istrip", ISTRIP, MD_INP},
178 #endif /* ISTRIP */
179 #ifdef INLCR
180  {"inlcr", INLCR, MD_INP},
181 #endif /* INLCR */
182 #ifdef IGNCR
183  {"igncr", IGNCR, MD_INP},
184 #endif /* IGNCR */
185 #ifdef ICRNL
186  {"icrnl", ICRNL, MD_INP},
187 #endif /* ICRNL */
188 #ifdef IUCLC
189  {"iuclc", IUCLC, MD_INP},
190 #endif /* IUCLC */
191 #ifdef IXON
192  {"ixon", IXON, MD_INP},
193 #endif /* IXON */
194 #ifdef IXANY
195  {"ixany", IXANY, MD_INP},
196 #endif /* IXANY */
197 #ifdef IXOFF
198  {"ixoff", IXOFF, MD_INP},
199 #endif /* IXOFF */
200 #ifdef IMAXBEL
201  {"imaxbel", IMAXBEL, MD_INP},
202 #endif /* IMAXBEL */
203 
204 #ifdef OPOST
205  {"opost", OPOST, MD_OUT},
206 #endif /* OPOST */
207 #ifdef OLCUC
208  {"olcuc", OLCUC, MD_OUT},
209 #endif /* OLCUC */
210 #ifdef ONLCR
211  {"onlcr", ONLCR, MD_OUT},
212 #endif /* ONLCR */
213 #ifdef OCRNL
214  {"ocrnl", OCRNL, MD_OUT},
215 #endif /* OCRNL */
216 #ifdef ONOCR
217  {"onocr", ONOCR, MD_OUT},
218 #endif /* ONOCR */
219 #ifdef ONOEOT
220  {"onoeot", ONOEOT, MD_OUT},
221 #endif /* ONOEOT */
222 #ifdef ONLRET
223  {"onlret", ONLRET, MD_OUT},
224 #endif /* ONLRET */
225 #ifdef OFILL
226  {"ofill", OFILL, MD_OUT},
227 #endif /* OFILL */
228 #ifdef OFDEL
229  {"ofdel", OFDEL, MD_OUT},
230 #endif /* OFDEL */
231 #ifdef NLDLY
232  {"nldly", NLDLY, MD_OUT},
233 #endif /* NLDLY */
234 #ifdef CRDLY
235  {"crdly", CRDLY, MD_OUT},
236 #endif /* CRDLY */
237 #ifdef TABDLY
238  {"tabdly", TABDLY, MD_OUT},
239 #endif /* TABDLY */
240 #ifdef XTABS
241  {"xtabs", XTABS, MD_OUT},
242 #endif /* XTABS */
243 #ifdef BSDLY
244  {"bsdly", BSDLY, MD_OUT},
245 #endif /* BSDLY */
246 #ifdef VTDLY
247  {"vtdly", VTDLY, MD_OUT},
248 #endif /* VTDLY */
249 #ifdef FFDLY
250  {"ffdly", FFDLY, MD_OUT},
251 #endif /* FFDLY */
252 #ifdef PAGEOUT
253  {"pageout", PAGEOUT, MD_OUT},
254 #endif /* PAGEOUT */
255 #ifdef WRAP
256  {"wrap", WRAP, MD_OUT},
257 #endif /* WRAP */
258 
259 #ifdef CIGNORE
260  {"cignore", CIGNORE, MD_CTL},
261 #endif /* CBAUD */
262 #ifdef CBAUD
263  {"cbaud", CBAUD, MD_CTL},
264 #endif /* CBAUD */
265 #ifdef CSTOPB
266  {"cstopb", CSTOPB, MD_CTL},
267 #endif /* CSTOPB */
268 #ifdef CREAD
269  {"cread", CREAD, MD_CTL},
270 #endif /* CREAD */
271 #ifdef PARENB
272  {"parenb", PARENB, MD_CTL},
273 #endif /* PARENB */
274 #ifdef PARODD
275  {"parodd", PARODD, MD_CTL},
276 #endif /* PARODD */
277 #ifdef HUPCL
278  {"hupcl", HUPCL, MD_CTL},
279 #endif /* HUPCL */
280 #ifdef CLOCAL
281  {"clocal", CLOCAL, MD_CTL},
282 #endif /* CLOCAL */
283 #ifdef LOBLK
284  {"loblk", LOBLK, MD_CTL},
285 #endif /* LOBLK */
286 #ifdef CIBAUD
287  {"cibaud", CIBAUD, MD_CTL},
288 #endif /* CIBAUD */
289 #ifdef CRTSCTS
290 #ifdef CCTS_OFLOW
291  {"ccts_oflow", CCTS_OFLOW, MD_CTL},
292 #else
293  {"crtscts", CRTSCTS, MD_CTL},
294 #endif /* CCTS_OFLOW */
295 #endif /* CRTSCTS */
296 #ifdef CRTS_IFLOW
297  {"crts_iflow", CRTS_IFLOW, MD_CTL},
298 #endif /* CRTS_IFLOW */
299 #ifdef CDTRCTS
300  {"cdtrcts", CDTRCTS, MD_CTL},
301 #endif /* CDTRCTS */
302 #ifdef MDMBUF
303  {"mdmbuf", MDMBUF, MD_CTL},
304 #endif /* MDMBUF */
305 #ifdef RCV1EN
306  {"rcv1en", RCV1EN, MD_CTL},
307 #endif /* RCV1EN */
308 #ifdef XMT1EN
309  {"xmt1en", XMT1EN, MD_CTL},
310 #endif /* XMT1EN */
311 
312 #ifdef ISIG
313  {"isig", ISIG, MD_LIN},
314 #endif /* ISIG */
315 #ifdef ICANON
316  {"icanon", ICANON, MD_LIN},
317 #endif /* ICANON */
318 #ifdef XCASE
319  {"xcase", XCASE, MD_LIN},
320 #endif /* XCASE */
321 #ifdef ECHO
322  {"echo", ECHO, MD_LIN},
323 #endif /* ECHO */
324 #ifdef ECHOE
325  {"echoe", ECHOE, MD_LIN},
326 #endif /* ECHOE */
327 #ifdef ECHOK
328  {"echok", ECHOK, MD_LIN},
329 #endif /* ECHOK */
330 #ifdef ECHONL
331  {"echonl", ECHONL, MD_LIN},
332 #endif /* ECHONL */
333 #ifdef NOFLSH
334  {"noflsh", NOFLSH, MD_LIN},
335 #endif /* NOFLSH */
336 #ifdef TOSTOP
337  {"tostop", TOSTOP, MD_LIN},
338 #endif /* TOSTOP */
339 #ifdef ECHOCTL
340  {"echoctl", ECHOCTL, MD_LIN},
341 #endif /* ECHOCTL */
342 #ifdef ECHOPRT
343  {"echoprt", ECHOPRT, MD_LIN},
344 #endif /* ECHOPRT */
345 #ifdef ECHOKE
346  {"echoke", ECHOKE, MD_LIN},
347 #endif /* ECHOKE */
348 #ifdef DEFECHO
349  {"defecho", DEFECHO, MD_LIN},
350 #endif /* DEFECHO */
351 #ifdef FLUSHO
352  {"flusho", FLUSHO, MD_LIN},
353 #endif /* FLUSHO */
354 #ifdef PENDIN
355  {"pendin", PENDIN, MD_LIN},
356 #endif /* PENDIN */
357 #ifdef IEXTEN
358  {"iexten", IEXTEN, MD_LIN},
359 #endif /* IEXTEN */
360 #ifdef NOKERNINFO
361  {"nokerninfo", NOKERNINFO, MD_LIN},
362 #endif /* NOKERNINFO */
363 #ifdef ALTWERASE
364  {"altwerase", ALTWERASE, MD_LIN},
365 #endif /* ALTWERASE */
366 #ifdef EXTPROC
367  {"extproc", EXTPROC, MD_LIN},
368 #endif /* EXTPROC */
369 
370 #if defined(VINTR)
371  {"intr", C_SH(C_INTR), MD_CHAR},
372 #endif /* VINTR */
373 #if defined(VQUIT)
374  {"quit", C_SH(C_QUIT), MD_CHAR},
375 #endif /* VQUIT */
376 #if defined(VERASE)
377  {"erase", C_SH(C_ERASE), MD_CHAR},
378 #endif /* VERASE */
379 #if defined(VKILL)
380  {"kill", C_SH(C_KILL), MD_CHAR},
381 #endif /* VKILL */
382 #if defined(VEOF)
383  {"eof", C_SH(C_EOF), MD_CHAR},
384 #endif /* VEOF */
385 #if defined(VEOL)
386  {"eol", C_SH(C_EOL), MD_CHAR},
387 #endif /* VEOL */
388 #if defined(VEOL2)
389  {"eol2", C_SH(C_EOL2), MD_CHAR},
390 #endif /* VEOL2 */
391 #if defined(VSWTCH)
392  {"swtch", C_SH(C_SWTCH), MD_CHAR},
393 #endif /* VSWTCH */
394 #if defined(VDSWTCH)
395  {"dswtch", C_SH(C_DSWTCH), MD_CHAR},
396 #endif /* VDSWTCH */
397 #if defined(VERASE2)
398  {"erase2", C_SH(C_ERASE2), MD_CHAR},
399 #endif /* VERASE2 */
400 #if defined(VSTART)
401  {"start", C_SH(C_START), MD_CHAR},
402 #endif /* VSTART */
403 #if defined(VSTOP)
404  {"stop", C_SH(C_STOP), MD_CHAR},
405 #endif /* VSTOP */
406 #if defined(VWERASE)
407  {"werase", C_SH(C_WERASE), MD_CHAR},
408 #endif /* VWERASE */
409 #if defined(VSUSP)
410  {"susp", C_SH(C_SUSP), MD_CHAR},
411 #endif /* VSUSP */
412 #if defined(VDSUSP)
413  {"dsusp", C_SH(C_DSUSP), MD_CHAR},
414 #endif /* VDSUSP */
415 #if defined(VREPRINT)
416  {"reprint", C_SH(C_REPRINT), MD_CHAR},
417 #endif /* VREPRINT */
418 #if defined(VDISCARD)
419  {"discard", C_SH(C_DISCARD), MD_CHAR},
420 #endif /* VDISCARD */
421 #if defined(VLNEXT)
422  {"lnext", C_SH(C_LNEXT), MD_CHAR},
423 #endif /* VLNEXT */
424 #if defined(VSTATUS)
425  {"status", C_SH(C_STATUS), MD_CHAR},
426 #endif /* VSTATUS */
427 #if defined(VPAGE)
428  {"page", C_SH(C_PAGE), MD_CHAR},
429 #endif /* VPAGE */
430 #if defined(VPGOFF)
431  {"pgoff", C_SH(C_PGOFF), MD_CHAR},
432 #endif /* VPGOFF */
433 #if defined(VKILL2)
434  {"kill2", C_SH(C_KILL2), MD_CHAR},
435 #endif /* VKILL2 */
436 #if defined(VBRK)
437  {"brk", C_SH(C_BRK), MD_CHAR},
438 #endif /* VBRK */
439 #if defined(VMIN)
440  {"min", C_SH(C_MIN), MD_CHAR},
441 #endif /* VMIN */
442 #if defined(VTIME)
443  {"time", C_SH(C_TIME), MD_CHAR},
444 #endif /* VTIME */
445  {NULL, 0, -1},
446 };
447 
448 
449 
450 #define tty__gettabs(td) ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
451 #define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8)
452 #define tty__cooked_mode(td) ((td)->c_lflag & ICANON)
453 
454 private int tty_getty(EditLine *, struct termios *);
455 private int tty_setty(EditLine *, int, const struct termios *);
456 private int tty__getcharindex(int);
457 private void tty__getchar(struct termios *, unsigned char *);
458 private void tty__setchar(struct termios *, unsigned char *);
459 private speed_t tty__getspeed(struct termios *);
460 private int tty_setup(EditLine *);
461 
462 #define t_qu t_ts
463 
464 /* tty_getty():
465  * Wrapper for tcgetattr to handle EINTR
466  */
467 private int
468 tty_getty(EditLine *el, struct termios *t)
469 {
470  int rv;
471  while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR)
472  continue;
473  return rv;
474 }
475 
476 /* tty_setty():
477  * Wrapper for tcsetattr to handle EINTR
478  */
479 private int
480 tty_setty(EditLine *el, int action, const struct termios *t)
481 {
482  int rv;
483  while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR)
484  continue;
485  return rv;
486 }
487 
488 /* tty_setup():
489  * Get the tty parameters and initialize the editing state
490  */
491 private int
492 tty_setup(EditLine *el)
493 {
494  int rst = 1;
495 
496  if (el->el_flags & EDIT_DISABLED)
497  return 0;
498 
499  if (!isatty(el->el_outfd)) {
500 #ifdef DEBUG_TTY
501  (void) fprintf(el->el_errfile,
502  "tty_setup: isatty: %s\n", strerror(errno));
503 #endif /* DEBUG_TTY */
504  return -1;
505  }
506  if (tty_getty(el, &el->el_tty.t_ed) == -1) {
507 #ifdef DEBUG_TTY
508  (void) fprintf(el->el_errfile,
509  "tty_setup: tty_getty: %s\n", strerror(errno));
510 #endif /* DEBUG_TTY */
511  return -1;
512  }
513  el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed;
514 
515  el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
516  el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
517  el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
518 
519  el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
520  el->el_tty.t_ex.c_iflag |= el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
521 
522  el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
523  el->el_tty.t_ex.c_oflag |= el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
524 
525  el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
526  el->el_tty.t_ex.c_cflag |= el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
527 
528  el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
529  el->el_tty.t_ex.c_lflag |= el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
530 
531  /*
532  * Reset the tty chars to reasonable defaults
533  * If they are disabled, then enable them.
534  */
535  if (rst) {
536  if (tty__cooked_mode(&el->el_tty.t_ts)) {
537  tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
538  /*
539  * Don't affect CMIN and CTIME for the editor mode
540  */
541  for (rst = 0; rst < C_NCC - 2; rst++)
542  if (el->el_tty.t_c[TS_IO][rst] !=
543  el->el_tty.t_vdisable
544  && el->el_tty.t_c[ED_IO][rst] !=
545  el->el_tty.t_vdisable)
546  el->el_tty.t_c[ED_IO][rst] =
547  el->el_tty.t_c[TS_IO][rst];
548  for (rst = 0; rst < C_NCC; rst++)
549  if (el->el_tty.t_c[TS_IO][rst] !=
550  el->el_tty.t_vdisable)
551  el->el_tty.t_c[EX_IO][rst] =
552  el->el_tty.t_c[TS_IO][rst];
553  }
554  tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
555  if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
556 #ifdef DEBUG_TTY
557  (void) fprintf(el->el_errfile,
558  "tty_setup: tty_setty: %s\n",
559  strerror(errno));
560 #endif /* DEBUG_TTY */
561  return -1;
562  }
563  }
564 
565  el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
566  el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
567 
568  el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
569  el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
570 
571  el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
572  el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
573 
574  el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
575  el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
576 
577  tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
578  tty_bind_char(el, 1);
579  return 0;
580 }
581 
582 protected int
583 tty_init(EditLine *el)
584 {
585 
586  el->el_tty.t_mode = EX_IO;
587  el->el_tty.t_vdisable = _POSIX_VDISABLE;
588  (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
589  (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
590  return tty_setup(el);
591 }
592 
593 
594 /* tty_end():
595  * Restore the tty to its original settings
596  */
597 protected void
598 /*ARGSUSED*/
599 tty_end(EditLine *el __attribute__((__unused__)))
600 {
601 
602  /* XXX: Maybe reset to an initial state? */
603 }
604 
605 
606 /* tty__getspeed():
607  * Get the tty speed
608  */
609 private speed_t
610 tty__getspeed(struct termios *td)
611 {
612  speed_t spd;
613 
614  if ((spd = cfgetispeed(td)) == 0)
615  spd = cfgetospeed(td);
616  return spd;
617 }
618 
619 /* tty__getspeed():
620  * Return the index of the asked char in the c_cc array
621  */
622 private int
623 tty__getcharindex(int i)
624 {
625  switch (i) {
626 #ifdef VINTR
627  case C_INTR:
628  return VINTR;
629 #endif /* VINTR */
630 #ifdef VQUIT
631  case C_QUIT:
632  return VQUIT;
633 #endif /* VQUIT */
634 #ifdef VERASE
635  case C_ERASE:
636  return VERASE;
637 #endif /* VERASE */
638 #ifdef VKILL
639  case C_KILL:
640  return VKILL;
641 #endif /* VKILL */
642 #ifdef VEOF
643  case C_EOF:
644  return VEOF;
645 #endif /* VEOF */
646 #ifdef VEOL
647  case C_EOL:
648  return VEOL;
649 #endif /* VEOL */
650 #ifdef VEOL2
651  case C_EOL2:
652  return VEOL2;
653 #endif /* VEOL2 */
654 #ifdef VSWTCH
655  case C_SWTCH:
656  return VSWTCH;
657 #endif /* VSWTCH */
658 #ifdef VDSWTCH
659  case C_DSWTCH:
660  return VDSWTCH;
661 #endif /* VDSWTCH */
662 #ifdef VERASE2
663  case C_ERASE2:
664  return VERASE2;
665 #endif /* VERASE2 */
666 #ifdef VSTART
667  case C_START:
668  return VSTART;
669 #endif /* VSTART */
670 #ifdef VSTOP
671  case C_STOP:
672  return VSTOP;
673 #endif /* VSTOP */
674 #ifdef VWERASE
675  case C_WERASE:
676  return VWERASE;
677 #endif /* VWERASE */
678 #ifdef VSUSP
679  case C_SUSP:
680  return VSUSP;
681 #endif /* VSUSP */
682 #ifdef VDSUSP
683  case C_DSUSP:
684  return VDSUSP;
685 #endif /* VDSUSP */
686 #ifdef VREPRINT
687  case C_REPRINT:
688  return VREPRINT;
689 #endif /* VREPRINT */
690 #ifdef VDISCARD
691  case C_DISCARD:
692  return VDISCARD;
693 #endif /* VDISCARD */
694 #ifdef VLNEXT
695  case C_LNEXT:
696  return VLNEXT;
697 #endif /* VLNEXT */
698 #ifdef VSTATUS
699  case C_STATUS:
700  return VSTATUS;
701 #endif /* VSTATUS */
702 #ifdef VPAGE
703  case C_PAGE:
704  return VPAGE;
705 #endif /* VPAGE */
706 #ifdef VPGOFF
707  case C_PGOFF:
708  return VPGOFF;
709 #endif /* VPGOFF */
710 #ifdef VKILL2
711  case C_KILL2:
712  return VKILL2;
713 #endif /* KILL2 */
714 #ifdef VMIN
715  case C_MIN:
716  return VMIN;
717 #endif /* VMIN */
718 #ifdef VTIME
719  case C_TIME:
720  return VTIME;
721 #endif /* VTIME */
722  default:
723  return -1;
724  }
725 }
726 
727 /* tty__getchar():
728  * Get the tty characters
729  */
730 private void
731 tty__getchar(struct termios *td, unsigned char *s)
732 {
733 
734 #ifdef VINTR
735  s[C_INTR] = td->c_cc[VINTR];
736 #endif /* VINTR */
737 #ifdef VQUIT
738  s[C_QUIT] = td->c_cc[VQUIT];
739 #endif /* VQUIT */
740 #ifdef VERASE
741  s[C_ERASE] = td->c_cc[VERASE];
742 #endif /* VERASE */
743 #ifdef VKILL
744  s[C_KILL] = td->c_cc[VKILL];
745 #endif /* VKILL */
746 #ifdef VEOF
747  s[C_EOF] = td->c_cc[VEOF];
748 #endif /* VEOF */
749 #ifdef VEOL
750  s[C_EOL] = td->c_cc[VEOL];
751 #endif /* VEOL */
752 #ifdef VEOL2
753  s[C_EOL2] = td->c_cc[VEOL2];
754 #endif /* VEOL2 */
755 #ifdef VSWTCH
756  s[C_SWTCH] = td->c_cc[VSWTCH];
757 #endif /* VSWTCH */
758 #ifdef VDSWTCH
759  s[C_DSWTCH] = td->c_cc[VDSWTCH];
760 #endif /* VDSWTCH */
761 #ifdef VERASE2
762  s[C_ERASE2] = td->c_cc[VERASE2];
763 #endif /* VERASE2 */
764 #ifdef VSTART
765  s[C_START] = td->c_cc[VSTART];
766 #endif /* VSTART */
767 #ifdef VSTOP
768  s[C_STOP] = td->c_cc[VSTOP];
769 #endif /* VSTOP */
770 #ifdef VWERASE
771  s[C_WERASE] = td->c_cc[VWERASE];
772 #endif /* VWERASE */
773 #ifdef VSUSP
774  s[C_SUSP] = td->c_cc[VSUSP];
775 #endif /* VSUSP */
776 #ifdef VDSUSP
777  s[C_DSUSP] = td->c_cc[VDSUSP];
778 #endif /* VDSUSP */
779 #ifdef VREPRINT
780  s[C_REPRINT] = td->c_cc[VREPRINT];
781 #endif /* VREPRINT */
782 #ifdef VDISCARD
783  s[C_DISCARD] = td->c_cc[VDISCARD];
784 #endif /* VDISCARD */
785 #ifdef VLNEXT
786  s[C_LNEXT] = td->c_cc[VLNEXT];
787 #endif /* VLNEXT */
788 #ifdef VSTATUS
789  s[C_STATUS] = td->c_cc[VSTATUS];
790 #endif /* VSTATUS */
791 #ifdef VPAGE
792  s[C_PAGE] = td->c_cc[VPAGE];
793 #endif /* VPAGE */
794 #ifdef VPGOFF
795  s[C_PGOFF] = td->c_cc[VPGOFF];
796 #endif /* VPGOFF */
797 #ifdef VKILL2
798  s[C_KILL2] = td->c_cc[VKILL2];
799 #endif /* KILL2 */
800 #ifdef VMIN
801  s[C_MIN] = td->c_cc[VMIN];
802 #endif /* VMIN */
803 #ifdef VTIME
804  s[C_TIME] = td->c_cc[VTIME];
805 #endif /* VTIME */
806 } /* tty__getchar */
807 
808 
809 /* tty__setchar():
810  * Set the tty characters
811  */
812 private void
813 tty__setchar(struct termios *td, unsigned char *s)
814 {
815 
816 #ifdef VINTR
817  td->c_cc[VINTR] = s[C_INTR];
818 #endif /* VINTR */
819 #ifdef VQUIT
820  td->c_cc[VQUIT] = s[C_QUIT];
821 #endif /* VQUIT */
822 #ifdef VERASE
823  td->c_cc[VERASE] = s[C_ERASE];
824 #endif /* VERASE */
825 #ifdef VKILL
826  td->c_cc[VKILL] = s[C_KILL];
827 #endif /* VKILL */
828 #ifdef VEOF
829  td->c_cc[VEOF] = s[C_EOF];
830 #endif /* VEOF */
831 #ifdef VEOL
832  td->c_cc[VEOL] = s[C_EOL];
833 #endif /* VEOL */
834 #ifdef VEOL2
835  td->c_cc[VEOL2] = s[C_EOL2];
836 #endif /* VEOL2 */
837 #ifdef VSWTCH
838  td->c_cc[VSWTCH] = s[C_SWTCH];
839 #endif /* VSWTCH */
840 #ifdef VDSWTCH
841  td->c_cc[VDSWTCH] = s[C_DSWTCH];
842 #endif /* VDSWTCH */
843 #ifdef VERASE2
844  td->c_cc[VERASE2] = s[C_ERASE2];
845 #endif /* VERASE2 */
846 #ifdef VSTART
847  td->c_cc[VSTART] = s[C_START];
848 #endif /* VSTART */
849 #ifdef VSTOP
850  td->c_cc[VSTOP] = s[C_STOP];
851 #endif /* VSTOP */
852 #ifdef VWERASE
853  td->c_cc[VWERASE] = s[C_WERASE];
854 #endif /* VWERASE */
855 #ifdef VSUSP
856  td->c_cc[VSUSP] = s[C_SUSP];
857 #endif /* VSUSP */
858 #ifdef VDSUSP
859  td->c_cc[VDSUSP] = s[C_DSUSP];
860 #endif /* VDSUSP */
861 #ifdef VREPRINT
862  td->c_cc[VREPRINT] = s[C_REPRINT];
863 #endif /* VREPRINT */
864 #ifdef VDISCARD
865  td->c_cc[VDISCARD] = s[C_DISCARD];
866 #endif /* VDISCARD */
867 #ifdef VLNEXT
868  td->c_cc[VLNEXT] = s[C_LNEXT];
869 #endif /* VLNEXT */
870 #ifdef VSTATUS
871  td->c_cc[VSTATUS] = s[C_STATUS];
872 #endif /* VSTATUS */
873 #ifdef VPAGE
874  td->c_cc[VPAGE] = s[C_PAGE];
875 #endif /* VPAGE */
876 #ifdef VPGOFF
877  td->c_cc[VPGOFF] = s[C_PGOFF];
878 #endif /* VPGOFF */
879 #ifdef VKILL2
880  td->c_cc[VKILL2] = s[C_KILL2];
881 #endif /* VKILL2 */
882 #ifdef VMIN
883  td->c_cc[VMIN] = s[C_MIN];
884 #endif /* VMIN */
885 #ifdef VTIME
886  td->c_cc[VTIME] = s[C_TIME];
887 #endif /* VTIME */
888 } /* tty__setchar */
889 
890 
891 /* tty_bind_char():
892  * Rebind the editline functions
893  */
894 protected void
895 tty_bind_char(EditLine *el, int force)
896 {
897 
898  unsigned char *t_n = el->el_tty.t_c[ED_IO];
899  unsigned char *t_o = el->el_tty.t_ed.c_cc;
900  Char new[2], old[2];
901  const ttymap_t *tp;
902  el_action_t *map, *alt;
903  const el_action_t *dmap, *dalt;
904  new[1] = old[1] = '\0';
905 
906  map = el->el_map.key;
907  alt = el->el_map.alt;
908  if (el->el_map.type == MAP_VI) {
909  dmap = el->el_map.vii;
910  dalt = el->el_map.vic;
911  } else {
912  dmap = el->el_map.emacs;
913  dalt = NULL;
914  }
915 
916  for (tp = tty_map; tp->nch != (Int)-1; tp++) {
917  new[0] = t_n[tp->nch];
918  old[0] = t_o[tp->och];
919  if (new[0] == old[0] && !force)
920  continue;
921  /* Put the old default binding back, and set the new binding */
922  keymacro_clear(el, map, old);
923  map[UC(old[0])] = dmap[UC(old[0])];
924  keymacro_clear(el, map, new);
925  /* MAP_VI == 1, MAP_EMACS == 0... */
926  map[UC(new[0])] = tp->bind[el->el_map.type];
927  if (dalt) {
928  keymacro_clear(el, alt, old);
929  alt[UC(old[0])] = dalt[UC(old[0])];
930  keymacro_clear(el, alt, new);
931  alt[UC(new[0])] = tp->bind[el->el_map.type + 1];
932  }
933  }
934 }
935 
936 
937 /* tty_rawmode():
938  * Set terminal into 1 character at a time mode.
939  */
940 protected int
941 tty_rawmode(EditLine *el)
942 {
943 
944  if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
945  return 0;
946 
947  if (el->el_flags & EDIT_DISABLED)
948  return 0;
949 
950  if (tty_getty(el, &el->el_tty.t_ts) == -1) {
951 #ifdef DEBUG_TTY
952  (void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n",
953  strerror(errno));
954 #endif /* DEBUG_TTY */
955  return -1;
956  }
957  /*
958  * We always keep up with the eight bit setting and the speed of the
959  * tty. But we only believe changes that are made to cooked mode!
960  */
961  el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
962  el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
963 
964  if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
965  tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
966  (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
967  (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
968  (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
969  (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
970  }
971  if (tty__cooked_mode(&el->el_tty.t_ts)) {
972  if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) {
973  el->el_tty.t_ex.c_cflag =
974  el->el_tty.t_ts.c_cflag;
975  el->el_tty.t_ex.c_cflag &=
976  ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
977  el->el_tty.t_ex.c_cflag |=
978  el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
979 
980  el->el_tty.t_ed.c_cflag =
981  el->el_tty.t_ts.c_cflag;
982  el->el_tty.t_ed.c_cflag &=
983  ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
984  el->el_tty.t_ed.c_cflag |=
985  el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
986  }
987  if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
988  (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
989  el->el_tty.t_ex.c_lflag =
990  el->el_tty.t_ts.c_lflag;
991  el->el_tty.t_ex.c_lflag &=
992  ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
993  el->el_tty.t_ex.c_lflag |=
994  el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
995 
996  el->el_tty.t_ed.c_lflag =
997  el->el_tty.t_ts.c_lflag;
998  el->el_tty.t_ed.c_lflag &=
999  ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
1000  el->el_tty.t_ed.c_lflag |=
1001  el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
1002  }
1003  if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
1004  (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
1005  el->el_tty.t_ex.c_iflag =
1006  el->el_tty.t_ts.c_iflag;
1007  el->el_tty.t_ex.c_iflag &=
1008  ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
1009  el->el_tty.t_ex.c_iflag |=
1010  el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
1011 
1012  el->el_tty.t_ed.c_iflag =
1013  el->el_tty.t_ts.c_iflag;
1014  el->el_tty.t_ed.c_iflag &=
1015  ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
1016  el->el_tty.t_ed.c_iflag |=
1017  el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
1018  }
1019  if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
1020  (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
1021  el->el_tty.t_ex.c_oflag =
1022  el->el_tty.t_ts.c_oflag;
1023  el->el_tty.t_ex.c_oflag &=
1024  ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
1025  el->el_tty.t_ex.c_oflag |=
1026  el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
1027 
1028  el->el_tty.t_ed.c_oflag =
1029  el->el_tty.t_ts.c_oflag;
1030  el->el_tty.t_ed.c_oflag &=
1031  ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
1032  el->el_tty.t_ed.c_oflag |=
1033  el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
1034  }
1035  if (tty__gettabs(&el->el_tty.t_ex) == 0)
1036  el->el_tty.t_tabs = 0;
1037  else
1038  el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1039 
1040  {
1041  int i;
1042 
1043  tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1044  /*
1045  * Check if the user made any changes.
1046  * If he did, then propagate the changes to the
1047  * edit and execute data structures.
1048  */
1049  for (i = 0; i < C_NCC; i++)
1050  if (el->el_tty.t_c[TS_IO][i] !=
1051  el->el_tty.t_c[EX_IO][i])
1052  break;
1053 
1054  if (i != C_NCC) {
1055  /*
1056  * Propagate changes only to the unprotected
1057  * chars that have been modified just now.
1058  */
1059  for (i = 0; i < C_NCC; i++) {
1060  if (!((el->el_tty.t_t[ED_IO][MD_CHAR].t_setmask & C_SH(i)))
1061  && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1062  el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
1063  if (el->el_tty.t_t[ED_IO][MD_CHAR].t_clrmask & C_SH(i))
1064  el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
1065  }
1066  tty_bind_char(el, 0);
1067  tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1068 
1069  for (i = 0; i < C_NCC; i++) {
1070  if (!((el->el_tty.t_t[EX_IO][MD_CHAR].t_setmask & C_SH(i)))
1071  && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1072  el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
1073  if (el->el_tty.t_t[EX_IO][MD_CHAR].t_clrmask & C_SH(i))
1074  el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
1075  }
1076  tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1077  }
1078  }
1079  }
1080  if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1081 #ifdef DEBUG_TTY
1082  (void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
1083  strerror(errno));
1084 #endif /* DEBUG_TTY */
1085  return -1;
1086  }
1087  el->el_tty.t_mode = ED_IO;
1088  return 0;
1089 }
1090 
1091 
1092 /* tty_cookedmode():
1093  * Set the tty back to normal mode
1094  */
1095 protected int
1096 tty_cookedmode(EditLine *el)
1097 { /* set tty in normal setup */
1098 
1099  if (el->el_tty.t_mode == EX_IO)
1100  return 0;
1101 
1102  if (el->el_flags & EDIT_DISABLED)
1103  return 0;
1104 
1105  if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
1106 #ifdef DEBUG_TTY
1107  (void) fprintf(el->el_errfile,
1108  "tty_cookedmode: tty_setty: %s\n",
1109  strerror(errno));
1110 #endif /* DEBUG_TTY */
1111  return -1;
1112  }
1113  el->el_tty.t_mode = EX_IO;
1114  return 0;
1115 }
1116 
1117 
1118 /* tty_quotemode():
1119  * Turn on quote mode
1120  */
1121 protected int
1122 tty_quotemode(EditLine *el)
1123 {
1124  if (el->el_tty.t_mode == QU_IO)
1125  return 0;
1126 
1127  el->el_tty.t_qu = el->el_tty.t_ed;
1128 
1129  el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][MD_INP].t_clrmask;
1130  el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask;
1131 
1132  el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask;
1133  el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask;
1134 
1135  el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask;
1136  el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask;
1137 
1138  el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask;
1139  el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_LIN].t_setmask;
1140 
1141  if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
1142 #ifdef DEBUG_TTY
1143  (void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
1144  strerror(errno));
1145 #endif /* DEBUG_TTY */
1146  return -1;
1147  }
1148  el->el_tty.t_mode = QU_IO;
1149  return 0;
1150 }
1151 
1152 
1153 /* tty_noquotemode():
1154  * Turn off quote mode
1155  */
1156 protected int
1157 tty_noquotemode(EditLine *el)
1158 {
1159 
1160  if (el->el_tty.t_mode != QU_IO)
1161  return 0;
1162  if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1163 #ifdef DEBUG_TTY
1164  (void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
1165  strerror(errno));
1166 #endif /* DEBUG_TTY */
1167  return -1;
1168  }
1169  el->el_tty.t_mode = ED_IO;
1170  return 0;
1171 }
1172 
1173 
1174 /* tty_stty():
1175  * Stty builtin
1176  */
1177 protected int
1178 /*ARGSUSED*/
1179 tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv)
1180 {
1181  const ttymodes_t *m;
1182  char x;
1183  int aflag = 0;
1184  const Char *s, *d;
1185  char name[EL_BUFSIZ];
1186  struct termios *tios = &el->el_tty.t_ex;
1187  int z = EX_IO;
1188 
1189  if (argv == NULL)
1190  return -1;
1191  strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
1192  name[sizeof(name) - 1] = '\0';
1193 
1194  while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1195  switch (argv[0][1]) {
1196  case 'a':
1197  aflag++;
1198  argv++;
1199  break;
1200  case 'd':
1201  argv++;
1202  tios = &el->el_tty.t_ed;
1203  z = ED_IO;
1204  break;
1205  case 'x':
1206  argv++;
1207  tios = &el->el_tty.t_ex;
1208  z = EX_IO;
1209  break;
1210  case 'q':
1211  argv++;
1212  tios = &el->el_tty.t_ts;
1213  z = QU_IO;
1214  break;
1215  default:
1216  (void) fprintf(el->el_errfile,
1217  "%s: Unknown switch `%c'.\n",
1218  name, (int) argv[0][1]);
1219  return -1;
1220  }
1221 
1222  if (!argv || !*argv) {
1223  int i = -1;
1224  size_t len = 0, st = 0, cu;
1225  for (m = ttymodes; m->m_name; m++) {
1226  if (m->m_type != i) {
1227  (void) fprintf(el->el_outfile, "%s%s",
1228  i != -1 ? "\n" : "",
1229  el->el_tty.t_t[z][m->m_type].t_name);
1230  i = m->m_type;
1231  st = len =
1232  strlen(el->el_tty.t_t[z][m->m_type].t_name);
1233  }
1234  if (i != -1) {
1235  x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1236  ? '+' : '\0';
1237 
1238  if (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1239  x = '-';
1240  } else {
1241  x = '\0';
1242  }
1243 
1244  if (x != '\0' || aflag) {
1245 
1246  cu = strlen(m->m_name) + (x != '\0') + 1;
1247 
1248  if (len + cu >= (size_t)el->el_terminal.t_size.h) {
1249  (void) fprintf(el->el_outfile, "\n%*s",
1250  (int)st, "");
1251  len = st + cu;
1252  } else
1253  len += cu;
1254 
1255  if (x != '\0')
1256  (void) fprintf(el->el_outfile, "%c%s ",
1257  x, m->m_name);
1258  else
1259  (void) fprintf(el->el_outfile, "%s ",
1260  m->m_name);
1261  }
1262  }
1263  (void) fprintf(el->el_outfile, "\n");
1264  return 0;
1265  }
1266  while (argv && (s = *argv++)) {
1267  const Char *p;
1268  switch (*s) {
1269  case '+':
1270  case '-':
1271  x = (char)*s++;
1272  break;
1273  default:
1274  x = '\0';
1275  break;
1276  }
1277  d = s;
1278  p = Strchr(s, '=');
1279  for (m = ttymodes; m->m_name; m++)
1280  if ((p ? strncmp(m->m_name, ct_encode_string(d, &el->el_scratch), (size_t)(p - d)) :
1281  strcmp(m->m_name, ct_encode_string(d, &el->el_scratch))) == 0 &&
1282  (p == NULL || m->m_type == MD_CHAR))
1283  break;
1284 
1285  if (!m->m_name) {
1286  (void) fprintf(el->el_errfile,
1287  "%s: Invalid argument `" FSTR "'.\n", name, d);
1288  return -1;
1289  }
1290  if (p) {
1291  int c = ffs((int)m->m_value);
1292  int v = *++p ? parse__escape(&p) :
1293  el->el_tty.t_vdisable;
1294  assert(c != 0);
1295  c--;
1296  c = tty__getcharindex(c);
1297  assert(c != -1);
1298  tios->c_cc[c] = (cc_t)v;
1299  continue;
1300  }
1301  switch (x) {
1302  case '+':
1303  el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1304  el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1305  break;
1306  case '-':
1307  el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1308  el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1309  break;
1310  default:
1311  el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1312  el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1313  break;
1314  }
1315  }
1316 
1317  if (el->el_tty.t_mode == z) {
1318  if (tty_setty(el, TCSADRAIN, tios) == -1) {
1319 #ifdef DEBUG_TTY
1320  (void) fprintf(el->el_errfile,
1321  "tty_stty: tty_setty: %s\n", strerror(errno));
1322 #endif /* DEBUG_TTY */
1323  return -1;
1324  }
1325  }
1326 
1327  return 0;
1328 }
1329 
1330 
1331 #ifdef notyet
1332 /* tty_printchar():
1333  * DEbugging routine to print the tty characters
1334  */
1335 private void
1336 tty_printchar(EditLine *el, unsigned char *s)
1337 {
1338  ttyperm_t *m;
1339  int i;
1340 
1341  for (i = 0; i < C_NCC; i++) {
1342  for (m = el->el_tty.t_t; m->m_name; m++)
1343  if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1344  break;
1345  if (m->m_name)
1346  (void) fprintf(el->el_errfile, "%s ^%c ",
1347  m->m_name, s[i] + 'A' - 1);
1348  if (i % 5 == 0)
1349  (void) fprintf(el->el_errfile, "\n");
1350  }
1351  (void) fprintf(el->el_errfile, "\n");
1352 }
1353 #endif /* notyet */