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

📄 eval.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
/* vi:set ts=8 sts=4 sw=4:
 *
 * VIM - Vi IMproved	by Bram Moolenaar
 *
 * Do ":help uganda"  in Vim to read copying and usage conditions.
 * Do ":help credits" in Vim to see a list of people who contributed.
 */

/*
 * eval.c: Expression evaluation.
 */

#include "vim.h"

#ifdef HAVE_FCNTL_H
# include <fcntl.h>	/* contains setenv() declaration for Amiga */
#endif
#ifdef AMIGA
# include <time.h>	/* for strftime() */
#endif

#ifdef WANT_EVAL

/*
 * Structure to hold an internal variable.
 */
typedef struct
{
    char_u	*var_name;	/* name of variable */
    char	var_type;	/* VAR_NUMBER or VAR_STRING */
    union
    {
#if SIZEOF_INT <= 3		/* use long if int is smaller than 32 bits */
	long	var_number;	/* number value */
#else
	int	var_number;	/* number value */
#endif
	char_u	*var_string;	/* string value (Careful: can be NULL!) */
    }		var_val;
} var;

#define VAR_UNKNOWN 0
#define VAR_NUMBER  1
#define VAR_STRING  2

typedef var *	VAR;

/*
 * All user-defined internal variables are stored in "variables".
 */
struct growarray    variables = {0, 0, sizeof(var), 4, NULL};

#define VAR_ENTRY(idx)	(((VAR)(variables.ga_data))[idx])
#define VAR_GAP_ENTRY(idx, gap)	(((VAR)(gap->ga_data))[idx])
#define BVAR_ENTRY(idx)	(((VAR)(curbuf->b_vars.ga_data))[idx])
#define WVAR_ENTRY(idx)	(((VAR)(curwin->w_vars.ga_data))[idx])

static int echo_attr = 0;   /* attributes used for ":echo" */

/*
 * Structure to hold info for a user function.
 */
struct ufunc
{
    struct ufunc	*next;		/* next function in list */
    char_u		*name;		/* name of function */
    int			varargs;	/* variable nr of arguments */
    int			flags;
    struct growarray	args;		/* arguments */
    struct growarray	lines;		/* function lines */
};

/* function flags */
#define FC_ABORT    1		/* abort function on error */
#define FC_RANGE    2		/* function accepts range */

/*
 * All user-defined functions are found in the forward-linked function list.
 * The first function is pointed at by firstfunc.
 */
struct ufunc	    *firstfunc = NULL;

#define FUNCARG(fp, j)	((char_u **)(fp->args.ga_data))[j]
#define FUNCLINE(fp, j)	((char_u **)(fp->lines.ga_data))[j]

/* structure to hold info for a function that is currently being executed. */
struct funccall
{
    struct ufunc *func;		/* function being called */
    int		linenr;		/* next line to be executed */
    int		argcount;	/* nr of arguments */
    VAR		argvars;	/* arguments */
    var		a0_var;		/* "a:0" variable */
    var		firstline;	/* "a:firstline" variable */
    var		lastline;	/* "a:lastline" variable */
    struct growarray l_vars;	/* local function variables */
    VAR		retvar;		/* return value variable */
};

/* pointer to funccal for currently active function */
struct funccall *current_funccal = NULL;

static char_u *cat_prefix_varname __ARGS((int prefix, char_u *name));
static int eval0 __ARGS((char_u *arg,  VAR retvar, char_u **nextcmd));
static int eval1 __ARGS((char_u **arg, VAR retvar));
static int eval2 __ARGS((char_u **arg, VAR retvar));
static int eval3 __ARGS((char_u **arg, VAR retvar));
static int eval4 __ARGS((char_u **arg, VAR retvar));
static int eval5 __ARGS((char_u **arg, VAR retvar));
static int eval6 __ARGS((char_u **arg, VAR retvar));
static int get_option_var __ARGS((char_u **arg, VAR retvar));
static int get_string_var __ARGS((char_u **arg, VAR retvar));
static int get_lit_string_var __ARGS((char_u **arg, VAR retvar));
static int get_env_var __ARGS((char_u **arg, VAR retvar));
static int get_func_var __ARGS((char_u *name, int len, VAR retvar, char_u **arg, linenr_t firstline, linenr_t lastline, int *doesrange));
static void f_argc __ARGS((VAR argvars, VAR retvar));
static void f_argv __ARGS((VAR argvars, VAR retvar));
static void f_browse __ARGS((VAR argvars, VAR retvar));
static void f_bufexists __ARGS((VAR argvars, VAR retvar));
static BUF *get_buf_var __ARGS((VAR avar));
static void f_bufname __ARGS((VAR argvars, VAR retvar));
static void f_bufnr __ARGS((VAR argvars, VAR retvar));
static void f_char2nr __ARGS((VAR argvars, VAR retvar));
static void f_col __ARGS((VAR argvars, VAR retvar));
static void f_confirm __ARGS((VAR argvars, VAR retvar));
static void f_delete __ARGS((VAR argvars, VAR retvar));
static void f_escape __ARGS((VAR argvars, VAR retvar));
static void f_exists __ARGS((VAR argvars, VAR retvar));
static void f_expand __ARGS((VAR argvars, VAR retvar));
static void f_filereadable __ARGS((VAR argvars, VAR retvar));
static void f_fnamemodify __ARGS((VAR argvars, VAR retvar));
static void f_getcwd __ARGS((VAR argvars, VAR retvar));
static void f_getline __ARGS((VAR argvars, VAR retvar));
static void f_has __ARGS((VAR argvars, VAR retvar));
static void f_hlexists __ARGS((VAR argvars, VAR retvar));
static void f_hlID __ARGS((VAR argvars, VAR retvar));
static void f_hostname __ARGS((VAR argvars, VAR retvar));
static void f_isdirectory __ARGS((VAR argvars, VAR retvar));
static void f_input __ARGS((VAR argvars, VAR retvar));
static void f_last_buffer_nr __ARGS((VAR argvars, VAR retvar));
static void f_line __ARGS((VAR argvars, VAR retvar));
static void f_match __ARGS((VAR argvars, VAR retvar));
static void f_matchend __ARGS((VAR argvars, VAR retvar));
static void f_matchstr __ARGS((VAR argvars, VAR retvar));
static void f_nr2char __ARGS((VAR argvars, VAR retvar));
static void f_setline __ARGS((VAR argvars, VAR retvar));
static void f_some_match __ARGS((VAR argvars, VAR retvar, int start));
static void f_strftime __ARGS((VAR argvars, VAR retvar));
static void f_strlen __ARGS((VAR argvars, VAR retvar));
static void f_strpart __ARGS((VAR argvars, VAR retvar));
static void f_synID __ARGS((VAR argvars, VAR retvar));
static void f_synIDattr __ARGS((VAR argvars, VAR retvar));
static void f_synIDtrans __ARGS((VAR argvars, VAR retvar));
static void f_substitute __ARGS((VAR argvars, VAR retvar));
static void f_tempname __ARGS((VAR argvars, VAR retvar));
static void f_virtcol __ARGS((VAR argvars, VAR retvar));
static void f_winbufnr __ARGS((VAR argvars, VAR retvar));
static void f_winheight __ARGS((VAR argvars, VAR retvar));
static void f_winnr __ARGS((VAR argvars, VAR retvar));
static WIN *find_win_by_nr __ARGS((VAR vp));
static FPOS *var2fpos __ARGS((VAR varp));
static int get_env_len __ARGS((char_u **arg));
char_u *get_env_string __ARGS((char_u **arg));
static int get_id_len __ARGS((char_u **arg));
static int eval_isnamec __ARGS((int c));
static int get_var_var __ARGS((char_u *name, int len, VAR retvar));
static VAR alloc_var __ARGS((void));
static VAR alloc_string_var __ARGS((char_u *string));
static void free_var __ARGS((VAR varp));
static void clear_var __ARGS((VAR varp));
static long get_var_number __ARGS((VAR varp));
static char_u *get_var_string __ARGS((VAR varp));
static char_u *get_var_string_buf __ARGS((VAR varp, char_u *buf));
static VAR find_var __ARGS((char_u *name, int writing));
static struct growarray *find_var_ga __ARGS((char_u *name, char_u **varname));
static void var_free_one __ARGS((VAR v));
static void list_one_var __ARGS((VAR v, char_u *prefix));
static void set_var __ARGS((char_u *name, VAR varp));
static char_u *find_option_end __ARGS((char_u *p));
static void list_func_head __ARGS((struct ufunc *fp));
static struct ufunc *find_func __ARGS((char_u *name));
static void call_func __ARGS((struct ufunc *fp, int argcount, VAR argvars, VAR retvar, linenr_t firstline, linenr_t lastline));

/*
 * Set an internal variable to a string value. Creates the variable if it does
 * not already exist.
 */
    void
set_internal_string_var(name, value)
    char_u	*name;
    char_u	*value;
{
    char_u  *val;
    VAR	    varp;

    val = vim_strsave(value);
    if (val != NULL)
    {
	varp = alloc_string_var(val);
	if (varp != NULL)
	{
	    set_var(name, varp);
	    free_var(varp);
	}
    }
}

/*
 * Top level evaluation function, returning a boolean.
 * Sets "error" to TRUE if there was an error.
 * Return TRUE or FALSE.
 */
    int
eval_to_bool(arg, error, nextcmd)
    char_u	*arg;
    int		*error;
    char_u	**nextcmd;
{
    var		retvar;
    int		retval;

    if (eval0(arg, &retvar, nextcmd) == FAIL)
    {
	*error = TRUE;
	retval = FALSE;
    }
    else
    {
	*error = FALSE;
	retval = (get_var_number(&retvar) != 0);
	clear_var(&retvar);
    }

    return retval;
}

/*
 * Top level evaluation function, returning a string.
 * Return pointer to allocated memory, or NULL for failure.
 */
    char_u *
eval_to_string(arg, nextcmd)
    char_u	*arg;
    char_u	**nextcmd;
{
    var		retvar;
    char_u	*retval;

    if (eval0(arg, &retvar, nextcmd) == FAIL)
	retval = NULL;
    else
    {
	retval = vim_strsave(get_var_string(&retvar));
	clear_var(&retvar);
    }

    return retval;
}

/*
 * ":let var = expr"	assignment command.
 * ":let var"		list one variable value
 * ":let"		list all variable values
 */
    void
do_let(eap)
    EXARG	*eap;
{
    char_u	*arg = eap->arg;
    char_u	*expr;
    char_u	*name;
    VAR		varp;
    var		retvar;
    char_u	*p;
    int		c1, c2;
    int		i;
#ifndef HAVE_SETENV
    char_u	*envbuf;
#endif

    expr = vim_strchr(arg, '=');
    if (expr == NULL)
    {
	if (ends_excmd(*arg))
	{
	    if (!eap->skip)
	    {
		/*
		 * List all variables.
		 */
		for (i = 0; i < variables.ga_len; ++i)
		    if (VAR_ENTRY(i).var_name != NULL)
			list_one_var(&VAR_ENTRY(i), (char_u *)"");
		for (i = 0; i < curbuf->b_vars.ga_len; ++i)
		    if (BVAR_ENTRY(i).var_name != NULL)
			list_one_var(&BVAR_ENTRY(i), (char_u *)"b:");
		for (i = 0; i < curwin->w_vars.ga_len; ++i)
		    if (WVAR_ENTRY(i).var_name != NULL)
			list_one_var(&WVAR_ENTRY(i), (char_u *)"w:");
	    }
	}
	else
	{
	    /*
	     * List variables.
	     */
	    while (!ends_excmd(*arg))
	    {
		for (p = arg; eval_isnamec(*p); ++p)
		    ;
		if (!vim_iswhite(*p) && !ends_excmd(*p))
		{
		    EMSG(e_trailing);
		    break;
		}
		if (!eap->skip)
		{
		    c1 = *p;
		    *p = NUL;
		    varp = find_var(arg, FALSE);
		    if (varp == NULL)
			EMSG2("Unknown variable: \"%s\"", arg);
		    else
		    {
			name = vim_strchr(arg, ':');
			if (name != NULL)
			{
			    c2 = *++name;
			    *name = NUL;
			    list_one_var(varp, arg);
			    *name = c2;
			}
			else
			    list_one_var(varp, (char_u *)"");
		    }
		    *p = c1;
		}
		arg = skipwhite(p);
	    }
	}
	eap->nextcmd = check_nextcmd(arg);
    }
    else
    {
	if (eap->skip)
	    ++emsg_off;
	i = eval0(expr + 1, &retvar, &eap->nextcmd);
	if (eap->skip)
	{
	    if (i != FAIL)
		clear_var(&retvar);
	    --emsg_off;
	}
	else if (i != FAIL)
	{
	    /*
	     * ":let $VAR = expr": Set environment variable.
	     */
	    if (*arg == '$')
	    {
		int	len;
		int	cc;

		/* Find the end of the name. */
		++arg;
		name = arg;
		len = get_env_len(&arg);
		if (name != NULL)
		{
		    if (*skipwhite(arg) != '=')
			EMSG(e_letunexp);
		    else
		    {
			cc = name[len];
			name[len] = NUL;
			p = get_var_string(&retvar);
#ifdef HAVE_SETENV
			mch_setenv((char *)name, (char *)p, 1);
#else
			/*
			 * Putenv does not copy the string, it has to remain
			 * valid.  The allocated memory will never be freed.
			 */
			envbuf = alloc((unsigned)(STRLEN(p) +
							   STRLEN(name) + 2));
			if (envbuf != NULL)
			{
			    sprintf((char *)envbuf, "%s=%s", name, p);
			    putenv((char *)envbuf);
			}
#endif
			if (STRICMP(name, "home") == 0)
			    init_homedir();
			name[len] = cc;
		    }
		}
	    }

	    /*
	     * ":let &option = expr": Set option value.
	     */
	    else if (*arg == '&')
	    {
		/*
		 * Find the end of the name;
		 */
		++arg;
		p = find_option_end(arg);
		if (*skipwhite(p) != '=')
		    EMSG(e_letunexp);
		else
		{
		    c1 = *p;
		    *p = NUL;
		    set_option_value(arg, get_var_number(&retvar),
						     get_var_string(&retvar));
		    *p = c1;		    /* put back for error messages */
		}
	    }

	    /*
	     * ":let @r = expr": Set register contents.
	     */
	    else if (*arg == '@')
	    {
		++arg;
		if (*skipwhite(arg + 1) != '=')
		    EMSG(e_letunexp);
		else
		    write_reg_contents(*arg == '@' ? '"' : *arg,
						     get_var_string(&retvar));
	    }

	    /*
	     * ":let var = expr": Set internal variable.
	     */
	    else if (eval_isnamec(*arg) && !isdigit(*arg))
	    {
		/*
		 * Find the end of the name;
		 */
		for (p = arg; eval_isnamec(*p); ++p)
		    ;
		if (*skipwhite(p) != '=')
		    EMSG(e_letunexp);
		else
		{
		    c1 = *p;
		    *p = NUL;
		    set_var(arg, &retvar);
		    *p = c1;		/* put char back for error messages */
		}
	    }

	    else
	    {
		EMSG2(e_invarg2, arg);
	    }

	    clear_var(&retvar);
	}
    }
}

/*
 * ":1,25call func(arg1, arg2)"	function call.
 */
    void
do_call(eap)
    EXARG	*eap;
{
    char_u	*arg = eap->arg;
    char_u	*startarg;
    char_u	*name;
    var		retvar;
    int		len;
    linenr_t	lnum;
    int		doesrange;

    name = arg;
    len = get_id_len(&arg);
    startarg = arg;

    if (*startarg != '(')
    {
	EMSG2("Missing braces: %s", name);
	return;
    }

    /*
     * When skipping, evaluate the function once, to find the end of the
     * arguments.
     * When the function takes a range, this is discovered after the first
     * call, and the loop is broken.
     */
    if (eap->skip)
	++emsg_off;
    for (lnum = eap->line1; lnum <= eap->line2; ++lnum)
    {
	if (!eap->skip && eap->line1 != eap->line2)
	{
	    curwin->w_cursor.lnum = lnum;
	    curwin->w_cursor.col = 0;
	}
	arg = startarg;
	if (get_func_var(name, len, &retvar, &arg,
				  eap->line1, eap->line2, &doesrange) == FAIL)
	    break;
	clear_var(&retvar);
	if (doesrange || eap->skip)
	    break;
    }
    if (eap->skip)
	--emsg_off;
    eap->nextcmd = check_nextcmd(arg);
}

/*
 * ":unlet[!] var1 ... " command.
 */
    void
do_unlet(arg, forceit)
    char_u	*arg;
    int		forceit;
{
    char_u	*name_end;
    VAR		v;
    char_u	cc;

    do
    {
	name_end = skiptowhite(arg);
	cc = *name_end;
	*name_end = NUL;

	v = find_var(arg, TRUE);
	if (v != NULL)	    /* existing variable, may need to free string */
	    var_free_one(v);
	else if (!forceit)  /* non-existing variable */
	{
	    *name_end = cc;
	    EMSG2("No such variable: \"%s\"", arg);
	    break;
	}

	*name_end = cc;
	arg = skipwhite(name_end);
    } while (*arg != NUL);
}

/*
 * Local string buffer for the next two functions to store a variable name
 * with its prefix. Allocated in cat_prefix_varname(), freed later in
 * get_user_var_name().
 */

static char_u	*varnamebuf = NULL;
static int	varnamebuflen = 0;

/*
 * Function to concatenate a prefix and a variable name.
 * TODO: Use string instead of char for 'prefix' when allowing 'b3:' like vars.
 */
    static char_u *
cat_prefix_varname(prefix, name)
    int		prefix;
    char_u	*name;
{
    int		len;

    len = STRLEN( name ) + 3;
    if ( len > varnamebuflen )
    {
	vim_free(varnamebuf);
	len += 10;			/* some additional space */
	varnamebuf = alloc(len);
	if (varnamebuf)
	    varnamebuflen = len;
	else
	{
	    varnamebuflen = 0;
	    return NULL;
	}
    }
    *varnamebuf = prefix;
    varnamebuf[1] = ':';
    STRCPY(varnamebuf+2, name);
    return varnamebuf;
}

/*
 * Function given to ExpandGeneric() to obtain the list of user defined
 * (global/buffer/window) variable names.
 */
    char_u *
get_user_var_name(idx)
    int	    idx;
{
    if (idx < variables.ga_len)				/* Global variables */
	return VAR_ENTRY(idx).var_name;
						/* Current buffer variables */
    else if ((idx -= variables.ga_len) < curbuf->b_vars.ga_len)
	return cat_prefix_varname('b', BVAR_ENTRY(idx).var_name);
						/* Current window variables */
    else if ((idx -= curbuf->b_vars.ga_len) < curwin->w_vars.ga_len)
	return cat_prefix_varname('w', WVAR_ENTRY(idx).var_name);
    else
    {
	vim_free(varnamebuf);
	varnamebuf = NULL;
	varnamebuflen = 0;

⌨️ 快捷键说明

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