forked from aniani/vim
patch 7.4.1279
Problem: jsonencode() is not producing strict JSON. Solution: Add jsencode() and jsdecode(). Make jsonencode() and jsondecode() strict.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
*channel.txt* For Vim version 7.4. Last change: 2016 Feb 06
|
*channel.txt* For Vim version 7.4. Last change: 2016 Feb 07
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@@ -16,7 +16,7 @@ The Netbeans interface also uses a channel. |netbeans|
|
|||||||
|
|
||||||
1. Demo |channel-demo|
|
1. Demo |channel-demo|
|
||||||
2. Opening a channel |channel-open|
|
2. Opening a channel |channel-open|
|
||||||
3. Using a JSON channel |channel-use|
|
3. Using a JSON or JS channel |channel-use|
|
||||||
4. Vim commands |channel-commands|
|
4. Vim commands |channel-commands|
|
||||||
5. Using a raw channel |channel-use|
|
5. Using a raw channel |channel-use|
|
||||||
6. Job control |job-control|
|
6. Job control |job-control|
|
||||||
@@ -77,6 +77,7 @@ To open a channel: >
|
|||||||
|
|
||||||
"mode" can be: *channel-mode*
|
"mode" can be: *channel-mode*
|
||||||
"json" - Use JSON, see below; most convenient way. Default.
|
"json" - Use JSON, see below; most convenient way. Default.
|
||||||
|
"js" - Use JavaScript encoding, more efficient than JSON.
|
||||||
"raw" - Use raw messages
|
"raw" - Use raw messages
|
||||||
|
|
||||||
*channel-callback*
|
*channel-callback*
|
||||||
@@ -86,7 +87,7 @@ message. Example: >
|
|||||||
func Handle(handle, msg)
|
func Handle(handle, msg)
|
||||||
echo 'Received: ' . a:msg
|
echo 'Received: ' . a:msg
|
||||||
endfunc
|
endfunc
|
||||||
let handle = ch_open("localhost:8765", 'json', "Handle")
|
let handle = ch_open("localhost:8765", {"callback": "Handle"})
|
||||||
|
|
||||||
"waittime" is the time to wait for the connection to be made in milliseconds.
|
"waittime" is the time to wait for the connection to be made in milliseconds.
|
||||||
The default is zero, don't wait, which is useful if the server is supposed to
|
The default is zero, don't wait, which is useful if the server is supposed to
|
||||||
@@ -95,12 +96,12 @@ be running already. A negative number waits forever.
|
|||||||
"timeout" is the time to wait for a request when blocking, using
|
"timeout" is the time to wait for a request when blocking, using
|
||||||
ch_sendexpr(). Again in milliseconds. The default is 2000 (2 seconds).
|
ch_sendexpr(). Again in milliseconds. The default is 2000 (2 seconds).
|
||||||
|
|
||||||
When "mode" is "json" the "msg" argument is the body of the received message,
|
When "mode" is "json" or "js" the "msg" argument is the body of the received
|
||||||
converted to Vim types.
|
message, converted to Vim types.
|
||||||
When "mode" is "raw" the "msg" argument is the whole message as a string.
|
When "mode" is "raw" the "msg" argument is the whole message as a string.
|
||||||
|
|
||||||
When "mode" is "json" the "callback" is optional. When omitted it is only
|
When "mode" is "json" or "js" the "callback" is optional. When omitted it is
|
||||||
possible to receive a message after sending one.
|
only possible to receive a message after sending one.
|
||||||
|
|
||||||
The handler can be added or changed later: >
|
The handler can be added or changed later: >
|
||||||
call ch_setcallback(handle, {callback})
|
call ch_setcallback(handle, {callback})
|
||||||
@@ -123,12 +124,15 @@ If there is an error reading or writing a channel it will be closed.
|
|||||||
*E896* *E630* *E631*
|
*E896* *E630* *E631*
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
3. Using a JSON channel *channel-use*
|
3. Using a JSON or JS channel *channel-use*
|
||||||
|
|
||||||
If {mode} is "json" then a message can be sent synchronously like this: >
|
If {mode} is "json" then a message can be sent synchronously like this: >
|
||||||
let response = ch_sendexpr(handle, {expr})
|
let response = ch_sendexpr(handle, {expr})
|
||||||
This awaits a response from the other side.
|
This awaits a response from the other side.
|
||||||
|
|
||||||
|
When {mode} is "js" this works the same, except that the messages use
|
||||||
|
JavaScript encoding. See |jsencode()| for the difference.
|
||||||
|
|
||||||
To send a message, without handling a response: >
|
To send a message, without handling a response: >
|
||||||
call ch_sendexpr(handle, {expr}, 0)
|
call ch_sendexpr(handle, {expr}, 0)
|
||||||
|
|
||||||
@@ -231,7 +235,8 @@ Here {number} is the same as what was in the request. Use a negative number
|
|||||||
to avoid confusion with message that Vim sends.
|
to avoid confusion with message that Vim sends.
|
||||||
|
|
||||||
{result} is the result of the evaluation and is JSON encoded. If the
|
{result} is the result of the evaluation and is JSON encoded. If the
|
||||||
evaluation fails it is the string "ERROR".
|
evaluation fails or the result can't be encoded in JSON it is the string
|
||||||
|
"ERROR".
|
||||||
|
|
||||||
|
|
||||||
Command "expr" ~
|
Command "expr" ~
|
||||||
|
@@ -1956,6 +1956,8 @@ job_start({command} [, {options}]) Job start a job
|
|||||||
job_status({job}) String get the status of a job
|
job_status({job}) String get the status of a job
|
||||||
job_stop({job} [, {how}]) Number stop a job
|
job_stop({job} [, {how}]) Number stop a job
|
||||||
join( {list} [, {sep}]) String join {list} items into one String
|
join( {list} [, {sep}]) String join {list} items into one String
|
||||||
|
jsdecode( {string}) any decode JS style JSON
|
||||||
|
jsencode( {expr}) String encode JS style JSON
|
||||||
jsondecode( {string}) any decode JSON
|
jsondecode( {string}) any decode JSON
|
||||||
jsonencode( {expr}) String encode JSON
|
jsonencode( {expr}) String encode JSON
|
||||||
keys( {dict}) List keys in {dict}
|
keys( {dict}) List keys in {dict}
|
||||||
@@ -2439,7 +2441,6 @@ bufwinnr({expr}) *bufwinnr()*
|
|||||||
|:wincmd|.
|
|:wincmd|.
|
||||||
Only deals with the current tab page.
|
Only deals with the current tab page.
|
||||||
|
|
||||||
|
|
||||||
byte2line({byte}) *byte2line()*
|
byte2line({byte}) *byte2line()*
|
||||||
Return the line number that contains the character at byte
|
Return the line number that contains the character at byte
|
||||||
count {byte} in the current buffer. This includes the
|
count {byte} in the current buffer. This includes the
|
||||||
@@ -2688,7 +2689,7 @@ ch_open({address} [, {argdict}]) *ch_open()*
|
|||||||
|
|
||||||
If {argdict} is given it must be a |Dictionary|. The optional
|
If {argdict} is given it must be a |Dictionary|. The optional
|
||||||
items are:
|
items are:
|
||||||
mode "raw" or "json".
|
mode "raw", "js" or "json".
|
||||||
Default "json".
|
Default "json".
|
||||||
callback function to call for requests with a zero
|
callback function to call for requests with a zero
|
||||||
sequence number. See |channel-callback|.
|
sequence number. See |channel-callback|.
|
||||||
@@ -4381,17 +4382,33 @@ join({list} [, {sep}]) *join()*
|
|||||||
converted into a string like with |string()|.
|
converted into a string like with |string()|.
|
||||||
The opposite function is |split()|.
|
The opposite function is |split()|.
|
||||||
|
|
||||||
|
jsdecode({string}) *jsdecode()*
|
||||||
|
This is similar to |jsondecode()| with these differences:
|
||||||
|
- Object key names do not have to be in quotes.
|
||||||
|
- Empty items in an array (between two commas) are allowed and
|
||||||
|
result in v:none items.
|
||||||
|
|
||||||
|
jsencode({expr}) *jsencode()*
|
||||||
|
This is similar to |jsonencode()| with these differences:
|
||||||
|
- Object key names are not in quotes.
|
||||||
|
- v:none items in an array result in an empty item between
|
||||||
|
commas.
|
||||||
|
For example, the Vim object:
|
||||||
|
[1,v:none,{"one":1}],v:none ~
|
||||||
|
Will be encoded as:
|
||||||
|
[1,,{one:1},,] ~
|
||||||
|
While jsonencode() would produce:
|
||||||
|
[1,null,{"one":1},null] ~
|
||||||
|
This encoding is valid for JavaScript. It is more efficient
|
||||||
|
than JSON, especially when using an array with optional items.
|
||||||
|
|
||||||
|
|
||||||
jsondecode({string}) *jsondecode()*
|
jsondecode({string}) *jsondecode()*
|
||||||
This parses a JSON formatted string and returns the equivalent
|
This parses a JSON formatted string and returns the equivalent
|
||||||
in Vim values. See |jsonencode()| for the relation between
|
in Vim values. See |jsonencode()| for the relation between
|
||||||
JSON and Vim values.
|
JSON and Vim values.
|
||||||
The decoding is permissive:
|
The decoding is permissive:
|
||||||
- A trailing comma in an array and object is ignored.
|
- A trailing comma in an array and object is ignored.
|
||||||
- An empty item in an array, two commas with nothing or white
|
|
||||||
space in between, results in v:none.
|
|
||||||
- When an object member name is not a string it is converted
|
|
||||||
to a string. E.g. the number 123 is used as the string
|
|
||||||
"123".
|
|
||||||
- More floating point numbers are recognized, e.g. "1." for
|
- More floating point numbers are recognized, e.g. "1." for
|
||||||
"1.0".
|
"1.0".
|
||||||
The result must be a valid Vim type:
|
The result must be a valid Vim type:
|
||||||
@@ -4413,7 +4430,7 @@ jsonencode({expr}) *jsonencode()*
|
|||||||
used recursively: {}
|
used recursively: {}
|
||||||
v:false "false"
|
v:false "false"
|
||||||
v:true "true"
|
v:true "true"
|
||||||
v:none nothing
|
v:none "null"
|
||||||
v:null "null"
|
v:null "null"
|
||||||
Note that using v:none is permitted, although the JSON
|
Note that using v:none is permitted, although the JSON
|
||||||
standard does not allow empty items. This can be useful for
|
standard does not allow empty items. This can be useful for
|
||||||
|
@@ -119,7 +119,7 @@ typedef struct {
|
|||||||
char_u *ch_callback; /* function to call when a msg is not handled */
|
char_u *ch_callback; /* function to call when a msg is not handled */
|
||||||
cbq_T ch_cb_head; /* dummy node for pre-request callbacks */
|
cbq_T ch_cb_head; /* dummy node for pre-request callbacks */
|
||||||
|
|
||||||
int ch_json_mode; /* TRUE for a json channel */
|
ch_mode_T ch_mode;
|
||||||
jsonq_T ch_json_head; /* dummy node, header for circular queue */
|
jsonq_T ch_json_head; /* dummy node, header for circular queue */
|
||||||
|
|
||||||
int ch_timeout; /* request timeout in msec */
|
int ch_timeout; /* request timeout in msec */
|
||||||
@@ -526,12 +526,12 @@ channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void))
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the json mode of channel "idx" to TRUE or FALSE.
|
* Set the json mode of channel "idx" to "ch_mode".
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
channel_set_json_mode(int idx, int json_mode)
|
channel_set_json_mode(int idx, ch_mode_T ch_mode)
|
||||||
{
|
{
|
||||||
channels[idx].ch_json_mode = json_mode;
|
channels[idx].ch_mode = ch_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -672,7 +672,8 @@ channel_parse_json(int ch_idx)
|
|||||||
js_read_T reader;
|
js_read_T reader;
|
||||||
typval_T listtv;
|
typval_T listtv;
|
||||||
jsonq_T *item;
|
jsonq_T *item;
|
||||||
jsonq_T *head = &channels[ch_idx].ch_json_head;
|
channel_T *channel = &channels[ch_idx];
|
||||||
|
jsonq_T *head = &channel->ch_json_head;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (channel_peek(ch_idx) == NULL)
|
if (channel_peek(ch_idx) == NULL)
|
||||||
@@ -685,7 +686,8 @@ channel_parse_json(int ch_idx)
|
|||||||
reader.js_fill = NULL;
|
reader.js_fill = NULL;
|
||||||
/* reader.js_fill = channel_fill; */
|
/* reader.js_fill = channel_fill; */
|
||||||
reader.js_cookie = &ch_idx;
|
reader.js_cookie = &ch_idx;
|
||||||
ret = json_decode(&reader, &listtv);
|
ret = json_decode(&reader, &listtv,
|
||||||
|
channel->ch_mode == MODE_JS ? JSON_JS : 0);
|
||||||
if (ret == OK)
|
if (ret == OK)
|
||||||
{
|
{
|
||||||
/* Only accept the response when it is a list with at least two
|
/* Only accept the response when it is a list with at least two
|
||||||
@@ -854,6 +856,8 @@ channel_exe_cmd(int idx, char_u *cmd, typval_T *arg2, typval_T *arg3)
|
|||||||
typval_T *tv;
|
typval_T *tv;
|
||||||
typval_T err_tv;
|
typval_T err_tv;
|
||||||
char_u *json = NULL;
|
char_u *json = NULL;
|
||||||
|
channel_T *channel = &channels[idx];
|
||||||
|
int options = channel->ch_mode == MODE_JS ? JSON_JS : 0;
|
||||||
|
|
||||||
/* Don't pollute the display with errors. */
|
/* Don't pollute the display with errors. */
|
||||||
++emsg_skip;
|
++emsg_skip;
|
||||||
@@ -861,7 +865,8 @@ channel_exe_cmd(int idx, char_u *cmd, typval_T *arg2, typval_T *arg3)
|
|||||||
if (is_eval)
|
if (is_eval)
|
||||||
{
|
{
|
||||||
if (tv != NULL)
|
if (tv != NULL)
|
||||||
json = json_encode_nr_expr(arg3->vval.v_number, tv);
|
json = json_encode_nr_expr(arg3->vval.v_number, tv,
|
||||||
|
options);
|
||||||
if (tv == NULL || (json != NULL && *json == NUL))
|
if (tv == NULL || (json != NULL && *json == NUL))
|
||||||
{
|
{
|
||||||
/* If evaluation failed or the result can't be encoded
|
/* If evaluation failed or the result can't be encoded
|
||||||
@@ -869,7 +874,8 @@ channel_exe_cmd(int idx, char_u *cmd, typval_T *arg2, typval_T *arg3)
|
|||||||
err_tv.v_type = VAR_STRING;
|
err_tv.v_type = VAR_STRING;
|
||||||
err_tv.vval.v_string = (char_u *)"ERROR";
|
err_tv.vval.v_string = (char_u *)"ERROR";
|
||||||
tv = &err_tv;
|
tv = &err_tv;
|
||||||
json = json_encode_nr_expr(arg3->vval.v_number, tv);
|
json = json_encode_nr_expr(arg3->vval.v_number, tv,
|
||||||
|
options);
|
||||||
}
|
}
|
||||||
if (json != NULL)
|
if (json != NULL)
|
||||||
{
|
{
|
||||||
@@ -900,13 +906,13 @@ may_invoke_callback(int idx)
|
|||||||
typval_T argv[3];
|
typval_T argv[3];
|
||||||
int seq_nr = -1;
|
int seq_nr = -1;
|
||||||
channel_T *channel = &channels[idx];
|
channel_T *channel = &channels[idx];
|
||||||
int json_mode = channel->ch_json_mode;
|
ch_mode_T ch_mode = channel->ch_mode;
|
||||||
|
|
||||||
if (channel->ch_close_cb != NULL)
|
if (channel->ch_close_cb != NULL)
|
||||||
/* this channel is handled elsewhere (netbeans) */
|
/* this channel is handled elsewhere (netbeans) */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (json_mode)
|
if (ch_mode != MODE_RAW)
|
||||||
{
|
{
|
||||||
/* Get any json message in the queue. */
|
/* Get any json message in the queue. */
|
||||||
if (channel_get_json(idx, -1, &listtv) == FAIL)
|
if (channel_get_json(idx, -1, &listtv) == FAIL)
|
||||||
|
47
src/eval.c
47
src/eval.c
@@ -628,6 +628,8 @@ static void f_job_stop(typval_T *argvars, typval_T *rettv);
|
|||||||
static void f_job_status(typval_T *argvars, typval_T *rettv);
|
static void f_job_status(typval_T *argvars, typval_T *rettv);
|
||||||
#endif
|
#endif
|
||||||
static void f_join(typval_T *argvars, typval_T *rettv);
|
static void f_join(typval_T *argvars, typval_T *rettv);
|
||||||
|
static void f_jsdecode(typval_T *argvars, typval_T *rettv);
|
||||||
|
static void f_jsencode(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_jsondecode(typval_T *argvars, typval_T *rettv);
|
static void f_jsondecode(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_jsonencode(typval_T *argvars, typval_T *rettv);
|
static void f_jsonencode(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_keys(typval_T *argvars, typval_T *rettv);
|
static void f_keys(typval_T *argvars, typval_T *rettv);
|
||||||
@@ -8206,6 +8208,8 @@ static struct fst
|
|||||||
{"job_stop", 1, 1, f_job_stop},
|
{"job_stop", 1, 1, f_job_stop},
|
||||||
#endif
|
#endif
|
||||||
{"join", 1, 2, f_join},
|
{"join", 1, 2, f_join},
|
||||||
|
{"jsdecode", 1, 1, f_jsdecode},
|
||||||
|
{"jsencode", 1, 1, f_jsencode},
|
||||||
{"jsondecode", 1, 1, f_jsondecode},
|
{"jsondecode", 1, 1, f_jsondecode},
|
||||||
{"jsonencode", 1, 1, f_jsonencode},
|
{"jsonencode", 1, 1, f_jsonencode},
|
||||||
{"keys", 1, 1, f_keys},
|
{"keys", 1, 1, f_keys},
|
||||||
@@ -9829,7 +9833,7 @@ f_ch_open(typval_T *argvars, typval_T *rettv)
|
|||||||
int port;
|
int port;
|
||||||
int waittime = 0;
|
int waittime = 0;
|
||||||
int timeout = 2000;
|
int timeout = 2000;
|
||||||
int json_mode = TRUE;
|
ch_mode_T ch_mode = MODE_JSON;
|
||||||
int ch_idx;
|
int ch_idx;
|
||||||
|
|
||||||
/* default: fail */
|
/* default: fail */
|
||||||
@@ -9868,8 +9872,12 @@ f_ch_open(typval_T *argvars, typval_T *rettv)
|
|||||||
{
|
{
|
||||||
mode = get_dict_string(dict, (char_u *)"mode", FALSE);
|
mode = get_dict_string(dict, (char_u *)"mode", FALSE);
|
||||||
if (STRCMP(mode, "raw") == 0)
|
if (STRCMP(mode, "raw") == 0)
|
||||||
json_mode = FALSE;
|
ch_mode = MODE_RAW;
|
||||||
else if (STRCMP(mode, "json") != 0)
|
else if (STRCMP(mode, "js") == 0)
|
||||||
|
ch_mode = MODE_JS;
|
||||||
|
else if (STRCMP(mode, "json") == 0)
|
||||||
|
ch_mode = MODE_JSON;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
EMSG2(_(e_invarg2), mode);
|
EMSG2(_(e_invarg2), mode);
|
||||||
return;
|
return;
|
||||||
@@ -9891,7 +9899,7 @@ f_ch_open(typval_T *argvars, typval_T *rettv)
|
|||||||
ch_idx = channel_open((char *)address, port, waittime, NULL);
|
ch_idx = channel_open((char *)address, port, waittime, NULL);
|
||||||
if (ch_idx >= 0)
|
if (ch_idx >= 0)
|
||||||
{
|
{
|
||||||
channel_set_json_mode(ch_idx, json_mode);
|
channel_set_json_mode(ch_idx, ch_mode);
|
||||||
channel_set_timeout(ch_idx, timeout);
|
channel_set_timeout(ch_idx, timeout);
|
||||||
if (callback != NULL && *callback != NUL)
|
if (callback != NULL && *callback != NUL)
|
||||||
channel_set_callback(ch_idx, callback);
|
channel_set_callback(ch_idx, callback);
|
||||||
@@ -9946,7 +9954,7 @@ f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
|
|||||||
rettv->vval.v_string = NULL;
|
rettv->vval.v_string = NULL;
|
||||||
|
|
||||||
id = channel_get_id();
|
id = channel_get_id();
|
||||||
text = json_encode_nr_expr(id, &argvars[1]);
|
text = json_encode_nr_expr(id, &argvars[1], 0);
|
||||||
if (text == NULL)
|
if (text == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -14442,6 +14450,31 @@ f_join(typval_T *argvars, typval_T *rettv)
|
|||||||
rettv->vval.v_string = NULL;
|
rettv->vval.v_string = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "jsdecode()" function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
f_jsdecode(typval_T *argvars, typval_T *rettv)
|
||||||
|
{
|
||||||
|
js_read_T reader;
|
||||||
|
|
||||||
|
reader.js_buf = get_tv_string(&argvars[0]);
|
||||||
|
reader.js_fill = NULL;
|
||||||
|
reader.js_used = 0;
|
||||||
|
if (json_decode_all(&reader, rettv, JSON_JS) != OK)
|
||||||
|
EMSG(_(e_invarg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "jsencode()" function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
f_jsencode(typval_T *argvars, typval_T *rettv)
|
||||||
|
{
|
||||||
|
rettv->v_type = VAR_STRING;
|
||||||
|
rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "jsondecode()" function
|
* "jsondecode()" function
|
||||||
*/
|
*/
|
||||||
@@ -14453,7 +14486,7 @@ f_jsondecode(typval_T *argvars, typval_T *rettv)
|
|||||||
reader.js_buf = get_tv_string(&argvars[0]);
|
reader.js_buf = get_tv_string(&argvars[0]);
|
||||||
reader.js_fill = NULL;
|
reader.js_fill = NULL;
|
||||||
reader.js_used = 0;
|
reader.js_used = 0;
|
||||||
if (json_decode_all(&reader, rettv) != OK)
|
if (json_decode_all(&reader, rettv, 0) != OK)
|
||||||
EMSG(_(e_invarg));
|
EMSG(_(e_invarg));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14464,7 +14497,7 @@ f_jsondecode(typval_T *argvars, typval_T *rettv)
|
|||||||
f_jsonencode(typval_T *argvars, typval_T *rettv)
|
f_jsonencode(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
rettv->v_type = VAR_STRING;
|
rettv->v_type = VAR_STRING;
|
||||||
rettv->vval.v_string = json_encode(&argvars[0]);
|
rettv->vval.v_string = json_encode(&argvars[0], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
120
src/json.c
120
src/json.c
@@ -16,22 +16,23 @@
|
|||||||
#include "vim.h"
|
#include "vim.h"
|
||||||
|
|
||||||
#if defined(FEAT_EVAL) || defined(PROTO)
|
#if defined(FEAT_EVAL) || defined(PROTO)
|
||||||
static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none);
|
static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options);
|
||||||
static int json_decode_item(js_read_T *reader, typval_T *res);
|
static int json_decode_item(js_read_T *reader, typval_T *res, int options);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Encode "val" into a JSON format string.
|
* Encode "val" into a JSON format string.
|
||||||
* The result is in allocated memory.
|
* The result is in allocated memory.
|
||||||
* The result is empty when encoding fails.
|
* The result is empty when encoding fails.
|
||||||
|
* "options" can be JSON_JS or zero;
|
||||||
*/
|
*/
|
||||||
char_u *
|
char_u *
|
||||||
json_encode(typval_T *val)
|
json_encode(typval_T *val, int options)
|
||||||
{
|
{
|
||||||
garray_T ga;
|
garray_T ga;
|
||||||
|
|
||||||
/* Store bytes in the growarray. */
|
/* Store bytes in the growarray. */
|
||||||
ga_init2(&ga, 1, 4000);
|
ga_init2(&ga, 1, 4000);
|
||||||
if (json_encode_item(&ga, val, get_copyID(), TRUE) == FAIL)
|
if (json_encode_item(&ga, val, get_copyID(), options) == FAIL)
|
||||||
{
|
{
|
||||||
vim_free(ga.ga_data);
|
vim_free(ga.ga_data);
|
||||||
return vim_strsave((char_u *)"");
|
return vim_strsave((char_u *)"");
|
||||||
@@ -41,10 +42,11 @@ json_encode(typval_T *val)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Encode ["nr", "val"] into a JSON format string in allocated memory.
|
* Encode ["nr", "val"] into a JSON format string in allocated memory.
|
||||||
|
* "options" can be JSON_JS or zero;
|
||||||
* Returns NULL when out of memory.
|
* Returns NULL when out of memory.
|
||||||
*/
|
*/
|
||||||
char_u *
|
char_u *
|
||||||
json_encode_nr_expr(int nr, typval_T *val)
|
json_encode_nr_expr(int nr, typval_T *val, int options)
|
||||||
{
|
{
|
||||||
typval_T listtv;
|
typval_T listtv;
|
||||||
typval_T nrtv;
|
typval_T nrtv;
|
||||||
@@ -61,7 +63,7 @@ json_encode_nr_expr(int nr, typval_T *val)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
text = json_encode(&listtv);
|
text = json_encode(&listtv, options);
|
||||||
list_unref(listtv.vval.v_list);
|
list_unref(listtv.vval.v_list);
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
@@ -122,12 +124,30 @@ write_string(garray_T *gap, char_u *str)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Encode "val" into "gap".
|
* Encode "val" into "gap".
|
||||||
* Return FAIL or OK.
|
* Return FAIL or OK.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none)
|
json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
|
||||||
{
|
{
|
||||||
char_u numbuf[NUMBUFLEN];
|
char_u numbuf[NUMBUFLEN];
|
||||||
char_u *res;
|
char_u *res;
|
||||||
@@ -141,13 +161,11 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none)
|
|||||||
{
|
{
|
||||||
case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
|
case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
|
||||||
case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
|
case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
|
||||||
case VVAL_NONE: if (!allow_none)
|
case VVAL_NONE: if ((options & JSON_JS) != 0
|
||||||
{
|
&& (options & JSON_NO_NONE) == 0)
|
||||||
/* TODO: better error */
|
/* empty item */
|
||||||
EMSG(_(e_invarg));
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
/* FALLTHROUGH */
|
||||||
case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
|
case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -185,9 +203,15 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none)
|
|||||||
ga_append(gap, '[');
|
ga_append(gap, '[');
|
||||||
for (li = l->lv_first; li != NULL && !got_int; )
|
for (li = l->lv_first; li != NULL && !got_int; )
|
||||||
{
|
{
|
||||||
if (json_encode_item(gap, &li->li_tv, copyID, TRUE)
|
if (json_encode_item(gap, &li->li_tv, copyID,
|
||||||
== FAIL)
|
options & JSON_JS) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
if ((options & JSON_JS)
|
||||||
|
&& li->li_next == NULL
|
||||||
|
&& li->li_tv.v_type == VAR_SPECIAL
|
||||||
|
&& li->li_tv.vval.v_number == VVAL_NONE)
|
||||||
|
/* add an extra comma if the last item is v:none */
|
||||||
|
ga_append(gap, ',');
|
||||||
li = li->li_next;
|
li = li->li_next;
|
||||||
if (li != NULL)
|
if (li != NULL)
|
||||||
ga_append(gap, ',');
|
ga_append(gap, ',');
|
||||||
@@ -224,10 +248,14 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none)
|
|||||||
first = FALSE;
|
first = FALSE;
|
||||||
else
|
else
|
||||||
ga_append(gap, ',');
|
ga_append(gap, ',');
|
||||||
|
if ((options & JSON_JS)
|
||||||
|
&& is_simple_key(hi->hi_key))
|
||||||
|
ga_concat(gap, hi->hi_key);
|
||||||
|
else
|
||||||
write_string(gap, hi->hi_key);
|
write_string(gap, hi->hi_key);
|
||||||
ga_append(gap, ':');
|
ga_append(gap, ':');
|
||||||
if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
|
if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
|
||||||
copyID, FALSE) == FAIL)
|
copyID, options | JSON_NO_NONE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
ga_append(gap, '}');
|
ga_append(gap, '}');
|
||||||
@@ -265,7 +293,8 @@ fill_numbuflen(js_read_T *reader)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip white space in "reader".
|
* Skip white space in "reader". All characters <= space are considered white
|
||||||
|
* space.
|
||||||
* Also tops up readahead when needed.
|
* Also tops up readahead when needed.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
@@ -282,7 +311,7 @@ json_skip_white(js_read_T *reader)
|
|||||||
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
|
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c != ' ' && c != TAB && c != NL && c != CAR)
|
if (c == NUL || c > ' ')
|
||||||
break;
|
break;
|
||||||
++reader->js_used;
|
++reader->js_used;
|
||||||
}
|
}
|
||||||
@@ -290,7 +319,7 @@ json_skip_white(js_read_T *reader)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
json_decode_array(js_read_T *reader, typval_T *res)
|
json_decode_array(js_read_T *reader, typval_T *res, int options)
|
||||||
{
|
{
|
||||||
char_u *p;
|
char_u *p;
|
||||||
typval_T item;
|
typval_T item;
|
||||||
@@ -317,7 +346,7 @@ json_decode_array(js_read_T *reader, typval_T *res)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = json_decode_item(reader, res == NULL ? NULL : &item);
|
ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
|
||||||
if (ret != OK)
|
if (ret != OK)
|
||||||
return ret;
|
return ret;
|
||||||
if (res != NULL)
|
if (res != NULL)
|
||||||
@@ -347,7 +376,7 @@ json_decode_array(js_read_T *reader, typval_T *res)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
json_decode_object(js_read_T *reader, typval_T *res)
|
json_decode_object(js_read_T *reader, typval_T *res, int options)
|
||||||
{
|
{
|
||||||
char_u *p;
|
char_u *p;
|
||||||
typval_T tvkey;
|
typval_T tvkey;
|
||||||
@@ -377,7 +406,21 @@ json_decode_object(js_read_T *reader, typval_T *res)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = json_decode_item(reader, res == NULL ? NULL : &tvkey);
|
if ((options & JSON_JS) && reader->js_buf[reader->js_used] != '"')
|
||||||
|
{
|
||||||
|
/* accept a key that is not in quotes */
|
||||||
|
key = p = reader->js_buf + reader->js_used;
|
||||||
|
while (*p != NUL && *p != ':' && *p > ' ')
|
||||||
|
++p;
|
||||||
|
tvkey.v_type = VAR_STRING;
|
||||||
|
tvkey.vval.v_string = vim_strnsave(key, (int)(p - key));
|
||||||
|
reader->js_used += (int)(p - key);
|
||||||
|
key = tvkey.vval.v_string;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = json_decode_item(reader, res == NULL ? NULL : &tvkey,
|
||||||
|
options);
|
||||||
if (ret != OK)
|
if (ret != OK)
|
||||||
return ret;
|
return ret;
|
||||||
if (res != NULL)
|
if (res != NULL)
|
||||||
@@ -389,6 +432,7 @@ json_decode_object(js_read_T *reader, typval_T *res)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
json_skip_white(reader);
|
json_skip_white(reader);
|
||||||
p = reader->js_buf + reader->js_used;
|
p = reader->js_buf + reader->js_used;
|
||||||
@@ -403,7 +447,7 @@ json_decode_object(js_read_T *reader, typval_T *res)
|
|||||||
++reader->js_used;
|
++reader->js_used;
|
||||||
json_skip_white(reader);
|
json_skip_white(reader);
|
||||||
|
|
||||||
ret = json_decode_item(reader, res == NULL ? NULL : &item);
|
ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
|
||||||
if (ret != OK)
|
if (ret != OK)
|
||||||
{
|
{
|
||||||
if (res != NULL)
|
if (res != NULL)
|
||||||
@@ -569,7 +613,7 @@ json_decode_string(js_read_T *reader, typval_T *res)
|
|||||||
* Return MAYBE for an incomplete message.
|
* Return MAYBE for an incomplete message.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
json_decode_item(js_read_T *reader, typval_T *res)
|
json_decode_item(js_read_T *reader, typval_T *res, int options)
|
||||||
{
|
{
|
||||||
char_u *p;
|
char_u *p;
|
||||||
int len;
|
int len;
|
||||||
@@ -579,15 +623,18 @@ json_decode_item(js_read_T *reader, typval_T *res)
|
|||||||
switch (*p)
|
switch (*p)
|
||||||
{
|
{
|
||||||
case '[': /* array */
|
case '[': /* array */
|
||||||
return json_decode_array(reader, res);
|
return json_decode_array(reader, res, options);
|
||||||
|
|
||||||
case '{': /* object */
|
case '{': /* object */
|
||||||
return json_decode_object(reader, res);
|
return json_decode_object(reader, res, options);
|
||||||
|
|
||||||
case '"': /* string */
|
case '"': /* string */
|
||||||
return json_decode_string(reader, res);
|
return json_decode_string(reader, res);
|
||||||
|
|
||||||
case ',': /* comma: empty item */
|
case ',': /* comma: empty item */
|
||||||
|
if ((options & JSON_JS) == 0)
|
||||||
|
return FAIL;
|
||||||
|
/* FALLTHROUGH */
|
||||||
case NUL: /* empty */
|
case NUL: /* empty */
|
||||||
if (res != NULL)
|
if (res != NULL)
|
||||||
{
|
{
|
||||||
@@ -691,17 +738,18 @@ json_decode_item(js_read_T *reader, typval_T *res)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Decode the JSON from "reader" and store the result in "res".
|
* Decode the JSON from "reader" and store the result in "res".
|
||||||
|
* "options" can be JSON_JS or zero;
|
||||||
* Return FAIL if not the whole message was consumed.
|
* Return FAIL if not the whole message was consumed.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
json_decode_all(js_read_T *reader, typval_T *res)
|
json_decode_all(js_read_T *reader, typval_T *res, int options)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* We get the end once, to avoid calling strlen() many times. */
|
/* We find the end once, to avoid calling strlen() many times. */
|
||||||
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
|
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
|
||||||
json_skip_white(reader);
|
json_skip_white(reader);
|
||||||
ret = json_decode_item(reader, res);
|
ret = json_decode_item(reader, res, options);
|
||||||
if (ret != OK)
|
if (ret != OK)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
json_skip_white(reader);
|
json_skip_white(reader);
|
||||||
@@ -712,18 +760,19 @@ json_decode_all(js_read_T *reader, typval_T *res)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Decode the JSON from "reader" and store the result in "res".
|
* Decode the JSON from "reader" and store the result in "res".
|
||||||
|
* "options" can be JSON_JS or zero;
|
||||||
* Return FAIL if the message has a decoding error or the message is
|
* Return FAIL if the message has a decoding error or the message is
|
||||||
* truncated. Consumes the message anyway.
|
* truncated. Consumes the message anyway.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
json_decode(js_read_T *reader, typval_T *res)
|
json_decode(js_read_T *reader, typval_T *res, int options)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* We get the end once, to avoid calling strlen() many times. */
|
/* We find the end once, to avoid calling strlen() many times. */
|
||||||
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
|
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
|
||||||
json_skip_white(reader);
|
json_skip_white(reader);
|
||||||
ret = json_decode_item(reader, res);
|
ret = json_decode_item(reader, res, options);
|
||||||
json_skip_white(reader);
|
json_skip_white(reader);
|
||||||
|
|
||||||
return ret == OK ? OK : FAIL;
|
return ret == OK ? OK : FAIL;
|
||||||
@@ -731,6 +780,7 @@ json_decode(js_read_T *reader, typval_T *res)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Decode the JSON from "reader" to find the end of the message.
|
* Decode the JSON from "reader" to find the end of the message.
|
||||||
|
* "options" can be JSON_JS or zero;
|
||||||
* Return FAIL if the message has a decoding error.
|
* Return FAIL if the message has a decoding error.
|
||||||
* Return MAYBE if the message is truncated, need to read more.
|
* Return MAYBE if the message is truncated, need to read more.
|
||||||
* This only works reliable if the message contains an object, array or
|
* This only works reliable if the message contains an object, array or
|
||||||
@@ -738,15 +788,15 @@ json_decode(js_read_T *reader, typval_T *res)
|
|||||||
* Does not advance the reader.
|
* Does not advance the reader.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
json_find_end(js_read_T *reader)
|
json_find_end(js_read_T *reader, int options)
|
||||||
{
|
{
|
||||||
int used_save = reader->js_used;
|
int used_save = reader->js_used;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* We get the end once, to avoid calling strlen() many times. */
|
/* We find the end once, to avoid calling strlen() many times. */
|
||||||
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
|
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
|
||||||
json_skip_white(reader);
|
json_skip_white(reader);
|
||||||
ret = json_decode_item(reader, NULL);
|
ret = json_decode_item(reader, NULL, options);
|
||||||
reader->js_used = used_save;
|
reader->js_used = used_save;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@@ -35,107 +35,107 @@ test_decode_find_end(void)
|
|||||||
|
|
||||||
/* string and incomplete string */
|
/* string and incomplete string */
|
||||||
reader.js_buf = (char_u *)"\"hello\"";
|
reader.js_buf = (char_u *)"\"hello\"";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)" \"hello\" ";
|
reader.js_buf = (char_u *)" \"hello\" ";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)"\"hello";
|
reader.js_buf = (char_u *)"\"hello";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
|
|
||||||
/* number and dash (incomplete number) */
|
/* number and dash (incomplete number) */
|
||||||
reader.js_buf = (char_u *)"123";
|
reader.js_buf = (char_u *)"123";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)"-";
|
reader.js_buf = (char_u *)"-";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
|
|
||||||
/* false, true and null, also incomplete */
|
/* false, true and null, also incomplete */
|
||||||
reader.js_buf = (char_u *)"false";
|
reader.js_buf = (char_u *)"false";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)"f";
|
reader.js_buf = (char_u *)"f";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"fa";
|
reader.js_buf = (char_u *)"fa";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"fal";
|
reader.js_buf = (char_u *)"fal";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"fals";
|
reader.js_buf = (char_u *)"fals";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
|
|
||||||
reader.js_buf = (char_u *)"true";
|
reader.js_buf = (char_u *)"true";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)"t";
|
reader.js_buf = (char_u *)"t";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"tr";
|
reader.js_buf = (char_u *)"tr";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"tru";
|
reader.js_buf = (char_u *)"tru";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
|
|
||||||
reader.js_buf = (char_u *)"null";
|
reader.js_buf = (char_u *)"null";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)"n";
|
reader.js_buf = (char_u *)"n";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"nu";
|
reader.js_buf = (char_u *)"nu";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"nul";
|
reader.js_buf = (char_u *)"nul";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
|
|
||||||
/* object without white space */
|
/* object without white space */
|
||||||
reader.js_buf = (char_u *)"{\"a\":123}";
|
reader.js_buf = (char_u *)"{\"a\":123}";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)"{\"a\":123";
|
reader.js_buf = (char_u *)"{\"a\":123";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"{\"a\":";
|
reader.js_buf = (char_u *)"{\"a\":";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"{\"a\"";
|
reader.js_buf = (char_u *)"{\"a\"";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"{\"a";
|
reader.js_buf = (char_u *)"{\"a";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"{\"";
|
reader.js_buf = (char_u *)"{\"";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"{";
|
reader.js_buf = (char_u *)"{";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
|
|
||||||
/* object with white space */
|
/* object with white space */
|
||||||
reader.js_buf = (char_u *)" { \"a\" : 123 } ";
|
reader.js_buf = (char_u *)" { \"a\" : 123 } ";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)" { \"a\" : 123 ";
|
reader.js_buf = (char_u *)" { \"a\" : 123 ";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)" { \"a\" : ";
|
reader.js_buf = (char_u *)" { \"a\" : ";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)" { \"a\" ";
|
reader.js_buf = (char_u *)" { \"a\" ";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)" { \"a ";
|
reader.js_buf = (char_u *)" { \"a ";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)" { ";
|
reader.js_buf = (char_u *)" { ";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
|
|
||||||
/* array without white space */
|
/* array without white space */
|
||||||
reader.js_buf = (char_u *)"[\"a\",123]";
|
reader.js_buf = (char_u *)"[\"a\",123]";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)"[\"a\",123";
|
reader.js_buf = (char_u *)"[\"a\",123";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"[\"a\",";
|
reader.js_buf = (char_u *)"[\"a\",";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"[\"a\"";
|
reader.js_buf = (char_u *)"[\"a\"";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"[\"a";
|
reader.js_buf = (char_u *)"[\"a";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"[\"";
|
reader.js_buf = (char_u *)"[\"";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)"[";
|
reader.js_buf = (char_u *)"[";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
|
|
||||||
/* array with white space */
|
/* array with white space */
|
||||||
reader.js_buf = (char_u *)" [ \"a\" , 123 ] ";
|
reader.js_buf = (char_u *)" [ \"a\" , 123 ] ";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)" [ \"a\" , 123 ";
|
reader.js_buf = (char_u *)" [ \"a\" , 123 ";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)" [ \"a\" , ";
|
reader.js_buf = (char_u *)" [ \"a\" , ";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)" [ \"a\" ";
|
reader.js_buf = (char_u *)" [ \"a\" ";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)" [ \"a ";
|
reader.js_buf = (char_u *)" [ \"a ";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
reader.js_buf = (char_u *)" [ ";
|
reader.js_buf = (char_u *)" [ ";
|
||||||
assert(json_find_end(&reader) == MAYBE);
|
assert(json_find_end(&reader, 0) == MAYBE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -157,15 +157,15 @@ test_fill_called_on_find_end(void)
|
|||||||
reader.js_used = 0;
|
reader.js_used = 0;
|
||||||
reader.js_buf = (char_u *)" [ \"a\" , 123 ";
|
reader.js_buf = (char_u *)" [ \"a\" , 123 ";
|
||||||
reader.js_cookie = " [ \"a\" , 123 ] ";
|
reader.js_cookie = " [ \"a\" , 123 ] ";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)" [ \"a\" , ";
|
reader.js_buf = (char_u *)" [ \"a\" , ";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)" [ \"a\" ";
|
reader.js_buf = (char_u *)" [ \"a\" ";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)" [ \"a";
|
reader.js_buf = (char_u *)" [ \"a";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
reader.js_buf = (char_u *)" [ ";
|
reader.js_buf = (char_u *)" [ ";
|
||||||
assert(json_find_end(&reader) == OK);
|
assert(json_find_end(&reader, 0) == OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/* channel.c */
|
/* channel.c */
|
||||||
void channel_gui_register_all(void);
|
void channel_gui_register_all(void);
|
||||||
int channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void));
|
int channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void));
|
||||||
void channel_set_json_mode(int idx, int json_mode);
|
void channel_set_json_mode(int idx, ch_mode_T ch_mode);
|
||||||
void channel_set_timeout(int idx, int timeout);
|
void channel_set_timeout(int idx, int timeout);
|
||||||
void channel_set_callback(int idx, char_u *callback);
|
void channel_set_callback(int idx, char_u *callback);
|
||||||
void channel_set_req_callback(int idx, char_u *callback, int id);
|
void channel_set_req_callback(int idx, char_u *callback, int id);
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/* json.c */
|
/* json.c */
|
||||||
char_u *json_encode(typval_T *val);
|
char_u *json_encode(typval_T *val, int options);
|
||||||
char_u *json_encode_nr_expr(int nr, typval_T *val);
|
char_u *json_encode_nr_expr(int nr, typval_T *val, int options);
|
||||||
int json_decode_all(js_read_T *reader, typval_T *res);
|
int json_decode_all(js_read_T *reader, typval_T *res, int options);
|
||||||
int json_decode(js_read_T *reader, typval_T *res);
|
int json_decode(js_read_T *reader, typval_T *res, int options);
|
||||||
int json_find_end(js_read_T *reader);
|
int json_find_end(js_read_T *reader, int options);
|
||||||
/* vim: set ft=c : */
|
/* vim: set ft=c : */
|
||||||
|
@@ -2728,3 +2728,11 @@ struct js_reader
|
|||||||
void *js_cookie; /* can be used by js_fill */
|
void *js_cookie; /* can be used by js_fill */
|
||||||
};
|
};
|
||||||
typedef struct js_reader js_read_T;
|
typedef struct js_reader js_read_T;
|
||||||
|
|
||||||
|
/* mode for a channel */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MODE_RAW = 0,
|
||||||
|
MODE_JSON,
|
||||||
|
MODE_JS
|
||||||
|
} ch_mode_T;
|
||||||
|
@@ -32,9 +32,12 @@ let l3 = [1, 2]
|
|||||||
let s:varl3 = [l3, l3]
|
let s:varl3 = [l3, l3]
|
||||||
|
|
||||||
let s:jsond1 = '{"a":1,"b":"bee","c":[1,2]}'
|
let s:jsond1 = '{"a":1,"b":"bee","c":[1,2]}'
|
||||||
|
let s:jsd1 = '{a:1,b:"bee",c:[1,2]}'
|
||||||
let s:vard1 = {"a": 1, "b": "bee","c": [1,2]}
|
let s:vard1 = {"a": 1, "b": "bee","c": [1,2]}
|
||||||
let s:jsond2 = '{"1":1,"2":{"a":"aa","b":{},"c":"cc"},"3":3}'
|
let s:jsond2 = '{"1":1,"2":{"a":"aa","b":{},"c":"cc"},"3":3}'
|
||||||
|
let s:jsd2 = '{"1":1,"2":{a:"aa",b:{},c:"cc"},"3":3}'
|
||||||
let s:jsond2s = " { \"1\" : 1 , \"2\" :\n{ \"a\"\r: \"aa\" , \"b\" : {\<Tab>} , \"c\" : \"cc\" } , \"3\" : 3 }\r\n"
|
let s:jsond2s = " { \"1\" : 1 , \"2\" :\n{ \"a\"\r: \"aa\" , \"b\" : {\<Tab>} , \"c\" : \"cc\" } , \"3\" : 3 }\r\n"
|
||||||
|
let s:jsd2s = " { \"1\" : 1 , \"2\" :\n{ a\r: \"aa\" , b : {\<Tab>} , c : \"cc\" } , \"3\" : 3 }\r\n"
|
||||||
let s:vard2 = {"1": 1, "2": 2, "3": 3}
|
let s:vard2 = {"1": 1, "2": 2, "3": 3}
|
||||||
let d2 = {"a": "aa", "b": s:vard2, "c": "cc"}
|
let d2 = {"a": "aa", "b": s:vard2, "c": "cc"}
|
||||||
let s:vard2["2"] = d2
|
let s:vard2["2"] = d2
|
||||||
@@ -42,11 +45,16 @@ let s:vard2x = {"1": 1, "2": {"a": "aa", "b": {}, "c": "cc"}, "3": 3}
|
|||||||
let d3 = {"a": 1, "b": 2}
|
let d3 = {"a": 1, "b": 2}
|
||||||
let s:vard3 = {"x": d3, "y": d3}
|
let s:vard3 = {"x": d3, "y": d3}
|
||||||
let s:jsond3 = '{"x":{"a":1,"b":2},"y":{"a":1,"b":2}}'
|
let s:jsond3 = '{"x":{"a":1,"b":2},"y":{"a":1,"b":2}}'
|
||||||
|
let s:jsd3 = '{x:{a:1,b:2},y:{a:1,b:2}}'
|
||||||
|
let s:vard4 = {"key": v:none}
|
||||||
|
let s:vard4x = {"key": v:null}
|
||||||
|
let s:jsond4 = '{"key":null}'
|
||||||
|
let s:jsd4 = '{key:null}'
|
||||||
|
|
||||||
let s:jsonvals = '[true,false,,null]'
|
let s:jsonvals = '[true,false,null,null]'
|
||||||
let s:varvals = [v:true, v:false, v:none, v:null]
|
let s:varvals = [v:true, v:false, v:null, v:null]
|
||||||
|
|
||||||
func Test_encode()
|
func Test_json_encode()
|
||||||
call assert_equal(s:json1, jsonencode(s:var1))
|
call assert_equal(s:json1, jsonencode(s:var1))
|
||||||
call assert_equal(s:json2, jsonencode(s:var2))
|
call assert_equal(s:json2, jsonencode(s:var2))
|
||||||
call assert_equal(s:json3, jsonencode(s:var3))
|
call assert_equal(s:json3, jsonencode(s:var3))
|
||||||
@@ -69,18 +77,18 @@ func Test_encode()
|
|||||||
call assert_equal(s:jsond1, jsonencode(s:vard1))
|
call assert_equal(s:jsond1, jsonencode(s:vard1))
|
||||||
call assert_equal(s:jsond2, jsonencode(s:vard2))
|
call assert_equal(s:jsond2, jsonencode(s:vard2))
|
||||||
call assert_equal(s:jsond3, jsonencode(s:vard3))
|
call assert_equal(s:jsond3, jsonencode(s:vard3))
|
||||||
|
call assert_equal(s:jsond4, jsonencode(s:vard4))
|
||||||
|
|
||||||
call assert_equal(s:jsonvals, jsonencode(s:varvals))
|
call assert_equal(s:jsonvals, jsonencode(s:varvals))
|
||||||
|
|
||||||
call assert_fails('echo jsonencode(function("tr"))', 'E474:')
|
call assert_fails('echo jsonencode(function("tr"))', 'E474:')
|
||||||
call assert_fails('echo jsonencode([function("tr")])', 'E474:')
|
call assert_fails('echo jsonencode([function("tr")])', 'E474:')
|
||||||
call assert_fails('echo jsonencode({"key":v:none})', 'E474:')
|
|
||||||
|
|
||||||
silent! let res = jsonencode(function("tr"))
|
silent! let res = jsonencode(function("tr"))
|
||||||
call assert_equal("", res)
|
call assert_equal("", res)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_decode()
|
func Test_json_decode()
|
||||||
call assert_equal(s:var1, jsondecode(s:json1))
|
call assert_equal(s:var1, jsondecode(s:json1))
|
||||||
call assert_equal(s:var2, jsondecode(s:json2))
|
call assert_equal(s:var2, jsondecode(s:json2))
|
||||||
call assert_equal(s:var3, jsondecode(s:json3))
|
call assert_equal(s:var3, jsondecode(s:json3))
|
||||||
@@ -103,7 +111,9 @@ func Test_decode()
|
|||||||
|
|
||||||
call assert_equal(s:vard1, jsondecode(s:jsond1))
|
call assert_equal(s:vard1, jsondecode(s:jsond1))
|
||||||
call assert_equal(s:vard2x, jsondecode(s:jsond2))
|
call assert_equal(s:vard2x, jsondecode(s:jsond2))
|
||||||
|
call assert_equal(s:vard2x, jsondecode(s:jsond2s))
|
||||||
call assert_equal(s:vard3, jsondecode(s:jsond3))
|
call assert_equal(s:vard3, jsondecode(s:jsond3))
|
||||||
|
call assert_equal(s:vard4x, jsondecode(s:jsond4))
|
||||||
|
|
||||||
call assert_equal(s:varvals, jsondecode(s:jsonvals))
|
call assert_equal(s:varvals, jsondecode(s:jsonvals))
|
||||||
|
|
||||||
@@ -134,4 +144,110 @@ func Test_decode()
|
|||||||
call assert_fails('call jsondecode("[1")', "E474:")
|
call assert_fails('call jsondecode("[1")', "E474:")
|
||||||
call assert_fails('call jsondecode("[1,")', "E474:")
|
call assert_fails('call jsondecode("[1,")', "E474:")
|
||||||
call assert_fails('call jsondecode("[1 2]")', "E474:")
|
call assert_fails('call jsondecode("[1 2]")', "E474:")
|
||||||
|
|
||||||
|
call assert_fails('call jsondecode("[1,,2]")', "E474:")
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
let s:jsl5 = '[7,,,]'
|
||||||
|
let s:varl5 = [7, v:none, v:none]
|
||||||
|
|
||||||
|
func Test_js_encode()
|
||||||
|
call assert_equal(s:json1, jsencode(s:var1))
|
||||||
|
call assert_equal(s:json2, jsencode(s:var2))
|
||||||
|
call assert_equal(s:json3, jsencode(s:var3))
|
||||||
|
call assert_equal(s:json4, jsencode(s:var4))
|
||||||
|
call assert_equal(s:json5, jsencode(s:var5))
|
||||||
|
|
||||||
|
if has('multi_byte')
|
||||||
|
call assert_equal(s:jsonmb, jsencode(s:varmb))
|
||||||
|
endif
|
||||||
|
|
||||||
|
call assert_equal(s:jsonnr, jsencode(s:varnr))
|
||||||
|
if has('float')
|
||||||
|
call assert_equal(s:jsonfl, jsencode(s:varfl))
|
||||||
|
endif
|
||||||
|
|
||||||
|
call assert_equal(s:jsonl1, jsencode(s:varl1))
|
||||||
|
call assert_equal(s:jsonl2, jsencode(s:varl2))
|
||||||
|
call assert_equal(s:jsonl3, jsencode(s:varl3))
|
||||||
|
|
||||||
|
call assert_equal(s:jsd1, jsencode(s:vard1))
|
||||||
|
call assert_equal(s:jsd2, jsencode(s:vard2))
|
||||||
|
call assert_equal(s:jsd3, jsencode(s:vard3))
|
||||||
|
call assert_equal(s:jsd4, jsencode(s:vard4))
|
||||||
|
|
||||||
|
call assert_equal(s:jsonvals, jsencode(s:varvals))
|
||||||
|
|
||||||
|
call assert_fails('echo jsencode(function("tr"))', 'E474:')
|
||||||
|
call assert_fails('echo jsencode([function("tr")])', 'E474:')
|
||||||
|
|
||||||
|
silent! let res = jsencode(function("tr"))
|
||||||
|
call assert_equal("", res)
|
||||||
|
|
||||||
|
call assert_equal(s:jsl5, jsencode(s:varl5))
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_js_decode()
|
||||||
|
call assert_equal(s:var1, jsdecode(s:json1))
|
||||||
|
call assert_equal(s:var2, jsdecode(s:json2))
|
||||||
|
call assert_equal(s:var3, jsdecode(s:json3))
|
||||||
|
call assert_equal(s:var4, jsdecode(s:json4))
|
||||||
|
call assert_equal(s:var5, jsdecode(s:json5))
|
||||||
|
|
||||||
|
if has('multi_byte')
|
||||||
|
call assert_equal(s:varmb, jsdecode(s:jsonmb))
|
||||||
|
endif
|
||||||
|
|
||||||
|
call assert_equal(s:varnr, jsdecode(s:jsonnr))
|
||||||
|
if has('float')
|
||||||
|
call assert_equal(s:varfl, jsdecode(s:jsonfl))
|
||||||
|
endif
|
||||||
|
|
||||||
|
call assert_equal(s:varl1, jsdecode(s:jsonl1))
|
||||||
|
call assert_equal(s:varl2x, jsdecode(s:jsonl2))
|
||||||
|
call assert_equal(s:varl2x, jsdecode(s:jsonl2s))
|
||||||
|
call assert_equal(s:varl3, jsdecode(s:jsonl3))
|
||||||
|
|
||||||
|
call assert_equal(s:vard1, jsdecode(s:jsond1))
|
||||||
|
call assert_equal(s:vard1, jsdecode(s:jsd1))
|
||||||
|
call assert_equal(s:vard2x, jsdecode(s:jsond2))
|
||||||
|
call assert_equal(s:vard2x, jsdecode(s:jsd2))
|
||||||
|
call assert_equal(s:vard2x, jsdecode(s:jsond2s))
|
||||||
|
call assert_equal(s:vard2x, jsdecode(s:jsd2s))
|
||||||
|
call assert_equal(s:vard3, jsdecode(s:jsond3))
|
||||||
|
call assert_equal(s:vard3, jsdecode(s:jsd3))
|
||||||
|
call assert_equal(s:vard4x, jsdecode(s:jsond4))
|
||||||
|
call assert_equal(s:vard4x, jsdecode(s:jsd4))
|
||||||
|
|
||||||
|
call assert_equal(s:varvals, jsdecode(s:jsonvals))
|
||||||
|
|
||||||
|
call assert_equal(v:true, jsdecode('true'))
|
||||||
|
call assert_equal(type(v:true), type(jsdecode('true')))
|
||||||
|
call assert_equal(v:none, jsdecode(''))
|
||||||
|
call assert_equal(type(v:none), type(jsdecode('')))
|
||||||
|
call assert_equal("", jsdecode('""'))
|
||||||
|
|
||||||
|
call assert_equal({'n': 1}, jsdecode('{"n":1,}'))
|
||||||
|
|
||||||
|
call assert_fails('call jsdecode("\"")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("blah")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("true blah")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("<foobar>")', "E474:")
|
||||||
|
|
||||||
|
call assert_fails('call jsdecode("{")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("{foobar}")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("{\"n\",")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("{\"n\":")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("{\"n\":1")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("{\"n\":1,")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("{\"n\",1}")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("{-}")', "E474:")
|
||||||
|
|
||||||
|
call assert_fails('call jsdecode("[foobar]")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("[")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("[1")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("[1,")', "E474:")
|
||||||
|
call assert_fails('call jsdecode("[1 2]")', "E474:")
|
||||||
|
|
||||||
|
call assert_equal(s:varl5, jsdecode(s:jsl5))
|
||||||
endfunc
|
endfunc
|
||||||
|
@@ -747,6 +747,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1279,
|
||||||
/**/
|
/**/
|
||||||
1278,
|
1278,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -2317,6 +2317,10 @@ typedef int sock_T;
|
|||||||
# define MAX_OPEN_CHANNELS 0
|
# define MAX_OPEN_CHANNELS 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Options for json_encode() and json_decode. */
|
||||||
|
#define JSON_JS 1 /* use JS instead of JSON */
|
||||||
|
#define JSON_NO_NONE 2 /* v:none item not allowed */
|
||||||
|
|
||||||
#ifdef FEAT_MZSCHEME
|
#ifdef FEAT_MZSCHEME
|
||||||
/* this is in main.c, cproto can't handle it. */
|
/* this is in main.c, cproto can't handle it. */
|
||||||
int vim_main2(int argc, char **argv);
|
int vim_main2(int argc, char **argv);
|
||||||
|
Reference in New Issue
Block a user