diff options
| author | Justin M. Keyes <justinkz@gmail.com> | 2015-10-25 22:38:23 -0400 |
|---|---|---|
| committer | Justin M. Keyes <justinkz@gmail.com> | 2015-10-25 22:38:23 -0400 |
| commit | 1ca5646bb52ec5c23b28f45bb7bc5d25cffad9b0 (patch) | |
| tree | 7495d3f50b897e74fc4597d061d427a4e9b1ae36 /src/nvim | |
| parent | de4cb766ca381c09fd3f938136c1932ebf008f63 (diff) | |
| parent | 42047acb4f07c689936b051864c6b4448b1b6aa1 (diff) | |
| download | rneovim-1ca5646bb52ec5c23b28f45bb7bc5d25cffad9b0.tar.gz rneovim-1ca5646bb52ec5c23b28f45bb7bc5d25cffad9b0.tar.bz2 rneovim-1ca5646bb52ec5c23b28f45bb7bc5d25cffad9b0.zip | |
Merge pull request #3470 from ZyX-I/pr-3198
XDG base directory specification support
Diffstat (limited to 'src/nvim')
| -rw-r--r-- | src/nvim/main.c | 211 | ||||
| -rw-r--r-- | src/nvim/memline.c | 123 | ||||
| -rw-r--r-- | src/nvim/option.c | 322 | ||||
| -rw-r--r-- | src/nvim/options.lua | 10 | ||||
| -rw-r--r-- | src/nvim/os/env.c | 68 | ||||
| -rw-r--r-- | src/nvim/os/fs.c | 10 | ||||
| -rw-r--r-- | src/nvim/os/os.h | 2 | ||||
| -rw-r--r-- | src/nvim/os/stdpaths.c | 108 | ||||
| -rw-r--r-- | src/nvim/os/stdpaths_defs.h | 14 | ||||
| -rw-r--r-- | src/nvim/os/unix_defs.h | 37 | ||||
| -rw-r--r-- | src/nvim/os/win_defs.h | 4 | ||||
| -rw-r--r-- | src/nvim/path.c | 59 | ||||
| -rw-r--r-- | src/nvim/shada.c | 31 | ||||
| -rw-r--r-- | src/nvim/testdir/unix.vim | 3 | ||||
| -rw-r--r-- | src/nvim/version.c | 25 |
15 files changed, 748 insertions, 279 deletions
diff --git a/src/nvim/main.c b/src/nvim/main.c index d865260295..60a242fae3 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -287,8 +287,8 @@ int main(int argc, char **argv) * Set the default values for the options that use Rows and Columns. */ win_init_size(); - /* Set the 'diff' option now, so that it can be checked for in a .vimrc - * file. There is no buffer yet though. */ + // Set the 'diff' option now, so that it can be checked for in a vimrc + // file. There is no buffer yet though. if (params.diff_mode) diff_win_options(firstwin, FALSE); @@ -345,7 +345,7 @@ int main(int argc, char **argv) */ load_plugins(); - /* Decide about window layout for diff mode after reading vimrc. */ + // Decide about window layout for diff mode after reading vimrc. set_window_layout(¶ms); /* @@ -358,10 +358,8 @@ int main(int argc, char **argv) mch_exit(0); } - /* - * Set a few option defaults after reading .vimrc files: - * 'title' and 'icon', Unix: 'shellpipe' and 'shellredir'. - */ + // Set a few option defaults after reading vimrc files: + // 'title' and 'icon', Unix: 'shellpipe' and 'shellredir'. set_init_3(); TIME_MSG("inits 3"); @@ -1551,8 +1549,8 @@ static void create_windows(mparm_T *parmp) if (parmp->window_count == 0) parmp->window_count = GARGCOUNT; if (parmp->window_count > 1) { - /* Don't change the windows if there was a command in .vimrc that - * already split some windows */ + // Don't change the windows if there was a command in vimrc that + // already split some windows if (parmp->window_layout == 0) parmp->window_layout = WIN_HOR; if (parmp->window_layout == WIN_TABS) { @@ -1574,14 +1572,11 @@ static void create_windows(mparm_T *parmp) getout(1); do_modelines(0); /* do modelines */ } else { - /* - * Open a buffer for windows that don't have one yet. - * Commands in the .vimrc might have loaded a file or split the window. - * Watch out for autocommands that delete a window. - */ - /* - * Don't execute Win/Buf Enter/Leave autocommands here - */ + // Open a buffer for windows that don't have one yet. + // Commands in the vimrc might have loaded a file or split the window. + // Watch out for autocommands that delete a window. + // + // Don't execute Win/Buf Enter/Leave autocommands here ++autocmd_no_enter; ++autocmd_no_leave; dorewind = TRUE; @@ -1691,8 +1686,8 @@ static void edit_buffers(mparm_T *parmp) } advance = TRUE; - /* Only open the file if there is no file in this window yet (that can - * happen when .vimrc contains ":sall"). */ + // Only open the file if there is no file in this window yet (that can + // happen when vimrc contains ":sall"). if (curbuf == firstwin->w_buffer || curbuf->b_ffname == NULL) { curwin->w_arg_idx = arg_idx; /* Edit file from arg list, if there is one. When "Quit" selected @@ -1801,117 +1796,121 @@ static void exe_commands(mparm_T *parmp) TIME_MSG("executing command arguments"); } -/* - * Source startup scripts. - */ -static void source_startup_scripts(mparm_T *parmp) +/// Source vimrc or do other user initialization +/// +/// Does one of the following things, stops after whichever succeeds: +/// +/// 1. Execution of VIMINIT environment variable. +/// 2. Sourcing user vimrc file ($XDG_CONFIG_HOME/nvim/init.vim). +/// 3. Sourcing other vimrc files ($XDG_CONFIG_DIRS[1]/nvim/init.vim, …). +/// 4. Execution of EXINIT environment variable. +/// +/// @return True if it is needed to attempt to source exrc file according to +/// 'exrc' option definition. +static bool do_user_initialization(void) + FUNC_ATTR_WARN_UNUSED_RESULT { - int i; + bool do_exrc = p_exrc; + if (process_env("VIMINIT", true) == OK) { + return do_exrc; + } + char_u *user_vimrc = (char_u *)stdpaths_user_conf_subpath("init.vim"); + if (do_source(user_vimrc, true, DOSO_VIMRC) != FAIL) { + if (do_exrc) { + do_exrc = (path_full_compare((char_u *)VIMRC_FILE, user_vimrc, false) + != kEqualFiles); + } + xfree(user_vimrc); + return do_exrc; + } + xfree(user_vimrc); + char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs); + if (config_dirs != NULL) { + const void *iter = NULL; + do { + const char *dir; + size_t dir_len; + iter = vim_colon_env_iter(config_dirs, iter, &dir, &dir_len); + if (dir == NULL || dir_len == 0) { + break; + } + const char path_tail[] = { 'n', 'v', 'i', 'm', PATHSEP, + 'i', 'n', 'i', 't', '.', 'v', 'i', 'm', NUL }; + char *vimrc = xmalloc(dir_len + sizeof(path_tail) + 1); + memmove(vimrc, dir, dir_len); + vimrc[dir_len] = PATHSEP; + memmove(vimrc + dir_len + 1, path_tail, sizeof(path_tail)); + if (do_source((char_u *) vimrc, true, DOSO_VIMRC) != FAIL) { + if (do_exrc) { + do_exrc = (path_full_compare((char_u *)VIMRC_FILE, (char_u *)vimrc, + false) != kEqualFiles); + } + xfree(vimrc); + xfree(config_dirs); + return do_exrc; + } + xfree(vimrc); + } while (iter != NULL); + xfree(config_dirs); + } + if (process_env("EXINIT", false) == OK) { + return do_exrc; + } + return do_exrc; +} - /* - * If -u argument given, use only the initializations from that file and - * nothing else. - */ +/// Source startup scripts +/// +/// @param[in] +static void source_startup_scripts(const mparm_T *const parmp) + FUNC_ATTR_NONNULL_ALL +{ + // If -u argument given, use only the initializations from that file and + // nothing else. if (parmp->use_vimrc != NULL) { if (strcmp(parmp->use_vimrc, "NONE") == 0 || strcmp(parmp->use_vimrc, "NORC") == 0) { if (parmp->use_vimrc[2] == 'N') - p_lpl = FALSE; // don't load plugins either + p_lpl = false; // don't load plugins either } else { if (do_source((char_u *)parmp->use_vimrc, FALSE, DOSO_NONE) != OK) EMSG2(_("E282: Cannot read from \"%s\""), parmp->use_vimrc); } } else if (!silent_mode) { - - /* - * Get system wide defaults, if the file name is defined. - */ #ifdef SYS_VIMRC_FILE - (void)do_source((char_u *)SYS_VIMRC_FILE, FALSE, DOSO_NONE); -#endif - - /* - * Try to read initialization commands from the following places: - * - environment variable VIMINIT - * - user vimrc file (~/.vimrc) - * - second user vimrc file ($VIM/.vimrc for Dos) - * - environment variable EXINIT - * - user exrc file (~/.exrc) - * - second user exrc file ($VIM/.exrc for Dos) - * The first that exists is used, the rest is ignored. - */ - if (process_env("VIMINIT", true) != OK) { - if (do_source((char_u *)USR_VIMRC_FILE, TRUE, DOSO_VIMRC) == FAIL -#ifdef USR_VIMRC_FILE2 - && do_source((char_u *)USR_VIMRC_FILE2, TRUE, - DOSO_VIMRC) == FAIL + // Get system wide defaults, if the file name is defined. + (void) do_source((char_u *)SYS_VIMRC_FILE, false, DOSO_NONE); #endif -#ifdef USR_VIMRC_FILE3 - && do_source((char_u *)USR_VIMRC_FILE3, TRUE, - DOSO_VIMRC) == FAIL -#endif - && process_env("EXINIT", FALSE) == FAIL - && do_source((char_u *)USR_EXRC_FILE, FALSE, DOSO_NONE) == FAIL) { -#ifdef USR_EXRC_FILE2 - (void)do_source((char_u *)USR_EXRC_FILE2, FALSE, DOSO_NONE); -#endif - } - } - /* - * Read initialization commands from ".vimrc" or ".exrc" in current - * directory. This is only done if the 'exrc' option is set. - * Because of security reasons we disallow shell and write commands - * now, except for unix if the file is owned by the user or 'secure' - * option has been reset in environment of global ".exrc" or ".vimrc". - * Only do this if VIMRC_FILE is not the same as USR_VIMRC_FILE or - * SYS_VIMRC_FILE. - */ - if (p_exrc) { + if (do_user_initialization()) { + // Read initialization commands from ".vimrc" or ".exrc" in current + // directory. This is only done if the 'exrc' option is set. + // Because of security reasons we disallow shell and write commands + // now, except for unix if the file is owned by the user or 'secure' + // option has been reset in environment of global "exrc" or "vimrc". + // Only do this if VIMRC_FILE is not the same as vimrc file sourced in + // do_user_initialization. #if defined(UNIX) - /* If ".vimrc" file is not owned by user, set 'secure' mode. */ + // If vimrc file is not owned by user, set 'secure' mode. if (!file_owned(VIMRC_FILE)) #endif secure = p_secure; - i = FAIL; - if (path_full_compare((char_u *)USR_VIMRC_FILE, - (char_u *)VIMRC_FILE, FALSE) != kEqualFiles -#ifdef USR_VIMRC_FILE2 - && path_full_compare((char_u *)USR_VIMRC_FILE2, - (char_u *)VIMRC_FILE, FALSE) != kEqualFiles -#endif -#ifdef USR_VIMRC_FILE3 - && path_full_compare((char_u *)USR_VIMRC_FILE3, - (char_u *)VIMRC_FILE, FALSE) != kEqualFiles -#endif -#ifdef SYS_VIMRC_FILE - && path_full_compare((char_u *)SYS_VIMRC_FILE, - (char_u *)VIMRC_FILE, FALSE) != kEqualFiles -#endif - ) - i = do_source((char_u *)VIMRC_FILE, TRUE, DOSO_VIMRC); - - if (i == FAIL) { + if (do_source((char_u *)VIMRC_FILE, true, DOSO_VIMRC) == FAIL) { #if defined(UNIX) - /* if ".exrc" is not owned by user set 'secure' mode */ - if (!file_owned(EXRC_FILE)) + // if ".exrc" is not owned by user set 'secure' mode + if (!file_owned(EXRC_FILE)) { secure = p_secure; - else + } else { secure = 0; + } #endif - if ( path_full_compare((char_u *)USR_EXRC_FILE, - (char_u *)EXRC_FILE, FALSE) != kEqualFiles -#ifdef USR_EXRC_FILE2 - && path_full_compare((char_u *)USR_EXRC_FILE2, - (char_u *)EXRC_FILE, FALSE) != kEqualFiles -#endif - ) - (void)do_source((char_u *)EXRC_FILE, FALSE, DOSO_NONE); + (void)do_source((char_u *)EXRC_FILE, false, DOSO_NONE); } } - if (secure == 2) - need_wait_return = TRUE; + if (secure == 2) { + need_wait_return = true; + } secure = 0; } did_source_startup_scripts = true; @@ -2042,7 +2041,7 @@ static void usage(void) mch_msg(_(" -r, -L List swap files and exit\n")); mch_msg(_(" -r <file> Recover crashed session\n")); mch_msg(_(" -u <nvimrc> Use <nvimrc> instead of the default\n")); - mch_msg(_(" -i <shada> Use <shada> instead of the default " SHADA_FILE "\n")); // NOLINT(whitespace/line_length) + mch_msg(_(" -i <shada> Use <shada> instead of the default\n")); mch_msg(_(" --noplugin Don't load plugin scripts\n")); mch_msg(_(" -o[N] Open N windows (default: one for each file)\n")); mch_msg(_(" -O[N] Like -o but split vertically\n")); diff --git a/src/nvim/memline.c b/src/nvim/memline.c index d90e91be5d..aa3e0e0b1c 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -406,10 +406,12 @@ void ml_setname(buf_T *buf) * Try all directories in the 'directory' option. */ dirp = p_dir; + bool found_existing_dir = false; for (;; ) { if (*dirp == NUL) /* tried all directories, fail */ break; - fname = findswapname(buf, &dirp, mfp->mf_fname); + fname = (char_u *)findswapname(buf, (char **)&dirp, (char *)mfp->mf_fname, + &found_existing_dir); /* alloc's fname */ if (dirp == NULL) /* out of memory */ break; @@ -504,13 +506,15 @@ void ml_open_file(buf_T *buf) * Try all directories in 'directory' option. */ dirp = p_dir; + bool found_existing_dir = false; for (;; ) { if (*dirp == NUL) break; - /* There is a small chance that between choosing the swap file name - * and creating it, another Vim creates the file. In that case the - * creation will fail and we will use another directory. */ - fname = findswapname(buf, &dirp, NULL); /* allocates fname */ + // There is a small chance that between choosing the swap file name + // and creating it, another Vim creates the file. In that case the + // creation will fail and we will use another directory. + fname = (char_u *)findswapname(buf, (char **)&dirp, NULL, + &found_existing_dir); if (dirp == NULL) break; /* out of memory */ if (fname == NULL) @@ -3222,45 +3226,56 @@ static int do_swapexists(buf_T *buf, char_u *fname) return 0; } -/* - * Find out what name to use for the swap file for buffer 'buf'. - * - * Several names are tried to find one that does not exist - * Returns the name in allocated memory or NULL. - * When out of memory "dirp" is set to NULL. - * - * Note: If BASENAMELEN is not correct, you will get error messages for - * not being able to open the swap or undo file - * Note: May trigger SwapExists autocmd, pointers may change! - */ -static char_u * -findswapname ( - buf_T *buf, - char_u **dirp, /* pointer to list of directories */ - char_u *old_fname /* don't give warning for this file name */ -) +/// Find out what name to use for the swap file for buffer 'buf'. +/// +/// Several names are tried to find one that does not exist. Last directory in +/// option is automatically created. +/// +/// @note If BASENAMELEN is not correct, you will get error messages for +/// not being able to open the swap or undo file. +/// @note May trigger SwapExists autocmd, pointers may change! +/// +/// @param[in] buf Buffer for which swap file names needs to be found. +/// @param[in,out] dirp Pointer to a list of directories. When out of memory, +/// is set to NULL. Is advanced to the next directory in +/// the list otherwise. +/// @param[in] old_fname Allowed existing swap file name. Except for this +/// case, name of the non-existing file is used. +/// @param[in,out] found_existing_dir If points to true, then new directory +/// for swap file is not created. At first +/// findswapname() call this argument must +/// point to false. This parameter may only +/// be set to true by this function, it is +/// never set to false. +/// +/// @return [allocated] Name of the swap file. +static char *findswapname(buf_T *buf, char **dirp, char *old_fname, + bool *found_existing_dir) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 2, 4) { - char_u *fname; - int n; - char_u *dir_name; - char_u *buf_fname = buf->b_fname; + char *fname; + size_t n; + char *dir_name; + char *buf_fname = (char *) buf->b_fname; /* * Isolate a directory name from *dirp and put it in dir_name. * First allocate some memory to put the directory name in. */ - dir_name = xmalloc(STRLEN(*dirp) + 1); - (void)copy_option_part(dirp, dir_name, 31000, ","); + const size_t dir_len = strlen(*dirp); + dir_name = xmalloc(dir_len + 1); + (void)copy_option_part((char_u **) dirp, (char_u *) dir_name, dir_len, ","); /* * we try different names until we find one that does not exist yet */ - fname = makeswapname(buf_fname, buf->b_ffname, buf, dir_name); + fname = (char *)makeswapname((char_u *)buf_fname, buf->b_ffname, buf, + (char_u *)dir_name); for (;; ) { if (fname == NULL) /* must be out of memory */ break; - if ((n = (int)STRLEN(fname)) == 0) { /* safety check */ + if ((n = strlen(fname)) == 0) { /* safety check */ xfree(fname); fname = NULL; break; @@ -3269,7 +3284,7 @@ findswapname ( // Extra security check: When a swap file is a symbolic link, this // is most likely a symlink attack. FileInfo file_info; - bool file_or_link_found = os_fileinfo_link((char *)fname, &file_info); + bool file_or_link_found = os_fileinfo_link(fname, &file_info); if (!file_or_link_found) { break; } @@ -3300,7 +3315,7 @@ findswapname ( * Try to read block 0 from the swap file to get the original * file name (and inode number). */ - fd = os_open((char *)fname, O_RDONLY, 0); + fd = os_open(fname, O_RDONLY, 0); if (fd >= 0) { if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) { /* @@ -3311,7 +3326,7 @@ findswapname ( if (b0.b0_flags & B0_SAME_DIR) { if (fnamecmp(path_tail(buf->b_ffname), path_tail(b0.b0_fname)) != 0 - || !same_directory(fname, buf->b_ffname)) { + || !same_directory((char_u *) fname, buf->b_ffname)) { /* Symlinks may point to the same file even * when the name differs, need to check the * inode too. */ @@ -3351,12 +3366,12 @@ findswapname ( * user anyway. */ if (swap_exists_action != SEA_NONE - && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf)) - choice = do_swapexists(buf, fname); + && has_autocmd(EVENT_SWAPEXISTS, (char_u *) buf_fname, buf)) + choice = do_swapexists(buf, (char_u *) fname); if (choice == 0) { /* Show info about the existing swap file. */ - attention_message(buf, fname); + attention_message(buf, (char_u *) fname); /* We don't want a 'q' typed at the more-prompt * interrupt loading a file. */ @@ -3364,20 +3379,21 @@ findswapname ( } if (swap_exists_action != SEA_NONE && choice == 0) { - char_u *name; + char *name; - name = xmalloc(STRLEN(fname) - + STRLEN(_("Swap file \"")) - + STRLEN(_("\" already exists!")) + 5); + const size_t fname_len = strlen(fname); + name = xmalloc(fname_len + + strlen(_("Swap file \"")) + + strlen(_("\" already exists!")) + 5); STRCPY(name, _("Swap file \"")); - home_replace(NULL, fname, name + STRLEN(name), - 1000, TRUE); + home_replace(NULL, (char_u *) fname, (char_u *)&name[strlen(name)], + fname_len, true); STRCAT(name, _("\" already exists!")); choice = do_dialog(VIM_WARNING, (char_u *)_("VIM - ATTENTION"), - name == NULL - ? (char_u *)_("Swap file already exists!") - : name, + (char_u *)(name == NULL + ? _("Swap file already exists!") + : name), # if defined(UNIX) process_still_running ? (char_u *)_( @@ -3409,7 +3425,7 @@ findswapname ( swap_exists_action = SEA_RECOVER; break; case 4: - os_remove((char *)fname); + os_remove(fname); break; case 5: swap_exists_action = SEA_QUIT; @@ -3421,7 +3437,7 @@ findswapname ( } /* If the file was deleted this fname can be used. */ - if (!os_file_exists(fname)) + if (!os_file_exists((char_u *) fname)) break; } else { @@ -3454,6 +3470,19 @@ findswapname ( --fname[n - 1]; /* ".swo", ".swn", etc. */ } + if (os_isdir((char_u *) dir_name)) { + *found_existing_dir = true; + } else if (!*found_existing_dir && **dirp == NUL) { + int ret; + char *failed_dir; + if ((ret = os_mkdir_recurse(dir_name, 0755, &failed_dir)) != 0) { + EMSG3(_("E303: Unable to create directory \"%s\" for swap file, " + "recovery impossible: %s"), + failed_dir, os_strerror(ret)); + xfree(failed_dir); + } + } + xfree(dir_name); return fname; } diff --git a/src/nvim/option.c b/src/nvim/option.c index a578f2bb01..a4cfe45f10 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -301,6 +301,243 @@ static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview", # include "option.c.generated.h" #endif +/// Append string with escaped commas +static char *strcpy_comma_escaped(char *dest, const char *src, const size_t len) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + size_t shift = 0; + for (size_t i = 0; i < len; i++) { + if (src[i] == ',') { + dest[i + shift++] = '\\'; + } + dest[i + shift] = src[i]; + } + 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 && *val) { + 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 + memcnt(dir, ',', dir_len) + common_suf_len + + !after_pathsep(dir, dir + dir_len)) * 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 && *val) { + 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); + if (!after_pathsep(dest - 1, dest)) { + *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 && dir_len != 0) { + return dest; + } + dest = strcpy_comma_escaped(dest, dir, dir_len); + if (append_nvim) { + if (!after_pathsep(dest - 1, dest)) { + *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) +{ + size_t rtp_size = 0; + char *const data_home = stdpaths_get_xdg_var(kXDGDataHome); + char *const config_home = stdpaths_get_xdg_var(kXDGConfigHome); + 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 SITE_SIZE (sizeof("site") - 1) +#define AFTER_SIZE (sizeof("after") - 1) + size_t data_len = 0; + size_t config_len = 0; + size_t vimruntime_len = 0; + if (data_home != NULL) { + data_len = strlen(data_home); + if (data_len != 0) { + rtp_size += ((data_len + memcnt(data_home, ',', data_len) + + NVIM_SIZE + 1 + SITE_SIZE + 1 + + !after_pathsep(data_home, data_home + data_len)) * 2 + + AFTER_SIZE + 1); + } + } + if (config_home != NULL) { + config_len = strlen(config_home); + if (config_len != 0) { + rtp_size += ((config_len + memcnt(config_home, ',', config_len) + + NVIM_SIZE + 1 + + !after_pathsep(config_home, config_home + config_len)) * 2 + + AFTER_SIZE + 1); + } + } + if (vimruntime != NULL) { + vimruntime_len = strlen(vimruntime); + if (vimruntime_len != 0) { + rtp_size += vimruntime_len + memcnt(vimruntime, ',', vimruntime_len) + 1; + } + } + 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; + } + char *const rtp = xmalloc(rtp_size); + char *rtp_cur = rtp; + 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); + xfree(data_dirs); + xfree(config_dirs); + xfree(data_home); + xfree(config_home); + xfree(vimruntime); +} + +#undef NVIM_SIZE + /* * Initialize the options, first part. * @@ -308,7 +545,6 @@ static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview", */ void set_init_1(void) { - char_u *p; int opt_idx; langmap_init(); @@ -320,8 +556,12 @@ void set_init_1(void) * Find default value for 'shell' option. * Don't use it if it is empty. */ - if ((p = (char_u *)os_getenv("SHELL")) != NULL) - set_string_default("sh", p); + { + const char *shell = os_getenv("SHELL"); + if (shell != NULL) { + set_string_default("sh", (char *) shell, false); + } + } /* * Set the default for 'backupskip' to include environment variables for @@ -339,17 +579,18 @@ void set_init_1(void) ga_init(&ga, 1, 100); for (size_t n = 0; n < ARRAY_SIZE(names); ++n) { bool mustfree = true; + char *p; # ifdef UNIX if (*names[n] == NUL) { - p = (char_u *)"/tmp"; + p = "/tmp"; mustfree = false; } else # endif - p = (char_u *)vim_getenv(names[n]); + p = vim_getenv(names[n]); if (p != NULL && *p != NUL) { // First time count the NUL, otherwise count the ','. - len = (int)STRLEN(p) + 3; + len = (int)strlen(p) + 3; ga_grow(&ga, len); if (!GA_EMPTY(&ga)) STRCAT(ga.ga_data, ","); @@ -363,8 +604,7 @@ void set_init_1(void) } } if (ga.ga_data != NULL) { - set_string_default("bsk", ga.ga_data); - xfree(ga.ga_data); + set_string_default("bsk", ga.ga_data, true); } } @@ -425,17 +665,34 @@ void set_init_1(void) #if defined(MSWIN) || defined(MAC) /* Set print encoding on platforms that don't default to latin1 */ - set_string_default("penc", - (char_u *)"hp-roman8" - ); + set_string_default("printencoding", "hp-roman8", false); #endif - /* 'printexpr' must be allocated to be able to evaluate it. */ - set_string_default( - "pexpr", - (char_u *) - "system('lpr' . (&printdevice == '' ? '' : ' -P' . &printdevice) . ' ' . v:fname_in) . delete(v:fname_in) + v:shell_error" - ); + // 'printexpr' must be allocated to be able to evaluate it. + set_string_default("printexpr", +#ifdef UNIX + "system(['lpr'] " + "+ (empty(&printdevice)?[]:['-P', &printdevice]) " + "+ [v:fname_in])" + ". delete(v:fname_in)" |