diff --git a/CMakeLists.txt b/CMakeLists.txt
index 409ef786..1a12a954 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,6 +20,9 @@ set (CMAKE_CXX_FLAGS "-std=c++11 -Wno-return-type -Wall -Wextra -Wnon-virtual-dt
find_package (GnuTLS 3.1 REQUIRED)
find_package (Msgpack 1.1 REQUIRED)
+if (OPENDHT_TOOLS)
+ find_package (Readline 6 REQUIRED)
+endif ()
list (APPEND opendht_SOURCES
src/infohash.cpp
diff --git a/cmake/FindReadline.cmake b/cmake/FindReadline.cmake
new file mode 100644
index 00000000..6807812f
--- /dev/null
+++ b/cmake/FindReadline.cmake
@@ -0,0 +1,48 @@
+# - Try to find readline, a library for easy editing of command lines.
+# Variables used by this module:
+# READLINE_ROOT_DIR - Readline root directory
+# Variables defined by this module:
+# READLINE_FOUND - system has Readline
+# READLINE_INCLUDE_DIR - the Readline include directory (cached)
+# READLINE_INCLUDE_DIRS - the Readline include directories
+# (identical to READLINE_INCLUDE_DIR)
+# READLINE_LIBRARY - the Readline library (cached)
+# READLINE_LIBRARIES - the Readline library plus the libraries it
+# depends on
+
+# Copyright (C) 2009
+# ASTRON (Netherlands Institute for Radio Astronomy)
+# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+#
+# This program is free software; you can redistribute it and/or modify
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see .
+#
+# $Id: FindReadline.cmake 15228 2010-03-16 09:27:26Z loose $
+
+if(NOT READLINE_FOUND)
+
+ find_path(READLINE_INCLUDE_DIR readline/readline.h
+ HINTS ${READLINE_ROOT_DIR} PATH_SUFFIXES include)
+ find_library(READLINE_LIBRARY readline
+ HINTS ${READLINE_ROOT_DIR} PATH_SUFFIXES lib)
+ find_library(NCURSES_LIBRARY ncurses) # readline depends on libncurses
+ mark_as_advanced(READLINE_INCLUDE_DIR READLINE_LIBRARY NCURSES_LIBRARY)
+
+ include(FindPackageHandleStandardArgs)
+ find_package_handle_standard_args(Readline DEFAULT_MSG
+ READLINE_LIBRARY NCURSES_LIBRARY READLINE_INCLUDE_DIR)
+
+ set(READLINE_INCLUDE_DIRS ${READLINE_INCLUDE_DIR})
+ set(READLINE_LIBRARIES ${READLINE_LIBRARY} ${NCURSES_LIBRARY})
+
+endif(NOT READLINE_FOUND)
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index f299d212..2db4ef36 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -3,9 +3,9 @@ add_executable (dhtnode dhtnode.cpp tools_common.h)
add_executable (dhtscanner dhtscanner.cpp tools_common.h)
add_executable (dhtchat dhtchat.cpp tools_common.h)
-target_link_libraries (dhtnode LINK_PUBLIC opendht gnutls)
-target_link_libraries (dhtscanner LINK_PUBLIC opendht gnutls)
-target_link_libraries (dhtchat LINK_PUBLIC opendht gnutls)
+target_link_libraries (dhtnode LINK_PUBLIC opendht gnutls readline)
+target_link_libraries (dhtscanner LINK_PUBLIC opendht gnutls readline)
+target_link_libraries (dhtchat LINK_PUBLIC opendht gnutls readline)
if (NOT DEFINED CMAKE_INSTALL_BINDIR)
set(CMAKE_INSTALL_BINDIR bin)
diff --git a/tools/dhtchat.cpp b/tools/dhtchat.cpp
index 831f4b46..c610b546 100644
--- a/tools/dhtchat.cpp
+++ b/tools/dhtchat.cpp
@@ -72,18 +72,20 @@ main(int argc, char **argv)
InfoHash room;
const InfoHash myid = dht.getId();
+ // using the GNU History API
+ using_history();
+
while (true)
{
- std::cout << (connected ? ">> " : "> ");
- std::string line;
- std::getline(std::cin, line);
- static constexpr dht::InfoHash INVALID_ID {};
-
- if (std::cin.eof())
+ // using the GNU Readline API
+ std::string line = readLine(connected ? PROMPT : "> ");
+ if (!line.empty() && line[0] == '\0')
break;
if (line.empty())
continue;
+ static constexpr dht::InfoHash INVALID_ID {};
+
std::istringstream iss(line);
std::string op, idstr;
iss >> op;
diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp
index f9fc37ee..3dae0d37 100644
--- a/tools/dhtnode.cpp
+++ b/tools/dhtnode.cpp
@@ -114,16 +114,21 @@ main(int argc, char **argv)
print_node_info(dht, params);
std::cout << " (type 'h' or 'help' for a list of possible commands)" << std::endl << std::endl;
+ // using the GNU History API
+ using_history();
+
while (true)
{
- std::cout << ">> ";
- std::string line;
- std::getline(std::cin, line);
+ // using the GNU Readline API
+ std::string line = readLine();
+ if (!line.empty() && line[0] == '\0')
+ break;
+
std::istringstream iss(line);
std::string op, idstr, value;
iss >> op >> idstr;
- if (std::cin.eof() || op == "x" || op == "q" || op == "exit" || op == "quit") {
+ if (op == "x" || op == "q" || op == "exit" || op == "quit") {
break;
} else if (op == "h" || op == "help") {
print_help();
diff --git a/tools/tools_common.h b/tools/tools_common.h
index 4c7af5e2..c1aebb09 100644
--- a/tools/tools_common.h
+++ b/tools/tools_common.h
@@ -39,6 +39,8 @@
#include
#include
+#include
+#include
/**
* Terminal colors for logging
@@ -202,3 +204,15 @@ parseArgs(int argc, char **argv) {
}
return params;
}
+
+static const constexpr char* PROMPT = ">> ";
+
+std::string
+readLine(const char* prefix = PROMPT)
+{
+ const char* line_read = readline(prefix);
+ if (line_read && *line_read)
+ add_history(line_read);
+
+ return line_read ? std::string(line_read) : std::string("\0", 1);
+}