uc_check_code(
    char_u	*code,
    size_t	len,
    char_u	*buf,
    ucmd_T	*cmd,		/* the user command we're expanding */
    exarg_T	*eap,		/* ex arguments */
    char_u	**split_buf,
    size_t	*split_len)
{
    size_t	result = 0;
    char_u	*p = code + 1;
    size_t	l = len - 2;
    int		quote = 0;
    enum {
	ct_ARGS,
	ct_BANG,
	ct_COUNT,
	ct_LINE1,
	ct_LINE2,
	ct_RANGE,
	ct_MODS,
	ct_REGISTER,
	ct_LT,
	ct_NONE
    } type = ct_NONE;

    if ((vim_strchr((char_u *)"qQfF", *p) != NULL) && p[1] == '-')
    {
	quote = (*p == 'q' || *p == 'Q') ? 1 : 2;
	p += 2;
	l -= 2;
    }

    ++l;
    if (l <= 1)
	type = ct_NONE;
    else if (STRNICMP(p, "args>", l) == 0)
	type = ct_ARGS;
    else if (STRNICMP(p, "bang>", l) == 0)
	type = ct_BANG;
    else if (STRNICMP(p, "count>", l) == 0)
	type = ct_COUNT;
    else if (STRNICMP(p, "line1>", l) == 0)
	type = ct_LINE1;
    else if (STRNICMP(p, "line2>", l) == 0)
	type = ct_LINE2;
    else if (STRNICMP(p, "range>", l) == 0)
	type = ct_RANGE;
    else if (STRNICMP(p, "lt>", l) == 0)
	type = ct_LT;
    else if (STRNICMP(p, "reg>", l) == 0 || STRNICMP(p, "register>", l) == 0)
	type = ct_REGISTER;
    else if (STRNICMP(p, "mods>", l) == 0)
	type = ct_MODS;

    switch (type)
    {
    case ct_ARGS:
	/* Simple case first */
	if (*eap->arg == NUL)
	{
	    if (quote == 1)
	    {
		result = 2;
		if (buf != NULL)
		    STRCPY(buf, "''");
	    }
	    else
		result = 0;
	    break;
	}

	/* When specified there is a single argument don't split it.
	 * Works for ":Cmd %" when % is "a b c". */
	if ((eap->argt & NOSPC) && quote == 2)
	    quote = 1;

	switch (quote)
	{
	case 0: /* No quoting, no splitting */
	    result = STRLEN(eap->arg);
	    if (buf != NULL)
		STRCPY(buf, eap->arg);
	    break;
	case 1: /* Quote, but don't split */
	    result = STRLEN(eap->arg) + 2;
	    for (p = eap->arg; *p; ++p)
	    {
		if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2)
		    /* DBCS can contain \ in a trail byte, skip the
		     * double-byte character. */
		    ++p;
		else
		     if (*p == '\\' || *p == '"')
		    ++result;
	    }

	    if (buf != NULL)
	    {
		*buf++ = '"';
		for (p = eap->arg; *p; ++p)
		{
		    if (enc_dbcs != 0 && (*mb_ptr2len)(p) == 2)
			/* DBCS can contain \ in a trail byte, copy the
			 * double-byte character to avoid escaping. */
			*buf++ = *p++;
		    else
			 if (*p == '\\' || *p == '"')
			*buf++ = '\\';
		    *buf++ = *p;
		}
		*buf = '"';
	    }

	    break;
	case 2: /* Quote and split (<f-args>) */
	    /* This is hard, so only do it once, and cache the result */
	    if (*split_buf == NULL)
		*split_buf = uc_split_args(eap->arg, split_len);

	    result = *split_len;
	    if (buf != NULL && result != 0)
		STRCPY(buf, *split_buf);

	    break;
	}
	break;

    case ct_BANG:
	result = eap->forceit ? 1 : 0;
	if (quote)
	    result += 2;
	if (buf != NULL)
	{
	    if (quote)
		*buf++ = '"';
	    if (eap->forceit)
		*buf++ = '!';
	    if (quote)
		*buf = '"';
	}
	break;

    case ct_LINE1:
    case ct_LINE2:
    case ct_RANGE:
    case ct_COUNT:
    {
	char num_buf[20];
	long num = (type == ct_LINE1) ? eap->line1 :
		   (type == ct_LINE2) ? eap->line2 :
		   (type == ct_RANGE) ? eap->addr_count :
		   (eap->addr_count > 0) ? eap->line2 : cmd->uc_def;
	size_t num_len;

	sprintf(num_buf, "%ld", num);
	num_len = STRLEN(num_buf);
	result = num_len;

	if (quote)
	    result += 2;

	if (buf != NULL)
	{
	    if (quote)
		*buf++ = '"';
	    STRCPY(buf, num_buf);
	    buf += num_len;
	    if (quote)
		*buf = '"';
	}

	break;
    }

    case ct_MODS:
    {
	int multi_mods = 0;
	typedef struct {
	    int *varp;
	    char *name;
	} mod_entry_T;
	static mod_entry_T mod_entries[] = {
#ifdef FEAT_BROWSE_CMD
	    {&cmdmod.browse, "browse"},
#endif
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
	    {&cmdmod.confirm, "confirm"},
#endif
	    {&cmdmod.hide, "hide"},
	    {&cmdmod.keepalt, "keepalt"},
	    {&cmdmod.keepjumps, "keepjumps"},
	    {&cmdmod.keepmarks, "keepmarks"},
	    {&cmdmod.keeppatterns, "keeppatterns"},
	    {&cmdmod.lockmarks, "lockmarks"},
	    {&cmdmod.noswapfile, "noswapfile"},
	    {NULL, NULL}
	};
	int i;

	result = quote ? 2 : 0;
	if (buf != NULL)
	{
	    if (quote)
		*buf++ = '"';
	    *buf = '\0';
	}

	/* :aboveleft and :leftabove */
	if (cmdmod.split & WSP_ABOVE)
	    result += add_cmd_modifier(buf, "aboveleft", &multi_mods);
	/* :belowright and :rightbelow */
	if (cmdmod.split & WSP_BELOW)
	    result += add_cmd_modifier(buf, "belowright", &multi_mods);
	/* :botright */
	if (cmdmod.split & WSP_BOT)
	    result += add_cmd_modifier(buf, "botright", &multi_mods);

	/* the modifiers that are simple flags */
	for (i = 0; mod_entries[i].varp != NULL; ++i)
	    if (*mod_entries[i].varp)
		result += add_cmd_modifier(buf, mod_entries[i].name,
								 &multi_mods);

	/* TODO: How to support :noautocmd? */
#ifdef HAVE_SANDBOX
	/* TODO: How to support :sandbox?*/
#endif
	/* :silent */
	if (msg_silent > 0)
	    result += add_cmd_modifier(buf,
		    emsg_silent > 0 ? "silent!" : "silent", &multi_mods);
	/* :tab */
	if (cmdmod.tab > 0)
	    result += add_cmd_modifier(buf, "tab", &multi_mods);
	/* :topleft */
	if (cmdmod.split & WSP_TOP)
	    result += add_cmd_modifier(buf, "topleft", &multi_mods);
	/* TODO: How to support :unsilent?*/
	/* :verbose */
	if (p_verbose > 0)
	    result += add_cmd_modifier(buf, "verbose", &multi_mods);
	/* :vertical */
	if (cmdmod.split & WSP_VERT)
	    result += add_cmd_modifier(buf, "vertical", &multi_mods);
	if (quote && buf != NULL)
	{
	    buf += result - 2;
	    *buf = '"';
	}
	break;
    }

    case ct_REGISTER:
	result = eap->regname ? 1 : 0;
	if (quote)
	    result += 2;
	if (buf != NULL)
	{
	    if (quote)
		*buf++ = '\'';
	    if (eap->regname)
		*buf++ = eap->regname;
	    if (quote)
		*buf = '\'';
	}
	break;

    case ct_LT:
	result = 1;
	if (buf != NULL)
	    *buf = '<';
	break;

    default:
	/* Not recognized: just copy the '<' and return -1. */
	result = (size_t)-1;
	if (buf != NULL)
	    *buf = '<';
	break;
    }

    return result;
}