Mercurial > vim
diff src/eval.c @ 169:0e902b8f511f v7.0051
updated for version 7.0051
author | vimboss |
---|---|
date | Tue, 22 Feb 2005 08:56:13 +0000 |
parents | e943e5502fc9 |
children | 8c60f65311fa |
line wrap: on
line diff
--- a/src/eval.c +++ b/src/eval.c @@ -148,17 +148,17 @@ typedef struct ufunc ufunc_T; struct ufunc { - ufunc_T *next; /* next function in list */ - char_u *name; /* name of function; can start with <SNR>123_ - (<SNR> is K_SPECIAL KS_EXTRA KE_SNR) */ - int varargs; /* variable nr of arguments */ - int flags; - int calls; /* nr of active calls */ - garray_T args; /* arguments */ - garray_T lines; /* function lines */ - scid_T script_ID; /* ID of script where function was defined, + int uf_varargs; /* variable nr of arguments */ + int uf_flags; + int uf_calls; /* nr of active calls */ + garray_T uf_args; /* arguments */ + garray_T uf_lines; /* function lines */ + scid_T uf_script_ID; /* ID of script where function was defined, used for s: variables */ - int refcount; /* for numbered function: reference count */ + int uf_refcount; /* for numbered function: reference count */ + char_u uf_name[1]; /* name of function (actually longer); can + start with <SNR>123_ (<SNR> is K_SPECIAL + KS_EXTRA KE_SNR) */ }; /* function flags */ @@ -167,13 +167,18 @@ struct ufunc #define FC_DICT 4 /* Dict function, uses "self" */ /* - * All user-defined functions are found in the forward-linked function list. - * The first function is pointed at by firstfunc. - */ -ufunc_T *firstfunc = NULL; - -#define FUNCARG(fp, j) ((char_u **)(fp->args.ga_data))[j] -#define FUNCLINE(fp, j) ((char_u **)(fp->lines.ga_data))[j] + * All user-defined functions are found in this hash table. + */ +hashtab_T func_hashtab; + +/* From user function to hashitem and back. */ +static ufunc_T dumuf; +#define UF2HIKEY(fp) ((fp)->uf_name) +#define HIKEY2UF(p) ((ufunc_T *)(p - (dumuf.uf_name - (char_u *)&dumuf))) +#define HI2UF(hi) HIKEY2UF((hi)->hi_key) + +#define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j] +#define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j] #define MAX_FUNC_ARGS 20 /* maximum number of function arguments */ #define VAR_SHORT_LEN 20 /* short variable name length */ @@ -475,6 +480,9 @@ static void f_matchlist __ARGS((typval_T static void f_matchstr __ARGS((typval_T *argvars, typval_T *rettv)); static void f_max __ARGS((typval_T *argvars, typval_T *rettv)); static void f_min __ARGS((typval_T *argvars, typval_T *rettv)); +#ifdef vim_mkdir +static void f_mkdir __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_mode __ARGS((typval_T *argvars, typval_T *rettv)); static void f_nextnonblank __ARGS((typval_T *argvars, typval_T *rettv)); static void f_nr2char __ARGS((typval_T *argvars, typval_T *rettv)); @@ -554,7 +562,7 @@ static linenr_T get_tv_lnum __ARGS((typv static char_u *get_tv_string __ARGS((typval_T *varp)); static char_u *get_tv_string_buf __ARGS((typval_T *varp, char_u *buf)); static dictitem_T *find_var __ARGS((char_u *name, hashtab_T **htp)); -static dictitem_T *find_var_in_ht __ARGS((hashtab_T *ht, char_u *varname)); +static dictitem_T *find_var_in_ht __ARGS((hashtab_T *ht, char_u *varname, int writing)); static hashtab_T *find_var_ht __ARGS((char_u *name, char_u **varname)); static void vars_clear_ext __ARGS((hashtab_T *ht, int free_val)); static void delete_var __ARGS((hashtab_T *ht, hashitem_T *hi)); @@ -574,7 +582,8 @@ static void cat_func_name __ARGS((char_u static ufunc_T *find_func __ARGS((char_u *name)); static int function_exists __ARGS((char_u *name)); static int builtin_function __ARGS((char_u *name)); -static int func_autoload __ARGS((char_u *name)); +static int script_autoload __ARGS((char_u *name)); +static char_u *autoload_name __ARGS((char_u *name)); static void func_free __ARGS((ufunc_T *fp)); static void func_unref __ARGS((char_u *name)); static void func_ref __ARGS((char_u *name)); @@ -605,6 +614,7 @@ static void ex_unletlock __ARGS((exarg_T static int do_unlet_var __ARGS((lval_T *lp, char_u *name_end, int forceit)); static int do_lock_var __ARGS((lval_T *lp, char_u *name_end, int deep, int lock)); static void item_lock __ARGS((typval_T *tv, int deep, int lock)); +static int tv_islocked __ARGS((typval_T *tv)); /* * Initialize the global and v: variables. @@ -618,6 +628,7 @@ eval_init() init_var_dict(&globvardict, &globvars_var); init_var_dict(&vimvardict, &vimvars_var); hash_init(&compat_hashtab); + hash_init(&func_hashtab); for (i = 0; i < VV_LEN; ++i) { @@ -646,7 +657,7 @@ eval_init() func_name(cookie) void *cookie; { - return ((funccall_T *)cookie)->func->name; + return ((funccall_T *)cookie)->func->uf_name; } /* @@ -716,6 +727,136 @@ set_internal_string_var(name, value) } } +static lval_T *redir_lval = NULL; +static char_u *redir_endp = NULL; +static char_u *redir_varname = NULL; + +/* + * Start recording command output to a variable + * Returns OK if successfully completed the setup. FAIL otherwise. + */ + int +var_redir_start(name, append) + char_u *name; + int append; /* append to an existing variable */ +{ + int save_emsg; + int err; + typval_T tv; + + /* Make sure a valid variable name is specified */ + if (!eval_isnamec(*name) || VIM_ISDIGIT(*name)) + { + EMSG(_(e_invarg)); + return FAIL; + } + + redir_varname = vim_strsave(name); + if (redir_varname == NULL) + return FAIL; + + redir_lval = (lval_T *)alloc_clear((unsigned)sizeof(lval_T)); + if (redir_lval == NULL) + { + var_redir_stop(); + return FAIL; + } + + /* Parse the variable name (can be a dict or list entry). */ + redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, FALSE); + if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != NUL) + { + if (redir_endp != NULL && *redir_endp != NUL) + /* Trailing characters are present after the variable name */ + EMSG(_(e_trailing)); + else + EMSG(_(e_invarg)); + var_redir_stop(); + return FAIL; + } + + /* check if we can write to the variable: set it to or append an empty + * string */ + save_emsg = did_emsg; + did_emsg = FALSE; + tv.v_type = VAR_STRING; + tv.vval.v_string = (char_u *)""; + if (append) + set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)"."); + else + set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)"="); + err = did_emsg; + did_emsg += save_emsg; + if (err) + { + var_redir_stop(); + return FAIL; + } + if (redir_lval->ll_newkey != NULL) + { + /* Dictionary item was created, don't do it again. */ + vim_free(redir_lval->ll_newkey); + redir_lval->ll_newkey = NULL; + } + + return OK; +} + +/* + * Append "value[len]" to the variable set by var_redir_start(). + */ + void +var_redir_str(value, len) + char_u *value; + int len; +{ + char_u *val; + typval_T tv; + int save_emsg; + int err; + + if (redir_lval == NULL) + return; + + if (len == -1) + /* Append the entire string */ + val = vim_strsave(value); + else + /* Append only the specified number of characters */ + val = vim_strnsave(value, len); + if (val == NULL) + return; + + tv.v_type = VAR_STRING; + tv.vval.v_string = val; + + save_emsg = did_emsg; + did_emsg = FALSE; + set_var_lval(redir_lval, redir_endp, &tv, FALSE, (char_u *)"."); + err = did_emsg; + did_emsg += save_emsg; + if (err) + var_redir_stop(); + + vim_free(tv.vval.v_string); +} + +/* + * Stop redirecting command output to a variable. + */ + void +var_redir_stop() +{ + if (redir_lval != NULL) + { + clear_lval(redir_lval); + vim_free(redir_lval); + redir_lval = NULL; + } + vim_free(redir_varname); + redir_varname = NULL; +} + # if defined(FEAT_MBYTE) || defined(PROTO) int eval_charconvert(enc_from, enc_to, fname_from, fname_to) @@ -5866,12 +6007,15 @@ static struct fst {"matchstr", 2, 4, f_matchstr}, {"max", 1, 1, f_max}, {"min", 1, 1, f_min}, +#ifdef vim_mkdir + {"mkdir", 1, 3, f_mkdir}, +#endif {"mode", 0, 0, f_mode}, {"nextnonblank", 1, 1, f_nextnonblank}, {"nr2char", 1, 1, f_nr2char}, {"prevnonblank", 1, 1, f_prevnonblank}, {"range", 1, 3, f_range}, - {"readfile", 1, 2, f_readfile}, + {"readfile", 1, 3, f_readfile}, {"remote_expr", 2, 3, f_remote_expr}, {"remote_foreground", 1, 1, f_remote_foreground}, {"remote_peek", 1, 2, f_remote_peek}, @@ -6218,7 +6362,7 @@ call_func(name, len, rettv, argcount, ar } #endif /* Try loading a package. */ - if (fp == NULL && func_autoload(fname) && !aborting()) + if (fp == NULL && script_autoload(fname) && !aborting()) { /* loaded a package, search for the function again */ fp = find_func(fname); @@ -6226,13 +6370,13 @@ call_func(name, len, rettv, argcount, ar if (fp != NULL) { - if (fp->flags & FC_RANGE) + if (fp->uf_flags & FC_RANGE) *doesrange = TRUE; - if (argcount < fp->args.ga_len) + if (argcount < fp->uf_args.ga_len) error = ERROR_TOOFEW; - else if (!fp->varargs && argcount > fp->args.ga_len) + else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len) error = ERROR_TOOMANY; - else if ((fp->flags & FC_DICT) && selfdict == NULL) + else if ((fp->uf_flags & FC_DICT) && selfdict == NULL) error = ERROR_DICT; else { @@ -6243,12 +6387,12 @@ call_func(name, len, rettv, argcount, ar */ save_search_patterns(); saveRedobuff(); - ++fp->calls; + ++fp->uf_calls; call_user_func(fp, argcount, argvars, rettv, firstline, lastline, - (fp->flags & FC_DICT) ? selfdict : NULL); - if (--fp->calls <= 0 && isdigit(*fp->name) - && fp->refcount <= 0) + (fp->uf_flags & FC_DICT) ? selfdict : NULL); + if (--fp->uf_calls <= 0 && isdigit(*fp->uf_name) + && fp->uf_refcount <= 0) /* Function was unreferenced while being used, free it * now. */ func_free(fp); @@ -8198,7 +8342,7 @@ f_getbufvar(argvars, rettv) else { /* look up the variable */ - v = find_var_in_ht(&buf->b_vars.dv_hashtab, varname); + v = find_var_in_ht(&buf->b_vars.dv_hashtab, varname, FALSE); if (v != NULL) copy_tv(&v->di_tv, rettv); } @@ -8723,7 +8867,7 @@ f_getwinvar(argvars, rettv) else { /* look up the variable */ - v = find_var_in_ht(&win->w_vars.dv_hashtab, varname); + v = find_var_in_ht(&win->w_vars.dv_hashtab, varname, FALSE); if (v != NULL) copy_tv(&v->di_tv, rettv); } @@ -8909,6 +9053,9 @@ f_has(argvars, rettv) #ifdef FEAT_SEARCHPATH "file_in_path", #endif +#if defined(UNIX) && !defined(USE_SYSTEM) + "filterpipe", +#endif #ifdef FEAT_FIND_ID "find_in_path", #endif @@ -9772,8 +9919,6 @@ f_isdirectory(argvars, rettv) rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0])); } -static int tv_islocked __ARGS((typval_T *tv)); - /* * Return TRUE if typeval "tv" is locked: Either tha value is locked itself or * it refers to a List or Dictionary that is locked. @@ -10569,6 +10714,68 @@ f_min(argvars, rettv) max_min(argvars, rettv, FALSE); } +static int mkdir_recurse __ARGS((char_u *dir, int prot)); + +/* + * Create the directory in which "dir" is located, and higher levels when + * needed. + */ + static int +mkdir_recurse(dir, prot) + char_u *dir; + int prot; +{ + char_u *p; + char_u *updir; + int r = FAIL; + + /* Get end of directory name in "dir". + * We're done when it's "/" or "c:/". */ + p = gettail_sep(dir); + if (p <= get_past_head(dir)) + return OK; + + /* If the directory exists we're done. Otherwise: create it.*/ + updir = vim_strnsave(dir, (int)(p - dir)); + if (updir == NULL) + return FAIL; + if (mch_isdir(updir)) + r = OK; + else if (mkdir_recurse(updir, prot) == OK) + r = vim_mkdir_emsg(updir, prot); + vim_free(updir); + return r; +} + +#ifdef vim_mkdir +/* + * "mkdir()" function + */ + static void +f_mkdir(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + char_u *dir; + char_u buf[NUMBUFLEN]; + int prot = 0755; + + rettv->vval.v_number = FAIL; + if (check_restricted() || check_secure()) + return; + + dir = get_tv_string_buf(&argvars[0], buf); + if (argvars[1].v_type != VAR_UNKNOWN) + { + if (argvars[2].v_type != VAR_UNKNOWN) + prot = get_tv_number(&argvars[2]); + if (STRCMP(get_tv_string(&argvars[1]), "p") == 0) + mkdir_recurse(dir, prot); + } + rettv->vval.v_number = vim_mkdir_emsg(dir, prot); +} +#endif + /* * "mode()" function */ @@ -10754,10 +10961,16 @@ f_readfile(argvars, rettv) int prevlen = 0; /* length of "prev" if not NULL */ char_u *s; int len; - - if (argvars[1].v_type != VAR_UNKNOWN - && STRCMP(get_tv_string(&argvars[1]), "b") == 0) - binary = TRUE; + long maxline = MAXLNUM; + long cnt = 0; + + if (argvars[1].v_type != VAR_UNKNOWN) + { + if (STRCMP(get_tv_string(&argvars[1]), "b") == 0) + binary = TRUE; + if (argvars[2].v_type != VAR_UNKNOWN) + maxline = get_tv_number(&argvars[2]); + } l = list_alloc(); if (l == NULL) @@ -10776,7 +10989,7 @@ f_readfile(argvars, rettv) } filtd = 0; - for (;;) + while (cnt < maxline) { readlen = fread(buf + filtd, 1, FREAD_SIZE - filtd, fd); buflen = filtd + readlen; @@ -10825,6 +11038,8 @@ f_readfile(argvars, rettv) li->li_tv.vval.v_string = s; list_append(l, li); + if (++cnt >= maxline) + break; if (readlen <= 0) break; } @@ -10863,6 +11078,7 @@ f_readfile(argvars, rettv) } } + vim_free(prev); fclose(fd); } @@ -14132,7 +14348,7 @@ find_var(name, htp) *htp = ht; if (ht == NULL) return NULL; - return find_var_in_ht(ht, varname); + return find_var_in_ht(ht, varname, htp != NULL); } /* @@ -14140,9 +14356,10 @@ find_var(name, htp) * Returns NULL if not found. */ static dictitem_T * -find_var_in_ht(ht, varname) +find_var_in_ht(ht, varname, writing) hashtab_T *ht; char_u *varname; + int writing; { hashitem_T *hi; @@ -14164,7 +14381,15 @@ find_var_in_ht(ht, varname) hi = hash_find(ht, varname); if (HASHITEM_EMPTY(hi)) - return NULL; + { + /* For global variables we may try auto-loading the script. If it + * worked find the variable again. */ + if (ht == &globvarht && !writing + && script_autoload(varname) && !aborting()) + hi = hash_find(ht, varname); + if (HASHITEM_EMPTY(hi)) + return NULL; + } return HI2DI(hi); } @@ -14179,8 +14404,8 @@ find_var_ht(name, varname) { if (name[1] != ':') { - /* If not "x:name" there must not be any ":" in the name. */ - if (vim_strchr(name, ':') != NULL) + /* The name must not start with a colon. */ + if (name[0] == ':') return NULL; *varname = name; @@ -14193,12 +14418,15 @@ find_var_ht(name, varname) return ¤t_funccal->l_vars.dv_hashtab; /* l: variable */ } *varname = name + 2; + if (*name == 'g') /* global variable */ + return &globvarht; + /* There must be no ':' in the rest of the name, unless g: is used */ + if (vim_strchr(name + 2, ':') != NULL) + return NULL; if (*name == 'b') /* buffer variable */ return &curbuf->b_vars.dv_hashtab; if (*name == 'w') /* window variable */ return &curwin->w_vars.dv_hashtab; - if (*name == 'g') /* global variable */ - return &globvarht; if (*name == 'v') /* v: variable */ return &vimvarht; if (*name == 'a' && current_funccal != NULL) /* function argument */ @@ -14435,7 +14663,7 @@ set_var(name, tv, copy) return; } - v = find_var_in_ht(ht, varname); + v = find_var_in_ht(ht, varname, TRUE); if (v != NULL) { /* existing variable, need to clear the value */ @@ -14932,6 +15160,9 @@ ex_function(eap) funcdict_T fudi; static int func_nr = 0; /* number for nameless function */ int paren; + hashtab_T *ht; + int todo; + hashitem_T *hi; /* * ":function" without argument: list functions. @@ -14939,9 +15170,19 @@ ex_function(eap) if (ends_excmd(*eap->arg)) { if (!eap->skip) - for (fp = firstfunc; fp != NULL && !got_int; fp = fp->next) - if (!isdigit(*fp->name)) - list_func_head(fp, FALSE); + { + todo = globvarht.ht_used; + for (hi = globvarht.ht_array; todo > 0 && !got_int; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + --todo; + fp = HI2UF(hi); + if (!isdigit(*fp->uf_name)) + list_func_head(fp, FALSE); + } + } + } eap->nextcmd = check_nextcmd(eap->arg); return; } @@ -15004,7 +15245,7 @@ ex_function(eap) if (fp != NULL) { list_func_head(fp, TRUE); - for (j = 0; j < fp->lines.ga_len && !got_int; ++j) + for (j = 0; j < fp->uf_lines.ga_len && !got_int; ++j) { msg_putchar('\n'); msg_outnum((long)(j + 1)); @@ -15012,7 +15253,7 @@ ex_function(eap) msg_putchar(' '); if (j < 99) msg_putchar(' '); - msg_prt_line(FUNCLINE(fp, j)); + msg_prt_line(FUNCLINE(fp, j), FALSE); out_flush(); /* show a line at a time */ ui_breakcheck(); } @@ -15260,7 +15501,7 @@ ex_function(eap) */ if (fudi.fd_dict == NULL) { - v = find_var(name, NULL); + v = find_var(name, &ht); if (v != NULL && v->di_tv.v_type == VAR_FUNC) { emsg_funcname("E707: Function name conflicts with variable: %s", @@ -15276,15 +15517,15 @@ ex_function(eap) emsg_funcname(e_funcexts, name); goto erret; } - if (fp->calls > 0) + if (fp->uf_calls > 0) { emsg_funcname("E127: Cannot redefine function %s: It is in use", name); goto erret; } /* redefine existing function */ - ga_clear_strings(&(fp->args)); - ga_clear_strings(&(fp->lines)); + ga_clear_strings(&(fp->uf_args)); + ga_clear_strings(&(fp->uf_lines)); vim_free(name); name = NULL; } @@ -15320,7 +15561,35 @@ ex_function(eap) if (fp == NULL) { - fp = (ufunc_T *)alloc((unsigned)sizeof(ufunc_T)); + if (fudi.fd_dict == NULL && vim_strchr(name, ':') != NULL) + { + int slen, plen; + char_u *scriptname; + + /* Check that the autoload name matches the script name. */ + j = FAIL; + if (sourcing_name != NULL) + { + scriptname = autoload_name(name); + if (scriptname != NULL) + { + p = vim_strchr(scriptname, '/'); + plen = STRLEN(p); + slen = STRLEN(sourcing_name); + if (slen > plen && fnamecmp(p, + sourcing_name + slen - plen) == 0) + j = OK; + vim_free(scriptname); + } + } + if (j == FAIL) + { + EMSG2(_("E746: Function name does not match script file name: %s"), name); + goto erret; + } + } + + fp = (ufunc_T *)alloc((unsigned)(sizeof(ufunc_T) + STRLEN(name))); if (fp == NULL) goto erret; @@ -15347,21 +15616,19 @@ ex_function(eap) fudi.fd_di->di_tv.v_type = VAR_FUNC; fudi.fd_di->di_tv.v_lock = 0; fudi.fd_di->di_tv.vval.v_string = vim_strsave(name); - fp->refcount = 1; + fp->uf_refcount = 1; } /* insert the new function in the function list */ - fp->name = name; - name = NULL; - fp->next = firstfunc; - firstfunc = fp; - } - fp->args = newargs; - fp->lines = newlines; - fp->varargs = varargs; - fp->flags = flags; - fp->calls = 0; - fp->script_ID = current_SID; + STRCPY(fp->uf_name, name); + hash_add(&func_hashtab, UF2HIKEY(fp)); + } + fp->uf_args = newargs; + fp->uf_lines = newlines; + fp->uf_varargs = varargs; + fp->uf_flags = flags; + fp->uf_calls = 0; + fp->uf_script_ID = current_SID; goto ret_free; erret: @@ -15573,21 +15840,21 @@ list_func_head(fp, indent) if (indent) MSG_PUTS(" "); MSG_PUTS("function "); - if (fp->name[0] == K_SPECIAL) + if (fp->uf_name[0] == K_SPECIAL) { MSG_PUTS_ATTR("<SNR>", hl_attr(HLF_8)); - msg_puts(fp->name + 3); - } - else - msg_puts(fp->name); + msg_puts(fp->uf_name + 3); + } + else + msg_puts(fp->uf_name); msg_putchar('('); - for (j = 0; j < fp->args.ga_len; ++j) + for (j = 0; j < fp->uf_args.ga_len; ++j) { if (j) MSG_PUTS(", "); msg_puts(FUNCARG(fp, j)); } - if (fp->varargs) + if (fp->uf_varargs) { if (j) MSG_PUTS(", "); @@ -15604,12 +15871,12 @@ list_func_head(fp, indent) find_func(name) char_u *name; { - ufunc_T *fp; - - for (fp = firstfunc; fp != NULL; fp = fp->next) - if (STRCMP(name, fp->name) == 0) - break; - return fp; + hashitem_T *hi; + + hi = hash_find(&func_hashtab, name); + if (!HASHITEM_EMPTY(hi)) + return HI2UF(hi); + return NULL; } /* @@ -15646,11 +15913,11 @@ builtin_function(name) } /* - * If "name" has a package name try autoloading the script. + * If "name" has a package name try autoloading the script for it. * Return TRUE if a package was loaded. */ static int -func_autoload(name) +script_autoload(name) char_u *name; { char_u *p; @@ -15662,6 +15929,26 @@ func_autoload(name) if (p == NULL || p <= name + 2) return FALSE; + /* Try loading the package from $VIMRUNTIME/autoload/<name>.vim */ + scriptname = autoload_name(name); + if (cmd_runtime(scriptname, FALSE) == OK) + ret = TRUE; + + vim_free(scriptname); + return ret; +} + +/* + * Return the autoload script name for a function or variable name. + * Returns NULL when out of memory. + */ + static char_u * +autoload_name(name) + char_u *name; +{ + char_u *p; + char_u *scriptname; + /* Get the script file name: replace ':' with '/', append ".vim". */ scriptname = alloc((unsigned)(STRLEN(name) + 14)); if (scriptname == NULL) @@ -15672,13 +15959,7 @@ func_autoload(name) STRCAT(scriptname, ".vim"); while ((p = vim_strchr(scriptname, ':')) != NULL) *p = '/'; - - /* Try loading the package from $VIMRUNTIME/autoload/<name>.vim */ - if (cmd_runtime(scriptname, FALSE) == OK) - ret = TRUE; - - vim_free(scriptname); - return ret; + return scriptname; } #if defined(FEAT_CMDL_COMPL) || defined(PROTO) @@ -15692,24 +15973,33 @@ get_user_func_name(xp, idx) expand_T *xp; int idx; { - static ufunc_T *fp = NULL; + static long_u done; + static hashitem_T *hi; + ufunc_T *fp; if (idx == 0) - fp = firstfunc; - if (fp != NULL) - { - if (STRLEN(fp->name) + 4 >= IOSIZE) - return fp->name; /* prevents overflow */ + { + done = 0; + hi = func_hashtab.ht_array; + } + if (done < func_hashtab.ht_used) + { + if (done++ > 0) + ++hi; + while (HASHITEM_EMPTY(hi)) + ++hi; + fp = HI2UF(hi); + + if (STRLEN(fp->uf_name) + 4 >= IOSIZE) + return fp->uf_name; /* prevents overflow */ cat_func_name(IObuff, fp); if (xp->xp_context != EXPAND_USER_FUNC) { STRCAT(IObuff, "("); - if (!fp->varargs && fp->args.ga_len == 0) + if (!fp->uf_varargs && fp->uf_args.ga_len == 0) STRCAT(IObuff, ")"); } - - fp = fp->next; return IObuff; } return NULL; @@ -15727,13 +16017,13 @@ cat_func_name(buf, fp) char_u *buf; ufunc_T *fp; { - if (fp->name[0] == K_SPECIAL) + if (fp->uf_name[0] == K_SPECIAL) { STRCPY(buf, "<SNR>"); - STRCAT(buf, fp->name + 3); - } - else - STRCPY(buf, fp->name); + STRCAT(buf, fp->uf_name + 3); + } + else + STRCPY(buf, fp->uf_name); } /* @@ -15778,7 +16068,7 @@ ex_delfunction(eap) EMSG2(_("E130: Undefined function: %s"), eap->arg); return; } - if (fp->calls > 0) + if (fp->uf_calls > 0) { EMSG2(_("E131: Cannot delete function %s: It is in use"), eap->arg); return; @@ -15802,25 +16092,19 @@ ex_delfunction(eap) func_free(fp) ufunc_T *fp; { - ufunc_T *pfp; + hashitem_T *hi; /* clear this function */ - vim_free(fp->name); - ga_clear_strings(&(fp->args)); - ga_clear_strings(&(fp->lines)); - - /* remove the function from the function list */ - if (firstfunc == fp) - firstfunc = fp->next; - else - { - for (pfp = firstfunc; pfp != NULL; pfp = pfp->next) - if (pfp->next == fp) - { - pfp->next = fp->next; - break; - } - } + ga_clear_strings(&(fp->uf_args)); + ga_clear_strings(&(fp->uf_lines)); + + /* remove the function from the function hashtable */ + hi = hash_find(&func_hashtab, UF2HIKEY(fp)); + if (HASHITEM_EMPTY(hi)) + EMSG2(_(e_intern2), "func_free()"); + else + hash_remove(&func_hashtab, hi); + vim_free(fp); } @@ -15839,11 +16123,11 @@ func_unref(name) fp = find_func(name); if (fp == NULL) EMSG2(_(e_intern2), "func_unref()"); - else if (--fp->refcount <= 0) + else if (--fp->uf_refcount <= 0) { /* Only delete it when it's not being used. Otherwise it's done - * when "calls" becomes zero. */ - if (fp->calls == 0) + * when "uf_calls" becomes zero. */ + if (fp->uf_calls == 0) func_free(fp); } } @@ -15864,7 +16148,7 @@ func_ref(name) if (fp == NULL) EMSG2(_(e_intern2), "func_ref()"); else - ++fp->refcount; + ++fp->uf_refcount; } } @@ -15915,7 +16199,7 @@ call_user_func(fp, argcount, argvars, re fc.returned = FALSE; fc.level = ex_nesting_level; /* Check if this function has a breakpoint. */ - fc.breakpoint = dbg_find_breakpoint(FALSE, fp->name, (linenr_T)0); + fc.breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0); fc.dbg_tick = debug_tick; /* @@ -15947,7 +16231,7 @@ call_user_func(fp, argcount, argvars, re */ init_var_dict(&fc.l_avars, &fc.l_avars_var); add_nr_var(&fc.l_avars, &fc.fixvar[fixvar_idx++].var, "0", - (varnumber_T)(argcount - fp->args.ga_len)); + (varnumber_T)(argcount - fp->uf_args.ga_len)); v = &fc.fixvar[fixvar_idx++].var; STRCPY(v->di_key, "000"); v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; @@ -15969,7 +16253,7 @@ call_user_func(fp, argcount, argvars, re (varnumber_T)lastline); for (i = 0; i < argcount; ++i) { - ai = i - fp->args.ga_len; + ai = i - fp->uf_args.ga_len; if (ai < 0) /* named argument a:name */ name = FUNCARG(fp, i); @@ -16014,7 +16298,7 @@ call_user_func(fp, argcount, argvars, re save_sourcing_lnum = sourcing_lnum; sourcing_lnum = 1; sourcing_name = alloc((unsigned)((save_sourcing_name == NULL ? 0 - : STRLEN(save_sourcing_name)) + STRLEN(fp->name) + 13)); + : STRLEN(save_sourcing_name)) + STRLEN(fp->uf_name) + 13)); if (sourcing_name != NULL) { if (save_sourcing_name != NULL @@ -16058,7 +16342,7 @@ call_user_func(fp, argcount, argvars, re } } save_current_SID = current_SID; - current_SID = fp->script_ID; + current_SID = fp->uf_script_ID; save_did_emsg = did_emsg; did_emsg = FALSE; @@ -16069,7 +16353,7 @@ call_user_func(fp, argcount, argvars, re --RedrawingDisabled; /* when the function was aborted because of an error, return -1 */ - if ((did_emsg && (fp->flags & FC_ABORT)) || rettv->v_type == VAR_UNKNOWN) + if ((did_emsg && (fp->uf_flags & FC_ABORT)) || rettv->v_type == VAR_UNKNOWN) { clear_tv(rettv); rettv->v_type = VAR_NUMBER; @@ -16346,13 +16630,13 @@ get_func_line(c, cookie, indent) /* If breakpoints have been added/deleted need to check for it. */ if (fcp->dbg_tick != debug_tick) { - fcp->breakpoint = dbg_find_breakpoint(FALSE, fcp->func->name, + fcp->breakpoint = dbg_find_breakpoint(FALSE, fcp->func->uf_name, sourcing_lnum); fcp->dbg_tick = debug_tick; } - gap = &fcp->func->lines; - if ((fcp->func->flags & FC_ABORT) && did_emsg && !aborted_in_try()) + gap = &fcp->func->uf_lines; + if ((fcp->func->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try()) retval = NULL; else if (fcp->returned || fcp->linenr >= gap->ga_len) retval = NULL; @@ -16365,9 +16649,9 @@ get_func_line(c, cookie, indent) /* Did we encounter a breakpoint? */ if (fcp->breakpoint != 0 && fcp->breakpoint <= sourcing_lnum) { - dbg_breakpoint(fcp->func->name, sourcing_lnum); + dbg_breakpoint(fcp->func->uf_name, sourcing_lnum); /* Find next breakpoint. */ - fcp->breakpoint = dbg_find_breakpoint(FALSE, fcp->func->name, + fcp->breakpoint = dbg_find_breakpoint(FALSE, fcp->func->uf_name, sourcing_lnum); fcp->dbg_tick = debug_tick; } @@ -16387,7 +16671,7 @@ func_has_ended(cookie) /* Ignore the "abort" flag if the abortion behavior has been changed due to * an error inside a try conditional. */ - return (((fcp->func->flags & FC_ABORT) && did_emsg && !aborted_in_try()) + return (((fcp->func->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try()) || fcp->returned); } @@ -16398,7 +16682,7 @@ func_has_ended(cookie) func_has_abort(cookie) void *cookie; { - return ((funccall_T *)cookie)->func->flags & FC_ABORT; + return ((funccall_T *)cookie)->func->uf_flags & FC_ABORT; } #if defined(FEAT_VIMINFO) || defined(FEAT_SESSION)