added a lot of terminal control functions
This commit is contained in:
parent
85c0736c8d
commit
5266872c2b
@ -49,9 +49,7 @@ static Result(void) askUserNameAndPassword(ClientCredentials* cred){
|
|||||||
str username = str_null;
|
str username = str_null;
|
||||||
while(true) {
|
while(true) {
|
||||||
printf("username: ");
|
printf("username: ");
|
||||||
if(fgets(username_buf, sizeof(username_buf), stdin) == NULL){
|
try_void(term_readLine(username_buf, sizeof(username_buf)));
|
||||||
Return RESULT_ERROR("STDIN is closed", false);
|
|
||||||
}
|
|
||||||
username = str_from_cstr(username_buf);
|
username = str_from_cstr(username_buf);
|
||||||
str_trim(&username, true);
|
str_trim(&username, true);
|
||||||
if(username.size < USERNAME_SIZE_MIN || username.size > USERNAME_SIZE_MAX){
|
if(username.size < USERNAME_SIZE_MIN || username.size > USERNAME_SIZE_MAX){
|
||||||
@ -66,9 +64,7 @@ static Result(void) askUserNameAndPassword(ClientCredentials* cred){
|
|||||||
while(true) {
|
while(true) {
|
||||||
printf("password: ");
|
printf("password: ");
|
||||||
// TODO: hide password
|
// TODO: hide password
|
||||||
if(fgets(password_buf, sizeof(password_buf), stdin) == NULL){
|
try_void(term_readLineHidden(password_buf, sizeof(password_buf)));
|
||||||
Return RESULT_ERROR("STDIN is closed", false);
|
|
||||||
}
|
|
||||||
password = str_from_cstr(password_buf);
|
password = str_from_cstr(password_buf);
|
||||||
str_trim(&password, true);
|
str_trim(&password, true);
|
||||||
if(password.size < PASSWORD_SIZE_MIN || password.size > PASSWORD_SIZE_MAX){
|
if(password.size < PASSWORD_SIZE_MIN || password.size > PASSWORD_SIZE_MAX){
|
||||||
@ -84,9 +80,7 @@ static Result(void) askUserNameAndPassword(ClientCredentials* cred){
|
|||||||
|
|
||||||
Result(void) Client_run(Client* client) {
|
Result(void) Client_run(Client* client) {
|
||||||
Deferral(16);
|
Deferral(16);
|
||||||
if(!term_init()){
|
try_void(term_init());
|
||||||
Return RESULT_ERROR("can't init terminal", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs(greeting_art.data, stdout);
|
fputs(greeting_art.data, stdout);
|
||||||
try_void(askUserNameAndPassword(&client->cred));
|
try_void(askUserNameAndPassword(&client->cred));
|
||||||
@ -98,9 +92,7 @@ Result(void) Client_run(Client* client) {
|
|||||||
while(!stop){
|
while(!stop){
|
||||||
sleepMsec(50);
|
sleepMsec(50);
|
||||||
fputs("> ", stdout);
|
fputs("> ", stdout);
|
||||||
if(fgets(input_buf.data, input_buf.size, stdin) == NULL){
|
try_void(term_readLine(input_buf.data, input_buf.size));
|
||||||
Return RESULT_ERROR("STDIN is closed", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
command_input = str_from_cstr(input_buf.data);
|
command_input = str_from_cstr(input_buf.data);
|
||||||
str_trim(&command_input, true);
|
str_trim(&command_input, true);
|
||||||
@ -124,7 +116,6 @@ Result(void) Client_run(Client* client) {
|
|||||||
static Result(void) commandExec(Client* client, str command, bool* stop){
|
static Result(void) commandExec(Client* client, str command, bool* stop){
|
||||||
Deferral(64);
|
Deferral(64);
|
||||||
char answer_buf[10000];
|
char answer_buf[10000];
|
||||||
const u32 answer_buf_size = sizeof(answer_buf);
|
|
||||||
if(is_alias("q") || is_alias("quit") || is_alias("exit")){
|
if(is_alias("q") || is_alias("quit") || is_alias("exit")){
|
||||||
fputs(farewell_art.data, stdout);
|
fputs(farewell_art.data, stdout);
|
||||||
*stop = true;
|
*stop = true;
|
||||||
@ -146,9 +137,7 @@ static Result(void) commandExec(Client* client, str command, bool* stop){
|
|||||||
ServerConnection_close(client->server_connection);
|
ServerConnection_close(client->server_connection);
|
||||||
|
|
||||||
puts("Enter server address (ip:port:public_key): ");
|
puts("Enter server address (ip:port:public_key): ");
|
||||||
if(fgets(answer_buf, answer_buf_size, stdin) == NULL){
|
try_void(term_readLine(answer_buf, sizeof(answer_buf)));
|
||||||
Return RESULT_ERROR("STDIN is closed", false);
|
|
||||||
}
|
|
||||||
str new_server_link = str_from_cstr(answer_buf);
|
str new_server_link = str_from_cstr(answer_buf);
|
||||||
str_trim(&new_server_link, true);
|
str_trim(&new_server_link, true);
|
||||||
|
|
||||||
|
|||||||
@ -50,5 +50,5 @@ Result(void) sendErrorMessage_f(cstr log_ctx, bool logAsError,
|
|||||||
Defer(va_end(argv));
|
Defer(va_end(argv));
|
||||||
try_void(__sendErrorMessage_fv(log_ctx, logAsError, conn, res_head, format, argv));
|
try_void(__sendErrorMessage_fv(log_ctx, logAsError, conn, res_head, format, argv));
|
||||||
|
|
||||||
return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|||||||
181
src/term.c
181
src/term.c
@ -1,95 +1,182 @@
|
|||||||
#include "term.h"
|
#include "term.h"
|
||||||
#include <unistd.h>
|
|
||||||
#include IFWIN("windows.h", "sys/ioctl.h")
|
|
||||||
|
|
||||||
bool term_init(){
|
|
||||||
#if defined(_WIN64) || defined(_WIN32)
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
DWORD mode=0;
|
#include <windows.h>
|
||||||
HANDLE h;
|
#define try_win_bool(EXPR) if(!(EXPR)) { Return RESULT_ERROR_FMT(#EXPR " failed with WindowsError %lu", GetLastError()); }
|
||||||
|
#else
|
||||||
// configure stdout
|
#include <unistd.h>
|
||||||
h = GetStdHandle(STD_OUTPUT_HANDLE);
|
#include <sys/ioctl.h>
|
||||||
if(h == INVALID_HANDLE_VALUE)
|
#include <termios.h>
|
||||||
return false;
|
#define try_zero_errno(EXPR) if((EXPR) != 0) { Return RESULT_ERROR_FMT(#EXPR " failed with errno: %s", strerror(errno)); }
|
||||||
GetConsoleMode(h, &mode);
|
|
||||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
|
||||||
mode |= ENABLE_PROCESSED_OUTPUT;
|
|
||||||
SetConsoleMode(h, mode);
|
|
||||||
|
|
||||||
// configure stdin
|
|
||||||
h = GetStdHandle(STD_INPUT_HANDLE);
|
|
||||||
if(h == INVALID_HANDLE_VALUE)
|
|
||||||
return false;
|
|
||||||
GetConsoleMode(h, &mode);
|
|
||||||
mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
|
|
||||||
mode |= ENABLE_PROCESSED_INPUT;
|
|
||||||
SetConsoleMode(h, mode);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
Result(void) term_init(){
|
||||||
|
Deferral(8);
|
||||||
|
|
||||||
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
|
DWORD mode = 0;
|
||||||
|
HANDLE console_handle;
|
||||||
|
|
||||||
|
// configure stdout
|
||||||
|
console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
try_assert(console_handle != INVALID_HANDLE_VALUE);
|
||||||
|
GetConsoleMode(console_handle, &mode);
|
||||||
|
// https://learn.microsoft.com/en-us/windows/console/setconsolemode
|
||||||
|
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
mode |= ENABLE_PROCESSED_OUTPUT;
|
||||||
|
mode |= DISABLE_NEWLINE_AUTO_RETURN;
|
||||||
|
SetConsoleMode(console_handle, mode);
|
||||||
|
|
||||||
|
// configure stderr
|
||||||
|
console_handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
try_assert(console_handle != INVALID_HANDLE_VALUE);
|
||||||
|
GetConsoleMode(console_handle, &mode);
|
||||||
|
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
mode |= ENABLE_PROCESSED_OUTPUT;
|
||||||
|
mode |= DISABLE_NEWLINE_AUTO_RETURN;
|
||||||
|
SetConsoleMode(console_handle, mode);
|
||||||
|
|
||||||
|
// configure stdin
|
||||||
|
console_handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
try_assert(console_handle != INVALID_HANDLE_VALUE);
|
||||||
|
GetConsoleMode(console_handle, &mode);
|
||||||
|
mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
|
||||||
|
SetConsoleMode(console_handle, mode);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getenv_int(const char* var_name){
|
i64 getenv_int(const char* var_name){
|
||||||
char* str=getenv(var_name);
|
char* s = getenv(var_name);
|
||||||
if(str==NULL)
|
if(s == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
return strtol(str, NULL, 0);
|
return strtoll(s, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool term_getSize(TerminalSize* out) {
|
Result(void) term_getSize(TerminalSize* out) {
|
||||||
|
Deferral(4);
|
||||||
|
|
||||||
#if defined(_WIN64) || defined(_WIN32)
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
// helps when STD_OUT is redirected to a file
|
// helps when STD_OUT is redirected to a file
|
||||||
HANDLE hConsoleErr = GetStdHandle(STD_ERROR_HANDLE);
|
HANDLE console_handle_stderr = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
try_assert(console_handle_stderr != INVALID_HANDLE_VALUE)
|
||||||
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
|
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
|
||||||
if(!GetConsoleScreenBufferInfo(hConsoleErr, &consoleInfo))
|
try_win_bool(GetConsoleScreenBufferInfo(console_handle_stderr, &consoleInfo));
|
||||||
return false;
|
|
||||||
|
|
||||||
out->cols = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1;
|
out->cols = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1;
|
||||||
out->rows = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1;
|
out->rows = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1;
|
||||||
#else
|
#else
|
||||||
struct winsize ws = {0};
|
struct winsize ws = {0};
|
||||||
// try to get terminal size from stdin, stdout, stderr
|
// try to get terminal size from stdin, stdout, stderr
|
||||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)==0 ||
|
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0 ||
|
||||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)==0 ||
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 ||
|
||||||
ioctl(STDERR_FILENO, TIOCGWINSZ, &ws)==0 ){
|
ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == 0 ){
|
||||||
out->cols=ws.ws_col;
|
out->cols = ws.ws_col;
|
||||||
out->rows=ws.ws_row;
|
out->rows = ws.ws_row;
|
||||||
}
|
}
|
||||||
// try to get size from environtent variables
|
// try to get size from environtent variables
|
||||||
else {
|
else {
|
||||||
out->cols=getenv_int("COLUMNS");
|
out->cols = getenv_int("COLUMNS");
|
||||||
out->rows=getenv_int("LINES");
|
out->rows = getenv_int("LINES");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return out->cols > 0 && out->rows > 0;
|
try_assert(out->cols > 0);
|
||||||
|
try_assert(out->rows > 0);
|
||||||
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result(void) term_readLine(char* buf, u32 bufsize) {
|
||||||
|
Deferral(1);
|
||||||
|
try_assert(fgets(buf, bufsize, stdin) != NULL);
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) term_readLineHidden(char *buf, u32 bufsize) {
|
||||||
|
Deferral(4);
|
||||||
|
|
||||||
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
|
HANDLE console_handle_stdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
try_assert(console_handle_stdin != INVALID_HANDLE_VALUE);
|
||||||
|
DWORD old_mode;
|
||||||
|
GetConsoleMode(console_handle_stdin, &old_mode);
|
||||||
|
// turn off echo
|
||||||
|
DWORD new_mode = old_mode & ~(ENABLE_ECHO_INPUT);
|
||||||
|
SetConsoleMode(console_handle_stdin, new_mode);
|
||||||
|
// restore echo
|
||||||
|
Defer(SetConsoleMode(console_handle_stdin, old_mode));
|
||||||
|
#else
|
||||||
|
struct termios old_mode, new_mode;
|
||||||
|
try_zero_errno(tcgetattr(STDIN_FILENO, &old_mode));
|
||||||
|
new_mode = old_mode;
|
||||||
|
// turn off echo
|
||||||
|
new_mode.c_lflag &= ~(ECHO);
|
||||||
|
try_zero_errno(tcsetattr(STDIN_FILENO, TCSAFLUSH, &new_mode));
|
||||||
|
// restore echo
|
||||||
|
Defer(tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_mode));
|
||||||
|
#endif
|
||||||
|
// read line
|
||||||
|
try_void(term_readLine(buf, bufsize));
|
||||||
|
fputchar('\n');
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Most of escape sequences can be found there
|
Most of escape sequences can be found there
|
||||||
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
|
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
|
||||||
*/
|
*/
|
||||||
|
#define ESC "\x1b"
|
||||||
|
#define CSI ESC"["
|
||||||
|
|
||||||
|
void term_setFgColor16(Color16 c){
|
||||||
|
printf(CSI"%um", c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_setBgColor16(Color16 c){
|
||||||
|
printf(CSI"%um", c + 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_bold(){
|
||||||
|
printf(CSI"1m");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_italic(){
|
||||||
|
printf(CSI"3m");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_underline(){
|
||||||
|
printf(CSI"4m");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_strikethrough(){
|
||||||
|
printf(CSI"9m");
|
||||||
|
}
|
||||||
|
|
||||||
void term_resetCursor() {
|
void term_resetCursor() {
|
||||||
printf("\e[H");
|
printf(CSI"H");
|
||||||
}
|
}
|
||||||
|
|
||||||
void term_resetColors() {
|
void term_resetColors() {
|
||||||
printf("\e[0m");
|
printf(CSI"0m");
|
||||||
}
|
}
|
||||||
|
|
||||||
void term_clear() {
|
void term_clear() {
|
||||||
printf("\e[0m\e[H\e[2J");
|
printf(CSI"0m" CSI"H" CSI"2J");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_eraseRow(){
|
||||||
|
printf(CSI"2K\r");
|
||||||
}
|
}
|
||||||
|
|
||||||
void term_cursorMove(u16 row, u16 column) {
|
void term_cursorMove(u16 row, u16 column) {
|
||||||
printf("\e[%u;%uH",row,column);
|
printf(CSI"%u;%uH", row, column);
|
||||||
}
|
}
|
||||||
|
|
||||||
void term_cursorHide() {
|
void term_cursorHide() {
|
||||||
printf("\e[?25l");
|
printf(CSI"?25l");
|
||||||
}
|
}
|
||||||
|
|
||||||
void term_cursorShow() {
|
void term_cursorShow() {
|
||||||
printf("\e[?25h");
|
printf(CSI"?25h");
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/term.h
39
src/term.h
@ -1,16 +1,47 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "tlibc/std.h"
|
#include "tlibc/errors.h"
|
||||||
|
|
||||||
typedef struct TerminalSize {
|
typedef struct TerminalSize {
|
||||||
i16 cols;
|
i16 cols;
|
||||||
i16 rows;
|
i16 rows;
|
||||||
} TerminalSize;
|
} TerminalSize;
|
||||||
|
|
||||||
bool term_init();
|
typedef enum Color16 {
|
||||||
bool term_getSize(TerminalSize* out);
|
Color16_Black = 30,
|
||||||
void term_resetCursor();
|
Color16_DarkRed = 31,
|
||||||
|
Color16_DarkGreen = 32,
|
||||||
|
Color16_DarkYellow = 33,
|
||||||
|
Color16_DarkBlue = 34,
|
||||||
|
Color16_DarkMagenta = 35,
|
||||||
|
Color16_DarkCyan = 36,
|
||||||
|
Color16_Gray = 37,
|
||||||
|
Color16_DarkGray = 90,
|
||||||
|
Color16_Red = 91,
|
||||||
|
Color16_Green = 92,
|
||||||
|
Color16_Yellow = 93,
|
||||||
|
Color16_Blue = 94,
|
||||||
|
Color16_Magenta = 95,
|
||||||
|
Color16_Cyan = 96,
|
||||||
|
Color16_White = 97
|
||||||
|
} Color16;
|
||||||
|
|
||||||
|
Result(void) term_init();
|
||||||
|
Result(void) term_getSize(TerminalSize* out);
|
||||||
|
|
||||||
|
Result(void) term_readLine(char* buf, u32 bufsize);
|
||||||
|
Result(void) term_readLineHidden(char *buf, u32 bufsize);
|
||||||
|
|
||||||
|
void term_setFgColor16(Color16 c);
|
||||||
|
void term_setBgColor16(Color16 c);
|
||||||
|
void term_bold();
|
||||||
|
void term_italic();
|
||||||
|
void term_underline();
|
||||||
|
void term_strikethrough();
|
||||||
void term_resetColors();
|
void term_resetColors();
|
||||||
|
|
||||||
void term_clear();
|
void term_clear();
|
||||||
|
void term_eraseRow();
|
||||||
|
void term_resetCursor();
|
||||||
void term_cursorMove(u16 row, u16 column);
|
void term_cursorMove(u16 row, u16 column);
|
||||||
void term_cursorHide();
|
void term_cursorHide();
|
||||||
void term_cursorShow();
|
void term_cursorShow();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user