diff --git a/Makefile.am b/Makefile.am index 7f694d755a..ad371c4247 100644 --- a/Makefile.am +++ b/Makefile.am @@ -403,8 +403,6 @@ shared_nm_glib_aux_libnm_glib_aux_la_SOURCES = \ shared/nm-glib-aux/nm-jansson.h \ shared/nm-glib-aux/nm-json-aux.c \ shared/nm-glib-aux/nm-json-aux.h \ - shared/nm-glib-aux/nm-json.c \ - shared/nm-glib-aux/nm-json.h \ shared/nm-glib-aux/nm-keyfile-aux.c \ shared/nm-glib-aux/nm-keyfile-aux.h \ shared/nm-glib-aux/nm-logging-base.c \ diff --git a/libnm-core/nm-team-utils.c b/libnm-core/nm-team-utils.c index ec820e99e9..ccdefecbf7 100644 --- a/libnm-core/nm-team-utils.c +++ b/libnm-core/nm-team-utils.c @@ -11,7 +11,6 @@ #include "nm-errors.h" #include "nm-utils-private.h" -#include "nm-glib-aux/nm-json.h" #include "nm-glib-aux/nm-json-aux.h" #include "nm-core-internal.h" #include "nm-setting-team.h" diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 069c00e77c..b633a5099c 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -16,7 +16,7 @@ #include #include -#include "nm-glib-aux/nm-json.h" +#include "nm-glib-aux/nm-json-aux.h" #include "nm-glib-aux/nm-str-buf.h" #include "nm-glib-aux/nm-enum-utils.h" #include "nm-glib-aux/nm-time-utils.h" diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 0d2629eabe..1e4efe2452 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -14,7 +14,7 @@ #include "nm-std-aux/c-list-util.h" #include "nm-glib-aux/nm-enum-utils.h" #include "nm-glib-aux/nm-str-buf.h" -#include "nm-glib-aux/nm-json.h" +#include "nm-glib-aux/nm-json-aux.h" #include "systemd/nm-sd-utils-shared.h" #include "nm-utils.h" diff --git a/libnm-core/tests/test-keyfile.c b/libnm-core/tests/test-keyfile.c index c740a9068d..c9ec51f01b 100644 --- a/libnm-core/tests/test-keyfile.c +++ b/libnm-core/tests/test-keyfile.c @@ -5,7 +5,7 @@ #include "nm-default.h" -#include "nm-glib-aux/nm-json.h" +#include "nm-glib-aux/nm-json-aux.h" #include "nm-keyfile/nm-keyfile-utils.h" #include "nm-keyfile/nm-keyfile-internal.h" #include "nm-simple-connection.h" diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c index 3b59d7fa57..5ec0ccbdb1 100644 --- a/libnm-core/tests/test-setting.c +++ b/libnm-core/tests/test-setting.c @@ -8,7 +8,7 @@ #include #include -#include "nm-glib-aux/nm-json.h" +#include "nm-glib-aux/nm-json-aux.h" #include "nm-core-internal.h" #include "nm-utils.h" #include "nm-utils-private.h" diff --git a/shared/meson.build b/shared/meson.build index 0041c5cba3..0f46a00cbb 100644 --- a/shared/meson.build +++ b/shared/meson.build @@ -134,7 +134,6 @@ sources = files( 'nm-glib-aux/nm-hash-utils.c', 'nm-glib-aux/nm-io-utils.c', 'nm-glib-aux/nm-json-aux.c', - 'nm-glib-aux/nm-json.c', 'nm-glib-aux/nm-keyfile-aux.c', 'nm-glib-aux/nm-logging-base.c', 'nm-glib-aux/nm-random-utils.c', diff --git a/shared/nm-glib-aux/nm-json-aux.c b/shared/nm-glib-aux/nm-json-aux.c index afa92531c6..17a70edf75 100644 --- a/shared/nm-glib-aux/nm-json-aux.c +++ b/shared/nm-glib-aux/nm-json-aux.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: LGPL-2.1+ /* - * Copyright (C) 2019 Red Hat, Inc. + * Copyright (C) 2017 - 2019 Red Hat, Inc. */ #include "nm-default.h" #include "nm-json-aux.h" +#include + /*****************************************************************************/ static void @@ -133,3 +135,129 @@ nm_json_aux_gstr_append_obj_name (GString *gstr, } else g_string_append (gstr, ": "); } + +/*****************************************************************************/ + +typedef struct { + NMJsonVt vt; + void *dl_handle; +} NMJsonVtInternal; + +static NMJsonVtInternal * +_nm_json_vt_internal_load (void) +{ + NMJsonVtInternal *v; + void *handle = NULL; + int mode; + + v = g_new0 (NMJsonVtInternal, 1); + +#ifndef JANSSON_SONAME +#define JANSSON_SONAME "" +#endif + + mode = RTLD_LAZY | RTLD_LOCAL | RTLD_NODELETE | RTLD_DEEPBIND; +#if defined (ASAN_BUILD) + /* Address sanitizer is incompatible with RTLD_DEEPBIND. */ + mode &= ~RTLD_DEEPBIND; +#endif + + if (strlen (JANSSON_SONAME) > 0) + handle = dlopen (JANSSON_SONAME, mode); + + if (!handle) + return v; + +#define TRY_BIND_SYMBOL(symbol) \ + G_STMT_START { \ + void *_sym = dlsym (handle, #symbol); \ + \ + if (!_sym) \ + goto fail_symbol; \ + v->vt.nm_ ## symbol = _sym; \ + } G_STMT_END + + TRY_BIND_SYMBOL (json_array); + TRY_BIND_SYMBOL (json_array_append_new); + TRY_BIND_SYMBOL (json_array_get); + TRY_BIND_SYMBOL (json_array_size); + TRY_BIND_SYMBOL (json_delete); + TRY_BIND_SYMBOL (json_dumps); + TRY_BIND_SYMBOL (json_false); + TRY_BIND_SYMBOL (json_integer); + TRY_BIND_SYMBOL (json_integer_value); + TRY_BIND_SYMBOL (json_loads); + TRY_BIND_SYMBOL (json_object); + TRY_BIND_SYMBOL (json_object_del); + TRY_BIND_SYMBOL (json_object_get); + TRY_BIND_SYMBOL (json_object_iter); + TRY_BIND_SYMBOL (json_object_iter_key); + TRY_BIND_SYMBOL (json_object_iter_next); + TRY_BIND_SYMBOL (json_object_iter_value); + TRY_BIND_SYMBOL (json_object_key_to_iter); + TRY_BIND_SYMBOL (json_object_set_new); + TRY_BIND_SYMBOL (json_object_size); + TRY_BIND_SYMBOL (json_string); + TRY_BIND_SYMBOL (json_string_value); + TRY_BIND_SYMBOL (json_true); + + v->vt.loaded = TRUE; + v->dl_handle = handle; + return v; + +fail_symbol: + dlclose (&handle); + *v = (NMJsonVtInternal) { }; + return v; +} + +const NMJsonVt *_nm_json_vt_ptr = NULL; + +const NMJsonVt * +_nm_json_vt_init (void) +{ + NMJsonVtInternal *v; + +again: + v = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr); + if (G_UNLIKELY (!v)) { + v = _nm_json_vt_internal_load (); + if (!g_atomic_pointer_compare_and_exchange ((gpointer *) &_nm_json_vt_ptr, NULL, v)) { + if (v->dl_handle) + dlclose (v->dl_handle); + g_free (v); + goto again; + } + + /* we transfer ownership. */ + } + + nm_assert (v && v == g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr)); + return &v->vt; +} + +const NMJsonVt * +nmtst_json_vt_reset (gboolean loaded) +{ + NMJsonVtInternal *v_old; + NMJsonVtInternal *v; + + v_old = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr); + + if (!loaded) { + /* load a fake instance for testing. */ + v = g_new0 (NMJsonVtInternal, 1); + } else + v = _nm_json_vt_internal_load (); + + if (!g_atomic_pointer_compare_and_exchange ((gpointer *) &_nm_json_vt_ptr, v_old, v)) + g_assert_not_reached (); + + if (v_old) { + if (v_old->dl_handle) + dlclose (v_old->dl_handle); + g_free ((gpointer *) v_old); + } + + return v->vt.loaded ? &v->vt : NULL; +} diff --git a/shared/nm-glib-aux/nm-json-aux.h b/shared/nm-glib-aux/nm-json-aux.h index ed3be3768f..def96b6a7c 100644 --- a/shared/nm-glib-aux/nm-json-aux.h +++ b/shared/nm-glib-aux/nm-json-aux.h @@ -1,11 +1,13 @@ // SPDX-License-Identifier: LGPL-2.1+ /* - * Copyright (C) 2019 Red Hat, Inc. + * Copyright (C) 2017 - 2019 Red Hat, Inc. */ #ifndef __NM_JSON_AUX_H__ #define __NM_JSON_AUX_H__ +#include "nm-value-type.h" + /*****************************************************************************/ static inline GString * @@ -42,8 +44,238 @@ void nm_json_aux_gstr_append_obj_name (GString *gstr, /*****************************************************************************/ +#define NM_JSON_REJECT_DUPLICATES 0x1 + +typedef enum { + NM_JSON_OBJECT, + NM_JSON_ARRAY, + NM_JSON_STRING, + NM_JSON_INTEGER, + NM_JSON_REAL, + NM_JSON_TRUE, + NM_JSON_FALSE, + NM_JSON_NULL, +} nm_json_type; + +typedef struct nm_json_t { + nm_json_type type; + volatile size_t refcount; +} nm_json_t; + +typedef long long nm_json_int_t; + +#define NM_JSON_ERROR_TEXT_LENGTH 160 +#define NM_JSON_ERROR_SOURCE_LENGTH 80 + +typedef struct nm_json_error_t { + int line; + int column; + int position; + char source[NM_JSON_ERROR_SOURCE_LENGTH]; + char text[NM_JSON_ERROR_TEXT_LENGTH]; +} nm_json_error_t; + +typedef struct { + gboolean loaded; + char *(*nm_json_dumps) (const nm_json_t *json, size_t flags); + const char *(*nm_json_object_iter_key) (void *iter); + const char *(*nm_json_string_value) (const nm_json_t *json); + int (*nm_json_array_append_new) (nm_json_t *json, nm_json_t *value); + int (*nm_json_object_del) (nm_json_t *json, const char *key); + int (*nm_json_object_set_new) (nm_json_t *json, const char *key, nm_json_t *value); + nm_json_int_t (*nm_json_integer_value) (const nm_json_t *json); + nm_json_t *(*nm_json_array) (void); + nm_json_t *(*nm_json_array_get) (const nm_json_t *json, size_t index); + nm_json_t *(*nm_json_false) (void); + nm_json_t *(*nm_json_integer) (nm_json_int_t value); + nm_json_t *(*nm_json_loads) (const char *string, size_t flags, nm_json_error_t *error); + nm_json_t *(*nm_json_object) (void); + nm_json_t *(*nm_json_object_get) (const nm_json_t *json, const char *key); + nm_json_t *(*nm_json_object_iter_value) (void *); + nm_json_t *(*nm_json_string) (const char *value); + nm_json_t *(*nm_json_true) (void); + size_t (*nm_json_array_size) (const nm_json_t *json); + size_t (*nm_json_object_size) (const nm_json_t *json); + void (*nm_json_delete) (nm_json_t *json); + void *(*nm_json_object_iter) (nm_json_t *json); + void *(*nm_json_object_iter_next) (nm_json_t *json, void *iter); + void *(*nm_json_object_key_to_iter) (const char *key); +} NMJsonVt; + +extern const NMJsonVt *_nm_json_vt_ptr; + +const NMJsonVt *_nm_json_vt_init (void); + +static inline const NMJsonVt * +_nm_json_vt (void) +{ + const NMJsonVt *vt; + + vt = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr); + if (G_UNLIKELY (!vt)) { + vt = _nm_json_vt_init (); + nm_assert (vt); + } + return vt; +} + +static inline const NMJsonVt * +nm_json_vt (void) +{ + const NMJsonVt *vt; + + vt = _nm_json_vt(); + return vt->loaded ? vt : NULL; +} + +static inline const NMJsonVt * +nm_json_vt_assert (void) +{ + const NMJsonVt *vt; + + vt = _nm_json_vt(); + nm_assert (vt->loaded); + return vt; +} + +const NMJsonVt *nmtst_json_vt_reset (gboolean loaded); + +/*****************************************************************************/ + +#define nm_json_boolean(vt, val) \ + ((val) ? (vt)->nm_json_true () : (vt)->nm_json_false ()) + +static inline void +nm_json_decref (const NMJsonVt *vt, nm_json_t *json) +{ + /* Our ref-counting is not threadsafe, unlike libjansson's. But we never + * share one json_t instance between threads, and if we would, we would very likely + * wrap a mutex around it. */ + if ( json + && json->refcount != (size_t) -1 + && --json->refcount == 0) + vt->nm_json_delete (json); +} + +static inline void +_nm_auto_decref_json (nm_json_t **p_json) +{ + if ( *p_json + && (*p_json)->refcount != (size_t) -1 + && --(*p_json)->refcount == 0) + nm_json_vt ()->nm_json_delete (*p_json); +} + +#define nm_auto_decref_json nm_auto(_nm_auto_decref_json) + +/*****************************************************************************/ + +/* the following are implemented as pure macros in jansson.h. + * They can be used directly, however, add a nm_json* variant, + * to make it explict we don't accidentally use jansson ABI. */ + +#define nm_json_typeof(json) ((json)->type) +#define nm_json_is_object(json) ((json) && nm_json_typeof(json) == NM_JSON_OBJECT) +#define nm_json_is_array(json) ((json) && nm_json_typeof(json) == NM_JSON_ARRAY) +#define nm_json_is_string(json) ((json) && nm_json_typeof(json) == NM_JSON_STRING) +#define nm_json_is_integer(json) ((json) && nm_json_typeof(json) == NM_JSON_INTEGER) +#define nm_json_is_real(json) ((json) && nm_json_typeof(json) == NM_JSON_REAL) +#define nm_json_is_number(json) (nm_json_is_integer(json) || nm_json_is_real(json)) +#define nm_json_is_true(json) ((json) && nm_json_typeof(json) == NM_JSON_TRUE) +#define nm_json_is_false(json) ((json) && nm_json_typeof(json) == NM_JSON_FALSE) +#define nm_json_boolean_value nm_json_is_true +#define nm_json_is_boolean(json) (nm_json_is_true(json) || nm_json_is_false(json)) +#define nm_json_is_null(json) ((json) && nm_json_typeof(json) == NM_JSON_NULL) + +#define nm_json_array_foreach(vt, array, index, value) \ + for(index = 0; \ + index < vt->nm_json_array_size (array) && (value = vt->nm_json_array_get (array, index)); \ + index++) + +#define nm_json_object_foreach(vt, object, key, value) \ + for(key = vt->nm_json_object_iter_key (vt->nm_json_object_iter (object)); \ + key && (value = vt->nm_json_object_iter_value (vt->nm_json_object_key_to_iter (key))); \ + key = vt->nm_json_object_iter_key (vt->nm_json_object_iter_next (object, vt->nm_json_object_key_to_iter (key)))) + +/*****************************************************************************/ + +static inline int +nm_jansson_json_as_bool (const nm_json_t *elem, + bool *out_val) +{ + if (!elem) + return 0; + + if (!nm_json_is_boolean (elem)) + return -EINVAL; + + NM_SET_OUT (out_val, nm_json_boolean_value (elem)); + return 1; +} + +static inline int +nm_jansson_json_as_int32 (const NMJsonVt *vt, + const nm_json_t *elem, + gint32 *out_val) +{ + nm_json_int_t v; + + if (!elem) + return 0; + + if (!nm_json_is_integer (elem)) + return -EINVAL; + + v = vt->nm_json_integer_value (elem); + if ( v < (gint64) G_MININT32 + || v > (gint64) G_MAXINT32) + return -ERANGE; + + NM_SET_OUT (out_val, v); + return 1; +} + +static inline int +nm_jansson_json_as_int (const NMJsonVt *vt, + const nm_json_t *elem, + int *out_val) +{ + nm_json_int_t v; + + if (!elem) + return 0; + + if (!nm_json_is_integer (elem)) + return -EINVAL; + + v = vt->nm_json_integer_value (elem); + if ( v < (gint64) G_MININT + || v > (gint64) G_MAXINT) + return -ERANGE; + + NM_SET_OUT (out_val, v); + return 1; +} + +static inline int +nm_jansson_json_as_string (const NMJsonVt *vt, + const nm_json_t *elem, + const char **out_val) +{ + if (!elem) + return 0; + + if (!nm_json_is_string (elem)) + return -EINVAL; + + NM_SET_OUT (out_val, vt->nm_json_string_value (elem)); + return 1; +} + +/*****************************************************************************/ + #ifdef NM_VALUE_TYPE_DEFINE_FUNCTIONS -#include "nm-value-type.h" + static inline void nm_value_type_to_json (NMValueType value_type, GString *gstr, @@ -62,8 +294,29 @@ nm_value_type_to_json (NMValueType value_type, } nm_assert_not_reached (); } -#endif -/*****************************************************************************/ +static inline gboolean +nm_value_type_from_json (const NMJsonVt *vt, + NMValueType value_type, + const nm_json_t *elem, + gpointer out_val) +{ + switch (value_type) { + case NM_VALUE_TYPE_BOOL: return (nm_jansson_json_as_bool (elem, out_val) > 0); + case NM_VALUE_TYPE_INT32: return (nm_jansson_json_as_int32 (vt, elem, out_val) > 0); + case NM_VALUE_TYPE_INT: return (nm_jansson_json_as_int (vt, elem, out_val) > 0); -#endif /* __NM_JSON_AUX_H__ */ + /* warning: this overwrites/leaks the previous value. You better have *out_val + * point to uninitialized memory or NULL. */ + case NM_VALUE_TYPE_STRING: return (nm_jansson_json_as_string (vt, elem, out_val) > 0); + + case NM_VALUE_TYPE_UNSPEC: + break; + } + nm_assert_not_reached (); + return FALSE; +} + +#endif /* NM_VALUE_TYPE_DEFINE_FUNCTIONS */ + +#endif /* __NM_JSON_AUX_H__ */ diff --git a/shared/nm-glib-aux/nm-json.c b/shared/nm-glib-aux/nm-json.c deleted file mode 100644 index 57fc79def0..0000000000 --- a/shared/nm-glib-aux/nm-json.c +++ /dev/null @@ -1,134 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1+ -/* - * Copyright (C) 2017, 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-json.h" - -#include - -typedef struct { - NMJsonVt vt; - void *dl_handle; -} NMJsonVtInternal; - -static NMJsonVtInternal * -_nm_json_vt_internal_load (void) -{ - NMJsonVtInternal *v; - void *handle = NULL; - int mode; - - v = g_new0 (NMJsonVtInternal, 1); - -#ifndef JANSSON_SONAME -#define JANSSON_SONAME "" -#endif - - mode = RTLD_LAZY | RTLD_LOCAL | RTLD_NODELETE | RTLD_DEEPBIND; -#if defined (ASAN_BUILD) - /* Address sanitizer is incompatible with RTLD_DEEPBIND. */ - mode &= ~RTLD_DEEPBIND; -#endif - - if (strlen (JANSSON_SONAME) > 0) - handle = dlopen (JANSSON_SONAME, mode); - - if (!handle) - return v; - -#define TRY_BIND_SYMBOL(symbol) \ - G_STMT_START { \ - void *_sym = dlsym (handle, #symbol); \ - \ - if (!_sym) \ - goto fail_symbol; \ - v->vt.nm_ ## symbol = _sym; \ - } G_STMT_END - - TRY_BIND_SYMBOL (json_array); - TRY_BIND_SYMBOL (json_array_append_new); - TRY_BIND_SYMBOL (json_array_get); - TRY_BIND_SYMBOL (json_array_size); - TRY_BIND_SYMBOL (json_delete); - TRY_BIND_SYMBOL (json_dumps); - TRY_BIND_SYMBOL (json_false); - TRY_BIND_SYMBOL (json_integer); - TRY_BIND_SYMBOL (json_integer_value); - TRY_BIND_SYMBOL (json_loads); - TRY_BIND_SYMBOL (json_object); - TRY_BIND_SYMBOL (json_object_del); - TRY_BIND_SYMBOL (json_object_get); - TRY_BIND_SYMBOL (json_object_iter); - TRY_BIND_SYMBOL (json_object_iter_key); - TRY_BIND_SYMBOL (json_object_iter_next); - TRY_BIND_SYMBOL (json_object_iter_value); - TRY_BIND_SYMBOL (json_object_key_to_iter); - TRY_BIND_SYMBOL (json_object_set_new); - TRY_BIND_SYMBOL (json_object_size); - TRY_BIND_SYMBOL (json_string); - TRY_BIND_SYMBOL (json_string_value); - TRY_BIND_SYMBOL (json_true); - - v->vt.loaded = TRUE; - v->dl_handle = handle; - return v; - -fail_symbol: - dlclose (&handle); - *v = (NMJsonVtInternal) { }; - return v; -} - -const NMJsonVt *_nm_json_vt_ptr = NULL; - -const NMJsonVt * -_nm_json_vt_init (void) -{ - NMJsonVtInternal *v; - -again: - v = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr); - if (G_UNLIKELY (!v)) { - v = _nm_json_vt_internal_load (); - if (!g_atomic_pointer_compare_and_exchange ((gpointer *) &_nm_json_vt_ptr, NULL, v)) { - if (v->dl_handle) - dlclose (v->dl_handle); - g_free (v); - goto again; - } - - /* we transfer ownership. */ - } - - nm_assert (v && v == g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr)); - return &v->vt; -} - -const NMJsonVt * -nmtst_json_vt_reset (gboolean loaded) -{ - NMJsonVtInternal *v_old; - NMJsonVtInternal *v; - - v_old = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr); - - if (!loaded) { - /* load a fake instance for testing. */ - v = g_new0 (NMJsonVtInternal, 1); - } else - v = _nm_json_vt_internal_load (); - - if (!g_atomic_pointer_compare_and_exchange ((gpointer *) &_nm_json_vt_ptr, v_old, v)) - g_assert_not_reached (); - - if (v_old) { - if (v_old->dl_handle) - dlclose (v_old->dl_handle); - g_free ((gpointer *) v_old); - } - - return v->vt.loaded ? &v->vt : NULL; -} diff --git a/shared/nm-glib-aux/nm-json.h b/shared/nm-glib-aux/nm-json.h deleted file mode 100644 index 5042cf0f80..0000000000 --- a/shared/nm-glib-aux/nm-json.h +++ /dev/null @@ -1,264 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1+ -/* - * Copyright (C) 2017, 2018 Red Hat, Inc. - */ - -#ifndef __NM_JSON_H__ -#define __NM_JSON_H__ - -/*****************************************************************************/ - -#define NM_JSON_REJECT_DUPLICATES 0x1 - -typedef enum { - NM_JSON_OBJECT, - NM_JSON_ARRAY, - NM_JSON_STRING, - NM_JSON_INTEGER, - NM_JSON_REAL, - NM_JSON_TRUE, - NM_JSON_FALSE, - NM_JSON_NULL, -} nm_json_type; - -typedef struct nm_json_t { - nm_json_type type; - volatile size_t refcount; -} nm_json_t; - -typedef long long nm_json_int_t; - -#define NM_JSON_ERROR_TEXT_LENGTH 160 -#define NM_JSON_ERROR_SOURCE_LENGTH 80 - -typedef struct nm_json_error_t { - int line; - int column; - int position; - char source[NM_JSON_ERROR_SOURCE_LENGTH]; - char text[NM_JSON_ERROR_TEXT_LENGTH]; -} nm_json_error_t; - -typedef struct { - gboolean loaded; - char *(*nm_json_dumps) (const nm_json_t *json, size_t flags); - const char *(*nm_json_object_iter_key) (void *iter); - const char *(*nm_json_string_value) (const nm_json_t *json); - int (*nm_json_array_append_new) (nm_json_t *json, nm_json_t *value); - int (*nm_json_object_del) (nm_json_t *json, const char *key); - int (*nm_json_object_set_new) (nm_json_t *json, const char *key, nm_json_t *value); - nm_json_int_t (*nm_json_integer_value) (const nm_json_t *json); - nm_json_t *(*nm_json_array) (void); - nm_json_t *(*nm_json_array_get) (const nm_json_t *json, size_t index); - nm_json_t *(*nm_json_false) (void); - nm_json_t *(*nm_json_integer) (nm_json_int_t value); - nm_json_t *(*nm_json_loads) (const char *string, size_t flags, nm_json_error_t *error); - nm_json_t *(*nm_json_object) (void); - nm_json_t *(*nm_json_object_get) (const nm_json_t *json, const char *key); - nm_json_t *(*nm_json_object_iter_value) (void *); - nm_json_t *(*nm_json_string) (const char *value); - nm_json_t *(*nm_json_true) (void); - size_t (*nm_json_array_size) (const nm_json_t *json); - size_t (*nm_json_object_size) (const nm_json_t *json); - void (*nm_json_delete) (nm_json_t *json); - void *(*nm_json_object_iter) (nm_json_t *json); - void *(*nm_json_object_iter_next) (nm_json_t *json, void *iter); - void *(*nm_json_object_key_to_iter) (const char *key); -} NMJsonVt; - -extern const NMJsonVt *_nm_json_vt_ptr; - -const NMJsonVt *_nm_json_vt_init (void); - -static inline const NMJsonVt * -_nm_json_vt (void) -{ - const NMJsonVt *vt; - - vt = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr); - if (G_UNLIKELY (!vt)) { - vt = _nm_json_vt_init (); - nm_assert (vt); - } - return vt; -} - -static inline const NMJsonVt * -nm_json_vt (void) -{ - const NMJsonVt *vt; - - vt = _nm_json_vt(); - return vt->loaded ? vt : NULL; -} - -static inline const NMJsonVt * -nm_json_vt_assert (void) -{ - const NMJsonVt *vt; - - vt = _nm_json_vt(); - nm_assert (vt->loaded); - return vt; -} - -const NMJsonVt *nmtst_json_vt_reset (gboolean loaded); - -/*****************************************************************************/ - -#define nm_json_boolean(vt, val) \ - ((val) ? (vt)->nm_json_true () : (vt)->nm_json_false ()) - -static inline void -nm_json_decref (const NMJsonVt *vt, nm_json_t *json) -{ - /* Our ref-counting is not threadsafe, unlike libjansson's. But we never - * share one json_t instance between threads, and if we would, we would very likely - * wrap a mutex around it. */ - if ( json - && json->refcount != (size_t) -1 - && --json->refcount == 0) - vt->nm_json_delete (json); -} - -static inline void -_nm_auto_decref_json (nm_json_t **p_json) -{ - if ( *p_json - && (*p_json)->refcount != (size_t) -1 - && --(*p_json)->refcount == 0) - nm_json_vt ()->nm_json_delete (*p_json); -} - -#define nm_auto_decref_json nm_auto(_nm_auto_decref_json) - -/*****************************************************************************/ - -/* the following are implemented as pure macros in jansson.h. - * They can be used directly, however, add a nm_json* variant, - * to make it explict we don't accidentally use jansson ABI. */ - -#define nm_json_typeof(json) ((json)->type) -#define nm_json_is_object(json) ((json) && nm_json_typeof(json) == NM_JSON_OBJECT) -#define nm_json_is_array(json) ((json) && nm_json_typeof(json) == NM_JSON_ARRAY) -#define nm_json_is_string(json) ((json) && nm_json_typeof(json) == NM_JSON_STRING) -#define nm_json_is_integer(json) ((json) && nm_json_typeof(json) == NM_JSON_INTEGER) -#define nm_json_is_real(json) ((json) && nm_json_typeof(json) == NM_JSON_REAL) -#define nm_json_is_number(json) (nm_json_is_integer(json) || nm_json_is_real(json)) -#define nm_json_is_true(json) ((json) && nm_json_typeof(json) == NM_JSON_TRUE) -#define nm_json_is_false(json) ((json) && nm_json_typeof(json) == NM_JSON_FALSE) -#define nm_json_boolean_value nm_json_is_true -#define nm_json_is_boolean(json) (nm_json_is_true(json) || nm_json_is_false(json)) -#define nm_json_is_null(json) ((json) && nm_json_typeof(json) == NM_JSON_NULL) - -#define nm_json_object_foreach(vt, object, key, value) \ - for(key = vt->nm_json_object_iter_key (vt->nm_json_object_iter (object)); \ - key && (value = vt->nm_json_object_iter_value (vt->nm_json_object_key_to_iter (key))); \ - key = vt->nm_json_object_iter_key (vt->nm_json_object_iter_next (object, vt->nm_json_object_key_to_iter (key)))) - -/*****************************************************************************/ - -static inline int -nm_jansson_json_as_bool (const nm_json_t *elem, - bool *out_val) -{ - if (!elem) - return 0; - - if (!nm_json_is_boolean (elem)) - return -EINVAL; - - NM_SET_OUT (out_val, nm_json_boolean_value (elem)); - return 1; -} - -static inline int -nm_jansson_json_as_int32 (const NMJsonVt *vt, - const nm_json_t *elem, - gint32 *out_val) -{ - nm_json_int_t v; - - if (!elem) - return 0; - - if (!nm_json_is_integer (elem)) - return -EINVAL; - - v = vt->nm_json_integer_value (elem); - if ( v < (gint64) G_MININT32 - || v > (gint64) G_MAXINT32) - return -ERANGE; - - NM_SET_OUT (out_val, v); - return 1; -} - -static inline int -nm_jansson_json_as_int (const NMJsonVt *vt, - const nm_json_t *elem, - int *out_val) -{ - nm_json_int_t v; - - if (!elem) - return 0; - - if (!nm_json_is_integer (elem)) - return -EINVAL; - - v = vt->nm_json_integer_value (elem); - if ( v < (gint64) G_MININT - || v > (gint64) G_MAXINT) - return -ERANGE; - - NM_SET_OUT (out_val, v); - return 1; -} - -static inline int -nm_jansson_json_as_string (const NMJsonVt *vt, - const nm_json_t *elem, - const char **out_val) -{ - if (!elem) - return 0; - - if (!nm_json_is_string (elem)) - return -EINVAL; - - NM_SET_OUT (out_val, vt->nm_json_string_value (elem)); - return 1; -} - -/*****************************************************************************/ - -#ifdef NM_VALUE_TYPE_DEFINE_FUNCTIONS - -#include "nm-glib-aux/nm-value-type.h" - -static inline gboolean -nm_value_type_from_json (const NMJsonVt *vt, - NMValueType value_type, - const nm_json_t *elem, - gpointer out_val) -{ - switch (value_type) { - case NM_VALUE_TYPE_BOOL: return (nm_jansson_json_as_bool (elem, out_val) > 0); - case NM_VALUE_TYPE_INT32: return (nm_jansson_json_as_int32 (vt, elem, out_val) > 0); - case NM_VALUE_TYPE_INT: return (nm_jansson_json_as_int (vt, elem, out_val) > 0); - - /* warning: this overwrites/leaks the previous value. You better have *out_val - * point to uninitialized memory or NULL. */ - case NM_VALUE_TYPE_STRING: return (nm_jansson_json_as_string (vt, elem, out_val) > 0); - - case NM_VALUE_TYPE_UNSPEC: - break; - } - nm_assert_not_reached (); - return FALSE; -} - -#endif /* NM_VALUE_TYPE_DEFINE_FUNCTIONS */ - -#endif /* __NM_JSON_H__ */ diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index b8fdd922ce..935ea9fdf8 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -15,7 +15,7 @@ #include #include -#include "nm-glib-aux/nm-json.h" +#include "nm-glib-aux/nm-json-aux.h" #include "nm-utils.h" #include "nm-setting-connection.h" #include "nm-setting-wired.h"