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)); +} | 
