diff options
Diffstat (limited to 'src/nvim/ex_docmd.c')
-rw-r--r-- | src/nvim/ex_docmd.c | 841 |
1 files changed, 452 insertions, 389 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index bf518f3849..e11dd0a2f6 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4,59 +4,57 @@ // ex_docmd.c: functions for executing an Ex command line. #include <assert.h> +#include <ctype.h> #include <inttypes.h> +#include <limits.h> #include <stdbool.h> +#include <stddef.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> +#include "auto/config.h" #include "nvim/arglist.h" #include "nvim/ascii.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/change.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" -#include "nvim/cmdhist.h" #include "nvim/cursor.h" #include "nvim/debugger.h" -#include "nvim/diff.h" #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" #include "nvim/eval.h" +#include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" -#include "nvim/eval/vars.h" -#include "nvim/event/rstream.h" -#include "nvim/event/wstream.h" +#include "nvim/event/loop.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" -#include "nvim/ex_session.h" #include "nvim/file_search.h" #include "nvim/fileio.h" #include "nvim/fold.h" -#include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/getchar.h" +#include "nvim/gettext.h" #include "nvim/globals.h" -#include "nvim/hardcopy.h" -#include "nvim/help.h" +#include "nvim/highlight_defs.h" #include "nvim/highlight_group.h" -#include "nvim/if_cscope.h" #include "nvim/input.h" #include "nvim/keycodes.h" -#include "nvim/locale.h" -#include "nvim/lua/executor.h" +#include "nvim/macros.h" #include "nvim/main.h" -#include "nvim/mapping.h" #include "nvim/mark.h" -#include "nvim/match.h" #include "nvim/mbyte.h" +#include "nvim/memfile_defs.h" #include "nvim/memline.h" #include "nvim/memory.h" -#include "nvim/menu.h" #include "nvim/message.h" #include "nvim/mouse.h" #include "nvim/move.h" @@ -66,28 +64,25 @@ #include "nvim/optionstr.h" #include "nvim/os/input.h" #include "nvim/os/os.h" -#include "nvim/os/time.h" -#include "nvim/os_unix.h" +#include "nvim/os/shell.h" #include "nvim/path.h" #include "nvim/popupmenu.h" +#include "nvim/pos.h" #include "nvim/profile.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" +#include "nvim/screen.h" #include "nvim/search.h" #include "nvim/shada.h" -#include "nvim/sign.h" -#include "nvim/spell.h" -#include "nvim/spellfile.h" #include "nvim/state.h" +#include "nvim/statusline.h" #include "nvim/strings.h" -#include "nvim/syntax.h" #include "nvim/tag.h" -#include "nvim/terminal.h" +#include "nvim/types.h" #include "nvim/ui.h" #include "nvim/undo.h" -#include "nvim/undo_defs.h" #include "nvim/usercmd.h" -#include "nvim/version.h" #include "nvim/vim.h" #include "nvim/window.h" @@ -254,7 +249,7 @@ void do_exmode(void) RedrawingDisabled--; no_wait_return--; redraw_all_later(UPD_NOT_VALID); - update_screen(UPD_NOT_VALID); + update_screen(); need_wait_return = false; msg_scroll = save_msg_scroll; } @@ -535,7 +530,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) if (flags & DOCMD_KEEPLINE) { xfree(repeat_cmdline); if (count == 0) { - repeat_cmdline = (char *)vim_strsave((char_u *)next_cmdline); + repeat_cmdline = xstrdup(next_cmdline); } else { repeat_cmdline = NULL; } @@ -642,7 +637,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // Check for the next breakpoint at or after the ":while" // or ":for". - if (breakpoint != NULL) { + if (breakpoint != NULL && lines_ga.ga_len > current_line) { *breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline), fname, ((wcmd_T *)lines_ga.ga_data)[current_line].lnum - 1); *dbg_tick = debug_tick; @@ -727,7 +722,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) if (cstack.cs_idx >= 0) { // If a sourced file or executed function ran to its end, report the // unclosed conditional. - if (!got_int && !did_throw + if (!got_int && !did_throw && !aborting() && ((getline_equal(fgetline, cookie, getsourceline) && !source_finished(fgetline, cookie)) || (getline_equal(fgetline, cookie, get_func_line) @@ -771,52 +766,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // of interrupts or errors to exceptions, and ensure that no more // commands are executed. if (did_throw) { - assert(current_exception != NULL); - char *p = NULL; - msglist_T *messages = NULL; - msglist_T *next; - - // If the uncaught exception is a user exception, report it as an - // error. If it is an error exception, display the saved error - // message now. For an interrupt exception, do nothing; the - // interrupt message is given elsewhere. - switch (current_exception->type) { - case ET_USER: - vim_snprintf((char *)IObuff, IOSIZE, - _("E605: Exception not caught: %s"), - current_exception->value); - p = (char *)vim_strsave(IObuff); - break; - case ET_ERROR: - messages = current_exception->messages; - current_exception->messages = NULL; - break; - case ET_INTERRUPT: - break; - } - - estack_push(ETYPE_EXCEPT, current_exception->throw_name, current_exception->throw_lnum); - current_exception->throw_name = NULL; - - discard_current_exception(); // uses IObuff if 'verbose' - suppress_errthrow = true; - force_abort = true; - msg_ext_set_kind("emsg"); // kind=emsg for :throw, exceptions. #9993 - - if (messages != NULL) { - do { - next = messages->next; - emsg(messages->msg); - xfree(messages->msg); - xfree(messages); - messages = next; - } while (messages != NULL); - } else if (p != NULL) { - emsg(p); - xfree(p); - } - xfree(SOURCING_NAME); - estack_pop(); + handle_did_throw(); } else if (got_int || (did_emsg && force_abort)) { // On an interrupt or an aborting error not converted to an exception, // disable the conversion of errors to exceptions. (Interrupts are not @@ -906,6 +856,57 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) return retval; } +/// Handle when "did_throw" is set after executing commands. +void handle_did_throw(void) +{ + assert(current_exception != NULL); + char *p = NULL; + msglist_T *messages = NULL; + + // If the uncaught exception is a user exception, report it as an + // error. If it is an error exception, display the saved error + // message now. For an interrupt exception, do nothing; the + // interrupt message is given elsewhere. + switch (current_exception->type) { + case ET_USER: + vim_snprintf(IObuff, IOSIZE, + _("E605: Exception not caught: %s"), + current_exception->value); + p = xstrdup(IObuff); + break; + case ET_ERROR: + messages = current_exception->messages; + current_exception->messages = NULL; + break; + case ET_INTERRUPT: + break; + } + + estack_push(ETYPE_EXCEPT, current_exception->throw_name, current_exception->throw_lnum); + current_exception->throw_name = NULL; + + discard_current_exception(); // uses IObuff if 'verbose' + suppress_errthrow = true; + force_abort = true; + msg_ext_set_kind("emsg"); // kind=emsg for :throw, exceptions. #9993 + + if (messages != NULL) { + do { + msglist_T *next = messages->next; + emsg(messages->msg); + xfree(messages->msg); + xfree(messages->sfile); + xfree(messages); + messages = next; + } while (messages != NULL); + } else if (p != NULL) { + emsg(p); + xfree(p); + } + xfree(SOURCING_NAME); + estack_pop(); +} + /// Obtain a line when inside a ":while" or ":for" loop. static char *get_loop_line(int c, void *cookie, int indent, bool do_concat) { @@ -1060,7 +1061,7 @@ static int current_tab_nr(tabpage_T *tab) #define LAST_TAB_NR current_tab_nr(NULL) /// Figure out the address type for ":wincmd". -static void get_wincmd_addr_type(char *arg, exarg_T *eap) +static void get_wincmd_addr_type(const char *arg, exarg_T *eap) { switch (*arg) { case 'S': @@ -1300,9 +1301,9 @@ static void parse_register(exarg_T *eap) // for '=' register: accept the rest of the line as an expression if (eap->arg[-1] == '=' && eap->arg[0] != NUL) { if (!eap->skip) { - set_expr_line(vim_strsave((char_u *)eap->arg)); + set_expr_line(xstrdup(eap->arg)); } - eap->arg += STRLEN(eap->arg); + eap->arg += strlen(eap->arg); } eap->arg = skipwhite(eap->arg); } @@ -1339,6 +1340,20 @@ static int parse_count(exarg_T *eap, char **errormsg, bool validate) || ascii_iswhite(*p))) { long n = getdigits_long(&eap->arg, false, -1); eap->arg = skipwhite(eap->arg); + + if (eap->args != NULL) { + assert(eap->argc > 0 && eap->arg >= eap->args[0]); + // If eap->arg is still pointing to the first argument, just make eap->args[0] point to the + // same location. This is needed for usecases like vim.cmd.sleep('10m'). If eap->arg is + // pointing outside the first argument, shift arguments by 1. + if (eap->arg < eap->args[0] + eap->arglens[0]) { + eap->arglens[0] -= (size_t)(eap->arg - eap->args[0]); + eap->args[0] = eap->arg; + } else { + shift_cmd_args(eap); + } + } + if (n <= 0 && (eap->argt & EX_ZEROR) == 0) { if (errormsg != NULL) { *errormsg = _(e_zerocount); @@ -1430,7 +1445,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er // If the modifier was parsed OK the error must be in the following command char *cmdname = after_modifier ? after_modifier : cmdline; append_command(cmdname); - *errormsg = (char *)IObuff; + *errormsg = IObuff; goto end; } @@ -1512,6 +1527,30 @@ end: return retval; } +// Shift Ex-command arguments to the right. +static void shift_cmd_args(exarg_T *eap) +{ + assert(eap->args != NULL && eap->argc > 0); + + char **oldargs = eap->args; + size_t *oldarglens = eap->arglens; + + eap->argc--; + eap->args = eap->argc > 0 ? xcalloc(eap->argc, sizeof(char *)) : NULL; + eap->arglens = eap->argc > 0 ? xcalloc(eap->argc, sizeof(size_t)) : NULL; + + for (size_t i = 0; i < eap->argc; i++) { + eap->args[i] = oldargs[i + 1]; + eap->arglens[i] = oldarglens[i + 1]; + } + + // If there are no arguments, make eap->arg point to the end of string. + eap->arg = (eap->argc > 0 ? eap->args[0] : (oldargs[0] + oldarglens[0])); + + xfree(oldargs); + xfree(oldarglens); +} + static int execute_cmd0(int *retv, exarg_T *eap, char **errormsg, bool preview) { // If filename expansion is enabled, expand filenames @@ -1536,7 +1575,7 @@ static int execute_cmd0(int *retv, exarg_T *eap, char **errormsg, bool preview) || eap->cmdidx == CMD_bunload) { p = skiptowhite_esc(eap->arg); } else { - p = eap->arg + STRLEN(eap->arg); + p = eap->arg + strlen(eap->arg); while (p > eap->arg && ascii_iswhite(p[-1])) { p--; } @@ -1551,15 +1590,7 @@ static int execute_cmd0(int *retv, exarg_T *eap, char **errormsg, bool preview) eap->args[0] + eap->arglens[0], (eap->argt & EX_BUFUNL) != 0, false, false); eap->addr_count = 1; - // Shift each argument by 1 - for (size_t i = 0; i < eap->argc - 1; i++) { - eap->args[i] = eap->args[i + 1]; - } - // Make the last argument point to the NUL terminator at the end of string - eap->args[eap->argc - 1] = eap->args[eap->argc - 1] + eap->arglens[eap->argc - 1]; - eap->argc -= 1; - - eap->arg = eap->args[0]; + shift_cmd_args(eap); } if (eap->line2 < 0) { // failed return FAIL; @@ -1608,6 +1639,7 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) char *errormsg = NULL; int retv = 0; +#undef ERROR #define ERROR(msg) \ do { \ errormsg = msg; \ @@ -1658,6 +1690,11 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) (void)hasFolding(eap->line2, NULL, &eap->line2); } + // Use first argument as count when possible + if (parse_count(eap, &errormsg, true) == FAIL) { + goto end; + } + // Execute the command execute_cmd0(&retv, eap, &errormsg, preview); @@ -1757,6 +1794,7 @@ static bool skip_cmd(const exarg_T *eap) case CMD_filter: case CMD_help: case CMD_hide: + case CMD_horizontal: case CMD_ijump: case CMD_ilist: case CMD_isearch: @@ -1794,6 +1832,7 @@ static bool skip_cmd(const exarg_T *eap) case CMD_throw: case CMD_tilde: case CMD_topleft: + case CMD_trust: case CMD_unlet: case CMD_unlockvar: case CMD_verbose: @@ -1892,9 +1931,11 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter profile_cmd(&ea, cstack, fgetline, cookie); - // May go to debug mode. If this happens and the ">quit" debug command is - // used, throw an interrupt exception and skip the next command. - dbg_check_breakpoint(&ea); + if (!exiting) { + // May go to debug mode. If this happens and the ">quit" debug command is + // used, throw an interrupt exception and skip the next command. + dbg_check_breakpoint(&ea); + } if (!ea.skip && got_int) { ea.skip = true; (void)do_intthrow(cstack); @@ -1929,7 +1970,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter // If we got a line, but no command, then go to the line. // If we find a '|' or '\n' we set ea.nextcmd. if (*ea.cmd == NUL || *ea.cmd == '"' - || (ea.nextcmd = (char *)check_nextcmd((char_u *)ea.cmd)) != NULL) { + || (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL) { // strange vi behaviour: // ":3" jumps to line 3 // ":3|..." prints line 3 @@ -1997,7 +2038,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter if (!(flags & DOCMD_VERBOSE)) { append_command(cmdname); } - errormsg = (char *)IObuff; + errormsg = IObuff; did_emsg_syntax = true; verify_command(cmdname); } @@ -2266,9 +2307,9 @@ doend: if (errormsg != NULL && *errormsg != NUL && !did_emsg) { if (flags & DOCMD_VERBOSE) { - if (errormsg != (char *)IObuff) { + if (errormsg != IObuff) { STRCPY(IObuff, errormsg); - errormsg = (char *)IObuff; + errormsg = IObuff; } append_command(*ea.cmdlinep); } @@ -2438,8 +2479,12 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, cmdmod_T *cmod, bool continue; } - // ":hide" and ":hide | cmd" are not modifiers case 'h': + if (checkforcmd(&eap->cmd, "horizontal", 3)) { + cmod->cmod_split |= WSP_HOR; + continue; + } + // ":hide" and ":hide | cmd" are not modifiers if (p != eap->cmd || !checkforcmd(&p, "hide", 3) || *p == NUL || ends_excmd(*p)) { break; @@ -2798,7 +2843,7 @@ theend: /// @param pp start of command /// @param cmd name of command /// @param len required length -bool checkforcmd(char **pp, char *cmd, int len) +bool checkforcmd(char **pp, const char *cmd, int len) { int i; @@ -2819,24 +2864,24 @@ bool checkforcmd(char **pp, char *cmd, int len) /// invisible otherwise. static void append_command(char *cmd) { - size_t len = STRLEN(IObuff); + size_t len = strlen(IObuff); char *s = cmd; char *d; if (len > IOSIZE - 100) { // Not enough space, truncate and put in "...". - d = (char *)IObuff + IOSIZE - 100; - d -= utf_head_off(IObuff, (const char_u *)d); + d = IObuff + IOSIZE - 100; + d -= utf_head_off(IObuff, d); STRCPY(d, "..."); } STRCAT(IObuff, ": "); - d = (char *)IObuff + STRLEN(IObuff); - while (*s != NUL && (char_u *)d - IObuff + 5 < IOSIZE) { + d = IObuff + strlen(IObuff); + while (*s != NUL && d - IObuff + 5 < IOSIZE) { if ((char_u)s[0] == 0xc2 && (char_u)s[1] == 0xa0) { s += 2; STRCPY(d, "<a0>"); d += 4; - } else if ((char_u *)d - IObuff + utfc_ptr2len(s) + 1 >= IOSIZE) { + } else if (d - IObuff + utfc_ptr2len(s) + 1 >= IOSIZE) { break; } else { mb_copy_char((const char **)&s, &d); @@ -2936,7 +2981,7 @@ char *find_ex_command(exarg_T *eap, int *full) for (; (int)eap->cmdidx < CMD_SIZE; eap->cmdidx = (cmdidx_T)((int)eap->cmdidx + 1)) { - if (STRNCMP(cmdnames[(int)eap->cmdidx].cmd_name, eap->cmd, + if (strncmp(cmdnames[(int)eap->cmdidx].cmd_name, eap->cmd, (size_t)len) == 0) { if (full != NULL && cmdnames[(int)eap->cmdidx].cmd_name[len] == NUL) { @@ -3081,10 +3126,9 @@ void f_fullcommand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - rettv->vval.v_string = (char *)vim_strsave(IS_USER_CMDIDX(ea.cmdidx) - ? (char_u *)get_user_command_name(ea.useridx, - ea.cmdidx) - : (char_u *)cmdnames[ea.cmdidx].cmd_name); + rettv->vval.v_string = xstrdup(IS_USER_CMDIDX(ea.cmdidx) + ? get_user_command_name(ea.useridx, ea.cmdidx) + : cmdnames[ea.cmdidx].cmd_name); } cmdidx_T excmd_get_cmdidx(const char *cmd, size_t len) @@ -3313,7 +3357,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int goto error; } if (skip) { // skip "/pat/" - cmd = skip_regexp(cmd, c, p_magic, NULL); + cmd = skip_regexp(cmd, c, magic_isset()); if (*cmd == c) { cmd++; } @@ -3342,7 +3386,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int } searchcmdlen = 0; flags = silent ? 0 : SEARCH_HIS | SEARCH_MSG; - if (!do_search(NULL, c, c, (char_u *)cmd, 1L, flags, NULL)) { + if (!do_search(NULL, c, c, cmd, 1L, flags, NULL)) { curwin->w_cursor = pos; cmd = NULL; goto error; @@ -3442,9 +3486,10 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int } else { i = (char_u)(*cmd++); } - if (!ascii_isdigit(*cmd)) { // '+' is '+1', but '+0' is not '+1' + if (!ascii_isdigit(*cmd)) { // '+' is '+1' n = 1; } else { + // "number", "+number" or "-number" n = getdigits_int32(&cmd, false, MAXLNUM); if (n == MAXLNUM) { emsg(_(e_line_number_out_of_range)); @@ -3459,8 +3504,8 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int } else if (addr_type == ADDR_LOADED_BUFFERS || addr_type == ADDR_BUFFERS) { lnum = compute_buffer_local_count(addr_type, lnum, (i == '-') ? -1 * n : n); } else { - // Relative line addressing, need to adjust for folded lines - // now, but only do it after the first address. + // Relative line addressing: need to adjust for lines in a + // closed fold after the first address. if (addr_type == ADDR_LINES && (i == '-' || i == '+') && address_count >= 2) { (void)hasFolding(lnum, NULL, &lnum); @@ -3653,7 +3698,7 @@ char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep) // Don't do it when ":vimgrep" is used for ":grep". if ((eap->cmdidx == CMD_make || eap->cmdidx == CMD_lmake || isgrep) && !grep_internal(eap->cmdidx)) { - const char *program = isgrep ? (*curbuf->b_p_gp == NUL ? (char *)p_gp : curbuf->b_p_gp) + const char *program = isgrep ? (*curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) : (*curbuf->b_p_mp == NUL ? (char *)p_mp : curbuf->b_p_mp); arg = skipwhite(arg); @@ -3662,7 +3707,7 @@ char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep) // Replace $* by given arguments if ((new_cmdline = strrep(program, "$*", arg)) == NULL) { // No $* in arg, build "<makeprg> <arg>" instead - new_cmdline = xmalloc(STRLEN(program) + STRLEN(arg) + 2); + new_cmdline = xmalloc(strlen(program) + strlen(arg) + 2); STRCPY(new_cmdline, program); STRCAT(new_cmdline, " "); STRCAT(new_cmdline, arg); @@ -3690,7 +3735,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) // Decide to expand wildcards *before* replacing '%', '#', etc. If // the file name contains a wildcard it should not cause expanding. // (it will be expanded anyway if there is a wildcard before replacing). - int has_wildcards = path_has_wildcard((char_u *)p); + int has_wildcards = path_has_wildcard(p); while (*p != NUL) { // Skip over `=expr`, wildcards in it are not expanded. if (p[0] == '`' && p[1] == '=') { @@ -3739,7 +3784,6 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) && eap->cmdidx != CMD_bang && eap->cmdidx != CMD_grep && eap->cmdidx != CMD_grepadd - && eap->cmdidx != CMD_hardcopy && eap->cmdidx != CMD_lgrep && eap->cmdidx != CMD_lgrepadd && eap->cmdidx != CMD_lmake @@ -3758,7 +3802,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) for (l = repl; *l; l++) { if (vim_strchr((char *)ESCAPE_CHARS, *l) != NULL) { - l = (char *)vim_strsave_escaped((char_u *)repl, ESCAPE_CHARS); + l = vim_strsave_escaped(repl, (char *)ESCAPE_CHARS); xfree(repl); repl = l; break; @@ -3773,7 +3817,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) && strpbrk(repl, "!") != NULL) { char *l; - l = (char *)vim_strsave_escaped((char_u *)repl, (char_u *)"!"); + l = vim_strsave_escaped(repl, "!"); xfree(repl); repl = l; } @@ -3794,14 +3838,14 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) // if there are still wildcards present. if (vim_strchr(eap->arg, '$') != NULL || vim_strchr(eap->arg, '~') != NULL) { - expand_env_esc((char_u *)eap->arg, (char_u *)NameBuff, MAXPATHL, true, true, NULL); - has_wildcards = path_has_wildcard((char_u *)NameBuff); - p = (char *)NameBuff; + expand_env_esc(eap->arg, NameBuff, MAXPATHL, true, true, NULL); + has_wildcards = path_has_wildcard(NameBuff); + p = NameBuff; } else { p = NULL; } if (p != NULL) { - (void)repl_cmdline(eap, eap->arg, STRLEN(eap->arg), p, cmdlinep); + (void)repl_cmdline(eap, eap->arg, strlen(eap->arg), p, cmdlinep); } } @@ -3825,11 +3869,11 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) if (p_wic) { options += WILD_ICASE; } - p = (char *)ExpandOne(&xpc, (char_u *)eap->arg, NULL, options, WILD_EXPAND_FREE); + p = ExpandOne(&xpc, eap->arg, NULL, options, WILD_EXPAND_FREE); if (p == NULL) { return FAIL; } - (void)repl_cmdline(eap, eap->arg, STRLEN(eap->arg), p, cmdlinep); + (void)repl_cmdline(eap, eap->arg, strlen(eap->arg), p, cmdlinep); xfree(p); } } @@ -3847,10 +3891,10 @@ static char *repl_cmdline(exarg_T *eap, char *src, size_t srclen, char *repl, ch // The new command line is build in new_cmdline[]. // First allocate it. // Careful: a "+cmd" argument may have been NUL terminated. - size_t len = STRLEN(repl); - size_t i = (size_t)(src - *cmdlinep) + STRLEN(src + srclen) + len + 3; + size_t len = strlen(repl); + size_t i = (size_t)(src - *cmdlinep) + strlen(src + srclen) + len + 3; if (eap->nextcmd != NULL) { - i += STRLEN(eap->nextcmd); // add space for next command + i += strlen(eap->nextcmd); // add space for next command } char *new_cmdline = xmalloc(i); size_t offset = (size_t)(src - *cmdlinep); @@ -3868,7 +3912,7 @@ static char *repl_cmdline(exarg_T *eap, char *src, size_t srclen, char *repl, ch src = new_cmdline + i; // remember where to continue if (eap->nextcmd != NULL) { // append next command - i = STRLEN(new_cmdline) + 1; + i = strlen(new_cmdline) + 1; STRCPY(new_cmdline + i, eap->nextcmd); eap->nextcmd = new_cmdline + i; } @@ -3883,7 +3927,7 @@ static char *repl_cmdline(exarg_T *eap, char *src, size_t srclen, char *repl, ch } else { // Otherwise, argument gets shifted alongside the replaced text. // The amount of the shift is equal to the difference of the old and new string length. - eap->args[j] = new_cmdline + (eap->args[j] - *cmdlinep) + (len - srclen); + eap->args[j] = new_cmdline + ((eap->args[j] - *cmdlinep) + (ptrdiff_t)(len - srclen)); } } @@ -3935,7 +3979,7 @@ void separate_nextcmd(exarg_T *eap) STRMOVE(p - 1, p); // remove the '\' p--; } else { - eap->nextcmd = (char *)check_nextcmd((char_u *)p); + eap->nextcmd = check_nextcmd(p); *p = NUL; break; } @@ -3943,7 +3987,7 @@ void separate_nextcmd(exarg_T *eap) } if (!(eap->argt & EX_NOTRLCOM)) { // remove trailing spaces - del_trailing_spaces((char_u *)eap->arg); + del_trailing_spaces(eap->arg); } } @@ -4014,7 +4058,7 @@ static int getargopt(exarg_T *eap) int bad_char_idx; // ":edit ++[no]bin[ary] file" - if (STRNCMP(arg, "bin", 3) == 0 || STRNCMP(arg, "nobin", 5) == 0) { + if (strncmp(arg, "bin", 3) == 0 || strncmp(arg, "nobin", 5) == 0) { if (*arg == 'n') { arg += 2; eap->force_bin = FORCE_NOBIN; @@ -4029,26 +4073,33 @@ static int getargopt(exarg_T *eap) } // ":read ++edit file" - if (STRNCMP(arg, "edit", 4) == 0) { + if (strncmp(arg, "edit", 4) == 0) { eap->read_edit = true; eap->arg = skipwhite(arg + 4); return OK; } - if (STRNCMP(arg, "ff", 2) == 0) { + // ":write ++p foo/bar/file + if (strncmp(arg, "p", 1) == 0) { + eap->mkdir_p = true; + eap->arg = skipwhite(arg + 1); + return OK; + } + + if (strncmp(arg, "ff", 2) == 0) { arg += 2; pp = &eap->force_ff; - } else if (STRNCMP(arg, "fileformat", 10) == 0) { + } else if (strncmp(arg, "fileformat", 10) == 0) { arg += 10; pp = &eap->force_ff; - } else if (STRNCMP(arg, "enc", 3) == 0) { - if (STRNCMP(arg, "encoding", 8) == 0) { + } else if (strncmp(arg, "enc", 3) == 0) { + if (strncmp(arg, "encoding", 8) == 0) { arg += 8; } else { arg += 3; } pp = &eap->force_enc; - } else if (STRNCMP(arg, "bad", 3) == 0) { + } else if (strncmp(arg, "bad", 3) == 0) { arg += 3; pp = &bad_char_idx; } @@ -4110,9 +4161,9 @@ static int get_tabpage_arg(exarg_T *eap) tab_number = (int)getdigits(&p, false, tab_number); if (relative == 0) { - if (STRCMP(p, "$") == 0) { + if (strcmp(p, "$") == 0) { tab_number = LAST_TAB_NR; - } else if (STRCMP(p, "#") == 0) { + } else if (strcmp(p, "#") == 0) { if (valid_tabpage(lastused_tabpage)) { tab_number = tabpage_index(lastused_tabpage); } else { @@ -4179,13 +4230,12 @@ theend: static void ex_autocmd(exarg_T *eap) { - // Disallow autocommands from .exrc and .vimrc in current - // directory for security reasons. + // Disallow autocommands in secure mode. if (secure) { secure = 2; eap->errmsg = _(e_curdir); } else if (eap->cmdidx == CMD_autocmd) { - do_autocmd(eap->arg, eap->forceit); + do_autocmd(eap, eap->arg, eap->forceit); } else { do_augroup(eap->arg, eap->forceit); } @@ -4312,15 +4362,14 @@ char *find_nextcmd(const char *p) /// Check if *p is a separator between Ex commands, skipping over white space. /// /// @return NULL if it isn't, the following character if it is. -char_u *check_nextcmd(char_u *p) +char *check_nextcmd(char *p) { - char *s = skipwhite((char *)p); + char *s = skipwhite(p); if (*s == '|' || *s == '\n') { - return (char_u *)(s + 1); - } else { - return NULL; + return s + 1; } + return NULL; } /// - if there are more files to edit @@ -4343,14 +4392,14 @@ static int check_more(int message, bool forceit) vim_snprintf((char *)buff, DIALOG_MSG_SIZE, NGETTEXT("%d more file to edit. Quit anyway?", - "%d more files to edit. Quit anyway?", (unsigned long)n), n); - if (vim_dialog_yesno(VIM_QUESTION, NULL, (char_u *)buff, 1) == VIM_YES) { + "%d more files to edit. Quit anyway?", n), n); + if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES) { return OK; } return FAIL; } semsg(NGETTEXT("E173: %" PRId64 " more file to edit", - "E173: %" PRId64 " more files to edit", (unsigned long)n), (int64_t)n); + "E173: %" PRId64 " more files to edit", n), (int64_t)n); quitmore = 2; // next try to quit is allowed } return FAIL; @@ -4383,7 +4432,7 @@ static void ex_colorscheme(exarg_T *eap) } else { msg("default"); } - } else if (load_colors((char_u *)eap->arg) == FAIL) { + } else if (load_colors(eap->arg) == FAIL) { semsg(_("E185: Cannot find color scheme '%s'"), eap->arg); } } @@ -4578,7 +4627,7 @@ static void ex_pclose(exarg_T *eap) void ex_win_close(int forceit, win_T *win, tabpage_T *tp) { // Never close the autocommand window. - if (win == aucmd_win) { + if (is_aucmd_win(win)) { emsg(_(e_autocmd_close)); return; } @@ -4615,23 +4664,29 @@ static void ex_tabclose(exarg_T *eap) { if (cmdwin_type != 0) { cmdwin_result = K_IGNORE; - } else if (first_tabpage->tp_next == NULL) { + return; + } + + if (first_tabpage->tp_next == NULL) { emsg(_("E784: Cannot close last tab page")); - } else { - int tab_number = get_tabpage_arg(eap); - if (eap->errmsg == NULL) { - tabpage_T *tp = find_tabpage(tab_number); - if (tp == NULL) { - beep_flush(); - return; - } - if (tp != curtab) { - tabpage_close_other(tp, eap->forceit); - return; - } else if (!text_locked() && !curbuf_locked()) { - tabpage_close(eap->forceit); - } - } + return; + } + + int tab_number = get_tabpage_arg(eap); + if (eap->errmsg != NULL) { + return; + } + + tabpage_T *tp = find_tabpage(tab_number); + if (tp == NULL) { + beep_flush(); + return; + } + if (tp != curtab) { + tabpage_close_other(tp, eap->forceit); + return; + } else if (!text_locked() && !curbuf_locked()) { + tabpage_close(eap->forceit); } } @@ -4640,32 +4695,38 @@ static void ex_tabonly(exarg_T *eap) { if (cmdwin_type != 0) { cmdwin_result = K_IGNORE; - } else if (first_tabpage->tp_next == NULL) { + return; + } + + if (first_tabpage->tp_next == NULL) { msg(_("Already only one tab page")); - } else { - int tab_number = get_tabpage_arg(eap); - if (eap->errmsg == NULL) { - goto_tabpage(tab_number); - // Repeat this up to a 1000 times, because autocommands may - // mess up the lists. - for (int done = 0; done < 1000; done++) { - FOR_ALL_TABS(tp) { - if (tp->tp_topframe != topframe) { - tabpage_close_other(tp, eap->forceit); - // if we failed to close it quit - if (valid_tabpage(tp)) { - done = 1000; - } - // start over, "tp" is now invalid - break; - } - } - assert(first_tabpage); - if (first_tabpage->tp_next == NULL) { - break; + return; + } + + int tab_number = get_tabpage_arg(eap); + if (eap->errmsg != NULL) { + return; + } + + goto_tabpage(tab_number); + // Repeat this up to a 1000 times, because autocommands may + // mess up the lists. + for (int done = 0; done < 1000; done++) { + FOR_ALL_TABS(tp) { + if (tp->tp_topframe != topframe) { + tabpage_close_other(tp, eap->forceit); + // if we failed to close it quit + if (valid_tabpage(tp)) { + done = 1000; } + // start over, "tp" is now invalid + break; } } + assert(first_tabpage); + if (first_tabpage->tp_next == NULL) { + break; + } } } @@ -4692,7 +4753,6 @@ void tabpage_close(int forceit) void tabpage_close_other(tabpage_T *tp, int forceit) { int done = 0; - int h = tabline_height(); char prev_idx[NUMBUFLEN]; // Limit to 1000 windows, autocommands may add a window while we close @@ -4708,11 +4768,6 @@ void tabpage_close_other(tabpage_T *tp, int forceit) break; } } - - redraw_tabline = true; - if (h != tabline_height()) { - win_new_screen_rows(); - } } /// ":only". @@ -4725,9 +4780,8 @@ static void ex_only(exarg_T *eap) for (wp = firstwin; --wnr > 0;) { if (wp->w_next == NULL) { break; - } else { - wp = wp->w_next; } + wp = wp->w_next; } } else { wp = curwin; @@ -4741,25 +4795,27 @@ static void ex_only(exarg_T *eap) static void ex_hide(exarg_T *eap) { // ":hide" or ":hide | cmd": hide current window - if (!eap->skip) { - if (eap->addr_count == 0) { - win_close(curwin, false, eap->forceit); // don't free buffer - } else { - int winnr = 0; - win_T *win = NULL; + if (eap->skip) { + return; + } - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - winnr++; - if (winnr == eap->line2) { - win = wp; - break; - } - } - if (win == NULL) { - win = lastwin; + if (eap->addr_count == 0) { + win_close(curwin, false, eap->forceit); // don't free buffer + } else { + int winnr = 0; + win_T *win = NULL; + + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + winnr++; + if (winnr == eap->line2) { + win = wp; + break; } - win_close(win, false, eap->forceit); } + if (win == NULL) { + win = lastwin; + } + win_close(win, false, eap->forceit); } } @@ -4834,7 +4890,6 @@ static void ex_print(exarg_T *eap) if (++eap->line1 > eap->line2) { break; } - ui_flush(); // show one line at a time } setpcmark(); // put cursor at last line @@ -4910,8 +4965,8 @@ void ex_splitview(exarg_T *eap) } if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) { - fname = (char *)find_file_in_path((char_u *)eap->arg, STRLEN(eap->arg), - FNAME_MESS, true, (char_u *)curbuf->b_ffname); + fname = (char *)find_file_in_path(eap->arg, strlen(eap->arg), + FNAME_MESS, true, curbuf->b_ffname); if (fname == NULL) { goto theend; } @@ -5034,9 +5089,8 @@ static void ex_tabs(exarg_T *eap) } msg_putchar('\n'); - vim_snprintf((char *)IObuff, IOSIZE, _("Tab page %d"), tabcount++); - msg_outtrans_attr((char *)IObuff, HL_ATTR(HLF_T)); - ui_flush(); // output one line at a time + vim_snprintf(IObuff, IOSIZE, _("Tab page %d"), tabcount++); + msg_outtrans_attr(IObuff, HL_ATTR(HLF_T)); os_breakcheck(); FOR_ALL_WINDOWS_IN_TAB(wp, tp) { @@ -5050,12 +5104,11 @@ static void ex_tabs(exarg_T *eap) msg_putchar(bufIsChanged(wp->w_buffer) ? '+' : ' '); msg_putchar(' '); if (buf_spname(wp->w_buffer) != NULL) { - STRLCPY(IObuff, buf_spname(wp->w_buffer), IOSIZE); + xstrlcpy(IObuff, buf_spname(wp->w_buffer), IOSIZE); } else { - home_replace(wp->w_buffer, wp->w_buffer->b_fname, (char *)IObuff, IOSIZE, true); + home_replace(wp->w_buffer, wp->w_buffer->b_fname, IObuff, IOSIZE, true); } - msg_outtrans((char *)IObuff); - ui_flush(); // output one line at a time + msg_outtrans(IObuff); os_breakcheck(); } } @@ -5105,23 +5158,25 @@ static void ex_resize(exarg_T *eap) /// ":find [+command] <file>" command. static void ex_find(exarg_T *eap) { - char *fname = (char *)find_file_in_path((char_u *)eap->arg, STRLEN(eap->arg), - FNAME_MESS, true, (char_u *)curbuf->b_ffname); + char *fname = (char *)find_file_in_path(eap->arg, strlen(eap->arg), + FNAME_MESS, true, curbuf->b_ffname); if (eap->addr_count > 0) { // Repeat finding the file "count" times. This matters when it // appears several times in the path. linenr_T count = eap->line2; while (fname != NULL && --count > 0) { xfree(fname); - fname = (char *)find_file_in_path(NULL, 0, FNAME_MESS, false, (char_u *)curbuf->b_ffname); + fname = (char *)find_file_in_path(NULL, 0, FNAME_MESS, false, curbuf->b_ffname); } } - if (fname != NULL) { - eap->arg = fname; - do_exedit(eap, NULL); - xfree(fname); + if (fname == NULL) { + return; } + + eap->arg = fname; + do_exedit(eap, NULL); + xfree(fname); } /// ":edit", ":badd", ":balt", ":visual". @@ -5183,7 +5238,7 @@ void do_exedit(exarg_T *eap, win_T *old_curwin) old_curwin == NULL ? curwin : NULL); } else if ((eap->cmdidx != CMD_split && eap->cmdidx != CMD_vsplit) || *eap->arg != NUL) { - // Can't edit another file when "curbuf->b_ro_lockec" is set. Only ":edit" + // Can't edit another file when "curbuf->b_ro_locked" is set. Only ":edit" // can bring us here, others are stopped earlier. if (*eap->arg != NUL && curbuf_locked()) { return; @@ -5273,7 +5328,7 @@ static void ex_swapname(exarg_T *eap) if (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_mfp->mf_fname == NULL) { msg(_("No swap file")); } else { - msg((char *)curbuf->b_ml.ml_mfp->mf_fname); + msg(curbuf->b_ml.ml_mfp->mf_fname); } } @@ -5346,50 +5401,51 @@ static void ex_read(exarg_T *eap) if (eap->usefilter) { // :r!cmd do_bang(1, eap, false, false, true); - } else { - if (u_save(eap->line2, (linenr_T)(eap->line2 + 1)) == FAIL) { + return; + } + + if (u_save(eap->line2, (linenr_T)(eap->line2 + 1)) == FAIL) { + return; + } + + int i; + if (*eap->arg == NUL) { + if (check_fname() == FAIL) { // check for no file name return; } - int i; - - if (*eap->arg == NUL) { - if (check_fname() == FAIL) { // check for no file name - return; - } - i = readfile(curbuf->b_ffname, curbuf->b_fname, - eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0, false); - } else { - if (vim_strchr(p_cpo, CPO_ALTREAD) != NULL) { - (void)setaltfname(eap->arg, eap->arg, (linenr_T)1); - } - i = readfile(eap->arg, NULL, - eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0, false); + i = readfile(curbuf->b_ffname, curbuf->b_fname, + eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0, false); + } else { + if (vim_strchr(p_cpo, CPO_ALTREAD) != NULL) { + (void)setaltfname(eap->arg, eap->arg, (linenr_T)1); + } + i = readfile(eap->arg, NULL, + eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0, false); + } + if (i != OK) { + if (!aborting()) { + semsg(_(e_notopen), eap->arg); } - if (i != OK) { - if (!aborting()) { - semsg(_(e_notopen), eap->arg); + } else { + if (empty && exmode_active) { + // Delete the empty line that remains. Historically ex does + // this but vi doesn't. + linenr_T lnum; + if (eap->line2 == 0) { + lnum = curbuf->b_ml.ml_line_count; + } else { + lnum = 1; } - } else { - if (empty && exmode_active) { - // Delete the empty line that remains. Historically ex does - // this but vi doesn't. - linenr_T lnum; - if (eap->line2 == 0) { - lnum = curbuf->b_ml.ml_line_count; - } else { - lnum = 1; - } - if (*ml_get(lnum) == NUL && u_savedel(lnum, 1L) == OK) { - ml_delete(lnum, false); - if (curwin->w_cursor.lnum > 1 - && curwin->w_cursor.lnum >= lnum) { - curwin->w_cursor.lnum--; - } - deleted_lines_mark(lnum, 1L); + if (*ml_get(lnum) == NUL && u_savedel(lnum, 1L) == OK) { + ml_delete(lnum, false); + if (curwin->w_cursor.lnum > 1 + && curwin->w_cursor.lnum >= lnum) { + curwin->w_cursor.lnum--; } + deleted_lines_mark(lnum, 1L); } - redraw_curbuf_later(UPD_VALID); } + redraw_curbuf_later(UPD_VALID); } } @@ -5441,7 +5497,7 @@ static void post_chdir(CdScope scope, bool trigger_dirchanged) } char cwd[MAXPATHL]; - if (os_dirname((char_u *)cwd, MAXPATHL) != OK) { + if (os_dirname(cwd, MAXPATHL) != OK) { return; } switch (scope) { @@ -5479,7 +5535,7 @@ bool changedir_func(char *new_dir, CdScope scope) char *pdir = NULL; // ":cd -": Change to previous directory - if (STRCMP(new_dir, "-") == 0) { + if (strcmp(new_dir, "-") == 0) { pdir = get_prevdir(scope); if (pdir == NULL) { emsg(_("E186: No previous directory")); @@ -5488,7 +5544,7 @@ bool changedir_func(char *new_dir, CdScope scope) new_dir = pdir; } - if (os_dirname((char_u *)NameBuff, MAXPATHL) == OK) { + if (os_dirname(NameBuff, MAXPATHL) == OK) { pdir = xstrdup(NameBuff); } else { pdir = NULL; @@ -5503,13 +5559,13 @@ bool changedir_func(char *new_dir, CdScope scope) #endif // Use NameBuff for home directory name. expand_env("$HOME", NameBuff, MAXPATHL); - new_dir = (char *)NameBuff; + new_dir = NameBuff; } bool dir_differs = pdir == NULL || pathcmp(pdir, new_dir, -1) != 0; if (dir_differs) { do_autocmd_dirchanged(new_dir, scope, kCdCauseManual, true); - if (vim_chdir((char_u *)new_dir) != 0) { + if (vim_chdir(new_dir) != 0) { emsg(_(e_failed)); xfree(pdir); return false; @@ -5543,27 +5599,27 @@ void ex_cd(exarg_T *eap) // for non-UNIX ":cd" means: print current directory unless 'cdhome' is set if (*new_dir == NUL && !p_cdh) { ex_pwd(NULL); - } else + return; + } #endif - { - CdScope scope = kCdScopeGlobal; - switch (eap->cmdidx) { - case CMD_tcd: - case CMD_tchdir: - scope = kCdScopeTabpage; - break; - case CMD_lcd: - case CMD_lchdir: - scope = kCdScopeWindow; - break; - default: - break; - } - if (changedir_func(new_dir, scope)) { - // Echo the new current directory if the command was typed. - if (KeyTyped || p_verbose >= 5) { - ex_pwd(eap); - } + + CdScope scope = kCdScopeGlobal; + switch (eap->cmdidx) { + case CMD_tcd: + case CMD_tchdir: + scope = kCdScopeTabpage; + break; + case CMD_lcd: + case CMD_lchdir: + scope = kCdScopeWindow; + break; + default: + break; + } + if (changedir_func(new_dir, scope)) { + // Echo the new current directory if the command was typed. + if (KeyTyped || p_verbose >= 5) { + ex_pwd(eap); } } } @@ -5571,7 +5627,7 @@ void ex_cd(exarg_T *eap) /// ":pwd". static void ex_pwd(exarg_T *eap) { - if (os_dirname((char_u *)NameBuff, MAXPATHL) == OK) { + if (os_dirname(NameBuff, MAXPATHL) == OK) { #ifdef BACKSLASH_IN_FILENAME slash_adjust(NameBuff); #endif @@ -5584,9 +5640,9 @@ static void ex_pwd(exarg_T *eap) } else if (curtab->tp_localdir != NULL) { context = "tabpage"; } - smsg("[%s] %s", context, (char *)NameBuff); + smsg("[%s] %s", context, NameBuff); } else { - msg((char *)NameBuff); + msg(NameBuff); } } else { emsg(_("E187: Unknown")); @@ -5621,15 +5677,11 @@ static void ex_sleep(exarg_T *eap) do_sleep(len); } -/// Sleep for "msec" milliseconds, but keep checking for a CTRL-C every second. +/// Sleep for "msec" milliseconds, but return early on CTRL-C. void do_sleep(long msec) { ui_flush(); // flush before waiting - for (long left = msec; !got_int && left > 0; left -= 1000L) { - int next = left > 1000l ? 1000 : (int)left; - LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, (int)next, got_int); - os_breakcheck(); - } + LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, msec, got_int); // If CTRL-C was typed to interrupt the sleep, drop the CTRL-C from the // input buffer, otherwise a following call to input() fails. @@ -5675,7 +5727,7 @@ static void ex_wincmd(exarg_T *eap) p = eap->arg + 1; } - eap->nextcmd = (char *)check_nextcmd((char_u *)p); + eap->nextcmd = check_nextcmd(p); p = skipwhite(p); if (*p != NUL && *p != '"' && eap->nextcmd == NULL) { emsg(_(e_invarg)); @@ -5791,21 +5843,21 @@ void ex_may_print(exarg_T *eap) /// ":smagic" and ":snomagic". static void ex_submagic(exarg_T *eap) { - int magic_save = p_magic; + const optmagic_T saved = magic_overruled; - p_magic = (eap->cmdidx == CMD_smagic); + magic_overruled = eap->cmdidx == CMD_smagic ? OPTION_MAGIC_ON : OPTION_MAGIC_OFF; ex_substitute(eap); - p_magic = magic_save; + magic_overruled = saved; } /// ":smagic" and ":snomagic" preview callback. static int ex_submagic_preview(exarg_T *eap, long cmdpreview_ns, handle_T cmdpreview_bufnr) { - int magic_save = p_magic; + const optmagic_T saved = magic_overruled; - p_magic = (eap->cmdidx == CMD_smagic); + magic_overruled = eap->cmdidx == CMD_smagic ? OPTION_MAGIC_ON : OPTION_MAGIC_OFF; int retv = ex_substitute_preview(eap, cmdpreview_ns, cmdpreview_bufnr); - p_magic = magic_save; + magic_overruled = saved; return retv; } @@ -5846,20 +5898,21 @@ static void ex_at(exarg_T *eap) // Put the register in the typeahead buffer with the "silent" flag. if (do_execreg(c, true, vim_strchr(p_cpo, CPO_EXECBUF) != NULL, true) == FAIL) { beep_flush(); - } else { - bool save_efr = exec_from_reg; + return; + } - exec_from_reg = true; + const bool save_efr = exec_from_reg; - // Execute from the typeahead buffer. - // Continue until the stuff buffer is empty and all added characters - // have been consumed. - while (!stuff_empty() || typebuf.tb_len > prev_len) { - (void)do_cmdline(NULL, getexline, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE); - } + exec_from_reg = true; - exec_from_reg = save_efr; + // Execute from the typeahead buffer. + // Continue until the stuff buffer is empty and all added characters + // have been consumed. + while (!stuff_empty() || typebuf.tb_len > prev_len) { + (void)do_cmdline(NULL, getexline, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE); } + + exec_from_reg = save_efr; } /// ":!". @@ -5873,7 +5926,7 @@ static void ex_undo(exarg_T *eap) { if (eap->addr_count != 1) { if (eap->forceit) { - u_undo_and_forget(1); // :undo! + u_undo_and_forget(1, true); // :undo! } else { u_undo(1); // :undo } @@ -5900,7 +5953,7 @@ static void ex_undo(exarg_T *eap) emsg(_(e_undobang_cannot_redo_or_move_branch)); return; } - u_undo_and_forget(count); + u_undo_and_forget(count, true); } else { // :undo 123 undo_time(step, false, false, true); } @@ -5989,7 +6042,7 @@ static void ex_redir(exarg_T *eap) return; } - redir_fd = open_exfile((char_u *)fname, eap->forceit, mode); + redir_fd = open_exfile(fname, eap->forceit, mode); xfree(fname); } else if (*arg == '@') { // redirect to a register a-z (resp. A-Z for appending) @@ -6007,7 +6060,7 @@ static void ex_redir(exarg_T *eap) // Make register empty when not using @A-@Z and the // command is valid. if (*arg == NUL && !isupper(redir_reg)) { - write_reg_contents(redir_reg, (char_u *)"", 0, false); + write_reg_contents(redir_reg, "", 0, false); } } } @@ -6061,9 +6114,10 @@ static void ex_redraw(exarg_T *eap) if (eap->forceit) { redraw_all_later(UPD_NOT_VALID); redraw_cmdline = true; + } else if (VIsual_active) { + redraw_curbuf_later(UPD_INVERTED); } - update_screen(eap->forceit ? UPD_NOT_VALID - : VIsual_active ? UPD_INVERTED : 0); + update_screen(); if (need_maketitle) { maketitle(); } @@ -6089,14 +6143,22 @@ static void ex_redrawstatus(exarg_T *eap) int r = RedrawingDisabled; int p = p_lz; - RedrawingDisabled = 0; - p_lz = false; if (eap->forceit) { status_redraw_all(); } else { status_redraw_curbuf(); } - update_screen(VIsual_active ? UPD_INVERTED : 0); + + RedrawingDisabled = 0; + p_lz = false; + if (State & MODE_CMDLINE) { + redraw_statuslines(); + } else { + if (VIsual_active) { + redraw_curbuf_later(UPD_INVERTED); + } + update_screen(); + } RedrawingDisabled = r; p_lz = p; ui_flush(); @@ -6153,11 +6215,11 @@ int vim_mkdir_emsg(const char *const name, const int prot) /// @param mode "w" for create new file or "a" for append /// /// @return file descriptor, or NULL on failure. -FILE *open_exfile(char_u *fname, int forceit, char *mode) +FILE *open_exfile(char *fname, int forceit, char *mode) { #ifdef UNIX // with Unix it is possible to open a directory - if (os_isdir((char *)fname)) { + if (os_isdir(fname)) { semsg(_(e_isadir2), fname); return NULL; } @@ -6168,7 +6230,7 @@ FILE *open_exfile(char_u *fname, int forceit, char *mode) } FILE *fd; - if ((fd = os_fopen((char *)fname, mode)) == NULL) { + if ((fd = os_fopen(fname, mode)) == NULL) { semsg(_("E190: Cannot open \"%s\" for writing"), fname); } @@ -6180,17 +6242,21 @@ static void ex_mark(exarg_T *eap) { if (*eap->arg == NUL) { // No argument? emsg(_(e_argreq)); - } else if (eap->arg[1] != NUL) { // more than one character? + return; + } + + if (eap->arg[1] != NUL) { // more than one character? semsg(_(e_trailing_arg), eap->arg); - } else { - pos_T pos = curwin->w_cursor; // save curwin->w_cursor - curwin->w_cursor.lnum = eap->line2; - beginline(BL_WHITE | BL_FIX); - if (setmark(*eap->arg) == FAIL) { // set mark - emsg(_("E191: Argument must be a letter or forward/backward quote")); - } - curwin->w_cursor = pos; // restore curwin->w_cursor + return; } + + pos_T pos = curwin->w_cursor; // save curwin->w_cursor + curwin->w_cursor.lnum = eap->line2; + beginline(BL_WHITE | BL_FIX); + if (setmark(*eap->arg) == FAIL) { // set mark + emsg(_("E191: Argument must be a letter or forward/backward quote")); + } + curwin->w_cursor = pos; // restore curwin->w_cursor } /// Update w_topline, w_leftcol and the cursor position. @@ -6292,7 +6358,7 @@ static void ex_normal(exarg_T *eap) } } if (len > 0) { - arg = xmalloc(STRLEN(eap->arg) + (size_t)len + 1); + arg = xmalloc(strlen(eap->arg) + (size_t)len + 1); len = 0; for (p = eap->arg; *p != NUL; p++) { arg[len++] = *p; @@ -6321,7 +6387,7 @@ static void ex_normal(exarg_T *eap) check_cursor_moved(curwin); } - exec_normal_cmd((char_u *)(arg != NULL ? arg : eap->arg), + exec_normal_cmd((arg != NULL ? arg : eap->arg), eap->forceit ? REMAP_NONE : REMAP_YES, false); } while (eap->addr_count > 0 && eap->line1 <= eap->line2 && !got_int); } @@ -6385,10 +6451,10 @@ static void ex_stopinsert(exarg_T *eap) /// Execute normal mode command "cmd". /// "remap" can be REMAP_NONE or REMAP_YES. -void exec_normal_cmd(char_u *cmd, int remap, bool silent) +void exec_normal_cmd(char *cmd, int remap, bool silent) { // Stuff the argument into the typeahead buffer. - ins_typebuf((char *)cmd, remap, 0, true, silent); + ins_typebuf(cmd, remap, 0, true, silent); exec_normal(false); } @@ -6457,7 +6523,7 @@ static void ex_findpat(exarg_T *eap) if (*eap->arg == '/') { // Match regexp, not just whole words whole = false; eap->arg++; - char *p = skip_regexp(eap->arg, '/', p_magic, NULL); + char *p = skip_regexp(eap->arg, '/', magic_isset()); if (*p) { *p++ = NUL; p = skipwhite(p); @@ -6466,12 +6532,12 @@ static void ex_findpat(exarg_T *eap) if (!ends_excmd(*p)) { eap->errmsg = ex_errmsg(e_trailing_arg, p); } else { - eap->nextcmd = (char *)check_nextcmd((char_u *)p); + eap->nextcmd = check_nextcmd(p); } } } if (!eap->skip) { - find_pattern_in_path((char_u *)eap->arg, 0, STRLEN(eap->arg), whole, !eap->forceit, + find_pattern_in_path(eap->arg, 0, strlen(eap->arg), whole, !eap->forceit, *eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY, n, action, eap->line1, eap->line2); } @@ -6522,7 +6588,7 @@ static void ex_tag(exarg_T *eap) ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name); } -static void ex_tag_cmd(exarg_T *eap, char *name) +static void ex_tag_cmd(exarg_T *eap, const char *name) { int cmd; @@ -6551,10 +6617,6 @@ static void ex_tag_cmd(exarg_T *eap, char *name) cmd = DT_LAST; // ":tlast" break; default: // ":tag" - if (p_cst && *eap->arg != NUL) { - ex_cstag(eap); - return; - } cmd = DT_TAG; break; } @@ -6563,7 +6625,7 @@ static void ex_tag_cmd(exarg_T *eap, char *name) cmd = DT_LTAG; } - do_tag((char_u *)eap->arg, cmd, eap->addr_count > 0 ? (int)eap->line2 : 1, + do_tag(eap->arg, cmd, eap->addr_count > 0 ? (int)eap->line2 : 1, eap->forceit, true); } @@ -6589,7 +6651,7 @@ enum { /// Check "str" for starting with a special cmdline variable. /// If found return one of the SPEC_ values and set "*usedlen" to the length of /// the variable. Otherwise return -1 and "*usedlen" is unchanged. -ssize_t find_cmdline_var(const char_u *src, size_t *usedlen) +ssize_t find_cmdline_var(const char *src, size_t *usedlen) FUNC_ATTR_NONNULL_ALL { static char *(spec_str[]) = { @@ -6612,8 +6674,8 @@ ssize_t find_cmdline_var(const char_u *src, size_t *usedlen) }; for (size_t i = 0; i < ARRAY_SIZE(spec_str); i++) { - size_t len = STRLEN(spec_str[i]); - if (STRNCMP(src, spec_str[i], len) == 0) { + size_t len = strlen(spec_str[i]); + if (strncmp(src, spec_str[i], len) == 0) { *usedlen = len; assert(i <= SSIZE_MAX); return (ssize_t)i; @@ -6652,8 +6714,8 @@ ssize_t find_cmdline_var(const char_u *src, size_t *usedlen) /// @return an allocated string if a valid match was found. /// Returns NULL if no match was found. "usedlen" then still contains the /// number of characters to skip. -char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnump, char **errormsg, - int *escaped, bool empty_is_error) +char_u *eval_vars(char_u *src, const char_u *srcstart, size_t *usedlen, linenr_T *lnump, + char **errormsg, int *escaped, bool empty_is_error) { char *result; char *resultbuf = NULL; @@ -6669,7 +6731,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum } // Check if there is something to do. - ssize_t spec_idx = find_cmdline_var(src, usedlen); + ssize_t spec_idx = find_cmdline_var((char *)src, usedlen); if (spec_idx < 0) { // no match *usedlen = 1; return NULL; @@ -6679,7 +6741,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum // Note: In "\\%" the % is also not recognized! if (src > srcstart && src[-1] == '\\') { *usedlen = 0; - STRMOVE(src - 1, src); // remove backslash + STRMOVE(src - 1, (char *)src); // remove backslash return NULL; } @@ -6712,7 +6774,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum valid = 0; // Must have ":p:h" to be valid } else { result = curbuf->b_fname; - tilde_file = STRCMP(result, "~") == 0; + tilde_file = strcmp(result, "~") == 0; } break; @@ -6766,7 +6828,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum valid = 0; // Must have ":p:h" to be valid } else { result = buf->b_fname; - tilde_file = STRCMP(result, "~") == 0; + tilde_file = strcmp(result, "~") == 0; } } break; @@ -6789,7 +6851,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum // postponed to avoid a delay when <afile> is not used. result = FullName_save(autocmd_fname, false); // Copy into `autocmd_fname`, don't reassign it. #8165 - STRLCPY(autocmd_fname, result, MAXPATHL); + xstrlcpy(autocmd_fname, result, MAXPATHL); xfree(result); } result = autocmd_fname; @@ -6797,7 +6859,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum *errormsg = _("E495: no autocommand file name to substitute for \"<afile>\""); return NULL; } - result = (char *)path_try_shorten_fname((char_u *)result); + result = path_try_shorten_fname(result); break; case SPEC_ABUF: // buffer number for autocommand @@ -6879,7 +6941,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum } // Length of new string. - resultlen = STRLEN(result); + resultlen = strlen(result); // Remove the file name extension. if (src[*usedlen] == '<') { (*usedlen)++; @@ -6923,7 +6985,7 @@ char *expand_sfile(char *arg) char *result = xstrdup(arg); for (char *p = result; *p;) { - if (STRNCMP(p, "<sfile>", 7) != 0) { + if (strncmp(p, "<sfile>", 7) != 0) { p++; } else { // replace "<sfile>" with the sourced file name, and do ":" stuff @@ -6942,11 +7004,11 @@ char *expand_sfile(char *arg) p += srclen; continue; } - size_t len = STRLEN(result) - srclen + STRLEN(repl) + 1; + size_t len = strlen(result) - srclen + strlen(repl) + 1; char *newres = xmalloc(len); memmove(newres, result, (size_t)(p - result)); STRCPY(newres + (p - result), repl); - len = STRLEN(newres); + len = strlen(newres); STRCAT(newres, p + srclen); xfree(repl); xfree(result); @@ -6986,12 +7048,12 @@ void dialog_msg(char *buff, char *format, char *fname) /// ":behave {mswin,xterm}" static void ex_behave(exarg_T *eap) { - if (STRCMP(eap->arg, "mswin") == 0) { + if (strcmp(eap->arg, "mswin") == 0) { set_option_value_give_err("selection", 0L, "exclusive", 0); set_option_value_give_err("selectmode", 0L, "mouse,key", 0); set_option_value_give_err("mousemodel", 0L, "popup", 0); set_option_value_give_err("keymodel", 0L, "startsel,stopsel", 0); - } else if (STRCMP(eap->arg, "xterm") == 0) { + } else if (strcmp(eap->arg, "xterm") == 0) { set_option_value_give_err("selection", 0L, "inclusive", 0); set_option_value_give_err("selectmode", 0L, "", 0); set_option_value_give_err("mousemodel", 0L, "extend", 0); @@ -7029,19 +7091,19 @@ static void ex_filetype(exarg_T *eap) // Accept "plugin" and "indent" in any order. for (;;) { - if (STRNCMP(arg, "plugin", 6) == 0) { + if (strncmp(arg, "plugin", 6) == 0) { plugin = true; arg = skipwhite(arg + 6); continue; } - if (STRNCMP(arg, "indent", 6) == 0) { + if (strncmp(arg, "indent", 6) == 0) { indent = true; arg = skipwhite(arg + 6); continue; } break; } - if (STRCMP(arg, "on") == 0 || STRCMP(arg, "detect") == 0) { + if (strcmp(arg, "on") == 0 || strcmp(arg, "detect") == 0) { if (*arg == 'o' || !filetype_detect) { source_runtime(FILETYPE_FILE, DIP_ALL); filetype_detect = kTrue; @@ -7058,7 +7120,7 @@ static void ex_filetype(exarg_T *eap) (void)do_doautocmd("filetypedetect BufRead", true, NULL); do_modelines(0); } - } else if (STRCMP(arg, "off") == 0) { + } else if (strcmp(arg, "off") == 0) { if (plugin || indent) { if (plugin) { source_runtime(FTPLUGOF_FILE, DIP_ALL); @@ -7108,17 +7170,18 @@ void filetype_maybe_enable(void) /// ":setfiletype [FALLBACK] {name}" static void ex_setfiletype(exarg_T *eap) { - if (!did_filetype) { - char *arg = eap->arg; + if (did_filetype) { + return; + } - if (STRNCMP(arg, "FALLBACK ", 9) == 0) { - arg += 9; - } + char *arg = eap->arg; + if (strncmp(arg, "FALLBACK ", 9) == 0) { + arg += 9; + } - set_option_value_give_err("filetype", 0L, arg, OPT_LOCAL); - if (arg != eap->arg) { - did_filetype = false; - } + set_option_value_give_err("filetype", 0L, arg, OPT_LOCAL); + if (arg != eap->arg) { + did_filetype = false; } } @@ -7200,7 +7263,7 @@ static void ex_terminal(exarg_T *eap) char ex_cmd[1024]; if (*eap->arg != NUL) { // Run {cmd} in 'shell'. - char *name = (char *)vim_strsave_escaped((char_u *)eap->arg, (char_u *)"\"\\"); + char *name = vim_strsave_escaped(eap->arg, "\"\\"); snprintf(ex_cmd, sizeof(ex_cmd), ":enew%s | call termopen(\"%s\")", eap->forceit ? "!" : "", name); @@ -7233,7 +7296,7 @@ static void ex_terminal(exarg_T *eap) void verify_command(char *cmd) { - if (strcmp("smile", cmd)) { + if (strcmp("smile", cmd) != 0) { return; // acceptable non-existing command } msg(" #xxn` #xnxx` ,+x@##@Mz;` .xxx" |