// enable "vasprintf" from stdio.h #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include "console/console.h" #include #include #include #include #include // 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 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 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 vconsole_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 vconsole_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); }