typval.c (134556B)
1 #include <assert.h> 2 #include <lauxlib.h> 3 #include <stdbool.h> 4 #include <stddef.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <uv.h> 9 10 #include "nvim/ascii_defs.h" 11 #include "nvim/assert_defs.h" 12 #include "nvim/buffer_defs.h" 13 #include "nvim/charset.h" 14 #include "nvim/errors.h" 15 #include "nvim/eval.h" 16 #include "nvim/eval/encode.h" 17 #include "nvim/eval/executor.h" 18 #include "nvim/eval/gc.h" 19 #include "nvim/eval/typval.h" 20 #include "nvim/eval/typval_defs.h" 21 #include "nvim/eval/typval_encode.h" 22 #include "nvim/eval/userfunc.h" 23 #include "nvim/eval/vars.h" 24 #include "nvim/garray.h" 25 #include "nvim/garray_defs.h" 26 #include "nvim/gettext_defs.h" 27 #include "nvim/globals.h" 28 #include "nvim/hashtab.h" 29 #include "nvim/hashtab_defs.h" 30 #include "nvim/lib/queue_defs.h" 31 #include "nvim/lua/executor.h" 32 #include "nvim/macros_defs.h" 33 #include "nvim/mbyte.h" 34 #include "nvim/mbyte_defs.h" 35 #include "nvim/memory.h" 36 #include "nvim/memory_defs.h" 37 #include "nvim/message.h" 38 #include "nvim/os/input.h" 39 #include "nvim/pos_defs.h" 40 #include "nvim/strings.h" 41 #include "nvim/types_defs.h" 42 #include "nvim/vim_defs.h" 43 44 /// struct storing information about current sort 45 typedef struct { 46 int item_compare_ic; 47 bool item_compare_lc; 48 bool item_compare_numeric; 49 bool item_compare_numbers; 50 bool item_compare_float; 51 const char *item_compare_func; 52 partial_T *item_compare_partial; 53 dict_T *item_compare_selfdict; 54 bool item_compare_func_err; 55 } sortinfo_T; 56 57 /// Structure representing one list item, used for sort array. 58 typedef struct { 59 listitem_T *item; ///< Sorted list item. 60 int idx; ///< Sorted list item index. 61 } ListSortItem; 62 63 typedef int (*ListSorter)(const void *, const void *); 64 65 /// Type for tv_dict2list() function 66 typedef enum { 67 kDict2ListKeys, ///< List dictionary keys. 68 kDict2ListValues, ///< List dictionary values. 69 kDict2ListItems, ///< List dictionary contents: [keys, values]. 70 } DictListType; 71 72 #include "eval/typval.c.generated.h" 73 74 static const char e_variable_nested_too_deep_for_unlock[] 75 = N_("E743: Variable nested too deep for (un)lock"); 76 static const char e_using_invalid_value_as_string[] 77 = N_("E908: Using an invalid value as a String"); 78 static const char e_string_required_for_argument_nr[] 79 = N_("E1174: String required for argument %d"); 80 static const char e_non_empty_string_required_for_argument_nr[] 81 = N_("E1175: Non-empty string required for argument %d"); 82 static const char e_dict_required_for_argument_nr[] 83 = N_("E1206: Dictionary required for argument %d"); 84 static const char e_number_required_for_argument_nr[] 85 = N_("E1210: Number required for argument %d"); 86 static const char e_list_required_for_argument_nr[] 87 = N_("E1211: List required for argument %d"); 88 static const char e_bool_required_for_argument_nr[] 89 = N_("E1212: Bool required for argument %d"); 90 static const char e_float_or_number_required_for_argument_nr[] 91 = N_("E1219: Float or Number required for argument %d"); 92 static const char e_string_or_number_required_for_argument_nr[] 93 = N_("E1220: String or Number required for argument %d"); 94 static const char e_string_or_list_required_for_argument_nr[] 95 = N_("E1222: String or List required for argument %d"); 96 static const char e_list_dict_blob_or_string_required_for_argument_nr[] 97 = N_("E1225: List, Dictionary, Blob or String required for argument %d"); 98 static const char e_list_or_blob_required_for_argument_nr[] 99 = N_("E1226: List or Blob required for argument %d"); 100 static const char e_blob_required_for_argument_nr[] 101 = N_("E1238: Blob required for argument %d"); 102 static const char e_string_list_or_blob_required_for_argument_nr[] 103 = N_("E1252: String, List or Blob required for argument %d"); 104 static const char e_string_or_function_required_for_argument_nr[] 105 = N_("E1256: String or function required for argument %d"); 106 static const char e_non_null_dict_required_for_argument_nr[] 107 = N_("E1297: Non-NULL Dictionary required for argument %d"); 108 109 bool tv_in_free_unref_items = false; 110 111 // TODO(ZyX-I): Remove DICT_MAXNEST, make users be non-recursive instead 112 113 #define DICT_MAXNEST 100 114 115 const char *const tv_empty_string = ""; 116 117 // Lists: 118 // List item: 119 120 /// Allocate a list item 121 /// 122 /// @warning Allocated item is not initialized, do not forget to initialize it 123 /// and specifically set lv_lock. 124 /// 125 /// @return [allocated] new list item. 126 static listitem_T *tv_list_item_alloc(void) 127 FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC 128 { 129 return xmalloc(sizeof(listitem_T)); 130 } 131 132 /// Remove a list item from a List and free it 133 /// 134 /// Also clears the value. 135 /// 136 /// @param[out] l List to remove item from. 137 /// @param[in,out] item Item to remove. 138 /// 139 /// @return Pointer to the list item just after removed one, NULL if removed 140 /// item was the last one. 141 listitem_T *tv_list_item_remove(list_T *const l, listitem_T *const item) 142 FUNC_ATTR_NONNULL_ALL 143 { 144 listitem_T *const next_item = TV_LIST_ITEM_NEXT(l, item); 145 tv_list_drop_items(l, item, item); 146 tv_clear(TV_LIST_ITEM_TV(item)); 147 xfree(item); 148 return next_item; 149 } 150 151 // List watchers: 152 153 /// Add a watcher to a list 154 /// 155 /// @param[out] l List to add watcher to. 156 /// @param[in] lw Watcher to add. 157 void tv_list_watch_add(list_T *const l, listwatch_T *const lw) 158 FUNC_ATTR_NONNULL_ALL 159 { 160 lw->lw_next = l->lv_watch; 161 l->lv_watch = lw; 162 } 163 164 /// Remove a watcher from a list 165 /// 166 /// Does not give a warning if watcher was not found. 167 /// 168 /// @param[out] l List to remove watcher from. 169 /// @param[in] lwrem Watcher to remove. 170 void tv_list_watch_remove(list_T *const l, listwatch_T *const lwrem) 171 FUNC_ATTR_NONNULL_ALL 172 { 173 listwatch_T **lwp = &l->lv_watch; 174 for (listwatch_T *lw = l->lv_watch; lw != NULL; lw = lw->lw_next) { 175 if (lw == lwrem) { 176 *lwp = lw->lw_next; 177 break; 178 } 179 lwp = &lw->lw_next; 180 } 181 } 182 183 /// Advance watchers to the next item 184 /// 185 /// Used just before removing an item from a list. 186 /// 187 /// @param[out] l List from which item is removed. 188 /// @param[in] item List item being removed. 189 static void tv_list_watch_fix(list_T *const l, const listitem_T *const item) 190 FUNC_ATTR_NONNULL_ALL 191 { 192 for (listwatch_T *lw = l->lv_watch; lw != NULL; lw = lw->lw_next) { 193 if (lw->lw_item == item) { 194 lw->lw_item = item->li_next; 195 } 196 } 197 } 198 199 // Alloc/free: 200 201 /// Allocate an empty list 202 /// 203 /// Caller should take care of the reference count. 204 /// 205 /// @param[in] len Expected number of items to be populated before list 206 /// becomes accessible from Vimscript. It is still valid to 207 /// underpopulate a list, value only controls how many elements 208 /// will be allocated in advance. Currently does nothing. 209 /// @see ListLenSpecials. 210 /// 211 /// @return [allocated] new list. 212 list_T *tv_list_alloc(const ptrdiff_t len) 213 FUNC_ATTR_NONNULL_RET 214 { 215 list_T *const list = xcalloc(1, sizeof(list_T)); 216 217 // Prepend the list to the list of lists for garbage collection. 218 if (gc_first_list != NULL) { 219 gc_first_list->lv_used_prev = list; 220 } 221 list->lv_used_prev = NULL; 222 list->lv_used_next = gc_first_list; 223 gc_first_list = list; 224 list->lua_table_ref = LUA_NOREF; 225 return list; 226 } 227 228 /// Initialize a static list with 10 items 229 /// 230 /// @param[out] sl Static list to initialize. 231 void tv_list_init_static10(staticList10_T *const sl) 232 FUNC_ATTR_NONNULL_ALL 233 { 234 #define SL_SIZE ARRAY_SIZE(sl->sl_items) 235 list_T *const l = &sl->sl_list; 236 237 CLEAR_POINTER(sl); 238 l->lv_first = &sl->sl_items[0]; 239 l->lv_last = &sl->sl_items[SL_SIZE - 1]; 240 l->lv_refcount = DO_NOT_FREE_CNT; 241 tv_list_set_lock(l, VAR_FIXED); 242 sl->sl_list.lv_len = 10; 243 244 sl->sl_items[0].li_prev = NULL; 245 sl->sl_items[0].li_next = &sl->sl_items[1]; 246 sl->sl_items[SL_SIZE - 1].li_prev = &sl->sl_items[SL_SIZE - 2]; 247 sl->sl_items[SL_SIZE - 1].li_next = NULL; 248 249 for (size_t i = 1; i < SL_SIZE - 1; i++) { 250 listitem_T *const li = &sl->sl_items[i]; 251 li->li_prev = li - 1; 252 li->li_next = li + 1; 253 } 254 #undef SL_SIZE 255 } 256 257 /// Initialize static list with undefined number of elements 258 /// 259 /// @param[out] l List to initialize. 260 void tv_list_init_static(list_T *const l) 261 FUNC_ATTR_NONNULL_ALL 262 { 263 CLEAR_POINTER(l); 264 l->lv_refcount = DO_NOT_FREE_CNT; 265 } 266 267 /// Free items contained in a list 268 /// 269 /// @param[in,out] l List to clear. 270 void tv_list_free_contents(list_T *const l) 271 FUNC_ATTR_NONNULL_ALL 272 { 273 for (listitem_T *item = l->lv_first; item != NULL; item = l->lv_first) { 274 // Remove the item before deleting it. 275 l->lv_first = item->li_next; 276 tv_clear(&item->li_tv); 277 xfree(item); 278 } 279 l->lv_len = 0; 280 l->lv_idx_item = NULL; 281 l->lv_last = NULL; 282 assert(l->lv_watch == NULL); 283 } 284 285 /// Free a list itself, ignoring items it contains 286 /// 287 /// Ignores the reference count. 288 /// 289 /// @param[in,out] l List to free. 290 void tv_list_free_list(list_T *const l) 291 FUNC_ATTR_NONNULL_ALL 292 { 293 // Remove the list from the list of lists for garbage collection. 294 if (l->lv_used_prev == NULL) { 295 gc_first_list = l->lv_used_next; 296 } else { 297 l->lv_used_prev->lv_used_next = l->lv_used_next; 298 } 299 if (l->lv_used_next != NULL) { 300 l->lv_used_next->lv_used_prev = l->lv_used_prev; 301 } 302 303 NLUA_CLEAR_REF(l->lua_table_ref); 304 xfree(l); 305 } 306 307 /// Free a list, including all items it points to 308 /// 309 /// Ignores the reference count. Does not do anything if 310 /// tv_in_free_unref_items is true. 311 /// 312 /// @param[in,out] l List to free. 313 void tv_list_free(list_T *const l) 314 FUNC_ATTR_NONNULL_ALL 315 { 316 if (tv_in_free_unref_items) { 317 return; 318 } 319 320 tv_list_free_contents(l); 321 tv_list_free_list(l); 322 } 323 324 /// Unreference a list 325 /// 326 /// Decrements the reference count and frees when it becomes zero or less. 327 /// 328 /// @param[in,out] l List to unreference. 329 void tv_list_unref(list_T *const l) 330 { 331 if (l != NULL && --l->lv_refcount <= 0) { 332 tv_list_free(l); 333 } 334 } 335 336 // Add/remove: 337 338 /// Remove items "item" to "item2" from list "l" 339 /// 340 /// @warning Does not free the listitem or the value! 341 /// 342 /// @param[out] l List to remove from. 343 /// @param[in] item First item to remove. 344 /// @param[in] item2 Last item to remove. 345 void tv_list_drop_items(list_T *const l, listitem_T *const item, listitem_T *const item2) 346 FUNC_ATTR_NONNULL_ALL 347 { 348 // Notify watchers. 349 for (listitem_T *ip = item; ip != item2->li_next; ip = ip->li_next) { 350 l->lv_len--; 351 tv_list_watch_fix(l, ip); 352 } 353 354 if (item2->li_next == NULL) { 355 l->lv_last = item->li_prev; 356 } else { 357 item2->li_next->li_prev = item->li_prev; 358 } 359 if (item->li_prev == NULL) { 360 l->lv_first = item2->li_next; 361 } else { 362 item->li_prev->li_next = item2->li_next; 363 } 364 l->lv_idx_item = NULL; 365 } 366 367 /// Like tv_list_drop_items, but also frees all removed items 368 void tv_list_remove_items(list_T *const l, listitem_T *const item, listitem_T *const item2) 369 FUNC_ATTR_NONNULL_ALL 370 { 371 tv_list_drop_items(l, item, item2); 372 for (listitem_T *li = item;;) { 373 tv_clear(TV_LIST_ITEM_TV(li)); 374 listitem_T *const nli = li->li_next; 375 xfree(li); 376 if (li == item2) { 377 break; 378 } 379 li = nli; 380 } 381 } 382 383 /// Move items "item" to "item2" from list "l" to the end of the list "tgt_l" 384 /// 385 /// @param[out] l List to move from. 386 /// @param[in] item First item to move. 387 /// @param[in] item2 Last item to move. 388 /// @param[out] tgt_l List to move to. 389 /// @param[in] cnt Number of items moved. 390 void tv_list_move_items(list_T *const l, listitem_T *const item, listitem_T *const item2, 391 list_T *const tgt_l, const int cnt) 392 FUNC_ATTR_NONNULL_ALL 393 { 394 tv_list_drop_items(l, item, item2); 395 item->li_prev = tgt_l->lv_last; 396 item2->li_next = NULL; 397 if (tgt_l->lv_last == NULL) { 398 tgt_l->lv_first = item; 399 } else { 400 tgt_l->lv_last->li_next = item; 401 } 402 tgt_l->lv_last = item2; 403 tgt_l->lv_len += cnt; 404 } 405 406 /// Insert list item 407 /// 408 /// @param[out] l List to insert to. 409 /// @param[in,out] ni Item to insert. 410 /// @param[in] item Item to insert before. If NULL, inserts at the end of the 411 /// list. 412 void tv_list_insert(list_T *const l, listitem_T *const ni, listitem_T *const item) 413 FUNC_ATTR_NONNULL_ARG(1, 2) 414 { 415 if (item == NULL) { 416 // Append new item at end of list. 417 tv_list_append(l, ni); 418 } else { 419 // Insert new item before existing item. 420 ni->li_prev = item->li_prev; 421 ni->li_next = item; 422 if (item->li_prev == NULL) { 423 l->lv_first = ni; 424 l->lv_idx++; 425 } else { 426 item->li_prev->li_next = ni; 427 l->lv_idx_item = NULL; 428 } 429 item->li_prev = ni; 430 l->lv_len++; 431 } 432 } 433 434 /// Insert Vimscript value into a list 435 /// 436 /// @param[out] l List to insert to. 437 /// @param[in,out] tv Value to insert. Is copied (@see tv_copy()) to an 438 /// allocated listitem_T and inserted. 439 /// @param[in] item Item to insert before. If NULL, inserts at the end of the 440 /// list. 441 void tv_list_insert_tv(list_T *const l, typval_T *const tv, listitem_T *const item) 442 { 443 listitem_T *const ni = tv_list_item_alloc(); 444 445 tv_copy(tv, &ni->li_tv); 446 tv_list_insert(l, ni, item); 447 } 448 449 /// Append item to the end of list 450 /// 451 /// @param[out] l List to append to. 452 /// @param[in,out] item Item to append. 453 void tv_list_append(list_T *const l, listitem_T *const item) 454 FUNC_ATTR_NONNULL_ALL 455 { 456 if (l->lv_last == NULL) { 457 // empty list 458 l->lv_first = item; 459 l->lv_last = item; 460 item->li_prev = NULL; 461 } else { 462 l->lv_last->li_next = item; 463 item->li_prev = l->lv_last; 464 l->lv_last = item; 465 } 466 l->lv_len++; 467 item->li_next = NULL; 468 } 469 470 /// Append Vimscript value to the end of list 471 /// 472 /// @param[out] l List to append to. 473 /// @param[in,out] tv Value to append. Is copied (@see tv_copy()) to an 474 /// allocated listitem_T. 475 void tv_list_append_tv(list_T *const l, typval_T *const tv) 476 FUNC_ATTR_NONNULL_ALL 477 { 478 listitem_T *const li = tv_list_item_alloc(); 479 tv_copy(tv, TV_LIST_ITEM_TV(li)); 480 tv_list_append(l, li); 481 } 482 483 /// Like tv_list_append_tv(), but tv is moved to a list 484 /// 485 /// This means that it is no longer valid to use contents of the typval_T after 486 /// function exits. A pointer is returned to the allocated typval which can be used 487 typval_T *tv_list_append_owned_tv(list_T *const l, typval_T tv) 488 FUNC_ATTR_NONNULL_ALL 489 { 490 listitem_T *const li = tv_list_item_alloc(); 491 *TV_LIST_ITEM_TV(li) = tv; 492 tv_list_append(l, li); 493 return TV_LIST_ITEM_TV(li); 494 } 495 496 /// Append a list to a list as one item 497 /// 498 /// @param[out] l List to append to. 499 /// @param[in,out] itemlist List to append. Reference count is increased. 500 void tv_list_append_list(list_T *const l, list_T *const itemlist) 501 FUNC_ATTR_NONNULL_ARG(1) 502 { 503 tv_list_append_owned_tv(l, (typval_T) { 504 .v_type = VAR_LIST, 505 .v_lock = VAR_UNLOCKED, 506 .vval.v_list = itemlist, 507 }); 508 tv_list_ref(itemlist); 509 } 510 511 /// Append a dictionary to a list 512 /// 513 /// @param[out] l List to append to. 514 /// @param[in,out] dict Dictionary to append. Reference count is increased. 515 void tv_list_append_dict(list_T *const l, dict_T *const dict) 516 FUNC_ATTR_NONNULL_ARG(1) 517 { 518 tv_list_append_owned_tv(l, (typval_T) { 519 .v_type = VAR_DICT, 520 .v_lock = VAR_UNLOCKED, 521 .vval.v_dict = dict, 522 }); 523 if (dict != NULL) { 524 dict->dv_refcount++; 525 } 526 } 527 528 /// Make a copy of "str" and append it as an item to list "l" 529 /// 530 /// @param[out] l List to append to. 531 /// @param[in] str String to append. 532 /// @param[in] len Length of the appended string. May be -1, in this 533 /// case string is considered to be usual zero-terminated 534 /// string or NULL “empty” string. 535 void tv_list_append_string(list_T *const l, const char *const str, const ssize_t len) 536 FUNC_ATTR_NONNULL_ARG(1) 537 { 538 tv_list_append_owned_tv(l, (typval_T) { 539 .v_type = VAR_STRING, 540 .v_lock = VAR_UNLOCKED, 541 .vval.v_string = (str == NULL 542 ? NULL 543 : (len >= 0 544 ? xmemdupz(str, (size_t)len) 545 : xstrdup(str))), 546 }); 547 } 548 549 /// Append given string to the list 550 /// 551 /// Unlike list_append_string this function does not copy the string. 552 /// 553 /// @param[out] l List to append to. 554 /// @param[in] str String to append. 555 void tv_list_append_allocated_string(list_T *const l, char *const str) 556 FUNC_ATTR_NONNULL_ARG(1) 557 { 558 tv_list_append_owned_tv(l, (typval_T) { 559 .v_type = VAR_STRING, 560 .v_lock = VAR_UNLOCKED, 561 .vval.v_string = str, 562 }); 563 } 564 565 /// Append number to the list 566 /// 567 /// @param[out] l List to append to. 568 /// @param[in] n Number to append. Will be recorded in the allocated 569 /// listitem_T. 570 void tv_list_append_number(list_T *const l, const varnumber_T n) 571 { 572 tv_list_append_owned_tv(l, (typval_T) { 573 .v_type = VAR_NUMBER, 574 .v_lock = VAR_UNLOCKED, 575 .vval.v_number = n, 576 }); 577 } 578 579 // Operations on the whole list: 580 581 /// Make a copy of list 582 /// 583 /// @param[in] conv If non-NULL, then all internal strings will be converted. 584 /// Only used when `deep` is true. 585 /// @param[in] orig Original list to copy. 586 /// @param[in] deep If false, then shallow copy will be done. 587 /// @param[in] copyID See var_item_copy(). 588 /// 589 /// @return Copied list. May be NULL in case original list is NULL or some 590 /// failure happens. The refcount of the new list is set to 1. 591 list_T *tv_list_copy(const vimconv_T *const conv, list_T *const orig, const bool deep, 592 const int copyID) 593 FUNC_ATTR_WARN_UNUSED_RESULT 594 { 595 if (orig == NULL) { 596 return NULL; 597 } 598 599 list_T *copy = tv_list_alloc(tv_list_len(orig)); 600 tv_list_ref(copy); 601 if (copyID != 0) { 602 // Do this before adding the items, because one of the items may 603 // refer back to this list. 604 orig->lv_copyID = copyID; 605 orig->lv_copylist = copy; 606 } 607 TV_LIST_ITER(orig, item, { 608 if (got_int) { 609 break; 610 } 611 listitem_T *const ni = tv_list_item_alloc(); 612 if (deep) { 613 if (var_item_copy(conv, TV_LIST_ITEM_TV(item), TV_LIST_ITEM_TV(ni), 614 deep, copyID) == FAIL) { 615 xfree(ni); 616 goto tv_list_copy_error; 617 } 618 } else { 619 tv_copy(TV_LIST_ITEM_TV(item), TV_LIST_ITEM_TV(ni)); 620 } 621 tv_list_append(copy, ni); 622 }); 623 624 return copy; 625 626 tv_list_copy_error: 627 tv_list_unref(copy); 628 return NULL; 629 } 630 631 /// Get the list item in "l" with index "n1". "n1" is adjusted if needed. 632 /// Return NULL if there is no such item. 633 listitem_T *tv_list_check_range_index_one(list_T *const l, int *const n1, const bool quiet) 634 { 635 listitem_T *li = tv_list_find_index(l, n1); 636 if (li != NULL) { 637 return li; 638 } 639 640 if (!quiet) { 641 semsg(_(e_list_index_out_of_range_nr), (int64_t)(*n1)); 642 } 643 return NULL; 644 } 645 646 /// Check that "n2" can be used as the second index in a range of list "l". 647 /// If "n1" or "n2" is negative it is changed to the positive index. 648 /// "li1" is the item for item "n1". 649 /// Return OK or FAIL. 650 int tv_list_check_range_index_two(list_T *const l, int *const n1, const listitem_T *const li1, 651 int *const n2, const bool quiet) 652 { 653 if (*n2 < 0) { 654 listitem_T *ni = tv_list_find(l, *n2); 655 if (ni == NULL) { 656 if (!quiet) { 657 semsg(_(e_list_index_out_of_range_nr), (int64_t)(*n2)); 658 } 659 return FAIL; 660 } 661 *n2 = tv_list_idx_of_item(l, ni); 662 } 663 664 // Check that n2 isn't before n1. 665 if (*n1 < 0) { 666 *n1 = tv_list_idx_of_item(l, li1); 667 } 668 if (*n2 < *n1) { 669 if (!quiet) { 670 semsg(_(e_list_index_out_of_range_nr), (int64_t)(*n2)); 671 } 672 return FAIL; 673 } 674 return OK; 675 } 676 677 /// Assign values from list "src" into a range of "dest". 678 /// "idx1_arg" is the index of the first item in "dest" to be replaced. 679 /// "idx2" is the index of last item to be replaced, but when "empty_idx2" is 680 /// true then replace all items after "idx1". 681 /// "op" is the operator, normally "=" but can be "+=" and the like. 682 /// "varname" is used for error messages. 683 /// Returns OK or FAIL. 684 int tv_list_assign_range(list_T *const dest, list_T *const src, const int idx1_arg, const int idx2, 685 const bool empty_idx2, const char *const op, const char *const varname) 686 { 687 int idx1 = idx1_arg; 688 listitem_T *const first_li = tv_list_find_index(dest, &idx1); 689 listitem_T *src_li; 690 691 // Check whether any of the list items is locked before making any changes. 692 int idx = idx1; 693 listitem_T *dest_li = first_li; 694 for (src_li = tv_list_first(src); src_li != NULL && dest_li != NULL;) { 695 if (value_check_lock(TV_LIST_ITEM_TV(dest_li)->v_lock, varname, TV_CSTRING)) { 696 return FAIL; 697 } 698 src_li = TV_LIST_ITEM_NEXT(src, src_li); 699 if (src_li == NULL || (!empty_idx2 && idx2 == idx)) { 700 break; 701 } 702 dest_li = TV_LIST_ITEM_NEXT(dest, dest_li); 703 idx++; 704 } 705 706 // Assign the List values to the list items. 707 idx = idx1; 708 dest_li = first_li; 709 for (src_li = tv_list_first(src); src_li != NULL;) { 710 assert(dest_li != NULL); 711 if (op != NULL && *op != '=') { 712 eexe_mod_op(TV_LIST_ITEM_TV(dest_li), TV_LIST_ITEM_TV(src_li), op); 713 } else { 714 tv_clear(TV_LIST_ITEM_TV(dest_li)); 715 tv_copy(TV_LIST_ITEM_TV(src_li), TV_LIST_ITEM_TV(dest_li)); 716 } 717 src_li = TV_LIST_ITEM_NEXT(src, src_li); 718 if (src_li == NULL || (!empty_idx2 && idx2 == idx)) { 719 break; 720 } 721 if (TV_LIST_ITEM_NEXT(dest, dest_li) == NULL) { 722 // Need to add an empty item. 723 tv_list_append_number(dest, 0); 724 // "dest_li" may have become invalid after append, don’t use it. 725 dest_li = tv_list_last(dest); // Valid again. 726 } else { 727 dest_li = TV_LIST_ITEM_NEXT(dest, dest_li); 728 } 729 idx++; 730 } 731 if (src_li != NULL) { 732 emsg(_("E710: List value has more items than target")); 733 return FAIL; 734 } 735 if (empty_idx2 736 ? (dest_li != NULL && TV_LIST_ITEM_NEXT(dest, dest_li) != NULL) 737 : idx != idx2) { 738 emsg(_("E711: List value has not enough items")); 739 return FAIL; 740 } 741 return OK; 742 } 743 744 /// Flatten up to "maxitems" in "list", starting at "first" to depth "maxdepth". 745 /// When "first" is NULL use the first item. 746 /// Does nothing if "maxdepth" is 0. 747 /// 748 /// @param[in,out] list List to flatten 749 /// @param[in] maxdepth Maximum depth that will be flattened 750 /// 751 /// @return OK or FAIL 752 void tv_list_flatten(list_T *list, listitem_T *first, int64_t maxitems, int64_t maxdepth) 753 FUNC_ATTR_NONNULL_ARG(1) 754 { 755 listitem_T *item; 756 int done = 0; 757 if (maxdepth == 0) { 758 return; 759 } 760 761 if (first == NULL) { 762 item = list->lv_first; 763 } else { 764 item = first; 765 } 766 767 while (item != NULL && done < maxitems) { 768 listitem_T *next = item->li_next; 769 770 fast_breakcheck(); 771 if (got_int) { 772 return; 773 } 774 if (item->li_tv.v_type == VAR_LIST) { 775 list_T *itemlist = item->li_tv.vval.v_list; 776 777 tv_list_drop_items(list, item, item); 778 tv_list_extend(list, itemlist, next); 779 780 if (maxdepth > 0) { 781 tv_list_flatten(list, 782 item->li_prev == NULL ? list->lv_first : item->li_prev->li_next, 783 itemlist->lv_len, maxdepth - 1); 784 } 785 tv_clear(&item->li_tv); 786 xfree(item); 787 } 788 789 done++; 790 item = next; 791 } 792 } 793 794 /// "items(blob)" function 795 /// Converts a Blob into a List of [index, byte] pairs. 796 /// Caller must have already checked that argvars[0] is a Blob. 797 /// A null blob behaves like an empty blob. 798 static void tv_blob2items(typval_T *argvars, typval_T *rettv) 799 { 800 blob_T *blob = argvars[0].vval.v_blob; 801 802 tv_list_alloc_ret(rettv, tv_blob_len(blob)); 803 804 for (int i = 0; i < tv_blob_len(blob); i++) { 805 list_T *l2 = tv_list_alloc(2); 806 tv_list_append_list(rettv->vval.v_list, l2); 807 tv_list_append_number(l2, i); 808 tv_list_append_number(l2, tv_blob_get(blob, i)); 809 } 810 } 811 812 /// "items(dict)" function 813 static void tv_dict2items(typval_T *argvars, typval_T *rettv) 814 { 815 tv_dict2list(argvars, rettv, kDict2ListItems); 816 } 817 818 /// "items(list)" function 819 /// Caller must have already checked that argvars[0] is a List. 820 static void tv_list2items(typval_T *argvars, typval_T *rettv) 821 { 822 list_T *l = argvars[0].vval.v_list; 823 824 tv_list_alloc_ret(rettv, tv_list_len(l)); 825 if (l == NULL) { 826 return; // null list behaves like an empty list 827 } 828 829 varnumber_T idx = 0; 830 TV_LIST_ITER(l, li, { 831 list_T *l2 = tv_list_alloc(2); 832 tv_list_append_list(rettv->vval.v_list, l2); 833 tv_list_append_number(l2, idx); 834 tv_list_append_tv(l2, TV_LIST_ITEM_TV(li)); 835 idx++; 836 }); 837 } 838 839 /// "items(string)" function 840 /// Caller must have already checked that argvars[0] is a String. 841 static void tv_string2items(typval_T *argvars, typval_T *rettv) 842 { 843 const char *p = argvars[0].vval.v_string; 844 845 tv_list_alloc_ret(rettv, kListLenMayKnow); 846 if (p == NULL) { 847 return; // null string behaves like an empty string 848 } 849 850 for (varnumber_T idx = 0; *p != NUL; idx++) { 851 int len = utfc_ptr2len(p); 852 if (len == 0) { 853 break; 854 } 855 list_T *l2 = tv_list_alloc(2); 856 tv_list_append_list(rettv->vval.v_list, l2); 857 tv_list_append_number(l2, idx); 858 tv_list_append_string(l2, p, len); 859 p += len; 860 } 861 } 862 863 /// Extend first list with the second 864 /// 865 /// @param[out] l1 List to extend. 866 /// @param[in] l2 List to extend with. 867 /// @param[in] bef If not NULL, extends before this item. 868 void tv_list_extend(list_T *const l1, list_T *const l2, listitem_T *const bef) 869 FUNC_ATTR_NONNULL_ARG(1) 870 { 871 int todo = tv_list_len(l2); 872 listitem_T *const befbef = (bef == NULL ? NULL : bef->li_prev); 873 listitem_T *const saved_next = (befbef == NULL ? NULL : befbef->li_next); 874 // We also quit the loop when we have inserted the original item count of 875 // the list, avoid a hang when we extend a list with itself. 876 for (listitem_T *item = tv_list_first(l2) 877 ; item != NULL && todo-- 878 ; item = (item == befbef ? saved_next : item->li_next)) { 879 tv_list_insert_tv(l1, TV_LIST_ITEM_TV(item), bef); 880 } 881 } 882 883 /// Concatenate lists into a new list 884 /// 885 /// @param[in] l1 First list. 886 /// @param[in] l2 Second list. 887 /// @param[out] ret_tv Location where new list is saved. 888 /// 889 /// @return OK or FAIL. 890 int tv_list_concat(list_T *const l1, list_T *const l2, typval_T *const tv) 891 FUNC_ATTR_WARN_UNUSED_RESULT 892 { 893 list_T *l; 894 895 tv->v_type = VAR_LIST; 896 tv->v_lock = VAR_UNLOCKED; 897 if (l1 == NULL && l2 == NULL) { 898 l = NULL; 899 } else if (l1 == NULL) { 900 l = tv_list_copy(NULL, l2, false, 0); 901 } else { 902 l = tv_list_copy(NULL, l1, false, 0); 903 if (l != NULL && l2 != NULL) { 904 tv_list_extend(l, l2, NULL); 905 } 906 } 907 if (l == NULL && !(l1 == NULL && l2 == NULL)) { 908 return FAIL; 909 } 910 911 tv->vval.v_list = l; 912 return OK; 913 } 914 915 static list_T *tv_list_slice(list_T *ol, varnumber_T n1, varnumber_T n2) 916 { 917 list_T *l = tv_list_alloc(n2 - n1 + 1); 918 listitem_T *item = tv_list_find(ol, (int)n1); 919 for (; n1 <= n2; n1++) { 920 tv_list_append_tv(l, TV_LIST_ITEM_TV(item)); 921 item = TV_LIST_ITEM_NEXT(rettv->vval.v_list, item); 922 } 923 return l; 924 } 925 926 int tv_list_slice_or_index(list_T *list, bool range, varnumber_T n1_arg, varnumber_T n2_arg, 927 bool exclusive, typval_T *rettv, bool verbose) 928 { 929 int len = tv_list_len(rettv->vval.v_list); 930 varnumber_T n1 = n1_arg; 931 varnumber_T n2 = n2_arg; 932 933 if (n1 < 0) { 934 n1 = len + n1; 935 } 936 if (n1 < 0 || n1 >= len) { 937 // For a range we allow invalid values and return an empty list. 938 // A list index out of range is an error. 939 if (!range) { 940 if (verbose) { 941 semsg(_(e_list_index_out_of_range_nr), (int64_t)n1_arg); 942 } 943 return FAIL; 944 } 945 n1 = len; 946 } 947 if (range) { 948 if (n2 < 0) { 949 n2 = len + n2; 950 } else if (n2 >= len) { 951 n2 = len - (exclusive ? 0 : 1); 952 } 953 if (exclusive) { 954 n2--; 955 } 956 if (n2 < 0 || n2 + 1 < n1) { 957 n2 = -1; 958 } 959 list_T *l = tv_list_slice(rettv->vval.v_list, n1, n2); 960 tv_clear(rettv); 961 tv_list_set_ret(rettv, l); 962 } else { 963 // copy the item to "var1" to avoid that freeing the list makes it 964 // invalid. 965 typval_T var1; 966 tv_copy(TV_LIST_ITEM_TV(tv_list_find(rettv->vval.v_list, (int)n1)), &var1); 967 tv_clear(rettv); 968 *rettv = var1; 969 } 970 return OK; 971 } 972 973 typedef struct { 974 String s; 975 char *tofree; 976 } Join; 977 978 /// Join list into a string, helper function 979 /// 980 /// @param[out] gap Garray where result will be saved. 981 /// @param[in] l List to join. 982 /// @param[in] sep Used separator. 983 /// @param[in] join_gap Garray to keep each list item string. 984 /// 985 /// @return OK in case of success, FAIL otherwise. 986 static int list_join_inner(garray_T *const gap, list_T *const l, const char *const sep, 987 garray_T *const join_gap) 988 FUNC_ATTR_NONNULL_ALL 989 { 990 size_t sumlen = 0; 991 bool first = true; 992 993 // Stringify each item in the list. 994 TV_LIST_ITER(l, item, { 995 if (got_int) { 996 break; 997 } 998 String s; 999 s.data = encode_tv2echo(TV_LIST_ITEM_TV(item), &s.size); 1000 if (s.data == NULL) { 1001 return FAIL; 1002 } 1003 1004 sumlen += s.size; 1005 1006 Join *const p = GA_APPEND_VIA_PTR(Join, join_gap); 1007 p->s = s; 1008 p->tofree = s.data; 1009 1010 line_breakcheck(); 1011 }); 1012 1013 // Allocate result buffer with its total size, avoid re-allocation and 1014 // multiple copy operations. Add 2 for a tailing ']' and NUL. 1015 size_t seplen = strlen(sep); 1016 if (join_gap->ga_len >= 2) { 1017 sumlen += seplen * (size_t)(join_gap->ga_len - 1); 1018 } 1019 ga_grow(gap, (int)sumlen + 2); 1020 1021 for (int i = 0; i < join_gap->ga_len && !got_int; i++) { 1022 if (first) { 1023 first = false; 1024 } else { 1025 ga_concat_len(gap, sep, seplen); 1026 } 1027 const Join *const p = ((const Join *)join_gap->ga_data) + i; 1028 1029 if (p->s.data != NULL) { 1030 ga_concat_len(gap, p->s.data, p->s.size); 1031 } 1032 line_breakcheck(); 1033 } 1034 1035 return OK; 1036 } 1037 1038 /// Join list into a string using given separator 1039 /// 1040 /// @param[out] gap Garray where the joined list will be saved. 1041 /// @param[in] l List. 1042 /// @param[in] sep Separator. 1043 /// 1044 /// @return OK in case of success, FAIL otherwise. 1045 int tv_list_join(garray_T *const gap, list_T *const l, const char *const sep) 1046 FUNC_ATTR_NONNULL_ARG(1) 1047 { 1048 if (!tv_list_len(l)) { 1049 return OK; 1050 } 1051 1052 garray_T join_ga; 1053 int retval; 1054 1055 ga_init(&join_ga, (int)sizeof(Join), tv_list_len(l)); 1056 retval = list_join_inner(gap, l, sep, &join_ga); 1057 1058 #define FREE_JOIN_TOFREE(join) xfree((join)->tofree) 1059 GA_DEEP_CLEAR(&join_ga, Join, FREE_JOIN_TOFREE); 1060 #undef FREE_JOIN_TOFREE 1061 1062 return retval; 1063 } 1064 1065 /// "join()" function 1066 void f_join(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 1067 { 1068 if (argvars[0].v_type != VAR_LIST) { 1069 emsg(_(e_listreq)); 1070 return; 1071 } 1072 const char *const sep = (argvars[1].v_type == VAR_UNKNOWN 1073 ? " " 1074 : tv_get_string_chk(&argvars[1])); 1075 1076 rettv->v_type = VAR_STRING; 1077 1078 if (sep != NULL) { 1079 garray_T ga; 1080 ga_init(&ga, (int)sizeof(char), 80); 1081 tv_list_join(&ga, argvars[0].vval.v_list, sep); 1082 ga_append(&ga, NUL); 1083 rettv->vval.v_string = ga.ga_data; 1084 } else { 1085 rettv->vval.v_string = NULL; 1086 } 1087 } 1088 1089 /// "list2str()" function 1090 void f_list2str(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 1091 { 1092 garray_T ga; 1093 1094 rettv->v_type = VAR_STRING; 1095 rettv->vval.v_string = NULL; 1096 if (argvars[0].v_type != VAR_LIST) { 1097 emsg(_(e_invarg)); 1098 return; 1099 } 1100 1101 list_T *const l = argvars[0].vval.v_list; 1102 if (l == NULL) { 1103 return; // empty list results in empty string 1104 } 1105 1106 ga_init(&ga, 1, 80); 1107 char buf[MB_MAXBYTES + 1]; 1108 1109 TV_LIST_ITER_CONST(l, li, { 1110 const varnumber_T n = tv_get_number(TV_LIST_ITEM_TV(li)); 1111 const size_t buflen = (size_t)utf_char2bytes((int)n, buf); 1112 buf[buflen] = NUL; 1113 ga_concat_len(&ga, buf, buflen); 1114 }); 1115 ga_append(&ga, NUL); 1116 1117 rettv->vval.v_string = ga.ga_data; 1118 } 1119 1120 /// "remove({list})" function 1121 void tv_list_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) 1122 { 1123 list_T *l; 1124 bool error = false; 1125 1126 if (value_check_lock(tv_list_locked((l = argvars[0].vval.v_list)), 1127 arg_errmsg, TV_TRANSLATE)) { 1128 return; 1129 } 1130 1131 int64_t idx = tv_get_number_chk(&argvars[1], &error); 1132 1133 listitem_T *item; 1134 1135 if (error) { 1136 // Type error: do nothing, errmsg already given. 1137 } else if ((item = tv_list_find(l, (int)idx)) == NULL) { 1138 semsg(_(e_list_index_out_of_range_nr), idx); 1139 } else { 1140 if (argvars[2].v_type == VAR_UNKNOWN) { 1141 // Remove one item, return its value. 1142 tv_list_drop_items(l, item, item); 1143 *rettv = *TV_LIST_ITEM_TV(item); 1144 xfree(item); 1145 } else { 1146 listitem_T *item2; 1147 // Remove range of items, return list with values. 1148 int64_t end = tv_get_number_chk(&argvars[2], &error); 1149 if (error) { 1150 // Type error: do nothing. 1151 } else if ((item2 = tv_list_find(l, (int)end)) == NULL) { 1152 semsg(_(e_list_index_out_of_range_nr), end); 1153 } else { 1154 int cnt = 0; 1155 1156 listitem_T *li; 1157 for (li = item; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) { 1158 cnt++; 1159 if (li == item2) { 1160 break; 1161 } 1162 } 1163 if (li == NULL) { // Didn't find "item2" after "item". 1164 emsg(_(e_invrange)); 1165 } else { 1166 tv_list_move_items(l, item, item2, tv_list_alloc_ret(rettv, cnt), 1167 cnt); 1168 } 1169 } 1170 } 1171 } 1172 } 1173 1174 static sortinfo_T *sortinfo = NULL; 1175 1176 #define ITEM_COMPARE_FAIL 999 1177 1178 /// Compare functions for f_sort() and f_uniq() below. 1179 static int item_compare(const void *s1, const void *s2, bool keep_zero) 1180 { 1181 ListSortItem *const si1 = (ListSortItem *)s1; 1182 ListSortItem *const si2 = (ListSortItem *)s2; 1183 1184 typval_T *const tv1 = TV_LIST_ITEM_TV(si1->item); 1185 typval_T *const tv2 = TV_LIST_ITEM_TV(si2->item); 1186 1187 int res; 1188 1189 if (sortinfo->item_compare_numbers) { 1190 const varnumber_T v1 = tv_get_number(tv1); 1191 const varnumber_T v2 = tv_get_number(tv2); 1192 1193 res = v1 == v2 ? 0 : v1 > v2 ? 1 : -1; 1194 goto item_compare_end; 1195 } 1196 1197 if (sortinfo->item_compare_float) { 1198 const float_T v1 = tv_get_float(tv1); 1199 const float_T v2 = tv_get_float(tv2); 1200 1201 res = v1 == v2 ? 0 : v1 > v2 ? 1 : -1; 1202 goto item_compare_end; 1203 } 1204 1205 char *tofree1 = NULL; 1206 char *tofree2 = NULL; 1207 char *p1; 1208 char *p2; 1209 1210 // encode_tv2string() puts quotes around a string and allocates memory. Don't 1211 // do that for string variables. Use a single quote when comparing with 1212 // a non-string to do what the docs promise. 1213 if (tv1->v_type == VAR_STRING) { 1214 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) { 1215 p1 = "'"; 1216 } else { 1217 p1 = tv1->vval.v_string; 1218 } 1219 } else { 1220 tofree1 = p1 = encode_tv2string(tv1, NULL); 1221 } 1222 if (tv2->v_type == VAR_STRING) { 1223 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) { 1224 p2 = "'"; 1225 } else { 1226 p2 = tv2->vval.v_string; 1227 } 1228 } else { 1229 tofree2 = p2 = encode_tv2string(tv2, NULL); 1230 } 1231 if (p1 == NULL) { 1232 p1 = ""; 1233 } 1234 if (p2 == NULL) { 1235 p2 = ""; 1236 } 1237 if (!sortinfo->item_compare_numeric) { 1238 if (sortinfo->item_compare_lc) { 1239 res = strcoll(p1, p2); 1240 } else { 1241 res = sortinfo->item_compare_ic ? STRICMP(p1, p2) : strcmp(p1, p2); 1242 } 1243 } else { 1244 double n1 = strtod(p1, &p1); 1245 double n2 = strtod(p2, &p2); 1246 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1; 1247 } 1248 1249 xfree(tofree1); 1250 xfree(tofree2); 1251 1252 item_compare_end: 1253 // When the result would be zero, compare the item indexes. Makes the 1254 // sort stable. 1255 if (res == 0 && !keep_zero) { 1256 // WARNING: When using uniq si1 and si2 are actually listitem_T **, no 1257 // indexes are there. 1258 res = si1->idx > si2->idx ? 1 : -1; 1259 } 1260 return res; 1261 } 1262 1263 static int item_compare_keeping_zero(const void *s1, const void *s2) 1264 { 1265 return item_compare(s1, s2, true); 1266 } 1267 1268 static int item_compare_not_keeping_zero(const void *s1, const void *s2) 1269 { 1270 return item_compare(s1, s2, false); 1271 } 1272 1273 static int item_compare2(const void *s1, const void *s2, bool keep_zero) 1274 { 1275 typval_T rettv; 1276 typval_T argv[3]; 1277 const char *func_name; 1278 partial_T *partial = sortinfo->item_compare_partial; 1279 1280 // shortcut after failure in previous call; compare all items equal 1281 if (sortinfo->item_compare_func_err) { 1282 return 0; 1283 } 1284 1285 ListSortItem *si1 = (ListSortItem *)s1; 1286 ListSortItem *si2 = (ListSortItem *)s2; 1287 1288 if (partial == NULL) { 1289 func_name = sortinfo->item_compare_func; 1290 } else { 1291 func_name = partial_name(partial); 1292 } 1293 1294 // Copy the values. This is needed to be able to set v_lock to VAR_FIXED 1295 // in the copy without changing the original list items. 1296 tv_copy(TV_LIST_ITEM_TV(si1->item), &argv[0]); 1297 tv_copy(TV_LIST_ITEM_TV(si2->item), &argv[1]); 1298 1299 rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this 1300 funcexe_T funcexe = FUNCEXE_INIT; 1301 funcexe.fe_evaluate = true; 1302 funcexe.fe_partial = partial; 1303 funcexe.fe_selfdict = sortinfo->item_compare_selfdict; 1304 int res = call_func(func_name, -1, &rettv, 2, argv, &funcexe); 1305 tv_clear(&argv[0]); 1306 tv_clear(&argv[1]); 1307 1308 if (res == FAIL) { 1309 // XXX: ITEM_COMPARE_FAIL is unused 1310 res = ITEM_COMPARE_FAIL; 1311 sortinfo->item_compare_func_err = true; 1312 } else { 1313 varnumber_T n = tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err); 1314 res = (n > 0) ? 1 : (n < 0) ? -1 : 0; 1315 } 1316 if (sortinfo->item_compare_func_err) { 1317 res = ITEM_COMPARE_FAIL; // return value has wrong type 1318 } 1319 tv_clear(&rettv); 1320 1321 // When the result would be zero, compare the pointers themselves. Makes 1322 // the sort stable. 1323 if (res == 0 && !keep_zero) { 1324 // WARNING: When using uniq si1 and si2 are actually listitem_T **, no 1325 // indexes are there. 1326 res = si1->idx > si2->idx ? 1 : -1; 1327 } 1328 1329 return res; 1330 } 1331 1332 static int item_compare2_keeping_zero(const void *s1, const void *s2) 1333 { 1334 return item_compare2(s1, s2, true); 1335 } 1336 1337 static int item_compare2_not_keeping_zero(const void *s1, const void *s2) 1338 { 1339 return item_compare2(s1, s2, false); 1340 } 1341 1342 /// sort() List "l" 1343 static void do_sort(list_T *l, sortinfo_T *info) 1344 { 1345 const int len = tv_list_len(l); 1346 1347 // Make an array with each entry pointing to an item in the List. 1348 ListSortItem *ptrs = xmalloc((size_t)((unsigned)len * sizeof(ListSortItem))); 1349 1350 // f_sort(): ptrs will be the list to sort 1351 int i = 0; 1352 TV_LIST_ITER(l, li, { 1353 ptrs[i].item = li; 1354 ptrs[i].idx = i; 1355 i++; 1356 }); 1357 1358 info->item_compare_func_err = false; 1359 ListSorter item_compare_func = ((info->item_compare_func == NULL 1360 && info->item_compare_partial == NULL) 1361 ? item_compare_not_keeping_zero 1362 : item_compare2_not_keeping_zero); 1363 1364 // Sort the array with item pointers. 1365 qsort(ptrs, (size_t)len, sizeof(ListSortItem), item_compare_func); 1366 if (!info->item_compare_func_err) { 1367 // Clear the list and append the items in the sorted order. 1368 l->lv_first = NULL; 1369 l->lv_last = NULL; 1370 l->lv_idx_item = NULL; 1371 l->lv_len = 0; 1372 for (i = 0; i < len; i++) { 1373 tv_list_append(l, ptrs[i].item); 1374 } 1375 } 1376 if (info->item_compare_func_err) { 1377 emsg(_("E702: Sort compare function failed")); 1378 } 1379 1380 xfree(ptrs); 1381 } 1382 1383 /// uniq() List "l" 1384 static void do_uniq(list_T *l, sortinfo_T *info) 1385 { 1386 const int len = tv_list_len(l); 1387 1388 // Make an array with each entry pointing to an item in the List. 1389 ListSortItem *ptrs = xmalloc((size_t)((unsigned)len * sizeof(ListSortItem))); 1390 1391 // f_uniq(): ptrs will be a stack of items to remove. 1392 1393 info->item_compare_func_err = false; 1394 ListSorter item_compare_func = ((info->item_compare_func == NULL 1395 && info->item_compare_partial == NULL) 1396 ? item_compare_keeping_zero 1397 : item_compare2_keeping_zero); 1398 1399 for (listitem_T *li = TV_LIST_ITEM_NEXT(l, tv_list_first(l)); li != NULL;) { 1400 listitem_T *const prev_li = TV_LIST_ITEM_PREV(l, li); 1401 if (item_compare_func(&prev_li, &li) == 0) { 1402 li = tv_list_item_remove(l, li); 1403 } else { 1404 li = TV_LIST_ITEM_NEXT(l, li); 1405 } 1406 if (info->item_compare_func_err) { 1407 emsg(_("E882: Uniq compare function failed")); 1408 break; 1409 } 1410 } 1411 1412 xfree(ptrs); 1413 } 1414 1415 /// Parse the optional arguments to sort() and uniq() and return the values in "info". 1416 static int parse_sort_uniq_args(typval_T *argvars, sortinfo_T *info) 1417 { 1418 info->item_compare_ic = false; 1419 info->item_compare_lc = false; 1420 info->item_compare_numeric = false; 1421 info->item_compare_numbers = false; 1422 info->item_compare_float = false; 1423 info->item_compare_func = NULL; 1424 info->item_compare_partial = NULL; 1425 info->item_compare_selfdict = NULL; 1426 1427 if (argvars[1].v_type == VAR_UNKNOWN) { 1428 return OK; 1429 } 1430 1431 // optional second argument: {func} 1432 if (argvars[1].v_type == VAR_FUNC) { 1433 info->item_compare_func = argvars[1].vval.v_string; 1434 } else if (argvars[1].v_type == VAR_PARTIAL) { 1435 info->item_compare_partial = argvars[1].vval.v_partial; 1436 } else { 1437 bool error = false; 1438 int nr = (int)tv_get_number_chk(&argvars[1], &error); 1439 if (error) { 1440 return FAIL; // type error; errmsg already given 1441 } 1442 if (nr == 1) { 1443 info->item_compare_ic = true; 1444 } else if (argvars[1].v_type != VAR_NUMBER) { 1445 info->item_compare_func = tv_get_string(&argvars[1]); 1446 } else if (nr != 0) { 1447 emsg(_(e_invarg)); 1448 return FAIL; 1449 } 1450 if (info->item_compare_func != NULL) { 1451 if (*info->item_compare_func == NUL) { 1452 // empty string means default sort 1453 info->item_compare_func = NULL; 1454 } else if (strcmp(info->item_compare_func, "n") == 0) { 1455 info->item_compare_func = NULL; 1456 info->item_compare_numeric = true; 1457 } else if (strcmp(info->item_compare_func, "N") == 0) { 1458 info->item_compare_func = NULL; 1459 info->item_compare_numbers = true; 1460 } else if (strcmp(info->item_compare_func, "f") == 0) { 1461 info->item_compare_func = NULL; 1462 info->item_compare_float = true; 1463 } else if (strcmp(info->item_compare_func, "i") == 0) { 1464 info->item_compare_func = NULL; 1465 info->item_compare_ic = true; 1466 } else if (strcmp(info->item_compare_func, "l") == 0) { 1467 info->item_compare_func = NULL; 1468 info->item_compare_lc = true; 1469 } 1470 } 1471 } 1472 1473 if (argvars[2].v_type != VAR_UNKNOWN) { 1474 // optional third argument: {dict} 1475 if (tv_check_for_dict_arg(argvars, 2) == FAIL) { 1476 return FAIL; 1477 } 1478 info->item_compare_selfdict = argvars[2].vval.v_dict; 1479 } 1480 1481 return OK; 1482 } 1483 1484 /// "sort()" or "uniq()" function 1485 static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) 1486 { 1487 if (argvars[0].v_type != VAR_LIST) { 1488 semsg(_(e_listarg), sort ? "sort()" : "uniq()"); 1489 return; 1490 } 1491 1492 // Pointer to current info struct used in compare function. Save and restore 1493 // the current one for nested calls. 1494 sortinfo_T info; 1495 sortinfo_T *old_sortinfo = sortinfo; 1496 sortinfo = &info; 1497 1498 const char *const arg_errmsg = (sort ? N_("sort() argument") : N_("uniq() argument")); 1499 list_T *const l = argvars[0].vval.v_list; 1500 if (value_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE)) { 1501 goto theend; 1502 } 1503 tv_list_set_ret(rettv, l); 1504 1505 const int len = tv_list_len(l); 1506 if (len <= 1) { 1507 goto theend; // short list sorts pretty quickly 1508 } 1509 if (parse_sort_uniq_args(argvars, &info) == FAIL) { 1510 goto theend; 1511 } 1512 1513 if (sort) { 1514 do_sort(l, &info); 1515 } else { 1516 do_uniq(l, &info); 1517 } 1518 1519 theend: 1520 sortinfo = old_sortinfo; 1521 } 1522 1523 /// "sort({list})" function 1524 void f_sort(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 1525 { 1526 do_sort_uniq(argvars, rettv, true); 1527 } 1528 1529 /// "uniq({list})" function 1530 void f_uniq(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 1531 { 1532 do_sort_uniq(argvars, rettv, false); 1533 } 1534 1535 /// Check whether two lists are equal 1536 /// 1537 /// @param[in] l1 First list to compare. 1538 /// @param[in] l2 Second list to compare. 1539 /// @param[in] ic True if case is to be ignored. 1540 /// 1541 /// @return True if lists are equal, false otherwise. 1542 bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic) 1543 FUNC_ATTR_WARN_UNUSED_RESULT 1544 { 1545 if (l1 == l2) { 1546 return true; 1547 } 1548 if (tv_list_len(l1) != tv_list_len(l2)) { 1549 return false; 1550 } 1551 if (tv_list_len(l1) == 0) { 1552 // empty and NULL list are considered equal 1553 return true; 1554 } 1555 if (l1 == NULL || l2 == NULL) { 1556 return false; 1557 } 1558 1559 listitem_T *item1 = tv_list_first(l1); 1560 listitem_T *item2 = tv_list_first(l2); 1561 for (; item1 != NULL && item2 != NULL 1562 ; (item1 = TV_LIST_ITEM_NEXT(l1, item1), 1563 item2 = TV_LIST_ITEM_NEXT(l2, item2))) { 1564 if (!tv_equal(TV_LIST_ITEM_TV(item1), TV_LIST_ITEM_TV(item2), ic)) { 1565 return false; 1566 } 1567 } 1568 assert(item1 == NULL && item2 == NULL); 1569 return true; 1570 } 1571 1572 /// Reverse list in-place 1573 /// 1574 /// @param[in,out] l List to reverse. 1575 void tv_list_reverse(list_T *const l) 1576 { 1577 if (tv_list_len(l) <= 1) { 1578 return; 1579 } 1580 #define SWAP(a, b) \ 1581 do { \ 1582 tmp = (a); \ 1583 (a) = (b); \ 1584 (b) = tmp; \ 1585 } while (0) 1586 listitem_T *tmp; 1587 1588 SWAP(l->lv_first, l->lv_last); 1589 for (listitem_T *li = l->lv_first; li != NULL; li = li->li_next) { 1590 SWAP(li->li_next, li->li_prev); 1591 } 1592 #undef SWAP 1593 1594 l->lv_idx = l->lv_len - l->lv_idx - 1; 1595 } 1596 1597 // Indexing/searching: 1598 1599 /// Locate item with a given index in a list and return it 1600 /// 1601 /// @param[in] l List to index. 1602 /// @param[in] n Index. Negative index is counted from the end, -1 is the last 1603 /// item. 1604 /// 1605 /// @return Item at the given index or NULL if `n` is out of range. 1606 listitem_T *tv_list_find(list_T *const l, int n) 1607 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 1608 { 1609 STATIC_ASSERT(sizeof(n) == sizeof(l->lv_idx), 1610 "n and lv_idx sizes do not match"); 1611 if (l == NULL) { 1612 return NULL; 1613 } 1614 1615 n = tv_list_uidx(l, n); 1616 if (n == -1) { 1617 return NULL; 1618 } 1619 1620 int idx; 1621 listitem_T *item; 1622 1623 // When there is a cached index may start search from there. 1624 if (l->lv_idx_item != NULL) { 1625 if (n < l->lv_idx / 2) { 1626 // Closest to the start of the list. 1627 item = l->lv_first; 1628 idx = 0; 1629 } else if (n > (l->lv_idx + l->lv_len) / 2) { 1630 // Closest to the end of the list. 1631 item = l->lv_last; 1632 idx = l->lv_len - 1; 1633 } else { 1634 // Closest to the cached index. 1635 item = l->lv_idx_item; 1636 idx = l->lv_idx; 1637 } 1638 } else { 1639 if (n < l->lv_len / 2) { 1640 // Closest to the start of the list. 1641 item = l->lv_first; 1642 idx = 0; 1643 } else { 1644 // Closest to the end of the list. 1645 item = l->lv_last; 1646 idx = l->lv_len - 1; 1647 } 1648 } 1649 1650 while (n > idx) { 1651 // Search forward. 1652 item = item->li_next; 1653 idx++; 1654 } 1655 while (n < idx) { 1656 // Search backward. 1657 item = item->li_prev; 1658 idx--; 1659 } 1660 1661 assert(idx == n); 1662 // Cache the used index. 1663 l->lv_idx = idx; 1664 l->lv_idx_item = item; 1665 1666 return item; 1667 } 1668 1669 /// Get list item l[n] as a number 1670 /// 1671 /// @param[in] l List to index. 1672 /// @param[in] n Index in a list. 1673 /// @param[out] ret_error Location where 1 will be saved if index was not 1674 /// found. May be NULL. If everything is OK, 1675 /// `*ret_error` is not touched. 1676 /// 1677 /// @return Integer value at the given index or -1. 1678 varnumber_T tv_list_find_nr(list_T *const l, const int n, bool *const ret_error) 1679 FUNC_ATTR_WARN_UNUSED_RESULT 1680 { 1681 const listitem_T *const li = tv_list_find(l, n); 1682 if (li == NULL) { 1683 if (ret_error != NULL) { 1684 *ret_error = true; 1685 } 1686 return -1; 1687 } 1688 return tv_get_number_chk(TV_LIST_ITEM_TV(li), ret_error); 1689 } 1690 1691 /// Get list item l[n] as a string 1692 /// 1693 /// @param[in] l List to index. 1694 /// @param[in] n Index in a list. 1695 /// 1696 /// @return List item string value or NULL in case of error. 1697 const char *tv_list_find_str(list_T *const l, const int n) 1698 FUNC_ATTR_WARN_UNUSED_RESULT 1699 { 1700 const listitem_T *const li = tv_list_find(l, n); 1701 if (li == NULL) { 1702 semsg(_(e_list_index_out_of_range_nr), (int64_t)n); 1703 return NULL; 1704 } 1705 return tv_get_string(TV_LIST_ITEM_TV(li)); 1706 } 1707 1708 /// Like tv_list_find() but when a negative index is used that is not found use 1709 /// zero and set "idx" to zero. Used for first index of a range. 1710 static listitem_T *tv_list_find_index(list_T *const l, int *const idx) 1711 FUNC_ATTR_WARN_UNUSED_RESULT 1712 { 1713 listitem_T *li = tv_list_find(l, *idx); 1714 if (li != NULL) { 1715 return li; 1716 } 1717 1718 if (*idx < 0) { 1719 *idx = 0; 1720 li = tv_list_find(l, *idx); 1721 } 1722 return li; 1723 } 1724 1725 /// Locate item in a list and return its index 1726 /// 1727 /// @param[in] l List to search. 1728 /// @param[in] item Item to search for. 1729 /// 1730 /// @return Index of an item or -1 if item is not in the list. 1731 int tv_list_idx_of_item(const list_T *const l, const listitem_T *const item) 1732 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 1733 { 1734 if (l == NULL) { 1735 return -1; 1736 } 1737 int idx = 0; 1738 TV_LIST_ITER_CONST(l, li, { 1739 if (li == item) { 1740 return idx; 1741 } 1742 idx++; 1743 }); 1744 return -1; 1745 } 1746 1747 // Dictionaries: 1748 // Dictionary watchers: 1749 1750 /// Perform all necessary cleanup for a `DictWatcher` instance 1751 /// 1752 /// @param watcher Watcher to free. 1753 static void tv_dict_watcher_free(DictWatcher *watcher) 1754 FUNC_ATTR_NONNULL_ALL 1755 { 1756 callback_free(&watcher->callback); 1757 xfree(watcher->key_pattern); 1758 xfree(watcher); 1759 } 1760 1761 /// Add watcher to a dictionary 1762 /// 1763 /// @param[in] dict Dictionary to add watcher to. 1764 /// @param[in] key_pattern Pattern to watch for. 1765 /// @param[in] key_pattern_len Key pattern length. 1766 /// @param callback Function to be called on events. 1767 void tv_dict_watcher_add(dict_T *const dict, const char *const key_pattern, 1768 const size_t key_pattern_len, Callback callback) 1769 FUNC_ATTR_NONNULL_ARG(2) 1770 { 1771 if (dict == NULL) { 1772 return; 1773 } 1774 DictWatcher *const watcher = xmalloc(sizeof(DictWatcher)); 1775 watcher->key_pattern = xmemdupz(key_pattern, key_pattern_len); 1776 watcher->key_pattern_len = key_pattern_len; 1777 watcher->callback = callback; 1778 watcher->busy = false; 1779 watcher->needs_free = false; 1780 QUEUE_INSERT_TAIL(&dict->watchers, &watcher->node); 1781 } 1782 1783 /// Check whether two callbacks are equal 1784 /// 1785 /// @param[in] cb1 First callback to check. 1786 /// @param[in] cb2 Second callback to check. 1787 /// 1788 /// @return True if they are equal, false otherwise. 1789 bool tv_callback_equal(const Callback *cb1, const Callback *cb2) 1790 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 1791 { 1792 if (cb1->type != cb2->type) { 1793 return false; 1794 } 1795 switch (cb1->type) { 1796 case kCallbackFuncref: 1797 return strcmp(cb1->data.funcref, cb2->data.funcref) == 0; 1798 case kCallbackPartial: 1799 // FIXME: this is inconsistent with tv_equal but is needed for precision 1800 // maybe change dictwatcheradd to return a watcher id instead? 1801 return cb1->data.partial == cb2->data.partial; 1802 case kCallbackLua: 1803 return cb1->data.luaref == cb2->data.luaref; 1804 case kCallbackNone: 1805 return true; 1806 } 1807 abort(); 1808 return false; 1809 } 1810 1811 /// Unref/free callback 1812 void callback_free(Callback *callback) 1813 FUNC_ATTR_NONNULL_ALL 1814 { 1815 switch (callback->type) { 1816 case kCallbackFuncref: 1817 func_unref(callback->data.funcref); 1818 xfree(callback->data.funcref); 1819 break; 1820 case kCallbackPartial: 1821 partial_unref(callback->data.partial); 1822 break; 1823 case kCallbackLua: 1824 NLUA_CLEAR_REF(callback->data.luaref); 1825 break; 1826 case kCallbackNone: 1827 break; 1828 } 1829 callback->type = kCallbackNone; 1830 callback->data.funcref = NULL; 1831 } 1832 1833 /// Copy a callback into a typval_T. 1834 void callback_put(Callback *cb, typval_T *tv) 1835 FUNC_ATTR_NONNULL_ALL 1836 { 1837 switch (cb->type) { 1838 case kCallbackPartial: 1839 tv->v_type = VAR_PARTIAL; 1840 tv->vval.v_partial = cb->data.partial; 1841 cb->data.partial->pt_refcount++; 1842 break; 1843 case kCallbackFuncref: 1844 tv->v_type = VAR_FUNC; 1845 tv->vval.v_string = xstrdup(cb->data.funcref); 1846 func_ref(cb->data.funcref); 1847 break; 1848 case kCallbackLua: 1849 // TODO(tjdevries): Unified Callback. 1850 // At this point this isn't possible, but it'd be nice to put 1851 // these handled more neatly in one place. 1852 // So instead, we just do the default and put nil 1853 default: 1854 tv->v_type = VAR_SPECIAL; 1855 tv->vval.v_special = kSpecialVarNull; 1856 break; 1857 } 1858 } 1859 1860 // Copy callback from "src" to "dest", incrementing the refcounts. 1861 void callback_copy(Callback *dest, Callback *src) 1862 FUNC_ATTR_NONNULL_ALL 1863 { 1864 dest->type = src->type; 1865 switch (src->type) { 1866 case kCallbackPartial: 1867 dest->data.partial = src->data.partial; 1868 dest->data.partial->pt_refcount++; 1869 break; 1870 case kCallbackFuncref: 1871 dest->data.funcref = xstrdup(src->data.funcref); 1872 func_ref(src->data.funcref); 1873 break; 1874 case kCallbackLua: 1875 dest->data.luaref = api_new_luaref(src->data.luaref); 1876 break; 1877 default: 1878 dest->data.funcref = NULL; 1879 break; 1880 } 1881 } 1882 1883 /// Generate a string description of a callback 1884 char *callback_to_string(Callback *cb, Arena *arena) 1885 { 1886 if (cb->type == kCallbackLua) { 1887 return nlua_funcref_str(cb->data.luaref, arena); 1888 } 1889 1890 const size_t msglen = 100; 1891 char *msg = xmallocz(msglen); 1892 1893 switch (cb->type) { 1894 case kCallbackFuncref: 1895 // TODO(tjdevries): Is this enough space for this? 1896 snprintf(msg, msglen, "<vim function: %s>", cb->data.funcref); 1897 break; 1898 case kCallbackPartial: 1899 snprintf(msg, msglen, "<vim partial: %s>", cb->data.partial->pt_name); 1900 break; 1901 default: 1902 *msg = NUL; 1903 break; 1904 } 1905 return msg; 1906 } 1907 1908 /// Remove watcher from a dictionary 1909 /// 1910 /// @param dict Dictionary to remove watcher from. 1911 /// @param[in] key_pattern Pattern to remove watcher for. 1912 /// @param[in] key_pattern_len Pattern length. 1913 /// @param callback Callback to remove watcher for. 1914 /// 1915 /// @return True on success, false if relevant watcher was not found. 1916 bool tv_dict_watcher_remove(dict_T *const dict, const char *const key_pattern, 1917 const size_t key_pattern_len, Callback callback) 1918 FUNC_ATTR_NONNULL_ARG(2) 1919 { 1920 if (dict == NULL) { 1921 return false; 1922 } 1923 1924 QUEUE *w = NULL; 1925 DictWatcher *watcher = NULL; 1926 bool matched = false; 1927 bool queue_is_busy = false; 1928 QUEUE_FOREACH(w, &dict->watchers, { 1929 watcher = tv_dict_watcher_node_data(w); 1930 if (watcher->busy) { 1931 queue_is_busy = true; 1932 } 1933 if (tv_callback_equal(&watcher->callback, &callback) 1934 && watcher->key_pattern_len == key_pattern_len 1935 && memcmp(watcher->key_pattern, key_pattern, key_pattern_len) == 0) { 1936 matched = true; 1937 break; 1938 } 1939 }) 1940 1941 if (!matched) { 1942 return false; 1943 } 1944 1945 if (queue_is_busy) { 1946 watcher->needs_free = true; 1947 } else { 1948 QUEUE_REMOVE(w); 1949 tv_dict_watcher_free(watcher); 1950 } 1951 return true; 1952 } 1953 1954 /// Test if `key` matches with with `watcher->key_pattern` 1955 /// 1956 /// @param[in] watcher Watcher to check key pattern from. 1957 /// @param[in] key Key to check. 1958 /// 1959 /// @return true if key matches, false otherwise. 1960 static bool tv_dict_watcher_matches(DictWatcher *watcher, const char *const key) 1961 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 1962 { 1963 // For now only allow very simple globbing in key patterns: a '*' at the end 1964 // of the string means it should match everything up to the '*' instead of the 1965 // whole string. 1966 const size_t len = watcher->key_pattern_len; 1967 if (len && watcher->key_pattern[len - 1] == '*') { 1968 return strncmp(key, watcher->key_pattern, len - 1) == 0; 1969 } 1970 return strcmp(key, watcher->key_pattern) == 0; 1971 } 1972 1973 /// Send a change notification to all dictionary watchers that match given key 1974 /// 1975 /// @param[in] dict Dictionary which was modified. 1976 /// @param[in] key Key which was modified. 1977 /// @param[in] newtv New key value. 1978 /// @param[in] oldtv Old key value. 1979 void tv_dict_watcher_notify(dict_T *const dict, const char *const key, typval_T *const newtv, 1980 typval_T *const oldtv) 1981 FUNC_ATTR_NONNULL_ARG(1, 2) 1982 { 1983 typval_T argv[3]; 1984 1985 argv[0].v_type = VAR_DICT; 1986 argv[0].v_lock = VAR_UNLOCKED; 1987 argv[0].vval.v_dict = dict; 1988 argv[1].v_type = VAR_STRING; 1989 argv[1].v_lock = VAR_UNLOCKED; 1990 argv[1].vval.v_string = xstrdup(key); 1991 argv[2].v_type = VAR_DICT; 1992 argv[2].v_lock = VAR_UNLOCKED; 1993 argv[2].vval.v_dict = tv_dict_alloc(); 1994 argv[2].vval.v_dict->dv_refcount++; 1995 1996 if (newtv) { 1997 dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("new")); 1998 tv_copy(newtv, &v->di_tv); 1999 tv_dict_add(argv[2].vval.v_dict, v); 2000 } 2001 2002 if (oldtv && oldtv->v_type != VAR_UNKNOWN) { 2003 dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("old")); 2004 tv_copy(oldtv, &v->di_tv); 2005 tv_dict_add(argv[2].vval.v_dict, v); 2006 } 2007 2008 typval_T rettv; 2009 2010 bool any_needs_free = false; 2011 dict->dv_refcount++; 2012 QUEUE *w; 2013 QUEUE_FOREACH(w, &dict->watchers, { 2014 DictWatcher *watcher = tv_dict_watcher_node_data(w); 2015 if (!watcher->busy && tv_dict_watcher_matches(watcher, key)) { 2016 rettv = TV_INITIAL_VALUE; 2017 watcher->busy = true; 2018 callback_call(&watcher->callback, 3, argv, &rettv); 2019 watcher->busy = false; 2020 tv_clear(&rettv); 2021 if (watcher->needs_free) { 2022 any_needs_free = true; 2023 } 2024 } 2025 }) 2026 if (any_needs_free) { 2027 QUEUE_FOREACH(w, &dict->watchers, { 2028 DictWatcher *watcher = tv_dict_watcher_node_data(w); 2029 if (watcher->needs_free) { 2030 QUEUE_REMOVE(w); 2031 tv_dict_watcher_free(watcher); 2032 } 2033 }) 2034 } 2035 tv_dict_unref(dict); 2036 2037 for (size_t i = 1; i < ARRAY_SIZE(argv); i++) { 2038 tv_clear(argv + i); 2039 } 2040 } 2041 2042 // Dictionary item: 2043 2044 /// Allocate a dictionary item 2045 /// 2046 /// @note that the type and value of the item (->di_tv) still needs to 2047 /// be initialized. 2048 /// 2049 /// @param[in] key Key, is copied to the new item. 2050 /// @param[in] key_len Key length. 2051 /// 2052 /// @return [allocated] new dictionary item. 2053 dictitem_T *tv_dict_item_alloc_len(const char *const key, const size_t key_len) 2054 FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 2055 FUNC_ATTR_MALLOC 2056 { 2057 // Allocating a struct smaller than its static size is UB (#37160) 2058 dictitem_T *const di = xmalloc(MAX(sizeof(dictitem_T), 2059 offsetof(dictitem_T, di_key) + key_len + 1)); 2060 memcpy(di->di_key, key, key_len); 2061 di->di_key[key_len] = NUL; 2062 di->di_flags = DI_FLAGS_ALLOC; 2063 di->di_tv.v_lock = VAR_UNLOCKED; 2064 di->di_tv.v_type = VAR_UNKNOWN; 2065 return di; 2066 } 2067 2068 /// Allocate a dictionary item 2069 /// 2070 /// @note that the type and value of the item (->di_tv) still needs to 2071 /// be initialized. 2072 /// 2073 /// @param[in] key Key, is copied to the new item. 2074 /// 2075 /// @return [allocated] new dictionary item. 2076 dictitem_T *tv_dict_item_alloc(const char *const key) 2077 FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 2078 FUNC_ATTR_MALLOC 2079 { 2080 return tv_dict_item_alloc_len(key, strlen(key)); 2081 } 2082 2083 /// Free a dictionary item, also clearing the value 2084 /// 2085 /// @param item Item to free. 2086 void tv_dict_item_free(dictitem_T *const item) 2087 FUNC_ATTR_NONNULL_ALL 2088 { 2089 tv_clear(&item->di_tv); 2090 if (item->di_flags & DI_FLAGS_ALLOC) { 2091 xfree(item); 2092 } 2093 } 2094 2095 /// Make a copy of a dictionary item 2096 /// 2097 /// @param[in] di Item to copy. 2098 /// 2099 /// @return [allocated] new dictionary item. 2100 dictitem_T *tv_dict_item_copy(dictitem_T *const di) 2101 FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 2102 { 2103 dictitem_T *const new_di = tv_dict_item_alloc(di->di_key); 2104 tv_copy(&di->di_tv, &new_di->di_tv); 2105 return new_di; 2106 } 2107 2108 /// Remove item from dictionary and free it 2109 /// 2110 /// @param dict Dictionary to remove item from. 2111 /// @param item Item to remove. 2112 void tv_dict_item_remove(dict_T *const dict, dictitem_T *const item) 2113 FUNC_ATTR_NONNULL_ALL 2114 { 2115 hashitem_T *const hi = hash_find(&dict->dv_hashtab, item->di_key); 2116 if (HASHITEM_EMPTY(hi)) { 2117 semsg(_(e_intern2), "tv_dict_item_remove()"); 2118 } else { 2119 hash_remove(&dict->dv_hashtab, hi); 2120 } 2121 tv_dict_item_free(item); 2122 } 2123 2124 // Alloc/free: 2125 2126 /// Allocate an empty dictionary. 2127 /// Caller should take care of the reference count. 2128 /// 2129 /// @return [allocated] new dictionary. 2130 dict_T *tv_dict_alloc(void) 2131 FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT 2132 { 2133 dict_T *const d = xcalloc(1, sizeof(dict_T)); 2134 2135 // Add the dict to the list of dicts for garbage collection. 2136 if (gc_first_dict != NULL) { 2137 gc_first_dict->dv_used_prev = d; 2138 } 2139 d->dv_used_next = gc_first_dict; 2140 d->dv_used_prev = NULL; 2141 gc_first_dict = d; 2142 2143 hash_init(&d->dv_hashtab); 2144 d->dv_lock = VAR_UNLOCKED; 2145 d->dv_scope = VAR_NO_SCOPE; 2146 d->dv_refcount = 0; 2147 d->dv_copyID = 0; 2148 QUEUE_INIT(&d->watchers); 2149 2150 d->lua_table_ref = LUA_NOREF; 2151 2152 return d; 2153 } 2154 2155 /// Free items contained in a dictionary 2156 /// 2157 /// @param[in,out] d Dictionary to clear. 2158 void tv_dict_free_contents(dict_T *const d) 2159 FUNC_ATTR_NONNULL_ALL 2160 { 2161 // Lock the hashtab, we don't want it to resize while freeing items. 2162 hash_lock(&d->dv_hashtab); 2163 assert(d->dv_hashtab.ht_locked > 0); 2164 HASHTAB_ITER(&d->dv_hashtab, hi, { 2165 // Remove the item before deleting it, just in case there is 2166 // something recursive causing trouble. 2167 dictitem_T *const di = TV_DICT_HI2DI(hi); 2168 hash_remove(&d->dv_hashtab, hi); 2169 tv_dict_item_free(di); 2170 }); 2171 2172 while (!QUEUE_EMPTY(&d->watchers)) { 2173 QUEUE *w = QUEUE_HEAD(&d->watchers); 2174 QUEUE_REMOVE(w); 2175 DictWatcher *watcher = tv_dict_watcher_node_data(w); 2176 tv_dict_watcher_free(watcher); 2177 } 2178 2179 hash_clear(&d->dv_hashtab); 2180 d->dv_hashtab.ht_locked--; 2181 hash_init(&d->dv_hashtab); 2182 } 2183 2184 /// Free a dictionary itself, ignoring items it contains 2185 /// 2186 /// Ignores the reference count. 2187 /// 2188 /// @param[in,out] d Dictionary to free. 2189 void tv_dict_free_dict(dict_T *const d) 2190 FUNC_ATTR_NONNULL_ALL 2191 { 2192 // Remove the dict from the list of dicts for garbage collection. 2193 if (d->dv_used_prev == NULL) { 2194 gc_first_dict = d->dv_used_next; 2195 } else { 2196 d->dv_used_prev->dv_used_next = d->dv_used_next; 2197 } 2198 if (d->dv_used_next != NULL) { 2199 d->dv_used_next->dv_used_prev = d->dv_used_prev; 2200 } 2201 2202 NLUA_CLEAR_REF(d->lua_table_ref); 2203 xfree(d); 2204 } 2205 2206 /// Free a dictionary, including all items it contains 2207 /// 2208 /// Ignores the reference count. 2209 /// 2210 /// @param d Dictionary to free. 2211 void tv_dict_free(dict_T *const d) 2212 FUNC_ATTR_NONNULL_ALL 2213 { 2214 if (tv_in_free_unref_items) { 2215 return; 2216 } 2217 2218 tv_dict_free_contents(d); 2219 tv_dict_free_dict(d); 2220 } 2221 2222 /// Unreference a dictionary 2223 /// 2224 /// Decrements the reference count and frees dictionary when it becomes zero. 2225 /// 2226 /// @param[in] d Dictionary to operate on. 2227 void tv_dict_unref(dict_T *const d) 2228 { 2229 if (d != NULL && --d->dv_refcount <= 0) { 2230 tv_dict_free(d); 2231 } 2232 } 2233 2234 // Indexing/searching: 2235 2236 /// Find item in dictionary 2237 /// 2238 /// @param[in] d Dictionary to check. 2239 /// @param[in] key Dictionary key. 2240 /// @param[in] len Key length. If negative, then strlen(key) is used. 2241 /// 2242 /// @return found item or NULL if nothing was found. 2243 dictitem_T *tv_dict_find(const dict_T *const d, const char *const key, const ptrdiff_t len) 2244 FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 2245 { 2246 if (d == NULL) { 2247 return NULL; 2248 } 2249 hashitem_T *const hi = (len < 0 2250 ? hash_find(&d->dv_hashtab, key) 2251 : hash_find_len(&d->dv_hashtab, key, (size_t)len)); 2252 if (HASHITEM_EMPTY(hi)) { 2253 return NULL; 2254 } 2255 return TV_DICT_HI2DI(hi); 2256 } 2257 2258 /// Check if a key is present in a dictionary. 2259 /// 2260 /// @param[in] d Dictionary to check. 2261 /// @param[in] key Dictionary key. 2262 /// 2263 /// @return whether the key is present in the dictionary. 2264 bool tv_dict_has_key(const dict_T *const d, const char *const key) 2265 FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 2266 { 2267 return tv_dict_find(d, key, -1) != NULL; 2268 } 2269 2270 /// Get a typval item from a dictionary and copy it into "rettv". 2271 /// 2272 /// @param[in] d Dictionary to check. 2273 /// @param[in] key Dictionary key. 2274 /// @param[in] rettv Return value. 2275 /// @return OK in case of success or FAIL if nothing was found. 2276 int tv_dict_get_tv(dict_T *d, const char *const key, typval_T *rettv) 2277 { 2278 dictitem_T *const di = tv_dict_find(d, key, -1); 2279 if (di == NULL) { 2280 return FAIL; 2281 } 2282 2283 tv_copy(&di->di_tv, rettv); 2284 return OK; 2285 } 2286 2287 /// Gets a number item from a dictionary. 2288 /// 2289 /// @param[in] d Dictionary to get item from. 2290 /// @param[in] key Key to find in dictionary. 2291 /// 2292 /// @return Number value, or 0 if the item does not exist. 2293 varnumber_T tv_dict_get_number(const dict_T *const d, const char *const key) 2294 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 2295 { 2296 return tv_dict_get_number_def(d, key, 0); 2297 } 2298 2299 /// Gets a number item from a dictionary, or a given default value. 2300 /// 2301 /// @param[in] d Dictionary to get item from. 2302 /// @param[in] key Key to find in dictionary. 2303 /// @param[in] def Default value. 2304 /// 2305 /// @return Number value, or `def` value if the item does not exist. 2306 varnumber_T tv_dict_get_number_def(const dict_T *const d, const char *const key, const int def) 2307 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 2308 { 2309 dictitem_T *const di = tv_dict_find(d, key, -1); 2310 if (di == NULL) { 2311 return def; 2312 } 2313 return tv_get_number(&di->di_tv); 2314 } 2315 2316 varnumber_T tv_dict_get_bool(const dict_T *const d, const char *const key, const int def) 2317 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 2318 { 2319 dictitem_T *const di = tv_dict_find(d, key, -1); 2320 if (di == NULL) { 2321 return def; 2322 } 2323 return tv_get_bool(&di->di_tv); 2324 } 2325 2326 /// Converts a dict to an environment 2327 char **tv_dict_to_env(dict_T *denv) 2328 { 2329 size_t env_size = (size_t)tv_dict_len(denv); 2330 2331 size_t i = 0; 2332 char **env = NULL; 2333 2334 // + 1 for NULL 2335 env = xmalloc((env_size + 1) * sizeof(*env)); 2336 2337 TV_DICT_ITER(denv, var, { 2338 const char *str = tv_get_string(&var->di_tv); 2339 assert(str); 2340 size_t len = strlen(var->di_key) + strlen(str) + strlen("=") + 1; 2341 env[i] = xmalloc(len); 2342 snprintf(env[i], len, "%s=%s", var->di_key, str); 2343 i++; 2344 }); 2345 2346 // must be null terminated 2347 env[env_size] = NULL; 2348 return env; 2349 } 2350 2351 /// Get a string item from a dictionary 2352 /// 2353 /// @param[in] d Dictionary to get item from. 2354 /// @param[in] key Dictionary key. 2355 /// @param[in] save If true, returned string will be placed in the allocated 2356 /// memory. 2357 /// 2358 /// @return NULL if key does not exist, empty string in case of type error, 2359 /// string item value otherwise. If returned value is not NULL, it may 2360 /// be allocated depending on `save` argument. 2361 char *tv_dict_get_string(const dict_T *const d, const char *const key, const bool save) 2362 FUNC_ATTR_WARN_UNUSED_RESULT 2363 { 2364 static char numbuf[NUMBUFLEN]; 2365 const char *const s = tv_dict_get_string_buf(d, key, numbuf); 2366 if (save && s != NULL) { 2367 return xstrdup(s); 2368 } 2369 return (char *)s; 2370 } 2371 2372 /// Get a string item from a dictionary 2373 /// 2374 /// @param[in] d Dictionary to get item from. 2375 /// @param[in] key Dictionary key. 2376 /// @param[in] numbuf Buffer for non-string items converted to strings, at 2377 /// least of #NUMBUFLEN length. 2378 /// 2379 /// @return NULL if key does not exist, empty string in case of type error, 2380 /// string item value otherwise. 2381 const char *tv_dict_get_string_buf(const dict_T *const d, const char *const key, char *const numbuf) 2382 FUNC_ATTR_WARN_UNUSED_RESULT 2383 { 2384 const dictitem_T *const di = tv_dict_find(d, key, -1); 2385 if (di == NULL) { 2386 return NULL; 2387 } 2388 return tv_get_string_buf(&di->di_tv, numbuf); 2389 } 2390 2391 /// Get a string item from a dictionary 2392 /// 2393 /// @param[in] d Dictionary to get item from. 2394 /// @param[in] key Dictionary key. 2395 /// @param[in] key_len Key length. 2396 /// @param[in] numbuf Buffer for non-string items converted to strings, at 2397 /// least of #NUMBUFLEN length. 2398 /// @param[in] def Default return when key does not exist. 2399 /// 2400 /// @return `def` when key does not exist, 2401 /// NULL in case of type error, 2402 /// string item value in case of success. 2403 const char *tv_dict_get_string_buf_chk(const dict_T *const d, const char *const key, 2404 const ptrdiff_t key_len, char *const numbuf, 2405 const char *const def) 2406 FUNC_ATTR_WARN_UNUSED_RESULT 2407 { 2408 const dictitem_T *const di = tv_dict_find(d, key, key_len); 2409 if (di == NULL) { 2410 return def; 2411 } 2412 return tv_get_string_buf_chk(&di->di_tv, numbuf); 2413 } 2414 2415 /// Get a function from a dictionary 2416 /// 2417 /// @param[in] d Dictionary to get callback from. 2418 /// @param[in] key Dictionary key. 2419 /// @param[in] key_len Key length, may be -1 to use strlen(). 2420 /// @param[out] result The address where a pointer to the wanted callback 2421 /// will be left. 2422 /// 2423 /// @return true/false on success/failure. 2424 bool tv_dict_get_callback(dict_T *const d, const char *const key, const ptrdiff_t key_len, 2425 Callback *const result) 2426 FUNC_ATTR_NONNULL_ARG(2, 4) FUNC_ATTR_WARN_UNUSED_RESULT 2427 { 2428 result->type = kCallbackNone; 2429 2430 dictitem_T *const di = tv_dict_find(d, key, key_len); 2431 2432 if (di == NULL) { 2433 return true; 2434 } 2435 2436 if (!tv_is_func(di->di_tv) && di->di_tv.v_type != VAR_STRING) { 2437 emsg(_("E6000: Argument is not a function or function name")); 2438 return false; 2439 } 2440 2441 typval_T tv; 2442 tv_copy(&di->di_tv, &tv); 2443 set_selfdict(&tv, d); 2444 const bool res = callback_from_typval(result, &tv); 2445 tv_clear(&tv); 2446 return res; 2447 } 2448 2449 /// Check for adding a function to g: or l:. 2450 /// If the name is wrong give an error message and return true. 2451 int tv_dict_wrong_func_name(dict_T *d, typval_T *tv, const char *name) 2452 { 2453 return (d == get_globvar_dict() || &d->dv_hashtab == get_funccal_local_ht()) 2454 && tv_is_func(*tv) 2455 && var_wrong_func_name(name, true); 2456 } 2457 2458 // dict_add*: 2459 2460 /// Add item to dictionary 2461 /// 2462 /// @param[out] d Dictionary to add to. 2463 /// @param[in] item Item to add. 2464 /// 2465 /// @return FAIL if key already exists. 2466 int tv_dict_add(dict_T *const d, dictitem_T *const item) 2467 FUNC_ATTR_NONNULL_ALL 2468 { 2469 if (tv_dict_wrong_func_name(d, &item->di_tv, item->di_key)) { 2470 return FAIL; 2471 } 2472 return hash_add(&d->dv_hashtab, item->di_key); 2473 } 2474 2475 /// Add a list entry to dictionary 2476 /// 2477 /// @param[out] d Dictionary to add entry to. 2478 /// @param[in] key Key to add. 2479 /// @param[in] key_len Key length. 2480 /// @param list List to add. Will have reference count incremented. 2481 /// 2482 /// @return OK in case of success, FAIL when key already exists. 2483 int tv_dict_add_list(dict_T *const d, const char *const key, const size_t key_len, 2484 list_T *const list) 2485 FUNC_ATTR_NONNULL_ALL 2486 { 2487 dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); 2488 2489 item->di_tv.v_type = VAR_LIST; 2490 item->di_tv.vval.v_list = list; 2491 tv_list_ref(list); 2492 if (tv_dict_add(d, item) == FAIL) { 2493 tv_dict_item_free(item); 2494 return FAIL; 2495 } 2496 return OK; 2497 } 2498 2499 /// Add a typval entry to dictionary. 2500 /// 2501 /// @param[out] d Dictionary to add entry to. 2502 /// @param[in] key Key to add. 2503 /// @param[in] key_len Key length. 2504 /// 2505 /// @return FAIL if out of memory or key already exists. 2506 int tv_dict_add_tv(dict_T *d, const char *key, const size_t key_len, typval_T *tv) 2507 { 2508 dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); 2509 2510 tv_copy(tv, &item->di_tv); 2511 if (tv_dict_add(d, item) == FAIL) { 2512 tv_dict_item_free(item); 2513 return FAIL; 2514 } 2515 return OK; 2516 } 2517 2518 /// Add a dictionary entry to dictionary 2519 /// 2520 /// @param[out] d Dictionary to add entry to. 2521 /// @param[in] key Key to add. 2522 /// @param[in] key_len Key length. 2523 /// @param dict Dictionary to add. Will have reference count incremented. 2524 /// 2525 /// @return OK in case of success, FAIL when key already exists. 2526 int tv_dict_add_dict(dict_T *const d, const char *const key, const size_t key_len, 2527 dict_T *const dict) 2528 FUNC_ATTR_NONNULL_ALL 2529 { 2530 dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); 2531 2532 item->di_tv.v_type = VAR_DICT; 2533 item->di_tv.vval.v_dict = dict; 2534 dict->dv_refcount++; 2535 if (tv_dict_add(d, item) == FAIL) { 2536 tv_dict_item_free(item); 2537 return FAIL; 2538 } 2539 return OK; 2540 } 2541 2542 /// Add a number entry to dictionary 2543 /// 2544 /// @param[out] d Dictionary to add entry to. 2545 /// @param[in] key Key to add. 2546 /// @param[in] key_len Key length. 2547 /// @param[in] nr Number to add. 2548 /// 2549 /// @return OK in case of success, FAIL when key already exists. 2550 int tv_dict_add_nr(dict_T *const d, const char *const key, const size_t key_len, 2551 const varnumber_T nr) 2552 { 2553 dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); 2554 2555 item->di_tv.v_type = VAR_NUMBER; 2556 item->di_tv.vval.v_number = nr; 2557 if (tv_dict_add(d, item) == FAIL) { 2558 tv_dict_item_free(item); 2559 return FAIL; 2560 } 2561 return OK; 2562 } 2563 2564 /// Add a floating point number entry to dictionary 2565 /// 2566 /// @param[out] d Dictionary to add entry to. 2567 /// @param[in] key Key to add. 2568 /// @param[in] key_len Key length. 2569 /// @param[in] nr Floating point number to add. 2570 /// 2571 /// @return OK in case of success, FAIL when key already exists. 2572 int tv_dict_add_float(dict_T *const d, const char *const key, const size_t key_len, 2573 const float_T nr) 2574 { 2575 dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); 2576 2577 item->di_tv.v_type = VAR_FLOAT; 2578 item->di_tv.vval.v_float = nr; 2579 if (tv_dict_add(d, item) == FAIL) { 2580 tv_dict_item_free(item); 2581 return FAIL; 2582 } 2583 return OK; 2584 } 2585 2586 /// Add a boolean entry to dictionary 2587 /// 2588 /// @param[out] d Dictionary to add entry to. 2589 /// @param[in] key Key to add. 2590 /// @param[in] key_len Key length. 2591 /// @param[in] val BoolVarValue to add. 2592 /// 2593 /// @return OK in case of success, FAIL when key already exists. 2594 int tv_dict_add_bool(dict_T *const d, const char *const key, const size_t key_len, BoolVarValue val) 2595 { 2596 dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); 2597 2598 item->di_tv.v_type = VAR_BOOL; 2599 item->di_tv.vval.v_bool = val; 2600 if (tv_dict_add(d, item) == FAIL) { 2601 tv_dict_item_free(item); 2602 return FAIL; 2603 } 2604 return OK; 2605 } 2606 2607 /// Add a string entry to dictionary 2608 /// 2609 /// @see tv_dict_add_allocated_str 2610 int tv_dict_add_str(dict_T *const d, const char *const key, const size_t key_len, 2611 const char *const val) 2612 FUNC_ATTR_NONNULL_ARG(1, 2) 2613 { 2614 return tv_dict_add_str_len(d, key, key_len, val, -1); 2615 } 2616 2617 /// Add a string entry to dictionary 2618 /// 2619 /// @param[out] d Dictionary to add entry to. 2620 /// @param[in] key Key to add. 2621 /// @param[in] key_len Key length. 2622 /// @param[in] val String to add. NULL adds empty string. 2623 /// @param[in] len Use this many bytes from `val`, or -1 for whole string. 2624 /// 2625 /// @return OK in case of success, FAIL when key already exists. 2626 int tv_dict_add_str_len(dict_T *const d, const char *const key, const size_t key_len, 2627 const char *const val, int len) 2628 FUNC_ATTR_NONNULL_ARG(1, 2) 2629 { 2630 char *s = NULL; 2631 if (val != NULL) { 2632 s = (len < 0) ? xstrdup(val) : xstrndup(val, (size_t)len); 2633 } 2634 return tv_dict_add_allocated_str(d, key, key_len, s); 2635 } 2636 2637 /// Add a string entry to dictionary 2638 /// 2639 /// Unlike tv_dict_add_str() saves val to the new dictionary item in place of 2640 /// creating a new copy. 2641 /// 2642 /// @warning String will be freed even in case addition fails. 2643 /// 2644 /// @param[out] d Dictionary to add entry to. 2645 /// @param[in] key Key to add. 2646 /// @param[in] key_len Key length. 2647 /// @param[in] val String to add. 2648 /// 2649 /// @return OK in case of success, FAIL when key already exists. 2650 int tv_dict_add_allocated_str(dict_T *const d, const char *const key, const size_t key_len, 2651 char *const val) 2652 FUNC_ATTR_NONNULL_ARG(1, 2) 2653 { 2654 dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); 2655 2656 item->di_tv.v_type = VAR_STRING; 2657 item->di_tv.vval.v_string = val; 2658 if (tv_dict_add(d, item) == FAIL) { 2659 tv_dict_item_free(item); 2660 return FAIL; 2661 } 2662 return OK; 2663 } 2664 2665 /// Add a function entry to dictionary. 2666 /// 2667 /// @param[out] d Dictionary to add entry to. 2668 /// @param[in] key Key to add. 2669 /// @param[in] key_len Key length. 2670 /// @param[in] fp Function to add. 2671 /// 2672 /// @return OK in case of success, FAIL when key already exists. 2673 int tv_dict_add_func(dict_T *const d, const char *const key, const size_t key_len, 2674 ufunc_T *const fp) 2675 FUNC_ATTR_NONNULL_ARG(1, 2, 4) 2676 { 2677 dictitem_T *const item = tv_dict_item_alloc_len(key, key_len); 2678 2679 item->di_tv.v_type = VAR_FUNC; 2680 item->di_tv.vval.v_string = xmemdupz(fp->uf_name, fp->uf_namelen); 2681 if (tv_dict_add(d, item) == FAIL) { 2682 tv_dict_item_free(item); 2683 return FAIL; 2684 } 2685 func_ref(item->di_tv.vval.v_string); 2686 return OK; 2687 } 2688 2689 // Operations on the whole dict: 2690 2691 /// Clear all the keys of a Dictionary. "d" remains a valid empty Dictionary. 2692 /// 2693 /// @param d The Dictionary to clear 2694 void tv_dict_clear(dict_T *const d) 2695 FUNC_ATTR_NONNULL_ALL 2696 { 2697 hash_lock(&d->dv_hashtab); 2698 assert(d->dv_hashtab.ht_locked > 0); 2699 2700 HASHTAB_ITER(&d->dv_hashtab, hi, { 2701 tv_dict_item_free(TV_DICT_HI2DI(hi)); 2702 hash_remove(&d->dv_hashtab, hi); 2703 }); 2704 2705 hash_unlock(&d->dv_hashtab); 2706 } 2707 2708 /// Extend dictionary with items from another dictionary 2709 /// 2710 /// @param d1 Dictionary to extend. 2711 /// @param[in] d2 Dictionary to extend with. 2712 /// @param[in] action "error", "force", "move", "keep": 2713 /// e*, including "error": duplicate key gives an error. 2714 /// f*, including "force": duplicate d2 keys override d1. 2715 /// m*, including "move": move items instead of copying. 2716 /// other, including "keep": duplicate d2 keys ignored. 2717 void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action) 2718 FUNC_ATTR_NONNULL_ALL 2719 { 2720 const bool watched = tv_dict_is_watched(d1); 2721 const char *const arg_errmsg = _("extend() argument"); 2722 const size_t arg_errmsg_len = strlen(arg_errmsg); 2723 2724 if (*action == 'm') { 2725 hash_lock(&d2->dv_hashtab); // don't rehash on hash_remove() 2726 } 2727 2728 HASHTAB_ITER(&d2->dv_hashtab, hi2, { 2729 dictitem_T *const di2 = TV_DICT_HI2DI(hi2); 2730 dictitem_T *const di1 = tv_dict_find(d1, di2->di_key, -1); 2731 // Check the key to be valid when adding to any scope. 2732 if (d1->dv_scope != VAR_NO_SCOPE && !valid_varname(di2->di_key)) { 2733 break; 2734 } 2735 if (di1 == NULL) { 2736 if (*action == 'm') { 2737 // Cheap way to move a dict item from "d2" to "d1". 2738 // If dict_add() fails then "d2" won't be empty. 2739 dictitem_T *const new_di = di2; 2740 if (tv_dict_add(d1, new_di) == OK) { 2741 hash_remove(&d2->dv_hashtab, hi2); 2742 tv_dict_watcher_notify(d1, new_di->di_key, &new_di->di_tv, NULL); 2743 } 2744 } else { 2745 dictitem_T *const new_di = tv_dict_item_copy(di2); 2746 if (tv_dict_add(d1, new_di) == FAIL) { 2747 tv_dict_item_free(new_di); 2748 } else if (watched) { 2749 tv_dict_watcher_notify(d1, new_di->di_key, &new_di->di_tv, NULL); 2750 } 2751 } 2752 } else if (*action == 'e') { 2753 semsg(_("E737: Key already exists: %s"), di2->di_key); 2754 break; 2755 } else if (*action == 'f' && di2 != di1) { 2756 typval_T oldtv; 2757 2758 if (value_check_lock(di1->di_tv.v_lock, arg_errmsg, arg_errmsg_len) 2759 || var_check_ro(di1->di_flags, arg_errmsg, arg_errmsg_len)) { 2760 break; 2761 } 2762 // Disallow replacing a builtin function. 2763 if (tv_dict_wrong_func_name(d1, &di2->di_tv, di2->di_key)) { 2764 break; 2765 } 2766 2767 if (watched) { 2768 tv_copy(&di1->di_tv, &oldtv); 2769 } 2770 2771 tv_clear(&di1->di_tv); 2772 tv_copy(&di2->di_tv, &di1->di_tv); 2773 2774 if (watched) { 2775 tv_dict_watcher_notify(d1, di1->di_key, &di1->di_tv, &oldtv); 2776 tv_clear(&oldtv); 2777 } 2778 } 2779 }); 2780 2781 if (*action == 'm') { 2782 hash_unlock(&d2->dv_hashtab); 2783 } 2784 } 2785 2786 /// Compare two dictionaries 2787 /// 2788 /// @param[in] d1 First dictionary. 2789 /// @param[in] d2 Second dictionary. 2790 /// @param[in] ic True if case is to be ignored. 2791 /// 2792 /// @return True if dictionaries are equal, false otherwise. 2793 bool tv_dict_equal(dict_T *const d1, dict_T *const d2, const bool ic) 2794 FUNC_ATTR_WARN_UNUSED_RESULT 2795 { 2796 if (d1 == d2) { 2797 return true; 2798 } 2799 if (tv_dict_len(d1) != tv_dict_len(d2)) { 2800 return false; 2801 } 2802 if (tv_dict_len(d1) == 0) { 2803 // empty and NULL dicts are considered equal 2804 return true; 2805 } 2806 if (d1 == NULL || d2 == NULL) { 2807 return false; 2808 } 2809 2810 TV_DICT_ITER(d1, di1, { 2811 dictitem_T *const di2 = tv_dict_find(d2, di1->di_key, -1); 2812 if (di2 == NULL) { 2813 return false; 2814 } 2815 if (!tv_equal(&di1->di_tv, &di2->di_tv, ic)) { 2816 return false; 2817 } 2818 }); 2819 return true; 2820 } 2821 2822 /// Make a copy of dictionary 2823 /// 2824 /// @param[in] conv If non-NULL, then all internal strings will be converted. 2825 /// @param[in] orig Original dictionary to copy. 2826 /// @param[in] deep If false, then shallow copy will be done. 2827 /// @param[in] copyID See var_item_copy(). 2828 /// 2829 /// @return Copied dictionary. May be NULL in case original dictionary is NULL 2830 /// or some failure happens. The refcount of the new dictionary is set 2831 /// to 1. 2832 dict_T *tv_dict_copy(const vimconv_T *const conv, dict_T *const orig, const bool deep, 2833 const int copyID) 2834 { 2835 if (orig == NULL) { 2836 return NULL; 2837 } 2838 2839 dict_T *copy = tv_dict_alloc(); 2840 if (copyID != 0) { 2841 orig->dv_copyID = copyID; 2842 orig->dv_copydict = copy; 2843 } 2844 TV_DICT_ITER(orig, di, { 2845 if (got_int) { 2846 break; 2847 } 2848 dictitem_T *new_di; 2849 if (conv == NULL || conv->vc_type == CONV_NONE) { 2850 new_di = tv_dict_item_alloc(di->di_key); 2851 } else { 2852 size_t len = strlen(di->di_key); 2853 char *const key = string_convert(conv, di->di_key, &len); 2854 if (key == NULL) { 2855 new_di = tv_dict_item_alloc_len(di->di_key, len); 2856 } else { 2857 new_di = tv_dict_item_alloc_len(key, len); 2858 xfree(key); 2859 } 2860 } 2861 if (deep) { 2862 if (var_item_copy(conv, &di->di_tv, &new_di->di_tv, deep, 2863 copyID) == FAIL) { 2864 xfree(new_di); 2865 break; 2866 } 2867 } else { 2868 tv_copy(&di->di_tv, &new_di->di_tv); 2869 } 2870 if (tv_dict_add(copy, new_di) == FAIL) { 2871 tv_dict_item_free(new_di); 2872 break; 2873 } 2874 }); 2875 2876 copy->dv_refcount++; 2877 if (got_int) { 2878 tv_dict_unref(copy); 2879 copy = NULL; 2880 } 2881 2882 return copy; 2883 } 2884 2885 /// Set all existing keys in "dict" as read-only. 2886 /// 2887 /// This does not protect against adding new keys to the Dictionary. 2888 /// 2889 /// @param dict The dict whose keys should be frozen. 2890 void tv_dict_set_keys_readonly(dict_T *const dict) 2891 FUNC_ATTR_NONNULL_ALL 2892 { 2893 TV_DICT_ITER(dict, di, { 2894 di->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX; 2895 }); 2896 } 2897 2898 // Blobs: 2899 // Alloc/free: 2900 2901 /// Allocate an empty blob. 2902 /// 2903 /// Caller should take care of the reference count. 2904 /// 2905 /// @return [allocated] new blob. 2906 blob_T *tv_blob_alloc(void) 2907 FUNC_ATTR_NONNULL_RET 2908 { 2909 blob_T *const blob = xcalloc(1, sizeof(blob_T)); 2910 ga_init(&blob->bv_ga, 1, 100); 2911 return blob; 2912 } 2913 2914 /// Free a blob. Ignores the reference count. 2915 /// 2916 /// @param[in,out] b Blob to free. 2917 void tv_blob_free(blob_T *const b) 2918 FUNC_ATTR_NONNULL_ALL 2919 { 2920 ga_clear(&b->bv_ga); 2921 xfree(b); 2922 } 2923 2924 /// Unreference a blob. 2925 /// 2926 /// Decrements the reference count and frees blob when it becomes zero. 2927 /// 2928 /// @param[in,out] b Blob to operate on. 2929 void tv_blob_unref(blob_T *const b) 2930 { 2931 if (b != NULL && --b->bv_refcount <= 0) { 2932 tv_blob_free(b); 2933 } 2934 } 2935 2936 // Operations on the whole blob: 2937 2938 /// Check whether two blobs are equal. 2939 /// 2940 /// @param[in] b1 First blob. 2941 /// @param[in] b2 Second blob. 2942 /// 2943 /// @return true if blobs are equal, false otherwise. 2944 bool tv_blob_equal(const blob_T *const b1, const blob_T *const b2) 2945 FUNC_ATTR_WARN_UNUSED_RESULT 2946 { 2947 const int len1 = tv_blob_len(b1); 2948 const int len2 = tv_blob_len(b2); 2949 2950 // empty and NULL are considered the same 2951 if (len1 == 0 && len2 == 0) { 2952 return true; 2953 } 2954 if (b1 == b2) { 2955 return true; 2956 } 2957 if (len1 != len2) { 2958 return false; 2959 } 2960 2961 for (int i = 0; i < b1->bv_ga.ga_len; i++) { 2962 if (tv_blob_get(b1, i) != tv_blob_get(b2, i)) { 2963 return false; 2964 } 2965 } 2966 return true; 2967 } 2968 2969 /// Returns a slice of "blob" from index "n1" to "n2" in "rettv". The length of 2970 /// the blob is "len". Returns an empty blob if the indexes are out of range. 2971 static int tv_blob_slice(const blob_T *blob, int len, varnumber_T n1, varnumber_T n2, 2972 bool exclusive, typval_T *rettv) 2973 { 2974 // The resulting variable is a sub-blob. If the indexes 2975 // are out of range the result is empty. 2976 if (n1 < 0) { 2977 n1 = len + n1; 2978 if (n1 < 0) { 2979 n1 = 0; 2980 } 2981 } 2982 if (n2 < 0) { 2983 n2 = len + n2; 2984 } else if (n2 >= len) { 2985 n2 = len - (exclusive ? 0 : 1); 2986 } 2987 if (exclusive) { 2988 n2--; 2989 } 2990 if (n1 >= len || n2 < 0 || n1 > n2) { 2991 tv_clear(rettv); 2992 rettv->v_type = VAR_BLOB; 2993 rettv->vval.v_blob = NULL; 2994 } else { 2995 blob_T *const new_blob = tv_blob_alloc(); 2996 ga_grow(&new_blob->bv_ga, (int)(n2 - n1 + 1)); 2997 new_blob->bv_ga.ga_len = (int)(n2 - n1 + 1); 2998 for (int i = (int)n1; i <= (int)n2; i++) { 2999 tv_blob_set(new_blob, i - (int)n1, tv_blob_get(rettv->vval.v_blob, i)); 3000 } 3001 tv_clear(rettv); 3002 tv_blob_set_ret(rettv, new_blob); 3003 } 3004 3005 return OK; 3006 } 3007 3008 /// Return the byte value in "blob" at index "idx" in "rettv". If the index is 3009 /// too big or negative that is an error. The length of the blob is "len". 3010 static int tv_blob_index(const blob_T *blob, int len, varnumber_T idx, typval_T *rettv) 3011 { 3012 // The resulting variable is a byte value. 3013 // If the index is too big or negative that is an error. 3014 if (idx < 0) { 3015 idx = len + idx; 3016 } 3017 if (idx < len && idx >= 0) { 3018 const int v = (int)tv_blob_get(rettv->vval.v_blob, (int)idx); 3019 tv_clear(rettv); 3020 rettv->v_type = VAR_NUMBER; 3021 rettv->vval.v_number = v; 3022 } else { 3023 semsg(_(e_blobidx), idx); 3024 return FAIL; 3025 } 3026 3027 return OK; 3028 } 3029 3030 int tv_blob_slice_or_index(const blob_T *blob, bool is_range, varnumber_T n1, varnumber_T n2, 3031 bool exclusive, typval_T *rettv) 3032 { 3033 int len = tv_blob_len(rettv->vval.v_blob); 3034 3035 if (is_range) { 3036 return tv_blob_slice(blob, len, n1, n2, exclusive, rettv); 3037 } else { 3038 return tv_blob_index(blob, len, n1, rettv); 3039 } 3040 } 3041 3042 /// Check if "n1" is a valid index for a blob with length "bloblen". 3043 int tv_blob_check_index(int bloblen, varnumber_T n1, bool quiet) 3044 { 3045 if (n1 < 0 || n1 > bloblen) { 3046 if (!quiet) { 3047 semsg(_(e_blobidx), n1); 3048 } 3049 return FAIL; 3050 } 3051 return OK; 3052 } 3053 3054 /// Check if "n1"-"n2" is a valid range for a blob with length "bloblen". 3055 int tv_blob_check_range(int bloblen, varnumber_T n1, varnumber_T n2, bool quiet) 3056 { 3057 if (n2 < 0 || n2 >= bloblen || n2 < n1) { 3058 if (!quiet) { 3059 semsg(_(e_blobidx), n2); 3060 } 3061 return FAIL; 3062 } 3063 return OK; 3064 } 3065 3066 /// Set bytes "n1" to "n2" (inclusive) in "dest" to the value of "src". 3067 /// Caller must make sure "src" is a blob. 3068 /// Returns FAIL if the number of bytes does not match. 3069 int tv_blob_set_range(blob_T *dest, varnumber_T n1, varnumber_T n2, typval_T *src) 3070 { 3071 if (n2 - n1 + 1 != tv_blob_len(src->vval.v_blob)) { 3072 emsg(_("E972: Blob value does not have the right number of bytes")); 3073 return FAIL; 3074 } 3075 3076 for (int il = (int)n1, ir = 0; il <= (int)n2; il++) { 3077 tv_blob_set(dest, il, tv_blob_get(src->vval.v_blob, ir++)); 3078 } 3079 return OK; 3080 } 3081 3082 /// Store one byte "byte" in blob "blob" at "idx". 3083 /// Append one byte if needed. 3084 void tv_blob_set_append(blob_T *blob, int idx, uint8_t byte) 3085 { 3086 garray_T *gap = &blob->bv_ga; 3087 3088 // Allow for appending a byte. Setting a byte beyond 3089 // the end is an error otherwise. 3090 if (idx <= gap->ga_len) { 3091 if (idx == gap->ga_len) { 3092 ga_grow(gap, 1); 3093 gap->ga_len++; 3094 } 3095 tv_blob_set(blob, idx, byte); 3096 } 3097 } 3098 3099 /// "remove({blob})" function 3100 void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) 3101 { 3102 blob_T *const b = argvars[0].vval.v_blob; 3103 3104 if (b != NULL && value_check_lock(b->bv_lock, arg_errmsg, TV_TRANSLATE)) { 3105 return; 3106 } 3107 3108 bool error = false; 3109 int64_t idx = tv_get_number_chk(&argvars[1], &error); 3110 3111 if (!error) { 3112 const int len = tv_blob_len(b); 3113 3114 if (idx < 0) { 3115 // count from the end 3116 idx = len + idx; 3117 } 3118 if (idx < 0 || idx >= len) { 3119 semsg(_(e_blobidx), idx); 3120 return; 3121 } 3122 if (argvars[2].v_type == VAR_UNKNOWN) { 3123 // Remove one item, return its value. 3124 uint8_t *const p = (uint8_t *)b->bv_ga.ga_data; 3125 rettv->vval.v_number = (varnumber_T)(*(p + idx)); 3126 memmove(p + idx, p + idx + 1, (size_t)(len - idx - 1)); 3127 b->bv_ga.ga_len--; 3128 } else { 3129 // Remove range of items, return blob with values. 3130 int64_t end = tv_get_number_chk(&argvars[2], &error); 3131 if (error) { 3132 return; 3133 } 3134 if (end < 0) { 3135 // count from the end 3136 end = len + end; 3137 } 3138 if (end >= len || idx > end) { 3139 semsg(_(e_blobidx), end); 3140 return; 3141 } 3142 blob_T *const blob = tv_blob_alloc(); 3143 blob->bv_ga.ga_len = (int)(end - idx + 1); 3144 ga_grow(&blob->bv_ga, (int)(end - idx + 1)); 3145 3146 uint8_t *const p = (uint8_t *)b->bv_ga.ga_data; 3147 memmove(blob->bv_ga.ga_data, p + idx, (size_t)(end - idx + 1)); 3148 tv_blob_set_ret(rettv, blob); 3149 3150 if (len - end - 1 > 0) { 3151 memmove(p + idx, p + end + 1, (size_t)(len - end - 1)); 3152 } 3153 b->bv_ga.ga_len -= (int)(end - idx + 1); 3154 } 3155 } 3156 } 3157 3158 /// blob2list() function 3159 void f_blob2list(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 3160 { 3161 tv_list_alloc_ret(rettv, kListLenMayKnow); 3162 3163 if (tv_check_for_blob_arg(argvars, 0) == FAIL) { 3164 return; 3165 } 3166 3167 blob_T *const blob = argvars->vval.v_blob; 3168 list_T *const l = rettv->vval.v_list; 3169 for (int i = 0; i < tv_blob_len(blob); i++) { 3170 tv_list_append_number(l, tv_blob_get(blob, i)); 3171 } 3172 } 3173 3174 /// list2blob() function 3175 void f_list2blob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 3176 { 3177 blob_T *blob = tv_blob_alloc_ret(rettv); 3178 3179 if (tv_check_for_list_arg(argvars, 0) == FAIL) { 3180 return; 3181 } 3182 3183 list_T *const l = argvars->vval.v_list; 3184 if (l == NULL) { 3185 return; 3186 } 3187 3188 TV_LIST_ITER_CONST(l, li, { 3189 bool error = false; 3190 varnumber_T n = tv_get_number_chk(TV_LIST_ITEM_TV(li), &error); 3191 if (error || n < 0 || n > 255) { 3192 if (!error) { 3193 semsg(_(e_invalid_value_for_blob_nr), (int)n); 3194 } 3195 ga_clear(&blob->bv_ga); 3196 return; 3197 } 3198 ga_append(&blob->bv_ga, (uint8_t)n); 3199 }); 3200 } 3201 3202 // Generic typval operations: 3203 // Init/alloc/clear: 3204 // Alloc: 3205 3206 /// Allocate an empty list for a return value 3207 /// 3208 /// Also sets reference count. 3209 /// 3210 /// @param[out] ret_tv Structure where list is saved. 3211 /// @param[in] len Expected number of items to be populated before list 3212 /// becomes accessible from Vimscript. It is still valid to 3213 /// underpopulate a list, value only controls how many elements 3214 /// will be allocated in advance. @see ListLenSpecials. 3215 /// 3216 /// @return [allocated] pointer to the created list. 3217 list_T *tv_list_alloc_ret(typval_T *const ret_tv, const ptrdiff_t len) 3218 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET 3219 { 3220 list_T *const l = tv_list_alloc(len); 3221 tv_list_set_ret(ret_tv, l); 3222 ret_tv->v_lock = VAR_UNLOCKED; 3223 return l; 3224 } 3225 3226 dict_T *tv_dict_alloc_lock(VarLockStatus lock) 3227 FUNC_ATTR_NONNULL_RET 3228 { 3229 dict_T *const d = tv_dict_alloc(); 3230 d->dv_lock = lock; 3231 return d; 3232 } 3233 3234 /// Allocate an empty dictionary for a return value 3235 /// 3236 /// Also sets reference count. 3237 /// 3238 /// @param[out] ret_tv Structure where dictionary is saved. 3239 void tv_dict_alloc_ret(typval_T *const ret_tv) 3240 FUNC_ATTR_NONNULL_ALL 3241 { 3242 dict_T *const d = tv_dict_alloc_lock(VAR_UNLOCKED); 3243 tv_dict_set_ret(ret_tv, d); 3244 } 3245 3246 /// Turn a dictionary into a list 3247 /// 3248 /// @param[in] argvars Arguments to items(). The first argument is check for being 3249 /// a dictionary, will give an error if not. 3250 /// @param[out] rettv Location where result will be saved. 3251 /// @param[in] what What to save in rettv. 3252 static void tv_dict2list(typval_T *const argvars, typval_T *const rettv, const DictListType what) 3253 { 3254 if (tv_check_for_dict_arg(argvars, 0) == FAIL) { 3255 tv_list_alloc_ret(rettv, 0); 3256 return; 3257 } 3258 3259 dict_T *d = argvars[0].vval.v_dict; 3260 tv_list_alloc_ret(rettv, tv_dict_len(d)); 3261 if (d == NULL) { 3262 // NULL dict behaves like an empty dict 3263 return; 3264 } 3265 3266 TV_DICT_ITER(d, di, { 3267 typval_T tv_item = { .v_lock = VAR_UNLOCKED }; 3268 3269 switch (what) { 3270 case kDict2ListKeys: 3271 tv_item.v_type = VAR_STRING; 3272 tv_item.vval.v_string = xstrdup(di->di_key); 3273 break; 3274 case kDict2ListValues: 3275 tv_copy(&di->di_tv, &tv_item); 3276 break; 3277 case kDict2ListItems: { 3278 // items() 3279 list_T *const sub_l = tv_list_alloc(2); 3280 tv_item.v_type = VAR_LIST; 3281 tv_item.vval.v_list = sub_l; 3282 tv_list_ref(sub_l); 3283 tv_list_append_string(sub_l, di->di_key, -1); 3284 tv_list_append_tv(sub_l, &di->di_tv); 3285 break; 3286 } 3287 } 3288 3289 tv_list_append_owned_tv(rettv->vval.v_list, tv_item); 3290 }); 3291 } 3292 3293 /// "items()" function 3294 void f_items(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 3295 { 3296 if (argvars[0].v_type == VAR_STRING) { 3297 tv_string2items(argvars, rettv); 3298 } else if (argvars[0].v_type == VAR_LIST) { 3299 tv_list2items(argvars, rettv); 3300 } else if (argvars[0].v_type == VAR_BLOB) { 3301 tv_blob2items(argvars, rettv); 3302 } else if (argvars[0].v_type == VAR_DICT) { 3303 tv_dict2items(argvars, rettv); 3304 } else { 3305 semsg(_(e_list_dict_blob_or_string_required_for_argument_nr), 1); 3306 } 3307 } 3308 3309 /// "keys()" function 3310 void f_keys(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 3311 { 3312 tv_dict2list(argvars, rettv, kDict2ListKeys); 3313 } 3314 3315 /// "values(dict)" function 3316 void f_values(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 3317 { 3318 tv_dict2list(argvars, rettv, kDict2ListValues); 3319 } 3320 3321 /// "has_key()" function 3322 void f_has_key(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 3323 { 3324 if (tv_check_for_dict_arg(argvars, 0) == FAIL) { 3325 return; 3326 } 3327 3328 if (argvars[0].vval.v_dict == NULL) { 3329 return; 3330 } 3331 3332 rettv->vval.v_number = tv_dict_find(argvars[0].vval.v_dict, 3333 tv_get_string(&argvars[1]), 3334 -1) != NULL; 3335 } 3336 3337 /// "remove({dict})" function 3338 void tv_dict_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg) 3339 { 3340 dict_T *d; 3341 if (argvars[2].v_type != VAR_UNKNOWN) { 3342 semsg(_(e_toomanyarg), "remove()"); 3343 } else if ((d = argvars[0].vval.v_dict) != NULL 3344 && !value_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE)) { 3345 const char *key = tv_get_string_chk(&argvars[1]); 3346 if (key != NULL) { 3347 dictitem_T *di = tv_dict_find(d, key, -1); 3348 if (di == NULL) { 3349 semsg(_(e_dictkey), key); 3350 } else if (!var_check_fixed(di->di_flags, arg_errmsg, TV_TRANSLATE) 3351 && !var_check_ro(di->di_flags, arg_errmsg, TV_TRANSLATE)) { 3352 *rettv = di->di_tv; 3353 di->di_tv = TV_INITIAL_VALUE; 3354 tv_dict_item_remove(d, di); 3355 if (tv_dict_is_watched(d)) { 3356 tv_dict_watcher_notify(d, key, NULL, rettv); 3357 } 3358 } 3359 } 3360 } 3361 } 3362 3363 /// Allocate an empty blob for a return value. 3364 /// 3365 /// Also sets reference count. 3366 /// 3367 /// @param[out] ret_tv Structure where blob is saved. 3368 blob_T *tv_blob_alloc_ret(typval_T *const ret_tv) 3369 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET 3370 { 3371 blob_T *const b = tv_blob_alloc(); 3372 tv_blob_set_ret(ret_tv, b); 3373 return b; 3374 } 3375 3376 /// Copy a blob typval to a different typval. 3377 /// 3378 /// @param[in] from Blob object to copy from. 3379 /// @param[out] to Blob object to copy to. 3380 void tv_blob_copy(blob_T *const from, typval_T *const to) 3381 FUNC_ATTR_NONNULL_ARG(2) 3382 { 3383 to->v_type = VAR_BLOB; 3384 to->v_lock = VAR_UNLOCKED; 3385 if (from == NULL) { 3386 to->vval.v_blob = NULL; 3387 } else { 3388 tv_blob_alloc_ret(to); 3389 int len = from->bv_ga.ga_len; 3390 3391 if (len > 0) { 3392 to->vval.v_blob->bv_ga.ga_data = xmemdup(from->bv_ga.ga_data, (size_t)len); 3393 } 3394 to->vval.v_blob->bv_ga.ga_len = len; 3395 to->vval.v_blob->bv_ga.ga_maxlen = len; 3396 } 3397 } 3398 3399 // Clear: 3400 #define TYPVAL_ENCODE_ALLOW_SPECIALS false 3401 #define TYPVAL_ENCODE_CHECK_BEFORE 3402 3403 #define TYPVAL_ENCODE_CONV_NIL(tv) \ 3404 do { \ 3405 (tv)->vval.v_special = kSpecialVarNull; \ 3406 (tv)->v_lock = VAR_UNLOCKED; \ 3407 } while (0) 3408 3409 #define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ 3410 do { \ 3411 (tv)->vval.v_bool = kBoolVarFalse; \ 3412 (tv)->v_lock = VAR_UNLOCKED; \ 3413 } while (0) 3414 3415 #define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ 3416 do { \ 3417 (void)(num); \ 3418 (tv)->vval.v_number = 0; \ 3419 (tv)->v_lock = VAR_UNLOCKED; \ 3420 } while (0) 3421 3422 #define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num) 3423 3424 #define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ 3425 do { \ 3426 (tv)->vval.v_float = 0; \ 3427 (tv)->v_lock = VAR_UNLOCKED; \ 3428 } while (0) 3429 3430 #define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \ 3431 do { \ 3432 xfree(buf); \ 3433 (tv)->vval.v_string = NULL; \ 3434 (tv)->v_lock = VAR_UNLOCKED; \ 3435 } while (0) 3436 3437 #define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len) 3438 3439 #define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type) 3440 3441 #define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \ 3442 do { \ 3443 tv_blob_unref((tv)->vval.v_blob); \ 3444 (tv)->vval.v_blob = NULL; \ 3445 (tv)->v_lock = VAR_UNLOCKED; \ 3446 } while (0) 3447 3448 static inline int _nothing_conv_func_start(typval_T *const tv, char *const fun) 3449 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1) 3450 { 3451 tv->v_lock = VAR_UNLOCKED; 3452 if (tv->v_type == VAR_PARTIAL) { 3453 partial_T *const pt_ = tv->vval.v_partial; 3454 if (pt_ != NULL && pt_->pt_refcount > 1) { 3455 pt_->pt_refcount--; 3456 tv->vval.v_partial = NULL; 3457 return OK; 3458 } 3459 } else { 3460 func_unref(fun); 3461 if (fun != tv_empty_string) { 3462 xfree(fun); 3463 } 3464 tv->vval.v_string = NULL; 3465 } 3466 return NOTDONE; 3467 } 3468 #define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun, prefix) \ 3469 do { \ 3470 if (_nothing_conv_func_start(tv, fun) != NOTDONE) { \ 3471 return OK; \ 3472 } \ 3473 } while (0) 3474 3475 #define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len) 3476 #define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len) 3477 3478 static inline void _nothing_conv_func_end(typval_T *const tv, const int copyID) 3479 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL 3480 { 3481 if (tv->v_type == VAR_PARTIAL) { 3482 partial_T *const pt = tv->vval.v_partial; 3483 if (pt == NULL) { 3484 return; 3485 } 3486 // Dictionary should already be freed by the time. 3487 // If it was not freed then it is a part of the reference cycle. 3488 assert(pt->pt_dict == NULL || pt->pt_dict->dv_copyID == copyID); 3489 pt->pt_dict = NULL; 3490 // As well as all arguments. 3491 pt->pt_argc = 0; 3492 assert(pt->pt_refcount <= 1); 3493 partial_unref(pt); 3494 tv->vval.v_partial = NULL; 3495 assert(tv->v_lock == VAR_UNLOCKED); 3496 } 3497 } 3498 #define TYPVAL_ENCODE_CONV_FUNC_END(tv) _nothing_conv_func_end(tv, copyID) 3499 3500 #define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \ 3501 do { \ 3502 tv_list_unref((tv)->vval.v_list); \ 3503 (tv)->vval.v_list = NULL; \ 3504 (tv)->v_lock = VAR_UNLOCKED; \ 3505 } while (0) 3506 3507 static inline void _nothing_conv_empty_dict(typval_T *const tv, dict_T **const dictp) 3508 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(2) 3509 { 3510 tv_dict_unref(*dictp); 3511 *dictp = NULL; 3512 if (tv != NULL) { 3513 tv->v_lock = VAR_UNLOCKED; 3514 } 3515 } 3516 #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ 3517 do { \ 3518 assert((void *)&(dict) != (void *)&TYPVAL_ENCODE_NODICT_VAR); \ 3519 _nothing_conv_empty_dict(tv, ((dict_T **)&(dict))); \ 3520 } while (0) 3521 3522 static inline int _nothing_conv_real_list_after_start(typval_T *const tv, 3523 MPConvStackVal *const mpsv) 3524 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT 3525 { 3526 assert(tv != NULL); 3527 tv->v_lock = VAR_UNLOCKED; 3528 if (tv->vval.v_list->lv_refcount > 1) { 3529 tv->vval.v_list->lv_refcount--; 3530 tv->vval.v_list = NULL; 3531 mpsv->data.l.li = NULL; 3532 return OK; 3533 } 3534 return NOTDONE; 3535 } 3536 #define TYPVAL_ENCODE_CONV_LIST_START(tv, len) 3537 3538 #define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) \ 3539 do { \ 3540 if (_nothing_conv_real_list_after_start(tv, &(mpsv)) != NOTDONE) { \ 3541 goto typval_encode_stop_converting_one_item; \ 3542 } \ 3543 } while (0) 3544 3545 #define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) 3546 3547 static inline void _nothing_conv_list_end(typval_T *const tv) 3548 FUNC_ATTR_ALWAYS_INLINE 3549 { 3550 if (tv == NULL) { 3551 return; 3552 } 3553 assert(tv->v_type == VAR_LIST); 3554 list_T *const list = tv->vval.v_list; 3555 tv_list_unref(list); 3556 tv->vval.v_list = NULL; 3557 } 3558 #define TYPVAL_ENCODE_CONV_LIST_END(tv) _nothing_conv_list_end(tv) 3559 3560 static inline int _nothing_conv_real_dict_after_start(typval_T *const tv, dict_T **const dictp, 3561 const void *const nodictvar, 3562 MPConvStackVal *const mpsv) 3563 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT 3564 { 3565 if (tv != NULL) { 3566 tv->v_lock = VAR_UNLOCKED; 3567 } 3568 if ((const void *)dictp != nodictvar && (*dictp)->dv_refcount > 1) { 3569 (*dictp)->dv_refcount--; 3570 *dictp = NULL; 3571 mpsv->data.d.todo = 0; 3572 return OK; 3573 } 3574 return NOTDONE; 3575 } 3576 #define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) 3577 3578 #define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv) \ 3579 do { \ 3580 if (_nothing_conv_real_dict_after_start(tv, (dict_T **)&(dict), \ 3581 (void *)&TYPVAL_ENCODE_NODICT_VAR, &(mpsv)) \ 3582 != NOTDONE) { \ 3583 goto typval_encode_stop_converting_one_item; \ 3584 } \ 3585 } while (0) 3586 3587 #define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(tv, dict) 3588 #define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict) 3589 #define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) 3590 3591 static inline void _nothing_conv_dict_end(typval_T *const tv, dict_T **const dictp, 3592 const void *const nodictvar) 3593 FUNC_ATTR_ALWAYS_INLINE 3594 { 3595 if ((const void *)dictp != nodictvar) { 3596 tv_dict_unref(*dictp); 3597 *dictp = NULL; 3598 } 3599 } 3600 #define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \ 3601 _nothing_conv_dict_end(tv, (dict_T **)&(dict), \ 3602 (void *)&TYPVAL_ENCODE_NODICT_VAR) 3603 3604 #define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) 3605 3606 #define TYPVAL_ENCODE_SCOPE static 3607 #define TYPVAL_ENCODE_NAME nothing 3608 #define TYPVAL_ENCODE_FIRST_ARG_TYPE const void *const 3609 #define TYPVAL_ENCODE_FIRST_ARG_NAME ignored 3610 #include "nvim/eval/typval_encode.c.h" 3611 3612 #undef TYPVAL_ENCODE_SCOPE 3613 #undef TYPVAL_ENCODE_NAME 3614 #undef TYPVAL_ENCODE_FIRST_ARG_TYPE 3615 #undef TYPVAL_ENCODE_FIRST_ARG_NAME 3616 3617 #undef TYPVAL_ENCODE_ALLOW_SPECIALS 3618 #undef TYPVAL_ENCODE_CHECK_BEFORE 3619 #undef TYPVAL_ENCODE_CONV_NIL 3620 #undef TYPVAL_ENCODE_CONV_BOOL 3621 #undef TYPVAL_ENCODE_CONV_NUMBER 3622 #undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER 3623 #undef TYPVAL_ENCODE_CONV_FLOAT 3624 #undef TYPVAL_ENCODE_CONV_STRING 3625 #undef TYPVAL_ENCODE_CONV_STR_STRING 3626 #undef TYPVAL_ENCODE_CONV_EXT_STRING 3627 #undef TYPVAL_ENCODE_CONV_BLOB 3628 #undef TYPVAL_ENCODE_CONV_FUNC_START 3629 #undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS 3630 #undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF 3631 #undef TYPVAL_ENCODE_CONV_FUNC_END 3632 #undef TYPVAL_ENCODE_CONV_EMPTY_LIST 3633 #undef TYPVAL_ENCODE_CONV_EMPTY_DICT 3634 #undef TYPVAL_ENCODE_CONV_LIST_START 3635 #undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START 3636 #undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS 3637 #undef TYPVAL_ENCODE_CONV_LIST_END 3638 #undef TYPVAL_ENCODE_CONV_DICT_START 3639 #undef TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START 3640 #undef TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK 3641 #undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY 3642 #undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS 3643 #undef TYPVAL_ENCODE_CONV_DICT_END 3644 #undef TYPVAL_ENCODE_CONV_RECURSE 3645 3646 /// Free memory for a variable value and set the value to NULL or 0 3647 /// 3648 /// @param[in,out] tv Value to free. 3649 void tv_clear(typval_T *const tv) 3650 { 3651 if (tv == NULL || tv->v_type == VAR_UNKNOWN) { 3652 return; 3653 } 3654 3655 // WARNING: do not translate the string here, gettext is slow and function 3656 // is used *very* often. At the current state encode_vim_to_nothing() does 3657 // not error out and does not use the argument anywhere. 3658 // 3659 // If situation changes and this argument will be used, translate it in the 3660 // place where it is used. 3661 const int evn_ret = encode_vim_to_nothing(NULL, tv, "tv_clear() argument"); 3662 (void)evn_ret; 3663 assert(evn_ret == OK); 3664 } 3665 3666 // Free: 3667 3668 /// Free allocated Vimscript object and value stored inside 3669 /// 3670 /// @param tv Object to free. 3671 void tv_free(typval_T *tv) 3672 { 3673 if (tv == NULL) { 3674 return; 3675 } 3676 3677 switch (tv->v_type) { 3678 case VAR_PARTIAL: 3679 partial_unref(tv->vval.v_partial); 3680 break; 3681 case VAR_FUNC: 3682 func_unref(tv->vval.v_string); 3683 FALLTHROUGH; 3684 case VAR_STRING: 3685 xfree(tv->vval.v_string); 3686 break; 3687 case VAR_BLOB: 3688 tv_blob_unref(tv->vval.v_blob); 3689 break; 3690 case VAR_LIST: 3691 tv_list_unref(tv->vval.v_list); 3692 break; 3693 case VAR_DICT: 3694 tv_dict_unref(tv->vval.v_dict); 3695 break; 3696 case VAR_BOOL: 3697 case VAR_SPECIAL: 3698 case VAR_NUMBER: 3699 case VAR_FLOAT: 3700 case VAR_UNKNOWN: 3701 break; 3702 } 3703 xfree(tv); 3704 } 3705 3706 // Copy: 3707 3708 /// Copy typval from one location to another 3709 /// 3710 /// When needed allocates string or increases reference count. Does not make 3711 /// a copy of a container, but copies its reference! 3712 /// 3713 /// It is OK for `from` and `to` to point to the same location; this is used to 3714 /// make a copy later. 3715 /// 3716 /// @param[in] from Location to copy from. 3717 /// @param[out] to Location to copy to. 3718 void tv_copy(const typval_T *const from, typval_T *const to) 3719 { 3720 to->v_type = from->v_type; 3721 to->v_lock = VAR_UNLOCKED; 3722 memmove(&to->vval, &from->vval, sizeof(to->vval)); 3723 switch (from->v_type) { 3724 case VAR_NUMBER: 3725 case VAR_FLOAT: 3726 case VAR_BOOL: 3727 case VAR_SPECIAL: 3728 break; 3729 case VAR_STRING: 3730 case VAR_FUNC: 3731 if (from->vval.v_string != NULL) { 3732 to->vval.v_string = xstrdup(from->vval.v_string); 3733 if (from->v_type == VAR_FUNC) { 3734 func_ref(to->vval.v_string); 3735 } 3736 } 3737 break; 3738 case VAR_PARTIAL: 3739 if (to->vval.v_partial != NULL) { 3740 to->vval.v_partial->pt_refcount++; 3741 } 3742 break; 3743 case VAR_BLOB: 3744 if (from->vval.v_blob != NULL) { 3745 to->vval.v_blob->bv_refcount++; 3746 } 3747 break; 3748 case VAR_LIST: 3749 tv_list_ref(to->vval.v_list); 3750 break; 3751 case VAR_DICT: 3752 if (from->vval.v_dict != NULL) { 3753 to->vval.v_dict->dv_refcount++; 3754 } 3755 break; 3756 case VAR_UNKNOWN: 3757 semsg(_(e_intern2), "tv_copy(UNKNOWN)"); 3758 break; 3759 } 3760 } 3761 3762 // Locks: 3763 3764 /// Lock or unlock an item 3765 /// 3766 /// @param[out] tv Item to (un)lock. 3767 /// @param[in] deep Levels to (un)lock, -1 to (un)lock everything. 3768 /// @param[in] lock True if it is needed to lock an item, false to unlock. 3769 /// @param[in] check_refcount If true, do not lock a list or dict with a 3770 /// reference count larger than 1. 3771 void tv_item_lock(typval_T *const tv, const int deep, const bool lock, const bool check_refcount) 3772 FUNC_ATTR_NONNULL_ALL 3773 { 3774 // TODO(ZyX-I): Make this not recursive 3775 static int recurse = 0; 3776 3777 if (recurse >= DICT_MAXNEST) { 3778 emsg(_(e_variable_nested_too_deep_for_unlock)); 3779 return; 3780 } 3781 if (deep == 0) { 3782 return; 3783 } 3784 recurse++; 3785 3786 // lock/unlock the item itself 3787 #define CHANGE_LOCK(lock, var) \ 3788 do { \ 3789 (var) = ((VarLockStatus[]) { \ 3790 [VAR_UNLOCKED] = ((lock) ? VAR_LOCKED : VAR_UNLOCKED), \ 3791 [VAR_LOCKED] = ((lock) ? VAR_LOCKED : VAR_UNLOCKED), \ 3792 [VAR_FIXED] = VAR_FIXED, \ 3793 })[var]; \ 3794 } while (0) 3795 CHANGE_LOCK(lock, tv->v_lock); 3796 3797 switch (tv->v_type) { 3798 case VAR_BLOB: { 3799 blob_T *const b = tv->vval.v_blob; 3800 if (b != NULL && !(check_refcount && b->bv_refcount > 1)) { 3801 CHANGE_LOCK(lock, b->bv_lock); 3802 } 3803 break; 3804 } 3805 case VAR_LIST: { 3806 list_T *const l = tv->vval.v_list; 3807 if (l != NULL && !(check_refcount && l->lv_refcount > 1)) { 3808 CHANGE_LOCK(lock, l->lv_lock); 3809 if (deep < 0 || deep > 1) { 3810 // Recursive: lock/unlock the items the List contains. 3811 TV_LIST_ITER(l, li, { 3812 tv_item_lock(TV_LIST_ITEM_TV(li), deep - 1, lock, check_refcount); 3813 }); 3814 } 3815 } 3816 break; 3817 } 3818 case VAR_DICT: { 3819 dict_T *const d = tv->vval.v_dict; 3820 if (d != NULL && !(check_refcount && d->dv_refcount > 1)) { 3821 CHANGE_LOCK(lock, d->dv_lock); 3822 if (deep < 0 || deep > 1) { 3823 // recursive: lock/unlock the items the List contains 3824 TV_DICT_ITER(d, di, { 3825 tv_item_lock(&di->di_tv, deep - 1, lock, check_refcount); 3826 }); 3827 } 3828 } 3829 break; 3830 } 3831 case VAR_NUMBER: 3832 case VAR_FLOAT: 3833 case VAR_STRING: 3834 case VAR_FUNC: 3835 case VAR_PARTIAL: 3836 case VAR_BOOL: 3837 case VAR_SPECIAL: 3838 break; 3839 case VAR_UNKNOWN: 3840 abort(); 3841 } 3842 #undef CHANGE_LOCK 3843 recurse--; 3844 } 3845 3846 /// Check whether Vimscript value is locked itself or refers to a locked container 3847 /// 3848 /// @warning Fixed container is not the same as locked. 3849 /// 3850 /// @param[in] tv Value to check. 3851 /// 3852 /// @return True if value is locked, false otherwise. 3853 bool tv_islocked(const typval_T *const tv) 3854 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL 3855 { 3856 return ((tv->v_lock == VAR_LOCKED) 3857 || (tv->v_type == VAR_LIST 3858 && (tv_list_locked(tv->vval.v_list) == VAR_LOCKED)) 3859 || (tv->v_type == VAR_DICT 3860 && tv->vval.v_dict != NULL 3861 && (tv->vval.v_dict->dv_lock == VAR_LOCKED))); 3862 } 3863 3864 /// Return true if typval is locked 3865 /// 3866 /// Also gives an error message when typval is locked. 3867 /// 3868 /// @param[in] tv Typval. 3869 /// @param[in] name Variable name, used in the error message. 3870 /// @param[in] name_len Variable name length. Use #TV_TRANSLATE to translate 3871 /// variable name and compute the length. Use #TV_CSTRING 3872 /// to compute the length with strlen() without 3873 /// translating. 3874 /// 3875 /// Both #TV_… values are used for optimization purposes: 3876 /// variable name with its length is needed only in case 3877 /// of error, when no error occurs computing them is 3878 /// a waste of CPU resources. This especially applies to 3879 /// gettext. 3880 /// 3881 /// @return true if variable is locked, false otherwise. 3882 bool tv_check_lock(const typval_T *tv, const char *name, size_t name_len) 3883 FUNC_ATTR_WARN_UNUSED_RESULT 3884 { 3885 VarLockStatus lock = VAR_UNLOCKED; 3886 3887 switch (tv->v_type) { 3888 case VAR_BLOB: 3889 if (tv->vval.v_blob != NULL) { 3890 lock = tv->vval.v_blob->bv_lock; 3891 } 3892 break; 3893 case VAR_LIST: 3894 if (tv->vval.v_list != NULL) { 3895 lock = tv->vval.v_list->lv_lock; 3896 } 3897 break; 3898 case VAR_DICT: 3899 if (tv->vval.v_dict != NULL) { 3900 lock = tv->vval.v_dict->dv_lock; 3901 } 3902 break; 3903 default: 3904 break; 3905 } 3906 return value_check_lock(tv->v_lock, name, name_len) 3907 || (lock != VAR_UNLOCKED && value_check_lock(lock, name, name_len)); 3908 } 3909 3910 /// @return true if variable "name" has a locked (immutable) value 3911 bool value_check_lock(VarLockStatus lock, const char *name, size_t name_len) 3912 { 3913 const char *error_message = NULL; 3914 switch (lock) { 3915 case VAR_UNLOCKED: 3916 return false; 3917 case VAR_LOCKED: 3918 error_message = name == NULL ? N_(e_value_is_locked) 3919 : N_(e_value_is_locked_str); 3920 break; 3921 case VAR_FIXED: 3922 error_message = name == NULL ? N_(e_cannot_change_value) 3923 : N_(e_cannot_change_value_of_str); 3924 break; 3925 } 3926 assert(error_message != NULL); 3927 3928 if (name == NULL) { 3929 emsg(_(error_message)); 3930 } else { 3931 if (name_len == TV_TRANSLATE) { 3932 name = _(name); 3933 name_len = strlen(name); 3934 } else if (name_len == TV_CSTRING) { 3935 name_len = strlen(name); 3936 } 3937 semsg(_(error_message), (int)name_len, name); 3938 } 3939 3940 return true; 3941 } 3942 3943 // Comparison: 3944 3945 static int tv_equal_recurse_limit; 3946 3947 /// Compare two Vimscript values 3948 /// 3949 /// Like "==", but strings and numbers are different, as well as floats and 3950 /// numbers. 3951 /// 3952 /// @warning Too nested structures may be considered equal even if they are not. 3953 /// 3954 /// @param[in] tv1 First value to compare. 3955 /// @param[in] tv2 Second value to compare. 3956 /// @param[in] ic True if case is to be ignored. 3957 /// 3958 /// @return true if values are equal. 3959 bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic) 3960 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL 3961 { 3962 // TODO(ZyX-I): Make this not recursive 3963 static int recursive_cnt = 0; // Catch recursive loops. 3964 3965 if (!(tv_is_func(*tv1) && tv_is_func(*tv2)) && tv1->v_type != tv2->v_type) { 3966 return false; 3967 } 3968 3969 // Catch lists and dicts that have an endless loop by limiting 3970 // recursiveness to a limit. We guess they are equal then. 3971 // A fixed limit has the problem of still taking an awful long time. 3972 // Reduce the limit every time running into it. That should work fine for 3973 // deeply linked structures that are not recursively linked and catch 3974 // recursiveness quickly. 3975 if (recursive_cnt == 0) { 3976 tv_equal_recurse_limit = 1000; 3977 } 3978 if (recursive_cnt >= tv_equal_recurse_limit) { 3979 tv_equal_recurse_limit--; 3980 return true; 3981 } 3982 3983 switch (tv1->v_type) { 3984 case VAR_LIST: { 3985 recursive_cnt++; 3986 const bool r = tv_list_equal(tv1->vval.v_list, tv2->vval.v_list, ic); 3987 recursive_cnt--; 3988 return r; 3989 } 3990 case VAR_DICT: { 3991 recursive_cnt++; 3992 const bool r = tv_dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic); 3993 recursive_cnt--; 3994 return r; 3995 } 3996 case VAR_PARTIAL: 3997 case VAR_FUNC: { 3998 if ((tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial == NULL) 3999 || (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial == NULL)) { 4000 return false; 4001 } 4002 recursive_cnt++; 4003 const bool r = func_equal(tv1, tv2, ic); 4004 recursive_cnt--; 4005 return r; 4006 } 4007 case VAR_BLOB: 4008 return tv_blob_equal(tv1->vval.v_blob, tv2->vval.v_blob); 4009 case VAR_NUMBER: 4010 return tv1->vval.v_number == tv2->vval.v_number; 4011 case VAR_FLOAT: 4012 return tv1->vval.v_float == tv2->vval.v_float; 4013 case VAR_STRING: { 4014 char buf1[NUMBUFLEN]; 4015 char buf2[NUMBUFLEN]; 4016 const char *s1 = tv_get_string_buf(tv1, buf1); 4017 const char *s2 = tv_get_string_buf(tv2, buf2); 4018 return mb_strcmp_ic(ic, s1, s2) == 0; 4019 } 4020 case VAR_BOOL: 4021 return tv1->vval.v_bool == tv2->vval.v_bool; 4022 case VAR_SPECIAL: 4023 return tv1->vval.v_special == tv2->vval.v_special; 4024 case VAR_UNKNOWN: 4025 // VAR_UNKNOWN can be the result of an invalid expression, let’s say it 4026 // does not equal anything, not even self. 4027 return false; 4028 } 4029 4030 abort(); 4031 return false; 4032 } 4033 4034 // Type checks: 4035 4036 /// Check that given value is a number or string 4037 /// 4038 /// Error messages are compatible with tv_get_number() previously used for the 4039 /// same purpose in buf*() functions. Special values are not accepted (previous 4040 /// behaviour: silently fail to find buffer). 4041 /// 4042 /// @param[in] tv Value to check. 4043 /// 4044 /// @return true if everything is OK, false otherwise. 4045 bool tv_check_str_or_nr(const typval_T *const tv) 4046 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL 4047 { 4048 switch (tv->v_type) { 4049 case VAR_NUMBER: 4050 case VAR_STRING: 4051 return true; 4052 case VAR_FLOAT: 4053 emsg(_("E805: Expected a Number or a String, Float found")); 4054 return false; 4055 case VAR_PARTIAL: 4056 case VAR_FUNC: 4057 emsg(_("E703: Expected a Number or a String, Funcref found")); 4058 return false; 4059 case VAR_LIST: 4060 emsg(_("E745: Expected a Number or a String, List found")); 4061 return false; 4062 case VAR_DICT: 4063 emsg(_("E728: Expected a Number or a String, Dictionary found")); 4064 return false; 4065 case VAR_BLOB: 4066 emsg(_("E974: Expected a Number or a String, Blob found")); 4067 return false; 4068 case VAR_BOOL: 4069 emsg(_("E5299: Expected a Number or a String, Boolean found")); 4070 return false; 4071 case VAR_SPECIAL: 4072 emsg(_("E5300: Expected a Number or a String")); 4073 return false; 4074 case VAR_UNKNOWN: 4075 semsg(_(e_intern2), "tv_check_str_or_nr(UNKNOWN)"); 4076 return false; 4077 } 4078 abort(); 4079 return false; 4080 } 4081 4082 #define FUNC_ERROR "E703: Using a Funcref as a Number" 4083 4084 static const char *const num_errors[] = { 4085 [VAR_PARTIAL] = N_(FUNC_ERROR), 4086 [VAR_FUNC] = N_(FUNC_ERROR), 4087 [VAR_LIST] = N_("E745: Using a List as a Number"), 4088 [VAR_DICT] = N_("E728: Using a Dictionary as a Number"), 4089 [VAR_FLOAT] = N_("E805: Using a Float as a Number"), 4090 [VAR_BLOB] = N_("E974: Using a Blob as a Number"), 4091 [VAR_UNKNOWN] = N_("E685: using an invalid value as a Number"), 4092 }; 4093 4094 #undef FUNC_ERROR 4095 4096 /// Check that given value is a number or can be converted to it 4097 /// 4098 /// Error messages are compatible with tv_get_number_chk() previously used for 4099 /// the same purpose. 4100 /// 4101 /// @param[in] tv Value to check. 4102 /// 4103 /// @return true if everything is OK, false otherwise. 4104 bool tv_check_num(const typval_T *const tv) 4105 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 4106 { 4107 switch (tv->v_type) { 4108 case VAR_NUMBER: 4109 case VAR_BOOL: 4110 case VAR_SPECIAL: 4111 case VAR_STRING: 4112 return true; 4113 case VAR_FUNC: 4114 case VAR_PARTIAL: 4115 case VAR_LIST: 4116 case VAR_DICT: 4117 case VAR_FLOAT: 4118 case VAR_BLOB: 4119 case VAR_UNKNOWN: 4120 emsg(_(num_errors[tv->v_type])); 4121 return false; 4122 } 4123 abort(); 4124 return false; 4125 } 4126 4127 #define FUNC_ERROR "E729: Using a Funcref as a String" 4128 4129 static const char *const str_errors[] = { 4130 [VAR_PARTIAL] = N_(FUNC_ERROR), 4131 [VAR_FUNC] = N_(FUNC_ERROR), 4132 [VAR_LIST] = N_("E730: Using a List as a String"), 4133 [VAR_DICT] = N_("E731: Using a Dictionary as a String"), 4134 [VAR_BLOB] = N_("E976: Using a Blob as a String"), 4135 [VAR_UNKNOWN] = e_using_invalid_value_as_string, 4136 }; 4137 4138 #undef FUNC_ERROR 4139 4140 /// Check that given value is a Vimscript String or can be "cast" to it. 4141 /// 4142 /// Error messages are compatible with tv_get_string_chk() previously used for 4143 /// the same purpose. 4144 /// 4145 /// @param[in] tv Value to check. 4146 /// 4147 /// @return true if everything is OK, false otherwise. 4148 bool tv_check_str(const typval_T *const tv) 4149 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 4150 { 4151 switch (tv->v_type) { 4152 case VAR_NUMBER: 4153 case VAR_BOOL: 4154 case VAR_SPECIAL: 4155 case VAR_STRING: 4156 case VAR_FLOAT: 4157 return true; 4158 case VAR_PARTIAL: 4159 case VAR_FUNC: 4160 case VAR_LIST: 4161 case VAR_DICT: 4162 case VAR_BLOB: 4163 case VAR_UNKNOWN: 4164 emsg(_(str_errors[tv->v_type])); 4165 return false; 4166 } 4167 abort(); 4168 return false; 4169 } 4170 4171 // Get: 4172 4173 /// Get the number value of a Vimscript object 4174 /// 4175 /// @note Use tv_get_number_chk() if you need to determine whether there was an 4176 /// error. 4177 /// 4178 /// @param[in] tv Object to get value from. 4179 /// 4180 /// @return Number value: vim_str2nr() output for VAR_STRING objects, value 4181 /// for VAR_NUMBER objects, -1 for other types. 4182 varnumber_T tv_get_number(const typval_T *const tv) 4183 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 4184 { 4185 bool error = false; 4186 return tv_get_number_chk(tv, &error); 4187 } 4188 4189 /// Get the number value of a Vimscript object 4190 /// 4191 /// @param[in] tv Object to get value from. 4192 /// @param[out] ret_error If type error occurred then `true` will be written 4193 /// to this location. Otherwise it is not touched. 4194 /// 4195 /// @note Needs to be initialized to `false` to be 4196 /// useful. 4197 /// 4198 /// @return Number value: vim_str2nr() output for VAR_STRING objects, value 4199 /// for VAR_NUMBER objects, -1 (ret_error == NULL) or 0 (otherwise) for 4200 /// other types. 4201 varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error) 4202 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) 4203 { 4204 switch (tv->v_type) { 4205 case VAR_FUNC: 4206 case VAR_PARTIAL: 4207 case VAR_LIST: 4208 case VAR_DICT: 4209 case VAR_BLOB: 4210 case VAR_FLOAT: 4211 emsg(_(num_errors[tv->v_type])); 4212 break; 4213 case VAR_NUMBER: 4214 return tv->vval.v_number; 4215 case VAR_STRING: { 4216 varnumber_T n = 0; 4217 if (tv->vval.v_string != NULL) { 4218 vim_str2nr(tv->vval.v_string, NULL, NULL, STR2NR_ALL, &n, NULL, 0, false, NULL); 4219 } 4220 return n; 4221 } 4222 case VAR_BOOL: 4223 return tv->vval.v_bool == kBoolVarTrue ? 1 : 0; 4224 case VAR_SPECIAL: 4225 return 0; 4226 case VAR_UNKNOWN: 4227 semsg(_(e_intern2), "tv_get_number(UNKNOWN)"); 4228 break; 4229 } 4230 if (ret_error != NULL) { 4231 *ret_error = true; 4232 } 4233 return (ret_error == NULL ? -1 : 0); 4234 } 4235 4236 varnumber_T tv_get_bool(const typval_T *const tv) 4237 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 4238 { 4239 return tv_get_number_chk(tv, NULL); 4240 } 4241 4242 varnumber_T tv_get_bool_chk(const typval_T *const tv, bool *const ret_error) 4243 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) 4244 { 4245 return tv_get_number_chk(tv, ret_error); 4246 } 4247 4248 /// Get the line number from Vimscript object 4249 /// 4250 /// @param[in] tv Object to get value from. Is expected to be a number or 4251 /// a special string like ".", "$", … (works with current buffer 4252 /// only). 4253 /// 4254 /// @return Line number or -1 or 0. 4255 linenr_T tv_get_lnum(const typval_T *const tv) 4256 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 4257 { 4258 const int did_emsg_before = did_emsg; 4259 linenr_T lnum = (linenr_T)tv_get_number_chk(tv, NULL); 4260 if (lnum <= 0 && did_emsg_before == did_emsg && tv->v_type != VAR_NUMBER) { 4261 int fnum; 4262 // No valid number, try using same function as line() does. 4263 pos_T *const fp = var2fpos(tv, true, &fnum, false, curwin); 4264 if (fp != NULL) { 4265 lnum = fp->lnum; 4266 } 4267 } 4268 return lnum; 4269 } 4270 4271 /// Get the line number from Vimscript object 4272 /// 4273 /// @note Unlike tv_get_lnum(), this one supports only "$" special string. 4274 /// 4275 /// @param[in] tv Object to get value from. Is expected to be a number or 4276 /// a special string "$". 4277 /// @param[in] buf Buffer to take last line number from in case tv is "$". May 4278 /// be NULL, in this case "$" results in zero return. 4279 /// 4280 /// @return Line number or 0 in case of error. 4281 linenr_T tv_get_lnum_buf(const typval_T *const tv, const buf_T *const buf) 4282 FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT 4283 { 4284 if (tv->v_type == VAR_STRING 4285 && tv->vval.v_string != NULL 4286 && tv->vval.v_string[0] == '$' 4287 && tv->vval.v_string[1] == NUL 4288 && buf != NULL) { 4289 return buf->b_ml.ml_line_count; 4290 } 4291 return (linenr_T)tv_get_number_chk(tv, NULL); 4292 } 4293 4294 /// Get the floating-point value of a Vimscript object 4295 /// 4296 /// Raises an error if object is not number or floating-point. 4297 /// 4298 /// @param[in] tv Object to get value of. 4299 /// 4300 /// @return Floating-point value of the variable or zero. 4301 float_T tv_get_float(const typval_T *const tv) 4302 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 4303 { 4304 switch (tv->v_type) { 4305 case VAR_NUMBER: 4306 return (float_T)(tv->vval.v_number); 4307 case VAR_FLOAT: 4308 return tv->vval.v_float; 4309 case VAR_PARTIAL: 4310 case VAR_FUNC: 4311 emsg(_("E891: Using a Funcref as a Float")); 4312 break; 4313 case VAR_STRING: 4314 emsg(_("E892: Using a String as a Float")); 4315 break; 4316 case VAR_LIST: 4317 emsg(_("E893: Using a List as a Float")); 4318 break; 4319 case VAR_DICT: 4320 emsg(_("E894: Using a Dictionary as a Float")); 4321 break; 4322 case VAR_BOOL: 4323 emsg(_("E362: Using a boolean value as a Float")); 4324 break; 4325 case VAR_SPECIAL: 4326 emsg(_("E907: Using a special value as a Float")); 4327 break; 4328 case VAR_BLOB: 4329 emsg(_("E975: Using a Blob as a Float")); 4330 break; 4331 case VAR_UNKNOWN: 4332 semsg(_(e_intern2), "tv_get_float(UNKNOWN)"); 4333 break; 4334 } 4335 return 0; 4336 } 4337 4338 /// Give an error and return FAIL unless "args[idx]" is a string. 4339 int tv_check_for_string_arg(const typval_T *const args, const int idx) 4340 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4341 { 4342 if (args[idx].v_type != VAR_STRING) { 4343 semsg(_(e_string_required_for_argument_nr), idx + 1); 4344 return FAIL; 4345 } 4346 return OK; 4347 } 4348 4349 /// Give an error and return FAIL unless "args[idx]" is a non-empty string. 4350 int tv_check_for_nonempty_string_arg(const typval_T *const args, const int idx) 4351 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4352 { 4353 if (tv_check_for_string_arg(args, idx) == FAIL) { 4354 return FAIL; 4355 } 4356 if (args[idx].vval.v_string == NULL || *args[idx].vval.v_string == NUL) { 4357 semsg(_(e_non_empty_string_required_for_argument_nr), idx + 1); 4358 return FAIL; 4359 } 4360 return OK; 4361 } 4362 4363 /// Check for an optional string argument at "idx" 4364 int tv_check_for_opt_string_arg(const typval_T *const args, const int idx) 4365 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4366 { 4367 return (args[idx].v_type == VAR_UNKNOWN 4368 || tv_check_for_string_arg(args, idx) != FAIL) ? OK : FAIL; 4369 } 4370 4371 /// Give an error and return FAIL unless "args[idx]" is a number. 4372 int tv_check_for_number_arg(const typval_T *const args, const int idx) 4373 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4374 { 4375 if (args[idx].v_type != VAR_NUMBER) { 4376 semsg(_(e_number_required_for_argument_nr), idx + 1); 4377 return FAIL; 4378 } 4379 return OK; 4380 } 4381 4382 /// Check for an optional number argument at "idx" 4383 int tv_check_for_opt_number_arg(const typval_T *const args, const int idx) 4384 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4385 { 4386 return (args[idx].v_type == VAR_UNKNOWN 4387 || tv_check_for_number_arg(args, idx) != FAIL) ? OK : FAIL; 4388 } 4389 4390 /// Give an error and return FAIL unless "args[idx]" is a float or a number. 4391 int tv_check_for_float_or_nr_arg(const typval_T *const args, const int idx) 4392 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4393 { 4394 if (args[idx].v_type != VAR_FLOAT && args[idx].v_type != VAR_NUMBER) { 4395 semsg(_(e_float_or_number_required_for_argument_nr), idx + 1); 4396 return FAIL; 4397 } 4398 return OK; 4399 } 4400 4401 /// Give an error and return FAIL unless "args[idx]" is a bool. 4402 int tv_check_for_bool_arg(const typval_T *const args, const int idx) 4403 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4404 { 4405 if (args[idx].v_type != VAR_BOOL 4406 && !(args[idx].v_type == VAR_NUMBER 4407 && (args[idx].vval.v_number == 0 4408 || args[idx].vval.v_number == 1))) { 4409 semsg(_(e_bool_required_for_argument_nr), idx + 1); 4410 return FAIL; 4411 } 4412 return OK; 4413 } 4414 4415 /// Check for an optional bool argument at "idx". 4416 /// Return FAIL if the type is wrong. 4417 int tv_check_for_opt_bool_arg(const typval_T *const args, const int idx) 4418 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4419 { 4420 if (args[idx].v_type == VAR_UNKNOWN) { 4421 return OK; 4422 } 4423 return tv_check_for_bool_arg(args, idx); 4424 } 4425 4426 /// Give an error and return FAIL unless "args[idx]" is a blob. 4427 int tv_check_for_blob_arg(const typval_T *const args, const int idx) 4428 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4429 { 4430 if (args[idx].v_type != VAR_BLOB) { 4431 semsg(_(e_blob_required_for_argument_nr), idx + 1); 4432 return FAIL; 4433 } 4434 return OK; 4435 } 4436 4437 /// Give an error and return FAIL unless "args[idx]" is a list. 4438 int tv_check_for_list_arg(const typval_T *const args, const int idx) 4439 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4440 { 4441 if (args[idx].v_type != VAR_LIST) { 4442 semsg(_(e_list_required_for_argument_nr), idx + 1); 4443 return FAIL; 4444 } 4445 return OK; 4446 } 4447 4448 /// Give an error and return FAIL unless "args[idx]" is a dict. 4449 int tv_check_for_dict_arg(const typval_T *const args, const int idx) 4450 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4451 { 4452 if (args[idx].v_type != VAR_DICT) { 4453 semsg(_(e_dict_required_for_argument_nr), idx + 1); 4454 return FAIL; 4455 } 4456 return OK; 4457 } 4458 4459 /// Give an error and return FAIL unless "args[idx]" is a non-NULL dict. 4460 int tv_check_for_nonnull_dict_arg(const typval_T *const args, const int idx) 4461 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4462 { 4463 if (tv_check_for_dict_arg(args, idx) == FAIL) { 4464 return FAIL; 4465 } 4466 if (args[idx].vval.v_dict == NULL) { 4467 semsg(_(e_non_null_dict_required_for_argument_nr), idx + 1); 4468 return FAIL; 4469 } 4470 return OK; 4471 } 4472 4473 /// Check for an optional dict argument at "idx" 4474 int tv_check_for_opt_dict_arg(const typval_T *const args, const int idx) 4475 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4476 { 4477 return (args[idx].v_type == VAR_UNKNOWN 4478 || tv_check_for_dict_arg(args, idx) != FAIL) ? OK : FAIL; 4479 } 4480 4481 /// Give an error and return FAIL unless "args[idx]" is a string or 4482 /// a number. 4483 int tv_check_for_string_or_number_arg(const typval_T *const args, const int idx) 4484 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4485 { 4486 if (args[idx].v_type != VAR_STRING && args[idx].v_type != VAR_NUMBER) { 4487 semsg(_(e_string_or_number_required_for_argument_nr), idx + 1); 4488 return FAIL; 4489 } 4490 return OK; 4491 } 4492 4493 /// Give an error and return FAIL unless "args[idx]" is a buffer number. 4494 /// Buffer number can be a number or a string. 4495 int tv_check_for_buffer_arg(const typval_T *const args, const int idx) 4496 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4497 { 4498 return tv_check_for_string_or_number_arg(args, idx); 4499 } 4500 4501 /// Give an error and return FAIL unless "args[idx]" is a line number. 4502 /// Line number can be a number or a string. 4503 int tv_check_for_lnum_arg(const typval_T *const args, const int idx) 4504 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4505 { 4506 return tv_check_for_string_or_number_arg(args, idx); 4507 } 4508 4509 /// Give an error and return FAIL unless "args[idx]" is a string or a list. 4510 int tv_check_for_string_or_list_arg(const typval_T *const args, const int idx) 4511 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4512 { 4513 if (args[idx].v_type != VAR_STRING && args[idx].v_type != VAR_LIST) { 4514 semsg(_(e_string_or_list_required_for_argument_nr), idx + 1); 4515 return FAIL; 4516 } 4517 return OK; 4518 } 4519 4520 /// Give an error and return FAIL unless "args[idx]" is a string, a list or a blob. 4521 int tv_check_for_string_or_list_or_blob_arg(const typval_T *const args, const int idx) 4522 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4523 { 4524 if (args[idx].v_type != VAR_STRING 4525 && args[idx].v_type != VAR_LIST 4526 && args[idx].v_type != VAR_BLOB) { 4527 semsg(_(e_string_list_or_blob_required_for_argument_nr), idx + 1); 4528 return FAIL; 4529 } 4530 return OK; 4531 } 4532 4533 /// Check for an optional string or list argument at "idx" 4534 int tv_check_for_opt_string_or_list_arg(const typval_T *const args, const int idx) 4535 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4536 { 4537 return (args[idx].v_type == VAR_UNKNOWN 4538 || tv_check_for_string_or_list_arg(args, idx) != FAIL) ? OK : FAIL; 4539 } 4540 4541 /// Give an error and return FAIL unless "args[idx]" is a string 4542 /// or a function reference. 4543 int tv_check_for_string_or_func_arg(const typval_T *const args, const int idx) 4544 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4545 { 4546 if (args[idx].v_type != VAR_PARTIAL 4547 && args[idx].v_type != VAR_FUNC 4548 && args[idx].v_type != VAR_STRING) { 4549 semsg(_(e_string_or_function_required_for_argument_nr), idx + 1); 4550 return FAIL; 4551 } 4552 return OK; 4553 } 4554 4555 /// Give an error and return FAIL unless "args[idx]" is a list or a blob. 4556 int tv_check_for_list_or_blob_arg(const typval_T *const args, const int idx) 4557 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4558 { 4559 if (args[idx].v_type != VAR_LIST && args[idx].v_type != VAR_BLOB) { 4560 semsg(_(e_list_or_blob_required_for_argument_nr), idx + 1); 4561 return FAIL; 4562 } 4563 return OK; 4564 } 4565 4566 /// Get the string value of a "stringish" Vimscript object. 4567 /// 4568 /// @param[in] tv Object to get value of. 4569 /// @param buf Buffer used to hold numbers and special variables converted to 4570 /// string. When function encounters one of these stringified value 4571 /// will be written to buf and buf will be returned. 4572 /// 4573 /// Buffer must have NUMBUFLEN size. 4574 /// 4575 /// @return Object value if it is VAR_STRING object, number converted to 4576 /// a string for VAR_NUMBER, v: variable name for VAR_SPECIAL or NULL. 4577 const char *tv_get_string_buf_chk(const typval_T *const tv, char *const buf) 4578 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 4579 { 4580 switch (tv->v_type) { 4581 case VAR_NUMBER: 4582 snprintf(buf, NUMBUFLEN, "%" PRIdVARNUMBER, tv->vval.v_number); 4583 return buf; 4584 case VAR_FLOAT: 4585 vim_snprintf(buf, NUMBUFLEN, "%g", tv->vval.v_float); 4586 return buf; 4587 case VAR_STRING: 4588 if (tv->vval.v_string != NULL) { 4589 return tv->vval.v_string; 4590 } 4591 return ""; 4592 case VAR_BOOL: 4593 STRCPY(buf, encode_bool_var_names[tv->vval.v_bool]); 4594 return buf; 4595 case VAR_SPECIAL: 4596 STRCPY(buf, encode_special_var_names[tv->vval.v_special]); 4597 return buf; 4598 case VAR_PARTIAL: 4599 case VAR_FUNC: 4600 case VAR_LIST: 4601 case VAR_DICT: 4602 case VAR_BLOB: 4603 case VAR_UNKNOWN: 4604 emsg(_(str_errors[tv->v_type])); 4605 return NULL; 4606 } 4607 abort(); 4608 return NULL; 4609 } 4610 4611 /// Get the string value of a "stringish" Vimscript object. 4612 /// 4613 /// @warning For number and special values it uses a single, static buffer. It 4614 /// may be used only once, next call to tv_get_string may reuse it. Use 4615 /// tv_get_string_buf() if you need to use tv_get_string() output after 4616 /// calling it again. 4617 /// 4618 /// @param[in] tv Object to get value of. 4619 /// 4620 /// @return Object value if it is VAR_STRING object, number converted to 4621 /// a string for VAR_NUMBER, v: variable name for VAR_SPECIAL or NULL. 4622 const char *tv_get_string_chk(const typval_T *const tv) 4623 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 4624 { 4625 static char mybuf[NUMBUFLEN]; 4626 4627 return tv_get_string_buf_chk(tv, mybuf); 4628 } 4629 4630 /// Get the string value of a "stringish" Vimscript object. 4631 /// 4632 /// @warning For number and special values it uses a single, static buffer. It 4633 /// may be used only once, next call to tv_get_string may reuse it. Use 4634 /// tv_get_string_buf() if you need to use tv_get_string() output after 4635 /// calling it again. 4636 /// 4637 /// @note tv_get_string_chk() and tv_get_string_buf_chk() are similar, but 4638 /// return NULL on error. 4639 /// 4640 /// @param[in] tv Object to get value of. 4641 /// 4642 /// @return Object value if it is VAR_STRING object, number converted to 4643 /// a string for VAR_NUMBER, v: variable name for VAR_SPECIAL or empty 4644 /// string. 4645 const char *tv_get_string(const typval_T *const tv) 4646 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT 4647 { 4648 static char mybuf[NUMBUFLEN]; 4649 return tv_get_string_buf((typval_T *)tv, mybuf); 4650 } 4651 4652 /// Get the string value of a "stringish" Vimscript object. 4653 /// 4654 /// @note tv_get_string_chk() and tv_get_string_buf_chk() are similar, but 4655 /// return NULL on error. 4656 /// 4657 /// @param[in] tv Object to get value of. 4658 /// @param buf Buffer used to hold numbers and special variables converted to 4659 /// string. When function encounters one of these stringified value 4660 /// will be written to buf and buf will be returned. 4661 /// 4662 /// Buffer must have NUMBUFLEN size. 4663 /// 4664 /// @return Object value if it is VAR_STRING object, number converted to 4665 /// a string for VAR_NUMBER, v: variable name for VAR_SPECIAL or empty 4666 /// string. 4667 const char *tv_get_string_buf(const typval_T *const tv, char *const buf) 4668 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT 4669 { 4670 const char *const res = tv_get_string_buf_chk(tv, buf); 4671 4672 return res != NULL ? res : ""; 4673 } 4674 4675 /// Return true when "tv" is not falsy: non-zero, non-empty string, non-empty 4676 /// list, etc. Mostly like what JavaScript does, except that empty list and 4677 /// empty dictionary are false. 4678 bool tv2bool(const typval_T *const tv) 4679 { 4680 switch (tv->v_type) { 4681 case VAR_NUMBER: 4682 return tv->vval.v_number != 0; 4683 case VAR_FLOAT: 4684 return tv->vval.v_float != 0.0; 4685 case VAR_PARTIAL: 4686 return tv->vval.v_partial != NULL; 4687 case VAR_FUNC: 4688 case VAR_STRING: 4689 return tv->vval.v_string != NULL && *tv->vval.v_string != NUL; 4690 case VAR_LIST: 4691 return tv->vval.v_list != NULL && tv->vval.v_list->lv_len > 0; 4692 case VAR_DICT: 4693 return tv->vval.v_dict != NULL && tv->vval.v_dict->dv_hashtab.ht_used > 0; 4694 case VAR_BOOL: 4695 return tv->vval.v_bool == kBoolVarTrue; 4696 case VAR_SPECIAL: 4697 return tv->vval.v_special != kSpecialVarNull; 4698 case VAR_BLOB: 4699 return tv->vval.v_blob != NULL && tv->vval.v_blob->bv_ga.ga_len > 0; 4700 case VAR_UNKNOWN: 4701 break; 4702 } 4703 return false; 4704 }