diff options
-rw-r--r-- | src/nvim/option.c | 247 |
1 files changed, 170 insertions, 77 deletions
diff --git a/src/nvim/option.c b/src/nvim/option.c index b4b0ff0c43..a449deb014 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -328,6 +328,146 @@ static char *strcpy_comma_escaped(char *dest, const char *src, const size_t len) return &dest[len + shift]; } +/// Compute length of a colon-separated value, doubled and with some suffixes +/// +/// @param[in] val Colon-separated array value. +/// @param[in] common_suf_len Length of the common suffix which is appended to +/// each item in the array, twice. +/// @param[in] single_suf_len Length of the suffix which is appended to each +/// item in the array once. +/// +/// @return Length of the comma-separated string array that contains each item +/// in the original array twice with suffixes with given length +/// (common_suf is present after each new item, single_suf is present +/// after half of the new items) and with commas after each item, commas +/// inside the values are escaped. +static inline size_t compute_double_colon_len(const char *const val, + const size_t common_suf_len, + const size_t single_suf_len) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE +{ + if (val == NULL) { + return 0; + } + size_t ret = 0; + const void *iter = NULL; + do { + size_t dir_len; + const char *dir; + iter = vim_colon_env_iter(val, iter, &dir, &dir_len); + if (dir != NULL && dir_len > 0) { + ret += ((dir_len + count_commas(dir, dir_len) + common_suf_len + 1) * 2 + + single_suf_len); + } + } while (iter != NULL); + return ret; +} + +#define NVIM_SIZE (sizeof("nvim") - 1) + +/// Add directories to a comma-separated array from a colon-separated one +/// +/// Commas are escaped in process. To each item PATHSEP "nvim" is appended in +/// addition to suf1 and suf2. +/// +/// @param[in,out] dest Destination comma-separated array. +/// @param[in] val Source colon-separated array. +/// @param[in] suf1 If not NULL, suffix appended to destination. Prior to it +/// directory separator is appended. Suffix must not contain +/// commas. +/// @param[in] len1 Length of the suf1. +/// @param[in] suf2 If not NULL, another suffix appended to destination. Again +/// with directory separator behind. Suffix must not contain +/// commas. +/// @param[in] len2 Length of the suf2. +/// @param[in] forward If true, iterate over val in forward direction. +/// Otherwise in reverse. +/// +/// @return (dest + appended_characters_length) +static inline char *add_colon_dirs(char *dest, const char *const val, + const char *const suf1, const size_t len1, + const char *const suf2, const size_t len2, + const bool forward) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1) +{ + if (val == NULL) { + return dest; + } + const void *iter = NULL; + do { + size_t dir_len; + const char *dir; + iter = (forward ? vim_colon_env_iter : vim_colon_env_iter_rev)( + val, iter, &dir, &dir_len); + if (dir != NULL && dir_len > 0) { + dest = strcpy_comma_escaped(dest, dir, dir_len); + *dest++ = PATHSEP; + memmove(dest, "nvim", NVIM_SIZE); + dest += NVIM_SIZE; + if (suf1 != NULL) { + *dest++ = PATHSEP; + memmove(dest, suf1, len1); + dest += len1; + if (suf2 != NULL) { + *dest++ = PATHSEP; + memmove(dest, suf2, len2); + dest += len2; + } + } + *dest++ = ','; + } + } while (iter != NULL); + return dest; +} + +/// Add directory to a comma-separated list of directories +/// +/// In the added directory comma is escaped. +/// +/// @param[in,out] dest Destination comma-separated array. +/// @param[in] dir Directory to append. +/// @param[in] append_nvim If true, append "nvim" as the very first suffix. +/// @param[in] suf1 If not NULL, suffix appended to destination. Prior to it +/// directory separator is appended. Suffix must not contain +/// commas. +/// @param[in] len1 Length of the suf1. +/// @param[in] suf2 If not NULL, another suffix appended to destination. Again +/// with directory separator behind. Suffix must not contain +/// commas. +/// @param[in] len2 Length of the suf2. +/// @param[in] forward If true, iterate over val in forward direction. +/// Otherwise in reverse. +/// +/// @return (dest + appended_characters_length) +static inline char *add_dir(char *dest, const char *const dir, + const size_t dir_len, const bool append_nvim, + const char *const suf1, const size_t len1, + const char *const suf2, const size_t len2) + FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (dir == NULL) { + return dest; + } + dest = strcpy_comma_escaped(dest, dir, dir_len); + if (append_nvim) { + *dest++ = PATHSEP; + memmove(dest, "nvim", NVIM_SIZE); + dest += NVIM_SIZE; + if (suf1 != NULL) { + *dest++ = PATHSEP; + memmove(dest, suf1, len1); + dest += len1; + if (suf2 != NULL) { + *dest++ = PATHSEP; + memmove(dest, suf2, len2); + dest += len2; + } + } + } + *dest++ = ','; + return dest; +} + /// Set &runtimepath to default value static void set_runtimepath_default(void) { @@ -337,102 +477,53 @@ static void set_runtimepath_default(void) char *const vimruntime = vim_getenv("VIMRUNTIME"); char *const data_dirs = stdpaths_get_xdg_var(kXDGDataDirs); char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs); -#define NVIM_SIZE (sizeof("/nvim") - 1) -#define SITE_SIZE (sizeof("/site") - 1) -#define AFTER_SIZE (sizeof("/after") - 1) +#define SITE_SIZE (sizeof("site") - 1) +#define AFTER_SIZE (sizeof("after") - 1) size_t data_len; size_t config_len; size_t vimruntime_len; if (data_home != NULL) { data_len = strlen(data_home); rtp_size += ((data_len + count_commas(data_home, data_len) - + NVIM_SIZE + SITE_SIZE) * 2 + AFTER_SIZE) + 2; + + NVIM_SIZE + 1 + SITE_SIZE + 1 + 1) * 2 + AFTER_SIZE + 1); } if (config_home != NULL) { config_len = strlen(config_home); rtp_size += ((config_len + count_commas(config_home, config_len) - + NVIM_SIZE) * 2 + AFTER_SIZE) + 2; + + NVIM_SIZE + 1 + 1) * 2 + AFTER_SIZE + 1); } if (vimruntime != NULL) { vimruntime_len = strlen(vimruntime); rtp_size += vimruntime_len + count_commas(vimruntime, vimruntime_len) + 1; } -#define COMPUTE_COLON_LEN(rtp_size, additional_size, val) \ - do { \ - if (val != NULL) { \ - const void *iter = NULL; \ - do { \ - size_t dir_len; \ - const char *dir; \ - iter = vim_colon_env_iter(val, iter, &dir, &dir_len); \ - if (dir != NULL && dir_len > 0) { \ - rtp_size += ((dir_len + count_commas(dir, dir_len) \ - + NVIM_SIZE + additional_size) * 2 \ - + AFTER_SIZE) + 2; \ - } \ - } while (iter != NULL); \ - } \ - } while (0) - COMPUTE_COLON_LEN(rtp_size, SITE_SIZE, data_dirs); - COMPUTE_COLON_LEN(rtp_size, 0, config_dirs); -#undef COMPUTE_COLON_LEN + rtp_size += compute_double_colon_len(data_dirs, NVIM_SIZE + 1 + SITE_SIZE + 1, + AFTER_SIZE + 1); + rtp_size += compute_double_colon_len(config_dirs, NVIM_SIZE + 1, + AFTER_SIZE + 1); if (rtp_size == 0) { return; } - // All additions were including comma. - rtp_size--; - char *const rtp = xmallocz(rtp_size); + char *const rtp = xmalloc(rtp_size); char *rtp_cur = rtp; -#define ADD_STRING(tgt, src, len) \ - tgt = strcpy_comma_escaped(tgt, src, len) -#define ADD_STATIC_STRING(tgt, src) \ - do { memmove(tgt, src, sizeof(src) - 1); tgt += sizeof(src) - 1; } while (0) -#define ADD_COLON_DIRS(tgt, val, suffix, revsuffix) \ - do { \ - if (val != NULL) { \ - const void *iter = NULL; \ - do { \ - size_t dir_len; \ - const char *dir; \ - iter = vim_colon_env_iter##revsuffix(val, iter, &dir, &dir_len); \ - if (dir != NULL && dir_len > 0) { \ - ADD_STRING(rtp_cur, dir, dir_len); \ - ADD_STATIC_STRING(rtp_cur, "/nvim" suffix ","); \ - } \ - } while (iter != NULL); \ - } \ - } while (0) - if (config_home != NULL) { - ADD_STRING(rtp_cur, config_home, config_len); - ADD_STATIC_STRING(rtp_cur, "/nvim,"); - } - ADD_COLON_DIRS(rtp_cur, config_dirs, "", ); - if (data_home != NULL) { - ADD_STRING(rtp_cur, data_home, data_len); - ADD_STATIC_STRING(rtp_cur, "/nvim/site,"); - } - ADD_COLON_DIRS(rtp_cur, data_dirs, "/site", ); - if (vimruntime != NULL) { - ADD_STRING(rtp_cur, vimruntime, vimruntime_len); - *rtp_cur++ = ','; - } - ADD_COLON_DIRS(rtp_cur, data_dirs, "/site/after", _rev); - if (data_home != NULL) { - ADD_STRING(rtp_cur, data_home, data_len); - ADD_STATIC_STRING(rtp_cur, "/nvim/site/after,"); - } - ADD_COLON_DIRS(rtp_cur, config_dirs, "/after", _rev); - if (config_home != NULL) { - ADD_STRING(rtp_cur, config_home, config_len); - ADD_STATIC_STRING(rtp_cur, "/nvim/after"); - } else { - // Strip trailing comma. - rtp[rtp_size] = NUL; - } -#undef ADD_COLON_DIRS -#undef ADD_STATIC_STRING -#undef ADD_STRING -#undef NVIM_SIZE + rtp_cur = add_dir(rtp_cur, config_home, config_len, true, NULL, 0, NULL, 0); + rtp_cur = add_colon_dirs(rtp_cur, config_dirs, NULL, 0, NULL, 0, true); + rtp_cur = add_dir(rtp_cur, data_home, data_len, true, "site", SITE_SIZE, + NULL, 0); + rtp_cur = add_colon_dirs(rtp_cur, data_dirs, "site", SITE_SIZE, NULL, 0, + true); + rtp_cur = add_dir(rtp_cur, vimruntime, vimruntime_len, false, NULL, 0, + NULL, 0); + rtp_cur = add_colon_dirs(rtp_cur, data_dirs, "site", SITE_SIZE, + "after", AFTER_SIZE, false); + rtp_cur = add_dir(rtp_cur, data_home, data_len, true, "site", SITE_SIZE, + "after", AFTER_SIZE); + rtp_cur = add_colon_dirs(rtp_cur, config_dirs, "after", AFTER_SIZE, NULL, 0, + false); + rtp_cur = add_dir(rtp_cur, config_home, config_len, true, + "after", AFTER_SIZE, NULL, 0); + // Strip trailing comma. + rtp_cur[-1] = NUL; + assert((size_t) (rtp_cur - rtp) == rtp_size); #undef SITE_SIZE #undef AFTER_SIZE set_string_default("runtimepath", rtp, true); @@ -443,6 +534,8 @@ static void set_runtimepath_default(void) xfree(vimruntime); } +#undef NVIM_SIZE + /* * Initialize the options, first part. * |