diff options
| author | David Faulkner <[email protected]> | 2026-08-07 23:40:47 -0500 |
|---|---|---|
| committer | David Faulkner <[email protected]> | 2026-08-07 23:40:47 -0500 |
| commit | b3e9e62599532050fc776c5e8f076915b56c2235 (patch) | |
| tree | af252346106a61b18cc6fc6fdbd32e962d096f1c /termin.c | |
Import official C23 code examples for Modern C (Jens Gustedt, 2024)HEADupstream-importmain
- Add official C source files, Makefile, c23-fallback.h, and LICENSE
- Update README.md with study mirror notice
Diffstat (limited to 'termin.c')
| -rw-r--r-- | termin.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/termin.c b/termin.c new file mode 100644 index 0000000..5de89da --- /dev/null +++ b/termin.c @@ -0,0 +1,97 @@ +#include "termin.h" +#include "c23-fallback.h" +#include <termios.h> +#include <stdio.h> +#include <stdbool.h> +#ifndef __STDC_NO_THREADS__ +# include <threads.h> +#endif +#include <ctype.h> +#include <string.h> + +/* Store the flags as they were set before termin_unbuffered. */ +static tcflag_t termin_echo; + +/* The flags that we manipulate. */ +#define TERMIN_FLAGS (ECHO | ECHONL | ICANON) + +void termin_reset(void) { + struct termios term; + tcgetattr(0, &term); + term.c_lflag |= termin_echo; + tcsetattr(0, TCSAFLUSH, &term); +} + +void termin_unbuffered(void) { + // have stdin unbuffered on stdio level + setvbuf(stdin, 0, _IONBF, 0); + // store the terminal settings with respect to the flags + struct termios term; + tcgetattr(0, &term); + termin_echo = term.c_lflag & TERMIN_FLAGS; + // install exit handlers + atexit(termin_reset); + at_quick_exit(termin_reset); + // change the terminal settings to raw mode + term.c_lflag &= ~TERMIN_FLAGS; + tcsetattr(0, TCSAFLUSH, &term); +} + +static unsigned minc = 0; +static unsigned maxc = UCHAR_MAX; + +static +void term_init(void) { + while (!termin_trans[minc]) ++minc; + while (!termin_trans[maxc]) --maxc; +} + +#ifndef __STDC_NO_THREADS__ +static once_flag term_once = ONCE_FLAG_INIT; +#endif + +static +bool termin_read_csi(size_t len, char command[len]) { + for (char *p = command, *stop = command+len-1; p < stop; ++p) { + int c = getchar(); + // catch all: EOF, 0, control characters + if (c < ' ') return false; + p[0] = c; + if ('@' <= c && c <= '~') { + p[1] = 0; + return true; + } + } + return false; +} + +char const* termin_read_esc(size_t len, char command[len]) { + command[1] = getchar(); + switch (command[1]) { + case '[': + return + termin_read_csi(len-2, command+2) + ? command + : 0; + case 'N': + case 'O': + case 'Z': + case '%': + command[2] = getchar(); + command[3] = 0; + return command; + default: + ungetc(command[1], stdin); + return nullptr; + } +} + +char termin_translate(char const* command) { + call_once(&term_once, term_init); + for (unsigned c = minc; c <= maxc; ++c) { + if (termin_trans[c] && !strcmp(command, termin_trans[c])) { + return c; + } + } + return 0; +} |
