To: vim_dev@googlegroups.com Subject: Patch 8.1.0281 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.0281 Problem: Parsing command modifiers is not separated. Solution: Move command modifier parsing to a separate function. Files: src/ex_docmd.c, src/proto/ex_docmd.pro, src/ex_cmds.h, src/globals.h, src/feature.h *** ../vim-8.1.0280/src/ex_docmd.c 2018-08-10 23:13:07.934024645 +0200 --- src/ex_docmd.c 2018-08-13 23:27:03.980298529 +0200 *************** *** 1709,1721 **** char_u *errormsg = NULL; /* error message */ char_u *after_modifier = NULL; exarg_T ea; /* Ex command arguments */ - long verbose_save = -1; int save_msg_scroll = msg_scroll; - int save_msg_silent = -1; - int did_esilent = 0; - #ifdef HAVE_SANDBOX - int did_sandbox = FALSE; - #endif cmdmod_T save_cmdmod; int ni; /* set when Not Implemented */ char_u *cmd; --- 1709,1715 ---- *************** *** 1742,1748 **** * recursive calls. */ save_cmdmod = cmdmod; - vim_memset(&cmdmod, 0, sizeof(cmdmod)); /* "#!anything" is handled like a comment. */ if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') --- 1736,1741 ---- *************** *** 1750,1977 **** /* * Repeat until no more command modifiers are found. */ ea.cmd = *cmdlinep; ! for (;;) ! { ! /* ! * 1. Skip comment lines and leading white space and colons. ! */ ! while (*ea.cmd == ' ' || *ea.cmd == '\t' || *ea.cmd == ':') ! ++ea.cmd; ! ! /* in ex mode, an empty line works like :+ */ ! if (*ea.cmd == NUL && exmode_active ! && (getline_equal(fgetline, cookie, getexmodeline) ! || getline_equal(fgetline, cookie, getexline)) ! && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) ! { ! ea.cmd = (char_u *)"+"; ! ex_pressedreturn = TRUE; ! } ! ! /* ignore comment and empty lines */ ! if (*ea.cmd == '"') ! goto doend; ! if (*ea.cmd == NUL) ! { ! ex_pressedreturn = TRUE; ! goto doend; ! } ! ! /* ! * 2. Handle command modifiers. ! */ ! p = skip_range(ea.cmd, NULL); ! switch (*p) ! { ! /* When adding an entry, also modify cmd_exists(). */ ! case 'a': if (!checkforcmd(&ea.cmd, "aboveleft", 3)) ! break; ! cmdmod.split |= WSP_ABOVE; ! continue; ! ! case 'b': if (checkforcmd(&ea.cmd, "belowright", 3)) ! { ! cmdmod.split |= WSP_BELOW; ! continue; ! } ! if (checkforcmd(&ea.cmd, "browse", 3)) ! { ! #ifdef FEAT_BROWSE_CMD ! cmdmod.browse = TRUE; ! #endif ! continue; ! } ! if (!checkforcmd(&ea.cmd, "botright", 2)) ! break; ! cmdmod.split |= WSP_BOT; ! continue; ! ! case 'c': if (!checkforcmd(&ea.cmd, "confirm", 4)) ! break; ! #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) ! cmdmod.confirm = TRUE; ! #endif ! continue; ! ! case 'k': if (checkforcmd(&ea.cmd, "keepmarks", 3)) ! { ! cmdmod.keepmarks = TRUE; ! continue; ! } ! if (checkforcmd(&ea.cmd, "keepalt", 5)) ! { ! cmdmod.keepalt = TRUE; ! continue; ! } ! if (checkforcmd(&ea.cmd, "keeppatterns", 5)) ! { ! cmdmod.keeppatterns = TRUE; ! continue; ! } ! if (!checkforcmd(&ea.cmd, "keepjumps", 5)) ! break; ! cmdmod.keepjumps = TRUE; ! continue; ! ! case 'f': /* only accept ":filter {pat} cmd" */ ! { ! char_u *reg_pat; ! ! if (!checkforcmd(&p, "filter", 4) ! || *p == NUL || ends_excmd(*p)) ! break; ! if (*p == '!') ! { ! cmdmod.filter_force = TRUE; ! p = skipwhite(p + 1); ! if (*p == NUL || ends_excmd(*p)) ! break; ! } ! p = skip_vimgrep_pat(p, ®_pat, NULL); ! if (p == NULL || *p == NUL) ! break; ! cmdmod.filter_regmatch.regprog = ! vim_regcomp(reg_pat, RE_MAGIC); ! if (cmdmod.filter_regmatch.regprog == NULL) ! break; ! ea.cmd = p; ! continue; ! } ! ! /* ":hide" and ":hide | cmd" are not modifiers */ ! case 'h': if (p != ea.cmd || !checkforcmd(&p, "hide", 3) ! || *p == NUL || ends_excmd(*p)) ! break; ! ea.cmd = p; ! cmdmod.hide = TRUE; ! continue; ! ! case 'l': if (checkforcmd(&ea.cmd, "lockmarks", 3)) ! { ! cmdmod.lockmarks = TRUE; ! continue; ! } ! ! if (!checkforcmd(&ea.cmd, "leftabove", 5)) ! break; ! cmdmod.split |= WSP_ABOVE; ! continue; ! ! case 'n': if (checkforcmd(&ea.cmd, "noautocmd", 3)) ! { ! if (cmdmod.save_ei == NULL) ! { ! /* Set 'eventignore' to "all". Restore the ! * existing option value later. */ ! cmdmod.save_ei = vim_strsave(p_ei); ! set_string_option_direct((char_u *)"ei", -1, ! (char_u *)"all", OPT_FREE, SID_NONE); ! } ! continue; ! } ! if (!checkforcmd(&ea.cmd, "noswapfile", 3)) ! break; ! cmdmod.noswapfile = TRUE; ! continue; ! ! case 'r': if (!checkforcmd(&ea.cmd, "rightbelow", 6)) ! break; ! cmdmod.split |= WSP_BELOW; ! continue; ! ! case 's': if (checkforcmd(&ea.cmd, "sandbox", 3)) ! { ! #ifdef HAVE_SANDBOX ! if (!did_sandbox) ! ++sandbox; ! did_sandbox = TRUE; #endif ! continue; ! } ! if (!checkforcmd(&ea.cmd, "silent", 3)) ! break; ! if (save_msg_silent == -1) ! save_msg_silent = msg_silent; ! ++msg_silent; ! if (*ea.cmd == '!' && !VIM_ISWHITE(ea.cmd[-1])) ! { ! /* ":silent!", but not "silent !cmd" */ ! ea.cmd = skipwhite(ea.cmd + 1); ! ++emsg_silent; ! ++did_esilent; ! } ! continue; ! ! case 't': if (checkforcmd(&p, "tab", 3)) ! { ! long tabnr = get_address(&ea, &ea.cmd, ADDR_TABS, ! ea.skip, FALSE, 1); ! if (tabnr == MAXLNUM) ! cmdmod.tab = tabpage_index(curtab) + 1; ! else ! { ! if (tabnr < 0 || tabnr > LAST_TAB_NR) ! { ! errormsg = (char_u *)_(e_invrange); ! goto doend; ! } ! cmdmod.tab = tabnr + 1; ! } ! ea.cmd = p; ! continue; ! } ! if (!checkforcmd(&ea.cmd, "topleft", 2)) ! break; ! cmdmod.split |= WSP_TOP; ! continue; ! ! case 'u': if (!checkforcmd(&ea.cmd, "unsilent", 3)) ! break; ! if (save_msg_silent == -1) ! save_msg_silent = msg_silent; ! msg_silent = 0; ! continue; - case 'v': if (checkforcmd(&ea.cmd, "vertical", 4)) - { - cmdmod.split |= WSP_VERT; - continue; - } - if (!checkforcmd(&p, "verbose", 4)) - break; - if (verbose_save < 0) - verbose_save = p_verbose; - if (vim_isdigit(*ea.cmd)) - p_verbose = atoi((char *)ea.cmd); - else - p_verbose = 1; - ea.cmd = p; - continue; - } - break; - } after_modifier = ea.cmd; #ifdef FEAT_EVAL --- 1743,1760 ---- /* * Repeat until no more command modifiers are found. + * The "ea" structure holds the arguments that can be used. */ ea.cmd = *cmdlinep; ! ea.cmdlinep = cmdlinep; ! ea.getline = fgetline; ! ea.cookie = cookie; ! #ifdef FEAT_EVAL ! ea.cstack = cstack; #endif ! if (parse_command_modifiers(&ea, &errormsg) == FAIL) ! goto doend; after_modifier = ea.cmd; #ifdef FEAT_EVAL *************** *** 2688,2712 **** /* The :try command saves the emsg_silent flag, reset it here when * ":silent! try" was used, it should only apply to :try itself. */ ! if (ea.cmdidx == CMD_try && did_esilent > 0) { ! emsg_silent -= did_esilent; if (emsg_silent < 0) emsg_silent = 0; ! did_esilent = 0; } /* * 7. Execute the command. - * - * The "ea" structure holds the arguments that can be used. */ - ea.cmdlinep = cmdlinep; - ea.getline = fgetline; - ea.cookie = cookie; - #ifdef FEAT_EVAL - ea.cstack = cstack; - #endif #ifdef FEAT_USR_CMDS if (IS_USER_CMDIDX(ea.cmdidx)) --- 2471,2487 ---- /* The :try command saves the emsg_silent flag, reset it here when * ":silent! try" was used, it should only apply to :try itself. */ ! if (ea.cmdidx == CMD_try && ea.did_esilent > 0) { ! emsg_silent -= ea.did_esilent; if (emsg_silent < 0) emsg_silent = 0; ! ea.did_esilent = 0; } /* * 7. Execute the command. */ #ifdef FEAT_USR_CMDS if (IS_USER_CMDIDX(ea.cmdidx)) *************** *** 2775,2782 **** ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL); #endif ! if (verbose_save >= 0) ! p_verbose = verbose_save; if (cmdmod.save_ei != NULL) { --- 2550,2557 ---- ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL); #endif ! if (ea.verbose_save >= 0) ! p_verbose = ea.verbose_save; if (cmdmod.save_ei != NULL) { *************** *** 2791,2803 **** cmdmod = save_cmdmod; ! if (save_msg_silent != -1) { /* messages could be enabled for a serious error, need to check if the * counters don't become negative */ ! if (!did_emsg || msg_silent > save_msg_silent) ! msg_silent = save_msg_silent; ! emsg_silent -= did_esilent; if (emsg_silent < 0) emsg_silent = 0; /* Restore msg_scroll, it's set by file I/O commands, even when no --- 2566,2578 ---- cmdmod = save_cmdmod; ! if (ea.save_msg_silent != -1) { /* messages could be enabled for a serious error, need to check if the * counters don't become negative */ ! if (!did_emsg || msg_silent > ea.save_msg_silent) ! msg_silent = ea.save_msg_silent; ! emsg_silent -= ea.did_esilent; if (emsg_silent < 0) emsg_silent = 0; /* Restore msg_scroll, it's set by file I/O commands, even when no *************** *** 2811,2817 **** } #ifdef HAVE_SANDBOX ! if (did_sandbox) --sandbox; #endif --- 2586,2592 ---- } #ifdef HAVE_SANDBOX ! if (ea.did_sandbox) --sandbox; #endif *************** *** 2829,2834 **** --- 2604,2853 ---- #endif /* + * Parse and skip over command modifiers: + * - update eap->cmd + * - store flags in "cmdmod". + * - Set ex_pressedreturn for an empty command line. + * - set msg_silent for ":silent" + * - set p_verbose for ":verbose" + * - Increment "sandbox" for ":sandbox" + * Return FAIL when the command is not to be executed. + * May set "errormsg" to an error message. + */ + int + parse_command_modifiers(exarg_T *eap, char_u **errormsg) + { + char_u *p; + + vim_memset(&cmdmod, 0, sizeof(cmdmod)); + eap->verbose_save = -1; + eap->save_msg_silent = -1; + + for (;;) + { + /* + * 1. Skip comment lines and leading white space and colons. + */ + while (*eap->cmd == ' ' || *eap->cmd == '\t' || *eap->cmd == ':') + ++eap->cmd; + + /* in ex mode, an empty line works like :+ */ + if (*eap->cmd == NUL && exmode_active + && (getline_equal(eap->getline, eap->cookie, getexmodeline) + || getline_equal(eap->getline, eap->cookie, getexline)) + && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) + { + eap->cmd = (char_u *)"+"; + ex_pressedreturn = TRUE; + } + + /* ignore comment and empty lines */ + if (*eap->cmd == '"') + return FAIL; + if (*eap->cmd == NUL) + { + ex_pressedreturn = TRUE; + return FAIL; + } + + /* + * 2. Handle command modifiers. + */ + p = skip_range(eap->cmd, NULL); + switch (*p) + { + /* When adding an entry, also modify cmd_exists(). */ + case 'a': if (!checkforcmd(&eap->cmd, "aboveleft", 3)) + break; + cmdmod.split |= WSP_ABOVE; + continue; + + case 'b': if (checkforcmd(&eap->cmd, "belowright", 3)) + { + cmdmod.split |= WSP_BELOW; + continue; + } + if (checkforcmd(&eap->cmd, "browse", 3)) + { + #ifdef FEAT_BROWSE_CMD + cmdmod.browse = TRUE; + #endif + continue; + } + if (!checkforcmd(&eap->cmd, "botright", 2)) + break; + cmdmod.split |= WSP_BOT; + continue; + + case 'c': if (!checkforcmd(&eap->cmd, "confirm", 4)) + break; + #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) + cmdmod.confirm = TRUE; + #endif + continue; + + case 'k': if (checkforcmd(&eap->cmd, "keepmarks", 3)) + { + cmdmod.keepmarks = TRUE; + continue; + } + if (checkforcmd(&eap->cmd, "keepalt", 5)) + { + cmdmod.keepalt = TRUE; + continue; + } + if (checkforcmd(&eap->cmd, "keeppatterns", 5)) + { + cmdmod.keeppatterns = TRUE; + continue; + } + if (!checkforcmd(&eap->cmd, "keepjumps", 5)) + break; + cmdmod.keepjumps = TRUE; + continue; + + case 'f': /* only accept ":filter {pat} cmd" */ + { + char_u *reg_pat; + + if (!checkforcmd(&p, "filter", 4) + || *p == NUL || ends_excmd(*p)) + break; + if (*p == '!') + { + cmdmod.filter_force = TRUE; + p = skipwhite(p + 1); + if (*p == NUL || ends_excmd(*p)) + break; + } + p = skip_vimgrep_pat(p, ®_pat, NULL); + if (p == NULL || *p == NUL) + break; + cmdmod.filter_regmatch.regprog = + vim_regcomp(reg_pat, RE_MAGIC); + if (cmdmod.filter_regmatch.regprog == NULL) + break; + eap->cmd = p; + continue; + } + + /* ":hide" and ":hide | cmd" are not modifiers */ + case 'h': if (p != eap->cmd || !checkforcmd(&p, "hide", 3) + || *p == NUL || ends_excmd(*p)) + break; + eap->cmd = p; + cmdmod.hide = TRUE; + continue; + + case 'l': if (checkforcmd(&eap->cmd, "lockmarks", 3)) + { + cmdmod.lockmarks = TRUE; + continue; + } + + if (!checkforcmd(&eap->cmd, "leftabove", 5)) + break; + cmdmod.split |= WSP_ABOVE; + continue; + + case 'n': if (checkforcmd(&eap->cmd, "noautocmd", 3)) + { + if (cmdmod.save_ei == NULL) + { + /* Set 'eventignore' to "all". Restore the + * existing option value later. */ + cmdmod.save_ei = vim_strsave(p_ei); + set_string_option_direct((char_u *)"ei", -1, + (char_u *)"all", OPT_FREE, SID_NONE); + } + continue; + } + if (!checkforcmd(&eap->cmd, "noswapfile", 3)) + break; + cmdmod.noswapfile = TRUE; + continue; + + case 'r': if (!checkforcmd(&eap->cmd, "rightbelow", 6)) + break; + cmdmod.split |= WSP_BELOW; + continue; + + case 's': if (checkforcmd(&eap->cmd, "sandbox", 3)) + { + #ifdef HAVE_SANDBOX + if (!eap->did_sandbox) + ++sandbox; + eap->did_sandbox = TRUE; + #endif + continue; + } + if (!checkforcmd(&eap->cmd, "silent", 3)) + break; + if (eap->save_msg_silent == -1) + eap->save_msg_silent = msg_silent; + ++msg_silent; + if (*eap->cmd == '!' && !VIM_ISWHITE(eap->cmd[-1])) + { + /* ":silent!", but not "silent !cmd" */ + eap->cmd = skipwhite(eap->cmd + 1); + ++emsg_silent; + ++eap->did_esilent; + } + continue; + + case 't': if (checkforcmd(&p, "tab", 3)) + { + long tabnr = get_address(eap, &eap->cmd, ADDR_TABS, + eap->skip, FALSE, 1); + if (tabnr == MAXLNUM) + cmdmod.tab = tabpage_index(curtab) + 1; + else + { + if (tabnr < 0 || tabnr > LAST_TAB_NR) + { + *errormsg = (char_u *)_(e_invrange); + return FAIL; + } + cmdmod.tab = tabnr + 1; + } + eap->cmd = p; + continue; + } + if (!checkforcmd(&eap->cmd, "topleft", 2)) + break; + cmdmod.split |= WSP_TOP; + continue; + + case 'u': if (!checkforcmd(&eap->cmd, "unsilent", 3)) + break; + if (eap->save_msg_silent == -1) + eap->save_msg_silent = msg_silent; + msg_silent = 0; + continue; + + case 'v': if (checkforcmd(&eap->cmd, "vertical", 4)) + { + cmdmod.split |= WSP_VERT; + continue; + } + if (!checkforcmd(&p, "verbose", 4)) + break; + if (eap->verbose_save < 0) + eap->verbose_save = p_verbose; + if (vim_isdigit(*eap->cmd)) + p_verbose = atoi((char *)eap->cmd); + else + p_verbose = 1; + eap->cmd = p; + continue; + } + break; + } + + return OK; + } + + /* * Parse the address range, if any, in "eap". * Return FAIL and set "errormsg" or return OK. */ *** ../vim-8.1.0280/src/proto/ex_docmd.pro 2018-08-10 23:13:07.934024645 +0200 --- src/proto/ex_docmd.pro 2018-08-13 23:24:18.797373050 +0200 *************** *** 4,9 **** --- 4,10 ---- int do_cmdline(char_u *cmdline, char_u *(*fgetline)(int, void *, int), void *cookie, int flags); int getline_equal(char_u *(*fgetline)(int, void *, int), void *cookie, char_u *(*func)(int, void *, int)); void *getline_cookie(char_u *(*fgetline)(int, void *, int), void *cookie); + int parse_command_modifiers(exarg_T *eap, char_u **errormsg); int parse_cmd_address(exarg_T *eap, char_u **errormsg); int checkforcmd(char_u **pp, char *cmd, int len); int modifier_len(char_u *cmd); *** ../vim-8.1.0280/src/ex_cmds.h 2018-07-10 19:39:14.994973018 +0200 --- src/ex_cmds.h 2018-08-13 23:25:36.236870329 +0200 *************** *** 1792,1797 **** --- 1792,1803 ---- #ifdef FEAT_EVAL struct condstack *cstack; /* condition stack for ":if" etc. */ #endif + long verbose_save; // saved value of p_verbose + int save_msg_silent; // saved value of msg_silent + int did_esilent; // how many times emsg_silent was incremented + #ifdef HAVE_SANDBOX + int did_sandbox; // when TRUE did ++sandbox + #endif }; #define FORCE_BIN 1 /* ":edit ++bin file" */ *** ../vim-8.1.0280/src/globals.h 2018-08-11 16:40:39.064311995 +0200 --- src/globals.h 2018-08-13 23:18:14.323704509 +0200 *************** *** 678,685 **** * changed, no buffer can be deleted and * current directory can't be changed. * Used for SwapExists et al. */ ! #ifdef FEAT_EVAL ! # define HAVE_SANDBOX EXTERN int sandbox INIT(= 0); /* Non-zero when evaluating an expression in a * "sandbox". Several things are not allowed --- 678,684 ---- * changed, no buffer can be deleted and * current directory can't be changed. * Used for SwapExists et al. */ ! #ifdef HAVE_SANDBOX EXTERN int sandbox INIT(= 0); /* Non-zero when evaluating an expression in a * "sandbox". Several things are not allowed *** ../vim-8.1.0280/src/feature.h 2018-07-29 16:09:14.644945560 +0200 --- src/feature.h 2018-08-13 23:19:07.623368124 +0200 *************** *** 355,360 **** --- 355,364 ---- # endif #endif + #ifdef FEAT_EVAL + # define HAVE_SANDBOX + #endif + /* * +profile Profiling for functions and scripts. */ *** ../vim-8.1.0280/src/version.c 2018-08-13 22:54:31.456665135 +0200 --- src/version.c 2018-08-13 23:04:38.032484283 +0200 *************** *** 796,797 **** --- 796,799 ---- { /* Add new patch number below this line */ + /**/ + 281, /**/ -- Violators can be fined, arrested or jailed for making ugly faces at a dog. [real standing law in Oklahoma, United States of America] /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///