1// This is an open source non-commercial project. Dear PVS-Studio, please check
2// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
3
4#include <stdio.h>
5#include <stddef.h>
6#include <stdlib.h>
7#include <string.h>
8#include <assert.h>
9#include <stdbool.h>
10
11#include "nvim/lib/queue.h"
12#include "nvim/eval/typval.h"
13#include "nvim/eval/gc.h"
14#include "nvim/eval/executor.h"
15#include "nvim/eval/encode.h"
16#include "nvim/eval/typval_encode.h"
17#include "nvim/eval.h"
18#include "nvim/types.h"
19#include "nvim/assert.h"
20#include "nvim/memory.h"
21#include "nvim/globals.h"
22#include "nvim/hashtab.h"
23#include "nvim/vim.h"
24#include "nvim/ascii.h"
25#include "nvim/pos.h"
26#include "nvim/charset.h"
27#include "nvim/garray.h"
28#include "nvim/gettext.h"
29#include "nvim/macros.h"
30#include "nvim/mbyte.h"
31#include "nvim/message.h"
32// TODO(ZyX-I): Move line_breakcheck out of misc1
33#include "nvim/misc1.h" // For line_breakcheck
34#include "nvim/os/fileio.h"
35
36#ifdef INCLUDE_GENERATED_DECLARATIONS
37# include "eval/typval.c.generated.h"
38#endif
39
40bool tv_in_free_unref_items = false;
41
42// TODO(ZyX-I): Remove DICT_MAXNEST, make users be non-recursive instead
43
44#define DICT_MAXNEST 100
45
46const char *const tv_empty_string = "";
47
48//{{{1 Lists
49//{{{2 List log
50#ifdef LOG_LIST_ACTIONS
51ListLog *list_log_first = NULL;
52ListLog *list_log_last = NULL;
53
54/// Write list log to the given file
55///
56/// @param[in] fname File to write log to. Will be appended to if already
57/// present.
58void list_write_log(const char *const fname)
59 FUNC_ATTR_NONNULL_ALL
60{
61 FileDescriptor fp;
62 const int fo_ret = file_open(&fp, fname, kFileCreate|kFileAppend, 0600);
63 if (fo_ret != 0) {
64 emsgf(_("E5142: Failed to open file %s: %s"), fname, os_strerror(fo_ret));
65 return;
66 }
67 for (ListLog *chunk = list_log_first; chunk != NULL;) {
68 for (size_t i = 0; i < chunk->size; i++) {
69 char buf[10 + 1 + ((16 + 3) * 3) + (8 + 2) + 2];
70 // act : hex " c:" len "[]" "\n\0"
71 const ListLogEntry entry = chunk->entries[i];
72 const size_t snp_len = (size_t)snprintf(
73 buf, sizeof(buf),
74 "%-10.10s: l:%016" PRIxPTR "[%08d] 1:%016" PRIxPTR " 2:%016" PRIxPTR
75 "\n",
76 entry.action, entry.l, entry.len, entry.li1, entry.li2);
77 assert(snp_len + 1 == sizeof(buf));
78 const ptrdiff_t fw_ret = file_write(&fp, buf, snp_len);
79 if (fw_ret != (ptrdiff_t)snp_len) {
80 assert(fw_ret < 0);
81 if (i) {
82 memmove(chunk->entries, chunk->entries + i,
83 sizeof(chunk->entries[0]) * (chunk->size - i));
84 chunk->size -= i;
85 }
86 emsgf(_("E5143: Failed to write to file %s: %s"),
87 fname, os_strerror((int)fw_ret));
88 return;
89 }
90 }
91 list_log_first = chunk->next;
92 xfree(chunk);
93 chunk = list_log_first;
94 }
95 const int fc_ret = file_close(&fp, true);
96 if (fc_ret != 0) {
97 emsgf(_("E5144: Failed to close file %s: %s"), fname, os_strerror(fc_ret));
98 }
99}
100
101#ifdef EXITFREE
102/// Free list log
103void list_free_log(void)
104{
105 for (ListLog *chunk = list_log_first; chunk != NULL;) {
106 list_log_first = chunk->next;
107 xfree(chunk);
108 chunk = list_log_first;
109 }
110}
111#endif
112#endif
113//{{{2 List item
114
115/// Allocate a list item
116///
117/// @warning Allocated item is not initialized, do not forget to initialize it
118/// and specifically set lv_lock.
119///
120/// @return [allocated] new list item.
121static listitem_T *tv_list_item_alloc(void)
122 FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC
123{
124 return xmalloc(sizeof(listitem_T));
125}
126
127/// Remove a list item from a List and free it
128///
129/// Also clears the value.
130///
131/// @param[out] l List to remove item from.
132/// @param[in,out] item Item to remove.
133///
134/// @return Pointer to the list item just after removed one, NULL if removed
135/// item was the last one.
136listitem_T *tv_list_item_remove(list_T *const l, listitem_T *const item)
137 FUNC_ATTR_NONNULL_ALL
138{
139 listitem_T *const next_item = TV_LIST_ITEM_NEXT(l, item);
140 tv_list_drop_items(l, item, item);
141 tv_clear(TV_LIST_ITEM_TV(item));
142 xfree(item);
143 return next_item;
144}
145
146//{{{2 List watchers
147
148/// Add a watcher to a list
149///
150/// @param[out] l List to add watcher to.
151/// @param[in] lw Watcher to add.
152void tv_list_watch_add(list_T *const l, listwatch_T *const lw)
153 FUNC_ATTR_NONNULL_ALL
154{
155 lw->lw_next = l->lv_watch;
156 l->lv_watch = lw;
157}
158
159/// Remove a watcher from a list
160///
161/// Does not give a warning if watcher was not found.
162///
163/// @param[out] l List to remove watcher from.
164/// @param[in] lwrem Watcher to remove.
165void tv_list_watch_remove(list_T *const l, listwatch_T *const lwrem)
166 FUNC_ATTR_NONNULL_ALL
167{
168 listwatch_T **lwp = &l->lv_watch;
169 for (listwatch_T *lw = l->lv_watch; lw != NULL; lw = lw->lw_next) {
170 if (lw == lwrem) {
171 *lwp = lw->lw_next;
172 break;
173 }
174 lwp = &lw->lw_next;
175 }
176}
177
178/// Advance watchers to the next item
179///
180/// Used just before removing an item from a list.
181///
182/// @param[out] l List from which item is removed.
183/// @param[in] item List item being removed.
184void tv_list_watch_fix(list_T *const l, const listitem_T *const item)
185 FUNC_ATTR_NONNULL_ALL
186{
187 for (listwatch_T *lw = l->lv_watch; lw != NULL; lw = lw->lw_next) {
188 if (lw->lw_item == item) {
189 lw->lw_item = item->li_next;
190 }
191 }
192}
193
194//{{{2 Alloc/free
195
196/// Allocate an empty list
197///
198/// Caller should take care of the reference count.
199///
200/// @param[in] len Expected number of items to be populated before list
201/// becomes accessible from VimL. It is still valid to
202/// underpopulate a list, value only controls how many elements
203/// will be allocated in advance. Currently does nothing.
204/// @see ListLenSpecials.
205///
206/// @return [allocated] new list.
207list_T *tv_list_alloc(const ptrdiff_t len)
208 FUNC_ATTR_NONNULL_RET
209{
210 list_T *const list = xcalloc(1, sizeof(list_T));
211
212 // Prepend the list to the list of lists for garbage collection.
213 if (gc_first_list != NULL) {
214 gc_first_list->lv_used_prev = list;
215 }
216 list->lv_used_prev = NULL;
217 list->lv_used_next = gc_first_list;
218 gc_first_list = list;
219 list_log(list, NULL, (void *)(uintptr_t)len, "alloc");
220 return list;
221}
222
223/// Initialize a static list with 10 items
224///
225/// @param[out] sl Static list to initialize.
226void tv_list_init_static10(staticList10_T *const sl)
227 FUNC_ATTR_NONNULL_ALL
228{
229#define SL_SIZE ARRAY_SIZE(sl->sl_items)
230 list_T *const l = &sl->sl_list;
231
232 memset(sl, 0, sizeof(staticList10_T));
233 l->lv_first = &sl->sl_items[0];
234 l->lv_last = &sl->sl_items[SL_SIZE - 1];
235 l->lv_refcount = DO_NOT_FREE_CNT;
236 tv_list_set_lock(l, VAR_FIXED);
237 sl->sl_list.lv_len = 10;
238
239 sl->sl_items[0].li_prev = NULL;
240 sl->sl_items[0].li_next = &sl->sl_items[1];
241 sl->sl_items[SL_SIZE - 1].li_prev = &sl->sl_items[SL_SIZE - 2];
242 sl->sl_items[SL_SIZE - 1].li_next = NULL;
243
244 for (size_t i = 1; i < SL_SIZE - 1; i++) {
245 listitem_T *const li = &sl->sl_items[i];
246 li->li_prev = li - 1;
247 li->li_next = li + 1;
248 }
249 list_log((const list_T *)sl, &sl->sl_items[0], &sl->sl_items[SL_SIZE - 1],
250 "s10init");
251#undef SL_SIZE
252}
253
254/// Initialize static list with undefined number of elements
255///
256/// @param[out] l List to initialize.
257void tv_list_init_static(list_T *const l)
258 FUNC_ATTR_NONNULL_ALL
259{
260 memset(l, 0, sizeof(*l));
261 l->lv_refcount = DO_NOT_FREE_CNT;
262 list_log(l, NULL, NULL, "sinit");
263}
264
265/// Free items contained in a list
266///
267/// @param[in,out] l List to clear.
268void tv_list_free_contents(list_T *const l)
269 FUNC_ATTR_NONNULL_ALL
270{
271 list_log(l, NULL, NULL, "freecont");
272 for (listitem_T *item = l->lv_first; item != NULL; item = l->lv_first) {
273 // Remove the item before deleting it.
274 l->lv_first = item->li_next;
275 tv_clear(&item->li_tv);
276 xfree(item);
277 }
278 l->lv_len = 0;
279 l->lv_idx_item = NULL;
280 l->lv_last = NULL;
281 assert(l->lv_watch == NULL);
282}
283
284/// Free a list itself, ignoring items it contains
285///
286/// Ignores the reference count.
287///
288/// @param[in,out] l List to free.
289void tv_list_free_list(list_T *const l)
290 FUNC_ATTR_NONNULL_ALL
291{
292 // Remove the list from the list of lists for garbage collection.
293 if (l->lv_used_prev == NULL) {
294 gc_first_list = l->lv_used_next;
295 } else {
296 l->lv_used_prev->lv_used_next = l->lv_used_next;
297 }
298 if (l->lv_used_next != NULL) {
299 l->lv_used_next->lv_used_prev = l->lv_used_prev;
300 }
301 list_log(l, NULL, NULL, "freelist");
302
303 xfree(l);
304}
305
306/// Free a list, including all items it points to
307///
308/// Ignores the reference count. Does not do anything if
309/// tv_in_free_unref_items is true.
310///
311/// @param[in,out] l List to free.
312void tv_list_free(list_T *const l)
313 FUNC_ATTR_NONNULL_ALL
314{
315 if (!tv_in_free_unref_items) {
316 tv_list_free_contents(l);
317 tv_list_free_list(l);
318 }
319}
320
321/// Unreference a list
322///
323/// Decrements the reference count and frees when it becomes zero or less.
324///
325/// @param[in,out] l List to unreference.
326void tv_list_unref(list_T *const l)
327{
328 if (l != NULL && --l->lv_refcount <= 0) {
329 tv_list_free(l);
330 }
331}
332
333//{{{2 Add/remove
334
335/// Remove items "item" to "item2" from list "l"
336///
337/// @warning Does not free the listitem or the value!
338///
339/// @param[out] l List to remove from.
340/// @param[in] item First item to remove.
341/// @param[in] item2 Last item to remove.
342void tv_list_drop_items(list_T *const l, listitem_T *const item,
343 listitem_T *const item2)
344 FUNC_ATTR_NONNULL_ALL
345{
346 list_log(l, item, item2, "drop");
347 // Notify watchers.
348 for (listitem_T *ip = item; ip != item2->li_next; ip = ip->li_next) {
349 l->lv_len--;
350 tv_list_watch_fix(l, ip);
351 }
352
353 if (item2->li_next == NULL) {
354 l->lv_last = item->li_prev;
355 } else {
356 item2->li_next->li_prev = item->li_prev;
357 }
358 if (item->li_prev == NULL) {
359 l->lv_first = item2->li_next;
360 } else {
361 item->li_prev->li_next = item2->li_next;
362 }
363 l->lv_idx_item = NULL;
364 list_log(l, l->lv_first, l->lv_last, "afterdrop");
365}
366
367/// Like tv_list_drop_items, but also frees all removed items
368void tv_list_remove_items(list_T *const l, listitem_T *const item,
369 listitem_T *const item2)
370 FUNC_ATTR_NONNULL_ALL
371{
372 list_log(l, item, item2, "remove");
373 tv_list_drop_items(l, item, item2);
374 for (listitem_T *li = item;;) {
375 tv_clear(TV_LIST_ITEM_TV(li));
376 listitem_T *const nli = li->li_next;
377 xfree(li);
378 if (li == item2) {
379 break;
380 }
381 li = nli;
382 }
383}
384
385/// Move items "item" to "item2" from list "l" to the end of the list "tgt_l"
386///
387/// @param[out] l List to move from.
388/// @param[in] item First item to move.
389/// @param[in] item2 Last item to move.
390/// @param[out] tgt_l List to move to.
391/// @param[in] cnt Number of items moved.
392void tv_list_move_items(list_T *const l, listitem_T *const item,
393 listitem_T *const item2, list_T *const tgt_l,
394 const int cnt)
395 FUNC_ATTR_NONNULL_ALL
396{
397 list_log(l, item, item2, "move");
398 tv_list_drop_items(l, item, item2);
399 item->li_prev = tgt_l->lv_last;
400 item2->li_next = NULL;
401 if (tgt_l->lv_last == NULL) {
402 tgt_l->lv_first = item;
403 } else {
404 tgt_l->lv_last->li_next = item;
405 }
406 tgt_l->lv_last = item2;
407 tgt_l->lv_len += cnt;
408 list_log(tgt_l, tgt_l->lv_first, tgt_l->lv_last, "movetgt");
409}
410
411/// Insert list item
412///
413/// @param[out] l List to insert to.
414/// @param[in,out] ni Item to insert.
415/// @param[in] item Item to insert before. If NULL, inserts at the end of the
416/// list.
417void tv_list_insert(list_T *const l, listitem_T *const ni,
418 listitem_T *const item)
419 FUNC_ATTR_NONNULL_ARG(1, 2)
420{
421 if (item == NULL) {
422 // Append new item at end of list.
423 tv_list_append(l, ni);
424 } else {
425 // Insert new item before existing item.
426 ni->li_prev = item->li_prev;
427 ni->li_next = item;
428 if (item->li_prev == NULL) {
429 l->lv_first = ni;
430 l->lv_idx++;
431 } else {
432 item->li_prev->li_next = ni;
433 l->lv_idx_item = NULL;
434 }
435 item->li_prev = ni;
436 l->lv_len++;
437 list_log(l, ni, item, "insert");
438 }
439}
440
441/// Insert VimL value into a list
442///
443/// @param[out] l List to insert to.
444/// @param[in,out] tv Value to insert. Is copied (@see tv_copy()) to an
445/// allocated listitem_T and inserted.
446/// @param[in] item Item to insert before. If NULL, inserts at the end of the
447/// list.
448void tv_list_insert_tv(list_T *const l, typval_T *const tv,
449 listitem_T *const item)
450{
451 listitem_T *const ni = tv_list_item_alloc();
452
453 tv_copy(tv, &ni->li_tv);
454 tv_list_insert(l, ni, item);
455}
456
457/// Append item to the end of list
458///
459/// @param[out] l List to append to.
460/// @param[in,out] item Item to append.
461void tv_list_append(list_T *const l, listitem_T *const item)
462 FUNC_ATTR_NONNULL_ALL
463{
464 list_log(l, item, NULL, "append");
465 if (l->lv_last == NULL) {
466 // empty list
467 l->lv_first = item;
468 l->lv_last = item;
469 item->li_prev = NULL;
470 } else {
471 l->lv_last->li_next = item;
472 item->li_prev = l->lv_last;
473 l->lv_last = item;
474 }
475 l->lv_len++;
476 item->li_next = NULL;
477}
478
479/// Append VimL value to the end of list
480///
481/// @param[out] l List to append to.
482/// @param[in,out] tv Value to append. Is copied (@see tv_copy()) to an
483/// allocated listitem_T.
484void tv_list_append_tv(list_T *const l, typval_T *const tv)
485 FUNC_ATTR_NONNULL_ALL
486{
487 listitem_T *const li = tv_list_item_alloc();
488 tv_copy(tv, TV_LIST_ITEM_TV(li));
489 tv_list_append(l, li);
490}
491
492/// Like tv_list_append_tv(), but tv is moved to a list
493///
494/// This means that it is no longer valid to use contents of the typval_T after
495/// function exits.
496void tv_list_append_owned_tv(list_T *const l, typval_T tv)
497 FUNC_ATTR_NONNULL_ALL
498{
499 listitem_T *const li = tv_list_item_alloc();
500 *TV_LIST_ITEM_TV(li) = tv;
501 tv_list_append(l, li);
502}
503
504/// Append a list to a list as one item
505///
506/// @param[out] l List to append to.
507/// @param[in,out] itemlist List to append. Reference count is increased.
508void tv_list_append_list(list_T *const l, list_T *const itemlist)
509 FUNC_ATTR_NONNULL_ARG(1)
510{
511 tv_list_append_owned_tv(l, (typval_T) {
512 .v_type = VAR_LIST,
513 .v_lock = VAR_UNLOCKED,
514 .vval.v_list = itemlist,
515 });
516 tv_list_ref(itemlist);
517}
518
519/// Append a dictionary to a list
520///
521/// @param[out] l List to append to.
522/// @param[in,out] dict Dictionary to append. Reference count is increased.
523void tv_list_append_dict(list_T *const l, dict_T *const dict)
524 FUNC_ATTR_NONNULL_ARG(1)
525{
526 tv_list_append_owned_tv(l, (typval_T) {
527 .v_type = VAR_DICT,
528 .v_lock = VAR_UNLOCKED,
529 .vval.v_dict = dict,
530 });
531 if (dict != NULL) {
532 dict->dv_refcount++;
533 }
534}
535
536/// Make a copy of "str" and append it as an item to list "l"
537///
538/// @param[out] l List to append to.
539/// @param[in] str String to append.
540/// @param[in] len Length of the appended string. May be -1, in this
541/// case string is considered to be usual zero-terminated
542/// string or NULL “empty” string.
543void tv_list_append_string(list_T *const l, const char *const str,
544 const ssize_t len)
545 FUNC_ATTR_NONNULL_ARG(1)
546{
547 tv_list_append_owned_tv(l, (typval_T) {
548 .v_type = VAR_STRING,
549 .v_lock = VAR_UNLOCKED,
550 .vval.v_string = (str == NULL
551 ? NULL
552 : (len >= 0
553 ? xmemdupz(str, (size_t)len)
554 : xstrdup(str))),
555 });
556}
557
558/// Append given string to the list
559///
560/// Unlike list_append_string this function does not copy the string.
561///
562/// @param[out] l List to append to.
563/// @param[in] str String to append.
564void tv_list_append_allocated_string(list_T *const l, char *const str)
565 FUNC_ATTR_NONNULL_ARG(1)
566{
567 tv_list_append_owned_tv(l, (typval_T) {
568 .v_type = VAR_STRING,
569 .v_lock = VAR_UNLOCKED,
570 .vval.v_string = (char_u *)str,
571 });
572}
573
574/// Append number to the list
575///
576/// @param[out] l List to append to.
577/// @param[in] n Number to append. Will be recorded in the allocated
578/// listitem_T.
579void tv_list_append_number(list_T *const l, const varnumber_T n)
580{
581 tv_list_append_owned_tv(l, (typval_T) {
582 .v_type = VAR_NUMBER,
583 .v_lock = VAR_UNLOCKED,
584 .vval.v_number = n,
585 });
586}
587
588//{{{2 Operations on the whole list
589
590/// Make a copy of list
591///
592/// @param[in] conv If non-NULL, then all internal strings will be converted.
593/// Only used when `deep` is true.
594/// @param[in] orig Original list to copy.
595/// @param[in] deep If false, then shallow copy will be done.
596/// @param[in] copyID See var_item_copy().
597///
598/// @return Copied list. May be NULL in case original list is NULL or some
599/// failure happens. The refcount of the new list is set to 1.
600list_T *tv_list_copy(const vimconv_T *const conv, list_T *const orig,
601 const bool deep, const int copyID)
602 FUNC_ATTR_WARN_UNUSED_RESULT
603{
604 if (orig == NULL) {
605 return NULL;
606 }
607
608 list_T *copy = tv_list_alloc(tv_list_len(orig));
609 tv_list_ref(copy);
610 if (copyID != 0) {
611 // Do this before adding the items, because one of the items may
612 // refer back to this list.
613 orig->lv_copyID = copyID;
614 orig->lv_copylist = copy;
615 }
616 TV_LIST_ITER(orig, item, {
617 if (got_int) {
618 break;
619 }
620 listitem_T *const ni = tv_list_item_alloc();
621 if (deep) {
622 if (var_item_copy(conv, TV_LIST_ITEM_TV(item), TV_LIST_ITEM_TV(ni),
623 deep, copyID) == FAIL) {
624 xfree(ni);
625 goto tv_list_copy_error;
626 }
627 } else {
628 tv_copy(TV_LIST_ITEM_TV(item), TV_LIST_ITEM_TV(ni));
629 }
630 tv_list_append(copy, ni);
631 });
632
633 return copy;
634
635tv_list_copy_error:
636 tv_list_unref(copy);
637 return NULL;
638}
639
640/// Extend first list with the second
641///
642/// @param[out] l1 List to extend.
643/// @param[in] l2 List to extend with.
644/// @param[in] bef If not NULL, extends before this item.
645void tv_list_extend(list_T *const l1, list_T *const l2,
646 listitem_T *const bef)
647 FUNC_ATTR_NONNULL_ARG(1)
648{
649 int todo = tv_list_len(l2);
650 listitem_T *const befbef = (bef == NULL ? NULL : bef->li_prev);
651 listitem_T *const saved_next = (befbef == NULL ? NULL : befbef->li_next);
652 // We also quit the loop when we have inserted the original item count of
653 // the list, avoid a hang when we extend a list with itself.
654 for (listitem_T *item = tv_list_first(l2)
655 ; item != NULL && todo--
656 ; item = (item == befbef ? saved_next : item->li_next)) {
657 tv_list_insert_tv(l1, TV_LIST_ITEM_TV(item), bef);
658 }
659}
660
661/// Concatenate lists into a new list
662///
663/// @param[in] l1 First list.
664/// @param[in] l2 Second list.
665/// @param[out] ret_tv Location where new list is saved.
666///
667/// @return OK or FAIL.
668int tv_list_concat(list_T *const l1, list_T *const l2, typval_T *const tv)
669 FUNC_ATTR_WARN_UNUSED_RESULT
670{
671 list_T *l;
672
673 tv->v_type = VAR_LIST;
674
675 if (l1 == NULL && l2 == NULL) {
676 l = NULL;
677 } else if (l1 == NULL) {
678 l = tv_list_copy(NULL, l2, false, 0);
679 } else {
680 l = tv_list_copy(NULL, l1, false, 0);
681 if (l != NULL && l2 != NULL) {
682 tv_list_extend(l, l2, NULL);
683 }
684 }
685 if (l == NULL && !(l1 == NULL && l2 == NULL)) {
686 return FAIL;
687 }
688
689 tv->vval.v_list = l;
690 return OK;
691}
692
693typedef struct {
694 char_u *s;
695 char_u *tofree;
696} Join;
697
698/// Join list into a string, helper function
699///
700/// @param[out] gap Garray where result will be saved.
701/// @param[in] l List to join.
702/// @param[in] sep Used separator.
703/// @param[in] join_gap Garray to keep each list item string.
704///
705/// @return OK in case of success, FAIL otherwise.
706static int list_join_inner(garray_T *const gap, list_T *const l,
707 const char *const sep, garray_T *const join_gap)
708 FUNC_ATTR_NONNULL_ALL
709{
710 size_t sumlen = 0;
711 bool first = true;
712
713 // Stringify each item in the list.
714 TV_LIST_ITER(l, item, {
715 if (got_int) {
716 break;
717 }
718 char *s;
719 size_t len;
720 s = encode_tv2echo(TV_LIST_ITEM_TV(item), &len);
721 if (s == NULL) {
722 return FAIL;
723 }
724
725 sumlen += len;
726
727 Join *const p = GA_APPEND_VIA_PTR(Join, join_gap);
728 p->tofree = p->s = (char_u *)s;
729
730 line_breakcheck();
731 });
732
733 // Allocate result buffer with its total size, avoid re-allocation and
734 // multiple copy operations. Add 2 for a tailing ']' and NUL.
735 if (join_gap->ga_len >= 2) {
736 sumlen += strlen(sep) * (size_t)(join_gap->ga_len - 1);
737 }
738 ga_grow(gap, (int)sumlen + 2);
739
740 for (int i = 0; i < join_gap->ga_len && !got_int; i++) {
741 if (first) {
742 first = false;
743 } else {
744 ga_concat(gap, (const char_u *)sep);
745 }
746 const Join *const p = ((const Join *)join_gap->ga_data) + i;
747
748 if (p->s != NULL) {
749 ga_concat(gap, p->s);
750 }
751 line_breakcheck();
752 }
753
754 return OK;
755}
756
757/// Join list into a string using given separator
758///
759/// @param[out] gap Garray where result will be saved.
760/// @param[in] l Joined list.
761/// @param[in] sep Separator.
762///
763/// @return OK in case of success, FAIL otherwise.
764int tv_list_join(garray_T *const gap, list_T *const l, const char *const sep)
765 FUNC_ATTR_NONNULL_ARG(1)
766{
767 if (!tv_list_len(l)) {
768 return OK;
769 }
770
771 garray_T join_ga;
772 int retval;
773
774 ga_init(&join_ga, (int)sizeof(Join), tv_list_len(l));
775 retval = list_join_inner(gap, l, sep, &join_ga);
776
777#define FREE_JOIN_TOFREE(join) xfree((join)->tofree)
778 GA_DEEP_CLEAR(&join_ga, Join, FREE_JOIN_TOFREE);
779#undef FREE_JOIN_TOFREE
780
781 return retval;
782}
783
784/// Chech whether two lists are equal
785///
786/// @param[in] l1 First list to compare.
787/// @param[in] l2 Second list to compare.
788/// @param[in] ic True if case is to be ignored.
789/// @param[in] recursive True when used recursively.
790///
791/// @return True if lists are equal, false otherwise.
792bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic,
793 const bool recursive)
794 FUNC_ATTR_WARN_UNUSED_RESULT
795{
796 if (l1 == l2) {
797 return true;
798 }
799 if (l1 == NULL || l2 == NULL) {
800 return false;
801 }
802 if (tv_list_len(l1) != tv_list_len(l2)) {
803 return false;
804 }
805
806 listitem_T *item1 = tv_list_first(l1);
807 listitem_T *item2 = tv_list_first(l2);
808 for (; item1 != NULL && item2 != NULL
809 ; (item1 = TV_LIST_ITEM_NEXT(l1, item1),
810 item2 = TV_LIST_ITEM_NEXT(l2, item2))) {
811 if (!tv_equal(TV_LIST_ITEM_TV(item1), TV_LIST_ITEM_TV(item2), ic,
812 recursive)) {
813 return false;
814 }
815 }
816 assert(item1 == NULL && item2 == NULL);
817 return true;
818}
819
820/// Reverse list in-place
821///
822/// @param[in,out] l List to reverse.
823void tv_list_reverse(list_T *const l)
824{
825 if (tv_list_len(l) <= 1) {
826 return;
827 }
828 list_log(l, NULL, NULL, "reverse");
829#define SWAP(a, b) \
830 do { \
831 tmp = a; \
832 a = b; \
833 b = tmp; \
834 } while (0)
835 listitem_T *tmp;
836
837 SWAP(l->lv_first, l->lv_last);
838 for (listitem_T *li = l->lv_first; li != NULL; li = li->li_next) {
839 SWAP(li->li_next, li->li_prev);
840 }
841#undef SWAP
842
843 l->lv_idx = l->lv_len - l->lv_idx - 1;
844}
845
846// FIXME Add unit tests for tv_list_item_sort().
847
848/// Sort list using libc qsort
849///
850/// @param[in,out] l List to sort, will be sorted in-place.
851/// @param ptrs Preallocated array of items to sort, must have at least
852/// tv_list_len(l) entries. Should not be initialized.
853/// @param[in] item_compare_func Function used to compare list items.
854/// @param errp Location where information about whether error occurred is
855/// saved by item_compare_func. If boolean there appears to be
856/// true list will not be modified. Must be initialized to false
857/// by the caller.
858void tv_list_item_sort(list_T *const l, ListSortItem *const ptrs,
859 const ListSorter item_compare_func,
860 bool *errp)
861 FUNC_ATTR_NONNULL_ARG(3, 4)
862{
863 const int len = tv_list_len(l);
864 if (len <= 1) {
865 return;
866 }
867 list_log(l, NULL, NULL, "sort");
868 int i = 0;
869 TV_LIST_ITER(l, li, {
870 ptrs[i].item = li;
871 ptrs[i].idx = i;
872 i++;
873 });
874 // Sort the array with item pointers.
875 qsort(ptrs, (size_t)len, sizeof(ListSortItem), item_compare_func);
876 if (!(*errp)) {
877 // Clear the list and append the items in the sorted order.
878 l->lv_first = NULL;
879 l->lv_last = NULL;
880 l->lv_idx_item = NULL;
881 l->lv_len = 0;
882 for (i = 0; i < len; i++) {
883 tv_list_append(l, ptrs[i].item);
884 }
885 }
886}
887
888//{{{2 Indexing/searching
889
890/// Locate item with a given index in a list and return it
891///
892/// @param[in] l List to index.
893/// @param[in] n Index. Negative index is counted from the end, -1 is the last
894/// item.
895///
896/// @return Item at the given index or NULL if `n` is out of range.
897listitem_T *tv_list_find(list_T *const l, int n)
898 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
899{
900 STATIC_ASSERT(sizeof(n) == sizeof(l->lv_idx),
901 "n and lv_idx sizes do not match");
902 if (l == NULL) {
903 return NULL;
904 }
905
906 n = tv_list_uidx(l, n);
907 if (n == -1) {
908 return NULL;
909 }
910
911 int idx;
912 listitem_T *item;
913
914 // When there is a cached index may start search from there.
915 if (l->lv_idx_item != NULL) {
916 if (n < l->lv_idx / 2) {
917 // Closest to the start of the list.
918 item = l->lv_first;
919 idx = 0;
920 } else if (n > (l->lv_idx + l->lv_len) / 2) {
921 // Closest to the end of the list.
922 item = l->lv_last;
923 idx = l->lv_len - 1;
924 } else {
925 // Closest to the cached index.
926 item = l->lv_idx_item;
927 idx = l->lv_idx;
928 }
929 } else {
930 if (n < l->lv_len / 2) {
931 // Closest to the start of the list.
932 item = l->lv_first;
933 idx = 0;
934 } else {
935 // Closest to the end of the list.
936 item = l->lv_last;
937 idx = l->lv_len - 1;
938 }
939 }
940
941 while (n > idx) {
942 // Search forward.
943 item = item->li_next;
944 idx++;
945 }
946 while (n < idx) {
947 // Search backward.
948 item = item->li_prev;
949 idx--;
950 }
951
952 assert(idx == n);
953 // Cache the used index.
954 l->lv_idx = idx;
955 l->lv_idx_item = item;
956 list_log(l, l->lv_idx_item, (void *)(uintptr_t)l->lv_idx, "find");
957
958 return item;
959}
960
961/// Get list item l[n] as a number
962///
963/// @param[in] l List to index.
964/// @param[in] n Index in a list.
965/// @param[out] ret_error Location where 1 will be saved if index was not
966/// found. May be NULL. If everything is OK,
967/// `*ret_error` is not touched.
968///
969/// @return Integer value at the given index or -1.
970varnumber_T tv_list_find_nr(list_T *const l, const int n, bool *const ret_error)
971 FUNC_ATTR_WARN_UNUSED_RESULT
972{
973 const listitem_T *const li = tv_list_find(l, n);
974 if (li == NULL) {
975 if (ret_error != NULL) {
976 *ret_error = true;
977 }
978 return -1;
979 }
980 return tv_get_number_chk(TV_LIST_ITEM_TV(li), ret_error);
981}
982
983/// Get list item l[n] as a string
984///
985/// @param[in] l List to index.
986/// @param[in] n Index in a list.
987///
988/// @return List item string value or NULL in case of error.
989const char *tv_list_find_str(list_T *const l, const int n)
990 FUNC_ATTR_WARN_UNUSED_RESULT
991{
992 const listitem_T *const li = tv_list_find(l, n);
993 if (li == NULL) {
994 EMSG2(_(e_listidx), (int64_t)n);
995 return NULL;
996 }
997 return tv_get_string(TV_LIST_ITEM_TV(li));
998}
999
1000/// Locate item in a list and return its index
1001///
1002/// @param[in] l List to search.
1003/// @param[in] item Item to search for.
1004///
1005/// @return Index of an item or -1 if item is not in the list.
1006long tv_list_idx_of_item(const list_T *const l, const listitem_T *const item)
1007 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
1008{
1009 if (l == NULL) {
1010 return -1;
1011 }
1012 int idx = 0;
1013 TV_LIST_ITER_CONST(l, li, {
1014 if (li == item) {
1015 return idx;
1016 }
1017 idx++;
1018 });
1019 return -1;
1020}
1021
1022//{{{1 Dictionaries
1023//{{{2 Dictionary watchers
1024
1025/// Perform all necessary cleanup for a `DictWatcher` instance
1026///
1027/// @param watcher Watcher to free.
1028static void tv_dict_watcher_free(DictWatcher *watcher)
1029 FUNC_ATTR_NONNULL_ALL
1030{
1031 callback_free(&watcher->callback);
1032 xfree(watcher->key_pattern);
1033 xfree(watcher);
1034}
1035
1036/// Add watcher to a dictionary
1037///
1038/// @param[in] dict Dictionary to add watcher to.
1039/// @param[in] key_pattern Pattern to watch for.
1040/// @param[in] key_pattern_len Key pattern length.
1041/// @param callback Function to be called on events.
1042void tv_dict_watcher_add(dict_T *const dict, const char *const key_pattern,
1043 const size_t key_pattern_len, Callback callback)
1044 FUNC_ATTR_NONNULL_ARG(2)
1045{
1046 if (dict == NULL) {
1047 return;
1048 }
1049 DictWatcher *const watcher = xmalloc(sizeof(DictWatcher));
1050 watcher->key_pattern = xmemdupz(key_pattern, key_pattern_len);
1051 watcher->key_pattern_len = key_pattern_len;
1052 watcher->callback = callback;
1053 watcher->busy = false;
1054 QUEUE_INSERT_TAIL(&dict->watchers, &watcher->node);
1055}
1056
1057/// Check whether two callbacks are equal
1058///
1059/// @param[in] cb1 First callback to check.
1060/// @param[in] cb2 Second callback to check.
1061///
1062/// @return True if they are equal, false otherwise.
1063bool tv_callback_equal(const Callback *cb1, const Callback *cb2)
1064 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
1065{
1066 if (cb1->type != cb2->type) {
1067 return false;
1068 }
1069 switch (cb1->type) {
1070 case kCallbackFuncref: {
1071 return STRCMP(cb1->data.funcref, cb2->data.funcref) == 0;
1072 }
1073 case kCallbackPartial: {
1074 // FIXME: this is inconsistent with tv_equal but is needed for precision
1075 // maybe change dictwatcheradd to return a watcher id instead?
1076 return cb1->data.partial == cb2->data.partial;
1077 }
1078 case kCallbackNone: {
1079 return true;
1080 }
1081 }
1082 abort();
1083 return false;
1084}
1085
1086/// Unref/free callback
1087void callback_free(Callback *callback)
1088 FUNC_ATTR_NONNULL_ALL
1089{
1090 switch (callback->type) {
1091 case kCallbackFuncref: {
1092 func_unref(callback->data.funcref);
1093 xfree(callback->data.funcref);
1094 break;
1095 }
1096 case kCallbackPartial: {
1097 partial_unref(callback->data.partial);
1098 break;
1099 }
1100 case kCallbackNone: {
1101 break;
1102 }
1103 }
1104 callback->type = kCallbackNone;
1105}
1106
1107/// Remove watcher from a dictionary
1108///
1109/// @param dict Dictionary to remove watcher from.
1110/// @param[in] key_pattern Pattern to remove watcher for.
1111/// @param[in] key_pattern_len Pattern length.
1112/// @param callback Callback to remove watcher for.
1113///
1114/// @return True on success, false if relevant watcher was not found.
1115bool tv_dict_watcher_remove(dict_T *const dict, const char *const key_pattern,
1116 const size_t key_pattern_len,
1117 Callback callback)
1118 FUNC_ATTR_NONNULL_ARG(2)
1119{
1120 if (dict == NULL) {
1121 return false;
1122 }
1123
1124 QUEUE *w = NULL;
1125 DictWatcher *watcher = NULL;
1126 bool matched = false;
1127 QUEUE_FOREACH(w, &dict->watchers) {
1128 watcher = tv_dict_watcher_node_data(w);
1129 if (tv_callback_equal(&watcher->callback, &callback)
1130 && watcher->key_pattern_len == key_pattern_len
1131 && memcmp(watcher->key_pattern, key_pattern, key_pattern_len) == 0) {
1132 matched = true;
1133 break;
1134 }
1135 }
1136
1137 if (!matched) {
1138 return false;
1139 }
1140
1141 QUEUE_REMOVE(w);
1142 tv_dict_watcher_free(watcher);
1143 return true;
1144}
1145
1146/// Test if `key` matches with with `watcher->key_pattern`
1147///
1148/// @param[in] watcher Watcher to check key pattern from.
1149/// @param[in] key Key to check.
1150///
1151/// @return true if key matches, false otherwise.
1152static bool tv_dict_watcher_matches(DictWatcher *watcher, const char *const key)
1153 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
1154{
1155 // For now only allow very simple globbing in key patterns: a '*' at the end
1156 // of the string means it should match everything up to the '*' instead of the
1157 // whole string.
1158 const size_t len = watcher->key_pattern_len;
1159 if (len && watcher->key_pattern[len - 1] == '*') {
1160 return strncmp(key, watcher->key_pattern, len - 1) == 0;
1161 } else {
1162 return strcmp(key, watcher->key_pattern) == 0;
1163 }
1164}
1165
1166/// Send a change notification to all dictionary watchers that match given key
1167///
1168/// @param[in] dict Dictionary which was modified.
1169/// @param[in] key Key which was modified.
1170/// @param[in] newtv New key value.
1171/// @param[in] oldtv Old key value.
1172void tv_dict_watcher_notify(dict_T *const dict, const char *const key,
1173 typval_T *const newtv, typval_T *const oldtv)
1174 FUNC_ATTR_NONNULL_ARG(1, 2)
1175{
1176 typval_T argv[3];
1177
1178 argv[0].v_type = VAR_DICT;
1179 argv[0].v_lock = VAR_UNLOCKED;
1180 argv[0].vval.v_dict = dict;
1181 argv[1].v_type = VAR_STRING;
1182 argv[1].v_lock = VAR_UNLOCKED;
1183 argv[1].vval.v_string = (char_u *)xstrdup(key);
1184 argv[2].v_type = VAR_DICT;
1185 argv[2].v_lock = VAR_UNLOCKED;
1186 argv[2].vval.v_dict = tv_dict_alloc();
1187 argv[2].vval.v_dict->dv_refcount++;
1188
1189 if (newtv) {
1190 dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("new"));
1191 tv_copy(newtv, &v->di_tv);
1192 tv_dict_add(argv[2].vval.v_dict, v);
1193 }
1194
1195 if (oldtv) {
1196 dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("old"));
1197 tv_copy(oldtv, &v->di_tv);
1198 tv_dict_add(argv[2].vval.v_dict, v);
1199 }
1200
1201 typval_T rettv;
1202
1203 QUEUE *w;
1204 QUEUE_FOREACH(w, &dict->watchers) {
1205 DictWatcher *watcher = tv_dict_watcher_node_data(w);
1206 if (!watcher->busy && tv_dict_watcher_matches(watcher, key)) {
1207 rettv = TV_INITIAL_VALUE;
1208 watcher->busy = true;
1209 callback_call(&watcher->callback, 3, argv, &rettv);
1210 watcher->busy = false;
1211 tv_clear(&rettv);
1212 }
1213 }
1214
1215 for (size_t i = 1; i < ARRAY_SIZE(argv); i++) {
1216 tv_clear(argv + i);
1217 }
1218}
1219
1220//{{{2 Dictionary item
1221
1222/// Allocate a dictionary item
1223///
1224/// @note that the type and value of the item (->di_tv) still needs to
1225/// be initialized.
1226///
1227/// @param[in] key Key, is copied to the new item.
1228/// @param[in] key_len Key length.
1229///
1230/// @return [allocated] new dictionary item.
1231dictitem_T *tv_dict_item_alloc_len(const char *const key, const size_t key_len)
1232 FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
1233 FUNC_ATTR_MALLOC
1234{
1235 dictitem_T *const di = xmalloc(offsetof(dictitem_T, di_key) + key_len + 1);
1236 memcpy(di->di_key, key, key_len);
1237 di->di_key[key_len] = NUL;
1238 di->di_flags = DI_FLAGS_ALLOC;
1239 di->di_tv.v_lock = VAR_UNLOCKED;
1240 return di;
1241}
1242
1243/// Allocate a dictionary item
1244///
1245/// @note that the type and value of the item (->di_tv) still needs to
1246/// be initialized.
1247///
1248/// @param[in] key Key, is copied to the new item.
1249///
1250/// @return [allocated] new dictionary item.
1251dictitem_T *tv_dict_item_alloc(const char *const key)
1252 FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
1253 FUNC_ATTR_MALLOC
1254{
1255 return tv_dict_item_alloc_len(key, strlen(key));
1256}
1257
1258/// Free a dictionary item, also clearing the value
1259///
1260/// @param item Item to free.
1261void tv_dict_item_free(dictitem_T *const item)
1262 FUNC_ATTR_NONNULL_ALL
1263{
1264 tv_clear(&item->di_tv);
1265 if (item->di_flags & DI_FLAGS_ALLOC) {
1266 xfree(item);
1267 }
1268}
1269
1270/// Make a copy of a dictionary item
1271///
1272/// @param[in] di Item to copy.
1273///
1274/// @return [allocated] new dictionary item.
1275dictitem_T *tv_dict_item_copy(dictitem_T *const di)
1276 FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
1277{
1278 dictitem_T *const new_di = tv_dict_item_alloc((const char *)di->di_key);
1279 tv_copy(&di->di_tv, &new_di->di_tv);
1280 return new_di;
1281}
1282
1283/// Remove item from dictionary and free it
1284///
1285/// @param dict Dictionary to remove item from.
1286/// @param item Item to remove.
1287void tv_dict_item_remove(dict_T *const dict, dictitem_T *const item)
1288 FUNC_ATTR_NONNULL_ALL
1289{
1290 hashitem_T *const hi = hash_find(&dict->dv_hashtab, item->di_key);
1291 if (HASHITEM_EMPTY(hi)) {
1292 emsgf(_(e_intern2), "tv_dict_item_remove()");
1293 } else {
1294 hash_remove(&dict->dv_hashtab, hi);
1295 }
1296 tv_dict_item_free(item);
1297}
1298
1299//{{{2 Alloc/free
1300
1301/// Allocate an empty dictionary
1302///
1303/// @return [allocated] new dictionary.
1304dict_T *tv_dict_alloc(void)
1305 FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
1306{
1307 dict_T *const d = xmalloc(sizeof(dict_T));
1308
1309 // Add the dict to the list of dicts for garbage collection.
1310 if (gc_first_dict != NULL) {
1311 gc_first_dict->dv_used_prev = d;
1312 }
1313 d->dv_used_next = gc_first_dict;
1314 d->dv_used_prev = NULL;
1315 gc_first_dict = d;
1316
1317 hash_init(&d->dv_hashtab);
1318 d->dv_lock = VAR_UNLOCKED;
1319 d->dv_scope = VAR_NO_SCOPE;
1320 d->dv_refcount = 0;
1321 d->dv_copyID = 0;
1322 QUEUE_INIT(&d->watchers);
1323
1324 return d;
1325}
1326
1327/// Free items contained in a dictionary
1328///
1329/// @param[in,out] d Dictionary to clear.
1330void tv_dict_free_contents(dict_T *const d)
1331 FUNC_ATTR_NONNULL_ALL
1332{
1333 // Lock the hashtab, we don't want it to resize while freeing items.
1334 hash_lock(&d->dv_hashtab);
1335 assert(d->dv_hashtab.ht_locked > 0);
1336 HASHTAB_ITER(&d->dv_hashtab, hi, {
1337 // Remove the item before deleting it, just in case there is
1338 // something recursive causing trouble.
1339 dictitem_T *const di = TV_DICT_HI2DI(hi);
1340 hash_remove(&d->dv_hashtab, hi);
1341 tv_dict_item_free(di);
1342 });
1343
1344 while (!QUEUE_EMPTY(&d->watchers)) {
1345 QUEUE *w = QUEUE_HEAD(&d->watchers);
1346 QUEUE_REMOVE(w);
1347 DictWatcher *watcher = tv_dict_watcher_node_data(w);
1348 tv_dict_watcher_free(watcher);
1349 }
1350
1351 hash_clear(&d->dv_hashtab);
1352 d->dv_hashtab.ht_locked--;
1353 hash_init(&d->dv_hashtab);
1354}
1355
1356/// Free a dictionary itself, ignoring items it contains
1357///
1358/// Ignores the reference count.
1359///
1360/// @param[in,out] d Dictionary to free.
1361void tv_dict_free_dict(dict_T *const d)
1362 FUNC_ATTR_NONNULL_ALL
1363{
1364 // Remove the dict from the list of dicts for garbage collection.
1365 if (d->dv_used_prev == NULL) {
1366 gc_first_dict = d->dv_used_next;
1367 } else {
1368 d->dv_used_prev->dv_used_next = d->dv_used_next;
1369 }
1370 if (d->dv_used_next != NULL) {
1371 d->dv_used_next->dv_used_prev = d->dv_used_prev;
1372 }
1373
1374 xfree(d);
1375}
1376
1377/// Free a dictionary, including all items it contains
1378///
1379/// Ignores the reference count.
1380///
1381/// @param d Dictionary to free.
1382void tv_dict_free(dict_T *const d)
1383 FUNC_ATTR_NONNULL_ALL
1384{
1385 if (!tv_in_free_unref_items) {
1386 tv_dict_free_contents(d);
1387 tv_dict_free_dict(d);
1388 }
1389}
1390
1391
1392/// Unreference a dictionary
1393///
1394/// Decrements the reference count and frees dictionary when it becomes zero.
1395///
1396/// @param[in] d Dictionary to operate on.
1397void tv_dict_unref(dict_T *const d)
1398{
1399 if (d != NULL && --d->dv_refcount <= 0) {
1400 tv_dict_free(d);
1401 }
1402}
1403
1404//{{{2 Indexing/searching
1405
1406/// Find item in dictionary
1407///
1408/// @param[in] d Dictionary to check.
1409/// @param[in] key Dictionary key.
1410/// @param[in] len Key length. If negative, then strlen(key) is used.
1411///
1412/// @return found item or NULL if nothing was found.
1413dictitem_T *tv_dict_find(const dict_T *const d, const char *const key,
1414 const ptrdiff_t len)
1415 FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
1416{
1417 if (d == NULL) {
1418 return NULL;
1419 }
1420 hashitem_T *const hi = (len < 0
1421 ? hash_find(&d->dv_hashtab, (const char_u *)key)
1422 : hash_find_len(&d->dv_hashtab, key, (size_t)len));
1423 if (HASHITEM_EMPTY(hi)) {
1424 return NULL;
1425 }
1426 return TV_DICT_HI2DI(hi);
1427}
1428
1429/// Get a number item from a dictionary
1430///
1431/// Returns 0 if the entry does not exist.
1432///
1433/// @param[in] d Dictionary to get item from.
1434/// @param[in] key Key to find in dictionary.
1435///
1436/// @return Dictionary item.
1437varnumber_T tv_dict_get_number(const dict_T *const d, const char *const key)
1438 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
1439{
1440 dictitem_T *const di = tv_dict_find(d, key, -1);
1441 if (di == NULL) {
1442 return 0;
1443 }
1444 return tv_get_number(&di->di_tv);
1445}
1446
1447/// Get a string item from a dictionary
1448///
1449/// @param[in] d Dictionary to get item from.
1450/// @param[in] key Dictionary key.
1451/// @param[in] save If true, returned string will be placed in the allocated
1452/// memory.
1453///
1454/// @return NULL if key does not exist, empty string in case of type error,
1455/// string item value otherwise. If returned value is not NULL, it may
1456/// be allocated depending on `save` argument.
1457char *tv_dict_get_string(const dict_T *const d, const char *const key,
1458 const bool save)
1459 FUNC_ATTR_WARN_UNUSED_RESULT
1460{
1461 static char numbuf[NUMBUFLEN];
1462 const char *const s = tv_dict_get_string_buf(d, key, numbuf);
1463 if (save && s != NULL) {
1464 return xstrdup(s);
1465 }
1466 return (char *)s;
1467}
1468
1469/// Get a string item from a dictionary
1470///
1471/// @param[in] d Dictionary to get item from.
1472/// @param[in] key Dictionary key.
1473/// @param[in] numbuf Buffer for non-string items converted to strings, at
1474/// least of #NUMBUFLEN length.
1475///
1476/// @return NULL if key does not exist, empty string in case of type error,
1477/// string item value otherwise.
1478const char *tv_dict_get_string_buf(const dict_T *const d, const char *const key,
1479 char *const numbuf)
1480 FUNC_ATTR_WARN_UNUSED_RESULT
1481{
1482 const dictitem_T *const di = tv_dict_find(d, key, -1);
1483 if (di == NULL) {
1484 return NULL;
1485 }
1486 return tv_get_string_buf(&di->di_tv, numbuf);
1487}
1488
1489/// Get a string item from a dictionary
1490///
1491/// @param[in] d Dictionary to get item from.
1492/// @param[in] key Dictionary key.
1493/// @param[in] key_len Key length.
1494/// @param[in] numbuf Buffer for non-string items converted to strings, at
1495/// least of #NUMBUFLEN length.
1496/// @param[in] def Default return when key does not exist.
1497///
1498/// @return `def` when key does not exist,
1499/// NULL in case of type error,
1500/// string item value in case of success.
1501const char *tv_dict_get_string_buf_chk(const dict_T *const d,
1502 const char *const key,
1503 const ptrdiff_t key_len,
1504 char *const numbuf,
1505 const char *const def)
1506 FUNC_ATTR_WARN_UNUSED_RESULT
1507{
1508 const dictitem_T *const di = tv_dict_find(d, key, key_len);
1509 if (di == NULL) {
1510 return def;
1511 }
1512 return tv_get_string_buf_chk(&di->di_tv, numbuf);
1513}
1514
1515/// Get a function from a dictionary
1516///
1517/// @param[in] d Dictionary to get callback from.
1518/// @param[in] key Dictionary key.
1519/// @param[in] key_len Key length, may be -1 to use strlen().
1520/// @param[out] result The address where a pointer to the wanted callback
1521/// will be left.
1522///
1523/// @return true/false on success/failure.
1524bool tv_dict_get_callback(dict_T *const d,
1525 const char *const key, const ptrdiff_t key_len,
1526 Callback *const result)
1527 FUNC_ATTR_NONNULL_ARG(2, 4) FUNC_ATTR_WARN_UNUSED_RESULT
1528{
1529 result->type = kCallbackNone;
1530
1531 dictitem_T *const di = tv_dict_find(d, key, key_len);
1532
1533 if (di == NULL) {
1534 return true;
1535 }
1536
1537 if (!tv_is_func(di->di_tv) && di->di_tv.v_type != VAR_STRING) {
1538 EMSG(_("E6000: Argument is not a function or function name"));
1539 return false;
1540 }
1541
1542 typval_T tv;
1543 tv_copy(&di->di_tv, &tv);
1544 set_selfdict(&tv, d);
1545 const bool res = callback_from_typval(result, &tv);
1546 tv_clear(&tv);
1547 return res;
1548}
1549
1550//{{{2 dict_add*
1551
1552/// Add item to dictionary
1553///
1554/// @param[out] d Dictionary to add to.
1555/// @param[in] item Item to add.
1556///
1557/// @return FAIL if key already exists.
1558int tv_dict_add(dict_T *const d, dictitem_T *const item)
1559 FUNC_ATTR_NONNULL_ALL
1560{
1561 return hash_add(&d->dv_hashtab, item->di_key);
1562}
1563
1564/// Add a list entry to dictionary
1565///
1566/// @param[out] d Dictionary to add entry to.
1567/// @param[in] key Key to add.
1568/// @param[in] key_len Key length.
1569/// @param list List to add. Will have reference count incremented.
1570///
1571/// @return OK in case of success, FAIL when key already exists.
1572int tv_dict_add_list(dict_T *const d, const char *const key,
1573 const size_t key_len, list_T *const list)
1574 FUNC_ATTR_NONNULL_ALL
1575{
1576 dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
1577
1578 item->di_tv.v_type = VAR_LIST;
1579 item->di_tv.vval.v_list = list;
1580 tv_list_ref(list);
1581 if (tv_dict_add(d, item) == FAIL) {
1582 tv_dict_item_free(item);
1583 return FAIL;
1584 }
1585 return OK;
1586}
1587
1588/// Add a dictionary entry to dictionary
1589///
1590/// @param[out] d Dictionary to add entry to.
1591/// @param[in] key Key to add.
1592/// @param[in] key_len Key length.
1593/// @param dict Dictionary to add. Will have reference count incremented.
1594///
1595/// @return OK in case of success, FAIL when key already exists.
1596int tv_dict_add_dict(dict_T *const d, const char *const key,
1597 const size_t key_len, dict_T *const dict)
1598 FUNC_ATTR_NONNULL_ALL
1599{
1600 dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
1601
1602 item->di_tv.v_type = VAR_DICT;
1603 item->di_tv.vval.v_dict = dict;
1604 dict->dv_refcount++;
1605 if (tv_dict_add(d, item) == FAIL) {
1606 tv_dict_item_free(item);
1607 return FAIL;
1608 }
1609 return OK;
1610}
1611
1612/// Add a number entry to dictionary
1613///
1614/// @param[out] d Dictionary to add entry to.
1615/// @param[in] key Key to add.
1616/// @param[in] key_len Key length.
1617/// @param[in] nr Number to add.
1618///
1619/// @return OK in case of success, FAIL when key already exists.
1620int tv_dict_add_nr(dict_T *const d, const char *const key,
1621 const size_t key_len, const varnumber_T nr)
1622{
1623 dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
1624
1625 item->di_tv.v_type = VAR_NUMBER;
1626 item->di_tv.vval.v_number = nr;
1627 if (tv_dict_add(d, item) == FAIL) {
1628 tv_dict_item_free(item);
1629 return FAIL;
1630 }
1631 return OK;
1632}
1633
1634/// Add a special entry to dictionary
1635///
1636/// @param[out] d Dictionary to add entry to.
1637/// @param[in] key Key to add.
1638/// @param[in] key_len Key length.
1639/// @param[in] val SpecialVarValue to add.
1640///
1641/// @return OK in case of success, FAIL when key already exists.
1642int tv_dict_add_special(dict_T *const d, const char *const key,
1643 const size_t key_len, SpecialVarValue val)
1644{
1645 dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
1646
1647 item->di_tv.v_type = VAR_SPECIAL;
1648 item->di_tv.vval.v_special = val;
1649 if (tv_dict_add(d, item) == FAIL) {
1650 tv_dict_item_free(item);
1651 return FAIL;
1652 }
1653 return OK;
1654}
1655
1656/// Add a string entry to dictionary
1657///
1658/// @see tv_dict_add_allocated_str
1659int tv_dict_add_str(dict_T *const d,
1660 const char *const key, const size_t key_len,
1661 const char *const val)
1662 FUNC_ATTR_NONNULL_ALL
1663{
1664 return tv_dict_add_allocated_str(d, key, key_len, xstrdup(val));
1665}
1666
1667/// Add a string entry to dictionary
1668///
1669/// @param[out] d Dictionary to add entry to.
1670/// @param[in] key Key to add.
1671/// @param[in] key_len Key length.
1672/// @param[in] val String to add. NULL adds empty string.
1673/// @param[in] len Use this many bytes from `val`, or -1 for whole string.
1674///
1675/// @return OK in case of success, FAIL when key already exists.
1676int tv_dict_add_str_len(dict_T *const d,
1677 const char *const key, const size_t key_len,
1678 char *const val, int len)
1679 FUNC_ATTR_NONNULL_ARG(1, 2)
1680{
1681 char *s = val ? val : "";
1682 if (val != NULL) {
1683 s = (len < 0) ? xstrdup(val) : xstrndup(val, (size_t)len);
1684 }
1685 return tv_dict_add_allocated_str(d, key, key_len, s);
1686}
1687
1688/// Add a string entry to dictionary
1689///
1690/// Unlike tv_dict_add_str() saves val to the new dictionary item in place of
1691/// creating a new copy.
1692///
1693/// @warning String will be freed even in case addition fails.
1694///
1695/// @param[out] d Dictionary to add entry to.
1696/// @param[in] key Key to add.
1697/// @param[in] key_len Key length.
1698/// @param[in] val String to add.
1699///
1700/// @return OK in case of success, FAIL when key already exists.
1701int tv_dict_add_allocated_str(dict_T *const d,
1702 const char *const key, const size_t key_len,
1703 char *const val)
1704 FUNC_ATTR_NONNULL_ALL
1705{
1706 dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
1707
1708 item->di_tv.v_type = VAR_STRING;
1709 item->di_tv.vval.v_string = (char_u *)val;
1710 if (tv_dict_add(d, item) == FAIL) {
1711 tv_dict_item_free(item);
1712 return FAIL;
1713 }
1714 return OK;
1715}
1716
1717//{{{2 Operations on the whole dict
1718
1719/// Clear all the keys of a Dictionary. "d" remains a valid empty Dictionary.
1720///
1721/// @param d The Dictionary to clear
1722void tv_dict_clear(dict_T *const d)
1723 FUNC_ATTR_NONNULL_ALL
1724{
1725 hash_lock(&d->dv_hashtab);
1726 assert(d->dv_hashtab.ht_locked > 0);
1727
1728 HASHTAB_ITER(&d->dv_hashtab, hi, {
1729 tv_dict_item_free(TV_DICT_HI2DI(hi));
1730 hash_remove(&d->dv_hashtab, hi);
1731 });
1732
1733 hash_unlock(&d->dv_hashtab);
1734}
1735
1736/// Extend dictionary with items from another dictionary
1737///
1738/// @param d1 Dictionary to extend.
1739/// @param[in] d2 Dictionary to extend with.
1740/// @param[in] action "error", "force", "keep":
1741///
1742/// e*, including "error": duplicate key gives an error.
1743/// f*, including "force": duplicate d2 keys override d1.
1744/// other, including "keep": duplicate d2 keys ignored.
1745void tv_dict_extend(dict_T *const d1, dict_T *const d2,
1746 const char *const action)
1747 FUNC_ATTR_NONNULL_ALL
1748{
1749 const bool watched = tv_dict_is_watched(d1);
1750 const char *const arg_errmsg = _("extend() argument");
1751 const size_t arg_errmsg_len = strlen(arg_errmsg);
1752
1753 TV_DICT_ITER(d2, di2, {
1754 dictitem_T *const di1 = tv_dict_find(d1, (const char *)di2->di_key, -1);
1755 if (d1->dv_scope != VAR_NO_SCOPE) {
1756 // Disallow replacing a builtin function in l: and g:.
1757 // Check the key to be valid when adding to any scope.
1758 if (d1->dv_scope == VAR_DEF_SCOPE
1759 && tv_is_func(di2->di_tv)
1760 && !var_check_func_name((const char *)di2->di_key, di1 == NULL)) {
1761 break;
1762 }
1763 if (!valid_varname((const char *)di2->di_key)) {
1764 break;
1765 }
1766 }
1767 if (di1 == NULL) {
1768 dictitem_T *const new_di = tv_dict_item_copy(di2);
1769 if (tv_dict_add(d1, new_di) == FAIL) {
1770 tv_dict_item_free(new_di);
1771 } else if (watched) {
1772 tv_dict_watcher_notify(d1, (const char *)new_di->di_key, &new_di->di_tv,
1773 NULL);
1774 }
1775 } else if (*action == 'e') {
1776 emsgf(_("E737: Key already exists: %s"), di2->di_key);
1777 break;
1778 } else if (*action == 'f' && di2 != di1) {
1779 typval_T oldtv;
1780
1781 if (tv_check_lock(di1->di_tv.v_lock, arg_errmsg, arg_errmsg_len)
1782 || var_check_ro(di1->di_flags, arg_errmsg, arg_errmsg_len)) {
1783 break;
1784 }
1785
1786 if (watched) {
1787 tv_copy(&di1->di_tv, &oldtv);
1788 }
1789
1790 tv_clear(&di1->di_tv);
1791 tv_copy(&di2->di_tv, &di1->di_tv);
1792
1793 if (watched) {
1794 tv_dict_watcher_notify(d1, (const char *)di1->di_key, &di1->di_tv,
1795 &oldtv);
1796 tv_clear(&oldtv);
1797 }
1798 }
1799 });
1800}
1801
1802/// Compare two dictionaries
1803///
1804/// @param[in] d1 First dictionary.
1805/// @param[in] d2 Second dictionary.
1806/// @param[in] ic True if case is to be ignored.
1807/// @param[in] recursive True when used recursively.
1808bool tv_dict_equal(dict_T *const d1, dict_T *const d2,
1809 const bool ic, const bool recursive)
1810 FUNC_ATTR_WARN_UNUSED_RESULT
1811{
1812 if (d1 == d2) {
1813 return true;
1814 }
1815 if (d1 == NULL || d2 == NULL) {
1816 return false;
1817 }
1818 if (tv_dict_len(d1) != tv_dict_len(d2)) {
1819 return false;
1820 }
1821
1822 TV_DICT_ITER(d1, di1, {
1823 dictitem_T *const di2 = tv_dict_find(d2, (const char *)di1->di_key, -1);
1824 if (di2 == NULL) {
1825 return false;
1826 }
1827 if (!tv_equal(&di1->di_tv, &di2->di_tv, ic, recursive)) {
1828 return false;
1829 }
1830 });
1831 return true;
1832}
1833
1834/// Make a copy of dictionary
1835///
1836/// @param[in] conv If non-NULL, then all internal strings will be converted.
1837/// @param[in] orig Original dictionary to copy.
1838/// @param[in] deep If false, then shallow copy will be done.
1839/// @param[in] copyID See var_item_copy().
1840///
1841/// @return Copied dictionary. May be NULL in case original dictionary is NULL
1842/// or some failure happens. The refcount of the new dictionary is set
1843/// to 1.
1844dict_T *tv_dict_copy(const vimconv_T *const conv,
1845 dict_T *const orig,
1846 const bool deep,
1847 const int copyID)
1848{
1849 if (orig == NULL) {
1850 return NULL;
1851 }
1852
1853 dict_T *copy = tv_dict_alloc();
1854 if (copyID != 0) {
1855 orig->dv_copyID = copyID;
1856 orig->dv_copydict = copy;
1857 }
1858 TV_DICT_ITER(orig, di, {
1859 if (got_int) {
1860 break;
1861 }
1862 dictitem_T *new_di;
1863 if (conv == NULL || conv->vc_type == CONV_NONE) {
1864 new_di = tv_dict_item_alloc((const char *)di->di_key);
1865 } else {
1866 size_t len = STRLEN(di->di_key);
1867 char *const key = (char *)string_convert(conv, di->di_key, &len);
1868 if (key == NULL) {
1869 new_di = tv_dict_item_alloc_len((const char *)di->di_key, len);
1870 } else {
1871 new_di = tv_dict_item_alloc_len(key, len);
1872 xfree(key);
1873 }
1874 }
1875 if (deep) {
1876 if (var_item_copy(conv, &di->di_tv, &new_di->di_tv, deep,
1877 copyID) == FAIL) {
1878 xfree(new_di);
1879 break;
1880 }
1881 } else {
1882 tv_copy(&di->di_tv, &new_di->di_tv);
1883 }
1884 if (tv_dict_add(copy, new_di) == FAIL) {
1885 tv_dict_item_free(new_di);
1886 break;
1887 }
1888 });
1889
1890 copy->dv_refcount++;
1891 if (got_int) {
1892 tv_dict_unref(copy);
1893 copy = NULL;
1894 }
1895
1896 return copy;
1897}
1898
1899/// Set all existing keys in "dict" as read-only.
1900///
1901/// This does not protect against adding new keys to the Dictionary.
1902///
1903/// @param dict The dict whose keys should be frozen.
1904void tv_dict_set_keys_readonly(dict_T *const dict)
1905 FUNC_ATTR_NONNULL_ALL
1906{
1907 TV_DICT_ITER(dict, di, {
1908 di->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX;
1909 });
1910}
1911
1912//{{{1 Generic typval operations
1913//{{{2 Init/alloc/clear
1914//{{{3 Alloc
1915
1916/// Allocate an empty list for a return value
1917///
1918/// Also sets reference count.
1919///
1920/// @param[out] ret_tv Structure where list is saved.
1921/// @param[in] len Expected number of items to be populated before list
1922/// becomes accessible from VimL. It is still valid to
1923/// underpopulate a list, value only controls how many elements
1924/// will be allocated in advance. @see ListLenSpecials.
1925///
1926/// @return [allocated] pointer to the created list.
1927list_T *tv_list_alloc_ret(typval_T *const ret_tv, const ptrdiff_t len)
1928 FUNC_ATTR_NONNULL_ALL
1929{
1930 list_T *const l = tv_list_alloc(len);
1931 tv_list_set_ret(ret_tv, l);
1932 ret_tv->v_lock = VAR_UNLOCKED;
1933 return l;
1934}
1935
1936/// Allocate an empty dictionary for a return value
1937///
1938/// Also sets reference count.
1939///
1940/// @param[out] ret_tv Structure where dictionary is saved.
1941void tv_dict_alloc_ret(typval_T *const ret_tv)
1942 FUNC_ATTR_NONNULL_ALL
1943{
1944 dict_T *const d = tv_dict_alloc();
1945 tv_dict_set_ret(ret_tv, d);
1946 ret_tv->v_lock = VAR_UNLOCKED;
1947}
1948
1949//{{{3 Clear
1950#define TYPVAL_ENCODE_ALLOW_SPECIALS false
1951
1952#define TYPVAL_ENCODE_CONV_NIL(tv) \
1953 do { \
1954 tv->vval.v_special = kSpecialVarFalse; \
1955 tv->v_lock = VAR_UNLOCKED; \
1956 } while (0)
1957
1958#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \
1959 TYPVAL_ENCODE_CONV_NIL(tv)
1960
1961#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \
1962 do { \
1963 (void)num; \
1964 tv->vval.v_number = 0; \
1965 tv->v_lock = VAR_UNLOCKED; \
1966 } while (0)
1967
1968#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num)
1969
1970#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \
1971 do { \
1972 tv->vval.v_float = 0; \
1973 tv->v_lock = VAR_UNLOCKED; \
1974 } while (0)
1975
1976#define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \
1977 do { \
1978 xfree(buf); \
1979 tv->vval.v_string = NULL; \
1980 tv->v_lock = VAR_UNLOCKED; \
1981 } while (0)
1982
1983#define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len)
1984
1985#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type)
1986
1987static inline int _nothing_conv_func_start(typval_T *const tv,
1988 char_u *const fun)
1989 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1)
1990{
1991 tv->v_lock = VAR_UNLOCKED;
1992 if (tv->v_type == VAR_PARTIAL) {
1993 partial_T *const pt_ = tv->vval.v_partial;
1994 if (pt_ != NULL && pt_->pt_refcount > 1) {
1995 pt_->pt_refcount--;
1996 tv->vval.v_partial = NULL;
1997 return OK;
1998 }
1999 } else {
2000 func_unref(fun);
2001 if ((const char *)fun != tv_empty_string) {
2002 xfree(fun);
2003 }
2004 tv->vval.v_string = NULL;
2005 }
2006 return NOTDONE;
2007}
2008#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
2009 do { \
2010 if (_nothing_conv_func_start(tv, fun) != NOTDONE) { \
2011 return OK; \
2012 } \
2013 } while (0)
2014
2015#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len)
2016#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len)
2017
2018static inline void _nothing_conv_func_end(typval_T *const tv, const int copyID)
2019 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
2020{
2021 if (tv->v_type == VAR_PARTIAL) {
2022 partial_T *const pt = tv->vval.v_partial;
2023 if (pt == NULL) {
2024 return;
2025 }
2026 // Dictionary should already be freed by the time.
2027 // If it was not freed then it is a part of the reference cycle.
2028 assert(pt->pt_dict == NULL || pt->pt_dict->dv_copyID == copyID);
2029 pt->pt_dict = NULL;
2030 // As well as all arguments.
2031 pt->pt_argc = 0;
2032 assert(pt->pt_refcount <= 1);
2033 partial_unref(pt);
2034 tv->vval.v_partial = NULL;
2035 assert(tv->v_lock == VAR_UNLOCKED);
2036 }
2037}
2038#define TYPVAL_ENCODE_CONV_FUNC_END(tv) _nothing_conv_func_end(tv, copyID)
2039
2040#define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \
2041 do { \
2042 tv_list_unref(tv->vval.v_list); \
2043 tv->vval.v_list = NULL; \
2044 tv->v_lock = VAR_UNLOCKED; \
2045 } while (0)
2046
2047static inline void _nothing_conv_empty_dict(typval_T *const tv,
2048 dict_T **const dictp)
2049 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(2)
2050{
2051 tv_dict_unref(*dictp);
2052 *dictp = NULL;
2053 if (tv != NULL) {
2054 tv->v_lock = VAR_UNLOCKED;
2055 }
2056}
2057#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \
2058 do { \
2059 assert((void *)&dict != (void *)&TYPVAL_ENCODE_NODICT_VAR); \
2060 _nothing_conv_empty_dict(tv, ((dict_T **)&dict)); \
2061 } while (0)
2062
2063static inline int _nothing_conv_real_list_after_start(
2064 typval_T *const tv, MPConvStackVal *const mpsv)
2065 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT
2066{
2067 assert(tv != NULL);
2068 tv->v_lock = VAR_UNLOCKED;
2069 if (tv->vval.v_list->lv_refcount > 1) {
2070 tv->vval.v_list->lv_refcount--;
2071 tv->vval.v_list = NULL;
2072 mpsv->data.l.li = NULL;
2073 return OK;
2074 }
2075 return NOTDONE;
2076}
2077#define TYPVAL_ENCODE_CONV_LIST_START(tv, len)
2078
2079#define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) \
2080 do { \
2081 if (_nothing_conv_real_list_after_start(tv, &mpsv) != NOTDONE) { \
2082 goto typval_encode_stop_converting_one_item; \
2083 } \
2084 } while (0)
2085
2086#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv)
2087
2088static inline void _nothing_conv_list_end(typval_T *const tv)
2089 FUNC_ATTR_ALWAYS_INLINE
2090{
2091 if (tv == NULL) {
2092 return;
2093 }
2094 assert(tv->v_type == VAR_LIST);
2095 list_T *const list = tv->vval.v_list;
2096 tv_list_unref(list);
2097 tv->vval.v_list = NULL;
2098}
2099#define TYPVAL_ENCODE_CONV_LIST_END(tv) _nothing_conv_list_end(tv)
2100
2101static inline int _nothing_conv_real_dict_after_start(
2102 typval_T *const tv, dict_T **const dictp, const void *const nodictvar,
2103 MPConvStackVal *const mpsv)
2104 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT
2105{
2106 if (tv != NULL) {
2107 tv->v_lock = VAR_UNLOCKED;
2108 }
2109 if ((const void *)dictp != nodictvar && (*dictp)->dv_refcount > 1) {
2110 (*dictp)->dv_refcount--;
2111 *dictp = NULL;
2112 mpsv->data.d.todo = 0;
2113 return OK;
2114 }
2115 return NOTDONE;
2116}
2117#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len)
2118
2119#define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv) \
2120 do { \
2121 if (_nothing_conv_real_dict_after_start( \
2122 tv, (dict_T **)&dict, (void *)&TYPVAL_ENCODE_NODICT_VAR, \
2123 &mpsv) != NOTDONE) { \
2124 goto typval_encode_stop_converting_one_item; \
2125 } \
2126 } while (0)
2127
2128#define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(tv, dict)
2129#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict)
2130#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict)
2131
2132static inline void _nothing_conv_dict_end(typval_T *const tv,
2133 dict_T **const dictp,
2134 const void *const nodictvar)
2135 FUNC_ATTR_ALWAYS_INLINE
2136{
2137 if ((const void *)dictp != nodictvar) {
2138 tv_dict_unref(*dictp);
2139 *dictp = NULL;
2140 }
2141}
2142#define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \
2143 _nothing_conv_dict_end(tv, (dict_T **)&dict, \
2144 (void *)&TYPVAL_ENCODE_NODICT_VAR)
2145
2146#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type)
2147
2148#define TYPVAL_ENCODE_SCOPE static
2149#define TYPVAL_ENCODE_NAME nothing
2150#define TYPVAL_ENCODE_FIRST_ARG_TYPE const void *const
2151#define TYPVAL_ENCODE_FIRST_ARG_NAME ignored
2152#define TYPVAL_ENCODE_TRANSLATE_OBJECT_NAME
2153#include "nvim/eval/typval_encode.c.h"
2154#undef TYPVAL_ENCODE_SCOPE
2155#undef TYPVAL_ENCODE_NAME
2156#undef TYPVAL_ENCODE_FIRST_ARG_TYPE
2157#undef TYPVAL_ENCODE_FIRST_ARG_NAME
2158#undef TYPVAL_ENCODE_TRANSLATE_OBJECT_NAME
2159
2160#undef TYPVAL_ENCODE_ALLOW_SPECIALS
2161#undef TYPVAL_ENCODE_CONV_NIL
2162#undef TYPVAL_ENCODE_CONV_BOOL
2163#undef TYPVAL_ENCODE_CONV_NUMBER
2164#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER
2165#undef TYPVAL_ENCODE_CONV_FLOAT
2166#undef TYPVAL_ENCODE_CONV_STRING
2167#undef TYPVAL_ENCODE_CONV_STR_STRING
2168#undef TYPVAL_ENCODE_CONV_EXT_STRING
2169#undef TYPVAL_ENCODE_CONV_FUNC_START
2170#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS
2171#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF
2172#undef TYPVAL_ENCODE_CONV_FUNC_END
2173#undef TYPVAL_ENCODE_CONV_EMPTY_LIST
2174#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
2175#undef TYPVAL_ENCODE_CONV_LIST_START
2176#undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START
2177#undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS
2178#undef TYPVAL_ENCODE_CONV_LIST_END
2179#undef TYPVAL_ENCODE_CONV_DICT_START
2180#undef TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START
2181#undef TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK
2182#undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY
2183#undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS
2184#undef TYPVAL_ENCODE_CONV_DICT_END
2185#undef TYPVAL_ENCODE_CONV_RECURSE
2186
2187/// Free memory for a variable value and set the value to NULL or 0
2188///
2189/// @param[in,out] tv Value to free.
2190void tv_clear(typval_T *const tv)
2191{
2192 if (tv != NULL && tv->v_type != VAR_UNKNOWN) {
2193 // WARNING: do not translate the string here, gettext is slow and function
2194 // is used *very* often. At the current state encode_vim_to_nothing() does
2195 // not error out and does not use the argument anywhere.
2196 //
2197 // If situation changes and this argument will be used, translate it in the
2198 // place where it is used.
2199 const int evn_ret = encode_vim_to_nothing(NULL, tv, "tv_clear() argument");
2200 (void)evn_ret;
2201 assert(evn_ret == OK);
2202 }
2203}
2204
2205//{{{3 Free
2206
2207/// Free allocated VimL object and value stored inside
2208///
2209/// @param tv Object to free.
2210void tv_free(typval_T *tv)
2211{
2212 if (tv != NULL) {
2213 switch (tv->v_type) {
2214 case VAR_PARTIAL: {
2215 partial_unref(tv->vval.v_partial);
2216 break;
2217 }
2218 case VAR_FUNC: {
2219 func_unref(tv->vval.v_string);
2220 FALLTHROUGH;
2221 }
2222 case VAR_STRING: {
2223 xfree(tv->vval.v_string);
2224 break;
2225 }
2226 case VAR_LIST: {
2227 tv_list_unref(tv->vval.v_list);
2228 break;
2229 }
2230 case VAR_DICT: {
2231 tv_dict_unref(tv->vval.v_dict);
2232 break;
2233 }
2234 case VAR_SPECIAL:
2235 case VAR_NUMBER:
2236 case VAR_FLOAT:
2237 case VAR_UNKNOWN: {
2238 break;
2239 }
2240 }
2241 xfree(tv);
2242 }
2243}
2244
2245//{{{3 Copy
2246
2247/// Copy typval from one location to another
2248///
2249/// When needed allocates string or increases reference count. Does not make
2250/// a copy of a container, but copies its reference!
2251///
2252/// It is OK for `from` and `to` to point to the same location; this is used to
2253/// make a copy later.
2254///
2255/// @param[in] from Location to copy from.
2256/// @param[out] to Location to copy to.
2257void tv_copy(const typval_T *const from, typval_T *const to)
2258{
2259 to->v_type = from->v_type;
2260 to->v_lock = VAR_UNLOCKED;
2261 memmove(&to->vval, &from->vval, sizeof(to->vval));
2262 switch (from->v_type) {
2263 case VAR_NUMBER:
2264 case VAR_FLOAT:
2265 case VAR_SPECIAL: {
2266 break;
2267 }
2268 case VAR_STRING:
2269 case VAR_FUNC: {
2270 if (from->vval.v_string != NULL) {
2271 to->vval.v_string = vim_strsave(from->vval.v_string);
2272 if (from->v_type == VAR_FUNC) {
2273 func_ref(to->vval.v_string);
2274 }
2275 }
2276 break;
2277 }
2278 case VAR_PARTIAL: {
2279 if (to->vval.v_partial != NULL) {
2280 to->vval.v_partial->pt_refcount++;
2281 }
2282 break;
2283 }
2284 case VAR_LIST: {
2285 tv_list_ref(to->vval.v_list);
2286 break;
2287 }
2288 case VAR_DICT: {
2289 if (from->vval.v_dict != NULL) {
2290 to->vval.v_dict->dv_refcount++;
2291 }
2292 break;
2293 }
2294 case VAR_UNKNOWN: {
2295 emsgf(_(e_intern2), "tv_copy(UNKNOWN)");
2296 break;
2297 }
2298 }
2299}
2300
2301//{{{2 Locks
2302
2303/// Lock or unlock an item
2304///
2305/// @param[out] tv Item to (un)lock.
2306/// @param[in] deep Levels to (un)lock, -1 to (un)lock everything.
2307/// @param[in] lock True if it is needed to lock an item, false to unlock.
2308void tv_item_lock(typval_T *const tv, const int deep, const bool lock)
2309 FUNC_ATTR_NONNULL_ALL
2310{
2311 // TODO(ZyX-I): Make this not recursive
2312 static int recurse = 0;
2313
2314 if (recurse >= DICT_MAXNEST) {
2315 EMSG(_("E743: variable nested too deep for (un)lock"));
2316 return;
2317 }
2318 if (deep == 0) {
2319 return;
2320 }
2321 recurse++;
2322
2323 // lock/unlock the item itself
2324#define CHANGE_LOCK(lock, var) \
2325 do { \
2326 var = ((VarLockStatus[]) { \
2327 [VAR_UNLOCKED] = (lock ? VAR_LOCKED : VAR_UNLOCKED), \
2328 [VAR_LOCKED] = (lock ? VAR_LOCKED : VAR_UNLOCKED), \
2329 [VAR_FIXED] = VAR_FIXED, \
2330 })[var]; \
2331 } while (0)
2332 CHANGE_LOCK(lock, tv->v_lock);
2333
2334 switch (tv->v_type) {
2335 case VAR_LIST: {
2336 list_T *const l = tv->vval.v_list;
2337 if (l != NULL) {
2338 CHANGE_LOCK(lock, l->lv_lock);
2339 if (deep < 0 || deep > 1) {
2340 // Recursive: lock/unlock the items the List contains.
2341 TV_LIST_ITER(l, li, {
2342 tv_item_lock(TV_LIST_ITEM_TV(li), deep - 1, lock);
2343 });
2344 }
2345 }
2346 break;
2347 }
2348 case VAR_DICT: {
2349 dict_T *const d = tv->vval.v_dict;
2350 if (d != NULL) {
2351 CHANGE_LOCK(lock, d->dv_lock);
2352 if (deep < 0 || deep > 1) {
2353 // recursive: lock/unlock the items the List contains
2354 TV_DICT_ITER(d, di, {
2355 tv_item_lock(&di->di_tv, deep - 1, lock);
2356 });
2357 }
2358 }
2359 break;
2360 }
2361 case VAR_NUMBER:
2362 case VAR_FLOAT:
2363 case VAR_STRING:
2364 case VAR_FUNC:
2365 case VAR_PARTIAL:
2366 case VAR_SPECIAL: {
2367 break;
2368 }
2369 case VAR_UNKNOWN: {
2370 assert(false);
2371 }
2372 }
2373#undef CHANGE_LOCK
2374 recurse--;
2375}
2376
2377/// Check whether VimL value is locked itself or refers to a locked container
2378///
2379/// @warning Fixed container is not the same as locked.
2380///
2381/// @param[in] tv Value to check.
2382///
2383/// @return True if value is locked, false otherwise.
2384bool tv_islocked(const typval_T *const tv)
2385 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
2386{
2387 return ((tv->v_lock == VAR_LOCKED)
2388 || (tv->v_type == VAR_LIST
2389 && (tv_list_locked(tv->vval.v_list) == VAR_LOCKED))
2390 || (tv->v_type == VAR_DICT
2391 && tv->vval.v_dict != NULL
2392 && (tv->vval.v_dict->dv_lock == VAR_LOCKED)));
2393}
2394
2395/// Return true if typval is locked
2396///
2397/// Also gives an error message when typval is locked.
2398///
2399/// @param[in] lock Lock status.
2400/// @param[in] name Variable name, used in the error message.
2401/// @param[in] name_len Variable name length. Use #TV_TRANSLATE to translate
2402/// variable name and compute the length. Use #TV_CSTRING
2403/// to compute the length with strlen() without
2404/// translating.
2405///
2406/// Both #TV_… values are used for optimization purposes:
2407/// variable name with its length is needed only in case
2408/// of error, when no error occurs computing them is
2409/// a waste of CPU resources. This especially applies to
2410/// gettext.
2411///
2412/// @return true if variable is locked, false otherwise.
2413bool tv_check_lock(const VarLockStatus lock, const char *name,
2414 size_t name_len)
2415 FUNC_ATTR_WARN_UNUSED_RESULT
2416{
2417 const char *error_message = NULL;
2418 switch (lock) {
2419 case VAR_UNLOCKED: {
2420 return false;
2421 }
2422 case VAR_LOCKED: {
2423 error_message = N_("E741: Value is locked: %.*s");
2424 break;
2425 }
2426 case VAR_FIXED: {
2427 error_message = N_("E742: Cannot change value of %.*s");
2428 break;
2429 }
2430 }
2431 assert(error_message != NULL);
2432
2433 if (name == NULL) {
2434 name = _("Unknown");
2435 name_len = strlen(name);
2436 } else if (name_len == TV_TRANSLATE) {
2437 name = _(name);
2438 name_len = strlen(name);
2439 } else if (name_len == TV_CSTRING) {
2440 name_len = strlen(name);
2441 }
2442
2443 emsgf(_(error_message), (int)name_len, name);
2444
2445 return true;
2446}
2447
2448//{{{2 Comparison
2449
2450static int tv_equal_recurse_limit;
2451
2452/// Compare two VimL values
2453///
2454/// Like "==", but strings and numbers are different, as well as floats and
2455/// numbers.
2456///
2457/// @warning Too nested structures may be considered equal even if they are not.
2458///
2459/// @param[in] tv1 First value to compare.
2460/// @param[in] tv2 Second value to compare.
2461/// @param[in] ic True if case is to be ignored.
2462/// @param[in] recursive True when used recursively.
2463///
2464/// @return true if values are equal.
2465bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic,
2466 const bool recursive)
2467 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
2468{
2469 // TODO(ZyX-I): Make this not recursive
2470 static int recursive_cnt = 0; // Catch recursive loops.
2471
2472 if (!(tv_is_func(*tv1) && tv_is_func(*tv2)) && tv1->v_type != tv2->v_type) {
2473 return false;
2474 }
2475
2476 // Catch lists and dicts that have an endless loop by limiting
2477 // recursiveness to a limit. We guess they are equal then.
2478 // A fixed limit has the problem of still taking an awful long time.
2479 // Reduce the limit every time running into it. That should work fine for
2480 // deeply linked structures that are not recursively linked and catch
2481 // recursiveness quickly.
2482 if (!recursive) {
2483 tv_equal_recurse_limit = 1000;
2484 }
2485 if (recursive_cnt >= tv_equal_recurse_limit) {
2486 tv_equal_recurse_limit--;
2487 return true;
2488 }
2489
2490 switch (tv1->v_type) {
2491 case VAR_LIST: {
2492 recursive_cnt++;
2493 const bool r = tv_list_equal(tv1->vval.v_list, tv2->vval.v_list, ic,
2494 true);
2495 recursive_cnt--;
2496 return r;
2497 }
2498 case VAR_DICT: {
2499 recursive_cnt++;
2500 const bool r = tv_dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic,
2501 true);
2502 recursive_cnt--;
2503 return r;
2504 }
2505 case VAR_PARTIAL:
2506 case VAR_FUNC: {
2507 if ((tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial == NULL)
2508 || (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial == NULL)) {
2509 return false;
2510 }
2511 recursive_cnt++;
2512 const bool r = func_equal(tv1, tv2, ic);
2513 recursive_cnt--;
2514 return r;
2515 }
2516 case VAR_NUMBER: {
2517 return tv1->vval.v_number == tv2->vval.v_number;
2518 }
2519 case VAR_FLOAT: {
2520 return tv1->vval.v_float == tv2->vval.v_float;
2521 }
2522 case VAR_STRING: {
2523 char buf1[NUMBUFLEN];
2524 char buf2[NUMBUFLEN];
2525 const char *s1 = tv_get_string_buf(tv1, buf1);
2526 const char *s2 = tv_get_string_buf(tv2, buf2);
2527 return mb_strcmp_ic((bool)ic, s1, s2) == 0;
2528 }
2529 case VAR_SPECIAL: {
2530 return tv1->vval.v_special == tv2->vval.v_special;
2531 }
2532 case VAR_UNKNOWN: {
2533 // VAR_UNKNOWN can be the result of an invalid expression, let’s say it
2534 // does not equal anything, not even self.
2535 return false;
2536 }
2537 }
2538
2539 assert(false);
2540 return false;
2541}
2542
2543//{{{2 Type checks
2544
2545/// Check that given value is a number or string
2546///
2547/// Error messages are compatible with tv_get_number() previously used for the
2548/// same purpose in buf*() functions. Special values are not accepted (previous
2549/// behaviour: silently fail to find buffer).
2550///
2551/// @param[in] tv Value to check.
2552///
2553/// @return true if everything is OK, false otherwise.
2554bool tv_check_str_or_nr(const typval_T *const tv)
2555 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
2556{
2557 switch (tv->v_type) {
2558 case VAR_NUMBER:
2559 case VAR_STRING: {
2560 return true;
2561 }
2562 case VAR_FLOAT: {
2563 EMSG(_("E805: Expected a Number or a String, Float found"));
2564 return false;
2565 }
2566 case VAR_PARTIAL:
2567 case VAR_FUNC: {
2568 EMSG(_("E703: Expected a Number or a String, Funcref found"));
2569 return false;
2570 }
2571 case VAR_LIST: {
2572 EMSG(_("E745: Expected a Number or a String, List found"));
2573 return false;
2574 }
2575 case VAR_DICT: {
2576 EMSG(_("E728: Expected a Number or a String, Dictionary found"));
2577 return false;
2578 }
2579 case VAR_SPECIAL: {
2580 EMSG(_("E5300: Expected a Number or a String"));
2581 return false;
2582 }
2583 case VAR_UNKNOWN: {
2584 EMSG2(_(e_intern2), "tv_check_str_or_nr(UNKNOWN)");
2585 return false;
2586 }
2587 }
2588 assert(false);
2589 return false;
2590}
2591
2592#define FUNC_ERROR "E703: Using a Funcref as a Number"
2593
2594static const char *const num_errors[] = {
2595 [VAR_PARTIAL]=N_(FUNC_ERROR),
2596 [VAR_FUNC]=N_(FUNC_ERROR),
2597 [VAR_LIST]=N_("E745: Using a List as a Number"),
2598 [VAR_DICT]=N_("E728: Using a Dictionary as a Number"),
2599 [VAR_FLOAT]=N_("E805: Using a Float as a Number"),
2600 [VAR_UNKNOWN]=N_("E685: using an invalid value as a Number"),
2601};
2602
2603#undef FUNC_ERROR
2604
2605/// Check that given value is a number or can be converted to it
2606///
2607/// Error messages are compatible with tv_get_number_chk() previously used for
2608/// the same purpose.
2609///
2610/// @param[in] tv Value to check.
2611///
2612/// @return true if everything is OK, false otherwise.
2613bool tv_check_num(const typval_T *const tv)
2614 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
2615{
2616 switch (tv->v_type) {
2617 case VAR_NUMBER:
2618 case VAR_SPECIAL:
2619 case VAR_STRING: {
2620 return true;
2621 }
2622 case VAR_FUNC:
2623 case VAR_PARTIAL:
2624 case VAR_LIST:
2625 case VAR_DICT:
2626 case VAR_FLOAT:
2627 case VAR_UNKNOWN: {
2628 EMSG(_(num_errors[tv->v_type]));
2629 return false;
2630 }
2631 }
2632 assert(false);
2633 return false;
2634}
2635
2636#define FUNC_ERROR "E729: using Funcref as a String"
2637
2638static const char *const str_errors[] = {
2639 [VAR_PARTIAL]=N_(FUNC_ERROR),
2640 [VAR_FUNC]=N_(FUNC_ERROR),
2641 [VAR_LIST]=N_("E730: using List as a String"),
2642 [VAR_DICT]=N_("E731: using Dictionary as a String"),
2643 [VAR_FLOAT]=((const char *)e_float_as_string),
2644 [VAR_UNKNOWN]=N_("E908: using an invalid value as a String"),
2645};
2646
2647#undef FUNC_ERROR
2648
2649/// Check that given value is a VimL String or can be "cast" to it.
2650///
2651/// Error messages are compatible with tv_get_string_chk() previously used for
2652/// the same purpose.
2653///
2654/// @param[in] tv Value to check.
2655///
2656/// @return true if everything is OK, false otherwise.
2657bool tv_check_str(const typval_T *const tv)
2658 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
2659{
2660 switch (tv->v_type) {
2661 case VAR_NUMBER:
2662 case VAR_SPECIAL:
2663 case VAR_STRING: {
2664 return true;
2665 }
2666 case VAR_PARTIAL:
2667 case VAR_FUNC:
2668 case VAR_LIST:
2669 case VAR_DICT:
2670 case VAR_FLOAT:
2671 case VAR_UNKNOWN: {
2672 EMSG(_(str_errors[tv->v_type]));
2673 return false;
2674 }
2675 }
2676 assert(false);
2677 return false;
2678}
2679
2680//{{{2 Get
2681
2682/// Get the number value of a VimL object
2683///
2684/// @note Use tv_get_number_chk() if you need to determine whether there was an
2685/// error.
2686///
2687/// @param[in] tv Object to get value from.
2688///
2689/// @return Number value: vim_str2nr() output for VAR_STRING objects, value
2690/// for VAR_NUMBER objects, -1 for other types.
2691varnumber_T tv_get_number(const typval_T *const tv)
2692 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
2693{
2694 bool error = false;
2695 return tv_get_number_chk(tv, &error);
2696}
2697
2698/// Get the number value of a VimL object
2699///
2700/// @param[in] tv Object to get value from.
2701/// @param[out] ret_error If type error occurred then `true` will be written
2702/// to this location. Otherwise it is not touched.
2703///
2704/// @note Needs to be initialized to `false` to be
2705/// useful.
2706///
2707/// @return Number value: vim_str2nr() output for VAR_STRING objects, value
2708/// for VAR_NUMBER objects, -1 (ret_error == NULL) or 0 (otherwise) for
2709/// other types.
2710varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error)
2711 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
2712{
2713 switch (tv->v_type) {
2714 case VAR_FUNC:
2715 case VAR_PARTIAL:
2716 case VAR_LIST:
2717 case VAR_DICT:
2718 case VAR_FLOAT: {
2719 EMSG(_(num_errors[tv->v_type]));
2720 break;
2721 }
2722 case VAR_NUMBER: {
2723 return tv->vval.v_number;
2724 }
2725 case VAR_STRING: {
2726 varnumber_T n = 0;
2727 if (tv->vval.v_string != NULL) {
2728 vim_str2nr(tv->vval.v_string, NULL, NULL, STR2NR_ALL, &n, NULL, 0);
2729 }
2730 return n;
2731 }
2732 case VAR_SPECIAL: {
2733 switch (tv->vval.v_special) {
2734 case kSpecialVarTrue: {
2735 return 1;
2736 }
2737 case kSpecialVarFalse:
2738 case kSpecialVarNull: {
2739 return 0;
2740 }
2741 }
2742 break;
2743 }
2744 case VAR_UNKNOWN: {
2745 emsgf(_(e_intern2), "tv_get_number(UNKNOWN)");
2746 break;
2747 }
2748 }
2749 if (ret_error != NULL) {
2750 *ret_error = true;
2751 }
2752 return (ret_error == NULL ? -1 : 0);
2753}
2754
2755/// Get the line number from VimL object
2756///
2757/// @param[in] tv Object to get value from. Is expected to be a number or
2758/// a special string like ".", "$", … (works with current buffer
2759/// only).
2760///
2761/// @return Line number or -1 or 0.
2762linenr_T tv_get_lnum(const typval_T *const tv)
2763 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
2764{
2765 linenr_T lnum = (linenr_T)tv_get_number_chk(tv, NULL);
2766 if (lnum == 0) { // No valid number, try using same function as line() does.
2767 int fnum;
2768 pos_T *const fp = var2fpos(tv, true, &fnum);
2769 if (fp != NULL) {
2770 lnum = fp->lnum;
2771 }
2772 }
2773 return lnum;
2774}
2775
2776/// Get the floating-point value of a VimL object
2777///
2778/// Raises an error if object is not number or floating-point.
2779///
2780/// @param[in] tv Object to get value of.
2781///
2782/// @return Floating-point value of the variable or zero.
2783float_T tv_get_float(const typval_T *const tv)
2784 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
2785{
2786 switch (tv->v_type) {
2787 case VAR_NUMBER: {
2788 return (float_T)(tv->vval.v_number);
2789 }
2790 case VAR_FLOAT: {
2791 return tv->vval.v_float;
2792 }
2793 case VAR_PARTIAL:
2794 case VAR_FUNC: {
2795 EMSG(_("E891: Using a Funcref as a Float"));
2796 break;
2797 }
2798 case VAR_STRING: {
2799 EMSG(_("E892: Using a String as a Float"));
2800 break;
2801 }
2802 case VAR_LIST: {
2803 EMSG(_("E893: Using a List as a Float"));
2804 break;
2805 }
2806 case VAR_DICT: {
2807 EMSG(_("E894: Using a Dictionary as a Float"));
2808 break;
2809 }
2810 case VAR_SPECIAL: {
2811 EMSG(_("E907: Using a special value as a Float"));
2812 break;
2813 }
2814 case VAR_UNKNOWN: {
2815 emsgf(_(e_intern2), "tv_get_float(UNKNOWN)");
2816 break;
2817 }
2818 }
2819 return 0;
2820}
2821
2822/// Get the string value of a "stringish" VimL object.
2823///
2824/// @param[in] tv Object to get value of.
2825/// @param buf Buffer used to hold numbers and special variables converted to
2826/// string. When function encounters one of these stringified value
2827/// will be written to buf and buf will be returned.
2828///
2829/// Buffer must have NUMBUFLEN size.
2830///
2831/// @return Object value if it is VAR_STRING object, number converted to
2832/// a string for VAR_NUMBER, v: variable name for VAR_SPECIAL or NULL.
2833const char *tv_get_string_buf_chk(const typval_T *const tv, char *const buf)
2834 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
2835{
2836 switch (tv->v_type) {
2837 case VAR_NUMBER: {
2838 snprintf(buf, NUMBUFLEN, "%" PRIdVARNUMBER, tv->vval.v_number); // -V576
2839 return buf;
2840 }
2841 case VAR_STRING: {
2842 if (tv->vval.v_string != NULL) {
2843 return (const char *)tv->vval.v_string;
2844 }
2845 return "";
2846 }
2847 case VAR_SPECIAL: {
2848 STRCPY(buf, encode_special_var_names[tv->vval.v_special]);
2849 return buf;
2850 }
2851 case VAR_PARTIAL:
2852 case VAR_FUNC:
2853 case VAR_LIST:
2854 case VAR_DICT:
2855 case VAR_FLOAT:
2856 case VAR_UNKNOWN: {
2857 EMSG(_(str_errors[tv->v_type]));
2858 return false;
2859 }
2860 }
2861 return NULL;
2862}
2863
2864/// Get the string value of a "stringish" VimL object.
2865///
2866/// @warning For number and special values it uses a single, static buffer. It
2867/// may be used only once, next call to tv_get_string may reuse it. Use
2868/// tv_get_string_buf() if you need to use tv_get_string() output after
2869/// calling it again.
2870///
2871/// @param[in] tv Object to get value of.
2872///
2873/// @return Object value if it is VAR_STRING object, number converted to
2874/// a string for VAR_NUMBER, v: variable name for VAR_SPECIAL or NULL.
2875const char *tv_get_string_chk(const typval_T *const tv)
2876 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
2877{
2878 static char mybuf[NUMBUFLEN];
2879
2880 return tv_get_string_buf_chk(tv, mybuf);
2881}
2882
2883/// Get the string value of a "stringish" VimL object.
2884///
2885/// @warning For number and special values it uses a single, static buffer. It
2886/// may be used only once, next call to tv_get_string may reuse it. Use
2887/// tv_get_string_buf() if you need to use tv_get_string() output after
2888/// calling it again.
2889///
2890/// @note tv_get_string_chk() and tv_get_string_buf_chk() are similar, but
2891/// return NULL on error.
2892///
2893/// @param[in] tv Object to get value of.
2894///
2895/// @return Object value if it is VAR_STRING object, number converted to
2896/// a string for VAR_NUMBER, v: variable name for VAR_SPECIAL or empty
2897/// string.
2898const char *tv_get_string(const typval_T *const tv)
2899 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
2900{
2901 static char mybuf[NUMBUFLEN];
2902 return tv_get_string_buf((typval_T *)tv, mybuf);
2903}
2904
2905/// Get the string value of a "stringish" VimL object.
2906///
2907/// @note tv_get_string_chk() and tv_get_string_buf_chk() are similar, but
2908/// return NULL on error.
2909///
2910/// @param[in] tv Object to get value of.
2911/// @param buf Buffer used to hold numbers and special variables converted to
2912/// string. When function encounters one of these stringified value
2913/// will be written to buf and buf will be returned.
2914///
2915/// Buffer must have NUMBUFLEN size.
2916///
2917/// @return Object value if it is VAR_STRING object, number converted to
2918/// a string for VAR_NUMBER, v: variable name for VAR_SPECIAL or empty
2919/// string.
2920const char *tv_get_string_buf(const typval_T *const tv, char *const buf)
2921 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
2922{
2923 const char *const res = (const char *)tv_get_string_buf_chk(tv, buf);
2924
2925 return res != NULL ? res : "";
2926}
2927