aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/garray.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/garray.c')
-rw-r--r--src/nvim/garray.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/src/nvim/garray.c b/src/nvim/garray.c
new file mode 100644
index 0000000000..e1046ceb5e
--- /dev/null
+++ b/src/nvim/garray.c
@@ -0,0 +1,197 @@
+/// @file garray.c
+///
+/// Functions for handling growing arrays.
+
+#include <string.h>
+
+#include "vim.h"
+#include "ascii.h"
+#include "misc2.h"
+#include "memory.h"
+#include "path.h"
+#include "garray.h"
+
+// #include "globals.h"
+#include "memline.h"
+
+/// Clear an allocated growing array.
+void ga_clear(garray_T *gap)
+{
+ free(gap->ga_data);
+
+ // Initialize growing array without resetting itemsize or growsize
+ gap->ga_data = NULL;
+ gap->ga_maxlen = 0;
+ gap->ga_len = 0;
+}
+
+/// Clear a growing array that contains a list of strings.
+///
+/// @param gap
+void ga_clear_strings(garray_T *gap)
+{
+ int i;
+ for (i = 0; i < gap->ga_len; ++i) {
+ free(((char_u **)(gap->ga_data))[i]);
+ }
+ ga_clear(gap);
+}
+
+/// Initialize a growing array.
+///
+/// @param gap
+/// @param itemsize
+/// @param growsize
+void ga_init(garray_T *gap, int itemsize, int growsize)
+{
+ gap->ga_data = NULL;
+ gap->ga_maxlen = 0;
+ gap->ga_len = 0;
+ gap->ga_itemsize = itemsize;
+ gap->ga_growsize = growsize;
+}
+
+/// Make room in growing array "gap" for at least "n" items.
+///
+/// @param gap
+/// @param n
+void ga_grow(garray_T *gap, int n)
+{
+ if (gap->ga_maxlen - gap->ga_len >= n) {
+ // the garray still has enough space, do nothing
+ return;
+ }
+
+ // the garray grows by at least growsize (do we have a MIN macro somewhere?)
+ n = (n < gap->ga_growsize) ? gap->ga_growsize : n;
+
+ size_t new_size = (size_t)(gap->ga_itemsize * (gap->ga_len + n));
+ size_t old_size = (size_t)(gap->ga_itemsize * gap->ga_maxlen);
+
+ // reallocate and clear the new memory
+ char_u *pp = xrealloc(gap->ga_data, new_size);
+ memset(pp + old_size, 0, new_size - old_size);
+
+ gap->ga_maxlen = gap->ga_len + n;
+ gap->ga_data = pp;
+}
+
+/// Sort "gap" and remove duplicate entries. "gap" is expected to contain a
+/// list of file names in allocated memory.
+///
+/// @param gap
+void ga_remove_duplicate_strings(garray_T *gap)
+{
+ char_u **fnames = gap->ga_data;
+
+ // sort the growing array, which puts duplicates next to each other
+ sort_strings(fnames, gap->ga_len);
+
+ // loop over the growing array in reverse
+ for (int i = gap->ga_len - 1; i > 0; i--) {
+ if (fnamecmp(fnames[i - 1], fnames[i]) == 0) {
+ free(fnames[i]);
+
+ // close the gap (move all strings one slot lower)
+ for (int j = i + 1; j < gap->ga_len; j++) {
+ fnames[j - 1] = fnames[j];
+ }
+
+ --gap->ga_len;
+ }
+ }
+}
+
+/// For a growing array that contains a list of strings: concatenate all the
+/// strings with sep as separator.
+///
+/// @param gap
+///
+/// @returns the concatenated strings
+char_u *ga_concat_strings_sep(const garray_T *gap, const char *sep)
+{
+ const size_t nelem = (size_t) gap->ga_len;
+ const char **strings = gap->ga_data;
+
+ if (nelem == 0) {
+ return (char_u *) xstrdup("");
+ }
+
+ size_t len = 0;
+ for (size_t i = 0; i < nelem; i++) {
+ len += strlen(strings[i]);
+ }
+
+ // add some space for the (num - 1) separators
+ len += (nelem - 1) * strlen(sep);
+ char *const ret = xmallocz(len);
+
+ char *s = ret;
+ for (size_t i = 0; i < nelem - 1; i++) {
+ s = xstpcpy(s, strings[i]);
+ s = xstpcpy(s, sep);
+ }
+ s = xstpcpy(s, strings[nelem - 1]);
+
+ return (char_u *) ret;
+}
+
+/// For a growing array that contains a list of strings: concatenate all the
+/// strings with a separating comma.
+///
+/// @param gap
+///
+/// @returns the concatenated strings
+char_u* ga_concat_strings(const garray_T *gap)
+{
+ return ga_concat_strings_sep(gap, ",");
+}
+
+/// Concatenate a string to a growarray which contains characters.
+///
+/// WARNING:
+/// - Does NOT copy the NUL at the end!
+/// - The parameter may not overlap with the growing array
+///
+/// @param gap
+/// @param s
+void ga_concat(garray_T *gap, const char_u *restrict s)
+{
+ int len = (int)strlen((char *) s);
+ ga_grow(gap, len);
+ char *data = gap->ga_data;
+ memcpy(data + gap->ga_len, s, (size_t) len);
+ gap->ga_len += len;
+}
+
+/// Append one byte to a growarray which contains bytes.
+///
+/// @param gap
+/// @param c
+void ga_append(garray_T *gap, char c)
+{
+ ga_grow(gap, 1);
+ char *str = gap->ga_data;
+ str[gap->ga_len] = c;
+ gap->ga_len++;
+}
+
+#if defined(UNIX) || defined(WIN3264)
+
+/// Append the text in "gap" below the cursor line and clear "gap".
+///
+/// @param gap
+void append_ga_line(garray_T *gap)
+{
+ // Remove trailing CR.
+ if ((gap->ga_len > 0)
+ && !curbuf->b_p_bin
+ && (((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)) {
+ gap->ga_len--;
+ }
+ ga_append(gap, NUL);
+ ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
+ gap->ga_len = 0;
+}
+
+#endif // if defined(UNIX) || defined(WIN3264)