mirror of
https://github.com/neovim/neovim.git
synced 2025-10-09 03:16:31 +00:00
vim-patch:8.1.0735: cannot handle binary data
Problem: Cannot handle binary data. Solution: Add the Blob type. (Yasuhiro Matsumoto, closes vim/vim#3638)6e5ea8d2a9
Nvim-specific Blob conversions are implemented in future commits. Refactor write_blob() to use a FileDescriptor, as f_writefile() was refactored to use one (does not apply to read_blob()). Use var_check_lock() in f_add() for Blobs from v8.1.0897. Add a modeline to test_blob.vim and fix some doc typos. Include if_perl.txt's VIM::Blob() documentation. Interestingly, this function already worked before this port, as it just returns a Blob string literal, not an actual Blob object. N/A patches for version.c: vim-patch:8.1.0741: viminfo with Blob is not tested Problem: Viminfo with Blob is not tested. Solution: Extend the viminfo test. Fix reading a blob. Fixed storing a special variable value.8c8b8bb56c
vim-patch:8.1.1022: may use NULL pointer when out of memory Problem: May use NULL pointer when out of memory. (Coverity) Solution: Check for blob_alloc() returning NULL.e142a9467a
This commit is contained in:
@@ -2125,6 +2125,73 @@ void tv_dict_set_keys_readonly(dict_T *const dict)
|
||||
});
|
||||
}
|
||||
|
||||
//{{{1 Blobs
|
||||
//{{{2 Alloc/free
|
||||
|
||||
/// Allocate an empty blob.
|
||||
///
|
||||
/// Caller should take care of the reference count.
|
||||
///
|
||||
/// @return [allocated] new blob.
|
||||
blob_T *tv_blob_alloc(void)
|
||||
FUNC_ATTR_NONNULL_RET
|
||||
{
|
||||
blob_T *const blob = xcalloc(1, sizeof(blob_T));
|
||||
ga_init(&blob->bv_ga, 1, 100);
|
||||
return blob;
|
||||
}
|
||||
|
||||
/// Free a blob. Ignores the reference count.
|
||||
///
|
||||
/// @param[in,out] b Blob to free.
|
||||
void tv_blob_free(blob_T *const b)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
ga_clear(&b->bv_ga);
|
||||
xfree(b);
|
||||
}
|
||||
|
||||
/// Unreference a blob.
|
||||
///
|
||||
/// Decrements the reference count and frees blob when it becomes zero.
|
||||
///
|
||||
/// @param[in,out] b Blob to operate on.
|
||||
void tv_blob_unref(blob_T *const b)
|
||||
{
|
||||
if (b != NULL && --b->bv_refcount <= 0) {
|
||||
tv_blob_free(b);
|
||||
}
|
||||
}
|
||||
|
||||
//{{{2 Operations on the whole blob
|
||||
|
||||
/// Check whether two blobs are equal.
|
||||
///
|
||||
/// @param[in] b1 First blob.
|
||||
/// @param[in] b2 Second blob.
|
||||
///
|
||||
/// @return true if blobs are equal, false otherwise.
|
||||
bool tv_blob_equal(const blob_T *const b1, const blob_T *const b2)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
if (b1 == NULL || b2 == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (b1 == b2) {
|
||||
return true;
|
||||
}
|
||||
if (tv_blob_len(b1) != tv_blob_len(b2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < b1->bv_ga.ga_len; i++) {
|
||||
if (tv_blob_get(b1, i) != tv_blob_get(b2, i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//{{{1 Generic typval operations
|
||||
//{{{2 Init/alloc/clear
|
||||
//{{{3 Alloc
|
||||
@@ -2169,6 +2236,18 @@ void tv_dict_alloc_ret(typval_T *const ret_tv)
|
||||
tv_dict_set_ret(ret_tv, d);
|
||||
}
|
||||
|
||||
/// Allocate an empty blob for a return value.
|
||||
///
|
||||
/// Also sets reference count.
|
||||
///
|
||||
/// @param[out] ret_tv Structure where blob is saved.
|
||||
void tv_blob_alloc_ret(typval_T *const ret_tv)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
blob_T *const b = tv_blob_alloc();
|
||||
tv_blob_set_ret(ret_tv, b);
|
||||
}
|
||||
|
||||
//{{{3 Clear
|
||||
#define TYPVAL_ENCODE_ALLOW_SPECIALS false
|
||||
|
||||
@@ -2210,6 +2289,13 @@ void tv_dict_alloc_ret(typval_T *const ret_tv)
|
||||
|
||||
#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type)
|
||||
|
||||
#define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \
|
||||
do { \
|
||||
tv_blob_unref(tv->vval.v_blob); \
|
||||
tv->vval.v_blob = NULL; \
|
||||
tv->v_lock = VAR_UNLOCKED; \
|
||||
} while (0)
|
||||
|
||||
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)
|
||||
@@ -2392,6 +2478,7 @@ static inline void _nothing_conv_dict_end(typval_T *const tv,
|
||||
#undef TYPVAL_ENCODE_CONV_STRING
|
||||
#undef TYPVAL_ENCODE_CONV_STR_STRING
|
||||
#undef TYPVAL_ENCODE_CONV_EXT_STRING
|
||||
#undef TYPVAL_ENCODE_CONV_BLOB
|
||||
#undef TYPVAL_ENCODE_CONV_FUNC_START
|
||||
#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS
|
||||
#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF
|
||||
@@ -2449,6 +2536,10 @@ void tv_free(typval_T *tv)
|
||||
xfree(tv->vval.v_string);
|
||||
break;
|
||||
}
|
||||
case VAR_BLOB: {
|
||||
tv_blob_unref(tv->vval.v_blob);
|
||||
break;
|
||||
}
|
||||
case VAR_LIST: {
|
||||
tv_list_unref(tv->vval.v_list);
|
||||
break;
|
||||
@@ -2509,6 +2600,12 @@ void tv_copy(const typval_T *const from, typval_T *const to)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VAR_BLOB: {
|
||||
if (from->vval.v_blob != NULL) {
|
||||
to->vval.v_blob->bv_refcount++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VAR_LIST: {
|
||||
tv_list_ref(to->vval.v_list);
|
||||
break;
|
||||
@@ -2560,6 +2657,13 @@ void tv_item_lock(typval_T *const tv, const int deep, const bool lock)
|
||||
CHANGE_LOCK(lock, tv->v_lock);
|
||||
|
||||
switch (tv->v_type) {
|
||||
case VAR_BLOB: {
|
||||
blob_T *const b = tv->vval.v_blob;
|
||||
if (b != NULL) {
|
||||
CHANGE_LOCK(lock, b->bv_lock);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VAR_LIST: {
|
||||
list_T *const l = tv->vval.v_list;
|
||||
if (l != NULL) {
|
||||
@@ -2646,10 +2750,11 @@ bool tv_check_lock(const typval_T *tv, const char *name,
|
||||
VarLockStatus lock = VAR_UNLOCKED;
|
||||
|
||||
switch (tv->v_type) {
|
||||
// case VAR_BLOB:
|
||||
// if (tv->vval.v_blob != NULL)
|
||||
// lock = tv->vval.v_blob->bv_lock;
|
||||
// break;
|
||||
case VAR_BLOB:
|
||||
if (tv->vval.v_blob != NULL) {
|
||||
lock = tv->vval.v_blob->bv_lock;
|
||||
}
|
||||
break;
|
||||
case VAR_LIST:
|
||||
if (tv->vval.v_list != NULL) {
|
||||
lock = tv->vval.v_list->lv_lock;
|
||||
@@ -2769,6 +2874,9 @@ bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic,
|
||||
recursive_cnt--;
|
||||
return r;
|
||||
}
|
||||
case VAR_BLOB: {
|
||||
return tv_blob_equal(tv1->vval.v_blob, tv2->vval.v_blob);
|
||||
}
|
||||
case VAR_NUMBER: {
|
||||
return tv1->vval.v_number == tv2->vval.v_number;
|
||||
}
|
||||
@@ -2835,6 +2943,10 @@ bool tv_check_str_or_nr(const typval_T *const tv)
|
||||
EMSG(_("E728: Expected a Number or a String, Dictionary found"));
|
||||
return false;
|
||||
}
|
||||
case VAR_BLOB: {
|
||||
EMSG(_("E974: Expected a Number or a String, Blob found"));
|
||||
return false;
|
||||
}
|
||||
case VAR_BOOL: {
|
||||
EMSG(_("E5299: Expected a Number or a String, Boolean found"));
|
||||
return false;
|
||||
@@ -2860,6 +2972,7 @@ static const char *const num_errors[] = {
|
||||
[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_BLOB]=N_("E974: Using a Blob as a Number"),
|
||||
[VAR_UNKNOWN]=N_("E685: using an invalid value as a Number"),
|
||||
};
|
||||
|
||||
@@ -2888,6 +3001,7 @@ bool tv_check_num(const typval_T *const tv)
|
||||
case VAR_LIST:
|
||||
case VAR_DICT:
|
||||
case VAR_FLOAT:
|
||||
case VAR_BLOB:
|
||||
case VAR_UNKNOWN: {
|
||||
EMSG(_(num_errors[tv->v_type]));
|
||||
return false;
|
||||
@@ -2905,6 +3019,7 @@ static const char *const str_errors[] = {
|
||||
[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_BLOB]=N_("E976: using Blob as a String"),
|
||||
[VAR_UNKNOWN]=N_("E908: using an invalid value as a String"),
|
||||
};
|
||||
|
||||
@@ -2933,6 +3048,7 @@ bool tv_check_str(const typval_T *const tv)
|
||||
case VAR_LIST:
|
||||
case VAR_DICT:
|
||||
case VAR_FLOAT:
|
||||
case VAR_BLOB:
|
||||
case VAR_UNKNOWN: {
|
||||
EMSG(_(str_errors[tv->v_type]));
|
||||
return false;
|
||||
@@ -2980,6 +3096,7 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error)
|
||||
case VAR_PARTIAL:
|
||||
case VAR_LIST:
|
||||
case VAR_DICT:
|
||||
case VAR_BLOB:
|
||||
case VAR_FLOAT: {
|
||||
EMSG(_(num_errors[tv->v_type]));
|
||||
break;
|
||||
@@ -3075,6 +3192,10 @@ float_T tv_get_float(const typval_T *const tv)
|
||||
EMSG(_("E907: Using a special value as a Float"));
|
||||
break;
|
||||
}
|
||||
case VAR_BLOB: {
|
||||
EMSG(_("E975: Using a Blob as a Float"));
|
||||
break;
|
||||
}
|
||||
case VAR_UNKNOWN: {
|
||||
emsgf(_(e_intern2), "tv_get_float(UNKNOWN)");
|
||||
break;
|
||||
@@ -3134,6 +3255,7 @@ const char *tv_get_string_buf_chk(const typval_T *const tv, char *const buf)
|
||||
case VAR_LIST:
|
||||
case VAR_DICT:
|
||||
case VAR_FLOAT:
|
||||
case VAR_BLOB:
|
||||
case VAR_UNKNOWN: {
|
||||
EMSG(_(str_errors[tv->v_type]));
|
||||
return false;
|
||||
|
Reference in New Issue
Block a user