xref: /vim-8.2.3635/src/dict.c (revision ba3ff539)
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