1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * list.c: List support and container (List, Dict, Blob) functions. 12 */ 13 14 #include "vim.h" 15 16 #if defined(FEAT_EVAL) || defined(PROTO) 17 18 static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob"); 19 20 // List heads for garbage collection. 21 static list_T *first_list = NULL; // list of all lists 22 23 #define FOR_ALL_WATCHERS(l, lw) \ 24 for ((lw) = (l)->lv_watch; (lw) != NULL; (lw) = (lw)->lw_next) 25 26 static void list_free_item(list_T *l, listitem_T *item); 27 28 /* 29 * Add a watcher to a list. 30 */ 31 void 32 list_add_watch(list_T *l, listwatch_T *lw) 33 { 34 lw->lw_next = l->lv_watch; 35 l->lv_watch = lw; 36 } 37 38 /* 39 * Remove a watcher from a list. 40 * No warning when it isn't found... 41 */ 42 void 43 list_rem_watch(list_T *l, listwatch_T *lwrem) 44 { 45 listwatch_T *lw, **lwp; 46 47 lwp = &l->lv_watch; 48 FOR_ALL_WATCHERS(l, lw) 49 { 50 if (lw == lwrem) 51 { 52 *lwp = lw->lw_next; 53 break; 54 } 55 lwp = &lw->lw_next; 56 } 57 } 58 59 /* 60 * Just before removing an item from a list: advance watchers to the next 61 * item. 62 */ 63 static void 64 list_fix_watch(list_T *l, listitem_T *item) 65 { 66 listwatch_T *lw; 67 68 FOR_ALL_WATCHERS(l, lw) 69 if (lw->lw_item == item) 70 lw->lw_item = item->li_next; 71 } 72 73 static void 74 list_init(list_T *l) 75 { 76 // Prepend the list to the list of lists for garbage collection. 77 if (first_list != NULL) 78 first_list->lv_used_prev = l; 79 l->lv_used_prev = NULL; 80 l->lv_used_next = first_list; 81 first_list = l; 82 } 83 84 /* 85 * Allocate an empty header for a list. 86 * Caller should take care of the reference count. 87 */ 88 list_T * 89 list_alloc(void) 90 { 91 list_T *l; 92 93 l = ALLOC_CLEAR_ONE(list_T); 94 if (l != NULL) 95 list_init(l); 96 return l; 97 } 98 99 /* 100 * list_alloc() with an ID for alloc_fail(). 101 */ 102 list_T * 103 list_alloc_id(alloc_id_T id UNUSED) 104 { 105 #ifdef FEAT_EVAL 106 if (alloc_fail_id == id && alloc_does_fail(sizeof(list_T))) 107 return NULL; 108 #endif 109 return (list_alloc()); 110 } 111 112 /* 113 * Allocate space for a list, plus "count" items. 114 * Next list_set_item() must be called for each item. 115 */ 116 list_T * 117 list_alloc_with_items(int count) 118 { 119 list_T *l; 120 121 l = (list_T *)alloc_clear(sizeof(list_T) + count * sizeof(listitem_T)); 122 if (l != NULL) 123 { 124 list_init(l); 125 126 if (count > 0) 127 { 128 listitem_T *li = (listitem_T *)(l + 1); 129 int i; 130 131 l->lv_len = count; 132 l->lv_with_items = count; 133 l->lv_first = li; 134 l->lv_u.mat.lv_last = li + count - 1; 135 for (i = 0; i < count; ++i) 136 { 137 if (i == 0) 138 li->li_prev = NULL; 139 else 140 li->li_prev = li - 1; 141 if (i == count - 1) 142 li->li_next = NULL; 143 else 144 li->li_next = li + 1; 145 ++li; 146 } 147 } 148 } 149 return l; 150 } 151 152 /* 153 * Set item "idx" for a list previously allocated with list_alloc_with_items(). 154 * The contents of "tv" is moved into the list item. 155 * Each item must be set exactly once. 156 */ 157 void 158 list_set_item(list_T *l, int idx, typval_T *tv) 159 { 160 listitem_T *li = (listitem_T *)(l + 1) + idx; 161 162 li->li_tv = *tv; 163 } 164 165 /* 166 * Allocate an empty list for a return value, with reference count set. 167 * Returns OK or FAIL. 168 */ 169 int 170 rettv_list_alloc(typval_T *rettv) 171 { 172 list_T *l = list_alloc(); 173 174 if (l == NULL) 175 return FAIL; 176 177 rettv->v_lock = 0; 178 rettv_list_set(rettv, l); 179 return OK; 180 } 181 182 /* 183 * Same as rettv_list_alloc() but uses an allocation id for testing. 184 */ 185 int 186 rettv_list_alloc_id(typval_T *rettv, alloc_id_T id UNUSED) 187 { 188 #ifdef FEAT_EVAL 189 if (alloc_fail_id == id && alloc_does_fail(sizeof(list_T))) 190 return FAIL; 191 #endif 192 return rettv_list_alloc(rettv); 193 } 194 195 196 /* 197 * Set a list as the return value. Increments the reference count. 198 */ 199 void 200 rettv_list_set(typval_T *rettv, list_T *l) 201 { 202 rettv->v_type = VAR_LIST; 203 rettv->vval.v_list = l; 204 if (l != NULL) 205 ++l->lv_refcount; 206 } 207 208 /* 209 * Unreference a list: decrement the reference count and free it when it 210 * becomes zero. 211 */ 212 void 213 list_unref(list_T *l) 214 { 215 if (l != NULL && --l->lv_refcount <= 0) 216 list_free(l); 217 } 218 219 /* 220 * Free a list, including all non-container items it points to. 221 * Ignores the reference count. 222 */ 223 static void 224 list_free_contents(list_T *l) 225 { 226 listitem_T *item; 227 228 if (l->lv_first != &range_list_item) 229 for (item = l->lv_first; item != NULL; item = l->lv_first) 230 { 231 // Remove the item before deleting it. 232 l->lv_first = item->li_next; 233 clear_tv(&item->li_tv); 234 list_free_item(l, item); 235 } 236 } 237 238 /* 239 * Go through the list of lists and free items without the copyID. 240 * But don't free a list that has a watcher (used in a for loop), these 241 * are not referenced anywhere. 242 */ 243 int 244 list_free_nonref(int copyID) 245 { 246 list_T *ll; 247 int did_free = FALSE; 248 249 for (ll = first_list; ll != NULL; ll = ll->lv_used_next) 250 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK) 251 && ll->lv_watch == NULL) 252 { 253 // Free the List and ordinary items it contains, but don't recurse 254 // into Lists and Dictionaries, they will be in the list of dicts 255 // or list of lists. 256 list_free_contents(ll); 257 did_free = TRUE; 258 } 259 return did_free; 260 } 261 262 static void 263 list_free_list(list_T *l) 264 { 265 // Remove the list from the list of lists for garbage collection. 266 if (l->lv_used_prev == NULL) 267 first_list = l->lv_used_next; 268 else 269 l->lv_used_prev->lv_used_next = l->lv_used_next; 270 if (l->lv_used_next != NULL) 271 l->lv_used_next->lv_used_prev = l->lv_used_prev; 272 273 free_type(l->lv_type); 274 vim_free(l); 275 } 276 277 void 278 list_free_items(int copyID) 279 { 280 list_T *ll, *ll_next; 281 282 for (ll = first_list; ll != NULL; ll = ll_next) 283 { 284 ll_next = ll->lv_used_next; 285 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK) 286 && ll->lv_watch == NULL) 287 { 288 // Free the List and ordinary items it contains, but don't recurse 289 // into Lists and Dictionaries, they will be in the list of dicts 290 // or list of lists. 291 list_free_list(ll); 292 } 293 } 294 } 295 296 void 297 list_free(list_T *l) 298 { 299 if (!in_free_unref_items) 300 { 301 list_free_contents(l); 302 list_free_list(l); 303 } 304 } 305 306 /* 307 * Allocate a list item. 308 * It is not initialized, don't forget to set v_lock. 309 */ 310 listitem_T * 311 listitem_alloc(void) 312 { 313 return ALLOC_ONE(listitem_T); 314 } 315 316 /* 317 * Free a list item, unless it was allocated together with the list itself. 318 * Does not clear the value. Does not notify watchers. 319 */ 320 static void 321 list_free_item(list_T *l, listitem_T *item) 322 { 323 if (l->lv_with_items == 0 || item < (listitem_T *)l 324 || item >= (listitem_T *)(l + 1) + l->lv_with_items) 325 vim_free(item); 326 } 327 328 /* 329 * Free a list item, unless it was allocated together with the list itself. 330 * Also clears the value. Does not notify watchers. 331 */ 332 void 333 listitem_free(list_T *l, listitem_T *item) 334 { 335 clear_tv(&item->li_tv); 336 list_free_item(l, item); 337 } 338 339 /* 340 * Remove a list item from a List and free it. Also clears the value. 341 */ 342 void 343 listitem_remove(list_T *l, listitem_T *item) 344 { 345 vimlist_remove(l, item, item); 346 listitem_free(l, item); 347 } 348 349 /* 350 * Get the number of items in a list. 351 */ 352 long 353 list_len(list_T *l) 354 { 355 if (l == NULL) 356 return 0L; 357 return l->lv_len; 358 } 359 360 /* 361 * Return TRUE when two lists have exactly the same values. 362 */ 363 int 364 list_equal( 365 list_T *l1, 366 list_T *l2, 367 int ic, // ignore case for strings 368 int recursive) // TRUE when used recursively 369 { 370 listitem_T *item1, *item2; 371 372 if (l1 == l2) 373 return TRUE; 374 if (list_len(l1) != list_len(l2)) 375 return FALSE; 376 if (list_len(l1) == 0) 377 // empty and NULL list are considered equal 378 return TRUE; 379 if (l1 == NULL || l2 == NULL) 380 return FALSE; 381 382 CHECK_LIST_MATERIALIZE(l1); 383 CHECK_LIST_MATERIALIZE(l2); 384 385 for (item1 = l1->lv_first, item2 = l2->lv_first; 386 item1 != NULL && item2 != NULL; 387 item1 = item1->li_next, item2 = item2->li_next) 388 if (!tv_equal(&item1->li_tv, &item2->li_tv, ic, recursive)) 389 return FALSE; 390 return item1 == NULL && item2 == NULL; 391 } 392 393 /* 394 * Locate item with index "n" in list "l" and return it. 395 * A negative index is counted from the end; -1 is the last item. 396 * Returns NULL when "n" is out of range. 397 */ 398 listitem_T * 399 list_find(list_T *l, long n) 400 { 401 listitem_T *item; 402 long idx; 403 404 if (l == NULL) 405 return NULL; 406 407 // Negative index is relative to the end. 408 if (n < 0) 409 n = l->lv_len + n; 410 411 // Check for index out of range. 412 if (n < 0 || n >= l->lv_len) 413 return NULL; 414 415 CHECK_LIST_MATERIALIZE(l); 416 417 // When there is a cached index may start search from there. 418 if (l->lv_u.mat.lv_idx_item != NULL) 419 { 420 if (n < l->lv_u.mat.lv_idx / 2) 421 { 422 // closest to the start of the list 423 item = l->lv_first; 424 idx = 0; 425 } 426 else if (n > (l->lv_u.mat.lv_idx + l->lv_len) / 2) 427 { 428 // closest to the end of the list 429 item = l->lv_u.mat.lv_last; 430 idx = l->lv_len - 1; 431 } 432 else 433 { 434 // closest to the cached index 435 item = l->lv_u.mat.lv_idx_item; 436 idx = l->lv_u.mat.lv_idx; 437 } 438 } 439 else 440 { 441 if (n < l->lv_len / 2) 442 { 443 // closest to the start of the list 444 item = l->lv_first; 445 idx = 0; 446 } 447 else 448 { 449 // closest to the end of the list 450 item = l->lv_u.mat.lv_last; 451 idx = l->lv_len - 1; 452 } 453 } 454 455 while (n > idx) 456 { 457 // search forward 458 item = item->li_next; 459 ++idx; 460 } 461 while (n < idx) 462 { 463 // search backward 464 item = item->li_prev; 465 --idx; 466 } 467 468 // cache the used index 469 l->lv_u.mat.lv_idx = idx; 470 l->lv_u.mat.lv_idx_item = item; 471 472 return item; 473 } 474 475 /* 476 * Get list item "l[idx]" as a number. 477 */ 478 long 479 list_find_nr( 480 list_T *l, 481 long idx, 482 int *errorp) // set to TRUE when something wrong 483 { 484 listitem_T *li; 485 486 if (l != NULL && l->lv_first == &range_list_item) 487 { 488 long n = idx; 489 490 // not materialized range() list: compute the value. 491 // Negative index is relative to the end. 492 if (n < 0) 493 n = l->lv_len + n; 494 495 // Check for index out of range. 496 if (n < 0 || n >= l->lv_len) 497 { 498 if (errorp != NULL) 499 *errorp = TRUE; 500 return -1L; 501 } 502 503 return l->lv_u.nonmat.lv_start + n * l->lv_u.nonmat.lv_stride; 504 } 505 506 li = list_find(l, idx); 507 if (li == NULL) 508 { 509 if (errorp != NULL) 510 *errorp = TRUE; 511 return -1L; 512 } 513 return (long)tv_get_number_chk(&li->li_tv, errorp); 514 } 515 516 /* 517 * Get list item "l[idx - 1]" as a string. Returns NULL for failure. 518 */ 519 char_u * 520 list_find_str(list_T *l, long idx) 521 { 522 listitem_T *li; 523 524 li = list_find(l, idx - 1); 525 if (li == NULL) 526 { 527 semsg(_(e_listidx), idx); 528 return NULL; 529 } 530 return tv_get_string(&li->li_tv); 531 } 532 533 /* 534 * Like list_find() but when a negative index is used that is not found use 535 * zero and set "idx" to zero. Used for first index of a range. 536 */ 537 listitem_T * 538 list_find_index(list_T *l, long *idx) 539 { 540 listitem_T *li = list_find(l, *idx); 541 542 if (li == NULL) 543 { 544 if (*idx < 0) 545 { 546 *idx = 0; 547 li = list_find(l, *idx); 548 } 549 } 550 return li; 551 } 552 553 /* 554 * Locate "item" list "l" and return its index. 555 * Returns -1 when "item" is not in the list. 556 */ 557 long 558 list_idx_of_item(list_T *l, listitem_T *item) 559 { 560 long idx = 0; 561 listitem_T *li; 562 563 if (l == NULL) 564 return -1; 565 CHECK_LIST_MATERIALIZE(l); 566 idx = 0; 567 for (li = l->lv_first; li != NULL && li != item; li = li->li_next) 568 ++idx; 569 if (li == NULL) 570 return -1; 571 return idx; 572 } 573 574 /* 575 * Append item "item" to the end of list "l". 576 */ 577 void 578 list_append(list_T *l, listitem_T *item) 579 { 580 CHECK_LIST_MATERIALIZE(l); 581 if (l->lv_u.mat.lv_last == NULL) 582 { 583 // empty list 584 l->lv_first = item; 585 l->lv_u.mat.lv_last = item; 586 item->li_prev = NULL; 587 } 588 else 589 { 590 l->lv_u.mat.lv_last->li_next = item; 591 item->li_prev = l->lv_u.mat.lv_last; 592 l->lv_u.mat.lv_last = item; 593 } 594 ++l->lv_len; 595 item->li_next = NULL; 596 } 597 598 /* 599 * Append typval_T "tv" to the end of list "l". "tv" is copied. 600 * Return FAIL when out of memory. 601 */ 602 int 603 list_append_tv(list_T *l, typval_T *tv) 604 { 605 listitem_T *li = listitem_alloc(); 606 607 if (li == NULL) 608 return FAIL; 609 copy_tv(tv, &li->li_tv); 610 list_append(l, li); 611 return OK; 612 } 613 614 /* 615 * As list_append_tv() but move the value instead of copying it. 616 * Return FAIL when out of memory. 617 */ 618 int 619 list_append_tv_move(list_T *l, typval_T *tv) 620 { 621 listitem_T *li = listitem_alloc(); 622 623 if (li == NULL) 624 return FAIL; 625 li->li_tv = *tv; 626 list_append(l, li); 627 return OK; 628 } 629 630 /* 631 * Add a dictionary to a list. Used by getqflist(). 632 * Return FAIL when out of memory. 633 */ 634 int 635 list_append_dict(list_T *list, dict_T *dict) 636 { 637 listitem_T *li = listitem_alloc(); 638 639 if (li == NULL) 640 return FAIL; 641 li->li_tv.v_type = VAR_DICT; 642 li->li_tv.v_lock = 0; 643 li->li_tv.vval.v_dict = dict; 644 list_append(list, li); 645 ++dict->dv_refcount; 646 return OK; 647 } 648 649 /* 650 * Append list2 to list1. 651 * Return FAIL when out of memory. 652 */ 653 int 654 list_append_list(list_T *list1, list_T *list2) 655 { 656 listitem_T *li = listitem_alloc(); 657 658 if (li == NULL) 659 return FAIL; 660 li->li_tv.v_type = VAR_LIST; 661 li->li_tv.v_lock = 0; 662 li->li_tv.vval.v_list = list2; 663 list_append(list1, li); 664 ++list2->lv_refcount; 665 return OK; 666 } 667 668 /* 669 * Make a copy of "str" and append it as an item to list "l". 670 * When "len" >= 0 use "str[len]". 671 * Returns FAIL when out of memory. 672 */ 673 int 674 list_append_string(list_T *l, char_u *str, int len) 675 { 676 listitem_T *li = listitem_alloc(); 677 678 if (li == NULL) 679 return FAIL; 680 list_append(l, li); 681 li->li_tv.v_type = VAR_STRING; 682 li->li_tv.v_lock = 0; 683 if (str == NULL) 684 li->li_tv.vval.v_string = NULL; 685 else if ((li->li_tv.vval.v_string = (len >= 0 ? vim_strnsave(str, len) 686 : vim_strsave(str))) == NULL) 687 return FAIL; 688 return OK; 689 } 690 691 /* 692 * Append "n" to list "l". 693 * Returns FAIL when out of memory. 694 */ 695 int 696 list_append_number(list_T *l, varnumber_T n) 697 { 698 listitem_T *li; 699 700 li = listitem_alloc(); 701 if (li == NULL) 702 return FAIL; 703 li->li_tv.v_type = VAR_NUMBER; 704 li->li_tv.v_lock = 0; 705 li->li_tv.vval.v_number = n; 706 list_append(l, li); 707 return OK; 708 } 709 710 /* 711 * Insert typval_T "tv" in list "l" before "item". 712 * If "item" is NULL append at the end. 713 * Return FAIL when out of memory or the type is wrong. 714 */ 715 int 716 list_insert_tv(list_T *l, typval_T *tv, listitem_T *item) 717 { 718 listitem_T *ni; 719 720 if (l->lv_type != NULL && l->lv_type->tt_member != NULL 721 && check_typval_arg_type(l->lv_type->tt_member, tv, 0) == FAIL) 722 return FAIL; 723 ni = listitem_alloc(); 724 if (ni == NULL) 725 return FAIL; 726 copy_tv(tv, &ni->li_tv); 727 list_insert(l, ni, item); 728 return OK; 729 } 730 731 void 732 list_insert(list_T *l, listitem_T *ni, listitem_T *item) 733 { 734 CHECK_LIST_MATERIALIZE(l); 735 if (item == NULL) 736 // Append new item at end of list. 737 list_append(l, ni); 738 else 739 { 740 // Insert new item before existing item. 741 ni->li_prev = item->li_prev; 742 ni->li_next = item; 743 if (item->li_prev == NULL) 744 { 745 l->lv_first = ni; 746 ++l->lv_u.mat.lv_idx; 747 } 748 else 749 { 750 item->li_prev->li_next = ni; 751 l->lv_u.mat.lv_idx_item = NULL; 752 } 753 item->li_prev = ni; 754 ++l->lv_len; 755 } 756 } 757 758 /* 759 * Flatten "list" to depth "maxdepth". 760 * It does nothing if "maxdepth" is 0. 761 * Returns FAIL when out of memory. 762 */ 763 static void 764 list_flatten(list_T *list, long maxdepth) 765 { 766 listitem_T *item; 767 listitem_T *tofree; 768 int n; 769 770 if (maxdepth == 0) 771 return; 772 CHECK_LIST_MATERIALIZE(list); 773 774 n = 0; 775 item = list->lv_first; 776 while (item != NULL) 777 { 778 fast_breakcheck(); 779 if (got_int) 780 return; 781 782 if (item->li_tv.v_type == VAR_LIST) 783 { 784 listitem_T *next = item->li_next; 785 786 vimlist_remove(list, item, item); 787 if (list_extend(list, item->li_tv.vval.v_list, next) == FAIL) 788 return; 789 clear_tv(&item->li_tv); 790 tofree = item; 791 792 if (item->li_prev == NULL) 793 item = list->lv_first; 794 else 795 item = item->li_prev->li_next; 796 list_free_item(list, tofree); 797 798 if (++n >= maxdepth) 799 { 800 n = 0; 801 item = next; 802 } 803 } 804 else 805 { 806 n = 0; 807 item = item->li_next; 808 } 809 } 810 } 811 812 /* 813 * "flatten()" and "flattennew()" functions 814 */ 815 static void 816 flatten_common(typval_T *argvars, typval_T *rettv, int make_copy) 817 { 818 list_T *l; 819 long maxdepth; 820 int error = FALSE; 821 822 if (argvars[0].v_type != VAR_LIST) 823 { 824 semsg(_(e_listarg), "flatten()"); 825 return; 826 } 827 828 if (argvars[1].v_type == VAR_UNKNOWN) 829 maxdepth = 999999; 830 else 831 { 832 maxdepth = (long)tv_get_number_chk(&argvars[1], &error); 833 if (error) 834 return; 835 if (maxdepth < 0) 836 { 837 emsg(_("E900: maxdepth must be non-negative number")); 838 return; 839 } 840 } 841 842 l = argvars[0].vval.v_list; 843 rettv->v_type = VAR_LIST; 844 rettv->vval.v_list = l; 845 if (l == NULL) 846 return; 847 848 if (make_copy) 849 { 850 l = list_copy(l, TRUE, get_copyID()); 851 rettv->vval.v_list = l; 852 if (l == NULL) 853 return; 854 } 855 else 856 { 857 if (value_check_lock(l->lv_lock, 858 (char_u *)N_("flatten() argument"), TRUE)) 859 return; 860 ++l->lv_refcount; 861 } 862 863 list_flatten(l, maxdepth); 864 } 865 866 /* 867 * "flatten(list[, {maxdepth}])" function 868 */ 869 void 870 f_flatten(typval_T *argvars, typval_T *rettv) 871 { 872 if (in_vim9script()) 873 emsg(_(e_cannot_use_flatten_in_vim9_script)); 874 else 875 flatten_common(argvars, rettv, FALSE); 876 } 877 878 /* 879 * "flattennew(list[, {maxdepth}])" function 880 */ 881 void 882 f_flattennew(typval_T *argvars, typval_T *rettv) 883 { 884 flatten_common(argvars, rettv, TRUE); 885 } 886 887 /* 888 * Extend "l1" with "l2". "l1" must not be NULL. 889 * If "bef" is NULL append at the end, otherwise insert before this item. 890 * Returns FAIL when out of memory. 891 */ 892 int 893 list_extend(list_T *l1, list_T *l2, listitem_T *bef) 894 { 895 listitem_T *item; 896 int todo; 897 listitem_T *bef_prev; 898 899 // NULL list is equivalent to an empty list: nothing to do. 900 if (l2 == NULL || l2->lv_len == 0) 901 return OK; 902 903 todo = l2->lv_len; 904 CHECK_LIST_MATERIALIZE(l1); 905 CHECK_LIST_MATERIALIZE(l2); 906 907 // When exending a list with itself, at some point we run into the item 908 // that was before "bef" and need to skip over the already inserted items 909 // to "bef". 910 bef_prev = bef == NULL ? NULL : bef->li_prev; 911 912 // We also quit the loop when we have inserted the original item count of 913 // the list, avoid a hang when we extend a list with itself. 914 for (item = l2->lv_first; item != NULL && --todo >= 0; 915 item = item == bef_prev ? bef : item->li_next) 916 if (list_insert_tv(l1, &item->li_tv, bef) == FAIL) 917 return FAIL; 918 return OK; 919 } 920 921 /* 922 * Concatenate lists "l1" and "l2" into a new list, stored in "tv". 923 * Return FAIL when out of memory. 924 */ 925 int 926 list_concat(list_T *l1, list_T *l2, typval_T *tv) 927 { 928 list_T *l; 929 930 // make a copy of the first list. 931 if (l1 == NULL) 932 l = list_alloc(); 933 else 934 l = list_copy(l1, FALSE, 0); 935 if (l == NULL) 936 return FAIL; 937 tv->v_type = VAR_LIST; 938 tv->v_lock = 0; 939 tv->vval.v_list = l; 940 if (l1 == NULL) 941 ++l->lv_refcount; 942 943 // append all items from the second list 944 return list_extend(l, l2, NULL); 945 } 946 947 list_T * 948 list_slice(list_T *ol, long n1, long n2) 949 { 950 listitem_T *item; 951 list_T *l = list_alloc(); 952 953 if (l == NULL) 954 return NULL; 955 for (item = list_find(ol, n1); n1 <= n2; ++n1) 956 { 957 if (list_append_tv(l, &item->li_tv) == FAIL) 958 { 959 list_free(l); 960 return NULL; 961 } 962 item = item->li_next; 963 } 964 return l; 965 } 966 967 int 968 list_slice_or_index( 969 list_T *list, 970 int range, 971 varnumber_T n1_arg, 972 varnumber_T n2_arg, 973 int exclusive, 974 typval_T *rettv, 975 int verbose) 976 { 977 long len = list_len(list); 978 varnumber_T n1 = n1_arg; 979 varnumber_T n2 = n2_arg; 980 typval_T var1; 981 982 if (n1 < 0) 983 n1 = len + n1; 984 if (n1 < 0 || n1 >= len) 985 { 986 // For a range we allow invalid values and return an empty 987 // list. A list index out of range is an error. 988 if (!range) 989 { 990 if (verbose) 991 semsg(_(e_listidx), (long)n1_arg); 992 return FAIL; 993 } 994 n1 = n1 < 0 ? 0 : len; 995 } 996 if (range) 997 { 998 list_T *l; 999 1000 if (n2 < 0) 1001 n2 = len + n2; 1002 else if (n2 >= len) 1003 n2 = len - (exclusive ? 0 : 1); 1004 if (exclusive) 1005 --n2; 1006 if (n2 < 0 || n2 + 1 < n1) 1007 n2 = -1; 1008 l = list_slice(list, n1, n2); 1009 if (l == NULL) 1010 return FAIL; 1011 clear_tv(rettv); 1012 rettv_list_set(rettv, l); 1013 } 1014 else 1015 { 1016 // copy the item to "var1" to avoid that freeing the list makes it 1017 // invalid. 1018 copy_tv(&list_find(list, n1)->li_tv, &var1); 1019 clear_tv(rettv); 1020 *rettv = var1; 1021 } 1022 return OK; 1023 } 1024 1025 /* 1026 * Make a copy of list "orig". Shallow if "deep" is FALSE. 1027 * The refcount of the new list is set to 1. 1028 * See item_copy() for "copyID". 1029 * Returns NULL when out of memory. 1030 */ 1031 list_T * 1032 list_copy(list_T *orig, int deep, int copyID) 1033 { 1034 list_T *copy; 1035 listitem_T *item; 1036 listitem_T *ni; 1037 1038 if (orig == NULL) 1039 return NULL; 1040 1041 copy = list_alloc(); 1042 if (copy != NULL) 1043 { 1044 if (copyID != 0) 1045 { 1046 // Do this before adding the items, because one of the items may 1047 // refer back to this list. 1048 orig->lv_copyID = copyID; 1049 orig->lv_copylist = copy; 1050 } 1051 CHECK_LIST_MATERIALIZE(orig); 1052 for (item = orig->lv_first; item != NULL && !got_int; 1053 item = item->li_next) 1054 { 1055 ni = listitem_alloc(); 1056 if (ni == NULL) 1057 break; 1058 if (deep) 1059 { 1060 if (item_copy(&item->li_tv, &ni->li_tv, deep, copyID) == FAIL) 1061 { 1062 vim_free(ni); 1063 break; 1064 } 1065 } 1066 else 1067 copy_tv(&item->li_tv, &ni->li_tv); 1068 list_append(copy, ni); 1069 } 1070 ++copy->lv_refcount; 1071 if (item != NULL) 1072 { 1073 list_unref(copy); 1074 copy = NULL; 1075 } 1076 } 1077 1078 return copy; 1079 } 1080 1081 /* 1082 * Remove items "item" to "item2" from list "l". 1083 * Does not free the listitem or the value! 1084 * This used to be called list_remove, but that conflicts with a Sun header 1085 * file. 1086 */ 1087 void 1088 vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2) 1089 { 1090 listitem_T *ip; 1091 1092 CHECK_LIST_MATERIALIZE(l); 1093 1094 // notify watchers 1095 for (ip = item; ip != NULL; ip = ip->li_next) 1096 { 1097 --l->lv_len; 1098 list_fix_watch(l, ip); 1099 if (ip == item2) 1100 break; 1101 } 1102 1103 if (item2->li_next == NULL) 1104 l->lv_u.mat.lv_last = item->li_prev; 1105 else 1106 item2->li_next->li_prev = item->li_prev; 1107 if (item->li_prev == NULL) 1108 l->lv_first = item2->li_next; 1109 else 1110 item->li_prev->li_next = item2->li_next; 1111 l->lv_u.mat.lv_idx_item = NULL; 1112 } 1113 1114 /* 1115 * Return an allocated string with the string representation of a list. 1116 * May return NULL. 1117 */ 1118 char_u * 1119 list2string(typval_T *tv, int copyID, int restore_copyID) 1120 { 1121 garray_T ga; 1122 1123 if (tv->vval.v_list == NULL) 1124 return NULL; 1125 ga_init2(&ga, (int)sizeof(char), 80); 1126 ga_append(&ga, '['); 1127 CHECK_LIST_MATERIALIZE(tv->vval.v_list); 1128 if (list_join(&ga, tv->vval.v_list, (char_u *)", ", 1129 FALSE, restore_copyID, copyID) == FAIL) 1130 { 1131 vim_free(ga.ga_data); 1132 return NULL; 1133 } 1134 ga_append(&ga, ']'); 1135 ga_append(&ga, NUL); 1136 return (char_u *)ga.ga_data; 1137 } 1138 1139 typedef struct join_S { 1140 char_u *s; 1141 char_u *tofree; 1142 } join_T; 1143 1144 static int 1145 list_join_inner( 1146 garray_T *gap, // to store the result in 1147 list_T *l, 1148 char_u *sep, 1149 int echo_style, 1150 int restore_copyID, 1151 int copyID, 1152 garray_T *join_gap) // to keep each list item string 1153 { 1154 int i; 1155 join_T *p; 1156 int len; 1157 int sumlen = 0; 1158 int first = TRUE; 1159 char_u *tofree; 1160 char_u numbuf[NUMBUFLEN]; 1161 listitem_T *item; 1162 char_u *s; 1163 1164 // Stringify each item in the list. 1165 CHECK_LIST_MATERIALIZE(l); 1166 for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) 1167 { 1168 s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID, 1169 echo_style, restore_copyID, !echo_style); 1170 if (s == NULL) 1171 return FAIL; 1172 1173 len = (int)STRLEN(s); 1174 sumlen += len; 1175 1176 (void)ga_grow(join_gap, 1); 1177 p = ((join_T *)join_gap->ga_data) + (join_gap->ga_len++); 1178 if (tofree != NULL || s != numbuf) 1179 { 1180 p->s = s; 1181 p->tofree = tofree; 1182 } 1183 else 1184 { 1185 p->s = vim_strnsave(s, len); 1186 p->tofree = p->s; 1187 } 1188 1189 line_breakcheck(); 1190 if (did_echo_string_emsg) // recursion error, bail out 1191 break; 1192 } 1193 1194 // Allocate result buffer with its total size, avoid re-allocation and 1195 // multiple copy operations. Add 2 for a tailing ']' and NUL. 1196 if (join_gap->ga_len >= 2) 1197 sumlen += (int)STRLEN(sep) * (join_gap->ga_len - 1); 1198 if (ga_grow(gap, sumlen + 2) == FAIL) 1199 return FAIL; 1200 1201 for (i = 0; i < join_gap->ga_len && !got_int; ++i) 1202 { 1203 if (first) 1204 first = FALSE; 1205 else 1206 ga_concat(gap, sep); 1207 p = ((join_T *)join_gap->ga_data) + i; 1208 1209 if (p->s != NULL) 1210 ga_concat(gap, p->s); 1211 line_breakcheck(); 1212 } 1213 1214 return OK; 1215 } 1216 1217 /* 1218 * Join list "l" into a string in "*gap", using separator "sep". 1219 * When "echo_style" is TRUE use String as echoed, otherwise as inside a List. 1220 * Return FAIL or OK. 1221 */ 1222 int 1223 list_join( 1224 garray_T *gap, 1225 list_T *l, 1226 char_u *sep, 1227 int echo_style, 1228 int restore_copyID, 1229 int copyID) 1230 { 1231 garray_T join_ga; 1232 int retval; 1233 join_T *p; 1234 int i; 1235 1236 if (l->lv_len < 1) 1237 return OK; // nothing to do 1238 ga_init2(&join_ga, (int)sizeof(join_T), l->lv_len); 1239 retval = list_join_inner(gap, l, sep, echo_style, restore_copyID, 1240 copyID, &join_ga); 1241 1242 // Dispose each item in join_ga. 1243 if (join_ga.ga_data != NULL) 1244 { 1245 p = (join_T *)join_ga.ga_data; 1246 for (i = 0; i < join_ga.ga_len; ++i) 1247 { 1248 vim_free(p->tofree); 1249 ++p; 1250 } 1251 ga_clear(&join_ga); 1252 } 1253 1254 return retval; 1255 } 1256 1257 /* 1258 * "join()" function 1259 */ 1260 void 1261 f_join(typval_T *argvars, typval_T *rettv) 1262 { 1263 garray_T ga; 1264 char_u *sep; 1265 1266 if (argvars[0].v_type != VAR_LIST) 1267 { 1268 emsg(_(e_listreq)); 1269 return; 1270 } 1271 if (argvars[0].vval.v_list == NULL) 1272 return; 1273 if (argvars[1].v_type == VAR_UNKNOWN) 1274 sep = (char_u *)" "; 1275 else 1276 sep = tv_get_string_chk(&argvars[1]); 1277 1278 rettv->v_type = VAR_STRING; 1279 1280 if (sep != NULL) 1281 { 1282 ga_init2(&ga, (int)sizeof(char), 80); 1283 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0); 1284 ga_append(&ga, NUL); 1285 rettv->vval.v_string = (char_u *)ga.ga_data; 1286 } 1287 else 1288 rettv->vval.v_string = NULL; 1289 } 1290 1291 /* 1292 * Allocate a variable for a List and fill it from "*arg". 1293 * "*arg" points to the "[". 1294 * Return OK or FAIL. 1295 */ 1296 int 1297 eval_list(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int do_error) 1298 { 1299 int evaluate = evalarg == NULL ? FALSE 1300 : evalarg->eval_flags & EVAL_EVALUATE; 1301 list_T *l = NULL; 1302 typval_T tv; 1303 listitem_T *item; 1304 int vim9script = in_vim9script(); 1305 int had_comma; 1306 1307 if (evaluate) 1308 { 1309 l = list_alloc(); 1310 if (l == NULL) 1311 return FAIL; 1312 } 1313 1314 *arg = skipwhite_and_linebreak(*arg + 1, evalarg); 1315 while (**arg != ']' && **arg != NUL) 1316 { 1317 if (eval1(arg, &tv, evalarg) == FAIL) // recursive! 1318 goto failret; 1319 if (evaluate) 1320 { 1321 item = listitem_alloc(); 1322 if (item != NULL) 1323 { 1324 item->li_tv = tv; 1325 item->li_tv.v_lock = 0; 1326 list_append(l, item); 1327 } 1328 else 1329 clear_tv(&tv); 1330 } 1331 // Legacy Vim script allowed a space before the comma. 1332 if (!vim9script) 1333 *arg = skipwhite(*arg); 1334 1335 // the comma must come after the value 1336 had_comma = **arg == ','; 1337 if (had_comma) 1338 { 1339 if (vim9script && !IS_WHITE_OR_NUL((*arg)[1]) && (*arg)[1] != ']') 1340 { 1341 semsg(_(e_white_space_required_after_str_str), ",", *arg); 1342 goto failret; 1343 } 1344 *arg = skipwhite(*arg + 1); 1345 } 1346 1347 // The "]" can be on the next line. But a double quoted string may 1348 // follow, not a comment. 1349 *arg = skipwhite_and_linebreak(*arg, evalarg); 1350 if (**arg == ']') 1351 break; 1352 1353 if (!had_comma) 1354 { 1355 if (do_error) 1356 { 1357 if (**arg == ',') 1358 semsg(_(e_no_white_space_allowed_before_str_str), 1359 ",", *arg); 1360 else 1361 semsg(_("E696: Missing comma in List: %s"), *arg); 1362 } 1363 goto failret; 1364 } 1365 } 1366 1367 if (**arg != ']') 1368 { 1369 if (do_error) 1370 semsg(_(e_list_end), *arg); 1371 failret: 1372 if (evaluate) 1373 list_free(l); 1374 return FAIL; 1375 } 1376 1377 *arg += 1; 1378 if (evaluate) 1379 rettv_list_set(rettv, l); 1380 1381 return OK; 1382 } 1383 1384 /* 1385 * Write "list" of strings to file "fd". 1386 */ 1387 int 1388 write_list(FILE *fd, list_T *list, int binary) 1389 { 1390 listitem_T *li; 1391 int c; 1392 int ret = OK; 1393 char_u *s; 1394 1395 CHECK_LIST_MATERIALIZE(list); 1396 FOR_ALL_LIST_ITEMS(list, li) 1397 { 1398 for (s = tv_get_string(&li->li_tv); *s != NUL; ++s) 1399 { 1400 if (*s == '\n') 1401 c = putc(NUL, fd); 1402 else 1403 c = putc(*s, fd); 1404 if (c == EOF) 1405 { 1406 ret = FAIL; 1407 break; 1408 } 1409 } 1410 if (!binary || li->li_next != NULL) 1411 if (putc('\n', fd) == EOF) 1412 { 1413 ret = FAIL; 1414 break; 1415 } 1416 if (ret == FAIL) 1417 { 1418 emsg(_(e_write)); 1419 break; 1420 } 1421 } 1422 return ret; 1423 } 1424 1425 /* 1426 * Initialize a static list with 10 items. 1427 */ 1428 void 1429 init_static_list(staticList10_T *sl) 1430 { 1431 list_T *l = &sl->sl_list; 1432 int i; 1433 1434 memset(sl, 0, sizeof(staticList10_T)); 1435 l->lv_first = &sl->sl_items[0]; 1436 l->lv_u.mat.lv_last = &sl->sl_items[9]; 1437 l->lv_refcount = DO_NOT_FREE_CNT; 1438 l->lv_lock = VAR_FIXED; 1439 sl->sl_list.lv_len = 10; 1440 1441 for (i = 0; i < 10; ++i) 1442 { 1443 listitem_T *li = &sl->sl_items[i]; 1444 1445 if (i == 0) 1446 li->li_prev = NULL; 1447 else 1448 li->li_prev = li - 1; 1449 if (i == 9) 1450 li->li_next = NULL; 1451 else 1452 li->li_next = li + 1; 1453 } 1454 } 1455 1456 /* 1457 * "list2str()" function 1458 */ 1459 void 1460 f_list2str(typval_T *argvars, typval_T *rettv) 1461 { 1462 list_T *l; 1463 listitem_T *li; 1464 garray_T ga; 1465 int utf8 = FALSE; 1466 1467 rettv->v_type = VAR_STRING; 1468 rettv->vval.v_string = NULL; 1469 if (argvars[0].v_type != VAR_LIST) 1470 { 1471 emsg(_(e_invarg)); 1472 return; 1473 } 1474 1475 l = argvars[0].vval.v_list; 1476 if (l == NULL) 1477 return; // empty list results in empty string 1478 1479 if (argvars[1].v_type != VAR_UNKNOWN) 1480 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL); 1481 1482 CHECK_LIST_MATERIALIZE(l); 1483 ga_init2(&ga, 1, 80); 1484 if (has_mbyte || utf8) 1485 { 1486 char_u buf[MB_MAXBYTES + 1]; 1487 int (*char2bytes)(int, char_u *); 1488 1489 if (utf8 || enc_utf8) 1490 char2bytes = utf_char2bytes; 1491 else 1492 char2bytes = mb_char2bytes; 1493 1494 FOR_ALL_LIST_ITEMS(l, li) 1495 { 1496 buf[(*char2bytes)(tv_get_number(&li->li_tv), buf)] = NUL; 1497 ga_concat(&ga, buf); 1498 } 1499 ga_append(&ga, NUL); 1500 } 1501 else if (ga_grow(&ga, list_len(l) + 1) == OK) 1502 { 1503 FOR_ALL_LIST_ITEMS(l, li) 1504 ga_append(&ga, tv_get_number(&li->li_tv)); 1505 ga_append(&ga, NUL); 1506 } 1507 1508 rettv->v_type = VAR_STRING; 1509 rettv->vval.v_string = ga.ga_data; 1510 } 1511 1512 static void 1513 list_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg) 1514 { 1515 list_T *l; 1516 listitem_T *item, *item2; 1517 listitem_T *li; 1518 int error = FALSE; 1519 long idx; 1520 1521 if ((l = argvars[0].vval.v_list) == NULL 1522 || value_check_lock(l->lv_lock, arg_errmsg, TRUE)) 1523 return; 1524 1525 idx = (long)tv_get_number_chk(&argvars[1], &error); 1526 if (error) 1527 ; // type error: do nothing, errmsg already given 1528 else if ((item = list_find(l, idx)) == NULL) 1529 semsg(_(e_listidx), idx); 1530 else 1531 { 1532 if (argvars[2].v_type == VAR_UNKNOWN) 1533 { 1534 // Remove one item, return its value. 1535 vimlist_remove(l, item, item); 1536 *rettv = item->li_tv; 1537 list_free_item(l, item); 1538 } 1539 else 1540 { 1541 // Remove range of items, return list with values. 1542 long end = (long)tv_get_number_chk(&argvars[2], &error); 1543 1544 if (error) 1545 ; // type error: do nothing 1546 else if ((item2 = list_find(l, end)) == NULL) 1547 semsg(_(e_listidx), end); 1548 else 1549 { 1550 int cnt = 0; 1551 1552 for (li = item; li != NULL; li = li->li_next) 1553 { 1554 ++cnt; 1555 if (li == item2) 1556 break; 1557 } 1558 if (li == NULL) // didn't find "item2" after "item" 1559 emsg(_(e_invrange)); 1560 else 1561 { 1562 vimlist_remove(l, item, item2); 1563 if (rettv_list_alloc(rettv) == OK) 1564 { 1565 l = rettv->vval.v_list; 1566 l->lv_first = item; 1567 l->lv_u.mat.lv_last = item2; 1568 item->li_prev = NULL; 1569 item2->li_next = NULL; 1570 l->lv_len = cnt; 1571 } 1572 } 1573 } 1574 } 1575 } 1576 } 1577 1578 static int item_compare(const void *s1, const void *s2); 1579 static int item_compare2(const void *s1, const void *s2); 1580 1581 // struct used in the array that's given to qsort() 1582 typedef struct 1583 { 1584 listitem_T *item; 1585 int idx; 1586 } sortItem_T; 1587 1588 // struct storing information about current sort 1589 typedef struct 1590 { 1591 int item_compare_ic; 1592 int item_compare_lc; 1593 int item_compare_numeric; 1594 int item_compare_numbers; 1595 #ifdef FEAT_FLOAT 1596 int item_compare_float; 1597 #endif 1598 char_u *item_compare_func; 1599 partial_T *item_compare_partial; 1600 dict_T *item_compare_selfdict; 1601 int item_compare_func_err; 1602 int item_compare_keep_zero; 1603 } sortinfo_T; 1604 static sortinfo_T *sortinfo = NULL; 1605 #define ITEM_COMPARE_FAIL 999 1606 1607 /* 1608 * Compare functions for f_sort() and f_uniq() below. 1609 */ 1610 static int 1611 item_compare(const void *s1, const void *s2) 1612 { 1613 sortItem_T *si1, *si2; 1614 typval_T *tv1, *tv2; 1615 char_u *p1, *p2; 1616 char_u *tofree1 = NULL, *tofree2 = NULL; 1617 int res; 1618 char_u numbuf1[NUMBUFLEN]; 1619 char_u numbuf2[NUMBUFLEN]; 1620 1621 si1 = (sortItem_T *)s1; 1622 si2 = (sortItem_T *)s2; 1623 tv1 = &si1->item->li_tv; 1624 tv2 = &si2->item->li_tv; 1625 1626 if (sortinfo->item_compare_numbers) 1627 { 1628 varnumber_T v1 = tv_get_number(tv1); 1629 varnumber_T v2 = tv_get_number(tv2); 1630 1631 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; 1632 } 1633 1634 #ifdef FEAT_FLOAT 1635 if (sortinfo->item_compare_float) 1636 { 1637 float_T v1 = tv_get_float(tv1); 1638 float_T v2 = tv_get_float(tv2); 1639 1640 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; 1641 } 1642 #endif 1643 1644 // tv2string() puts quotes around a string and allocates memory. Don't do 1645 // that for string variables. Use a single quote when comparing with a 1646 // non-string to do what the docs promise. 1647 if (tv1->v_type == VAR_STRING) 1648 { 1649 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) 1650 p1 = (char_u *)"'"; 1651 else 1652 p1 = tv1->vval.v_string; 1653 } 1654 else 1655 p1 = tv2string(tv1, &tofree1, numbuf1, 0); 1656 if (tv2->v_type == VAR_STRING) 1657 { 1658 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) 1659 p2 = (char_u *)"'"; 1660 else 1661 p2 = tv2->vval.v_string; 1662 } 1663 else 1664 p2 = tv2string(tv2, &tofree2, numbuf2, 0); 1665 if (p1 == NULL) 1666 p1 = (char_u *)""; 1667 if (p2 == NULL) 1668 p2 = (char_u *)""; 1669 if (!sortinfo->item_compare_numeric) 1670 { 1671 if (sortinfo->item_compare_lc) 1672 res = strcoll((char *)p1, (char *)p2); 1673 else 1674 res = sortinfo->item_compare_ic ? STRICMP(p1, p2): STRCMP(p1, p2); 1675 } 1676 else 1677 { 1678 double n1, n2; 1679 n1 = strtod((char *)p1, (char **)&p1); 1680 n2 = strtod((char *)p2, (char **)&p2); 1681 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1; 1682 } 1683 1684 // When the result would be zero, compare the item indexes. Makes the 1685 // sort stable. 1686 if (res == 0 && !sortinfo->item_compare_keep_zero) 1687 res = si1->idx > si2->idx ? 1 : -1; 1688 1689 vim_free(tofree1); 1690 vim_free(tofree2); 1691 return res; 1692 } 1693 1694 static int 1695 item_compare2(const void *s1, const void *s2) 1696 { 1697 sortItem_T *si1, *si2; 1698 int res; 1699 typval_T rettv; 1700 typval_T argv[3]; 1701 char_u *func_name; 1702 partial_T *partial = sortinfo->item_compare_partial; 1703 funcexe_T funcexe; 1704 1705 // shortcut after failure in previous call; compare all items equal 1706 if (sortinfo->item_compare_func_err) 1707 return 0; 1708 1709 si1 = (sortItem_T *)s1; 1710 si2 = (sortItem_T *)s2; 1711 1712 if (partial == NULL) 1713 func_name = sortinfo->item_compare_func; 1714 else 1715 func_name = partial_name(partial); 1716 1717 // Copy the values. This is needed to be able to set v_lock to VAR_FIXED 1718 // in the copy without changing the original list items. 1719 copy_tv(&si1->item->li_tv, &argv[0]); 1720 copy_tv(&si2->item->li_tv, &argv[1]); 1721 1722 rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this 1723 CLEAR_FIELD(funcexe); 1724 funcexe.evaluate = TRUE; 1725 funcexe.partial = partial; 1726 funcexe.selfdict = sortinfo->item_compare_selfdict; 1727 res = call_func(func_name, -1, &rettv, 2, argv, &funcexe); 1728 clear_tv(&argv[0]); 1729 clear_tv(&argv[1]); 1730 1731 if (res == FAIL) 1732 res = ITEM_COMPARE_FAIL; 1733 else 1734 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err); 1735 if (sortinfo->item_compare_func_err) 1736 res = ITEM_COMPARE_FAIL; // return value has wrong type 1737 clear_tv(&rettv); 1738 1739 // When the result would be zero, compare the pointers themselves. Makes 1740 // the sort stable. 1741 if (res == 0 && !sortinfo->item_compare_keep_zero) 1742 res = si1->idx > si2->idx ? 1 : -1; 1743 1744 return res; 1745 } 1746 1747 /* 1748 * "sort()" or "uniq()" function 1749 */ 1750 static void 1751 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) 1752 { 1753 list_T *l; 1754 listitem_T *li; 1755 sortItem_T *ptrs; 1756 sortinfo_T *old_sortinfo; 1757 sortinfo_T info; 1758 long len; 1759 long i; 1760 1761 // Pointer to current info struct used in compare function. Save and 1762 // restore the current one for nested calls. 1763 old_sortinfo = sortinfo; 1764 sortinfo = &info; 1765 1766 if (argvars[0].v_type != VAR_LIST) 1767 semsg(_(e_listarg), sort ? "sort()" : "uniq()"); 1768 else 1769 { 1770 l = argvars[0].vval.v_list; 1771 if (l == NULL || value_check_lock(l->lv_lock, 1772 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")), 1773 TRUE)) 1774 goto theend; 1775 rettv_list_set(rettv, l); 1776 CHECK_LIST_MATERIALIZE(l); 1777 1778 len = list_len(l); 1779 if (len <= 1) 1780 goto theend; // short list sorts pretty quickly 1781 1782 info.item_compare_ic = FALSE; 1783 info.item_compare_lc = FALSE; 1784 info.item_compare_numeric = FALSE; 1785 info.item_compare_numbers = FALSE; 1786 #ifdef FEAT_FLOAT 1787 info.item_compare_float = FALSE; 1788 #endif 1789 info.item_compare_func = NULL; 1790 info.item_compare_partial = NULL; 1791 info.item_compare_selfdict = NULL; 1792 if (argvars[1].v_type != VAR_UNKNOWN) 1793 { 1794 // optional second argument: {func} 1795 if (argvars[1].v_type == VAR_FUNC) 1796 info.item_compare_func = argvars[1].vval.v_string; 1797 else if (argvars[1].v_type == VAR_PARTIAL) 1798 info.item_compare_partial = argvars[1].vval.v_partial; 1799 else 1800 { 1801 int error = FALSE; 1802 int nr = 0; 1803 1804 if (argvars[1].v_type == VAR_NUMBER) 1805 { 1806 nr = tv_get_number_chk(&argvars[1], &error); 1807 if (error) 1808 goto theend; // type error; errmsg already given 1809 if (nr == 1) 1810 info.item_compare_ic = TRUE; 1811 } 1812 if (nr != 1) 1813 { 1814 if (argvars[1].v_type != VAR_NUMBER) 1815 info.item_compare_func = tv_get_string(&argvars[1]); 1816 else if (nr != 0) 1817 { 1818 emsg(_(e_invarg)); 1819 goto theend; 1820 } 1821 } 1822 if (info.item_compare_func != NULL) 1823 { 1824 if (*info.item_compare_func == NUL) 1825 { 1826 // empty string means default sort 1827 info.item_compare_func = NULL; 1828 } 1829 else if (STRCMP(info.item_compare_func, "n") == 0) 1830 { 1831 info.item_compare_func = NULL; 1832 info.item_compare_numeric = TRUE; 1833 } 1834 else if (STRCMP(info.item_compare_func, "N") == 0) 1835 { 1836 info.item_compare_func = NULL; 1837 info.item_compare_numbers = TRUE; 1838 } 1839 #ifdef FEAT_FLOAT 1840 else if (STRCMP(info.item_compare_func, "f") == 0) 1841 { 1842 info.item_compare_func = NULL; 1843 info.item_compare_float = TRUE; 1844 } 1845 #endif 1846 else if (STRCMP(info.item_compare_func, "i") == 0) 1847 { 1848 info.item_compare_func = NULL; 1849 info.item_compare_ic = TRUE; 1850 } 1851 else if (STRCMP(info.item_compare_func, "l") == 0) 1852 { 1853 info.item_compare_func = NULL; 1854 info.item_compare_lc = TRUE; 1855 } 1856 } 1857 } 1858 1859 if (argvars[2].v_type != VAR_UNKNOWN) 1860 { 1861 // optional third argument: {dict} 1862 if (argvars[2].v_type != VAR_DICT) 1863 { 1864 emsg(_(e_dictreq)); 1865 goto theend; 1866 } 1867 info.item_compare_selfdict = argvars[2].vval.v_dict; 1868 } 1869 } 1870 1871 // Make an array with each entry pointing to an item in the List. 1872 ptrs = ALLOC_MULT(sortItem_T, len); 1873 if (ptrs == NULL) 1874 goto theend; 1875 1876 i = 0; 1877 if (sort) 1878 { 1879 // sort(): ptrs will be the list to sort 1880 FOR_ALL_LIST_ITEMS(l, li) 1881 { 1882 ptrs[i].item = li; 1883 ptrs[i].idx = i; 1884 ++i; 1885 } 1886 1887 info.item_compare_func_err = FALSE; 1888 info.item_compare_keep_zero = FALSE; 1889 // test the compare function 1890 if ((info.item_compare_func != NULL 1891 || info.item_compare_partial != NULL) 1892 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1]) 1893 == ITEM_COMPARE_FAIL) 1894 emsg(_("E702: Sort compare function failed")); 1895 else 1896 { 1897 // Sort the array with item pointers. 1898 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T), 1899 info.item_compare_func == NULL 1900 && info.item_compare_partial == NULL 1901 ? item_compare : item_compare2); 1902 1903 if (!info.item_compare_func_err) 1904 { 1905 // Clear the List and append the items in sorted order. 1906 l->lv_first = l->lv_u.mat.lv_last 1907 = l->lv_u.mat.lv_idx_item = NULL; 1908 l->lv_len = 0; 1909 for (i = 0; i < len; ++i) 1910 list_append(l, ptrs[i].item); 1911 } 1912 } 1913 } 1914 else 1915 { 1916 int (*item_compare_func_ptr)(const void *, const void *); 1917 1918 // f_uniq(): ptrs will be a stack of items to remove 1919 info.item_compare_func_err = FALSE; 1920 info.item_compare_keep_zero = TRUE; 1921 item_compare_func_ptr = info.item_compare_func != NULL 1922 || info.item_compare_partial != NULL 1923 ? item_compare2 : item_compare; 1924 1925 for (li = l->lv_first; li != NULL && li->li_next != NULL; 1926 li = li->li_next) 1927 { 1928 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next) 1929 == 0) 1930 ptrs[i++].item = li; 1931 if (info.item_compare_func_err) 1932 { 1933 emsg(_("E882: Uniq compare function failed")); 1934 break; 1935 } 1936 } 1937 1938 if (!info.item_compare_func_err) 1939 { 1940 while (--i >= 0) 1941 { 1942 li = ptrs[i].item->li_next; 1943 ptrs[i].item->li_next = li->li_next; 1944 if (li->li_next != NULL) 1945 li->li_next->li_prev = ptrs[i].item; 1946 else 1947 l->lv_u.mat.lv_last = ptrs[i].item; 1948 list_fix_watch(l, li); 1949 listitem_free(l, li); 1950 l->lv_len--; 1951 } 1952 } 1953 } 1954 1955 vim_free(ptrs); 1956 } 1957 theend: 1958 sortinfo = old_sortinfo; 1959 } 1960 1961 /* 1962 * "sort({list})" function 1963 */ 1964 void 1965 f_sort(typval_T *argvars, typval_T *rettv) 1966 { 1967 do_sort_uniq(argvars, rettv, TRUE); 1968 } 1969 1970 /* 1971 * "uniq({list})" function 1972 */ 1973 void 1974 f_uniq(typval_T *argvars, typval_T *rettv) 1975 { 1976 do_sort_uniq(argvars, rettv, FALSE); 1977 } 1978 1979 typedef enum { 1980 FILTERMAP_FILTER, 1981 FILTERMAP_MAP, 1982 FILTERMAP_MAPNEW 1983 } filtermap_T; 1984 1985 /* 1986 * Handle one item for map() and filter(). 1987 * Sets v:val to "tv". Caller must set v:key. 1988 */ 1989 static int 1990 filter_map_one( 1991 typval_T *tv, // original value 1992 typval_T *expr, // callback 1993 filtermap_T filtermap, 1994 typval_T *newtv, // for map() and mapnew(): new value 1995 int *remp) // for filter(): remove flag 1996 { 1997 typval_T argv[3]; 1998 int retval = FAIL; 1999 2000 copy_tv(tv, get_vim_var_tv(VV_VAL)); 2001 argv[0] = *get_vim_var_tv(VV_KEY); 2002 argv[1] = *get_vim_var_tv(VV_VAL); 2003 if (eval_expr_typval(expr, argv, 2, newtv) == FAIL) 2004 goto theend; 2005 if (filtermap == FILTERMAP_FILTER) 2006 { 2007 int error = FALSE; 2008 2009 // filter(): when expr is zero remove the item 2010 if (in_vim9script()) 2011 *remp = !tv2bool(newtv); 2012 else 2013 *remp = (tv_get_number_chk(newtv, &error) == 0); 2014 clear_tv(newtv); 2015 // On type error, nothing has been removed; return FAIL to stop the 2016 // loop. The error message was given by tv_get_number_chk(). 2017 if (error) 2018 goto theend; 2019 } 2020 retval = OK; 2021 theend: 2022 clear_tv(get_vim_var_tv(VV_VAL)); 2023 return retval; 2024 } 2025 2026 /* 2027 * Implementation of map() and filter(). 2028 */ 2029 static void 2030 filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap) 2031 { 2032 typval_T *expr; 2033 listitem_T *li, *nli; 2034 list_T *l = NULL; 2035 dictitem_T *di; 2036 hashtab_T *ht; 2037 hashitem_T *hi; 2038 dict_T *d = NULL; 2039 blob_T *b = NULL; 2040 int rem; 2041 int todo; 2042 char_u *ermsg = (char_u *)(filtermap == FILTERMAP_MAP ? "map()" 2043 : filtermap == FILTERMAP_MAPNEW ? "mapnew()" 2044 : "filter()"); 2045 char_u *arg_errmsg = (char_u *)(filtermap == FILTERMAP_MAP 2046 ? N_("map() argument") 2047 : filtermap == FILTERMAP_MAPNEW 2048 ? N_("mapnew() argument") 2049 : N_("filter() argument")); 2050 int save_did_emsg; 2051 int idx = 0; 2052 type_T *type = NULL; 2053 garray_T type_list; 2054 2055 // map() and filter() return the first argument, also on failure. 2056 if (filtermap != FILTERMAP_MAPNEW) 2057 copy_tv(&argvars[0], rettv); 2058 if (filtermap == FILTERMAP_MAP && in_vim9script()) 2059 { 2060 // Check that map() does not change the type of the dict. 2061 ga_init2(&type_list, sizeof(type_T *), 10); 2062 type = typval2type(argvars, get_copyID(), &type_list, TRUE); 2063 } 2064 2065 if (argvars[0].v_type == VAR_BLOB) 2066 { 2067 if (filtermap == FILTERMAP_MAPNEW) 2068 { 2069 rettv->v_type = VAR_BLOB; 2070 rettv->vval.v_blob = NULL; 2071 } 2072 if ((b = argvars[0].vval.v_blob) == NULL) 2073 goto theend; 2074 } 2075 else if (argvars[0].v_type == VAR_LIST) 2076 { 2077 if (filtermap == FILTERMAP_MAPNEW) 2078 { 2079 rettv->v_type = VAR_LIST; 2080 rettv->vval.v_list = NULL; 2081 } 2082 if ((l = argvars[0].vval.v_list) == NULL 2083 || (filtermap == FILTERMAP_FILTER 2084 && value_check_lock(l->lv_lock, arg_errmsg, TRUE))) 2085 goto theend; 2086 } 2087 else if (argvars[0].v_type == VAR_DICT) 2088 { 2089 if (filtermap == FILTERMAP_MAPNEW) 2090 { 2091 rettv->v_type = VAR_DICT; 2092 rettv->vval.v_dict = NULL; 2093 } 2094 if ((d = argvars[0].vval.v_dict) == NULL 2095 || (filtermap == FILTERMAP_FILTER 2096 && value_check_lock(d->dv_lock, arg_errmsg, TRUE))) 2097 goto theend; 2098 } 2099 else 2100 { 2101 semsg(_(e_listdictblobarg), ermsg); 2102 goto theend; 2103 } 2104 2105 expr = &argvars[1]; 2106 // On type errors, the preceding call has already displayed an error 2107 // message. Avoid a misleading error message for an empty string that 2108 // was not passed as argument. 2109 if (expr->v_type != VAR_UNKNOWN) 2110 { 2111 typval_T save_val; 2112 typval_T save_key; 2113 2114 prepare_vimvar(VV_VAL, &save_val); 2115 prepare_vimvar(VV_KEY, &save_key); 2116 2117 // We reset "did_emsg" to be able to detect whether an error 2118 // occurred during evaluation of the expression. 2119 save_did_emsg = did_emsg; 2120 did_emsg = FALSE; 2121 2122 if (argvars[0].v_type == VAR_DICT) 2123 { 2124 int prev_lock = d->dv_lock; 2125 dict_T *d_ret = NULL; 2126 2127 if (filtermap == FILTERMAP_MAPNEW) 2128 { 2129 if (rettv_dict_alloc(rettv) == FAIL) 2130 goto theend; 2131 d_ret = rettv->vval.v_dict; 2132 } 2133 2134 if (filtermap != FILTERMAP_FILTER && d->dv_lock == 0) 2135 d->dv_lock = VAR_LOCKED; 2136 ht = &d->dv_hashtab; 2137 hash_lock(ht); 2138 todo = (int)ht->ht_used; 2139 for (hi = ht->ht_array; todo > 0; ++hi) 2140 { 2141 if (!HASHITEM_EMPTY(hi)) 2142 { 2143 int r; 2144 typval_T newtv; 2145 2146 --todo; 2147 di = HI2DI(hi); 2148 if (filtermap == FILTERMAP_MAP 2149 && (value_check_lock(di->di_tv.v_lock, 2150 arg_errmsg, TRUE) 2151 || var_check_ro(di->di_flags, 2152 arg_errmsg, TRUE))) 2153 break; 2154 set_vim_var_string(VV_KEY, di->di_key, -1); 2155 newtv.v_type = VAR_UNKNOWN; 2156 r = filter_map_one(&di->di_tv, expr, filtermap, 2157 &newtv, &rem); 2158 clear_tv(get_vim_var_tv(VV_KEY)); 2159 if (r == FAIL || did_emsg) 2160 { 2161 clear_tv(&newtv); 2162 break; 2163 } 2164 if (filtermap == FILTERMAP_MAP) 2165 { 2166 if (type != NULL && check_typval_arg_type( 2167 type->tt_member, &newtv, 0) == FAIL) 2168 { 2169 clear_tv(&newtv); 2170 break; 2171 } 2172 // map(): replace the dict item value 2173 clear_tv(&di->di_tv); 2174 newtv.v_lock = 0; 2175 di->di_tv = newtv; 2176 } 2177 else if (filtermap == FILTERMAP_MAPNEW) 2178 { 2179 // mapnew(): add the item value to the new dict 2180 r = dict_add_tv(d_ret, (char *)di->di_key, &newtv); 2181 clear_tv(&newtv); 2182 if (r == FAIL) 2183 break; 2184 } 2185 else if (filtermap == FILTERMAP_FILTER && rem) 2186 { 2187 // filter(false): remove the item from the dict 2188 if (var_check_fixed(di->di_flags, arg_errmsg, TRUE) 2189 || var_check_ro(di->di_flags, arg_errmsg, TRUE)) 2190 break; 2191 dictitem_remove(d, di); 2192 } 2193 } 2194 } 2195 hash_unlock(ht); 2196 d->dv_lock = prev_lock; 2197 } 2198 else if (argvars[0].v_type == VAR_BLOB) 2199 { 2200 int i; 2201 typval_T tv; 2202 varnumber_T val; 2203 blob_T *b_ret = b; 2204 2205 if (filtermap == FILTERMAP_MAPNEW) 2206 { 2207 if (blob_copy(b, rettv) == FAIL) 2208 goto theend; 2209 b_ret = rettv->vval.v_blob; 2210 } 2211 2212 // set_vim_var_nr() doesn't set the type 2213 set_vim_var_type(VV_KEY, VAR_NUMBER); 2214 2215 for (i = 0; i < b->bv_ga.ga_len; i++) 2216 { 2217 typval_T newtv; 2218 2219 tv.v_type = VAR_NUMBER; 2220 val = blob_get(b, i); 2221 tv.vval.v_number = val; 2222 set_vim_var_nr(VV_KEY, idx); 2223 if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL 2224 || did_emsg) 2225 break; 2226 if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL) 2227 { 2228 clear_tv(&newtv); 2229 emsg(_(e_invalblob)); 2230 break; 2231 } 2232 if (filtermap != FILTERMAP_FILTER) 2233 { 2234 if (newtv.vval.v_number != val) 2235 blob_set(b_ret, i, newtv.vval.v_number); 2236 } 2237 else if (rem) 2238 { 2239 char_u *p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data; 2240 2241 mch_memmove(p + i, p + i + 1, 2242 (size_t)b->bv_ga.ga_len - i - 1); 2243 --b->bv_ga.ga_len; 2244 --i; 2245 } 2246 ++idx; 2247 } 2248 } 2249 else // argvars[0].v_type == VAR_LIST 2250 { 2251 int prev_lock = l->lv_lock; 2252 list_T *l_ret = NULL; 2253 2254 if (filtermap == FILTERMAP_MAPNEW) 2255 { 2256 if (rettv_list_alloc(rettv) == FAIL) 2257 goto theend; 2258 l_ret = rettv->vval.v_list; 2259 } 2260 // set_vim_var_nr() doesn't set the type 2261 set_vim_var_type(VV_KEY, VAR_NUMBER); 2262 2263 if (filtermap != FILTERMAP_FILTER && l->lv_lock == 0) 2264 l->lv_lock = VAR_LOCKED; 2265 2266 if (l->lv_first == &range_list_item) 2267 { 2268 varnumber_T val = l->lv_u.nonmat.lv_start; 2269 int len = l->lv_len; 2270 int stride = l->lv_u.nonmat.lv_stride; 2271 2272 // List from range(): loop over the numbers 2273 if (filtermap != FILTERMAP_MAPNEW) 2274 { 2275 l->lv_first = NULL; 2276 l->lv_u.mat.lv_last = NULL; 2277 l->lv_len = 0; 2278 l->lv_u.mat.lv_idx_item = NULL; 2279 } 2280 2281 for (idx = 0; idx < len; ++idx) 2282 { 2283 typval_T tv; 2284 typval_T newtv; 2285 2286 tv.v_type = VAR_NUMBER; 2287 tv.v_lock = 0; 2288 tv.vval.v_number = val; 2289 set_vim_var_nr(VV_KEY, idx); 2290 if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) 2291 == FAIL) 2292 break; 2293 if (did_emsg) 2294 { 2295 clear_tv(&newtv); 2296 break; 2297 } 2298 if (filtermap != FILTERMAP_FILTER) 2299 { 2300 if (filtermap == FILTERMAP_MAP && type != NULL 2301 && check_typval_arg_type( 2302 type->tt_member, &newtv, 0) == FAIL) 2303 { 2304 clear_tv(&newtv); 2305 break; 2306 } 2307 // map(), mapnew(): always append the new value to the 2308 // list 2309 if (list_append_tv_move(filtermap == FILTERMAP_MAP 2310 ? l : l_ret, &newtv) == FAIL) 2311 break; 2312 } 2313 else if (!rem) 2314 { 2315 // filter(): append the list item value when not rem 2316 if (list_append_tv_move(l, &tv) == FAIL) 2317 break; 2318 } 2319 2320 val += stride; 2321 } 2322 } 2323 else 2324 { 2325 // Materialized list: loop over the items 2326 for (li = l->lv_first; li != NULL; li = nli) 2327 { 2328 typval_T newtv; 2329 2330 if (filtermap == FILTERMAP_MAP && value_check_lock( 2331 li->li_tv.v_lock, arg_errmsg, TRUE)) 2332 break; 2333 nli = li->li_next; 2334 set_vim_var_nr(VV_KEY, idx); 2335 if (filter_map_one(&li->li_tv, expr, filtermap, 2336 &newtv, &rem) == FAIL) 2337 break; 2338 if (did_emsg) 2339 { 2340 clear_tv(&newtv); 2341 break; 2342 } 2343 if (filtermap == FILTERMAP_MAP) 2344 { 2345 if (type != NULL && check_typval_arg_type( 2346 type->tt_member, &newtv, 0) == FAIL) 2347 { 2348 clear_tv(&newtv); 2349 break; 2350 } 2351 // map(): replace the list item value 2352 clear_tv(&li->li_tv); 2353 newtv.v_lock = 0; 2354 li->li_tv = newtv; 2355 } 2356 else if (filtermap == FILTERMAP_MAPNEW) 2357 { 2358 // mapnew(): append the list item value 2359 if (list_append_tv_move(l_ret, &newtv) == FAIL) 2360 break; 2361 } 2362 else if (filtermap == FILTERMAP_FILTER && rem) 2363 listitem_remove(l, li); 2364 ++idx; 2365 } 2366 } 2367 2368 l->lv_lock = prev_lock; 2369 } 2370 2371 restore_vimvar(VV_KEY, &save_key); 2372 restore_vimvar(VV_VAL, &save_val); 2373 2374 did_emsg |= save_did_emsg; 2375 } 2376 2377 theend: 2378 if (type != NULL) 2379 clear_type_list(&type_list); 2380 } 2381 2382 /* 2383 * "filter()" function 2384 */ 2385 void 2386 f_filter(typval_T *argvars, typval_T *rettv) 2387 { 2388 filter_map(argvars, rettv, FILTERMAP_FILTER); 2389 } 2390 2391 /* 2392 * "map()" function 2393 */ 2394 void 2395 f_map(typval_T *argvars, typval_T *rettv) 2396 { 2397 filter_map(argvars, rettv, FILTERMAP_MAP); 2398 } 2399 2400 /* 2401 * "mapnew()" function 2402 */ 2403 void 2404 f_mapnew(typval_T *argvars, typval_T *rettv) 2405 { 2406 filter_map(argvars, rettv, FILTERMAP_MAPNEW); 2407 } 2408 2409 /* 2410 * "add(list, item)" function 2411 */ 2412 void 2413 f_add(typval_T *argvars, typval_T *rettv) 2414 { 2415 rettv->vval.v_number = 1; // Default: Failed 2416 if (argvars[0].v_type == VAR_LIST) 2417 { 2418 list_T *l = argvars[0].vval.v_list; 2419 2420 if (l == NULL) 2421 { 2422 if (in_vim9script()) 2423 emsg(_(e_cannot_add_to_null_list)); 2424 } 2425 else if (!value_check_lock(l->lv_lock, 2426 (char_u *)N_("add() argument"), TRUE) 2427 && list_append_tv(l, &argvars[1]) == OK) 2428 { 2429 copy_tv(&argvars[0], rettv); 2430 } 2431 } 2432 else if (argvars[0].v_type == VAR_BLOB) 2433 { 2434 blob_T *b = argvars[0].vval.v_blob; 2435 2436 if (b == NULL) 2437 { 2438 if (in_vim9script()) 2439 emsg(_(e_cannot_add_to_null_blob)); 2440 } 2441 else if (!value_check_lock(b->bv_lock, 2442 (char_u *)N_("add() argument"), TRUE)) 2443 { 2444 int error = FALSE; 2445 varnumber_T n = tv_get_number_chk(&argvars[1], &error); 2446 2447 if (!error) 2448 { 2449 ga_append(&b->bv_ga, (int)n); 2450 copy_tv(&argvars[0], rettv); 2451 } 2452 } 2453 } 2454 else 2455 emsg(_(e_listblobreq)); 2456 } 2457 2458 /* 2459 * "count()" function 2460 */ 2461 void 2462 f_count(typval_T *argvars, typval_T *rettv) 2463 { 2464 long n = 0; 2465 int ic = FALSE; 2466 int error = FALSE; 2467 2468 if (argvars[2].v_type != VAR_UNKNOWN) 2469 ic = (int)tv_get_bool_chk(&argvars[2], &error); 2470 2471 if (argvars[0].v_type == VAR_STRING) 2472 { 2473 char_u *expr = tv_get_string_chk(&argvars[1]); 2474 char_u *p = argvars[0].vval.v_string; 2475 char_u *next; 2476 2477 if (!error && expr != NULL && *expr != NUL && p != NULL) 2478 { 2479 if (ic) 2480 { 2481 size_t len = STRLEN(expr); 2482 2483 while (*p != NUL) 2484 { 2485 if (MB_STRNICMP(p, expr, len) == 0) 2486 { 2487 ++n; 2488 p += len; 2489 } 2490 else 2491 MB_PTR_ADV(p); 2492 } 2493 } 2494 else 2495 while ((next = (char_u *)strstr((char *)p, (char *)expr)) 2496 != NULL) 2497 { 2498 ++n; 2499 p = next + STRLEN(expr); 2500 } 2501 } 2502 2503 } 2504 else if (argvars[0].v_type == VAR_LIST) 2505 { 2506 listitem_T *li; 2507 list_T *l; 2508 long idx; 2509 2510 if ((l = argvars[0].vval.v_list) != NULL) 2511 { 2512 CHECK_LIST_MATERIALIZE(l); 2513 li = l->lv_first; 2514 if (argvars[2].v_type != VAR_UNKNOWN) 2515 { 2516 if (argvars[3].v_type != VAR_UNKNOWN) 2517 { 2518 idx = (long)tv_get_number_chk(&argvars[3], &error); 2519 if (!error) 2520 { 2521 li = list_find(l, idx); 2522 if (li == NULL) 2523 semsg(_(e_listidx), idx); 2524 } 2525 } 2526 if (error) 2527 li = NULL; 2528 } 2529 2530 for ( ; li != NULL; li = li->li_next) 2531 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE)) 2532 ++n; 2533 } 2534 } 2535 else if (argvars[0].v_type == VAR_DICT) 2536 { 2537 int todo; 2538 dict_T *d; 2539 hashitem_T *hi; 2540 2541 if ((d = argvars[0].vval.v_dict) != NULL) 2542 { 2543 if (argvars[2].v_type != VAR_UNKNOWN) 2544 { 2545 if (argvars[3].v_type != VAR_UNKNOWN) 2546 emsg(_(e_invarg)); 2547 } 2548 2549 todo = error ? 0 : (int)d->dv_hashtab.ht_used; 2550 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) 2551 { 2552 if (!HASHITEM_EMPTY(hi)) 2553 { 2554 --todo; 2555 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE)) 2556 ++n; 2557 } 2558 } 2559 } 2560 } 2561 else 2562 semsg(_(e_listdictarg), "count()"); 2563 rettv->vval.v_number = n; 2564 } 2565 2566 /* 2567 * "extend()" or "extendnew()" function. "is_new" is TRUE for extendnew(). 2568 */ 2569 static void 2570 extend(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg, int is_new) 2571 { 2572 type_T *type = NULL; 2573 garray_T type_list; 2574 2575 if (!is_new && in_vim9script()) 2576 { 2577 // Check that map() does not change the type of the dict. 2578 ga_init2(&type_list, sizeof(type_T *), 10); 2579 type = typval2type(argvars, get_copyID(), &type_list, TRUE); 2580 } 2581 2582 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) 2583 { 2584 list_T *l1, *l2; 2585 listitem_T *item; 2586 long before; 2587 int error = FALSE; 2588 2589 l1 = argvars[0].vval.v_list; 2590 if (l1 == NULL) 2591 { 2592 emsg(_(e_cannot_extend_null_list)); 2593 goto theend; 2594 } 2595 l2 = argvars[1].vval.v_list; 2596 if ((is_new || !value_check_lock(l1->lv_lock, arg_errmsg, TRUE)) 2597 && l2 != NULL) 2598 { 2599 if (is_new) 2600 { 2601 l1 = list_copy(l1, FALSE, get_copyID()); 2602 if (l1 == NULL) 2603 goto theend; 2604 } 2605 2606 if (argvars[2].v_type != VAR_UNKNOWN) 2607 { 2608 before = (long)tv_get_number_chk(&argvars[2], &error); 2609 if (error) 2610 goto theend; // type error; errmsg already given 2611 2612 if (before == l1->lv_len) 2613 item = NULL; 2614 else 2615 { 2616 item = list_find(l1, before); 2617 if (item == NULL) 2618 { 2619 semsg(_(e_listidx), before); 2620 goto theend; 2621 } 2622 } 2623 } 2624 else 2625 item = NULL; 2626 if (type != NULL && check_typval_arg_type( 2627 type, &argvars[1], 2) == FAIL) 2628 goto theend; 2629 list_extend(l1, l2, item); 2630 2631 if (is_new) 2632 { 2633 rettv->v_type = VAR_LIST; 2634 rettv->vval.v_list = l1; 2635 rettv->v_lock = FALSE; 2636 } 2637 else 2638 copy_tv(&argvars[0], rettv); 2639 } 2640 } 2641 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) 2642 { 2643 dict_T *d1, *d2; 2644 char_u *action; 2645 int i; 2646 2647 d1 = argvars[0].vval.v_dict; 2648 if (d1 == NULL) 2649 { 2650 emsg(_(e_cannot_extend_null_dict)); 2651 goto theend; 2652 } 2653 d2 = argvars[1].vval.v_dict; 2654 if ((is_new || !value_check_lock(d1->dv_lock, arg_errmsg, TRUE)) 2655 && d2 != NULL) 2656 { 2657 if (is_new) 2658 { 2659 d1 = dict_copy(d1, FALSE, get_copyID()); 2660 if (d1 == NULL) 2661 goto theend; 2662 } 2663 2664 // Check the third argument. 2665 if (argvars[2].v_type != VAR_UNKNOWN) 2666 { 2667 static char *(av[]) = {"keep", "force", "error"}; 2668 2669 action = tv_get_string_chk(&argvars[2]); 2670 if (action == NULL) 2671 goto theend; // type error; errmsg already given 2672 for (i = 0; i < 3; ++i) 2673 if (STRCMP(action, av[i]) == 0) 2674 break; 2675 if (i == 3) 2676 { 2677 semsg(_(e_invarg2), action); 2678 goto theend; 2679 } 2680 } 2681 else 2682 action = (char_u *)"force"; 2683 2684 if (type != NULL && check_typval_arg_type( 2685 type, &argvars[1], 2) == FAIL) 2686 goto theend; 2687 dict_extend(d1, d2, action); 2688 2689 if (is_new) 2690 { 2691 rettv->v_type = VAR_DICT; 2692 rettv->vval.v_dict = d1; 2693 rettv->v_lock = FALSE; 2694 } 2695 else 2696 copy_tv(&argvars[0], rettv); 2697 } 2698 } 2699 else 2700 semsg(_(e_listdictarg), is_new ? "extendnew()" : "extend()"); 2701 2702 theend: 2703 if (type != NULL) 2704 clear_type_list(&type_list); 2705 } 2706 2707 /* 2708 * "extend(list, list [, idx])" function 2709 * "extend(dict, dict [, action])" function 2710 */ 2711 void 2712 f_extend(typval_T *argvars, typval_T *rettv) 2713 { 2714 char_u *errmsg = (char_u *)N_("extend() argument"); 2715 2716 extend(argvars, rettv, errmsg, FALSE); 2717 } 2718 2719 /* 2720 * "extendnew(list, list [, idx])" function 2721 * "extendnew(dict, dict [, action])" function 2722 */ 2723 void 2724 f_extendnew(typval_T *argvars, typval_T *rettv) 2725 { 2726 char_u *errmsg = (char_u *)N_("extendnew() argument"); 2727 2728 extend(argvars, rettv, errmsg, TRUE); 2729 } 2730 2731 /* 2732 * "insert()" function 2733 */ 2734 void 2735 f_insert(typval_T *argvars, typval_T *rettv) 2736 { 2737 long before = 0; 2738 listitem_T *item; 2739 int error = FALSE; 2740 2741 if (argvars[0].v_type == VAR_BLOB) 2742 { 2743 int val, len; 2744 char_u *p; 2745 2746 if (argvars[0].vval.v_blob == NULL) 2747 { 2748 if (in_vim9script()) 2749 emsg(_(e_cannot_add_to_null_blob)); 2750 return; 2751 } 2752 2753 len = blob_len(argvars[0].vval.v_blob); 2754 if (argvars[2].v_type != VAR_UNKNOWN) 2755 { 2756 before = (long)tv_get_number_chk(&argvars[2], &error); 2757 if (error) 2758 return; // type error; errmsg already given 2759 if (before < 0 || before > len) 2760 { 2761 semsg(_(e_invarg2), tv_get_string(&argvars[2])); 2762 return; 2763 } 2764 } 2765 val = tv_get_number_chk(&argvars[1], &error); 2766 if (error) 2767 return; 2768 if (val < 0 || val > 255) 2769 { 2770 semsg(_(e_invarg2), tv_get_string(&argvars[1])); 2771 return; 2772 } 2773 2774 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL) 2775 return; 2776 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data; 2777 mch_memmove(p + before + 1, p + before, (size_t)len - before); 2778 *(p + before) = val; 2779 ++argvars[0].vval.v_blob->bv_ga.ga_len; 2780 2781 copy_tv(&argvars[0], rettv); 2782 } 2783 else if (argvars[0].v_type != VAR_LIST) 2784 semsg(_(e_listblobarg), "insert()"); 2785 else 2786 { 2787 list_T *l = argvars[0].vval.v_list; 2788 2789 if (l == NULL) 2790 { 2791 if (in_vim9script()) 2792 emsg(_(e_cannot_add_to_null_list)); 2793 } 2794 else if (!value_check_lock(l->lv_lock, 2795 (char_u *)N_("insert() argument"), TRUE)) 2796 { 2797 if (argvars[2].v_type != VAR_UNKNOWN) 2798 before = (long)tv_get_number_chk(&argvars[2], &error); 2799 if (error) 2800 return; // type error; errmsg already given 2801 2802 if (before == l->lv_len) 2803 item = NULL; 2804 else 2805 { 2806 item = list_find(l, before); 2807 if (item == NULL) 2808 { 2809 semsg(_(e_listidx), before); 2810 l = NULL; 2811 } 2812 } 2813 if (l != NULL) 2814 { 2815 (void)list_insert_tv(l, &argvars[1], item); 2816 copy_tv(&argvars[0], rettv); 2817 } 2818 } 2819 } 2820 } 2821 2822 /* 2823 * "remove()" function 2824 */ 2825 void 2826 f_remove(typval_T *argvars, typval_T *rettv) 2827 { 2828 char_u *arg_errmsg = (char_u *)N_("remove() argument"); 2829 2830 if (argvars[0].v_type == VAR_DICT) 2831 dict_remove(argvars, rettv, arg_errmsg); 2832 else if (argvars[0].v_type == VAR_BLOB) 2833 blob_remove(argvars, rettv); 2834 else if (argvars[0].v_type == VAR_LIST) 2835 list_remove(argvars, rettv, arg_errmsg); 2836 else 2837 semsg(_(e_listdictblobarg), "remove()"); 2838 } 2839 2840 /* 2841 * "reverse({list})" function 2842 */ 2843 void 2844 f_reverse(typval_T *argvars, typval_T *rettv) 2845 { 2846 list_T *l; 2847 listitem_T *li, *ni; 2848 2849 if (argvars[0].v_type == VAR_BLOB) 2850 { 2851 blob_T *b = argvars[0].vval.v_blob; 2852 int i, len = blob_len(b); 2853 2854 for (i = 0; i < len / 2; i++) 2855 { 2856 int tmp = blob_get(b, i); 2857 2858 blob_set(b, i, blob_get(b, len - i - 1)); 2859 blob_set(b, len - i - 1, tmp); 2860 } 2861 rettv_blob_set(rettv, b); 2862 return; 2863 } 2864 2865 if (argvars[0].v_type != VAR_LIST) 2866 semsg(_(e_listblobarg), "reverse()"); 2867 else if ((l = argvars[0].vval.v_list) != NULL 2868 && !value_check_lock(l->lv_lock, 2869 (char_u *)N_("reverse() argument"), TRUE)) 2870 { 2871 if (l->lv_first == &range_list_item) 2872 { 2873 varnumber_T new_start = l->lv_u.nonmat.lv_start 2874 + (l->lv_len - 1) * l->lv_u.nonmat.lv_stride; 2875 l->lv_u.nonmat.lv_end = new_start 2876 - (l->lv_u.nonmat.lv_end - l->lv_u.nonmat.lv_start); 2877 l->lv_u.nonmat.lv_start = new_start; 2878 l->lv_u.nonmat.lv_stride = -l->lv_u.nonmat.lv_stride; 2879 rettv_list_set(rettv, l); 2880 return; 2881 } 2882 li = l->lv_u.mat.lv_last; 2883 l->lv_first = l->lv_u.mat.lv_last = NULL; 2884 l->lv_len = 0; 2885 while (li != NULL) 2886 { 2887 ni = li->li_prev; 2888 list_append(l, li); 2889 li = ni; 2890 } 2891 rettv_list_set(rettv, l); 2892 l->lv_u.mat.lv_idx = l->lv_len - l->lv_u.mat.lv_idx - 1; 2893 } 2894 } 2895 2896 /* 2897 * "reduce(list, { accumulator, element -> value } [, initial])" function 2898 */ 2899 void 2900 f_reduce(typval_T *argvars, typval_T *rettv) 2901 { 2902 typval_T initial; 2903 char_u *func_name; 2904 partial_T *partial = NULL; 2905 funcexe_T funcexe; 2906 typval_T argv[3]; 2907 2908 if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) 2909 { 2910 emsg(_(e_listblobreq)); 2911 return; 2912 } 2913 2914 if (argvars[1].v_type == VAR_FUNC) 2915 func_name = argvars[1].vval.v_string; 2916 else if (argvars[1].v_type == VAR_PARTIAL) 2917 { 2918 partial = argvars[1].vval.v_partial; 2919 func_name = partial_name(partial); 2920 } 2921 else 2922 func_name = tv_get_string(&argvars[1]); 2923 if (func_name == NULL || *func_name == NUL) 2924 { 2925 emsg(_(e_missing_function_argument)); 2926 return; 2927 } 2928 2929 vim_memset(&funcexe, 0, sizeof(funcexe)); 2930 funcexe.evaluate = TRUE; 2931 funcexe.partial = partial; 2932 2933 if (argvars[0].v_type == VAR_LIST) 2934 { 2935 list_T *l = argvars[0].vval.v_list; 2936 listitem_T *li = NULL; 2937 int r; 2938 int called_emsg_start = called_emsg; 2939 2940 if (l != NULL) 2941 CHECK_LIST_MATERIALIZE(l); 2942 if (argvars[2].v_type == VAR_UNKNOWN) 2943 { 2944 if (l == NULL || l->lv_first == NULL) 2945 { 2946 semsg(_(e_reduceempty), "List"); 2947 return; 2948 } 2949 initial = l->lv_first->li_tv; 2950 li = l->lv_first->li_next; 2951 } 2952 else 2953 { 2954 initial = argvars[2]; 2955 if (l != NULL) 2956 li = l->lv_first; 2957 } 2958 copy_tv(&initial, rettv); 2959 2960 if (l != NULL) 2961 { 2962 int prev_locked = l->lv_lock; 2963 2964 l->lv_lock = VAR_FIXED; // disallow the list changing here 2965 for ( ; li != NULL; li = li->li_next) 2966 { 2967 argv[0] = *rettv; 2968 argv[1] = li->li_tv; 2969 rettv->v_type = VAR_UNKNOWN; 2970 r = call_func(func_name, -1, rettv, 2, argv, &funcexe); 2971 clear_tv(&argv[0]); 2972 if (r == FAIL || called_emsg != called_emsg_start) 2973 break; 2974 } 2975 l->lv_lock = prev_locked; 2976 } 2977 } 2978 else 2979 { 2980 blob_T *b = argvars[0].vval.v_blob; 2981 int i; 2982 2983 if (argvars[2].v_type == VAR_UNKNOWN) 2984 { 2985 if (b == NULL || b->bv_ga.ga_len == 0) 2986 { 2987 semsg(_(e_reduceempty), "Blob"); 2988 return; 2989 } 2990 initial.v_type = VAR_NUMBER; 2991 initial.vval.v_number = blob_get(b, 0); 2992 i = 1; 2993 } 2994 else if (argvars[2].v_type != VAR_NUMBER) 2995 { 2996 emsg(_(e_number_exp)); 2997 return; 2998 } 2999 else 3000 { 3001 initial = argvars[2]; 3002 i = 0; 3003 } 3004 3005 copy_tv(&initial, rettv); 3006 if (b != NULL) 3007 { 3008 for ( ; i < b->bv_ga.ga_len; i++) 3009 { 3010 argv[0] = *rettv; 3011 argv[1].v_type = VAR_NUMBER; 3012 argv[1].vval.v_number = blob_get(b, i); 3013 if (call_func(func_name, -1, rettv, 2, argv, &funcexe) == FAIL) 3014 return; 3015 } 3016 } 3017 } 3018 } 3019 3020 #endif // defined(FEAT_EVAL) 3021