Compare commits
30 Commits
f9e157293c
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
74fcb06828
|
|||
|
8cf1abf135
|
|||
|
b87fbc93a6
|
|||
|
ac1a21eac8
|
|||
|
6934550068
|
|||
|
cda7e1b1f3
|
|||
|
14c6d285fc
|
|||
|
ab5941aaef
|
|||
|
84d6c658e8
|
|||
|
a89fadf860
|
|||
|
4023155b67
|
|||
|
4ed58dd89a
|
|||
|
022668fb23
|
|||
|
ba5a6374b6
|
|||
|
67008963cf
|
|||
|
c1b6918db3
|
|||
|
3cf3c0215e
|
|||
|
a2a72c8b92
|
|||
|
57f89eba07
|
|||
|
4795ee851d
|
|||
|
87a644cc59
|
|||
|
990cf5a1d4
|
|||
|
4a5c818ba1
|
|||
|
af5929a383
|
|||
|
9f5845fc51
|
|||
|
3daf254b41
|
|||
|
c533fa2fd7
|
|||
|
2fe2d6bc03
|
|||
|
df93937789
|
|||
|
ae447065f7
|
33
.clang-format
Normal file
33
.clang-format
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# clang-format is fairly limited, and these rules are approximate:
|
||||||
|
# - array initializers can get terribly mangled with clang-format 12.0,
|
||||||
|
# - sometimes it still aligns with space characters,
|
||||||
|
# - EV_DEFAULT_ and EV_A_ are always taken as identifiers,
|
||||||
|
# - struct name NL { NL ... NL } NL name; is unachievable.
|
||||||
|
BasedOnStyle: GNU
|
||||||
|
ColumnLimit: 80
|
||||||
|
IndentWidth: 4
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: ForContinuationAndIndentation
|
||||||
|
BreakBeforeBraces: Allman
|
||||||
|
SpaceAfterCStyleCast: true
|
||||||
|
AlignAfterOpenBracket: DontAlign
|
||||||
|
AlignOperands: DontAlign
|
||||||
|
AlignConsecutiveMacros: Consecutive
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
IndentGotoLabels: false
|
||||||
|
|
||||||
|
# IncludeCategories has some potential, but it may also break the build.
|
||||||
|
# Note that the documentation says the value should be "Never".
|
||||||
|
SortIncludes: false
|
||||||
|
|
||||||
|
# This is a compromise, it generally works out aesthetically better.
|
||||||
|
BinPackArguments: false
|
||||||
|
|
||||||
|
# Unfortunately, this can't be told to align to column 40 or so.
|
||||||
|
SpacesBeforeTrailingComments: 2
|
||||||
|
|
||||||
|
# liberty-specific macro body wrappers.
|
||||||
|
MacroBlockBegin: "BLOCK_START"
|
||||||
|
MacroBlockEnd: "BLOCK_END"
|
||||||
|
ForEachMacros: ["LIST_FOR_EACH"]
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,3 +7,5 @@
|
|||||||
/json-rpc-shell.files
|
/json-rpc-shell.files
|
||||||
/json-rpc-shell.creator*
|
/json-rpc-shell.creator*
|
||||||
/json-rpc-shell.includes
|
/json-rpc-shell.includes
|
||||||
|
/json-rpc-shell.cflags
|
||||||
|
/json-rpc-shell.cxxflags
|
||||||
|
|||||||
128
CMakeLists.txt
128
CMakeLists.txt
@@ -1,5 +1,5 @@
|
|||||||
project (json-rpc-shell C)
|
cmake_minimum_required (VERSION 3.0...3.27)
|
||||||
cmake_minimum_required (VERSION 2.8.5)
|
project (json-rpc-shell VERSION 1.2.0 LANGUAGES C)
|
||||||
|
|
||||||
# Options
|
# Options
|
||||||
option (WANT_READLINE "Use GNU Readline for the UI (better)" ON)
|
option (WANT_READLINE "Use GNU Readline for the UI (better)" ON)
|
||||||
@@ -10,54 +10,73 @@ if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC)
|
|||||||
# -Wunused-function is pretty annoying here, as everything is static
|
# -Wunused-function is pretty annoying here, as everything is static
|
||||||
set (CMAKE_C_FLAGS
|
set (CMAKE_C_FLAGS
|
||||||
"${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Wno-unused-function")
|
"${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Wno-unused-function")
|
||||||
endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC)
|
endif ()
|
||||||
|
|
||||||
# Version
|
|
||||||
set (project_VERSION_MAJOR "1")
|
|
||||||
set (project_VERSION_MINOR "1")
|
|
||||||
set (project_VERSION_PATCH "0")
|
|
||||||
|
|
||||||
set (project_VERSION "${project_VERSION_MAJOR}")
|
|
||||||
set (project_VERSION "${project_VERSION}.${project_VERSION_MINOR}")
|
|
||||||
set (project_VERSION "${project_VERSION}.${project_VERSION_PATCH}")
|
|
||||||
|
|
||||||
# For custom modules
|
# For custom modules
|
||||||
set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
set (CMAKE_MODULE_PATH
|
||||||
|
"${PROJECT_SOURCE_DIR}/cmake;${PROJECT_SOURCE_DIR}/liberty/cmake")
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
find_package (Curses)
|
find_package (Curses)
|
||||||
|
find_package (Ncursesw)
|
||||||
find_package (PkgConfig REQUIRED)
|
find_package (PkgConfig REQUIRED)
|
||||||
pkg_check_modules (dependencies REQUIRED libcurl jansson)
|
|
||||||
# Note that cURL can link to a different version of libssl than we do,
|
# Note that cURL can link to a different version of libssl than we do,
|
||||||
# in which case the results are undefined
|
# in which case the results are undefined
|
||||||
pkg_check_modules (libssl REQUIRED libssl libcrypto)
|
pkg_check_modules (dependencies REQUIRED libcurl jansson libssl libcrypto)
|
||||||
find_package (LibEV REQUIRED)
|
find_package (LibEV REQUIRED)
|
||||||
pkg_check_modules (ncursesw ncursesw)
|
|
||||||
|
|
||||||
set (project_libraries ${dependencies_LIBRARIES}
|
set (project_libraries ${dependencies_LIBRARIES} ${LibEV_LIBRARIES})
|
||||||
${libssl_LIBRARIES} ${LIBEV_LIBRARIES})
|
include_directories (${dependencies_INCLUDE_DIRS} ${LibEV_INCLUDE_DIRS})
|
||||||
include_directories (${dependencies_INCLUDE_DIRS}
|
link_directories (${dependencies_LIBRARY_DIRS})
|
||||||
${libssl_INCLUDE_DIRS} ${LIBEV_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
if (ncursesw_FOUND)
|
if ("${CMAKE_SYSTEM_NAME}" MATCHES "BSD")
|
||||||
list (APPEND project_libraries ${ncursesw_LIBRARIES})
|
# Need this for SIGWINCH in FreeBSD and OpenBSD respectively;
|
||||||
include_directories (${ncursesw_INCLUDE_DIRS})
|
# our POSIX version macros make it undefined
|
||||||
|
add_definitions (-D__BSD_VISIBLE=1 -D_BSD_SOURCE=1)
|
||||||
|
elseif (APPLE)
|
||||||
|
add_definitions (-D_DARWIN_C_SOURCE)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
# -liconv may or may not be a part of libc
|
||||||
|
find_library (iconv_LIBRARIES iconv)
|
||||||
|
if (iconv_LIBRARIES)
|
||||||
|
list (APPEND project_libraries ${iconv_LIBRARIES})
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
include (CheckCSourceRuns)
|
||||||
|
set (CMAKE_REQUIRED_LIBRARIES ${project_libraries})
|
||||||
|
get_property (CMAKE_REQUIRED_INCLUDES
|
||||||
|
DIRECTORY "${PROJECT_SOURCE_DIR}" PROPERTY INCLUDE_DIRECTORIES)
|
||||||
|
CHECK_C_SOURCE_RUNS ("#include <iconv.h>
|
||||||
|
int main () { return iconv_open (\"UTF-8//TRANSLIT\", \"ISO-8859-1\")
|
||||||
|
== (iconv_t) -1; }" ICONV_ACCEPTS_TRANSLIT)
|
||||||
|
|
||||||
|
if (Ncursesw_FOUND)
|
||||||
|
list (APPEND project_libraries ${Ncursesw_LIBRARIES})
|
||||||
|
include_directories (${Ncursesw_INCLUDE_DIRS})
|
||||||
|
link_directories (${Ncursesw_LIBRARY_DIRS})
|
||||||
elseif (CURSES_FOUND)
|
elseif (CURSES_FOUND)
|
||||||
list (APPEND project_libraries ${CURSES_LIBRARY})
|
list (APPEND project_libraries ${CURSES_LIBRARY})
|
||||||
include_directories (${CURSES_INCLUDE_DIR})
|
include_directories (${CURSES_INCLUDE_DIR})
|
||||||
else (CURSES_FOUND)
|
else ()
|
||||||
message (SEND_ERROR "Curses not found")
|
message (SEND_ERROR "Curses not found")
|
||||||
endif (ncursesw_FOUND)
|
endif ()
|
||||||
|
|
||||||
if ((WANT_READLINE AND WANT_LIBEDIT) OR (NOT WANT_READLINE AND NOT WANT_LIBEDIT))
|
if ((WANT_READLINE AND WANT_LIBEDIT) OR (NOT WANT_READLINE AND NOT WANT_LIBEDIT))
|
||||||
message (SEND_ERROR "You have to choose either GNU Readline or libedit")
|
message (SEND_ERROR "You have to choose either GNU Readline or libedit")
|
||||||
elseif (WANT_READLINE)
|
elseif (WANT_READLINE)
|
||||||
list (APPEND project_libraries readline)
|
# OpenBSD's default readline is too old
|
||||||
|
if ("${CMAKE_SYSTEM_NAME}" MATCHES "OpenBSD")
|
||||||
|
include_directories (${OPENBSD_LOCALBASE}/include/ereadline)
|
||||||
|
list (APPEND project_libraries ereadline)
|
||||||
|
else ()
|
||||||
|
list (APPEND project_libraries readline)
|
||||||
|
endif ()
|
||||||
elseif (WANT_LIBEDIT)
|
elseif (WANT_LIBEDIT)
|
||||||
pkg_check_modules (libedit REQUIRED libedit)
|
pkg_check_modules (libedit REQUIRED libedit)
|
||||||
list (APPEND project_libraries ${libedit_LIBRARIES})
|
list (APPEND project_libraries ${libedit_LIBRARIES})
|
||||||
include_directories (${libedit_INCLUDE_DIRS})
|
include_directories (${libedit_INCLUDE_DIRS})
|
||||||
endif ((WANT_READLINE AND WANT_LIBEDIT) OR (NOT WANT_READLINE AND NOT WANT_LIBEDIT))
|
endif ()
|
||||||
|
|
||||||
# Generate a configuration file
|
# Generate a configuration file
|
||||||
set (HAVE_READLINE "${WANT_READLINE}")
|
set (HAVE_READLINE "${WANT_READLINE}")
|
||||||
@@ -86,23 +105,43 @@ install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
|||||||
install (PROGRAMS json-format.pl DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install (PROGRAMS json-format.pl DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
install (FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
install (FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
||||||
|
|
||||||
# Generate documentation from program help
|
# Generate documentation from text markup
|
||||||
find_program (ASCIIDOCTOR_EXECUTABLE asciidoctor)
|
find_program (ASCIIDOCTOR_EXECUTABLE asciidoctor)
|
||||||
if (NOT ASCIIDOCTOR_EXECUTABLE)
|
find_program (A2X_EXECUTABLE a2x)
|
||||||
message (FATAL_ERROR "asciidoctor not found")
|
if (NOT ASCIIDOCTOR_EXECUTABLE AND NOT A2X_EXECUTABLE)
|
||||||
endif (NOT ASCIIDOCTOR_EXECUTABLE)
|
message (WARNING "Neither asciidoctor nor a2x were found, "
|
||||||
|
"falling back to a substandard manual page generator")
|
||||||
|
endif ()
|
||||||
|
|
||||||
foreach (page ${PROJECT_NAME})
|
foreach (page ${PROJECT_NAME})
|
||||||
set (page_output "${PROJECT_BINARY_DIR}/${page}.1")
|
set (page_output "${PROJECT_BINARY_DIR}/${page}.1")
|
||||||
list (APPEND project_MAN_PAGES "${page_output}")
|
list (APPEND project_MAN_PAGES "${page_output}")
|
||||||
add_custom_command (OUTPUT ${page_output}
|
if (ASCIIDOCTOR_EXECUTABLE)
|
||||||
COMMAND ${ASCIIDOCTOR_EXECUTABLE} -b manpage
|
add_custom_command (OUTPUT ${page_output}
|
||||||
-a release-version=${project_VERSION}
|
COMMAND ${ASCIIDOCTOR_EXECUTABLE} -b manpage
|
||||||
"${PROJECT_SOURCE_DIR}/${page}.adoc"
|
-a release-version=${PROJECT_VERSION}
|
||||||
-o "${page_output}"
|
-o "${page_output}"
|
||||||
DEPENDS ${page}.adoc
|
"${PROJECT_SOURCE_DIR}/${page}.adoc"
|
||||||
COMMENT "Generating man page for ${page}" VERBATIM)
|
DEPENDS ${page}.adoc
|
||||||
endforeach (page)
|
COMMENT "Generating man page for ${page}" VERBATIM)
|
||||||
|
elseif (A2X_EXECUTABLE)
|
||||||
|
add_custom_command (OUTPUT ${page_output}
|
||||||
|
COMMAND ${A2X_EXECUTABLE} --doctype manpage --format manpage
|
||||||
|
-a release-version=${PROJECT_VERSION}
|
||||||
|
-D "${PROJECT_BINARY_DIR}"
|
||||||
|
"${PROJECT_SOURCE_DIR}/${page}.adoc"
|
||||||
|
DEPENDS ${page}.adoc
|
||||||
|
COMMENT "Generating man page for ${page}" VERBATIM)
|
||||||
|
else ()
|
||||||
|
set (ASCIIMAN ${PROJECT_SOURCE_DIR}/liberty/tools/asciiman.awk)
|
||||||
|
add_custom_command (OUTPUT ${page_output}
|
||||||
|
COMMAND env LC_ALL=C asciidoc-release-version=${PROJECT_VERSION}
|
||||||
|
awk -f ${ASCIIMAN} "${PROJECT_SOURCE_DIR}/${page}.adoc"
|
||||||
|
> ${page_output}
|
||||||
|
DEPENDS ${page}.adoc ${ASCIIMAN}
|
||||||
|
COMMENT "Generating man page for ${page}" VERBATIM)
|
||||||
|
endif ()
|
||||||
|
endforeach ()
|
||||||
|
|
||||||
add_custom_target (docs ALL DEPENDS ${project_MAN_PAGES})
|
add_custom_target (docs ALL DEPENDS ${project_MAN_PAGES})
|
||||||
|
|
||||||
@@ -110,22 +149,19 @@ foreach (page ${project_MAN_PAGES})
|
|||||||
string (REGEX MATCH "\\.([0-9])$" manpage_suffix "${page}")
|
string (REGEX MATCH "\\.([0-9])$" manpage_suffix "${page}")
|
||||||
install (FILES "${page}"
|
install (FILES "${page}"
|
||||||
DESTINATION "${CMAKE_INSTALL_MANDIR}/man${CMAKE_MATCH_1}")
|
DESTINATION "${CMAKE_INSTALL_MANDIR}/man${CMAKE_MATCH_1}")
|
||||||
endforeach (page)
|
endforeach ()
|
||||||
|
|
||||||
# CPack
|
# CPack
|
||||||
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "A shell for JSON-RPC 2.0")
|
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "A shell for JSON-RPC 2.0")
|
||||||
set (CPACK_PACKAGE_VENDOR "Premysl Eric Janouch")
|
set (CPACK_PACKAGE_VENDOR "Premysl Eric Janouch")
|
||||||
set (CPACK_PACKAGE_CONTACT "Přemysl Eric Janouch <p@janouch.name>")
|
set (CPACK_PACKAGE_CONTACT "Přemysl Eric Janouch <p@janouch.name>")
|
||||||
set (CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
set (CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
||||||
set (CPACK_PACKAGE_VERSION_MAJOR ${project_VERSION_MAJOR})
|
|
||||||
set (CPACK_PACKAGE_VERSION_MINOR ${project_VERSION_MINOR})
|
|
||||||
set (CPACK_PACKAGE_VERSION_PATCH ${project_VERSION_PATCH})
|
|
||||||
set (CPACK_GENERATOR "TGZ;ZIP")
|
set (CPACK_GENERATOR "TGZ;ZIP")
|
||||||
set (CPACK_PACKAGE_FILE_NAME
|
set (CPACK_PACKAGE_FILE_NAME
|
||||||
"${PROJECT_NAME}-${project_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
|
"${PROJECT_NAME}-${PROJECT_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
|
||||||
set (CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME}-${project_VERSION}")
|
set (CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME}-${PROJECT_VERSION}")
|
||||||
set (CPACK_SOURCE_GENERATOR "TGZ;ZIP")
|
set (CPACK_SOURCE_GENERATOR "TGZ;ZIP")
|
||||||
set (CPACK_SOURCE_IGNORE_FILES "/\\\\.git;/build;/CMakeLists.txt.user")
|
set (CPACK_SOURCE_IGNORE_FILES "/\\\\.git;/build;/CMakeLists.txt.user")
|
||||||
set (CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${project_VERSION}")
|
set (CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}")
|
||||||
|
|
||||||
include (CPack)
|
include (CPack)
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2014 - 2020, Přemysl Eric Janouch <p@janouch.name>
|
Copyright (c) 2014 - 2022, Přemysl Eric Janouch <p@janouch.name>
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
purpose with or without fee is hereby granted.
|
purpose with or without fee is hereby granted.
|
||||||
|
|||||||
19
NEWS
19
NEWS
@@ -1,3 +1,22 @@
|
|||||||
|
1.2.0 (2024-12-24)
|
||||||
|
|
||||||
|
* Add a backend for co-processes, such as language servers
|
||||||
|
|
||||||
|
* Support reading OpenRPC documents from a file
|
||||||
|
|
||||||
|
* Respect the NO_COLOR environment variable
|
||||||
|
|
||||||
|
* Miscellaneous libedit (editline) fixes
|
||||||
|
|
||||||
|
* Miscellaneous portability improvements
|
||||||
|
|
||||||
|
* json-rpc-test-server: implement OpenRPC discovery
|
||||||
|
|
||||||
|
* json-rpc-test-server: only serve regular files
|
||||||
|
|
||||||
|
* json-rpc-test-server: miscellaneous WebSocket fixes
|
||||||
|
|
||||||
|
|
||||||
1.1.0 (2020-10-13)
|
1.1.0 (2020-10-13)
|
||||||
|
|
||||||
* Add method name tab completion using OpenRPC information
|
* Add method name tab completion using OpenRPC information
|
||||||
|
|||||||
23
README.adoc
23
README.adoc
@@ -5,7 +5,7 @@ json-rpc-shell
|
|||||||
'json-rpc-shell' is a shell for running JSON-RPC 2.0 queries.
|
'json-rpc-shell' is a shell for running JSON-RPC 2.0 queries.
|
||||||
|
|
||||||
This software was originally created as a replacement for
|
This software was originally created as a replacement for
|
||||||
http://software.dzhuvinov.com/json-rpc-2.0-shell.html[a different one] made by
|
http://software.dzhuvinov.com/json-rpc-2.0-shell.html[a different shell] made by
|
||||||
Vladimir Dzhuvinov, in order to avoid Java, but has evolved since.
|
Vladimir Dzhuvinov, in order to avoid Java, but has evolved since.
|
||||||
|
|
||||||
Features
|
Features
|
||||||
@@ -29,19 +29,17 @@ The rest of this README will concern itself with externalities.
|
|||||||
|
|
||||||
Packages
|
Packages
|
||||||
--------
|
--------
|
||||||
Regular releases are sporadic. git master should be stable enough. You can get
|
Regular releases are sporadic. git master should be stable enough.
|
||||||
a package with the latest development version from Archlinux's AUR.
|
You can get a package with the latest development version using Arch Linux's
|
||||||
|
https://aur.archlinux.org/packages/json-rpc-shell-git[AUR],
|
||||||
|
or as a https://git.janouch.name/p/nixexprs[Nix derivation].
|
||||||
|
|
||||||
Building
|
Building
|
||||||
--------
|
--------
|
||||||
Build dependencies: CMake, pkg-config, asciidoctor,
|
Build dependencies: CMake, pkg-config, liberty (included),
|
||||||
liberty (included), http-parser (included) +
|
http-parser (included), asciidoctor or asciidoc (recommended but optional) +
|
||||||
Runtime dependencies: libev, Jansson, cURL, openssl,
|
Runtime dependencies:
|
||||||
readline or libedit >= 2013-07-12,
|
libev, Jansson, cURL, openssl, readline or libedit >= 2013-07-12
|
||||||
|
|
||||||
Avoid libedit if you can, in general it works but at the moment history is
|
|
||||||
acting up and I have no clue about fixing it. Multiline editing is also
|
|
||||||
misbehaving there.
|
|
||||||
|
|
||||||
$ git clone --recursive https://git.janouch.name/p/json-rpc-shell.git
|
$ git clone --recursive https://git.janouch.name/p/json-rpc-shell.git
|
||||||
$ mkdir json-rpc-shell/build
|
$ mkdir json-rpc-shell/build
|
||||||
@@ -58,9 +56,6 @@ Or you can try telling CMake to make a package for you. For Debian it is:
|
|||||||
$ cpack -G DEB
|
$ cpack -G DEB
|
||||||
# dpkg -i json-rpc-shell-*.deb
|
# dpkg -i json-rpc-shell-*.deb
|
||||||
|
|
||||||
Note that for versions of CMake before 2.8.9, you need to prefix `cpack` with
|
|
||||||
`fakeroot` or file ownership will end up wrong.
|
|
||||||
|
|
||||||
Test server
|
Test server
|
||||||
-----------
|
-----------
|
||||||
If you install development packages for libmagic, an included test server will
|
If you install development packages for libmagic, an included test server will
|
||||||
|
|||||||
@@ -5,14 +5,16 @@
|
|||||||
|
|
||||||
# Some distributions do add it, though
|
# Some distributions do add it, though
|
||||||
find_package (PkgConfig REQUIRED)
|
find_package (PkgConfig REQUIRED)
|
||||||
pkg_check_modules (LIBEV QUIET libev)
|
pkg_check_modules (LibEV QUIET libev)
|
||||||
|
|
||||||
if (NOT LIBEV_FOUND)
|
set (required_vars LibEV_LIBRARIES)
|
||||||
find_path (LIBEV_INCLUDE_DIRS ev.h)
|
if (NOT LibEV_FOUND)
|
||||||
find_library (LIBEV_LIBRARIES NAMES ev)
|
find_path (LibEV_INCLUDE_DIRS ev.h)
|
||||||
|
find_library (LibEV_LIBRARIES NAMES ev)
|
||||||
|
list (APPEND required_vars LibEV_INCLUDE_DIRS)
|
||||||
|
endif ()
|
||||||
|
|
||||||
if (LIBEV_INCLUDE_DIRS AND LIBEV_LIBRARIES)
|
include (FindPackageHandleStandardArgs)
|
||||||
set (LIBEV_FOUND TRUE)
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS (LibEV DEFAULT_MSG ${required_vars})
|
||||||
endif (LIBEV_INCLUDE_DIRS AND LIBEV_LIBRARIES)
|
|
||||||
endif (NOT LIBEV_FOUND)
|
|
||||||
|
|
||||||
|
mark_as_advanced (LibEV_LIBRARIES LibEV_INCLUDE_DIRS)
|
||||||
|
|||||||
@@ -2,10 +2,12 @@
|
|||||||
#define CONFIG_H
|
#define CONFIG_H
|
||||||
|
|
||||||
#define PROGRAM_NAME "${PROJECT_NAME}"
|
#define PROGRAM_NAME "${PROJECT_NAME}"
|
||||||
#define PROGRAM_VERSION "${project_VERSION}"
|
#define PROGRAM_VERSION "${PROJECT_VERSION}"
|
||||||
|
|
||||||
#cmakedefine HAVE_READLINE
|
#cmakedefine HAVE_READLINE
|
||||||
#cmakedefine HAVE_EDITLINE
|
#cmakedefine HAVE_EDITLINE
|
||||||
|
|
||||||
|
#cmakedefine01 ICONV_ACCEPTS_TRANSLIT
|
||||||
|
|
||||||
#endif // ! CONFIG_H
|
#endif // ! CONFIG_H
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ Synopsis
|
|||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
|
:colon: :
|
||||||
The _ENDPOINT_ must be either an HTTP or a WebSocket URL, with or without TLS
|
The _ENDPOINT_ must be either an HTTP or a WebSocket URL, with or without TLS
|
||||||
(i.e. one of the _+++http+++://_, _+++https+++://_, _ws://_, _wss://_ schemas).
|
(i.e. one of the _http{colon}//_, _https{colon}//_, _ws://_, _wss://_ schemas).
|
||||||
|
|
||||||
*json-rpc-shell* will use it to send any JSON-RPC 2.0 requests you enter on its
|
*json-rpc-shell* will use it to send any JSON-RPC 2.0 requests you enter on its
|
||||||
command line. The server's response will be parsed and validated, stripping it
|
command line. The server's response will be parsed and validated, stripping it
|
||||||
@@ -96,8 +97,16 @@ Program information
|
|||||||
*--write-default-cfg*[**=**__PATH__]::
|
*--write-default-cfg*[**=**__PATH__]::
|
||||||
Write a default configuration file, show its path and exit.
|
Write a default configuration file, show its path and exit.
|
||||||
|
|
||||||
|
Environment
|
||||||
|
-----------
|
||||||
|
*VISUAL*, *EDITOR*::
|
||||||
|
The editor program to be launched by the M-e key binding.
|
||||||
|
If neither variable is set, it defaults to *vi*(1).
|
||||||
|
|
||||||
Files
|
Files
|
||||||
-----
|
-----
|
||||||
|
*json-rpc-shell* follows the XDG Base Directory Specification.
|
||||||
|
|
||||||
_~/.config/json-rpc-shell/json-rpc-shell.conf_::
|
_~/.config/json-rpc-shell/json-rpc-shell.conf_::
|
||||||
The configuration file, in which you can configure color output and
|
The configuration file, in which you can configure color output and
|
||||||
CA certificate paths. Use the *--write-default-cfg* option to create
|
CA certificate paths. Use the *--write-default-cfg* option to create
|
||||||
@@ -132,8 +141,7 @@ the higher-level protocol (the "Sec-Ws-Protocol" HTTP field).
|
|||||||
|
|
||||||
Bugs
|
Bugs
|
||||||
----
|
----
|
||||||
The editline (libedit) frontend is more of a proof of concept that mostly seems
|
The editline (libedit) frontend may exhibit some unexpected behaviour.
|
||||||
to work but exhibits bugs that are not our fault.
|
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* json-rpc-shell.c: a shell for JSON-RPC 2.0
|
* json-rpc-shell.c: a shell for JSON-RPC 2.0
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014 - 2020, Přemysl Eric Janouch <p@janouch.name>
|
* Copyright (c) 2014 - 2022, Přemysl Eric Janouch <p@janouch.name>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted.
|
* purpose with or without fee is hereby granted.
|
||||||
@@ -515,6 +515,7 @@ struct input_el
|
|||||||
char *entered_line; ///< Buffers the entered line
|
char *entered_line; ///< Buffers the entered line
|
||||||
|
|
||||||
bool active; ///< Interface has been started
|
bool active; ///< Interface has been started
|
||||||
|
bool need_restart; ///< Need to clear history state
|
||||||
char *prompt; ///< The prompt we use
|
char *prompt; ///< The prompt we use
|
||||||
int prompt_shown; ///< Whether the prompt is shown now
|
int prompt_shown; ///< Whether the prompt is shown now
|
||||||
|
|
||||||
@@ -535,27 +536,29 @@ input_el_wcstombs (const wchar_t *s)
|
|||||||
return mb;
|
return mb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
input_el_get_termios (int character, int fallback)
|
|
||||||
{
|
|
||||||
if (!g_terminal.initialized)
|
|
||||||
return fallback;
|
|
||||||
|
|
||||||
cc_t value = g_terminal.termios.c_cc[character];
|
|
||||||
if (value == _POSIX_VDISABLE)
|
|
||||||
return fallback;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
input_el_redisplay (struct input_el *self)
|
input_el_redisplay (struct input_el *self)
|
||||||
{
|
{
|
||||||
char x[] = { input_el_get_termios (VREPRINT, 'R' - 0x40), 0 };
|
// See rl_redisplay(), however NetBSD editline's map.c v1.54 breaks VREPRINT
|
||||||
el_push (self->editline, x);
|
// so we bind redisplay somewhere else in input_el_start()
|
||||||
|
wchar_t x[] = { L'q' & 31, 0 };
|
||||||
|
el_wpush (self->editline, x);
|
||||||
|
|
||||||
// We have to do this or it gets stuck and nothing is done
|
// We have to do this or it gets stuck and nothing is done
|
||||||
int count = 0;
|
int dummy_count = 0;
|
||||||
(void) el_wgets (self->editline, &count);
|
(void) el_wgets (self->editline, &dummy_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Editline keeping its own history position (look for "eventno" there).
|
||||||
|
// This is the only sane way of resetting it.
|
||||||
|
static void
|
||||||
|
input_el_start_over (struct input_el *self)
|
||||||
|
{
|
||||||
|
wchar_t x[] = { L'c' & 31, 0 };
|
||||||
|
el_wpush (self->editline, x);
|
||||||
|
|
||||||
|
int dummy_count = 0;
|
||||||
|
(void) el_wgets (self->editline, &dummy_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
@@ -598,7 +601,7 @@ input_el_on_return (EditLine *editline, int key)
|
|||||||
int len = info->lastchar - info->buffer;
|
int len = info->lastchar - info->buffer;
|
||||||
int point = info->cursor - info->buffer;
|
int point = info->cursor - info->buffer;
|
||||||
|
|
||||||
wchar_t *line = calloc (sizeof *info->buffer, len + 1);
|
wchar_t *line = xcalloc (len + 1, sizeof *info->buffer);
|
||||||
memcpy (line, info->buffer, sizeof *info->buffer * len);
|
memcpy (line, info->buffer, sizeof *info->buffer * len);
|
||||||
|
|
||||||
if (*line)
|
if (*line)
|
||||||
@@ -613,13 +616,14 @@ input_el_on_return (EditLine *editline, int key)
|
|||||||
self->entered_line = xstrndup
|
self->entered_line = xstrndup
|
||||||
(info_mb->buffer, info_mb->lastchar - info_mb->buffer);
|
(info_mb->buffer, info_mb->lastchar - info_mb->buffer);
|
||||||
|
|
||||||
// Now we need to force editline to actually print the newline
|
// Now we need to force editline into actually printing the newline
|
||||||
el_cursor (editline, len++ - point);
|
el_cursor (editline, len++ - point);
|
||||||
el_insertstr (editline, "\n");
|
el_insertstr (editline, "\n");
|
||||||
input_el_redisplay (self);
|
input_el_redisplay (self);
|
||||||
|
|
||||||
// Finally we need to discard the old line's contents
|
// Finally we need to discard the old line's contents
|
||||||
el_wdeletestr (editline, len);
|
el_wdeletestr (editline, len);
|
||||||
|
self->need_restart = true;
|
||||||
return CC_NEWLINE;
|
return CC_NEWLINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -698,6 +702,11 @@ input_el_start (struct input *input, const char *program_name)
|
|||||||
// Source the user's defaults file
|
// Source the user's defaults file
|
||||||
el_source (self->editline, NULL);
|
el_source (self->editline, NULL);
|
||||||
|
|
||||||
|
// See input_el_redisplay(), functionally important
|
||||||
|
el_set (self->editline, EL_BIND, "^q", "ed-redisplay", NULL);
|
||||||
|
// This is what buffered el_wgets() does, functionally important
|
||||||
|
el_set (self->editline, EL_BIND, "^c", "ed-start-over", NULL);
|
||||||
|
|
||||||
self->active = true;
|
self->active = true;
|
||||||
self->prompt_shown = 1;
|
self->prompt_shown = 1;
|
||||||
}
|
}
|
||||||
@@ -753,7 +762,7 @@ input_el_hide (struct input *input)
|
|||||||
int len = info->lastchar - info->buffer;
|
int len = info->lastchar - info->buffer;
|
||||||
int point = info->cursor - info->buffer;
|
int point = info->cursor - info->buffer;
|
||||||
|
|
||||||
wchar_t *line = calloc (sizeof *info->buffer, len + 1);
|
wchar_t *line = xcalloc (len + 1, sizeof *info->buffer);
|
||||||
memcpy (line, info->buffer, sizeof *info->buffer * len);
|
memcpy (line, info->buffer, sizeof *info->buffer * len);
|
||||||
el_cursor (self->editline, len - point);
|
el_cursor (self->editline, len - point);
|
||||||
el_wdeletestr (self->editline, len);
|
el_wdeletestr (self->editline, len);
|
||||||
@@ -985,6 +994,16 @@ input_el_on_tty_readable (struct input *input)
|
|||||||
// We bind the return key to process it how we need to
|
// We bind the return key to process it how we need to
|
||||||
struct input_el *self = (struct input_el *) input;
|
struct input_el *self = (struct input_el *) input;
|
||||||
|
|
||||||
|
int unbuffered = 0;
|
||||||
|
(void) el_get (self->editline, EL_UNBUFFERED, &unbuffered);
|
||||||
|
|
||||||
|
// We must invoke ch_reset(), which isn't done for us with EL_UNBUFFERED.
|
||||||
|
if (unbuffered && self->need_restart)
|
||||||
|
{
|
||||||
|
self->need_restart = false;
|
||||||
|
input_el_start_over (self);
|
||||||
|
}
|
||||||
|
|
||||||
// el_gets() with EL_UNBUFFERED doesn't work with UTF-8,
|
// el_gets() with EL_UNBUFFERED doesn't work with UTF-8,
|
||||||
// we must use the wide-character interface
|
// we must use the wide-character interface
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@@ -992,8 +1011,7 @@ input_el_on_tty_readable (struct input *input)
|
|||||||
|
|
||||||
// Editline works in a funny NO_TTY mode when the input is not a tty,
|
// Editline works in a funny NO_TTY mode when the input is not a tty,
|
||||||
// we cannot use EL_UNBUFFERED and expect sane results then
|
// we cannot use EL_UNBUFFERED and expect sane results then
|
||||||
int unbuffered = 0;
|
if (!unbuffered)
|
||||||
if (!el_get (self->editline, EL_UNBUFFERED, &unbuffered) && !unbuffered)
|
|
||||||
{
|
{
|
||||||
char *entered_line = buf ? input_el_wcstombs (buf) : NULL;
|
char *entered_line = buf ? input_el_wcstombs (buf) : NULL;
|
||||||
self->super.on_input (entered_line, self->super.user_data);
|
self->super.on_input (entered_line, self->super.user_data);
|
||||||
@@ -1207,7 +1225,7 @@ await_try_cancel (struct app_context *ctx)
|
|||||||
|
|
||||||
static void on_config_attribute_change (struct config_item *item);
|
static void on_config_attribute_change (struct config_item *item);
|
||||||
|
|
||||||
static struct config_schema g_config_connection[] =
|
static const struct config_schema g_config_connection[] =
|
||||||
{
|
{
|
||||||
{ .name = "tls_ca_file",
|
{ .name = "tls_ca_file",
|
||||||
.comment = "OpenSSL CA bundle file",
|
.comment = "OpenSSL CA bundle file",
|
||||||
@@ -1218,7 +1236,7 @@ static struct config_schema g_config_connection[] =
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct config_schema g_config_attributes[] =
|
static const struct config_schema g_config_attributes[] =
|
||||||
{
|
{
|
||||||
#define XX(x, y, z) { .name = y, .comment = z, .type = CONFIG_ITEM_STRING, \
|
#define XX(x, y, z) { .name = y, .comment = z, .type = CONFIG_ITEM_STRING, \
|
||||||
.on_change = on_config_attribute_change },
|
.on_change = on_config_attribute_change },
|
||||||
@@ -1425,7 +1443,7 @@ init_colors (struct app_context *ctx)
|
|||||||
g_terminal.stderr_is_tty = true;
|
g_terminal.stderr_is_tty = true;
|
||||||
break;
|
break;
|
||||||
case COLOR_AUTO:
|
case COLOR_AUTO:
|
||||||
if (!g_terminal.initialized)
|
if (!g_terminal.initialized || getenv ("NO_COLOR"))
|
||||||
{
|
{
|
||||||
case COLOR_NEVER:
|
case COLOR_NEVER:
|
||||||
g_terminal.stdout_is_tty = false;
|
g_terminal.stdout_is_tty = false;
|
||||||
@@ -3670,7 +3688,7 @@ complete_method_name (const char *text, int state)
|
|||||||
// --- Main program ------------------------------------------------------------
|
// --- Main program ------------------------------------------------------------
|
||||||
|
|
||||||
// The ability to use an external editor on the input line has been shamelessly
|
// The ability to use an external editor on the input line has been shamelessly
|
||||||
// copypasted from degesch with minor changes only.
|
// copypasted from xC with minor changes only.
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
dump_line_to_file (const char *line, char *template, struct error **e)
|
dump_line_to_file (const char *line, char *template, struct error **e)
|
||||||
@@ -4058,11 +4076,10 @@ main (int argc, char *argv[])
|
|||||||
setlocale (LC_CTYPE, "");
|
setlocale (LC_CTYPE, "");
|
||||||
|
|
||||||
char *encoding = nl_langinfo (CODESET);
|
char *encoding = nl_langinfo (CODESET);
|
||||||
#ifdef __linux__
|
|
||||||
// XXX: not quite sure if this is actually desirable
|
// XXX: not quite sure if this is actually desirable
|
||||||
// TODO: instead retry with JSON_ENSURE_ASCII
|
// TODO: instead retry with JSON_ENSURE_ASCII
|
||||||
encoding = xstrdup_printf ("%s//TRANSLIT", encoding);
|
if (ICONV_ACCEPTS_TRANSLIT)
|
||||||
#endif // __linux__
|
encoding = xstrdup_printf ("%s//TRANSLIT", encoding);
|
||||||
|
|
||||||
if ((g_ctx.term_from_utf8 = iconv_open (encoding, "UTF-8"))
|
if ((g_ctx.term_from_utf8 = iconv_open (encoding, "UTF-8"))
|
||||||
== (iconv_t) -1
|
== (iconv_t) -1
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* json-rpc-test-server.c: JSON-RPC 2.0 demo server
|
* json-rpc-test-server.c: JSON-RPC 2.0 demo server
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015 - 2020, Přemysl Eric Janouch <p@janouch.name>
|
* Copyright (c) 2015 - 2022, Přemysl Eric Janouch <p@janouch.name>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted.
|
* purpose with or without fee is hereby granted.
|
||||||
@@ -1464,7 +1464,7 @@ json_rpc_discover (struct server_context *ctx, json_t *params)
|
|||||||
|
|
||||||
json_t *info = json_pack ("{ssss}",
|
json_t *info = json_pack ("{ssss}",
|
||||||
"title", PROGRAM_NAME, "version", PROGRAM_VERSION);
|
"title", PROGRAM_NAME, "version", PROGRAM_VERSION);
|
||||||
json_t *methods = json_pack ("[ooo]",
|
json_t *methods = json_pack ("[oooo]",
|
||||||
open_rpc_describe ("date", json_pack ("{ssso}", "type", "object",
|
open_rpc_describe ("date", json_pack ("{ssso}", "type", "object",
|
||||||
"properties", json_pack ("{s{ss}s{ss}s{ss}s{ss}s{ss}s{ss}}",
|
"properties", json_pack ("{s{ss}s{ss}s{ss}s{ss}s{ss}s{ss}}",
|
||||||
"year", "type", "number",
|
"year", "type", "number",
|
||||||
@@ -1475,7 +1475,8 @@ json_rpc_discover (struct server_context *ctx, json_t *params)
|
|||||||
"seconds", "type", "number"))),
|
"seconds", "type", "number"))),
|
||||||
open_rpc_describe ("ping", json_pack ("{ss}", "type", "string")),
|
open_rpc_describe ("ping", json_pack ("{ss}", "type", "string")),
|
||||||
open_rpc_describe ("rpc.discover", json_pack ("{ss}", "$ref",
|
open_rpc_describe ("rpc.discover", json_pack ("{ss}", "$ref",
|
||||||
"https://github.com/open-rpc/meta-schema/raw/master/schema.json")));
|
"https://github.com/open-rpc/meta-schema/raw/master/schema.json")),
|
||||||
|
open_rpc_describe ("wait", json_pack ("{ss}", "type", "null")));
|
||||||
return json_rpc_response (NULL, json_pack ("{sssoso}",
|
return json_rpc_response (NULL, json_pack ("{sssoso}",
|
||||||
"openrpc", "1.2.6", "info", info, "methods", methods), NULL);
|
"openrpc", "1.2.6", "info", info, "methods", methods), NULL);
|
||||||
}
|
}
|
||||||
@@ -1492,6 +1493,16 @@ json_rpc_ping (struct server_context *ctx, json_t *params)
|
|||||||
return json_rpc_response (NULL, json_string ("pong"), NULL);
|
return json_rpc_response (NULL, json_string ("pong"), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static json_t *
|
||||||
|
json_rpc_wait (struct server_context *ctx, json_t *params)
|
||||||
|
{
|
||||||
|
(void) ctx;
|
||||||
|
(void) params;
|
||||||
|
|
||||||
|
sleep (1);
|
||||||
|
return json_rpc_response (NULL, json_null (), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static json_t *
|
static json_t *
|
||||||
json_rpc_date (struct server_context *ctx, json_t *params)
|
json_rpc_date (struct server_context *ctx, json_t *params)
|
||||||
{
|
{
|
||||||
@@ -1524,6 +1535,7 @@ process_json_rpc_request (struct server_context *ctx, json_t *request)
|
|||||||
{ "date", json_rpc_date },
|
{ "date", json_rpc_date },
|
||||||
{ "ping", json_rpc_ping },
|
{ "ping", json_rpc_ping },
|
||||||
{ "rpc.discover", json_rpc_discover },
|
{ "rpc.discover", json_rpc_discover },
|
||||||
|
{ "wait", json_rpc_wait },
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!json_is_object (request))
|
if (!json_is_object (request))
|
||||||
|
|||||||
2
liberty
2
liberty
Submodule liberty updated: 69101eb155...1930f138d4
Reference in New Issue
Block a user