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 * dict.c: Dictionary support 12 */ 13 14 #include "vim.h" 15 16 #if defined(FEAT_EVAL) || defined(PROTO) 17 18 /* List head for garbage collection. Although there can be a reference loop 19 * from partial to dict to partial, we don't need to keep track of the partial, 20 * since it will get freed when the dict is unused and gets freed. */ 21 static dict_T *first_dict = NULL; /* list of all dicts */ 22 23 /* 24 * Allocate an empty header for a dictionary. 25 */ 26 dict_T * 27 dict_alloc(void) 28 { 29 dict_T *d; 30 31 d = (dict_T *)alloc(sizeof(dict_T)); 32 if (d != NULL) 33 { 34 /* Add the dict to the list of dicts for garbage collection. */ 35 if (first_dict != NULL) 36 first_dict->dv_used_prev = d; 37 d->dv_used_next = first_dict; 38 d->dv_used_prev = NULL; 39 first_dict = d; 40 41 hash_init(&d->dv_hashtab); 42 d->dv_lock = 0; 43 d->dv_scope = 0; 44 d->dv_refcount = 0; 45 d->dv_copyID = 0; 46 } 47 return d; 48 } 49 50 dict_T * 51 dict_alloc_lock(int lock) 52 { 53 dict_T *d = dict_alloc(); 54 55 if (d != NULL) 56 d->dv_lock = lock; 57 return d; 58 } 59 60 /* 61 * Allocate an empty dict for a return value. 62 * Returns OK or FAIL. 63 */ 64 int 65 rettv_dict_alloc(typval_T *rettv) 66 { 67 dict_T *d = dict_alloc_lock(0); 68 69 if (d == NULL) 70 return FAIL; 71 72 rettv_dict_set(rettv, d); 73 return OK; 74 } 75 76 /* 77 * Set a dictionary as the return value 78 */ 79 void 80 rettv_dict_set(typval_T *rettv, dict_T *d) 81 { 82 rettv->v_type = VAR_DICT; 83 rettv->vval.v_dict = d; 84 if (d != NULL) 85 ++d->dv_refcount; 86 } 87 88 /* 89 * Free a Dictionary, including all non-container items it contains. 90 * Ignores the reference count. 91 */ 92 void 93 dict_free_contents(dict_T *d) 94 { 95 int todo; 96 hashitem_T *hi; 97 dictitem_T *di; 98 99 /* Lock the hashtab, we don't want it to resize while freeing items. */ 100 hash_lock(&d->dv_hashtab); 101 todo = (int)d->dv_hashtab.ht_used; 102 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) 103 { 104 if (!HASHITEM_EMPTY(hi)) 105 { 106 /* Remove the item before deleting it, just in case there is 107 * something recursive causing trouble. */ 108 di = HI2DI(hi); 109 hash_remove(&d->dv_hashtab, hi); 110 dictitem_free(di); 111 --todo; 112 } 113 } 114 115 /* The hashtab is still locked, it has to be re-initialized anyway */ 116 hash_clear(&d->dv_hashtab); 117 } 118 119 static void 120 dict_free_dict(dict_T *d) 121 { 122 /* Remove the dict from the list of dicts for garbage collection. */ 123 if (d->dv_used_prev == NULL) 124 first_dict = d->dv_used_next; 125 else 126 d->dv_used_prev->dv_used_next = d->dv_used_next; 127 if (d->dv_used_next != NULL) 128 d->dv_used_next->dv_used_prev = d->dv_used_prev; 129 vim_free(d); 130 } 131 132 static void 133 dict_free(dict_T *d) 134 { 135 if (!in_free_unref_items) 136 { 137 dict_free_contents(d); 138 dict_free_dict(d); 139 } 140 } 141 142 /* 143 * Unreference a Dictionary: decrement the reference count and free it when it 144 * becomes zero. 145 */ 146 void 147 dict_unref(dict_T *d) 148 { 149 if (d != NULL && --d->dv_refcount <= 0) 150 dict_free(d); 151 } 152 153 /* 154 * Go through the list of dicts and free items without the copyID. 155 * Returns TRUE if something was freed. 156 */ 157 int 158 dict_free_nonref(int copyID) 159 { 160 dict_T *dd; 161 int did_free = FALSE; 162 163 for (dd = first_dict; dd != NULL; dd = dd->dv_used_next) 164 if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) 165 { 166 /* Free the Dictionary and ordinary items it contains, but don't 167 * recurse into Lists and Dictionaries, they will be in the list 168 * of dicts or list of lists. */ 169 dict_free_contents(dd); 170 did_free = TRUE; 171 } 172 return did_free; 173 } 174 175 void 176 dict_free_items(int copyID) 177 { 178 dict_T *dd, *dd_next; 179 180 for (dd = first_dict; dd != NULL; dd = dd_next) 181 { 182 dd_next = dd->dv_used_next; 183 if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) 184 dict_free_dict(dd); 185 } 186 } 187 188 /* 189 * Allocate a Dictionary item. 190 * The "key" is copied to the new item. 191 * Note that the type and value of the item "di_tv" still needs to be 192 * initialized! 193 * Returns NULL when out of memory. 194 */ 195 dictitem_T * 196 dictitem_alloc(char_u *key) 197 { 198 dictitem_T *di; 199 200 di = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T) + STRLEN(key))); 201 if (di != NULL) 202 { 203 STRCPY(di->di_key, key); 204 di->di_flags = DI_FLAGS_ALLOC; 205 di->di_tv.v_lock = 0; 206 } 207 return di; 208 } 209 210 /* 211 * Make a copy of a Dictionary item. 212 */ 213 static dictitem_T * 214 dictitem_copy(dictitem_T *org) 215 { 216 dictitem_T *di; 217 218 di = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T) 219 + STRLEN(org->di_key))); 220 if (di != NULL) 221 { 222 STRCPY(di->di_key, org->di_key); 223 di->di_flags = DI_FLAGS_ALLOC; 224 copy_tv(&org->di_tv, &di->di_tv); 225 } 226 return di; 227 } 228 229 /* 230 * Remove item "item" from Dictionary "dict" and free it. 231 */ 232 void 233 dictitem_remove(dict_T *dict, dictitem_T *item) 234 { 235 hashitem_T *hi; 236 237 hi = hash_find(&dict->dv_hashtab, item->di_key); 238 if (HASHITEM_EMPTY(hi)) 239 internal_error("dictitem_remove()"); 240 else 241 hash_remove(&dict->dv_hashtab, hi); 242 dictitem_free(item); 243 } 244 245 /* 246 * Free a dict item. Also clears the value. 247 */ 248 void 249 dictitem_free(dictitem_T *item) 250 { 251 clear_tv(&item->di_tv); 252 if (item->di_flags & DI_FLAGS_ALLOC) 253 vim_free(item); 254 } 255 256 /* 257 * Make a copy of dict "d". Shallow if "deep" is FALSE. 258 * The refcount of the new dict is set to 1. 259 * See item_copy() for "copyID". 260 * Returns NULL when out of memory. 261 */ 262 dict_T * 263 dict_copy(dict_T *orig, int deep, int copyID) 264 { 265 dict_T *copy; 266 dictitem_T *di; 267 int todo; 268 hashitem_T *hi; 269 270 if (orig == NULL) 271 return NULL; 272 273 copy = dict_alloc(); 274 if (copy != NULL) 275 { 276 if (copyID != 0) 277 { 278 orig->dv_copyID = copyID; 279 orig->dv_copydict = copy; 280 } 281 todo = (int)orig->dv_hashtab.ht_used; 282 for (hi = orig->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi) 283 { 284 if (!HASHITEM_EMPTY(hi)) 285 { 286 --todo; 287 288 di = dictitem_alloc(hi->hi_key); 289 if (di == NULL) 290 break; 291 if (deep) 292 { 293 if (item_copy(&HI2DI(hi)->di_tv, &di->di_tv, deep, 294 copyID) == FAIL) 295 { 296 vim_free(di); 297 break; 298 } 299 } 300 else 301 copy_tv(&HI2DI(hi)->di_tv, &di->di_tv); 302 if (dict_add(copy, di) == FAIL) 303 { 304 dictitem_free(di); 305 break; 306 } 307 } 308 } 309 310 ++copy->dv_refcount; 311 if (todo > 0) 312 { 313 dict_unref(copy); 314 copy = NULL; 315 } 316 } 317 318 return copy; 319 } 320 321 /* 322 * Add item "item" to Dictionary "d". 323 * Returns FAIL when out of memory and when key already exists. 324 */ 325 int 326 dict_add(dict_T *d, dictitem_T *item) 327 { 328 return hash_add(&d->dv_hashtab, item->di_key); 329 } 330 331 /* 332 * Add a number entry to dictionary "d". 333 * Returns FAIL when out of memory and when key already exists. 334 */ 335 int 336 dict_add_number(dict_T *d, char *key, varnumber_T nr) 337 { 338 dictitem_T *item; 339 340 item = dictitem_alloc((char_u *)key); 341 if (item == NULL) 342 return FAIL; 343 item->di_tv.v_type = VAR_NUMBER; 344 item->di_tv.vval.v_number = nr; 345 if (dict_add(d, item) == FAIL) 346 { 347 dictitem_free(item); 348 return FAIL; 349 } 350 return OK; 351 } 352 353 /* 354 * Add a string entry to dictionary "d". 355 * Returns FAIL when out of memory and when key already exists. 356 */ 357 int 358 dict_add_string(dict_T *d, char *key, char_u *str) 359 { 360 dictitem_T *item; 361 362 item = dictitem_alloc((char_u *)key); 363 if (item == NULL) 364 return FAIL; 365 item->di_tv.v_type = VAR_STRING; 366 item->di_tv.vval.v_string = str != NULL ? vim_strsave(str) : NULL; 367 if (dict_add(d, item) == FAIL) 368 { 369 dictitem_free(item); 370 return FAIL; 371 } 372 return OK; 373 } 374 375 /* 376 * Add a list entry to dictionary "d". 377 * Returns FAIL when out of memory and when key already exists. 378 */ 379 int 380 dict_add_list(dict_T *d, char *key, list_T *list) 381 { 382 dictitem_T *item; 383 384 item = dictitem_alloc((char_u *)key); 385 if (item == NULL) 386 return FAIL; 387 item->di_tv.v_type = VAR_LIST; 388 item->di_tv.vval.v_list = list; 389 ++list->lv_refcount; 390 if (dict_add(d, item) == FAIL) 391 { 392 dictitem_free(item); 393 return FAIL; 394 } 395 return OK; 396 } 397 398 /* 399 * Add a dict entry to dictionary "d". 400 * Returns FAIL when out of memory and when key already exists. 401 */ 402 int 403 dict_add_dict(dict_T *d, char *key, dict_T *dict) 404 { 405 dictitem_T *item; 406 407 item = dictitem_alloc((char_u *)key); 408 if (item == NULL) 409 return FAIL; 410 item->di_tv.v_type = VAR_DICT; 411 item->di_tv.vval.v_dict = dict; 412 ++dict->dv_refcount; 413 if (dict_add(d, item) == FAIL) 414 { 415 dictitem_free(item); 416 return FAIL; 417 } 418 return OK; 419 } 420 421 /* 422 * Get the number of items in a Dictionary. 423 */ 424 long 425 dict_len(dict_T *d) 426 { 427 if (d == NULL) 428 return 0L; 429 return (long)d->dv_hashtab.ht_used; 430 } 431 432 /* 433 * Find item "key[len]" in Dictionary "d". 434 * If "len" is negative use strlen(key). 435 * Returns NULL when not found. 436 */ 437 dictitem_T * 438 dict_find(dict_T *d, char_u *key, int len) 439 { 440 #define AKEYLEN 200 441 char_u buf[AKEYLEN]; 442 char_u *akey; 443 char_u *tofree = NULL; 444 hashitem_T *hi; 445 446 if (d == NULL) 447 return NULL; 448 if (len < 0) 449 akey = key; 450 else if (len >= AKEYLEN) 451 { 452 tofree = akey = vim_strnsave(key, len); 453 if (akey == NULL) 454 return NULL; 455 } 456 else 457 { 458 /* Avoid a malloc/free by using buf[]. */ 459 vim_strncpy(buf, key, len); 460 akey = buf; 461 } 462 463 hi = hash_find(&d->dv_hashtab, akey); 464 vim_free(tofree); 465 if (HASHITEM_EMPTY(hi)) 466 return NULL; 467 return HI2DI(hi); 468 } 469 470 /* 471 * Get a string item from a dictionary. 472 * When "save" is TRUE allocate memory for it. 473 * When FALSE a shared buffer is used, can only be used once! 474 * Returns NULL if the entry doesn't exist or out of memory. 475 */ 476 char_u * 477 get_dict_string(dict_T *d, char_u *key, int save) 478 { 479 dictitem_T *di; 480 char_u *s; 481 482 di = dict_find(d, key, -1); 483 if (di == NULL) 484 return NULL; 485 s = get_tv_string(&di->di_tv); 486 if (save && s != NULL) 487 s = vim_strsave(s); 488 return s; 489 } 490 491 /* 492 * Get a number item from a dictionary. 493 * Returns 0 if the entry doesn't exist. 494 */ 495 varnumber_T 496 get_dict_number(dict_T *d, char_u *key) 497 { 498 dictitem_T *di; 499 500 di = dict_find(d, key, -1); 501 if (di == NULL) 502 return 0; 503 return get_tv_number(&di->di_tv); 504 } 505 506 /* 507 * Return an allocated string with the string representation of a Dictionary. 508 * May return NULL. 509 */ 510 char_u * 511 dict2string(typval_T *tv, int copyID, int restore_copyID) 512 { 513 garray_T ga; 514 int first = TRUE; 515 char_u *tofree; 516 char_u numbuf[NUMBUFLEN]; 517 hashitem_T *hi; 518 char_u *s; 519 dict_T *d; 520 int todo; 521 522 if ((d = tv->vval.v_dict) == NULL) 523 return NULL; 524 ga_init2(&ga, (int)sizeof(char), 80); 525 ga_append(&ga, '{'); 526 527 todo = (int)d->dv_hashtab.ht_used; 528 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi) 529 { 530 if (!HASHITEM_EMPTY(hi)) 531 { 532 --todo; 533 534 if (first) 535 first = FALSE; 536 else 537 ga_concat(&ga, (char_u *)", "); 538 539 tofree = string_quote(hi->hi_key, FALSE); 540 if (tofree != NULL) 541 { 542 ga_concat(&ga, tofree); 543 vim_free(tofree); 544 } 545 ga_concat(&ga, (char_u *)": "); 546 s = echo_string_core(&HI2DI(hi)->di_tv, &tofree, numbuf, copyID, 547 FALSE, restore_copyID, TRUE); 548 if (s != NULL) 549 ga_concat(&ga, s); 550 vim_free(tofree); 551 if (s == NULL || did_echo_string_emsg) 552 break; 553 line_breakcheck(); 554 555 } 556 } 557 if (todo > 0) 558 { 559 vim_free(ga.ga_data); 560 return NULL; 561 } 562 563 ga_append(&ga, '}'); 564 ga_append(&ga, NUL); 565 return (char_u *)ga.ga_data; 566 } 567 568 /* 569 * Allocate a variable for a Dictionary and fill it from "*arg". 570 * Return OK or FAIL. Returns NOTDONE for {expr}. 571 */ 572 int 573 get_dict_tv(char_u **arg, typval_T *rettv, int evaluate) 574 { 575 dict_T *d = NULL; 576 typval_T tvkey; 577 typval_T tv; 578 char_u *key = NULL; 579 dictitem_T *item; 580 char_u *start = skipwhite(*arg + 1); 581 char_u buf[NUMBUFLEN]; 582 583 /* 584 * First check if it's not a curly-braces thing: {expr}. 585 * Must do this without evaluating, otherwise a function may be called 586 * twice. Unfortunately this means we need to call eval1() twice for the 587 * first item. 588 * But {} is an empty Dictionary. 589 */ 590 if (*start != '}') 591 { 592 if (eval1(&start, &tv, FALSE) == FAIL) /* recursive! */ 593 return FAIL; 594 if (*start == '}') 595 return NOTDONE; 596 } 597 598 if (evaluate) 599 { 600 d = dict_alloc(); 601 if (d == NULL) 602 return FAIL; 603 } 604 tvkey.v_type = VAR_UNKNOWN; 605 tv.v_type = VAR_UNKNOWN; 606 607 *arg = skipwhite(*arg + 1); 608 while (**arg != '}' && **arg != NUL) 609 { 610 if (eval1(arg, &tvkey, evaluate) == FAIL) /* recursive! */ 611 goto failret; 612 if (**arg != ':') 613 { 614 EMSG2(_("E720: Missing colon in Dictionary: %s"), *arg); 615 clear_tv(&tvkey); 616 goto failret; 617 } 618 if (evaluate) 619 { 620 key = get_tv_string_buf_chk(&tvkey, buf); 621 if (key == NULL) 622 { 623 /* "key" is NULL when get_tv_string_buf_chk() gave an errmsg */ 624 clear_tv(&tvkey); 625 goto failret; 626 } 627 } 628 629 *arg = skipwhite(*arg + 1); 630 if (eval1(arg, &tv, evaluate) == FAIL) /* recursive! */ 631 { 632 if (evaluate) 633 clear_tv(&tvkey); 634 goto failret; 635 } 636 if (evaluate) 637 { 638 item = dict_find(d, key, -1); 639 if (item != NULL) 640 { 641 EMSG2(_("E721: Duplicate key in Dictionary: \"%s\""), key); 642 clear_tv(&tvkey); 643 clear_tv(&tv); 644 goto failret; 645 } 646 item = dictitem_alloc(key); 647 clear_tv(&tvkey); 648 if (item != NULL) 649 { 650 item->di_tv = tv; 651 item->di_tv.v_lock = 0; 652 if (dict_add(d, item) == FAIL) 653 dictitem_free(item); 654 } 655 } 656 657 if (**arg == '}') 658 break; 659 if (**arg != ',') 660 { 661 EMSG2(_("E722: Missing comma in Dictionary: %s"), *arg); 662 goto failret; 663 } 664 *arg = skipwhite(*arg + 1); 665 } 666 667 if (**arg != '}') 668 { 669 EMSG2(_("E723: Missing end of Dictionary '}': %s"), *arg); 670 failret: 671 if (evaluate) 672 dict_free(d); 673 return FAIL; 674 } 675 676 *arg = skipwhite(*arg + 1); 677 if (evaluate) 678 rettv_dict_set(rettv, d); 679 680 return OK; 681 } 682 683 /* 684 * Go over all entries in "d2" and add them to "d1". 685 * When "action" is "error" then a duplicate key is an error. 686 * When "action" is "force" then a duplicate key is overwritten. 687 * Otherwise duplicate keys are ignored ("action" is "keep"). 688 */ 689 void 690 dict_extend(dict_T *d1, dict_T *d2, char_u *action) 691 { 692 dictitem_T *di1; 693 hashitem_T *hi2; 694 int todo; 695 char_u *arg_errmsg = (char_u *)N_("extend() argument"); 696 697 todo = (int)d2->dv_hashtab.ht_used; 698 for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2) 699 { 700 if (!HASHITEM_EMPTY(hi2)) 701 { 702 --todo; 703 di1 = dict_find(d1, hi2->hi_key, -1); 704 if (d1->dv_scope != 0) 705 { 706 /* Disallow replacing a builtin function in l: and g:. 707 * Check the key to be valid when adding to any scope. */ 708 if (d1->dv_scope == VAR_DEF_SCOPE 709 && HI2DI(hi2)->di_tv.v_type == VAR_FUNC 710 && var_check_func_name(hi2->hi_key, di1 == NULL)) 711 break; 712 if (!valid_varname(hi2->hi_key)) 713 break; 714 } 715 if (di1 == NULL) 716 { 717 di1 = dictitem_copy(HI2DI(hi2)); 718 if (di1 != NULL && dict_add(d1, di1) == FAIL) 719 dictitem_free(di1); 720 } 721 else if (*action == 'e') 722 { 723 EMSG2(_("E737: Key already exists: %s"), hi2->hi_key); 724 break; 725 } 726 else if (*action == 'f' && HI2DI(hi2) != di1) 727 { 728 if (tv_check_lock(di1->di_tv.v_lock, arg_errmsg, TRUE) 729 || var_check_ro(di1->di_flags, arg_errmsg, TRUE)) 730 break; 731 clear_tv(&di1->di_tv); 732 copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv); 733 } 734 } 735 } 736 } 737 738 /* 739 * Return the dictitem that an entry in a hashtable points to. 740 */ 741 dictitem_T * 742 dict_lookup(hashitem_T *hi) 743 { 744 return HI2DI(hi); 745 } 746 747 /* 748 * Return TRUE when two dictionaries have exactly the same key/values. 749 */ 750 int 751 dict_equal( 752 dict_T *d1, 753 dict_T *d2, 754 int ic, /* ignore case for strings */ 755 int recursive) /* TRUE when used recursively */ 756 { 757 hashitem_T *hi; 758 dictitem_T *item2; 759 int todo; 760 761 if (d1 == NULL && d2 == NULL) 762 return TRUE; 763 if (d1 == NULL || d2 == NULL) 764 return FALSE; 765 if (d1 == d2) 766 return TRUE; 767 if (dict_len(d1) != dict_len(d2)) 768 return FALSE; 769 770 todo = (int)d1->dv_hashtab.ht_used; 771 for (hi = d1->dv_hashtab.ht_array; todo > 0; ++hi) 772 { 773 if (!HASHITEM_EMPTY(hi)) 774 { 775 item2 = dict_find(d2, hi->hi_key, -1); 776 if (item2 == NULL) 777 return FALSE; 778 if (!tv_equal(&HI2DI(hi)->di_tv, &item2->di_tv, ic, recursive)) 779 return FALSE; 780 --todo; 781 } 782 } 783 return TRUE; 784 } 785 786 /* 787 * Turn a dict into a list: 788 * "what" == 0: list of keys 789 * "what" == 1: list of values 790 * "what" == 2: list of items 791 */ 792 void 793 dict_list(typval_T *argvars, typval_T *rettv, int what) 794 { 795 list_T *l2; 796 dictitem_T *di; 797 hashitem_T *hi; 798 listitem_T *li; 799 listitem_T *li2; 800 dict_T *d; 801 int todo; 802 803 if (argvars[0].v_type != VAR_DICT) 804 { 805 EMSG(_(e_dictreq)); 806 return; 807 } 808 if ((d = argvars[0].vval.v_dict) == NULL) 809 return; 810 811 if (rettv_list_alloc(rettv) == FAIL) 812 return; 813 814 todo = (int)d->dv_hashtab.ht_used; 815 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) 816 { 817 if (!HASHITEM_EMPTY(hi)) 818 { 819 --todo; 820 di = HI2DI(hi); 821 822 li = listitem_alloc(); 823 if (li == NULL) 824 break; 825 list_append(rettv->vval.v_list, li); 826 827 if (what == 0) 828 { 829 /* keys() */ 830 li->li_tv.v_type = VAR_STRING; 831 li->li_tv.v_lock = 0; 832 li->li_tv.vval.v_string = vim_strsave(di->di_key); 833 } 834 else if (what == 1) 835 { 836 /* values() */ 837 copy_tv(&di->di_tv, &li->li_tv); 838 } 839 else 840 { 841 /* items() */ 842 l2 = list_alloc(); 843 li->li_tv.v_type = VAR_LIST; 844 li->li_tv.v_lock = 0; 845 li->li_tv.vval.v_list = l2; 846 if (l2 == NULL) 847 break; 848 ++l2->lv_refcount; 849 850 li2 = listitem_alloc(); 851 if (li2 == NULL) 852 break; 853 list_append(l2, li2); 854 li2->li_tv.v_type = VAR_STRING; 855 li2->li_tv.v_lock = 0; 856 li2->li_tv.vval.v_string = vim_strsave(di->di_key); 857 858 li2 = listitem_alloc(); 859 if (li2 == NULL) 860 break; 861 list_append(l2, li2); 862 copy_tv(&di->di_tv, &li2->li_tv); 863 } 864 } 865 } 866 } 867 868 /* 869 * Make each item in the dict readonly (not the value of the item). 870 */ 871 void 872 dict_set_items_ro(dict_T *di) 873 { 874 int todo = (int)di->dv_hashtab.ht_used; 875 hashitem_T *hi; 876 877 /* Set readonly */ 878 for (hi = di->dv_hashtab.ht_array; todo > 0 ; ++hi) 879 { 880 if (HASHITEM_EMPTY(hi)) 881 continue; 882 --todo; 883 HI2DI(hi)->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX; 884 } 885 } 886 887 #endif /* defined(FEAT_EVAL) */ 888