diff options
Diffstat (limited to 'src/nvim/os/env.c')
| -rw-r--r-- | src/nvim/os/env.c | 267 |
1 files changed, 159 insertions, 108 deletions
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 12c2da6152..7fb4a93b54 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -1,11 +1,11 @@ -// env.c -- environment variable access +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -#include <assert.h> +// Environment inspection +#include <assert.h> #include <uv.h> -// vim.h must be included before charset.h (and possibly others) or things -// blow up #include "nvim/vim.h" #include "nvim/ascii.h" #include "nvim/charset.h" @@ -14,6 +14,7 @@ #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/path.h" +#include "nvim/macros.h" #include "nvim/strings.h" #include "nvim/eval.h" #include "nvim/ex_getln.h" @@ -176,7 +177,7 @@ void os_get_hostname(char *hostname, size_t size) /// - do os_dirname() to get the real name of that directory. /// This also works with mounts and links. /// Don't do this for Windows, it will change the "current dir" for a drive. -static char_u *homedir = NULL; +static char *homedir = NULL; void init_homedir(void) { @@ -220,7 +221,7 @@ void init_homedir(void) } } #endif - homedir = vim_strsave((char_u *)var); + homedir = xstrdup(var); } } @@ -357,7 +358,7 @@ void expand_env_esc(char_u *restrict srcp, } else if (src[1] == NUL // home directory || vim_ispathsep(src[1]) || vim_strchr((char_u *)" ,\t\n", src[1]) != NULL) { - var = homedir; + var = (char_u *)homedir; tail = src + 1; } else { // user directory #if defined(UNIX) @@ -521,10 +522,11 @@ static char *remove_tail(char *path, char *pend, char *dirname) return pend; } -/// Iterate over colon-separated list +/// Iterate over a delimited list. /// /// @note Environment variables must not be modified during iteration. /// +/// @param[in] delim Delimiter character. /// @param[in] val Value of the environment variable to iterate over. /// @param[in] iter Pointer used for iteration. Must be NULL on first /// iteration. @@ -533,18 +535,19 @@ static char *remove_tail(char *path, char *pend, char *dirname) /// @param[out] len Location where current directory length should be saved. /// /// @return Next iter argument value or NULL when iteration should stop. -const void *vim_colon_env_iter(const char *const val, - const void *const iter, - const char **const dir, - size_t *const len) - FUNC_ATTR_NONNULL_ARG(1, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT +const void *vim_env_iter(const char delim, + const char *const val, + const void *const iter, + const char **const dir, + size_t *const len) + FUNC_ATTR_NONNULL_ARG(2, 4, 5) FUNC_ATTR_WARN_UNUSED_RESULT { const char *varval = (const char *) iter; if (varval == NULL) { varval = val; } *dir = varval; - const char *const dirend = strchr(varval, ':'); + const char *const dirend = strchr(varval, delim); if (dirend == NULL) { *len = strlen(varval); return NULL; @@ -554,10 +557,11 @@ const void *vim_colon_env_iter(const char *const val, } } -/// Iterate over colon-separated list in reverse order +/// Iterate over a delimited list in reverse order. /// /// @note Environment variables must not be modified during iteration. /// +/// @param[in] delim Delimiter character. /// @param[in] val Value of the environment variable to iterate over. /// @param[in] iter Pointer used for iteration. Must be NULL on first /// iteration. @@ -566,18 +570,19 @@ const void *vim_colon_env_iter(const char *const val, /// @param[out] len Location where current directory length should be saved. /// /// @return Next iter argument value or NULL when iteration should stop. -const void *vim_colon_env_iter_rev(const char *const val, - const void *const iter, - const char **const dir, - size_t *const len) - FUNC_ATTR_NONNULL_ARG(1, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT +const void *vim_env_iter_rev(const char delim, + const char *const val, + const void *const iter, + const char **const dir, + size_t *const len) + FUNC_ATTR_NONNULL_ARG(2, 4, 5) FUNC_ATTR_WARN_UNUSED_RESULT { const char *varend = (const char *) iter; if (varend == NULL) { varend = val + strlen(val) - 1; } - const size_t varlen = (size_t) (varend - val) + 1; - const char *const colon = xmemrchr(val, ':', varlen); + const size_t varlen = (size_t)(varend - val) + 1; + const char *const colon = xmemrchr(val, (uint8_t)delim, varlen); if (colon == NULL) { *len = varlen; *dir = val; @@ -596,6 +601,9 @@ const void *vim_colon_env_iter_rev(const char *const val, /// @param name Environment variable to expand char *vim_getenv(const char *name) { + // init_path() should have been called before now. + assert(get_vim_var_str(VV_PROGPATH)[0] != NUL); + const char *kos_env_path = os_getenv(name); if (kos_env_path != NULL) { return xstrdup(kos_env_path); @@ -634,18 +642,17 @@ char *vim_getenv(const char *name) char exe_name[MAXPATHL]; // Find runtime path relative to the nvim binary: ../share/nvim/runtime if (vim_path == NULL) { - size_t exe_name_len = MAXPATHL; - if (os_exepath(exe_name, &exe_name_len) == 0) { - char *path_end = (char *)path_tail_with_sep((char_u *)exe_name); - *path_end = '\0'; // remove the trailing "nvim.exe" - path_end = (char *)path_tail((char_u *)exe_name); - *path_end = '\0'; // remove the trailing "bin/" - if (append_path( - exe_name, - "share" _PATHSEPSTR "nvim" _PATHSEPSTR "runtime" _PATHSEPSTR, - MAXPATHL) == OK) { - vim_path = exe_name; - } + xstrlcpy(exe_name, (char *)get_vim_var_str(VV_PROGPATH), + sizeof(exe_name)); + char *path_end = (char *)path_tail_with_sep((char_u *)exe_name); + *path_end = '\0'; // remove the trailing "nvim.exe" + path_end = (char *)path_tail((char_u *)exe_name); + *path_end = '\0'; // remove the trailing "bin/" + if (append_path( + exe_name, + "share" _PATHSEPSTR "nvim" _PATHSEPSTR "runtime" _PATHSEPSTR, + MAXPATHL) == OK) { + vim_path = exe_name; // -V507 } } @@ -678,6 +685,7 @@ char *vim_getenv(const char *name) vim_path = NULL; } } + assert(vim_path != exe_name); } #ifdef HAVE_PATHDEF @@ -712,108 +720,123 @@ char *vim_getenv(const char *name) /// Replace home directory by "~" in each space or comma separated file name in /// 'src'. +/// +/// Replace home directory with tilde in each file name +/// /// If anything fails (except when out of space) dst equals src. -/// @param buf When not NULL, check for help files -/// @param src Input file name -/// @param dst Where to put the result -/// @param dstlen Maximum length of the result -/// @param one If true, only replace one file name, including spaces and commas -/// in the file name -void home_replace(const buf_T *const buf, const char_u *src, - char_u *dst, size_t dstlen, bool one) +/// +/// @param[in] buf When not NULL, uses this buffer to check whether it is +/// a help file. If it is then path to file is removed +/// completely, `one` is ignored and assumed to be true. +/// @param[in] src Input file names. Assumed to be a space/comma separated +/// list unless `one` is true. +/// @param[out] dst Where to put the result. +/// @param[in] dstlen Destination length. +/// @param[in] one If true, assumes source is a single file name and not +/// a list of them. +/// +/// @return length of the string put into dst, does not include NUL byte. +size_t home_replace(const buf_T *const buf, const char_u *src, + char_u *const dst, size_t dstlen, const bool one) + FUNC_ATTR_NONNULL_ARG(3) { - size_t dirlen = 0, envlen = 0; - size_t len; + size_t dirlen = 0; + size_t envlen = 0; if (src == NULL) { *dst = NUL; - return; + return 0; } - /* - * If the file is a help file, remove the path completely. - */ if (buf != NULL && buf->b_help) { - xstrlcpy((char *)dst, (char *)path_tail(src), dstlen); - return; + const size_t dlen = xstrlcpy((char *)dst, (char *)path_tail(src), dstlen); + return MIN(dlen, dstlen - 1); } - /* - * We check both the value of the $HOME environment variable and the - * "real" home directory. - */ - if (homedir != NULL) - dirlen = STRLEN(homedir); + // We check both the value of the $HOME environment variable and the + // "real" home directory. + if (homedir != NULL) { + dirlen = strlen(homedir); + } - char_u *homedir_env = (char_u *)os_getenv("HOME"); + const char *const homedir_env = os_getenv("HOME"); + char *homedir_env_mod = (char *)homedir_env; bool must_free = false; - if (homedir_env != NULL && vim_strchr(homedir_env, '~') != NULL) { + if (homedir_env_mod != NULL && strchr(homedir_env_mod, '~') != NULL) { must_free = true; size_t usedlen = 0; - size_t flen = STRLEN(homedir_env); + size_t flen = strlen(homedir_env_mod); char_u *fbuf = NULL; - (void)modify_fname((char_u *)":p", &usedlen, &homedir_env, &fbuf, &flen); - flen = STRLEN(homedir_env); - if (flen > 0 && vim_ispathsep(homedir_env[flen - 1])) - /* Remove the trailing / that is added to a directory. */ - homedir_env[flen - 1] = NUL; + (void)modify_fname((char_u *)":p", &usedlen, (char_u **)&homedir_env_mod, + &fbuf, &flen); + flen = strlen(homedir_env_mod); + assert(homedir_env_mod != homedir_env); + if (vim_ispathsep(homedir_env_mod[flen - 1])) { + // Remove the trailing / that is added to a directory. + homedir_env_mod[flen - 1] = NUL; + } } - if (homedir_env != NULL) - envlen = STRLEN(homedir_env); + if (homedir_env_mod != NULL) { + envlen = strlen(homedir_env_mod); + } - if (!one) + if (!one) { src = skipwhite(src); + } + char *dst_p = (char *)dst; while (*src && dstlen > 0) { - /* - * Here we are at the beginning of a file name. - * First, check to see if the beginning of the file name matches - * $HOME or the "real" home directory. Check that there is a '/' - * after the match (so that if e.g. the file is "/home/pieter/bla", - * and the home directory is "/home/piet", the file does not end up - * as "~er/bla" (which would seem to indicate the file "bla" in user - * er's home directory)). - */ - char_u *p = homedir; - len = dirlen; - for (;; ) { - if ( len - && fnamencmp(src, p, len) == 0 - && (vim_ispathsep(src[len]) - || (!one && (src[len] == ',' || src[len] == ' ')) - || src[len] == NUL)) { + // Here we are at the beginning of a file name. + // First, check to see if the beginning of the file name matches + // $HOME or the "real" home directory. Check that there is a '/' + // after the match (so that if e.g. the file is "/home/pieter/bla", + // and the home directory is "/home/piet", the file does not end up + // as "~er/bla" (which would seem to indicate the file "bla" in user + // er's home directory)). + char *p = homedir; + size_t len = dirlen; + for (;;) { + if (len + && fnamencmp(src, (char_u *)p, len) == 0 + && (vim_ispathsep(src[len]) + || (!one && (src[len] == ',' || src[len] == ' ')) + || src[len] == NUL)) { src += len; - if (--dstlen > 0) - *dst++ = '~'; - - /* - * If it's just the home directory, add "/". - */ - if (!vim_ispathsep(src[0]) && --dstlen > 0) - *dst++ = '/'; + if (--dstlen > 0) { + *dst_p++ = '~'; + } + + // If it's just the home directory, add "/". + if (!vim_ispathsep(src[0]) && --dstlen > 0) { + *dst_p++ = '/'; + } break; } - if (p == homedir_env) + if (p == homedir_env_mod) { break; - p = homedir_env; + } + p = homedir_env_mod; len = envlen; } - /* if (!one) skip to separator: space or comma */ - while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0) - *dst++ = *src++; - /* skip separator */ - while ((*src == ' ' || *src == ',') && --dstlen > 0) - *dst++ = *src++; + // if (!one) skip to separator: space or comma. + while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0) { + *dst_p++ = (char)(*src++); + } + // Skip separator. + while ((*src == ' ' || *src == ',') && --dstlen > 0) { + *dst_p++ = (char)(*src++); + } } - /* if (dstlen == 0) out of space, what to do??? */ + // If (dstlen == 0) out of space, what to do??? - *dst = NUL; + *dst_p = NUL; if (must_free) { - xfree(homedir_env); + xfree(homedir_env_mod); } + return (size_t)(dst_p - (char *)dst); } /// Like home_replace, store the replaced string in allocated memory. @@ -879,8 +902,8 @@ bool os_setenv_append_path(const char *fname) // No prescribed maximum on unix. # define MAX_ENVPATHLEN INT_MAX #endif - if (!path_is_absolute_path((char_u *)fname)) { - EMSG2(_(e_intern2), "os_setenv_append_path()"); + if (!path_is_absolute((char_u *)fname)) { + internal_error("os_setenv_append_path()"); return false; } const char *tail = (char *)path_tail_with_sep((char_u *)fname); @@ -914,8 +937,36 @@ bool os_term_is_nice(void) return true; #else const char *vte_version = os_getenv("VTE_VERSION"); - return (vte_version && atoi(vte_version) >= 3900) - || NULL != os_getenv("KONSOLE_PROFILE_NAME") - || NULL != os_getenv("KONSOLE_DBUS_SESSION"); + if ((vte_version && atoi(vte_version) >= 3900) + || os_getenv("KONSOLE_PROFILE_NAME") + || os_getenv("KONSOLE_DBUS_SESSION")) { + return true; + } + const char *termprg = os_getenv("TERM_PROGRAM"); + if (termprg && striequal(termprg, "iTerm.app")) { + return true; + } + const char *term = os_getenv("TERM"); + if (term && strncmp(term, "rxvt", 4) == 0) { + return true; + } + return false; #endif } + +/// Returns true if `sh` looks like it resolves to "cmd.exe". +bool os_shell_is_cmdexe(const char *sh) + FUNC_ATTR_NONNULL_ALL +{ + if (*sh == NUL) { + return false; + } + if (striequal(sh, "$COMSPEC")) { + const char *comspec = os_getenv("COMSPEC"); + return striequal("cmd.exe", (char *)path_tail((char_u *)comspec)); + } + if (striequal(sh, "cmd.exe") || striequal(sh, "cmd")) { + return true; + } + return striequal("cmd.exe", (char *)path_tail((char_u *)sh)); +} |
