From 7b3cfd2724d2c0bb178712278976d836f9277ded Mon Sep 17 00:00:00 2001 From: Marius Greuel Date: Wed, 4 Jan 2023 08:02:48 +0100 Subject: [PATCH] Add readline library replacement for MSVC --- CMakeLists.txt | 2 + src/CMakeLists.txt | 1 + src/msvc/readline.cpp | 99 ++++++++++++++++++++++++++++++++++++ src/msvc/readline/history.h | 17 +++++++ src/msvc/readline/readline.h | 24 +++++++++ src/term.c | 4 +- 6 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 src/msvc/readline.cpp create mode 100644 src/msvc/readline/history.h create mode 100644 src/msvc/readline/readline.h diff --git a/CMakeLists.txt b/CMakeLists.txt index eed335f7..224f626b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,6 +223,8 @@ endif() find_library(HAVE_LIBREADLINE NAMES ${PREFERRED_LIBREADLINE}) if(HAVE_LIBREADLINE) set(LIB_LIBREADLINE ${HAVE_LIBREADLINE}) +elseif(MSVC) + set(HAVE_LIBREADLINE 1) endif() # ===================================== diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 462d9eae..c51214e6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -70,6 +70,7 @@ if(MSVC) "msvc/getopt.c" "msvc/gettimeofday.c" "msvc/usleep.cpp" + "msvc/readline.cpp" ) set(EXTRA_WINDOWS_INCLUDES ${EXTRA_WINDOWS_INCLUDES} "msvc" diff --git a/src/msvc/readline.cpp b/src/msvc/readline.cpp new file mode 100644 index 00000000..786bf247 --- /dev/null +++ b/src/msvc/readline.cpp @@ -0,0 +1,99 @@ +// +// readline.cpp +// Copyright (C) 2022 Marius Greuel +// SPDX-License-Identifier: GPL-2.0-or-later +// + +#include +#include +#include +#include +#include +#include +#include "readline/readline.h" +#include "readline/history.h" + +int rl_readline_version = 0x0500; + +static char* rl_prompt; +static rl_vcpfunc_t* rl_handler; +static std::unique_ptr rl_thread; +static std::mutex rl_mutex; +static std::string rl_line; +static bool rl_has_line = false; + +static void get_line_thread() +{ + std::string line; + std::getline(std::cin, line); + + const std::lock_guard lock(rl_mutex); + rl_line = line; + rl_has_line = true; +} + +static void call_handler(const char* string) +{ + rl_thread->join(); + rl_thread = nullptr; + + if (rl_handler != nullptr) + { + if (string == nullptr) + { + rl_handler(nullptr); + } + else + { + rl_handler(_strdup(string)); + } + } +} + +int rl_input_available(void) +{ + return 1; +} + +void rl_callback_read_char(void) +{ + if (std::cin.eof()) + { + call_handler(nullptr); + } + else if (!rl_thread) + { + rl_thread = std::make_unique(get_line_thread); + } + else + { + const std::lock_guard lock(rl_mutex); + if (rl_has_line) + { + rl_has_line = false; + call_handler(rl_line.c_str()); + } + } +} + +void rl_callback_handler_install(char* prompt, rl_vcpfunc_t* handler) +{ + rl_prompt = _strdup(prompt); + rl_handler = handler; + + std::cout << rl_prompt; +} + +void rl_callback_handler_remove(void) +{ + if (rl_prompt != nullptr) + { + free(rl_prompt); + } + + rl_handler = nullptr; +} + +void add_history(const char*) +{ +} diff --git a/src/msvc/readline/history.h b/src/msvc/readline/history.h new file mode 100644 index 00000000..86a7b0a8 --- /dev/null +++ b/src/msvc/readline/history.h @@ -0,0 +1,17 @@ +// +// history.h +// Copyright (C) 2022 Marius Greuel +// SPDX-License-Identifier: GPL-2.0-or-later +// + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void add_history(const char* string); + +#ifdef __cplusplus +} +#endif diff --git a/src/msvc/readline/readline.h b/src/msvc/readline/readline.h new file mode 100644 index 00000000..6a7d7a55 --- /dev/null +++ b/src/msvc/readline/readline.h @@ -0,0 +1,24 @@ +// +// readline.h +// Copyright (C) 2022 Marius Greuel +// SPDX-License-Identifier: GPL-2.0-or-later +// + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (rl_vcpfunc_t)(char* line); + +extern int rl_readline_version; + +int rl_input_available(void); +void rl_callback_read_char(void); +void rl_callback_handler_install(char* prompt, rl_vcpfunc_t* handler); +void rl_callback_handler_remove(void); + +#ifdef __cplusplus +} +#endif diff --git a/src/term.c b/src/term.c index d53d2df3..0828e17e 100644 --- a/src/term.c +++ b/src/term.c @@ -1314,7 +1314,9 @@ static int term_running; // Any character in standard input available (without sleeping)? static int readytoread() { -#ifdef WIN32 +#ifdef _MSC_VER + return rl_input_available(); +#elif defined(WIN32) HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); while(1) {