mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
Merge remote-tracking branch 'vim/master'
This commit is contained in:
@@ -41,6 +41,7 @@ SRC_ALL = \
|
||||
src/hardcopy.c \
|
||||
src/hashtab.c \
|
||||
src/json.c \
|
||||
src/json_test.c \
|
||||
src/keymap.h \
|
||||
src/macros.h \
|
||||
src/main.c \
|
||||
|
||||
+29
-25
@@ -1,4 +1,4 @@
|
||||
*eval.txt* For Vim version 7.4. Last change: 2016 Feb 01
|
||||
*eval.txt* For Vim version 7.4. Last change: 2016 Feb 02
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -1810,6 +1810,13 @@ byteidxcomp( {expr}, {nr}) Number byte index of {nr}'th char in {expr}
|
||||
call( {func}, {arglist} [, {dict}])
|
||||
any call {func} with arguments {arglist}
|
||||
ceil( {expr}) Float round {expr} up
|
||||
ch_close( {handle}) none close a channel
|
||||
ch_open( {address}, {mode} [, {callback}])
|
||||
Number open a channel
|
||||
ch_sendexpr( {handle}, {expr} [, {callback}])
|
||||
any send {expr} over JSON channel {handle}
|
||||
ch_sendraw( {handle}, {string} [, {callback}])
|
||||
any send {string} over raw channel {handle}
|
||||
changenr() Number current change number
|
||||
char2nr( {expr}[, {utf8}]) Number ASCII/UTF8 value of first char in {expr}
|
||||
cindent( {lnum}) Number C indent for line {lnum}
|
||||
@@ -1820,8 +1827,6 @@ complete_add( {expr}) Number add completion match
|
||||
complete_check() Number check for key typed during completion
|
||||
confirm( {msg} [, {choices} [, {default} [, {type}]]])
|
||||
Number number of choice picked by user
|
||||
connect( {address}, {mode} [, {callback}])
|
||||
Number open a channel
|
||||
copy( {expr}) any make a shallow copy of {expr}
|
||||
cos( {expr}) Float cosine of {expr}
|
||||
cosh( {expr}) Float hyperbolic cosine of {expr}
|
||||
@@ -2029,10 +2034,6 @@ searchpairpos( {start}, {middle}, {end} [, {flags} [, {skip} [...]]])
|
||||
List search for other end of start/end pair
|
||||
searchpos( {pattern} [, {flags} [, {stopline} [, {timeout}]]])
|
||||
List search for {pattern}
|
||||
sendexpr( {handle}, {expr} [, {callback}])
|
||||
any send {expr} over JSON channel {handle}
|
||||
sendraw( {handle}, {string} [, {callback}])
|
||||
any send {string} over raw channel {handle}
|
||||
server2client( {clientid}, {string})
|
||||
Number send reply string
|
||||
serverlist() String get a list of available servers
|
||||
@@ -2666,7 +2667,10 @@ confirm({msg} [, {choices} [, {default} [, {type}]]])
|
||||
don't fit, a vertical layout is used anyway. For some systems
|
||||
the horizontal layout is always used.
|
||||
|
||||
connect({address}, {mode} [, {callback}]) *connect()*
|
||||
ch_close({handle}) *ch_close()*
|
||||
Close channel {handle}. See |channel|.
|
||||
|
||||
ch_open({address}, {mode} [, {callback}]) *ch_open()*
|
||||
Open a channel to {address}. See |channel|.
|
||||
Returns the channel handle on success. Returns a negative
|
||||
number for failure.
|
||||
@@ -2680,6 +2684,23 @@ connect({address}, {mode} [, {callback}]) *connect()*
|
||||
{callback} is a function that handles received messages on the
|
||||
channel. See |channel-callback|.
|
||||
|
||||
ch_sendexpr({handle}, {expr} [, {callback}]) ch_*sendexpr()*
|
||||
Send {expr} over JSON channel {handle}. See |channel-use|.
|
||||
|
||||
When {callback} is given returns immediately. Without
|
||||
{callback} waits for a JSON response and returns the decoded
|
||||
expression. When there is an error or timeout returns an
|
||||
empty string.
|
||||
|
||||
When {callback} is zero no response is expected.
|
||||
Otherwise {callback} must be a Funcref or the name of a
|
||||
function. It is called when the response is received. See
|
||||
|channel-callback|.
|
||||
|
||||
ch_sendraw({handle}, {string} [, {callback}]) *ch_sendraw()*
|
||||
Send {string} over raw channel {handle}. See |channel-raw|.
|
||||
Works like |ch_sendexpr()|, but does not decode the response.
|
||||
|
||||
*copy()*
|
||||
copy({expr}) Make a copy of {expr}. For Numbers and Strings this isn't
|
||||
different from using {expr} directly.
|
||||
@@ -5615,23 +5636,6 @@ searchpos({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *searchpos()*
|
||||
< In this example "submatch" is 2 when a lowercase letter is
|
||||
found |/\l|, 3 when an uppercase letter is found |/\u|.
|
||||
|
||||
sendexpr({handle}, {expr} [, {callback}]) *sendexpr()*
|
||||
Send {expr} over JSON channel {handle}. See |channel-use|.
|
||||
|
||||
When {callback} is given returns immediately. Without
|
||||
{callback} waits for a JSON response and returns the decoded
|
||||
expression. When there is an error or timeout returns an
|
||||
empty string.
|
||||
|
||||
When {callback} is zero no response is expected.
|
||||
Otherwise {callback} must be a Funcref or the name of a
|
||||
function. It is called when the response is received. See
|
||||
|channel-callback|.
|
||||
|
||||
sendraw({handle}, {string} [, {callback}]) *sendraw()*
|
||||
Send {string} over raw channel {handle}. See |channel-raw|.
|
||||
Works like |sendexpr()|, but does not decode the response.
|
||||
|
||||
server2client( {clientid}, {string}) *server2client()*
|
||||
Send a reply string to {clientid}. The most recent {clientid}
|
||||
that sent a string can be retrieved with expand("<client>").
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Server that will accept connections from a Vim channel.
|
||||
# Run this server and then in Vim you can open the channel:
|
||||
# :let handle = connect('localhost:8765', 'json')
|
||||
# :let handle = ch_open('localhost:8765', 'json')
|
||||
#
|
||||
# Then Vim can send requests to the server:
|
||||
# :let response = sendexpr(handle, 'hello!')
|
||||
# :let response = ch_sendexpr(handle, 'hello!')
|
||||
#
|
||||
# And you can control Vim by typing a JSON message here, e.g.:
|
||||
# ["ex","echo 'hi there'"]
|
||||
#
|
||||
# There is no prompt, just type a line and press Enter.
|
||||
# To exit cleanly type "quit<Enter>".
|
||||
#
|
||||
# See ":help channel-demo" in Vim.
|
||||
#
|
||||
# This requires Python 2.6 or later.
|
||||
|
||||
from __future__ import print_function
|
||||
import json
|
||||
|
||||
@@ -52,7 +52,7 @@ gvimext.obj: gvimext.h
|
||||
$(cc) $(cflags) -DFEAT_GETTEXT $(cvarsmt) $*.cpp
|
||||
|
||||
gvimext.res: gvimext.rc
|
||||
$(rc) $(rcflags) $(rcvars) gvimext.rc
|
||||
$(rc) /nologo $(rcflags) $(rcvars) gvimext.rc
|
||||
|
||||
clean:
|
||||
- if exist gvimext.dll del gvimext.dll
|
||||
|
||||
+1
-1
@@ -1294,7 +1294,7 @@ $(OUTDIR)/xpm_w32.obj: $(OUTDIR) xpm_w32.c
|
||||
$(OUTDIR)/vim.res: $(OUTDIR) vim.rc gvim.exe.mnf version.h tools.bmp \
|
||||
tearoff.bmp vim.ico vim_error.ico \
|
||||
vim_alert.ico vim_info.ico vim_quest.ico
|
||||
$(RC) /l 0x409 /Fo$(OUTDIR)/vim.res $(RCFLAGS) vim.rc
|
||||
$(RC) /nologo /l 0x409 /Fo$(OUTDIR)/vim.res $(RCFLAGS) vim.rc
|
||||
|
||||
iid_ole.c if_ole.h vim.tlb: if_ole.idl
|
||||
midl /nologo /error none /proxy nul /iid iid_ole.c /tlb vim.tlb \
|
||||
|
||||
+33
-5
@@ -1562,11 +1562,13 @@ EXTRA_SRC = hangulin.c if_lua.c if_mzsch.c auto/if_perl.c if_perlsfio.c \
|
||||
$(GRESOURCE_SRC)
|
||||
|
||||
# Unittest files
|
||||
JSON_TEST_SRC = json_test.c
|
||||
JSON_TEST_TARGET = json_test$(EXEEXT)
|
||||
MEMFILE_TEST_SRC = memfile_test.c
|
||||
MEMFILE_TEST_TARGET = memfile_test$(EXEEXT)
|
||||
|
||||
UNITTEST_SRC = $(MEMFILE_TEST_SRC)
|
||||
UNITTEST_TARGETS = $(MEMFILE_TEST_TARGET)
|
||||
UNITTEST_SRC = $(JSON_TEST_SRC) $(MEMFILE_TEST_SRC)
|
||||
UNITTEST_TARGETS = $(JSON_TEST_TARGET) $(MEMFILE_TEST_TARGET)
|
||||
|
||||
# All sources, also the ones that are not configured
|
||||
ALL_SRC = $(BASIC_SRC) $(ALL_GUI_SRC) $(UNITTEST_SRC) $(EXTRA_SRC)
|
||||
@@ -1605,9 +1607,8 @@ OBJ_COMMON = \
|
||||
$(HANGULIN_OBJ) \
|
||||
objects/if_cscope.o \
|
||||
objects/if_xcmdsrv.o \
|
||||
objects/json.o \
|
||||
objects/mark.o \
|
||||
objects/memline.o \
|
||||
objects/memline.o \
|
||||
objects/menu.o \
|
||||
objects/message.o \
|
||||
objects/misc1.o \
|
||||
@@ -1649,11 +1650,17 @@ OBJ_COMMON = \
|
||||
$(WSDEBUG_OBJ)
|
||||
|
||||
OBJ = $(OBJ_COMMON) \
|
||||
objects/json.o \
|
||||
objects/main.o \
|
||||
objects/memfile.o
|
||||
|
||||
JSON_TEST_OBJ = $(OBJ_COMMON) \
|
||||
objects/json_test.o \
|
||||
objects/memfile.o
|
||||
|
||||
MEMFILE_TEST_OBJ = $(OBJ_COMMON) \
|
||||
objects/memfile_test.o
|
||||
objects/json.o \
|
||||
objects/memfile_test.o
|
||||
|
||||
PRO_AUTO = \
|
||||
blowfish.pro \
|
||||
@@ -1931,6 +1938,7 @@ types.vim: $(TAGS_SRC) $(TAGS_INCL)
|
||||
ctags --c-kinds=gstu -o- $(TAGS_SRC) $(TAGS_INCL) |\
|
||||
awk 'BEGIN{printf("syntax keyword Type\t")}\
|
||||
{printf("%s ", $$1)}END{print ""}' > $@
|
||||
echo "syn keyword Constant OK FAIL TRUE FALSE MAYBE" >> $@
|
||||
|
||||
# Execute the test scripts. Run these after compiling Vim, before installing.
|
||||
# This doesn't depend on $(VIMTARGET), because that won't work when configure
|
||||
@@ -1965,6 +1973,12 @@ unittest unittests: $(UNITTEST_TARGETS)
|
||||
./$$t || exit 1; echo $$t passed; \
|
||||
done
|
||||
|
||||
run_json_test: $(JSON_TEST_TARGET)
|
||||
./$(JSON_TEST_TARGET)
|
||||
|
||||
run_memfile_test: $(MEMFILE_TEST_TARGET)
|
||||
./$(MEMFILE_TEST_TARGET)
|
||||
|
||||
# Run individual OLD style test, assuming that Vim was already compiled.
|
||||
test1 \
|
||||
test_autocmd_option \
|
||||
@@ -2057,6 +2071,13 @@ testclean:
|
||||
|
||||
# Unittests
|
||||
# It's build just like Vim to satisfy all dependencies.
|
||||
$(JSON_TEST_TARGET): auto/config.mk objects $(JSON_TEST_OBJ)
|
||||
$(CCC) version.c -o objects/version.o
|
||||
@LINK="$(PURIFY) $(SHRPENV) $(CClink) $(ALL_LIB_DIRS) $(LDFLAGS) \
|
||||
-o $(JSON_TEST_TARGET) $(JSON_TEST_OBJ) $(ALL_LIBS)" \
|
||||
MAKE="$(MAKE)" LINK_AS_NEEDED=$(LINK_AS_NEEDED) \
|
||||
sh $(srcdir)/link.sh
|
||||
|
||||
$(MEMFILE_TEST_TARGET): auto/config.mk objects $(MEMFILE_TEST_OBJ)
|
||||
$(CCC) version.c -o objects/version.o
|
||||
@LINK="$(PURIFY) $(SHRPENV) $(CClink) $(ALL_LIB_DIRS) $(LDFLAGS) \
|
||||
@@ -2837,6 +2858,9 @@ objects/integration.o: integration.c
|
||||
objects/json.o: json.c
|
||||
$(CCC) -o $@ json.c
|
||||
|
||||
objects/json_test.o: json_test.c
|
||||
$(CCC) -o $@ json_test.c
|
||||
|
||||
objects/main.o: main.c
|
||||
$(CCC) -o $@ main.c
|
||||
|
||||
@@ -3360,6 +3384,10 @@ objects/gui_at_fs.o: gui_at_fs.c vim.h auto/config.h feature.h os_unix.h \
|
||||
objects/pty.o: pty.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h ascii.h \
|
||||
keymap.h term.h macros.h option.h structs.h regexp.h gui.h gui_beval.h \
|
||||
proto/gui_beval.pro alloc.h ex_cmds.h proto.h globals.h farsi.h arabic.h
|
||||
objects/json_test.o: json_test.c main.c vim.h auto/config.h feature.h os_unix.h \
|
||||
auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
|
||||
regexp.h gui.h gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h proto.h \
|
||||
globals.h farsi.h arabic.h farsi.c arabic.c json.c
|
||||
objects/memfile_test.o: memfile_test.c main.c vim.h auto/config.h feature.h \
|
||||
os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h \
|
||||
structs.h regexp.h gui.h gui_beval.h proto/gui_beval.pro alloc.h \
|
||||
|
||||
+21
-11
@@ -565,9 +565,8 @@ channel_read_json(int ch_idx)
|
||||
/* TODO: make reader work properly */
|
||||
/* reader.js_buf = channel_peek(ch_idx); */
|
||||
reader.js_buf = channel_get_all(ch_idx);
|
||||
reader.js_eof = TRUE;
|
||||
/* reader.js_eof = FALSE; */
|
||||
reader.js_used = 0;
|
||||
reader.js_fill = NULL;
|
||||
/* reader.js_fill = channel_fill; */
|
||||
reader.js_cookie = &ch_idx;
|
||||
if (json_decode(&reader, &listtv) == OK)
|
||||
@@ -593,6 +592,13 @@ channel_read_json(int ch_idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Put the unread part back into the channel.
|
||||
* TODO: insert in front */
|
||||
if (reader.js_buf[reader.js_used] != NUL)
|
||||
channel_save(ch_idx, reader.js_buf + reader.js_used,
|
||||
(int)(reader.js_end - reader.js_buf) - reader.js_used);
|
||||
vim_free(reader.js_buf);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -723,8 +729,9 @@ channel_exe_cmd(int idx, char_u *cmd, typval_T *arg2, typval_T *arg3)
|
||||
|
||||
/*
|
||||
* Invoke a callback for channel "idx" if needed.
|
||||
* Return OK when a message was handled, there might be another one.
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
may_invoke_callback(int idx)
|
||||
{
|
||||
char_u *msg = NULL;
|
||||
@@ -736,22 +743,22 @@ may_invoke_callback(int idx)
|
||||
int json_mode = channels[idx].ch_json_mode;
|
||||
|
||||
if (channel_peek(idx) == NULL)
|
||||
return;
|
||||
return FALSE;
|
||||
if (channels[idx].ch_close_cb != NULL)
|
||||
/* this channel is handled elsewhere (netbeans) */
|
||||
return;
|
||||
return FALSE;
|
||||
|
||||
if (json_mode)
|
||||
{
|
||||
/* Get any json message. Return if there isn't one. */
|
||||
channel_read_json(idx);
|
||||
if (channel_get_json(idx, -1, &listtv) == FAIL)
|
||||
return;
|
||||
return FALSE;
|
||||
if (listtv->v_type != VAR_LIST)
|
||||
{
|
||||
/* TODO: give error */
|
||||
clear_tv(listtv);
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
list = listtv->vval.v_list;
|
||||
@@ -759,7 +766,7 @@ may_invoke_callback(int idx)
|
||||
{
|
||||
/* TODO: give error */
|
||||
clear_tv(listtv);
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
argv[1] = list->lv_first->li_next->li_tv;
|
||||
@@ -774,14 +781,14 @@ may_invoke_callback(int idx)
|
||||
arg3 = &list->lv_last->li_tv;
|
||||
channel_exe_cmd(idx, cmd, &argv[1], arg3);
|
||||
clear_tv(listtv);
|
||||
return;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (typetv->v_type != VAR_NUMBER)
|
||||
{
|
||||
/* TODO: give error */
|
||||
clear_tv(listtv);
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
seq_nr = typetv->vval.v_number;
|
||||
}
|
||||
@@ -811,6 +818,8 @@ may_invoke_callback(int idx)
|
||||
if (listtv != NULL)
|
||||
clear_tv(listtv);
|
||||
vim_free(msg);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1270,7 +1279,8 @@ channel_parse_messages(void)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < channel_count; ++i)
|
||||
may_invoke_callback(i);
|
||||
while (may_invoke_callback(i) == OK)
|
||||
;
|
||||
}
|
||||
|
||||
#endif /* FEAT_CHANNEL */
|
||||
|
||||
+221
-234
@@ -499,6 +499,12 @@ static void f_call(typval_T *argvars, typval_T *rettv);
|
||||
#ifdef FEAT_FLOAT
|
||||
static void f_ceil(typval_T *argvars, typval_T *rettv);
|
||||
#endif
|
||||
#ifdef FEAT_CHANNEL
|
||||
static void f_ch_open(typval_T *argvars, typval_T *rettv);
|
||||
static void f_ch_close(typval_T *argvars, typval_T *rettv);
|
||||
static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
|
||||
static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
|
||||
#endif
|
||||
static void f_changenr(typval_T *argvars, typval_T *rettv);
|
||||
static void f_char2nr(typval_T *argvars, typval_T *rettv);
|
||||
static void f_cindent(typval_T *argvars, typval_T *rettv);
|
||||
@@ -515,9 +521,6 @@ static void f_copy(typval_T *argvars, typval_T *rettv);
|
||||
static void f_cos(typval_T *argvars, typval_T *rettv);
|
||||
static void f_cosh(typval_T *argvars, typval_T *rettv);
|
||||
#endif
|
||||
#ifdef FEAT_CHANNEL
|
||||
static void f_connect(typval_T *argvars, typval_T *rettv);
|
||||
#endif
|
||||
static void f_count(typval_T *argvars, typval_T *rettv);
|
||||
static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
|
||||
static void f_cursor(typval_T *argsvars, typval_T *rettv);
|
||||
@@ -526,9 +529,6 @@ static void f_delete(typval_T *argvars, typval_T *rettv);
|
||||
static void f_did_filetype(typval_T *argvars, typval_T *rettv);
|
||||
static void f_diff_filler(typval_T *argvars, typval_T *rettv);
|
||||
static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
|
||||
#ifdef FEAT_CHANNEL
|
||||
static void f_disconnect(typval_T *argvars, typval_T *rettv);
|
||||
#endif
|
||||
static void f_empty(typval_T *argvars, typval_T *rettv);
|
||||
static void f_escape(typval_T *argvars, typval_T *rettv);
|
||||
static void f_eval(typval_T *argvars, typval_T *rettv);
|
||||
@@ -703,10 +703,6 @@ static void f_searchdecl(typval_T *argvars, typval_T *rettv);
|
||||
static void f_searchpair(typval_T *argvars, typval_T *rettv);
|
||||
static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
|
||||
static void f_searchpos(typval_T *argvars, typval_T *rettv);
|
||||
#ifdef FEAT_CHANNEL
|
||||
static void f_sendexpr(typval_T *argvars, typval_T *rettv);
|
||||
static void f_sendraw(typval_T *argvars, typval_T *rettv);
|
||||
#endif
|
||||
static void f_server2client(typval_T *argvars, typval_T *rettv);
|
||||
static void f_serverlist(typval_T *argvars, typval_T *rettv);
|
||||
static void f_setbufvar(typval_T *argvars, typval_T *rettv);
|
||||
@@ -8002,6 +7998,12 @@ static struct fst
|
||||
{"call", 2, 3, f_call},
|
||||
#ifdef FEAT_FLOAT
|
||||
{"ceil", 1, 1, f_ceil},
|
||||
#endif
|
||||
#ifdef FEAT_CHANNEL
|
||||
{"ch_close", 1, 1, f_ch_close},
|
||||
{"ch_open", 2, 3, f_ch_open},
|
||||
{"ch_sendexpr", 2, 3, f_ch_sendexpr},
|
||||
{"ch_sendraw", 2, 3, f_ch_sendraw},
|
||||
#endif
|
||||
{"changenr", 0, 0, f_changenr},
|
||||
{"char2nr", 1, 2, f_char2nr},
|
||||
@@ -8014,9 +8016,6 @@ static struct fst
|
||||
{"complete_check", 0, 0, f_complete_check},
|
||||
#endif
|
||||
{"confirm", 1, 4, f_confirm},
|
||||
#ifdef FEAT_CHANNEL
|
||||
{"connect", 2, 3, f_connect},
|
||||
#endif
|
||||
{"copy", 1, 1, f_copy},
|
||||
#ifdef FEAT_FLOAT
|
||||
{"cos", 1, 1, f_cos},
|
||||
@@ -8030,9 +8029,6 @@ static struct fst
|
||||
{"did_filetype", 0, 0, f_did_filetype},
|
||||
{"diff_filler", 1, 1, f_diff_filler},
|
||||
{"diff_hlID", 2, 2, f_diff_hlID},
|
||||
#ifdef FEAT_CHANNEL
|
||||
{"disconnect", 1, 1, f_disconnect},
|
||||
#endif
|
||||
{"empty", 1, 1, f_empty},
|
||||
{"escape", 2, 2, f_escape},
|
||||
{"eval", 1, 1, f_eval},
|
||||
@@ -8211,10 +8207,6 @@ static struct fst
|
||||
{"searchpair", 3, 7, f_searchpair},
|
||||
{"searchpairpos", 3, 7, f_searchpairpos},
|
||||
{"searchpos", 1, 4, f_searchpos},
|
||||
#ifdef FEAT_CHANNEL
|
||||
{"sendexpr", 2, 3, f_sendexpr},
|
||||
{"sendraw", 2, 3, f_sendraw},
|
||||
#endif
|
||||
{"server2client", 2, 2, f_server2client},
|
||||
{"serverlist", 0, 0, f_serverlist},
|
||||
{"setbufvar", 3, 3, f_setbufvar},
|
||||
@@ -9685,6 +9677,213 @@ f_ceil(typval_T *argvars, typval_T *rettv)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_CHANNEL
|
||||
/*
|
||||
* Get the channel index from the handle argument.
|
||||
* Returns -1 if the handle is invalid or the channel is closed.
|
||||
*/
|
||||
static int
|
||||
get_channel_arg(typval_T *tv)
|
||||
{
|
||||
int ch_idx;
|
||||
|
||||
if (tv->v_type != VAR_NUMBER)
|
||||
{
|
||||
EMSG2(_(e_invarg2), get_tv_string(tv));
|
||||
return -1;
|
||||
}
|
||||
ch_idx = tv->vval.v_number;
|
||||
|
||||
if (!channel_is_open(ch_idx))
|
||||
{
|
||||
EMSGN(_("E906: not an open channel"), ch_idx);
|
||||
return -1;
|
||||
}
|
||||
return ch_idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* "ch_close()" function
|
||||
*/
|
||||
static void
|
||||
f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
{
|
||||
int ch_idx = get_channel_arg(&argvars[0]);
|
||||
|
||||
if (ch_idx >= 0)
|
||||
channel_close(ch_idx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a callback from "arg". It can be a Funcref or a function name.
|
||||
* When "arg" is zero return an empty string.
|
||||
* Return NULL for an invalid argument.
|
||||
*/
|
||||
static char_u *
|
||||
get_callback(typval_T *arg)
|
||||
{
|
||||
if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
|
||||
return arg->vval.v_string;
|
||||
if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
|
||||
return (char_u *)"";
|
||||
EMSG(_("E999: Invalid callback argument"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* "ch_open()" function
|
||||
*/
|
||||
static void
|
||||
f_ch_open(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
char_u *address;
|
||||
char_u *mode;
|
||||
char_u *callback = NULL;
|
||||
char_u buf1[NUMBUFLEN];
|
||||
char_u *p;
|
||||
int port;
|
||||
int json_mode = FALSE;
|
||||
|
||||
/* default: fail */
|
||||
rettv->vval.v_number = -1;
|
||||
|
||||
address = get_tv_string(&argvars[0]);
|
||||
mode = get_tv_string_buf(&argvars[1], buf1);
|
||||
if (argvars[2].v_type != VAR_UNKNOWN)
|
||||
{
|
||||
callback = get_callback(&argvars[2]);
|
||||
if (callback == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse address */
|
||||
p = vim_strchr(address, ':');
|
||||
if (p == NULL)
|
||||
{
|
||||
EMSG2(_(e_invarg2), address);
|
||||
return;
|
||||
}
|
||||
*p++ = NUL;
|
||||
port = atoi((char *)p);
|
||||
if (*address == NUL || port <= 0)
|
||||
{
|
||||
p[-1] = ':';
|
||||
EMSG2(_(e_invarg2), address);
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse mode */
|
||||
if (STRCMP(mode, "json") == 0)
|
||||
json_mode = TRUE;
|
||||
else if (STRCMP(mode, "raw") != 0)
|
||||
{
|
||||
EMSG2(_(e_invarg2), mode);
|
||||
return;
|
||||
}
|
||||
|
||||
rettv->vval.v_number = channel_open((char *)address, port, NULL);
|
||||
if (rettv->vval.v_number >= 0)
|
||||
{
|
||||
channel_set_json_mode(rettv->vval.v_number, json_mode);
|
||||
if (callback != NULL && *callback != NUL)
|
||||
channel_set_callback(rettv->vval.v_number, callback);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* common for "sendexpr()" and "sendraw()"
|
||||
* Returns the channel index if the caller should read the response.
|
||||
* Otherwise returns -1.
|
||||
*/
|
||||
static int
|
||||
send_common(typval_T *argvars, char_u *text, char *fun)
|
||||
{
|
||||
int ch_idx;
|
||||
char_u *callback = NULL;
|
||||
|
||||
ch_idx = get_channel_arg(&argvars[0]);
|
||||
if (ch_idx < 0)
|
||||
return -1;
|
||||
|
||||
if (argvars[2].v_type != VAR_UNKNOWN)
|
||||
{
|
||||
callback = get_callback(&argvars[2]);
|
||||
if (callback == NULL)
|
||||
return -1;
|
||||
}
|
||||
/* Set the callback or clear it. An empty callback means no callback and
|
||||
* not reading the response. */
|
||||
channel_set_req_callback(ch_idx,
|
||||
callback != NULL && *callback == NUL ? NULL : callback);
|
||||
|
||||
if (channel_send(ch_idx, text, fun) == OK && callback == NULL)
|
||||
return ch_idx;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* "ch_sendexpr()" function
|
||||
*/
|
||||
static void
|
||||
f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
char_u *text;
|
||||
typval_T *listtv;
|
||||
int ch_idx;
|
||||
int id;
|
||||
|
||||
/* return an empty string by default */
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = NULL;
|
||||
|
||||
id = channel_get_id();
|
||||
text = json_encode_nr_expr(id, &argvars[1]);
|
||||
if (text == NULL)
|
||||
return;
|
||||
|
||||
ch_idx = send_common(argvars, text, "sendexpr");
|
||||
if (ch_idx >= 0)
|
||||
{
|
||||
if (channel_read_json_block(ch_idx, id, &listtv) == OK)
|
||||
{
|
||||
if (listtv->v_type == VAR_LIST)
|
||||
{
|
||||
list_T *list = listtv->vval.v_list;
|
||||
|
||||
if (list->lv_len == 2)
|
||||
{
|
||||
/* Move the item from the list and then change the type to
|
||||
* avoid the value being freed. */
|
||||
*rettv = list->lv_last->li_tv;
|
||||
list->lv_last->li_tv.v_type = VAR_NUMBER;
|
||||
}
|
||||
}
|
||||
clear_tv(listtv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* "ch_sendraw()" function
|
||||
*/
|
||||
static void
|
||||
f_ch_sendraw(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
char_u buf[NUMBUFLEN];
|
||||
char_u *text;
|
||||
int ch_idx;
|
||||
|
||||
/* return an empty string by default */
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = NULL;
|
||||
|
||||
text = get_tv_string_buf(&argvars[1], buf);
|
||||
ch_idx = send_common(argvars, text, "sendraw");
|
||||
if (ch_idx >= 0)
|
||||
rettv->vval.v_string = channel_read_block(ch_idx);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* "changenr()" function
|
||||
*/
|
||||
@@ -10033,84 +10232,6 @@ f_count(typval_T *argvars, typval_T *rettv)
|
||||
rettv->vval.v_number = n;
|
||||
}
|
||||
|
||||
#ifdef FEAT_CHANNEL
|
||||
/*
|
||||
* Get a callback from "arg". It can be a Funcref or a function name.
|
||||
* When "arg" is zero return an empty string.
|
||||
* Return NULL for an invalid argument.
|
||||
*/
|
||||
static char_u *
|
||||
get_callback(typval_T *arg)
|
||||
{
|
||||
if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
|
||||
return arg->vval.v_string;
|
||||
if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
|
||||
return (char_u *)"";
|
||||
EMSG(_("E999: Invalid callback argument"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* "connect()" function
|
||||
*/
|
||||
static void
|
||||
f_connect(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
char_u *address;
|
||||
char_u *mode;
|
||||
char_u *callback = NULL;
|
||||
char_u buf1[NUMBUFLEN];
|
||||
char_u *p;
|
||||
int port;
|
||||
int json_mode = FALSE;
|
||||
|
||||
/* default: fail */
|
||||
rettv->vval.v_number = -1;
|
||||
|
||||
address = get_tv_string(&argvars[0]);
|
||||
mode = get_tv_string_buf(&argvars[1], buf1);
|
||||
if (argvars[2].v_type != VAR_UNKNOWN)
|
||||
{
|
||||
callback = get_callback(&argvars[2]);
|
||||
if (callback == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse address */
|
||||
p = vim_strchr(address, ':');
|
||||
if (p == NULL)
|
||||
{
|
||||
EMSG2(_(e_invarg2), address);
|
||||
return;
|
||||
}
|
||||
*p++ = NUL;
|
||||
port = atoi((char *)p);
|
||||
if (*address == NUL || port <= 0)
|
||||
{
|
||||
p[-1] = ':';
|
||||
EMSG2(_(e_invarg2), address);
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse mode */
|
||||
if (STRCMP(mode, "json") == 0)
|
||||
json_mode = TRUE;
|
||||
else if (STRCMP(mode, "raw") != 0)
|
||||
{
|
||||
EMSG2(_(e_invarg2), mode);
|
||||
return;
|
||||
}
|
||||
|
||||
rettv->vval.v_number = channel_open((char *)address, port, NULL);
|
||||
if (rettv->vval.v_number >= 0)
|
||||
{
|
||||
channel_set_json_mode(rettv->vval.v_number, json_mode);
|
||||
if (callback != NULL && *callback != NUL)
|
||||
channel_set_callback(rettv->vval.v_number, callback);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
|
||||
*
|
||||
@@ -10349,44 +10470,6 @@ f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef FEAT_CHANNEL
|
||||
/*
|
||||
* Get the channel index from the handle argument.
|
||||
* Returns -1 if the handle is invalid or the channel is closed.
|
||||
*/
|
||||
static int
|
||||
get_channel_arg(typval_T *tv)
|
||||
{
|
||||
int ch_idx;
|
||||
|
||||
if (tv->v_type != VAR_NUMBER)
|
||||
{
|
||||
EMSG2(_(e_invarg2), get_tv_string(tv));
|
||||
return -1;
|
||||
}
|
||||
ch_idx = tv->vval.v_number;
|
||||
|
||||
if (!channel_is_open(ch_idx))
|
||||
{
|
||||
EMSGN(_("E906: not an open channel"), ch_idx);
|
||||
return -1;
|
||||
}
|
||||
return ch_idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* "disconnect()" function
|
||||
*/
|
||||
static void
|
||||
f_disconnect(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
{
|
||||
int ch_idx = get_channel_arg(&argvars[0]);
|
||||
|
||||
if (ch_idx >= 0)
|
||||
channel_close(ch_idx);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* "empty({expr})" function
|
||||
*/
|
||||
@@ -14119,9 +14202,9 @@ f_jsondecode(typval_T *argvars, typval_T *rettv)
|
||||
js_read_T reader;
|
||||
|
||||
reader.js_buf = get_tv_string(&argvars[0]);
|
||||
reader.js_eof = TRUE;
|
||||
reader.js_fill = NULL;
|
||||
reader.js_used = 0;
|
||||
if (json_decode(&reader, rettv) == FAIL)
|
||||
if (json_decode_all(&reader, rettv) != OK)
|
||||
EMSG(_(e_invarg));
|
||||
}
|
||||
|
||||
@@ -16887,102 +16970,6 @@ f_searchpos(typval_T *argvars, typval_T *rettv)
|
||||
list_append_number(rettv->vval.v_list, (varnumber_T)n);
|
||||
}
|
||||
|
||||
#ifdef FEAT_CHANNEL
|
||||
/*
|
||||
* common for "sendexpr()" and "sendraw()"
|
||||
* Returns the channel index if the caller should read the response.
|
||||
* Otherwise returns -1.
|
||||
*/
|
||||
static int
|
||||
send_common(typval_T *argvars, char_u *text, char *fun)
|
||||
{
|
||||
int ch_idx;
|
||||
char_u *callback = NULL;
|
||||
|
||||
ch_idx = get_channel_arg(&argvars[0]);
|
||||
if (ch_idx < 0)
|
||||
return -1;
|
||||
|
||||
if (argvars[2].v_type != VAR_UNKNOWN)
|
||||
{
|
||||
callback = get_callback(&argvars[2]);
|
||||
if (callback == NULL)
|
||||
return -1;
|
||||
}
|
||||
/* Set the callback or clear it. An empty callback means no callback and
|
||||
* not reading the response. */
|
||||
channel_set_req_callback(ch_idx,
|
||||
callback != NULL && *callback == NUL ? NULL : callback);
|
||||
|
||||
if (channel_send(ch_idx, text, fun) == OK && callback == NULL)
|
||||
return ch_idx;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* "sendexpr()" function
|
||||
*/
|
||||
static void
|
||||
f_sendexpr(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
char_u *text;
|
||||
typval_T *listtv;
|
||||
int ch_idx;
|
||||
int id;
|
||||
|
||||
/* return an empty string by default */
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = NULL;
|
||||
|
||||
id = channel_get_id();
|
||||
text = json_encode_nr_expr(id, &argvars[1]);
|
||||
if (text == NULL)
|
||||
return;
|
||||
|
||||
ch_idx = send_common(argvars, text, "sendexpr");
|
||||
if (ch_idx >= 0)
|
||||
{
|
||||
if (channel_read_json_block(ch_idx, id, &listtv) == OK)
|
||||
{
|
||||
if (listtv->v_type == VAR_LIST)
|
||||
{
|
||||
list_T *list = listtv->vval.v_list;
|
||||
|
||||
if (list->lv_len == 2)
|
||||
{
|
||||
/* Move the item from the list and then change the type to
|
||||
* avoid the value being freed. */
|
||||
*rettv = list->lv_last->li_tv;
|
||||
list->lv_last->li_tv.v_type = VAR_NUMBER;
|
||||
}
|
||||
}
|
||||
clear_tv(listtv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* "sendraw()" function
|
||||
*/
|
||||
static void
|
||||
f_sendraw(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
char_u buf[NUMBUFLEN];
|
||||
char_u *text;
|
||||
int ch_idx;
|
||||
|
||||
/* return an empty string by default */
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = NULL;
|
||||
|
||||
text = get_tv_string_buf(&argvars[1], buf);
|
||||
ch_idx = send_common(argvars, text, "sendraw");
|
||||
if (ch_idx >= 0)
|
||||
rettv->vval.v_string = channel_read_block(ch_idx);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
|
||||
{
|
||||
|
||||
+303
-126
@@ -17,7 +17,7 @@
|
||||
|
||||
#if defined(FEAT_EVAL) || defined(PROTO)
|
||||
static int json_encode_item(garray_T *gap, typval_T *val, int copyID);
|
||||
static void json_decode_item(js_read_T *reader, typval_T *res);
|
||||
static int json_decode_item(js_read_T *reader, typval_T *res);
|
||||
|
||||
/*
|
||||
* Encode "val" into a JSON format string.
|
||||
@@ -234,37 +234,60 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* When "reader" has less than NUMBUFLEN bytes available, call the fill
|
||||
* callback to get more.
|
||||
*/
|
||||
static void
|
||||
fill_numbuflen(js_read_T *reader)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip white space in "reader".
|
||||
* Also tops up readahead when needed.
|
||||
*/
|
||||
static void
|
||||
json_skip_white(js_read_T *reader)
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = reader->js_buf[reader->js_used]) == ' '
|
||||
|| c == TAB || c == NL || c == CAR)
|
||||
for (;;)
|
||||
{
|
||||
c = reader->js_buf[reader->js_used];
|
||||
if (reader->js_fill != NULL && c == NUL)
|
||||
{
|
||||
if (reader->js_fill(reader))
|
||||
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
|
||||
continue;
|
||||
}
|
||||
if (c != ' ' && c != TAB && c != NL && c != CAR)
|
||||
break;
|
||||
++reader->js_used;
|
||||
}
|
||||
fill_numbuflen(reader);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure there are at least enough characters buffered to read a number.
|
||||
*/
|
||||
static void
|
||||
json_fill_buffer(js_read_T *reader UNUSED)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
json_decode_array(js_read_T *reader, typval_T *res)
|
||||
{
|
||||
char_u *p;
|
||||
typval_T item;
|
||||
listitem_T *li;
|
||||
int ret;
|
||||
|
||||
if (rettv_list_alloc(res) == FAIL)
|
||||
goto failsilent;
|
||||
if (res != NULL && rettv_list_alloc(res) == FAIL)
|
||||
{
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
return FAIL;
|
||||
}
|
||||
++reader->js_used; /* consume the '[' */
|
||||
|
||||
while (TRUE)
|
||||
@@ -272,38 +295,43 @@ json_decode_array(js_read_T *reader, typval_T *res)
|
||||
json_skip_white(reader);
|
||||
p = reader->js_buf + reader->js_used;
|
||||
if (*p == NUL)
|
||||
goto fail;
|
||||
return MAYBE;
|
||||
if (*p == ']')
|
||||
{
|
||||
++reader->js_used; /* consume the ']' */
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!reader->js_eof && (int)(reader->js_end - p) < NUMBUFLEN)
|
||||
json_fill_buffer(reader);
|
||||
|
||||
json_decode_item(reader, &item);
|
||||
li = listitem_alloc();
|
||||
if (li == NULL)
|
||||
return;
|
||||
li->li_tv = item;
|
||||
list_append(res->vval.v_list, li);
|
||||
ret = json_decode_item(reader, res == NULL ? NULL : &item);
|
||||
if (ret != OK)
|
||||
return ret;
|
||||
if (res != NULL)
|
||||
{
|
||||
li = listitem_alloc();
|
||||
if (li == NULL)
|
||||
{
|
||||
clear_tv(&item);
|
||||
return FAIL;
|
||||
}
|
||||
li->li_tv = item;
|
||||
list_append(res->vval.v_list, li);
|
||||
}
|
||||
|
||||
json_skip_white(reader);
|
||||
p = reader->js_buf + reader->js_used;
|
||||
if (*p == ',')
|
||||
++reader->js_used;
|
||||
else if (*p != ']')
|
||||
goto fail;
|
||||
{
|
||||
if (*p == NUL)
|
||||
return MAYBE;
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
fail:
|
||||
EMSG(_(e_invarg));
|
||||
failsilent:
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
json_decode_object(js_read_T *reader, typval_T *res)
|
||||
{
|
||||
char_u *p;
|
||||
@@ -311,10 +339,15 @@ json_decode_object(js_read_T *reader, typval_T *res)
|
||||
typval_T item;
|
||||
dictitem_T *di;
|
||||
char_u buf[NUMBUFLEN];
|
||||
char_u *key;
|
||||
char_u *key = NULL;
|
||||
int ret;
|
||||
|
||||
if (rettv_dict_alloc(res) == FAIL)
|
||||
goto failsilent;
|
||||
if (res != NULL && rettv_dict_alloc(res) == FAIL)
|
||||
{
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
return FAIL;
|
||||
}
|
||||
++reader->js_used; /* consume the '{' */
|
||||
|
||||
while (TRUE)
|
||||
@@ -322,243 +355,387 @@ json_decode_object(js_read_T *reader, typval_T *res)
|
||||
json_skip_white(reader);
|
||||
p = reader->js_buf + reader->js_used;
|
||||
if (*p == NUL)
|
||||
goto fail;
|
||||
return MAYBE;
|
||||
if (*p == '}')
|
||||
{
|
||||
++reader->js_used; /* consume the '}' */
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!reader->js_eof && (int)(reader->js_end - p) < NUMBUFLEN)
|
||||
json_fill_buffer(reader);
|
||||
json_decode_item(reader, &tvkey);
|
||||
key = get_tv_string_buf_chk(&tvkey, buf);
|
||||
if (key == NULL || *key == NUL)
|
||||
ret = json_decode_item(reader, res == NULL ? NULL : &tvkey);
|
||||
if (ret != OK)
|
||||
return ret;
|
||||
if (res != NULL)
|
||||
{
|
||||
/* "key" is NULL when get_tv_string_buf_chk() gave an errmsg */
|
||||
if (key != NULL)
|
||||
EMSG(_(e_emptykey));
|
||||
clear_tv(&tvkey);
|
||||
goto failsilent;
|
||||
key = get_tv_string_buf_chk(&tvkey, buf);
|
||||
if (key == NULL || *key == NUL)
|
||||
{
|
||||
clear_tv(&tvkey);
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
json_skip_white(reader);
|
||||
p = reader->js_buf + reader->js_used;
|
||||
if (*p != ':')
|
||||
{
|
||||
clear_tv(&tvkey);
|
||||
goto fail;
|
||||
if (res != NULL)
|
||||
clear_tv(&tvkey);
|
||||
if (*p == NUL)
|
||||
return MAYBE;
|
||||
return FAIL;
|
||||
}
|
||||
++reader->js_used;
|
||||
json_skip_white(reader);
|
||||
|
||||
if (!reader->js_eof && (int)(reader->js_end - p) < NUMBUFLEN)
|
||||
json_fill_buffer(reader);
|
||||
json_decode_item(reader, &item);
|
||||
|
||||
di = dictitem_alloc(key);
|
||||
clear_tv(&tvkey);
|
||||
if (di == NULL)
|
||||
ret = json_decode_item(reader, res == NULL ? NULL : &item);
|
||||
if (ret != OK)
|
||||
{
|
||||
clear_tv(&item);
|
||||
goto fail;
|
||||
if (res != NULL)
|
||||
clear_tv(&tvkey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (res != NULL)
|
||||
{
|
||||
di = dictitem_alloc(key);
|
||||
clear_tv(&tvkey);
|
||||
if (di == NULL)
|
||||
{
|
||||
clear_tv(&item);
|
||||
return FAIL;
|
||||
}
|
||||
di->di_tv = item;
|
||||
if (dict_add(res->vval.v_dict, di) == FAIL)
|
||||
{
|
||||
dictitem_free(di);
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
di->di_tv = item;
|
||||
if (dict_add(res->vval.v_dict, di) == FAIL)
|
||||
dictitem_free(di);
|
||||
|
||||
json_skip_white(reader);
|
||||
p = reader->js_buf + reader->js_used;
|
||||
if (*p == ',')
|
||||
++reader->js_used;
|
||||
else if (*p != '}')
|
||||
goto fail;
|
||||
{
|
||||
if (*p == NUL)
|
||||
return MAYBE;
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
fail:
|
||||
EMSG(_(e_invarg));
|
||||
failsilent:
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
json_decode_string(js_read_T *reader, typval_T *res)
|
||||
{
|
||||
garray_T ga;
|
||||
int len;
|
||||
char_u *p = reader->js_buf + reader->js_used + 1;
|
||||
char_u *p;
|
||||
int c;
|
||||
long nr;
|
||||
char_u buf[NUMBUFLEN];
|
||||
|
||||
ga_init2(&ga, 1, 200);
|
||||
if (res != NULL)
|
||||
ga_init2(&ga, 1, 200);
|
||||
|
||||
/* TODO: fill buffer when needed. */
|
||||
while (*p != NUL && *p != '"')
|
||||
p = reader->js_buf + reader->js_used + 1; /* skip over " */
|
||||
while (*p != '"')
|
||||
{
|
||||
if (*p == NUL || p[1] == NUL
|
||||
#ifdef FEAT_MBYTE
|
||||
|| utf_ptr2len(p) < utf_byte2len(*p)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
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))
|
||||
break; /* didn't get more */
|
||||
p = reader->js_buf + reader->js_used;
|
||||
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*p == '\\')
|
||||
{
|
||||
c = -1;
|
||||
switch (p[1])
|
||||
{
|
||||
case '\\': c = '\\'; break;
|
||||
case '"': c = '"'; break;
|
||||
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':
|
||||
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);
|
||||
}
|
||||
}
|
||||
vim_str2nr(p + 2, NULL, &len,
|
||||
STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
|
||||
p += len + 2;
|
||||
if (res != NULL)
|
||||
{
|
||||
#ifdef FEAT_MBYTE
|
||||
buf[(*mb_char2bytes)((int)nr, buf)] = NUL;
|
||||
ga_concat(&ga, buf);
|
||||
buf[(*mb_char2bytes)((int)nr, buf)] = NUL;
|
||||
ga_concat(&ga, buf);
|
||||
#else
|
||||
ga_append(&ga, nr);
|
||||
ga_append(&ga, nr);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default: c = p[1]; break;
|
||||
default:
|
||||
/* not a special char, skip over \ */
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
if (c > 0)
|
||||
{
|
||||
p += 2;
|
||||
ga_append(&ga, c);
|
||||
if (res != NULL)
|
||||
ga_append(&ga, c);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
len = MB_PTR2LEN(p);
|
||||
if (ga_grow(&ga, len) == OK)
|
||||
if (res != NULL)
|
||||
{
|
||||
if (ga_grow(&ga, len) == FAIL)
|
||||
{
|
||||
ga_clear(&ga);
|
||||
return FAIL;
|
||||
}
|
||||
mch_memmove((char *)ga.ga_data + ga.ga_len, p, (size_t)len);
|
||||
ga.ga_len += len;
|
||||
}
|
||||
p += len;
|
||||
}
|
||||
if (!reader->js_eof && (int)(reader->js_end - p) < NUMBUFLEN)
|
||||
{
|
||||
reader->js_used = (int)(p - reader->js_buf);
|
||||
json_fill_buffer(reader);
|
||||
p = reader->js_buf + reader->js_used;
|
||||
}
|
||||
}
|
||||
|
||||
reader->js_used = (int)(p - reader->js_buf);
|
||||
if (*p == '"')
|
||||
{
|
||||
++reader->js_used;
|
||||
res->v_type = VAR_STRING;
|
||||
if (ga.ga_data == NULL)
|
||||
res->vval.v_string = NULL;
|
||||
else
|
||||
res->vval.v_string = vim_strsave(ga.ga_data);
|
||||
if (res != NULL)
|
||||
{
|
||||
res->v_type = VAR_STRING;
|
||||
if (ga.ga_data == NULL)
|
||||
res->vval.v_string = NULL;
|
||||
else
|
||||
res->vval.v_string = vim_strsave(ga.ga_data);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
else
|
||||
if (res != NULL)
|
||||
{
|
||||
EMSG(_(e_invarg));
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
ga_clear(&ga);
|
||||
}
|
||||
ga_clear(&ga);
|
||||
return MAYBE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode one item and put it in "result".
|
||||
* Decode one item and put it in "res". If "res" is NULL only advance.
|
||||
* Must already have skipped white space.
|
||||
*
|
||||
* Return FAIL for a decoding error.
|
||||
* Return MAYBE for an incomplete message.
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
json_decode_item(js_read_T *reader, typval_T *res)
|
||||
{
|
||||
char_u *p = reader->js_buf + reader->js_used;
|
||||
char_u *p;
|
||||
int len;
|
||||
|
||||
fill_numbuflen(reader);
|
||||
p = reader->js_buf + reader->js_used;
|
||||
switch (*p)
|
||||
{
|
||||
case '[': /* array */
|
||||
json_decode_array(reader, res);
|
||||
return;
|
||||
return json_decode_array(reader, res);
|
||||
|
||||
case '{': /* object */
|
||||
json_decode_object(reader, res);
|
||||
return;
|
||||
return json_decode_object(reader, res);
|
||||
|
||||
case '"': /* string */
|
||||
json_decode_string(reader, res);
|
||||
return;
|
||||
return json_decode_string(reader, res);
|
||||
|
||||
case ',': /* comma: empty item */
|
||||
case NUL: /* empty */
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
return;
|
||||
if (res != NULL)
|
||||
{
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
}
|
||||
return OK;
|
||||
|
||||
default:
|
||||
if (VIM_ISDIGIT(*p) || *p == '-')
|
||||
{
|
||||
int len;
|
||||
char_u *sp = p;
|
||||
|
||||
#ifdef FEAT_FLOAT
|
||||
if (*sp == '-')
|
||||
{
|
||||
++sp;
|
||||
if (*sp == NUL)
|
||||
return MAYBE;
|
||||
if (!VIM_ISDIGIT(*sp))
|
||||
return FAIL;
|
||||
}
|
||||
sp = skipdigits(sp);
|
||||
if (*sp == '.' || *sp == 'e' || *sp == 'E')
|
||||
{
|
||||
res->v_type = VAR_FLOAT;
|
||||
len = string2float(p, &res->vval.v_float);
|
||||
if (res == NULL)
|
||||
{
|
||||
float_T f;
|
||||
|
||||
len = string2float(p, &f);
|
||||
}
|
||||
else
|
||||
{
|
||||
res->v_type = VAR_FLOAT;
|
||||
len = string2float(p, &res->vval.v_float);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
long nr;
|
||||
|
||||
res->v_type = VAR_NUMBER;
|
||||
vim_str2nr(reader->js_buf + reader->js_used,
|
||||
NULL, &len, 0, /* what */
|
||||
&nr, NULL, 0);
|
||||
res->vval.v_number = nr;
|
||||
if (res != NULL)
|
||||
{
|
||||
res->v_type = VAR_NUMBER;
|
||||
res->vval.v_number = nr;
|
||||
}
|
||||
}
|
||||
reader->js_used += len;
|
||||
return;
|
||||
return OK;
|
||||
}
|
||||
if (STRNICMP((char *)p, "false", 5) == 0)
|
||||
{
|
||||
reader->js_used += 5;
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_FALSE;
|
||||
return;
|
||||
if (res != NULL)
|
||||
{
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_FALSE;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
if (STRNICMP((char *)p, "true", 4) == 0)
|
||||
{
|
||||
reader->js_used += 4;
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_TRUE;
|
||||
return;
|
||||
if (res != NULL)
|
||||
{
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_TRUE;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
if (STRNICMP((char *)p, "null", 4) == 0)
|
||||
{
|
||||
reader->js_used += 4;
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NULL;
|
||||
return;
|
||||
if (res != NULL)
|
||||
{
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NULL;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
/* check for truncated name */
|
||||
len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
|
||||
if ((len < 5 && STRNICMP((char *)p, "false", len) == 0)
|
||||
|| (len < 4 && (STRNICMP((char *)p, "true", len) == 0
|
||||
|| STRNICMP((char *)p, "null", len) == 0)))
|
||||
return MAYBE;
|
||||
break;
|
||||
}
|
||||
|
||||
EMSG(_(e_invarg));
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
if (res != NUL)
|
||||
{
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
}
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the JSON from "reader" and store the result in "res".
|
||||
* Return OK or FAIL;
|
||||
* Return FAIL if not the whole message was consumed.
|
||||
*/
|
||||
int
|
||||
json_decode(js_read_T *reader, typval_T *res)
|
||||
json_decode_all(js_read_T *reader, typval_T *res)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* We get the end once, to avoid calling strlen() many times. */
|
||||
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
|
||||
json_skip_white(reader);
|
||||
json_decode_item(reader, res);
|
||||
ret = json_decode_item(reader, res);
|
||||
if (ret != OK)
|
||||
return FAIL;
|
||||
json_skip_white(reader);
|
||||
if (reader->js_buf[reader->js_used] != NUL)
|
||||
return FAIL;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the JSON from "reader" and store the result in "res".
|
||||
* Return FAIL if the message has a decoding error or the message is
|
||||
* truncated. Consumes the message anyway.
|
||||
*/
|
||||
int
|
||||
json_decode(js_read_T *reader, typval_T *res)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* We get the end once, to avoid calling strlen() many times. */
|
||||
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
|
||||
json_skip_white(reader);
|
||||
ret = json_decode_item(reader, res);
|
||||
json_skip_white(reader);
|
||||
|
||||
return ret == OK ? OK : FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the JSON from "reader" to find the end of the message.
|
||||
* 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
|
||||
* string. A number might be trucated without knowing.
|
||||
* Does not advance the reader.
|
||||
*/
|
||||
int
|
||||
json_find_end(js_read_T *reader)
|
||||
{
|
||||
int used_save = reader->js_used;
|
||||
int ret;
|
||||
|
||||
/* We get the end once, to avoid calling strlen() many times. */
|
||||
reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
|
||||
json_skip_white(reader);
|
||||
ret = json_decode_item(reader, NULL);
|
||||
reader->js_used = used_save;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
/* vi:set ts=8 sts=4 sw=4:
|
||||
*
|
||||
* 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_test.c: Unittests for json.c
|
||||
*/
|
||||
|
||||
#undef NDEBUG
|
||||
#include <assert.h>
|
||||
|
||||
/* Must include main.c because it contains much more than just main() */
|
||||
#define NO_VIM_MAIN
|
||||
#include "main.c"
|
||||
|
||||
/* This file has to be included because the tested functions are static */
|
||||
#include "json.c"
|
||||
|
||||
#if defined(FEAT_EVAL)
|
||||
/*
|
||||
* Test json_find_end() with imcomplete items.
|
||||
*/
|
||||
static void
|
||||
test_decode_find_end(void)
|
||||
{
|
||||
js_read_T reader;
|
||||
|
||||
reader.js_fill = NULL;
|
||||
reader.js_used = 0;
|
||||
|
||||
/* string and incomplete string */
|
||||
reader.js_buf = (char_u *)"\"hello\"";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)" \"hello\" ";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)"\"hello";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
|
||||
/* number and dash (incomplete number) */
|
||||
reader.js_buf = (char_u *)"123";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)"-";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
|
||||
/* false, true and null, also incomplete */
|
||||
reader.js_buf = (char_u *)"false";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)"f";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"fa";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"fal";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"fals";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
|
||||
reader.js_buf = (char_u *)"true";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)"t";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"tr";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"tru";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
|
||||
reader.js_buf = (char_u *)"null";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)"n";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"nu";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"nul";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
|
||||
/* object without white space */
|
||||
reader.js_buf = (char_u *)"{\"a\":123}";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)"{\"a\":123";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"{\"a\":";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"{\"a\"";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"{\"a";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"{\"";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"{";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
|
||||
/* object with white space */
|
||||
reader.js_buf = (char_u *)" { \"a\" : 123 } ";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)" { \"a\" : 123 ";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)" { \"a\" : ";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)" { \"a\" ";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)" { \"a ";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)" { ";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
|
||||
/* array without white space */
|
||||
reader.js_buf = (char_u *)"[\"a\",123]";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)"[\"a\",123";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"[\"a\",";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"[\"a\"";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"[\"a";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"[\"";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)"[";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
|
||||
/* array with white space */
|
||||
reader.js_buf = (char_u *)" [ \"a\" , 123 ] ";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)" [ \"a\" , 123 ";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)" [ \"a\" , ";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)" [ \"a\" ";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)" [ \"a ";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
reader.js_buf = (char_u *)" [ ";
|
||||
assert(json_find_end(&reader) == MAYBE);
|
||||
}
|
||||
|
||||
static int
|
||||
fill_from_cookie(js_read_T *reader)
|
||||
{
|
||||
reader->js_buf = reader->js_cookie;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test json_find_end with an incomplete array, calling the fill function.
|
||||
*/
|
||||
static void
|
||||
test_fill_called_on_find_end(void)
|
||||
{
|
||||
js_read_T reader;
|
||||
|
||||
reader.js_fill = fill_from_cookie;
|
||||
reader.js_used = 0;
|
||||
reader.js_buf = (char_u *)" [ \"a\" , 123 ";
|
||||
reader.js_cookie = " [ \"a\" , 123 ] ";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)" [ \"a\" , ";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)" [ \"a\" ";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)" [ \"a";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
reader.js_buf = (char_u *)" [ ";
|
||||
assert(json_find_end(&reader) == OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test json_find_end with an incomplete string, calling the fill function.
|
||||
*/
|
||||
static void
|
||||
test_fill_called_on_string(void)
|
||||
{
|
||||
js_read_T reader;
|
||||
|
||||
reader.js_fill = fill_from_cookie;
|
||||
reader.js_used = 0;
|
||||
reader.js_buf = (char_u *)" \"foo";
|
||||
reader.js_end = reader.js_buf + STRLEN(reader.js_buf);
|
||||
reader.js_cookie = " \"foobar\" ";
|
||||
assert(json_decode_string(&reader, NULL) == OK);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
#if defined(FEAT_EVAL)
|
||||
test_decode_find_end();
|
||||
test_fill_called_on_find_end();
|
||||
test_fill_called_on_string();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -25,8 +25,6 @@
|
||||
#define index_to_key(i) ((i) ^ 15167)
|
||||
#define TEST_COUNT 50000
|
||||
|
||||
static void test_mf_hash(void);
|
||||
|
||||
/*
|
||||
* Test mf_hash_*() functions.
|
||||
*/
|
||||
|
||||
+1
-2
@@ -4075,8 +4075,7 @@ attention_message(
|
||||
}
|
||||
/* Some of these messages are long to allow translation to
|
||||
* other languages. */
|
||||
MSG_PUTS(_("\n(1) Another program may be editing the same file. If this is the case,\n be careful not to end up with two different instances of the same\n file when making changes."));
|
||||
MSG_PUTS(_(" Quit, or continue with caution.\n"));
|
||||
MSG_PUTS(_("\n(1) Another program may be editing the same file. If this is the case,\n be careful not to end up with two different instances of the same\n file when making changes. Quit, or continue with caution.\n"));
|
||||
MSG_PUTS(_("(2) An edit session for this file crashed.\n"));
|
||||
MSG_PUTS(_(" If this is the case, use \":recover\" or \"vim -r "));
|
||||
msg_outtrans(buf->b_fname);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/* json.c */
|
||||
char_u *json_encode(typval_T *val);
|
||||
char_u *json_encode_nr_expr(int nr, typval_T *val);
|
||||
int json_decode_all(js_read_T *reader, typval_T *res);
|
||||
int json_decode(js_read_T *reader, typval_T *res);
|
||||
int json_find_end(js_read_T *reader);
|
||||
/* vim: set ft=c : */
|
||||
|
||||
+8
-6
@@ -2703,12 +2703,14 @@ typedef struct {
|
||||
/*
|
||||
* Structure used for reading in json_decode().
|
||||
*/
|
||||
typedef struct
|
||||
struct js_reader
|
||||
{
|
||||
char_u *js_buf; /* text to be decoded */
|
||||
char_u *js_end; /* NUL in js_buf when js_eof is FALSE */
|
||||
char_u *js_end; /* NUL in js_buf */
|
||||
int js_used; /* bytes used from js_buf */
|
||||
int js_eof; /* when TRUE js_buf is all there is */
|
||||
int (*js_fill)(void *); /* function to fill the buffer */
|
||||
void *js_cookie; /* passed to js_fill */
|
||||
} js_read_T;
|
||||
int (*js_fill)(struct js_reader *);
|
||||
/* function to fill the buffer or NULL;
|
||||
* return TRUE when the buffer was filled */
|
||||
void *js_cookie; /* can be used by js_fill */
|
||||
};
|
||||
typedef struct js_reader js_read_T;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# A very (if not the most) simplistic Makefile for MSVC
|
||||
|
||||
CC=cl
|
||||
CFLAGS=/O2
|
||||
CFLAGS=/O2 /nologo
|
||||
|
||||
tee.exe: tee.obj
|
||||
$(CC) $(CFLAGS) /Fo$@ $**
|
||||
|
||||
@@ -757,6 +757,24 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1245,
|
||||
/**/
|
||||
1244,
|
||||
/**/
|
||||
1243,
|
||||
/**/
|
||||
1242,
|
||||
/**/
|
||||
1241,
|
||||
/**/
|
||||
1240,
|
||||
/**/
|
||||
1239,
|
||||
/**/
|
||||
1238,
|
||||
/**/
|
||||
1237,
|
||||
/**/
|
||||
1236,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user