diff options
Diffstat (limited to 'src/nvim/ex_docmd.c')
-rw-r--r-- | src/nvim/ex_docmd.c | 974 |
1 files changed, 557 insertions, 417 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index a24e8458a6..0b466bbe4e 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - // ex_docmd.c: functions for executing an Ex command line. #include <assert.h> @@ -12,15 +9,18 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/types.h> #include "auto/config.h" #include "nvim/arglist.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/change.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" +#include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" #include "nvim/debugger.h" #include "nvim/digraph.h" @@ -28,7 +28,6 @@ #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/event/loop.h" #include "nvim/ex_cmds.h" @@ -40,19 +39,20 @@ #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/highlight_defs.h" +#include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/input.h" #include "nvim/keycodes.h" -#include "nvim/macros.h" +#include "nvim/lua/executor.h" +#include "nvim/macros_defs.h" #include "nvim/main.h" #include "nvim/mark.h" #include "nvim/mbyte.h" -#include "nvim/memfile_defs.h" #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/message.h" @@ -61,40 +61,52 @@ #include "nvim/normal.h" #include "nvim/ops.h" #include "nvim/option.h" +#include "nvim/option_vars.h" #include "nvim/optionstr.h" +#include "nvim/os/fs.h" #include "nvim/os/input.h" #include "nvim/os/os.h" #include "nvim/os/shell.h" #include "nvim/path.h" #include "nvim/popupmenu.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.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/state.h" #include "nvim/statusline.h" #include "nvim/strings.h" #include "nvim/tag.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/undo.h" #include "nvim/usercmd.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #include "nvim/window.h" +#include "nvim/winfloat.h" -static char e_ambiguous_use_of_user_defined_command[] +static const char e_ambiguous_use_of_user_defined_command[] = N_("E464: Ambiguous use of user-defined command"); -static char e_not_an_editor_command[] +static const char e_no_call_stack_to_substitute_for_stack[] + = N_("E489: No call stack to substitute for \"<stack>\""); +static const char e_not_an_editor_command[] = N_("E492: Not an editor command"); -static char e_no_source_file_name_to_substitute_for_sfile[] - = N_("E498: no :source file name to substitute for \"<sfile>\""); -static char e_no_call_stack_to_substitute_for_stack[] - = N_("E489: no call stack to substitute for \"<stack>\""); -static char e_no_script_file_name_to_substitute_for_script[] +static const char e_no_autocommand_file_name_to_substitute_for_afile[] + = N_("E495: No autocommand file name to substitute for \"<afile>\""); +static const char e_no_autocommand_buffer_number_to_substitute_for_abuf[] + = N_("E496: No autocommand buffer number to substitute for \"<abuf>\""); +static const char e_no_autocommand_match_name_to_substitute_for_amatch[] + = N_("E497: No autocommand match name to substitute for \"<amatch>\""); +static const char e_no_source_file_name_to_substitute_for_sfile[] + = N_("E498: No :source file name to substitute for \"<sfile>\""); +static const char e_no_line_number_to_use_for_slnum[] + = N_("E842: No line number to use for \"<slnum>\""); +static const char e_no_line_number_to_use_for_sflnum[] + = N_("E961: No line number to use for \"<sflnum>\""); +static const char e_no_script_file_name_to_substitute_for_script[] = N_("E1274: No script file name to substitute for \"<script>\""); static int quitmore = 0; @@ -139,10 +151,6 @@ struct dbg_stuff { # include "ex_docmd.c.generated.h" #endif -#ifndef HAVE_WORKING_LIBINTL -# define ex_language ex_ni -#endif - // Declare cmdnames[]. #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ex_cmds_defs.generated.h" @@ -152,19 +160,28 @@ static char dollar_command[2] = { '$', 0 }; static void save_dbg_stuff(struct dbg_stuff *dsp) { - dsp->trylevel = trylevel; trylevel = 0; - dsp->force_abort = force_abort; force_abort = false; - dsp->caught_stack = caught_stack; caught_stack = NULL; - dsp->vv_exception = v_exception(NULL); - dsp->vv_throwpoint = v_throwpoint(NULL); + dsp->trylevel = trylevel; + trylevel = 0; + dsp->force_abort = force_abort; + force_abort = false; + dsp->caught_stack = caught_stack; + caught_stack = NULL; + dsp->vv_exception = v_exception(NULL); + dsp->vv_throwpoint = v_throwpoint(NULL); // Necessary for debugging an inactive ":catch", ":finally", ":endtry". - dsp->did_emsg = did_emsg; did_emsg = false; - dsp->got_int = got_int; got_int = false; - dsp->did_throw = did_throw; did_throw = false; - dsp->need_rethrow = need_rethrow; need_rethrow = false; - dsp->check_cstack = check_cstack; check_cstack = false; - dsp->current_exception = current_exception; current_exception = NULL; + dsp->did_emsg = did_emsg; + did_emsg = false; + dsp->got_int = got_int; + got_int = false; + dsp->did_throw = did_throw; + did_throw = false; + dsp->need_rethrow = need_rethrow; + need_rethrow = false; + dsp->check_cstack = check_cstack; + check_cstack = false; + dsp->current_exception = current_exception; + current_exception = NULL; } static void restore_dbg_stuff(struct dbg_stuff *dsp) @@ -200,7 +217,7 @@ void do_exmode(void) RedrawingDisabled++; // don't redisplay the window no_wait_return++; // don't wait for return - msg(_("Entering Ex mode. Type \"visual\" to go to Normal mode.")); + msg(_("Entering Ex mode. Type \"visual\" to go to Normal mode."), 0); while (exmode_active) { // Check for a ":normal" command and no more characters left. if (ex_normal_busy > 0 && typebuf.tb_len == 0) { @@ -221,7 +238,7 @@ void do_exmode(void) if ((prev_line != curwin->w_cursor.lnum || changedtick != buf_get_changedtick(curbuf)) && !ex_no_reprint) { if (curbuf->b_ml.ml_flags & ML_EMPTY) { - emsg(_(e_emptybuf)); + emsg(_(e_empty_buffer)); } else { if (ex_pressedreturn) { // Make sure the message overwrites the right line and isn't throttled. @@ -239,7 +256,7 @@ void do_exmode(void) } } else if (ex_pressedreturn && !ex_no_reprint) { // must be at EOF if (curbuf->b_ml.ml_flags & ML_EMPTY) { - emsg(_(e_emptybuf)); + emsg(_(e_empty_buffer)); } else { emsg(_("E501: At end-of-file")); } @@ -264,9 +281,9 @@ static void msg_verbose_cmd(linenr_T lnum, char *cmd) verbose_enter_scroll(); if (lnum == 0) { - smsg(_("Executing: %s"), cmd); + smsg(0, _("Executing: %s"), cmd); } else { - smsg(_("line %" PRIdLINENR ": %s"), lnum, cmd); + smsg(0, _("line %" PRIdLINENR ": %s"), lnum, cmd); } if (msg_silent == 0) { msg_puts("\n"); // don't overwrite this @@ -279,7 +296,7 @@ static void msg_verbose_cmd(linenr_T lnum, char *cmd) /// Execute a simple command line. Used for translated commands like "*". int do_cmdline_cmd(const char *cmd) { - return do_cmdline((char *)cmd, NULL, NULL, DOCMD_NOWAIT|DOCMD_KEYTYPED); + return do_cmdline((char *)cmd, NULL, NULL, DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); } /// do_cmdline(): execute one Ex command line @@ -320,16 +337,12 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) linenr_T *breakpoint = NULL; // ptr to breakpoint field in cookie int *dbg_tick = NULL; // ptr to dbg_tick field in cookie struct dbg_stuff debug_saved; // saved things for debug mode - int initial_trylevel; - msglist_T **saved_msg_list = NULL; msglist_T *private_msg_list; // "fgetline" and "cookie" passed to do_one_cmd() char *(*cmd_getline)(int, void *, int, bool); void *cmd_cookie; struct loop_cookie cmd_loop_cookie; - void *real_cookie; - int getline_is_func; static int call_depth = 0; // recursiveness // For every pair of do_cmdline()/do_one_cmd() calls, use an extra memory @@ -338,7 +351,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // combine the messages stored by an earlier invocation of do_one_cmd() // with the command name of the later one. This would happen when // BufWritePost autocommands are executed after a write error. - saved_msg_list = msg_list; + msglist_T **saved_msg_list = msg_list; msg_list = &private_msg_list; private_msg_list = NULL; @@ -358,10 +371,10 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) ga_init(&lines_ga, (int)sizeof(wcmd_T), 10); - real_cookie = getline_cookie(fgetline, cookie); + void *real_cookie = getline_cookie(fgetline, cookie); // Inside a function use a higher nesting level. - getline_is_func = getline_equal(fgetline, cookie, get_func_line); + bool getline_is_func = getline_equal(fgetline, cookie, get_func_line); if (getline_is_func && ex_nesting_level == func_level(real_cookie)) { ex_nesting_level++; } @@ -393,7 +406,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) CLEAR_FIELD(debug_saved); } - initial_trylevel = trylevel; + int initial_trylevel = trylevel; // "did_throw" will be set to true when an exception is being thrown. did_throw = false; @@ -485,24 +498,6 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) } } - if (cstack.cs_looplevel > 0) { - // Inside a while/for loop we need to store the lines and use them - // again. Pass a different "fgetline" function to do_one_cmd() - // below, so that it stores lines in or reads them from - // "lines_ga". Makes it possible to define a function inside a - // while/for loop. - cmd_getline = get_loop_line; - cmd_cookie = (void *)&cmd_loop_cookie; - cmd_loop_cookie.lines_gap = &lines_ga; - cmd_loop_cookie.current_line = current_line; - cmd_loop_cookie.getline = fgetline; - cmd_loop_cookie.cookie = cookie; - cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len); - } else { - cmd_getline = fgetline; - cmd_cookie = cookie; - } - // 2. If no line given, get an allocated line with fgetline(). if (next_cmdline == NULL) { // Need to set msg_didout for the first line after an ":if", @@ -541,15 +536,37 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) } cmdline_copy = next_cmdline; - // Save the current line when inside a ":while" or ":for", and when - // the command looks like a ":while" or ":for", because we may need it - // later. When there is a '|' and another command, it is stored - // separately, because we need to be able to jump back to it from an + int current_line_before = 0; + // Inside a while/for loop, and when the command looks like a ":while" + // or ":for", the line is stored, because we may need it later when + // looping. + // + // When there is a '|' and another command, it is stored separately, + // because we need to be able to jump back to it from an // :endwhile/:endfor. - if (current_line == lines_ga.ga_len - && (cstack.cs_looplevel || has_loop_cmd(next_cmdline))) { - store_loop_line(&lines_ga, next_cmdline); + // + // Pass a different "fgetline" function to do_one_cmd() below, + // that it stores lines in or reads them from "lines_ga". Makes it + // possible to define a function inside a while/for loop. + if ((cstack.cs_looplevel > 0 || has_loop_cmd(next_cmdline))) { + cmd_getline = get_loop_line; + cmd_cookie = (void *)&cmd_loop_cookie; + cmd_loop_cookie.lines_gap = &lines_ga; + cmd_loop_cookie.current_line = current_line; + cmd_loop_cookie.getline = fgetline; + cmd_loop_cookie.cookie = cookie; + cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len); + + // Save the current line when encountering it the first time. + if (current_line == lines_ga.ga_len) { + store_loop_line(&lines_ga, next_cmdline); + } + current_line_before = current_line; + } else { + cmd_getline = fgetline; + cmd_cookie = cookie; } + did_endif = false; if (count++ == 0) { @@ -652,7 +669,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) } else if (cstack.cs_lflags & CSL_HAD_LOOP) { // For a ":while" or ":for" we need to remember the line number. cstack.cs_lflags &= ~CSL_HAD_LOOP; - cstack.cs_line[cstack.cs_idx] = current_line - 1; + cstack.cs_line[cstack.cs_idx] = current_line_before; } } @@ -819,8 +836,8 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // Cleanup if "cs_emsg_silent_list" remains. if (cstack.cs_emsg_silent_list != NULL) { - eslist_T *elem, *temp; - for (elem = cstack.cs_emsg_silent_list; elem != NULL; elem = temp) { + eslist_T *temp; + for (eslist_T *elem = cstack.cs_emsg_silent_list; elem != NULL; elem = temp) { temp = elem->next; xfree(elem); } @@ -893,7 +910,7 @@ void handle_did_throw(void) if (messages != NULL) { do { msglist_T *next = messages->next; - emsg(messages->msg); + emsg_multiline(messages->msg, messages->multiline); xfree(messages->msg); xfree(messages->sfile); xfree(messages); @@ -919,7 +936,7 @@ static char *get_loop_line(int c, void *cookie, int indent, bool do_concat) char *line; // First time inside the ":while"/":for": get line normally. if (cp->getline == NULL) { - line = getcmdline(c, 0L, indent, do_concat); + line = getcmdline(c, 0, indent, do_concat); } else { line = cp->getline(c, cp->cookie, indent, do_concat); } @@ -986,10 +1003,10 @@ void *getline_cookie(LineGetter fgetline, void *cookie) /// ":bwipeout", etc. /// /// @return the buffer number. -static int compute_buffer_local_count(cmd_addr_T addr_type, linenr_T lnum, long offset) +static int compute_buffer_local_count(cmd_addr_T addr_type, linenr_T lnum, int offset) { buf_T *nextbuf; - long count = offset; + int count = offset; buf_T *buf = firstbuf; while (buf->b_next != NULL && buf->b_fnum < lnum) { @@ -1107,7 +1124,7 @@ static void get_wincmd_addr_type(const char *arg, exarg_T *eap) case 'd': case Ctrl_D: // window size or any count - eap->addr_type = ADDR_OTHER; // -V1037 + eap->addr_type = ADDR_OTHER; break; case Ctrl_HAT: @@ -1311,16 +1328,16 @@ static void parse_register(exarg_T *eap) } // Change line1 and line2 of Ex command to use count -void set_cmd_count(exarg_T *eap, long count, bool validate) +void set_cmd_count(exarg_T *eap, linenr_T count, bool validate) { if (eap->addr_type != ADDR_LINES) { // e.g. :buffer 2, :sleep 3 - eap->line2 = (linenr_T)count; + eap->line2 = count; if (eap->addr_count == 0) { eap->addr_count = 1; } } else { eap->line1 = eap->line2; - eap->line2 += (linenr_T)count - 1; + eap->line2 += count - 1; eap->addr_count++; // Be vi compatible: no error message for out of range. if (validate && eap->line2 > curbuf->b_ml.ml_line_count) { @@ -1329,7 +1346,7 @@ void set_cmd_count(exarg_T *eap, long count, bool validate) } } -static int parse_count(exarg_T *eap, char **errormsg, bool validate) +static int parse_count(exarg_T *eap, const char **errormsg, bool validate) { // Check for a count. When accepting a EX_BUFNAME, don't use "123foo" as a // count, it's a buffer name. @@ -1338,7 +1355,7 @@ static int parse_count(exarg_T *eap, char **errormsg, bool validate) if ((eap->argt & EX_COUNT) && ascii_isdigit(*eap->arg) && (!(eap->argt & EX_BUFNAME) || *(p = skipdigits(eap->arg + 1)) == NUL || ascii_iswhite(*p))) { - long n = getdigits_long(&eap->arg, false, -1); + linenr_T n = getdigits_int32(&eap->arg, false, -1); eap->arg = skipwhite(eap->arg); if (eap->args != NULL) { @@ -1383,7 +1400,7 @@ bool is_cmd_ni(cmdidx_T cmdidx) /// @param[out] errormsg Error message, if any /// /// @return Success or failure -bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **errormsg) +bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, const char **errormsg) { char *after_modifier = NULL; bool retval = false; @@ -1441,7 +1458,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er } // Fail if command is invalid if (eap->cmdidx == CMD_SIZE) { - STRCPY(IObuff, _(e_not_an_editor_command)); + xstrlcpy(IObuff, _(e_not_an_editor_command), IOSIZE); // If the modifier was parsed OK the error must be in the following command char *cmdname = after_modifier ? after_modifier : cmdline; append_command(cmdname); @@ -1551,7 +1568,7 @@ static void shift_cmd_args(exarg_T *eap) xfree(oldarglens); } -static int execute_cmd0(int *retv, exarg_T *eap, char **errormsg, bool preview) +static int execute_cmd0(int *retv, exarg_T *eap, const char **errormsg, bool preview) { // If filename expansion is enabled, expand filenames if (eap->argt & EX_XFILE) { @@ -1636,7 +1653,7 @@ static int execute_cmd0(int *retv, exarg_T *eap, char **errormsg, bool preview) /// @param preview Execute command preview callback instead of actual command int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) { - char *errormsg = NULL; + const char *errormsg = NULL; int retv = 0; #undef ERROR @@ -1677,7 +1694,7 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) && !(eap->cmdidx == CMD_file && *eap->arg == NUL) && !IS_USER_CMDIDX(eap->cmdidx) && curbuf_locked()) { - ERROR(_(e_cannot_edit_other_buf)); + goto end; } correct_range(eap); @@ -1849,7 +1866,8 @@ static bool skip_cmd(const exarg_T *eap) /// Execute one Ex command. /// -/// If 'sourcing' is true, the command will be included in the error message. +/// If "flags" has DOCMD_VERBOSE, the command will be included in the error +/// message. /// /// 1. skip comment lines and leading space /// 2. handle command modifiers @@ -1867,7 +1885,7 @@ static bool skip_cmd(const exarg_T *eap) static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter fgetline, void *cookie) { - char *errormsg = NULL; // error message + const char *errormsg = NULL; // error message const int save_reg_executing = reg_executing; const bool save_pending_end_reg_executing = pending_end_reg_executing; @@ -1882,8 +1900,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter // avoid that a function call in 'statusline' does this && !getline_equal(fgetline, cookie, get_func_line) // avoid that an autocommand, e.g. QuitPre, does this - && !getline_equal(fgetline, cookie, - getnextac)) { + && !getline_equal(fgetline, cookie, getnextac)) { quitmore--; } @@ -2013,7 +2030,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter while (ASCII_ISALNUM(*p)) { p++; } - p = xstrnsave(ea.cmd, (size_t)(p - ea.cmd)); + p = xmemdupz(ea.cmd, (size_t)(p - ea.cmd)); int ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, true, NULL); xfree(p); // If the autocommands did something and didn't cause an error, try @@ -2031,7 +2048,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter // Check for wrong commands. if (ea.cmdidx == CMD_SIZE) { if (!ea.skip) { - STRCPY(IObuff, _(e_not_an_editor_command)); + xstrlcpy(IObuff, _(e_not_an_editor_command), IOSIZE); // If the modifier was parsed OK the error must be in the following // command char *cmdname = after_modifier ? after_modifier : *cmdlinep; @@ -2308,7 +2325,7 @@ doend: if (errormsg != NULL && *errormsg != NUL && !did_emsg) { if (flags & DOCMD_VERBOSE) { if (errormsg != IObuff) { - STRCPY(IObuff, errormsg); + xstrlcpy(IObuff, errormsg, IOSIZE); errormsg = IObuff; } append_command(*ea.cmdlinep); @@ -2329,6 +2346,7 @@ doend: } ex_nesting_level--; + xfree(ea.cmdline_tofree); return ea.nextcmd; } @@ -2362,12 +2380,12 @@ char *ex_errmsg(const char *const msg, const char *const arg) /// - set 'eventignore' to "all" for ":noautocmd" /// /// @return FAIL when the command is not to be executed. -int parse_command_modifiers(exarg_T *eap, char **errormsg, cmdmod_T *cmod, bool skip_only) +int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, bool skip_only) { CLEAR_POINTER(cmod); // Repeat until no more command modifiers are found. - for (;;) { + while (true) { while (*eap->cmd == ' ' || *eap->cmd == '\t' || *eap->cmd == ':') { @@ -2397,7 +2415,7 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, cmdmod_T *cmod, bool char *p = skip_range(eap->cmd, NULL); switch (*p) { - // When adding an entry, also modify cmd_exists(). + // When adding an entry, also modify cmdmods[] case 'a': if (!checkforcmd(&eap->cmd, "aboveleft", 3)) { break; @@ -2543,7 +2561,10 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, cmdmod_T *cmod, bool if (checkforcmd(&p, "tab", 3)) { if (!skip_only) { int tabnr = (int)get_address(eap, &eap->cmd, ADDR_TABS, eap->skip, skip_only, - false, 1); + false, 1, errormsg); + if (eap->cmd == NULL) { + return false; + } if (tabnr == MAXLNUM) { cmod->cmod_tab = tabpage_index(curtab) + 1; @@ -2687,7 +2708,7 @@ void undo_cmdmod(cmdmod_T *cmod) /// May set the last search pattern, unless "silent" is true. /// /// @return FAIL and set "errormsg" or return OK. -int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent) +int parse_cmd_address(exarg_T *eap, const char **errormsg, bool silent) FUNC_ATTR_NONNULL_ALL { int address_count = 1; @@ -2696,12 +2717,12 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent) int ret = FAIL; // Repeat for all ',' or ';' separated addresses. - for (;;) { + while (true) { eap->line1 = eap->line2; eap->line2 = get_cmd_default_range(eap); eap->cmd = skipwhite(eap->cmd); lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip, silent, - eap->addr_count == 0, address_count++); + eap->addr_count == 0, address_count++, errormsg); if (eap->cmd == NULL) { // error detected goto theend; } @@ -2737,7 +2758,7 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent) if (IS_USER_CMDIDX(eap->cmdidx)) { eap->line1 = 1; eap->line2 = eap->addr_type == ADDR_WINDOWS - ? LAST_WIN_NR : LAST_TAB_NR; + ? LAST_WIN_NR : LAST_TAB_NR; } else { // there is no Vim command which uses '%' and // ADDR_WINDOWS or ADDR_TABS @@ -2780,13 +2801,13 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent) eap->cmd++; if (!eap->skip) { fmark_T *fm = mark_get_visual(curbuf, '<'); - if (!mark_check(fm)) { + if (!mark_check(fm, errormsg)) { goto theend; } assert(fm != NULL); eap->line1 = fm->mark.lnum; fm = mark_get_visual(curbuf, '>'); - if (!mark_check(fm)) { + if (!mark_check(fm, errormsg)) { goto theend; } assert(fm != NULL); @@ -2862,10 +2883,10 @@ bool checkforcmd(char **pp, const char *cmd, int len) /// Append "cmd" to the error message in IObuff. /// Takes care of limiting the length and handling 0xa0, which would be /// invisible otherwise. -static void append_command(char *cmd) +static void append_command(const char *cmd) { size_t len = strlen(IObuff); - char *s = cmd; + const char *s = cmd; char *d; if (len > IOSIZE - 100) { @@ -2874,7 +2895,7 @@ static void append_command(char *cmd) d -= utf_head_off(IObuff, d); STRCPY(d, "..."); } - STRCAT(IObuff, ": "); + xstrlcat(IObuff, ": ", IOSIZE); d = IObuff + strlen(IObuff); while (*s != NUL && d - IObuff + 5 < IOSIZE) { if ((uint8_t)s[0] == 0xc2 && (uint8_t)s[1] == 0xa0) { @@ -2884,7 +2905,7 @@ static void append_command(char *cmd) } else if (d - IObuff + utfc_ptr2len(s) + 1 >= IOSIZE) { break; } else { - mb_copy_char((const char **)&s, &d); + mb_copy_char(&s, &d); } } *d = NUL; @@ -2988,6 +3009,11 @@ char *find_ex_command(exarg_T *eap, int *full) } assert(eap->cmdidx >= 0); + if (len == 3 && strncmp("def", eap->cmd, 3) == 0) { + // Make :def an unknown command to avoid confusing behavior. #23149 + eap->cmdidx = CMD_SIZE; + } + for (; (int)eap->cmdidx < CMD_SIZE; eap->cmdidx = (cmdidx_T)((int)eap->cmdidx + 1)) { if (strncmp(cmdnames[(int)eap->cmdidx].cmd_name, eap->cmd, @@ -3029,6 +3055,7 @@ static struct cmdmod { { "confirm", 4, false }, { "filter", 4, false }, { "hide", 3, false }, + { "horizontal", 3, false }, { "keepalt", 5, false }, { "keepjumps", 5, false }, { "keepmarks", 3, false }, @@ -3094,7 +3121,7 @@ int cmd_exists(const char *const name) // For ":2match" and ":3match" we need to skip the number. exarg_T ea; ea.cmd = (char *)((*name == '2' || *name == '3') ? name + 1 : name); - ea.cmdidx = (cmdidx_T)0; + ea.cmdidx = 0; ea.flags = 0; int full = false; char *p = find_ex_command(&ea, &full); @@ -3113,13 +3140,10 @@ int cmd_exists(const char *const name) /// "fullcommand" function void f_fullcommand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - char *name = argvars[0].vval.v_string; + char *name = (char *)tv_get_string(&argvars[0]); rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; - if (name == NULL) { - return; - } while (*name == ':') { name++; @@ -3128,7 +3152,7 @@ void f_fullcommand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) exarg_T ea; ea.cmd = (*name == '2' || *name == '3') ? name + 1 : name; - ea.cmdidx = (cmdidx_T)0; + ea.cmdidx = 0; ea.flags = 0; char *p = find_ex_command(&ea, NULL); if (p == NULL || ea.cmdidx == CMD_SIZE) { @@ -3142,10 +3166,15 @@ void f_fullcommand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) cmdidx_T excmd_get_cmdidx(const char *cmd, size_t len) { + if (len == 3 && strncmp("def", cmd, 3) == 0) { + // Make :def an unknown command to avoid confusing behavior. #23149 + return CMD_SIZE; + } + cmdidx_T idx; if (!one_letter_cmd(cmd, &idx)) { - for (idx = (cmdidx_T)0; (int)idx < CMD_SIZE; idx = (cmdidx_T)((int)idx + 1)) { + for (idx = 0; (int)idx < CMD_SIZE; idx = (cmdidx_T)((int)idx + 1)) { if (strncmp(cmdnames[(int)idx].cmd_name, cmd, len) == 0) { break; } @@ -3200,34 +3229,35 @@ char *skip_range(const char *cmd, int *ctx) } // Skip ":" and white space. - cmd = skip_colon_white((char *)cmd, false); + cmd = skip_colon_white(cmd, false); return (char *)cmd; } -static void addr_error(cmd_addr_T addr_type) +static const char *addr_error(cmd_addr_T addr_type) { if (addr_type == ADDR_NONE) { - emsg(_(e_norange)); + return _(e_norange); } else { - emsg(_(e_invrange)); + return _(e_invrange); } } -/// Get a single EX address +/// Gets a single EX address. /// -/// Set ptr to the next character after the part that was interpreted. -/// Set ptr to NULL when an error is encountered. -/// This may set the last used search pattern. +/// Sets ptr to the next character after the part that was interpreted. +/// Sets ptr to NULL when an error is encountered (stored in `errormsg`). +/// May set the last used search pattern. /// /// @param skip only skip the address, don't use it /// @param silent no errors or side effects /// @param to_other_file flag: may jump to other file /// @param address_count 1 for first, >1 after comma +/// @param errormsg Error message, if any /// /// @return MAXLNUM when no Ex address was found. static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int skip, bool silent, - int to_other_file, int address_count) + int to_other_file, int address_count, const char **errormsg) FUNC_ATTR_NONNULL_ALL { int c; @@ -3263,7 +3293,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int case ADDR_NONE: case ADDR_TABS_RELATIVE: case ADDR_UNSIGNED: - addr_error(addr_type); + *errormsg = addr_error(addr_type); cmd = NULL; goto error; break; @@ -3308,7 +3338,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int case ADDR_NONE: case ADDR_TABS_RELATIVE: case ADDR_UNSIGNED: - addr_error(addr_type); + *errormsg = addr_error(addr_type); cmd = NULL; goto error; break; @@ -3333,7 +3363,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int goto error; } if (addr_type != ADDR_LINES) { - addr_error(addr_type); + *errormsg = addr_error(addr_type); cmd = NULL; goto error; } @@ -3346,10 +3376,11 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int fmark_T *fm = mark_get(curbuf, curwin, NULL, flag, *cmd); cmd++; if (fm != NULL && fm->fnum != curbuf->handle) { + (void)mark_move_to(fm, 0); // Jumped to another file. lnum = curwin->w_cursor.lnum; } else { - if (!mark_check(fm)) { + if (!mark_check(fm, errormsg)) { cmd = NULL; goto error; } @@ -3363,7 +3394,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int case '?': // '/' or '?' - search c = (uint8_t)(*cmd++); if (addr_type != ADDR_LINES) { - addr_error(addr_type); + *errormsg = addr_error(addr_type); cmd = NULL; goto error; } @@ -3397,7 +3428,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, cmd, 1L, flags, NULL)) { + if (!do_search(NULL, c, c, cmd, 1, flags, NULL)) { curwin->w_cursor = pos; cmd = NULL; goto error; @@ -3412,7 +3443,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int case '\\': // "\?", "\/" or "\&", repeat search cmd++; if (addr_type != ADDR_LINES) { - addr_error(addr_type); + *errormsg = addr_error(addr_type); cmd = NULL; goto error; } @@ -3421,7 +3452,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int } else if (*cmd == '?' || *cmd == '/') { i = RE_SEARCH; } else { - emsg(_(e_backslash)); + *errormsg = _(e_backslash); cmd = NULL; goto error; } @@ -3434,7 +3465,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int pos.coladd = 0; if (searchit(curwin, curbuf, &pos, NULL, *cmd == '?' ? BACKWARD : FORWARD, - "", 1L, SEARCH_MSG, i, NULL) != FAIL) { + "", 1, SEARCH_MSG, i, NULL) != FAIL) { lnum = pos.lnum; } else { cmd = NULL; @@ -3450,7 +3481,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int } } - for (;;) { + while (true) { cmd = skipwhite(cmd); if (*cmd != '-' && *cmd != '+' && !ascii_isdigit(*cmd)) { break; @@ -3503,13 +3534,13 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int // "number", "+number" or "-number" n = getdigits_int32(&cmd, false, MAXLNUM); if (n == MAXLNUM) { - emsg(_(e_line_number_out_of_range)); + *errormsg = _(e_line_number_out_of_range); goto error; } } if (addr_type == ADDR_TABS_RELATIVE) { - emsg(_(e_invrange)); + *errormsg = _(e_invrange); cmd = NULL; goto error; } else if (addr_type == ADDR_LOADED_BUFFERS || addr_type == ADDR_BUFFERS) { @@ -3524,8 +3555,8 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int if (i == '-') { lnum -= n; } else { - if (n >= INT32_MAX - lnum) { - emsg(_(e_line_number_out_of_range)); + if (lnum >= 0 && n >= INT32_MAX - lnum) { + *errormsg = _(e_line_number_out_of_range); goto error; } lnum += n; @@ -3738,7 +3769,7 @@ char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep) /// When an error is detected, "errormsgp" is set to a non-NULL pointer. /// /// @return FAIL for failure, OK otherwise. -int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) +int expand_filename(exarg_T *eap, char **cmdlinep, const char **errormsgp) { // Skip a regexp pattern for ":vimgrep[add] pat file..." char *p = skip_grep_pat(eap); @@ -3751,7 +3782,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp) // Skip over `=expr`, wildcards in it are not expanded. if (p[0] == '`' && p[1] == '=') { p += 2; - (void)skip_expr(&p); + (void)skip_expr(&p, NULL); if (*p == '`') { p++; } @@ -3970,7 +4001,7 @@ void separate_nextcmd(exarg_T *eap) } else if (p[0] == '`' && p[1] == '=' && (eap->argt & EX_XFILE)) { // Skip over `=expr` when wildcards are expanded. p += 2; - (void)skip_expr(&p); + (void)skip_expr(&p, NULL); if (*p == NUL) { // stop at NUL after CTRL-V break; } @@ -4011,7 +4042,7 @@ static char *getargcmd(char **argp) if (*arg == '+') { // +[command] arg++; if (ascii_isspace(*arg) || *arg == '\0') { - command = (char *)dollar_command; + command = dollar_command; } else { command = arg; arg = skip_cmd_arg(command, true); @@ -4059,6 +4090,22 @@ int get_bad_opt(const char *p, exarg_T *eap) return OK; } +/// Function given to ExpandGeneric() to obtain the list of bad= names. +static char *get_bad_name(expand_T *xp FUNC_ATTR_UNUSED, int idx) +{ + // Note: Keep this in sync with get_bad_opt(). + static char *(p_bad_values[]) = { + "?", + "keep", + "drop", + }; + + if (idx < (int)ARRAY_SIZE(p_bad_values)) { + return p_bad_values[idx]; + } + return NULL; +} + /// Get "++opt=arg" argument. /// /// @return FAIL or OK. @@ -4068,6 +4115,8 @@ static int getargopt(exarg_T *eap) int *pp = NULL; int bad_char_idx; + // Note: Keep this in sync with get_argopt_name. + // ":edit ++[no]bin[ary] file" if (strncmp(arg, "bin", 3) == 0 || strncmp(arg, "nobin", 5) == 0) { if (*arg == 'n') { @@ -4146,6 +4195,71 @@ static int getargopt(exarg_T *eap) return OK; } +/// Function given to ExpandGeneric() to obtain the list of ++opt names. +static char *get_argopt_name(expand_T *xp FUNC_ATTR_UNUSED, int idx) +{ + // Note: Keep this in sync with getargopt(). + static char *(p_opt_values[]) = { + "fileformat=", + "encoding=", + "binary", + "nobinary", + "bad=", + "edit", + "p", + }; + + if (idx < (int)ARRAY_SIZE(p_opt_values)) { + return p_opt_values[idx]; + } + return NULL; +} + +/// Command-line expansion for ++opt=name. +int expand_argopt(char *pat, expand_T *xp, regmatch_T *rmp, char ***matches, int *numMatches) +{ + if (xp->xp_pattern > xp->xp_line && *(xp->xp_pattern - 1) == '=') { + CompleteListItemGetter cb = NULL; + + char *name_end = xp->xp_pattern - 1; + if (name_end - xp->xp_line >= 2 + && strncmp(name_end - 2, "ff", 2) == 0) { + cb = get_fileformat_name; + } else if (name_end - xp->xp_line >= 10 + && strncmp(name_end - 10, "fileformat", 10) == 0) { + cb = get_fileformat_name; + } else if (name_end - xp->xp_line >= 3 + && strncmp(name_end - 3, "enc", 3) == 0) { + cb = get_encoding_name; + } else if (name_end - xp->xp_line >= 8 + && strncmp(name_end - 8, "encoding", 8) == 0) { + cb = get_encoding_name; + } else if (name_end - xp->xp_line >= 3 + && strncmp(name_end - 3, "bad", 3) == 0) { + cb = get_bad_name; + } + + if (cb != NULL) { + ExpandGeneric(pat, xp, rmp, matches, numMatches, cb, false); + return OK; + } + return FAIL; + } + + // Special handling of "ff" which acts as a short form of + // "fileformat", as "ff" is not a substring of it. + if (xp->xp_pattern_len == 2 + && strncmp(xp->xp_pattern, "ff", xp->xp_pattern_len) == 0) { + *matches = xmalloc(sizeof(char *)); + *numMatches = 1; + (*matches)[0] = xstrdup("fileformat="); + return OK; + } + + ExpandGeneric(pat, xp, rmp, matches, numMatches, get_argopt_name, false); + return OK; +} + /// Handle the argument for a tabpage related ex command. /// When an error is encountered then eap->errmsg is set. /// @@ -4401,7 +4515,7 @@ static int check_more(int message, bool forceit) if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && curbuf->b_fname != NULL) { char buff[DIALOG_MSG_SIZE]; - vim_snprintf((char *)buff, DIALOG_MSG_SIZE, + vim_snprintf(buff, DIALOG_MSG_SIZE, NGETTEXT("%d more file to edit. Quit anyway?", "%d more files to edit. Quit anyway?", n), n); if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES) { @@ -4433,15 +4547,15 @@ static void ex_colorscheme(exarg_T *eap) char *expr = xstrdup("g:colors_name"); emsg_off++; - char *p = eval_to_string(expr, NULL, false); + char *p = eval_to_string(expr, false); emsg_off--; xfree(expr); if (p != NULL) { - msg(p); + msg(p, 0); xfree(p); } else { - msg("default"); + msg("default", 0); } } else if (load_colors(eap->arg) == FAIL) { semsg(_("E185: Cannot find color scheme '%s'"), eap->arg); @@ -4451,9 +4565,9 @@ static void ex_colorscheme(exarg_T *eap) static void ex_highlight(exarg_T *eap) { if (*eap->arg == NUL && eap->cmd[2] == '!') { - msg(_("Greetings, Vim user!")); + msg(_("Greetings, Vim user!"), 0); } - do_highlight((const char *)eap->arg, eap->forceit, false); + do_highlight(eap->arg, eap->forceit, false); } /// Call this function if we thought we were going to exit, but we won't @@ -4562,11 +4676,14 @@ static void ex_cquit(exarg_T *eap) FUNC_ATTR_NORETURN { // this does not always pass on the exit code to the Manx compiler. why? - getout(eap->addr_count > 0 ? (int)eap->line2 : EXIT_FAILURE); + int status = eap->addr_count > 0 ? (int)eap->line2 : EXIT_FAILURE; + ui_call_error_exit(status); + getout(status); } -/// ":qall": try to quit all windows -static void ex_quit_all(exarg_T *eap) +/// Do preparations for "qall" and "wqall". +/// Returns FAIL when quitting should be aborted. +int before_quit_all(exarg_T *eap) { if (cmdwin_type != 0) { if (eap->forceit) { @@ -4574,19 +4691,28 @@ static void ex_quit_all(exarg_T *eap) } else { cmdwin_result = K_XF2; } - return; + return FAIL; } // Don't quit while editing the command line. if (text_locked()) { text_locked_msg(); - return; + return FAIL; } if (before_quit_autocmds(curwin, true, eap->forceit)) { - return; + return FAIL; } + return OK; +} + +/// ":qall": try to quit all windows +static void ex_quit_all(exarg_T *eap) +{ + if (before_quit_all(eap) == FAIL) { + return; + } exiting = true; if (eap->forceit || !check_changed_any(false, false)) { getout(0); @@ -4710,7 +4836,7 @@ static void ex_tabonly(exarg_T *eap) } if (first_tabpage->tp_next == NULL) { - msg(_("Already only one tab page")); + msg(_("Already only one tab page"), 0); return; } @@ -4769,7 +4895,7 @@ void tabpage_close_other(tabpage_T *tp, int forceit) // Limit to 1000 windows, autocommands may add a window while we close // one. OK, so I'm paranoid... while (++done < 1000) { - snprintf((char *)prev_idx, sizeof(prev_idx), "%i", tabpage_index(tp)); + snprintf(prev_idx, sizeof(prev_idx), "%i", tabpage_index(tp)); win_T *wp = tp->tp_lastwin; ex_win_close(forceit, wp, tp); @@ -4836,19 +4962,9 @@ static void ex_stop(exarg_T *eap) if (!eap->forceit) { autowrite_all(); } - apply_autocmds(EVENT_VIMSUSPEND, NULL, NULL, false, NULL); - - // TODO(bfredl): the TUI should do this on suspend - ui_cursor_goto(Rows - 1, 0); - ui_call_grid_scroll(1, 0, Rows, 0, Columns, 1, 0); - ui_flush(); - ui_call_suspend(); // call machine specific function - + may_trigger_vim_suspend_resume(true); + ui_call_suspend(); ui_flush(); - maketitle(); - resettitle(); // force updating the title - ui_refresh(); // may have resized window - apply_autocmds(EVENT_VIMRESUME, NULL, NULL, false, NULL); } /// ":exit", ":xit" and ":wq": Write file and quit the current window. @@ -4891,7 +5007,7 @@ static void ex_exit(exarg_T *eap) static void ex_print(exarg_T *eap) { if (curbuf->b_ml.ml_flags & ML_EMPTY) { - emsg(_(e_emptybuf)); + emsg(_(e_empty_buffer)); } else { for (; !got_int; os_breakcheck()) { print_line(eap->line1, @@ -4976,8 +5092,13 @@ void ex_splitview(exarg_T *eap) } if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) { + char *file_to_find = NULL; + char *search_ctx = NULL; fname = find_file_in_path(eap->arg, strlen(eap->arg), - FNAME_MESS, true, curbuf->b_ffname); + FNAME_MESS, true, curbuf->b_ffname, + &file_to_find, &search_ctx); + xfree(file_to_find); + vim_findfile_cleanup(search_ctx); if (fname == NULL) { goto theend; } @@ -5091,8 +5212,8 @@ static void ex_tabs(exarg_T *eap) msg_scroll = true; win_T *lastused_win = valid_tabpage(lastused_tabpage) - ? lastused_tabpage->tp_curwin - : NULL; + ? lastused_tabpage->tp_curwin + : NULL; FOR_ALL_TABS(tp) { if (got_int) { @@ -5101,7 +5222,7 @@ static void ex_tabs(exarg_T *eap) msg_putchar('\n'); vim_snprintf(IObuff, IOSIZE, _("Tab page %d"), tabcount++); - msg_outtrans_attr(IObuff, HL_ATTR(HLF_T)); + msg_outtrans(IObuff, HL_ATTR(HLF_T)); os_breakcheck(); FOR_ALL_WINDOWS_IN_TAB(wp, tp) { @@ -5119,7 +5240,7 @@ static void ex_tabs(exarg_T *eap) } else { home_replace(wp->w_buffer, wp->w_buffer->b_fname, IObuff, IOSIZE, true); } - msg_outtrans(IObuff); + msg_outtrans(IObuff, 0); os_breakcheck(); } } @@ -5169,17 +5290,23 @@ static void ex_resize(exarg_T *eap) /// ":find [+command] <file>" command. static void ex_find(exarg_T *eap) { + char *file_to_find = NULL; + char *search_ctx = NULL; char *fname = find_file_in_path(eap->arg, strlen(eap->arg), - FNAME_MESS, true, curbuf->b_ffname); + FNAME_MESS, true, curbuf->b_ffname, + &file_to_find, &search_ctx); if (eap->addr_count > 0) { - // Repeat finding the file "count" times. This matters when it - // appears several times in the path. + // 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 = find_file_in_path(NULL, 0, FNAME_MESS, false, curbuf->b_ffname); + fname = find_file_in_path(NULL, 0, FNAME_MESS, false, curbuf->b_ffname, + &file_to_find, &search_ctx); } } + xfree(file_to_find); + vim_findfile_cleanup(search_ctx); if (fname == NULL) { return; @@ -5201,8 +5328,6 @@ static void ex_edit(exarg_T *eap) /// @param old_curwin curwin before doing a split or NULL void do_exedit(exarg_T *eap, win_T *old_curwin) { - int n; - // ":vi" command ends Ex mode. if (exmode_active && (eap->cmdidx == CMD_visual || eap->cmdidx == CMD_view)) { @@ -5211,18 +5336,17 @@ void do_exedit(exarg_T *eap, win_T *old_curwin) if (*eap->arg == NUL) { // Special case: ":global/pat/visual\NLvi-commands" if (global_busy) { - int rd = RedrawingDisabled; - int nwr = no_wait_return; - int ms = msg_scroll; - if (eap->nextcmd != NULL) { - stuffReadbuff((const char *)eap->nextcmd); + stuffReadbuff(eap->nextcmd); eap->nextcmd = NULL; } + const int save_rd = RedrawingDisabled; RedrawingDisabled = 0; + const int save_nwr = no_wait_return; no_wait_return = 0; need_wait_return = false; + const int save_ms = msg_scroll; msg_scroll = 0; redraw_all_later(UPD_NOT_VALID); pending_exmode_active = true; @@ -5230,9 +5354,9 @@ void do_exedit(exarg_T *eap, win_T *old_curwin) normal_enter(false, true); pending_exmode_active = false; - RedrawingDisabled = rd; - no_wait_return = nwr; - msg_scroll = ms; + RedrawingDisabled = save_rd; + no_wait_return = save_nwr; + msg_scroll = save_ms; } return; } @@ -5254,7 +5378,7 @@ void do_exedit(exarg_T *eap, win_T *old_curwin) if (*eap->arg != NUL && text_or_buf_locked()) { return; } - n = readonlymode; + int n = readonlymode; if (eap->cmdidx == CMD_view || eap->cmdidx == CMD_sview) { readonlymode = true; } else if (eap->cmdidx == CMD_enew) { @@ -5302,7 +5426,7 @@ void do_exedit(exarg_T *eap, win_T *old_curwin) if (eap->do_ecmd_cmd != NULL) { do_cmdline_cmd(eap->do_ecmd_cmd); } - n = curwin->w_arg_idx_invalid; + int n = curwin->w_arg_idx_invalid; check_arg_idx(curwin); if (n != curwin->w_arg_idx_invalid) { maketitle(); @@ -5337,9 +5461,9 @@ static void ex_popup(exarg_T *eap) 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")); + msg(_("No swap file"), 0); } else { - msg(curbuf->b_ml.ml_mfp->mf_fname); + msg(curbuf->b_ml.ml_mfp->mf_fname, 0); } } @@ -5350,8 +5474,8 @@ static void ex_syncbind(exarg_T *eap) { win_T *save_curwin = curwin; buf_T *save_curbuf = curbuf; - long topline; - long y; + linenr_T topline; + int y; linenr_T old_linenr = curwin->w_cursor.lnum; setpcmark(); @@ -5425,13 +5549,13 @@ static void ex_read(exarg_T *eap) return; } i = readfile(curbuf->b_ffname, curbuf->b_fname, - eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0, false); + eap->line2, 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); + (void)setaltfname(eap->arg, eap->arg, 1); } i = readfile(eap->arg, NULL, - eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0, false); + eap->line2, 0, (linenr_T)MAXLNUM, eap, 0, false); } if (i != OK) { if (!aborting()) { @@ -5447,13 +5571,13 @@ static void ex_read(exarg_T *eap) } else { lnum = 1; } - if (*ml_get(lnum) == NUL && u_savedel(lnum, 1L) == OK) { + if (*ml_get(lnum) == NUL && u_savedel(lnum, 1) == 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); + deleted_lines_mark(lnum, 1); } } redraw_curbuf_later(UPD_VALID); @@ -5651,9 +5775,9 @@ static void ex_pwd(exarg_T *eap) } else if (curtab->tp_localdir != NULL) { context = "tabpage"; } - smsg("[%s] %s", context, NameBuff); + smsg(0, "[%s] %s", context, NameBuff); } else { - msg(NameBuff); + msg(NameBuff, 0); } } else { emsg(_("E187: Unknown")); @@ -5663,25 +5787,27 @@ static void ex_pwd(exarg_T *eap) /// ":=". static void ex_equal(exarg_T *eap) { - smsg("%" PRId64, (int64_t)eap->line2); - ex_may_print(eap); + if (*eap->arg != NUL && *eap->arg != '|') { + // equivalent to :lua= expr + ex_lua(eap); + } else { + eap->nextcmd = find_nextcmd(eap->arg); + smsg(0, "%" PRId64, (int64_t)eap->line2); + } } static void ex_sleep(exarg_T *eap) { if (cursor_valid()) { - int n = curwin->w_winrow + curwin->w_wrow - msg_scrolled; - if (n >= 0) { - ui_cursor_goto(n, curwin->w_wincol + curwin->w_wcol); - } + setcursor_mayforce(true); } - long len = eap->line2; + int64_t len = eap->line2; switch (*eap->arg) { case 'm': break; case NUL: - len *= 1000L; break; + len *= 1000; break; default: semsg(_(e_invarg2), eap->arg); return; } @@ -5689,7 +5815,7 @@ static void ex_sleep(exarg_T *eap) } /// Sleep for "msec" milliseconds, but return early on CTRL-C. -void do_sleep(long msec) +void do_sleep(int64_t msec) { ui_flush(); // flush before waiting LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, msec, got_int); @@ -5746,7 +5872,7 @@ static void ex_wincmd(exarg_T *eap) // Pass flags on for ":vertical wincmd ]". postponed_split_flags = cmdmod.cmod_split; postponed_split_tab = cmdmod.cmod_tab; - do_window(*eap->arg, eap->addr_count > 0 ? eap->line2 : 0L, xchar); + do_window(*eap->arg, eap->addr_count > 0 ? eap->line2 : 0, xchar); postponed_split_flags = 0; postponed_split_tab = 0; } @@ -5816,8 +5942,12 @@ static void ex_put(exarg_T *eap) /// Handle ":copy" and ":move". static void ex_copymove(exarg_T *eap) { - long n = get_address(eap, &eap->arg, eap->addr_type, false, false, false, 1); + const char *errormsg = NULL; + linenr_T n = get_address(eap, &eap->arg, eap->addr_type, false, false, false, 1, &errormsg); if (eap->arg == NULL) { // error detected + if (errormsg != NULL) { + emsg(errormsg); + } eap->nextcmd = NULL; return; } @@ -5830,13 +5960,13 @@ static void ex_copymove(exarg_T *eap) } if (eap->cmdidx == CMD_move) { - if (do_move(eap->line1, eap->line2, (linenr_T)n) == FAIL) { + if (do_move(eap->line1, eap->line2, n) == FAIL) { return; } } else { - ex_copy(eap->line1, eap->line2, (linenr_T)n); + ex_copy(eap->line1, eap->line2, n); } - u_clearline(); + u_clearline(curbuf); beginline(BL_SOL | BL_FIX); ex_may_print(eap); } @@ -5862,7 +5992,7 @@ static void ex_submagic(exarg_T *eap) } /// ":smagic" and ":snomagic" preview callback. -static int ex_submagic_preview(exarg_T *eap, long cmdpreview_ns, handle_T cmdpreview_bufnr) +static int ex_submagic_preview(exarg_T *eap, int cmdpreview_ns, handle_T cmdpreview_bufnr) { const optmagic_T saved = magic_overruled; @@ -5944,7 +6074,7 @@ static void ex_undo(exarg_T *eap) return; } - long step = eap->line2; + linenr_T step = eap->line2; if (eap->forceit) { // undo! 123 // change number for "undo!" must be lesser than current change number @@ -5995,7 +6125,7 @@ static void ex_redo(exarg_T *eap) /// ":earlier" and ":later". static void ex_later(exarg_T *eap) { - long count = 0; + int count = 0; bool sec = false; bool file = false; char *p = eap->arg; @@ -6003,7 +6133,7 @@ static void ex_later(exarg_T *eap) if (*p == NUL) { count = 1; } else if (isdigit((uint8_t)(*p))) { - count = getdigits_long(&p, false, 0); + count = getdigits_int(&p, false, 0); switch (*p) { case 's': p++; sec = true; break; @@ -6334,6 +6464,11 @@ void restore_current_state(save_state_T *sst) ui_cursor_shape(); // may show different cursor shape } +bool expr_map_locked(void) +{ + return expr_map_lock > 0 && !(curbuf->b_flags & BF_DUMMY); +} + /// ":normal[!] {commands}": Execute normal mode commands. static void ex_normal(exarg_T *eap) { @@ -6343,10 +6478,11 @@ static void ex_normal(exarg_T *eap) } char *arg = NULL; - if (ex_normal_lock > 0) { + if (expr_map_locked()) { emsg(_(e_secure)); return; } + if (ex_normal_busy >= p_mmd) { emsg(_("E192: Recursive use of :normal too deep")); return; @@ -6360,8 +6496,7 @@ static void ex_normal(exarg_T *eap) // Count the number of characters to be escaped. int l; - char *p; - for (p = eap->arg; *p != NUL; p++) { + for (char *p = eap->arg; *p != NUL; p++) { for (l = utfc_ptr2len(p) - 1; l > 0; l--) { if (*++p == (char)K_SPECIAL) { // trailbyte K_SPECIAL len += 2; @@ -6371,7 +6506,7 @@ static void ex_normal(exarg_T *eap) if (len > 0) { arg = xmalloc(strlen(eap->arg) + (size_t)len + 1); len = 0; - for (p = eap->arg; *p != NUL; p++) { + for (char *p = eap->arg; *p != NUL; p++) { arg[len++] = *p; for (l = utfc_ptr2len(p) - 1; l > 0; l--) { arg[len++] = *++p; @@ -6489,9 +6624,9 @@ void exec_normal(bool was_typed) static void ex_checkpath(exarg_T *eap) { - find_pattern_in_path(NULL, 0, 0, false, false, CHECK_PATH, 1L, + find_pattern_in_path(NULL, 0, 0, false, false, CHECK_PATH, 1, eap->forceit ? ACTION_SHOW_ALL : ACTION_SHOW, - (linenr_T)1, (linenr_T)MAXLNUM); + 1, (linenr_T)MAXLNUM); } /// ":psearch" @@ -6526,9 +6661,9 @@ static void ex_findpat(exarg_T *eap) break; } - long n = 1; + int n = 1; if (ascii_isdigit(*eap->arg)) { // get count - n = getdigits_long(&eap->arg, false, 0); + n = getdigits_int(&eap->arg, false, 0); eap->arg = skipwhite(eap->arg); } if (*eap->arg == '/') { // Match regexp, not just whole words @@ -6549,7 +6684,7 @@ static void ex_findpat(exarg_T *eap) } if (!eap->skip) { find_pattern_in_path(eap->arg, 0, strlen(eap->arg), whole, !eap->forceit, - *eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY, + *eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY, n, action, eap->line1, eap->line2); } } @@ -6725,8 +6860,8 @@ ssize_t find_cmdline_var(const char *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 *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnump, char **errormsg, - int *escaped, bool empty_is_error) +char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnump, + const char **errormsg, int *escaped, bool empty_is_error) { char *result; char *resultbuf = NULL; @@ -6752,7 +6887,7 @@ char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnum // Note: In "\\%" the % is also not recognized! if (src > srcstart && src[-1] == '\\') { *usedlen = 0; - STRMOVE(src - 1, (char *)src); // remove backslash + STRMOVE(src - 1, src); // remove backslash return NULL; } @@ -6845,7 +6980,7 @@ char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnum break; case SPEC_CFILE: // file name under cursor - result = file_name_at_cursor(FNAME_MESS|FNAME_HYP, 1L, NULL); + result = file_name_at_cursor(FNAME_MESS|FNAME_HYP, 1, NULL); if (result == NULL) { *errormsg = ""; return NULL; @@ -6854,12 +6989,10 @@ char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnum break; case SPEC_AFILE: // file name for autocommand - if (autocmd_fname != NULL - && !path_is_absolute(autocmd_fname) - // For CmdlineEnter and related events, <afile> is not a path! #9348 - && !strequal("/", autocmd_fname)) { + if (autocmd_fname != NULL && !autocmd_fname_full) { // Still need to turn the fname into a full path. It was // postponed to avoid a delay when <afile> is not used. + autocmd_fname_full = true; result = FullName_save(autocmd_fname, false); // Copy into `autocmd_fname`, don't reassign it. #8165 xstrlcpy(autocmd_fname, result, MAXPATHL); @@ -6867,7 +7000,7 @@ char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnum } result = autocmd_fname; if (result == NULL) { - *errormsg = _("E495: no autocommand file name to substitute for \"<afile>\""); + *errormsg = _(e_no_autocommand_file_name_to_substitute_for_afile); return NULL; } result = path_try_shorten_fname(result); @@ -6875,7 +7008,7 @@ char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnum case SPEC_ABUF: // buffer number for autocommand if (autocmd_bufnr <= 0) { - *errormsg = _("E496: no autocommand buffer number to substitute for \"<abuf>\""); + *errormsg = _(e_no_autocommand_buffer_number_to_substitute_for_abuf); return NULL; } snprintf(strbuf, sizeof(strbuf), "%d", autocmd_bufnr); @@ -6885,7 +7018,7 @@ char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnum case SPEC_AMATCH: // match name for autocommand result = autocmd_match; if (result == NULL) { - *errormsg = _("E497: no autocommand match name to substitute for \"<amatch>\""); + *errormsg = _(e_no_autocommand_match_name_to_substitute_for_amatch); return NULL; } break; @@ -6917,7 +7050,7 @@ char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnum case SPEC_SLNUM: // line in file for ":so" command if (SOURCING_NAME == NULL || SOURCING_LNUM == 0) { - *errormsg = _("E842: no line number to use for \"<slnum>\""); + *errormsg = _(e_no_line_number_to_use_for_slnum); return NULL; } snprintf(strbuf, sizeof(strbuf), "%" PRIdLINENR, SOURCING_LNUM); @@ -6926,10 +7059,10 @@ char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnum case SPEC_SFLNUM: // line in script file if (current_sctx.sc_lnum + SOURCING_LNUM == 0) { - *errormsg = _("E961: no line number to use for \"<sflnum>\""); + *errormsg = _(e_no_line_number_to_use_for_sflnum); return NULL; } - snprintf((char *)strbuf, sizeof(strbuf), "%" PRIdLINENR, + snprintf(strbuf, sizeof(strbuf), "%" PRIdLINENR, current_sctx.sc_lnum + SOURCING_LNUM); result = strbuf; break; @@ -6982,7 +7115,7 @@ char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnum } result = NULL; } else { - result = xstrnsave(result, resultlen); + result = xmemdupz(result, resultlen); } xfree(resultbuf); return result; @@ -7001,7 +7134,7 @@ char *expand_sfile(char *arg) } else { // replace "<sfile>" with the sourced file name, and do ":" stuff size_t srclen; - char *errormsg; + const char *errormsg; char *repl = eval_vars(p, result, &srclen, NULL, &errormsg, NULL, true); if (errormsg != NULL) { if (*errormsg) { @@ -7055,24 +7188,6 @@ void dialog_msg(char *buff, char *format, char *fname) vim_snprintf(buff, DIALOG_MSG_SIZE, format, fname); } -/// ":behave {mswin,xterm}" -static void ex_behave(exarg_T *eap) -{ - 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) { - 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); - set_option_value_give_err("keymodel", 0L, "", 0); - } else { - semsg(_(e_invarg2), eap->arg); - } -} - static TriState filetype_detect = kNone; static TriState filetype_plugin = kNone; static TriState filetype_indent = kNone; @@ -7088,7 +7203,7 @@ static void ex_filetype(exarg_T *eap) { if (*eap->arg == NUL) { // Print current status. - smsg("filetype detection:%s plugin:%s indent:%s", + smsg(0, "filetype detection:%s plugin:%s indent:%s", filetype_detect == kTrue ? "ON" : "OFF", filetype_plugin == kTrue ? (filetype_detect == kTrue ? "ON" : "(on)") : "OFF", filetype_indent == kTrue ? (filetype_detect == kTrue ? "ON" : "(on)") : "OFF"); @@ -7100,7 +7215,7 @@ static void ex_filetype(exarg_T *eap) bool indent = false; // Accept "plugin" and "indent" in any order. - for (;;) { + while (true) { if (strncmp(arg, "plugin", 6) == 0) { plugin = true; arg = skipwhite(arg + 6); @@ -7189,7 +7304,7 @@ static void ex_setfiletype(exarg_T *eap) arg += 9; } - set_option_value_give_err("filetype", 0L, arg, OPT_LOCAL); + set_option_value_give_err("filetype", CSTR_AS_OPTVAL(arg), OPT_LOCAL); if (arg != eap->arg) { did_filetype = false; } @@ -7271,12 +7386,31 @@ void set_pressedreturn(bool val) static void ex_terminal(exarg_T *eap) { char ex_cmd[1024]; + size_t len = 0; + + if (cmdmod.cmod_tab > 0 || cmdmod.cmod_split != 0) { + bool multi_mods = false; + + // ex_cmd must be a null terminated string before passing to add_win_cmd_modifiers + ex_cmd[0] = '\0'; + + len = add_win_cmd_modifiers(ex_cmd, &cmdmod, &multi_mods); + assert(len < sizeof(ex_cmd)); + int result = snprintf(ex_cmd + len, sizeof(ex_cmd) - len, " new"); + assert(result > 0); + len += (size_t)result; + } else { + int result = snprintf(ex_cmd, sizeof(ex_cmd), "enew%s", eap->forceit ? "!" : ""); + assert(result > 0); + len += (size_t)result; + } + + assert(len < sizeof(ex_cmd)); if (*eap->arg != NUL) { // Run {cmd} in 'shell'. char *name = vim_strsave_escaped(eap->arg, "\"\\"); - snprintf(ex_cmd, sizeof(ex_cmd), - ":enew%s | call termopen(\"%s\")", - eap->forceit ? "!" : "", name); + snprintf(ex_cmd + len, sizeof(ex_cmd) - len, + " | call termopen(\"%s\")", name); xfree(name); } else { // No {cmd}: run the job with tokenized 'shell'. if (*p_sh == NUL) { @@ -7296,302 +7430,308 @@ static void ex_terminal(exarg_T *eap) } shell_free_argv(argv); - snprintf(ex_cmd, sizeof(ex_cmd), - ":enew%s | call termopen([%s])", - eap->forceit ? "!" : "", shell_argv + 1); + snprintf(ex_cmd + len, sizeof(ex_cmd) - len, + " | call termopen([%s])", shell_argv + 1); } do_cmdline_cmd(ex_cmd); } +/// ":fclose" +static void ex_fclose(exarg_T *eap) +{ + win_float_remove(eap->forceit, eap->line1); +} + void verify_command(char *cmd) { if (strcmp("smile", cmd) != 0) { return; // acceptable non-existing command } + int a = HL_ATTR(HLF_E); msg(" #xxn` #xnxx` ,+x@##@Mz;` .xxx" - "xxxxxxnz+, znnnnnnnnnnnnnnnn."); + "xxxxxxnz+, znnnnnnnnnnnnnnnn.", a); msg(" n###z x####` :x##########W+` ,###" - "##########M; W################."); + "##########M; W################.", a); msg(" n####; x####` `z##############W: ,###" - "############# W################."); + "############# W################.", a); msg(" n####W. x####` ,W#################+ ,###" - "############## W################."); + "############## W################.", a); msg(" n#####n x####` @################### ,###" - "##############i W################."); + "##############i W################.", a); msg(" n######i x####` .#########@W@########* ,###" - "##############W`W################."); + "##############W`W################.", a); msg(" n######@. x####` x######W*. `;n#######: ,###" - "#x,,,,:*M######iW###@:,,,,,,,,,,,`"); + "#x,,,,:*M######iW###@:,,,,,,,,,,,`", a); msg(" n#######n x####` *######+` :M#####M ,###" - "#n `x#####xW###@`"); + "#n `x#####xW###@`", a); msg(" n########* x####``@####@; `x#####i ,###" - "#n ,#####@W###@`"); + "#n ,#####@W###@`", a); msg(" n########@ x####`*#####i `M####M ,###" - "#n x#########@`"); + "#n x#########@`", a); msg(" n######### x####`M####z :#####:,###" - "#n z#########@`"); + "#n z#########@`", a); msg(" n#########* x####,#####. n####+,###" - "#n n#########@`"); + "#n n#########@`", a); msg(" n####@####@, x####i####x ;####x,###" - "#n `W#####@####+++++++++++i"); + "#n `W#####@####+++++++++++i", a); msg(" n####*#####M` x#########* `####@,###" - "#n i#####MW###############W"); + "#n i#####MW###############W", a); msg(" n####.######+ x####z####; W####,###" - "#n i@######W###############W"); + "#n i@######W###############W", a); msg(" n####.`W#####: x####n####: M####:###" - "#@nnnnnW#######,W###############W"); + "#@nnnnnW#######,W###############W", a); msg(" n####. :#####M`x####z####; W####,###" - "##############z W###############W"); + "##############z W###############W", a); msg(" n####. #######x#########* `####W,###" - "#############W` W###############W"); + "#############W` W###############W", a); msg(" n####. `M#####W####i####x ;####x,###" - "############W, W####+**********i"); + "############W, W####+**********i", a); msg(" n####. ,##########,#####. n####+,###" - "###########n. W###@`"); + "###########n. W###@`", a); msg(" n####. ##########`M####z :#####:,###" - "########Wz: W###@`"); + "########Wz: W###@`", a); msg(" n####. x#########`*#####i `M####M ,###" - "#x.....` W###@`"); + "#x.....` W###@`", a); msg(" n####. ,@########``@####@; `x#####i ,###" - "#n W###@`"); + "#n W###@`", a); msg(" n####. *########` *#####@+` ,M#####M ,###" - "#n W###@`"); + "#n W###@`", a); msg(" n####. x#######` x######W*. `;n######@: ,###" - "#n W###@,,,,,,,,,,,,`"); + "#n W###@,,,,,,,,,,,,`", a); msg(" n####. .@######` .#########@W@########* ,###" - "#n W################,"); + "#n W################,", a); msg(" n####. i######` @################### ,###" - "#n W################,"); + "#n W################,", a); msg(" n####. n#####` ,W#################+ ,###" - "#n W################,"); + "#n W################,", a); msg(" n####. .@####` .n##############W; ,###" - "#n W################,"); + "#n W################,", a); msg(" n####. i####` :x##########W+` ,###" - "#n W################,"); + "#n W################,", a); msg(" +nnnn` +nnn` ,+x@##@Mz;` .nnn" - "n+ zxxxxxxxxxxxxxxxx."); - msg(" "); + "n+ zxxxxxxxxxxxxxxxx.", a); + msg(" ", a); msg(" " - " ,+M@#Mi"); + " ,+M@#Mi", a); msg(" " - " .z########"); + " .z########", a); msg(" " - " i@#########i"); + " i@#########i", a); msg(" " - " `############W`"); + " `############W`", a); msg(" " - " `n#############i"); + " `n#############i", a); msg(" " - " `n##############n"); + " `n##############n", a); msg(" `` " - " z###############@`"); + " z###############@`", a); msg(" `W@z, " - " ##################,"); + " ##################,", a); msg(" *#####` " - " i############@x@###i"); + " i############@x@###i", a); msg(" ######M. " - " :#############n`,W##+"); + " :#############n`,W##+", a); msg(" +######@: " - " .W#########M@##+ *##z"); + " .W#########M@##+ *##z", a); msg(" :#######@: " - " `x########@#x###* ,##n"); + " `x########@#x###* ,##n", a); msg(" `@#######@; " - " z#########M*@nW#i .##x"); + " z#########M*@nW#i .##x", a); msg(" z########@i " - " *###########WM#@#, `##x"); + " *###########WM#@#, `##x", a); msg(" i##########+ " - " ;###########*n###@ `##x"); + " ;###########*n###@ `##x", a); msg(" `@#MM#######x, " - " ,@#########zM,`z##M `@#x"); + " ,@#########zM,`z##M `@#x", a); msg(" n##M#W#######n. " - " `.:i*+#zzzz##+i:.` ,W#########Wii,`n@#@` n@##n"); + " `.:i*+#zzzz##+i:.` ,W#########Wii,`n@#@` n@##n", a); msg(" ;###@#x#######n `,i" - "#nW@#####@@WWW@@####@Mzi. ,W##########@z.. ;zM#+i####z"); + "#nW@#####@@WWW@@####@Mzi. ,W##########@z.. ;zM#+i####z", a); msg(" x####nz######## .;#x@##" - "@Wn#*;,.` ``,:*#x@##M+, ;@########xz@WM+#` `n@#######"); + "@Wn#*;,.` ``,:*#x@##M+, ;@########xz@WM+#` `n@#######", a); msg(" ,@####M########xi#@##@Mzi," - "` .+x###Mi:n##########Mz```.:i *@######*"); + "` .+x###Mi:n##########Mz```.:i *@######*", a); msg(" *#####W#########ix+:` " - " :n#############z: `*.`M######i"); + " :n#############z: `*.`M######i", a); msg(" i#W##nW@+@##@#M@; " - " ;W@@##########W, i`x@#####,"); + " ;W@@##########W, i`x@#####,", a); msg(" `@@n@Wn#@iMW*#*: " - " `iz#z@######x. M######`"); + " `iz#z@######x. M######`", a); msg(" z##zM###x`*, .` " - " `iW#####W;:` +#####M"); + " `iW#####W;:` +#####M", a); msg(" ,###nn##n` " - " ,#####x;` ,;@######"); + " ,#####x;` ,;@######", a); msg(" x###xz#. " - " in###+ `:######@."); + " in###+ `:######@.", a); msg(" ;####n+ " - " `Mnx##xi` , zM#######"); + " `Mnx##xi` , zM#######", a); msg(" `W####+ " - "i. `.+x###@#. :n,z######:"); + "i. `.+x###@#. :n,z######:", a); msg(" z####@` ;" - "#: .ii@###@;.*M*z####@`"); + "#: .ii@###@;.*M*z####@`", a); msg(" i####M ` `i@" - "#, :: +#n##@+@##W####n"); + "#, :: +#n##@+@##W####n", a); msg(" :####x ,i. ##xzM###" - "@` i. .@@, .z####x#######*"); + "@` i. .@@, .z####x#######*", a); msg(" ,###W; i##Wz########" - "# :## z##n ,@########x###:"); + "# :## z##n ,@########x###:", a); msg(" n##n `W###########M" - "`;n, i#x ,###@i *W########W#@`"); + "`;n, i#x ,###@i *W########W#@`", a); msg(" .@##+ `x###########@." - " z#+ .M#W``x#####n` `;#######@z#x"); + " z#+ .M#W``x#####n` `;#######@z#x", a); msg(" n###z :W############@ " - " z#* @##xM#######@n; `########nW+"); + " z#* @##xM#######@n; `########nW+", a); msg(" ;####nW##############W " - ":@#* `@#############* :########z@i`"); + ":@#* `@#############* :########z@i`", a); msg(" M##################### " - "M##: @#############@: *W########M#"); + "M##: @#############@: *W########M#", a); msg(" ;#####################i." - "##x` W#############W, :n########zx"); + "##x` W#############W, :n########zx", a); msg(" x####################@.`" - "x; @#############z. .@########W#"); + "x; @#############z. .@########W#", a); msg(" ,######################` " - " W###############x*,` W######zM#i"); + " W###############x*,` W######zM#i", a); msg(" #######################: " - " z##################@x+*#zzi `@#########."); + " z##################@x+*#zzi `@#########.", a); msg(" W########W#z#M#########; " - " *##########################z :@#######@`"); + " *##########################z :@#######@`", a); msg(" `@#######x`;#z ,x#######; " - " z###########M###xnM@########* :M######@"); + " z###########M###xnM@########* :M######@", a); msg(" i########, x#@` z######; " - " *##########i *#@` `+########+` n######."); + " *##########i *#@` `+########+` n######.", a); msg(" n#######@` M##, `W#####. " - " *#########z ###; z########M: :W####n"); + " *#########z ###; z########M: :W####n", a); msg(" M#######M n##. x####x " - " `x########: z##+ M#########@; .n###+"); + " `x########: z##+ M#########@; .n###+", a); msg(" W#######@` :#W `@####: " - " `@######W i### ;###########@. n##n"); + " `@######W i### ;###########@. n##n", a); msg(" W########z` ,, .x####z " - " @######@` `W#; `W############* *###;"); + " @######@` `W#; `W############* *###;", a); msg(" `@#########Mi,:*n@####W` " - " W#######* .. `n#############i i###x"); + " W#######* .. `n#############i i###x", a); msg(" .#####################z " - " `@#######@*` .x############n:` ;####."); + " `@#######@*` .x############n:` ;####.", a); msg(" :####################x`,,` " - " `W#########@x#+#@#############i ,####:"); + " `W#########@x#+#@#############i ,####:", a); msg(" ;###################x#@###x" - "i` *############################: `####i"); + "i` *############################: `####i", a); msg(" i##################+#######" - "#M, x##########################@` W###i"); + "#M, x##########################@` W###i", a); msg(" *################@; @######" - "##@, .W#########################@ x###:"); + "##@, .W#########################@ x###:", a); msg(" .+M#############z. M######" - "###x ,W########################@` ####."); + "###x ,W########################@` ####.", a); msg(" *M*;z@########x: :W#####" - "##i .M########################i i###:"); + "##i .M########################i i###:", a); msg(" *##@z;#@####x: :z###" - "@i `########################x .###;"); + "@i `########################x .###;", a); msg(" *#####n;#@## ;##" - "* ,x#####################@` W##*"); + "* ,x#####################@` W##*", a); msg(" *#######n;* :M##" - "W*, *W####################` n##z"); + "W*, *W####################` n##z", a); msg(" i########@. ,*n####" - "###M*` `###################M *##M"); + "###M*` `###################M *##M", a); msg(" i########n `z#####@@" - "#####Wi ,M################; ,##@`"); + "#####Wi ,M################; ,##@`", a); msg(" ;WMWW@###* .x##@ni.``" - ".:+zW##z` `n##############z @##,"); + ".:+zW##z` `n##############z @##,", a); msg(" .*++*i;;;. .M#@+` " - " .##n `x############x` n##i"); + " .##n `x############x` n##i", a); msg(" :########* x#W, " - " *#+ *###########M` +##+"); + " *#+ *###########M` +##+", a); msg(" ,######### :#@: " - " ##: #nzzzzzzzzzz. :##x"); + " ##: #nzzzzzzzzzz. :##x", a); msg(" .#####Wz+` ##+ " - " `MM` .znnnnnnnnn. `@#@`"); + " `MM` .znnnnnnnnn. `@#@`", a); msg(" `@@ni;*nMz` @W` " - " :#+ .x#######n x##,"); + " :#+ .x#######n x##,", a); msg(" i;z@#####, .#* " - " z#: ;;;*zW##; ###i"); + " z#: ;;;*zW##; ###i", a); msg(" z########: :#; " - " `Wx +###Wni;n. ;##z"); + " `Wx +###Wni;n. ;##z", a); msg(" n########W: .#* " - " ,#, ;#######@+ `@#M"); + " ,#, ;#######@+ `@#M", a); msg(" .###########n;.MM " - " n* ;iM#######* x#@`"); + " n* ;iM#######* x#@`", a); msg(" :#############@;; " - " .n` ,#W*iW#####W` +##,"); + " .n` ,#W*iW#####W` +##,", a); msg(" ,##############. " - " ix. `x###M;####### ,##i"); + " ix. `x###M;####### ,##i", a); msg(" .#############@` " - " x@n**#W######z;M###@. W##"); + " x@n**#W######z;M###@. W##", a); msg(" .##############W: " - " .x############@*;zW#; z#x"); + " .x############@*;zW#; z#x", a); msg(" ,###############@; " - " `##############@n*;. i#@"); + " `##############@n*;. i#@", a); msg(" ,#################i " - " :n##############W` .##,"); + " :n##############W` .##,", a); msg(" ,###################` " - " .+W##########W, `##i"); + " .+W##########W, `##i", a); msg(" :###################@zi,` " - " ;zM@@@WMn*` @#z"); + " ;zM@@@WMn*` @#z", a); msg(" :#######################@x+" - "*i;;:i#M, `` M#W"); + "*i;;:i#M, `` M#W", a); msg(" ;##########################" - "######@x. n##,"); + "######@x. n##,", a); msg(" i#####################@W@@@" - "@Wxz*:` *##+"); + "@Wxz*:` *##+", a); msg(" *######################+```" - " :##M"); + " :##M", a); msg(" ########################M; " - " `@##,"); + " `@##,", a); msg(" z#########################x" - ", z###"); + ", z###", a); msg(" n##########################" - "#n: ;##W`"); + "#n: ;##W`", a); msg(" x##########################" - "###Mz#++##* `W##i"); + "###Mz#++##* `W##i", a); msg(" M##########################" - "##########@` ###x"); + "##########@` ###x", a); msg(" W##########################" - "###########` .###,"); + "###########` .###,", a); msg(" @##########################" - "##########M n##z"); + "##########M n##z", a); msg(" @##################z*i@WMMM" - "x#x@#####,. :##@."); + "x#x@#####,. :##@.", a); msg(" `#####################@xi` " - " `::,* x##+"); + " `::,* x##+", a); msg(" .#####################@#M. " - " ;##@`"); + " ;##@`", a); msg(" ,#####################:. " - " M##i"); + " M##i", a); msg(" ;###################ni` " - " i##M"); + " i##M", a); msg(" *#################W#` " - " `W##,"); + " `W##,", a); msg(" z#################@Wx+. " - " +###"); + " +###", a); msg(" x######################z. " - " .@#@`"); + " .@#@`", a); msg(" `@#######################@; " - " z##;"); + " z##;", a); msg(" :##########################: " - " :##z"); + " :##z", a); msg(" +#########################W# " - " M#W"); + " M#W", a); msg(" W################@n+*i;:,` " - " +##,"); + " +##,", a); msg(" :##################WMxz+, " - " ,##i"); + " ,##i", a); msg(" n#######################W.., " - " W##"); + " W##", a); msg(" +#########################WW@+. .:. " - " z#x"); + " z#x", a); msg(" `@#############################@@###: " - " *#W"); + " *#W", a); msg(" #################################Wz: " - " :#@"); + " :#@", a); msg(",@###############################i " - " .##"); + " .##", a); msg("n@@@@@@@#########################+ " - " `##"); + " `##", a); msg("` `.:.`.,:iii;;;;;;;;iii;;;:` `.`` " - " `nW"); + " `nW", a); } /// Get argt of command with id |