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 12 */ 13 14 #include "vim.h" 15 16 #if defined(FEAT_EVAL) || defined(PROTO) 17 18 /* List heads for garbage collection. */ 19 static list_T *first_list = NULL; /* list of all lists */ 20 21 /* 22 * Add a watcher to a list. 23 */ 24 void 25 list_add_watch(list_T *l, listwatch_T *lw) 26 { 27 lw->lw_next = l->lv_watch; 28 l->lv_watch = lw; 29 } 30 31 /* 32 * Remove a watcher from a list. 33 * No warning when it isn't found... 34 */ 35 void 36 list_rem_watch(list_T *l, listwatch_T *lwrem) 37 { 38 listwatch_T *lw, **lwp; 39 40 lwp = &l->lv_watch; 41 for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next) 42 { 43 if (lw == lwrem) 44 { 45 *lwp = lw->lw_next; 46 break; 47 } 48 lwp = &lw->lw_next; 49 } 50 } 51 52 /* 53 * Just before removing an item from a list: advance watchers to the next 54 * item. 55 */ 56 void 57 list_fix_watch(list_T *l, listitem_T *item) 58 { 59 listwatch_T *lw; 60 61 for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next) 62 if (lw->lw_item == item) 63 lw->lw_item = item->li_next; 64 } 65 66 /* 67 * Allocate an empty header for a list. 68 * Caller should take care of the reference count. 69 */ 70 list_T * 71 list_alloc(void) 72 { 73 list_T *l; 74 75 l = (list_T *)alloc_clear(sizeof(list_T)); 76 if (l != NULL) 77 { 78 /* Prepend the list to the list of lists for garbage collection. */ 79 if (first_list != NULL) 80 first_list->lv_used_prev = l; 81 l->lv_used_prev = NULL; 82 l->lv_used_next = first_list; 83 first_list = l; 84 } 85 return l; 86 } 87 88 /* 89 * Allocate an empty list for a return value, with reference count set. 90 * Returns OK or FAIL. 91 */ 92 int 93 rettv_list_alloc(typval_T *rettv) 94 { 95 list_T *l = list_alloc(); 96 97 if (l == NULL) 98 return FAIL; 99 100 rettv->v_lock = 0; 101 rettv_list_set(rettv, l); 102 return OK; 103 } 104 105 /* 106 * Set a list as the return value 107 */ 108 void 109 rettv_list_set(typval_T *rettv, list_T *l) 110 { 111 rettv->v_type = VAR_LIST; 112 rettv->vval.v_list = l; 113 if (l != NULL) 114 ++l->lv_refcount; 115 } 116 117 /* 118 * Unreference a list: decrement the reference count and free it when it 119 * becomes zero. 120 */ 121 void 122 list_unref(list_T *l) 123 { 124 if (l != NULL && --l->lv_refcount <= 0) 125 list_free(l); 126 } 127 128 /* 129 * Free a list, including all non-container items it points to. 130 * Ignores the reference count. 131 */ 132 static void 133 list_free_contents(list_T *l) 134 { 135 listitem_T *item; 136 137 for (item = l->lv_first; item != NULL; item = l->lv_first) 138 { 139 /* Remove the item before deleting it. */ 140 l->lv_first = item->li_next; 141 clear_tv(&item->li_tv); 142 vim_free(item); 143 } 144 } 145 146 /* 147 * Go through the list of lists and free items without the copyID. 148 * But don't free a list that has a watcher (used in a for loop), these 149 * are not referenced anywhere. 150 */ 151 int 152 list_free_nonref(int copyID) 153 { 154 list_T *ll; 155 int did_free = FALSE; 156 157 for (ll = first_list; ll != NULL; ll = ll->lv_used_next) 158 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK) 159 && ll->lv_watch == NULL) 160 { 161 /* Free the List and ordinary items it contains, but don't recurse 162 * into Lists and Dictionaries, they will be in the list of dicts 163 * or list of lists. */ 164 list_free_contents(ll); 165 did_free = TRUE; 166 } 167 return did_free; 168 } 169 170 static void 171 list_free_list(list_T *l) 172 { 173 /* Remove the list from the list of lists for garbage collection. */ 174 if (l->lv_used_prev == NULL) 175 first_list = l->lv_used_next; 176 else 177 l->lv_used_prev->lv_used_next = l->lv_used_next; 178 if (l->lv_used_next != NULL) 179 l->lv_used_next->lv_used_prev = l->lv_used_prev; 180 181 vim_free(l); 182 } 183 184 void 185 list_free_items(int copyID) 186 { 187 list_T *ll, *ll_next; 188 189 for (ll = first_list; ll != NULL; ll = ll_next) 190 { 191 ll_next = ll->lv_used_next; 192 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK) 193 && ll->lv_watch == NULL) 194 { 195 /* Free the List and ordinary items it contains, but don't recurse 196 * into Lists and Dictionaries, they will be in the list of dicts 197 * or list of lists. */ 198 list_free_list(ll); 199 } 200 } 201 } 202 203 void 204 list_free(list_T *l) 205 { 206 if (!in_free_unref_items) 207 { 208 list_free_contents(l); 209 list_free_list(l); 210 } 211 } 212 213 /* 214 * Allocate a list item. 215 * It is not initialized, don't forget to set v_lock. 216 */ 217 listitem_T * 218 listitem_alloc(void) 219 { 220 return (listitem_T *)alloc(sizeof(listitem_T)); 221 } 222 223 /* 224 * Free a list item. Also clears the value. Does not notify watchers. 225 */ 226 void 227 listitem_free(listitem_T *item) 228 { 229 clear_tv(&item->li_tv); 230 vim_free(item); 231 } 232 233 /* 234 * Remove a list item from a List and free it. Also clears the value. 235 */ 236 void 237 listitem_remove(list_T *l, listitem_T *item) 238 { 239 vimlist_remove(l, item, item); 240 listitem_free(item); 241 } 242 243 /* 244 * Get the number of items in a list. 245 */ 246 long 247 list_len(list_T *l) 248 { 249 if (l == NULL) 250 return 0L; 251 return l->lv_len; 252 } 253 254 /* 255 * Return TRUE when two lists have exactly the same values. 256 */ 257 int 258 list_equal( 259 list_T *l1, 260 list_T *l2, 261 int ic, /* ignore case for strings */ 262 int recursive) /* TRUE when used recursively */ 263 { 264 listitem_T *item1, *item2; 265 266 if (l1 == NULL || l2 == NULL) 267 return FALSE; 268 if (l1 == l2) 269 return TRUE; 270 if (list_len(l1) != list_len(l2)) 271 return FALSE; 272 273 for (item1 = l1->lv_first, item2 = l2->lv_first; 274 item1 != NULL && item2 != NULL; 275 item1 = item1->li_next, item2 = item2->li_next) 276 if (!tv_equal(&item1->li_tv, &item2->li_tv, ic, recursive)) 277 return FALSE; 278 return item1 == NULL && item2 == NULL; 279 } 280 281 /* 282 * Locate item with index "n" in list "l" and return it. 283 * A negative index is counted from the end; -1 is the last item. 284 * Returns NULL when "n" is out of range. 285 */ 286 listitem_T * 287 list_find(list_T *l, long n) 288 { 289 listitem_T *item; 290 long idx; 291 292 if (l == NULL) 293 return NULL; 294 295 /* Negative index is relative to the end. */ 296 if (n < 0) 297 n = l->lv_len + n; 298 299 /* Check for index out of range. */ 300 if (n < 0 || n >= l->lv_len) 301 return NULL; 302 303 /* When there is a cached index may start search from there. */ 304 if (l->lv_idx_item != NULL) 305 { 306 if (n < l->lv_idx / 2) 307 { 308 /* closest to the start of the list */ 309 item = l->lv_first; 310 idx = 0; 311 } 312 else if (n > (l->lv_idx + l->lv_len) / 2) 313 { 314 /* closest to the end of the list */ 315 item = l->lv_last; 316 idx = l->lv_len - 1; 317 } 318 else 319 { 320 /* closest to the cached index */ 321 item = l->lv_idx_item; 322 idx = l->lv_idx; 323 } 324 } 325 else 326 { 327 if (n < l->lv_len / 2) 328 { 329 /* closest to the start of the list */ 330 item = l->lv_first; 331 idx = 0; 332 } 333 else 334 { 335 /* closest to the end of the list */ 336 item = l->lv_last; 337 idx = l->lv_len - 1; 338 } 339 } 340 341 while (n > idx) 342 { 343 /* search forward */ 344 item = item->li_next; 345 ++idx; 346 } 347 while (n < idx) 348 { 349 /* search backward */ 350 item = item->li_prev; 351 --idx; 352 } 353 354 /* cache the used index */ 355 l->lv_idx = idx; 356 l->lv_idx_item = item; 357 358 return item; 359 } 360 361 /* 362 * Get list item "l[idx]" as a number. 363 */ 364 long 365 list_find_nr( 366 list_T *l, 367 long idx, 368 int *errorp) /* set to TRUE when something wrong */ 369 { 370 listitem_T *li; 371 372 li = list_find(l, idx); 373 if (li == NULL) 374 { 375 if (errorp != NULL) 376 *errorp = TRUE; 377 return -1L; 378 } 379 return (long)get_tv_number_chk(&li->li_tv, errorp); 380 } 381 382 /* 383 * Get list item "l[idx - 1]" as a string. Returns NULL for failure. 384 */ 385 char_u * 386 list_find_str(list_T *l, long idx) 387 { 388 listitem_T *li; 389 390 li = list_find(l, idx - 1); 391 if (li == NULL) 392 { 393 EMSGN(_(e_listidx), idx); 394 return NULL; 395 } 396 return get_tv_string(&li->li_tv); 397 } 398 399 /* 400 * Locate "item" list "l" and return its index. 401 * Returns -1 when "item" is not in the list. 402 */ 403 long 404 list_idx_of_item(list_T *l, listitem_T *item) 405 { 406 long idx = 0; 407 listitem_T *li; 408 409 if (l == NULL) 410 return -1; 411 idx = 0; 412 for (li = l->lv_first; li != NULL && li != item; li = li->li_next) 413 ++idx; 414 if (li == NULL) 415 return -1; 416 return idx; 417 } 418 419 /* 420 * Append item "item" to the end of list "l". 421 */ 422 void 423 list_append(list_T *l, listitem_T *item) 424 { 425 if (l->lv_last == NULL) 426 { 427 /* empty list */ 428 l->lv_first = item; 429 l->lv_last = item; 430 item->li_prev = NULL; 431 } 432 else 433 { 434 l->lv_last->li_next = item; 435 item->li_prev = l->lv_last; 436 l->lv_last = item; 437 } 438 ++l->lv_len; 439 item->li_next = NULL; 440 } 441 442 /* 443 * Append typval_T "tv" to the end of list "l". 444 * Return FAIL when out of memory. 445 */ 446 int 447 list_append_tv(list_T *l, typval_T *tv) 448 { 449 listitem_T *li = listitem_alloc(); 450 451 if (li == NULL) 452 return FAIL; 453 copy_tv(tv, &li->li_tv); 454 list_append(l, li); 455 return OK; 456 } 457 458 /* 459 * Add a dictionary to a list. Used by getqflist(). 460 * Return FAIL when out of memory. 461 */ 462 int 463 list_append_dict(list_T *list, dict_T *dict) 464 { 465 listitem_T *li = listitem_alloc(); 466 467 if (li == NULL) 468 return FAIL; 469 li->li_tv.v_type = VAR_DICT; 470 li->li_tv.v_lock = 0; 471 li->li_tv.vval.v_dict = dict; 472 list_append(list, li); 473 ++dict->dv_refcount; 474 return OK; 475 } 476 477 /* 478 * Make a copy of "str" and append it as an item to list "l". 479 * When "len" >= 0 use "str[len]". 480 * Returns FAIL when out of memory. 481 */ 482 int 483 list_append_string(list_T *l, char_u *str, int len) 484 { 485 listitem_T *li = listitem_alloc(); 486 487 if (li == NULL) 488 return FAIL; 489 list_append(l, li); 490 li->li_tv.v_type = VAR_STRING; 491 li->li_tv.v_lock = 0; 492 if (str == NULL) 493 li->li_tv.vval.v_string = NULL; 494 else if ((li->li_tv.vval.v_string = (len >= 0 ? vim_strnsave(str, len) 495 : vim_strsave(str))) == NULL) 496 return FAIL; 497 return OK; 498 } 499 500 /* 501 * Append "n" to list "l". 502 * Returns FAIL when out of memory. 503 */ 504 int 505 list_append_number(list_T *l, varnumber_T n) 506 { 507 listitem_T *li; 508 509 li = listitem_alloc(); 510 if (li == NULL) 511 return FAIL; 512 li->li_tv.v_type = VAR_NUMBER; 513 li->li_tv.v_lock = 0; 514 li->li_tv.vval.v_number = n; 515 list_append(l, li); 516 return OK; 517 } 518 519 /* 520 * Insert typval_T "tv" in list "l" before "item". 521 * If "item" is NULL append at the end. 522 * Return FAIL when out of memory. 523 */ 524 int 525 list_insert_tv(list_T *l, typval_T *tv, listitem_T *item) 526 { 527 listitem_T *ni = listitem_alloc(); 528 529 if (ni == NULL) 530 return FAIL; 531 copy_tv(tv, &ni->li_tv); 532 list_insert(l, ni, item); 533 return OK; 534 } 535 536 void 537 list_insert(list_T *l, listitem_T *ni, listitem_T *item) 538 { 539 if (item == NULL) 540 /* Append new item at end of list. */ 541 list_append(l, ni); 542 else 543 { 544 /* Insert new item before existing item. */ 545 ni->li_prev = item->li_prev; 546 ni->li_next = item; 547 if (item->li_prev == NULL) 548 { 549 l->lv_first = ni; 550 ++l->lv_idx; 551 } 552 else 553 { 554 item->li_prev->li_next = ni; 555 l->lv_idx_item = NULL; 556 } 557 item->li_prev = ni; 558 ++l->lv_len; 559 } 560 } 561 562 /* 563 * Extend "l1" with "l2". 564 * If "bef" is NULL append at the end, otherwise insert before this item. 565 * Returns FAIL when out of memory. 566 */ 567 int 568 list_extend(list_T *l1, list_T *l2, listitem_T *bef) 569 { 570 listitem_T *item; 571 int todo = l2->lv_len; 572 573 /* We also quit the loop when we have inserted the original item count of 574 * the list, avoid a hang when we extend a list with itself. */ 575 for (item = l2->lv_first; item != NULL && --todo >= 0; item = item->li_next) 576 if (list_insert_tv(l1, &item->li_tv, bef) == FAIL) 577 return FAIL; 578 return OK; 579 } 580 581 /* 582 * Concatenate lists "l1" and "l2" into a new list, stored in "tv". 583 * Return FAIL when out of memory. 584 */ 585 int 586 list_concat(list_T *l1, list_T *l2, typval_T *tv) 587 { 588 list_T *l; 589 590 if (l1 == NULL || l2 == NULL) 591 return FAIL; 592 593 /* make a copy of the first list. */ 594 l = list_copy(l1, FALSE, 0); 595 if (l == NULL) 596 return FAIL; 597 tv->v_type = VAR_LIST; 598 tv->vval.v_list = l; 599 600 /* append all items from the second list */ 601 return list_extend(l, l2, NULL); 602 } 603 604 /* 605 * Make a copy of list "orig". Shallow if "deep" is FALSE. 606 * The refcount of the new list is set to 1. 607 * See item_copy() for "copyID". 608 * Returns NULL when out of memory. 609 */ 610 list_T * 611 list_copy(list_T *orig, int deep, int copyID) 612 { 613 list_T *copy; 614 listitem_T *item; 615 listitem_T *ni; 616 617 if (orig == NULL) 618 return NULL; 619 620 copy = list_alloc(); 621 if (copy != NULL) 622 { 623 if (copyID != 0) 624 { 625 /* Do this before adding the items, because one of the items may 626 * refer back to this list. */ 627 orig->lv_copyID = copyID; 628 orig->lv_copylist = copy; 629 } 630 for (item = orig->lv_first; item != NULL && !got_int; 631 item = item->li_next) 632 { 633 ni = listitem_alloc(); 634 if (ni == NULL) 635 break; 636 if (deep) 637 { 638 if (item_copy(&item->li_tv, &ni->li_tv, deep, copyID) == FAIL) 639 { 640 vim_free(ni); 641 break; 642 } 643 } 644 else 645 copy_tv(&item->li_tv, &ni->li_tv); 646 list_append(copy, ni); 647 } 648 ++copy->lv_refcount; 649 if (item != NULL) 650 { 651 list_unref(copy); 652 copy = NULL; 653 } 654 } 655 656 return copy; 657 } 658 659 /* 660 * Remove items "item" to "item2" from list "l". 661 * Does not free the listitem or the value! 662 * This used to be called list_remove, but that conflicts with a Sun header 663 * file. 664 */ 665 void 666 vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2) 667 { 668 listitem_T *ip; 669 670 /* notify watchers */ 671 for (ip = item; ip != NULL; ip = ip->li_next) 672 { 673 --l->lv_len; 674 list_fix_watch(l, ip); 675 if (ip == item2) 676 break; 677 } 678 679 if (item2->li_next == NULL) 680 l->lv_last = item->li_prev; 681 else 682 item2->li_next->li_prev = item->li_prev; 683 if (item->li_prev == NULL) 684 l->lv_first = item2->li_next; 685 else 686 item->li_prev->li_next = item2->li_next; 687 l->lv_idx_item = NULL; 688 } 689 690 /* 691 * Return an allocated string with the string representation of a list. 692 * May return NULL. 693 */ 694 char_u * 695 list2string(typval_T *tv, int copyID, int restore_copyID) 696 { 697 garray_T ga; 698 699 if (tv->vval.v_list == NULL) 700 return NULL; 701 ga_init2(&ga, (int)sizeof(char), 80); 702 ga_append(&ga, '['); 703 if (list_join(&ga, tv->vval.v_list, (char_u *)", ", 704 FALSE, restore_copyID, copyID) == FAIL) 705 { 706 vim_free(ga.ga_data); 707 return NULL; 708 } 709 ga_append(&ga, ']'); 710 ga_append(&ga, NUL); 711 return (char_u *)ga.ga_data; 712 } 713 714 typedef struct join_S { 715 char_u *s; 716 char_u *tofree; 717 } join_T; 718 719 static int 720 list_join_inner( 721 garray_T *gap, /* to store the result in */ 722 list_T *l, 723 char_u *sep, 724 int echo_style, 725 int restore_copyID, 726 int copyID, 727 garray_T *join_gap) /* to keep each list item string */ 728 { 729 int i; 730 join_T *p; 731 int len; 732 int sumlen = 0; 733 int first = TRUE; 734 char_u *tofree; 735 char_u numbuf[NUMBUFLEN]; 736 listitem_T *item; 737 char_u *s; 738 739 /* Stringify each item in the list. */ 740 for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) 741 { 742 s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID, 743 echo_style, restore_copyID, !echo_style); 744 if (s == NULL) 745 return FAIL; 746 747 len = (int)STRLEN(s); 748 sumlen += len; 749 750 (void)ga_grow(join_gap, 1); 751 p = ((join_T *)join_gap->ga_data) + (join_gap->ga_len++); 752 if (tofree != NULL || s != numbuf) 753 { 754 p->s = s; 755 p->tofree = tofree; 756 } 757 else 758 { 759 p->s = vim_strnsave(s, len); 760 p->tofree = p->s; 761 } 762 763 line_breakcheck(); 764 if (did_echo_string_emsg) /* recursion error, bail out */ 765 break; 766 } 767 768 /* Allocate result buffer with its total size, avoid re-allocation and 769 * multiple copy operations. Add 2 for a tailing ']' and NUL. */ 770 if (join_gap->ga_len >= 2) 771 sumlen += (int)STRLEN(sep) * (join_gap->ga_len - 1); 772 if (ga_grow(gap, sumlen + 2) == FAIL) 773 return FAIL; 774 775 for (i = 0; i < join_gap->ga_len && !got_int; ++i) 776 { 777 if (first) 778 first = FALSE; 779 else 780 ga_concat(gap, sep); 781 p = ((join_T *)join_gap->ga_data) + i; 782 783 if (p->s != NULL) 784 ga_concat(gap, p->s); 785 line_breakcheck(); 786 } 787 788 return OK; 789 } 790 791 /* 792 * Join list "l" into a string in "*gap", using separator "sep". 793 * When "echo_style" is TRUE use String as echoed, otherwise as inside a List. 794 * Return FAIL or OK. 795 */ 796 int 797 list_join( 798 garray_T *gap, 799 list_T *l, 800 char_u *sep, 801 int echo_style, 802 int restore_copyID, 803 int copyID) 804 { 805 garray_T join_ga; 806 int retval; 807 join_T *p; 808 int i; 809 810 if (l->lv_len < 1) 811 return OK; /* nothing to do */ 812 ga_init2(&join_ga, (int)sizeof(join_T), l->lv_len); 813 retval = list_join_inner(gap, l, sep, echo_style, restore_copyID, 814 copyID, &join_ga); 815 816 /* Dispose each item in join_ga. */ 817 if (join_ga.ga_data != NULL) 818 { 819 p = (join_T *)join_ga.ga_data; 820 for (i = 0; i < join_ga.ga_len; ++i) 821 { 822 vim_free(p->tofree); 823 ++p; 824 } 825 ga_clear(&join_ga); 826 } 827 828 return retval; 829 } 830 831 /* 832 * Allocate a variable for a List and fill it from "*arg". 833 * Return OK or FAIL. 834 */ 835 int 836 get_list_tv(char_u **arg, typval_T *rettv, int evaluate) 837 { 838 list_T *l = NULL; 839 typval_T tv; 840 listitem_T *item; 841 842 if (evaluate) 843 { 844 l = list_alloc(); 845 if (l == NULL) 846 return FAIL; 847 } 848 849 *arg = skipwhite(*arg + 1); 850 while (**arg != ']' && **arg != NUL) 851 { 852 if (eval1(arg, &tv, evaluate) == FAIL) /* recursive! */ 853 goto failret; 854 if (evaluate) 855 { 856 item = listitem_alloc(); 857 if (item != NULL) 858 { 859 item->li_tv = tv; 860 item->li_tv.v_lock = 0; 861 list_append(l, item); 862 } 863 else 864 clear_tv(&tv); 865 } 866 867 if (**arg == ']') 868 break; 869 if (**arg != ',') 870 { 871 EMSG2(_("E696: Missing comma in List: %s"), *arg); 872 goto failret; 873 } 874 *arg = skipwhite(*arg + 1); 875 } 876 877 if (**arg != ']') 878 { 879 EMSG2(_("E697: Missing end of List ']': %s"), *arg); 880 failret: 881 if (evaluate) 882 list_free(l); 883 return FAIL; 884 } 885 886 *arg = skipwhite(*arg + 1); 887 if (evaluate) 888 rettv_list_set(rettv, l); 889 890 return OK; 891 } 892 893 /* 894 * Write "list" of strings to file "fd". 895 */ 896 int 897 write_list(FILE *fd, list_T *list, int binary) 898 { 899 listitem_T *li; 900 int c; 901 int ret = OK; 902 char_u *s; 903 904 for (li = list->lv_first; li != NULL; li = li->li_next) 905 { 906 for (s = get_tv_string(&li->li_tv); *s != NUL; ++s) 907 { 908 if (*s == '\n') 909 c = putc(NUL, fd); 910 else 911 c = putc(*s, fd); 912 if (c == EOF) 913 { 914 ret = FAIL; 915 break; 916 } 917 } 918 if (!binary || li->li_next != NULL) 919 if (putc('\n', fd) == EOF) 920 { 921 ret = FAIL; 922 break; 923 } 924 if (ret == FAIL) 925 { 926 EMSG(_(e_write)); 927 break; 928 } 929 } 930 return ret; 931 } 932 933 /* 934 * Initialize a static list with 10 items. 935 */ 936 void 937 init_static_list(staticList10_T *sl) 938 { 939 list_T *l = &sl->sl_list; 940 int i; 941 942 memset(sl, 0, sizeof(staticList10_T)); 943 l->lv_first = &sl->sl_items[0]; 944 l->lv_last = &sl->sl_items[9]; 945 l->lv_refcount = DO_NOT_FREE_CNT; 946 l->lv_lock = VAR_FIXED; 947 sl->sl_list.lv_len = 10; 948 949 for (i = 0; i < 10; ++i) 950 { 951 listitem_T *li = &sl->sl_items[i]; 952 953 if (i == 0) 954 li->li_prev = NULL; 955 else 956 li->li_prev = li - 1; 957 if (i == 9) 958 li->li_next = NULL; 959 else 960 li->li_next = li + 1; 961 } 962 } 963 964 #endif /* defined(FEAT_EVAL) */ 965