diff options
author | Josh Rahm <rahm@google.com> | 2022-07-18 19:37:18 +0000 |
---|---|---|
committer | Josh Rahm <rahm@google.com> | 2022-07-18 19:37:18 +0000 |
commit | 308e1940dcd64aa6c344c403d4f9e0dda58d9c5c (patch) | |
tree | 35fe43e01755e0f312650667004487a44d6b7941 /src/nvim/os | |
parent | 96a00c7c588b2f38a2424aeeb4ea3581d370bf2d (diff) | |
parent | e8c94697bcbe23a5c7b07c292b90a6b70aadfa87 (diff) | |
download | rneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.tar.gz rneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.tar.bz2 rneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.zip |
Merge remote-tracking branch 'upstream/master' into rahm
Diffstat (limited to 'src/nvim/os')
-rw-r--r-- | src/nvim/os/env.c | 77 | ||||
-rw-r--r-- | src/nvim/os/fs.c | 65 | ||||
-rw-r--r-- | src/nvim/os/fs.h | 10 | ||||
-rw-r--r-- | src/nvim/os/input.c | 67 | ||||
-rw-r--r-- | src/nvim/os/lang.c | 60 | ||||
-rw-r--r-- | src/nvim/os/os.h | 3 | ||||
-rw-r--r-- | src/nvim/os/os_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/os/os_win_console.c | 1 | ||||
-rw-r--r-- | src/nvim/os/pty_process_unix.c | 32 | ||||
-rw-r--r-- | src/nvim/os/pty_process_win.c | 168 | ||||
-rw-r--r-- | src/nvim/os/pty_process_win.h | 15 | ||||
-rw-r--r-- | src/nvim/os/shell.c | 41 | ||||
-rw-r--r-- | src/nvim/os/signal.c | 32 | ||||
-rw-r--r-- | src/nvim/os/stdpaths.c | 44 | ||||
-rw-r--r-- | src/nvim/os/stdpaths_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/os/time.c | 1 | ||||
-rw-r--r-- | src/nvim/os/users.c | 35 | ||||
-rw-r--r-- | src/nvim/os/win_defs.h | 2 |
18 files changed, 306 insertions, 350 deletions
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index e9f44d2775..9c93057fe7 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -529,9 +529,9 @@ void free_homedir(void) /// again soon. /// @param src String containing environment variables to expand /// @see {expand_env} -char_u *expand_env_save(char_u *src) +char *expand_env_save(char *src) { - return expand_env_save_opt(src, false); + return (char *)expand_env_save_opt((char_u *)src, false); } /// Similar to expand_env_save() but when "one" is `true` handle the string as @@ -580,14 +580,14 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo int prefix_len = (prefix == NULL) ? 0 : (int)STRLEN(prefix); - char_u *src = skipwhite(srcp); + char_u *src = (char_u *)skipwhite((char *)srcp); dstlen--; // leave one char space for "\," while (*src && dstlen > 0) { // Skip over `=expr`. if (src[0] == '`' && src[1] == '=') { var = src; src += 2; - (void)skip_expr(&src); + (void)skip_expr((char **)&src); if (*src == '`') { src++; } @@ -644,7 +644,7 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo #endif } else if (src[1] == NUL // home directory || vim_ispathsep(src[1]) - || vim_strchr((char_u *)" ,\t\n", src[1]) != NULL) { + || vim_strchr(" ,\t\n", src[1]) != NULL) { var = (char_u *)homedir; tail = src + 1; } else { // user directory @@ -663,7 +663,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_user_directory((char *)dst + 1); + : (char_u *)os_get_userdir((char *)dst + 1); mustfree = true; if (var == NULL) { expand_T xpc; @@ -698,7 +698,7 @@ 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 && vim_strpbrk(var, (char_u *)" \t") != NULL) { + if (esc && var != NULL && strpbrk((char *)var, " \t") != NULL) { char_u *p = vim_strsave_escaped(var, (char_u *)" \t"); if (mustfree) { @@ -715,12 +715,12 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo int c = (int)STRLEN(var); // if var[] ends in a path separator and tail[] starts // with it, skip a character - if (*var != NUL && after_pathsep((char *)dst, (char *)dst + c) + if (after_pathsep((char *)dst, (char *)dst + c) #if defined(BACKSLASH_IN_FILENAME) && dst[-1] != ':' #endif && vim_ispathsep(*tail)) { - ++tail; + tail++; } dst += c; src = tail; @@ -738,7 +738,7 @@ void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, boo at_start = false; if (src[0] == '\\' && src[1] != NUL) { *dst++ = *src++; - --dstlen; + dstlen--; } else if ((src[0] == ' ' || src[0] == ',') && !one) { at_start = true; } @@ -805,7 +805,7 @@ static char *remove_tail(char *path, char *pend, char *dirname) char *new_tail = pend - len - 1; if (new_tail >= path - && fnamencmp((char_u *)new_tail, (char_u *)dirname, len) == 0 + && FNAMENCMP((char_u *)new_tail, (char_u *)dirname, len) == 0 && (new_tail == path || after_pathsep(path, new_tail))) { return new_tail; } @@ -878,17 +878,15 @@ const void *vim_env_iter_rev(const char delim, const char *const val, const void } } - /// @param[out] exe_name should be at least MAXPATHL in size void vim_get_prefix_from_exepath(char *exe_name) { // TODO(bfredl): param could have been written as "char exe_name[MAXPATHL]" // but c_grammar.lua does not recognize it (yet). - xstrlcpy(exe_name, (char *)get_vim_var_str(VV_PROGPATH), - MAXPATHL * sizeof(*exe_name)); - char *path_end = (char *)path_tail_with_sep((char_u *)exe_name); + xstrlcpy(exe_name, get_vim_var_str(VV_PROGPATH), MAXPATHL * sizeof(*exe_name)); + char *path_end = path_tail_with_sep(exe_name); *path_end = '\0'; // remove the trailing "nvim.exe" - path_end = (char *)path_tail((char_u *)exe_name); + path_end = path_tail(exe_name); *path_end = '\0'; // remove the trailing "bin/" } @@ -940,7 +938,7 @@ 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(p_hf, '$') == NULL) { + if (p_hf != NULL && vim_strchr((char *)p_hf, '$') == NULL) { vim_path = (char *)p_hf; } @@ -957,7 +955,7 @@ char *vim_getenv(const char *name) if (vim_path != NULL) { // remove the file name - char *vim_path_end = (char *)path_tail((char_u *)vim_path); + char *vim_path_end = path_tail(vim_path); // remove "doc/" from 'helpfile', if present if (vim_path == (char *)p_hf) { @@ -1035,7 +1033,7 @@ char *vim_getenv(const char *name) /// 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, +size_t home_replace(const buf_T *const buf, const char *src, char *const dst, size_t dstlen, const bool one) FUNC_ATTR_NONNULL_ARG(3) { @@ -1048,7 +1046,7 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst } if (buf != NULL && buf->b_help) { - const size_t dlen = STRLCPY(dst, path_tail(src), dstlen); + const size_t dlen = STRLCPY(dst, path_tail((char *)src), dstlen); return MIN(dlen, dstlen - 1); } @@ -1072,8 +1070,8 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst size_t usedlen = 0; size_t flen = strlen(homedir_env_mod); char_u *fbuf = NULL; - (void)modify_fname((char_u *)":p", false, &usedlen, - (char_u **)&homedir_env_mod, &fbuf, &flen); + (void)modify_fname(":p", false, &usedlen, + &homedir_env_mod, (char **)&fbuf, &flen); flen = strlen(homedir_env_mod); assert(homedir_env_mod != homedir_env); if (vim_ispathsep(homedir_env_mod[flen - 1])) { @@ -1087,9 +1085,9 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst } if (!one) { - src = skipwhite(src); + src = skipwhite((char *)src); } - char *dst_p = (char *)dst; + char *dst_p = 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 @@ -1102,7 +1100,7 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst size_t len = dirlen; for (;;) { if (len - && fnamencmp(src, (char_u *)p, len) == 0 + && FNAMENCMP(src, (char_u *)p, len) == 0 && (vim_ispathsep(src[len]) || (!one && (src[len] == ',' || src[len] == ' ')) || src[len] == NUL)) { @@ -1111,10 +1109,9 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst *dst_p++ = '~'; } - // If it's just the home directory, add "/". - if (!vim_ispathsep(src[0]) && --dstlen > 0) { - *dst_p++ = '/'; - } + // Do not add directory separator into dst, because dst is + // expected to just return the directory name without the + // directory separator '/'. break; } if (p == homedir_env_mod) { @@ -1126,11 +1123,11 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst // if (!one) skip to separator: space or comma. while (*src && (one || (*src != ',' && *src != ' ')) && --dstlen > 0) { - *dst_p++ = (char)(*src++); + *dst_p++ = *src++; } // Skip separator. while ((*src == ' ' || *src == ',') && --dstlen > 0) { - *dst_p++ = (char)(*src++); + *dst_p++ = *src++; } } // If (dstlen == 0) out of space, what to do??? @@ -1140,26 +1137,26 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst if (must_free) { xfree(homedir_env_mod); } - return (size_t)(dst_p - (char *)dst); + return (size_t)(dst_p - dst); } /// Like home_replace, store the replaced string in allocated memory. /// @param buf When not NULL, check for help files /// @param src Input file name -char_u *home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET +char *home_replace_save(buf_T *buf, char *src) + FUNC_ATTR_NONNULL_RET { size_t len = 3; // space for "~/" and trailing NUL if (src != NULL) { // just in case len += STRLEN(src); } - char_u *dst = xmalloc(len); + char *dst = xmalloc(len); home_replace(buf, src, dst, len, true); return dst; } - /// Function given to ExpandGeneric() to obtain an environment variable name. -char_u *get_env_name(expand_T *xp, int idx) +char *get_env_name(expand_T *xp, int idx) { #define ENVNAMELEN 100 // this static buffer is needed to avoid a memory leak in ExpandGeneric @@ -1169,7 +1166,7 @@ char_u *get_env_name(expand_T *xp, int idx) if (envname) { STRLCPY(name, envname, ENVNAMELEN); xfree(envname); - return name; + return (char *)name; } return NULL; } @@ -1193,7 +1190,7 @@ bool os_setenv_append_path(const char *fname) internal_error("os_setenv_append_path()"); return false; } - const char *tail = (char *)path_tail_with_sep((char_u *)fname); + const char *tail = path_tail_with_sep((char *)fname); size_t dirlen = (size_t)(tail - fname); assert(tail >= fname && dirlen + 1 < sizeof(os_buf)); xstrlcpy(os_buf, fname, dirlen + 1); @@ -1227,10 +1224,10 @@ bool os_shell_is_cmdexe(const char *sh) } if (striequal(sh, "$COMSPEC")) { const char *comspec = os_getenv("COMSPEC"); - return striequal("cmd.exe", (char *)path_tail((char_u *)comspec)); + return striequal("cmd.exe", path_tail(comspec)); } if (striequal(sh, "cmd.exe") || striequal(sh, "cmd")) { return true; } - return striequal("cmd.exe", (char *)path_tail((char_u *)sh)); + return striequal("cmd.exe", path_tail(sh)); } diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 24c7678633..901a1bc5a6 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -40,8 +40,10 @@ bool did_try_to_free = false; \ uv_call_start: {} \ uv_fs_t req; \ + fs_loop_lock(); \ ret = func(&fs_loop, &req, __VA_ARGS__); \ uv_fs_req_cleanup(&req); \ + fs_loop_unlock(); \ if (ret == UV_ENOMEM && !did_try_to_free) { \ try_to_free_memory(); \ did_try_to_free = true; \ @@ -52,14 +54,27 @@ uv_call_start: {} \ // Many fs functions from libuv return that value on success. static const int kLibuvSuccess = 0; static uv_loop_t fs_loop; - +static uv_mutex_t fs_loop_mutex; // Initialize the fs module void fs_init(void) { uv_loop_init(&fs_loop); + uv_mutex_init_recursive(&fs_loop_mutex); +} + +/// TODO(bfredl): some of these operations should +/// be possible to do the private libuv loop of the +/// thread, instead of contending the global fs loop +void fs_loop_lock(void) +{ + uv_mutex_lock(&fs_loop_mutex); } +void fs_loop_unlock(void) +{ + uv_mutex_unlock(&fs_loop_mutex); +} /// Changes the current directory to `path`. /// @@ -98,9 +113,12 @@ bool os_isrealdir(const char *name) FUNC_ATTR_NONNULL_ALL { uv_fs_t request; + fs_loop_lock(); if (uv_fs_lstat(&fs_loop, &request, name, NULL) != kLibuvSuccess) { + fs_loop_unlock(); return false; } + fs_loop_unlock(); if (S_ISLNK(request.statbuf.st_mode)) { return false; } else { @@ -108,7 +126,7 @@ bool os_isrealdir(const char *name) } } -/// Check if the given path is a directory or not. +/// Check if the given path exists and is a directory. /// /// @return `true` if `name` is a directory. bool os_isdir(const char_u *name) @@ -738,7 +756,9 @@ static int os_stat(const char *name, uv_stat_t *statbuf) return UV_EINVAL; } uv_fs_t request; + fs_loop_lock(); int result = uv_fs_stat(&fs_loop, &request, name, NULL); + fs_loop_unlock(); if (result == kLibuvSuccess) { *statbuf = request.statbuf; } @@ -771,6 +791,27 @@ int os_setperm(const char *const name, int perm) return (r == kLibuvSuccess ? OK : FAIL); } +#ifdef UNIX +/// Checks if the current user owns a file. +/// +/// Uses both uv_fs_stat() and uv_fs_lstat() via os_fileinfo() and +/// os_fileinfo_link() respectively for extra security. +bool os_file_owned(const char *fname) + FUNC_ATTR_NONNULL_ALL +{ + uid_t uid = getuid(); + FileInfo finfo; + bool file_owned = os_fileinfo(fname, &finfo) && finfo.stat.st_uid == uid; + bool link_owned = os_fileinfo_link(fname, &finfo) && finfo.stat.st_uid == uid; + return file_owned && link_owned; +} +#else +bool os_file_owned(const char *fname) +{ + return true; // TODO(justinmk): Windows. #8244 +} +#endif + /// Changes the owner and group of a file, like chown(2). /// /// @return 0 on success, or libuv error code on failure. @@ -894,7 +935,7 @@ int os_mkdir_recurse(const char *const dir, int32_t mode, char **const failed_di const char *const real_end = e; const char past_head_save = *past_head; while (!os_isdir((char_u *)curdir)) { - e = (char *)path_tail_with_sep((char_u *)curdir); + e = path_tail_with_sep(curdir); if (e <= past_head) { *past_head = NUL; break; @@ -935,9 +976,11 @@ int os_mkdtemp(const char *template, char *path) FUNC_ATTR_NONNULL_ALL { uv_fs_t request; + fs_loop_lock(); int result = uv_fs_mkdtemp(&fs_loop, &request, template, NULL); + fs_loop_unlock(); if (result == kLibuvSuccess) { - STRNCPY(path, request.path, TEMP_FILE_PATH_MAXLEN); + xstrlcpy(path, request.path, TEMP_FILE_PATH_MAXLEN); } uv_fs_req_cleanup(&request); return result; @@ -962,7 +1005,9 @@ int os_rmdir(const char *path) bool os_scandir(Directory *dir, const char *path) FUNC_ATTR_NONNULL_ALL { + fs_loop_lock(); int r = uv_fs_scandir(&fs_loop, &dir->request, path, 0, NULL); + fs_loop_unlock(); if (r < 0) { os_closedir(dir); } @@ -1023,7 +1068,9 @@ bool os_fileinfo_link(const char *path, FileInfo *file_info) return false; } uv_fs_t request; + fs_loop_lock(); bool ok = uv_fs_lstat(&fs_loop, &request, path, NULL) == kLibuvSuccess; + fs_loop_unlock(); if (ok) { file_info->stat = request.statbuf; } @@ -1041,6 +1088,7 @@ bool os_fileinfo_fd(int file_descriptor, FileInfo *file_info) { uv_fs_t request; memset(file_info, 0, sizeof(*file_info)); + fs_loop_lock(); bool ok = uv_fs_fstat(&fs_loop, &request, file_descriptor, @@ -1049,6 +1097,7 @@ bool os_fileinfo_fd(int file_descriptor, FileInfo *file_info) file_info->stat = request.statbuf; } uv_fs_req_cleanup(&request); + fs_loop_unlock(); return ok; } @@ -1165,6 +1214,7 @@ char *os_realpath(const char *name, char *buf) FUNC_ATTR_NONNULL_ARG(1) { uv_fs_t request; + fs_loop_lock(); int result = uv_fs_realpath(&fs_loop, &request, name, NULL); if (result == kLibuvSuccess) { if (buf == NULL) { @@ -1173,6 +1223,7 @@ char *os_realpath(const char *name, char *buf) xstrlcpy(buf, request.ptr, MAXPATHL + 1); } uv_fs_req_cleanup(&request); + fs_loop_unlock(); return result == kLibuvSuccess ? buf : NULL; } @@ -1261,7 +1312,7 @@ shortcut_end: return rfname; } -# define is_path_sep(c) ((c) == L'\\' || (c) == L'/') +# define IS_PATH_SEP(c) ((c) == L'\\' || (c) == L'/') /// Returns true if the path contains a reparse point (junction or symbolic /// link). Otherwise false in returned. bool os_is_reparse_point_include(const char *path) @@ -1278,9 +1329,9 @@ 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(p[0]) && p[1] == L':' && IS_PATH_SEP(p[2])) { p += 3; - } else if (is_path_sep(p[0]) && is_path_sep(p[1])) { + } 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 new file mode 100644 index 0000000000..c68081da02 --- /dev/null +++ b/src/nvim/os/fs.h @@ -0,0 +1,10 @@ +#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 + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "os/fs.h.generated.h" +#endif +#endif // NVIM_OS_FS_H diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 3790eba212..c47a891c18 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -13,12 +13,13 @@ #include "nvim/ex_cmds2.h" #include "nvim/fileio.h" #include "nvim/getchar.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/main.h" #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/os/input.h" +#include "nvim/screen.h" #include "nvim/state.h" #include "nvim/ui.h" #include "nvim/vim.h" @@ -81,7 +82,7 @@ void input_stop(void) static void cursorhold_event(void **argv) { - event_T event = State & INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD; + event_T event = State & MODE_INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD; apply_autocmds(event, NULL, NULL, false, curbuf); did_cursorhold = true; } @@ -98,7 +99,7 @@ static void create_cursorhold_event(bool events_enabled) /// Low level input function /// -/// wait until either the input buffer is non-empty or , if `events` is not NULL +/// 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) { @@ -106,6 +107,11 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); } + // No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped. + if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state()) { + ctrl_c_interrupts = false; + } + InbufPollResult result; if (ms >= 0) { if ((result = inbuf_poll(ms, events)) == kInputNone) { @@ -127,6 +133,8 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e } } + ctrl_c_interrupts = true; + // If input was put directly in typeahead buffer bail out here. if (typebuf_changed(tb_change_cnt)) { return 0; @@ -171,15 +179,7 @@ void os_breakcheck(void) return; } - int save_us = updating_screen; - // We do not want screen_resize() to redraw here. - // TODO(bfredl): we are already special casing redraw events, is this - // hack still needed? - updating_screen++; - loop_poll_events(&main_loop, 0); - - updating_screen = save_us; } #define BREAKCHECK_SKIP 1000 @@ -216,7 +216,6 @@ void veryfast_breakcheck(void) } } - /// Test whether a file descriptor refers to a terminal. /// /// @param fd File descriptor. @@ -234,13 +233,13 @@ size_t input_enqueue(String keys) while (rbuffer_space(input_buffer) >= 19 && ptr < end) { // A "<x>" form occupies at least 1 characters, and produces up // to 19 characters (1 + 5 * 3 for the char and 3 for a modifier). - // In the case of K_SPECIAL(0x80) or CSI(0x9B), 3 bytes are escaped and - // needed, but since the keys are UTF-8, so the first byte cannot be - // K_SPECIAL(0x80) or CSI(0x9B). + // In the case of K_SPECIAL(0x80), 3 bytes are escaped and needed, + // but since the keys are UTF-8, so the first byte cannot be + // K_SPECIAL(0x80). 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, true, - false); + = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, FSK_KEYCODE, true, NULL); if (new_size) { new_size = handle_mouse_event(&ptr, buf, new_size); @@ -263,12 +262,8 @@ size_t input_enqueue(String keys) continue; } - // copy the character, escaping CSI and K_SPECIAL - if ((uint8_t)*ptr == CSI) { - rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1); - rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_EXTRA }, 1); - rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_CSI }, 1); - } else if ((uint8_t)*ptr == K_SPECIAL) { + // copy the character, escaping K_SPECIAL + if ((uint8_t)(*ptr) == K_SPECIAL) { rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1); rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_SPECIAL }, 1); rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_FILLER }, 1); @@ -279,7 +274,7 @@ size_t input_enqueue(String keys) } size_t rv = (size_t)(ptr - keys.data); - process_interrupts(); + process_ctrl_c(); return rv; } @@ -292,8 +287,13 @@ 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) { + if (code == KE_LEFTRELEASE + || code == KE_RIGHTRELEASE + || code == KE_MIDDLERELEASE + || code == KE_MOUSEDOWN + || code == KE_MOUSEUP + || code == KE_MOUSELEFT + || code == KE_MOUSERIGHT) { return 0; } uint64_t mouse_time = os_hrtime(); // time of current mouse click (ns) @@ -329,7 +329,6 @@ static uint8_t check_multiclick(int code, int grid, int row, int col) return modifiers; } - // Mouse event handling code(Extract row/col if available and detect multiple // clicks) static unsigned int handle_mouse_event(char **ptr, uint8_t *buf, unsigned int bufsize) @@ -412,7 +411,7 @@ size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int co mouse_row = row; mouse_col = col; - size_t written = 3 + (size_t)(p-buf); + size_t written = 3 + (size_t)(p - buf); rbuffer_write(input_buffer, (char *)buf, written); return written; } @@ -479,15 +478,20 @@ static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, bo } } -static void process_interrupts(void) +static void process_ctrl_c(void) { - if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state()) { + if (!ctrl_c_interrupts) { return; } size_t consume_count = 0; RBUFFER_EACH_REVERSE(input_buffer, c, i) { - if ((uint8_t)c == Ctrl_C) { + if ((uint8_t)c == Ctrl_C + || ((uint8_t)c == 'C' && i >= 3 + && (uint8_t)(*rbuffer_get(input_buffer, i - 3)) == K_SPECIAL + && (uint8_t)(*rbuffer_get(input_buffer, i - 2)) == KS_MODIFIER + && (uint8_t)(*rbuffer_get(input_buffer, i - 1)) == MOD_MASK_CTRL)) { + *rbuffer_get(input_buffer, i) = Ctrl_C; got_int = true; consume_count = i; break; @@ -526,6 +530,7 @@ static bool input_ready(MultiQueue *events) // Exit because of an input read error. static void read_error_exit(void) + FUNC_ATTR_NORETURN { if (silent_mode) { // Normal way to exit for "nvim -es". getout(0); diff --git a/src/nvim/os/lang.c b/src/nvim/os/lang.c index b63faacaae..28f43ff3af 100644 --- a/src/nvim/os/lang.c +++ b/src/nvim/os/lang.c @@ -3,9 +3,10 @@ #ifdef __APPLE__ # define Boolean CFBoolean // Avoid conflict with API's Boolean -# include <CoreFoundation/CFLocale.h> -# include <CoreFoundation/CFString.h> +# define FileInfo CSFileInfo // Avoid conflict with API's Fileinfo +# include <CoreServices/CoreServices.h> # undef Boolean +# undef FileInfo #endif #include "auto/config.h" @@ -21,55 +22,24 @@ void lang_init(void) { #ifdef __APPLE__ if (os_getenv("LANG") == NULL) { - const char *lang_region = NULL; - CFTypeRef cf_lang_region = NULL; - - CFLocaleRef cf_locale = CFLocaleCopyCurrent(); - if (cf_locale) { - cf_lang_region = CFLocaleGetValue(cf_locale, kCFLocaleIdentifier); - CFRetain(cf_lang_region); - lang_region = CFStringGetCStringPtr(cf_lang_region, - kCFStringEncodingUTF8); - CFRelease(cf_locale); - } else { - // Use the primary language defined in Preferences -> Language & Region - CFArrayRef cf_langs = CFLocaleCopyPreferredLanguages(); - if (cf_langs && CFArrayGetCount(cf_langs) > 0) { - cf_lang_region = CFArrayGetValueAtIndex(cf_langs, 0); - CFRetain(cf_lang_region); - CFRelease(cf_langs); - lang_region = CFStringGetCStringPtr(cf_lang_region, - kCFStringEncodingUTF8); - } else { - ELOG("$LANG is empty and your primary language cannot be inferred."); - return; - } - } - char buf[50] = { 0 }; - bool set_lang; - if (lang_region) { - set_lang = true; - xstrlcpy(buf, lang_region, sizeof(buf)); - } else { - set_lang = CFStringGetCString(cf_lang_region, buf, 40, - kCFStringEncodingUTF8); - } - if (set_lang) { + + // $LANG is not set, either because it was unset or Nvim was started + // from the Dock. Query the system locale. + if (LocaleRefGetPartString(NULL, + kLocaleLanguageMask | kLocaleLanguageVariantMask | + kLocaleRegionMask | kLocaleRegionVariantMask, + sizeof(buf) - 10, buf) == noErr && *buf) { if (strcasestr(buf, "utf-8") == NULL) { xstrlcat(buf, ".UTF-8", sizeof(buf)); } os_setenv("LANG", buf, true); + setlocale(LC_ALL, ""); + // Make sure strtod() uses a decimal point, not a comma. + setlocale(LC_NUMERIC, "C"); + } else { + ELOG("$LANG is empty and the macOS primary language cannot be inferred."); } - CFRelease(cf_lang_region); -# ifdef HAVE_LOCALE_H - setlocale(LC_ALL, ""); - -# ifdef LC_NUMERIC - // Make sure strtod() uses a decimal point, not a comma. - setlocale(LC_NUMERIC, "C"); -# endif -# endif } #endif } diff --git a/src/nvim/os/os.h b/src/nvim/os/os.h index bff2936f8e..a7496130cc 100644 --- a/src/nvim/os/os.h +++ b/src/nvim/os/os.h @@ -16,4 +16,7 @@ # include "os/users.h.generated.h" #endif +#define ENV_LOGFILE "NVIM_LOG_FILE" +#define ENV_NVIM "NVIM" + #endif // NVIM_OS_OS_H diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h index dce4b0c187..a4361859ec 100644 --- a/src/nvim/os/os_defs.h +++ b/src/nvim/os/os_defs.h @@ -14,7 +14,7 @@ #endif #if !defined(NAME_MAX) && defined(_XOPEN_NAME_MAX) -#define NAME_MAX _XOPEN_NAME_MAX +# define NAME_MAX _XOPEN_NAME_MAX #endif #define BASENAMELEN (NAME_MAX - 5) diff --git a/src/nvim/os/os_win_console.c b/src/nvim/os/os_win_console.c index 18e2e02b81..20b7f869f1 100644 --- a/src/nvim/os/os_win_console.c +++ b/src/nvim/os/os_win_console.c @@ -9,7 +9,6 @@ # include "os/os_win_console.c.generated.h" #endif - int os_get_conin_fd(void) { const HANDLE conin_handle = CreateFile("CONIN$", diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index 3459646bad..c5d6af0ff6 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -16,11 +16,11 @@ #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) # include <util.h> #elif defined(__sun) -# include <sys/stream.h> -# include <sys/syscall.h> -# include <fcntl.h> -# include <unistd.h> -# include <signal.h> +# include <fcntl.h> +# include <signal.h> +# include <sys/stream.h> +# include <sys/syscall.h> +# include <unistd.h> #else # include <pty.h> #endif @@ -49,10 +49,10 @@ // this header defines STR, just as nvim.h, but it is defined as ('S'<<8), // to avoid #undef STR, #undef STR, #define STR ('S'<<8) just delay the // inclusion of the header even though it gets include out of order. -#include <sys/stropts.h> +# include <sys/stropts.h> -static int openpty(int *amaster, int *aslave, char *name, - struct termios *termp, struct winsize *winp) +static int openpty(int *amaster, int *aslave, char *name, struct termios *termp, + struct winsize *winp) { int slave = -1; int master = open("/dev/ptmx", O_RDWR); @@ -63,7 +63,7 @@ static int openpty(int *amaster, int *aslave, char *name, // grantpt will invoke a setuid program to change permissions // and might fail if SIGCHLD handler is set, temporarily reset // while running - void(*sig_saved)(int) = signal(SIGCHLD, SIG_DFL); + void (*sig_saved)(int) = signal(SIGCHLD, SIG_DFL); int res = grantpt(master); signal(SIGCHLD, sig_saved); @@ -86,7 +86,7 @@ static int openpty(int *amaster, int *aslave, char *name, ioctl(slave, I_PUSH, "ptem"); // ldterm provides most of the termio terminal interface ioctl(slave, I_PUSH, "ldterm"); - // ttcompat compatability with older terminal ioctls + // ttcompat compatibility with older terminal ioctls ioctl(slave, I_PUSH, "ttcompat"); if (termp) { @@ -129,8 +129,7 @@ static int login_tty(int fd) return 0; } -static pid_t forkpty(int *amaster, char *name, - struct termios *termp, struct winsize *winp) +static pid_t forkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp) { int master, slave; if (openpty(&master, &slave, name, termp, winp) == -1) { @@ -164,10 +163,15 @@ static struct termios termios_default; /// @param tty_fd TTY file descriptor, or -1 if not in a terminal. void pty_process_save_termios(int tty_fd) { - DLOG("tty_fd=%d", tty_fd); - if (tty_fd == -1 || tcgetattr(tty_fd, &termios_default) != 0) { + 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 diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index f78f3e66f5..6233a90638 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -4,7 +4,6 @@ #include <assert.h> #include <stdbool.h> #include <stdlib.h> -#include <winpty_constants.h> #include "nvim/ascii.h" #include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8 @@ -23,11 +22,7 @@ static void CALLBACK pty_process_finish1(void *context, BOOLEAN unused) PtyProcess *ptyproc = (PtyProcess *)context; Process *proc = (Process *)ptyproc; - if (ptyproc->type == kConpty - && ptyproc->object.conpty != NULL) { - os_conpty_free(ptyproc->object.conpty); - ptyproc->object.conpty = NULL; - } + os_conpty_free(ptyproc->conpty); uv_timer_init(&proc->loop->uv, &ptyproc->wait_eof_timer); ptyproc->wait_eof_timer.data = (void *)ptyproc; uv_timer_start(&ptyproc->wait_eof_timer, wait_eof_timer_cb, 200, 200); @@ -39,10 +34,6 @@ int pty_process_spawn(PtyProcess *ptyproc) { Process *proc = (Process *)ptyproc; int status = 0; - winpty_error_ptr_t err = NULL; - winpty_config_t *cfg = NULL; - winpty_spawn_config_t *spawncfg = NULL; - winpty_t *winpty_object = NULL; conpty_t *conpty_object = NULL; char *in_name = NULL; char *out_name = NULL; @@ -56,39 +47,11 @@ int pty_process_spawn(PtyProcess *ptyproc) assert(proc->err.closed); - if (os_has_conpty_working()) { - if ((conpty_object = - os_conpty_init(&in_name, &out_name, - ptyproc->width, ptyproc->height)) != NULL) { - ptyproc->type = kConpty; - } - } - - if (ptyproc->type == kWinpty) { - cfg = winpty_config_new(WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION, &err); - if (cfg == NULL) { - emsg = "winpty_config_new failed"; - goto cleanup; - } - - winpty_config_set_initial_size(cfg, ptyproc->width, ptyproc->height); - winpty_object = winpty_open(cfg, &err); - if (winpty_object == NULL) { - emsg = "winpty_open failed"; - goto cleanup; - } - - status = utf16_to_utf8(winpty_conin_name(winpty_object), -1, &in_name); - if (status != 0) { - emsg = "utf16_to_utf8(winpty_conin_name) failed"; - goto cleanup; - } - - status = utf16_to_utf8(winpty_conout_name(winpty_object), -1, &out_name); - if (status != 0) { - emsg = "utf16_to_utf8(winpty_conout_name) failed"; - goto cleanup; - } + if (!os_has_conpty_working() || (conpty_object = os_conpty_init(&in_name, + &out_name, ptyproc->width, + ptyproc->height)) == NULL) { + status = UV_ENOSYS; + goto cleanup; } if (!proc->in.closed) { @@ -131,44 +94,15 @@ int pty_process_spawn(PtyProcess *ptyproc) goto cleanup; } - if (ptyproc->type == kConpty) { - if (!os_conpty_spawn(conpty_object, - &process_handle, - NULL, - cmd_line, - cwd, - env)) { - emsg = "os_conpty_spawn failed"; - status = (int)GetLastError(); - goto cleanup; - } - } else { - spawncfg = winpty_spawn_config_new(WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN, - NULL, // Optional application name - cmd_line, - cwd, - env, - &err); - if (spawncfg == NULL) { - emsg = "winpty_spawn_config_new failed"; - goto cleanup; - } - - DWORD win_err = 0; - if (!winpty_spawn(winpty_object, - spawncfg, - &process_handle, - NULL, // Optional thread handle - &win_err, - &err)) { - if (win_err) { - status = (int)win_err; - emsg = "failed to spawn process"; - } else { - emsg = "winpty_spawn failed"; - } - goto cleanup; - } + if (!os_conpty_spawn(conpty_object, + &process_handle, + NULL, + cmd_line, + cwd, + env)) { + emsg = "os_conpty_spawn failed"; + status = (int)GetLastError(); + goto cleanup; } proc->pid = (int)GetProcessId(process_handle); @@ -187,11 +121,8 @@ int pty_process_spawn(PtyProcess *ptyproc) uv_run(&proc->loop->uv, UV_RUN_ONCE); } - (ptyproc->type == kConpty) ? - (void *)(ptyproc->object.conpty = conpty_object) : - (void *)(ptyproc->object.winpty = winpty_object); + ptyproc->conpty = conpty_object; ptyproc->process_handle = process_handle; - winpty_object = NULL; conpty_object = NULL; process_handle = NULL; @@ -201,16 +132,7 @@ cleanup: ELOG("pty_process_spawn(%s): %s: error code: %d", proc->argv[0], emsg, status); status = os_translate_sys_error(status); - } else if (err != NULL) { - status = (int)winpty_error_code(err); - ELOG("pty_process_spawn(%s): %s: error code: %d", - proc->argv[0], emsg, status); - status = translate_winpty_error(status); } - winpty_error_free(err); - winpty_config_free(cfg); - winpty_spawn_config_free(spawncfg); - winpty_free(winpty_object); os_conpty_free(conpty_object); xfree(in_name); xfree(out_name); @@ -233,12 +155,7 @@ const char *pty_process_tty_name(PtyProcess *ptyproc) void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height) FUNC_ATTR_NONNULL_ALL { - if (ptyproc->type == kConpty - && ptyproc->object.conpty != NULL) { - os_conpty_set_size(ptyproc->object.conpty, width, height); - } else if (ptyproc->object.winpty != NULL) { - winpty_set_size(ptyproc->object.winpty, width, height, NULL); - } + os_conpty_set_size(ptyproc->conpty, width, height); } void pty_process_close(PtyProcess *ptyproc) @@ -255,18 +172,11 @@ void pty_process_close(PtyProcess *ptyproc) void pty_process_close_master(PtyProcess *ptyproc) FUNC_ATTR_NONNULL_ALL -{ - if (ptyproc->type == kWinpty - && ptyproc->object.winpty != NULL) { - winpty_free(ptyproc->object.winpty); - ptyproc->object.winpty = NULL; - } -} +{} void pty_process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL -{ -} +{} static void pty_process_connect_cb(uv_connect_t *req, int status) FUNC_ATTR_NONNULL_ALL @@ -281,7 +191,7 @@ static void wait_eof_timer_cb(uv_timer_t *wait_eof_timer) PtyProcess *ptyproc = wait_eof_timer->data; Process *proc = (Process *)ptyproc; - if (proc->out.closed || !uv_is_readable(proc->out.uvstream)) { + if (proc->out.closed || proc->out.did_eof || !uv_is_readable(proc->out.uvstream)) { uv_timer_stop(&ptyproc->wait_eof_timer); pty_process_finish2(ptyproc); } @@ -308,7 +218,7 @@ static void pty_process_finish2(PtyProcess *ptyproc) /// Build the command line to pass to CreateProcessW. /// /// @param[in] argv Array with string arguments. -/// @param[out] cmd_line Location where saved builded cmd line. +/// @param[out] cmd_line Location where saved built cmd line. /// /// @returns zero on success, or error code of MultiByteToWideChar function. /// @@ -435,40 +345,6 @@ static void quote_cmd_arg(char *dest, size_t dest_remaining, const char *src) } } -/// Translate winpty error code to libuv error. -/// -/// @param[in] winpty_errno Winpty error code returned by winpty_error_code -/// function. -/// -/// @returns Error code of libuv error. -int translate_winpty_error(int winpty_errno) -{ - if (winpty_errno <= 0) { - return winpty_errno; // If < 0 then it's already a libuv error. - } - - switch (winpty_errno) { - case WINPTY_ERROR_OUT_OF_MEMORY: - return UV_ENOMEM; - case WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED: - return UV_EAI_FAIL; - case WINPTY_ERROR_LOST_CONNECTION: - return UV_ENOTCONN; - case WINPTY_ERROR_AGENT_EXE_MISSING: - return UV_ENOENT; - case WINPTY_ERROR_UNSPECIFIED: - return UV_UNKNOWN; - case WINPTY_ERROR_AGENT_DIED: - return UV_ESRCH; - case WINPTY_ERROR_AGENT_TIMEOUT: - return UV_ETIMEDOUT; - case WINPTY_ERROR_AGENT_CREATION_FAILED: - return UV_EAI_FAIL; - default: - return UV_UNKNOWN; - } -} - typedef struct EnvNode { wchar_t *str; size_t len; @@ -485,7 +361,7 @@ static int build_env_block(dict_T *denv, wchar_t **env_block) { const size_t denv_size = (size_t)tv_dict_len(denv); size_t env_block_len = 0; - int rc; + int rc = 0; char **env = tv_dict_to_env(denv); QUEUE *q; diff --git a/src/nvim/os/pty_process_win.h b/src/nvim/os/pty_process_win.h index d1737fd63a..ed7d765ac7 100644 --- a/src/nvim/os/pty_process_win.h +++ b/src/nvim/os/pty_process_win.h @@ -2,25 +2,15 @@ #define NVIM_OS_PTY_PROCESS_WIN_H #include <uv.h> -#include <winpty.h> #include "nvim/event/process.h" #include "nvim/lib/queue.h" #include "nvim/os/pty_conpty_win.h" -typedef enum { - kWinpty, - kConpty, -} PtyType; - typedef struct pty_process { Process process; uint16_t width, height; - union { - winpty_t *winpty; - conpty_t *conpty; - } object; - PtyType type; + conpty_t *conpty; HANDLE finish_wait; HANDLE process_handle; uv_timer_t wait_eof_timer; @@ -38,8 +28,7 @@ static inline PtyProcess pty_process_init(Loop *loop, void *data) rv.process = process_init(loop, kProcessTypePty, data); rv.width = 80; rv.height = 24; - rv.object.winpty = NULL; - rv.type = kWinpty; + rv.conpty = NULL; rv.finish_wait = NULL; rv.process_handle = NULL; return rv; diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index e618b2788b..9283ea2e42 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -9,10 +9,10 @@ #include "nvim/ascii.h" #include "nvim/charset.h" +#include "nvim/eval.h" #include "nvim/event/libuv_process.h" #include "nvim/event/loop.h" #include "nvim/event/rstream.h" -#include "nvim/eval.h" #include "nvim/ex_cmds.h" #include "nvim/fileio.h" #include "nvim/lib/kvec.h" @@ -27,8 +27,8 @@ #include "nvim/path.h" #include "nvim/screen.h" #include "nvim/strings.h" -#include "nvim/types.h" #include "nvim/tag.h" +#include "nvim/types.h" #include "nvim/ui.h" #include "nvim/vim.h" @@ -36,7 +36,7 @@ #define NS_1_SECOND 1000000000U // 1 second, in nanoseconds #define OUT_DATA_THRESHOLD 1024 * 10U // 10KB, "a few screenfuls" of data. -#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|" +#define SHELL_SPECIAL "\t \"&'$;<>()\\|" typedef struct { char *data; @@ -73,7 +73,7 @@ static bool have_wildcard(int num, char_u **file) static bool have_dollars(int num, char_u **file) { for (int i = 0; i < num; i++) { - if (vim_strchr(file[i], '$') != NULL) { + if (vim_strchr((char *)file[i], '$') != NULL) { return true; } } @@ -151,7 +151,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file // Don't allow the use of backticks in secure. if (secure) { for (i = 0; i < num_pat; i++) { - if (vim_strchr(pat[i], '`') != NULL + if (vim_strchr((char *)pat[i], '`') != NULL && (check_secure())) { return FAIL; } @@ -188,7 +188,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file } } if (shell_style == STYLE_ECHO - && strstr((char *)path_tail(p_sh), "sh") != NULL) { + && strstr(path_tail((char *)p_sh), "sh") != NULL) { shell_style = STYLE_VIMGLOB; } @@ -405,7 +405,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file while (*p != ' ' && *p != '\n') { p++; } - p = skipwhite(p); // skip to next entry + p = (char_u *)skipwhite((char *)p); // skip to next entry } // file names are separated with NL } else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB) { @@ -418,7 +418,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file if (*p != NUL) { p++; } - p = skipwhite(p); // skip leading white space + p = (char_u *)skipwhite((char *)p); // skip leading white space } // file names are separated with NUL } else { @@ -483,7 +483,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file *p = NUL; } else { *p++ = NUL; - p = skipwhite(p); // skip to next entry + p = (char_u *)skipwhite((char *)p); // skip to next entry } } else { // NUL separates while (*p && p < buffer + len) { // skip entry @@ -644,7 +644,7 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args) if (opts & (kShellOptHideMess | kShellOptExpand)) { forward_output = false; } else { - State = EXTERNCMD; + State = MODE_EXTERNCMD; if (opts & kShellOptWrite) { read_input(&input); @@ -746,7 +746,7 @@ char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags, size_t *ret } // Add the redirection stuff - char_u *command = make_filter_cmd(cmd, infile, tempname); + char_u *command = (char_u *)make_filter_cmd((char *)cmd, (char *)infile, (char *)tempname); // Call the shell to execute the command (errors are ignored). // Don't check timestamps here. @@ -854,9 +854,9 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu // Failed, probably 'shell' is not executable. if (!silent) { msg_puts(_("\nshell failed to start: ")); - msg_outtrans((char_u *)os_strerror(status)); + msg_outtrans((char *)os_strerror(status)); msg_puts(": "); - msg_outtrans((char_u *)prog); + msg_outtrans(prog); msg_putchar('\n'); } multiqueue_free(events); @@ -1099,8 +1099,8 @@ 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; - if (!eof && i == 1 && utf8len_tab_zero[*(uint8_t *)p] > (end-p)) { + int i = *p ? utfc_ptr2len_len((char_u *)p, (int)(end - p)) : 1; + if (!eof && i == 1 && utf8len_tab_zero[*(uint8_t *)p] > (end - p)) { *count = (size_t)(p - output); goto end; } @@ -1158,7 +1158,7 @@ static size_t tokenize(const char_u *const str, char **const argv) } argc++; - p = (const char *)skipwhite((char_u *)(p + len)); + p = (const char *)skipwhite((p + len)); } return argc; @@ -1213,7 +1213,7 @@ static void read_input(DynamicBuffer *buf) dynamic_buffer_ensure(buf, buf->len + len); buf->data[buf->len++] = NUL; } else { - char_u *s = vim_strchr(lp + written, NL); + char_u *s = (char_u *)vim_strchr((char *)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); @@ -1229,7 +1229,7 @@ static void read_input(DynamicBuffer *buf) dynamic_buffer_ensure(buf, buf->len + 1); buf->data[buf->len++] = NL; } - ++lnum; + lnum++; if (lnum > curbuf->b_op_end.lnum) { break; } @@ -1253,7 +1253,7 @@ static size_t write_output(char *output, size_t remaining, bool eof) if (output[off] == NL) { // Insert the line output[off] = NUL; - ml_append(curwin->w_cursor.lnum++, (char_u *)output, (int)off + 1, + ml_append(curwin->w_cursor.lnum++, output, (int)off + 1, false); size_t skip = off + 1; output += skip; @@ -1272,7 +1272,7 @@ static size_t write_output(char *output, size_t remaining, bool eof) if (eof) { if (remaining) { // append unfinished line - ml_append(curwin->w_cursor.lnum++, (char_u *)output, 0, false); + ml_append(curwin->w_cursor.lnum++, output, 0, false); // remember that the NL was missing curbuf->b_no_eol_lnum = curwin->w_cursor.lnum; output += remaining; @@ -1331,4 +1331,3 @@ static char *shell_xescape_xquote(const char *cmd) return ncmd; } - diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c index a8bf68a1a2..581f025a0f 100644 --- a/src/nvim/os/signal.c +++ b/src/nvim/os/signal.c @@ -21,7 +21,7 @@ #include "nvim/os/signal.h" #include "nvim/vim.h" -static SignalWatcher spipe, shup, squit, sterm, susr1; +static SignalWatcher spipe, shup, squit, sterm, susr1, swinch; #ifdef SIGPWR static SignalWatcher spwr; #endif @@ -54,6 +54,9 @@ void signal_init(void) #ifdef SIGUSR1 signal_watcher_init(&main_loop, &susr1, NULL); #endif +#ifdef SIGWINCH + signal_watcher_init(&main_loop, &swinch, NULL); +#endif signal_start(); } @@ -70,6 +73,9 @@ void signal_teardown(void) #ifdef SIGUSR1 signal_watcher_close(&susr1, NULL); #endif +#ifdef SIGWINCH + signal_watcher_close(&swinch, NULL); +#endif } void signal_start(void) @@ -88,6 +94,9 @@ void signal_start(void) #ifdef SIGUSR1 signal_watcher_start(&susr1, on_signal, SIGUSR1); #endif +#ifdef SIGWINCH + signal_watcher_start(&swinch, on_signal, SIGWINCH); +#endif } void signal_stop(void) @@ -106,6 +115,9 @@ void signal_stop(void) #ifdef SIGUSR1 signal_watcher_stop(&susr1); #endif +#ifdef SIGWINCH + signal_watcher_stop(&swinch); +#endif } void signal_reject_deadly(void) @@ -141,6 +153,10 @@ static char *signal_name(int signum) case SIGUSR1: return "SIGUSR1"; #endif +#ifdef SIGWINCH + case SIGWINCH: + return "SIGWINCH"; +#endif default: return "Unknown"; } @@ -149,15 +165,15 @@ static char *signal_name(int signum) // This function handles deadly signals. // It tries to preserve any swap files and exit properly. // (partly from Elvis). -// NOTE: Avoid unsafe functions, such as allocating memory, they can result in -// a deadlock. +// NOTE: this is scheduled on the event loop, not called directly from a signal handler. static void deadly_signal(int signum) + FUNC_ATTR_NORETURN { // Set the v:dying variable. set_vim_var_nr(VV_DYING, 1); v_dying = 1; - WLOG("got signal %d (%s)", signum, signal_name(signum)); + ILOG("got signal %d (%s)", signum, signal_name(signum)); snprintf((char *)IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\r\n", signal_name(signum)); @@ -193,8 +209,12 @@ static void on_signal(SignalWatcher *handle, int signum, void *data) break; #ifdef SIGUSR1 case SIGUSR1: - apply_autocmds(EVENT_SIGNAL, (char_u *)"SIGUSR1", curbuf->b_fname, true, - curbuf); + apply_autocmds(EVENT_SIGNAL, "SIGUSR1", curbuf->b_fname, true, curbuf); + break; +#endif +#ifdef SIGWINCH + case SIGWINCH: + apply_autocmds(EVENT_SIGNAL, "SIGWINCH", curbuf->b_fname, true, curbuf); break; #endif default: diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c index 5b824d23f4..59d315d44c 100644 --- a/src/nvim/os/stdpaths.c +++ b/src/nvim/os/stdpaths.c @@ -4,6 +4,7 @@ #include <stdbool.h> #include "nvim/ascii.h" +#include "nvim/fileio.h" #include "nvim/memory.h" #include "nvim/os/os.h" #include "nvim/os/stdpaths_defs.h" @@ -14,6 +15,7 @@ static const char *xdg_env_vars[] = { [kXDGConfigHome] = "XDG_CONFIG_HOME", [kXDGDataHome] = "XDG_DATA_HOME", [kXDGCacheHome] = "XDG_CACHE_HOME", + [kXDGStateHome] = "XDG_STATE_HOME", [kXDGRuntimeDir] = "XDG_RUNTIME_DIR", [kXDGConfigDirs] = "XDG_CONFIG_DIRS", [kXDGDataDirs] = "XDG_DATA_DIRS", @@ -24,7 +26,8 @@ static const char *const xdg_defaults_env_vars[] = { [kXDGConfigHome] = "LOCALAPPDATA", [kXDGDataHome] = "LOCALAPPDATA", [kXDGCacheHome] = "TEMP", - [kXDGRuntimeDir] = NULL, + [kXDGStateHome] = "LOCALAPPDATA", + [kXDGRuntimeDir] = NULL, // Decided by vim_mktempdir(). [kXDGConfigDirs] = NULL, [kXDGDataDirs] = NULL, }; @@ -38,14 +41,16 @@ static const char *const xdg_defaults[] = { [kXDGConfigHome] = "~\\AppData\\Local", [kXDGDataHome] = "~\\AppData\\Local", [kXDGCacheHome] = "~\\AppData\\Local\\Temp", - [kXDGRuntimeDir] = NULL, + [kXDGStateHome] = "~\\AppData\\Local", + [kXDGRuntimeDir] = NULL, // Decided by vim_mktempdir(). [kXDGConfigDirs] = NULL, [kXDGDataDirs] = NULL, #else [kXDGConfigHome] = "~/.config", [kXDGDataHome] = "~/.local/share", [kXDGCacheHome] = "~/.cache", - [kXDGRuntimeDir] = NULL, + [kXDGStateHome] = "~/.local/state", + [kXDGRuntimeDir] = NULL, // Decided by vim_mktempdir(). [kXDGConfigDirs] = "/etc/xdg/", [kXDGDataDirs] = "/usr/local/share/:/usr/share/", #endif @@ -78,7 +83,12 @@ char *stdpaths_get_xdg_var(const XDGVarType idx) if (env_val != NULL) { ret = xstrdup(env_val); } else if (fallback) { - ret = (char *)expand_env_save((char_u *)fallback); + ret = expand_env_save((char *)fallback); + } else if (idx == kXDGRuntimeDir) { + // Special-case: stdpath('run') is defined at startup. + ret = vim_gettempdir(); + size_t len = strlen(ret); + ret = xstrndup(ret, len >= 2 ? len - 1 : 0); // Trim trailing slash. } return ret; @@ -99,11 +109,16 @@ char *get_xdg_home(const XDGVarType idx) if (dir) { #if defined(WIN32) dir = concat_fnames_realloc(dir, - (idx == kXDGDataHome ? "nvim-data" : "nvim"), + ((idx == kXDGDataHome + || idx == kXDGStateHome) ? "nvim-data" : "nvim"), true); #else dir = concat_fnames_realloc(dir, "nvim", true); #endif + +#ifdef BACKSLASH_IN_FILENAME + slash_adjust((char_u *)dir); +#endif } return dir; } @@ -133,15 +148,26 @@ char *stdpaths_user_conf_subpath(const char *fname) /// Return subpath of $XDG_DATA_HOME /// /// @param[in] fname New component of the path. +/// +/// @return [allocated] `$XDG_DATA_HOME/nvim/{fname}` +char *stdpaths_user_data_subpath(const char *fname) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET +{ + return concat_fnames_realloc(get_xdg_home(kXDGDataHome), fname, true); +} + +/// Return subpath of $XDG_STATE_HOME +/// +/// @param[in] fname New component of the path. /// @param[in] trailing_pathseps Amount of trailing path separators to add. /// @param[in] escape_commas If true, all commas will be escaped. /// -/// @return [allocated] `$XDG_DATA_HOME/nvim/{fname}`. -char *stdpaths_user_data_subpath(const char *fname, const size_t trailing_pathseps, - const bool escape_commas) +/// @return [allocated] `$XDG_STATE_HOME/nvim/{fname}`. +char *stdpaths_user_state_subpath(const char *fname, const size_t trailing_pathseps, + const bool escape_commas) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { - char *ret = concat_fnames_realloc(get_xdg_home(kXDGDataHome), fname, true); + char *ret = concat_fnames_realloc(get_xdg_home(kXDGStateHome), fname, true); const size_t len = strlen(ret); const size_t numcommas = (escape_commas ? memcnt(ret, ',', len) : 0); if (numcommas || trailing_pathseps) { diff --git a/src/nvim/os/stdpaths_defs.h b/src/nvim/os/stdpaths_defs.h index 44c30df373..f94c511fe7 100644 --- a/src/nvim/os/stdpaths_defs.h +++ b/src/nvim/os/stdpaths_defs.h @@ -7,6 +7,7 @@ typedef enum { kXDGConfigHome, ///< XDG_CONFIG_HOME kXDGDataHome, ///< XDG_DATA_HOME kXDGCacheHome, ///< XDG_CACHE_HOME + kXDGStateHome, ///< XDG_STATE_HOME kXDGRuntimeDir, ///< XDG_RUNTIME_DIR kXDGConfigDirs, ///< XDG_CONFIG_DIRS kXDGDataDirs, ///< XDG_DATA_DIRS diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c index d9f4fe9e37..396bf6986a 100644 --- a/src/nvim/os/time.c +++ b/src/nvim/os/time.c @@ -15,7 +15,6 @@ static uv_mutex_t delay_mutex; static uv_cond_t delay_cond; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/time.c.generated.h" #endif diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c index e0ce3fec31..bd34e917b2 100644 --- a/src/nvim/os/users.c +++ b/src/nvim/os/users.c @@ -30,7 +30,7 @@ static void add_user(garray_T *users, char *user, bool need_copy) if (user_copy == NULL || *user_copy == NUL) { if (need_copy) { - xfree(user); + xfree(user_copy); } return; } @@ -112,9 +112,13 @@ int os_get_usernames(garray_T *users) return OK; } -// Insert user name in s[len]. -// Return OK if a name found. -int os_get_user_name(char *s, size_t len) +/// Gets the username that owns the current Nvim process. +/// +/// @param s[out] Username. +/// @param len Length of `s`. +/// +/// @return OK if a name found. +int os_get_username(char *s, size_t len) { #ifdef UNIX return os_get_uname((uv_uid_t)getuid(), s, len); @@ -124,9 +128,13 @@ int os_get_user_name(char *s, size_t len) #endif } -// Insert user name for "uid" in s[len]. -// Return OK if a name found. -// If the name is not found, write the uid into s[len] and return FAIL. +/// Gets the username associated with `uid`. +/// +/// @param uid User id. +/// @param s[out] Username, or `uid` on failure. +/// @param len Length of `s`. +/// +/// @return OK if a username was found, else FAIL. int os_get_uname(uv_uid_t uid, char *s, size_t len) { #if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID) @@ -142,10 +150,10 @@ int os_get_uname(uv_uid_t uid, char *s, size_t len) return FAIL; // a number is not a name } -// Returns the user directory for the given username. -// The caller has to free() the returned string. -// If the username is not found, NULL is returned. -char *os_get_user_directory(const char *name) +/// Gets the user directory for the given username, or NULL on failure. +/// +/// Caller must free() the returned string. +char *os_get_userdir(const char *name) { #if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H) if (name == NULL || *name == NUL) { @@ -160,7 +168,6 @@ char *os_get_user_directory(const char *name) return NULL; } - #if defined(EXITFREE) void free_users(void) @@ -187,11 +194,11 @@ static void init_users(void) } /// Given to ExpandGeneric() to obtain an user names. -char_u *get_users(expand_T *xp, int idx) +char *get_users(expand_T *xp, int idx) { init_users(); if (idx < ga_users.ga_len) { - return ((char_u **)ga_users.ga_data)[idx]; + return ((char **)ga_users.ga_data)[idx]; } return NULL; } diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h index efef77be7b..1ae86d6bbe 100644 --- a/src/nvim/os/win_defs.h +++ b/src/nvim/os/win_defs.h @@ -36,7 +36,7 @@ // Windows defines a RGB macro that produces 0x00bbggrr color values for use // with GDI. Our macro is different, and we don't use GDI. // Duplicated from macros.h to avoid include-order sensitivity. -#define RGB_(r, g, b) ((r << 16) | (g << 8) | b) +#define RGB_(r, g, b) (((r) << 16) | ((g) << 8) | (b)) #ifdef _MSC_VER # ifndef inline |