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 898 // NULL list is equivalent to an empty list: nothing to do. 899 if (l2 == NULL || l2->lv_len == 0) 900 return OK; 901 902 todo = l2->lv_len; 903 CHECK_LIST_MATERIALIZE(l1); 904 CHECK_LIST_MATERIALIZE(l2); 905 906 // We also quit the loop when we have inserted the original item count of 907 // the list, avoid a hang when we extend a list with itself. 908 for (item = l2->lv_first; item != NULL && --todo >= 0; item = item->li_next) 909 if (list_insert_tv(l1, &item->li_tv, bef) == FAIL) 910 return FAIL; 911 return OK; 912 } 913 914 /* 915 * Concatenate lists "l1" and "l2" into a new list, stored in "tv". 916 * Return FAIL when out of memory. 917 */ 918 int 919 list_concat(list_T *l1, list_T *l2, typval_T *tv) 920 { 921 list_T *l; 922 923 // make a copy of the first list. 924 if (l1 == NULL) 925 l = list_alloc(); 926 else 927 l = list_copy(l1, FALSE, 0); 928 if (l == NULL) 929 return FAIL; 930 tv->v_type = VAR_LIST; 931 tv->v_lock = 0; 932 tv->vval.v_list = l; 933 if (l1 == NULL) 934 ++l->lv_refcount; 935 936 // append all items from the second list 937 return list_extend(l, l2, NULL); 938 } 939 940 list_T * 941 list_slice(list_T *ol, long n1, long n2) 942 { 943 listitem_T *item; 944 list_T *l = list_alloc(); 945 946 if (l == NULL) 947 return NULL; 948 for (item = list_find(ol, n1); n1 <= n2; ++n1) 949 { 950 if (list_append_tv(l, &item->li_tv) == FAIL) 951 { 952 list_free(l); 953 return NULL; 954 } 955 item = item->li_next; 956 } 957 return l; 958 } 959 960 int 961 list_slice_or_index( 962 list_T *list, 963 int range, 964 varnumber_T n1_arg, 965 varnumber_T n2_arg, 966 int exclusive, 967 typval_T *rettv, 968 int verbose) 969 { 970 long len = list_len(list); 971 varnumber_T n1 = n1_arg; 972 varnumber_T n2 = n2_arg; 973 typval_T var1; 974 975 if (n1 < 0) 976 n1 = len + n1; 977 if (n1 < 0 || n1 >= len) 978 { 979 // For a range we allow invalid values and return an empty 980 // list. A list index out of range is an error. 981 if (!range) 982 { 983 if (verbose) 984 semsg(_(e_listidx), (long)n1_arg); 985 return FAIL; 986 } 987 n1 = n1 < 0 ? 0 : len; 988 } 989 if (range) 990 { 991 list_T *l; 992 993 if (n2 < 0) 994 n2 = len + n2; 995 else if (n2 >= len) 996 n2 = len - (exclusive ? 0 : 1); 997 if (exclusive) 998 --n2; 999 if (n2 < 0 || n2 + 1 < n1) 1000 n2 = -1; 1001 l = list_slice(list, n1, n2); 1002 if (l == NULL) 1003 return FAIL; 1004 clear_tv(rettv); 1005 rettv_list_set(rettv, l); 1006 } 1007 else 1008 { 1009 // copy the item to "var1" to avoid that freeing the list makes it 1010 // invalid. 1011 copy_tv(&list_find(list, n1)->li_tv, &var1); 1012 clear_tv(rettv); 1013 *rettv = var1; 1014 } 1015 return OK; 1016 } 1017 1018 /* 1019 * Make a copy of list "orig". Shallow if "deep" is FALSE. 1020 * The refcount of the new list is set to 1. 1021 * See item_copy() for "copyID". 1022 * Returns NULL when out of memory. 1023 */ 1024 list_T * 1025 list_copy(list_T *orig, int deep, int copyID) 1026 { 1027 list_T *copy; 1028 listitem_T *item; 1029 listitem_T *ni; 1030 1031 if (orig == NULL) 1032 return NULL; 1033 1034 copy = list_alloc(); 1035 if (copy != NULL) 1036 { 1037 if (copyID != 0) 1038 { 1039 // Do this before adding the items, because one of the items may 1040 // refer back to this list. 1041 orig->lv_copyID = copyID; 1042 orig->lv_copylist = copy; 1043 } 1044 CHECK_LIST_MATERIALIZE(orig); 1045 for (item = orig->lv_first; item != NULL && !got_int; 1046 item = item->li_next) 1047 { 1048 ni = listitem_alloc(); 1049 if (ni == NULL) 1050 break; 1051 if (deep) 1052 { 1053 if (item_copy(&item->li_tv, &ni->li_tv, deep, copyID) == FAIL) 1054 { 1055 vim_free(ni); 1056 break; 1057 } 1058 } 1059 else 1060 copy_tv(&item->li_tv, &ni->li_tv); 1061 list_append(copy, ni); 1062 } 1063 ++copy->lv_refcount; 1064 if (item != NULL) 1065 { 1066 list_unref(copy); 1067 copy = NULL; 1068 } 1069 } 1070 1071 return copy; 1072 } 1073 1074 /* 1075 * Remove items "item" to "item2" from list "l". 1076 * Does not free the listitem or the value! 1077 * This used to be called list_remove, but that conflicts with a Sun header 1078 * file. 1079 */ 1080 void 1081 vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2) 1082 { 1083 listitem_T *ip; 1084 1085 CHECK_LIST_MATERIALIZE(l); 1086 1087 // notify watchers 1088 for (ip = item; ip != NULL; ip = ip->li_next) 1089 { 1090 --l->lv_len; 1091 list_fix_watch(l, ip); 1092 if (ip == item2) 1093 break; 1094 } 1095 1096 if (item2->li_next == NULL) 1097 l->lv_u.mat.lv_last = item->li_prev; 1098 else 1099 item2->li_next->li_prev = item->li_prev; 1100 if (item->li_prev == NULL) 1101 l->lv_first = item2->li_next; 1102 else 1103 item->li_prev->li_next = item2->li_next; 1104 l->lv_u.mat.lv_idx_item = NULL; 1105 } 1106 1107 /* 1108 * Return an allocated string with the string representation of a list. 1109 * May return NULL. 1110 */ 1111 char_u * 1112 list2string(typval_T *tv, int copyID, int restore_copyID) 1113 { 1114 garray_T ga; 1115 1116 if (tv->vval.v_list == NULL) 1117 return NULL; 1118 ga_init2(&ga, (int)sizeof(char), 80); 1119 ga_append(&ga, '['); 1120 CHECK_LIST_MATERIALIZE(tv->vval.v_list); 1121 if (list_join(&ga, tv->vval.v_list, (char_u *)", ", 1122 FALSE, restore_copyID, copyID) == FAIL) 1123 { 1124 vim_free(ga.ga_data); 1125 return NULL; 1126 } 1127 ga_append(&ga, ']'); 1128 ga_append(&ga, NUL); 1129 return (char_u *)ga.ga_data; 1130 } 1131 1132 typedef struct join_S { 1133 char_u *s; 1134 char_u *tofree; 1135 } join_T; 1136 1137 static int 1138 list_join_inner( 1139 garray_T *gap, // to store the result in 1140 list_T *l, 1141 char_u *sep, 1142 int echo_style, 1143 int restore_copyID, 1144 int copyID, 1145 garray_T *join_gap) // to keep each list item string 1146 { 1147 int i; 1148 join_T *p; 1149 int len; 1150 int sumlen = 0; 1151 int first = TRUE; 1152 char_u *tofree; 1153 char_u numbuf[NUMBUFLEN]; 1154 listitem_T *item; 1155 char_u *s; 1156 1157 // Stringify each item in the list. 1158 CHECK_LIST_MATERIALIZE(l); 1159 for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) 1160 { 1161 s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID, 1162 echo_style, restore_copyID, !echo_style); 1163 if (s == NULL) 1164 return FAIL; 1165 1166 len = (int)STRLEN(s); 1167 sumlen += len; 1168 1169 (void)ga_grow(join_gap, 1); 1170 p = ((join_T *)join_gap->ga_data) + (join_gap->ga_len++); 1171 if (tofree != NULL || s != numbuf) 1172 { 1173 p->s = s; 1174 p->tofree = tofree; 1175 } 1176 else 1177 { 1178 p->s = vim_strnsave(s, len); 1179 p->tofree = p->s; 1180 } 1181 1182 line_breakcheck(); 1183 if (did_echo_string_emsg) // recursion error, bail out 1184 break; 1185 } 1186 1187 // Allocate result buffer with its total size, avoid re-allocation and 1188 // multiple copy operations. Add 2 for a tailing ']' and NUL. 1189 if (join_gap->ga_len >= 2) 1190 sumlen += (int)STRLEN(sep) * (join_gap->ga_len - 1); 1191 if (ga_grow(gap, sumlen + 2) == FAIL) 1192 return FAIL; 1193 1194 for (i = 0; i < join_gap->ga_len && !got_int; ++i) 1195 { 1196 if (first) 1197 first = FALSE; 1198 else 1199 ga_concat(gap, sep); 1200 p = ((join_T *)join_gap->ga_data) + i; 1201 1202 if (p->s != NULL) 1203 ga_concat(gap, p->s); 1204 line_breakcheck(); 1205 } 1206 1207 return OK; 1208 } 1209 1210 /* 1211 * Join list "l" into a string in "*gap", using separator "sep". 1212 * When "echo_style" is TRUE use String as echoed, otherwise as inside a List. 1213 * Return FAIL or OK. 1214 */ 1215 int 1216 list_join( 1217 garray_T *gap, 1218 list_T *l, 1219 char_u *sep, 1220 int echo_style, 1221 int restore_copyID, 1222 int copyID) 1223 { 1224 garray_T join_ga; 1225 int retval; 1226 join_T *p; 1227 int i; 1228 1229 if (l->lv_len < 1) 1230 return OK; // nothing to do 1231 ga_init2(&join_ga, (int)sizeof(join_T), l->lv_len); 1232 retval = list_join_inner(gap, l, sep, echo_style, restore_copyID, 1233 copyID, &join_ga); 1234 1235 // Dispose each item in join_ga. 1236 if (join_ga.ga_data != NULL) 1237 { 1238 p = (join_T *)join_ga.ga_data; 1239 for (i = 0; i < join_ga.ga_len; ++i) 1240 { 1241 vim_free(p->tofree); 1242 ++p; 1243 } 1244 ga_clear(&join_ga); 1245 } 1246 1247 return retval; 1248 } 1249 1250 /* 1251 * "join()" function 1252 */ 1253 void 1254 f_join(typval_T *argvars, typval_T *rettv) 1255 { 1256 garray_T ga; 1257 char_u *sep; 1258 1259 if (argvars[0].v_type != VAR_LIST) 1260 { 1261 emsg(_(e_listreq)); 1262 return; 1263 } 1264 if (argvars[0].vval.v_list == NULL) 1265 return; 1266 if (argvars[1].v_type == VAR_UNKNOWN) 1267 sep = (char_u *)" "; 1268 else 1269 sep = tv_get_string_chk(&argvars[1]); 1270 1271 rettv->v_type = VAR_STRING; 1272 1273 if (sep != NULL) 1274 { 1275 ga_init2(&ga, (int)sizeof(char), 80); 1276 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0); 1277 ga_append(&ga, NUL); 1278 rettv->vval.v_string = (char_u *)ga.ga_data; 1279 } 1280 else 1281 rettv->vval.v_string = NULL; 1282 } 1283 1284 /* 1285 * Allocate a variable for a List and fill it from "*arg". 1286 * "*arg" points to the "[". 1287 * Return OK or FAIL. 1288 */ 1289 int 1290 eval_list(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int do_error) 1291 { 1292 int evaluate = evalarg == NULL ? FALSE 1293 : evalarg->eval_flags & EVAL_EVALUATE; 1294 list_T *l = NULL; 1295 typval_T tv; 1296 listitem_T *item; 1297 int vim9script = in_vim9script(); 1298 int had_comma; 1299 1300 if (evaluate) 1301 { 1302 l = list_alloc(); 1303 if (l == NULL) 1304 return FAIL; 1305 } 1306 1307 *arg = skipwhite_and_linebreak(*arg + 1, evalarg); 1308 while (**arg != ']' && **arg != NUL) 1309 { 1310 if (eval1(arg, &tv, evalarg) == FAIL) // recursive! 1311 goto failret; 1312 if (evaluate) 1313 { 1314 item = listitem_alloc(); 1315 if (item != NULL) 1316 { 1317 item->li_tv = tv; 1318 item->li_tv.v_lock = 0; 1319 list_append(l, item); 1320 } 1321 else 1322 clear_tv(&tv); 1323 } 1324 // Legacy Vim script allowed a space before the comma. 1325 if (!vim9script) 1326 *arg = skipwhite(*arg); 1327 1328 // the comma must come after the value 1329 had_comma = **arg == ','; 1330 if (had_comma) 1331 { 1332 if (vim9script && !IS_WHITE_OR_NUL((*arg)[1]) && (*arg)[1] != ']') 1333 { 1334 semsg(_(e_white_space_required_after_str_str), ",", *arg); 1335 goto failret; 1336 } 1337 *arg = skipwhite(*arg + 1); 1338 } 1339 1340 // The "]" can be on the next line. But a double quoted string may 1341 // follow, not a comment. 1342 *arg = skipwhite_and_linebreak(*arg, evalarg); 1343 if (**arg == ']') 1344 break; 1345 1346 if (!had_comma) 1347 { 1348 if (do_error) 1349 { 1350 if (**arg == ',') 1351 semsg(_(e_no_white_space_allowed_before_str_str), 1352 ",", *arg); 1353 else 1354 semsg(_("E696: Missing comma in List: %s"), *arg); 1355 } 1356 goto failret; 1357 } 1358 } 1359 1360 if (**arg != ']') 1361 { 1362 if (do_error) 1363 semsg(_(e_list_end), *arg); 1364 failret: 1365 if (evaluate) 1366 list_free(l); 1367 return FAIL; 1368 } 1369 1370 *arg += 1; 1371 if (evaluate) 1372 rettv_list_set(rettv, l); 1373 1374 return OK; 1375 } 1376 1377 /* 1378 * Write "list" of strings to file "fd". 1379 */ 1380 int 1381 write_list(FILE *fd, list_T *list, int binary) 1382 { 1383 listitem_T *li; 1384 int c; 1385 int ret = OK; 1386 char_u *s; 1387 1388 CHECK_LIST_MATERIALIZE(list); 1389 FOR_ALL_LIST_ITEMS(list, li) 1390 { 1391 for (s = tv_get_string(&li->li_tv); *s != NUL; ++s) 1392 { 1393 if (*s == '\n') 1394 c = putc(NUL, fd); 1395 else 1396 c = putc(*s, fd); 1397 if (c == EOF) 1398 { 1399 ret = FAIL; 1400 break; 1401 } 1402 } 1403 if (!binary || li->li_next != NULL) 1404 if (putc('\n', fd) == EOF) 1405 { 1406 ret = FAIL; 1407 break; 1408 } 1409 if (ret == FAIL) 1410 { 1411 emsg(_(e_write)); 1412 break; 1413 } 1414 } 1415 return ret; 1416 } 1417 1418 /* 1419 * Initialize a static list with 10 items. 1420 */ 1421 void 1422 init_static_list(staticList10_T *sl) 1423 { 1424 list_T *l = &sl->sl_list; 1425 int i; 1426 1427 memset(sl, 0, sizeof(staticList10_T)); 1428 l->lv_first = &sl->sl_items[0]; 1429 l->lv_u.mat.lv_last = &sl->sl_items[9]; 1430 l->lv_refcount = DO_NOT_FREE_CNT; 1431 l->lv_lock = VAR_FIXED; 1432 sl->sl_list.lv_len = 10; 1433 1434 for (i = 0; i < 10; ++i) 1435 { 1436 listitem_T *li = &sl->sl_items[i]; 1437 1438 if (i == 0) 1439 li->li_prev = NULL; 1440 else 1441 li->li_prev = li - 1; 1442 if (i == 9) 1443 li->li_next = NULL; 1444 else 1445 li->li_next = li + 1; 1446 } 1447 } 1448 1449 /* 1450 * "list2str()" function 1451 */ 1452 void 1453 f_list2str(typval_T *argvars, typval_T *rettv) 1454 { 1455 list_T *l; 1456 listitem_T *li; 1457 garray_T ga; 1458 int utf8 = FALSE; 1459 1460 rettv->v_type = VAR_STRING; 1461 rettv->vval.v_string = NULL; 1462 if (argvars[0].v_type != VAR_LIST) 1463 { 1464 emsg(_(e_invarg)); 1465 return; 1466 } 1467 1468 l = argvars[0].vval.v_list; 1469 if (l == NULL) 1470 return; // empty list results in empty string 1471 1472 if (argvars[1].v_type != VAR_UNKNOWN) 1473 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL); 1474 1475 CHECK_LIST_MATERIALIZE(l); 1476 ga_init2(&ga, 1, 80); 1477 if (has_mbyte || utf8) 1478 { 1479 char_u buf[MB_MAXBYTES + 1]; 1480 int (*char2bytes)(int, char_u *); 1481 1482 if (utf8 || enc_utf8) 1483 char2bytes = utf_char2bytes; 1484 else 1485 char2bytes = mb_char2bytes; 1486 1487 FOR_ALL_LIST_ITEMS(l, li) 1488 { 1489 buf[(*char2bytes)(tv_get_number(&li->li_tv), buf)] = NUL; 1490 ga_concat(&ga, buf); 1491 } 1492 ga_append(&ga, NUL); 1493 } 1494 else if (ga_grow(&ga, list_len(l) + 1) == OK) 1495 { 1496 FOR_ALL_LIST_ITEMS(l, li) 1497 ga_append(&ga, tv_get_number(&li->li_tv)); 1498 ga_append(&ga, NUL); 1499 } 1500 1501 rettv->v_type = VAR_STRING; 1502 rettv->vval.v_string = ga.ga_data; 1503 } 1504 1505 static void 1506 list_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg) 1507 { 1508 list_T *l; 1509 listitem_T *item, *item2; 1510 listitem_T *li; 1511 int error = FALSE; 1512 long idx; 1513 1514 if ((l = argvars[0].vval.v_list) == NULL 1515 || value_check_lock(l->lv_lock, arg_errmsg, TRUE)) 1516 return; 1517 1518 idx = (long)tv_get_number_chk(&argvars[1], &error); 1519 if (error) 1520 ; // type error: do nothing, errmsg already given 1521 else if ((item = list_find(l, idx)) == NULL) 1522 semsg(_(e_listidx), idx); 1523 else 1524 { 1525 if (argvars[2].v_type == VAR_UNKNOWN) 1526 { 1527 // Remove one item, return its value. 1528 vimlist_remove(l, item, item); 1529 *rettv = item->li_tv; 1530 list_free_item(l, item); 1531 } 1532 else 1533 { 1534 // Remove range of items, return list with values. 1535 long end = (long)tv_get_number_chk(&argvars[2], &error); 1536 1537 if (error) 1538 ; // type error: do nothing 1539 else if ((item2 = list_find(l, end)) == NULL) 1540 semsg(_(e_listidx), end); 1541 else 1542 { 1543 int cnt = 0; 1544 1545 for (li = item; li != NULL; li = li->li_next) 1546 { 1547 ++cnt; 1548 if (li == item2) 1549 break; 1550 } 1551 if (li == NULL) // didn't find "item2" after "item" 1552 emsg(_(e_invrange)); 1553 else 1554 { 1555 vimlist_remove(l, item, item2); 1556 if (rettv_list_alloc(rettv) == OK) 1557 { 1558 l = rettv->vval.v_list; 1559 l->lv_first = item; 1560 l->lv_u.mat.lv_last = item2; 1561 item->li_prev = NULL; 1562 item2->li_next = NULL; 1563 l->lv_len = cnt; 1564 } 1565 } 1566 } 1567 } 1568 } 1569 } 1570 1571 static int item_compare(const void *s1, const void *s2); 1572 static int item_compare2(const void *s1, const void *s2); 1573 1574 // struct used in the array that's given to qsort() 1575 typedef struct 1576 { 1577 listitem_T *item; 1578 int idx; 1579 } sortItem_T; 1580 1581 // struct storing information about current sort 1582 typedef struct 1583 { 1584 int item_compare_ic; 1585 int item_compare_lc; 1586 int item_compare_numeric; 1587 int item_compare_numbers; 1588 #ifdef FEAT_FLOAT 1589 int item_compare_float; 1590 #endif 1591 char_u *item_compare_func; 1592 partial_T *item_compare_partial; 1593 dict_T *item_compare_selfdict; 1594 int item_compare_func_err; 1595 int item_compare_keep_zero; 1596 } sortinfo_T; 1597 static sortinfo_T *sortinfo = NULL; 1598 #define ITEM_COMPARE_FAIL 999 1599 1600 /* 1601 * Compare functions for f_sort() and f_uniq() below. 1602 */ 1603 static int 1604 item_compare(const void *s1, const void *s2) 1605 { 1606 sortItem_T *si1, *si2; 1607 typval_T *tv1, *tv2; 1608 char_u *p1, *p2; 1609 char_u *tofree1 = NULL, *tofree2 = NULL; 1610 int res; 1611 char_u numbuf1[NUMBUFLEN]; 1612 char_u numbuf2[NUMBUFLEN]; 1613 1614 si1 = (sortItem_T *)s1; 1615 si2 = (sortItem_T *)s2; 1616 tv1 = &si1->item->li_tv; 1617 tv2 = &si2->item->li_tv; 1618 1619 if (sortinfo->item_compare_numbers) 1620 { 1621 varnumber_T v1 = tv_get_number(tv1); 1622 varnumber_T v2 = tv_get_number(tv2); 1623 1624 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; 1625 } 1626 1627 #ifdef FEAT_FLOAT 1628 if (sortinfo->item_compare_float) 1629 { 1630 float_T v1 = tv_get_float(tv1); 1631 float_T v2 = tv_get_float(tv2); 1632 1633 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; 1634 } 1635 #endif 1636 1637 // tv2string() puts quotes around a string and allocates memory. Don't do 1638 // that for string variables. Use a single quote when comparing with a 1639 // non-string to do what the docs promise. 1640 if (tv1->v_type == VAR_STRING) 1641 { 1642 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) 1643 p1 = (char_u *)"'"; 1644 else 1645 p1 = tv1->vval.v_string; 1646 } 1647 else 1648 p1 = tv2string(tv1, &tofree1, numbuf1, 0); 1649 if (tv2->v_type == VAR_STRING) 1650 { 1651 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) 1652 p2 = (char_u *)"'"; 1653 else 1654 p2 = tv2->vval.v_string; 1655 } 1656 else 1657 p2 = tv2string(tv2, &tofree2, numbuf2, 0); 1658 if (p1 == NULL) 1659 p1 = (char_u *)""; 1660 if (p2 == NULL) 1661 p2 = (char_u *)""; 1662 if (!sortinfo->item_compare_numeric) 1663 { 1664 if (sortinfo->item_compare_lc) 1665 res = strcoll((char *)p1, (char *)p2); 1666 else 1667 res = sortinfo->item_compare_ic ? STRICMP(p1, p2): STRCMP(p1, p2); 1668 } 1669 else 1670 { 1671 double n1, n2; 1672 n1 = strtod((char *)p1, (char **)&p1); 1673 n2 = strtod((char *)p2, (char **)&p2); 1674 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1; 1675 } 1676 1677 // When the result would be zero, compare the item indexes. Makes the 1678 // sort stable. 1679 if (res == 0 && !sortinfo->item_compare_keep_zero) 1680 res = si1->idx > si2->idx ? 1 : -1; 1681 1682 vim_free(tofree1); 1683 vim_free(tofree2); 1684 return res; 1685 } 1686 1687 static int 1688 item_compare2(const void *s1, const void *s2) 1689 { 1690 sortItem_T *si1, *si2; 1691 int res; 1692 typval_T rettv; 1693 typval_T argv[3]; 1694 char_u *func_name; 1695 partial_T *partial = sortinfo->item_compare_partial; 1696 funcexe_T funcexe; 1697 1698 // shortcut after failure in previous call; compare all items equal 1699 if (sortinfo->item_compare_func_err) 1700 return 0; 1701 1702 si1 = (sortItem_T *)s1; 1703 si2 = (sortItem_T *)s2; 1704 1705 if (partial == NULL) 1706 func_name = sortinfo->item_compare_func; 1707 else 1708 func_name = partial_name(partial); 1709 1710 // Copy the values. This is needed to be able to set v_lock to VAR_FIXED 1711 // in the copy without changing the original list items. 1712 copy_tv(&si1->item->li_tv, &argv[0]); 1713 copy_tv(&si2->item->li_tv, &argv[1]); 1714 1715 rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this 1716 CLEAR_FIELD(funcexe); 1717 funcexe.evaluate = TRUE; 1718 funcexe.partial = partial; 1719 funcexe.selfdict = sortinfo->item_compare_selfdict; 1720 res = call_func(func_name, -1, &rettv, 2, argv, &funcexe); 1721 clear_tv(&argv[0]); 1722 clear_tv(&argv[1]); 1723 1724 if (res == FAIL) 1725 res = ITEM_COMPARE_FAIL; 1726 else 1727 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err); 1728 if (sortinfo->item_compare_func_err) 1729 res = ITEM_COMPARE_FAIL; // return value has wrong type 1730 clear_tv(&rettv); 1731 1732 // When the result would be zero, compare the pointers themselves. Makes 1733 // the sort stable. 1734 if (res == 0 && !sortinfo->item_compare_keep_zero) 1735 res = si1->idx > si2->idx ? 1 : -1; 1736 1737 return res; 1738 } 1739 1740 /* 1741 * "sort()" or "uniq()" function 1742 */ 1743 static void 1744 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) 1745 { 1746 list_T *l; 1747 listitem_T *li; 1748 sortItem_T *ptrs; 1749 sortinfo_T *old_sortinfo; 1750 sortinfo_T info; 1751 long len; 1752 long i; 1753 1754 // Pointer to current info struct used in compare function. Save and 1755 // restore the current one for nested calls. 1756 old_sortinfo = sortinfo; 1757 sortinfo = &info; 1758 1759 if (argvars[0].v_type != VAR_LIST) 1760 semsg(_(e_listarg), sort ? "sort()" : "uniq()"); 1761 else 1762 { 1763 l = argvars[0].vval.v_list; 1764 if (l == NULL || value_check_lock(l->lv_lock, 1765 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")), 1766 TRUE)) 1767 goto theend; 1768 rettv_list_set(rettv, l); 1769 CHECK_LIST_MATERIALIZE(l); 1770 1771 len = list_len(l); 1772 if (len <= 1) 1773 goto theend; // short list sorts pretty quickly 1774 1775 info.item_compare_ic = FALSE; 1776 info.item_compare_lc = FALSE; 1777 info.item_compare_numeric = FALSE; 1778 info.item_compare_numbers = FALSE; 1779 #ifdef FEAT_FLOAT 1780 info.item_compare_float = FALSE; 1781 #endif 1782 info.item_compare_func = NULL; 1783 info.item_compare_partial = NULL; 1784 info.item_compare_selfdict = NULL; 1785 if (argvars[1].v_type != VAR_UNKNOWN) 1786 { 1787 // optional second argument: {func} 1788 if (argvars[1].v_type == VAR_FUNC) 1789 info.item_compare_func = argvars[1].vval.v_string; 1790 else if (argvars[1].v_type == VAR_PARTIAL) 1791 info.item_compare_partial = argvars[1].vval.v_partial; 1792 else 1793 { 1794 int error = FALSE; 1795 int nr = 0; 1796 1797 if (argvars[1].v_type == VAR_NUMBER) 1798 { 1799 nr = tv_get_number_chk(&argvars[1], &error); 1800 if (error) 1801 goto theend; // type error; errmsg already given 1802 if (nr == 1) 1803 info.item_compare_ic = TRUE; 1804 } 1805 if (nr != 1) 1806 { 1807 if (argvars[1].v_type != VAR_NUMBER) 1808 info.item_compare_func = tv_get_string(&argvars[1]); 1809 else if (nr != 0) 1810 { 1811 emsg(_(e_invarg)); 1812 goto theend; 1813 } 1814 } 1815 if (info.item_compare_func != NULL) 1816 { 1817 if (*info.item_compare_func == NUL) 1818 { 1819 // empty string means default sort 1820 info.item_compare_func = NULL; 1821 } 1822 else if (STRCMP(info.item_compare_func, "n") == 0) 1823 { 1824 info.item_compare_func = NULL; 1825 info.item_compare_numeric = TRUE; 1826 } 1827 else if (STRCMP(info.item_compare_func, "N") == 0) 1828 { 1829 info.item_compare_func = NULL; 1830 info.item_compare_numbers = TRUE; 1831 } 1832 #ifdef FEAT_FLOAT 1833 else if (STRCMP(info.item_compare_func, "f") == 0) 1834 { 1835 info.item_compare_func = NULL; 1836 info.item_compare_float = TRUE; 1837 } 1838 #endif 1839 else if (STRCMP(info.item_compare_func, "i") == 0) 1840 { 1841 info.item_compare_func = NULL; 1842 info.item_compare_ic = TRUE; 1843 } 1844 else if (STRCMP(info.item_compare_func, "l") == 0) 1845 { 1846 info.item_compare_func = NULL; 1847 info.item_compare_lc = TRUE; 1848 } 1849 } 1850 } 1851 1852 if (argvars[2].v_type != VAR_UNKNOWN) 1853 { 1854 // optional third argument: {dict} 1855 if (argvars[2].v_type != VAR_DICT) 1856 { 1857 emsg(_(e_dictreq)); 1858 goto theend; 1859 } 1860 info.item_compare_selfdict = argvars[2].vval.v_dict; 1861 } 1862 } 1863 1864 // Make an array with each entry pointing to an item in the List. 1865 ptrs = ALLOC_MULT(sortItem_T, len); 1866 if (ptrs == NULL) 1867 goto theend; 1868 1869 i = 0; 1870 if (sort) 1871 { 1872 // sort(): ptrs will be the list to sort 1873 FOR_ALL_LIST_ITEMS(l, li) 1874 { 1875 ptrs[i].item = li; 1876 ptrs[i].idx = i; 1877 ++i; 1878 } 1879 1880 info.item_compare_func_err = FALSE; 1881 info.item_compare_keep_zero = FALSE; 1882 // test the compare function 1883 if ((info.item_compare_func != NULL 1884 || info.item_compare_partial != NULL) 1885 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1]) 1886 == ITEM_COMPARE_FAIL) 1887 emsg(_("E702: Sort compare function failed")); 1888 else 1889 { 1890 // Sort the array with item pointers. 1891 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T), 1892 info.item_compare_func == NULL 1893 && info.item_compare_partial == NULL 1894 ? item_compare : item_compare2); 1895 1896 if (!info.item_compare_func_err) 1897 { 1898 // Clear the List and append the items in sorted order. 1899 l->lv_first = l->lv_u.mat.lv_last 1900 = l->lv_u.mat.lv_idx_item = NULL; 1901 l->lv_len = 0; 1902 for (i = 0; i < len; ++i) 1903 list_append(l, ptrs[i].item); 1904 } 1905 } 1906 } 1907 else 1908 { 1909 int (*item_compare_func_ptr)(const void *, const void *); 1910 1911 // f_uniq(): ptrs will be a stack of items to remove 1912 info.item_compare_func_err = FALSE; 1913 info.item_compare_keep_zero = TRUE; 1914 item_compare_func_ptr = info.item_compare_func != NULL 1915 || info.item_compare_partial != NULL 1916 ? item_compare2 : item_compare; 1917 1918 for (li = l->lv_first; li != NULL && li->li_next != NULL; 1919 li = li->li_next) 1920 { 1921 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next) 1922 == 0) 1923 ptrs[i++].item = li; 1924 if (info.item_compare_func_err) 1925 { 1926 emsg(_("E882: Uniq compare function failed")); 1927 break; 1928 } 1929 } 1930 1931 if (!info.item_compare_func_err) 1932 { 1933 while (--i >= 0) 1934 { 1935 li = ptrs[i].item->li_next; 1936 ptrs[i].item->li_next = li->li_next; 1937 if (li->li_next != NULL) 1938 li->li_next->li_prev = ptrs[i].item; 1939 else 1940 l->lv_u.mat.lv_last = ptrs[i].item; 1941 list_fix_watch(l, li); 1942 listitem_free(l, li); 1943 l->lv_len--; 1944 } 1945 } 1946 } 1947 1948 vim_free(ptrs); 1949 } 1950 theend: 1951 sortinfo = old_sortinfo; 1952 } 1953 1954 /* 1955 * "sort({list})" function 1956 */ 1957 void 1958 f_sort(typval_T *argvars, typval_T *rettv) 1959 { 1960 do_sort_uniq(argvars, rettv, TRUE); 1961 } 1962 1963 /* 1964 * "uniq({list})" function 1965 */ 1966 void 1967 f_uniq(typval_T *argvars, typval_T *rettv) 1968 { 1969 do_sort_uniq(argvars, rettv, FALSE); 1970 } 1971 1972 typedef enum { 1973 FILTERMAP_FILTER, 1974 FILTERMAP_MAP, 1975 FILTERMAP_MAPNEW 1976 } filtermap_T; 1977 1978 /* 1979 * Handle one item for map() and filter(). 1980 * Sets v:val to "tv". Caller must set v:key. 1981 */ 1982 static int 1983 filter_map_one( 1984 typval_T *tv, // original value 1985 typval_T *expr, // callback 1986 filtermap_T filtermap, 1987 typval_T *newtv, // for map() and mapnew(): new value 1988 int *remp) // for filter(): remove flag 1989 { 1990 typval_T argv[3]; 1991 int retval = FAIL; 1992 1993 copy_tv(tv, get_vim_var_tv(VV_VAL)); 1994 argv[0] = *get_vim_var_tv(VV_KEY); 1995 argv[1] = *get_vim_var_tv(VV_VAL); 1996 if (eval_expr_typval(expr, argv, 2, newtv) == FAIL) 1997 goto theend; 1998 if (filtermap == FILTERMAP_FILTER) 1999 { 2000 int error = FALSE; 2001 2002 // filter(): when expr is zero remove the item 2003 if (in_vim9script()) 2004 *remp = !tv2bool(newtv); 2005 else 2006 *remp = (tv_get_number_chk(newtv, &error) == 0); 2007 clear_tv(newtv); 2008 // On type error, nothing has been removed; return FAIL to stop the 2009 // loop. The error message was given by tv_get_number_chk(). 2010 if (error) 2011 goto theend; 2012 } 2013 retval = OK; 2014 theend: 2015 clear_tv(get_vim_var_tv(VV_VAL)); 2016 return retval; 2017 } 2018 2019 /* 2020 * Implementation of map() and filter(). 2021 */ 2022 static void 2023 filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap) 2024 { 2025 typval_T *expr; 2026 listitem_T *li, *nli; 2027 list_T *l = NULL; 2028 dictitem_T *di; 2029 hashtab_T *ht; 2030 hashitem_T *hi; 2031 dict_T *d = NULL; 2032 blob_T *b = NULL; 2033 int rem; 2034 int todo; 2035 char_u *ermsg = (char_u *)(filtermap == FILTERMAP_MAP ? "map()" 2036 : filtermap == FILTERMAP_MAPNEW ? "mapnew()" 2037 : "filter()"); 2038 char_u *arg_errmsg = (char_u *)(filtermap == FILTERMAP_MAP 2039 ? N_("map() argument") 2040 : filtermap == FILTERMAP_MAPNEW 2041 ? N_("mapnew() argument") 2042 : N_("filter() argument")); 2043 int save_did_emsg; 2044 int idx = 0; 2045 type_T *type = NULL; 2046 garray_T type_list; 2047 2048 // map() and filter() return the first argument, also on failure. 2049 if (filtermap != FILTERMAP_MAPNEW) 2050 copy_tv(&argvars[0], rettv); 2051 if (filtermap == FILTERMAP_MAP && in_vim9script()) 2052 { 2053 // Check that map() does not change the type of the dict. 2054 ga_init2(&type_list, sizeof(type_T *), 10); 2055 type = typval2type(argvars, &type_list); 2056 } 2057 2058 if (argvars[0].v_type == VAR_BLOB) 2059 { 2060 if (filtermap == FILTERMAP_MAPNEW) 2061 { 2062 rettv->v_type = VAR_BLOB; 2063 rettv->vval.v_blob = NULL; 2064 } 2065 if ((b = argvars[0].vval.v_blob) == NULL) 2066 goto theend; 2067 } 2068 else if (argvars[0].v_type == VAR_LIST) 2069 { 2070 if (filtermap == FILTERMAP_MAPNEW) 2071 { 2072 rettv->v_type = VAR_LIST; 2073 rettv->vval.v_list = NULL; 2074 } 2075 if ((l = argvars[0].vval.v_list) == NULL 2076 || (filtermap == FILTERMAP_FILTER 2077 && value_check_lock(l->lv_lock, arg_errmsg, TRUE))) 2078 goto theend; 2079 } 2080 else if (argvars[0].v_type == VAR_DICT) 2081 { 2082 if (filtermap == FILTERMAP_MAPNEW) 2083 { 2084 rettv->v_type = VAR_DICT; 2085 rettv->vval.v_dict = NULL; 2086 } 2087 if ((d = argvars[0].vval.v_dict) == NULL 2088 || (filtermap == FILTERMAP_FILTER 2089 && value_check_lock(d->dv_lock, arg_errmsg, TRUE))) 2090 goto theend; 2091 } 2092 else 2093 { 2094 semsg(_(e_listdictblobarg), ermsg); 2095 goto theend; 2096 } 2097 2098 expr = &argvars[1]; 2099 // On type errors, the preceding call has already displayed an error 2100 // message. Avoid a misleading error message for an empty string that 2101 // was not passed as argument. 2102 if (expr->v_type != VAR_UNKNOWN) 2103 { 2104 typval_T save_val; 2105 typval_T save_key; 2106 2107 prepare_vimvar(VV_VAL, &save_val); 2108 prepare_vimvar(VV_KEY, &save_key); 2109 2110 // We reset "did_emsg" to be able to detect whether an error 2111 // occurred during evaluation of the expression. 2112 save_did_emsg = did_emsg; 2113 did_emsg = FALSE; 2114 2115 if (argvars[0].v_type == VAR_DICT) 2116 { 2117 int prev_lock = d->dv_lock; 2118 dict_T *d_ret = NULL; 2119 2120 if (filtermap == FILTERMAP_MAPNEW) 2121 { 2122 if (rettv_dict_alloc(rettv) == FAIL) 2123 goto theend; 2124 d_ret = rettv->vval.v_dict; 2125 } 2126 2127 if (filtermap != FILTERMAP_FILTER && d->dv_lock == 0) 2128 d->dv_lock = VAR_LOCKED; 2129 ht = &d->dv_hashtab; 2130 hash_lock(ht); 2131 todo = (int)ht->ht_used; 2132 for (hi = ht->ht_array; todo > 0; ++hi) 2133 { 2134 if (!HASHITEM_EMPTY(hi)) 2135 { 2136 int r; 2137 typval_T newtv; 2138 2139 --todo; 2140 di = HI2DI(hi); 2141 if (filtermap == FILTERMAP_MAP 2142 && (value_check_lock(di->di_tv.v_lock, 2143 arg_errmsg, TRUE) 2144 || var_check_ro(di->di_flags, 2145 arg_errmsg, TRUE))) 2146 break; 2147 set_vim_var_string(VV_KEY, di->di_key, -1); 2148 newtv.v_type = VAR_UNKNOWN; 2149 r = filter_map_one(&di->di_tv, expr, filtermap, 2150 &newtv, &rem); 2151 clear_tv(get_vim_var_tv(VV_KEY)); 2152 if (r == FAIL || did_emsg) 2153 { 2154 clear_tv(&newtv); 2155 break; 2156 } 2157 if (filtermap == FILTERMAP_MAP) 2158 { 2159 if (type != NULL && check_typval_arg_type( 2160 type->tt_member, &newtv, 0) == FAIL) 2161 { 2162 clear_tv(&newtv); 2163 break; 2164 } 2165 // map(): replace the dict item value 2166 clear_tv(&di->di_tv); 2167 newtv.v_lock = 0; 2168 di->di_tv = newtv; 2169 } 2170 else if (filtermap == FILTERMAP_MAPNEW) 2171 { 2172 // mapnew(): add the item value to the new dict 2173 r = dict_add_tv(d_ret, (char *)di->di_key, &newtv); 2174 clear_tv(&newtv); 2175 if (r == FAIL) 2176 break; 2177 } 2178 else if (filtermap == FILTERMAP_FILTER && rem) 2179 { 2180 // filter(false): remove the item from the dict 2181 if (var_check_fixed(di->di_flags, arg_errmsg, TRUE) 2182 || var_check_ro(di->di_flags, arg_errmsg, TRUE)) 2183 break; 2184 dictitem_remove(d, di); 2185 } 2186 } 2187 } 2188 hash_unlock(ht); 2189 d->dv_lock = prev_lock; 2190 } 2191 else if (argvars[0].v_type == VAR_BLOB) 2192 { 2193 int i; 2194 typval_T tv; 2195 varnumber_T val; 2196 blob_T *b_ret = b; 2197 2198 if (filtermap == FILTERMAP_MAPNEW) 2199 { 2200 if (blob_copy(b, rettv) == FAIL) 2201 goto theend; 2202 b_ret = rettv->vval.v_blob; 2203 } 2204 2205 // set_vim_var_nr() doesn't set the type 2206 set_vim_var_type(VV_KEY, VAR_NUMBER); 2207 2208 for (i = 0; i < b->bv_ga.ga_len; i++) 2209 { 2210 typval_T newtv; 2211 2212 tv.v_type = VAR_NUMBER; 2213 val = blob_get(b, i); 2214 tv.vval.v_number = val; 2215 set_vim_var_nr(VV_KEY, idx); 2216 if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL 2217 || did_emsg) 2218 break; 2219 if (newtv.v_type != VAR_NUMBER) 2220 { 2221 clear_tv(&newtv); 2222 emsg(_(e_invalblob)); 2223 break; 2224 } 2225 if (filtermap != FILTERMAP_FILTER) 2226 { 2227 if (newtv.vval.v_number != val) 2228 blob_set(b_ret, i, newtv.vval.v_number); 2229 } 2230 else if (rem) 2231 { 2232 char_u *p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data; 2233 2234 mch_memmove(p + i, p + i + 1, 2235 (size_t)b->bv_ga.ga_len - i - 1); 2236 --b->bv_ga.ga_len; 2237 --i; 2238 } 2239 ++idx; 2240 } 2241 } 2242 else // argvars[0].v_type == VAR_LIST 2243 { 2244 int prev_lock = l->lv_lock; 2245 list_T *l_ret = NULL; 2246 2247 if (filtermap == FILTERMAP_MAPNEW) 2248 { 2249 if (rettv_list_alloc(rettv) == FAIL) 2250 goto theend; 2251 l_ret = rettv->vval.v_list; 2252 } 2253 // set_vim_var_nr() doesn't set the type 2254 set_vim_var_type(VV_KEY, VAR_NUMBER); 2255 2256 if (filtermap != FILTERMAP_FILTER && l->lv_lock == 0) 2257 l->lv_lock = VAR_LOCKED; 2258 2259 if (l->lv_first == &range_list_item) 2260 { 2261 varnumber_T val = l->lv_u.nonmat.lv_start; 2262 int len = l->lv_len; 2263 int stride = l->lv_u.nonmat.lv_stride; 2264 2265 // List from range(): loop over the numbers 2266 if (filtermap != FILTERMAP_MAPNEW) 2267 { 2268 l->lv_first = NULL; 2269 l->lv_u.mat.lv_last = NULL; 2270 l->lv_len = 0; 2271 l->lv_u.mat.lv_idx_item = NULL; 2272 } 2273 2274 for (idx = 0; idx < len; ++idx) 2275 { 2276 typval_T tv; 2277 typval_T newtv; 2278 2279 tv.v_type = VAR_NUMBER; 2280 tv.v_lock = 0; 2281 tv.vval.v_number = val; 2282 set_vim_var_nr(VV_KEY, idx); 2283 if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) 2284 == FAIL) 2285 break; 2286 if (did_emsg) 2287 { 2288 clear_tv(&newtv); 2289 break; 2290 } 2291 if (filtermap != FILTERMAP_FILTER) 2292 { 2293 if (filtermap == FILTERMAP_MAP && type != NULL 2294 && check_typval_arg_type( 2295 type->tt_member, &newtv, 0) == FAIL) 2296 { 2297 clear_tv(&newtv); 2298 break; 2299 } 2300 // map(), mapnew(): always append the new value to the 2301 // list 2302 if (list_append_tv_move(filtermap == FILTERMAP_MAP 2303 ? l : l_ret, &newtv) == FAIL) 2304 break; 2305 } 2306 else if (!rem) 2307 { 2308 // filter(): append the list item value when not rem 2309 if (list_append_tv_move(l, &tv) == FAIL) 2310 break; 2311 } 2312 2313 val += stride; 2314 } 2315 } 2316 else 2317 { 2318 // Materialized list: loop over the items 2319 for (li = l->lv_first; li != NULL; li = nli) 2320 { 2321 typval_T newtv; 2322 2323 if (filtermap == FILTERMAP_MAP && value_check_lock( 2324 li->li_tv.v_lock, arg_errmsg, TRUE)) 2325 break; 2326 nli = li->li_next; 2327 set_vim_var_nr(VV_KEY, idx); 2328 if (filter_map_one(&li->li_tv, expr, filtermap, 2329 &newtv, &rem) == FAIL) 2330 break; 2331 if (did_emsg) 2332 { 2333 clear_tv(&newtv); 2334 break; 2335 } 2336 if (filtermap == FILTERMAP_MAP) 2337 { 2338 if (type != NULL && check_typval_arg_type( 2339 type->tt_member, &newtv, 0) == FAIL) 2340 { 2341 clear_tv(&newtv); 2342 break; 2343 } 2344 // map(): replace the list item value 2345 clear_tv(&li->li_tv); 2346 newtv.v_lock = 0; 2347 li->li_tv = newtv; 2348 } 2349 else if (filtermap == FILTERMAP_MAPNEW) 2350 { 2351 // mapnew(): append the list item value 2352 if (list_append_tv_move(l_ret, &newtv) == FAIL) 2353 break; 2354 } 2355 else if (filtermap == FILTERMAP_FILTER && rem) 2356 listitem_remove(l, li); 2357 ++idx; 2358 } 2359 } 2360 2361 l->lv_lock = prev_lock; 2362 } 2363 2364 restore_vimvar(VV_KEY, &save_key); 2365 restore_vimvar(VV_VAL, &save_val); 2366 2367 did_emsg |= save_did_emsg; 2368 } 2369 2370 theend: 2371 if (type != NULL) 2372 clear_type_list(&type_list); 2373 } 2374 2375 /* 2376 * "filter()" function 2377 */ 2378 void 2379 f_filter(typval_T *argvars, typval_T *rettv) 2380 { 2381 filter_map(argvars, rettv, FILTERMAP_FILTER); 2382 } 2383 2384 /* 2385 * "map()" function 2386 */ 2387 void 2388 f_map(typval_T *argvars, typval_T *rettv) 2389 { 2390 filter_map(argvars, rettv, FILTERMAP_MAP); 2391 } 2392 2393 /* 2394 * "mapnew()" function 2395 */ 2396 void 2397 f_mapnew(typval_T *argvars, typval_T *rettv) 2398 { 2399 filter_map(argvars, rettv, FILTERMAP_MAPNEW); 2400 } 2401 2402 /* 2403 * "add(list, item)" function 2404 */ 2405 void 2406 f_add(typval_T *argvars, typval_T *rettv) 2407 { 2408 list_T *l; 2409 blob_T *b; 2410 2411 rettv->vval.v_number = 1; // Default: Failed 2412 if (argvars[0].v_type == VAR_LIST) 2413 { 2414 if ((l = argvars[0].vval.v_list) != NULL 2415 && !value_check_lock(l->lv_lock, 2416 (char_u *)N_("add() argument"), TRUE) 2417 && list_append_tv(l, &argvars[1]) == OK) 2418 copy_tv(&argvars[0], rettv); 2419 } 2420 else if (argvars[0].v_type == VAR_BLOB) 2421 { 2422 if ((b = argvars[0].vval.v_blob) != NULL 2423 && !value_check_lock(b->bv_lock, 2424 (char_u *)N_("add() argument"), TRUE)) 2425 { 2426 int error = FALSE; 2427 varnumber_T n = tv_get_number_chk(&argvars[1], &error); 2428 2429 if (!error) 2430 { 2431 ga_append(&b->bv_ga, (int)n); 2432 copy_tv(&argvars[0], rettv); 2433 } 2434 } 2435 } 2436 else 2437 emsg(_(e_listblobreq)); 2438 } 2439 2440 /* 2441 * "count()" function 2442 */ 2443 void 2444 f_count(typval_T *argvars, typval_T *rettv) 2445 { 2446 long n = 0; 2447 int ic = FALSE; 2448 int error = FALSE; 2449 2450 if (argvars[2].v_type != VAR_UNKNOWN) 2451 ic = (int)tv_get_bool_chk(&argvars[2], &error); 2452 2453 if (argvars[0].v_type == VAR_STRING) 2454 { 2455 char_u *expr = tv_get_string_chk(&argvars[1]); 2456 char_u *p = argvars[0].vval.v_string; 2457 char_u *next; 2458 2459 if (!error && expr != NULL && *expr != NUL && p != NULL) 2460 { 2461 if (ic) 2462 { 2463 size_t len = STRLEN(expr); 2464 2465 while (*p != NUL) 2466 { 2467 if (MB_STRNICMP(p, expr, len) == 0) 2468 { 2469 ++n; 2470 p += len; 2471 } 2472 else 2473 MB_PTR_ADV(p); 2474 } 2475 } 2476 else 2477 while ((next = (char_u *)strstr((char *)p, (char *)expr)) 2478 != NULL) 2479 { 2480 ++n; 2481 p = next + STRLEN(expr); 2482 } 2483 } 2484 2485 } 2486 else if (argvars[0].v_type == VAR_LIST) 2487 { 2488 listitem_T *li; 2489 list_T *l; 2490 long idx; 2491 2492 if ((l = argvars[0].vval.v_list) != NULL) 2493 { 2494 CHECK_LIST_MATERIALIZE(l); 2495 li = l->lv_first; 2496 if (argvars[2].v_type != VAR_UNKNOWN) 2497 { 2498 if (argvars[3].v_type != VAR_UNKNOWN) 2499 { 2500 idx = (long)tv_get_number_chk(&argvars[3], &error); 2501 if (!error) 2502 { 2503 li = list_find(l, idx); 2504 if (li == NULL) 2505 semsg(_(e_listidx), idx); 2506 } 2507 } 2508 if (error) 2509 li = NULL; 2510 } 2511 2512 for ( ; li != NULL; li = li->li_next) 2513 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE)) 2514 ++n; 2515 } 2516 } 2517 else if (argvars[0].v_type == VAR_DICT) 2518 { 2519 int todo; 2520 dict_T *d; 2521 hashitem_T *hi; 2522 2523 if ((d = argvars[0].vval.v_dict) != NULL) 2524 { 2525 if (argvars[2].v_type != VAR_UNKNOWN) 2526 { 2527 if (argvars[3].v_type != VAR_UNKNOWN) 2528 emsg(_(e_invarg)); 2529 } 2530 2531 todo = error ? 0 : (int)d->dv_hashtab.ht_used; 2532 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) 2533 { 2534 if (!HASHITEM_EMPTY(hi)) 2535 { 2536 --todo; 2537 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE)) 2538 ++n; 2539 } 2540 } 2541 } 2542 } 2543 else 2544 semsg(_(e_listdictarg), "count()"); 2545 rettv->vval.v_number = n; 2546 } 2547 2548 /* 2549 * "extend()" or "extendnew()" function. "is_new" is TRUE for extendnew(). 2550 */ 2551 static void 2552 extend(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg, int is_new) 2553 { 2554 type_T *type = NULL; 2555 garray_T type_list; 2556 2557 if (!is_new && in_vim9script()) 2558 { 2559 // Check that map() does not change the type of the dict. 2560 ga_init2(&type_list, sizeof(type_T *), 10); 2561 type = typval2type(argvars, &type_list); 2562 } 2563 2564 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) 2565 { 2566 list_T *l1, *l2; 2567 listitem_T *item; 2568 long before; 2569 int error = FALSE; 2570 2571 l1 = argvars[0].vval.v_list; 2572 if (l1 == NULL) 2573 { 2574 emsg(_(e_cannot_extend_null_list)); 2575 goto theend; 2576 } 2577 l2 = argvars[1].vval.v_list; 2578 if ((is_new || !value_check_lock(l1->lv_lock, arg_errmsg, TRUE)) 2579 && l2 != NULL) 2580 { 2581 if (is_new) 2582 { 2583 l1 = list_copy(l1, FALSE, get_copyID()); 2584 if (l1 == NULL) 2585 goto theend; 2586 } 2587 2588 if (argvars[2].v_type != VAR_UNKNOWN) 2589 { 2590 before = (long)tv_get_number_chk(&argvars[2], &error); 2591 if (error) 2592 goto theend; // type error; errmsg already given 2593 2594 if (before == l1->lv_len) 2595 item = NULL; 2596 else 2597 { 2598 item = list_find(l1, before); 2599 if (item == NULL) 2600 { 2601 semsg(_(e_listidx), before); 2602 goto theend; 2603 } 2604 } 2605 } 2606 else 2607 item = NULL; 2608 if (type != NULL && check_typval_arg_type( 2609 type, &argvars[1], 2) == FAIL) 2610 goto theend; 2611 list_extend(l1, l2, item); 2612 2613 if (is_new) 2614 { 2615 rettv->v_type = VAR_LIST; 2616 rettv->vval.v_list = l1; 2617 rettv->v_lock = FALSE; 2618 } 2619 else 2620 copy_tv(&argvars[0], rettv); 2621 } 2622 } 2623 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) 2624 { 2625 dict_T *d1, *d2; 2626 char_u *action; 2627 int i; 2628 2629 d1 = argvars[0].vval.v_dict; 2630 if (d1 == NULL) 2631 { 2632 emsg(_(e_cannot_extend_null_dict)); 2633 goto theend; 2634 } 2635 d2 = argvars[1].vval.v_dict; 2636 if ((is_new || !value_check_lock(d1->dv_lock, arg_errmsg, TRUE)) 2637 && d2 != NULL) 2638 { 2639 if (is_new) 2640 { 2641 d1 = dict_copy(d1, FALSE, get_copyID()); 2642 if (d1 == NULL) 2643 goto theend; 2644 } 2645 2646 // Check the third argument. 2647 if (argvars[2].v_type != VAR_UNKNOWN) 2648 { 2649 static char *(av[]) = {"keep", "force", "error"}; 2650 2651 action = tv_get_string_chk(&argvars[2]); 2652 if (action == NULL) 2653 goto theend; // type error; errmsg already given 2654 for (i = 0; i < 3; ++i) 2655 if (STRCMP(action, av[i]) == 0) 2656 break; 2657 if (i == 3) 2658 { 2659 semsg(_(e_invarg2), action); 2660 goto theend; 2661 } 2662 } 2663 else 2664 action = (char_u *)"force"; 2665 2666 if (type != NULL && check_typval_arg_type( 2667 type, &argvars[1], 2) == FAIL) 2668 goto theend; 2669 dict_extend(d1, d2, action); 2670 2671 if (is_new) 2672 { 2673 rettv->v_type = VAR_DICT; 2674 rettv->vval.v_dict = d1; 2675 rettv->v_lock = FALSE; 2676 } 2677 else 2678 copy_tv(&argvars[0], rettv); 2679 } 2680 } 2681 else 2682 semsg(_(e_listdictarg), is_new ? "extendnew()" : "extend()"); 2683 2684 theend: 2685 if (type != NULL) 2686 clear_type_list(&type_list); 2687 } 2688 2689 /* 2690 * "extend(list, list [, idx])" function 2691 * "extend(dict, dict [, action])" function 2692 */ 2693 void 2694 f_extend(typval_T *argvars, typval_T *rettv) 2695 { 2696 char_u *errmsg = (char_u *)N_("extend() argument"); 2697 2698 extend(argvars, rettv, errmsg, FALSE); 2699 } 2700 2701 /* 2702 * "extendnew(list, list [, idx])" function 2703 * "extendnew(dict, dict [, action])" function 2704 */ 2705 void 2706 f_extendnew(typval_T *argvars, typval_T *rettv) 2707 { 2708 char_u *errmsg = (char_u *)N_("extendnew() argument"); 2709 2710 extend(argvars, rettv, errmsg, TRUE); 2711 } 2712 2713 /* 2714 * "insert()" function 2715 */ 2716 void 2717 f_insert(typval_T *argvars, typval_T *rettv) 2718 { 2719 long before = 0; 2720 listitem_T *item; 2721 list_T *l; 2722 int error = FALSE; 2723 2724 if (argvars[0].v_type == VAR_BLOB) 2725 { 2726 int val, len; 2727 char_u *p; 2728 2729 if (argvars[0].vval.v_blob == NULL) 2730 return; 2731 2732 len = blob_len(argvars[0].vval.v_blob); 2733 if (argvars[2].v_type != VAR_UNKNOWN) 2734 { 2735 before = (long)tv_get_number_chk(&argvars[2], &error); 2736 if (error) 2737 return; // type error; errmsg already given 2738 if (before < 0 || before > len) 2739 { 2740 semsg(_(e_invarg2), tv_get_string(&argvars[2])); 2741 return; 2742 } 2743 } 2744 val = tv_get_number_chk(&argvars[1], &error); 2745 if (error) 2746 return; 2747 if (val < 0 || val > 255) 2748 { 2749 semsg(_(e_invarg2), tv_get_string(&argvars[1])); 2750 return; 2751 } 2752 2753 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL) 2754 return; 2755 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data; 2756 mch_memmove(p + before + 1, p + before, (size_t)len - before); 2757 *(p + before) = val; 2758 ++argvars[0].vval.v_blob->bv_ga.ga_len; 2759 2760 copy_tv(&argvars[0], rettv); 2761 } 2762 else if (argvars[0].v_type != VAR_LIST) 2763 semsg(_(e_listblobarg), "insert()"); 2764 else if ((l = argvars[0].vval.v_list) != NULL 2765 && !value_check_lock(l->lv_lock, 2766 (char_u *)N_("insert() argument"), TRUE)) 2767 { 2768 if (argvars[2].v_type != VAR_UNKNOWN) 2769 before = (long)tv_get_number_chk(&argvars[2], &error); 2770 if (error) 2771 return; // type error; errmsg already given 2772 2773 if (before == l->lv_len) 2774 item = NULL; 2775 else 2776 { 2777 item = list_find(l, before); 2778 if (item == NULL) 2779 { 2780 semsg(_(e_listidx), before); 2781 l = NULL; 2782 } 2783 } 2784 if (l != NULL) 2785 { 2786 (void)list_insert_tv(l, &argvars[1], item); 2787 copy_tv(&argvars[0], rettv); 2788 } 2789 } 2790 } 2791 2792 /* 2793 * "remove()" function 2794 */ 2795 void 2796 f_remove(typval_T *argvars, typval_T *rettv) 2797 { 2798 char_u *arg_errmsg = (char_u *)N_("remove() argument"); 2799 2800 if (argvars[0].v_type == VAR_DICT) 2801 dict_remove(argvars, rettv, arg_errmsg); 2802 else if (argvars[0].v_type == VAR_BLOB) 2803 blob_remove(argvars, rettv); 2804 else if (argvars[0].v_type == VAR_LIST) 2805 list_remove(argvars, rettv, arg_errmsg); 2806 else 2807 semsg(_(e_listdictblobarg), "remove()"); 2808 } 2809 2810 /* 2811 * "reverse({list})" function 2812 */ 2813 void 2814 f_reverse(typval_T *argvars, typval_T *rettv) 2815 { 2816 list_T *l; 2817 listitem_T *li, *ni; 2818 2819 if (argvars[0].v_type == VAR_BLOB) 2820 { 2821 blob_T *b = argvars[0].vval.v_blob; 2822 int i, len = blob_len(b); 2823 2824 for (i = 0; i < len / 2; i++) 2825 { 2826 int tmp = blob_get(b, i); 2827 2828 blob_set(b, i, blob_get(b, len - i - 1)); 2829 blob_set(b, len - i - 1, tmp); 2830 } 2831 rettv_blob_set(rettv, b); 2832 return; 2833 } 2834 2835 if (argvars[0].v_type != VAR_LIST) 2836 semsg(_(e_listblobarg), "reverse()"); 2837 else if ((l = argvars[0].vval.v_list) != NULL 2838 && !value_check_lock(l->lv_lock, 2839 (char_u *)N_("reverse() argument"), TRUE)) 2840 { 2841 if (l->lv_first == &range_list_item) 2842 { 2843 varnumber_T new_start = l->lv_u.nonmat.lv_start 2844 + (l->lv_len - 1) * l->lv_u.nonmat.lv_stride; 2845 l->lv_u.nonmat.lv_end = new_start 2846 - (l->lv_u.nonmat.lv_end - l->lv_u.nonmat.lv_start); 2847 l->lv_u.nonmat.lv_start = new_start; 2848 l->lv_u.nonmat.lv_stride = -l->lv_u.nonmat.lv_stride; 2849 rettv_list_set(rettv, l); 2850 return; 2851 } 2852 li = l->lv_u.mat.lv_last; 2853 l->lv_first = l->lv_u.mat.lv_last = NULL; 2854 l->lv_len = 0; 2855 while (li != NULL) 2856 { 2857 ni = li->li_prev; 2858 list_append(l, li); 2859 li = ni; 2860 } 2861 rettv_list_set(rettv, l); 2862 l->lv_u.mat.lv_idx = l->lv_len - l->lv_u.mat.lv_idx - 1; 2863 } 2864 } 2865 2866 /* 2867 * "reduce(list, { accumulator, element -> value } [, initial])" function 2868 */ 2869 void 2870 f_reduce(typval_T *argvars, typval_T *rettv) 2871 { 2872 typval_T initial; 2873 char_u *func_name; 2874 partial_T *partial = NULL; 2875 funcexe_T funcexe; 2876 typval_T argv[3]; 2877 2878 if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) 2879 { 2880 emsg(_(e_listblobreq)); 2881 return; 2882 } 2883 2884 if (argvars[1].v_type == VAR_FUNC) 2885 func_name = argvars[1].vval.v_string; 2886 else if (argvars[1].v_type == VAR_PARTIAL) 2887 { 2888 partial = argvars[1].vval.v_partial; 2889 func_name = partial_name(partial); 2890 } 2891 else 2892 func_name = tv_get_string(&argvars[1]); 2893 if (func_name == NULL || *func_name == NUL) 2894 { 2895 emsg(_(e_missing_function_argument)); 2896 return; 2897 } 2898 2899 vim_memset(&funcexe, 0, sizeof(funcexe)); 2900 funcexe.evaluate = TRUE; 2901 funcexe.partial = partial; 2902 2903 if (argvars[0].v_type == VAR_LIST) 2904 { 2905 list_T *l = argvars[0].vval.v_list; 2906 listitem_T *li = NULL; 2907 int r; 2908 int called_emsg_start = called_emsg; 2909 2910 if (l != NULL) 2911 CHECK_LIST_MATERIALIZE(l); 2912 if (argvars[2].v_type == VAR_UNKNOWN) 2913 { 2914 if (l == NULL || l->lv_first == NULL) 2915 { 2916 semsg(_(e_reduceempty), "List"); 2917 return; 2918 } 2919 initial = l->lv_first->li_tv; 2920 li = l->lv_first->li_next; 2921 } 2922 else 2923 { 2924 initial = argvars[2]; 2925 if (l != NULL) 2926 li = l->lv_first; 2927 } 2928 copy_tv(&initial, rettv); 2929 2930 if (l != NULL) 2931 { 2932 int prev_locked = l->lv_lock; 2933 2934 l->lv_lock = VAR_FIXED; // disallow the list changing here 2935 for ( ; li != NULL; li = li->li_next) 2936 { 2937 argv[0] = *rettv; 2938 argv[1] = li->li_tv; 2939 rettv->v_type = VAR_UNKNOWN; 2940 r = call_func(func_name, -1, rettv, 2, argv, &funcexe); 2941 clear_tv(&argv[0]); 2942 if (r == FAIL || called_emsg != called_emsg_start) 2943 break; 2944 } 2945 l->lv_lock = prev_locked; 2946 } 2947 } 2948 else 2949 { 2950 blob_T *b = argvars[0].vval.v_blob; 2951 int i; 2952 2953 if (argvars[2].v_type == VAR_UNKNOWN) 2954 { 2955 if (b == NULL || b->bv_ga.ga_len == 0) 2956 { 2957 semsg(_(e_reduceempty), "Blob"); 2958 return; 2959 } 2960 initial.v_type = VAR_NUMBER; 2961 initial.vval.v_number = blob_get(b, 0); 2962 i = 1; 2963 } 2964 else if (argvars[2].v_type != VAR_NUMBER) 2965 { 2966 emsg(_(e_number_exp)); 2967 return; 2968 } 2969 else 2970 { 2971 initial = argvars[2]; 2972 i = 0; 2973 } 2974 2975 copy_tv(&initial, rettv); 2976 if (b != NULL) 2977 { 2978 for ( ; i < b->bv_ga.ga_len; i++) 2979 { 2980 argv[0] = *rettv; 2981 argv[1].v_type = VAR_NUMBER; 2982 argv[1].vval.v_number = blob_get(b, i); 2983 if (call_func(func_name, -1, rettv, 2, argv, &funcexe) == FAIL) 2984 return; 2985 } 2986 } 2987 } 2988 } 2989 2990 #endif // defined(FEAT_EVAL) 2991