aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZyX <kp-pav@yandex.ru>2017-04-08 01:54:58 +0300
committerZyX <kp-pav@yandex.ru>2017-04-08 01:54:58 +0300
commit043d8ff9f2389f8deab7934aa0ab4ce88a747f01 (patch)
tree4d6fa32d7c1ddaa99c15f80c1a4ba95d5f3ca2da /src
parent5992cdf3c27ee9c73cea22e288c6ea6d54867394 (diff)
parent13352c00f1909d9296c5f276a3735f5e6f231b39 (diff)
downloadrneovim-043d8ff9f2389f8deab7934aa0ab4ce88a747f01.tar.gz
rneovim-043d8ff9f2389f8deab7934aa0ab4ce88a747f01.tar.bz2
rneovim-043d8ff9f2389f8deab7934aa0ab4ce88a747f01.zip
Merge branch 'master' into luaviml'/lua
Diffstat (limited to 'src')
-rw-r--r--src/.asan-blacklist2
-rwxr-xr-xsrc/clint.py10
-rw-r--r--src/coverity-model.c2
-rw-r--r--src/nvim/CMakeLists.txt312
-rw-r--r--src/nvim/api/buffer.c10
-rw-r--r--src/nvim/api/private/helpers.c54
-rw-r--r--src/nvim/api/ui.c10
-rw-r--r--src/nvim/api/vim.c20
-rw-r--r--src/nvim/ascii.h17
-rw-r--r--src/nvim/buffer.c33
-rw-r--r--src/nvim/buffer.h6
-rw-r--r--src/nvim/buffer_defs.h45
-rw-r--r--src/nvim/charset.c56
-rw-r--r--src/nvim/charset.h14
-rw-r--r--src/nvim/cursor.c15
-rw-r--r--src/nvim/cursor_shape.c143
-rw-r--r--src/nvim/cursor_shape.h73
-rw-r--r--src/nvim/diff.c2
-rw-r--r--src/nvim/diff.h3
-rw-r--r--src/nvim/edit.c439
-rw-r--r--src/nvim/eval.c9349
-rw-r--r--src/nvim/eval.h10
-rw-r--r--src/nvim/eval/decode.c131
-rw-r--r--src/nvim/eval/decode.h2
-rw-r--r--src/nvim/eval/encode.c13
-rw-r--r--src/nvim/eval/executor.c115
-rw-r--r--src/nvim/eval/executor.h11
-rw-r--r--src/nvim/eval/gc.c11
-rw-r--r--src/nvim/eval/gc.h12
-rw-r--r--src/nvim/eval/typval.c2556
-rw-r--r--src/nvim/eval/typval.h429
-rw-r--r--src/nvim/eval/typval_encode.c.h12
-rw-r--r--src/nvim/eval/typval_encode.h2
-rw-r--r--src/nvim/eval_defs.h285
-rw-r--r--src/nvim/event/process.h2
-rw-r--r--src/nvim/event/rstream.c10
-rw-r--r--src/nvim/ex_cmds.c10
-rw-r--r--src/nvim/ex_cmds.h2
-rw-r--r--src/nvim/ex_cmds2.c107
-rw-r--r--src/nvim/ex_docmd.c498
-rw-r--r--src/nvim/ex_docmd.h1
-rw-r--r--src/nvim/ex_eval.c49
-rw-r--r--src/nvim/ex_getln.c125
-rw-r--r--src/nvim/ex_getln.h2
-rw-r--r--src/nvim/file_search.c13
-rw-r--r--src/nvim/fileio.c295
-rw-r--r--src/nvim/fold.c71
-rw-r--r--src/nvim/getchar.c279
-rw-r--r--src/nvim/gettext.h21
-rw-r--r--src/nvim/globals.h22
-rw-r--r--src/nvim/hardcopy.c8
-rw-r--r--src/nvim/hashtab.c7
-rw-r--r--src/nvim/hashtab.h19
-rw-r--r--src/nvim/if_cscope.c29
-rw-r--r--src/nvim/indent_c.c2
-rw-r--r--src/nvim/macros.h2
-rw-r--r--src/nvim/main.c54
-rw-r--r--src/nvim/mark.c25
-rw-r--r--src/nvim/mark.h2
-rw-r--r--src/nvim/mark_defs.h2
-rw-r--r--src/nvim/mbyte.c130
-rw-r--r--src/nvim/mbyte.h39
-rw-r--r--src/nvim/memline.c2
-rw-r--r--src/nvim/memory.c13
-rw-r--r--src/nvim/message.c26
-rw-r--r--src/nvim/misc1.c49
-rw-r--r--src/nvim/msgpack_rpc/channel.c20
-rw-r--r--src/nvim/msgpack_rpc/helpers.c17
-rw-r--r--src/nvim/normal.c113
-rw-r--r--src/nvim/ops.c174
-rw-r--r--src/nvim/ops.h2
-rw-r--r--src/nvim/option.c466
-rw-r--r--src/nvim/option_defs.h14
-rw-r--r--src/nvim/options.lua17
-rw-r--r--src/nvim/os/env.c47
-rw-r--r--src/nvim/os/fileio.c51
-rw-r--r--src/nvim/os/fs.c31
-rw-r--r--src/nvim/os/fs_defs.h2
-rw-r--r--src/nvim/os/os_defs.h4
-rw-r--r--src/nvim/os/pty_process_win.h5
-rw-r--r--src/nvim/os/unix_defs.h2
-rw-r--r--src/nvim/os/win_defs.h6
-rw-r--r--src/nvim/os_unix.c4
-rw-r--r--src/nvim/path.c131
-rw-r--r--src/nvim/po/CMakeLists.txt10
-rw-r--r--src/nvim/popupmnu.c11
-rw-r--r--src/nvim/quickfix.c126
-rw-r--r--src/nvim/regexp.c66
-rw-r--r--src/nvim/regexp_nfa.c4
-rw-r--r--src/nvim/screen.c10
-rw-r--r--src/nvim/search.c14
-rw-r--r--src/nvim/sha256.c14
-rw-r--r--src/nvim/shada.c56
-rw-r--r--src/nvim/spell.c141
-rw-r--r--src/nvim/spellfile.c56
-rw-r--r--src/nvim/strings.c53
-rw-r--r--src/nvim/strings.h5
-rw-r--r--src/nvim/syntax.c305
-rw-r--r--src/nvim/syntax.h10
-rw-r--r--src/nvim/tag.c45
-rw-r--r--src/nvim/terminal.c26
-rw-r--r--src/nvim/testdir/Makefile6
-rw-r--r--src/nvim/testdir/test_charsearch.vim62
-rw-r--r--src/nvim/testdir/test_cmdline.vim15
-rw-r--r--src/nvim/testdir/test_fnameescape.vim21
-rw-r--r--src/nvim/testdir/test_fold.vim118
-rw-r--r--src/nvim/testdir/test_gf.vim33
-rw-r--r--src/nvim/testdir/test_hlsearch.vim34
-rw-r--r--src/nvim/testdir/test_mapping.vim82
-rw-r--r--src/nvim/testdir/test_smartindent.vim14
-rw-r--r--src/nvim/testdir/test_substitute.vim41
-rw-r--r--src/nvim/testdir/test_tagjump.vim30
-rw-r--r--src/nvim/tui/tui.c210
-rw-r--r--src/nvim/tui/tui.h2
-rw-r--r--src/nvim/ui.c10
-rw-r--r--src/nvim/ui.h1
-rw-r--r--src/nvim/ui_bridge.c21
-rw-r--r--src/nvim/undo.c38
-rw-r--r--src/nvim/version.c36
-rw-r--r--src/nvim/vim.h57
-rw-r--r--src/nvim/viml/executor/converter.c39
-rw-r--r--src/nvim/viml/executor/executor.c27
-rw-r--r--src/nvim/window.c55
123 files changed, 10645 insertions, 8485 deletions
diff --git a/src/.asan-blacklist b/src/.asan-blacklist
index 7636f8fa82..928d81bd5a 100644
--- a/src/.asan-blacklist
+++ b/src/.asan-blacklist
@@ -1,3 +1,3 @@
# multiqueue.h pointer arithmetic is not accepted by asan
fun:multiqueue_node_data
-fun:dictwatcher_node_data
+fun:tv_dict_watcher_node_data
diff --git a/src/clint.py b/src/clint.py
index ca4dbdb1bc..3babb7772b 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -572,7 +572,8 @@ class _CppLintState(object):
for category, count in self.errors_by_category.items():
sys.stderr.write('Category \'%s\' errors found: %d\n' %
(category, count))
- sys.stderr.write('Total errors found: %d\n' % self.error_count)
+ if self.error_count:
+ sys.stderr.write('Total errors found: %d\n' % self.error_count)
def SuppressErrorsFrom(self, fname):
"""Open file and read a list of suppressed errors from it"""
@@ -2273,11 +2274,14 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
# //!< Header comment
# or they begin with multiple slashes followed by a space:
# //////// Header comment
+ # or they are Vim {{{ fold markers
match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or
Search(r'^/$', line[commentend:]) or
Search(r'^!< ', line[commentend:]) or
Search(r'^/< ', line[commentend:]) or
- Search(r'^/+ ', line[commentend:]))
+ Search(r'^/+ ', line[commentend:]) or
+ Search(r'^(?:\{{3}|\}{3})\d*(?: |$)',
+ line[commentend:]))
if not match:
error(filename, linenum, 'whitespace/comments', 4,
'Should have a space between // and comment')
@@ -3580,7 +3584,7 @@ def main():
if __name__ == '__main__':
main()
-# vim: ts=4 sts=4 sw=4
+# vim: ts=4 sts=4 sw=4 foldmarker=▶,▲
# Ignore "too complex" warnings when using pymode.
# pylama:ignore=C901
diff --git a/src/coverity-model.c b/src/coverity-model.c
index a01ea6d316..3c38e4ae4d 100644
--- a/src/coverity-model.c
+++ b/src/coverity-model.c
@@ -64,7 +64,7 @@ void *je_realloc(void *ptr, size_t size)
// of the memory allocated for item.
typedef struct {} dictitem_T;
typedef struct {} dict_T;
-int dict_add(dict_T *d, dictitem_T *item)
+int tv_dict_add(dict_T *const d, dictitem_T *const item)
{
__coverity_escape__(item);
}
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index a6ae758a8e..e87f0d68aa 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -10,6 +10,7 @@ if(USE_GCOV)
endif()
endif()
+set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches)
set(GENERATED_DIR ${PROJECT_BINARY_DIR}/src/nvim/auto)
set(MSGPACK_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genmsgpack.lua)
set(API_METADATA ${PROJECT_BINARY_DIR}/api_metadata.mpack)
@@ -21,7 +22,6 @@ set(GENERATED_API_DISPATCH ${GENERATED_DIR}/api/private/dispatch_wrappers.genera
set(GENERATED_FUNCS_METADATA ${GENERATED_DIR}/api/private/funcs_metadata.generated.h)
set(GENERATED_EX_CMDS_ENUM ${GENERATED_INCLUDES_DIR}/ex_cmds_enum.generated.h)
set(GENERATED_EX_CMDS_DEFS ${GENERATED_DIR}/ex_cmds_defs.generated.h)
-set(GENERATED_FUNCS_HASH_INPUT ${GENERATED_DIR}/funcs.generated.h.gperf)
set(GENERATED_FUNCS ${GENERATED_DIR}/funcs.generated.h)
set(GENERATED_EVENTS_ENUM ${GENERATED_INCLUDES_DIR}/auevents_enum.generated.h)
set(GENERATED_EVENTS_NAMES_MAP ${GENERATED_DIR}/auevents_name_map.generated.h)
@@ -30,29 +30,34 @@ set(EX_CMDS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genex_cmds.lua)
set(FUNCS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/geneval.lua)
set(EVENTS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gen_events.lua)
set(OPTIONS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genoptions.lua)
-set(EVENTS_LIST_FILE ${PROJECT_SOURCE_DIR}/src/nvim/auevents.lua)
-set(EX_CMDS_DEFS_FILE ${PROJECT_SOURCE_DIR}/src/nvim/ex_cmds.lua)
-set(EVAL_DEFS_FILE ${PROJECT_SOURCE_DIR}/src/nvim/eval.lua)
-set(OPTIONS_LIST_FILE ${PROJECT_SOURCE_DIR}/src/nvim/options.lua)
set(UNICODE_TABLES_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genunicodetables.lua)
set(UNICODE_DIR ${PROJECT_SOURCE_DIR}/unicode)
set(GENERATED_UNICODE_TABLES ${GENERATED_DIR}/unicode_tables.generated.h)
set(VIM_MODULE_FILE ${GENERATED_DIR}/viml/executor/vim_module.generated.h)
set(VIM_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/src/nvim/viml/executor/vim.lua)
set(CHAR_BLOB_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gencharblob.lua)
+set(LINT_SUPPRESS_FILE ${PROJECT_BINARY_DIR}/errors.json)
+set(LINT_SUPPRESS_URL_BASE "https://raw.githubusercontent.com/neovim/doc/gh-pages/reports/clint")
+set(LINT_SUPPRESS_URL "${LINT_SUPPRESS_URL_BASE}/errors.json")
+set(LINT_PRG ${PROJECT_SOURCE_DIR}/src/clint.py)
+set(DOWNLOAD_SCRIPT ${PROJECT_SOURCE_DIR}/cmake/Download.cmake)
+set(LINT_SUPPRESSES_ROOT ${PROJECT_BINARY_DIR}/errors)
+set(LINT_SUPPRESSES_URL "https://raw.githubusercontent.com/neovim/doc/gh-pages/reports/clint/errors.tar.gz")
+file(GLOB UNICODE_FILES ${UNICODE_DIR}/*.txt)
file(GLOB API_HEADERS api/*.h)
file(GLOB MSGPACK_RPC_HEADERS msgpack_rpc/*.h)
-file(GLOB UNICODE_FILES ${UNICODE_DIR}/*.txt)
include_directories(${GENERATED_DIR})
include_directories(${CACHED_GENERATED_DIR})
include_directories(${GENERATED_INCLUDES_DIR})
+file(MAKE_DIRECTORY ${TOUCHES_DIR})
file(MAKE_DIRECTORY ${GENERATED_DIR})
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR})
-file(GLOB NEOVIM_SOURCES *.c)
+file(GLOB NVIM_SOURCES *.c)
+file(GLOB NVIM_HEADERS *.h)
foreach(subdir
os
@@ -72,18 +77,21 @@ foreach(subdir
file(MAKE_DIRECTORY ${GENERATED_DIR}/${subdir})
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/${subdir})
file(GLOB sources ${subdir}/*.c)
- list(APPEND NEOVIM_SOURCES ${sources})
+ file(GLOB headers ${subdir}/*.h)
+ list(APPEND NVIM_SOURCES ${sources})
+ list(APPEND NVIM_HEADERS ${headers})
endforeach()
-file(GLOB_RECURSE NEOVIM_HEADERS *.h)
file(GLOB UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c)
# Sort file lists to ensure generated files are created in the same order from
# build to build.
-list(SORT NEOVIM_SOURCES)
-list(SORT NEOVIM_HEADERS)
+list(SORT NVIM_SOURCES)
+list(SORT NVIM_HEADERS)
-foreach(sfile ${NEOVIM_SOURCES})
+list(APPEND LINT_NVIM_SOURCES ${NVIM_SOURCES} ${NVIM_HEADERS})
+
+foreach(sfile ${NVIM_SOURCES})
get_filename_component(f ${sfile} NAME)
if(${f} MATCHES "^(regexp_nfa.c)$")
list(APPEND to_remove ${sfile})
@@ -93,7 +101,7 @@ foreach(sfile ${NEOVIM_SOURCES})
endif()
endforeach()
-list(REMOVE_ITEM NEOVIM_SOURCES ${to_remove})
+list(REMOVE_ITEM NVIM_SOURCES ${to_remove})
# Legacy files that do not yet pass -Wconversion.
set(CONV_SOURCES
@@ -117,7 +125,7 @@ set(CONV_SOURCES
window.c)
foreach(sfile ${CONV_SOURCES})
- if(NOT EXISTS "${PROJECT_SOURCE_DIR}/src/nvim/${sfile}")
+ if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/${sfile}")
message(FATAL_ERROR "${sfile} doesn't exist (it was added to CONV_SOURCES)")
endif()
endforeach()
@@ -159,12 +167,24 @@ separate_arguments(C_FLAGS_ARRAY UNIX_COMMAND ${CMAKE_C_FLAGS})
separate_arguments(C_FLAGS_${build_type}_ARRAY UNIX_COMMAND ${CMAKE_C_FLAGS_${build_type}})
set(gen_cflags ${gen_cflags} ${C_FLAGS_${build_type}_ARRAY} ${C_FLAGS_ARRAY})
-foreach(sfile ${NEOVIM_SOURCES}
- "${PROJECT_SOURCE_DIR}/src/nvim/regexp_nfa.c"
+function(get_preproc_output varname iname)
+ if(MSVC)
+ set(${varname} /P /Fi${iname} PARENT_SCOPE)
+ else()
+ set(${varname} -E -o ${iname} PARENT_SCOPE)
+ endif()
+endfunction()
+
+# NVIM_GENERATED_FOR_HEADERS: generated headers to be included in headers
+# NVIM_GENERATED_FOR_SOURCES: generated headers to be included in sources
+# NVIM_GENERATED_SOURCES: generated source files
+# These lists must be mutually exclusive.
+foreach(sfile ${NVIM_SOURCES}
+ "${CMAKE_CURRENT_LIST_DIR}/regexp_nfa.c"
${GENERATED_API_DISPATCH})
get_filename_component(full_d ${sfile} PATH)
- file(RELATIVE_PATH d "${PROJECT_SOURCE_DIR}/src/nvim" "${full_d}")
- if(${d} MATCHES "^([.][.]|auto/)")
+ file(RELATIVE_PATH d "${CMAKE_CURRENT_LIST_DIR}" "${full_d}")
+ if(${d} MATCHES "^[.][.]|auto/")
file(RELATIVE_PATH d "${GENERATED_DIR}" "${full_d}")
endif()
get_filename_component(f ${sfile} NAME)
@@ -173,26 +193,22 @@ foreach(sfile ${NEOVIM_SOURCES}
set(f "${d}/${f}")
set(r "${d}/${r}")
endif()
- set(gf1 "${GENERATED_DIR}/${r}.c.generated.h")
- set(gf2 "${GENERATED_INCLUDES_DIR}/${r}.h.generated.h")
- set(gf3 "${GENERATED_DIR}/${r}.i")
+ set(gf_c_h "${GENERATED_DIR}/${r}.c.generated.h")
+ set(gf_h_h "${GENERATED_INCLUDES_DIR}/${r}.h.generated.h")
+ set(gf_i "${GENERATED_DIR}/${r}.i")
- if(MSVC)
- set(PREPROC_OUTPUT /P /Fi${gf3})
- else()
- set(PREPROC_OUTPUT -E -o ${gf3})
- endif()
+ get_preproc_output(PREPROC_OUTPUT ${gf_i})
add_custom_command(
- OUTPUT "${gf1}" "${gf2}"
+ OUTPUT "${gf_c_h}" "${gf_h_h}"
COMMAND ${CMAKE_C_COMPILER} ${sfile} ${PREPROC_OUTPUT} ${gen_cflags} ${C_FLAGS_ARRAY}
- COMMAND "${LUA_PRG}" "${HEADER_GENERATOR}" "${sfile}" "${gf1}" "${gf2}" "${gf3}"
+ COMMAND "${LUA_PRG}" "${HEADER_GENERATOR}" "${sfile}" "${gf_c_h}" "${gf_h_h}" "${gf_i}"
DEPENDS "${HEADER_GENERATOR}" "${sfile}"
)
- list(APPEND NEOVIM_GENERATED_SOURCES "${gf1}")
- list(APPEND NEOVIM_GENERATED_SOURCES "${gf2}")
+ list(APPEND NVIM_GENERATED_FOR_SOURCES "${gf_c_h}")
+ list(APPEND NVIM_GENERATED_FOR_HEADERS "${gf_h_h}")
if(${d} MATCHES "^api$" AND NOT ${f} MATCHES "^api/helpers.c$")
- list(APPEND API_HEADERS ${gf2})
+ list(APPEND API_HEADERS ${gf_h_h})
endif()
endforeach()
@@ -229,23 +245,32 @@ add_custom_command(
${VIM_MODULE_SOURCE}
)
-list(APPEND NEOVIM_GENERATED_SOURCES
- "${PROJECT_BINARY_DIR}/config/auto/pathdef.c"
- "${GENERATED_API_DISPATCH}"
+list(APPEND NVIM_GENERATED_SOURCES
+ "${MSGPACK_LUA_C_BINDINGS}"
+)
+
+list(APPEND NVIM_GENERATED_FOR_HEADERS
"${GENERATED_EX_CMDS_ENUM}"
- "${GENERATED_EX_CMDS_DEFS}"
"${GENERATED_EVENTS_ENUM}"
+)
+
+list(APPEND NVIM_GENERATED_FOR_SOURCES
+ "${GENERATED_API_DISPATCH}"
+ "${GENERATED_EX_CMDS_DEFS}"
"${GENERATED_EVENTS_NAMES_MAP}"
"${GENERATED_OPTIONS}"
"${GENERATED_UNICODE_TABLES}"
- "${MSGPACK_LUA_C_BINDINGS}"
"${VIM_MODULE_FILE}"
)
+list(APPEND NVIM_GENERATED_SOURCES
+ "${PROJECT_BINARY_DIR}/config/auto/pathdef.c"
+)
+
add_custom_command(OUTPUT ${GENERATED_EX_CMDS_ENUM} ${GENERATED_EX_CMDS_DEFS}
COMMAND ${LUA_PRG} ${EX_CMDS_GENERATOR}
- ${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_INCLUDES_DIR} ${GENERATED_DIR}
- DEPENDS ${EX_CMDS_GENERATOR} ${EX_CMDS_DEFS_FILE}
+ ${CMAKE_CURRENT_LIST_DIR} ${GENERATED_INCLUDES_DIR} ${GENERATED_DIR}
+ DEPENDS ${EX_CMDS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/ex_cmds.lua
)
if(NOT GPERF_PRG)
@@ -253,26 +278,34 @@ if(NOT GPERF_PRG)
endif()
add_custom_command(OUTPUT ${GENERATED_FUNCS} ${FUNCS_DATA}
COMMAND ${LUA_PRG} ${FUNCS_GENERATOR}
- ${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_DIR} ${API_METADATA} ${FUNCS_DATA}
+ ${CMAKE_CURRENT_LIST_DIR} ${GENERATED_DIR} ${API_METADATA} ${FUNCS_DATA}
COMMAND ${GPERF_PRG}
- ${GENERATED_FUNCS_HASH_INPUT} --output-file=${GENERATED_FUNCS}
- DEPENDS ${FUNCS_GENERATOR} ${EVAL_DEFS_FILE} ${API_METADATA}
+ ${GENERATED_DIR}/funcs.generated.h.gperf --output-file=${GENERATED_FUNCS}
+ DEPENDS ${FUNCS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/eval.lua ${API_METADATA}
)
-list(APPEND NEOVIM_GENERATED_SOURCES
+list(APPEND NVIM_GENERATED_FOR_SOURCES
"${GENERATED_FUNCS}")
add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
COMMAND ${LUA_PRG} ${EVENTS_GENERATOR}
- ${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
- DEPENDS ${EVENTS_GENERATOR} ${EVENTS_LIST_FILE}
+ ${CMAKE_CURRENT_LIST_DIR} ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
+ DEPENDS ${EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/auevents.lua
)
add_custom_command(OUTPUT ${GENERATED_OPTIONS}
COMMAND ${LUA_PRG} ${OPTIONS_GENERATOR}
- ${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_OPTIONS}
- DEPENDS ${OPTIONS_GENERATOR} ${OPTIONS_LIST_FILE}
+ ${CMAKE_CURRENT_LIST_DIR} ${GENERATED_OPTIONS}
+ DEPENDS ${OPTIONS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/options.lua
)
+# NVIM_GENERATED_FOR_SOURCES and NVIM_GENERATED_FOR_HEADERS must be mutually exclusive.
+foreach(hfile ${NVIM_GENERATED_FOR_HEADERS})
+ list(FIND NVIM_GENERATED_FOR_SOURCES ${hfile} hfile_idx)
+ if(NOT ${hfile_idx} EQUAL -1)
+ message(FATAL_ERROR "File included in both NVIM_GENERATED_FOR_HEADERS and NVIM_GENERATED_FOR_SOURCES")
+ endif()
+endforeach()
+
# Our dependencies come first.
if (LibIntl_FOUND)
@@ -315,8 +348,8 @@ if(JEMALLOC_FOUND)
list(APPEND NVIM_EXEC_LINK_LIBRARIES ${JEMALLOC_LIBRARIES})
endif()
-add_executable(nvim ${NEOVIM_GENERATED_SOURCES} ${NEOVIM_SOURCES}
- ${NEOVIM_HEADERS})
+add_executable(nvim ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
+ ${NVIM_GENERATED_SOURCES} ${NVIM_SOURCES} ${NVIM_HEADERS})
target_link_libraries(nvim ${NVIM_EXEC_LINK_LIBRARIES})
install_helper(TARGETS nvim)
@@ -374,26 +407,49 @@ if(WIN32)
add_dependencies(nvim_runtime_deps external_blobs)
endif()
-add_library(libnvim STATIC EXCLUDE_FROM_ALL ${NEOVIM_GENERATED_SOURCES}
- ${NEOVIM_SOURCES} ${NEOVIM_HEADERS})
+add_library(
+ libnvim
+ STATIC
+ EXCLUDE_FROM_ALL
+ ${NVIM_SOURCES} ${NVIM_GENERATED_SOURCES}
+ ${NVIM_HEADERS} ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
+)
set_property(TARGET libnvim APPEND PROPERTY
INCLUDE_DIRECTORIES ${LUAJIT_INCLUDE_DIRS})
target_link_libraries(libnvim ${NVIM_TEST_LINK_LIBRARIES})
-set_target_properties(libnvim PROPERTIES
- POSITION_INDEPENDENT_CODE ON
- OUTPUT_NAME nvim)
-set_property(TARGET libnvim
- APPEND_STRING PROPERTY COMPILE_FLAGS " -DMAKE_LIB ")
-
-add_library(nvim-test MODULE EXCLUDE_FROM_ALL ${NEOVIM_GENERATED_SOURCES}
- ${NEOVIM_SOURCES} ${UNIT_TEST_FIXTURES} ${NEOVIM_HEADERS})
+set_target_properties(
+ libnvim
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON
+ OUTPUT_NAME nvim
+)
+set_property(
+ TARGET libnvim
+ APPEND_STRING PROPERTY COMPILE_FLAGS " -DMAKE_LIB "
+)
+
+add_library(
+ nvim-test
+ MODULE
+ EXCLUDE_FROM_ALL
+ ${NVIM_SOURCES} ${NVIM_GENERATED_SOURCES}
+ ${NVIM_HEADERS} ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
+ ${UNIT_TEST_FIXTURES}
+)
target_link_libraries(nvim-test ${NVIM_TEST_LINK_LIBRARIES})
-set_property(TARGET nvim-test APPEND PROPERTY
- INCLUDE_DIRECTORIES ${LUAJIT_INCLUDE_DIRS})
-set_target_properties(nvim-test PROPERTIES
- POSITION_INDEPENDENT_CODE ON)
-set_property(TARGET nvim-test
- APPEND_STRING PROPERTY COMPILE_FLAGS " -DUNIT_TESTING ")
+set_property(
+ TARGET nvim-test
+ APPEND PROPERTY INCLUDE_DIRECTORIES ${LUAJIT_INCLUDE_DIRS}
+)
+set_target_properties(
+ nvim-test
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON
+)
+set_property(
+ TARGET nvim-test
+ APPEND_STRING PROPERTY COMPILE_FLAGS " -DUNIT_TESTING "
+)
if(CLANG_ASAN_UBSAN)
message(STATUS "Enabling Clang address sanitizer and undefined behavior sanitizer for nvim.")
@@ -419,4 +475,132 @@ elseif(CLANG_TSAN)
set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=thread ")
endif()
+function(get_test_target prefix sfile relative_path_var target_var)
+ get_filename_component(full_d "${sfile}" PATH)
+ file(RELATIVE_PATH d "${PROJECT_SOURCE_DIR}/src/nvim" "${full_d}")
+ if(d MATCHES "^[.][.]")
+ file(RELATIVE_PATH d "${GENERATED_DIR}" "${full_d}")
+ endif()
+ get_filename_component(r "${sfile}" NAME)
+ if(NOT d MATCHES "^[.]?$")
+ set(r "${d}/${r}")
+ endif()
+ string(REGEX REPLACE "[/.]" "-" suffix "${r}")
+ set(${relative_path_var} ${r} PARENT_SCOPE)
+ if(prefix STREQUAL "")
+ set(${target_var} "${suffix}" PARENT_SCOPE)
+ else()
+ set(${target_var} "${prefix}-${suffix}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+set(NO_SINGLE_CHECK_HEADERS
+ cursor_shape.h
+ digraph.h
+ ex_cmds.h
+ ex_getln.h
+ file_search.h
+ fold.h
+ getchar.h
+ hardcopy.h
+ if_cscope.h
+ if_cscope_defs.h
+ mark.h
+ mbyte.h
+ memfile_defs.h
+ memline.h
+ memline_defs.h
+ menu.h
+ misc2.h
+ move.h
+ msgpack_rpc/server.h
+ ops.h
+ option.h
+ os/shell.h
+ os_unix.h
+ os/win_defs.h
+ popupmnu.h
+ quickfix.h
+ regexp.h
+ regexp_defs.h
+ screen.h
+ search.h
+ sha256.h
+ sign_defs.h
+ spell.h
+ spellfile.h
+ syntax.h
+ syntax_defs.h
+ tag.h
+ terminal.h
+ tui/tui.h
+ ugrid.h
+ ui.h
+ ui_bridge.h
+ undo.h
+ undo_defs.h
+ version.h
+ window.h
+)
+foreach(hfile ${NVIM_HEADERS})
+ get_test_target(test-includes "${hfile}" relative_path texe)
+
+ if(NOT ${hfile} MATCHES "[.]c[.]h$")
+ set(tsource "${GENERATED_DIR}/${relative_path}.test-include.c")
+ write_file("${tsource}" "#include \"${hfile}\"\nint main(int argc, char **argv) { return 0; }")
+ add_executable(
+ ${texe}
+ EXCLUDE_FROM_ALL
+ ${tsource} ${NVIM_HEADERS} ${NVIM_GENERATED_FOR_HEADERS})
+
+ list(FIND NO_SINGLE_CHECK_HEADERS "${relative_path}" hfile_exclude_idx)
+ if(${hfile_exclude_idx} EQUAL -1)
+ list(APPEND HEADER_CHECK_TARGETS ${texe})
+ endif()
+ endif()
+endforeach()
+add_custom_target(check-single-includes DEPENDS ${HEADER_CHECK_TARGETS})
+
+function(add_download output url allow_failure)
+ add_custom_command(
+ OUTPUT "${output}"
+ COMMAND
+ ${CMAKE_COMMAND}
+ -DURL=${url} -DFILE=${output}
+ -DALLOW_FAILURE=${allow_failure}
+ -P ${DOWNLOAD_SCRIPT}
+ DEPENDS ${DOWNLOAD_SCRIPT}
+ )
+endfunction()
+
+add_download(${LINT_SUPPRESS_FILE} ${LINT_SUPPRESS_URL} off)
+
+set(LINT_NVIM_REL_SOURCES)
+foreach(sfile ${LINT_NVIM_SOURCES})
+ get_test_target("" "${sfile}" r suffix)
+ set(suppress_file ${LINT_SUPPRESSES_ROOT}/${suffix}.json)
+ set(suppress_url "${LINT_SUPPRESS_URL_BASE}/${suffix}.json")
+ set(rsfile src/nvim/${r})
+ add_download(${suppress_file} ${suppress_url} on)
+ set(touch_file "${TOUCHES_DIR}/ran-clint-${suffix}")
+ add_custom_command(
+ OUTPUT ${touch_file}
+ COMMAND ${LINT_PRG} --suppress-errors=${suppress_file} ${rsfile}
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+ COMMAND ${CMAKE_COMMAND} -E touch ${touch_file}
+ DEPENDS ${LINT_PRG} ${sfile} ${suppress_file}
+ )
+ list(APPEND LINT_TARGETS ${touch_file})
+ list(APPEND LINT_NVIM_REL_SOURCES ${rsfile})
+endforeach()
+add_custom_target(clint DEPENDS ${LINT_TARGETS})
+
+add_custom_target(
+ clint-full
+ COMMAND
+ ${LINT_PRG} --suppress-errors=${LINT_SUPPRESS_FILE} ${LINT_NVIM_REL_SOURCES}
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+ DEPENDS ${LINT_PRG} ${LINT_NVIM_SOURCES} ${LINT_SUPPRESS_FILE}
+)
+
add_subdirectory(po)
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 5eda88025f..611f29f1f2 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -296,7 +296,7 @@ void nvim_buf_set_lines(uint64_t channel_id,
tabpage_T *save_curtab = NULL;
size_t new_len = replacement.size;
size_t old_len = (size_t)(end - start);
- ssize_t extra = 0; // lines added to text, can be negative
+ ptrdiff_t extra = 0; // lines added to text, can be negative
char **lines = (new_len != 0) ? xcalloc(new_len, sizeof(char *)) : NULL;
for (size_t i = 0; i < new_len; i++) {
@@ -342,8 +342,8 @@ void nvim_buf_set_lines(uint64_t channel_id,
}
}
- if ((ssize_t)to_delete > 0) {
- extra -= (ssize_t)to_delete;
+ if (to_delete > 0) {
+ extra -= (ptrdiff_t)to_delete;
}
// For as long as possible, replace the existing old_len with the
@@ -395,10 +395,10 @@ void nvim_buf_set_lines(uint64_t channel_id,
mark_adjust((linenr_T)start, (linenr_T)(end - 1), MAXLNUM, extra);
}
- changed_lines((linenr_T)start, 0, (linenr_T)end, extra);
+ changed_lines((linenr_T)start, 0, (linenr_T)end, (long)extra);
if (save_curbuf.br_buf == NULL) {
- fix_cursor((linenr_T)start, (linenr_T)end, extra);
+ fix_cursor((linenr_T)start, (linenr_T)end, (linenr_T)extra);
}
end:
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 373e509120..7b898bc044 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -14,6 +14,7 @@
#include "nvim/window.h"
#include "nvim/memory.h"
#include "nvim/eval.h"
+#include "nvim/eval/typval.h"
#include "nvim/map_defs.h"
#include "nvim/map.h"
#include "nvim/option.h"
@@ -87,14 +88,13 @@ bool try_end(Error *err)
/// @param[out] err Details of an error that may have occurred
Object dict_get_value(dict_T *dict, String key, Error *err)
{
- hashitem_T *hi = hash_find(&dict->dv_hashtab, (uint8_t *) key.data);
+ dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size);
- if (HASHITEM_EMPTY(hi)) {
+ if (di == NULL) {
api_set_error(err, Validation, _("Key not found"));
return (Object) OBJECT_INIT;
}
- dictitem_T *di = dict_lookup(hi);
return vim_to_object(&di->di_tv);
}
@@ -129,7 +129,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del,
return rv;
}
- dictitem_T *di = dict_find(dict, (char_u *)key.data, (int)key.size);
+ dictitem_T *di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size);
if (di != NULL) {
if (di->di_flags & DI_FLAGS_RO) {
@@ -155,9 +155,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del,
rv = vim_to_object(&di->di_tv);
}
// Delete the entry
- hashitem_T *hi = hash_find(&dict->dv_hashtab, di->di_key);
- hash_remove(&dict->dv_hashtab, hi);
- dictitem_free(di);
+ tv_dict_item_remove(dict, di);
}
} else {
// Update the key
@@ -170,20 +168,20 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del,
if (di == NULL) {
// Need to create an entry
- di = dictitem_alloc((uint8_t *) key.data);
- dict_add(dict, di);
+ di = tv_dict_item_alloc_len(key.data, key.size);
+ tv_dict_add(dict, di);
} else {
// Return the old value
if (retval) {
rv = vim_to_object(&di->di_tv);
}
- clear_tv(&di->di_tv);
+ tv_clear(&di->di_tv);
}
// Update the value
- copy_tv(&tv, &di->di_tv);
+ tv_copy(&tv, &di->di_tv);
// Clear the temporary variable
- clear_tv(&tv);
+ tv_clear(&tv);
}
return rv;
@@ -291,7 +289,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
}
}
- int opt_flags = (type ? OPT_LOCAL : OPT_GLOBAL);
+ int opt_flags = (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL;
if (flags & SOPT_BOOL) {
if (value.type != kObjectTypeBoolean) {
@@ -627,7 +625,7 @@ String cstr_as_string(char *str) FUNC_ATTR_PURE
if (str == NULL) {
return (String) STRING_INIT;
}
- return (String) {.data = str, .size = strlen(str)};
+ return (String) { .data = str, .size = strlen(str) };
}
/// Converts from type Object to a VimL value.
@@ -682,20 +680,20 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
break;
case kObjectTypeArray: {
- list_T *list = list_alloc();
+ list_T *const list = tv_list_alloc();
for (uint32_t i = 0; i < obj.data.array.size; i++) {
Object item = obj.data.array.items[i];
- listitem_T *li = listitem_alloc();
+ listitem_T *li = tv_list_item_alloc();
if (!object_to_vim(item, &li->li_tv, err)) {
// cleanup
- listitem_free(li);
- list_free(list);
+ tv_list_item_free(li);
+ tv_list_free(list);
return false;
}
- list_append(list, li);
+ tv_list_append(list, li);
}
list->lv_refcount++;
@@ -705,7 +703,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
}
case kObjectTypeDictionary: {
- dict_T *dict = dict_alloc();
+ dict_T *const dict = tv_dict_alloc();
for (uint32_t i = 0; i < obj.data.dictionary.size; i++) {
KeyValuePair item = obj.data.dictionary.items[i];
@@ -715,20 +713,20 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
api_set_error(err, Validation,
_("Empty dictionary keys aren't allowed"));
// cleanup
- dict_free(dict);
+ tv_dict_free(dict);
return false;
}
- dictitem_T *di = dictitem_alloc((uint8_t *)key.data);
+ dictitem_T *const di = tv_dict_item_alloc(key.data);
if (!object_to_vim(item.value, &di->di_tv, err)) {
// cleanup
- dictitem_free(di);
- dict_free(dict);
+ tv_dict_item_free(di);
+ tv_dict_free(dict);
return false;
}
- dict_add(dict, di);
+ tv_dict_add(dict, di);
}
dict->dv_refcount++;
@@ -962,11 +960,7 @@ static void set_option_value_err(char *key,
{
char *errmsg;
- if ((errmsg = (char *)set_option_value((uint8_t *)key,
- numval,
- (uint8_t *)stringval,
- opt_flags)))
- {
+ if ((errmsg = set_option_value(key, numval, stringval, opt_flags))) {
if (try_end(err)) {
return;
}
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 625bcc6b4b..de60339e5f 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -12,6 +12,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/popupmnu.h"
+#include "nvim/cursor_shape.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/ui.c.generated.h"
@@ -69,6 +70,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->clear = remote_ui_clear;
ui->eol_clear = remote_ui_eol_clear;
ui->cursor_goto = remote_ui_cursor_goto;
+ ui->cursor_style_set = remote_ui_cursor_style_set;
ui->update_menu = remote_ui_update_menu;
ui->busy_start = remote_ui_busy_start;
ui->busy_stop = remote_ui_busy_stop;
@@ -298,6 +300,14 @@ static void remote_ui_scroll(UI *ui, int count)
push_call(ui, "scroll", args);
}
+static void remote_ui_cursor_style_set(UI *ui, bool enabled, Dictionary data)
+{
+ Array args = ARRAY_DICT_INIT;
+ ADD(args, BOOLEAN_OBJ(enabled));
+ ADD(args, copy_object(DICTIONARY_OBJ(data)));
+ push_call(ui, "cursor_style_set", args);
+}
+
static void remote_ui_highlight_set(UI *ui, HlAttrs attrs)
{
Array args = ARRAY_DICT_INIT;
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 3fd1f57ace..511c87f408 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -22,6 +22,7 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/eval.h"
+#include "nvim/eval/typval.h"
#include "nvim/option.h"
#include "nvim/syntax.h"
#include "nvim/getchar.h"
@@ -181,19 +182,20 @@ Object nvim_eval(String expr, Error *err)
Object rv = OBJECT_INIT;
// Evaluate the expression
try_start();
- typval_T *expr_result = eval_expr((char_u *)expr.data, NULL);
- if (!expr_result) {
- api_set_error(err, Exception, _("Failed to evaluate expression"));
+ typval_T rettv;
+ if (eval0((char_u *)expr.data, &rettv, NULL, true) == FAIL) {
+ api_set_error(err, Exception, "Failed to evaluate expression");
}
if (!try_end(err)) {
// No errors, convert the result
- rv = vim_to_object(expr_result);
+ rv = vim_to_object(&rettv);
}
- // Free the vim object
- free_tv(expr_result);
+ // Free the Vim object
+ tv_clear(&rettv);
+
return rv;
}
@@ -238,11 +240,11 @@ Object nvim_call_function(String fname, Array args, Error *err)
if (!try_end(err)) {
rv = vim_to_object(&rettv);
}
- clear_tv(&rettv);
+ tv_clear(&rettv);
free_vim_args:
while (i > 0) {
- clear_tv(&vim_args[--i]);
+ tv_clear(&vim_args[--i]);
}
return rv;
@@ -439,7 +441,7 @@ Object nvim_get_vvar(String name, Error *err)
///
/// @param name Option name
/// @param[out] err Error details, if any
-/// @return Option value
+/// @return Option value (global)
Object nvim_get_option(String name, Error *err)
FUNC_API_SINCE(1)
{
diff --git a/src/nvim/ascii.h b/src/nvim/ascii.h
index 44ff540b40..adde91f9ec 100644
--- a/src/nvim/ascii.h
+++ b/src/nvim/ascii.h
@@ -8,9 +8,11 @@
// Definitions of various common control characters.
-#define CharOrd(x) ((x) < 'a' ? (x) - 'A' : (x) - 'a')
-#define CharOrdLow(x) ((x) - 'a')
-#define CharOrdUp(x) ((x) - 'A')
+#define CharOrd(x) ((uint8_t)(x) < 'a' \
+ ? (uint8_t)(x) - 'A'\
+ : (uint8_t)(x) - 'a')
+#define CharOrdLow(x) ((uint8_t)(x) - 'a')
+#define CharOrdUp(x) ((uint8_t)(x) - 'A')
#define ROT13(c, a) (((((c) - (a)) + 13) % 26) + (a))
#define NUL '\000'
@@ -18,15 +20,14 @@
#define BS '\010'
#define TAB '\011'
#define NL '\012'
-#define NL_STR (char_u *)"\012"
+#define NL_STR "\012"
#define FF '\014'
#define CAR '\015' /* CR is used by Mac OS X */
#define ESC '\033'
-#define ESC_STR (char_u *)"\033"
-#define ESC_STR_nc "\033"
+#define ESC_STR "\033"
#define DEL 0x7f
-#define DEL_STR (char_u *)"\177"
-#define CSI 0x9b /* Control Sequence Introducer */
+#define DEL_STR "\177"
+#define CSI 0x9b // Control Sequence Introducer
#define CSI_STR "\233"
#define DCS 0x90 /* Device Control String */
#define STERM 0x9c /* String Terminator */
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 3c416c157f..292eb03a16 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -627,10 +627,11 @@ void buf_freeall(buf_T *buf, int flags)
*/
if (buf == curbuf && !is_curbuf)
return;
- diff_buf_delete(buf); /* Can't use 'diff' for unloaded buffer. */
- /* Remove any ownsyntax, unless exiting. */
- if (firstwin != NULL && curwin->w_buffer == buf)
+ diff_buf_delete(buf); // Can't use 'diff' for unloaded buffer.
+ // Remove any ownsyntax, unless exiting.
+ if (curwin != NULL && curwin->w_buffer == buf) {
reset_synblock(curwin);
+ }
/* No folds in an empty buffer. */
FOR_ALL_TAB_WINDOWS(tp, win) {
@@ -660,7 +661,7 @@ static void free_buffer(buf_T *buf)
free_buffer_stuff(buf, true);
unref_var_dict(buf->b_vars);
aubuflocal_remove(buf);
- dict_unref(buf->additional_data);
+ tv_dict_unref(buf->additional_data);
clear_fmark(&buf->b_last_cursor);
clear_fmark(&buf->b_last_insert);
clear_fmark(&buf->b_last_change);
@@ -1471,7 +1472,7 @@ static inline void buf_init_changedtick(buf_T *const buf)
{
STATIC_ASSERT(sizeof("changedtick") <= sizeof(buf->changedtick_di.di_key),
"buf->changedtick_di cannot hold large enough keys");
- buf->changedtick_di = (dictitem16_T) {
+ buf->changedtick_di = (ChangedtickDictItem) {
.di_flags = DI_FLAGS_RO|DI_FLAGS_FIX, // Must not include DI_FLAGS_ALLOC.
.di_tv = (typval_T) {
.v_type = VAR_NUMBER,
@@ -1480,7 +1481,7 @@ static inline void buf_init_changedtick(buf_T *const buf)
},
.di_key = "changedtick",
};
- dict_add(buf->b_vars, (dictitem_T *)&buf->changedtick_di);
+ tv_dict_add(buf->b_vars, (dictitem_T *)&buf->changedtick_di);
}
/// Add a file name to the buffer list.
@@ -1572,7 +1573,7 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags)
if (buf != curbuf || curbuf == NULL) {
buf = xcalloc(1, sizeof(buf_T));
// init b: variables
- buf->b_vars = dict_alloc();
+ buf->b_vars = tv_dict_alloc();
init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
buf_init_changedtick(buf);
}
@@ -2723,7 +2724,7 @@ fileinfo (
else
name = curbuf->b_ffname;
home_replace(shorthelp ? curbuf : NULL, name, p,
- (int)(IOSIZE - (p - buffer)), TRUE);
+ (size_t)(IOSIZE - (p - buffer)), true);
}
vim_snprintf_add((char *)buffer, IOSIZE, "\"%s%s%s%s%s%s",
@@ -2888,7 +2889,7 @@ void maketitle(void)
buf[off++] = ' ';
buf[off++] = '(';
home_replace(curbuf, curbuf->b_ffname,
- buf + off, SPACE_FOR_DIR - off, TRUE);
+ buf + off, (size_t)(SPACE_FOR_DIR - off), true);
#ifdef BACKSLASH_IN_FILENAME
/* avoid "c:/name" to be reduced to "c" */
if (isalpha(buf[off]) && buf[off + 1] == ':')
@@ -3503,7 +3504,7 @@ int build_stl_str_hl(
curbuf = o_curbuf;
// Remove the variable we just stored
- do_unlet((char_u *)"g:actual_curbuf", true);
+ do_unlet(S_LEN("g:actual_curbuf"), true);
// }
@@ -4206,11 +4207,11 @@ void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname)
#ifdef WIN32
if (!buf->b_p_bin) {
// If the file name is a shortcut file, use the file it links to.
- char_u *rfname = (char_u *)os_resolve_shortcut(*ffname);
+ char *rfname = os_resolve_shortcut((const char *)(*ffname));
if (rfname != NULL) {
xfree(*ffname);
- *ffname = rfname;
- *sfname = rfname;
+ *ffname = (char_u *)rfname;
+ *sfname = (char_u *)rfname;
}
}
#endif
@@ -5442,8 +5443,8 @@ void buf_open_scratch(handle_T bufnr, char *bufname)
{
(void)do_ecmd((int)bufnr, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL);
(void)setfname(curbuf, (char_u *)bufname, NULL, true);
- set_option_value((char_u *)"bh", 0L, (char_u *)"hide", OPT_LOCAL);
- set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL);
- set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
+ set_option_value("bh", 0L, "hide", OPT_LOCAL);
+ set_option_value("bt", 0L, "nofile", OPT_LOCAL);
+ set_option_value("swf", 0L, NULL, OPT_LOCAL);
RESET_BINDING(curwin);
}
diff --git a/src/nvim/buffer.h b/src/nvim/buffer.h
index ed3e6ab6cc..016c5ce3b7 100644
--- a/src/nvim/buffer.h
+++ b/src/nvim/buffer.h
@@ -1,12 +1,14 @@
#ifndef NVIM_BUFFER_H
#define NVIM_BUFFER_H
+#include "nvim/vim.h"
#include "nvim/window.h"
#include "nvim/pos.h" // for linenr_T
#include "nvim/ex_cmds_defs.h" // for exarg_T
#include "nvim/screen.h" // for StlClickRecord
#include "nvim/func_attr.h"
#include "nvim/eval.h"
+#include "nvim/macros.h"
// Values for buflist_getfile()
enum getf_values {
@@ -91,8 +93,8 @@ static inline void buf_set_changedtick(buf_T *const buf, const int changedtick)
static inline void buf_set_changedtick(buf_T *const buf, const int changedtick)
{
#ifndef NDEBUG
- dictitem_T *const changedtick_di = dict_find(
- buf->b_vars, (char_u *)"changedtick", sizeof("changedtick") - 1);
+ dictitem_T *const changedtick_di = tv_dict_find(
+ buf->b_vars, S_LEN("changedtick"));
assert(changedtick_di != NULL);
assert(changedtick_di->di_tv.v_type == VAR_NUMBER);
assert(changedtick_di->di_tv.v_lock == VAR_FIXED);
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 9d350c763e..20a2b931bd 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -21,8 +21,6 @@ typedef struct {
#include "nvim/pos.h"
// for the number window-local and buffer-local options
#include "nvim/option_defs.h"
-// for optional iconv support
-#include "nvim/iconv.h"
// for jump list and tag stack sizes in a buffer and mark types
#include "nvim/mark_defs.h"
// for u_header_T; needs buf_T.
@@ -30,7 +28,9 @@ typedef struct {
// for hashtab_T
#include "nvim/hashtab.h"
// for dict_T
-#include "nvim/eval_defs.h"
+#include "nvim/eval/typval.h"
+// for proftime_T
+#include "nvim/profile.h"
// for String
#include "nvim/api/private/defs.h"
// for Map(K, V)
@@ -319,25 +319,6 @@ typedef struct {
} tasave_T;
/*
- * Used for conversion of terminal I/O and script files.
- */
-typedef struct {
- int vc_type; /* zero or one of the CONV_ values */
- int vc_factor; /* max. expansion factor */
-# ifdef USE_ICONV
- iconv_t vc_fd; /* for CONV_ICONV */
-# endif
- bool vc_fail; /* fail for invalid char, don't use '?' */
-} vimconv_T;
-
-#define CONV_NONE 0
-#define CONV_TO_UTF8 1
-#define CONV_9_TO_UTF8 2
-#define CONV_TO_LATIN1 3
-#define CONV_TO_LATIN9 4
-#define CONV_ICONV 5
-
-/*
* Structure used for mappings and abbreviations.
*/
typedef struct mapblock mapblock_T;
@@ -447,6 +428,10 @@ typedef struct {
char_u *b_syn_isk; // iskeyword option
} synblock_T;
+/// Type used for changedtick_di member in buf_T
+///
+/// Primary exists so that literals of relevant type can be made.
+typedef TV_DICTITEM_STRUCT(sizeof("changedtick")) ChangedtickDictItem;
#define BUF_HAS_QF_ENTRY 1
#define BUF_HAS_LL_ENTRY 2
@@ -491,7 +476,7 @@ struct file_buffer {
// file has been changed and not written out.
/// Change identifier incremented for each change, including undo
#define b_changedtick changedtick_di.di_tv.vval.v_number
- dictitem16_T changedtick_di; // b:changedtick dictionary item.
+ ChangedtickDictItem changedtick_di; // b:changedtick dictionary item.
bool b_saving; /* Set to true if we are in the middle of
saving the buffer. */
@@ -735,8 +720,8 @@ struct file_buffer {
int b_bad_char; /* "++bad=" argument when edit started or 0 */
int b_start_bomb; /* 'bomb' when it was read */
- dictitem_T b_bufvar; /* variable for "b:" Dictionary */
- dict_T *b_vars; /* internal variables, local to buffer */
+ ScopeDictDictItem b_bufvar; ///< Variable for "b:" Dictionary.
+ dict_T *b_vars; ///< b: scope dictionary.
/* When a buffer is created, it starts without a swap file. b_may_swap is
* then set to indicate that a swap file may be opened later. It is reset
@@ -824,9 +809,9 @@ struct tabpage_S {
buf_T *(tp_diffbuf[DB_COUNT]);
int tp_diff_invalid; ///< list of diffs is outdated
frame_T *(tp_snapshot[SNAP_COUNT]); ///< window layout snapshots
- dictitem_T tp_winvar; ///< variable for "t:" Dictionary
- dict_T *tp_vars; ///< internal variables, local to tab page
- char_u *tp_localdir; ///< Absolute path of local CWD or NULL
+ ScopeDictDictItem tp_winvar; ///< Variable for "t:" Dictionary.
+ dict_T *tp_vars; ///< Internal variables, local to tab page.
+ char_u *tp_localdir; ///< Absolute path of local cwd or NULL.
};
/*
@@ -1118,8 +1103,8 @@ struct window_S {
long w_scbind_pos;
- dictitem_T w_winvar; /* variable for "w:" Dictionary */
- dict_T *w_vars; /* internal variables, local to window */
+ ScopeDictDictItem w_winvar; ///< Variable for "w:" dictionary.
+ dict_T *w_vars; ///< Dictionary with w: variables.
int w_farsi; /* for the window dependent Farsi functions */
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index efe32b915f..99d3e2dd88 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -41,8 +41,10 @@ static bool chartab_initialized = false;
(buf)->b_chartab[(unsigned)(c) >> 6] |= (1ull << ((c) & 0x3f))
#define RESET_CHARTAB(buf, c) \
(buf)->b_chartab[(unsigned)(c) >> 6] &= ~(1ull << ((c) & 0x3f))
+#define GET_CHARTAB_TAB(chartab, c) \
+ ((chartab)[(unsigned)(c) >> 6] & (1ull << ((c) & 0x3f)))
#define GET_CHARTAB(buf, c) \
- ((buf)->b_chartab[(unsigned)(c) >> 6] & (1ull << ((c) & 0x3f)))
+ GET_CHARTAB_TAB((buf)->b_chartab, c)
// Table used below, see init_chartab() for an explanation
static char_u g_chartab[256];
@@ -88,7 +90,6 @@ int buf_init_chartab(buf_T *buf, int global)
{
int c;
int c2;
- char_u *p;
int i;
bool tilde;
bool do_isalpha;
@@ -142,7 +143,8 @@ int buf_init_chartab(buf_T *buf, int global)
// Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint'
// options Each option is a list of characters, character numbers or
// ranges, separated by commas, e.g.: "200-210,x,#-178,-"
- for (i = global ? 0 : 3; i <= 3; ++i) {
+ for (i = global ? 0 : 3; i <= 3; i++) {
+ const char_u *p;
if (i == 0) {
// first round: 'isident'
p = p_isi;
@@ -167,7 +169,7 @@ int buf_init_chartab(buf_T *buf, int global)
}
if (ascii_isdigit(*p)) {
- c = getdigits_int(&p);
+ c = getdigits_int((char_u **)&p);
} else {
c = mb_ptr2char_adv(&p);
}
@@ -177,7 +179,7 @@ int buf_init_chartab(buf_T *buf, int global)
++p;
if (ascii_isdigit(*p)) {
- c2 = getdigits_int(&p);
+ c2 = getdigits_int((char_u **)&p);
} else {
c2 = mb_ptr2char_adv(&p);
}
@@ -634,7 +636,7 @@ int char2cells(int c)
/// @param p
///
/// @return number of display cells.
-int ptr2cells(char_u *p)
+int ptr2cells(const char_u *p)
{
// For UTF-8 we need to look at more bytes if the first byte is >= 0x80.
if (*p >= 0x80) {
@@ -776,6 +778,20 @@ bool vim_iswordc(int c)
return vim_iswordc_buf(c, curbuf);
}
+/// Check that "c" is a keyword character
+/// Letters and characters from 'iskeyword' option for given buffer.
+/// For multi-byte characters mb_get_class() is used (builtin rules).
+///
+/// @param[in] c Character to check.
+/// @param[in] chartab Buffer chartab.
+bool vim_iswordc_tab(const int c, const uint64_t *const chartab)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+{
+ return (c >= 0x100
+ ? (utf_class(c) >= 2)
+ : (c > 0 && GET_CHARTAB_TAB(chartab, c) != 0));
+}
+
/// Check that "c" is a keyword character:
/// Letters and characters from 'iskeyword' option for given buffer.
/// For multi-byte characters mb_get_class() is used (builtin rules).
@@ -785,10 +801,7 @@ bool vim_iswordc(int c)
bool vim_iswordc_buf(int c, buf_T *buf)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(2)
{
- if (c >= 0x100) {
- return utf_class(c) >= 2;
- }
- return c > 0 && c < 0x100 && GET_CHARTAB(buf, c) != 0;
+ return vim_iswordc_tab(c, buf->b_chartab);
}
/// Just like vim_iswordc() but uses a pointer to the (multi-byte) character.
@@ -1384,7 +1397,8 @@ void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left,
///
/// @return Pointer to character after the skipped whitespace.
char_u *skipwhite(const char_u *q)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_RET
{
const char_u *p = q;
while (ascii_iswhite(*p)) {
@@ -1393,19 +1407,21 @@ char_u *skipwhite(const char_u *q)
return (char_u *)p;
}
-/// skip over digits
+/// Skip over digits
///
-/// @param q
+/// @param[in] q String to skip digits in.
///
/// @return Pointer to the character after the skipped digits.
-char_u* skipdigits(char_u *q)
+char_u *skipdigits(const char_u *q)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_RET
{
- char_u *p = q;
+ const char_u *p = q;
while (ascii_isdigit(*p)) {
// skip to next non-digit
p++;
}
- return p;
+ return (char_u *)p;
}
/// skip over binary digits
@@ -1551,17 +1567,17 @@ int vim_tolower(int c)
return TOLOWER_LOC(c);
}
-/// skiptowhite: skip over text until ' ' or '\t' or NUL.
+/// Skip over text until ' ' or '\t' or NUL
///
-/// @param p
+/// @param[in] p Text to skip over.
///
/// @return Pointer to the next whitespace or NUL character.
-char_u* skiptowhite(char_u *p)
+char_u *skiptowhite(const char_u *p)
{
while (*p != ' ' && *p != '\t' && *p != NUL) {
p++;
}
- return p;
+ return (char_u *)p;
}
/// skiptowhite_esc: Like skiptowhite(), but also skip escaped chars
diff --git a/src/nvim/charset.h b/src/nvim/charset.h
index 78d6f2a76c..c69582c4c6 100644
--- a/src/nvim/charset.h
+++ b/src/nvim/charset.h
@@ -1,6 +1,20 @@
#ifndef NVIM_CHARSET_H
#define NVIM_CHARSET_H
+#include "nvim/types.h"
+#include "nvim/pos.h"
+#include "nvim/buffer_defs.h"
+
+/// Return the folded-case equivalent of the given character
+///
+/// @param[in] c Character to transform.
+///
+/// @return Folded variant.
+#define CH_FOLD(c) \
+ utf_fold((sizeof(c) == sizeof(char)) \
+ ?((int)(uint8_t)(c)) \
+ :((int)(c)))
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "charset.h.generated.h"
#endif
diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c
index 82f1bf0a16..45abd314fc 100644
--- a/src/nvim/cursor.c
+++ b/src/nvim/cursor.c
@@ -12,6 +12,7 @@
#include "nvim/state.h"
#include "nvim/vim.h"
#include "nvim/ascii.h"
+#include "nvim/mark.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "cursor.c.generated.h"
@@ -227,9 +228,10 @@ static int coladvance2(
}
}
- /* prevent from moving onto a trail byte */
- if (has_mbyte)
- mb_adjustpos(curbuf, pos);
+ // Prevent from moving onto a trail byte.
+ if (has_mbyte) {
+ mark_mb_adjustpos(curbuf, pos);
+ }
if (col < wcol)
return FAIL;
@@ -361,9 +363,10 @@ void check_cursor_col_win(win_T *win)
win->w_cursor.col = len;
} else {
win->w_cursor.col = len - 1;
- /* Move the cursor to the head byte. */
- if (has_mbyte)
- mb_adjustpos(win->w_buffer, &win->w_cursor);
+ // Move the cursor to the head byte.
+ if (has_mbyte) {
+ mark_mb_adjustpos(win->w_buffer, &win->w_cursor);
+ }
}
} else if (win->w_cursor.col < 0) {
win->w_cursor.col = 0;
diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c
index b50462664c..34ee53bf75 100644
--- a/src/nvim/cursor_shape.c
+++ b/src/nvim/cursor_shape.c
@@ -7,40 +7,74 @@
#include "nvim/charset.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
+#include "nvim/api/private/helpers.h"
+#include "nvim/ui.h"
-/*
- * Handling of cursor and mouse pointer shapes in various modes.
- */
-
+/// Handling of cursor and mouse pointer shapes in various modes.
static cursorentry_T shape_table[SHAPE_IDX_COUNT] =
{
- /* The values will be filled in from the 'guicursor' and 'mouseshape'
- * defaults when Vim starts.
- * Adjust the SHAPE_IDX_ defines when making changes! */
- {0, 0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE},
- {0, 0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE},
- {0, 0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE},
- {0, 0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE},
- {0, 0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE},
- {0, 0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE},
- {0, 0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE},
- {0, 0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE},
- {0, 0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE},
- {0, 0, 0, 0L, 0L, 0L, 0, 0, "e", SHAPE_MOUSE},
- {0, 0, 0, 0L, 0L, 0L, 0, 0, "s", SHAPE_MOUSE},
- {0, 0, 0, 0L, 0L, 0L, 0, 0, "sd", SHAPE_MOUSE},
- {0, 0, 0, 0L, 0L, 0L, 0, 0, "vs", SHAPE_MOUSE},
- {0, 0, 0, 0L, 0L, 0L, 0, 0, "vd", SHAPE_MOUSE},
- {0, 0, 0, 0L, 0L, 0L, 0, 0, "m", SHAPE_MOUSE},
- {0, 0, 0, 0L, 0L, 0L, 0, 0, "ml", SHAPE_MOUSE},
- {0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR},
+ // Values are set by 'guicursor' and 'mouseshape'.
+ // Adjust the SHAPE_IDX_ defines when changing this!
+ { "normal", 0, 0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE },
+ { "visual", 0, 0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE },
+ { "insert", 0, 0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE },
+ { "replace", 0, 0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE },
+ { "cmdline_normal", 0, 0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE },
+ { "cmdline_insert", 0, 0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE },
+ { "cmdline_replace", 0, 0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE },
+ { "operator", 0, 0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE },
+ { "visual_select", 0, 0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE },
+ { "cmdline_hover", 0, 0, 0, 0L, 0L, 0L, 0, 0, "e", SHAPE_MOUSE },
+ { "statusline_hover", 0, 0, 0, 0L, 0L, 0L, 0, 0, "s", SHAPE_MOUSE },
+ { "statusline_drag", 0, 0, 0, 0L, 0L, 0L, 0, 0, "sd", SHAPE_MOUSE },
+ { "vsep_hover", 0, 0, 0, 0L, 0L, 0L, 0, 0, "vs", SHAPE_MOUSE },
+ { "vsep_drag", 0, 0, 0, 0L, 0L, 0L, 0, 0, "vd", SHAPE_MOUSE },
+ { "more", 0, 0, 0, 0L, 0L, 0L, 0, 0, "m", SHAPE_MOUSE },
+ { "more_lastline", 0, 0, 0, 0L, 0L, 0L, 0, 0, "ml", SHAPE_MOUSE },
+ { "showmatch", 0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR },
};
-/*
- * Parse the 'guicursor' option ("what" is SHAPE_CURSOR) or 'mouseshape'
- * ("what" is SHAPE_MOUSE).
- * Returns error message for an illegal option, NULL otherwise.
- */
+/// Converts cursor_shapes into a Dictionary of dictionaries
+/// @return dictionary of the form {"normal" : { "cursor_shape": ... }, ...}
+Dictionary cursor_shape_dict(void)
+{
+ Dictionary all = ARRAY_DICT_INIT;
+
+ for (int i = 0; i < SHAPE_IDX_COUNT; i++) {
+ Dictionary dic = ARRAY_DICT_INIT;
+ cursorentry_T *cur = &shape_table[i];
+ if (cur->used_for & SHAPE_MOUSE) {
+ PUT(dic, "mouse_shape", INTEGER_OBJ(cur->mshape));
+ }
+ if (cur->used_for & SHAPE_CURSOR) {
+ String shape_str;
+ switch (cur->shape) {
+ case SHAPE_BLOCK: shape_str = cstr_to_string("block"); break;
+ case SHAPE_VER: shape_str = cstr_to_string("vertical"); break;
+ case SHAPE_HOR: shape_str = cstr_to_string("horizontal"); break;
+ default: shape_str = cstr_to_string("unknown");
+ }
+ PUT(dic, "cursor_shape", STRING_OBJ(shape_str));
+ PUT(dic, "cell_percentage", INTEGER_OBJ(cur->percentage));
+ PUT(dic, "blinkwait", INTEGER_OBJ(cur->blinkwait));
+ PUT(dic, "blinkon", INTEGER_OBJ(cur->blinkon));
+ PUT(dic, "blinkoff", INTEGER_OBJ(cur->blinkoff));
+ PUT(dic, "hl_id", INTEGER_OBJ(cur->id));
+ PUT(dic, "id_lm", INTEGER_OBJ(cur->id_lm));
+ }
+ PUT(dic, "short_name", STRING_OBJ(cstr_to_string(cur->name)));
+
+ PUT(all, cur->full_name, DICTIONARY_OBJ(dic));
+ }
+
+ return all;
+}
+
+/// Parse the 'guicursor' option
+///
+/// @param what SHAPE_CURSOR or SHAPE_MOUSE ('mouseshape')
+///
+/// @returns error message for an illegal option, NULL otherwise.
char_u *parse_shape_opt(int what)
{
char_u *modep;
@@ -55,14 +89,13 @@ char_u *parse_shape_opt(int what)
int found_ve = false; /* found "ve" flag */
int round;
- /*
- * First round: check for errors; second round: do it for real.
- */
- for (round = 1; round <= 2; ++round) {
- /*
- * Repeat for all comma separated parts.
- */
+ // First round: check for errors; second round: do it for real.
+ for (round = 1; round <= 2; round++) {
+ // Repeat for all comma separated parts.
modep = p_guicursor;
+ if (*p_guicursor == NUL) {
+ modep = (char_u *)"a:block-blinkon0";
+ }
while (*modep != NUL) {
colonp = vim_strchr(modep, ':');
if (colonp == NULL)
@@ -71,19 +104,18 @@ char_u *parse_shape_opt(int what)
return (char_u *)N_("E546: Illegal mode");
commap = vim_strchr(modep, ',');
- /*
- * Repeat for all mode's before the colon.
- * For the 'a' mode, we loop to handle all the modes.
- */
+ // Repeat for all modes before the colon.
+ // For the 'a' mode, we loop to handle all the modes.
all_idx = -1;
assert(modep < colonp);
while (modep < colonp || all_idx >= 0) {
if (all_idx < 0) {
- /* Find the mode. */
- if (modep[1] == '-' || modep[1] == ':')
+ // Find the mode
+ if (modep[1] == '-' || modep[1] == ':') {
len = 1;
- else
+ } else {
len = 2;
+ }
if (len == 1 && TOLOWER_ASC(modep[0]) == 'a') {
all_idx = SHAPE_IDX_COUNT - 1;
@@ -100,11 +132,11 @@ char_u *parse_shape_opt(int what)
modep += len + 1;
}
- if (all_idx >= 0)
+ if (all_idx >= 0) {
idx = all_idx--;
- else if (round == 2) {
+ } else if (round == 2) {
{
- /* Set the defaults, for the missing parts */
+ // Set the defaults, for the missing parts
shape_table[idx].shape = SHAPE_BLOCK;
shape_table[idx].blinkwait = 700L;
shape_table[idx].blinkon = 400L;
@@ -208,6 +240,23 @@ char_u *parse_shape_opt(int what)
shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm;
}
}
-
+ ui_cursor_style_set();
return NULL;
}
+
+
+/// Map cursor mode from string to integer
+///
+/// @param mode Fullname of the mode whose id we are looking for
+/// @return -1 in case of failure, else the matching SHAPE_ID* integer
+int cursor_mode_str2int(const char *mode)
+{
+ for (int current_mode = 0; current_mode < SHAPE_IDX_COUNT; current_mode++) {
+ if (strcmp(shape_table[current_mode].full_name, mode) == 0) {
+ return current_mode;
+ }
+ }
+ ELOG("Unknown mode %s", mode);
+ return -1;
+}
+
diff --git a/src/nvim/cursor_shape.h b/src/nvim/cursor_shape.h
index 9ce1b6e0a0..0006ede31d 100644
--- a/src/nvim/cursor_shape.h
+++ b/src/nvim/cursor_shape.h
@@ -1,32 +1,34 @@
#ifndef NVIM_CURSOR_SHAPE_H
#define NVIM_CURSOR_SHAPE_H
-/*
- * struct to store values from 'guicursor' and 'mouseshape'
- */
-/* Indexes in shape_table[] */
-#define SHAPE_IDX_N 0 /* Normal mode */
-#define SHAPE_IDX_V 1 /* Visual mode */
-#define SHAPE_IDX_I 2 /* Insert mode */
-#define SHAPE_IDX_R 3 /* Replace mode */
-#define SHAPE_IDX_C 4 /* Command line Normal mode */
-#define SHAPE_IDX_CI 5 /* Command line Insert mode */
-#define SHAPE_IDX_CR 6 /* Command line Replace mode */
-#define SHAPE_IDX_O 7 /* Operator-pending mode */
-#define SHAPE_IDX_VE 8 /* Visual mode with 'selection' exclusive */
-#define SHAPE_IDX_CLINE 9 /* On command line */
-#define SHAPE_IDX_STATUS 10 /* A status line */
-#define SHAPE_IDX_SDRAG 11 /* dragging a status line */
-#define SHAPE_IDX_VSEP 12 /* A vertical separator line */
-#define SHAPE_IDX_VDRAG 13 /* dragging a vertical separator line */
-#define SHAPE_IDX_MORE 14 /* Hit-return or More */
-#define SHAPE_IDX_MOREL 15 /* Hit-return or More in last line */
-#define SHAPE_IDX_SM 16 /* showing matching paren */
-#define SHAPE_IDX_COUNT 17
+/// struct to store values from 'guicursor' and 'mouseshape'
+/// Indexes in shape_table[]
+typedef enum {
+SHAPE_IDX_N = 0, ///< Normal mode
+SHAPE_IDX_V = 1, ///< Visual mode
+SHAPE_IDX_I = 2, ///< Insert mode
+SHAPE_IDX_R = 3, ///< Replace mode
+SHAPE_IDX_C = 4, ///< Command line Normal mode
+SHAPE_IDX_CI = 5, ///< Command line Insert mode
+SHAPE_IDX_CR = 6, ///< Command line Replace mode
+SHAPE_IDX_O = 7, ///< Operator-pending mode
+SHAPE_IDX_VE = 8, ///< Visual mode with 'selection' exclusive
+SHAPE_IDX_CLINE = 9, ///< On command line
+SHAPE_IDX_STATUS = 10, ///< On status line
+SHAPE_IDX_SDRAG = 11, ///< dragging a status line
+SHAPE_IDX_VSEP = 12, ///< On vertical separator line
+SHAPE_IDX_VDRAG = 13, ///< dragging a vertical separator line
+SHAPE_IDX_MORE = 14, ///< Hit-return or More
+SHAPE_IDX_MOREL = 15, ///< Hit-return or More in last line
+SHAPE_IDX_SM = 16, ///< showing matching paren
+SHAPE_IDX_COUNT = 17
+} MouseMode;
-#define SHAPE_BLOCK 0 /* block cursor */
-#define SHAPE_HOR 1 /* horizontal bar cursor */
-#define SHAPE_VER 2 /* vertical bar cursor */
+typedef enum {
+SHAPE_BLOCK = 0, ///< block cursor
+SHAPE_HOR = 1, ///< horizontal bar cursor
+SHAPE_VER = 2 ///< vertical bar cursor
+} CursorShape;
#define MSHAPE_NUMBERED 1000 /* offset for shapes identified by number */
#define MSHAPE_HIDE 1 /* hide mouse pointer */
@@ -35,16 +37,17 @@
#define SHAPE_CURSOR 2 /* used for text cursor shape */
typedef struct cursor_entry {
- int shape; /* one of the SHAPE_ defines */
- int mshape; /* one of the MSHAPE defines */
- int percentage; /* percentage of cell for bar */
- long blinkwait; /* blinking, wait time before blinking starts */
- long blinkon; /* blinking, on time */
- long blinkoff; /* blinking, off time */
- int id; /* highlight group ID */
- int id_lm; /* highlight group ID for :lmap mode */
- char *name; /* mode name (fixed) */
- char used_for; /* SHAPE_MOUSE and/or SHAPE_CURSOR */
+ char *full_name; ///< mode description
+ CursorShape shape; ///< cursor shape: one of the SHAPE_ defines
+ int mshape; ///< mouse shape: one of the MSHAPE defines
+ int percentage; ///< percentage of cell for bar
+ long blinkwait; ///< blinking, wait time before blinking starts
+ long blinkon; ///< blinking, on time
+ long blinkoff; ///< blinking, off time
+ int id; ///< highlight group ID
+ int id_lm; ///< highlight group ID for :lmap mode
+ char *name; ///< mode short name
+ char used_for; ///< SHAPE_MOUSE and/or SHAPE_CURSOR
} cursorentry_T;
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 11ade20c1c..ff76abc01f 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -1586,7 +1586,7 @@ static int diff_cmp(char_u *s1, char_u *s2)
}
if ((diff_flags & DIFF_ICASE) && !(diff_flags & DIFF_IWHITE)) {
- return mb_stricmp(s1, s2);
+ return mb_stricmp((const char *)s1, (const char *)s2);
}
// Ignore white space changes and possibly ignore case.
diff --git a/src/nvim/diff.h b/src/nvim/diff.h
index f6cef1cafd..3624ce29bb 100644
--- a/src/nvim/diff.h
+++ b/src/nvim/diff.h
@@ -1,6 +1,9 @@
#ifndef NVIM_DIFF_H
#define NVIM_DIFF_H
+#include "nvim/pos.h"
+#include "nvim/ex_cmds_defs.h"
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "diff.h.generated.h"
#endif
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 5544f0b163..b35504908e 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -15,6 +15,7 @@
#include "nvim/cursor.h"
#include "nvim/digraph.h"
#include "nvim/eval.h"
+#include "nvim/eval/typval.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/farsi.h"
@@ -1422,7 +1423,7 @@ static void ins_ctrl_v(void)
edit_putchar('^', TRUE);
did_putchar = TRUE;
}
- AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
+ AppendToRedobuff(CTRL_V_STR);
add_to_showcmd_c(Ctrl_V);
@@ -1976,7 +1977,6 @@ static bool ins_compl_accept_char(int c)
*/
int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int dir, int flags)
{
- char_u *p;
int i, c;
int actual_len; /* Take multi-byte characters */
int actual_compl_length; /* into account. */
@@ -1986,11 +1986,11 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
int was_letter = FALSE;
if (p_ic && curbuf->b_p_inf && len > 0) {
- /* Infer case of completed part. */
+ // Infer case of completed part.
- /* Find actual length of completion. */
+ // Find actual length of completion.
if (has_mbyte) {
- p = str;
+ const char_u *p = str;
actual_len = 0;
while (*p != NUL) {
mb_ptr_adv(p);
@@ -2001,7 +2001,7 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
/* Find actual length of original text. */
if (has_mbyte) {
- p = compl_orig_text;
+ const char_u *p = compl_orig_text;
actual_compl_length = 0;
while (*p != NUL) {
mb_ptr_adv(p);
@@ -2017,27 +2017,35 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
/* Allocate wide character array for the completion and fill it. */
wca = xmalloc(actual_len * sizeof(*wca));
- p = str;
- for (i = 0; i < actual_len; ++i)
- if (has_mbyte)
- wca[i] = mb_ptr2char_adv(&p);
- else
- wca[i] = *(p++);
+ {
+ const char_u *p = str;
+ for (i = 0; i < actual_len; i++) {
+ if (has_mbyte) {
+ wca[i] = mb_ptr2char_adv(&p);
+ } else {
+ wca[i] = *(p++);
+ }
+ }
+ }
- /* Rule 1: Were any chars converted to lower? */
- p = compl_orig_text;
- for (i = 0; i < min_len; ++i) {
- if (has_mbyte)
- c = mb_ptr2char_adv(&p);
- else
- c = *(p++);
- if (vim_islower(c)) {
- has_lower = TRUE;
- if (vim_isupper(wca[i])) {
- /* Rule 1 is satisfied. */
- for (i = actual_compl_length; i < actual_len; ++i)
- wca[i] = vim_tolower(wca[i]);
- break;
+ // Rule 1: Were any chars converted to lower?
+ {
+ const char_u *p = compl_orig_text;
+ for (i = 0; i < min_len; i++) {
+ if (has_mbyte) {
+ c = mb_ptr2char_adv(&p);
+ } else {
+ c = *(p++);
+ }
+ if (vim_islower(c)) {
+ has_lower = true;
+ if (vim_isupper(wca[i])) {
+ // Rule 1 is satisfied.
+ for (i = actual_compl_length; i < actual_len; i++) {
+ wca[i] = vim_tolower(wca[i]);
+ }
+ break;
+ }
}
}
}
@@ -2047,84 +2055,110 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
* upper case.
*/
if (!has_lower) {
- p = compl_orig_text;
- for (i = 0; i < min_len; ++i) {
- if (has_mbyte)
+ const char_u *p = compl_orig_text;
+ for (i = 0; i < min_len; i++) {
+ if (has_mbyte) {
c = mb_ptr2char_adv(&p);
- else
+ } else {
c = *(p++);
+ }
if (was_letter && vim_isupper(c) && vim_islower(wca[i])) {
- /* Rule 2 is satisfied. */
- for (i = actual_compl_length; i < actual_len; ++i)
+ // Rule 2 is satisfied.
+ for (i = actual_compl_length; i < actual_len; i++) {
wca[i] = vim_toupper(wca[i]);
+ }
break;
}
was_letter = vim_islower(c) || vim_isupper(c);
}
}
- /* Copy the original case of the part we typed. */
- p = compl_orig_text;
- for (i = 0; i < min_len; ++i) {
- if (has_mbyte)
- c = mb_ptr2char_adv(&p);
- else
- c = *(p++);
- if (vim_islower(c))
- wca[i] = vim_tolower(wca[i]);
- else if (vim_isupper(c))
- wca[i] = vim_toupper(wca[i]);
+ // Copy the original case of the part we typed.
+ {
+ const char_u *p = compl_orig_text;
+ for (i = 0; i < min_len; i++) {
+ if (has_mbyte) {
+ c = mb_ptr2char_adv(&p);
+ } else {
+ c = *(p++);
+ }
+ if (vim_islower(c)) {
+ wca[i] = vim_tolower(wca[i]);
+ } else if (vim_isupper(c)) {
+ wca[i] = vim_toupper(wca[i]);
+ }
+ }
}
- /*
- * Generate encoding specific output from wide character array.
- * Multi-byte characters can occupy up to five bytes more than
- * ASCII characters, and we also need one byte for NUL, so stay
- * six bytes away from the edge of IObuff.
- */
- p = IObuff;
- i = 0;
- while (i < actual_len && (p - IObuff + 6) < IOSIZE)
- if (has_mbyte)
- p += (*mb_char2bytes)(wca[i++], p);
- else
- *(p++) = wca[i++];
- *p = NUL;
+ // Generate encoding specific output from wide character array.
+ // Multi-byte characters can occupy up to five bytes more than
+ // ASCII characters, and we also need one byte for NUL, so stay
+ // six bytes away from the edge of IObuff.
+ {
+ char_u *p = IObuff;
+ i = 0;
+ while (i < actual_len && (p - IObuff + 6) < IOSIZE) {
+ if (has_mbyte) {
+ p += (*mb_char2bytes)(wca[i++], p);
+ } else {
+ *(p++) = wca[i++];
+ }
+ }
+ *p = NUL;
+ }
xfree(wca);
- return ins_compl_add(IObuff, len, icase, fname, NULL, dir,
- flags, FALSE);
+ return ins_compl_add(IObuff, len, icase, fname, NULL, false, dir, flags,
+ false);
}
- return ins_compl_add(str, len, icase, fname, NULL, dir, flags, FALSE);
+ return ins_compl_add(str, len, icase, fname, NULL, false, dir, flags, false);
}
-/*
- * Add a match to the list of matches.
- * If the given string is already in the list of completions, then return
- * NOTDONE, otherwise add it to the list and return OK. If there is an error
- * then FAIL is returned.
- */
-static int
-ins_compl_add (
- char_u *str,
- int len,
- int icase,
- char_u *fname,
- char_u **cptext, /* extra text for popup menu or NULL */
- int cdir,
- int flags,
- int adup /* accept duplicate match */
-)
+/// Add a match to the list of matches
+///
+/// @param[in] str Match to add.
+/// @param[in] len Match length, -1 to use #STRLEN.
+/// @param[in] icase Whether case is to be ignored.
+/// @param[in] fname File name match comes from. May be NULL.
+/// @param[in] cptext Extra text for popup menu. May be NULL. If not NULL,
+/// must have exactly #CPT_COUNT items.
+/// @param[in] cptext_allocated If true, will not copy cptext strings.
+///
+/// @note Will free strings in case of error.
+/// cptext itself will not be freed.
+/// @param[in] cdir Completion direction.
+/// @param[in] adup True if duplicate matches are to be accepted.
+///
+/// @return NOTDONE if the given string is already in the list of completions,
+/// otherwise it is added to the list and OK is returned. FAIL will be
+/// returned in case of error.
+static int ins_compl_add(char_u *const str, int len,
+ const bool icase, char_u *const fname,
+ char_u *const *const cptext,
+ const bool cptext_allocated,
+ const Direction cdir, int flags, const bool adup)
+ FUNC_ATTR_NONNULL_ARG(1)
{
compl_T *match;
- int dir = (cdir == 0 ? compl_direction : cdir);
+ int dir = (cdir == kDirectionNotSet ? compl_direction : cdir);
os_breakcheck();
- if (got_int)
+#define FREE_CPTEXT(cptext, cptext_allocated) \
+ do { \
+ if (cptext != NULL && cptext_allocated) { \
+ for (size_t i = 0; i < CPT_COUNT; i++) { \
+ xfree(cptext[i]); \
+ } \
+ } \
+ } while (0)
+ if (got_int) {
+ FREE_CPTEXT(cptext, cptext_allocated);
return FAIL;
- if (len < 0)
+ }
+ if (len < 0) {
len = (int)STRLEN(str);
+ }
/*
* If the same match is already present, don't add it.
@@ -2132,10 +2166,12 @@ ins_compl_add (
if (compl_first_match != NULL && !adup) {
match = compl_first_match;
do {
- if ( !(match->cp_flags & ORIGINAL_TEXT)
- && STRNCMP(match->cp_str, str, len) == 0
- && match->cp_str[len] == NUL)
+ if (!(match->cp_flags & ORIGINAL_TEXT)
+ && STRNCMP(match->cp_str, str, len) == 0
+ && match->cp_str[len] == NUL) {
+ FREE_CPTEXT(cptext, cptext_allocated);
return NOTDONE;
+ }
match = match->cp_next;
} while (match != NULL && match != compl_first_match);
}
@@ -2166,16 +2202,26 @@ ins_compl_add (
else if (fname != NULL) {
match->cp_fname = vim_strsave(fname);
flags |= FREE_FNAME;
- } else
+ } else {
match->cp_fname = NULL;
+ }
match->cp_flags = flags;
if (cptext != NULL) {
int i;
- for (i = 0; i < CPT_COUNT; ++i)
- if (cptext[i] != NULL && *cptext[i] != NUL)
- match->cp_text[i] = vim_strsave(cptext[i]);
+ for (i = 0; i < CPT_COUNT; i++) {
+ if (cptext[i] == NULL) {
+ continue;
+ }
+ if (*cptext[i] != NUL) {
+ match->cp_text[i] = (cptext_allocated
+ ? cptext[i]
+ : (char_u *)xstrdup((char *)cptext[i]));
+ } else if (cptext_allocated) {
+ xfree(cptext[i]);
+ }
+ }
}
/*
@@ -2298,9 +2344,10 @@ static void ins_compl_add_matches(int num_matches, char_u **matches, int icase)
for (i = 0; i < num_matches && add_r != FAIL; i++)
if ((add_r = ins_compl_add(matches[i], -1, icase,
- NULL, NULL, dir, 0, FALSE)) == OK)
- /* if dir was BACKWARD then honor it just once */
+ NULL, NULL, false, dir, 0, false)) == OK) {
+ // If dir was BACKWARD then honor it just once.
dir = FORWARD;
+ }
FreeWild(num_matches, matches);
}
@@ -2364,8 +2411,8 @@ void set_completion(colnr_T startcol, list_T *list)
/* compl_pattern doesn't need to be set */
compl_orig_text = vim_strnsave(get_cursor_line_ptr() + compl_col,
compl_length);
- if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, 0,
- ORIGINAL_TEXT, FALSE) != OK) {
+ if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, false, 0,
+ ORIGINAL_TEXT, false) != OK) {
return;
}
@@ -2887,7 +2934,7 @@ static void ins_compl_clear(void)
compl_orig_text = NULL;
compl_enter_selects = FALSE;
// clear v:completed_item
- set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
+ set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc());
}
/// Check that Insert completion is active.
@@ -3432,7 +3479,6 @@ expand_by_function (
{
list_T *matchlist = NULL;
dict_T *matchdict = NULL;
- char_u *args[2];
char_u *funcname;
pos_T pos;
win_T *curwin_save;
@@ -3443,9 +3489,8 @@ expand_by_function (
if (*funcname == NUL)
return;
- /* Call 'completefunc' to obtain the list of matches. */
- args[0] = (char_u *)"0";
- args[1] = base;
+ // Call 'completefunc' to obtain the list of matches.
+ const char_u *const args[2] = { (char_u *)"0", base };
pos = curwin->w_cursor;
curwin_save = curwin;
@@ -3461,8 +3506,8 @@ expand_by_function (
matchdict = rettv.vval.v_dict;
break;
default:
- /* TODO: Give error message? */
- clear_tv(&rettv);
+ // TODO(brammool): Give error message?
+ tv_clear(&rettv);
break;
}
}
@@ -3484,10 +3529,12 @@ expand_by_function (
ins_compl_add_dict(matchdict);
theend:
- if (matchdict != NULL)
- dict_unref(matchdict);
- if (matchlist != NULL)
- list_unref(matchlist);
+ if (matchdict != NULL) {
+ tv_dict_unref(matchdict);
+ }
+ if (matchlist != NULL) {
+ tv_list_unref(matchlist);
+ }
}
/*
@@ -3516,53 +3563,60 @@ static void ins_compl_add_dict(dict_T *dict)
dictitem_T *di_refresh;
dictitem_T *di_words;
- /* Check for optional "refresh" item. */
- compl_opt_refresh_always = FALSE;
- di_refresh = dict_find(dict, (char_u *)"refresh", 7);
+ // Check for optional "refresh" item.
+ compl_opt_refresh_always = false;
+ di_refresh = tv_dict_find(dict, S_LEN("refresh"));
if (di_refresh != NULL && di_refresh->di_tv.v_type == VAR_STRING) {
- char_u *v = di_refresh->di_tv.vval.v_string;
+ const char *v = (const char *)di_refresh->di_tv.vval.v_string;
- if (v != NULL && STRCMP(v, (char_u *)"always") == 0)
- compl_opt_refresh_always = TRUE;
+ if (v != NULL && strcmp(v, "always") == 0) {
+ compl_opt_refresh_always = true;
+ }
}
- /* Add completions from a "words" list. */
- di_words = dict_find(dict, (char_u *)"words", 5);
- if (di_words != NULL && di_words->di_tv.v_type == VAR_LIST)
+ // Add completions from a "words" list.
+ di_words = tv_dict_find(dict, S_LEN("words"));
+ if (di_words != NULL && di_words->di_tv.v_type == VAR_LIST) {
ins_compl_add_list(di_words->di_tv.vval.v_list);
+ }
}
-/*
- * Add a match to the list of matches from a typeval_T.
- * If the given string is already in the list of completions, then return
- * NOTDONE, otherwise add it to the list and return OK. If there is an error
- * then FAIL is returned.
- */
-int ins_compl_add_tv(typval_T *tv, int dir)
-{
- char_u *word;
- int icase = FALSE;
- int adup = FALSE;
- int aempty = FALSE;
- char_u *(cptext[CPT_COUNT]);
+/// Add a match to the list of matches from VimL object
+///
+/// @param[in] tv Object to get matches from.
+/// @param[in] dir Completion direction.
+///
+/// @return NOTDONE if the given string is already in the list of completions,
+/// otherwise it is added to the list and OK is returned. FAIL will be
+/// returned in case of error.
+int ins_compl_add_tv(typval_T *const tv, const Direction dir)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const char *word;
+ bool icase = false;
+ bool adup = false;
+ bool aempty = false;
+ char *(cptext[CPT_COUNT]);
if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) {
- word = get_dict_string(tv->vval.v_dict, "word", false);
- cptext[CPT_ABBR] = get_dict_string(tv->vval.v_dict, "abbr", false);
- cptext[CPT_MENU] = get_dict_string(tv->vval.v_dict, "menu", false);
- cptext[CPT_KIND] = get_dict_string(tv->vval.v_dict, "kind", false);
- cptext[CPT_INFO] = get_dict_string(tv->vval.v_dict, "info", false);
-
- icase = get_dict_number(tv->vval.v_dict, "icase");
- adup = get_dict_number(tv->vval.v_dict, "dup");
- aempty = get_dict_number(tv->vval.v_dict, "empty");
+ word = tv_dict_get_string(tv->vval.v_dict, "word", false);
+ cptext[CPT_ABBR] = tv_dict_get_string(tv->vval.v_dict, "abbr", true);
+ cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", true);
+ cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true);
+ cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true);
+
+ icase = (bool)tv_dict_get_number(tv->vval.v_dict, "icase");
+ adup = (bool)tv_dict_get_number(tv->vval.v_dict, "dup");
+ aempty = (bool)tv_dict_get_number(tv->vval.v_dict, "empty");
} else {
- word = get_tv_string_chk(tv);
+ word = (const char *)tv_get_string_chk(tv);
memset(cptext, 0, sizeof(cptext));
}
- if (word == NULL || (!aempty && *word == NUL))
+ if (word == NULL || (!aempty && *word == NUL)) {
return FAIL;
- return ins_compl_add(word, -1, icase, NULL, cptext, dir, 0, adup);
+ }
+ return ins_compl_add((char_u *)word, -1, icase, NULL,
+ (char_u **)cptext, true, dir, 0, adup);
}
/*
@@ -3977,7 +4031,7 @@ static void ins_compl_delete(void)
// causes flicker, thus we can't do that.
changed_cline_bef_curs();
// clear v:completed_item
- set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
+ set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc());
}
// Insert the new text being completed.
@@ -3992,17 +4046,21 @@ static void ins_compl_insert(int in_compl_func)
// Set completed item.
// { word, abbr, menu, kind, info }
- dict_T *dict = dict_alloc();
- dict_add_nr_str(dict, "word", 0L,
- EMPTY_IF_NULL(compl_shown_match->cp_str));
- dict_add_nr_str(dict, "abbr", 0L,
- EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_ABBR]));
- dict_add_nr_str(dict, "menu", 0L,
- EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_MENU]));
- dict_add_nr_str(dict, "kind", 0L,
- EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_KIND]));
- dict_add_nr_str(dict, "info", 0L,
- EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_INFO]));
+ dict_T *dict = tv_dict_alloc();
+ tv_dict_add_str(dict, S_LEN("word"),
+ (const char *)EMPTY_IF_NULL(compl_shown_match->cp_str));
+ tv_dict_add_str(
+ dict, S_LEN("abbr"),
+ (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_ABBR]));
+ tv_dict_add_str(
+ dict, S_LEN("menu"),
+ (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_MENU]));
+ tv_dict_add_str(
+ dict, S_LEN("kind"),
+ (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_KIND]));
+ tv_dict_add_str(
+ dict, S_LEN("info"),
+ (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_INFO]));
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
if (!in_compl_func) {
compl_curr_match = compl_shown_match;
@@ -4544,7 +4602,6 @@ static int ins_complete(int c, bool enable_pum)
* Call user defined function 'completefunc' with "a:findstart"
* set to 1 to obtain the length of text to use for completion.
*/
- char_u *args[2];
int col;
char_u *funcname;
pos_T pos;
@@ -4563,8 +4620,7 @@ static int ins_complete(int c, bool enable_pum)
return FAIL;
}
- args[0] = (char_u *)"1";
- args[1] = NULL;
+ const char_u *const args[2] = { (char_u *)"1", NULL };
pos = curwin->w_cursor;
curwin_save = curwin;
curbuf_save = curbuf;
@@ -4664,8 +4720,8 @@ static int ins_complete(int c, bool enable_pum)
/* Always add completion for the original text. */
xfree(compl_orig_text);
compl_orig_text = vim_strnsave(line + compl_col, compl_length);
- if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, 0,
- ORIGINAL_TEXT, FALSE) != OK) {
+ if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, false, 0,
+ ORIGINAL_TEXT, false) != OK) {
xfree(compl_pattern);
compl_pattern = NULL;
xfree(compl_orig_text);
@@ -5744,15 +5800,16 @@ comp_textwidth (
*/
static void redo_literal(int c)
{
- char_u buf[10];
+ char buf[10];
- /* Only digits need special treatment. Translate them into a string of
- * three digits. */
+ // Only digits need special treatment. Translate them into a string of
+ // three digits.
if (ascii_isdigit(c)) {
- vim_snprintf((char *)buf, sizeof(buf), "%03d", c);
+ vim_snprintf(buf, sizeof(buf), "%03d", c);
AppendToRedobuff(buf);
- } else
+ } else {
AppendCharToRedobuff(c);
+ }
}
// start_arrow() is called when an arrow key is used in insert mode.
@@ -5781,8 +5838,8 @@ static void start_arrow_common(pos_T *end_insert_pos, bool end_change)
{
if (!arrow_used && end_change) { // something has been inserted
AppendToRedobuff(ESC_STR);
- stop_insert(end_insert_pos, FALSE, FALSE);
- arrow_used = TRUE; /* this means we stopped the current insert */
+ stop_insert(end_insert_pos, false, false);
+ arrow_used = true; // This means we stopped the current insert.
}
check_spell_redraw();
}
@@ -5839,7 +5896,7 @@ int stop_arrow(void)
vr_lines_changed = 1;
}
ResetRedobuff();
- AppendToRedobuff((char_u *)"1i"); /* pretend we start an insertion */
+ AppendToRedobuff("1i"); // Pretend we start an insertion.
new_insert_skip = 2;
} else if (ins_need_undo) {
if (u_save_cursor() == OK)
@@ -6304,12 +6361,13 @@ stuff_inserted (
}
do {
- stuffReadbuff(ptr);
- /* a trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^" */
- if (last)
- stuffReadbuff((char_u *)(last == '0'
- ? "\026\060\064\070"
- : "\026^"));
+ stuffReadbuff((const char *)ptr);
+ // A trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^".
+ if (last) {
+ stuffReadbuff((last == '0'
+ ? "\026\060\064\070"
+ : "\026^"));
+ }
} while (--count > 0);
if (last)
@@ -7066,8 +7124,8 @@ static void ins_ctrl_g(void)
*/
static void ins_ctrl_hat(void)
{
- if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE)) {
- /* ":lmap" mappings exists, Toggle use of ":lmap" mappings. */
+ if (map_to_exists_mode("", LANGMAP, false)) {
+ // ":lmap" mappings exists, Toggle use of ":lmap" mappings.
if (State & LANGMAP) {
curbuf->b_p_iminsert = B_IMODE_NONE;
State &= ~LANGMAP;
@@ -7102,13 +7160,12 @@ static bool ins_esc(long *count, int cmdchar, bool nomove)
disabled_redraw = false;
}
if (!arrow_used) {
- /*
- * Don't append the ESC for "r<CR>" and "grx".
- * When 'insertmode' is set only CTRL-L stops Insert mode. Needed for
- * when "count" is non-zero.
- */
- if (cmdchar != 'r' && cmdchar != 'v')
- AppendToRedobuff(p_im ? (char_u *)"\014" : ESC_STR);
+ // Don't append the ESC for "r<CR>" and "grx".
+ // When 'insertmode' is set only CTRL-L stops Insert mode. Needed for
+ // when "count" is non-zero.
+ if (cmdchar != 'r' && cmdchar != 'v') {
+ AppendToRedobuff(p_im ? "\014" : ESC_STR);
+ }
/*
* Repeating insert may take a long time. Check for
@@ -7262,7 +7319,8 @@ static bool ins_start_select(int c)
// Execute the key in (insert) Select mode.
stuffcharReadbuff(Ctrl_O);
if (mod_mask) {
- char_u buf[4] = { K_SPECIAL, KS_MODIFIER, mod_mask, NUL };
+ const char buf[] = { (char)K_SPECIAL, (char)KS_MODIFIER,
+ (char)(uint8_t)mod_mask, NUL };
stuffReadbuff(buf);
}
stuffcharReadbuff(c);
@@ -8070,11 +8128,11 @@ static bool ins_tab(void)
return true;
}
- did_ai = FALSE;
- did_si = FALSE;
- can_si = FALSE;
- can_si_back = FALSE;
- AppendToRedobuff((char_u *)"\t");
+ did_ai = false;
+ did_si = false;
+ can_si = false;
+ can_si_back = false;
+ AppendToRedobuff("\t");
if (p_sta && ind) { // insert tab in indent, use "shiftwidth"
temp = get_sw_value(curbuf);
@@ -8339,8 +8397,8 @@ static int ins_digraph(void)
edit_unputchar();
}
if (cc != ESC) {
- AppendToRedobuff((char_u *)CTRL_V_STR);
- c = getdigraph(c, cc, TRUE);
+ AppendToRedobuff(CTRL_V_STR);
+ c = getdigraph(c, cc, true);
clear_showcmd();
return c;
}
@@ -8402,12 +8460,13 @@ static int ins_ctrl_ey(int tc)
if (c != NUL) {
long tw_save;
- /* The character must be taken literally, insert like it
- * was typed after a CTRL-V, and pretend 'textwidth'
- * wasn't set. Digits, 'o' and 'x' are special after a
- * CTRL-V, don't use it for these. */
- if (c < 256 && !isalnum(c))
- AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
+ // The character must be taken literally, insert like it
+ // was typed after a CTRL-V, and pretend 'textwidth'
+ // wasn't set. Digits, 'o' and 'x' are special after a
+ // CTRL-V, don't use it for these.
+ if (c < 256 && !isalnum(c)) {
+ AppendToRedobuff(CTRL_V_STR);
+ }
tw_save = curbuf->b_p_tw;
curbuf->b_p_tw = -1;
insert_special(c, TRUE, FALSE);
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 67b755f053..2002554b0b 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -94,8 +94,13 @@
#include "nvim/lib/kvec.h"
#include "nvim/lib/khash.h"
#include "nvim/lib/queue.h"
-#include "nvim/eval/typval_encode.h"
#include "nvim/viml/executor/executor.h"
+#include "nvim/eval/typval.h"
+#include "nvim/eval/executor.h"
+#include "nvim/eval/gc.h"
+#include "nvim/macros.h"
+
+// TODO(ZyX-I): Remove DICT_MAXNEST, make users be non-recursive instead
#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */
@@ -133,31 +138,28 @@
* "newkey" is the key for the new item.
*/
typedef struct lval_S {
- char_u *ll_name; /* start of variable name (can be NULL) */
- char_u *ll_exp_name; /* NULL or expanded name in allocated memory. */
- typval_T *ll_tv; /* Typeval of item being used. If "newkey"
- isn't NULL it's the Dict to which to add
- the item. */
- listitem_T *ll_li; /* The list item or NULL. */
- list_T *ll_list; /* The list or NULL. */
- int ll_range; /* TRUE when a [i:j] range was used */
- long ll_n1; /* First index for list */
- long ll_n2; /* Second index for list range */
- int ll_empty2; /* Second index is empty: [i:] */
- dict_T *ll_dict; /* The Dictionary or NULL */
- dictitem_T *ll_di; /* The dictitem or NULL */
- char_u *ll_newkey; /* New key for Dict in alloc. mem or NULL. */
+ const char *ll_name; ///< Start of variable name (can be NULL).
+ size_t ll_name_len; ///< Length of the .ll_name.
+ char *ll_exp_name; ///< NULL or expanded name in allocated memory.
+ typval_T *ll_tv; ///< Typeval of item being used. If "newkey"
+ ///< isn't NULL it's the Dict to which to add the item.
+ listitem_T *ll_li; ///< The list item or NULL.
+ list_T *ll_list; ///< The list or NULL.
+ int ll_range; ///< TRUE when a [i:j] range was used.
+ long ll_n1; ///< First index for list.
+ long ll_n2; ///< Second index for list range.
+ int ll_empty2; ///< Second index is empty: [i:].
+ dict_T *ll_dict; ///< The Dictionary or NULL.
+ dictitem_T *ll_di; ///< The dictitem or NULL.
+ char_u *ll_newkey; ///< New key for Dict in allocated memory or NULL.
} lval_T;
static char *e_letunexp = N_("E18: Unexpected characters in :let");
-static char *e_listidx = N_("E684: list index out of range: %" PRId64);
-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_stringreq = N_("E928: String required");
@@ -168,17 +170,20 @@ static char *e_funcexts = N_(
static char *e_funcdict = N_("E717: Dictionary entry already exists");
static char *e_funcref = N_("E718: Funcref required");
static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
-static char *e_letwrong = N_("E734: Wrong variable type for %s=");
static char *e_nofunc = N_("E130: Unknown function: %s");
static char *e_illvar = N_("E461: Illegal variable name: %s");
-static char *e_float_as_string = N_("E806: using Float as a String");
static const char *e_readonlyvar = N_(
"E46: Cannot change read-only variable \"%.*s\"");
-static char_u * const empty_string = (char_u *)"";
+// TODO(ZyX-I): move to eval/executor
+static char *e_letwrong = N_("E734: Wrong variable type for %s=");
+
static char_u * const namespace_char = (char_u *)"abglstvw";
-static dictitem_T globvars_var; /* variable used for g: */
+/// Variable used for g:
+static ScopeDictDictItem globvars_var;
+
+/// g: value
#define globvarht globvardict.dv_hashtab
/*
@@ -189,12 +194,15 @@ static hashtab_T compat_hashtab;
hashtab_T func_hashtab;
+// Used for checking if local variables or arguments used in a lambda.
+static int *eval_lavars_used = NULL;
+
/*
* Array to hold the hashtab with variables local to each sourced script.
* Each item holds a variable (nameless) that points to the dict_T.
*/
typedef struct {
- dictitem_T sv_var;
+ ScopeDictDictItem sv_var;
dict_T sv_dict;
} scriptvar_T;
@@ -232,17 +240,44 @@ typedef enum {
// The names of packages that once were loaded are remembered.
static garray_T ga_loaded = { 0, 0, sizeof(char_u *), 4, NULL };
-// List heads for garbage collection. Although there can be a reference loop
-// from partial to dict to partial, we don't need to keep track of the partial,
-// since it will get freed when the dict is unused and gets freed.
-static dict_T *first_dict = NULL; // list of all dicts
-static list_T *first_list = NULL; // list of all lists
-
-#define FLEN_FIXED 40
-
#define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j]
#define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j]
+/// Short variable name length
+#define VAR_SHORT_LEN 20
+/// Number of fixed variables used for arguments
+#define FIXVAR_CNT 12
+
+struct funccall_S {
+ ufunc_T *func; ///< Function being called.
+ int linenr; ///< Next line to be executed.
+ int returned; ///< ":return" used.
+ /// Fixed variables for arguments.
+ TV_DICTITEM_STRUCT(VAR_SHORT_LEN + 1) fixvar[FIXVAR_CNT];
+ dict_T l_vars; ///< l: local function variables.
+ ScopeDictDictItem l_vars_var; ///< Variable for l: scope.
+ dict_T l_avars; ///< a: argument variables.
+ ScopeDictDictItem l_avars_var; ///< Variable for a: scope.
+ list_T l_varlist; ///< List for a:000.
+ listitem_T l_listitems[MAX_FUNC_ARGS]; ///< List items for a:000.
+ typval_T *rettv; ///< Return value.
+ linenr_T breakpoint; ///< Next line with breakpoint or zero.
+ int dbg_tick; ///< Debug_tick when breakpoint was set.
+ int level; ///< Top nesting level of executed function.
+ proftime_T prof_child; ///< Time spent in a child.
+ funccall_T *caller; ///< Calling function or NULL.
+ int fc_refcount; ///< Number of user functions that reference this funccall.
+ int fc_copyID; ///< CopyID used for garbage collection.
+ garray_T fc_funcs; ///< List of ufunc_T* which keep a reference to "func".
+};
+
+///< Structure used by trans_function_name()
+typedef struct {
+ dict_T *fd_dict; ///< Dictionary used.
+ char_u *fd_newkey; ///< New key in "dict" in allocated memory.
+ dictitem_T *fd_di; ///< Dictionary item used.
+} funcdict_T;
+
/*
* Info used by a ":for" loop.
*/
@@ -284,8 +319,8 @@ typedef enum {
// variables with the VV_ defines.
static struct vimvar {
char *vv_name; ///< Name of the variable, without v:.
- dictitem16_T vv_di; ///< Value and name for key (max 16 chars)
- char vv_flags; ///< Flags: #VV_COMPAT, #VV_RO, #VV_RO_SBX.
+ TV_DICTITEM_STRUCT(17) vv_di; ///< Value and name for key (max 16 chars).
+ char vv_flags; ///< Flags: #VV_COMPAT, #VV_RO, #VV_RO_SBX.
} vimvars[] =
{
// VV_ tails differing from upcased string literals:
@@ -390,23 +425,11 @@ static struct vimvar {
#define vv_dict vv_di.di_tv.vval.v_dict
#define vv_tv vv_di.di_tv
-static dictitem_T vimvars_var; // variable used for v:
-#define vimvarht vimvardict.dv_hashtab
+/// Variable used for v:
+static ScopeDictDictItem vimvars_var;
-typedef enum {
- kCallbackNone,
- kCallbackFuncref,
- kCallbackPartial,
-} CallbackType;
-
-typedef struct {
- union {
- char_u *funcref;
- partial_T *partial;
- } data;
- CallbackType type;
-} Callback;
-#define CALLBACK_NONE ((Callback){ .type = kCallbackNone })
+/// v: hashtab
+#define vimvarht vimvardict.dv_hashtab
typedef struct {
union {
@@ -425,13 +448,6 @@ typedef struct {
MultiQueue *events;
} TerminalJobData;
-typedef struct dict_watcher {
- Callback callback;
- char *key_pattern;
- QUEUE node;
- bool busy; // prevent recursion if the dict is changed in the callback
-} DictWatcher;
-
typedef struct {
TerminalJobData *data;
Callback *callback;
@@ -466,6 +482,24 @@ typedef struct fst {
KHASH_MAP_INIT_STR(functions, VimLFuncDef)
+/// Type of assert_* check being performed
+typedef enum
+{
+ ASSERT_EQUAL,
+ ASSERT_NOTEQUAL,
+ ASSERT_MATCH,
+ ASSERT_NOTMATCH,
+ ASSERT_INRANGE,
+ ASSERT_OTHER,
+} assert_type_T;
+
+/// Type for dict_list function
+typedef enum {
+ kDictListKeys, ///< List dictionary keys.
+ kDictListValues, ///< List dictionary values.
+ kDictListItems, ///< List dictionary contents: [keys, values].
+} DictListType;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval.c.generated.h"
#endif
@@ -546,19 +580,19 @@ void eval_init(void)
}
vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
- dict_T *const msgpack_types_dict = dict_alloc();
+ dict_T *const msgpack_types_dict = tv_dict_alloc();
for (size_t i = 0; i < ARRAY_SIZE(msgpack_type_names); i++) {
- list_T *const type_list = list_alloc();
+ list_T *const type_list = tv_list_alloc();
type_list->lv_lock = VAR_FIXED;
type_list->lv_refcount = 1;
- dictitem_T *const di = dictitem_alloc((char_u *)msgpack_type_names[i]);
+ dictitem_T *const di = tv_dict_item_alloc(msgpack_type_names[i]);
di->di_flags |= DI_FLAGS_RO|DI_FLAGS_FIX;
di->di_tv = (typval_T) {
.v_type = VAR_LIST,
.vval = { .v_list = type_list, },
};
eval_msgpack_type_lists[i] = type_list;
- if (dict_add(msgpack_types_dict, di) == FAIL) {
+ if (tv_dict_add(msgpack_types_dict, di) == FAIL) {
// There must not be duplicate items in this dictionary by definition.
assert(false);
}
@@ -566,12 +600,12 @@ void eval_init(void)
msgpack_types_dict->dv_lock = VAR_FIXED;
set_vim_var_dict(VV_MSGPACK_TYPES, msgpack_types_dict);
- set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
+ set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc());
- dict_T *v_event = dict_alloc();
+ dict_T *v_event = tv_dict_alloc();
v_event->dv_lock = VAR_FIXED;
set_vim_var_dict(VV_EVENT, v_event);
- set_vim_var_list(VV_ERRORS, list_alloc());
+ set_vim_var_list(VV_ERRORS, tv_list_alloc());
set_vim_var_nr(VV_SEARCHFORWARD, 1L);
set_vim_var_nr(VV_HLSEARCH, 1L);
set_vim_var_nr(VV_COUNT1, 1);
@@ -602,7 +636,7 @@ void eval_clear(void)
xfree(p->vv_str);
p->vv_str = NULL;
} else if (p->vv_di.di_tv.v_type == VAR_LIST) {
- list_unref(p->vv_list);
+ tv_list_unref(p->vv_list);
p->vv_list = NULL;
}
}
@@ -690,18 +724,17 @@ int current_func_returned(void)
*/
void set_internal_string_var(char_u *name, char_u *value)
{
- char_u *val = vim_strsave(value);
- typval_T *tvp = xcalloc(1, sizeof(typval_T));
+ const typval_T tv = {
+ .v_type = VAR_STRING,
+ .vval.v_string = value,
+ };
- tvp->v_type = VAR_STRING;
- tvp->vval.v_string = val;
- set_var(name, tvp, FALSE);
- free_tv(tvp);
+ set_var((const char *)name, STRLEN(name), (typval_T *)&tv, true);
}
static lval_T *redir_lval = NULL;
-static garray_T redir_ga; /* only valid when redir_lval is not NULL */
-static char_u *redir_endp = NULL;
+static garray_T redir_ga; // Only valid when redir_lval is not NULL.
+static char_u *redir_endp = NULL;
static char_u *redir_varname = NULL;
/*
@@ -732,11 +765,11 @@ var_redir_start (
/* The output is stored in growarray "redir_ga" until redirection ends. */
ga_init(&redir_ga, (int)sizeof(char), 500);
- /* Parse the variable name (can be a dict or list entry). */
- redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, 0,
- FNE_CHECK_START);
- if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp !=
- NUL) {
+ // Parse the variable name (can be a dict or list entry).
+ redir_endp = (char_u *)get_lval(redir_varname, NULL, redir_lval, false, false,
+ 0, FNE_CHECK_START);
+ if (redir_endp == NULL || redir_lval->ll_name == NULL
+ || *redir_endp != NUL) {
clear_lval(redir_lval);
if (redir_endp != NULL && *redir_endp != NUL)
/* Trailing characters are present after the variable name */
@@ -810,12 +843,13 @@ void var_redir_stop(void)
ga_append(&redir_ga, NUL); /* Append the trailing NUL. */
tv.v_type = VAR_STRING;
tv.vval.v_string = redir_ga.ga_data;
- /* Call get_lval() again, if it's inside a Dict or List it may
- * have changed. */
- redir_endp = get_lval(redir_varname, NULL, redir_lval,
- FALSE, FALSE, 0, FNE_CHECK_START);
- if (redir_endp != NULL && redir_lval->ll_name != NULL)
- set_var_lval(redir_lval, redir_endp, &tv, FALSE, (char_u *)".");
+ // Call get_lval() again, if it's inside a Dict or List it may
+ // have changed.
+ redir_endp = (char_u *)get_lval(redir_varname, NULL, redir_lval,
+ false, false, 0, FNE_CHECK_START);
+ if (redir_endp != NULL && redir_lval->ll_name != NULL) {
+ set_var_lval(redir_lval, redir_endp, &tv, false, (char_u *)".");
+ }
clear_lval(redir_lval);
}
@@ -833,7 +867,7 @@ void var_redir_stop(void)
int eval_charconvert(const char *const enc_from, const char *const enc_to,
const char *const fname_from, const char *const fname_to)
{
- int err = false;
+ bool err = false;
set_vim_var_string(VV_CC_FROM, enc_from, -1);
set_vim_var_string(VV_CC_TO, enc_to, -1);
@@ -855,7 +889,7 @@ int eval_charconvert(const char *const enc_from, const char *const enc_to,
int eval_printexpr(const char *const fname, const char *const args)
{
- int err = false;
+ bool err = false;
set_vim_var_string(VV_FNAME_IN, fname, -1);
set_vim_var_string(VV_CMDARG, args, -1);
@@ -875,7 +909,7 @@ int eval_printexpr(const char *const fname, const char *const args)
void eval_diff(const char *const origfile, const char *const newfile,
const char *const outfile)
{
- int err = FALSE;
+ bool err = false;
set_vim_var_string(VV_FNAME_IN, origfile, -1);
set_vim_var_string(VV_FNAME_NEW, newfile, -1);
@@ -889,7 +923,7 @@ void eval_diff(const char *const origfile, const char *const newfile,
void eval_patch(const char *const origfile, const char *const difffile,
const char *const outfile)
{
- int err;
+ bool err = false;
set_vim_var_string(VV_FNAME_IN, origfile, -1);
set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
@@ -908,56 +942,61 @@ void eval_patch(const char *const origfile, const char *const difffile,
int
eval_to_bool (
char_u *arg,
- int *error,
+ bool *error,
char_u **nextcmd,
int skip /* only parse, don't execute */
)
{
typval_T tv;
- int retval = FALSE;
+ bool retval = false;
- if (skip)
- ++emsg_skip;
- if (eval0(arg, &tv, nextcmd, !skip) == FAIL)
- *error = TRUE;
- else {
- *error = FALSE;
+ if (skip) {
+ emsg_skip++;
+ }
+ if (eval0(arg, &tv, nextcmd, !skip) == FAIL) {
+ *error = true;
+ } else {
+ *error = false;
if (!skip) {
- retval = (get_tv_number_chk(&tv, error) != 0);
- clear_tv(&tv);
+ retval = (tv_get_number_chk(&tv, error) != 0);
+ tv_clear(&tv);
}
}
- if (skip)
- --emsg_skip;
+ if (skip) {
+ emsg_skip--;
+ }
return retval;
}
-/*
- * Top level evaluation function, returning a string. If "skip" is TRUE,
- * only parsing to "nextcmd" is done, without reporting errors. Return
- * pointer to allocated memory, or NULL for failure or when "skip" is TRUE.
- */
-char_u *
-eval_to_string_skip (
- char_u *arg,
- char_u **nextcmd,
- int skip /* only parse, don't execute */
-)
+/// Top level evaluation function, returning a string
+///
+/// @param[in] arg String to evaluate.
+/// @param nextcmd Pointer to the start of the next Ex command.
+/// @param[in] skip If true, only do parsing to nextcmd without reporting
+/// errors or actually evaluating anything.
+///
+/// @return [allocated] string result of evaluation or NULL in case of error or
+/// when skipping.
+char *eval_to_string_skip(const char *arg, const char **nextcmd,
+ const bool skip)
+ FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT
{
typval_T tv;
- char_u *retval;
+ char *retval;
- if (skip)
- ++emsg_skip;
- if (eval0(arg, &tv, nextcmd, !skip) == FAIL || skip)
+ if (skip) {
+ emsg_skip++;
+ }
+ if (eval0((char_u *)arg, &tv, (char_u **)nextcmd, !skip) == FAIL || skip) {
retval = NULL;
- else {
- retval = vim_strsave(get_tv_string(&tv));
- clear_tv(&tv);
+ } else {
+ retval = xstrdup(tv_get_string(&tv));
+ tv_clear(&tv);
+ }
+ if (skip) {
+ emsg_skip--;
}
- if (skip)
- --emsg_skip;
return retval;
}
@@ -983,31 +1022,33 @@ int skip_expr(char_u **pp)
char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert)
{
typval_T tv;
- char_u *retval;
+ char *retval;
garray_T ga;
- char_u numbuf[NUMBUFLEN];
- if (eval0(arg, &tv, nextcmd, TRUE) == FAIL)
+ if (eval0(arg, &tv, nextcmd, true) == FAIL) {
retval = NULL;
- else {
+ } else {
if (convert && tv.v_type == VAR_LIST) {
ga_init(&ga, (int)sizeof(char), 80);
if (tv.vval.v_list != NULL) {
- list_join(&ga, tv.vval.v_list, "\n");
- if (tv.vval.v_list->lv_len > 0)
+ tv_list_join(&ga, tv.vval.v_list, "\n");
+ if (tv.vval.v_list->lv_len > 0) {
ga_append(&ga, NL);
+ }
}
ga_append(&ga, NUL);
- retval = (char_u *)ga.ga_data;
+ retval = (char *)ga.ga_data;
} else if (convert && tv.v_type == VAR_FLOAT) {
- vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", tv.vval.v_float);
- retval = vim_strsave(numbuf);
- } else
- retval = vim_strsave(get_tv_string(&tv));
- clear_tv(&tv);
+ char numbuf[NUMBUFLEN];
+ vim_snprintf(numbuf, NUMBUFLEN, "%g", tv.vval.v_float);
+ retval = xstrdup(numbuf);
+ } else {
+ retval = xstrdup(tv_get_string(&tv));
+ }
+ tv_clear(&tv);
}
- return retval;
+ return (char_u *)retval;
}
/*
@@ -1044,11 +1085,11 @@ int eval_to_number(char_u *expr)
++emsg_off;
- if (eval1(&p, &rettv, TRUE) == FAIL)
+ if (eval1(&p, &rettv, true) == FAIL) {
retval = -1;
- else {
- retval = get_tv_number_chk(&rettv, NULL);
- clear_tv(&rettv);
+ } else {
+ retval = tv_get_number_chk(&rettv, NULL);
+ tv_clear(&rettv);
}
--emsg_off;
@@ -1105,11 +1146,12 @@ list_T *eval_spell_expr(char_u *badword, char_u *expr)
if (p_verbose == 0)
++emsg_off;
- if (eval1(&p, &rettv, TRUE) == OK) {
- if (rettv.v_type != VAR_LIST)
- clear_tv(&rettv);
- else
+ if (eval1(&p, &rettv, true) == OK) {
+ if (rettv.v_type != VAR_LIST) {
+ tv_clear(&rettv);
+ } else {
list = rettv.vval.v_list;
+ }
}
if (p_verbose == 0)
@@ -1125,36 +1167,21 @@ list_T *eval_spell_expr(char_u *badword, char_u *expr)
* Return -1 if anything isn't right.
* Used to get the good word and score from the eval_spell_expr() result.
*/
-int get_spellword(list_T *list, char_u **pp)
+int get_spellword(list_T *list, const char **pp)
{
listitem_T *li;
li = list->lv_first;
- if (li == NULL)
+ if (li == NULL) {
return -1;
- *pp = get_tv_string(&li->li_tv);
+ }
+ *pp = tv_get_string(&li->li_tv);
li = li->li_next;
- if (li == NULL)
+ if (li == NULL) {
return -1;
- return get_tv_number(&li->li_tv);
-}
-
-/*
- * Top level evaluation function.
- * Returns an allocated typval_T with the result.
- * Returns NULL when there is an error.
- */
-typval_T *eval_expr(char_u *arg, char_u **nextcmd)
-{
- typval_T *tv = xmalloc(sizeof(typval_T));
-
- if (eval0(arg, tv, nextcmd, TRUE) == FAIL) {
- xfree(tv);
- return NULL;
}
-
- return tv;
+ return tv_get_number(&li->li_tv);
}
@@ -1164,9 +1191,9 @@ typval_T *eval_expr(char_u *arg, char_u **nextcmd)
//
// Return OK or FAIL.
int call_vim_function(
- char_u *func,
+ const char_u *func,
int argc,
- char_u **argv,
+ const char_u *const *const argv,
int safe, // use the sandbox
int str_arg_only, // all arguments are strings
typval_T *rettv
@@ -1199,7 +1226,7 @@ int call_vim_function(
argvars[i].vval.v_number = n;
} else {
argvars[i].v_type = VAR_STRING;
- argvars[i].vval.v_string = argv[i];
+ argvars[i].vval.v_string = (char_u *)argv[i];
}
}
@@ -1208,7 +1235,7 @@ int call_vim_function(
++sandbox;
}
- rettv->v_type = VAR_UNKNOWN; // clear_tv() uses this
+ rettv->v_type = VAR_UNKNOWN; // tv_clear() uses this.
ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars, NULL,
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&doesrange, true, NULL, NULL);
@@ -1219,7 +1246,7 @@ int call_vim_function(
xfree(argvars);
if (ret == FAIL) {
- clear_tv(rettv);
+ tv_clear(rettv);
}
return ret;
@@ -1234,8 +1261,8 @@ long
call_func_retnr (
char_u *func,
int argc,
- char_u **argv,
- int safe /* use the sandbox */
+ const char_u *const *const argv,
+ int safe // use the sandbox
)
{
typval_T rettv;
@@ -1245,33 +1272,34 @@ call_func_retnr (
if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL)
return -1;
- retval = get_tv_number_chk(&rettv, NULL);
- clear_tv(&rettv);
+ retval = tv_get_number_chk(&rettv, NULL);
+ tv_clear(&rettv);
return retval;
}
-/*
- * Call vimL function "func" and return the result as a string.
- * Returns NULL when calling the function fails.
- * Uses argv[argc] for the function arguments.
- */
-void *
-call_func_retstr (
- char_u *func,
- int argc,
- char_u **argv,
- int safe /* use the sandbox */
-)
+/// Call VimL function and return the result as a string
+///
+/// @param[in] func Function name.
+/// @param[in] argc Number of arguments.
+/// @param[in] argv Array with string arguments.
+/// @param[in] safe Use the sandbox.
+///
+/// @return [allocated] NULL when calling function failes, allocated string
+/// otherwise.
+char *call_func_retstr(const char *const func, const int argc,
+ const char_u *const *const argv,
+ const bool safe)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
{
typval_T rettv;
- char_u *retval;
-
- /* All arguments are passed as strings, no conversion to number. */
- if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL)
+ // All arguments are passed as strings, no conversion to number.
+ if (call_vim_function((const char_u *)func, argc, argv, safe, true, &rettv)
+ == FAIL) {
return NULL;
+ }
- retval = vim_strsave(get_tv_string(&rettv));
- clear_tv(&rettv);
+ char *const retval = xstrdup(tv_get_string(&rettv));
+ tv_clear(&rettv);
return retval;
}
@@ -1284,8 +1312,8 @@ void *
call_func_retlist (
char_u *func,
int argc,
- char_u **argv,
- int safe /* use the sandbox */
+ const char_u *const *const argv,
+ int safe // use the sandbox
)
{
typval_T rettv;
@@ -1295,7 +1323,7 @@ call_func_retlist (
return NULL;
if (rettv.v_type != VAR_LIST) {
- clear_tv(&rettv);
+ tv_clear(&rettv);
return NULL;
}
@@ -1393,7 +1421,7 @@ int eval_foldexpr(char_u *arg, int *cp)
*cp = *s++;
retval = atol((char *)s);
}
- clear_tv(&tv);
+ tv_clear(&tv);
}
--emsg_off;
if (use_sandbox)
@@ -1424,11 +1452,13 @@ void ex_let(exarg_T *eap)
char_u *argend;
int first = TRUE;
- argend = skip_var_list(arg, &var_count, &semicolon);
- if (argend == NULL)
+ argend = (char_u *)skip_var_list(arg, &var_count, &semicolon);
+ if (argend == NULL) {
return;
- if (argend > arg && argend[-1] == '.') /* for var.='str' */
- --argend;
+ }
+ if (argend > arg && argend[-1] == '.') { // For var.='str'.
+ argend--;
+ }
expr = skipwhite(argend);
if (*expr != '=' && !(vim_strchr((char_u *)"+-.", *expr) != NULL
&& expr[1] == '=')) {
@@ -1465,13 +1495,13 @@ void ex_let(exarg_T *eap)
++emsg_skip;
i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip);
if (eap->skip) {
- if (i != FAIL)
- clear_tv(&rettv);
- --emsg_skip;
+ if (i != FAIL) {
+ tv_clear(&rettv);
+ }
+ emsg_skip--;
} else if (i != FAIL) {
- (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
- op);
- clear_tv(&rettv);
+ (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, op);
+ tv_clear(&rettv);
}
}
}
@@ -1494,7 +1524,7 @@ ex_let_vars (
char_u *nextchars
)
{
- char_u *arg = arg_start;
+ char_u *arg = arg_start;
list_T *l;
int i;
listitem_T *item;
@@ -1517,7 +1547,7 @@ ex_let_vars (
return FAIL;
}
- i = list_len(l);
+ i = tv_list_len(l);
if (semicolon == 0 && var_count < i) {
EMSG(_("E687: Less targets than List items"));
return FAIL;
@@ -1539,9 +1569,9 @@ ex_let_vars (
if (*arg == ';') {
/* Put the rest of the list (may be empty) in the var after ';'.
* Create a new list for this. */
- l = list_alloc();
+ l = tv_list_alloc();
while (item != NULL) {
- list_append_tv(l, &item->li_tv);
+ tv_list_append_tv(l, &item->li_tv);
item = item->li_next;
}
@@ -1550,11 +1580,12 @@ ex_let_vars (
ltv.vval.v_list = l;
l->lv_refcount = 1;
- arg = ex_let_one(skipwhite(arg + 1), &ltv, FALSE,
- (char_u *)"]", nextchars);
- clear_tv(&ltv);
- if (arg == NULL)
+ arg = ex_let_one(skipwhite(arg + 1), &ltv, false,
+ (char_u *)"]", nextchars);
+ tv_clear(&ltv);
+ if (arg == NULL) {
return FAIL;
+ }
break;
} else if (*arg != ',' && *arg != ']') {
EMSG2(_(e_intern2), "ex_let_vars()");
@@ -1572,9 +1603,11 @@ ex_let_vars (
* for "[var, var; var]" set "semicolon".
* Return NULL for an error.
*/
-static char_u *skip_var_list(char_u *arg, int *var_count, int *semicolon)
+static const char_u *skip_var_list(const char_u *arg, int *var_count,
+ int *semicolon)
{
- char_u *p, *s;
+ const char_u *p;
+ const char_u *s;
if (*arg == '[') {
/* "[var, var]": find the matching ']'. */
@@ -1611,7 +1644,7 @@ static char_u *skip_var_list(char_u *arg, int *var_count, int *semicolon)
* Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
* l[idx].
*/
-static char_u *skip_var_one(char_u *arg)
+static const char_u *skip_var_one(const char_u *arg)
{
if (*arg == '@' && arg[1] != NUL)
return arg + 2;
@@ -1634,7 +1667,7 @@ static void list_hashtable_vars(hashtab_T *ht, const char *prefix, int empty,
for (hi = ht->ht_array; todo > 0 && !got_int; ++hi) {
if (!HASHITEM_EMPTY(hi)) {
todo--;
- di = HI2DI(hi);
+ di = TV_DICT_HI2DI(hi);
if (empty || di->di_tv.v_type != VAR_STRING
|| di->di_tv.vval.v_string != NULL) {
list_one_var(di, prefix, first);
@@ -1775,7 +1808,7 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
tv.v_type, s == NULL ? "" : s, first);
xfree(s);
}
- clear_tv(&tv);
+ tv_clear(&tv);
}
}
}
@@ -1789,34 +1822,37 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
return arg;
}
-/*
- * Set one item of ":let var = expr" or ":let [v1, v2] = list" to its value.
- * Returns a pointer to the char just after the var name.
- * Returns NULL if there is an error.
- */
-static char_u *
-ex_let_one (
- char_u *arg, /* points to variable name */
- typval_T *tv, /* value to assign to variable */
- int copy, /* copy value from "tv" */
- char_u *endchars, /* valid chars after variable name or NULL */
- char_u *op /* "+", "-", "." or NULL*/
-)
-{
- char_u *name;
- char_u *arg_end = NULL;
+// TODO(ZyX-I): move to eval/ex_cmds
+
+/// Set one item of `:let var = expr` or `:let [v1, v2] = list` to its value
+///
+/// @param[in] arg Start of the variable name.
+/// @param[in] tv Value to assign to the variable.
+/// @param[in] copy If true, copy value from `tv`.
+/// @param[in] endchars Valid characters after variable name or NULL.
+/// @param[in] op Operation performed: *op is `+`, `-`, `.` for `+=`, etc.
+/// NULL for `=`.
+///
+/// @return a pointer to the char just after the var name or NULL in case of
+/// error.
+static char_u *ex_let_one(char_u *arg, typval_T *const tv,
+ const bool copy, const char_u *const endchars,
+ const char_u *const op)
+ FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ char_u *arg_end = NULL;
int len;
int opt_flags;
- char_u *tofree = NULL;
+ char_u *tofree = NULL;
/*
* ":let $VAR = expr": Set environment variable.
*/
if (*arg == '$') {
- /* Find the end of the name. */
- ++arg;
- name = arg;
- len = get_env_len(&arg);
+ // Find the end of the name.
+ arg++;
+ char *name = (char *)arg;
+ len = get_env_len((const char_u **)&arg);
if (len == 0) {
EMSG2(_(e_invarg2), name - 1);
} else {
@@ -1826,26 +1862,28 @@ ex_let_one (
&& vim_strchr(endchars, *skipwhite(arg)) == NULL) {
EMSG(_(e_letunexp));
} else if (!check_secure()) {
- const char_u c1 = name[len];
+ const char c1 = name[len];
name[len] = NUL;
- char_u *p = get_tv_string_chk(tv);
+ const char *p = tv_get_string_chk(tv);
if (p != NULL && op != NULL && *op == '.') {
- char *s = vim_getenv((char *)name);
+ char *s = vim_getenv(name);
if (s != NULL) {
- p = tofree = concat_str((char_u *)s, p);
+ tofree = concat_str((const char_u *)s, (const char_u *)p);
+ p = (const char *)tofree;
xfree(s);
}
}
if (p != NULL) {
- vim_setenv((char *)name, (char *)p);
- if (STRICMP(name, "HOME") == 0)
+ vim_setenv(name, p);
+ if (STRICMP(name, "HOME") == 0) {
init_homedir();
- else if (didset_vim && STRICMP(name, "VIM") == 0)
- didset_vim = FALSE;
- else if (didset_vimruntime
- && STRICMP(name, "VIMRUNTIME") == 0)
- didset_vimruntime = FALSE;
+ } else if (didset_vim && STRICMP(name, "VIM") == 0) {
+ didset_vim = false;
+ } else if (didset_vimruntime
+ && STRICMP(name, "VIMRUNTIME") == 0) {
+ didset_vimruntime = false;
+ }
arg_end = arg;
}
name[len] = c1;
@@ -1863,19 +1901,18 @@ ex_let_one (
&& vim_strchr(endchars, *skipwhite((const char_u *)p)) == NULL)) {
EMSG(_(e_letunexp));
} else {
- long n;
int opt_type;
long numval;
- char_u *stringval = NULL;
- char_u *s;
+ char *stringval = NULL;
const char c1 = *p;
*p = NUL;
- n = get_tv_number(tv);
- s = get_tv_string_chk(tv); /* != NULL if number or string */
+ varnumber_T n = tv_get_number(tv);
+ const char *s = tv_get_string_chk(tv); // != NULL if number or string.
if (s != NULL && op != NULL && *op != '=') {
- opt_type = get_option_value(arg, &numval, &stringval, opt_flags);
+ opt_type = get_option_value(arg, &numval, (char_u **)&stringval,
+ opt_flags);
if ((opt_type == 1 && *op == '.')
|| (opt_type == 0 && *op != '.')) {
EMSG2(_(e_letwrong), op);
@@ -1887,44 +1924,45 @@ ex_let_one (
n = numval - n;
}
} else if (opt_type == 0 && stringval != NULL) { // string
- s = concat_str(stringval, s);
- xfree(stringval);
- stringval = s;
+ char *const oldstringval = stringval;
+ stringval = (char *)concat_str((const char_u *)stringval,
+ (const char_u *)s);
+ xfree(oldstringval);
+ s = stringval;
}
}
}
if (s != NULL) {
- set_option_value(arg, n, s, opt_flags);
+ set_option_value((const char *)arg, n, s, opt_flags);
arg_end = (char_u *)p;
}
*p = c1;
xfree(stringval);
}
- }
- /*
- * ":let @r = expr": Set register contents.
- */
- else if (*arg == '@') {
- ++arg;
- if (op != NULL && (*op == '+' || *op == '-'))
- EMSG2(_(e_letwrong), op);
- else if (endchars != NULL
- && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
- EMSG(_(e_letunexp));
- else {
- char_u *ptofree = NULL;
+ // ":let @r = expr": Set register contents.
+ } else if (*arg == '@') {
+ arg++;
+ if (op != NULL && (*op == '+' || *op == '-')) {
+ emsgf(_(e_letwrong), op);
+ } else if (endchars != NULL
+ && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL) {
+ emsgf(_(e_letunexp));
+ } else {
char_u *s;
- char_u *p = get_tv_string_chk(tv);
+ char_u *ptofree = NULL;
+ const char *p = tv_get_string_chk(tv);
if (p != NULL && op != NULL && *op == '.') {
s = get_reg_contents(*arg == '@' ? '"' : *arg, kGRegExprSrc);
if (s != NULL) {
- p = ptofree = concat_str(s, p);
+ ptofree = concat_str(s, (const char_u *)p);
+ p = (const char *)ptofree;
xfree(s);
}
}
if (p != NULL) {
- write_reg_contents(*arg == '@' ? '"' : *arg, p, STRLEN(p), false);
+ write_reg_contents(*arg == '@' ? '"' : *arg,
+ (const char_u *)p, STRLEN(p), false);
arg_end = arg + 1;
}
xfree(ptofree);
@@ -1939,9 +1977,9 @@ ex_let_one (
char_u *const p = get_lval(arg, tv, &lv, false, false, 0, FNE_CHECK_START);
if (p != NULL && lv.ll_name != NULL) {
- if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL)
+ if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL) {
EMSG(_(e_letunexp));
- else {
+ } else {
set_var_lval(&lv, p, tv, copy, op);
arg_end = p;
}
@@ -1953,6 +1991,8 @@ ex_let_one (
return arg_end;
}
+// TODO(ZyX-I): move to eval/executor
+
/// Get an lvalue
///
/// Lvalue may be
@@ -1981,16 +2021,11 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
const int flags, const int fne_flags)
FUNC_ATTR_NONNULL_ARG(1, 3)
{
- char_u *p;
- char_u *expr_start, *expr_end;
- int cc;
dictitem_T *v;
typval_T var1;
typval_T var2;
int empty1 = FALSE;
listitem_T *ni;
- char_u *key = NULL;
- int len;
hashtab_T *ht;
int quiet = flags & GLV_QUIET;
@@ -1998,13 +2033,19 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
memset(lp, 0, sizeof(lval_T));
if (skip) {
- /* When skipping just find the end of the name. */
- lp->ll_name = name;
- return find_name_end(name, NULL, NULL, FNE_INCL_BR | fne_flags);
+ // When skipping just find the end of the name.
+ lp->ll_name = (const char *)name;
+ return (char_u *)find_name_end((const char_u *)name, NULL, NULL,
+ FNE_INCL_BR | fne_flags);
}
- /* Find the end of the name. */
- p = find_name_end(name, &expr_start, &expr_end, fne_flags);
+ // Find the end of the name.
+ char_u *expr_start;
+ char_u *expr_end;
+ char_u *p = (char_u *)find_name_end(name,
+ (const char_u **)&expr_start,
+ (const char_u **)&expr_end,
+ fne_flags);
if (expr_start != NULL) {
/* Don't expand the name when we already know there is an error. */
if (unlet && !ascii_iswhite(*p) && !ends_excmd(*p)
@@ -2013,7 +2054,9 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
return NULL;
}
- lp->ll_exp_name = make_expanded_name(name, expr_start, expr_end, p);
+ lp->ll_exp_name = (char *)make_expanded_name(name, expr_start, expr_end,
+ (char_u *)p);
+ lp->ll_name = lp->ll_exp_name;
if (lp->ll_exp_name == NULL) {
/* Report an invalid expression in braces, unless the
* expression evaluation has been cancelled due to an
@@ -2023,25 +2066,28 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
EMSG2(_(e_invarg2), name);
return NULL;
}
+ lp->ll_name_len = 0;
+ } else {
+ lp->ll_name_len = strlen(lp->ll_name);
}
- lp->ll_name = lp->ll_exp_name;
- } else
- lp->ll_name = name;
+ } else {
+ lp->ll_name = (const char *)name;
+ lp->ll_name_len = (size_t)((const char *)p - lp->ll_name);
+ }
- /* Without [idx] or .key we are done. */
- if ((*p != '[' && *p != '.') || lp->ll_name == NULL)
+ // Without [idx] or .key we are done.
+ if ((*p != '[' && *p != '.') || lp->ll_name == NULL) {
return p;
+ }
- cc = *p;
- *p = NUL;
- v = find_var((const char *)lp->ll_name, STRLEN(lp->ll_name), &ht,
- flags & GLV_NO_AUTOLOAD);
+ v = find_var(lp->ll_name, lp->ll_name_len, &ht, flags & GLV_NO_AUTOLOAD);
if (v == NULL && !quiet) {
- EMSG2(_(e_undefvar), lp->ll_name);
+ emsgf(_("E121: Undefined variable: %.*s"),
+ (int)lp->ll_name_len, lp->ll_name);
}
- *p = cc;
- if (v == NULL)
+ if (v == NULL) {
return NULL;
+ }
/*
* Loop until no more [idx] or .key is following.
@@ -2061,29 +2107,32 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
return NULL;
}
- len = -1;
+ int len = -1;
+ char_u *key = NULL;
if (*p == '.') {
key = p + 1;
- for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len)
- ;
+ for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; len++) {
+ }
if (len == 0) {
- if (!quiet)
- EMSG(_(e_emptykey));
+ if (!quiet) {
+ EMSG(_("E713: Cannot use empty key after ."));
+ }
return NULL;
}
p = key + len;
} else {
/* Get the index [expr] or the first index [expr: ]. */
p = skipwhite(p + 1);
- if (*p == ':')
- empty1 = TRUE;
- else {
- empty1 = FALSE;
- if (eval1(&p, &var1, TRUE) == FAIL) /* recursive! */
+ if (*p == ':') {
+ empty1 = true;
+ } else {
+ empty1 = false;
+ if (eval1(&p, &var1, true) == FAIL) { // Recursive!
return NULL;
- if (get_tv_string_chk(&var1) == NULL) {
- /* not a number or string */
- clear_tv(&var1);
+ }
+ if (!tv_check_str(&var1)) {
+ // Not a number or string.
+ tv_clear(&var1);
return NULL;
}
}
@@ -2091,35 +2140,41 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
/* Optionally get the second index [ :expr]. */
if (*p == ':') {
if (lp->ll_tv->v_type == VAR_DICT) {
- if (!quiet)
+ if (!quiet) {
EMSG(_(e_dictrange));
- if (!empty1)
- clear_tv(&var1);
+ }
+ if (!empty1) {
+ tv_clear(&var1);
+ }
return NULL;
}
if (rettv != NULL && (rettv->v_type != VAR_LIST
|| rettv->vval.v_list == NULL)) {
- if (!quiet)
- EMSG(_("E709: [:] requires a List value"));
- if (!empty1)
- clear_tv(&var1);
+ if (!quiet) {
+ emsgf(_("E709: [:] requires a List value"));
+ }
+ if (!empty1) {
+ tv_clear(&var1);
+ }
return NULL;
}
p = skipwhite(p + 1);
- if (*p == ']')
- lp->ll_empty2 = TRUE;
- else {
- lp->ll_empty2 = FALSE;
- if (eval1(&p, &var2, TRUE) == FAIL) { /* recursive! */
- if (!empty1)
- clear_tv(&var1);
+ if (*p == ']') {
+ lp->ll_empty2 = true;
+ } else {
+ lp->ll_empty2 = false;
+ if (eval1(&p, &var2, true) == FAIL) { // Recursive!
+ if (!empty1) {
+ tv_clear(&var1);
+ }
return NULL;
}
- if (get_tv_string_chk(&var2) == NULL) {
- /* not a number or string */
- if (!empty1)
- clear_tv(&var1);
- clear_tv(&var2);
+ if (!tv_check_str(&var2)) {
+ // Not a number or string.
+ if (!empty1) {
+ tv_clear(&var1);
+ }
+ tv_clear(&var2);
return NULL;
}
}
@@ -2128,12 +2183,15 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
lp->ll_range = FALSE;
if (*p != ']') {
- if (!quiet)
- EMSG(_(e_missbrac));
- if (!empty1)
- clear_tv(&var1);
- if (lp->ll_range && !lp->ll_empty2)
- clear_tv(&var2);
+ if (!quiet) {
+ emsgf(_(e_missbrac));
+ }
+ if (!empty1) {
+ tv_clear(&var1);
+ }
+ if (lp->ll_range && !lp->ll_empty2) {
+ tv_clear(&var2);
+ }
return NULL;
}
@@ -2144,15 +2202,15 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
if (lp->ll_tv->v_type == VAR_DICT) {
if (len == -1) {
// "[key]": get key from "var1"
- key = get_tv_string_chk(&var1); // is number or string
+ key = (char_u *)tv_get_string(&var1); // is number or string
if (key == NULL) {
- clear_tv(&var1);
+ tv_clear(&var1);
return NULL;
}
}
lp->ll_list = NULL;
lp->ll_dict = lp->ll_tv->vval.v_dict;
- lp->ll_di = dict_find(lp->ll_dict, key, len);
+ lp->ll_di = tv_dict_find(lp->ll_dict, (const char *)key, len);
/* When assigning to a scope dictionary check that a function and
* variable name is valid (only variable name unless it is l: or
@@ -2164,16 +2222,19 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
if (len != -1) {
prevval = key[len];
key[len] = NUL;
- } else
- prevval = 0; /* avoid compiler warning */
- wrong = (lp->ll_dict->dv_scope == VAR_DEF_SCOPE
- && rettv->v_type == VAR_FUNC
- && var_check_func_name(key, lp->ll_di == NULL))
- || !valid_varname(key);
- if (len != -1)
+ } else {
+ prevval = 0; // Avoid compiler warning.
+ }
+ wrong = ((lp->ll_dict->dv_scope == VAR_DEF_SCOPE
+ && tv_is_func(*rettv)
+ && !var_check_func_name((const char *)key, lp->ll_di == NULL))
+ || !valid_varname((const char *)key));
+ if (len != -1) {
key[len] = prevval;
- if (wrong)
+ }
+ if (wrong) {
return NULL;
+ }
}
if (lp->ll_di == NULL) {
@@ -2185,56 +2246,61 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
/* Key does not exist in dict: may need to add it. */
if (*p == '[' || *p == '.' || unlet) {
- if (!quiet)
- EMSG2(_(e_dictkey), key);
- if (len == -1)
- clear_tv(&var1);
+ if (!quiet) {
+ emsgf(_(e_dictkey), key);
+ }
+ if (len == -1) {
+ tv_clear(&var1);
+ }
return NULL;
}
- if (len == -1)
+ if (len == -1) {
lp->ll_newkey = vim_strsave(key);
- else
+ } else {
lp->ll_newkey = vim_strnsave(key, len);
- if (len == -1)
- clear_tv(&var1);
+ }
+ if (len == -1) {
+ tv_clear(&var1);
+ }
break;
// existing variable, need to check if it can be changed
} else if (!(flags & GLV_READ_ONLY) && var_check_ro(lp->ll_di->di_flags,
(const char *)name,
(size_t)(p - name))) {
if (len == -1) {
- clear_tv(&var1);
+ tv_clear(&var1);
}
return NULL;
}
- if (len == -1)
- clear_tv(&var1);
+ if (len == -1) {
+ tv_clear(&var1);
+ }
lp->ll_tv = &lp->ll_di->di_tv;
} else {
- /*
- * Get the number and item for the only or first index of the List.
- */
- if (empty1)
+ // Get the number and item for the only or first index of the List.
+ if (empty1) {
lp->ll_n1 = 0;
- else {
- lp->ll_n1 = get_tv_number(&var1); /* is number or string */
- clear_tv(&var1);
+ } else {
+ lp->ll_n1 = tv_get_number(&var1); // Is number or string.
+ tv_clear(&var1);
}
lp->ll_dict = NULL;
lp->ll_list = lp->ll_tv->vval.v_list;
- lp->ll_li = list_find(lp->ll_list, lp->ll_n1);
+ lp->ll_li = tv_list_find(lp->ll_list, lp->ll_n1);
if (lp->ll_li == NULL) {
if (lp->ll_n1 < 0) {
lp->ll_n1 = 0;
- lp->ll_li = list_find(lp->ll_list, lp->ll_n1);
+ lp->ll_li = tv_list_find(lp->ll_list, lp->ll_n1);
}
}
if (lp->ll_li == NULL) {
- if (lp->ll_range && !lp->ll_empty2)
- clear_tv(&var2);
- if (!quiet)
+ if (lp->ll_range && !lp->ll_empty2) {
+ tv_clear(&var2);
+ }
+ if (!quiet) {
EMSGN(_(e_listidx), lp->ll_n1);
+ }
return NULL;
}
@@ -2245,24 +2311,26 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
* Otherwise "lp->ll_n2" is set to the second index.
*/
if (lp->ll_range && !lp->ll_empty2) {
- lp->ll_n2 = get_tv_number(&var2); /* is number or string */
- clear_tv(&var2);
+ lp->ll_n2 = tv_get_number(&var2); // Is number or string.
+ tv_clear(&var2);
if (lp->ll_n2 < 0) {
- ni = list_find(lp->ll_list, lp->ll_n2);
+ ni = tv_list_find(lp->ll_list, lp->ll_n2);
if (ni == NULL) {
if (!quiet)
EMSGN(_(e_listidx), lp->ll_n2);
return NULL;
}
- lp->ll_n2 = list_idx_of_item(lp->ll_list, ni);
+ lp->ll_n2 = tv_list_idx_of_item(lp->ll_list, ni);
}
- /* Check that lp->ll_n2 isn't before lp->ll_n1. */
- if (lp->ll_n1 < 0)
- lp->ll_n1 = list_idx_of_item(lp->ll_list, lp->ll_li);
+ // Check that lp->ll_n2 isn't before lp->ll_n1.
+ if (lp->ll_n1 < 0) {
+ lp->ll_n1 = tv_list_idx_of_item(lp->ll_list, lp->ll_li);
+ }
if (lp->ll_n2 < lp->ll_n1) {
- if (!quiet)
+ if (!quiet) {
EMSGN(_(e_listidx), lp->ll_n2);
+ }
return NULL;
}
}
@@ -2274,6 +2342,8 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
return p;
}
+// TODO(ZyX-I): move to eval/executor
+
/*
* Clear lval "lp" that was filled by get_lval().
*/
@@ -2283,12 +2353,15 @@ static void clear_lval(lval_T *lp)
xfree(lp->ll_newkey);
}
+// TODO(ZyX-I): move to eval/executor
+
/*
* Set a variable that was parsed by get_lval() to "rettv".
* "endp" points to just after the parsed name.
* "op" is NULL, "+" for "+=", "-" for "-=", "." for ".=" or "=" for "=".
*/
-static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, char_u *op)
+static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
+ int copy, const char_u *op)
{
int cc;
listitem_T *ri;
@@ -2309,13 +2382,13 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch
STRLEN(lp->ll_name))
&& !tv_check_lock(di->di_tv.v_lock, (const char *)lp->ll_name,
STRLEN(lp->ll_name))))
- && tv_op(&tv, rettv, op) == OK) {
- set_var(lp->ll_name, &tv, false);
+ && eexe_mod_op(&tv, rettv, (const char *)op) == OK) {
+ set_var(lp->ll_name, lp->ll_name_len, &tv, false);
}
- clear_tv(&tv);
+ tv_clear(&tv);
}
} else {
- set_var(lp->ll_name, rettv, copy);
+ set_var(lp->ll_name, lp->ll_name_len, rettv, copy);
}
*endp = cc;
} else if (tv_check_lock(lp->ll_newkey == NULL
@@ -2345,18 +2418,18 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch
* Assign the List values to the list items.
*/
for (ri = rettv->vval.v_list->lv_first; ri != NULL; ) {
- if (op != NULL && *op != '=')
- tv_op(&lp->ll_li->li_tv, &ri->li_tv, op);
- else {
- clear_tv(&lp->ll_li->li_tv);
- copy_tv(&ri->li_tv, &lp->ll_li->li_tv);
+ if (op != NULL && *op != '=') {
+ eexe_mod_op(&lp->ll_li->li_tv, &ri->li_tv, (const char *)op);
+ } else {
+ tv_clear(&lp->ll_li->li_tv);
+ tv_copy(&ri->li_tv, &lp->ll_li->li_tv);
}
ri = ri->li_next;
if (ri == NULL || (!lp->ll_empty2 && lp->ll_n2 == lp->ll_n1))
break;
if (lp->ll_li->li_next == NULL) {
- /* Need to add an empty item. */
- list_append_number(lp->ll_list, 0);
+ // Need to add an empty item.
+ tv_list_append_number(lp->ll_list, 0);
assert(lp->ll_li->li_next);
}
lp->ll_li = lp->ll_li->li_next;
@@ -2369,198 +2442,60 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch
: lp->ll_n1 != lp->ll_n2)
EMSG(_("E711: List value has not enough items"));
} else {
- typval_T oldtv;
+ typval_T oldtv = TV_INITIAL_VALUE;
dict_T *dict = lp->ll_dict;
- bool watched = is_watched(dict);
+ bool watched = tv_dict_is_watched(dict);
- if (watched) {
- init_tv(&oldtv);
- }
-
- /*
- * Assign to a List or Dictionary item.
- */
+ // Assign to a List or Dictionary item.
if (lp->ll_newkey != NULL) {
if (op != NULL && *op != '=') {
EMSG2(_(e_letwrong), op);
return;
}
- /* Need to add an item to the Dictionary. */
- di = dictitem_alloc(lp->ll_newkey);
- if (dict_add(lp->ll_tv->vval.v_dict, di) == FAIL) {
+ // Need to add an item to the Dictionary.
+ di = tv_dict_item_alloc((const char *)lp->ll_newkey);
+ if (tv_dict_add(lp->ll_tv->vval.v_dict, di) == FAIL) {
xfree(di);
return;
}
lp->ll_tv = &di->di_tv;
} else {
if (watched) {
- copy_tv(lp->ll_tv, &oldtv);
+ tv_copy(lp->ll_tv, &oldtv);
}
if (op != NULL && *op != '=') {
- tv_op(lp->ll_tv, rettv, op);
+ eexe_mod_op(lp->ll_tv, rettv, (const char *)op);
goto notify;
} else {
- clear_tv(lp->ll_tv);
+ tv_clear(lp->ll_tv);
}
}
// Assign the value to the variable or list item.
if (copy) {
- copy_tv(rettv, lp->ll_tv);
+ tv_copy(rettv, lp->ll_tv);
} else {
*lp->ll_tv = *rettv;
lp->ll_tv->v_lock = 0;
- init_tv(rettv);
+ tv_init(rettv);
}
notify:
if (watched) {
if (oldtv.v_type == VAR_UNKNOWN) {
- dictwatcher_notify(dict, (char *)lp->ll_newkey, lp->ll_tv, NULL);
+ tv_dict_watcher_notify(dict, (char *)lp->ll_newkey, lp->ll_tv, NULL);
} else {
dictitem_T *di = lp->ll_di;
- dictwatcher_notify(dict, (char *)di->di_key, lp->ll_tv, &oldtv);
- clear_tv(&oldtv);
- }
- }
- }
-}
-
-/*
- * Handle "tv1 += tv2", "tv1 -= tv2" and "tv1 .= tv2"
- * Returns OK or FAIL.
- */
-static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
-{
- long n;
- char_u numbuf[NUMBUFLEN];
- char_u *s;
-
- // Can't do anything with a Funcref, a Dict or special value on the right.
- if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT) {
- switch (tv1->v_type) {
- case VAR_DICT:
- case VAR_FUNC:
- case VAR_PARTIAL:
- case VAR_SPECIAL:
- break;
-
- case VAR_LIST:
- if (*op != '+' || tv2->v_type != VAR_LIST)
- break;
- /* List += List */
- if (tv1->vval.v_list != NULL && tv2->vval.v_list != NULL)
- list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL);
- return OK;
-
- case VAR_NUMBER:
- case VAR_STRING:
- if (tv2->v_type == VAR_LIST)
- break;
- if (*op == '+' || *op == '-') {
- /* nr += nr or nr -= nr*/
- n = get_tv_number(tv1);
- if (tv2->v_type == VAR_FLOAT) {
- float_T f = n;
-
- if (*op == '+')
- f += tv2->vval.v_float;
- else
- f -= tv2->vval.v_float;
- clear_tv(tv1);
- tv1->v_type = VAR_FLOAT;
- tv1->vval.v_float = f;
- } else {
- if (*op == '+')
- n += get_tv_number(tv2);
- else
- n -= get_tv_number(tv2);
- clear_tv(tv1);
- tv1->v_type = VAR_NUMBER;
- tv1->vval.v_number = n;
- }
- } else {
- if (tv2->v_type == VAR_FLOAT)
- break;
-
- /* str .= str */
- s = get_tv_string(tv1);
- s = concat_str(s, get_tv_string_buf(tv2, numbuf));
- clear_tv(tv1);
- tv1->v_type = VAR_STRING;
- tv1->vval.v_string = s;
+ tv_dict_watcher_notify(dict, (char *)di->di_key, lp->ll_tv, &oldtv);
+ tv_clear(&oldtv);
}
- return OK;
-
- case VAR_FLOAT:
- {
- float_T f;
-
- if (*op == '.' || (tv2->v_type != VAR_FLOAT
- && tv2->v_type != VAR_NUMBER
- && tv2->v_type != VAR_STRING))
- break;
- if (tv2->v_type == VAR_FLOAT)
- f = tv2->vval.v_float;
- else
- f = get_tv_number(tv2);
- if (*op == '+')
- tv1->vval.v_float += f;
- else
- tv1->vval.v_float -= f;
- }
- return OK;
-
- case VAR_UNKNOWN:
- assert(false);
- }
- }
-
- EMSG2(_(e_letwrong), op);
- return FAIL;
-}
-
-/*
- * Add a watcher to a list.
- */
-void list_add_watch(list_T *l, listwatch_T *lw)
-{
- lw->lw_next = l->lv_watch;
- l->lv_watch = lw;
-}
-
-/*
- * Remove a watcher from a list.
- * No warning when it isn't found...
- */
-void list_rem_watch(list_T *l, listwatch_T *lwrem)
-{
- listwatch_T *lw, **lwp;
-
- lwp = &l->lv_watch;
- for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next) {
- if (lw == lwrem) {
- *lwp = lw->lw_next;
- break;
}
- lwp = &lw->lw_next;
}
}
-/*
- * Just before removing an item from a list: advance watchers to the next
- * item.
- */
-static void list_fix_watch(list_T *l, listitem_T *item)
-{
- listwatch_T *lw;
-
- for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next)
- if (lw->lw_item == item)
- lw->lw_item = item->li_next;
-}
+// TODO(ZyX-I): move to eval/ex_cmds
/*
* Evaluate the expression used in a ":for var in expr" command.
@@ -2568,14 +2503,14 @@ static void list_fix_watch(list_T *l, listitem_T *item)
* Set "*errp" to TRUE for an error, FALSE otherwise;
* Return a pointer that holds the info. Null when there is an error.
*/
-void *eval_for_line(char_u *arg, int *errp, char_u **nextcmdp, int skip)
+void *eval_for_line(const char_u *arg, bool *errp, char_u **nextcmdp, int skip)
{
forinfo_T *fi = xcalloc(1, sizeof(forinfo_T));
- char_u *expr;
+ const char_u *expr;
typval_T tv;
list_T *l;
- *errp = TRUE; /* default: there is an error */
+ *errp = true; // Default: there is an error.
expr = skip_var_list(arg, &fi->fi_varcount, &fi->fi_semicolon);
if (expr == NULL)
@@ -2590,20 +2525,20 @@ void *eval_for_line(char_u *arg, int *errp, char_u **nextcmdp, int skip)
if (skip)
++emsg_skip;
if (eval0(skipwhite(expr + 2), &tv, nextcmdp, !skip) == OK) {
- *errp = FALSE;
+ *errp = false;
if (!skip) {
l = tv.vval.v_list;
if (tv.v_type != VAR_LIST) {
EMSG(_(e_listreq));
- clear_tv(&tv);
+ tv_clear(&tv);
} else if (l == NULL) {
// a null list is like an empty list: do nothing
- clear_tv(&tv);
+ tv_clear(&tv);
} else {
/* No need to increment the refcount, it's already set for the
* list being used in "tv". */
fi->fi_list = l;
- list_add_watch(l, &fi->fi_lw);
+ tv_list_watch_add(l, &fi->fi_lw);
fi->fi_lw.lw_item = l->lv_first;
}
}
@@ -2614,6 +2549,8 @@ void *eval_for_line(char_u *arg, int *errp, char_u **nextcmdp, int skip)
return fi;
}
+// TODO(ZyX-I): move to eval/ex_cmds
+
/*
* Use the first item in a ":for" list. Advance to the next.
* Assign the values to the variable (list). "arg" points to the first one.
@@ -2637,6 +2574,8 @@ int next_for_item(void *fi_void, char_u *arg)
return result;
}
+// TODO(ZyX-I): move to eval/ex_cmds
+
/*
* Free the structure used to store info used by ":for".
*/
@@ -2645,8 +2584,8 @@ void free_for_info(void *fi_void)
forinfo_T *fi = (forinfo_T *)fi_void;
if (fi != NULL && fi->fi_list != NULL) {
- list_rem_watch(fi->fi_list, &fi->fi_lw);
- list_unref(fi->fi_list);
+ tv_list_watch_remove(fi->fi_list, &fi->fi_lw);
+ tv_list_unref(fi->fi_list);
}
xfree(fi);
}
@@ -2734,6 +2673,7 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx)
xp->xp_pattern = arg;
}
+// TODO(ZyX-I): move to eval/ex_cmds
/*
* ":1,25call func(arg1, arg2)" function call.
@@ -2753,13 +2693,14 @@ void ex_call(exarg_T *eap)
partial_T *partial = NULL;
if (eap->skip) {
- /* trans_function_name() doesn't work well when skipping, use eval0()
- * instead to skip to any following command, e.g. for:
- * :if 0 | call dict.foo().bar() | endif */
- ++emsg_skip;
- if (eval0(eap->arg, &rettv, &eap->nextcmd, FALSE) != FAIL)
- clear_tv(&rettv);
- --emsg_skip;
+ // trans_function_name() doesn't work well when skipping, use eval0()
+ // instead to skip to any following command, e.g. for:
+ // :if 0 | call dict.foo().bar() | endif.
+ emsg_skip++;
+ if (eval0(eap->arg, &rettv, &eap->nextcmd, false) != FAIL) {
+ tv_clear(&rettv);
+ }
+ emsg_skip--;
return;
}
@@ -2787,7 +2728,7 @@ void ex_call(exarg_T *eap)
/* Skip white space to allow ":call func ()". Not good, but required for
* backward compatibility. */
startarg = skipwhite(arg);
- rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
+ rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this.
if (*startarg != '(') {
EMSG2(_("E107: Missing parentheses: %s"), eap->arg);
@@ -2826,9 +2767,10 @@ void ex_call(exarg_T *eap)
break;
}
- clear_tv(&rettv);
- if (doesrange || eap->skip)
+ tv_clear(&rettv);
+ if (doesrange || eap->skip) {
break;
+ }
/* Stop when immediately aborting on error, or when an interrupt
* occurred or an exception was thrown but not caught.
@@ -2850,10 +2792,12 @@ void ex_call(exarg_T *eap)
}
end:
- dict_unref(fudi.fd_dict);
+ tv_dict_unref(fudi.fd_dict);
xfree(tofree);
}
+// TODO(ZyX-I): move to eval/ex_cmds
+
/*
* ":unlet[!] var1 ... " command.
*/
@@ -2862,6 +2806,8 @@ void ex_unlet(exarg_T *eap)
ex_unletlock(eap, eap->arg, 0);
}
+// TODO(ZyX-I): move to eval/ex_cmds
+
/*
* ":lockvar" and ":unlockvar" commands
*/
@@ -2880,22 +2826,25 @@ void ex_lockvar(exarg_T *eap)
ex_unletlock(eap, arg, deep);
}
+// TODO(ZyX-I): move to eval/ex_cmds
+
/*
* ":unlet", ":lockvar" and ":unlockvar" are quite similar.
*/
static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep)
{
char_u *arg = argstart;
- char_u *name_end;
- int error = FALSE;
+ bool error = false;
lval_T lv;
do {
- /* Parse the name and find the end. */
- name_end = get_lval(arg, NULL, &lv, TRUE, eap->skip || error, 0,
- FNE_CHECK_START);
- if (lv.ll_name == NULL)
- error = TRUE; /* error but continue parsing */
+ // Parse the name and find the end.
+ char_u *const name_end = (char_u *)get_lval(arg, NULL, &lv, true,
+ eap->skip || error,
+ 0, FNE_CHECK_START);
+ if (lv.ll_name == NULL) {
+ error = true; // error, but continue parsing.
+ }
if (name_end == NULL || (!ascii_iswhite(*name_end)
&& !ends_excmd(*name_end))) {
if (name_end != NULL) {
@@ -2913,8 +2862,9 @@ static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep)
error = TRUE;
} else {
if (do_lock_var(&lv, name_end, deep,
- eap->cmdidx == CMD_lockvar) == FAIL)
- error = TRUE;
+ eap->cmdidx == CMD_lockvar) == FAIL) {
+ error = true;
+ }
}
}
@@ -2927,7 +2877,9 @@ static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep)
eap->nextcmd = check_nextcmd(arg);
}
-static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit)
+// TODO(ZyX-I): move to eval/ex_cmds
+
+static int do_unlet_var(lval_T *const lp, char_u *const name_end, int forceit)
{
int ret = OK;
int cc;
@@ -2937,17 +2889,17 @@ static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit)
*name_end = NUL;
// Normal name or expanded name.
- if (do_unlet(lp->ll_name, forceit) == FAIL) {
+ if (do_unlet(lp->ll_name, lp->ll_name_len, forceit) == FAIL) {
ret = FAIL;
}
*name_end = cc;
} else if ((lp->ll_list != NULL
&& tv_check_lock(lp->ll_list->lv_lock, (const char *)lp->ll_name,
- STRLEN(lp->ll_name)))
+ lp->ll_name_len))
|| (lp->ll_dict != NULL
&& tv_check_lock(lp->ll_dict->dv_lock,
(const char *)lp->ll_name,
- STRLEN(lp->ll_name)))) {
+ lp->ll_name_len))) {
return FAIL;
} else if (lp->ll_range) {
listitem_T *li;
@@ -2957,7 +2909,7 @@ static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit)
while (ll_li != NULL && (lp->ll_empty2 || lp->ll_n2 >= ll_n1)) {
li = ll_li->li_next;
if (tv_check_lock(ll_li->li_tv.v_lock, (const char *)lp->ll_name,
- STRLEN(lp->ll_name))) {
+ lp->ll_name_len)) {
return false;
}
ll_li = li;
@@ -2967,33 +2919,33 @@ static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit)
/* Delete a range of List items. */
while (lp->ll_li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1)) {
li = lp->ll_li->li_next;
- listitem_remove(lp->ll_list, lp->ll_li);
+ tv_list_item_remove(lp->ll_list, lp->ll_li);
lp->ll_li = li;
++lp->ll_n1;
}
} else {
if (lp->ll_list != NULL) {
// unlet a List item.
- listitem_remove(lp->ll_list, lp->ll_li);
+ tv_list_item_remove(lp->ll_list, lp->ll_li);
} else {
// unlet a Dictionary item.
dict_T *d = lp->ll_dict;
dictitem_T *di = lp->ll_di;
- bool watched = is_watched(d);
+ bool watched = tv_dict_is_watched(d);
char *key = NULL;
typval_T oldtv;
if (watched) {
- copy_tv(&di->di_tv, &oldtv);
+ tv_copy(&di->di_tv, &oldtv);
// need to save key because dictitem_remove will free it
key = xstrdup((char *)di->di_key);
}
- dictitem_remove(d, di);
+ tv_dict_item_remove(d, di);
if (watched) {
- dictwatcher_notify(d, key, NULL, &oldtv);
- clear_tv(&oldtv);
+ tv_dict_watcher_notify(d, key, NULL, &oldtv);
+ tv_clear(&oldtv);
xfree(key);
}
}
@@ -3002,22 +2954,24 @@ static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit)
return ret;
}
-/*
- * "unlet" a variable. Return OK if it existed, FAIL if not.
- * When "forceit" is TRUE don't complain if the variable doesn't exist.
- */
-int do_unlet(char_u *name, int forceit)
+// TODO(ZyX-I): move to eval/ex_cmds
+
+/// unlet a variable
+///
+/// @param[in] name Variable name to unlet.
+/// @param[in] name_len Variable name length.
+/// @param[in] fonceit If true, do not complain if variable doesn’t exist.
+///
+/// @return OK if it existed, FAIL otherwise.
+int do_unlet(const char *const name, const size_t name_len, const int forceit)
+ FUNC_ATTR_NONNULL_ALL
{
- hashtab_T *ht;
- hashitem_T *hi;
- char_u *varname;
- dict_T *d;
- dictitem_T *di;
+ const char *varname;
dict_T *dict;
- ht = find_var_ht_dict((const char *)name, STRLEN(name),
- (const char **)&varname, &dict);
+ hashtab_T *ht = find_var_ht_dict(name, name_len, &varname, &dict);
if (ht != NULL && *varname != NUL) {
+ dict_T *d;
if (ht == &globvarht) {
d = &globvardict;
} else if (current_funccal != NULL
@@ -3026,19 +2980,19 @@ int do_unlet(char_u *name, int forceit)
} else if (ht == &compat_hashtab) {
d = &vimvardict;
} else {
- di = find_var_in_ht(ht, *name, "", 0, false);
+ dictitem_T *const di = find_var_in_ht(ht, *name, "", 0, false);
d = di->di_tv.vval.v_dict;
}
if (d == NULL) {
EMSG2(_(e_intern2), "do_unlet()");
return FAIL;
}
- hi = hash_find(ht, varname);
+ hashitem_T *hi = hash_find(ht, (const char_u *)varname);
if (HASHITEM_EMPTY(hi)) {
hi = find_hi_in_scoped_ht((const char *)name, &ht);
}
if (hi != NULL && !HASHITEM_EMPTY(hi)) {
- di = HI2DI(hi);
+ dictitem_T *const di = TV_DICT_HI2DI(hi);
if (var_check_fixed(di->di_flags, (const char *)name, STRLEN(name))
|| var_check_ro(di->di_flags, (const char *)name, STRLEN(name))
|| tv_check_lock(d->dv_lock, (const char *)name, STRLEN(name))) {
@@ -3051,17 +3005,17 @@ int do_unlet(char_u *name, int forceit)
}
typval_T oldtv;
- bool watched = is_watched(dict);
+ bool watched = tv_dict_is_watched(dict);
if (watched) {
- copy_tv(&di->di_tv, &oldtv);
+ tv_copy(&di->di_tv, &oldtv);
}
delete_var(ht, hi);
if (watched) {
- dictwatcher_notify(dict, (char *)varname, NULL, &oldtv);
- clear_tv(&oldtv);
+ tv_dict_watcher_notify(dict, varname, NULL, &oldtv);
+ tv_clear(&oldtv);
}
return OK;
}
@@ -3072,12 +3026,15 @@ int do_unlet(char_u *name, int forceit)
return FAIL;
}
+// TODO(ZyX-I): move to eval/ex_cmds
+
/*
* Lock or unlock variable indicated by "lp".
* "deep" is the levels to go (-1 for unlimited);
* "lock" is TRUE for ":lockvar", FALSE for ":unlockvar".
*/
-static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock)
+static int do_lock_var(lval_T *lp, char_u *const name_end, const int deep,
+ const bool lock)
{
int ret = OK;
@@ -3087,9 +3044,8 @@ static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock)
if (lp->ll_tv == NULL) {
// Normal name or expanded name.
- const size_t name_len = (size_t)(name_end - lp->ll_name);
dictitem_T *const di = find_var(
- (const char *)lp->ll_name, name_len, NULL,
+ (const char *)lp->ll_name, lp->ll_name_len, NULL,
true);
if (di == NULL) {
ret = FAIL;
@@ -3105,134 +3061,39 @@ static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock)
} else {
di->di_flags &= ~DI_FLAGS_LOCK;
}
- item_lock(&di->di_tv, deep, lock);
+ tv_item_lock(&di->di_tv, deep, lock);
}
} else if (lp->ll_range) {
listitem_T *li = lp->ll_li;
/* (un)lock a range of List items. */
while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1)) {
- item_lock(&li->li_tv, deep, lock);
+ tv_item_lock(&li->li_tv, deep, lock);
li = li->li_next;
++lp->ll_n1;
}
} else if (lp->ll_list != NULL) {
// (un)lock a List item.
- item_lock(&lp->ll_li->li_tv, deep, lock);
+ tv_item_lock(&lp->ll_li->li_tv, deep, lock);
} else {
// (un)lock a Dictionary item.
- item_lock(&lp->ll_di->di_tv, deep, lock);
+ tv_item_lock(&lp->ll_di->di_tv, deep, lock);
}
return ret;
}
/*
- * Lock or unlock an item. "deep" is nr of levels to go.
- */
-static void item_lock(typval_T *tv, int deep, int lock)
-{
- static int recurse = 0;
-
- if (recurse >= DICT_MAXNEST) {
- EMSG(_("E743: variable nested too deep for (un)lock"));
- return;
- }
- if (deep == 0) {
- return;
- }
- recurse++;
-
- // lock/unlock the item itself
-#define CHANGE_LOCK(var, lock) \
- do { \
- var = ((VarLockStatus[]) { \
- [VAR_UNLOCKED] = (lock ? VAR_LOCKED : VAR_UNLOCKED), \
- [VAR_LOCKED] = (lock ? VAR_LOCKED : VAR_UNLOCKED), \
- [VAR_FIXED] = VAR_FIXED, \
- })[var]; \
- } while (0)
- CHANGE_LOCK(tv->v_lock, lock);
-
- switch (tv->v_type) {
- case VAR_LIST: {
- list_T *const l = tv->vval.v_list;
- if (l != NULL) {
- CHANGE_LOCK(l->lv_lock, lock);
- if (deep < 0 || deep > 1) {
- // Recursive: lock/unlock the items the List contains.
- for (listitem_T *li = l->lv_first; li != NULL; li = li->li_next) {
- item_lock(&li->li_tv, deep - 1, lock);
- }
- }
- }
- break;
- }
- case VAR_DICT: {
- dict_T *const d = tv->vval.v_dict;
- if (d != NULL) {
- CHANGE_LOCK(d->dv_lock, lock);
- if (deep < 0 || deep > 1) {
- // Recursive: lock/unlock the items the List contains.
- int todo = (int)d->dv_hashtab.ht_used;
- for (hashitem_T *hi = d->dv_hashtab.ht_array; todo > 0; hi++) {
- if (!HASHITEM_EMPTY(hi)) {
- todo--;
- item_lock(&HI2DI(hi)->di_tv, deep - 1, lock);
- }
- }
- }
- }
- break;
- }
- case VAR_NUMBER:
- case VAR_FLOAT:
- case VAR_STRING:
- case VAR_FUNC:
- case VAR_PARTIAL:
- case VAR_SPECIAL: {
- break;
- }
- case VAR_UNKNOWN: {
- assert(false);
- }
- }
-#undef CHANGE_LOCK
- recurse--;
-}
-
-/*
- * Return TRUE if typeval "tv" is locked: Either that value is locked itself
- * or it refers to a List or Dictionary that is locked.
- */
-static int tv_islocked(typval_T *tv)
-{
- return (tv->v_lock & VAR_LOCKED)
- || (tv->v_type == VAR_LIST
- && tv->vval.v_list != NULL
- && (tv->vval.v_list->lv_lock & VAR_LOCKED))
- || (tv->v_type == VAR_DICT
- && tv->vval.v_dict != NULL
- && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
-}
-
-/*
* Delete all "menutrans_" variables.
*/
void del_menutrans_vars(void)
{
- hashitem_T *hi;
- int todo;
-
hash_lock(&globvarht);
- todo = (int)globvarht.ht_used;
- for (hi = globvarht.ht_array; todo > 0 && !got_int; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- --todo;
- if (STRNCMP(HI2DI(hi)->di_key, "menutrans_", 10) == 0)
- delete_var(&globvarht, hi);
+ HASHTAB_ITER(&globvarht, hi, {
+ if (STRNCMP(hi->hi_key, "menutrans_", 10) == 0) {
+ delete_var(&globvarht, hi);
}
- }
+ });
hash_unlock(&globvarht);
}
@@ -3344,6 +3205,7 @@ char_u *get_user_var_name(expand_T *xp, int idx)
return NULL;
}
+// TODO(ZyX-I): move to eval/expressions
/// Return TRUE if "pat" matches "text".
/// Does not use 'cpo' and always uses 'magic'.
@@ -3380,6 +3242,8 @@ typedef enum {
, TYPE_NOMATCH /* !~ */
} exptype_T;
+// TODO(ZyX-I): move to eval/expressions
+
/*
* The "evaluate" argument: When FALSE, the argument is only parsed but not
* executed. The function may return OK, but the rettv will be of type
@@ -3393,7 +3257,7 @@ typedef enum {
* Note: "rettv.v_lock" is not set.
* Return OK or FAIL.
*/
-static int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate)
+int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate)
{
int ret;
char_u *p;
@@ -3401,15 +3265,15 @@ static int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate)
p = skipwhite(arg);
ret = eval1(&p, rettv, evaluate);
if (ret == FAIL || !ends_excmd(*p)) {
- if (ret != FAIL)
- clear_tv(rettv);
- /*
- * Report the invalid expression unless the expression evaluation has
- * been cancelled due to an aborting error, an interrupt, or an
- * exception.
- */
- if (!aborting())
- EMSG2(_(e_invexpr2), arg);
+ if (ret != FAIL) {
+ tv_clear(rettv);
+ }
+ // Report the invalid expression unless the expression evaluation has
+ // been cancelled due to an aborting error, an interrupt, or an
+ // exception.
+ if (!aborting()) {
+ emsgf(_(e_invexpr2), arg);
+ }
ret = FAIL;
}
if (nextcmd != NULL)
@@ -3418,6 +3282,8 @@ static int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate)
return ret;
}
+// TODO(ZyX-I): move to eval/expressions
+
/*
* Handle top level expression:
* expr2 ? expr1 : expr1
@@ -3443,13 +3309,15 @@ static int eval1(char_u **arg, typval_T *rettv, int evaluate)
if ((*arg)[0] == '?') {
result = FALSE;
if (evaluate) {
- int error = FALSE;
+ bool error = false;
- if (get_tv_number_chk(rettv, &error) != 0)
- result = TRUE;
- clear_tv(rettv);
- if (error)
+ if (tv_get_number_chk(rettv, &error) != 0) {
+ result = true;
+ }
+ tv_clear(rettv);
+ if (error) {
return FAIL;
+ }
}
/*
@@ -3463,9 +3331,10 @@ static int eval1(char_u **arg, typval_T *rettv, int evaluate)
* Check for the ":".
*/
if ((*arg)[0] != ':') {
- EMSG(_("E109: Missing ':' after '?'"));
- if (evaluate && result)
- clear_tv(rettv);
+ emsgf(_("E109: Missing ':' after '?'"));
+ if (evaluate && result) {
+ tv_clear(rettv);
+ }
return FAIL;
}
@@ -3473,9 +3342,10 @@ static int eval1(char_u **arg, typval_T *rettv, int evaluate)
* Get the third variable.
*/
*arg = skipwhite(*arg + 1);
- if (eval1(arg, &var2, evaluate && !result) == FAIL) { /* recursive! */
- if (evaluate && result)
- clear_tv(rettv);
+ if (eval1(arg, &var2, evaluate && !result) == FAIL) { // Recursive!
+ if (evaluate && result) {
+ tv_clear(rettv);
+ }
return FAIL;
}
if (evaluate && !result)
@@ -3485,6 +3355,8 @@ static int eval1(char_u **arg, typval_T *rettv, int evaluate)
return OK;
}
+// TODO(ZyX-I): move to eval/expressions
+
/*
* Handle first level expression:
* expr2 || expr2 || expr2 logical OR
@@ -3499,7 +3371,7 @@ static int eval2(char_u **arg, typval_T *rettv, int evaluate)
typval_T var2;
long result;
int first;
- int error = FALSE;
+ bool error = false;
/*
* Get the first variable.
@@ -3514,12 +3386,14 @@ static int eval2(char_u **arg, typval_T *rettv, int evaluate)
result = FALSE;
while ((*arg)[0] == '|' && (*arg)[1] == '|') {
if (evaluate && first) {
- if (get_tv_number_chk(rettv, &error) != 0)
- result = TRUE;
- clear_tv(rettv);
- if (error)
+ if (tv_get_number_chk(rettv, &error) != 0) {
+ result = true;
+ }
+ tv_clear(rettv);
+ if (error) {
return FAIL;
- first = FALSE;
+ }
+ first = false;
}
/*
@@ -3533,11 +3407,13 @@ static int eval2(char_u **arg, typval_T *rettv, int evaluate)
* Compute the result.
*/
if (evaluate && !result) {
- if (get_tv_number_chk(&var2, &error) != 0)
- result = TRUE;
- clear_tv(&var2);
- if (error)
+ if (tv_get_number_chk(&var2, &error) != 0) {
+ result = true;
+ }
+ tv_clear(&var2);
+ if (error) {
return FAIL;
+ }
}
if (evaluate) {
rettv->v_type = VAR_NUMBER;
@@ -3548,6 +3424,8 @@ static int eval2(char_u **arg, typval_T *rettv, int evaluate)
return OK;
}
+// TODO(ZyX-I): move to eval/expressions
+
/*
* Handle second level expression:
* expr3 && expr3 && expr3 logical AND
@@ -3562,7 +3440,7 @@ static int eval3(char_u **arg, typval_T *rettv, int evaluate)
typval_T var2;
long result;
int first;
- int error = FALSE;
+ bool error = false;
/*
* Get the first variable.
@@ -3577,12 +3455,14 @@ static int eval3(char_u **arg, typval_T *rettv, int evaluate)
result = TRUE;
while ((*arg)[0] == '&' && (*arg)[1] == '&') {
if (evaluate && first) {
- if (get_tv_number_chk(rettv, &error) == 0)
- result = FALSE;
- clear_tv(rettv);
- if (error)
+ if (tv_get_number_chk(rettv, &error) == 0) {
+ result = false;
+ }
+ tv_clear(rettv);
+ if (error) {
return FAIL;
- first = FALSE;
+ }
+ first = false;
}
/*
@@ -3596,11 +3476,13 @@ static int eval3(char_u **arg, typval_T *rettv, int evaluate)
* Compute the result.
*/
if (evaluate && result) {
- if (get_tv_number_chk(&var2, &error) == 0)
- result = FALSE;
- clear_tv(&var2);
- if (error)
+ if (tv_get_number_chk(&var2, &error) == 0) {
+ result = false;
+ }
+ tv_clear(&var2);
+ if (error) {
return FAIL;
+ }
}
if (evaluate) {
rettv->v_type = VAR_NUMBER;
@@ -3611,6 +3493,8 @@ static int eval3(char_u **arg, typval_T *rettv, int evaluate)
return OK;
}
+// TODO(ZyX-I): move to eval/expressions
+
/*
* Handle third level expression:
* var1 == var2
@@ -3638,8 +3522,6 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
int type_is = FALSE; /* TRUE for "is" and "isnot" */
int len = 2;
long n1, n2;
- char_u *s1, *s2;
- char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
int ic;
/*
@@ -3707,7 +3589,7 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
*/
*arg = skipwhite(p + len);
if (eval5(arg, &var2, evaluate) == FAIL) {
- clear_tv(rettv);
+ tv_clear(rettv);
return FAIL;
}
@@ -3729,15 +3611,15 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
} else {
EMSG(_("E692: Invalid operation for List"));
}
- clear_tv(rettv);
- clear_tv(&var2);
+ tv_clear(rettv);
+ tv_clear(&var2);
return FAIL;
} else {
- /* Compare two Lists for being equal or unequal. */
- n1 = list_equal(rettv->vval.v_list, var2.vval.v_list,
- ic, FALSE);
- if (type == TYPE_NEQUAL)
+ // Compare two Lists for being equal or unequal.
+ n1 = tv_list_equal(rettv->vval.v_list, var2.vval.v_list, ic, false);
+ if (type == TYPE_NEQUAL) {
n1 = !n1;
+ }
}
} else if (rettv->v_type == VAR_DICT || var2.v_type == VAR_DICT) {
if (type_is) {
@@ -3751,23 +3633,22 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
EMSG(_("E735: Can only compare Dictionary with Dictionary"));
else
EMSG(_("E736: Invalid operation for Dictionary"));
- clear_tv(rettv);
- clear_tv(&var2);
+ tv_clear(rettv);
+ tv_clear(&var2);
return FAIL;
} else {
- /* Compare two Dictionaries for being equal or unequal. */
- n1 = dict_equal(rettv->vval.v_dict, var2.vval.v_dict,
- ic, FALSE);
- if (type == TYPE_NEQUAL)
+ // Compare two Dictionaries for being equal or unequal.
+ n1 = tv_dict_equal(rettv->vval.v_dict, var2.vval.v_dict,
+ ic, false);
+ if (type == TYPE_NEQUAL) {
n1 = !n1;
+ }
}
- } else if (rettv->v_type == VAR_FUNC || var2.v_type == VAR_FUNC
- || rettv->v_type == VAR_PARTIAL
- || var2.v_type == VAR_PARTIAL) {
+ } else if (tv_is_func(*rettv) || tv_is_func(var2)) {
if (type != TYPE_EQUAL && type != TYPE_NEQUAL) {
EMSG(_("E694: Invalid operation for Funcrefs"));
- clear_tv(rettv);
- clear_tv(&var2);
+ tv_clear(rettv);
+ tv_clear(&var2);
return FAIL;
}
if ((rettv->v_type == VAR_PARTIAL
@@ -3802,25 +3683,27 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
&& type != TYPE_MATCH && type != TYPE_NOMATCH) {
float_T f1, f2;
- if (rettv->v_type == VAR_FLOAT)
+ if (rettv->v_type == VAR_FLOAT) {
f1 = rettv->vval.v_float;
- else
- f1 = get_tv_number(rettv);
- if (var2.v_type == VAR_FLOAT)
+ } else {
+ f1 = tv_get_number(rettv);
+ }
+ if (var2.v_type == VAR_FLOAT) {
f2 = var2.vval.v_float;
- else
- f2 = get_tv_number(&var2);
- n1 = FALSE;
+ } else {
+ f2 = tv_get_number(&var2);
+ }
+ n1 = false;
switch (type) {
- case TYPE_EQUAL: n1 = (f1 == f2); break;
- case TYPE_NEQUAL: n1 = (f1 != f2); break;
- case TYPE_GREATER: n1 = (f1 > f2); break;
- case TYPE_GEQUAL: n1 = (f1 >= f2); break;
- case TYPE_SMALLER: n1 = (f1 < f2); break;
- case TYPE_SEQUAL: n1 = (f1 <= f2); break;
- case TYPE_UNKNOWN:
- case TYPE_MATCH:
- case TYPE_NOMATCH: break; /* avoid gcc warning */
+ case TYPE_EQUAL: n1 = (f1 == f2); break;
+ case TYPE_NEQUAL: n1 = (f1 != f2); break;
+ case TYPE_GREATER: n1 = (f1 > f2); break;
+ case TYPE_GEQUAL: n1 = (f1 >= f2); break;
+ case TYPE_SMALLER: n1 = (f1 < f2); break;
+ case TYPE_SEQUAL: n1 = (f1 <= f2); break;
+ case TYPE_UNKNOWN:
+ case TYPE_MATCH:
+ case TYPE_NOMATCH: break;
}
}
/*
@@ -3829,48 +3712,51 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
*/
else if ((rettv->v_type == VAR_NUMBER || var2.v_type == VAR_NUMBER)
&& type != TYPE_MATCH && type != TYPE_NOMATCH) {
- n1 = get_tv_number(rettv);
- n2 = get_tv_number(&var2);
+ n1 = tv_get_number(rettv);
+ n2 = tv_get_number(&var2);
switch (type) {
- case TYPE_EQUAL: n1 = (n1 == n2); break;
- case TYPE_NEQUAL: n1 = (n1 != n2); break;
- case TYPE_GREATER: n1 = (n1 > n2); break;
- case TYPE_GEQUAL: n1 = (n1 >= n2); break;
- case TYPE_SMALLER: n1 = (n1 < n2); break;
- case TYPE_SEQUAL: n1 = (n1 <= n2); break;
- case TYPE_UNKNOWN:
- case TYPE_MATCH:
- case TYPE_NOMATCH: break; /* avoid gcc warning */
+ case TYPE_EQUAL: n1 = (n1 == n2); break;
+ case TYPE_NEQUAL: n1 = (n1 != n2); break;
+ case TYPE_GREATER: n1 = (n1 > n2); break;
+ case TYPE_GEQUAL: n1 = (n1 >= n2); break;
+ case TYPE_SMALLER: n1 = (n1 < n2); break;
+ case TYPE_SEQUAL: n1 = (n1 <= n2); break;
+ case TYPE_UNKNOWN:
+ case TYPE_MATCH:
+ case TYPE_NOMATCH: break;
}
} else {
- s1 = get_tv_string_buf(rettv, buf1);
- s2 = get_tv_string_buf(&var2, buf2);
- if (type != TYPE_MATCH && type != TYPE_NOMATCH)
- i = ic ? mb_stricmp(s1, s2) : STRCMP(s1, s2);
- else
+ char buf1[NUMBUFLEN];
+ char buf2[NUMBUFLEN];
+ const char *const s1 = tv_get_string_buf(rettv, buf1);
+ const char *const s2 = tv_get_string_buf(&var2, buf2);
+ if (type != TYPE_MATCH && type != TYPE_NOMATCH) {
+ i = mb_strcmp_ic((bool)ic, s1, s2);
+ } else {
i = 0;
- n1 = FALSE;
+ }
+ n1 = false;
switch (type) {
- case TYPE_EQUAL: n1 = (i == 0); break;
- case TYPE_NEQUAL: n1 = (i != 0); break;
- case TYPE_GREATER: n1 = (i > 0); break;
- case TYPE_GEQUAL: n1 = (i >= 0); break;
- case TYPE_SMALLER: n1 = (i < 0); break;
- case TYPE_SEQUAL: n1 = (i <= 0); break;
-
- case TYPE_MATCH:
- case TYPE_NOMATCH:
- n1 = pattern_match(s2, s1, ic);
- if (type == TYPE_NOMATCH) {
- n1 = !n1;
+ case TYPE_EQUAL: n1 = (i == 0); break;
+ case TYPE_NEQUAL: n1 = (i != 0); break;
+ case TYPE_GREATER: n1 = (i > 0); break;
+ case TYPE_GEQUAL: n1 = (i >= 0); break;
+ case TYPE_SMALLER: n1 = (i < 0); break;
+ case TYPE_SEQUAL: n1 = (i <= 0); break;
+
+ case TYPE_MATCH:
+ case TYPE_NOMATCH: {
+ n1 = pattern_match((char_u *)s2, (char_u *)s1, ic);
+ if (type == TYPE_NOMATCH) {
+ n1 = !n1;
+ }
+ break;
}
- break;
-
- case TYPE_UNKNOWN: break; /* avoid gcc warning */
+ case TYPE_UNKNOWN: break; // Avoid gcc warning.
}
}
- clear_tv(rettv);
- clear_tv(&var2);
+ tv_clear(rettv);
+ tv_clear(&var2);
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = n1;
}
@@ -3879,6 +3765,8 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
return OK;
}
+// TODO(ZyX-I): move to eval/expressions
+
/*
* Handle fourth level expression:
* + number addition
@@ -3897,8 +3785,6 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
int op;
long n1, n2;
float_T f1 = 0, f2 = 0;
- char_u *s1, *s2;
- char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
char_u *p;
/*
@@ -3916,17 +3802,16 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
break;
if ((op != '+' || rettv->v_type != VAR_LIST)
- && (op == '.' || rettv->v_type != VAR_FLOAT)
- ) {
- /* For "list + ...", an illegal use of the first operand as
- * a number cannot be determined before evaluating the 2nd
- * operand: if this is also a list, all is ok.
- * For "something . ...", "something - ..." or "non-list + ...",
- * we know that the first operand needs to be a string or number
- * without evaluating the 2nd operand. So check before to avoid
- * side effects after an error. */
- if (evaluate && get_tv_string_chk(rettv) == NULL) {
- clear_tv(rettv);
+ && (op == '.' || rettv->v_type != VAR_FLOAT)) {
+ // For "list + ...", an illegal use of the first operand as
+ // a number cannot be determined before evaluating the 2nd
+ // operand: if this is also a list, all is ok.
+ // For "something . ...", "something - ..." or "non-list + ...",
+ // we know that the first operand needs to be a string or number
+ // without evaluating the 2nd operand. So check before to avoid
+ // side effects after an error.
+ if (evaluate && !tv_check_str(rettv)) {
+ tv_clear(rettv);
return FAIL;
}
}
@@ -3936,7 +3821,7 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
*/
*arg = skipwhite(*arg + 1);
if (eval6(arg, &var2, evaluate, op == '.') == FAIL) {
- clear_tv(rettv);
+ tv_clear(rettv);
return FAIL;
}
@@ -3945,41 +3830,44 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
* Compute the result.
*/
if (op == '.') {
- s1 = get_tv_string_buf(rettv, buf1); /* already checked */
- s2 = get_tv_string_buf_chk(&var2, buf2);
- if (s2 == NULL) { /* type error ? */
- clear_tv(rettv);
- clear_tv(&var2);
+ char buf1[NUMBUFLEN];
+ char buf2[NUMBUFLEN];
+ // s1 already checked
+ const char *const s1 = tv_get_string_buf(rettv, buf1);
+ const char *const s2 = tv_get_string_buf_chk(&var2, buf2);
+ if (s2 == NULL) { // Type error?
+ tv_clear(rettv);
+ tv_clear(&var2);
return FAIL;
}
- p = concat_str(s1, s2);
- clear_tv(rettv);
+ p = concat_str((const char_u *)s1, (const char_u *)s2);
+ tv_clear(rettv);
rettv->v_type = VAR_STRING;
rettv->vval.v_string = p;
} else if (op == '+' && rettv->v_type == VAR_LIST
&& var2.v_type == VAR_LIST) {
- /* concatenate Lists */
- if (list_concat(rettv->vval.v_list, var2.vval.v_list,
- &var3) == FAIL) {
- clear_tv(rettv);
- clear_tv(&var2);
+ // Concatenate Lists.
+ if (tv_list_concat(rettv->vval.v_list, var2.vval.v_list, &var3)
+ == FAIL) {
+ tv_clear(rettv);
+ tv_clear(&var2);
return FAIL;
}
- clear_tv(rettv);
+ tv_clear(rettv);
*rettv = var3;
} else {
- int error = FALSE;
+ bool error = false;
if (rettv->v_type == VAR_FLOAT) {
f1 = rettv->vval.v_float;
n1 = 0;
} else {
- n1 = get_tv_number_chk(rettv, &error);
+ n1 = tv_get_number_chk(rettv, &error);
if (error) {
/* This can only happen for "list + non-list". For
* "non-list + ..." or "something - ...", we returned
* before evaluating the 2nd operand. */
- clear_tv(rettv);
+ tv_clear(rettv);
return FAIL;
}
if (var2.v_type == VAR_FLOAT)
@@ -3989,16 +3877,16 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
f2 = var2.vval.v_float;
n2 = 0;
} else {
- n2 = get_tv_number_chk(&var2, &error);
+ n2 = tv_get_number_chk(&var2, &error);
if (error) {
- clear_tv(rettv);
- clear_tv(&var2);
+ tv_clear(rettv);
+ tv_clear(&var2);
return FAIL;
}
if (rettv->v_type == VAR_FLOAT)
f2 = n2;
}
- clear_tv(rettv);
+ tv_clear(rettv);
/* If there is a float on either side the result is a float. */
if (rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT) {
@@ -4017,12 +3905,14 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
rettv->vval.v_number = n1;
}
}
- clear_tv(&var2);
+ tv_clear(&var2);
}
}
return OK;
}
+// TODO(ZyX-I): move to eval/expressions
+
/*
* Handle fifth level expression:
* * number multiplication
@@ -4047,7 +3937,7 @@ eval6 (
long n1, n2;
int use_float = FALSE;
float_T f1 = 0, f2;
- int error = FALSE;
+ bool error = false;
/*
* Get the first variable.
@@ -4068,13 +3958,16 @@ eval6 (
f1 = rettv->vval.v_float;
use_float = TRUE;
n1 = 0;
- } else
- n1 = get_tv_number_chk(rettv, &error);
- clear_tv(rettv);
- if (error)
+ } else {
+ n1 = tv_get_number_chk(rettv, &error);
+ }
+ tv_clear(rettv);
+ if (error) {
return FAIL;
- } else
+ }
+ } else {
n1 = 0;
+ }
/*
* Get the second variable.
@@ -4092,12 +3985,14 @@ eval6 (
f2 = var2.vval.v_float;
n2 = 0;
} else {
- n2 = get_tv_number_chk(&var2, &error);
- clear_tv(&var2);
- if (error)
+ n2 = tv_get_number_chk(&var2, &error);
+ tv_clear(&var2);
+ if (error) {
return FAIL;
- if (use_float)
+ }
+ if (use_float) {
f2 = n2;
+ }
}
/*
@@ -4155,6 +4050,8 @@ eval6 (
return OK;
}
+// TODO(ZyX-I): move to eval/expressions
+
// Handle sixth level expression:
// number number constant
// "string" string constant
@@ -4193,7 +4090,7 @@ static int eval7(
int ret = OK;
char_u *alias;
- // Initialise variable so that clear_tv() can't mistake this for a
+ // Initialise variable so that tv_clear() can't mistake this for a
// string and free a string that isn't there.
rettv->v_type = VAR_UNKNOWN;
@@ -4309,7 +4206,7 @@ static int eval7(
++*arg;
} else if (ret == OK) {
EMSG(_("E110: Missing ')'"));
- clear_tv(rettv);
+ tv_clear(rettv);
ret = FAIL;
}
break;
@@ -4350,7 +4247,7 @@ static int eval7(
// get_func_tv, but it's needed in handle_subscript() to parse
// what follows. So set it here.
if (rettv->v_type == VAR_UNKNOWN && !evaluate && **arg == '(') {
- rettv->vval.v_string = empty_string;
+ rettv->vval.v_string = (char_u *)tv_empty_string;
rettv->v_type = VAR_FUNC;
}
@@ -4359,7 +4256,7 @@ static int eval7(
// an exception was thrown but not caught.
if (aborting()) {
if (ret == OK) {
- clear_tv(rettv);
+ tv_clear(rettv);
}
ret = FAIL;
}
@@ -4383,17 +4280,17 @@ static int eval7(
// Apply logical NOT and unary '-', from right to left, ignore '+'.
if (ret == OK && evaluate && end_leader > start_leader) {
- int error = false;
+ bool error = false;
int val = 0;
float_T f = 0.0;
if (rettv->v_type == VAR_FLOAT) {
f = rettv->vval.v_float;
} else {
- val = get_tv_number_chk(rettv, &error);
+ val = tv_get_number_chk(rettv, &error);
}
if (error) {
- clear_tv(rettv);
+ tv_clear(rettv);
ret = FAIL;
} else {
while (end_leader > start_leader) {
@@ -4413,10 +4310,10 @@ static int eval7(
}
}
if (rettv->v_type == VAR_FLOAT) {
- clear_tv(rettv);
+ tv_clear(rettv);
rettv->vval.v_float = f;
} else {
- clear_tv(rettv);
+ tv_clear(rettv);
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = val;
}
@@ -4426,6 +4323,8 @@ static int eval7(
return ret;
}
+// TODO(ZyX-I): move to eval/expressions
+
/*
* Evaluate an "[expr]" or "[expr:expr]" index. Also "dict.key".
* "*arg" points to the '[' or '.'.
@@ -4439,12 +4338,11 @@ eval_index (
int verbose /* give error messages */
)
{
- int empty1 = FALSE, empty2 = FALSE;
- typval_T var1, var2;
+ bool empty1 = false;
+ bool empty2 = false;
long n1, n2 = 0;
- long len = -1;
- int range = FALSE;
- char_u *s;
+ ptrdiff_t len = -1;
+ int range = false;
char_u *key = NULL;
switch (rettv->v_type) {
@@ -4481,8 +4379,8 @@ eval_index (
}
}
- init_tv(&var1);
- init_tv(&var2);
+ typval_T var1 = TV_INITIAL_VALUE;
+ typval_T var2 = TV_INITIAL_VALUE;
if (**arg == '.') {
/*
* dict.name
@@ -4500,13 +4398,13 @@ eval_index (
* Get the (first) variable from inside the [].
*/
*arg = skipwhite(*arg + 1);
- if (**arg == ':')
- empty1 = TRUE;
- else if (eval1(arg, &var1, evaluate) == FAIL) /* recursive! */
+ if (**arg == ':') {
+ empty1 = true;
+ } else if (eval1(arg, &var1, evaluate) == FAIL) { // Recursive!
return FAIL;
- else if (evaluate && get_tv_string_chk(&var1) == NULL) {
- /* not a number or string */
- clear_tv(&var1);
+ } else if (evaluate && !tv_check_str(&var1)) {
+ // Not a number or string.
+ tv_clear(&var1);
return FAIL;
}
@@ -4516,28 +4414,32 @@ eval_index (
if (**arg == ':') {
range = TRUE;
*arg = skipwhite(*arg + 1);
- if (**arg == ']')
- empty2 = TRUE;
- else if (eval1(arg, &var2, evaluate) == FAIL) { /* recursive! */
- if (!empty1)
- clear_tv(&var1);
+ if (**arg == ']') {
+ empty2 = true;
+ } else if (eval1(arg, &var2, evaluate) == FAIL) { // Recursive!
+ if (!empty1) {
+ tv_clear(&var1);
+ }
return FAIL;
- } else if (evaluate && get_tv_string_chk(&var2) == NULL) {
- /* not a number or string */
- if (!empty1)
- clear_tv(&var1);
- clear_tv(&var2);
+ } else if (evaluate && !tv_check_str(&var2)) {
+ // Not a number or string.
+ if (!empty1) {
+ tv_clear(&var1);
+ }
+ tv_clear(&var2);
return FAIL;
}
}
/* Check for the ']'. */
if (**arg != ']') {
- if (verbose)
- EMSG(_(e_missbrac));
- clear_tv(&var1);
- if (range)
- clear_tv(&var2);
+ if (verbose) {
+ emsgf(_(e_missbrac));
+ }
+ tv_clear(&var1);
+ if (range) {
+ tv_clear(&var2);
+ }
return FAIL;
}
*arg = skipwhite(*arg + 1); /* skip the ']' */
@@ -4546,139 +4448,155 @@ eval_index (
if (evaluate) {
n1 = 0;
if (!empty1 && rettv->v_type != VAR_DICT) {
- n1 = get_tv_number(&var1);
- clear_tv(&var1);
+ n1 = tv_get_number(&var1);
+ tv_clear(&var1);
}
if (range) {
- if (empty2)
+ if (empty2) {
n2 = -1;
- else {
- n2 = get_tv_number(&var2);
- clear_tv(&var2);
+ } else {
+ n2 = tv_get_number(&var2);
+ tv_clear(&var2);
}
}
switch (rettv->v_type) {
- case VAR_NUMBER:
- case VAR_STRING:
- s = get_tv_string(rettv);
- len = (long)STRLEN(s);
- if (range) {
- /* The resulting variable is a substring. If the indexes
- * are out of range the result is empty. */
+ case VAR_NUMBER:
+ case VAR_STRING: {
+ const char *const s = tv_get_string(rettv);
+ char *v;
+ len = (ptrdiff_t)strlen(s);
+ if (range) {
+ // The resulting variable is a substring. If the indexes
+ // are out of range the result is empty.
+ if (n1 < 0) {
+ n1 = len + n1;
+ if (n1 < 0) {
+ n1 = 0;
+ }
+ }
+ if (n2 < 0) {
+ n2 = len + n2;
+ } else if (n2 >= len) {
+ n2 = len;
+ }
+ if (n1 >= len || n2 < 0 || n1 > n2) {
+ v = NULL;
+ } else {
+ v = xmemdupz(s + n1, (size_t)(n2 - n1 + 1));
+ }
+ } else {
+ // The resulting variable is a string of a single
+ // character. If the index is too big or negative the
+ // result is empty.
+ if (n1 >= len || n1 < 0) {
+ v = NULL;
+ } else {
+ v = xmemdupz(s + n1, 1);
+ }
+ }
+ tv_clear(rettv);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = (char_u *)v;
+ break;
+ }
+ case VAR_LIST: {
+ len = tv_list_len(rettv->vval.v_list);
if (n1 < 0) {
n1 = len + n1;
- if (n1 < 0)
- n1 = 0;
}
- if (n2 < 0)
- n2 = len + n2;
- else if (n2 >= len)
- n2 = len;
- if (n1 >= len || n2 < 0 || n1 > n2)
- s = NULL;
- else
- s = vim_strnsave(s + n1, (int)(n2 - n1 + 1));
- } else {
- /* The resulting variable is a string of a single
- * character. If the index is too big or negative the
- * result is empty. */
- if (n1 >= len || n1 < 0)
- s = NULL;
- else
- s = vim_strnsave(s + n1, 1);
- }
- clear_tv(rettv);
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = s;
- break;
-
- case VAR_LIST:
- len = list_len(rettv->vval.v_list);
- if (n1 < 0)
- n1 = len + n1;
- if (!empty1 && (n1 < 0 || n1 >= len)) {
- /* For a range we allow invalid values and return an empty
- * list. A list index out of range is an error. */
- if (!range) {
- if (verbose)
- EMSGN(_(e_listidx), n1);
- return FAIL;
+ if (!empty1 && (n1 < 0 || n1 >= len)) {
+ // For a range we allow invalid values and return an empty
+ // list. A list index out of range is an error.
+ if (!range) {
+ if (verbose) {
+ EMSGN(_(e_listidx), n1);
+ }
+ return FAIL;
+ }
+ n1 = len;
}
- n1 = len;
- }
- if (range) {
- list_T *l;
- listitem_T *item;
-
- if (n2 < 0)
- n2 = len + n2;
- else if (n2 >= len)
- n2 = len - 1;
- if (!empty2 && (n2 < 0 || n2 + 1 < n1))
- n2 = -1;
- l = list_alloc();
- item = list_find(rettv->vval.v_list, n1);
- while (n1++ <= n2) {
- list_append_tv(l, &item->li_tv);
- item = item->li_next;
+ if (range) {
+ list_T *l;
+ listitem_T *item;
+
+ if (n2 < 0) {
+ n2 = len + n2;
+ } else if (n2 >= len) {
+ n2 = len - 1;
+ }
+ if (!empty2 && (n2 < 0 || n2 + 1 < n1)) {
+ n2 = -1;
+ }
+ l = tv_list_alloc();
+ item = tv_list_find(rettv->vval.v_list, n1);
+ while (n1++ <= n2) {
+ tv_list_append_tv(l, &item->li_tv);
+ item = item->li_next;
+ }
+ tv_clear(rettv);
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = l;
+ l->lv_refcount++;
+ } else {
+ tv_copy(&tv_list_find(rettv->vval.v_list, n1)->li_tv, &var1);
+ tv_clear(rettv);
+ *rettv = var1;
}
- clear_tv(rettv);
- rettv->v_type = VAR_LIST;
- rettv->vval.v_list = l;
- ++l->lv_refcount;
- } else {
- copy_tv(&list_find(rettv->vval.v_list, n1)->li_tv, &var1);
- clear_tv(rettv);
- *rettv = var1;
- }
- break;
-
- case VAR_DICT:
- if (range) {
- if (verbose)
- EMSG(_(e_dictrange));
- if (len == -1)
- clear_tv(&var1);
- return FAIL;
+ break;
}
- {
- dictitem_T *item;
+ case VAR_DICT: {
+ if (range) {
+ if (verbose) {
+ emsgf(_(e_dictrange));
+ }
+ if (len == -1) {
+ tv_clear(&var1);
+ }
+ return FAIL;
+ }
if (len == -1) {
- key = get_tv_string_chk(&var1);
+ key = (char_u *)tv_get_string_chk(&var1);
if (key == NULL) {
- clear_tv(&var1);
+ tv_clear(&var1);
return FAIL;
}
}
- item = dict_find(rettv->vval.v_dict, key, (int)len);
+ dictitem_T *const item = tv_dict_find(rettv->vval.v_dict,
+ (const char *)key, len);
- if (item == NULL && verbose)
- EMSG2(_(e_dictkey), key);
- if (len == -1)
- clear_tv(&var1);
- if (item == NULL)
+ if (item == NULL && verbose) {
+ emsgf(_(e_dictkey), key);
+ }
+ if (len == -1) {
+ tv_clear(&var1);
+ }
+ if (item == NULL) {
return FAIL;
+ }
- copy_tv(&item->di_tv, &var1);
- clear_tv(rettv);
+ tv_copy(&item->di_tv, &var1);
+ tv_clear(rettv);
*rettv = var1;
+ break;
+ }
+ case VAR_SPECIAL:
+ case VAR_FUNC:
+ case VAR_FLOAT:
+ case VAR_PARTIAL:
+ case VAR_UNKNOWN: {
+ break; // Not evaluating, skipping over subscript
}
- break;
- case VAR_SPECIAL:
- case VAR_FUNC:
- case VAR_PARTIAL:
- case VAR_FLOAT:
- case VAR_UNKNOWN:
- break; // Not evaluating, skipping over subscript
}
}
return OK;
}
+// TODO(ZyX-I): move to eval/executor
+
/// Get an option value
///
/// @param[in,out] arg Points to the '&' or '+' before the option name. Is
@@ -4932,13 +4850,15 @@ char_u *partial_name(partial_T *pt)
return pt->pt_func->uf_name;
}
+// TODO(ZyX-I): Move to eval/typval.h
+
static void partial_free(partial_T *pt)
{
for (int i = 0; i < pt->pt_argc; i++) {
- clear_tv(&pt->pt_argv[i]);
+ tv_clear(&pt->pt_argv[i]);
}
xfree(pt->pt_argv);
- dict_unref(pt->pt_dict);
+ tv_dict_unref(pt->pt_dict);
if (pt->pt_name != NULL) {
func_unref(pt->pt_name);
xfree(pt->pt_name);
@@ -4948,6 +4868,8 @@ static void partial_free(partial_T *pt)
xfree(pt);
}
+// TODO(ZyX-I): Move to eval/typval.h
+
/// Unreference a closure: decrement the reference count and free it when it
/// becomes zero.
void partial_unref(partial_T *pt)
@@ -4966,7 +4888,7 @@ static int get_list_tv(char_u **arg, typval_T *rettv, int evaluate)
listitem_T *item;
if (evaluate) {
- l = list_alloc();
+ l = tv_list_alloc();
}
*arg = skipwhite(*arg + 1);
@@ -4974,10 +4896,10 @@ static int get_list_tv(char_u **arg, typval_T *rettv, int evaluate)
if (eval1(arg, &tv, evaluate) == FAIL) /* recursive! */
goto failret;
if (evaluate) {
- item = listitem_alloc();
+ item = tv_list_item_alloc();
item->li_tv = tv;
item->li_tv.v_lock = 0;
- list_append(l, item);
+ tv_list_append(l, item);
}
if (**arg == ']')
@@ -4993,7 +4915,7 @@ static int get_list_tv(char_u **arg, typval_T *rettv, int evaluate)
EMSG2(_("E697: Missing end of List ']': %s"), *arg);
failret:
if (evaluate) {
- list_free(l);
+ tv_list_free(l);
}
return FAIL;
}
@@ -5008,196 +4930,7 @@ failret:
return OK;
}
-/*
- * Allocate an empty header for a list.
- * Caller should take care of the reference count.
- */
-list_T *list_alloc(void) FUNC_ATTR_NONNULL_RET
-{
- list_T *list = xcalloc(1, sizeof(list_T));
-
- /* Prepend the list to the list of lists for garbage collection. */
- if (first_list != NULL)
- first_list->lv_used_prev = list;
- list->lv_used_prev = NULL;
- list->lv_used_next = first_list;
- first_list = list;
- return list;
-}
-
-/*
- * Allocate an empty list for a return value.
- */
-static list_T *rettv_list_alloc(typval_T *rettv)
-{
- list_T *l = list_alloc();
- rettv->vval.v_list = l;
- rettv->v_type = VAR_LIST;
- rettv->v_lock = VAR_UNLOCKED;
- l->lv_refcount++;
- return l;
-}
-
-/// Unreference a list: decrement the reference count and free it when it
-/// becomes zero.
-void list_unref(list_T *l) {
- if (l != NULL && --l->lv_refcount <= 0) {
- list_free(l);
- }
-}
-
-/// Free a list, including all items it points to.
-/// Ignores the reference count.
-static void list_free_contents(list_T *l) {
- listitem_T *item;
-
- for (item = l->lv_first; item != NULL; item = l->lv_first) {
- // Remove the item before deleting it.
- l->lv_first = item->li_next;
- clear_tv(&item->li_tv);
- xfree(item);
- }
-}
-
-static void list_free_list(list_T *l) {
- // Remove the list from the list of lists for garbage collection.
- if (l->lv_used_prev == NULL) {
- first_list = l->lv_used_next;
- } else {
- l->lv_used_prev->lv_used_next = l->lv_used_next;
- }
- if (l->lv_used_next != NULL) {
- l->lv_used_next->lv_used_prev = l->lv_used_prev;
- }
-
- xfree(l);
-}
-
-void list_free(list_T *l) {
- if (!in_free_unref_items) {
- list_free_contents(l);
- list_free_list(l);
- }
-}
-
-/*
- * Allocate a list item.
- * It is not initialized, don't forget to set v_lock.
- */
-listitem_T *listitem_alloc(void) FUNC_ATTR_NONNULL_RET
-{
- return xmalloc(sizeof(listitem_T));
-}
-
-/*
- * Free a list item. Also clears the value. Does not notify watchers.
- */
-void listitem_free(listitem_T *item)
-{
- clear_tv(&item->li_tv);
- xfree(item);
-}
-
-/*
- * Remove a list item from a List and free it. Also clears the value.
- */
-void listitem_remove(list_T *l, listitem_T *item)
-{
- vim_list_remove(l, item, item);
- listitem_free(item);
-}
-
-/*
- * Get the number of items in a list.
- */
-static long list_len(list_T *l)
-{
- if (l == NULL)
- return 0L;
- return l->lv_len;
-}
-
-/*
- * Return TRUE when two lists have exactly the same values.
- */
-static int
-list_equal (
- list_T *l1,
- list_T *l2,
- int ic, /* ignore case for strings */
- int recursive /* TRUE when used recursively */
-)
-{
- listitem_T *item1, *item2;
-
- if (l1 == NULL || l2 == NULL)
- return FALSE;
- if (l1 == l2)
- return TRUE;
- if (list_len(l1) != list_len(l2))
- return FALSE;
-
- for (item1 = l1->lv_first, item2 = l2->lv_first;
- item1 != NULL && item2 != NULL;
- item1 = item1->li_next, item2 = item2->li_next)
- if (!tv_equal(&item1->li_tv, &item2->li_tv, ic, recursive))
- return FALSE;
- return item1 == NULL && item2 == NULL;
-}
-
-/*
- * Return the dictitem that an entry in a hashtable points to.
- */
-dictitem_T *dict_lookup(hashitem_T *hi)
-{
- return HI2DI(hi);
-}
-
-/*
- * Return TRUE when two dictionaries have exactly the same key/values.
- */
-static int
-dict_equal (
- dict_T *d1,
- dict_T *d2,
- int ic, /* ignore case for strings */
- int recursive /* TRUE when used recursively */
-)
-{
- hashitem_T *hi;
- dictitem_T *item2;
- int todo;
-
- if (d1 == NULL && d2 == NULL) {
- return true;
- }
- if (d1 == NULL || d2 == NULL) {
- return false;
- }
- if (d1 == d2) {
- return true;
- }
- if (dict_len(d1) != dict_len(d2)) {
- return false;
- }
-
- todo = (int)d1->dv_hashtab.ht_used;
- for (hi = d1->dv_hashtab.ht_array; todo > 0; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- item2 = dict_find(d2, hi->hi_key, -1);
- if (item2 == NULL)
- return FALSE;
- if (!tv_equal(&HI2DI(hi)->di_tv, &item2->di_tv, ic, recursive))
- return FALSE;
- --todo;
- }
- }
- return TRUE;
-}
-
-static int tv_equal_recurse_limit;
-
-static bool func_equal(
+bool func_equal(
typval_T *tv1,
typval_T *tv2,
bool ic // ignore case
@@ -5232,7 +4965,7 @@ static bool func_equal(
if (d1 != d2) {
return false;
}
- } else if (!dict_equal(d1, d2, ic, true)) {
+ } else if (!tv_dict_equal(d1, d2, ic, true)) {
return false;
}
@@ -5251,551 +4984,6 @@ static bool func_equal(
return true;
}
-/*
- * Return TRUE if "tv1" and "tv2" have the same value.
- * Compares the items just like "==" would compare them, but strings and
- * numbers are different. Floats and numbers are also different.
- */
-static int
-tv_equal (
- typval_T *tv1,
- typval_T *tv2,
- int ic, /* ignore case */
- int recursive /* TRUE when used recursively */
-)
-{
- char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
- char_u *s1, *s2;
- static int recursive_cnt = 0; /* catch recursive loops */
- int r;
-
- /* Catch lists and dicts that have an endless loop by limiting
- * recursiveness to a limit. We guess they are equal then.
- * A fixed limit has the problem of still taking an awful long time.
- * Reduce the limit every time running into it. That should work fine for
- * deeply linked structures that are not recursively linked and catch
- * recursiveness quickly. */
- if (!recursive)
- tv_equal_recurse_limit = 1000;
- if (recursive_cnt >= tv_equal_recurse_limit) {
- --tv_equal_recurse_limit;
- return TRUE;
- }
-
- // For VAR_FUNC and VAR_PARTIAL compare the function name, bound dict and
- // arguments.
- if ((tv1->v_type == VAR_FUNC
- || (tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial != NULL))
- && (tv2->v_type == VAR_FUNC
- || (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial != NULL))) {
- recursive_cnt++;
- r = func_equal(tv1, tv2, ic);
- recursive_cnt--;
- return r;
- }
- if (tv1->v_type != tv2->v_type) {
- return false;
- }
-
- switch (tv1->v_type) {
- case VAR_LIST:
- ++recursive_cnt;
- r = list_equal(tv1->vval.v_list, tv2->vval.v_list, ic, TRUE);
- --recursive_cnt;
- return r;
-
- case VAR_DICT:
- ++recursive_cnt;
- r = dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic, TRUE);
- --recursive_cnt;
- return r;
-
- case VAR_NUMBER:
- return tv1->vval.v_number == tv2->vval.v_number;
-
- case VAR_FLOAT:
- return tv1->vval.v_float == tv2->vval.v_float;
-
- case VAR_STRING:
- 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_special == tv2->vval.v_special;
-
- case VAR_FUNC:
- case VAR_PARTIAL:
- case VAR_UNKNOWN:
- // VAR_UNKNOWN can be the result of an invalid expression, let’s say it does
- // not equal anything, not even self.
- return false;
- }
-
- assert(false);
- return false;
-}
-
-/*
- * Locate item with index "n" in list "l" and return it.
- * A negative index is counted from the end; -1 is the last item.
- * Returns NULL when "n" is out of range.
- */
-listitem_T *list_find(list_T *l, long n)
-{
- listitem_T *item;
- long idx;
-
- if (l == NULL)
- return NULL;
-
- /* Negative index is relative to the end. */
- if (n < 0)
- n = l->lv_len + n;
-
- /* Check for index out of range. */
- if (n < 0 || n >= l->lv_len)
- return NULL;
-
- /* When there is a cached index may start search from there. */
- if (l->lv_idx_item != NULL) {
- if (n < l->lv_idx / 2) {
- /* closest to the start of the list */
- item = l->lv_first;
- idx = 0;
- } else if (n > (l->lv_idx + l->lv_len) / 2) {
- /* closest to the end of the list */
- item = l->lv_last;
- idx = l->lv_len - 1;
- } else {
- /* closest to the cached index */
- item = l->lv_idx_item;
- idx = l->lv_idx;
- }
- } else {
- if (n < l->lv_len / 2) {
- /* closest to the start of the list */
- item = l->lv_first;
- idx = 0;
- } else {
- /* closest to the end of the list */
- item = l->lv_last;
- idx = l->lv_len - 1;
- }
- }
-
- while (n > idx) {
- /* search forward */
- item = item->li_next;
- ++idx;
- }
- while (n < idx) {
- /* search backward */
- item = item->li_prev;
- --idx;
- }
-
- /* cache the used index */
- l->lv_idx = idx;
- l->lv_idx_item = item;
-
- return item;
-}
-
-/*
- * Get list item "l[idx]" as a number.
- */
-static long
-list_find_nr (
- list_T *l,
- long idx,
- int *errorp /* set to TRUE when something wrong */
-)
-{
- listitem_T *li;
-
- li = list_find(l, idx);
- if (li == NULL) {
- if (errorp != NULL)
- *errorp = TRUE;
- return -1L;
- }
- return get_tv_number_chk(&li->li_tv, errorp);
-}
-
-/*
- * Get list item "l[idx - 1]" as a string. Returns NULL for failure.
- */
-char_u *list_find_str(list_T *l, long idx)
-{
- listitem_T *li;
-
- li = list_find(l, idx - 1);
- if (li == NULL) {
- EMSGN(_(e_listidx), idx);
- return NULL;
- }
- return get_tv_string(&li->li_tv);
-}
-
-/*
- * Locate "item" list "l" and return its index.
- * Returns -1 when "item" is not in the list.
- */
-static long list_idx_of_item(list_T *l, listitem_T *item)
-{
- long idx = 0;
- listitem_T *li;
-
- if (l == NULL)
- return -1;
- idx = 0;
- for (li = l->lv_first; li != NULL && li != item; li = li->li_next)
- ++idx;
- if (li == NULL)
- return -1;
- return idx;
-}
-
-/*
- * Append item "item" to the end of list "l".
- */
-void list_append(list_T *l, listitem_T *item)
-{
- if (l->lv_last == NULL) {
- /* empty list */
- l->lv_first = item;
- l->lv_last = item;
- item->li_prev = NULL;
- } else {
- l->lv_last->li_next = item;
- item->li_prev = l->lv_last;
- l->lv_last = item;
- }
- ++l->lv_len;
- item->li_next = NULL;
-}
-
-/*
- * Append typval_T "tv" to the end of list "l".
- */
-void list_append_tv(list_T *l, typval_T *tv)
-{
- listitem_T *li = listitem_alloc();
- copy_tv(tv, &li->li_tv);
- list_append(l, li);
-}
-
-/*
- * Add a list to a list.
- */
-void list_append_list(list_T *list, list_T *itemlist)
-{
- listitem_T *li = listitem_alloc();
-
- li->li_tv.v_type = VAR_LIST;
- li->li_tv.v_lock = 0;
- li->li_tv.vval.v_list = itemlist;
- list_append(list, li);
- ++itemlist->lv_refcount;
-}
-
-/*
- * Add a dictionary to a list. Used by getqflist().
- */
-void list_append_dict(list_T *list, dict_T *dict)
-{
- listitem_T *li = listitem_alloc();
-
- li->li_tv.v_type = VAR_DICT;
- li->li_tv.v_lock = 0;
- li->li_tv.vval.v_dict = dict;
- list_append(list, li);
- ++dict->dv_refcount;
-}
-
-/// Make a copy of "str" and append it as an item to list "l"
-///
-/// @param[out] l List to append to.
-/// @param[in] str String to append.
-/// @param[in] len Length of the appended string. May be negative, in this
-/// case string is considered to be usual zero-terminated
-/// string.
-void list_append_string(list_T *l, const char_u *str, int len)
- FUNC_ATTR_NONNULL_ARG(1)
-{
- if (str == NULL) {
- list_append_allocated_string(l, NULL);
- } else {
- list_append_allocated_string(l, (len >= 0
- ? xmemdupz((char *) str, len)
- : xstrdup((char *) str)));
- }
-}
-
-/// Append given string to the list
-///
-/// Unlike list_append_string this function does not copy the string.
-///
-/// @param[out] l List to append to.
-/// @param[in] str String to append.
-void list_append_allocated_string(list_T *l, char *const str)
- FUNC_ATTR_NONNULL_ARG(1)
-{
- listitem_T *li = listitem_alloc();
-
- list_append(l, li);
- li->li_tv.v_type = VAR_STRING;
- li->li_tv.v_lock = 0;
- li->li_tv.vval.v_string = (char_u *) str;
-}
-
-/*
- * Append "n" to list "l".
- */
-void list_append_number(list_T *l, varnumber_T n)
-{
- listitem_T *li = listitem_alloc();
- li->li_tv.v_type = VAR_NUMBER;
- li->li_tv.v_lock = 0;
- li->li_tv.vval.v_number = n;
- list_append(l, li);
-}
-
-/*
- * Insert typval_T "tv" in list "l" before "item".
- * If "item" is NULL append at the end.
- */
-void list_insert_tv(list_T *l, typval_T *tv, listitem_T *item)
-{
- listitem_T *ni = listitem_alloc();
-
- copy_tv(tv, &ni->li_tv);
- list_insert(l, ni, item);
-}
-
-void list_insert(list_T *l, listitem_T *ni, listitem_T *item)
-{
- if (item == NULL)
- /* Append new item at end of list. */
- list_append(l, ni);
- else {
- /* Insert new item before existing item. */
- ni->li_prev = item->li_prev;
- ni->li_next = item;
- if (item->li_prev == NULL) {
- l->lv_first = ni;
- ++l->lv_idx;
- } else {
- item->li_prev->li_next = ni;
- l->lv_idx_item = NULL;
- }
- item->li_prev = ni;
- ++l->lv_len;
- }
-}
-
-/*
- * Extend "l1" with "l2".
- * If "bef" is NULL append at the end, otherwise insert before this item.
- */
-static void list_extend(list_T *l1, list_T *l2, listitem_T *bef)
-{
- listitem_T *item;
- int todo = l2->lv_len;
-
- /* We also quit the loop when we have inserted the original item count of
- * the list, avoid a hang when we extend a list with itself. */
- for (item = l2->lv_first; item != NULL && --todo >= 0; item = item->li_next) {
- list_insert_tv(l1, &item->li_tv, bef);
- }
-}
-
-/*
- * Concatenate lists "l1" and "l2" into a new list, stored in "tv".
- * Return FAIL on failure to copy.
- */
-static int list_concat(list_T *l1, list_T *l2, typval_T *tv)
-{
- list_T *l;
-
- if (l1 == NULL || l2 == NULL)
- return FAIL;
-
- /* make a copy of the first list. */
- l = list_copy(NULL, l1, false, 0);
- if (l == NULL)
- return FAIL;
- tv->v_type = VAR_LIST;
- tv->vval.v_list = l;
-
- /* append all items from the second list */
- list_extend(l, l2, NULL);
- return OK;
-}
-
-/// Make a copy of list
-///
-/// @param[in] conv If non-NULL, then all internal strings will be converted.
-/// @param[in] orig Original list to copy.
-/// @param[in] deep If false, then shallow copy will be done.
-/// @param[in] copyID See var_item_copy().
-///
-/// @return Copied list. May be NULL in case original list is NULL or some
-/// failure happens. The refcount of the new list is set to 1.
-static list_T *list_copy(const vimconv_T *const conv,
- list_T *const orig,
- const bool deep,
- const int copyID)
- FUNC_ATTR_WARN_UNUSED_RESULT
-{
- listitem_T *item;
- listitem_T *ni;
-
- if (orig == NULL)
- return NULL;
-
- list_T *copy = list_alloc();
- if (copyID != 0) {
- /* Do this before adding the items, because one of the items may
- * refer back to this list. */
- orig->lv_copyID = copyID;
- orig->lv_copylist = copy;
- }
- for (item = orig->lv_first; item != NULL && !got_int;
- item = item->li_next) {
- ni = listitem_alloc();
- if (deep) {
- if (var_item_copy(conv, &item->li_tv, &ni->li_tv, deep, copyID) == FAIL) {
- xfree(ni);
- break;
- }
- } else
- copy_tv(&item->li_tv, &ni->li_tv);
- list_append(copy, ni);
- }
- ++copy->lv_refcount;
- if (item != NULL) {
- list_unref(copy);
- copy = NULL;
- }
-
- return copy;
-}
-
-/// Remove items "item" to "item2" from list "l".
-/// @warning Does not free the listitem or the value!
-void vim_list_remove(list_T *l, listitem_T *item, listitem_T *item2)
-{
- // notify watchers
- for (listitem_T *ip = item; ip != NULL; ip = ip->li_next) {
- --l->lv_len;
- list_fix_watch(l, ip);
- if (ip == item2) {
- break;
- }
- }
-
- if (item2->li_next == NULL) {
- l->lv_last = item->li_prev;
- } else {
- item2->li_next->li_prev = item->li_prev;
- }
- if (item->li_prev == NULL) {
- l->lv_first = item2->li_next;
- } else {
- item->li_prev->li_next = item2->li_next;
- }
- l->lv_idx_item = NULL;
-}
-
-typedef struct join_S {
- char_u *s;
- char_u *tofree;
-} join_T;
-
-/// Join list into a string, helper function
-///
-/// @param[out] gap Garray where result will be saved.
-/// @param[in] l List to join.
-/// @param[in] sep Used separator.
-/// @param[in] join_gap Garray to keep each list item string.
-///
-/// @return OK in case of success, FAIL otherwise.
-static int list_join_inner(garray_T *const gap, list_T *const l,
- const char *const sep, garray_T *const join_gap)
- FUNC_ATTR_NONNULL_ALL
-{
- int sumlen = 0;
- bool first = true;
- listitem_T *item;
-
- /* Stringify each item in the list. */
- for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) {
- char *s;
- size_t len;
- s = encode_tv2echo(&item->li_tv, &len);
- if (s == NULL) {
- return FAIL;
- }
-
- sumlen += (int) len;
-
- join_T *const p = GA_APPEND_VIA_PTR(join_T, join_gap);
- p->tofree = p->s = (char_u *) s;
-
- line_breakcheck();
- }
-
- /* Allocate result buffer with its total size, avoid re-allocation and
- * multiple copy operations. Add 2 for a tailing ']' and NUL. */
- if (join_gap->ga_len >= 2)
- sumlen += (int)STRLEN(sep) * (join_gap->ga_len - 1);
- ga_grow(gap, sumlen + 2);
-
- for (int i = 0; i < join_gap->ga_len && !got_int; ++i) {
- if (first) {
- first = false;
- } else {
- ga_concat(gap, (const char_u *) sep);
- }
- const join_T *const p = ((const join_T *)join_gap->ga_data) + i;
-
- if (p->s != NULL)
- ga_concat(gap, p->s);
- line_breakcheck();
- }
-
- return OK;
-}
-
-/// Join list into a string using given separator
-///
-/// @param[out] gap Garray where result will be saved.
-/// @param[in] l Joined list.
-/// @param[in] sep Separator.
-///
-/// @return OK in case of success, FAIL otherwise.
-static int list_join(garray_T *const gap, list_T *const l,
- const char *const sep)
- FUNC_ATTR_NONNULL_ALL
-{
- if (l->lv_len < 1) {
- return OK;
- }
-
- garray_T join_ga;
- int retval;
-
- ga_init(&join_ga, (int)sizeof(join_T), l->lv_len);
- retval = list_join_inner(gap, l, sep, &join_ga);
-
-# define FREE_JOIN_TOFREE(join) xfree((join)->tofree)
- GA_DEEP_CLEAR(&join_ga, join_T, FREE_JOIN_TOFREE);
-
- return retval;
-}
-
/// Get next (unique) copy ID
///
/// Used for traversing nested structures e.g. when serializing them or garbage
@@ -6036,7 +5224,7 @@ bool garbage_collect(bool testing)
/// Free lists and dictionaries that are no longer referenced.
///
-/// Note: This function may only be called from garbage_collect().
+/// @note This function may only be called from garbage_collect().
///
/// @param copyID Free lists/dictionaries that don't have this ID.
/// @return true, if something was freed.
@@ -6049,19 +5237,19 @@ static int free_unref_items(int copyID)
// Let all "free" functions know that we are here. This means no
// dictionaries, lists, or jobs are to be freed, because we will
// do that here.
- in_free_unref_items = true;
+ tv_in_free_unref_items = true;
// PASS 1: free the contents of the items. We don't free the items
// themselves yet, so that it is possible to decrement refcount counters.
// Go through the list of dicts and free items without the copyID.
// Don't free dicts that are referenced internally.
- for (dict_T *dd = first_dict; dd != NULL; dd = dd->dv_used_next) {
+ for (dict_T *dd = gc_first_dict; dd != NULL; dd = dd->dv_used_next) {
if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) {
// Free the Dictionary and ordinary items it contains, but don't
// recurse into Lists and Dictionaries, they will be in the list
// of dicts or list of lists.
- dict_free_contents(dd);
+ tv_dict_free_contents(dd);
did_free = true;
}
}
@@ -6069,36 +5257,36 @@ static int free_unref_items(int copyID)
// Go through the list of lists and free items without the copyID.
// But don't free a list that has a watcher (used in a for loop), these
// are not referenced anywhere.
- for (list_T *ll = first_list; ll != NULL; ll = ll->lv_used_next) {
+ for (list_T *ll = gc_first_list; ll != NULL; ll = ll->lv_used_next) {
if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)
&& ll->lv_watch == NULL) {
// Free the List and ordinary items it contains, but don't recurse
// into Lists and Dictionaries, they will be in the list of dicts
// or list of lists.
- list_free_contents(ll);
+ tv_list_free_contents(ll);
did_free = true;
}
}
// PASS 2: free the items themselves.
- for (dd = first_dict; dd != NULL; dd = dd_next) {
+ for (dd = gc_first_dict; dd != NULL; dd = dd_next) {
dd_next = dd->dv_used_next;
if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) {
- dict_free_dict(dd);
+ tv_dict_free_dict(dd);
}
}
- for (ll = first_list; ll != NULL; ll = ll_next) {
+ for (ll = gc_first_list; ll != NULL; ll = ll_next) {
ll_next = ll->lv_used_next;
if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)
&& ll->lv_watch == NULL) {
// Free the List and ordinary items it contains, but don't recurse
// into Lists and Dictionaries, they will be in the list of dicts
// or list of lists.
- list_free_list(ll);
+ tv_list_free_list(ll);
}
}
- in_free_unref_items = false;
+ tv_in_free_unref_items = false;
return did_free;
}
@@ -6121,14 +5309,10 @@ bool set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack)
// Mark each item in the hashtab. If the item contains a hashtab
// it is added to ht_stack, if it contains a list it is added to
// list_stack.
- int todo = (int)cur_ht->ht_used;
- for (hashitem_T *hi = cur_ht->ht_array; todo > 0; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- --todo;
- abort = abort || set_ref_in_item(&HI2DI(hi)->di_tv, copyID, &ht_stack,
- list_stack);
- }
- }
+ HASHTAB_ITER(cur_ht, hi, {
+ abort = abort || set_ref_in_item(
+ &TV_DICT_HI2DI(hi)->di_tv, copyID, &ht_stack, list_stack);
+ });
}
if (ht_stack == NULL) {
@@ -6220,7 +5404,7 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack,
QUEUE *w = NULL;
DictWatcher *watcher = NULL;
QUEUE_FOREACH(w, &dd->watchers) {
- watcher = dictwatcher_node_data(w);
+ watcher = tv_dict_watcher_node_data(w);
set_ref_in_callback(&watcher->callback, copyID, ht_stack, list_stack);
}
}
@@ -6365,463 +5549,6 @@ static bool set_ref_in_funccal(funccall_T *fc, int copyID)
return abort;
}
-/// Allocate an empty header for a dictionary.
-dict_T *dict_alloc(void) FUNC_ATTR_NONNULL_RET
-{
- dict_T *d = xmalloc(sizeof(dict_T));
-
- /* Add the dict to the list of dicts for garbage collection. */
- if (first_dict != NULL)
- first_dict->dv_used_prev = d;
- d->dv_used_next = first_dict;
- d->dv_used_prev = NULL;
- first_dict = d;
-
- hash_init(&d->dv_hashtab);
- d->dv_lock = VAR_UNLOCKED;
- d->dv_scope = 0;
- d->dv_refcount = 0;
- d->dv_copyID = 0;
- QUEUE_INIT(&d->watchers);
-
- return d;
-}
-
-/*
- * Allocate an empty dict for a return value.
- */
-static void rettv_dict_alloc(typval_T *rettv)
-{
- dict_T *d = dict_alloc();
-
- rettv->vval.v_dict = d;
- rettv->v_type = VAR_DICT;
- rettv->v_lock = VAR_UNLOCKED;
- d->dv_refcount++;
-}
-
-/// Clear all the keys of a Dictionary. "d" remains a valid empty Dictionary.
-///
-/// @param d The Dictionary to clear
-void dict_clear(dict_T *d)
- FUNC_ATTR_NONNULL_ALL
-{
- hash_lock(&d->dv_hashtab);
- assert(d->dv_hashtab.ht_locked > 0);
-
- size_t todo = d->dv_hashtab.ht_used;
- for (hashitem_T *hi = d->dv_hashtab.ht_array; todo > 0; hi++) {
- if (!HASHITEM_EMPTY(hi)) {
- dictitem_free(HI2DI(hi));
- hash_remove(&d->dv_hashtab, hi);
- todo--;
- }
- }
-
- hash_unlock(&d->dv_hashtab);
-}
-
-
-/*
- * Unreference a Dictionary: decrement the reference count and free it when it
- * becomes zero.
- */
-void dict_unref(dict_T *d)
-{
- if (d != NULL && --d->dv_refcount <= 0) {
- dict_free(d);
- }
-}
-
-/// Free a Dictionary, including all items it contains.
-/// Ignores the reference count.
-static void dict_free_contents(dict_T *d) {
- int todo;
- hashitem_T *hi;
- dictitem_T *di;
-
-
- /* Lock the hashtab, we don't want it to resize while freeing items. */
- hash_lock(&d->dv_hashtab);
- assert(d->dv_hashtab.ht_locked > 0);
- todo = (int)d->dv_hashtab.ht_used;
- for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- /* Remove the item before deleting it, just in case there is
- * something recursive causing trouble. */
- di = HI2DI(hi);
- hash_remove(&d->dv_hashtab, hi);
- dictitem_free(di);
- todo--;
- }
- }
-
- while (!QUEUE_EMPTY(&d->watchers)) {
- QUEUE *w = QUEUE_HEAD(&d->watchers);
- DictWatcher *watcher = dictwatcher_node_data(w);
- QUEUE_REMOVE(w);
- dictwatcher_free(watcher);
- }
-
- hash_clear(&d->dv_hashtab);
-}
-
-static void dict_free_dict(dict_T *d) {
- // Remove the dict from the list of dicts for garbage collection.
- if (d->dv_used_prev == NULL) {
- first_dict = d->dv_used_next;
- } else {
- d->dv_used_prev->dv_used_next = d->dv_used_next;
- }
- if (d->dv_used_next != NULL) {
- d->dv_used_next->dv_used_prev = d->dv_used_prev;
- }
-
- xfree(d);
-}
-
-void dict_free(dict_T *d)
-{
- if (!in_free_unref_items) {
- dict_free_contents(d);
- dict_free_dict(d);
- }
-}
-
-/// Allocate a dictionary item
-///
-/// @note that the value of the item di_tv still needs to be initialized.
-///
-/// @param[in] key Item key.
-/// @param[in] len Key length.
-///
-/// @return [allocated] New dictionary item.
-dictitem_T *dictitem_alloc_len(const char *const key, const size_t len)
- FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
-{
- dictitem_T *const di = xmallocz(offsetof(dictitem_T, di_key) + len);
- memcpy(di->di_key, key, len);
- di->di_flags = DI_FLAGS_ALLOC;
- return di;
-}
-
-/// Allocate a dictionary item
-///
-/// @note that the value of the item di_tv still needs to be initialized.
-///
-/// @param[in] key Item key, NUL-terminated string.
-///
-/// @return [allocated] New dictionary item.
-dictitem_T *dictitem_alloc(const char_u *const key)
- FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
-{
- return dictitem_alloc_len((const char *)key, STRLEN(key));
-}
-
-/*
- * Make a copy of a Dictionary item.
- */
-static dictitem_T *dictitem_copy(dictitem_T *org) FUNC_ATTR_NONNULL_RET
-{
- dictitem_T *di = xmalloc(sizeof(dictitem_T) + STRLEN(org->di_key));
-
- STRCPY(di->di_key, org->di_key);
- di->di_flags = DI_FLAGS_ALLOC;
- copy_tv(&org->di_tv, &di->di_tv);
-
- return di;
-}
-
-/*
- * Remove item "item" from Dictionary "dict" and free it.
- */
-static void dictitem_remove(dict_T *dict, dictitem_T *item)
-{
- hashitem_T *hi;
-
- hi = hash_find(&dict->dv_hashtab, item->di_key);
- if (HASHITEM_EMPTY(hi)) {
- EMSG2(_(e_intern2), "dictitem_remove()");
- } else {
- hash_remove(&dict->dv_hashtab, hi);
- }
- dictitem_free(item);
-}
-
-/*
- * Free a dict item. Also clears the value.
- */
-void dictitem_free(dictitem_T *item)
-{
- clear_tv(&item->di_tv);
- if (item->di_flags & DI_FLAGS_ALLOC) {
- xfree(item);
- }
-}
-
-/// Make a copy of dictionary
-///
-/// @param[in] conv If non-NULL, then all internal strings will be converted.
-/// @param[in] orig Original dictionary to copy.
-/// @param[in] deep If false, then shallow copy will be done.
-/// @param[in] copyID See var_item_copy().
-///
-/// @return Copied dictionary. May be NULL in case original dictionary is NULL
-/// or some failure happens. The refcount of the new dictionary is set
-/// to 1.
-static dict_T *dict_copy(const vimconv_T *const conv,
- dict_T *const orig,
- const bool deep,
- const int copyID)
-{
- dictitem_T *di;
- int todo;
- hashitem_T *hi;
-
- if (orig == NULL)
- return NULL;
-
- dict_T *copy = dict_alloc();
- {
- if (copyID != 0) {
- orig->dv_copyID = copyID;
- orig->dv_copydict = copy;
- }
- todo = (int)orig->dv_hashtab.ht_used;
- for (hi = orig->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- --todo;
-
- if (conv == NULL || conv->vc_type == CONV_NONE) {
- di = dictitem_alloc(hi->hi_key);
- } else {
- char *const key = (char *) string_convert((vimconv_T *) conv,
- hi->hi_key, NULL);
- if (key == NULL) {
- di = dictitem_alloc(hi->hi_key);
- } else {
- di = dictitem_alloc((char_u *) key);
- xfree(key);
- }
- }
- if (deep) {
- if (var_item_copy(conv, &HI2DI(hi)->di_tv, &di->di_tv, deep,
- copyID) == FAIL) {
- xfree(di);
- break;
- }
- } else
- copy_tv(&HI2DI(hi)->di_tv, &di->di_tv);
- if (dict_add(copy, di) == FAIL) {
- dictitem_free(di);
- break;
- }
- }
- }
-
- ++copy->dv_refcount;
- if (todo > 0) {
- dict_unref(copy);
- copy = NULL;
- }
- }
-
- return copy;
-}
-
-/*
- * Add item "item" to Dictionary "d".
- * Returns FAIL when key already exists.
- */
-int dict_add(dict_T *d, dictitem_T *item)
-{
- return hash_add(&d->dv_hashtab, item->di_key);
-}
-
-/*
- * Add a number or string entry to dictionary "d".
- * When "str" is NULL use number "nr", otherwise use "str".
- * Returns FAIL when key already exists.
- */
-int dict_add_nr_str(dict_T *d, char *key, long nr, char_u *str)
-{
- dictitem_T *item;
-
- item = dictitem_alloc((char_u *)key);
- item->di_tv.v_lock = 0;
- if (str == NULL) {
- item->di_tv.v_type = VAR_NUMBER;
- item->di_tv.vval.v_number = nr;
- } else {
- item->di_tv.v_type = VAR_STRING;
- item->di_tv.vval.v_string = vim_strsave(str);
- }
- if (dict_add(d, item) == FAIL) {
- dictitem_free(item);
- return FAIL;
- }
- return OK;
-}
-
-/*
- * Add a list entry to dictionary "d".
- * Returns FAIL when key already exists.
- */
-int dict_add_list(dict_T *d, char *key, list_T *list)
-{
- dictitem_T *item = dictitem_alloc((char_u *)key);
-
- item->di_tv.v_lock = 0;
- item->di_tv.v_type = VAR_LIST;
- item->di_tv.vval.v_list = list;
- if (dict_add(d, item) == FAIL) {
- dictitem_free(item);
- return FAIL;
- }
- ++list->lv_refcount;
- return OK;
-}
-
-/// Add a dict entry to dictionary "d".
-/// Returns FAIL when out of memory and when key already exists.
-int dict_add_dict(dict_T *d, char *key, dict_T *dict)
-{
- dictitem_T *item = dictitem_alloc((char_u *)key);
-
- item->di_tv.v_lock = 0;
- item->di_tv.v_type = VAR_DICT;
- item->di_tv.vval.v_dict = dict;
- if (dict_add(d, item) == FAIL) {
- dictitem_free(item);
- return FAIL;
- }
- dict->dv_refcount++;
- return OK;
-}
-
-/// Set all existing keys in "dict" as read-only.
-///
-/// This does not protect against adding new keys to the Dictionary.
-///
-/// @param dict The dict whose keys should be frozen
-void dict_set_keys_readonly(dict_T *dict)
- FUNC_ATTR_NONNULL_ALL
-{
- size_t todo = dict->dv_hashtab.ht_used;
- for (hashitem_T *hi = dict->dv_hashtab.ht_array; todo > 0 ; hi++) {
- if (HASHITEM_EMPTY(hi)) {
- continue;
- }
- todo--;
- HI2DI(hi)->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX;
- }
-}
-
-/*
- * Get the number of items in a Dictionary.
- */
-static long dict_len(dict_T *d)
-{
- if (d == NULL)
- return 0L;
- return (long)d->dv_hashtab.ht_used;
-}
-
-/*
- * Find item "key[len]" in Dictionary "d".
- * If "len" is negative use strlen(key).
- * Returns NULL when not found.
- */
-dictitem_T *dict_find(dict_T *d, char_u *key, int len)
-{
-#define AKEYLEN 200
- char_u buf[AKEYLEN];
- char_u *akey;
- char_u *tofree = NULL;
- hashitem_T *hi;
-
- if (d == NULL) {
- return NULL;
- }
- if (len < 0) {
- akey = key;
- } else if (len >= AKEYLEN) {
- tofree = akey = vim_strnsave(key, len);
- } else {
- /* Avoid a malloc/free by using buf[]. */
- STRLCPY(buf, key, len + 1);
- akey = buf;
- }
-
- hi = hash_find(&d->dv_hashtab, akey);
- xfree(tofree);
- if (HASHITEM_EMPTY(hi))
- return NULL;
- return HI2DI(hi);
-}
-
-/// Get a function from a dictionary
-/// @param[out] result The address where a pointer to the wanted callback
-/// will be left.
-/// @return true/false on success/failure.
-static bool get_dict_callback(dict_T *d, char *key, Callback *result)
-{
- dictitem_T *di = dict_find(d, (uint8_t *)key, -1);
-
- if (di == NULL) {
- result->type = kCallbackNone;
- return true;
- }
-
- if (di->di_tv.v_type != VAR_FUNC && di->di_tv.v_type != VAR_STRING
- && di->di_tv.v_type != VAR_PARTIAL) {
- EMSG(_("Argument is not a function or function name"));
- result->type = kCallbackNone;
- return false;
- }
-
- typval_T tv;
- copy_tv(&di->di_tv, &tv);
- set_selfdict(&tv, d);
- bool res = callback_from_typval(result, &tv);
- clear_tv(&tv);
- return res;
-}
-
-/// Get a string item from a dictionary.
-///
-/// @param save whether memory should be allocated for the return value
-/// when false a shared buffer is used, can only be used once!
-///
-/// @return the entry or NULL if the entry doesn't exist.
-char_u *get_dict_string(dict_T *d, char *key, bool save)
-{
- dictitem_T *di;
- char_u *s;
-
- di = dict_find(d, (char_u *)key, -1);
- if (di == NULL) {
- return NULL;
- }
- s = get_tv_string(&di->di_tv);
- if (save) {
- s = vim_strsave(s);
- }
- return s;
-}
-
-/// Get a number item from a dictionary.
-///
-/// @return the entry or 0 if the entry doesn't exist.
-long get_dict_number(dict_T *d, char *key)
-{
- dictitem_T *di = dict_find(d, (char_u *)key, -1);
- if (di == NULL) {
- return 0;
- }
- return get_tv_number(&di->di_tv);
-}
-
/*
* Allocate a variable for a Dictionary and fill it from "*arg".
* Return OK or FAIL. Returns NOTDONE for {expr}.
@@ -6834,7 +5561,7 @@ static int get_dict_tv(char_u **arg, typval_T *rettv, int evaluate)
char_u *key = NULL;
dictitem_T *item;
char_u *start = skipwhite(*arg + 1);
- char_u buf[NUMBUFLEN];
+ char buf[NUMBUFLEN];
/*
* First check if it's not a curly-braces thing: {expr}.
@@ -6851,7 +5578,7 @@ static int get_dict_tv(char_u **arg, typval_T *rettv, int evaluate)
}
if (evaluate) {
- d = dict_alloc();
+ d = tv_dict_alloc();
}
tvkey.v_type = VAR_UNKNOWN;
tv.v_type = VAR_UNKNOWN;
@@ -6862,38 +5589,39 @@ static int get_dict_tv(char_u **arg, typval_T *rettv, int evaluate)
goto failret;
if (**arg != ':') {
EMSG2(_("E720: Missing colon in Dictionary: %s"), *arg);
- clear_tv(&tvkey);
+ tv_clear(&tvkey);
goto failret;
}
if (evaluate) {
- key = get_tv_string_buf_chk(&tvkey, buf);
+ key = (char_u *)tv_get_string_buf_chk(&tvkey, buf);
if (key == NULL) {
- // "key" is NULL when get_tv_string_buf_chk() gave an errmsg
- clear_tv(&tvkey);
+ // "key" is NULL when tv_get_string_buf_chk() gave an errmsg
+ tv_clear(&tvkey);
goto failret;
}
}
*arg = skipwhite(*arg + 1);
- if (eval1(arg, &tv, evaluate) == FAIL) { /* recursive! */
- if (evaluate)
- clear_tv(&tvkey);
+ if (eval1(arg, &tv, evaluate) == FAIL) { // Recursive!
+ if (evaluate) {
+ tv_clear(&tvkey);
+ }
goto failret;
}
if (evaluate) {
- item = dict_find(d, key, -1);
+ item = tv_dict_find(d, (const char *)key, -1);
if (item != NULL) {
EMSG2(_("E721: Duplicate key in Dictionary: \"%s\""), key);
- clear_tv(&tvkey);
- clear_tv(&tv);
+ tv_clear(&tvkey);
+ tv_clear(&tv);
goto failret;
}
- item = dictitem_alloc(key);
- clear_tv(&tvkey);
+ item = tv_dict_item_alloc((const char *)key);
+ tv_clear(&tvkey);
item->di_tv = tv;
item->di_tv.v_lock = 0;
- if (dict_add(d, item) == FAIL) {
- dictitem_free(item);
+ if (tv_dict_add(d, item) == FAIL) {
+ tv_dict_item_free(item);
}
}
@@ -6910,7 +5638,7 @@ static int get_dict_tv(char_u **arg, typval_T *rettv, int evaluate)
EMSG2(_("E723: Missing end of Dictionary '}': %s"), *arg);
failret:
if (evaluate) {
- dict_free(d);
+ tv_dict_free(d);
}
return FAIL;
}
@@ -7185,7 +5913,7 @@ static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate)
++*arg;
name = *arg;
- len = get_env_len(arg);
+ len = get_env_len((const char_u **)arg);
if (evaluate) {
if (len == 0) {
@@ -7408,8 +6136,9 @@ get_func_tv (
}
}
- while (--argcount >= 0)
- clear_tv(&argvars[argcount]);
+ while (--argcount >= 0) {
+ tv_clear(&argvars[argcount]);
+ }
*arg = skipwhite(argp);
return ret;
@@ -7527,7 +6256,7 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
/// Also returns OK when an error was encountered while executing the function.
int
call_func(
- char_u *funcname, // name of the function
+ const char_u *funcname, // name of the function
int len, // length of "name"
typval_T *rettv, // return value goes here
int argcount_in, // number of "argvars"
@@ -7576,7 +6305,7 @@ call_func(
}
if (error == ERROR_NONE && partial->pt_argc > 0) {
for (argv_clear = 0; argv_clear < partial->pt_argc; argv_clear++) {
- copy_tv(&partial->pt_argv[argv_clear], &argv[argv_clear]);
+ tv_copy(&partial->pt_argv[argv_clear], &argv[argv_clear]);
}
for (int i = 0; i < argcount_in; i++) {
argv[i + argv_clear] = argvars_in[i];
@@ -7705,7 +6434,7 @@ call_func(
}
while (argv_clear > 0) {
- clear_tv(&argv[--argv_clear]);
+ tv_clear(&argv[--argv_clear]);
}
xfree(tofree);
xfree(name);
@@ -7749,24 +6478,6 @@ static int non_zero_arg(typval_T *argvars)
*/
-/*
- * Get the float value of "argvars[0]" into "f".
- * Returns FAIL when the argument is not a Number or Float.
- */
-static inline int get_float_arg(typval_T *argvars, float_T *f)
-{
- if (argvars[0].v_type == VAR_FLOAT) {
- *f = argvars[0].vval.v_float;
- return OK;
- }
- if (argvars[0].v_type == VAR_NUMBER) {
- *f = (float_T)argvars[0].vval.v_number;
- return OK;
- }
- EMSG(_("E808: Number or Float required"));
- return FAIL;
-}
-
// Apply a floating point C function on a typval with one float_T.
//
// Some versions of glibc on i386 have an optimization that makes it harder to
@@ -7778,7 +6489,7 @@ static void float_op_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr)
float_T (*function)(float_T) = (float_T (*)(float_T))fptr;
rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &f) == OK) {
+ if (tv_get_float_chk(argvars, &f)) {
rettv->vval.v_float = function(f);
} else {
rettv->vval.v_float = 0.0;
@@ -7821,15 +6532,16 @@ static void f_abs(typval_T *argvars, typval_T *rettv, FunPtr fptr)
float_op_wrapper(argvars, rettv, (FunPtr)&fabs);
} else {
varnumber_T n;
- int error = FALSE;
+ bool error = false;
- n = get_tv_number_chk(&argvars[0], &error);
- if (error)
+ n = tv_get_number_chk(&argvars[0], &error);
+ if (error) {
rettv->vval.v_number = -1;
- else if (n > 0)
+ } else if (n > 0) {
rettv->vval.v_number = n;
- else
+ } else {
rettv->vval.v_number = -n;
+ }
}
}
@@ -7846,11 +6558,12 @@ static void f_add(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const size_t arg_errmsg_len = strlen(arg_errmsg);
if ((l = argvars[0].vval.v_list) != NULL
&& !tv_check_lock(l->lv_lock, arg_errmsg, arg_errmsg_len)) {
- list_append_tv(l, &argvars[1]);
- copy_tv(&argvars[0], rettv);
+ tv_list_append_tv(l, &argvars[1]);
+ tv_copy(&argvars[0], rettv);
}
- } else
+ } else {
EMSG(_(e_listreq));
+ }
}
/*
@@ -7858,8 +6571,8 @@ static void f_add(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_and(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
- & get_tv_number_chk(&argvars[1], NULL);
+ rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
+ & tv_get_number_chk(&argvars[1], NULL);
}
@@ -7877,7 +6590,6 @@ static void f_api_info(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_append(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
long lnum;
- char_u *line;
list_T *l = NULL;
listitem_T *li = NULL;
typval_T *tv;
@@ -7890,7 +6602,7 @@ static void f_append(typval_T *argvars, typval_T *rettv, FunPtr fptr)
u_sync(TRUE);
}
- lnum = get_tv_lnum(argvars);
+ lnum = tv_get_lnum(argvars);
if (lnum >= 0
&& lnum <= curbuf->b_ml.ml_line_count
&& u_save(lnum, lnum + 1) == OK) {
@@ -7901,21 +6613,23 @@ static void f_append(typval_T *argvars, typval_T *rettv, FunPtr fptr)
li = l->lv_first;
}
for (;; ) {
- if (l == NULL)
- tv = &argvars[1]; /* append a string */
- else if (li == NULL)
- break; /* end of list */
- else
- tv = &li->li_tv; /* append item from list */
- line = get_tv_string_chk(tv);
- if (line == NULL) { /* type error */
- rettv->vval.v_number = 1; /* Failed */
+ if (l == NULL) {
+ tv = &argvars[1]; // Append a string.
+ } else if (li == NULL) {
+ break; // End of list.
+ } else {
+ tv = &li->li_tv; // Append item from list.
+ }
+ const char *const line = tv_get_string_chk(tv);
+ if (line == NULL) { // Type error.
+ rettv->vval.v_number = 1; // Failed.
break;
}
- ml_append(lnum + added, line, (colnr_T)0, FALSE);
- ++added;
- if (l == NULL)
+ ml_append(lnum + added, (char_u *)line, (colnr_T)0, false);
+ added++;
+ if (l == NULL) {
break;
+ }
li = li->li_next;
}
@@ -7960,16 +6674,19 @@ static void f_argv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int idx;
if (argvars[0].v_type != VAR_UNKNOWN) {
- idx = get_tv_number_chk(&argvars[0], NULL);
- if (idx >= 0 && idx < ARGCOUNT)
- rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
- else
+ idx = tv_get_number_chk(&argvars[0], NULL);
+ if (idx >= 0 && idx < ARGCOUNT) {
+ rettv->vval.v_string = (char_u *)xstrdup(
+ (const char *)alist_name(&ARGLIST[idx]));
+ } else {
rettv->vval.v_string = NULL;
+ }
rettv->v_type = VAR_STRING;
} else {
- rettv_list_alloc(rettv);
- for (idx = 0; idx < ARGCOUNT; ++idx) {
- list_append_string(rettv->vval.v_list, alist_name(&ARGLIST[idx]), -1);
+ tv_list_alloc_ret(rettv);
+ for (idx = 0; idx < ARGCOUNT; idx++) {
+ tv_list_append_string(rettv->vval.v_list,
+ (const char *)alist_name(&ARGLIST[idx]), -1);
}
}
}
@@ -8041,10 +6758,10 @@ static void assert_error(garray_T *gap)
if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL) {
// Make sure v:errors is a list.
- set_vim_var_list(VV_ERRORS, list_alloc());
+ set_vim_var_list(VV_ERRORS, tv_list_alloc());
}
- list_append_string(vimvars[VV_ERRORS].vv_list,
- gap->ga_data, gap->ga_len);
+ tv_list_append_string(vimvars[VV_ERRORS].vv_list,
+ (const char *)gap->ga_data, (ptrdiff_t)gap->ga_len);
}
static void assert_equal_common(typval_T *argvars, assert_type_T atype)
@@ -8078,7 +6795,7 @@ static void f_assert_exception(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
garray_T ga;
- char *error = (char *)get_tv_string_chk(&argvars[0]);
+ const char *const error = tv_get_string_chk(&argvars[0]);
if (vimvars[VV_EXCEPTION].vv_str == NULL) {
prepare_assert_error(&ga);
ga_concat(&ga, (char_u *)"v:exception is not set");
@@ -8097,22 +6814,22 @@ static void f_assert_exception(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "assert_fails(cmd [, error])" function
static void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *cmd = get_tv_string_chk(&argvars[0]);
+ const char *const cmd = tv_get_string_chk(&argvars[0]);
garray_T ga;
called_emsg = false;
suppress_errthrow = true;
emsg_silent = true;
- do_cmdline_cmd((char *)cmd);
+ do_cmdline_cmd(cmd);
if (!called_emsg) {
prepare_assert_error(&ga);
- ga_concat(&ga, (char_u *)"command did not fail: ");
- ga_concat(&ga, cmd);
+ ga_concat(&ga, (const char_u *)"command did not fail: ");
+ ga_concat(&ga, (const char_u *)cmd);
assert_error(&ga);
ga_clear(&ga);
} else if (argvars[1].v_type != VAR_UNKNOWN) {
- char_u buf[NUMBUFLEN];
- char *error = (char *)get_tv_string_buf_chk(&argvars[1], buf);
+ char buf[NUMBUFLEN];
+ const char *const error = tv_get_string_buf_chk(&argvars[1], buf);
if (error == NULL
|| strstr((char *)vimvars[VV_ERRMSG].vv_str, error) == NULL) {
@@ -8133,10 +6850,10 @@ static void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr)
void assert_inrange(typval_T *argvars)
{
- int error = (int)false;
- varnumber_T lower = get_tv_number_chk(&argvars[0], &error);
- varnumber_T upper = get_tv_number_chk(&argvars[1], &error);
- varnumber_T actual = get_tv_number_chk(&argvars[2], &error);
+ bool error = false;
+ const varnumber_T lower = tv_get_number_chk(&argvars[0], &error);
+ const varnumber_T upper = tv_get_number_chk(&argvars[1], &error);
+ const varnumber_T actual = tv_get_number_chk(&argvars[2], &error);
if (error) {
return;
@@ -8146,8 +6863,9 @@ void assert_inrange(typval_T *argvars)
prepare_assert_error(&ga);
char msg[55];
- vim_snprintf(msg, sizeof(msg), "range %" PRId64 " - %" PRId64 ",",
- (int64_t)lower, (int64_t)upper);
+ vim_snprintf(msg, sizeof(msg),
+ "range %" PRIdVARNUMBER " - %" PRIdVARNUMBER ",",
+ lower, upper);
fill_assert_error(&ga, &argvars[3], (char_u *)msg, NULL, &argvars[2],
ASSERT_INRANGE);
assert_error(&ga);
@@ -8158,11 +6876,11 @@ void assert_inrange(typval_T *argvars)
// Common for assert_true() and assert_false().
static void assert_bool(typval_T *argvars, bool is_true)
{
- int error = (int)false;
+ bool error = false;
garray_T ga;
if ((argvars[0].v_type != VAR_NUMBER
- || (get_tv_number_chk(&argvars[0], &error) == 0) == is_true
+ || (tv_get_number_chk(&argvars[0], &error) == 0) == is_true
|| error)
&& (argvars[0].v_type != VAR_SPECIAL
|| (argvars[0].vval.v_special
@@ -8186,14 +6904,15 @@ static void f_assert_false(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void assert_match_common(typval_T *argvars, assert_type_T atype)
{
- char_u buf1[NUMBUFLEN];
- char_u buf2[NUMBUFLEN];
- char_u *pat = get_tv_string_buf_chk(&argvars[0], buf1);
- char_u *text = get_tv_string_buf_chk(&argvars[1], buf2);
+ char buf1[NUMBUFLEN];
+ char buf2[NUMBUFLEN];
+ const char *const pat = tv_get_string_buf_chk(&argvars[0], buf1);
+ const char *const text = tv_get_string_buf_chk(&argvars[1], buf2);
if (pat == NULL || text == NULL) {
EMSG(_(e_invarg));
- } else if (pattern_match(pat, text, false) != (atype == ASSERT_MATCH)) {
+ } else if (pattern_match((char_u *)pat, (char_u *)text, false)
+ != (atype == ASSERT_MATCH)) {
garray_T ga;
prepare_assert_error(&ga);
fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], atype);
@@ -8231,14 +6950,15 @@ static void f_assert_true(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_atan2(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- float_T fx, fy;
+ float_T fx;
+ float_T fy;
rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &fx) == OK
- && get_float_arg(&argvars[1], &fy) == OK)
+ if (tv_get_float_chk(argvars, &fx) && tv_get_float_chk(&argvars[1], &fy)) {
rettv->vval.v_float = atan2(fx, fy);
- else
+ } else {
rettv->vval.v_float = 0.0;
+ }
}
/*
@@ -8380,8 +7100,7 @@ static void f_bufname(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_bufnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int error = false;
- char_u *name;
+ bool error = false;
rettv->vval.v_number = -1;
if (!tv_check_str_or_nr(&argvars[0])) {
@@ -8393,13 +7112,14 @@ static void f_bufnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// If the buffer isn't found and the second argument is not zero create a
// new buffer.
+ const char *name;
if (buf == NULL
&& argvars[1].v_type != VAR_UNKNOWN
- && get_tv_number_chk(&argvars[1], &error) != 0
+ && tv_get_number_chk(&argvars[1], &error) != 0
&& !error
- && (name = get_tv_string_chk(&argvars[0])) != NULL
+ && (name = tv_get_string_chk(&argvars[0])) != NULL
&& !error) {
- buf = buflist_new(name, NULL, (linenr_T)1, 0);
+ buf = buflist_new((char_u *)name, NULL, 1, 0);
}
if (buf != NULL) {
@@ -8453,7 +7173,7 @@ static void f_bufwinnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_byte2line(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- long boff = get_tv_number(&argvars[0]) - 1;
+ long boff = tv_get_number(&argvars[0]) - 1;
if (boff < 0) {
rettv->vval.v_number = -1;
} else {
@@ -8464,24 +7184,23 @@ static void f_byte2line(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void byteidx(typval_T *argvars, typval_T *rettv, int comp)
{
- char_u *t;
- char_u *str;
- long idx;
-
- str = get_tv_string_chk(&argvars[0]);
- idx = get_tv_number_chk(&argvars[1], NULL);
+ const char *const str = tv_get_string_chk(&argvars[0]);
+ varnumber_T idx = tv_get_number_chk(&argvars[1], NULL);
rettv->vval.v_number = -1;
- if (str == NULL || idx < 0)
+ if (str == NULL || idx < 0) {
return;
+ }
- t = str;
+ const char *t = str;
for (; idx > 0; idx--) {
- if (*t == NUL) /* EOL reached */
+ if (*t == NUL) { // EOL reached.
return;
- if (enc_utf8 && comp)
- t += utf_ptr2len(t);
- else
- t += (*mb_ptr2len)(t);
+ }
+ if (enc_utf8 && comp) {
+ t += utf_ptr2len((const char_u *)t);
+ } else {
+ t += (*mb_ptr2len)((const char_u *)t);
+ }
}
rettv->vval.v_number = (varnumber_T)(t - str);
}
@@ -8520,7 +7239,7 @@ int func_call(char_u *name, typval_T *args, partial_T *partial,
/* Make a copy of each argument. This is needed to be able to set
* v_lock to VAR_FIXED in the copy without changing the original list.
*/
- copy_tv(&item->li_tv, &argv[argc++]);
+ tv_copy(&item->li_tv, &argv[argc++]);
}
if (item == NULL) {
@@ -8529,9 +7248,10 @@ int func_call(char_u *name, typval_T *args, partial_T *partial,
&dummy, true, partial, selfdict);
}
- /* Free the arguments. */
- while (argc > 0)
- clear_tv(&argv[--argc]);
+ // Free the arguments.
+ while (argc > 0) {
+ tv_clear(&argv[--argc]);
+ }
return r;
}
@@ -8539,24 +7259,24 @@ int func_call(char_u *name, typval_T *args, partial_T *partial,
/// "call(func, arglist [, dict])" function
static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *func;
- partial_T *partial = NULL;
- dict_T *selfdict = NULL;
-
if (argvars[1].v_type != VAR_LIST) {
EMSG(_(e_listreq));
return;
}
- if (argvars[1].vval.v_list == NULL)
+ if (argvars[1].vval.v_list == NULL) {
return;
+ }
+ char_u *func;
+ partial_T *partial = NULL;
+ dict_T *selfdict = NULL;
if (argvars[0].v_type == VAR_FUNC) {
func = argvars[0].vval.v_string;
} else if (argvars[0].v_type == VAR_PARTIAL) {
partial = argvars[0].vval.v_partial;
func = partial_name(partial);
} else {
- func = get_tv_string(&argvars[0]);
+ func = (char_u *)tv_get_string(&argvars[0]);
}
if (*func == NUL) {
return; // type error or empty name
@@ -8589,15 +7309,15 @@ static void f_char2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (has_mbyte) {
int utf8 = 0;
- if (argvars[1].v_type != VAR_UNKNOWN)
- utf8 = get_tv_number_chk(&argvars[1], NULL);
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ utf8 = tv_get_number_chk(&argvars[1], NULL);
+ }
- if (utf8)
- rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
- else
- rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
- } else
- rettv->vval.v_number = get_tv_string(&argvars[0])[0];
+ rettv->vval.v_number = (utf8 ? *utf_ptr2char : *mb_ptr2char)(
+ (const char_u *)tv_get_string(&argvars[0]));
+ } else {
+ rettv->vval.v_number = (uint8_t)(tv_get_string(&argvars[0])[0]);
+ }
}
/*
@@ -8609,7 +7329,7 @@ static void f_cindent(typval_T *argvars, typval_T *rettv, FunPtr fptr)
linenr_T lnum;
pos = curwin->w_cursor;
- lnum = get_tv_lnum(argvars);
+ lnum = tv_get_lnum(argvars);
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
curwin->w_cursor.lnum = lnum;
rettv->vval.v_number = get_c_indent();
@@ -8668,8 +7388,6 @@ static void f_col(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int startcol;
-
if ((State & INSERT) == 0) {
EMSG(_("E785: complete() can only be used in Insert mode"));
return;
@@ -8685,9 +7403,10 @@ static void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- startcol = get_tv_number_chk(&argvars[0], NULL);
- if (startcol <= 0)
+ const int startcol = tv_get_number_chk(&argvars[0], NULL);
+ if (startcol <= 0) {
return;
+ }
set_completion(startcol - 1, argvars[1].vval.v_list);
}
@@ -8718,47 +7437,51 @@ static void f_complete_check(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_confirm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *message;
- char_u *buttons = NULL;
- char_u buf[NUMBUFLEN];
- char_u buf2[NUMBUFLEN];
+ char buf[NUMBUFLEN];
+ char buf2[NUMBUFLEN];
+ const char *message;
+ const char *buttons = NULL;
int def = 1;
int type = VIM_GENERIC;
- char_u *typestr;
- int error = FALSE;
+ const char *typestr;
+ bool error = false;
- message = get_tv_string_chk(&argvars[0]);
- if (message == NULL)
- error = TRUE;
+ message = tv_get_string_chk(&argvars[0]);
+ if (message == NULL) {
+ error = true;
+ }
if (argvars[1].v_type != VAR_UNKNOWN) {
- buttons = get_tv_string_buf_chk(&argvars[1], buf);
- if (buttons == NULL)
- error = TRUE;
+ buttons = tv_get_string_buf_chk(&argvars[1], buf);
+ if (buttons == NULL) {
+ error = true;
+ }
if (argvars[2].v_type != VAR_UNKNOWN) {
- def = get_tv_number_chk(&argvars[2], &error);
+ def = tv_get_number_chk(&argvars[2], &error);
if (argvars[3].v_type != VAR_UNKNOWN) {
- typestr = get_tv_string_buf_chk(&argvars[3], buf2);
- if (typestr == NULL)
- error = TRUE;
- else {
+ typestr = tv_get_string_buf_chk(&argvars[3], buf2);
+ if (typestr == NULL) {
+ error = true;
+ } else {
switch (TOUPPER_ASC(*typestr)) {
- case 'E': type = VIM_ERROR; break;
- case 'Q': type = VIM_QUESTION; break;
- case 'I': type = VIM_INFO; break;
- case 'W': type = VIM_WARNING; break;
- case 'G': type = VIM_GENERIC; break;
+ case 'E': type = VIM_ERROR; break;
+ case 'Q': type = VIM_QUESTION; break;
+ case 'I': type = VIM_INFO; break;
+ case 'W': type = VIM_WARNING; break;
+ case 'G': type = VIM_GENERIC; break;
}
}
}
}
}
- if (buttons == NULL || *buttons == NUL)
- buttons = (char_u *)_("&Ok");
+ if (buttons == NULL || *buttons == NUL) {
+ buttons = _("&Ok");
+ }
- if (!error)
- rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
- def, NULL, FALSE);
+ if (!error) {
+ rettv->vval.v_number = do_dialog(
+ type, NULL, (char_u *)message, (char_u *)buttons, def, NULL, false);
+ }
}
/*
@@ -8785,15 +7508,16 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if ((l = argvars[0].vval.v_list) != NULL) {
li = l->lv_first;
if (argvars[2].v_type != VAR_UNKNOWN) {
- int error = FALSE;
+ bool error = false;
- ic = get_tv_number_chk(&argvars[2], &error);
+ ic = tv_get_number_chk(&argvars[2], &error);
if (argvars[3].v_type != VAR_UNKNOWN) {
- idx = get_tv_number_chk(&argvars[3], &error);
+ idx = tv_get_number_chk(&argvars[3], &error);
if (!error) {
- li = list_find(l, idx);
- if (li == NULL)
+ li = tv_list_find(l, idx);
+ if (li == NULL) {
EMSGN(_(e_listidx), idx);
+ }
}
}
if (error)
@@ -8810,20 +7534,22 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
hashitem_T *hi;
if ((d = argvars[0].vval.v_dict) != NULL) {
- int error = FALSE;
+ bool error = false;
if (argvars[2].v_type != VAR_UNKNOWN) {
- ic = get_tv_number_chk(&argvars[2], &error);
- if (argvars[3].v_type != VAR_UNKNOWN)
+ ic = tv_get_number_chk(&argvars[2], &error);
+ if (argvars[3].v_type != VAR_UNKNOWN) {
EMSG(_(e_invarg));
+ }
}
todo = error ? 0 : (int)d->dv_hashtab.ht_used;
for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) {
if (!HASHITEM_EMPTY(hi)) {
- --todo;
- if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
- ++n;
+ todo--;
+ if (tv_equal(&TV_DICT_HI2DI(hi)->di_tv, &argvars[1], ic, false)) {
+ n++;
+ }
}
}
}
@@ -8840,19 +7566,21 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_cscope_connection(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int num = 0;
- char_u *dbpath = NULL;
- char_u *prepend = NULL;
- char_u buf[NUMBUFLEN];
+ const char *dbpath = NULL;
+ const char *prepend = NULL;
+ char buf[NUMBUFLEN];
if (argvars[0].v_type != VAR_UNKNOWN
&& argvars[1].v_type != VAR_UNKNOWN) {
- num = (int)get_tv_number(&argvars[0]);
- dbpath = get_tv_string(&argvars[1]);
- if (argvars[2].v_type != VAR_UNKNOWN)
- prepend = get_tv_string_buf(&argvars[2], buf);
+ num = (int)tv_get_number(&argvars[0]);
+ dbpath = tv_get_string(&argvars[1]);
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ prepend = tv_get_string_buf(&argvars[2], buf);
+ }
}
- rettv->vval.v_number = cs_connection(num, dbpath, prepend);
+ rettv->vval.v_number = cs_connection(num, (char_u *)dbpath,
+ (char_u *)prepend);
}
/// "cursor(lnum, col)" function, or
@@ -8885,10 +7613,10 @@ static void f_cursor(typval_T *argvars, typval_T *rettv, FunPtr fptr)
set_curswant = false;
}
} else {
- line = get_tv_lnum(argvars);
- col = get_tv_number_chk(&argvars[1], NULL);
+ line = tv_get_lnum(argvars);
+ col = tv_get_number_chk(&argvars[1], NULL);
if (argvars[2].v_type != VAR_UNKNOWN) {
- coladd = get_tv_number_chk(&argvars[2], NULL);
+ coladd = tv_get_number_chk(&argvars[2], NULL);
}
}
if (line < 0 || col < 0
@@ -8921,10 +7649,11 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int noref = 0;
- if (argvars[1].v_type != VAR_UNKNOWN)
- noref = get_tv_number_chk(&argvars[1], NULL);
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ noref = tv_get_number_chk(&argvars[1], NULL);
+ }
if (noref < 0 || noref > 1) {
- EMSG(_(e_invarg));
+ emsgf(_(e_invarg));
} else {
var_item_copy(NULL, &argvars[0], rettv, true, (noref == 0
? get_copyID()
@@ -8935,34 +7664,32 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// "delete()" function
static void f_delete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u nbuf[NUMBUFLEN];
- char_u *name;
- char_u *flags;
-
rettv->vval.v_number = -1;
if (check_restricted() || check_secure()) {
return;
}
- name = get_tv_string(&argvars[0]);
+ const char *const name = tv_get_string(&argvars[0]);
if (name == NULL || *name == NUL) {
EMSG(_(e_invarg));
return;
}
+ char nbuf[NUMBUFLEN];
+ const char *flags;
if (argvars[1].v_type != VAR_UNKNOWN) {
- flags = get_tv_string_buf(&argvars[1], nbuf);
+ flags = tv_get_string_buf(&argvars[1], nbuf);
} else {
- flags = (char_u *)"";
+ flags = "";
}
if (*flags == NUL) {
// delete a file
- rettv->vval.v_number = os_remove((char *)name) == 0 ? 0 : -1;
- } else if (STRCMP(flags, "d") == 0) {
+ rettv->vval.v_number = os_remove(name) == 0 ? 0 : -1;
+ } else if (strcmp(flags, "d") == 0) {
// delete an empty directory
- rettv->vval.v_number = os_rmdir((char *)name) == 0 ? 0 : -1;
- } else if (STRCMP(flags, "rf") == 0) {
+ rettv->vval.v_number = os_rmdir(name) == 0 ? 0 : -1;
+ } else if (strcmp(flags, "rf") == 0) {
// delete a directory recursively
rettv->vval.v_number = delete_recursive(name);
} else {
@@ -8978,35 +7705,34 @@ static void f_dictwatcheradd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (argvars[0].v_type != VAR_DICT) {
- EMSG2(e_invarg2, "dict");
+ emsgf(_(e_invarg2), "dict");
+ return;
+ } else if (argvars[0].vval.v_dict == NULL) {
+ const char *const arg_errmsg = _("dictwatcheradd() argument");
+ const size_t arg_errmsg_len = strlen(arg_errmsg);
+ emsgf(_(e_readonlyvar), (int)arg_errmsg_len, arg_errmsg);
return;
}
if (argvars[1].v_type != VAR_STRING && argvars[1].v_type != VAR_NUMBER) {
- EMSG2(e_invarg2, "key");
+ emsgf(_(e_invarg2), "key");
return;
}
- char *key_pattern = (char *)get_tv_string_chk(argvars + 1);
- assert(key_pattern);
- const size_t key_len = STRLEN(argvars[1].vval.v_string);
-
- if (key_len == 0) {
- EMSG(_(e_emptykey));
+ const char *const key_pattern = tv_get_string_chk(argvars + 1);
+ if (key_pattern == NULL) {
return;
}
+ const size_t key_pattern_len = strlen(key_pattern);
Callback callback;
if (!callback_from_typval(&callback, &argvars[2])) {
- EMSG2(e_invarg2, "funcref");
+ emsgf(_(e_invarg2), "funcref");
return;
}
- DictWatcher *watcher = xmalloc(sizeof(DictWatcher));
- watcher->key_pattern = xmemdupz(key_pattern, key_len);
- watcher->callback = callback;
- watcher->busy = false;
- QUEUE_INSERT_TAIL(&argvars[0].vval.v_dict->watchers, &watcher->node);
+ tv_dict_watcher_add(argvars[0].vval.v_dict, key_pattern, key_pattern_len,
+ callback);
}
// dictwatcherdel(dict, key, funcref) function
@@ -9017,26 +7743,17 @@ static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (argvars[0].v_type != VAR_DICT) {
- EMSG2(e_invarg2, "dict");
- return;
- }
-
- if (argvars[1].v_type != VAR_STRING && argvars[1].v_type != VAR_NUMBER) {
- EMSG2(e_invarg2, "key");
+ emsgf(_(e_invarg2), "dict");
return;
}
if (argvars[2].v_type != VAR_FUNC && argvars[2].v_type != VAR_STRING) {
- EMSG2(e_invarg2, "funcref");
+ emsgf(_(e_invarg2), "funcref");
return;
}
- char *key_pattern = (char *)get_tv_string_chk(argvars + 1);
- assert(key_pattern);
- const size_t key_len = STRLEN(argvars[1].vval.v_string);
-
- if (key_len == 0) {
- EMSG(_(e_emptykey));
+ const char *const key_pattern = tv_get_string_chk(argvars + 1);
+ if (key_pattern == NULL) {
return;
}
@@ -9045,28 +7762,12 @@ static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- dict_T *dict = argvars[0].vval.v_dict;
- QUEUE *w = NULL;
- DictWatcher *watcher = NULL;
- bool matched = false;
- QUEUE_FOREACH(w, &dict->watchers) {
- watcher = dictwatcher_node_data(w);
- if (callback_equal(&watcher->callback, &callback)
- && !strcmp(watcher->key_pattern, key_pattern)) {
- matched = true;
- break;
- }
- }
-
- callback_free(&callback);
-
- if (!matched) {
+ if (!tv_dict_watcher_remove(argvars[0].vval.v_dict, key_pattern,
+ strlen(key_pattern), callback)) {
EMSG("Couldn't find a watcher matching key and callback");
- return;
}
- QUEUE_REMOVE(w);
- dictwatcher_free(watcher);
+ callback_free(&callback);
}
/*
@@ -9082,7 +7783,7 @@ static void f_did_filetype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_diff_filler(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
+ rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
}
/*
@@ -9090,7 +7791,7 @@ static void f_diff_filler(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_diff_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T lnum = get_tv_lnum(argvars);
+ linenr_T lnum = tv_get_lnum(argvars);
static linenr_T prev_lnum = 0;
static int changedtick = 0;
static int fnum = 0;
@@ -9125,11 +7826,12 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (hlID == HLF_CHD || hlID == HLF_TXD) {
- col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
- if (col >= change_start && col <= change_end)
- hlID = HLF_TXD; /* changed text */
- else
- hlID = HLF_CHD; /* changed line */
+ col = tv_get_number(&argvars[1]) - 1; // Ignore type error in {col}.
+ if (col >= change_start && col <= change_end) {
+ hlID = HLF_TXD; // Changed text.
+ } else {
+ hlID = HLF_CHD; // Changed line.
+ }
}
rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
}
@@ -9180,10 +7882,11 @@ static void f_empty(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_escape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u buf[NUMBUFLEN];
+ char buf[NUMBUFLEN];
- rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
- get_tv_string_buf(&argvars[1], buf));
+ rettv->vval.v_string = vim_strsave_escaped(
+ (const char_u *)tv_get_string(&argvars[0]),
+ (const char_u *)tv_get_string_buf(&argvars[1], buf));
rettv->v_type = VAR_STRING;
}
@@ -9192,16 +7895,15 @@ static void f_escape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_eval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *s;
-
- s = get_tv_string_chk(&argvars[0]);
- if (s != NULL)
- s = skipwhite(s);
+ const char *s = tv_get_string_chk(&argvars[0]);
+ if (s != NULL) {
+ s = (const char *)skipwhite((const char_u *)s);
+ }
- char_u *p = s;
- if (s == NULL || eval1(&s, rettv, TRUE) == FAIL) {
- if (p != NULL && !aborting()) {
- EMSG2(_(e_invexpr2), p);
+ const char *const expr_start = s;
+ if (s == NULL || eval1((char_u **)&s, rettv, true) == FAIL) {
+ if (expr_start != NULL && !aborting()) {
+ EMSG2(_(e_invexpr2), expr_start);
}
need_clr_eos = FALSE;
rettv->v_type = VAR_NUMBER;
@@ -9224,91 +7926,92 @@ static void f_eventhandler(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_executable(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *name = get_tv_string(&argvars[0]);
+ const char *name = tv_get_string(&argvars[0]);
// Check in $PATH and also check directly if there is a directory name
- rettv->vval.v_number = os_can_exe(name, NULL, true)
- || (gettail_dir(name) != name && os_can_exe(name, NULL, false));
+ rettv->vval.v_number = (
+ os_can_exe((const char_u *)name, NULL, true)
+ || (gettail_dir(name) != name
+ && os_can_exe((const char_u *)name, NULL, false)));
}
-static char_u * get_list_line(int c, void *cookie, int indent)
+static char_u *get_list_line(int c, void *cookie, int indent)
{
- listitem_T **p = (listitem_T **)cookie;
- listitem_T *item = *p;
- char_u buf[NUMBUFLEN];
- char_u *s;
+ const listitem_T **const p = (const listitem_T **)cookie;
+ const listitem_T *item = *p;
if (item == NULL) {
return NULL;
}
- s = get_tv_string_buf_chk(&item->li_tv, buf);
+ char buf[NUMBUFLEN];
+ const char *const s = tv_get_string_buf_chk(&item->li_tv, buf);
*p = item->li_next;
- return s == NULL ? NULL : vim_strsave(s);
+ return (char_u *)(s == NULL ? NULL : xstrdup(s));
}
// "execute(command)" function
static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int save_msg_silent = msg_silent;
- int save_emsg_silent = emsg_silent;
- bool save_emsg_noredir = emsg_noredir;
- garray_T *save_capture_ga = capture_ga;
+ const int save_msg_silent = msg_silent;
+ const int save_emsg_silent = emsg_silent;
+ const bool save_emsg_noredir = emsg_noredir;
+ garray_T *const save_capture_ga = capture_ga;
- if (check_secure()) {
- return;
- }
+ if (check_secure()) {
+ return;
+ }
- if (argvars[1].v_type != VAR_UNKNOWN) {
- char_u buf[NUMBUFLEN];
- char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ char buf[NUMBUFLEN];
+ const char *const s = tv_get_string_buf_chk(&argvars[1], buf);
- if (s == NULL) {
- return;
- }
- if (STRNCMP(s, "silent", 6) == 0) {
- msg_silent++;
- }
- if (STRCMP(s, "silent!") == 0) {
- emsg_silent = true;
- emsg_noredir = true;
- }
- } else {
+ if (s == NULL) {
+ return;
+ }
+ if (strncmp(s, "silent", 6) == 0) {
msg_silent++;
}
-
- garray_T capture_local;
- ga_init(&capture_local, (int)sizeof(char), 80);
- capture_ga = &capture_local;
-
- if (argvars[0].v_type != VAR_LIST) {
- do_cmdline_cmd((char *)get_tv_string(&argvars[0]));
- } else if (argvars[0].vval.v_list != NULL) {
- list_T *list = argvars[0].vval.v_list;
- list->lv_refcount++;
- listitem_T *item = list->lv_first;
- do_cmdline(NULL, get_list_line, (void *)&item,
- DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
- list->lv_refcount--;
+ if (strcmp(s, "silent!") == 0) {
+ emsg_silent = true;
+ emsg_noredir = true;
}
- msg_silent = save_msg_silent;
- emsg_silent = save_emsg_silent;
- emsg_noredir = save_emsg_noredir;
+ } else {
+ msg_silent++;
+ }
- ga_append(capture_ga, NUL);
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = vim_strsave(capture_ga->ga_data);
- ga_clear(capture_ga);
+ garray_T capture_local;
+ ga_init(&capture_local, (int)sizeof(char), 80);
+ capture_ga = &capture_local;
- capture_ga = save_capture_ga;
+ if (argvars[0].v_type != VAR_LIST) {
+ do_cmdline_cmd(tv_get_string(&argvars[0]));
+ } else if (argvars[0].vval.v_list != NULL) {
+ list_T *const list = argvars[0].vval.v_list;
+ list->lv_refcount++;
+ listitem_T *const item = list->lv_first;
+ do_cmdline(NULL, get_list_line, (void *)&item,
+ DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
+ list->lv_refcount--;
+ }
+ msg_silent = save_msg_silent;
+ emsg_silent = save_emsg_silent;
+ emsg_noredir = save_emsg_noredir;
+
+ ga_append(capture_ga, NUL);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_strsave(capture_ga->ga_data);
+ ga_clear(capture_ga);
+
+ capture_ga = save_capture_ga;
}
/// "exepath()" function
static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *arg = get_tv_string(&argvars[0]);
+ const char *arg = tv_get_string(&argvars[0]);
char_u *path = NULL;
- (void)os_can_exe(arg, &path, true);
+ (void)os_can_exe((const char_u *)arg, &path, true);
rettv->v_type = VAR_STRING;
rettv->vval.v_string = path;
@@ -9322,21 +8025,21 @@ static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int n = false;
int len = 0;
- char *p = (char *)get_tv_string(&argvars[0]);
+ const char *p = tv_get_string(&argvars[0]);
if (*p == '$') { // Environment variable.
// First try "normal" environment variables (fast).
if (os_getenv(p + 1) != NULL) {
n = true;
} else {
// Try expanding things like $VIM and ${HOME}.
- p = (char *)expand_env_save((char_u *)p);
- if (p != NULL && *p != '$') {
+ char_u *const exp = expand_env_save((char_u *)p);
+ if (exp != NULL && *exp != '$') {
n = true;
}
- xfree(p);
+ xfree(exp);
}
} else if (*p == '&' || *p == '+') { // Option.
- n = (get_option_tv((const char **)&p, NULL, true) == OK);
+ n = (get_option_tv(&p, NULL, true) == OK);
if (*skipwhite((const char_u *)p) != NUL) {
n = false; // Trailing garbage.
}
@@ -9364,9 +8067,9 @@ static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
n = (get_var_tv(name, len, &tv, NULL, false, true) == OK);
if (n) {
// Handle d.key, l[idx], f(expr).
- n = (handle_subscript((const char **)&p, &tv, true, false) == OK);
+ n = (handle_subscript(&p, &tv, true, false) == OK);
if (n) {
- clear_tv(&tv);
+ tv_clear(&tv);
}
}
}
@@ -9384,32 +8087,31 @@ static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *s;
size_t len;
char_u *errormsg;
int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
expand_T xpc;
- int error = FALSE;
- char_u *result;
+ bool error = false;
+ char_u *result;
rettv->v_type = VAR_STRING;
if (argvars[1].v_type != VAR_UNKNOWN
&& argvars[2].v_type != VAR_UNKNOWN
- && get_tv_number_chk(&argvars[2], &error)
+ && tv_get_number_chk(&argvars[2], &error)
&& !error) {
rettv->v_type = VAR_LIST;
rettv->vval.v_list = NULL;
}
- s = get_tv_string(&argvars[0]);
+ const char *s = tv_get_string(&argvars[0]);
if (*s == '%' || *s == '#' || *s == '<') {
- ++emsg_off;
- result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
- --emsg_off;
+ emsg_off++;
+ result = eval_vars((char_u *)s, (char_u *)s, &len, NULL, &errormsg, NULL);
+ emsg_off--;
if (rettv->v_type == VAR_LIST) {
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
if (result != NULL) {
- list_append_string(rettv->vval.v_list, result, -1);
+ tv_list_append_string(rettv->vval.v_list, (const char *)result, -1);
}
} else
rettv->vval.v_string = result;
@@ -9417,93 +8119,29 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/* When the optional second argument is non-zero, don't remove matches
* for 'wildignore' and don't put matches for 'suffixes' at the end. */
if (argvars[1].v_type != VAR_UNKNOWN
- && get_tv_number_chk(&argvars[1], &error))
+ && tv_get_number_chk(&argvars[1], &error)) {
options |= WILD_KEEP_ALL;
+ }
if (!error) {
ExpandInit(&xpc);
xpc.xp_context = EXPAND_FILES;
- if (p_wic)
+ if (p_wic) {
options += WILD_ICASE;
- if (rettv->v_type == VAR_STRING)
- rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
- options, WILD_ALL);
- else {
- rettv_list_alloc(rettv);
- ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
+ }
+ if (rettv->v_type == VAR_STRING) {
+ rettv->vval.v_string = ExpandOne(&xpc, (char_u *)s, NULL, options,
+ WILD_ALL);
+ } else {
+ tv_list_alloc_ret(rettv);
+ ExpandOne(&xpc, (char_u *)s, NULL, options, WILD_ALL_KEEP);
for (int i = 0; i < xpc.xp_numfiles; i++) {
- list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
+ tv_list_append_string(rettv->vval.v_list,
+ (const char *)xpc.xp_files[i], -1);
}
ExpandCleanup(&xpc);
}
- } else
+ } else {
rettv->vval.v_string = NULL;
- }
-}
-
-/*
- * Go over all entries in "d2" and add them to "d1".
- * When "action" is "error" then a duplicate key is an error.
- * When "action" is "force" then a duplicate key is overwritten.
- * Otherwise duplicate keys are ignored ("action" is "keep").
- */
-void dict_extend(dict_T *d1, dict_T *d2, char_u *action)
-{
- dictitem_T *di1;
- hashitem_T *hi2;
- int todo;
- bool watched = is_watched(d1);
- const char *const arg_errmsg = _("extend() argument");
- const size_t arg_errmsg_len = strlen(arg_errmsg);
-
- todo = (int)d2->dv_hashtab.ht_used;
- for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2) {
- if (!HASHITEM_EMPTY(hi2)) {
- --todo;
- di1 = dict_find(d1, hi2->hi_key, -1);
- if (d1->dv_scope != 0) {
- /* Disallow replacing a builtin function in l: and g:.
- * Check the key to be valid when adding to any
- * scope. */
- if (d1->dv_scope == VAR_DEF_SCOPE
- && HI2DI(hi2)->di_tv.v_type == VAR_FUNC
- && var_check_func_name(hi2->hi_key,
- di1 == NULL))
- break;
- if (!valid_varname(hi2->hi_key))
- break;
- }
- if (di1 == NULL) {
- di1 = dictitem_copy(HI2DI(hi2));
- if (dict_add(d1, di1) == FAIL) {
- dictitem_free(di1);
- }
-
- if (watched) {
- dictwatcher_notify(d1, (char *)di1->di_key, &di1->di_tv, NULL);
- }
- } else if (*action == 'e') {
- EMSG2(_("E737: Key already exists: %s"), hi2->hi_key);
- break;
- } else if (*action == 'f' && HI2DI(hi2) != di1) {
- typval_T oldtv;
-
- if (tv_check_lock(di1->di_tv.v_lock, arg_errmsg, arg_errmsg_len)
- || var_check_ro(di1->di_flags, arg_errmsg, arg_errmsg_len)) {
- break;
- }
-
- if (watched) {
- copy_tv(&di1->di_tv, &oldtv);
- }
-
- clear_tv(&di1->di_tv);
- copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv);
-
- if (watched) {
- dictwatcher_notify(d1, (char *)di1->di_key, &di1->di_tv, &oldtv);
- clear_tv(&oldtv);
- }
- }
}
}
}
@@ -9518,24 +8156,30 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const size_t arg_errmsg_len = strlen(arg_errmsg);
if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) {
- list_T *l1, *l2;
- listitem_T *item;
long before;
- int error = FALSE;
-
- l1 = argvars[0].vval.v_list;
- l2 = argvars[1].vval.v_list;
- if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, arg_errmsg_len)
- && l2 != NULL) {
+ bool error = false;
+
+ list_T *const l1 = argvars[0].vval.v_list;
+ list_T *const l2 = argvars[1].vval.v_list;
+ if (l1 == NULL) {
+ const bool locked = tv_check_lock(VAR_FIXED, arg_errmsg, arg_errmsg_len);
+ (void)locked;
+ assert(locked == true);
+ } else if (l2 == NULL) {
+ // Do nothing
+ tv_copy(&argvars[0], rettv);
+ } else if (!tv_check_lock(l1->lv_lock, arg_errmsg, arg_errmsg_len)) {
+ listitem_T *item;
if (argvars[2].v_type != VAR_UNKNOWN) {
- before = get_tv_number_chk(&argvars[2], &error);
- if (error)
- return; /* type error; errmsg already given */
+ before = tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ return; // Type error; errmsg already given.
+ }
- if (before == l1->lv_len)
+ if (before == l1->lv_len) {
item = NULL;
- else {
- item = list_find(l1, before);
+ } else {
+ item = tv_list_find(l1, before);
if (item == NULL) {
EMSGN(_(e_listidx), before);
return;
@@ -9543,43 +8187,50 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
} else
item = NULL;
- list_extend(l1, l2, item);
+ tv_list_extend(l1, l2, item);
- copy_tv(&argvars[0], rettv);
+ tv_copy(&argvars[0], rettv);
}
} else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type ==
VAR_DICT) {
- dict_T *d1, *d2;
- char_u *action;
- int i;
-
- d1 = argvars[0].vval.v_dict;
- d2 = argvars[1].vval.v_dict;
- if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, arg_errmsg_len)
- && d2 != NULL) {
- /* Check the third argument. */
+ dict_T *const d1 = argvars[0].vval.v_dict;
+ dict_T *const d2 = argvars[1].vval.v_dict;
+ if (d1 == NULL) {
+ const bool locked = tv_check_lock(VAR_FIXED, arg_errmsg, arg_errmsg_len);
+ (void)locked;
+ assert(locked == true);
+ } else if (d2 == NULL) {
+ // Do nothing
+ tv_copy(&argvars[0], rettv);
+ } else if (!tv_check_lock(d1->dv_lock, arg_errmsg, arg_errmsg_len)) {
+ const char *action = "force";
+ // Check the third argument.
if (argvars[2].v_type != VAR_UNKNOWN) {
- static char *(av[]) = {"keep", "force", "error"};
+ const char *const av[] = { "keep", "force", "error" };
- action = get_tv_string_chk(&argvars[2]);
- if (action == NULL)
- return; /* type error; errmsg already given */
- for (i = 0; i < 3; ++i)
- if (STRCMP(action, av[i]) == 0)
+ action = tv_get_string_chk(&argvars[2]);
+ if (action == NULL) {
+ return; // Type error; error message already given.
+ }
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(av); i++) {
+ if (strcmp(action, av[i]) == 0) {
break;
+ }
+ }
if (i == 3) {
EMSG2(_(e_invarg2), action);
return;
}
- } else
- action = (char_u *)"force";
+ }
- dict_extend(d1, d2, action);
+ tv_dict_extend(d1, d2, action);
- copy_tv(&argvars[0], rettv);
+ tv_copy(&argvars[0], rettv);
}
- } else
+ } else {
EMSG2(_(e_listdictarg), "extend()");
+ }
}
/*
@@ -9587,19 +8238,18 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_feedkeys(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *keys, *flags = NULL;
- char_u nbuf[NUMBUFLEN];
-
- /* This is not allowed in the sandbox. If the commands would still be
- * executed in the sandbox it would be OK, but it probably happens later,
- * when "sandbox" is no longer set. */
- if (check_secure())
+ // This is not allowed in the sandbox. If the commands would still be
+ // executed in the sandbox it would be OK, but it probably happens later,
+ // when "sandbox" is no longer set.
+ if (check_secure()) {
return;
+ }
- keys = get_tv_string(&argvars[0]);
-
+ const char *const keys = tv_get_string(&argvars[0]);
+ char nbuf[NUMBUFLEN];
+ const char *flags = NULL;
if (argvars[1].v_type != VAR_UNKNOWN) {
- flags = get_tv_string_buf(&argvars[1], nbuf);
+ flags = tv_get_string_buf(&argvars[1], nbuf);
}
nvim_feedkeys(cstr_as_string((char *)keys),
@@ -9609,9 +8259,9 @@ static void f_feedkeys(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "filereadable()" function
static void f_filereadable(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *p = get_tv_string(&argvars[0]);
+ const char *const p = tv_get_string(&argvars[0]);
rettv->vval.v_number =
- (*p && !os_isdir(p) && os_file_is_readable((char*)p));
+ (*p && !os_isdir((const char_u *)p) && os_file_is_readable(p));
}
/*
@@ -9620,60 +8270,60 @@ static void f_filereadable(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_filewritable(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char *filename = (char *)get_tv_string(&argvars[0]);
+ const char *filename = tv_get_string(&argvars[0]);
rettv->vval.v_number = os_file_is_writable(filename);
}
static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
{
- char_u *fname;
- char_u *fresult = NULL;
- char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
- char_u *p;
- char_u pathbuf[NUMBUFLEN];
+ char_u *fresult = NULL;
+ char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
int count = 1;
- int first = TRUE;
- int error = FALSE;
+ bool first = true;
+ bool error = false;
rettv->vval.v_string = NULL;
rettv->v_type = VAR_STRING;
- fname = get_tv_string(&argvars[0]);
+ const char *fname = tv_get_string(&argvars[0]);
+ char pathbuf[NUMBUFLEN];
if (argvars[1].v_type != VAR_UNKNOWN) {
- p = get_tv_string_buf_chk(&argvars[1], pathbuf);
- if (p == NULL)
- error = TRUE;
- else {
- if (*p != NUL)
- path = p;
+ const char *p = tv_get_string_buf_chk(&argvars[1], pathbuf);
+ if (p == NULL) {
+ error = true;
+ } else {
+ if (*p != NUL) {
+ path = (char_u *)p;
+ }
- if (argvars[2].v_type != VAR_UNKNOWN)
- count = get_tv_number_chk(&argvars[2], &error);
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ count = tv_get_number_chk(&argvars[2], &error);
+ }
}
}
if (count < 0) {
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
}
if (*fname != NUL && !error) {
do {
if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
xfree(fresult);
- fresult = find_file_in_path_option(first ? fname : NULL,
- first ? STRLEN(fname) : 0,
+ fresult = find_file_in_path_option(first ? (char_u *)fname : NULL,
+ first ? strlen(fname) : 0,
0, first, path,
find_what, curbuf->b_ffname,
(find_what == FINDFILE_DIR
? (char_u *)""
: curbuf->b_p_sua));
- first = FALSE;
-
- if (fresult != NULL && rettv->v_type == VAR_LIST)
- list_append_string(rettv->vval.v_list, fresult, -1);
+ first = false;
+ if (fresult != NULL && rettv->v_type == VAR_LIST) {
+ tv_list_append_string(rettv->vval.v_list, (const char *)fresult, -1);
+ }
} while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
}
@@ -9744,7 +8394,7 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
if (!HASHITEM_EMPTY(hi)) {
--todo;
- di = HI2DI(hi);
+ di = TV_DICT_HI2DI(hi);
if (map
&& (tv_check_lock(di->di_tv.v_lock, arg_errmsg, arg_errmsg_len)
|| var_check_ro(di->di_flags, arg_errmsg, arg_errmsg_len))) {
@@ -9753,15 +8403,16 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
vimvars[VV_KEY].vv_str = vim_strsave(di->di_key);
int r = filter_map_one(&di->di_tv, expr, map, &rem);
- clear_tv(&vimvars[VV_KEY].vv_tv);
- if (r == FAIL || did_emsg)
+ tv_clear(&vimvars[VV_KEY].vv_tv);
+ if (r == FAIL || did_emsg) {
break;
+ }
if (!map && rem) {
if (var_check_fixed(di->di_flags, arg_errmsg, arg_errmsg_len)
|| var_check_ro(di->di_flags, arg_errmsg, arg_errmsg_len)) {
break;
}
- dictitem_remove(d, di);
+ tv_dict_item_remove(d, di);
}
}
}
@@ -9779,9 +8430,10 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL
|| did_emsg)
break;
- if (!map && rem)
- listitem_remove(l, li);
- ++idx;
+ if (!map && rem) {
+ tv_list_item_remove(l, li);
+ }
+ idx++;
}
}
@@ -9791,23 +8443,21 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
did_emsg |= save_did_emsg;
}
- copy_tv(&argvars[0], rettv);
+ tv_copy(&argvars[0], rettv);
}
static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
{
typval_T rettv;
typval_T argv[3];
- char_u buf[NUMBUFLEN];
- char_u *s;
int retval = FAIL;
int dummy;
- copy_tv(tv, &vimvars[VV_VAL].vv_tv);
+ tv_copy(tv, &vimvars[VV_VAL].vv_tv);
argv[0] = vimvars[VV_KEY].vv_tv;
argv[1] = vimvars[VV_VAL].vv_tv;
if (expr->v_type == VAR_FUNC) {
- s = expr->vval.v_string;
+ const char_u *const s = expr->vval.v_string;
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
0L, 0L, &dummy, true, NULL, NULL) == FAIL) {
goto theend;
@@ -9815,45 +8465,47 @@ static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
} else if (expr->v_type == VAR_PARTIAL) {
partial_T *partial = expr->vval.v_partial;
- s = partial_name(partial);
+ const char_u *const s = partial_name(partial);
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
0L, 0L, &dummy, true, partial, NULL) == FAIL) {
goto theend;
}
} else {
- s = get_tv_string_buf_chk(expr, buf);
+ char buf[NUMBUFLEN];
+ const char *s = tv_get_string_buf_chk(expr, buf);
if (s == NULL) {
goto theend;
}
- s = skipwhite(s);
- if (eval1(&s, &rettv, true) == FAIL) {
+ s = (const char *)skipwhite((const char_u *)s);
+ if (eval1((char_u **)&s, &rettv, true) == FAIL) {
goto theend;
}
if (*s != NUL) { // check for trailing chars after expr
- EMSG2(_(e_invexpr2), s);
+ emsgf(_(e_invexpr2), s);
goto theend;
}
}
if (map) {
- /* map(): replace the list item value */
- clear_tv(tv);
+ // map(): replace the list item value.
+ tv_clear(tv);
rettv.v_lock = 0;
*tv = rettv;
} else {
- int error = FALSE;
-
- /* filter(): when expr is zero remove the item */
- *remp = (get_tv_number_chk(&rettv, &error) == 0);
- clear_tv(&rettv);
- /* On type error, nothing has been removed; return FAIL to stop the
- * loop. The error message was given by get_tv_number_chk(). */
- if (error)
+ bool error = false;
+
+ // filter(): when expr is zero remove the item
+ *remp = (tv_get_number_chk(&rettv, &error) == 0);
+ tv_clear(&rettv);
+ // On type error, nothing has been removed; return FAIL to stop the
+ // loop. The error message was given by tv_get_number_chk().
+ if (error) {
goto theend;
+ }
}
retval = OK;
theend:
- clear_tv(&vimvars[VV_VAL].vv_tv);
+ tv_clear(&vimvars[VV_VAL].vv_tv);
return retval;
}
@@ -9888,13 +8540,14 @@ static void f_float2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
float_T f;
- if (get_float_arg(argvars, &f) == OK) {
- if (f < -0x7fffffff)
- rettv->vval.v_number = -0x7fffffff;
- else if (f > 0x7fffffff)
- rettv->vval.v_number = 0x7fffffff;
- else
+ if (tv_get_float_chk(argvars, &f)) {
+ if (f < VARNUMBER_MIN) {
+ rettv->vval.v_number = VARNUMBER_MIN;
+ } else if (f > VARNUMBER_MAX) {
+ rettv->vval.v_number = VARNUMBER_MAX;
+ } else {
rettv->vval.v_number = (varnumber_T)f;
+ }
}
}
@@ -9903,14 +8556,15 @@ static void f_float2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_fmod(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- float_T fx, fy;
+ float_T fx;
+ float_T fy;
rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &fx) == OK
- && get_float_arg(&argvars[1], &fy) == OK)
+ if (tv_get_float_chk(argvars, &fx) && tv_get_float_chk(&argvars[1], &fy)) {
rettv->vval.v_float = fmod(fx, fy);
- else
+ } else {
rettv->vval.v_float = 0.0;
+ }
}
/*
@@ -9918,8 +8572,8 @@ static void f_fmod(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_fnameescape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_string = vim_strsave_fnameescape(
- get_tv_string(&argvars[0]), FALSE);
+ rettv->vval.v_string = (char_u *)vim_strsave_fnameescape(
+ tv_get_string(&argvars[0]), false);
rettv->v_type = VAR_STRING;
}
@@ -9928,27 +8582,26 @@ static void f_fnameescape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *fname;
- char_u *mods;
- size_t usedlen = 0;
+ char_u *fbuf = NULL;
size_t len;
- char_u *fbuf = NULL;
- char_u buf[NUMBUFLEN];
-
- fname = get_tv_string_chk(&argvars[0]);
- mods = get_tv_string_buf_chk(&argvars[1], buf);
- if (fname == NULL || mods == NULL)
+ char buf[NUMBUFLEN];
+ const char *fname = tv_get_string_chk(&argvars[0]);
+ const char *const mods = tv_get_string_buf_chk(&argvars[1], buf);
+ if (fname == NULL || mods == NULL) {
fname = NULL;
- else {
- len = STRLEN(fname);
- (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
+ } else {
+ len = strlen(fname);
+ size_t usedlen = 0;
+ (void)modify_fname((char_u *)mods, &usedlen, (char_u **)&fname, &fbuf,
+ &len);
}
rettv->v_type = VAR_STRING;
- if (fname == NULL)
+ if (fname == NULL) {
rettv->vval.v_string = NULL;
- else
- rettv->vval.v_string = vim_strnsave(fname, len);
+ } else {
+ rettv->vval.v_string = (char_u *)xmemdupz(fname, len);
+ }
xfree(fbuf);
}
@@ -9958,16 +8611,16 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end)
{
- linenr_T lnum;
- linenr_T first, last;
-
- lnum = get_tv_lnum(argvars);
+ const linenr_T lnum = tv_get_lnum(argvars);
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
- if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL)) {
- if (end)
+ linenr_T first;
+ linenr_T last;
+ if (hasFoldingWin(curwin, lnum, &first, &last, false, NULL)) {
+ if (end) {
rettv->vval.v_number = (varnumber_T)last;
- else
+ } else {
rettv->vval.v_number = (varnumber_T)first;
+ }
return;
}
}
@@ -9995,11 +8648,10 @@ static void f_foldclosedend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_foldlevel(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T lnum;
-
- lnum = get_tv_lnum(argvars);
- if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
+ const linenr_T lnum = tv_get_lnum(argvars);
+ if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
rettv->vval.v_number = foldLevel(lnum);
+ }
}
/*
@@ -10063,7 +8715,6 @@ static void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T lnum;
char_u *text;
char_u buf[51];
foldinfo_T foldinfo;
@@ -10071,10 +8722,11 @@ static void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
- lnum = get_tv_lnum(argvars);
- /* treat illegal types and illegal string values for {lnum} the same */
- if (lnum < 0)
+ linenr_T lnum = tv_get_lnum(argvars);
+ // Treat illegal types and illegal string values for {lnum} the same.
+ if (lnum < 0) {
lnum = 0;
+ }
fold_count = foldedCount(curwin, lnum, &foldinfo);
if (fold_count > 0) {
text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
@@ -10111,7 +8763,7 @@ static void common_function(typval_T *argvars, typval_T *rettv,
s = partial_name(arg_pt);
} else {
// function('MyFunc', [arg], dict)
- s = get_tv_string(&argvars[0]);
+ s = (char_u *)tv_get_string(&argvars[0]);
use_string = true;
}
@@ -10126,7 +8778,9 @@ static void common_function(typval_T *argvars, typval_T *rettv,
}
if (s == NULL || *s == NUL || (use_string && ascii_isdigit(*s))
|| (is_funcref && trans_name == NULL)) {
- EMSG2(_(e_invarg2), use_string ? get_tv_string(&argvars[0]) : s);
+ emsgf(_(e_invarg2), (use_string
+ ? tv_get_string(&argvars[0])
+ : (const char *)s));
// Don't check an autoload name for existence here.
} else if (trans_name != NULL
&& (is_funcref ? find_func(trans_name) == NULL
@@ -10207,13 +8861,13 @@ static void common_function(typval_T *argvars, typval_T *rettv,
}
int i = 0;
for (; i < arg_len; i++) {
- copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
+ tv_copy(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
}
if (lv_len > 0) {
for (listitem_T *li = list->lv_first;
li != NULL;
li = li->li_next) {
- copy_tv(&li->li_tv, &pt->pt_argv[i++]);
+ tv_copy(&li->li_tv, &pt->pt_argv[i++]);
}
}
}
@@ -10274,12 +8928,13 @@ static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "garbagecollect()" function
static void f_garbagecollect(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- /* This is postponed until we are back at the toplevel, because we may be
- * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
- want_garbage_collect = TRUE;
+ // This is postponed until we are back at the toplevel, because we may be
+ // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
+ want_garbage_collect = true;
- if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
- garbage_collect_at_exit = TRUE;
+ if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1) {
+ garbage_collect_at_exit = true;
+ }
}
/*
@@ -10295,20 +8950,21 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[0].v_type == VAR_LIST) {
if ((l = argvars[0].vval.v_list) != NULL) {
- int error = FALSE;
+ bool error = false;
- li = list_find(l, get_tv_number_chk(&argvars[1], &error));
- if (!error && li != NULL)
+ li = tv_list_find(l, tv_get_number_chk(&argvars[1], &error));
+ if (!error && li != NULL) {
tv = &li->li_tv;
+ }
}
} else if (argvars[0].v_type == VAR_DICT) {
if ((d = argvars[0].vval.v_dict) != NULL) {
- di = dict_find(d, get_tv_string(&argvars[1]), -1);
- if (di != NULL)
+ di = tv_dict_find(d, tv_get_string(&argvars[1]), -1);
+ if (di != NULL) {
tv = &di->di_tv;
+ }
}
- } else if (argvars[0].v_type == VAR_PARTIAL
- || argvars[0].v_type == VAR_FUNC) {
+ } else if (tv_is_func(argvars[0])) {
partial_T *pt;
partial_T fref_pt;
@@ -10321,33 +8977,30 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (pt != NULL) {
- char_u *what = get_tv_string(&argvars[1]);
- char_u *n;
+ const char *const what = tv_get_string(&argvars[1]);
- if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0) {
+ if (strcmp(what, "func") == 0 || strcmp(what, "name") == 0) {
rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
- n = partial_name(pt);
+ const char *const n = (const char *)partial_name(pt);
if (n == NULL) {
rettv->vval.v_string = NULL;
} else {
- rettv->vval.v_string = vim_strsave(n);
+ rettv->vval.v_string = (char_u *)xstrdup(n);
if (rettv->v_type == VAR_FUNC) {
func_ref(rettv->vval.v_string);
}
}
- } else if (STRCMP(what, "dict") == 0) {
+ } else if (strcmp(what, "dict") == 0) {
rettv->v_type = VAR_DICT;
rettv->vval.v_dict = pt->pt_dict;
if (pt->pt_dict != NULL) {
(pt->pt_dict->dv_refcount)++;
}
- } else if (STRCMP(what, "args") == 0) {
+ } else if (strcmp(what, "args") == 0) {
rettv->v_type = VAR_LIST;
- if (rettv_list_alloc(rettv) != NULL) {
- int i;
-
- for (i = 0; i < pt->pt_argc; i++) {
- list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
+ if (tv_list_alloc_ret(rettv) != NULL) {
+ for (int i = 0; i < pt->pt_argc; i++) {
+ tv_list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
}
}
} else {
@@ -10360,60 +9013,62 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (tv == NULL) {
- if (argvars[2].v_type != VAR_UNKNOWN)
- copy_tv(&argvars[2], rettv);
- } else
- copy_tv(tv, rettv);
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ tv_copy(&argvars[2], rettv);
+ }
+ } else {
+ tv_copy(tv, rettv);
+ }
}
/// Returns information about signs placed in a buffer as list of dicts.
static void get_buffer_signs(buf_T *buf, list_T *l)
{
for (signlist_T *sign = buf->b_signlist; sign; sign = sign->next) {
- dict_T *d = dict_alloc();
+ dict_T *const d = tv_dict_alloc();
- dict_add_nr_str(d, "id", sign->id, NULL);
- dict_add_nr_str(d, "lnum", sign->lnum, NULL);
- dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr));
+ tv_dict_add_nr(d, S_LEN("id"), sign->id);
+ tv_dict_add_nr(d, S_LEN("lnum"), sign->lnum);
+ tv_dict_add_str(d, S_LEN("name"),
+ (const char *)sign_typenr2name(sign->typenr));
- list_append_dict(l, d);
+ tv_list_append_dict(l, d);
}
}
/// Returns buffer options, variables and other attributes in a dictionary.
static dict_T *get_buffer_info(buf_T *buf)
{
- dict_T *dict = dict_alloc();
-
- dict_add_nr_str(dict, "bufnr", buf->b_fnum, NULL);
- dict_add_nr_str(dict, "name", 0L,
- buf->b_ffname != NULL ? buf->b_ffname : (char_u *)"");
- dict_add_nr_str(dict, "lnum", buflist_findlnum(buf), NULL);
- dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
- dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL);
- dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
- dict_add_nr_str(dict, "changedtick", buf->b_changedtick, NULL);
- dict_add_nr_str(dict, "hidden",
- buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
- NULL);
+ dict_T *const dict = tv_dict_alloc();
+
+ tv_dict_add_nr(dict, S_LEN("bufnr"), buf->b_fnum);
+ tv_dict_add_str(dict, S_LEN("name"),
+ buf->b_ffname != NULL ? (const char *)buf->b_ffname : "");
+ tv_dict_add_nr(dict, S_LEN("lnum"), buflist_findlnum(buf));
+ tv_dict_add_nr(dict, S_LEN("loaded"), buf->b_ml.ml_mfp != NULL);
+ tv_dict_add_nr(dict, S_LEN("listed"), buf->b_p_bl);
+ tv_dict_add_nr(dict, S_LEN("changed"), bufIsChanged(buf));
+ tv_dict_add_nr(dict, S_LEN("changedtick"), buf->b_changedtick);
+ tv_dict_add_nr(dict, S_LEN("hidden"),
+ buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
// Get a reference to buffer variables
- dict_add_dict(dict, "variables", buf->b_vars);
+ tv_dict_add_dict(dict, S_LEN("variables"), buf->b_vars);
// List of windows displaying this buffer
- list_T *windows = list_alloc();
+ list_T *const windows = tv_list_alloc();
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == buf) {
- list_append_number(windows, (varnumber_T)wp->handle);
+ tv_list_append_number(windows, (varnumber_T)wp->handle);
}
}
- dict_add_list(dict, "windows", windows);
+ tv_dict_add_list(dict, S_LEN("windows"), windows);
if (buf->b_signlist != NULL) {
// List of signs placed in this buffer
- list_T *signs = list_alloc();
+ list_T *const signs = tv_list_alloc();
get_buffer_signs(buf, signs);
- dict_add_list(dict, "signs", signs);
+ tv_dict_add_list(dict, S_LEN("signs"), signs);
}
return dict;
@@ -10427,7 +9082,7 @@ static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
bool sel_buflisted = false;
bool sel_bufloaded = false;
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
// List of all the buffers or selected buffers
if (argvars[0].v_type == VAR_DICT) {
@@ -10438,24 +9093,25 @@ static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
filtered = true;
- di = dict_find(sel_d, (char_u *)"buflisted", -1);
- if (di != NULL && get_tv_number(&di->di_tv)) {
+ di = tv_dict_find(sel_d, S_LEN("buflisted"));
+ if (di != NULL && tv_get_number(&di->di_tv)) {
sel_buflisted = true;
}
- di = dict_find(sel_d, (char_u *)"bufloaded", -1);
- if (di != NULL && get_tv_number(&di->di_tv)) {
+ di = tv_dict_find(sel_d, S_LEN("bufloaded"));
+ if (di != NULL && tv_get_number(&di->di_tv)) {
sel_bufloaded = true;
}
}
} else if (argvars[0].v_type != VAR_UNKNOWN) {
// Information about one buffer. Argument specifies the buffer
- (void)get_tv_number(&argvars[0]); // issue errmsg if type error
- emsg_off++;
- argbuf = get_buf_tv(&argvars[0], false);
- emsg_off--;
- if (argbuf == NULL) {
- return;
+ if (tv_check_num(&argvars[0])) { // issue errmsg if type error
+ emsg_off++;
+ argbuf = get_buf_tv(&argvars[0], false);
+ emsg_off--;
+ if (argbuf == NULL) {
+ return;
+ }
}
}
@@ -10469,9 +9125,9 @@ static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
continue;
}
- dict_T *d = get_buffer_info(buf);
+ dict_T *const d = get_buffer_info(buf);
if (d != NULL) {
- list_append_dict(rettv->vval.v_list, d);
+ tv_list_append_dict(rettv->vval.v_list, d);
}
if (argbuf != NULL) {
return;
@@ -10492,7 +9148,7 @@ static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retli
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
if (retlist) {
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
}
if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
@@ -10513,19 +9169,40 @@ static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retli
if (end > buf->b_ml.ml_line_count)
end = buf->b_ml.ml_line_count;
while (start <= end) {
- list_append_string(
- rettv->vval.v_list, ml_get_buf(buf, start++, FALSE), -1);
+ tv_list_append_string(rettv->vval.v_list,
+ (const char *)ml_get_buf(buf, start++, false), -1);
}
}
}
+/// Get the line number from VimL object
+///
+/// @note Unlike tv_get_lnum(), this one supports only "$" special string.
+///
+/// @param[in] tv Object to get value from. Is expected to be a number or
+/// a special string "$".
+/// @param[in] buf Buffer to take last line number from in case tv is "$". May
+/// be NULL, in this case "$" results in zero return.
+///
+/// @return Line number or 0 in case of error.
+static linenr_T tv_get_lnum_buf(const typval_T *const tv,
+ const buf_T *const buf)
+ FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (tv->v_type == VAR_STRING
+ && tv->vval.v_string != NULL
+ && tv->vval.v_string[0] == '$'
+ && buf != NULL) {
+ return buf->b_ml.ml_line_count;
+ }
+ return tv_get_number_chk(tv, NULL);
+}
+
/*
* "getbufline()" function
*/
static void f_getbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T lnum;
- linenr_T end;
buf_T *buf = NULL;
if (tv_check_str_or_nr(&argvars[0])) {
@@ -10534,12 +9211,10 @@ static void f_getbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
emsg_off--;
}
- lnum = get_tv_lnum_buf(&argvars[1], buf);
- if (argvars[2].v_type == VAR_UNKNOWN) {
- end = lnum;
- } else {
- end = get_tv_lnum_buf(&argvars[2], buf);
- }
+ const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
+ const linenr_T end = (argvars[2].v_type == VAR_UNKNOWN
+ ? lnum
+ : tv_get_lnum_buf(&argvars[2], buf));
get_buffer_lines(buf, lnum, end, true, rettv);
}
@@ -10558,7 +9233,7 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
goto f_getbufvar_end;
}
- const char *varname = (const char *)get_tv_string_chk(&argvars[1]);
+ const char *varname = tv_get_string_chk(&argvars[1]);
emsg_off++;
buf_T *const buf = get_buf_tv(&argvars[0], false);
@@ -10588,7 +9263,7 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
dictitem_T *const v = find_var_in_ht(&curbuf->b_vars->dv_hashtab, 'b',
varname, strlen(varname), false);
if (v != NULL) {
- copy_tv(&v->di_tv, rettv);
+ tv_copy(&v->di_tv, rettv);
done = true;
}
}
@@ -10601,7 +9276,7 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
f_getbufvar_end:
if (!done && argvars[2].v_type != VAR_UNKNOWN) {
// use the default value
- copy_tv(&argvars[2], rettv);
+ tv_copy(&argvars[2], rettv);
}
}
@@ -10611,7 +9286,7 @@ f_getbufvar_end:
static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
varnumber_T n;
- int error = FALSE;
+ bool error = false;
no_mapping++;
for (;; ) {
@@ -10631,7 +9306,7 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
n = safe_vgetc();
- } else if (get_tv_number_chk(&argvars[0], &error) == 1) {
+ } else if (tv_get_number_chk(&argvars[0], &error) == 1) {
// getchar(1): only check if char avail
n = vpeekc_any();
} else if (error || vpeekc_any() == NUL) {
@@ -10642,8 +9317,9 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
n = safe_vgetc();
}
- if (n == K_IGNORE)
+ if (n == K_IGNORE) {
continue;
+ }
break;
}
no_mapping--;
@@ -10713,13 +9389,13 @@ static void f_getcharmod(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_getcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv_dict_alloc(rettv);
+ tv_dict_alloc_ret(rettv);
dict_T *dict = rettv->vval.v_dict;
- dict_add_nr_str(dict, "char", 0L, last_csearch());
- dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
- dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
+ tv_dict_add_str(dict, S_LEN("char"), last_csearch());
+ tv_dict_add_nr(dict, S_LEN("forward"), last_csearch_forward());
+ tv_dict_add_nr(dict, S_LEN("until"), last_csearch_until());
}
/*
@@ -10770,7 +9446,7 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
| WILD_NO_BEEP;
if (argvars[2].v_type != VAR_UNKNOWN) {
- filtered = get_tv_number_chk(&argvars[2], NULL);
+ filtered = (bool)tv_get_number_chk(&argvars[2], NULL);
}
if (p_wic) {
@@ -10782,16 +9458,24 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
options |= WILD_KEEP_ALL;
}
+ if (argvars[0].v_type != VAR_STRING || argvars[1].v_type != VAR_STRING) {
+ EMSG(_(e_invarg));
+ return;
+ }
+
+ if (strcmp(tv_get_string(&argvars[1]), "cmdline") == 0) {
+ set_one_cmd_context(&xpc, tv_get_string(&argvars[0]));
+ xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
+ goto theend;
+ }
+
ExpandInit(&xpc);
- xpc.xp_pattern = get_tv_string(&argvars[0]);
+ xpc.xp_pattern = (char_u *)tv_get_string(&argvars[0]);
xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
- xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
+ xpc.xp_context = cmdcomplete_str_to_type(
+ (char_u *)tv_get_string(&argvars[1]));
if (xpc.xp_context == EXPAND_NOTHING) {
- if (argvars[1].v_type == VAR_STRING) {
- EMSG2(_(e_invarg2), argvars[1].vval.v_string);
- } else {
- EMSG(_(e_invarg));
- }
+ EMSG2(_(e_invarg2), argvars[1].vval.v_string);
return;
}
@@ -10801,7 +9485,7 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (xpc.xp_context == EXPAND_CSCOPE) {
- set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
+ set_context_in_cscope_cmd(&xpc, (const char *)xpc.xp_pattern, CMD_cscope);
xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
}
@@ -10810,13 +9494,15 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
}
+theend:
pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
if (pat != NULL) {
ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
for (int i = 0; i < xpc.xp_numfiles; i++) {
- list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
+ tv_list_append_string(rettv->vval.v_list, (const char *)xpc.xp_files[i],
+ -1);
}
}
xfree(pat);
@@ -10960,20 +9646,21 @@ static void f_getfontname(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_getfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *perm = NULL;
+ char *perm = NULL;
char_u flags[] = "rwx";
- char_u *filename = get_tv_string(&argvars[0]);
+ const char *filename = tv_get_string(&argvars[0]);
int32_t file_perm = os_getperm(filename);
if (file_perm >= 0) {
- perm = vim_strsave((char_u *)"---------");
+ perm = xstrdup("---------");
for (int i = 0; i < 9; i++) {
- if (file_perm & (1 << (8 - i)))
+ if (file_perm & (1 << (8 - i))) {
perm[i] = flags[i % 3];
+ }
}
}
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = perm;
+ rettv->vval.v_string = (char_u *)perm;
}
/*
@@ -10981,16 +9668,16 @@ static void f_getfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_getfsize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char *fname = (char *)get_tv_string(&argvars[0]);
+ const char *fname = tv_get_string(&argvars[0]);
rettv->v_type = VAR_NUMBER;
FileInfo file_info;
if (os_fileinfo(fname, &file_info)) {
uint64_t filesize = os_fileinfo_size(&file_info);
- if (os_isdir((char_u *)fname))
+ if (os_isdir((const char_u *)fname)) {
rettv->vval.v_number = 0;
- else {
+ } else {
rettv->vval.v_number = (varnumber_T)filesize;
/* non-perfect check for overflow */
@@ -11008,7 +9695,7 @@ static void f_getfsize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_getftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char *fname = (char *)get_tv_string(&argvars[0]);
+ const char *fname = tv_get_string(&argvars[0]);
FileInfo file_info;
if (os_fileinfo(fname, &file_info)) {
@@ -11023,15 +9710,14 @@ static void f_getftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_getftype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *fname;
char_u *type = NULL;
char *t;
- fname = get_tv_string(&argvars[0]);
+ const char *fname = tv_get_string(&argvars[0]);
rettv->v_type = VAR_STRING;
FileInfo file_info;
- if (os_fileinfo_link((char *)fname, &file_info)) {
+ if (os_fileinfo_link(fname, &file_info)) {
uint64_t mode = file_info.stat.st_mode;
#ifdef S_ISREG
if (S_ISREG(mode))
@@ -11083,10 +9769,11 @@ static void f_getftype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
default: t = "other";
}
# else
- if (os_isdir(fname))
+ if (os_isdir((const char_u *)fname)) {
t = "dir";
- else
+ } else {
t = "file";
+ }
# endif
#endif
type = vim_strsave((char_u *)t);
@@ -11099,17 +9786,16 @@ static void f_getftype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_getline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T lnum;
linenr_T end;
- int retlist;
+ bool retlist;
- lnum = get_tv_lnum(argvars);
+ const linenr_T lnum = tv_get_lnum(argvars);
if (argvars[1].v_type == VAR_UNKNOWN) {
end = 0;
- retlist = FALSE;
+ retlist = false;
} else {
- end = get_tv_lnum(&argvars[1]);
- retlist = TRUE;
+ end = tv_get_lnum(&argvars[1]);
+ retlist = true;
}
get_buffer_lines(curbuf, lnum, end, retlist, rettv);
@@ -11119,12 +9805,12 @@ static void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg,
typval_T *rettv)
{
if (what_arg->v_type == VAR_UNKNOWN) {
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
if (is_qf || wp != NULL) {
(void)get_errorlist(wp, -1, rettv->vval.v_list);
}
} else {
- rettv_dict_alloc(rettv);
+ tv_dict_alloc_ret(rettv);
if (is_qf || wp != NULL) {
if (what_arg->v_type == VAR_DICT) {
dict_T *d = what_arg->vval.v_dict;
@@ -11154,43 +9840,45 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
matchitem_T *cur = curwin->w_match_head;
int i;
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
while (cur != NULL) {
- dict_T *dict = dict_alloc();
+ dict_T *dict = tv_dict_alloc();
if (cur->match.regprog == NULL) {
// match added with matchaddpos()
for (i = 0; i < MAXPOSMATCH; ++i) {
llpos_T *llpos;
- char buf[6];
+ char buf[6];
llpos = &cur->pos.pos[i];
if (llpos->lnum == 0) {
break;
}
- list_T *l = list_alloc();
- list_append_number(l, (varnumber_T)llpos->lnum);
+ list_T *l = tv_list_alloc();
+ tv_list_append_number(l, (varnumber_T)llpos->lnum);
if (llpos->col > 0) {
- list_append_number(l, (varnumber_T)llpos->col);
- list_append_number(l, (varnumber_T)llpos->len);
+ tv_list_append_number(l, (varnumber_T)llpos->col);
+ tv_list_append_number(l, (varnumber_T)llpos->len);
}
- sprintf(buf, "pos%d", i + 1);
- dict_add_list(dict, buf, l);
+ int len = snprintf(buf, sizeof(buf), "pos%d", i + 1);
+ assert((size_t)len < sizeof(buf));
+ tv_dict_add_list(dict, buf, (size_t)len, l);
}
} else {
- dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
+ tv_dict_add_str(dict, S_LEN("pattern"), (const char *)cur->pattern);
}
- dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
- dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
- dict_add_nr_str(dict, "id", (long)cur->id, NULL);
+ tv_dict_add_str(dict, S_LEN("group"),
+ (const char *)syn_id2name(cur->hlg_id));
+ tv_dict_add_nr(dict, S_LEN("priority"), (varnumber_T)cur->priority);
+ tv_dict_add_nr(dict, S_LEN("id"), (varnumber_T)cur->id);
if (cur->conceal_char) {
- char_u buf[MB_MAXBYTES + 1];
+ char buf[MB_MAXBYTES + 1];
- buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
- dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
+ buf[(*mb_char2bytes)((int)cur->conceal_char, (char_u *)buf)] = NUL;
+ tv_dict_add_str(dict, S_LEN("conceal"), buf);
}
- list_append_dict(rettv->vval.v_list, dict);
+ tv_list_append_dict(rettv->vval.v_list, dict);
cur = cur->next;
}
}
@@ -11214,20 +9902,22 @@ static void getpos_both(typval_T *argvars, typval_T *rettv, bool getcurpos)
fp = var2fpos(&argvars[0], true, &fnum);
}
- list_T *l = rettv_list_alloc(rettv);
- list_append_number(l, (fnum != -1) ? (varnumber_T)fnum : (varnumber_T)0);
- list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum : (varnumber_T)0);
- list_append_number(l,
- (fp != NULL)
- ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
- : (varnumber_T)0);
- list_append_number(l,
- (fp != NULL) ? (varnumber_T)fp->coladd : (varnumber_T)0);
+ list_T *l = tv_list_alloc_ret(rettv);
+ tv_list_append_number(l, (fnum != -1) ? (varnumber_T)fnum : (varnumber_T)0);
+ tv_list_append_number(l, ((fp != NULL)
+ ? (varnumber_T)fp->lnum
+ : (varnumber_T)0));
+ tv_list_append_number(
+ l, ((fp != NULL)
+ ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
+ : (varnumber_T)0));
+ tv_list_append_number(
+ l, (fp != NULL) ? (varnumber_T)fp->coladd : (varnumber_T)0);
if (getcurpos) {
update_curswant();
- list_append_number(l, curwin->w_curswant == MAXCOL
+ tv_list_append_number(l, (curwin->w_curswant == MAXCOL
? (varnumber_T)MAXCOL
- : (varnumber_T)curwin->w_curswant + 1);
+ : (varnumber_T)curwin->w_curswant + 1));
}
}
@@ -11256,39 +9946,39 @@ static void f_getqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "getreg()" function
static void f_getreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *strregname;
- int regname;
+ const char *strregname;
int arg2 = false;
bool return_list = false;
- int error = false;
+ bool error = false;
if (argvars[0].v_type != VAR_UNKNOWN) {
- strregname = get_tv_string_chk(&argvars[0]);
+ strregname = tv_get_string_chk(&argvars[0]);
error = strregname == NULL;
if (argvars[1].v_type != VAR_UNKNOWN) {
- arg2 = get_tv_number_chk(&argvars[1], &error);
+ arg2 = tv_get_number_chk(&argvars[1], &error);
if (!error && argvars[2].v_type != VAR_UNKNOWN) {
- return_list = get_tv_number_chk(&argvars[2], &error);
+ return_list = tv_get_number_chk(&argvars[2], &error);
}
}
} else {
- strregname = vimvars[VV_REG].vv_str;
+ strregname = (const char *)vimvars[VV_REG].vv_str;
}
if (error) {
return;
}
- regname = (strregname == NULL ? '"' : *strregname);
- if (regname == 0)
+ int regname = (uint8_t)(strregname == NULL ? '"' : *strregname);
+ if (regname == 0) {
regname = '"';
+ }
if (return_list) {
rettv->v_type = VAR_LIST;
rettv->vval.v_list =
get_reg_contents(regname, (arg2 ? kGRegExprSrc : 0) | kGRegList);
if (rettv->vval.v_list == NULL) {
- rettv->vval.v_list = list_alloc();
+ rettv->vval.v_list = tv_list_alloc();
}
rettv->vval.v_list->lv_refcount++;
} else {
@@ -11302,23 +9992,24 @@ static void f_getreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_getregtype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *strregname;
- int regname;
+ const char *strregname;
if (argvars[0].v_type != VAR_UNKNOWN) {
- strregname = get_tv_string_chk(&argvars[0]);
- if (strregname == NULL) { /* type error; errmsg already given */
+ strregname = tv_get_string_chk(&argvars[0]);
+ if (strregname == NULL) { // Type error; errmsg already given.
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
return;
}
- } else
- /* Default to v:register */
- strregname = vimvars[VV_REG].vv_str;
+ } else {
+ // Default to v:register.
+ strregname = (const char *)vimvars[VV_REG].vv_str;
+ }
- regname = (strregname == NULL ? '"' : *strregname);
- if (regname == 0)
+ int regname = (uint8_t)(strregname == NULL ? '"' : *strregname);
+ if (regname == 0) {
regname = '"';
+ }
colnr_T reglen = 0;
char buf[NUMBUFLEN + 2];
@@ -11333,18 +10024,18 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// as a dictionary.
static dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx)
{
- dict_T *dict = dict_alloc();
+ dict_T *const dict = tv_dict_alloc();
- dict_add_nr_str(dict, "tabnr", tp_idx, NULL);
+ tv_dict_add_nr(dict, S_LEN("tabnr"), tp_idx);
- list_T *l = list_alloc();
+ list_T *const l = tv_list_alloc();
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
- list_append_number(l, (varnumber_T)wp->handle);
+ tv_list_append_number(l, (varnumber_T)wp->handle);
}
- dict_add_list(dict, "windows", l);
+ tv_dict_add_list(dict, S_LEN("windows"), l);
// Make a reference to tabpage variables
- dict_add_dict(dict, "variables", tp->tp_vars);
+ tv_dict_add_dict(dict, S_LEN("variables"), tp->tp_vars);
return dict;
}
@@ -11354,11 +10045,11 @@ static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
tabpage_T *tparg = NULL;
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
if (argvars[0].v_type != VAR_UNKNOWN) {
// Information about one tab page
- tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
+ tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
if (tparg == NULL) {
return;
}
@@ -11371,9 +10062,9 @@ static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (tparg != NULL && tp != tparg) {
continue;
}
- dict_T *d = get_tabpage_info(tp, tpnr);
+ dict_T *const d = get_tabpage_info(tp, tpnr);
if (d != NULL) {
- list_append_dict(rettv->vval.v_list, d);
+ tv_list_append_dict(rettv->vval.v_list, d);
}
if (tparg != NULL) {
return;
@@ -11394,8 +10085,8 @@ static void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
- const char *const varname = (const char *)get_tv_string_chk(&argvars[1]);
- tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
+ const char *const varname = tv_get_string_chk(&argvars[1]);
+ tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
if (tp != NULL && varname != NULL) {
// Set tp to be our tabpage, temporarily. Also set the window to the
// first window in the tabpage, otherwise the window is not valid.
@@ -11406,7 +10097,7 @@ static void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't',
varname, strlen(varname), false);
if (v != NULL) {
- copy_tv(&v->di_tv, rettv);
+ tv_copy(&v->di_tv, rettv);
done = true;
}
}
@@ -11416,7 +10107,7 @@ static void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (!done && argvars[2].v_type != VAR_UNKNOWN) {
- copy_tv(&argvars[2], rettv);
+ tv_copy(&argvars[2], rettv);
}
}
@@ -11431,22 +10122,21 @@ static void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// Returns information about a window as a dictionary.
static dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr)
{
- dict_T *dict = dict_alloc();
+ dict_T *const dict = tv_dict_alloc();
- dict_add_nr_str(dict, "tabnr", tpnr, NULL);
- dict_add_nr_str(dict, "winnr", winnr, NULL);
- dict_add_nr_str(dict, "winid", wp->handle, NULL);
- dict_add_nr_str(dict, "height", wp->w_height, NULL);
- dict_add_nr_str(dict, "width", wp->w_width, NULL);
- dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL);
+ tv_dict_add_nr(dict, S_LEN("tabnr"), tpnr);
+ tv_dict_add_nr(dict, S_LEN("winnr"), winnr);
+ tv_dict_add_nr(dict, S_LEN("winid"), wp->handle);
+ tv_dict_add_nr(dict, S_LEN("height"), wp->w_height);
+ tv_dict_add_nr(dict, S_LEN("width"), wp->w_width);
+ tv_dict_add_nr(dict, S_LEN("bufnr"), wp->w_buffer->b_fnum);
- dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL);
- dict_add_nr_str(dict, "loclist",
- (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL),
- NULL);
+ tv_dict_add_nr(dict, S_LEN("quickfix"), bt_quickfix(wp->w_buffer));
+ tv_dict_add_nr(dict, S_LEN("loclist"),
+ (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
// Add a reference to window variables
- dict_add_dict(dict, "variables", wp->w_vars);
+ tv_dict_add_dict(dict, S_LEN("variables"), wp->w_vars);
return dict;
}
@@ -11456,7 +10146,7 @@ static void f_getwininfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
win_T *wparg = NULL;
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
if (argvars[0].v_type != VAR_UNKNOWN) {
wparg = win_id2wp(argvars);
@@ -11476,9 +10166,9 @@ static void f_getwininfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
continue;
}
winnr++;
- dict_T *d = get_win_info(wp, tabnr, winnr);
+ dict_T *const d = get_win_info(wp, tabnr, winnr);
if (d != NULL) {
- list_append_dict(rettv->vval.v_list, d);
+ tv_list_append_dict(rettv->vval.v_list, d);
}
if (wparg != NULL) {
// found information about a specific window
@@ -11513,7 +10203,7 @@ find_win_by_nr (
tabpage_T *tp /* NULL for current tab page */
)
{
- int nr = get_tv_number_chk(vp, NULL);
+ int nr = (int)tv_get_number_chk(vp, NULL);
if (nr < 0) {
return NULL;
@@ -11548,7 +10238,7 @@ static win_T *find_tabwin(typval_T *wvp, typval_T *tvp)
if (wvp->v_type != VAR_UNKNOWN) {
if (tvp->v_type != VAR_UNKNOWN) {
- long n = get_tv_number(tvp);
+ long n = tv_get_number(tvp);
if (n >= 0) {
tp = find_tabpage(n);
}
@@ -11588,13 +10278,13 @@ getwinvar (
tabpage_T *oldtabpage = NULL;
bool done = false;
- if (off == 1)
- tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
- else
+ if (off == 1) {
+ tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ } else {
tp = curtab;
+ }
win = find_win_by_nr(&argvars[off], tp);
- const char *varname = (const char *)get_tv_string_chk(
- &argvars[off + 1]);
+ const char *varname = tv_get_string_chk(&argvars[off + 1]);
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
@@ -11628,7 +10318,7 @@ getwinvar (
v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w', varname,
strlen(varname), false);
if (v != NULL) {
- copy_tv(&v->di_tv, rettv);
+ tv_copy(&v->di_tv, rettv);
done = true;
}
}
@@ -11643,7 +10333,7 @@ getwinvar (
if (!done && argvars[off + 2].v_type != VAR_UNKNOWN) {
// use the default return value
- copy_tv(&argvars[off + 2], rettv);
+ tv_copy(&argvars[off + 2], rettv);
}
}
@@ -11654,21 +10344,22 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int options = WILD_SILENT|WILD_USE_NL;
expand_T xpc;
- int error = FALSE;
+ bool error = false;
/* When the optional second argument is non-zero, don't remove matches
* for 'wildignore' and don't put matches for 'suffixes' at the end. */
rettv->v_type = VAR_STRING;
if (argvars[1].v_type != VAR_UNKNOWN) {
- if (get_tv_number_chk(&argvars[1], &error))
+ if (tv_get_number_chk(&argvars[1], &error)) {
options |= WILD_KEEP_ALL;
+ }
if (argvars[2].v_type != VAR_UNKNOWN) {
- if (get_tv_number_chk(&argvars[2], &error)) {
+ if (tv_get_number_chk(&argvars[2], &error)) {
rettv->v_type = VAR_LIST;
rettv->vval.v_list = NULL;
}
if (argvars[3].v_type != VAR_UNKNOWN
- && get_tv_number_chk(&argvars[3], &error)) {
+ && tv_get_number_chk(&argvars[3], &error)) {
options |= WILD_ALLLINKS;
}
}
@@ -11678,14 +10369,16 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
xpc.xp_context = EXPAND_FILES;
if (p_wic)
options += WILD_ICASE;
- if (rettv->v_type == VAR_STRING)
- rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
- NULL, options, WILD_ALL);
- else {
- rettv_list_alloc(rettv);
- ExpandOne(&xpc, get_tv_string(&argvars[0]), NULL, options, WILD_ALL_KEEP);
+ if (rettv->v_type == VAR_STRING) {
+ rettv->vval.v_string = ExpandOne(
+ &xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options, WILD_ALL);
+ } else {
+ tv_list_alloc_ret(rettv);
+ ExpandOne(&xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options,
+ WILD_ALL_KEEP);
for (int i = 0; i < xpc.xp_numfiles; i++) {
- list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
+ tv_list_append_string(rettv->vval.v_list, (const char *)xpc.xp_files[i],
+ -1);
}
ExpandCleanup(&xpc);
}
@@ -11697,7 +10390,7 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int flags = 0; // Flags for globpath.
- int error = false;
+ bool error = false;
// Return a string, or a list if the optional third argument is non-zero.
rettv->v_type = VAR_STRING;
@@ -11705,36 +10398,36 @@ static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[2].v_type != VAR_UNKNOWN) {
// When the optional second argument is non-zero, don't remove matches
// for 'wildignore' and don't put matches for 'suffixes' at the end.
- if (get_tv_number_chk(&argvars[2], &error)) {
+ if (tv_get_number_chk(&argvars[2], &error)) {
flags |= WILD_KEEP_ALL;
}
if (argvars[3].v_type != VAR_UNKNOWN) {
- if (get_tv_number_chk(&argvars[3], &error)) {
+ if (tv_get_number_chk(&argvars[3], &error)) {
rettv->v_type = VAR_LIST;
rettv->vval.v_list = NULL;
}
if (argvars[4].v_type != VAR_UNKNOWN
- && get_tv_number_chk(&argvars[4], &error)) {
+ && tv_get_number_chk(&argvars[4], &error)) {
flags |= WILD_ALLLINKS;
}
}
}
- char_u buf1[NUMBUFLEN];
- char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
+ char buf1[NUMBUFLEN];
+ const char *const file = tv_get_string_buf_chk(&argvars[1], buf1);
if (file != NULL && !error) {
garray_T ga;
ga_init(&ga, (int)sizeof(char_u *), 10);
- globpath(get_tv_string(&argvars[0]), file, &ga, flags);
+ globpath((char_u *)tv_get_string(&argvars[0]), (char_u *)file, &ga, flags);
if (rettv->v_type == VAR_STRING) {
rettv->vval.v_string = ga_concat_strings_sep(&ga, "\n");
} else {
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
for (int i = 0; i < ga.ga_len; i++) {
- list_append_string(rettv->vval.v_list,
- ((char_u **)(ga.ga_data))[i], -1);
+ tv_list_append_string(rettv->vval.v_list,
+ ((const char **)(ga.ga_data))[i], -1);
}
}
@@ -11747,18 +10440,19 @@ static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// "glob2regpat()" function
static void f_glob2regpat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *pat = get_tv_string_chk(&argvars[0]); // NULL on type error
+ const char *const pat = tv_get_string_chk(&argvars[0]); // NULL on type error
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = (pat == NULL)
- ? NULL
- : file_pat_to_reg_pat(pat, NULL, NULL, false);
+ rettv->vval.v_string = ((pat == NULL)
+ ? NULL
+ : file_pat_to_reg_pat((char_u *)pat, NULL, NULL,
+ false));
}
/// "has()" function
static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- static char *(has_list[]) = {
+ static const char *const has_list[] = {
#ifdef UNIX
"unix",
#endif
@@ -11869,13 +10563,11 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
"winaltkeys",
"writebackup",
"nvim",
- NULL
};
bool n = false;
- char *name = (char *)get_tv_string(&argvars[0]);
-
- for (int i = 0; has_list[i] != NULL; i++) {
+ const char *const name = tv_get_string(&argvars[0]);
+ for (size_t i = 0; i < ARRAY_SIZE(has_list); i++) {
if (STRICMP(name, has_list[i]) == 0) {
n = true;
break;
@@ -11940,8 +10632,9 @@ static void f_has_key(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[0].vval.v_dict == NULL)
return;
- rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
- get_tv_string(&argvars[1]), -1) != NULL;
+ rettv->vval.v_number = tv_dict_find(argvars[0].vval.v_dict,
+ tv_get_string(&argvars[1]),
+ -1) != NULL;
}
/// `haslocaldir([{win}[, {tab}]])` function
@@ -12050,24 +10743,24 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_hasmapto(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *name;
- char_u *mode;
- char_u buf[NUMBUFLEN];
- int abbr = FALSE;
-
- name = get_tv_string(&argvars[0]);
- if (argvars[1].v_type == VAR_UNKNOWN)
- mode = (char_u *)"nvo";
- else {
- mode = get_tv_string_buf(&argvars[1], buf);
- if (argvars[2].v_type != VAR_UNKNOWN)
- abbr = get_tv_number(&argvars[2]);
+ const char *mode;
+ const char *const name = tv_get_string(&argvars[0]);
+ bool abbr = false;
+ char buf[NUMBUFLEN];
+ if (argvars[1].v_type == VAR_UNKNOWN) {
+ mode = "nvo";
+ } else {
+ mode = tv_get_string_buf(&argvars[1], buf);
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ abbr = tv_get_number(&argvars[2]);
+ }
}
- if (map_to_exists(name, mode, abbr))
- rettv->vval.v_number = TRUE;
- else
- rettv->vval.v_number = FALSE;
+ if (map_to_exists(name, mode, abbr)) {
+ rettv->vval.v_number = true;
+ } else {
+ rettv->vval.v_number = false;
+ }
}
/*
@@ -12076,20 +10769,19 @@ static void f_hasmapto(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_histadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
HistoryType histype;
- char_u *str;
- char_u buf[NUMBUFLEN];
rettv->vval.v_number = false;
if (check_restricted() || check_secure()) {
return;
}
- str = get_tv_string_chk(&argvars[0]); // NULL on type error
- histype = str != NULL ? get_histtype(str, STRLEN(str), false) : HIST_INVALID;
+ const char *str = tv_get_string_chk(&argvars[0]); // NULL on type error
+ histype = str != NULL ? get_histtype(str, strlen(str), false) : HIST_INVALID;
if (histype != HIST_INVALID) {
- str = get_tv_string_buf(&argvars[1], buf);
+ char buf[NUMBUFLEN];
+ str = tv_get_string_buf(&argvars[1], buf);
if (*str != NUL) {
init_history();
- add_to_history(histype, str, false, NUL);
+ add_to_history(histype, (char_u *)str, false, NUL);
rettv->vval.v_number = true;
return;
}
@@ -12102,23 +10794,21 @@ static void f_histadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_histdel(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int n;
- char_u buf[NUMBUFLEN];
- char_u *str;
-
- str = get_tv_string_chk(&argvars[0]); // NULL on type error
+ const char *const str = tv_get_string_chk(&argvars[0]); // NULL on type error
if (str == NULL) {
n = 0;
} else if (argvars[1].v_type == VAR_UNKNOWN) {
// only one argument: clear entire history
- n = clr_history(get_histtype(str, STRLEN(str), false));
+ n = clr_history(get_histtype(str, strlen(str), false));
} else if (argvars[1].v_type == VAR_NUMBER) {
// index given: remove that entry
- n = del_history_idx(get_histtype(str, STRLEN(str), false),
- (int) get_tv_number(&argvars[1]));
+ n = del_history_idx(get_histtype(str, strlen(str), false),
+ (int)tv_get_number(&argvars[1]));
} else {
// string given: remove all matching entries
- n = del_history_entry(get_histtype(str, STRLEN(str), false),
- get_tv_string_buf(&argvars[1], buf));
+ char buf[NUMBUFLEN];
+ n = del_history_entry(get_histtype(str, strlen(str), false),
+ (char_u *)tv_get_string_buf(&argvars[1], buf));
}
rettv->vval.v_number = n;
}
@@ -12130,17 +10820,16 @@ static void f_histget(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
HistoryType type;
int idx;
- char_u *str;
- str = get_tv_string_chk(&argvars[0]); // NULL on type error
+ const char *const str = tv_get_string_chk(&argvars[0]); // NULL on type error
if (str == NULL) {
rettv->vval.v_string = NULL;
} else {
- type = get_histtype(str, STRLEN(str), false);
+ type = get_histtype(str, strlen(str), false);
if (argvars[1].v_type == VAR_UNKNOWN) {
idx = get_history_idx(type);
} else {
- idx = (int)get_tv_number_chk(&argvars[1], NULL);
+ idx = (int)tv_get_number_chk(&argvars[1], NULL);
}
// -1 on type error
rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
@@ -12155,9 +10844,9 @@ static void f_histnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int i;
- char_u *history = get_tv_string_chk(&argvars[0]);
+ const char *const history = tv_get_string_chk(&argvars[0]);
- i = history == NULL ? HIST_CMD - 1 : get_histtype(history, STRLEN(history),
+ i = history == NULL ? HIST_CMD - 1 : get_histtype(history, strlen(history),
false);
if (i != HIST_INVALID) {
i = get_history_idx(i);
@@ -12172,7 +10861,8 @@ static void f_histnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
+ rettv->vval.v_number = syn_name2id(
+ (const char_u *)tv_get_string(&argvars[0]));
}
/*
@@ -12180,7 +10870,8 @@ static void f_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_hlexists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
+ rettv->vval.v_number = highlight_exists(
+ (const char_u *)tv_get_string(&argvars[0]));
}
/*
@@ -12200,25 +10891,27 @@ static void f_hostname(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_iconv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u buf1[NUMBUFLEN];
- char_u buf2[NUMBUFLEN];
- char_u *from, *to, *str;
vimconv_T vimconv;
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
- str = get_tv_string(&argvars[0]);
- from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
- to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
+ const char *const str = tv_get_string(&argvars[0]);
+ char buf1[NUMBUFLEN];
+ char_u *const from = enc_canonize(enc_skip(
+ (char_u *)tv_get_string_buf(&argvars[1], buf1)));
+ char buf2[NUMBUFLEN];
+ char_u *const to = enc_canonize(enc_skip(
+ (char_u *)tv_get_string_buf(&argvars[2], buf2)));
vimconv.vc_type = CONV_NONE;
convert_setup(&vimconv, from, to);
- /* If the encodings are equal, no conversion needed. */
- if (vimconv.vc_type == CONV_NONE)
- rettv->vval.v_string = vim_strsave(str);
- else
- rettv->vval.v_string = string_convert(&vimconv, str, NULL);
+ // If the encodings are equal, no conversion needed.
+ if (vimconv.vc_type == CONV_NONE) {
+ rettv->vval.v_string = (char_u *)xstrdup(str);
+ } else {
+ rettv->vval.v_string = string_convert(&vimconv, (char_u *)str, NULL);
+ }
convert_setup(&vimconv, NULL, NULL);
xfree(from);
@@ -12230,13 +10923,12 @@ static void f_iconv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_indent(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T lnum;
-
- lnum = get_tv_lnum(argvars);
- if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
+ const linenr_T lnum = tv_get_lnum(argvars);
+ if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
rettv->vval.v_number = get_indent_lnum(lnum);
- else
+ } else {
rettv->vval.v_number = -1;
+ }
}
/*
@@ -12258,16 +10950,18 @@ static void f_index(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (l != NULL) {
item = l->lv_first;
if (argvars[2].v_type != VAR_UNKNOWN) {
- int error = FALSE;
+ bool error = false;
- /* Start at specified item. Use the cached index that list_find()
- * sets, so that a negative number also works. */
- item = list_find(l, get_tv_number_chk(&argvars[2], &error));
+ // Start at specified item. Use the cached index that tv_list_find()
+ // sets, so that a negative number also works.
+ item = tv_list_find(l, tv_get_number_chk(&argvars[2], &error));
idx = l->lv_idx;
- if (argvars[3].v_type != VAR_UNKNOWN)
- ic = get_tv_number_chk(&argvars[3], &error);
- if (error)
+ if (argvars[3].v_type != VAR_UNKNOWN) {
+ ic = tv_get_number_chk(&argvars[3], &error);
+ }
+ if (error) {
item = NULL;
+ }
}
for (; item != NULL; item = item->li_next, ++idx)
@@ -12280,70 +10974,93 @@ static void f_index(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static int inputsecret_flag = 0;
-/// Get user input
-///
-/// Used for f_input and f_inputdialog functions.
-///
-/// @param[in] prompt Input prompt.
-/// @param[in] initval Initial value, may be NULL.
-/// @param[in] xp_name Completion, for input().
-/// @param[in] cancelval Value returned when user cancelled dialog, for
-/// inputdialog().
-///
-/// @return [allocated] User input or NULL.
-char *get_user_input(const char *const prompt,
- const char *const initval,
- const char *const xp_name,
- const char *const cancelval)
- FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
-{
- char *ret = NULL;
- const int saved_cmd_silent = cmd_silent;
- cmd_silent = false; // Want to see the prompt.
- // Only the part of the message after the last NL is considered as
- // prompt for the command line.
- const char *p = strrchr(prompt, NL);
- if (p == NULL) {
- p = prompt;
- } else {
- p++;
- msg_start();
- msg_clr_eos();
- msg_puts_attr_len(prompt, (int)(p - prompt) + 1, echo_attr);
- msg_didout = false;
- msg_starthere();
- }
- cmdline_row = msg_row;
-
- stuffReadbuffSpec((char_u *)initval);
- char *xp_arg = NULL;
+/*
+ * This function is used by f_input() and f_inputdialog() functions. The third
+ * argument to f_input() specifies the type of completion to use at the
+ * prompt. The third argument to f_inputdialog() specifies the value to return
+ * when the user cancels the prompt.
+ */
+void get_user_input(const typval_T *const argvars,
+ typval_T *const rettv, const bool inputdialog)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const char *prompt = tv_get_string_chk(&argvars[0]);
+ int cmd_silent_save = cmd_silent;
int xp_type = EXPAND_NOTHING;
- if (xp_name != NULL) {
- uint32_t argt;
- if (parse_compl_arg((const char_u *)xp_name, (int)strlen(xp_name),
- &xp_type, &argt, (char_u **)&xp_arg) == FAIL) {
- return NULL;
+ char_u *xp_arg = NULL;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ cmd_silent = FALSE; /* Want to see the prompt. */
+ if (prompt != NULL) {
+ // Only the part of the message after the last NL is considered as
+ // prompt for the command line.
+ const char *p = strrchr(prompt, '\n');
+ if (p == NULL) {
+ p = prompt;
+ } else {
+ p++;
+ msg_start();
+ msg_clr_eos();
+ msg_puts_attr_len(prompt, p - prompt, echo_attr);
+ msg_didout = false;
+ msg_starthere();
}
- }
+ cmdline_row = msg_row;
- const int saved_ex_normal_busy = ex_normal_busy;
- ex_normal_busy = 0;
- ret = (char *)getcmdline_prompt(inputsecret_flag ? NUL : '@', (char_u *)p,
- echo_attr, xp_type, (char_u *)xp_arg);
- ex_normal_busy = saved_ex_normal_busy;
+ const char *defstr = "";
+ char buf[NUMBUFLEN];
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ defstr = tv_get_string_buf_chk(&argvars[1], buf);
+ if (defstr != NULL) {
+ stuffReadbuffSpec(defstr);
+ }
- if (ret == NULL && cancelval != NULL) {
- ret = xstrdup(cancelval);
- }
+ if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN) {
+ char buf2[NUMBUFLEN];
+ // input() with a third argument: completion
+ rettv->vval.v_string = NULL;
+
+ const char *const xp_name = tv_get_string_buf_chk(&argvars[2], buf2);
+ if (xp_name == NULL) {
+ return;
+ }
- xfree(xp_arg);
+ const int xp_namelen = (int)strlen(xp_name);
- // Since the user typed this, no need to wait for return.
- need_wait_return = false;
- msg_didout = false;
- cmd_silent = saved_cmd_silent;
- return ret;
+ uint32_t argt;
+ if (parse_compl_arg((char_u *)xp_name, xp_namelen, &xp_type, &argt,
+ &xp_arg) == FAIL) {
+ return;
+ }
+ }
+ }
+
+ if (defstr != NULL) {
+ int save_ex_normal_busy = ex_normal_busy;
+ ex_normal_busy = 0;
+ rettv->vval.v_string =
+ getcmdline_prompt(inputsecret_flag ? NUL : '@', (char_u *)p, echo_attr,
+ xp_type, xp_arg);
+ ex_normal_busy = save_ex_normal_busy;
+ }
+ if (inputdialog && rettv->vval.v_string == NULL
+ && argvars[1].v_type != VAR_UNKNOWN
+ && argvars[2].v_type != VAR_UNKNOWN) {
+ char buf[NUMBUFLEN];
+ rettv->vval.v_string = (char_u *)xstrdup(tv_get_string_buf(
+ &argvars[2], buf));
+ }
+
+ xfree(xp_arg);
+
+ /* since the user typed this, no need to wait for return */
+ need_wait_return = FALSE;
+ msg_didout = FALSE;
+ }
+ cmd_silent = cmd_silent_save;
}
/*
@@ -12352,25 +11069,7 @@ char *get_user_input(const char *const prompt,
*/
static void f_input(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char initval_buf[NUMBUFLEN];
- char xp_name_buf[NUMBUFLEN];
- const char *const prompt = (const char *)get_tv_string_chk(&argvars[0]);
- const char *const initval = (
- argvars[1].v_type != VAR_UNKNOWN
- ? (const char *)get_tv_string_buf(&argvars[1], (char_u *)initval_buf)
- : "");
- const char *const xp_name = (
- argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN
- ? (const char *)get_tv_string_buf(&argvars[2], (char_u *)xp_name_buf)
- : NULL);
- if (prompt == NULL || initval == NULL
- || (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN
- && xp_name == NULL)) {
- return;
- }
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = (char_u *)get_user_input(prompt, initval, xp_name,
- NULL);
+ get_user_input(argvars, rettv, FALSE);
}
/*
@@ -12378,25 +11077,7 @@ static void f_input(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_inputdialog(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char initval_buf[NUMBUFLEN];
- char cancelval_buf[NUMBUFLEN];
- const char *const prompt = (const char *)get_tv_string_chk(&argvars[0]);
- const char *const initval = (
- argvars[1].v_type != VAR_UNKNOWN
- ? (const char *)get_tv_string_buf(&argvars[1], (char_u *)initval_buf)
- : "");
- const char *const cancelval = (
- argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN
- ? (const char *)get_tv_string_buf(&argvars[2], (char_u *)cancelval_buf)
- : NULL);
- if (prompt == NULL || initval == NULL
- || (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN
- && cancelval == NULL)) {
- return;
- }
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = (char_u *)get_user_input(prompt, initval, NULL,
- cancelval);
+ get_user_input(argvars, rettv, TRUE);
}
/*
@@ -12420,7 +11101,7 @@ static void f_inputlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
msg_clr_eos();
for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next) {
- msg_puts((const char *)get_tv_string(&li->li_tv));
+ msg_puts(tv_get_string(&li->li_tv));
msg_putchar('\n');
}
@@ -12478,10 +11159,8 @@ static void f_inputsecret(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- long before = 0;
- listitem_T *item;
- list_T *l;
- int error = false;
+ list_T *l;
+ bool error = false;
const char *const arg_errmsg = _("insert() argument");
const size_t arg_errmsg_len = strlen(arg_errmsg);
@@ -12489,26 +11168,26 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
EMSG2(_(e_listarg), "insert()");
} else if ((l = argvars[0].vval.v_list) != NULL
&& !tv_check_lock(l->lv_lock, arg_errmsg, arg_errmsg_len)) {
+ long before = 0;
if (argvars[2].v_type != VAR_UNKNOWN) {
- before = get_tv_number_chk(&argvars[2], &error);
+ before = tv_get_number_chk(&argvars[2], &error);
}
if (error) {
// type error; errmsg already given
return;
}
- if (before == l->lv_len)
- item = NULL;
- else {
- item = list_find(l, before);
+ listitem_T *item = NULL;
+ if (before != l->lv_len) {
+ item = tv_list_find(l, before);
if (item == NULL) {
EMSGN(_(e_listidx), before);
l = NULL;
}
}
if (l != NULL) {
- list_insert_tv(l, &argvars[1], item);
- copy_tv(&argvars[0], rettv);
+ tv_list_insert_tv(l, &argvars[1], item);
+ tv_copy(&argvars[0], rettv);
}
}
}
@@ -12518,7 +11197,7 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_invert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
+ rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
}
/*
@@ -12526,7 +11205,7 @@ static void f_invert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_isdirectory(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = os_isdir(get_tv_string(&argvars[0]));
+ rettv->vval.v_number = os_isdir((const char_u *)tv_get_string(&argvars[0]));
}
/*
@@ -12535,18 +11214,20 @@ static void f_isdirectory(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_islocked(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
lval_T lv;
- char_u *end;
dictitem_T *di;
rettv->vval.v_number = -1;
- end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, false, false,
- GLV_NO_AUTOLOAD|GLV_READ_ONLY, FNE_CHECK_START);
+ const char_u *const end = get_lval((char_u *)tv_get_string(&argvars[0]),
+ NULL,
+ &lv, false, false,
+ GLV_NO_AUTOLOAD|GLV_READ_ONLY,
+ FNE_CHECK_START);
if (end != NULL && lv.ll_name != NULL) {
- if (*end != NUL)
+ if (*end != NUL) {
EMSG(_(e_trailing));
- else {
+ } else {
if (lv.ll_tv == NULL) {
- di = find_var((const char *)lv.ll_name, STRLEN(lv.ll_name), NULL, true);
+ di = find_var((const char *)lv.ll_name, lv.ll_name_len, NULL, true);
if (di != NULL) {
// Consider a variable locked when:
// 1. the variable itself is locked
@@ -12573,68 +11254,61 @@ static void f_islocked(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
-/*
- * Turn a dict into a list:
- * "what" == 0: list of keys
- * "what" == 1: list of values
- * "what" == 2: list of items
- */
-static void dict_list(typval_T *argvars, typval_T *rettv, int what)
-{
- list_T *l2;
- dictitem_T *di;
- hashitem_T *hi;
- listitem_T *li;
- listitem_T *li2;
- dict_T *d;
- int todo;
-
- if (argvars[0].v_type != VAR_DICT) {
- EMSG(_(e_dictreq));
+/// Turn a dictionary into a list
+///
+/// @param[in] tv Dictionary to convert. Is checked for actually being
+/// a dictionary, will give an error if not.
+/// @param[out] rettv Location where result will be saved.
+/// @param[in] what What to save in rettv.
+static void dict_list(typval_T *const tv, typval_T *const rettv,
+ const DictListType what)
+{
+ if (tv->v_type != VAR_DICT) {
+ emsgf(_(e_dictreq));
return;
}
- if ((d = argvars[0].vval.v_dict) == NULL)
+ if (tv->vval.v_dict == NULL) {
return;
+ }
- rettv_list_alloc(rettv);
-
- todo = (int)d->dv_hashtab.ht_used;
- for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- --todo;
- di = HI2DI(hi);
+ tv_list_alloc_ret(rettv);
- li = listitem_alloc();
- list_append(rettv->vval.v_list, li);
+ TV_DICT_ITER(tv->vval.v_dict, di, {
+ listitem_T *const li = tv_list_item_alloc();
+ tv_list_append(rettv->vval.v_list, li);
- if (what == 0) {
- /* keys() */
+ switch (what) {
+ case kDictListKeys: {
li->li_tv.v_type = VAR_STRING;
- li->li_tv.v_lock = 0;
+ li->li_tv.v_lock = VAR_UNLOCKED;
li->li_tv.vval.v_string = vim_strsave(di->di_key);
- } else if (what == 1) {
- /* values() */
- copy_tv(&di->di_tv, &li->li_tv);
- } else {
- /* items() */
- l2 = list_alloc();
+ break;
+ }
+ case kDictListValues: {
+ tv_copy(&di->di_tv, &li->li_tv);
+ break;
+ }
+ case kDictListItems: {
+ // items()
+ list_T *const sub_l = tv_list_alloc();
li->li_tv.v_type = VAR_LIST;
- li->li_tv.v_lock = 0;
- li->li_tv.vval.v_list = l2;
- ++l2->lv_refcount;
-
- li2 = listitem_alloc();
- list_append(l2, li2);
- li2->li_tv.v_type = VAR_STRING;
- li2->li_tv.v_lock = 0;
- li2->li_tv.vval.v_string = vim_strsave(di->di_key);
-
- li2 = listitem_alloc();
- list_append(l2, li2);
- copy_tv(&di->di_tv, &li2->li_tv);
+ li->li_tv.v_lock = VAR_UNLOCKED;
+ li->li_tv.vval.v_list = sub_l;
+ sub_l->lv_refcount++;
+
+ listitem_T *sub_li = tv_list_item_alloc();
+ tv_list_append(sub_l, sub_li);
+ sub_li->li_tv.v_type = VAR_STRING;
+ sub_li->li_tv.v_lock = VAR_UNLOCKED;
+ sub_li->li_tv.vval.v_string = vim_strsave(di->di_key);
+
+ sub_li = tv_list_item_alloc();
+ tv_list_append(sub_l, sub_li);
+ tv_copy(&di->di_tv, &sub_li->li_tv);
+ break;
}
}
- }
+ });
}
/// "id()" function
@@ -12775,8 +11449,8 @@ static void f_jobsend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- ssize_t input_len;
- char *input = (char *) save_tv_as_string(&argvars[1], &input_len, false);
+ ptrdiff_t input_len = 0;
+ char *input = save_tv_as_string(&argvars[1], &input_len, false);
if (!input) {
// Either the error has been handled by save_tv_as_string(), or there is no
// input to send.
@@ -12821,10 +11495,10 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = 1;
}
-static char **tv_to_argv(typval_T *cmd_tv, char **cmd, bool *executable)
+static char **tv_to_argv(typval_T *cmd_tv, const char **cmd, bool *executable)
{
if (cmd_tv->v_type == VAR_STRING) {
- char *cmd_str = (char *)get_tv_string(cmd_tv);
+ const char *cmd_str = tv_get_string(cmd_tv);
if (cmd) {
*cmd = cmd_str;
}
@@ -12845,8 +11519,8 @@ static char **tv_to_argv(typval_T *cmd_tv, char **cmd, bool *executable)
assert(argl->lv_first);
- const char_u *exe = get_tv_string_chk(&argl->lv_first->li_tv);
- if (!exe || !os_can_exe(exe, NULL, true)) {
+ const char *exe = tv_get_string_chk(&argl->lv_first->li_tv);
+ if (!exe || !os_can_exe((const char_u *)exe, NULL, true)) {
if (exe && executable) {
*executable = false;
}
@@ -12854,16 +11528,16 @@ static char **tv_to_argv(typval_T *cmd_tv, char **cmd, bool *executable)
}
if (cmd) {
- *cmd = (char *)exe;
+ *cmd = exe;
}
// Build the argument vector
int i = 0;
char **argv = xcalloc(argc + 1, sizeof(char *));
for (listitem_T *arg = argl->lv_first; arg != NULL; arg = arg->li_next) {
- char *a = (char *)get_tv_string_chk(&arg->li_tv);
+ const char *a = tv_get_string_chk(&arg->li_tv);
if (!a) {
- // Did emsg in get_tv_string; just deallocate argv.
+ // Did emsg in tv_get_string_chk; just deallocate argv.
shell_free_argv(argv);
return NULL;
}
@@ -12899,23 +11573,26 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
dict_T *job_opts = NULL;
- bool detach = false, rpc = false, pty = false;
- Callback on_stdout = CALLBACK_NONE, on_stderr = CALLBACK_NONE,
- on_exit = CALLBACK_NONE;
+ bool detach = false;
+ bool rpc = false;
+ bool pty = false;
+ Callback on_stdout = CALLBACK_NONE;
+ Callback on_stderr = CALLBACK_NONE;
+ Callback on_exit = CALLBACK_NONE;
char *cwd = NULL;
if (argvars[1].v_type == VAR_DICT) {
job_opts = argvars[1].vval.v_dict;
- detach = get_dict_number(job_opts, "detach") != 0;
- rpc = get_dict_number(job_opts, "rpc") != 0;
- pty = get_dict_number(job_opts, "pty") != 0;
+ detach = tv_dict_get_number(job_opts, "detach") != 0;
+ rpc = tv_dict_get_number(job_opts, "rpc") != 0;
+ pty = tv_dict_get_number(job_opts, "pty") != 0;
if (pty && rpc) {
EMSG2(_(e_invarg2), "job cannot have both 'pty' and 'rpc' options set");
shell_free_argv(argv);
return;
}
- char *new_cwd = (char *)get_dict_string(job_opts, "cwd", false);
+ char *new_cwd = tv_dict_get_string(job_opts, "cwd", false);
if (new_cwd && strlen(new_cwd) > 0) {
cwd = new_cwd;
// The new cwd must be a directory.
@@ -12937,15 +11614,15 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
Process *proc = (Process *)&data->proc;
if (pty) {
- uint16_t width = get_dict_number(job_opts, "width");
+ uint16_t width = (uint16_t)tv_dict_get_number(job_opts, "width");
if (width > 0) {
data->proc.pty.width = width;
}
- uint16_t height = get_dict_number(job_opts, "height");
+ uint16_t height = (uint16_t)tv_dict_get_number(job_opts, "height");
if (height > 0) {
data->proc.pty.height = height;
}
- char *term = (char *)get_dict_string(job_opts, "TERM", true);
+ char *term = tv_dict_get_string(job_opts, "TERM", true);
if (term) {
data->proc.pty.term_name = term;
}
@@ -13005,7 +11682,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
list_T *args = argvars[0].vval.v_list;
- list_T *rv = list_alloc();
+ list_T *rv = tv_list_alloc();
ui_busy_start();
MultiQueue *waiting_jobs = multiqueue_new_parent(loop_on_put, &main_loop);
@@ -13016,11 +11693,11 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
TerminalJobData *data = NULL;
if (arg->li_tv.v_type != VAR_NUMBER
|| !(data = find_job(arg->li_tv.vval.v_number))) {
- list_append_number(rv, -3);
+ tv_list_append_number(rv, -3);
} else {
// append the list item and set the status pointer so we'll collect the
// status code when the job exits
- list_append_number(rv, -1);
+ tv_list_append_number(rv, -1);
data->status_ptr = &rv->lv_last->li_tv.vval.v_number;
// Process any pending events for the job because we'll temporarily
// replace the parent queue
@@ -13101,50 +11778,49 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_join(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- garray_T ga;
- char_u *sep;
-
if (argvars[0].v_type != VAR_LIST) {
EMSG(_(e_listreq));
return;
}
- if (argvars[0].vval.v_list == NULL)
+ if (argvars[0].vval.v_list == NULL) {
return;
- if (argvars[1].v_type == VAR_UNKNOWN)
- sep = (char_u *)" ";
- else
- sep = get_tv_string_chk(&argvars[1]);
+ }
+ const char *const sep = (argvars[1].v_type == VAR_UNKNOWN
+ ? " "
+ : tv_get_string_chk(&argvars[1]));
rettv->v_type = VAR_STRING;
if (sep != NULL) {
+ garray_T ga;
ga_init(&ga, (int)sizeof(char), 80);
- list_join(&ga, argvars[0].vval.v_list, (char *) sep);
+ tv_list_join(&ga, argvars[0].vval.v_list, sep);
ga_append(&ga, NUL);
rettv->vval.v_string = (char_u *)ga.ga_data;
- } else
+ } else {
rettv->vval.v_string = NULL;
+ }
}
/// json_decode() function
static void f_json_decode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
char numbuf[NUMBUFLEN];
- char *s = NULL;
+ const char *s = NULL;
char *tofree = NULL;
size_t len;
if (argvars[0].v_type == VAR_LIST) {
- if (!encode_vim_list_to_buf(argvars[0].vval.v_list, &len, &s)) {
+ if (!encode_vim_list_to_buf(argvars[0].vval.v_list, &len, &tofree)) {
EMSG(_("E474: Failed to convert list to string"));
return;
}
- tofree = s;
+ s = tofree;
if (s == NULL) {
assert(len == 0);
s = "";
}
} else {
- s = (char *) get_tv_string_buf_chk(&argvars[0], (char_u *) numbuf);
+ s = tv_get_string_buf_chk(&argvars[0], numbuf);
if (s) {
len = strlen(s);
} else {
@@ -13197,24 +11873,28 @@ static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_len(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
switch (argvars[0].v_type) {
- case VAR_STRING:
- case VAR_NUMBER:
- rettv->vval.v_number = (varnumber_T)STRLEN(
- get_tv_string(&argvars[0]));
- break;
- case VAR_LIST:
- rettv->vval.v_number = list_len(argvars[0].vval.v_list);
- break;
- case VAR_DICT:
- rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
- break;
- case VAR_UNKNOWN:
- case VAR_SPECIAL:
- case VAR_FLOAT:
- case VAR_FUNC:
- case VAR_PARTIAL:
- EMSG(_("E701: Invalid type for len()"));
- break;
+ case VAR_STRING:
+ case VAR_NUMBER: {
+ rettv->vval.v_number = (varnumber_T)strlen(
+ tv_get_string(&argvars[0]));
+ break;
+ }
+ case VAR_LIST: {
+ rettv->vval.v_number = tv_list_len(argvars[0].vval.v_list);
+ break;
+ }
+ case VAR_DICT: {
+ rettv->vval.v_number = tv_dict_len(argvars[0].vval.v_dict);
+ break;
+ }
+ case VAR_UNKNOWN:
+ case VAR_SPECIAL:
+ case VAR_FLOAT:
+ case VAR_PARTIAL:
+ case VAR_FUNC: {
+ EMSG(_("E701: Invalid type for len()"));
+ break;
+ }
}
}
@@ -13299,15 +11979,15 @@ static void f_line(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_line2byte(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T lnum;
-
- lnum = get_tv_lnum(argvars);
- if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
+ const linenr_T lnum = tv_get_lnum(argvars);
+ if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) {
rettv->vval.v_number = -1;
- else
+ } else {
rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
- if (rettv->vval.v_number >= 0)
- ++rettv->vval.v_number;
+ }
+ if (rettv->vval.v_number >= 0) {
+ rettv->vval.v_number++;
+ }
}
/*
@@ -13315,17 +11995,15 @@ static void f_line2byte(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_lispindent(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- pos_T pos;
- linenr_T lnum;
-
- pos = curwin->w_cursor;
- lnum = get_tv_lnum(argvars);
+ const pos_T pos = curwin->w_cursor;
+ const linenr_T lnum = tv_get_lnum(argvars);
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) {
curwin->w_cursor.lnum = lnum;
rettv->vval.v_number = get_lisp_indent();
curwin->w_cursor = pos;
- } else
+ } else {
rettv->vval.v_number = -1;
+ }
}
/*
@@ -13339,38 +12017,41 @@ static void f_localtime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
{
- char_u *keys;
- char_u *which;
- char_u buf[NUMBUFLEN];
- char_u *keys_buf = NULL;
- char_u *rhs;
+ char_u *keys_buf = NULL;
+ char_u *rhs;
int mode;
int abbr = FALSE;
int get_dict = FALSE;
mapblock_T *mp;
int buffer_local;
- /* return empty string for failure */
+ // Return empty string for failure.
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
- keys = get_tv_string(&argvars[0]);
- if (*keys == NUL)
+ char_u *keys = (char_u *)tv_get_string(&argvars[0]);
+ if (*keys == NUL) {
return;
+ }
+ char buf[NUMBUFLEN];
+ const char *which;
if (argvars[1].v_type != VAR_UNKNOWN) {
- which = get_tv_string_buf_chk(&argvars[1], buf);
+ which = tv_get_string_buf_chk(&argvars[1], buf);
if (argvars[2].v_type != VAR_UNKNOWN) {
- abbr = get_tv_number(&argvars[2]);
- if (argvars[3].v_type != VAR_UNKNOWN)
- get_dict = get_tv_number(&argvars[3]);
+ abbr = tv_get_number(&argvars[2]);
+ if (argvars[3].v_type != VAR_UNKNOWN) {
+ get_dict = tv_get_number(&argvars[3]);
+ }
}
- } else
- which = (char_u *)"";
- if (which == NULL)
+ } else {
+ which = "";
+ }
+ if (which == NULL) {
return;
+ }
- mode = get_map_mode(&which, 0);
+ mode = get_map_mode((char_u **)&which, 0);
keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, false,
CPO_TO_CPO_FLAGS);
@@ -13383,22 +12064,22 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
rettv->vval.v_string = str2special_save(rhs, FALSE);
} else {
- rettv_dict_alloc(rettv);
+ tv_dict_alloc_ret(rettv);
if (rhs != NULL) {
// Return a dictionary.
char_u *lhs = str2special_save(mp->m_keys, true);
char *const mapmode = map_mode_to_chars(mp->m_mode);
dict_T *dict = rettv->vval.v_dict;
- dict_add_nr_str(dict, "lhs", 0L, lhs);
- dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
- dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L, NULL);
- dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
- dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
- dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
- dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
- dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
- dict_add_nr_str(dict, "mode", 0L, (char_u *)mapmode);
+ tv_dict_add_str(dict, S_LEN("lhs"), (const char *)lhs);
+ tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str);
+ tv_dict_add_nr(dict, S_LEN("noremap"), mp->m_noremap ? 1 : 0);
+ tv_dict_add_nr(dict, S_LEN("expr"), mp->m_expr ? 1 : 0);
+ tv_dict_add_nr(dict, S_LEN("silent"), mp->m_silent ? 1 : 0);
+ tv_dict_add_nr(dict, S_LEN("sid"), (varnumber_T)mp->m_script_ID);
+ tv_dict_add_nr(dict, S_LEN("buffer"), (varnumber_T)buffer_local);
+ tv_dict_add_nr(dict, S_LEN("nowait"), mp->m_nowait ? 1 : 0);
+ tv_dict_add_str(dict, S_LEN("mode"), mapmode);
xfree(lhs);
xfree(mapmode);
@@ -13410,7 +12091,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
static void f_luaeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
FUNC_ATTR_NONNULL_ALL
{
- const char *const str = (const char *)get_tv_string(&argvars[0]);
+ const char *const str = (const char *)tv_get_string_chk(&argvars[0]);
if (str == NULL) {
return;
}
@@ -13448,9 +12129,7 @@ static void find_some_match(typval_T *argvars, typval_T *rettv, int type)
char_u *str = NULL;
long len = 0;
char_u *expr = NULL;
- char_u *pat;
regmatch_T regmatch;
- char_u patbuf[NUMBUFLEN];
char_u *save_cpo;
long start = 0;
long nth = 1;
@@ -13469,12 +12148,12 @@ static void find_some_match(typval_T *argvars, typval_T *rettv, int type)
if (type == 3 || type == 4) {
// type 3: return empty list when there are no matches.
// type 4: return ["", -1, -1, -1]
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
if (type == 4) {
- list_append_string(rettv->vval.v_list, (char_u *)"", 0);
- list_append_number(rettv->vval.v_list, (varnumber_T)-1);
- list_append_number(rettv->vval.v_list, (varnumber_T)-1);
- list_append_number(rettv->vval.v_list, (varnumber_T)-1);
+ tv_list_append_string(rettv->vval.v_list, "", 0);
+ tv_list_append_number(rettv->vval.v_list, -1);
+ tv_list_append_number(rettv->vval.v_list, -1);
+ tv_list_append_number(rettv->vval.v_list, -1);
}
} else if (type == 2) {
rettv->v_type = VAR_STRING;
@@ -13486,25 +12165,29 @@ static void find_some_match(typval_T *argvars, typval_T *rettv, int type)
goto theend;
li = l->lv_first;
} else {
- expr = str = get_tv_string(&argvars[0]);
+ expr = str = (char_u *)tv_get_string(&argvars[0]);
len = (long)STRLEN(str);
}
- pat = get_tv_string_buf_chk(&argvars[1], patbuf);
- if (pat == NULL)
+ char patbuf[NUMBUFLEN];
+ const char *const pat = tv_get_string_buf_chk(&argvars[1], patbuf);
+ if (pat == NULL) {
goto theend;
+ }
if (argvars[2].v_type != VAR_UNKNOWN) {
- int error = FALSE;
+ bool error = false;
- start = get_tv_number_chk(&argvars[2], &error);
- if (error)
+ start = tv_get_number_chk(&argvars[2], &error);
+ if (error) {
goto theend;
+ }
if (l != NULL) {
- li = list_find(l, start);
- if (li == NULL)
+ li = tv_list_find(l, start);
+ if (li == NULL) {
goto theend;
- idx = l->lv_idx; /* use the cached index */
+ }
+ idx = l->lv_idx; // Use the cached index.
} else {
if (start < 0)
start = 0;
@@ -13521,13 +12204,15 @@ static void find_some_match(typval_T *argvars, typval_T *rettv, int type)
}
}
- if (argvars[3].v_type != VAR_UNKNOWN)
- nth = get_tv_number_chk(&argvars[3], &error);
- if (error)
+ if (argvars[3].v_type != VAR_UNKNOWN) {
+ nth = tv_get_number_chk(&argvars[3], &error);
+ }
+ if (error) {
goto theend;
+ }
}
- regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ regmatch.regprog = vim_regcomp((char_u *)pat, RE_MAGIC + RE_STRING);
if (regmatch.regprog != NULL) {
regmatch.rm_ic = p_ic;
@@ -13586,29 +12271,32 @@ static void find_some_match(typval_T *argvars, typval_T *rettv, int type)
/* return list with matched string and submatches */
for (i = 0; i < NSUBEXP; ++i) {
if (regmatch.endp[i] == NULL) {
- list_append_string(rettv->vval.v_list, (char_u *)"", 0);
+ tv_list_append_string(rettv->vval.v_list, NULL, 0);
} else {
- list_append_string(rettv->vval.v_list,
- regmatch.startp[i],
- (int)(regmatch.endp[i] - regmatch.startp[i]));
+ tv_list_append_string(rettv->vval.v_list,
+ (const char *)regmatch.startp[i],
+ (regmatch.endp[i] - regmatch.startp[i]));
}
}
} else if (type == 2) {
- /* return matched string */
- if (l != NULL)
- copy_tv(&li->li_tv, rettv);
- else
- rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
- (int)(regmatch.endp[0] - regmatch.startp[0]));
- } else if (l != NULL)
+ // Return matched string.
+ if (l != NULL) {
+ tv_copy(&li->li_tv, rettv);
+ } else {
+ rettv->vval.v_string = (char_u *)xmemdupz(
+ (const char *)regmatch.startp[0],
+ (size_t)(regmatch.endp[0] - regmatch.startp[0]));
+ }
+ } else if (l != NULL) {
rettv->vval.v_number = idx;
- else {
- if (type != 0)
+ } else {
+ if (type != 0) {
rettv->vval.v_number =
(varnumber_T)(regmatch.startp[0] - str);
- else
+ } else {
rettv->vval.v_number =
(varnumber_T)(regmatch.endp[0] - str);
+ }
rettv->vval.v_number += (varnumber_T)(str - expr);
}
}
@@ -13617,7 +12305,8 @@ static void find_some_match(typval_T *argvars, typval_T *rettv, int type)
if (type == 4 && l == NULL) {
// matchstrpos() without a list: drop the second item
- listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first->li_next);
+ tv_list_item_remove(rettv->vval.v_list,
+ rettv->vval.v_list->lv_first->li_next);
}
theend:
@@ -13638,36 +12327,38 @@ static void f_match(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_matchadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u buf[NUMBUFLEN];
- char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
- char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
- int prio = 10; /* default priority */
+ char grpbuf[NUMBUFLEN];
+ char patbuf[NUMBUFLEN];
+ const char *const grp = tv_get_string_buf_chk(&argvars[0], grpbuf);
+ const char *const pat = tv_get_string_buf_chk(&argvars[1], patbuf);
+ int prio = 10;
int id = -1;
- int error = false;
- char_u *conceal_char = NULL;
+ bool error = false;
+ const char *conceal_char = NULL;
rettv->vval.v_number = -1;
- if (grp == NULL || pat == NULL)
+ if (grp == NULL || pat == NULL) {
return;
+ }
if (argvars[2].v_type != VAR_UNKNOWN) {
- prio = get_tv_number_chk(&argvars[2], &error);
+ prio = tv_get_number_chk(&argvars[2], &error);
if (argvars[3].v_type != VAR_UNKNOWN) {
- id = get_tv_number_chk(&argvars[3], &error);
+ id = tv_get_number_chk(&argvars[3], &error);
if (argvars[4].v_type != VAR_UNKNOWN) {
if (argvars[4].v_type != VAR_DICT) {
EMSG(_(e_dictreq));
return;
}
- if (dict_find(argvars[4].vval.v_dict,
- (char_u *)"conceal", -1) != NULL) {
- conceal_char = get_dict_string(argvars[4].vval.v_dict,
- "conceal", false);
+ dictitem_T *di;
+ if ((di = tv_dict_find(argvars[4].vval.v_dict, S_LEN("conceal")))
+ != NULL) {
+ conceal_char = tv_get_string(&di->di_tv);
}
}
}
}
- if (error == true) {
+ if (error) {
return;
}
if (id >= 1 && id <= 3) {
@@ -13682,10 +12373,9 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_matchaddpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = -1;
-
- char_u buf[NUMBUFLEN];
- char_u *group;
- group = get_tv_string_buf_chk(&argvars[0], buf);
+
+ char buf[NUMBUFLEN];
+ const char *const group = tv_get_string_buf_chk(&argvars[0], buf);
if (group == NULL) {
return;
}
@@ -13701,24 +12391,24 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- int error = false;
+ bool error = false;
int prio = 10;
int id = -1;
- char_u *conceal_char = NULL;
+ const char *conceal_char = NULL;
if (argvars[2].v_type != VAR_UNKNOWN) {
- prio = get_tv_number_chk(&argvars[2], &error);
+ prio = tv_get_number_chk(&argvars[2], &error);
if (argvars[3].v_type != VAR_UNKNOWN) {
- id = get_tv_number_chk(&argvars[3], &error);
+ id = tv_get_number_chk(&argvars[3], &error);
if (argvars[4].v_type != VAR_UNKNOWN) {
if (argvars[4].v_type != VAR_DICT) {
EMSG(_(e_dictreq));
return;
}
- if (dict_find(argvars[4].vval.v_dict,
- (char_u *)"conceal", -1) != NULL) {
- conceal_char = get_dict_string(argvars[4].vval.v_dict,
- "conceal", false);
+ dictitem_T *di;
+ if ((di = tv_dict_find(argvars[4].vval.v_dict, S_LEN("conceal")))
+ != NULL) {
+ conceal_char = tv_get_string(&di->di_tv);
}
}
}
@@ -13742,19 +12432,20 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_matcharg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
- int id = get_tv_number(&argvars[0]);
+ int id = tv_get_number(&argvars[0]);
if (id >= 1 && id <= 3) {
matchitem_T *m;
if ((m = (matchitem_T *)get_match(curwin, id)) != NULL) {
- list_append_string(rettv->vval.v_list, syn_id2name(m->hlg_id), -1);
- list_append_string(rettv->vval.v_list, m->pattern, -1);
+ tv_list_append_string(rettv->vval.v_list,
+ (const char *)syn_id2name(m->hlg_id), -1);
+ tv_list_append_string(rettv->vval.v_list, (const char *)m->pattern, -1);
} else {
- list_append_string(rettv->vval.v_list, NULL, -1);
- list_append_string(rettv->vval.v_list, NULL, -1);
+ tv_list_append_string(rettv->vval.v_list, NULL, 0);
+ tv_list_append_string(rettv->vval.v_list, NULL, 0);
}
}
}
@@ -13765,7 +12456,7 @@ static void f_matcharg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_matchdelete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = match_delete(curwin,
- (int)get_tv_number(&argvars[0]), TRUE);
+ (int)tv_get_number(&argvars[0]), true);
}
/*
@@ -13798,51 +12489,49 @@ static void f_matchstrpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
find_some_match(argvars, rettv, 4);
}
-static void max_min(typval_T *argvars, typval_T *rettv, int domax)
+/// Get maximal/minimal number value in a list or dictionary
+///
+/// @param[in] tv List or dictionary to work with. If it contains something
+/// that is not an integer number (or cannot be coerced to
+/// it) error is given.
+/// @param[out] rettv Location where result will be saved. Only assigns
+/// vval.v_number, type is not touched. Returns zero for
+/// empty lists/dictionaries.
+/// @param[in] domax Determines whether maximal or minimal value is desired.
+static void max_min(const typval_T *const tv, typval_T *const rettv,
+ const bool domax)
+ FUNC_ATTR_NONNULL_ALL
{
- long n = 0;
- long i;
- int error = FALSE;
-
- if (argvars[0].v_type == VAR_LIST) {
- list_T *l;
- listitem_T *li;
+ varnumber_T n = 0;
+ bool error = false;
- l = argvars[0].vval.v_list;
- if (l != NULL) {
- li = l->lv_first;
- if (li != NULL) {
- n = get_tv_number_chk(&li->li_tv, &error);
- for (;; ) {
- li = li->li_next;
- if (li == NULL)
- break;
- i = get_tv_number_chk(&li->li_tv, &error);
- if (domax ? i > n : i < n)
- n = i;
+ if (tv->v_type == VAR_LIST) {
+ const list_T *const l = tv->vval.v_list;
+ if (tv_list_len(l) != 0) {
+ n = tv_get_number_chk(&l->lv_first->li_tv, &error);
+ for (const listitem_T *li = l->lv_first->li_next; li != NULL && !error;
+ li = li->li_next) {
+ const varnumber_T i = tv_get_number_chk(&li->li_tv, &error);
+ if (domax ? i > n : i < n) {
+ n = i;
}
}
}
- } else if (argvars[0].v_type == VAR_DICT) {
- dict_T *d;
- int first = TRUE;
- hashitem_T *hi;
- int todo;
-
- d = argvars[0].vval.v_dict;
- if (d != NULL) {
- todo = (int)d->dv_hashtab.ht_used;
- for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- --todo;
- i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
- if (first) {
- n = i;
- first = FALSE;
- } else if (domax ? i > n : i < n)
- n = i;
+ } else if (tv->v_type == VAR_DICT) {
+ if (tv->vval.v_dict != NULL) {
+ bool first = true;
+ TV_DICT_ITER(tv->vval.v_dict, di, {
+ const varnumber_T i = tv_get_number_chk(&di->di_tv, &error);
+ if (error) {
+ break;
}
- }
+ if (first) {
+ n = i;
+ first = true;
+ } else if (domax ? i > n : i < n) {
+ n = i;
+ }
+ });
}
} else {
EMSG2(_(e_listdictarg), domax ? "max()" : "min()");
@@ -13871,28 +12560,29 @@ static void f_min(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_mkdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *dir;
- char_u buf[NUMBUFLEN];
int prot = 0755;
rettv->vval.v_number = FAIL;
if (check_restricted() || check_secure())
return;
- dir = get_tv_string_buf(&argvars[0], buf);
- if (*dir == NUL)
+ char buf[NUMBUFLEN];
+ const char *const dir = tv_get_string_buf(&argvars[0], buf);
+ if (*dir == NUL) {
rettv->vval.v_number = FAIL;
- else {
- if (*path_tail(dir) == NUL)
- /* remove trailing slashes */
- *path_tail_with_sep(dir) = NUL;
+ } else {
+ if (*path_tail((char_u *)dir) == NUL) {
+ // Remove trailing slashes.
+ *path_tail_with_sep((char_u *)dir) = NUL;
+ }
if (argvars[1].v_type != VAR_UNKNOWN) {
- if (argvars[2].v_type != VAR_UNKNOWN)
- prot = get_tv_number_chk(&argvars[2], NULL);
- if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0) {
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ prot = tv_get_number_chk(&argvars[2], NULL);
+ }
+ if (prot != -1 && strcmp(tv_get_string(&argvars[1]), "p") == 0) {
char *failed_dir;
- int ret = os_mkdir_recurse((char *) dir, prot, &failed_dir);
+ int ret = os_mkdir_recurse(dir, prot, &failed_dir);
if (ret != 0) {
EMSG3(_(e_mkdir), failed_dir, os_strerror(ret));
xfree(failed_dir);
@@ -13972,7 +12662,7 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, FunPtr fptr)
EMSG2(_(e_listarg), "msgpackdump()");
return;
}
- list_T *ret_list = rettv_list_alloc(rettv);
+ list_T *ret_list = tv_list_alloc_ret(rettv);
const list_T *list = argvars[0].vval.v_list;
if (list == NULL) {
return;
@@ -14000,7 +12690,7 @@ static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
EMSG2(_(e_listarg), "msgpackparse()");
return;
}
- list_T *ret_list = rettv_list_alloc(rettv);
+ list_T *ret_list = tv_list_alloc_ret(rettv);
const list_T *list = argvars[0].vval.v_list;
if (list == NULL || list->lv_first == NULL) {
return;
@@ -14045,9 +12735,9 @@ static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
goto f_msgpackparse_exit;
}
if (result == MSGPACK_UNPACK_SUCCESS) {
- listitem_T *li = listitem_alloc();
+ listitem_T *li = tv_list_item_alloc();
li->li_tv.v_type = VAR_UNKNOWN;
- list_append(ret_list, li);
+ tv_list_append(ret_list, li);
if (msgpack_to_vim(unpacked.data, &li->li_tv) == FAIL) {
EMSG2(_(e_invarg2), "Failed to convert msgpack string");
goto f_msgpackparse_exit;
@@ -14078,13 +12768,14 @@ static void f_nextnonblank(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
linenr_T lnum;
- for (lnum = get_tv_lnum(argvars);; ++lnum) {
+ for (lnum = tv_get_lnum(argvars);; lnum++) {
if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count) {
lnum = 0;
break;
}
- if (*skipwhite(ml_get(lnum)) != NUL)
+ if (*skipwhite(ml_get(lnum)) != NUL) {
break;
+ }
}
rettv->vval.v_number = lnum;
}
@@ -14099,14 +12790,16 @@ static void f_nr2char(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (has_mbyte) {
int utf8 = 0;
- if (argvars[1].v_type != VAR_UNKNOWN)
- utf8 = get_tv_number_chk(&argvars[1], NULL);
- if (utf8)
- buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
- else
- buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ utf8 = tv_get_number_chk(&argvars[1], NULL);
+ }
+ if (utf8) {
+ buf[(*utf_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
+ } else {
+ buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
+ }
} else {
- buf[0] = (char_u)get_tv_number(&argvars[0]);
+ buf[0] = (char_u)tv_get_number(&argvars[0]);
buf[1] = NUL;
}
rettv->v_type = VAR_STRING;
@@ -14118,8 +12811,8 @@ static void f_nr2char(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_or(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
- | get_tv_number_chk(&argvars[1], NULL);
+ rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
+ | tv_get_number_chk(&argvars[1], NULL);
}
/*
@@ -14128,11 +12821,11 @@ static void f_or(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_pathshorten(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = get_tv_string_chk(&argvars[0]);
- if (!rettv->vval.v_string) {
+ const char *const s = tv_get_string_chk(&argvars[0]);
+ if (!s) {
return;
}
- rettv->vval.v_string = shorten_dir(vim_strsave(rettv->vval.v_string));
+ rettv->vval.v_string = shorten_dir((char_u *)xstrdup(s));
}
/*
@@ -14140,14 +12833,15 @@ static void f_pathshorten(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_pow(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- float_T fx, fy;
+ float_T fx;
+ float_T fy;
rettv->v_type = VAR_FLOAT;
- if (get_float_arg(argvars, &fx) == OK
- && get_float_arg(&argvars[1], &fy) == OK)
+ if (tv_get_float_chk(argvars, &fx) && tv_get_float_chk(&argvars[1], &fy)) {
rettv->vval.v_float = pow(fx, fy);
- else
+ } else {
rettv->vval.v_float = 0.0;
+ }
}
/*
@@ -14155,14 +12849,14 @@ static void f_pow(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_prevnonblank(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T lnum;
-
- lnum = get_tv_lnum(argvars);
- if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
+ linenr_T lnum = tv_get_lnum(argvars);
+ if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) {
lnum = 0;
- else
- while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
- --lnum;
+ } else {
+ while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL) {
+ lnum--;
+ }
+ }
rettv->vval.v_number = lnum;
}
@@ -14174,14 +12868,13 @@ static void f_printf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
{
- char_u buf[NUMBUFLEN];
int len;
int saved_did_emsg = did_emsg;
- char *fmt;
- /* Get the required length, allocate the buffer and do it for real. */
- did_emsg = FALSE;
- fmt = (char *)get_tv_string_buf(&argvars[0], buf);
+ // Get the required length, allocate the buffer and do it for real.
+ did_emsg = false;
+ char buf[NUMBUFLEN];
+ const char *fmt = tv_get_string_buf(&argvars[0], buf);
len = vim_vsnprintf(NULL, 0, fmt, dummy_ap, argvars + 1);
if (!did_emsg) {
char *s = xmalloc(len + 1);
@@ -14222,32 +12915,34 @@ static void f_py3eval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_range(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- long start;
- long end;
- long stride = 1;
+ varnumber_T start;
+ varnumber_T end;
+ varnumber_T stride = 1;
long i;
- int error = FALSE;
+ bool error = false;
- start = get_tv_number_chk(&argvars[0], &error);
+ start = tv_get_number_chk(&argvars[0], &error);
if (argvars[1].v_type == VAR_UNKNOWN) {
end = start - 1;
start = 0;
} else {
- end = get_tv_number_chk(&argvars[1], &error);
- if (argvars[2].v_type != VAR_UNKNOWN)
- stride = get_tv_number_chk(&argvars[2], &error);
+ end = tv_get_number_chk(&argvars[1], &error);
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ stride = tv_get_number_chk(&argvars[2], &error);
+ }
}
- if (error)
- return; /* type error; errmsg already given */
- if (stride == 0)
- EMSG(_("E726: Stride is zero"));
- else if (stride > 0 ? end + 1 < start : end - 1 > start)
- EMSG(_("E727: Start past end"));
- else {
- rettv_list_alloc(rettv);
+ if (error) {
+ return; // Type error; errmsg already given.
+ }
+ if (stride == 0) {
+ emsgf(_("E726: Stride is zero"));
+ } else if (stride > 0 ? end + 1 < start : end - 1 > start) {
+ emsgf(_("E727: Start past end"));
+ } else {
+ tv_list_alloc_ret(rettv);
for (i = start; stride > 0 ? i <= end : i >= end; i += stride) {
- list_append_number(rettv->vval.v_list, (varnumber_T)i);
+ tv_list_append_number(rettv->vval.v_list, (varnumber_T)i);
}
}
}
@@ -14257,8 +12952,7 @@ static void f_range(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int binary = FALSE;
- char_u *fname;
+ bool binary = false;
FILE *fd;
char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
int io_size = sizeof(buf);
@@ -14272,19 +12966,21 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
char_u *start; /* start of current line */
if (argvars[1].v_type != VAR_UNKNOWN) {
- if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
- binary = TRUE;
- if (argvars[2].v_type != VAR_UNKNOWN)
- maxline = get_tv_number(&argvars[2]);
+ if (strcmp(tv_get_string(&argvars[1]), "b") == 0) {
+ binary = true;
+ }
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ maxline = tv_get_number(&argvars[2]);
+ }
}
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
- /* Always open the file in binary mode, library functions have a mind of
- * their own about CR-LF conversion. */
- fname = get_tv_string(&argvars[0]);
- if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL) {
- EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
+ // Always open the file in binary mode, library functions have a mind of
+ // their own about CR-LF conversion.
+ const char *const fname = tv_get_string(&argvars[0]);
+ if (*fname == NUL || (fd = mch_fopen(fname, READBIN)) == NULL) {
+ EMSG2(_(e_notopen), *fname == NUL ? _("<empty>") : fname);
return;
}
@@ -14327,11 +13023,11 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
prevlen = prevsize = 0;
}
- li = listitem_alloc();
+ li = tv_list_item_alloc();
li->li_tv.v_type = VAR_STRING;
li->li_tv.v_lock = 0;
li->li_tv.vval.v_string = s;
- list_append(rettv->vval.v_list, li);
+ tv_list_append(rettv->vval.v_list, li);
start = p + 1; /* step over newline */
if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
@@ -14406,8 +13102,8 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
if (maxline < 0)
while (cnt > -maxline) {
- listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
- --cnt;
+ tv_list_item_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
+ cnt--;
}
xfree(prev);
@@ -14429,9 +13125,9 @@ static int list2proftime(typval_T *arg, proftime_T *tm) FUNC_ATTR_NONNULL_ALL
return FAIL;
}
- int error = false;
- varnumber_T n1 = list_find_nr(arg->vval.v_list, 0L, &error);
- varnumber_T n2 = list_find_nr(arg->vval.v_list, 1L, &error);
+ bool error = false;
+ varnumber_T n1 = tv_list_find_nr(arg->vval.v_list, 0L, &error);
+ varnumber_T n2 = tv_list_find_nr(arg->vval.v_list, 1L, &error);
if (error) {
return FAIL;
}
@@ -14490,9 +13186,9 @@ static void f_reltime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
STATIC_ASSERT(sizeof(u.prof) == sizeof(u) && sizeof(u.split) == sizeof(u),
"type punning will produce incorrect results on this platform");
- rettv_list_alloc(rettv);
- list_append_number(rettv->vval.v_list, u.split.high);
- list_append_number(rettv->vval.v_list, u.split.low);
+ tv_list_alloc_ret(rettv);
+ tv_list_append_number(rettv->vval.v_list, u.split.high);
+ tv_list_append_number(rettv->vval.v_list, u.split.low);
}
/// f_reltimestr - return a string that represents the value of {time}
@@ -14522,7 +13218,6 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
listitem_T *li;
long idx;
long end;
- char_u *key;
dict_T *d;
dictitem_T *di;
const char *const arg_errmsg = _("remove() argument");
@@ -14533,18 +13228,18 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
EMSG2(_(e_toomanyarg), "remove()");
} else if ((d = argvars[0].vval.v_dict) != NULL
&& !tv_check_lock(d->dv_lock, arg_errmsg, arg_errmsg_len)) {
- key = get_tv_string_chk(&argvars[1]);
+ const char *key = tv_get_string_chk(&argvars[1]);
if (key != NULL) {
- di = dict_find(d, key, -1);
+ di = tv_dict_find(d, key, -1);
if (di == NULL) {
EMSG2(_(e_dictkey), key);
} else if (!var_check_fixed(di->di_flags, arg_errmsg, arg_errmsg_len)
&& !var_check_ro(di->di_flags, arg_errmsg, arg_errmsg_len)) {
*rettv = di->di_tv;
- init_tv(&di->di_tv);
- dictitem_remove(d, di);
- if (is_watched(d)) {
- dictwatcher_notify(d, (char *)key, NULL, rettv);
+ di->di_tv = TV_INITIAL_VALUE;
+ tv_dict_item_remove(d, di);
+ if (tv_dict_is_watched(d)) {
+ tv_dict_watcher_notify(d, key, NULL, rettv);
}
}
}
@@ -14553,27 +13248,27 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
EMSG2(_(e_listdictarg), "remove()");
} else if ((l = argvars[0].vval.v_list) != NULL
&& !tv_check_lock(l->lv_lock, arg_errmsg, arg_errmsg_len)) {
- int error = (int)false;
+ bool error = false;
- idx = get_tv_number_chk(&argvars[1], &error);
- if (error)
- ; /* type error: do nothing, errmsg already given */
- else if ((item = list_find(l, idx)) == NULL)
+ idx = tv_get_number_chk(&argvars[1], &error);
+ if (error) {
+ // Type error: do nothing, errmsg already given.
+ } else if ((item = tv_list_find(l, idx)) == NULL) {
EMSGN(_(e_listidx), idx);
- else {
+ } else {
if (argvars[2].v_type == VAR_UNKNOWN) {
// Remove one item, return its value.
- vim_list_remove(l, item, item);
+ tv_list_remove_items(l, item, item);
*rettv = item->li_tv;
xfree(item);
} else {
- /* Remove range of items, return list with values. */
- end = get_tv_number_chk(&argvars[2], &error);
- if (error)
- ; /* type error: do nothing */
- else if ((item2 = list_find(l, end)) == NULL)
+ // Remove range of items, return list with values.
+ end = tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ // Type error: do nothing.
+ } else if ((item2 = tv_list_find(l, end)) == NULL) {
EMSGN(_(e_listidx), end);
- else {
+ } else {
int cnt = 0;
for (li = item; li != NULL; li = li->li_next) {
@@ -14581,11 +13276,11 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (li == item2)
break;
}
- if (li == NULL) /* didn't find "item2" after "item" */
- EMSG(_(e_invrange));
- else {
- vim_list_remove(l, item, item2);
- l = rettv_list_alloc(rettv);
+ if (li == NULL) { // Didn't find "item2" after "item".
+ emsgf(_(e_invrange));
+ } else {
+ tv_list_remove_items(l, item, item2);
+ l = tv_list_alloc_ret(rettv);
l->lv_first = item;
l->lv_last = item2;
item->li_prev = NULL;
@@ -14603,13 +13298,14 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_rename(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u buf[NUMBUFLEN];
-
- if (check_restricted() || check_secure())
+ if (check_restricted() || check_secure()) {
rettv->vval.v_number = -1;
- else
- rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
- get_tv_string_buf(&argvars[1], buf));
+ } else {
+ char buf[NUMBUFLEN];
+ rettv->vval.v_number = vim_rename(
+ (const char_u *)tv_get_string(&argvars[0]),
+ (const char_u *)tv_get_string_buf(&argvars[1], buf));
+ }
}
/*
@@ -14617,32 +13313,37 @@ static void f_rename(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_repeat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *p;
- int n;
-
- n = get_tv_number(&argvars[1]);
+ varnumber_T n = tv_get_number(&argvars[1]);
if (argvars[0].v_type == VAR_LIST) {
- rettv_list_alloc(rettv);
- if (argvars[0].vval.v_list != NULL) {
- while (n-- > 0) {
- list_extend(rettv->vval.v_list, argvars[0].vval.v_list, NULL);
- }
+ tv_list_alloc_ret(rettv);
+ while (n-- > 0) {
+ tv_list_extend(rettv->vval.v_list, argvars[0].vval.v_list, NULL);
}
} else {
- p = get_tv_string(&argvars[0]);
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
+ if (n <= 0) {
+ return;
+ }
- int slen = (int)STRLEN(p);
- int len = slen * n;
- if (len <= 0)
+ const char *const p = tv_get_string(&argvars[0]);
+
+ const size_t slen = strlen(p);
+ if (slen == 0) {
+ return;
+ }
+ const size_t len = slen * n;
+ // Detect overflow.
+ if (len / n != slen) {
return;
+ }
- char_u *r = xmallocz(len);
- for (int i = 0; i < n; i++)
- memmove(r + i * slen, p, (size_t)slen);
+ char *const r = xmallocz(len);
+ for (varnumber_T i = 0; i < n; i++) {
+ memmove(r + i * slen, p, slen);
+ }
- rettv->vval.v_string = r;
+ rettv->vval.v_string = (char_u *)r;
}
}
@@ -14651,59 +13352,49 @@ static void f_repeat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *p;
-#ifdef HAVE_READLINK
- char_u *buf = NULL;
-#endif
-
- p = get_tv_string(&argvars[0]);
+ rettv->v_type = VAR_STRING;
+ const char *fname = tv_get_string(&argvars[0]);
#ifdef WIN32
- {
- char *v = os_resolve_shortcut(p);
- if (v != NULL) {
- rettv->vval.v_string = (char_u *)v;
- } else {
- rettv->vval.v_string = vim_strsave(p);
- }
- }
+ char *const v = os_resolve_shortcut(fname);
+ rettv->vval.v_string = (char_u *)(v == NULL ? xstrdup(fname) : v);
#else
# ifdef HAVE_READLINK
{
- char_u *cpy;
- int len;
- char_u *remain = NULL;
- char_u *q;
- int is_relative_to_current = FALSE;
- int has_trailing_pathsep = FALSE;
+ bool is_relative_to_current = false;
+ bool has_trailing_pathsep = false;
int limit = 100;
- p = vim_strsave(p);
+ char *p = xstrdup(fname);
if (p[0] == '.' && (vim_ispathsep(p[1])
- || (p[1] == '.' && (vim_ispathsep(p[2])))))
- is_relative_to_current = TRUE;
+ || (p[1] == '.' && (vim_ispathsep(p[2]))))) {
+ is_relative_to_current = true;
+ }
- len = STRLEN(p);
- if (len > 0 && after_pathsep((char *)p, (char *)p + len)) {
- has_trailing_pathsep = TRUE;
- p[len - 1] = NUL; /* the trailing slash breaks readlink() */
+ ptrdiff_t len = (ptrdiff_t)strlen(p);
+ if (len > 0 && after_pathsep(p, p + len)) {
+ has_trailing_pathsep = true;
+ p[len - 1] = NUL; // The trailing slash breaks readlink().
}
- q = path_next_component(p);
+ char *q = (char *)path_next_component(p);
+ char *remain = NULL;
if (*q != NUL) {
- /* Separate the first path component in "p", and keep the
- * remainder (beginning with the path separator). */
- remain = vim_strsave(q - 1);
+ // Separate the first path component in "p", and keep the
+ // remainder (beginning with the path separator).
+ remain = xstrdup(q - 1);
q[-1] = NUL;
}
- buf = xmallocz(MAXPATHL);
+ char *const buf = xmallocz(MAXPATHL);
+ char *cpy;
for (;; ) {
for (;; ) {
- len = readlink((char *)p, (char *)buf, MAXPATHL);
- if (len <= 0)
+ len = readlink(p, buf, MAXPATHL);
+ if (len <= 0) {
break;
+ }
buf[len] = NUL;
if (limit-- == 0) {
@@ -14711,66 +13402,72 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
xfree(remain);
EMSG(_("E655: Too many symbolic links (cycle?)"));
rettv->vval.v_string = NULL;
- goto fail;
+ xfree(buf);
+ return;
}
- /* Ensure that the result will have a trailing path separator
- * if the argument has one. */
- if (remain == NULL && has_trailing_pathsep)
- add_pathsep((char *)buf);
+ // Ensure that the result will have a trailing path separator
+ // if the argument has one. */
+ if (remain == NULL && has_trailing_pathsep) {
+ add_pathsep(buf);
+ }
- /* Separate the first path component in the link value and
- * concatenate the remainders. */
- q = path_next_component(vim_ispathsep(*buf) ? buf + 1 : buf);
+ // Separate the first path component in the link value and
+ // concatenate the remainders. */
+ q = (char *)path_next_component(vim_ispathsep(*buf) ? buf + 1 : buf);
if (*q != NUL) {
cpy = remain;
- remain = remain ?
- concat_str(q - 1, remain) : (char_u *) xstrdup((char *)q - 1);
+ remain = (remain
+ ? (char *)concat_str((char_u *)q - 1, (char_u *)remain)
+ : xstrdup(q - 1));
xfree(cpy);
q[-1] = NUL;
}
- q = path_tail(p);
+ q = (char *)path_tail((char_u *)p);
if (q > p && *q == NUL) {
- /* Ignore trailing path separator. */
+ // Ignore trailing path separator.
q[-1] = NUL;
- q = path_tail(p);
+ q = (char *)path_tail((char_u *)p);
}
- if (q > p && !path_is_absolute_path(buf)) {
- /* symlink is relative to directory of argument */
- cpy = xmalloc(STRLEN(p) + STRLEN(buf) + 1);
- STRCPY(cpy, p);
- STRCPY(path_tail(cpy), buf);
- xfree(p);
- p = cpy;
+ if (q > p && !path_is_absolute_path((const char_u *)buf)) {
+ // Symlink is relative to directory of argument. Replace the
+ // symlink with the resolved name in the same directory.
+ const size_t p_len = strlen(p);
+ const size_t buf_len = strlen(buf);
+ p = xrealloc(p, p_len + buf_len + 1);
+ memcpy(path_tail((char_u *)p), buf, buf_len + 1);
} else {
xfree(p);
- p = vim_strsave(buf);
+ p = xstrdup(buf);
}
}
- if (remain == NULL)
+ if (remain == NULL) {
break;
+ }
- /* Append the first path component of "remain" to "p". */
- q = path_next_component(remain + 1);
+ // Append the first path component of "remain" to "p".
+ q = (char *)path_next_component(remain + 1);
len = q - remain - (*q != NUL);
- cpy = vim_strnsave(p, STRLEN(p) + len);
- STRNCAT(cpy, remain, len);
+ const size_t p_len = strlen(p);
+ cpy = xmallocz(p_len + len);
+ memcpy(cpy, p, p_len + 1);
+ xstrlcat(cpy + p_len, remain, len + 1);
xfree(p);
p = cpy;
- /* Shorten "remain". */
- if (*q != NUL)
+ // Shorten "remain".
+ if (*q != NUL) {
STRMOVE(remain, q - 1);
- else {
+ } else {
xfree(remain);
remain = NULL;
}
}
- /* If the result is a relative path name, make it explicitly relative to
- * the current directory if and only if the argument had this form. */
+ // If the result is a relative path name, make it explicitly relative to
+ // the current directory if and only if the argument had this form.
if (!vim_ispathsep(*p)) {
if (is_relative_to_current
&& *p != NUL
@@ -14780,42 +13477,40 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|| (p[1] == '.'
&& (p[2] == NUL
|| vim_ispathsep(p[2])))))) {
- /* Prepend "./". */
- cpy = concat_str((char_u *)"./", p);
+ // Prepend "./".
+ cpy = (char *)concat_str((const char_u *)"./", (const char_u *)p);
xfree(p);
p = cpy;
} else if (!is_relative_to_current) {
- /* Strip leading "./". */
+ // Strip leading "./".
q = p;
- while (q[0] == '.' && vim_ispathsep(q[1]))
+ while (q[0] == '.' && vim_ispathsep(q[1])) {
q += 2;
- if (q > p)
+ }
+ if (q > p) {
STRMOVE(p, p + 2);
+ }
}
}
- /* Ensure that the result will have no trailing path separator
- * if the argument had none. But keep "/" or "//". */
+ // Ensure that the result will have no trailing path separator
+ // if the argument had none. But keep "/" or "//".
if (!has_trailing_pathsep) {
- q = p + STRLEN(p);
- if (after_pathsep((char *)p, (char *)q))
- *path_tail_with_sep(p) = NUL;
+ q = p + strlen(p);
+ if (after_pathsep(p, q)) {
+ *path_tail_with_sep((char_u *)p) = NUL;
+ }
}
- rettv->vval.v_string = p;
+ rettv->vval.v_string = (char_u *)p;
+ xfree(buf);
}
# else
- rettv->vval.v_string = vim_strsave(p);
+ rettv->vval.v_string = (char_u *)xstrdup(p);
# endif
#endif
simplify_filename(rettv->vval.v_string);
-
-#ifdef HAVE_READLINK
-fail:
- xfree(buf);
-#endif
- rettv->v_type = VAR_STRING;
}
/*
@@ -14836,12 +13531,12 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
l->lv_len = 0;
while (li != NULL) {
listitem_T *const ni = li->li_prev;
- list_append(l, li);
+ tv_list_append(l, li);
li = ni;
}
rettv->vval.v_list = l;
rettv->v_type = VAR_LIST;
- ++l->lv_refcount;
+ l->lv_refcount++;
l->lv_idx = l->lv_len - l->lv_idx - 1;
}
}
@@ -14863,40 +13558,45 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static int get_search_arg(typval_T *varp, int *flagsp)
{
int dir = FORWARD;
- char_u *flags;
- char_u nbuf[NUMBUFLEN];
int mask;
if (varp->v_type != VAR_UNKNOWN) {
- flags = get_tv_string_buf_chk(varp, nbuf);
- if (flags == NULL)
- return 0; /* type error; errmsg already given */
+ char nbuf[NUMBUFLEN];
+ const char *flags = tv_get_string_buf_chk(varp, nbuf);
+ if (flags == NULL) {
+ return 0; // Type error; errmsg already given.
+ }
while (*flags != NUL) {
switch (*flags) {
- case 'b': dir = BACKWARD; break;
- case 'w': p_ws = true; break;
- case 'W': p_ws = false; break;
- default: mask = 0;
- if (flagsp != NULL)
- switch (*flags) {
- case 'c': mask = SP_START; break;
- case 'e': mask = SP_END; break;
- case 'm': mask = SP_RETCOUNT; break;
- case 'n': mask = SP_NOMOVE; break;
- case 'p': mask = SP_SUBPAT; break;
- case 'r': mask = SP_REPEAT; break;
- case 's': mask = SP_SETPCMARK; break;
- case 'z': mask = SP_COLUMN; break;
+ case 'b': dir = BACKWARD; break;
+ case 'w': p_ws = true; break;
+ case 'W': p_ws = false; break;
+ default: {
+ mask = 0;
+ if (flagsp != NULL) {
+ switch (*flags) {
+ case 'c': mask = SP_START; break;
+ case 'e': mask = SP_END; break;
+ case 'm': mask = SP_RETCOUNT; break;
+ case 'n': mask = SP_NOMOVE; break;
+ case 'p': mask = SP_SUBPAT; break;
+ case 'r': mask = SP_REPEAT; break;
+ case 's': mask = SP_SETPCMARK; break;
+ case 'z': mask = SP_COLUMN; break;
+ }
}
- if (mask == 0) {
- EMSG2(_(e_invarg2), flags);
- dir = 0;
- } else
- *flagsp |= mask;
+ if (mask == 0) {
+ emsgf(_(e_invarg2), flags);
+ dir = 0;
+ } else {
+ *flagsp |= mask;
+ }
+ }
}
- if (dir == 0)
+ if (dir == 0) {
break;
- ++flags;
+ }
+ flags++;
}
}
return dir;
@@ -14906,7 +13606,6 @@ static int get_search_arg(typval_T *varp, int *flagsp)
static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
{
int flags;
- char_u *pat;
pos_T pos;
pos_T save_cursor;
bool save_p_ws = p_ws;
@@ -14918,10 +13617,11 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
int options = SEARCH_KEEP;
int subpatnum;
- pat = get_tv_string(&argvars[0]);
- dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
- if (dir == 0)
+ const char *const pat = tv_get_string(&argvars[0]);
+ dir = get_search_arg(&argvars[1], flagsp); // May set p_ws.
+ if (dir == 0) {
goto theend;
+ }
flags = *flagsp;
if (flags & SP_START) {
options |= SEARCH_START;
@@ -14935,13 +13635,15 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
/* Optional arguments: line number to stop searching and timeout. */
if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) {
- lnum_stop = get_tv_number_chk(&argvars[2], NULL);
- if (lnum_stop < 0)
+ lnum_stop = tv_get_number_chk(&argvars[2], NULL);
+ if (lnum_stop < 0) {
goto theend;
+ }
if (argvars[3].v_type != VAR_UNKNOWN) {
- time_limit = get_tv_number_chk(&argvars[3], NULL);
- if (time_limit < 0)
+ time_limit = tv_get_number_chk(&argvars[3], NULL);
+ if (time_limit < 0) {
goto theend;
+ }
}
}
@@ -14956,13 +13658,13 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
*/
if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
|| ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) {
- EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
+ EMSG2(_(e_invarg2), tv_get_string(&argvars[1]));
goto theend;
}
pos = save_cursor = curwin->w_cursor;
- subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
- options, RE_SEARCH, (linenr_T)lnum_stop, &tm);
+ subpatnum = searchit(curwin, curbuf, &pos, dir, (char_u *)pat, 1,
+ options, RE_SEARCH, (linenr_T)lnum_stop, &tm);
if (subpatnum != FAIL) {
if (flags & SP_SUBPAT)
retval = subpatnum;
@@ -15019,7 +13721,7 @@ static void f_rpcnotify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (!channel_send_event((uint64_t)argvars[0].vval.v_number,
- (char *)get_tv_string(&argvars[1]),
+ tv_get_string(&argvars[1]),
args)) {
EMSG2(_(e_invarg2), "Channel doesn't exist");
return;
@@ -15086,7 +13788,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
Error err = ERROR_INIT;
Object result = channel_send_call((uint64_t)argvars[0].vval.v_number,
- (char *)get_tv_string(&argvars[1]),
+ tv_get_string(&argvars[1]),
args,
&err);
@@ -15161,7 +13863,7 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Copy arguments to the vector
if (argsl > 0) {
for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) {
- argv[i++] = xstrdup((char *) get_tv_string(&arg->li_tv));
+ argv[i++] = xstrdup(tv_get_string(&arg->li_tv));
}
}
@@ -15203,17 +13905,16 @@ static void f_rpcstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int row;
- int col;
int c;
- row = get_tv_number_chk(&argvars[0], NULL) - 1;
- col = get_tv_number_chk(&argvars[1], NULL) - 1;
+ const int row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
+ const int col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
if (row < 0 || row >= screen_Rows
- || col < 0 || col >= screen_Columns)
+ || col < 0 || col >= screen_Columns) {
c = -1;
- else
+ } else {
c = ScreenAttrs[LineOffset[row] + col];
+ }
rettv->vval.v_number = c;
}
@@ -15222,17 +13923,15 @@ static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int row;
- int col;
int off;
int c;
- row = get_tv_number_chk(&argvars[0], NULL) - 1;
- col = get_tv_number_chk(&argvars[1], NULL) - 1;
+ const int row = tv_get_number_chk(&argvars[0], NULL) - 1;
+ const int col = tv_get_number_chk(&argvars[1], NULL) - 1;
if (row < 0 || row >= screen_Rows
- || col < 0 || col >= screen_Columns)
+ || col < 0 || col >= screen_Columns) {
c = -1;
- else {
+ } else {
off = LineOffset[row] + col;
if (enc_utf8 && ScreenLinesUC[off] != 0)
c = ScreenLinesUC[off];
@@ -15277,19 +13976,21 @@ static void f_searchdecl(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int locally = 1;
int thisblock = 0;
- int error = FALSE;
+ bool error = false;
rettv->vval.v_number = 1; /* default: FAIL */
- char_u *name = get_tv_string_chk(&argvars[0]);
+ const char *const name = tv_get_string_chk(&argvars[0]);
if (argvars[1].v_type != VAR_UNKNOWN) {
- locally = get_tv_number_chk(&argvars[1], &error) == 0;
- if (!error && argvars[2].v_type != VAR_UNKNOWN)
- thisblock = get_tv_number_chk(&argvars[2], &error) != 0;
+ locally = tv_get_number_chk(&argvars[1], &error) == 0;
+ if (!error && argvars[2].v_type != VAR_UNKNOWN) {
+ thisblock = tv_get_number_chk(&argvars[2], &error) != 0;
+ }
}
- if (!error && name != NULL)
- rettv->vval.v_number = find_decl(name, STRLEN(name), locally,
+ if (!error && name != NULL) {
+ rettv->vval.v_number = find_decl((char_u *)name, strlen(name), locally,
thisblock, SEARCH_KEEP) == FAIL;
+ }
}
/*
@@ -15297,65 +13998,70 @@ static void f_searchdecl(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static int searchpair_cmn(typval_T *argvars, pos_T *match_pos)
{
- char_u *spat, *mpat, *epat;
- char_u *skip;
bool save_p_ws = p_ws;
int dir;
int flags = 0;
- char_u nbuf1[NUMBUFLEN];
- char_u nbuf2[NUMBUFLEN];
- char_u nbuf3[NUMBUFLEN];
- int retval = 0; /* default: FAIL */
+ int retval = 0; // default: FAIL
long lnum_stop = 0;
long time_limit = 0;
- /* Get the three pattern arguments: start, middle, end. */
- spat = get_tv_string_chk(&argvars[0]);
- mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
- epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
- if (spat == NULL || mpat == NULL || epat == NULL)
- goto theend; /* type error */
+ // Get the three pattern arguments: start, middle, end.
+ char nbuf1[NUMBUFLEN];
+ char nbuf2[NUMBUFLEN];
+ char nbuf3[NUMBUFLEN];
+ const char *spat = tv_get_string_chk(&argvars[0]);
+ const char *mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
+ const char *epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
+ if (spat == NULL || mpat == NULL || epat == NULL) {
+ goto theend; // Type error.
+ }
- /* Handle the optional fourth argument: flags */
- dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
- if (dir == 0)
+ // Handle the optional fourth argument: flags.
+ dir = get_search_arg(&argvars[3], &flags); // may set p_ws.
+ if (dir == 0) {
goto theend;
+ }
- /* Don't accept SP_END or SP_SUBPAT.
- * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
- */
+ // Don't accept SP_END or SP_SUBPAT.
+ // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
if ((flags & (SP_END | SP_SUBPAT)) != 0
|| ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) {
- EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
+ EMSG2(_(e_invarg2), tv_get_string(&argvars[3]));
goto theend;
}
- /* Using 'r' implies 'W', otherwise it doesn't work. */
- if (flags & SP_REPEAT)
+ // Using 'r' implies 'W', otherwise it doesn't work.
+ if (flags & SP_REPEAT) {
p_ws = false;
+ }
- /* Optional fifth argument: skip expression */
+ // Optional fifth argument: skip expression.
+ const char *skip;
if (argvars[3].v_type == VAR_UNKNOWN
- || argvars[4].v_type == VAR_UNKNOWN)
- skip = (char_u *)"";
- else {
- skip = get_tv_string_buf_chk(&argvars[4], nbuf3);
+ || argvars[4].v_type == VAR_UNKNOWN) {
+ skip = "";
+ } else {
+ skip = tv_get_string_buf_chk(&argvars[4], nbuf3);
+ if (skip == NULL) {
+ goto theend; // Type error.
+ }
if (argvars[5].v_type != VAR_UNKNOWN) {
- lnum_stop = get_tv_number_chk(&argvars[5], NULL);
- if (lnum_stop < 0)
+ lnum_stop = tv_get_number_chk(&argvars[5], NULL);
+ if (lnum_stop < 0) {
goto theend;
+ }
if (argvars[6].v_type != VAR_UNKNOWN) {
- time_limit = get_tv_number_chk(&argvars[6], NULL);
- if (time_limit < 0)
+ time_limit = tv_get_number_chk(&argvars[6], NULL);
+ if (time_limit < 0) {
goto theend;
+ }
}
}
}
- if (skip == NULL)
- goto theend; /* type error */
- retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
- match_pos, lnum_stop, time_limit);
+ retval = do_searchpair(
+ (char_u *)spat, (char_u *)mpat, (char_u *)epat, dir, (char_u *)skip,
+ flags, match_pos, lnum_stop, time_limit);
theend:
p_ws = save_p_ws;
@@ -15380,15 +14086,15 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int lnum = 0;
int col = 0;
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
if (searchpair_cmn(argvars, &match_pos) > 0) {
lnum = match_pos.lnum;
col = match_pos.col;
}
- list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
- list_append_number(rettv->vval.v_list, (varnumber_T)col);
+ tv_list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
+ tv_list_append_number(rettv->vval.v_list, (varnumber_T)col);
}
/*
@@ -15420,7 +14126,6 @@ do_searchpair (
int n;
int r;
int nest = 1;
- int err;
int options = SEARCH_KEEP;
proftime_T tm;
@@ -15476,7 +14181,8 @@ do_searchpair (
if (*skip != NUL) {
save_pos = curwin->w_cursor;
curwin->w_cursor = pos;
- r = eval_to_bool(skip, &err, NULL, FALSE);
+ bool err;
+ r = eval_to_bool(skip, &err, NULL, false);
curwin->w_cursor = save_pos;
if (err) {
/* Evaluating {skip} caused an error, break here. */
@@ -15547,7 +14253,7 @@ static void f_searchpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int n;
int flags = 0;
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
n = search_cmn(argvars, &match_pos, &flags);
if (n > 0) {
@@ -15555,10 +14261,11 @@ static void f_searchpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
col = match_pos.col;
}
- list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
- list_append_number(rettv->vval.v_list, (varnumber_T)col);
- if (flags & SP_SUBPAT)
- list_append_number(rettv->vval.v_list, (varnumber_T)n);
+ tv_list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
+ tv_list_append_number(rettv->vval.v_list, (varnumber_T)col);
+ if (flags & SP_SUBPAT) {
+ tv_list_append_number(rettv->vval.v_list, (varnumber_T)n);
+ }
}
/// "serverlist()" function
@@ -15568,13 +14275,13 @@ static void f_serverlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
char **addrs = server_address_list(&n);
// Copy addrs into a linked list.
- list_T *l = rettv_list_alloc(rettv);
+ list_T *l = tv_list_alloc_ret(rettv);
for (size_t i = 0; i < n; i++) {
- listitem_T *li = listitem_alloc();
+ listitem_T *li = tv_list_item_alloc();
li->li_tv.v_type = VAR_STRING;
li->li_tv.v_lock = 0;
- li->li_tv.vval.v_string = (char_u *) addrs[i];
- list_append(l, li);
+ li->li_tv.vval.v_string = (char_u *)addrs[i];
+ tv_list_append(l, li);
}
xfree(addrs);
}
@@ -15595,7 +14302,7 @@ static void f_serverstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
EMSG(_(e_invarg));
return;
} else {
- rettv->vval.v_string = vim_strsave(get_tv_string(argvars));
+ rettv->vval.v_string = (char_u *)xstrdup(tv_get_string(argvars));
}
} else {
rettv->vval.v_string = (char_u *)server_address_new();
@@ -15629,32 +14336,30 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u nbuf[NUMBUFLEN];
-
if (check_restricted()
|| check_secure()
|| !tv_check_str_or_nr(&argvars[0])) {
return;
}
- const char *varname = (const char *)get_tv_string_chk(&argvars[1]);
+ const char *varname = tv_get_string_chk(&argvars[1]);
buf_T *const buf = get_buf_tv(&argvars[0], false);
typval_T *varp = &argvars[2];
if (buf != NULL && varname != NULL && varp != NULL) {
if (*varname == '&') {
long numval;
- char_u *strval;
- int error = false;
+ bool error = false;
aco_save_T aco;
// set curbuf to be our buf, temporarily
aucmd_prepbuf(&aco, buf);
varname++;
- numval = get_tv_number_chk(varp, &error);
- strval = get_tv_string_buf_chk(varp, nbuf);
+ numval = tv_get_number_chk(varp, &error);
+ char nbuf[NUMBUFLEN];
+ const char *const strval = tv_get_string_buf_chk(varp, nbuf);
if (!error && strval != NULL) {
- set_option_value((char_u *)varname, numval, strval, OPT_LOCAL);
+ set_option_value(varname, numval, strval, OPT_LOCAL);
}
// reset notion of buffer
@@ -15663,11 +14368,11 @@ static void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
buf_T *save_curbuf = curbuf;
const size_t varname_len = STRLEN(varname);
- char_u *const bufvarname = xmalloc(STRLEN(varname) + 3);
+ char *const bufvarname = xmalloc(varname_len + 3);
curbuf = buf;
memcpy(bufvarname, "b:", 2);
memcpy(bufvarname + 2, varname, varname_len + 1);
- set_var(bufvarname, varp, true);
+ set_var(bufvarname, varname_len + 2, varp, true);
xfree(bufvarname);
curbuf = save_curbuf;
}
@@ -15678,7 +14383,6 @@ static void f_setcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
dict_T *d;
dictitem_T *di;
- char_u *csearch;
if (argvars[0].v_type != VAR_DICT) {
EMSG(_(e_dictreq));
@@ -15686,7 +14390,7 @@ static void f_setcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if ((d = argvars[0].vval.v_dict) != NULL) {
- csearch = get_dict_string(d, "char", false);
+ char_u *const csearch = (char_u *)tv_dict_get_string(d, "char", false);
if (csearch != NULL) {
if (enc_utf8) {
int pcc[MAX_MCO];
@@ -15698,13 +14402,15 @@ static void f_setcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
csearch, MB_PTR2LEN(csearch));
}
- di = dict_find(d, (char_u *)"forward", -1);
- if (di != NULL)
- set_csearch_direction(get_tv_number(&di->di_tv) ? FORWARD : BACKWARD);
+ di = tv_dict_find(d, S_LEN("forward"));
+ if (di != NULL) {
+ set_csearch_direction(tv_get_number(&di->di_tv) ? FORWARD : BACKWARD);
+ }
- di = dict_find(d, (char_u *)"until", -1);
- if (di != NULL)
- set_csearch_until(!!get_tv_number(&di->di_tv));
+ di = tv_dict_find(d, S_LEN("until"));
+ if (di != NULL) {
+ set_csearch_until(!!tv_get_number(&di->di_tv));
+ }
}
}
@@ -15713,10 +14419,11 @@ static void f_setcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_setcmdpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int pos = (int)get_tv_number(&argvars[0]) - 1;
+ const int pos = (int)tv_get_number(&argvars[0]) - 1;
- if (pos >= 0)
+ if (pos >= 0) {
rettv->vval.v_number = set_cmdline_pos(pos);
+ }
}
@@ -15725,17 +14432,17 @@ static void f_setfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = 0;
- char_u *fname = get_tv_string_chk(&argvars[0]);
+ const char *const fname = tv_get_string_chk(&argvars[0]);
if (fname == NULL) {
return;
}
- char_u modebuf[NUMBUFLEN];
- char_u *mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
+ char modebuf[NUMBUFLEN];
+ const char *const mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
if (mode_str == NULL) {
return;
}
- if (STRLEN(mode_str) != 9) {
+ if (strlen(mode_str) != 9) {
EMSG2(_(e_invarg2), mode_str);
return;
}
@@ -15756,27 +14463,28 @@ static void f_setfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_setline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T lnum;
- char_u *line = NULL;
list_T *l = NULL;
listitem_T *li = NULL;
long added = 0;
linenr_T lcount = curbuf->b_ml.ml_line_count;
- lnum = get_tv_lnum(&argvars[0]);
+ linenr_T lnum = tv_get_lnum(&argvars[0]);
+ const char *line = NULL;
if (argvars[1].v_type == VAR_LIST) {
l = argvars[1].vval.v_list;
li = l->lv_first;
- } else
- line = get_tv_string_chk(&argvars[1]);
+ } else {
+ line = tv_get_string_chk(&argvars[1]);
+ }
/* default result is zero == OK */
for (;; ) {
if (l != NULL) {
- /* list argument, get next string */
- if (li == NULL)
+ // List argument, get next string.
+ if (li == NULL) {
break;
- line = get_tv_string_chk(&li->li_tv);
+ }
+ line = tv_get_string_chk(&li->li_tv);
li = li->li_next;
}
@@ -15792,18 +14500,20 @@ static void f_setline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (lnum <= curbuf->b_ml.ml_line_count) {
- /* existing line, replace it */
- if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK) {
+ // Existing line, replace it.
+ if (u_savesub(lnum) == OK
+ && ml_replace(lnum, (char_u *)line, true) == OK) {
changed_bytes(lnum, 0);
if (lnum == curwin->w_cursor.lnum)
check_cursor_col();
rettv->vval.v_number = 0; /* OK */
}
} else if (added > 0 || u_save(lnum - 1, lnum) == OK) {
- /* lnum is one past the last line, append the line */
- ++added;
- if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
- rettv->vval.v_number = 0; /* OK */
+ // lnum is one past the last line, append the line.
+ added++;
+ if (ml_append(lnum - 1, (char_u *)line, 0, false) == OK) {
+ rettv->vval.v_number = 0; // OK
+ }
}
if (l == NULL) /* only one string argument */
@@ -15832,7 +14542,7 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
FUNC_ATTR_NONNULL_ARG(2, 3)
{
static char *e_invact = N_("E927: Invalid action: '%s'");
- char_u *title = NULL;
+ const char *title = NULL;
int action = ' ';
rettv->vval.v_number = -1;
dict_T *d = NULL;
@@ -15851,7 +14561,7 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
EMSG(_(e_stringreq));
return;
}
- char_u *act = get_tv_string_chk(action_arg);
+ const char *const act = tv_get_string_chk(action_arg);
if ((*act == 'a' || *act == 'r' || *act == ' ') && act[1] == NUL) {
action = *act;
} else {
@@ -15864,25 +14574,25 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
// Option argument was not given.
goto skip_args;
} else if (title_arg->v_type == VAR_STRING) {
- title = get_tv_string_chk(title_arg);
+ title = tv_get_string_chk(title_arg);
if (!title) {
- // Type error. Error already printed by get_tv_string_chk().
+ // Type error. Error already printed by tv_get_string_chk().
return;
}
} else if (title_arg->v_type == VAR_DICT) {
d = title_arg->vval.v_dict;
} else {
- EMSG(_(e_dictreq));
+ emsgf(_(e_dictreq));
return;
}
skip_args:
if (!title) {
- title = (char_u*)(wp ? "setloclist()" : "setqflist()");
+ title = (wp ? "setloclist()" : "setqflist()");
}
list_T *l = list_arg->vval.v_list;
- if (l && set_errorlist(wp, l, action, title, d) == OK) {
+ if (l && set_errorlist(wp, l, action, (char_u *)title, d) == OK) {
rettv->vval.v_number = 0;
}
}
@@ -15928,11 +14638,11 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
EMSG(_(e_invarg));
return;
}
- if (!(dict_find(d, (char_u *)"group", -1) != NULL
- && (dict_find(d, (char_u *)"pattern", -1) != NULL
- || dict_find(d, (char_u *)"pos1", -1) != NULL)
- && dict_find(d, (char_u *)"priority", -1) != NULL
- && dict_find(d, (char_u *)"id", -1) != NULL)) {
+ if (!(tv_dict_find(d, S_LEN("group")) != NULL
+ && (tv_dict_find(d, S_LEN("pattern")) != NULL
+ || tv_dict_find(d, S_LEN("pos1")) != NULL)
+ && tv_dict_find(d, S_LEN("priority")) != NULL
+ && tv_dict_find(d, S_LEN("id")) != NULL)) {
EMSG(_(e_invarg));
return;
}
@@ -15941,29 +14651,31 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
clear_matches(curwin);
li = l->lv_first;
+ bool match_add_failed = false;
while (li != NULL) {
int i = 0;
- char_u buf[5];
- dictitem_T *di;
d = li->li_tv.vval.v_dict;
- if (dict_find(d, (char_u *)"pattern", -1) == NULL) {
+ dictitem_T *const di = tv_dict_find(d, S_LEN("pattern"));
+ if (di == NULL) {
if (s == NULL) {
- s = list_alloc();
+ s = tv_list_alloc();
if (s == NULL) {
return;
}
}
// match from matchaddpos()
- for (i = 1; i < 9; ++i) {
- snprintf((char *)buf, sizeof(buf), (char *)"pos%d", i);
- if ((di = dict_find(d, (char_u *)buf, -1)) != NULL) {
- if (di->di_tv.v_type != VAR_LIST) {
+ for (i = 1; i < 9; i++) {
+ char buf[5];
+ snprintf(buf, sizeof(buf), "pos%d", i);
+ dictitem_T *const pos_di = tv_dict_find(d, buf, -1);
+ if (pos_di != NULL) {
+ if (pos_di->di_tv.v_type != VAR_LIST) {
return;
}
- list_append_tv(s, &di->di_tv);
+ tv_list_append_tv(s, &pos_di->di_tv);
s->lv_refcount++;
} else {
break;
@@ -15971,26 +14683,39 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
- char_u *group = get_dict_string(d, "group", true);
- int priority = get_dict_number(d, "priority");
- int id = get_dict_number(d, "id");
- char_u *conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
- ? get_dict_string(d, "conceal", true)
- : NULL;
+ // Note: there are three number buffers involved:
+ // - group_buf below.
+ // - numbuf in tv_dict_get_string().
+ // - mybuf in tv_get_string().
+ //
+ // If you change this code make sure that buffers will not get
+ // accidentally reused.
+ char group_buf[NUMBUFLEN];
+ const char *const group = tv_dict_get_string_buf(d, "group", group_buf);
+ const int priority = (int)tv_dict_get_number(d, "priority");
+ const int id = (int)tv_dict_get_number(d, "id");
+ dictitem_T *const conceal_di = tv_dict_find(d, S_LEN("conceal"));
+ const char *const conceal = (conceal_di != NULL
+ ? tv_get_string(&conceal_di->di_tv)
+ : NULL);
if (i == 0) {
- match_add(curwin, group,
- get_dict_string(d, "pattern", false),
- priority, id, NULL, conceal);
+ if (match_add(curwin, group,
+ tv_dict_get_string(d, "pattern", false),
+ priority, id, NULL, conceal) != id) {
+ match_add_failed = true;
+ }
} else {
- match_add(curwin, group, NULL, priority, id, s, conceal);
- list_unref(s);
+ if (match_add(curwin, group, NULL, priority, id, s, conceal) != id) {
+ match_add_failed = true;
+ }
+ tv_list_unref(s);
s = NULL;
}
- xfree(group);
- xfree(conceal);
li = li->li_next;
}
- rettv->vval.v_number = 0;
+ if (!match_add_failed) {
+ rettv->vval.v_number = 0;
+ }
}
}
@@ -16001,11 +14726,10 @@ static void f_setpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
pos_T pos;
int fnum;
- char_u *name;
colnr_T curswant = -1;
rettv->vval.v_number = -1;
- name = get_tv_string_chk(argvars);
+ const char *const name = tv_get_string_chk(argvars);
if (name != NULL) {
if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK) {
if (--pos.col < 0) {
@@ -16026,7 +14750,7 @@ static void f_setpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
} else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) {
// set mark
- if (setmark_pos(name[1], &pos, fnum) == OK) {
+ if (setmark_pos((uint8_t)name[1], &pos, fnum) == OK) {
rettv->vval.v_number = 0;
}
} else {
@@ -16050,8 +14774,6 @@ static void f_setqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int regname;
- char_u *strregname;
- char_u *stropt;
bool append = false;
MotionType yank_type;
long block_len;
@@ -16059,39 +14781,47 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
block_len = -1;
yank_type = kMTUnknown;
- strregname = get_tv_string_chk(argvars);
- rettv->vval.v_number = 1; /* FAIL is default */
+ rettv->vval.v_number = 1; // FAIL is default.
- if (strregname == NULL)
- return; /* type error; errmsg already given */
- regname = *strregname;
- if (regname == 0 || regname == '@')
+ const char *const strregname = tv_get_string_chk(argvars);
+ if (strregname == NULL) {
+ return; // Type error; errmsg already given.
+ }
+ regname = (uint8_t)(*strregname);
+ if (regname == 0 || regname == '@') {
regname = '"';
+ }
if (argvars[2].v_type != VAR_UNKNOWN) {
- stropt = get_tv_string_chk(&argvars[2]);
- if (stropt == NULL)
- return; /* type error */
- for (; *stropt != NUL; ++stropt)
+ const char *stropt = tv_get_string_chk(&argvars[2]);
+ if (stropt == NULL) {
+ return; // Type error.
+ }
+ for (; *stropt != NUL; stropt++) {
switch (*stropt) {
- case 'a': case 'A': // append
- append = true;
- break;
- case 'v': case 'c': // character-wise selection
- yank_type = kMTCharWise;
- break;
- case 'V': case 'l': // line-wise selection
- yank_type = kMTLineWise;
- break;
- case 'b': case Ctrl_V: // block-wise selection
- yank_type = kMTBlockWise;
- if (ascii_isdigit(stropt[1])) {
- ++stropt;
- block_len = getdigits_long(&stropt) - 1;
- --stropt;
+ case 'a': case 'A': { // append
+ append = true;
+ break;
+ }
+ case 'v': case 'c': { // character-wise selection
+ yank_type = kMTCharWise;
+ break;
+ }
+ case 'V': case 'l': { // line-wise selection
+ yank_type = kMTLineWise;
+ break;
+ }
+ case 'b': case Ctrl_V: { // block-wise selection
+ yank_type = kMTBlockWise;
+ if (ascii_isdigit(stropt[1])) {
+ stropt++;
+ block_len = getdigits_long((char_u **)&stropt) - 1;
+ stropt--;
+ }
+ break;
}
- break;
}
+ }
}
if (argvars[1].v_type == VAR_LIST) {
@@ -16101,42 +14831,44 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// First half: use for pointers to result lines; second half: use for
// pointers to allocated copies.
- char_u **lstval = xmalloc(sizeof(char_u *) * ((len + 1) * 2));
- char_u **curval = lstval;
- char_u **allocval = lstval + len + 2;
- char_u **curallocval = allocval;
+ char **lstval = xmalloc(sizeof(char *) * ((len + 1) * 2));
+ const char **curval = (const char **)lstval;
+ char **allocval = lstval + len + 2;
+ char **curallocval = allocval;
- char_u buf[NUMBUFLEN];
for (listitem_T *li = ll == NULL ? NULL : ll->lv_first;
li != NULL;
li = li->li_next) {
- char_u *strval = get_tv_string_buf_chk(&li->li_tv, buf);
- if (strval == NULL) {
+ char buf[NUMBUFLEN];
+ *curval = tv_get_string_buf_chk(&li->li_tv, buf);
+ if (*curval == NULL) {
goto free_lstval;
}
- if (strval == buf) {
+ if (*curval == buf) {
// Need to make a copy,
- // next get_tv_string_buf_chk() will overwrite the string.
- strval = vim_strsave(buf);
- *curallocval++ = strval;
+ // next tv_get_string_buf_chk() will overwrite the string.
+ *curallocval = xstrdup(*curval);
+ *curval = *curallocval;
+ curallocval++;
}
- *curval++ = strval;
+ curval++;
}
*curval++ = NULL;
- write_reg_contents_lst(regname, lstval, STRLEN(lstval),
- append, yank_type, block_len);
+ write_reg_contents_lst(regname, (char_u **)lstval, append, yank_type,
+ block_len);
free_lstval:
- while (curallocval > allocval)
- xfree(*--curallocval);
+ while (curallocval > allocval) {
+ xfree(*--curallocval);
+ }
xfree(lstval);
} else {
- char_u *strval = get_tv_string_chk(&argvars[1]);
+ const char *strval = tv_get_string_chk(&argvars[1]);
if (strval == NULL) {
return;
}
- write_reg_contents_ex(regname, strval, STRLEN(strval),
+ write_reg_contents_ex(regname, (const char_u *)strval, STRLEN(strval),
append, yank_type, block_len);
}
rettv->vval.v_number = 0;
@@ -16147,35 +14879,31 @@ free_lstval:
*/
static void f_settabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- tabpage_T *save_curtab;
- tabpage_T *tp;
- char_u *varname, *tabvarname;
- typval_T *varp;
-
rettv->vval.v_number = 0;
- if (check_restricted() || check_secure())
+ if (check_restricted() || check_secure()) {
return;
+ }
- tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
- varname = get_tv_string_chk(&argvars[1]);
- varp = &argvars[2];
+ tabpage_T *const tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ const char *const varname = tv_get_string_chk(&argvars[1]);
+ typval_T *const varp = &argvars[2];
- if (varname != NULL && varp != NULL
- && tp != NULL
- ) {
- save_curtab = curtab;
- goto_tabpage_tp(tp, FALSE, FALSE);
+ if (varname != NULL && varp != NULL && tp != NULL) {
+ tabpage_T *const save_curtab = curtab;
+ goto_tabpage_tp(tp, false, false);
- tabvarname = xmalloc(STRLEN(varname) + 3);
- STRCPY(tabvarname, "t:");
- STRCPY(tabvarname + 2, varname);
- set_var(tabvarname, varp, TRUE);
+ const size_t varname_len = strlen(varname);
+ char *const tabvarname = xmalloc(varname_len + 3);
+ memcpy(tabvarname, "t:", 2);
+ memcpy(tabvarname + 2, varname, varname_len + 1);
+ set_var(tabvarname, varname_len + 2, varp, true);
xfree(tabvarname);
- /* Restore current tabpage */
- if (valid_tabpage(save_curtab))
- goto_tabpage_tp(save_curtab, FALSE, FALSE);
+ // Restore current tabpage.
+ if (valid_tabpage(save_curtab)) {
+ goto_tabpage_tp(save_curtab, false, false);
+ }
}
}
@@ -16201,45 +14929,43 @@ static void f_setwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void setwinvar(typval_T *argvars, typval_T *rettv, int off)
{
- win_T *win;
- win_T *save_curwin;
- tabpage_T *save_curtab;
- char_u *varname, *winvarname;
- typval_T *varp;
- char_u nbuf[NUMBUFLEN];
- tabpage_T *tp = NULL;
-
- if (check_restricted() || check_secure())
+ if (check_restricted() || check_secure()) {
return;
+ }
- if (off == 1)
- tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
- else
+ tabpage_T *tp = NULL;
+ if (off == 1) {
+ tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ } else {
tp = curtab;
- win = find_win_by_nr(&argvars[off], tp);
- varname = get_tv_string_chk(&argvars[off + 1]);
- varp = &argvars[off + 2];
+ }
+ win_T *const win = find_win_by_nr(&argvars[off], tp);
+ const char *varname = tv_get_string_chk(&argvars[off + 1]);
+ typval_T *varp = &argvars[off + 2];
if (win != NULL && varname != NULL && varp != NULL) {
+ win_T *save_curwin;
+ tabpage_T *save_curtab;
bool need_switch_win = tp != curtab || win != curwin;
if (!need_switch_win
|| switch_win(&save_curwin, &save_curtab, win, tp, true) == OK) {
if (*varname == '&') {
long numval;
- char_u *strval;
- int error = false;
+ bool error = false;
- ++varname;
- numval = get_tv_number_chk(varp, &error);
- strval = get_tv_string_buf_chk(varp, nbuf);
+ varname++;
+ numval = tv_get_number_chk(varp, &error);
+ char nbuf[NUMBUFLEN];
+ const char *const strval = tv_get_string_buf_chk(varp, nbuf);
if (!error && strval != NULL) {
set_option_value(varname, numval, strval, OPT_LOCAL);
}
} else {
- winvarname = xmalloc(STRLEN(varname) + 3);
- STRCPY(winvarname, "w:");
- STRCPY(winvarname + 2, varname);
- set_var(winvarname, varp, true);
+ const size_t varname_len = strlen(varname);
+ char *const winvarname = xmalloc(varname_len + 3);
+ memcpy(winvarname, "w:", 2);
+ memcpy(winvarname + 2, varname, varname_len + 1);
+ set_var(winvarname, varname_len + 2, varp, true);
xfree(winvarname);
}
}
@@ -16252,11 +14978,11 @@ static void setwinvar(typval_T *argvars, typval_T *rettv, int off)
/// f_sha256 - sha256({string}) function
static void f_sha256(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *p = get_tv_string(&argvars[0]);
- const char_u *hash = sha256_bytes(p, (int) STRLEN(p) , NULL, 0);
+ const char *p = tv_get_string(&argvars[0]);
+ const char *hash = sha256_bytes((const uint8_t *)p, strlen(p) , NULL, 0);
// make a copy of the hash (sha256_bytes returns a static buffer)
- rettv->vval.v_string = (char_u *) xstrdup((char *) hash);
+ rettv->vval.v_string = (char_u *)xstrdup(hash);
rettv->v_type = VAR_STRING;
}
@@ -16266,7 +14992,8 @@ static void f_sha256(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_shellescape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_string = vim_strsave_shellescape(
- get_tv_string(&argvars[0]), non_zero_arg(&argvars[1]), true);
+ (const char_u *)tv_get_string(&argvars[0]), non_zero_arg(&argvars[1]),
+ true);
rettv->v_type = VAR_STRING;
}
@@ -16283,11 +15010,9 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_simplify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *p;
-
- p = get_tv_string(&argvars[0]);
- rettv->vval.v_string = vim_strsave(p);
- simplify_filename(rettv->vval.v_string); /* simplify in place */
+ const char *const p = tv_get_string(&argvars[0]);
+ rettv->vval.v_string = (char_u *)xstrdup(p);
+ simplify_filename(rettv->vval.v_string); // Simplify in place.
rettv->v_type = VAR_STRING;
}
@@ -16303,10 +15028,10 @@ typedef struct {
bool item_compare_numeric;
bool item_compare_numbers;
bool item_compare_float;
- char_u *item_compare_func;
+ const char *item_compare_func;
partial_T *item_compare_partial;
dict_T *item_compare_selfdict;
- int item_compare_func_err;
+ bool item_compare_func_err;
} sortinfo_T;
static sortinfo_T *sortinfo = NULL;
@@ -16317,58 +15042,61 @@ static sortinfo_T *sortinfo = NULL;
*/
static int item_compare(const void *s1, const void *s2, bool keep_zero)
{
- sortItem_T *si1, *si2;
- char_u *p1;
- char_u *p2;
- char_u *tofree1 = NULL;
- char_u *tofree2 = NULL;
- int res;
+ sortItem_T *const si1 = (sortItem_T *)s1;
+ sortItem_T *const si2 = (sortItem_T *)s2;
- si1 = (sortItem_T *)s1;
- si2 = (sortItem_T *)s2;
- typval_T *tv1 = &si1->item->li_tv;
- typval_T *tv2 = &si2->item->li_tv;
+ typval_T *const tv1 = &si1->item->li_tv;
+ typval_T *const tv2 = &si2->item->li_tv;
+
+ int res;
if (sortinfo->item_compare_numbers) {
- long v1 = get_tv_number(tv1);
- long v2 = get_tv_number(tv2);
+ const long v1 = tv_get_number(tv1);
+ const long v2 = tv_get_number(tv2);
- return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+ res = v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+ goto item_compare_end;
}
if (sortinfo->item_compare_float) {
- float_T v1 = get_tv_float(tv1);
- float_T v2 = get_tv_float(tv2);
+ const float_T v1 = tv_get_float(tv1);
+ const float_T v2 = tv_get_float(tv2);
- return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+ res = v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+ goto item_compare_end;
}
+ char *tofree1 = NULL;
+ char *tofree2 = NULL;
+ char *p1;
+ char *p2;
+
// encode_tv2string() puts quotes around a string and allocates memory. Don't
// do that for string variables. Use a single quote when comparing with
// a non-string to do what the docs promise.
if (tv1->v_type == VAR_STRING) {
if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) {
- p1 = (char_u *)"'";
+ p1 = "'";
} else {
- p1 = tv1->vval.v_string;
+ p1 = (char *)tv1->vval.v_string;
}
} else {
- tofree1 = p1 = (char_u *) encode_tv2string(tv1, NULL);
+ tofree1 = p1 = encode_tv2string(tv1, NULL);
}
if (tv2->v_type == VAR_STRING) {
if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) {
- p2 = (char_u *)"'";
+ p2 = "'";
} else {
- p2 = tv2->vval.v_string;
+ p2 = (char *)tv2->vval.v_string;
}
} else {
- tofree2 = p2 = (char_u *) encode_tv2string(tv2, NULL);
+ tofree2 = p2 = encode_tv2string(tv2, NULL);
}
if (p1 == NULL) {
- p1 = (char_u *)"";
+ p1 = "";
}
if (p2 == NULL) {
- p2 = (char_u *)"";
+ p2 = "";
}
if (!sortinfo->item_compare_numeric) {
if (sortinfo->item_compare_ic) {
@@ -16378,19 +15106,20 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
}
} else {
double n1, n2;
- n1 = strtod((char *)p1, (char **)&p1);
- n2 = strtod((char *)p2, (char **)&p2);
+ n1 = strtod(p1, &p1);
+ n2 = strtod(p2, &p2);
res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
}
+ xfree(tofree1);
+ xfree(tofree2);
+
+item_compare_end:
// When the result would be zero, compare the item indexes. Makes the
// sort stable.
if (res == 0 && !keep_zero) {
res = si1->idx > si2->idx ? 1 : -1;
}
-
- xfree(tofree1);
- xfree(tofree2);
return res;
}
@@ -16411,7 +15140,7 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
typval_T rettv;
typval_T argv[3];
int dummy;
- char_u *func_name;
+ const char *func_name;
partial_T *partial = sortinfo->item_compare_partial;
// shortcut after failure in previous call; compare all items equal
@@ -16425,31 +15154,31 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
if (partial == NULL) {
func_name = sortinfo->item_compare_func;
} else {
- func_name = partial_name(partial);
+ func_name = (const char *)partial_name(partial);
}
// Copy the values. This is needed to be able to set v_lock to VAR_FIXED
// in the copy without changing the original list items.
- copy_tv(&si1->item->li_tv, &argv[0]);
- copy_tv(&si2->item->li_tv, &argv[1]);
+ tv_copy(&si1->item->li_tv, &argv[0]);
+ tv_copy(&si2->item->li_tv, &argv[1]);
- rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this
- res = call_func(func_name,
+ rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
+ res = call_func((const char_u *)func_name,
(int)STRLEN(func_name),
&rettv, 2, argv, NULL, 0L, 0L, &dummy, true,
partial, sortinfo->item_compare_selfdict);
- clear_tv(&argv[0]);
- clear_tv(&argv[1]);
+ tv_clear(&argv[0]);
+ tv_clear(&argv[1]);
if (res == FAIL) {
res = ITEM_COMPARE_FAIL;
} else {
- res = get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
+ res = tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
}
if (sortinfo->item_compare_func_err) {
res = ITEM_COMPARE_FAIL; // return value has wrong type
}
- clear_tv(&rettv);
+ tv_clear(&rettv);
// When the result would be zero, compare the pointers themselves. Makes
// the sort stable.
@@ -16504,7 +15233,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
rettv->v_type = VAR_LIST;
++l->lv_refcount;
- len = list_len(l);
+ len = tv_list_len(l);
if (len <= 1) {
goto theend; // short list sorts pretty quickly
}
@@ -16520,20 +15249,20 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
if (argvars[1].v_type != VAR_UNKNOWN) {
/* optional second argument: {func} */
if (argvars[1].v_type == VAR_FUNC) {
- info.item_compare_func = argvars[1].vval.v_string;
+ info.item_compare_func = (const char *)argvars[1].vval.v_string;
} else if (argvars[1].v_type == VAR_PARTIAL) {
info.item_compare_partial = argvars[1].vval.v_partial;
} else {
- int error = FALSE;
+ bool error = false;
- i = get_tv_number_chk(&argvars[1], &error);
+ i = tv_get_number_chk(&argvars[1], &error);
if (error) {
goto theend; // type error; errmsg already given
}
if (i == 1) {
info.item_compare_ic = true;
} else if (argvars[1].v_type != VAR_NUMBER) {
- info.item_compare_func = get_tv_string(&argvars[1]);
+ info.item_compare_func = tv_get_string(&argvars[1]);
} else if (i != 0) {
EMSG(_(e_invarg));
goto theend;
@@ -16542,16 +15271,16 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
if (*info.item_compare_func == NUL) {
// empty string means default sort
info.item_compare_func = NULL;
- } else if (STRCMP(info.item_compare_func, "n") == 0) {
+ } else if (strcmp(info.item_compare_func, "n") == 0) {
info.item_compare_func = NULL;
info.item_compare_numeric = true;
- } else if (STRCMP(info.item_compare_func, "N") == 0) {
+ } else if (strcmp(info.item_compare_func, "N") == 0) {
info.item_compare_func = NULL;
info.item_compare_numbers = true;
- } else if (STRCMP(info.item_compare_func, "f") == 0) {
+ } else if (strcmp(info.item_compare_func, "f") == 0) {
info.item_compare_func = NULL;
info.item_compare_float = true;
- } else if (STRCMP(info.item_compare_func, "i") == 0) {
+ } else if (strcmp(info.item_compare_func, "i") == 0) {
info.item_compare_func = NULL;
info.item_compare_ic = true;
}
@@ -16603,7 +15332,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
l->lv_len = 0;
for (i = 0; i < len; i++) {
- list_append(l, ptrs[i].item);
+ tv_list_append(l, ptrs[i].item);
}
}
}
@@ -16639,8 +15368,8 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
} else {
l->lv_last = ptrs[i].item;
}
- list_fix_watch(l, li);
- listitem_free(li);
+ tv_list_watch_fix(l, li);
+ tv_list_item_free(li);
l->lv_len--;
}
}
@@ -16685,11 +15414,9 @@ static void f_reltimefloat(typval_T *argvars , typval_T *rettv, FunPtr fptr)
*/
static void f_soundfold(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *s;
-
rettv->v_type = VAR_STRING;
- s = get_tv_string(&argvars[0]);
- rettv->vval.v_string = eval_soundfold(s);
+ const char *const s = tv_get_string(&argvars[0]);
+ rettv->vval.v_string = (char_u *)eval_soundfold(s);
}
/*
@@ -16697,25 +15424,26 @@ static void f_soundfold(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *word = (char_u *)"";
+ const char *word = "";
hlf_T attr = HLF_COUNT;
size_t len = 0;
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
if (argvars[0].v_type == VAR_UNKNOWN) {
- /* Find the start and length of the badly spelled word. */
- len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
- if (len != 0)
- word = get_cursor_pos_ptr();
+ // Find the start and length of the badly spelled word.
+ len = spell_move_to(curwin, FORWARD, true, true, &attr);
+ if (len != 0) {
+ word = (char *)get_cursor_pos_ptr();
+ }
} else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL) {
- char_u *str = get_tv_string_chk(&argvars[0]);
+ const char *str = tv_get_string_chk(&argvars[0]);
int capcol = -1;
if (str != NULL) {
- /* Check the argument for spelling. */
+ // Check the argument for spelling.
while (*str != NUL) {
- len = spell_check(curwin, str, &attr, &capcol, false);
+ len = spell_check(curwin, (char_u *)str, &attr, &capcol, false);
if (attr != HLF_COUNT) {
word = str;
break;
@@ -16726,14 +15454,13 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
assert(len <= INT_MAX);
- list_append_string(rettv->vval.v_list, word, (int)len);
- list_append_string(rettv->vval.v_list,
- (char_u *)(attr == HLF_SPB ? "bad" :
- attr == HLF_SPR ? "rare" :
- attr == HLF_SPL ? "local" :
- attr == HLF_SPC ? "caps" :
- ""),
- -1);
+ tv_list_append_string(rettv->vval.v_list, word, len);
+ tv_list_append_string(rettv->vval.v_list,
+ (attr == HLF_SPB ? "bad"
+ : attr == HLF_SPR ? "rare"
+ : attr == HLF_SPL ? "local"
+ : attr == HLF_SPC ? "caps"
+ : NULL), -1);
}
/*
@@ -16741,39 +15468,40 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_spellsuggest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *str;
- int typeerr = FALSE;
+ bool typeerr = false;
int maxcount;
garray_T ga;
listitem_T *li;
bool need_capital = false;
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) {
- str = get_tv_string(&argvars[0]);
+ const char *const str = tv_get_string(&argvars[0]);
if (argvars[1].v_type != VAR_UNKNOWN) {
- maxcount = get_tv_number_chk(&argvars[1], &typeerr);
- if (maxcount <= 0)
+ maxcount = tv_get_number_chk(&argvars[1], &typeerr);
+ if (maxcount <= 0) {
return;
+ }
if (argvars[2].v_type != VAR_UNKNOWN) {
- need_capital = get_tv_number_chk(&argvars[2], &typeerr);
- if (typeerr)
+ need_capital = tv_get_number_chk(&argvars[2], &typeerr);
+ if (typeerr) {
return;
+ }
}
} else
maxcount = 25;
- spell_suggest_list(&ga, str, maxcount, need_capital, false);
+ spell_suggest_list(&ga, (char_u *)str, maxcount, need_capital, false);
- for (int i = 0; i < ga.ga_len; ++i) {
- str = ((char_u **)ga.ga_data)[i];
+ for (int i = 0; i < ga.ga_len; i++) {
+ char *p = ((char **)ga.ga_data)[i];
- li = listitem_alloc();
+ li = tv_list_item_alloc();
li->li_tv.v_type = VAR_STRING;
li->li_tv.v_lock = 0;
- li->li_tv.vval.v_string = str;
- list_append(rettv->vval.v_list, li);
+ li->li_tv.vval.v_string = (char_u *)p;
+ tv_list_append(rettv->vval.v_list, li);
}
ga_clear(&ga);
}
@@ -16781,64 +15509,69 @@ static void f_spellsuggest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *str;
- char_u *end;
- char_u *pat = NULL;
regmatch_T regmatch;
- char_u patbuf[NUMBUFLEN];
char_u *save_cpo;
int match;
colnr_T col = 0;
- int keepempty = FALSE;
- int typeerr = FALSE;
+ bool keepempty = false;
+ bool typeerr = false;
/* Make 'cpoptions' empty, the 'l' flag should not be used here. */
save_cpo = p_cpo;
p_cpo = (char_u *)"";
- str = get_tv_string(&argvars[0]);
+ const char *str = tv_get_string(&argvars[0]);
+ const char *pat = NULL;
+ char patbuf[NUMBUFLEN];
if (argvars[1].v_type != VAR_UNKNOWN) {
- pat = get_tv_string_buf_chk(&argvars[1], patbuf);
- if (pat == NULL)
- typeerr = TRUE;
- if (argvars[2].v_type != VAR_UNKNOWN)
- keepempty = get_tv_number_chk(&argvars[2], &typeerr);
+ pat = tv_get_string_buf_chk(&argvars[1], patbuf);
+ if (pat == NULL) {
+ typeerr = true;
+ }
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ keepempty = (bool)tv_get_number_chk(&argvars[2], &typeerr);
+ }
+ }
+ if (pat == NULL || *pat == NUL) {
+ pat = "[\\x01- ]\\+";
}
- if (pat == NULL || *pat == NUL)
- pat = (char_u *)"[\\x01- ]\\+";
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
if (typeerr)
return;
- regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ regmatch.regprog = vim_regcomp((char_u *)pat, RE_MAGIC + RE_STRING);
if (regmatch.regprog != NULL) {
regmatch.rm_ic = FALSE;
while (*str != NUL || keepempty) {
- if (*str == NUL)
- match = FALSE; /* empty item at the end */
- else
- match = vim_regexec_nl(&regmatch, str, col);
- if (match)
- end = regmatch.startp[0];
- else
- end = str + STRLEN(str);
+ if (*str == NUL) {
+ match = false; // Empty item at the end.
+ } else {
+ match = vim_regexec_nl(&regmatch, (char_u *)str, col);
+ }
+ const char *end;
+ if (match) {
+ end = (const char *)regmatch.startp[0];
+ } else {
+ end = str + strlen(str);
+ }
if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
- && *str != NUL && match && end <
- regmatch.endp[0])) {
- list_append_string(rettv->vval.v_list, str, (int)(end - str));
+ && *str != NUL
+ && match
+ && end < (const char *)regmatch.endp[0])) {
+ tv_list_append_string(rettv->vval.v_list, str, end - str);
}
if (!match)
break;
- /* Advance to just after the match. */
- if (regmatch.endp[0] > str)
+ // Advance to just after the match.
+ if (regmatch.endp[0] > (char_u *)str) {
col = 0;
- else {
- /* Don't get stuck at the same match. */
+ } else {
+ // Don't get stuck at the same match.
col = (*mb_ptr2len)(regmatch.endp[0]);
}
- str = regmatch.endp[0];
+ str = (const char *)regmatch.endp[0];
}
vim_regfree(regmatch.regprog);
@@ -16852,11 +15585,12 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_str2float(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *p = skipwhite(get_tv_string(&argvars[0]));
+ char_u *p = skipwhite((const char_u *)tv_get_string(&argvars[0]));
- if (*p == '+')
+ if (*p == '+') {
p = skipwhite(p + 1);
- (void) string2float((char *) p, &rettv->vval.v_float);
+ }
+ (void)string2float((char *)p, &rettv->vval.v_float);
rettv->v_type = VAR_FLOAT;
}
@@ -16864,34 +15598,37 @@ static void f_str2float(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int base = 10;
- char_u *p;
long n;
int what;
if (argvars[1].v_type != VAR_UNKNOWN) {
- base = get_tv_number(&argvars[1]);
+ base = tv_get_number(&argvars[1]);
if (base != 2 && base != 8 && base != 10 && base != 16) {
EMSG(_(e_invarg));
return;
}
}
- p = skipwhite(get_tv_string(&argvars[0]));
+ char_u *p = skipwhite((const char_u *)tv_get_string(&argvars[0]));
if (*p == '+') {
p = skipwhite(p + 1);
}
switch (base) {
- case 2:
- what = STR2NR_BIN + STR2NR_FORCE;
+ case 2: {
+ what = STR2NR_BIN | STR2NR_FORCE;
break;
- case 8:
- what = STR2NR_OCT + STR2NR_FORCE;
+ }
+ case 8: {
+ what = STR2NR_OCT | STR2NR_FORCE;
break;
- case 16:
- what = STR2NR_HEX + STR2NR_FORCE;
+ }
+ case 16: {
+ what = STR2NR_HEX | STR2NR_FORCE;
break;
- default:
+ }
+ default: {
what = 0;
+ }
}
vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
rettv->vval.v_number = n;
@@ -16902,17 +15639,16 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u result_buf[256];
time_t seconds;
- char_u *p;
rettv->v_type = VAR_STRING;
- p = get_tv_string(&argvars[0]);
- if (argvars[1].v_type == VAR_UNKNOWN)
+ char *p = (char *)tv_get_string(&argvars[0]);
+ if (argvars[1].v_type == VAR_UNKNOWN) {
seconds = time(NULL);
- else
- seconds = (time_t)get_tv_number(&argvars[1]);
+ } else {
+ seconds = (time_t)tv_get_number(&argvars[1]);
+ }
struct tm curtime;
struct tm *curtime_ptr = os_localtime_r(&seconds, &curtime);
@@ -16926,23 +15662,27 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
conv.vc_type = CONV_NONE;
enc = enc_locale();
convert_setup(&conv, p_enc, enc);
- if (conv.vc_type != CONV_NONE)
- p = string_convert(&conv, p, NULL);
- if (p != NULL)
- (void)strftime((char *)result_buf, sizeof(result_buf),
- (char *)p, curtime_ptr);
- else
+ if (conv.vc_type != CONV_NONE) {
+ p = (char *)string_convert(&conv, (char_u *)p, NULL);
+ }
+ char result_buf[256];
+ if (p != NULL) {
+ (void)strftime(result_buf, sizeof(result_buf), p, curtime_ptr);
+ } else {
result_buf[0] = NUL;
+ }
- if (conv.vc_type != CONV_NONE)
+ if (conv.vc_type != CONV_NONE) {
xfree(p);
+ }
convert_setup(&conv, enc, p_enc);
- if (conv.vc_type != CONV_NONE)
- rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
- else
- rettv->vval.v_string = vim_strsave(result_buf);
+ if (conv.vc_type != CONV_NONE) {
+ rettv->vval.v_string = string_convert(&conv, (char_u *)result_buf, NULL);
+ } else {
+ rettv->vval.v_string = (char_u *)xstrdup(result_buf);
+ }
- /* Release conversion descriptors */
+ // Release conversion descriptors.
convert_setup(&conv, NULL, NULL);
xfree(enc);
}
@@ -16951,33 +15691,28 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// "strgetchar()" function
static void f_strgetchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *str;
- int len;
- int error = false;
- int charidx;
-
rettv->vval.v_number = -1;
- str = get_tv_string_chk(&argvars[0]);
+
+ const char *const str = tv_get_string_chk(&argvars[0]);
if (str == NULL) {
return;
}
- len = (int)STRLEN(str);
- charidx = get_tv_number_chk(&argvars[1], &error);
+ bool error = false;
+ varnumber_T charidx = tv_get_number_chk(&argvars[1], &error);
if (error) {
return;
}
- {
- int byteidx = 0;
+ const size_t len = STRLEN(str);
+ size_t byteidx = 0;
- while (charidx >= 0 && byteidx < len) {
- if (charidx == 0) {
- rettv->vval.v_number = mb_ptr2char(str + byteidx);
- break;
- }
- charidx--;
- byteidx += MB_CPTR2LEN(str + byteidx);
+ while (charidx >= 0 && byteidx < len) {
+ if (charidx == 0) {
+ rettv->vval.v_number = mb_ptr2char((const char_u *)str + byteidx);
+ break;
}
+ charidx--;
+ byteidx += MB_CPTR2LEN((const char_u *)str + byteidx);
}
}
@@ -16986,32 +15721,33 @@ static void f_strgetchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_stridx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u buf[NUMBUFLEN];
- char_u *needle;
- char_u *haystack;
- char_u *save_haystack;
- char_u *pos;
- int start_idx;
-
- needle = get_tv_string_chk(&argvars[1]);
- save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
rettv->vval.v_number = -1;
- if (needle == NULL || haystack == NULL)
- return; /* type error; errmsg already given */
+
+ char buf[NUMBUFLEN];
+ const char *const needle = tv_get_string_chk(&argvars[1]);
+ const char *haystack = tv_get_string_buf_chk(&argvars[0], buf);
+ const char *const haystack_start = haystack;
+ if (needle == NULL || haystack == NULL) {
+ return; // Type error; errmsg already given.
+ }
if (argvars[2].v_type != VAR_UNKNOWN) {
- int error = FALSE;
+ bool error = false;
- start_idx = get_tv_number_chk(&argvars[2], &error);
- if (error || start_idx >= (int)STRLEN(haystack))
+ const ptrdiff_t start_idx = (ptrdiff_t)tv_get_number_chk(&argvars[2],
+ &error);
+ if (error || start_idx >= (ptrdiff_t)strlen(haystack)) {
return;
- if (start_idx >= 0)
+ }
+ if (start_idx >= 0) {
haystack += start_idx;
+ }
}
- pos = (char_u *)strstr((char *)haystack, (char *)needle);
- if (pos != NULL)
- rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
+ const char *pos = strstr(haystack, needle);
+ if (pos != NULL) {
+ rettv->vval.v_number = (varnumber_T)(pos - haystack_start);
+ }
}
/*
@@ -17028,8 +15764,7 @@ static void f_string(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_strlen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = (varnumber_T)(STRLEN(
- get_tv_string(&argvars[0])));
+ rettv->vval.v_number = (varnumber_T)strlen(tv_get_string(&argvars[0]));
}
/*
@@ -17037,21 +15772,21 @@ static void f_strlen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_strchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *s = get_tv_string(&argvars[0]);
+ const char *s = tv_get_string(&argvars[0]);
int skipcc = 0;
varnumber_T len = 0;
- int (*func_mb_ptr2char_adv)(char_u **pp);
+ int (*func_mb_ptr2char_adv)(const char_u **pp);
if (argvars[1].v_type != VAR_UNKNOWN) {
- skipcc = get_tv_number_chk(&argvars[1], NULL);
+ skipcc = tv_get_number_chk(&argvars[1], NULL);
}
if (skipcc < 0 || skipcc > 1) {
EMSG(_(e_invarg));
} else {
func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
while (*s != NUL) {
- func_mb_ptr2char_adv(&s);
- ++len;
+ func_mb_ptr2char_adv((const char_u **)&s);
+ len++;
}
rettv->vval.v_number = len;
}
@@ -17062,13 +15797,14 @@ static void f_strchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *s = get_tv_string(&argvars[0]);
+ const char *const s = tv_get_string(&argvars[0]);
int col = 0;
- if (argvars[1].v_type != VAR_UNKNOWN)
- col = get_tv_number(&argvars[1]);
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ col = tv_get_number(&argvars[1]);
+ }
- rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
+ rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, (char_u *)s) - col);
}
/*
@@ -17076,44 +15812,40 @@ static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_strwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *s = get_tv_string(&argvars[0]);
+ const char *const s = tv_get_string(&argvars[0]);
- rettv->vval.v_number = (varnumber_T) mb_string2cells(s);
+ rettv->vval.v_number = (varnumber_T)mb_string2cells((const char_u *)s);
}
// "strcharpart()" function
-static void f_strcharpart(typval_T *argvars, typval_T *rettv, FunPtr fptr) {
- char_u *p;
- int nchar;
- int nbyte = 0;
- int charlen;
- int len = 0;
- int slen;
- int error = false;
-
- p = get_tv_string(&argvars[0]);
- slen = (int)STRLEN(p);
+static void f_strcharpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ const char *const p = tv_get_string(&argvars[0]);
+ const size_t slen = STRLEN(p);
- nchar = get_tv_number_chk(&argvars[1], &error);
+ int nbyte = 0;
+ bool error = false;
+ varnumber_T nchar = tv_get_number_chk(&argvars[1], &error);
if (!error) {
if (nchar > 0) {
- while (nchar > 0 && nbyte < slen) {
- nbyte += MB_CPTR2LEN(p + nbyte);
+ while (nchar > 0 && (size_t)nbyte < slen) {
+ nbyte += MB_CPTR2LEN((const char_u *)p + nbyte);
nchar--;
}
} else {
nbyte = nchar;
}
}
+ int len = 0;
if (argvars[2].v_type != VAR_UNKNOWN) {
- charlen = get_tv_number(&argvars[2]);
- while (charlen > 0 && nbyte + len < slen) {
+ int charlen = tv_get_number(&argvars[2]);
+ while (charlen > 0 && nbyte + len < (int)slen) {
int off = nbyte + len;
if (off < 0) {
len += 1;
} else {
- len += MB_CPTR2LEN(p + off);
+ len += (size_t)MB_CPTR2LEN((const char_u *)p + off);
}
charlen--;
}
@@ -17126,17 +15858,17 @@ static void f_strcharpart(typval_T *argvars, typval_T *rettv, FunPtr fptr) {
if (nbyte < 0) {
len += nbyte;
nbyte = 0;
- } else if (nbyte > slen) {
+ } else if ((size_t)nbyte > slen) {
nbyte = slen;
}
if (len < 0) {
len = 0;
- } else if (nbyte + len > slen) {
+ } else if (nbyte + len > (int)slen) {
len = slen - nbyte;
}
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = vim_strnsave(p + nbyte, len);
+ rettv->vval.v_string = (char_u *)xstrndup(p + nbyte, (size_t)len);
}
/*
@@ -17144,39 +15876,37 @@ static void f_strcharpart(typval_T *argvars, typval_T *rettv, FunPtr fptr) {
*/
static void f_strpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *p;
- int n;
- int len;
- int slen;
- int error = FALSE;
+ bool error = false;
- p = get_tv_string(&argvars[0]);
- slen = (int)STRLEN(p);
+ const char *const p = tv_get_string(&argvars[0]);
+ const size_t slen = strlen(p);
- n = get_tv_number_chk(&argvars[1], &error);
- if (error)
+ varnumber_T n = tv_get_number_chk(&argvars[1], &error);
+ varnumber_T len;
+ if (error) {
len = 0;
- else if (argvars[2].v_type != VAR_UNKNOWN)
- len = get_tv_number(&argvars[2]);
- else
- len = slen - n; /* default len: all bytes that are available. */
+ } else if (argvars[2].v_type != VAR_UNKNOWN) {
+ len = tv_get_number(&argvars[2]);
+ } else {
+ len = slen - n; // Default len: all bytes that are available.
+ }
- /*
- * Only return the overlap between the specified part and the actual
- * string.
- */
+ // Only return the overlap between the specified part and the actual
+ // string.
if (n < 0) {
len += n;
n = 0;
- } else if (n > slen)
+ } else if (n > (varnumber_T)slen) {
n = slen;
- if (len < 0)
+ }
+ if (len < 0) {
len = 0;
- else if (n + len > slen)
+ } else if (n + len > (varnumber_T)slen) {
len = slen - n;
+ }
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = vim_strnsave(p + n, len);
+ rettv->vval.v_string = (char_u *)xmemdupz(p + n, (size_t)len);
}
/*
@@ -17184,45 +15914,46 @@ static void f_strpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_strridx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u buf[NUMBUFLEN];
- char_u *needle;
- char_u *haystack;
- char_u *rest;
- char_u *lastmatch = NULL;
- int haystack_len, end_idx;
-
- needle = get_tv_string_chk(&argvars[1]);
- haystack = get_tv_string_buf_chk(&argvars[0], buf);
+ char buf[NUMBUFLEN];
+ const char *const needle = tv_get_string_chk(&argvars[1]);
+ const char *const haystack = tv_get_string_buf_chk(&argvars[0], buf);
rettv->vval.v_number = -1;
- if (needle == NULL || haystack == NULL)
- return; /* type error; errmsg already given */
+ if (needle == NULL || haystack == NULL) {
+ return; // Type error; errmsg already given.
+ }
- haystack_len = (int)STRLEN(haystack);
+ const size_t haystack_len = STRLEN(haystack);
+ ptrdiff_t end_idx;
if (argvars[2].v_type != VAR_UNKNOWN) {
- /* Third argument: upper limit for index */
- end_idx = get_tv_number_chk(&argvars[2], NULL);
- if (end_idx < 0)
- return; /* can never find a match */
- } else
- end_idx = haystack_len;
+ // Third argument: upper limit for index.
+ end_idx = (ptrdiff_t)tv_get_number_chk(&argvars[2], NULL);
+ if (end_idx < 0) {
+ return; // Can never find a match.
+ }
+ } else {
+ end_idx = (ptrdiff_t)haystack_len;
+ }
+ const char *lastmatch = NULL;
if (*needle == NUL) {
- /* Empty string matches past the end. */
+ // Empty string matches past the end.
lastmatch = haystack + end_idx;
} else {
- for (rest = haystack; *rest != NUL; ++rest) {
- rest = (char_u *)strstr((char *)rest, (char *)needle);
- if (rest == NULL || rest > haystack + end_idx)
+ for (const char *rest = haystack; *rest != NUL; rest++) {
+ rest = strstr(rest, needle);
+ if (rest == NULL || rest > haystack + end_idx) {
break;
+ }
lastmatch = rest;
}
}
- if (lastmatch == NULL)
+ if (lastmatch == NULL) {
rettv->vval.v_number = -1;
- else
+ } else {
rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
+ }
}
/*
@@ -17231,7 +15962,7 @@ static void f_strridx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_strtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
+ rettv->vval.v_string = transstr((char_u *)tv_get_string(&argvars[0]));
}
/*
@@ -17239,8 +15970,8 @@ static void f_strtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_submatch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int error = FALSE;
- int no = (int)get_tv_number_chk(&argvars[0], &error);
+ bool error = false;
+ int no = (int)tv_get_number_chk(&argvars[0], &error);
if (error) {
return;
}
@@ -17252,7 +15983,7 @@ static void f_submatch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int retList = 0;
if (argvars[1].v_type != VAR_UNKNOWN) {
- retList = get_tv_number_chk(&argvars[1], &error);
+ retList = tv_get_number_chk(&argvars[1], &error);
if (error) {
return;
}
@@ -17272,20 +16003,20 @@ static void f_submatch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_substitute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u patbuf[NUMBUFLEN];
- char_u subbuf[NUMBUFLEN];
- char_u flagsbuf[NUMBUFLEN];
+ char patbuf[NUMBUFLEN];
+ char subbuf[NUMBUFLEN];
+ char flagsbuf[NUMBUFLEN];
- char_u *str = get_tv_string_chk(&argvars[0]);
- char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
- char_u *sub = NULL;
- typval_T *expr = NULL;
- char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
+ const char *const str = tv_get_string_chk(&argvars[0]);
+ const char *const pat = tv_get_string_buf_chk(&argvars[1], patbuf);
+ const char *sub = NULL;
+ const char *const flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
- if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL) {
+ typval_T *expr = NULL;
+ if (tv_is_func(argvars[2])) {
expr = &argvars[2];
} else {
- sub = get_tv_string_buf_chk(&argvars[2], subbuf);
+ sub = tv_get_string_buf_chk(&argvars[2], subbuf);
}
rettv->v_type = VAR_STRING;
@@ -17293,26 +16024,26 @@ static void f_substitute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|| flg == NULL) {
rettv->vval.v_string = NULL;
} else {
- rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
+ rettv->vval.v_string = do_string_sub((char_u *)str, (char_u *)pat,
+ (char_u *)sub, expr, (char_u *)flg);
}
}
/// "synID(lnum, col, trans)" function
static void f_synID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int id = 0;
- long lnum;
- long col;
- int trans;
- int transerr = FALSE;
+ // -1 on type error (both)
+ const linenr_T lnum = tv_get_lnum(argvars);
+ const colnr_T col = (colnr_T)tv_get_number(&argvars[1]) - 1;
- lnum = get_tv_lnum(argvars); /* -1 on type error */
- col = get_tv_number(&argvars[1]) - 1; /* -1 on type error */
- trans = get_tv_number_chk(&argvars[2], &transerr);
+ bool transerr = false;
+ const int trans = tv_get_number_chk(&argvars[2], &transerr);
+ int id = 0;
if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
- && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
- id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
+ && col >= 0 && (size_t)col < STRLEN(ml_get(lnum))) {
+ id = syn_get_id(curwin, lnum, col, trans, NULL, false);
+ }
rettv->vval.v_number = id;
}
@@ -17322,20 +16053,16 @@ static void f_synID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *p = NULL;
- int id;
- char_u *what;
- char_u *mode;
- char_u modebuf[NUMBUFLEN];
+ const int id = (int)tv_get_number(&argvars[0]);
+ const char *const what = tv_get_string(&argvars[1]);
int modec;
-
- id = get_tv_number(&argvars[0]);
- what = get_tv_string(&argvars[1]);
if (argvars[2].v_type != VAR_UNKNOWN) {
- mode = get_tv_string_buf(&argvars[2], modebuf);
+ char modebuf[NUMBUFLEN];
+ const char *const mode = tv_get_string_buf(&argvars[2], modebuf);
modec = TOLOWER_ASC(mode[0]);
- if (modec != 'c' && modec != 'g')
- modec = 0; /* replace invalid with current */
+ if (modec != 'c' && modec != 'g') {
+ modec = 0; // Replace invalid with current.
+ }
} else if (ui_rgb_attached()) {
modec = 'g';
} else {
@@ -17343,54 +16070,56 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
+ const char *p = NULL;
switch (TOLOWER_ASC(what[0])) {
- case 'b':
- if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
+ case 'b': {
+ if (TOLOWER_ASC(what[1]) == 'g') { // bg[#]
+ p = highlight_color(id, what, modec);
+ } else { // bold
+ p = highlight_has_attr(id, HL_BOLD, modec);
+ }
+ break;
+ }
+ case 'f': { // fg[#] or font
p = highlight_color(id, what, modec);
- else /* bold */
- p = highlight_has_attr(id, HL_BOLD, modec);
- break;
-
- case 'f': /* fg[#] or font */
- p = highlight_color(id, what, modec);
- break;
-
- case 'i':
- if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
+ break;
+ }
+ case 'i': {
+ if (TOLOWER_ASC(what[1]) == 'n') { // inverse
+ p = highlight_has_attr(id, HL_INVERSE, modec);
+ } else { // italic
+ p = highlight_has_attr(id, HL_ITALIC, modec);
+ }
+ break;
+ }
+ case 'n': { // name
+ p = get_highlight_name(NULL, id - 1);
+ break;
+ }
+ case 'r': { // reverse
p = highlight_has_attr(id, HL_INVERSE, modec);
- else /* italic */
- p = highlight_has_attr(id, HL_ITALIC, modec);
- break;
-
- case 'n': // name
- p = (char_u *)get_highlight_name(NULL, id - 1);
- break;
-
- case 'r': /* reverse */
- p = highlight_has_attr(id, HL_INVERSE, modec);
- break;
-
- case 's':
- if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
- p = highlight_color(id, what, modec);
- else /* standout */
- p = highlight_has_attr(id, HL_STANDOUT, modec);
- break;
-
- case 'u':
- if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
- /* underline */
- p = highlight_has_attr(id, HL_UNDERLINE, modec);
- else
- /* undercurl */
- p = highlight_has_attr(id, HL_UNDERCURL, modec);
- break;
+ break;
+ }
+ case 's': {
+ if (TOLOWER_ASC(what[1]) == 'p') { // sp[#]
+ p = highlight_color(id, what, modec);
+ } else { // standout
+ p = highlight_has_attr(id, HL_STANDOUT, modec);
+ }
+ break;
+ }
+ case 'u': {
+ if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c') { // underline
+ p = highlight_has_attr(id, HL_UNDERLINE, modec);
+ } else { // undercurl
+ p = highlight_has_attr(id, HL_UNDERCURL, modec);
+ }
+ break;
+ }
}
- if (p != NULL)
- p = vim_strsave(p);
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = p;
+ rettv->vval.v_string = (char_u *)(p == NULL ? p : xstrdup(p));
}
/*
@@ -17398,14 +16127,13 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_synIDtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int id;
-
- id = get_tv_number(&argvars[0]);
+ int id = tv_get_number(&argvars[0]);
- if (id > 0)
+ if (id > 0) {
id = syn_get_final_id(id);
- else
+ } else {
id = 0;
+ }
rettv->vval.v_number = id;
}
@@ -17415,8 +16143,6 @@ static void f_synIDtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- long lnum;
- long col;
int syntax_flags = 0;
int cchar;
int matchid = 0;
@@ -17425,15 +16151,16 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_LIST;
rettv->vval.v_list = NULL;
- lnum = get_tv_lnum(argvars); /* -1 on type error */
- col = get_tv_number(&argvars[1]) - 1; /* -1 on type error */
+ // -1 on type error (both)
+ const linenr_T lnum = tv_get_lnum(argvars);
+ const colnr_T col = (colnr_T)tv_get_number(&argvars[1]) - 1;
memset(str, NUL, sizeof(str));
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count && col >= 0
- && col <= (long)STRLEN(ml_get(lnum)) && curwin->w_p_cole > 0) {
- (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
+ && (size_t)col <= STRLEN(ml_get(lnum)) && curwin->w_p_cole > 0) {
+ (void)syn_get_id(curwin, lnum, col, false, NULL, false);
syntax_flags = get_syntax_info(&matchid);
// get the conceal character
@@ -17451,10 +16178,10 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
- list_append_number(rettv->vval.v_list, (syntax_flags & HL_CONCEAL) != 0);
+ tv_list_append_number(rettv->vval.v_list, (syntax_flags & HL_CONCEAL) != 0);
// -1 to auto-determine strlen
- list_append_string(rettv->vval.v_list, str, -1);
- list_append_number(rettv->vval.v_list, matchid);
+ tv_list_append_string(rettv->vval.v_list, (const char *)str, -1);
+ tv_list_append_number(rettv->vval.v_list, matchid);
}
/*
@@ -17462,56 +16189,35 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_synstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- long lnum;
- long col;
-
rettv->v_type = VAR_LIST;
rettv->vval.v_list = NULL;
- lnum = get_tv_lnum(argvars); /* -1 on type error */
- col = get_tv_number(&argvars[1]) - 1; /* -1 on type error */
+ // -1 on type error (both)
+ const linenr_T lnum = tv_get_lnum(argvars);
+ const colnr_T col = (colnr_T)tv_get_number(&argvars[1]) - 1;
if (lnum >= 1
&& lnum <= curbuf->b_ml.ml_line_count
&& col >= 0
- && col <= (long)STRLEN(ml_get(lnum))) {
- rettv_list_alloc(rettv);
- (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
+ && (size_t)col <= STRLEN(ml_get(lnum))) {
+ tv_list_alloc_ret(rettv);
+ (void)syn_get_id(curwin, lnum, col, false, NULL, true);
int id;
int i = 0;
while ((id = syn_get_stack_item(i++)) >= 0) {
- list_append_number(rettv->vval.v_list, id);
+ tv_list_append_number(rettv->vval.v_list, id);
}
}
}
-static list_T* string_to_list(char_u *str, size_t len, bool keepempty)
+static list_T *string_to_list(const char *str, size_t len, const bool keepempty)
{
- list_T *list = list_alloc();
-
- // Copy each line to a list element using NL as the delimiter.
- for (size_t i = 0; i < len; i++) {
- char_u *start = str + i;
- size_t line_len = (char_u *) xmemscan(start, NL, len - i) - start;
- i += line_len;
-
- // Don't use a str function to copy res as it may contains NULs.
- char_u *s = xmemdupz(start, line_len);
- memchrsub(s, NUL, NL, line_len); // Replace NUL with NL to avoid truncation
-
- listitem_T *li = listitem_alloc();
- li->li_tv.v_type = VAR_STRING;
- li->li_tv.v_lock = 0;
- li->li_tv.vval.v_string = s;
- list_append(list, li);
+ if (!keepempty && str[len - 1] == NL) {
+ len--;
}
-
- // Optionally retain final newline, if present
- if (keepempty && str[len-1] == NL) {
- list_append_string(list, (char_u*)"", 0);
- }
-
+ list_T *const list = tv_list_alloc();
+ encode_list_write(list, str, len);
return list;
}
@@ -17526,8 +16232,8 @@ static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
}
// get input to the shell command (if any), and its length
- ssize_t input_len;
- char *input = (char *) save_tv_as_string(&argvars[1], &input_len, false);
+ ptrdiff_t input_len;
+ char *input = save_tv_as_string(&argvars[1], &input_len, false);
if (input_len < 0) {
assert(input == NULL);
return;
@@ -17556,7 +16262,7 @@ static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
if (res == NULL) {
if (retlist) {
// return an empty list when there's no output
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
} else {
rettv->vval.v_string = (char_u *) xstrdup("");
}
@@ -17566,9 +16272,9 @@ static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
if (retlist) {
int keepempty = 0;
if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) {
- keepempty = get_tv_number(&argvars[2]);
+ keepempty = tv_get_number(&argvars[2]);
}
- rettv->vval.v_list = string_to_list((char_u *) res, nread, keepempty != 0);
+ rettv->vval.v_list = string_to_list(res, nread, (bool)keepempty);
rettv->vval.v_list->lv_refcount++;
rettv->v_type = VAR_LIST;
@@ -17611,20 +16317,20 @@ static void f_systemlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- tabpage_T *tp;
win_T *wp = NULL;
- if (argvars[0].v_type == VAR_UNKNOWN)
+ if (argvars[0].v_type == VAR_UNKNOWN) {
wp = firstwin;
- else {
- tp = find_tabpage((int)get_tv_number(&argvars[0]));
- if (tp != NULL)
+ } else {
+ tabpage_T *const tp = find_tabpage((int)tv_get_number(&argvars[0]));
+ if (tp != NULL) {
wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
+ }
}
if (wp != NULL) {
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
while (wp != NULL) {
- list_append_number(rettv->vval.v_list, wp->w_buffer->b_fnum);
+ tv_list_append_number(rettv->vval.v_list, wp->w_buffer->b_fnum);
wp = wp->w_next;
}
}
@@ -17637,19 +16343,20 @@ static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_tabpagenr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int nr = 1;
- char_u *arg;
if (argvars[0].v_type != VAR_UNKNOWN) {
- arg = get_tv_string_chk(&argvars[0]);
+ const char *const arg = tv_get_string_chk(&argvars[0]);
nr = 0;
if (arg != NULL) {
- if (STRCMP(arg, "$") == 0)
+ if (strcmp(arg, "$") == 0) {
nr = tabpage_index(NULL) - 1;
- else
+ } else {
EMSG2(_(e_invexpr2), arg);
+ }
}
- } else
+ } else {
nr = tabpage_index(curtab);
+ }
rettv->vval.v_number = nr;
}
@@ -17663,19 +16370,19 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
win_T *twin;
int nr = 1;
win_T *wp;
- char_u *arg;
twin = (tp == curtab) ? curwin : tp->tp_curwin;
if (argvar->v_type != VAR_UNKNOWN) {
- arg = get_tv_string_chk(argvar);
- if (arg == NULL)
- nr = 0; /* type error; errmsg already given */
- else if (STRCMP(arg, "$") == 0)
+ const char *const arg = tv_get_string_chk(argvar);
+ if (arg == NULL) {
+ nr = 0; // Type error; errmsg already given.
+ } else if (strcmp(arg, "$") == 0) {
twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
- else if (STRCMP(arg, "#") == 0) {
+ } else if (strcmp(arg, "#") == 0) {
twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
- if (twin == NULL)
+ if (twin == NULL) {
nr = 0;
+ }
} else {
EMSG2(_(e_invexpr2), arg);
nr = 0;
@@ -17701,13 +16408,12 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int nr = 1;
- tabpage_T *tp;
-
- tp = find_tabpage((int)get_tv_number(&argvars[0]));
- if (tp == NULL)
+ tabpage_T *const tp = find_tabpage((int)tv_get_number(&argvars[0]));
+ if (tp == NULL) {
nr = 0;
- else
+ } else {
nr = get_winnr(tp, &argvars[1]);
+ }
rettv->vval.v_number = nr;
}
@@ -17717,16 +16423,16 @@ static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_tagfiles(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *fname;
+ char *fname;
tagname_T tn;
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
fname = xmalloc(MAXPATHL);
- int first = TRUE;
- while (get_tagfname(&tn, first, fname) == OK) {
- list_append_string(rettv->vval.v_list, fname, -1);
- first = FALSE;
+ bool first = true;
+ while (get_tagfname(&tn, first, (char_u *)fname) == OK) {
+ tv_list_append_string(rettv->vval.v_list, fname, -1);
+ first = false;
}
tagname_free(&tn);
@@ -17738,15 +16444,14 @@ static void f_tagfiles(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_taglist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *tag_pattern;
+ const char *const tag_pattern = tv_get_string(&argvars[0]);
- tag_pattern = get_tv_string(&argvars[0]);
-
- rettv->vval.v_number = FALSE;
- if (*tag_pattern == NUL)
+ rettv->vval.v_number = false;
+ if (*tag_pattern == NUL) {
return;
+ }
- (void)get_tags(rettv_list_alloc(rettv), tag_pattern);
+ (void)get_tags(tv_list_alloc_ret(rettv), (char_u *)tag_pattern);
}
/*
@@ -17770,7 +16475,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- char *cmd;
+ const char *cmd;
bool executable = true;
char **argv = tv_to_argv(&argvars[0], &cmd, &executable);
if (!argv) {
@@ -17788,15 +16493,15 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
Callback on_stdout = CALLBACK_NONE, on_stderr = CALLBACK_NONE,
on_exit = CALLBACK_NONE;
dict_T *job_opts = NULL;
- char *cwd = ".";
+ const char *cwd = ".";
if (argvars[1].v_type == VAR_DICT) {
job_opts = argvars[1].vval.v_dict;
- char *new_cwd = (char *)get_dict_string(job_opts, "cwd", false);
- if (new_cwd && strlen(new_cwd) > 0) {
+ const char *const new_cwd = tv_dict_get_string(job_opts, "cwd", false);
+ if (new_cwd && *new_cwd != NUL) {
cwd = new_cwd;
// The new cwd must be a directory.
- if (!os_isdir((char_u *)cwd)) {
+ if (!os_isdir((const char_u *)cwd)) {
EMSG2(_(e_invarg2), "expected valid directory");
shell_free_argv(argv);
return;
@@ -17833,7 +16538,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// at this point the buffer has no terminal instance associated yet, so unset
// the 'swapfile' option to ensure no swap file will be created
curbuf->b_p_swf = false;
- (void)setfname(curbuf, (uint8_t *)buf, NULL, true);
+ (void)setfname(curbuf, (char_u *)buf, NULL, true);
// Save the job id and pid in b:terminal_job_{id,pid}
Error err;
dict_set_var(curbuf->b_vars, cstr_as_string("terminal_job_id"),
@@ -17857,7 +16562,8 @@ static void f_test_garbagecollect_now(typval_T *argvars,
garbage_collect(true);
}
-static bool callback_from_typval(Callback *callback, typval_T *arg)
+bool callback_from_typval(Callback *const callback, typval_T *const arg)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL) {
callback->data.partial = arg->vval.v_partial;
@@ -17877,53 +16583,33 @@ static bool callback_from_typval(Callback *callback, typval_T *arg)
return true;
}
-
/// Unref/free callback
-static void callback_free(Callback *callback)
+void callback_free(Callback *const callback)
+ FUNC_ATTR_NONNULL_ALL
{
switch (callback->type) {
- case kCallbackFuncref:
+ case kCallbackFuncref: {
func_unref(callback->data.funcref);
xfree(callback->data.funcref);
break;
-
- case kCallbackPartial:
+ }
+ case kCallbackPartial: {
partial_unref(callback->data.partial);
break;
-
- case kCallbackNone:
+ }
+ case kCallbackNone: {
break;
-
- default:
+ }
+ default: {
abort();
+ }
}
callback->type = kCallbackNone;
}
-static bool callback_equal(Callback *cb1, Callback *cb2)
-{
- if (cb1->type != cb2->type) {
- return false;
- }
- switch (cb1->type) {
- case kCallbackFuncref:
- return STRCMP(cb1->data.funcref, cb2->data.funcref) == 0;
-
- case kCallbackPartial:
- // FIXME: this is inconsistent with tv_equal but is needed for precision
- // maybe change dictwatcheradd to return a watcher id instead?
- return cb1->data.partial == cb2->data.partial;
-
- case kCallbackNone:
- return true;
-
- default:
- abort();
- }
-}
-
-static bool callback_call(Callback *callback, int argcount_in,
- typval_T *argvars_in, typval_T *rettv)
+bool callback_call(Callback *const callback, const int argcount_in,
+ typval_T *const argvars_in, typval_T *const rettv)
+ FUNC_ATTR_NONNULL_ALL
{
partial_T *partial;
char_u *name;
@@ -17979,7 +16665,7 @@ static bool set_ref_in_callback(Callback *callback, int copyID,
/// "timer_start(timeout, callback, opts)" function
static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- long timeout = get_tv_number(&argvars[0]);
+ const long timeout = tv_get_number(&argvars[0]);
timer_T *timer;
int repeat = 1;
dict_T *dict;
@@ -17989,11 +16675,12 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[2].v_type != VAR_UNKNOWN) {
if (argvars[2].v_type != VAR_DICT
|| (dict = argvars[2].vval.v_dict) == NULL) {
- EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
+ EMSG2(_(e_invarg2), tv_get_string(&argvars[2]));
return;
}
- if (dict_find(dict, (char_u *)"repeat", -1) != NULL) {
- repeat = get_dict_number(dict, "repeat");
+ dictitem_T *const di = tv_dict_find(dict, S_LEN("repeat"));
+ if (di != NULL) {
+ repeat = tv_get_number(&di->di_tv);
if (repeat == 0) {
repeat = 1;
}
@@ -18033,7 +16720,7 @@ static void f_timer_stop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- timer_T *timer = pmap_get(uint64_t)(timers, get_tv_number(&argvars[0]));
+ timer_T *timer = pmap_get(uint64_t)(timers, tv_get_number(&argvars[0]));
if (timer == NULL) {
return;
@@ -18055,15 +16742,13 @@ static void timer_due_cb(TimeWatcher *tw, void *data)
timer_stop(timer);
}
- typval_T argv[2];
- init_tv(argv);
+ typval_T argv[2] = { TV_INITIAL_VALUE, TV_INITIAL_VALUE };
argv[0].v_type = VAR_NUMBER;
argv[0].vval.v_number = timer->timer_id;
- typval_T rettv;
+ typval_T rettv = TV_INITIAL_VALUE;
- init_tv(&rettv);
callback_call(&timer->callback, 1, argv, &rettv);
- clear_tv(&rettv);
+ tv_clear(&rettv);
if (!timer->stopped && timer->timeout == 0) {
// special case: timeout=0 means the callback will be
@@ -18116,7 +16801,7 @@ void timer_teardown(void)
*/
static void f_tolower(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *p = vim_strsave(get_tv_string(&argvars[0]));
+ char_u *p = (char_u *)xstrdup(tv_get_string(&argvars[0]));
rettv->v_type = VAR_STRING;
rettv->vval.v_string = p;
@@ -18148,7 +16833,7 @@ static void f_tolower(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_toupper(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
+ rettv->vval.v_string = (char_u *)strup_save(tv_get_string(&argvars[0]));
}
/*
@@ -18156,77 +16841,71 @@ static void f_toupper(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_tr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *in_str;
- char_u *fromstr;
- char_u *tostr;
- char_u *p;
- int inlen;
- int fromlen;
- int tolen;
- int idx;
- char_u *cpstr;
- int cplen;
- int first = TRUE;
- char_u buf[NUMBUFLEN];
- char_u buf2[NUMBUFLEN];
- garray_T ga;
+ char buf[NUMBUFLEN];
+ char buf2[NUMBUFLEN];
- in_str = get_tv_string(&argvars[0]);
- fromstr = get_tv_string_buf_chk(&argvars[1], buf);
- tostr = get_tv_string_buf_chk(&argvars[2], buf2);
+ const char *in_str = tv_get_string(&argvars[0]);
+ const char *fromstr = tv_get_string_buf_chk(&argvars[1], buf);
+ const char *tostr = tv_get_string_buf_chk(&argvars[2], buf2);
- /* Default return value: empty string. */
+ // Default return value: empty string.
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
- if (fromstr == NULL || tostr == NULL)
- return; /* type error; errmsg already given */
+ if (fromstr == NULL || tostr == NULL) {
+ return; // Type error; errmsg already given.
+ }
+ garray_T ga;
ga_init(&ga, (int)sizeof(char), 80);
- if (!has_mbyte)
- /* not multi-byte: fromstr and tostr must be the same length */
- if (STRLEN(fromstr) != STRLEN(tostr)) {
-error:
- EMSG2(_(e_invarg2), fromstr);
- ga_clear(&ga);
- return;
+ if (!has_mbyte) {
+ // Not multi-byte: fromstr and tostr must be the same length.
+ if (strlen(fromstr) != strlen(tostr)) {
+ goto error;
}
+ }
- /* fromstr and tostr have to contain the same number of chars */
+ // fromstr and tostr have to contain the same number of chars.
+ bool first = true;
while (*in_str != NUL) {
if (has_mbyte) {
- inlen = (*mb_ptr2len)(in_str);
- cpstr = in_str;
- cplen = inlen;
- idx = 0;
- for (p = fromstr; *p != NUL; p += fromlen) {
- fromlen = (*mb_ptr2len)(p);
+ const char *cpstr = in_str;
+ const int inlen = (*mb_ptr2len)((const char_u *)in_str);
+ int cplen = inlen;
+ int idx = 0;
+ int fromlen;
+ for (const char *p = fromstr; *p != NUL; p += fromlen) {
+ fromlen = (*mb_ptr2len)((const char_u *)p);
if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0) {
+ int tolen;
for (p = tostr; *p != NUL; p += tolen) {
- tolen = (*mb_ptr2len)(p);
+ tolen = (*mb_ptr2len)((const char_u *)p);
if (idx-- == 0) {
cplen = tolen;
- cpstr = p;
+ cpstr = (char *)p;
break;
}
}
- if (*p == NUL) /* tostr is shorter than fromstr */
+ if (*p == NUL) { // tostr is shorter than fromstr.
goto error;
+ }
break;
}
- ++idx;
+ idx++;
}
if (first && cpstr == in_str) {
- /* Check that fromstr and tostr have the same number of
- * (multi-byte) characters. Done only once when a character
- * of in_str doesn't appear in fromstr. */
- first = FALSE;
- for (p = tostr; *p != NUL; p += tolen) {
- tolen = (*mb_ptr2len)(p);
- --idx;
+ // Check that fromstr and tostr have the same number of
+ // (multi-byte) characters. Done only once when a character
+ // of in_str doesn't appear in fromstr.
+ first = false;
+ int tolen;
+ for (const char *p = tostr; *p != NUL; p += tolen) {
+ tolen = (*mb_ptr2len)((const char_u *)p);
+ idx--;
}
- if (idx != 0)
+ if (idx != 0) {
goto error;
+ }
}
ga_grow(&ga, cplen);
@@ -18235,13 +16914,14 @@ error:
in_str += inlen;
} else {
- /* When not using multi-byte chars we can do it faster. */
- p = vim_strchr(fromstr, *in_str);
- if (p != NULL)
+ // When not using multi-byte chars we can do it faster.
+ const char *const p = strchr(fromstr, *in_str);
+ if (p != NULL) {
ga_append(&ga, tostr[p - fromstr]);
- else
+ } else {
ga_append(&ga, *in_str);
- ++in_str;
+ }
+ in_str++;
}
}
@@ -18249,6 +16929,11 @@ error:
ga_append(&ga, NUL);
rettv->vval.v_string = ga.ga_data;
+ return;
+error:
+ EMSG2(_(e_invarg2), fromstr);
+ ga_clear(&ga);
+ return;
}
/*
@@ -18294,20 +16979,18 @@ static void f_type(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_undofile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->v_type = VAR_STRING;
- {
- char_u *fname = get_tv_string(&argvars[0]);
+ const char *const fname = tv_get_string(&argvars[0]);
- if (*fname == NUL) {
- /* If there is no file name there will be no undo file. */
- rettv->vval.v_string = NULL;
- } else {
- char *ffname = FullName_save((char *)fname, false);
+ if (*fname == NUL) {
+ // If there is no file name there will be no undo file.
+ rettv->vval.v_string = NULL;
+ } else {
+ char *ffname = FullName_save(fname, false);
- if (ffname != NULL) {
- rettv->vval.v_string = (char_u *)u_get_undo_file_name(ffname, false);
- }
- xfree(ffname);
+ if (ffname != NULL) {
+ rettv->vval.v_string = (char_u *)u_get_undo_file_name(ffname, false);
}
+ xfree(ffname);
}
}
@@ -18316,22 +16999,22 @@ static void f_undofile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_undotree(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv_dict_alloc(rettv);
+ tv_dict_alloc_ret(rettv);
dict_T *dict = rettv->vval.v_dict;
list_T *list;
- dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
- dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
- dict_add_nr_str(dict, "save_last",
- (long)curbuf->b_u_save_nr_last, NULL);
- dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
- dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
- dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
+ tv_dict_add_nr(dict, S_LEN("synced"), (varnumber_T)curbuf->b_u_synced);
+ tv_dict_add_nr(dict, S_LEN("seq_last"), (varnumber_T)curbuf->b_u_seq_last);
+ tv_dict_add_nr(dict, S_LEN("save_last"),
+ (varnumber_T)curbuf->b_u_save_nr_last);
+ tv_dict_add_nr(dict, S_LEN("seq_cur"), (varnumber_T)curbuf->b_u_seq_cur);
+ tv_dict_add_nr(dict, S_LEN("time_cur"), (varnumber_T)curbuf->b_u_time_cur);
+ tv_dict_add_nr(dict, S_LEN("save_cur"), (varnumber_T)curbuf->b_u_save_nr_cur);
- list = list_alloc();
+ list = tv_list_alloc();
u_eval_tree(curbuf->b_u_oldhead, list);
- dict_add_list(dict, "entries", list);
+ tv_dict_add_list(dict, S_LEN("entries"), list);
}
/*
@@ -18390,7 +17073,7 @@ static void f_wildmenumode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "win_findbuf()" function
static void f_win_findbuf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
win_findbuf(argvars, rettv->vval.v_list);
}
@@ -18409,7 +17092,7 @@ static void f_win_gotoid(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "win_id2tabwin()" function
static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv_list_alloc(rettv);
+ tv_list_alloc_ret(rettv);
win_id2tabwin(argvars, rettv->vval.v_list);
}
@@ -18504,36 +17187,37 @@ static void f_winrestcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_winrestview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- dict_T *dict;
+ dict_T *dict;
if (argvars[0].v_type != VAR_DICT
- || (dict = argvars[0].vval.v_dict) == NULL)
- EMSG(_(e_invarg));
- else {
- if (dict_find(dict, (char_u *)"lnum", -1) != NULL) {
- curwin->w_cursor.lnum = get_dict_number(dict, "lnum");
+ || (dict = argvars[0].vval.v_dict) == NULL) {
+ emsgf(_(e_invarg));
+ } else {
+ dictitem_T *di;
+ if ((di = tv_dict_find(dict, S_LEN("lnum"))) != NULL) {
+ curwin->w_cursor.lnum = tv_get_number(&di->di_tv);
}
- if (dict_find(dict, (char_u *)"col", -1) != NULL) {
- curwin->w_cursor.col = get_dict_number(dict, "col");
+ if ((di = tv_dict_find(dict, S_LEN("col"))) != NULL) {
+ curwin->w_cursor.col = tv_get_number(&di->di_tv);
}
- if (dict_find(dict, (char_u *)"coladd", -1) != NULL) {
- curwin->w_cursor.coladd = get_dict_number(dict, "coladd");
+ if ((di = tv_dict_find(dict, S_LEN("coladd"))) != NULL) {
+ curwin->w_cursor.coladd = tv_get_number(&di->di_tv);
}
- if (dict_find(dict, (char_u *)"curswant", -1) != NULL) {
- curwin->w_curswant = get_dict_number(dict, "curswant");
+ if ((di = tv_dict_find(dict, S_LEN("curswant"))) != NULL) {
+ curwin->w_curswant = tv_get_number(&di->di_tv);
curwin->w_set_curswant = false;
}
- if (dict_find(dict, (char_u *)"topline", -1) != NULL) {
- set_topline(curwin, get_dict_number(dict, "topline"));
+ if ((di = tv_dict_find(dict, S_LEN("topline"))) != NULL) {
+ set_topline(curwin, tv_get_number(&di->di_tv));
}
- if (dict_find(dict, (char_u *)"topfill", -1) != NULL) {
- curwin->w_topfill = get_dict_number(dict, "topfill");
+ if ((di = tv_dict_find(dict, S_LEN("topfill"))) != NULL) {
+ curwin->w_topfill = tv_get_number(&di->di_tv);
}
- if (dict_find(dict, (char_u *)"leftcol", -1) != NULL) {
- curwin->w_leftcol = get_dict_number(dict, "leftcol");
+ if ((di = tv_dict_find(dict, S_LEN("leftcol"))) != NULL) {
+ curwin->w_leftcol = tv_get_number(&di->di_tv);
}
- if (dict_find(dict, (char_u *)"skipcol", -1) != NULL) {
- curwin->w_skipcol = get_dict_number(dict, "skipcol");
+ if ((di = tv_dict_find(dict, S_LEN("skipcol"))) != NULL) {
+ curwin->w_skipcol = tv_get_number(&di->di_tv);
}
check_cursor();
@@ -18556,19 +17240,19 @@ static void f_winsaveview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
dict_T *dict;
- rettv_dict_alloc(rettv);
+ tv_dict_alloc_ret(rettv);
dict = rettv->vval.v_dict;
- dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
- dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
- dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
+ tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)curwin->w_cursor.lnum);
+ tv_dict_add_nr(dict, S_LEN("col"), (varnumber_T)curwin->w_cursor.col);
+ tv_dict_add_nr(dict, S_LEN("coladd"), (varnumber_T)curwin->w_cursor.coladd);
update_curswant();
- dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
+ tv_dict_add_nr(dict, S_LEN("curswant"), (varnumber_T)curwin->w_curswant);
- dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
- dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
- dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
- dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
+ tv_dict_add_nr(dict, S_LEN("topline"), (varnumber_T)curwin->w_topline);
+ tv_dict_add_nr(dict, S_LEN("topfill"), (varnumber_T)curwin->w_topfill);
+ tv_dict_add_nr(dict, S_LEN("leftcol"), (varnumber_T)curwin->w_leftcol);
+ tv_dict_add_nr(dict, S_LEN("skipcol"), (varnumber_T)curwin->w_skipcol);
}
/// Writes list of strings to file
@@ -18583,8 +17267,7 @@ static bool write_list(FileDescriptor *const fp, const list_T *const list,
{
int error = 0;
for (const listitem_T *li = list->lv_first; li != NULL; li = li->li_next) {
- const char *const s = (const char *)get_tv_string_chk(
- (typval_T *)&li->li_tv);
+ const char *const s = tv_get_string_chk(&li->li_tv);
if (s == NULL) {
return false;
}
@@ -18619,7 +17302,7 @@ static bool write_list(FileDescriptor *const fp, const list_T *const list,
}
}
}
- if ((error = file_fsync(fp)) != 0) {
+ if ((error = file_flush(fp)) != 0) {
goto write_list_error;
}
return true;
@@ -18665,7 +17348,7 @@ void init_static_list(staticList10_T *sl)
/// @param[in] endnl If true, the output will end in a newline (if a list).
/// @returns an allocated string if `tv` represents a VimL string, list, or
/// number; NULL otherwise.
-static char_u *save_tv_as_string(typval_T *tv, ssize_t *len, bool endnl)
+static char *save_tv_as_string(typval_T *tv, ptrdiff_t *const len, bool endnl)
FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{
if (tv->v_type == VAR_UNKNOWN) {
@@ -18673,34 +17356,33 @@ static char_u *save_tv_as_string(typval_T *tv, ssize_t *len, bool endnl)
return NULL;
}
- // For types other than list, let get_tv_string_buf_chk() get the value or
+ // For types other than list, let tv_get_string_buf_chk() get the value or
// print an error.
if (tv->v_type != VAR_LIST) {
- char_u *ret = get_tv_string_chk(tv);
- if (ret && (*len = STRLEN(ret))) {
- ret = vim_strsave(ret);
+ const char *ret = tv_get_string_chk(tv);
+ if (ret && (*len = strlen(ret))) {
+ return xmemdupz(ret, (size_t)(*len));
} else {
- ret = NULL;
*len = -1;
+ return NULL;
}
- return ret;
}
// Pre-calculate the resulting length.
*len = 0;
list_T *list = tv->vval.v_list;
for (listitem_T *li = list->lv_first; li != NULL; li = li->li_next) {
- *len += STRLEN(get_tv_string(&li->li_tv)) + 1;
+ *len += strlen(tv_get_string(&li->li_tv)) + 1;
}
if (*len == 0) {
return NULL;
}
- char_u *ret = xmalloc(*len + endnl);
- char_u *end = ret;
+ char *ret = xmalloc(*len + endnl);
+ char *end = ret;
for (listitem_T *li = list->lv_first; li != NULL; li = li->li_next) {
- for (char_u *s = get_tv_string(&li->li_tv); *s != NUL; s++) {
+ for (const char *s = tv_get_string(&li->li_tv); *s != NUL; s++) {
*end++ = (*s == '\n') ? NUL : *s;
}
if (endnl || li->li_next != NULL) {
@@ -18729,7 +17411,7 @@ static void f_winwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "wordcount()" function
static void f_wordcount(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv_dict_alloc(rettv);
+ tv_dict_alloc_ret(rettv);
cursor_pos_info(rettv->vval.v_dict);
}
@@ -18752,40 +17434,47 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
bool binary = false;
bool append = false;
+ bool do_fsync = !!p_fs;
if (argvars[2].v_type != VAR_UNKNOWN) {
- const char *const flags = (const char *)get_tv_string_chk(&argvars[2]);
+ const char *const flags = tv_get_string_chk(&argvars[2]);
if (flags == NULL) {
return;
}
- if (strchr(flags, 'b')) {
- binary = true;
- }
- if (strchr(flags, 'a')) {
- append = true;
+ for (const char *p = flags; *p; p++) {
+ switch (*p) {
+ case 'b': { binary = true; break; }
+ case 'a': { append = true; break; }
+ case 's': { do_fsync = true; break; }
+ case 'S': { do_fsync = false; break; }
+ default: {
+ // Using %s, p and not %c, *p to preserve multibyte characters
+ emsgf(_("E5060: Unknown flag: %s"), p);
+ return;
+ }
+ }
}
}
- const char buf[NUMBUFLEN];
- const char *const fname = (const char *)get_tv_string_buf_chk(&argvars[1],
- (char_u *)buf);
+ char buf[NUMBUFLEN];
+ const char *const fname = tv_get_string_buf_chk(&argvars[1], buf);
if (fname == NULL) {
return;
}
- FileDescriptor *fp;
+ FileDescriptor fp;
int error;
rettv->vval.v_number = -1;
if (*fname == NUL) {
EMSG(_("E482: Can't open file with an empty name"));
- } else if ((fp = file_open_new(&error, fname,
- ((append ? kFileAppend : kFileTruncate)
- | kFileCreate), 0666)) == NULL) {
+ } else if ((error = file_open(&fp, fname,
+ ((append ? kFileAppend : kFileTruncate)
+ | kFileCreate), 0666)) != 0) {
emsgf(_("E482: Can't open file %s for writing: %s"),
fname, os_strerror(error));
} else {
- if (write_list(fp, argvars[0].vval.v_list, binary)) {
+ if (write_list(&fp, argvars[0].vval.v_list, binary)) {
rettv->vval.v_number = 0;
}
- if ((error = file_free(fp)) != 0) {
+ if ((error = file_close(&fp, do_fsync)) != 0) {
emsgf(_("E80: Error when closing file %s: %s"),
fname, os_strerror(error));
}
@@ -18796,82 +17485,96 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_xor(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
- ^ get_tv_number_chk(&argvars[1], NULL);
+ rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
+ ^ tv_get_number_chk(&argvars[1], NULL);
}
-/*
- * Translate a String variable into a position.
- * Returns NULL when there is an error.
- */
-static pos_T *
-var2fpos (
- typval_T *varp,
- int dollar_lnum, /* TRUE when $ is last line */
- int *fnum /* set to fnum for '0, 'A, etc. */
-)
+/// Translate a VimL object into a position
+///
+/// Accepts VAR_LIST and VAR_STRING objects. Does not give an error for invalid
+/// type.
+///
+/// @param[in] tv Object to translate.
+/// @param[in] dollar_lnum True when "$" is last line.
+/// @param[out] ret_fnum Set to fnum for marks.
+///
+/// @return Pointer to position or NULL in case of error (e.g. invalid type).
+pos_T *var2fpos(const typval_T *const tv, const int dollar_lnum,
+ int *const ret_fnum)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- char_u *name;
static pos_T pos;
pos_T *pp;
- /* Argument can be [lnum, col, coladd]. */
- if (varp->v_type == VAR_LIST) {
+ // Argument can be [lnum, col, coladd].
+ if (tv->v_type == VAR_LIST) {
list_T *l;
int len;
- int error = FALSE;
- listitem_T *li;
+ bool error = false;
+ listitem_T *li;
- l = varp->vval.v_list;
- if (l == NULL)
+ l = tv->vval.v_list;
+ if (l == NULL) {
return NULL;
+ }
- /* Get the line number */
- pos.lnum = list_find_nr(l, 0L, &error);
- if (error || pos.lnum <= 0 || pos.lnum > curbuf->b_ml.ml_line_count)
- return NULL; /* invalid line number */
+ // Get the line number.
+ pos.lnum = tv_list_find_nr(l, 0L, &error);
+ if (error || pos.lnum <= 0 || pos.lnum > curbuf->b_ml.ml_line_count) {
+ // Invalid line number.
+ return NULL;
+ }
- /* Get the column number */
- pos.col = list_find_nr(l, 1L, &error);
- if (error)
+ // Get the column number.
+ pos.col = tv_list_find_nr(l, 1L, &error);
+ if (error) {
return NULL;
+ }
len = (long)STRLEN(ml_get(pos.lnum));
- /* We accept "$" for the column number: last column. */
- li = list_find(l, 1L);
+ // We accept "$" for the column number: last column.
+ li = tv_list_find(l, 1L);
if (li != NULL && li->li_tv.v_type == VAR_STRING
&& li->li_tv.vval.v_string != NULL
- && STRCMP(li->li_tv.vval.v_string, "$") == 0)
+ && STRCMP(li->li_tv.vval.v_string, "$") == 0) {
pos.col = len + 1;
+ }
- /* Accept a position up to the NUL after the line. */
- if (pos.col == 0 || (int)pos.col > len + 1)
- return NULL; /* invalid column number */
- --pos.col;
+ // Accept a position up to the NUL after the line.
+ if (pos.col == 0 || (int)pos.col > len + 1) {
+ // Invalid column number.
+ return NULL;
+ }
+ pos.col--;
- /* Get the virtual offset. Defaults to zero. */
- pos.coladd = list_find_nr(l, 2L, &error);
- if (error)
+ // Get the virtual offset. Defaults to zero.
+ pos.coladd = tv_list_find_nr(l, 2L, &error);
+ if (error) {
pos.coladd = 0;
+ }
return &pos;
}
- name = get_tv_string_chk(varp);
- if (name == NULL)
+ const char *const name = tv_get_string_chk(tv);
+ if (name == NULL) {
return NULL;
- if (name[0] == '.') /* cursor */
+ }
+ if (name[0] == '.') { // Cursor.
return &curwin->w_cursor;
- if (name[0] == 'v' && name[1] == NUL) { /* Visual start */
- if (VIsual_active)
+ }
+ if (name[0] == 'v' && name[1] == NUL) { // Visual start.
+ if (VIsual_active) {
return &VIsual;
+ }
return &curwin->w_cursor;
}
- if (name[0] == '\'') { /* mark */
- pp = getmark_buf_fnum(curbuf, name[1], FALSE, fnum);
- if (pp == NULL || pp == (pos_T *)-1 || pp->lnum <= 0)
+ if (name[0] == '\'') { // Mark.
+ pp = getmark_buf_fnum(curbuf, (uint8_t)name[1], false, ret_fnum);
+ if (pp == NULL || pp == (pos_T *)-1 || pp->lnum <= 0) {
return NULL;
+ }
return pp;
}
@@ -18924,32 +17627,37 @@ static int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp)
return FAIL;
if (fnump != NULL) {
- n = list_find_nr(l, i++, NULL); /* fnum */
- if (n < 0)
+ n = tv_list_find_nr(l, i++, NULL); // fnum
+ if (n < 0) {
return FAIL;
- if (n == 0)
- n = curbuf->b_fnum; /* current buffer */
+ }
+ if (n == 0) {
+ n = curbuf->b_fnum; // Current buffer.
+ }
*fnump = n;
}
- n = list_find_nr(l, i++, NULL); /* lnum */
- if (n < 0)
+ n = tv_list_find_nr(l, i++, NULL); // lnum
+ if (n < 0) {
return FAIL;
+ }
posp->lnum = n;
- n = list_find_nr(l, i++, NULL); /* col */
- if (n < 0)
+ n = tv_list_find_nr(l, i++, NULL); // col
+ if (n < 0) {
return FAIL;
+ }
posp->col = n;
- n = list_find_nr(l, i, NULL); // off
- if (n < 0)
+ n = tv_list_find_nr(l, i, NULL); // off
+ if (n < 0) {
posp->coladd = 0;
- else
+ } else {
posp->coladd = n;
+ }
if (curswantp != NULL) {
- *curswantp = list_find_nr(l, i + 1, NULL); // curswant
+ *curswantp = tv_list_find_nr(l, i + 1, NULL); // curswant
}
return OK;
@@ -18960,15 +17668,16 @@ static int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp)
* Advance "arg" to the first character after the name.
* Return 0 for error.
*/
-static int get_env_len(char_u **arg)
+static int get_env_len(const char_u **arg)
{
- char_u *p;
int len;
- for (p = *arg; vim_isIDc(*p); ++p)
- ;
- if (p == *arg) /* no name found */
+ const char_u *p;
+ for (p = *arg; vim_isIDc(*p); p++) {
+ }
+ if (p == *arg) { // No name found.
return 0;
+ }
len = (int)(p - *arg);
*arg = p;
@@ -19020,8 +17729,6 @@ static int get_name_len(const char **const arg,
int verbose)
{
int len;
- char_u *expr_start;
- char_u *expr_end;
*alias = NULL; /* default to no alias */
@@ -19037,12 +17744,12 @@ static int get_name_len(const char **const arg,
*arg += len;
}
- /*
- * Find the end of the name; check for {} construction.
- */
+ // Find the end of the name; check for {} construction.
+ char_u *expr_start;
+ char_u *expr_end;
const char *p = (const char *)find_name_end((char_u *)(*arg),
- &expr_start,
- &expr_end,
+ (const char_u **)&expr_start,
+ (const char_u **)&expr_end,
len > 0 ? 0 : FNE_CHECK_START);
if (expr_start != NULL) {
if (!evaluate) {
@@ -19078,12 +17785,11 @@ static int get_name_len(const char **const arg,
// "flags" can have FNE_INCL_BR and FNE_CHECK_START.
// Return a pointer to just after the name. Equal to "arg" if there is no
// valid name.
-static char_u *find_name_end(char_u *arg, char_u **expr_start,
- char_u **expr_end, int flags)
+static const char_u *find_name_end(const char_u *arg, const char_u **expr_start,
+ const char_u **expr_end, int flags)
{
int mb_nest = 0;
int br_nest = 0;
- char_u *p;
int len;
if (expr_start != NULL) {
@@ -19096,6 +17802,7 @@ static char_u *find_name_end(char_u *arg, char_u **expr_start,
return arg;
}
+ const char_u *p;
for (p = arg; *p != NUL
&& (eval_isnamec(*p)
|| *p == '{'
@@ -19167,7 +17874,8 @@ static char_u *find_name_end(char_u *arg, char_u **expr_start,
* Returns a new allocated string, which the caller must free.
* Returns NULL for failure.
*/
-static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end)
+static char_u *make_expanded_name(const char_u *in_start, char_u *expr_start,
+ char_u *expr_end, char_u *in_end)
{
char_u c1;
char_u *retval = NULL;
@@ -19196,7 +17904,9 @@ static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *
*expr_end = '}';
if (retval != NULL) {
- temp_result = find_name_end(retval, &expr_start, &expr_end, 0);
+ temp_result = (char_u *)find_name_end(retval,
+ (const char_u **)&expr_start,
+ (const char_u **)&expr_end, 0);
if (expr_start != NULL) {
/* Further expansion! */
temp_result = make_expanded_name(retval, expr_start,
@@ -19240,7 +17950,7 @@ long get_vim_var_nr(int idx) FUNC_ATTR_PURE
*/
char_u *get_vim_var_str(int idx) FUNC_ATTR_PURE FUNC_ATTR_NONNULL_RET
{
- return get_tv_string(&vimvars[idx].vv_tv);
+ return (char_u *)tv_get_string(&vimvars[idx].vv_tv);
}
/*
@@ -19293,7 +18003,7 @@ void set_vcount(long count, long count1, int set_prevcount)
/// @param[in] val Value to set to.
void set_vim_var_nr(const VimVarIndex idx, const varnumber_T val)
{
- clear_tv(&vimvars[idx].vv_tv);
+ tv_clear(&vimvars[idx].vv_tv);
vimvars[idx].vv_type = VAR_NUMBER;
vimvars[idx].vv_nr = val;
}
@@ -19304,7 +18014,7 @@ void set_vim_var_nr(const VimVarIndex idx, const varnumber_T val)
/// @param[in] val Value to set to.
void set_vim_var_special(const VimVarIndex idx, const SpecialVarValue val)
{
- clear_tv(&vimvars[idx].vv_tv);
+ tv_clear(&vimvars[idx].vv_tv);
vimvars[idx].vv_type = VAR_SPECIAL;
vimvars[idx].vv_special = val;
}
@@ -19318,7 +18028,7 @@ void set_vim_var_special(const VimVarIndex idx, const SpecialVarValue val)
void set_vim_var_string(const VimVarIndex idx, const char *const val,
const ptrdiff_t len)
{
- clear_tv(&vimvars[idx].vv_di.di_tv);
+ tv_clear(&vimvars[idx].vv_di.di_tv);
vimvars[idx].vv_type = VAR_STRING;
if (val == NULL) {
vimvars[idx].vv_str = NULL;
@@ -19335,7 +18045,7 @@ void set_vim_var_string(const VimVarIndex idx, const char *const val,
/// @param[in,out] val Value to set to. Reference count will be incremented.
void set_vim_var_list(const VimVarIndex idx, list_T *const val)
{
- clear_tv(&vimvars[idx].vv_di.di_tv);
+ tv_clear(&vimvars[idx].vv_di.di_tv);
vimvars[idx].vv_type = VAR_LIST;
vimvars[idx].vv_list = val;
if (val != NULL) {
@@ -19350,14 +18060,14 @@ void set_vim_var_list(const VimVarIndex idx, list_T *const val)
/// Also keys of the dictionary will be made read-only.
void set_vim_var_dict(const VimVarIndex idx, dict_T *const val)
{
- clear_tv(&vimvars[idx].vv_di.di_tv);
+ tv_clear(&vimvars[idx].vv_di.di_tv);
vimvars[idx].vv_type = VAR_DICT;
vimvars[idx].vv_dict = val;
if (val != NULL) {
val->dv_refcount++;
// Set readonly
- dict_set_keys_readonly(val);
+ tv_dict_set_keys_readonly(val);
}
}
@@ -19502,7 +18212,7 @@ static int get_var_tv(
}
ret = FAIL;
} else if (rettv != NULL) {
- copy_tv(tv, rettv);
+ tv_copy(tv, rettv);
}
return ret;
@@ -19546,8 +18256,7 @@ handle_subscript(
while (ret == OK
&& (**arg == '['
|| (**arg == '.' && rettv->v_type == VAR_DICT)
- || (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC
- || rettv->v_type == VAR_PARTIAL)))
+ || (**arg == '(' && (!evaluate || tv_is_func(*rettv))))
&& !ascii_iswhite(*(*arg - 1))) {
if (**arg == '(') {
partial_T *pt = NULL;
@@ -19570,23 +18279,25 @@ handle_subscript(
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&len, evaluate, pt, selfdict);
- /* Clear the funcref afterwards, so that deleting it while
- * evaluating the arguments is possible (see test55). */
- if (evaluate)
- clear_tv(&functv);
+ // Clear the funcref afterwards, so that deleting it while
+ // evaluating the arguments is possible (see test55).
+ if (evaluate) {
+ tv_clear(&functv);
+ }
/* Stop the expression evaluation when immediately aborting on
* error, or when an interrupt occurred or an exception was thrown
* but not caught. */
if (aborting()) {
- if (ret == OK)
- clear_tv(rettv);
+ if (ret == OK) {
+ tv_clear(rettv);
+ }
ret = FAIL;
}
- dict_unref(selfdict);
+ tv_dict_unref(selfdict);
selfdict = NULL;
- } else { /* **arg == '[' || **arg == '.' */
- dict_unref(selfdict);
+ } else { // **arg == '[' || **arg == '.'
+ tv_dict_unref(selfdict);
if (rettv->v_type == VAR_DICT) {
selfdict = rettv->vval.v_dict;
if (selfdict != NULL)
@@ -19594,24 +18305,22 @@ handle_subscript(
} else
selfdict = NULL;
if (eval_index((char_u **)arg, rettv, evaluate, verbose) == FAIL) {
- clear_tv(rettv);
+ tv_clear(rettv);
ret = FAIL;
}
}
}
// Turn "dict.Func" into a partial for "Func" bound to "dict".
- if (selfdict != NULL
- && (rettv->v_type == VAR_FUNC
- || rettv->v_type == VAR_PARTIAL)) {
+ if (selfdict != NULL && tv_is_func(*rettv)) {
set_selfdict(rettv, selfdict);
}
- dict_unref(selfdict);
+ tv_dict_unref(selfdict);
return ret;
}
-static void set_selfdict(typval_T *rettv, dict_T *selfdict)
+void set_selfdict(typval_T *rettv, dict_T *selfdict)
{
// Don't do this when "dict.Func" is already a partial that was bound
// explicitly (pt_auto is false).
@@ -19672,7 +18381,7 @@ static void set_selfdict(typval_T *rettv, dict_T *selfdict)
} else {
pt->pt_argc = ret_pt->pt_argc;
for (i = 0; i < pt->pt_argc; i++) {
- copy_tv(&ret_pt->pt_argv[i], &pt->pt_argv[i]);
+ tv_copy(&ret_pt->pt_argv[i], &pt->pt_argv[i]);
}
}
}
@@ -19684,553 +18393,26 @@ static void set_selfdict(typval_T *rettv, dict_T *selfdict)
}
}
-/*
- * Free the memory for a variable type-value.
- */
-void free_tv(typval_T *varp)
-{
- if (varp != NULL) {
- switch (varp->v_type) {
- case VAR_FUNC:
- func_unref(varp->vval.v_string);
- // FALLTHROUGH
- case VAR_STRING:
- xfree(varp->vval.v_string);
- break;
- case VAR_PARTIAL:
- partial_unref(varp->vval.v_partial);
- break;
- case VAR_LIST:
- list_unref(varp->vval.v_list);
- break;
- case VAR_DICT:
- dict_unref(varp->vval.v_dict);
- break;
- case VAR_SPECIAL:
- case VAR_NUMBER:
- case VAR_FLOAT:
- case VAR_UNKNOWN:
- break;
- }
- xfree(varp);
- }
-}
-
-#define TYPVAL_ENCODE_ALLOW_SPECIALS false
-
-#define TYPVAL_ENCODE_CONV_NIL(tv) \
- do { \
- tv->vval.v_special = kSpecialVarFalse; \
- tv->v_lock = VAR_UNLOCKED; \
- } while (0)
-
-#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \
- TYPVAL_ENCODE_CONV_NIL(tv)
-
-#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \
- do { \
- (void)num; \
- tv->vval.v_number = 0; \
- tv->v_lock = VAR_UNLOCKED; \
- } while (0)
-
-#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num)
-
-#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \
- do { \
- tv->vval.v_float = 0; \
- tv->v_lock = VAR_UNLOCKED; \
- } while (0)
-
-#define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \
- do { \
- xfree(buf); \
- tv->vval.v_string = NULL; \
- tv->v_lock = VAR_UNLOCKED; \
- } while (0)
-
-#define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len)
-
-#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type)
-
-static inline int _nothing_conv_func_start(typval_T *const tv,
- char_u *const fun)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1)
-{
- tv->v_lock = VAR_UNLOCKED;
- if (tv->v_type == VAR_PARTIAL) {
- partial_T *const pt_ = tv->vval.v_partial;
- if (pt_ != NULL && pt_->pt_refcount > 1) {
- pt_->pt_refcount--;
- tv->vval.v_partial = NULL;
- return OK;
- }
- } else {
- func_unref(fun);
- if (fun != empty_string) {
- xfree(fun);
- }
- tv->vval.v_string = NULL;
- }
- return NOTDONE;
-}
-#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
- do { \
- if (_nothing_conv_func_start(tv, fun) != NOTDONE) { \
- return OK; \
- } \
- } while (0)
-
-#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len)
-#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len)
-
-static inline void _nothing_conv_func_end(typval_T *const tv, const int copyID)
- FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
-{
- if (tv->v_type == VAR_PARTIAL) {
- partial_T *const pt = tv->vval.v_partial;
- if (pt == NULL) {
- return;
- }
- // Dictionary should already be freed by the time.
- // If it was not freed then it is a part of the reference cycle.
- assert(pt->pt_dict == NULL || pt->pt_dict->dv_copyID == copyID);
- pt->pt_dict = NULL;
- // As well as all arguments.
- pt->pt_argc = 0;
- assert(pt->pt_refcount <= 1);
- partial_unref(pt);
- tv->vval.v_partial = NULL;
- assert(tv->v_lock == VAR_UNLOCKED);
- }
-}
-#define TYPVAL_ENCODE_CONV_FUNC_END(tv) _nothing_conv_func_end(tv, copyID)
-
-#define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \
- do { \
- list_unref(tv->vval.v_list); \
- tv->vval.v_list = NULL; \
- tv->v_lock = VAR_UNLOCKED; \
- } while (0)
-
-#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \
- do { \
- assert((void *)&dict != (void *)&TYPVAL_ENCODE_NODICT_VAR); \
- dict_unref((dict_T *)dict); \
- *((dict_T **)&dict) = NULL; \
- if (tv != NULL) { \
- ((typval_T *)tv)->v_lock = VAR_UNLOCKED; \
- } \
- } while (0)
-
-static inline int _nothing_conv_real_list_after_start(
- typval_T *const tv, MPConvStackVal *const mpsv)
- FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT
-{
- assert(tv != NULL);
- tv->v_lock = VAR_UNLOCKED;
- if (tv->vval.v_list->lv_refcount > 1) {
- tv->vval.v_list->lv_refcount--;
- tv->vval.v_list = NULL;
- mpsv->data.l.li = NULL;
- return OK;
- }
- return NOTDONE;
-}
-#define TYPVAL_ENCODE_CONV_LIST_START(tv, len)
-
-#define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) \
- do { \
- if (_nothing_conv_real_list_after_start(tv, &mpsv) != NOTDONE) { \
- goto typval_encode_stop_converting_one_item; \
- } \
- } while (0)
-
-#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv)
-
-static inline void _nothing_conv_list_end(typval_T *const tv)
- FUNC_ATTR_ALWAYS_INLINE
-{
- if (tv == NULL) {
- return;
- }
- assert(tv->v_type == VAR_LIST);
- list_T *const list = tv->vval.v_list;
- list_unref(list);
- tv->vval.v_list = NULL;
-}
-#define TYPVAL_ENCODE_CONV_LIST_END(tv) _nothing_conv_list_end(tv)
-
-static inline int _nothing_conv_real_dict_after_start(
- typval_T *const tv, dict_T **const dictp, const void *const nodictvar,
- MPConvStackVal *const mpsv)
- FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT
-{
- if (tv != NULL) {
- tv->v_lock = VAR_UNLOCKED;
- }
- if ((const void *)dictp != nodictvar && (*dictp)->dv_refcount > 1) {
- (*dictp)->dv_refcount--;
- *dictp = NULL;
- mpsv->data.d.todo = 0;
- return OK;
- }
- return NOTDONE;
-}
-#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len)
-
-#define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv) \
- do { \
- if (_nothing_conv_real_dict_after_start( \
- tv, (dict_T **)&dict, (void *)&TYPVAL_ENCODE_NODICT_VAR, \
- &mpsv) != NOTDONE) { \
- goto typval_encode_stop_converting_one_item; \
- } \
- } while (0)
-
-#define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(tv, dict)
-#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict)
-#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict)
-
-static inline void _nothing_conv_dict_end(typval_T *const tv,
- dict_T **const dictp,
- const void *const nodictvar)
- FUNC_ATTR_ALWAYS_INLINE
-{
- if ((const void *)dictp != nodictvar) {
- dict_unref(*dictp);
- *dictp = NULL;
- }
-}
-#define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \
- _nothing_conv_dict_end(tv, (dict_T **)&dict, \
- (void *)&TYPVAL_ENCODE_NODICT_VAR)
-
-#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type)
-
-#define TYPVAL_ENCODE_SCOPE static
-#define TYPVAL_ENCODE_NAME nothing
-#define TYPVAL_ENCODE_FIRST_ARG_TYPE const void *const
-#define TYPVAL_ENCODE_FIRST_ARG_NAME ignored
-#include "nvim/eval/typval_encode.c.h"
-#undef TYPVAL_ENCODE_SCOPE
-#undef TYPVAL_ENCODE_NAME
-#undef TYPVAL_ENCODE_FIRST_ARG_TYPE
-#undef TYPVAL_ENCODE_FIRST_ARG_NAME
-
-#undef TYPVAL_ENCODE_ALLOW_SPECIALS
-#undef TYPVAL_ENCODE_CONV_NIL
-#undef TYPVAL_ENCODE_CONV_BOOL
-#undef TYPVAL_ENCODE_CONV_NUMBER
-#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER
-#undef TYPVAL_ENCODE_CONV_FLOAT
-#undef TYPVAL_ENCODE_CONV_STRING
-#undef TYPVAL_ENCODE_CONV_STR_STRING
-#undef TYPVAL_ENCODE_CONV_EXT_STRING
-#undef TYPVAL_ENCODE_CONV_FUNC_START
-#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS
-#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF
-#undef TYPVAL_ENCODE_CONV_FUNC_END
-#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
-#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
-#undef TYPVAL_ENCODE_CONV_LIST_START
-#undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START
-#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS
-#undef TYPVAL_ENCODE_CONV_LIST_END
-#undef TYPVAL_ENCODE_CONV_DICT_START
-#undef TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START
-#undef TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK
-#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY
-#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS
-#undef TYPVAL_ENCODE_CONV_DICT_END
-#undef TYPVAL_ENCODE_CONV_RECURSE
-
-/// Free memory for a variable value and set the value to NULL or 0
-///
-/// @param[in,out] varp Value to free.
-void clear_tv(typval_T *varp)
-{
- if (varp != NULL && varp->v_type != VAR_UNKNOWN) {
- const int evn_ret = encode_vim_to_nothing(varp, varp, "clear_tv argument");
- (void)evn_ret;
- assert(evn_ret == OK);
- }
-}
-
-/*
- * Set the value of a variable to NULL without freeing items.
- */
-static void init_tv(typval_T *varp)
-{
- if (varp != NULL)
- memset(varp, 0, sizeof(typval_T));
-}
-
-/// Check that given value is a number or string
-///
-/// Error messages are compatible with get_tv_number() previously used for the
-/// same purpose in buf*() functions. Special values are not accepted (previous
-/// behaviour: silently fail to find buffer).
-///
-/// @param[in] tv Value to check.
-///
-/// @return true if everything is OK, false otherwise.
-bool tv_check_str_or_nr(const typval_T *const tv)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
-{
- switch (tv->v_type) {
- case VAR_NUMBER:
- case VAR_STRING: {
- return true;
- }
- case VAR_FLOAT: {
- EMSG(_("E805: Expected a Number or a String, Float found"));
- return false;
- }
- case VAR_PARTIAL:
- case VAR_FUNC: {
- EMSG(_("E703: Expected a Number or a String, Funcref found"));
- return false;
- }
- case VAR_LIST: {
- EMSG(_("E745: Expected a Number or a String, List found"));
- return false;
- }
- case VAR_DICT: {
- EMSG(_("E728: Expected a Number or a String, Dictionary found"));
- return false;
- }
- case VAR_SPECIAL: {
- EMSG(_("E5300: Expected a Number or a String"));
- return false;
- }
- case VAR_UNKNOWN: {
- EMSG2(_(e_intern2), "tv_check_str_or_nr(UNKNOWN)");
- return false;
- }
- }
- assert(false);
- return false;
-}
-
-/*
- * Get the number value of a variable.
- * If it is a String variable, uses vim_str2nr().
- * For incompatible types, return 0.
- * get_tv_number_chk() is similar to get_tv_number(), but informs the
- * caller of incompatible types: it sets *denote to TRUE if "denote"
- * is not NULL or returns -1 otherwise.
- */
-long get_tv_number(typval_T *varp)
-{
- int error = FALSE;
-
- return get_tv_number_chk(varp, &error); /* return 0L on error */
-}
-
-long get_tv_number_chk(typval_T *varp, int *denote)
-{
- long n = 0L;
-
- switch (varp->v_type) {
- case VAR_NUMBER:
- return (long)(varp->vval.v_number);
- case VAR_FLOAT:
- EMSG(_("E805: Using a Float as a Number"));
- break;
- case VAR_FUNC:
- case VAR_PARTIAL:
- EMSG(_("E703: Using a Funcref as a Number"));
- break;
- case VAR_STRING:
- if (varp->vval.v_string != NULL) {
- vim_str2nr(varp->vval.v_string, NULL, NULL,
- STR2NR_ALL, &n, NULL, 0);
- }
- return n;
- case VAR_LIST:
- EMSG(_("E745: Using a List as a Number"));
- break;
- case VAR_DICT:
- EMSG(_("E728: Using a Dictionary as a Number"));
- break;
- case VAR_SPECIAL:
- switch (varp->vval.v_special) {
- case kSpecialVarTrue: {
- return 1;
- }
- case kSpecialVarFalse:
- case kSpecialVarNull: {
- return 0;
- }
- }
- break;
- case VAR_UNKNOWN:
- EMSG2(_(e_intern2), "get_tv_number(UNKNOWN)");
- break;
- }
- if (denote == NULL) {
- // useful for values that must be unsigned
- n = -1;
- } else {
- *denote = true;
- }
- return n;
-}
-
-static float_T get_tv_float(typval_T *varp)
-{
- switch (varp->v_type) {
- case VAR_NUMBER:
- return (float_T)(varp->vval.v_number);
- case VAR_FLOAT:
- return varp->vval.v_float;
- break;
- case VAR_FUNC:
- case VAR_PARTIAL:
- EMSG(_("E891: Using a Funcref as a Float"));
- break;
- case VAR_STRING:
- EMSG(_("E892: Using a String as a Float"));
- break;
- case VAR_LIST:
- EMSG(_("E893: Using a List as a Float"));
- break;
- case VAR_DICT:
- EMSG(_("E894: Using a Dictionary as a Float"));
- break;
- default:
- EMSG2(_(e_intern2), "get_tv_float()");
- break;
- }
- return 0;
-}
-
-/*
- * Get the lnum from the first argument.
- * Also accepts ".", "$", etc., but that only works for the current buffer.
- * Returns -1 on error.
- */
-static linenr_T get_tv_lnum(typval_T *argvars)
-{
- typval_T rettv;
- linenr_T lnum;
-
- lnum = get_tv_number_chk(&argvars[0], NULL);
- if (lnum == 0) { /* no valid number, try using line() */
- rettv.v_type = VAR_NUMBER;
- f_line(argvars, &rettv, NULL);
- lnum = rettv.vval.v_number;
- clear_tv(&rettv);
- }
- return lnum;
-}
-
-/*
- * Get the lnum from the first argument.
- * Also accepts "$", then "buf" is used.
- * Returns 0 on error.
- */
-static linenr_T get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
-{
- if (argvars[0].v_type == VAR_STRING
- && argvars[0].vval.v_string != NULL
- && argvars[0].vval.v_string[0] == '$'
- && buf != NULL)
- return buf->b_ml.ml_line_count;
- return get_tv_number_chk(&argvars[0], NULL);
-}
-
-/*
- * Get the string value of a variable.
- * If it is a Number variable, the number is converted into a string.
- * get_tv_string() uses a single, static buffer. YOU CAN ONLY USE IT ONCE!
- * get_tv_string_buf() uses a given buffer.
- * If the String variable has never been set, return an empty string.
- * Never returns NULL;
- * get_tv_string_chk() and get_tv_string_buf_chk() are similar, but return
- * NULL on error.
- */
-static char_u *get_tv_string(const typval_T *varp)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
-{
- static char_u mybuf[NUMBUFLEN];
-
- return get_tv_string_buf(varp, mybuf);
-}
-
-static char_u *get_tv_string_buf(const typval_T *varp, char_u *buf)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
-{
- char_u *res = get_tv_string_buf_chk(varp, buf);
-
- return res != NULL ? res : (char_u *)"";
-}
-
-/// Careful: This uses a single, static buffer. YOU CAN ONLY USE IT ONCE!
-char_u *get_tv_string_chk(const typval_T *varp)
- FUNC_ATTR_NONNULL_ALL
-{
- static char_u mybuf[NUMBUFLEN];
-
- return get_tv_string_buf_chk(varp, mybuf);
-}
-
-char_u *get_tv_string_buf_chk(const typval_T *varp, char_u *buf)
- FUNC_ATTR_NONNULL_ALL
-{
- switch (varp->v_type) {
- case VAR_NUMBER:
- sprintf((char *)buf, "%" PRId64, (int64_t)varp->vval.v_number);
- return buf;
- case VAR_FUNC:
- case VAR_PARTIAL:
- EMSG(_("E729: using Funcref as a String"));
- break;
- case VAR_LIST:
- EMSG(_("E730: using List as a String"));
- break;
- case VAR_DICT:
- EMSG(_("E731: using Dictionary as a String"));
- break;
- case VAR_FLOAT:
- EMSG(_(e_float_as_string));
- break;
- case VAR_STRING:
- if (varp->vval.v_string != NULL)
- return varp->vval.v_string;
- return (char_u *)"";
- case VAR_SPECIAL:
- STRCPY(buf, encode_special_var_names[varp->vval.v_special]);
- return buf;
- case VAR_UNKNOWN:
- EMSG(_("E908: using an invalid value as a String"));
- break;
- }
- return NULL;
-}
-
-/*
- * Find variable "name" in the list of variables.
- * Return a pointer to it if found, NULL if not found.
- * Careful: "a:0" variables don't have a name.
- * When "htp" is not NULL we are writing to the variable, set "htp" to the
- * hashtab_T used.
- */
+// Find variable "name" in the list of variables.
+// Return a pointer to it if found, NULL if not found.
+// Careful: "a:0" variables don't have a name.
+// When "htp" is not NULL we are writing to the variable, set "htp" to the
+// hashtab_T used.
static dictitem_T *find_var(const char *const name, const size_t name_len,
hashtab_T **htp, int no_autoload)
{
const char *varname;
- hashtab_T *ht = find_var_ht(name, name_len, &varname);
+ hashtab_T *const ht = find_var_ht(name, name_len, &varname);
if (htp != NULL) {
*htp = ht;
}
if (ht == NULL) {
return NULL;
}
- dictitem_T *ret = find_var_in_ht(ht, *name,
- varname, name_len - (size_t)(varname - name),
- no_autoload || htp != NULL);
+ dictitem_T *const ret = find_var_in_ht(ht, *name,
+ varname,
+ name_len - (size_t)(varname - name),
+ no_autoload || htp != NULL);
if (ret != NULL) {
return ret;
}
@@ -20294,7 +18476,7 @@ static dictitem_T *find_var_in_ht(hashtab_T *const ht,
return NULL;
}
}
- return HI2DI(hi);
+ return TV_DICT_HI2DI(hi);
}
// Get function call environment based on backtrace debug level
@@ -20424,7 +18606,7 @@ static hashtab_T *find_var_ht(const char *name, const size_t name_len,
/*
* Get the string value of a (global/local) variable.
- * Note: see get_tv_string() for how long the pointer remains valid.
+ * Note: see tv_get_string() for how long the pointer remains valid.
* Returns NULL when it doesn't exist.
*/
char_u *get_var_value(const char *const name)
@@ -20435,7 +18617,7 @@ char_u *get_var_value(const char *const name)
if (v == NULL) {
return NULL;
}
- return get_tv_string(&v->di_tv);
+ return (char_u *)tv_get_string(&v->di_tv);
}
/*
@@ -20472,7 +18654,7 @@ void new_script_vars(scid_T id)
* Initialize dictionary "dict" as a scope and set variable "dict_var" to
* point to it.
*/
-void init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope)
+void init_var_dict(dict_T *dict, ScopeDictDictItem *dict_var, int scope)
{
hash_init(&dict->dv_hashtab);
dict->dv_lock = VAR_UNLOCKED;
@@ -20495,7 +18677,7 @@ void unref_var_dict(dict_T *dict)
/* Now the dict needs to be freed if no one else is using it, go back to
* normal reference counting. */
dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
- dict_unref(dict);
+ tv_dict_unref(dict);
}
/*
@@ -20526,9 +18708,9 @@ static void vars_clear_ext(hashtab_T *ht, int free_val)
// Free the variable. Don't remove it from the hashtab,
// ht_array might change then. hash_clear() takes care of it
// later.
- v = HI2DI(hi);
+ v = TV_DICT_HI2DI(hi);
if (free_val) {
- clear_tv(&v->di_tv);
+ tv_clear(&v->di_tv);
}
if (v->di_flags & DI_FLAGS_ALLOC) {
xfree(v);
@@ -20545,10 +18727,10 @@ static void vars_clear_ext(hashtab_T *ht, int free_val)
*/
static void delete_var(hashtab_T *ht, hashitem_T *hi)
{
- dictitem_T *di = HI2DI(hi);
+ dictitem_T *di = TV_DICT_HI2DI(hi);
hash_remove(ht, hi);
- clear_tv(&di->di_tv);
+ tv_clear(&di->di_tv);
xfree(di);
}
@@ -20604,55 +18786,47 @@ static void list_one_var_a(const char *prefix, const char *name,
}
}
-/*
- * Set variable "name" to value in "tv".
- * If the variable already exists, the value is updated.
- * Otherwise the variable is created.
- */
-static void
-set_var (
- char_u *name,
- typval_T *tv,
- int copy /* make copy of value in "tv" */
-)
+/// Set variable to the given value
+///
+/// If the variable already exists, the value is updated. Otherwise the variable
+/// is created.
+///
+/// @param[in] name Variable name to set.
+/// @param[in] name_len Length of the variable name.
+/// @param tv Variable value.
+/// @param[in] copy True if value in tv is to be copied.
+static void set_var(const char *name, const size_t name_len, typval_T *const tv,
+ const bool copy)
+ FUNC_ATTR_NONNULL_ALL
{
dictitem_T *v;
hashtab_T *ht;
- typval_T oldtv;
dict_T *dict;
- const size_t name_len = STRLEN(name);
- char_u *varname;
- ht = find_var_ht_dict((const char *)name, name_len, (const char **)&varname,
- &dict);
- bool watched = is_watched(dict);
-
- if (watched) {
- init_tv(&oldtv);
- }
+ const char *varname;
+ ht = find_var_ht_dict(name, name_len, &varname, &dict);
+ const bool watched = tv_dict_is_watched(dict);
if (ht == NULL || *varname == NUL) {
EMSG2(_(e_illvar), name);
return;
}
- v = find_var_in_ht(ht, 0,
- (const char *)varname, name_len - (size_t)(varname - name),
- true);
+ v = find_var_in_ht(ht, 0, varname, name_len - (size_t)(varname - name), true);
// Search in parent scope which is possible to reference from lambda
if (v == NULL) {
v = find_var_in_scoped_ht((const char *)name, name_len, true);
}
- if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
- && var_check_func_name(name, v == NULL)) {
+ if (tv_is_func(*tv) && !var_check_func_name(name, v == NULL)) {
return;
}
+ typval_T oldtv = TV_INITIAL_VALUE;
if (v != NULL) {
// existing variable, need to clear the value
- if (var_check_ro(v->di_flags, (const char *)name, name_len)
- || tv_check_lock(v->di_tv.v_lock, (const char *)name, name_len)) {
+ if (var_check_ro(v->di_flags, name, name_len)
+ || tv_check_lock(v->di_tv.v_lock, name, name_len)) {
return;
}
@@ -20661,19 +18835,19 @@ set_var (
if (ht == &vimvarht) {
if (v->di_tv.v_type == VAR_STRING) {
xfree(v->di_tv.vval.v_string);
- if (copy || tv->v_type != VAR_STRING)
- v->di_tv.vval.v_string = vim_strsave(get_tv_string(tv));
- else {
+ if (copy || tv->v_type != VAR_STRING) {
+ v->di_tv.vval.v_string = (char_u *)xstrdup(tv_get_string(tv));
+ } else {
// Take over the string to avoid an extra alloc/free.
v->di_tv.vval.v_string = tv->vval.v_string;
tv->vval.v_string = NULL;
}
return;
} else if (v->di_tv.v_type == VAR_NUMBER) {
- v->di_tv.vval.v_number = get_tv_number(tv);
- if (STRCMP(varname, "searchforward") == 0)
+ v->di_tv.vval.v_number = tv_get_number(tv);
+ if (strcmp(varname, "searchforward") == 0) {
set_search_direction(v->di_tv.vval.v_number ? '/' : '?');
- else if (STRCMP(varname, "hlsearch") == 0) {
+ } else if (strcmp(varname, "hlsearch") == 0) {
no_hlsearch = !v->di_tv.vval.v_number;
redraw_all_later(SOME_VALID);
}
@@ -20684,23 +18858,24 @@ set_var (
}
if (watched) {
- copy_tv(&v->di_tv, &oldtv);
+ tv_copy(&v->di_tv, &oldtv);
}
- clear_tv(&v->di_tv);
- } else { /* add a new variable */
- /* Can't add "v:" variable. */
+ tv_clear(&v->di_tv);
+ } else { // Add a new variable.
+ // Can't add "v:" variable.
if (ht == &vimvarht) {
- EMSG2(_(e_illvar), name);
+ emsgf(_(e_illvar), name);
return;
}
- /* Make sure the variable name is valid. */
- if (!valid_varname(varname))
+ // Make sure the variable name is valid.
+ if (!valid_varname(varname)) {
return;
+ }
- v = xmalloc(sizeof(dictitem_T) + STRLEN(varname));
+ v = xmalloc(sizeof(dictitem_T) + strlen(varname));
STRCPY(v->di_key, varname);
- if (hash_add(ht, DI2HIKEY(v)) == FAIL) {
+ if (tv_dict_add(dict, v) == FAIL) {
xfree(v);
return;
}
@@ -20708,19 +18883,19 @@ set_var (
}
if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) {
- copy_tv(tv, &v->di_tv);
+ tv_copy(tv, &v->di_tv);
} else {
v->di_tv = *tv;
v->di_tv.v_lock = 0;
- init_tv(tv);
+ tv_init(tv);
}
if (watched) {
if (oldtv.v_type == VAR_UNKNOWN) {
- dictwatcher_notify(dict, (char *)v->di_key, &v->di_tv, NULL);
+ tv_dict_watcher_notify(dict, (char *)v->di_key, &v->di_tv, NULL);
} else {
- dictwatcher_notify(dict, (char *)v->di_key, &v->di_tv, &oldtv);
- clear_tv(&oldtv);
+ tv_dict_watcher_notify(dict, (char *)v->di_key, &v->di_tv, &oldtv);
+ tv_clear(&oldtv);
}
}
}
@@ -20735,8 +18910,8 @@ set_var (
///
/// @return True if variable is read-only: either always or in sandbox when
/// sandbox is enabled, false otherwise.
-static bool var_check_ro(const int flags, const char *const name,
- const size_t name_len)
+bool var_check_ro(const int flags, const char *const name,
+ const size_t name_len)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
if (flags & DI_FLAGS_RO) {
@@ -20771,22 +18946,24 @@ static bool var_check_fixed(const int flags, const char *const name,
return false;
}
-/*
- * Check if a funcref is assigned to a valid variable name.
- * Return TRUE and give an error if not.
- */
-static int
-var_check_func_name (
- char_u *name, /* points to start of variable name */
- int new_var /* TRUE when creating the variable */
-)
+// TODO(ZyX-I): move to eval/expressions
+
+/// Check if name is a valid name to assign funcref to
+///
+/// @param[in] name Possible function/funcref name.
+/// @param[in] new_var True if it is a name for a variable.
+///
+/// @return false in case of error, true in case of success. Also gives an
+/// error message if appropriate.
+bool var_check_func_name(const char *const name, const bool new_var)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
// Allow for w: b: s: and t:.
if (!(vim_strchr((char_u *)"wbst", name[0]) != NULL && name[1] == ':')
&& !ASCII_ISUPPER((name[0] != NUL && name[1] == ':') ? name[2]
: name[0])) {
EMSG2(_("E704: Funcref variable name must start with a capital: %s"), name);
- return TRUE;
+ return false;
}
// Don't allow hiding a function. When "v" is not NULL we might be
// assigning another function to the same var, the type is checked
@@ -20794,116 +18971,33 @@ var_check_func_name (
if (new_var && function_exists((const char *)name, false)) {
EMSG2(_("E705: Variable name conflicts with existing function: %s"),
name);
- return true;
+ return false;
}
- return false;
+ return true;
}
-/*
- * Check if a variable name is valid.
- * Return FALSE and give an error if not.
- */
-static int valid_varname(char_u *varname)
-{
- char_u *p;
+// TODO(ZyX-I): move to eval/expressions
- for (p = varname; *p != NUL; ++p)
- if (!eval_isnamec1(*p) && (p == varname || !ascii_isdigit(*p))
- && *p != AUTOLOAD_CHAR) {
- EMSG2(_(e_illvar), varname);
- return FALSE;
- }
- return TRUE;
-}
-
-/// Check whether typval is locked
-///
-/// Also gives an error message.
+/// Check if a variable name is valid
///
-/// @param[in] lock Lock status.
-/// @param[in] name Value name, for use in error message.
-/// @param[in] name_len Value name length.
+/// @param[in] varname Variable name to check.
///
-/// @return True if value is locked.
-static bool tv_check_lock(const VarLockStatus lock,
- const char *const name,
- const size_t name_len)
- FUNC_ATTR_WARN_UNUSED_RESULT
+/// @return false when variable name is not valid, true when it is. Also gives
+/// an error message if appropriate.
+bool valid_varname(const char *varname)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- const char *error_message = NULL;
- switch (lock) {
- case VAR_UNLOCKED: {
+ for (const char *p = varname; *p != NUL; p++) {
+ if (!eval_isnamec1((int)(uint8_t)(*p))
+ && (p == varname || !ascii_isdigit(*p))
+ && *p != AUTOLOAD_CHAR) {
+ emsgf(_(e_illvar), varname);
return false;
}
- case VAR_LOCKED: {
- error_message = N_("E741: Value is locked: %.*s");
- break;
- }
- case VAR_FIXED: {
- error_message = N_("E742: Cannot change value of %.*s");
- break;
- }
}
- assert(error_message != NULL);
-
- const char *const unknown_name = _("Unknown");
-
- emsgf(_(error_message), (name != NULL ? name_len : strlen(unknown_name)),
- (name != NULL ? name : unknown_name));
-
return true;
}
-/*
- * Copy the values from typval_T "from" to typval_T "to".
- * When needed allocates string or increases reference count.
- * Does not make a copy of a list or dict but copies the reference!
- * It is OK for "from" and "to" to point to the same item. This is used to
- * make a copy later.
- */
-void copy_tv(typval_T *from, typval_T *to)
-{
- to->v_type = from->v_type;
- to->v_lock = 0;
- memmove(&to->vval, &from->vval, sizeof(to->vval));
- switch (from->v_type) {
- case VAR_NUMBER:
- case VAR_FLOAT:
- case VAR_SPECIAL:
- break;
- case VAR_STRING:
- case VAR_FUNC:
- if (from->vval.v_string != NULL) {
- to->vval.v_string = vim_strsave(from->vval.v_string);
- if (from->v_type == VAR_FUNC) {
- func_ref(to->vval.v_string);
- }
- }
- break;
- case VAR_PARTIAL:
- if (from->vval.v_partial == NULL) {
- to->vval.v_partial = NULL;
- } else {
- to->vval.v_partial = from->vval.v_partial;
- (to->vval.v_partial->pt_refcount)++;
- }
- break;
- case VAR_LIST:
- if (from->vval.v_list != NULL) {
- to->vval.v_list->lv_refcount++;
- }
- break;
- case VAR_DICT:
- if (from->vval.v_dict != NULL) {
- to->vval.v_dict->dv_refcount++;
- }
- break;
- case VAR_UNKNOWN:
- EMSG2(_(e_intern2), "copy_tv(UNKNOWN)");
- break;
- }
-}
-
/// Make a copy of an item
///
/// Lists and Dictionaries are also copied.
@@ -20919,7 +19013,7 @@ void copy_tv(typval_T *from, typval_T *to)
/// list[1]`) var_item_copy with zero copyID will emit
/// a copy with (`copy[0] isnot copy[1]`), with non-zero it
/// will emit a copy with (`copy[0] is copy[1]`) like in the
-/// original list. Not use when deep is false.
+/// original list. Not used when deep is false.
int var_item_copy(const vimconv_T *const conv,
typval_T *const from,
typval_T *const to,
@@ -20942,11 +19036,12 @@ int var_item_copy(const vimconv_T *const conv,
case VAR_FUNC:
case VAR_PARTIAL:
case VAR_SPECIAL:
- copy_tv(from, to);
+ tv_copy(from, to);
break;
case VAR_STRING:
- if (conv == NULL || conv->vc_type == CONV_NONE) {
- copy_tv(from, to);
+ if (conv == NULL || conv->vc_type == CONV_NONE
+ || from->vval.v_string == NULL) {
+ tv_copy(from, to);
} else {
to->v_type = VAR_STRING;
to->v_lock = 0;
@@ -20968,10 +19063,11 @@ int var_item_copy(const vimconv_T *const conv,
to->vval.v_list = from->vval.v_list->lv_copylist;
++to->vval.v_list->lv_refcount;
} else {
- to->vval.v_list = list_copy(conv, from->vval.v_list, deep, copyID);
+ to->vval.v_list = tv_list_copy(conv, from->vval.v_list, deep, copyID);
}
- if (to->vval.v_list == NULL)
+ if (to->vval.v_list == NULL && from->vval.v_list != NULL) {
ret = FAIL;
+ }
break;
case VAR_DICT:
to->v_type = VAR_DICT;
@@ -20983,10 +19079,11 @@ int var_item_copy(const vimconv_T *const conv,
to->vval.v_dict = from->vval.v_dict->dv_copydict;
++to->vval.v_dict->dv_refcount;
} else {
- to->vval.v_dict = dict_copy(conv, from->vval.v_dict, deep, copyID);
+ to->vval.v_dict = tv_dict_copy(conv, from->vval.v_dict, deep, copyID);
}
- if (to->vval.v_dict == NULL)
+ if (to->vval.v_dict == NULL && from->vval.v_dict != NULL) {
ret = FAIL;
+ }
break;
case VAR_UNKNOWN:
EMSG2(_(e_intern2), "var_item_copy(UNKNOWN)");
@@ -21070,7 +19167,7 @@ void ex_echo(exarg_T *eap)
}
xfree(tofree);
}
- clear_tv(&rettv);
+ tv_clear(&rettv);
arg = skipwhite(arg);
}
eap->nextcmd = check_nextcmd(arg);
@@ -21114,7 +19211,6 @@ void ex_execute(exarg_T *eap)
int ret = OK;
char_u *p;
garray_T ga;
- int len;
int save_did_emsg;
ga_init(&ga, 1, 80);
@@ -21136,16 +19232,17 @@ void ex_execute(exarg_T *eap)
}
if (!eap->skip) {
- p = get_tv_string(&rettv);
- len = (int)STRLEN(p);
+ const char *const argstr = tv_get_string(&rettv);
+ const size_t len = strlen(argstr);
ga_grow(&ga, len + 2);
- if (!GA_EMPTY(&ga))
+ if (!GA_EMPTY(&ga)) {
((char_u *)(ga.ga_data))[ga.ga_len++] = ' ';
- STRCPY((char_u *)(ga.ga_data) + ga.ga_len, p);
+ }
+ memcpy((char_u *)(ga.ga_data) + ga.ga_len, argstr, len + 1);
ga.ga_len += len;
}
- clear_tv(&rettv);
+ tv_clear(&rettv);
arg = skipwhite(arg);
}
@@ -21389,9 +19486,7 @@ void ex_function(exarg_T *eap)
arg = name;
else
arg = fudi.fd_newkey;
- if (arg != NULL && (fudi.fd_di == NULL
- || (fudi.fd_di->di_tv.v_type != VAR_FUNC
- && fudi.fd_di->di_tv.v_type != VAR_PARTIAL))) {
+ if (arg != NULL && (fudi.fd_di == NULL || !tv_is_func(fudi.fd_di->di_tv))) {
int j = (*arg == K_SPECIAL) ? 3 : 0;
while (arg[j] != NUL && (j == 0 ? eval_isnamec1(arg[j])
: eval_isnamec(arg[j])))
@@ -21697,16 +19792,17 @@ void ex_function(exarg_T *eap)
if (fudi.fd_dict != NULL) {
if (fudi.fd_di == NULL) {
- /* add new dict entry */
- fudi.fd_di = dictitem_alloc(fudi.fd_newkey);
- if (dict_add(fudi.fd_dict, fudi.fd_di) == FAIL) {
+ // Add new dict entry
+ fudi.fd_di = tv_dict_item_alloc((const char *)fudi.fd_newkey);
+ if (tv_dict_add(fudi.fd_dict, fudi.fd_di) == FAIL) {
xfree(fudi.fd_di);
xfree(fp);
goto erret;
}
- } else
- /* overwrite existing dict entry */
- clear_tv(&fudi.fd_di->di_tv);
+ } else {
+ // Overwrite existing dict entry.
+ tv_clear(&fudi.fd_di->di_tv);
+ }
fudi.fd_di->di_tv.v_type = VAR_FUNC;
fudi.fd_di->di_tv.v_lock = 0;
fudi.fd_di->di_tv.vval.v_string = vim_strsave(name);
@@ -21767,20 +19863,19 @@ ret_free:
/// Advances "pp" to just after the function name (if no error).
///
/// @return the function name in allocated memory, or NULL for failure.
-char_u *
+static char_u *
trans_function_name(
char_u **pp,
- int skip, /* only find the end, don't evaluate */
+ int skip, // only find the end, don't evaluate
int flags,
funcdict_T *fdp, // return: info about dictionary used
partial_T **partial // return: partial of a FuncRef
)
{
char_u *name = NULL;
- char_u *start;
- char_u *end;
+ const char_u *start;
+ const char_u *end;
int lead;
- char_u sid_buf[20];
int len;
lval_T lv;
@@ -21804,9 +19899,9 @@ trans_function_name(
start += lead;
}
- /* Note that TFN_ flags use the same values as GLV_ flags. */
- end = get_lval(start, NULL, &lv, FALSE, skip, flags,
- lead > 2 ? 0 : FNE_CHECK_START);
+ // Note that TFN_ flags use the same values as GLV_ flags.
+ end = get_lval((char_u *)start, NULL, &lv, false, skip, flags,
+ lead > 2 ? 0 : FNE_CHECK_START);
if (end == start) {
if (!skip)
EMSG(_("E129: Function name required"));
@@ -21819,10 +19914,12 @@ trans_function_name(
* interrupt, or an exception.
*/
if (!aborting()) {
- if (end != NULL)
- EMSG2(_(e_invarg2), start);
- } else
- *pp = find_name_end(start, NULL, NULL, FNE_INCL_BR);
+ if (end != NULL) {
+ emsgf(_(e_invarg2), start);
+ }
+ } else {
+ *pp = (char_u *)find_name_end(start, NULL, NULL, FNE_INCL_BR);
+ }
goto theend;
}
@@ -21835,11 +19932,11 @@ trans_function_name(
}
if (lv.ll_tv->v_type == VAR_FUNC && lv.ll_tv->vval.v_string != NULL) {
name = vim_strsave(lv.ll_tv->vval.v_string);
- *pp = end;
+ *pp = (char_u *)end;
} else if (lv.ll_tv->v_type == VAR_PARTIAL
&& lv.ll_tv->vval.v_partial != NULL) {
name = vim_strsave(partial_name(lv.ll_tv->vval.v_partial));
- *pp = end;
+ *pp = (char_u *)end;
if (partial != NULL) {
*partial = lv.ll_tv->vval.v_partial;
}
@@ -21849,7 +19946,7 @@ trans_function_name(
|| fdp->fd_newkey == NULL)) {
EMSG(_(e_funcref));
} else {
- *pp = end;
+ *pp = (char_u *)end;
}
name = NULL;
}
@@ -21857,17 +19954,17 @@ trans_function_name(
}
if (lv.ll_name == NULL) {
- /* Error found, but continue after the function name. */
- *pp = end;
+ // Error found, but continue after the function name.
+ *pp = (char_u *)end;
goto theend;
}
/* Check if the name is a Funcref. If so, use the value. */
if (lv.ll_exp_name != NULL) {
- len = (int)STRLEN(lv.ll_exp_name);
- name = deref_func_name((const char *)lv.ll_exp_name, &len, partial,
+ len = (int)strlen(lv.ll_exp_name);
+ name = deref_func_name(lv.ll_exp_name, &len, partial,
flags & TFN_NO_AUTOLOAD);
- if (name == lv.ll_exp_name) {
+ if ((const char *)name == lv.ll_exp_name) {
name = NULL;
}
} else if (!(flags & TFN_NO_DEREF)) {
@@ -21880,7 +19977,7 @@ trans_function_name(
}
if (name != NULL) {
name = vim_strsave(name);
- *pp = end;
+ *pp = (char_u *)end;
if (strncmp((char *)name, "<SNR>", 5) == 0) {
// Change "<SNR>" to the byte sequence.
name[0] = K_SPECIAL;
@@ -21892,12 +19989,13 @@ trans_function_name(
}
if (lv.ll_exp_name != NULL) {
- len = (int)STRLEN(lv.ll_exp_name);
+ len = (int)strlen(lv.ll_exp_name);
if (lead <= 2 && lv.ll_name == lv.ll_exp_name
- && STRNCMP(lv.ll_name, "s:", 2) == 0) {
- /* When there was "s:" already or the name expanded to get a
- * leading "s:" then remove it. */
+ && lv.ll_name_len >= 2 && memcmp(lv.ll_name, "s:", 2) == 0) {
+ // When there was "s:" already or the name expanded to get a
+ // leading "s:" then remove it.
lv.ll_name += 2;
+ lv.ll_name_len -= 2;
len -= 2;
lead = 2;
}
@@ -21905,38 +20003,41 @@ trans_function_name(
// Skip over "s:" and "g:".
if (lead == 2 || (lv.ll_name[0] == 'g' && lv.ll_name[1] == ':')) {
lv.ll_name += 2;
+ lv.ll_name_len -= 2;
}
- len = (int)(end - lv.ll_name);
+ len = (int)((const char *)end - lv.ll_name);
}
- /*
- * Copy the function name to allocated memory.
- * Accept <SID>name() inside a script, translate into <SNR>123_name().
- * Accept <SNR>123_name() outside a script.
- */
- if (skip)
- lead = 0; /* do nothing */
- else if (lead > 0) {
+ size_t sid_buf_len = 0;
+ char sid_buf[20];
+
+ // Copy the function name to allocated memory.
+ // Accept <SID>name() inside a script, translate into <SNR>123_name().
+ // Accept <SNR>123_name() outside a script.
+ if (skip) {
+ lead = 0; // do nothing
+ } else if (lead > 0) {
lead = 3;
- if ((lv.ll_exp_name != NULL && eval_fname_sid((const char *)lv.ll_exp_name))
+ if ((lv.ll_exp_name != NULL && eval_fname_sid(lv.ll_exp_name))
|| eval_fname_sid((const char *)(*pp))) {
// It's "s:" or "<SID>".
if (current_SID <= 0) {
EMSG(_(e_usingsid));
goto theend;
}
- sprintf((char *)sid_buf, "%" PRId64 "_", (int64_t)current_SID);
- lead += (int)STRLEN(sid_buf);
+ sid_buf_len = snprintf(sid_buf, sizeof(sid_buf),
+ "%" PRIdSCID "_", current_SID);
+ lead += sid_buf_len;
}
} else if (!(flags & TFN_INT)
- && builtin_function((const char *)lv.ll_name, len)) {
+ && builtin_function(lv.ll_name, lv.ll_name_len)) {
EMSG2(_("E128: Function name must start with a capital or \"s:\": %s"),
start);
goto theend;
}
if (!skip && !(flags & TFN_QUIET) && !(flags & TFN_NO_DEREF)) {
- char_u *cp = vim_strchr(lv.ll_name, ':');
+ char_u *cp = xmemrchr(lv.ll_name, ':', lv.ll_name_len);
if (cp != NULL && cp < end) {
EMSG2(_("E884: Function name cannot contain a colon: %s"), start);
@@ -21949,12 +20050,13 @@ trans_function_name(
name[0] = K_SPECIAL;
name[1] = KS_EXTRA;
name[2] = (int)KE_SNR;
- if (lead > 3) /* If it's "<SID>" */
- STRCPY(name + 3, sid_buf);
+ if (sid_buf_len > 0) { // If it's "<SID>"
+ memcpy(name + 3, sid_buf, sid_buf_len);
+ }
}
- memmove(name + lead, lv.ll_name, (size_t)len);
+ memmove(name + lead, lv.ll_name, len);
name[lead + len] = NUL;
- *pp = end;
+ *pp = (char_u *)end;
theend:
clear_lval(&lv);
@@ -21968,7 +20070,7 @@ theend:
*/
static int eval_fname_script(const char *const p)
{
- // Use mb_stricmp() because in Turkish comparing the "I" may not work with
+ // Use mb_strnicmp() because in Turkish comparing the "I" may not work with
// the standard library function.
if (p[0] == '<'
&& (mb_strnicmp((char_u *)p + 1, (char_u *)"SID>", 4) == 0
@@ -21983,8 +20085,8 @@ static int eval_fname_script(const char *const p)
/// Check whether function name starts with <SID> or s:
///
-/// Only works for names previously checked by eval_fname_script(), if it
-/// returned non-zero.
+/// @warning Only works for names previously checked by eval_fname_script(), if
+/// it returned non-zero.
///
/// @param[in] name Name to check.
///
@@ -22133,14 +20235,15 @@ bool translated_function_exists(const char *name)
/// @return True if it exists, false otherwise.
static bool function_exists(const char *const name, bool no_deref)
{
- char_u *nm = (char_u *)name;
+ const char_u *nm = (const char_u *)name;
bool n = false;
int flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD;
if (no_deref) {
flag |= TFN_NO_DEREF;
}
- char *const p = (char *)trans_function_name(&nm, false, flag, NULL, NULL);
+ char *const p = (char *)trans_function_name((char_u **)&nm, false, flag, NULL,
+ NULL);
nm = skipwhite(nm);
/* Only accept "funcname", "funcname ", "funcname (..." and
@@ -22524,9 +20627,9 @@ void ex_delfunction(exarg_T *eap)
}
if (fudi.fd_dict != NULL) {
- /* Delete the dict item that refers to the function, it will
- * invoke func_unref() and possibly delete the function. */
- dictitem_remove(fudi.fd_dict, fudi.fd_di);
+ // Delete the dict item that refers to the function, it will
+ // invoke func_unref() and possibly delete the function.
+ tv_dict_item_remove(fudi.fd_dict, fudi.fd_di);
} else {
// A normal function (not a numbered function or lambda) has a
// refcount of 1 for the entry in the hashtable. When deleting
@@ -22630,17 +20733,16 @@ void func_unref(char_u *name)
abort();
#endif
}
- if (fp != NULL && --fp->uf_refcount <= 0) {
- // Only delete it when it's not being used. Otherwise it's done
- // when "uf_calls" becomes zero.
- if (fp->uf_calls == 0) {
- func_clear_free(fp, false);
- }
- }
+ func_ptr_unref(fp);
}
/// Unreference a Function: decrement the reference count and free it when it
/// becomes zero.
+/// Unreference user function, freeing it if needed
+///
+/// Decrements the reference count and frees when it becomes zero.
+///
+/// @param fp Function to unreference.
void func_ptr_unref(ufunc_T *fp)
{
if (fp != NULL && --fp->uf_refcount <= 0) {
@@ -22678,17 +20780,19 @@ void func_ptr_ref(ufunc_T *fp)
}
}
-/// Call a user function.
-static void
-call_user_func(
- ufunc_T *fp, // pointer to function
- int argcount, // nr of args
- typval_T *argvars, // arguments
- typval_T *rettv, // return value
- linenr_T firstline, // first line of range
- linenr_T lastline, // last line of range
- dict_T *selfdict // Dictionary for "self"
-)
+/// Call a user function
+///
+/// @param fp Function to call.
+/// @param[in] argcount Number of arguments.
+/// @param argvars Arguments.
+/// @param[out] rettv Return value.
+/// @param[in] firstline First line of range.
+/// @param[in] lastline Last line of range.
+/// @param selfdict Dictionary for "self" for dictionary functions.
+void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
+ typval_T *rettv, linenr_T firstline, linenr_T lastline,
+ dict_T *selfdict)
+ FUNC_ATTR_NONNULL_ARG(1, 3, 4)
{
char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
@@ -22754,15 +20858,15 @@ call_user_func(
// Init l: variables.
init_var_dict(&fc->l_vars, &fc->l_vars_var, VAR_DEF_SCOPE);
if (selfdict != NULL) {
- /* Set l:self to "selfdict". Use "name" to avoid a warning from
- * some compiler that checks the destination size. */
- v = &fc->fixvar[fixvar_idx++].var;
+ // Set l:self to "selfdict". Use "name" to avoid a warning from
+ // some compiler that checks the destination size.
+ v = (dictitem_T *)&fc->fixvar[fixvar_idx++];
#ifndef __clang_analyzer__
name = v->di_key;
STRCPY(name, "self");
#endif
v->di_flags = DI_FLAGS_RO + DI_FLAGS_FIX;
- hash_add(&fc->l_vars.dv_hashtab, DI2HIKEY(v));
+ tv_dict_add(&fc->l_vars, v);
v->di_tv.v_type = VAR_DICT;
v->di_tv.v_lock = 0;
v->di_tv.vval.v_dict = selfdict;
@@ -22775,17 +20879,17 @@ call_user_func(
* Set a:000 to a list with room for the "..." arguments.
*/
init_var_dict(&fc->l_avars, &fc->l_avars_var, VAR_SCOPE);
- add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "0",
- (varnumber_T)(argcount - fp->uf_args.ga_len));
- /* Use "name" to avoid a warning from some compiler that checks the
- * destination size. */
- v = &fc->fixvar[fixvar_idx++].var;
+ add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++], "0",
+ (varnumber_T)(argcount - fp->uf_args.ga_len));
+ // Use "name" to avoid a warning from some compiler that checks the
+ // destination size.
+ v = (dictitem_T *)&fc->fixvar[fixvar_idx++];
#ifndef __clang_analyzer__
name = v->di_key;
STRCPY(name, "000");
#endif
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
- hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v));
+ tv_dict_add(&fc->l_avars, v);
v->di_tv.v_type = VAR_LIST;
v->di_tv.v_lock = VAR_FIXED;
v->di_tv.vval.v_list = &fc->l_varlist;
@@ -22796,10 +20900,10 @@ call_user_func(
// Set a:firstline to "firstline" and a:lastline to "lastline".
// Set a:name to named arguments.
// Set a:N to the "..." arguments.
- add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "firstline",
- (varnumber_T)firstline);
- add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "lastline",
- (varnumber_T)lastline);
+ add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++],
+ "firstline", (varnumber_T)firstline);
+ add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++],
+ "lastline", (varnumber_T)lastline);
for (int i = 0; i < argcount; i++) {
bool addlocal = false;
@@ -22816,7 +20920,7 @@ call_user_func(
name = numbuf;
}
if (fixvar_idx < FIXVAR_CNT && STRLEN(name) <= VAR_SHORT_LEN) {
- v = &fc->fixvar[fixvar_idx++].var;
+ v = (dictitem_T *)&fc->fixvar[fixvar_idx++];
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
} else {
v = xmalloc(sizeof(dictitem_T) + STRLEN(name));
@@ -22832,14 +20936,14 @@ call_user_func(
if (addlocal) {
// Named arguments can be accessed without the "a:" prefix in lambda
// expressions. Add to the l: dict.
- copy_tv(&v->di_tv, &v->di_tv);
- hash_add(&fc->l_vars.dv_hashtab, DI2HIKEY(v));
+ tv_copy(&v->di_tv, &v->di_tv);
+ tv_dict_add(&fc->l_vars, v);
} else {
- hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v));
+ tv_dict_add(&fc->l_avars, v);
}
if (ai >= 0 && ai < MAX_FUNC_ARGS) {
- list_append(&fc->l_varlist, &fc->l_listitems[ai]);
+ tv_list_append(&fc->l_varlist, &fc->l_listitems[ai]);
fc->l_listitems[ai].li_tv = argvars[i];
fc->l_listitems[ai].li_tv.v_lock = VAR_FIXED;
}
@@ -22947,7 +21051,7 @@ call_user_func(
// when the function was aborted because of an error, return -1
if ((did_emsg
&& (fp->uf_flags & FC_ABORT)) || rettv->v_type == VAR_UNKNOWN) {
- clear_tv(rettv);
+ tv_clear(rettv);
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = -1;
}
@@ -23031,29 +21135,22 @@ call_user_func(
&& fc->fc_refcount <= 0) {
free_funccal(fc, false);
} else {
- hashitem_T *hi;
- listitem_T *li;
- int todo;
-
// "fc" is still in use. This can happen when returning "a:000",
// assigning "l:" to a global variable or defining a closure.
// Link "fc" in the list for garbage collection later.
fc->caller = previous_funccal;
previous_funccal = fc;
- /* Make a copy of the a: variables, since we didn't do that above. */
- todo = (int)fc->l_avars.dv_hashtab.ht_used;
- for (hi = fc->l_avars.dv_hashtab.ht_array; todo > 0; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- --todo;
- v = HI2DI(hi);
- copy_tv(&v->di_tv, &v->di_tv);
- }
- }
+ // Make a copy of the a: variables, since we didn't do that above.
+ TV_DICT_ITER(&fc->l_avars, di, {
+ tv_copy(&di->di_tv, &di->di_tv);
+ });
- /* Make a copy of the a:000 items, since we didn't do that above. */
- for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next)
- copy_tv(&li->li_tv, &li->li_tv);
+ // Make a copy of the a:000 items, since we didn't do that above.
+ for (listitem_T *li = fc->l_varlist.lv_first; li != NULL;
+ li = li->li_next) {
+ tv_copy(&li->li_tv, &li->li_tv);
+ }
}
if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0) {
@@ -23143,7 +21240,7 @@ free_funccal (
// Free the a:000 variables if they were allocated.
if (free_val) {
for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next) {
- clear_tv(&li->li_tv);
+ tv_clear(&li->li_tv);
}
}
@@ -23160,7 +21257,7 @@ static void add_nr_var(dict_T *dp, dictitem_T *v, char *name, varnumber_T nr)
STRCPY(v->di_key, name);
#endif
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
- hash_add(&dp->dv_hashtab, DI2HIKEY(v));
+ tv_dict_add(dp, v);
v->di_tv.v_type = VAR_NUMBER;
v->di_tv.v_lock = VAR_FIXED;
v->di_tv.vval.v_number = nr;
@@ -23186,10 +21283,11 @@ void ex_return(exarg_T *eap)
eap->nextcmd = NULL;
if ((*arg != NUL && *arg != '|' && *arg != '\n')
&& eval0(arg, &rettv, &eap->nextcmd, !eap->skip) != FAIL) {
- if (!eap->skip)
- returning = do_return(eap, FALSE, TRUE, &rettv);
- else
- clear_tv(&rettv);
+ if (!eap->skip) {
+ returning = do_return(eap, false, true, &rettv);
+ } else {
+ tv_clear(&rettv);
+ }
}
/* It's safer to return also on error. */
else if (!eap->skip) {
@@ -23276,7 +21374,7 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
* a return immediately after reanimation, the value is already
* there. */
if (!reanimate && rettv != NULL) {
- clear_tv(current_funccal->rettv);
+ tv_clear(current_funccal->rettv);
*current_funccal->rettv = *(typval_T *)rettv;
if (!is_cmd)
xfree(rettv);
@@ -23287,14 +21385,6 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
}
/*
- * Free the variable with a pending return value.
- */
-void discard_pending_return(void *rettv)
-{
- free_tv((typval_T *)rettv);
-}
-
-/*
* Generate a return command for producing the value of "rettv". The result
* is an allocated string. Used by report_pending() for verbose messages.
*/
@@ -23555,7 +21645,7 @@ const void *var_shada_iter(const void *const iter, const char **const name,
hi = globvarht.ht_array;
while ((size_t) (hi - hifirst) < hinum
&& (HASHITEM_EMPTY(hi)
- || var_flavour(HI2DI(hi)->di_key) != VAR_FLAVOUR_SHADA)) {
+ || var_flavour(hi->hi_key) != VAR_FLAVOUR_SHADA)) {
hi++;
}
if ((size_t) (hi - hifirst) == hinum) {
@@ -23564,11 +21654,10 @@ const void *var_shada_iter(const void *const iter, const char **const name,
} else {
hi = (const hashitem_T *) iter;
}
- *name = (char *) HI2DI(hi)->di_key;
- copy_tv(&(HI2DI(hi)->di_tv), rettv);
- while ((size_t) (++hi - hifirst) < hinum) {
- if (!HASHITEM_EMPTY(hi)
- && var_flavour(HI2DI(hi)->di_key) == VAR_FLAVOUR_SHADA) {
+ *name = (char *)TV_DICT_HI2DI(hi)->di_key;
+ tv_copy(&TV_DICT_HI2DI(hi)->di_tv, rettv);
+ while ((size_t)(++hi - hifirst) < hinum) {
+ if (!HASHITEM_EMPTY(hi) && var_flavour(hi->hi_key) == VAR_FLAVOUR_SHADA) {
return hi;
}
}
@@ -23579,62 +21668,55 @@ void var_set_global(const char *const name, typval_T vartv)
{
funccall_T *const saved_current_funccal = current_funccal;
current_funccal = NULL;
- set_var((char_u *) name, &vartv, false);
+ set_var(name, strlen(name), &vartv, false);
current_funccal = saved_current_funccal;
}
int store_session_globals(FILE *fd)
{
- hashitem_T *hi;
- dictitem_T *this_var;
- int todo;
- char_u *p, *t;
-
- todo = (int)globvarht.ht_used;
- for (hi = globvarht.ht_array; todo > 0; ++hi) {
- if (!HASHITEM_EMPTY(hi)) {
- --todo;
- this_var = HI2DI(hi);
- if ((this_var->di_tv.v_type == VAR_NUMBER
- || this_var->di_tv.v_type == VAR_STRING)
- && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION) {
- /* Escape special characters with a backslash. Turn a LF and
- * CR into \n and \r. */
- p = vim_strsave_escaped(get_tv_string(&this_var->di_tv),
- (char_u *)"\\\"\n\r");
- for (t = p; *t != NUL; ++t)
- if (*t == '\n')
- *t = 'n';
- else if (*t == '\r')
- *t = 'r';
- if ((fprintf(fd, "let %s = %c%s%c",
- this_var->di_key,
- (this_var->di_tv.v_type == VAR_STRING) ? '"'
- : ' ',
- p,
- (this_var->di_tv.v_type == VAR_STRING) ? '"'
- : ' ') < 0)
- || put_eol(fd) == FAIL) {
- xfree(p);
- return FAIL;
+ TV_DICT_ITER(&globvardict, this_var, {
+ if ((this_var->di_tv.v_type == VAR_NUMBER
+ || this_var->di_tv.v_type == VAR_STRING)
+ && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION) {
+ // Escape special characters with a backslash. Turn a LF and
+ // CR into \n and \r.
+ char_u *const p = vim_strsave_escaped(
+ (const char_u *)tv_get_string(&this_var->di_tv),
+ (const char_u *)"\\\"\n\r");
+ for (char_u *t = p; *t != NUL; t++) {
+ if (*t == '\n') {
+ *t = 'n';
+ } else if (*t == '\r') {
+ *t = 'r';
}
+ }
+ if ((fprintf(fd, "let %s = %c%s%c",
+ this_var->di_key,
+ ((this_var->di_tv.v_type == VAR_STRING) ? '"'
+ : ' '),
+ p,
+ ((this_var->di_tv.v_type == VAR_STRING) ? '"'
+ : ' ')) < 0)
+ || put_eol(fd) == FAIL) {
xfree(p);
- } else if (this_var->di_tv.v_type == VAR_FLOAT
- && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION) {
- float_T f = this_var->di_tv.vval.v_float;
- int sign = ' ';
-
- if (f < 0) {
- f = -f;
- sign = '-';
- }
- if ((fprintf(fd, "let %s = %c%f",
- this_var->di_key, sign, f) < 0)
- || put_eol(fd) == FAIL)
- return FAIL;
+ return FAIL;
+ }
+ xfree(p);
+ } else if (this_var->di_tv.v_type == VAR_FLOAT
+ && var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION) {
+ float_T f = this_var->di_tv.vval.v_float;
+ int sign = ' ';
+
+ if (f < 0) {
+ f = -f;
+ sign = '-';
+ }
+ if ((fprintf(fd, "let %s = %c%f", this_var->di_key, sign, f) < 0)
+ || put_eol(fd) == FAIL) {
+ return FAIL;
}
}
- }
+ });
return OK;
}
@@ -23671,7 +21753,7 @@ void ex_oldfiles(exarg_T *eap)
for (li = l->lv_first; li != NULL && !got_int; li = li->li_next) {
msg_outnum(++nr);
MSG_PUTS(": ");
- msg_outtrans(get_tv_string(&li->li_tv));
+ msg_outtrans((char_u *)tv_get_string(&li->li_tv));
msg_clr_eos();
msg_putchar('\n');
ui_flush(); /* output one line at a time */
@@ -23686,15 +21768,15 @@ void ex_oldfiles(exarg_T *eap)
nr = prompt_for_number(false);
msg_starthere();
if (nr > 0 && nr <= l->lv_len) {
- char_u *p = list_find_str(l, nr);
+ const char *const p = tv_list_find_str(l, nr - 1);
if (p == NULL) {
return;
}
- p = expand_env_save(p);
- eap->arg = p;
+ char *const s = (char *)expand_env_save((char_u *)p);
+ eap->arg = (char_u *)s;
eap->cmdidx = CMD_edit;
do_exedit(eap, NULL);
- xfree(p);
+ xfree(s);
}
}
}
@@ -24059,7 +22141,7 @@ static inline TerminalJobData *common_job_init(char **argv,
bool pty,
bool rpc,
bool detach,
- char *cwd)
+ const char *cwd)
{
TerminalJobData *data = xcalloc(1, sizeof(TerminalJobData));
data->stopped = false;
@@ -24093,9 +22175,9 @@ static inline TerminalJobData *common_job_init(char **argv,
static inline bool common_job_callbacks(dict_T *vopts, Callback *on_stdout,
Callback *on_stderr, Callback *on_exit)
{
- if (get_dict_callback(vopts, "on_stdout", on_stdout)
- && get_dict_callback(vopts, "on_stderr", on_stderr)
- && get_dict_callback(vopts, "on_exit", on_exit)) {
+ if (tv_dict_get_callback(vopts, S_LEN("on_stdout"), on_stdout)
+ &&tv_dict_get_callback(vopts, S_LEN("on_stderr"), on_stderr)
+ && tv_dict_get_callback(vopts, S_LEN("on_exit"), on_exit)) {
vopts->dv_refcount++;
return true;
}
@@ -24182,7 +22264,7 @@ static inline void process_job_event(TerminalJobData *data, Callback *callback,
JobEvent event_data;
event_data.received = NULL;
if (buf) {
- event_data.received = list_alloc();
+ event_data.received = tv_list_alloc();
char *ptr = buf;
size_t remaining = count;
size_t off = 0;
@@ -24190,7 +22272,7 @@ static inline void process_job_event(TerminalJobData *data, Callback *callback,
while (off < remaining) {
// append the line
if (ptr[off] == NL) {
- list_append_string(event_data.received, (uint8_t *)ptr, off);
+ tv_list_append_string(event_data.received, ptr, off);
size_t skip = off + 1;
ptr += skip;
remaining -= skip;
@@ -24203,7 +22285,7 @@ static inline void process_job_event(TerminalJobData *data, Callback *callback,
}
off++;
}
- list_append_string(event_data.received, (uint8_t *)ptr, off);
+ tv_list_append_string(event_data.received, ptr, off);
} else {
event_data.status = status;
}
@@ -24349,10 +22431,9 @@ static void on_job_event(JobEvent *ev)
argv[2].v_lock = 0;
argv[2].vval.v_string = (uint8_t *)ev->type;
- typval_T rettv;
- init_tv(&rettv);
+ typval_T rettv = TV_INITIAL_VALUE;
callback_call(ev->callback, 3, argv, &rettv);
- clear_tv(&rettv);
+ tv_clear(&rettv);
}
static TerminalJobData *find_job(uint64_t id)
@@ -24375,8 +22456,8 @@ static void script_host_eval(char *name, typval_T *argvars, typval_T *rettv)
return;
}
- list_T *args = list_alloc();
- list_append_string(args, argvars[0].vval.v_string, -1);
+ list_T *args = tv_list_alloc();
+ tv_list_append_string(args, (const char *)argvars[0].vval.v_string, -1);
*rettv = eval_call_provider(name, "eval", args);
}
@@ -24408,7 +22489,7 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
arguments->lv_refcount++;
int dummy;
- (void)call_func((uint8_t *)func,
+ (void)call_func((const char_u *)func,
name_len,
&rettv,
2,
@@ -24421,7 +22502,7 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
NULL,
NULL);
- list_unref(arguments);
+ tv_list_unref(arguments);
// Restore caller scope information
restore_funccal(provider_caller_scope.funccalp);
provider_caller_scope = saved_provider_caller_scope;
@@ -24430,7 +22511,7 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
return rettv;
}
-bool eval_has_provider(char *name)
+bool eval_has_provider(const char *name)
{
#define check_provider(name) \
if (has_##name == -1) { \
@@ -24464,91 +22545,3 @@ bool eval_has_provider(char *name)
return false;
}
-
-// Compute the `DictWatcher` address from a QUEUE node. This only exists for
-// .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer arithmetic).
-static DictWatcher *dictwatcher_node_data(QUEUE *q)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
-{
- return QUEUE_DATA(q, DictWatcher, node);
-}
-
-// Send a change notification to all `dict` watchers that match `key`.
-static void dictwatcher_notify(dict_T *dict, const char *key, typval_T *newtv,
- typval_T *oldtv)
- FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2)
-{
- typval_T argv[4];
- for (size_t i = 0; i < ARRAY_SIZE(argv); i++) {
- init_tv(argv + i);
- }
-
- argv[0].v_type = VAR_DICT;
- argv[0].vval.v_dict = dict;
- argv[1].v_type = VAR_STRING;
- argv[1].vval.v_string = (char_u *)xstrdup(key);
- argv[2].v_type = VAR_DICT;
- argv[2].vval.v_dict = dict_alloc();
- argv[2].vval.v_dict->dv_refcount++;
-
- if (newtv) {
- dictitem_T *v = dictitem_alloc((char_u *)"new");
- copy_tv(newtv, &v->di_tv);
- dict_add(argv[2].vval.v_dict, v);
- }
-
- if (oldtv) {
- dictitem_T *v = dictitem_alloc((char_u *)"old");
- copy_tv(oldtv, &v->di_tv);
- dict_add(argv[2].vval.v_dict, v);
- }
-
- typval_T rettv;
-
- QUEUE *w;
- QUEUE_FOREACH(w, &dict->watchers) {
- DictWatcher *watcher = dictwatcher_node_data(w);
- if (!watcher->busy && dictwatcher_matches(watcher, key)) {
- init_tv(&rettv);
- watcher->busy = true;
- callback_call(&watcher->callback, 3, argv, &rettv);
- watcher->busy = false;
- clear_tv(&rettv);
- }
- }
-
- for (size_t i = 1; i < ARRAY_SIZE(argv); i++) {
- clear_tv(argv + i);
- }
-}
-
-// Test if `key` matches with with `watcher->key_pattern`
-static bool dictwatcher_matches(DictWatcher *watcher, const char *key)
- FUNC_ATTR_NONNULL_ALL
-{
- // For now only allow very simple globbing in key patterns: a '*' at the end
- // of the string means it should match everything up to the '*' instead of the
- // whole string.
- char *nul = strchr(watcher->key_pattern, NUL);
- size_t len = nul - watcher->key_pattern;
- if (*(nul - 1) == '*') {
- return !strncmp(key, watcher->key_pattern, len - 1);
- } else {
- return !strcmp(key, watcher->key_pattern);
- }
-}
-
-// Perform all necessary cleanup for a `DictWatcher` instance.
-static void dictwatcher_free(DictWatcher *watcher)
- FUNC_ATTR_NONNULL_ALL
-{
- callback_free(&watcher->callback);
- xfree(watcher->key_pattern);
- xfree(watcher);
-}
-
-// Check if `d` has at least one watcher.
-static bool is_watched(dict_T *d)
-{
- return d && !QUEUE_EMPTY(&d->watchers);
-}
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index 57fee5c5a2..070bc35bd5 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -1,21 +1,23 @@
#ifndef NVIM_EVAL_H
#define NVIM_EVAL_H
-#include "nvim/profile.h"
#include "nvim/hashtab.h" // For hashtab_T
-#include "nvim/garray.h" // For garray_T
-#include "nvim/buffer_defs.h" // For scid_T
+#include "nvim/buffer_defs.h"
#include "nvim/ex_cmds_defs.h" // For exarg_T
+#include "nvim/eval/typval.h"
+#include "nvim/profile.h"
+#include "nvim/garray.h"
#define COPYID_INC 2
#define COPYID_MASK (~0x1)
// All user-defined functions are found in this hashtable.
extern hashtab_T func_hashtab;
+
// From user function to hashitem and back.
EXTERN ufunc_T dumuf;
#define UF2HIKEY(fp) ((fp)->uf_name)
-#define HIKEY2UF(p) ((ufunc_T *)(p - (dumuf.uf_name - (char_u *)&dumuf)))
+#define HIKEY2UF(p) ((ufunc_T *)(p - offsetof(ufunc_T, uf_name)))
#define HI2UF(hi) HIKEY2UF((hi)->hi_key)
/// Defines for Vim variables
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index d95e75170a..939d75608c 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -2,10 +2,11 @@
#include <msgpack.h>
-#include "nvim/eval_defs.h"
+#include "nvim/eval/typval.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/ascii.h"
+#include "nvim/macros.h"
#include "nvim/message.h"
#include "nvim/globals.h"
#include "nvim/charset.h" // vim_str2nr
@@ -52,16 +53,16 @@ static inline void create_special_dict(typval_T *const rettv,
typval_T val)
FUNC_ATTR_NONNULL_ALL
{
- dict_T *const dict = dict_alloc();
- dictitem_T *const type_di = dictitem_alloc((char_u *) "_TYPE");
+ dict_T *const dict = tv_dict_alloc();
+ dictitem_T *const type_di = tv_dict_item_alloc_len(S_LEN("_TYPE"));
type_di->di_tv.v_type = VAR_LIST;
type_di->di_tv.v_lock = VAR_UNLOCKED;
type_di->di_tv.vval.v_list = (list_T *) eval_msgpack_type_lists[type];
type_di->di_tv.vval.v_list->lv_refcount++;
- dict_add(dict, type_di);
- dictitem_T *const val_di = dictitem_alloc((char_u *) "_VAL");
+ tv_dict_add(dict, type_di);
+ dictitem_T *const val_di = tv_dict_item_alloc_len(S_LEN("_VAL"));
val_di->di_tv = val;
- dict_add(dict, val_di);
+ tv_dict_add(dict, val_di);
dict->dv_refcount++;
*rettv = (typval_T) {
.v_type = VAR_DICT,
@@ -119,18 +120,18 @@ static inline int json_decoder_pop(ValuesStackItem obj,
if (last_container.container.vval.v_list->lv_len != 0
&& !obj.didcomma) {
EMSG2(_("E474: Expected comma before list item: %s"), val_location);
- clear_tv(&obj.val);
+ tv_clear(&obj.val);
return FAIL;
}
assert(last_container.special_val == NULL);
- listitem_T *obj_li = listitem_alloc();
+ listitem_T *obj_li = tv_list_item_alloc();
obj_li->li_tv = obj.val;
- list_append(last_container.container.vval.v_list, obj_li);
+ tv_list_append(last_container.container.vval.v_list, obj_li);
} else if (last_container.stack_index == kv_size(*stack) - 2) {
if (!obj.didcolon) {
EMSG2(_("E474: Expected colon before dictionary value: %s"),
val_location);
- clear_tv(&obj.val);
+ tv_clear(&obj.val);
return FAIL;
}
ValuesStackItem key = kv_pop(*stack);
@@ -139,34 +140,35 @@ static inline int json_decoder_pop(ValuesStackItem obj,
assert(!(key.is_special_string
|| key.val.vval.v_string == NULL
|| *key.val.vval.v_string == NUL));
- dictitem_T *obj_di = dictitem_alloc(key.val.vval.v_string);
- clear_tv(&key.val);
- if (dict_add(last_container.container.vval.v_dict, obj_di)
+ dictitem_T *const obj_di = tv_dict_item_alloc(
+ (const char *)key.val.vval.v_string);
+ tv_clear(&key.val);
+ if (tv_dict_add(last_container.container.vval.v_dict, obj_di)
== FAIL) {
assert(false);
}
obj_di->di_tv = obj.val;
} else {
- list_T *const kv_pair = list_alloc();
- list_append_list(last_container.special_val, kv_pair);
- listitem_T *const key_li = listitem_alloc();
+ list_T *const kv_pair = tv_list_alloc();
+ tv_list_append_list(last_container.special_val, kv_pair);
+ listitem_T *const key_li = tv_list_item_alloc();
key_li->li_tv = key.val;
- list_append(kv_pair, key_li);
- listitem_T *const val_li = listitem_alloc();
+ tv_list_append(kv_pair, key_li);
+ listitem_T *const val_li = tv_list_item_alloc();
val_li->li_tv = obj.val;
- list_append(kv_pair, val_li);
+ tv_list_append(kv_pair, val_li);
}
} else {
// Object with key only
if (!obj.is_special_string && obj.val.v_type != VAR_STRING) {
EMSG2(_("E474: Expected string key: %s"), *pp);
- clear_tv(&obj.val);
+ tv_clear(&obj.val);
return FAIL;
} else if (!obj.didcomma
&& (last_container.special_val == NULL
&& (DICT_LEN(last_container.container.vval.v_dict) != 0))) {
EMSG2(_("E474: Expected comma before dictionary key: %s"), val_location);
- clear_tv(&obj.val);
+ tv_clear(&obj.val);
return FAIL;
}
// Handle empty key and key represented as special dictionary
@@ -174,16 +176,16 @@ static inline int json_decoder_pop(ValuesStackItem obj,
&& (obj.is_special_string
|| obj.val.vval.v_string == NULL
|| *obj.val.vval.v_string == NUL
- || dict_find(last_container.container.vval.v_dict,
- obj.val.vval.v_string, -1))) {
- clear_tv(&obj.val);
+ || tv_dict_find(last_container.container.vval.v_dict,
+ (const char *)obj.val.vval.v_string, -1))) {
+ tv_clear(&obj.val);
// Restart
(void) kv_pop(*container_stack);
ValuesStackItem last_container_val =
kv_A(*stack, last_container.stack_index);
while (kv_size(*stack) > last_container.stack_index) {
- clear_tv(&(kv_pop(*stack).val));
+ tv_clear(&(kv_pop(*stack).val));
}
*pp = last_container.s;
*didcomma = last_container_val.didcomma;
@@ -228,7 +230,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
list_T *decode_create_map_special_dict(typval_T *const ret_tv)
FUNC_ATTR_NONNULL_ALL
{
- list_T *const list = list_alloc();
+ list_T *const list = tv_list_alloc();
list->lv_refcount++;
create_special_dict(ret_tv, kMPMap, ((typval_T) {
.v_type = VAR_LIST,
@@ -264,7 +266,7 @@ typval_T decode_string(const char *const s, const size_t len,
? memchr(s, NUL, len) != NULL
: (bool)hasnul);
if (really_hasnul) {
- list_T *const list = list_alloc();
+ list_T *const list = tv_list_alloc();
list->lv_refcount++;
typval_T tv;
create_special_dict(&tv, binary ? kMPBinary : kMPString, ((typval_T) {
@@ -277,7 +279,7 @@ typval_T decode_string(const char *const s, const size_t len,
xfree((void *)s);
}
if (elw_ret == -1) {
- clear_tv(&tv);
+ tv_clear(&tv);
return (typval_T) { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED };
}
return tv;
@@ -502,9 +504,8 @@ static inline int parse_json_string(vimconv_T *const conv,
str_end = new_str + str_len;
}
*str_end = NUL;
- typval_T obj;
- obj = decode_string(str, (size_t)(str_end - str), hasnul ? kTrue : kFalse,
- false, true);
+ typval_T obj = decode_string(
+ str, (size_t)(str_end - str), hasnul ? kTrue : kFalse, false, true);
if (obj.v_type == VAR_UNKNOWN) {
goto parse_json_string_fail;
}
@@ -864,7 +865,7 @@ json_decode_string_cycle_start:
break;
}
case '[': {
- list_T *list = list_alloc();
+ list_T *list = tv_list_alloc();
list->lv_refcount++;
typval_T tv = {
.v_type = VAR_LIST,
@@ -887,7 +888,7 @@ json_decode_string_cycle_start:
next_map_special = false;
val_list = decode_create_map_special_dict(&tv);
} else {
- dict_T *dict = dict_alloc();
+ dict_T *dict = tv_dict_alloc();
dict->dv_refcount++;
tv = (typval_T) {
.v_type = VAR_DICT,
@@ -939,7 +940,7 @@ json_decode_string_after_cycle:
json_decode_string_fail:
ret = FAIL;
while (kv_size(stack)) {
- clear_tv(&(kv_pop(stack).val));
+ tv_clear(&(kv_pop(stack).val));
}
json_decode_string_ret:
kv_destroy(stack);
@@ -985,7 +986,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
.vval = { .v_number = (varnumber_T) mobj.via.u64 },
};
} else {
- list_T *const list = list_alloc();
+ list_T *const list = tv_list_alloc();
list->lv_refcount++;
create_special_dict(rettv, kMPInteger, ((typval_T) {
.v_type = VAR_LIST,
@@ -993,10 +994,10 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
.vval = { .v_list = list },
}));
uint64_t n = mobj.via.u64;
- list_append_number(list, 1);
- list_append_number(list, (varnumber_T) ((n >> 62) & 0x3));
- list_append_number(list, (varnumber_T) ((n >> 31) & 0x7FFFFFFF));
- list_append_number(list, (varnumber_T) (n & 0x7FFFFFFF));
+ tv_list_append_number(list, 1);
+ tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
+ tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
+ tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
}
break;
}
@@ -1008,22 +1009,28 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
.vval = { .v_number = (varnumber_T) mobj.via.i64 },
};
} else {
- list_T *const list = list_alloc();
+ list_T *const list = tv_list_alloc();
list->lv_refcount++;
create_special_dict(rettv, kMPInteger, ((typval_T) {
.v_type = VAR_LIST,
.v_lock = VAR_UNLOCKED,
.vval = { .v_list = list },
}));
- uint64_t n = -((uint64_t) mobj.via.i64);
- list_append_number(list, -1);
- list_append_number(list, (varnumber_T) ((n >> 62) & 0x3));
- list_append_number(list, (varnumber_T) ((n >> 31) & 0x7FFFFFFF));
- list_append_number(list, (varnumber_T) (n & 0x7FFFFFFF));
+ uint64_t n = -((uint64_t)mobj.via.i64);
+ tv_list_append_number(list, -1);
+ tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
+ tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
+ tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
}
break;
}
- case MSGPACK_OBJECT_FLOAT: {
+#ifdef NVIM_MSGPACK_HAS_FLOAT32
+ case MSGPACK_OBJECT_FLOAT32:
+ case MSGPACK_OBJECT_FLOAT64:
+#else
+ case MSGPACK_OBJECT_FLOAT:
+#endif
+ {
*rettv = (typval_T) {
.v_type = VAR_FLOAT,
.v_lock = VAR_UNLOCKED,
@@ -1048,7 +1055,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
break;
}
case MSGPACK_OBJECT_ARRAY: {
- list_T *const list = list_alloc();
+ list_T *const list = tv_list_alloc();
list->lv_refcount++;
*rettv = (typval_T) {
.v_type = VAR_LIST,
@@ -1056,9 +1063,9 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
.vval = { .v_list = list },
};
for (size_t i = 0; i < mobj.via.array.size; i++) {
- listitem_T *const li = listitem_alloc();
+ listitem_T *const li = tv_list_item_alloc();
li->li_tv.v_type = VAR_UNKNOWN;
- list_append(list, li);
+ tv_list_append(list, li);
if (msgpack_to_vim(mobj.via.array.ptr[i], &li->li_tv) == FAIL) {
return FAIL;
}
@@ -1074,7 +1081,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
goto msgpack_to_vim_generic_map;
}
}
- dict_T *const dict = dict_alloc();
+ dict_T *const dict = tv_dict_alloc();
dict->dv_refcount++;
*rettv = (typval_T) {
.v_type = VAR_DICT,
@@ -1087,9 +1094,9 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
memcpy(&di->di_key[0], mobj.via.map.ptr[i].key.via.str.ptr,
mobj.via.map.ptr[i].key.via.str.size);
di->di_tv.v_type = VAR_UNKNOWN;
- if (dict_add(dict, di) == FAIL) {
+ if (tv_dict_add(dict, di) == FAIL) {
// Duplicate key: fallback to generic map
- clear_tv(rettv);
+ tv_clear(rettv);
xfree(di);
goto msgpack_to_vim_generic_map;
}
@@ -1101,14 +1108,14 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
msgpack_to_vim_generic_map: {}
list_T *const list = decode_create_map_special_dict(rettv);
for (size_t i = 0; i < mobj.via.map.size; i++) {
- list_T *const kv_pair = list_alloc();
- list_append_list(list, kv_pair);
- listitem_T *const key_li = listitem_alloc();
+ list_T *const kv_pair = tv_list_alloc();
+ tv_list_append_list(list, kv_pair);
+ listitem_T *const key_li = tv_list_item_alloc();
key_li->li_tv.v_type = VAR_UNKNOWN;
- list_append(kv_pair, key_li);
- listitem_T *const val_li = listitem_alloc();
+ tv_list_append(kv_pair, key_li);
+ listitem_T *const val_li = tv_list_item_alloc();
val_li->li_tv.v_type = VAR_UNKNOWN;
- list_append(kv_pair, val_li);
+ tv_list_append(kv_pair, val_li);
if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_li->li_tv) == FAIL) {
return FAIL;
}
@@ -1119,11 +1126,11 @@ msgpack_to_vim_generic_map: {}
break;
}
case MSGPACK_OBJECT_EXT: {
- list_T *const list = list_alloc();
+ list_T *const list = tv_list_alloc();
list->lv_refcount++;
- list_append_number(list, mobj.via.ext.type);
- list_T *const ext_val_list = list_alloc();
- list_append_list(list, ext_val_list);
+ tv_list_append_number(list, mobj.via.ext.type);
+ list_T *const ext_val_list = tv_list_alloc();
+ tv_list_append_list(list, ext_val_list);
create_special_dict(rettv, kMPExt, ((typval_T) {
.v_type = VAR_LIST,
.v_lock = VAR_UNLOCKED,
diff --git a/src/nvim/eval/decode.h b/src/nvim/eval/decode.h
index 5c25a64f7a..c8e7a189e3 100644
--- a/src/nvim/eval/decode.h
+++ b/src/nvim/eval/decode.h
@@ -5,7 +5,7 @@
#include <msgpack.h>
-#include "nvim/eval_defs.h"
+#include "nvim/eval/typval.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/decode.h.generated.h"
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
index ee66b7cf09..26f9aaa27d 100644
--- a/src/nvim/eval/encode.c
+++ b/src/nvim/eval/encode.c
@@ -13,7 +13,7 @@
#include "nvim/eval/encode.h"
#include "nvim/buffer_defs.h" // vimconv_T
#include "nvim/eval.h"
-#include "nvim/eval_defs.h"
+#include "nvim/eval/typval.h"
#include "nvim/garray.h"
#include "nvim/mbyte.h"
#include "nvim/message.h"
@@ -45,7 +45,8 @@ const char *const encode_special_var_names[] = {
#endif
/// Msgpack callback for writing to readfile()-style list
-int encode_list_write(void *data, const char *buf, size_t len)
+int encode_list_write(void *const data, const char *const buf, const size_t len)
+ FUNC_ATTR_NONNULL_ARG(1)
{
if (len == 0) {
return 0;
@@ -80,11 +81,11 @@ int encode_list_write(void *data, const char *buf, size_t len)
str = xmemdupz(line_start, line_length);
memchrsub(str, NUL, NL, line_length);
}
- list_append_allocated_string(list, str);
+ tv_list_append_allocated_string(list, str);
line_end++;
}
if (line_end == end) {
- list_append_allocated_string(list, NULL);
+ tv_list_append_allocated_string(list, NULL);
}
return 0;
}
@@ -743,11 +744,11 @@ bool encode_check_json_key(const typval_T *const tv)
}
const dictitem_T *type_di;
const dictitem_T *val_di;
- if ((type_di = dict_find((dict_T *) spdict, (char_u *) "_TYPE", -1)) == NULL
+ if ((type_di = tv_dict_find(spdict, S_LEN("_TYPE"))) == NULL
|| type_di->di_tv.v_type != VAR_LIST
|| (type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPString]
&& type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPBinary])
- || (val_di = dict_find((dict_T *) spdict, (char_u *) "_VAL", -1)) == NULL
+ || (val_di = tv_dict_find(spdict, S_LEN("_VAL"))) == NULL
|| val_di->di_tv.v_type != VAR_LIST) {
return false;
}
diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c
new file mode 100644
index 0000000000..ec6c86ac64
--- /dev/null
+++ b/src/nvim/eval/executor.c
@@ -0,0 +1,115 @@
+#include "nvim/eval/typval.h"
+#include "nvim/eval/executor.h"
+#include "nvim/eval.h"
+#include "nvim/message.h"
+#include "nvim/vim.h"
+#include "nvim/globals.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/executor.c.generated.h"
+#endif
+
+static char *e_letwrong = N_("E734: Wrong variable type for %s=");
+
+char *e_listidx = N_("E684: list index out of range: %" PRId64);
+
+/// Hanle tv1 += tv2, -=, .=
+///
+/// @param[in,out] tv1 First operand, modified typval.
+/// @param[in] tv2 Second operand.
+/// @param[in] op Used operator.
+///
+/// @return OK or FAIL.
+int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2,
+ const char *const op)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Can't do anything with a Funcref, a Dict or special value on the right.
+ if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT) {
+ switch (tv1->v_type) {
+ case VAR_DICT:
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_SPECIAL: {
+ break;
+ }
+ case VAR_LIST: {
+ if (*op != '+' || tv2->v_type != VAR_LIST) {
+ break;
+ }
+ // List += List
+ if (tv1->vval.v_list != NULL && tv2->vval.v_list != NULL) {
+ tv_list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL);
+ }
+ return OK;
+ }
+ case VAR_NUMBER:
+ case VAR_STRING: {
+ if (tv2->v_type == VAR_LIST) {
+ break;
+ }
+ if (*op == '+' || *op == '-') {
+ // nr += nr or nr -= nr
+ varnumber_T n = tv_get_number(tv1);
+ if (tv2->v_type == VAR_FLOAT) {
+ float_T f = n;
+
+ if (*op == '+') {
+ f += tv2->vval.v_float;
+ } else {
+ f -= tv2->vval.v_float;
+ }
+ tv_clear(tv1);
+ tv1->v_type = VAR_FLOAT;
+ tv1->vval.v_float = f;
+ } else {
+ if (*op == '+') {
+ n += tv_get_number(tv2);
+ } else {
+ n -= tv_get_number(tv2);
+ }
+ tv_clear(tv1);
+ tv1->v_type = VAR_NUMBER;
+ tv1->vval.v_number = n;
+ }
+ } else {
+ // str .= str
+ if (tv2->v_type == VAR_FLOAT) {
+ break;
+ }
+ const char *tvs = tv_get_string(tv1);
+ char numbuf[NUMBUFLEN];
+ char *const s = (char *)concat_str(
+ (const char_u *)tvs, (const char_u *)tv_get_string_buf(tv2,
+ numbuf));
+ tv_clear(tv1);
+ tv1->v_type = VAR_STRING;
+ tv1->vval.v_string = (char_u *)s;
+ }
+ return OK;
+ }
+ case VAR_FLOAT: {
+ if (*op == '.' || (tv2->v_type != VAR_FLOAT
+ && tv2->v_type != VAR_NUMBER
+ && tv2->v_type != VAR_STRING)) {
+ break;
+ }
+ const float_T f = (tv2->v_type == VAR_FLOAT
+ ? tv2->vval.v_float
+ : tv_get_number(tv2));
+ if (*op == '+') {
+ tv1->vval.v_float += f;
+ } else {
+ tv1->vval.v_float -= f;
+ }
+ return OK;
+ }
+ case VAR_UNKNOWN: {
+ assert(false);
+ }
+ }
+ }
+
+ EMSG2(_(e_letwrong), op);
+ return FAIL;
+}
diff --git a/src/nvim/eval/executor.h b/src/nvim/eval/executor.h
new file mode 100644
index 0000000000..3d789f76a5
--- /dev/null
+++ b/src/nvim/eval/executor.h
@@ -0,0 +1,11 @@
+#ifndef NVIM_EVAL_EXECUTOR_H
+#define NVIM_EVAL_EXECUTOR_H
+
+#include "nvim/eval/typval.h"
+
+extern char *e_listidx;
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/executor.h.generated.h"
+#endif
+#endif // NVIM_EVAL_EXECUTOR_H
diff --git a/src/nvim/eval/gc.c b/src/nvim/eval/gc.c
new file mode 100644
index 0000000000..5ce52ddd70
--- /dev/null
+++ b/src/nvim/eval/gc.c
@@ -0,0 +1,11 @@
+#include "nvim/eval/typval.h"
+#include "nvim/eval/gc.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/gc.c.generated.h"
+#endif
+
+/// Head of list of all dictionaries
+dict_T *gc_first_dict = NULL;
+/// Head of list of all lists
+list_T *gc_first_list = NULL;
diff --git a/src/nvim/eval/gc.h b/src/nvim/eval/gc.h
new file mode 100644
index 0000000000..c2e862e469
--- /dev/null
+++ b/src/nvim/eval/gc.h
@@ -0,0 +1,12 @@
+#ifndef NVIM_EVAL_GC_H
+#define NVIM_EVAL_GC_H
+
+#include "nvim/eval/typval.h"
+
+extern dict_T *gc_first_dict;
+extern list_T *gc_first_list;
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/gc.h.generated.h"
+#endif
+#endif // NVIM_EVAL_GC_H
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
new file mode 100644
index 0000000000..779bb18175
--- /dev/null
+++ b/src/nvim/eval/typval.c
@@ -0,0 +1,2556 @@
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include <stdbool.h>
+
+#include "nvim/lib/queue.h"
+#include "nvim/eval/typval.h"
+#include "nvim/eval/gc.h"
+#include "nvim/eval/executor.h"
+#include "nvim/eval/encode.h"
+#include "nvim/eval/typval_encode.h"
+#include "nvim/eval.h"
+#include "nvim/types.h"
+#include "nvim/assert.h"
+#include "nvim/memory.h"
+#include "nvim/globals.h"
+#include "nvim/hashtab.h"
+#include "nvim/vim.h"
+#include "nvim/ascii.h"
+#include "nvim/pos.h"
+#include "nvim/charset.h"
+#include "nvim/garray.h"
+#include "nvim/gettext.h"
+#include "nvim/macros.h"
+#include "nvim/mbyte.h"
+#include "nvim/message.h"
+// TODO(ZyX-I): Move line_breakcheck out of misc1
+#include "nvim/misc1.h" // For line_breakcheck
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/typval.c.generated.h"
+#endif
+
+bool tv_in_free_unref_items = false;
+
+// TODO(ZyX-I): Remove DICT_MAXNEST, make users be non-recursive instead
+
+#define DICT_MAXNEST 100
+
+const char *const tv_empty_string = "";
+
+//{{{1 Lists
+//{{{2 List item
+
+/// Allocate a list item
+///
+/// @warning Allocated item is not initialized, do not forget to initialize it
+/// and specifically set lv_lock.
+///
+/// @return [allocated] new list item.
+listitem_T *tv_list_item_alloc(void)
+ FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC
+{
+ return xmalloc(sizeof(listitem_T));
+}
+
+/// Free a list item
+///
+/// Also clears the value. Does not touch watchers.
+///
+/// @param[out] item Item to free.
+void tv_list_item_free(listitem_T *const item)
+ FUNC_ATTR_NONNULL_ALL
+{
+ tv_clear(&item->li_tv);
+ xfree(item);
+}
+
+/// Remove a list item from a List and free it
+///
+/// Also clears the value.
+///
+/// @param[out] l List to remove item from.
+/// @param[in,out] item Item to remove.
+void tv_list_item_remove(list_T *const l, listitem_T *const item)
+ FUNC_ATTR_NONNULL_ALL
+{
+ tv_list_remove_items(l, item, item);
+ tv_list_item_free(item);
+}
+
+//{{{2 List watchers
+
+/// Add a watcher to a list
+///
+/// @param[out] l List to add watcher to.
+/// @param[in] lw Watcher to add.
+void tv_list_watch_add(list_T *const l, listwatch_T *const lw)
+ FUNC_ATTR_NONNULL_ALL
+{
+ lw->lw_next = l->lv_watch;
+ l->lv_watch = lw;
+}
+
+/// Remove a watcher from a list
+///
+/// Does not give a warning if watcher was not found.
+///
+/// @param[out] l List to remove watcher from.
+/// @param[in] lwrem Watcher to remove.
+void tv_list_watch_remove(list_T *const l, listwatch_T *const lwrem)
+ FUNC_ATTR_NONNULL_ALL
+{
+ listwatch_T **lwp = &l->lv_watch;
+ for (listwatch_T *lw = l->lv_watch; lw != NULL; lw = lw->lw_next) {
+ if (lw == lwrem) {
+ *lwp = lw->lw_next;
+ break;
+ }
+ lwp = &lw->lw_next;
+ }
+}
+
+/// Advance watchers to the next item
+///
+/// Used just before removing an item from a list.
+///
+/// @param[out] l List from which item is removed.
+/// @param[in] item List item being removed.
+void tv_list_watch_fix(list_T *const l, const listitem_T *const item)
+ FUNC_ATTR_NONNULL_ALL
+{
+ for (listwatch_T *lw = l->lv_watch; lw != NULL; lw = lw->lw_next) {
+ if (lw->lw_item == item) {
+ lw->lw_item = item->li_next;
+ }
+ }
+}
+
+//{{{2 Alloc/free
+
+/// Allocate an empty list
+///
+/// Caller should take care of the reference count.
+///
+/// @return [allocated] new list.
+list_T *tv_list_alloc(void)
+ FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC
+{
+ list_T *const list = xcalloc(1, sizeof(list_T));
+
+ // Prepend the list to the list of lists for garbage collection.
+ if (gc_first_list != NULL) {
+ gc_first_list->lv_used_prev = list;
+ }
+ list->lv_used_prev = NULL;
+ list->lv_used_next = gc_first_list;
+ gc_first_list = list;
+ return list;
+}
+
+/// Free items contained in a list
+///
+/// @param[in,out] l List to clear.
+void tv_list_free_contents(list_T *const l)
+ FUNC_ATTR_NONNULL_ALL
+{
+ for (listitem_T *item = l->lv_first; item != NULL; item = l->lv_first) {
+ // Remove the item before deleting it.
+ l->lv_first = item->li_next;
+ tv_clear(&item->li_tv);
+ xfree(item);
+ }
+ l->lv_len = 0;
+ l->lv_idx_item = NULL;
+ l->lv_last = NULL;
+ assert(l->lv_watch == NULL);
+}
+
+/// Free a list itself, ignoring items it contains
+///
+/// Ignores the reference count.
+///
+/// @param[in,out] l List to free.
+void tv_list_free_list(list_T *const l)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Remove the list from the list of lists for garbage collection.
+ if (l->lv_used_prev == NULL) {
+ gc_first_list = l->lv_used_next;
+ } else {
+ l->lv_used_prev->lv_used_next = l->lv_used_next;
+ }
+ if (l->lv_used_next != NULL) {
+ l->lv_used_next->lv_used_prev = l->lv_used_prev;
+ }
+
+ xfree(l);
+}
+
+/// Free a list, including all items it points to
+///
+/// Ignores the reference count. Does not do anything if
+/// tv_in_free_unref_items is true.
+///
+/// @param[in,out] l List to free.
+void tv_list_free(list_T *const l)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (!tv_in_free_unref_items) {
+ tv_list_free_contents(l);
+ tv_list_free_list(l);
+ }
+}
+
+/// Unreference a list
+///
+/// Decrements the reference count and frees when it becomes zero or less.
+///
+/// @param[in,out] l List to unreference.
+void tv_list_unref(list_T *const l)
+{
+ if (l != NULL && --l->lv_refcount <= 0) {
+ tv_list_free(l);
+ }
+}
+
+//{{{2 Add/remove
+
+/// Remove items "item" to "item2" from list "l".
+///
+/// @warning Does not free the listitem or the value!
+///
+/// @param[out] l List to remove from.
+/// @param[in] item First item to remove.
+/// @param[in] item2 Last item to remove.
+void tv_list_remove_items(list_T *const l, listitem_T *const item,
+ listitem_T *const item2)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Notify watchers.
+ for (listitem_T *ip = item; ip != item2->li_next; ip = ip->li_next) {
+ l->lv_len--;
+ tv_list_watch_fix(l, ip);
+ }
+
+ if (item2->li_next == NULL) {
+ l->lv_last = item->li_prev;
+ } else {
+ item2->li_next->li_prev = item->li_prev;
+ }
+ if (item->li_prev == NULL) {
+ l->lv_first = item2->li_next;
+ } else {
+ item->li_prev->li_next = item2->li_next;
+ }
+ l->lv_idx_item = NULL;
+}
+
+/// Insert list item
+///
+/// @param[out] l List to insert to.
+/// @param[in,out] ni Item to insert.
+/// @param[in] item Item to insert before. If NULL, inserts at the end of the
+/// list.
+void tv_list_insert(list_T *const l, listitem_T *const ni,
+ listitem_T *const item)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
+{
+ if (item == NULL) {
+ // Append new item at end of list.
+ tv_list_append(l, ni);
+ } else {
+ // Insert new item before existing item.
+ ni->li_prev = item->li_prev;
+ ni->li_next = item;
+ if (item->li_prev == NULL) {
+ l->lv_first = ni;
+ l->lv_idx++;
+ } else {
+ item->li_prev->li_next = ni;
+ l->lv_idx_item = NULL;
+ }
+ item->li_prev = ni;
+ l->lv_len++;
+ }
+}
+
+/// Insert VimL value into a list
+///
+/// @param[out] l List to insert to.
+/// @param[in,out] tv Value to insert. Is copied (@see tv_copy()) to an
+/// allocated listitem_T and inserted.
+/// @param[in] item Item to insert before. If NULL, inserts at the end of the
+/// list.
+void tv_list_insert_tv(list_T *const l, typval_T *const tv,
+ listitem_T *const item)
+{
+ listitem_T *const ni = tv_list_item_alloc();
+
+ tv_copy(tv, &ni->li_tv);
+ tv_list_insert(l, ni, item);
+}
+
+/// Append item to the end of list
+///
+/// @param[out] l List to append to.
+/// @param[in,out] item Item to append.
+void tv_list_append(list_T *const l, listitem_T *const item)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (l->lv_last == NULL) {
+ // empty list
+ l->lv_first = item;
+ l->lv_last = item;
+ item->li_prev = NULL;
+ } else {
+ l->lv_last->li_next = item;
+ item->li_prev = l->lv_last;
+ l->lv_last = item;
+ }
+ l->lv_len++;
+ item->li_next = NULL;
+}
+
+/// Append VimL value to the end of list
+///
+/// @param[out] l List to append to.
+/// @param[in,out] tv Value to append. Is copied (@see tv_copy()) to an
+/// allocated listitem_T.
+void tv_list_append_tv(list_T *const l, typval_T *const tv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ listitem_T *const li = tv_list_item_alloc();
+ tv_copy(tv, &li->li_tv);
+ tv_list_append(l, li);
+}
+
+/// Append a list to a list as one item
+///
+/// @param[out] l List to append to.
+/// @param[in,out] itemlist List to append. Reference count is increased.
+void tv_list_append_list(list_T *const list, list_T *const itemlist)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ listitem_T *const li = tv_list_item_alloc();
+
+ li->li_tv.v_type = VAR_LIST;
+ li->li_tv.v_lock = VAR_UNLOCKED;
+ li->li_tv.vval.v_list = itemlist;
+ tv_list_append(list, li);
+ if (itemlist != NULL) {
+ itemlist->lv_refcount++;
+ }
+}
+
+/// Append a dictionary to a list
+///
+/// @param[out] l List to append to.
+/// @param[in,out] dict Dictionary to append. Reference count is increased.
+void tv_list_append_dict(list_T *const list, dict_T *const dict)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ listitem_T *const li = tv_list_item_alloc();
+
+ li->li_tv.v_type = VAR_DICT;
+ li->li_tv.v_lock = VAR_UNLOCKED;
+ li->li_tv.vval.v_dict = dict;
+ tv_list_append(list, li);
+ if (dict != NULL) {
+ dict->dv_refcount++;
+ }
+}
+
+/// Make a copy of "str" and append it as an item to list "l"
+///
+/// @param[out] l List to append to.
+/// @param[in] str String to append.
+/// @param[in] len Length of the appended string. May be -1, in this
+/// case string is considered to be usual zero-terminated
+/// string or NULL “empty” string.
+void tv_list_append_string(list_T *const l, const char *const str,
+ const ptrdiff_t len)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ if (str == NULL) {
+ assert(len == 0 || len == -1);
+ tv_list_append_allocated_string(l, NULL);
+ } else {
+ tv_list_append_allocated_string(l, (len >= 0
+ ? xmemdupz(str, (size_t)len)
+ : xstrdup(str)));
+ }
+}
+
+/// Append given string to the list
+///
+/// Unlike list_append_string this function does not copy the string.
+///
+/// @param[out] l List to append to.
+/// @param[in] str String to append.
+void tv_list_append_allocated_string(list_T *const l, char *const str)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ listitem_T *const li = tv_list_item_alloc();
+
+ tv_list_append(l, li);
+ li->li_tv.v_type = VAR_STRING;
+ li->li_tv.v_lock = VAR_UNLOCKED;
+ li->li_tv.vval.v_string = (char_u *)str;
+}
+
+/// Append number to the list
+///
+/// @param[out] l List to append to.
+/// @param[in] n Number to append. Will be recorded in the allocated
+/// listitem_T.
+void tv_list_append_number(list_T *const l, const varnumber_T n)
+{
+ listitem_T *const li = tv_list_item_alloc();
+ li->li_tv.v_type = VAR_NUMBER;
+ li->li_tv.v_lock = VAR_UNLOCKED;
+ li->li_tv.vval.v_number = n;
+ tv_list_append(l, li);
+}
+
+//{{{2 Operations on the whole list
+
+/// Make a copy of list
+///
+/// @param[in] conv If non-NULL, then all internal strings will be converted.
+/// Only used when `deep` is true.
+/// @param[in] orig Original list to copy.
+/// @param[in] deep If false, then shallow copy will be done.
+/// @param[in] copyID See var_item_copy().
+///
+/// @return Copied list. May be NULL in case original list is NULL or some
+/// failure happens. The refcount of the new list is set to 1.
+list_T *tv_list_copy(const vimconv_T *const conv, list_T *const orig,
+ const bool deep, const int copyID)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (orig == NULL) {
+ return NULL;
+ }
+
+ list_T *copy = tv_list_alloc();
+ if (copyID != 0) {
+ // Do this before adding the items, because one of the items may
+ // refer back to this list.
+ orig->lv_copyID = copyID;
+ orig->lv_copylist = copy;
+ }
+ listitem_T *item;
+ for (item = orig->lv_first; item != NULL && !got_int;
+ item = item->li_next) {
+ listitem_T *const ni = tv_list_item_alloc();
+ if (deep) {
+ if (var_item_copy(conv, &item->li_tv, &ni->li_tv, deep, copyID) == FAIL) {
+ xfree(ni);
+ break;
+ }
+ } else {
+ tv_copy(&item->li_tv, &ni->li_tv);
+ }
+ tv_list_append(copy, ni);
+ }
+ copy->lv_refcount++;
+ if (item != NULL) {
+ tv_list_unref(copy);
+ copy = NULL;
+ }
+
+ return copy;
+}
+
+/// Extend first list with the second
+///
+/// @param[out] l1 List to extend.
+/// @param[in] l2 List to extend with.
+/// @param[in] bef If not NULL, extends before this item.
+void tv_list_extend(list_T *const l1, list_T *const l2,
+ listitem_T *const bef)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
+{
+ int todo = l2->lv_len;
+ listitem_T *const befbef = (bef == NULL ? NULL : bef->li_prev);
+ listitem_T *const saved_next = (befbef == NULL ? NULL : befbef->li_next);
+ // We also quit the loop when we have inserted the original item count of
+ // the list, avoid a hang when we extend a list with itself.
+ for (listitem_T *item = l2->lv_first
+ ; item != NULL && --todo >= 0
+ ; item = (item == befbef ? saved_next : item->li_next)) {
+ tv_list_insert_tv(l1, &item->li_tv, bef);
+ }
+}
+
+/// Concatenate lists into a new list
+///
+/// @param[in] l1 First list.
+/// @param[in] l2 Second list.
+/// @param[out] ret_tv Location where new list is saved.
+///
+/// @return OK or FAIL.
+int tv_list_concat(list_T *const l1, list_T *const l2, typval_T *const tv)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ list_T *l;
+
+ tv->v_type = VAR_LIST;
+
+ if (l1 == NULL && l2 == NULL) {
+ l = NULL;
+ } else if (l1 == NULL) {
+ l = tv_list_copy(NULL, l2, false, 0);
+ } else {
+ l = tv_list_copy(NULL, l1, false, 0);
+ if (l != NULL && l2 != NULL) {
+ tv_list_extend(l, l2, NULL);
+ }
+ }
+ if (l == NULL && !(l1 == NULL && l2 == NULL)) {
+ return FAIL;
+ }
+
+ tv->vval.v_list = l;
+ return OK;
+}
+
+typedef struct {
+ char_u *s;
+ char_u *tofree;
+} Join;
+
+/// Join list into a string, helper function
+///
+/// @param[out] gap Garray where result will be saved.
+/// @param[in] l List to join.
+/// @param[in] sep Used separator.
+/// @param[in] join_gap Garray to keep each list item string.
+///
+/// @return OK in case of success, FAIL otherwise.
+static int list_join_inner(garray_T *const gap, list_T *const l,
+ const char *const sep, garray_T *const join_gap)
+ FUNC_ATTR_NONNULL_ALL
+{
+ size_t sumlen = 0;
+ bool first = true;
+ listitem_T *item;
+
+ // Stringify each item in the list.
+ for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) {
+ char *s;
+ size_t len;
+ s = encode_tv2echo(&item->li_tv, &len);
+ if (s == NULL) {
+ return FAIL;
+ }
+
+ sumlen += len;
+
+ Join *const p = GA_APPEND_VIA_PTR(Join, join_gap);
+ p->tofree = p->s = (char_u *)s;
+
+ line_breakcheck();
+ }
+
+ // Allocate result buffer with its total size, avoid re-allocation and
+ // multiple copy operations. Add 2 for a tailing ']' and NUL.
+ if (join_gap->ga_len >= 2) {
+ sumlen += strlen(sep) * (size_t)(join_gap->ga_len - 1);
+ }
+ ga_grow(gap, (int)sumlen + 2);
+
+ for (int i = 0; i < join_gap->ga_len && !got_int; i++) {
+ if (first) {
+ first = false;
+ } else {
+ ga_concat(gap, (const char_u *)sep);
+ }
+ const Join *const p = ((const Join *)join_gap->ga_data) + i;
+
+ if (p->s != NULL) {
+ ga_concat(gap, p->s);
+ }
+ line_breakcheck();
+ }
+
+ return OK;
+}
+
+/// Join list into a string using given separator
+///
+/// @param[out] gap Garray where result will be saved.
+/// @param[in] l Joined list.
+/// @param[in] sep Separator.
+///
+/// @return OK in case of success, FAIL otherwise.
+int tv_list_join(garray_T *const gap, list_T *const l, const char *const sep)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (l->lv_len < 1) {
+ return OK;
+ }
+
+ garray_T join_ga;
+ int retval;
+
+ ga_init(&join_ga, (int)sizeof(Join), l->lv_len);
+ retval = list_join_inner(gap, l, sep, &join_ga);
+
+#define FREE_JOIN_TOFREE(join) xfree((join)->tofree)
+ GA_DEEP_CLEAR(&join_ga, Join, FREE_JOIN_TOFREE);
+#undef FREE_JOIN_TOFREE
+
+ return retval;
+}
+
+/// Chech whether two lists are equal
+///
+/// @param[in] l1 First list to compare.
+/// @param[in] l2 Second list to compare.
+/// @param[in] ic True if case is to be ignored.
+/// @param[in] recursive True when used recursively.
+///
+/// @return True if lists are equal, false otherwise.
+bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic,
+ const bool recursive)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (l1 == l2) {
+ return true;
+ }
+ if (l1 == NULL || l2 == NULL) {
+ return false;
+ }
+ if (tv_list_len(l1) != tv_list_len(l2)) {
+ return false;
+ }
+
+ listitem_T *item1 = l1->lv_first;
+ listitem_T *item2 = l2->lv_first;
+ for (; item1 != NULL && item2 != NULL
+ ; item1 = item1->li_next, item2 = item2->li_next) {
+ if (!tv_equal(&item1->li_tv, &item2->li_tv, ic, recursive)) {
+ return false;
+ }
+ }
+ assert(item1 == NULL && item2 == NULL);
+ return true;
+}
+
+//{{{2 Indexing/searching
+
+/// Locate item with a given index in a list and return it
+///
+/// @param[in] l List to index.
+/// @param[in] n Index. Negative index is counted from the end, -1 is the last
+/// item.
+///
+/// @return Item at the given index or NULL if `n` is out of range.
+listitem_T *tv_list_find(list_T *const l, int n)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ STATIC_ASSERT(sizeof(n) == sizeof(l->lv_idx),
+ "n and lv_idx sizes do not match");
+ if (l == NULL) {
+ return NULL;
+ }
+
+ // Negative index is relative to the end.
+ if (n < 0) {
+ n = l->lv_len + n;
+ }
+
+ // Check for index out of range.
+ if (n < 0 || n >= l->lv_len) {
+ return NULL;
+ }
+
+ int idx;
+ listitem_T *item;
+
+ // When there is a cached index may start search from there.
+ if (l->lv_idx_item != NULL) {
+ if (n < l->lv_idx / 2) {
+ // Closest to the start of the list.
+ item = l->lv_first;
+ idx = 0;
+ } else if (n > (l->lv_idx + l->lv_len) / 2) {
+ // Closest to the end of the list.
+ item = l->lv_last;
+ idx = l->lv_len - 1;
+ } else {
+ // Closest to the cached index.
+ item = l->lv_idx_item;
+ idx = l->lv_idx;
+ }
+ } else {
+ if (n < l->lv_len / 2) {
+ // Closest to the start of the list.
+ item = l->lv_first;
+ idx = 0;
+ } else {
+ // Closest to the end of the list.
+ item = l->lv_last;
+ idx = l->lv_len - 1;
+ }
+ }
+
+ while (n > idx) {
+ // Search forward.
+ item = item->li_next;
+ idx++;
+ }
+ while (n < idx) {
+ // Search backward.
+ item = item->li_prev;
+ idx--;
+ }
+
+ assert(idx == n);
+ // Cache the used index.
+ l->lv_idx = idx;
+ l->lv_idx_item = item;
+
+ return item;
+}
+
+/// Get list item l[n] as a number
+///
+/// @param[in] l List to index.
+/// @param[in] n Index in a list.
+/// @param[out] ret_error Location where 1 will be saved if index was not
+/// found. May be NULL. If everything is OK,
+/// `*ret_error` is not touched.
+///
+/// @return Integer value at the given index or -1.
+varnumber_T tv_list_find_nr(list_T *const l, const int n, bool *const ret_error)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ const listitem_T *const li = tv_list_find(l, n);
+ if (li == NULL) {
+ if (ret_error != NULL) {
+ *ret_error = true;
+ }
+ return -1;
+ }
+ return tv_get_number_chk(&li->li_tv, ret_error);
+}
+
+/// Get list item l[n] as a string
+///
+/// @param[in] l List to index.
+/// @param[in] n Index in a list.
+///
+/// @return List item string value or NULL in case of error.
+const char *tv_list_find_str(list_T *const l, const int n)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ const listitem_T *const li = tv_list_find(l, n);
+ if (li == NULL) {
+ emsgf(_(e_listidx), (int64_t)n);
+ return NULL;
+ }
+ return tv_get_string(&li->li_tv);
+}
+
+/// Locate item in a list and return its index
+///
+/// @param[in] l List to search.
+/// @param[in] item Item to search for.
+///
+/// @return Index of an item or -1 if item is not in the list.
+long tv_list_idx_of_item(const list_T *const l, const listitem_T *const item)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
+{
+ if (l == NULL) {
+ return -1;
+ }
+ long idx = 0;
+ const listitem_T *li;
+ for (li = l->lv_first; li != NULL && li != item; li = li->li_next) {
+ idx++;
+ }
+ if (li == NULL) {
+ return -1;
+ }
+ return idx;
+}
+
+//{{{1 Dictionaries
+//{{{2 Dictionary watchers
+
+/// Perform all necessary cleanup for a `DictWatcher` instance
+///
+/// @param watcher Watcher to free.
+static void tv_dict_watcher_free(DictWatcher *watcher)
+ FUNC_ATTR_NONNULL_ALL
+{
+ callback_free(&watcher->callback);
+ xfree(watcher->key_pattern);
+ xfree(watcher);
+}
+
+/// Add watcher to a dictionary
+///
+/// @param[in] dict Dictionary to add watcher to.
+/// @param[in] key_pattern Pattern to watch for.
+/// @param[in] key_pattern_len Key pattern length.
+/// @param callback Function to be called on events.
+void tv_dict_watcher_add(dict_T *const dict, const char *const key_pattern,
+ const size_t key_pattern_len, Callback callback)
+ FUNC_ATTR_NONNULL_ARG(2)
+{
+ if (dict == NULL) {
+ return;
+ }
+ DictWatcher *const watcher = xmalloc(sizeof(DictWatcher));
+ watcher->key_pattern = xmemdupz(key_pattern, key_pattern_len);
+ watcher->key_pattern_len = key_pattern_len;
+ watcher->callback = callback;
+ watcher->busy = false;
+ QUEUE_INSERT_TAIL(&dict->watchers, &watcher->node);
+}
+
+/// Check whether two callbacks are equal
+///
+/// @param[in] cb1 First callback to check.
+/// @param[in] cb2 Second callback to check.
+///
+/// @return True if they are equal, false otherwise.
+bool tv_callback_equal(const Callback *const cb1, const Callback *const cb2)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (cb1->type != cb2->type) {
+ return false;
+ }
+ switch (cb1->type) {
+ case kCallbackFuncref: {
+ return STRCMP(cb1->data.funcref, cb2->data.funcref) == 0;
+ }
+ case kCallbackPartial: {
+ // FIXME: this is inconsistent with tv_equal but is needed for precision
+ // maybe change dictwatcheradd to return a watcher id instead?
+ return cb1->data.partial == cb2->data.partial;
+ }
+ case kCallbackNone: {
+ return true;
+ }
+ }
+ assert(false);
+ return false;
+}
+
+/// Remove watcher from a dictionary
+///
+/// @param dict Dictionary to remove watcher from.
+/// @param[in] key_pattern Pattern to remove watcher for.
+/// @param[in] key_pattern_len Pattern length.
+/// @param callback Callback to remove watcher for.
+///
+/// @return True on success, false if relevant watcher was not found.
+bool tv_dict_watcher_remove(dict_T *const dict, const char *const key_pattern,
+ const size_t key_pattern_len,
+ Callback callback)
+ FUNC_ATTR_NONNULL_ARG(2)
+{
+ if (dict == NULL) {
+ return false;
+ }
+
+ QUEUE *w = NULL;
+ DictWatcher *watcher = NULL;
+ bool matched = false;
+ QUEUE_FOREACH(w, &dict->watchers) {
+ watcher = tv_dict_watcher_node_data(w);
+ if (tv_callback_equal(&watcher->callback, &callback)
+ && watcher->key_pattern_len == key_pattern_len
+ && memcmp(watcher->key_pattern, key_pattern, key_pattern_len) == 0) {
+ matched = true;
+ break;
+ }
+ }
+
+ if (!matched) {
+ return false;
+ }
+
+ QUEUE_REMOVE(w);
+ tv_dict_watcher_free(watcher);
+ return true;
+}
+
+/// Test if `key` matches with with `watcher->key_pattern`
+///
+/// @param[in] watcher Watcher to check key pattern from.
+/// @param[in] key Key to check.
+///
+/// @return true if key matches, false otherwise.
+static bool tv_dict_watcher_matches(DictWatcher *watcher, const char *const key)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
+{
+ // For now only allow very simple globbing in key patterns: a '*' at the end
+ // of the string means it should match everything up to the '*' instead of the
+ // whole string.
+ const size_t len = watcher->key_pattern_len;
+ if (len && watcher->key_pattern[len - 1] == '*') {
+ return strncmp(key, watcher->key_pattern, len - 1) == 0;
+ } else {
+ return strcmp(key, watcher->key_pattern) == 0;
+ }
+}
+
+/// Send a change notification to all dictionary watchers that match given key
+///
+/// @param[in] dict Dictionary which was modified.
+/// @param[in] key Key which was modified.
+/// @param[in] newtv New key value.
+/// @param[in] oldtv Old key value.
+void tv_dict_watcher_notify(dict_T *const dict, const char *const key,
+ typval_T *const newtv, typval_T *const oldtv)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
+{
+ typval_T argv[3];
+
+ argv[0].v_type = VAR_DICT;
+ argv[0].v_lock = VAR_UNLOCKED;
+ argv[0].vval.v_dict = dict;
+ argv[1].v_type = VAR_STRING;
+ argv[1].v_lock = VAR_UNLOCKED;
+ argv[1].vval.v_string = (char_u *)xstrdup(key);
+ argv[2].v_type = VAR_DICT;
+ argv[2].v_lock = VAR_UNLOCKED;
+ argv[2].vval.v_dict = tv_dict_alloc();
+ argv[2].vval.v_dict->dv_refcount++;
+
+ if (newtv) {
+ dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("new"));
+ tv_copy(newtv, &v->di_tv);
+ tv_dict_add(argv[2].vval.v_dict, v);
+ }
+
+ if (oldtv) {
+ dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("old"));
+ tv_copy(oldtv, &v->di_tv);
+ tv_dict_add(argv[2].vval.v_dict, v);
+ }
+
+ typval_T rettv;
+
+ QUEUE *w;
+ QUEUE_FOREACH(w, &dict->watchers) {
+ DictWatcher *watcher = tv_dict_watcher_node_data(w);
+ if (!watcher->busy && tv_dict_watcher_matches(watcher, key)) {
+ rettv = TV_INITIAL_VALUE;
+ watcher->busy = true;
+ callback_call(&watcher->callback, 3, argv, &rettv);
+ watcher->busy = false;
+ tv_clear(&rettv);
+ }
+ }
+
+ for (size_t i = 1; i < ARRAY_SIZE(argv); i++) {
+ tv_clear(argv + i);
+ }
+}
+
+//{{{2 Dictionary item
+
+/// Allocate a dictionary item
+///
+/// @note that the value of the item (->di_tv) still needs to be initialized.
+///
+/// @param[in] key Key, is copied to the new item.
+/// @param[in] key_len Key length.
+///
+/// @return [allocated] new dictionary item.
+dictitem_T *tv_dict_item_alloc_len(const char *const key, const size_t key_len)
+ FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+ FUNC_ATTR_MALLOC
+{
+ dictitem_T *const di = xmalloc(offsetof(dictitem_T, di_key) + key_len + 1);
+ memcpy(di->di_key, key, key_len);
+ di->di_key[key_len] = NUL;
+ di->di_flags = DI_FLAGS_ALLOC;
+ return di;
+}
+
+/// Allocate a dictionary item
+///
+/// @note that the value of the item (->di_tv) still needs to be initialized.
+///
+/// @param[in] key Key, is copied to the new item.
+///
+/// @return [allocated] new dictionary item.
+dictitem_T *tv_dict_item_alloc(const char *const key)
+ FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+ FUNC_ATTR_MALLOC
+{
+ return tv_dict_item_alloc_len(key, strlen(key));
+}
+
+/// Free a dictionary item, also clearing the value
+///
+/// @param item Item to free.
+void tv_dict_item_free(dictitem_T *const item)
+ FUNC_ATTR_NONNULL_ALL
+{
+ tv_clear(&item->di_tv);
+ if (item->di_flags & DI_FLAGS_ALLOC) {
+ xfree(item);
+ }
+}
+
+/// Make a copy of a dictionary item
+///
+/// @param[in] di Item to copy.
+///
+/// @return [allocated] new dictionary item.
+static dictitem_T *tv_dict_item_copy(dictitem_T *const di)
+ FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+ FUNC_ATTR_MALLOC
+{
+ dictitem_T *const new_di = tv_dict_item_alloc((const char *)di->di_key);
+ tv_copy(&di->di_tv, &new_di->di_tv);
+ return new_di;
+}
+
+/// Remove item from dictionary and free it
+///
+/// @param dict Dictionary to remove item from.
+/// @param item Item to remove.
+void tv_dict_item_remove(dict_T *const dict, dictitem_T *const item)
+ FUNC_ATTR_NONNULL_ALL
+{
+ hashitem_T *const hi = hash_find(&dict->dv_hashtab, item->di_key);
+ if (HASHITEM_EMPTY(hi)) {
+ emsgf(_(e_intern2), "tv_dict_item_remove()");
+ } else {
+ hash_remove(&dict->dv_hashtab, hi);
+ }
+ tv_dict_item_free(item);
+}
+
+//{{{2 Alloc/free
+
+/// Allocate an empty dictionary
+///
+/// @return [allocated] new dictionary.
+dict_T *tv_dict_alloc(void)
+ FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ dict_T *const d = xmalloc(sizeof(dict_T));
+
+ // Add the dict to the list of dicts for garbage collection.
+ if (gc_first_dict != NULL) {
+ gc_first_dict->dv_used_prev = d;
+ }
+ d->dv_used_next = gc_first_dict;
+ d->dv_used_prev = NULL;
+ gc_first_dict = d;
+
+ hash_init(&d->dv_hashtab);
+ d->dv_lock = VAR_UNLOCKED;
+ d->dv_scope = VAR_NO_SCOPE;
+ d->dv_refcount = 0;
+ d->dv_copyID = 0;
+ QUEUE_INIT(&d->watchers);
+
+ return d;
+}
+
+/// Free items contained in a dictionary
+///
+/// @param[in,out] d Dictionary to clear.
+void tv_dict_free_contents(dict_T *const d)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Lock the hashtab, we don't want it to resize while freeing items.
+ hash_lock(&d->dv_hashtab);
+ assert(d->dv_hashtab.ht_locked > 0);
+ HASHTAB_ITER(&d->dv_hashtab, hi, {
+ // Remove the item before deleting it, just in case there is
+ // something recursive causing trouble.
+ dictitem_T *const di = TV_DICT_HI2DI(hi);
+ hash_remove(&d->dv_hashtab, hi);
+ tv_dict_item_free(di);
+ });
+
+ while (!QUEUE_EMPTY(&d->watchers)) {
+ QUEUE *w = QUEUE_HEAD(&d->watchers);
+ QUEUE_REMOVE(w);
+ DictWatcher *watcher = tv_dict_watcher_node_data(w);
+ tv_dict_watcher_free(watcher);
+ }
+
+ hash_clear(&d->dv_hashtab);
+ d->dv_hashtab.ht_locked--;
+ hash_init(&d->dv_hashtab);
+}
+
+/// Free a dictionary itself, ignoring items it contains
+///
+/// Ignores the reference count.
+///
+/// @param[in,out] d Dictionary to free.
+void tv_dict_free_dict(dict_T *const d)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Remove the dict from the list of dicts for garbage collection.
+ if (d->dv_used_prev == NULL) {
+ gc_first_dict = d->dv_used_next;
+ } else {
+ d->dv_used_prev->dv_used_next = d->dv_used_next;
+ }
+ if (d->dv_used_next != NULL) {
+ d->dv_used_next->dv_used_prev = d->dv_used_prev;
+ }
+
+ xfree(d);
+}
+
+/// Free a dictionary, including all items it contains
+///
+/// Ignores the reference count.
+///
+/// @param d Dictionary to free.
+void tv_dict_free(dict_T *const d)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (!tv_in_free_unref_items) {
+ tv_dict_free_contents(d);
+ tv_dict_free_dict(d);
+ }
+}
+
+
+/// Unreference a dictionary
+///
+/// Decrements the reference count and frees dictionary when it becomes zero.
+///
+/// @param[in] d Dictionary to operate on.
+void tv_dict_unref(dict_T *const d)
+{
+ if (d != NULL && --d->dv_refcount <= 0) {
+ tv_dict_free(d);
+ }
+}
+
+//{{{2 Indexing/searching
+
+/// Find item in dictionary
+///
+/// @param[in] d Dictionary to check.
+/// @param[in] key Dictionary key.
+/// @param[in] len Key length. If negative, then strlen(key) is used.
+///
+/// @return found item or NULL if nothing was found.
+dictitem_T *tv_dict_find(const dict_T *const d, const char *const key,
+ const ptrdiff_t len)
+ FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (d == NULL) {
+ return NULL;
+ }
+ hashitem_T *const hi = (len < 0
+ ? hash_find(&d->dv_hashtab, (const char_u *)key)
+ : hash_find_len(&d->dv_hashtab, key, (size_t)len));
+ if (HASHITEM_EMPTY(hi)) {
+ return NULL;
+ }
+ return TV_DICT_HI2DI(hi);
+}
+
+/// Get a number item from a dictionary
+///
+/// Returns 0 if the entry does not exist.
+///
+/// @param[in] d Dictionary to get item from.
+/// @param[in] key Key to find in dictionary.
+///
+/// @return Dictionary item.
+varnumber_T tv_dict_get_number(const dict_T *const d, const char *const key)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ dictitem_T *const di = tv_dict_find(d, key, -1);
+ if (di == NULL) {
+ return 0;
+ }
+ return tv_get_number(&di->di_tv);
+}
+
+/// Get a string item from a dictionary
+///
+/// @param[in] d Dictionary to get item from.
+/// @param[in] key Dictionary key.
+/// @param[in] save If true, returned string will be placed in the allocated
+/// memory.
+///
+/// @return NULL if key does not exist, empty string in case of type error,
+/// string item value otherwise. If returned value is not NULL, it may
+/// be allocated depending on `save` argument.
+char *tv_dict_get_string(const dict_T *const d, const char *const key,
+ const bool save)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ static char numbuf[NUMBUFLEN];
+ const char *const s = tv_dict_get_string_buf(d, key, numbuf);
+ if (save && s != NULL) {
+ return xstrdup(s);
+ }
+ return (char *)s;
+}
+
+/// Get a string item from a dictionary
+///
+/// @param[in] d Dictionary to get item from.
+/// @param[in] key Dictionary key.
+/// @param[in] numbuf Numbuf for.
+///
+/// @return NULL if key does not exist, empty string in case of type error,
+/// string item value otherwise.
+const char *tv_dict_get_string_buf(const dict_T *const d, const char *const key,
+ char *const numbuf)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ const dictitem_T *const di = tv_dict_find(d, key, -1);
+ if (di == NULL) {
+ return NULL;
+ }
+ return tv_get_string_buf(&di->di_tv, numbuf);
+}
+
+/// Get a function from a dictionary
+///
+/// @param[in] d Dictionary to get callback from.
+/// @param[in] key Dictionary key.
+/// @param[in] key_len Key length, may be -1 to use strlen().
+/// @param[out] result The address where a pointer to the wanted callback
+/// will be left.
+///
+/// @return true/false on success/failure.
+bool tv_dict_get_callback(dict_T *const d,
+ const char *const key, const ptrdiff_t key_len,
+ Callback *const result)
+ FUNC_ATTR_NONNULL_ARG(2, 4) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ result->type = kCallbackNone;
+
+ dictitem_T *const di = tv_dict_find(d, key, key_len);
+
+ if (di == NULL) {
+ return true;
+ }
+
+ if (!tv_is_func(di->di_tv) && di->di_tv.v_type != VAR_STRING) {
+ emsgf(_("E6000: Argument is not a function or function name"));
+ return false;
+ }
+
+ typval_T tv;
+ tv_copy(&di->di_tv, &tv);
+ set_selfdict(&tv, d);
+ const bool res = callback_from_typval(result, &tv);
+ tv_clear(&tv);
+ return res;
+}
+
+//{{{2 dict_add*
+
+/// Add item to dictionary
+///
+/// @param[out] d Dictionary to add to.
+/// @param[in] item Item to add.
+///
+/// @return FAIL if key already exists.
+int tv_dict_add(dict_T *const d, dictitem_T *const item)
+ FUNC_ATTR_NONNULL_ALL
+{
+ return hash_add(&d->dv_hashtab, item->di_key);
+}
+
+/// Add a list entry to dictionary
+///
+/// @param[out] d Dictionary to add entry to.
+/// @param[in] key Key to add.
+/// @param[in] key_len Key length.
+/// @param list List to add. Will have reference count incremented.
+///
+/// @return OK in case of success, FAIL when key already exists.
+int tv_dict_add_list(dict_T *const d, const char *const key,
+ const size_t key_len, list_T *const list)
+ FUNC_ATTR_NONNULL_ALL
+{
+ dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
+
+ item->di_tv.v_lock = VAR_UNLOCKED;
+ item->di_tv.v_type = VAR_LIST;
+ item->di_tv.vval.v_list = list;
+ list->lv_refcount++;
+ if (tv_dict_add(d, item) == FAIL) {
+ tv_dict_item_free(item);
+ return FAIL;
+ }
+ return OK;
+}
+
+/// Add a dictionary entry to dictionary
+///
+/// @param[out] d Dictionary to add entry to.
+/// @param[in] key Key to add.
+/// @param[in] key_len Key length.
+/// @param dict Dictionary to add. Will have reference count incremented.
+///
+/// @return OK in case of success, FAIL when key already exists.
+int tv_dict_add_dict(dict_T *const d, const char *const key,
+ const size_t key_len, dict_T *const dict)
+ FUNC_ATTR_NONNULL_ALL
+{
+ dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
+
+ item->di_tv.v_lock = VAR_UNLOCKED;
+ item->di_tv.v_type = VAR_DICT;
+ item->di_tv.vval.v_dict = dict;
+ dict->dv_refcount++;
+ if (tv_dict_add(d, item) == FAIL) {
+ tv_dict_item_free(item);
+ return FAIL;
+ }
+ return OK;
+}
+
+/// Add a number entry to dictionary
+///
+/// @param[out] d Dictionary to add entry to.
+/// @param[in] key Key to add.
+/// @param[in] key_len Key length.
+/// @param[in] nr Number to add.
+///
+/// @return OK in case of success, FAIL when key already exists.
+int tv_dict_add_nr(dict_T *const d, const char *const key,
+ const size_t key_len, const varnumber_T nr)
+{
+ dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
+
+ item->di_tv.v_lock = VAR_UNLOCKED;
+ item->di_tv.v_type = VAR_NUMBER;
+ item->di_tv.vval.v_number = nr;
+ if (tv_dict_add(d, item) == FAIL) {
+ tv_dict_item_free(item);
+ return FAIL;
+ }
+ return OK;
+}
+
+/// Add a string entry to dictionary
+///
+/// @param[out] d Dictionary to add entry to.
+/// @param[in] key Key to add.
+/// @param[in] key_len Key length.
+/// @param[in] val String to add.
+///
+/// @return OK in case of success, FAIL when key already exists.
+int tv_dict_add_str(dict_T *const d,
+ const char *const key, const size_t key_len,
+ const char *const val)
+ FUNC_ATTR_NONNULL_ALL
+{
+ dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
+
+ item->di_tv.v_lock = VAR_UNLOCKED;
+ item->di_tv.v_type = VAR_STRING;
+ item->di_tv.vval.v_string = (char_u *)xstrdup(val);
+ if (tv_dict_add(d, item) == FAIL) {
+ tv_dict_item_free(item);
+ return FAIL;
+ }
+ return OK;
+}
+
+//{{{2 Operations on the whole dict
+
+/// Clear all the keys of a Dictionary. "d" remains a valid empty Dictionary.
+///
+/// @param d The Dictionary to clear
+void tv_dict_clear(dict_T *const d)
+ FUNC_ATTR_NONNULL_ALL
+{
+ hash_lock(&d->dv_hashtab);
+ assert(d->dv_hashtab.ht_locked > 0);
+
+ HASHTAB_ITER(&d->dv_hashtab, hi, {
+ tv_dict_item_free(TV_DICT_HI2DI(hi));
+ hash_remove(&d->dv_hashtab, hi);
+ });
+
+ hash_unlock(&d->dv_hashtab);
+}
+
+/// Extend dictionary with items from another dictionary
+///
+/// @param d1 Dictionary to extend.
+/// @param[in] d2 Dictionary to extend with.
+/// @param[in] action "error", "force", "keep":
+///
+/// e*, including "error": duplicate key gives an error.
+/// f*, including "force": duplicate d2 keys override d1.
+/// other, including "keep": duplicate d2 keys ignored.
+void tv_dict_extend(dict_T *const d1, dict_T *const d2,
+ const char *const action)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const bool watched = tv_dict_is_watched(d1);
+ const char *const arg_errmsg = _("extend() argument");
+ const size_t arg_errmsg_len = strlen(arg_errmsg);
+
+ TV_DICT_ITER(d2, di2, {
+ dictitem_T *const di1 = tv_dict_find(d1, (const char *)di2->di_key, -1);
+ if (d1->dv_scope != VAR_NO_SCOPE) {
+ // Disallow replacing a builtin function in l: and g:.
+ // Check the key to be valid when adding to any scope.
+ if (d1->dv_scope == VAR_DEF_SCOPE
+ && tv_is_func(di2->di_tv)
+ && !var_check_func_name((const char *)di2->di_key, di1 == NULL)) {
+ break;
+ }
+ if (!valid_varname((const char *)di2->di_key)) {
+ break;
+ }
+ }
+ if (di1 == NULL) {
+ dictitem_T *const new_di = tv_dict_item_copy(di2);
+ if (tv_dict_add(d1, new_di) == FAIL) {
+ tv_dict_item_free(new_di);
+ } else if (watched) {
+ tv_dict_watcher_notify(d1, (const char *)new_di->di_key, &new_di->di_tv,
+ NULL);
+ }
+ } else if (*action == 'e') {
+ emsgf(_("E737: Key already exists: %s"), di2->di_key);
+ break;
+ } else if (*action == 'f' && di2 != di1) {
+ typval_T oldtv;
+
+ if (tv_check_lock(di1->di_tv.v_lock, arg_errmsg, arg_errmsg_len)
+ || var_check_ro(di1->di_flags, arg_errmsg, arg_errmsg_len)) {
+ break;
+ }
+
+ if (watched) {
+ tv_copy(&di1->di_tv, &oldtv);
+ }
+
+ tv_clear(&di1->di_tv);
+ tv_copy(&di2->di_tv, &di1->di_tv);
+
+ if (watched) {
+ tv_dict_watcher_notify(d1, (const char *)di1->di_key, &di1->di_tv,
+ &oldtv);
+ tv_clear(&oldtv);
+ }
+ }
+ });
+}
+
+/// Compare two dictionaries
+///
+/// @param[in] d1 First dictionary.
+/// @param[in] d2 Second dictionary.
+/// @param[in] ic True if case is to be ignored.
+/// @param[in] recursive True when used recursively.
+bool tv_dict_equal(dict_T *const d1, dict_T *const d2,
+ const bool ic, const bool recursive)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (d1 == d2) {
+ return true;
+ }
+ if (d1 == NULL || d2 == NULL) {
+ return false;
+ }
+ if (tv_dict_len(d1) != tv_dict_len(d2)) {
+ return false;
+ }
+
+ TV_DICT_ITER(d1, di1, {
+ dictitem_T *const di2 = tv_dict_find(d2, (const char *)di1->di_key, -1);
+ if (di2 == NULL) {
+ return false;
+ }
+ if (!tv_equal(&di1->di_tv, &di2->di_tv, ic, recursive)) {
+ return false;
+ }
+ });
+ return true;
+}
+
+/// Make a copy of dictionary
+///
+/// @param[in] conv If non-NULL, then all internal strings will be converted.
+/// @param[in] orig Original dictionary to copy.
+/// @param[in] deep If false, then shallow copy will be done.
+/// @param[in] copyID See var_item_copy().
+///
+/// @return Copied dictionary. May be NULL in case original dictionary is NULL
+/// or some failure happens. The refcount of the new dictionary is set
+/// to 1.
+dict_T *tv_dict_copy(const vimconv_T *const conv,
+ dict_T *const orig,
+ const bool deep,
+ const int copyID)
+{
+ if (orig == NULL) {
+ return NULL;
+ }
+
+ dict_T *copy = tv_dict_alloc();
+ if (copyID != 0) {
+ orig->dv_copyID = copyID;
+ orig->dv_copydict = copy;
+ }
+ TV_DICT_ITER(orig, di, {
+ if (got_int) {
+ break;
+ }
+ dictitem_T *new_di;
+ if (conv == NULL || conv->vc_type == CONV_NONE) {
+ new_di = tv_dict_item_alloc((const char *)di->di_key);
+ } else {
+ size_t len = STRLEN(di->di_key);
+ char *const key = (char *)string_convert(conv, di->di_key, &len);
+ if (key == NULL) {
+ new_di = tv_dict_item_alloc_len((const char *)di->di_key, len);
+ } else {
+ new_di = tv_dict_item_alloc_len(key, len);
+ xfree(key);
+ }
+ }
+ if (deep) {
+ if (var_item_copy(conv, &di->di_tv, &new_di->di_tv, deep,
+ copyID) == FAIL) {
+ xfree(new_di);
+ break;
+ }
+ } else {
+ tv_copy(&di->di_tv, &new_di->di_tv);
+ }
+ if (tv_dict_add(copy, new_di) == FAIL) {
+ tv_dict_item_free(new_di);
+ break;
+ }
+ });
+
+ copy->dv_refcount++;
+ if (got_int) {
+ tv_dict_unref(copy);
+ copy = NULL;
+ }
+
+ return copy;
+}
+
+/// Set all existing keys in "dict" as read-only.
+///
+/// This does not protect against adding new keys to the Dictionary.
+///
+/// @param dict The dict whose keys should be frozen.
+void tv_dict_set_keys_readonly(dict_T *const dict)
+ FUNC_ATTR_NONNULL_ALL
+{
+ TV_DICT_ITER(dict, di, {
+ di->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX;
+ });
+}
+
+//{{{1 Generic typval operations
+//{{{2 Init/alloc/clear
+//{{{3 Alloc
+
+/// Allocate an empty list for a return value
+///
+/// Also sets reference count.
+///
+/// @param[out] ret_tv Structure where list is saved.
+///
+/// @return [allocated] pointer to the created list.
+list_T *tv_list_alloc_ret(typval_T *const ret_tv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC
+{
+ list_T *const l = tv_list_alloc();
+ ret_tv->vval.v_list = l;
+ ret_tv->v_type = VAR_LIST;
+ ret_tv->v_lock = VAR_UNLOCKED;
+ l->lv_refcount++;
+ return l;
+}
+
+/// Allocate an empty dictionary for a return value
+///
+/// Also sets reference count.
+///
+/// @param[out] ret_tv Structure where dictionary is saved.
+void tv_dict_alloc_ret(typval_T *const ret_tv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ dict_T *const d = tv_dict_alloc();
+ ret_tv->vval.v_dict = d;
+ ret_tv->v_type = VAR_DICT;
+ ret_tv->v_lock = VAR_UNLOCKED;
+ d->dv_refcount++;
+}
+
+//{{{3 Clear
+#define TYPVAL_ENCODE_ALLOW_SPECIALS false
+
+#define TYPVAL_ENCODE_CONV_NIL(tv) \
+ do { \
+ tv->vval.v_special = kSpecialVarFalse; \
+ tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \
+ TYPVAL_ENCODE_CONV_NIL(tv)
+
+#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \
+ do { \
+ (void)num; \
+ tv->vval.v_number = 0; \
+ tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num)
+
+#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \
+ do { \
+ tv->vval.v_float = 0; \
+ tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \
+ do { \
+ xfree(buf); \
+ tv->vval.v_string = NULL; \
+ tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len)
+
+#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type)
+
+static inline int _nothing_conv_func_start(typval_T *const tv,
+ char_u *const fun)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1)
+{
+ tv->v_lock = VAR_UNLOCKED;
+ if (tv->v_type == VAR_PARTIAL) {
+ partial_T *const pt_ = tv->vval.v_partial;
+ if (pt_ != NULL && pt_->pt_refcount > 1) {
+ pt_->pt_refcount--;
+ tv->vval.v_partial = NULL;
+ return OK;
+ }
+ } else {
+ func_unref(fun);
+ if ((const char *)fun != tv_empty_string) {
+ xfree(fun);
+ }
+ tv->vval.v_string = NULL;
+ }
+ return NOTDONE;
+}
+#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
+ do { \
+ if (_nothing_conv_func_start(tv, fun) != NOTDONE) { \
+ return OK; \
+ } \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len)
+#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len)
+
+static inline void _nothing_conv_func_end(typval_T *const tv, const int copyID)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
+{
+ if (tv->v_type == VAR_PARTIAL) {
+ partial_T *const pt = tv->vval.v_partial;
+ if (pt == NULL) {
+ return;
+ }
+ // Dictionary should already be freed by the time.
+ // If it was not freed then it is a part of the reference cycle.
+ assert(pt->pt_dict == NULL || pt->pt_dict->dv_copyID == copyID);
+ pt->pt_dict = NULL;
+ // As well as all arguments.
+ pt->pt_argc = 0;
+ assert(pt->pt_refcount <= 1);
+ partial_unref(pt);
+ tv->vval.v_partial = NULL;
+ assert(tv->v_lock == VAR_UNLOCKED);
+ }
+}
+#define TYPVAL_ENCODE_CONV_FUNC_END(tv) _nothing_conv_func_end(tv, copyID)
+
+#define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \
+ do { \
+ tv_list_unref(tv->vval.v_list); \
+ tv->vval.v_list = NULL; \
+ tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \
+ do { \
+ assert((void *)&dict != (void *)&TYPVAL_ENCODE_NODICT_VAR); \
+ tv_dict_unref((dict_T *)dict); \
+ *((dict_T **)&dict) = NULL; \
+ if (tv != NULL) { \
+ ((typval_T *)tv)->v_lock = VAR_UNLOCKED; \
+ } \
+ } while (0)
+
+static inline int _nothing_conv_real_list_after_start(
+ typval_T *const tv, MPConvStackVal *const mpsv)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ assert(tv != NULL);
+ tv->v_lock = VAR_UNLOCKED;
+ if (tv->vval.v_list->lv_refcount > 1) {
+ tv->vval.v_list->lv_refcount--;
+ tv->vval.v_list = NULL;
+ mpsv->data.l.li = NULL;
+ return OK;
+ }
+ return NOTDONE;
+}
+#define TYPVAL_ENCODE_CONV_LIST_START(tv, len)
+
+#define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) \
+ do { \
+ if (_nothing_conv_real_list_after_start(tv, &mpsv) != NOTDONE) { \
+ goto typval_encode_stop_converting_one_item; \
+ } \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv)
+
+static inline void _nothing_conv_list_end(typval_T *const tv)
+ FUNC_ATTR_ALWAYS_INLINE
+{
+ if (tv == NULL) {
+ return;
+ }
+ assert(tv->v_type == VAR_LIST);
+ list_T *const list = tv->vval.v_list;
+ tv_list_unref(list);
+ tv->vval.v_list = NULL;
+}
+#define TYPVAL_ENCODE_CONV_LIST_END(tv) _nothing_conv_list_end(tv)
+
+static inline int _nothing_conv_real_dict_after_start(
+ typval_T *const tv, dict_T **const dictp, const void *const nodictvar,
+ MPConvStackVal *const mpsv)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (tv != NULL) {
+ tv->v_lock = VAR_UNLOCKED;
+ }
+ if ((const void *)dictp != nodictvar && (*dictp)->dv_refcount > 1) {
+ (*dictp)->dv_refcount--;
+ *dictp = NULL;
+ mpsv->data.d.todo = 0;
+ return OK;
+ }
+ return NOTDONE;
+}
+#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len)
+
+#define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv) \
+ do { \
+ if (_nothing_conv_real_dict_after_start( \
+ tv, (dict_T **)&dict, (void *)&TYPVAL_ENCODE_NODICT_VAR, \
+ &mpsv) != NOTDONE) { \
+ goto typval_encode_stop_converting_one_item; \
+ } \
+ } while (0)
+
+#define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(tv, dict)
+#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict)
+#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict)
+
+static inline void _nothing_conv_dict_end(typval_T *const tv,
+ dict_T **const dictp,
+ const void *const nodictvar)
+ FUNC_ATTR_ALWAYS_INLINE
+{
+ if ((const void *)dictp != nodictvar) {
+ tv_dict_unref(*dictp);
+ *dictp = NULL;
+ }
+}
+#define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \
+ _nothing_conv_dict_end(tv, (dict_T **)&dict, \
+ (void *)&TYPVAL_ENCODE_NODICT_VAR)
+
+#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type)
+
+#define TYPVAL_ENCODE_SCOPE static
+#define TYPVAL_ENCODE_NAME nothing
+#define TYPVAL_ENCODE_FIRST_ARG_TYPE const void *const
+#define TYPVAL_ENCODE_FIRST_ARG_NAME ignored
+#include "nvim/eval/typval_encode.c.h"
+#undef TYPVAL_ENCODE_SCOPE
+#undef TYPVAL_ENCODE_NAME
+#undef TYPVAL_ENCODE_FIRST_ARG_TYPE
+#undef TYPVAL_ENCODE_FIRST_ARG_NAME
+
+#undef TYPVAL_ENCODE_ALLOW_SPECIALS
+#undef TYPVAL_ENCODE_CONV_NIL
+#undef TYPVAL_ENCODE_CONV_BOOL
+#undef TYPVAL_ENCODE_CONV_NUMBER
+#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER
+#undef TYPVAL_ENCODE_CONV_FLOAT
+#undef TYPVAL_ENCODE_CONV_STRING
+#undef TYPVAL_ENCODE_CONV_STR_STRING
+#undef TYPVAL_ENCODE_CONV_EXT_STRING
+#undef TYPVAL_ENCODE_CONV_FUNC_START
+#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS
+#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF
+#undef TYPVAL_ENCODE_CONV_FUNC_END
+#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
+#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
+#undef TYPVAL_ENCODE_CONV_LIST_START
+#undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START
+#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS
+#undef TYPVAL_ENCODE_CONV_LIST_END
+#undef TYPVAL_ENCODE_CONV_DICT_START
+#undef TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START
+#undef TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK
+#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY
+#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS
+#undef TYPVAL_ENCODE_CONV_DICT_END
+#undef TYPVAL_ENCODE_CONV_RECURSE
+
+/// Free memory for a variable value and set the value to NULL or 0
+///
+/// @param[in,out] tv Value to free.
+void tv_clear(typval_T *const tv)
+{
+ if (tv != NULL && tv->v_type != VAR_UNKNOWN) {
+ const int evn_ret = encode_vim_to_nothing(NULL, tv,
+ _("tv_clear() argument"));
+ (void)evn_ret;
+ assert(evn_ret == OK);
+ }
+}
+
+//{{{3 Free
+
+/// Free allocated VimL object and value stored inside
+///
+/// @param tv Object to free.
+void tv_free(typval_T *tv)
+{
+ if (tv != NULL) {
+ switch (tv->v_type) {
+ case VAR_PARTIAL: {
+ partial_unref(tv->vval.v_partial);
+ break;
+ }
+ case VAR_FUNC: {
+ func_unref(tv->vval.v_string);
+ // FALLTHROUGH
+ }
+ case VAR_STRING: {
+ xfree(tv->vval.v_string);
+ break;
+ }
+ case VAR_LIST: {
+ tv_list_unref(tv->vval.v_list);
+ break;
+ }
+ case VAR_DICT: {
+ tv_dict_unref(tv->vval.v_dict);
+ break;
+ }
+ case VAR_SPECIAL:
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_UNKNOWN: {
+ break;
+ }
+ }
+ xfree(tv);
+ }
+}
+
+//{{{3 Copy
+
+/// Copy typval from one location to another
+///
+/// When needed allocates string or increases reference count. Does not make
+/// a copy of a container, but copies its reference!
+///
+/// It is OK for `from` and `to` to point to the same location; this is used to
+/// make a copy later.
+///
+/// @param[in] from Location to copy from.
+/// @param[out] to Location to copy to.
+void tv_copy(typval_T *const from, typval_T *const to)
+{
+ to->v_type = from->v_type;
+ to->v_lock = VAR_UNLOCKED;
+ memmove(&to->vval, &from->vval, sizeof(to->vval));
+ switch (from->v_type) {
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_SPECIAL: {
+ break;
+ }
+ case VAR_STRING:
+ case VAR_FUNC: {
+ if (from->vval.v_string != NULL) {
+ to->vval.v_string = vim_strsave(from->vval.v_string);
+ if (from->v_type == VAR_FUNC) {
+ func_ref(to->vval.v_string);
+ }
+ }
+ break;
+ }
+ case VAR_PARTIAL: {
+ if (to->vval.v_partial != NULL) {
+ to->vval.v_partial->pt_refcount++;
+ }
+ break;
+ }
+ case VAR_LIST: {
+ if (from->vval.v_list != NULL) {
+ to->vval.v_list->lv_refcount++;
+ }
+ break;
+ }
+ case VAR_DICT: {
+ if (from->vval.v_dict != NULL) {
+ to->vval.v_dict->dv_refcount++;
+ }
+ break;
+ }
+ case VAR_UNKNOWN: {
+ emsgf(_(e_intern2), "tv_copy(UNKNOWN)");
+ break;
+ }
+ }
+}
+
+//{{{2 Locks
+
+/// Lock or unlock an item
+///
+/// @param[out] tv Item to (un)lock.
+/// @param[in] deep Levels to (un)lock, -1 to (un)lock everything.
+/// @param[in] lock True if it is needed to lock an item, false to unlock.
+void tv_item_lock(typval_T *const tv, const int deep, const bool lock)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // TODO(ZyX-I): Make this not recursive
+ static int recurse = 0;
+
+ if (recurse >= DICT_MAXNEST) {
+ emsgf(_("E743: variable nested too deep for (un)lock"));
+ return;
+ }
+ if (deep == 0) {
+ return;
+ }
+ recurse++;
+
+ // lock/unlock the item itself
+#define CHANGE_LOCK(lock, var) \
+ do { \
+ var = ((VarLockStatus[]) { \
+ [VAR_UNLOCKED] = (lock ? VAR_LOCKED : VAR_UNLOCKED), \
+ [VAR_LOCKED] = (lock ? VAR_LOCKED : VAR_UNLOCKED), \
+ [VAR_FIXED] = VAR_FIXED, \
+ })[var]; \
+ } while (0)
+ CHANGE_LOCK(lock, tv->v_lock);
+
+ switch (tv->v_type) {
+ case VAR_LIST: {
+ list_T *const l = tv->vval.v_list;
+ if (l != NULL) {
+ CHANGE_LOCK(lock, l->lv_lock);
+ if (deep < 0 || deep > 1) {
+ // Recursive: lock/unlock the items the List contains.
+ for (listitem_T *li = l->lv_first; li != NULL; li = li->li_next) {
+ tv_item_lock(&li->li_tv, deep - 1, lock);
+ }
+ }
+ }
+ break;
+ }
+ case VAR_DICT: {
+ dict_T *const d = tv->vval.v_dict;
+ if (d != NULL) {
+ CHANGE_LOCK(lock, d->dv_lock);
+ if (deep < 0 || deep > 1) {
+ // recursive: lock/unlock the items the List contains
+ TV_DICT_ITER(d, di, {
+ tv_item_lock(&di->di_tv, deep - 1, lock);
+ });
+ }
+ }
+ break;
+ }
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_STRING:
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_SPECIAL: {
+ break;
+ }
+ case VAR_UNKNOWN: {
+ assert(false);
+ }
+ }
+#undef CHANGE_LOCK
+ recurse--;
+}
+
+/// Check whether VimL value is locked itself or refers to a locked container
+///
+/// @param[in] tv Value to check.
+///
+/// @return True if value is locked, false otherwise.
+bool tv_islocked(const typval_T *const tv)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+{
+ return ((tv->v_lock == VAR_LOCKED)
+ || (tv->v_type == VAR_LIST
+ && tv->vval.v_list != NULL
+ && (tv->vval.v_list->lv_lock == VAR_LOCKED))
+ || (tv->v_type == VAR_DICT
+ && tv->vval.v_dict != NULL
+ && (tv->vval.v_dict->dv_lock == VAR_LOCKED)));
+}
+
+/// Return true if typval is locked
+///
+/// Also gives an error message when typval is locked.
+///
+/// @param[in] lock Lock status.
+/// @param[in] name Variable name, used in the error message.
+/// @param[in] name_len Variable name length.
+///
+/// @return true if variable is locked, false otherwise.
+bool tv_check_lock(const VarLockStatus lock, const char *const name,
+ const size_t name_len)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ const char *error_message = NULL;
+ switch (lock) {
+ case VAR_UNLOCKED: {
+ return false;
+ }
+ case VAR_LOCKED: {
+ error_message = N_("E741: Value is locked: %.*s");
+ break;
+ }
+ case VAR_FIXED: {
+ error_message = N_("E742: Cannot change value of %.*s");
+ break;
+ }
+ }
+ assert(error_message != NULL);
+
+ const char *const unknown_name = _("Unknown");
+
+ emsgf(_(error_message), (name != NULL ? name_len : strlen(unknown_name)),
+ (name != NULL ? name : unknown_name));
+
+ return true;
+}
+
+//{{{2 Comparison
+
+static int tv_equal_recurse_limit;
+
+/// Compare two VimL values
+///
+/// Like "==", but strings and numbers are different, as well as floats and
+/// numbers.
+///
+/// @warning Too nested structures may be considered equal even if they are not.
+///
+/// @param[in] tv1 First value to compare.
+/// @param[in] tv2 Second value to compare.
+/// @param[in] ic True if case is to be ignored.
+/// @param[in] recursive True when used recursively.
+///
+/// @return true if values are equal.
+bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic,
+ const bool recursive)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+{
+ // TODO(ZyX-I): Make this not recursive
+ static int recursive_cnt = 0; // Catch recursive loops.
+
+ if (!(tv_is_func(*tv1) && tv_is_func(*tv2)) && tv1->v_type != tv2->v_type) {
+ return false;
+ }
+
+ // Catch lists and dicts that have an endless loop by limiting
+ // recursiveness to a limit. We guess they are equal then.
+ // A fixed limit has the problem of still taking an awful long time.
+ // Reduce the limit every time running into it. That should work fine for
+ // deeply linked structures that are not recursively linked and catch
+ // recursiveness quickly.
+ if (!recursive) {
+ tv_equal_recurse_limit = 1000;
+ }
+ if (recursive_cnt >= tv_equal_recurse_limit) {
+ tv_equal_recurse_limit--;
+ return true;
+ }
+
+ switch (tv1->v_type) {
+ case VAR_LIST: {
+ recursive_cnt++;
+ const bool r = tv_list_equal(tv1->vval.v_list, tv2->vval.v_list, ic,
+ true);
+ recursive_cnt--;
+ return r;
+ }
+ case VAR_DICT: {
+ recursive_cnt++;
+ const bool r = tv_dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic,
+ true);
+ recursive_cnt--;
+ return r;
+ }
+ case VAR_PARTIAL:
+ case VAR_FUNC: {
+ if ((tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial == NULL)
+ || (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial == NULL)) {
+ return false;
+ }
+ recursive_cnt++;
+ const bool r = func_equal(tv1, tv2, ic);
+ recursive_cnt--;
+ return r;
+ }
+ case VAR_NUMBER: {
+ return tv1->vval.v_number == tv2->vval.v_number;
+ }
+ case VAR_FLOAT: {
+ return tv1->vval.v_float == tv2->vval.v_float;
+ }
+ case VAR_STRING: {
+ char buf1[NUMBUFLEN];
+ char buf2[NUMBUFLEN];
+ const char *s1 = tv_get_string_buf(tv1, buf1);
+ const char *s2 = tv_get_string_buf(tv2, buf2);
+ return mb_strcmp_ic((bool)ic, s1, s2) == 0;
+ }
+ case VAR_SPECIAL: {
+ return tv1->vval.v_special == tv2->vval.v_special;
+ }
+ case VAR_UNKNOWN: {
+ // VAR_UNKNOWN can be the result of an invalid expression, let’s say it
+ // does not equal anything, not even self.
+ return false;
+ }
+ }
+
+ assert(false);
+ return false;
+}
+
+//{{{2 Type checks
+
+/// Check that given value is a number or string
+///
+/// Error messages are compatible with tv_get_number() previously used for the
+/// same purpose in buf*() functions. Special values are not accepted (previous
+/// behaviour: silently fail to find buffer).
+///
+/// @param[in] tv Value to check.
+///
+/// @return true if everything is OK, false otherwise.
+bool tv_check_str_or_nr(const typval_T *const tv)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+{
+ switch (tv->v_type) {
+ case VAR_NUMBER:
+ case VAR_STRING: {
+ return true;
+ }
+ case VAR_FLOAT: {
+ emsgf(_("E805: Expected a Number or a String, Float found"));
+ return false;
+ }
+ case VAR_PARTIAL:
+ case VAR_FUNC: {
+ emsgf(_("E703: Expected a Number or a String, Funcref found"));
+ return false;
+ }
+ case VAR_LIST: {
+ emsgf(_("E745: Expected a Number or a String, List found"));
+ return false;
+ }
+ case VAR_DICT: {
+ emsgf(_("E728: Expected a Number or a String, Dictionary found"));
+ return false;
+ }
+ case VAR_SPECIAL: {
+ emsgf(_("E5300: Expected a Number or a String"));
+ return false;
+ }
+ case VAR_UNKNOWN: {
+ emsgf(_(e_intern2), "tv_check_str_or_nr(UNKNOWN)");
+ return false;
+ }
+ }
+ assert(false);
+ return false;
+}
+
+#define FUNC_ERROR "E703: Using a Funcref as a Number"
+
+static const char *const num_errors[] = {
+ [VAR_PARTIAL]=N_(FUNC_ERROR),
+ [VAR_FUNC]=N_(FUNC_ERROR),
+ [VAR_LIST]=N_("E745: Using a List as a Number"),
+ [VAR_DICT]=N_("E728: Using a Dictionary as a Number"),
+ [VAR_FLOAT]=N_("E805: Using a Float as a Number"),
+ [VAR_UNKNOWN]=N_("E685: using an invalid value as a Number"),
+};
+
+#undef FUNC_ERROR
+
+/// Check that given value is a number or can be converted to it
+///
+/// Error messages are compatible with tv_get_number_chk() previously used for
+/// the same purpose.
+///
+/// @param[in] tv Value to check.
+///
+/// @return true if everything is OK, false otherwise.
+bool tv_check_num(const typval_T *const tv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ switch (tv->v_type) {
+ case VAR_NUMBER:
+ case VAR_SPECIAL:
+ case VAR_STRING: {
+ return true;
+ }
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_LIST:
+ case VAR_DICT:
+ case VAR_FLOAT:
+ case VAR_UNKNOWN: {
+ emsgf(_(num_errors[tv->v_type]));
+ return false;
+ }
+ }
+ assert(false);
+ return false;
+}
+
+#define FUNC_ERROR "E729: using Funcref as a String"
+
+static const char *const str_errors[] = {
+ [VAR_PARTIAL]=N_(FUNC_ERROR),
+ [VAR_FUNC]=N_(FUNC_ERROR),
+ [VAR_LIST]=N_("E730: using List as a String"),
+ [VAR_DICT]=N_("E731: using Dictionary as a String"),
+ [VAR_FLOAT]=((const char *)e_float_as_string),
+ [VAR_UNKNOWN]=N_("E908: using an invalid value as a String"),
+};
+
+#undef FUNC_ERROR
+
+/// Check that given value is a string or can be converted to it
+///
+/// Error messages are compatible with tv_get_string_chk() previously used for
+/// the same purpose.
+///
+/// @param[in] tv Value to check.
+///
+/// @return true if everything is OK, false otherwise.
+bool tv_check_str(const typval_T *const tv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ switch (tv->v_type) {
+ case VAR_NUMBER:
+ case VAR_SPECIAL:
+ case VAR_STRING: {
+ return true;
+ }
+ case VAR_PARTIAL:
+ case VAR_FUNC:
+ case VAR_LIST:
+ case VAR_DICT:
+ case VAR_FLOAT:
+ case VAR_UNKNOWN: {
+ emsgf(_(str_errors[tv->v_type]));
+ return false;
+ }
+ }
+ assert(false);
+ return false;
+}
+
+//{{{2 Get
+
+/// Get the number value of a VimL object
+///
+/// @note Use tv_get_number_chk() if you need to determine whether there was an
+/// error.
+///
+/// @param[in] tv Object to get value from.
+///
+/// @return Number value: vim_str2nr() output for VAR_STRING objects, value
+/// for VAR_NUMBER objects, -1 for other types.
+varnumber_T tv_get_number(const typval_T *const tv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ bool error = false;
+ return tv_get_number_chk(tv, &error);
+}
+
+/// Get the number value of a VimL object
+///
+/// @param[in] tv Object to get value from.
+/// @param[out] ret_error If type error occurred then `true` will be written
+/// to this location. Otherwise it is not touched.
+///
+/// @note Needs to be initialized to `false` to be
+/// useful.
+///
+/// @return Number value: vim_str2nr() output for VAR_STRING objects, value
+/// for VAR_NUMBER objects, -1 (ret_error == NULL) or 0 (otherwise) for
+/// other types.
+varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
+{
+ switch (tv->v_type) {
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_LIST:
+ case VAR_DICT:
+ case VAR_FLOAT: {
+ emsgf(_(num_errors[tv->v_type]));
+ break;
+ }
+ case VAR_NUMBER: {
+ return tv->vval.v_number;
+ }
+ case VAR_STRING: {
+ varnumber_T n = 0;
+ if (tv->vval.v_string != NULL) {
+ long nr;
+ vim_str2nr(tv->vval.v_string, NULL, NULL, STR2NR_ALL, &nr, NULL, 0);
+ n = (varnumber_T)nr;
+ }
+ return n;
+ }
+ case VAR_SPECIAL: {
+ switch (tv->vval.v_special) {
+ case kSpecialVarTrue: {
+ return 1;
+ }
+ case kSpecialVarFalse:
+ case kSpecialVarNull: {
+ return 0;
+ }
+ }
+ break;
+ }
+ case VAR_UNKNOWN: {
+ emsgf(_(e_intern2), "tv_get_number(UNKNOWN)");
+ break;
+ }
+ }
+ if (ret_error != NULL) {
+ *ret_error = true;
+ }
+ return (ret_error == NULL ? -1 : 0);
+}
+
+/// Get the line number from VimL object
+///
+/// @param[in] tv Object to get value from. Is expected to be a number or
+/// a special string like ".", "$", … (works with current buffer
+/// only).
+///
+/// @return Line number or -1 or 0.
+linenr_T tv_get_lnum(const typval_T *const tv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ linenr_T lnum = tv_get_number_chk(tv, NULL);
+ if (lnum == 0) { // No valid number, try using same function as line() does.
+ int fnum;
+ pos_T *const fp = var2fpos(tv, true, &fnum);
+ if (fp != NULL) {
+ lnum = fp->lnum;
+ }
+ }
+ return lnum;
+}
+
+/// Get the floating-point value of a VimL object
+///
+/// Raises an error if object is not number or floating-point.
+///
+/// @param[in] tv Object to get value of.
+///
+/// @return Floating-point value of the variable or zero.
+float_T tv_get_float(const typval_T *const tv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ switch (tv->v_type) {
+ case VAR_NUMBER: {
+ return (float_T)(tv->vval.v_number);
+ }
+ case VAR_FLOAT: {
+ return tv->vval.v_float;
+ }
+ case VAR_PARTIAL:
+ case VAR_FUNC: {
+ emsgf(_("E891: Using a Funcref as a Float"));
+ break;
+ }
+ case VAR_STRING: {
+ emsgf(_("E892: Using a String as a Float"));
+ break;
+ }
+ case VAR_LIST: {
+ emsgf(_("E893: Using a List as a Float"));
+ break;
+ }
+ case VAR_DICT: {
+ emsgf(_("E894: Using a Dictionary as a Float"));
+ break;
+ }
+ case VAR_SPECIAL: {
+ emsgf(_("E907: Using a special value as a Float"));
+ break;
+ }
+ case VAR_UNKNOWN: {
+ emsgf(_(e_intern2), "tv_get_float(UNKNOWN)");
+ break;
+ }
+ }
+ return 0;
+}
+
+/// Get the string value of a VimL object
+///
+/// @param[in] tv Object to get value of.
+/// @param buf Buffer used to hold numbers and special variables converted to
+/// string. When function encounters one of these stringified value
+/// will be written to buf and buf will be returned.
+///
+/// Buffer must have NUMBUFLEN size.
+///
+/// @return Object value if it is VAR_STRING object, number converted to
+/// a string for VAR_NUMBER, v: variable name for VAR_SPECIAL or NULL.
+const char *tv_get_string_buf_chk(const typval_T *const tv, char *const buf)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ switch (tv->v_type) {
+ case VAR_NUMBER: {
+ snprintf(buf, NUMBUFLEN, "%" PRIdVARNUMBER, tv->vval.v_number);
+ return buf;
+ }
+ case VAR_STRING: {
+ if (tv->vval.v_string != NULL) {
+ return (const char *)tv->vval.v_string;
+ }
+ return "";
+ }
+ case VAR_SPECIAL: {
+ STRCPY(buf, encode_special_var_names[tv->vval.v_special]);
+ return buf;
+ }
+ case VAR_PARTIAL:
+ case VAR_FUNC:
+ case VAR_LIST:
+ case VAR_DICT:
+ case VAR_FLOAT:
+ case VAR_UNKNOWN: {
+ emsgf(_(str_errors[tv->v_type]));
+ return false;
+ }
+ }
+ return NULL;
+}
+
+/// Get the string value of a VimL object
+///
+/// @warning For number and special values it uses a single, static buffer. It
+/// may be used only once, next call to get_tv_string may reuse it. Use
+/// tv_get_string_buf() if you need to use tv_get_string() output after
+/// calling it again.
+///
+/// @param[in] tv Object to get value of.
+///
+/// @return Object value if it is VAR_STRING object, number converted to
+/// a string for VAR_NUMBER, v: variable name for VAR_SPECIAL or NULL.
+const char *tv_get_string_chk(const typval_T *const tv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ static char mybuf[NUMBUFLEN];
+
+ return tv_get_string_buf_chk(tv, mybuf);
+}
+
+/// Get the string value of a VimL object
+///
+/// @warning For number and special values it uses a single, static buffer. It
+/// may be used only once, next call to get_tv_string may reuse it. Use
+/// tv_get_string_buf() if you need to use tv_get_string() output after
+/// calling it again.
+///
+/// @note tv_get_string_chk() and tv_get_string_buf_chk() are similar, but
+/// return NULL on error.
+///
+/// @param[in] tv Object to get value of.
+///
+/// @return Object value if it is VAR_STRING object, number converted to
+/// a string for VAR_NUMBER, v: variable name for VAR_SPECIAL or empty
+/// string.
+const char *tv_get_string(const typval_T *const tv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ static char mybuf[NUMBUFLEN];
+ return tv_get_string_buf((typval_T *)tv, mybuf);
+}
+
+/// Get the string value of a VimL object
+///
+/// @note tv_get_string_chk() and tv_get_string_buf_chk() are similar, but
+/// return NULL on error.
+///
+/// @param[in] tv Object to get value of.
+/// @param buf Buffer used to hold numbers and special variables converted to
+/// string. When function encounters one of these stringified value
+/// will be written to buf and buf will be returned.
+///
+/// Buffer must have NUMBUFLEN size.
+///
+/// @return Object value if it is VAR_STRING object, number converted to
+/// a string for VAR_NUMBER, v: variable name for VAR_SPECIAL or empty
+/// string.
+const char *tv_get_string_buf(const typval_T *const tv, char *const buf)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ const char *const res = (const char *)tv_get_string_buf_chk(tv, buf);
+
+ return res != NULL ? res : "";
+}
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
new file mode 100644
index 0000000000..7eab22bc12
--- /dev/null
+++ b/src/nvim/eval/typval.h
@@ -0,0 +1,429 @@
+#ifndef NVIM_EVAL_TYPVAL_H
+#define NVIM_EVAL_TYPVAL_H
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "nvim/types.h"
+#include "nvim/hashtab.h"
+#include "nvim/garray.h"
+#include "nvim/mbyte.h"
+#include "nvim/func_attr.h"
+#include "nvim/lib/queue.h"
+#include "nvim/profile.h" // for proftime_T
+#include "nvim/pos.h" // for linenr_T
+#include "nvim/gettext.h"
+#include "nvim/message.h"
+
+/// Type used for VimL VAR_NUMBER values
+typedef int varnumber_T;
+
+/// Type used for VimL VAR_FLOAT values
+typedef double float_T;
+
+/// Maximal possible value of varnumber_T variable
+#define VARNUMBER_MAX INT_MAX
+
+/// Mimimal possible value of varnumber_T variable
+#define VARNUMBER_MIN INT_MIN
+#define PRIdVARNUMBER "d"
+
+/// %d printf format specifier for varnumber_T
+#define PRIdVARNUMBER "d"
+
+typedef struct listvar_S list_T;
+typedef struct dictvar_S dict_T;
+typedef struct partial_S partial_T;
+
+typedef struct ufunc ufunc_T;
+
+typedef enum {
+ kCallbackNone,
+ kCallbackFuncref,
+ kCallbackPartial,
+} CallbackType;
+
+typedef struct {
+ union {
+ char_u *funcref;
+ partial_T *partial;
+ } data;
+ CallbackType type;
+} Callback;
+#define CALLBACK_NONE ((Callback){ .type = kCallbackNone })
+
+/// Structure holding dictionary watcher
+typedef struct dict_watcher {
+ Callback callback;
+ char *key_pattern;
+ size_t key_pattern_len;
+ QUEUE node;
+ bool busy; // prevent recursion if the dict is changed in the callback
+} DictWatcher;
+
+/// Special variable values
+typedef enum {
+ kSpecialVarFalse, ///< v:false
+ kSpecialVarTrue, ///< v:true
+ kSpecialVarNull, ///< v:null
+} SpecialVarValue;
+
+/// Variable lock status for typval_T.v_lock
+typedef enum {
+ VAR_UNLOCKED = 0, ///< Not locked.
+ VAR_LOCKED = 1, ///< User lock, can be unlocked.
+ VAR_FIXED = 2, ///< Locked forever.
+} VarLockStatus;
+
+/// VimL variable types, for use in typval_T.v_type
+typedef enum {
+ VAR_UNKNOWN = 0, ///< Unknown (unspecified) value.
+ VAR_NUMBER, ///< Number, .v_number is used.
+ VAR_STRING, ///< String, .v_string is used.
+ VAR_FUNC, ///< Function reference, .v_string is used as function name.
+ VAR_LIST, ///< List, .v_list is used.
+ VAR_DICT, ///< Dictionary, .v_dict is used.
+ VAR_FLOAT, ///< Floating-point value, .v_float is used.
+ VAR_SPECIAL, ///< Special value (true, false, null), .v_special
+ ///< is used.
+ VAR_PARTIAL, ///< Partial, .v_partial is used.
+} VarType;
+
+/// Structure that holds an internal variable value
+typedef struct {
+ VarType v_type; ///< Variable type.
+ VarLockStatus v_lock; ///< Variable lock status.
+ union typval_vval_union {
+ varnumber_T v_number; ///< Number, for VAR_NUMBER.
+ SpecialVarValue v_special; ///< Special value, for VAR_SPECIAL.
+ float_T v_float; ///< Floating-point number, for VAR_FLOAT.
+ char_u *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL.
+ list_T *v_list; ///< List for VAR_LIST, can be NULL.
+ dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL.
+ partial_T *v_partial; ///< Closure: function with args.
+ } vval; ///< Actual value.
+} typval_T;
+
+/// Values for (struct dictvar_S).dv_scope
+typedef enum {
+ VAR_NO_SCOPE = 0, ///< Not a scope dictionary.
+ VAR_SCOPE = 1, ///< Scope dictionary which requires prefix (a:, v:, …).
+ VAR_DEF_SCOPE = 2, ///< Scope dictionary which may be accessed without prefix
+ ///< (l:, g:).
+} ScopeType;
+
+/// Structure to hold an item of a list
+typedef struct listitem_S listitem_T;
+
+struct listitem_S {
+ listitem_T *li_next; ///< Next item in list.
+ listitem_T *li_prev; ///< Previous item in list.
+ typval_T li_tv; ///< Item value.
+};
+
+/// Structure used by those that are using an item in a list
+typedef struct listwatch_S listwatch_T;
+
+struct listwatch_S {
+ listitem_T *lw_item; ///< Item being watched.
+ listwatch_T *lw_next; ///< Next watcher.
+};
+
+/// Structure to hold info about a list
+struct listvar_S {
+ listitem_T *lv_first; ///< First item, NULL if none.
+ listitem_T *lv_last; ///< Last item, NULL if none.
+ int lv_refcount; ///< Reference count.
+ int lv_len; ///< Number of items.
+ listwatch_T *lv_watch; ///< First watcher, NULL if none.
+ int lv_idx; ///< Index of a cached item, used for optimising repeated l[idx].
+ listitem_T *lv_idx_item; ///< When not NULL item at index "lv_idx".
+ int lv_copyID; ///< ID used by deepcopy().
+ list_T *lv_copylist; ///< Copied list used by deepcopy().
+ VarLockStatus lv_lock; ///< Zero, VAR_LOCKED, VAR_FIXED.
+ list_T *lv_used_next; ///< next list in used lists list.
+ list_T *lv_used_prev; ///< Previous list in used lists list.
+};
+
+// Static list with 10 items. Use init_static_list() to initialize.
+typedef struct {
+ list_T sl_list; // must be first
+ listitem_T sl_items[10];
+} staticList10_T;
+
+// Structure to hold an item of a Dictionary.
+// Also used for a variable.
+// The key is copied into "di_key" to avoid an extra alloc/free for it.
+struct dictitem_S {
+ typval_T di_tv; ///< type and value of the variable
+ char_u di_flags; ///< flags (only used for variable)
+ char_u di_key[1]; ///< key (actually longer!)
+};
+
+#define TV_DICTITEM_STRUCT(KEY_LEN) \
+ struct { \
+ typval_T di_tv; /* Structure that holds scope dictionary itself. */ \
+ uint8_t di_flags; /* Flags. */ \
+ char_u di_key[KEY_LEN]; /* Key value. */ \
+ }
+
+/// Structure to hold a scope dictionary
+///
+/// @warning Must be compatible with dictitem_T.
+///
+/// For use in find_var_in_ht to pretend that it found dictionary item when it
+/// finds scope dictionary.
+typedef TV_DICTITEM_STRUCT(1) ScopeDictDictItem;
+
+/// Structure to hold an item of a Dictionary
+///
+/// @warning Must be compatible with ScopeDictDictItem.
+///
+/// Also used for a variable.
+typedef TV_DICTITEM_STRUCT() dictitem_T;
+
+/// Flags for dictitem_T.di_flags
+typedef enum {
+ DI_FLAGS_RO = 1, ///< Read-only value
+ DI_FLAGS_RO_SBX = 2, ///< Value, read-only in the sandbox
+ DI_FLAGS_FIX = 4, ///< Fixed value: cannot be :unlet or remove()d.
+ DI_FLAGS_LOCK = 8, ///< Locked value.
+ DI_FLAGS_ALLOC = 16, ///< Separately allocated.
+} DictItemFlags;
+
+/// Structure representing a Dictionary
+struct dictvar_S {
+ VarLockStatus dv_lock; ///< Whole dictionary lock status.
+ ScopeType dv_scope; ///< Non-zero (#VAR_SCOPE, #VAR_DEF_SCOPE) if
+ ///< dictionary represents a scope (i.e. g:, l: …).
+ int dv_refcount; ///< Reference count.
+ int dv_copyID; ///< ID used when recursivery traversing a value.
+ hashtab_T dv_hashtab; ///< Hashtab containing all items.
+ dict_T *dv_copydict; ///< Copied dict used by deepcopy().
+ dict_T *dv_used_next; ///< Next dictionary in used dictionaries list.
+ dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list.
+ QUEUE watchers; ///< Dictionary key watchers set by user code.
+};
+
+/// Type used for script ID
+typedef int scid_T;
+/// Format argument for scid_T
+#define PRIdSCID "d"
+
+// Structure to hold info for a function that is currently being executed.
+typedef struct funccall_S funccall_T;
+
+/// Structure to hold info for a user function.
+struct ufunc {
+ int uf_varargs; ///< variable nr of arguments
+ int uf_flags;
+ int uf_calls; ///< nr of active calls
+ bool uf_cleared; ///< func_clear() was already called
+ garray_T uf_args; ///< arguments
+ garray_T uf_lines; ///< function lines
+ int uf_profiling; ///< true when func is being profiled
+ // Profiling the function as a whole.
+ int uf_tm_count; ///< nr of calls
+ proftime_T uf_tm_total; ///< time spent in function + children
+ proftime_T uf_tm_self; ///< time spent in function itself
+ proftime_T uf_tm_children; ///< time spent in children this call
+ // Profiling the function per line.
+ int *uf_tml_count; ///< nr of times line was executed
+ proftime_T *uf_tml_total; ///< time spent in a line + children
+ proftime_T *uf_tml_self; ///< time spent in a line itself
+ proftime_T uf_tml_start; ///< start time for current line
+ proftime_T uf_tml_children; ///< time spent in children for this line
+ proftime_T uf_tml_wait; ///< start wait time for current line
+ int uf_tml_idx; ///< index of line being timed; -1 if none
+ int uf_tml_execed; ///< line being timed was executed
+ scid_T uf_script_ID; ///< ID of script where function was defined,
+ ///< used for s: variables
+ int uf_refcount; ///< reference count, see func_name_refcount()
+ funccall_T *uf_scoped; ///< l: local variables for closure
+ char_u uf_name[1]; ///< name of function (actually longer); can
+ ///< start with <SNR>123_ (<SNR> is K_SPECIAL
+ ///< KS_EXTRA KE_SNR)
+};
+
+/// Maximum number of function arguments
+#define MAX_FUNC_ARGS 20
+
+struct partial_S {
+ int pt_refcount; ///< Reference count.
+ char_u *pt_name; ///< Function name; when NULL use pt_func->name.
+ ufunc_T *pt_func; ///< Function pointer; when NULL lookup function with
+ ///< pt_name.
+ bool pt_auto; ///< When true the partial was created by using dict.member
+ ///< in handle_subscript().
+ int pt_argc; ///< Number of arguments.
+ typval_T *pt_argv; ///< Arguments in allocated array.
+ dict_T *pt_dict; ///< Dict for "self".
+};
+
+/// Structure used for explicit stack while garbage collecting hash tables
+typedef struct ht_stack_S {
+ hashtab_T *ht;
+ struct ht_stack_S *prev;
+} ht_stack_T;
+
+/// Structure used for explicit stack while garbage collecting lists
+typedef struct list_stack_S {
+ list_T *list;
+ struct list_stack_S *prev;
+} list_stack_T;
+
+// In a hashtab item "hi_key" points to "di_key" in a dictitem.
+// This avoids adding a pointer to the hashtab item.
+
+/// Convert a hashitem pointer to a dictitem pointer
+#define TV_DICT_HI2DI(hi) \
+ ((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key)))
+
+static inline long tv_list_len(const list_T *const l)
+ REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
+
+/// Get the number of items in a list
+///
+/// @param[in] l List to check.
+static inline long tv_list_len(const list_T *const l)
+{
+ if (l == NULL) {
+ return 0;
+ }
+ return l->lv_len;
+}
+
+static inline long tv_dict_len(const dict_T *const d)
+ REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
+
+/// Get the number of items in a Dictionary
+///
+/// @param[in] d Dictionary to check.
+static inline long tv_dict_len(const dict_T *const d)
+{
+ if (d == NULL) {
+ return 0L;
+ }
+ return (long)d->dv_hashtab.ht_used;
+}
+
+static inline bool tv_dict_is_watched(const dict_T *const d)
+ REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
+
+/// Check if dictionary is watched
+///
+/// @param[in] d Dictionary to check.
+///
+/// @return true if there is at least one watcher.
+static inline bool tv_dict_is_watched(const dict_T *const d)
+{
+ return d && !QUEUE_EMPTY(&d->watchers);
+}
+
+/// Initialize VimL object
+///
+/// Initializes to unlocked VAR_UNKNOWN object.
+///
+/// @param[out] tv Object to initialize.
+static inline void tv_init(typval_T *const tv)
+{
+ if (tv != NULL) {
+ memset(tv, 0, sizeof(*tv));
+ }
+}
+
+#define TV_INITIAL_VALUE \
+ ((typval_T) { \
+ .v_type = VAR_UNKNOWN, \
+ .v_lock = VAR_UNLOCKED, \
+ })
+
+/// Empty string
+///
+/// Needed for hack which allows not allocating empty string and still not
+/// crashing when freeing it.
+extern const char *const tv_empty_string;
+
+/// Specifies that free_unref_items() function has (not) been entered
+extern bool tv_in_free_unref_items;
+
+/// Iterate over a dictionary
+///
+/// @param[in] d Dictionary to iterate over.
+/// @param di Name of the variable with current dictitem_T entry.
+/// @param code Cycle body.
+#define TV_DICT_ITER(d, di, code) \
+ HASHTAB_ITER(&(d)->dv_hashtab, di##hi_, { \
+ { \
+ dictitem_T *const di = TV_DICT_HI2DI(di##hi_); \
+ { \
+ code \
+ } \
+ } \
+ })
+
+static inline bool tv_get_float_chk(const typval_T *const tv,
+ float_T *const ret_f)
+ REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
+
+// FIXME circular dependency, cannot import message.h.
+bool emsgf(const char *const fmt, ...);
+
+/// Get the float value
+///
+/// Raises an error if object is not number or floating-point.
+///
+/// @param[in] tv VimL object to get value from.
+/// @param[out] ret_f Location where resulting float is stored.
+///
+/// @return true in case of success, false if tv is not a number or float.
+static inline bool tv_get_float_chk(const typval_T *const tv,
+ float_T *const ret_f)
+{
+ if (tv->v_type == VAR_FLOAT) {
+ *ret_f = tv->vval.v_float;
+ return true;
+ }
+ if (tv->v_type == VAR_NUMBER) {
+ *ret_f = (float_T)tv->vval.v_number;
+ return true;
+ }
+ emsgf(_("E808: Number or Float required"));
+ return false;
+}
+
+static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
+ REAL_FATTR_NONNULL_ALL REAL_FATTR_NONNULL_RET REAL_FATTR_PURE
+ REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE;
+
+/// Compute the `DictWatcher` address from a QUEUE node.
+///
+/// This only exists for .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer
+/// arithmetic).
+static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
+{
+ return QUEUE_DATA(q, DictWatcher, node);
+}
+
+static inline bool tv_is_func(const typval_T tv)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST;
+
+/// Check whether given typval_T contains a function
+///
+/// That is, whether it contains VAR_FUNC or VAR_PARTIAL.
+///
+/// @param[in] tv Typval to check.
+///
+/// @return True if it is a function or a partial, false otherwise.
+static inline bool tv_is_func(const typval_T tv)
+{
+ return tv.v_type == VAR_FUNC || tv.v_type == VAR_PARTIAL;
+}
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/typval.h.generated.h"
+#endif
+#endif // NVIM_EVAL_TYPVAL_H
diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h
index 812340b9c3..17cab4f6ea 100644
--- a/src/nvim/eval/typval_encode.c.h
+++ b/src/nvim/eval/typval_encode.c.h
@@ -238,7 +238,7 @@
#include <assert.h>
#include "nvim/lib/kvec.h"
-#include "nvim/eval_defs.h"
+#include "nvim/eval/typval.h"
#include "nvim/eval/encode.h"
#include "nvim/func_attr.h"
#include "nvim/eval/typval_encode.h"
@@ -402,11 +402,11 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
const dictitem_T *val_di;
if (TYPVAL_ENCODE_ALLOW_SPECIALS
&& tv->vval.v_dict->dv_hashtab.ht_used == 2
- && (type_di = dict_find((dict_T *)tv->vval.v_dict,
- (char_u *)"_TYPE", -1)) != NULL
+ && (type_di = tv_dict_find((dict_T *)tv->vval.v_dict,
+ S_LEN("_TYPE"))) != NULL
&& type_di->di_tv.v_type == VAR_LIST
- && (val_di = dict_find((dict_T *)tv->vval.v_dict,
- (char_u *)"_VAL", -1)) != NULL) {
+ && (val_di = tv_dict_find((dict_T *)tv->vval.v_dict,
+ S_LEN("_VAL"))) != NULL) {
size_t i;
for (i = 0; i < ARRAY_SIZE(eval_msgpack_type_lists); i++) {
if (type_di->di_tv.vval.v_list == eval_msgpack_type_lists[i]) {
@@ -658,7 +658,7 @@ typval_encode_stop_converting_one_item:
while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) {
cur_mpsv->data.d.hi++;
}
- dictitem_T *const di = HI2DI(cur_mpsv->data.d.hi);
+ dictitem_T *const di = TV_DICT_HI2DI(cur_mpsv->data.d.hi);
cur_mpsv->data.d.todo--;
cur_mpsv->data.d.hi++;
TYPVAL_ENCODE_CONV_STR_STRING(NULL, &di->di_key[0],
diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h
index 46145c5d03..3475f6d8b3 100644
--- a/src/nvim/eval/typval_encode.h
+++ b/src/nvim/eval/typval_encode.h
@@ -11,7 +11,7 @@
#include <assert.h>
#include "nvim/lib/kvec.h"
-#include "nvim/eval_defs.h"
+#include "nvim/eval/typval.h"
#include "nvim/func_attr.h"
/// Type of the stack entry
diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h
deleted file mode 100644
index 39028fdb11..0000000000
--- a/src/nvim/eval_defs.h
+++ /dev/null
@@ -1,285 +0,0 @@
-#ifndef NVIM_EVAL_DEFS_H
-#define NVIM_EVAL_DEFS_H
-
-#include <limits.h>
-#include <stddef.h>
-
-#include "nvim/hashtab.h"
-#include "nvim/lib/queue.h"
-#include "nvim/garray.h" // for garray_T
-#include "nvim/profile.h" // for proftime_T
-#include "nvim/pos.h" // for linenr_T
-
-typedef int varnumber_T;
-typedef double float_T;
-
-#define VARNUMBER_MAX INT_MAX
-#define VARNUMBER_MIN INT_MIN
-
-typedef struct listvar_S list_T;
-typedef struct dictvar_S dict_T;
-typedef struct partial_S partial_T;
-
-/// Special variable values
-typedef enum {
- kSpecialVarFalse, ///< v:false
- kSpecialVarTrue, ///< v:true
- kSpecialVarNull, ///< v:null
-} SpecialVarValue;
-
-/// Variable lock status for typval_T.v_lock
-typedef enum {
- VAR_UNLOCKED = 0, ///< Not locked.
- VAR_LOCKED = 1, ///< User lock, can be unlocked.
- VAR_FIXED = 2, ///< Locked forever.
-} VarLockStatus;
-
-/// VimL variable types, for use in typval_T.v_type
-typedef enum {
- VAR_UNKNOWN = 0, ///< Unknown (unspecified) value.
- VAR_NUMBER, ///< Number, .v_number is used.
- VAR_STRING, ///< String, .v_string is used.
- VAR_FUNC, ///< Function reference, .v_string is used as function name.
- VAR_LIST, ///< List, .v_list is used.
- VAR_DICT, ///< Dictionary, .v_dict is used.
- VAR_FLOAT, ///< Floating-point value, .v_float is used.
- VAR_SPECIAL, ///< Special value (true, false, null), .v_special
- ///< is used.
- VAR_PARTIAL, ///< Partial, .v_partial is used.
-} VarType;
-
-/// Structure that holds an internal variable value
-typedef struct {
- VarType v_type; ///< Variable type.
- VarLockStatus v_lock; ///< Variable lock status.
- union typval_vval_union {
- varnumber_T v_number; ///< Number, for VAR_NUMBER.
- SpecialVarValue v_special; ///< Special value, for VAR_SPECIAL.
- float_T v_float; ///< Floating-point number, for VAR_FLOAT.
- char_u *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL.
- list_T *v_list; ///< List for VAR_LIST, can be NULL.
- dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL.
- partial_T *v_partial; ///< Closure: function with args.
- } vval; ///< Actual value.
-} typval_T;
-
-/* Values for "dv_scope". */
-#define VAR_SCOPE 1 /* a:, v:, s:, etc. scope dictionaries */
-#define VAR_DEF_SCOPE 2 /* l:, g: scope dictionaries: here funcrefs are not
- allowed to mask existing functions */
-
-/*
- * Structure to hold an item of a list: an internal variable without a name.
- */
-typedef struct listitem_S listitem_T;
-
-struct listitem_S {
- listitem_T *li_next; /* next item in list */
- listitem_T *li_prev; /* previous item in list */
- typval_T li_tv; /* type and value of the variable */
-};
-
-/*
- * Struct used by those that are using an item in a list.
- */
-typedef struct listwatch_S listwatch_T;
-
-struct listwatch_S {
- listitem_T *lw_item; /* item being watched */
- listwatch_T *lw_next; /* next watcher */
-};
-
-/*
- * Structure to hold info about a list.
- */
-struct listvar_S {
- listitem_T *lv_first; ///< First item, NULL if none.
- listitem_T *lv_last; ///< Last item, NULL if none.
- int lv_refcount; ///< Reference count.
- int lv_len; ///< Number of items.
- listwatch_T *lv_watch; ///< First watcher, NULL if none.
- int lv_idx; ///< Index of a cached item, used for optimising repeated l[idx].
- listitem_T *lv_idx_item; ///< When not NULL item at index "lv_idx".
- int lv_copyID; ///< ID used by deepcopy().
- list_T *lv_copylist; ///< Copied list used by deepcopy().
- VarLockStatus lv_lock; ///< Zero, VAR_LOCKED, VAR_FIXED.
- list_T *lv_used_next; ///< next list in used lists list.
- list_T *lv_used_prev; ///< Previous list in used lists list.
-};
-
-// Static list with 10 items. Use init_static_list() to initialize.
-typedef struct {
- list_T sl_list; // must be first
- listitem_T sl_items[10];
-} staticList10_T;
-
-// Structure to hold an item of a Dictionary.
-// Also used for a variable.
-// The key is copied into "di_key" to avoid an extra alloc/free for it.
-struct dictitem_S {
- typval_T di_tv; ///< type and value of the variable
- char_u di_flags; ///< flags (only used for variable)
- char_u di_key[1]; ///< key (actually longer!)
-};
-
-typedef struct dictitem_S dictitem_T;
-
-/// A dictitem with a 16 character key (plus NUL)
-struct dictitem16_S {
- typval_T di_tv; ///< type and value of the variable
- char_u di_flags; ///< flags (only used for variable)
- char_u di_key[17]; ///< key
-};
-
-typedef struct dictitem16_S dictitem16_T;
-
-
-#define DI_FLAGS_RO 1 // "di_flags" value: read-only variable
-#define DI_FLAGS_RO_SBX 2 // "di_flags" value: read-only in the sandbox
-#define DI_FLAGS_FIX 4 // "di_flags" value: fixed: no :unlet or remove()
-#define DI_FLAGS_LOCK 8 // "di_flags" value: locked variable
-#define DI_FLAGS_ALLOC 16 // "di_flags" value: separately allocated
-
-/// Structure representing a Dictionary
-struct dictvar_S {
- VarLockStatus dv_lock; ///< Whole dictionary lock status.
- char dv_scope; ///< Non-zero (#VAR_SCOPE, #VAR_DEF_SCOPE) if
- ///< dictionary represents a scope (i.e. g:, l: …).
- int dv_refcount; ///< Reference count.
- int dv_copyID; ///< ID used when recursivery traversing a value.
- hashtab_T dv_hashtab; ///< Hashtab containing all items.
- dict_T *dv_copydict; ///< Copied dict used by deepcopy().
- dict_T *dv_used_next; ///< Next dictionary in used dictionaries list.
- dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list.
- QUEUE watchers; ///< Dictionary key watchers set by user code.
-};
-
-typedef int scid_T; // script ID
-typedef struct funccall_S funccall_T;
-
-// Structure to hold info for a user function.
-typedef struct ufunc ufunc_T;
-
-struct ufunc {
- int uf_varargs; ///< variable nr of arguments
- int uf_flags;
- int uf_calls; ///< nr of active calls
- bool uf_cleared; ///< func_clear() was already called
- garray_T uf_args; ///< arguments
- garray_T uf_lines; ///< function lines
- int uf_profiling; ///< true when func is being profiled
- // Profiling the function as a whole.
- int uf_tm_count; ///< nr of calls
- proftime_T uf_tm_total; ///< time spent in function + children
- proftime_T uf_tm_self; ///< time spent in function itself
- proftime_T uf_tm_children; ///< time spent in children this call
- // Profiling the function per line.
- int *uf_tml_count; ///< nr of times line was executed
- proftime_T *uf_tml_total; ///< time spent in a line + children
- proftime_T *uf_tml_self; ///< time spent in a line itself
- proftime_T uf_tml_start; ///< start time for current line
- proftime_T uf_tml_children; ///< time spent in children for this line
- proftime_T uf_tml_wait; ///< start wait time for current line
- int uf_tml_idx; ///< index of line being timed; -1 if none
- int uf_tml_execed; ///< line being timed was executed
- scid_T uf_script_ID; ///< ID of script where function was defined,
- // used for s: variables
- int uf_refcount; ///< reference count, see func_name_refcount()
- funccall_T *uf_scoped; ///< l: local variables for closure
- char_u uf_name[1]; ///< name of function (actually longer); can
- // start with <SNR>123_ (<SNR> is K_SPECIAL
- // KS_EXTRA KE_SNR)
-};
-
-/// Maximum number of function arguments
-#define MAX_FUNC_ARGS 20
-#define VAR_SHORT_LEN 20 // short variable name length
-#define FIXVAR_CNT 12 // number of fixed variables
-
-// structure to hold info for a function that is currently being executed.
-struct funccall_S {
- ufunc_T *func; ///< function being called
- int linenr; ///< next line to be executed
- int returned; ///< ":return" used
- struct { ///< fixed variables for arguments
- dictitem_T var; ///< variable (without room for name)
- char_u room[VAR_SHORT_LEN]; ///< room for the name
- } fixvar[FIXVAR_CNT];
- dict_T l_vars; ///< l: local function variables
- dictitem_T l_vars_var; ///< variable for l: scope
- dict_T l_avars; ///< a: argument variables
- dictitem_T l_avars_var; ///< variable for a: scope
- list_T l_varlist; ///< list for a:000
- listitem_T l_listitems[MAX_FUNC_ARGS]; ///< listitems for a:000
- typval_T *rettv; ///< return value
- linenr_T breakpoint; ///< next line with breakpoint or zero
- int dbg_tick; ///< debug_tick when breakpoint was set
- int level; ///< top nesting level of executed function
- proftime_T prof_child; ///< time spent in a child
- funccall_T *caller; ///< calling function or NULL
- int fc_refcount; ///< number of user functions that reference
- // this funccal
- int fc_copyID; ///< for garbage collection
- garray_T fc_funcs; ///< list of ufunc_T* which keep a reference
- // to "func"
-};
-
-// structure used by trans_function_name()
-typedef struct {
- dict_T *fd_dict; ///< Dictionary used.
- char_u *fd_newkey; ///< New key in "dict" in allocated memory.
- dictitem_T *fd_di; ///< Dictionary item used.
-} funcdict_T;
-
-struct partial_S {
- int pt_refcount; ///< Reference count.
- char_u *pt_name; ///< Function name; when NULL use pt_func->name.
- ufunc_T *pt_func; ///< Function pointer; when NULL lookup function
- ///< with pt_name.
- bool pt_auto; ///< when true the partial was created for using
- ///< dict.member in handle_subscript().
- int pt_argc; ///< Number of arguments.
- typval_T *pt_argv; ///< Arguments in allocated array.
- dict_T *pt_dict; ///< Dict for "self".
-};
-
-// structure used for explicit stack while garbage collecting hash tables
-typedef struct ht_stack_S {
- hashtab_T *ht;
- struct ht_stack_S *prev;
-} ht_stack_T;
-
-// structure used for explicit stack while garbage collecting lists
-typedef struct list_stack_S {
- list_T *list;
- struct list_stack_S *prev;
-} list_stack_T;
-
-// In a hashtab item "hi_key" points to "di_key" in a dictitem.
-// This avoids adding a pointer to the hashtab item.
-
-/// Convert a dictitem pointer to a hashitem key pointer
-#define DI2HIKEY(di) ((di)->di_key)
-
-/// Convert a hashitem key pointer to a dictitem pointer
-#define HIKEY2DI(p) ((dictitem_T *)(p - offsetof(dictitem_T, di_key)))
-
-/// Convert a hashitem value pointer to a dictitem pointer
-#define HIVAL2DI(p) \
- ((dictitem_T *)(((char *)p) - offsetof(dictitem_T, di_tv)))
-
-/// Convert a hashitem pointer to a dictitem pointer
-#define HI2DI(hi) HIKEY2DI((hi)->hi_key)
-
-/// Type of assert_* check being performed
-typedef enum
-{
- ASSERT_EQUAL,
- ASSERT_NOTEQUAL,
- ASSERT_MATCH,
- ASSERT_NOTMATCH,
- ASSERT_INRANGE,
- ASSERT_OTHER,
-} assert_type_T;
-
-#endif // NVIM_EVAL_DEFS_H
diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
index 5cbf7f9ce7..26d70a5e6d 100644
--- a/src/nvim/event/process.h
+++ b/src/nvim/event/process.h
@@ -21,7 +21,7 @@ struct process {
int pid, status, refcount;
// set to the hrtime of when process_stop was called for the process.
uint64_t stopped_time;
- char *cwd;
+ const char *cwd;
char **argv;
Stream *in, *out, *err;
process_exit_cb cb;
diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c
index 92efc9fa2e..2737dad305 100644
--- a/src/nvim/event/rstream.c
+++ b/src/nvim/event/rstream.c
@@ -89,7 +89,10 @@ static void on_rbuffer_nonfull(RBuffer *buf, void *data)
static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf)
{
Stream *stream = handle->data;
- buf->base = rbuffer_write_ptr(stream->buffer, &buf->len);
+ // `uv_buf_t.len` happens to have different size on Windows.
+ size_t write_count;
+ buf->base = rbuffer_write_ptr(stream->buffer, &write_count);
+ buf->len = write_count;
}
// Callback invoked by libuv after it copies the data into the buffer provided
@@ -136,7 +139,10 @@ static void fread_idle_cb(uv_idle_t *handle)
uv_fs_t req;
Stream *stream = handle->data;
- stream->uvbuf.base = rbuffer_write_ptr(stream->buffer, &stream->uvbuf.len);
+ // `uv_buf_t.len` happens to have different size on Windows.
+ size_t write_count;
+ stream->uvbuf.base = rbuffer_write_ptr(stream->buffer, &write_count);
+ stream->uvbuf.len = write_count;
// the offset argument to uv_fs_read is int64_t, could someone really try
// to read more than 9 quintillion (9e18) bytes?
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 678102daf6..9a847a4c0a 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1008,8 +1008,8 @@ void do_bang(int addr_count, exarg_T *eap, int forceit, int do_in, int do_out)
AppendToRedobuffLit(cmd, -1);
xfree(cmd);
- AppendToRedobuff((char_u *)"\n");
- bangredo = FALSE;
+ AppendToRedobuff("\n");
+ bangredo = false;
}
/*
* Add quotes around the command, for shells that need them.
@@ -2958,7 +2958,7 @@ void sub_set_replacement(SubReplacementString sub)
{
xfree(old_sub.sub);
if (sub.additional_elements != old_sub.additional_elements) {
- list_unref(old_sub.additional_elements);
+ tv_list_unref(old_sub.additional_elements);
}
old_sub = sub;
}
@@ -4764,8 +4764,8 @@ void fix_help_buffer(void)
char_u *p;
char_u *rt;
- /* set filetype to "help". */
- set_option_value((char_u *)"ft", 0L, (char_u *)"help", OPT_LOCAL);
+ // Set filetype to "help".
+ set_option_value("ft", 0L, "help", OPT_LOCAL);
if (!syntax_present(curwin)) {
for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) {
diff --git a/src/nvim/ex_cmds.h b/src/nvim/ex_cmds.h
index 243b11255e..65bbd8a99e 100644
--- a/src/nvim/ex_cmds.h
+++ b/src/nvim/ex_cmds.h
@@ -4,8 +4,8 @@
#include <stdbool.h>
#include "nvim/os/time.h"
-#include "nvim/eval_defs.h"
#include "nvim/pos.h"
+#include "nvim/eval/typval.h"
// flags for do_ecmd()
#define ECMD_HIDE 0x01 // don't free the current buffer
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 092bb38dd0..a0ae0ffac5 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -957,23 +957,21 @@ char_u *get_profile_name(expand_T *xp, int idx)
}
/// Handle command line completion for :profile command.
-void set_context_in_profile_cmd(expand_T *xp, char_u *arg)
+void set_context_in_profile_cmd(expand_T *xp, const char *arg)
{
- char_u *end_subcmd;
-
// Default: expand subcommands.
xp->xp_context = EXPAND_PROFILE;
pexpand_what = PEXP_SUBCMD;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
- end_subcmd = skiptowhite(arg);
+ char_u *const end_subcmd = skiptowhite((const char_u *)arg);
if (*end_subcmd == NUL) {
return;
}
- if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0) {
+ if ((const char *)end_subcmd - arg == 5 && strncmp(arg, "start", 5) == 0) {
xp->xp_context = EXPAND_FILES;
- xp->xp_pattern = skipwhite(end_subcmd);
+ xp->xp_pattern = skipwhite((const char_u *)end_subcmd);
return;
}
@@ -2073,9 +2071,9 @@ void ex_listdo(exarg_T *eap)
// Clear 'shm' to avoid that the file message overwrites
// any output from the command.
p_shm_save = vim_strsave(p_shm);
- set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
+ set_option_value("shm", 0L, "", 0);
do_argfile(eap, i);
- set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
+ set_option_value("shm", 0L, (char *)p_shm_save, 0);
xfree(p_shm_save);
}
if (curwin->w_arg_idx != i) {
@@ -2138,9 +2136,9 @@ void ex_listdo(exarg_T *eap)
// Go to the next buffer. Clear 'shm' to avoid that the file
// message overwrites any output from the command.
p_shm_save = vim_strsave(p_shm);
- set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
+ set_option_value("shm", 0L, "", 0);
goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
- set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
+ set_option_value("shm", 0L, (char *)p_shm_save, 0);
xfree(p_shm_save);
// If autocommands took us elsewhere, quit here.
@@ -2256,8 +2254,8 @@ void ex_compiler(exarg_T *eap)
}
do_cmdline_cmd("command -nargs=* CompilerSet setlocal <args>");
}
- do_unlet((char_u *)"g:current_compiler", true);
- do_unlet((char_u *)"b:current_compiler", true);
+ do_unlet(S_LEN("g:current_compiler"), true);
+ do_unlet(S_LEN("b:current_compiler"), true);
snprintf((char *)buf, bufsize, "compiler/%s.vim", eap->arg);
if (source_runtime(buf, DIP_ALL) == FAIL) {
@@ -2280,7 +2278,7 @@ void ex_compiler(exarg_T *eap)
old_cur_comp);
xfree(old_cur_comp);
} else {
- do_unlet((char_u *)"g:current_compiler", true);
+ do_unlet(S_LEN("g:current_compiler"), true);
}
}
}
@@ -2496,16 +2494,16 @@ static int APP_BOTH;
static void add_pack_plugin(char_u *fname, void *cookie)
{
char_u *p4, *p3, *p2, *p1, *p;
- char_u *new_rtp;
- char_u *ffname = (char_u *)fix_fname((char *)fname);
+
+ char *const ffname = fix_fname((char *)fname);
if (ffname == NULL) {
return;
}
- if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL) {
+ if (cookie != &APP_LOAD && strstr((char *)p_rtp, ffname) == NULL) {
// directory is not yet in 'runtimepath', add it
- p4 = p3 = p2 = p1 = get_past_head(ffname);
+ p4 = p3 = p2 = p1 = get_past_head((char_u *)ffname);
for (p = p1; *p; mb_ptr_adv(p)) {
if (vim_ispathsep_nocolon(*p)) {
p4 = p3; p3 = p2; p2 = p1; p1 = p;
@@ -2521,13 +2519,13 @@ static void add_pack_plugin(char_u *fname, void *cookie)
*p4 = NUL;
// Find "ffname" in "p_rtp", ignoring '/' vs '\' differences
- size_t fname_len = STRLEN(ffname);
- char_u *insp = p_rtp;
+ size_t fname_len = strlen(ffname);
+ const char *insp = (const char *)p_rtp;
for (;;) {
- if (vim_fnamencmp(insp, ffname, fname_len) == 0) {
+ if (path_fnamencmp(insp, ffname, fname_len) == 0) {
break;
}
- insp = vim_strchr(insp, ',');
+ insp = strchr(insp, ',');
if (insp == NULL) {
break;
}
@@ -2536,10 +2534,10 @@ static void add_pack_plugin(char_u *fname, void *cookie)
if (insp == NULL) {
// not found, append at the end
- insp = p_rtp + STRLEN(p_rtp);
+ insp = (const char *)p_rtp + STRLEN(p_rtp);
} else {
// append after the matching directory.
- insp += STRLEN(ffname);
+ insp += strlen(ffname);
while (*insp != NUL && *insp != ',') {
insp++;
}
@@ -2547,31 +2545,40 @@ static void add_pack_plugin(char_u *fname, void *cookie)
*p4 = c;
// check if rtp/pack/name/start/name/after exists
- char *afterdir = concat_fnames((char *)ffname, "after", true);
+ char *afterdir = concat_fnames(ffname, "after", true);
size_t afterlen = 0;
if (os_isdir((char_u *)afterdir)) {
- afterlen = STRLEN(afterdir) + 1; // add one for comma
+ afterlen = strlen(afterdir) + 1; // add one for comma
}
- size_t oldlen = STRLEN(p_rtp);
- size_t addlen = STRLEN(ffname) + 1; // add one for comma
- new_rtp = try_malloc(oldlen + addlen + afterlen + 1); // add one for NUL
+ const size_t oldlen = STRLEN(p_rtp);
+ const size_t addlen = strlen(ffname) + 1; // add one for comma
+ const size_t new_rtp_len = oldlen + addlen + afterlen + 1;
+ // add one for NUL -------------------------------------^
+ char *const new_rtp = try_malloc(new_rtp_len);
if (new_rtp == NULL) {
goto theend;
}
- uintptr_t keep = (uintptr_t)(insp - p_rtp);
+ const size_t keep = (size_t)(insp - (const char *)p_rtp);
+ size_t new_rtp_fill = 0;
memmove(new_rtp, p_rtp, keep);
- new_rtp[keep] = ',';
- memmove(new_rtp + keep + 1, ffname, addlen);
+ new_rtp_fill += keep;
+ new_rtp[new_rtp_fill++] = ',';
+ memmove(new_rtp + new_rtp_fill, ffname, addlen);
+ new_rtp_fill += addlen - 1;
+ assert(new_rtp[new_rtp_fill] == NUL || new_rtp[new_rtp_fill] == ',');
if (p_rtp[keep] != NUL) {
- memmove(new_rtp + keep + addlen, p_rtp + keep,
- oldlen - keep + 1);
+ memmove(new_rtp + new_rtp_fill, p_rtp + keep, oldlen - keep + 1);
+ new_rtp_fill += oldlen - keep;
}
if (afterlen > 0) {
- STRCAT(new_rtp, ",");
- STRCAT(new_rtp, afterdir);
+ assert(new_rtp[new_rtp_fill] == NUL);
+ new_rtp[new_rtp_fill++] = ',';
+ memmove(new_rtp + new_rtp_fill, afterdir, afterlen - 1);
+ new_rtp_fill += afterlen - 1;
}
- set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
+ new_rtp[new_rtp_fill] = NUL;
+ set_option_value("rtp", 0L, new_rtp, 0);
xfree(new_rtp);
xfree(afterdir);
}
@@ -2580,7 +2587,7 @@ static void add_pack_plugin(char_u *fname, void *cookie)
static const char *plugpat = "%s/plugin/**/*.vim"; // NOLINT
static const char *ftpat = "%s/ftdetect/*.vim"; // NOLINT
- size_t len = STRLEN(ffname) + STRLEN(ftpat);
+ size_t len = strlen(ffname) + STRLEN(ftpat);
char_u *pat = try_malloc(len + 1);
if (pat == NULL) {
goto theend;
@@ -3699,12 +3706,12 @@ static void script_host_execute(char *name, exarg_T *eap)
char *const script = script_get(eap, &len);
if (script != NULL) {
- list_T *const args = list_alloc();
+ list_T *const args = tv_list_alloc();
// script
- list_append_allocated_string(args, script);
+ tv_list_append_allocated_string(args, script);
// current range
- list_append_number(args, (int)eap->line1);
- list_append_number(args, (int)eap->line2);
+ tv_list_append_number(args, (int)eap->line1);
+ tv_list_append_number(args, (int)eap->line2);
(void)eval_call_provider(name, "execute", args);
}
}
@@ -3714,21 +3721,21 @@ static void script_host_execute_file(char *name, exarg_T *eap)
uint8_t buffer[MAXPATHL];
vim_FullName((char *)eap->arg, (char *)buffer, sizeof(buffer), false);
- list_T *args = list_alloc();
+ list_T *args = tv_list_alloc();
// filename
- list_append_string(args, buffer, -1);
+ tv_list_append_string(args, (const char *)buffer, -1);
// current range
- list_append_number(args, (int)eap->line1);
- list_append_number(args, (int)eap->line2);
+ tv_list_append_number(args, (int)eap->line1);
+ tv_list_append_number(args, (int)eap->line2);
(void)eval_call_provider(name, "execute_file", args);
}
static void script_host_do_range(char *name, exarg_T *eap)
{
- list_T *args = list_alloc();
- list_append_number(args, (int)eap->line1);
- list_append_number(args, (int)eap->line2);
- list_append_string(args, eap->arg, -1);
+ list_T *args = tv_list_alloc();
+ tv_list_append_number(args, (int)eap->line1);
+ tv_list_append_number(args, (int)eap->line2);
+ tv_list_append_string(args, (const char *)eap->arg, -1);
(void)eval_call_provider(name, "do_range", args);
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 69dab9c18f..e44d759e04 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -68,6 +68,7 @@
#include "nvim/event/wstream.h"
#include "nvim/shada.h"
#include "nvim/viml/executor/executor.h"
+#include "nvim/globals.h"
static int quitmore = 0;
static int ex_pressedreturn = FALSE;
@@ -270,7 +271,7 @@ do_exmode (
/*
* Execute a simple command line. Used for translated commands like "*".
*/
-int do_cmdline_cmd(char *cmd)
+int do_cmdline_cmd(const char *cmd)
{
return do_cmdline((char_u *)cmd, NULL, NULL,
DOCMD_NOWAIT|DOCMD_KEYTYPED);
@@ -2633,32 +2634,27 @@ int cmd_exists(const char *const name)
* perfectly compatible with each other, but then the command line syntax
* probably won't change that much -- webb.
*/
-char_u *
-set_one_cmd_context (
+const char * set_one_cmd_context(
expand_T *xp,
- char_u *buff /* buffer for command string */
+ const char *buff // buffer for command string
)
{
- char_u *p;
- char_u *cmd, *arg;
- int len = 0;
+ size_t len = 0;
exarg_T ea;
- int compl = EXPAND_NOTHING;
- int delim;
- int forceit = FALSE;
- int usefilter = FALSE; /* filter instead of file name */
+ int context = EXPAND_NOTHING;
+ int forceit = false;
+ int usefilter = false; // Filter instead of file name.
ExpandInit(xp);
- xp->xp_pattern = buff;
- xp->xp_context = EXPAND_COMMANDS; /* Default until we get past command */
+ xp->xp_pattern = (char_u *)buff;
+ xp->xp_context = EXPAND_COMMANDS; // Default until we get past command
ea.argt = 0;
- /*
- * 2. skip comment lines and leading space, colons or bars
- */
- for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++)
- ;
- xp->xp_pattern = cmd;
+ // 2. skip comment lines and leading space, colons or bars
+ const char *cmd;
+ for (cmd = buff; strchr(" \t:|", *cmd) != NULL; cmd++) {
+ }
+ xp->xp_pattern = (char_u *)cmd;
if (*cmd == NUL)
return NULL;
@@ -2670,14 +2666,15 @@ set_one_cmd_context (
/*
* 3. parse a range specifier of the form: addr [,addr] [;addr] ..
*/
- cmd = skip_range(cmd, &xp->xp_context);
+ cmd = (const char *)skip_range((const char_u *)cmd, &xp->xp_context);
/*
* 4. parse command
*/
- xp->xp_pattern = cmd;
- if (*cmd == NUL)
+ xp->xp_pattern = (char_u *)cmd;
+ if (*cmd == NUL) {
return NULL;
+ }
if (*cmd == '"') {
xp->xp_context = EXPAND_NOTHING;
return NULL;
@@ -2693,6 +2690,7 @@ set_one_cmd_context (
* do accept "keepmarks", "keepalt" and "keepjumps".
* - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
*/
+ const char *p;
if (*cmd == 'k' && cmd[1] != 'e') {
ea.cmdidx = CMD_k;
p = cmd + 1;
@@ -2715,20 +2713,21 @@ set_one_cmd_context (
}
}
// check for non-alpha command
- if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL) {
+ if (p == cmd && strchr("@*!=><&~#", *p) != NULL) {
p++;
}
- len = (int)(p - cmd);
+ len = (size_t)(p - cmd);
if (len == 0) {
xp->xp_context = EXPAND_UNSUCCESSFUL;
return NULL;
}
for (ea.cmdidx = (cmdidx_T)0; (int)ea.cmdidx < (int)CMD_SIZE;
- ea.cmdidx = (cmdidx_T)((int)ea.cmdidx + 1))
- if (STRNCMP(cmdnames[(int)ea.cmdidx].cmd_name, cmd,
- (size_t)len) == 0)
+ ea.cmdidx = (cmdidx_T)((int)ea.cmdidx + 1)) {
+ if (STRNCMP(cmdnames[(int)ea.cmdidx].cmd_name, cmd, len) == 0) {
break;
+ }
+ }
if (cmd[0] >= 'A' && cmd[0] <= 'Z') {
while (ASCII_ISALNUM(*p) || *p == '*') { // Allow * wild card
@@ -2745,16 +2744,15 @@ set_one_cmd_context (
return NULL;
if (ea.cmdidx == CMD_SIZE) {
- if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL) {
+ if (*cmd == 's' && strchr("cgriI", cmd[1]) != NULL) {
ea.cmdidx = CMD_substitute;
p = cmd + 1;
} else if (cmd[0] >= 'A' && cmd[0] <= 'Z') {
- ea.cmd = cmd;
- p = find_ucmd(&ea, p, NULL, xp,
- &compl
- );
- if (p == NULL)
- ea.cmdidx = CMD_SIZE; /* ambiguous user command */
+ ea.cmd = (char_u *)cmd;
+ p = (const char *)find_ucmd(&ea, (char_u *)p, NULL, xp, &context);
+ if (p == NULL) {
+ ea.cmdidx = CMD_SIZE; // Ambiguous user command.
+ }
}
}
if (ea.cmdidx == CMD_SIZE) {
@@ -2777,16 +2775,17 @@ set_one_cmd_context (
ea.argt = cmdnames[(int)ea.cmdidx].cmd_argt;
}
- arg = skipwhite(p);
+ const char *arg = (const char *)skipwhite((const char_u *)p);
if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) {
- if (*arg == '>') { /* append */
- if (*++arg == '>')
- ++arg;
- arg = skipwhite(arg);
- } else if (*arg == '!' && ea.cmdidx == CMD_write) { /* :w !filter */
- ++arg;
- usefilter = TRUE;
+ if (*arg == '>') { // Append.
+ if (*++arg == '>') {
+ arg++;
+ }
+ arg = (const char *)skipwhite((const char_u *)arg);
+ } else if (*arg == '!' && ea.cmdidx == CMD_write) { // :w !filter
+ arg++;
+ usefilter = true;
}
}
@@ -2799,23 +2798,24 @@ set_one_cmd_context (
}
if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) {
- while (*arg == *cmd) /* allow any number of '>' or '<' */
- ++arg;
- arg = skipwhite(arg);
+ while (*arg == *cmd) { // allow any number of '>' or '<'
+ arg++;
+ }
+ arg = (const char *)skipwhite((const char_u *)arg);
}
/* Does command allow "+command"? */
if ((ea.argt & EDITCMD) && !usefilter && *arg == '+') {
/* Check if we're in the +command */
p = arg + 1;
- arg = skip_cmd_arg(arg, FALSE);
+ arg = (const char *)skip_cmd_arg((char_u *)arg, false);
/* Still touching the command after '+'? */
if (*arg == NUL)
return p;
- /* Skip space(s) after +command to get to the real argument */
- arg = skipwhite(arg);
+ // Skip space(s) after +command to get to the real argument.
+ arg = (const char *)skipwhite((const char_u *)arg);
}
/*
@@ -2844,19 +2844,18 @@ set_one_cmd_context (
}
// no arguments allowed
- if (!(ea.argt & EXTRA) && *arg != NUL
- && vim_strchr((char_u *)"|\"", *arg) == NULL) {
+ if (!(ea.argt & EXTRA) && *arg != NUL && strchr("|\"", *arg) == NULL) {
return NULL;
}
/* Find start of last argument (argument just before cursor): */
p = buff;
- xp->xp_pattern = p;
- len = (int)STRLEN(buff);
+ xp->xp_pattern = (char_u *)p;
+ len = strlen(buff);
while (*p && p < buff + len) {
if (*p == ' ' || *p == TAB) {
- /* argument starts after a space */
- xp->xp_pattern = ++p;
+ // Argument starts after a space.
+ xp->xp_pattern = (char_u *)++p;
} else {
if (*p == '\\' && *(p + 1) != NUL)
++p; /* skip over escaped character */
@@ -2866,25 +2865,26 @@ set_one_cmd_context (
if (ea.argt & XFILE) {
int c;
- int in_quote = FALSE;
- char_u *bow = NULL; /* Beginning of word */
+ int in_quote = false;
+ const char *bow = NULL; // Beginning of word.
/*
* Allow spaces within back-quotes to count as part of the argument
* being expanded.
*/
- xp->xp_pattern = skipwhite(arg);
- p = xp->xp_pattern;
+ xp->xp_pattern = skipwhite((const char_u *)arg);
+ p = (const char *)xp->xp_pattern;
while (*p != NUL) {
- if (has_mbyte)
- c = mb_ptr2char(p);
- else
- c = *p;
- if (c == '\\' && p[1] != NUL)
- ++p;
- else if (c == '`') {
+ if (has_mbyte) {
+ c = mb_ptr2char((const char_u *)p);
+ } else {
+ c = (uint8_t)(*p);
+ }
+ if (c == '\\' && p[1] != NUL) {
+ p++;
+ } else if (c == '`') {
if (!in_quote) {
- xp->xp_pattern = p;
+ xp->xp_pattern = (char_u *)p;
bow = p + 1;
}
in_quote = !in_quote;
@@ -2897,22 +2897,26 @@ set_one_cmd_context (
|| ascii_iswhite(c)) {
len = 0; /* avoid getting stuck when space is in 'isfname' */
while (*p != NUL) {
- if (has_mbyte)
- c = mb_ptr2char(p);
- else
+ if (has_mbyte) {
+ c = mb_ptr2char((const char_u *)p);
+ } else {
c = *p;
- if (c == '`' || vim_isfilec_or_wc(c))
+ }
+ if (c == '`' || vim_isfilec_or_wc(c)) {
break;
- if (has_mbyte)
- len = (*mb_ptr2len)(p);
- else
+ }
+ if (has_mbyte) {
+ len = (size_t)(*mb_ptr2len)((const char_u *)p);
+ } else {
len = 1;
+ }
mb_ptr_adv(p);
}
- if (in_quote)
+ if (in_quote) {
bow = p;
- else
- xp->xp_pattern = p;
+ } else {
+ xp->xp_pattern = (char_u *)p;
+ }
p -= len;
}
mb_ptr_adv(p);
@@ -2922,8 +2926,9 @@ set_one_cmd_context (
* If we are still inside the quotes, and we passed a space, just
* expand from there.
*/
- if (bow != NULL && in_quote)
- xp->xp_pattern = bow;
+ if (bow != NULL && in_quote) {
+ xp->xp_pattern = (char_u *)bow;
+ }
xp->xp_context = EXPAND_FILES;
/* For a shell command more chars need to be escaped. */
@@ -2931,33 +2936,36 @@ set_one_cmd_context (
#ifndef BACKSLASH_IN_FILENAME
xp->xp_shell = TRUE;
#endif
- /* When still after the command name expand executables. */
- if (xp->xp_pattern == skipwhite(arg))
+ // When still after the command name expand executables.
+ if (xp->xp_pattern == skipwhite((const char_u *)arg)) {
xp->xp_context = EXPAND_SHELLCMD;
+ }
}
- /* Check for environment variable */
- if (*xp->xp_pattern == '$'
- ) {
- for (p = xp->xp_pattern + 1; *p != NUL; ++p)
- if (!vim_isIDc(*p))
+ // Check for environment variable.
+ if (*xp->xp_pattern == '$') {
+ for (p = (const char *)xp->xp_pattern + 1; *p != NUL; p++) {
+ if (!vim_isIDc((uint8_t)(*p))) {
break;
+ }
+ }
if (*p == NUL) {
xp->xp_context = EXPAND_ENV_VARS;
- ++xp->xp_pattern;
- /* Avoid that the assignment uses EXPAND_FILES again. */
- if (compl != EXPAND_USER_DEFINED && compl != EXPAND_USER_LIST)
- compl = EXPAND_ENV_VARS;
+ xp->xp_pattern++;
+ // Avoid that the assignment uses EXPAND_FILES again.
+ if (context != EXPAND_USER_DEFINED && context != EXPAND_USER_LIST) {
+ context = EXPAND_ENV_VARS;
+ }
}
}
/* Check for user names */
if (*xp->xp_pattern == '~') {
- for (p = xp->xp_pattern + 1; *p != NUL && *p != '/'; ++p)
- ;
- /* Complete ~user only if it partially matches a user name.
- * A full match ~user<Tab> will be replaced by user's home
- * directory i.e. something like ~user<Tab> -> /home/user/ */
- if (*p == NUL && p > xp->xp_pattern + 1
+ for (p = (const char *)xp->xp_pattern + 1; *p != NUL && *p != '/'; p++) {
+ }
+ // Complete ~user only if it partially matches a user name.
+ // A full match ~user<Tab> will be replaced by user's home
+ // directory i.e. something like ~user<Tab> -> /home/user/
+ if (*p == NUL && p > (const char *)xp->xp_pattern + 1
&& match_user(xp->xp_pattern + 1) == 1) {
xp->xp_context = EXPAND_USER;
++xp->xp_pattern;
@@ -2987,7 +2995,7 @@ set_one_cmd_context (
break;
case CMD_help:
xp->xp_context = EXPAND_HELP;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
/* Command modifiers: return the argument.
@@ -3030,13 +3038,14 @@ set_one_cmd_context (
if (*arg == NUL || !ends_excmd(*arg)) {
/* also complete "None" */
set_context_in_echohl_cmd(xp, arg);
- arg = skipwhite(skiptowhite(arg));
+ arg = (const char *)skipwhite(skiptowhite((const char_u *)arg));
if (*arg != NUL) {
xp->xp_context = EXPAND_NOTHING;
- arg = skip_regexp(arg + 1, *arg, p_magic, NULL);
+ arg = (const char *)skip_regexp((char_u *)arg + 1, (uint8_t)(*arg),
+ p_magic, NULL);
}
}
- return find_nextcmd(arg);
+ return (const char *)find_nextcmd((char_u *)arg);
/*
* All completion for the +cmdline_compl feature goes here.
@@ -3045,15 +3054,15 @@ set_one_cmd_context (
case CMD_command:
/* Check for attributes */
while (*arg == '-') {
- arg++; /* Skip "-" */
- p = skiptowhite(arg);
+ arg++; // Skip "-".
+ p = (const char *)skiptowhite((const char_u *)arg);
if (*p == NUL) {
- /* Cursor is still in the attribute */
- p = vim_strchr(arg, '=');
+ // Cursor is still in the attribute.
+ p = strchr(arg, '=');
if (p == NULL) {
- /* No "=", so complete attribute names */
+ // No "=", so complete attribute names.
xp->xp_context = EXPAND_USER_CMD_FLAGS;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
return NULL;
}
@@ -3061,73 +3070,81 @@ set_one_cmd_context (
// their arguments as well.
if (STRNICMP(arg, "complete", p - arg) == 0) {
xp->xp_context = EXPAND_USER_COMPLETE;
- xp->xp_pattern = p + 1;
+ xp->xp_pattern = (char_u *)p + 1;
return NULL;
} else if (STRNICMP(arg, "nargs", p - arg) == 0) {
xp->xp_context = EXPAND_USER_NARGS;
- xp->xp_pattern = p + 1;
+ xp->xp_pattern = (char_u *)p + 1;
return NULL;
} else if (STRNICMP(arg, "addr", p - arg) == 0) {
xp->xp_context = EXPAND_USER_ADDR_TYPE;
- xp->xp_pattern = p + 1;
+ xp->xp_pattern = (char_u *)p + 1;
return NULL;
}
return NULL;
}
- arg = skipwhite(p);
+ arg = (const char *)skipwhite((char_u *)p);
}
- /* After the attributes comes the new command name */
- p = skiptowhite(arg);
+ // After the attributes comes the new command name.
+ p = (const char *)skiptowhite((const char_u *)arg);
if (*p == NUL) {
xp->xp_context = EXPAND_USER_COMMANDS;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
}
- /* And finally comes a normal command */
- return skipwhite(p);
+ // And finally comes a normal command.
+ return (const char *)skipwhite((const char_u *)p);
case CMD_delcommand:
xp->xp_context = EXPAND_USER_COMMANDS;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
case CMD_global:
- case CMD_vglobal:
- delim = *arg; /* get the delimiter */
- if (delim)
- ++arg; /* skip delimiter if there is one */
+ case CMD_vglobal: {
+ const int delim = (uint8_t)(*arg); // Get the delimiter.
+ if (delim) {
+ arg++; // Skip delimiter if there is one.
+ }
- while (arg[0] != NUL && arg[0] != delim) {
- if (arg[0] == '\\' && arg[1] != NUL)
- ++arg;
- ++arg;
+ while (arg[0] != NUL && (uint8_t)arg[0] != delim) {
+ if (arg[0] == '\\' && arg[1] != NUL) {
+ arg++;
+ }
+ arg++;
}
if (arg[0] != NUL)
return arg + 1;
break;
+ }
case CMD_and:
- case CMD_substitute:
- delim = *arg;
+ case CMD_substitute: {
+ const int delim = (uint8_t)(*arg);
if (delim) {
- /* skip "from" part */
- ++arg;
- arg = skip_regexp(arg, delim, p_magic, NULL);
+ // Skip "from" part.
+ arg++;
+ arg = (const char *)skip_regexp((char_u *)arg, delim, p_magic, NULL);
}
- /* skip "to" part */
- while (arg[0] != NUL && arg[0] != delim) {
- if (arg[0] == '\\' && arg[1] != NUL)
- ++arg;
- ++arg;
+ // Skip "to" part.
+ while (arg[0] != NUL && (uint8_t)arg[0] != delim) {
+ if (arg[0] == '\\' && arg[1] != NUL) {
+ arg++;
+ }
+ arg++;
}
- if (arg[0] != NUL) /* skip delimiter */
- ++arg;
- while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL)
- ++arg;
- if (arg[0] != NUL)
+ if (arg[0] != NUL) { // Skip delimiter.
+ arg++;
+ }
+ while (arg[0] && strchr("|\"#", arg[0]) == NULL) {
+ arg++;
+ }
+ if (arg[0] != NUL) {
return arg;
+ }
break;
+ }
case CMD_isearch:
case CMD_dsearch:
case CMD_ilist:
@@ -3137,36 +3154,40 @@ set_one_cmd_context (
case CMD_djump:
case CMD_isplit:
case CMD_dsplit:
- arg = skipwhite(skipdigits(arg)); /* skip count */
- if (*arg == '/') { /* Match regexp, not just whole words */
- for (++arg; *arg && *arg != '/'; arg++)
- if (*arg == '\\' && arg[1] != NUL)
+ // Skip count.
+ arg = (const char *)skipwhite(skipdigits((const char_u *)arg));
+ if (*arg == '/') { // Match regexp, not just whole words.
+ for (++arg; *arg && *arg != '/'; arg++) {
+ if (*arg == '\\' && arg[1] != NUL) {
arg++;
+ }
+ }
if (*arg) {
- arg = skipwhite(arg + 1);
+ arg = (const char *)skipwhite((const char_u *)arg + 1);
- /* Check for trailing illegal characters */
- if (*arg && vim_strchr((char_u *)"|\"\n", *arg) == NULL)
+ // Check for trailing illegal characters.
+ if (*arg && strchr("|\"\n", *arg) == NULL) {
xp->xp_context = EXPAND_NOTHING;
- else
+ } else {
return arg;
+ }
}
}
break;
case CMD_autocmd:
- return set_context_in_autocmd(xp, arg, FALSE);
+ return (const char *)set_context_in_autocmd(xp, (char_u *)arg, false);
case CMD_doautocmd:
case CMD_doautoall:
- return set_context_in_autocmd(xp, arg, TRUE);
+ return (const char *)set_context_in_autocmd(xp, (char_u *)arg, true);
case CMD_set:
- set_context_in_set_cmd(xp, arg, 0);
+ set_context_in_set_cmd(xp, (char_u *)arg, 0);
break;
case CMD_setglobal:
- set_context_in_set_cmd(xp, arg, OPT_GLOBAL);
+ set_context_in_set_cmd(xp, (char_u *)arg, OPT_GLOBAL);
break;
case CMD_setlocal:
- set_context_in_set_cmd(xp, arg, OPT_LOCAL);
+ set_context_in_set_cmd(xp, (char_u *)arg, OPT_LOCAL);
break;
case CMD_tag:
case CMD_stag:
@@ -3178,15 +3199,16 @@ set_one_cmd_context (
case CMD_tjump:
case CMD_stjump:
case CMD_ptjump:
- if (*p_wop != NUL)
+ if (*p_wop != NUL) {
xp->xp_context = EXPAND_TAGS_LISTFILES;
- else
+ } else {
xp->xp_context = EXPAND_TAGS;
- xp->xp_pattern = arg;
+ }
+ xp->xp_pattern = (char_u *)arg;
break;
case CMD_augroup:
xp->xp_context = EXPAND_AUGROUP;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
case CMD_syntax:
set_context_in_syntax_cmd(xp, arg);
@@ -3203,20 +3225,21 @@ set_one_cmd_context (
case CMD_echoerr:
case CMD_call:
case CMD_return:
- set_context_for_expression(xp, arg, ea.cmdidx);
+ set_context_for_expression(xp, (char_u *)arg, ea.cmdidx);
break;
case CMD_unlet:
- while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
- arg = xp->xp_pattern + 1;
+ while ((xp->xp_pattern = (char_u *)strchr(arg, ' ')) != NULL) {
+ arg = (const char *)xp->xp_pattern + 1;
+ }
xp->xp_context = EXPAND_USER_VARS;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
case CMD_function:
case CMD_delfunction:
xp->xp_context = EXPAND_USER_FUNC;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
case CMD_echohl:
@@ -3231,33 +3254,37 @@ set_one_cmd_context (
set_context_in_cscope_cmd(xp, arg, ea.cmdidx);
break;
case CMD_sign:
- set_context_in_sign_cmd(xp, arg);
+ set_context_in_sign_cmd(xp, (char_u *)arg);
break;
case CMD_bdelete:
case CMD_bwipeout:
case CMD_bunload:
- while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL)
- arg = xp->xp_pattern + 1;
- /*FALLTHROUGH*/
+ while ((xp->xp_pattern = (char_u *)strchr(arg, ' ')) != NULL) {
+ arg = (const char *)xp->xp_pattern + 1;
+ }
+ // FALLTHROUGH
case CMD_buffer:
case CMD_sbuffer:
case CMD_checktime:
xp->xp_context = EXPAND_BUFFERS;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
case CMD_USER:
case CMD_USER_BUF:
- if (compl != EXPAND_NOTHING) {
- /* XFILE: file names are handled above */
+ if (context != EXPAND_NOTHING) {
+ // XFILE: file names are handled above.
if (!(ea.argt & XFILE)) {
- if (compl == EXPAND_MENUS)
- return set_context_in_menu_cmd(xp, cmd, arg, forceit);
- if (compl == EXPAND_COMMANDS)
+ if (context == EXPAND_MENUS) {
+ return (const char *)set_context_in_menu_cmd(xp, (char_u *)cmd,
+ (char_u *)arg, forceit);
+ } else if (context == EXPAND_COMMANDS) {
return arg;
- if (compl == EXPAND_MAPPINGS)
- return set_context_in_map_cmd(xp, (char_u *)"map",
- arg, forceit, FALSE, FALSE, CMD_map);
- /* Find start of last argument. */
+ } else if (context == EXPAND_MAPPINGS) {
+ return (const char *)set_context_in_map_cmd(
+ xp, (char_u *)"map", (char_u *)arg, forceit, false, false,
+ CMD_map);
+ }
+ // Find start of last argument.
p = arg;
while (*p) {
if (*p == ' ')
@@ -3267,9 +3294,9 @@ set_one_cmd_context (
++p; /* skip over escaped character */
mb_ptr_adv(p);
}
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
}
- xp->xp_context = compl;
+ xp->xp_context = context;
}
break;
case CMD_map: case CMD_noremap:
@@ -3281,8 +3308,8 @@ set_one_cmd_context (
case CMD_lmap: case CMD_lnoremap:
case CMD_smap: case CMD_snoremap:
case CMD_xmap: case CMD_xnoremap:
- return set_context_in_map_cmd(xp, cmd, arg, forceit,
- FALSE, FALSE, ea.cmdidx);
+ return (const char *)set_context_in_map_cmd(
+ xp, (char_u *)cmd, (char_u *)arg, forceit, false, false, ea.cmdidx);
case CMD_unmap:
case CMD_nunmap:
case CMD_vunmap:
@@ -3292,18 +3319,18 @@ set_one_cmd_context (
case CMD_lunmap:
case CMD_sunmap:
case CMD_xunmap:
- return set_context_in_map_cmd(xp, cmd, arg, forceit,
- FALSE, TRUE, ea.cmdidx);
+ return (const char *)set_context_in_map_cmd(
+ xp, (char_u *)cmd, (char_u *)arg, forceit, false, true, ea.cmdidx);
case CMD_abbreviate: case CMD_noreabbrev:
case CMD_cabbrev: case CMD_cnoreabbrev:
case CMD_iabbrev: case CMD_inoreabbrev:
- return set_context_in_map_cmd(xp, cmd, arg, forceit,
- TRUE, FALSE, ea.cmdidx);
+ return (const char *)set_context_in_map_cmd(
+ xp, (char_u *)cmd, (char_u *)arg, forceit, true, false, ea.cmdidx);
case CMD_unabbreviate:
case CMD_cunabbrev:
case CMD_iunabbrev:
- return set_context_in_map_cmd(xp, cmd, arg, forceit,
- TRUE, TRUE, ea.cmdidx);
+ return (const char *)set_context_in_map_cmd(
+ xp, (char_u *)cmd, (char_u *)arg, forceit, true, true, ea.cmdidx);
case CMD_menu: case CMD_noremenu: case CMD_unmenu:
case CMD_amenu: case CMD_anoremenu: case CMD_aunmenu:
case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu:
@@ -3313,47 +3340,49 @@ set_one_cmd_context (
case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu:
case CMD_tmenu: case CMD_tunmenu:
case CMD_popup: case CMD_emenu:
- return set_context_in_menu_cmd(xp, cmd, arg, forceit);
+ return (const char *)set_context_in_menu_cmd(
+ xp, (char_u *)cmd, (char_u *)arg, forceit);
case CMD_colorscheme:
xp->xp_context = EXPAND_COLORS;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
case CMD_compiler:
xp->xp_context = EXPAND_COMPILER;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
case CMD_ownsyntax:
xp->xp_context = EXPAND_OWNSYNTAX;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
case CMD_setfiletype:
xp->xp_context = EXPAND_FILETYPE;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
case CMD_packadd:
xp->xp_context = EXPAND_PACKADD;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
#ifdef HAVE_WORKING_LIBINTL
case CMD_language:
- p = skiptowhite(arg);
+ p = (const char *)skiptowhite((const char_u *)arg);
if (*p == NUL) {
xp->xp_context = EXPAND_LANGUAGE;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
} else {
- if ( STRNCMP(arg, "messages", p - arg) == 0
- || STRNCMP(arg, "ctype", p - arg) == 0
- || STRNCMP(arg, "time", p - arg) == 0) {
+ if (strncmp(arg, "messages", p - arg) == 0
+ || strncmp(arg, "ctype", p - arg) == 0
+ || strncmp(arg, "time", p - arg) == 0) {
xp->xp_context = EXPAND_LOCALES;
- xp->xp_pattern = skipwhite(p);
- } else
+ xp->xp_pattern = skipwhite((const char_u *)p);
+ } else {
xp->xp_context = EXPAND_NOTHING;
+ }
}
break;
#endif
@@ -3362,16 +3391,16 @@ set_one_cmd_context (
break;
case CMD_behave:
xp->xp_context = EXPAND_BEHAVE;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
case CMD_history:
xp->xp_context = EXPAND_HISTORY;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
case CMD_syntime:
xp->xp_context = EXPAND_SYNTIME;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
break;
@@ -3390,10 +3419,9 @@ set_one_cmd_context (
* Also skip white space and ":" characters.
* Returns the "cmd" pointer advanced to beyond the range.
*/
-char_u *
-skip_range (
- char_u *cmd,
- int *ctx /* pointer to xp_context or NULL */
+char_u *skip_range(
+ const char_u *cmd,
+ int *ctx // pointer to xp_context or NULL
)
{
unsigned delim;
@@ -3418,7 +3446,7 @@ skip_range (
while (*cmd == ':')
cmd = skipwhite(cmd + 1);
- return cmd;
+ return (char_u *)cmd;
}
/*
@@ -4587,14 +4615,15 @@ int ends_excmd(int c) FUNC_ATTR_CONST
* Return the next command, after the first '|' or '\n'.
* Return NULL if not found.
*/
-char_u *find_nextcmd(char_u *p)
+char_u *find_nextcmd(const char_u *p)
{
while (*p != '|' && *p != '\n') {
- if (*p == NUL)
+ if (*p == NUL) {
return NULL;
- ++p;
+ }
+ p++;
}
- return p + 1;
+ return (char_u *)p + 1;
}
/*
@@ -6796,7 +6825,7 @@ do_exedit (
int ms = msg_scroll;
if (eap->nextcmd != NULL) {
- stuffReadbuff(eap->nextcmd);
+ stuffReadbuff((const char *)eap->nextcmd);
eap->nextcmd = NULL;
}
@@ -7726,7 +7755,7 @@ static void ex_mkrc(exarg_T *eap)
/* When using 'viewdir' may have to create the directory. */
if (using_vdir && !os_isdir(p_vdir)) {
- vim_mkdir_emsg(p_vdir, 0755);
+ vim_mkdir_emsg((const char *)p_vdir, 0755);
}
fd = open_exfile((char_u *) fname, eap->forceit, WRITEBIN);
@@ -7838,10 +7867,17 @@ static void ex_mkrc(exarg_T *eap)
xfree(viewFile);
}
-int vim_mkdir_emsg(char_u *name, int prot)
+/// Try creating a directory, give error message on failure
+///
+/// @param[in] name Directory to create.
+/// @param[in] prot Directory permissions.
+///
+/// @return OK in case of success, FAIL otherwise.
+int vim_mkdir_emsg(const char *const name, const int prot)
+ FUNC_ATTR_NONNULL_ALL
{
int ret;
- if ((ret = os_mkdir((char *)name, prot)) != 0) {
+ if ((ret = os_mkdir(name, prot)) != 0) {
EMSG3(_(e_mkdir), name, os_strerror(ret));
return FAIL;
}
@@ -8418,8 +8454,8 @@ eval_vars (
*usedlen = 1;
return NULL;
}
- result = list_find_str(get_vim_var_list(VV_OLDFILES),
- (long)i);
+ result = (char_u *)tv_list_find_str(get_vim_var_list(VV_OLDFILES),
+ i - 1);
if (result == NULL) {
*errormsg = (char_u *)"";
return NULL;
@@ -9349,8 +9385,8 @@ static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp)
*p = '/';
}
- /* escape special characters */
- p = vim_strsave_fnameescape(sname, FALSE);
+ // Escape special characters.
+ p = (char_u *)vim_strsave_fnameescape((const char *)sname, false);
xfree(sname);
/* write the result */
@@ -9485,18 +9521,18 @@ void dialog_msg(char_u *buff, char *format, char_u *fname)
static void ex_behave(exarg_T *eap)
{
if (STRCMP(eap->arg, "mswin") == 0) {
- set_option_value((char_u *)"selection", 0L, (char_u *)"exclusive", 0);
- set_option_value((char_u *)"selectmode", 0L, (char_u *)"mouse,key", 0);
- set_option_value((char_u *)"mousemodel", 0L, (char_u *)"popup", 0);
- set_option_value((char_u *)"keymodel", 0L,
- (char_u *)"startsel,stopsel", 0);
+ set_option_value("selection", 0L, "exclusive", 0);
+ set_option_value("selectmode", 0L, "mouse,key", 0);
+ set_option_value("mousemodel", 0L, "popup", 0);
+ set_option_value("keymodel", 0L, "startsel,stopsel", 0);
} else if (STRCMP(eap->arg, "xterm") == 0) {
- set_option_value((char_u *)"selection", 0L, (char_u *)"inclusive", 0);
- set_option_value((char_u *)"selectmode", 0L, (char_u *)"", 0);
- set_option_value((char_u *)"mousemodel", 0L, (char_u *)"extend", 0);
- set_option_value((char_u *)"keymodel", 0L, (char_u *)"", 0);
- } else
+ set_option_value("selection", 0L, "inclusive", 0);
+ set_option_value("selectmode", 0L, "", 0);
+ set_option_value("mousemodel", 0L, "extend", 0);
+ set_option_value("keymodel", 0L, "", 0);
+ } else {
EMSG2(_(e_invarg2), eap->arg);
+ }
}
/*
@@ -9610,8 +9646,9 @@ void filetype_maybe_enable(void)
*/
static void ex_setfiletype(exarg_T *eap)
{
- if (!did_filetype)
- set_option_value((char_u *)"filetype", 0L, eap->arg, OPT_LOCAL);
+ if (!did_filetype) {
+ set_option_value("filetype", 0L, (char *)eap->arg, OPT_LOCAL);
+ }
}
static void ex_digraphs(exarg_T *eap)
@@ -9697,7 +9734,8 @@ static void ex_match(exarg_T *eap)
c = *end;
*end = NUL;
- match_add(curwin, g, p + 1, 10, id, NULL, NULL);
+ match_add(curwin, (const char *)g, (const char *)p + 1, 10, id,
+ NULL, NULL);
xfree(g);
*end = c;
}
diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h
index 4def4cbbae..cff350de08 100644
--- a/src/nvim/ex_docmd.h
+++ b/src/nvim/ex_docmd.h
@@ -2,6 +2,7 @@
#define NVIM_EX_DOCMD_H
#include "nvim/ex_cmds_defs.h"
+#include "nvim/globals.h"
// flags for do_cmdline()
#define DOCMD_VERBOSE 0x01 // included command in error message
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index 4bb6f97035..65112c4dd8 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -1,6 +1,8 @@
-/*
- * ex_eval.c: functions for Ex command line for the +eval feature.
- */
+// TODO(ZyX-I): move to eval/executor
+
+/// @file ex_eval.c
+///
+/// Functions for Ex command line for the +eval feature.
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
@@ -12,6 +14,7 @@
#include "nvim/ex_eval.h"
#include "nvim/charset.h"
#include "nvim/eval.h"
+#include "nvim/eval/typval.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/message.h"
@@ -19,8 +22,6 @@
#include "nvim/regexp.h"
#include "nvim/strings.h"
-
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_eval.c.generated.h"
#endif
@@ -57,12 +58,14 @@
* is an error exception.) - The macros can be defined as expressions checking
* for a variable that is allowed to be changed during execution of a script.
*/
-/* Values used for the Vim release. */
-# define THROW_ON_ERROR TRUE
-# define THROW_ON_ERROR_TRUE
-# define THROW_ON_INTERRUPT TRUE
-# define THROW_ON_INTERRUPT_TRUE
+// Values used for the Vim release.
+#define THROW_ON_ERROR true
+#define THROW_ON_ERROR_TRUE
+#define THROW_ON_INTERRUPT true
+#define THROW_ON_INTERRUPT_TRUE
+
+#define discard_pending_return(p) tv_free((typval_T *)(p))
/*
* When several errors appear in a row, setting "force_abort" is delayed until
@@ -779,7 +782,6 @@ void report_discard_pending(int pending, void *value)
*/
void ex_if(exarg_T *eap)
{
- int error;
int skip;
int result;
struct condstack *cstack = eap->cstack;
@@ -800,6 +802,7 @@ void ex_if(exarg_T *eap)
1] &
CSF_ACTIVE));
+ bool error;
result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
if (!skip && !error) {
@@ -844,7 +847,6 @@ void ex_endif(exarg_T *eap)
*/
void ex_else(exarg_T *eap)
{
- int error;
int skip;
int result;
struct condstack *cstack = eap->cstack;
@@ -901,6 +903,7 @@ void ex_else(exarg_T *eap)
}
if (eap->cmdidx == CMD_elseif) {
+ bool error;
result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
/* When throwing error exceptions, we want to throw always the first
* of several errors in a row. This is what actually happens when
@@ -925,7 +928,7 @@ void ex_else(exarg_T *eap)
*/
void ex_while(exarg_T *eap)
{
- int error;
+ bool error;
int skip;
int result;
struct condstack *cstack = eap->cstack;
@@ -1147,23 +1150,25 @@ void ex_endwhile(exarg_T *eap)
*/
void ex_throw(exarg_T *eap)
{
- char_u *arg = eap->arg;
- char_u *value;
+ const char *arg = (const char *)eap->arg;
+ char *value;
- if (*arg != NUL && *arg != '|' && *arg != '\n')
- value = eval_to_string_skip(arg, &eap->nextcmd, eap->skip);
- else {
+ if (*arg != NUL && *arg != '|' && *arg != '\n') {
+ value = eval_to_string_skip(arg, (const char **)&eap->nextcmd,
+ (bool)eap->skip);
+ } else {
EMSG(_(e_argreq));
value = NULL;
}
- /* On error or when an exception is thrown during argument evaluation, do
- * not throw. */
+ // On error or when an exception is thrown during argument evaluation, do
+ // not throw.
if (!eap->skip && value != NULL) {
- if (throw_exception(value, ET_USER, NULL) == FAIL)
+ if (throw_exception((char_u *)value, ET_USER, NULL) == FAIL) {
xfree(value);
- else
+ } else {
do_throw(eap->cstack);
+ }
}
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index f7e10f3787..6d23ba9913 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <inttypes.h>
+#include "nvim/assert.h"
#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/arabic.h"
@@ -578,7 +579,7 @@ static int command_line_execute(VimState *state, int key)
}
if (vim_ispathsep(ccline.cmdbuff[s->j])
#ifdef BACKSLASH_IN_FILENAME
- && vim_strchr(" *?[{`$%#", ccline.cmdbuff[s->j + 1])
+ && strchr(" *?[{`$%#", ccline.cmdbuff[s->j + 1])
== NULL
#endif
) {
@@ -960,7 +961,7 @@ static int command_line_handle_key(CommandLineState *s)
return command_line_not_changed(s);
case Ctrl_HAT:
- if (map_to_exists_mode((char_u *)"", LANGMAP, false)) {
+ if (map_to_exists_mode("", LANGMAP, false)) {
// ":lmap" mappings exists, toggle use of mappings.
State ^= LANGMAP;
if (s->b_im_ptr != NULL) {
@@ -2553,19 +2554,22 @@ void cmdline_paste_str(char_u *s, int literally)
else
while (*s != NUL) {
cv = *s;
- if (cv == Ctrl_V && s[1])
- ++s;
- if (has_mbyte)
- c = mb_cptr2char_adv(&s);
- else
+ if (cv == Ctrl_V && s[1]) {
+ s++;
+ }
+ if (has_mbyte) {
+ c = mb_cptr2char_adv((const char_u **)&s);
+ } else {
c = *s++;
+ }
if (cv == Ctrl_V || c == ESC || c == Ctrl_C
|| c == CAR || c == NL || c == Ctrl_L
#ifdef UNIX
|| c == intr_char
#endif
- || (c == Ctrl_BSL && *s == Ctrl_N))
+ || (c == Ctrl_BSL && *s == Ctrl_N)) {
stuffcharReadbuff(Ctrl_V);
+ }
stuffcharReadbuff(c);
}
}
@@ -3120,9 +3124,10 @@ void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int o
#endif
}
#ifdef BACKSLASH_IN_FILENAME
- p = vim_strsave_fnameescape(files[i], FALSE);
+ p = (char_u *)vim_strsave_fnameescape((const char *)files[i], false);
#else
- p = vim_strsave_fnameescape(files[i], xp->xp_shell);
+ p = (char_u *)vim_strsave_fnameescape((const char *)files[i],
+ xp->xp_shell);
#endif
xfree(files[i]);
files[i] = p;
@@ -3152,42 +3157,49 @@ void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int o
}
}
-/*
- * Escape special characters in "fname" for when used as a file name argument
- * after a Vim command, or, when "shell" is non-zero, a shell command.
- * Returns the result in allocated memory.
- */
-char_u *vim_strsave_fnameescape(char_u *fname, int shell) FUNC_ATTR_NONNULL_RET
+/// Escape special characters in a file name for use as a command argument
+///
+/// @param[in] fname File name to escape.
+/// @param[in] shell What to escape for: if false, escapes for VimL command,
+/// if true then it escapes for a shell command.
+///
+/// @return [allocated] escaped file name.
+char *vim_strsave_fnameescape(const char *const fname, const bool shell)
+ FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{
- char_u *p;
#ifdef BACKSLASH_IN_FILENAME
-#define PATH_ESC_CHARS ((char_u *)" \t\n*?[{`%#'\"|!<")
- char_u buf[20];
+#define PATH_ESC_CHARS " \t\n*?[{`%#'\"|!<"
+ char_u buf[sizeof(PATH_ESC_CHARS)];
int j = 0;
- /* Don't escape '[', '{' and '!' if they are in 'isfname'. */
- for (p = PATH_ESC_CHARS; *p != NUL; ++p)
- if ((*p != '[' && *p != '{' && *p != '!') || !vim_isfilec(*p))
- buf[j++] = *p;
+ // Don't escape '[', '{' and '!' if they are in 'isfname'.
+ for (const char *s = PATH_ESC_CHARS; *s != NUL; s++) {
+ if ((*s != '[' && *s != '{' && *s != '!') || !vim_isfilec(*s)) {
+ buf[j++] = *s;
+ }
+ }
buf[j] = NUL;
- p = vim_strsave_escaped(fname, buf);
+ char *p = (char *)vim_strsave_escaped((const char_u *)fname,
+ (const char_u *)buf);
#else
#define PATH_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<")
#define SHELL_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<>();&")
- p = vim_strsave_escaped(fname, shell ? SHELL_ESC_CHARS : PATH_ESC_CHARS);
+ char *p = (char *)vim_strsave_escaped(
+ (const char_u *)fname, (shell ? SHELL_ESC_CHARS : PATH_ESC_CHARS));
if (shell && csh_like_shell()) {
- /* For csh and similar shells need to put two backslashes before '!'.
- * One is taken by Vim, one by the shell. */
- char_u *s = vim_strsave_escaped(p, (char_u *)"!");
+ // For csh and similar shells need to put two backslashes before '!'.
+ // One is taken by Vim, one by the shell.
+ char *s = (char *)vim_strsave_escaped((const char_u *)p,
+ (const char_u *)"!");
xfree(p);
p = s;
}
#endif
- /* '>' and '+' are special at the start of some commands, e.g. ":edit" and
- * ":write". "cd -" has a special meaning. */
+ // '>' and '+' are special at the start of some commands, e.g. ":edit" and
+ // ":write". "cd -" has a special meaning.
if (*p == '>' || *p == '+' || (*p == '-' && p[1] == NUL)) {
- escape_fname(&p);
+ escape_fname((char_u **)&p);
}
return p;
@@ -3624,7 +3636,6 @@ set_cmd_context (
)
{
int old_char = NUL;
- char_u *nextcomm;
/*
* Avoid a UMR warning from Purify, only save the character if it has been
@@ -3633,7 +3644,7 @@ set_cmd_context (
if (col < len)
old_char = str[col];
str[col] = NUL;
- nextcomm = str;
+ const char *nextcomm = (const char *)str;
if (use_ccline && ccline.cmdfirstc == '=') {
// pass CMD_SIZE because there is no real command
@@ -3642,9 +3653,11 @@ set_cmd_context (
xp->xp_context = ccline.xp_context;
xp->xp_pattern = ccline.cmdbuff;
xp->xp_arg = ccline.xp_arg;
- } else
- while (nextcomm != NULL)
+ } else {
+ while (nextcomm != NULL) {
nextcomm = set_one_cmd_context(xp, nextcomm);
+ }
+ }
/* Store the string here so that call_user_expand_func() can get to them
* easily. */
@@ -4197,9 +4210,11 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file,
char_u keep;
garray_T ga;
- retstr = call_user_expand_func(call_func_retstr, xp, num_file, file);
- if (retstr == NULL)
+ retstr = call_user_expand_func((user_expand_func_T)call_func_retstr, xp,
+ num_file, file);
+ if (retstr == NULL) {
return FAIL;
+ }
ga_init(&ga, (int)sizeof(char *), 3);
for (s = retstr; *s != NUL; s = e) {
@@ -4237,9 +4252,11 @@ static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file)
listitem_T *li;
garray_T ga;
- retlist = call_user_expand_func(call_func_retlist, xp, num_file, file);
- if (retlist == NULL)
+ retlist = call_user_expand_func((user_expand_func_T)call_func_retlist, xp,
+ num_file, file);
+ if (retlist == NULL) {
return FAIL;
+ }
ga_init(&ga, (int)sizeof(char *), 3);
/* Loop over the items in the list. */
@@ -4249,7 +4266,7 @@ static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file)
GA_APPEND(char_u *, &ga, vim_strsave(li->li_tv.vval.v_string));
}
- list_unref(retlist);
+ tv_list_unref(retlist);
*file = ga.ga_data;
*num_file = ga.ga_len;
@@ -4545,7 +4562,7 @@ static inline void hist_free_entry(histentry_T *hisptr)
FUNC_ATTR_NONNULL_ALL
{
xfree(hisptr->hisstr);
- list_unref(hisptr->additional_elements);
+ tv_list_unref(hisptr->additional_elements);
clear_hist_entry(hisptr);
}
@@ -4601,7 +4618,7 @@ in_history (
history[type][last_i] = history[type][i];
last_i = i;
}
- list_unref(list);
+ tv_list_unref(list);
history[type][i].hisnum = ++hisnum[type];
history[type][i].hisstr = str;
history[type][i].timestamp = os_time();
@@ -4623,7 +4640,7 @@ in_history (
///
/// @return Any value from HistoryType enum, including HIST_INVALID. May not
/// return HIST_DEFAULT unless return_default is true.
-HistoryType get_histtype(const char_u *const name, const size_t len,
+HistoryType get_histtype(const char *const name, const size_t len,
const bool return_default)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -4677,8 +4694,8 @@ add_to_history (
* down, only lines that were added.
*/
if (histype == HIST_SEARCH && in_map) {
- if (maptick == last_maptick) {
- /* Current line is from the same mapping, remove it */
+ if (maptick == last_maptick && hisidx[HIST_SEARCH] >= 0) {
+ // Current line is from the same mapping, remove it
hisptr = &history[HIST_SEARCH][hisidx[HIST_SEARCH]];
hist_free_entry(hisptr);
--hisnum[histype];
@@ -5016,7 +5033,7 @@ void ex_history(exarg_T *eap)
while (ASCII_ISALPHA(*end)
|| vim_strchr((char_u *)":=@>/?", *end) != NULL)
end++;
- histype1 = get_histtype(arg, end - arg, false);
+ histype1 = get_histtype((const char *)arg, end - arg, false);
if (histype1 == HIST_INVALID) {
if (STRNICMP(arg, "all", end - arg) == 0) {
histype1 = 0;
@@ -5173,7 +5190,7 @@ static int ex_window(void)
// Create empty command-line buffer.
buf_open_scratch(0, "[Command Line]");
// Command-line buffer has bufhidden=wipe, unlike a true "scratch" buffer.
- set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL);
+ set_option_value("bh", 0L, "wipe", OPT_LOCAL);
curwin->w_p_rl = cmdmsg_rl;
cmdmsg_rl = false;
curbuf->b_p_ma = true;
@@ -5191,7 +5208,7 @@ static int ex_window(void)
add_map((char_u *)"<buffer> <Tab> <C-X><C-V>", INSERT);
add_map((char_u *)"<buffer> <Tab> a<C-X><C-V>", NORMAL);
}
- set_option_value((char_u *)"ft", 0L, (char_u *)"vim", OPT_LOCAL);
+ set_option_value("ft", 0L, "vim", OPT_LOCAL);
}
/* Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin
@@ -5275,18 +5292,18 @@ static int ex_window(void)
cmdwin_result = Ctrl_C;
/* Set the new command line from the cmdline buffer. */
xfree(ccline.cmdbuff);
- if (cmdwin_result == K_XF1 || cmdwin_result == K_XF2) { /* :qa[!] typed */
- char *p = (cmdwin_result == K_XF2) ? "qa" : "qa!";
+ if (cmdwin_result == K_XF1 || cmdwin_result == K_XF2) { // :qa[!] typed
+ const char *p = (cmdwin_result == K_XF2) ? "qa" : "qa!";
if (histtype == HIST_CMD) {
- /* Execute the command directly. */
- ccline.cmdbuff = vim_strsave((char_u *)p);
+ // Execute the command directly.
+ ccline.cmdbuff = (char_u *)xstrdup(p);
cmdwin_result = CAR;
} else {
- /* First need to cancel what we were doing. */
+ // First need to cancel what we were doing.
ccline.cmdbuff = NULL;
stuffcharReadbuff(':');
- stuffReadbuff((char_u *)p);
+ stuffReadbuff(p);
stuffcharReadbuff(CAR);
}
} else if (cmdwin_result == K_XF2) { /* :qa typed */
diff --git a/src/nvim/ex_getln.h b/src/nvim/ex_getln.h
index 24eebdc303..5a1ca5213a 100644
--- a/src/nvim/ex_getln.h
+++ b/src/nvim/ex_getln.h
@@ -1,7 +1,7 @@
#ifndef NVIM_EX_GETLN_H
#define NVIM_EX_GETLN_H
-#include "nvim/eval_defs.h"
+#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
/* Values for nextwild() and ExpandOne(). See ExpandOne() for meaning. */
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index b73d9944ce..9592235905 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -322,8 +322,11 @@ vim_findfile_init (
drive[0] = path[0];
drive[1] = ':';
drive[2] = NUL;
- if (vim_FullName(drive, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
+ if (vim_FullName((const char *)drive, (char *)ff_expand_buffer, MAXPATHL,
+ true)
+ == FAIL) {
goto error_return;
+ }
path += 2;
} else
#endif
@@ -1549,14 +1552,14 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope)
assert(false);
}
- dict_add_nr_str(dict, "scope", 0L, (char_u *)buf);
- dict_add_nr_str(dict, "cwd", 0L, (char_u *)new_dir);
- dict_set_keys_readonly(dict);
+ tv_dict_add_str(dict, S_LEN("scope"), buf);
+ tv_dict_add_str(dict, S_LEN("cwd"), new_dir);
+ tv_dict_set_keys_readonly(dict);
apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, (char_u *)new_dir, false,
NULL);
- dict_clear(dict);
+ tv_dict_clear(dict);
recursive = false;
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index d948e20b32..c1b8203ed1 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -200,18 +200,14 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr)
{
int msg_scroll_save;
- if (msg_silent != 0)
+ if (msg_silent != 0) {
return;
- msg_add_fname(buf, name); /* put file name in IObuff with quotes */
- /* If it's extremely long, truncate it. */
- if (STRLEN(IObuff) > IOSIZE - 80)
- IObuff[IOSIZE - 80] = NUL;
- STRCAT(IObuff, s);
- /*
- * For the first message may have to start a new line.
- * For further ones overwrite the previous one, reset msg_scroll before
- * calling filemess().
- */
+ }
+ add_quoted_fname((char *)IObuff, IOSIZE - 80, buf, (const char *)name);
+ xstrlcat((char *)IObuff, (const char *)s, IOSIZE);
+ // For the first message may have to start a new line.
+ // For further ones overwrite the previous one, reset msg_scroll before
+ // calling filemess().
msg_scroll_save = msg_scroll;
if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
msg_scroll = FALSE;
@@ -428,7 +424,7 @@ readfile (
}
if (!read_buffer && !read_stdin) {
- perm = os_getperm(fname);
+ perm = os_getperm((const char *)fname);
#ifdef UNIX
// On Unix it is possible to read a directory, so we have to
// check for it before os_open().
@@ -614,10 +610,12 @@ readfile (
return FAIL;
}
#ifdef UNIX
- /* Set swap file protection bits after creating it. */
+ // Set swap file protection bits after creating it.
if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL
- && curbuf->b_ml.ml_mfp->mf_fname != NULL)
- (void)os_setperm(curbuf->b_ml.ml_mfp->mf_fname, (long)swap_mode);
+ && curbuf->b_ml.ml_mfp->mf_fname != NULL) {
+ (void)os_setperm((const char *)curbuf->b_ml.ml_mfp->mf_fname,
+ (long)swap_mode);
+ }
#endif
}
@@ -1798,8 +1796,8 @@ failed:
}
if (!filtering && !(flags & READ_DUMMY)) {
- msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */
- c = FALSE;
+ add_quoted_fname((char *)IObuff, IOSIZE, curbuf, (const char *)sfname);
+ c = false;
#ifdef UNIX
# ifdef S_ISFIFO
@@ -2256,9 +2254,16 @@ buf_write (
int len;
linenr_T lnum;
long nchars;
- char_u *errmsg = NULL;
- int errmsg_allocated = FALSE;
- char_u *errnum = NULL;
+#define SET_ERRMSG_NUM(num, msg) \
+ errnum = num, errmsg = msg, errmsgarg = 0
+#define SET_ERRMSG_ARG(msg, error) \
+ errnum = NULL, errmsg = msg, errmsgarg = error
+#define SET_ERRMSG(msg) \
+ errnum = NULL, errmsg = msg, errmsgarg = 0
+ const char *errnum = NULL;
+ char *errmsg = NULL;
+ int errmsgarg = 0;
+ bool errmsg_allocated = false;
char_u *buffer;
char_u smallbuf[SMBUFSIZE];
char_u *backup_ext;
@@ -2280,7 +2285,6 @@ buf_write (
/* writing everything */
int whole = (start == 1 && end == buf->b_ml.ml_line_count);
linenr_T old_line_count = buf->b_ml.ml_line_count;
- int attr;
int fileformat;
int write_bin;
struct bw_info write_info; /* info for buf_write_bytes() */
@@ -2575,13 +2579,11 @@ buf_write (
perm = file_info_old.stat.st_mode;
if (!S_ISREG(file_info_old.stat.st_mode)) { /* not a file */
if (S_ISDIR(file_info_old.stat.st_mode)) {
- errnum = (char_u *)"E502: ";
- errmsg = (char_u *)_("is a directory");
+ SET_ERRMSG_NUM("E502", _("is a directory"));
goto fail;
}
if (os_nodetype((char *)fname) != NODE_WRITABLE) {
- errnum = (char_u *)"E503: ";
- errmsg = (char_u *)_("is not a file or writable device");
+ SET_ERRMSG_NUM("E503", _("is not a file or writable device"));
goto fail;
}
/* It's a device of some kind (or a fifo) which we can write to
@@ -2597,8 +2599,7 @@ buf_write (
*/
c = os_nodetype((char *)fname);
if (c == NODE_OTHER) {
- errnum = (char_u *)"E503: ";
- errmsg = (char_u *)_("is not a file or writable device");
+ SET_ERRMSG_NUM("E503", _("is not a file or writable device"));
goto fail;
}
if (c == NODE_WRITABLE) {
@@ -2606,12 +2607,11 @@ buf_write (
newfile = TRUE;
perm = -1;
} else {
- perm = os_getperm(fname);
- if (perm < 0)
- newfile = TRUE;
- else if (os_isdir(fname)) {
- errnum = (char_u *)"E502: ";
- errmsg = (char_u *)_("is a directory");
+ perm = os_getperm((const char *)fname);
+ if (perm < 0) {
+ newfile = true;
+ } else if (os_isdir(fname)) {
+ SET_ERRMSG_NUM("E502", _("is a directory"));
goto fail;
}
if (overwriting) {
@@ -2630,11 +2630,9 @@ buf_write (
if (!forceit && file_readonly) {
if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
- errnum = (char_u *)"E504: ";
- errmsg = (char_u *)_(err_readonly);
+ SET_ERRMSG_NUM("E504", _(err_readonly));
} else {
- errnum = (char_u *)"E505: ";
- errmsg = (char_u *)_("is read-only (add ! to override)");
+ SET_ERRMSG_NUM("E505", _("is read-only (add ! to override)"));
}
goto fail;
}
@@ -2870,9 +2868,9 @@ buf_write (
xfree(backup);
backup = NULL;
} else {
- /* set file protection same as original file, but
- * strip s-bit */
- (void)os_setperm(backup, perm & 0777);
+ // set file protection same as original file, but
+ // strip s-bit.
+ (void)os_setperm((const char *)backup, perm & 0777);
#ifdef UNIX
/*
@@ -2883,7 +2881,8 @@ buf_write (
*/
if (file_info_new.stat.st_gid != file_info_old.stat.st_gid
&& os_fchown(bfd, -1, file_info_old.stat.st_gid) != 0) {
- os_setperm(backup, (perm & 0707) | ((perm & 07) << 3));
+ os_setperm((const char *)backup,
+ (perm & 0707) | ((perm & 07) << 3));
}
# ifdef HAVE_SELINUX
mch_copy_sec(fname, backup);
@@ -2901,23 +2900,27 @@ buf_write (
while ((write_info.bw_len = read_eintr(fd, copybuf,
BUFSIZE)) > 0) {
if (buf_write_bytes(&write_info) == FAIL) {
- errmsg = (char_u *)_(
- "E506: Can't write to backup file (add ! to override)");
+ SET_ERRMSG(_(
+ "E506: Can't write to backup file (add ! to override)"));
break;
}
os_breakcheck();
if (got_int) {
- errmsg = (char_u *)_(e_interr);
+ SET_ERRMSG(_(e_interr));
break;
}
}
- if (close(bfd) < 0 && errmsg == NULL)
- errmsg = (char_u *)_(
- "E507: Close error for backup file (add ! to override)");
- if (write_info.bw_len < 0)
- errmsg = (char_u *)_(
- "E508: Can't read file for backup (add ! to override)");
+ int error;
+ if ((error = os_close(bfd)) != 0 && errmsg == NULL) {
+ SET_ERRMSG_ARG(_("E507: Close error for backup file "
+ "(add ! to override): %s"),
+ error);
+ }
+ if (write_info.bw_len < 0) {
+ SET_ERRMSG(_(
+ "E508: Can't read file for backup (add ! to override)"));
+ }
#ifdef UNIX
set_file_time(backup,
file_info_old.stat.st_atim.tv_sec,
@@ -2934,18 +2937,19 @@ buf_write (
}
}
nobackup:
- close(fd); /* ignore errors for closing read file */
+ os_close(fd); // Ignore errors for closing read file.
xfree(copybuf);
- if (backup == NULL && errmsg == NULL)
- errmsg = (char_u *)_(
- "E509: Cannot create backup file (add ! to override)");
- /* ignore errors when forceit is TRUE */
+ if (backup == NULL && errmsg == NULL) {
+ SET_ERRMSG(_(
+ "E509: Cannot create backup file (add ! to override)"));
+ }
+ // Ignore errors when forceit is TRUE.
if ((some_error || errmsg != NULL) && !forceit) {
retval = FAIL;
goto fail;
}
- errmsg = NULL;
+ SET_ERRMSG(NULL);
} else {
char_u *dirp;
char_u *p;
@@ -2960,8 +2964,7 @@ nobackup:
* anyway, thus we need an extra check here.
*/
if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
- errnum = (char_u *)"E504: ";
- errmsg = (char_u *)_(err_readonly);
+ SET_ERRMSG_NUM("E504", _(err_readonly));
goto fail;
}
@@ -3025,7 +3028,7 @@ nobackup:
}
}
if (backup == NULL && !forceit) {
- errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)");
+ SET_ERRMSG(_("E510: Can't make backup file (add ! to override)"));
goto fail;
}
}
@@ -3037,8 +3040,8 @@ nobackup:
&& file_info_old.stat.st_uid == getuid()
&& vim_strchr(p_cpo, CPO_FWRITE) == NULL) {
perm |= 0200;
- (void)os_setperm(fname, perm);
- made_writable = TRUE;
+ (void)os_setperm((const char *)fname, perm);
+ made_writable = true;
}
#endif
@@ -3066,7 +3069,7 @@ nobackup:
&& !(exiting && backup != NULL)) {
ml_preserve(buf, FALSE);
if (got_int) {
- errmsg = (char_u *)_(e_interr);
+ SET_ERRMSG(_(e_interr));
goto restore_backup;
}
}
@@ -3137,8 +3140,8 @@ nobackup:
*/
if (*p_ccv != NUL) {
wfname = vim_tempname();
- if (wfname == NULL) { /* Can't write without a tempfile! */
- errmsg = (char_u *)_("E214: Can't find temp file for writing");
+ if (wfname == NULL) { // Can't write without a tempfile!
+ SET_ERRMSG(_("E214: Can't find temp file for writing"));
goto restore_backup;
}
}
@@ -3150,8 +3153,8 @@ nobackup:
&& wfname == fname
) {
if (!forceit) {
- errmsg = (char_u *)_(
- "E213: Cannot convert (add ! to write without conversion)");
+ SET_ERRMSG(_(
+ "E213: Cannot convert (add ! to write without conversion)"));
goto restore_backup;
}
notconverted = TRUE;
@@ -3186,11 +3189,10 @@ nobackup:
if ((!newfile && os_fileinfo_hardlinks(&file_info) > 1)
|| (os_fileinfo_link((char *)fname, &file_info)
&& !os_fileinfo_id_equal(&file_info, &file_info_old))) {
- errmsg = (char_u *)_("E166: Can't open linked file for writing");
- } else
+ SET_ERRMSG(_("E166: Can't open linked file for writing"));
+ } else {
#endif
- {
- errmsg = (char_u *)_("E212: Can't open file for writing");
+ SET_ERRMSG_ARG(_("E212: Can't open file for writing: %s"), fd);
if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
&& perm >= 0) {
#ifdef UNIX
@@ -3208,7 +3210,9 @@ nobackup:
os_remove((char *)wfname);
continue;
}
+#ifdef UNIX
}
+#endif
}
restore_backup:
@@ -3250,7 +3254,7 @@ restore_backup:
xfree(wfname);
goto fail;
}
- errmsg = NULL;
+ SET_ERRMSG(NULL);
write_info.bw_fd = fd;
@@ -3370,7 +3374,6 @@ restore_backup:
nchars += len;
}
-#if defined(UNIX)
// On many journalling file systems there is a bug that causes both the
// original and the backup file to be lost when halting the system right
// after writing the file. That's because only the meta-data is
@@ -3379,11 +3382,11 @@ restore_backup:
// For a device do try the fsync() but don't complain if it does not work
// (could be a pipe).
// If the 'fsync' option is FALSE, don't fsync(). Useful for laptops.
- if (p_fs && os_fsync(fd) != 0 && !device) {
- errmsg = (char_u *)_("E667: Fsync failed");
+ int error;
+ if (p_fs && (error = os_fsync(fd)) != 0 && !device) {
+ SET_ERRMSG_ARG(_("E667: Fsync failed: %s"), error);
end = 0;
}
-#endif
#ifdef HAVE_SELINUX
/* Probably need to set the security context. */
@@ -3402,8 +3405,9 @@ restore_backup:
|| file_info.stat.st_uid != file_info_old.stat.st_uid
|| file_info.stat.st_gid != file_info_old.stat.st_gid) {
os_fchown(fd, file_info_old.stat.st_uid, file_info_old.stat.st_gid);
- if (perm >= 0) /* set permission again, may have changed */
- (void)os_setperm(wfname, perm);
+ if (perm >= 0) { // Set permission again, may have changed.
+ (void)os_setperm((const char *)wfname, perm);
+ }
}
buf_set_file_id(buf);
} else if (!buf->file_id_valid) {
@@ -3412,8 +3416,8 @@ restore_backup:
}
#endif
- if (close(fd) != 0) {
- errmsg = (char_u *)_("E512: Close failed");
+ if ((error = os_close(fd)) != 0) {
+ SET_ERRMSG_ARG(_("E512: Close failed: %s"), error);
end = 0;
}
@@ -3421,8 +3425,9 @@ restore_backup:
if (made_writable)
perm &= ~0200; /* reset 'w' bit for security reasons */
#endif
- if (perm >= 0) /* set perm. of new file same as old file */
- (void)os_setperm(wfname, perm);
+ if (perm >= 0) { // Set perm. of new file same as old file.
+ (void)os_setperm((const char *)wfname, perm);
+ }
#ifdef HAVE_ACL
/* Probably need to set the ACL before changing the user (can't set the
* ACL on a file the user doesn't own). */
@@ -3449,21 +3454,24 @@ restore_backup:
if (end == 0) {
if (errmsg == NULL) {
if (write_info.bw_conv_error) {
- if (write_info.bw_conv_error_lnum == 0)
- errmsg = (char_u *)_(
- "E513: write error, conversion failed (make 'fenc' empty to override)");
- else {
- errmsg_allocated = TRUE;
- errmsg = xmalloc(300);
- vim_snprintf((char *)errmsg, 300,
- _("E513: write error, conversion failed in line %" PRId64
+ if (write_info.bw_conv_error_lnum == 0) {
+ SET_ERRMSG(_(
+ "E513: write error, conversion failed "
+ "(make 'fenc' empty to override)"));
+ } else {
+ errmsg_allocated = true;
+ SET_ERRMSG(xmalloc(300));
+ vim_snprintf(
+ errmsg, 300,
+ _("E513: write error, conversion failed in line %" PRIdLINENR
" (make 'fenc' empty to override)"),
- (int64_t)write_info.bw_conv_error_lnum);
+ write_info.bw_conv_error_lnum);
}
- } else if (got_int)
- errmsg = (char_u *)_(e_interr);
- else
- errmsg = (char_u *)_("E514: write error (file system full?)");
+ } else if (got_int) {
+ SET_ERRMSG(_(e_interr));
+ } else {
+ SET_ERRMSG(_("E514: write error (file system full?)"));
+ }
}
/*
@@ -3518,8 +3526,8 @@ restore_backup:
fname = sfname; /* use shortname now, for the messages */
#endif
if (!filtering) {
- msg_add_fname(buf, fname); /* put fname in IObuff with quotes */
- c = FALSE;
+ add_quoted_fname((char *)IObuff, IOSIZE, buf, (const char *)fname);
+ c = false;
if (write_info.bw_conv_error) {
STRCAT(IObuff, _(" CONVERSION ERROR"));
c = TRUE;
@@ -3628,7 +3636,7 @@ restore_backup:
close(empty_fd);
}
if (org != NULL) {
- os_setperm((char_u *)org, os_getperm(fname) & 0777);
+ os_setperm(org, os_getperm((const char *)fname) & 0777);
xfree(org);
}
}
@@ -3668,33 +3676,32 @@ nofail:
#endif
if (errmsg != NULL) {
- int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0;
-
- attr = hl_attr(HLF_E); /* set highlight for error messages */
- msg_add_fname(buf,
+ // - 100 to save some space for further error message
#ifndef UNIX
- sfname
+ add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)sfname);
#else
- fname
+ add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)fname);
#endif
- ); /* put file name in IObuff with quotes */
- if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE)
- IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL;
- /* If the error message has the form "is ...", put the error number in
- * front of the file name. */
if (errnum != NULL) {
- STRMOVE(IObuff + numlen, IObuff);
- memmove(IObuff, errnum, (size_t)numlen);
+ if (errmsgarg != 0) {
+ emsgf("%s: %s%s: %s", errnum, IObuff, errmsg, os_strerror(errmsgarg));
+ } else {
+ emsgf("%s: %s%s", errnum, IObuff, errmsg);
+ }
+ } else if (errmsgarg != 0) {
+ emsgf(errmsg, os_strerror(errmsgarg));
+ } else {
+ emsgf(errmsg);
}
- STRCAT(IObuff, errmsg);
- emsg(IObuff);
- if (errmsg_allocated)
+ if (errmsg_allocated) {
xfree(errmsg);
+ }
retval = FAIL;
if (end == 0) {
+ const int attr = hl_attr(HLF_E); // Set highlight for error messages.
MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n"),
- attr | MSG_HIST);
+ attr | MSG_HIST);
MSG_PUTS_ATTR(_(
"don't quit the editor until the file is successfully written!"),
attr | MSG_HIST);
@@ -3754,6 +3761,9 @@ nofail:
got_int |= prev_got_int;
return retval;
+#undef SET_ERRMSG
+#undef SET_ERRMSG_ARG
+#undef SET_ERRMSG_NUM
}
/*
@@ -3797,16 +3807,25 @@ static int set_rw_fname(char_u *fname, char_u *sfname)
return OK;
}
-/*
- * Put file name into IObuff with quotes.
- */
-void msg_add_fname(buf_T *buf, char_u *fname)
+/// Put file name into the specified buffer with quotes
+///
+/// Replaces home directory at the start with `~`.
+///
+/// @param[out] ret_buf Buffer to save results to.
+/// @param[in] buf_len ret_buf length.
+/// @param[in] buf buf_T file name is coming from.
+/// @param[in] fname File name to write.
+static void add_quoted_fname(char *const ret_buf, const size_t buf_len,
+ const buf_T *const buf, const char *fname)
+ FUNC_ATTR_NONNULL_ARG(1)
{
- if (fname == NULL)
- fname = (char_u *)"-stdin-";
- home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE);
- IObuff[0] = '"';
- STRCAT(IObuff, "\" ");
+ if (fname == NULL) {
+ fname = "-stdin-";
+ }
+ ret_buf[0] = '"';
+ home_replace(buf, (const char_u *)fname, (char_u *)ret_buf + 1,
+ (int)buf_len - 4, true);
+ xstrlcat(ret_buf, "\" ", buf_len);
}
/// Append message for text mode to IObuff.
@@ -4548,9 +4567,9 @@ int put_time(FILE *fd, time_t time_)
/// os_rename() only works if both files are on the same file system, this
/// function will (attempts to?) copy the file across if rename fails -- webb
-//
+///
/// @return -1 for failure, 0 for success
-int vim_rename(char_u *from, char_u *to)
+int vim_rename(const char_u *from, const char_u *to)
{
int fd_in;
int fd_out;
@@ -4569,10 +4588,12 @@ int vim_rename(char_u *from, char_u *to)
* the file name differs we need to go through a temp file.
*/
if (fnamecmp(from, to) == 0) {
- if (p_fic && STRCMP(path_tail(from), path_tail(to)) != 0)
+ if (p_fic && (STRCMP(path_tail((char_u *)from), path_tail((char_u *)to))
+ != 0)) {
use_tmp_file = true;
- else
+ } else {
return 0;
+ }
}
// Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
@@ -4638,9 +4659,9 @@ int vim_rename(char_u *from, char_u *to)
/*
* Rename() failed, try copying the file.
*/
- perm = os_getperm(from);
+ perm = os_getperm((const char *)from);
#ifdef HAVE_ACL
- /* For systems that support ACL: get the ACL from the original file. */
+ // For systems that support ACL: get the ACL from the original file.
acl = mch_get_acl(from);
#endif
fd_in = os_open((char *)from, O_RDONLY, 0);
@@ -4688,8 +4709,8 @@ int vim_rename(char_u *from, char_u *to)
errmsg = _("E210: Error reading \"%s\"");
to = from;
}
-#ifndef UNIX /* for Unix os_open() already set the permission */
- os_setperm(to, perm);
+#ifndef UNIX // For Unix os_open() already set the permission.
+ os_setperm((const char *)to, perm);
#endif
#ifdef HAVE_ACL
mch_set_acl(to, acl);
@@ -5200,7 +5221,7 @@ void forward_slash(char_u *fname)
{
char_u *p;
- if (path_with_url(fname)) {
+ if (path_with_url((const char *)fname)) {
return;
}
for (p = fname; *p != NUL; p++) {
@@ -5261,7 +5282,7 @@ static void vim_maketempdir(void)
/// Delete "name" and everything in it, recursively.
/// @param name The path which should be deleted.
/// @return 0 for success, -1 if some file was not deleted.
-int delete_recursive(char_u *name)
+int delete_recursive(const char *name)
{
int result = 0;
@@ -5275,7 +5296,7 @@ int delete_recursive(char_u *name)
EW_DIR | EW_FILE | EW_SILENT | EW_ALLLINKS
| EW_DODOT | EW_EMPTYOK) == OK) {
for (int i = 0; i < file_count; i++) {
- if (delete_recursive(files[i]) != 0) {
+ if (delete_recursive((const char *)files[i]) != 0) {
result = -1;
}
}
@@ -5285,9 +5306,9 @@ int delete_recursive(char_u *name)
}
xfree(exp);
- os_rmdir((char *)name);
+ os_rmdir(name);
} else {
- result = os_remove((char *)name) == 0 ? 0 : -1;
+ result = os_remove(name) == 0 ? 0 : -1;
}
return result;
@@ -5299,7 +5320,7 @@ void vim_deltempdir(void)
if (vim_tempdir != NULL) {
// remove the trailing path separator
path_tail(vim_tempdir)[-1] = NUL;
- delete_recursive(vim_tempdir);
+ delete_recursive((const char *)vim_tempdir);
xfree(vim_tempdir);
vim_tempdir = NULL;
}
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 36a5b0efd7..d810aee0ce 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -2232,32 +2232,51 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *gap, int level,
* before where we started looking, extend it. If it
* starts at another line, update nested folds to keep
* their position, compensating for the new fd_top. */
- if (fp->fd_top >= startlnum && fp->fd_top != firstlnum) {
- if (fp->fd_top > firstlnum)
- /* like lines are inserted */
+ if (fp->fd_top == firstlnum) {
+ // We have found a fold beginning exactly where we want one.
+ } else if (fp->fd_top >= startlnum) {
+ if (fp->fd_top > firstlnum) {
+ // We will move the start of this fold up, hence we move all
+ // nested folds (with relative line numbers) down.
foldMarkAdjustRecurse(&fp->fd_nested,
- (linenr_T)0, (linenr_T)MAXLNUM,
- (long)(fp->fd_top - firstlnum), 0L);
- else
- /* like lines are deleted */
+ (linenr_T)0, (linenr_T)MAXLNUM,
+ (long)(fp->fd_top - firstlnum), 0L);
+ } else {
+ // Will move fold down, move nested folds relatively up.
foldMarkAdjustRecurse(&fp->fd_nested,
- (linenr_T)0,
- (long)(firstlnum - fp->fd_top - 1),
- (linenr_T)MAXLNUM,
- (long)(fp->fd_top - firstlnum));
+ (linenr_T)0,
+ (long)(firstlnum - fp->fd_top - 1),
+ (linenr_T)MAXLNUM,
+ (long)(fp->fd_top - firstlnum));
+ }
fp->fd_len += fp->fd_top - firstlnum;
fp->fd_top = firstlnum;
- fold_changed = TRUE;
- } else if (flp->start != 0 && lvl == level
- && fp->fd_top != firstlnum) {
- /* Existing fold that includes startlnum must stop
- * if we find the start of a new fold at the same
- * level. Split it. Delete contained folds at
- * this point to split them too. */
- foldRemove(&fp->fd_nested, flp->lnum - fp->fd_top,
- flp->lnum - fp->fd_top);
+ fold_changed = true;
+ } else if ((flp->start != 0 && lvl == level)
+ || (firstlnum != startlnum)) {
+ // Before there was a fold spanning from above startlnum to below
+ // firstlnum. This fold is valid above startlnum (because we are
+ // not updating that range), but there is now a break in it.
+ // If the break is because we are now forced to start a new fold
+ // at the level "level" at line fline->lnum, then we need to
+ // split the fold at fline->lnum.
+ // If the break is because the range [startlnum, firstlnum) is
+ // now at a lower indent than "level", we need to split the fold
+ // in this range.
+ // Any splits have to be done recursively.
+ linenr_T breakstart;
+ linenr_T breakend;
+ if (firstlnum != startlnum) {
+ breakstart = startlnum;
+ breakend = firstlnum;
+ } else {
+ breakstart = flp->lnum;
+ breakend = flp->lnum;
+ }
+ foldRemove(&fp->fd_nested, breakstart - fp->fd_top,
+ breakend - fp->fd_top);
i = (int)(fp - (fold_T *)gap->ga_data);
- foldSplit(gap, i, flp->lnum, flp->lnum - 1);
+ foldSplit(gap, i, breakstart, breakend - 1);
fp = (fold_T *)gap->ga_data + i + 1;
/* If using the "marker" or "syntax" method, we
* need to continue until the end of the fold is
@@ -2267,6 +2286,16 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *gap, int level,
|| getlevel == foldlevelSyntax)
finish = TRUE;
}
+ if (fp->fd_top == startlnum && concat) {
+ i = (int)(fp - (fold_T *)gap->ga_data);
+ if (i != 0) {
+ fp2 = fp - 1;
+ if (fp2->fd_top + fp2->fd_len == fp->fd_top) {
+ foldMerge(fp2, gap, fp);
+ fp = fp2;
+ }
+ }
+ }
break;
}
if (fp->fd_top >= startlnum) {
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 0c131d7b33..b83681ad01 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -235,19 +235,18 @@ char_u *get_inserted(void)
return get_buffcont(&redobuff, FALSE);
}
-/*
- * Add string "s" after the current block of buffer "buf".
- * K_SPECIAL and CSI should have been escaped already.
- */
-static void
-add_buff (
- buffheader_T *buf,
- char_u *s,
- ssize_t slen // length of "s" or -1
-)
+/// Add string after the current block of the given buffer
+///
+/// K_SPECIAL and CSI should have been escaped already.
+///
+/// @param[out] buf Buffer to add to.
+/// @param[in] s String to add.
+/// @param[in] slen String length or -1 for NUL-terminated string.
+static void add_buff(buffheader_T *const buf, const char *const s,
+ ptrdiff_t slen)
{
if (slen < 0) {
- slen = (ssize_t)STRLEN(s);
+ slen = (ptrdiff_t)strlen(s);
}
if (slen == 0) { // don't add empty strings
return;
@@ -292,9 +291,8 @@ add_buff (
*/
static void add_num_buff(buffheader_T *buf, long n)
{
- char_u number[32];
-
- sprintf((char *)number, "%" PRId64, (int64_t)n);
+ char number[32];
+ snprintf(number, sizeof(number), "%ld", n);
add_buff(buf, number, -1L);
}
@@ -304,27 +302,29 @@ static void add_num_buff(buffheader_T *buf, long n)
*/
static void add_char_buff(buffheader_T *buf, int c)
{
- char_u bytes[MB_MAXBYTES + 1];
- int len;
- int i;
- char_u temp[4];
+ char bytes[MB_MAXBYTES + 1];
- if (IS_SPECIAL(c))
+ int len;
+ if (IS_SPECIAL(c)) {
len = 1;
- else
- len = (*mb_char2bytes)(c, bytes);
- for (i = 0; i < len; ++i) {
- if (!IS_SPECIAL(c))
+ } else {
+ len = (*mb_char2bytes)(c, (char_u *)bytes);
+ }
+
+ for (int i = 0; i < len; i++) {
+ if (!IS_SPECIAL(c)) {
c = bytes[i];
+ }
+ char temp[4];
if (IS_SPECIAL(c) || c == K_SPECIAL || c == NUL) {
- /* translate special key code into three byte sequence */
- temp[0] = K_SPECIAL;
- temp[1] = (char_u)K_SECOND(c);
- temp[2] = (char_u)K_THIRD(c);
+ // Translate special key code into three byte sequence.
+ temp[0] = (char)K_SPECIAL;
+ temp[1] = (char)K_SECOND(c);
+ temp[2] = (char)K_THIRD(c);
temp[3] = NUL;
} else {
- temp[0] = (char_u)c;
+ temp[0] = (char)c;
temp[1] = NUL;
}
add_buff(buf, temp, -1L);
@@ -479,16 +479,14 @@ static int save_level = 0;
void saveRedobuff(void)
{
- char_u *s;
-
if (save_level++ == 0) {
save_redobuff = redobuff;
redobuff.bh_first.b_next = NULL;
save_old_redobuff = old_redobuff;
old_redobuff.bh_first.b_next = NULL;
- /* Make a copy, so that ":normal ." in a function works. */
- s = get_buffcont(&save_redobuff, FALSE);
+ // Make a copy, so that ":normal ." in a function works.
+ char *const s = (char *)get_buffcont(&save_redobuff, false);
if (s != NULL) {
add_buff(&redobuff, s, -1L);
xfree(s);
@@ -514,10 +512,11 @@ void restoreRedobuff(void)
* Append "s" to the redo buffer.
* K_SPECIAL and CSI should already have been escaped.
*/
-void AppendToRedobuff(char_u *s)
+void AppendToRedobuff(const char *s)
{
- if (!block_redo)
- add_buff(&redobuff, s, -1L);
+ if (!block_redo) {
+ add_buff(&redobuff, (const char *)s, -1L);
+ }
}
/*
@@ -530,44 +529,47 @@ AppendToRedobuffLit (
int len /* length of "str" or -1 for up to the NUL */
)
{
- char_u *s = str;
- int c;
- char_u *start;
-
- if (block_redo)
+ if (block_redo) {
return;
+ }
- while (len < 0 ? *s != NUL : s - str < len) {
- /* Put a string of normal characters in the redo buffer (that's
- * faster). */
- start = s;
- while (*s >= ' ' && *s < DEL && (len < 0 || s - str < len))
- ++s;
-
- /* Don't put '0' or '^' as last character, just in case a CTRL-D is
- * typed next. */
- if (*s == NUL && (s[-1] == '0' || s[-1] == '^'))
- --s;
- if (s > start)
+ const char *s = (const char *)str;
+ while (len < 0 ? *s != NUL : s - (const char *)str < len) {
+ // Put a string of normal characters in the redo buffer (that's
+ // faster).
+ const char *start = s;
+ while (*s >= ' ' && *s < DEL && (len < 0 || s - (const char *)str < len)) {
+ s++;
+ }
+
+ // Don't put '0' or '^' as last character, just in case a CTRL-D is
+ // typed next.
+ if (*s == NUL && (s[-1] == '0' || s[-1] == '^')) {
+ s--;
+ }
+ if (s > start) {
add_buff(&redobuff, start, (long)(s - start));
+ }
- if (*s == NUL || (len >= 0 && s - str >= len))
+ if (*s == NUL || (len >= 0 && s - (const char *)str >= len)) {
break;
+ }
- /* Handle a special or multibyte character. */
- if (has_mbyte)
- /* Handle composing chars separately. */
- c = mb_cptr2char_adv(&s);
- else
- c = *s++;
- if (c < ' ' || c == DEL || (*s == NUL && (c == '0' || c == '^')))
+ // Handle a special or multibyte character.
+ // Composing chars separately are handled separately.
+ const int c = (has_mbyte
+ ? mb_cptr2char_adv((const char_u **)&s)
+ : (uint8_t)(*s++));
+ if (c < ' ' || c == DEL || (*s == NUL && (c == '0' || c == '^'))) {
add_char_buff(&redobuff, Ctrl_V);
+ }
- /* CTRL-V '0' must be inserted as CTRL-V 048 */
- if (*s == NUL && c == '0')
- add_buff(&redobuff, (char_u *)"048", 3L);
- else
+ // CTRL-V '0' must be inserted as CTRL-V 048.
+ if (*s == NUL && c == '0') {
+ add_buff(&redobuff, "048", 3L);
+ } else {
add_char_buff(&redobuff, c);
+ }
}
}
@@ -594,19 +596,19 @@ void AppendNumberToRedobuff(long n)
* Append string "s" to the stuff buffer.
* CSI and K_SPECIAL must already have been escaped.
*/
-void stuffReadbuff(char_u *s)
+void stuffReadbuff(const char *s)
{
add_buff(&readbuf1, s, -1L);
}
/// Append string "s" to the redo stuff buffer.
/// @remark CSI and K_SPECIAL must already have been escaped.
-void stuffRedoReadbuff(char_u *s)
+void stuffRedoReadbuff(const char *s)
{
add_buff(&readbuf2, s, -1L);
}
-void stuffReadbuffLen(char_u *s, long len)
+void stuffReadbuffLen(const char *s, long len)
{
add_buff(&readbuf1, s, len);
}
@@ -616,19 +618,18 @@ void stuffReadbuffLen(char_u *s, long len)
* escaping other K_SPECIAL and CSI bytes.
* Change CR, LF and ESC into a space.
*/
-void stuffReadbuffSpec(char_u *s)
+void stuffReadbuffSpec(const char *s)
{
- int c;
-
while (*s != NUL) {
- if (*s == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
- /* Insert special key literally. */
- stuffReadbuffLen(s, 3L);
+ if ((uint8_t)(*s) == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
+ // Insert special key literally.
+ stuffReadbuffLen(s, 3);
s += 3;
} else {
- c = mb_ptr2char_adv(&s);
- if (c == CAR || c == NL || c == ESC)
+ int c = mb_ptr2char_adv((const char_u **)&s);
+ if (c == CAR || c == NL || c == ESC) {
c = ' ';
+ }
stuffcharReadbuff(c);
}
}
@@ -747,8 +748,8 @@ int start_redo(long count, int old_redo)
/* copy the buffer name, if present */
if (c == '"') {
- add_buff(&readbuf2, (char_u *)"\"", 1L);
- c = read_redo(FALSE, old_redo);
+ add_buff(&readbuf2, "\"", 1L);
+ c = read_redo(false, old_redo);
/* if a numbered buffer is used, increment the number */
if (c >= '1' && c < '9')
@@ -1091,21 +1092,19 @@ static void gotchars(char_u *chars, size_t len)
{
char_u *s = chars;
int c;
- char_u buf[2];
// remember how many chars were last recorded
if (Recording) {
last_recorded_len += len;
}
- buf[1] = NUL;
while (len--) {
// Handle one byte at a time; no translation to be done.
c = *s++;
updatescript(c);
if (Recording) {
- buf[0] = (char_u)c;
+ char buf[2] = { (char)c, NUL };
add_buff(&recordbuff, buf, 1L);
}
}
@@ -1881,9 +1880,8 @@ static int vgetorpeek(int advance)
(size_t)(mlen - typebuf.tb_maplen));
}
- del_typebuf(mlen, 0); /* remove the chars */
- set_option_value((char_u *)"paste",
- (long)!p_paste, NULL, 0);
+ del_typebuf(mlen, 0); // Remove the chars.
+ set_option_value("paste", !p_paste, NULL, 0);
if (!(State & INSERT)) {
msg_col = 0;
msg_row = (int)Rows - 1;
@@ -1905,7 +1903,7 @@ static int vgetorpeek(int advance)
}
if ((mp == NULL || max_mlen >= mp_match_len)
- && keylen != KEYLEN_PART_MAP) {
+ && keylen != KEYLEN_PART_MAP && keylen != KEYLEN_PART_KEY) {
// No matching mapping found or found a non-matching mapping that
// matches at least what the matching mapping matched
keylen = 0;
@@ -3219,82 +3217,99 @@ showmap (
ui_flush(); /* show one line at a time */
}
-/*
- * Return TRUE if a map exists that has "str" in the rhs for mode "modechars".
- * Recognize termcap codes in "str".
- * Also checks mappings local to the current buffer.
- */
-int map_to_exists(char_u *str, char_u *modechars, int abbr)
+/// Check if a map exists that has given string in the rhs
+///
+/// Also checks mappings local to the current buffer.
+///
+/// @param[in] str String which mapping must have in the rhs. Termcap codes
+/// are recognized in this argument.
+/// @param[in] modechars Mode(s) in which mappings are checked.
+/// @param[in] abbr true if checking abbreviations in place of mappings.
+///
+/// @return true if there is at least one mapping with given parameters.
+bool map_to_exists(const char *const str, const char *const modechars,
+ const bool abbr)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{
int mode = 0;
- char_u *rhs;
- char_u *buf;
int retval;
- rhs = replace_termcodes(str, STRLEN(str), &buf, false, true, false,
- CPO_TO_CPO_FLAGS);
-
- if (vim_strchr(modechars, 'n') != NULL)
- mode |= NORMAL;
- if (vim_strchr(modechars, 'v') != NULL)
- mode |= VISUAL + SELECTMODE;
- if (vim_strchr(modechars, 'x') != NULL)
- mode |= VISUAL;
- if (vim_strchr(modechars, 's') != NULL)
- mode |= SELECTMODE;
- if (vim_strchr(modechars, 'o') != NULL)
- mode |= OP_PENDING;
- if (vim_strchr(modechars, 'i') != NULL)
- mode |= INSERT;
- if (vim_strchr(modechars, 'l') != NULL)
- mode |= LANGMAP;
- if (vim_strchr(modechars, 'c') != NULL)
- mode |= CMDLINE;
-
- retval = map_to_exists_mode(rhs, mode, abbr);
+ char_u *buf;
+ char_u *const rhs = replace_termcodes((const char_u *)str, strlen(str), &buf,
+ false, true, false,
+ CPO_TO_CPO_FLAGS);
+
+#define MAPMODE(mode, modechars, chr, modeflags) \
+ do { \
+ if (strchr(modechars, chr) != NULL) { \
+ mode |= modeflags; \
+ } \
+ } while (0)
+ MAPMODE(mode, modechars, 'n', NORMAL);
+ MAPMODE(mode, modechars, 'v', VISUAL|SELECTMODE);
+ MAPMODE(mode, modechars, 'x', VISUAL);
+ MAPMODE(mode, modechars, 's', SELECTMODE);
+ MAPMODE(mode, modechars, 'o', OP_PENDING);
+ MAPMODE(mode, modechars, 'i', INSERT);
+ MAPMODE(mode, modechars, 'l', LANGMAP);
+ MAPMODE(mode, modechars, 'c', CMDLINE);
+#undef MAPMODE
+
+ retval = map_to_exists_mode((const char *)rhs, mode, abbr);
xfree(buf);
return retval;
}
-/*
- * Return TRUE if a map exists that has "str" in the rhs for mode "mode".
- * Also checks mappings local to the current buffer.
- */
-int map_to_exists_mode(char_u *rhs, int mode, int abbr)
+/// Check if a map exists that has given string in the rhs
+///
+/// Also checks mappings local to the current buffer.
+///
+/// @param[in] rhs String which mapping must have in the rhs. Termcap codes
+/// are recognized in this argument.
+/// @param[in] mode Mode(s) in which mappings are checked.
+/// @param[in] abbr true if checking abbreviations in place of mappings.
+///
+/// @return true if there is at least one mapping with given parameters.
+int map_to_exists_mode(const char *const rhs, const int mode, const bool abbr)
{
mapblock_T *mp;
int hash;
- int expand_buffer = FALSE;
+ bool expand_buffer = false;
validate_maphash();
- /* Do it twice: once for global maps and once for local maps. */
- for (;; ) {
- for (hash = 0; hash < 256; ++hash) {
+ // Do it twice: once for global maps and once for local maps.
+ for (;;) {
+ for (hash = 0; hash < 256; hash++) {
if (abbr) {
- if (hash > 0) /* there is only one abbr list */
+ if (hash > 0) { // There is only one abbr list.
break;
- if (expand_buffer)
+ }
+ if (expand_buffer) {
mp = curbuf->b_first_abbr;
- else
+ } else {
mp = first_abbr;
- } else if (expand_buffer)
+ }
+ } else if (expand_buffer) {
mp = curbuf->b_maphash[hash];
- else
+ } else {
mp = maphash[hash];
+ }
for (; mp; mp = mp->m_next) {
if ((mp->m_mode & mode)
- && strstr((char *)mp->m_str, (char *)rhs) != NULL)
- return TRUE;
+ && strstr((char *)mp->m_str, rhs) != NULL) {
+ return true;
+ }
}
}
- if (expand_buffer)
+ if (expand_buffer) {
break;
- expand_buffer = TRUE;
+ }
+ expand_buffer = true;
}
- return FALSE;
+ return false;
}
/*
diff --git a/src/nvim/gettext.h b/src/nvim/gettext.h
new file mode 100644
index 0000000000..aa0e97233e
--- /dev/null
+++ b/src/nvim/gettext.h
@@ -0,0 +1,21 @@
+#ifndef NVIM_GETTEXT_H
+#define NVIM_GETTEXT_H
+
+#ifdef HAVE_WORKING_LIBINTL
+# include <libintl.h>
+# define _(x) gettext((char *)(x))
+// XXX do we actually need this?
+# ifdef gettext_noop
+# define N_(x) gettext_noop(x)
+# else
+# define N_(x) x
+# endif
+#else
+# define _(x) ((char *)(x))
+# define N_(x) x
+# define bindtextdomain(x, y) // empty
+# define bind_textdomain_codeset(x, y) // empty
+# define textdomain(x) // empty
+#endif
+
+#endif // NVIM_GETTEXT_H
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index ad14ec4f8c..3c705d88a5 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -12,6 +12,7 @@
#include "nvim/syntax_defs.h"
#include "nvim/types.h"
#include "nvim/event/loop.h"
+#include "nvim/os/os_defs.h"
#define IOSIZE (1024+1) // file I/O and sprintf buffer size
@@ -21,16 +22,6 @@
# define MSG_BUF_CLEN (MSG_BUF_LEN / 6) // cell length (worst case: utf-8
// takes 6 bytes for one cell)
-// Maximum length of a file path. Make it a bit long, to stay
-// on the safe side. But not too long to put on the stack.
-#ifndef MAXPATHL
-# ifdef MAXPATHLEN
-# define MAXPATHL MAXPATHLEN
-# else
-# define MAXPATHL 256
-# endif
-#endif
-
#ifdef WIN32
# define _PATHSEPSTR "\\"
#else
@@ -473,6 +464,7 @@ typedef enum {
, HLF_CUL // 'cursurline'
, HLF_MC // 'colorcolumn'
, HLF_QFL // selected quickfix line
+ , HLF_0 // Whitespace
, HLF_COUNT // MUST be the last one
} hlf_T;
@@ -481,7 +473,7 @@ typedef enum {
#define HL_FLAGS { '8', '~', 'z', 'Z', '@', 'd', 'e', 'i', 'l', 'm', 'M', 'n', \
'N', 'r', 's', 'S', 'c', 't', 'v', 'V', 'w', 'W', 'f', 'F', \
'A', 'C', 'D', 'T', '-', '>', 'B', 'P', 'R', 'L', '+', '=', \
- 'x', 'X', '*', '#', '_', '!', '.', 'o', 'q' }
+ 'x', 'X', '*', '#', '_', '!', '.', 'o', 'q', '0' }
EXTERN int highlight_attr[HLF_COUNT]; /* Highl. attr for each context. */
EXTERN int highlight_user[9]; /* User[1-9] attributes */
@@ -1208,6 +1200,7 @@ EXTERN char_u e_dirnotf[] INIT(= N_(
"E919: Directory not found in '%s': \"%s\""));
EXTERN char_u e_unsupportedoption[] INIT(= N_("E519: Option not supported"));
EXTERN char_u e_fnametoolong[] INIT(= N_("E856: Filename too long"));
+EXTERN char_u e_float_as_string[] INIT(= N_("E806: using Float as a String"));
EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
@@ -1226,11 +1219,6 @@ EXTERN FILE *time_fd INIT(= NULL); /* where to write startup timing */
EXTERN int ignored;
EXTERN char *ignoredp;
-EXTERN bool in_free_unref_items INIT(= false);
-
-// Used for checking if local variables or arguments used in a lambda.
-EXTERN int *eval_lavars_used INIT(= NULL);
-
// If a msgpack-rpc channel should be started over stdin/stdout
EXTERN bool embedded_mode INIT(= false);
@@ -1255,7 +1243,7 @@ typedef enum {
kCdScopeInvalid = -1,
kCdScopeWindow, ///< Affects one window.
kCdScopeTab, ///< Affects one tab page.
- kCdScopeGlobal, ///< Affects the entire instance of Neovim.
+ kCdScopeGlobal, ///< Affects the entire Nvim instance.
} CdScope;
#define MIN_CD_SCOPE kCdScopeWindow
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index 19d97ecfef..4cb05ffc12 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -369,7 +369,6 @@ static void prt_get_attr(int hl_id, prt_text_attr_T *pattr, int modec)
{
int colorindex;
uint32_t fg_color;
- char *color;
pattr->bold = (highlight_has_attr(hl_id, HL_BOLD, modec) != NULL);
pattr->italic = (highlight_has_attr(hl_id, HL_ITALIC, modec) != NULL);
@@ -377,11 +376,12 @@ static void prt_get_attr(int hl_id, prt_text_attr_T *pattr, int modec)
pattr->undercurl = (highlight_has_attr(hl_id, HL_UNDERCURL, modec) != NULL);
{
- color = (char *)highlight_color(hl_id, (char_u *)"fg", modec);
- if (color == NULL)
+ const char *color = highlight_color(hl_id, "fg", modec);
+ if (color == NULL) {
colorindex = 0;
- else
+ } else {
colorindex = atoi(color);
+ }
if (colorindex >= 0 && colorindex < t_colors)
fg_color = prt_get_term_color(colorindex);
diff --git a/src/nvim/hashtab.c b/src/nvim/hashtab.c
index b14bb01c0e..354c9718ba 100644
--- a/src/nvim/hashtab.c
+++ b/src/nvim/hashtab.c
@@ -82,7 +82,7 @@ void hash_clear_all(hashtab_T *ht, unsigned int off)
/// used for that key.
/// WARNING: Returned pointer becomes invalid as soon as the hash table
/// is changed in any way.
-hashitem_T *hash_find(hashtab_T *ht, const char_u *key)
+hashitem_T *hash_find(const hashtab_T *const ht, const char_u *const key)
{
return hash_lookup(ht, (const char *)key, STRLEN(key), hash_hash(key));
}
@@ -99,7 +99,8 @@ hashitem_T *hash_find(hashtab_T *ht, const char_u *key)
///
/// @warning Returned pointer becomes invalid as soon as the hash table
/// is changed in any way.
-hashitem_T *hash_find_len(hashtab_T *ht, const char *key, const size_t len)
+hashitem_T *hash_find_len(const hashtab_T *const ht, const char *const key,
+ const size_t len)
{
return hash_lookup(ht, key, len, hash_hash_len(key, len));
}
@@ -115,7 +116,7 @@ hashitem_T *hash_find_len(hashtab_T *ht, const char *key, const size_t len)
/// used for that key.
/// WARNING: Returned pointer becomes invalid as soon as the hash table
/// is changed in any way.
-hashitem_T *hash_lookup(hashtab_T *const ht,
+hashitem_T *hash_lookup(const hashtab_T *const ht,
const char *const key, const size_t key_len,
const hash_T hash)
{
diff --git a/src/nvim/hashtab.h b/src/nvim/hashtab.h
index 0da2b13f2e..973b97d476 100644
--- a/src/nvim/hashtab.h
+++ b/src/nvim/hashtab.h
@@ -70,6 +70,25 @@ typedef struct hashtable_S {
hashitem_T ht_smallarray[HT_INIT_SIZE]; /// initial array
} hashtab_T;
+/// Iterate over a hashtab
+///
+/// @param[in] ht Hashtab to iterate over.
+/// @param hi Name of the variable with current hashtab entry.
+/// @param code Cycle body.
+#define HASHTAB_ITER(ht, hi, code) \
+ do { \
+ hashtab_T *const hi##ht_ = (ht); \
+ size_t hi##todo_ = hi##ht_->ht_used; \
+ for (hashitem_T *hi = hi##ht_->ht_array; hi##todo_; hi++) { \
+ if (!HASHITEM_EMPTY(hi)) { \
+ { \
+ code \
+ } \
+ hi##todo_--; \
+ } \
+ } \
+ } while (0)
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "hashtab.h.generated.h"
#endif
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index 550d256de5..b647b8146a 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -140,31 +140,30 @@ char_u *get_cscope_name(expand_T *xp, int idx)
/*
* Handle command line completion for :cscope command.
*/
-void set_context_in_cscope_cmd(expand_T *xp, char_u *arg, cmdidx_T cmdidx)
+void set_context_in_cscope_cmd(expand_T *xp, const char *arg, cmdidx_T cmdidx)
{
- char_u *p;
-
- /* Default: expand subcommands */
+ // Default: expand subcommands.
xp->xp_context = EXPAND_CSCOPE;
- xp->xp_pattern = arg;
- expand_what = (cmdidx == CMD_scscope)
- ? EXP_SCSCOPE_SUBCMD : EXP_CSCOPE_SUBCMD;
+ xp->xp_pattern = (char_u *)arg;
+ expand_what = ((cmdidx == CMD_scscope)
+ ? EXP_SCSCOPE_SUBCMD : EXP_CSCOPE_SUBCMD);
/* (part of) subcommand already typed */
if (*arg != NUL) {
- p = skiptowhite(arg);
- if (*p != NUL) { /* past first word */
- xp->xp_pattern = skipwhite(p);
- if (*skiptowhite(xp->xp_pattern) != NUL)
+ const char *p = (const char *)skiptowhite((const char_u *)arg);
+ if (*p != NUL) { // Past first word.
+ xp->xp_pattern = skipwhite((const char_u *)p);
+ if (*skiptowhite(xp->xp_pattern) != NUL) {
xp->xp_context = EXPAND_NOTHING;
- else if (STRNICMP(arg, "add", p - arg) == 0)
+ } else if (STRNICMP(arg, "add", p - arg) == 0) {
xp->xp_context = EXPAND_FILES;
- else if (STRNICMP(arg, "kill", p - arg) == 0)
+ } else if (STRNICMP(arg, "kill", p - arg) == 0) {
expand_what = EXP_CSCOPE_KILL;
- else if (STRNICMP(arg, "find", p - arg) == 0)
+ } else if (STRNICMP(arg, "find", p - arg) == 0) {
expand_what = EXP_CSCOPE_FIND;
- else
+ } else {
xp->xp_context = EXPAND_NOTHING;
+ }
}
}
}
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index 7b758b4dac..4a73fbaf61 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -174,7 +174,7 @@ static char_u *skip_string(char_u *p)
char_u *paren = vim_strchr(delim, '(');
if (paren != NULL) {
- ptrdiff_t delim_len = paren - delim;
+ const ptrdiff_t delim_len = paren - delim;
for (p += 3; *p; ++p)
if (p[0] == ')' && STRNCMP(p + 1, delim, delim_len) == 0
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index 5042663041..a8df6322cf 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -94,7 +94,7 @@
do { \
if (*p_langmap \
&& (condition) \
- && (!p_lnr || (p_lnr && typebuf_maplen() == 0)) \
+ && (p_lrm || (!p_lrm && KeyTyped)) \
&& !KeyStuffed \
&& (c) >= 0) \
{ \
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 7b1c912f4b..7ad42d6776 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -283,7 +283,7 @@ int main(int argc, char **argv)
cmdline_row = (int)(Rows - p_ch);
msg_row = cmdline_row;
screenalloc(false); /* allocate screen buffers */
- set_init_2();
+ set_init_2(params.headless);
TIME_MSG("inits 2");
msg_scroll = TRUE;
@@ -391,9 +391,10 @@ int main(int argc, char **argv)
shada_read_everything(NULL, false, true);
TIME_MSG("reading ShaDa");
}
- /* It's better to make v:oldfiles an empty list than NULL. */
- if (get_vim_var_list(VV_OLDFILES) == NULL)
- set_vim_var_list(VV_OLDFILES, list_alloc());
+ // It's better to make v:oldfiles an empty list than NULL.
+ if (get_vim_var_list(VV_OLDFILES) == NULL) {
+ set_vim_var_list(VV_OLDFILES, tv_list_alloc());
+ }
/*
* "-q errorfile": Load the error file now.
@@ -802,17 +803,18 @@ static void command_line_scan(mparm_T *parmp)
argv_idx = -1; /* skip to next argument */
break;
- case 'A': /* "-A" start in Arabic mode */
- set_option_value((char_u *)"arabic", 1L, NULL, 0);
+ case 'A': { // "-A" start in Arabic mode.
+ set_option_value("arabic", 1L, NULL, 0);
break;
-
- case 'b': /* "-b" binary mode */
- /* Needs to be effective before expanding file names, because
- * for Win32 this makes us edit a shortcut file itself,
- * instead of the file it links to. */
+ }
+ case 'b': { // "-b" binary mode.
+ // Needs to be effective before expanding file names, because
+ // for Win32 this makes us edit a shortcut file itself,
+ // instead of the file it links to.
set_options_bin(curbuf->b_p_bin, 1, 0);
- curbuf->b_p_bin = 1; /* binary file I/O */
+ curbuf->b_p_bin = 1; // Binary file I/O.
break;
+ }
case 'e': /* "-e" Ex mode */
exmode_active = EXMODE_NORMAL;
@@ -829,24 +831,27 @@ static void command_line_scan(mparm_T *parmp)
main_start_gui();
break;
- case 'F': /* "-F" start in Farsi mode: rl + fkmap set */
- p_fkmap = TRUE;
- set_option_value((char_u *)"rl", 1L, NULL, 0);
+ case 'F': { // "-F" start in Farsi mode: rl + fkmap set.
+ p_fkmap = true;
+ set_option_value("rl", 1L, NULL, 0);
break;
+ }
case 'h': /* "-h" give help message */
usage();
mch_exit(0);
- case 'H': /* "-H" start in Hebrew mode: rl + hkmap set */
- p_hkmap = TRUE;
- set_option_value((char_u *)"rl", 1L, NULL, 0);
+ case 'H': { // "-H" start in Hebrew mode: rl + hkmap set.
+ p_hkmap = true;
+ set_option_value("rl", 1L, NULL, 0);
break;
+ }
- case 'l': /* "-l" lisp mode, 'lisp' and 'showmatch' on */
- set_option_value((char_u *)"lisp", 1L, NULL, 0);
- p_sm = TRUE;
+ case 'l': { // "-l" lisp mode, 'lisp' and 'showmatch' on.
+ set_option_value("lisp", 1L, NULL, 0);
+ p_sm = true;
break;
+ }
case 'M': /* "-M" no changes or writing of files */
reset_modifiable();
@@ -945,8 +950,7 @@ static void command_line_scan(mparm_T *parmp)
/* default is 10: a little bit verbose */
p_verbose = get_number_arg(argv[0], &argv_idx, 10);
if (argv[0][argv_idx] != NUL) {
- set_option_value((char_u *)"verbosefile", 0L,
- (char_u *)argv[0] + argv_idx, 0);
+ set_option_value("verbosefile", 0L, argv[0] + argv_idx, 0);
argv_idx = (int)STRLEN(argv[0]);
}
break;
@@ -955,7 +959,7 @@ static void command_line_scan(mparm_T *parmp)
/* "-w {scriptout}" write to script */
if (ascii_isdigit(((char_u *)argv[0])[argv_idx])) {
n = get_number_arg(argv[0], &argv_idx, 10);
- set_option_value((char_u *)"window", n, NULL, 0);
+ set_option_value("window", n, NULL, 0);
break;
}
want_argument = TRUE;
@@ -1087,7 +1091,7 @@ scripterror:
if (ascii_isdigit(*((char_u *)argv[0]))) {
argv_idx = 0;
n = get_number_arg(argv[0], &argv_idx, 10);
- set_option_value((char_u *)"window", n, NULL, 0);
+ set_option_value("window", n, NULL, 0);
argv_idx = -1;
break;
}
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index de2fdd7f13..ae94ec7ecd 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -62,7 +62,7 @@ int setmark(int c)
/// Free fmark_T item
void free_fmark(fmark_T fm)
{
- dict_unref(fm.additional_data);
+ tv_dict_unref(fm.additional_data);
}
/// Free xfmark_T item
@@ -1431,3 +1431,26 @@ void free_all_marks(void)
memset(&namedfm[0], 0, sizeof(namedfm));
}
#endif
+
+/// Adjust position to point to the first byte of a multi-byte character
+///
+/// If it points to a tail byte it is move backwards to the head byte.
+///
+/// @param[in] buf Buffer to adjust position in.
+/// @param[out] lp Position to adjust.
+void mark_mb_adjustpos(buf_T *buf, pos_T *lp)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (lp->col > 0 || lp->coladd > 1) {
+ const char_u *const p = ml_get_buf(buf, lp->lnum, false);
+ lp->col -= (*mb_head_off)(p, p + lp->col);
+ // Reset "coladd" when the cursor would be on the right half of a
+ // double-wide character.
+ if (lp->coladd == 1
+ && p[lp->col] != TAB
+ && vim_isprintc((*mb_ptr2char)(p + lp->col))
+ && ptr2cells(p + lp->col) > 1) {
+ lp->coladd = 0;
+ }
+ }
+}
diff --git a/src/nvim/mark.h b/src/nvim/mark.h
index aff6e7273a..efba9708db 100644
--- a/src/nvim/mark.h
+++ b/src/nvim/mark.h
@@ -29,7 +29,7 @@
/// Clear given fmark
#define CLEAR_FMARK(fmarkp_) \
- RESET_FMARK(fmarkp_, ((pos_T) {0, 0, 0}), 0)
+ RESET_FMARK(fmarkp_, ((pos_T) { 0, 0, 0 }), 0)
/// Set given extended mark (regular mark + file name)
#define SET_XFMARK(xfmarkp_, mark_, fnum_, fname_) \
diff --git a/src/nvim/mark_defs.h b/src/nvim/mark_defs.h
index 720b2475ed..2cb489501e 100644
--- a/src/nvim/mark_defs.h
+++ b/src/nvim/mark_defs.h
@@ -3,7 +3,7 @@
#include "nvim/pos.h"
#include "nvim/os/time.h"
-#include "nvim/eval_defs.h"
+#include "nvim/eval/typval.h"
/*
* marks: positions in a file
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 0ab133a545..460528b85f 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -50,6 +50,7 @@
#include "nvim/strings.h"
#include "nvim/os/os.h"
#include "nvim/arabic.h"
+#include "nvim/mark.h"
typedef struct {
int rangeStart;
@@ -375,16 +376,18 @@ void remove_bom(char_u *s)
*/
int mb_get_class(const char_u *p)
{
- return mb_get_class_buf(p, curbuf);
+ return mb_get_class_tab(p, curbuf->b_chartab);
}
-int mb_get_class_buf(const char_u *p, buf_T *buf)
+int mb_get_class_tab(const char_u *p, const uint64_t *const chartab)
{
if (MB_BYTE2LEN(p[0]) == 1) {
- if (p[0] == NUL || ascii_iswhite(p[0]))
+ if (p[0] == NUL || ascii_iswhite(p[0])) {
return 0;
- if (vim_iswordc_buf(p[0], buf))
+ }
+ if (vim_iswordc_tab(p[0], chartab)) {
return 2;
+ }
return 1;
}
return utf_class(utf_ptr2char(p));
@@ -580,7 +583,7 @@ int utf_ptr2char(const char_u *p)
* If byte sequence is illegal or incomplete, returns -1 and does not advance
* "s".
*/
-static int utf_safe_read_char_adv(char_u **s, size_t *n)
+static int utf_safe_read_char_adv(const char_u **s, size_t *n)
{
int c;
@@ -622,7 +625,7 @@ static int utf_safe_read_char_adv(char_u **s, size_t *n)
* Get character at **pp and advance *pp to the next character.
* Note: composing characters are skipped!
*/
-int mb_ptr2char_adv(char_u **pp)
+int mb_ptr2char_adv(const char_u **const pp)
{
int c;
@@ -635,7 +638,7 @@ int mb_ptr2char_adv(char_u **pp)
* Get character at **pp and advance *pp to the next character.
* Note: composing characters are returned as separate characters.
*/
-int mb_cptr2char_adv(char_u **pp)
+int mb_cptr2char_adv(const char_u **pp)
{
int c;
@@ -1230,7 +1233,8 @@ bool utf_isupper(int a)
return utf_tolower(a) != a;
}
-static int utf_strnicmp(char_u *s1, char_u *s2, size_t n1, size_t n2)
+static int utf_strnicmp(const char_u *s1, const char_u *s2, size_t n1,
+ size_t n2)
{
int c1, c2, cdiff;
char_u buffer[6];
@@ -1300,6 +1304,7 @@ static int utf_strnicmp(char_u *s1, char_u *s2, size_t n1, size_t n2)
# define CP_UTF8 65001 /* magic number from winnls.h */
#endif
+/// Reassigns `strw` to a new, allocated pointer to a UTF16 string.
int utf8_to_utf16(const char *str, WCHAR **strw)
FUNC_ATTR_NONNULL_ALL
{
@@ -1341,40 +1346,40 @@ int utf8_to_utf16(const char *str, WCHAR **strw)
return 0;
}
+/// Reassigns `str` to a new, allocated pointer to a UTF8 string.
int utf16_to_utf8(const WCHAR *strw, char **str)
FUNC_ATTR_NONNULL_ALL
{
// Compute the space required to store the string as UTF-8.
- ssize_t utf8_len = WideCharToMultiByte(CP_UTF8,
- 0,
- strw,
- -1,
- NULL,
- 0,
- NULL,
- NULL);
+ DWORD utf8_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ strw,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ NULL);
if (utf8_len == 0) {
return GetLastError();
}
- ssize_t buf_sz = utf8_len * sizeof(char);
- char *buf = xmalloc(buf_sz);
- char *pos = buf;
+ *str = xmalloc(utf8_len);
- // Convert string to UTF-8.
- int r = WideCharToMultiByte(CP_UTF8,
- 0,
- strw,
- -1,
- pos,
- utf8_len,
- NULL,
- NULL);
- assert(r == utf8_len);
- if (r != utf8_len) {
- EMSG2("WideCharToMultiByte failed: %d", r);
+ // Convert to UTF-8.
+ utf8_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ strw,
+ -1,
+ *str,
+ utf8_len,
+ NULL,
+ NULL);
+ if (utf8_len == 0) {
+ free(*str);
+ *str = NULL;
+ return GetLastError();
}
- *str = pos;
+ (*str)[utf8_len] = '\0';
return 0;
}
@@ -1389,19 +1394,26 @@ int utf16_to_utf8(const WCHAR *strw, char **str)
* Returns zero if s1 and s2 are equal (ignoring case), the difference between
* two characters otherwise.
*/
-int mb_strnicmp(char_u *s1, char_u *s2, size_t nn)
+int mb_strnicmp(const char_u *s1, const char_u *s2, const size_t nn)
{
return utf_strnicmp(s1, s2, nn, nn);
}
-/* We need to call mb_stricmp() even when we aren't dealing with a multi-byte
- * encoding because mb_stricmp() takes care of all ascii and non-ascii
- * encodings, including characters with umlauts in latin1, etc., while
- * STRICMP() only handles the system locale version, which often does not
- * handle non-ascii properly. */
-int mb_stricmp(char_u *s1, char_u *s2)
+/// Compare strings case-insensitively
+///
+/// @note We need to call mb_stricmp() even when we aren't dealing with
+/// a multi-byte encoding because mb_stricmp() takes care of all ASCII and
+/// non-ascii encodings, including characters with umlauts in latin1,
+/// etc., while STRICMP() only handles the system locale version, which
+/// often does not handle non-ascii properly.
+///
+/// @param[in] s1 First string to compare, not more then #MAXCOL characters.
+/// @param[in] s2 Second string to compare, not more then #MAXCOL characters.
+///
+/// @return 0 if strings are equal, <0 if s1 < s2, >0 if s1 > s2.
+int mb_stricmp(const char *s1, const char *s2)
{
- return mb_strnicmp(s1, s2, MAXCOL);
+ return mb_strnicmp((const char_u *)s1, (const char_u *)s2, MAXCOL);
}
/*
@@ -1639,38 +1651,16 @@ theend:
*/
void mb_adjust_cursor(void)
{
- mb_adjustpos(curbuf, &curwin->w_cursor);
-}
-
-/*
- * Adjust position "*lp" to point to the first byte of a multi-byte character.
- * If it points to a tail byte it's moved backwards to the head byte.
- */
-void mb_adjustpos(buf_T *buf, pos_T *lp)
-{
- char_u *p;
-
- if (lp->col > 0
- || lp->coladd > 1
- ) {
- p = ml_get_buf(buf, lp->lnum, FALSE);
- lp->col -= (*mb_head_off)(p, p + lp->col);
- /* Reset "coladd" when the cursor would be on the right half of a
- * double-wide character. */
- if (lp->coladd == 1
- && p[lp->col] != TAB
- && vim_isprintc((*mb_ptr2char)(p + lp->col))
- && ptr2cells(p + lp->col) > 1)
- lp->coladd = 0;
- }
+ mark_mb_adjustpos(curbuf, &curwin->w_cursor);
}
/// Checks and adjusts cursor column. Not mode-dependent.
/// @see check_cursor_col_win
///
-/// @param win Places cursor on a valid column for this window.
-void mb_check_adjust_col(win_T *win)
+/// @param win_ Places cursor on a valid column for this window.
+void mb_check_adjust_col(void *win_)
{
+ win_T *win = (win_T *)win_;
colnr_T oldcol = win->w_cursor.col;
// Column 0 is always valid.
@@ -2039,8 +2029,8 @@ void * my_iconv_open(char_u *to, char_u *from)
* Returns the converted string in allocated memory. NULL for an error.
* If resultlenp is not NULL, sets it to the result length in bytes.
*/
-static char_u * iconv_string(vimconv_T *vcp, char_u *str, size_t slen,
- size_t *unconvlenp, size_t *resultlenp)
+static char_u *iconv_string(const vimconv_T *const vcp, char_u *str,
+ size_t slen, size_t *unconvlenp, size_t *resultlenp)
{
const char *from;
size_t fromlen;
@@ -2325,7 +2315,7 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8,
* Illegal chars are often changed to "?", unless vcp->vc_fail is set.
* When something goes wrong, NULL is returned and "*lenp" is unchanged.
*/
-char_u * string_convert(vimconv_T *vcp, char_u *ptr, size_t *lenp)
+char_u *string_convert(const vimconv_T *const vcp, char_u *ptr, size_t *lenp)
{
return string_convert_ext(vcp, ptr, lenp, NULL);
}
@@ -2335,7 +2325,7 @@ char_u * string_convert(vimconv_T *vcp, char_u *ptr, size_t *lenp)
* an incomplete sequence at the end it is not converted and "*unconvlenp" is
* set to the number of remaining bytes.
*/
-char_u * string_convert_ext(vimconv_T *vcp, char_u *ptr,
+char_u * string_convert_ext(const vimconv_T *const vcp, char_u *ptr,
size_t *lenp, size_t *unconvlenp)
{
char_u *retval = NULL;
diff --git a/src/nvim/mbyte.h b/src/nvim/mbyte.h
index 2c92a0fbb2..3565202466 100644
--- a/src/nvim/mbyte.h
+++ b/src/nvim/mbyte.h
@@ -2,6 +2,11 @@
#define NVIM_MBYTE_H
#include <stdbool.h>
+#include <string.h>
+
+#include "nvim/iconv.h"
+#include "nvim/func_attr.h"
+#include "nvim/os/os_defs.h" // For WCHAR, indirect
/*
* Return byte length of character that starts with byte "b".
@@ -40,7 +45,41 @@
#define mb_ptr2char utf_ptr2char
#define mb_head_off utf_head_off
+/// Flags for vimconv_T
+typedef enum {
+ CONV_NONE = 0,
+ CONV_TO_UTF8 = 1,
+ CONV_9_TO_UTF8 = 2,
+ CONV_TO_LATIN1 = 3,
+ CONV_TO_LATIN9 = 4,
+ CONV_ICONV = 5,
+} ConvFlags;
+
+/// Structure used for string conversions
+typedef struct {
+ int vc_type; ///< Zero or more ConvFlags.
+ int vc_factor; ///< Maximal expansion factor.
+# ifdef USE_ICONV
+ iconv_t vc_fd; ///< Value for CONV_ICONV.
+# endif
+ bool vc_fail; ///< What to do with invalid characters: if true, fail,
+ ///< otherwise use '?'.
+} vimconv_T;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mbyte.h.generated.h"
#endif
+
+static inline int mb_strcmp_ic(bool ic, const char *s1, const char *s2)
+ REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
+
+/// Compare strings
+///
+/// @param[in] ic True if case is to be ignored.
+///
+/// @return 0 if s1 == s2, <0 if s1 < s2, >0 if s1 > s2.
+static inline int mb_strcmp_ic(bool ic, const char *s1, const char *s2)
+{
+ return (ic ? mb_stricmp(s1, s2) : strcmp(s1, s2));
+}
#endif // NVIM_MBYTE_H
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index f9d3751390..5ea2397db3 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -992,7 +992,7 @@ void ml_recover(void)
if (b0_ff != 0)
set_fileformat(b0_ff - 1, OPT_LOCAL);
if (b0_fenc != NULL) {
- set_option_value((char_u *)"fenc", 0L, b0_fenc, OPT_LOCAL);
+ set_option_value("fenc", 0L, (char *)b0_fenc, OPT_LOCAL);
xfree(b0_fenc);
}
unchanged(curbuf, TRUE);
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 58c01fbe7a..b4fdd86a6d 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -430,6 +430,19 @@ char *xstrdup(const char *str)
return xmemdupz(str, strlen(str));
}
+/// strdup() wrapper
+///
+/// Unlike xstrdup() allocates a new empty string if it receives NULL.
+char *xstrdupnul(const char *const str)
+ FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
+{
+ if (str == NULL) {
+ return xmallocz(0);
+ } else {
+ return xstrdup(str);
+ }
+}
+
/// A version of memchr that starts the search at `src + len`.
///
/// Based on glibc's memrchr.
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 4b786c11dd..1d3609291a 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -573,16 +573,17 @@ void emsg_invreg(int name)
/// Print an error message with unknown number of arguments
bool emsgf(const char *const fmt, ...)
{
+ static char errbuf[IOSIZE];
if (emsg_not_now()) {
return true;
}
va_list ap;
va_start(ap, fmt);
- vim_vsnprintf((char *) IObuff, IOSIZE, fmt, ap, NULL);
+ vim_vsnprintf(errbuf, sizeof(errbuf), fmt, ap, NULL);
va_end(ap);
- return emsg(IObuff);
+ return emsg((const char_u *)errbuf);
}
static void msg_emsgf_event(void **argv)
@@ -718,7 +719,7 @@ int delete_first_msg(void)
void ex_messages(void *const eap_p)
FUNC_ATTR_NONNULL_ALL
{
- exarg_T *eap = (exarg_T *)eap_p;
+ const exarg_T *const eap = (const exarg_T *)eap_p;
struct msg_hist *p;
int c = 0;
@@ -1562,12 +1563,17 @@ void msg_puts_attr(const char *const s, const int attr)
msg_puts_attr_len(s, -1, attr);
}
-/// Like msg_puts_attr(), but with a maximum length "maxlen" (in bytes).
-/// When "maxlen" is -1 there is no maximum length.
-void msg_puts_attr_len(const char *str, const ptrdiff_t maxlen, int attr)
+/// Write a message with highlight attributes
+///
+/// @param[in] str NUL-terminated message string.
+/// @param[in] len Length of the string or -1.
+/// @param[in] attr Highlight attribute.
+void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr)
+ FUNC_ATTR_NONNULL_ALL
{
+ assert(len < 0 || memchr(str, 0, len) == NULL);
// If redirection is on, also write to the redirection file.
- redir_write(str, maxlen);
+ redir_write(str, len);
// Don't print anything when using ":silent cmd".
if (msg_silent != 0) {
@@ -1576,7 +1582,7 @@ void msg_puts_attr_len(const char *str, const ptrdiff_t maxlen, int attr)
// if MSG_HIST flag set, add message to history
if (attr & MSG_HIST) {
- add_msg_hist(str, -1, attr);
+ add_msg_hist(str, (int)len, attr);
attr &= ~MSG_HIST;
}
@@ -1595,9 +1601,9 @@ void msg_puts_attr_len(const char *str, const ptrdiff_t maxlen, int attr)
// different, e.g. for Win32 console) or we just don't know where the
// cursor is.
if (msg_use_printf()) {
- msg_puts_printf(str, maxlen);
+ msg_puts_printf(str, len);
} else {
- msg_puts_display((const char_u *)str, maxlen, attr, false);
+ msg_puts_display((const char_u *)str, len, attr, false);
}
}
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index d751f13644..0b74b4437e 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -2211,39 +2211,44 @@ change_warning (
}
}
-/*
- * Ask for a reply from the user, a 'y' or a 'n'.
- * No other characters are accepted, the message is repeated until a valid
- * reply is entered or CTRL-C is hit.
- * If direct is TRUE, don't use vgetc() but ui_inchar(), don't get characters
- * from any buffers but directly from the user.
- *
- * return the 'y' or 'n'
- */
-int ask_yesno(const char *str, bool direct)
+/// Ask for a reply from the user, 'y' or 'n'
+///
+/// No other characters are accepted, the message is repeated until a valid
+/// reply is entered or <C-c> is hit.
+///
+/// @param[in] str Prompt: question to ask user. Is always followed by
+/// " (y/n)?".
+/// @param[in] direct Determines what function to use to get user input. If
+/// true then ui_inchar() will be used, otherwise vgetc().
+/// I.e. when direct is true then characters are obtained
+/// directly from the user without buffers involved.
+///
+/// @return 'y' or 'n'. Last is also what will be returned in case of interrupt.
+int ask_yesno(const char *const str, const bool direct)
{
- int r = ' ';
- int save_State = State;
+ const int save_State = State;
no_wait_return++;
- State = CONFIRM; // mouse behaves like with :confirm
- setmouse(); // disables mouse for xterm
+ State = CONFIRM; // Mouse behaves like with :confirm.
+ setmouse(); // Disable mouse in xterm.
no_mapping++;
+ int r = ' ';
while (r != 'y' && r != 'n') {
- /* same highlighting as for wait_return */
- smsg_attr(hl_attr(HLF_R),
- "%s (y/n)?", str);
- if (direct)
+ // Same highlighting as for wait_return.
+ smsg_attr(hl_attr(HLF_R), "%s (y/n)?", str);
+ if (direct) {
r = get_keystroke();
- else
+ } else {
r = plain_vgetc();
- if (r == Ctrl_C || r == ESC)
+ }
+ if (r == Ctrl_C || r == ESC) {
r = 'n';
- msg_putchar(r); /* show what you typed */
+ }
+ msg_putchar(r); // Show what you typed.
ui_flush();
}
- --no_wait_return;
+ no_wait_return--;
State = save_State;
setmouse();
no_mapping--;
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index de6167c7fc..259dcc523c 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -147,7 +147,7 @@ void channel_from_connection(SocketWatcher *watcher)
/// @param name The event name, an arbitrary string
/// @param args Array with event arguments
/// @return True if the event was sent successfully, false otherwise.
-bool channel_send_event(uint64_t id, char *name, Array args)
+bool channel_send_event(uint64_t id, const char *name, Array args)
{
Channel *channel = NULL;
@@ -160,7 +160,7 @@ bool channel_send_event(uint64_t id, char *name, Array args)
if (channel) {
if (channel->pending_requests) {
// Pending request, queue the notification for later sending.
- String method = cstr_as_string(name);
+ const String method = cstr_as_string((char *)name);
WBuffer *buffer = serialize_request(id, 0, method, args, &out_buffer, 1);
kv_push(channel->delayed_notifications, buffer);
} else {
@@ -182,7 +182,7 @@ bool channel_send_event(uint64_t id, char *name, Array args)
/// @param[out] error True if the return value is an error
/// @return Whatever the remote method returned
Object channel_send_call(uint64_t id,
- char *method_name,
+ const char *method_name,
Array args,
Error *err)
{
@@ -519,10 +519,10 @@ static void send_error(Channel *channel, uint64_t id, char *err)
static void send_request(Channel *channel,
uint64_t id,
- char *name,
+ const char *name,
Array args)
{
- String method = {.size = strlen(name), .data = name};
+ const String method = cstr_as_string((char *)name);
channel_write(channel, serialize_request(channel->id,
id,
method,
@@ -532,10 +532,10 @@ static void send_request(Channel *channel,
}
static void send_event(Channel *channel,
- char *name,
+ const char *name,
Array args)
{
- String method = {.size = strlen(name), .data = name};
+ const String method = cstr_as_string((char *)name);
channel_write(channel, serialize_request(channel->id,
0,
method,
@@ -544,7 +544,7 @@ static void send_event(Channel *channel,
1));
}
-static void broadcast_event(char *name, Array args)
+static void broadcast_event(const char *name, Array args)
{
kvec_t(Channel *) subscribed = KV_INITIAL_VALUE;
Channel *channel;
@@ -560,7 +560,7 @@ static void broadcast_event(char *name, Array args)
goto end;
}
- String method = {.size = strlen(name), .data = name};
+ const String method = cstr_as_string((char *)name);
WBuffer *buffer = serialize_request(0,
0,
method,
@@ -728,7 +728,7 @@ static void call_set_error(Channel *channel, char *msg)
static WBuffer *serialize_request(uint64_t channel_id,
uint64_t request_id,
- String method,
+ const String method,
Array args,
msgpack_sbuffer *sbuffer,
size_t refcount)
diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c
index 21acd6a394..1a65a89e9b 100644
--- a/src/nvim/msgpack_rpc/helpers.c
+++ b/src/nvim/msgpack_rpc/helpers.c
@@ -115,7 +115,13 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg)
}
break;
}
- case MSGPACK_OBJECT_FLOAT: {
+#ifdef NVIM_MSGPACK_HAS_FLOAT32
+ case MSGPACK_OBJECT_FLOAT32:
+ case MSGPACK_OBJECT_FLOAT64:
+#else
+ case MSGPACK_OBJECT_FLOAT:
+#endif
+ {
STATIC_ASSERT(sizeof(Float) == sizeof(cur.mobj->via.f64),
"Msgpack floating-point size does not match API integer");
*cur.aobj = FLOAT_OBJ(cur.mobj->via.f64);
@@ -182,7 +188,12 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg)
case MSGPACK_OBJECT_BOOLEAN:
case MSGPACK_OBJECT_POSITIVE_INTEGER:
case MSGPACK_OBJECT_NEGATIVE_INTEGER:
+#ifdef NVIM_MSGPACK_HAS_FLOAT32
+ case MSGPACK_OBJECT_FLOAT32:
+ case MSGPACK_OBJECT_FLOAT64:
+#else
case MSGPACK_OBJECT_FLOAT:
+#endif
case MSGPACK_OBJECT_EXT:
case MSGPACK_OBJECT_MAP:
case MSGPACK_OBJECT_ARRAY: {
@@ -332,7 +343,7 @@ void msgpack_rpc_from_float(Float result, msgpack_packer *res)
msgpack_pack_double(res, result);
}
-void msgpack_rpc_from_string(String result, msgpack_packer *res)
+void msgpack_rpc_from_string(const String result, msgpack_packer *res)
FUNC_ATTR_NONNULL_ARG(2)
{
msgpack_pack_str(res, result.size);
@@ -491,7 +502,7 @@ Object msgpack_rpc_handle_invalid_arguments(uint64_t channel_id,
/// Serializes a msgpack-rpc request or notification(id == 0)
void msgpack_rpc_serialize_request(uint64_t request_id,
- String method,
+ const String method,
Array args,
msgpack_packer *pac)
FUNC_ATTR_NONNULL_ARG(4)
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 2ade9cb87d..388ddfc8bb 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1155,7 +1155,7 @@ static void normal_check_stuff_buffer(NormalState *s)
if (need_start_insertmode && goto_im() && !VIsual_active) {
need_start_insertmode = false;
- stuffReadbuff((uint8_t *)"i"); // start insert mode next
+ stuffReadbuff("i"); // start insert mode next
// skip the fileinfo message now, because it would be shown
// after insert mode finishes!
need_fileinfo = false;
@@ -1469,8 +1469,9 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
* If 'cpoptions' does not contain 'r', insert the search
* pattern to really repeat the same command.
*/
- if (vim_strchr(p_cpo, CPO_REDO) == NULL)
+ if (vim_strchr(p_cpo, CPO_REDO) == NULL) {
AppendToRedobuffLit(cap->searchbuf, -1);
+ }
AppendToRedobuff(NL_STR);
} else if (cap->cmdchar == ':') {
/* do_cmdline() has stored the first typed line in
@@ -1853,10 +1854,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
break;
case OP_FILTER:
- if (vim_strchr(p_cpo, CPO_FILTER) != NULL)
- AppendToRedobuff((char_u *)"!\r"); /* use any last used !cmd */
- else
- bangredo = true; /* do_bang() will put cmd in redo buffer */
+ if (vim_strchr(p_cpo, CPO_FILTER) != NULL) {
+ AppendToRedobuff("!\r"); // Use any last used !cmd.
+ } else {
+ bangredo = true; // do_bang() will put cmd in redo buffer.
+ }
case OP_INDENT:
case OP_COLON:
@@ -2026,43 +2028,44 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
static void op_colon(oparg_T *oap)
{
stuffcharReadbuff(':');
- if (oap->is_VIsual)
- stuffReadbuff((char_u *)"'<,'>");
- else {
- /*
- * Make the range look nice, so it can be repeated.
- */
- if (oap->start.lnum == curwin->w_cursor.lnum)
+ if (oap->is_VIsual) {
+ stuffReadbuff("'<,'>");
+ } else {
+ // Make the range look nice, so it can be repeated.
+ if (oap->start.lnum == curwin->w_cursor.lnum) {
stuffcharReadbuff('.');
- else
+ } else {
stuffnumReadbuff((long)oap->start.lnum);
+ }
if (oap->end.lnum != oap->start.lnum) {
stuffcharReadbuff(',');
- if (oap->end.lnum == curwin->w_cursor.lnum)
+ if (oap->end.lnum == curwin->w_cursor.lnum) {
stuffcharReadbuff('.');
- else if (oap->end.lnum == curbuf->b_ml.ml_line_count)
+ } else if (oap->end.lnum == curbuf->b_ml.ml_line_count) {
stuffcharReadbuff('$');
- else if (oap->start.lnum == curwin->w_cursor.lnum) {
- stuffReadbuff((char_u *)".+");
+ } else if (oap->start.lnum == curwin->w_cursor.lnum) {
+ stuffReadbuff(".+");
stuffnumReadbuff(oap->line_count - 1);
- } else
+ } else {
stuffnumReadbuff((long)oap->end.lnum);
+ }
}
}
- if (oap->op_type != OP_COLON)
- stuffReadbuff((char_u *)"!");
+ if (oap->op_type != OP_COLON) {
+ stuffReadbuff("!");
+ }
if (oap->op_type == OP_INDENT) {
- stuffReadbuff(get_equalprg());
- stuffReadbuff((char_u *)"\n");
+ stuffReadbuff((const char *)get_equalprg());
+ stuffReadbuff("\n");
} else if (oap->op_type == OP_FORMAT) {
if (*curbuf->b_p_fp != NUL) {
- stuffReadbuff(curbuf->b_p_fp);
+ stuffReadbuff((const char *)curbuf->b_p_fp);
} else if (*p_fp != NUL) {
- stuffReadbuff(p_fp);
+ stuffReadbuff((const char *)p_fp);
} else {
- stuffReadbuff((char_u *)"fmt");
+ stuffReadbuff("fmt");
}
- stuffReadbuff((char_u *)"\n']");
+ stuffReadbuff("\n']");
}
/*
@@ -2075,7 +2078,6 @@ static void op_colon(oparg_T *oap)
*/
static void op_function(oparg_T *oap)
{
- char_u *(argv[1]);
int save_virtual_op = virtual_op;
if (*p_opfunc == NUL)
@@ -2089,16 +2091,16 @@ static void op_function(oparg_T *oap)
decl(&curbuf->b_op_end);
}
- if (oap->motion_type == kMTBlockWise) {
- argv[0] = (char_u *)"block";
- } else if (oap->motion_type == kMTLineWise) {
- argv[0] = (char_u *)"line";
- } else {
- argv[0] = (char_u *)"char";
- }
+ const char_u *const argv[1] = {
+ (const char_u *)(((const char *const[]) {
+ [kMTBlockWise] = "block",
+ [kMTLineWise] = "line",
+ [kMTCharWise] = "char",
+ })[oap->motion_type]),
+ };
- /* Reset virtual_op so that 'virtualedit' can be changed in the
- * function. */
+ // Reset virtual_op so that 'virtualedit' can be changed in the
+ // function.
virtual_op = MAYBE;
(void)call_func_retnr(p_opfunc, 1, argv, false);
@@ -2305,7 +2307,7 @@ do_mouse (
if (VIsual_active) {
if (VIsual_select) {
stuffcharReadbuff(Ctrl_G);
- stuffReadbuff((char_u *)"\"+p");
+ stuffReadbuff("\"+p");
} else {
stuffcharReadbuff('y');
stuffcharReadbuff(K_MIDDLEMOUSE);
@@ -2465,7 +2467,7 @@ do_mouse (
&rettv, ARRAY_SIZE(argv), argv, NULL,
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&doesrange, true, NULL, NULL);
- clear_tv(&rettv);
+ tv_clear(&rettv);
break;
}
}
@@ -4477,7 +4479,7 @@ static void nv_colon(cmdarg_T *cap)
/* translate "count:" into ":.,.+(count - 1)" */
stuffcharReadbuff('.');
if (cap->count0 > 1) {
- stuffReadbuff((char_u *)",.+");
+ stuffReadbuff(",.+");
stuffnumReadbuff(cap->count0 - 1L);
}
}
@@ -4668,6 +4670,7 @@ static void nv_ident(cmdarg_T *cap)
char_u *kp = *curbuf->b_p_kp == NUL ? p_kp : curbuf->b_p_kp; // 'keywordprg'
assert(*kp != NUL); // option.c:do_set() should default to ":help" if empty.
bool kp_ex = (*kp == ':'); // 'keywordprg' is an ex command
+ bool kp_help = (STRCMP(kp, ":he") == 0 || STRCMP(kp, ":help") == 0);
size_t buf_size = n * 2 + 30 + STRLEN(kp);
char *buf = xmalloc(buf_size);
buf[0] = NUL;
@@ -4690,7 +4693,9 @@ static void nv_ident(cmdarg_T *cap)
break;
case 'K':
- if (kp_ex) {
+ if (kp_help) {
+ STRCPY(buf, "he! ");
+ } else if (kp_ex) {
if (cap->count0 != 0) { // Send the count to the ex command.
snprintf(buf, buf_size, "%" PRId64, (int64_t)(cap->count0));
}
@@ -4753,11 +4758,11 @@ static void nv_ident(cmdarg_T *cap)
}
// Now grab the chars in the identifier
- if (cmdchar == 'K') {
+ if (cmdchar == 'K' && !kp_help) {
ptr = vim_strnsave(ptr, n);
if (kp_ex) {
// Escape the argument properly for an Ex command
- p = vim_strsave_fnameescape(ptr, false);
+ p = (char_u *)vim_strsave_fnameescape((const char *)ptr, false);
} else {
// Escape the argument properly for a shell command
p = vim_strsave_shellescape(ptr, true, true);
@@ -6157,17 +6162,15 @@ static void nv_abbrev(cmdarg_T *cap)
*/
static void nv_optrans(cmdarg_T *cap)
{
- static char_u *(ar[8]) = {(char_u *)"dl", (char_u *)"dh",
- (char_u *)"d$", (char_u *)"c$",
- (char_u *)"cl", (char_u *)"cc",
- (char_u *)"yy", (char_u *)":s\r"};
- static char_u *str = (char_u *)"xXDCsSY&";
+ static const char *(ar[]) = { "dl", "dh", "d$", "c$", "cl", "cc", "yy",
+ ":s\r" };
+ static const char *str = "xXDCsSY&";
if (!checkclearopq(cap->oap)) {
if (cap->count0) {
stuffnumReadbuff(cap->count0);
}
- stuffReadbuff(ar[(int)(vim_strchr(str, cap->cmdchar) - str)]);
+ stuffReadbuff(ar[strchr(str, (char)cap->cmdchar) - str]);
}
cap->opcount = 0;
}
@@ -7290,11 +7293,11 @@ static bool unadjust_for_sel(void)
pp = &curwin->w_cursor;
else
pp = &VIsual;
- if (pp->coladd > 0)
- --pp->coladd;
- else if (pp->col > 0) {
- --pp->col;
- mb_adjustpos(curbuf, pp);
+ if (pp->coladd > 0) {
+ pp->coladd--;
+ } else if (pp->col > 0) {
+ pp->col--;
+ mark_mb_adjustpos(curbuf, pp);
} else if (pp->lnum > 1) {
--pp->lnum;
pp->col = (colnr_T)STRLEN(ml_get(pp->lnum));
@@ -7829,7 +7832,7 @@ static void get_op_vcol(
// prevent from moving onto a trail byte
if (has_mbyte) {
- mb_adjustpos(curwin->w_buffer, &oap->end);
+ mark_mb_adjustpos(curwin->w_buffer, &oap->end);
}
getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol);
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index c13b6f736a..68ef27222c 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -14,8 +14,10 @@
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
+#include "nvim/assert.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_getln.h"
@@ -41,6 +43,7 @@
#include "nvim/terminal.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
+#include "nvim/macros.h"
#include "nvim/window.h"
#include "nvim/os/input.h"
#include "nvim/os/time.h"
@@ -888,7 +891,7 @@ static void set_yreg_additional_data(yankreg_T *reg, dict_T *additional_data)
if (reg->additional_data == additional_data) {
return;
}
- dict_unref(reg->additional_data);
+ tv_dict_unref(reg->additional_data);
reg->additional_data = additional_data;
}
@@ -1106,7 +1109,6 @@ int insert_reg(
)
{
int retval = OK;
- char_u *arg;
int allocated;
/*
@@ -1122,21 +1124,24 @@ int insert_reg(
if (regname != NUL && !valid_yank_reg(regname, false))
return FAIL;
- if (regname == '.') /* insert last inserted text */
- retval = stuff_inserted(NUL, 1L, TRUE);
- else if (get_spec_reg(regname, &arg, &allocated, TRUE)) {
- if (arg == NULL)
+ char_u *arg;
+ if (regname == '.') { // Insert last inserted text.
+ retval = stuff_inserted(NUL, 1L, true);
+ } else if (get_spec_reg(regname, &arg, &allocated, true)) {
+ if (arg == NULL) {
return FAIL;
- stuffescaped(arg, literally);
- if (allocated)
+ }
+ stuffescaped((const char *)arg, literally);
+ if (allocated) {
xfree(arg);
- } else { /* name or number register */
+ }
+ } else { // Name or number register.
yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
if (reg->y_array == NULL) {
retval = FAIL;
} else {
for (size_t i = 0; i < reg->y_size; i++) {
- stuffescaped(reg->y_array[i], literally);
+ stuffescaped((const char *)reg->y_array[i], literally);
// Insert a newline between lines and after last line if
// y_type is kMTLineWise.
if (reg->y_type == kMTLineWise || i < reg->y_size - 1) {
@@ -1153,29 +1158,29 @@ int insert_reg(
* Stuff a string into the typeahead buffer, such that edit() will insert it
* literally ("literally" TRUE) or interpret is as typed characters.
*/
-static void stuffescaped(char_u *arg, int literally)
+static void stuffescaped(const char *arg, int literally)
{
- int c;
- char_u *start;
-
while (*arg != NUL) {
- /* Stuff a sequence of normal ASCII characters, that's fast. Also
- * stuff K_SPECIAL to get the effect of a special key when "literally"
- * is TRUE. */
- start = arg;
- while ((*arg >= ' ' && *arg < DEL) || (*arg == K_SPECIAL && !literally))
- ++arg;
- if (arg > start)
+ // Stuff a sequence of normal ASCII characters, that's fast. Also
+ // stuff K_SPECIAL to get the effect of a special key when "literally"
+ // is TRUE.
+ const char *const start = arg;
+ while ((*arg >= ' ' && *arg < DEL) || ((uint8_t)(*arg) == K_SPECIAL
+ && !literally)) {
+ arg++;
+ }
+ if (arg > start) {
stuffReadbuffLen(start, (long)(arg - start));
+ }
/* stuff a single special character */
if (*arg != NUL) {
- if (has_mbyte)
- c = mb_cptr2char_adv(&arg);
- else
- c = *arg++;
- if (literally && ((c < ' ' && c != TAB) || c == DEL))
+ const int c = (has_mbyte
+ ? mb_cptr2char_adv((const char_u **)&arg)
+ : (uint8_t)(*arg++));
+ if (literally && ((c < ' ' && c != TAB) || c == DEL)) {
stuffcharReadbuff(Ctrl_V);
+ }
stuffcharReadbuff(c);
}
}
@@ -2555,33 +2560,33 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
dict_T *dict = get_vim_var_dict(VV_EVENT);
// the yanked text
- list_T *list = list_alloc();
+ list_T *list = tv_list_alloc();
for (size_t i = 0; i < reg->y_size; i++) {
- list_append_string(list, reg->y_array[i], -1);
+ tv_list_append_string(list, (const char *)reg->y_array[i], -1);
}
list->lv_lock = VAR_FIXED;
- dict_add_list(dict, "regcontents", list);
+ tv_dict_add_list(dict, S_LEN("regcontents"), list);
// the register type
char buf[NUMBUFLEN+2];
format_reg_type(reg->y_type, reg->y_width, buf, ARRAY_SIZE(buf));
- dict_add_nr_str(dict, "regtype", 0, (char_u *)buf);
+ tv_dict_add_str(dict, S_LEN("regtype"), buf);
// name of requested register or the empty string for an unnamed operation.
buf[0] = (char)oap->regname;
buf[1] = NUL;
- dict_add_nr_str(dict, "regname", 0, (char_u *)buf);
+ tv_dict_add_str(dict, S_LEN("regname"), buf);
// kind of operation (yank/delete/change)
buf[0] = (char)get_op_char(oap->op_type);
buf[1] = NUL;
- dict_add_nr_str(dict, "operator", 0, (char_u *)buf);
+ tv_dict_add_str(dict, S_LEN("operator"), buf);
- dict_set_keys_readonly(dict);
+ tv_dict_set_keys_readonly(dict);
textlock++;
apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, false, curbuf);
textlock--;
- dict_clear(dict);
+ tv_dict_clear(dict);
recursive = false;
}
@@ -2660,7 +2665,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
// back to the previous line in the case of 'noautoindent' and
// 'backspace' includes "eol". So we insert a dummy space for Ctrl_U
// to consume.
- stuffReadbuff((char_u *)"\n ");
+ stuffReadbuff("\n ");
stuffcharReadbuff(Ctrl_U);
}
}
@@ -2672,7 +2677,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
// character. Simulate it with motion commands after the insert.
if (flags & PUT_CURSEND) {
if (flags & PUT_LINE) {
- stuffReadbuff((char_u *)"j0");
+ stuffReadbuff("j0");
} else {
// Avoid ringing the bell from attempting to move into the space after
// the current line. We can stuff the readbuffer with "l" if:
@@ -2702,7 +2707,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
}
} else if (flags & PUT_LINE) {
- stuffReadbuff((char_u *)"g'[");
+ stuffReadbuff("g'[");
}
// So the 'u' command restores cursor position after ".p, save the cursor
@@ -4844,8 +4849,8 @@ static void *get_reg_wrap_one_line(char_u *s, int flags)
if (!(flags & kGRegList)) {
return s;
}
- list_T *list = list_alloc();
- list_append_string(list, NULL, -1);
+ list_T *list = tv_list_alloc();
+ tv_list_append_string(list, NULL, 0);
list->lv_first->li_tv.vval.v_string = s;
return list;
}
@@ -4895,9 +4900,9 @@ void *get_reg_contents(int regname, int flags)
return NULL;
if (flags & kGRegList) {
- list_T *list = list_alloc();
+ list_T *list = tv_list_alloc();
for (size_t i = 0; i < reg->y_size; i++) {
- list_append_string(list, reg->y_array[i], -1);
+ tv_list_append_string(list, (const char *)reg->y_array[i], -1);
}
return list;
@@ -4978,7 +4983,7 @@ void write_reg_contents(int name, const char_u *str, ssize_t len,
write_reg_contents_ex(name, str, len, must_append, kMTUnknown, 0L);
}
-void write_reg_contents_lst(int name, char_u **strings, int maxlen,
+void write_reg_contents_lst(int name, char_u **strings,
bool must_append, MotionType yank_type,
colnr_T block_len)
{
@@ -5482,17 +5487,19 @@ void cursor_pos_info(dict_T *dict)
if (dict != NULL) {
// Don't shorten this message, the user asked for it.
- dict_add_nr_str(dict, "words", word_count, NULL);
- dict_add_nr_str(dict, "chars", char_count, NULL);
- dict_add_nr_str(dict, "bytes", byte_count + bom_count, NULL);
-
- dict_add_nr_str(dict, l_VIsual_active ? "visual_bytes" : "cursor_bytes",
- byte_count_cursor, NULL);
- dict_add_nr_str(dict, l_VIsual_active ? "visual_chars" : "cursor_chars",
- char_count_cursor, NULL);
- dict_add_nr_str(dict, l_VIsual_active ? "visual_words" : "cursor_words",
- word_count_cursor, NULL);
- }
+ tv_dict_add_nr(dict, S_LEN("words"), (varnumber_T)word_count);
+ tv_dict_add_nr(dict, S_LEN("chars"), (varnumber_T)char_count);
+ tv_dict_add_nr(dict, S_LEN("bytes"), (varnumber_T)(byte_count + bom_count));
+
+ STATIC_ASSERT(sizeof("visual") == sizeof("cursor"),
+ "key_len argument in tv_dict_add_nr is wrong");
+ tv_dict_add_nr(dict, l_VIsual_active ? "visual_bytes" : "cursor_bytes",
+ sizeof("visual_bytes") - 1, (varnumber_T)byte_count_cursor);
+ tv_dict_add_nr(dict, l_VIsual_active ? "visual_chars" : "cursor_chars",
+ sizeof("visual_chars") - 1, (varnumber_T)char_count_cursor);
+ tv_dict_add_nr(dict, l_VIsual_active ? "visual_words" : "cursor_words",
+ sizeof("visual_words") - 1, (varnumber_T)word_count_cursor);
+ }
}
/// Check if the default register (used in an unnamed paste) should be a
@@ -5570,9 +5577,9 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
}
free_register(reg);
- list_T *args = list_alloc();
- char_u regname = (char_u)name;
- list_append_string(args, &regname, 1);
+ list_T *const args = tv_list_alloc();
+ const char regname = (char)name;
+ tv_list_append_string(args, &regname, 1);
typval_T result = eval_call_provider("clipboard", "get", args);
@@ -5584,7 +5591,8 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
goto err;
}
- list_T *res = result.vval.v_list, *lines = NULL;
+ list_T *res = result.vval.v_list;
+ list_T *lines = NULL;
if (res->lv_len == 2 && res->lv_first->li_tv.v_type == VAR_LIST) {
lines = res->lv_first->li_tv.vval.v_list;
if (res->lv_last->li_tv.v_type != VAR_STRING) {
@@ -5628,7 +5636,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
if (li->li_tv.v_type != VAR_STRING) {
goto err;
}
- reg->y_array[i++] = (uint8_t *)xstrdup((char *)li->li_tv.vval.v_string);
+ reg->y_array[i++] = (char_u *)xstrdupnul((char *)li->li_tv.vval.v_string);
}
if (reg->y_size > 0 && strlen((char*)reg->y_array[reg->y_size-1]) == 0) {
@@ -5686,35 +5694,39 @@ static void set_clipboard(int name, yankreg_T *reg)
return;
}
- list_T *lines = list_alloc();
+ list_T *lines = tv_list_alloc();
for (size_t i = 0; i < reg->y_size; i++) {
- list_append_string(lines, reg->y_array[i], -1);
+ tv_list_append_string(lines, (const char *)reg->y_array[i], -1);
}
- list_T *args = list_alloc();
- list_append_list(args, lines);
+ list_T *args = tv_list_alloc();
+ tv_list_append_list(args, lines);
- char_u regtype;
+ char regtype;
switch (reg->y_type) {
- case kMTLineWise:
- regtype = 'V';
- list_append_string(lines, (char_u*)"", 0);
- break;
- case kMTCharWise:
- regtype = 'v';
- break;
- case kMTBlockWise:
- regtype = 'b';
- list_append_string(lines, (char_u*)"", 0);
- break;
- case kMTUnknown:
- assert(false);
- }
- list_append_string(args, &regtype, 1);
-
- char_u regname = (char_u)name;
- list_append_string(args, &regname, 1);
+ case kMTLineWise: {
+ regtype = 'V';
+ tv_list_append_string(lines, NULL, 0);
+ break;
+ }
+ case kMTCharWise: {
+ regtype = 'v';
+ break;
+ }
+ case kMTBlockWise: {
+ regtype = 'b';
+ tv_list_append_string(lines, NULL, 0);
+ break;
+ }
+ case kMTUnknown: {
+ assert(false);
+ }
+ }
+ tv_list_append_string(args, &regtype, 1);
+
+ const char regname = (char)name;
+ tv_list_append_string(args, &regname, 1);
(void)eval_call_provider("clipboard", "set", args);
}
diff --git a/src/nvim/ops.h b/src/nvim/ops.h
index 44df2e9e0c..13d0142343 100644
--- a/src/nvim/ops.h
+++ b/src/nvim/ops.h
@@ -6,7 +6,7 @@
#include "nvim/macros.h"
#include "nvim/ascii.h"
#include "nvim/types.h"
-#include "nvim/eval_defs.h"
+#include "nvim/eval/typval.h"
#include "nvim/os/time.h"
typedef int (*Indenter)(void);
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 2a17ca69d1..458d80716c 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -25,6 +25,7 @@
#include <limits.h>
#include "nvim/vim.h"
+#include "nvim/macros.h"
#include "nvim/ascii.h"
#include "nvim/edit.h"
#include "nvim/option.h"
@@ -34,6 +35,7 @@
#include "nvim/diff.h"
#include "nvim/digraph.h"
#include "nvim/eval.h"
+#include "nvim/eval/typval.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
@@ -156,7 +158,6 @@ static long p_ts;
static long p_tw;
static int p_udf;
static long p_wm;
-static long p_scbk;
static char_u *p_keymap;
/* Saved values for when 'bin' is set. */
@@ -244,7 +245,8 @@ typedef struct vimoption {
"A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn,-:Conceal," \
"B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel," \
"x:PmenuSbar,X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill," \
- "!:CursorColumn,.:CursorLine,o:ColorColumn,q:QuickFixLine"
+ "!:CursorColumn,.:CursorLine,o:ColorColumn,q:QuickFixLine," \
+ "0:Whitespace"
/*
* options[] is initialized here.
@@ -605,7 +607,7 @@ void set_init_1(void)
/*
* 'maxmemtot' and 'maxmem' may have to be adjusted for available memory
*/
- opt_idx = findoption((char_u *)"maxmemtot");
+ opt_idx = findoption("maxmemtot");
if (opt_idx >= 0) {
{
/* Use half of amount of memory available to Vim. */
@@ -615,7 +617,7 @@ void set_init_1(void)
? UINTPTR_MAX
: (uintptr_t)(available_kib /2);
options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n;
- opt_idx = findoption((char_u *)"maxmem");
+ opt_idx = findoption("maxmem");
if (opt_idx >= 0) {
options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n;
}
@@ -646,7 +648,7 @@ void set_init_1(void)
}
}
buf[j] = NUL;
- opt_idx = findoption((char_u *)"cdpath");
+ opt_idx = findoption("cdpath");
if (opt_idx >= 0) {
options[opt_idx].def_val[VI_DEFAULT] = buf;
options[opt_idx].flags |= P_DEF_ALLOCED;
@@ -765,8 +767,9 @@ void set_init_1(void)
* NOTE: mlterm's author is being asked to 'set' a variable
* instead of an environment variable due to inheritance.
*/
- if (os_env_exists("MLTERM"))
- set_option_value((char_u *)"tbidi", 1L, NULL, 0);
+ if (os_env_exists("MLTERM")) {
+ set_option_value("tbidi", 1L, NULL, 0);
+ }
didset_options2();
@@ -776,7 +779,7 @@ void set_init_1(void)
char_u *p = enc_locale();
if (p == NULL) {
// use utf-8 as 'default' if locale encoding can't be detected.
- p = vim_strsave((char_u *)"utf-8");
+ p = (char_u *)xmemdupz(S_LEN("utf-8"));
}
fenc_default = p;
@@ -883,7 +886,7 @@ set_options_default (
static void set_string_default(const char *name, char *val, bool allocated)
FUNC_ATTR_NONNULL_ALL
{
- int opt_idx = findoption((char_u *)name);
+ int opt_idx = findoption(name);
if (opt_idx >= 0) {
if (options[opt_idx].flags & P_DEF_ALLOCED) {
xfree(options[opt_idx].def_val[VI_DEFAULT]);
@@ -905,9 +908,10 @@ void set_number_default(char *name, long val)
{
int opt_idx;
- opt_idx = findoption((char_u *)name);
- if (opt_idx >= 0)
+ opt_idx = findoption(name);
+ if (opt_idx >= 0) {
options[opt_idx].def_val[VI_DEFAULT] = (char_u *)val;
+ }
}
#if defined(EXITFREE)
@@ -935,11 +939,8 @@ void free_all_options(void)
#endif
-/*
- * Initialize the options, part two: After getting Rows and Columns and
- * setting 'term'.
- */
-void set_init_2(void)
+/// Initialize the options, part two: After getting Rows and Columns.
+void set_init_2(bool headless)
{
int idx;
@@ -948,20 +949,26 @@ void set_init_2(void)
* wrong when the window height changes.
*/
set_number_default("scroll", Rows / 2);
- idx = findoption((char_u *)"scroll");
- if (idx >= 0 && !(options[idx].flags & P_WAS_SET))
+ idx = findoption("scroll");
+ if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) {
set_option_default(idx, OPT_LOCAL, p_cp);
+ }
comp_col();
/*
* 'window' is only for backwards compatibility with Vi.
* Default is Rows - 1.
*/
- if (!option_was_set((char_u *)"window"))
+ if (!option_was_set("window")) {
p_window = Rows - 1;
+ }
set_number_default("window", Rows - 1);
- parse_shape_opt(SHAPE_CURSOR); /* set cursor shapes from 'guicursor' */
- (void)parse_printoptions(); /* parse 'printoptions' default value */
+ if (!headless && !os_term_is_nice()) {
+ set_string_option_direct((char_u *)"guicursor", -1, (char_u *)"",
+ OPT_GLOBAL, SID_NONE);
+ }
+ parse_shape_opt(SHAPE_CURSOR); // set cursor shapes from 'guicursor'
+ (void)parse_printoptions(); // parse 'printoptions' default value
}
/*
@@ -977,16 +984,18 @@ void set_init_3(void)
int idx_sp;
int do_sp;
- idx_srr = findoption((char_u *)"srr");
- if (idx_srr < 0)
- do_srr = FALSE;
- else
+ idx_srr = findoption("srr");
+ if (idx_srr < 0) {
+ do_srr = false;
+ } else {
do_srr = !(options[idx_srr].flags & P_WAS_SET);
- idx_sp = findoption((char_u *)"sp");
- if (idx_sp < 0)
- do_sp = FALSE;
- else
+ }
+ idx_sp = findoption("sp");
+ if (idx_sp < 0) {
+ do_sp = false;
+ } else {
do_sp = !(options[idx_sp].flags & P_WAS_SET);
+ }
size_t len = 0;
char_u *p = (char_u *)invocation_path_tail(p_sh, &len);
@@ -1030,7 +1039,7 @@ void set_init_3(void)
}
if (bufempty()) {
- int idx_ffs = findoption((char_u *)"ffs");
+ int idx_ffs = findoption_len(S_LEN("ffs"));
// Apply the first entry of 'fileformats' to the initial buffer.
if (idx_ffs >= 0 && (options[idx_ffs].flags & P_WAS_SET)) {
@@ -1047,16 +1056,20 @@ void set_init_3(void)
*/
void set_helplang_default(const char *lang)
{
- int idx;
+ if (lang == NULL) {
+ return;
+ }
- if (lang == NULL || STRLEN(lang) < 2) /* safety check */
+ const size_t lang_len = strlen(lang);
+ if (lang_len < 2) { // safety check
return;
- idx = findoption((char_u *)"hlg");
+ }
+ int idx = findoption("hlg");
if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) {
if (options[idx].flags & P_ALLOCED)
free_string_option(p_hlg);
- p_hlg = (char_u *)xstrdup(lang);
- /* zh_CN becomes "cn", zh_TW becomes "tw". */
+ p_hlg = (char_u *)xmemdupz(lang, lang_len);
+ // zh_CN becomes "cn", zh_TW becomes "tw".
if (STRNICMP(p_hlg, "zh_", 3) == 0 && STRLEN(p_hlg) >= 5) {
p_hlg[0] = (char_u)TOLOWER_ASC(p_hlg[3]);
p_hlg[1] = (char_u)TOLOWER_ASC(p_hlg[4]);
@@ -1083,12 +1096,12 @@ void set_title_defaults(void)
* icon name. Saves a bit of time, because the X11 display server does
* not need to be contacted.
*/
- idx1 = findoption((char_u *)"title");
+ idx1 = findoption("title");
if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) {
options[idx1].def_val[VI_DEFAULT] = (char_u *)(intptr_t)0;
p_title = 0;
}
- idx1 = findoption((char_u *)"icon");
+ idx1 = findoption("icon");
if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) {
options[idx1].def_val[VI_DEFAULT] = (char_u *)(intptr_t)0;
p_icon = 0;
@@ -1194,7 +1207,7 @@ do_set (
goto skip;
}
if (arg[1] == 't' && arg[2] == '_') { // could be term code
- opt_idx = findoption_len(arg + 1, (size_t) (len - 1));
+ opt_idx = findoption_len((const char *)arg + 1, (size_t)(len - 1));
}
len++;
if (opt_idx == -1) {
@@ -1210,7 +1223,7 @@ do_set (
len++;
}
}
- opt_idx = findoption_len(arg, (size_t) len);
+ opt_idx = findoption_len((const char *)arg, (size_t)len);
if (opt_idx == -1) {
key = find_key_option(arg);
}
@@ -1392,11 +1405,10 @@ do_set (
value = prefix;
}
- errmsg = set_bool_option(opt_idx, varp, (int)value,
- opt_flags);
- } else { /* numeric or string */
- if (vim_strchr((char_u *)"=:&<", nextchar) == NULL
- || prefix != 1) {
+ errmsg = (char_u *)set_bool_option(opt_idx, varp, (int)value,
+ opt_flags);
+ } else { // Numeric or string.
+ if (strchr("=:&<", nextchar) == NULL || prefix != 1) {
errmsg = e_invarg;
goto skip;
}
@@ -1449,15 +1461,19 @@ do_set (
goto skip;
}
- if (adding)
+ if (adding) {
value = *(long *)varp + value;
- if (prepending)
+ }
+ if (prepending) {
value = *(long *)varp * value;
- if (removing)
+ }
+ if (removing) {
value = *(long *)varp - value;
- errmsg = set_num_option(opt_idx, varp, value,
- errbuf, sizeof(errbuf), opt_flags);
- } else if (opt_idx >= 0) { /* string */
+ }
+ errmsg = (char_u *)set_num_option(opt_idx, varp, value,
+ errbuf, sizeof(errbuf),
+ opt_flags);
+ } else if (opt_idx >= 0) { // String.
char_u *save_arg = NULL;
char_u *s = NULL;
char_u *oldval = NULL; // previous value if *varp
@@ -2222,7 +2238,7 @@ static void check_string_option(char_u **pp)
*/
int was_set_insecurely(char_u *opt, int opt_flags)
{
- int idx = findoption(opt);
+ int idx = findoption((const char *)opt);
if (idx >= 0) {
uint32_t *flagp = insecure_flag(idx, opt_flags);
@@ -2284,9 +2300,9 @@ set_string_option_direct (
int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
int idx = opt_idx;
- if (idx == -1) { /* use name */
- idx = findoption(name);
- if (idx < 0) { /* not found (should not happen) */
+ if (idx == -1) { // Use name.
+ idx = findoption((const char *)name);
+ if (idx < 0) { // Not found (should not happen).
EMSG2(_(e_intern2), "set_string_option_direct()");
EMSG2(_("For option %s"), name);
return;
@@ -2570,7 +2586,7 @@ did_set_string_option (
// The color scheme must have set 'background' back to another
// value, that's not what we want here. Disable the color
// scheme and set the colors again.
- do_unlet((char_u *)"g:colors_name", true);
+ do_unlet(S_LEN("g:colors_name"), true);
free_string_option(p_bg);
p_bg = vim_strsave((char_u *)(dark ? "dark" : "light"));
check_string_option(&p_bg);
@@ -2766,7 +2782,7 @@ did_set_string_option (
// option.
opt_idx = ((options[opt_idx].fullname[0] == 'v')
? (shada_idx == -1
- ? ((shada_idx = findoption((char_u *) "shada")))
+ ? ((shada_idx = findoption("shada")))
: shada_idx)
: opt_idx);
// Update free_oldval now that we have the opt_idx for 'shada', otherwise
@@ -2827,9 +2843,10 @@ did_set_string_option (
}
}
- /* 'guicursor' */
- else if (varp == &p_guicursor)
+ // 'guicursor'
+ else if (varp == &p_guicursor) {
errmsg = parse_shape_opt(SHAPE_CURSOR);
+ }
else if (varp == &p_popt)
errmsg = parse_printoptions();
@@ -3407,15 +3424,18 @@ static char_u *set_chars_option(char_u **varp)
&& p[len] == ':'
&& p[len + 1] != NUL) {
s = p + len + 1;
- c1 = mb_ptr2char_adv(&s);
- if (mb_char2cells(c1) > 1)
+ c1 = mb_ptr2char_adv((const char_u **)&s);
+ if (mb_char2cells(c1) > 1) {
continue;
+ }
if (tab[i].cp == &lcs_tab2) {
- if (*s == NUL)
+ if (*s == NUL) {
continue;
- c2 = mb_ptr2char_adv(&s);
- if (mb_char2cells(c2) > 1)
+ }
+ c2 = mb_ptr2char_adv((const char_u **)&s);
+ if (mb_char2cells(c2) > 1) {
continue;
+ }
}
if (*s == ',' || *s == NUL) {
if (round) {
@@ -3576,24 +3596,24 @@ static void set_option_scriptID_idx(int opt_idx, int opt_flags, int id)
}
}
-/*
- * Set the value of a boolean option, and take care of side effects.
- * Returns NULL for success, or an error message for an error.
- */
-static char_u *
-set_bool_option (
- int opt_idx, /* index in options[] table */
- char_u *varp, /* pointer to the option variable */
- int value, /* new value */
- int opt_flags /* OPT_LOCAL and/or OPT_GLOBAL */
-)
+/// Set the value of a boolean option, taking care of side effects
+///
+/// @param[in] opt_idx Option index in options[] table.
+/// @param[out] varp Pointer to the option variable.
+/// @param[in] value New value.
+/// @param[in] opt_flags OPT_LOCAL and/or OPT_GLOBAL.
+///
+/// @return NULL on success, error message on error.
+static char *set_bool_option(const int opt_idx, char_u *const varp,
+ const int value,
+ const int opt_flags)
{
int old_value = *(int *)varp;
/* Disallow changing some options from secure mode */
if ((secure || sandbox != 0)
&& (options[opt_idx].flags & P_SECURE)) {
- return e_secure;
+ return (char *)e_secure;
}
*(int *)varp = value; /* set the new value */
@@ -3606,20 +3626,24 @@ set_bool_option (
*(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = value;
// Ensure that options set to p_force_on cannot be disabled.
- if ((int *)varp == &p_force_on && p_force_on == FALSE) {
- p_force_on = TRUE;
- return e_unsupportedoption;
- }
+ if ((int *)varp == &p_force_on && p_force_on == false) {
+ p_force_on = true;
+ return (char *)e_unsupportedoption;
// Ensure that options set to p_force_off cannot be enabled.
- else if ((int *)varp == &p_force_off && p_force_off == TRUE) {
- p_force_off = FALSE;
- return e_unsupportedoption;
- }
- /* 'undofile' */
- else if ((int *)varp == &curbuf->b_p_udf || (int *)varp == &p_udf) {
- /* Only take action when the option was set. When reset we do not
- * delete the undo file, the option may be set again without making
- * any changes in between. */
+ } else if ((int *)varp == &p_force_off && p_force_off == true) {
+ p_force_off = false;
+ return (char *)e_unsupportedoption;
+ } else if ((int *)varp == &p_lrm) {
+ // 'langremap' -> !'langnoremap'
+ p_lnr = !p_lrm;
+ } else if ((int *)varp == &p_lnr) {
+ // 'langnoremap' -> !'langremap'
+ p_lrm = !p_lnr;
+ // 'undofile'
+ } else if ((int *)varp == &curbuf->b_p_udf || (int *)varp == &p_udf) {
+ // Only take action when the option was set. When reset we do not
+ // delete the undo file, the option may be set again without making
+ // any changes in between.
if (curbuf->b_p_udf || p_udf) {
char_u hash[UNDO_HASH_SIZE];
buf_T *save_curbuf = curbuf;
@@ -3741,8 +3765,8 @@ set_bool_option (
if (curwin->w_p_pvw) {
FOR_ALL_WINDOWS_IN_TAB(win, curtab) {
if (win->w_p_pvw && win != curwin) {
- curwin->w_p_pvw = FALSE;
- return (char_u *)N_("E590: A preview window already exists");
+ curwin->w_p_pvw = false;
+ return N_("E590: A preview window already exists");
}
}
}
@@ -3890,9 +3914,8 @@ set_bool_option (
/* set 'delcombine' */
p_deco = TRUE;
- /* Force-set the necessary keymap for arabic */
- set_option_value((char_u *)"keymap", 0L, (char_u *)"arabic",
- OPT_LOCAL);
+ // Force-set the necessary keymap for arabic.
+ set_option_value("keymap", 0L, "arabic", OPT_LOCAL);
p_altkeymap = 0;
p_hkmap = 0;
p_fkmap = 0;
@@ -3958,20 +3981,18 @@ set_bool_option (
return NULL;
}
-/*
- * Set the value of a number option, and take care of side effects.
- * Returns NULL for success, or an error message for an error.
- */
-static char_u *
-set_num_option (
- int opt_idx, /* index in options[] table */
- char_u *varp, /* pointer to the option variable */
- long value, /* new value */
- char_u *errbuf, /* buffer for error messages */
- size_t errbuflen, /* length of "errbuf" */
- int opt_flags /* OPT_LOCAL, OPT_GLOBAL and
- OPT_MODELINE */
-)
+/// Set the value of a number option, taking care of side effects
+///
+/// @param[in] opt_idx Option index in options[] table.
+/// @param[out] varp Pointer to the option variable.
+/// @param[in] value New value.
+/// @param errbuf Buffer for error messages.
+/// @param[in] errbuflen Length of `errbuf`.
+/// @param[in] opt_flags OPT_LOCAL, OPT_GLOBAL or OPT_MODELINE.
+///
+/// @return NULL on success, error message on error.
+static char *set_num_option(int opt_idx, char_u *varp, long value,
+ char_u *errbuf, size_t errbuflen, int opt_flags)
{
char_u *errmsg = NULL;
long old_value = *(long *)varp;
@@ -3982,7 +4003,7 @@ set_num_option (
/* Disallow changing some options from secure mode. */
if ((secure || sandbox != 0)
&& (options[opt_idx].flags & P_SECURE)) {
- return e_secure;
+ return (char *)e_secure;
}
*pp = value;
@@ -4199,16 +4220,13 @@ set_num_option (
FOR_ALL_TAB_WINDOWS(tp, wp) {
check_colorcolumn(wp);
}
- } else if (pp == &curbuf->b_p_scbk) {
+ } else if (pp == &curbuf->b_p_scbk || pp == &p_scbk) {
// 'scrollback'
- if (!curbuf->terminal) {
+ if (*pp < -1 || *pp > SB_MAX
+ || (opt_flags == OPT_LOCAL && !curbuf->terminal)) {
errmsg = e_invarg;
- curbuf->b_p_scbk = -1;
- } else {
- if (curbuf->b_p_scbk < -1 || curbuf->b_p_scbk > 100000) {
- errmsg = e_invarg;
- curbuf->b_p_scbk = 1000;
- }
+ *pp = old_value;
+ } else if (curbuf->terminal) {
// Force the scrollback to take effect.
terminal_resize(curbuf->terminal, UINT16_MAX, UINT16_MAX);
}
@@ -4255,8 +4273,9 @@ set_num_option (
cmdline_row = (int)(Rows - p_ch);
}
}
- if (p_window >= Rows || !option_was_set((char_u *)"window"))
+ if (p_window >= Rows || !option_was_set("window")) {
p_window = Rows - 1;
+ }
}
if (curbuf->b_p_ts <= 0) {
@@ -4331,6 +4350,11 @@ set_num_option (
if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
*(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = *pp;
+ if (pp == &curbuf->b_p_scbk && !curbuf->terminal) {
+ // Normal buffer: reset local 'scrollback' after updating the global value.
+ curbuf->b_p_scbk = -1;
+ }
+
options[opt_idx].flags |= P_WAS_SET;
if (!starting && errmsg == NULL) {
@@ -4356,7 +4380,7 @@ set_num_option (
curwin->w_set_curswant = TRUE;
check_redraw(options[opt_idx].flags);
- return errmsg;
+ return (char *)errmsg;
}
/*
@@ -4394,39 +4418,36 @@ static void check_redraw(uint32_t flags)
/// @param[in] len Length of the option.
///
/// @return Index of the option or -1 if option was not found.
-int findoption_len(const char_u *const arg, const size_t len)
+int findoption_len(const char *const arg, const size_t len)
{
- char *s, *p;
+ const char *s;
+ const char *p;
static int quick_tab[27] = { 0, 0 }; // quick access table
- int is_term_opt;
- /*
- * For first call: Initialize the quick-access table.
- * It contains the index for the first option that starts with a certain
- * letter. There are 26 letters, plus the first "t_" option.
- */
+ // For first call: Initialize the quick-access table.
+ // It contains the index for the first option that starts with a certain
+ // letter. There are 26 letters, plus the first "t_" option.
if (quick_tab[1] == 0) {
p = options[0].fullname;
for (short int i = 1; (s = options[i].fullname) != NULL; i++) {
if (s[0] != p[0]) {
- if (s[0] == 't' && s[1] == '_')
+ if (s[0] == 't' && s[1] == '_') {
quick_tab[26] = i;
- else
+ } else {
quick_tab[CharOrdLow(s[0])] = i;
+ }
}
p = s;
}
}
- /*
- * Check for name starting with an illegal character.
- */
+ // Check for name starting with an illegal character.
if (len == 0 || arg[0] < 'a' || arg[0] > 'z') {
return -1;
}
int opt_idx;
- is_term_opt = (len > 2 && arg[0] == 't' && arg[1] == '_');
+ const bool is_term_opt = (len > 2 && arg[0] == 't' && arg[1] == '_');
if (is_term_opt) {
opt_idx = quick_tab[26];
} else {
@@ -4434,7 +4455,7 @@ int findoption_len(const char_u *const arg, const size_t len)
}
// Match full name
for (; (s = options[opt_idx].fullname) != NULL; opt_idx++) {
- if (STRNCMP(arg, s, len) == 0 && s[len] == NUL) {
+ if (strncmp(arg, s, len) == 0 && s[len] == NUL) {
break;
}
}
@@ -4443,20 +4464,22 @@ int findoption_len(const char_u *const arg, const size_t len)
// Match short name
for (; options[opt_idx].fullname != NULL; opt_idx++) {
s = options[opt_idx].shortname;
- if (s != NULL && STRNCMP(arg, s, len) == 0 && s[len] == NUL) {
+ if (s != NULL && strncmp(arg, s, len) == 0 && s[len] == NUL) {
break;
}
s = NULL;
}
}
- if (s == NULL)
+ if (s == NULL) {
opt_idx = -1;
+ }
return opt_idx;
}
-bool is_tty_option(char *name)
+bool is_tty_option(const char *name)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- return (name[0] == 't' && name[1] == '_') || !strcmp((char *)name, "term");
+ return (name[0] == 't' && name[1] == '_') || strcmp(name, "term") == 0;
}
#define TCO_BUFFER_SIZE 8
@@ -4492,7 +4515,7 @@ bool get_tty_option(char *name, char **value)
return false;
}
-bool set_tty_option(char *name, char *value)
+bool set_tty_option(const char *name, const char *value)
{
if (!strcmp(name, "t_Co")) {
int colors = atoi(value);
@@ -4503,23 +4526,24 @@ bool set_tty_option(char *name, char *value)
if (colors != t_colors) {
t_colors = colors;
// We now have a different color setup, initialize it again.
- init_highlight(TRUE, FALSE);
+ init_highlight(true, false);
}
return true;
}
- return is_tty_option(name) || !strcmp(name, "term")
- || !strcmp(name, "ttytype");
+ return (is_tty_option(name) || !strcmp(name, "term")
+ || !strcmp(name, "ttytype"));
}
-/*
- * Find index for option 'arg'.
- * Return -1 if not found.
- */
-static int findoption(char_u *arg)
+/// Find index for an option
+///
+/// @param[in] arg Option name.
+///
+/// @return Option index or -1 if option was not found.
+static int findoption(const char *const arg)
{
- return findoption_len(arg, STRLEN(arg));
+ return findoption_len(arg, strlen(arg));
}
/*
@@ -4547,9 +4571,10 @@ get_option_value (
int opt_idx;
char_u *varp;
- opt_idx = findoption(name);
- if (opt_idx < 0) /* unknown option */
+ opt_idx = findoption((const char *)name);
+ if (opt_idx < 0) { // Unknown option.
return -3;
+ }
varp = get_varp_scope(&(options[opt_idx]), opt_flags);
@@ -4586,7 +4611,7 @@ get_option_value (
//
// Pretends that option is absent if it is not present in the requested scope
// (i.e. has no global, window-local or buffer-local value depending on
-// opt_type). Uses
+// opt_type).
//
// Returned flags:
// 0 hidden or unknown option, also option that does not have requested
@@ -4605,14 +4630,13 @@ int get_option_value_strict(char *name,
}
char_u *varp = NULL;
- vimoption_T *p;
int rv = 0;
- int opt_idx = findoption((uint8_t *)name);
+ int opt_idx = findoption(name);
if (opt_idx < 0) {
return 0;
}
- p = &(options[opt_idx]);
+ vimoption_T *p = &options[opt_idx];
// Hidden option
if (p->var == NULL) {
@@ -4628,26 +4652,25 @@ int get_option_value_strict(char *name,
}
if (p->indir == PV_NONE) {
- if (opt_type == SREQ_GLOBAL)
+ if (opt_type == SREQ_GLOBAL) {
rv |= SOPT_GLOBAL;
- else
- return 0; // Did not request global-only option
+ } else {
+ return 0; // Did not request global-only option
+ }
} else {
if (p->indir & PV_BOTH) {
rv |= SOPT_GLOBAL;
- } else if (opt_type == SREQ_GLOBAL) {
- return 0; // Requested global option
}
if (p->indir & PV_WIN) {
if (opt_type == SREQ_BUF) {
- return 0; // Did not request window-local option
+ return 0; // Requested buffer-local, not window-local option
} else {
rv |= SOPT_WIN;
}
} else if (p->indir & PV_BUF) {
if (opt_type == SREQ_WIN) {
- return 0; // Did not request buffer-local option
+ return 0; // Requested window-local, not buffer-local option
} else {
rv |= SOPT_BUF;
}
@@ -4659,7 +4682,11 @@ int get_option_value_strict(char *name,
}
if (opt_type == SREQ_GLOBAL) {
- varp = p->var;
+ if (p->var == VAR_WIN) {
+ return 0;
+ } else {
+ varp = p->var;
+ }
} else {
if (opt_type == SREQ_BUF) {
// Special case: 'modified' is b_changed, but we also want to
@@ -4701,21 +4728,19 @@ int get_option_value_strict(char *name,
return rv;
}
-/*
- * Set the value of option "name".
- * Use "string" for string options, use "number" for other options.
- *
- * Returns NULL on success or error message on error.
- */
-char_u *
-set_option_value (
- char_u *name,
- long number,
- char_u *string,
- int opt_flags /* OPT_LOCAL or 0 (both) */
-)
+/// Set the value of an option
+///
+/// @param[in] name Option name.
+/// @param[in] number New value for the number or boolean option.
+/// @param[in] string New value for string option.
+/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both).
+///
+/// @return NULL on success, error message on error.
+char *set_option_value(const char *const name, const long number,
+ const char *const string, const int opt_flags)
+ FUNC_ATTR_NONNULL_ARG(1)
{
- if (set_tty_option((char *)name, (char *)string)) {
+ if (set_tty_option(name, string)) {
return NULL;
}
@@ -4723,9 +4748,9 @@ set_option_value (
char_u *varp;
opt_idx = findoption(name);
- if (opt_idx < 0)
+ if (opt_idx < 0) {
EMSG2(_("E355: Unknown option: %s"), name);
- else {
+ } else {
uint32_t flags = options[opt_idx].flags;
// Disallow changing some options in the sandbox
if (sandbox > 0 && (flags & P_SECURE)) {
@@ -4733,11 +4758,11 @@ set_option_value (
return NULL;
}
if (flags & P_STRING) {
- const char *s = (const char *)string;
+ const char *s = string;
if (s == NULL) {
s = "";
}
- return (char_u *)set_string_option(opt_idx, s, opt_flags);
+ return set_string_option(opt_idx, s, opt_flags);
} else {
varp = get_varp_scope(&(options[opt_idx]), opt_flags);
if (varp != NULL) { /* hidden option is not changed */
@@ -4756,12 +4781,11 @@ set_option_value (
return NULL; // do nothing as we hit an error
}
}
- if (flags & P_NUM)
- return set_num_option(opt_idx, varp, number,
- NULL, 0, opt_flags);
- else
- return set_bool_option(opt_idx, varp, (int)number,
- opt_flags);
+ if (flags & P_NUM) {
+ return set_num_option(opt_idx, varp, number, NULL, 0, opt_flags);
+ } else {
+ return set_bool_option(opt_idx, varp, (int)number, opt_flags);
+ }
}
}
}
@@ -4772,9 +4796,10 @@ char_u *get_highlight_default(void)
{
int i;
- i = findoption((char_u *)"hl");
- if (i >= 0)
+ i = findoption("hl");
+ if (i >= 0) {
return options[i].def_val[VI_DEFAULT];
+ }
return (char_u *)NULL;
}
@@ -5211,7 +5236,7 @@ void unset_global_local_option(char *name, void *from)
vimoption_T *p;
buf_T *buf = (buf_T *)from;
- int opt_idx = findoption((uint8_t *)name);
+ int opt_idx = findoption(name);
if (opt_idx < 0) {
EMSG2(_("E355: Unknown option: %s"), name);
return;
@@ -5774,11 +5799,12 @@ void reset_modifiable(void)
{
int opt_idx;
- curbuf->b_p_ma = FALSE;
- p_ma = FALSE;
- opt_idx = findoption((char_u *)"ma");
- if (opt_idx >= 0)
- options[opt_idx].def_val[VI_DEFAULT] = FALSE;
+ curbuf->b_p_ma = false;
+ p_ma = false;
+ opt_idx = findoption("ma");
+ if (opt_idx >= 0) {
+ options[opt_idx].def_val[VI_DEFAULT] = false;
+ }
}
/*
@@ -5876,15 +5902,15 @@ set_context_in_set_cmd (
expand_option_name[2] = p[-2];
expand_option_name[3] = p[-1];
} else {
- /* Allow * wildcard */
- while (ASCII_ISALNUM(*p) || *p == '_' || *p == '*')
+ // Allow * wildcard.
+ while (ASCII_ISALNUM(*p) || *p == '_' || *p == '*') {
p++;
- if (*p == NUL)
+ }
+ if (*p == NUL) {
return;
+ }
nextchar = *p;
- *p = NUL;
- opt_idx = findoption(arg);
- *p = nextchar;
+ opt_idx = findoption_len((const char *)arg, (size_t)(p - arg));
if (opt_idx == -1 || options[opt_idx].var == NULL) {
xp->xp_context = EXPAND_NOTHING;
return;
@@ -6046,7 +6072,7 @@ void ExpandOldSetting(int *num_file, char_u ***file)
* For a terminal key code expand_option_idx is < 0.
*/
if (expand_option_idx < 0) {
- expand_option_idx = findoption(expand_option_name);
+ expand_option_idx = findoption((const char *)expand_option_name);
}
if (expand_option_idx >= 0) {
@@ -6446,20 +6472,22 @@ void vimrc_found(char_u *fname, char_u *envname)
}
}
-/*
- * Return TRUE when option "name" has been set.
- * Only works correctly for global options.
- */
-int option_was_set(char_u *name)
+/// Check whether global option has been set
+///
+/// @param[in] name Option name.
+///
+/// @return True if it was set.
+static bool option_was_set(const char *name)
{
int idx;
idx = findoption(name);
- if (idx < 0) /* unknown option */
- return FALSE;
- if (options[idx].flags & P_WAS_SET)
- return TRUE;
- return FALSE;
+ if (idx < 0) { // Unknown option.
+ return false;
+ } else if (options[idx].flags & P_WAS_SET) {
+ return true;
+ }
+ return false;
}
/*
@@ -6875,8 +6903,8 @@ void set_fileformat(int eol_style, int opt_flags)
need_maketitle = true; // Set window title later.
}
-/// Skip to next part of an option argument: Skip space and comma.
-char_u *skip_to_option_part(char_u *p)
+/// Skip to next part of an option argument: skip space and comma
+char_u *skip_to_option_part(const char_u *p)
{
if (*p == ',') {
p++;
@@ -6884,7 +6912,7 @@ char_u *skip_to_option_part(char_u *p)
while (*p == ' ') {
p++;
}
- return p;
+ return (char_u *)p;
}
/// Isolate one part of a string option separated by `sep_chars`.
@@ -6944,10 +6972,11 @@ bool signcolumn_on(win_T *wp)
return wp->w_buffer->b_signlist != NULL;
}
-/// Get window or buffer local options.
-dict_T * get_winbuf_options(int bufopt)
+/// Get window or buffer local options
+dict_T *get_winbuf_options(const int bufopt)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
{
- dict_T *d = dict_alloc();
+ dict_T *const d = tv_dict_alloc();
for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) {
struct vimoption *opt = &options[opt_idx];
@@ -6958,9 +6987,10 @@ dict_T * get_winbuf_options(int bufopt)
if (varp != NULL) {
if (opt->flags & P_STRING) {
- dict_add_nr_str(d, opt->fullname, 0L, *(char_u **)varp);
+ tv_dict_add_str(d, opt->fullname, strlen(opt->fullname),
+ *(const char **)varp);
} else {
- dict_add_nr_str(d, opt->fullname, *varp, NULL);
+ tv_dict_add_nr(d, opt->fullname, strlen(opt->fullname), *varp);
}
}
}
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index b171b23edb..4ee0f4f225 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -16,9 +16,9 @@
#define SOPT_UNSET 0x40 // Option does not have local value set
// Option types for various functions in option.c
-#define SREQ_GLOBAL 0 // Request global option
-#define SREQ_WIN 1 // Request window-local option
-#define SREQ_BUF 2 // Request buffer-local option
+#define SREQ_GLOBAL 0 // Request global option value
+#define SREQ_WIN 1 // Request window-local option value
+#define SREQ_BUF 2 // Request buffer-local option value
/*
* Default values for 'errorformat'.
@@ -476,8 +476,9 @@ EXTERN char_u *p_isp; // 'isprint'
EXTERN int p_js; // 'joinspaces'
EXTERN char_u *p_kp; // 'keywordprg'
EXTERN char_u *p_km; // 'keymodel'
-EXTERN char_u *p_langmap; // 'langmap'*/
-EXTERN int p_lnr; // 'langnoremap'*/
+EXTERN char_u *p_langmap; // 'langmap'
+EXTERN int p_lnr; // 'langnoremap'
+EXTERN int p_lrm; // 'langremap'
EXTERN char_u *p_lm; // 'langmenu'
EXTERN char_u *p_lispwords; // 'lispwords'
EXTERN long p_ls; // 'laststatus'
@@ -524,6 +525,7 @@ EXTERN int p_ru; // 'ruler'
EXTERN char_u *p_ruf; // 'rulerformat'
EXTERN char_u *p_pp; // 'packpath'
EXTERN char_u *p_rtp; // 'runtimepath'
+EXTERN long p_scbk; // 'scrollback'
EXTERN long p_sj; // 'scrolljump'
EXTERN long p_so; // 'scrolloff'
EXTERN char_u *p_sbo; // 'scrollopt'
@@ -811,4 +813,6 @@ enum {
/* Value for b_p_ul indicating the global value must be used. */
#define NO_LOCAL_UNDOLEVEL -123456
+#define SB_MAX 100000 // Maximum 'scrollback' value.
+
#endif // NVIM_OPTION_DEFS_H
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 853c2b52d7..4ca63f2efe 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1000,7 +1000,7 @@ return {
deny_duplicates=true,
vi_def=true,
varname='p_guicursor',
- defaults={if_true={vi="n-v-c:block,o:hor50,i-ci:hor15,r-cr:hor30,sm:block"}}
+ defaults={if_true={vi="n-v-c:block-Cursor/lCursor,ve:ver35-Cursor,o:hor50-Cursor,i-ci:ver25-Cursor/lCursor,r-cr:hor20-Cursor/lCursor,sm:block-Cursor-blinkwait175-blinkoff150-blinkon175"}}
},
{
full_name='guifont', abbreviation='gfn',
@@ -1026,13 +1026,6 @@ return {
enable_if=false,
},
{
- full_name='guiheadroom', abbreviation='ghr',
- type='number', scope={'global'},
- vi_def=true,
- enable_if=false,
- defaults={if_true={vi=50}}
- },
- {
full_name='guioptions', abbreviation='go',
type='string', list='flags', scope={'global'},
vi_def=true,
@@ -1347,6 +1340,12 @@ return {
defaults={if_true={vi=false, vim=true}}
},
{
+ full_name='langremap', abbreviation='lrm',
+ type='bool', scope={'global'},
+ varname='p_lrm',
+ defaults={if_true={vi=true, vim=false}}
+ },
+ {
full_name='laststatus', abbreviation='ls',
type='number', scope={'global'},
vim=true,
@@ -1918,7 +1917,7 @@ return {
vi_def=true,
varname='p_scbk',
redraw={'current_buffer'},
- defaults={if_true={vi=-1}}
+ defaults={if_true={vi=1000}}
},
{
full_name='scrollbind', abbreviation='scb',
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index a73d753e46..12c2da6152 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -118,7 +118,6 @@ char *os_getenvname_at_index(size_t index)
return name;
}
-
/// Get the process ID of the Neovim process.
///
/// @return the process ID.
@@ -145,10 +144,27 @@ void os_get_hostname(char *hostname, size_t size)
} else {
xstrlcpy(hostname, vutsname.nodename, size);
}
+#elif defined(WIN32)
+ WCHAR host_utf16[MAX_COMPUTERNAME_LENGTH + 1];
+ DWORD host_wsize = sizeof(host_utf16) / sizeof(host_utf16[0]);
+ if (GetComputerNameW(host_utf16, &host_wsize) == 0) {
+ *hostname = '\0';
+ DWORD err = GetLastError();
+ EMSG2("GetComputerNameW failed: %d", err);
+ return;
+ }
+ host_utf16[host_wsize] = '\0';
+
+ char *host_utf8;
+ int conversion_result = utf16_to_utf8(host_utf16, &host_utf8);
+ if (conversion_result != 0) {
+ EMSG2("utf16_to_utf8 failed: %d", conversion_result);
+ return;
+ }
+ xstrlcpy(hostname, host_utf8, size);
+ xfree(host_utf8);
#else
- // TODO(unknown): Implement this for windows.
- // See the implementation used in vim:
- // https://code.google.com/p/vim/source/browse/src/os_win32.c?r=6b69d8dde19e32909f4ee3a6337e6a2ecfbb6f72#2899
+ EMSG("os_get_hostname failed: missing uname()");
*hostname = '\0';
#endif
}
@@ -615,9 +631,9 @@ char *vim_getenv(const char *name)
vim_path = (char *)p_hf;
}
+ char exe_name[MAXPATHL];
// Find runtime path relative to the nvim binary: ../share/nvim/runtime
if (vim_path == NULL) {
- char exe_name[MAXPATHL];
size_t exe_name_len = MAXPATHL;
if (os_exepath(exe_name, &exe_name_len) == 0) {
char *path_end = (char *)path_tail_with_sep((char_u *)exe_name);
@@ -703,7 +719,8 @@ char *vim_getenv(const char *name)
/// @param dstlen Maximum length of the result
/// @param one If true, only replace one file name, including spaces and commas
/// in the file name
-void home_replace(buf_T *buf, char_u *src, char_u *dst, int dstlen, bool one)
+void home_replace(const buf_T *const buf, const char_u *src,
+ char_u *dst, size_t dstlen, bool one)
{
size_t dirlen = 0, envlen = 0;
size_t len;
@@ -717,7 +734,7 @@ void home_replace(buf_T *buf, char_u *src, char_u *dst, int dstlen, bool one)
* If the file is a help file, remove the path completely.
*/
if (buf != NULL && buf->b_help) {
- STRCPY(dst, path_tail(src));
+ xstrlcpy((char *)dst, (char *)path_tail(src), dstlen);
return;
}
@@ -809,7 +826,7 @@ char_u * home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET
len += STRLEN(src);
}
char_u *dst = xmalloc(len);
- home_replace(buf, src, dst, (int)len, true);
+ home_replace(buf, src, dst, len, true);
return dst;
}
@@ -888,3 +905,17 @@ bool os_setenv_append_path(const char *fname)
}
return false;
}
+
+/// Returns true if the terminal can be assumed to silently ignore unknown
+/// control codes.
+bool os_term_is_nice(void)
+{
+#if defined(__APPLE__) || defined(WIN32)
+ return true;
+#else
+ const char *vte_version = os_getenv("VTE_VERSION");
+ return (vte_version && atoi(vte_version) >= 3900)
+ || NULL != os_getenv("KONSOLE_PROFILE_NAME")
+ || NULL != os_getenv("KONSOLE_DBUS_SESSION");
+#endif
+}
diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c
index 775f2bd449..4b7b53fc7f 100644
--- a/src/nvim/os/fileio.c
+++ b/src/nvim/os/fileio.c
@@ -113,27 +113,31 @@ FileDescriptor *file_open_new(int *const error, const char *const fname,
/// Close file and free its buffer
///
/// @param[in,out] fp File to close.
+/// @param[in] do_fsync If true, use fsync() to write changes to disk.
///
/// @return 0 or error code.
-int file_close(FileDescriptor *const fp) FUNC_ATTR_NONNULL_ALL
+int file_close(FileDescriptor *const fp, const bool do_fsync)
+ FUNC_ATTR_NONNULL_ALL
{
- const int error = file_fsync(fp);
- const int error2 = os_close(fp->fd);
+ const int flush_error = (do_fsync ? file_fsync(fp) : file_flush(fp));
+ const int close_error = os_close(fp->fd);
rbuffer_free(fp->rv);
- if (error2 != 0) {
- return error2;
+ if (close_error != 0) {
+ return close_error;
}
- return error;
+ return flush_error;
}
/// Close and free file obtained using file_open_new()
///
/// @param[in,out] fp File to close.
+/// @param[in] do_fsync If true, use fsync() to write changes to disk.
///
/// @return 0 or error code.
-int file_free(FileDescriptor *const fp) FUNC_ATTR_NONNULL_ALL
+int file_free(FileDescriptor *const fp, const bool do_fsync)
+ FUNC_ATTR_NONNULL_ALL
{
- const int ret = file_close(fp);
+ const int ret = file_close(fp, do_fsync);
xfree(fp);
return ret;
}
@@ -143,21 +147,36 @@ int file_free(FileDescriptor *const fp) FUNC_ATTR_NONNULL_ALL
/// @param[in,out] fp File to work with.
///
/// @return 0 or error code.
-int file_fsync(FileDescriptor *const fp)
+int file_flush(FileDescriptor *const fp)
FUNC_ATTR_NONNULL_ALL
{
if (!fp->wr) {
return 0;
}
file_rb_write_full_cb(fp->rv, fp);
- if (fp->_error != 0) {
- const int error = fp->_error;
- fp->_error = 0;
- return error;
+ const int error = fp->_error;
+ fp->_error = 0;
+ return error;
+}
+
+/// Flush file modifications to disk and run fsync()
+///
+/// @param[in,out] fp File to work with.
+///
+/// @return 0 or error code.
+int file_fsync(FileDescriptor *const fp)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (!fp->wr) {
+ return 0;
}
- const int error = os_fsync(fp->fd);
- if (error != UV_EINVAL && error != UV_EROFS) {
- return error;
+ const int flush_error = file_flush(fp);
+ if (flush_error != 0) {
+ return flush_error;
+ }
+ const int fsync_error = os_fsync(fp->fd);
+ if (fsync_error != UV_EINVAL && fsync_error != UV_EROFS) {
+ return fsync_error;
}
return 0;
}
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 2beeae7ec6..c33e1140e8 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -91,11 +91,11 @@ int os_dirname(char_u *buf, size_t len)
/// Check if the given path is a directory and not a symlink to a directory.
/// @return `true` if `name` is a directory and NOT a symlink to a directory.
/// `false` if `name` is not a directory or if an error occurred.
-bool os_isrealdir(const char_u *name)
+bool os_isrealdir(const char *name)
FUNC_ATTR_NONNULL_ALL
{
uv_fs_t request;
- if (uv_fs_lstat(&fs_loop, &request, (char *)name, NULL) != kLibuvSuccess) {
+ if (uv_fs_lstat(&fs_loop, &request, name, NULL) != kLibuvSuccess) {
return false;
}
if (S_ISLNK(request.statbuf.st_mode)) {
@@ -111,7 +111,7 @@ bool os_isrealdir(const char_u *name)
bool os_isdir(const char_u *name)
FUNC_ATTR_NONNULL_ALL
{
- int32_t mode = os_getperm(name);
+ int32_t mode = os_getperm((const char *)name);
if (mode < 0) {
return false;
}
@@ -236,7 +236,8 @@ bool os_can_exe(const char_u *name, char_u **abspath, bool use_path)
pathext);
#else
// Must have path separator, cannot execute files in the current directory.
- bool ok = gettail_dir(name) != name && is_executable((char *)name);
+ const bool ok = ((const char_u *)gettail_dir((const char *)name) != name
+ && is_executable((char *)name));
#endif
if (ok) {
if (abspath != NULL) {
@@ -254,7 +255,7 @@ bool os_can_exe(const char_u *name, char_u **abspath, bool use_path)
static bool is_executable(const char *name)
FUNC_ATTR_NONNULL_ALL
{
- int32_t mode = os_getperm((char_u *)name);
+ int32_t mode = os_getperm((const char *)name);
if (mode < 0) {
return false;
@@ -606,11 +607,11 @@ static int os_stat(const char *name, uv_stat_t *statbuf)
/// Get the file permissions for a given file.
///
/// @return libuv error code on error.
-int32_t os_getperm(const char_u *name)
+int32_t os_getperm(const char *name)
FUNC_ATTR_NONNULL_ALL
{
uv_stat_t statbuf;
- int stat_result = os_stat((char *)name, &statbuf);
+ int stat_result = os_stat(name, &statbuf);
if (stat_result == kLibuvSuccess) {
return (int32_t)statbuf.st_mode;
} else {
@@ -621,11 +622,11 @@ int32_t os_getperm(const char_u *name)
/// Set the permission of a file.
///
/// @return `OK` for success, `FAIL` for failure.
-int os_setperm(const char_u *name, int perm)
+int os_setperm(const char *const name, int perm)
FUNC_ATTR_NONNULL_ALL
{
int r;
- RUN_UV_FS_FUNC(r, uv_fs_chmod, (const char *)name, perm, NULL);
+ RUN_UV_FS_FUNC(r, uv_fs_chmod, name, perm, NULL);
return (r == kLibuvSuccess ? OK : FAIL);
}
@@ -979,13 +980,13 @@ bool os_fileid_equal_fileinfo(const FileID *file_id,
/// When "fname" is the name of a shortcut (*.lnk) resolve the file it points
/// to and return that name in allocated memory.
/// Otherwise NULL is returned.
-char *os_resolve_shortcut(char_u *fname)
+char *os_resolve_shortcut(const char *fname)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
{
HRESULT hr;
IPersistFile *ppf = NULL;
OLECHAR wsz[MAX_PATH];
char *rfname = NULL;
- int len;
IShellLinkW *pslw = NULL;
WIN32_FIND_DATAW ffdw;
@@ -994,7 +995,7 @@ char *os_resolve_shortcut(char_u *fname)
if (fname == NULL) {
return rfname;
}
- len = (int)STRLEN(fname);
+ const size_t len = strlen(fname);
if (len <= 4 || STRNICMP(fname + len - 4, ".lnk", 4) != 0) {
return rfname;
}
@@ -1006,9 +1007,9 @@ char *os_resolve_shortcut(char_u *fname)
&IID_IShellLinkW, (void **)&pslw);
if (hr == S_OK) {
WCHAR *p;
- int conversion_result = utf8_to_utf16((char *)fname, &p);
+ const int conversion_result = utf8_to_utf16(fname, &p);
if (conversion_result != 0) {
- EMSG2("utf8_to_utf16 failed: %s", uv_strerror(conversion_result));
+ EMSG2("utf8_to_utf16 failed: %d", conversion_result);
}
if (p != NULL) {
@@ -1036,7 +1037,7 @@ char *os_resolve_shortcut(char_u *fname)
ZeroMemory(wsz, MAX_PATH * sizeof(WCHAR));
hr = pslw->lpVtbl->GetPath(pslw, wsz, MAX_PATH, &ffdw, 0);
if (hr == S_OK && wsz[0] != NUL) {
- int conversion_result = utf16_to_utf8(wsz, &rfname);
+ const int conversion_result = utf16_to_utf8(wsz, &rfname);
if (conversion_result != 0) {
EMSG2("utf16_to_utf8 failed: %s", uv_strerror(conversion_result));
}
diff --git a/src/nvim/os/fs_defs.h b/src/nvim/os/fs_defs.h
index 0bd9c37750..2277d926b3 100644
--- a/src/nvim/os/fs_defs.h
+++ b/src/nvim/os/fs_defs.h
@@ -14,7 +14,7 @@ typedef struct {
uint64_t device_id; ///< @private The id of the device containing the file
} FileID;
-#define FILE_ID_EMPTY (FileID) {.inode = 0, .device_id = 0}
+#define FILE_ID_EMPTY (FileID) { .inode = 0, .device_id = 0 }
typedef struct {
uv_fs_t request; ///< @private The request to uv for the directory.
diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h
index 14c210c69c..f81785675e 100644
--- a/src/nvim/os/os_defs.h
+++ b/src/nvim/os/os_defs.h
@@ -27,11 +27,11 @@
// Use up to 5 Mbyte for a buffer.
#ifndef DFLT_MAXMEM
-# define DFLT_MAXMEM (5*1024)
+# define DFLT_MAXMEM (5 * 1024)
#endif
// use up to 10 Mbyte for Vim.
#ifndef DFLT_MAXMEMTOT
-# define DFLT_MAXMEMTOT (10*1024)
+# define DFLT_MAXMEMTOT (10 * 1024)
#endif
// Note: Some systems need both string.h and strings.h (Savage). However,
diff --git a/src/nvim/os/pty_process_win.h b/src/nvim/os/pty_process_win.h
index 20cc589925..8e2b37a1c1 100644
--- a/src/nvim/os/pty_process_win.h
+++ b/src/nvim/os/pty_process_win.h
@@ -12,8 +12,9 @@ typedef struct pty_process {
#define pty_process_spawn(job) libuv_process_spawn((LibuvProcess *)job)
#define pty_process_close(job) libuv_process_close((LibuvProcess *)job)
#define pty_process_close_master(job) libuv_process_close((LibuvProcess *)job)
-#define pty_process_resize(job, width, height)
-#define pty_process_teardown(loop)
+#define pty_process_resize(job, width, height) ( \
+ (void)job, (void)width, (void)height, 0)
+#define pty_process_teardown(loop) ((void)loop, 0)
static inline PtyProcess pty_process_init(Loop *loop, void *data)
{
diff --git a/src/nvim/os/unix_defs.h b/src/nvim/os/unix_defs.h
index c98aa88bfa..5c9daca476 100644
--- a/src/nvim/os/unix_defs.h
+++ b/src/nvim/os/unix_defs.h
@@ -8,7 +8,7 @@
// POSIX.1-2008 says that NAME_MAX should be in here
#include <limits.h>
-#define TEMP_DIR_NAMES {"$TMPDIR", "/tmp", ".", "~"}
+#define TEMP_DIR_NAMES { "$TMPDIR", "/tmp", ".", "~" }
#define TEMP_FILE_PATH_MAXLEN 256
#define HAVE_ACL (HAVE_POSIX_ACL || HAVE_SOLARIS_ACL)
diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h
index 8de896c490..7c980c3768 100644
--- a/src/nvim/os/win_defs.h
+++ b/src/nvim/os/win_defs.h
@@ -1,6 +1,10 @@
#ifndef NVIM_OS_WIN_DEFS_H
#define NVIM_OS_WIN_DEFS_H
+#ifndef WIN32
+# error Header must be included only when compiling for Windows.
+#endif
+
// winsock2.h must be first to avoid incompatibilities
// with winsock.h (included by windows.h)
#include <winsock2.h>
@@ -15,7 +19,7 @@
#define NAME_MAX _MAX_PATH
-#define TEMP_DIR_NAMES {"$TMP", "$TEMP", "$USERPROFILE", ""}
+#define TEMP_DIR_NAMES { "$TMPDIR", "$TMP", "$TEMP", "$USERPROFILE", "" }
#define TEMP_FILE_PATH_MAXLEN _MAX_PATH
#define FNAME_ILLEGAL "\"*?><|"
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index ed3410ffe5..acd86f06dc 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -110,14 +110,14 @@ void mch_copy_sec(char_u *from_file, char_u *to_file)
// Return a pointer to the ACL of file "fname" in allocated memory.
// Return NULL if the ACL is not available for whatever reason.
-vim_acl_T mch_get_acl(char_u *fname)
+vim_acl_T mch_get_acl(const char_u *fname)
{
vim_acl_T ret = NULL;
return ret;
}
// Set the ACL of file "fname" to "acl" (unless it's NULL).
-void mch_set_acl(char_u *fname, vim_acl_T aclent)
+void mch_set_acl(const char_u *fname, vim_acl_T aclent)
{
if (aclent == NULL)
return;
diff --git a/src/nvim/path.c b/src/nvim/path.c
index dfcafc85de..6bf42ed2fa 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -84,15 +84,15 @@ FileComparison path_full_compare(char_u *s1, char_u *s2, int checkname)
///
/// @return pointer just past the last path separator (empty string, if fname
/// ends in a slash), or empty string if fname is NULL.
-char_u *path_tail(char_u *fname)
+char_u *path_tail(const char_u *fname)
FUNC_ATTR_NONNULL_RET
{
if (fname == NULL) {
return (char_u *)"";
}
- char_u *tail = get_past_head(fname);
- char_u *p = tail;
+ const char_u *tail = get_past_head(fname);
+ const char_u *p = tail;
// Find last part of path.
while (*p != NUL) {
if (vim_ispathsep_nocolon(*p)) {
@@ -100,7 +100,7 @@ char_u *path_tail(char_u *fname)
}
mb_ptr_adv(p);
}
- return tail;
+ return (char_u *)tail;
}
/// Get pointer to tail of "fname", including path separators.
@@ -159,7 +159,7 @@ const char_u *invocation_path_tail(const char_u *invocation, size_t *len)
/// @param fname A file path. (Must be != NULL.)
/// @return Pointer to first found path separator + 1.
/// An empty string, if `fname` doesn't contain a path separator,
-char_u *path_next_component(char_u *fname)
+const char *path_next_component(const char *fname)
{
assert(fname != NULL);
while (*fname != NUL && !vim_ispathsep(*fname)) {
@@ -174,9 +174,9 @@ char_u *path_next_component(char_u *fname)
/// Get a pointer to one character past the head of a path name.
/// Unix: after "/"; Win: after "c:\"
/// If there is no head, path is returned.
-char_u *get_past_head(char_u *path)
+char_u *get_past_head(const char_u *path)
{
- char_u *retval = path;
+ const char_u *retval = path;
#ifdef WIN32
// May skip "c:"
@@ -189,7 +189,7 @@ char_u *get_past_head(char_u *path)
++retval;
}
- return retval;
+ return (char_u *)retval;
}
/*
@@ -282,48 +282,63 @@ bool dir_of_file_exists(char_u *fname)
return retval;
}
-/*
- * Versions of fnamecmp() and fnamencmp() that handle '/' and '\' equally
- * and deal with 'fileignorecase'.
- */
-int vim_fnamecmp(char_u *x, char_u *y)
+/// Compare two file names
+///
+/// Handles '/' and '\\' correctly and deals with &fileignorecase option.
+///
+/// @param[in] fname1 First file name.
+/// @param[in] fname2 Second file name.
+///
+/// @return 0 if they are equal, non-zero otherwise.
+int path_fnamecmp(const char *fname1, const char *fname2)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
#ifdef BACKSLASH_IN_FILENAME
- return vim_fnamencmp(x, y, MAXPATHL);
+ const size_t len1 = strlen(fname1);
+ const size_t len2 = strlen(fname2);
+ return path_fnamencmp(fname1, fname2, MAX(len1, len2));
#else
- if (p_fic)
- return mb_stricmp(x, y);
- return STRCMP(x, y);
+ return mb_strcmp_ic((bool)p_fic, fname1, fname2);
#endif
}
-int vim_fnamencmp(char_u *x, char_u *y, size_t len)
+/// Compare two file names
+///
+/// Handles '/' and '\\' correctly and deals with &fileignorecase option.
+///
+/// @param[in] fname1 First file name.
+/// @param[in] fname2 Second file name.
+/// @param[in] len Compare at most len bytes.
+///
+/// @return 0 if they are equal, non-zero otherwise.
+int path_fnamencmp(const char *const fname1, const char *const fname2,
+ size_t len)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
#ifdef BACKSLASH_IN_FILENAME
- char_u *px = x;
- char_u *py = y;
- int cx = NUL;
- int cy = NUL;
+ int c1 = NUL;
+ int c2 = NUL;
+ const char *p1 = fname1;
+ const char *p2 = fname2;
while (len > 0) {
- cx = PTR2CHAR(px);
- cy = PTR2CHAR(py);
- if (cx == NUL || cy == NUL
- || ((p_fic ? vim_tolower(cx) != vim_tolower(cy) : cx != cy)
- && !(cx == '/' && cy == '\\')
- && !(cx == '\\' && cy == '/')))
+ c1 = PTR2CHAR((const char_u *)p1);
+ c2 = PTR2CHAR((const char_u *)p2);
+ if ((c1 == NUL || c2 == NUL
+ || (!((c1 == '/' || c1 == '\\') && (c2 == '\\' || c2 == '/'))))
+ && (p_fic ? (c1 != c2 && CH_FOLD(c1) != CH_FOLD(c2)) : c1 != c2)) {
break;
- len -= MB_PTR2LEN(px);
- px += MB_PTR2LEN(px);
- py += MB_PTR2LEN(py);
+ }
+ len -= MB_PTR2LEN((const char_u *)p1);
+ p1 += MB_PTR2LEN((const char_u *)p1);
+ p2 += MB_PTR2LEN((const char_u *)p2);
}
- if (len == 0)
- return 0;
- return cx - cy;
+ return c1 - c2;
#else
- if (p_fic)
- return mb_strnicmp(x, y, len);
- return STRNCMP(x, y, len);
+ if (p_fic) {
+ return mb_strnicmp((const char_u *)fname1, (const char_u *)fname2, len);
+ }
+ return strncmp(fname1, fname2, len);
#endif
}
@@ -416,7 +431,7 @@ bool add_pathsep(char *p)
///
/// @return [allocated] Copy of absolute path to `fname` or NULL when
/// `fname` is NULL.
-char *FullName_save(char *fname, bool force)
+char *FullName_save(const char *fname, bool force)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC
{
if (fname == NULL) {
@@ -804,7 +819,7 @@ static void expand_path_option(char_u *curdir, garray_T *gap)
}
STRMOVE(buf + len + 1, buf);
STRCPY(buf, curdir);
- buf[len] = PATHSEP;
+ buf[len] = (char_u)PATHSEP;
simplify_filename(buf);
}
@@ -891,9 +906,9 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern)
in_curdir = xcalloc((size_t)gap->ga_len, sizeof(char_u *));
for (int i = 0; i < gap->ga_len && !got_int; i++) {
- char_u *path = fnames[i];
+ char_u *path = fnames[i];
int is_in_curdir;
- char_u *dir_end = gettail_dir(path);
+ char_u *dir_end = (char_u *)gettail_dir((const char *)path);
char_u *pathsep_p;
char_u *path_cutoff;
@@ -995,18 +1010,22 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern)
ga_remove_duplicate_strings(gap);
}
-/// Return the end of the directory name, on the first path
-/// separator:
-/// "/path/file", "/path/dir/", "/path//dir", "/file"
-/// ^ ^ ^ ^
-char_u *gettail_dir(const char_u *fname)
+/// Find end of the directory name
+///
+/// @param[in] fname File name to process.
+///
+/// @return end of the directory name, on the first path separator:
+///
+/// "/path/file", "/path/dir/", "/path//dir", "/file"
+/// ^ ^ ^ ^
+const char *gettail_dir(const char *const fname)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- const char_u *dir_end = fname;
- const char_u *next_dir_end = fname;
+ const char *dir_end = fname;
+ const char *next_dir_end = fname;
bool look_for_sep = true;
- const char_u *p;
- for (p = fname; *p != NUL; ) {
+ for (const char *p = fname; *p != NUL; ) {
if (vim_ispathsep(*p)) {
if (look_for_sep) {
next_dir_end = p;
@@ -1019,7 +1038,7 @@ char_u *gettail_dir(const char_u *fname)
}
mb_ptr_adv(p);
}
- return (char_u *)dir_end;
+ return dir_end;
}
@@ -1314,12 +1333,12 @@ static int expand_backtick(
/// When the path looks like a URL leave it unmodified.
void slash_adjust(char_u *p)
{
- if (path_with_url(p)) {
+ if (path_with_url((const char *)p)) {
return;
}
while (*p) {
- if (*p == psepcN) {
- *p = psepc;
+ if (*p == (char_u)psepcN) {
+ *p = (char_u)psepc;
}
mb_ptr_adv(p);
}
@@ -1538,8 +1557,8 @@ void simplify_filename(char_u *filename)
p = tail; /* skip to char after ".." or "../" */
}
} else {
- ++components; /* simple path component */
- p = path_next_component(p);
+ components++; // Simple path component.
+ p = (char_u *)path_next_component((const char *)p);
}
} while (*p != NUL);
}
diff --git a/src/nvim/po/CMakeLists.txt b/src/nvim/po/CMakeLists.txt
index d2b62f89a0..121f22129a 100644
--- a/src/nvim/po/CMakeLists.txt
+++ b/src/nvim/po/CMakeLists.txt
@@ -32,10 +32,10 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG)
zh_CN.UTF-8
zh_TW.UTF-8)
- set(NEOVIM_RELATIVE_SOURCES)
- foreach(SRC ${NEOVIM_SOURCES} ${NEOVIM_HEADERS})
+ set(NVIM_RELATIVE_SOURCES)
+ foreach(SRC ${NVIM_SOURCES} ${NVIM_HEADERS})
file(RELATIVE_PATH RELATIVE_SRC ${CMAKE_CURRENT_SOURCE_DIR} ${SRC})
- list(APPEND NEOVIM_RELATIVE_SOURCES ${RELATIVE_SRC})
+ list(APPEND NVIM_RELATIVE_SOURCES ${RELATIVE_SRC})
endforeach()
set(NVIM_POT ${CMAKE_CURRENT_BINARY_DIR}/nvim.pot)
@@ -46,9 +46,9 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG)
-DXGETTEXT_PRG=${XGETTEXT_PRG}
-DPOT_FILE=${NVIM_POT}
-DSEARCH_DIR=${CMAKE_CURRENT_SOURCE_DIR}
- "\"-DSOURCES=${NEOVIM_RELATIVE_SOURCES}\""
+ "\"-DSOURCES=${NVIM_RELATIVE_SOURCES}\""
-P ${PROJECT_SOURCE_DIR}/cmake/RunXgettext.cmake
- DEPENDS ${NEOVIM_SOURCES})
+ DEPENDS ${NVIM_SOURCES})
add_custom_target(potfile DEPENDS ${NVIM_POT})
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index ea00afbd86..6346951c05 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -610,13 +610,10 @@ static int pum_set_selected(int n, int repeat)
if (res == OK) {
// Edit a new, empty buffer. Set options for a "wipeout"
// buffer.
- set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
- set_option_value((char_u *)"bt", 0L,
- (char_u *)"nofile", OPT_LOCAL);
- set_option_value((char_u *)"bh", 0L,
- (char_u *)"wipe", OPT_LOCAL);
- set_option_value((char_u *)"diff", 0L,
- NULL, OPT_LOCAL);
+ set_option_value("swf", 0L, NULL, OPT_LOCAL);
+ set_option_value("bt", 0L, "nofile", OPT_LOCAL);
+ set_option_value("bh", 0L, "wipe", OPT_LOCAL);
+ set_option_value("diff", 0L, NULL, OPT_LOCAL);
}
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 8d8c20c1d0..4fa5c85abd 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -1236,7 +1236,7 @@ static int qf_add_entry(qf_info_T *qi, char_u *dir, char_u *fname, int bufnum,
qfp->qf_nr = nr;
if (type != 1 && !vim_isprintc(type)) /* only printable chars allowed */
type = 0;
- qfp->qf_type = type;
+ qfp->qf_type = (char_u)type;
qfp->qf_valid = valid;
lastp = &qi->qf_lists[qi->qf_curlist].qf_last;
@@ -2581,15 +2581,13 @@ void ex_copen(exarg_T *eap)
else {
/* Create a new quickfix buffer */
(void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin);
- /* switch off 'swapfile' */
- set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
- set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix",
- OPT_LOCAL);
- set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL);
+ // Switch off 'swapfile'.
+ set_option_value("swf", 0L, NULL, OPT_LOCAL);
+ set_option_value("bt", 0L, "quickfix", OPT_LOCAL);
+ set_option_value("bh", 0L, "wipe", OPT_LOCAL);
RESET_BINDING(curwin);
- curwin->w_p_diff = FALSE;
- set_option_value((char_u *)"fdm", 0L, (char_u *)"manual",
- OPT_LOCAL);
+ curwin->w_p_diff = false;
+ set_option_value("fdm", 0L, "manual", OPT_LOCAL);
}
/* Only set the height when still in the same tab page and there is no
@@ -2901,14 +2899,14 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
}
}
- /* correct cursor position */
- check_lnums(TRUE);
+ // Correct cursor position.
+ check_lnums(true);
if (old_last == NULL) {
// Set the 'filetype' to "qf" each time after filling the buffer. This
// resembles reading a file into a buffer, it's more logical when using
// autocommands.
- set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL);
+ set_option_value("ft", 0L, "qf", OPT_LOCAL);
curbuf->b_p_ma = false;
keep_filetype = true; // don't detect 'filetype'
@@ -3974,7 +3972,6 @@ static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start)
int get_errorlist(win_T *wp, int qf_idx, list_T *list)
{
qf_info_T *qi = &ql_info;
- dict_T *dict;
char_u buf[2];
qfline_T *qfp;
int i;
@@ -4002,23 +3999,34 @@ int get_errorlist(win_T *wp, int qf_idx, list_T *list)
if (bufnum != 0 && (buflist_findnr(bufnum) == NULL))
bufnum = 0;
- dict = dict_alloc();
- list_append_dict(list, dict);
+ dict_T *const dict = tv_dict_alloc();
+ tv_list_append_dict(list, dict);
buf[0] = qfp->qf_type;
buf[1] = NUL;
- if ( dict_add_nr_str(dict, "bufnr", (long)bufnum, NULL) == FAIL
- || dict_add_nr_str(dict, "lnum", (long)qfp->qf_lnum, NULL) == FAIL
- || dict_add_nr_str(dict, "col", (long)qfp->qf_col, NULL) == FAIL
- || dict_add_nr_str(dict, "vcol", (long)qfp->qf_viscol, NULL) == FAIL
- || dict_add_nr_str(dict, "nr", (long)qfp->qf_nr, NULL) == FAIL
- || dict_add_nr_str(dict, "pattern", 0L,
- qfp->qf_pattern == NULL ? (char_u *)"" : qfp->qf_pattern) == FAIL
- || dict_add_nr_str(dict, "text", 0L,
- qfp->qf_text == NULL ? (char_u *)"" : qfp->qf_text) == FAIL
- || dict_add_nr_str(dict, "type", 0L, buf) == FAIL
- || dict_add_nr_str(dict, "valid", (long)qfp->qf_valid, NULL) == FAIL)
- return FAIL;
+ if (tv_dict_add_nr(dict, S_LEN("bufnr"), (varnumber_T)bufnum) == FAIL
+ || (tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)qfp->qf_lnum)
+ == FAIL)
+ || (tv_dict_add_nr(dict, S_LEN("col"), (varnumber_T)qfp->qf_col)
+ == FAIL)
+ || (tv_dict_add_nr(dict, S_LEN("vcol"), (varnumber_T)qfp->qf_viscol)
+ == FAIL)
+ || (tv_dict_add_nr(dict, S_LEN("nr"), (varnumber_T)qfp->qf_nr) == FAIL)
+ || tv_dict_add_str(dict, S_LEN("pattern"),
+ (qfp->qf_pattern == NULL
+ ? ""
+ : (const char *)qfp->qf_pattern)) == FAIL
+ || tv_dict_add_str(dict, S_LEN("text"),
+ (qfp->qf_text == NULL
+ ? ""
+ : (const char *)qfp->qf_text)) == FAIL
+ || tv_dict_add_str(dict, S_LEN("type"), (const char *)buf) == FAIL
+ || (tv_dict_add_nr(dict, S_LEN("valid"), (varnumber_T)qfp->qf_valid)
+ == FAIL)) {
+ // tv_dict_add* fail only if key already exist, but this is a newly
+ // allocated dictionary which is thus guaranteed to have no existing keys.
+ assert(false);
+ }
qfp = qfp->qf_next;
if (qfp == NULL) {
@@ -4057,7 +4065,7 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
int flags = QF_GETLIST_NONE;
int qf_idx = qi->qf_curlist; // default is the current list
- if ((di = dict_find(what, (char_u *)"nr", -1)) != NULL) {
+ if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) {
// Use the specified quickfix/location list
if (di->di_tv.v_type == VAR_NUMBER) {
qf_idx = di->di_tv.vval.v_number - 1;
@@ -4070,15 +4078,15 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
}
}
- if (dict_find(what, (char_u *)"all", -1) != NULL) {
+ if (tv_dict_find(what, S_LEN("all")) != NULL) {
flags |= QF_GETLIST_ALL;
}
- if (dict_find(what, (char_u *)"title", -1) != NULL) {
+ if (tv_dict_find(what, S_LEN("title")) != NULL) {
flags |= QF_GETLIST_TITLE;
}
- if (dict_find(what, (char_u *)"winid", -1) != NULL) {
+ if (tv_dict_find(what, S_LEN("winid")) != NULL) {
flags |= QF_GETLIST_WINID;
}
@@ -4087,15 +4095,15 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
if (t == NULL) {
t = (char_u *)"";
}
- status = dict_add_nr_str(retdict, "title", 0L, t);
+ status = tv_dict_add_str(retdict, S_LEN("title"), (const char *)t);
}
if ((status == OK) && (flags & QF_GETLIST_NR)) {
- status = dict_add_nr_str(retdict, "nr", qf_idx + 1, NULL);
+ status = tv_dict_add_nr(retdict, S_LEN("nr"), qf_idx + 1);
}
if ((status == OK) && (flags & QF_GETLIST_WINID)) {
win_T *win = qf_find_win(qi);
if (win != NULL) {
- status = dict_add_nr_str(retdict, "winid", win->handle, NULL);
+ status = tv_dict_add_nr(retdict, S_LEN("winid"), win->handle);
}
}
@@ -4132,17 +4140,18 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
if (d == NULL)
continue;
- char_u *filename = get_dict_string(d, "filename", true);
- int bufnum = (int)get_dict_number(d, "bufnr");
- long lnum = get_dict_number(d, "lnum");
- int col = (int)get_dict_number(d, "col");
- char_u vcol = (char_u)get_dict_number(d, "vcol");
- int nr = (int)get_dict_number(d, "nr");
- char_u *type = get_dict_string(d, "type", true);
- char_u *pattern = get_dict_string(d, "pattern", true);
- char_u *text = get_dict_string(d, "text", true);
+ char *const filename = tv_dict_get_string(d, "filename", true);
+ int bufnum = (int)tv_dict_get_number(d, "bufnr");
+ long lnum = tv_dict_get_number(d, "lnum");
+ int col = (int)tv_dict_get_number(d, "col");
+ char_u vcol = (char_u)tv_dict_get_number(d, "vcol");
+ int nr = (int)tv_dict_get_number(d, "nr");
+ const char *type_str = tv_dict_get_string(d, "type", false);
+ const char_u type = (char_u)(uint8_t)(type_str == NULL ? NUL : *type_str);
+ char *const pattern = tv_dict_get_string(d, "pattern", true);
+ char *text = tv_dict_get_string(d, "text", true);
if (text == NULL) {
- text = vim_strsave((char_u *)"");
+ text = xcalloc(1, 1);
}
bool valid = true;
if ((filename == NULL && bufnum == 0) || (lnum == 0 && pattern == NULL)) {
@@ -4162,21 +4171,20 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
int status = qf_add_entry(qi,
NULL, // dir
- filename,
+ (char_u *)filename,
bufnum,
- text,
+ (char_u *)text,
lnum,
col,
vcol, // vis_col
- pattern, // search pattern
+ (char_u *)pattern, // search pattern
nr,
- (char_u)(type == NULL ? NUL : *type),
+ type,
valid);
xfree(filename);
xfree(pattern);
xfree(text);
- xfree(type);
if (status == FAIL) {
retval = FAIL;
@@ -4213,7 +4221,7 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action)
newlist = true;
}
int qf_idx = qi->qf_curlist; // default is the current list
- if ((di = dict_find(what, (char_u *)"nr", -1)) != NULL) {
+ if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) {
// Use the specified quickfix/location list
if (di->di_tv.v_type == VAR_NUMBER) {
qf_idx = di->di_tv.vval.v_number - 1;
@@ -4231,10 +4239,11 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action)
qf_idx = qi->qf_curlist;
}
- if ((di = dict_find(what, (char_u *)"title", -1)) != NULL) {
+ if ((di = tv_dict_find(what, S_LEN("title"))) != NULL) {
if (di->di_tv.v_type == VAR_STRING) {
xfree(qi->qf_lists[qf_idx].qf_title);
- qi->qf_lists[qf_idx].qf_title = get_dict_string(what, "title", true);
+ qi->qf_lists[qf_idx].qf_title = (char_u *)tv_dict_get_string(
+ what, "title", true);
if (qf_idx == qi->qf_curlist) {
qf_update_win_titlevar(qi);
}
@@ -4363,7 +4372,6 @@ void ex_cbuffer(exarg_T *eap)
*/
void ex_cexpr(exarg_T *eap)
{
- typval_T *tv;
qf_info_T *qi = &ql_info;
const char *au_name = NULL;
@@ -4403,11 +4411,11 @@ void ex_cexpr(exarg_T *eap)
/* Evaluate the expression. When the result is a string or a list we can
* use it to fill the errorlist. */
- tv = eval_expr(eap->arg, NULL);
- if (tv != NULL) {
- if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL)
- || (tv->v_type == VAR_LIST && tv->vval.v_list != NULL)) {
- if (qf_init_ext(qi, NULL, NULL, tv, p_efm,
+ typval_T tv;
+ if (eval0(eap->arg, &tv, NULL, true) != FAIL) {
+ if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL)
+ || (tv.v_type == VAR_LIST && tv.vval.v_list != NULL)) {
+ if (qf_init_ext(qi, NULL, NULL, &tv, p_efm,
(eap->cmdidx != CMD_caddexpr
&& eap->cmdidx != CMD_laddexpr),
(linenr_T)0, (linenr_T)0, *eap->cmdlinep) > 0) {
@@ -4422,7 +4430,7 @@ void ex_cexpr(exarg_T *eap)
} else {
EMSG(_("E777: String or List expected"));
}
- free_tv(tv);
+ tv_clear(&tv);
}
}
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 1cd334abcd..9baa53d2a2 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -2221,10 +2221,11 @@ collection:
if (*regparse == '[')
endc = get_coll_element(&regparse);
if (endc == 0) {
- if (has_mbyte)
- endc = mb_ptr2char_adv(&regparse);
- else
+ if (has_mbyte) {
+ endc = mb_ptr2char_adv((const char_u **)&regparse);
+ } else {
endc = *regparse++;
+ }
}
/* Handle \o40, \x20 and \u20AC style sequences */
@@ -3650,9 +3651,11 @@ static long regtry(bt_regprog_T *prog, colnr_T col)
*/
static int reg_prev_class(void)
{
- if (reginput > regline)
- return mb_get_class_buf(reginput - 1
- - (*mb_head_off)(regline, reginput - 1), reg_buf);
+ if (reginput > regline) {
+ return mb_get_class_tab(reginput - 1 - (*mb_head_off)(regline,
+ reginput - 1),
+ reg_buf->b_chartab);
+ }
return -1;
}
@@ -3918,12 +3921,13 @@ regmatch (
else if (has_mbyte) {
int this_class;
- /* Get class of current and previous char (if it exists). */
- this_class = mb_get_class_buf(reginput, reg_buf);
- if (this_class <= 1)
- status = RA_NOMATCH; /* not on a word at all */
- else if (reg_prev_class() == this_class)
- status = RA_NOMATCH; /* previous char is in same word */
+ // Get class of current and previous char (if it exists).
+ this_class = mb_get_class_tab(reginput, reg_buf->b_chartab);
+ if (this_class <= 1) {
+ status = RA_NOMATCH; // Not on a word at all.
+ } else if (reg_prev_class() == this_class) {
+ status = RA_NOMATCH; // Previous char is in same word.
+ }
} else {
if (!vim_iswordc_buf(c, reg_buf) || (reginput > regline
&& vim_iswordc_buf(reginput[-1
@@ -3938,8 +3942,8 @@ regmatch (
else if (has_mbyte) {
int this_class, prev_class;
- /* Get class of current and previous char (if it exists). */
- this_class = mb_get_class_buf(reginput, reg_buf);
+ // Get class of current and previous char (if it exists).
+ this_class = mb_get_class_tab(reginput, reg_buf->b_chartab);
prev_class = reg_prev_class();
if (this_class == prev_class
|| prev_class == 0 || prev_class == 1)
@@ -6268,8 +6272,8 @@ static int cstrncmp(char_u *s1, char_u *s2, int *n)
str2 = s2;
c1 = c2 = 0;
while ((int)(str1 - s1) < *n) {
- c1 = mb_ptr2char_adv(&str1);
- c2 = mb_ptr2char_adv(&str2);
+ c1 = mb_ptr2char_adv((const char_u **)&str1);
+ c2 = mb_ptr2char_adv((const char_u **)&str2);
/* decompose the character if necessary, into 'base' characters
* because I don't care about Arabic, I will hard-code the Hebrew
@@ -6583,7 +6587,6 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest,
if (expr != NULL) {
typval_T argv[2];
int dummy;
- char_u buf[NUMBUFLEN];
typval_T rettv;
staticList10_T matchList;
@@ -6613,11 +6616,12 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest,
clear_submatch_list(&matchList);
}
}
- eval_result = get_tv_string_buf_chk(&rettv, buf);
+ char buf[NUMBUFLEN];
+ eval_result = (char_u *)tv_get_string_buf_chk(&rettv, buf);
if (eval_result != NULL) {
eval_result = vim_strsave(eval_result);
}
- clear_tv(&rettv);
+ tv_clear(&rettv);
} else {
eval_result = eval_to_string(source + 2, NULL, true);
}
@@ -6976,7 +6980,7 @@ list_T *reg_submatch_list(int no)
linenr_T slnum;
linenr_T elnum;
list_T *list;
- char_u *s;
+ const char *s;
if (submatch_match == NULL) {
slnum = submatch_mmatch->startpos[no].lnum;
@@ -6988,27 +6992,27 @@ list_T *reg_submatch_list(int no)
colnr_T scol = submatch_mmatch->startpos[no].col;
colnr_T ecol = submatch_mmatch->endpos[no].col;
- list = list_alloc();
+ list = tv_list_alloc();
- s = reg_getline_submatch(slnum) + scol;
+ s = (const char *)reg_getline_submatch(slnum) + scol;
if (slnum == elnum) {
- list_append_string(list, s, ecol - scol);
+ tv_list_append_string(list, s, ecol - scol);
} else {
- list_append_string(list, s, -1);
+ tv_list_append_string(list, s, -1);
for (int i = 1; i < elnum - slnum; i++) {
- s = reg_getline_submatch(slnum + i);
- list_append_string(list, s, -1);
+ s = (const char *)reg_getline_submatch(slnum + i);
+ tv_list_append_string(list, s, -1);
}
- s = reg_getline_submatch(elnum);
- list_append_string(list, s, ecol);
+ s = (const char *)reg_getline_submatch(elnum);
+ tv_list_append_string(list, s, ecol);
}
} else {
- s = submatch_match->startp[no];
+ s = (const char *)submatch_match->startp[no];
if (s == NULL || submatch_match->endp[no] == NULL) {
return NULL;
}
- list = list_alloc();
- list_append_string(list, s, (int)(submatch_match->endp[no] - s));
+ list = tv_list_alloc();
+ tv_list_append_string(list, s, (const char *)submatch_match->endp[no] - s);
}
return list;
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 3f4e12af4a..5b49ab38f0 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -5410,7 +5410,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
int this_class;
// Get class of current and previous char (if it exists).
- this_class = mb_get_class_buf(reginput, reg_buf);
+ this_class = mb_get_class_tab(reginput, reg_buf->b_chartab);
if (this_class <= 1) {
result = false;
} else if (reg_prev_class() == this_class) {
@@ -5435,7 +5435,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
int this_class, prev_class;
// Get class of current and previous char (if it exists).
- this_class = mb_get_class_buf(reginput, reg_buf);
+ this_class = mb_get_class_tab(reginput, reg_buf->b_chartab);
prev_class = reg_prev_class();
if (this_class == prev_class
|| prev_class == 0 || prev_class == 1) {
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 505d04ed56..d9a21aa81f 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -3141,7 +3141,7 @@ win_line (
p_extra = extra;
c = *p_extra;
- mb_c = mb_ptr2char_adv(&p_extra);
+ mb_c = mb_ptr2char_adv((const char_u **)&p_extra);
mb_utf8 = (c >= 0x80);
n_extra = (int)STRLEN(p_extra);
c_extra = NUL;
@@ -3409,7 +3409,7 @@ win_line (
|| (c == ' ' && lcs_space && ptr - line <= trailcol))) {
c = (c == ' ') ? lcs_space : lcs_nbsp;
n_attr = 1;
- extra_attr = hl_attr(HLF_8);
+ extra_attr = hl_attr(HLF_0);
saved_attr2 = char_attr; // save current attr
mb_c = c;
if (enc_utf8 && (*mb_char2len)(c) > 1) {
@@ -3424,7 +3424,7 @@ win_line (
if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ') {
c = lcs_trail;
n_attr = 1;
- extra_attr = hl_attr(HLF_8);
+ extra_attr = hl_attr(HLF_0);
saved_attr2 = char_attr; // save current attr
mb_c = c;
if (enc_utf8 && (*mb_char2len)(c) > 1) {
@@ -3525,8 +3525,8 @@ win_line (
c_extra = lcs_tab2;
}
n_attr = tab_len + 1;
- extra_attr = hl_attr(HLF_8);
- saved_attr2 = char_attr; /* save current attr */
+ extra_attr = hl_attr(HLF_0);
+ saved_attr2 = char_attr; // save current attr
mb_c = c;
if (enc_utf8 && (*mb_char2len)(c) > 1) {
mb_utf8 = TRUE;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 8c56eda7cf..c5c92b41c5 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -282,7 +282,7 @@ void restore_search_patterns(void)
static inline void free_spat(struct spat *const spat)
{
xfree(spat->pat);
- dict_unref(spat->additional_data);
+ tv_dict_unref(spat->additional_data);
}
#if defined(EXITFREE)
@@ -356,9 +356,10 @@ int pat_has_uppercase(char_u *pat)
return FALSE;
}
-char_u *last_csearch(void)
+const char *last_csearch(void)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- return lastc_bytes;
+ return (const char *)lastc_bytes;
}
int last_csearch_forward(void)
@@ -1290,10 +1291,11 @@ int search_for_exact_line(buf_T *buf, pos_T *pos, int dir, char_u *pat)
* ignored because we are interested in the next line -- Acevedo */
if ((compl_cont_status & CONT_ADDING)
&& !(compl_cont_status & CONT_SOL)) {
- if ((p_ic ? mb_stricmp(p, pat) : STRCMP(p, pat)) == 0)
+ if (mb_strcmp_ic((bool)p_ic, (const char *)p, (const char *)pat) == 0) {
return OK;
- } else if (*p != NUL) { /* ignore empty lines */
- /* expanding lines or words */
+ }
+ } else if (*p != NUL) { // Ignore empty lines.
+ // Expanding lines or words.
assert(compl_length >= 0);
if ((p_ic ? mb_strnicmp(p, pat, (size_t)compl_length)
: STRNCMP(p, pat, compl_length)) == 0)
diff --git a/src/nvim/sha256.c b/src/nvim/sha256.c
index 7670b64468..c72dafd08e 100644
--- a/src/nvim/sha256.c
+++ b/src/nvim/sha256.c
@@ -259,11 +259,11 @@ void sha256_finish(context_sha256_T *ctx, char_u digest[SHA256_SUM_SIZE])
///
/// @returns hex digest of "buf[buf_len]" in a static array.
/// if "salt" is not NULL also do "salt[salt_len]".
-char_u *sha256_bytes(const char_u *restrict buf, size_t buf_len,
- const char_u *restrict salt, size_t salt_len)
+const char *sha256_bytes(const uint8_t *restrict buf, size_t buf_len,
+ const uint8_t *restrict salt, size_t salt_len)
{
char_u sha256sum[SHA256_SUM_SIZE];
- static char_u hexit[SHA256_BUFFER_SIZE + 1]; // buf size + NULL
+ static char hexit[SHA256_BUFFER_SIZE + 1]; // buf size + NULL
context_sha256_T ctx;
sha256_self_test();
@@ -277,7 +277,7 @@ char_u *sha256_bytes(const char_u *restrict buf, size_t buf_len,
sha256_finish(&ctx, sha256sum);
for (size_t j = 0; j < SHA256_SUM_SIZE; j++) {
- snprintf((char *) hexit + j * SHA_STEP, SHA_STEP+1, "%02x", sha256sum[j]);
+ snprintf(hexit + j * SHA_STEP, SHA_STEP + 1, "%02x", sha256sum[j]);
}
hexit[sizeof(hexit) - 1] = '\0';
return hexit;
@@ -308,7 +308,7 @@ bool sha256_self_test(void)
context_sha256_T ctx;
char_u buf[1000];
char_u sha256sum[SHA256_SUM_SIZE];
- char_u *hexit;
+ const char *hexit;
static bool sha256_self_tested = false;
static bool failures = false;
@@ -320,8 +320,8 @@ bool sha256_self_test(void)
for (size_t i = 0; i < 3; i++) {
if (i < 2) {
- hexit = sha256_bytes((char_u *) sha_self_test_msg[i],
- STRLEN(sha_self_test_msg[i]),
+ hexit = sha256_bytes((uint8_t *)sha_self_test_msg[i],
+ strlen(sha_self_test_msg[i]),
NULL, 0);
STRCPY(output, hexit);
} else {
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 197b029591..c7b95958e0 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -30,7 +30,7 @@
#include "nvim/ex_getln.h"
#include "nvim/search.h"
#include "nvim/regexp.h"
-#include "nvim/eval_defs.h"
+#include "nvim/eval/typval.h"
#include "nvim/version.h"
#include "nvim/path.h"
#include "nvim/fileio.h"
@@ -82,8 +82,6 @@ KHASH_SET_INIT_STR(strset)
(buflist_new((char_u *)ffname, (char_u *)sfname, __VA_ARGS__))
#define convert_setup(vcp, from, to) \
(convert_setup(vcp, (char_u *)from, (char_u *)to))
-#define os_getperm(f) \
- (os_getperm((char_u *) f))
#define os_isdir(f) (os_isdir((char_u *) f))
#define regtilde(s, m) ((char *) regtilde((char_u *) s, m))
#define path_tail_with_sep(f) ((char *) path_tail_with_sep((char_u *)f))
@@ -813,7 +811,7 @@ static int open_shada_file_for_reading(const char *const fname,
/// Wrapper for closing file descriptors
static void close_file(void *cookie)
{
- const int error = file_free(cookie);
+ const int error = file_free(cookie, true);
if (error != 0) {
emsgf(_(SERR "System error while closing ShaDa file: %s"),
os_strerror(error));
@@ -1223,7 +1221,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
khash_t(fnamebufs) fname_bufs = KHASH_EMPTY_TABLE(fnamebufs);
khash_t(strset) oldfiles_set = KHASH_EMPTY_TABLE(strset);
if (get_old_files && (oldfiles_list == NULL || force)) {
- oldfiles_list = list_alloc();
+ oldfiles_list = tv_list_alloc();
set_vim_var_list(VV_OLDFILES, oldfiles_list);
}
ShaDaReadResult srni_ret;
@@ -1435,8 +1433,8 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
fname = xstrdup(fname);
}
int kh_ret;
- (void) kh_put(strset, &oldfiles_set, fname, &kh_ret);
- list_append_allocated_string(oldfiles_list, fname);
+ (void)kh_put(strset, &oldfiles_set, fname, &kh_ret);
+ tv_list_append_allocated_string(oldfiles_list, fname);
if (!want_marks) {
// Avoid free because this string was already used.
cur_entry.data.filemark.fname = NULL;
@@ -1573,7 +1571,9 @@ static char *shada_filename(const char *file)
do { \
const String s_ = (s); \
msgpack_pack_str(spacker, s_.size); \
- msgpack_pack_str_body(spacker, s_.data, s_.size); \
+ if (s_.size) { \
+ msgpack_pack_str_body(spacker, s_.data, s_.size); \
+ } \
} while (0)
#define PACK_BIN(s) \
do { \
@@ -1621,10 +1621,10 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
for (const hashitem_T *hi= d->dv_hashtab.ht_array; todo; hi++) { \
if (!HASHITEM_EMPTY(hi)) { \
todo--; \
- dictitem_T *const di = HI2DI(hi); \
- const size_t key_len = strlen((const char *) hi->hi_key); \
+ dictitem_T *const di = TV_DICT_HI2DI(hi); \
+ const size_t key_len = strlen((const char *)hi->hi_key); \
msgpack_pack_str(spacker, key_len); \
- msgpack_pack_str_body(spacker, (const char *) hi->hi_key, key_len); \
+ msgpack_pack_str_body(spacker, (const char *)hi->hi_key, key_len); \
if (encode_vim_to_msgpack(spacker, &di->di_tv, \
_("additional data of ShaDa " what)) \
== FAIL) { \
@@ -1965,7 +1965,7 @@ static ShaDaWriteResult shada_pack_encoded_entry(msgpack_packer *const packer,
typval_T tgttv;
var_item_copy(sd_conv, &entry.data.data.global_var.value, &tgttv,
true, 0);
- clear_tv(&entry.data.data.global_var.value);
+ tv_clear(&entry.data.data.global_var.value);
entry.data.data.global_var.value = tgttv;
}
ret = shada_pack_entry(packer, entry.data, max_kbyte);
@@ -2559,7 +2559,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
if (sd_writer->sd_conv.vc_type != CONV_NONE) {
var_item_copy(&sd_writer->sd_conv, &vartv, &tgttv, true, 0);
} else {
- copy_tv(&vartv, &tgttv);
+ tv_copy(&vartv, &tgttv);
}
ShaDaWriteResult spe_ret;
if ((spe_ret = shada_pack_entry(packer, (ShadaEntry) {
@@ -2573,13 +2573,13 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
}
}
}, max_kbyte)) == kSDWriteFailed) {
- clear_tv(&vartv);
- clear_tv(&tgttv);
+ tv_clear(&vartv);
+ tv_clear(&tgttv);
ret = kSDWriteFailed;
goto shada_write_exit;
}
- clear_tv(&vartv);
- clear_tv(&tgttv);
+ tv_clear(&vartv);
+ tv_clear(&tgttv);
if (spe_ret == kSDWriteSuccessfull) {
int kh_ret;
(void) kh_put(strset, &wms->dumped_variables, name, &kh_ret);
@@ -3154,17 +3154,17 @@ static void shada_free_shada_entry(ShadaEntry *const entry)
case kSDItemJump:
case kSDItemGlobalMark:
case kSDItemLocalMark: {
- dict_unref(entry->data.filemark.additional_data);
+ tv_dict_unref(entry->data.filemark.additional_data);
xfree(entry->data.filemark.fname);
break;
}
case kSDItemSearchPattern: {
- dict_unref(entry->data.search_pattern.additional_data);
+ tv_dict_unref(entry->data.search_pattern.additional_data);
xfree(entry->data.search_pattern.pat);
break;
}
case kSDItemRegister: {
- dict_unref(entry->data.reg.additional_data);
+ tv_dict_unref(entry->data.reg.additional_data);
for (size_t i = 0; i < entry->data.reg.contents_size; i++) {
xfree(entry->data.reg.contents[i]);
}
@@ -3172,25 +3172,25 @@ static void shada_free_shada_entry(ShadaEntry *const entry)
break;
}
case kSDItemHistoryEntry: {
- list_unref(entry->data.history_item.additional_elements);
+ tv_list_unref(entry->data.history_item.additional_elements);
xfree(entry->data.history_item.string);
break;
}
case kSDItemVariable: {
- list_unref(entry->data.global_var.additional_elements);
+ tv_list_unref(entry->data.global_var.additional_elements);
xfree(entry->data.global_var.name);
- clear_tv(&entry->data.global_var.value);
+ tv_clear(&entry->data.global_var.value);
break;
}
case kSDItemSubString: {
- list_unref(entry->data.sub_string.additional_elements);
+ tv_list_unref(entry->data.sub_string.additional_elements);
xfree(entry->data.sub_string.sub);
break;
}
case kSDItemBufferList: {
for (size_t i = 0; i < entry->data.buffer_list.size; i++) {
xfree(entry->data.buffer_list.buffers[i].fname);
- dict_unref(entry->data.buffer_list.buffers[i].additional_data);
+ tv_dict_unref(entry->data.buffer_list.buffers[i].additional_data);
}
xfree(entry->data.buffer_list.buffers);
break;
@@ -3451,7 +3451,7 @@ static inline char *get_converted_string(const vimconv_T *const sd_conv,
"cannot be converted to a VimL dictionary")), \
initial_fpos); \
ga_clear(&ad_ga); \
- clear_tv(&adtv); \
+ tv_clear(&adtv); \
goto shada_read_next_item_error; \
} \
tgt = adtv.vval.v_dict; \
@@ -3474,7 +3474,7 @@ static inline char *get_converted_string(const vimconv_T *const sd_conv,
if (msgpack_to_vim(obj, &aetv) == FAIL) { \
emsgf(_(READERR(name, "cannot be converted to a VimL list")), \
initial_fpos); \
- clear_tv(&aetv); \
+ tv_clear(&aetv); \
goto shada_read_next_item_error; \
} \
assert(aetv.v_type == VAR_LIST); \
@@ -3866,7 +3866,7 @@ shada_read_next_item_hist_no_conv:
&tgttv,
true,
0);
- clear_tv(&entry->data.global_var.value);
+ tv_clear(&entry->data.global_var.value);
entry->data.global_var.value = tgttv;
}
SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 2,
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 3b891d998f..d4f49bffb2 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -2309,10 +2309,11 @@ int captype(char_u *word, char_u *end)
for (p = word; !spell_iswordp_nmw(p, curwin); mb_ptr_adv(p))
if (end == NULL ? *p == NUL : p >= end)
return 0; // only non-word characters, illegal word
- if (has_mbyte)
- c = mb_ptr2char_adv(&p);
- else
+ if (has_mbyte) {
+ c = mb_ptr2char_adv((const char_u **)&p);
+ } else {
c = *p++;
+ }
firstcap = allcap = SPELL_ISUPPER(c);
// Need to check all letters to find a word with mixed upper/lower.
@@ -2607,14 +2608,15 @@ static bool spell_iswordp(char_u *p, win_T *wp)
// Returns true if "p" points to a word character.
// Unlike spell_iswordp() this doesn't check for "midword" characters.
-bool spell_iswordp_nmw(char_u *p, win_T *wp)
+bool spell_iswordp_nmw(const char_u *p, win_T *wp)
{
int c;
if (has_mbyte) {
c = mb_ptr2char(p);
- if (c > 255)
+ if (c > 255) {
return spell_mb_isword_class(mb_get_class(p), wp);
+ }
return spelltab.st_isw[c];
}
return spelltab.st_isw[*p];
@@ -2675,7 +2677,7 @@ int spell_casefold(char_u *str, int len, char_u *buf, int buflen)
buf[outi] = NUL;
return FAIL;
}
- c = mb_cptr2char_adv(&p);
+ c = mb_cptr2char_adv((const char_u **)&p);
outi += mb_char2bytes(SPELL_TOFOLD(c), buf + outi);
}
buf[outi] = NUL;
@@ -2937,7 +2939,7 @@ void spell_suggest(int count)
// For redo we use a change-word command.
ResetRedobuff();
- AppendToRedobuff((char_u *)"ciw");
+ AppendToRedobuff("ciw");
AppendToRedobuffLit(p + c,
stp->st_wordlen + sug.su_badlen - stp->st_orglen);
AppendCharToRedobuff(ESC);
@@ -3232,7 +3234,7 @@ static void spell_suggest_expr(suginfo_T *su, char_u *expr)
list_T *list;
listitem_T *li;
int score;
- char_u *p;
+ const char *p;
// The work is split up in a few parts to avoid having to export
// suginfo_T.
@@ -3244,11 +3246,12 @@ static void spell_suggest_expr(suginfo_T *su, char_u *expr)
if (li->li_tv.v_type == VAR_LIST) {
// Get the word and the score from the items.
score = get_spellword(li->li_tv.vval.v_list, &p);
- if (score >= 0 && score <= su->su_maxscore)
- add_suggestion(su, &su->su_ga, p, su->su_badlen,
- score, 0, true, su->su_sallang, false);
+ if (score >= 0 && score <= su->su_maxscore) {
+ add_suggestion(su, &su->su_ga, (const char_u *)p, su->su_badlen,
+ score, 0, true, su->su_sallang, false);
+ }
}
- list_unref(list);
+ tv_list_unref(list);
}
// Remove bogus suggestions, sort and truncate at "maxcount".
@@ -3405,17 +3408,19 @@ void onecap_copy(char_u *word, char_u *wcopy, bool upper)
int l;
p = word;
- if (has_mbyte)
- c = mb_cptr2char_adv(&p);
- else
+ if (has_mbyte) {
+ c = mb_cptr2char_adv((const char_u **)&p);
+ } else {
c = *p++;
- if (upper)
+ }
+ if (upper) {
c = SPELL_TOUPPER(c);
- else
+ } else {
c = SPELL_TOFOLD(c);
- if (has_mbyte)
+ }
+ if (has_mbyte) {
l = mb_char2bytes(c, wcopy);
- else {
+ } else {
l = 1;
wcopy[0] = c;
}
@@ -3432,10 +3437,11 @@ static void allcap_copy(char_u *word, char_u *wcopy)
d = wcopy;
for (s = word; *s != NUL; ) {
- if (has_mbyte)
- c = mb_cptr2char_adv(&s);
- else
+ if (has_mbyte) {
+ c = mb_cptr2char_adv((const char_u **)&s);
+ } else {
c = *s++;
+ }
if (c == 0xdf) {
c = 'S';
@@ -5616,7 +5622,7 @@ static void
add_suggestion (
suginfo_T *su,
garray_T *gap, // either su_ga or su_sga
- char_u *goodword,
+ const char_u *goodword,
int badlenarg, // len of bad word replaced with "goodword"
int score,
int altscore,
@@ -5630,13 +5636,11 @@ add_suggestion (
int badlen; // len of bad word changed
suggest_T *stp;
suggest_T new_sug;
- int i;
- char_u *pgood, *pbad;
// Minimize "badlen" for consistency. Avoids that changing "the the" to
// "thee the" is added next to changing the first "the" the "thee".
- pgood = goodword + STRLEN(goodword);
- pbad = su->su_badptr + badlenarg;
+ const char_u *pgood = goodword + STRLEN(goodword);
+ char_u *pbad = su->su_badptr + badlenarg;
for (;; ) {
goodlen = (int)(pgood - goodword);
badlen = (int)(pbad - su->su_badptr);
@@ -5656,9 +5660,10 @@ add_suggestion (
// the first "the" to itself.
return;
- if (GA_EMPTY(gap))
+ int i;
+ if (GA_EMPTY(gap)) {
i = -1;
- else {
+ } else {
// Check if the word is already there. Also check the length that is
// being replaced "thes," -> "these" is a different suggestion from
// "thes" -> "these".
@@ -5857,27 +5862,31 @@ cleanup_suggestions (
return maxscore;
}
-// Soundfold a string, for soundfold().
-// Result is in allocated memory, NULL for an error.
-char_u *eval_soundfold(char_u *word)
+/// Soundfold a string, for soundfold()
+///
+/// @param[in] word Word to soundfold.
+///
+/// @return [allocated] soundfolded string or NULL in case of error. May return
+/// copy of the input string if soundfolding is not
+/// supported by any of the languages in &spellang.
+char *eval_soundfold(const char *const word)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{
- langp_T *lp;
- char_u sound[MAXWLEN];
-
if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) {
// Use the sound-folding of the first language that supports it.
- for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi) {
- lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
+ for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; lpi++) {
+ langp_T *const lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
if (!GA_EMPTY(&lp->lp_slang->sl_sal)) {
// soundfold the word
- spell_soundfold(lp->lp_slang, word, false, sound);
- return vim_strsave(sound);
+ char_u sound[MAXWLEN];
+ spell_soundfold(lp->lp_slang, (char_u *)word, false, sound);
+ return xstrdup((const char *)sound);
}
}
}
// No language with sound folding, return word as-is.
- return vim_strsave(word);
+ return xstrdup(word);
}
/// Turn "inword" into its sound-a-like equivalent in "res[MAXWLEN]".
@@ -5934,12 +5943,12 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res)
// The sl_sal_first[] table contains the translation for chars up to
// 255, sl_sal the rest.
for (s = inword; *s != NUL; ) {
- c = mb_cptr2char_adv(&s);
- if (enc_utf8 ? utf_class(c) == 0 : ascii_iswhite(c))
+ c = mb_cptr2char_adv((const char_u **)&s);
+ if (enc_utf8 ? utf_class(c) == 0 : ascii_iswhite(c)) {
c = ' ';
- else if (c < 256)
+ } else if (c < 256) {
c = slang->sl_sal_first[c];
- else {
+ } else {
ip = ((int **)slang->sl_sal.ga_data)[c & 0xff];
if (ip == NULL) // empty list, can't match
c = NUL;
@@ -6224,9 +6233,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
int word[MAXWLEN];
int wres[MAXWLEN];
int l;
- char_u *s;
int *ws;
- char_u *t;
int *pf;
int i, j, z;
int reslen;
@@ -6246,9 +6253,9 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
// Remove accents, if wanted. We actually remove all non-word characters.
// But keep white space.
wordlen = 0;
- for (s = inword; *s != NUL; ) {
- t = s;
- c = mb_cptr2char_adv(&s);
+ for (const char_u *s = inword; *s != NUL; ) {
+ const char_u *t = s;
+ c = mb_cptr2char_adv((const char_u **)&s);
if (slang->sl_rem_accents) {
if (enc_utf8 ? utf_class(c) == 0 : ascii_iswhite(c)) {
if (did_white)
@@ -6257,8 +6264,9 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
did_white = true;
} else {
did_white = false;
- if (!spell_iswordp_nmw(t, curwin))
+ if (!spell_iswordp_nmw(t, curwin)) {
continue;
+ }
}
}
word[wordlen++] = c;
@@ -6305,7 +6313,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
continue;
++k;
}
- s = smp[n].sm_rules;
+ char_u *s = smp[n].sm_rules;
pri = 5; // default priority
p0 = *s;
@@ -6704,25 +6712,30 @@ soundalike_score (
// support multi-byte characters.
static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword)
{
- int *cnt;
- int badlen, goodlen; // lengths including NUL
+ int *cnt;
int j, i;
int t;
int bc, gc;
int pbc, pgc;
- char_u *p;
int wbadword[MAXWLEN];
int wgoodword[MAXWLEN];
const bool l_has_mbyte = has_mbyte;
+ // Lengths with NUL.
+ int badlen;
+ int goodlen;
if (l_has_mbyte) {
// Get the characters from the multi-byte strings and put them in an
// int array for easy access.
- for (p = badword, badlen = 0; *p != NUL; )
+ badlen = 0;
+ for (const char_u *p = badword; *p != NUL; ) {
wbadword[badlen++] = mb_cptr2char_adv(&p);
+ }
wbadword[badlen++] = 0;
- for (p = goodword, goodlen = 0; *p != NUL; )
+ goodlen = 0;
+ for (const char_u *p = goodword; *p != NUL; ) {
wgoodword[goodlen++] = mb_cptr2char_adv(&p);
+ }
wgoodword[goodlen++] = 0;
} else {
badlen = (int)STRLEN(badword) + 1;
@@ -6956,19 +6969,20 @@ static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goo
int score_off;
int minscore;
int round;
- char_u *p;
int wbadword[MAXWLEN];
int wgoodword[MAXWLEN];
// Get the characters from the multi-byte strings and put them in an
// int array for easy access.
bi = 0;
- for (p = badword; *p != NUL; )
+ for (const char_u *p = badword; *p != NUL; ) {
wbadword[bi++] = mb_cptr2char_adv(&p);
+ }
wbadword[bi++] = 0;
gi = 0;
- for (p = goodword; *p != NUL; )
+ for (const char_u *p = goodword; *p != NUL; ) {
wgoodword[gi++] = mb_cptr2char_adv(&p);
+ }
wgoodword[gi++] = 0;
// The idea is to go from start to end over the words. So long as
@@ -7134,16 +7148,17 @@ void ex_spelldump(exarg_T *eap)
char_u *spl;
long dummy;
- if (no_spell_checking(curwin))
+ if (no_spell_checking(curwin)) {
return;
- get_option_value((char_u*)"spl", &dummy, &spl, OPT_LOCAL);
+ }
+ get_option_value((char_u *)"spl", &dummy, &spl, OPT_LOCAL);
// Create a new empty buffer in a new window.
do_cmdline_cmd("new");
// enable spelling locally in the new window
- set_option_value((char_u*)"spell", true, (char_u*)"", OPT_LOCAL);
- set_option_value((char_u*)"spl", dummy, spl, OPT_LOCAL);
+ set_option_value("spell", true, "", OPT_LOCAL);
+ set_option_value("spl", dummy, (char *)spl, OPT_LOCAL);
xfree(spl);
if (!bufempty()) {
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index c108ae4a2c..4d7ff558ad 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -1435,7 +1435,7 @@ static int set_sofo(slang_T *lp, char_u *from, char_u *to)
// First count the number of items for each list. Temporarily use
// sl_sal_first[] for this.
for (p = from, s = to; *p != NUL && *s != NUL; ) {
- c = mb_cptr2char_adv(&p);
+ c = mb_cptr2char_adv((const char_u **)&p);
mb_cptr_adv(s);
if (c >= 256)
++lp->sl_sal_first[c & 0xff];
@@ -1455,8 +1455,8 @@ static int set_sofo(slang_T *lp, char_u *from, char_u *to)
// list.
memset(lp->sl_sal_first, 0, sizeof(salfirst_T) * 256);
for (p = from, s = to; *p != NUL && *s != NUL; ) {
- c = mb_cptr2char_adv(&p);
- i = mb_cptr2char_adv(&s);
+ c = mb_cptr2char_adv((const char_u **)&p);
+ i = mb_cptr2char_adv((const char_u **)&s);
if (c >= 256) {
// Append the from-to chars at the end of the list with
// the low byte.
@@ -1542,8 +1542,9 @@ static int *mb_str2wide(char_u *s)
int i = 0;
int *res = xmalloc((mb_charlen(s) + 1) * sizeof(int));
- for (char_u *p = s; *p != NUL; )
- res[i++] = mb_ptr2char_adv(&p);
+ for (char_u *p = s; *p != NUL; ) {
+ res[i++] = mb_ptr2char_adv((const char_u **)&p);
+ }
res[i] = NUL;
return res;
@@ -2486,13 +2487,14 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
// Check that every character appears only once.
for (p = items[1]; *p != NUL; ) {
- c = mb_ptr2char_adv(&p);
+ c = mb_ptr2char_adv((const char_u **)&p);
if ((!GA_EMPTY(&spin->si_map)
&& vim_strchr(spin->si_map.ga_data, c)
!= NULL)
- || vim_strchr(p, c) != NULL)
+ || vim_strchr(p, c) != NULL) {
smsg(_("Duplicate character in MAP in %s line %d"),
fname, lnum);
+ }
}
// We simply concatenate all the MAP strings, separated by
@@ -2717,12 +2719,12 @@ static unsigned get_affitem(int flagtype, char_u **pp)
}
res = getdigits_int(pp);
} else {
- res = mb_ptr2char_adv(pp);
+ res = mb_ptr2char_adv((const char_u **)pp);
if (flagtype == AFT_LONG || (flagtype == AFT_CAPLONG
&& res >= 'A' && res <= 'Z')) {
if (**pp == NUL)
return 0;
- res = mb_ptr2char_adv(pp) + (res << 16);
+ res = mb_ptr2char_adv((const char_u **)pp) + (res << 16);
}
}
return res;
@@ -2823,12 +2825,14 @@ static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag)
case AFT_CAPLONG:
case AFT_LONG:
for (p = afflist; *p != NUL; ) {
- n = mb_ptr2char_adv(&p);
+ n = mb_ptr2char_adv((const char_u **)&p);
if ((flagtype == AFT_LONG || (n >= 'A' && n <= 'Z'))
- && *p != NUL)
- n = mb_ptr2char_adv(&p) + (n << 16);
- if (n == flag)
+ && *p != NUL) {
+ n = mb_ptr2char_adv((const char_u **)&p) + (n << 16);
+ }
+ if (n == flag) {
return true;
+ }
}
break;
@@ -5436,10 +5440,11 @@ static void init_spellfile(void)
fname = LANGP_ENTRY(curwin->w_s->b_langp, 0)
->lp_slang->sl_fname;
vim_snprintf((char *)buf + l, MAXPATHL - l, ".%s.add",
- fname != NULL
- && strstr((char *)path_tail(fname), ".ascii.") != NULL
- ? (char_u *)"ascii" : spell_enc());
- set_option_value((char_u *)"spellfile", 0L, buf, OPT_LOCAL);
+ ((fname != NULL
+ && strstr((char *)path_tail(fname), ".ascii.") != NULL)
+ ? "ascii"
+ : (const char *)spell_enc()));
+ set_option_value("spellfile", 0L, (const char *)buf, OPT_LOCAL);
break;
}
aspath = false;
@@ -5465,9 +5470,9 @@ static int set_spell_chartab(char_u *fol, char_u *low, char_u *upp)
EMSG(_(e_affform));
return FAIL;
}
- f = mb_ptr2char_adv(&pf);
- l = mb_ptr2char_adv(&pl);
- u = mb_ptr2char_adv(&pu);
+ f = mb_ptr2char_adv((const char_u **)&pf);
+ l = mb_ptr2char_adv((const char_u **)&pl);
+ u = mb_ptr2char_adv((const char_u **)&pu);
// Every character that appears is a word character.
if (f < 256)
new_st.st_isw[f] = true;
@@ -5532,7 +5537,7 @@ set_spell_charflags (
}
if (*p != NUL) {
- c = mb_ptr2char_adv(&p);
+ c = mb_ptr2char_adv((const char_u **)&p);
new_st.st_fold[i + 128] = c;
if (i + 128 != c && new_st.st_isu[i + 128] && c < 256)
new_st.st_upper[c] = i + 128;
@@ -5619,12 +5624,13 @@ static void set_map_str(slang_T *lp, char_u *map)
// "aaa/bbb/ccc/". Fill sl_map_array[c] with the character before c and
// before the same slash. For characters above 255 sl_map_hash is used.
for (p = map; *p != NUL; ) {
- c = mb_cptr2char_adv(&p);
- if (c == '/')
+ c = mb_cptr2char_adv((const char_u **)&p);
+ if (c == '/') {
headc = 0;
- else {
- if (headc == 0)
+ } else {
+ if (headc == 0) {
headc = c;
+ }
// Characters above 255 don't fit in sl_map_array[], put them in
// the hash table. Each entry is the char, a NUL the headchar and
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index 267832ed2d..5dcffe00e0 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -291,30 +291,33 @@ void vim_strup(char_u *p)
}
}
-/*
- * Make string "s" all upper-case and return it in allocated memory.
- * Handles multi-byte characters as well as possible.
- */
-char_u *strup_save(const char_u *orig)
+/// Make given string all upper-case
+///
+/// Handels multi-byte characters as good as possible.
+///
+/// @param[in] orig Input string.
+///
+/// @return [allocated] upper-cased string.
+char *strup_save(const char *const orig)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{
- char_u *res = vim_strsave(orig);
+ char *res = xstrdup(orig);
- char_u *p = res;
+ char *p = res;
while (*p != NUL) {
int l;
if (enc_utf8) {
- int c = utf_ptr2char(p);
+ int c = utf_ptr2char((const char_u *)p);
int uc = utf_toupper(c);
- /* Reallocate string when byte count changes. This is rare,
- * thus it's OK to do another malloc()/free(). */
- l = utf_ptr2len(p);
+ // Reallocate string when byte count changes. This is rare,
+ // thus it's OK to do another malloc()/free().
+ l = utf_ptr2len((const char_u *)p);
int newl = utf_char2len(uc);
if (newl != l) {
// TODO(philix): use xrealloc() in strup_save()
- char_u *s = xmalloc(STRLEN(res) + (size_t)(1 + newl - l));
+ char *s = xmalloc(STRLEN(res) + (size_t)(1 + newl - l));
memcpy(s, res, (size_t)(p - res));
STRCPY(s + (p - res) + newl, p + l);
p = s + (p - res);
@@ -322,12 +325,13 @@ char_u *strup_save(const char_u *orig)
res = s;
}
- utf_char2bytes(uc, p);
+ utf_char2bytes(uc, (char_u *)p);
p += newl;
- } else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
- p += l; /* skip multi-byte character */
- else {
- *p = (char_u) TOUPPER_LOC(*p); // note that toupper() can be a macro
+ } else if (has_mbyte && (l = (*mb_ptr2len)((const char_u *)p)) > 1) {
+ p += l; // Skip multi-byte character.
+ } else {
+ // note that toupper() can be a macro
+ *p = (char)(uint8_t)TOUPPER_LOC(*p);
p++;
}
}
@@ -571,8 +575,8 @@ static varnumber_T tv_nr(typval_T *tvs, int *idxp)
EMSG(_(e_printf));
} else {
(*idxp)++;
- int err = false;
- n = (varnumber_T)get_tv_number_chk(&tvs[idx], &err);
+ bool err = false;
+ n = tv_get_number_chk(&tvs[idx], &err);
if (err) {
n = 0;
}
@@ -594,22 +598,21 @@ static varnumber_T tv_nr(typval_T *tvs, int *idxp)
/// free "*tofree".
///
/// @return String value or NULL in case of error.
-static char *tv_str(typval_T *tvs, int *idxp, char ** const tofree)
+static const char *tv_str(typval_T *tvs, int *idxp, char **const tofree)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
int idx = *idxp - 1;
- char *s = NULL;
+ const char *s = NULL;
if (tvs[idx].v_type == VAR_UNKNOWN) {
EMSG(_(e_printf));
} else {
(*idxp)++;
if (tvs[idx].v_type == VAR_STRING || tvs[idx].v_type == VAR_NUMBER) {
- s = (char *)get_tv_string_chk(&tvs[idx]);
+ s = tv_get_string_chk(&tvs[idx]);
*tofree = NULL;
} else {
- s = encode_tv2echo(&tvs[idx], NULL);
- *tofree = s;
+ s = *tofree = encode_tv2echo(&tvs[idx], NULL);
}
}
return s;
@@ -949,7 +952,7 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,
case 's':
case 'S':
str_arg = tvs ? tv_str(tvs, &arg_idx, &tofree)
- : va_arg(ap, char *);
+ : va_arg(ap, const char *);
if (!str_arg) {
str_arg = "[NULL]";
str_arg_l = 6;
diff --git a/src/nvim/strings.h b/src/nvim/strings.h
index eb8b83c7d0..59b8701a3f 100644
--- a/src/nvim/strings.h
+++ b/src/nvim/strings.h
@@ -1,12 +1,11 @@
#ifndef NVIM_STRINGS_H
#define NVIM_STRINGS_H
-#include <stdarg.h>
#include <stdbool.h>
-#include <stddef.h>
+#include <stdarg.h>
#include "nvim/types.h"
-#include "nvim/eval_defs.h"
+#include "nvim/eval/typval.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "strings.h.generated.h"
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 0a27d9dd92..e36b00d770 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -42,34 +42,38 @@
static bool did_syntax_onoff = false;
-// Structure that stores information about a highlight group.
-// The ID of a highlight group is also called group ID. It is the index in
-// the highlight_ga array PLUS ONE.
+/// Structure that stores information about a highlight group.
+/// The ID of a highlight group is also called group ID. It is the index in
+/// the highlight_ga array PLUS ONE.
struct hl_group {
- char_u *sg_name; // highlight group name
- char_u *sg_name_u; // uppercase of sg_name
- int sg_attr; // Screen attr
- int sg_link; // link to this highlight group ID
- int sg_set; // combination of SG_* flags
- scid_T sg_scriptID; // script in which the group was last set
+ char_u *sg_name; ///< highlight group name
+ char_u *sg_name_u; ///< uppercase of sg_name
+ int sg_attr; ///< Screen attr @see ATTR_ENTRY
+ int sg_link; ///< link to this highlight group ID
+ int sg_set; ///< combination of flags in \ref SG_SET
+ scid_T sg_scriptID; ///< script in which the group was last set
// for terminal UIs
- int sg_cterm; // "cterm=" highlighting attr
- int sg_cterm_fg; // terminal fg color number + 1
- int sg_cterm_bg; // terminal bg color number + 1
- int sg_cterm_bold; // bold attr was set for light color
+ int sg_cterm; ///< "cterm=" highlighting attr
+ int sg_cterm_fg; ///< terminal fg color number + 1
+ int sg_cterm_bg; ///< terminal bg color number + 1
+ int sg_cterm_bold; ///< bold attr was set for light color
// for RGB UIs
- int sg_gui; // "gui=" highlighting attributes
- RgbValue sg_rgb_fg; // RGB foreground color
- RgbValue sg_rgb_bg; // RGB background color
- RgbValue sg_rgb_sp; // RGB special color
- uint8_t *sg_rgb_fg_name; // RGB foreground color name
- uint8_t *sg_rgb_bg_name; // RGB background color name
- uint8_t *sg_rgb_sp_name; // RGB special color name
+ int sg_gui; ///< "gui=" highlighting attributes
+ ///< (combination of \ref HL_ATTRIBUTES)
+ RgbValue sg_rgb_fg; ///< RGB foreground color
+ RgbValue sg_rgb_bg; ///< RGB background color
+ RgbValue sg_rgb_sp; ///< RGB special color
+ uint8_t *sg_rgb_fg_name; ///< RGB foreground color name
+ uint8_t *sg_rgb_bg_name; ///< RGB background color name
+ uint8_t *sg_rgb_sp_name; ///< RGB special color name
};
+/// \addtogroup SG_SET
+/// @{
#define SG_CTERM 2 // cterm has been set
#define SG_GUI 4 // gui has been set
#define SG_LINK 8 // link has been set
+/// @}
// highlight groups for 'highlight' option
static garray_T highlight_ga = GA_EMPTY_INIT_VALUE;
@@ -1406,14 +1410,14 @@ static int syn_stack_equal(synstate_T *sp)
/* If the pointer is different it can still be the
* same text. Compare the strings, ignore case when
* the start item has the sp_ic flag set. */
- if (bsx->matches[j] == NULL
- || six->matches[j] == NULL)
+ if (bsx->matches[j] == NULL || six->matches[j] == NULL) {
break;
- if ((SYN_ITEMS(syn_block)[CUR_STATE(i).si_idx]).sp_ic
- ? mb_stricmp(bsx->matches[j],
- six->matches[j]) != 0
- : STRCMP(bsx->matches[j], six->matches[j]) != 0)
+ }
+ if (mb_strcmp_ic((SYN_ITEMS(syn_block)[CUR_STATE(i).si_idx]).sp_ic,
+ (const char *)bsx->matches[j],
+ (const char *)six->matches[j]) != 0) {
break;
+ }
}
}
if (j != NSUBEXP)
@@ -3259,9 +3263,10 @@ static void syn_cmd_clear(exarg_T *eap, int syncing)
syntax_sync_clear();
else {
syntax_clear(curwin->w_s);
- if (curwin->w_s == &curwin->w_buffer->b_s)
- do_unlet((char_u *)"b:current_syntax", TRUE);
- do_unlet((char_u *)"w:current_syntax", TRUE);
+ if (curwin->w_s == &curwin->w_buffer->b_s) {
+ do_unlet(S_LEN("b:current_syntax"), true);
+ }
+ do_unlet(S_LEN("w:current_syntax"), true);
}
} else {
/*
@@ -3337,7 +3342,7 @@ static void syn_cmd_enable(exarg_T *eap, int syncing)
{
set_internal_string_var((char_u *)"syntax_cmd", (char_u *)"enable");
syn_cmd_onoff(eap, "syntax");
- do_unlet((char_u *)"g:syntax_cmd", TRUE);
+ do_unlet(S_LEN("g:syntax_cmd"), true);
}
/*
@@ -3350,7 +3355,7 @@ static void syn_cmd_reset(exarg_T *eap, int syncing)
if (!eap->skip) {
set_internal_string_var((char_u *)"syntax_cmd", (char_u *)"reset");
do_cmdline_cmd("runtime! syntax/syncolor.vim");
- do_unlet((char_u *)"g:syntax_cmd", TRUE);
+ do_unlet(S_LEN("g:syntax_cmd"), true);
}
}
@@ -5537,10 +5542,10 @@ void ex_ownsyntax(exarg_T *eap)
set_internal_string_var((char_u *)"w:current_syntax", new_value);
}
- /* restore value of b:current_syntax */
- if (old_value == NULL)
- do_unlet((char_u *)"b:current_syntax", TRUE);
- else {
+ // Restore value of b:current_syntax.
+ if (old_value == NULL) {
+ do_unlet(S_LEN("b:current_syntax"), true);
+ } else {
set_internal_string_var((char_u *)"b:current_syntax", old_value);
xfree(old_value);
}
@@ -5573,43 +5578,42 @@ void reset_expand_highlight(void)
* Handle command line completion for :match and :echohl command: Add "None"
* as highlight group.
*/
-void set_context_in_echohl_cmd(expand_T *xp, char_u *arg)
+void set_context_in_echohl_cmd(expand_T *xp, const char *arg)
{
xp->xp_context = EXPAND_HIGHLIGHT;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
include_none = 1;
}
/*
* Handle command line completion for :syntax command.
*/
-void set_context_in_syntax_cmd(expand_T *xp, char_u *arg)
+void set_context_in_syntax_cmd(expand_T *xp, const char *arg)
{
- char_u *p;
-
- /* Default: expand subcommands */
+ // Default: expand subcommands.
xp->xp_context = EXPAND_SYNTAX;
expand_what = EXP_SUBCMD;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
include_link = 0;
include_default = 0;
/* (part of) subcommand already typed */
if (*arg != NUL) {
- p = skiptowhite(arg);
- if (*p != NUL) { /* past first word */
- xp->xp_pattern = skipwhite(p);
- if (*skiptowhite(xp->xp_pattern) != NUL)
+ const char *p = (const char *)skiptowhite((const char_u *)arg);
+ if (*p != NUL) { // Past first word.
+ xp->xp_pattern = skipwhite((const char_u *)p);
+ if (*skiptowhite(xp->xp_pattern) != NUL) {
xp->xp_context = EXPAND_NOTHING;
- else if (STRNICMP(arg, "case", p - arg) == 0)
+ } else if (STRNICMP(arg, "case", p - arg) == 0) {
expand_what = EXP_CASE;
- else if ( STRNICMP(arg, "keyword", p - arg) == 0
+ } else if (STRNICMP(arg, "keyword", p - arg) == 0
|| STRNICMP(arg, "region", p - arg) == 0
|| STRNICMP(arg, "match", p - arg) == 0
- || STRNICMP(arg, "list", p - arg) == 0)
+ || STRNICMP(arg, "list", p - arg) == 0) {
xp->xp_context = EXPAND_HIGHLIGHT;
- else
+ } else {
xp->xp_context = EXPAND_NOTHING;
+ }
}
}
}
@@ -5912,6 +5916,7 @@ static char *highlight_init_both[] =
"default link EndOfBuffer NonText",
"default link QuickFixLine Search",
"default link Substitute Search",
+ "default link Whitespace NonText",
NULL
};
@@ -6093,16 +6098,16 @@ int load_colors(char_u *name)
return retval;
}
-/*
- * Handle the ":highlight .." command.
- * When using ":hi clear" this is called recursively for each group with
- * "forceit" and "init" both TRUE.
- */
-void
-do_highlight (
+
+/// Handle the ":highlight .." command.
+/// When using ":hi clear" this is called recursively for each group with
+/// "forceit" and "init" both TRUE.
+/// @param init TRUE when called for initializing
+void
+do_highlight(
char_u *line,
int forceit,
- int init /* TRUE when called for initializing */
+ int init
)
{
char_u *name_end;
@@ -6231,7 +6236,7 @@ do_highlight (
*/
line = linep;
if (ends_excmd(*line)) {
- do_unlet((char_u *)"colors_name", TRUE);
+ do_unlet(S_LEN("colors_name"), true);
restore_cterm_colors();
/*
@@ -6510,16 +6515,16 @@ do_highlight (
if (!ui_rgb_attached()) {
must_redraw = CLEAR;
if (color >= 0) {
- if (t_colors < 16)
+ if (t_colors < 16) {
i = (color == 0 || color == 4);
- else
+ } else {
i = (color < 7 || color == 8);
- /* Set the 'background' option if the value is
- * wrong. */
- if (i != (*p_bg == 'd'))
- set_option_value((char_u *)"bg", 0L,
- i ? (char_u *)"dark"
- : (char_u *)"light", 0);
+ }
+ // Set the 'background' option if the value is
+ // wrong.
+ if (i != (*p_bg == 'd')) {
+ set_option_value("bg", 0L, (i ? "dark" : "light"), 0);
+ }
}
}
}
@@ -6704,12 +6709,10 @@ static garray_T attr_table = GA_EMPTY_INIT_VALUE;
#define ATTR_ENTRY(idx) ((attrentry_T *)attr_table.ga_data)[idx]
-/*
- * Return the attr number for a set of colors and font.
- * Add a new entry to the term_attr_table, attr_table or gui_attr_table
- * if the combination is new.
- * Return 0 for error.
- */
+/// Return the attr number for a set of colors and font.
+/// Add a new entry to the term_attr_table, attr_table or gui_attr_table
+/// if the combination is new.
+/// @return 0 for error.
int get_attr_entry(attrentry_T *aep)
{
garray_T *table = &attr_table;
@@ -6930,21 +6933,21 @@ static int highlight_list_arg(int id, int didh, int type, int iarg, char_u *sarg
return didh;
}
-/*
- * Return "1" if highlight group "id" has attribute "flag".
- * Return NULL otherwise.
- */
-char_u *
-highlight_has_attr (
- int id,
- int flag,
- int modec // 'g' for GUI, 'c' for cterm
-)
+/// Check whether highlight group has attribute
+///
+/// @param[in] id Highlight group to check.
+/// @param[in] flag Attribute to check.
+/// @param[in] modec 'g' for GUI, 'c' for term.
+///
+/// @return "1" if highlight group has attribute, NULL otherwise.
+const char *highlight_has_attr(const int id, const int flag, const int modec)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{
int attr;
- if (id <= 0 || id > highlight_ga.ga_len)
+ if (id <= 0 || id > highlight_ga.ga_len) {
return NULL;
+ }
if (modec == 'g') {
attr = HL_TABLE()[id - 1].sg_gui;
@@ -6952,39 +6955,42 @@ highlight_has_attr (
attr = HL_TABLE()[id - 1].sg_cterm;
}
- if (attr & flag)
- return (char_u *)"1";
- return NULL;
+ return (attr & flag) ? "1" : NULL;
}
-/*
- * Return color name of highlight group "id".
- */
-char_u *
-highlight_color (
- int id,
- char_u *what, /* "font", "fg", "bg", "sp", "fg#", "bg#" or "sp#" */
- int modec /* 'g' for GUI, 'c' for cterm, 't' for term */
-)
+/// Return color name of the given highlight group
+///
+/// @param[in] id Highlight group to work with.
+/// @param[in] what What to return: one of "font", "fg", "bg", "sp", "fg#",
+/// "bg#" or "sp#".
+/// @param[in] modec 'g' for GUI, 'c' for cterm and 't' for term.
+///
+/// @return color name, possibly in a static buffer. Buffer will be overwritten
+/// on next highlight_color() call. May return NULL.
+const char *highlight_color(const int id, const char *const what,
+ const int modec)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- static char_u name[20];
+ static char name[20];
int n;
- int fg = FALSE;
- int sp = FALSE;
- int font = FALSE;
+ bool fg = false;
+ bool sp = false;
+ bool font = false;
- if (id <= 0 || id > highlight_ga.ga_len)
+ if (id <= 0 || id > highlight_ga.ga_len) {
return NULL;
+ }
- if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'g')
- fg = TRUE;
- else if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'o'
- && TOLOWER_ASC(what[2]) == 'n' && TOLOWER_ASC(what[3]) == 't')
- font = TRUE;
- else if (TOLOWER_ASC(what[0]) == 's' && TOLOWER_ASC(what[1]) == 'p')
- sp = TRUE;
- else if (!(TOLOWER_ASC(what[0]) == 'b' && TOLOWER_ASC(what[1]) == 'g'))
+ if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'g') {
+ fg = true;
+ } else if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'o'
+ && TOLOWER_ASC(what[2]) == 'n' && TOLOWER_ASC(what[3]) == 't') {
+ font = true;
+ } else if (TOLOWER_ASC(what[0]) == 's' && TOLOWER_ASC(what[1]) == 'p') {
+ sp = true;
+ } else if (!(TOLOWER_ASC(what[0]) == 'b' && TOLOWER_ASC(what[1]) == 'g')) {
return NULL;
+ }
if (modec == 'g') {
if (what[2] == '#' && ui_rgb_attached()) {
if (fg) {
@@ -6997,19 +7003,20 @@ highlight_color (
if (n < 0 || n > 0xffffff) {
return NULL;
}
- snprintf((char *)name, sizeof(name), "#%06x", n);
+ snprintf(name, sizeof(name), "#%06x", n);
return name;
}
if (fg) {
- return HL_TABLE()[id - 1].sg_rgb_fg_name;
+ return (const char *)HL_TABLE()[id - 1].sg_rgb_fg_name;
}
if (sp) {
- return HL_TABLE()[id - 1].sg_rgb_sp_name;
+ return (const char *)HL_TABLE()[id - 1].sg_rgb_sp_name;
}
- return HL_TABLE()[id - 1].sg_rgb_bg_name;
+ return (const char *)HL_TABLE()[id - 1].sg_rgb_bg_name;
}
- if (font || sp)
+ if (font || sp) {
return NULL;
+ }
if (modec == 'c') {
if (fg) {
n = HL_TABLE()[id - 1].sg_cterm_fg - 1;
@@ -7019,10 +7026,10 @@ highlight_color (
if (n < 0) {
return NULL;
}
- snprintf((char *)name, sizeof(name), "%d", n);
+ snprintf(name, sizeof(name), "%d", n);
return name;
}
- /* term doesn't have color */
+ // term doesn't have color.
return NULL;
}
@@ -7113,7 +7120,7 @@ set_hl_attr (
* Lookup a highlight group name and return it's ID.
* If it is not found, 0 is returned.
*/
-int syn_name2id(char_u *name)
+int syn_name2id(const char_u *name)
{
int i;
char_u name_u[200];
@@ -7133,7 +7140,7 @@ int syn_name2id(char_u *name)
/*
* Return TRUE if highlight group "name" exists.
*/
-int highlight_exists(char_u *name)
+int highlight_exists(const char_u *name)
{
return syn_name2id(name) > 0;
}
@@ -7161,12 +7168,13 @@ int syn_namen2id(char_u *linep, int len)
return id;
}
-/*
- * Find highlight group name in the table and return it's ID.
- * The argument is a pointer to the name and the length of the name.
- * If it doesn't exist yet, a new entry is created.
- * Return 0 for failure.
- */
+/// Find highlight group name in the table and return it's ID.
+/// If it doesn't exist yet, a new entry is created.
+///
+/// @param pp Highlight group name
+/// @param len length of \p pp
+///
+/// @return 0 for failure else the id of the group
int syn_check_group(char_u *pp, int len)
{
char_u *name = vim_strnsave(pp, len);
@@ -7469,41 +7477,41 @@ int highlight_changed(void)
/*
* Handle command line completion for :highlight command.
*/
-void set_context_in_highlight_cmd(expand_T *xp, char_u *arg)
+void set_context_in_highlight_cmd(expand_T *xp, const char *arg)
{
- char_u *p;
-
- /* Default: expand group names */
+ // Default: expand group names.
xp->xp_context = EXPAND_HIGHLIGHT;
- xp->xp_pattern = arg;
+ xp->xp_pattern = (char_u *)arg;
include_link = 2;
include_default = 1;
/* (part of) subcommand already typed */
if (*arg != NUL) {
- p = skiptowhite(arg);
- if (*p != NUL) { /* past "default" or group name */
+ const char *p = (const char *)skiptowhite((const char_u *)arg);
+ if (*p != NUL) { // Past "default" or group name.
include_default = 0;
- if (STRNCMP("default", arg, p - arg) == 0) {
- arg = skipwhite(p);
- xp->xp_pattern = arg;
- p = skiptowhite(arg);
+ if (strncmp("default", arg, p - arg) == 0) {
+ arg = (const char *)skipwhite((const char_u *)p);
+ xp->xp_pattern = (char_u *)arg;
+ p = (const char *)skiptowhite((const char_u *)arg);
}
if (*p != NUL) { /* past group name */
include_link = 0;
- if (arg[1] == 'i' && arg[0] == 'N')
+ if (arg[1] == 'i' && arg[0] == 'N') {
highlight_list();
- if (STRNCMP("link", arg, p - arg) == 0
- || STRNCMP("clear", arg, p - arg) == 0) {
- xp->xp_pattern = skipwhite(p);
- p = skiptowhite(xp->xp_pattern);
- if (*p != NUL) { /* past first group name */
- xp->xp_pattern = skipwhite(p);
- p = skiptowhite(xp->xp_pattern);
+ }
+ if (strncmp("link", arg, p - arg) == 0
+ || strncmp("clear", arg, p - arg) == 0) {
+ xp->xp_pattern = skipwhite((const char_u *)p);
+ p = (const char *)skiptowhite(xp->xp_pattern);
+ if (*p != NUL) { // Past first group name.
+ xp->xp_pattern = skipwhite((const char_u *)p);
+ p = (const char *)skiptowhite(xp->xp_pattern);
}
}
- if (*p != NUL) /* past group name(s) */
+ if (*p != NUL) { // Past group name(s).
xp->xp_context = EXPAND_NOTHING;
+ }
}
}
}
@@ -8240,7 +8248,14 @@ color_name_table_T color_name_table[] = {
{ NULL, 0 },
};
-RgbValue name_to_color(uint8_t *name)
+
+/// Translate to RgbValue if \p name is an hex value (e.g. #XXXXXX),
+/// else look into color_name_table to translate a color name to its
+/// hex value
+///
+/// @param[in] name string value to convert to RGB
+/// return the hex value or -1 if could not find a correct value
+RgbValue name_to_color(const uint8_t *name)
{
if (name[0] == '#' && isxdigit(name[1]) && isxdigit(name[2])
diff --git a/src/nvim/syntax.h b/src/nvim/syntax.h
index af2ac719c6..574e3372e2 100644
--- a/src/nvim/syntax.h
+++ b/src/nvim/syntax.h
@@ -5,10 +5,11 @@
#include "nvim/buffer_defs.h"
-/*
- * Terminal highlighting attribute bits.
- * Attributes above HL_ALL are used for syntax highlighting.
- */
+
+/// Terminal highlighting attribute bits.
+/// Attributes above HL_ALL are used for syntax highlighting.
+/// \addtogroup HL_ATTRIBUTES
+/// @{
#define HL_NORMAL 0x00
#define HL_INVERSE 0x01
#define HL_BOLD 0x02
@@ -16,6 +17,7 @@
#define HL_UNDERLINE 0x08
#define HL_UNDERCURL 0x10
#define HL_STANDOUT 0x20
+/// @}
#define HL_CONTAINED 0x01 /* not used on toplevel */
#define HL_TRANSP 0x02 /* has no highlighting */
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 7bcaff662c..b812dd2ffd 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -674,7 +674,7 @@ do_tag (
fname = xmalloc(MAXPATHL + 1);
cmd = xmalloc(CMDBUFFSIZE + 1);
- list = list_alloc();
+ list = tv_list_alloc();
for (i = 0; i < num_matches; ++i) {
int len, cmd_len;
@@ -773,20 +773,21 @@ do_tag (
cmd[len] = NUL;
}
- dict = dict_alloc();
- list_append_dict(list, dict);
+ dict = tv_dict_alloc();
+ tv_list_append_dict(list, dict);
- dict_add_nr_str(dict, "text", 0L, tag_name);
- dict_add_nr_str(dict, "filename", 0L, fname);
- dict_add_nr_str(dict, "lnum", lnum, NULL);
- if (lnum == 0)
- dict_add_nr_str(dict, "pattern", 0L, cmd);
+ tv_dict_add_str(dict, S_LEN("text"), (const char *)tag_name);
+ tv_dict_add_str(dict, S_LEN("filename"), (const char *)fname);
+ tv_dict_add_nr(dict, S_LEN("lnum"), lnum);
+ if (lnum == 0) {
+ tv_dict_add_str(dict, S_LEN("pattern"), (const char *)cmd);
+ }
}
vim_snprintf((char *)IObuff, IOSIZE, "ltag %s", tag);
set_errorlist(curwin, list, ' ', IObuff, NULL);
- list_free(list);
+ tv_list_free(list);
xfree(fname);
xfree(cmd);
@@ -2203,7 +2204,7 @@ parse_tag_line (
* Return TRUE if it is a static tag and adjust *tagname to the real tag.
* Return FALSE if it is not a static tag.
*/
-static int test_for_static(tagptrs_T *tagp)
+static bool test_for_static(tagptrs_T *tagp)
{
char_u *p;
@@ -2768,8 +2769,8 @@ add_tag_field (
int len = 0;
int retval;
- /* check that the field name doesn't exist yet */
- if (dict_find(dict, (char_u *)field_name, -1) != NULL) {
+ // Check that the field name doesn't exist yet.
+ if (tv_dict_find(dict, field_name, -1) != NULL) {
if (p_verbose > 0) {
verbose_enter();
smsg(_("Duplicate field name: %s"), field_name);
@@ -2790,7 +2791,8 @@ add_tag_field (
STRLCPY(buf, start, len + 1);
}
buf[len] = NUL;
- retval = dict_add_nr_str(dict, field_name, 0L, buf);
+ retval = tv_dict_add_str(dict, field_name, STRLEN(field_name),
+ (const char *)buf);
xfree(buf);
return retval;
}
@@ -2806,7 +2808,7 @@ int get_tags(list_T *list, char_u *pat)
char_u *full_fname;
dict_T *dict;
tagptrs_T tp;
- long is_static;
+ bool is_static;
ret = find_tags(pat, &num_matches, &matches,
TAG_REGEXP | TAG_NOIC, (int)MAXCOL, NULL);
@@ -2824,19 +2826,18 @@ int get_tags(list_T *list, char_u *pat)
if (STRNCMP(tp.tagname, "!_TAG_", 6) == 0)
continue;
- dict = dict_alloc();
- list_append_dict(list, dict);
+ dict = tv_dict_alloc();
+ tv_list_append_dict(list, dict);
full_fname = tag_full_fname(&tp);
if (add_tag_field(dict, "name", tp.tagname, tp.tagname_end) == FAIL
- || add_tag_field(dict, "filename", full_fname,
- NULL) == FAIL
- || add_tag_field(dict, "cmd", tp.command,
- tp.command_end) == FAIL
+ || add_tag_field(dict, "filename", full_fname, NULL) == FAIL
+ || add_tag_field(dict, "cmd", tp.command, tp.command_end) == FAIL
|| add_tag_field(dict, "kind", tp.tagkind,
- tp.tagkind ? tp.tagkind_end : NULL) == FAIL
- || dict_add_nr_str(dict, "static", is_static, NULL) == FAIL)
+ tp.tagkind ? tp.tagkind_end : NULL) == FAIL
+ || tv_dict_add_nr(dict, S_LEN("static"), is_static) == FAIL) {
ret = FAIL;
+ }
xfree(full_fname);
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 87ee8f410f..85c4950b42 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -85,8 +85,6 @@ typedef struct terminal_state {
# include "terminal.c.generated.h"
#endif
-#define SB_MAX 100000 // Maximum 'scrollback' value.
-
// Delay for refreshing the terminal buffer after receiving updates from
// libvterm. Improves performance when receiving large bursts of data.
#define REFRESH_DELAY 10
@@ -228,17 +226,17 @@ Terminal *terminal_open(TerminalOptions opts)
rv->invalid_start = 0;
rv->invalid_end = opts.height;
refresh_screen(rv, curbuf);
- set_option_value((uint8_t *)"buftype", 0, (uint8_t *)"terminal", OPT_LOCAL);
+ set_option_value("buftype", 0, "terminal", OPT_LOCAL);
// Default settings for terminal buffers
- curbuf->b_p_ma = false; // 'nomodifiable'
- curbuf->b_p_ul = -1; // 'undolevels'
- curbuf->b_p_scbk = 1000; // 'scrollback'
- curbuf->b_p_tw = 0; // 'textwidth'
- set_option_value((uint8_t *)"wrap", false, NULL, OPT_LOCAL);
- set_option_value((uint8_t *)"number", false, NULL, OPT_LOCAL);
- set_option_value((uint8_t *)"relativenumber", false, NULL, OPT_LOCAL);
- set_option_value((uint8_t *)"list", false, NULL, OPT_LOCAL);
+ curbuf->b_p_ma = false; // 'nomodifiable'
+ curbuf->b_p_ul = -1; // 'undolevels'
+ curbuf->b_p_scbk = p_scbk; // 'scrollback'
+ curbuf->b_p_tw = 0; // 'textwidth'
+ set_option_value("wrap", false, NULL, OPT_LOCAL);
+ set_option_value("number", false, NULL, OPT_LOCAL);
+ set_option_value("relativenumber", false, NULL, OPT_LOCAL);
+ set_option_value("list", false, NULL, OPT_LOCAL);
buf_set_term_title(curbuf, (char *)curbuf->b_ffname);
RESET_BINDING(curwin);
// Reset cursor in current window.
@@ -248,7 +246,8 @@ Terminal *terminal_open(TerminalOptions opts)
apply_autocmds(EVENT_TERMOPEN, NULL, NULL, false, curbuf);
// Configure the scrollback buffer.
- rv->sb_size = curbuf->b_p_scbk < 0 ? SB_MAX : (size_t)curbuf->b_p_scbk;;
+ rv->sb_size = curbuf->b_p_scbk < 0
+ ? SB_MAX : (size_t)MAX(1, curbuf->b_p_scbk);
rv->sb_buffer = xmalloc(sizeof(ScrollbackLine *) * rv->sb_size);
if (!true_color) {
@@ -1156,7 +1155,6 @@ static void redraw(bool restore_cursor)
save_col = ui_current_col();
}
block_autocmds();
- validate_cursor();
if (must_redraw) {
update_screen(0);
@@ -1173,7 +1171,7 @@ static void redraw(bool restore_cursor)
int off = is_focused(term) ? 0 : (curwin->w_p_rl ? 1 : -1);
curwin->w_cursor.col = MAX(0, term->cursor.col + win_col_off(curwin) + off);
curwin->w_cursor.coladd = 0;
- setcursor();
+ mb_check_adjust_col(curwin);
}
unblock_autocmds();
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 531a07912f..70a9f2b8c4 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -30,6 +30,7 @@ SCRIPTS ?= \
NEW_TESTS ?= \
test_autocmd.res \
test_bufwintabinfo.res \
+ test_charsearch.res \
test_cmdline.res \
test_command_count.res \
test_cscope.res \
@@ -37,12 +38,15 @@ NEW_TESTS ?= \
test_diffmode.res \
test_farsi.res \
test_filter_map.res \
+ test_fnameescape.res \
test_fold.res \
test_glob2regpat.res \
+ test_gf.res \
test_gn.res \
test_hardcopy.res \
test_help_tagjump.res \
test_history.res \
+ test_hlsearch.res \
test_increment.res \
test_increment_dbcs.res \
test_lambda.res \
@@ -55,6 +59,8 @@ NEW_TESTS ?= \
test_normal.res \
test_quickfix.res \
test_signs.res \
+ test_smartindent.res \
+ test_substitute.res \
test_syntax.res \
test_tabpage.res \
test_textobjects.res \
diff --git a/src/nvim/testdir/test_charsearch.vim b/src/nvim/testdir/test_charsearch.vim
new file mode 100644
index 0000000000..8b313b5a35
--- /dev/null
+++ b/src/nvim/testdir/test_charsearch.vim
@@ -0,0 +1,62 @@
+
+function! Test_charsearch()
+ enew!
+ call append(0, ['Xabcdefghijkemnopqretuvwxyz',
+ \ 'Yabcdefghijkemnopqretuvwxyz',
+ \ 'Zabcdefghijkemnokqretkvwxyz'])
+ " check that "fe" and ";" work
+ 1
+ normal! ylfep;;p,,p
+ call assert_equal('XabcdeXfghijkeXmnopqreXtuvwxyz', getline(1))
+ " check that save/restore works
+ 2
+ normal! ylfep
+ let csave = getcharsearch()
+ normal! fip
+ call setcharsearch(csave)
+ normal! ;p;p
+ call assert_equal('YabcdeYfghiYjkeYmnopqreYtuvwxyz', getline(2))
+
+ " check that setcharsearch() changes the settings.
+ 3
+ normal! ylfep
+ call setcharsearch({'char': 'k'})
+ normal! ;p
+ call setcharsearch({'forward': 0})
+ normal! $;p
+ call setcharsearch({'until': 1})
+ set cpo-=;
+ normal! ;;p
+ call assert_equal('ZabcdeZfghijkZZemnokqretkZvwxyz', getline(3))
+ enew!
+endfunction
+
+" Test for t,f,F,T movement commands and 'cpo-;' setting
+function! Test_search_cmds()
+ enew!
+ call append(0, ["aaa two three four", " zzz", "yyy ",
+ \ "bbb yee yoo four", "ccc two three four",
+ \ "ddd yee yoo four"])
+ set cpo-=;
+ 1
+ normal! 0tt;D
+ 2
+ normal! 0fz;D
+ 3
+ normal! $Fy;D
+ 4
+ normal! $Ty;D
+ set cpo+=;
+ 5
+ normal! 0tt;;D
+ 6
+ normal! $Ty;;D
+
+ call assert_equal('aaa two', getline(1))
+ call assert_equal(' z', getline(2))
+ call assert_equal('y', getline(3))
+ call assert_equal('bbb y', getline(4))
+ call assert_equal('ccc', getline(5))
+ call assert_equal('ddd yee y', getline(6))
+ enew!
+endfunction
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 40db227d97..0c9d1297d6 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -156,6 +156,20 @@ func Test_getcompletion()
call assert_equal(['Testing'], l)
endif
+ " Command line completion tests
+ let l = getcompletion('cd ', 'cmdline')
+ call assert_true(index(l, 'sautest/') >= 0)
+ let l = getcompletion('cd NoMatch', 'cmdline')
+ call assert_equal([], l)
+ let l = getcompletion('let v:n', 'cmdline')
+ call assert_true(index(l, 'v:null') >= 0)
+ let l = getcompletion('let v:notexists', 'cmdline')
+ call assert_equal([], l)
+ let l = getcompletion('call tag', 'cmdline')
+ call assert_true(index(l, 'taglist(') >= 0)
+ let l = getcompletion('call paint', 'cmdline')
+ call assert_equal([], l)
+
" For others test if the name is recognized.
let names = ['buffer', 'environment', 'file_in_path',
\ 'mapping', 'shellcmd', 'tag', 'tag_listfiles', 'user']
@@ -187,5 +201,6 @@ func Test_expand_star_star()
call writefile(['asdfasdf'], 'a/b/fileXname')
call feedkeys(":find **/fileXname\<Tab>\<CR>", 'xt')
call assert_equal('find a/b/fileXname', getreg(':'))
+ bwipe!
call delete('a', 'rf')
endfunc
diff --git a/src/nvim/testdir/test_fnameescape.vim b/src/nvim/testdir/test_fnameescape.vim
new file mode 100644
index 0000000000..cdff0dfbd9
--- /dev/null
+++ b/src/nvim/testdir/test_fnameescape.vim
@@ -0,0 +1,21 @@
+
+" Test if fnameescape is correct for special chars like !
+function! Test_fnameescape()
+ let fname = 'Xspa ce'
+ let status = v:false
+ try
+ exe "w! " . fnameescape(fname)
+ let status = v:true
+ endtry
+ call assert_true(status, "Space")
+ call delete(fname)
+
+ let fname = 'Xemark!'
+ let status = v:false
+ try
+ exe "w! " . fnameescape(fname)
+ let status = v:true
+ endtry
+ call assert_true(status, "ExclamationMark")
+ call delete(fname)
+endfunction
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index 976c6b5cd1..46c54e8614 100644
--- a/src/nvim/testdir/test_fold.vim
+++ b/src/nvim/testdir/test_fold.vim
@@ -100,22 +100,6 @@ func! Test_indent_fold2()
bw!
endfunc
-func Test_folds_marker_in_comment()
- new
- call setline(1, ['" foo', 'bar', 'baz'])
- setl fen fdm=marker
- setl com=sO:\"\ -,mO:\"\ \ ,eO:\"\",:\" cms=\"%s
- norm! zf2j
- setl nofen
- :1y
- call assert_equal(['" foo{{{'], getreg(0,1,1))
- :+2y
- call assert_equal(['baz"}}}'], getreg(0,1,1))
-
- set foldmethod&
- bwipe!
-endfunc
-
func Test_manual_fold_with_filter()
if !executable('cat')
return
@@ -138,6 +122,108 @@ func Test_manual_fold_with_filter()
endfor
endfunc
+func! Test_indent_fold_with_read()
+ new
+ set foldmethod=indent
+ call setline(1, repeat(["\<Tab>a"], 4))
+ for n in range(1, 4)
+ call assert_equal(1, foldlevel(n))
+ endfor
+
+ call writefile(["a", "", "\<Tab>a"], 'Xfile')
+ foldopen
+ 2read Xfile
+ %foldclose
+ call assert_equal(1, foldlevel(1))
+ call assert_equal(2, foldclosedend(1))
+ call assert_equal(0, foldlevel(3))
+ call assert_equal(0, foldlevel(4))
+ call assert_equal(1, foldlevel(5))
+ call assert_equal(7, foldclosedend(5))
+
+ bwipe!
+ set foldmethod&
+ call delete('Xfile')
+endfunc
+
+func Test_combining_folds_indent()
+ new
+ let one = "\<Tab>a"
+ let zero = 'a'
+ call setline(1, [one, one, zero, zero, zero, one, one, one])
+ set foldmethod=indent
+ 3,5d
+ %foldclose
+ call assert_equal(5, foldclosedend(1))
+
+ set foldmethod&
+ bwipe!
+endfunc
+
+func Test_combining_folds_marker()
+ new
+ call setline(1, ['{{{', '}}}', '', '', '', '{{{', '', '}}}'])
+ set foldmethod=marker
+ 3,5d
+ %foldclose
+ call assert_equal(2, foldclosedend(1))
+
+ set foldmethod&
+ bwipe!
+endfunc
+
+func Test_folds_marker_in_comment()
+ new
+ call setline(1, ['" foo', 'bar', 'baz'])
+ setl fen fdm=marker
+ setl com=sO:\"\ -,mO:\"\ \ ,eO:\"\",:\" cms=\"%s
+ norm! zf2j
+ setl nofen
+ :1y
+ call assert_equal(['" foo{{{'], getreg(0,1,1))
+ :+2y
+ call assert_equal(['baz"}}}'], getreg(0,1,1))
+
+ set foldmethod&
+ bwipe!
+endfunc
+
+func s:TestFoldExpr(lnum)
+ let thisline = getline(a:lnum)
+ if thisline == 'a'
+ return 1
+ elseif thisline == 'b'
+ return 0
+ elseif thisline == 'c'
+ return '<1'
+ elseif thisline == 'd'
+ return '>1'
+ endif
+ return 0
+endfunction
+
+func Test_update_folds_expr_read()
+ new
+ call setline(1, ['a', 'a', 'a', 'a', 'a', 'a'])
+ set foldmethod=expr
+ set foldexpr=s:TestFoldExpr(v:lnum)
+ 2
+ foldopen
+ call writefile(['b', 'b', 'a', 'a', 'd', 'a', 'a', 'c'], 'Xfile')
+ read Xfile
+ %foldclose
+ call assert_equal(2, foldclosedend(1))
+ call assert_equal(0, foldlevel(3))
+ call assert_equal(0, foldlevel(4))
+ call assert_equal(6, foldclosedend(5))
+ call assert_equal(10, foldclosedend(7))
+ call assert_equal(14, foldclosedend(11))
+
+ call delete('Xfile')
+ bwipe!
+ set foldmethod& foldexpr&
+endfunc
+
func! Test_move_folds_around_manual()
new
let input = PrepIndent("a") + PrepIndent("b") + PrepIndent("c")
diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim
new file mode 100644
index 0000000000..c4aa6f9218
--- /dev/null
+++ b/src/nvim/testdir/test_gf.vim
@@ -0,0 +1,33 @@
+
+" This is a test if a URL is recognized by "gf", with the cursor before and
+" after the "://". Also test ":\\".
+function! Test_gf_url()
+ enew!
+ call append(0, [
+ \ "first test for URL://machine.name/tmp/vimtest2a and other text",
+ \ "second test for URL://machine.name/tmp/vimtest2b. And other text",
+ \ "third test for URL:\\\\machine.name\\vimtest2c and other text",
+ \ "fourth test for URL:\\\\machine.name\\tmp\\vimtest2d, and other text"
+ \ ])
+ call cursor(1,1)
+ call search("^first")
+ call search("tmp")
+ call assert_equal("URL://machine.name/tmp/vimtest2a", expand("<cfile>"))
+ call search("^second")
+ call search("URL")
+ call assert_equal("URL://machine.name/tmp/vimtest2b", expand("<cfile>"))
+ if has("ebcdic")
+ set isf=@,240-249,/,.,-,_,+,,,$,:,~,\
+ else
+ set isf=@,48-57,/,.,-,_,+,,,$,:,~,\
+ endif
+ call search("^third")
+ call search("name")
+ call assert_equal("URL:\\\\machine.name\\vimtest2c", expand("<cfile>"))
+ call search("^fourth")
+ call search("URL")
+ call assert_equal("URL:\\\\machine.name\\tmp\\vimtest2d", expand("<cfile>"))
+
+ set isf&vim
+ enew!
+endfunction
diff --git a/src/nvim/testdir/test_hlsearch.vim b/src/nvim/testdir/test_hlsearch.vim
new file mode 100644
index 0000000000..066fdd0250
--- /dev/null
+++ b/src/nvim/testdir/test_hlsearch.vim
@@ -0,0 +1,34 @@
+" Test for v:hlsearch
+
+function! Test_hlsearch()
+ new
+ call setline(1, repeat(['aaa'], 10))
+ set hlsearch nolazyredraw
+ let r=[]
+ " redraw is needed to make hlsearch highlight the matches
+ exe "normal! /aaa\<CR>" | redraw
+ let r1 = screenattr(1, 1)
+ nohlsearch | redraw
+ call assert_notequal(r1, screenattr(1,1))
+ let v:hlsearch=1 | redraw
+ call assert_equal(r1, screenattr(1,1))
+ let v:hlsearch=0 | redraw
+ call assert_notequal(r1, screenattr(1,1))
+ set hlsearch | redraw
+ call assert_equal(r1, screenattr(1,1))
+ let v:hlsearch=0 | redraw
+ call assert_notequal(r1, screenattr(1,1))
+ exe "normal! n" | redraw
+ call assert_equal(r1, screenattr(1,1))
+ let v:hlsearch=0 | redraw
+ call assert_notequal(r1, screenattr(1,1))
+ exe "normal! /\<CR>" | redraw
+ call assert_equal(r1, screenattr(1,1))
+ set nohls
+ exe "normal! /\<CR>" | redraw
+ call assert_notequal(r1, screenattr(1,1))
+ call assert_fails('let v:hlsearch=[]', 'E745')
+ call garbagecollect(1)
+ call getchar(1)
+ enew!
+endfunction
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
index d937565ce5..6b313ff54f 100644
--- a/src/nvim/testdir/test_mapping.vim
+++ b/src/nvim/testdir/test_mapping.vim
@@ -35,29 +35,81 @@ func Test_map_ctrl_c_visual()
endfunc
func Test_map_langmap()
- " langmap should not get remapped in insert mode
- inoremap { FAIL_ilangmap
- set langmap=+{ langnoremap
+ if !has('langmap')
+ return
+ endif
+
+ " check langmap applies in normal mode
+ set langmap=+- nolangremap
+ new
+ call setline(1, ['a', 'b', 'c'])
+ 2
+ call assert_equal('b', getline('.'))
+ call feedkeys("+", "xt")
+ call assert_equal('a', getline('.'))
+
+ " check no remapping
+ map x +
+ 2
+ call feedkeys("x", "xt")
+ call assert_equal('c', getline('.'))
+
+ " check with remapping
+ set langremap
+ 2
+ call feedkeys("x", "xt")
+ call assert_equal('a', getline('.'))
+
+ unmap x
+ bwipe!
+
+ " 'langnoremap' follows 'langremap' and vise versa
+ set langremap
+ set langnoremap
+ call assert_equal(0, &langremap)
+ set langremap
+ call assert_equal(0, &langnoremap)
+ set nolangremap
+ call assert_equal(1, &langnoremap)
+
+ " check default values
+ set langnoremap&
+ call assert_equal(1, &langnoremap)
+ call assert_equal(0, &langremap)
+ set langremap&
+ call assert_equal(1, &langnoremap)
+ call assert_equal(0, &langremap)
+
+ " langmap should not apply in insert mode, 'langremap' doesn't matter
+ set langmap=+{ nolangremap
call feedkeys("Go+\<Esc>", "xt")
call assert_equal('+', getline('$'))
-
- " Insert-mode expr mapping with langmap
- inoremap <expr> { "FAIL_iexplangmap"
+ set langmap=+{ langremap
call feedkeys("Go+\<Esc>", "xt")
call assert_equal('+', getline('$'))
- iunmap <expr> {
- " langmap should not get remapped in Command-line mode
- cnoremap { FAIL_clangmap
+ " langmap used for register name in insert mode.
+ call setreg('a', 'aaaa')
+ call setreg('b', 'bbbb')
+ call setreg('c', 'cccc')
+ set langmap=ab langremap
+ call feedkeys("Go\<C-R>a\<Esc>", "xt")
+ call assert_equal('bbbb', getline('$'))
+ call feedkeys("Go\<C-R>\<C-R>a\<Esc>", "xt")
+ call assert_equal('bbbb', getline('$'))
+ " mapping does not apply
+ imap c a
+ call feedkeys("Go\<C-R>c\<Esc>", "xt")
+ call assert_equal('cccc', getline('$'))
+ imap a c
+ call feedkeys("Go\<C-R>a\<Esc>", "xt")
+ call assert_equal('bbbb', getline('$'))
+
+ " langmap should not apply in Command-line mode
+ set langmap=+{ nolangremap
call feedkeys(":call append(line('$'), '+')\<CR>", "xt")
call assert_equal('+', getline('$'))
- cunmap {
- " Command-line mode expr mapping with langmap
- cnoremap <expr> { "FAIL_cexplangmap"
- call feedkeys(":call append(line('$'), '+')\<CR>", "xt")
- call assert_equal('+', getline('$'))
- cunmap {
set nomodified
endfunc
diff --git a/src/nvim/testdir/test_smartindent.vim b/src/nvim/testdir/test_smartindent.vim
new file mode 100644
index 0000000000..d00eac9798
--- /dev/null
+++ b/src/nvim/testdir/test_smartindent.vim
@@ -0,0 +1,14 @@
+
+" Tests for not doing smart indenting when it isn't set.
+function! Test_nosmartindent()
+ new
+ call append(0, [" some test text",
+ \ " test text",
+ \ "test text",
+ \ " test text"])
+ set nocindent nosmartindent autoindent
+ exe "normal! gg/some\<CR>"
+ exe "normal! 2cc#test\<Esc>"
+ call assert_equal(" #test", getline(1))
+ enew! | close
+endfunction
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
new file mode 100644
index 0000000000..e2b6de03c3
--- /dev/null
+++ b/src/nvim/testdir/test_substitute.vim
@@ -0,0 +1,41 @@
+" Tests for multi-line regexps with ":s".
+
+function! Test_multiline_subst()
+ enew!
+ call append(0, ["1 aa",
+ \ "bb",
+ \ "cc",
+ \ "2 dd",
+ \ "ee",
+ \ "3 ef",
+ \ "gh",
+ \ "4 ij",
+ \ "5 a8",
+ \ "8b c9",
+ \ "9d",
+ \ "6 e7",
+ \ "77f",
+ \ "xxxxx"])
+
+ 1
+ " test if replacing a line break works with a back reference
+ /^1/,/^2/s/\n\(.\)/ \1/
+ " test if inserting a line break works with a back reference
+ /^3/,/^4/s/\(.\)$/\r\1/
+ " test if replacing a line break with another line break works
+ /^5/,/^6/s/\(\_d\{3}\)/x\1x/
+ call assert_equal('1 aa bb cc 2 dd ee', getline(1))
+ call assert_equal('3 e', getline(2))
+ call assert_equal('f', getline(3))
+ call assert_equal('g', getline(4))
+ call assert_equal('h', getline(5))
+ call assert_equal('4 i', getline(6))
+ call assert_equal('j', getline(7))
+ call assert_equal('5 ax8', getline(8))
+ call assert_equal('8xb cx9', getline(9))
+ call assert_equal('9xd', getline(10))
+ call assert_equal('6 ex7', getline(11))
+ call assert_equal('7x7f', getline(12))
+ call assert_equal('xxxxx', getline(13))
+ enew!
+endfunction
diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim
index 2044c23f79..0d697b3f3e 100644
--- a/src/nvim/testdir/test_tagjump.vim
+++ b/src/nvim/testdir/test_tagjump.vim
@@ -65,4 +65,34 @@ func Test_duplicate_tagjump()
call delete('Xfile1')
endfunc
+" Tests for [ CTRL-I and CTRL-W CTRL-I commands
+function Test_keyword_jump()
+ call writefile(["#include Xinclude", "",
+ \ "",
+ \ "/* test text test tex start here",
+ \ " some text",
+ \ " test text",
+ \ " start OK if found this line",
+ \ " start found wrong line",
+ \ "test text"], 'Xtestfile')
+ call writefile(["/* test text test tex start here",
+ \ " some text",
+ \ " test text",
+ \ " start OK if found this line",
+ \ " start found wrong line",
+ \ "test text"], 'Xinclude')
+ new Xtestfile
+ call cursor(1,1)
+ call search("start")
+ exe "normal! 5[\<C-I>"
+ call assert_equal(" start OK if found this line", getline('.'))
+ call cursor(1,1)
+ call search("start")
+ exe "normal! 5\<C-W>\<C-I>"
+ call assert_equal(" start OK if found this line", getline('.'))
+ enew! | only
+ call delete('Xtestfile')
+ call delete('Xinclude')
+endfunction
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 9fbbe8be92..f34f5f1bc4 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -31,6 +31,8 @@
#include "nvim/ugrid.h"
#include "nvim/tui/input.h"
#include "nvim/tui/tui.h"
+#include "nvim/cursor_shape.h"
+#include "nvim/syntax.h"
// Space reserved in the output buffer to restore the cursor to normal when
// flushing. No existing terminal will require 32 bytes to do that.
@@ -69,18 +71,20 @@ typedef struct {
bool can_use_terminal_scroll;
bool mouse_enabled;
bool busy;
+ cursorentry_T cursor_shapes[SHAPE_IDX_COUNT];
HlAttrs print_attrs;
int showing_mode;
struct {
int enable_mouse, disable_mouse;
int enable_bracketed_paste, disable_bracketed_paste;
- int set_cursor_shape_bar, set_cursor_shape_ul, set_cursor_shape_block;
int set_rgb_foreground, set_rgb_background;
+ int set_cursor_color;
int enable_focus_reporting, disable_focus_reporting;
} unibi_ext;
} TUIData;
static bool volatile got_winch = false;
+static bool cursor_style_enabled = false;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/tui.c.generated.h"
@@ -97,6 +101,7 @@ UI *tui_start(void)
ui->clear = tui_clear;
ui->eol_clear = tui_eol_clear;
ui->cursor_goto = tui_cursor_goto;
+ ui->cursor_style_set = tui_cursor_style_set;
ui->update_menu = tui_update_menu;
ui->busy_start = tui_busy_start;
ui->busy_stop = tui_busy_stop;
@@ -129,11 +134,9 @@ static void terminfo_start(UI *ui)
data->showing_mode = 0;
data->unibi_ext.enable_mouse = -1;
data->unibi_ext.disable_mouse = -1;
+ data->unibi_ext.set_cursor_color = -1;
data->unibi_ext.enable_bracketed_paste = -1;
data->unibi_ext.disable_bracketed_paste = -1;
- data->unibi_ext.set_cursor_shape_bar = -1;
- data->unibi_ext.set_cursor_shape_ul = -1;
- data->unibi_ext.set_cursor_shape_block = -1;
data->unibi_ext.enable_focus_reporting = -1;
data->unibi_ext.disable_focus_reporting = -1;
data->out_fd = 1;
@@ -146,11 +149,10 @@ static void terminfo_start(UI *ui)
data->ut = unibi_dummy();
}
fix_terminfo(data);
- // Initialize the cursor shape.
- unibi_out(ui, data->unibi_ext.set_cursor_shape_block);
// Set 't_Co' from the result of unibilium & fix_terminfo.
t_colors = unibi_get_num(data->ut, unibi_max_colors);
// Enter alternate screen and clear
+ // NOTE: Do this *before* changing terminal settings. #6433
unibi_out(ui, unibi_enter_ca_mode);
unibi_out(ui, unibi_clear_screen);
// Enable bracketed paste
@@ -434,6 +436,65 @@ static void tui_cursor_goto(UI *ui, int row, int col)
unibi_goto(ui, row, col);
}
+CursorShape tui_cursor_decode_shape(const char *shape_str)
+{
+ CursorShape shape = 0;
+ if (strequal(shape_str, "block")) {
+ shape = SHAPE_BLOCK;
+ } else if (strequal(shape_str, "vertical")) {
+ shape = SHAPE_VER;
+ } else if (strequal(shape_str, "horizontal")) {
+ shape = SHAPE_HOR;
+ } else {
+ EMSG2(_(e_invarg2), shape_str);
+ }
+ return shape;
+}
+
+static cursorentry_T decode_cursor_entry(Dictionary args)
+{
+ cursorentry_T r;
+
+ for (size_t i = 0; i < args.size; i++) {
+ char *key = args.items[i].key.data;
+ Object value = args.items[i].value;
+
+ if (strequal(key, "cursor_shape")) {
+ r.shape = tui_cursor_decode_shape(args.items[i].value.data.string.data);
+ } else if (strequal(key, "blinkon")) {
+ r.blinkon = (int)value.data.integer;
+ } else if (strequal(key, "blinkoff")) {
+ r.blinkoff = (int)value.data.integer;
+ } else if (strequal(key, "hl_id")) {
+ r.id = (int)value.data.integer;
+ }
+ }
+ return r;
+}
+
+static void tui_cursor_style_set(UI *ui, bool enabled, Dictionary args)
+{
+ cursor_style_enabled = enabled;
+ if (!enabled) {
+ return; // Do not send cursor style control codes.
+ }
+ TUIData *data = ui->data;
+
+ assert(args.size);
+ // Keys: as defined by `shape_table`.
+ for (size_t i = 0; i < args.size; i++) {
+ char *mode_name = args.items[i].key.data;
+ const int mode_id = cursor_mode_str2int(mode_name);
+ assert(mode_id >= 0);
+ cursorentry_T r = decode_cursor_entry(args.items[i].value.data.dictionary);
+ r.full_name = mode_name;
+ data->cursor_shapes[mode_id] = r;
+ }
+
+ MouseMode cursor_mode = tui_mode2cursor(data->showing_mode);
+ tui_set_cursor(ui, cursor_mode);
+}
+
static void tui_update_menu(UI *ui)
{
// Do nothing; menus are for GUI only
@@ -452,44 +513,117 @@ static void tui_busy_stop(UI *ui)
static void tui_mouse_on(UI *ui)
{
TUIData *data = ui->data;
- unibi_out(ui, data->unibi_ext.enable_mouse);
- data->mouse_enabled = true;
+ if (!data->mouse_enabled) {
+ unibi_out(ui, data->unibi_ext.enable_mouse);
+ data->mouse_enabled = true;
+ }
}
static void tui_mouse_off(UI *ui)
{
TUIData *data = ui->data;
- unibi_out(ui, data->unibi_ext.disable_mouse);
- data->mouse_enabled = false;
+ if (data->mouse_enabled) {
+ unibi_out(ui, data->unibi_ext.disable_mouse);
+ data->mouse_enabled = false;
+ }
+}
+
+/// @param mode one of SHAPE_XXX
+static void tui_set_cursor(UI *ui, MouseMode mode)
+{
+ if (!cursor_style_enabled) {
+ return;
+ }
+ TUIData *data = ui->data;
+ cursorentry_T c = data->cursor_shapes[mode];
+ int shape = c.shape;
+ bool inside_tmux = os_getenv("TMUX") != NULL;
+ unibi_var_t vars[26 + 26] = { { 0 } };
+
+# define TMUX_WRAP(seq) (inside_tmux ? "\x1bPtmux;\x1b" seq "\x1b\\" : seq)
+ // Support changing cursor shape on some popular terminals.
+ const char *vte_version = os_getenv("VTE_VERSION");
+
+ if (os_getenv("KONSOLE_PROFILE_NAME") || os_getenv("KONSOLE_DBUS_SESSION")) {
+ // Konsole uses a proprietary escape code to set the cursor shape
+ // and does not support DECSCUSR.
+ switch (shape) {
+ case SHAPE_BLOCK: shape = 0; break;
+ case SHAPE_VER: shape = 1; break;
+ case SHAPE_HOR: shape = 2; break;
+ default: WLOG("Unknown shape value %d", shape); break;
+ }
+ data->params[0].i = shape;
+ data->params[1].i = (c.blinkon == 0);
+
+ unibi_format(vars, vars + 26,
+ TMUX_WRAP("\x1b]50;CursorShape=%p1%d;BlinkingCursorEnabled=%p2%d\x07"),
+ data->params, out, ui, NULL, NULL);
+ } else if (!vte_version || atoi(vte_version) >= 3900) {
+ // Assume that the terminal supports DECSCUSR unless it is an
+ // old VTE based terminal. This should not get wrapped for tmux,
+ // which will handle it via its Ss/Se terminfo extension - usually
+ // according to its terminal-overrides.
+
+ switch (shape) {
+ case SHAPE_BLOCK: shape = 1; break;
+ case SHAPE_VER: shape = 5; break;
+ case SHAPE_HOR: shape = 3; break;
+ default: WLOG("Unknown shape value %d", shape); break;
+ }
+ data->params[0].i = shape + (c.blinkon ==0);
+ unibi_format(vars, vars + 26, "\x1b[%p1%d q",
+ data->params, out, ui, NULL, NULL);
+ }
+
+ if (c.id != 0 && ui->rgb) {
+ int attr = syn_id2attr(c.id);
+ attrentry_T *aep = syn_cterm_attr2entry(attr);
+ data->params[0].i = aep->rgb_bg_color;
+ unibi_out(ui, data->unibi_ext.set_cursor_color);
+ }
+}
+
+/// Returns cursor mode from edit mode
+static MouseMode tui_mode2cursor(int mode)
+{
+ switch (mode) {
+ case INSERT: return SHAPE_IDX_I;
+ case CMDLINE: return SHAPE_IDX_C;
+ case REPLACE: return SHAPE_IDX_R;
+ case NORMAL:
+ default: return SHAPE_IDX_N;
+ }
}
+/// @param mode editor mode
static void tui_mode_change(UI *ui, int mode)
{
TUIData *data = ui->data;
if (mode == INSERT) {
if (data->showing_mode != INSERT) {
- unibi_out(ui, data->unibi_ext.set_cursor_shape_bar);
+ tui_set_cursor(ui, SHAPE_IDX_I);
}
} else if (mode == CMDLINE) {
if (data->showing_mode != CMDLINE) {
- unibi_out(ui, data->unibi_ext.set_cursor_shape_bar);
+ tui_set_cursor(ui, SHAPE_IDX_C);
}
} else if (mode == REPLACE) {
if (data->showing_mode != REPLACE) {
- unibi_out(ui, data->unibi_ext.set_cursor_shape_ul);
+ tui_set_cursor(ui, SHAPE_IDX_R);
}
} else {
assert(mode == NORMAL);
if (data->showing_mode != NORMAL) {
- unibi_out(ui, data->unibi_ext.set_cursor_shape_block);
+ tui_set_cursor(ui, SHAPE_IDX_N);
}
}
data->showing_mode = mode;
}
static void tui_set_scroll_region(UI *ui, int top, int bot, int left,
- int right)
+ int right)
{
TUIData *data = ui->data;
ugrid_set_scroll_region(&data->grid, top, bot, left, right);
@@ -827,8 +961,6 @@ static void fix_terminfo(TUIData *data)
goto end;
}
- bool inside_tmux = os_getenv("TMUX") != NULL;
-
#define STARTS_WITH(str, prefix) (!memcmp(str, prefix, sizeof(prefix) - 1))
if (STARTS_WITH(term, "rxvt")) {
@@ -886,42 +1018,10 @@ static void fix_terminfo(TUIData *data)
unibi_set_str(ut, unibi_set_a_background, XTERM_SETAB);
}
- const char * env_cusr_shape = os_getenv("NVIM_TUI_ENABLE_CURSOR_SHAPE");
- if (env_cusr_shape && strncmp(env_cusr_shape, "0", 1) == 0) {
- goto end;
- }
- bool cusr_blink = env_cusr_shape && strncmp(env_cusr_shape, "2", 1) == 0;
-
-#define TMUX_WRAP(seq) (inside_tmux ? "\x1bPtmux;\x1b" seq "\x1b\\" : seq)
- // Support changing cursor shape on some popular terminals.
- const char *term_prog = os_getenv("TERM_PROGRAM");
- const char *vte_version = os_getenv("VTE_VERSION");
-
- if ((term_prog && !strcmp(term_prog, "Konsole"))
- || os_getenv("KONSOLE_DBUS_SESSION") != NULL) {
- // Konsole uses a proprietary escape code to set the cursor shape
- // and does not support DECSCUSR.
- data->unibi_ext.set_cursor_shape_bar = (int)unibi_add_ext_str(ut, NULL,
- TMUX_WRAP("\x1b]50;CursorShape=1\x07"));
- data->unibi_ext.set_cursor_shape_ul = (int)unibi_add_ext_str(ut, NULL,
- TMUX_WRAP("\x1b]50;CursorShape=2\x07"));
- data->unibi_ext.set_cursor_shape_block = (int)unibi_add_ext_str(ut, NULL,
- TMUX_WRAP("\x1b]50;CursorShape=0\x07"));
- } else if (!vte_version || atoi(vte_version) >= 3900) {
- // Assume that the terminal supports DECSCUSR unless it is an
- // old VTE based terminal. This should not get wrapped for tmux,
- // which will handle it via its Ss/Se terminfo extension - usually
- // according to its terminal-overrides.
- data->unibi_ext.set_cursor_shape_bar =
- (int)unibi_add_ext_str(ut, NULL, cusr_blink ? "\x1b[5 q" : "\x1b[6 q");
- data->unibi_ext.set_cursor_shape_ul =
- (int)unibi_add_ext_str(ut, NULL, cusr_blink ? "\x1b[3 q" : "\x1b[4 q");
- data->unibi_ext.set_cursor_shape_block =
- (int)unibi_add_ext_str(ut, NULL, cusr_blink ? "\x1b[1 q" : "\x1b[2 q");
- }
-
end:
// Fill some empty slots with common terminal strings
+ data->unibi_ext.set_cursor_color = (int)unibi_add_ext_str(
+ ut, NULL, "\033]12;#%p1%06x\007");
data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut, NULL,
"\x1b[?1002h\x1b[?1006h");
data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut, NULL,
@@ -1006,16 +1106,16 @@ static const char *tui_tk_ti_getstr(const char *name, const char *value,
stty_erase = tui_get_stty_erase();
}
- if (strcmp(name, "key_backspace") == 0) {
+ if (strequal(name, "key_backspace")) {
ILOG("libtermkey:kbs=%s", value);
if (stty_erase != NULL && stty_erase[0] != 0) {
return stty_erase;
}
- } else if (strcmp(name, "key_dc") == 0) {
+ } else if (strequal(name, "key_dc")) {
ILOG("libtermkey:kdch1=%s", value);
// Vim: "If <BS> and <DEL> are now the same, redefine <DEL>."
- if (stty_erase != NULL && value != NULL && strcmp(stty_erase, value) == 0) {
- return stty_erase[0] == DEL ? (char *)CTRL_H_STR : (char *)DEL_STR;
+ if (stty_erase != NULL && value != NULL && strequal(stty_erase, value)) {
+ return stty_erase[0] == DEL ? CTRL_H_STR : DEL_STR;
}
}
diff --git a/src/nvim/tui/tui.h b/src/nvim/tui/tui.h
index 07523bc124..2915b0e2f8 100644
--- a/src/nvim/tui/tui.h
+++ b/src/nvim/tui/tui.h
@@ -1,6 +1,8 @@
#ifndef NVIM_TUI_TUI_H
#define NVIM_TUI_TUI_H
+#include "nvim/cursor_shape.h"
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/tui.h.generated.h"
#endif
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index ea42e3e357..28f71b7ef2 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -29,6 +29,7 @@
#include "nvim/screen.h"
#include "nvim/syntax.h"
#include "nvim/window.h"
+#include "nvim/cursor_shape.h"
#ifdef FEAT_TUI
# include "nvim/tui/tui.h"
#else
@@ -179,6 +180,7 @@ void ui_refresh(void)
row = col = 0;
screen_resize(width, height);
pum_set_external(pum_external);
+ ui_cursor_style_set();
}
static void ui_refresh_event(void **argv)
@@ -376,6 +378,14 @@ void ui_cursor_goto(int new_row, int new_col)
pending_cursor_update = true;
}
+void ui_cursor_style_set(void)
+{
+ Dictionary style = cursor_shape_dict();
+ bool enabled = (*p_guicursor != NUL);
+ UI_CALL(cursor_style_set, enabled, style);
+ api_free_dictionary(style);
+}
+
void ui_update_menu(void)
{
UI_CALL(update_menu);
diff --git a/src/nvim/ui.h b/src/nvim/ui.h
index d14bc5812c..8ffc5a45a6 100644
--- a/src/nvim/ui.h
+++ b/src/nvim/ui.h
@@ -22,6 +22,7 @@ struct ui_t {
void (*clear)(UI *ui);
void (*eol_clear)(UI *ui);
void (*cursor_goto)(UI *ui, int row, int col);
+ void (*cursor_style_set)(UI *ui, bool enabled, Dictionary cursor_styles);
void (*update_menu)(UI *ui);
void (*busy_start)(UI *ui);
void (*busy_stop)(UI *ui);
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index 25861abc1b..9f780663ac 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -13,6 +13,7 @@
#include "nvim/memory.h"
#include "nvim/ui_bridge.h"
#include "nvim/ugrid.h"
+#include "nvim/api/private/helpers.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ui_bridge.c.generated.h"
@@ -59,6 +60,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
rv->bridge.clear = ui_bridge_clear;
rv->bridge.eol_clear = ui_bridge_eol_clear;
rv->bridge.cursor_goto = ui_bridge_cursor_goto;
+ rv->bridge.cursor_style_set = ui_bridge_cursor_style_set;
rv->bridge.update_menu = ui_bridge_update_menu;
rv->bridge.busy_start = ui_bridge_busy_start;
rv->bridge.busy_stop = ui_bridge_busy_stop;
@@ -178,6 +180,25 @@ static void ui_bridge_cursor_goto_event(void **argv)
ui->cursor_goto(ui, PTR2INT(argv[1]), PTR2INT(argv[2]));
}
+static void ui_bridge_cursor_style_set(UI *b, bool enabled, Dictionary styles)
+{
+ bool *enabledp = xmalloc(sizeof(*enabledp));
+ Object *stylesp = xmalloc(sizeof(*stylesp));
+ *enabledp = enabled;
+ *stylesp = copy_object(DICTIONARY_OBJ(styles));
+ UI_CALL(b, cursor_style_set, 3, b, enabledp, stylesp);
+}
+static void ui_bridge_cursor_style_set_event(void **argv)
+{
+ UI *ui = UI(argv[0]);
+ bool *enabled = argv[1];
+ Object *styles = argv[2];
+ ui->cursor_style_set(ui, *enabled, styles->data.dictionary);
+ xfree(enabled);
+ api_free_object(*styles);
+ xfree(styles);
+}
+
static void ui_bridge_update_menu(UI *b)
{
UI_CALL(b, update_menu, 1, b);
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index c95a795587..4d4e8d9bb9 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -82,6 +82,7 @@
#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/undo.h"
+#include "nvim/macros.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
@@ -317,7 +318,7 @@ static long get_undolevel(void)
static inline void zero_fmark_additional_data(fmark_T *fmarks)
{
for (size_t i = 0; i < NMARKS; i++) {
- dict_unref(fmarks[i].additional_data);
+ tv_dict_unref(fmarks[i].additional_data);
fmarks[i].additional_data = NULL;
}
}
@@ -1080,7 +1081,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
*/
perm = 0600;
if (buf->b_ffname != NULL) {
- perm = os_getperm(buf->b_ffname);
+ perm = os_getperm((const char *)buf->b_ffname);
if (perm < 0) {
perm = 0600;
}
@@ -1139,7 +1140,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
EMSG2(_(e_not_open), file_name);
goto theend;
}
- (void)os_setperm((char_u *)file_name, perm);
+ (void)os_setperm(file_name, perm);
if (p_verbose > 0) {
verbose_enter();
smsg(_("Writing undo file: %s"), file_name);
@@ -1164,7 +1165,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
&& os_fileinfo(file_name, &file_info_new)
&& file_info_old.stat.st_gid != file_info_new.stat.st_gid
&& os_fchown(fd, (uv_uid_t)-1, (uv_gid_t)file_info_old.stat.st_gid)) {
- os_setperm((char_u *)file_name, (perm & 0707) | ((perm & 07) << 3));
+ os_setperm(file_name, (perm & 0707) | ((perm & 07) << 3));
}
# ifdef HAVE_SELINUX
if (buf->b_ffname != NULL)
@@ -2941,25 +2942,28 @@ void u_eval_tree(u_header_T *first_uhp, list_T *list)
dict_T *dict;
while (uhp != NULL) {
- dict = dict_alloc();
- dict_add_nr_str(dict, "seq", uhp->uh_seq, NULL);
- dict_add_nr_str(dict, "time", (long)uhp->uh_time, NULL);
- if (uhp == curbuf->b_u_newhead)
- dict_add_nr_str(dict, "newhead", 1, NULL);
- if (uhp == curbuf->b_u_curhead)
- dict_add_nr_str(dict, "curhead", 1, NULL);
- if (uhp->uh_save_nr > 0)
- dict_add_nr_str(dict, "save", uhp->uh_save_nr, NULL);
+ dict = tv_dict_alloc();
+ tv_dict_add_nr(dict, S_LEN("seq"), (varnumber_T)uhp->uh_seq);
+ tv_dict_add_nr(dict, S_LEN("time"), (varnumber_T)uhp->uh_time);
+ if (uhp == curbuf->b_u_newhead) {
+ tv_dict_add_nr(dict, S_LEN("newhead"), 1);
+ }
+ if (uhp == curbuf->b_u_curhead) {
+ tv_dict_add_nr(dict, S_LEN("curhead"), 1);
+ }
+ if (uhp->uh_save_nr > 0) {
+ tv_dict_add_nr(dict, S_LEN("save"), (varnumber_T)uhp->uh_save_nr);
+ }
if (uhp->uh_alt_next.ptr != NULL) {
- list_T *alt_list = list_alloc();
+ list_T *alt_list = tv_list_alloc();
- /* Recursive call to add alternate undo tree. */
+ // Recursive call to add alternate undo tree.
u_eval_tree(uhp->uh_alt_next.ptr, alt_list);
- dict_add_list(dict, "alt", alt_list);
+ tv_dict_add_list(dict, S_LEN("alt"), alt_list);
}
- list_append_dict(list, dict);
+ tv_list_append_dict(list, dict);
uhp = uhp->uh_prev.ptr;
}
}
diff --git a/src/nvim/version.c b/src/nvim/version.c
index a354634218..0ee0419849 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -73,18 +73,18 @@ static char *features[] = {
};
// clang-format off
-static int included_patches[] = {
- // 2367,
+static const int included_patches[] = {
+ // 2367,NA
// 2366 NA
// 2365 NA
- // 2364,
+ // 2364,NA
// 2363 NA
2362,
// 2361 NA
// 2360,
// 2359 NA
// 2358 NA
- // 2357,
+ 2357,
// 2356,
2355,
// 2354,
@@ -98,7 +98,7 @@ static int included_patches[] = {
2346,
// 2345 NA
// 2344 NA
- // 2343,
+ 2343,
// 2342 NA
2341,
// 2340 NA
@@ -107,11 +107,11 @@ static int included_patches[] = {
2337,
2336,
2335,
- // 2334,
+ 2334,
2333,
// 2332 NA
2331,
- // 2330,
+ 2330,
2329,
2328,
// 2327 NA
@@ -134,8 +134,8 @@ static int included_patches[] = {
// 2310 NA
2309,
// 2308 NA
- // 2307,
- // 2306,
+ 2307,
+ 2306,
2305,
// 2304 NA
2303,
@@ -165,14 +165,14 @@ static int included_patches[] = {
2279,
// 2278 NA
2277,
- // 2276,
+ 2276,
2275,
2274,
2273,
2272,
// 2271 NA
// 2270 NA
- // 2269,
+ 2269,
// 2268,
// 2267 NA
2266,
@@ -205,7 +205,7 @@ static int included_patches[] = {
// 2239,
// 2238 NA
2237,
- // 2236,
+ 2236,
2235,
// 2234 NA
2233,
@@ -337,7 +337,7 @@ static int included_patches[] = {
2107,
2106,
// 2105 NA
- // 2104,
+ 2104,
2103,
// 2102 NA
2101,
@@ -2461,10 +2461,10 @@ static char *(extra_patches[]) = {
/// @param version Version string like "1.3.42"
///
/// @return true if Nvim is at or above the version.
-bool has_nvim_version(char *version_str)
- FUNC_ATTR_NONNULL_ALL
+bool has_nvim_version(const char *const version_str)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- char *p = version_str;
+ const char *p = version_str;
int major = 0;
int minor = 0;
int patch = 0;
@@ -2473,7 +2473,7 @@ bool has_nvim_version(char *version_str)
return false;
}
major = atoi(p);
- p = strchr(p, '.'); // Find the next dot.
+ p = strchr(p, '.'); // Find the next dot.
if (p) {
p++; // Advance past the dot.
@@ -2481,7 +2481,7 @@ bool has_nvim_version(char *version_str)
return false;
}
minor = atoi(p);
- p = strchr(p, '.');
+ p = strchr(p, '.');
if (p) {
p++;
if (!ascii_isdigit(*p)) {
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 87e9889465..cc0587fb88 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -30,7 +30,7 @@ Error: configure did not run properly.Check auto/config.log.
#include "nvim/os/os_defs.h" /* bring lots of system header files */
/// length of a buffer to store a number in ASCII (64 bits binary + NUL)
-#define NUMBUFLEN 65
+enum { NUMBUFLEN = 65 };
// flags for vim_str2nr()
#define STR2NR_BIN 1
@@ -51,22 +51,7 @@ Error: configure did not run properly.Check auto/config.log.
/* ================ end of the header file puzzle =============== */
-#ifdef HAVE_WORKING_LIBINTL
-# include <libintl.h>
-# define _(x) gettext((char *)(x))
-// XXX do we actually need this?
-# ifdef gettext_noop
-# define N_(x) gettext_noop(x)
-# else
-# define N_(x) x
-# endif
-#else
-# define _(x) ((char *)(x))
-# define N_(x) x
-# define bindtextdomain(x, y) /* empty */
-# define bind_textdomain_codeset(x, y) /* empty */
-# define textdomain(x) /* empty */
-#endif
+#include "nvim/gettext.h"
/* special attribute addition: Put message in history */
#define MSG_HIST 0x1000
@@ -109,11 +94,14 @@ Error: configure did not run properly.Check auto/config.log.
// all mode bits used for mapping
#define MAP_ALL_MODES (0x3f | SELECTMODE | TERM_FOCUS)
-/* directions */
-#define FORWARD 1
-#define BACKWARD (-1)
-#define FORWARD_FILE 3
-#define BACKWARD_FILE (-3)
+/// Directions.
+typedef enum {
+ kDirectionNotSet = 0,
+ FORWARD = 1,
+ BACKWARD = (-1),
+ FORWARD_FILE = 3,
+ BACKWARD_FILE = (-3),
+} Direction;
/* return values for functions */
#if !(defined(OK) && (OK == 1))
@@ -282,15 +270,22 @@ enum {
#define SHOWCMD_COLS 10 /* columns needed by shown command */
#define STL_MAX_ITEM 80 /* max nr of %<flag> in statusline */
-/*
- * fnamecmp() is used to compare file names.
- * On some systems case in a file name does not matter, on others it does.
- * (this does not account for maximum name lengths and things like "../dir",
- * thus it is not 100% accurate!)
- */
-#define fnamecmp(x, y) vim_fnamecmp((char_u *)(x), (char_u *)(y))
-#define fnamencmp(x, y, n) vim_fnamencmp((char_u *)(x), (char_u *)(y), \
- (size_t)(n))
+/// Compare file names
+///
+/// On some systems case in a file name does not matter, on others it does.
+///
+/// @note Does not account for maximum name lengths and things like "../dir",
+/// thus it is not 100% accurate. OS may also use different algorythm for
+/// case-insensitive comparison.
+///
+/// @param[in] x First file name to compare.
+/// @param[in] y Second file name to compare.
+///
+/// @return 0 for equal file names, non-zero otherwise.
+#define fnamecmp(x, y) path_fnamecmp((const char *)(x), (const char *)(y))
+#define fnamencmp(x, y, n) path_fnamencmp((const char *)(x), \
+ (const char *)(y), \
+ (size_t)(n))
/*
* Enums need a typecast to be used as array index (for Ultrix).
diff --git a/src/nvim/viml/executor/converter.c b/src/nvim/viml/executor/converter.c
index a39f573036..425a38538d 100644
--- a/src/nvim/viml/executor/converter.c
+++ b/src/nvim/viml/executor/converter.c
@@ -15,8 +15,9 @@
#include "nvim/vim.h"
#include "nvim/globals.h"
#include "nvim/message.h"
-#include "nvim/eval_defs.h"
+#include "nvim/eval/typval.h"
#include "nvim/ascii.h"
+#include "nvim/macros.h"
#include "nvim/lib/kvec.h"
#include "nvim/eval/decode.h"
@@ -207,23 +208,23 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
size_t len;
const char *s = lua_tolstring(lstate, -2, &len);
if (cur.special) {
- list_T *const kv_pair = list_alloc();
- list_append_list(cur.tv->vval.v_list, kv_pair);
- listitem_T *const key = listitem_alloc();
+ list_T *const kv_pair = tv_list_alloc();
+ tv_list_append_list(cur.tv->vval.v_list, kv_pair);
+ listitem_T *const key = tv_list_item_alloc();
key->li_tv = decode_string(s, len, kTrue, false, false);
- list_append(kv_pair, key);
+ tv_list_append(kv_pair, key);
if (key->li_tv.v_type == VAR_UNKNOWN) {
ret = false;
- list_unref(kv_pair);
+ tv_list_unref(kv_pair);
continue;
}
- listitem_T *const val = listitem_alloc();
- list_append(kv_pair, val);
+ listitem_T *const val = tv_list_item_alloc();
+ tv_list_append(kv_pair, val);
kv_push(stack, cur);
cur = (TVPopStackItem) { &val->li_tv, false, false, 0 };
} else {
- dictitem_T *const di = dictitem_alloc_len(s, len);
- if (dict_add(cur.tv->vval.v_dict, di) == FAIL) {
+ dictitem_T *const di = tv_dict_item_alloc_len(s, len);
+ if (tv_dict_add(cur.tv->vval.v_dict, di) == FAIL) {
assert(false);
}
kv_push(stack, cur);
@@ -240,8 +241,8 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
lua_pop(lstate, 2);
continue;
}
- listitem_T *const li = listitem_alloc();
- list_append(cur.tv->vval.v_list, li);
+ listitem_T *const li = tv_list_item_alloc();
+ tv_list_append(cur.tv->vval.v_list, li);
kv_push(stack, cur);
cur = (TVPopStackItem) { &li->li_tv, false, false, 0 };
}
@@ -292,7 +293,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
for (size_t i = 0; i < kv_size(stack); i++) {
const TVPopStackItem item = kv_A(stack, i);
if (item.container && lua_rawequal(lstate, -1, item.idx)) {
- copy_tv(item.tv, cur.tv);
+ tv_copy(item.tv, cur.tv);
cur.container = false;
goto nlua_pop_typval_table_processing_end;
}
@@ -301,7 +302,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
switch (table_props.type) {
case kObjectTypeArray: {
cur.tv->v_type = VAR_LIST;
- cur.tv->vval.v_list = list_alloc();
+ cur.tv->vval.v_list = tv_list_alloc();
cur.tv->vval.v_list->lv_refcount++;
if (table_props.maxidx != 0) {
cur.container = true;
@@ -313,21 +314,21 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
case kObjectTypeDictionary: {
if (table_props.string_keys_num == 0) {
cur.tv->v_type = VAR_DICT;
- cur.tv->vval.v_dict = dict_alloc();
+ cur.tv->vval.v_dict = tv_dict_alloc();
cur.tv->vval.v_dict->dv_refcount++;
} else {
cur.special = table_props.has_string_with_nul;
if (table_props.has_string_with_nul) {
decode_create_map_special_dict(cur.tv);
assert(cur.tv->v_type = VAR_DICT);
- dictitem_T *const val_di = dict_find(cur.tv->vval.v_dict,
- (char_u *)"_VAL", 4);
+ dictitem_T *const val_di = tv_dict_find(cur.tv->vval.v_dict,
+ S_LEN("_VAL"));
assert(val_di != NULL);
cur.tv = &val_di->di_tv;
assert(cur.tv->v_type == VAR_LIST);
} else {
cur.tv->v_type = VAR_DICT;
- cur.tv->vval.v_dict = dict_alloc();
+ cur.tv->vval.v_dict = tv_dict_alloc();
cur.tv->vval.v_dict->dv_refcount++;
}
cur.container = true;
@@ -368,7 +369,7 @@ nlua_pop_typval_table_processing_end:
}
kv_destroy(stack);
if (!ret) {
- clear_tv(ret_tv);
+ tv_clear(ret_tv);
*ret_tv = (typval_T) {
.v_type = VAR_NUMBER,
.v_lock = VAR_UNLOCKED,
diff --git a/src/nvim/viml/executor/executor.c b/src/nvim/viml/executor/executor.c
index d0e269bf6a..826460772e 100644
--- a/src/nvim/viml/executor/executor.c
+++ b/src/nvim/viml/executor/executor.c
@@ -461,18 +461,33 @@ nlua_print_error:
int nlua_debug(lua_State *lstate)
FUNC_ATTR_NONNULL_ALL
{
+ const typval_T input_args[] = {
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_STRING,
+ .vval.v_string = (char_u *)"lua_debug> ",
+ },
+ {
+ .v_type = VAR_UNKNOWN,
+ },
+ };
for (;;) {
lua_settop(lstate, 0);
- char *const input = get_user_input("lua_debug> ", "", NULL, NULL);
+ typval_T input;
+ get_user_input(input_args, &input, false);
msg_putchar('\n'); // Avoid outputting on input line.
- if (input == NULL || *input == NUL || strcmp(input, "cont") == 0) {
- xfree(input);
+ if (input.v_type != VAR_STRING
+ || input.vval.v_string == NULL
+ || *input.vval.v_string == NUL
+ || STRCMP(input.vval.v_string, "cont") == 0) {
+ tv_clear(&input);
return 0;
}
- if (luaL_loadbuffer(lstate, input, strlen(input), "=(debug command)")) {
+ if (luaL_loadbuffer(lstate, (const char *)input.vval.v_string,
+ STRLEN(input.vval.v_string), "=(debug command)")) {
nlua_error(lstate, _("E5115: Error while loading debug string: %.*s"));
}
- xfree(input);
+ tv_clear(&input);
if (lua_pcall(lstate, 0, 0, 0)) {
nlua_error(lstate, _("E5116: Error while calling debug string: %.*s"));
}
@@ -517,7 +532,7 @@ void ex_lua(exarg_T *const eap)
}
typval_T tv = { .v_type = VAR_UNKNOWN };
executor_exec_lua((String) { .data = code, .size = len }, &tv);
- clear_tv(&tv);
+ tv_clear(&tv);
xfree(code);
}
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 4fac730f02..6020159af9 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -2983,8 +2983,8 @@ static tabpage_T *alloc_tabpage(void)
tp->handle = ++last_tp_handle;
handle_register_tabpage(tp);
- /* init t: variables */
- tp->tp_vars = dict_alloc();
+ // Init t: variables.
+ tp->tp_vars = tv_dict_alloc();
init_var_dict(tp->tp_vars, &tp->tp_winvar, VAR_SCOPE);
tp->tp_diff_invalid = TRUE;
tp->tp_ch_used = p_ch;
@@ -3811,8 +3811,8 @@ static win_T *win_alloc(win_T *after, int hidden)
new_wp->handle = ++last_win_id;
handle_register_window(new_wp);
- /* init w: variables */
- new_wp->w_vars = dict_alloc();
+ // Init w: variables.
+ new_wp->w_vars = tv_dict_alloc();
init_var_dict(new_wp->w_vars, &new_wp->w_winvar, VAR_SCOPE);
/* Don't execute autocommands while the window is not properly
@@ -5504,9 +5504,9 @@ void restore_buffer(bufref_T *save_curbuf)
// Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
// If no particular ID is desired, -1 must be specified for 'id'.
// Return ID of added match, -1 on failure.
-int match_add(win_T *wp, char_u *grp, char_u *pat,
+int match_add(win_T *wp, const char *const grp, const char *const pat,
int prio, int id, list_T *pos_list,
- char_u *conceal_char)
+ const char *const conceal_char)
{
matchitem_T *cur;
matchitem_T *prev;
@@ -5534,11 +5534,11 @@ int match_add(win_T *wp, char_u *grp, char_u *pat,
cur = cur->next;
}
}
- if ((hlg_id = syn_namen2id(grp, (int)STRLEN(grp))) == 0) {
+ if ((hlg_id = syn_name2id((const char_u *)grp)) == 0) {
EMSG2(_(e_nogroup), grp);
return -1;
}
- if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL) {
+ if (pat != NULL && (regprog = vim_regcomp((char_u *)pat, RE_MAGIC)) == NULL) {
EMSG2(_(e_invarg2), pat);
return -1;
}
@@ -5557,14 +5557,14 @@ int match_add(win_T *wp, char_u *grp, char_u *pat,
m = xcalloc(1, sizeof(matchitem_T));
m->id = id;
m->priority = prio;
- m->pattern = pat == NULL ? NULL: vim_strsave(pat);
+ m->pattern = pat == NULL ? NULL: (char_u *)xstrdup(pat);
m->hlg_id = hlg_id;
m->match.regprog = regprog;
m->match.rmm_ic = FALSE;
m->match.rmm_maxcol = 0;
m->conceal_char = 0;
if (conceal_char != NULL) {
- m->conceal_char = (*mb_ptr2char)(conceal_char);
+ m->conceal_char = (*mb_ptr2char)((const char_u *)conceal_char);
}
// Set up position matches
@@ -5582,7 +5582,7 @@ int match_add(win_T *wp, char_u *grp, char_u *pat,
int len = 1;
list_T *subl;
listitem_T *subli;
- int error = false;
+ bool error = false;
if (li->li_tv.v_type == VAR_LIST) {
subl = li->li_tv.vval.v_list;
@@ -5593,8 +5593,8 @@ int match_add(win_T *wp, char_u *grp, char_u *pat,
if (subli == NULL) {
goto fail;
}
- lnum = get_tv_number_chk(&subli->li_tv, &error);
- if (error == true) {
+ lnum = tv_get_number_chk(&subli->li_tv, &error);
+ if (error) {
goto fail;
}
if (lnum == 0) {
@@ -5604,13 +5604,14 @@ int match_add(win_T *wp, char_u *grp, char_u *pat,
m->pos.pos[i].lnum = lnum;
subli = subli->li_next;
if (subli != NULL) {
- col = get_tv_number_chk(&subli->li_tv, &error);
- if (error == true)
+ col = tv_get_number_chk(&subli->li_tv, &error);
+ if (error) {
goto fail;
+ }
subli = subli->li_next;
if (subli != NULL) {
- len = get_tv_number_chk(&subli->li_tv, &error);
- if (error == true) {
+ len = tv_get_number_chk(&subli->li_tv, &error);
+ if (error) {
goto fail;
}
}
@@ -5809,14 +5810,14 @@ int win_getid(typval_T *argvars)
if (argvars[0].v_type == VAR_UNKNOWN) {
return curwin->handle;
}
- int winnr = get_tv_number(&argvars[0]);
+ int winnr = tv_get_number(&argvars[0]);
win_T *wp;
if (winnr > 0) {
if (argvars[1].v_type == VAR_UNKNOWN) {
wp = firstwin;
} else {
tabpage_T *tp = NULL;
- int tabnr = get_tv_number(&argvars[1]);
+ int tabnr = tv_get_number(&argvars[1]);
FOR_ALL_TABS(tp2) {
if (--tabnr == 0) {
tp = tp2;
@@ -5843,7 +5844,7 @@ int win_getid(typval_T *argvars)
int win_gotoid(typval_T *argvars)
{
- int id = get_tv_number(&argvars[0]);
+ int id = tv_get_number(&argvars[0]);
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->handle == id) {
@@ -5878,16 +5879,16 @@ void win_id2tabwin(typval_T *argvars, list_T *list)
{
int winnr = 1;
int tabnr = 1;
- int id = get_tv_number(&argvars[0]);
+ handle_T id = (handle_T)tv_get_number(&argvars[0]);
win_get_tabwin(id, &tabnr, &winnr);
- list_append_number(list, tabnr);
- list_append_number(list, winnr);
+ tv_list_append_number(list, tabnr);
+ tv_list_append_number(list, winnr);
}
win_T * win_id2wp(typval_T *argvars)
{
- int id = get_tv_number(&argvars[0]);
+ int id = tv_get_number(&argvars[0]);
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->handle == id) {
@@ -5901,7 +5902,7 @@ win_T * win_id2wp(typval_T *argvars)
int win_id2win(typval_T *argvars)
{
int nr = 1;
- int id = get_tv_number(&argvars[0]);
+ int id = tv_get_number(&argvars[0]);
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->handle == id) {
@@ -5914,11 +5915,11 @@ int win_id2win(typval_T *argvars)
void win_findbuf(typval_T *argvars, list_T *list)
{
- int bufnr = get_tv_number(&argvars[0]);
+ int bufnr = tv_get_number(&argvars[0]);
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer->b_fnum == bufnr) {
- list_append_number(list, wp->handle);
+ tv_list_append_number(list, wp->handle);
}
}
}