xref: /vim-8.2.3635/src/json.c (revision 2950065e)
1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2520e1e41SBram Moolenaar  *
3520e1e41SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
4520e1e41SBram Moolenaar  *
5520e1e41SBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
6520e1e41SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
7520e1e41SBram Moolenaar  * See README.txt for an overview of the Vim source code.
8520e1e41SBram Moolenaar  */
9520e1e41SBram Moolenaar 
10520e1e41SBram Moolenaar /*
11520e1e41SBram Moolenaar  * json.c: Encoding and decoding JSON.
12520e1e41SBram Moolenaar  *
13009d84a3SBram Moolenaar  * Follows this standard: https://tools.ietf.org/html/rfc7159.html
14520e1e41SBram Moolenaar  */
15fefecb0fSBram Moolenaar #define USING_FLOAT_STUFF
16520e1e41SBram Moolenaar 
17520e1e41SBram Moolenaar #include "vim.h"
18520e1e41SBram Moolenaar 
19520e1e41SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
20f1b6ac72SBram Moolenaar 
21595e64e2SBram Moolenaar static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options);
22520e1e41SBram Moolenaar 
23a09195f2SBram Moolenaar static char e_json_error[] = N_("E491: json decode error at '%s'");
24a09195f2SBram Moolenaar 
25520e1e41SBram Moolenaar /*
26520e1e41SBram Moolenaar  * Encode "val" into a JSON format string.
27f1f0792eSBram Moolenaar  * The result is added to "gap"
28f1f0792eSBram Moolenaar  * Returns FAIL on failure and makes gap->ga_data empty.
29f1f0792eSBram Moolenaar  */
30f1f0792eSBram Moolenaar     static int
json_encode_gap(garray_T * gap,typval_T * val,int options)31f1f0792eSBram Moolenaar json_encode_gap(garray_T *gap, typval_T *val, int options)
32f1f0792eSBram Moolenaar {
33f1f0792eSBram Moolenaar     if (json_encode_item(gap, val, get_copyID(), options) == FAIL)
34f1f0792eSBram Moolenaar     {
35f1f0792eSBram Moolenaar 	ga_clear(gap);
36f1f0792eSBram Moolenaar 	gap->ga_data = vim_strsave((char_u *)"");
37f1f0792eSBram Moolenaar 	return FAIL;
38f1f0792eSBram Moolenaar     }
39f1f0792eSBram Moolenaar     return OK;
40f1f0792eSBram Moolenaar }
41f1f0792eSBram Moolenaar 
42f1f0792eSBram Moolenaar /*
43f1f0792eSBram Moolenaar  * Encode "val" into a JSON format string.
4455fab439SBram Moolenaar  * The result is in allocated memory.
4555fab439SBram Moolenaar  * The result is empty when encoding fails.
46f1f0792eSBram Moolenaar  * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL.
47520e1e41SBram Moolenaar  */
48520e1e41SBram Moolenaar     char_u *
json_encode(typval_T * val,int options)49595e64e2SBram Moolenaar json_encode(typval_T *val, int options)
50520e1e41SBram Moolenaar {
51520e1e41SBram Moolenaar     garray_T ga;
52520e1e41SBram Moolenaar 
534ba37b58SBram Moolenaar     // Store bytes in the growarray.
54520e1e41SBram Moolenaar     ga_init2(&ga, 1, 4000);
55f1f0792eSBram Moolenaar     json_encode_gap(&ga, val, options);
5604af1963SBram Moolenaar     ga_append(&ga, NUL);
57520e1e41SBram Moolenaar     return ga.ga_data;
58520e1e41SBram Moolenaar }
59520e1e41SBram Moolenaar 
60113e1072SBram Moolenaar #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
61fb1f6269SBram Moolenaar /*
6255fab439SBram Moolenaar  * Encode ["nr", "val"] into a JSON format string in allocated memory.
63f1f0792eSBram Moolenaar  * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL.
64fb1f6269SBram Moolenaar  * Returns NULL when out of memory.
65fb1f6269SBram Moolenaar  */
66fb1f6269SBram Moolenaar     char_u *
json_encode_nr_expr(int nr,typval_T * val,int options)67595e64e2SBram Moolenaar json_encode_nr_expr(int nr, typval_T *val, int options)
68fb1f6269SBram Moolenaar {
69fb1f6269SBram Moolenaar     typval_T	listtv;
70fb1f6269SBram Moolenaar     typval_T	nrtv;
71f1f0792eSBram Moolenaar     garray_T	ga;
72fb1f6269SBram Moolenaar 
73fb1f6269SBram Moolenaar     nrtv.v_type = VAR_NUMBER;
74fb1f6269SBram Moolenaar     nrtv.vval.v_number = nr;
75fb1f6269SBram Moolenaar     if (rettv_list_alloc(&listtv) == FAIL)
76fb1f6269SBram Moolenaar 	return NULL;
77fb1f6269SBram Moolenaar     if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL
78fb1f6269SBram Moolenaar 	    || list_append_tv(listtv.vval.v_list, val) == FAIL)
79fb1f6269SBram Moolenaar     {
80fb1f6269SBram Moolenaar 	list_unref(listtv.vval.v_list);
81fb1f6269SBram Moolenaar 	return NULL;
82fb1f6269SBram Moolenaar     }
83fb1f6269SBram Moolenaar 
84f1f0792eSBram Moolenaar     ga_init2(&ga, 1, 4000);
85f1f0792eSBram Moolenaar     if (json_encode_gap(&ga, &listtv, options) == OK && (options & JSON_NL))
86f1f0792eSBram Moolenaar 	ga_append(&ga, '\n');
87fb1f6269SBram Moolenaar     list_unref(listtv.vval.v_list);
8804af1963SBram Moolenaar     ga_append(&ga, NUL);
89f1f0792eSBram Moolenaar     return ga.ga_data;
90fb1f6269SBram Moolenaar }
91113e1072SBram Moolenaar #endif
92fb1f6269SBram Moolenaar 
93520e1e41SBram Moolenaar     static void
write_string(garray_T * gap,char_u * str)94520e1e41SBram Moolenaar write_string(garray_T *gap, char_u *str)
95520e1e41SBram Moolenaar {
96520e1e41SBram Moolenaar     char_u	*res = str;
97520e1e41SBram Moolenaar     char_u	numbuf[NUMBUFLEN];
98520e1e41SBram Moolenaar 
99520e1e41SBram Moolenaar     if (res == NULL)
100b29d328eSBram Moolenaar 	ga_concat(gap, (char_u *)"\"\"");
101520e1e41SBram Moolenaar     else
102520e1e41SBram Moolenaar     {
103fc3abf47SBram Moolenaar #if defined(USE_ICONV)
104b6ff8118SBram Moolenaar 	vimconv_T   conv;
105b6ff8118SBram Moolenaar 	char_u	    *converted = NULL;
106b6ff8118SBram Moolenaar 
107f97ddbebSBram Moolenaar 	if (!enc_utf8)
108f97ddbebSBram Moolenaar 	{
1094ba37b58SBram Moolenaar 	    // Convert the text from 'encoding' to utf-8, the JSON string is
1104ba37b58SBram Moolenaar 	    // always utf-8.
111f97ddbebSBram Moolenaar 	    conv.vc_type = CONV_NONE;
112b6ff8118SBram Moolenaar 	    convert_setup(&conv, p_enc, (char_u*)"utf-8");
113b6ff8118SBram Moolenaar 	    if (conv.vc_type != CONV_NONE)
114b6ff8118SBram Moolenaar 		converted = res = string_convert(&conv, res, NULL);
115b6ff8118SBram Moolenaar 	    convert_setup(&conv, NULL, NULL);
116f97ddbebSBram Moolenaar 	}
117b6ff8118SBram Moolenaar #endif
118520e1e41SBram Moolenaar 	ga_append(gap, '"');
119520e1e41SBram Moolenaar 	while (*res != NUL)
120520e1e41SBram Moolenaar 	{
121b6ff8118SBram Moolenaar 	    int c;
1224ba37b58SBram Moolenaar 	    // always use utf-8 encoding, ignore 'encoding'
123b6ff8118SBram Moolenaar 	    c = utf_ptr2char(res);
124520e1e41SBram Moolenaar 
125520e1e41SBram Moolenaar 	    switch (c)
126520e1e41SBram Moolenaar 	    {
127520e1e41SBram Moolenaar 		case 0x08:
128520e1e41SBram Moolenaar 		    ga_append(gap, '\\'); ga_append(gap, 'b'); break;
129520e1e41SBram Moolenaar 		case 0x09:
130520e1e41SBram Moolenaar 		    ga_append(gap, '\\'); ga_append(gap, 't'); break;
131520e1e41SBram Moolenaar 		case 0x0a:
132520e1e41SBram Moolenaar 		    ga_append(gap, '\\'); ga_append(gap, 'n'); break;
133520e1e41SBram Moolenaar 		case 0x0c:
134520e1e41SBram Moolenaar 		    ga_append(gap, '\\'); ga_append(gap, 'f'); break;
135520e1e41SBram Moolenaar 		case 0x0d:
136520e1e41SBram Moolenaar 		    ga_append(gap, '\\'); ga_append(gap, 'r'); break;
1374ba37b58SBram Moolenaar 		case 0x22: // "
1384ba37b58SBram Moolenaar 		case 0x5c: // backslash
139520e1e41SBram Moolenaar 		    ga_append(gap, '\\');
140520e1e41SBram Moolenaar 		    ga_append(gap, c);
141520e1e41SBram Moolenaar 		    break;
142520e1e41SBram Moolenaar 		default:
143520e1e41SBram Moolenaar 		    if (c >= 0x20)
144520e1e41SBram Moolenaar 		    {
145b6ff8118SBram Moolenaar 			numbuf[utf_char2bytes(c, numbuf)] = NUL;
146520e1e41SBram Moolenaar 			ga_concat(gap, numbuf);
147520e1e41SBram Moolenaar 		    }
148520e1e41SBram Moolenaar 		    else
149520e1e41SBram Moolenaar 		    {
150520e1e41SBram Moolenaar 			vim_snprintf((char *)numbuf, NUMBUFLEN,
151520e1e41SBram Moolenaar 							 "\\u%04lx", (long)c);
152520e1e41SBram Moolenaar 			ga_concat(gap, numbuf);
153520e1e41SBram Moolenaar 		    }
154520e1e41SBram Moolenaar 	    }
155b6ff8118SBram Moolenaar 	    res += utf_ptr2len(res);
156520e1e41SBram Moolenaar 	}
157520e1e41SBram Moolenaar 	ga_append(gap, '"');
158fc3abf47SBram Moolenaar #if defined(USE_ICONV)
159b6ff8118SBram Moolenaar 	vim_free(converted);
160b6ff8118SBram Moolenaar #endif
161520e1e41SBram Moolenaar     }
162520e1e41SBram Moolenaar }
163520e1e41SBram Moolenaar 
164fcaaae6bSBram Moolenaar /*
165595e64e2SBram Moolenaar  * Return TRUE if "key" can be used without quotes.
166595e64e2SBram Moolenaar  * That is when it starts with a letter and only contains letters, digits and
167595e64e2SBram Moolenaar  * underscore.
168595e64e2SBram Moolenaar  */
169595e64e2SBram Moolenaar     static int
is_simple_key(char_u * key)170595e64e2SBram Moolenaar is_simple_key(char_u *key)
171595e64e2SBram Moolenaar {
172595e64e2SBram Moolenaar     char_u *p;
173595e64e2SBram Moolenaar 
174595e64e2SBram Moolenaar     if (!ASCII_ISALPHA(*key))
175595e64e2SBram Moolenaar 	return FALSE;
176595e64e2SBram Moolenaar     for (p = key + 1; *p != NUL; ++p)
177595e64e2SBram Moolenaar 	if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p))
178595e64e2SBram Moolenaar 	    return FALSE;
179595e64e2SBram Moolenaar     return TRUE;
180595e64e2SBram Moolenaar }
181595e64e2SBram Moolenaar 
182595e64e2SBram Moolenaar /*
183fcaaae6bSBram Moolenaar  * Encode "val" into "gap".
184fcaaae6bSBram Moolenaar  * Return FAIL or OK.
185fcaaae6bSBram Moolenaar  */
186fcaaae6bSBram Moolenaar     static int
json_encode_item(garray_T * gap,typval_T * val,int copyID,int options)187595e64e2SBram Moolenaar json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
188520e1e41SBram Moolenaar {
189520e1e41SBram Moolenaar     char_u	numbuf[NUMBUFLEN];
190520e1e41SBram Moolenaar     char_u	*res;
1916e5ea8d2SBram Moolenaar     blob_T	*b;
192520e1e41SBram Moolenaar     list_T	*l;
193520e1e41SBram Moolenaar     dict_T	*d;
1946e5ea8d2SBram Moolenaar     int		i;
195520e1e41SBram Moolenaar 
196520e1e41SBram Moolenaar     switch (val->v_type)
197520e1e41SBram Moolenaar     {
1989b4a15d5SBram Moolenaar 	case VAR_BOOL:
199c593bec4SBram Moolenaar 	    switch ((long)val->vval.v_number)
200520e1e41SBram Moolenaar 	    {
201520e1e41SBram Moolenaar 		case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
202520e1e41SBram Moolenaar 		case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
2039b4a15d5SBram Moolenaar 	    }
2049b4a15d5SBram Moolenaar 	    break;
2059b4a15d5SBram Moolenaar 
2069b4a15d5SBram Moolenaar 	case VAR_SPECIAL:
207c593bec4SBram Moolenaar 	    switch ((long)val->vval.v_number)
2089b4a15d5SBram Moolenaar 	    {
209595e64e2SBram Moolenaar 		case VVAL_NONE: if ((options & JSON_JS) != 0
210595e64e2SBram Moolenaar 					     && (options & JSON_NO_NONE) == 0)
2114ba37b58SBram Moolenaar 				    // empty item
2124f8b8faeSBram Moolenaar 				    break;
2134ba37b58SBram Moolenaar 				// FALLTHROUGH
214520e1e41SBram Moolenaar 		case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
215520e1e41SBram Moolenaar 	    }
216520e1e41SBram Moolenaar 	    break;
217520e1e41SBram Moolenaar 
218520e1e41SBram Moolenaar 	case VAR_NUMBER:
21922fcfad2SBram Moolenaar 	    vim_snprintf((char *)numbuf, NUMBUFLEN, "%lld",
220f9706e9dSBram Moolenaar 					      (varnumber_T)val->vval.v_number);
221520e1e41SBram Moolenaar 	    ga_concat(gap, numbuf);
222520e1e41SBram Moolenaar 	    break;
223520e1e41SBram Moolenaar 
224520e1e41SBram Moolenaar 	case VAR_STRING:
225520e1e41SBram Moolenaar 	    res = val->vval.v_string;
226520e1e41SBram Moolenaar 	    write_string(gap, res);
227520e1e41SBram Moolenaar 	    break;
228520e1e41SBram Moolenaar 
229520e1e41SBram Moolenaar 	case VAR_FUNC:
2301735bc98SBram Moolenaar 	case VAR_PARTIAL:
23155fab439SBram Moolenaar 	case VAR_JOB:
2327707344dSBram Moolenaar 	case VAR_CHANNEL:
233f18332fbSBram Moolenaar 	case VAR_INSTR:
234a8530894SBram Moolenaar 	    semsg(_(e_cannot_json_encode_str), vartype_name(val->v_type));
235fcaaae6bSBram Moolenaar 	    return FAIL;
236520e1e41SBram Moolenaar 
2376e5ea8d2SBram Moolenaar 	case VAR_BLOB:
2386e5ea8d2SBram Moolenaar 	    b = val->vval.v_blob;
2396e5ea8d2SBram Moolenaar 	    if (b == NULL || b->bv_ga.ga_len == 0)
2406e5ea8d2SBram Moolenaar 		ga_concat(gap, (char_u *)"[]");
2416e5ea8d2SBram Moolenaar 	    else
2426e5ea8d2SBram Moolenaar 	    {
2436e5ea8d2SBram Moolenaar 		ga_append(gap, '[');
2446e5ea8d2SBram Moolenaar 		for (i = 0; i < b->bv_ga.ga_len; i++)
2456e5ea8d2SBram Moolenaar 		{
2466e5ea8d2SBram Moolenaar 		    if (i > 0)
2476e5ea8d2SBram Moolenaar 			ga_concat(gap, (char_u *)",");
2486e5ea8d2SBram Moolenaar 		    vim_snprintf((char *)numbuf, NUMBUFLEN, "%d",
2496e5ea8d2SBram Moolenaar 			    (int)blob_get(b, i));
2506e5ea8d2SBram Moolenaar 		    ga_concat(gap, numbuf);
2516e5ea8d2SBram Moolenaar 		}
2526e5ea8d2SBram Moolenaar 		ga_append(gap, ']');
2536e5ea8d2SBram Moolenaar 	    }
2546e5ea8d2SBram Moolenaar 	    break;
2556e5ea8d2SBram Moolenaar 
256520e1e41SBram Moolenaar 	case VAR_LIST:
257520e1e41SBram Moolenaar 	    l = val->vval.v_list;
258520e1e41SBram Moolenaar 	    if (l == NULL)
259b29d328eSBram Moolenaar 		ga_concat(gap, (char_u *)"[]");
260520e1e41SBram Moolenaar 	    else
261520e1e41SBram Moolenaar 	    {
262520e1e41SBram Moolenaar 		if (l->lv_copyID == copyID)
263520e1e41SBram Moolenaar 		    ga_concat(gap, (char_u *)"[]");
264520e1e41SBram Moolenaar 		else
265520e1e41SBram Moolenaar 		{
266520e1e41SBram Moolenaar 		    listitem_T	*li;
267520e1e41SBram Moolenaar 
268520e1e41SBram Moolenaar 		    l->lv_copyID = copyID;
269520e1e41SBram Moolenaar 		    ga_append(gap, '[');
2707e9f351bSBram Moolenaar 		    CHECK_LIST_MATERIALIZE(l);
271520e1e41SBram Moolenaar 		    for (li = l->lv_first; li != NULL && !got_int; )
272520e1e41SBram Moolenaar 		    {
273595e64e2SBram Moolenaar 			if (json_encode_item(gap, &li->li_tv, copyID,
274595e64e2SBram Moolenaar 						   options & JSON_JS) == FAIL)
275fcaaae6bSBram Moolenaar 			    return FAIL;
276595e64e2SBram Moolenaar 			if ((options & JSON_JS)
277595e64e2SBram Moolenaar 				&& li->li_next == NULL
278595e64e2SBram Moolenaar 				&& li->li_tv.v_type == VAR_SPECIAL
279595e64e2SBram Moolenaar 				&& li->li_tv.vval.v_number == VVAL_NONE)
2804ba37b58SBram Moolenaar 			    // add an extra comma if the last item is v:none
281595e64e2SBram Moolenaar 			    ga_append(gap, ',');
282520e1e41SBram Moolenaar 			li = li->li_next;
283520e1e41SBram Moolenaar 			if (li != NULL)
284520e1e41SBram Moolenaar 			    ga_append(gap, ',');
285520e1e41SBram Moolenaar 		    }
286520e1e41SBram Moolenaar 		    ga_append(gap, ']');
287fcaaae6bSBram Moolenaar 		    l->lv_copyID = 0;
288520e1e41SBram Moolenaar 		}
289520e1e41SBram Moolenaar 	    }
290520e1e41SBram Moolenaar 	    break;
291520e1e41SBram Moolenaar 
292520e1e41SBram Moolenaar 	case VAR_DICT:
293520e1e41SBram Moolenaar 	    d = val->vval.v_dict;
294520e1e41SBram Moolenaar 	    if (d == NULL)
295b29d328eSBram Moolenaar 		ga_concat(gap, (char_u *)"{}");
296520e1e41SBram Moolenaar 	    else
297520e1e41SBram Moolenaar 	    {
298520e1e41SBram Moolenaar 		if (d->dv_copyID == copyID)
299520e1e41SBram Moolenaar 		    ga_concat(gap, (char_u *)"{}");
300520e1e41SBram Moolenaar 		else
301520e1e41SBram Moolenaar 		{
302520e1e41SBram Moolenaar 		    int		first = TRUE;
303520e1e41SBram Moolenaar 		    int		todo = (int)d->dv_hashtab.ht_used;
304520e1e41SBram Moolenaar 		    hashitem_T	*hi;
305520e1e41SBram Moolenaar 
306520e1e41SBram Moolenaar 		    d->dv_copyID = copyID;
307520e1e41SBram Moolenaar 		    ga_append(gap, '{');
308520e1e41SBram Moolenaar 
309520e1e41SBram Moolenaar 		    for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
310520e1e41SBram Moolenaar 									 ++hi)
311520e1e41SBram Moolenaar 			if (!HASHITEM_EMPTY(hi))
312520e1e41SBram Moolenaar 			{
313520e1e41SBram Moolenaar 			    --todo;
314520e1e41SBram Moolenaar 			    if (first)
315520e1e41SBram Moolenaar 				first = FALSE;
316520e1e41SBram Moolenaar 			    else
317520e1e41SBram Moolenaar 				ga_append(gap, ',');
318595e64e2SBram Moolenaar 			    if ((options & JSON_JS)
319595e64e2SBram Moolenaar 						 && is_simple_key(hi->hi_key))
320595e64e2SBram Moolenaar 				ga_concat(gap, hi->hi_key);
321595e64e2SBram Moolenaar 			    else
322520e1e41SBram Moolenaar 				write_string(gap, hi->hi_key);
323520e1e41SBram Moolenaar 			    ga_append(gap, ':');
324fcaaae6bSBram Moolenaar 			    if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
325595e64e2SBram Moolenaar 				      copyID, options | JSON_NO_NONE) == FAIL)
326fcaaae6bSBram Moolenaar 				return FAIL;
327520e1e41SBram Moolenaar 			}
328520e1e41SBram Moolenaar 		    ga_append(gap, '}');
329fcaaae6bSBram Moolenaar 		    d->dv_copyID = 0;
330520e1e41SBram Moolenaar 		}
331520e1e41SBram Moolenaar 	    }
332520e1e41SBram Moolenaar 	    break;
333520e1e41SBram Moolenaar 
334520e1e41SBram Moolenaar 	case VAR_FLOAT:
33555fab439SBram Moolenaar #ifdef FEAT_FLOAT
336f1b6ac72SBram Moolenaar # if defined(HAVE_MATH_H)
3377ce686c9SBram Moolenaar 	    if (isnan(val->vval.v_float))
338f1b6ac72SBram Moolenaar 		ga_concat(gap, (char_u *)"NaN");
3397ce686c9SBram Moolenaar 	    else if (isinf(val->vval.v_float))
3405f6b379fSBram Moolenaar 	    {
3415f6b379fSBram Moolenaar 		if (val->vval.v_float < 0.0)
3425f6b379fSBram Moolenaar 		    ga_concat(gap, (char_u *)"-Infinity");
3435f6b379fSBram Moolenaar 		else
344f1b6ac72SBram Moolenaar 		    ga_concat(gap, (char_u *)"Infinity");
3455f6b379fSBram Moolenaar 	    }
346f1b6ac72SBram Moolenaar 	    else
347f1b6ac72SBram Moolenaar # endif
348f1b6ac72SBram Moolenaar 	    {
349f1b6ac72SBram Moolenaar 		vim_snprintf((char *)numbuf, NUMBUFLEN, "%g",
350f1b6ac72SBram Moolenaar 							   val->vval.v_float);
351520e1e41SBram Moolenaar 		ga_concat(gap, numbuf);
352f1b6ac72SBram Moolenaar 	    }
353520e1e41SBram Moolenaar 	    break;
354520e1e41SBram Moolenaar #endif
35555fab439SBram Moolenaar 	case VAR_UNKNOWN:
3564c683750SBram Moolenaar 	case VAR_ANY:
3578a7d6542SBram Moolenaar 	case VAR_VOID:
358dd58923cSBram Moolenaar 	    internal_error_no_abort("json_encode_item()");
359fcaaae6bSBram Moolenaar 	    return FAIL;
360520e1e41SBram Moolenaar     }
361fcaaae6bSBram Moolenaar     return OK;
362520e1e41SBram Moolenaar }
363520e1e41SBram Moolenaar 
364520e1e41SBram Moolenaar /*
36556ead341SBram Moolenaar  * When "reader" has less than NUMBUFLEN bytes available, call the fill
36656ead341SBram Moolenaar  * callback to get more.
36756ead341SBram Moolenaar  */
36856ead341SBram Moolenaar     static void
fill_numbuflen(js_read_T * reader)36956ead341SBram Moolenaar fill_numbuflen(js_read_T *reader)
37056ead341SBram Moolenaar {
37156ead341SBram Moolenaar     if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf)
37256ead341SBram Moolenaar 						- reader->js_used < NUMBUFLEN)
37356ead341SBram Moolenaar     {
37456ead341SBram Moolenaar 	if (reader->js_fill(reader))
37556ead341SBram Moolenaar 	    reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
37656ead341SBram Moolenaar     }
37756ead341SBram Moolenaar }
37856ead341SBram Moolenaar 
37956ead341SBram Moolenaar /*
380595e64e2SBram Moolenaar  * Skip white space in "reader".  All characters <= space are considered white
381595e64e2SBram Moolenaar  * space.
38256ead341SBram Moolenaar  * Also tops up readahead when needed.
383520e1e41SBram Moolenaar  */
384520e1e41SBram Moolenaar     static void
json_skip_white(js_read_T * reader)385520e1e41SBram Moolenaar json_skip_white(js_read_T *reader)
386520e1e41SBram Moolenaar {
387520e1e41SBram Moolenaar     int c;
388520e1e41SBram Moolenaar 
38956ead341SBram Moolenaar     for (;;)
39056ead341SBram Moolenaar     {
39156ead341SBram Moolenaar 	c = reader->js_buf[reader->js_used];
39256ead341SBram Moolenaar 	if (reader->js_fill != NULL && c == NUL)
39356ead341SBram Moolenaar 	{
39456ead341SBram Moolenaar 	    if (reader->js_fill(reader))
39546c00a65SBram Moolenaar 	    {
39656ead341SBram Moolenaar 		reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
39756ead341SBram Moolenaar 		continue;
39856ead341SBram Moolenaar 	    }
39946c00a65SBram Moolenaar 	}
400595e64e2SBram Moolenaar 	if (c == NUL || c > ' ')
40156ead341SBram Moolenaar 	    break;
402520e1e41SBram Moolenaar 	++reader->js_used;
403520e1e41SBram Moolenaar     }
40456ead341SBram Moolenaar     fill_numbuflen(reader);
405520e1e41SBram Moolenaar }
406520e1e41SBram Moolenaar 
40756ead341SBram Moolenaar     static int
json_decode_string(js_read_T * reader,typval_T * res,int quote)408ee142addSBram Moolenaar json_decode_string(js_read_T *reader, typval_T *res, int quote)
409520e1e41SBram Moolenaar {
410520e1e41SBram Moolenaar     garray_T    ga;
411520e1e41SBram Moolenaar     int		len;
41256ead341SBram Moolenaar     char_u	*p;
413520e1e41SBram Moolenaar     int		c;
41422fcfad2SBram Moolenaar     varnumber_T	nr;
415520e1e41SBram Moolenaar 
41656ead341SBram Moolenaar     if (res != NULL)
417520e1e41SBram Moolenaar 	ga_init2(&ga, 1, 200);
418520e1e41SBram Moolenaar 
4194ba37b58SBram Moolenaar     p = reader->js_buf + reader->js_used + 1; // skip over " or '
420ee142addSBram Moolenaar     while (*p != quote)
421520e1e41SBram Moolenaar     {
4224ba37b58SBram Moolenaar 	// The JSON is always expected to be utf-8, thus use utf functions
4234ba37b58SBram Moolenaar 	// here. The string is converted below if needed.
424fc3abf47SBram Moolenaar 	if (*p == NUL || p[1] == NUL || utf_ptr2len(p) < utf_byte2len(*p))
42556ead341SBram Moolenaar 	{
4264ba37b58SBram Moolenaar 	    // Not enough bytes to make a character or end of the string. Get
4274ba37b58SBram Moolenaar 	    // more if possible.
42856ead341SBram Moolenaar 	    if (reader->js_fill == NULL)
42956ead341SBram Moolenaar 		break;
43056ead341SBram Moolenaar 	    len = (int)(reader->js_end - p);
43156ead341SBram Moolenaar 	    reader->js_used = (int)(p - reader->js_buf);
43256ead341SBram Moolenaar 	    if (!reader->js_fill(reader))
4334ba37b58SBram Moolenaar 		break; // didn't get more
43456ead341SBram Moolenaar 	    p = reader->js_buf + reader->js_used;
43556ead341SBram Moolenaar 	    reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
43656ead341SBram Moolenaar 	    continue;
43756ead341SBram Moolenaar 	}
43856ead341SBram Moolenaar 
439520e1e41SBram Moolenaar 	if (*p == '\\')
440520e1e41SBram Moolenaar 	{
441520e1e41SBram Moolenaar 	    c = -1;
442520e1e41SBram Moolenaar 	    switch (p[1])
443520e1e41SBram Moolenaar 	    {
44456ead341SBram Moolenaar 		case '\\': c = '\\'; break;
44556ead341SBram Moolenaar 		case '"': c = '"'; break;
446520e1e41SBram Moolenaar 		case 'b': c = BS; break;
447520e1e41SBram Moolenaar 		case 't': c = TAB; break;
448520e1e41SBram Moolenaar 		case 'n': c = NL; break;
449520e1e41SBram Moolenaar 		case 'f': c = FF; break;
450520e1e41SBram Moolenaar 		case 'r': c = CAR; break;
451520e1e41SBram Moolenaar 		case 'u':
45256ead341SBram Moolenaar 		    if (reader->js_fill != NULL
45356ead341SBram Moolenaar 				     && (int)(reader->js_end - p) < NUMBUFLEN)
45456ead341SBram Moolenaar 		    {
45556ead341SBram Moolenaar 			reader->js_used = (int)(p - reader->js_buf);
45656ead341SBram Moolenaar 			if (reader->js_fill(reader))
45756ead341SBram Moolenaar 			{
45856ead341SBram Moolenaar 			    p = reader->js_buf + reader->js_used;
45956ead341SBram Moolenaar 			    reader->js_end = reader->js_buf
46056ead341SBram Moolenaar 						     + STRLEN(reader->js_buf);
46156ead341SBram Moolenaar 			}
46256ead341SBram Moolenaar 		    }
463b6ff8118SBram Moolenaar 		    nr = 0;
464b6ff8118SBram Moolenaar 		    len = 0;
465520e1e41SBram Moolenaar 		    vim_str2nr(p + 2, NULL, &len,
46616e9b851SBram Moolenaar 			     STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4, TRUE);
46716e9b851SBram Moolenaar 		    if (len == 0)
46816e9b851SBram Moolenaar 		    {
469b4368372SBram Moolenaar 			if (res != NULL)
47016e9b851SBram Moolenaar 			    ga_clear(&ga);
47116e9b851SBram Moolenaar 			return FAIL;
47216e9b851SBram Moolenaar 		    }
473520e1e41SBram Moolenaar 		    p += len + 2;
474b6ff8118SBram Moolenaar 		    if (0xd800 <= nr && nr <= 0xdfff
475b6ff8118SBram Moolenaar 			    && (int)(reader->js_end - p) >= 6
476b6ff8118SBram Moolenaar 			    && *p == '\\' && *(p+1) == 'u')
477b6ff8118SBram Moolenaar 		    {
47822fcfad2SBram Moolenaar 			varnumber_T	nr2 = 0;
479b6ff8118SBram Moolenaar 
4804ba37b58SBram Moolenaar 			// decode surrogate pair: \ud812\u3456
481b6ff8118SBram Moolenaar 			len = 0;
482b6ff8118SBram Moolenaar 			vim_str2nr(p + 2, NULL, &len,
48316e9b851SBram Moolenaar 			     STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4, TRUE);
48416e9b851SBram Moolenaar 			if (len == 0)
48516e9b851SBram Moolenaar 			{
486b4368372SBram Moolenaar 			    if (res != NULL)
48716e9b851SBram Moolenaar 				ga_clear(&ga);
48816e9b851SBram Moolenaar 			    return FAIL;
48916e9b851SBram Moolenaar 			}
490b6ff8118SBram Moolenaar 			if (0xdc00 <= nr2 && nr2 <= 0xdfff)
491b6ff8118SBram Moolenaar 			{
492b6ff8118SBram Moolenaar 			    p += len + 2;
493b6ff8118SBram Moolenaar 			    nr = (((nr - 0xd800) << 10) |
494b6ff8118SBram Moolenaar 				((nr2 - 0xdc00) & 0x3ff)) + 0x10000;
495b6ff8118SBram Moolenaar 			}
496b6ff8118SBram Moolenaar 		    }
49756ead341SBram Moolenaar 		    if (res != NULL)
49856ead341SBram Moolenaar 		    {
499dc633cf8SBram Moolenaar 			char_u	buf[NUMBUFLEN];
500b4368372SBram Moolenaar 
501b6ff8118SBram Moolenaar 			buf[utf_char2bytes((int)nr, buf)] = NUL;
502520e1e41SBram Moolenaar 			ga_concat(&ga, buf);
50356ead341SBram Moolenaar 		    }
504520e1e41SBram Moolenaar 		    break;
50556ead341SBram Moolenaar 		default:
5064ba37b58SBram Moolenaar 		    // not a special char, skip over backslash
50756ead341SBram Moolenaar 		    ++p;
50856ead341SBram Moolenaar 		    continue;
509520e1e41SBram Moolenaar 	    }
510520e1e41SBram Moolenaar 	    if (c > 0)
511520e1e41SBram Moolenaar 	    {
512520e1e41SBram Moolenaar 		p += 2;
51356ead341SBram Moolenaar 		if (res != NULL)
514520e1e41SBram Moolenaar 		    ga_append(&ga, c);
515520e1e41SBram Moolenaar 	    }
516520e1e41SBram Moolenaar 	}
517520e1e41SBram Moolenaar 	else
518520e1e41SBram Moolenaar 	{
519b6ff8118SBram Moolenaar 	    len = utf_ptr2len(p);
52056ead341SBram Moolenaar 	    if (res != NULL)
521520e1e41SBram Moolenaar 	    {
52256ead341SBram Moolenaar 		if (ga_grow(&ga, len) == FAIL)
52356ead341SBram Moolenaar 		{
52456ead341SBram Moolenaar 		    ga_clear(&ga);
52556ead341SBram Moolenaar 		    return FAIL;
52656ead341SBram Moolenaar 		}
527520e1e41SBram Moolenaar 		mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
528520e1e41SBram Moolenaar 		ga.ga_len += len;
529520e1e41SBram Moolenaar 	    }
530520e1e41SBram Moolenaar 	    p += len;
531520e1e41SBram Moolenaar 	}
532520e1e41SBram Moolenaar     }
53356ead341SBram Moolenaar 
534520e1e41SBram Moolenaar     reader->js_used = (int)(p - reader->js_buf);
535ee142addSBram Moolenaar     if (*p == quote)
536520e1e41SBram Moolenaar     {
537520e1e41SBram Moolenaar 	++reader->js_used;
53856ead341SBram Moolenaar 	if (res != NULL)
53956ead341SBram Moolenaar 	{
54080e78847SBram Moolenaar 	    ga_append(&ga, NUL);
541520e1e41SBram Moolenaar 	    res->v_type = VAR_STRING;
542fc3abf47SBram Moolenaar #if defined(USE_ICONV)
543b3628728SBram Moolenaar 	    if (!enc_utf8)
544b3628728SBram Moolenaar 	    {
545b3628728SBram Moolenaar 		vimconv_T   conv;
546b3628728SBram Moolenaar 
5474ba37b58SBram Moolenaar 		// Convert the utf-8 string to 'encoding'.
548b3628728SBram Moolenaar 		conv.vc_type = CONV_NONE;
549b3628728SBram Moolenaar 		convert_setup(&conv, (char_u*)"utf-8", p_enc);
550b3628728SBram Moolenaar 		if (conv.vc_type != CONV_NONE)
551b3628728SBram Moolenaar 		{
552b3628728SBram Moolenaar 		    res->vval.v_string =
553b3628728SBram Moolenaar 				      string_convert(&conv, ga.ga_data, NULL);
554b3628728SBram Moolenaar 		    vim_free(ga.ga_data);
555b3628728SBram Moolenaar 		}
556b3628728SBram Moolenaar 		convert_setup(&conv, NULL, NULL);
557b3628728SBram Moolenaar 	    }
558b3628728SBram Moolenaar 	    else
559b3628728SBram Moolenaar #endif
5604b6a6dcbSBram Moolenaar 		res->vval.v_string = ga.ga_data;
561520e1e41SBram Moolenaar 	}
56256ead341SBram Moolenaar 	return OK;
56356ead341SBram Moolenaar     }
56456ead341SBram Moolenaar     if (res != NULL)
565520e1e41SBram Moolenaar     {
566520e1e41SBram Moolenaar 	res->v_type = VAR_SPECIAL;
567520e1e41SBram Moolenaar 	res->vval.v_number = VVAL_NONE;
568520e1e41SBram Moolenaar 	ga_clear(&ga);
569520e1e41SBram Moolenaar     }
57056ead341SBram Moolenaar     return MAYBE;
57156ead341SBram Moolenaar }
572520e1e41SBram Moolenaar 
5738b2f1953SBram Moolenaar typedef enum {
5744ba37b58SBram Moolenaar     JSON_ARRAY,		// parsing items in an array
5754ba37b58SBram Moolenaar     JSON_OBJECT_KEY,	// parsing key of an object
5764ba37b58SBram Moolenaar     JSON_OBJECT		// parsing item in an object, after the key
5778b2f1953SBram Moolenaar } json_decode_T;
5788b2f1953SBram Moolenaar 
5798b2f1953SBram Moolenaar typedef struct {
5808b2f1953SBram Moolenaar     json_decode_T jd_type;
5814ba37b58SBram Moolenaar     typval_T	  jd_tv;	// the list or dict
5828b2f1953SBram Moolenaar     typval_T	  jd_key_tv;
5838b2f1953SBram Moolenaar     char_u	  *jd_key;
5848b2f1953SBram Moolenaar } json_dec_item_T;
5858b2f1953SBram Moolenaar 
586520e1e41SBram Moolenaar /*
58756ead341SBram Moolenaar  * Decode one item and put it in "res".  If "res" is NULL only advance.
588520e1e41SBram Moolenaar  * Must already have skipped white space.
58956ead341SBram Moolenaar  *
59003c60c15SBram Moolenaar  * Return FAIL for a decoding error (and give an error).
59156ead341SBram Moolenaar  * Return MAYBE for an incomplete message.
592520e1e41SBram Moolenaar  */
59356ead341SBram Moolenaar     static int
json_decode_item(js_read_T * reader,typval_T * res,int options)594595e64e2SBram Moolenaar json_decode_item(js_read_T *reader, typval_T *res, int options)
595520e1e41SBram Moolenaar {
59656ead341SBram Moolenaar     char_u	*p;
5976d3a7213SBram Moolenaar     int		i;
59856ead341SBram Moolenaar     int		len;
5998b2f1953SBram Moolenaar     int		retval;
6008b2f1953SBram Moolenaar     garray_T	stack;
6018b2f1953SBram Moolenaar     typval_T	item;
6028b2f1953SBram Moolenaar     typval_T	*cur_item;
6038b2f1953SBram Moolenaar     json_dec_item_T *top_item;
6048b2f1953SBram Moolenaar     char_u	key_buf[NUMBUFLEN];
6058b2f1953SBram Moolenaar 
6068b2f1953SBram Moolenaar     ga_init2(&stack, sizeof(json_dec_item_T), 100);
6078b2f1953SBram Moolenaar     cur_item = res;
6088b2f1953SBram Moolenaar     init_tv(&item);
609e32abbe4SBram Moolenaar     if (res != NULL)
610e32abbe4SBram Moolenaar 	init_tv(res);
611520e1e41SBram Moolenaar 
61256ead341SBram Moolenaar     fill_numbuflen(reader);
61356ead341SBram Moolenaar     p = reader->js_buf + reader->js_used;
6148b2f1953SBram Moolenaar     for (;;)
6158b2f1953SBram Moolenaar     {
6168b2f1953SBram Moolenaar 	top_item = NULL;
6178b2f1953SBram Moolenaar 	if (stack.ga_len > 0)
6188b2f1953SBram Moolenaar 	{
6198b2f1953SBram Moolenaar 	    top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1;
6208b2f1953SBram Moolenaar 	    json_skip_white(reader);
6218b2f1953SBram Moolenaar 	    p = reader->js_buf + reader->js_used;
6228b2f1953SBram Moolenaar 	    if (*p == NUL)
6238b2f1953SBram Moolenaar 	    {
6248b2f1953SBram Moolenaar 		retval = MAYBE;
6258b2f1953SBram Moolenaar 		goto theend;
6268b2f1953SBram Moolenaar 	    }
6278b2f1953SBram Moolenaar 	    if (top_item->jd_type == JSON_OBJECT_KEY
6288b2f1953SBram Moolenaar 					    || top_item->jd_type == JSON_ARRAY)
6298b2f1953SBram Moolenaar 	    {
6304ba37b58SBram Moolenaar 		// Check for end of object or array.
6318b2f1953SBram Moolenaar 		if (*p == (top_item->jd_type == JSON_ARRAY ? ']' : '}'))
6328b2f1953SBram Moolenaar 		{
6334ba37b58SBram Moolenaar 		    ++reader->js_used; // consume the ']' or '}'
6348b2f1953SBram Moolenaar 		    --stack.ga_len;
6358b2f1953SBram Moolenaar 		    if (stack.ga_len == 0)
6368b2f1953SBram Moolenaar 		    {
6378b2f1953SBram Moolenaar 			retval = OK;
6388b2f1953SBram Moolenaar 			goto theend;
6398b2f1953SBram Moolenaar 		    }
6408b2f1953SBram Moolenaar 		    if (cur_item != NULL)
6418b2f1953SBram Moolenaar 			cur_item = &top_item->jd_tv;
6428b2f1953SBram Moolenaar 		    goto item_end;
6438b2f1953SBram Moolenaar 		}
6448b2f1953SBram Moolenaar 	    }
6458b2f1953SBram Moolenaar 	}
6468b2f1953SBram Moolenaar 
6478b2f1953SBram Moolenaar 	if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY
6488b2f1953SBram Moolenaar 		&& (options & JSON_JS)
649ee142addSBram Moolenaar 		&& reader->js_buf[reader->js_used] != '"'
650625f0c1eSBram Moolenaar 		&& reader->js_buf[reader->js_used] != '\''
651625f0c1eSBram Moolenaar 		&& reader->js_buf[reader->js_used] != '['
652625f0c1eSBram Moolenaar 		&& reader->js_buf[reader->js_used] != '{')
6538b2f1953SBram Moolenaar 	{
6548b2f1953SBram Moolenaar 	    char_u *key;
6558b2f1953SBram Moolenaar 
6564ba37b58SBram Moolenaar 	    // accept an object key that is not in quotes
6578b2f1953SBram Moolenaar 	    key = p = reader->js_buf + reader->js_used;
6588b2f1953SBram Moolenaar 	    while (*p != NUL && *p != ':' && *p > ' ')
6598b2f1953SBram Moolenaar 		++p;
660e2c6037dSBram Moolenaar 	    if (cur_item != NULL)
661e2c6037dSBram Moolenaar 	    {
6628b2f1953SBram Moolenaar 		cur_item->v_type = VAR_STRING;
66371ccd03eSBram Moolenaar 		cur_item->vval.v_string = vim_strnsave(key, p - key);
6648b2f1953SBram Moolenaar 		top_item->jd_key = cur_item->vval.v_string;
6658b2f1953SBram Moolenaar 	    }
666e2c6037dSBram Moolenaar 	    reader->js_used += (int)(p - key);
667e2c6037dSBram Moolenaar 	}
6688b2f1953SBram Moolenaar 	else
6698b2f1953SBram Moolenaar 	{
670520e1e41SBram Moolenaar 	    switch (*p)
671520e1e41SBram Moolenaar 	    {
6724ba37b58SBram Moolenaar 		case '[': // start of array
673625f0c1eSBram Moolenaar 		    if (top_item && top_item->jd_type == JSON_OBJECT_KEY)
674625f0c1eSBram Moolenaar 		    {
675625f0c1eSBram Moolenaar 			retval = FAIL;
676625f0c1eSBram Moolenaar 			break;
677625f0c1eSBram Moolenaar 		    }
6788b2f1953SBram Moolenaar 		    if (ga_grow(&stack, 1) == FAIL)
6798b2f1953SBram Moolenaar 		    {
6808b2f1953SBram Moolenaar 			retval = FAIL;
6818b2f1953SBram Moolenaar 			break;
6828b2f1953SBram Moolenaar 		    }
6838b2f1953SBram Moolenaar 		    if (cur_item != NULL && rettv_list_alloc(cur_item) == FAIL)
6848b2f1953SBram Moolenaar 		    {
6858b2f1953SBram Moolenaar 			cur_item->v_type = VAR_SPECIAL;
6868b2f1953SBram Moolenaar 			cur_item->vval.v_number = VVAL_NONE;
6878b2f1953SBram Moolenaar 			retval = FAIL;
6888b2f1953SBram Moolenaar 			break;
6898b2f1953SBram Moolenaar 		    }
690520e1e41SBram Moolenaar 
6914ba37b58SBram Moolenaar 		    ++reader->js_used; // consume the '['
6928b2f1953SBram Moolenaar 		    top_item = ((json_dec_item_T *)stack.ga_data)
6938b2f1953SBram Moolenaar 								+ stack.ga_len;
6948b2f1953SBram Moolenaar 		    top_item->jd_type = JSON_ARRAY;
6958b2f1953SBram Moolenaar 		    ++stack.ga_len;
6968b2f1953SBram Moolenaar 		    if (cur_item != NULL)
6978b2f1953SBram Moolenaar 		    {
6988b2f1953SBram Moolenaar 			top_item->jd_tv = *cur_item;
6998b2f1953SBram Moolenaar 			cur_item = &item;
7008b2f1953SBram Moolenaar 		    }
7018b2f1953SBram Moolenaar 		    continue;
7028b2f1953SBram Moolenaar 
7034ba37b58SBram Moolenaar 		case '{': // start of object
704625f0c1eSBram Moolenaar 		    if (top_item && top_item->jd_type == JSON_OBJECT_KEY)
705625f0c1eSBram Moolenaar 		    {
706625f0c1eSBram Moolenaar 			retval = FAIL;
707625f0c1eSBram Moolenaar 			break;
708625f0c1eSBram Moolenaar 		    }
7098b2f1953SBram Moolenaar 		    if (ga_grow(&stack, 1) == FAIL)
7108b2f1953SBram Moolenaar 		    {
7118b2f1953SBram Moolenaar 			retval = FAIL;
7128b2f1953SBram Moolenaar 			break;
7138b2f1953SBram Moolenaar 		    }
7148b2f1953SBram Moolenaar 		    if (cur_item != NULL && rettv_dict_alloc(cur_item) == FAIL)
7158b2f1953SBram Moolenaar 		    {
7168b2f1953SBram Moolenaar 			cur_item->v_type = VAR_SPECIAL;
7178b2f1953SBram Moolenaar 			cur_item->vval.v_number = VVAL_NONE;
7188b2f1953SBram Moolenaar 			retval = FAIL;
7198b2f1953SBram Moolenaar 			break;
7208b2f1953SBram Moolenaar 		    }
7218b2f1953SBram Moolenaar 
7224ba37b58SBram Moolenaar 		    ++reader->js_used; // consume the '{'
7238b2f1953SBram Moolenaar 		    top_item = ((json_dec_item_T *)stack.ga_data)
7248b2f1953SBram Moolenaar 								+ stack.ga_len;
7258b2f1953SBram Moolenaar 		    top_item->jd_type = JSON_OBJECT_KEY;
7268b2f1953SBram Moolenaar 		    ++stack.ga_len;
7278b2f1953SBram Moolenaar 		    if (cur_item != NULL)
7288b2f1953SBram Moolenaar 		    {
7298b2f1953SBram Moolenaar 			top_item->jd_tv = *cur_item;
7308b2f1953SBram Moolenaar 			cur_item = &top_item->jd_key_tv;
7318b2f1953SBram Moolenaar 		    }
7328b2f1953SBram Moolenaar 		    continue;
733520e1e41SBram Moolenaar 
7344ba37b58SBram Moolenaar 		case '"': // string
735ee142addSBram Moolenaar 		    retval = json_decode_string(reader, cur_item, *p);
736ee142addSBram Moolenaar 		    break;
737ee142addSBram Moolenaar 
738ee142addSBram Moolenaar 		case '\'':
739ee142addSBram Moolenaar 		    if (options & JSON_JS)
740ee142addSBram Moolenaar 			retval = json_decode_string(reader, cur_item, *p);
741ee142addSBram Moolenaar 		    else
742ee142addSBram Moolenaar 		    {
743a09195f2SBram Moolenaar 			semsg(_(e_json_error), p);
744ee142addSBram Moolenaar 			retval = FAIL;
745ee142addSBram Moolenaar 		    }
7468b2f1953SBram Moolenaar 		    break;
747520e1e41SBram Moolenaar 
7484ba37b58SBram Moolenaar 		case ',': // comma: empty item
749595e64e2SBram Moolenaar 		    if ((options & JSON_JS) == 0)
75003c60c15SBram Moolenaar 		    {
751a09195f2SBram Moolenaar 			semsg(_(e_json_error), p);
7528b2f1953SBram Moolenaar 			retval = FAIL;
7538b2f1953SBram Moolenaar 			break;
75403c60c15SBram Moolenaar 		    }
7554ba37b58SBram Moolenaar 		    // FALLTHROUGH
7564ba37b58SBram Moolenaar 		case NUL: // empty
7578b2f1953SBram Moolenaar 		    if (cur_item != NULL)
75856ead341SBram Moolenaar 		    {
7598b2f1953SBram Moolenaar 			cur_item->v_type = VAR_SPECIAL;
7608b2f1953SBram Moolenaar 			cur_item->vval.v_number = VVAL_NONE;
76156ead341SBram Moolenaar 		    }
7628b2f1953SBram Moolenaar 		    retval = OK;
7638b2f1953SBram Moolenaar 		    break;
764520e1e41SBram Moolenaar 
765520e1e41SBram Moolenaar 		default:
766a5d5953dSBram Moolenaar 		    if (VIM_ISDIGIT(*p) || (*p == '-'
767a5d5953dSBram Moolenaar 					&& (VIM_ISDIGIT(p[1]) || p[1] == NUL)))
768520e1e41SBram Moolenaar 		    {
769520e1e41SBram Moolenaar 			char_u  *sp = p;
77056ead341SBram Moolenaar 
771520e1e41SBram Moolenaar 			if (*sp == '-')
77256ead341SBram Moolenaar 			{
773520e1e41SBram Moolenaar 			    ++sp;
77456ead341SBram Moolenaar 			    if (*sp == NUL)
7758b2f1953SBram Moolenaar 			    {
7768b2f1953SBram Moolenaar 				retval = MAYBE;
7778b2f1953SBram Moolenaar 				break;
7788b2f1953SBram Moolenaar 			    }
77956ead341SBram Moolenaar 			    if (!VIM_ISDIGIT(*sp))
78003c60c15SBram Moolenaar 			    {
781a09195f2SBram Moolenaar 				semsg(_(e_json_error), p);
7828b2f1953SBram Moolenaar 				retval = FAIL;
7838b2f1953SBram Moolenaar 				break;
78456ead341SBram Moolenaar 			    }
78503c60c15SBram Moolenaar 			}
786520e1e41SBram Moolenaar 			sp = skipdigits(sp);
787a5d5953dSBram Moolenaar #ifdef FEAT_FLOAT
788520e1e41SBram Moolenaar 			if (*sp == '.' || *sp == 'e' || *sp == 'E')
789520e1e41SBram Moolenaar 			{
7908b2f1953SBram Moolenaar 			    if (cur_item == NULL)
79156ead341SBram Moolenaar 			    {
79256ead341SBram Moolenaar 				float_T f;
79356ead341SBram Moolenaar 
794*2950065eSBram Moolenaar 				len = string2float(p, &f, FALSE);
79556ead341SBram Moolenaar 			    }
79656ead341SBram Moolenaar 			    else
79756ead341SBram Moolenaar 			    {
7988b2f1953SBram Moolenaar 				cur_item->v_type = VAR_FLOAT;
799*2950065eSBram Moolenaar 				len = string2float(p, &cur_item->vval.v_float,
800*2950065eSBram Moolenaar 									FALSE);
801520e1e41SBram Moolenaar 			    }
80256ead341SBram Moolenaar 			}
803520e1e41SBram Moolenaar 			else
804520e1e41SBram Moolenaar #endif
805520e1e41SBram Moolenaar 			{
80622fcfad2SBram Moolenaar 			    varnumber_T nr;
807520e1e41SBram Moolenaar 
808520e1e41SBram Moolenaar 			    vim_str2nr(reader->js_buf + reader->js_used,
8094ba37b58SBram Moolenaar 				    NULL, &len, 0, // what
81016e9b851SBram Moolenaar 				    &nr, NULL, 0, TRUE);
81116e9b851SBram Moolenaar 			    if (len == 0)
81216e9b851SBram Moolenaar 			    {
813a09195f2SBram Moolenaar 				semsg(_(e_json_error), p);
81416e9b851SBram Moolenaar 				retval = FAIL;
81516e9b851SBram Moolenaar 				goto theend;
81616e9b851SBram Moolenaar 			    }
8178b2f1953SBram Moolenaar 			    if (cur_item != NULL)
81856ead341SBram Moolenaar 			    {
8198b2f1953SBram Moolenaar 				cur_item->v_type = VAR_NUMBER;
8208b2f1953SBram Moolenaar 				cur_item->vval.v_number = nr;
821520e1e41SBram Moolenaar 			    }
82256ead341SBram Moolenaar 			}
823520e1e41SBram Moolenaar 			reader->js_used += len;
8248b2f1953SBram Moolenaar 			retval = OK;
8258b2f1953SBram Moolenaar 			break;
826520e1e41SBram Moolenaar 		    }
827520e1e41SBram Moolenaar 		    if (STRNICMP((char *)p, "false", 5) == 0)
828520e1e41SBram Moolenaar 		    {
829520e1e41SBram Moolenaar 			reader->js_used += 5;
8308b2f1953SBram Moolenaar 			if (cur_item != NULL)
83156ead341SBram Moolenaar 			{
8329b4a15d5SBram Moolenaar 			    cur_item->v_type = VAR_BOOL;
8338b2f1953SBram Moolenaar 			    cur_item->vval.v_number = VVAL_FALSE;
83456ead341SBram Moolenaar 			}
8358b2f1953SBram Moolenaar 			retval = OK;
8368b2f1953SBram Moolenaar 			break;
837520e1e41SBram Moolenaar 		    }
838520e1e41SBram Moolenaar 		    if (STRNICMP((char *)p, "true", 4) == 0)
839520e1e41SBram Moolenaar 		    {
840520e1e41SBram Moolenaar 			reader->js_used += 4;
8418b2f1953SBram Moolenaar 			if (cur_item != NULL)
84256ead341SBram Moolenaar 			{
8439b4a15d5SBram Moolenaar 			    cur_item->v_type = VAR_BOOL;
8448b2f1953SBram Moolenaar 			    cur_item->vval.v_number = VVAL_TRUE;
84556ead341SBram Moolenaar 			}
8468b2f1953SBram Moolenaar 			retval = OK;
8478b2f1953SBram Moolenaar 			break;
848520e1e41SBram Moolenaar 		    }
849520e1e41SBram Moolenaar 		    if (STRNICMP((char *)p, "null", 4) == 0)
850520e1e41SBram Moolenaar 		    {
851520e1e41SBram Moolenaar 			reader->js_used += 4;
8528b2f1953SBram Moolenaar 			if (cur_item != NULL)
85356ead341SBram Moolenaar 			{
8548b2f1953SBram Moolenaar 			    cur_item->v_type = VAR_SPECIAL;
8558b2f1953SBram Moolenaar 			    cur_item->vval.v_number = VVAL_NULL;
856520e1e41SBram Moolenaar 			}
8578b2f1953SBram Moolenaar 			retval = OK;
8588b2f1953SBram Moolenaar 			break;
85956ead341SBram Moolenaar 		    }
860f1b6ac72SBram Moolenaar #ifdef FEAT_FLOAT
861f1b6ac72SBram Moolenaar 		    if (STRNICMP((char *)p, "NaN", 3) == 0)
862f1b6ac72SBram Moolenaar 		    {
863f1b6ac72SBram Moolenaar 			reader->js_used += 3;
8648b2f1953SBram Moolenaar 			if (cur_item != NULL)
865f1b6ac72SBram Moolenaar 			{
8668b2f1953SBram Moolenaar 			    cur_item->v_type = VAR_FLOAT;
8678b2f1953SBram Moolenaar 			    cur_item->vval.v_float = NAN;
868f1b6ac72SBram Moolenaar 			}
8698b2f1953SBram Moolenaar 			retval = OK;
8708b2f1953SBram Moolenaar 			break;
871f1b6ac72SBram Moolenaar 		    }
8725f6b379fSBram Moolenaar 		    if (STRNICMP((char *)p, "-Infinity", 9) == 0)
8735f6b379fSBram Moolenaar 		    {
8745f6b379fSBram Moolenaar 			reader->js_used += 9;
8755f6b379fSBram Moolenaar 			if (cur_item != NULL)
8765f6b379fSBram Moolenaar 			{
8775f6b379fSBram Moolenaar 			    cur_item->v_type = VAR_FLOAT;
8785f6b379fSBram Moolenaar 			    cur_item->vval.v_float = -INFINITY;
8795f6b379fSBram Moolenaar 			}
8805f6b379fSBram Moolenaar 			retval = OK;
8815f6b379fSBram Moolenaar 			break;
8825f6b379fSBram Moolenaar 		    }
883f1b6ac72SBram Moolenaar 		    if (STRNICMP((char *)p, "Infinity", 8) == 0)
884f1b6ac72SBram Moolenaar 		    {
885f1b6ac72SBram Moolenaar 			reader->js_used += 8;
8868b2f1953SBram Moolenaar 			if (cur_item != NULL)
887f1b6ac72SBram Moolenaar 			{
8888b2f1953SBram Moolenaar 			    cur_item->v_type = VAR_FLOAT;
8898b2f1953SBram Moolenaar 			    cur_item->vval.v_float = INFINITY;
890f1b6ac72SBram Moolenaar 			}
8918b2f1953SBram Moolenaar 			retval = OK;
8928b2f1953SBram Moolenaar 			break;
893f1b6ac72SBram Moolenaar 		    }
894f1b6ac72SBram Moolenaar #endif
8954ba37b58SBram Moolenaar 		    // check for truncated name
896a5d5953dSBram Moolenaar 		    len = (int)(reader->js_end
897a5d5953dSBram Moolenaar 					 - (reader->js_buf + reader->js_used));
898f1b6ac72SBram Moolenaar 		    if (
899f1b6ac72SBram Moolenaar 			    (len < 5 && STRNICMP((char *)p, "false", len) == 0)
900f1b6ac72SBram Moolenaar #ifdef FEAT_FLOAT
9015f6b379fSBram Moolenaar 			    || (len < 9 && STRNICMP((char *)p, "-Infinity", len) == 0)
902f1b6ac72SBram Moolenaar 			    || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0)
903f1b6ac72SBram Moolenaar 			    || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0)
904f1b6ac72SBram Moolenaar #endif
90556ead341SBram Moolenaar 			    || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
90656ead341SBram Moolenaar 				       ||  STRNICMP((char *)p, "null", len) == 0)))
9078b2f1953SBram Moolenaar 
9088b2f1953SBram Moolenaar 			retval = MAYBE;
9098b2f1953SBram Moolenaar 		    else
9108b2f1953SBram Moolenaar 			retval = FAIL;
911520e1e41SBram Moolenaar 		    break;
912520e1e41SBram Moolenaar 	    }
913520e1e41SBram Moolenaar 
9144ba37b58SBram Moolenaar 	    // We are finished when retval is FAIL or MAYBE and when at the
9154ba37b58SBram Moolenaar 	    // toplevel.
9168b2f1953SBram Moolenaar 	    if (retval == FAIL)
9178b2f1953SBram Moolenaar 		break;
9188b2f1953SBram Moolenaar 	    if (retval == MAYBE || stack.ga_len == 0)
9198b2f1953SBram Moolenaar 		goto theend;
9208b2f1953SBram Moolenaar 
9218b2f1953SBram Moolenaar 	    if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY
9228b2f1953SBram Moolenaar 		    && cur_item != NULL)
9238b2f1953SBram Moolenaar 	    {
9243cfa5b16SBram Moolenaar #ifdef FEAT_FLOAT
9253cfa5b16SBram Moolenaar 		if (cur_item->v_type == VAR_FLOAT)
9263cfa5b16SBram Moolenaar 		{
9273cfa5b16SBram Moolenaar 		    // cannot use a float as a key
9283cfa5b16SBram Moolenaar 		    emsg(_(e_float_as_string));
9293cfa5b16SBram Moolenaar 		    retval = FAIL;
9303cfa5b16SBram Moolenaar 		    goto theend;
9313cfa5b16SBram Moolenaar 		}
9323cfa5b16SBram Moolenaar #endif
933d155d7a8SBram Moolenaar 		top_item->jd_key = tv_get_string_buf_chk(cur_item, key_buf);
934059b7482SBram Moolenaar 		if (top_item->jd_key == NULL)
9358b2f1953SBram Moolenaar 		{
936f9e3e09fSBram Moolenaar 		    emsg(_(e_invarg));
9378b2f1953SBram Moolenaar 		    retval = FAIL;
9388b2f1953SBram Moolenaar 		    goto theend;
9398b2f1953SBram Moolenaar 		}
9408b2f1953SBram Moolenaar 	    }
9418b2f1953SBram Moolenaar 	}
9428b2f1953SBram Moolenaar 
9438b2f1953SBram Moolenaar item_end:
9448b2f1953SBram Moolenaar 	top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1;
9458b2f1953SBram Moolenaar 	switch (top_item->jd_type)
9468b2f1953SBram Moolenaar 	{
9478b2f1953SBram Moolenaar 	    case JSON_ARRAY:
9487756e746SBram Moolenaar 		if (res != NULL)
94956ead341SBram Moolenaar 		{
9508b2f1953SBram Moolenaar 		    listitem_T	*li = listitem_alloc();
9518b2f1953SBram Moolenaar 
9528b2f1953SBram Moolenaar 		    if (li == NULL)
9538b2f1953SBram Moolenaar 		    {
9548b2f1953SBram Moolenaar 			clear_tv(cur_item);
9558b2f1953SBram Moolenaar 			retval = FAIL;
9568b2f1953SBram Moolenaar 			goto theend;
9578b2f1953SBram Moolenaar 		    }
9588b2f1953SBram Moolenaar 		    li->li_tv = *cur_item;
9598b2f1953SBram Moolenaar 		    list_append(top_item->jd_tv.vval.v_list, li);
9608b2f1953SBram Moolenaar 		}
9618b2f1953SBram Moolenaar 		if (cur_item != NULL)
9628b2f1953SBram Moolenaar 		    cur_item = &item;
9638b2f1953SBram Moolenaar 
9648b2f1953SBram Moolenaar 		json_skip_white(reader);
9658b2f1953SBram Moolenaar 		p = reader->js_buf + reader->js_used;
9668b2f1953SBram Moolenaar 		if (*p == ',')
9678b2f1953SBram Moolenaar 		    ++reader->js_used;
9688b2f1953SBram Moolenaar 		else if (*p != ']')
9698b2f1953SBram Moolenaar 		{
9708b2f1953SBram Moolenaar 		    if (*p == NUL)
9718b2f1953SBram Moolenaar 			retval = MAYBE;
9728b2f1953SBram Moolenaar 		    else
9738b2f1953SBram Moolenaar 		    {
974a09195f2SBram Moolenaar 			semsg(_(e_json_error), p);
9758b2f1953SBram Moolenaar 			retval = FAIL;
9768b2f1953SBram Moolenaar 		    }
9778b2f1953SBram Moolenaar 		    goto theend;
9788b2f1953SBram Moolenaar 		}
9798b2f1953SBram Moolenaar 		break;
9808b2f1953SBram Moolenaar 
9818b2f1953SBram Moolenaar 	    case JSON_OBJECT_KEY:
9828b2f1953SBram Moolenaar 		json_skip_white(reader);
9838b2f1953SBram Moolenaar 		p = reader->js_buf + reader->js_used;
9848b2f1953SBram Moolenaar 		if (*p != ':')
9858b2f1953SBram Moolenaar 		{
9868b2f1953SBram Moolenaar 		    if (cur_item != NULL)
9878b2f1953SBram Moolenaar 			clear_tv(cur_item);
9888b2f1953SBram Moolenaar 		    if (*p == NUL)
9898b2f1953SBram Moolenaar 			retval = MAYBE;
9908b2f1953SBram Moolenaar 		    else
9918b2f1953SBram Moolenaar 		    {
992a09195f2SBram Moolenaar 			semsg(_(e_json_error), p);
9938b2f1953SBram Moolenaar 			retval = FAIL;
9948b2f1953SBram Moolenaar 		    }
9958b2f1953SBram Moolenaar 		    goto theend;
9968b2f1953SBram Moolenaar 		}
9978b2f1953SBram Moolenaar 		++reader->js_used;
9988b2f1953SBram Moolenaar 		json_skip_white(reader);
9998b2f1953SBram Moolenaar 		top_item->jd_type = JSON_OBJECT;
10008b2f1953SBram Moolenaar 		if (cur_item != NULL)
10018b2f1953SBram Moolenaar 		    cur_item = &item;
10028b2f1953SBram Moolenaar 		break;
10038b2f1953SBram Moolenaar 
10048b2f1953SBram Moolenaar 	    case JSON_OBJECT:
10058b2f1953SBram Moolenaar 		if (cur_item != NULL
10068b2f1953SBram Moolenaar 			&& dict_find(top_item->jd_tv.vval.v_dict,
10078b2f1953SBram Moolenaar 						 top_item->jd_key, -1) != NULL)
10088b2f1953SBram Moolenaar 		{
1009f9e3e09fSBram Moolenaar 		    semsg(_("E938: Duplicate key in JSON: \"%s\""),
10108b2f1953SBram Moolenaar 							     top_item->jd_key);
10118b2f1953SBram Moolenaar 		    clear_tv(cur_item);
10128b2f1953SBram Moolenaar 		    retval = FAIL;
10138b2f1953SBram Moolenaar 		    goto theend;
10148b2f1953SBram Moolenaar 		}
10158b2f1953SBram Moolenaar 
10168b2f1953SBram Moolenaar 		if (cur_item != NULL)
10178b2f1953SBram Moolenaar 		{
10188b2f1953SBram Moolenaar 		    dictitem_T *di = dictitem_alloc(top_item->jd_key);
10198b2f1953SBram Moolenaar 
10208b2f1953SBram Moolenaar 		    clear_tv(&top_item->jd_key_tv);
10218b2f1953SBram Moolenaar 		    if (di == NULL)
10228b2f1953SBram Moolenaar 		    {
10238b2f1953SBram Moolenaar 			clear_tv(cur_item);
10248b2f1953SBram Moolenaar 			retval = FAIL;
10258b2f1953SBram Moolenaar 			goto theend;
10268b2f1953SBram Moolenaar 		    }
10278b2f1953SBram Moolenaar 		    di->di_tv = *cur_item;
10288b2f1953SBram Moolenaar 		    di->di_tv.v_lock = 0;
10298b2f1953SBram Moolenaar 		    if (dict_add(top_item->jd_tv.vval.v_dict, di) == FAIL)
10308b2f1953SBram Moolenaar 		    {
10318b2f1953SBram Moolenaar 			dictitem_free(di);
10328b2f1953SBram Moolenaar 			retval = FAIL;
10338b2f1953SBram Moolenaar 			goto theend;
10348b2f1953SBram Moolenaar 		    }
10358b2f1953SBram Moolenaar 		}
10368b2f1953SBram Moolenaar 
10378b2f1953SBram Moolenaar 		json_skip_white(reader);
10388b2f1953SBram Moolenaar 		p = reader->js_buf + reader->js_used;
10398b2f1953SBram Moolenaar 		if (*p == ',')
10408b2f1953SBram Moolenaar 		    ++reader->js_used;
10418b2f1953SBram Moolenaar 		else if (*p != '}')
10428b2f1953SBram Moolenaar 		{
10438b2f1953SBram Moolenaar 		    if (*p == NUL)
10448b2f1953SBram Moolenaar 			retval = MAYBE;
10458b2f1953SBram Moolenaar 		    else
10468b2f1953SBram Moolenaar 		    {
1047a09195f2SBram Moolenaar 			semsg(_(e_json_error), p);
10488b2f1953SBram Moolenaar 			retval = FAIL;
10498b2f1953SBram Moolenaar 		    }
10508b2f1953SBram Moolenaar 		    goto theend;
10518b2f1953SBram Moolenaar 		}
10528b2f1953SBram Moolenaar 		top_item->jd_type = JSON_OBJECT_KEY;
10538b2f1953SBram Moolenaar 		if (cur_item != NULL)
10548b2f1953SBram Moolenaar 		    cur_item = &top_item->jd_key_tv;
10558b2f1953SBram Moolenaar 		break;
10568b2f1953SBram Moolenaar 	}
10578b2f1953SBram Moolenaar     }
10588b2f1953SBram Moolenaar 
10594ba37b58SBram Moolenaar     // Get here when parsing failed.
10608b2f1953SBram Moolenaar     if (res != NULL)
10618b2f1953SBram Moolenaar     {
10628b2f1953SBram Moolenaar 	clear_tv(res);
1063520e1e41SBram Moolenaar 	res->v_type = VAR_SPECIAL;
1064520e1e41SBram Moolenaar 	res->vval.v_number = VVAL_NONE;
1065520e1e41SBram Moolenaar     }
1066a09195f2SBram Moolenaar     semsg(_(e_json_error), p);
10678b2f1953SBram Moolenaar 
10688b2f1953SBram Moolenaar theend:
10696d3a7213SBram Moolenaar     for (i = 0; i < stack.ga_len; i++)
10706d3a7213SBram Moolenaar 	clear_tv(&(((json_dec_item_T *)stack.ga_data) + i)->jd_key_tv);
10718b2f1953SBram Moolenaar     ga_clear(&stack);
10726d3a7213SBram Moolenaar 
10738b2f1953SBram Moolenaar     return retval;
107456ead341SBram Moolenaar }
1075520e1e41SBram Moolenaar 
1076520e1e41SBram Moolenaar /*
1077520e1e41SBram Moolenaar  * Decode the JSON from "reader" and store the result in "res".
1078595e64e2SBram Moolenaar  * "options" can be JSON_JS or zero;
107956ead341SBram Moolenaar  * Return FAIL if not the whole message was consumed.
1080520e1e41SBram Moolenaar  */
10815843f5f3SBram Moolenaar     static int
json_decode_all(js_read_T * reader,typval_T * res,int options)1082595e64e2SBram Moolenaar json_decode_all(js_read_T *reader, typval_T *res, int options)
1083520e1e41SBram Moolenaar {
108456ead341SBram Moolenaar     int ret;
108556ead341SBram Moolenaar 
10864ba37b58SBram Moolenaar     // We find the end once, to avoid calling strlen() many times.
108756ead341SBram Moolenaar     reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
1088520e1e41SBram Moolenaar     json_skip_white(reader);
1089595e64e2SBram Moolenaar     ret = json_decode_item(reader, res, options);
109056ead341SBram Moolenaar     if (ret != OK)
109103c60c15SBram Moolenaar     {
109203c60c15SBram Moolenaar 	if (ret == MAYBE)
1093a09195f2SBram Moolenaar 	    semsg(_(e_json_error), reader->js_buf);
109456ead341SBram Moolenaar 	return FAIL;
109503c60c15SBram Moolenaar     }
1096520e1e41SBram Moolenaar     json_skip_white(reader);
1097520e1e41SBram Moolenaar     if (reader->js_buf[reader->js_used] != NUL)
109803c60c15SBram Moolenaar     {
10992d06bfdeSBram Moolenaar 	semsg(_(e_trailing_arg), reader->js_buf + reader->js_used);
110019d2f158SBram Moolenaar 	return FAIL;
110103c60c15SBram Moolenaar     }
110219d2f158SBram Moolenaar     return OK;
1103520e1e41SBram Moolenaar }
110456ead341SBram Moolenaar 
1105113e1072SBram Moolenaar #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
110656ead341SBram Moolenaar /*
110756ead341SBram Moolenaar  * Decode the JSON from "reader" and store the result in "res".
1108595e64e2SBram Moolenaar  * "options" can be JSON_JS or zero;
1109ba61ac0dSBram Moolenaar  * Return FAIL for a decoding error.
1110ba61ac0dSBram Moolenaar  * Return MAYBE for an incomplete message.
1111ba61ac0dSBram Moolenaar  * Consumes the message anyway.
111256ead341SBram Moolenaar  */
111356ead341SBram Moolenaar     int
json_decode(js_read_T * reader,typval_T * res,int options)1114595e64e2SBram Moolenaar json_decode(js_read_T *reader, typval_T *res, int options)
111556ead341SBram Moolenaar {
111656ead341SBram Moolenaar     int ret;
111756ead341SBram Moolenaar 
11184ba37b58SBram Moolenaar     // We find the end once, to avoid calling strlen() many times.
111956ead341SBram Moolenaar     reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
112056ead341SBram Moolenaar     json_skip_white(reader);
1121595e64e2SBram Moolenaar     ret = json_decode_item(reader, res, options);
112256ead341SBram Moolenaar     json_skip_white(reader);
112356ead341SBram Moolenaar 
1124ba61ac0dSBram Moolenaar     return ret;
112556ead341SBram Moolenaar }
1126113e1072SBram Moolenaar #endif
112756ead341SBram Moolenaar 
112856ead341SBram Moolenaar /*
112956ead341SBram Moolenaar  * Decode the JSON from "reader" to find the end of the message.
1130e2c6037dSBram Moolenaar  * "options" can be JSON_JS or zero.
1131e2c6037dSBram Moolenaar  * This is only used for testing.
113256ead341SBram Moolenaar  * Return FAIL if the message has a decoding error.
113356ead341SBram Moolenaar  * Return MAYBE if the message is truncated, need to read more.
113456ead341SBram Moolenaar  * This only works reliable if the message contains an object, array or
11355f6b379fSBram Moolenaar  * string.  A number might be truncated without knowing.
113656ead341SBram Moolenaar  * Does not advance the reader.
113756ead341SBram Moolenaar  */
113856ead341SBram Moolenaar     int
json_find_end(js_read_T * reader,int options)1139595e64e2SBram Moolenaar json_find_end(js_read_T *reader, int options)
114056ead341SBram Moolenaar {
114156ead341SBram Moolenaar     int used_save = reader->js_used;
114256ead341SBram Moolenaar     int ret;
114356ead341SBram Moolenaar 
11444ba37b58SBram Moolenaar     // We find the end once, to avoid calling strlen() many times.
114556ead341SBram Moolenaar     reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
114656ead341SBram Moolenaar     json_skip_white(reader);
1147595e64e2SBram Moolenaar     ret = json_decode_item(reader, NULL, options);
114856ead341SBram Moolenaar     reader->js_used = used_save;
114956ead341SBram Moolenaar     return ret;
115056ead341SBram Moolenaar }
115129b7d7a9SBram Moolenaar 
115229b7d7a9SBram Moolenaar /*
115329b7d7a9SBram Moolenaar  * "js_decode()" function
115429b7d7a9SBram Moolenaar  */
115529b7d7a9SBram Moolenaar     void
f_js_decode(typval_T * argvars,typval_T * rettv)115629b7d7a9SBram Moolenaar f_js_decode(typval_T *argvars, typval_T *rettv)
115729b7d7a9SBram Moolenaar {
115829b7d7a9SBram Moolenaar     js_read_T	reader;
115929b7d7a9SBram Moolenaar 
11604490ec4eSYegappan Lakshmanan     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
11614490ec4eSYegappan Lakshmanan 	return;
11624490ec4eSYegappan Lakshmanan 
116329b7d7a9SBram Moolenaar     reader.js_buf = tv_get_string(&argvars[0]);
116429b7d7a9SBram Moolenaar     reader.js_fill = NULL;
116529b7d7a9SBram Moolenaar     reader.js_used = 0;
116629b7d7a9SBram Moolenaar     if (json_decode_all(&reader, rettv, JSON_JS) != OK)
116729b7d7a9SBram Moolenaar 	emsg(_(e_invarg));
116829b7d7a9SBram Moolenaar }
116929b7d7a9SBram Moolenaar 
117029b7d7a9SBram Moolenaar /*
117129b7d7a9SBram Moolenaar  * "js_encode()" function
117229b7d7a9SBram Moolenaar  */
117329b7d7a9SBram Moolenaar     void
f_js_encode(typval_T * argvars,typval_T * rettv)117429b7d7a9SBram Moolenaar f_js_encode(typval_T *argvars, typval_T *rettv)
117529b7d7a9SBram Moolenaar {
117629b7d7a9SBram Moolenaar     rettv->v_type = VAR_STRING;
117729b7d7a9SBram Moolenaar     rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
117829b7d7a9SBram Moolenaar }
117929b7d7a9SBram Moolenaar 
118029b7d7a9SBram Moolenaar /*
118129b7d7a9SBram Moolenaar  * "json_decode()" function
118229b7d7a9SBram Moolenaar  */
118329b7d7a9SBram Moolenaar     void
f_json_decode(typval_T * argvars,typval_T * rettv)118429b7d7a9SBram Moolenaar f_json_decode(typval_T *argvars, typval_T *rettv)
118529b7d7a9SBram Moolenaar {
118629b7d7a9SBram Moolenaar     js_read_T	reader;
118729b7d7a9SBram Moolenaar 
11884490ec4eSYegappan Lakshmanan     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
11894490ec4eSYegappan Lakshmanan 	return;
11904490ec4eSYegappan Lakshmanan 
119129b7d7a9SBram Moolenaar     reader.js_buf = tv_get_string(&argvars[0]);
119229b7d7a9SBram Moolenaar     reader.js_fill = NULL;
119329b7d7a9SBram Moolenaar     reader.js_used = 0;
119429b7d7a9SBram Moolenaar     json_decode_all(&reader, rettv, 0);
119529b7d7a9SBram Moolenaar }
119629b7d7a9SBram Moolenaar 
119729b7d7a9SBram Moolenaar /*
119829b7d7a9SBram Moolenaar  * "json_encode()" function
119929b7d7a9SBram Moolenaar  */
120029b7d7a9SBram Moolenaar     void
f_json_encode(typval_T * argvars,typval_T * rettv)120129b7d7a9SBram Moolenaar f_json_encode(typval_T *argvars, typval_T *rettv)
120229b7d7a9SBram Moolenaar {
120329b7d7a9SBram Moolenaar     rettv->v_type = VAR_STRING;
120429b7d7a9SBram Moolenaar     rettv->vval.v_string = json_encode(&argvars[0], 0);
120529b7d7a9SBram Moolenaar }
1206c61a48d2SBram Moolenaar #endif
1207