1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
/* Terminal control for outputting styled text to a terminal.
Copyright (C) 2019-2021 Free Software Foundation, Inc.
Written by Bruno Haible <bruno@clisp.org>, 2019.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef _TERM_STYLE_CONTROL_H
#define _TERM_STYLE_CONTROL_H
#include <stdbool.h>
/* The user of this file will define a macro 'term_style_user_data', such that
'struct term_style_user_data' is a user-defined struct. */
/* The amount of control to take over the underlying tty in order to avoid
garbled output on the screen, due to interleaved output of escape sequences
and output from the kernel (such as when the kernel echoes user's input
or when the kernel prints '^C' after the user pressed Ctrl-C). */
typedef enum
{
TTYCTL_AUTO = 0, /* Automatic best-possible choice. */
TTYCTL_NONE, /* No control.
Result: Garbled output can occur, and the terminal can
be left in any state when the program is interrupted. */
TTYCTL_PARTIAL, /* Signal handling.
Result: Garbled output can occur, but the terminal will
be left in the default state when the program is
interrupted. */
TTYCTL_FULL /* Signal handling and disabling echo and flush-upon-signal.
Result: No garbled output, and the the terminal will
be left in the default state when the program is
interrupted. */
} ttyctl_t;
/* This struct contains data, used by implementation of this module.
You should not access the members of this struct; they may be renamed or
removed without notice. */
struct term_style_control_data
{
int volatile fd;
ttyctl_t volatile tty_control; /* Signal handling and tty control. */
#if HAVE_TCGETATTR
bool volatile same_as_stderr;
#endif
bool non_default_active; /* True if activate_term_non_default_mode()
is in effect. */
};
/* Forward declaration. */
struct term_style_user_data;
/* This struct contains function pointers. You implement these functions
in your application; this module invokes them when it needs to. */
struct term_style_controller
{
/* This function returns a pointer to the embedded
'struct term_style_control_data' contained in a
'struct term_style_user_data'. */
struct term_style_control_data * (*get_control_data) (struct term_style_user_data *);
/* This function brings the terminal's state back to the default state
(no styling attributes set). It is invoked when the process terminates
through exit(). */
void (*restore) (struct term_style_user_data *);
/* This function brings the terminal's state back to the default state
(no styling attributes set). It is async-safe (see gnulib-common.m4 for
the precise definition). It is invoked when the process receives a fatal
or stopping signal. */
_GL_ASYNC_SAFE void (*async_restore) (struct term_style_user_data *);
/* This function brings the terminal's state, from the default state, back
to the state where it has the desired attributes set. It is async-safe
(see gnulib-common.m4 for the precise definition). It is invoked when
the process receives a SIGCONT signal. */
_GL_ASYNC_SAFE void (*async_set_attributes_from_default) (struct term_style_user_data *);
};
#ifdef __cplusplus
extern "C" {
#endif
/* This module is used as follows:
1. You fill a 'struct term_style_controller' with function pointers.
You create a 'struct term_style_user_data' that contains, among other
members, a 'struct term_style_control_data'.
You will pass these two objects to all API functions below.
2. You call activate_term_style_controller to activate this controller.
Activation of the controller is the prerequisite for activating
the non-default mode, which in turn is the prerequisite for changing
the terminal's attributes.
When you are done with the styled output, you may deactivate the
controller. This is not required before exiting the program, but is
required before activating a different controller.
You cannot have more than one controller activated at the same time.
3. Once the controller is activated, you may turn on the non-default mode.
The non-default mode is the prerequisite for changing the terminal's
attributes. Once the terminal's attributes are in the default state
again, you may turn off the non-default mode again.
In other words:
- In the default mode, the terminal's attributes MUST be in the default
state; no styled output is possible.
- In the non-default mode, the terminal's attributes MAY switch among
the default state and other states.
This module exercises a certain amount of control over the terminal
during the non-default mode phases; see above (ttyctl_t) for details.
You may switch between the default and the non-default modes any number
of times.
The idea is that you switch back to the default mode before doing large
amounts of output of unstyled text. However, this is not a requirement:
You may leave the non-default mode turned on all the time until the
the program exits.
4. Once the non-default mode is activated, you may change the attributes
(foreground color, background color, font weight, font posture, underline
decoration, etc.) of the terminal. On Unix, this is typically done by
outputting appropriate escape sequences.
5. Once attributes are set, text output to the terminal will be rendered
with these attributes.
Note: You MUST return the terminal to the default state before outputting
a newline.
*/
/* Activates a controller. The CONTROLLER and its USER_DATA controls the
terminal associated with FD. FD is usually STDOUT_FILENO.
TTY_CONTROL specifies the amount of control to take over the underlying tty.
The effects of this functions are undone by calling
deactivate_term_style_controller.
You cannot have more than one controller activated at the same time.
You must not close FD while the controller is active. */
extern void
activate_term_style_controller (const struct term_style_controller *controller,
struct term_style_user_data *user_data,
int fd, ttyctl_t tty_control);
/* Activates the non-default mode.
CONTROLLER and its USER_DATA must be a currently active controller.
This function fiddles with the signals of the current process and with
the underlying tty, to an extent described by TTY_CONTROL.
This function is idempotent: When you call it twice in a row, the second
invocation does nothing.
The effects of this function are undone by calling
deactivate_term_non_default_mode. */
extern void
activate_term_non_default_mode (const struct term_style_controller *controller,
struct term_style_user_data *user_data);
/* Deactivates the non-default mode.
CONTROLLER and its USER_DATA must be a currently active controller.
This function is idempotent: When you call it twice in a row, the second
invocation does nothing.
Before invoking this function, you must put the terminal's attributes in
the default state. */
extern void
deactivate_term_non_default_mode (const struct term_style_controller *controller,
struct term_style_user_data *user_data);
/* Deactivates a controller.
CONTROLLER and its USER_DATA must be a currently active controller.
Before invoking this function, you must ensure that the non-default mode
is deactivated. */
extern void
deactivate_term_style_controller (const struct term_style_controller *controller,
struct term_style_user_data *user_data);
#ifdef __cplusplus
}
#endif
#endif /* _TERM_STYLE_CONTROL_H */
|