You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
195 lines
5.1 KiB
195 lines
5.1 KiB
3 years ago
|
// enable "vasprintf" from stdio.h
|
||
|
#ifndef _GNU_SOURCE
|
||
|
#define _GNU_SOURCE
|
||
|
#endif
|
||
|
|
||
|
#include "console/console.h"
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
// These are either implemented using unix file descriptors, or in a platform specific way through a void* context
|
||
|
// - then the user code must provide the implementations.
|
||
|
#if CONSOLE_USE_FILE_IO_STREAMS
|
||
|
#include <unistd.h>
|
||
|
|
||
|
bool console_have_stdin_ctx(console_ctx_t *ctx)
|
||
|
{
|
||
|
return ctx && ctx->in &&
|
||
|
!feof(ctx->in);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write to console context.
|
||
|
*
|
||
|
* This is also a Linenoise write callback.
|
||
|
*
|
||
|
* Return number of characters written, -1 on error.
|
||
|
*/
|
||
|
int __attribute__((weak)) console_write_ctx(console_ctx_t *ctx, const char *text, size_t len) {
|
||
|
if (!ctx || !ctx->out) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
size_t written = fwrite(text, 1, len, ctx->out);
|
||
|
if (written != len) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return (int) written;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Read from console context's input stream.
|
||
|
*
|
||
|
* This is also a Linenoise read callback.
|
||
|
*
|
||
|
* Return number of characters read, -1 on error
|
||
|
*/
|
||
|
int __attribute__((weak)) console_read_ctx(console_ctx_t *ctx, char *dest, size_t count) {
|
||
|
if (!console_have_stdin_ctx(ctx)) return -1;
|
||
|
ssize_t readn = fread(dest, 1, (size_t) count, ctx->in);
|
||
|
return (int) readn;
|
||
|
}
|
||
|
|
||
|
#if CONSOLE_USE_TERMIOS
|
||
|
#include <termio.h>
|
||
|
|
||
|
int console_can_read_ctx(console_ctx_t *ctx) {
|
||
|
if (!console_have_stdin_ctx(ctx)) return -1;
|
||
|
|
||
|
int fd = fileno(ctx->in);
|
||
|
|
||
|
struct termios original;
|
||
|
tcgetattr(fd, &original);
|
||
|
|
||
|
struct termios term;
|
||
|
memcpy(&term, &original, sizeof(term));
|
||
|
|
||
|
term.c_lflag &= ~ICANON;
|
||
|
tcsetattr(fd, TCSANOW, &term);
|
||
|
|
||
|
int characters_buffered = 0;
|
||
|
ioctl(fd, FIONREAD, &characters_buffered);
|
||
|
|
||
|
tcsetattr(fd, TCSANOW, &original);
|
||
|
|
||
|
return characters_buffered;
|
||
|
}
|
||
|
#endif // CONSOLE_USE_TERMIOS
|
||
|
|
||
|
#endif // CONSOLE_USE_FILEDES_IO
|
||
|
|
||
|
ssize_t console_printf_ctx(console_ctx_t *ctx, console_color_t color, const char *format, ...) {
|
||
|
if (!ctx) return -1;
|
||
|
va_list list;
|
||
|
va_start(list, format);
|
||
|
ssize_t len = console_vprintf_ctx(ctx, color, format, list);
|
||
|
va_end(list);
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
ssize_t console_vprintf_ctx(console_ctx_t *ctx, console_color_t color, const char *format, va_list args) {
|
||
|
if (!ctx) return -1;
|
||
|
|
||
|
if (ctx->use_colors && color != COLOR_RESET) {
|
||
|
switch(color) {
|
||
|
case COLOR_BLACK:
|
||
|
console_write_ctx(ctx, "\x1b[30;1m", 7);
|
||
|
break;
|
||
|
case COLOR_RED:
|
||
|
console_write_ctx(ctx, "\x1b[31;1m", 7);
|
||
|
break;
|
||
|
case COLOR_GREEN:
|
||
|
console_write_ctx(ctx, "\x1b[32;1m", 7);
|
||
|
break;
|
||
|
case COLOR_YELLOW:
|
||
|
console_write_ctx(ctx, "\x1b[33;1m", 7);
|
||
|
break;
|
||
|
case COLOR_BLUE:
|
||
|
console_write_ctx(ctx, "\x1b[34;1m", 7);
|
||
|
break;
|
||
|
case COLOR_MAGENTA:
|
||
|
console_write_ctx(ctx, "\x1b[35;1m", 7);
|
||
|
break;
|
||
|
case COLOR_CYAN:
|
||
|
console_write_ctx(ctx, "\x1b[36;1m", 7);
|
||
|
break;
|
||
|
//case COLOR_WHITE:
|
||
|
default:
|
||
|
console_write_ctx(ctx, "\x1b[37;1m", 7);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
char *buf = NULL;
|
||
|
ssize_t len = vasprintf(&buf, format, args);
|
||
|
if (buf && len >= 0) {
|
||
|
// change to actual len written, can also result in -1 on error
|
||
|
len = console_write_ctx(ctx, buf, (size_t) len);
|
||
|
free(buf); // allocated by vasprintf
|
||
|
}
|
||
|
|
||
|
if (ctx->use_colors && color != COLOR_RESET) {
|
||
|
console_write_ctx(ctx, "\x1b[0m", 4);
|
||
|
len += 7+4;
|
||
|
}
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
int console_print_ctx(console_ctx_t *ctx, const char *text) {
|
||
|
if (!ctx) return -1;
|
||
|
|
||
|
return console_write_ctx(ctx, text, (int) strlen(text));
|
||
|
}
|
||
|
|
||
|
ssize_t console_println_ctx(console_ctx_t *ctx, const char *text) {
|
||
|
if (!ctx) return -1;
|
||
|
|
||
|
ssize_t n = console_write_ctx(ctx, text, (int) strlen(text));
|
||
|
if (n < 0) return n;
|
||
|
ssize_t m = console_write_ctx(ctx, "\n", 2);
|
||
|
if (m < 0) return m;
|
||
|
return n + m;
|
||
|
}
|
||
|
|
||
|
// ---------------- convenience functions -------------------
|
||
|
|
||
|
bool console_have_stdin(void) {
|
||
|
if (!console_context_available()) return false;
|
||
|
return console_have_stdin_ctx(console_active_ctx);
|
||
|
}
|
||
|
|
||
|
int console_can_read(void) {
|
||
|
if (!console_have_stdin()) return -1; // Input not available
|
||
|
return console_can_read_ctx(console_active_ctx);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Linenoise read callback.
|
||
|
*
|
||
|
* Return number of characters read, -1 on error
|
||
|
*/
|
||
|
ssize_t console_read(char *dest, size_t count) {
|
||
|
if (!console_have_stdin()) return -1;
|
||
|
return console_read_ctx(console_active_ctx, dest, count);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Linenoise write callback.
|
||
|
*
|
||
|
* Return number of characters written, -1 on error.
|
||
|
*/
|
||
|
ssize_t console_write(const char *text, size_t len) {
|
||
|
if (!console_context_available()) return -1;
|
||
|
return console_write_ctx(console_active_ctx, text, len);
|
||
|
}
|
||
|
|
||
|
ssize_t console_println(const char *text) {
|
||
|
if (!console_context_available()) return -1;
|
||
|
return console_println_ctx(console_active_ctx, text);
|
||
|
}
|