For Anon...
This commit is contained in:
commit
7bce39f49b
389
xerminal.h
Executable file
389
xerminal.h
Executable file
@ -0,0 +1,389 @@
|
||||
/// _ _
|
||||
/// __ _____ _ __ _ __ ___ (_)_ __ __ _| |
|
||||
/// \ \/ / _ \ '__| '_ ` _ \| | '_ \ / _` | |
|
||||
/// > < __/ | | | | | | | | | | | (_| | |
|
||||
/// /_/\_\___|_| |_| |_| |_|_|_| |_|\__,_|_|
|
||||
///
|
||||
/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic
|
||||
///
|
||||
/// xolatile@chud.cyou - xerminal - Library containing the full power of VT100 escape sequences or something for TUI programs.
|
||||
///
|
||||
/// This program is free software, free as in freedom and as in free beer, 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 any later version if you wish...
|
||||
///
|
||||
/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied
|
||||
/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License
|
||||
/// for more details, if you dare, it is a lot of text that nobody wants to read...
|
||||
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#define terminal_format_length (sizeof ("\033[-;3-m-\033[0m") - 1)
|
||||
#define terminal_revert_length (sizeof ("\033[H") - 1)
|
||||
#define terminal_cursor_length (sizeof ("\033[---;---H") - 1)
|
||||
|
||||
typedef struct {
|
||||
char * screen;
|
||||
uint screen_width;
|
||||
uint screen_height;
|
||||
|
||||
char format [terminal_format_length + 1];
|
||||
char cursor [terminal_cursor_length + 1];
|
||||
|
||||
bool active;
|
||||
bool signal [signal_count];
|
||||
|
||||
uint character;
|
||||
|
||||
struct termios * old_terminal;
|
||||
struct termios * new_terminal;
|
||||
} terminal_structure;
|
||||
|
||||
static char * terminal_screen_offset (terminal_structure * terminal, uint x, uint y) {
|
||||
return (& terminal->screen [terminal_revert_length + terminal_format_length * (y * terminal->screen_width + x) + 2 * y]);
|
||||
}
|
||||
|
||||
static uint terminal_screen_length (terminal_structure * terminal) {
|
||||
uint constant = terminal_revert_length + terminal_cursor_length + 1;
|
||||
uint variable = terminal_format_length * terminal->screen_height * terminal->screen_width;
|
||||
uint new_line = 2 * (terminal->screen_height - 1);
|
||||
|
||||
return (constant + variable + new_line);
|
||||
}
|
||||
|
||||
static void terminal_screen_dimensions (terminal_structure * terminal) {
|
||||
struct winsize screen_dimension = { 0 };
|
||||
|
||||
uint old_width = terminal->screen_width;
|
||||
uint old_height = terminal->screen_height;
|
||||
|
||||
int status = ioctl (STDOUT_FILENO, TIOCGWINSZ, & screen_dimension);
|
||||
|
||||
fatal_failure (status == -1, "ioctl: Failed to get dimensions.");
|
||||
|
||||
terminal->screen_width = screen_dimension.ws_col;
|
||||
terminal->screen_height = screen_dimension.ws_row;
|
||||
|
||||
if ((old_width != terminal->screen_width) || (old_height != terminal->screen_height)) {
|
||||
if (terminal->screen != null) {
|
||||
terminal->screen = deallocate (terminal->screen);
|
||||
}
|
||||
|
||||
terminal->screen = allocate (terminal_screen_length (terminal));
|
||||
}
|
||||
|
||||
string_copy (& terminal->screen [0], "\033[H");
|
||||
|
||||
for (uint index = 0; index < terminal->screen_height - 1; ++index) {
|
||||
string_copy (& terminal->screen [terminal_revert_length + index * terminal_format_length * terminal->screen_width], "\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
static char * terminal_format_character (terminal_structure * terminal, char character, int colour, int effect) {
|
||||
if (character_is_visible (character) == false) {
|
||||
character = ' ';
|
||||
}
|
||||
|
||||
colour %= colour_count;
|
||||
effect %= effect_count;
|
||||
|
||||
terminal->format [2] = (char) effect + '0';
|
||||
terminal->format [5] = (char) colour + '0';
|
||||
terminal->format [7] = character;
|
||||
|
||||
return (terminal->format);
|
||||
}
|
||||
|
||||
static terminal_structure * terminal_initialize (void) {
|
||||
terminal_structure * terminal = allocate (sizeof (* terminal));
|
||||
|
||||
int status = -1;
|
||||
|
||||
string_copy_limit (terminal->format, "\033[-;3-m-\033[0m", terminal_format_length + 1);
|
||||
string_copy_limit (terminal->cursor, "\033[---;---H", terminal_cursor_length + 1);
|
||||
|
||||
terminal->old_terminal = allocate (sizeof (* terminal->old_terminal));
|
||||
terminal->new_terminal = allocate (sizeof (* terminal->new_terminal));
|
||||
|
||||
terminal_screen_dimensions (terminal);
|
||||
|
||||
status = tcgetattr (STDIN_FILENO, terminal->old_terminal);
|
||||
|
||||
fatal_failure (status == -1, "tcgetattr: Failed to get default attributes.");
|
||||
|
||||
memory_copy (terminal->new_terminal, terminal->old_terminal, sizeof (* terminal->old_terminal));
|
||||
|
||||
terminal->new_terminal->c_cc [VMIN] = (uchar) 0;
|
||||
terminal->new_terminal->c_cc [VTIME] = (uchar) 1;
|
||||
|
||||
terminal->new_terminal->c_iflag &= (uint) ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
terminal->new_terminal->c_oflag &= (uint) ~(OPOST);
|
||||
terminal->new_terminal->c_cflag |= (uint) (CS8);
|
||||
terminal->new_terminal->c_lflag &= (uint) ~(ECHO | ICANON | IEXTEN | ISIG);
|
||||
|
||||
status = tcsetattr (STDIN_FILENO, TCSAFLUSH, terminal->new_terminal);
|
||||
|
||||
fatal_failure (status == -1, "tcsetattr: Failed to set reverse attributes.");
|
||||
|
||||
terminal->active = true;
|
||||
|
||||
show_cursor (false);
|
||||
|
||||
echo_clear ();
|
||||
|
||||
return (terminal);
|
||||
}
|
||||
|
||||
static terminal_structure * terminal_deinitialize (terminal_structure * terminal) {
|
||||
int status = tcsetattr (STDIN_FILENO, TCSAFLUSH, terminal->old_terminal);
|
||||
|
||||
fatal_failure (status == -1, "tcsetattr: Failed to set default attributes.");
|
||||
|
||||
terminal->screen = deallocate (terminal->screen);
|
||||
terminal->old_terminal = deallocate (terminal->old_terminal);
|
||||
terminal->new_terminal = deallocate (terminal->new_terminal);
|
||||
|
||||
echo_clear ();
|
||||
|
||||
show_cursor (true);
|
||||
|
||||
return (deallocate (terminal));
|
||||
}
|
||||
|
||||
static void terminal_synchronize (terminal_structure * terminal) {
|
||||
uint character = 0;
|
||||
|
||||
output (terminal->screen, terminal_screen_length (terminal));
|
||||
|
||||
terminal_screen_dimensions (terminal);
|
||||
|
||||
for (uint index = 0; index < signal_count; ++index) {
|
||||
terminal->signal [index] = false;
|
||||
}
|
||||
|
||||
input (& character, sizeof (character));
|
||||
|
||||
terminal->character = (uint) character;
|
||||
|
||||
if (character == 0x0000001b) {
|
||||
terminal->signal [signal_escape] = true;
|
||||
} else if (character == 0x00415b1b) {
|
||||
terminal->signal [signal_arrow_up] = true;
|
||||
} else if (character == 0x00425b1b) {
|
||||
terminal->signal [signal_arrow_down] = true;
|
||||
} else if (character == 0x00435b1b) {
|
||||
terminal->signal [signal_arrow_right] = true;
|
||||
} else if (character == 0x00445b1b) {
|
||||
terminal->signal [signal_arrow_left] = true;
|
||||
} else if (character == 0x00000020) {
|
||||
terminal->signal [signal_space] = true;
|
||||
} else if (character == 0x0000007f) {
|
||||
terminal->signal [signal_backspace] = true;
|
||||
} else if (character == 0x0000000d) {
|
||||
terminal->signal [signal_return] = true;
|
||||
} else if (character_is_digit ((char) character) == true) {
|
||||
terminal->signal [signal_0 + character - '0'] = true;
|
||||
} else if (character_is_lowercase ((char) character) == true) {
|
||||
terminal->signal [signal_a + character - 'a'] = true;
|
||||
} else if (character_is_uppercase ((char) character) == true) {
|
||||
terminal->signal [signal_a + character - 'A'] = true;
|
||||
terminal->signal [signal_left_shift] = true;
|
||||
terminal->signal [signal_right_shift] = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void terminal_render_cursor (terminal_structure * terminal, uint x, uint y) { /* BROKE IT INTENTIONALLY */
|
||||
string_copy_limit (terminal->cursor + 2, string_align_left (number_to_string (y % 1000 + 1), 3, '0'), 3);
|
||||
string_copy_limit (terminal->cursor + 6, string_align_left (number_to_string (x % 1000 + 1), 3, '0'), 3);
|
||||
|
||||
string_copy_limit (& terminal->screen [terminal_screen_length (terminal) - terminal_cursor_length - 1], terminal->cursor, terminal_cursor_length);
|
||||
}
|
||||
|
||||
static void terminal_render_character (terminal_structure * terminal, char character, uint colour, uint effect, uint x, uint y) {
|
||||
if ((x >= terminal->screen_width) || (y >= terminal->screen_height)) {
|
||||
return;
|
||||
}
|
||||
|
||||
string_copy_limit (terminal_screen_offset (terminal, x, y), terminal_format_character (terminal, character, colour, effect), terminal_format_length);
|
||||
}
|
||||
|
||||
static void terminal_render_toggle (terminal_structure * terminal, bool toggle, uint x, uint y) {
|
||||
const char marker = (toggle == true) ? '+' : '-';
|
||||
const char colour = (toggle == true) ? colour_green : colour_red;
|
||||
|
||||
terminal_render_character (terminal, '[', colour_grey, effect_bold, x + 0, y);
|
||||
terminal_render_character (terminal, marker, colour, effect_bold, x + 1, y);
|
||||
terminal_render_character (terminal, ']', colour_grey, effect_bold, x + 2, y);
|
||||
}
|
||||
|
||||
static void terminal_render_fill_bar (terminal_structure * terminal, uint value, uint limit, char character, uint colour, uint effect, uint x, uint y) {
|
||||
terminal_render_character (terminal, '[', colour_grey, effect_bold, x, y);
|
||||
terminal_render_character (terminal, ']', colour_grey, effect_bold, x + limit + 1, y);
|
||||
|
||||
for (uint index = 0; index < limit; ++index) {
|
||||
terminal_render_character (terminal, (index < value) ? character : ' ', colour, effect, x + index + 1, y);
|
||||
}
|
||||
}
|
||||
|
||||
static void terminal_render_string (terminal_structure * terminal, const char * string, uint colour, uint effect, uint x, uint y) {
|
||||
for (uint index = 0; string [index] != '\0'; ++index) {
|
||||
terminal_render_character (terminal, string [index], colour, effect, x + index, y);
|
||||
}
|
||||
}
|
||||
|
||||
static void terminal_render_number (terminal_structure * terminal, int number, uint colour, uint effect, uint x, uint y) {
|
||||
terminal_render_string (terminal, number_to_string (number), colour, effect, x, y);
|
||||
}
|
||||
|
||||
static void terminal_render_string_crop (terminal_structure * terminal, const char * string, uint colour, uint effect, uint x, uint y, uint crop) {
|
||||
for (uint index = 0; (string [index] != '\0') && (index < crop); ++index) {
|
||||
terminal_render_character (terminal, string [index], colour, effect, x + index, y);
|
||||
}
|
||||
}
|
||||
|
||||
static void terminal_render_number_crop (terminal_structure * terminal, int number, uint colour, uint effect, uint x, uint y, uint crop) {
|
||||
terminal_render_string_crop (terminal, number_to_string (number), colour, effect, x, y, crop);
|
||||
}
|
||||
|
||||
static void terminal_render_vertical_line (terminal_structure * terminal, char character, uint colour, uint effect, uint x, uint y, uint height) {
|
||||
for (uint offset = 0; offset != height; ++offset) {
|
||||
terminal_render_character (terminal, character, colour, effect, x, y + offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void terminal_render_horizontal_line (terminal_structure * terminal, char character, uint colour, uint effect, uint x, uint y, uint width) {
|
||||
for (uint offset = 0; offset != width; ++offset) {
|
||||
terminal_render_character (terminal, character, colour, effect, x + offset, y);
|
||||
}
|
||||
}
|
||||
|
||||
static void terminal_render_rectangle_line (terminal_structure * terminal, char character, uint colour, uint effect, uint x, uint y, uint width, uint height) {
|
||||
terminal_render_vertical_line (terminal, character, colour, effect, x + 0, y + 0, height + 0);
|
||||
terminal_render_vertical_line (terminal, character, colour, effect, x + width - 1, y + 0, height + 0);
|
||||
terminal_render_horizontal_line (terminal, character, colour, effect, x + 1, y + 0, width - 1);
|
||||
terminal_render_horizontal_line (terminal, character, colour, effect, x + 1, y + height - 1, width - 1);
|
||||
}
|
||||
|
||||
static void terminal_render_rectangle_fill (terminal_structure * terminal, char character, uint colour, uint effect, uint x, uint y, uint width, uint height) {
|
||||
for (uint offset_y = 0; offset_y != height; ++offset_y) {
|
||||
for (uint offset_x = 0; offset_x != width; ++offset_x) {
|
||||
terminal_render_character (terminal, character, colour, effect, x + offset_x, y + offset_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void terminal_render_background (terminal_structure * terminal, char character, uint colour, uint effect) {
|
||||
for (uint y = 0; y != terminal->screen_height; ++y) {
|
||||
for (uint x = 0; x != terminal->screen_width; ++x) {
|
||||
terminal_render_character (terminal, character, colour, effect, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void terminal_render_format (terminal_structure * terminal, const char * format, uint x, uint y, ...) {
|
||||
va_list list;
|
||||
|
||||
uint offset_x = 0;
|
||||
uint offset_y = 0;
|
||||
|
||||
colour_enumeration colour = colour_white;
|
||||
effect_enumeration effect = effect_normal;
|
||||
|
||||
va_start (list, format);
|
||||
|
||||
for (; * format != character_null; ++format) {
|
||||
switch (* format) {
|
||||
case '\t': {
|
||||
offset_x += 8;
|
||||
} break;
|
||||
case '\n': {
|
||||
offset_x *= 0;
|
||||
offset_y += 1;
|
||||
} break;
|
||||
case '\r': {
|
||||
offset_x *= 0;
|
||||
} break;
|
||||
case '%': {
|
||||
++format;
|
||||
switch (* format) {
|
||||
case '%': {
|
||||
terminal_render_character (terminal, '%', colour, effect, x + offset_x, y + offset_y);
|
||||
++offset_x;
|
||||
} break;
|
||||
case 'i': {
|
||||
char * number = number_to_string (va_arg (list, int));
|
||||
terminal_render_string (terminal, number, colour, effect, x + offset_x, y + offset_y);
|
||||
offset_x += string_length (number);
|
||||
} break;
|
||||
case 't': {
|
||||
bool toggle = (bool) va_arg (list, int);
|
||||
terminal_render_toggle (terminal, toggle, x + offset_x, y + offset_y);
|
||||
offset_x += 3;
|
||||
} break;
|
||||
case 'b': {
|
||||
bool boolean = (bool) va_arg (list, int);
|
||||
terminal_render_string (terminal, (boolean == true) ? "true" : "false", colour, effect, x + offset_x, y + offset_y);
|
||||
offset_x += (boolean == true) ? 4 : 5;
|
||||
} break;
|
||||
case 'c': {
|
||||
char character = (char) va_arg (list, int);
|
||||
terminal_render_character (terminal, character, colour, effect, x + offset_x, y + offset_y);
|
||||
++offset_x;
|
||||
} break;
|
||||
case 's': {
|
||||
char * string = va_arg (list, char *);
|
||||
terminal_render_string (terminal, string, colour, effect, x + offset_x, y + offset_y);
|
||||
offset_x += string_length (string);
|
||||
} break;
|
||||
default: {
|
||||
terminal_render_character (terminal, '?', colour, effect, x + offset_x, y + offset_y);
|
||||
++offset_x;
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
case '/': {
|
||||
++format;
|
||||
switch (* format) {
|
||||
case '/': {
|
||||
terminal_render_character (terminal, '/', colour, effect, x + offset_x, y + offset_y);
|
||||
++offset_x;
|
||||
} break;
|
||||
case 'A': effect = effect_normal; break;
|
||||
case 'B': effect = effect_bold; break;
|
||||
case 'C': effect = effect_italic; break;
|
||||
case 'D': effect = effect_undefined_code; break;
|
||||
case 'E': effect = effect_underline; break;
|
||||
case 'F': effect = effect_blink; break;
|
||||
case 'G': effect = effect_reverse; break;
|
||||
case 'H': effect = effect_invisible_text; break;
|
||||
case '0': colour = colour_grey; break;
|
||||
case '1': colour = colour_red; break;
|
||||
case '2': colour = colour_green; break;
|
||||
case '3': colour = colour_yellow; break;
|
||||
case '4': colour = colour_blue; break;
|
||||
case '5': colour = colour_pink; break;
|
||||
case '6': colour = colour_cyan; break;
|
||||
case '7': colour = colour_white; break;
|
||||
case '-': {
|
||||
colour = colour_white;
|
||||
effect = effect_normal;
|
||||
} break;
|
||||
default: {
|
||||
terminal_render_character (terminal, '?', colour, effect, x + offset_x, y + offset_y);
|
||||
++offset_x;
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
terminal_render_character (terminal, * format, colour, effect, x + offset_x, y + offset_y);
|
||||
++offset_x;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
va_end (list);
|
||||
}
|
||||
|
||||
#undef terminal_format_length
|
||||
#undef terminal_revert_length
|
||||
#undef terminal_cursor_length
|
||||
Loading…
Reference in New Issue
Block a user