📄 eval.c
字号:
/*
* 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 + -