1 /* Terminal control for outputting styled text to a terminal.
2 Copyright (C) 2006-2008, 2017, 2019-2024 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2019.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
21 #include "term-style-control.h"
23 /* Set to 1 to get debugging output regarding signals. */
24 #define DEBUG_SIGNALS 0
36 # if !defined NOFLSH /* QNX */
41 # include <sys/stat.h>
44 #include "fatal-signal.h"
45 #include "sig-handler.h"
46 #include "full-write.h"
47 #include "same-inode.h"
50 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
53 /* ============================ EINTR handling ============================ */
55 /* EINTR handling for tcgetattr(), tcsetattr().
56 These functions can return -1/EINTR even when we don't have any
57 signal handlers set up, namely when we get interrupted via SIGSTOP. */
62 nonintr_tcgetattr (int fd
, struct termios
*tcp
)
67 retval
= tcgetattr (fd
, tcp
);
68 while (retval
< 0 && errno
== EINTR
);
74 nonintr_tcsetattr (int fd
, int flush_mode
, const struct termios
*tcp
)
79 retval
= tcsetattr (fd
, flush_mode
, tcp
);
80 while (retval
< 0 && errno
== EINTR
);
88 /* ========================== Logging primitives ========================== */
90 /* We need logging, especially for the signal handling, because
91 - Debugging through gdb is hardly possible, because gdb produces output
92 by itself and interferes with the process states.
93 - strace is buggy when it comes to SIGTSTP handling: By default, it
94 sends the process a SIGSTOP signal instead of SIGTSTP. It supports
95 an option '-D -I4' to mitigate this, though. Also, race conditions
96 appear with different probability with and without strace.
97 fprintf(stderr) is not possible within async-safe code, because fprintf()
98 may invoke malloc(). */
102 /* Log a simple message. */
103 static _GL_ASYNC_SAFE
void
104 log_message (const char *message
)
106 full_write (STDERR_FILENO
, message
, strlen (message
));
111 # define log_message(message)
115 #if HAVE_TCGETATTR || DEBUG_SIGNALS
117 /* Async-safe implementation of sprintf (str, "%d", n). */
118 static _GL_ASYNC_SAFE
void
119 sprintf_integer (char *str
, int x
)
129 y
= (unsigned int) (-1 - x
) + 1;
134 p
= buf
+ sizeof (buf
);
137 *--p
= '0' + (y
% 10);
141 n
= buf
+ sizeof (buf
) - p
;
150 /* Async-safe conversion of errno value to string. */
151 static _GL_ASYNC_SAFE
void
152 simple_errno_string (char *str
, int errnum
)
156 case EBADF
: strcpy (str
, "EBADF"); break;
157 case EINTR
: strcpy (str
, "EINTR"); break;
158 case EINVAL
: strcpy (str
, "EINVAL"); break;
159 case EIO
: strcpy (str
, "EIO"); break;
160 case ENOTTY
: strcpy (str
, "ENOTTY"); break;
161 default: sprintf_integer (str
, errnum
); break;
169 /* Async-safe conversion of signal number to name. */
170 static _GL_ASYNC_SAFE
void
171 simple_signal_string (char *str
, int sig
)
175 /* Fatal signals (see fatal-signal.c). */
177 case SIGINT
: strcpy (str
, "SIGINT"); break;
180 case SIGTERM
: strcpy (str
, "SIGTERM"); break;
183 case SIGHUP
: strcpy (str
, "SIGHUP"); break;
186 case SIGPIPE
: strcpy (str
, "SIGPIPE"); break;
189 case SIGXCPU
: strcpy (str
, "SIGXCPU"); break;
192 case SIGXFSZ
: strcpy (str
, "SIGXFSZ"); break;
195 case SIGBREAK
: strcpy (str
, "SIGBREAK"); break;
197 /* Stopping signals. */
199 case SIGTSTP
: strcpy (str
, "SIGTSTP"); break;
202 case SIGTTIN
: strcpy (str
, "SIGTTIN"); break;
205 case SIGTTOU
: strcpy (str
, "SIGTTOU"); break;
207 /* Continuing signals. */
209 case SIGCONT
: strcpy (str
, "SIGCONT"); break;
211 default: sprintf_integer (str
, sig
); break;
215 /* Emit a message that a given signal handler is being run. */
216 static _GL_ASYNC_SAFE
void
217 log_signal_handler_called (int sig
)
220 strcpy (message
, "Signal handler for signal ");
221 simple_signal_string (message
+ strlen (message
), sig
);
222 strcat (message
, " called.\n");
223 log_message (message
);
229 log_signal_handler_called (_GL_UNUSED
int sig
)
236 /* ============================ Signal handling ============================ */
238 /* There are several situations which can cause garbled output on the terminal's
240 (1) When the program calls exit() after calling flush_to_current_style,
241 the program would terminate and leave the terminal in a non-default
243 (2) When the program is interrupted through a fatal signal, the terminal
244 would be left in a non-default state.
245 (3) When the program is stopped through a stopping signal, the terminal
246 would be left (for temporary use by other programs) in a non-default
248 (4) When a foreground process receives a SIGINT, the kernel(!) prints '^C'.
249 On Linux, the place where this happens is
250 linux-5.0/drivers/tty/n_tty.c:713..730
251 within a call sequence
252 n_tty_receive_signal_char (n_tty.c:1245..1246)
253 -> commit_echoes (n_tty.c:792)
254 -> __process_echoes (n_tty.c:713..730).
255 (5) When a signal is sent, the output buffer is cleared.
256 On Linux, this output buffer consists of the "echo buffer" in the tty
257 and the "output buffer" in the driver. The place where this happens is
258 linux-5.0/drivers/tty/n_tty.c:1133..1140
260 isig (n_tty.c:1133..1140).
262 How do we mitigate these problems?
263 (1) We install an exit handler that restores the terminal to the default
265 (2) If tty_control is TTYCTL_PARTIAL or TTYCTL_FULL:
266 For some of the fatal signals (see gnulib's 'fatal-signal' module for
267 the precise list), we install a handler that attempts to restore the
268 terminal to the default state. Since the terminal may be in the middle
269 of outputting an escape sequence at this point, the first escape
270 sequence emitted from this handler may have no effect and produce
271 garbled characters instead. Therefore the handler outputs the cleanup
273 For the other fatal signals, we don't do anything.
274 (3) If tty_control is TTYCTL_PARTIAL or TTYCTL_FULL:
275 For some of the stopping signals (SIGTSTP, SIGTTIN, SIGTTOU), we install
276 a handler that attempts to restore the terminal to the default state.
277 For SIGCONT, we install a handler that does the opposite: it puts the
278 terminal into the desired state again.
279 For SIGSTOP, we cannot do anything.
280 (4) If tty_control is TTYCTL_FULL:
281 The kernel's action depends on L_ECHO(tty) and L_ISIG(tty), that is, on
282 the local modes of the tty (see
283 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>
284 section 11.2.5). We don't want to change L_ISIG; hence we change L_ECHO.
285 So, we disable the ECHO local flag of the tty; the equivalent command is
287 (5) If tty_control is TTYCTL_FULL:
288 The kernel's action depends on !L_NOFLSH(tty), that is, again on the
289 local modes of the tty (see
290 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>
291 section 11.2.5). So, we enable the NOFLSH local flag of the tty; the
292 equivalent command is 'stty noflsh'.
293 For terminals with a baud rate < 9600 this is suboptimal. For this case
294 - where the traditional flushing behaviour makes sense - we would use a
295 technique that involves tcdrain(), TIOCOUTQ, and usleep() when it is OK
298 Regarding (4) and (5), there is a complication: Changing the local modes is
299 done through tcsetattr(). However, when the process is put into the
300 background, tcsetattr() does not operate the same way as when the process is
301 running in the foreground.
302 To test this kind of behaviour, use the 'color-filter' example like this:
303 $ yes | ./filter '.*'
306 We have three possible implementation options:
307 * If we don't ignore the signal SIGTTOU:
308 If the TOSTOP bit in the terminal's local mode is clear (command
309 equivalent: 'stty -tostop') and the process is put into the background,
310 normal output would continue (per POSIX
311 <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>
312 section 11.2.5) but tcsetattr() calls would cause it to stop due to
313 a SIGTTOU signal (per POSIX
314 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html>).
315 Thus, the program would behave differently with term-style-control than
317 * If we ignore the signal SIGTTOU when the TOSTOP bit in the terminal's
318 local mode is clear (i.e. when (tc.c_lflag & TOSTOP) == 0):
319 The tcsetattr() calls do not stop the process, but they don't have the
321 On Linux, when I put the process into the background and then kill it with
322 signal SIGINT, I can see that the last operation on the terminal settings
323 (as shown by 'strace') is
324 ioctl(1, TCSETSW, {B38400 opost isig icanon echo ...}) = 0
325 and yet, once the process is terminated, the terminal settings contain
327 * Don't call tcsetattr() if the process is not in the foreground.
328 This approach produces reliable results.
330 Blocking some signals while a non-default style is active is *not* useful:
331 - It does not help against (1), since exit() is not a signal.
332 - Signal handlers are the better approach against (2) and (3).
333 - It does not help against (4) and (5), because the kernel's actions happen
334 outside the process. */
335 #define BLOCK_SIGNALS_DURING_NON_DEFAULT_STYLE_OUTPUT 0
337 /* File descriptor of the currently active 'struct term_style_controller' and
338 'struct term_style_user_data'. */
339 static int volatile term_fd
= -1;
343 /* Status of the process group of term_fd. */
346 PGRP_UNKNOWN
= 0, /* term_fd < 0. Unknown status. */
347 PGRP_NO_TTY
, /* term_fd >= 0 but is not connected to a tty. */
348 PGRP_IN_FOREGROUND
, /* term_fd >= 0 is a tty. This process is running in
350 PGRP_IN_BACKGROUND
/* term_fd >= 0 is a tty. This process is running in
353 static pgrp_status_t
volatile pgrp_status
= PGRP_UNKNOWN
;
355 /* Update pgrp_status, depending on term_fd. */
356 static _GL_ASYNC_SAFE
void
357 update_pgrp_status (void)
362 pgrp_status
= PGRP_UNKNOWN
;
363 log_message ("pgrp_status = PGRP_UNKNOWN\n");
367 pid_t p
= tcgetpgrp (fd
);
370 pgrp_status
= PGRP_NO_TTY
;
371 log_message ("pgrp_status = PGRP_NO_TTY\n");
375 /* getpgrp () changes when the process gets put into the background
376 by a shell that implements job control. */
379 pgrp_status
= PGRP_IN_FOREGROUND
;
380 log_message ("pgrp_status = PGRP_IN_FOREGROUND\n");
384 pgrp_status
= PGRP_IN_BACKGROUND
;
385 log_message ("pgrp_status = PGRP_IN_BACKGROUND\n");
393 # define update_pgrp_status()
397 /* Controller and its user_data that contain information about how to do
399 static const struct term_style_controller
* volatile active_controller
;
400 static struct term_style_user_data
* volatile active_user_data
;
402 /* The 'struct term_style_control_data' embedded in active_user_data.
404 (active_controller != NULL
405 ? active_controller->get_control_data (active_user_data)
407 static struct term_style_control_data
* volatile active_control_data
;
409 /* The fd contained in active_control_data.
411 (active_controller != NULL
412 ? active_control_data->fd
414 static int volatile active_fd
= -1;
416 /* The exit handler. */
418 atexit_handler (void)
420 /* Only do something while some output was started but not completed. */
421 if (active_controller
!= NULL
)
423 active_controller
->restore (active_user_data
);
424 deactivate_term_non_default_mode (active_controller
, active_user_data
);
425 #if 0 /* not needed */
426 deactivate_term_style_controller (active_controller
, active_user_data
);
433 /* Return a failure message after tcsetattr() failed. */
434 static _GL_ASYNC_SAFE
void
435 tcsetattr_failed (char message
[100], const char *caller
)
438 strcpy (message
, caller
);
439 strcat (message
, ": tcsetattr(fd=");
440 sprintf_integer (message
+ strlen (message
), active_fd
);
441 strcat (message
, ") failed, errno=");
442 simple_errno_string (message
+ strlen (message
), errnum
);
443 strcat (message
, "\n");
446 /* True when orig_lflag represents the original tc.c_lflag. */
447 static bool volatile orig_lflag_set
;
448 static tcflag_t
volatile orig_lflag
;
450 /* Modifies the tty's local mode, preparing for non-default terminal state.
451 Used only when the active_control_data's tty_control is TTYCTL_FULL. */
452 static _GL_ASYNC_SAFE
void
453 clobber_local_mode (void)
455 /* Here, active_fd == term_fd. */
456 if (pgrp_status
== PGRP_IN_FOREGROUND
)
459 if (nonintr_tcgetattr (active_fd
, &tc
) >= 0)
462 orig_lflag
= tc
.c_lflag
;
463 /* Set orig_lflag_set to true before actually modifying the tty's
464 local mode, because restore_local_mode does nothing if
465 orig_lflag_set is false. */
466 orig_lflag_set
= true;
468 tc
.c_lflag
|= NOFLSH
;
469 if (nonintr_tcsetattr (active_fd
, TCSANOW
, &tc
) < 0)
471 /* Since tcsetattr failed, restore_local_mode does not need to
472 restore anything. Set orig_lflag_set to false to indicate
474 orig_lflag_set
= false;
477 tcsetattr_failed (message
,
478 "term-style-control:clobber_local_mode");
479 full_write (STDERR_FILENO
, message
, strlen (message
));
486 /* Modifies the tty's local mode, once the terminal is back to the default state.
487 Returns true if ECHO was turned off.
488 Used only when the active_control_data's tty_control is TTYCTL_FULL. */
489 static _GL_ASYNC_SAFE
bool
490 restore_local_mode (void)
492 /* Here, active_fd == term_fd. */
493 bool echo_was_off
= false;
494 /* Nothing to do if !orig_lflag_set. */
498 if (nonintr_tcgetattr (active_fd
, &tc
) >= 0)
500 echo_was_off
= (tc
.c_lflag
& ECHO
) == 0;
501 tc
.c_lflag
= orig_lflag
;
502 if (nonintr_tcsetattr (active_fd
, TCSADRAIN
, &tc
) < 0)
505 tcsetattr_failed (message
,
506 "term-style-control:restore_local_mode");
507 full_write (STDERR_FILENO
, message
, strlen (message
));
510 orig_lflag_set
= false;
519 /* The list of signals whose default behaviour is to stop or continue the
521 static int const job_control_signals
[] =
538 # define num_job_control_signals (SIZEOF (job_control_signals) - 1)
542 /* The following signals are relevant because they output escape sequences to
546 - continuing signals (SIGCONT). */
548 static sigset_t relevant_signal_set
;
549 static bool relevant_signal_set_initialized
= false;
552 init_relevant_signal_set ()
554 if (!relevant_signal_set_initialized
)
556 int fatal_signals
[64];
557 size_t num_fatal_signals
;
560 num_fatal_signals
= get_fatal_signals (fatal_signals
);
562 sigemptyset (&relevant_signal_set
);
563 for (i
= 0; i
< num_fatal_signals
; i
++)
564 sigaddset (&relevant_signal_set
, fatal_signals
[i
]);
566 for (i
= 0; i
< num_job_control_signals
; i
++)
567 sigaddset (&relevant_signal_set
, job_control_signals
[i
]);
570 relevant_signal_set_initialized
= true;
574 /* Temporarily delay the relevant signals. */
575 static _GL_ASYNC_SAFE
inline void
576 block_relevant_signals ()
578 /* The caller must ensure that init_relevant_signal_set () was already
580 if (!relevant_signal_set_initialized
)
583 sigprocmask (SIG_BLOCK
, &relevant_signal_set
, NULL
);
586 /* Stop delaying the relevant signals. */
587 static _GL_ASYNC_SAFE
inline void
588 unblock_relevant_signals ()
590 sigprocmask (SIG_UNBLOCK
, &relevant_signal_set
, NULL
);
595 /* Determines whether a signal is ignored. */
596 static _GL_ASYNC_SAFE
bool
599 struct sigaction action
;
601 return (sigaction (sig
, NULL
, &action
) >= 0
602 && get_handler (&action
) == SIG_IGN
);
609 /* Write the same signal marker that the kernel would have printed if ECHO had
610 been turned on. See (4) above.
611 This is a makeshift and is not perfect:
612 - When stderr refers to a different target than active_control_data->fd,
613 it is too hairy to write the signal marker.
614 - In some cases, when the signal was generated right before and delivered
615 right after a clobber_local_mode invocation, the result is that the
616 marker appears twice, e.g. ^C^C. This occurs only with a small
618 - In some cases, when the signal was generated right before and delivered
619 right after a restore_local_mode invocation, the result is that the
620 marker does not appear at all. This occurs only with a small
622 To test this kind of behaviour, use the 'test-term-style-control-yes' example
624 $ ./test-term-style-control-yes
626 static _GL_ASYNC_SAFE
void
627 show_signal_marker (int sig
)
629 /* Write to stderr, not to active_control_data->fd, because
630 active_control_data->fd is often logged or used with 'less -R'. */
631 if (active_controller
!= NULL
&& active_control_data
->same_as_stderr
)
634 /* The kernel's action when the user presses the INTR key. */
636 full_write (STDERR_FILENO
, "^C", 2); break;
637 /* The kernel's action when the user presses the SUSP key. */
639 full_write (STDERR_FILENO
, "^Z", 2); break;
640 /* The kernel's action when the user presses the QUIT key. */
642 full_write (STDERR_FILENO
, "^\\", 2); break;
649 /* The main code of the signal handler for fatal signals and stopping signals.
651 static _GL_ASYNC_SAFE
void
652 fatal_or_stopping_signal_handler (int sig
)
655 bool echo_was_off
= false;
657 /* Only do something while some output was interrupted. */
658 if (active_controller
!= NULL
659 && active_control_data
->tty_control
!= TTYCTL_NONE
)
663 /* Block the relevant signals. This is needed, because the output
664 of escape sequences below (usually through tputs invocations) is
666 block_relevant_signals ();
668 /* Restore the terminal to the default state. */
669 for (i
= 0; i
< 2; i
++)
670 active_controller
->async_restore (active_user_data
);
672 if (active_control_data
->tty_control
== TTYCTL_FULL
)
674 /* Restore the local mode, once the escape sequences output above
675 have reached their destination. */
676 echo_was_off
= restore_local_mode ();
680 /* Unblock the relevant signals. */
681 unblock_relevant_signals ();
686 show_signal_marker (sig
);
690 /* The signal handler for fatal signals.
692 static _GL_ASYNC_SAFE
void
693 fatal_signal_handler (int sig
)
695 log_signal_handler_called (sig
);
696 fatal_or_stopping_signal_handler (sig
);
701 /* The signal handler for stopping signals.
703 static _GL_ASYNC_SAFE
void
704 stopping_signal_handler (int sig
)
706 int saved_errno
= errno
;
708 log_signal_handler_called (sig
);
709 fatal_or_stopping_signal_handler (sig
);
711 /* Now execute the signal's default action.
712 We reinstall the handler later, during the SIGCONT handler. */
714 struct sigaction action
;
715 action
.sa_handler
= SIG_DFL
;
716 action
.sa_flags
= SA_NODEFER
;
717 sigemptyset (&action
.sa_mask
);
718 sigaction (sig
, &action
, NULL
);
724 /* The signal handler for SIGCONT.
726 static _GL_ASYNC_SAFE
void
727 continuing_signal_handler (int sigcont
)
729 int saved_errno
= errno
;
731 log_signal_handler_called (sigcont
);
732 update_pgrp_status ();
733 /* Only do something while some output was interrupted. */
734 if (active_controller
!= NULL
735 && active_control_data
->tty_control
!= TTYCTL_NONE
)
737 /* Reinstall the signals handlers removed in stopping_signal_handler. */
741 for (i
= 0; i
< num_job_control_signals
; i
++)
743 int sig
= job_control_signals
[i
];
745 if (sig
!= SIGCONT
&& !is_ignored (sig
))
747 struct sigaction action
;
748 action
.sa_handler
= &stopping_signal_handler
;
749 /* If we get a stopping or continuing signal while executing
750 stopping_signal_handler or continuing_signal_handler, enter
751 it recursively, since it is reentrant.
752 Hence no SA_RESETHAND. */
753 action
.sa_flags
= SA_NODEFER
;
754 sigemptyset (&action
.sa_mask
);
755 sigaction (sig
, &action
, NULL
);
760 /* Block the relevant signals. This is needed, because the output of
761 escape sequences done inside the async_set_attributes_from_default
762 call below is not reentrant. */
763 block_relevant_signals ();
766 if (active_control_data
->tty_control
== TTYCTL_FULL
)
768 /* Modify the local mode. */
769 clobber_local_mode ();
772 /* Set the terminal attributes. */
773 active_controller
->async_set_attributes_from_default (active_user_data
);
775 /* Unblock the relevant signals. */
776 unblock_relevant_signals ();
782 /* Ensure the signal handlers are installed.
783 Once they are installed, we leave them installed. It's not worth
784 installing and uninstalling them each time we switch the terminal to a
785 non-default state and back; instead we set active_controller to tell the
786 signal handler whether it has something to do or not. */
789 ensure_continuing_signal_handler (void)
791 static bool signal_handler_installed
= false;
793 if (!signal_handler_installed
)
796 struct sigaction action
;
797 action
.sa_handler
= &continuing_signal_handler
;
798 /* If we get a stopping or continuing signal while executing
799 continuing_signal_handler, enter it recursively, since it is
800 reentrant. Hence no SA_RESETHAND. */
801 action
.sa_flags
= SA_NODEFER
;
802 sigemptyset (&action
.sa_mask
);
803 sigaction (sig
, &action
, NULL
);
805 signal_handler_installed
= true;
812 ensure_other_signal_handlers (void)
814 static bool signal_handlers_installed
= false;
816 if (!signal_handlers_installed
)
818 /* Install the handlers for the fatal signals. */
819 if (at_fatal_signal (fatal_signal_handler
) < 0)
824 /* Install the handlers for the stopping and continuing signals. */
828 for (i
= 0; i
< num_job_control_signals
; i
++)
830 int sig
= job_control_signals
[i
];
833 /* Already handled in ensure_continuing_signal_handler. */
835 else if (!is_ignored (sig
))
837 struct sigaction action
;
838 action
.sa_handler
= &stopping_signal_handler
;
839 /* If we get a stopping or continuing signal while executing
840 stopping_signal_handler, enter it recursively, since it is
841 reentrant. Hence no SA_RESETHAND. */
842 action
.sa_flags
= SA_NODEFER
;
843 sigemptyset (&action
.sa_mask
);
844 sigaction (sig
, &action
, NULL
);
849 fprintf (stderr
, "Signal %d is ignored. Not installing a handler!\n",
859 signal_handlers_installed
= true;
864 /* ============================== Public API ============================== */
867 activate_term_non_default_mode (const struct term_style_controller
*controller
,
868 struct term_style_user_data
*user_data
)
870 struct term_style_control_data
*control_data
=
871 controller
->get_control_data (user_data
);
873 if (!control_data
->non_default_active
)
875 if (control_data
->tty_control
!= TTYCTL_NONE
)
876 ensure_other_signal_handlers ();
878 #if BLOCK_SIGNALS_DURING_NON_DEFAULT_STYLE_OUTPUT
879 /* Block fatal signals, so that a SIGINT or similar doesn't interrupt
880 us without the possibility of restoring the terminal's state.
881 Likewise for SIGTSTP etc. */
882 block_relevant_signals ();
885 /* Enable the exit handler for restoring the terminal's state,
886 and make the signal handlers effective. */
887 if (active_controller
!= NULL
)
889 /* We can't support two active controllers with non-default
890 attributes at the same time. */
893 /* The uses of 'volatile' (and ISO C 99 section 5.1.2.3.(5)) ensure that
894 we set active_controller to a non-NULL value only after the memory
895 locations active_user_data, active_control_data, active_fd have been
897 active_fd
= control_data
->fd
;
898 active_control_data
= control_data
;
899 active_user_data
= user_data
;
900 active_controller
= controller
;
903 /* Now that the signal handlers are effective, modify the tty. */
904 if (active_control_data
->tty_control
== TTYCTL_FULL
)
906 /* Modify the local mode. */
907 clobber_local_mode ();
911 control_data
->non_default_active
= true;
916 deactivate_term_non_default_mode (const struct term_style_controller
*controller
,
917 struct term_style_user_data
*user_data
)
919 struct term_style_control_data
*control_data
=
920 controller
->get_control_data (user_data
);
922 if (control_data
->non_default_active
)
925 /* Before we make the signal handlers ineffective, modify the tty. */
926 if (active_control_data
->tty_control
== TTYCTL_FULL
)
928 /* Restore the local mode, once the tputs calls from out_attr_change
929 have reached their destination. */
930 restore_local_mode ();
934 /* Disable the exit handler, and make the signal handlers ineffective. */
935 /* The uses of 'volatile' (and ISO C 99 section 5.1.2.3.(5)) ensure that
936 we reset active_user_data, active_control_data, active_fd only after
937 the memory location active_controller has been cleared. */
938 active_controller
= NULL
;
939 active_user_data
= NULL
;
940 active_control_data
= NULL
;
943 #if BLOCK_SIGNALS_DURING_NON_DEFAULT_STYLE_OUTPUT
944 /* Unblock the relevant signals. */
945 unblock_relevant_signals ();
948 control_data
->non_default_active
= false;
953 activate_term_style_controller (const struct term_style_controller
*controller
,
954 struct term_style_user_data
*user_data
,
955 int fd
, ttyctl_t tty_control
)
957 struct term_style_control_data
*control_data
=
958 controller
->get_control_data (user_data
);
960 control_data
->fd
= fd
;
962 /* Prepare tty control. */
963 if (tty_control
== TTYCTL_AUTO
)
964 tty_control
= TTYCTL_FULL
;
965 control_data
->tty_control
= tty_control
;
966 if (control_data
->tty_control
!= TTYCTL_NONE
)
967 init_relevant_signal_set ();
969 if (control_data
->tty_control
== TTYCTL_FULL
)
971 struct stat statbuf1
;
972 struct stat statbuf2
;
973 if (fd
== STDERR_FILENO
974 || (fstat (fd
, &statbuf1
) >= 0
975 && fstat (STDERR_FILENO
, &statbuf2
) >= 0
976 && psame_inode (&statbuf1
, &statbuf2
)))
977 control_data
->same_as_stderr
= true;
979 control_data
->same_as_stderr
= false;
982 /* This value is actually not used. */
983 control_data
->same_as_stderr
= false;
986 control_data
->non_default_active
= false;
988 /* Start keeping track of the process group status. */
991 ensure_continuing_signal_handler ();
993 update_pgrp_status ();
995 /* Register an exit handler. */
997 static bool registered
= false;
1000 atexit (atexit_handler
);
1007 deactivate_term_style_controller (const struct term_style_controller
*controller
,
1008 struct term_style_user_data
*user_data
)
1010 struct term_style_control_data
*control_data
=
1011 controller
->get_control_data (user_data
);
1013 /* Verify that the non-default attributes mode is turned off. */
1014 if (control_data
->non_default_active
)
1018 update_pgrp_status ();