blob: c2bf4909cc72ef1f9f3157dbc3f9f505d00e2194 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaarda861d62016-07-17 15:46:27 +02002 *
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 * list.c: List support
12 */
13
14#include "vim.h"
15
16#if defined(FEAT_EVAL) || defined(PROTO)
17
18/* List heads for garbage collection. */
19static list_T *first_list = NULL; /* list of all lists */
20
21/*
22 * Add a watcher to a list.
23 */
24 void
25list_add_watch(list_T *l, listwatch_T *lw)
26{
27 lw->lw_next = l->lv_watch;
28 l->lv_watch = lw;
29}
30
31/*
32 * Remove a watcher from a list.
33 * No warning when it isn't found...
34 */
35 void
36list_rem_watch(list_T *l, listwatch_T *lwrem)
37{
38 listwatch_T *lw, **lwp;
39
40 lwp = &l->lv_watch;
41 for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next)
42 {
43 if (lw == lwrem)
44 {
45 *lwp = lw->lw_next;
46 break;
47 }
48 lwp = &lw->lw_next;
49 }
50}
51
52/*
53 * Just before removing an item from a list: advance watchers to the next
54 * item.
55 */
56 void
57list_fix_watch(list_T *l, listitem_T *item)
58{
59 listwatch_T *lw;
60
61 for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next)
62 if (lw->lw_item == item)
63 lw->lw_item = item->li_next;
64}
65
66/*
67 * Allocate an empty header for a list.
68 * Caller should take care of the reference count.
69 */
70 list_T *
71list_alloc(void)
72{
73 list_T *l;
74
Bram Moolenaarc799fe22019-05-28 23:08:19 +020075 l = ALLOC_CLEAR_ONE(list_T);
Bram Moolenaarda861d62016-07-17 15:46:27 +020076 if (l != NULL)
77 {
78 /* Prepend the list to the list of lists for garbage collection. */
79 if (first_list != NULL)
80 first_list->lv_used_prev = l;
81 l->lv_used_prev = NULL;
82 l->lv_used_next = first_list;
83 first_list = l;
84 }
85 return l;
86}
87
88/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010089 * list_alloc() with an ID for alloc_fail().
90 */
91 list_T *
92list_alloc_id(alloc_id_T id UNUSED)
93{
94#ifdef FEAT_EVAL
Bram Moolenaar51e14382019-05-25 20:21:28 +020095 if (alloc_fail_id == id && alloc_does_fail(sizeof(list_T)))
Bram Moolenaarf49cc602018-11-11 15:21:05 +010096 return NULL;
97#endif
98 return (list_alloc());
99}
100
101/*
Bram Moolenaarda861d62016-07-17 15:46:27 +0200102 * Allocate an empty list for a return value, with reference count set.
103 * Returns OK or FAIL.
104 */
105 int
106rettv_list_alloc(typval_T *rettv)
107{
108 list_T *l = list_alloc();
109
110 if (l == NULL)
111 return FAIL;
112
Bram Moolenaarda861d62016-07-17 15:46:27 +0200113 rettv->v_lock = 0;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +0200114 rettv_list_set(rettv, l);
Bram Moolenaarda861d62016-07-17 15:46:27 +0200115 return OK;
116}
117
118/*
Bram Moolenaar162b7142018-12-21 15:17:36 +0100119 * Same as rettv_list_alloc() but uses an allocation id for testing.
120 */
121 int
122rettv_list_alloc_id(typval_T *rettv, alloc_id_T id UNUSED)
123{
124#ifdef FEAT_EVAL
Bram Moolenaar51e14382019-05-25 20:21:28 +0200125 if (alloc_fail_id == id && alloc_does_fail(sizeof(list_T)))
Bram Moolenaar162b7142018-12-21 15:17:36 +0100126 return FAIL;
127#endif
128 return rettv_list_alloc(rettv);
129}
130
131
132/*
Bram Moolenaare809a4e2019-07-04 17:35:05 +0200133 * Set a list as the return value. Increments the reference count.
Bram Moolenaar45cf6e92017-04-30 20:25:19 +0200134 */
135 void
136rettv_list_set(typval_T *rettv, list_T *l)
137{
138 rettv->v_type = VAR_LIST;
139 rettv->vval.v_list = l;
140 if (l != NULL)
141 ++l->lv_refcount;
142}
143
144/*
Bram Moolenaarda861d62016-07-17 15:46:27 +0200145 * Unreference a list: decrement the reference count and free it when it
146 * becomes zero.
147 */
148 void
149list_unref(list_T *l)
150{
151 if (l != NULL && --l->lv_refcount <= 0)
152 list_free(l);
153}
154
155/*
156 * Free a list, including all non-container items it points to.
157 * Ignores the reference count.
158 */
159 static void
160list_free_contents(list_T *l)
161{
162 listitem_T *item;
163
164 for (item = l->lv_first; item != NULL; item = l->lv_first)
165 {
166 /* Remove the item before deleting it. */
167 l->lv_first = item->li_next;
168 clear_tv(&item->li_tv);
169 vim_free(item);
170 }
171}
172
173/*
174 * Go through the list of lists and free items without the copyID.
175 * But don't free a list that has a watcher (used in a for loop), these
176 * are not referenced anywhere.
177 */
178 int
179list_free_nonref(int copyID)
180{
181 list_T *ll;
182 int did_free = FALSE;
183
184 for (ll = first_list; ll != NULL; ll = ll->lv_used_next)
185 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)
186 && ll->lv_watch == NULL)
187 {
188 /* Free the List and ordinary items it contains, but don't recurse
189 * into Lists and Dictionaries, they will be in the list of dicts
190 * or list of lists. */
191 list_free_contents(ll);
192 did_free = TRUE;
193 }
194 return did_free;
195}
196
197 static void
198list_free_list(list_T *l)
199{
200 /* Remove the list from the list of lists for garbage collection. */
201 if (l->lv_used_prev == NULL)
202 first_list = l->lv_used_next;
203 else
204 l->lv_used_prev->lv_used_next = l->lv_used_next;
205 if (l->lv_used_next != NULL)
206 l->lv_used_next->lv_used_prev = l->lv_used_prev;
207
208 vim_free(l);
209}
210
211 void
212list_free_items(int copyID)
213{
214 list_T *ll, *ll_next;
215
216 for (ll = first_list; ll != NULL; ll = ll_next)
217 {
218 ll_next = ll->lv_used_next;
219 if ((ll->lv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)
220 && ll->lv_watch == NULL)
221 {
222 /* Free the List and ordinary items it contains, but don't recurse
223 * into Lists and Dictionaries, they will be in the list of dicts
224 * or list of lists. */
225 list_free_list(ll);
226 }
227 }
228}
229
230 void
231list_free(list_T *l)
232{
233 if (!in_free_unref_items)
234 {
235 list_free_contents(l);
236 list_free_list(l);
237 }
238}
239
240/*
241 * Allocate a list item.
242 * It is not initialized, don't forget to set v_lock.
243 */
244 listitem_T *
245listitem_alloc(void)
246{
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200247 return ALLOC_ONE(listitem_T);
Bram Moolenaarda861d62016-07-17 15:46:27 +0200248}
249
250/*
251 * Free a list item. Also clears the value. Does not notify watchers.
252 */
253 void
254listitem_free(listitem_T *item)
255{
256 clear_tv(&item->li_tv);
257 vim_free(item);
258}
259
260/*
261 * Remove a list item from a List and free it. Also clears the value.
262 */
263 void
264listitem_remove(list_T *l, listitem_T *item)
265{
266 vimlist_remove(l, item, item);
267 listitem_free(item);
268}
269
270/*
271 * Get the number of items in a list.
272 */
273 long
274list_len(list_T *l)
275{
276 if (l == NULL)
277 return 0L;
278 return l->lv_len;
279}
280
281/*
282 * Return TRUE when two lists have exactly the same values.
283 */
284 int
285list_equal(
286 list_T *l1,
287 list_T *l2,
288 int ic, /* ignore case for strings */
289 int recursive) /* TRUE when used recursively */
290{
291 listitem_T *item1, *item2;
292
293 if (l1 == NULL || l2 == NULL)
294 return FALSE;
295 if (l1 == l2)
296 return TRUE;
297 if (list_len(l1) != list_len(l2))
298 return FALSE;
299
300 for (item1 = l1->lv_first, item2 = l2->lv_first;
301 item1 != NULL && item2 != NULL;
302 item1 = item1->li_next, item2 = item2->li_next)
303 if (!tv_equal(&item1->li_tv, &item2->li_tv, ic, recursive))
304 return FALSE;
305 return item1 == NULL && item2 == NULL;
306}
307
308/*
309 * Locate item with index "n" in list "l" and return it.
310 * A negative index is counted from the end; -1 is the last item.
311 * Returns NULL when "n" is out of range.
312 */
313 listitem_T *
314list_find(list_T *l, long n)
315{
316 listitem_T *item;
317 long idx;
318
319 if (l == NULL)
320 return NULL;
321
322 /* Negative index is relative to the end. */
323 if (n < 0)
324 n = l->lv_len + n;
325
326 /* Check for index out of range. */
327 if (n < 0 || n >= l->lv_len)
328 return NULL;
329
330 /* When there is a cached index may start search from there. */
331 if (l->lv_idx_item != NULL)
332 {
333 if (n < l->lv_idx / 2)
334 {
335 /* closest to the start of the list */
336 item = l->lv_first;
337 idx = 0;
338 }
339 else if (n > (l->lv_idx + l->lv_len) / 2)
340 {
341 /* closest to the end of the list */
342 item = l->lv_last;
343 idx = l->lv_len - 1;
344 }
345 else
346 {
347 /* closest to the cached index */
348 item = l->lv_idx_item;
349 idx = l->lv_idx;
350 }
351 }
352 else
353 {
354 if (n < l->lv_len / 2)
355 {
356 /* closest to the start of the list */
357 item = l->lv_first;
358 idx = 0;
359 }
360 else
361 {
362 /* closest to the end of the list */
363 item = l->lv_last;
364 idx = l->lv_len - 1;
365 }
366 }
367
368 while (n > idx)
369 {
370 /* search forward */
371 item = item->li_next;
372 ++idx;
373 }
374 while (n < idx)
375 {
376 /* search backward */
377 item = item->li_prev;
378 --idx;
379 }
380
381 /* cache the used index */
382 l->lv_idx = idx;
383 l->lv_idx_item = item;
384
385 return item;
386}
387
388/*
389 * Get list item "l[idx]" as a number.
390 */
391 long
392list_find_nr(
393 list_T *l,
394 long idx,
395 int *errorp) /* set to TRUE when something wrong */
396{
397 listitem_T *li;
398
399 li = list_find(l, idx);
400 if (li == NULL)
401 {
402 if (errorp != NULL)
403 *errorp = TRUE;
404 return -1L;
405 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +0100406 return (long)tv_get_number_chk(&li->li_tv, errorp);
Bram Moolenaarda861d62016-07-17 15:46:27 +0200407}
408
409/*
410 * Get list item "l[idx - 1]" as a string. Returns NULL for failure.
411 */
412 char_u *
413list_find_str(list_T *l, long idx)
414{
415 listitem_T *li;
416
417 li = list_find(l, idx - 1);
418 if (li == NULL)
419 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100420 semsg(_(e_listidx), idx);
Bram Moolenaarda861d62016-07-17 15:46:27 +0200421 return NULL;
422 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +0100423 return tv_get_string(&li->li_tv);
Bram Moolenaarda861d62016-07-17 15:46:27 +0200424}
425
426/*
427 * Locate "item" list "l" and return its index.
428 * Returns -1 when "item" is not in the list.
429 */
430 long
431list_idx_of_item(list_T *l, listitem_T *item)
432{
433 long idx = 0;
434 listitem_T *li;
435
436 if (l == NULL)
437 return -1;
438 idx = 0;
439 for (li = l->lv_first; li != NULL && li != item; li = li->li_next)
440 ++idx;
441 if (li == NULL)
442 return -1;
443 return idx;
444}
445
446/*
447 * Append item "item" to the end of list "l".
448 */
449 void
450list_append(list_T *l, listitem_T *item)
451{
452 if (l->lv_last == NULL)
453 {
454 /* empty list */
455 l->lv_first = item;
456 l->lv_last = item;
457 item->li_prev = NULL;
458 }
459 else
460 {
461 l->lv_last->li_next = item;
462 item->li_prev = l->lv_last;
463 l->lv_last = item;
464 }
465 ++l->lv_len;
466 item->li_next = NULL;
467}
468
469/*
470 * Append typval_T "tv" to the end of list "l".
471 * Return FAIL when out of memory.
472 */
473 int
474list_append_tv(list_T *l, typval_T *tv)
475{
476 listitem_T *li = listitem_alloc();
477
478 if (li == NULL)
479 return FAIL;
480 copy_tv(tv, &li->li_tv);
481 list_append(l, li);
482 return OK;
483}
484
485/*
486 * Add a dictionary to a list. Used by getqflist().
487 * Return FAIL when out of memory.
488 */
489 int
490list_append_dict(list_T *list, dict_T *dict)
491{
492 listitem_T *li = listitem_alloc();
493
494 if (li == NULL)
495 return FAIL;
496 li->li_tv.v_type = VAR_DICT;
497 li->li_tv.v_lock = 0;
498 li->li_tv.vval.v_dict = dict;
499 list_append(list, li);
500 ++dict->dv_refcount;
501 return OK;
502}
503
504/*
Bram Moolenaar4f505882018-02-10 21:06:32 +0100505 * Append list2 to list1.
506 * Return FAIL when out of memory.
507 */
508 int
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +0200509list_append_list(list_T *list1, list_T *list2)
Bram Moolenaar4f505882018-02-10 21:06:32 +0100510{
511 listitem_T *li = listitem_alloc();
512
513 if (li == NULL)
514 return FAIL;
515 li->li_tv.v_type = VAR_LIST;
516 li->li_tv.v_lock = 0;
517 li->li_tv.vval.v_list = list2;
518 list_append(list1, li);
519 ++list2->lv_refcount;
520 return OK;
521}
522
523/*
Bram Moolenaarda861d62016-07-17 15:46:27 +0200524 * Make a copy of "str" and append it as an item to list "l".
525 * When "len" >= 0 use "str[len]".
526 * Returns FAIL when out of memory.
527 */
528 int
529list_append_string(list_T *l, char_u *str, int len)
530{
531 listitem_T *li = listitem_alloc();
532
533 if (li == NULL)
534 return FAIL;
535 list_append(l, li);
536 li->li_tv.v_type = VAR_STRING;
537 li->li_tv.v_lock = 0;
538 if (str == NULL)
539 li->li_tv.vval.v_string = NULL;
540 else if ((li->li_tv.vval.v_string = (len >= 0 ? vim_strnsave(str, len)
541 : vim_strsave(str))) == NULL)
542 return FAIL;
543 return OK;
544}
545
546/*
547 * Append "n" to list "l".
548 * Returns FAIL when out of memory.
549 */
550 int
551list_append_number(list_T *l, varnumber_T n)
552{
553 listitem_T *li;
554
555 li = listitem_alloc();
556 if (li == NULL)
557 return FAIL;
558 li->li_tv.v_type = VAR_NUMBER;
559 li->li_tv.v_lock = 0;
560 li->li_tv.vval.v_number = n;
561 list_append(l, li);
562 return OK;
563}
564
565/*
566 * Insert typval_T "tv" in list "l" before "item".
567 * If "item" is NULL append at the end.
568 * Return FAIL when out of memory.
569 */
570 int
571list_insert_tv(list_T *l, typval_T *tv, listitem_T *item)
572{
573 listitem_T *ni = listitem_alloc();
574
575 if (ni == NULL)
576 return FAIL;
577 copy_tv(tv, &ni->li_tv);
578 list_insert(l, ni, item);
579 return OK;
580}
581
582 void
583list_insert(list_T *l, listitem_T *ni, listitem_T *item)
584{
585 if (item == NULL)
586 /* Append new item at end of list. */
587 list_append(l, ni);
588 else
589 {
590 /* Insert new item before existing item. */
591 ni->li_prev = item->li_prev;
592 ni->li_next = item;
593 if (item->li_prev == NULL)
594 {
595 l->lv_first = ni;
596 ++l->lv_idx;
597 }
598 else
599 {
600 item->li_prev->li_next = ni;
601 l->lv_idx_item = NULL;
602 }
603 item->li_prev = ni;
604 ++l->lv_len;
605 }
606}
607
608/*
609 * Extend "l1" with "l2".
610 * If "bef" is NULL append at the end, otherwise insert before this item.
611 * Returns FAIL when out of memory.
612 */
613 int
614list_extend(list_T *l1, list_T *l2, listitem_T *bef)
615{
616 listitem_T *item;
617 int todo = l2->lv_len;
618
619 /* We also quit the loop when we have inserted the original item count of
620 * the list, avoid a hang when we extend a list with itself. */
621 for (item = l2->lv_first; item != NULL && --todo >= 0; item = item->li_next)
622 if (list_insert_tv(l1, &item->li_tv, bef) == FAIL)
623 return FAIL;
624 return OK;
625}
626
627/*
628 * Concatenate lists "l1" and "l2" into a new list, stored in "tv".
629 * Return FAIL when out of memory.
630 */
631 int
632list_concat(list_T *l1, list_T *l2, typval_T *tv)
633{
634 list_T *l;
635
636 if (l1 == NULL || l2 == NULL)
637 return FAIL;
638
639 /* make a copy of the first list. */
640 l = list_copy(l1, FALSE, 0);
641 if (l == NULL)
642 return FAIL;
643 tv->v_type = VAR_LIST;
644 tv->vval.v_list = l;
645
646 /* append all items from the second list */
647 return list_extend(l, l2, NULL);
648}
649
650/*
651 * Make a copy of list "orig". Shallow if "deep" is FALSE.
652 * The refcount of the new list is set to 1.
653 * See item_copy() for "copyID".
654 * Returns NULL when out of memory.
655 */
656 list_T *
657list_copy(list_T *orig, int deep, int copyID)
658{
659 list_T *copy;
660 listitem_T *item;
661 listitem_T *ni;
662
663 if (orig == NULL)
664 return NULL;
665
666 copy = list_alloc();
667 if (copy != NULL)
668 {
669 if (copyID != 0)
670 {
671 /* Do this before adding the items, because one of the items may
672 * refer back to this list. */
673 orig->lv_copyID = copyID;
674 orig->lv_copylist = copy;
675 }
676 for (item = orig->lv_first; item != NULL && !got_int;
677 item = item->li_next)
678 {
679 ni = listitem_alloc();
680 if (ni == NULL)
681 break;
682 if (deep)
683 {
684 if (item_copy(&item->li_tv, &ni->li_tv, deep, copyID) == FAIL)
685 {
686 vim_free(ni);
687 break;
688 }
689 }
690 else
691 copy_tv(&item->li_tv, &ni->li_tv);
692 list_append(copy, ni);
693 }
694 ++copy->lv_refcount;
695 if (item != NULL)
696 {
697 list_unref(copy);
698 copy = NULL;
699 }
700 }
701
702 return copy;
703}
704
705/*
706 * Remove items "item" to "item2" from list "l".
707 * Does not free the listitem or the value!
708 * This used to be called list_remove, but that conflicts with a Sun header
709 * file.
710 */
711 void
712vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2)
713{
714 listitem_T *ip;
715
716 /* notify watchers */
717 for (ip = item; ip != NULL; ip = ip->li_next)
718 {
719 --l->lv_len;
720 list_fix_watch(l, ip);
721 if (ip == item2)
722 break;
723 }
724
725 if (item2->li_next == NULL)
726 l->lv_last = item->li_prev;
727 else
728 item2->li_next->li_prev = item->li_prev;
729 if (item->li_prev == NULL)
730 l->lv_first = item2->li_next;
731 else
732 item->li_prev->li_next = item2->li_next;
733 l->lv_idx_item = NULL;
734}
735
736/*
737 * Return an allocated string with the string representation of a list.
738 * May return NULL.
739 */
740 char_u *
741list2string(typval_T *tv, int copyID, int restore_copyID)
742{
743 garray_T ga;
744
745 if (tv->vval.v_list == NULL)
746 return NULL;
747 ga_init2(&ga, (int)sizeof(char), 80);
748 ga_append(&ga, '[');
749 if (list_join(&ga, tv->vval.v_list, (char_u *)", ",
750 FALSE, restore_copyID, copyID) == FAIL)
751 {
752 vim_free(ga.ga_data);
753 return NULL;
754 }
755 ga_append(&ga, ']');
756 ga_append(&ga, NUL);
757 return (char_u *)ga.ga_data;
758}
759
760typedef struct join_S {
761 char_u *s;
762 char_u *tofree;
763} join_T;
764
765 static int
766list_join_inner(
767 garray_T *gap, /* to store the result in */
768 list_T *l,
769 char_u *sep,
770 int echo_style,
771 int restore_copyID,
772 int copyID,
773 garray_T *join_gap) /* to keep each list item string */
774{
775 int i;
776 join_T *p;
777 int len;
778 int sumlen = 0;
779 int first = TRUE;
780 char_u *tofree;
781 char_u numbuf[NUMBUFLEN];
782 listitem_T *item;
783 char_u *s;
784
785 /* Stringify each item in the list. */
786 for (item = l->lv_first; item != NULL && !got_int; item = item->li_next)
787 {
788 s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID,
Bram Moolenaar35422f42017-08-05 16:33:56 +0200789 echo_style, restore_copyID, !echo_style);
Bram Moolenaarda861d62016-07-17 15:46:27 +0200790 if (s == NULL)
791 return FAIL;
792
793 len = (int)STRLEN(s);
794 sumlen += len;
795
796 (void)ga_grow(join_gap, 1);
797 p = ((join_T *)join_gap->ga_data) + (join_gap->ga_len++);
798 if (tofree != NULL || s != numbuf)
799 {
800 p->s = s;
801 p->tofree = tofree;
802 }
803 else
804 {
805 p->s = vim_strnsave(s, len);
806 p->tofree = p->s;
807 }
808
809 line_breakcheck();
810 if (did_echo_string_emsg) /* recursion error, bail out */
811 break;
812 }
813
814 /* Allocate result buffer with its total size, avoid re-allocation and
815 * multiple copy operations. Add 2 for a tailing ']' and NUL. */
816 if (join_gap->ga_len >= 2)
817 sumlen += (int)STRLEN(sep) * (join_gap->ga_len - 1);
818 if (ga_grow(gap, sumlen + 2) == FAIL)
819 return FAIL;
820
821 for (i = 0; i < join_gap->ga_len && !got_int; ++i)
822 {
823 if (first)
824 first = FALSE;
825 else
826 ga_concat(gap, sep);
827 p = ((join_T *)join_gap->ga_data) + i;
828
829 if (p->s != NULL)
830 ga_concat(gap, p->s);
831 line_breakcheck();
832 }
833
834 return OK;
835}
836
837/*
838 * Join list "l" into a string in "*gap", using separator "sep".
839 * When "echo_style" is TRUE use String as echoed, otherwise as inside a List.
840 * Return FAIL or OK.
841 */
842 int
843list_join(
844 garray_T *gap,
845 list_T *l,
846 char_u *sep,
847 int echo_style,
848 int restore_copyID,
849 int copyID)
850{
851 garray_T join_ga;
852 int retval;
853 join_T *p;
854 int i;
855
856 if (l->lv_len < 1)
857 return OK; /* nothing to do */
858 ga_init2(&join_ga, (int)sizeof(join_T), l->lv_len);
859 retval = list_join_inner(gap, l, sep, echo_style, restore_copyID,
860 copyID, &join_ga);
861
862 /* Dispose each item in join_ga. */
863 if (join_ga.ga_data != NULL)
864 {
865 p = (join_T *)join_ga.ga_data;
866 for (i = 0; i < join_ga.ga_len; ++i)
867 {
868 vim_free(p->tofree);
869 ++p;
870 }
871 ga_clear(&join_ga);
872 }
873
874 return retval;
875}
876
877/*
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200878 * "join()" function
879 */
880 void
881f_join(typval_T *argvars, typval_T *rettv)
882{
883 garray_T ga;
884 char_u *sep;
885
886 if (argvars[0].v_type != VAR_LIST)
887 {
888 emsg(_(e_listreq));
889 return;
890 }
891 if (argvars[0].vval.v_list == NULL)
892 return;
893 if (argvars[1].v_type == VAR_UNKNOWN)
894 sep = (char_u *)" ";
895 else
896 sep = tv_get_string_chk(&argvars[1]);
897
898 rettv->v_type = VAR_STRING;
899
900 if (sep != NULL)
901 {
902 ga_init2(&ga, (int)sizeof(char), 80);
903 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
904 ga_append(&ga, NUL);
905 rettv->vval.v_string = (char_u *)ga.ga_data;
906 }
907 else
908 rettv->vval.v_string = NULL;
909}
910
911/*
Bram Moolenaarda861d62016-07-17 15:46:27 +0200912 * Allocate a variable for a List and fill it from "*arg".
913 * Return OK or FAIL.
914 */
915 int
916get_list_tv(char_u **arg, typval_T *rettv, int evaluate)
917{
918 list_T *l = NULL;
919 typval_T tv;
920 listitem_T *item;
921
922 if (evaluate)
923 {
924 l = list_alloc();
925 if (l == NULL)
926 return FAIL;
927 }
928
929 *arg = skipwhite(*arg + 1);
930 while (**arg != ']' && **arg != NUL)
931 {
932 if (eval1(arg, &tv, evaluate) == FAIL) /* recursive! */
933 goto failret;
934 if (evaluate)
935 {
936 item = listitem_alloc();
937 if (item != NULL)
938 {
939 item->li_tv = tv;
940 item->li_tv.v_lock = 0;
941 list_append(l, item);
942 }
943 else
944 clear_tv(&tv);
945 }
946
947 if (**arg == ']')
948 break;
949 if (**arg != ',')
950 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100951 semsg(_("E696: Missing comma in List: %s"), *arg);
Bram Moolenaarda861d62016-07-17 15:46:27 +0200952 goto failret;
953 }
954 *arg = skipwhite(*arg + 1);
955 }
956
957 if (**arg != ']')
958 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100959 semsg(_("E697: Missing end of List ']': %s"), *arg);
Bram Moolenaarda861d62016-07-17 15:46:27 +0200960failret:
961 if (evaluate)
962 list_free(l);
963 return FAIL;
964 }
965
966 *arg = skipwhite(*arg + 1);
967 if (evaluate)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +0200968 rettv_list_set(rettv, l);
Bram Moolenaarda861d62016-07-17 15:46:27 +0200969
970 return OK;
971}
972
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200973/*
Bram Moolenaarcaa55b62017-01-10 13:51:09 +0100974 * Write "list" of strings to file "fd".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200975 */
976 int
977write_list(FILE *fd, list_T *list, int binary)
978{
979 listitem_T *li;
980 int c;
981 int ret = OK;
982 char_u *s;
983
984 for (li = list->lv_first; li != NULL; li = li->li_next)
985 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +0100986 for (s = tv_get_string(&li->li_tv); *s != NUL; ++s)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200987 {
988 if (*s == '\n')
989 c = putc(NUL, fd);
990 else
991 c = putc(*s, fd);
992 if (c == EOF)
993 {
994 ret = FAIL;
995 break;
996 }
997 }
998 if (!binary || li->li_next != NULL)
999 if (putc('\n', fd) == EOF)
1000 {
1001 ret = FAIL;
1002 break;
1003 }
1004 if (ret == FAIL)
1005 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001006 emsg(_(e_write));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001007 break;
1008 }
1009 }
1010 return ret;
1011}
1012
Bram Moolenaardf48fb42016-07-22 21:50:18 +02001013/*
1014 * Initialize a static list with 10 items.
1015 */
1016 void
1017init_static_list(staticList10_T *sl)
1018{
1019 list_T *l = &sl->sl_list;
1020 int i;
1021
1022 memset(sl, 0, sizeof(staticList10_T));
1023 l->lv_first = &sl->sl_items[0];
1024 l->lv_last = &sl->sl_items[9];
1025 l->lv_refcount = DO_NOT_FREE_CNT;
1026 l->lv_lock = VAR_FIXED;
1027 sl->sl_list.lv_len = 10;
1028
1029 for (i = 0; i < 10; ++i)
1030 {
1031 listitem_T *li = &sl->sl_items[i];
1032
1033 if (i == 0)
1034 li->li_prev = NULL;
1035 else
1036 li->li_prev = li - 1;
1037 if (i == 9)
1038 li->li_next = NULL;
1039 else
1040 li->li_next = li + 1;
1041 }
1042}
1043
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02001044/*
1045 * "list2str()" function
1046 */
1047 void
1048f_list2str(typval_T *argvars, typval_T *rettv)
1049{
1050 list_T *l;
1051 listitem_T *li;
1052 garray_T ga;
1053 int utf8 = FALSE;
1054
1055 rettv->v_type = VAR_STRING;
1056 rettv->vval.v_string = NULL;
1057 if (argvars[0].v_type != VAR_LIST)
1058 {
1059 emsg(_(e_invarg));
1060 return;
1061 }
1062
1063 l = argvars[0].vval.v_list;
1064 if (l == NULL)
1065 return; // empty list results in empty string
1066
1067 if (argvars[1].v_type != VAR_UNKNOWN)
1068 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
1069
1070 ga_init2(&ga, 1, 80);
1071 if (has_mbyte || utf8)
1072 {
1073 char_u buf[MB_MAXBYTES + 1];
1074 int (*char2bytes)(int, char_u *);
1075
1076 if (utf8 || enc_utf8)
1077 char2bytes = utf_char2bytes;
1078 else
1079 char2bytes = mb_char2bytes;
1080
1081 for (li = l->lv_first; li != NULL; li = li->li_next)
1082 {
1083 buf[(*char2bytes)(tv_get_number(&li->li_tv), buf)] = NUL;
1084 ga_concat(&ga, buf);
1085 }
1086 ga_append(&ga, NUL);
1087 }
1088 else if (ga_grow(&ga, list_len(l) + 1) == OK)
1089 {
1090 for (li = l->lv_first; li != NULL; li = li->li_next)
1091 ga_append(&ga, tv_get_number(&li->li_tv));
1092 ga_append(&ga, NUL);
1093 }
1094
1095 rettv->v_type = VAR_STRING;
1096 rettv->vval.v_string = ga.ga_data;
1097}
1098
1099 void
1100list_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
1101{
1102 list_T *l;
1103 listitem_T *item, *item2;
1104 listitem_T *li;
1105 int error = FALSE;
1106 int idx;
1107
1108 if ((l = argvars[0].vval.v_list) == NULL
1109 || var_check_lock(l->lv_lock, arg_errmsg, TRUE))
1110 return;
1111
1112 idx = (long)tv_get_number_chk(&argvars[1], &error);
1113 if (error)
1114 ; // type error: do nothing, errmsg already given
1115 else if ((item = list_find(l, idx)) == NULL)
1116 semsg(_(e_listidx), idx);
1117 else
1118 {
1119 if (argvars[2].v_type == VAR_UNKNOWN)
1120 {
1121 /* Remove one item, return its value. */
1122 vimlist_remove(l, item, item);
1123 *rettv = item->li_tv;
1124 vim_free(item);
1125 }
1126 else
1127 {
1128 // Remove range of items, return list with values.
1129 int end = (long)tv_get_number_chk(&argvars[2], &error);
1130
1131 if (error)
1132 ; // type error: do nothing
1133 else if ((item2 = list_find(l, end)) == NULL)
1134 semsg(_(e_listidx), end);
1135 else
1136 {
1137 int cnt = 0;
1138
1139 for (li = item; li != NULL; li = li->li_next)
1140 {
1141 ++cnt;
1142 if (li == item2)
1143 break;
1144 }
1145 if (li == NULL) /* didn't find "item2" after "item" */
1146 emsg(_(e_invrange));
1147 else
1148 {
1149 vimlist_remove(l, item, item2);
1150 if (rettv_list_alloc(rettv) == OK)
1151 {
1152 l = rettv->vval.v_list;
1153 l->lv_first = item;
1154 l->lv_last = item2;
1155 item->li_prev = NULL;
1156 item2->li_next = NULL;
1157 l->lv_len = cnt;
1158 }
1159 }
1160 }
1161 }
1162 }
1163}
1164
1165static int item_compare(const void *s1, const void *s2);
1166static int item_compare2(const void *s1, const void *s2);
1167
1168/* struct used in the array that's given to qsort() */
1169typedef struct
1170{
1171 listitem_T *item;
1172 int idx;
1173} sortItem_T;
1174
1175/* struct storing information about current sort */
1176typedef struct
1177{
1178 int item_compare_ic;
1179 int item_compare_numeric;
1180 int item_compare_numbers;
1181#ifdef FEAT_FLOAT
1182 int item_compare_float;
1183#endif
1184 char_u *item_compare_func;
1185 partial_T *item_compare_partial;
1186 dict_T *item_compare_selfdict;
1187 int item_compare_func_err;
1188 int item_compare_keep_zero;
1189} sortinfo_T;
1190static sortinfo_T *sortinfo = NULL;
1191#define ITEM_COMPARE_FAIL 999
1192
1193/*
1194 * Compare functions for f_sort() and f_uniq() below.
1195 */
1196 static int
1197item_compare(const void *s1, const void *s2)
1198{
1199 sortItem_T *si1, *si2;
1200 typval_T *tv1, *tv2;
1201 char_u *p1, *p2;
1202 char_u *tofree1 = NULL, *tofree2 = NULL;
1203 int res;
1204 char_u numbuf1[NUMBUFLEN];
1205 char_u numbuf2[NUMBUFLEN];
1206
1207 si1 = (sortItem_T *)s1;
1208 si2 = (sortItem_T *)s2;
1209 tv1 = &si1->item->li_tv;
1210 tv2 = &si2->item->li_tv;
1211
1212 if (sortinfo->item_compare_numbers)
1213 {
1214 varnumber_T v1 = tv_get_number(tv1);
1215 varnumber_T v2 = tv_get_number(tv2);
1216
1217 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
1218 }
1219
1220#ifdef FEAT_FLOAT
1221 if (sortinfo->item_compare_float)
1222 {
1223 float_T v1 = tv_get_float(tv1);
1224 float_T v2 = tv_get_float(tv2);
1225
1226 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
1227 }
1228#endif
1229
1230 /* tv2string() puts quotes around a string and allocates memory. Don't do
1231 * that for string variables. Use a single quote when comparing with a
1232 * non-string to do what the docs promise. */
1233 if (tv1->v_type == VAR_STRING)
1234 {
1235 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
1236 p1 = (char_u *)"'";
1237 else
1238 p1 = tv1->vval.v_string;
1239 }
1240 else
1241 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
1242 if (tv2->v_type == VAR_STRING)
1243 {
1244 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
1245 p2 = (char_u *)"'";
1246 else
1247 p2 = tv2->vval.v_string;
1248 }
1249 else
1250 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
1251 if (p1 == NULL)
1252 p1 = (char_u *)"";
1253 if (p2 == NULL)
1254 p2 = (char_u *)"";
1255 if (!sortinfo->item_compare_numeric)
1256 {
1257 if (sortinfo->item_compare_ic)
1258 res = STRICMP(p1, p2);
1259 else
1260 res = STRCMP(p1, p2);
1261 }
1262 else
1263 {
1264 double n1, n2;
1265 n1 = strtod((char *)p1, (char **)&p1);
1266 n2 = strtod((char *)p2, (char **)&p2);
1267 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
1268 }
1269
1270 /* When the result would be zero, compare the item indexes. Makes the
1271 * sort stable. */
1272 if (res == 0 && !sortinfo->item_compare_keep_zero)
1273 res = si1->idx > si2->idx ? 1 : -1;
1274
1275 vim_free(tofree1);
1276 vim_free(tofree2);
1277 return res;
1278}
1279
1280 static int
1281item_compare2(const void *s1, const void *s2)
1282{
1283 sortItem_T *si1, *si2;
1284 int res;
1285 typval_T rettv;
1286 typval_T argv[3];
1287 int dummy;
1288 char_u *func_name;
1289 partial_T *partial = sortinfo->item_compare_partial;
1290
1291 /* shortcut after failure in previous call; compare all items equal */
1292 if (sortinfo->item_compare_func_err)
1293 return 0;
1294
1295 si1 = (sortItem_T *)s1;
1296 si2 = (sortItem_T *)s2;
1297
1298 if (partial == NULL)
1299 func_name = sortinfo->item_compare_func;
1300 else
1301 func_name = partial_name(partial);
1302
1303 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
1304 * in the copy without changing the original list items. */
1305 copy_tv(&si1->item->li_tv, &argv[0]);
1306 copy_tv(&si2->item->li_tv, &argv[1]);
1307
1308 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
1309 res = call_func(func_name, -1, &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
1310 partial, sortinfo->item_compare_selfdict);
1311 clear_tv(&argv[0]);
1312 clear_tv(&argv[1]);
1313
1314 if (res == FAIL)
1315 res = ITEM_COMPARE_FAIL;
1316 else
1317 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
1318 if (sortinfo->item_compare_func_err)
1319 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
1320 clear_tv(&rettv);
1321
1322 /* When the result would be zero, compare the pointers themselves. Makes
1323 * the sort stable. */
1324 if (res == 0 && !sortinfo->item_compare_keep_zero)
1325 res = si1->idx > si2->idx ? 1 : -1;
1326
1327 return res;
1328}
1329
1330/*
1331 * "sort()" or "uniq()" function
1332 */
1333 static void
1334do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
1335{
1336 list_T *l;
1337 listitem_T *li;
1338 sortItem_T *ptrs;
1339 sortinfo_T *old_sortinfo;
1340 sortinfo_T info;
1341 long len;
1342 long i;
1343
1344 /* Pointer to current info struct used in compare function. Save and
1345 * restore the current one for nested calls. */
1346 old_sortinfo = sortinfo;
1347 sortinfo = &info;
1348
1349 if (argvars[0].v_type != VAR_LIST)
1350 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
1351 else
1352 {
1353 l = argvars[0].vval.v_list;
1354 if (l == NULL || var_check_lock(l->lv_lock,
1355 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
1356 TRUE))
1357 goto theend;
1358 rettv_list_set(rettv, l);
1359
1360 len = list_len(l);
1361 if (len <= 1)
1362 goto theend; /* short list sorts pretty quickly */
1363
1364 info.item_compare_ic = FALSE;
1365 info.item_compare_numeric = FALSE;
1366 info.item_compare_numbers = FALSE;
1367#ifdef FEAT_FLOAT
1368 info.item_compare_float = FALSE;
1369#endif
1370 info.item_compare_func = NULL;
1371 info.item_compare_partial = NULL;
1372 info.item_compare_selfdict = NULL;
1373 if (argvars[1].v_type != VAR_UNKNOWN)
1374 {
1375 /* optional second argument: {func} */
1376 if (argvars[1].v_type == VAR_FUNC)
1377 info.item_compare_func = argvars[1].vval.v_string;
1378 else if (argvars[1].v_type == VAR_PARTIAL)
1379 info.item_compare_partial = argvars[1].vval.v_partial;
1380 else
1381 {
1382 int error = FALSE;
1383
1384 i = (long)tv_get_number_chk(&argvars[1], &error);
1385 if (error)
1386 goto theend; /* type error; errmsg already given */
1387 if (i == 1)
1388 info.item_compare_ic = TRUE;
1389 else if (argvars[1].v_type != VAR_NUMBER)
1390 info.item_compare_func = tv_get_string(&argvars[1]);
1391 else if (i != 0)
1392 {
1393 emsg(_(e_invarg));
1394 goto theend;
1395 }
1396 if (info.item_compare_func != NULL)
1397 {
1398 if (*info.item_compare_func == NUL)
1399 {
1400 /* empty string means default sort */
1401 info.item_compare_func = NULL;
1402 }
1403 else if (STRCMP(info.item_compare_func, "n") == 0)
1404 {
1405 info.item_compare_func = NULL;
1406 info.item_compare_numeric = TRUE;
1407 }
1408 else if (STRCMP(info.item_compare_func, "N") == 0)
1409 {
1410 info.item_compare_func = NULL;
1411 info.item_compare_numbers = TRUE;
1412 }
1413#ifdef FEAT_FLOAT
1414 else if (STRCMP(info.item_compare_func, "f") == 0)
1415 {
1416 info.item_compare_func = NULL;
1417 info.item_compare_float = TRUE;
1418 }
1419#endif
1420 else if (STRCMP(info.item_compare_func, "i") == 0)
1421 {
1422 info.item_compare_func = NULL;
1423 info.item_compare_ic = TRUE;
1424 }
1425 }
1426 }
1427
1428 if (argvars[2].v_type != VAR_UNKNOWN)
1429 {
1430 /* optional third argument: {dict} */
1431 if (argvars[2].v_type != VAR_DICT)
1432 {
1433 emsg(_(e_dictreq));
1434 goto theend;
1435 }
1436 info.item_compare_selfdict = argvars[2].vval.v_dict;
1437 }
1438 }
1439
1440 /* Make an array with each entry pointing to an item in the List. */
1441 ptrs = ALLOC_MULT(sortItem_T, len);
1442 if (ptrs == NULL)
1443 goto theend;
1444
1445 i = 0;
1446 if (sort)
1447 {
1448 /* sort(): ptrs will be the list to sort */
1449 for (li = l->lv_first; li != NULL; li = li->li_next)
1450 {
1451 ptrs[i].item = li;
1452 ptrs[i].idx = i;
1453 ++i;
1454 }
1455
1456 info.item_compare_func_err = FALSE;
1457 info.item_compare_keep_zero = FALSE;
1458 /* test the compare function */
1459 if ((info.item_compare_func != NULL
1460 || info.item_compare_partial != NULL)
1461 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
1462 == ITEM_COMPARE_FAIL)
1463 emsg(_("E702: Sort compare function failed"));
1464 else
1465 {
1466 /* Sort the array with item pointers. */
1467 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
1468 info.item_compare_func == NULL
1469 && info.item_compare_partial == NULL
1470 ? item_compare : item_compare2);
1471
1472 if (!info.item_compare_func_err)
1473 {
1474 /* Clear the List and append the items in sorted order. */
1475 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
1476 l->lv_len = 0;
1477 for (i = 0; i < len; ++i)
1478 list_append(l, ptrs[i].item);
1479 }
1480 }
1481 }
1482 else
1483 {
1484 int (*item_compare_func_ptr)(const void *, const void *);
1485
1486 /* f_uniq(): ptrs will be a stack of items to remove */
1487 info.item_compare_func_err = FALSE;
1488 info.item_compare_keep_zero = TRUE;
1489 item_compare_func_ptr = info.item_compare_func != NULL
1490 || info.item_compare_partial != NULL
1491 ? item_compare2 : item_compare;
1492
1493 for (li = l->lv_first; li != NULL && li->li_next != NULL;
1494 li = li->li_next)
1495 {
1496 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
1497 == 0)
1498 ptrs[i++].item = li;
1499 if (info.item_compare_func_err)
1500 {
1501 emsg(_("E882: Uniq compare function failed"));
1502 break;
1503 }
1504 }
1505
1506 if (!info.item_compare_func_err)
1507 {
1508 while (--i >= 0)
1509 {
1510 li = ptrs[i].item->li_next;
1511 ptrs[i].item->li_next = li->li_next;
1512 if (li->li_next != NULL)
1513 li->li_next->li_prev = ptrs[i].item;
1514 else
1515 l->lv_last = ptrs[i].item;
1516 list_fix_watch(l, li);
1517 listitem_free(li);
1518 l->lv_len--;
1519 }
1520 }
1521 }
1522
1523 vim_free(ptrs);
1524 }
1525theend:
1526 sortinfo = old_sortinfo;
1527}
1528
1529/*
1530 * "sort({list})" function
1531 */
1532 void
1533f_sort(typval_T *argvars, typval_T *rettv)
1534{
1535 do_sort_uniq(argvars, rettv, TRUE);
1536}
1537
1538/*
1539 * "uniq({list})" function
1540 */
1541 void
1542f_uniq(typval_T *argvars, typval_T *rettv)
1543{
1544 do_sort_uniq(argvars, rettv, FALSE);
1545}
1546
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001547#endif /* defined(FEAT_EVAL) */