1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2  *@ Terminal attributes and state.
3  *
4  * Copyright (c) 2019 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
5  * SPDX-License-Identifier: ISC
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 #ifndef mx_TERMIOS_H
20 #define mx_TERMIOS_H
21 
22 #include <mx/nail.h>
23 
24 #define mx_HEADER
25 #include <su/code-in.h>
26 
27 struct mx_termios_dimension;
28 
29 enum mx_termios_cmd{
30    /* Throw away the entire stack, and restore normal terminal state.
31     * The outermost level will be regularly shutdown, as via POP.
32     * The state_change handlers of all stack entries will be called.
33     * Further bits may not be set (this is 0) */
34    mx_TERMIOS_CMD_RESET,
35    /* Only when HANDS_OFF is active, only by itself! */
36 /*   mx_TERMIOS_CMD_SET_PGRP = 1u,*/
37    /* Create a (POPable) environment, as necessary change to the given mode.
38     * An environment carries the terminal mode as well as a possibly installed
39     * on_state_change hook; if such environment is reentered, the state change
40     * hook gets called to resume after the mode has been reestablished.
41     * Likewise, if it is left, it gets called to suspend first.
42     * XXX Any state change requires this, only RAW and RAW_TIMEOUT may be
43     * XXX switched back and forth on the same level (otherwise state_change
44     * XXX needs cmd argument, plus plus plus) */
45    mx_TERMIOS_CMD_PUSH = 1u<<1,
46    /* Pop stack and restore the terminal setting active before.
47     * If a hook is installed, it will be called first.
48     * If a mode is given, debug version will assert the stack top matches.
49     * Further bits are ignored */
50    mx_TERMIOS_CMD_POP = 1u<<2,
51    mx__TERMIOS_CMD_CTL_MASK = mx_TERMIOS_CMD_PUSH | mx_TERMIOS_CMD_POP,
52    mx_TERMIOS_CMD_NORMAL = 1u<<3, /* Normal canonical mode */
53    mx_TERMIOS_CMD_PASSWORD = 2u<<3, /* Password input mode */
54    mx_TERMIOS_CMD_RAW = 3u<<3, /* Raw mode, use by-(the given-)byte(s) input */
55    mx_TERMIOS_CMD_RAW_TIMEOUT = 4u<<3, /* Raw mode, use (the given) timeout */
56    mx_TERMIOS_CMD_HANDS_OFF = 5u<<3, /* We do not own the terminal */
57    mx__TERMIOS_CMD_ACT_MASK = 7u<<3
58 };
59 
60 enum mx_termios_setup{
61    mx_TERMIOS_SETUP_STARTUP,
62    mx_TERMIOS_SETUP_TERMSIZE
63 };
64 
65 enum mx_termios_state_change{
66    mx_TERMIOS_STATE_SUSPEND = 1u<<0, /* Need to suspend terminal state */
67    mx_TERMIOS_STATE_RESUME = 1u<<1, /* Need to resume terminal state */
68    mx_TERMIOS_STATE_SIGNAL = 1u<<2, /* Call was caused by a signal */
69    mx_TERMIOS_STATE_JOB_SIGNAL = 1u<<3, /* It was a job signal indeed */
70    /* The environment is being popped.
71     * If it is still active, _STATE_SUSPEND will be set in addition.
72     * For HANDS_OFF handlers this will be called in a RESET even in already
73     * suspended state, so no _STATE_SUSPEND is set, then! */
74    mx_TERMIOS_STATE_POP = 1u<<4
75 };
76 
77 /* tiossc is termios_state_change bitmix, cookie is user argument.
78  * signal is only meaningful when _STATE_SIGNAL is set.
79  * Return value indicates whether level shall be CMD_POPped: it is only
80  * honoured if TERMIOS_STATE_SUSPEND and TERMIOS_STATE_SIGNAL are both set.
81  * TODO This "to-pop" return will vanish in v15, we only need it due to longjmp
82  * TODO and of course it sucks since how many levels does the jump cross?
83  * TODO We do not know except when installing setjmps on each and every level,
84  * TODO but we do not; it is ok for this MUA today, but a real generic solution
85  * TODO in v15 will simply not care for signal jumps at all, they suck more */
86 typedef boole (*mx_termios_on_state_change)(up cookie, u32 tiossc, s32 signal);
87 
88 struct mx_termios_dimension{
89    u32 tiosd_height;
90    /* .tiosd_height might be deduced via terminal speed, in which case this
91     * still is set to the real terminal height */
92    u32 tiosd_real_height;
93    u32 tiosd_width;
94    /* .tiosd_width might be reduces deduced by one if we have no termcap
95     * support or if the terminal cannot write in the last column (without
96     * wrapping), in which case this still is set to the real terminal width */
97    u32 tiosd_real_width;
98 };
99 
100 /* */
101 EXPORT_DATA struct mx_termios_dimension mx_termios_dimen;
102 
103 /* For long iterative output, like `list', tabulator-completion, etc.,
104  * determine the screen width that should be used */
105 #define mx_TERMIOS_WIDTH_OF_LISTS() \
106    (mx_termios_dimen.tiosd_width - (mx_termios_dimen.tiosd_width >> 3))
107 
108 /* Installs signal handlers etc.  Early! */
109 EXPORT void mx_termios_controller_setup(enum mx_termios_setup what);
110 
111 /* Install a state change hook for the current environment,
112  * which will receive cookie as its user argument.
113  * May not be used in and for the top level */
114 EXPORT void mx_termios_on_state_change_set(mx_termios_on_state_change hdl,
115       up cookie);
116 
117 /* tiosc is a bitmix of mx_termios_cmd values.
118  * For _RAW and _RAW_TIMEOUT a1 describes VMIN and VTIME, respectively,
119  * for SET_PGRP it is the PID */
120 EXPORT boole mx_termios_cmd(u32 tiosc, uz a1);
121 #define mx_termios_cmdx(CMD) mx_termios_cmd(CMD, 0)
122 
123 #include <su/code-ou.h>
124 #endif /* mx_TERMIOS_H */
125 /* s-it-mode */
126