diff options
author | Bram Moolenaar <Bram@vim.org> | 2016-07-17 14:57:05 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2016-07-17 14:57:05 +0200 |
commit | cd52459c387785796713826c63174cdeed295dd4 (patch) | |
tree | f2c964f83534a80d539b44826baea085a41fa595 /src/eval.c | |
parent | 42ebd066422d73cdb7bda6a1dc828a3dd022dec8 (diff) |
patch 7.4.2055v7.4.2055
Problem: eval.c is too big.
Solution: Move Dictionary functions to dict.c.
Diffstat (limited to 'src/eval.c')
-rw-r--r-- | src/eval.c | 846 |
1 files changed, 13 insertions, 833 deletions
diff --git a/src/eval.c b/src/eval.c index fadd26fc7b..e74ccfa33e 100644 --- a/src/eval.c +++ b/src/eval.c @@ -34,18 +34,6 @@ be freed. */ /* - * In a hashtab item "hi_key" points to "di_key" in a dictitem. - * This avoids adding a pointer to the hashtab item. - * DI2HIKEY() converts a dictitem pointer to a hashitem key pointer. - * HIKEY2DI() converts a hashitem key pointer to a dictitem pointer. - * HI2DI() converts a hashitem pointer to a dictitem pointer. - */ -static dictitem_T dumdi; -#define DI2HIKEY(di) ((di)->di_key) -#define HIKEY2DI(p) ((dictitem_T *)(p - (dumdi.di_key - (char_u *)&dumdi))) -#define HI2DI(hi) HIKEY2DI((hi)->hi_key) - -/* * Structure returned by get_lval() and used by set_var_lval(). * For a plain name: * "name" points to the variable name. @@ -97,7 +85,6 @@ static char *e_missbrac = N_("E111: Missing ']'"); static char *e_listarg = N_("E686: Argument of %s must be a List"); static char *e_listdictarg = N_("E712: Argument of %s must be a List or Dictionary"); static char *e_listreq = N_("E714: List required"); -static char *e_dictreq = N_("E715: Dictionary required"); #ifdef FEAT_QUICKFIX static char *e_stringreq = N_("E928: String required"); #endif @@ -131,11 +118,6 @@ static hashtab_T compat_hashtab; * The last bit is used for previous_funccal, ignored when comparing. */ static int current_copyID = 0; -#define COPYID_INC 2 -#define COPYID_MASK (~0x1) - -/* Abort conversion to string after a recursion error. */ -static int did_echo_string_emsg = FALSE; /* * Array to hold the hashtab with variables local to each sourced script. @@ -215,7 +197,6 @@ static garray_T ga_loaded = {0, 0, sizeof(char_u *), 4, NULL}; /* List heads for garbage collection. Although there can be a reference loop * from partial to dict to partial, we don't need to keep track of the partial, * since it will get freed when the dict is unused and gets freed. */ -static dict_T *first_dict = NULL; /* list of all dicts */ static list_T *first_list = NULL; /* list of all lists */ /* From user function to hashitem and back. */ @@ -423,7 +404,6 @@ static void item_lock(typval_T *tv, int deep, int lock); static int tv_islocked(typval_T *tv); static int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate); -static int eval1(char_u **arg, typval_T *rettv, int evaluate); static int eval2(char_u **arg, typval_T *rettv, int evaluate); static int eval3(char_u **arg, typval_T *rettv, int evaluate); static int eval4(char_u **arg, typval_T *rettv, int evaluate); @@ -440,8 +420,6 @@ static void list_free_contents(list_T *l); static void list_free_list(list_T *l); static long list_len(list_T *l); static int list_equal(list_T *l1, list_T *l2, int ic, int recursive); -static int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive); -static int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive); static long list_find_nr(list_T *l, long idx, int *errorp); static long list_idx_of_item(list_T *l, listitem_T *item); static int list_extend(list_T *l1, list_T *l2, listitem_T *bef); @@ -451,17 +429,9 @@ static char_u *list2string(typval_T *tv, int copyID, int restore_copyID); static int list_join_inner(garray_T *gap, list_T *l, char_u *sep, int echo_style, int restore_copyID, int copyID, garray_T *join_gap); static int list_join(garray_T *gap, list_T *l, char_u *sep, int echo_style, int restore_copyID, int copyID); static int free_unref_items(int copyID); -static dictitem_T *dictitem_copy(dictitem_T *org); -static void dictitem_remove(dict_T *dict, dictitem_T *item); -static dict_T *dict_copy(dict_T *orig, int deep, int copyID); -static long dict_len(dict_T *d); -static char_u *dict2string(typval_T *tv, int copyID, int restore_copyID); -static int get_dict_tv(char_u **arg, typval_T *rettv, int evaluate); static int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, int *varargs, int skip); static int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate); -static char_u *echo_string_core(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID, int echo_style, int restore_copyID, int dict_val); static char_u *echo_string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID); -static char_u *string_quote(char_u *str, int function); static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate); static int find_internal_func(char_u *name); static char_u *deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload); @@ -469,9 +439,6 @@ static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, lin static void emsg_funcname(char *ermsg, char_u *name); static int non_zero_arg(typval_T *argvars); -static void dict_free_contents(dict_T *d); -static void dict_free_dict(dict_T *d); - #ifdef FEAT_FLOAT static void f_abs(typval_T *argvars, typval_T *rettv); static void f_acos(typval_T *argvars, typval_T *rettv); @@ -898,12 +865,7 @@ static void delete_var(hashtab_T *ht, hashitem_T *hi); static void list_one_var(dictitem_T *v, char_u *prefix, int *first); static void list_one_var_a(char_u *prefix, char_u *name, int type, char_u *string, int *first); static void set_var(char_u *name, typval_T *varp, int copy); -static int var_check_ro(int flags, char_u *name, int use_gettext); static int var_check_fixed(int flags, char_u *name, int use_gettext); -static int var_check_func_name(char_u *name, int new_var); -static int valid_varname(char_u *varname); -static int tv_check_lock(int lock, char_u *name, int use_gettext); -static int item_copy(typval_T *from, typval_T *to, int deep, int copyID); static char_u *find_option_end(char_u **arg, int *opt_flags); static char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fd, partial_T **partial); static int eval_fname_script(char_u *p); @@ -4260,7 +4222,7 @@ eval0( * * Return OK or FAIL. */ - static int + int eval1(char_u **arg, typval_T *rettv, int evaluate) { int result; @@ -6259,54 +6221,6 @@ list_equal( return item1 == NULL && item2 == NULL; } -/* - * Return the dictitem that an entry in a hashtable points to. - */ - dictitem_T * -dict_lookup(hashitem_T *hi) -{ - return HI2DI(hi); -} - -/* - * Return TRUE when two dictionaries have exactly the same key/values. - */ - static int -dict_equal( - dict_T *d1, - dict_T *d2, - int ic, /* ignore case for strings */ - int recursive) /* TRUE when used recursively */ -{ - hashitem_T *hi; - dictitem_T *item2; - int todo; - - if (d1 == NULL && d2 == NULL) - return TRUE; - if (d1 == NULL || d2 == NULL) - return FALSE; - if (d1 == d2) - return TRUE; - if (dict_len(d1) != dict_len(d2)) - return FALSE; - - todo = (int)d1->dv_hashtab.ht_used; - for (hi = d1->dv_hashtab.ht_array; todo > 0; ++hi) - { - if (!HASHITEM_EMPTY(hi)) - { - item2 = dict_find(d2, hi->hi_key, -1); - if (item2 == NULL) - return FALSE; - if (!tv_equal(&HI2DI(hi)->di_tv, &item2->di_tv, ic, recursive)) - return FALSE; - --todo; - } - } - return TRUE; -} - static int tv_equal_recurse_limit; static int @@ -6366,7 +6280,7 @@ func_equal( * Compares the items just like "==" would compare them, but strings and * numbers are different. Floats and numbers are also different. */ - static int + int tv_equal( typval_T *tv1, typval_T *tv2, @@ -7198,7 +7112,6 @@ garbage_collect(int testing) static int free_unref_items(int copyID) { - dict_T *dd, *dd_next; list_T *ll, *ll_next; int did_free = FALSE; @@ -7212,18 +7125,8 @@ free_unref_items(int copyID) * themselves yet, so that it is possible to decrement refcount counters */ - /* - * Go through the list of dicts and free items without the copyID. - */ - for (dd = first_dict; dd != NULL; dd = dd->dv_used_next) - if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) - { - /* Free the Dictionary and ordinary items it contains, but don't - * recurse into Lists and Dictionaries, they will be in the list - * of dicts or list of lists. */ - dict_free_contents(dd); - did_free = TRUE; - } + /* Go through the list of dicts and free items without the copyID. */ + did_free |= dict_free_nonref(copyID); /* * Go through the list of lists and free items without the copyID. @@ -7254,12 +7157,7 @@ free_unref_items(int copyID) /* * PASS 2: free the items themselves. */ - for (dd = first_dict; dd != NULL; dd = dd_next) - { - dd_next = dd->dv_used_next; - if ((dd->dv_copyID & COPYID_MASK) != (copyID & COPYID_MASK)) - dict_free_dict(dd); - } + dict_free_items(copyID); for (ll = first_list; ll != NULL; ll = ll_next) { @@ -7538,583 +7436,6 @@ set_ref_in_item( return abort; } -/* - * Allocate an empty header for a dictionary. - */ - dict_T * -dict_alloc(void) -{ - dict_T *d; - - d = (dict_T *)alloc(sizeof(dict_T)); - if (d != NULL) - { - /* Add the dict to the list of dicts for garbage collection. */ - if (first_dict != NULL) - first_dict->dv_used_prev = d; - d->dv_used_next = first_dict; - d->dv_used_prev = NULL; - first_dict = d; - - hash_init(&d->dv_hashtab); - d->dv_lock = 0; - d->dv_scope = 0; - d->dv_refcount = 0; - d->dv_copyID = 0; - } - return d; -} - -/* - * Allocate an empty dict for a return value. - * Returns OK or FAIL. - */ - int -rettv_dict_alloc(typval_T *rettv) -{ - dict_T *d = dict_alloc(); - - if (d == NULL) - return FAIL; - - rettv->vval.v_dict = d; - rettv->v_type = VAR_DICT; - rettv->v_lock = 0; - ++d->dv_refcount; - return OK; -} - - -/* - * Unreference a Dictionary: decrement the reference count and free it when it - * becomes zero. - */ - void -dict_unref(dict_T *d) -{ - if (d != NULL && --d->dv_refcount <= 0) - dict_free(d); -} - -/* - * Free a Dictionary, including all non-container items it contains. - * Ignores the reference count. - */ - static void -dict_free_contents(dict_T *d) -{ - int todo; - hashitem_T *hi; - dictitem_T *di; - - /* Lock the hashtab, we don't want it to resize while freeing items. */ - hash_lock(&d->dv_hashtab); - todo = (int)d->dv_hashtab.ht_used; - for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) - { - if (!HASHITEM_EMPTY(hi)) - { - /* Remove the item before deleting it, just in case there is - * something recursive causing trouble. */ - di = HI2DI(hi); - hash_remove(&d->dv_hashtab, hi); - clear_tv(&di->di_tv); - vim_free(di); - --todo; - } - } - hash_clear(&d->dv_hashtab); -} - - static void -dict_free_dict(dict_T *d) -{ - /* Remove the dict from the list of dicts for garbage collection. */ - if (d->dv_used_prev == NULL) - first_dict = d->dv_used_next; - else - d->dv_used_prev->dv_used_next = d->dv_used_next; - if (d->dv_used_next != NULL) - d->dv_used_next->dv_used_prev = d->dv_used_prev; - vim_free(d); -} - - void -dict_free(dict_T *d) -{ - if (!in_free_unref_items) - { - dict_free_contents(d); - dict_free_dict(d); - } -} - -/* - * Allocate a Dictionary item. - * The "key" is copied to the new item. - * Note that the value of the item "di_tv" still needs to be initialized! - * Returns NULL when out of memory. - */ - dictitem_T * -dictitem_alloc(char_u *key) -{ - dictitem_T *di; - - di = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T) + STRLEN(key))); - if (di != NULL) - { - STRCPY(di->di_key, key); - di->di_flags = DI_FLAGS_ALLOC; - } - return di; -} - -/* - * Make a copy of a Dictionary item. - */ - static dictitem_T * -dictitem_copy(dictitem_T *org) -{ - dictitem_T *di; - - di = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T) - + STRLEN(org->di_key))); - if (di != NULL) - { - STRCPY(di->di_key, org->di_key); - di->di_flags = DI_FLAGS_ALLOC; - copy_tv(&org->di_tv, &di->di_tv); - } - return di; -} - -/* - * Remove item "item" from Dictionary "dict" and free it. - */ - static void -dictitem_remove(dict_T *dict, dictitem_T *item) -{ - hashitem_T *hi; - - hi = hash_find(&dict->dv_hashtab, item->di_key); - if (HASHITEM_EMPTY(hi)) - EMSG2(_(e_intern2), "dictitem_remove()"); - else - hash_remove(&dict->dv_hashtab, hi); - dictitem_free(item); -} - -/* - * Free a dict item. Also clears the value. - */ - void -dictitem_free(dictitem_T *item) -{ - clear_tv(&item->di_tv); - if (item->di_flags & DI_FLAGS_ALLOC) - vim_free(item); -} - -/* - * Make a copy of dict "d". Shallow if "deep" is FALSE. - * The refcount of the new dict is set to 1. - * See item_copy() for "copyID". - * Returns NULL when out of memory. - */ - static dict_T * -dict_copy(dict_T *orig, int deep, int copyID) -{ - dict_T *copy; - dictitem_T *di; - int todo; - hashitem_T *hi; - - if (orig == NULL) - return NULL; - - copy = dict_alloc(); - if (copy != NULL) - { - if (copyID != 0) - { - orig->dv_copyID = copyID; - orig->dv_copydict = copy; - } - todo = (int)orig->dv_hashtab.ht_used; - for (hi = orig->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi) - { - if (!HASHITEM_EMPTY(hi)) - { - --todo; - - di = dictitem_alloc(hi->hi_key); - if (di == NULL) - break; - if (deep) - { - if (item_copy(&HI2DI(hi)->di_tv, &di->di_tv, deep, - copyID) == FAIL) - { - vim_free(di); - break; - } - } - else - copy_tv(&HI2DI(hi)->di_tv, &di->di_tv); - if (dict_add(copy, di) == FAIL) - { - dictitem_free(di); - break; - } - } - } - - ++copy->dv_refcount; - if (todo > 0) - { - dict_unref(copy); - copy = NULL; - } - } - - return copy; -} - -/* - * Add item "item" to Dictionary "d". - * Returns FAIL when out of memory and when key already exists. - */ - int -dict_add(dict_T *d, dictitem_T *item) -{ - return hash_add(&d->dv_hashtab, item->di_key); -} - -/* - * Add a number or string entry to dictionary "d". - * When "str" is NULL use number "nr", otherwise use "str". - * Returns FAIL when out of memory and when key already exists. - */ - int -dict_add_nr_str( - dict_T *d, - char *key, - varnumber_T nr, - char_u *str) -{ - dictitem_T *item; - - item = dictitem_alloc((char_u *)key); - if (item == NULL) - return FAIL; - item->di_tv.v_lock = 0; - if (str == NULL) - { - item->di_tv.v_type = VAR_NUMBER; - item->di_tv.vval.v_number = nr; - } - else - { - item->di_tv.v_type = VAR_STRING; - item->di_tv.vval.v_string = vim_strsave(str); - } - if (dict_add(d, item) == FAIL) - { - dictitem_free(item); - return FAIL; - } - return OK; -} - -/* - * Add a list entry to dictionary "d". - * Returns FAIL when out of memory and when key already exists. - */ - int -dict_add_list(dict_T *d, char *key, list_T *list) -{ - dictitem_T *item; - - item = dictitem_alloc((char_u *)key); - if (item == NULL) - return FAIL; - item->di_tv.v_lock = 0; - item->di_tv.v_type = VAR_LIST; - item->di_tv.vval.v_list = list; - if (dict_add(d, item) == FAIL) - { - dictitem_free(item); - return FAIL; - } - ++list->lv_refcount; - return OK; -} - -/* - * Get the number of items in a Dictionary. - */ - static long -dict_len(dict_T *d) -{ - if (d == NULL) - return 0L; - return (long)d->dv_hashtab.ht_used; -} - -/* - * Find item "key[len]" in Dictionary "d". - * If "len" is negative use strlen(key). - * Returns NULL when not found. - */ - dictitem_T * -dict_find(dict_T *d, char_u *key, int len) -{ -#define AKEYLEN 200 - char_u buf[AKEYLEN]; - char_u *akey; - char_u *tofree = NULL; - hashitem_T *hi; - - if (d == NULL) - return NULL; - if (len < 0) - akey = key; - else if (len >= AKEYLEN) - { - tofree = akey = vim_strnsave(key, len); - if (akey == NULL) - return NULL; - } - else - { - /* Avoid a malloc/free by using buf[]. */ - vim_strncpy(buf, key, len); - akey = buf; - } - - hi = hash_find(&d->dv_hashtab, akey); - vim_free(tofree); - if (HASHITEM_EMPTY(hi)) - return NULL; - return HI2DI(hi); -} - -/* - * Get a string item from a dictionary. - * When "save" is TRUE allocate memory for it. - * Returns NULL if the entry doesn't exist or out of memory. - */ - char_u * -get_dict_string(dict_T *d, char_u *key, int save) -{ - dictitem_T *di; - char_u *s; - - di = dict_find(d, key, -1); - if (di == NULL) - return NULL; - s = get_tv_string(&di->di_tv); - if (save && s != NULL) - s = vim_strsave(s); - return s; -} - -/* - * Get a number item from a dictionary. - * Returns 0 if the entry doesn't exist. - */ - varnumber_T -get_dict_number(dict_T *d, char_u *key) -{ - dictitem_T *di; - - di = dict_find(d, key, -1); - if (di == NULL) - return 0; - return get_tv_number(&di->di_tv); -} - -/* - * Return an allocated string with the string representation of a Dictionary. - * May return NULL. - */ - static char_u * -dict2string(typval_T *tv, int copyID, int restore_copyID) -{ - garray_T ga; - int first = TRUE; - char_u *tofree; - char_u numbuf[NUMBUFLEN]; - hashitem_T *hi; - char_u *s; - dict_T *d; - int todo; - - if ((d = tv->vval.v_dict) == NULL) - return NULL; - ga_init2(&ga, (int)sizeof(char), 80); - ga_append(&ga, '{'); - - todo = (int)d->dv_hashtab.ht_used; - for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi) - { - if (!HASHITEM_EMPTY(hi)) - { - --todo; - - if (first) - first = FALSE; - else - ga_concat(&ga, (char_u *)", "); - - tofree = string_quote(hi->hi_key, FALSE); - if (tofree != NULL) - { - ga_concat(&ga, tofree); - vim_free(tofree); - } - ga_concat(&ga, (char_u *)": "); - s = echo_string_core(&HI2DI(hi)->di_tv, &tofree, numbuf, copyID, - FALSE, restore_copyID, TRUE); - if (s != NULL) - ga_concat(&ga, s); - vim_free(tofree); - if (s == NULL || did_echo_string_emsg) - break; - line_breakcheck(); - - } - } - if (todo > 0) - { - vim_free(ga.ga_data); - return NULL; - } - - ga_append(&ga, '}'); - ga_append(&ga, NUL); - return (char_u *)ga.ga_data; -} - -/* - * Allocate a variable for a Dictionary and fill it from "*arg". - * Return OK or FAIL. Returns NOTDONE for {expr}. - */ - static int -get_dict_tv(char_u **arg, typval_T *rettv, int evaluate) -{ - dict_T *d = NULL; - typval_T tvkey; - typval_T tv; - char_u *key = NULL; - dictitem_T *item; - char_u *start = skipwhite(*arg + 1); - char_u buf[NUMBUFLEN]; - - /* - * First check if it's not a curly-braces thing: {expr}. - * Must do this without evaluating, otherwise a function may be called - * twice. Unfortunately this means we need to call eval1() twice for the - * first item. - * But {} is an empty Dictionary. - */ - if (*start != '}') - { - if (eval1(&start, &tv, FALSE) == FAIL) /* recursive! */ - return FAIL; - if (*start == '}') - return NOTDONE; - } - - if (evaluate) - { - d = dict_alloc(); - if (d == NULL) - return FAIL; - } - tvkey.v_type = VAR_UNKNOWN; - tv.v_type = VAR_UNKNOWN; - - *arg = skipwhite(*arg + 1); - while (**arg != '}' && **arg != NUL) - { - if (eval1(arg, &tvkey, evaluate) == FAIL) /* recursive! */ - goto failret; - if (**arg != ':') - { - EMSG2(_("E720: Missing colon in Dictionary: %s"), *arg); - clear_tv(&tvkey); - goto failret; - } - if (evaluate) - { - key = get_tv_string_buf_chk(&tvkey, buf); - if (key == NULL) - { - /* "key" is NULL when get_tv_string_buf_chk() gave an errmsg */ - clear_tv(&tvkey); - goto failret; - } - } - - *arg = skipwhite(*arg + 1); - if (eval1(arg, &tv, evaluate) == FAIL) /* recursive! */ - { - if (evaluate) - clear_tv(&tvkey); - goto failret; - } - if (evaluate) - { - item = dict_find(d, key, -1); - if (item != NULL) - { - EMSG2(_("E721: Duplicate key in Dictionary: \"%s\""), key); - clear_tv(&tvkey); - clear_tv(&tv); - goto failret; - } - item = dictitem_alloc(key); - clear_tv(&tvkey); - if (item != NULL) - { - item->di_tv = tv; - item->di_tv.v_lock = 0; - if (dict_add(d, item) == FAIL) - dictitem_free(item); - } - } - - if (**arg == '}') - break; - if (**arg != ',') - { - EMSG2(_("E722: Missing comma in Dictionary: %s"), *arg); - goto failret; - } - *arg = skipwhite(*arg + 1); - } - - if (**arg != '}') - { - EMSG2(_("E723: Missing end of Dictionary '}': %s"), *arg); -failret: - if (evaluate) - dict_free(d); - return FAIL; - } - - *arg = skipwhite(*arg + 1); - if (evaluate) - { - rettv->v_type = VAR_DICT; - rettv->vval.v_dict = d; - ++d->dv_refcount; - } - - return OK; -} - /* Get function arguments. */ static int get_function_args( @@ -8228,7 +7549,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate) ga_init(&newargs); ga_init(&newlines); - /* First, check if this is a lambda expression. "->" must exists. */ + /* First, check if this is a lambda expression. "->" must exist. */ ret = get_function_args(&start, '-', NULL, NULL, TRUE); if (ret == FAIL || *start != '>') return NOTDONE; @@ -8337,7 +7658,7 @@ get_var_special_name(int nr) * are replaced with "...". * May return NULL. */ - static char_u * + char_u * echo_string_core( typval_T *tv, char_u **tofree, @@ -8553,7 +7874,7 @@ tv2string( * If "str" is NULL an empty string is assumed. * If "function" is TRUE make it function('string'). */ - static char_u * + char_u * string_quote(char_u *str, int function) { unsigned len; @@ -11885,63 +11206,6 @@ f_expand(typval_T *argvars, typval_T *rettv) } /* - * Go over all entries in "d2" and add them to "d1". - * When "action" is "error" then a duplicate key is an error. - * When "action" is "force" then a duplicate key is overwritten. - * Otherwise duplicate keys are ignored ("action" is "keep"). - */ - void -dict_extend(dict_T *d1, dict_T *d2, char_u *action) -{ - dictitem_T *di1; - hashitem_T *hi2; - int todo; - char_u *arg_errmsg = (char_u *)N_("extend() argument"); - - todo = (int)d2->dv_hashtab.ht_used; - for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2) - { - if (!HASHITEM_EMPTY(hi2)) - { - --todo; - di1 = dict_find(d1, hi2->hi_key, -1); - if (d1->dv_scope != 0) - { - /* Disallow replacing a builtin function in l: and g:. - * Check the key to be valid when adding to any - * scope. */ - if (d1->dv_scope == VAR_DEF_SCOPE - && HI2DI(hi2)->di_tv.v_type == VAR_FUNC - && var_check_func_name(hi2->hi_key, - di1 == NULL)) - break; - if (!valid_varname(hi2->hi_key)) - break; - } - if (di1 == NULL) - { - di1 = dictitem_copy(HI2DI(hi2)); - if (di1 != NULL && dict_add(d1, di1) == FAIL) - dictitem_free(di1); - } - else if (*action == 'e') - { - EMSG2(_("E737: Key already exists: %s"), hi2->hi_key); - break; - } - else if (*action == 'f' && HI2DI(hi2) != di1) - { - if (tv_check_lock(di1->di_tv.v_lock, arg_errmsg, TRUE) - || var_check_ro(di1->di_flags, arg_errmsg, TRUE)) - break; - clear_tv(&di1->di_tv); - copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv); - } - } - } -} - -/* * "extend(list, list [, idx])" function * "extend(dict, dict [, action])" function */ @@ -15538,90 +14802,6 @@ f_isnan(typval_T *argvars, typval_T *rettv) } #endif -static void dict_list(typval_T *argvars, typval_T *rettv, int what); - -/* - * Turn a dict into a list: - * "what" == 0: list of keys - * "what" == 1: list of values - * "what" == 2: list of items - */ - static void -dict_list(typval_T *argvars, typval_T *rettv, int what) -{ - list_T *l2; - dictitem_T *di; - hashitem_T *hi; - listitem_T *li; - listitem_T *li2; - dict_T *d; - int todo; - - if (argvars[0].v_type != VAR_DICT) - { - EMSG(_(e_dictreq)); - return; - } - if ((d = argvars[0].vval.v_dict) == NULL) - return; - - if (rettv_list_alloc(rettv) == FAIL) - return; - - todo = (int)d->dv_hashtab.ht_used; - for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) - { - if (!HASHITEM_EMPTY(hi)) - { - --todo; - di = HI2DI(hi); - - li = listitem_alloc(); - if (li == NULL) - break; - list_append(rettv->vval.v_list, li); - - if (what == 0) - { - /* keys() */ - li->li_tv.v_type = VAR_STRING; - li->li_tv.v_lock = 0; - li->li_tv.vval.v_string = vim_strsave(di->di_key); - } - else if (what == 1) - { - /* values() */ - copy_tv(&di->di_tv, &li->li_tv); - } - else - { - /* items() */ - l2 = list_alloc(); - li->li_tv.v_type = VAR_LIST; - li->li_tv.v_lock = 0; - li->li_tv.vval.v_list = l2; - if (l2 == NULL) - break; - ++l2->lv_refcount; - - li2 = listitem_alloc(); - if (li2 == NULL) - break; - list_append(l2, li2); - li2->li_tv.v_type = VAR_STRING; - li2->li_tv.v_lock = 0; - li2->li_tv.vval.v_string = vim_strsave(di->di_key); - - li2 = listitem_alloc(); - if (li2 == NULL) - break; - list_append(l2, li2); - copy_tv(&di->di_tv, &li2->li_tv); - } - } - } -} - /* * "items(dict)" function */ @@ -23962,7 +23142,7 @@ set_var( * Return TRUE if di_flags "flags" indicates variable "name" is read-only. * Also give an error message. */ - static int + int var_check_ro(int flags, char_u *name, int use_gettext) { if (flags & DI_FLAGS_RO) @@ -23998,7 +23178,7 @@ var_check_fixed(int flags, char_u *name, int use_gettext) * Check if a funcref is assigned to a valid variable name. * Return TRUE and give an error if not. */ - static int + int var_check_func_name( char_u *name, /* points to start of variable name */ int new_var) /* TRUE when creating the variable */ @@ -24028,7 +23208,7 @@ var_check_func_name( * Check if a variable name is valid. * Return FALSE and give an error if not. */ - static int + int valid_varname(char_u *varname) { char_u *p; @@ -24048,7 +23228,7 @@ valid_varname(char_u *varname) * Also give an error message, using "name" or _("name") when use_gettext is * TRUE. */ - static int + int tv_check_lock(int lock, char_u *name, int use_gettext) { if (lock & VAR_LOCKED) @@ -24158,7 +23338,7 @@ copy_tv(typval_T *from, typval_T *to) * reference to an already copied list/dict can be used. * Returns FAIL or OK. */ - static int + int item_copy( typval_T *from, typval_T *to, |