diff options
Diffstat (limited to 'src/nvim/os')
-rw-r--r-- | src/nvim/os/dl.c | 3 | ||||
-rw-r--r-- | src/nvim/os/env.c | 162 | ||||
-rw-r--r-- | src/nvim/os/fileio.c | 45 | ||||
-rw-r--r-- | src/nvim/os/fileio.h | 5 | ||||
-rw-r--r-- | src/nvim/os/fs.c | 149 | ||||
-rw-r--r-- | src/nvim/os/fs.h | 4 | ||||
-rw-r--r-- | src/nvim/os/input.c | 113 | ||||
-rw-r--r-- | src/nvim/os/input.h | 2 | ||||
-rw-r--r-- | src/nvim/os/lang.c | 10 | ||||
-rw-r--r-- | src/nvim/os/mem.c | 1 | ||||
-rw-r--r-- | src/nvim/os/nvim.manifest | 20 | ||||
-rw-r--r-- | src/nvim/os/os_defs.h | 4 | ||||
-rw-r--r-- | src/nvim/os/os_win_console.c | 64 | ||||
-rw-r--r-- | src/nvim/os/process.c | 45 | ||||
-rw-r--r-- | src/nvim/os/pty_conpty_win.c | 4 | ||||
-rw-r--r-- | src/nvim/os/pty_conpty_win.h | 2 | ||||
-rw-r--r-- | src/nvim/os/pty_process.h | 2 | ||||
-rw-r--r-- | src/nvim/os/pty_process_unix.c | 39 | ||||
-rw-r--r-- | src/nvim/os/pty_process_unix.h | 2 | ||||
-rw-r--r-- | src/nvim/os/shell.c | 159 | ||||
-rw-r--r-- | src/nvim/os/signal.c | 13 | ||||
-rw-r--r-- | src/nvim/os/stdpaths.c | 14 | ||||
-rw-r--r-- | src/nvim/os/time.c | 48 | ||||
-rw-r--r-- | src/nvim/os/tty.c | 6 | ||||
-rw-r--r-- | src/nvim/os/unix_defs.h | 3 | ||||
-rw-r--r-- | src/nvim/os/users.c | 22 | ||||
-rw-r--r-- | src/nvim/os/win_defs.h | 2 |
27 files changed, 604 insertions, 339 deletions
diff --git a/src/nvim/os/dl.c b/src/nvim/os/dl.c index 7d095d31e3..519cef7876 100644 --- a/src/nvim/os/dl.c +++ b/src/nvim/os/dl.c @@ -4,13 +4,14 @@ /// Functions for using external native libraries #include <stdbool.h> +#include <stddef.h> #include <stdint.h> #include <uv.h> +#include "nvim/gettext.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/os/dl.h" -#include "nvim/os/os.h" /// possible function prototypes that can be called by os_libcall() /// int -> int diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 795bff66cb..0611de14aa 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -4,23 +4,36 @@ // Environment inspection #include <assert.h> +#include <limits.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> #include <uv.h> +#include "auto/config.h" #include "nvim/ascii.h" +#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/eval.h" +#include "nvim/ex_cmds_defs.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" +#include "nvim/log.h" #include "nvim/macros.h" #include "nvim/map.h" #include "nvim/memory.h" #include "nvim/message.h" +#include "nvim/option_defs.h" #include "nvim/os/os.h" #include "nvim/path.h" #include "nvim/strings.h" +#include "nvim/types.h" #include "nvim/version.h" #include "nvim/vim.h" -#ifdef WIN32 +#ifdef MSWIN # include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8 #endif @@ -128,7 +141,7 @@ int os_setenv(const char *name, const char *value, int overwrite) if (name[0] == '\0') { return -1; } -#ifdef WIN32 +#ifdef MSWIN if (!overwrite && os_getenv(name) != NULL) { return 0; } @@ -143,7 +156,7 @@ int os_setenv(const char *name, const char *value, int overwrite) #endif uv_mutex_lock(&mutex); int r; -#ifdef WIN32 +#ifdef MSWIN // libintl uses getenv() for LC_ALL/LANG/etc., so we must use _putenv_s(). if (striequal(name, "LC_ALL") || striequal(name, "LANGUAGE") || striequal(name, "LANG") || striequal(name, "LC_MESSAGES")) { @@ -186,7 +199,7 @@ int os_unsetenv(const char *name) size_t os_get_fullenv_size(void) { size_t len = 0; -#ifdef _WIN32 +#ifdef MSWIN wchar_t *envstrings = GetEnvironmentStringsW(); wchar_t *p = envstrings; size_t l; @@ -235,7 +248,7 @@ void os_free_fullenv(char **env) /// @param env_size size of `env`, @see os_fullenv_size void os_copy_fullenv(char **env, size_t env_size) { -#ifdef _WIN32 +#ifdef MSWIN wchar_t *envstrings = GetEnvironmentStringsW(); if (!envstrings) { return; @@ -280,7 +293,7 @@ void os_copy_fullenv(char **env, size_t env_size) /// @return [allocated] environment variable's value, or NULL char *os_getenvname_at_index(size_t index) { -#ifdef _WIN32 +#ifdef MSWIN wchar_t *envstrings = GetEnvironmentStringsW(); if (!envstrings) { return NULL; @@ -347,7 +360,7 @@ char *os_getenvname_at_index(size_t index) /// @return the process ID. int64_t os_get_pid(void) { -#ifdef _WIN32 +#ifdef MSWIN return (int64_t)GetCurrentProcessId(); #else return (int64_t)getpid(); @@ -368,7 +381,7 @@ void os_get_hostname(char *hostname, size_t size) } else { xstrlcpy(hostname, vutsname.nodename, size); } -#elif defined(WIN32) +#elif defined(MSWIN) wchar_t host_utf16[MAX_COMPUTERNAME_LENGTH + 1]; DWORD host_wsize = sizeof(host_utf16) / sizeof(host_utf16[0]); if (GetComputerNameW(host_utf16, &host_wsize) == 0) { @@ -418,7 +431,7 @@ void init_homedir(void) const char *var = os_getenv("HOME"); -#ifdef WIN32 +#ifdef MSWIN // Typically, $HOME is not defined on Windows, unless the user has // specifically defined it for Vim's sake. However, on Windows NT // platforms, $HOMEDRIVE and $HOMEPATH are automatically defined for @@ -451,7 +464,7 @@ void init_homedir(void) var = NULL; const char *exp = os_getenv(os_buf); if (exp != NULL && *exp != NUL - && STRLEN(exp) + STRLEN(p) < MAXPATHL) { + && strlen(exp) + strlen(p) < MAXPATHL) { vim_snprintf(os_buf, MAXPATHL, "%s%s", exp, p + 1); var = os_buf; } @@ -475,7 +488,7 @@ void init_homedir(void) if (var != NULL) { // Change to the directory and get the actual path. This resolves // links. Don't do it when we can't return. - if (os_dirname((char_u *)os_buf, MAXPATHL) == OK && os_chdir(os_buf) == 0) { + if (os_dirname(os_buf, MAXPATHL) == OK && os_chdir(os_buf) == 0) { if (!os_chdir(var) && os_dirname(IObuff, IOSIZE) == OK) { var = (char *)IObuff; } @@ -487,7 +500,7 @@ void init_homedir(void) // Fall back to current working directory if home is not found if ((var == NULL || *var == NUL) - && os_dirname((char_u *)os_buf, sizeof(os_buf)) == OK) { + && os_dirname(os_buf, sizeof(os_buf)) == OK) { var = os_buf; } #endif @@ -530,7 +543,7 @@ void free_homedir(void) /// @see {expand_env} char *expand_env_save(char *src) { - return (char *)expand_env_save_opt((char_u *)src, false); + return expand_env_save_opt(src, false); } /// Similar to expand_env_save() but when "one" is `true` handle the string as @@ -538,9 +551,9 @@ char *expand_env_save(char *src) /// @param src String containing environment variables to expand /// @param one Should treat as only one file name /// @see {expand_env} -char_u *expand_env_save_opt(char_u *src, bool one) +char *expand_env_save_opt(char *src, bool one) { - char_u *p = xmalloc(MAXPATHL); + char *p = xmalloc(MAXPATHL); expand_env_esc(src, p, MAXPATHL, false, one, NULL); return p; } @@ -553,7 +566,7 @@ char_u *expand_env_save_opt(char_u *src, bool one) /// @param src Input string e.g. "$HOME/vim.hlp" /// @param dst[out] Where to put the result /// @param dstlen Maximum length of the result -void expand_env(char_u *src, char_u *dst, int dstlen) +void expand_env(char *src, char *dst, int dstlen) { expand_env_esc(src, dst, dstlen, false, false, NULL); } @@ -567,34 +580,34 @@ void expand_env(char_u *src, char_u *dst, int dstlen) /// @param esc Escape spaces in expanded variables /// @param one `srcp` is a single filename /// @param prefix Start again after this (can be NULL) -void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, bool esc, bool one, - char_u *prefix) +void expand_env_esc(char *restrict srcp, char *restrict dst, int dstlen, bool esc, bool one, + char *prefix) FUNC_ATTR_NONNULL_ARG(1, 2) { - char_u *tail; - char_u *var; + char *tail; + char *var; bool copy_char; bool mustfree; // var was allocated, need to free it later bool at_start = true; // at start of a name - int prefix_len = (prefix == NULL) ? 0 : (int)STRLEN(prefix); + int prefix_len = (prefix == NULL) ? 0 : (int)strlen(prefix); - char *src = skipwhite((char *)srcp); + char *src = skipwhite(srcp); dstlen--; // leave one char space for "\," while (*src && dstlen > 0) { // Skip over `=expr`. if (src[0] == '`' && src[1] == '=') { - var = (char_u *)src; + var = src; src += 2; (void)skip_expr(&src); if (*src == '`') { src++; } - size_t len = (size_t)(src - (char *)var); + size_t len = (size_t)(src - var); if (len > (size_t)dstlen) { len = (size_t)dstlen; } - memcpy((char *)dst, (char *)var, len); + memcpy(dst, var, len); dst += len; dstlen -= (int)len; continue; @@ -607,7 +620,7 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo // The variable name is copied into dst temporarily, because it may // be a string in read-only memory and a NUL needs to be appended. if (*src != '~') { // environment var - tail = (char_u *)src + 1; + tail = src + 1; var = dst; int c = dstlen - 1; @@ -621,7 +634,7 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo } else // NOLINT #endif { - while (c-- > 0 && *tail != NUL && vim_isIDc(*tail)) { + while (c-- > 0 && *tail != NUL && vim_isIDc((uint8_t)(*tail))) { *var++ = *tail++; } } @@ -636,25 +649,25 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo } #endif *var = NUL; - var = (char_u *)vim_getenv((char *)dst); + var = vim_getenv(dst); mustfree = true; #if defined(UNIX) } #endif } else if (src[1] == NUL // home directory || vim_ispathsep(src[1]) - || vim_strchr(" ,\t\n", src[1]) != NULL) { - var = (char_u *)homedir; - tail = (char_u *)src + 1; + || vim_strchr(" ,\t\n", (uint8_t)src[1]) != NULL) { + var = homedir; + tail = src + 1; } else { // user directory #if defined(UNIX) // Copy ~user to dst[], so we can put a NUL after it. - tail = (char_u *)src; + tail = src; var = dst; int c = dstlen - 1; while (c-- > 0 && *tail - && vim_isfilec(*tail) + && vim_isfilec((uint8_t)(*tail)) && !vim_ispathsep(*tail)) { *var++ = *tail++; } @@ -662,7 +675,7 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo // Get the user directory. If this fails the shell is used to expand // ~user, which is slower and may fail on old versions of /bin/sh. var = (*dst == NUL) ? NULL - : (char_u *)os_get_userdir((char *)dst + 1); + : os_get_userdir(dst + 1); mustfree = true; if (var == NULL) { expand_T xpc; @@ -676,7 +689,7 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo #else // cannot expand user's home directory, so don't try var = NULL; - tail = (char_u *)""; // for gcc + tail = ""; // for gcc #endif // UNIX } @@ -684,7 +697,7 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo // If 'shellslash' is set change backslashes to forward slashes. // Can't use slash_adjust(), p_ssl may be set temporarily. if (p_ssl && var != NULL && vim_strchr(var, '\\') != NULL) { - char_u *p = vim_strsave(var); + char *p = xstrdup(var); if (mustfree) { xfree(var); @@ -697,8 +710,8 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo // If "var" contains white space, escape it with a backslash. // Required for ":e ~/tt" when $HOME includes a space. - if (esc && var != NULL && strpbrk((char *)var, " \t") != NULL) { - char_u *p = vim_strsave_escaped(var, (char_u *)" \t"); + if (esc && var != NULL && strpbrk(var, " \t") != NULL) { + char *p = vim_strsave_escaped(var, " \t"); if (mustfree) { xfree(var); @@ -708,13 +721,13 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo } if (var != NULL && *var != NUL - && (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen)) { + && (strlen(var) + strlen(tail) + 1 < (unsigned)dstlen)) { STRCPY(dst, var); - dstlen -= (int)STRLEN(var); - int c = (int)STRLEN(var); + dstlen -= (int)strlen(var); + int c = (int)strlen(var); // if var[] ends in a path separator and tail[] starts // with it, skip a character - if (after_pathsep((char *)dst, (char *)dst + c) + if (after_pathsep(dst, dst + c) #if defined(BACKSLASH_IN_FILENAME) && dst[-1] != ':' #endif @@ -722,7 +735,7 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo tail++; } dst += c; - src = (char *)tail; + src = tail; copy_char = false; } if (mustfree) { @@ -736,18 +749,18 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo // ":edit foo ~ foo". at_start = false; if (src[0] == '\\' && src[1] != NUL) { - *dst++ = (char_u)(*src++); + *dst++ = *src++; dstlen--; } else if ((src[0] == ' ' || src[0] == ',') && !one) { at_start = true; } if (dstlen > 0) { - *dst++ = (char_u)(*src++); + *dst++ = *src++; dstlen--; if (prefix != NULL - && src - prefix_len >= (char *)srcp - && STRNCMP(src - prefix_len, prefix, prefix_len) == 0) { + && src - prefix_len >= srcp + && strncmp(src - prefix_len, prefix, (size_t)prefix_len) == 0) { at_start = true; } } @@ -765,12 +778,12 @@ static char *vim_version_dir(const char *vimdir) return NULL; } char *p = concat_fnames(vimdir, VIM_VERSION_NODOT, true); - if (os_isdir((char_u *)p)) { + if (os_isdir(p)) { return p; } xfree(p); p = concat_fnames(vimdir, RUNTIME_DIRNAME, true); - if (os_isdir((char_u *)p)) { + if (os_isdir(p)) { return p; } xfree(p); @@ -800,11 +813,11 @@ static char *vim_version_dir(const char *vimdir) /// @return The new pend including dirname or just pend static char *remove_tail(char *path, char *pend, char *dirname) { - size_t len = STRLEN(dirname); + size_t len = strlen(dirname); char *new_tail = pend - len - 1; if (new_tail >= path - && FNAMENCMP((char_u *)new_tail, (char_u *)dirname, len) == 0 + && path_fnamencmp(new_tail, dirname, len) == 0 && (new_tail == path || after_pathsep(path, new_tail))) { return new_tail; } @@ -837,10 +850,9 @@ const void *vim_env_iter(const char delim, const char *const val, const void *co if (dirend == NULL) { *len = strlen(varval); return NULL; - } else { - *len = (size_t)(dirend - varval); - return dirend + 1; } + *len = (size_t)(dirend - varval); + return dirend + 1; } /// Iterates $PATH-like delimited list `val` in reverse order. @@ -870,11 +882,10 @@ const void *vim_env_iter_rev(const char delim, const char *const val, const void *len = varlen; *dir = val; return NULL; - } else { - *dir = colon + 1; - *len = (size_t)(varend - colon); - return colon - 1; } + *dir = colon + 1; + *len = (size_t)(varend - colon); + return colon - 1; } /// @param[out] exe_name should be at least MAXPATHL in size @@ -900,7 +911,7 @@ char *vim_getenv(const char *name) // init_path() should have been called before now. assert(get_vim_var_str(VV_PROGPATH)[0] != NUL); -#ifdef WIN32 +#ifdef MSWIN if (strcmp(name, "HOME") == 0) { return xstrdup(homedir); } @@ -937,8 +948,8 @@ char *vim_getenv(const char *name) // - the directory name from 'helpfile' (unless it contains '$') // - the executable name from argv[0] if (vim_path == NULL) { - if (p_hf != NULL && vim_strchr((char *)p_hf, '$') == NULL) { - vim_path = (char *)p_hf; + if (p_hf != NULL && vim_strchr(p_hf, '$') == NULL) { + vim_path = p_hf; } char exe_name[MAXPATHL]; @@ -957,7 +968,7 @@ char *vim_getenv(const char *name) char *vim_path_end = path_tail(vim_path); // remove "doc/" from 'helpfile', if present - if (vim_path == (char *)p_hf) { + if (vim_path == p_hf) { vim_path_end = remove_tail(vim_path, vim_path_end, "doc"); } @@ -976,7 +987,7 @@ char *vim_getenv(const char *name) assert(vim_path_end >= vim_path); vim_path = xstrndup(vim_path, (size_t)(vim_path_end - vim_path)); - if (!os_isdir((char_u *)vim_path)) { + if (!os_isdir(vim_path)) { xfree(vim_path); vim_path = NULL; } @@ -1045,7 +1056,7 @@ size_t home_replace(const buf_T *const buf, const char *src, char *const dst, si } if (buf != NULL && buf->b_help) { - const size_t dlen = STRLCPY(dst, path_tail((char *)src), dstlen); + const size_t dlen = xstrlcpy(dst, path_tail((char *)src), dstlen); return MIN(dlen, dstlen - 1); } @@ -1056,7 +1067,7 @@ size_t home_replace(const buf_T *const buf, const char *src, char *const dst, si } const char *homedir_env = os_getenv("HOME"); -#ifdef WIN32 +#ifdef MSWIN if (homedir_env == NULL) { homedir_env = os_getenv("USERPROFILE"); } @@ -1098,7 +1109,7 @@ size_t home_replace(const buf_T *const buf, const char *src, char *const dst, si size_t len = dirlen; for (;;) { if (len - && FNAMENCMP(src, (char_u *)p, len) == 0 + && path_fnamencmp(src, p, len) == 0 && (vim_ispathsep(src[len]) || (!one && (src[len] == ',' || src[len] == ' ')) || src[len] == NUL)) { @@ -1119,10 +1130,16 @@ size_t home_replace(const buf_T *const buf, const char *src, char *const dst, si len = envlen; } + if (dstlen == 0) { + break; // Avoid overflowing below. + } // if (!one) skip to separator: space or comma. while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0) { *dst_p++ = *src++; } + if (dstlen == 0) { + break; // Avoid overflowing below. + } // Skip separator. while ((*src == ' ' || *src == ',') && --dstlen > 0) { *dst_p++ = *src++; @@ -1146,7 +1163,7 @@ char *home_replace_save(buf_T *buf, const char *src) { size_t len = 3; // space for "~/" and trailing NUL if (src != NULL) { // just in case - len += STRLEN(src); + len += strlen(src); } char *dst = xmalloc(len); home_replace(buf, src, dst, len, true); @@ -1156,15 +1173,12 @@ char *home_replace_save(buf_T *buf, const char *src) /// Function given to ExpandGeneric() to obtain an environment variable name. char *get_env_name(expand_T *xp, int idx) { -#define ENVNAMELEN 100 - // this static buffer is needed to avoid a memory leak in ExpandGeneric - static char_u name[ENVNAMELEN]; assert(idx >= 0); char *envname = os_getenvname_at_index((size_t)idx); if (envname) { - STRLCPY(name, envname, ENVNAMELEN); + xstrlcpy(xp->xp_buf, envname, EXPAND_BUF_LEN); xfree(envname); - return (char *)name; + return xp->xp_buf; } return NULL; } @@ -1177,14 +1191,14 @@ char *get_env_name(expand_T *xp, int idx) bool os_setenv_append_path(const char *fname) FUNC_ATTR_NONNULL_ALL { -#ifdef WIN32 +#ifdef MSWIN // 8191 (plus NUL) is considered the practical maximum. # define MAX_ENVPATHLEN 8192 #else // No prescribed maximum on unix. # define MAX_ENVPATHLEN INT_MAX #endif - if (!path_is_absolute((char_u *)fname)) { + if (!path_is_absolute(fname)) { internal_error("os_setenv_append_path()"); return false; } diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index b1710737d0..5af39555c9 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -11,22 +11,21 @@ #include <fcntl.h> #include <stdbool.h> #include <stddef.h> - -#include "auto/config.h" - -#ifdef HAVE_SYS_UIO_H -# include <sys/uio.h> -#endif - +#include <stdint.h> #include <uv.h> +#include "auto/config.h" +#include "nvim/gettext.h" #include "nvim/globals.h" +#include "nvim/log.h" #include "nvim/macros.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/os/fileio.h" #include "nvim/os/os.h" +#include "nvim/os/os_defs.h" #include "nvim/rbuffer.h" +#include "nvim/types.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/fileio.c.generated.h" @@ -71,6 +70,7 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname, const int f FLAG(flags, kFileReadOnly, O_RDONLY, kFalse, wr != kTrue); #ifdef O_NOFOLLOW FLAG(flags, kFileNoSymlink, O_NOFOLLOW, kNone, true); + FLAG(flags, kFileMkDir, O_CREAT|O_WRONLY, kTrue, !(flags & kFileCreateOnly)); #endif #undef FLAG // wr is used for kFileReadOnly flag, but on @@ -78,6 +78,13 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname, const int f // `error: variable ‘wr’ set but not used [-Werror=unused-but-set-variable]` (void)wr; + if (flags & kFileMkDir) { + int mkdir_ret = os_file_mkdir((char *)fname, 0755); + if (mkdir_ret < 0) { + return mkdir_ret; + } + } + const int fd = os_open(fname, os_open_flags, mode); if (fd < 0) { @@ -162,6 +169,30 @@ FileDescriptor *file_open_fd_new(int *const error, const int fd, const int flags return fp; } +/// Opens standard input as a FileDescriptor. +FileDescriptor *file_open_stdin(void) + FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT +{ + int error; + int stdin_dup_fd; + if (stdin_fd > 0) { + stdin_dup_fd = stdin_fd; + } else { + stdin_dup_fd = os_dup(STDIN_FILENO); +#ifdef MSWIN + // Replace the original stdin with the console input handle. + os_replace_stdin_to_conin(); +#endif + } + FileDescriptor *const stdin_dup = file_open_fd_new(&error, stdin_dup_fd, + kFileReadOnly|kFileNonBlocking); + assert(stdin_dup != NULL); + if (error != 0) { + ELOG("failed to open stdin: %s", os_strerror(error)); + } + return stdin_dup; +} + /// Close file and free its buffer /// /// @param[in,out] fp File to close. diff --git a/src/nvim/os/fileio.h b/src/nvim/os/fileio.h index 426dc422c2..5e47bbf921 100644 --- a/src/nvim/os/fileio.h +++ b/src/nvim/os/fileio.h @@ -35,9 +35,10 @@ typedef enum { ///< be used with kFileCreateOnly. kFileNonBlocking = 128, ///< Do not restart read() or write() syscall if ///< EAGAIN was encountered. + kFileMkDir = 256, } FileOpenFlags; -static inline bool file_eof(const FileDescriptor *const fp) +static inline bool file_eof(const FileDescriptor *fp) REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; /// Check whether end of file was encountered @@ -51,7 +52,7 @@ static inline bool file_eof(const FileDescriptor *const fp) return fp->eof && rbuffer_size(fp->rv) == 0; } -static inline int file_fd(const FileDescriptor *const fp) +static inline int file_fd(const FileDescriptor *fp) REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL; /// Return the file descriptor associated with the FileDescriptor structure diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 0d62a5f5f9..302faa8140 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -5,11 +5,23 @@ #include <assert.h> #include <errno.h> #include <fcntl.h> -#include <limits.h> #include <stdbool.h> #include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> #include "auto/config.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" +#include "nvim/log.h" +#include "nvim/macros.h" +#include "nvim/option_defs.h" +#include "nvim/os/fs_defs.h" +#include "nvim/types.h" +#include "nvim/vim.h" #ifdef HAVE_SYS_UIO_H # include <sys/uio.h> @@ -18,16 +30,14 @@ #include <uv.h> #include "nvim/ascii.h" -#include "nvim/assert.h" #include "nvim/memory.h" #include "nvim/message.h" -#include "nvim/option.h" #include "nvim/os/os.h" -#include "nvim/os/os_defs.h" #include "nvim/path.h" -#include "nvim/strings.h" -#ifdef WIN32 +struct iovec; + +#ifdef MSWIN # include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8 #endif @@ -95,12 +105,12 @@ int os_chdir(const char *path) /// @param buf Buffer to store the directory name. /// @param len Length of `buf`. /// @return `OK` for success, `FAIL` for failure. -int os_dirname(char_u *buf, size_t len) +int os_dirname(char *buf, size_t len) FUNC_ATTR_NONNULL_ALL { int error_number; - if ((error_number = uv_cwd((char *)buf, &len)) != kLibuvSuccess) { - STRLCPY(buf, uv_strerror(error_number), len); + if ((error_number = uv_cwd(buf, &len)) != kLibuvSuccess) { + xstrlcpy(buf, uv_strerror(error_number), len); return FAIL; } return OK; @@ -121,18 +131,17 @@ bool os_isrealdir(const char *name) fs_loop_unlock(); if (S_ISLNK(request.statbuf.st_mode)) { return false; - } else { - return S_ISDIR(request.statbuf.st_mode); } + return S_ISDIR(request.statbuf.st_mode); } /// Check if the given path exists and is a directory. /// /// @return `true` if `name` is a directory. -bool os_isdir(const char_u *name) +bool os_isdir(const char *name) FUNC_ATTR_NONNULL_ALL { - int32_t mode = os_getperm((const char *)name); + int32_t mode = os_getperm(name); if (mode < 0) { return false; } @@ -151,7 +160,7 @@ bool os_isdir(const char_u *name) int os_nodetype(const char *name) FUNC_ATTR_NONNULL_ALL { -#ifndef WIN32 // Unix +#ifndef MSWIN // Unix uv_stat_t statbuf; if (0 != os_stat(name, &statbuf)) { return NODE_NORMAL; // File doesn't exist. @@ -171,7 +180,7 @@ int os_nodetype(const char *name) // Edge case from Vim os_win32.c: // We can't open a file with a name "\\.\con" or "\\.\prn", trying to read // from it later will cause Vim to hang. Thus return NODE_WRITABLE here. - if (STRNCMP(name, "\\\\.\\", 4) == 0) { + if (strncmp(name, "\\\\.\\", 4) == 0) { return NODE_WRITABLE; } @@ -241,7 +250,7 @@ bool os_can_exe(const char *name, char **abspath, bool use_path) FUNC_ATTR_NONNULL_ARG(1) { if (!use_path || gettail_dir(name) != name) { -#ifdef WIN32 +#ifdef MSWIN if (is_executable_ext(name, abspath)) { #else // Must have path separator, cannot execute files in the current directory. @@ -249,9 +258,8 @@ bool os_can_exe(const char *name, char **abspath, bool use_path) && is_executable(name, abspath)) { #endif return true; - } else { - return false; } + return false; } return is_executable_in_path(name, abspath); @@ -270,7 +278,7 @@ static bool is_executable(const char *name, char **abspath) return false; } -#ifdef WIN32 +#ifdef MSWIN // Windows does not have exec bit; just check if the file exists and is not // a directory. const bool ok = S_ISREG(mode); @@ -287,14 +295,16 @@ static bool is_executable(const char *name, char **abspath) return ok; } -#ifdef WIN32 +#ifdef MSWIN /// Checks if file `name` is executable under any of these conditions: /// - extension is in $PATHEXT and `name` is executable /// - result of any $PATHEXT extension appended to `name` is executable static bool is_executable_ext(const char *name, char **abspath) FUNC_ATTR_NONNULL_ARG(1) { - const bool is_unix_shell = strstr((char *)path_tail(p_sh), "sh") != NULL; + const bool is_unix_shell = strstr(path_tail(p_sh), "powershell") == NULL + && strstr(path_tail(p_sh), "pwsh") == NULL + && strstr(path_tail(p_sh), "sh") != NULL; char *nameext = strrchr(name, '.'); size_t nameext_len = nameext ? strlen(nameext) : 0; xstrlcpy(os_buf, name, sizeof(os_buf)); @@ -320,11 +330,11 @@ static bool is_executable_ext(const char *name, char **abspath) const char *ext_end = ext; size_t ext_len = - copy_option_part(&ext_end, (char_u *)buf_end, + copy_option_part((char **)&ext_end, buf_end, sizeof(os_buf) - (size_t)(buf_end - os_buf), ENV_SEPSTR); if (ext_len != 0) { bool in_pathext = nameext_len == ext_len - && 0 == mb_strnicmp((char_u *)nameext, (char_u *)ext, ext_len); + && 0 == mb_strnicmp(nameext, ext, ext_len); if (((in_pathext || is_unix_shell) && is_executable(name, abspath)) || is_executable(os_buf, abspath)) { @@ -351,7 +361,7 @@ static bool is_executable_in_path(const char *name, char **abspath) return false; } -#ifdef WIN32 +#ifdef MSWIN // Prepend ".;" to $PATH. size_t pathlen = strlen(path_env); char *path = memcpy(xmallocz(pathlen + 2), "." ENV_SEPSTR, 2); @@ -371,10 +381,10 @@ static bool is_executable_in_path(const char *name, char **abspath) char *e = xstrchrnul(p, ENV_SEPCHAR); // Combine the $PATH segment with `name`. - STRLCPY(buf, p, e - p + 1); + xstrlcpy(buf, p, (size_t)(e - p) + 1); append_path(buf, name, buf_len); -#ifdef WIN32 +#ifdef MSWIN if (is_executable_ext(buf, abspath)) { #else if (is_executable(buf, abspath)) { @@ -446,7 +456,7 @@ FILE *os_fopen(const char *path, const char *flags) default: abort(); } -#ifdef WIN32 +#ifdef MSWIN if (flags[1] == 'b') { iflags |= O_BINARY; } @@ -756,9 +766,8 @@ int32_t os_getperm(const char *name) int stat_result = os_stat(name, &statbuf); if (stat_result == kLibuvSuccess) { return (int32_t)statbuf.st_mode; - } else { - return stat_result; } + return stat_result; } /// Set the permission of a file. @@ -772,6 +781,38 @@ int os_setperm(const char *const name, int perm) return (r == kLibuvSuccess ? OK : FAIL); } +#if defined(HAVE_ACL) +# ifdef HAVE_SYS_ACL_H +# include <sys/acl.h> +# endif +# ifdef HAVE_SYS_ACCESS_H +# include <sys/access.h> +# endif + +// Return a pointer to the ACL of file "fname" in allocated memory. +// Return NULL if the ACL is not available for whatever reason. +vim_acl_T os_get_acl(const char *fname) +{ + vim_acl_T ret = NULL; + return ret; +} + +// Set the ACL of file "fname" to "acl" (unless it's NULL). +void os_set_acl(const char *fname, vim_acl_T aclent) +{ + if (aclent == NULL) { + return; + } +} + +void os_free_acl(vim_acl_T aclent) +{ + if (aclent == NULL) { + return; + } +} +#endif + #ifdef UNIX /// Checks if the current user owns a file. /// @@ -821,10 +862,10 @@ int os_fchown(int fd, uv_uid_t owner, uv_gid_t group) /// Check if a path exists. /// /// @return `true` if `path` exists -bool os_path_exists(const char_u *path) +bool os_path_exists(const char *path) { uv_stat_t statbuf; - return os_stat((char *)path, &statbuf) == kLibuvSuccess; + return os_stat(path, &statbuf) == kLibuvSuccess; } /// Sets file access and modification times. @@ -865,7 +906,7 @@ int os_file_is_writable(const char *name) int r; RUN_UV_FS_FUNC(r, uv_fs_access, name, W_OK, NULL); if (r == 0) { - return os_isdir((char_u *)name) ? 2 : 1; + return os_isdir(name) ? 2 : 1; } return 0; } @@ -873,12 +914,11 @@ int os_file_is_writable(const char *name) /// Rename a file or directory. /// /// @return `OK` for success, `FAIL` for failure. -int os_rename(const char_u *path, const char_u *new_path) +int os_rename(const char *path, const char *new_path) FUNC_ATTR_NONNULL_ALL { int r; - RUN_UV_FS_FUNC(r, uv_fs_rename, (const char *)path, (const char *)new_path, - NULL); + RUN_UV_FS_FUNC(r, uv_fs_rename, path, new_path, NULL); return (r == kLibuvSuccess ? OK : FAIL); } @@ -911,11 +951,11 @@ int os_mkdir_recurse(const char *const dir, int32_t mode, char **const failed_di // We're done when it's "/" or "c:/". const size_t dirlen = strlen(dir); char *const curdir = xmemdupz(dir, dirlen); - char *const past_head = (char *)get_past_head((char_u *)curdir); + char *const past_head = get_past_head(curdir); char *e = curdir + dirlen; const char *const real_end = e; const char past_head_save = *past_head; - while (!os_isdir((char_u *)curdir)) { + while (!os_isdir(curdir)) { e = path_tail_with_sep(curdir); if (e <= past_head) { *past_head = NUL; @@ -946,6 +986,37 @@ int os_mkdir_recurse(const char *const dir, int32_t mode, char **const failed_di return 0; } +/// Create the parent directory of a file if it does not exist +/// +/// @param[in] fname Full path of the file name whose parent directories +/// we want to create +/// @param[in] mode Permissions for the newly-created directory. +/// +/// @return `0` for success, libuv error code for failure. +int os_file_mkdir(char *fname, int32_t mode) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (!dir_of_file_exists(fname)) { + char *tail = path_tail_with_sep(fname); + char *last_char = tail + strlen(tail) - 1; + if (vim_ispathsep(*last_char)) { + emsg(_(e_noname)); + return -1; + } + char c = *tail; + *tail = NUL; + int r; + char *failed_dir; + if (((r = os_mkdir_recurse(fname, mode, &failed_dir)) < 0)) { + semsg(_(e_mkdir), failed_dir, os_strerror(r)); + xfree(failed_dir); + } + *tail = c; + return r; + } + return 0; +} + /// Create a unique temporary directory. /// /// @param[in] template Template of the path to the directory with XXXXXX @@ -1208,7 +1279,7 @@ char *os_realpath(const char *name, char *buf) return result == kLibuvSuccess ? buf : NULL; } -#ifdef WIN32 +#ifdef MSWIN # include <shlobj.h> /// When "fname" is the name of a shortcut (*.lnk) resolve the file it points @@ -1310,7 +1381,7 @@ bool os_is_reparse_point_include(const char *path) } p = utf16_path; - if (isalpha(p[0]) && p[1] == L':' && IS_PATH_SEP(p[2])) { + if (isalpha((uint8_t)p[0]) && p[1] == L':' && IS_PATH_SEP(p[2])) { p += 3; } else if (IS_PATH_SEP(p[0]) && IS_PATH_SEP(p[1])) { p += 2; diff --git a/src/nvim/os/fs.h b/src/nvim/os/fs.h index c68081da02..75c24b8db2 100644 --- a/src/nvim/os/fs.h +++ b/src/nvim/os/fs.h @@ -1,8 +1,8 @@ #ifndef NVIM_OS_FS_H #define NVIM_OS_FS_H -#include "nvim/os/fs_defs.h" // for uv_* -#include "nvim/types.h" // for char_u +#include "nvim/os/fs_defs.h" +#include "nvim/types.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/fs.h.generated.h" diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index bfe6d59dc6..759b3cf83c 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -3,25 +3,33 @@ #include <assert.h> #include <stdbool.h> +#include <stdint.h> +#include <stdio.h> #include <string.h> #include <uv.h> #include "nvim/api/private/defs.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" +#include "nvim/buffer_defs.h" #include "nvim/event/loop.h" +#include "nvim/event/multiqueue.h" #include "nvim/event/rstream.h" +#include "nvim/event/stream.h" #include "nvim/getchar.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" #include "nvim/keycodes.h" +#include "nvim/log.h" +#include "nvim/macros.h" #include "nvim/main.h" -#include "nvim/mbyte.h" -#include "nvim/memory.h" #include "nvim/msgpack_rpc/channel.h" +#include "nvim/option_defs.h" #include "nvim/os/input.h" +#include "nvim/os/time.h" #include "nvim/profile.h" -#include "nvim/screen.h" +#include "nvim/rbuffer.h" #include "nvim/state.h" -#include "nvim/ui.h" #include "nvim/vim.h" #define READ_BUFFER_SIZE 0xfff @@ -36,8 +44,9 @@ typedef enum { static Stream read_stream = { .closed = true }; // Input before UI starts. static RBuffer *input_buffer = NULL; static bool input_eof = false; -static int global_fd = -1; static bool blocking = false; +static int cursorhold_time = 0; ///< time waiting for CursorHold event +static int cursorhold_tb_change_cnt = 0; ///< tb_change_cnt when waiting started #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/input.c.generated.h" @@ -48,25 +57,14 @@ void input_init(void) input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN); } -void input_global_fd_init(int fd) -{ - global_fd = fd; -} - -/// Global TTY (or pipe for "-es") input stream, before UI starts. -int input_global_fd(void) -{ - return global_fd; -} - -void input_start(int fd) +void input_start(void) { if (!read_stream.closed) { return; } - input_global_fd_init(fd); - rstream_init_fd(&main_loop, &read_stream, fd, READ_BUFFER_SIZE); + used_stdin = true; + rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO, READ_BUFFER_SIZE); rstream_start(&read_stream, input_read_cb, NULL); } @@ -97,13 +95,25 @@ static void create_cursorhold_event(bool events_enabled) multiqueue_put(main_loop.events, cursorhold_event, 0); } +static void restart_cursorhold_wait(int tb_change_cnt) +{ + cursorhold_time = 0; + cursorhold_tb_change_cnt = tb_change_cnt; +} + /// Low level input function /// /// wait until either the input buffer is non-empty or, if `events` is not NULL /// until `events` is non-empty. int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events) { + // This check is needed so that feeding typeahead from RPC can prevent CursorHold. + if (tb_change_cnt != cursorhold_tb_change_cnt) { + restart_cursorhold_wait(tb_change_cnt); + } + if (maxlen && rbuffer_size(input_buffer)) { + restart_cursorhold_wait(tb_change_cnt); return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); } @@ -118,18 +128,22 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e return 0; } } else { - if ((result = inbuf_poll((int)p_ut, events)) == kInputNone) { + uint64_t wait_start = os_hrtime(); + cursorhold_time = MIN(cursorhold_time, (int)p_ut); + if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kInputNone) { if (read_stream.closed && silent_mode) { // Drained eventloop & initial input; exit silent/batch-mode (-es/-Es). read_error_exit(); } - + restart_cursorhold_wait(tb_change_cnt); if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) { create_cursorhold_event(events == main_loop.events); } else { before_blocking(); result = inbuf_poll(-1, events); } + } else { + cursorhold_time += (int)((os_hrtime() - wait_start) / 1000000); } } @@ -141,6 +155,7 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e } if (maxlen && rbuffer_size(input_buffer)) { + restart_cursorhold_wait(tb_change_cnt); // Safe to convert rbuffer_read to int, it will never overflow since we use // relatively small buffers. return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); @@ -239,7 +254,8 @@ size_t input_enqueue(String keys) uint8_t buf[19] = { 0 }; // Do not simplify the keys here. Simplification will be done later. unsigned int new_size - = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, FSK_KEYCODE, true, NULL); + = trans_special((const char **)&ptr, (size_t)(end - ptr), (char *)buf, FSK_KEYCODE, true, + NULL); if (new_size) { new_size = handle_mouse_event(&ptr, buf, new_size); @@ -287,36 +303,35 @@ static uint8_t check_multiclick(int code, int grid, int row, int col) static int orig_mouse_row = 0; static uint64_t orig_mouse_time = 0; // time of previous mouse click - if (code == KE_LEFTRELEASE - || code == KE_RIGHTRELEASE - || code == KE_MIDDLERELEASE - || code == KE_MOUSEDOWN - || code == KE_MOUSEUP - || code == KE_MOUSELEFT - || code == KE_MOUSERIGHT) { + if ((code >= KE_MOUSEDOWN && code <= KE_MOUSERIGHT) || code == KE_MOUSEMOVE) { return 0; } - uint64_t mouse_time = os_hrtime(); // time of current mouse click (ns) - - // compute the time elapsed since the previous mouse click and - // convert p_mouse from ms to ns - uint64_t timediff = mouse_time - orig_mouse_time; - uint64_t mouset = (uint64_t)p_mouset * 1000000; - if (code == orig_mouse_code - && timediff < mouset - && orig_num_clicks != 4 - && orig_mouse_grid == grid - && orig_mouse_col == col - && orig_mouse_row == row) { - orig_num_clicks++; - } else { - orig_num_clicks = 1; + + // For click events the number of clicks is updated. + if (code == KE_LEFTMOUSE || code == KE_RIGHTMOUSE || code == KE_MIDDLEMOUSE) { + uint64_t mouse_time = os_hrtime(); // time of current mouse click (ns) + // compute the time elapsed since the previous mouse click and + // convert p_mouse from ms to ns + uint64_t timediff = mouse_time - orig_mouse_time; + uint64_t mouset = (uint64_t)p_mouset * 1000000; + if (code == orig_mouse_code + && timediff < mouset + && orig_num_clicks != 4 + && orig_mouse_grid == grid + && orig_mouse_col == col + && orig_mouse_row == row) { + orig_num_clicks++; + } else { + orig_num_clicks = 1; + } + orig_mouse_code = code; + orig_mouse_time = mouse_time; } - orig_mouse_code = code; + // For drag and release events the number of clicks is kept. + orig_mouse_grid = grid; orig_mouse_col = col; orig_mouse_row = row; - orig_mouse_time = mouse_time; uint8_t modifiers = 0; if (orig_num_clicks == 2) { @@ -347,7 +362,8 @@ static unsigned int handle_mouse_event(char **ptr, uint8_t *buf, unsigned int bu if (type != KS_EXTRA || !((mouse_code >= KE_LEFTMOUSE && mouse_code <= KE_RIGHTRELEASE) - || (mouse_code >= KE_MOUSEDOWN && mouse_code <= KE_MOUSERIGHT))) { + || (mouse_code >= KE_MOUSEDOWN && mouse_code <= KE_MOUSERIGHT) + || mouse_code == KE_MOUSEMOVE)) { return bufsize; } @@ -450,9 +466,8 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events) if (input_ready(events)) { return kInputAvail; - } else { - return input_eof ? kInputEof : kInputNone; } + return input_eof ? kInputEof : kInputNone; } void input_done(void) diff --git a/src/nvim/os/input.h b/src/nvim/os/input.h index 7026781407..6f25efdc7b 100644 --- a/src/nvim/os/input.h +++ b/src/nvim/os/input.h @@ -7,6 +7,8 @@ #include "nvim/api/private/defs.h" #include "nvim/event/multiqueue.h" +EXTERN bool used_stdin INIT(= false); + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/input.h.generated.h" #endif diff --git a/src/nvim/os/lang.c b/src/nvim/os/lang.c index 28f43ff3af..57c82bba86 100644 --- a/src/nvim/os/lang.c +++ b/src/nvim/os/lang.c @@ -7,16 +7,16 @@ # include <CoreServices/CoreServices.h> # undef Boolean # undef FileInfo -#endif -#include "auto/config.h" +# include "auto/config.h" +# ifdef HAVE_LOCALE_H +# include <locale.h> +# endif +# include "nvim/os/os.h" -#ifdef HAVE_LOCALE_H -# include <locale.h> #endif #include "nvim/os/lang.h" -#include "nvim/os/os.h" void lang_init(void) { diff --git a/src/nvim/os/mem.c b/src/nvim/os/mem.c index eccb3c97e5..0b7e8065ef 100644 --- a/src/nvim/os/mem.c +++ b/src/nvim/os/mem.c @@ -3,6 +3,7 @@ /// Functions for accessing system memory information. +#include <stdint.h> #include <uv.h> #include "nvim/os/os.h" diff --git a/src/nvim/os/nvim.manifest b/src/nvim/os/nvim.manifest new file mode 100644 index 0000000000..8878822a5d --- /dev/null +++ b/src/nvim/os/nvim.manifest @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> + <assemblyIdentity + processorArchitecture="*" + version="0.9.0.0" + type="win32" + name="Neovim" + /> + <description>Neovim</description> + <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> + <application> + <!-- Windows 10 and Windows 11 --> + <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> + <!-- Windows 8.1 --> + <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> + <!-- Windows 8 --> + <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> + </application> + </compatibility> +</assembly> diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h index a4361859ec..a30e16eeba 100644 --- a/src/nvim/os/os_defs.h +++ b/src/nvim/os/os_defs.h @@ -7,7 +7,7 @@ #include <sys/stat.h> #include <sys/types.h> -#ifdef WIN32 +#ifdef MSWIN # include "nvim/os/win_defs.h" #else # include "nvim/os/unix_defs.h" @@ -43,7 +43,7 @@ /// Converts system error code to libuv error code. #define os_translate_sys_error uv_translate_sys_error -#ifdef WIN32 +#ifdef MSWIN # define os_strtok strtok_s #else # define os_strtok strtok_r diff --git a/src/nvim/os/os_win_console.c b/src/nvim/os/os_win_console.c index 20b7f869f1..006e27d28f 100644 --- a/src/nvim/os/os_win_console.c +++ b/src/nvim/os/os_win_console.c @@ -2,6 +2,7 @@ // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include "nvim/os/input.h" +#include "nvim/os/os.h" #include "nvim/os/os_win_console.h" #include "nvim/vim.h" @@ -9,7 +10,12 @@ # include "os/os_win_console.c.generated.h" #endif -int os_get_conin_fd(void) +static char origTitle[256] = { 0 }; +static HWND hWnd = NULL; +static HICON hOrigIconSmall = NULL; +static HICON hOrigIcon = NULL; + +int os_open_conin_fd(void) { const HANDLE conin_handle = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, @@ -25,7 +31,7 @@ int os_get_conin_fd(void) void os_replace_stdin_to_conin(void) { close(STDIN_FILENO); - const int conin_fd = os_get_conin_fd(); + const int conin_fd = os_open_conin_fd(); assert(conin_fd == STDIN_FILENO); } @@ -45,3 +51,57 @@ void os_replace_stdout_and_stderr_to_conout(void) const int conerr_fd = _open_osfhandle((intptr_t)conout_handle, 0); assert(conerr_fd == STDERR_FILENO); } + +/// Sets Windows console icon, or pass NULL to restore original icon. +void os_icon_set(HICON hIconSmall, HICON hIcon) +{ + if (hWnd == NULL) { + return; + } + hIconSmall = hIconSmall ? hIconSmall : hOrigIconSmall; + hIcon = hIcon ? hIcon : hOrigIcon; + + if (hIconSmall != NULL) { + SendMessage(hWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIconSmall); + } + if (hIcon != NULL) { + SendMessage(hWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon); + } +} + +/// Sets Nvim logo as Windows console icon. +/// +/// Saves the original icon so it can be restored at exit. +void os_icon_init(void) +{ + if ((hWnd = GetConsoleWindow()) == NULL) { + return; + } + // Save Windows console icon to be restored later. + hOrigIconSmall = (HICON)SendMessage(hWnd, WM_GETICON, (WPARAM)ICON_SMALL, (LPARAM)0); + hOrigIcon = (HICON)SendMessage(hWnd, WM_GETICON, (WPARAM)ICON_BIG, (LPARAM)0); + + const char *vimruntime = os_getenv("VIMRUNTIME"); + if (vimruntime != NULL) { + snprintf(NameBuff, MAXPATHL, "%s" _PATHSEPSTR "neovim.ico", vimruntime); + if (!os_path_exists(NameBuff)) { + WLOG("neovim.ico not found: %s", NameBuff); + } else { + HICON hVimIcon = LoadImage(NULL, NameBuff, IMAGE_ICON, 64, 64, + LR_LOADFROMFILE | LR_LOADMAP3DCOLORS); + os_icon_set(hVimIcon, hVimIcon); + } + } +} + +/// Saves the original Windows console title. +void os_title_save(void) +{ + GetConsoleTitle(origTitle, sizeof(origTitle)); +} + +/// Resets the original Windows console title. +void os_title_reset(void) +{ + SetConsoleTitle(origTitle); +} diff --git a/src/nvim/os/process.c b/src/nvim/os/process.c index e70bc71961..f4d95e141b 100644 --- a/src/nvim/os/process.c +++ b/src/nvim/os/process.c @@ -6,10 +6,21 @@ /// psutil is a good reference for cross-platform syscall voodoo: /// https://github.com/giampaolo/psutil/tree/master/psutil/arch -#include <uv.h> // for HANDLE (win32) +#include <assert.h> +#include <signal.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <uv.h> -#ifdef WIN32 -# include <tlhelp32.h> // for CreateToolhelp32Snapshot +#include "nvim/log.h" +#include "nvim/memory.h" +#include "nvim/os/process.h" + +#ifdef MSWIN +# include <tlhelp32.h> + +# include "nvim/api/private/helpers.h" #endif #if defined(__FreeBSD__) // XXX: OpenBSD ? @@ -27,18 +38,11 @@ # include <sys/sysctl.h> #endif -#include "nvim/api/private/helpers.h" -#include "nvim/globals.h" -#include "nvim/log.h" -#include "nvim/os/os.h" -#include "nvim/os/os_defs.h" -#include "nvim/os/process.h" - #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "os/process.c.generated.h" +# include "os/process.c.generated.h" // IWYU pragma: export #endif -#ifdef WIN32 +#ifdef MSWIN static bool os_proc_tree_kill_rec(HANDLE process, int sig) { if (process == NULL) { @@ -114,7 +118,7 @@ int os_proc_children(int ppid, int **proc_list, size_t *proc_count) *proc_list = NULL; *proc_count = 0; -#ifdef WIN32 +#ifdef MSWIN PROCESSENTRY32 pe; // Snapshot of all processes. @@ -215,7 +219,7 @@ int os_proc_children(int ppid, int **proc_list, size_t *proc_count) return 0; } -#ifdef WIN32 +#ifdef MSWIN /// Gets various properties of the process identified by `pid`. /// /// @param pid Process to inspect. @@ -260,5 +264,16 @@ Dictionary os_proc_info(int pid) /// Return true if process `pid` is running. bool os_proc_running(int pid) { - return uv_kill(pid, 0) == 0; + int err = uv_kill(pid, 0); + // If there is no error the process must be running. + if (err == 0) { + return true; + } + // If the error is ESRCH then the process is not running. + if (err == UV_ESRCH) { + return false; + } + // If the process is running and owned by another user we get EPERM. With + // other errors the process might be running, assuming it is then. + return true; } diff --git a/src/nvim/os/pty_conpty_win.c b/src/nvim/os/pty_conpty_win.c index f9478d951f..43c89f8865 100644 --- a/src/nvim/os/pty_conpty_win.c +++ b/src/nvim/os/pty_conpty_win.c @@ -67,7 +67,7 @@ conpty_t *os_conpty_init(char **in_name, char **out_name, uint16_t width, uint16 | PIPE_ACCESS_OUTBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE; sa.nLength = sizeof(sa); - snprintf(buf, sizeof(buf), "\\\\.\\pipe\\nvim-term-in-%d-%d", + snprintf(buf, sizeof(buf), "\\\\.\\pipe\\nvim-term-in-%lld-%d", os_get_pid(), count); *in_name = xstrdup(buf); if ((in_read = CreateNamedPipeA(*in_name, @@ -81,7 +81,7 @@ conpty_t *os_conpty_init(char **in_name, char **out_name, uint16_t width, uint16 emsg = "create input pipe failed"; goto failed; } - snprintf(buf, sizeof(buf), "\\\\.\\pipe\\nvim-term-out-%d-%d", + snprintf(buf, sizeof(buf), "\\\\.\\pipe\\nvim-term-out-%lld-%d", os_get_pid(), count); *out_name = xstrdup(buf); if ((out_write = CreateNamedPipeA(*out_name, diff --git a/src/nvim/os/pty_conpty_win.h b/src/nvim/os/pty_conpty_win.h index 15e7c3da0c..0c25a5970e 100644 --- a/src/nvim/os/pty_conpty_win.h +++ b/src/nvim/os/pty_conpty_win.h @@ -1,7 +1,7 @@ #ifndef NVIM_OS_PTY_CONPTY_WIN_H #define NVIM_OS_PTY_CONPTY_WIN_H -#include "nvim/lib/kvec.h" +#include "klib/kvec.h" #include "nvim/os/input.h" #ifndef HPCON diff --git a/src/nvim/os/pty_process.h b/src/nvim/os/pty_process.h index 94923499ca..07d346be22 100644 --- a/src/nvim/os/pty_process.h +++ b/src/nvim/os/pty_process.h @@ -1,7 +1,7 @@ #ifndef NVIM_OS_PTY_PROCESS_H #define NVIM_OS_PTY_PROCESS_H -#ifdef WIN32 +#ifdef MSWIN # include "nvim/os/pty_process_win.h" #else # include "nvim/os/pty_process_unix.h" diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index c5d6af0ff6..2413f0339b 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -2,13 +2,15 @@ // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com // Some of the code came from pangoterm and libuv -#include <stdbool.h> + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> -#include <sys/types.h> #include <sys/wait.h> -#include <termios.h> // forkpty is not in POSIX, so headers are platform-specific #if defined(__FreeBSD__) || defined(__DragonFly__) @@ -31,13 +33,16 @@ #include <uv.h> +#include "auto/config.h" +#include "klib/klist.h" +#include "nvim/eval/typval.h" #include "nvim/event/loop.h" #include "nvim/event/process.h" -#include "nvim/event/rstream.h" -#include "nvim/event/wstream.h" -#include "nvim/lib/klist.h" +#include "nvim/event/stream.h" #include "nvim/log.h" #include "nvim/os/os.h" +#include "nvim/os/os_defs.h" +#include "nvim/os/pty_process.h" #include "nvim/os/pty_process_unix.h" #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -155,31 +160,13 @@ static pid_t forkpty(int *amaster, char *name, struct termios *termp, struct win #endif -/// termios saved at startup (for TUI) or initialized by pty_process_spawn(). -static struct termios termios_default; - -/// Saves the termios properties associated with `tty_fd`. -/// -/// @param tty_fd TTY file descriptor, or -1 if not in a terminal. -void pty_process_save_termios(int tty_fd) -{ - if (tty_fd == -1) { - return; - } - int rv = tcgetattr(tty_fd, &termios_default); - if (rv != 0) { - ELOG("tcgetattr failed (tty_fd=%d): %s", tty_fd, strerror(errno)); - } else { - DLOG("tty_fd=%d", tty_fd); - } -} - /// @returns zero on success, or negative error code int pty_process_spawn(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL { + // termios initialized at first use + static struct termios termios_default; if (!termios_default.c_cflag) { - // TODO(jkeyes): We could pass NULL to forkpty() instead ... init_termios(&termios_default); } diff --git a/src/nvim/os/pty_process_unix.h b/src/nvim/os/pty_process_unix.h index 765490b92b..0cc68cf3e9 100644 --- a/src/nvim/os/pty_process_unix.h +++ b/src/nvim/os/pty_process_unix.h @@ -1,8 +1,10 @@ #ifndef NVIM_OS_PTY_PROCESS_UNIX_H #define NVIM_OS_PTY_PROCESS_UNIX_H +#include <stdint.h> #include <sys/ioctl.h> +#include "nvim/event/loop.h" #include "nvim/event/process.h" typedef struct pty_process { diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index b793b8f9c6..f1e2c5440f 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -3,30 +3,45 @@ #include <assert.h> #include <stdbool.h> -#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> #include <string.h> #include <uv.h> +#include "auto/config.h" +#include "klib/kvec.h" #include "nvim/ascii.h" +#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/eval.h" +#include "nvim/eval/typval_defs.h" #include "nvim/event/libuv_process.h" #include "nvim/event/loop.h" +#include "nvim/event/multiqueue.h" +#include "nvim/event/process.h" #include "nvim/event/rstream.h" +#include "nvim/event/stream.h" +#include "nvim/event/wstream.h" #include "nvim/ex_cmds.h" #include "nvim/fileio.h" -#include "nvim/lib/kvec.h" -#include "nvim/log.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" +#include "nvim/macros.h" #include "nvim/main.h" +#include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/option_defs.h" +#include "nvim/os/fs.h" +#include "nvim/os/os_defs.h" #include "nvim/os/shell.h" #include "nvim/os/signal.h" +#include "nvim/os/time.h" #include "nvim/path.h" +#include "nvim/pos.h" #include "nvim/profile.h" -#include "nvim/screen.h" +#include "nvim/rbuffer.h" #include "nvim/strings.h" #include "nvim/tag.h" #include "nvim/types.h" @@ -50,13 +65,13 @@ typedef struct { static void save_patterns(int num_pat, char **pat, int *num_file, char ***file) { - *file = xmalloc((size_t)num_pat * sizeof(char_u *)); + *file = xmalloc((size_t)num_pat * sizeof(char *)); for (int i = 0; i < num_pat; i++) { - char_u *s = vim_strsave((char_u *)pat[i]); + char *s = xstrdup(pat[i]); // Be compatible with expand_filename(): halve the number of // backslashes. backslash_halve(s); - (*file)[i] = (char *)s; + (*file)[i] = s; } *num_file = num_pat; } @@ -64,7 +79,7 @@ static void save_patterns(int num_pat, char **pat, int *num_file, char ***file) static bool have_wildcard(int num, char **file) { for (int i = 0; i < num; i++) { - if (path_has_wildcard((char_u *)file[i])) { + if (path_has_wildcard(file[i])) { return true; } } @@ -74,7 +89,7 @@ static bool have_wildcard(int num, char **file) static bool have_dollars(int num, char **file) { for (int i = 0; i < num; i++) { - if (vim_strchr((char *)file[i], '$') != NULL) { + if (vim_strchr(file[i], '$') != NULL) { return true; } } @@ -105,15 +120,15 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in { int i; size_t len; - char_u *p; + char *p; bool dir; - char_u *extra_shell_arg = NULL; + char *extra_shell_arg = NULL; ShellOpts shellopts = kShellOptExpand | kShellOptSilent; int j; - char_u *tempname; - char_u *command; + char *tempname; + char *command; FILE *fd; - char_u *buffer; + char *buffer; #define STYLE_ECHO 0 // use "echo", the default #define STYLE_GLOB 1 // use "glob", for csh #define STYLE_VIMGLOB 2 // use "vimglob", for Posix sh @@ -129,7 +144,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in bool is_fish_shell = #if defined(UNIX) - STRNCMP(invocation_path_tail(p_sh, NULL), "fish", 4) == 0; + strncmp((char *)invocation_path_tail(p_sh, NULL), "fish", 4) == 0; #else false; #endif @@ -178,27 +193,27 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in // STYLE_ECHO: space separated. // A shell we don't know, stay safe and use "echo". if (num_pat == 1 && *pat[0] == '`' - && (len = STRLEN(pat[0])) > 2 + && (len = strlen(pat[0])) > 2 && *(pat[0] + len - 1) == '`') { shell_style = STYLE_BT; - } else if ((len = STRLEN(p_sh)) >= 3) { - if (STRCMP(p_sh + len - 3, "csh") == 0) { + } else if ((len = strlen(p_sh)) >= 3) { + if (strcmp(p_sh + len - 3, "csh") == 0) { shell_style = STYLE_GLOB; - } else if (STRCMP(p_sh + len - 3, "zsh") == 0) { + } else if (strcmp(p_sh + len - 3, "zsh") == 0) { shell_style = STYLE_PRINT; } } if (shell_style == STYLE_ECHO - && strstr(path_tail((char *)p_sh), "sh") != NULL) { + && strstr(path_tail(p_sh), "sh") != NULL) { shell_style = STYLE_VIMGLOB; } // Compute the length of the command. We need 2 extra bytes: for the // optional '&' and for the NUL. // Worst case: "unset nonomatch; print -N >" plus two is 29 - len = STRLEN(tempname) + 29; + len = strlen(tempname) + 29; if (shell_style == STYLE_VIMGLOB) { - len += STRLEN(sh_vimglob_func); + len += strlen(sh_vimglob_func); } for (i = 0; i < num_pat; i++) { @@ -206,7 +221,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in // "command" below. len++; // add space for (j = 0; pat[i][j] != NUL; j++) { - if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL) { + if (vim_strchr(SHELL_SPECIAL, (uint8_t)pat[i][j]) != NULL) { len++; // may add a backslash } len++; @@ -233,7 +248,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in STRCPY(command, "("); } STRCAT(command, pat[0] + 1); // exclude first backtick - p = command + STRLEN(command) - 1; + p = command + strlen(command) - 1; if (is_fish_shell) { *p-- = ';'; STRCAT(command, " end"); @@ -279,7 +294,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in // characters, except inside ``. bool intick = false; - p = command + STRLEN(command); + p = command + strlen(command); *p++ = ' '; for (j = 0; pat[i][j] != NUL; j++) { if (pat[i][j] == '`') { @@ -289,14 +304,14 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in // backslash inside backticks, before a special character // and before a backtick. if (intick - || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL + || vim_strchr(SHELL_SPECIAL, (uint8_t)pat[i][j + 1]) != NULL || pat[i][j + 1] == '`') { *p++ = '\\'; } j++; } else if (!intick && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$') - && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL) { + && vim_strchr(SHELL_SPECIAL, (uint8_t)pat[i][j]) != NULL) { // Put a backslash before a special character, but not // when inside ``. And not for $var when EW_KEEPDOLLAR is // set. @@ -304,7 +319,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in } // Copy one character. - *p++ = (char_u)pat[i][j]; + *p++ = pat[i][j]; } *p = NUL; } @@ -322,13 +337,13 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in // the argument list, otherwise zsh gives an error message and doesn't // expand any other pattern. if (shell_style == STYLE_PRINT) { - extra_shell_arg = (char_u *)"-G"; // Use zsh NULL_GLOB option + extra_shell_arg = "-G"; // Use zsh NULL_GLOB option // If we use -f then shell variables set in .cshrc won't get expanded. // vi can do it, so we will too, but it is only necessary if there is a "$" // in one of the patterns, otherwise we can still use the fast option. } else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat)) { - extra_shell_arg = (char_u *)"-f"; // Use csh fast option + extra_shell_arg = "-f"; // Use csh fast option } // execute the shell command @@ -343,7 +358,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in xfree(command); if (i) { // os_call_shell() failed - os_remove((char *)tempname); + os_remove(tempname); xfree(tempname); // With interactive completion, the error message is not printed. if (!(flags & EW_SILENT)) { @@ -362,7 +377,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in } // read the names from the file into memory - fd = fopen((char *)tempname, READBIN); + fd = fopen(tempname, READBIN); if (fd == NULL) { // Something went wrong, perhaps a file name with a special char. if (!(flags & EW_SILENT)) { @@ -392,9 +407,9 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in buffer = xmalloc(len + 1); // fread() doesn't terminate buffer with NUL; // appropriate termination (not always NUL) is done below. - size_t readlen = fread((char *)buffer, 1, len, fd); + size_t readlen = fread(buffer, 1, len, fd); fclose(fd); - os_remove((char *)tempname); + os_remove(tempname); if (readlen != len) { // unexpected read error semsg(_(e_notread), tempname); @@ -412,7 +427,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in while (*p != ' ' && *p != '\n') { p++; } - p = (char_u *)skipwhite((char *)p); // skip to next entry + p = skipwhite(p); // skip to next entry } // file names are separated with NL } else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB) { @@ -425,7 +440,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in if (*p != NUL) { p++; } - p = (char_u *)skipwhite((char *)p); // skip leading white space + p = skipwhite(p); // skip leading white space } // file names are separated with NUL } else { @@ -439,7 +454,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in if (shell_style == STYLE_PRINT && !did_find_nul) { // If there is a NUL, set did_find_nul, else set check_spaces buffer[len] = NUL; - if (len && (int)STRLEN(buffer) < (int)len) { + if (len && (int)strlen(buffer) < (int)len) { did_find_nul = true; } else { check_spaces = true; @@ -473,12 +488,12 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in goto notfound; } *num_file = i; - *file = xmalloc(sizeof(char_u *) * (size_t)i); + *file = xmalloc(sizeof(char *) * (size_t)i); // Isolate the individual file names. p = buffer; for (i = 0; i < *num_file; i++) { - (*file)[i] = (char *)p; + (*file)[i] = p; // Space or NL separates if (shell_style == STYLE_ECHO || shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB) { @@ -490,7 +505,7 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in *p = NUL; } else { *p++ = NUL; - p = (char_u *)skipwhite((char *)p); // skip to next entry + p = skipwhite(p); // skip to next entry } } else { // NUL separates while (*p && p < buffer + len) { // skip entry @@ -503,12 +518,12 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in // Move the file names to allocated memory. for (j = 0, i = 0; i < *num_file; i++) { // Require the files to exist. Helps when using /bin/sh - if (!(flags & EW_NOTFOUND) && !os_path_exists((char_u *)(*file)[i])) { + if (!(flags & EW_NOTFOUND) && !os_path_exists((*file)[i])) { continue; } // check if this entry should be included - dir = (os_isdir((char_u *)(*file)[i])); + dir = (os_isdir((*file)[i])); if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE))) { continue; } @@ -519,12 +534,12 @@ int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, in continue; } - p = xmalloc(STRLEN((*file)[i]) + 1 + dir); + p = xmalloc(strlen((*file)[i]) + 1 + dir); STRCPY(p, (*file)[i]); if (dir) { - add_pathsep((char *)p); // add '/' to a directory name + add_pathsep(p); // add '/' to a directory name } - (*file)[j++] = (char *)p; + (*file)[j++] = p; } xfree(buffer); *num_file = j; @@ -638,7 +653,7 @@ char *shell_argv_to_str(char **const argv) /// @param extra_args Extra arguments to the shell, or NULL. /// /// @return shell command exit code -int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args) +int os_call_shell(char *cmd, ShellOpts opts, char *extra_args) { DynamicBuffer input = DYNAMIC_BUFFER_INIT; char *output = NULL, **output_ptr = NULL; @@ -667,7 +682,7 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args) } size_t nread; - int exitcode = do_os_system(shell_build_argv((char *)cmd, (char *)extra_args), + int exitcode = do_os_system(shell_build_argv(cmd, extra_args), input.data, input.len, output_ptr, &nread, emsg_silent, forward_output); xfree(input.data); @@ -693,7 +708,7 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args) /// Invalidates cached tags. /// /// @return shell command exit code -int call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg) +int call_shell(char *cmd, ShellOpts opts, char *extra_shell_arg) { int retval; proftime_T wait_time; @@ -737,23 +752,23 @@ int call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg) /// @param ret_len length of the stdout /// /// @return an allocated string, or NULL for error. -char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags, size_t *ret_len) +char *get_cmd_output(char *cmd, char *infile, ShellOpts flags, size_t *ret_len) { - char_u *buffer = NULL; + char *buffer = NULL; if (check_secure()) { return NULL; } // get a name for the temp file - char_u *tempname = vim_tempname(); + char *tempname = vim_tempname(); if (tempname == NULL) { emsg(_(e_notmp)); return NULL; } // Add the redirection stuff - char_u *command = (char_u *)make_filter_cmd((char *)cmd, (char *)infile, (char *)tempname); + char *command = make_filter_cmd(cmd, infile, tempname); // Call the shell to execute the command (errors are ignored). // Don't check timestamps here. @@ -764,7 +779,7 @@ char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags, size_t *ret xfree(command); // read the names from the file into memory - FILE *fd = os_fopen((char *)tempname, READBIN); + FILE *fd = os_fopen(tempname, READBIN); if (fd == NULL) { semsg(_(e_notopen), tempname); @@ -776,9 +791,9 @@ char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags, size_t *ret fseek(fd, 0L, SEEK_SET); buffer = xmalloc(len + 1); - size_t i = fread((char *)buffer, 1, len, fd); + size_t i = fread(buffer, 1, len, fd); fclose(fd); - os_remove((char *)tempname); + os_remove(tempname); if (i != len) { semsg(_(e_notread), tempname); XFREE_CLEAR(buffer); @@ -805,7 +820,7 @@ done: /// char *output = NULL; /// size_t nread = 0; /// char *argv[] = {"ls", "-la", NULL}; -/// int exitcode = os_sytem(argv, NULL, 0, &output, &nread); +/// int exitcode = os_system(argv, NULL, 0, &output, &nread); /// /// @param argv The commandline arguments to be passed to the shell. `argv` /// will be consumed. @@ -911,7 +926,7 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu out_data_ring(NULL, SIZE_MAX); } if (forward_output) { - // caller should decide if wait_return is invoked + // caller should decide if wait_return() is invoked no_wait_return++; msg_end(); no_wait_return--; @@ -1106,13 +1121,13 @@ static void out_data_append_to_screen(char *output, size_t *count, bool eof) // incomplete UTF-8 sequence that could be composing with the last // complete sequence. // This will be corrected when we switch to vterm based implementation - int i = *p ? utfc_ptr2len_len((char_u *)p, (int)(end - p)) : 1; + int i = *p ? utfc_ptr2len_len(p, (int)(end - p)) : 1; if (!eof && i == 1 && utf8len_tab_zero[*(uint8_t *)p] > (end - p)) { *count = (size_t)(p - output); goto end; } - (void)msg_outtrans_len_attr((char_u *)p, i, 0); + (void)msg_outtrans_len_attr(p, i, 0); p += i; } } @@ -1150,14 +1165,14 @@ static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, /// @param argv The vector that will be filled with copies of the parsed /// words. It can be NULL if the caller only needs to count words. /// @return The number of words parsed. -static size_t tokenize(const char_u *const str, char **const argv) +static size_t tokenize(const char *const str, char **const argv) FUNC_ATTR_NONNULL_ARG(1) { size_t argc = 0; - const char *p = (const char *)str; + const char *p = str; while (*p != NUL) { - const size_t len = word_length((const char_u *)p); + const size_t len = word_length(p); if (argv != NULL) { // Fill the slot @@ -1175,9 +1190,9 @@ static size_t tokenize(const char_u *const str, char **const argv) /// /// @param str A pointer to the first character of the word /// @return The offset from `str` at which the word ends. -static size_t word_length(const char_u *str) +static size_t word_length(const char *str) { - const char_u *p = str; + const char *p = str; bool inquote = false; size_t length = 0; @@ -1208,10 +1223,10 @@ static void read_input(DynamicBuffer *buf) { size_t written = 0, l = 0, len = 0; linenr_T lnum = curbuf->b_op_start.lnum; - char_u *lp = ml_get(lnum); + char *lp = ml_get(lnum); for (;;) { - l = strlen((char *)lp + written); + l = strlen(lp + written); if (l == 0) { len = 0; } else if (lp[written] == NL) { @@ -1220,7 +1235,7 @@ static void read_input(DynamicBuffer *buf) dynamic_buffer_ensure(buf, buf->len + len); buf->data[buf->len++] = NUL; } else { - char_u *s = (char_u *)vim_strchr((char *)lp + written, NL); + char *s = vim_strchr(lp + written, NL); len = s == NULL ? l : (size_t)(s - (lp + written)); dynamic_buffer_ensure(buf, buf->len + len); memcpy(buf->data + buf->len, lp + written, len); @@ -1316,17 +1331,17 @@ static char *shell_xescape_xquote(const char *cmd) } const char *ecmd = cmd; - if (*p_sxe != NUL && STRCMP(p_sxq, "(") == 0) { - ecmd = (char *)vim_strsave_escaped_ext((char_u *)cmd, p_sxe, '^', false); + if (*p_sxe != NUL && strcmp(p_sxq, "(") == 0) { + ecmd = vim_strsave_escaped_ext(cmd, p_sxe, '^', false); } - size_t ncmd_size = strlen(ecmd) + STRLEN(p_sxq) * 2 + 1; + size_t ncmd_size = strlen(ecmd) + strlen(p_sxq) * 2 + 1; char *ncmd = xmalloc(ncmd_size); // When 'shellxquote' is ( append ). // When 'shellxquote' is "( append )". - if (STRCMP(p_sxq, "(") == 0) { + if (strcmp(p_sxq, "(") == 0) { vim_snprintf(ncmd, ncmd_size, "(%s)", ecmd); - } else if (STRCMP(p_sxq, "\"(") == 0) { + } else if (strcmp(p_sxq, "\"(") == 0) { vim_snprintf(ncmd, ncmd_size, "\"(%s)\"", ecmd); } else { vim_snprintf(ncmd, ncmd_size, "%s%s%s", p_sxq, ecmd, p_sxq); diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c index e592570966..b8daaabba2 100644 --- a/src/nvim/os/signal.c +++ b/src/nvim/os/signal.c @@ -3,23 +3,20 @@ #include <assert.h> #include <stdbool.h> -#include <uv.h> -#ifndef WIN32 +#include <stdio.h> +#ifndef MSWIN # include <signal.h> // for sigset_t #endif -#include "nvim/ascii.h" #include "nvim/autocmd.h" +#include "nvim/buffer_defs.h" #include "nvim/eval.h" -#include "nvim/event/loop.h" #include "nvim/event/signal.h" #include "nvim/globals.h" #include "nvim/log.h" #include "nvim/main.h" #include "nvim/memline.h" -#include "nvim/memory.h" #include "nvim/os/signal.h" -#include "nvim/vim.h" static SignalWatcher spipe, shup, squit, sterm, susr1, swinch; #ifdef SIGPWR @@ -34,7 +31,7 @@ static bool rejecting_deadly; void signal_init(void) { -#ifndef WIN32 +#ifndef MSWIN // Ensure a clean slate by unblocking all signals. For example, if SIGCHLD is // blocked, libuv may hang after spawning a subprocess on Linux. #5230 sigset_t mask; @@ -175,7 +172,7 @@ static void deadly_signal(int signum) ILOG("got signal %d (%s)", signum, signal_name(signum)); - snprintf((char *)IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\r\n", + snprintf(IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\r\n", signal_name(signum)); // Preserve files and exit. diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c index 59d315d44c..6b07b6ef70 100644 --- a/src/nvim/os/stdpaths.c +++ b/src/nvim/os/stdpaths.c @@ -2,6 +2,7 @@ // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include <stdbool.h> +#include <string.h> #include "nvim/ascii.h" #include "nvim/fileio.h" @@ -21,7 +22,7 @@ static const char *xdg_env_vars[] = { [kXDGDataDirs] = "XDG_DATA_DIRS", }; -#ifdef WIN32 +#ifdef MSWIN static const char *const xdg_defaults_env_vars[] = { [kXDGConfigHome] = "LOCALAPPDATA", [kXDGDataHome] = "LOCALAPPDATA", @@ -37,7 +38,7 @@ static const char *const xdg_defaults_env_vars[] = { /// /// Used in case environment variables contain nothing. Need to be expanded. static const char *const xdg_defaults[] = { -#ifdef WIN32 +#ifdef MSWIN [kXDGConfigHome] = "~\\AppData\\Local", [kXDGDataHome] = "~\\AppData\\Local", [kXDGCacheHome] = "~\\AppData\\Local\\Temp", @@ -69,7 +70,7 @@ char *stdpaths_get_xdg_var(const XDGVarType idx) const char *env_val = os_getenv(env); -#ifdef WIN32 +#ifdef MSWIN if (env_val == NULL && xdg_defaults_env_vars[idx] != NULL) { env_val = os_getenv(xdg_defaults_env_vars[idx]); } @@ -87,6 +88,9 @@ char *stdpaths_get_xdg_var(const XDGVarType idx) } else if (idx == kXDGRuntimeDir) { // Special-case: stdpath('run') is defined at startup. ret = vim_gettempdir(); + if (ret == NULL) { + ret = "/tmp/"; + } size_t len = strlen(ret); ret = xstrndup(ret, len >= 2 ? len - 1 : 0); // Trim trailing slash. } @@ -107,7 +111,7 @@ char *get_xdg_home(const XDGVarType idx) { char *dir = stdpaths_get_xdg_var(idx); if (dir) { -#if defined(WIN32) +#if defined(MSWIN) dir = concat_fnames_realloc(dir, ((idx == kXDGDataHome || idx == kXDGStateHome) ? "nvim-data" : "nvim"), @@ -117,7 +121,7 @@ char *get_xdg_home(const XDGVarType idx) #endif #ifdef BACKSLASH_IN_FILENAME - slash_adjust((char_u *)dir); + slash_adjust(dir); #endif } return dir; diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c index 396bf6986a..873302a27d 100644 --- a/src/nvim/os/time.c +++ b/src/nvim/os/time.c @@ -1,22 +1,34 @@ // 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> +#include <inttypes.h> #include <limits.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + #include <uv.h> -#include "nvim/assert.h" +#include "auto/config.h" #include "nvim/event/loop.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" +#include "nvim/log.h" +#include "nvim/macros.h" #include "nvim/main.h" +#include "nvim/memory.h" #include "nvim/os/input.h" #include "nvim/os/os.h" #include "nvim/os/time.h" +struct tm; + static uv_mutex_t delay_mutex; static uv_cond_t delay_cond; #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "os/time.c.generated.h" +# include "os/time.c.generated.h" // IWYU pragma: export #endif /// Initializes the time module @@ -67,7 +79,7 @@ void os_delay(uint64_t ms, bool ignoreinput) } LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, (int)ms, got_int); } else { - os_microdelay(ms * 1000u, ignoreinput); + os_microdelay(ms * 1000U, ignoreinput); } } @@ -80,10 +92,10 @@ void os_delay(uint64_t ms, bool ignoreinput) /// If false, waiting is aborted on any input. void os_microdelay(uint64_t us, bool ignoreinput) { - uint64_t elapsed = 0u; + uint64_t elapsed = 0U; uint64_t base = uv_hrtime(); // Convert microseconds to nanoseconds, or UINT64_MAX on overflow. - const uint64_t ns = (us < UINT64_MAX / 1000u) ? us * 1000u : UINT64_MAX; + const uint64_t ns = (us < UINT64_MAX / 1000U) ? us * 1000U : UINT64_MAX; uv_mutex_lock(&delay_mutex); @@ -92,7 +104,7 @@ void os_microdelay(uint64_t us, bool ignoreinput) // Else we check for input in ~100ms intervals. const uint64_t ns_delta = ignoreinput ? ns - elapsed - : MIN(ns - elapsed, 100000000u); // 100ms + : MIN(ns - elapsed, 100000000U); // 100ms const int rv = uv_cond_timedwait(&delay_cond, &delay_mutex, ns_delta); if (0 != rv && UV_ETIMEDOUT != rv) { @@ -167,18 +179,28 @@ struct tm *os_localtime(struct tm *result) FUNC_ATTR_NONNULL_ALL /// @param result[out] Pointer to a 'char' where the result should be placed /// @param result_len length of result buffer /// @return human-readable string of current local time -char *os_ctime_r(const time_t *restrict clock, char *restrict result, size_t result_len) +char *os_ctime_r(const time_t *restrict clock, char *restrict result, size_t result_len, + bool add_newline) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { struct tm clock_local; struct tm *clock_local_ptr = os_localtime_r(clock, &clock_local); // MSVC returns NULL for an invalid value of seconds. if (clock_local_ptr == NULL) { - xstrlcpy(result, _("(Invalid)"), result_len); + xstrlcpy(result, _("(Invalid)"), result_len - 1); } else { - strftime(result, result_len, _("%a %b %d %H:%M:%S %Y"), clock_local_ptr); + // xgettext:no-c-format + if (strftime(result, result_len - 1, _("%a %b %d %H:%M:%S %Y"), clock_local_ptr) == 0) { + // Quoting "man strftime": + // > If the length of the result string (including the terminating + // > null byte) would exceed max bytes, then strftime() returns 0, + // > and the contents of the array are undefined. + xstrlcpy(result, _("(Invalid)"), result_len - 1); + } + } + if (add_newline) { + xstrlcat(result, "\n", result_len); } - xstrlcat(result, "\n", result_len); return result; } @@ -187,11 +209,11 @@ char *os_ctime_r(const time_t *restrict clock, char *restrict result, size_t res /// @param result[out] Pointer to a 'char' where the result should be placed /// @param result_len length of result buffer /// @return human-readable string of current local time -char *os_ctime(char *result, size_t result_len) +char *os_ctime(char *result, size_t result_len, bool add_newline) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { time_t rawtime = time(NULL); - return os_ctime_r(&rawtime, result, result_len); + return os_ctime_r(&rawtime, result, result_len, add_newline); } /// Portable version of POSIX strptime() diff --git a/src/nvim/os/tty.c b/src/nvim/os/tty.c index 126b1b0044..b5124bd83a 100644 --- a/src/nvim/os/tty.c +++ b/src/nvim/os/tty.c @@ -5,14 +5,14 @@ // Terminal/console utils // -#include "nvim/os/os.h" +#include "nvim/os/os.h" // IWYU pragma: keep (Windows) #include "nvim/os/tty.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "os/tty.c.generated.h" +# include "os/tty.c.generated.h" // IWYU pragma: export #endif -#ifdef WIN32 +#ifdef MSWIN # if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) # define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 # endif diff --git a/src/nvim/os/unix_defs.h b/src/nvim/os/unix_defs.h index 4ed3b51694..8d002fc5e9 100644 --- a/src/nvim/os/unix_defs.h +++ b/src/nvim/os/unix_defs.h @@ -3,6 +3,9 @@ #include <sys/param.h> #include <unistd.h> +#if defined(HAVE_TERMIOS_H) +# include <termios.h> +#endif // POSIX.1-2008 says that NAME_MAX should be in here #include <limits.h> diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c index bd34e917b2..ef2986246b 100644 --- a/src/nvim/os/users.c +++ b/src/nvim/os/users.c @@ -3,6 +3,9 @@ // users.c -- operating system user information +#include <stdbool.h> +#include <stdio.h> +#include <string.h> #include <uv.h> #include "auto/config.h" @@ -10,11 +13,12 @@ #include "nvim/garray.h" #include "nvim/memory.h" #include "nvim/os/os.h" -#include "nvim/strings.h" +#include "nvim/types.h" +#include "nvim/vim.h" #ifdef HAVE_PWD_H # include <pwd.h> #endif -#ifdef WIN32 +#ifdef MSWIN # include <lm.h> #endif @@ -56,7 +60,7 @@ int os_get_usernames(garray_T *users) } endpwent(); } -#elif defined(WIN32) +#elif defined(MSWIN) { DWORD nusers = 0, ntotal = 0, i; PUSER_INFO_0 uinfo; @@ -93,7 +97,7 @@ int os_get_usernames(garray_T *users) for (i = 0; i < users->ga_len; i++) { char *local_user = ((char **)users->ga_data)[i]; - if (STRCMP(local_user, user_env) == 0) { + if (strcmp(local_user, user_env) == 0) { break; } } @@ -142,7 +146,7 @@ int os_get_uname(uv_uid_t uid, char *s, size_t len) if ((pw = getpwuid(uid)) != NULL // NOLINT(runtime/threadsafe_fn) && pw->pw_name != NULL && *(pw->pw_name) != NUL) { - STRLCPY(s, pw->pw_name, len); + xstrlcpy(s, pw->pw_name, len); return OK; } #endif @@ -208,17 +212,17 @@ char *get_users(expand_T *xp, int idx) /// @return 0 if name does not match any user name. /// 1 if name partially matches the beginning of a user name. /// 2 is name fully matches a user name. -int match_user(char_u *name) +int match_user(char *name) { - int n = (int)STRLEN(name); + int n = (int)strlen(name); int result = 0; init_users(); for (int i = 0; i < ga_users.ga_len; i++) { - if (STRCMP(((char_u **)ga_users.ga_data)[i], name) == 0) { + if (strcmp(((char **)ga_users.ga_data)[i], name) == 0) { return 2; // full match } - if (STRNCMP(((char_u **)ga_users.ga_data)[i], name, n) == 0) { + if (strncmp(((char **)ga_users.ga_data)[i], name, (size_t)n) == 0) { result = 1; // partial match } } diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h index 1ae86d6bbe..4f8a242a51 100644 --- a/src/nvim/os/win_defs.h +++ b/src/nvim/os/win_defs.h @@ -1,7 +1,7 @@ #ifndef NVIM_OS_WIN_DEFS_H #define NVIM_OS_WIN_DEFS_H -#ifndef WIN32 +#ifndef MSWIN # error Header must be included only when compiling for Windows. #endif |