⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eval.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:

    /*
     * Apply logical NOT and unary '-', from right to left.
     */
    if (ret == OK && end_leader > start_leader)
    {
	val = get_var_number(retvar);
	while (end_leader > start_leader)
	{
	    --end_leader;
	    if (*end_leader == '!')
		val = !val;
	    else if (*end_leader == '-')
		val = -val;
	}
	clear_var(retvar);
	retvar->var_type = VAR_NUMBER;
	retvar->var_val.var_number = val;
    }

    return ret;
}

/*
 * Get an option value.
 * "arg" points to the '&' before the option name.
 * "arg" is advanced to character after the option name.
 * Return OK or FAIL.
 */
    static int
get_option_var(arg, retvar)
    char_u	**arg;
    VAR		retvar;		/* when NULL, only check if option exists */
{
    char_u	*option_end;
    long	numval;
    char_u	*stringval;
    int		opt_type;
    int		c;
    int		ret = OK;

    /*
     * Isolate the option name and find its value.
     */
    option_end = find_option_end(*arg + 1);
    if (option_end == *arg + 1)
    {
	if (retvar != NULL)
	    EMSG2("Option name missing: %s", *arg);
	return FAIL;
    }

    c = *option_end;
    *option_end = NUL;
    opt_type = get_option_value(*arg + 1, &numval,
					  retvar == NULL ? NULL : &stringval);

    if (opt_type < 0)		    /* invalid name */
    {
	if (retvar != NULL)
	    EMSG2("Unknown option: %s", *arg + 1);
	ret = FAIL;
    }
    else if (retvar != NULL)
    {
	if (opt_type == 1)		/* number option */
	{
	    retvar->var_type = VAR_NUMBER;
	    retvar->var_val.var_number = numval;
	}
	else				/* string option */
	{
	    retvar->var_type = VAR_STRING;
	    retvar->var_val.var_string = stringval;
	}
    }

    *option_end = c;		    /* put back for error messages */
    *arg = option_end;

    return ret;
}

/*
 * Allocate a variable for an string constant.
 * Return OK or FAIL.
 */
    static int
get_string_var(arg, retvar)
    char_u	**arg;
    VAR		retvar;
{
    char_u	*p;
    char_u	*name;
    int		i;
    int		extra = 0;

    /*
     * Find the end of the string, skipping backslashed characters.
     */
    for (p = *arg + 1; *p && *p != '\"'; ++p)
	if (*p == '\\' && p[1] != NUL)
	{
	    ++p;
	    /* A "\<x>" form occupies at least 4 characters, and produces up
	     * to 6 characters: reserve space for 2 extra */
	    if (*p == '<')
		extra += 2;
	}
    if (*p != '\"')
    {
	EMSG2("Missing quote: %s", *arg);
	return FAIL;
    }

    /*
     * Copy the string into allocated memory, handling backslashed
     * characters.
     */
    name = alloc((unsigned)(p - *arg + extra));
    if (name == NULL)
	return FAIL;

    i = 0;
    for (p = *arg + 1; *p && *p != '\"'; ++p)
    {
	if (*p == '\\')
	{
	    switch (*++p)
	    {
		case 'b': name[i++] = BS; break;
		case 'e': name[i++] = ESC; break;
		case 'f': name[i++] = FF; break;
		case 'n': name[i++] = NL; break;
		case 'r': name[i++] = CR; break;
		case 't': name[i++] = TAB; break;

			  /* hex: "\x1", "\x12" */
		case 'X':
		case 'x': if (isxdigit(p[1]))
			  {
			      ++p;
			      name[i] = hex2nr(*p);
			      if (isxdigit(p[1]))
			      {
				  ++p;
				  name[i] = (name[i] << 4) + hex2nr(*p);
			      }
			      ++i;
			  }
			  else
			      name[i++] = *p;
			  break;

			  /* octal: "\1", "\12", "\123" */
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7': name[i] = *p - '0';
			  if (p[1] >= '0' && p[1] <= '7')
			  {
			      ++p;
			      name[i] = (name[i] << 3) + *p - '0';
			      if (p[1] >= '0' && p[1] <= '7')
			      {
				  ++p;
				  name[i] = (name[i] << 3) + *p - '0';
			      }
			  }
			  ++i;
			  break;

			    /* Special key, e.g.: "\<C-W>" */
		case '<': extra = trans_special(&p, name + i, FALSE);
			  if (extra)
			  {
			      i += extra;
			      --p;
			      break;
			  }
			  /* FALLTHROUGH */

		default:  name[i++] = *p;
			  break;
	    }
	}
	else
	    name[i++] = *p;
    }
    name[i] = NUL;
    *arg = p + 1;

    retvar->var_type = VAR_STRING;
    retvar->var_val.var_string = name;

    return OK;
}

/*
 * Allocate a variable for an backtick-string constant.
 * Return OK or FAIL.
 */
    static int
get_lit_string_var(arg, retvar)
    char_u	**arg;
    VAR		retvar;
{
    char_u	*p;
    char_u	*name;

    /*
     * Find the end of the string.
     */
    p = vim_strchr(*arg + 1, '\'');
    if (p == NULL)
    {
	EMSG2("Missing quote: %s", *arg);
	return FAIL;
    }

    /*
     * Copy the string into allocated memory.
     */
    name = vim_strnsave(*arg + 1, (int)(p - (*arg + 1)));
    if (name == NULL)
	return FAIL;

    *arg = p + 1;

    retvar->var_type = VAR_STRING;
    retvar->var_val.var_string = name;

    return OK;
}

/*
 * Get the value of an environment variable.
 * Return OK or FAIL.
 */
    static int
get_env_var(arg, retvar)
    char_u	**arg;
    VAR		retvar;
{
    char_u	*string;

    string = get_env_string(arg);

    /*
     * Allocate a variable.  If the environment variable was not set, silently
     * assume it is empty.
     */
    if (string != NULL)
	string = vim_strsave(string);
    retvar->var_type = VAR_STRING;
    retvar->var_val.var_string = string;

    return OK;
}

/*
 * Allocate a variable for the result of a function.
 * Return OK or FAIL.
 */
    static int
get_func_var(name, len, retvar, arg, firstline, lastline, doesrange)
    char_u	*name;		/* name of the function */
    int		len;		/* length of "name" */
    VAR		retvar;
    char_u	**arg;		/* argument, pointing to the '(' */
    linenr_t	firstline;	/* first line of range */
    linenr_t	lastline;	/* last line of range */
    int		*doesrange;	/* return: function handled range */
{
    char_u	*argp;
    int		ret = FAIL;
#define MAX_FUNC_ARGS	20
    var		argvars[MAX_FUNC_ARGS];	/* vars for arguments */
    int		argcount = 0;		/* number of arguments found */
    static char *errors[] =
		{"Invalid arguments for function %s",
		 "Unknown function: %s",
		 "Too many arguments for function: %s",
		 "Not enough arguments for function: %s",
		};
#define ERROR_INVARG	0
#define ERROR_UNKOWN	1
#define ERROR_TOOMANY	2
#define ERROR_TOOFEW	3
#define ERROR_NONE	4
#define ERROR_OTHER	5
    int		error = ERROR_NONE;
    int		i;
    struct ufunc *fp;
    int		cc;
    static struct fst
    {
	char	*f_name;	/* function name */
	char	f_min_argc;	/* minimal number of arguments */
	char	f_max_argc;	/* miximal number of arguments */
	void	(*f_func) __ARGS((VAR args, VAR rvar));    /* impl. function */
    } functions[] =
    {
	{"argc",		0, 0, f_argc},
	{"argv",		1, 1, f_argv},
	{"browse",		4, 4, f_browse},
	{"buffer_exists",	1, 1, f_bufexists},	/* obsolete */
	{"bufexists",		1, 1, f_bufexists},
	{"buffer_name",		1, 1, f_bufname},	/* obsolete */
	{"buffer_number",	1, 1, f_bufnr},		/* obsolete */
	{"bufname",		1, 1, f_bufname},
	{"bufnr",		1, 1, f_bufnr},
	{"char2nr",		1, 1, f_char2nr},
	{"col",			1, 1, f_col},
	{"confirm",		2, 4, f_confirm},
	{"delete",		1, 1, f_delete},
	{"escape",		2, 2, f_escape},
	{"exists",		1, 1, f_exists},
	{"expand",		1, 1, f_expand},
	{"file_readable",	1, 1, f_filereadable},	/* obsolete */
	{"filereadable",	1, 1, f_filereadable},
	{"fnamemodify",		2, 2, f_fnamemodify},
	{"getcwd",		0, 0, f_getcwd},
	{"getline",		1, 1, f_getline},
	{"has",			1, 1, f_has},
	{"highlight_exists",	1, 1, f_hlexists},	/* obsolete */
	{"highlightID",		1, 1, f_hlID},		/* obsolete */
	{"hlexists",		1, 1, f_hlexists},
	{"hlID",		1, 1, f_hlID},
	{"hostname",		0, 0, f_hostname},
	{"input",		1, 1, f_input },
	{"isdirectory",		1, 1, f_isdirectory},
	{"last_buffer_nr",	0, 0, f_last_buffer_nr},/* obsolete */
	{"line",		1, 1, f_line},
	{"match",		2, 2, f_match},
	{"matchend",		2, 2, f_matchend},
	{"matchstr",		2, 2, f_matchstr},
	{"nr2char",		1, 1, f_nr2char},
	{"setline",		2, 2, f_setline},
#ifdef HAVE_STRFTIME
	{"strftime",		1, 1, f_strftime},
#endif
	{"strlen",		1, 1, f_strlen},
	{"strpart",		3, 3, f_strpart},
	{"synID",		3, 3, f_synID},
	{"synIDattr",		2, 3, f_synIDattr},
	{"synIDtrans",		1, 1, f_synIDtrans},
	{"substitute",		4, 4, f_substitute},
	{"tempname",		0, 0, f_tempname},
	{"virtcol",		1, 1, f_virtcol},
	{"winbufnr",		1, 1, f_winbufnr},
	{"winheight",		1, 1, f_winheight},
	{"winnr",		0, 0, f_winnr},
    };

    cc = name[len];
    name[len] = NUL;
    *doesrange = FALSE;

    /*
     * Get the arguments.
     */
    argp = *arg;
    while (argcount < MAX_FUNC_ARGS)
    {
	argp = skipwhite(argp + 1);	    /* skip the '(' or ',' */
	if (*argp == ')' || *argp == ',' || *argp == NUL)
	    break;
	if (eval1(&argp, &argvars[argcount]) == FAIL)
	{
	    error = ERROR_OTHER;
	    break;
	}
	++argcount;
	if (*argp != ',')
	    break;
    }
    if (*argp != ')' && error == ERROR_NONE)
	error = ERROR_INVARG;

    /* execute the function if no errors detected and executing */
    if (error == ERROR_NONE && !emsg_off)
    {
	retvar->var_type = VAR_NUMBER;	/* default is number retvar */

	error = ERROR_UNKOWN;
	if (!islower(name[0]))
	{
	    /*
	     * User defined function.
	     */
	    fp = find_func(name);
	    if (fp != NULL)
	    {
		if (fp->flags & FC_RANGE)
		    *doesrange = TRUE;
		if (argcount < fp->args.ga_len)
		    error = ERROR_TOOFEW;
		else if (!fp->varargs && argcount > fp->args.ga_len)
		    error = ERROR_TOOMANY;
		else
		{
		    /*
		     * Call the user function.
		     * Save and restore search patterns and redo buffer.
		     */
		    save_search_patterns();
		    saveRedobuff();
		    call_func(fp, argcount, argvars, retvar,
							 firstline, lastline);
		    restoreRedobuff();
		    restore_search_patterns();
		    error = ERROR_NONE;
		}
	    }
	}
	else
	{
	    /*
	     * Find the function name in the table, call its implementation.
	     */
	    for (i = 0; i < (int)(sizeof(functions) / sizeof(struct fst)); ++i)
		if (STRCMP(name, functions[i].f_name) == 0)
		{
		    if (argcount < functions[i].f_min_argc)
			error = ERROR_TOOFEW;
		    else if (argcount > functions[i].f_max_argc)
			error = ERROR_TOOMANY;
		    else
		    {
			argvars[argcount].var_type = VAR_UNKNOWN;
			functions[i].f_func(argvars, retvar);
			error = ERROR_NONE;
		    }
		    break;
		}
	}

	*arg = skipwhite(argp + 1);
	if (error == ERROR_NONE)
	    ret = OK;
    }

    while (--argcount >= 0)
	clear_var(&argvars[argcount]);

    if (error < ERROR_NONE)
	EMSG2((char_u *)errors[error], name);

    name[len] = cc;

    return ret;
}

/*
 * "argc()" function.
 */
/* ARGSUSED */
    static void
f_argc(argvars, retvar)
    VAR		argvars;
    VAR		retvar;
{
    retvar->var_val.var_number = arg_file_count;
}

/*
 * "argv()" function.
 */
    static void
f_argv(argvars, retvar)
    VAR		argvars;
    VAR		retvar;
{
    int		idx;

    idx = get_var_number(&argvars[0]);
    if (idx >= 0 && idx < arg_file_count)
	retvar->var_val.var_string = vim_strsave(arg_files[idx]);
    else
	retvar->var_val.var_string = NULL;
    retvar->var_type = VAR_STRING;
}

    static BUF *
get_buf_var(avar)
    VAR		avar;
{
    char_u	*name = avar->var_val.var_string;

    if (avar->var_type == VAR_NUMBER)
	return buflist_findnr((int)avar->var_val.var_number);
    else if (name == NULL || *name == NUL)
	return curbuf;
    else if (name[0] == '$' && name[1] == NUL)
	return lastbuf;
    else
	return buflist_findnr(buflist_findpat(name, name + STRLEN(name)));
}

/*
 * "buffer_name()" function.
 */
    static void
f_bufname(argvars, retvar)
    VAR		argvars;
    VAR		retvar;
{
    BUF		*buf;

    ++emsg_off;
    buf = get_buf_var(&argvars[0]);
    retvar->var_type = VAR_STRING;
    if (buf != NULL && buf->b_fname != NULL)
	retvar->var_val.var_string = vim_strsave(buf->b_fname);
    else
	retvar->var_val.var_string = NULL;
    --emsg_off;
}

/*
 * "buffer_number()" function.
 */
    static void
f_bufnr(argvars, retvar)
    VAR		argvars;
    VAR		retvar;
{
    BUF		*buf;

    ++emsg_off;
    buf = get_buf_var(&argvars[0]);
    if (buf != NULL)
	retvar->var_val.var_number = buf->b_fnum;
    else
	retvar->var_val.var_number = -1;
    --emsg_off;
}

/*
 * "buffer_exists()" function.
 */
    static void
f_bufexists(argvars, retvar)
    VAR		argvars;
    VAR		retvar;
{
    int		n = FALSE;
    char_u	*name;

    if (argvars[0].var_type == VAR_NUMBER)
	n = (buflist_findnr((int)argvars[0].var_val.var_number) != NULL);
    else if (argvars[0].var_val.var_string != NULL)
    {
	/* First make the name into a full path name */
	name = FullName_save(argvars[0].var_val.var_string,
#ifdef UNIX
		TRUE	    /* force expansion, get rid of symbolic links */
#else
		FALSE
#endif
		);
	if (name != NULL)
	{
	    n = (buflist_findname(name) != NULL);
	    vim_free(name);
	}
    }

    retvar->var_val.var_number = n;
}

/*
 * "char2nr()" function
 */
    static void
f_char2nr(argvars, retvar)
    VAR		argvars;
    VAR		retvar;
{
    retvar->var_val.var_number = get_var_string(&argvars[0])[0];
}

/*
 * "col(string)" function
 */
    static void
f_col(argvars, retvar)
    VAR		argvars;
    VAR		retvar;
{
    colnr_t	col = 0;
    FPOS	*fp;

    fp = var2fpos(&argvars[0]);
    if (fp != NULL && fp->lnum > 0)
	col = fp->col + 1;

    retvar->var_val.var_number = col;
}

/*
 * "confirm(message, buttons[, default [, type]])" function
 */
    static void
f_confirm(argvars, retvar)
    VAR		argvars;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -