parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only)
{
    char_u *p;

    vim_memset(&cmdmod, 0, sizeof(cmdmod));
    eap->verbose_save = -1;
    eap->save_msg_silent = -1;

    // Repeat until no more command modifiers are found.
    for (;;)
    {
	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 *)"+";
	    if (!skip_only)
		ex_pressedreturn = TRUE;
	}

	/* ignore comment and empty lines */
	if (*eap->cmd == '"')
	    return FAIL;
	if (*eap->cmd == NUL)
	{
	    if (!skip_only)
		ex_pressedreturn = TRUE;
	    return FAIL;
	}

	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;
			    }
			    if (skip_only)
				p = skip_vimgrep_pat(p, NULL, NULL);
			    else
				// NOTE: This puts a NUL after the pattern.
				p = skip_vimgrep_pat(p, &reg_pat, NULL);
			    if (p == NULL || *p == NUL)
				break;
			    if (!skip_only)
			    {
				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 && !skip_only)
			    {
				/* 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 (!skip_only)
			    {
				if (!eap->did_sandbox)
				    ++sandbox;
				eap->did_sandbox = TRUE;
			    }
#endif
			    continue;
			}
			if (!checkforcmd(&eap->cmd, "silent", 3))
			    break;
			if (!skip_only)
			{
			    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);
			    if (!skip_only)
			    {
				++emsg_silent;
				++eap->did_esilent;
			    }
			}
			continue;

	    case 't':	if (checkforcmd(&p, "tab", 3))
			{
			    if (!skip_only)
			    {
				long tabnr = get_address(eap, &eap->cmd,
						    ADDR_TABS, eap->skip,
						    skip_only, FALSE, 1);
				if (tabnr == MAXLNUM)
				    cmdmod.tab = tabpage_index(curtab) + 1;
				else
				{
				    if (tabnr < 0 || tabnr > LAST_TAB_NR)
				    {
					*errormsg = _(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 (!skip_only)
			{
			    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 (!skip_only)
			{
			    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;
}