diff options
Diffstat (limited to 'src/nvim/garray.c')
-rw-r--r-- | src/nvim/garray.c | 197 |
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) |