THANKS: Coverity.com (overdue)
[s-mailx.git] / src / mx / termios.c
blob733974ebcebec4ccef42df2b16be92ecc38bfbde
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Implementation of termios.h.
3 *@ FIXME everywhere: tcsetattr() generates SIGTTOU when we're not in
4 *@ FIXME foreground pgrp, and can fail with EINTR!!
5 *@ TODO . SIGINT during HANDS_OFF reaches us nonetheless.
6 *@ TODO . _HANDS_OFF as well as the stack based approach as such is nonsense.
7 *@ TODO It might work well for this MUA, but in general termios_ctx should
8 *@ TODO be a public struct with a lifetime, and activate/suspend methods.
9 *@ TODO It shall be up to the callers how this is managed, we can emit some
10 *@ TODO state events to let them decide for good.
11 *@ TODO Handling children which take over terminal via HANDS_OFF is bad:
12 *@ TODO instead, we need to have a notion of background and foreground,
13 *@ TODO and ensure the terminal is in normal mode when going backward.
14 *@ TODO What children do is up to them, managing them in stack: impossible
16 * Copyright (c) 2012 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
17 * SPDX-License-Identifier: ISC
19 * Permission to use, copy, modify, and/or distribute this software for any
20 * purpose with or without fee is hereby granted, provided that the above
21 * copyright notice and this permission notice appear in all copies.
23 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
24 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
26 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
27 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
28 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
29 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31 #undef su_FILE
32 #define su_FILE termios
33 #define mx_SOURCE
34 #define mx_SOURCE_TERMIOS
36 #ifndef mx_HAVE_AMALGAMATION
37 # include "mx/nail.h"
38 #endif
40 #include <sys/ioctl.h>
42 #include <termios.h>
44 #include <su/icodec.h>
45 #include <su/mem.h>
47 #include "mx/sigs.h"
48 #include "mx/tty.h"
50 #include "mx/termios.h"
51 #include "su/code-in.h"
53 /* Problem: VAL_ configuration values are strings, we need numbers */
54 #define a_TERMIOS_DEFAULT_HEIGHT \
55 (VAL_HEIGHT[1] == '\0' ? (VAL_HEIGHT[0] - '0') \
56 : (VAL_HEIGHT[2] == '\0' \
57 ? ((VAL_HEIGHT[0] - '0') * 10 + (VAL_HEIGHT[1] - '0')) \
58 : (((VAL_HEIGHT[0] - '0') * 10 + (VAL_HEIGHT[1] - '0')) * 10 + \
59 (VAL_HEIGHT[2] - '0'))))
60 #define a_TERMIOS_DEFAULT_WIDTH \
61 (VAL_WIDTH[1] == '\0' ? (VAL_WIDTH[0] - '0') \
62 : (VAL_WIDTH[2] == '\0' \
63 ? ((VAL_WIDTH[0] - '0') * 10 + (VAL_WIDTH[1] - '0')) \
64 : (((VAL_WIDTH[0] - '0') * 10 + (VAL_WIDTH[1] - '0')) * 10 + \
65 (VAL_WIDTH[2] - '0'))))
67 #ifdef SIGWINCH
68 # define a_TERMIOS_SIGWINCH SIGWINCH
69 #else
70 # define a_TERMIOS_SIGWINCH -1
71 #endif
73 struct a_termios_env{
74 struct a_termios_env *tiose_prev;
75 u8 tiose_cmd;
76 u8 tiose_a1;
77 boole tiose_suspended;
78 u8 tiose__pad[1];
79 /*s32 tiose_pgrp;*/ /* In HANDS_OFF mode */
80 su_64( u8 tiose__pad2[4]; )
81 mx_termios_on_state_change tiose_on_state_change;
82 up tiose_osc_cookie;
83 struct termios tiose_state;
86 struct a_termios_g{
87 struct a_termios_env *tiosg_envp;
88 /* If outermost == normal state; used as init switch, too */
89 struct a_termios_env *tiosg_normal;
90 struct a_termios_env *tiosg_pend_free;
91 /*s32 tiosg_pgrp;
92 *u8 tiosg__pad[4];*/
93 n_sighdl_t tiosg_otstp;
94 n_sighdl_t tiosg_ottin;
95 n_sighdl_t tiosg_ottou;
96 n_sighdl_t tiosg_ocont;
97 #if a_TERMIOS_SIGWINCH != -1
98 n_sighdl_t tiosg_owinch;
99 #endif
100 /* Remaining signals only when in password/raw mode */
101 n_sighdl_t tiosg_ohup;
102 n_sighdl_t tiosg_oint;
103 n_sighdl_t tiosg_oquit;
104 n_sighdl_t tiosg_oterm;
105 struct a_termios_env tiosg_env_base;
108 static struct a_termios_g a_termios_g;
110 struct mx_termios_dimension mx_termios_dimen;
112 /* */
113 static void a_termios_sig_adjust(boole condome);
115 /* */
116 static void a_termios_onsig(int sig);
118 /* */
119 SINLINE boole a_termios_norm_query(void);
121 /* Do the system-dependent dance on getting used to terminal dimension */
122 static void a_termios_dimen_query(struct mx_termios_dimension *tiosdp);
124 static void
125 a_termios_sig_adjust(boole condome){
126 NYD2_IN;
128 if(condome){
129 if((a_termios_g.tiosg_ohup = safe_signal(SIGHUP, SIG_IGN)) != SIG_IGN)
130 safe_signal(SIGHUP, &a_termios_onsig);
131 if((a_termios_g.tiosg_oint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
132 safe_signal(SIGINT, &a_termios_onsig);
133 safe_signal(SIGQUIT, &a_termios_onsig);
134 safe_signal(SIGTERM, &a_termios_onsig);
135 }else{
136 if(a_termios_g.tiosg_ohup != SIG_IGN)
137 safe_signal(SIGHUP, a_termios_g.tiosg_ohup);
138 if(a_termios_g.tiosg_oint != SIG_IGN)
139 safe_signal(SIGINT, a_termios_g.tiosg_oint);
140 safe_signal(SIGQUIT, a_termios_g.tiosg_oquit);
141 safe_signal(SIGTERM, a_termios_g.tiosg_oterm);
143 NYD2_OU;
146 SINLINE boole
147 a_termios_norm_query(void){
148 boole rv;
149 /*NYD2_IN;*/
151 rv = (tcgetattr(fileno(mx_tty_fp),
152 &a_termios_g.tiosg_normal->tiose_state) == 0);
153 /* XXX always set ECHO and ICANON in our "normal" canonical state */
154 a_termios_g.tiosg_normal->tiose_state.c_lflag |= ECHO | ICANON;
155 /*NYD2_OU;*/
156 return rv;
159 static void
160 a_termios_onsig(int sig){
161 n_sighdl_t oact, myact;
162 sigset_t nset;
163 struct a_termios_env *tiosep;
164 boole jobsig, dopop;
165 NYD; /* Signal handler */
167 if(sig == a_TERMIOS_SIGWINCH)
168 goto jsigwinch;
170 #undef a_X
171 #define a_X(N,X,Y) \
172 case SIG ## N: oact = a_termios_g.tiosg_o ## X; jobsig = Y; break;
174 switch(sig){
175 default:
176 a_X(TSTP, tstp, TRU1)
177 a_X(TTIN, ttin, TRU1)
178 a_X(TTOU, ttou, TRU1)
179 a_X(CONT, cont, TRU1)
180 a_X(HUP, hup, FAL0)
181 a_X(INT, int, FAL0)
182 a_X(QUIT, quit, FAL0)
183 a_X(TERM, term, FAL0)
186 #undef a_X
188 dopop = FAL0;
189 tiosep = a_termios_g.tiosg_envp;
191 if(!jobsig || sig != SIGCONT){
192 if(!tiosep->tiose_suspended){
193 tiosep->tiose_suspended = TRU1;
195 if(tiosep->tiose_on_state_change != NIL){
196 dopop = (*tiosep->tiose_on_state_change)(
197 tiosep->tiose_osc_cookie,
198 (mx_TERMIOS_STATE_SUSPEND | mx_TERMIOS_STATE_SIGNAL |
199 (jobsig ? mx_TERMIOS_STATE_JOB_SIGNAL : 0)), sig);
200 if(dopop)
201 a_termios_g.tiosg_envp = tiosep->tiose_prev;
204 if(tiosep->tiose_cmd != mx_TERMIOS_CMD_NORMAL)
205 (void)tcsetattr(fileno(mx_tty_fp), TCSAFLUSH,
206 &a_termios_g.tiosg_normal->tiose_state);
210 /* If we shall pop this level link context in a list for later freeing in
211 * a more regular context */
212 if(dopop){
213 tiosep->tiose_prev = a_termios_g.tiosg_pend_free;
214 a_termios_g.tiosg_pend_free = tiosep;
217 if(jobsig || (tiosep->tiose_cmd != mx_TERMIOS_CMD_HANDS_OFF &&
218 oact != SIG_DFL && oact != SIG_IGN && oact != SIG_ERR)){
219 myact = safe_signal(sig, oact);
221 sigemptyset(&nset);
222 sigaddset(&nset, sig);
223 sigprocmask(SIG_UNBLOCK, &nset, NIL);
224 n_raise(sig);
225 sigprocmask(SIG_BLOCK, &nset, NIL);
227 safe_signal(sig, myact);
229 /* When we come here we shall continue */
230 if(!dopop && tiosep->tiose_suspended){
231 tiosep->tiose_suspended = FAL0;
233 if(tiosep->tiose_cmd != mx_TERMIOS_CMD_HANDS_OFF){
234 /* Requery our notion of what is "normal", so that possible user
235 * adjustments which happened in the meantime are kept */
236 a_termios_norm_query();
238 if(tiosep->tiose_cmd != mx_TERMIOS_CMD_NORMAL)
239 (void)tcsetattr(fileno(mx_tty_fp), TCSADRAIN,
240 &tiosep->tiose_state);
243 if(tiosep->tiose_on_state_change != NIL)
244 (*tiosep->tiose_on_state_change)(tiosep->tiose_osc_cookie,
245 (mx_TERMIOS_STATE_RESUME | mx_TERMIOS_STATE_SIGNAL |
246 (jobsig ? mx_TERMIOS_STATE_JOB_SIGNAL : 0)), sig);
249 #if a_TERMIOS_SIGWINCH == -1
250 if(sig == SIGCONT)
251 goto jsigwinch;
252 #endif
255 jleave:
256 return;
258 jsigwinch:
259 if(n_psonce & n_PSO_INTERACTIVE){
260 a_termios_dimen_query(&mx_termios_dimen);
261 if(mx_termios_dimen.tiosd_width > 1 &&
262 !(n_psonce & n_PSO_TERMCAP_FULLWIDTH))
263 --mx_termios_dimen.tiosd_width;
264 n_pstate |= n_PS_SIGWINCH_PEND;
266 goto jleave;
269 static void
270 a_termios_dimen_query(struct mx_termios_dimension *tiosdp){
271 struct termios tbuf;
272 #if defined mx_HAVE_TCGETWINSIZE || defined TIOCGWINSZ
273 struct winsize ws;
274 #elif defined TIOCGSIZE
275 struct ttysize ts;
276 #else
277 # error One of tcgetwinsize(3), TIOCGWINSZ and TIOCGSIZE
278 #endif
279 /*NYD2_IN;*/
281 #ifdef mx_HAVE_TCGETWINSIZE
282 if(tcgetwinsize(fileno(mx_tty_fp), &ws) == -1)
283 ws.ws_col = ws.ws_row = 0;
284 #elif defined TIOCGWINSZ
285 if(ioctl(fileno(mx_tty_fp), TIOCGWINSZ, &ws) == -1)
286 ws.ws_col = ws.ws_row = 0;
287 #elif defined TIOCGSIZE
288 if(ioctl(fileno(mx_tty_fp), TIOCGSIZE, &ws) == -1)
289 ts.ts_lines = ts.ts_cols = 0;
290 #endif
292 #if defined mx_HAVE_TCGETWINSIZE || defined TIOCGWINSZ
293 if(ws.ws_row != 0)
294 tiosdp->tiosd_height = tiosdp->tiosd_real_height = ws.ws_row;
295 #elif defined TIOCGSIZE
296 if(ts.ts_lines != 0)
297 tiosdp->tiosd_height = tiosdp->tiosd_real_height = ts.ts_lines;
298 #endif
299 else{
300 speed_t ospeed;
302 /* We use the following algorithm for the fallback height:
303 * If baud rate < 1200, use 9
304 * If baud rate = 1200, use 14
305 * If baud rate > 1200, use VAL_HEIGHT */
306 ospeed = ((tcgetattr(fileno(mx_tty_fp), &tbuf) == -1)
307 ? B9600 : cfgetospeed(&tbuf));
309 if(ospeed < B1200)
310 tiosdp->tiosd_height = 9;
311 else if(ospeed == B1200)
312 tiosdp->tiosd_height = 14;
313 else
314 tiosdp->tiosd_height = a_TERMIOS_DEFAULT_HEIGHT;
316 tiosdp->tiosd_real_height = a_TERMIOS_DEFAULT_HEIGHT;
319 if(0 == (
320 #if defined mx_HAVE_TCGETWINSIZE || defined TIOCGWINSZ
321 tiosdp->tiosd_width = tiosdp->tiosd_real_width = ws.ws_col
322 #elif defined TIOCGSIZE
323 tiosdp->tiosd_width = tiosdp->tiosd_real_width = ts.ts_cols
324 #endif
326 tiosdp->tiosd_width = tiosdp->tiosd_real_width = a_TERMIOS_DEFAULT_WIDTH;
328 /*NYD2_OU;*/
331 void
332 mx_termios_controller_setup(enum mx_termios_setup what){
333 sigset_t nset, oset;
334 NYD_IN;
336 if(what == mx_TERMIOS_SETUP_STARTUP){
337 a_termios_g.tiosg_envp = &a_termios_g.tiosg_env_base;
339 sigfillset(&nset);
340 sigprocmask(SIG_BLOCK, &nset, &oset);
342 a_termios_g.tiosg_otstp = safe_signal(SIGTSTP, &a_termios_onsig);
343 a_termios_g.tiosg_ottin = safe_signal(SIGTTIN, &a_termios_onsig);
344 a_termios_g.tiosg_ottou = safe_signal(SIGTTOU, &a_termios_onsig);
345 a_termios_g.tiosg_ocont = safe_signal(SIGCONT, &a_termios_onsig);
347 /* This assumes oset contains nothing but SIGCHLD, so to say */
348 sigdelset(&oset, SIGTSTP);
349 sigdelset(&oset, SIGTTIN);
350 sigdelset(&oset, SIGTTOU);
351 sigdelset(&oset, SIGCONT);
352 sigprocmask(SIG_SETMASK, &oset, NIL);
353 }else{
354 /* Semantics are a bit hairy and cast in stone in the manual, and
355 * scattered all over the place, at least $COLUMNS, $LINES, -# */
356 if(!su_state_has(su_STATE_REPRODUCIBLE) &&
357 ((n_psonce & n_PSO_INTERACTIVE) ||
358 ((n_psonce & n_PSO_TTYANY) && (n_poption & n_PO_BATCH_FLAG)))){
359 /* (Also) POSIX: LINES and COLUMNS always override. These variables
360 * are ensured to be positive numbers, so no checking */
361 u32 l, c;
362 char const *cp;
363 boole hadl, hadc;
365 ASSERT(mx_termios_dimen.tiosd_height == 0);
366 ASSERT(mx_termios_dimen.tiosd_real_height == 0);
367 ASSERT(mx_termios_dimen.tiosd_width == 0);
368 ASSERT(mx_termios_dimen.tiosd_real_width == 0);
369 if(n_psonce & n_PSO_INTERACTIVE){
370 /* XXX Yet WINCH after WINCH/CONT, but see POSIX TOSTOP flag */
371 #if a_TERMIOS_SIGWINCH != -1
372 if(safe_signal(SIGWINCH, SIG_IGN) != SIG_IGN)
373 a_termios_g.tiosg_owinch = safe_signal(SIGWINCH,
374 &a_termios_onsig);
375 #endif
378 l = c = 0;
379 if((hadl = ((cp = ok_vlook(LINES)) != NIL)))
380 su_idec_u32_cp(&l, cp, 0, NIL);
381 if((hadc = ((cp = ok_vlook(COLUMNS)) != NIL)))
382 su_idec_u32_cp(&c, cp, 0, NIL);
384 if(l == 0 || c == 0){
385 /* In non-interactive mode, stop now, except for the documented
386 * case that both are set but not both have been usable */
387 if(!(n_psonce & n_PSO_INTERACTIVE) &&
388 !((n_psonce & n_PSO_TTYANY) &&
389 (n_poption & n_PO_BATCH_FLAG)) &&
390 (!hadl || !hadc))
391 goto jtermsize_default;
393 a_termios_dimen_query(&mx_termios_dimen);
396 if(l != 0)
397 mx_termios_dimen.tiosd_real_height =
398 mx_termios_dimen.tiosd_height = l;
399 if(c != 0)
400 mx_termios_dimen.tiosd_width =
401 mx_termios_dimen.tiosd_real_width = c;
402 }else{
403 jtermsize_default:
404 /* $COLUMNS and $LINES defaults as documented in the manual! */
405 mx_termios_dimen.tiosd_height =
406 mx_termios_dimen.tiosd_real_height = a_TERMIOS_DEFAULT_HEIGHT;
407 mx_termios_dimen.tiosd_width =
408 mx_termios_dimen.tiosd_real_width = a_TERMIOS_DEFAULT_WIDTH;
411 /* Note: for this first invocation this will always trigger.
412 * If we have termcap support then termcap_init() will undo this if
413 * FULLWIDTH is set after termcap is initialized.
414 * We have to evaluate it now since cmds may run pre-termcap ... */
415 if(mx_termios_dimen.tiosd_width > 1)
416 --mx_termios_dimen.tiosd_width;
417 n_pstate |= n_PS_SIGWINCH_PEND;
420 NYD_OU;
423 void
424 mx_termios_on_state_change_set(mx_termios_on_state_change tiossc, up cookie){
425 NYD2_IN;
426 ASSERT(a_termios_g.tiosg_envp->tiose_prev != NIL); /* Not in base level */
428 a_termios_g.tiosg_envp->tiose_on_state_change = tiossc;
429 a_termios_g.tiosg_envp->tiose_osc_cookie = cookie;
430 NYD2_OU;
433 boole
434 mx_termios_cmd(u32 tiosc, uz a1){
435 /* xxx tcsetattr not correct says manual: would need to requery and check
436 * whether all desired changes made it instead! */
437 boole rv;
438 struct a_termios_env *tiosep_2free, *tiosep;
439 NYD_IN;
441 tiosep_2free = NIL;
442 UNINIT(tiosep, NIL);
444 ASSERT_NYD_EXEC((tiosc & mx__TERMIOS_CMD_CTL_MASK) ||
445 tiosc == mx_TERMIOS_CMD_RESET ||
446 /*(tiosc == mx_TERMIOS_CMD_SET_PGRP &&
447 * a_termios_g.tiosg_envp->tiose_cmd == mx_TERMIOS_CMD_HANDS_OFF) ||*/
448 (a_termios_g.tiosg_envp->tiose_prev != NIL &&
449 ((tiosc & mx__TERMIOS_CMD_ACT_MASK) == mx_TERMIOS_CMD_RAW ||
450 (tiosc & mx__TERMIOS_CMD_ACT_MASK) == mx_TERMIOS_CMD_RAW_TIMEOUT) &&
451 (a_termios_g.tiosg_envp->tiose_cmd == mx_TERMIOS_CMD_RAW ||
452 a_termios_g.tiosg_envp->tiose_cmd == mx_TERMIOS_CMD_RAW_TIMEOUT)),
453 rv = FAL0);
454 ASSERT_NYD_EXEC(!(tiosc & mx_TERMIOS_CMD_POP) ||
455 a_termios_g.tiosg_envp->tiose_prev != NIL, rv = FAL0);
456 ASSERT_NYD_EXEC((tiosc & mx__TERMIOS_CMD_ACT_MASK) ||
457 (tiosc == mx_TERMIOS_CMD_RESET /*|| tiosc == mx_TERMIOS_CMD_SET_PGRP*/),
458 rv = FAL0);
460 if(a_termios_g.tiosg_normal == NIL){
461 a_termios_g.tiosg_normal = a_termios_g.tiosg_envp;
462 a_termios_g.tiosg_normal->tiose_cmd = mx_TERMIOS_CMD_NORMAL;
463 /*rv =*/ a_termios_norm_query();
466 /* Note: RESET only called with signals blocked in main loop handler */
467 if(tiosc == mx_TERMIOS_CMD_RESET){
468 boole isfirst;
470 if((tiosep = a_termios_g.tiosg_envp)->tiose_prev == NIL){
471 rv = TRU1;
472 goto jleave;
474 rv = (tcsetattr(fileno(mx_tty_fp), TCSADRAIN, &tiosep->tiose_state
475 ) == 0);
477 for(isfirst = TRU1;; isfirst = FAL0){
478 a_termios_g.tiosg_envp = tiosep->tiose_prev;
480 if(isfirst || !tiosep->tiose_suspended){
481 if(tiosep->tiose_on_state_change != NIL)
482 (*tiosep->tiose_on_state_change)(tiosep->tiose_osc_cookie,
483 (isfirst ? mx_TERMIOS_STATE_SUSPEND : 0
484 | mx_TERMIOS_STATE_POP), 0);
487 su_FREE(tiosep);
489 if((tiosep = a_termios_g.tiosg_envp)->tiose_prev == NIL)
490 break;
493 a_termios_sig_adjust(FAL0);
494 goto jleave;
495 #if 0
496 }else if(tiosc == mx_TERMIOS_CMD_SET_PGRP){
497 if(a_termios_g.tiosg_pgrp == 0)
498 a_termios_g.tiosg_pgrp = getpgrp();
499 rv = (tcsetpgrp(fileno(mx_tty_fp), S(pid_t,a1)) == 0);
500 goto jleave;
501 #endif
502 }else if(a_termios_g.tiosg_envp->tiose_cmd ==
503 (tiosc & mx__TERMIOS_CMD_ACT_MASK) &&
504 !(tiosc & mx__TERMIOS_CMD_CTL_MASK)){
505 rv = TRU1;
506 goto jleave;
509 if(tiosc & mx_TERMIOS_CMD_PUSH){
510 tiosep = su_TCALLOC(struct a_termios_env, 1);
511 tiosep->tiose_cmd = (tiosc & mx__TERMIOS_CMD_ACT_MASK);
514 mx_sigs_all_holdx();
516 if(tiosc & mx_TERMIOS_CMD_PUSH){
517 if((tiosep->tiose_prev = a_termios_g.tiosg_envp)->tiose_prev == NIL)
518 a_termios_sig_adjust(TRU1);
519 else{
520 if(!a_termios_g.tiosg_envp->tiose_suspended){
521 a_termios_g.tiosg_envp->tiose_suspended = TRU1;
522 if(a_termios_g.tiosg_envp->tiose_on_state_change != NIL)
523 (*a_termios_g.tiosg_envp->tiose_on_state_change)(
524 a_termios_g.tiosg_envp->tiose_osc_cookie,
525 mx_TERMIOS_STATE_SUSPEND, 0);
529 a_termios_g.tiosg_envp = tiosep;
530 }else if(tiosc & mx_TERMIOS_CMD_POP){
531 tiosep_2free = tiosep = a_termios_g.tiosg_envp;
532 a_termios_g.tiosg_envp = tiosep->tiose_prev;
533 tiosep->tiose_prev = NIL;
535 if(!tiosep->tiose_suspended && tiosep->tiose_on_state_change != NIL)
536 (*tiosep->tiose_on_state_change)(tiosep->tiose_osc_cookie,
537 (mx_TERMIOS_STATE_SUSPEND | mx_TERMIOS_STATE_POP), 0);
539 if((tiosep = a_termios_g.tiosg_envp)->tiose_prev == NIL)
540 a_termios_sig_adjust(FAL0);
542 tiosc = tiosep->tiose_cmd | mx_TERMIOS_CMD_POP;
543 a1 = tiosep->tiose_a1;
544 }else
545 tiosep = a_termios_g.tiosg_envp;
547 if(tiosep->tiose_prev != NIL)
548 su_mem_copy(&tiosep->tiose_state, &a_termios_g.tiosg_normal->tiose_state,
549 sizeof(tiosep->tiose_state));
550 else
551 ASSERT(tiosep->tiose_cmd == mx_TERMIOS_CMD_NORMAL);
553 switch((tiosep->tiose_cmd = (tiosc & mx__TERMIOS_CMD_ACT_MASK))){
554 default:
555 case mx_TERMIOS_CMD_HANDS_OFF:
556 if(!(tiosc & mx_TERMIOS_CMD_PUSH)){
557 rv = TRU1;
558 break;
560 /* FALLTHRU */
561 case mx_TERMIOS_CMD_NORMAL:
562 rv = (tcsetattr(fileno(mx_tty_fp), TCSADRAIN, &tiosep->tiose_state
563 ) == 0);
564 break;
565 case mx_TERMIOS_CMD_PASSWORD:
566 tiosep->tiose_state.c_iflag &= ~(ISTRIP);
567 tiosep->tiose_state.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
568 rv = (tcsetattr(fileno(mx_tty_fp), TCSADRAIN, &tiosep->tiose_state
569 ) == 0);
570 break;
571 case mx_TERMIOS_CMD_RAW:
572 case mx_TERMIOS_CMD_RAW_TIMEOUT:
573 a1 = MIN(U8_MAX, a1);
574 tiosep->tiose_a1 = S(u8,a1);
575 if((tiosc & mx__TERMIOS_CMD_ACT_MASK) == mx_TERMIOS_CMD_RAW){
576 tiosep->tiose_state.c_cc[VMIN] = S(u8,a1);
577 tiosep->tiose_state.c_cc[VTIME] = 0;
578 }else{
579 tiosep->tiose_state.c_cc[VMIN] = 0;
580 tiosep->tiose_state.c_cc[VTIME] = S(u8,a1);
582 tiosep->tiose_state.c_iflag &= ~(ISTRIP | IGNCR | IXON | IXOFF);
583 tiosep->tiose_state.c_lflag &= ~(ECHO /*| ECHOE | ECHONL */|
584 ICANON | IEXTEN | ISIG);
585 rv = (tcsetattr(fileno(mx_tty_fp), TCSADRAIN, &tiosep->tiose_state
586 ) == 0);
587 break;
590 if(/*!(tiosc & mx__TERMIOS_CMD_CTL_MASK) &&*/ tiosep->tiose_suspended &&
591 tiosep->tiose_on_state_change != NIL)
592 (*tiosep->tiose_on_state_change)(tiosep->tiose_osc_cookie,
593 mx_TERMIOS_STATE_RESUME, 0);
595 /* XXX if(rv)*/{
596 tiosep->tiose_suspended = FAL0;
599 if(tiosep_2free != NIL)
600 tiosep_2free->tiose_prev = a_termios_g.tiosg_pend_free;
601 else
602 tiosep_2free = a_termios_g.tiosg_pend_free;
603 a_termios_g.tiosg_pend_free = NIL;
605 mx_sigs_all_rele();
607 jleave:
608 while((tiosep = tiosep_2free) != NIL){
609 tiosep_2free = tiosep->tiose_prev;
610 su_FREE(tiosep);
613 NYD_OU;
614 return rv;
617 #include "su/code-ou.h"
618 /* s-it-mode */