From ba2f615cd40d5d809d1a141c7b098e3bd22ff7bb Mon Sep 17 00:00:00 2001 From: ZyX Date: Sat, 16 Jul 2016 02:26:04 +0300 Subject: functests: Test for error conditions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During testing found the following bugs: 1. msgpack-gen.lua script is completely unprepared for Float values either in return type or in arguments. Specifically: 1. At the time of writing relevant code FLOAT_OBJ did not exist as well as FLOATING_OBJ, but it would be used by msgpack-gen.lua should return type be Float. I added FLOATING_OBJ macros later because did not know that msgpack-gen.lua uses these _OBJ macros, otherwise it would be FLOAT_OBJ. 2. msgpack-gen.lua should use .data.floating in place of .data.float. But it did not expect that .data subattribute may have name different from lowercased type name. 2. vim_replace_termcodes returned its argument as-is if it receives an empty string (as well as _vim_id*() functions did). But if something in returned argument lives in an allocated memory such action will cause double free: once when freeing arguments, then when freeing return value. It did not cause problems yet because msgpack bindings return empty string as {NULL, 0} and nothing was actually allocated. 3. New code in msgpack-gen.lua popped arguments in reversed order, making lua bindings’ signatures be different from API ones. --- src/nvim/api/private/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 7efa086af2..23d1540e2f 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -351,7 +351,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) #define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER TYPVAL_ENCODE_CONV_NUMBER #define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ - kv_push(edata->stack, FLOATING_OBJ((Float)(flt))) + kv_push(edata->stack, FLOAT_OBJ((Float)(flt))) #define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \ do { \ -- cgit From 62fde319360e27a86c0deba0053ff230f80ca772 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 29 Jan 2017 01:29:51 +0300 Subject: api: Also shift numbers in api_metadata output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes problem introduced by “api: Allow kObjectTypeNil to be zero without breaking compatibility”: apparently there are clients which use metadata and there are which aren’t. For the first that commit would not be needed, for the second that commit misses this critical piece. --- src/nvim/api/private/helpers.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 23d1540e2f..373e509120 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -851,15 +851,18 @@ static void init_type_metadata(Dictionary *metadata) Dictionary types = ARRAY_DICT_INIT; Dictionary buffer_metadata = ARRAY_DICT_INIT; - PUT(buffer_metadata, "id", INTEGER_OBJ(kObjectTypeBuffer)); + PUT(buffer_metadata, "id", + INTEGER_OBJ(kObjectTypeBuffer - EXT_OBJECT_TYPE_SHIFT)); PUT(buffer_metadata, "prefix", STRING_OBJ(cstr_to_string("nvim_buf_"))); Dictionary window_metadata = ARRAY_DICT_INIT; - PUT(window_metadata, "id", INTEGER_OBJ(kObjectTypeWindow)); + PUT(window_metadata, "id", + INTEGER_OBJ(kObjectTypeWindow - EXT_OBJECT_TYPE_SHIFT)); PUT(window_metadata, "prefix", STRING_OBJ(cstr_to_string("nvim_win_"))); Dictionary tabpage_metadata = ARRAY_DICT_INIT; - PUT(tabpage_metadata, "id", INTEGER_OBJ(kObjectTypeTabpage)); + PUT(tabpage_metadata, "id", + INTEGER_OBJ(kObjectTypeTabpage - EXT_OBJECT_TYPE_SHIFT)); PUT(tabpage_metadata, "prefix", STRING_OBJ(cstr_to_string("nvim_tabpage_"))); PUT(types, "Buffer", DICTIONARY_OBJ(buffer_metadata)); -- cgit From fb146e80aa1ead96518f38b9684e39249bc83485 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 26 Jul 2016 23:16:23 +0300 Subject: eval: Split eval.c into smaller files --- src/nvim/api/private/helpers.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 7efa086af2..ff45cad8f5 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,7 +88,7 @@ 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); + hashitem_T *hi = hash_find(&dict->dv_hashtab, (char_u *)key.data); if (HASHITEM_EMPTY(hi)) { api_set_error(err, Validation, _("Key not found")); @@ -177,13 +178,13 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, 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); // Clear the temporary variable - clear_tv(&tv); + tv_clear(&tv); } return rv; @@ -682,20 +683,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++; -- cgit From e18a5783080f7c94f408ec5f53dedffdb69789e1 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sat, 20 Aug 2016 22:24:34 +0300 Subject: *: Move some dictionary functions to typval.h and use char* Also fixes buffer reusage in setmatches() and complete(). --- src/nvim/api/private/helpers.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index ff45cad8f5..6b17ba1a11 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -88,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, (char_u *)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); } @@ -130,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) { @@ -156,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 @@ -171,8 +168,8 @@ 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) { @@ -706,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]; @@ -716,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++; @@ -960,11 +957,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; } -- cgit From 28dafe3ff0b0dc082fb62b2251fd64a167ce7188 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 21 Aug 2016 08:16:47 +0300 Subject: eval,*: Move get_tv_string to typval.c Function was renamed and changed to return `const char *`. --- src/nvim/api/private/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 6b17ba1a11..2c8a56cc1a 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -625,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. -- cgit From 2ad4fba46db26d0724106b194f7cb628fb9b02e8 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 11 Sep 2016 03:37:03 +0300 Subject: eval: Move copy_tv to eval/typval --- src/nvim/api/private/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 2c8a56cc1a..b245132ba7 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -179,7 +179,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, } // Update the value - copy_tv(&tv, &di->di_tv); + tv_copy(&tv, &di->di_tv); // Clear the temporary variable tv_clear(&tv); } -- cgit From eb0e94f71b1f44cebf7ae5c1bcff348264af6cef Mon Sep 17 00:00:00 2001 From: Jakob Schnitzer Date: Thu, 30 Mar 2017 22:03:52 +0200 Subject: api: {get,set}_option should {get,set} global value of local options (#6405) - nvim_get_option should return the global default of a local option. - nvim_set_option should set the global default of a local option. --- src/nvim/api/private/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index b245132ba7..fe15b28041 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -289,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) { -- cgit From c2f3e361c52ec4e7149ea1d8c6a1202e0873da8e Mon Sep 17 00:00:00 2001 From: ZyX Date: Wed, 19 Apr 2017 19:11:50 +0300 Subject: *: Add comment to all C files --- src/nvim/api/private/helpers.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index fe15b28041..5877b848fc 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1,3 +1,6 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + #include #include #include -- cgit From 5c9860a0a2bf27d409c986673f0a74542561c4c3 Mon Sep 17 00:00:00 2001 From: Sander Bosma Date: Wed, 1 Mar 2017 10:43:47 +0100 Subject: api: Do not truncate errors <1 MB. #6237 Closes #5984 --- src/nvim/api/private/helpers.c | 113 +++++++++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 44 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 5877b848fc..e6632525e1 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -61,7 +61,7 @@ bool try_end(Error *err) discard_current_exception(); } - api_set_error(err, Exception, _("Keyboard interrupt")); + _api_set_error(err, kErrorTypeException, _("Keyboard interrupt")); got_int = false; } else if (msg_list != NULL && *msg_list != NULL) { int should_free; @@ -69,15 +69,14 @@ bool try_end(Error *err) ET_ERROR, NULL, &should_free); - xstrlcpy(err->msg, msg, sizeof(err->msg)); - err->set = true; + _api_set_error(err, err->type, "%s", msg); free_global_msglist(); if (should_free) { xfree(msg); } } else if (did_throw) { - api_set_error(err, Exception, "%s", current_exception->value); + _api_set_error(err, kErrorTypeException, "%s", current_exception->value); discard_current_exception(); } @@ -94,7 +93,7 @@ Object dict_get_value(dict_T *dict, String key, Error *err) dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size); if (di == NULL) { - api_set_error(err, Validation, _("Key not found")); + _api_set_error(err, kErrorTypeValidation, _("Key not found")); return (Object) OBJECT_INIT; } @@ -118,17 +117,17 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, Object rv = OBJECT_INIT; if (dict->dv_lock) { - api_set_error(err, Exception, _("Dictionary is locked")); + _api_set_error(err, kErrorTypeException, _("Dictionary is locked")); return rv; } if (key.size == 0) { - api_set_error(err, Validation, _("Empty variable names aren't allowed")); + _api_set_error(err, kErrorTypeValidation, _("Empty variable names aren't allowed")); return rv; } if (key.size > INT_MAX) { - api_set_error(err, Validation, _("Key length is too high")); + _api_set_error(err, kErrorTypeValidation, _("Key length is too high")); return rv; } @@ -136,13 +135,13 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, if (di != NULL) { if (di->di_flags & DI_FLAGS_RO) { - api_set_error(err, Exception, _("Key is read-only: %s"), key.data); + _api_set_error(err, kErrorTypeException, _("Key is read-only: %s"), key.data); return rv; } else if (di->di_flags & DI_FLAGS_FIX) { - api_set_error(err, Exception, _("Key is fixed: %s"), key.data); + _api_set_error(err, kErrorTypeException, _("Key is fixed: %s"), key.data); return rv; } else if (di->di_flags & DI_FLAGS_LOCK) { - api_set_error(err, Exception, _("Key is locked: %s"), key.data); + _api_set_error(err, kErrorTypeException, _("Key is locked: %s"), key.data); return rv; } } @@ -151,7 +150,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, // Delete the key if (di == NULL) { // Doesn't exist, fail - api_set_error(err, Validation, _("Key \"%s\" doesn't exist"), key.data); + _api_set_error(err, kErrorTypeValidation, _("Key \"%s\" doesn't exist"), key.data); } else { // Return the old value if (retval) { @@ -203,7 +202,7 @@ Object get_option_from(void *from, int type, String name, Error *err) Object rv = OBJECT_INIT; if (name.size == 0) { - api_set_error(err, Validation, _("Empty option name")); + _api_set_error(err, kErrorTypeValidation, _("Empty option name")); return rv; } @@ -214,8 +213,8 @@ Object get_option_from(void *from, int type, String name, Error *err) type, from); if (!flags) { - api_set_error(err, - Validation, + _api_set_error(err, + kErrorTypeValidation, _("Invalid option name \"%s\""), name.data); return rv; @@ -233,14 +232,14 @@ Object get_option_from(void *from, int type, String name, Error *err) rv.data.string.data = stringval; rv.data.string.size = strlen(stringval); } else { - api_set_error(err, - Exception, + _api_set_error(err, + kErrorTypeException, _("Unable to get value for option \"%s\""), name.data); } } else { - api_set_error(err, - Exception, + _api_set_error(err, + kErrorTypeException, _("Unknown type for option \"%s\""), name.data); } @@ -258,15 +257,15 @@ Object get_option_from(void *from, int type, String name, Error *err) void set_option_to(void *to, int type, String name, Object value, Error *err) { if (name.size == 0) { - api_set_error(err, Validation, _("Empty option name")); + _api_set_error(err, kErrorTypeValidation, _("Empty option name")); return; } int flags = get_option_value_strict(name.data, NULL, NULL, type, to); if (flags == 0) { - api_set_error(err, - Validation, + _api_set_error(err, + kErrorTypeValidation, _("Invalid option name \"%s\""), name.data); return; @@ -274,14 +273,14 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) if (value.type == kObjectTypeNil) { if (type == SREQ_GLOBAL) { - api_set_error(err, - Exception, + _api_set_error(err, + kErrorTypeException, _("Unable to unset option \"%s\""), name.data); return; } else if (!(flags & SOPT_GLOBAL)) { - api_set_error(err, - Exception, + _api_set_error(err, + kErrorTypeException, _("Cannot unset option \"%s\" " "because it doesn't have a global value"), name.data); @@ -296,8 +295,8 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) if (flags & SOPT_BOOL) { if (value.type != kObjectTypeBoolean) { - api_set_error(err, - Validation, + _api_set_error(err, + kErrorTypeValidation, _("Option \"%s\" requires a boolean value"), name.data); return; @@ -307,16 +306,16 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) set_option_value_for(name.data, val, NULL, opt_flags, type, to, err); } else if (flags & SOPT_NUM) { if (value.type != kObjectTypeInteger) { - api_set_error(err, - Validation, + _api_set_error(err, + kErrorTypeValidation, _("Option \"%s\" requires an integer value"), name.data); return; } if (value.data.integer > INT_MAX || value.data.integer < INT_MIN) { - api_set_error(err, - Validation, + _api_set_error(err, + kErrorTypeValidation, _("Value for option \"%s\" is outside range"), name.data); return; @@ -326,8 +325,8 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) set_option_value_for(name.data, val, NULL, opt_flags, type, to, err); } else { if (value.type != kObjectTypeString) { - api_set_error(err, - Validation, + _api_set_error(err, + kErrorTypeValidation, _("Option \"%s\" requires a string value"), name.data); return; @@ -561,13 +560,13 @@ buf_T *find_buffer_by_handle(Buffer buffer, Error *err) buf_T *rv = handle_get_buffer(buffer); if (!rv) { - api_set_error(err, Validation, _("Invalid buffer id")); + _api_set_error(err, kErrorTypeValidation, _("Invalid buffer id")); } return rv; } -win_T * find_window_by_handle(Window window, Error *err) +win_T *find_window_by_handle(Window window, Error *err) { if (window == 0) { return curwin; @@ -576,13 +575,13 @@ win_T * find_window_by_handle(Window window, Error *err) win_T *rv = handle_get_window(window); if (!rv) { - api_set_error(err, Validation, _("Invalid window id")); + _api_set_error(err, kErrorTypeValidation, _("Invalid window id")); } return rv; } -tabpage_T * find_tab_by_handle(Tabpage tabpage, Error *err) +tabpage_T *find_tab_by_handle(Tabpage tabpage, Error *err) { if (tabpage == 0) { return curtab; @@ -591,7 +590,7 @@ tabpage_T * find_tab_by_handle(Tabpage tabpage, Error *err) tabpage_T *rv = handle_get_tabpage(tabpage); if (!rv) { - api_set_error(err, Validation, _("Invalid tabpage id")); + _api_set_error(err, kErrorTypeValidation, _("Invalid tabpage id")); } return rv; @@ -659,7 +658,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) case kObjectTypeInteger: if (obj.data.integer > VARNUMBER_MAX || obj.data.integer < VARNUMBER_MIN) { - api_set_error(err, Validation, _("Integer value outside range")); + _api_set_error(err, kErrorTypeValidation, _("Integer value outside range")); return false; } @@ -713,7 +712,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) String key = item.key; if (key.size == 0) { - api_set_error(err, Validation, + _api_set_error(err, kErrorTypeValidation, _("Empty dictionary keys aren't allowed")); // cleanup tv_dict_free(dict); @@ -801,6 +800,12 @@ void api_free_dictionary(Dictionary value) xfree(value.items); } +void api_free_error(Error *value) +{ + xfree(value->msg); + value->msg = NULL; +} + Dictionary api_metadata(void) { static Dictionary metadata = ARRAY_DICT_INIT; @@ -926,8 +931,8 @@ static void set_option_value_for(char *key, if (try_end(err)) { return; } - api_set_error(err, - Exception, + _api_set_error(err, + kErrorTypeException, _("Problem while switching windows")); return; } @@ -965,6 +970,26 @@ static void set_option_value_err(char *key, return; } - api_set_error(err, Exception, "%s", errmsg); + _api_set_error(err, kErrorTypeException, "%s", errmsg); } } + +void _api_set_error(Error *err, ErrorType errType, const char *format, ...) + FUNC_ATTR_NONNULL_ALL +{ + va_list args1; + va_list args2; + va_start(args1, format); + va_copy(args2, args1); + int len = vsnprintf(NULL, 0, format, args1); + va_end(args1); + assert(len >= 0); + // Limit error message to 1 MB. + size_t bufsize = MIN((size_t)len + 1, 1024 * 1024); + err->msg = xmalloc(bufsize); + vsnprintf(err->msg, bufsize, format, args2); + va_end(args2); + + err->set = true; + err->type = errType; +} -- cgit From 2a49163103827465f25810f5f4e3d4305159f209 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 23 Apr 2017 15:59:59 +0200 Subject: api_clear_error() --- src/nvim/api/private/helpers.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index e6632525e1..547ac29bed 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -800,7 +800,8 @@ void api_free_dictionary(Dictionary value) xfree(value.items); } -void api_free_error(Error *value) +void api_clear_error(Error *value) + FUNC_ATTR_NONNULL_ALL { xfree(value->msg); value->msg = NULL; -- cgit From 62c3f436a96e2102ec5c1e3af974c8e57fe4e76c Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 23 Apr 2017 16:43:07 +0200 Subject: api_clear_error: Skip if error was not set. --- src/nvim/api/private/helpers.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 547ac29bed..3bf584ff2f 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -803,6 +803,9 @@ void api_free_dictionary(Dictionary value) void api_clear_error(Error *value) FUNC_ATTR_NONNULL_ALL { + if (!value->set) { + return; + } xfree(value->msg); value->msg = NULL; } -- cgit From 2ed91f222f1dddda10fbdc9cb80df2be7d4c2da3 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 23 Apr 2017 19:58:13 +0200 Subject: api/internal: Remove `set` field from Error type. --- src/nvim/api/private/helpers.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 3bf584ff2f..58534d78a0 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -69,7 +69,7 @@ bool try_end(Error *err) ET_ERROR, NULL, &should_free); - _api_set_error(err, err->type, "%s", msg); + _api_set_error(err, kErrorTypeException, "%s", msg); free_global_msglist(); if (should_free) { @@ -80,7 +80,7 @@ bool try_end(Error *err) discard_current_exception(); } - return err->set; + return ERROR_SET(err); } /// Recursively expands a vimscript value in a dict @@ -803,11 +803,12 @@ void api_free_dictionary(Dictionary value) void api_clear_error(Error *value) FUNC_ATTR_NONNULL_ALL { - if (!value->set) { + if (!ERROR_SET(value)) { return; } xfree(value->msg); value->msg = NULL; + value->type = kErrorTypeNone; } Dictionary api_metadata(void) @@ -953,7 +954,7 @@ static void set_option_value_for(char *key, break; } - if (err->set) { + if (ERROR_SET(err)) { return; } @@ -981,6 +982,7 @@ static void set_option_value_err(char *key, void _api_set_error(Error *err, ErrorType errType, const char *format, ...) FUNC_ATTR_NONNULL_ALL { + assert(kErrorTypeNone != errType); va_list args1; va_list args2; va_start(args1, format); @@ -994,6 +996,5 @@ void _api_set_error(Error *err, ErrorType errType, const char *format, ...) vsnprintf(err->msg, bufsize, format, args2); va_end(args2); - err->set = true; err->type = errType; } -- cgit From 3fbc660d57f4726044662bde1bf52c527e45fb98 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 23 Apr 2017 21:54:44 +0200 Subject: api_set_error(): rename --- src/nvim/api/private/helpers.c | 62 +++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 58534d78a0..d7274920b6 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -61,7 +61,7 @@ bool try_end(Error *err) discard_current_exception(); } - _api_set_error(err, kErrorTypeException, _("Keyboard interrupt")); + api_set_error(err, kErrorTypeException, _("Keyboard interrupt")); got_int = false; } else if (msg_list != NULL && *msg_list != NULL) { int should_free; @@ -69,14 +69,14 @@ bool try_end(Error *err) ET_ERROR, NULL, &should_free); - _api_set_error(err, kErrorTypeException, "%s", msg); + api_set_error(err, kErrorTypeException, "%s", msg); free_global_msglist(); if (should_free) { xfree(msg); } } else if (did_throw) { - _api_set_error(err, kErrorTypeException, "%s", current_exception->value); + api_set_error(err, kErrorTypeException, "%s", current_exception->value); discard_current_exception(); } @@ -93,7 +93,7 @@ Object dict_get_value(dict_T *dict, String key, Error *err) dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size); if (di == NULL) { - _api_set_error(err, kErrorTypeValidation, _("Key not found")); + api_set_error(err, kErrorTypeValidation, _("Key not found")); return (Object) OBJECT_INIT; } @@ -117,17 +117,17 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, Object rv = OBJECT_INIT; if (dict->dv_lock) { - _api_set_error(err, kErrorTypeException, _("Dictionary is locked")); + api_set_error(err, kErrorTypeException, _("Dictionary is locked")); return rv; } if (key.size == 0) { - _api_set_error(err, kErrorTypeValidation, _("Empty variable names aren't allowed")); + api_set_error(err, kErrorTypeValidation, _("Empty variable names aren't allowed")); return rv; } if (key.size > INT_MAX) { - _api_set_error(err, kErrorTypeValidation, _("Key length is too high")); + api_set_error(err, kErrorTypeValidation, _("Key length is too high")); return rv; } @@ -135,13 +135,13 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, if (di != NULL) { if (di->di_flags & DI_FLAGS_RO) { - _api_set_error(err, kErrorTypeException, _("Key is read-only: %s"), key.data); + api_set_error(err, kErrorTypeException, _("Key is read-only: %s"), key.data); return rv; } else if (di->di_flags & DI_FLAGS_FIX) { - _api_set_error(err, kErrorTypeException, _("Key is fixed: %s"), key.data); + api_set_error(err, kErrorTypeException, _("Key is fixed: %s"), key.data); return rv; } else if (di->di_flags & DI_FLAGS_LOCK) { - _api_set_error(err, kErrorTypeException, _("Key is locked: %s"), key.data); + api_set_error(err, kErrorTypeException, _("Key is locked: %s"), key.data); return rv; } } @@ -150,7 +150,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, // Delete the key if (di == NULL) { // Doesn't exist, fail - _api_set_error(err, kErrorTypeValidation, _("Key \"%s\" doesn't exist"), key.data); + api_set_error(err, kErrorTypeValidation, _("Key \"%s\" doesn't exist"), key.data); } else { // Return the old value if (retval) { @@ -202,7 +202,7 @@ Object get_option_from(void *from, int type, String name, Error *err) Object rv = OBJECT_INIT; if (name.size == 0) { - _api_set_error(err, kErrorTypeValidation, _("Empty option name")); + api_set_error(err, kErrorTypeValidation, _("Empty option name")); return rv; } @@ -213,7 +213,7 @@ Object get_option_from(void *from, int type, String name, Error *err) type, from); if (!flags) { - _api_set_error(err, + api_set_error(err, kErrorTypeValidation, _("Invalid option name \"%s\""), name.data); @@ -232,13 +232,13 @@ Object get_option_from(void *from, int type, String name, Error *err) rv.data.string.data = stringval; rv.data.string.size = strlen(stringval); } else { - _api_set_error(err, + api_set_error(err, kErrorTypeException, _("Unable to get value for option \"%s\""), name.data); } } else { - _api_set_error(err, + api_set_error(err, kErrorTypeException, _("Unknown type for option \"%s\""), name.data); @@ -257,14 +257,14 @@ Object get_option_from(void *from, int type, String name, Error *err) void set_option_to(void *to, int type, String name, Object value, Error *err) { if (name.size == 0) { - _api_set_error(err, kErrorTypeValidation, _("Empty option name")); + api_set_error(err, kErrorTypeValidation, _("Empty option name")); return; } int flags = get_option_value_strict(name.data, NULL, NULL, type, to); if (flags == 0) { - _api_set_error(err, + api_set_error(err, kErrorTypeValidation, _("Invalid option name \"%s\""), name.data); @@ -273,13 +273,13 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) if (value.type == kObjectTypeNil) { if (type == SREQ_GLOBAL) { - _api_set_error(err, + api_set_error(err, kErrorTypeException, _("Unable to unset option \"%s\""), name.data); return; } else if (!(flags & SOPT_GLOBAL)) { - _api_set_error(err, + api_set_error(err, kErrorTypeException, _("Cannot unset option \"%s\" " "because it doesn't have a global value"), @@ -295,7 +295,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) if (flags & SOPT_BOOL) { if (value.type != kObjectTypeBoolean) { - _api_set_error(err, + api_set_error(err, kErrorTypeValidation, _("Option \"%s\" requires a boolean value"), name.data); @@ -306,7 +306,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) set_option_value_for(name.data, val, NULL, opt_flags, type, to, err); } else if (flags & SOPT_NUM) { if (value.type != kObjectTypeInteger) { - _api_set_error(err, + api_set_error(err, kErrorTypeValidation, _("Option \"%s\" requires an integer value"), name.data); @@ -314,7 +314,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) } if (value.data.integer > INT_MAX || value.data.integer < INT_MIN) { - _api_set_error(err, + api_set_error(err, kErrorTypeValidation, _("Value for option \"%s\" is outside range"), name.data); @@ -325,7 +325,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) set_option_value_for(name.data, val, NULL, opt_flags, type, to, err); } else { if (value.type != kObjectTypeString) { - _api_set_error(err, + api_set_error(err, kErrorTypeValidation, _("Option \"%s\" requires a string value"), name.data); @@ -560,7 +560,7 @@ buf_T *find_buffer_by_handle(Buffer buffer, Error *err) buf_T *rv = handle_get_buffer(buffer); if (!rv) { - _api_set_error(err, kErrorTypeValidation, _("Invalid buffer id")); + api_set_error(err, kErrorTypeValidation, _("Invalid buffer id")); } return rv; @@ -575,7 +575,7 @@ win_T *find_window_by_handle(Window window, Error *err) win_T *rv = handle_get_window(window); if (!rv) { - _api_set_error(err, kErrorTypeValidation, _("Invalid window id")); + api_set_error(err, kErrorTypeValidation, _("Invalid window id")); } return rv; @@ -590,7 +590,7 @@ tabpage_T *find_tab_by_handle(Tabpage tabpage, Error *err) tabpage_T *rv = handle_get_tabpage(tabpage); if (!rv) { - _api_set_error(err, kErrorTypeValidation, _("Invalid tabpage id")); + api_set_error(err, kErrorTypeValidation, _("Invalid tabpage id")); } return rv; @@ -658,7 +658,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) case kObjectTypeInteger: if (obj.data.integer > VARNUMBER_MAX || obj.data.integer < VARNUMBER_MIN) { - _api_set_error(err, kErrorTypeValidation, _("Integer value outside range")); + api_set_error(err, kErrorTypeValidation, _("Integer value outside range")); return false; } @@ -712,7 +712,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) String key = item.key; if (key.size == 0) { - _api_set_error(err, kErrorTypeValidation, + api_set_error(err, kErrorTypeValidation, _("Empty dictionary keys aren't allowed")); // cleanup tv_dict_free(dict); @@ -936,7 +936,7 @@ static void set_option_value_for(char *key, if (try_end(err)) { return; } - _api_set_error(err, + api_set_error(err, kErrorTypeException, _("Problem while switching windows")); return; @@ -975,11 +975,11 @@ static void set_option_value_err(char *key, return; } - _api_set_error(err, kErrorTypeException, "%s", errmsg); + api_set_error(err, kErrorTypeException, "%s", errmsg); } } -void _api_set_error(Error *err, ErrorType errType, const char *format, ...) +void api_set_error(Error *err, ErrorType errType, const char *format, ...) FUNC_ATTR_NONNULL_ALL { assert(kErrorTypeNone != errType); -- cgit From 086c354a0aad2769042dc91bf5bad021109f56e4 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 23 Apr 2017 22:30:08 +0200 Subject: api: Do not translate error messages. Also re-word some error messages: - "Key does not exist: %s" - "Invalid channel: %" - "Request array size must be 4 (request) or 3 (notification)" - "String cannot contain newlines" References #6150 --- src/nvim/api/private/helpers.c | 60 ++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 29 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index d7274920b6..69cb19c14f 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -61,7 +61,7 @@ bool try_end(Error *err) discard_current_exception(); } - api_set_error(err, kErrorTypeException, _("Keyboard interrupt")); + api_set_error(err, kErrorTypeException, "Keyboard interrupt"); got_int = false; } else if (msg_list != NULL && *msg_list != NULL) { int should_free; @@ -93,8 +93,8 @@ Object dict_get_value(dict_T *dict, String key, Error *err) dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size); if (di == NULL) { - api_set_error(err, kErrorTypeValidation, _("Key not found")); - return (Object) OBJECT_INIT; + api_set_error(err, kErrorTypeValidation, "Key not found"); + return (Object)OBJECT_INIT; } return vim_to_object(&di->di_tv); @@ -117,17 +117,18 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, Object rv = OBJECT_INIT; if (dict->dv_lock) { - api_set_error(err, kErrorTypeException, _("Dictionary is locked")); + api_set_error(err, kErrorTypeException, "Dictionary is locked"); return rv; } if (key.size == 0) { - api_set_error(err, kErrorTypeValidation, _("Empty variable names aren't allowed")); + api_set_error(err, kErrorTypeValidation, + "Empty variable names aren't allowed"); return rv; } if (key.size > INT_MAX) { - api_set_error(err, kErrorTypeValidation, _("Key length is too high")); + api_set_error(err, kErrorTypeValidation, "Key length is too high"); return rv; } @@ -135,13 +136,13 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, if (di != NULL) { if (di->di_flags & DI_FLAGS_RO) { - api_set_error(err, kErrorTypeException, _("Key is read-only: %s"), key.data); + api_set_error(err, kErrorTypeException, "Key is read-only: %s", key.data); return rv; } else if (di->di_flags & DI_FLAGS_FIX) { - api_set_error(err, kErrorTypeException, _("Key is fixed: %s"), key.data); + api_set_error(err, kErrorTypeException, "Key is fixed: %s", key.data); return rv; } else if (di->di_flags & DI_FLAGS_LOCK) { - api_set_error(err, kErrorTypeException, _("Key is locked: %s"), key.data); + api_set_error(err, kErrorTypeException, "Key is locked: %s", key.data); return rv; } } @@ -150,7 +151,8 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, // Delete the key if (di == NULL) { // Doesn't exist, fail - api_set_error(err, kErrorTypeValidation, _("Key \"%s\" doesn't exist"), key.data); + api_set_error(err, kErrorTypeValidation, "Key does not exist: %s", + key.data); } else { // Return the old value if (retval) { @@ -202,7 +204,7 @@ Object get_option_from(void *from, int type, String name, Error *err) Object rv = OBJECT_INIT; if (name.size == 0) { - api_set_error(err, kErrorTypeValidation, _("Empty option name")); + api_set_error(err, kErrorTypeValidation, "Empty option name"); return rv; } @@ -215,7 +217,7 @@ Object get_option_from(void *from, int type, String name, Error *err) if (!flags) { api_set_error(err, kErrorTypeValidation, - _("Invalid option name \"%s\""), + "Invalid option name \"%s\"", name.data); return rv; } @@ -234,13 +236,13 @@ Object get_option_from(void *from, int type, String name, Error *err) } else { api_set_error(err, kErrorTypeException, - _("Unable to get value for option \"%s\""), + "Unable to get value for option \"%s\"", name.data); } } else { api_set_error(err, kErrorTypeException, - _("Unknown type for option \"%s\""), + "Unknown type for option \"%s\"", name.data); } @@ -257,7 +259,7 @@ Object get_option_from(void *from, int type, String name, Error *err) void set_option_to(void *to, int type, String name, Object value, Error *err) { if (name.size == 0) { - api_set_error(err, kErrorTypeValidation, _("Empty option name")); + api_set_error(err, kErrorTypeValidation, "Empty option name"); return; } @@ -266,7 +268,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) if (flags == 0) { api_set_error(err, kErrorTypeValidation, - _("Invalid option name \"%s\""), + "Invalid option name \"%s\"", name.data); return; } @@ -275,14 +277,14 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) if (type == SREQ_GLOBAL) { api_set_error(err, kErrorTypeException, - _("Unable to unset option \"%s\""), + "Unable to unset option \"%s\"", name.data); return; } else if (!(flags & SOPT_GLOBAL)) { api_set_error(err, kErrorTypeException, - _("Cannot unset option \"%s\" " - "because it doesn't have a global value"), + "Cannot unset option \"%s\" " + "because it doesn't have a global value", name.data); return; } else { @@ -297,7 +299,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) if (value.type != kObjectTypeBoolean) { api_set_error(err, kErrorTypeValidation, - _("Option \"%s\" requires a boolean value"), + "Option \"%s\" requires a boolean value", name.data); return; } @@ -308,7 +310,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) if (value.type != kObjectTypeInteger) { api_set_error(err, kErrorTypeValidation, - _("Option \"%s\" requires an integer value"), + "Option \"%s\" requires an integer value", name.data); return; } @@ -316,7 +318,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) if (value.data.integer > INT_MAX || value.data.integer < INT_MIN) { api_set_error(err, kErrorTypeValidation, - _("Value for option \"%s\" is outside range"), + "Value for option \"%s\" is outside range", name.data); return; } @@ -327,7 +329,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) if (value.type != kObjectTypeString) { api_set_error(err, kErrorTypeValidation, - _("Option \"%s\" requires a string value"), + "Option \"%s\" requires a string value", name.data); return; } @@ -560,7 +562,7 @@ buf_T *find_buffer_by_handle(Buffer buffer, Error *err) buf_T *rv = handle_get_buffer(buffer); if (!rv) { - api_set_error(err, kErrorTypeValidation, _("Invalid buffer id")); + api_set_error(err, kErrorTypeValidation, "Invalid buffer id"); } return rv; @@ -575,7 +577,7 @@ win_T *find_window_by_handle(Window window, Error *err) win_T *rv = handle_get_window(window); if (!rv) { - api_set_error(err, kErrorTypeValidation, _("Invalid window id")); + api_set_error(err, kErrorTypeValidation, "Invalid window id"); } return rv; @@ -590,7 +592,7 @@ tabpage_T *find_tab_by_handle(Tabpage tabpage, Error *err) tabpage_T *rv = handle_get_tabpage(tabpage); if (!rv) { - api_set_error(err, kErrorTypeValidation, _("Invalid tabpage id")); + api_set_error(err, kErrorTypeValidation, "Invalid tabpage id"); } return rv; @@ -658,7 +660,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) case kObjectTypeInteger: if (obj.data.integer > VARNUMBER_MAX || obj.data.integer < VARNUMBER_MIN) { - api_set_error(err, kErrorTypeValidation, _("Integer value outside range")); + api_set_error(err, kErrorTypeValidation, "Integer value outside range"); return false; } @@ -713,7 +715,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) if (key.size == 0) { api_set_error(err, kErrorTypeValidation, - _("Empty dictionary keys aren't allowed")); + "Empty dictionary keys aren't allowed"); // cleanup tv_dict_free(dict); return false; @@ -938,7 +940,7 @@ static void set_option_value_for(char *key, } api_set_error(err, kErrorTypeException, - _("Problem while switching windows")); + "Problem while switching windows"); return; } set_option_value_err(key, numval, stringval, opt_flags, err); -- cgit From 489d10c57c68183c042fd582e6c8eadbb0efc5a7 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 29 Apr 2017 13:06:14 +0200 Subject: api: generate ui events --- src/nvim/api/private/helpers.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 4cc4b600d5..361570bff4 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -885,6 +885,24 @@ static void init_type_metadata(Dictionary *metadata) PUT(*metadata, "types", DICTIONARY_OBJ(types)); } +String copy_string(String str) +{ + if (str.data != NULL) { + return (String){ .data = xmemdupz(str.data, str.size), .size = str.size }; + } else { + return (String)STRING_INIT; + } +} + +Array copy_array(Array array) +{ + Array rv = ARRAY_DICT_INIT; + for (size_t i = 0; i < array.size; i++) { + ADD(rv, copy_object(array.items[i])); + } + return rv; +} + /// Creates a deep clone of an object Object copy_object(Object obj) { @@ -896,15 +914,10 @@ Object copy_object(Object obj) return obj; case kObjectTypeString: - return STRING_OBJ(cstr_to_string(obj.data.string.data)); + return STRING_OBJ(copy_string(obj.data.string)); - case kObjectTypeArray: { - Array rv = ARRAY_DICT_INIT; - for (size_t i = 0; i < obj.data.array.size; i++) { - ADD(rv, copy_object(obj.data.array.items[i])); - } - return ARRAY_OBJ(rv); - } + case kObjectTypeArray: + return ARRAY_OBJ(copy_array(obj.data.array)); case kObjectTypeDictionary: { Dictionary rv = ARRAY_DICT_INIT; -- cgit From e82cb5de4adc8a88e8213d0aca85400362df4bd1 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 30 Apr 2017 14:35:36 +0200 Subject: api: add metadata for ui events --- src/nvim/api/private/helpers.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 361570bff4..1d7b305da3 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -33,6 +33,7 @@ typedef struct { #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/helpers.c.generated.h" # include "api/private/funcs_metadata.generated.h" +# include "api/private/ui_events_metadata.generated.h" #endif /// Start block that may cause vimscript exceptions @@ -820,6 +821,7 @@ Dictionary api_metadata(void) if (!metadata.size) { PUT(metadata, "version", DICTIONARY_OBJ(version_dict())); init_function_metadata(&metadata); + init_ui_event_metadata(&metadata); init_error_type_metadata(&metadata); init_type_metadata(&metadata); } @@ -843,6 +845,22 @@ static void init_function_metadata(Dictionary *metadata) PUT(*metadata, "functions", functions); } +static void init_ui_event_metadata(Dictionary *metadata) +{ + msgpack_unpacked unpacked; + msgpack_unpacked_init(&unpacked); + if (msgpack_unpack_next(&unpacked, + (const char *)ui_events_metadata, + sizeof(ui_events_metadata), + NULL) != MSGPACK_UNPACK_SUCCESS) { + abort(); + } + Object ui_events; + msgpack_rpc_to_object(&unpacked.data, &ui_events); + msgpack_unpacked_destroy(&unpacked); + PUT(*metadata, "ui_events", ui_events); +} + static void init_error_type_metadata(Dictionary *metadata) { Dictionary types = ARRAY_DICT_INIT; -- cgit From 45626de63f2b8057c13df0466406c43f04d6a1e6 Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Thu, 25 May 2017 05:41:53 -0500 Subject: get_keymap API (#6236) * Add api function get keymap nvim_get_keymap(mode) nvim_buf_get_keymap(buffer, mode) --- src/nvim/api/private/helpers.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 1d7b305da3..ef789b3ed4 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -24,6 +24,7 @@ #include "nvim/option_defs.h" #include "nvim/version.h" #include "nvim/lib/kvec.h" +#include "nvim/getchar.h" /// Helper structure for vim_to_object typedef struct { @@ -1034,3 +1035,41 @@ void api_set_error(Error *err, ErrorType errType, const char *format, ...) err->type = errType; } + +/// Get an array containing dictionaries describing mappings +/// based on mode and buffer id +/// +/// @param mode The abbreviation for the mode +/// @param buf The buffer to get the mapping array. NULL for global +/// @returns An array of maparg() like dictionaries describing mappings +ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf) +{ + Array mappings = ARRAY_DICT_INIT; + dict_T *const dict = tv_dict_alloc(); + + // Convert the string mode to the integer mode + // that is stored within each mapblock + char_u *p = (char_u *)mode.data; + int int_mode = get_map_mode(&p, 0); + + // Determine the desired buffer value + long buffer_value = (buf == NULL) ? 0 : buf->handle; + + for (int i = 0; i < MAX_MAPHASH; i++) { + for (const mapblock_T *current_maphash = get_maphash(i, buf); + current_maphash; + current_maphash = current_maphash->m_next) { + // Check for correct mode + if (int_mode & current_maphash->m_mode) { + mapblock_fill_dict(dict, current_maphash, buffer_value, false); + ADD(mappings, vim_to_object( + (typval_T[]) { { .v_type = VAR_DICT, .vval.v_dict = dict } })); + + tv_dict_clear(dict); + } + } + } + tv_dict_free(dict); + + return mappings; +} -- cgit From d0ff2000b2a639f3bb0f70e37104b561dab05562 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 11 Jun 2017 15:03:02 +0200 Subject: vim-patch:8.0.0607 (#6879) Problem: When creating a bufref, then using :bwipe and :new it might get the same memory and bufref_valid() returns true. Solution: Add br_fnum to check the buffer number didn't change. https://github.com/vim/vim/commit/45e5fd135da5710f24a1acc142692f120f8b0b78 --- src/nvim/api/private/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index ef789b3ed4..d401ae52a0 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -961,7 +961,7 @@ static void set_option_value_for(char *key, { win_T *save_curwin = NULL; tabpage_T *save_curtab = NULL; - bufref_T save_curbuf = { NULL, 0 }; + bufref_T save_curbuf = { NULL, 0, 0 }; try_start(); switch (opt_type) -- cgit From 7ab152aaa58f493e54d03a15960b8a288196e588 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sat, 1 Jul 2017 15:34:25 +0300 Subject: ex_getln: Save and restore try state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: when processing cycle such as :for pat in [' \ze*', ' \zs*'] : try : let l = matchlist('x x', pat) : $put ='E888 NOT detected for ' . pat : catch : $put ='E888 detected for ' . pat : endtry :endfor `:let l = …` throwing an error causes this error to be caught after color_cmdline attempts to get callback for highlighting next line (the one with `$put = 'E888 NOT…`). Saving/restoring state prevents this from happening. --- src/nvim/api/private/helpers.c | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index d401ae52a0..883a5a2fd1 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -37,6 +37,52 @@ typedef struct { # include "api/private/ui_events_metadata.generated.h" #endif +/// Start block that may cause VimL exceptions while evaluating another code +/// +/// Used when caller is supposed to be operating when other VimL code is being +/// processed and that “other VimL code” must not be affected. +/// +/// @param[out] tstate Location where try state should be saved. +void try_enter(TryState *const tstate) +{ + *tstate = (TryState) { + .trylevel = trylevel, + .got_int = got_int, + .did_throw = did_throw, + .msg_list = (const struct msglist *const *)msg_list, + .private_msg_list = NULL, + }; + trylevel = 1; + got_int = false; + did_throw = false; + msg_list = &tstate->private_msg_list; +} + +/// End try block, set the error message if any and restore previous state +/// +/// @warning Return is consistent with most functions (false on error), not with +/// try_end (true on error). +/// +/// @param[in] tstate Previous state to restore. +/// @param[out] err Location where error should be saved. +/// +/// @return false if error occurred, true otherwise. +bool try_leave(const TryState *const tstate, Error *const err) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + const bool ret = !try_end(err); + assert(trylevel == 0); + assert(!got_int); + assert(!did_throw); + assert(msg_list == &tstate->private_msg_list); + assert(*msg_list == NULL); + trylevel = tstate->trylevel; + got_int = tstate->got_int; + did_throw = tstate->did_throw; + msg_list = (struct msglist **)tstate->msg_list; + return ret; +} + /// Start block that may cause vimscript exceptions void try_start(void) { -- cgit From e333957a1a9ae64b7daa36e08fd1df583114d4ba Mon Sep 17 00:00:00 2001 From: Matthieu Coudron Date: Mon, 3 Jul 2017 23:03:30 +0200 Subject: dict_get_value(): name the missing key (#6952) --- src/nvim/api/private/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index d401ae52a0..1ed2bc013e 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -95,7 +95,7 @@ Object dict_get_value(dict_T *dict, String key, Error *err) dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size); if (di == NULL) { - api_set_error(err, kErrorTypeValidation, "Key not found"); + api_set_error(err, kErrorTypeValidation, "Key '%s' not found", key.data); return (Object)OBJECT_INIT; } -- cgit From 2a6423eba732b005e277bac393f2246308dcc378 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 16 Jul 2017 22:03:31 +0300 Subject: api helpers: Save/restore more values in try_enter/try_leave This fixes memory leak reported by ASAN. This also somehow fixes test40, though I have no idea why except that that test yields memory leak report. --- src/nvim/api/private/helpers.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index a04cc9a312..6ff56709cd 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -49,13 +49,17 @@ void try_enter(TryState *const tstate) .trylevel = trylevel, .got_int = got_int, .did_throw = did_throw, + .need_rethrow = need_rethrow, + .current_exception = current_exception, .msg_list = (const struct msglist *const *)msg_list, .private_msg_list = NULL, }; trylevel = 1; got_int = false; did_throw = false; + need_rethrow = false; msg_list = &tstate->private_msg_list; + current_exception = NULL; } /// End try block, set the error message if any and restore previous state @@ -72,14 +76,17 @@ bool try_leave(const TryState *const tstate, Error *const err) { const bool ret = !try_end(err); assert(trylevel == 0); + assert(!need_rethrow); assert(!got_int); assert(!did_throw); assert(msg_list == &tstate->private_msg_list); assert(*msg_list == NULL); + assert(current_exception == NULL); trylevel = tstate->trylevel; got_int = tstate->got_int; did_throw = tstate->did_throw; msg_list = (struct msglist **)tstate->msg_list; + current_exception = tstate->current_exception; return ret; } @@ -96,6 +103,8 @@ void try_start(void) /// @return true if an error occurred bool try_end(Error *err) { + // Note: all globals manipulated here should be saved/restored in + // try_enter/try_leave. --trylevel; // Without this it stops processing all subsequent VimL commands and -- cgit From cfb1d937a64fcec836fdf26d6ea67024aeafabeb Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 18 Jul 2017 00:08:57 +0300 Subject: api helpers: Also save and restore did_emsg --- src/nvim/api/private/helpers.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 6ff56709cd..b6ecc319c1 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -46,20 +46,22 @@ typedef struct { void try_enter(TryState *const tstate) { *tstate = (TryState) { + .current_exception = current_exception, + .msg_list = (const struct msglist *const *)msg_list, + .private_msg_list = NULL, .trylevel = trylevel, .got_int = got_int, .did_throw = did_throw, .need_rethrow = need_rethrow, - .current_exception = current_exception, - .msg_list = (const struct msglist *const *)msg_list, - .private_msg_list = NULL, + .did_emsg = did_emsg, }; + msg_list = &tstate->private_msg_list; + current_exception = NULL; trylevel = 1; got_int = false; did_throw = false; need_rethrow = false; - msg_list = &tstate->private_msg_list; - current_exception = NULL; + did_emsg = false; } /// End try block, set the error message if any and restore previous state @@ -79,14 +81,17 @@ bool try_leave(const TryState *const tstate, Error *const err) assert(!need_rethrow); assert(!got_int); assert(!did_throw); + assert(!did_emsg); assert(msg_list == &tstate->private_msg_list); assert(*msg_list == NULL); assert(current_exception == NULL); + msg_list = (struct msglist **)tstate->msg_list; + current_exception = tstate->current_exception; trylevel = tstate->trylevel; got_int = tstate->got_int; did_throw = tstate->did_throw; - msg_list = (struct msglist **)tstate->msg_list; - current_exception = tstate->current_exception; + need_rethrow = tstate->need_rethrow; + did_emsg = tstate->did_emsg; return ret; } -- cgit From 25c6ac1af63c0d68b7993910e94d3b0f1b8bbfd7 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 18 Jul 2017 01:21:23 +0300 Subject: *: Fix clint errors --- src/nvim/api/private/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index b6ecc319c1..cdaceddc11 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -110,7 +110,7 @@ bool try_end(Error *err) { // Note: all globals manipulated here should be saved/restored in // try_enter/try_leave. - --trylevel; + trylevel--; // Without this it stops processing all subsequent VimL commands and // generates strange error messages if I e.g. try calling Test() in a -- cgit From 4d8ff5ec012cd517cf8010144f158d6f5c96d5bb Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 6 Aug 2017 14:38:54 +0300 Subject: api/helpers: Clarify try_start() usage --- src/nvim/api/private/helpers.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index cdaceddc11..021d1d43ff 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -96,6 +96,13 @@ bool try_leave(const TryState *const tstate, Error *const err) } /// Start block that may cause vimscript exceptions +/// +/// Each try_start() call should be mirrorred by try_end() call. +/// +/// To be used as a replacement of `:try … catch … endtry` in C code, in cases +/// when error flag could not already be set. If there may be pending error +/// state at the time try_start() is executed which needs to be preserved, +/// try_enter()/try_leave() pair should be used instead. void try_start(void) { ++trylevel; -- cgit From 36acfce4eac9dd131a39c4dbdff2836ab3e21d73 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 6 Aug 2017 15:23:05 +0300 Subject: api/helpers: Fix typo --- src/nvim/api/private/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 021d1d43ff..e736e29e2d 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -97,7 +97,7 @@ bool try_leave(const TryState *const tstate, Error *const err) /// Start block that may cause vimscript exceptions /// -/// Each try_start() call should be mirrorred by try_end() call. +/// Each try_start() call should be mirrored by try_end() call. /// /// To be used as a replacement of `:try … catch … endtry` in C code, in cases /// when error flag could not already be set. If there may be pending error -- cgit From 866dadaf753ba3733feb8c22d7da47af757bd35c Mon Sep 17 00:00:00 2001 From: Dongdong Zhou Date: Thu, 11 May 2017 07:51:10 +0100 Subject: ext_cmdline: added cmdline level add cchar_to_string --- src/nvim/api/private/helpers.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index e736e29e2d..f00fbf69ea 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -667,6 +667,22 @@ tabpage_T *find_tab_by_handle(Tabpage tabpage, Error *err) return rv; } +/// Allocates a String consisting of a single char. Does not support multibyte +/// characters. The resulting string is also NUL-terminated, to facilitate +/// interoperating with code using C strings. +/// +/// @param char the char to convert +/// @return the resulting String, if the input char was NUL, an +/// empty String is returned +String cchar_to_string(char c) +{ + char buf[] = { c, NUL }; + return (String) { + .data = xmemdupz(buf, 1), + .size = (c != NUL) ? 1 : 0 + }; +} + /// Copies a C string into a String (binary safe string, characters + length). /// The resulting string is also NUL-terminated, to facilitate interoperating /// with code using C strings. -- cgit From 22402fb99d05191cf140293cfb5f67902e78a8a8 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 16 Aug 2017 12:19:29 +0200 Subject: ext_cmdline: add support for highlighting --- src/nvim/api/private/helpers.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index f00fbf69ea..2944925a9c 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -703,6 +703,23 @@ String cstr_to_string(const char *str) }; } +/// Copies buffer to an allocated String. +/// The resulting string is also NUL-terminated, to facilitate interoperating +/// with code using C strings. +/// +/// @param buf the buffer to copy +/// @param size length of the buffer +/// @return the resulting String, if the input string was NULL, an +/// empty String is returned +String cbuf_to_string(const char *buf, size_t size) + FUNC_ATTR_NONNULL_ALL +{ + return (String) { + .data = xmemdupz(buf, size), + .size = size + }; +} + /// Creates a String using the given C string. Unlike /// cstr_to_string this function DOES NOT copy the C string. /// -- cgit From c030a381684f3491decf5597b16dfa9a21f29500 Mon Sep 17 00:00:00 2001 From: Peter Kalauskas Date: Mon, 20 Nov 2017 11:27:06 -0800 Subject: helpers.c: statically assert integer falls within range --- src/nvim/api/private/helpers.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 2944925a9c..6808048ac8 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -12,6 +12,7 @@ #include "nvim/api/private/handle.h" #include "nvim/msgpack_rpc/helpers.h" #include "nvim/ascii.h" +#include "nvim/assert.h" #include "nvim/vim.h" #include "nvim/buffer.h" #include "nvim/window.h" @@ -760,12 +761,9 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) case kObjectTypeWindow: case kObjectTypeTabpage: case kObjectTypeInteger: - if (obj.data.integer > VARNUMBER_MAX - || obj.data.integer < VARNUMBER_MIN) { - api_set_error(err, kErrorTypeValidation, "Integer value outside range"); - return false; - } - + STATIC_ASSERT(sizeof(obj.data.integer) <= sizeof(varnumber_T), + "Expected integer size to be less than or equal to VimL " + "number size"); tv->v_type = VAR_NUMBER; tv->vval.v_number = (varnumber_T)obj.data.integer; break; -- cgit