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 or special entry to dictionary "d". 346 * Returns FAIL when out of memory and when key already exists. 347 */ 348 static int 349 dict_add_number_special(dict_T *d, char *key, varnumber_T nr, int special) 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 = special ? VAR_SPECIAL : 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 number entry to dictionary "d". 368 * Returns FAIL when out of memory and when key already exists. 369 */ 370 int 371 dict_add_number(dict_T *d, char *key, varnumber_T nr) 372 { 373 return dict_add_number_special(d, key, nr, FALSE); 374 } 375 376 /* 377 * Add a special entry to dictionary "d". 378 * Returns FAIL when out of memory and when key already exists. 379 */ 380 int 381 dict_add_special(dict_T *d, char *key, varnumber_T nr) 382 { 383 return dict_add_number_special(d, key, nr, TRUE); 384 } 385 386 /* 387 * Add a string entry to dictionary "d". 388 * Returns FAIL when out of memory and when key already exists. 389 */ 390 int 391 dict_add_string(dict_T *d, char *key, char_u *str) 392 { 393 return dict_add_string_len(d, key, str, -1); 394 } 395 396 /* 397 * Add a string entry to dictionary "d". 398 * "str" will be copied to allocated memory. 399 * When "len" is -1 use the whole string, otherwise only this many bytes. 400 * Returns FAIL when out of memory and when key already exists. 401 */ 402 int 403 dict_add_string_len(dict_T *d, char *key, char_u *str, int len) 404 { 405 dictitem_T *item; 406 char_u *val = NULL; 407 408 item = dictitem_alloc((char_u *)key); 409 if (item == NULL) 410 return FAIL; 411 item->di_tv.v_type = VAR_STRING; 412 if (str != NULL) 413 { 414 if (len == -1) 415 val = vim_strsave(str); 416 else 417 val = vim_strnsave(str, len); 418 } 419 item->di_tv.vval.v_string = val; 420 if (dict_add(d, item) == FAIL) 421 { 422 dictitem_free(item); 423 return FAIL; 424 } 425 return OK; 426 } 427 428 /* 429 * Add a list entry to dictionary "d". 430 * Returns FAIL when out of memory and when key already exists. 431 */ 432 int 433 dict_add_list(dict_T *d, char *key, list_T *list) 434 { 435 dictitem_T *item; 436 437 item = dictitem_alloc((char_u *)key); 438 if (item == NULL) 439 return FAIL; 440 item->di_tv.v_type = VAR_LIST; 441 item->di_tv.vval.v_list = list; 442 ++list->lv_refcount; 443 if (dict_add(d, item) == FAIL) 444 { 445 dictitem_free(item); 446 return FAIL; 447 } 448 return OK; 449 } 450 451 /* 452 * Initializes "iter" for iterating over dictionary items with 453 * dict_iterate_next(). 454 * If "var" is not a Dict or an empty Dict then there will be nothing to 455 * iterate over, no error is given. 456 * NOTE: The dictionary must not change until iterating is finished! 457 */ 458 void 459 dict_iterate_start(typval_T *var, dict_iterator_T *iter) 460 { 461 if (var->v_type != VAR_DICT || var->vval.v_dict == NULL) 462 iter->dit_todo = 0; 463 else 464 { 465 dict_T *d = var->vval.v_dict; 466 467 iter->dit_todo = d->dv_hashtab.ht_used; 468 iter->dit_hi = d->dv_hashtab.ht_array; 469 } 470 } 471 472 /* 473 * Iterate over the items referred to by "iter". It should be initialized with 474 * dict_iterate_start(). 475 * Returns a pointer to the key. 476 * "*tv_result" is set to point to the value for that key. 477 * If there are no more items, NULL is returned. 478 */ 479 char_u * 480 dict_iterate_next(dict_iterator_T *iter, typval_T **tv_result) 481 { 482 dictitem_T *di; 483 char_u *result; 484 485 if (iter->dit_todo == 0) 486 return NULL; 487 488 while (HASHITEM_EMPTY(iter->dit_hi)) 489 ++iter->dit_hi; 490 491 di = HI2DI(iter->dit_hi); 492 result = di->di_key; 493 *tv_result = &di->di_tv; 494 495 --iter->dit_todo; 496 ++iter->dit_hi; 497 return result; 498 } 499 500 /* 501 * Add a dict entry to dictionary "d". 502 * Returns FAIL when out of memory and when key already exists. 503 */ 504 int 505 dict_add_dict(dict_T *d, char *key, dict_T *dict) 506 { 507 dictitem_T *item; 508 509 item = dictitem_alloc((char_u *)key); 510 if (item == NULL) 511 return FAIL; 512 item->di_tv.v_type = VAR_DICT; 513 item->di_tv.vval.v_dict = dict; 514 ++dict->dv_refcount; 515 if (dict_add(d, item) == FAIL) 516 { 517 dictitem_free(item); 518 return FAIL; 519 } 520 return OK; 521 } 522 523 /* 524 * Get the number of items in a Dictionary. 525 */ 526 long 527 dict_len(dict_T *d) 528 { 529 if (d == NULL) 530 return 0L; 531 return (long)d->dv_hashtab.ht_used; 532 } 533 534 /* 535 * Find item "key[len]" in Dictionary "d". 536 * If "len" is negative use strlen(key). 537 * Returns NULL when not found. 538 */ 539 dictitem_T * 540 dict_find(dict_T *d, char_u *key, int len) 541 { 542 #define AKEYLEN 200 543 char_u buf[AKEYLEN]; 544 char_u *akey; 545 char_u *tofree = NULL; 546 hashitem_T *hi; 547 548 if (d == NULL) 549 return NULL; 550 if (len < 0) 551 akey = key; 552 else if (len >= AKEYLEN) 553 { 554 tofree = akey = vim_strnsave(key, len); 555 if (akey == NULL) 556 return NULL; 557 } 558 else 559 { 560 /* Avoid a malloc/free by using buf[]. */ 561 vim_strncpy(buf, key, len); 562 akey = buf; 563 } 564 565 hi = hash_find(&d->dv_hashtab, akey); 566 vim_free(tofree); 567 if (HASHITEM_EMPTY(hi)) 568 return NULL; 569 return HI2DI(hi); 570 } 571 572 /* 573 * Get a string item from a dictionary. 574 * When "save" is TRUE allocate memory for it. 575 * When FALSE a shared buffer is used, can only be used once! 576 * Returns NULL if the entry doesn't exist or out of memory. 577 */ 578 char_u * 579 dict_get_string(dict_T *d, char_u *key, int save) 580 { 581 dictitem_T *di; 582 char_u *s; 583 584 di = dict_find(d, key, -1); 585 if (di == NULL) 586 return NULL; 587 s = tv_get_string(&di->di_tv); 588 if (save && s != NULL) 589 s = vim_strsave(s); 590 return s; 591 } 592 593 /* 594 * Get a number item from a dictionary. 595 * Returns 0 if the entry doesn't exist. 596 */ 597 varnumber_T 598 dict_get_number(dict_T *d, char_u *key) 599 { 600 dictitem_T *di; 601 602 di = dict_find(d, key, -1); 603 if (di == NULL) 604 return 0; 605 return tv_get_number(&di->di_tv); 606 } 607 608 /* 609 * Return an allocated string with the string representation of a Dictionary. 610 * May return NULL. 611 */ 612 char_u * 613 dict2string(typval_T *tv, int copyID, int restore_copyID) 614 { 615 garray_T ga; 616 int first = TRUE; 617 char_u *tofree; 618 char_u numbuf[NUMBUFLEN]; 619 hashitem_T *hi; 620 char_u *s; 621 dict_T *d; 622 int todo; 623 624 if ((d = tv->vval.v_dict) == NULL) 625 return NULL; 626 ga_init2(&ga, (int)sizeof(char), 80); 627 ga_append(&ga, '{'); 628 629 todo = (int)d->dv_hashtab.ht_used; 630 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi) 631 { 632 if (!HASHITEM_EMPTY(hi)) 633 { 634 --todo; 635 636 if (first) 637 first = FALSE; 638 else 639 ga_concat(&ga, (char_u *)", "); 640 641 tofree = string_quote(hi->hi_key, FALSE); 642 if (tofree != NULL) 643 { 644 ga_concat(&ga, tofree); 645 vim_free(tofree); 646 } 647 ga_concat(&ga, (char_u *)": "); 648 s = echo_string_core(&HI2DI(hi)->di_tv, &tofree, numbuf, copyID, 649 FALSE, restore_copyID, TRUE); 650 if (s != NULL) 651 ga_concat(&ga, s); 652 vim_free(tofree); 653 if (s == NULL || did_echo_string_emsg) 654 break; 655 line_breakcheck(); 656 657 } 658 } 659 if (todo > 0) 660 { 661 vim_free(ga.ga_data); 662 return NULL; 663 } 664 665 ga_append(&ga, '}'); 666 ga_append(&ga, NUL); 667 return (char_u *)ga.ga_data; 668 } 669 670 /* 671 * Allocate a variable for a Dictionary and fill it from "*arg". 672 * Return OK or FAIL. Returns NOTDONE for {expr}. 673 */ 674 int 675 dict_get_tv(char_u **arg, typval_T *rettv, int evaluate) 676 { 677 dict_T *d = NULL; 678 typval_T tvkey; 679 typval_T tv; 680 char_u *key = NULL; 681 dictitem_T *item; 682 char_u *start = skipwhite(*arg + 1); 683 char_u buf[NUMBUFLEN]; 684 685 /* 686 * First check if it's not a curly-braces thing: {expr}. 687 * Must do this without evaluating, otherwise a function may be called 688 * twice. Unfortunately this means we need to call eval1() twice for the 689 * first item. 690 * But {} is an empty Dictionary. 691 */ 692 if (*start != '}') 693 { 694 if (eval1(&start, &tv, FALSE) == FAIL) /* recursive! */ 695 return FAIL; 696 if (*start == '}') 697 return NOTDONE; 698 } 699 700 if (evaluate) 701 { 702 d = dict_alloc(); 703 if (d == NULL) 704 return FAIL; 705 } 706 tvkey.v_type = VAR_UNKNOWN; 707 tv.v_type = VAR_UNKNOWN; 708 709 *arg = skipwhite(*arg + 1); 710 while (**arg != '}' && **arg != NUL) 711 { 712 if (eval1(arg, &tvkey, evaluate) == FAIL) /* recursive! */ 713 goto failret; 714 if (**arg != ':') 715 { 716 semsg(_("E720: Missing colon in Dictionary: %s"), *arg); 717 clear_tv(&tvkey); 718 goto failret; 719 } 720 if (evaluate) 721 { 722 key = tv_get_string_buf_chk(&tvkey, buf); 723 if (key == NULL) 724 { 725 /* "key" is NULL when tv_get_string_buf_chk() gave an errmsg */ 726 clear_tv(&tvkey); 727 goto failret; 728 } 729 } 730 731 *arg = skipwhite(*arg + 1); 732 if (eval1(arg, &tv, evaluate) == FAIL) /* recursive! */ 733 { 734 if (evaluate) 735 clear_tv(&tvkey); 736 goto failret; 737 } 738 if (evaluate) 739 { 740 item = dict_find(d, key, -1); 741 if (item != NULL) 742 { 743 semsg(_("E721: Duplicate key in Dictionary: \"%s\""), key); 744 clear_tv(&tvkey); 745 clear_tv(&tv); 746 goto failret; 747 } 748 item = dictitem_alloc(key); 749 clear_tv(&tvkey); 750 if (item != NULL) 751 { 752 item->di_tv = tv; 753 item->di_tv.v_lock = 0; 754 if (dict_add(d, item) == FAIL) 755 dictitem_free(item); 756 } 757 } 758 759 if (**arg == '}') 760 break; 761 if (**arg != ',') 762 { 763 semsg(_("E722: Missing comma in Dictionary: %s"), *arg); 764 goto failret; 765 } 766 *arg = skipwhite(*arg + 1); 767 } 768 769 if (**arg != '}') 770 { 771 semsg(_("E723: Missing end of Dictionary '}': %s"), *arg); 772 failret: 773 if (evaluate) 774 dict_free(d); 775 return FAIL; 776 } 777 778 *arg = skipwhite(*arg + 1); 779 if (evaluate) 780 rettv_dict_set(rettv, d); 781 782 return OK; 783 } 784 785 /* 786 * Go over all entries in "d2" and add them to "d1". 787 * When "action" is "error" then a duplicate key is an error. 788 * When "action" is "force" then a duplicate key is overwritten. 789 * Otherwise duplicate keys are ignored ("action" is "keep"). 790 */ 791 void 792 dict_extend(dict_T *d1, dict_T *d2, char_u *action) 793 { 794 dictitem_T *di1; 795 hashitem_T *hi2; 796 int todo; 797 char_u *arg_errmsg = (char_u *)N_("extend() argument"); 798 799 todo = (int)d2->dv_hashtab.ht_used; 800 for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2) 801 { 802 if (!HASHITEM_EMPTY(hi2)) 803 { 804 --todo; 805 di1 = dict_find(d1, hi2->hi_key, -1); 806 if (d1->dv_scope != 0) 807 { 808 /* Disallow replacing a builtin function in l: and g:. 809 * Check the key to be valid when adding to any scope. */ 810 if (d1->dv_scope == VAR_DEF_SCOPE 811 && HI2DI(hi2)->di_tv.v_type == VAR_FUNC 812 && var_check_func_name(hi2->hi_key, di1 == NULL)) 813 break; 814 if (!valid_varname(hi2->hi_key)) 815 break; 816 } 817 if (di1 == NULL) 818 { 819 di1 = dictitem_copy(HI2DI(hi2)); 820 if (di1 != NULL && dict_add(d1, di1) == FAIL) 821 dictitem_free(di1); 822 } 823 else if (*action == 'e') 824 { 825 semsg(_("E737: Key already exists: %s"), hi2->hi_key); 826 break; 827 } 828 else if (*action == 'f' && HI2DI(hi2) != di1) 829 { 830 if (var_check_lock(di1->di_tv.v_lock, arg_errmsg, TRUE) 831 || var_check_ro(di1->di_flags, arg_errmsg, TRUE)) 832 break; 833 clear_tv(&di1->di_tv); 834 copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv); 835 } 836 } 837 } 838 } 839 840 /* 841 * Return the dictitem that an entry in a hashtable points to. 842 */ 843 dictitem_T * 844 dict_lookup(hashitem_T *hi) 845 { 846 return HI2DI(hi); 847 } 848 849 /* 850 * Return TRUE when two dictionaries have exactly the same key/values. 851 */ 852 int 853 dict_equal( 854 dict_T *d1, 855 dict_T *d2, 856 int ic, /* ignore case for strings */ 857 int recursive) /* TRUE when used recursively */ 858 { 859 hashitem_T *hi; 860 dictitem_T *item2; 861 int todo; 862 863 if (d1 == NULL && d2 == NULL) 864 return TRUE; 865 if (d1 == NULL || d2 == NULL) 866 return FALSE; 867 if (d1 == d2) 868 return TRUE; 869 if (dict_len(d1) != dict_len(d2)) 870 return FALSE; 871 872 todo = (int)d1->dv_hashtab.ht_used; 873 for (hi = d1->dv_hashtab.ht_array; todo > 0; ++hi) 874 { 875 if (!HASHITEM_EMPTY(hi)) 876 { 877 item2 = dict_find(d2, hi->hi_key, -1); 878 if (item2 == NULL) 879 return FALSE; 880 if (!tv_equal(&HI2DI(hi)->di_tv, &item2->di_tv, ic, recursive)) 881 return FALSE; 882 --todo; 883 } 884 } 885 return TRUE; 886 } 887 888 /* 889 * Turn a dict into a list: 890 * "what" == 0: list of keys 891 * "what" == 1: list of values 892 * "what" == 2: list of items 893 */ 894 void 895 dict_list(typval_T *argvars, typval_T *rettv, int what) 896 { 897 list_T *l2; 898 dictitem_T *di; 899 hashitem_T *hi; 900 listitem_T *li; 901 listitem_T *li2; 902 dict_T *d; 903 int todo; 904 905 if (argvars[0].v_type != VAR_DICT) 906 { 907 emsg(_(e_dictreq)); 908 return; 909 } 910 if ((d = argvars[0].vval.v_dict) == NULL) 911 return; 912 913 if (rettv_list_alloc(rettv) == FAIL) 914 return; 915 916 todo = (int)d->dv_hashtab.ht_used; 917 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) 918 { 919 if (!HASHITEM_EMPTY(hi)) 920 { 921 --todo; 922 di = HI2DI(hi); 923 924 li = listitem_alloc(); 925 if (li == NULL) 926 break; 927 list_append(rettv->vval.v_list, li); 928 929 if (what == 0) 930 { 931 /* keys() */ 932 li->li_tv.v_type = VAR_STRING; 933 li->li_tv.v_lock = 0; 934 li->li_tv.vval.v_string = vim_strsave(di->di_key); 935 } 936 else if (what == 1) 937 { 938 /* values() */ 939 copy_tv(&di->di_tv, &li->li_tv); 940 } 941 else 942 { 943 /* items() */ 944 l2 = list_alloc(); 945 li->li_tv.v_type = VAR_LIST; 946 li->li_tv.v_lock = 0; 947 li->li_tv.vval.v_list = l2; 948 if (l2 == NULL) 949 break; 950 ++l2->lv_refcount; 951 952 li2 = listitem_alloc(); 953 if (li2 == NULL) 954 break; 955 list_append(l2, li2); 956 li2->li_tv.v_type = VAR_STRING; 957 li2->li_tv.v_lock = 0; 958 li2->li_tv.vval.v_string = vim_strsave(di->di_key); 959 960 li2 = listitem_alloc(); 961 if (li2 == NULL) 962 break; 963 list_append(l2, li2); 964 copy_tv(&di->di_tv, &li2->li_tv); 965 } 966 } 967 } 968 } 969 970 /* 971 * Make each item in the dict readonly (not the value of the item). 972 */ 973 void 974 dict_set_items_ro(dict_T *di) 975 { 976 int todo = (int)di->dv_hashtab.ht_used; 977 hashitem_T *hi; 978 979 /* Set readonly */ 980 for (hi = di->dv_hashtab.ht_array; todo > 0 ; ++hi) 981 { 982 if (HASHITEM_EMPTY(hi)) 983 continue; 984 --todo; 985 HI2DI(hi)->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX; 986 } 987 } 988 989 #endif /* defined(FEAT_EVAL) */ 990