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;
22
23 /*
24 * Allocate an empty header for a dictionary.
25 * Caller should take care of the reference count.
26 */
27 dict_T *
dict_alloc(void)28 dict_alloc(void)
29 {
30 dict_T *d;
31
32 d = ALLOC_CLEAR_ONE(dict_T);
33 if (d != NULL)
34 {
35 // Add the dict to the list of dicts for garbage collection.
36 if (first_dict != NULL)
37 first_dict->dv_used_prev = d;
38 d->dv_used_next = first_dict;
39 d->dv_used_prev = NULL;
40 first_dict = d;
41
42 hash_init(&d->dv_hashtab);
43 d->dv_lock = 0;
44 d->dv_scope = 0;
45 d->dv_refcount = 0;
46 d->dv_copyID = 0;
47 }
48 return d;
49 }
50
51 /*
52 * dict_alloc() with an ID for alloc_fail().
53 */
54 dict_T *
dict_alloc_id(alloc_id_T id UNUSED)55 dict_alloc_id(alloc_id_T id UNUSED)
56 {
57 #ifdef FEAT_EVAL
58 if (alloc_fail_id == id && alloc_does_fail(sizeof(list_T)))
59 return NULL;
60 #endif
61 return (dict_alloc());
62 }
63
64 dict_T *
dict_alloc_lock(int lock)65 dict_alloc_lock(int lock)
66 {
67 dict_T *d = dict_alloc();
68
69 if (d != NULL)
70 d->dv_lock = lock;
71 return d;
72 }
73
74 /*
75 * Allocate an empty dict for a return value.
76 * Returns OK or FAIL.
77 */
78 int
rettv_dict_alloc(typval_T * rettv)79 rettv_dict_alloc(typval_T *rettv)
80 {
81 dict_T *d = dict_alloc_lock(0);
82
83 if (d == NULL)
84 return FAIL;
85
86 rettv_dict_set(rettv, d);
87 return OK;
88 }
89
90 /*
91 * Set a dictionary as the return value
92 */
93 void
rettv_dict_set(typval_T * rettv,dict_T * d)94 rettv_dict_set(typval_T *rettv, dict_T *d)
95 {
96 rettv->v_type = VAR_DICT;
97 rettv->vval.v_dict = d;
98 if (d != NULL)
99 ++d->dv_refcount;
100 }
101
102 /*
103 * Free a Dictionary, including all non-container items it contains.
104 * Ignores the reference count.
105 */
106 void
dict_free_contents(dict_T * d)107 dict_free_contents(dict_T *d)
108 {
109 hashtab_free_contents(&d->dv_hashtab);
110 free_type(d->dv_type);
111 d->dv_type = NULL;
112 }
113
114 /*
115 * Clear hashtab "ht" and dict items it contains.
116 * If "ht" is not freed then you should call hash_init() next!
117 */
118 void
hashtab_free_contents(hashtab_T * ht)119 hashtab_free_contents(hashtab_T *ht)
120 {
121 int todo;
122 hashitem_T *hi;
123 dictitem_T *di;
124
125 // Lock the hashtab, we don't want it to resize while freeing items.
126 hash_lock(ht);
127 todo = (int)ht->ht_used;
128 for (hi = ht->ht_array; todo > 0; ++hi)
129 {
130 if (!HASHITEM_EMPTY(hi))
131 {
132 // Remove the item before deleting it, just in case there is
133 // something recursive causing trouble.
134 di = HI2DI(hi);
135 hash_remove(ht, hi);
136 dictitem_free(di);
137 --todo;
138 }
139 }
140
141 // The hashtab is still locked, it has to be re-initialized anyway.
142 hash_clear(ht);
143 }
144
145 static void
dict_free_dict(dict_T * d)146 dict_free_dict(dict_T *d)
147 {
148 // Remove the dict from the list of dicts for garbage collection.
149 if (d->dv_used_prev == NULL)
150 first_dict = d->dv_used_next;
151 else
152 d->dv_used_prev->dv_used_next = d->dv_used_next;
153 if (d->dv_used_next != NULL)
154 d->dv_used_next->dv_used_prev = d->dv_used_prev;
155 vim_free(d);
156 }
157
158 static void
dict_free(dict_T * d)159 dict_free(dict_T *d)
160 {
161 if (!in_free_unref_items)
162 {
163 dict_free_contents(d);
164 dict_free_dict(d);
165 }
166 }
167
168 /*
169 * Unreference a Dictionary: decrement the reference count and free it when it
170 * becomes zero.
171 */
172 void
dict_unref(dict_T * d)173 dict_unref(dict_T *d)
174 {
175 if (d != NULL && --d->dv_refcount <= 0)
176 dict_free(d);
177 }
178
179 /*
180 * Go through the list of dicts and free items without the copyID.
181 * Returns TRUE if something was freed.
182 */
183 int
dict_free_nonref(int copyID)184 dict_free_nonref(int copyID)
185 {
186 dict_T *dd;
187 int did_free = FALSE;
188
189 for (dd = first_dict; dd != NULL; dd = dd->dv_used_next)
190 if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
191 {
192 // Free the Dictionary and ordinary items it contains, but don't
193 // recurse into Lists and Dictionaries, they will be in the list
194 // of dicts or list of lists.
195 dict_free_contents(dd);
196 did_free = TRUE;
197 }
198 return did_free;
199 }
200
201 void
dict_free_items(int copyID)202 dict_free_items(int copyID)
203 {
204 dict_T *dd, *dd_next;
205
206 for (dd = first_dict; dd != NULL; dd = dd_next)
207 {
208 dd_next = dd->dv_used_next;
209 if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
210 dict_free_dict(dd);
211 }
212 }
213
214 /*
215 * Allocate a Dictionary item.
216 * The "key" is copied to the new item.
217 * Note that the type and value of the item "di_tv" still needs to be
218 * initialized!
219 * Returns NULL when out of memory.
220 */
221 dictitem_T *
dictitem_alloc(char_u * key)222 dictitem_alloc(char_u *key)
223 {
224 dictitem_T *di;
225
226 di = alloc(offsetof(dictitem_T, di_key) + STRLEN(key) + 1);
227 if (di != NULL)
228 {
229 STRCPY(di->di_key, key);
230 di->di_flags = DI_FLAGS_ALLOC;
231 di->di_tv.v_lock = 0;
232 di->di_tv.v_type = VAR_UNKNOWN;
233 }
234 return di;
235 }
236
237 /*
238 * Make a copy of a Dictionary item.
239 */
240 static dictitem_T *
dictitem_copy(dictitem_T * org)241 dictitem_copy(dictitem_T *org)
242 {
243 dictitem_T *di;
244 size_t len = STRLEN(org->di_key);
245
246 di = alloc(offsetof(dictitem_T, di_key) + len + 1);
247 if (di != NULL)
248 {
249 mch_memmove(di->di_key, org->di_key, len + 1);
250 di->di_flags = DI_FLAGS_ALLOC;
251 copy_tv(&org->di_tv, &di->di_tv);
252 }
253 return di;
254 }
255
256 /*
257 * Remove item "item" from Dictionary "dict" and free it.
258 */
259 void
dictitem_remove(dict_T * dict,dictitem_T * item)260 dictitem_remove(dict_T *dict, dictitem_T *item)
261 {
262 hashitem_T *hi;
263
264 hi = hash_find(&dict->dv_hashtab, item->di_key);
265 if (HASHITEM_EMPTY(hi))
266 internal_error("dictitem_remove()");
267 else
268 hash_remove(&dict->dv_hashtab, hi);
269 dictitem_free(item);
270 }
271
272 /*
273 * Free a dict item. Also clears the value.
274 */
275 void
dictitem_free(dictitem_T * item)276 dictitem_free(dictitem_T *item)
277 {
278 clear_tv(&item->di_tv);
279 if (item->di_flags & DI_FLAGS_ALLOC)
280 vim_free(item);
281 }
282
283 /*
284 * Make a copy of dict "d". Shallow if "deep" is FALSE.
285 * The refcount of the new dict is set to 1.
286 * See item_copy() for "copyID".
287 * Returns NULL when out of memory.
288 */
289 dict_T *
dict_copy(dict_T * orig,int deep,int copyID)290 dict_copy(dict_T *orig, int deep, int copyID)
291 {
292 dict_T *copy;
293 dictitem_T *di;
294 int todo;
295 hashitem_T *hi;
296
297 if (orig == NULL)
298 return NULL;
299
300 copy = dict_alloc();
301 if (copy != NULL)
302 {
303 if (copyID != 0)
304 {
305 orig->dv_copyID = copyID;
306 orig->dv_copydict = copy;
307 }
308 todo = (int)orig->dv_hashtab.ht_used;
309 for (hi = orig->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi)
310 {
311 if (!HASHITEM_EMPTY(hi))
312 {
313 --todo;
314
315 di = dictitem_alloc(hi->hi_key);
316 if (di == NULL)
317 break;
318 if (deep)
319 {
320 if (item_copy(&HI2DI(hi)->di_tv, &di->di_tv, deep,
321 copyID) == FAIL)
322 {
323 vim_free(di);
324 break;
325 }
326 }
327 else
328 copy_tv(&HI2DI(hi)->di_tv, &di->di_tv);
329 if (dict_add(copy, di) == FAIL)
330 {
331 dictitem_free(di);
332 break;
333 }
334 }
335 }
336
337 ++copy->dv_refcount;
338 if (todo > 0)
339 {
340 dict_unref(copy);
341 copy = NULL;
342 }
343 }
344
345 return copy;
346 }
347
348 /*
349 * Check for adding a function to g: or s:.
350 * If the name is wrong give an error message and return TRUE.
351 */
352 int
dict_wrong_func_name(dict_T * d,typval_T * tv,char_u * name)353 dict_wrong_func_name(dict_T *d, typval_T *tv, char_u *name)
354 {
355 return (d == get_globvar_dict()
356 || (in_vim9script() && SCRIPT_ID_VALID(current_sctx.sc_sid)
357 && d == &SCRIPT_ITEM(current_sctx.sc_sid)->sn_vars->sv_dict)
358 || &d->dv_hashtab == get_funccal_local_ht())
359 && (tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
360 && var_wrong_func_name(name, TRUE);
361 }
362
363 /*
364 * Add item "item" to Dictionary "d".
365 * Returns FAIL when out of memory and when key already exists.
366 */
367 int
dict_add(dict_T * d,dictitem_T * item)368 dict_add(dict_T *d, dictitem_T *item)
369 {
370 if (dict_wrong_func_name(d, &item->di_tv, item->di_key))
371 return FAIL;
372 return hash_add(&d->dv_hashtab, item->di_key);
373 }
374
375 /*
376 * Add a number or special entry to dictionary "d".
377 * Returns FAIL when out of memory and when key already exists.
378 */
379 static int
dict_add_number_special(dict_T * d,char * key,varnumber_T nr,vartype_T vartype)380 dict_add_number_special(dict_T *d, char *key, varnumber_T nr, vartype_T vartype)
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 = vartype;
388 item->di_tv.vval.v_number = nr;
389 if (dict_add(d, item) == FAIL)
390 {
391 dictitem_free(item);
392 return FAIL;
393 }
394 return OK;
395 }
396
397 /*
398 * Add a number entry to dictionary "d".
399 * Returns FAIL when out of memory and when key already exists.
400 */
401 int
dict_add_number(dict_T * d,char * key,varnumber_T nr)402 dict_add_number(dict_T *d, char *key, varnumber_T nr)
403 {
404 return dict_add_number_special(d, key, nr, VAR_NUMBER);
405 }
406
407 /*
408 * Add a special entry to dictionary "d".
409 * Returns FAIL when out of memory and when key already exists.
410 */
411 int
dict_add_bool(dict_T * d,char * key,varnumber_T nr)412 dict_add_bool(dict_T *d, char *key, varnumber_T nr)
413 {
414 return dict_add_number_special(d, key, nr, VAR_BOOL);
415 }
416
417 /*
418 * Add a string entry to dictionary "d".
419 * Returns FAIL when out of memory and when key already exists.
420 */
421 int
dict_add_string(dict_T * d,char * key,char_u * str)422 dict_add_string(dict_T *d, char *key, char_u *str)
423 {
424 return dict_add_string_len(d, key, str, -1);
425 }
426
427 /*
428 * Add a string entry to dictionary "d".
429 * "str" will be copied to allocated memory.
430 * When "len" is -1 use the whole string, otherwise only this many bytes.
431 * Returns FAIL when out of memory and when key already exists.
432 */
433 int
dict_add_string_len(dict_T * d,char * key,char_u * str,int len)434 dict_add_string_len(dict_T *d, char *key, char_u *str, int len)
435 {
436 dictitem_T *item;
437 char_u *val = NULL;
438
439 item = dictitem_alloc((char_u *)key);
440 if (item == NULL)
441 return FAIL;
442 item->di_tv.v_type = VAR_STRING;
443 if (str != NULL)
444 {
445 if (len == -1)
446 val = vim_strsave(str);
447 else
448 val = vim_strnsave(str, len);
449 }
450 item->di_tv.vval.v_string = val;
451 if (dict_add(d, item) == FAIL)
452 {
453 dictitem_free(item);
454 return FAIL;
455 }
456 return OK;
457 }
458
459 /*
460 * Add a list entry to dictionary "d".
461 * Returns FAIL when out of memory and when key already exists.
462 */
463 int
dict_add_list(dict_T * d,char * key,list_T * list)464 dict_add_list(dict_T *d, char *key, list_T *list)
465 {
466 dictitem_T *item;
467
468 item = dictitem_alloc((char_u *)key);
469 if (item == NULL)
470 return FAIL;
471 item->di_tv.v_type = VAR_LIST;
472 item->di_tv.vval.v_list = list;
473 ++list->lv_refcount;
474 if (dict_add(d, item) == FAIL)
475 {
476 dictitem_free(item);
477 return FAIL;
478 }
479 return OK;
480 }
481
482 /*
483 * Add a typval_T entry to dictionary "d".
484 * Returns FAIL when out of memory and when key already exists.
485 */
486 int
dict_add_tv(dict_T * d,char * key,typval_T * tv)487 dict_add_tv(dict_T *d, char *key, typval_T *tv)
488 {
489 dictitem_T *item;
490
491 item = dictitem_alloc((char_u *)key);
492 if (item == NULL)
493 return FAIL;
494 copy_tv(tv, &item->di_tv);
495 if (dict_add(d, item) == FAIL)
496 {
497 dictitem_free(item);
498 return FAIL;
499 }
500 return OK;
501 }
502
503 /*
504 * Add a callback to dictionary "d".
505 * Returns FAIL when out of memory and when key already exists.
506 */
507 int
dict_add_callback(dict_T * d,char * key,callback_T * cb)508 dict_add_callback(dict_T *d, char *key, callback_T *cb)
509 {
510 dictitem_T *item;
511
512 item = dictitem_alloc((char_u *)key);
513 if (item == NULL)
514 return FAIL;
515 put_callback(cb, &item->di_tv);
516 if (dict_add(d, item) == FAIL)
517 {
518 dictitem_free(item);
519 return FAIL;
520 }
521 return OK;
522 }
523
524 /*
525 * Initializes "iter" for iterating over dictionary items with
526 * dict_iterate_next().
527 * If "var" is not a Dict or an empty Dict then there will be nothing to
528 * iterate over, no error is given.
529 * NOTE: The dictionary must not change until iterating is finished!
530 */
531 void
dict_iterate_start(typval_T * var,dict_iterator_T * iter)532 dict_iterate_start(typval_T *var, dict_iterator_T *iter)
533 {
534 if (var->v_type != VAR_DICT || var->vval.v_dict == NULL)
535 iter->dit_todo = 0;
536 else
537 {
538 dict_T *d = var->vval.v_dict;
539
540 iter->dit_todo = d->dv_hashtab.ht_used;
541 iter->dit_hi = d->dv_hashtab.ht_array;
542 }
543 }
544
545 /*
546 * Iterate over the items referred to by "iter". It should be initialized with
547 * dict_iterate_start().
548 * Returns a pointer to the key.
549 * "*tv_result" is set to point to the value for that key.
550 * If there are no more items, NULL is returned.
551 */
552 char_u *
dict_iterate_next(dict_iterator_T * iter,typval_T ** tv_result)553 dict_iterate_next(dict_iterator_T *iter, typval_T **tv_result)
554 {
555 dictitem_T *di;
556 char_u *result;
557
558 if (iter->dit_todo == 0)
559 return NULL;
560
561 while (HASHITEM_EMPTY(iter->dit_hi))
562 ++iter->dit_hi;
563
564 di = HI2DI(iter->dit_hi);
565 result = di->di_key;
566 *tv_result = &di->di_tv;
567
568 --iter->dit_todo;
569 ++iter->dit_hi;
570 return result;
571 }
572
573 /*
574 * Add a dict entry to dictionary "d".
575 * Returns FAIL when out of memory and when key already exists.
576 */
577 int
dict_add_dict(dict_T * d,char * key,dict_T * dict)578 dict_add_dict(dict_T *d, char *key, dict_T *dict)
579 {
580 dictitem_T *item;
581
582 item = dictitem_alloc((char_u *)key);
583 if (item == NULL)
584 return FAIL;
585 item->di_tv.v_type = VAR_DICT;
586 item->di_tv.vval.v_dict = dict;
587 ++dict->dv_refcount;
588 if (dict_add(d, item) == FAIL)
589 {
590 dictitem_free(item);
591 return FAIL;
592 }
593 return OK;
594 }
595
596 /*
597 * Get the number of items in a Dictionary.
598 */
599 long
dict_len(dict_T * d)600 dict_len(dict_T *d)
601 {
602 if (d == NULL)
603 return 0L;
604 return (long)d->dv_hashtab.ht_used;
605 }
606
607 /*
608 * Find item "key[len]" in Dictionary "d".
609 * If "len" is negative use strlen(key).
610 * Returns NULL when not found.
611 */
612 dictitem_T *
dict_find(dict_T * d,char_u * key,int len)613 dict_find(dict_T *d, char_u *key, int len)
614 {
615 #define AKEYLEN 200
616 char_u buf[AKEYLEN];
617 char_u *akey;
618 char_u *tofree = NULL;
619 hashitem_T *hi;
620
621 if (d == NULL)
622 return NULL;
623 if (len < 0)
624 akey = key;
625 else if (len >= AKEYLEN)
626 {
627 tofree = akey = vim_strnsave(key, len);
628 if (akey == NULL)
629 return NULL;
630 }
631 else
632 {
633 // Avoid a malloc/free by using buf[].
634 vim_strncpy(buf, key, len);
635 akey = buf;
636 }
637
638 hi = hash_find(&d->dv_hashtab, akey);
639 vim_free(tofree);
640 if (HASHITEM_EMPTY(hi))
641 return NULL;
642 return HI2DI(hi);
643 }
644
645 /*
646 * Get a typval_T item from a dictionary and copy it into "rettv".
647 * Returns FAIL if the entry doesn't exist or out of memory.
648 */
649 int
dict_get_tv(dict_T * d,char_u * key,typval_T * rettv)650 dict_get_tv(dict_T *d, char_u *key, typval_T *rettv)
651 {
652 dictitem_T *di;
653
654 di = dict_find(d, key, -1);
655 if (di == NULL)
656 return FAIL;
657 copy_tv(&di->di_tv, rettv);
658 return OK;
659 }
660
661 /*
662 * Get a string item from a dictionary.
663 * When "save" is TRUE allocate memory for it.
664 * When FALSE a shared buffer is used, can only be used once!
665 * Returns NULL if the entry doesn't exist or out of memory.
666 */
667 char_u *
dict_get_string(dict_T * d,char_u * key,int save)668 dict_get_string(dict_T *d, char_u *key, int save)
669 {
670 dictitem_T *di;
671 char_u *s;
672
673 di = dict_find(d, key, -1);
674 if (di == NULL)
675 return NULL;
676 s = tv_get_string(&di->di_tv);
677 if (save && s != NULL)
678 s = vim_strsave(s);
679 return s;
680 }
681
682 /*
683 * Get a number item from a dictionary.
684 * Returns 0 if the entry doesn't exist.
685 */
686 varnumber_T
dict_get_number(dict_T * d,char_u * key)687 dict_get_number(dict_T *d, char_u *key)
688 {
689 return dict_get_number_def(d, key, 0);
690 }
691
692 /*
693 * Get a number item from a dictionary.
694 * Returns "def" if the entry doesn't exist.
695 */
696 varnumber_T
dict_get_number_def(dict_T * d,char_u * key,int def)697 dict_get_number_def(dict_T *d, char_u *key, int def)
698 {
699 dictitem_T *di;
700
701 di = dict_find(d, key, -1);
702 if (di == NULL)
703 return def;
704 return tv_get_number(&di->di_tv);
705 }
706
707 /*
708 * Get a number item from a dictionary.
709 * Returns 0 if the entry doesn't exist.
710 * Give an error if the entry is not a number.
711 */
712 varnumber_T
dict_get_number_check(dict_T * d,char_u * key)713 dict_get_number_check(dict_T *d, char_u *key)
714 {
715 dictitem_T *di;
716
717 di = dict_find(d, key, -1);
718 if (di == NULL)
719 return 0;
720 if (di->di_tv.v_type != VAR_NUMBER)
721 {
722 semsg(_(e_invarg2), tv_get_string(&di->di_tv));
723 return 0;
724 }
725 return tv_get_number(&di->di_tv);
726 }
727
728 /*
729 * Get a bool item (number or true/false) from a dictionary.
730 * Returns "def" if the entry doesn't exist.
731 */
732 varnumber_T
dict_get_bool(dict_T * d,char_u * key,int def)733 dict_get_bool(dict_T *d, char_u *key, int def)
734 {
735 dictitem_T *di;
736
737 di = dict_find(d, key, -1);
738 if (di == NULL)
739 return def;
740 return tv_get_bool(&di->di_tv);
741 }
742
743 /*
744 * Return an allocated string with the string representation of a Dictionary.
745 * May return NULL.
746 */
747 char_u *
dict2string(typval_T * tv,int copyID,int restore_copyID)748 dict2string(typval_T *tv, int copyID, int restore_copyID)
749 {
750 garray_T ga;
751 int first = TRUE;
752 char_u *tofree;
753 char_u numbuf[NUMBUFLEN];
754 hashitem_T *hi;
755 char_u *s;
756 dict_T *d;
757 int todo;
758
759 if ((d = tv->vval.v_dict) == NULL)
760 return NULL;
761 ga_init2(&ga, (int)sizeof(char), 80);
762 ga_append(&ga, '{');
763
764 todo = (int)d->dv_hashtab.ht_used;
765 for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi)
766 {
767 if (!HASHITEM_EMPTY(hi))
768 {
769 --todo;
770
771 if (first)
772 first = FALSE;
773 else
774 ga_concat(&ga, (char_u *)", ");
775
776 tofree = string_quote(hi->hi_key, FALSE);
777 if (tofree != NULL)
778 {
779 ga_concat(&ga, tofree);
780 vim_free(tofree);
781 }
782 ga_concat(&ga, (char_u *)": ");
783 s = echo_string_core(&HI2DI(hi)->di_tv, &tofree, numbuf, copyID,
784 FALSE, restore_copyID, TRUE);
785 if (s != NULL)
786 ga_concat(&ga, s);
787 vim_free(tofree);
788 if (s == NULL || did_echo_string_emsg)
789 break;
790 line_breakcheck();
791
792 }
793 }
794 if (todo > 0)
795 {
796 vim_free(ga.ga_data);
797 return NULL;
798 }
799
800 ga_append(&ga, '}');
801 ga_append(&ga, NUL);
802 return (char_u *)ga.ga_data;
803 }
804
805 /*
806 * Advance over a literal key, including "-". If the first character is not a
807 * literal key character then "key" is returned.
808 */
809 static char_u *
skip_literal_key(char_u * key)810 skip_literal_key(char_u *key)
811 {
812 char_u *p;
813
814 for (p = key; ASCII_ISALNUM(*p) || *p == '_' || *p == '-'; ++p)
815 ;
816 return p;
817 }
818
819 /*
820 * Get the key for #{key: val} into "tv" and advance "arg".
821 * Return FAIL when there is no valid key.
822 */
823 static int
get_literal_key_tv(char_u ** arg,typval_T * tv)824 get_literal_key_tv(char_u **arg, typval_T *tv)
825 {
826 char_u *p = skip_literal_key(*arg);
827
828 if (p == *arg)
829 return FAIL;
830 tv->v_type = VAR_STRING;
831 tv->vval.v_string = vim_strnsave(*arg, p - *arg);
832
833 *arg = p;
834 return OK;
835 }
836
837 /*
838 * Get a literal key for a Vim9 dict:
839 * {"name": value},
840 * {'name': value},
841 * {name: value} use "name" as a literal key
842 * Return the key in allocated memory or NULL in the case of an error.
843 * "arg" is advanced to just after the key.
844 */
845 char_u *
get_literal_key(char_u ** arg)846 get_literal_key(char_u **arg)
847 {
848 char_u *key;
849 char_u *end;
850 typval_T rettv;
851
852 if (**arg == '\'')
853 {
854 if (eval_lit_string(arg, &rettv, TRUE) == FAIL)
855 return NULL;
856 key = rettv.vval.v_string;
857 }
858 else if (**arg == '"')
859 {
860 if (eval_string(arg, &rettv, TRUE) == FAIL)
861 return NULL;
862 key = rettv.vval.v_string;
863 }
864 else
865 {
866 end = skip_literal_key(*arg);
867 if (end == *arg)
868 {
869 semsg(_(e_invalid_key_str), *arg);
870 return NULL;
871 }
872 key = vim_strnsave(*arg, end - *arg);
873 *arg = end;
874 }
875 return key;
876 }
877
878 /*
879 * Allocate a variable for a Dictionary and fill it from "*arg".
880 * "*arg" points to the "{".
881 * "literal" is TRUE for #{key: val}
882 * Return OK or FAIL. Returns NOTDONE for {expr}.
883 */
884 int
eval_dict(char_u ** arg,typval_T * rettv,evalarg_T * evalarg,int literal)885 eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
886 {
887 int evaluate = evalarg == NULL ? FALSE
888 : evalarg->eval_flags & EVAL_EVALUATE;
889 dict_T *d = NULL;
890 typval_T tvkey;
891 typval_T tv;
892 char_u *key = NULL;
893 dictitem_T *item;
894 char_u *curly_expr = skipwhite(*arg + 1);
895 char_u buf[NUMBUFLEN];
896 int vim9script = in_vim9script();
897 int had_comma;
898
899 /*
900 * First check if it's not a curly-braces thing: {expr}.
901 * Must do this without evaluating, otherwise a function may be called
902 * twice. Unfortunately this means we need to call eval1() twice for the
903 * first item.
904 * But {} is an empty Dictionary.
905 */
906 if (!vim9script
907 && *curly_expr != '}'
908 && eval1(&curly_expr, &tv, NULL) == OK
909 && *skipwhite(curly_expr) == '}')
910 return NOTDONE;
911
912 if (evaluate)
913 {
914 d = dict_alloc();
915 if (d == NULL)
916 return FAIL;
917 }
918 tvkey.v_type = VAR_UNKNOWN;
919 tv.v_type = VAR_UNKNOWN;
920
921 *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
922 while (**arg != '}' && **arg != NUL)
923 {
924 int has_bracket = vim9script && **arg == '[';
925
926 if (literal)
927 {
928 if (get_literal_key_tv(arg, &tvkey) == FAIL)
929 goto failret;
930 }
931 else if (vim9script && !has_bracket)
932 {
933 tvkey.vval.v_string = get_literal_key(arg);
934 if (tvkey.vval.v_string == NULL)
935 goto failret;
936 tvkey.v_type = VAR_STRING;
937 }
938 else
939 {
940 if (has_bracket)
941 *arg = skipwhite(*arg + 1);
942 if (eval1(arg, &tvkey, evalarg) == FAIL) // recursive!
943 goto failret;
944 if (has_bracket)
945 {
946 *arg = skipwhite(*arg);
947 if (**arg != ']')
948 {
949 emsg(_(e_missing_matching_bracket_after_dict_key));
950 clear_tv(&tvkey);
951 return FAIL;
952 }
953 ++*arg;
954 }
955 }
956
957 // the colon should come right after the key, but this wasn't checked
958 // previously, so only require it in Vim9 script.
959 if (!vim9script)
960 *arg = skipwhite(*arg);
961 if (**arg != ':')
962 {
963 if (*skipwhite(*arg) == ':')
964 semsg(_(e_no_white_space_allowed_before_str_str), ":", *arg);
965 else
966 semsg(_(e_missing_dict_colon), *arg);
967 clear_tv(&tvkey);
968 goto failret;
969 }
970 if (evaluate)
971 {
972 #ifdef FEAT_FLOAT
973 if (tvkey.v_type == VAR_FLOAT)
974 {
975 tvkey.vval.v_string = typval_tostring(&tvkey, TRUE);
976 tvkey.v_type = VAR_STRING;
977 }
978 #endif
979 key = tv_get_string_buf_chk(&tvkey, buf);
980 if (key == NULL)
981 {
982 // "key" is NULL when tv_get_string_buf_chk() gave an errmsg
983 clear_tv(&tvkey);
984 goto failret;
985 }
986 }
987 if (vim9script && (*arg)[1] != NUL && !VIM_ISWHITE((*arg)[1]))
988 {
989 semsg(_(e_white_space_required_after_str_str), ":", *arg);
990 clear_tv(&tvkey);
991 goto failret;
992 }
993
994 *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
995 if (eval1(arg, &tv, evalarg) == FAIL) // recursive!
996 {
997 if (evaluate)
998 clear_tv(&tvkey);
999 goto failret;
1000 }
1001 if (evaluate)
1002 {
1003 item = dict_find(d, key, -1);
1004 if (item != NULL)
1005 {
1006 semsg(_(e_duplicate_key), key);
1007 clear_tv(&tvkey);
1008 clear_tv(&tv);
1009 goto failret;
1010 }
1011 item = dictitem_alloc(key);
1012 if (item != NULL)
1013 {
1014 item->di_tv = tv;
1015 item->di_tv.v_lock = 0;
1016 if (dict_add(d, item) == FAIL)
1017 dictitem_free(item);
1018 }
1019 }
1020 clear_tv(&tvkey);
1021
1022 // the comma should come right after the value, but this wasn't checked
1023 // previously, so only require it in Vim9 script.
1024 if (!vim9script)
1025 *arg = skipwhite(*arg);
1026 had_comma = **arg == ',';
1027 if (had_comma)
1028 {
1029 if (vim9script && (*arg)[1] != NUL && !VIM_ISWHITE((*arg)[1]))
1030 {
1031 semsg(_(e_white_space_required_after_str_str), ",", *arg);
1032 goto failret;
1033 }
1034 *arg = skipwhite(*arg + 1);
1035 }
1036
1037 // the "}" can be on the next line
1038 *arg = skipwhite_and_linebreak(*arg, evalarg);
1039 if (**arg == '}')
1040 break;
1041 if (!had_comma)
1042 {
1043 if (**arg == ',')
1044 semsg(_(e_no_white_space_allowed_before_str_str), ",", *arg);
1045 else
1046 semsg(_(e_missing_dict_comma), *arg);
1047 goto failret;
1048 }
1049 }
1050
1051 if (**arg != '}')
1052 {
1053 if (evalarg != NULL)
1054 semsg(_(e_missing_dict_end), *arg);
1055 failret:
1056 if (d != NULL)
1057 dict_free(d);
1058 return FAIL;
1059 }
1060
1061 *arg = *arg + 1;
1062 if (evaluate)
1063 rettv_dict_set(rettv, d);
1064
1065 return OK;
1066 }
1067
1068 /*
1069 * Go over all entries in "d2" and add them to "d1".
1070 * When "action" is "error" then a duplicate key is an error.
1071 * When "action" is "force" then a duplicate key is overwritten.
1072 * Otherwise duplicate keys are ignored ("action" is "keep").
1073 */
1074 void
dict_extend(dict_T * d1,dict_T * d2,char_u * action,char * func_name)1075 dict_extend(dict_T *d1, dict_T *d2, char_u *action, char *func_name)
1076 {
1077 dictitem_T *di1;
1078 hashitem_T *hi2;
1079 int todo;
1080 char_u *arg_errmsg = (char_u *)N_("extend() argument");
1081 type_T *type;
1082
1083 if (d1->dv_type != NULL && d1->dv_type->tt_member != NULL)
1084 type = d1->dv_type->tt_member;
1085 else
1086 type = NULL;
1087
1088 todo = (int)d2->dv_hashtab.ht_used;
1089 for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2)
1090 {
1091 if (!HASHITEM_EMPTY(hi2))
1092 {
1093 --todo;
1094 di1 = dict_find(d1, hi2->hi_key, -1);
1095 if (d1->dv_scope != 0)
1096 {
1097 // Disallow replacing a builtin function in l: and g:.
1098 // Check the key to be valid when adding to any scope.
1099 if (d1->dv_scope == VAR_DEF_SCOPE
1100 && HI2DI(hi2)->di_tv.v_type == VAR_FUNC
1101 && var_wrong_func_name(hi2->hi_key, di1 == NULL))
1102 break;
1103 if (!valid_varname(hi2->hi_key, -1, TRUE))
1104 break;
1105 }
1106
1107 if (type != NULL
1108 && check_typval_arg_type(type, &HI2DI(hi2)->di_tv,
1109 func_name, 0) == FAIL)
1110 break;
1111
1112 if (di1 == NULL)
1113 {
1114 di1 = dictitem_copy(HI2DI(hi2));
1115 if (di1 != NULL && dict_add(d1, di1) == FAIL)
1116 dictitem_free(di1);
1117 }
1118 else if (*action == 'e')
1119 {
1120 semsg(_("E737: Key already exists: %s"), hi2->hi_key);
1121 break;
1122 }
1123 else if (*action == 'f' && HI2DI(hi2) != di1)
1124 {
1125 if (value_check_lock(di1->di_tv.v_lock, arg_errmsg, TRUE)
1126 || var_check_ro(di1->di_flags, arg_errmsg, TRUE))
1127 break;
1128 if (dict_wrong_func_name(d1, &HI2DI(hi2)->di_tv, hi2->hi_key))
1129 break;
1130 clear_tv(&di1->di_tv);
1131 copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv);
1132 }
1133 }
1134 }
1135 }
1136
1137 /*
1138 * Return the dictitem that an entry in a hashtable points to.
1139 */
1140 dictitem_T *
dict_lookup(hashitem_T * hi)1141 dict_lookup(hashitem_T *hi)
1142 {
1143 return HI2DI(hi);
1144 }
1145
1146 /*
1147 * Return TRUE when two dictionaries have exactly the same key/values.
1148 */
1149 int
dict_equal(dict_T * d1,dict_T * d2,int ic,int recursive)1150 dict_equal(
1151 dict_T *d1,
1152 dict_T *d2,
1153 int ic, // ignore case for strings
1154 int recursive) // TRUE when used recursively
1155 {
1156 hashitem_T *hi;
1157 dictitem_T *item2;
1158 int todo;
1159
1160 if (d1 == d2)
1161 return TRUE;
1162 if (dict_len(d1) != dict_len(d2))
1163 return FALSE;
1164 if (dict_len(d1) == 0)
1165 // empty and NULL dicts are considered equal
1166 return TRUE;
1167 if (d1 == NULL || d2 == NULL)
1168 return FALSE;
1169
1170 todo = (int)d1->dv_hashtab.ht_used;
1171 for (hi = d1->dv_hashtab.ht_array; todo > 0; ++hi)
1172 {
1173 if (!HASHITEM_EMPTY(hi))
1174 {
1175 item2 = dict_find(d2, hi->hi_key, -1);
1176 if (item2 == NULL)
1177 return FALSE;
1178 if (!tv_equal(&HI2DI(hi)->di_tv, &item2->di_tv, ic, recursive))
1179 return FALSE;
1180 --todo;
1181 }
1182 }
1183 return TRUE;
1184 }
1185
1186 /*
1187 * Turn a dict into a list:
1188 * "what" == 0: list of keys
1189 * "what" == 1: list of values
1190 * "what" == 2: list of items
1191 */
1192 static void
dict_list(typval_T * argvars,typval_T * rettv,int what)1193 dict_list(typval_T *argvars, typval_T *rettv, int what)
1194 {
1195 list_T *l2;
1196 dictitem_T *di;
1197 hashitem_T *hi;
1198 listitem_T *li;
1199 listitem_T *li2;
1200 dict_T *d;
1201 int todo;
1202
1203 if (in_vim9script() && check_for_dict_arg(argvars, 0) == FAIL)
1204 return;
1205
1206 if (argvars[0].v_type != VAR_DICT)
1207 {
1208 emsg(_(e_dictreq));
1209 return;
1210 }
1211
1212 if (rettv_list_alloc(rettv) == FAIL)
1213 return;
1214 if ((d = argvars[0].vval.v_dict) == NULL)
1215 // empty dict behaves like an empty dict
1216 return;
1217
1218 todo = (int)d->dv_hashtab.ht_used;
1219 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
1220 {
1221 if (!HASHITEM_EMPTY(hi))
1222 {
1223 --todo;
1224 di = HI2DI(hi);
1225
1226 li = listitem_alloc();
1227 if (li == NULL)
1228 break;
1229 list_append(rettv->vval.v_list, li);
1230
1231 if (what == 0)
1232 {
1233 // keys()
1234 li->li_tv.v_type = VAR_STRING;
1235 li->li_tv.v_lock = 0;
1236 li->li_tv.vval.v_string = vim_strsave(di->di_key);
1237 }
1238 else if (what == 1)
1239 {
1240 // values()
1241 copy_tv(&di->di_tv, &li->li_tv);
1242 }
1243 else
1244 {
1245 // items()
1246 l2 = list_alloc();
1247 li->li_tv.v_type = VAR_LIST;
1248 li->li_tv.v_lock = 0;
1249 li->li_tv.vval.v_list = l2;
1250 if (l2 == NULL)
1251 break;
1252 ++l2->lv_refcount;
1253
1254 li2 = listitem_alloc();
1255 if (li2 == NULL)
1256 break;
1257 list_append(l2, li2);
1258 li2->li_tv.v_type = VAR_STRING;
1259 li2->li_tv.v_lock = 0;
1260 li2->li_tv.vval.v_string = vim_strsave(di->di_key);
1261
1262 li2 = listitem_alloc();
1263 if (li2 == NULL)
1264 break;
1265 list_append(l2, li2);
1266 copy_tv(&di->di_tv, &li2->li_tv);
1267 }
1268 }
1269 }
1270 }
1271
1272 /*
1273 * "items(dict)" function
1274 */
1275 void
f_items(typval_T * argvars,typval_T * rettv)1276 f_items(typval_T *argvars, typval_T *rettv)
1277 {
1278 dict_list(argvars, rettv, 2);
1279 }
1280
1281 /*
1282 * "keys()" function
1283 */
1284 void
f_keys(typval_T * argvars,typval_T * rettv)1285 f_keys(typval_T *argvars, typval_T *rettv)
1286 {
1287 dict_list(argvars, rettv, 0);
1288 }
1289
1290 /*
1291 * "values(dict)" function
1292 */
1293 void
f_values(typval_T * argvars,typval_T * rettv)1294 f_values(typval_T *argvars, typval_T *rettv)
1295 {
1296 dict_list(argvars, rettv, 1);
1297 }
1298
1299 /*
1300 * Make each item in the dict readonly (not the value of the item).
1301 */
1302 void
dict_set_items_ro(dict_T * di)1303 dict_set_items_ro(dict_T *di)
1304 {
1305 int todo = (int)di->dv_hashtab.ht_used;
1306 hashitem_T *hi;
1307
1308 // Set readonly
1309 for (hi = di->dv_hashtab.ht_array; todo > 0 ; ++hi)
1310 {
1311 if (HASHITEM_EMPTY(hi))
1312 continue;
1313 --todo;
1314 HI2DI(hi)->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX;
1315 }
1316 }
1317
1318 /*
1319 * "has_key()" function
1320 */
1321 void
f_has_key(typval_T * argvars,typval_T * rettv)1322 f_has_key(typval_T *argvars, typval_T *rettv)
1323 {
1324 if (in_vim9script()
1325 && (check_for_dict_arg(argvars, 0) == FAIL
1326 || check_for_string_or_number_arg(argvars, 1) == FAIL))
1327 return;
1328
1329 if (argvars[0].v_type != VAR_DICT)
1330 {
1331 emsg(_(e_dictreq));
1332 return;
1333 }
1334 if (argvars[0].vval.v_dict == NULL)
1335 return;
1336
1337 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
1338 tv_get_string(&argvars[1]), -1) != NULL;
1339 }
1340
1341 /*
1342 * "remove({dict})" function
1343 */
1344 void
dict_remove(typval_T * argvars,typval_T * rettv,char_u * arg_errmsg)1345 dict_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
1346 {
1347 dict_T *d;
1348 char_u *key;
1349 dictitem_T *di;
1350
1351 if (argvars[2].v_type != VAR_UNKNOWN)
1352 semsg(_(e_toomanyarg), "remove()");
1353 else if ((d = argvars[0].vval.v_dict) != NULL
1354 && !value_check_lock(d->dv_lock, arg_errmsg, TRUE))
1355 {
1356 key = tv_get_string_chk(&argvars[1]);
1357 if (key != NULL)
1358 {
1359 di = dict_find(d, key, -1);
1360 if (di == NULL)
1361 semsg(_(e_dictkey), key);
1362 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
1363 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
1364 {
1365 *rettv = di->di_tv;
1366 init_tv(&di->di_tv);
1367 dictitem_remove(d, di);
1368 }
1369 }
1370 }
1371 }
1372
1373 #endif // defined(FEAT_EVAL)
1374