| 
									
										
										
										
											2016-08-29 22:49:24 +02:00
										 |  |  | /* vi:set ts=8 sts=4 sw=4 noet:
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * VIM - Vi IMproved	by Bram Moolenaar | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Do ":help uganda"  in Vim to read copying and usage conditions. | 
					
						
							|  |  |  |  * Do ":help credits" in Vim to see a list of people who contributed. | 
					
						
							|  |  |  |  * See README.txt for an overview of the Vim source code. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * json.c: Encoding and decoding JSON. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-01-28 14:12:00 +01:00
										 |  |  |  * Follows this standard: https://tools.ietf.org/html/rfc7159.html
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-02-27 21:27:20 +01:00
										 |  |  | #define USING_FLOAT_STUFF
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "vim.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(FEAT_EVAL) || defined(PROTO)
 | 
					
						
							| 
									
										
										
										
											2016-02-23 21:26:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-19 22:38:59 +02:00
										 |  |  | static char e_json_error[] = N_("E491: json decode error at '%s'"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-26 17:58:53 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Encode "val" into a JSON format string. | 
					
						
							|  |  |  |  * The result is added to "gap" | 
					
						
							|  |  |  |  * Returns FAIL on failure and makes gap->ga_data empty. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  |     static int | 
					
						
							|  |  |  | json_encode_gap(garray_T *gap, typval_T *val, int options) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (json_encode_item(gap, val, get_copyID(), options) == FAIL) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	ga_clear(gap); | 
					
						
							|  |  |  | 	gap->ga_data = vim_strsave((char_u *)""); | 
					
						
							|  |  |  | 	return FAIL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Encode "val" into a JSON format string. | 
					
						
							| 
									
										
										
										
											2016-02-07 16:53:13 +01:00
										 |  |  |  * The result is in allocated memory. | 
					
						
							|  |  |  |  * The result is empty when encoding fails. | 
					
						
							| 
									
										
										
										
											2016-08-26 17:58:53 +02:00
										 |  |  |  * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL. | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |  */ | 
					
						
							|  |  |  |     char_u * | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | json_encode(typval_T *val, int options) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     garray_T ga; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  |     // Store bytes in the growarray.
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     ga_init2(&ga, 1, 4000); | 
					
						
							| 
									
										
										
										
											2016-08-26 17:58:53 +02:00
										 |  |  |     json_encode_gap(&ga, val, options); | 
					
						
							| 
									
										
										
										
											2019-04-12 21:19:04 +02:00
										 |  |  |     ga_append(&ga, NUL); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     return ga.ga_data; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-20 15:30:40 +01:00
										 |  |  | #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
 | 
					
						
							| 
									
										
										
										
											2016-01-31 20:24:32 +01:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2016-02-07 16:53:13 +01:00
										 |  |  |  * Encode ["nr", "val"] into a JSON format string in allocated memory. | 
					
						
							| 
									
										
										
										
											2016-08-26 17:58:53 +02:00
										 |  |  |  * "options" can contain JSON_JS, JSON_NO_NONE and JSON_NL. | 
					
						
							| 
									
										
										
										
											2016-01-31 20:24:32 +01:00
										 |  |  |  * Returns NULL when out of memory. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  |     char_u * | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | json_encode_nr_expr(int nr, typval_T *val, int options) | 
					
						
							| 
									
										
										
										
											2016-01-31 20:24:32 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     typval_T	listtv; | 
					
						
							|  |  |  |     typval_T	nrtv; | 
					
						
							| 
									
										
										
										
											2016-08-26 17:58:53 +02:00
										 |  |  |     garray_T	ga; | 
					
						
							| 
									
										
										
										
											2016-01-31 20:24:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     nrtv.v_type = VAR_NUMBER; | 
					
						
							|  |  |  |     nrtv.vval.v_number = nr; | 
					
						
							|  |  |  |     if (rettv_list_alloc(&listtv) == FAIL) | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  |     if (list_append_tv(listtv.vval.v_list, &nrtv) == FAIL | 
					
						
							|  |  |  | 	    || list_append_tv(listtv.vval.v_list, val) == FAIL) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	list_unref(listtv.vval.v_list); | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-26 17:58:53 +02:00
										 |  |  |     ga_init2(&ga, 1, 4000); | 
					
						
							|  |  |  |     if (json_encode_gap(&ga, &listtv, options) == OK && (options & JSON_NL)) | 
					
						
							|  |  |  | 	ga_append(&ga, '\n'); | 
					
						
							| 
									
										
										
										
											2016-01-31 20:24:32 +01:00
										 |  |  |     list_unref(listtv.vval.v_list); | 
					
						
							| 
									
										
										
										
											2019-04-12 21:19:04 +02:00
										 |  |  |     ga_append(&ga, NUL); | 
					
						
							| 
									
										
										
										
											2016-08-26 17:58:53 +02:00
										 |  |  |     return ga.ga_data; | 
					
						
							| 
									
										
										
										
											2016-01-31 20:24:32 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-01-20 15:30:40 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-01-31 20:24:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     static void | 
					
						
							|  |  |  | write_string(garray_T *gap, char_u *str) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char_u	*res = str; | 
					
						
							|  |  |  |     char_u	numbuf[NUMBUFLEN]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (res == NULL) | 
					
						
							| 
									
										
										
										
											2017-12-15 21:25:01 +01:00
										 |  |  | 	ga_concat(gap, (char_u *)"\"\""); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-01-24 15:54:21 +01:00
										 |  |  | #if defined(USE_ICONV)
 | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | 	vimconv_T   conv; | 
					
						
							|  |  |  | 	char_u	    *converted = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-27 21:13:38 +01:00
										 |  |  | 	if (!enc_utf8) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 	    // Convert the text from 'encoding' to utf-8, the JSON string is
 | 
					
						
							|  |  |  | 	    // always utf-8.
 | 
					
						
							| 
									
										
										
										
											2016-02-27 21:13:38 +01:00
										 |  |  | 	    conv.vc_type = CONV_NONE; | 
					
						
							|  |  |  | 	    convert_setup(&conv, p_enc, (char_u*)"utf-8"); | 
					
						
							|  |  |  | 	    if (conv.vc_type != CONV_NONE) | 
					
						
							|  |  |  | 		converted = res = string_convert(&conv, res, NULL); | 
					
						
							|  |  |  | 	    convert_setup(&conv, NULL, NULL); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	ga_append(gap, '"'); | 
					
						
							|  |  |  | 	while (*res != NUL) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | 	    int c; | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 	    // always use utf-8 encoding, ignore 'encoding'
 | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | 	    c = utf_ptr2char(res); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	    switch (c) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 		case 0x08: | 
					
						
							|  |  |  | 		    ga_append(gap, '\\'); ga_append(gap, 'b'); break; | 
					
						
							|  |  |  | 		case 0x09: | 
					
						
							|  |  |  | 		    ga_append(gap, '\\'); ga_append(gap, 't'); break; | 
					
						
							|  |  |  | 		case 0x0a: | 
					
						
							|  |  |  | 		    ga_append(gap, '\\'); ga_append(gap, 'n'); break; | 
					
						
							|  |  |  | 		case 0x0c: | 
					
						
							|  |  |  | 		    ga_append(gap, '\\'); ga_append(gap, 'f'); break; | 
					
						
							|  |  |  | 		case 0x0d: | 
					
						
							|  |  |  | 		    ga_append(gap, '\\'); ga_append(gap, 'r'); break; | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		case 0x22: // "
 | 
					
						
							|  |  |  | 		case 0x5c: // backslash
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 		    ga_append(gap, '\\'); | 
					
						
							|  |  |  | 		    ga_append(gap, c); | 
					
						
							|  |  |  | 		    break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 		    if (c >= 0x20) | 
					
						
							|  |  |  | 		    { | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | 			numbuf[utf_char2bytes(c, numbuf)] = NUL; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 			ga_concat(gap, numbuf); | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		    else | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			vim_snprintf((char *)numbuf, NUMBUFLEN, | 
					
						
							|  |  |  | 							 "\\u%04lx", (long)c); | 
					
						
							|  |  |  | 			ga_concat(gap, numbuf); | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | 	    res += utf_ptr2len(res); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	ga_append(gap, '"'); | 
					
						
							| 
									
										
										
										
											2019-01-24 15:54:21 +01:00
										 |  |  | #if defined(USE_ICONV)
 | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | 	vim_free(converted); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Return TRUE if "key" can be used without quotes. | 
					
						
							|  |  |  |  * That is when it starts with a letter and only contains letters, digits and | 
					
						
							|  |  |  |  * underscore. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  |     static int | 
					
						
							|  |  |  | is_simple_key(char_u *key) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char_u *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!ASCII_ISALPHA(*key)) | 
					
						
							|  |  |  | 	return FALSE; | 
					
						
							|  |  |  |     for (p = key + 1; *p != NUL; ++p) | 
					
						
							|  |  |  | 	if (!ASCII_ISALPHA(*p) && *p != '_' && !vim_isdigit(*p)) | 
					
						
							|  |  |  | 	    return FALSE; | 
					
						
							|  |  |  |     return TRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-24 16:49:11 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Encode "val" into "gap". | 
					
						
							|  |  |  |  * Return FAIL or OK. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  |     static int | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     char_u	numbuf[NUMBUFLEN]; | 
					
						
							|  |  |  |     char_u	*res; | 
					
						
							| 
									
										
										
										
											2019-01-12 22:47:31 +01:00
										 |  |  |     blob_T	*b; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     list_T	*l; | 
					
						
							|  |  |  |     dict_T	*d; | 
					
						
							| 
									
										
										
										
											2019-01-12 22:47:31 +01:00
										 |  |  |     int		i; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     switch (val->v_type) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-01-11 16:05:23 +01:00
										 |  |  | 	case VAR_BOOL: | 
					
						
							| 
									
										
										
										
											2020-02-25 21:26:49 +01:00
										 |  |  | 	    switch ((long)val->vval.v_number) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	    { | 
					
						
							|  |  |  | 		case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break; | 
					
						
							|  |  |  | 		case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break; | 
					
						
							| 
									
										
										
										
											2020-01-11 16:05:23 +01:00
										 |  |  | 	    } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case VAR_SPECIAL: | 
					
						
							| 
									
										
										
										
											2020-02-25 21:26:49 +01:00
										 |  |  | 	    switch ((long)val->vval.v_number) | 
					
						
							| 
									
										
										
										
											2020-01-11 16:05:23 +01:00
										 |  |  | 	    { | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | 		case VVAL_NONE: if ((options & JSON_JS) != 0 | 
					
						
							|  |  |  | 					     && (options & JSON_NO_NONE) == 0) | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 				    // empty item
 | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | 				    break; | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 				// FALLTHROUGH
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 		case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case VAR_NUMBER: | 
					
						
							| 
									
										
										
										
											2016-07-01 18:17:26 +02:00
										 |  |  | 	    vim_snprintf((char *)numbuf, NUMBUFLEN, "%lld", | 
					
						
							| 
									
										
										
										
											2020-02-22 14:27:04 +01:00
										 |  |  | 					      (varnumber_T)val->vval.v_number); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	    ga_concat(gap, numbuf); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case VAR_STRING: | 
					
						
							|  |  |  | 	    res = val->vval.v_string; | 
					
						
							|  |  |  | 	    write_string(gap, res); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case VAR_FUNC: | 
					
						
							| 
									
										
										
										
											2016-03-14 23:05:14 +01:00
										 |  |  | 	case VAR_PARTIAL: | 
					
						
							| 
									
										
										
										
											2016-02-07 16:53:13 +01:00
										 |  |  | 	case VAR_JOB: | 
					
						
							| 
									
										
										
										
											2016-02-13 23:23:53 +01:00
										 |  |  | 	case VAR_CHANNEL: | 
					
						
							| 
									
										
										
										
											2021-05-07 17:55:55 +02:00
										 |  |  | 	case VAR_INSTR: | 
					
						
							| 
									
										
										
										
											2021-02-08 21:53:09 +01:00
										 |  |  | 	    semsg(_(e_cannot_json_encode_str), vartype_name(val->v_type)); | 
					
						
							| 
									
										
										
										
											2016-01-24 16:49:11 +01:00
										 |  |  | 	    return FAIL; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-12 22:47:31 +01:00
										 |  |  | 	case VAR_BLOB: | 
					
						
							|  |  |  | 	    b = val->vval.v_blob; | 
					
						
							|  |  |  | 	    if (b == NULL || b->bv_ga.ga_len == 0) | 
					
						
							|  |  |  | 		ga_concat(gap, (char_u *)"[]"); | 
					
						
							|  |  |  | 	    else | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 		ga_append(gap, '['); | 
					
						
							|  |  |  | 		for (i = 0; i < b->bv_ga.ga_len; i++) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		    if (i > 0) | 
					
						
							|  |  |  | 			ga_concat(gap, (char_u *)","); | 
					
						
							|  |  |  | 		    vim_snprintf((char *)numbuf, NUMBUFLEN, "%d", | 
					
						
							|  |  |  | 			    (int)blob_get(b, i)); | 
					
						
							|  |  |  | 		    ga_concat(gap, numbuf); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ga_append(gap, ']'); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	case VAR_LIST: | 
					
						
							|  |  |  | 	    l = val->vval.v_list; | 
					
						
							|  |  |  | 	    if (l == NULL) | 
					
						
							| 
									
										
										
										
											2017-12-15 21:25:01 +01:00
										 |  |  | 		ga_concat(gap, (char_u *)"[]"); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	    else | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 		if (l->lv_copyID == copyID) | 
					
						
							|  |  |  | 		    ga_concat(gap, (char_u *)"[]"); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		    listitem_T	*li; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		    l->lv_copyID = copyID; | 
					
						
							|  |  |  | 		    ga_append(gap, '['); | 
					
						
							| 
									
										
										
										
											2020-05-13 22:44:22 +02:00
										 |  |  | 		    CHECK_LIST_MATERIALIZE(l); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 		    for (li = l->lv_first; li != NULL && !got_int; ) | 
					
						
							|  |  |  | 		    { | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | 			if (json_encode_item(gap, &li->li_tv, copyID, | 
					
						
							|  |  |  | 						   options & JSON_JS) == FAIL) | 
					
						
							| 
									
										
										
										
											2016-01-24 16:49:11 +01:00
										 |  |  | 			    return FAIL; | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | 			if ((options & JSON_JS) | 
					
						
							|  |  |  | 				&& li->li_next == NULL | 
					
						
							|  |  |  | 				&& li->li_tv.v_type == VAR_SPECIAL | 
					
						
							|  |  |  | 				&& li->li_tv.vval.v_number == VVAL_NONE) | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 			    // add an extra comma if the last item is v:none
 | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | 			    ga_append(gap, ','); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 			li = li->li_next; | 
					
						
							|  |  |  | 			if (li != NULL) | 
					
						
							|  |  |  | 			    ga_append(gap, ','); | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		    ga_append(gap, ']'); | 
					
						
							| 
									
										
										
										
											2016-01-24 16:49:11 +01:00
										 |  |  | 		    l->lv_copyID = 0; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case VAR_DICT: | 
					
						
							|  |  |  | 	    d = val->vval.v_dict; | 
					
						
							|  |  |  | 	    if (d == NULL) | 
					
						
							| 
									
										
										
										
											2017-12-15 21:25:01 +01:00
										 |  |  | 		ga_concat(gap, (char_u *)"{}"); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	    else | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 		if (d->dv_copyID == copyID) | 
					
						
							|  |  |  | 		    ga_concat(gap, (char_u *)"{}"); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		    int		first = TRUE; | 
					
						
							|  |  |  | 		    int		todo = (int)d->dv_hashtab.ht_used; | 
					
						
							|  |  |  | 		    hashitem_T	*hi; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		    d->dv_copyID = copyID; | 
					
						
							|  |  |  | 		    ga_append(gap, '{'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		    for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int; | 
					
						
							|  |  |  | 									 ++hi) | 
					
						
							|  |  |  | 			if (!HASHITEM_EMPTY(hi)) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			    --todo; | 
					
						
							|  |  |  | 			    if (first) | 
					
						
							|  |  |  | 				first = FALSE; | 
					
						
							|  |  |  | 			    else | 
					
						
							|  |  |  | 				ga_append(gap, ','); | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | 			    if ((options & JSON_JS) | 
					
						
							|  |  |  | 						 && is_simple_key(hi->hi_key)) | 
					
						
							|  |  |  | 				ga_concat(gap, hi->hi_key); | 
					
						
							|  |  |  | 			    else | 
					
						
							|  |  |  | 				write_string(gap, hi->hi_key); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 			    ga_append(gap, ':'); | 
					
						
							| 
									
										
										
										
											2016-01-24 16:49:11 +01:00
										 |  |  | 			    if (json_encode_item(gap, &dict_lookup(hi)->di_tv, | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | 				      copyID, options | JSON_NO_NONE) == FAIL) | 
					
						
							| 
									
										
										
										
											2016-01-24 16:49:11 +01:00
										 |  |  | 				return FAIL; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		    ga_append(gap, '}'); | 
					
						
							| 
									
										
										
										
											2016-01-24 16:49:11 +01:00
										 |  |  | 		    d->dv_copyID = 0; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case VAR_FLOAT: | 
					
						
							| 
									
										
										
										
											2016-02-07 16:53:13 +01:00
										 |  |  | #ifdef FEAT_FLOAT
 | 
					
						
							| 
									
										
										
										
											2016-02-23 21:26:43 +01:00
										 |  |  | # if defined(HAVE_MATH_H)
 | 
					
						
							| 
									
										
										
										
											2016-02-27 16:33:22 +01:00
										 |  |  | 	    if (isnan(val->vval.v_float)) | 
					
						
							| 
									
										
										
										
											2016-02-23 21:26:43 +01:00
										 |  |  | 		ga_concat(gap, (char_u *)"NaN"); | 
					
						
							| 
									
										
										
										
											2016-02-27 16:33:22 +01:00
										 |  |  | 	    else if (isinf(val->vval.v_float)) | 
					
						
							| 
									
										
										
										
											2019-01-12 14:24:27 +01:00
										 |  |  | 	    { | 
					
						
							|  |  |  | 		if (val->vval.v_float < 0.0) | 
					
						
							|  |  |  | 		    ga_concat(gap, (char_u *)"-Infinity"); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		    ga_concat(gap, (char_u *)"Infinity"); | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2016-02-23 21:26:43 +01:00
										 |  |  | 	    else | 
					
						
							|  |  |  | # endif
 | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 		vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", | 
					
						
							|  |  |  | 							   val->vval.v_float); | 
					
						
							|  |  |  | 		ga_concat(gap, numbuf); | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	    break; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-02-07 16:53:13 +01:00
										 |  |  | 	case VAR_UNKNOWN: | 
					
						
							| 
									
										
										
										
											2020-04-05 21:38:23 +02:00
										 |  |  | 	case VAR_ANY: | 
					
						
							| 
									
										
										
										
											2020-01-26 15:56:19 +01:00
										 |  |  | 	case VAR_VOID: | 
					
						
							| 
									
										
										
										
											2020-02-29 17:38:12 +01:00
										 |  |  | 	    internal_error_no_abort("json_encode_item()"); | 
					
						
							| 
									
										
										
										
											2016-02-07 16:53:13 +01:00
										 |  |  | 	    return FAIL; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-01-24 16:49:11 +01:00
										 |  |  |     return OK; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |  * When "reader" has less than NUMBUFLEN bytes available, call the fill | 
					
						
							|  |  |  |  * callback to get more. | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |  */ | 
					
						
							|  |  |  |     static void | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | fill_numbuflen(js_read_T *reader) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     if (reader->js_fill != NULL && (int)(reader->js_end - reader->js_buf) | 
					
						
							|  |  |  | 						- reader->js_used < NUMBUFLEN) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	if (reader->js_fill(reader)) | 
					
						
							|  |  |  | 	    reader->js_end = reader->js_buf + STRLEN(reader->js_buf); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  |  * Skip white space in "reader".  All characters <= space are considered white | 
					
						
							|  |  |  |  * space. | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |  * Also tops up readahead when needed. | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |  */ | 
					
						
							|  |  |  |     static void | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | json_skip_white(js_read_T *reader) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     int c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (;;) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	c = reader->js_buf[reader->js_used]; | 
					
						
							|  |  |  | 	if (reader->js_fill != NULL && c == NUL) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    if (reader->js_fill(reader)) | 
					
						
							| 
									
										
										
										
											2016-03-28 14:11:42 +02:00
										 |  |  | 	    { | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		reader->js_end = reader->js_buf + STRLEN(reader->js_buf); | 
					
						
							| 
									
										
										
										
											2016-03-28 14:11:42 +02:00
										 |  |  | 		continue; | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | 	if (c == NUL || c > ' ') | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	    break; | 
					
						
							|  |  |  | 	++reader->js_used; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     fill_numbuflen(reader); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     static int | 
					
						
							| 
									
										
										
										
											2017-01-11 21:50:08 +01:00
										 |  |  | json_decode_string(js_read_T *reader, typval_T *res, int quote) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     garray_T    ga; | 
					
						
							|  |  |  |     int		len; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     char_u	*p; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     int		c; | 
					
						
							| 
									
										
										
										
											2016-07-01 18:17:26 +02:00
										 |  |  |     varnumber_T	nr; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     if (res != NULL) | 
					
						
							|  |  |  | 	ga_init2(&ga, 1, 200); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  |     p = reader->js_buf + reader->js_used + 1; // skip over " or '
 | 
					
						
							| 
									
										
										
										
											2017-01-11 21:50:08 +01:00
										 |  |  |     while (*p != quote) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 	// The JSON is always expected to be utf-8, thus use utf functions
 | 
					
						
							|  |  |  | 	// here. The string is converted below if needed.
 | 
					
						
							| 
									
										
										
										
											2019-01-24 15:54:21 +01:00
										 |  |  | 	if (*p == NUL || p[1] == NUL || utf_ptr2len(p) < utf_byte2len(*p)) | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 	    // Not enough bytes to make a character or end of the string. Get
 | 
					
						
							|  |  |  | 	    // more if possible.
 | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	    if (reader->js_fill == NULL) | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	    len = (int)(reader->js_end - p); | 
					
						
							|  |  |  | 	    reader->js_used = (int)(p - reader->js_buf); | 
					
						
							|  |  |  | 	    if (!reader->js_fill(reader)) | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		break; // didn't get more
 | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	    p = reader->js_buf + reader->js_used; | 
					
						
							|  |  |  | 	    reader->js_end = reader->js_buf + STRLEN(reader->js_buf); | 
					
						
							|  |  |  | 	    continue; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	if (*p == '\\') | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    c = -1; | 
					
						
							|  |  |  | 	    switch (p[1]) | 
					
						
							|  |  |  | 	    { | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		case '\\': c = '\\'; break; | 
					
						
							|  |  |  | 		case '"': c = '"'; break; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 		case 'b': c = BS; break; | 
					
						
							|  |  |  | 		case 't': c = TAB; break; | 
					
						
							|  |  |  | 		case 'n': c = NL; break; | 
					
						
							|  |  |  | 		case 'f': c = FF; break; | 
					
						
							|  |  |  | 		case 'r': c = CAR; break; | 
					
						
							|  |  |  | 		case 'u': | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		    if (reader->js_fill != NULL | 
					
						
							|  |  |  | 				     && (int)(reader->js_end - p) < NUMBUFLEN) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			reader->js_used = (int)(p - reader->js_buf); | 
					
						
							|  |  |  | 			if (reader->js_fill(reader)) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			    p = reader->js_buf + reader->js_used; | 
					
						
							|  |  |  | 			    reader->js_end = reader->js_buf | 
					
						
							|  |  |  | 						     + STRLEN(reader->js_buf); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | 		    nr = 0; | 
					
						
							|  |  |  | 		    len = 0; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 		    vim_str2nr(p + 2, NULL, &len, | 
					
						
							| 
									
										
										
										
											2019-05-19 19:59:35 +02:00
										 |  |  | 			     STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4, TRUE); | 
					
						
							|  |  |  | 		    if (len == 0) | 
					
						
							|  |  |  | 		    { | 
					
						
							| 
									
										
										
										
											2019-05-27 20:01:41 +02:00
										 |  |  | 			if (res != NULL) | 
					
						
							|  |  |  | 			    ga_clear(&ga); | 
					
						
							| 
									
										
										
										
											2019-05-19 19:59:35 +02:00
										 |  |  | 			return FAIL; | 
					
						
							|  |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 		    p += len + 2; | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | 		    if (0xd800 <= nr && nr <= 0xdfff | 
					
						
							|  |  |  | 			    && (int)(reader->js_end - p) >= 6 | 
					
						
							|  |  |  | 			    && *p == '\\' && *(p+1) == 'u') | 
					
						
							|  |  |  | 		    { | 
					
						
							| 
									
										
										
										
											2016-07-01 18:17:26 +02:00
										 |  |  | 			varnumber_T	nr2 = 0; | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 			// decode surrogate pair: \ud812\u3456
 | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | 			len = 0; | 
					
						
							|  |  |  | 			vim_str2nr(p + 2, NULL, &len, | 
					
						
							| 
									
										
										
										
											2019-05-19 19:59:35 +02:00
										 |  |  | 			     STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4, TRUE); | 
					
						
							|  |  |  | 			if (len == 0) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2019-05-27 20:01:41 +02:00
										 |  |  | 			    if (res != NULL) | 
					
						
							|  |  |  | 				ga_clear(&ga); | 
					
						
							| 
									
										
										
										
											2019-05-19 19:59:35 +02:00
										 |  |  | 			    return FAIL; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | 			if (0xdc00 <= nr2 && nr2 <= 0xdfff) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			    p += len + 2; | 
					
						
							|  |  |  | 			    nr = (((nr - 0xd800) << 10) | | 
					
						
							|  |  |  | 				((nr2 - 0xdc00) & 0x3ff)) + 0x10000; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		    if (res != NULL) | 
					
						
							|  |  |  | 		    { | 
					
						
							| 
									
										
										
										
											2016-04-23 14:33:19 +02:00
										 |  |  | 			char_u	buf[NUMBUFLEN]; | 
					
						
							| 
									
										
										
										
											2019-05-27 20:01:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | 			buf[utf_char2bytes((int)nr, buf)] = NUL; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 			ga_concat(&ga, buf); | 
					
						
							|  |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 		    break; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		    // not a special char, skip over backslash
 | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		    ++p; | 
					
						
							|  |  |  | 		    continue; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	    } | 
					
						
							|  |  |  | 	    if (c > 0) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 		p += 2; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		if (res != NULL) | 
					
						
							|  |  |  | 		    ga_append(&ga, c); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	    } | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2016-02-27 18:41:27 +01:00
										 |  |  | 	    len = utf_ptr2len(p); | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	    if (res != NULL) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	    { | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		if (ga_grow(&ga, len) == FAIL) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		    ga_clear(&ga); | 
					
						
							|  |  |  | 		    return FAIL; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 		mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len); | 
					
						
							|  |  |  | 		ga.ga_len += len; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    p += len; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     reader->js_used = (int)(p - reader->js_buf); | 
					
						
							| 
									
										
										
										
											2017-01-11 21:50:08 +01:00
										 |  |  |     if (*p == quote) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     { | 
					
						
							|  |  |  | 	++reader->js_used; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	if (res != NULL) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2016-02-28 15:21:13 +01:00
										 |  |  | 	    ga_append(&ga, NUL); | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	    res->v_type = VAR_STRING; | 
					
						
							| 
									
										
										
										
											2019-01-24 15:54:21 +01:00
										 |  |  | #if defined(USE_ICONV)
 | 
					
						
							| 
									
										
										
										
											2016-02-28 14:56:39 +01:00
										 |  |  | 	    if (!enc_utf8) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 		vimconv_T   conv; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		// Convert the utf-8 string to 'encoding'.
 | 
					
						
							| 
									
										
										
										
											2016-02-28 14:56:39 +01:00
										 |  |  | 		conv.vc_type = CONV_NONE; | 
					
						
							|  |  |  | 		convert_setup(&conv, (char_u*)"utf-8", p_enc); | 
					
						
							|  |  |  | 		if (conv.vc_type != CONV_NONE) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		    res->vval.v_string = | 
					
						
							|  |  |  | 				      string_convert(&conv, ga.ga_data, NULL); | 
					
						
							|  |  |  | 		    vim_free(ga.ga_data); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		convert_setup(&conv, NULL, NULL); | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    else | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 		res->vval.v_string = ga.ga_data; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return OK; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     if (res != NULL) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     { | 
					
						
							|  |  |  | 	res->v_type = VAR_SPECIAL; | 
					
						
							|  |  |  | 	res->vval.v_number = VVAL_NONE; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	ga_clear(&ga); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     return MAYBE; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | typedef enum { | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  |     JSON_ARRAY,		// parsing items in an array
 | 
					
						
							|  |  |  |     JSON_OBJECT_KEY,	// parsing key of an object
 | 
					
						
							|  |  |  |     JSON_OBJECT		// parsing item in an object, after the key
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | } json_decode_T; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  |     json_decode_T jd_type; | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  |     typval_T	  jd_tv;	// the list or dict
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  |     typval_T	  jd_key_tv; | 
					
						
							|  |  |  |     char_u	  *jd_key; | 
					
						
							|  |  |  | } json_dec_item_T; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |  * Decode one item and put it in "res".  If "res" is NULL only advance. | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |  * Must already have skipped white space. | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2017-01-10 15:15:37 +01:00
										 |  |  |  * Return FAIL for a decoding error (and give an error). | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |  * Return MAYBE for an incomplete message. | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     static int | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | json_decode_item(js_read_T *reader, typval_T *res, int options) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     char_u	*p; | 
					
						
							| 
									
										
										
										
											2020-07-12 14:34:00 +02:00
										 |  |  |     int		i; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     int		len; | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  |     int		retval; | 
					
						
							|  |  |  |     garray_T	stack; | 
					
						
							|  |  |  |     typval_T	item; | 
					
						
							|  |  |  |     typval_T	*cur_item; | 
					
						
							|  |  |  |     json_dec_item_T *top_item; | 
					
						
							|  |  |  |     char_u	key_buf[NUMBUFLEN]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ga_init2(&stack, sizeof(json_dec_item_T), 100); | 
					
						
							|  |  |  |     cur_item = res; | 
					
						
							|  |  |  |     init_tv(&item); | 
					
						
							| 
									
										
										
										
											2017-01-10 22:57:34 +01:00
										 |  |  |     if (res != NULL) | 
					
						
							| 
									
										
										
										
											2021-06-06 14:14:39 +02:00
										 |  |  | 	init_tv(res); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     fill_numbuflen(reader); | 
					
						
							|  |  |  |     p = reader->js_buf + reader->js_used; | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  |     for (;;) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 	top_item = NULL; | 
					
						
							|  |  |  | 	if (stack.ga_len > 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1; | 
					
						
							|  |  |  | 	    json_skip_white(reader); | 
					
						
							|  |  |  | 	    p = reader->js_buf + reader->js_used; | 
					
						
							|  |  |  | 	    if (*p == NUL) | 
					
						
							| 
									
										
										
										
											2017-01-10 15:15:37 +01:00
										 |  |  | 	    { | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		retval = MAYBE; | 
					
						
							|  |  |  | 		goto theend; | 
					
						
							| 
									
										
										
										
											2017-01-10 15:15:37 +01:00
										 |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 	    if (top_item->jd_type == JSON_OBJECT_KEY | 
					
						
							|  |  |  | 					    || top_item->jd_type == JSON_ARRAY) | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	    { | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		// Check for end of object or array.
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		if (*p == (top_item->jd_type == JSON_ARRAY ? ']' : '}')) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		    ++reader->js_used; // consume the ']' or '}'
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    --stack.ga_len; | 
					
						
							|  |  |  | 		    if (stack.ga_len == 0) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			retval = OK; | 
					
						
							|  |  |  | 			goto theend; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		    if (cur_item != NULL) | 
					
						
							|  |  |  | 			cur_item = &top_item->jd_tv; | 
					
						
							|  |  |  | 		    goto item_end; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 	if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY | 
					
						
							|  |  |  | 		&& (options & JSON_JS) | 
					
						
							| 
									
										
										
										
											2017-01-11 21:50:08 +01:00
										 |  |  | 		&& reader->js_buf[reader->js_used] != '"' | 
					
						
							| 
									
										
										
										
											2018-03-13 13:10:41 +01:00
										 |  |  | 		&& reader->js_buf[reader->js_used] != '\'' | 
					
						
							|  |  |  | 		&& reader->js_buf[reader->js_used] != '[' | 
					
						
							|  |  |  | 		&& reader->js_buf[reader->js_used] != '{') | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 	    char_u *key; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 	    // accept an object key that is not in quotes
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 	    key = p = reader->js_buf + reader->js_used; | 
					
						
							|  |  |  | 	    while (*p != NUL && *p != ':' && *p > ' ') | 
					
						
							|  |  |  | 		++p; | 
					
						
							| 
									
										
										
										
											2017-01-22 15:56:26 +01:00
										 |  |  | 	    if (cur_item != NULL) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 		cur_item->v_type = VAR_STRING; | 
					
						
							| 
									
										
										
										
											2020-06-12 22:59:11 +02:00
										 |  |  | 		cur_item->vval.v_string = vim_strnsave(key, p - key); | 
					
						
							| 
									
										
										
										
											2017-01-22 15:56:26 +01:00
										 |  |  | 		top_item->jd_key = cur_item->vval.v_string; | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 	    reader->js_used += (int)(p - key); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    switch (*p) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	    { | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		case '[': // start of array
 | 
					
						
							| 
									
										
										
										
											2018-03-13 13:10:41 +01:00
										 |  |  | 		    if (top_item && top_item->jd_type == JSON_OBJECT_KEY) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    if (ga_grow(&stack, 1) == FAIL) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		    if (cur_item != NULL && rettv_list_alloc(cur_item) == FAIL) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			cur_item->v_type = VAR_SPECIAL; | 
					
						
							|  |  |  | 			cur_item->vval.v_number = VVAL_NONE; | 
					
						
							|  |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		    ++reader->js_used; // consume the '['
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    top_item = ((json_dec_item_T *)stack.ga_data) | 
					
						
							|  |  |  | 								+ stack.ga_len; | 
					
						
							|  |  |  | 		    top_item->jd_type = JSON_ARRAY; | 
					
						
							|  |  |  | 		    ++stack.ga_len; | 
					
						
							|  |  |  | 		    if (cur_item != NULL) | 
					
						
							| 
									
										
										
										
											2017-01-10 15:15:37 +01:00
										 |  |  | 		    { | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			top_item->jd_tv = *cur_item; | 
					
						
							|  |  |  | 			cur_item = &item; | 
					
						
							| 
									
										
										
										
											2017-01-10 15:15:37 +01:00
										 |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		case '{': // start of object
 | 
					
						
							| 
									
										
										
										
											2018-03-13 13:10:41 +01:00
										 |  |  | 		    if (top_item && top_item->jd_type == JSON_OBJECT_KEY) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    if (ga_grow(&stack, 1) == FAIL) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		    if (cur_item != NULL && rettv_dict_alloc(cur_item) == FAIL) | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		    { | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			cur_item->v_type = VAR_SPECIAL; | 
					
						
							|  |  |  | 			cur_item->vval.v_number = VVAL_NONE; | 
					
						
							|  |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		    ++reader->js_used; // consume the '{'
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    top_item = ((json_dec_item_T *)stack.ga_data) | 
					
						
							|  |  |  | 								+ stack.ga_len; | 
					
						
							|  |  |  | 		    top_item->jd_type = JSON_OBJECT_KEY; | 
					
						
							|  |  |  | 		    ++stack.ga_len; | 
					
						
							|  |  |  | 		    if (cur_item != NULL) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			top_item->jd_tv = *cur_item; | 
					
						
							|  |  |  | 			cur_item = &top_item->jd_key_tv; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		case '"': // string
 | 
					
						
							| 
									
										
										
										
											2017-01-11 21:50:08 +01:00
										 |  |  | 		    retval = json_decode_string(reader, cur_item, *p); | 
					
						
							|  |  |  | 		    break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case '\'': | 
					
						
							|  |  |  | 		    if (options & JSON_JS) | 
					
						
							|  |  |  | 			retval = json_decode_string(reader, cur_item, *p); | 
					
						
							|  |  |  | 		    else | 
					
						
							|  |  |  | 		    { | 
					
						
							| 
									
										
										
										
											2020-05-19 22:38:59 +02:00
										 |  |  | 			semsg(_(e_json_error), p); | 
					
						
							| 
									
										
										
										
											2017-01-11 21:50:08 +01:00
										 |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		case ',': // comma: empty item
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    if ((options & JSON_JS) == 0) | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		    { | 
					
						
							| 
									
										
										
										
											2020-05-19 22:38:59 +02:00
										 |  |  | 			semsg(_(e_json_error), p); | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		    // FALLTHROUGH
 | 
					
						
							|  |  |  | 		case NUL: // empty
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    if (cur_item != NULL) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			cur_item->v_type = VAR_SPECIAL; | 
					
						
							|  |  |  | 			cur_item->vval.v_number = VVAL_NONE; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		    retval = OK; | 
					
						
							|  |  |  | 		    break; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2020-01-26 21:42:03 +01:00
										 |  |  | 		    if (VIM_ISDIGIT(*p) || (*p == '-' | 
					
						
							|  |  |  | 					&& (VIM_ISDIGIT(p[1]) || p[1] == NUL))) | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    { | 
					
						
							|  |  |  | 			char_u  *sp = p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (*sp == '-') | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			    ++sp; | 
					
						
							|  |  |  | 			    if (*sp == NUL) | 
					
						
							|  |  |  | 			    { | 
					
						
							|  |  |  | 				retval = MAYBE; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			    } | 
					
						
							|  |  |  | 			    if (!VIM_ISDIGIT(*sp)) | 
					
						
							|  |  |  | 			    { | 
					
						
							| 
									
										
										
										
											2020-05-19 22:38:59 +02:00
										 |  |  | 				semsg(_(e_json_error), p); | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 				retval = FAIL; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			    } | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			sp = skipdigits(sp); | 
					
						
							| 
									
										
										
										
											2020-01-26 21:42:03 +01:00
										 |  |  | #ifdef FEAT_FLOAT
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			if (*sp == '.' || *sp == 'e' || *sp == 'E') | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			    if (cur_item == NULL) | 
					
						
							|  |  |  | 			    { | 
					
						
							|  |  |  | 				float_T f; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-08 15:43:34 +02:00
										 |  |  | 				len = string2float(p, &f, FALSE); | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			    } | 
					
						
							|  |  |  | 			    else | 
					
						
							|  |  |  | 			    { | 
					
						
							|  |  |  | 				cur_item->v_type = VAR_FLOAT; | 
					
						
							| 
									
										
										
										
											2021-08-08 15:43:34 +02:00
										 |  |  | 				len = string2float(p, &cur_item->vval.v_float, | 
					
						
							|  |  |  | 									FALSE); | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			    } | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			    varnumber_T nr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			    vim_str2nr(reader->js_buf + reader->js_used, | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 				    NULL, &len, 0, // what
 | 
					
						
							| 
									
										
										
										
											2019-05-19 19:59:35 +02:00
										 |  |  | 				    &nr, NULL, 0, TRUE); | 
					
						
							|  |  |  | 			    if (len == 0) | 
					
						
							|  |  |  | 			    { | 
					
						
							| 
									
										
										
										
											2020-05-19 22:38:59 +02:00
										 |  |  | 				semsg(_(e_json_error), p); | 
					
						
							| 
									
										
										
										
											2019-05-19 19:59:35 +02:00
										 |  |  | 				retval = FAIL; | 
					
						
							|  |  |  | 				goto theend; | 
					
						
							|  |  |  | 			    } | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			    if (cur_item != NULL) | 
					
						
							|  |  |  | 			    { | 
					
						
							|  |  |  | 				cur_item->v_type = VAR_NUMBER; | 
					
						
							|  |  |  | 				cur_item->vval.v_number = nr; | 
					
						
							|  |  |  | 			    } | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			reader->js_used += len; | 
					
						
							|  |  |  | 			retval = OK; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		    if (STRNICMP((char *)p, "false", 5) == 0) | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		    { | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			reader->js_used += 5; | 
					
						
							|  |  |  | 			if (cur_item != NULL) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2020-01-11 16:05:23 +01:00
										 |  |  | 			    cur_item->v_type = VAR_BOOL; | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			    cur_item->vval.v_number = VVAL_FALSE; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			retval = OK; | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    if (STRNICMP((char *)p, "true", 4) == 0) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			reader->js_used += 4; | 
					
						
							|  |  |  | 			if (cur_item != NULL) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2020-01-11 16:05:23 +01:00
										 |  |  | 			    cur_item->v_type = VAR_BOOL; | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			    cur_item->vval.v_number = VVAL_TRUE; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			retval = OK; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		    if (STRNICMP((char *)p, "null", 4) == 0) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			reader->js_used += 4; | 
					
						
							|  |  |  | 			if (cur_item != NULL) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			    cur_item->v_type = VAR_SPECIAL; | 
					
						
							|  |  |  | 			    cur_item->vval.v_number = VVAL_NULL; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			retval = OK; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | #ifdef FEAT_FLOAT
 | 
					
						
							|  |  |  | 		    if (STRNICMP((char *)p, "NaN", 3) == 0) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			reader->js_used += 3; | 
					
						
							|  |  |  | 			if (cur_item != NULL) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			    cur_item->v_type = VAR_FLOAT; | 
					
						
							|  |  |  | 			    cur_item->vval.v_float = NAN; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			retval = OK; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2019-01-12 14:24:27 +01:00
										 |  |  | 		    if (STRNICMP((char *)p, "-Infinity", 9) == 0) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			reader->js_used += 9; | 
					
						
							|  |  |  | 			if (cur_item != NULL) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			    cur_item->v_type = VAR_FLOAT; | 
					
						
							|  |  |  | 			    cur_item->vval.v_float = -INFINITY; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			retval = OK; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    if (STRNICMP((char *)p, "Infinity", 8) == 0) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			reader->js_used += 8; | 
					
						
							|  |  |  | 			if (cur_item != NULL) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			    cur_item->v_type = VAR_FLOAT; | 
					
						
							|  |  |  | 			    cur_item->vval.v_float = INFINITY; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			retval = OK; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 		    // check for truncated name
 | 
					
						
							| 
									
										
										
										
											2020-01-26 21:42:03 +01:00
										 |  |  | 		    len = (int)(reader->js_end | 
					
						
							|  |  |  | 					 - (reader->js_buf + reader->js_used)); | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    if ( | 
					
						
							|  |  |  | 			    (len < 5 && STRNICMP((char *)p, "false", len) == 0) | 
					
						
							|  |  |  | #ifdef FEAT_FLOAT
 | 
					
						
							| 
									
										
										
										
											2019-01-12 14:24:27 +01:00
										 |  |  | 			    || (len < 9 && STRNICMP((char *)p, "-Infinity", len) == 0) | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			    || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0) | 
					
						
							|  |  |  | 			    || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0) | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 			    || (len < 4 && (STRNICMP((char *)p, "true", len) == 0 | 
					
						
							|  |  |  | 				       ||  STRNICMP((char *)p, "null", len) == 0))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			retval = MAYBE; | 
					
						
							|  |  |  | 		    else | 
					
						
							|  |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 		    break; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  | 	    // We are finished when retval is FAIL or MAYBE and when at the
 | 
					
						
							|  |  |  | 	    // toplevel.
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 	    if (retval == FAIL) | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	    if (retval == MAYBE || stack.ga_len == 0) | 
					
						
							|  |  |  | 		goto theend; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY | 
					
						
							|  |  |  | 		    && cur_item != NULL) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	    { | 
					
						
							| 
									
										
										
										
											2021-06-06 14:14:39 +02:00
										 |  |  | #ifdef FEAT_FLOAT
 | 
					
						
							|  |  |  | 		if (cur_item->v_type == VAR_FLOAT) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		    // cannot use a float as a key
 | 
					
						
							|  |  |  | 		    emsg(_(e_float_as_string)); | 
					
						
							|  |  |  | 		    retval = FAIL; | 
					
						
							|  |  |  | 		    goto theend; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-12-21 16:04:21 +01:00
										 |  |  | 		top_item->jd_key = tv_get_string_buf_chk(cur_item, key_buf); | 
					
						
							| 
									
										
										
										
											2017-02-05 16:34:43 +01:00
										 |  |  | 		if (top_item->jd_key == NULL) | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-01-13 23:38:42 +01:00
										 |  |  | 		    emsg(_(e_invarg)); | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    retval = FAIL; | 
					
						
							|  |  |  | 		    goto theend; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | item_end: | 
					
						
							|  |  |  | 	top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1; | 
					
						
							|  |  |  | 	switch (top_item->jd_type) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    case JSON_ARRAY: | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		if (res != NULL) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    listitem_T	*li = listitem_alloc(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		    if (li == NULL) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			clear_tv(cur_item); | 
					
						
							|  |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 			goto theend; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		    li->li_tv = *cur_item; | 
					
						
							|  |  |  | 		    list_append(top_item->jd_tv.vval.v_list, li); | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		if (cur_item != NULL) | 
					
						
							|  |  |  | 		    cur_item = &item; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		json_skip_white(reader); | 
					
						
							|  |  |  | 		p = reader->js_buf + reader->js_used; | 
					
						
							|  |  |  | 		if (*p == ',') | 
					
						
							|  |  |  | 		    ++reader->js_used; | 
					
						
							|  |  |  | 		else if (*p != ']') | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    if (*p == NUL) | 
					
						
							|  |  |  | 			retval = MAYBE; | 
					
						
							|  |  |  | 		    else | 
					
						
							|  |  |  | 		    { | 
					
						
							| 
									
										
										
										
											2020-05-19 22:38:59 +02:00
										 |  |  | 			semsg(_(e_json_error), p); | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		    goto theend; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    case JSON_OBJECT_KEY: | 
					
						
							|  |  |  | 		json_skip_white(reader); | 
					
						
							|  |  |  | 		p = reader->js_buf + reader->js_used; | 
					
						
							|  |  |  | 		if (*p != ':') | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		    if (cur_item != NULL) | 
					
						
							|  |  |  | 			clear_tv(cur_item); | 
					
						
							|  |  |  | 		    if (*p == NUL) | 
					
						
							|  |  |  | 			retval = MAYBE; | 
					
						
							|  |  |  | 		    else | 
					
						
							|  |  |  | 		    { | 
					
						
							| 
									
										
										
										
											2020-05-19 22:38:59 +02:00
										 |  |  | 			semsg(_(e_json_error), p); | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		    goto theend; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		++reader->js_used; | 
					
						
							|  |  |  | 		json_skip_white(reader); | 
					
						
							|  |  |  | 		top_item->jd_type = JSON_OBJECT; | 
					
						
							|  |  |  | 		if (cur_item != NULL) | 
					
						
							|  |  |  | 		    cur_item = &item; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    case JSON_OBJECT: | 
					
						
							|  |  |  | 		if (cur_item != NULL | 
					
						
							|  |  |  | 			&& dict_find(top_item->jd_tv.vval.v_dict, | 
					
						
							|  |  |  | 						 top_item->jd_key, -1) != NULL) | 
					
						
							| 
									
										
										
										
											2016-02-23 21:26:43 +01:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-01-13 23:38:42 +01:00
										 |  |  | 		    semsg(_("E938: Duplicate key in JSON: \"%s\""), | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 							     top_item->jd_key); | 
					
						
							|  |  |  | 		    clear_tv(cur_item); | 
					
						
							|  |  |  | 		    retval = FAIL; | 
					
						
							|  |  |  | 		    goto theend; | 
					
						
							| 
									
										
										
										
											2016-02-23 21:26:43 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (cur_item != NULL) | 
					
						
							| 
									
										
										
										
											2016-02-23 21:26:43 +01:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 		    dictitem_T *di = dictitem_alloc(top_item->jd_key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		    clear_tv(&top_item->jd_key_tv); | 
					
						
							|  |  |  | 		    if (di == NULL) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			clear_tv(cur_item); | 
					
						
							|  |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 			goto theend; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		    di->di_tv = *cur_item; | 
					
						
							|  |  |  | 		    di->di_tv.v_lock = 0; | 
					
						
							|  |  |  | 		    if (dict_add(top_item->jd_tv.vval.v_dict, di) == FAIL) | 
					
						
							|  |  |  | 		    { | 
					
						
							|  |  |  | 			dictitem_free(di); | 
					
						
							|  |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 			goto theend; | 
					
						
							|  |  |  | 		    } | 
					
						
							| 
									
										
										
										
											2016-02-23 21:26:43 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		json_skip_white(reader); | 
					
						
							|  |  |  | 		p = reader->js_buf + reader->js_used; | 
					
						
							|  |  |  | 		if (*p == ',') | 
					
						
							|  |  |  | 		    ++reader->js_used; | 
					
						
							|  |  |  | 		else if (*p != '}') | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		    if (*p == NUL) | 
					
						
							|  |  |  | 			retval = MAYBE; | 
					
						
							|  |  |  | 		    else | 
					
						
							|  |  |  | 		    { | 
					
						
							| 
									
										
										
										
											2020-05-19 22:38:59 +02:00
										 |  |  | 			semsg(_(e_json_error), p); | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 			retval = FAIL; | 
					
						
							|  |  |  | 		    } | 
					
						
							|  |  |  | 		    goto theend; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		top_item->jd_type = JSON_OBJECT_KEY; | 
					
						
							|  |  |  | 		if (cur_item != NULL) | 
					
						
							|  |  |  | 		    cur_item = &top_item->jd_key_tv; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  |     // Get here when parsing failed.
 | 
					
						
							| 
									
										
										
										
											2016-10-21 20:35:37 +02:00
										 |  |  |     if (res != NULL) | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 	clear_tv(res); | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	res->v_type = VAR_SPECIAL; | 
					
						
							|  |  |  | 	res->vval.v_number = VVAL_NONE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-05-19 22:38:59 +02:00
										 |  |  |     semsg(_(e_json_error), p); | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | theend: | 
					
						
							| 
									
										
										
										
											2020-07-12 14:34:00 +02:00
										 |  |  |     for (i = 0; i < stack.ga_len; i++) | 
					
						
							|  |  |  | 	clear_tv(&(((json_dec_item_T *)stack.ga_data) + i)->jd_key_tv); | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  |     ga_clear(&stack); | 
					
						
							| 
									
										
										
										
											2020-07-12 14:34:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-10 19:44:18 +01:00
										 |  |  |     return retval; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Decode the JSON from "reader" and store the result in "res". | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  |  * "options" can be JSON_JS or zero; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |  * Return FAIL if not the whole message was consumed. | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-08-20 20:13:45 +02:00
										 |  |  |     static int | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | json_decode_all(js_read_T *reader, typval_T *res, int options) | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  |     // We find the end once, to avoid calling strlen() many times.
 | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     reader->js_end = reader->js_buf + STRLEN(reader->js_buf); | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     json_skip_white(reader); | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  |     ret = json_decode_item(reader, res, options); | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     if (ret != OK) | 
					
						
							| 
									
										
										
										
											2017-01-10 15:15:37 +01:00
										 |  |  |     { | 
					
						
							|  |  |  | 	if (ret == MAYBE) | 
					
						
							| 
									
										
										
										
											2020-05-19 22:38:59 +02:00
										 |  |  | 	    semsg(_(e_json_error), reader->js_buf); | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 	return FAIL; | 
					
						
							| 
									
										
										
										
											2017-01-10 15:15:37 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  |     json_skip_white(reader); | 
					
						
							|  |  |  |     if (reader->js_buf[reader->js_used] != NUL) | 
					
						
							| 
									
										
										
										
											2017-01-10 15:15:37 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-07-23 17:16:18 +02:00
										 |  |  | 	semsg(_(e_trailing_arg), reader->js_buf + reader->js_used); | 
					
						
							| 
									
										
										
										
											2016-02-01 21:38:19 +01:00
										 |  |  | 	return FAIL; | 
					
						
							| 
									
										
										
										
											2017-01-10 15:15:37 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-02-01 21:38:19 +01:00
										 |  |  |     return OK; | 
					
						
							| 
									
										
										
										
											2016-01-23 19:46:28 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-20 15:30:40 +01:00
										 |  |  | #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
 | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Decode the JSON from "reader" and store the result in "res". | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  |  * "options" can be JSON_JS or zero; | 
					
						
							| 
									
										
										
										
											2016-03-20 16:40:37 +01:00
										 |  |  |  * Return FAIL for a decoding error. | 
					
						
							|  |  |  |  * Return MAYBE for an incomplete message. | 
					
						
							|  |  |  |  * Consumes the message anyway. | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |  */ | 
					
						
							|  |  |  |     int | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | json_decode(js_read_T *reader, typval_T *res, int options) | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  |     // We find the end once, to avoid calling strlen() many times.
 | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     reader->js_end = reader->js_buf + STRLEN(reader->js_buf); | 
					
						
							|  |  |  |     json_skip_white(reader); | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  |     ret = json_decode_item(reader, res, options); | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     json_skip_white(reader); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-20 16:40:37 +01:00
										 |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-01-20 15:30:40 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Decode the JSON from "reader" to find the end of the message. | 
					
						
							| 
									
										
										
										
											2017-01-22 15:56:26 +01:00
										 |  |  |  * "options" can be JSON_JS or zero. | 
					
						
							|  |  |  |  * This is only used for testing. | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |  * Return FAIL if the message has a decoding error. | 
					
						
							|  |  |  |  * Return MAYBE if the message is truncated, need to read more. | 
					
						
							|  |  |  |  * This only works reliable if the message contains an object, array or | 
					
						
							| 
									
										
										
										
											2019-01-12 14:24:27 +01:00
										 |  |  |  * string.  A number might be truncated without knowing. | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |  * Does not advance the reader. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  |     int | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  | json_find_end(js_read_T *reader, int options) | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     int used_save = reader->js_used; | 
					
						
							|  |  |  |     int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 21:57:43 +01:00
										 |  |  |     // We find the end once, to avoid calling strlen() many times.
 | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     reader->js_end = reader->js_buf + STRLEN(reader->js_buf); | 
					
						
							|  |  |  |     json_skip_white(reader); | 
					
						
							| 
									
										
										
										
											2016-02-07 19:19:53 +01:00
										 |  |  |     ret = json_decode_item(reader, NULL, options); | 
					
						
							| 
									
										
										
										
											2016-02-02 18:20:08 +01:00
										 |  |  |     reader->js_used = used_save; | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-07-22 23:03:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * "js_decode()" function | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  | f_js_decode(typval_T *argvars, typval_T *rettv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     js_read_T	reader; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-27 22:00:44 +02:00
										 |  |  |     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-22 23:03:57 +02:00
										 |  |  |     reader.js_buf = tv_get_string(&argvars[0]); | 
					
						
							|  |  |  |     reader.js_fill = NULL; | 
					
						
							|  |  |  |     reader.js_used = 0; | 
					
						
							|  |  |  |     if (json_decode_all(&reader, rettv, JSON_JS) != OK) | 
					
						
							|  |  |  | 	emsg(_(e_invarg)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * "js_encode()" function | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  | f_js_encode(typval_T *argvars, typval_T *rettv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     rettv->v_type = VAR_STRING; | 
					
						
							|  |  |  |     rettv->vval.v_string = json_encode(&argvars[0], JSON_JS); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * "json_decode()" function | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  | f_json_decode(typval_T *argvars, typval_T *rettv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     js_read_T	reader; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-27 22:00:44 +02:00
										 |  |  |     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL) | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-22 23:03:57 +02:00
										 |  |  |     reader.js_buf = tv_get_string(&argvars[0]); | 
					
						
							|  |  |  |     reader.js_fill = NULL; | 
					
						
							|  |  |  |     reader.js_used = 0; | 
					
						
							|  |  |  |     json_decode_all(&reader, rettv, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * "json_encode()" function | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  | f_json_encode(typval_T *argvars, typval_T *rettv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     rettv->v_type = VAR_STRING; | 
					
						
							|  |  |  |     rettv->vval.v_string = json_encode(&argvars[0], 0); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-07-22 23:16:33 +02:00
										 |  |  | #endif
 |