summaryrefslogtreecommitdiff
path: root/src/json.c
diff options
context:
space:
mode:
authorJoão Távora <joaotavora@gmail.com>2018-06-02 00:23:38 +0100
committerJoão Távora <joaotavora@gmail.com>2018-06-07 12:30:39 +0100
commit3509aaaefe1996ea46b038850629b6d2f7a726fe (patch)
tree651fec98d47d8c77863f6f0b08c9b3c9c6ac2362 /src/json.c
parent2e2f61efa66b69fbd12c83bbd5370a4be2374f66 (diff)
downloademacs-3509aaaefe1996ea46b038850629b6d2f7a726fe.tar.gz
Accept plists when serializing and parsing JSON
* doc/lispref/text.texi (Parsing JSON): Mention plist support. * src/json.c (lisp_to_json_toplevel_1): Serialize plists to json. (Fjson_serialize): Mention plists in docstring. (enum json_object_type): Add json_object_plist. (json_to_lisp): Parse JSON into plists. (json_parse_object_type): Consider plists. (Fjson_parse_string): Mention plists in docstring. (syms_of_json): New Qplist sym_of_json. (lisp_to_json): Update comment. * test/src/json-tests.el (json-serialize/object) (json-parse-string/object): New plist tests.
Diffstat (limited to 'src/json.c')
-rw-r--r--src/json.c97
1 files changed, 73 insertions, 24 deletions
diff --git a/src/json.c b/src/json.c
index b046d34f667..afb81587a47 100644
--- a/src/json.c
+++ b/src/json.c
@@ -393,18 +393,39 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json)
*json = json_check (json_object ());
ptrdiff_t count = SPECPDL_INDEX ();
record_unwind_protect_ptr (json_release_object, *json);
+ bool is_plist = !CONSP (XCAR (tail));
FOR_EACH_TAIL (tail)
{
- Lisp_Object pair = XCAR (tail);
- CHECK_CONS (pair);
- Lisp_Object key_symbol = XCAR (pair);
- Lisp_Object value = XCDR (pair);
+ const char *key_str;
+ Lisp_Object value;
+ Lisp_Object key_symbol;
+ if (is_plist)
+ {
+ key_symbol = XCAR (tail);
+ tail = XCDR (tail);
+ CHECK_CONS (tail);
+ value = XCAR (tail);
+ if (EQ (tail, li.tortoise)) circular_list (lisp);
+ }
+ else
+ {
+ Lisp_Object pair = XCAR (tail);
+ CHECK_CONS (pair);
+ key_symbol = XCAR (pair);
+ value = XCDR (pair);
+ }
CHECK_SYMBOL (key_symbol);
Lisp_Object key = SYMBOL_NAME (key_symbol);
/* We can't specify the length, so the string must be
null-terminated. */
check_string_without_embedded_nulls (key);
- const char *key_str = SSDATA (key);
+ key_str = SSDATA (key);
+ /* In plists, ensure leading ":" in keys is stripped. It
+ will be reconstructed later in `json_to_lisp'.*/
+ if (is_plist && ':' == key_str[0] && key_str[1])
+ {
+ key_str = &key_str[1];
+ }
/* Only add element if key is not already present. */
if (json_object_get (*json, key_str) == NULL)
{
@@ -423,7 +444,7 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json)
/* Convert LISP to a toplevel JSON object (array or object). Signal
an error of type `wrong-type-argument' if LISP is not a vector,
- hashtable, or alist. */
+ hashtable, alist, or plist. */
static json_t *
lisp_to_json_toplevel (Lisp_Object lisp)
@@ -470,20 +491,21 @@ lisp_to_json (Lisp_Object lisp)
return json;
}
- /* LISP now must be a vector, hashtable, or alist. */
+ /* LISP now must be a vector, hashtable, alist, or plist. */
return lisp_to_json_toplevel (lisp);
}
DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, 1, NULL,
doc: /* Return the JSON representation of OBJECT as a string.
-OBJECT must be a vector, hashtable, or alist, and its elements can
-recursively contain `:null', `:false', t, numbers, strings, or other
-vectors hashtables, and alist. `:null', `:false', and t will be
-converted to JSON null, false, and true values, respectively. Vectors
-will be converted to JSON arrays, and hashtables and alists to JSON
-objects. Hashtable keys must be strings without embedded null
-characters and must be unique within each object. Alist keys must be
-symbols; if a key is duplicate, the first instance is used. */)
+OBJECT must be a vector, hashtable, alist, or plist and its elements
+can recursively contain `:null', `:false', t, numbers, strings, or
+other vectors hashtables, alists or plists. `:null', `:false', and t
+will be converted to JSON null, false, and true values, respectively.
+Vectors will be converted to JSON arrays, whereas hashtables, alists
+and plists are converted to JSON objects. Hashtable keys must be
+strings without embedded null characters and must be unique within
+each object. Alist and plist keys must be symbols; if a key is
+duplicate, the first instance is used. */)
(Lisp_Object object)
{
ptrdiff_t count = SPECPDL_INDEX ();
@@ -605,6 +627,7 @@ OBJECT. */)
enum json_object_type {
json_object_hashtable,
json_object_alist,
+ json_object_plist
};
/* Convert a JSON object to a Lisp object. */
@@ -692,6 +715,28 @@ json_to_lisp (json_t *json, enum json_object_type object_type)
result = Fnreverse (result);
break;
}
+ case json_object_plist:
+ {
+ result = Qnil;
+ const char *key_str;
+ json_t *value;
+ json_object_foreach (json, key_str, value)
+ {
+ USE_SAFE_ALLOCA;
+ ptrdiff_t key_str_len = strlen (key_str);
+ char *keyword_key_str = SAFE_ALLOCA (1 + key_str_len + 1);
+ keyword_key_str[0] = ':';
+ strcpy (&keyword_key_str[1], key_str);
+ Lisp_Object key = intern_1 (keyword_key_str, key_str_len + 1);
+ /* Build the plist as value-key since we're going to
+ reverse it in the end.*/
+ result = Fcons (key, result);
+ result = Fcons (json_to_lisp (value, object_type), result);
+ SAFE_FREE ();
+ }
+ result = Fnreverse (result);
+ break;
+ }
default:
/* Can't get here. */
emacs_abort ();
@@ -721,8 +766,10 @@ json_parse_object_type (ptrdiff_t nargs, Lisp_Object *args)
return json_object_hashtable;
else if (EQ (value, Qalist))
return json_object_alist;
+ else if (EQ (value, Qplist))
+ return json_object_plist;
else
- wrong_choice (list2 (Qhash_table, Qalist), value);
+ wrong_choice (list3 (Qhash_table, Qalist, Qplist), value);
}
default:
wrong_type_argument (Qplistp, Flist (nargs, args));
@@ -733,14 +780,15 @@ DEFUN ("json-parse-string", Fjson_parse_string, Sjson_parse_string, 1, MANY,
NULL,
doc: /* Parse the JSON STRING into a Lisp object.
This is essentially the reverse operation of `json-serialize', which
-see. The returned object will be a vector, hashtable, or alist. Its
-elements will be `:null', `:false', t, numbers, strings, or further
-vectors, hashtables, and alists. If there are duplicate keys in an
-object, all but the last one are ignored. If STRING doesn't contain a
-valid JSON object, an error of type `json-parse-error' is signaled.
-The keyword argument `:object-type' specifies which Lisp type is used
-to represent objects; it can be `hash-table' or `alist'.
-usage: (json-parse-string STRING &key (OBJECT-TYPE \\='hash-table)) */)
+see. The returned object will be a vector, hashtable, alist, or
+plist. Its elements will be `:null', `:false', t, numbers, strings,
+or further vectors, hashtables, alists, or plists. If there are
+duplicate keys in an object, all but the last one are ignored. If
+STRING doesn't contain a valid JSON object, an error of type
+`json-parse-error' is signaled. The keyword argument `:object-type'
+specifies which Lisp type is used to represent objects; it can be
+`hash-table', `alist' or `plist'.
+usage: (json-parse-string STRING &key (OBJECT-TYPE \\='hash-table)) */)
(ptrdiff_t nargs, Lisp_Object *args)
{
ptrdiff_t count = SPECPDL_INDEX ();
@@ -912,6 +960,7 @@ syms_of_json (void)
DEFSYM (QCobject_type, ":object-type");
DEFSYM (Qalist, "alist");
+ DEFSYM (Qplist, "plist");
defsubr (&Sjson_serialize);
defsubr (&Sjson_insert);