forked from aniani/vim
patch 7.4.1154
Problem: No support for JSON.
Solution: Add jsonencode() and jsondecode(). Also add v:false, v:true,
v:null and v:none.
This commit is contained in:
2
Filelist
2
Filelist
@@ -40,6 +40,7 @@ SRC_ALL = \
|
||||
src/hardcopy.c \
|
||||
src/hashtab.c \
|
||||
src/keymap.h \
|
||||
src/json.c \
|
||||
src/macros.h \
|
||||
src/main.c \
|
||||
src/mark.c \
|
||||
@@ -132,6 +133,7 @@ SRC_ALL = \
|
||||
src/proto/gui_beval.pro \
|
||||
src/proto/hardcopy.pro \
|
||||
src/proto/hashtab.pro \
|
||||
src/proto/json.pro \
|
||||
src/proto/main.pro \
|
||||
src/proto/mark.pro \
|
||||
src/proto/mbyte.pro \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*eval.txt* For Vim version 7.4. Last change: 2016 Jan 21
|
||||
*eval.txt* For Vim version 7.4. Last change: 2016 Jan 23
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -1409,6 +1409,10 @@ v:exception The value of the exception most recently caught and not
|
||||
:endtry
|
||||
< Output: "caught oops".
|
||||
|
||||
*v:false* *false-variable*
|
||||
v:false A Number with value zero. Used to put "false" in JSON. See
|
||||
|jsonencode()|.
|
||||
|
||||
*v:fcs_reason* *fcs_reason-variable*
|
||||
v:fcs_reason The reason why the |FileChangedShell| event was triggered.
|
||||
Can be used in an autocommand to decide what to do and/or what
|
||||
@@ -1542,6 +1546,14 @@ v:mouse_col Column number for a mouse click obtained with |getchar()|.
|
||||
This is the screen column number, like with |virtcol()|. The
|
||||
value is zero when there was no mouse button click.
|
||||
|
||||
*v:none* *none-variable*
|
||||
v:none An empty String. Used to put an empty item in JSON. See
|
||||
|jsonencode()|.
|
||||
|
||||
*v:null* *null-variable*
|
||||
v:null An empty String. Used to put "null" in JSON. See
|
||||
|jsonencode()|.
|
||||
|
||||
*v:oldfiles* *oldfiles-variable*
|
||||
v:oldfiles List of file names that is loaded from the |viminfo| file on
|
||||
startup. These are the files that Vim remembers marks for.
|
||||
@@ -1707,6 +1719,10 @@ v:throwpoint The point where the exception most recently caught and not
|
||||
:endtry
|
||||
< Output: "Exception from test.vim, line 2"
|
||||
|
||||
*v:true* *true-variable*
|
||||
v:true A Number with value one. Used to put "true" in JSON. See
|
||||
|jsonencode()|.
|
||||
|
||||
*v:val* *val-variable*
|
||||
v:val Value of the current item of a |List| or |Dictionary|. Only
|
||||
valid while evaluating the expression used with |map()| and
|
||||
@@ -1913,6 +1929,8 @@ isdirectory( {directory}) Number TRUE if {directory} is a directory
|
||||
islocked( {expr}) Number TRUE if {expr} is locked
|
||||
items( {dict}) List key-value pairs in {dict}
|
||||
join( {list} [, {sep}]) String join {list} items into one String
|
||||
jsondecode( {string}) any decode JSON
|
||||
jsonencode( {expr}) String encode JSON
|
||||
keys( {dict}) List keys in {dict}
|
||||
len( {expr}) Number the length of {expr}
|
||||
libcall( {lib}, {func}, {arg}) String call {func} in library {lib} with {arg}
|
||||
@@ -4215,6 +4233,27 @@ join({list} [, {sep}]) *join()*
|
||||
converted into a string like with |string()|.
|
||||
The opposite function is |split()|.
|
||||
|
||||
jsondecode({string}) *jsondecode()*
|
||||
TODO
|
||||
|
||||
jsonencode({expr}) *jsonencode()*
|
||||
Encodode {expr} as JSON and return this as a string.
|
||||
The encoding is specified in:
|
||||
http://www.ietf.org/rfc/rfc4627.txt
|
||||
Vim values are converted as follows:
|
||||
Number decimal number
|
||||
Float floating point number
|
||||
String in double quotes (possibly null)
|
||||
Funcref nothing
|
||||
List as an array (possibly null); when
|
||||
used recursively: []
|
||||
Dict as an object (possibly null); when
|
||||
used recursively: {}
|
||||
v:false "false"
|
||||
v:true "true"
|
||||
v:none nothing
|
||||
v:null "null"
|
||||
|
||||
keys({dict}) *keys()*
|
||||
Return a |List| with all the keys of {dict}. The |List| is in
|
||||
arbitrary order.
|
||||
|
||||
@@ -72,6 +72,7 @@ EXE_dependencies = \
|
||||
getchar.obj \
|
||||
hardcopy.obj \
|
||||
hashtab.obj \
|
||||
json.obj \
|
||||
main.obj \
|
||||
mark.obj \
|
||||
memfile.obj \
|
||||
|
||||
@@ -598,6 +598,7 @@ vimobj = \
|
||||
$(OBJDIR)\getchar.obj \
|
||||
$(OBJDIR)\hardcopy.obj \
|
||||
$(OBJDIR)\hashtab.obj \
|
||||
$(OBJDIR)\json.obj \
|
||||
$(OBJDIR)\main.obj \
|
||||
$(OBJDIR)\mark.obj \
|
||||
$(OBJDIR)\memfile.obj \
|
||||
|
||||
@@ -601,6 +601,7 @@ OBJ = \
|
||||
$(OUTDIR)/getchar.o \
|
||||
$(OUTDIR)/hardcopy.o \
|
||||
$(OUTDIR)/hashtab.o \
|
||||
$(OUTDIR)/json.o \
|
||||
$(OUTDIR)/main.o \
|
||||
$(OUTDIR)/mark.o \
|
||||
$(OUTDIR)/memfile.o \
|
||||
|
||||
@@ -45,6 +45,7 @@ SRC = \
|
||||
getchar.c \
|
||||
hardcopy.c \
|
||||
hashtab.c \
|
||||
json.c \
|
||||
main.c \
|
||||
mark.c \
|
||||
memfile.c \
|
||||
@@ -93,6 +94,7 @@ OBJ = o/blowfish.o \
|
||||
o/getchar.o \
|
||||
o/hardcopy.o \
|
||||
o/hashtab.o \
|
||||
o/json.o \
|
||||
o/main.o \
|
||||
o/mark.o \
|
||||
o/memfile.o \
|
||||
@@ -179,6 +181,8 @@ o/hardcopy.o: hardcopy.c $(SYMS)
|
||||
|
||||
o/hashtab.o: hashtab.c $(SYMS)
|
||||
|
||||
o/json.o: json.c $(SYMS)
|
||||
|
||||
o/main.o: main.c $(SYMS)
|
||||
|
||||
o/mark.o: mark.c $(SYMS)
|
||||
|
||||
@@ -229,6 +229,7 @@ LINK32_OBJS= \
|
||||
"$(INTDIR)/getchar.obj" \
|
||||
"$(INTDIR)/hardcopy.obj" \
|
||||
"$(INTDIR)/hashtab.obj" \
|
||||
"$(INTDIR)/json.obj" \
|
||||
"$(INTDIR)/main.obj" \
|
||||
"$(INTDIR)/mark.obj" \
|
||||
"$(INTDIR)/mbyte.obj" \
|
||||
@@ -555,6 +556,10 @@ SOURCE=.\if_ole.idl
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\json.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\main.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
@@ -55,6 +55,7 @@ SRC = blowfish.c \
|
||||
getchar.c \
|
||||
hardcopy.c \
|
||||
hashtab.c \
|
||||
json.c \
|
||||
main.c \
|
||||
mark.c \
|
||||
memfile.c \
|
||||
@@ -105,6 +106,7 @@ OBJ = obj/blowfish.o \
|
||||
obj/getchar.o \
|
||||
obj/hardcopy.o \
|
||||
obj/hashtab.o \
|
||||
obj/json.o \
|
||||
obj/main.o \
|
||||
obj/mark.o \
|
||||
obj/memfile.o \
|
||||
@@ -153,6 +155,7 @@ PRO = proto/blowfish.pro \
|
||||
proto/getchar.pro \
|
||||
proto/hardcopy.pro \
|
||||
proto/hashtab.pro \
|
||||
proto/json.pro \
|
||||
proto/main.pro \
|
||||
proto/mark.pro \
|
||||
proto/memfile.pro \
|
||||
@@ -284,6 +287,9 @@ obj/hardcopy.o: hardcopy.c
|
||||
obj/hashtab.o: hashtab.c
|
||||
$(CCSYM) $@ hashtab.c
|
||||
|
||||
obj/json.o: json.c
|
||||
$(CCSYM) $@ json.c
|
||||
|
||||
# Don't use $(SYMS) here, because main.c defines EXTERN
|
||||
obj/main.o: main.c option.h globals.h
|
||||
$(CCNOSYM) $@ main.c
|
||||
|
||||
@@ -43,6 +43,7 @@ SRC = blowfish.c \
|
||||
getchar.c \
|
||||
hardcopy.c \
|
||||
hashtab.c \
|
||||
json.c \
|
||||
main.c \
|
||||
mark.c \
|
||||
mbyte.c \
|
||||
|
||||
@@ -536,6 +536,7 @@ OBJ = \
|
||||
$(OUTDIR)\getchar.obj \
|
||||
$(OUTDIR)\hardcopy.obj \
|
||||
$(OUTDIR)\hashtab.obj \
|
||||
$(OUTDIR)\json.obj \
|
||||
$(OUTDIR)\main.obj \
|
||||
$(OUTDIR)\mark.obj \
|
||||
$(OUTDIR)\mbyte.obj \
|
||||
@@ -1202,6 +1203,8 @@ $(OUTDIR)/if_sniff.obj: $(OUTDIR) if_sniff.c $(INCL)
|
||||
$(OUTDIR)/if_tcl.obj: $(OUTDIR) if_tcl.c $(INCL)
|
||||
$(CC) $(CFLAGS) $(TCL_INC) if_tcl.c
|
||||
|
||||
$(OUTDIR)/json.obj: $(OUTDIR) json.c $(INCL)
|
||||
|
||||
$(OUTDIR)/main.obj: $(OUTDIR) main.c $(INCL)
|
||||
|
||||
$(OUTDIR)/mark.obj: $(OUTDIR) mark.c $(INCL)
|
||||
@@ -1329,6 +1332,7 @@ proto.h: \
|
||||
proto/getchar.pro \
|
||||
proto/hardcopy.pro \
|
||||
proto/hashtab.pro \
|
||||
proto/json.pro \
|
||||
proto/main.pro \
|
||||
proto/mark.pro \
|
||||
proto/memfile.pro \
|
||||
|
||||
@@ -108,6 +108,7 @@ SRC = \
|
||||
getchar.c \
|
||||
hardcopy.c \
|
||||
hashtab.c \
|
||||
json.c \
|
||||
main.c \
|
||||
mark.c \
|
||||
memfile.c \
|
||||
@@ -157,6 +158,7 @@ OBJ = \
|
||||
getchar.o \
|
||||
hardcopy.o \
|
||||
hashtab.o \
|
||||
json.o \
|
||||
main.o \
|
||||
mark.o \
|
||||
memfile.o \
|
||||
@@ -206,6 +208,7 @@ PRO = \
|
||||
proto/getchar.pro \
|
||||
proto/hardcopy.pro \
|
||||
proto/hashtab.pro \
|
||||
proto/json.pro \
|
||||
proto/main.pro \
|
||||
proto/mark.pro \
|
||||
proto/memfile.pro \
|
||||
@@ -328,6 +331,8 @@ hardcopy.o: hardcopy.c
|
||||
proto/hardcopy.pro: hardcopy.c
|
||||
hashtab.o: hashtab.c
|
||||
proto/hashtab.pro: hashtab.c
|
||||
json.o: json.c
|
||||
proto/json.pro: json.c
|
||||
main.o: main.c
|
||||
proto/main.pro: main.c
|
||||
mark.o: mark.c
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Makefile for Vim on OpenVMS
|
||||
#
|
||||
# Maintainer: Zoltan Arpadffy <arpadffy@polarhome.com>
|
||||
# Last change: 2014 Aug 10
|
||||
# Last change: 2016 Jan 22
|
||||
#
|
||||
# This has script been tested on VMS 6.2 to 8.2 on DEC Alpha, VAX and IA64
|
||||
# with MMS and MMK
|
||||
@@ -311,7 +311,7 @@ ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_LIB) \
|
||||
|
||||
SRC = blowfish.c buffer.c charset.c crypt.c, crypt_zip.c diff.c digraph.c edit.c eval.c ex_cmds.c ex_cmds2.c \
|
||||
ex_docmd.c ex_eval.c ex_getln.c if_xcmdsrv.c fileio.c fold.c getchar.c \
|
||||
hardcopy.c hashtab.c main.c mark.c menu.c mbyte.c memfile.c memline.c message.c misc1.c \
|
||||
hardcopy.c hashtab.c json.c main.c mark.c menu.c mbyte.c memfile.c memline.c message.c misc1.c \
|
||||
misc2.c move.c normal.c ops.c option.c popupmnu.c quickfix.c regexp.c search.c sha256.c\
|
||||
spell.c syntax.c tag.c term.c termlib.c ui.c undo.c version.c screen.c \
|
||||
window.c os_unix.c os_vms.c pathdef.c \
|
||||
@@ -320,7 +320,7 @@ SRC = blowfish.c buffer.c charset.c crypt.c, crypt_zip.c diff.c digraph.c edit.c
|
||||
|
||||
OBJ = blowfish.obj buffer.obj charset.obj crypt.obj, crypt_zip.obj diff.obj digraph.obj edit.obj eval.obj \
|
||||
ex_cmds.obj ex_cmds2.obj ex_docmd.obj ex_eval.obj ex_getln.obj \
|
||||
if_xcmdsrv.obj fileio.obj fold.obj getchar.obj hardcopy.obj hashtab.obj main.obj mark.obj \
|
||||
if_xcmdsrv.obj fileio.obj fold.obj getchar.obj hardcopy.obj hashtab.obj json.obj main.obj mark.obj \
|
||||
menu.obj memfile.obj memline.obj message.obj misc1.obj misc2.obj \
|
||||
move.obj mbyte.obj normal.obj ops.obj option.obj popupmnu.obj quickfix.obj \
|
||||
regexp.obj search.obj sha256.obj spell.obj syntax.obj tag.obj term.obj termlib.obj \
|
||||
@@ -572,6 +572,10 @@ if_mzsch.obj : if_mzsch.c vim.h [.auto]config.h feature.h os_unix.h \
|
||||
ascii.h keymap.h term.h macros.h option.h structs.h \
|
||||
regexp.h gui.h gui_beval.h [.proto]gui_beval.pro ex_cmds.h proto.h \
|
||||
globals.h farsi.h arabic.h if_mzsch.h
|
||||
json.obj : json.c vim.h [.auto]config.h feature.h os_unix.h \
|
||||
ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h gui_beval.h \
|
||||
[.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
|
||||
arabic.h version.h
|
||||
main.obj : main.c vim.h [.auto]config.h feature.h os_unix.h \
|
||||
ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h gui_beval.h \
|
||||
[.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \
|
||||
|
||||
23
src/Makefile
23
src/Makefile
@@ -1487,6 +1487,7 @@ BASIC_SRC = \
|
||||
hashtab.c \
|
||||
if_cscope.c \
|
||||
if_xcmdsrv.c \
|
||||
json.c \
|
||||
main.c \
|
||||
mark.c \
|
||||
memfile.c \
|
||||
@@ -1580,6 +1581,7 @@ OBJ_COMMON = \
|
||||
$(HANGULIN_OBJ) \
|
||||
objects/if_cscope.o \
|
||||
objects/if_xcmdsrv.o \
|
||||
objects/json.o \
|
||||
objects/mark.o \
|
||||
objects/memline.o \
|
||||
objects/menu.o \
|
||||
@@ -1654,6 +1656,7 @@ PRO_AUTO = \
|
||||
if_python.pro \
|
||||
if_python3.pro \
|
||||
if_ruby.pro \
|
||||
json.pro \
|
||||
main.pro \
|
||||
mark.pro \
|
||||
memfile.pro \
|
||||
@@ -1986,6 +1989,8 @@ test_arglist \
|
||||
test_expand \
|
||||
test_hardcopy \
|
||||
test_increment \
|
||||
test_json \
|
||||
test_langmap \
|
||||
test_lispwords \
|
||||
test_menu \
|
||||
test_perl \
|
||||
@@ -1993,6 +1998,7 @@ test_arglist \
|
||||
test_searchpos \
|
||||
test_set \
|
||||
test_sort \
|
||||
test_syntax \
|
||||
test_undolevels \
|
||||
test_unlet \
|
||||
test_viminfo \
|
||||
@@ -2770,6 +2776,9 @@ objects/if_tcl.o: if_tcl.c
|
||||
objects/integration.o: integration.c
|
||||
$(CCC) -o $@ integration.c
|
||||
|
||||
objects/json.o: json.c
|
||||
$(CCC) -o $@ json.c
|
||||
|
||||
objects/main.o: main.c
|
||||
$(CCC) -o $@ main.c
|
||||
|
||||
@@ -3060,6 +3069,10 @@ objects/if_xcmdsrv.o: if_xcmdsrv.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 ex_cmds.h proto.h \
|
||||
globals.h farsi.h arabic.h version.h
|
||||
objects/json.o: json.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 ex_cmds.h proto.h globals.h farsi.h \
|
||||
arabic.h
|
||||
objects/main.o: 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 ex_cmds.h proto.h globals.h farsi.h \
|
||||
@@ -3114,7 +3127,7 @@ objects/option.o: option.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h
|
||||
objects/os_unix.o: os_unix.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 ex_cmds.h proto.h globals.h farsi.h \
|
||||
arabic.h if_mzsch.h os_unixx.h
|
||||
arabic.h os_unixx.h
|
||||
objects/pathdef.o: auto/pathdef.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 ex_cmds.h proto.h \
|
||||
@@ -3179,7 +3192,7 @@ objects/gui.o: gui.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h ascii.
|
||||
objects/gui_gtk.o: gui_gtk.c gui_gtk_f.h 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 ex_cmds.h proto.h \
|
||||
globals.h farsi.h arabic.h ../pixmaps/stock_icons.h
|
||||
globals.h farsi.h arabic.h
|
||||
objects/gui_gtk_f.o: gui_gtk_f.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 ex_cmds.h proto.h \
|
||||
@@ -3245,8 +3258,8 @@ objects/gui_athena.o: gui_athena.c vim.h auto/config.h feature.h os_unix.h \
|
||||
objects/gui_gtk_x11.o: gui_gtk_x11.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 ex_cmds.h proto.h \
|
||||
globals.h farsi.h arabic.h gui_gtk_f.h ../runtime/vim32x32.xpm \
|
||||
../runtime/vim16x16.xpm ../runtime/vim48x48.xpm $(GRESOURCE_HDR)
|
||||
globals.h farsi.h arabic.h auto/gui_gtk_gresources.h gui_gtk_f.h \
|
||||
../runtime/vim32x32.xpm ../runtime/vim16x16.xpm ../runtime/vim48x48.xpm
|
||||
objects/gui_x11.o: gui_x11.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 ex_cmds.h proto.h globals.h farsi.h \
|
||||
@@ -3278,7 +3291,7 @@ objects/if_lua.o: if_lua.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h
|
||||
objects/if_mzsch.o: if_mzsch.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 ex_cmds.h proto.h \
|
||||
globals.h farsi.h arabic.h if_mzsch.h mzscheme_base.c
|
||||
globals.h farsi.h arabic.h if_mzsch.h
|
||||
objects/if_perl.o: auto/if_perl.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 ex_cmds.h proto.h \
|
||||
|
||||
107
src/eval.c
107
src/eval.c
@@ -99,7 +99,6 @@ static char *e_undefvar = N_("E121: Undefined variable: %s");
|
||||
static char *e_missbrac = N_("E111: Missing ']'");
|
||||
static char *e_listarg = N_("E686: Argument of %s must be a List");
|
||||
static char *e_listdictarg = N_("E712: Argument of %s must be a List or Dictionary");
|
||||
static char *e_emptykey = N_("E713: Cannot use empty key for Dictionary");
|
||||
static char *e_listreq = N_("E714: List required");
|
||||
static char *e_dictreq = N_("E715: Dictionary required");
|
||||
static char *e_toomanyarg = N_("E118: Too many arguments for function: %s");
|
||||
@@ -371,6 +370,10 @@ static struct vimvar
|
||||
{VV_NAME("option_old", VAR_STRING), VV_RO},
|
||||
{VV_NAME("option_type", VAR_STRING), VV_RO},
|
||||
{VV_NAME("errors", VAR_LIST), 0},
|
||||
{VV_NAME("false", VAR_SPECIAL), VV_RO},
|
||||
{VV_NAME("true", VAR_SPECIAL), VV_RO},
|
||||
{VV_NAME("null", VAR_SPECIAL), VV_RO},
|
||||
{VV_NAME("none", VAR_SPECIAL), VV_RO},
|
||||
};
|
||||
|
||||
/* shorthand */
|
||||
@@ -428,7 +431,6 @@ static int get_option_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate));
|
||||
static int get_string_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate));
|
||||
static int get_lit_string_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate));
|
||||
static int get_list_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate));
|
||||
static int rettv_list_alloc __ARGS((typval_T *rettv));
|
||||
static long list_len __ARGS((list_T *l));
|
||||
static int list_equal __ARGS((list_T *l1, list_T *l2, int ic, int recursive));
|
||||
static int dict_equal __ARGS((dict_T *d1, dict_T *d2, int ic, int recursive));
|
||||
@@ -443,7 +445,6 @@ static char_u *list2string __ARGS((typval_T *tv, int copyID));
|
||||
static int list_join_inner __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo_style, int copyID, garray_T *join_gap));
|
||||
static int list_join __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo, int copyID));
|
||||
static int free_unref_items __ARGS((int copyID));
|
||||
static int rettv_dict_alloc __ARGS((typval_T *rettv));
|
||||
static dictitem_T *dictitem_copy __ARGS((dictitem_T *org));
|
||||
static void dictitem_remove __ARGS((dict_T *dict, dictitem_T *item));
|
||||
static dict_T *dict_copy __ARGS((dict_T *orig, int deep, int copyID));
|
||||
@@ -453,9 +454,6 @@ static int get_dict_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate));
|
||||
static char_u *echo_string __ARGS((typval_T *tv, char_u **tofree, char_u *numbuf, int copyID));
|
||||
static char_u *tv2string __ARGS((typval_T *tv, char_u **tofree, char_u *numbuf, int copyID));
|
||||
static char_u *string_quote __ARGS((char_u *str, int function));
|
||||
#ifdef FEAT_FLOAT
|
||||
static int string2float __ARGS((char_u *text, float_T *value));
|
||||
#endif
|
||||
static int get_env_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate));
|
||||
static int find_internal_func __ARGS((char_u *name));
|
||||
static char_u *deref_func_name __ARGS((char_u *name, int *lenp, int no_autoload));
|
||||
@@ -617,6 +615,8 @@ static void f_isdirectory __ARGS((typval_T *argvars, typval_T *rettv));
|
||||
static void f_islocked __ARGS((typval_T *argvars, typval_T *rettv));
|
||||
static void f_items __ARGS((typval_T *argvars, typval_T *rettv));
|
||||
static void f_join __ARGS((typval_T *argvars, typval_T *rettv));
|
||||
static void f_jsondecode __ARGS((typval_T *argvars, typval_T *rettv));
|
||||
static void f_jsonencode __ARGS((typval_T *argvars, typval_T *rettv));
|
||||
static void f_keys __ARGS((typval_T *argvars, typval_T *rettv));
|
||||
static void f_last_buffer_nr __ARGS((typval_T *argvars, typval_T *rettv));
|
||||
static void f_len __ARGS((typval_T *argvars, typval_T *rettv));
|
||||
@@ -816,7 +816,6 @@ static linenr_T get_tv_lnum __ARGS((typval_T *argvars));
|
||||
static linenr_T get_tv_lnum_buf __ARGS((typval_T *argvars, buf_T *buf));
|
||||
static char_u *get_tv_string __ARGS((typval_T *varp));
|
||||
static char_u *get_tv_string_buf __ARGS((typval_T *varp, char_u *buf));
|
||||
static char_u *get_tv_string_buf_chk __ARGS((typval_T *varp, char_u *buf));
|
||||
static dictitem_T *find_var __ARGS((char_u *name, hashtab_T **htp, int no_autoload));
|
||||
static dictitem_T *find_var_in_ht __ARGS((hashtab_T *ht, int htname, char_u *varname, int no_autoload));
|
||||
static hashtab_T *find_var_ht __ARGS((char_u *name, char_u **varname));
|
||||
@@ -915,6 +914,12 @@ eval_init()
|
||||
set_vim_var_nr(VV_HLSEARCH, 1L);
|
||||
set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
|
||||
set_vim_var_list(VV_ERRORS, list_alloc());
|
||||
|
||||
set_vim_var_nr(VV_FALSE, VVAL_FALSE);
|
||||
set_vim_var_nr(VV_TRUE, VVAL_TRUE);
|
||||
set_vim_var_nr(VV_NONE, VVAL_NONE);
|
||||
set_vim_var_nr(VV_NULL, VVAL_NULL);
|
||||
|
||||
set_reg_var(0); /* default for v:register is not 0 but '"' */
|
||||
|
||||
#ifdef EBCDIC
|
||||
@@ -3080,13 +3085,15 @@ tv_op(tv1, tv2, op)
|
||||
char_u numbuf[NUMBUFLEN];
|
||||
char_u *s;
|
||||
|
||||
/* Can't do anything with a Funcref or a Dict on the right. */
|
||||
if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT)
|
||||
/* Can't do anything with a Funcref, Dict, v:true on the right. */
|
||||
if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT
|
||||
&& tv2->v_type != VAR_SPECIAL)
|
||||
{
|
||||
switch (tv1->v_type)
|
||||
{
|
||||
case VAR_DICT:
|
||||
case VAR_FUNC:
|
||||
case VAR_SPECIAL:
|
||||
break;
|
||||
|
||||
case VAR_LIST:
|
||||
@@ -5390,6 +5397,10 @@ eval_index(arg, rettv, evaluate, verbose)
|
||||
return FAIL;
|
||||
}
|
||||
#endif
|
||||
else if (rettv->v_type == VAR_SPECIAL)
|
||||
{
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
init_tv(&var1);
|
||||
init_tv(&var2);
|
||||
@@ -5999,7 +6010,7 @@ list_alloc()
|
||||
* Allocate an empty list for a return value.
|
||||
* Returns OK or FAIL.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
rettv_list_alloc(rettv)
|
||||
typval_T *rettv;
|
||||
{
|
||||
@@ -6246,6 +6257,9 @@ tv_equal(tv1, tv2, ic, recursive)
|
||||
s1 = get_tv_string_buf(tv1, buf1);
|
||||
s2 = get_tv_string_buf(tv2, buf2);
|
||||
return ((ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2)) == 0);
|
||||
|
||||
case VAR_SPECIAL:
|
||||
return tv1->vval.v_number == tv2->vval.v_number;
|
||||
}
|
||||
|
||||
EMSG2(_(e_intern2), "tv_equal()");
|
||||
@@ -6837,6 +6851,17 @@ list_join(gap, l, sep, echo_style, copyID)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next (unique) copy ID.
|
||||
* Used for serializing nested structures.
|
||||
*/
|
||||
int
|
||||
get_copyID()
|
||||
{
|
||||
current_copyID += COPYID_INC;
|
||||
return current_copyID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Garbage collection for lists and dictionaries.
|
||||
*
|
||||
@@ -6883,8 +6908,7 @@ garbage_collect()
|
||||
|
||||
/* We advance by two because we add one for items referenced through
|
||||
* previous_funccal. */
|
||||
current_copyID += COPYID_INC;
|
||||
copyID = current_copyID;
|
||||
copyID = get_copyID();
|
||||
|
||||
/*
|
||||
* 1. Go through all accessible variables and mark all lists and dicts
|
||||
@@ -7236,7 +7260,7 @@ dict_alloc()
|
||||
* Allocate an empty dict for a return value.
|
||||
* Returns OK or FAIL.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
rettv_dict_alloc(rettv)
|
||||
typval_T *rettv;
|
||||
{
|
||||
@@ -7891,6 +7915,18 @@ echo_string(tv, tofree, numbuf, copyID)
|
||||
break;
|
||||
#endif
|
||||
|
||||
case VAR_SPECIAL:
|
||||
*tofree = NULL;
|
||||
switch (tv->vval.v_number)
|
||||
{
|
||||
case VVAL_FALSE: r = (char_u *)"false"; break;
|
||||
case VVAL_TRUE: r = (char_u *)"true"; break;
|
||||
case VVAL_NONE: r = (char_u *)"none"; break;
|
||||
case VVAL_NULL: r = (char_u *)"null"; break;
|
||||
default: EMSG2(_(e_intern2), "echo_string(special)");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
EMSG2(_(e_intern2), "echo_string()");
|
||||
*tofree = NULL;
|
||||
@@ -7932,6 +7968,7 @@ tv2string(tv, tofree, numbuf, copyID)
|
||||
case VAR_NUMBER:
|
||||
case VAR_LIST:
|
||||
case VAR_DICT:
|
||||
case VAR_SPECIAL:
|
||||
break;
|
||||
default:
|
||||
EMSG2(_(e_intern2), "tv2string()");
|
||||
@@ -7985,14 +8022,14 @@ string_quote(str, function)
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef FEAT_FLOAT
|
||||
#if defined(FEAT_FLOAT) || defined(PROTO)
|
||||
/*
|
||||
* Convert the string "text" to a floating point number.
|
||||
* This uses strtod(). setlocale(LC_NUMERIC, "C") has been used to make sure
|
||||
* this always uses a decimal point.
|
||||
* Returns the length of the text that was consumed.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
string2float(text, value)
|
||||
char_u *text;
|
||||
float_T *value; /* result stored here */
|
||||
@@ -8237,6 +8274,8 @@ static struct fst
|
||||
{"islocked", 1, 1, f_islocked},
|
||||
{"items", 1, 1, f_items},
|
||||
{"join", 1, 2, f_join},
|
||||
{"jsondecode", 1, 1, f_jsondecode},
|
||||
{"jsonencode", 1, 1, f_jsonencode},
|
||||
{"keys", 1, 1, f_keys},
|
||||
{"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
|
||||
{"len", 1, 1, f_len},
|
||||
@@ -14393,6 +14432,34 @@ f_join(argvars, rettv)
|
||||
rettv->vval.v_string = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* "jsondecode()" function
|
||||
*/
|
||||
static void
|
||||
f_jsondecode(argvars, rettv)
|
||||
typval_T *argvars;
|
||||
typval_T *rettv;
|
||||
{
|
||||
js_read_T reader;
|
||||
|
||||
reader.js_buf = get_tv_string(&argvars[0]);
|
||||
reader.js_eof = TRUE;
|
||||
reader.js_used = 0;
|
||||
json_decode(&reader, rettv);
|
||||
}
|
||||
|
||||
/*
|
||||
* "jsonencode()" function
|
||||
*/
|
||||
static void
|
||||
f_jsonencode(argvars, rettv)
|
||||
typval_T *argvars;
|
||||
typval_T *rettv;
|
||||
{
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = json_encode(&argvars[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
* "keys()" function
|
||||
*/
|
||||
@@ -21558,6 +21625,7 @@ clear_tv(varp)
|
||||
varp->vval.v_dict = NULL;
|
||||
break;
|
||||
case VAR_NUMBER:
|
||||
case VAR_SPECIAL:
|
||||
varp->vval.v_number = 0;
|
||||
break;
|
||||
#ifdef FEAT_FLOAT
|
||||
@@ -21759,7 +21827,7 @@ get_tv_string_chk(varp)
|
||||
return get_tv_string_buf_chk(varp, mybuf);
|
||||
}
|
||||
|
||||
static char_u *
|
||||
char_u *
|
||||
get_tv_string_buf_chk(varp, buf)
|
||||
typval_T *varp;
|
||||
char_u *buf;
|
||||
@@ -22120,8 +22188,7 @@ list_one_var(v, prefix, first)
|
||||
char_u *s;
|
||||
char_u numbuf[NUMBUFLEN];
|
||||
|
||||
current_copyID += COPYID_INC;
|
||||
s = echo_string(&v->di_tv, &tofree, numbuf, current_copyID);
|
||||
s = echo_string(&v->di_tv, &tofree, numbuf, get_copyID());
|
||||
list_one_var_a(prefix, v->di_key, v->di_tv.v_type,
|
||||
s == NULL ? (char_u *)"" : s, first);
|
||||
vim_free(tofree);
|
||||
@@ -22435,6 +22502,7 @@ copy_tv(from, to)
|
||||
switch (from->v_type)
|
||||
{
|
||||
case VAR_NUMBER:
|
||||
case VAR_SPECIAL:
|
||||
to->vval.v_number = from->vval.v_number;
|
||||
break;
|
||||
#ifdef FEAT_FLOAT
|
||||
@@ -22609,8 +22677,7 @@ ex_echo(eap)
|
||||
}
|
||||
else if (eap->cmdidx == CMD_echo)
|
||||
msg_puts_attr((char_u *)" ", echo_attr);
|
||||
current_copyID += COPYID_INC;
|
||||
p = echo_string(&rettv, &tofree, numbuf, current_copyID);
|
||||
p = echo_string(&rettv, &tofree, numbuf, get_copyID());
|
||||
if (p != NULL)
|
||||
for ( ; *p != NUL && !got_int; ++p)
|
||||
{
|
||||
|
||||
@@ -1523,6 +1523,7 @@ EXTERN char_u e_readonly[] INIT(= N_("E45: 'readonly' option is set (add ! to ov
|
||||
#ifdef FEAT_EVAL
|
||||
EXTERN char_u e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%s\""));
|
||||
EXTERN char_u e_readonlysbx[] INIT(= N_("E794: Cannot set variable in the sandbox: \"%s\""));
|
||||
EXTERN char_u e_emptykey[] INIT(= N_("E713: Cannot use empty key for Dictionary"));
|
||||
#endif
|
||||
#ifdef FEAT_QUICKFIX
|
||||
EXTERN char_u e_readerrf[] INIT(= N_("E47: Error while reading errorfile"));
|
||||
|
||||
@@ -499,6 +499,12 @@ luaV_pushtypval(lua_State *L, typval_T *tv)
|
||||
case VAR_DICT:
|
||||
luaV_pushdict(L, tv->vval.v_dict);
|
||||
break;
|
||||
case VAR_SPECIAL:
|
||||
if (tv->vval.v_number <= VVAL_TRUE)
|
||||
lua_pushinteger(L, (int) tv->vval.v_number);
|
||||
else
|
||||
lua_pushnil(L);
|
||||
break;
|
||||
default:
|
||||
lua_pushnil(L);
|
||||
}
|
||||
@@ -510,7 +516,7 @@ luaV_totypval (lua_State *L, int pos, typval_T *tv)
|
||||
{
|
||||
switch(lua_type(L, pos)) {
|
||||
case LUA_TBOOLEAN:
|
||||
tv->v_type = VAR_NUMBER;
|
||||
tv->v_type = VAR_SPECIAL;
|
||||
tv->vval.v_number = (varnumber_T) lua_toboolean(L, pos);
|
||||
break;
|
||||
case LUA_TSTRING:
|
||||
|
||||
@@ -3084,6 +3084,14 @@ vim_to_mzscheme_impl(typval_T *vim_value, int depth, Scheme_Hash_Table *visited)
|
||||
|
||||
MZ_GC_UNREG();
|
||||
}
|
||||
else if (vim_value->v_type == VAR_SPECIAL)
|
||||
{
|
||||
if (vim_value->vval.v_number <= VVAL_TRUE)
|
||||
result = scheme_make_integer((long)vim_value->vval.v_number);
|
||||
else
|
||||
result = scheme_null;
|
||||
MZ_GC_CHECK();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = scheme_void;
|
||||
@@ -3148,8 +3156,8 @@ mzscheme_to_vim_impl(Scheme_Object *obj, typval_T *tv, int depth,
|
||||
copy_tv(found, tv);
|
||||
else if (SCHEME_VOIDP(obj))
|
||||
{
|
||||
tv->v_type = VAR_NUMBER;
|
||||
tv->vval.v_number = 0;
|
||||
tv->v_type = VAR_SPECIAL;
|
||||
tv->vval.v_number = VVAL_NULL;
|
||||
}
|
||||
else if (SCHEME_INTP(obj))
|
||||
{
|
||||
@@ -3158,7 +3166,7 @@ mzscheme_to_vim_impl(Scheme_Object *obj, typval_T *tv, int depth,
|
||||
}
|
||||
else if (SCHEME_BOOLP(obj))
|
||||
{
|
||||
tv->v_type = VAR_NUMBER;
|
||||
tv->v_type = VAR_SPECIAL;
|
||||
tv->vval.v_number = SCHEME_TRUEP(obj);
|
||||
}
|
||||
# ifdef FEAT_FLOAT
|
||||
|
||||
@@ -810,6 +810,25 @@ VimToPython(typval_T *our_tv, int depth, PyObject *lookup_dict)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (our_tv->v_type == VAR_SPECIAL)
|
||||
{
|
||||
if (our_tv->vval.v_number == VVAL_FALSE)
|
||||
{
|
||||
ret = Py_False;
|
||||
Py_INCREF(ret);
|
||||
}
|
||||
else if (our_tv->vval.v_number == VVAL_TRUE)
|
||||
{
|
||||
ret = Py_True;
|
||||
Py_INCREF(ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
Py_INCREF(Py_None);
|
||||
ret = Py_None;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
Py_INCREF(Py_None);
|
||||
|
||||
@@ -1032,6 +1032,11 @@ static VALUE vim_to_ruby(typval_T *tv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tv->v_type == VAR_SPECIAL)
|
||||
{
|
||||
if (tv->vval.v_number <= VVAL_TRUE)
|
||||
result = INT2NUM(tv->vval.v_number);
|
||||
} /* else return Qnil; */
|
||||
|
||||
return result;
|
||||
|
||||
509
src/json.c
Normal file
509
src/json.c
Normal file
@@ -0,0 +1,509 @@
|
||||
/* 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.c: Encoding and decoding JSON.
|
||||
*
|
||||
* Follows this standard: http://www.ietf.org/rfc/rfc4627.txt
|
||||
*/
|
||||
|
||||
#include "vim.h"
|
||||
|
||||
#if defined(FEAT_EVAL) || defined(PROTO)
|
||||
static void json_decode_item(js_read_T *reader, typval_T *res);
|
||||
|
||||
/*
|
||||
* Encode "val" into a JSON format string.
|
||||
*/
|
||||
char_u *
|
||||
json_encode(typval_T *val)
|
||||
{
|
||||
garray_T ga;
|
||||
|
||||
/* Store bytes in the growarray. */
|
||||
ga_init2(&ga, 1, 4000);
|
||||
json_encode_item(&ga, val, get_copyID());
|
||||
return ga.ga_data;
|
||||
}
|
||||
|
||||
static void
|
||||
write_string(garray_T *gap, char_u *str)
|
||||
{
|
||||
char_u *res = str;
|
||||
char_u numbuf[NUMBUFLEN];
|
||||
|
||||
if (res == NULL)
|
||||
ga_concat(gap, (char_u *)"null");
|
||||
else
|
||||
{
|
||||
ga_append(gap, '"');
|
||||
while (*res != NUL)
|
||||
{
|
||||
int c = PTR2CHAR(res);
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0x08:
|
||||
ga_append(gap, '\\'); ga_append(gap, 'b'); break;
|
||||
case 0x09:
|
||||
ga_append(gap, '\\'); ga_append(gap, 't'); break;
|
||||
case 0x0a:
|
||||
ga_append(gap, '\\'); ga_append(gap, 'n'); break;
|
||||
case 0x0c:
|
||||
ga_append(gap, '\\'); ga_append(gap, 'f'); break;
|
||||
case 0x0d:
|
||||
ga_append(gap, '\\'); ga_append(gap, 'r'); break;
|
||||
case 0x22: /* " */
|
||||
case 0x5c: /* \ */
|
||||
ga_append(gap, '\\');
|
||||
ga_append(gap, c);
|
||||
break;
|
||||
default:
|
||||
if (c >= 0x20)
|
||||
{
|
||||
numbuf[mb_char2bytes(c, numbuf)] = NUL;
|
||||
ga_concat(gap, numbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
vim_snprintf((char *)numbuf, NUMBUFLEN,
|
||||
"\\u%04lx", (long)c);
|
||||
ga_concat(gap, numbuf);
|
||||
}
|
||||
}
|
||||
mb_cptr_adv(res);
|
||||
}
|
||||
ga_append(gap, '"');
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
json_encode_item(garray_T *gap, typval_T *val, int copyID)
|
||||
{
|
||||
char_u numbuf[NUMBUFLEN];
|
||||
char_u *res;
|
||||
list_T *l;
|
||||
dict_T *d;
|
||||
|
||||
switch (val->v_type)
|
||||
{
|
||||
case VAR_SPECIAL:
|
||||
switch(val->vval.v_number)
|
||||
{
|
||||
case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
|
||||
case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
|
||||
case VVAL_NONE: break;
|
||||
case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case VAR_NUMBER:
|
||||
vim_snprintf((char *)numbuf, NUMBUFLEN, "%ld",
|
||||
(long)val->vval.v_number);
|
||||
ga_concat(gap, numbuf);
|
||||
break;
|
||||
|
||||
case VAR_STRING:
|
||||
res = val->vval.v_string;
|
||||
write_string(gap, res);
|
||||
break;
|
||||
|
||||
case VAR_FUNC:
|
||||
/* no JSON equivalent, skip */
|
||||
break;
|
||||
|
||||
case VAR_LIST:
|
||||
l = val->vval.v_list;
|
||||
if (l == NULL)
|
||||
ga_concat(gap, (char_u *)"null");
|
||||
else
|
||||
{
|
||||
if (l->lv_copyID == copyID)
|
||||
ga_concat(gap, (char_u *)"[]");
|
||||
else
|
||||
{
|
||||
listitem_T *li;
|
||||
|
||||
l->lv_copyID = copyID;
|
||||
ga_append(gap, '[');
|
||||
for (li = l->lv_first; li != NULL && !got_int; )
|
||||
{
|
||||
json_encode_item(gap, &li->li_tv, copyID);
|
||||
li = li->li_next;
|
||||
if (li != NULL)
|
||||
ga_append(gap, ',');
|
||||
}
|
||||
ga_append(gap, ']');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case VAR_DICT:
|
||||
d = val->vval.v_dict;
|
||||
if (d == NULL)
|
||||
ga_concat(gap, (char_u *)"null");
|
||||
else
|
||||
{
|
||||
if (d->dv_copyID == copyID)
|
||||
ga_concat(gap, (char_u *)"{}");
|
||||
else
|
||||
{
|
||||
int first = TRUE;
|
||||
int todo = (int)d->dv_hashtab.ht_used;
|
||||
hashitem_T *hi;
|
||||
|
||||
d->dv_copyID = copyID;
|
||||
ga_append(gap, '{');
|
||||
|
||||
for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int;
|
||||
++hi)
|
||||
if (!HASHITEM_EMPTY(hi))
|
||||
{
|
||||
--todo;
|
||||
if (first)
|
||||
first = FALSE;
|
||||
else
|
||||
ga_append(gap, ',');
|
||||
write_string(gap, hi->hi_key);
|
||||
ga_append(gap, ':');
|
||||
json_encode_item(gap, &dict_lookup(hi)->di_tv,
|
||||
copyID);
|
||||
}
|
||||
ga_append(gap, '}');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef FEAT_FLOAT
|
||||
case VAR_FLOAT:
|
||||
vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", val->vval.v_float);
|
||||
ga_concat(gap, numbuf);
|
||||
break;
|
||||
#endif
|
||||
default: EMSG2(_(e_intern2), "json_encode_item()"); break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip white space in "reader".
|
||||
*/
|
||||
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)
|
||||
++reader->js_used;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
json_decode_array(js_read_T *reader, typval_T *res)
|
||||
{
|
||||
char_u *p;
|
||||
typval_T item;
|
||||
listitem_T *li;
|
||||
|
||||
if (rettv_list_alloc(res) == FAIL)
|
||||
goto fail;
|
||||
++reader->js_used; /* consume the '[' */
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
json_skip_white(reader);
|
||||
p = reader->js_buf + reader->js_used;
|
||||
if (*p == NUL)
|
||||
goto fail;
|
||||
if (*p == ']')
|
||||
{
|
||||
++reader->js_used; /* consume the ']' */
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
json_skip_white(reader);
|
||||
p = reader->js_buf + reader->js_used;
|
||||
if (*p == ',')
|
||||
++reader->js_used;
|
||||
else if (*p != ']')
|
||||
goto fail;
|
||||
}
|
||||
fail:
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
json_decode_object(js_read_T *reader, typval_T *res)
|
||||
{
|
||||
char_u *p;
|
||||
typval_T tvkey;
|
||||
typval_T item;
|
||||
dictitem_T *di;
|
||||
char_u buf[NUMBUFLEN];
|
||||
char_u *key;
|
||||
|
||||
if (rettv_dict_alloc(res) == FAIL)
|
||||
goto fail;
|
||||
++reader->js_used; /* consume the '{' */
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
json_skip_white(reader);
|
||||
p = reader->js_buf + reader->js_used;
|
||||
if (*p == NUL)
|
||||
goto fail;
|
||||
if (*p == '}')
|
||||
{
|
||||
++reader->js_used; /* consume the '}' */
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* "key" is NULL when get_tv_string_buf_chk() gave an errmsg */
|
||||
if (key != NULL)
|
||||
EMSG(_(e_emptykey));
|
||||
clear_tv(&tvkey);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
json_skip_white(reader);
|
||||
p = reader->js_buf + reader->js_used;
|
||||
if (*p != ':')
|
||||
{
|
||||
clear_tv(&tvkey);
|
||||
goto 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)
|
||||
{
|
||||
clear_tv(&item);
|
||||
goto fail;
|
||||
}
|
||||
di->di_tv = item;
|
||||
dict_add(res->vval.v_dict, di);
|
||||
|
||||
json_skip_white(reader);
|
||||
p = reader->js_buf + reader->js_used;
|
||||
if (*p == ',')
|
||||
++reader->js_used;
|
||||
else if (*p != '}')
|
||||
goto fail;
|
||||
}
|
||||
fail:
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
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;
|
||||
int c;
|
||||
long nr;
|
||||
char_u buf[NUMBUFLEN];
|
||||
|
||||
ga_init2(&ga, 1, 200);
|
||||
|
||||
/* TODO: fill buffer when needed. */
|
||||
while (*p != NUL && *p != '"')
|
||||
{
|
||||
if (*p == '\\')
|
||||
{
|
||||
c = -1;
|
||||
switch (p[1])
|
||||
{
|
||||
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':
|
||||
vim_str2nr(p + 2, NULL, &len,
|
||||
STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4);
|
||||
p += len + 2;
|
||||
#ifdef FEAT_MBYTE
|
||||
buf[(*mb_char2bytes)((int)nr, buf)] = NUL;
|
||||
ga_concat(&ga, buf);
|
||||
#else
|
||||
ga_append(&ga, nr);
|
||||
#endif
|
||||
break;
|
||||
default: c = p[1]; break;
|
||||
}
|
||||
if (c > 0)
|
||||
{
|
||||
p += 2;
|
||||
ga_append(&ga, c);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
len = MB_PTR2LEN(p);
|
||||
if (ga_grow(&ga, len) == OK)
|
||||
{
|
||||
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;
|
||||
res->vval.v_string = vim_strsave(ga.ga_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
}
|
||||
ga_clear(&ga);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode one item and put it in "result".
|
||||
* Must already have skipped white space.
|
||||
*/
|
||||
static void
|
||||
json_decode_item(js_read_T *reader, typval_T *res)
|
||||
{
|
||||
char_u *p = reader->js_buf + reader->js_used;
|
||||
|
||||
switch (*p)
|
||||
{
|
||||
case '[': /* array */
|
||||
json_decode_array(reader, res);
|
||||
return;
|
||||
|
||||
case '{': /* object */
|
||||
json_decode_object(reader, res);
|
||||
return;
|
||||
|
||||
case '"': /* string */
|
||||
json_decode_string(reader, res);
|
||||
return;
|
||||
|
||||
case ',': /* comma: empty item */
|
||||
case NUL: /* empty */
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
return;
|
||||
|
||||
default:
|
||||
if (VIM_ISDIGIT(*p) || *p == '-')
|
||||
{
|
||||
int len;
|
||||
char_u *sp = p;
|
||||
#ifdef FEAT_FLOAT
|
||||
if (*sp == '-')
|
||||
++sp;
|
||||
sp = skipdigits(sp);
|
||||
if (*sp == '.' || *sp == 'e' || *sp == 'E')
|
||||
{
|
||||
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;
|
||||
}
|
||||
reader->js_used += len;
|
||||
return;
|
||||
}
|
||||
if (STRNICMP((char *)p, "false", 5) == 0)
|
||||
{
|
||||
reader->js_used += 5;
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_FALSE;
|
||||
return;
|
||||
}
|
||||
if (STRNICMP((char *)p, "true", 4) == 0)
|
||||
{
|
||||
reader->js_used += 4;
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_TRUE;
|
||||
return;
|
||||
}
|
||||
if (STRNICMP((char *)p, "null", 4) == 0)
|
||||
{
|
||||
reader->js_used += 4;
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NULL;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
EMSG(_(e_invarg));
|
||||
res->v_type = VAR_SPECIAL;
|
||||
res->vval.v_number = VVAL_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the JSON from "reader" and store the result in "res".
|
||||
*/
|
||||
void
|
||||
json_decode(js_read_T *reader, typval_T *res)
|
||||
{
|
||||
json_skip_white(reader);
|
||||
json_decode_item(reader, res);
|
||||
json_skip_white(reader);
|
||||
if (reader->js_buf[reader->js_used] != NUL)
|
||||
EMSG(_(e_invarg));
|
||||
}
|
||||
#endif
|
||||
@@ -95,6 +95,7 @@ extern int _stricoll __ARGS((char *a, char *b));
|
||||
# endif
|
||||
# include "hardcopy.pro"
|
||||
# include "hashtab.pro"
|
||||
# include "json.pro"
|
||||
# include "main.pro"
|
||||
# include "mark.pro"
|
||||
# include "memfile.pro"
|
||||
|
||||
@@ -46,6 +46,7 @@ int do_unlet(char_u *name, int forceit);
|
||||
void del_menutrans_vars(void);
|
||||
char_u *get_user_var_name(expand_T *xp, int idx);
|
||||
list_T *list_alloc(void);
|
||||
int rettv_list_alloc(typval_T *rettv);
|
||||
void list_unref(list_T *l);
|
||||
void list_free(list_T *l, int recurse);
|
||||
listitem_T *listitem_alloc(void);
|
||||
@@ -61,11 +62,13 @@ int list_append_string(list_T *l, char_u *str, int len);
|
||||
int list_insert_tv(list_T *l, typval_T *tv, listitem_T *item);
|
||||
void list_insert(list_T *l, listitem_T *ni, listitem_T *item);
|
||||
void vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2);
|
||||
int get_copyID(void);
|
||||
int garbage_collect(void);
|
||||
int set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack);
|
||||
int set_ref_in_list(list_T *l, int copyID, ht_stack_T **ht_stack);
|
||||
int set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack_T **list_stack);
|
||||
dict_T *dict_alloc(void);
|
||||
int rettv_dict_alloc(typval_T *rettv);
|
||||
void dict_unref(dict_T *d);
|
||||
void dict_free(dict_T *d, int recurse);
|
||||
dictitem_T *dictitem_alloc(char_u *key);
|
||||
@@ -76,6 +79,7 @@ int dict_add_list(dict_T *d, char *key, list_T *list);
|
||||
dictitem_T *dict_find(dict_T *d, char_u *key, int len);
|
||||
char_u *get_dict_string(dict_T *d, char_u *key, int save);
|
||||
long get_dict_number(dict_T *d, char_u *key);
|
||||
int string2float(char_u *text, float_T *value);
|
||||
char_u *get_function_name(expand_T *xp, int idx);
|
||||
char_u *get_expr_name(expand_T *xp, int idx);
|
||||
int func_call(char_u *name, typval_T *args, dict_T *selfdict, typval_T *rettv);
|
||||
@@ -100,6 +104,7 @@ void free_tv(typval_T *varp);
|
||||
void clear_tv(typval_T *varp);
|
||||
long get_tv_number_chk(typval_T *varp, int *denote);
|
||||
char_u *get_tv_string_chk(typval_T *varp);
|
||||
char_u *get_tv_string_buf_chk(typval_T *varp, char_u *buf);
|
||||
char_u *get_var_value(char_u *name);
|
||||
void new_script_vars(scid_T id);
|
||||
void init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope);
|
||||
|
||||
5
src/proto/json.pro
Normal file
5
src/proto/json.pro
Normal file
@@ -0,0 +1,5 @@
|
||||
/* json.c */
|
||||
char_u *json_encode(typval_T *val);
|
||||
void json_encode_item(garray_T *gap, typval_T *val, int copyID);
|
||||
void json_decode(js_read_T *reader, typval_T *res);
|
||||
/* vim: set ft=c : */
|
||||
@@ -1138,6 +1138,7 @@ typedef struct
|
||||
#define VAR_LIST 4 /* "v_list" is used */
|
||||
#define VAR_DICT 5 /* "v_dict" is used */
|
||||
#define VAR_FLOAT 6 /* "v_float" is used */
|
||||
#define VAR_SPECIAL 7 /* "v_number" is used */
|
||||
|
||||
/* Values for "dv_scope". */
|
||||
#define VAR_SCOPE 1 /* a:, v:, s:, etc. scope dictionaries */
|
||||
@@ -2682,3 +2683,15 @@ typedef struct {
|
||||
UINT32_T state[8];
|
||||
char_u buffer[64];
|
||||
} context_sha256_T;
|
||||
|
||||
/*
|
||||
* Structure used for reading in json_decode().
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char_u *js_buf; /* text to be decoded */
|
||||
char_u *js_end; /* NUL in js_buf when js_eof is FALSE */
|
||||
int js_used; /* bytes used from js_buf */
|
||||
int js_eof; /* when TRUE js_buf is all there is */
|
||||
FILE *js_fd; /* file descriptor to read more from */
|
||||
} js_read_T;
|
||||
|
||||
@@ -5,6 +5,7 @@ source test_backspace_opt.vim
|
||||
source test_cursor_func.vim
|
||||
source test_delete.vim
|
||||
source test_expand.vim
|
||||
source test_json.vim
|
||||
source test_lispwords.vim
|
||||
source test_menu.vim
|
||||
source test_searchpos.vim
|
||||
|
||||
91
src/testdir/test_json.vim
Normal file
91
src/testdir/test_json.vim
Normal file
@@ -0,0 +1,91 @@
|
||||
" Test for JSON functions.
|
||||
|
||||
let s:json1 = '"str\"in\\g"'
|
||||
let s:var1 = "str\"in\\g"
|
||||
let s:json2 = '"\u0001\u0002\u0003\u0004\u0005\u0006\u0007"'
|
||||
let s:var2 = "\x01\x02\x03\x04\x05\x06\x07"
|
||||
let s:json3 = '"\b\t\n\u000b\f\r\u000e\u000f"'
|
||||
let s:var3 = "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
|
||||
let s:json4 = '"\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017"'
|
||||
let s:var4 = "\x10\x11\x12\x13\x14\x15\x16\x17"
|
||||
let s:json5 = '"\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f"'
|
||||
let s:var5 = "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
|
||||
|
||||
let s:jsonmb = '"s¢cĴgё"'
|
||||
let s:varmb = "s¢cĴgё"
|
||||
let s:jsonnr = '1234'
|
||||
let s:varnr = 1234
|
||||
let s:jsonfl = '12.34'
|
||||
let s:varfl = 12.34
|
||||
|
||||
let s:jsonl1 = '[1,"a",3]'
|
||||
let s:varl1 = [1, "a", 3]
|
||||
let s:jsonl2 = '[1,["a",[],"c"],3]'
|
||||
let s:jsonl2s = " [\r1 , [ \"a\" , [ ] , \"c\" ] , 3\<Tab>]\r\n"
|
||||
let s:varl2 = [1, 2, 3]
|
||||
let l2 = ['a', s:varl2, 'c']
|
||||
let s:varl2[1] = l2
|
||||
let s:varl2x = [1, ["a", [], "c"], 3]
|
||||
|
||||
let s:jsond1 = '{"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:jsond2s = " { \"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 d2 = {"a": "aa", "b": s:vard2, "c": "cc"}
|
||||
let s:vard2["2"] = d2
|
||||
let s:vard2x = {"1": 1, "2": {"a": "aa", "b": {}, "c": "cc"}, "3": 3}
|
||||
|
||||
let s:jsonvals = '[true,false,,null]'
|
||||
let s:varvals = [v:true, v:false, v:none, v:null]
|
||||
|
||||
func Test_encode()
|
||||
call assert_equal(s:json1, jsonencode(s:var1))
|
||||
call assert_equal(s:json2, jsonencode(s:var2))
|
||||
call assert_equal(s:json3, jsonencode(s:var3))
|
||||
call assert_equal(s:json4, jsonencode(s:var4))
|
||||
call assert_equal(s:json5, jsonencode(s:var5))
|
||||
|
||||
if has('multi_byte')
|
||||
call assert_equal(s:jsonmb, jsonencode(s:varmb))
|
||||
endif
|
||||
|
||||
call assert_equal(s:jsonnr, jsonencode(s:varnr))
|
||||
if has('float')
|
||||
call assert_equal(s:jsonfl, jsonencode(s:varfl))
|
||||
endif
|
||||
|
||||
call assert_equal(s:jsonl1, jsonencode(s:varl1))
|
||||
call assert_equal(s:jsonl2, jsonencode(s:varl2))
|
||||
|
||||
call assert_equal(s:jsond1, jsonencode(s:vard1))
|
||||
call assert_equal(s:jsond2, jsonencode(s:vard2))
|
||||
|
||||
call assert_equal(s:jsonvals, jsonencode(s:varvals))
|
||||
endfunc
|
||||
|
||||
func Test_decode()
|
||||
call assert_equal(s:var1, jsondecode(s:json1))
|
||||
call assert_equal(s:var2, jsondecode(s:json2))
|
||||
call assert_equal(s:var3, jsondecode(s:json3))
|
||||
call assert_equal(s:var4, jsondecode(s:json4))
|
||||
call assert_equal(s:var5, jsondecode(s:json5))
|
||||
|
||||
if has('multi_byte')
|
||||
call assert_equal(s:varmb, jsondecode(s:jsonmb))
|
||||
endif
|
||||
|
||||
call assert_equal(s:varnr, jsondecode(s:jsonnr))
|
||||
if has('float')
|
||||
call assert_equal(s:varfl, jsondecode(s:jsonfl))
|
||||
endif
|
||||
|
||||
call assert_equal(s:varl1, jsondecode(s:jsonl1))
|
||||
call assert_equal(s:varl2x, jsondecode(s:jsonl2))
|
||||
call assert_equal(s:varl2x, jsondecode(s:jsonl2s))
|
||||
|
||||
call assert_equal(s:vard1, jsondecode(s:jsond1))
|
||||
call assert_equal(s:vard2x, jsondecode(s:jsond2))
|
||||
|
||||
call assert_equal(s:varvals, jsondecode(s:jsonvals))
|
||||
endfunc
|
||||
@@ -741,6 +741,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1154,
|
||||
/**/
|
||||
1153,
|
||||
/**/
|
||||
|
||||
12
src/vim.h
12
src/vim.h
@@ -1896,7 +1896,17 @@ typedef int proftime_T; /* dummy for function prototypes */
|
||||
#define VV_OPTION_OLD 60
|
||||
#define VV_OPTION_TYPE 61
|
||||
#define VV_ERRORS 62
|
||||
#define VV_LEN 63 /* number of v: vars */
|
||||
#define VV_FALSE 63
|
||||
#define VV_TRUE 64
|
||||
#define VV_NULL 65
|
||||
#define VV_NONE 66
|
||||
#define VV_LEN 67 /* number of v: vars */
|
||||
|
||||
/* used for v_number in VAR_SPECIAL */
|
||||
#define VVAL_FALSE 0L
|
||||
#define VVAL_TRUE 1L
|
||||
#define VVAL_NONE 2L
|
||||
#define VVAL_NULL 3L
|
||||
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
|
||||
|
||||
Reference in New Issue
Block a user