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