From b2942d1e729c4cfa8ec9d3bedcdc7ad838a689ef Mon Sep 17 00:00:00 2001 From: ZyX Date: Thu, 13 Apr 2017 19:16:32 +0300 Subject: [PATCH 1/5] eval: Change the point at which arg_errmsg and its length are changed Ref #6437 --- src/nvim/eval.c | 130 ++++++++++++++++++++++------------------- src/nvim/eval/typval.c | 22 +++++-- src/nvim/eval/typval.h | 11 ++++ 3 files changed, 98 insertions(+), 65 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 0663e19b9a..e81378bcaa 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2378,9 +2378,9 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, &tv, &di, true, false) == OK) { if ((di == NULL || (!var_check_ro(di->di_flags, (const char *)lp->ll_name, - STRLEN(lp->ll_name)) + TV_CSTRING) && !tv_check_lock(di->di_tv.v_lock, (const char *)lp->ll_name, - STRLEN(lp->ll_name)))) + TV_CSTRING))) && eexe_mod_op(&tv, rettv, (const char *)op) == OK) { set_var(lp->ll_name, lp->ll_name_len, &tv, false); } @@ -2393,7 +2393,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, } else if (tv_check_lock(lp->ll_newkey == NULL ? lp->ll_tv->v_lock : lp->ll_tv->vval.v_dict->dv_lock, - (const char *)lp->ll_name, STRLEN(lp->ll_name))) { + (const char *)lp->ll_name, TV_CSTRING)) { } else if (lp->ll_range) { listitem_T *ll_li = lp->ll_li; int ll_n1 = lp->ll_n1; @@ -2402,7 +2402,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, for (listitem_T *ri = rettv->vval.v_list->lv_first; ri != NULL && ll_li != NULL; ) { if (tv_check_lock(ll_li->li_tv.v_lock, (const char *)lp->ll_name, - STRLEN(lp->ll_name))) { + TV_CSTRING)) { return; } ri = ri->li_next; @@ -2992,14 +2992,14 @@ int do_unlet(const char *const name, const size_t name_len, const int forceit) } if (hi != NULL && !HASHITEM_EMPTY(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))) { + if (var_check_fixed(di->di_flags, (const char *)name, TV_CSTRING) + || var_check_ro(di->di_flags, (const char *)name, TV_CSTRING) + || tv_check_lock(d->dv_lock, (const char *)name, TV_CSTRING)) { return FAIL; } if (d == NULL - || tv_check_lock(d->dv_lock, (const char *)name, STRLEN(name))) { + || tv_check_lock(d->dv_lock, (const char *)name, TV_CSTRING)) { return FAIL; } @@ -6553,10 +6553,8 @@ static void f_add(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_number = 1; /* Default: Failed */ if (argvars[0].v_type == VAR_LIST) { - const char *const arg_errmsg = _("add() argument"); - 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)) { + && !tv_check_lock(l->lv_lock, "add() argument", TV_TRANSLATE)) { tv_list_append_tv(l, &argvars[1]); tv_copy(&argvars[0], rettv); } @@ -8152,7 +8150,6 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr) { const char *const arg_errmsg = N_("extend() argument"); - const size_t arg_errmsg_len = strlen(arg_errmsg); if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) { long before; @@ -8161,13 +8158,13 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr) 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); + const bool locked = tv_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE); (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)) { + } else if (!tv_check_lock(l1->lv_lock, arg_errmsg, TV_TRANSLATE)) { listitem_T *item; if (argvars[2].v_type != VAR_UNKNOWN) { before = tv_get_number_chk(&argvars[2], &error); @@ -8195,13 +8192,13 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr) 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); + const bool locked = tv_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE); (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)) { + } else if (!tv_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) { const char *action = "force"; // Check the third argument. if (argvars[2].v_type != VAR_UNKNOWN) { @@ -8349,20 +8346,19 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) int todo; char_u *ermsg = (char_u *)(map ? "map()" : "filter()"); const char *const arg_errmsg = (map - ? _("map() argument") - : _("filter() argument")); - const size_t arg_errmsg_len = strlen(arg_errmsg); + ? N_("map() argument") + : N_("filter() argument")); int save_did_emsg; int idx = 0; if (argvars[0].v_type == VAR_LIST) { if ((l = argvars[0].vval.v_list) == NULL - || (!map && tv_check_lock(l->lv_lock, arg_errmsg, arg_errmsg_len))) { + || (!map && tv_check_lock(l->lv_lock, arg_errmsg, TV_TRANSLATE))) { return; } } else if (argvars[0].v_type == VAR_DICT) { if ((d = argvars[0].vval.v_dict) == NULL - || (!map && tv_check_lock(d->dv_lock, arg_errmsg, arg_errmsg_len))) { + || (!map && tv_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE))) { return; } } else { @@ -8395,8 +8391,8 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) 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))) { + && (tv_check_lock(di->di_tv.v_lock, arg_errmsg, TV_TRANSLATE) + || var_check_ro(di->di_flags, arg_errmsg, TV_TRANSLATE))) { break; } @@ -8407,8 +8403,8 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) 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)) { + if (var_check_fixed(di->di_flags, arg_errmsg, TV_TRANSLATE) + || var_check_ro(di->di_flags, arg_errmsg, TV_TRANSLATE)) { break; } tv_dict_item_remove(d, di); @@ -8421,7 +8417,7 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) for (li = l->lv_first; li != NULL; li = nli) { if (map - && tv_check_lock(li->li_tv.v_lock, arg_errmsg, arg_errmsg_len)) { + && tv_check_lock(li->li_tv.v_lock, arg_errmsg, TV_TRANSLATE)) { break; } nli = li->li_next; @@ -11158,13 +11154,12 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr) { list_T *l; bool error = false; - const char *const arg_errmsg = _("insert() argument"); - const size_t arg_errmsg_len = strlen(arg_errmsg); if (argvars[0].v_type != VAR_LIST) { EMSG2(_(e_listarg), "insert()"); } else if ((l = argvars[0].vval.v_list) != NULL - && !tv_check_lock(l->lv_lock, arg_errmsg, arg_errmsg_len)) { + && !tv_check_lock(l->lv_lock, N_("insert() argument"), + TV_TRANSLATE)) { long before = 0; if (argvars[2].v_type != VAR_UNKNOWN) { before = tv_get_number_chk(&argvars[2], &error); @@ -13205,21 +13200,20 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr) long end; dict_T *d; dictitem_T *di; - const char *const arg_errmsg = _("remove() argument"); - const size_t arg_errmsg_len = strlen(arg_errmsg); + const char *const arg_errmsg = N_("remove() argument"); if (argvars[0].v_type == VAR_DICT) { if (argvars[2].v_type != VAR_UNKNOWN) { EMSG2(_(e_toomanyarg), "remove()"); } else if ((d = argvars[0].vval.v_dict) != NULL - && !tv_check_lock(d->dv_lock, arg_errmsg, arg_errmsg_len)) { + && !tv_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE)) { const char *key = tv_get_string_chk(&argvars[1]); if (key != NULL) { 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)) { + } else if (!var_check_fixed(di->di_flags, arg_errmsg, TV_TRANSLATE) + && !var_check_ro(di->di_flags, arg_errmsg, TV_TRANSLATE)) { *rettv = di->di_tv; di->di_tv = TV_INITIAL_VALUE; tv_dict_item_remove(d, di); @@ -13232,7 +13226,7 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr) } else if (argvars[0].v_type != VAR_LIST) { EMSG2(_(e_listdictarg), "remove()"); } else if ((l = argvars[0].vval.v_list) != NULL - && !tv_check_lock(l->lv_lock, arg_errmsg, arg_errmsg_len)) { + && !tv_check_lock(l->lv_lock, arg_errmsg, TV_TRANSLATE)) { bool error = false; idx = tv_get_number_chk(&argvars[1], &error); @@ -13503,14 +13497,12 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void f_reverse(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - const char *const arg_errmsg = _("reverse() argument"); - const size_t arg_errmsg_len = strlen(arg_errmsg); - list_T *l; if (argvars[0].v_type != VAR_LIST) { EMSG2(_(e_listarg), "reverse()"); } else if ((l = argvars[0].vval.v_list) != NULL - && !tv_check_lock(l->lv_lock, arg_errmsg, arg_errmsg_len)) { + && !tv_check_lock(l->lv_lock, N_("reverse() argument"), + TV_TRANSLATE)) { listitem_T *li = l->lv_last; l->lv_first = l->lv_last = NULL; l->lv_len = 0; @@ -15202,16 +15194,14 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) sortinfo = &info; const char *const arg_errmsg = (sort - ? _("sort() argument") - : _("uniq() argument")); - const size_t arg_errmsg_len = strlen(arg_errmsg); + ? N_("sort() argument") + : N_("uniq() argument")); if (argvars[0].v_type != VAR_LIST) { EMSG2(_(e_listarg), sort ? "sort()" : "uniq()"); } else { l = argvars[0].vval.v_list; - if (l == NULL - || tv_check_lock(l->lv_lock, arg_errmsg, arg_errmsg_len)) { + if (l == NULL || tv_check_lock(l->lv_lock, arg_errmsg, TV_TRANSLATE)) { goto theend; } rettv->vval.v_list = l; @@ -18876,24 +18866,37 @@ static void set_var(const char *name, const size_t name_len, typval_T *const tv, /// /// @param[in] flags di_flags attribute value. /// @param[in] name Variable name, for use in error message. -/// @param[in] name_len Variable name length. +/// @param[in] name_len Variable name length. Use #TV_TRANSLATE to translate +/// variable name and compute the length. Use #TV_CSTRING +/// to compute the length with strlen() without +/// translating. /// /// @return True if variable is read-only: either always or in sandbox when /// sandbox is enabled, false otherwise. -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 *name, + size_t name_len) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { + const char *error_message = NULL; if (flags & DI_FLAGS_RO) { - emsgf(_(e_readonlyvar), (int)name_len, name); - return true; + error_message = N_(e_readonlyvar); + } else if ((flags & DI_FLAGS_RO_SBX) && sandbox) { + error_message = N_("E794: Cannot set variable in the sandbox: \"%.*s\""); } - if ((flags & DI_FLAGS_RO_SBX) && sandbox) { - emsgf(_("E794: Cannot set variable in the sandbox: \"%.*s\""), - (int)name_len, name); - return true; + + if (error_message == NULL) { + return false; } - return false; + if (name_len == TV_TRANSLATE) { + name = _(name); + name_len = strlen(name); + } else if (name_len == TV_CSTRING) { + name_len = strlen(name); + } + + emsgf(_(error_message), (int)name_len, name); + + return true; } /// Check whether variable is fixed (DI_FLAGS_FIX) @@ -18902,14 +18905,23 @@ bool var_check_ro(const int flags, const char *const name, /// /// @param[in] flags di_flags attribute value. /// @param[in] name Variable name, for use in error message. -/// @param[in] name_len Variable name length. +/// @param[in] name_len Variable name length. Use #TV_TRANSLATE to translate +/// variable name and compute the length. Use #TV_CSTRING +/// to compute the length with strlen() without +/// translating. /// /// @return True if variable is fixed, false otherwise. -static bool var_check_fixed(const int flags, const char *const name, - const size_t name_len) +static bool var_check_fixed(const int flags, const char *name, + size_t name_len) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { if (flags & DI_FLAGS_FIX) { + if (name_len == TV_TRANSLATE) { + name = _(name); + name_len = strlen(name); + } else if (name_len == TV_CSTRING) { + name_len = strlen(name); + } emsgf(_("E795: Cannot delete variable %.*s"), (int)name_len, name); return true; } @@ -19716,12 +19728,12 @@ void ex_function(exarg_T *eap) } if (fudi.fd_di == NULL) { if (tv_check_lock(fudi.fd_dict->dv_lock, (const char *)eap->arg, - STRLEN(eap->arg))) { + TV_CSTRING)) { // Can't add a function to a locked dictionary goto erret; } } else if (tv_check_lock(fudi.fd_di->di_tv.v_lock, (const char *)eap->arg, - STRLEN(eap->arg))) { + TV_CSTRING)) { // Can't change an existing function if it is locked goto erret; } diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index eb6db9547b..c29c67124f 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -2045,11 +2045,14 @@ bool tv_islocked(const typval_T *const tv) /// /// @param[in] lock Lock status. /// @param[in] name Variable name, used in the error message. -/// @param[in] name_len Variable name length. +/// @param[in] name_len Variable name length. Use #TV_TRANSLATE to translate +/// variable name and compute the length. Use #TV_CSTRING +/// to compute the length with strlen() without +/// translating. /// /// @return true if variable is locked, false otherwise. -bool tv_check_lock(const VarLockStatus lock, const char *const name, - const size_t name_len) +bool tv_check_lock(const VarLockStatus lock, const char *name, + size_t name_len) FUNC_ATTR_WARN_UNUSED_RESULT { const char *error_message = NULL; @@ -2068,10 +2071,17 @@ bool tv_check_lock(const VarLockStatus lock, const char *const name, } assert(error_message != NULL); - const char *const unknown_name = _("Unknown"); + if (name == NULL) { + name = _("Unknown"); + name_len = strlen(name); + } else if (name_len == TV_TRANSLATE) { + name = _(name); + name_len = strlen(name); + } else if (name_len == TV_CSTRING) { + name_len = strlen(name); + } - emsgf(_(error_message), (name != NULL ? name_len : strlen(unknown_name)), - (name != NULL ? name : unknown_name)); + emsgf(_(error_message), (int)name_len, name); return true; } diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 7eab22bc12..df46222067 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -423,6 +423,17 @@ static inline bool tv_is_func(const typval_T tv) return tv.v_type == VAR_FUNC || tv.v_type == VAR_PARTIAL; } +/// Specify that argument needs to be translated +/// +/// Used for size_t length arguments to avoid calling gettext() and strlen() +/// unless needed. +#define TV_TRANSLATE (SIZE_MAX) + +/// Specify that argument is a NUL-terminated C string +/// +/// Used for size_t length arguments to avoid calling strlen() unless needed. +#define TV_CSTRING (SIZE_MAX - 1) + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval/typval.h.generated.h" #endif From 276ee1f7fb989b931a9ddfabfd4aaf1782bcbb77 Mon Sep 17 00:00:00 2001 From: ZyX Date: Thu, 13 Apr 2017 23:42:51 +0300 Subject: [PATCH 2/5] eval: Add comment regarding why special values are needed --- src/nvim/eval.c | 12 ++++++++++++ src/nvim/eval/typval.c | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index e81378bcaa..281b80a915 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -18871,6 +18871,12 @@ static void set_var(const char *name, const size_t name_len, typval_T *const tv, /// to compute the length with strlen() without /// translating. /// +/// Both #TV_… values are used for optimization purposes: +/// variable name with its length is needed only in case +/// of error, when no error occurs computing them is +/// a waste of CPU resources. This especially applies to +/// gettext. +/// /// @return True if variable is read-only: either always or in sandbox when /// sandbox is enabled, false otherwise. bool var_check_ro(const int flags, const char *name, @@ -18910,6 +18916,12 @@ bool var_check_ro(const int flags, const char *name, /// to compute the length with strlen() without /// translating. /// +/// Both #TV_… values are used for optimization purposes: +/// variable name with its length is needed only in case +/// of error, when no error occurs computing them is +/// a waste of CPU resources. This especially applies to +/// gettext. +/// /// @return True if variable is fixed, false otherwise. static bool var_check_fixed(const int flags, const char *name, size_t name_len) diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index c29c67124f..b70554c1ef 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -2050,6 +2050,12 @@ bool tv_islocked(const typval_T *const tv) /// to compute the length with strlen() without /// translating. /// +/// Both #TV_… values are used for optimization purposes: +/// variable name with its length is needed only in case +/// of error, when no error occurs computing them is +/// a waste of CPU resources. This especially applies to +/// gettext. +/// /// @return true if variable is locked, false otherwise. bool tv_check_lock(const VarLockStatus lock, const char *name, size_t name_len) From b54e5c220f0b1bff31ce65c6988f70cbb9780b5e Mon Sep 17 00:00:00 2001 From: ZyX Date: Fri, 14 Apr 2017 00:12:05 +0300 Subject: [PATCH 3/5] unittests: Add a test for TV_CSTRING MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not using enum{} because SIZE_MAX exceeds integer and I do not really like how enum definition is described in C99: 1. Even though all values must fit into the chosen type (6.7.2.2, p 4) the type to choose is still implementation-defined. 2. 6.4.4.3 explicitly states that “an identifier declared as an enumeration constant has type `int`”. So it looks like “no matter what type was chosen for enumeration, constants will be integers”. Yet the following simple program: #include #include #include enum { X=SIZE_MAX }; int main(int argc, char **argv) { printf("x:%zu m:%zu t:%zu v:%zu", sizeof(X), sizeof(SIZE_MAX), sizeof(size_t), (size_t)X); } yields one of the following using different compilers: - clang/gcc/pathcc: `x:8 m:8 t:8 v:18446744073709551615` - pcc/tcc: `x:4 m:8 t:8 v:1844674407370955161` If I remove the cast of X to size_t then pcc/tcc both yield `x:4 m:8 t:8 v:4294967295`, other compilers’ output does not change. All compilers were called with `$compiler -std=c99 -xc -` (feeding program from echo), except for `tcc` which has missing `-std=c99`. `pcc` seems to ignore the argument though: it is perfectly fine with `-std=c1000`. --- src/nvim/eval/typval.h | 7 +++++++ test/unit/eval/typval_spec.lua | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index df46222067..0f659727ee 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -17,6 +17,7 @@ #include "nvim/pos.h" // for linenr_T #include "nvim/gettext.h" #include "nvim/message.h" +#include "nvim/macros.h" /// Type used for VimL VAR_NUMBER values typedef int varnumber_T; @@ -434,6 +435,12 @@ static inline bool tv_is_func(const typval_T tv) /// Used for size_t length arguments to avoid calling strlen() unless needed. #define TV_CSTRING (SIZE_MAX - 1) +#ifdef UNIT_TESTING +// Do not use enum constants, see commit message. +EXTERN const size_t kTVCstring INIT(= TV_CSTRING); +EXTERN const size_t kTVTranslate INIT(= TV_TRANSLATE); +#endif + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval/typval.h.generated.h" #endif diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua index a1edfcfb7c..6308ae7367 100644 --- a/test/unit/eval/typval_spec.lua +++ b/test/unit/eval/typval_spec.lua @@ -2450,6 +2450,10 @@ describe('typval.c', function() 'E741: Value is locked: Unknown')) eq(true, tv_check_lock(lib.VAR_FIXED, nil, 0, 'E742: Cannot change value of Unknown')) + eq(true, tv_check_lock(lib.VAR_LOCKED, nil, lib.kTVCstring, + 'E741: Value is locked: Unknown')) + eq(true, tv_check_lock(lib.VAR_FIXED, 'test', lib.kTVCstring, + 'E742: Cannot change value of test')) end) end) describe('equal()', function() From 31fd6d4bbf80d0f50893ab6144aa5eb70c95c351 Mon Sep 17 00:00:00 2001 From: ZyX Date: Fri, 14 Apr 2017 23:57:44 +0300 Subject: [PATCH 4/5] eval/typval: Do not translate tv_clear argument, this is useless --- src/nvim/eval/typval.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index b70554c1ef..d5177138b0 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1799,11 +1799,13 @@ static inline void _nothing_conv_dict_end(typval_T *const tv, #define TYPVAL_ENCODE_NAME nothing #define TYPVAL_ENCODE_FIRST_ARG_TYPE const void *const #define TYPVAL_ENCODE_FIRST_ARG_NAME ignored +#define TYPVAL_ENCODE_TRANSLATE_OBJECT_NAME #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_TRANSLATE_OBJECT_NAME #undef TYPVAL_ENCODE_ALLOW_SPECIALS #undef TYPVAL_ENCODE_CONV_NIL @@ -1837,12 +1839,14 @@ static inline void _nothing_conv_dict_end(typval_T *const tv, /// @param[in,out] tv Value to free. void tv_clear(typval_T *const tv) { - static char *objname = NULL; // cached because gettext() is slow. #6437 - if (objname == NULL) { - objname = xstrdup(_("tv_clear() argument")); - } if (tv != NULL && tv->v_type != VAR_UNKNOWN) { - const int evn_ret = encode_vim_to_nothing(NULL, tv, objname); + // WARNING: do not translate the string here, gettext is slow and function + // is used *very* often. At the current state encode_vim_to_nothing() does + // not error out and does not use the argument anywhere. + // + // If situation changes and this argument will be used, translate it in the + // place where it is used. + const int evn_ret = encode_vim_to_nothing(NULL, tv, "tv_clear() argument"); (void)evn_ret; assert(evn_ret == OK); } From c289986c89dd0189ed8ab709bf2eb822c493542a Mon Sep 17 00:00:00 2001 From: ZyX Date: Sat, 15 Apr 2017 00:08:50 +0300 Subject: [PATCH 5/5] =?UTF-8?q?eval/encode:=20Do=20translate=20=E2=80=9C?= =?UTF-8?q?=E2=80=A6=20argument=E2=80=9D=20strings,=20but=20only=20in=20co?= =?UTF-8?q?nv=5Ferror?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nvim/eval/encode.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index d74913a481..c058c3a9c0 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -179,9 +179,9 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack, } } } - EMSG3(msg, objname, (kv_size(*mpstack) == 0 - ? _("itself") - : (char *) msg_ga.ga_data)); + emsgf(msg, _(objname), (kv_size(*mpstack) == 0 + ? _("itself") + : (char *)msg_ga.ga_data)); ga_clear(&msg_ga); return FAIL; } @@ -790,7 +790,7 @@ char *encode_tv2string(typval_T *tv, size_t *len) garray_T ga; ga_init(&ga, (int)sizeof(char), 80); const int evs_ret = encode_vim_to_string(&ga, tv, - "encode_tv2string() argument"); + N_("encode_tv2string() argument")); (void)evs_ret; assert(evs_ret == OK); did_echo_string_emsg = false; @@ -818,7 +818,7 @@ char *encode_tv2echo(typval_T *tv, size_t *len) ga_concat(&ga, tv->vval.v_string); } } else { - const int eve_ret = encode_vim_to_echo(&ga, tv, ":echo argument"); + const int eve_ret = encode_vim_to_echo(&ga, tv, N_(":echo argument")); (void)eve_ret; assert(eve_ret == OK); } @@ -841,7 +841,8 @@ char *encode_tv2json(typval_T *tv, size_t *len) { garray_T ga; ga_init(&ga, (int)sizeof(char), 80); - const int evj_ret = encode_vim_to_json(&ga, tv, "encode_tv2json() argument"); + const int evj_ret = encode_vim_to_json(&ga, tv, + N_("encode_tv2json() argument")); if (!evj_ret) { ga_clear(&ga); }