From 2b8a1b76920dbdfc39dab2ec29ab7650bf779275 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 10 Dec 2017 18:36:37 +0200 Subject: [PATCH] Support dynamic loading of libjansson on MS-Windows * src/json.c [WINDOWSNT]: Define fn_* function pointers to jansson functions. (json_delete) [WINDOWSNT]: A wrapper around fn_json_delete, needed by json_decref. (init_json_functions) [WINDOWSNT]: New function. (Fjson_serialize, Fjson_insert, Fjson_parse_string) (Fjson_parse_buffer) [WINDOWSNT]: Call init_json_functions if needed, and record JSON in Vlibrary_cache. * src/emacs.c (main): Don't call init_json on WINDOWSNT. * src/w32fns.c (syms_of_w32fns): DEFSYM "json". * lisp/term/w32-win.el (dynamic-library-alist): Add JSON DLL to the list. * configure.ac (HAVE_JSON): Empty JSON_LIBS for MinGW. * nt/INSTALL.W64: * nt/INSTALL: Add information about libjansson. --- configure.ac | 5 ++ lisp/term/w32-win.el | 3 +- nt/INSTALL | 7 ++ nt/INSTALL.W64 | 1 + src/emacs.c | 2 +- src/json.c | 181 +++++++++++++++++++++++++++++++++++++++++++ src/w32fns.c | 1 + 7 files changed, 198 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index caee0159548..562b19afe64 100644 --- a/configure.ac +++ b/configure.ac @@ -2881,6 +2881,11 @@ if test "${with_json}" = yes; then AC_DEFINE(HAVE_JSON, 1, [Define if using Jansson.]) JSON_OBJ=json.o fi + + # Windows loads libjansson dynamically + if test "${opsys}" = "mingw32"; then + JSON_LIBS= + fi fi AC_SUBST(JSON_LIBS) diff --git a/lisp/term/w32-win.el b/lisp/term/w32-win.el index 4e0e54ae179..1db90aec984 100644 --- a/lisp/term/w32-win.el +++ b/lisp/term/w32-win.el @@ -276,7 +276,8 @@ See the documentation of `create-fontset-from-fontset-spec' for the format.") '(gnutls "libgnutls-28.dll" "libgnutls-26.dll")) '(libxml2 "libxml2-2.dll" "libxml2.dll") '(zlib "zlib1.dll" "libz-1.dll") - '(lcms2 "liblcms2-2.dll"))) + '(lcms2 "liblcms2-2.dll") + '(json "libjansson-4.dll"))) ;;; multi-tty support (defvar w32-initialized nil diff --git a/nt/INSTALL b/nt/INSTALL index 30e14293f5c..361d607ff68 100644 --- a/nt/INSTALL +++ b/nt/INSTALL @@ -806,6 +806,13 @@ build will run on Windows 9X and newer systems). Prebuilt binaries of lcms2 DLL (for 32-bit builds of Emacs) are available from the ezwinports site and from the MSYS2 project. +* Optional support for JSON + + Emacs can provide built-in support for JSON parsing and + serialization using the libjansson library. Prebuilt binaries of + the libjansson DLL (for 32-bit builds of Emacs) are available from + the ezwinports site and from the MSYS2 project. + This file is part of GNU Emacs. diff --git a/nt/INSTALL.W64 b/nt/INSTALL.W64 index e08b72f2ca0..41d57bd3689 100644 --- a/nt/INSTALL.W64 +++ b/nt/INSTALL.W64 @@ -52,6 +52,7 @@ packages (you can copy and paste it into the shell with Shift + Insert): mingw-w64-x86_64-libjpeg-turbo \ mingw-w64-x86_64-librsvg \ mingw-w64-x86_64-lcms2 \ + mingw-w64-x86_64-jansson \ mingw-w64-x86_64-libxml2 \ mingw-w64-x86_64-gnutls \ mingw-w64-x86_64-zlib diff --git a/src/emacs.c b/src/emacs.c index 7c1ae1f2c5b..5a6b896ef47 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1262,7 +1262,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem running_asynch_code = 0; init_random (); -#ifdef HAVE_JSON +#if defined HAVE_JSON && !defined WINDOWSNT init_json (); #endif diff --git a/src/json.c b/src/json.c index dc449e43e11..7025ae165cd 100644 --- a/src/json.c +++ b/src/json.c @@ -30,6 +30,126 @@ along with GNU Emacs. If not, see . */ #include "buffer.h" #include "coding.h" +#ifdef WINDOWSNT +# include +# include "w32.h" + +DEF_DLL_FN (void, json_set_alloc_funcs, + (json_malloc_t malloc_fn, json_free_t free_fn)); +DEF_DLL_FN (void, json_delete, (json_t *json)); +DEF_DLL_FN (json_t *, json_array, (void)); +DEF_DLL_FN (int, json_array_append_new, (json_t *array, json_t *value)); +DEF_DLL_FN (size_t, json_array_size, (const json_t *array)); +DEF_DLL_FN (json_t *, json_object, (void)); +DEF_DLL_FN (int, json_object_set_new, + (json_t *object, const char *key, json_t *value)); +DEF_DLL_FN (json_t *, json_null, (void)); +DEF_DLL_FN (json_t *, json_true, (void)); +DEF_DLL_FN (json_t *, json_false, (void)); +DEF_DLL_FN (json_t *, json_integer, (json_int_t value)); +DEF_DLL_FN (json_t *, json_real, (double value)); +DEF_DLL_FN (json_t *, json_stringn, (const char *value, size_t len)); +DEF_DLL_FN (char *, json_dumps, (const json_t *json, size_t flags)); +DEF_DLL_FN (int, json_dump_callback, + (const json_t *json, json_dump_callback_t callback, void *data, + size_t flags)); +DEF_DLL_FN (json_int_t, json_integer_value, (const json_t *integer)); +DEF_DLL_FN (double, json_real_value, (const json_t *real)); +DEF_DLL_FN (const char *, json_string_value, (const json_t *string)); +DEF_DLL_FN (size_t, json_string_length, (const json_t *string)); +DEF_DLL_FN (json_t *, json_array_get, (const json_t *array, size_t index)); +DEF_DLL_FN (size_t, json_object_size, (const json_t *object)); +DEF_DLL_FN (const char *, json_object_iter_key, (void *iter)); +DEF_DLL_FN (void *, json_object_iter, (json_t *object)); +DEF_DLL_FN (json_t *, json_object_iter_value, (void *iter)); +DEF_DLL_FN (void *, json_object_key_to_iter, (const char *key)); +DEF_DLL_FN (void *, json_object_iter_next, (json_t *object, void *iter)); +DEF_DLL_FN (json_t *, json_loads, + (const char *input, size_t flags, json_error_t *error)); +DEF_DLL_FN (json_t *, json_load_callback, + (json_load_callback_t callback, void *data, size_t flags, + json_error_t *error)); + +/* This is called by json_decref, which is an inline function. */ +void json_delete(json_t *json) +{ + fn_json_delete (json); +} + +static bool json_initialized; + +static bool +init_json_functions (void) +{ + HMODULE library = w32_delayed_load (Qjson); + + if (!library) + return false; + + LOAD_DLL_FN (library, json_set_alloc_funcs); + LOAD_DLL_FN (library, json_delete); + LOAD_DLL_FN (library, json_array); + LOAD_DLL_FN (library, json_array_append_new); + LOAD_DLL_FN (library, json_array_size); + LOAD_DLL_FN (library, json_object); + LOAD_DLL_FN (library, json_object_set_new); + LOAD_DLL_FN (library, json_null); + LOAD_DLL_FN (library, json_true); + LOAD_DLL_FN (library, json_false); + LOAD_DLL_FN (library, json_integer); + LOAD_DLL_FN (library, json_real); + LOAD_DLL_FN (library, json_stringn); + LOAD_DLL_FN (library, json_dumps); + LOAD_DLL_FN (library, json_dump_callback); + LOAD_DLL_FN (library, json_integer_value); + LOAD_DLL_FN (library, json_real_value); + LOAD_DLL_FN (library, json_string_value); + LOAD_DLL_FN (library, json_string_length); + LOAD_DLL_FN (library, json_array_get); + LOAD_DLL_FN (library, json_object_size); + LOAD_DLL_FN (library, json_object_iter_key); + LOAD_DLL_FN (library, json_object_iter); + LOAD_DLL_FN (library, json_object_iter_value); + LOAD_DLL_FN (library, json_object_key_to_iter); + LOAD_DLL_FN (library, json_object_iter_next); + LOAD_DLL_FN (library, json_loads); + LOAD_DLL_FN (library, json_load_callback); + + init_json (); + + return true; +} + +#define json_set_alloc_funcs fn_json_set_alloc_funcs +#define json_array fn_json_array +#define json_array_append_new fn_json_array_append_new +#define json_array_size fn_json_array_size +#define json_object fn_json_object +#define json_object_set_new fn_json_object_set_new +#define json_null fn_json_null +#define json_true fn_json_true +#define json_false fn_json_false +#define json_integer fn_json_integer +#define json_real fn_json_real +#define json_stringn fn_json_stringn +#define json_dumps fn_json_dumps +#define json_dump_callback fn_json_dump_callback +#define json_integer_value fn_json_integer_value +#define json_real_value fn_json_real_value +#define json_string_value fn_json_string_value +#define json_string_length fn_json_string_length +#define json_array_get fn_json_array_get +#define json_object_size fn_json_object_size +#define json_object_iter_key fn_json_object_iter_key +#define json_object_iter fn_json_object_iter +#define json_object_iter_value fn_json_object_iter_value +#define json_object_key_to_iter fn_json_object_key_to_iter +#define json_object_iter_next fn_json_object_iter_next +#define json_loads fn_json_loads +#define json_load_callback fn_json_load_callback + +#endif /* WINDOWSNT */ + /* We install a custom allocator so that we can avoid objects larger than PTRDIFF_MAX. Such objects wouldn’t play well with the rest of Emacs’s codebase, which generally uses ptrdiff_t for sizes and @@ -277,6 +397,21 @@ each object. */) { ptrdiff_t count = SPECPDL_INDEX (); +#ifdef WINDOWSNT + if (!json_initialized) + { + Lisp_Object status; + json_initialized = init_json_functions (); + status = json_initialized ? Qt : Qnil; + Vlibrary_cache = Fcons (Fcons (Qjson, status), Vlibrary_cache); + } + if (!json_initialized) + { + message1 ("jansson library not found"); + return Qnil; + } +#endif + json_t *json = lisp_to_json_toplevel (object); record_unwind_protect_ptr (json_release_object, json); @@ -340,6 +475,21 @@ OBJECT. */) { ptrdiff_t count = SPECPDL_INDEX (); +#ifdef WINDOWSNT + if (!json_initialized) + { + Lisp_Object status; + json_initialized = init_json_functions (); + status = json_initialized ? Qt : Qnil; + Vlibrary_cache = Fcons (Fcons (Qjson, status), Vlibrary_cache); + } + if (!json_initialized) + { + message1 ("jansson library not found"); + return Qnil; + } +#endif + json_t *json = lisp_to_json (object); record_unwind_protect_ptr (json_release_object, json); @@ -439,6 +589,22 @@ an error of type `json-parse-error' is signaled. */) (Lisp_Object string) { ptrdiff_t count = SPECPDL_INDEX (); + +#ifdef WINDOWSNT + if (!json_initialized) + { + Lisp_Object status; + json_initialized = init_json_functions (); + status = json_initialized ? Qt : Qnil; + Vlibrary_cache = Fcons (Fcons (Qjson, status), Vlibrary_cache); + } + if (!json_initialized) + { + message1 ("jansson library not found"); + return Qnil; + } +#endif + Lisp_Object encoded = json_encode (string); check_string_without_embedded_nulls (encoded); @@ -493,6 +659,21 @@ not moved. */) { ptrdiff_t count = SPECPDL_INDEX (); +#ifdef WINDOWSNT + if (!json_initialized) + { + Lisp_Object status; + json_initialized = init_json_functions (); + status = json_initialized ? Qt : Qnil; + Vlibrary_cache = Fcons (Fcons (Qjson, status), Vlibrary_cache); + } + if (!json_initialized) + { + message1 ("jansson library not found"); + return Qnil; + } +#endif + ptrdiff_t point = PT_BYTE; struct json_read_buffer_data data = {.point = point}; json_error_t error; diff --git a/src/w32fns.c b/src/w32fns.c index d2d4b2c7355..90d09542c45 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -10418,6 +10418,7 @@ syms_of_w32fns (void) DEFSYM (Qserif, "serif"); DEFSYM (Qzlib, "zlib"); DEFSYM (Qlcms2, "lcms2"); + DEFSYM (Qjson, "json"); Fput (Qundefined_color, Qerror_conditions, listn (CONSTYPE_PURE, 2, Qundefined_color, Qerror)); -- 2.39.5