diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -619,7 +619,11 @@ endif() # RPC client support -add_library(rpcclient rpc/client.cpp) +add_library(rpcclient + compat/stdin.cpp + rpc/client.cpp +) + target_link_libraries(rpcclient univalue util) # bitcoin-seeder diff --git a/src/compat/stdin.h b/src/compat/stdin.h new file mode 100644 --- /dev/null +++ b/src/compat/stdin.h @@ -0,0 +1,18 @@ +// Copyright (c) 2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_COMPAT_STDIN_H +#define BITCOIN_COMPAT_STDIN_H + +struct NoechoInst { + NoechoInst(); + ~NoechoInst(); +}; + +#define NO_STDIN_ECHO() NoechoInst _no_echo + +bool StdinTerminal(); +bool StdinReady(); + +#endif // BITCOIN_COMPAT_STDIN_H diff --git a/src/compat/stdin.cpp b/src/compat/stdin.cpp new file mode 100644 --- /dev/null +++ b/src/compat/stdin.cpp @@ -0,0 +1,73 @@ +// Copyright (c) 2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include // for fileno(), stdin + +#ifdef WIN32 +#include // for isatty() +#include // for SetStdinEcho() +#else +#include // for StdinReady() +#include // for SetStdinEcho() +#include // for SetStdinEcho(), isatty() +#endif + +#include + +// https://stackoverflow.com/questions/1413445/reading-a-password-from-stdcin +void SetStdinEcho(bool enable) { +#ifdef WIN32 + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); + DWORD mode; + GetConsoleMode(hStdin, &mode); + if (!enable) { + mode &= ~ENABLE_ECHO_INPUT; + } else { + mode |= ENABLE_ECHO_INPUT; + } + SetConsoleMode(hStdin, mode); +#else + struct termios tty; + tcgetattr(STDIN_FILENO, &tty); + if (!enable) { + tty.c_lflag &= ~ECHO; + } else { + tty.c_lflag |= ECHO; + } + (void)tcsetattr(STDIN_FILENO, TCSANOW, &tty); +#endif +} + +bool StdinTerminal() { +#ifdef WIN32 + return _isatty(_fileno(stdin)); +#else + return isatty(fileno(stdin)); +#endif +} + +bool StdinReady() { + if (!StdinTerminal()) { + return true; + } +#ifdef WIN32 + return false; +#else + struct pollfd fds; + fds.fd = 0; /* this is STDIN */ + fds.events = POLLIN; + return poll(&fds, 1, 0) == 1; +#endif +} + +NoechoInst::NoechoInst() { + SetStdinEcho(false); +} +NoechoInst::~NoechoInst() { + SetStdinEcho(true); +}