diff src/evalvars.c @ 17922:4d63d47d87ef v8.1.1957

patch 8.1.1957: more code can be moved to evalvars.c Commit: https://github.com/vim/vim/commit/da6c03342117fb7f4a8110bd9e8627b612a05a64 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Sep 1 16:01:30 2019 +0200 patch 8.1.1957: more code can be moved to evalvars.c Problem: More code can be moved to evalvars.c. Solution: Move code to where it fits better. (Yegappan Lakshmanan, closes #4883)
author Bram Moolenaar <Bram@vim.org>
date Sun, 01 Sep 2019 16:15:03 +0200
parents e4d3b6c466d4
children 745c02392844
line wrap: on
line diff
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -18,6 +18,8 @@
 static char *e_letunexp	= N_("E18: Unexpected characters in :let");
 
 static dictitem_T	globvars_var;		// variable used for g:
+static dict_T		globvardict;		// Dictionary with g: variables
+#define globvarht globvardict.dv_hashtab
 
 /*
  * Old Vim variables such as "v:version" are also available without the "v:".
@@ -154,6 +156,7 @@ static struct vimvar
 #define vv_tv		vv_di.di_tv
 
 static dictitem_T	vimvars_var;		// variable used for v:
+static dict_T		vimvardict;		// Dictionary with v: variables
 #define vimvarht  vimvardict.dv_hashtab
 
 // for VIM_VERSION_ defines
@@ -185,6 +188,7 @@ static void ex_unletlock(exarg_T *eap, c
 static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit);
 static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock);
 static void item_lock(typval_T *tv, int deep, int lock);
+static void delete_var(hashtab_T *ht, hashitem_T *hi);
 static void list_one_var(dictitem_T *v, char *prefix, int *first);
 static void list_one_var_a(char *prefix, char_u *name, int type, char_u *string, int *first);
 
@@ -296,6 +300,12 @@ evalvars_clear(void)
 #endif
 
     int
+garbage_collect_globvars(int copyID)
+{
+    return set_ref_in_ht(&globvarht, copyID, NULL);
+}
+
+    int
 garbage_collect_vimvars(int copyID)
 {
     return set_ref_in_ht(&vimvarht, copyID, NULL);
@@ -335,6 +345,148 @@ set_internal_string_var(char_u *name, ch
     }
 }
 
+    int
+eval_charconvert(
+    char_u	*enc_from,
+    char_u	*enc_to,
+    char_u	*fname_from,
+    char_u	*fname_to)
+{
+    int		err = FALSE;
+
+    set_vim_var_string(VV_CC_FROM, enc_from, -1);
+    set_vim_var_string(VV_CC_TO, enc_to, -1);
+    set_vim_var_string(VV_FNAME_IN, fname_from, -1);
+    set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
+    if (eval_to_bool(p_ccv, &err, NULL, FALSE))
+	err = TRUE;
+    set_vim_var_string(VV_CC_FROM, NULL, -1);
+    set_vim_var_string(VV_CC_TO, NULL, -1);
+    set_vim_var_string(VV_FNAME_IN, NULL, -1);
+    set_vim_var_string(VV_FNAME_OUT, NULL, -1);
+
+    if (err)
+	return FAIL;
+    return OK;
+}
+
+# if defined(FEAT_POSTSCRIPT) || defined(PROTO)
+    int
+eval_printexpr(char_u *fname, char_u *args)
+{
+    int		err = FALSE;
+
+    set_vim_var_string(VV_FNAME_IN, fname, -1);
+    set_vim_var_string(VV_CMDARG, args, -1);
+    if (eval_to_bool(p_pexpr, &err, NULL, FALSE))
+	err = TRUE;
+    set_vim_var_string(VV_FNAME_IN, NULL, -1);
+    set_vim_var_string(VV_CMDARG, NULL, -1);
+
+    if (err)
+    {
+	mch_remove(fname);
+	return FAIL;
+    }
+    return OK;
+}
+# endif
+
+# if defined(FEAT_DIFF) || defined(PROTO)
+    void
+eval_diff(
+    char_u	*origfile,
+    char_u	*newfile,
+    char_u	*outfile)
+{
+    int		err = FALSE;
+
+    set_vim_var_string(VV_FNAME_IN, origfile, -1);
+    set_vim_var_string(VV_FNAME_NEW, newfile, -1);
+    set_vim_var_string(VV_FNAME_OUT, outfile, -1);
+    (void)eval_to_bool(p_dex, &err, NULL, FALSE);
+    set_vim_var_string(VV_FNAME_IN, NULL, -1);
+    set_vim_var_string(VV_FNAME_NEW, NULL, -1);
+    set_vim_var_string(VV_FNAME_OUT, NULL, -1);
+}
+
+    void
+eval_patch(
+    char_u	*origfile,
+    char_u	*difffile,
+    char_u	*outfile)
+{
+    int		err;
+
+    set_vim_var_string(VV_FNAME_IN, origfile, -1);
+    set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
+    set_vim_var_string(VV_FNAME_OUT, outfile, -1);
+    (void)eval_to_bool(p_pex, &err, NULL, FALSE);
+    set_vim_var_string(VV_FNAME_IN, NULL, -1);
+    set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
+    set_vim_var_string(VV_FNAME_OUT, NULL, -1);
+}
+# endif
+
+#if defined(FEAT_SPELL) || defined(PROTO)
+/*
+ * Evaluate an expression to a list with suggestions.
+ * For the "expr:" part of 'spellsuggest'.
+ * Returns NULL when there is an error.
+ */
+    list_T *
+eval_spell_expr(char_u *badword, char_u *expr)
+{
+    typval_T	save_val;
+    typval_T	rettv;
+    list_T	*list = NULL;
+    char_u	*p = skipwhite(expr);
+
+    // Set "v:val" to the bad word.
+    prepare_vimvar(VV_VAL, &save_val);
+    set_vim_var_string(VV_VAL, badword, -1);
+    if (p_verbose == 0)
+	++emsg_off;
+
+    if (eval1(&p, &rettv, TRUE) == OK)
+    {
+	if (rettv.v_type != VAR_LIST)
+	    clear_tv(&rettv);
+	else
+	    list = rettv.vval.v_list;
+    }
+
+    if (p_verbose == 0)
+	--emsg_off;
+    clear_tv(get_vim_var_tv(VV_VAL));
+    restore_vimvar(VV_VAL, &save_val);
+
+    return list;
+}
+
+/*
+ * "list" is supposed to contain two items: a word and a number.  Return the
+ * word in "pp" and the number as the return value.
+ * Return -1 if anything isn't right.
+ * Used to get the good word and score from the eval_spell_expr() result.
+ */
+    int
+get_spellword(list_T *list, char_u **pp)
+{
+    listitem_T	*li;
+
+    li = list->lv_first;
+    if (li == NULL)
+	return -1;
+    *pp = tv_get_string(&li->li_tv);
+
+    li = li->li_next;
+    if (li == NULL)
+	return -1;
+    return (int)tv_get_number(&li->li_tv);
+}
+#endif
+
 /*
  * Prepare v: variable "idx" to be used.
  * Save the current typeval in "save_tv".
@@ -1569,6 +1721,31 @@ item_lock(typval_T *tv, int deep, int lo
     --recurse;
 }
 
+#if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO)
+/*
+ * Delete all "menutrans_" variables.
+ */
+    void
+del_menutrans_vars(void)
+{
+    hashitem_T	*hi;
+    int		todo;
+
+    hash_lock(&globvarht);
+    todo = (int)globvarht.ht_used;
+    for (hi = globvarht.ht_array; todo > 0 && !got_int; ++hi)
+    {
+	if (!HASHITEM_EMPTY(hi))
+	{
+	    --todo;
+	    if (STRNCMP(HI2DI(hi)->di_key, "menutrans_", 10) == 0)
+		delete_var(&globvarht, hi);
+	}
+    }
+    hash_unlock(&globvarht);
+}
+#endif
+
 /*
  * Local string buffer for the next two functions to store a variable name
  * with its prefix. Allocated in cat_prefix_varname(), freed later in
@@ -1688,6 +1865,47 @@ get_user_var_name(expand_T *xp, int idx)
     return NULL;
 }
 
+    char *
+get_var_special_name(int nr)
+{
+    switch (nr)
+    {
+	case VVAL_FALSE: return "v:false";
+	case VVAL_TRUE:  return "v:true";
+	case VVAL_NONE:  return "v:none";
+	case VVAL_NULL:  return "v:null";
+    }
+    internal_error("get_var_special_name()");
+    return "42";
+}
+
+/*
+ * Returns the global variable dictionary
+ */
+    dict_T *
+get_globvar_dict(void)
+{
+    return &globvardict;
+}
+
+/*
+ * Returns the global variable hash table
+ */
+    hashtab_T *
+get_globvar_ht(void)
+{
+    return &globvarht;
+}
+
+/*
+ * Returns the v: variable dictionary
+ */
+    dict_T *
+get_vimvar_dict(void)
+{
+    return &vimvardict;
+}
+
 /*
  * Set type of v: variable to "type".
  */
@@ -2321,7 +2539,7 @@ vars_clear_ext(hashtab_T *ht, int free_v
  * Delete a variable from hashtab "ht" at item "hi".
  * Clear the variable value and free the dictitem.
  */
-    void
+    static void
 delete_var(hashtab_T *ht, hashitem_T *hi)
 {
     dictitem_T	*di = HI2DI(hi);
@@ -2853,6 +3071,157 @@ var_exists(char_u *var)
     return n;
 }
 
+static lval_T	*redir_lval = NULL;
+#define EVALCMD_BUSY (redir_lval == (lval_T *)&redir_lval)
+static garray_T redir_ga;	// only valid when redir_lval is not NULL
+static char_u	*redir_endp = NULL;
+static char_u	*redir_varname = NULL;
+
+/*
+ * Start recording command output to a variable
+ * When "append" is TRUE append to an existing variable.
+ * Returns OK if successfully completed the setup.  FAIL otherwise.
+ */
+    int
+var_redir_start(char_u *name, int append)
+{
+    int		save_emsg;
+    int		err;
+    typval_T	tv;
+
+    // Catch a bad name early.
+    if (!eval_isnamec1(*name))
+    {
+	emsg(_(e_invarg));
+	return FAIL;
+    }
+
+    // Make a copy of the name, it is used in redir_lval until redir ends.
+    redir_varname = vim_strsave(name);
+    if (redir_varname == NULL)
+	return FAIL;
+
+    redir_lval = ALLOC_CLEAR_ONE(lval_T);
+    if (redir_lval == NULL)
+    {
+	var_redir_stop();
+	return FAIL;
+    }
+
+    // The output is stored in growarray "redir_ga" until redirection ends.
+    ga_init2(&redir_ga, (int)sizeof(char), 500);
+
+    // Parse the variable name (can be a dict or list entry).
+    redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, 0,
+							     FNE_CHECK_START);
+    if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != NUL)
+    {
+	clear_lval(redir_lval);
+	if (redir_endp != NULL && *redir_endp != NUL)
+	    // Trailing characters are present after the variable name
+	    emsg(_(e_trailing));
+	else
+	    emsg(_(e_invarg));
+	redir_endp = NULL;  // don't store a value, only cleanup
+	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, FALSE, (char_u *)".");
+    else
+	set_var_lval(redir_lval, redir_endp, &tv, TRUE, FALSE, (char_u *)"=");
+    clear_lval(redir_lval);
+    err = did_emsg;
+    did_emsg |= save_emsg;
+    if (err)
+    {
+	redir_endp = NULL;  // don't store a value, only cleanup
+	var_redir_stop();
+	return FAIL;
+    }
+
+    return OK;
+}
+
+/*
+ * Append "value[value_len]" to the variable set by var_redir_start().
+ * The actual appending is postponed until redirection ends, because the value
+ * appended may in fact be the string we write to, changing it may cause freed
+ * memory to be used:
+ *   :redir => foo
+ *   :let foo
+ *   :redir END
+ */
+    void
+var_redir_str(char_u *value, int value_len)
+{
+    int		len;
+
+    if (redir_lval == NULL)
+	return;
+
+    if (value_len == -1)
+	len = (int)STRLEN(value);	// Append the entire string
+    else
+	len = value_len;		// Append only "value_len" characters
+
+    if (ga_grow(&redir_ga, len) == OK)
+    {
+	mch_memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len);
+	redir_ga.ga_len += len;
+    }
+    else
+	var_redir_stop();
+}
+
+/*
+ * Stop redirecting command output to a variable.
+ * Frees the allocated memory.
+ */
+    void
+var_redir_stop(void)
+{
+    typval_T	tv;
+
+    if (EVALCMD_BUSY)
+    {
+	redir_lval = NULL;
+	return;
+    }
+
+    if (redir_lval != NULL)
+    {
+	// If there was no error: assign the text to the variable.
+	if (redir_endp != NULL)
+	{
+	    ga_append(&redir_ga, NUL);  // Append the trailing NUL.
+	    tv.v_type = VAR_STRING;
+	    tv.vval.v_string = redir_ga.ga_data;
+	    // Call get_lval() again, if it's inside a Dict or List it may
+	    // have changed.
+	    redir_endp = get_lval(redir_varname, NULL, redir_lval,
+					FALSE, FALSE, 0, FNE_CHECK_START);
+	    if (redir_endp != NULL && redir_lval->ll_name != NULL)
+		set_var_lval(redir_lval, redir_endp, &tv, FALSE, FALSE,
+								(char_u *)".");
+	    clear_lval(redir_lval);
+	}
+
+	// free the collected output
+	VIM_CLEAR(redir_ga.ga_data);
+
+	VIM_CLEAR(redir_lval);
+    }
+    VIM_CLEAR(redir_varname);
+}
+
 /*
  * "gettabvar()" function
  */