Mirror of the Vim source from https://github.com/vim/vim
Revisión | 86d71ae0c85a546d4a00b53481b540a4ade2c9bd (tree) |
---|---|
Tiempo | 2005-01-20 07:24:34 |
Autor | vimboss |
Commiter | vimboss |
updated for version 7.0042
@@ -1,4 +1,4 @@ | ||
1 | -*todo.txt* For Vim version 7.0aa. Last change: 2005 Jan 17 | |
1 | +*todo.txt* For Vim version 7.0aa. Last change: 2005 Jan 19 | |
2 | 2 | |
3 | 3 | |
4 | 4 | VIM REFERENCE MANUAL by Bram Moolenaar |
@@ -30,6 +30,12 @@ | ||
30 | 30 | *known-bugs* |
31 | 31 | -------------------- Known bugs and current work ----------------------- |
32 | 32 | |
33 | +Hashtable implementation: | |
34 | +- Use hashtable for variables and syntax keywords. | |
35 | + | |
36 | +":grep": display progress (filename, every second or so) | |
37 | +Can ":grep" made faster somehow? Do profiling. | |
38 | + | |
33 | 39 | Sanity check of eval.c: |
34 | 40 | - Go through the code for magic braces. |
35 | 41 |
@@ -104,6 +110,7 @@ | ||
104 | 110 | - REFACTORING: The main() function is very long. Move parts to separate |
105 | 111 | functions, especially loops. Ideas from Walter Briscoe (2003 Apr 3, 2004 |
106 | 112 | Feb 9). |
113 | + Move the printing stuff to hardcopy.c. | |
107 | 114 | - Improve the interface between the generic GUI code and the system-specific |
108 | 115 | code. Generic code handles text window with scrollbars, system-specific |
109 | 116 | code menu, toolbar, etc. |
@@ -1576,7 +1583,6 @@ | ||
1576 | 1583 | 7 Add argument to winwidth() to subtract the space taken by 'foldcolumn', |
1577 | 1584 | signs and/or 'number'. |
1578 | 1585 | 8 Add functions: |
1579 | - search() Add optional offset argument. | |
1580 | 1586 | realname() Get user name (first, last, full) |
1581 | 1587 | user_fullname() patch by Nikolai Weibull, Nov |
1582 | 1588 | 3 2002 |
@@ -2417,6 +2423,8 @@ | ||
2417 | 2423 | like it's done when there is no code. And there is no automatic wrapping. |
2418 | 2424 | Recognize comments that come after code. Should insert the comment leader |
2419 | 2425 | when it's "#" or "//". |
2426 | + Other way around: when a C command starts with "* 4" the "*" is repeated | |
2427 | + while it should not. Use syntax HL comment recognition? | |
2420 | 2428 | 7 When using "comments=fg:--", Vim inserts three spaces for a new line. |
2421 | 2429 | When hitting a TAB, these spaces could be removed. |
2422 | 2430 | 7 The 'n'esting flag doesn't do the indenting of the last (rightmost) item. |
@@ -3236,11 +3244,11 @@ | ||
3236 | 3244 | 8 findmatchlimit() should be able to skip comments. Solves problem of |
3237 | 3245 | matching the '{' in /* if (foo) { */ (Fiveash) |
3238 | 3246 | - Add more redirecting of Ex commands: |
3239 | - :redir @> register (append) | |
3240 | - :redir # bufname | |
3241 | - :redir #> bufname (append) | |
3242 | - :redir = variable | |
3243 | - :redir => variable (append) | |
3247 | + :redir @r> register (append) | |
3248 | + :redir #> bufname | |
3249 | + :redir #>> bufname (append) | |
3250 | + :redir => variable | |
3251 | + :redir =>> variable (append) | |
3244 | 3252 | - Setting of options, specifically for a buffer or window, with |
3245 | 3253 | ":set window.option" or ":set buffer.option=val". Or use ":buffer.set". |
3246 | 3254 | Also: "buffer.map <F1> quit". |
@@ -33,6 +33,7 @@ | ||
33 | 33 | obj/fileio.o \ |
34 | 34 | obj/fold.o \ |
35 | 35 | obj/getchar.o \ |
36 | + obj/hashtable.o \ | |
36 | 37 | obj/main.o \ |
37 | 38 | obj/mark.o \ |
38 | 39 | obj/memfile.o \ |
@@ -48,6 +48,7 @@ | ||
48 | 48 | fileio.c \ |
49 | 49 | fold.c \ |
50 | 50 | getchar.c \ |
51 | + hashtable.c \ | |
51 | 52 | main.c \ |
52 | 53 | mark.c \ |
53 | 54 | memfile.c \ |
@@ -90,6 +91,7 @@ | ||
90 | 91 | obj/fileio.o \ |
91 | 92 | obj/fold.o \ |
92 | 93 | obj/getchar.o \ |
94 | + obj/hashtable.o \ | |
93 | 95 | obj/main.o \ |
94 | 96 | obj/mark.o \ |
95 | 97 | obj/memfile.o \ |
@@ -130,6 +132,7 @@ | ||
130 | 132 | proto/fileio.pro \ |
131 | 133 | proto/fold.pro \ |
132 | 134 | proto/getchar.pro \ |
135 | + proto/hashtable.pro \ | |
133 | 136 | proto/main.pro \ |
134 | 137 | proto/mark.pro \ |
135 | 138 | proto/memfile.pro \ |
@@ -243,6 +246,9 @@ | ||
243 | 246 | obj/getchar.o: getchar.c |
244 | 247 | $(CCSYM) $@ getchar.c |
245 | 248 | |
249 | +obj/hashtable.o: hashtable.c | |
250 | + $(CCSYM) $@ hashtable.c | |
251 | + | |
246 | 252 | # Don't use $(SYMS) here, because main.c defines EXTERN |
247 | 253 | obj/main.o: main.c option.h globals.h |
248 | 254 | $(CCNOSYM) $@ main.c |
@@ -38,6 +38,7 @@ | ||
38 | 38 | fileio.c \ |
39 | 39 | fold.c \ |
40 | 40 | getchar.c \ |
41 | + hashtable.c \ | |
41 | 42 | main.c \ |
42 | 43 | mark.c \ |
43 | 44 | mbyte.c \ |
@@ -109,23 +109,35 @@ | ||
109 | 109 | |
110 | 110 | /* |
111 | 111 | * Structure to hold an item of a Dictionary. |
112 | + * The key is copied into "di_key" to avoid an extra alloc/free for it. | |
112 | 113 | */ |
113 | 114 | struct dictitem_S |
114 | 115 | { |
115 | - struct dictitem_S *di_next; /* next item in list */ | |
116 | - char_u *di_key; /* key (never NULL!) */ | |
117 | 116 | typeval di_tv; /* type and value of the variable */ |
117 | + char_u di_key[1]; /* key (actually longer!) */ | |
118 | 118 | }; |
119 | 119 | |
120 | 120 | typedef struct dictitem_S dictitem; |
121 | 121 | |
122 | 122 | /* |
123 | + * In a hashtable item "hi_key" points to "di_key" in a dictitem. | |
124 | + * This avoids adding a pointer to the hashtable item. | |
125 | + * DI2HIKEY() converts a dictitem pointer to a hashitem key pointer. | |
126 | + * HIKEY2DI() converts a hashitem key pointer to a dictitem pointer. | |
127 | + * HI2DI() converts a hashitem pointer to a dictitem pointer. | |
128 | + */ | |
129 | +static dictitem dumdi; | |
130 | +#define DI2HIKEY(p) ((p)->di_key) | |
131 | +#define HIKEY2DI(p) ((dictitem *)(p - (dumdi.di_key - (char_u *)&dumdi.di_tv))) | |
132 | +#define HI2DI(p) HIKEY2DI((p)->hi_key) | |
133 | + | |
134 | +/* | |
123 | 135 | * Structure to hold info about a Dictionary. |
124 | 136 | */ |
125 | 137 | struct dictvar_S |
126 | 138 | { |
127 | 139 | int dv_refcount; /* reference count */ |
128 | - dictitem *dv_first; /* first item, NULL if none */ | |
140 | + hashtable dv_hashtable; /* hashtable that refers to the items */ | |
129 | 141 | }; |
130 | 142 | |
131 | 143 | typedef struct dictvar_S dictvar; |
@@ -173,7 +185,6 @@ | ||
173 | 185 | dictvar *ll_dict; /* The Dictionary or NULL */ |
174 | 186 | dictitem *ll_di; /* The dictitem or NULL */ |
175 | 187 | char_u *ll_newkey; /* New key for Dict in alloc. mem or NULL. */ |
176 | - dictitem **ll_pdi; /* di_next field pointing to found dictitem */ | |
177 | 188 | } lval; |
178 | 189 | |
179 | 190 |
@@ -181,10 +192,9 @@ | ||
181 | 192 | static char *e_listidx = N_("E684: list index out of range: %ld"); |
182 | 193 | static char *e_undefvar = N_("E121: Undefined variable: %s"); |
183 | 194 | static char *e_missbrac = N_("E111: Missing ']'"); |
184 | -static char *e_intern2 = N_("E685: Internal error: %s"); | |
185 | 195 | static char *e_listarg = N_("E686: Argument of %s must be a List"); |
186 | 196 | static char *e_listdictarg = N_("E712: Argument of %s must be a List or Dictionaary"); |
187 | -static char *e_emptykey = N_("E713: Empty key in Dictionary"); | |
197 | +static char *e_emptykey = N_("E713: Cannot use empty key for Dictionary"); | |
188 | 198 | static char *e_listreq = N_("E714: List required"); |
189 | 199 | static char *e_dictreq = N_("E715: Dictionary required"); |
190 | 200 | static char *e_toomanyarg = N_("E118: Too many arguments for function: %s"); |
@@ -289,7 +299,6 @@ | ||
289 | 299 | dictvar *fd_dict; /* Dictionary used */ |
290 | 300 | char_u *fd_newkey; /* new key in "dict" */ |
291 | 301 | dictitem *fd_di; /* Dictionary item used */ |
292 | - dictitem **fd_pdi; /* field that points to "fd_di" */ | |
293 | 302 | } funcdict; |
294 | 303 | |
295 | 304 | /* |
@@ -451,12 +460,13 @@ | ||
451 | 460 | static dictvar *dict_alloc __ARGS((void)); |
452 | 461 | static void dict_unref __ARGS((dictvar *d)); |
453 | 462 | static void dict_free __ARGS((dictvar *d)); |
454 | -static dictitem *dictitem_alloc __ARGS((void)); | |
463 | +static dictitem *dictitem_alloc __ARGS((char_u *key)); | |
455 | 464 | static dictitem *dictitem_copy __ARGS((dictitem *org)); |
465 | +static void dictitem_remove __ARGS((dictvar *dict, dictitem *item)); | |
456 | 466 | static void dictitem_free __ARGS((dictitem *item)); |
457 | -static void dict_add __ARGS((dictvar *d, dictitem *item)); | |
467 | +static int dict_add __ARGS((dictvar *d, dictitem *item)); | |
458 | 468 | static long dict_len __ARGS((dictvar *d)); |
459 | -static dictitem *dict_find __ARGS((dictvar *d, char_u *key, int len, dictitem ***pdi)); | |
469 | +static dictitem *dict_find __ARGS((dictvar *d, char_u *key, int len)); | |
460 | 470 | static char_u *dict2string __ARGS((typeval *tv)); |
461 | 471 | static int get_dict_tv __ARGS((char_u **arg, typeval *rettv, int evaluate)); |
462 | 472 |
@@ -1829,8 +1839,7 @@ | ||
1829 | 1839 | * aborting error, an interrupt, or an exception. */ |
1830 | 1840 | if (!aborting() && !quiet) |
1831 | 1841 | { |
1832 | - if (unlet) | |
1833 | - emsg_severe = TRUE; | |
1842 | + emsg_severe = TRUE; | |
1834 | 1843 | EMSG2(_(e_invarg2), name); |
1835 | 1844 | return NULL; |
1836 | 1845 | } |
@@ -1970,10 +1979,10 @@ | ||
1970 | 1979 | } |
1971 | 1980 | lp->ll_list = NULL; |
1972 | 1981 | lp->ll_dict = lp->ll_tv->vval.v_dict; |
1973 | - lp->ll_di = dict_find(lp->ll_dict, key, len, &lp->ll_pdi); | |
1982 | + lp->ll_di = dict_find(lp->ll_dict, key, len); | |
1974 | 1983 | if (lp->ll_di == NULL) |
1975 | 1984 | { |
1976 | - /* Key does not exist in dict: may need toadd it. */ | |
1985 | + /* Key does not exist in dict: may need to add it. */ | |
1977 | 1986 | if (*p == '[' || *p == '.' || unlet) |
1978 | 1987 | { |
1979 | 1988 | if (!quiet) |
@@ -2165,12 +2174,14 @@ | ||
2165 | 2174 | } |
2166 | 2175 | |
2167 | 2176 | /* Need to add an item to the Dictionary. */ |
2168 | - di = dictitem_alloc(); | |
2177 | + di = dictitem_alloc(lp->ll_newkey); | |
2169 | 2178 | if (di == NULL) |
2170 | 2179 | return; |
2171 | - di->di_key = lp->ll_newkey; | |
2172 | - lp->ll_newkey = NULL; | |
2173 | - dict_add(lp->ll_tv->vval.v_dict, di); | |
2180 | + if (dict_add(lp->ll_tv->vval.v_dict, di) == FAIL) | |
2181 | + { | |
2182 | + vim_free(di); | |
2183 | + return; | |
2184 | + } | |
2174 | 2185 | lp->ll_tv = &di->di_tv; |
2175 | 2186 | } |
2176 | 2187 | else if (op != NULL && *op != '=') |
@@ -2532,11 +2543,18 @@ | ||
2532 | 2543 | linenr_T lnum; |
2533 | 2544 | int doesrange; |
2534 | 2545 | int failed = FALSE; |
2535 | - | |
2536 | - tofree = trans_function_name(&arg, eap->skip, TFN_INT, NULL); | |
2546 | + funcdict fudi; | |
2547 | + | |
2548 | + tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi); | |
2549 | + vim_free(fudi.fd_newkey); | |
2537 | 2550 | if (tofree == NULL) |
2538 | 2551 | return; |
2539 | 2552 | |
2553 | + /* Increase refcount on dictionary, it could get deleted when evaluating | |
2554 | + * the arguments. */ | |
2555 | + if (fudi.fd_dict != NULL) | |
2556 | + ++fudi.fd_dict->dv_refcount; | |
2557 | + | |
2540 | 2558 | /* If it is the name of a variable of type VAR_FUNC use its contents. */ |
2541 | 2559 | len = STRLEN(tofree); |
2542 | 2560 | name = deref_func_name(tofree, &len); |
@@ -2572,7 +2590,8 @@ | ||
2572 | 2590 | } |
2573 | 2591 | arg = startarg; |
2574 | 2592 | if (get_func_tv(name, STRLEN(name), &rettv, &arg, |
2575 | - eap->line1, eap->line2, &doesrange, !eap->skip, NULL) == FAIL) | |
2593 | + eap->line1, eap->line2, &doesrange, | |
2594 | + !eap->skip, fudi.fd_dict) == FAIL) | |
2576 | 2595 | { |
2577 | 2596 | failed = TRUE; |
2578 | 2597 | break; |
@@ -2603,6 +2622,7 @@ | ||
2603 | 2622 | } |
2604 | 2623 | |
2605 | 2624 | end: |
2625 | + dict_unref(fudi.fd_dict); | |
2606 | 2626 | vim_free(tofree); |
2607 | 2627 | } |
2608 | 2628 |
@@ -2691,18 +2711,12 @@ | ||
2691 | 2711 | } |
2692 | 2712 | else |
2693 | 2713 | { |
2694 | - clear_tv(lp->ll_tv); | |
2695 | 2714 | if (lp->ll_list != NULL) |
2696 | - { | |
2697 | 2715 | /* unlet a List item. */ |
2698 | 2716 | listitem_remove(lp->ll_list, lp->ll_li); |
2699 | - } | |
2700 | - else | |
2701 | - { | |
2717 | + else | |
2702 | 2718 | /* unlet a Dictionary item. */ |
2703 | - *lp->ll_pdi = lp->ll_di->di_next; | |
2704 | - dictitem_free(lp->ll_di); | |
2705 | - } | |
2719 | + dictitem_remove(lp->ll_dict, lp->ll_di); | |
2706 | 2720 | } |
2707 | 2721 | |
2708 | 2722 | return ret; |
@@ -3761,7 +3775,7 @@ | ||
3761 | 3775 | /* |
3762 | 3776 | * Handle expr[expr], expr[expr:expr] subscript and .name lookup. |
3763 | 3777 | * Also handle function call with Funcref variable: func(expr) |
3764 | - * Can all be combined: dict.func(expr)[idx].func(expr) | |
3778 | + * Can all be combined: dict.func(expr)[idx]['func'](expr) | |
3765 | 3779 | */ |
3766 | 3780 | selfdict = NULL; |
3767 | 3781 | while (ret == OK |
@@ -3779,21 +3793,27 @@ | ||
3779 | 3793 | curwin->w_cursor.lnum, curwin->w_cursor.lnum, |
3780 | 3794 | &len, evaluate, selfdict); |
3781 | 3795 | |
3782 | - /* Stop the expression evaluation when immediately | |
3783 | - * aborting on error, or when an interrupt occurred or | |
3784 | - * an exception was thrown but not caught. */ | |
3796 | + /* Stop the expression evaluation when immediately aborting on | |
3797 | + * error, or when an interrupt occurred or an exception was thrown | |
3798 | + * but not caught. */ | |
3785 | 3799 | if (aborting()) |
3786 | 3800 | { |
3787 | 3801 | if (ret == OK) |
3788 | 3802 | clear_tv(rettv); |
3789 | 3803 | ret = FAIL; |
3790 | 3804 | } |
3805 | + dict_unref(selfdict); | |
3791 | 3806 | selfdict = NULL; |
3792 | 3807 | } |
3793 | - else | |
3794 | - { | |
3808 | + else /* **arg == '[' || **arg == '.' */ | |
3809 | + { | |
3810 | + dict_unref(selfdict); | |
3795 | 3811 | if (rettv->v_type == VAR_DICT) |
3812 | + { | |
3796 | 3813 | selfdict = rettv->vval.v_dict; |
3814 | + if (selfdict != NULL) | |
3815 | + ++selfdict->dv_refcount; | |
3816 | + } | |
3797 | 3817 | else |
3798 | 3818 | selfdict = NULL; |
3799 | 3819 | if (eval_index(arg, rettv, evaluate) == FAIL) |
@@ -3803,6 +3823,7 @@ | ||
3803 | 3823 | } |
3804 | 3824 | } |
3805 | 3825 | } |
3826 | + dict_unref(selfdict); | |
3806 | 3827 | |
3807 | 3828 | /* |
3808 | 3829 | * Apply logical NOT and unary '-', from right to left, ignore '+'. |
@@ -4033,7 +4054,7 @@ | ||
4033 | 4054 | } |
4034 | 4055 | } |
4035 | 4056 | |
4036 | - item = dict_find(rettv->vval.v_dict, key, (int)len, NULL); | |
4057 | + item = dict_find(rettv->vval.v_dict, key, (int)len); | |
4037 | 4058 | |
4038 | 4059 | if (item == NULL) |
4039 | 4060 | EMSG2(_(e_dictkey), key); |
@@ -4371,6 +4392,8 @@ | ||
4371 | 4392 | item->li_tv = tv; |
4372 | 4393 | list_append(l, item); |
4373 | 4394 | } |
4395 | + else | |
4396 | + clear_tv(&tv); | |
4374 | 4397 | } |
4375 | 4398 | |
4376 | 4399 | if (**arg == ']') |
@@ -4523,18 +4546,25 @@ | ||
4523 | 4546 | dictvar *d2; |
4524 | 4547 | int ic; /* ignore case for strings */ |
4525 | 4548 | { |
4526 | - dictitem *item1, *item2; | |
4549 | + hashitem *hi; | |
4550 | + dictitem *item2; | |
4551 | + int todo; | |
4527 | 4552 | |
4528 | 4553 | if (dict_len(d1) != dict_len(d2)) |
4529 | 4554 | return FALSE; |
4530 | 4555 | |
4531 | - for (item1 = d1->dv_first; item1 != NULL; item1 = item1->di_next) | |
4532 | - { | |
4533 | - item2 = dict_find(d2, item1->di_key, -1, NULL); | |
4534 | - if (item2 == NULL) | |
4535 | - return FALSE; | |
4536 | - if (!tv_equal(&item1->di_tv, &item2->di_tv, ic)) | |
4537 | - return FALSE; | |
4556 | + todo = d1->dv_hashtable.ht_used; | |
4557 | + for (hi = d1->dv_hashtable.ht_array; todo > 0; ++hi) | |
4558 | + { | |
4559 | + if (!HASHITEM_EMPTY(hi)) | |
4560 | + { | |
4561 | + item2 = dict_find(d2, hi->hi_key, -1); | |
4562 | + if (item2 == NULL) | |
4563 | + return FALSE; | |
4564 | + if (!tv_equal(&HI2DI(hi)->di_tv, &item2->di_tv, ic)) | |
4565 | + return FALSE; | |
4566 | + --todo; | |
4567 | + } | |
4538 | 4568 | } |
4539 | 4569 | return TRUE; |
4540 | 4570 | } |
@@ -4558,6 +4588,13 @@ | ||
4558 | 4588 | || !list_equal(tv1->vval.v_list, tv2->vval.v_list, ic)) |
4559 | 4589 | return FALSE; |
4560 | 4590 | } |
4591 | + else if (tv1->v_type == VAR_DICT || tv2->v_type == VAR_DICT) | |
4592 | + { | |
4593 | + /* recursive! */ | |
4594 | + if (tv1->v_type != tv2->v_type | |
4595 | + || !dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic)) | |
4596 | + return FALSE; | |
4597 | + } | |
4561 | 4598 | else if (tv1->v_type == VAR_FUNC || tv2->v_type == VAR_FUNC) |
4562 | 4599 | { |
4563 | 4600 | if (tv1->v_type != tv2->v_type |
@@ -4931,7 +4968,12 @@ | ||
4931 | 4968 | static dictvar * |
4932 | 4969 | dict_alloc() |
4933 | 4970 | { |
4934 | - return (dictvar *)alloc_clear(sizeof(dictvar)); | |
4971 | + dictvar *d; | |
4972 | + | |
4973 | + d = (dictvar *)alloc(sizeof(dictvar)); | |
4974 | + if (d != NULL) | |
4975 | + hash_init(&d->dv_hashtable); | |
4976 | + return d; | |
4935 | 4977 | } |
4936 | 4978 | |
4937 | 4979 | /* |
@@ -4954,24 +4996,39 @@ | ||
4954 | 4996 | dict_free(d) |
4955 | 4997 | dictvar *d; |
4956 | 4998 | { |
4957 | - dictitem *item; | |
4958 | - dictitem *next; | |
4959 | - | |
4960 | - for (item = d->dv_first; item != NULL; item = next) | |
4961 | - { | |
4962 | - next = item->di_next; | |
4963 | - dictitem_free(item); | |
4999 | + int todo; | |
5000 | + hashitem *hi; | |
5001 | + | |
5002 | + /* Careful: we free the dictitems while they still appear in the | |
5003 | + * hashtable. Must not try to resize the hashtable! */ | |
5004 | + todo = d->dv_hashtable.ht_used; | |
5005 | + for (hi = d->dv_hashtable.ht_array; todo > 0; ++hi) | |
5006 | + { | |
5007 | + if (!HASHITEM_EMPTY(hi)) | |
5008 | + { | |
5009 | + dictitem_free(HI2DI(hi)); | |
5010 | + --todo; | |
5011 | + } | |
4964 | 5012 | } |
4965 | 5013 | vim_free(d); |
4966 | 5014 | } |
4967 | 5015 | |
4968 | 5016 | /* |
4969 | 5017 | * Allocate a Dictionary item. |
5018 | + * The "key" is copied to the new item. | |
5019 | + * Note that the value of the item "di_tv" still needs to be initialized! | |
5020 | + * Returns NULL when out of memory. | |
4970 | 5021 | */ |
4971 | 5022 | static dictitem * |
4972 | -dictitem_alloc() | |
4973 | -{ | |
4974 | - return (dictitem *)alloc(sizeof(dictitem)); | |
5023 | +dictitem_alloc(key) | |
5024 | + char_u *key; | |
5025 | +{ | |
5026 | + dictitem *di; | |
5027 | + | |
5028 | + di = (dictitem *)alloc(sizeof(dictitem) + STRLEN(key)); | |
5029 | + if (di != NULL) | |
5030 | + STRCPY(di->di_key, key); | |
5031 | + return di; | |
4975 | 5032 | } |
4976 | 5033 | |
4977 | 5034 | /* |
@@ -4983,28 +5040,40 @@ | ||
4983 | 5040 | { |
4984 | 5041 | dictitem *di; |
4985 | 5042 | |
4986 | - di = (dictitem *)alloc(sizeof(dictitem)); | |
5043 | + di = (dictitem *)alloc(sizeof(dictitem) + STRLEN(org->di_key)); | |
4987 | 5044 | if (di != NULL) |
4988 | 5045 | { |
4989 | - di->di_key = vim_strsave(org->di_key); | |
4990 | - if (di->di_key == NULL) | |
4991 | - { | |
4992 | - vim_free(di); | |
4993 | - return NULL; | |
4994 | - } | |
5046 | + STRCPY(di->di_key, org->di_key); | |
4995 | 5047 | copy_tv(&org->di_tv, &di->di_tv); |
4996 | 5048 | } |
4997 | 5049 | return di; |
4998 | 5050 | } |
4999 | 5051 | |
5000 | 5052 | /* |
5053 | + * Remove item "item" from Dictionary "dict" and free it. | |
5054 | + */ | |
5055 | + static void | |
5056 | +dictitem_remove(dict, item) | |
5057 | + dictvar *dict; | |
5058 | + dictitem *item; | |
5059 | +{ | |
5060 | + hashitem *hi; | |
5061 | + | |
5062 | + hi = hash_find(&dict->dv_hashtable, item->di_key); | |
5063 | + if (HASHITEM_EMPTY(hi)) | |
5064 | + EMSG2(_(e_intern2), "dictitem_remove()"); | |
5065 | + else | |
5066 | + hash_remove(&dict->dv_hashtable, hi); | |
5067 | + dictitem_free(item); | |
5068 | +} | |
5069 | + | |
5070 | +/* | |
5001 | 5071 | * Free a dict item. Also clears the value. |
5002 | 5072 | */ |
5003 | 5073 | static void |
5004 | 5074 | dictitem_free(item) |
5005 | 5075 | dictitem *item; |
5006 | 5076 | { |
5007 | - vim_free(item->di_key); | |
5008 | 5077 | clear_tv(&item->di_tv); |
5009 | 5078 | vim_free(item); |
5010 | 5079 | } |
@@ -5020,8 +5089,9 @@ | ||
5020 | 5089 | int deep; |
5021 | 5090 | { |
5022 | 5091 | dictvar *copy; |
5023 | - dictitem *item; | |
5024 | 5092 | dictitem *di; |
5093 | + int todo; | |
5094 | + hashitem *hi; | |
5025 | 5095 | |
5026 | 5096 | if (orig == NULL) |
5027 | 5097 | return NULL; |
@@ -5029,23 +5099,28 @@ | ||
5029 | 5099 | copy = dict_alloc(); |
5030 | 5100 | if (copy != NULL) |
5031 | 5101 | { |
5032 | - for (item = orig->dv_first; item != NULL; item = item->di_next) | |
5033 | - { | |
5034 | - di = dictitem_alloc(); | |
5035 | - if (di == NULL) | |
5036 | - break; | |
5037 | - di->di_key = vim_strsave(item->di_key); | |
5038 | - if (di->di_key == NULL) | |
5039 | - { | |
5040 | - vim_free(di); | |
5041 | - break; | |
5042 | - } | |
5043 | - if (deep) | |
5044 | - item_copy(&item->di_tv, &di->di_tv, deep); | |
5045 | - else | |
5046 | - copy_tv(&item->di_tv, &di->di_tv); | |
5047 | - dict_add(copy, di); | |
5048 | - } | |
5102 | + todo = orig->dv_hashtable.ht_used; | |
5103 | + for (hi = orig->dv_hashtable.ht_array; todo > 0; ++hi) | |
5104 | + { | |
5105 | + if (!HASHITEM_EMPTY(hi)) | |
5106 | + { | |
5107 | + --todo; | |
5108 | + | |
5109 | + di = dictitem_alloc(hi->hi_key); | |
5110 | + if (di == NULL) | |
5111 | + break; | |
5112 | + if (deep) | |
5113 | + item_copy(&HI2DI(hi)->di_tv, &di->di_tv, deep); | |
5114 | + else | |
5115 | + copy_tv(&HI2DI(hi)->di_tv, &di->di_tv); | |
5116 | + if (dict_add(copy, di) == FAIL) | |
5117 | + { | |
5118 | + dictitem_free(di); | |
5119 | + break; | |
5120 | + } | |
5121 | + } | |
5122 | + } | |
5123 | + | |
5049 | 5124 | ++copy->dv_refcount; |
5050 | 5125 | } |
5051 | 5126 |
@@ -5054,69 +5129,15 @@ | ||
5054 | 5129 | |
5055 | 5130 | /* |
5056 | 5131 | * Add item "item" to Dictionary "d". |
5057 | - */ | |
5058 | - static void | |
5132 | + * Returns FAIL when out of memory and when key already existed. | |
5133 | + */ | |
5134 | + static int | |
5059 | 5135 | dict_add(d, item) |
5060 | 5136 | dictvar *d; |
5061 | 5137 | dictitem *item; |
5062 | 5138 | { |
5063 | - item->di_next = d->dv_first; | |
5064 | - d->dv_first = item; | |
5065 | -} | |
5066 | - | |
5067 | -#if 0 /* not currently used */ | |
5068 | -static void dict_set_item __ARGS((dictvar *d, int type, char *key, void *val)); | |
5069 | - | |
5070 | -/* | |
5071 | - * Add an item to Dictionary "d" with type "type", key "key" and value "val". | |
5072 | - * If it already exists it is overwritten. | |
5073 | - * The key and value are copied to allocated memory. | |
5074 | - */ | |
5075 | - static void | |
5076 | -dict_set_item(d, type, key, val) | |
5077 | - dictvar *d; | |
5078 | - int type; | |
5079 | - char *key; | |
5080 | - void *val; | |
5081 | -{ | |
5082 | - dictitem *di; | |
5083 | - char_u *dkey; | |
5084 | - | |
5085 | - di = dict_find(d, (char_u *)key, -1, NULL); | |
5086 | - if (di == NULL) | |
5087 | - { | |
5088 | - dkey = vim_strsave((char_u *)key); | |
5089 | - if (dkey != NULL) | |
5090 | - { | |
5091 | - di = dictitem_alloc(); | |
5092 | - if (di == NULL) | |
5093 | - vim_free(dkey); | |
5094 | - else | |
5095 | - di->di_key = dkey; | |
5096 | - } | |
5097 | - } | |
5098 | - else | |
5099 | - clear_tv(&di->di_tv); | |
5100 | - | |
5101 | - if (di != NULL) | |
5102 | - { | |
5103 | - di->di_tv.v_type = type; | |
5104 | - switch (type) | |
5105 | - { | |
5106 | - case VAR_NUMBER: | |
5107 | - di->di_tv.vval.v_number = (varnumber_T)val; | |
5108 | - break; | |
5109 | - case VAR_FUNC: | |
5110 | - case VAR_STRING: | |
5111 | - di->di_tv.vval.v_string = vim_strsave((char_u *)val); | |
5112 | - break; | |
5113 | - default: | |
5114 | - EMSG2(_(e_intern2), "dict_set_item()"); | |
5115 | - } | |
5116 | - dict_add(d, di); | |
5117 | - } | |
5118 | -} | |
5119 | -#endif | |
5139 | + return hash_add(&d->dv_hashtable, item->di_key); | |
5140 | +} | |
5120 | 5141 | |
5121 | 5142 | /* |
5122 | 5143 | * Get the number of items in a Dictionary. |
@@ -5125,43 +5146,49 @@ | ||
5125 | 5146 | dict_len(d) |
5126 | 5147 | dictvar *d; |
5127 | 5148 | { |
5128 | - dictitem *item; | |
5129 | - long len = 0; | |
5130 | - | |
5131 | 5149 | if (d == NULL) |
5132 | 5150 | return 0L; |
5133 | - for (item = d->dv_first; item != NULL; item = item->di_next) | |
5134 | - ++len; | |
5135 | - return len; | |
5151 | + return d->dv_hashtable.ht_used; | |
5136 | 5152 | } |
5137 | 5153 | |
5138 | 5154 | /* |
5139 | 5155 | * Find item "key[len]" in Dictionary "d". |
5140 | 5156 | * If "len" is negative use strlen(key). |
5141 | - * Sets "*pdi" to pointer to found item, unless "pdi" is NULL. | |
5142 | 5157 | * Returns NULL when not found. |
5143 | 5158 | */ |
5144 | 5159 | static dictitem * |
5145 | -dict_find(d, key, len, pdi) | |
5160 | +dict_find(d, key, len) | |
5146 | 5161 | dictvar *d; |
5147 | 5162 | char_u *key; |
5148 | 5163 | int len; |
5149 | - dictitem ***pdi; | |
5150 | -{ | |
5151 | - static dictitem *di; | |
5152 | - | |
5153 | - if (pdi != NULL) | |
5154 | - *pdi = &d->dv_first; | |
5155 | - for (di = d->dv_first; di != NULL; di = di->di_next) | |
5156 | - { | |
5157 | - if (len < 0 | |
5158 | - ? STRCMP(di->di_key, key) == 0 | |
5159 | - : STRNCMP(di->di_key, key, len) == 0 && di->di_key[len] == NUL) | |
5160 | - return di; | |
5161 | - if (pdi != NULL) | |
5162 | - *pdi = &di->di_next; | |
5163 | - } | |
5164 | - return NULL; | |
5164 | +{ | |
5165 | +#define AKEYLEN 200 | |
5166 | + char_u buf[AKEYLEN]; | |
5167 | + char_u *akey; | |
5168 | + char_u *tofree = NULL; | |
5169 | + hashitem *hi; | |
5170 | + | |
5171 | + if (len < 0) | |
5172 | + akey = key; | |
5173 | + else if (len >= AKEYLEN) | |
5174 | + { | |
5175 | + tofree = akey = vim_strnsave(key, len); | |
5176 | + if (akey == NULL) | |
5177 | + return NULL; | |
5178 | + } | |
5179 | + else | |
5180 | + { | |
5181 | + /* Avoid a malloc/free by using buf[]. */ | |
5182 | + STRNCPY(buf, key, len); | |
5183 | + buf[len] = NUL; | |
5184 | + akey = buf; | |
5185 | + } | |
5186 | + | |
5187 | + hi = hash_find(&d->dv_hashtable, akey); | |
5188 | + vim_free(tofree); | |
5189 | + if (HASHITEM_EMPTY(hi)) | |
5190 | + return NULL; | |
5191 | + return HI2DI(hi); | |
5165 | 5192 | } |
5166 | 5193 | |
5167 | 5194 | /* |
@@ -5176,32 +5203,40 @@ | ||
5176 | 5203 | int first = TRUE; |
5177 | 5204 | char_u *tofree; |
5178 | 5205 | char_u numbuf[NUMBUFLEN]; |
5179 | - dictitem *item; | |
5206 | + hashitem *hi; | |
5180 | 5207 | char_u *s; |
5181 | - | |
5182 | - if (tv->vval.v_dict == NULL) | |
5208 | + dictvar *d; | |
5209 | + int todo; | |
5210 | + | |
5211 | + if ((d = tv->vval.v_dict) == NULL) | |
5183 | 5212 | return NULL; |
5184 | 5213 | ga_init2(&ga, (int)sizeof(char), 80); |
5185 | 5214 | ga_append(&ga, '{'); |
5186 | 5215 | |
5187 | - for (item = tv->vval.v_dict->dv_first; item != NULL; item = item->di_next) | |
5188 | - { | |
5189 | - if (first) | |
5190 | - first = FALSE; | |
5191 | - else | |
5192 | - ga_concat(&ga, (char_u *)", "); | |
5193 | - | |
5194 | - tofree = string_quote(item->di_key, FALSE); | |
5195 | - if (tofree != NULL) | |
5196 | - { | |
5197 | - ga_concat(&ga, tofree); | |
5216 | + todo = d->dv_hashtable.ht_used; | |
5217 | + for (hi = d->dv_hashtable.ht_array; todo > 0; ++hi) | |
5218 | + { | |
5219 | + if (!HASHITEM_EMPTY(hi)) | |
5220 | + { | |
5221 | + --todo; | |
5222 | + | |
5223 | + if (first) | |
5224 | + first = FALSE; | |
5225 | + else | |
5226 | + ga_concat(&ga, (char_u *)", "); | |
5227 | + | |
5228 | + tofree = string_quote(hi->hi_key, FALSE); | |
5229 | + if (tofree != NULL) | |
5230 | + { | |
5231 | + ga_concat(&ga, tofree); | |
5232 | + vim_free(tofree); | |
5233 | + } | |
5234 | + ga_concat(&ga, (char_u *)": "); | |
5235 | + s = tv2string(&HI2DI(hi)->di_tv, &tofree, numbuf); | |
5236 | + if (s != NULL) | |
5237 | + ga_concat(&ga, s); | |
5198 | 5238 | vim_free(tofree); |
5199 | 5239 | } |
5200 | - ga_concat(&ga, (char_u *)": "); | |
5201 | - s = tv2string(&item->di_tv, &tofree, numbuf); | |
5202 | - if (s != NULL) | |
5203 | - ga_concat(&ga, s); | |
5204 | - vim_free(tofree); | |
5205 | 5240 | } |
5206 | 5241 | |
5207 | 5242 | ga_append(&ga, '}'); |
@@ -5220,10 +5255,12 @@ | ||
5220 | 5255 | int evaluate; |
5221 | 5256 | { |
5222 | 5257 | dictvar *d = NULL; |
5258 | + typeval tvkey; | |
5223 | 5259 | typeval tv; |
5224 | 5260 | char_u *key; |
5225 | 5261 | dictitem *item; |
5226 | 5262 | char_u *start = skipwhite(*arg + 1); |
5263 | + char_u buf[NUMBUFLEN]; | |
5227 | 5264 | |
5228 | 5265 | /* |
5229 | 5266 | * First check if it's not a curly-braces thing: {expr}. |
@@ -5246,54 +5283,51 @@ | ||
5246 | 5283 | if (d == NULL) |
5247 | 5284 | return FAIL; |
5248 | 5285 | } |
5286 | + tvkey.v_type = VAR_UNKNOWN; | |
5287 | + tv.v_type = VAR_UNKNOWN; | |
5249 | 5288 | |
5250 | 5289 | *arg = skipwhite(*arg + 1); |
5251 | 5290 | while (**arg != '}' && **arg != NUL) |
5252 | 5291 | { |
5253 | - if (eval1(arg, &tv, evaluate) == FAIL) /* recursive! */ | |
5292 | + if (eval1(arg, &tvkey, evaluate) == FAIL) /* recursive! */ | |
5254 | 5293 | goto failret; |
5255 | 5294 | if (**arg != ':') |
5256 | 5295 | { |
5257 | 5296 | EMSG2(_("E720: Missing colon in Dictionary: %s"), *arg); |
5258 | - clear_tv(&tv); | |
5297 | + clear_tv(&tvkey); | |
5259 | 5298 | goto failret; |
5260 | 5299 | } |
5261 | - key = get_tv_string(&tv); | |
5300 | + key = get_tv_string_buf(&tvkey, buf); | |
5262 | 5301 | if (*key == NUL) |
5263 | 5302 | { |
5264 | 5303 | EMSG(_(e_emptykey)); |
5265 | - clear_tv(&tv); | |
5304 | + clear_tv(&tvkey); | |
5266 | 5305 | goto failret; |
5267 | 5306 | } |
5268 | - key = vim_strsave(key); | |
5269 | - clear_tv(&tv); | |
5270 | - if (key == NULL) | |
5271 | - goto failret; | |
5272 | 5307 | |
5273 | 5308 | *arg = skipwhite(*arg + 1); |
5274 | 5309 | if (eval1(arg, &tv, evaluate) == FAIL) /* recursive! */ |
5275 | 5310 | { |
5276 | - vim_free(key); | |
5311 | + clear_tv(&tvkey); | |
5277 | 5312 | goto failret; |
5278 | 5313 | } |
5279 | 5314 | if (evaluate) |
5280 | 5315 | { |
5281 | - item = dict_find(d, key, -1, NULL); | |
5316 | + item = dict_find(d, key, -1); | |
5282 | 5317 | if (item != NULL) |
5283 | 5318 | { |
5284 | 5319 | EMSG(_("E721: Duplicate key in Dictionary")); |
5285 | - vim_free(key); | |
5320 | + clear_tv(&tvkey); | |
5286 | 5321 | clear_tv(&tv); |
5287 | 5322 | goto failret; |
5288 | 5323 | } |
5289 | - item = dictitem_alloc(); | |
5290 | - if (item == NULL) | |
5291 | - vim_free(key); | |
5292 | - else | |
5293 | - { | |
5294 | - item->di_key = key; | |
5324 | + item = dictitem_alloc(key); | |
5325 | + clear_tv(&tvkey); | |
5326 | + if (item != NULL) | |
5327 | + { | |
5295 | 5328 | item->di_tv = tv; |
5296 | - dict_add(d, item); | |
5329 | + if (dict_add(d, item) == FAIL) | |
5330 | + dictitem_free(item); | |
5297 | 5331 | } |
5298 | 5332 | } |
5299 | 5333 |
@@ -5994,7 +6028,8 @@ | ||
5994 | 6028 | call_user_func(fp, argcount, argvars, rettv, |
5995 | 6029 | firstline, lastline, |
5996 | 6030 | (fp->flags & FC_DICT) ? selfdict : NULL); |
5997 | - if (--fp->calls <= 0 && isdigit(*fp->name)) | |
6031 | + if (--fp->calls <= 0 && isdigit(*fp->name) | |
6032 | + && fp->refcount <= 0) | |
5998 | 6033 | /* Function was unreferenced while being used, free it |
5999 | 6034 | * now. */ |
6000 | 6035 | func_free(fp); |
@@ -6744,11 +6779,12 @@ | ||
6744 | 6779 | } |
6745 | 6780 | else if (argvars[0].v_type == VAR_DICT) |
6746 | 6781 | { |
6747 | - if (argvars[0].vval.v_dict != NULL) | |
6748 | - { | |
6749 | - dictitem *di; | |
6750 | - | |
6751 | - di = argvars[0].vval.v_dict->dv_first; | |
6782 | + int todo; | |
6783 | + dictvar *d; | |
6784 | + hashitem *hi; | |
6785 | + | |
6786 | + if ((d = argvars[0].vval.v_dict) != NULL) | |
6787 | + { | |
6752 | 6788 | if (argvars[2].v_type != VAR_UNKNOWN) |
6753 | 6789 | { |
6754 | 6790 | ic = get_tv_number(&argvars[2]); |
@@ -6756,9 +6792,16 @@ | ||
6756 | 6792 | EMSG(_(e_invarg)); |
6757 | 6793 | } |
6758 | 6794 | |
6759 | - for ( ; di != NULL; di = di->di_next) | |
6760 | - if (tv_equal(&di->di_tv, &argvars[1], ic)) | |
6761 | - ++n; | |
6795 | + todo = d->dv_hashtable.ht_used; | |
6796 | + for (hi = d->dv_hashtable.ht_array; todo > 0; ++hi) | |
6797 | + { | |
6798 | + if (!HASHITEM_EMPTY(hi)) | |
6799 | + { | |
6800 | + --todo; | |
6801 | + if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic)) | |
6802 | + ++n; | |
6803 | + } | |
6804 | + } | |
6762 | 6805 | } |
6763 | 6806 | } |
6764 | 6807 | else |
@@ -6972,7 +7015,7 @@ | ||
6972 | 7015 | break; |
6973 | 7016 | case VAR_DICT: |
6974 | 7017 | n = argvars[0].vval.v_dict == NULL |
6975 | - || argvars[0].vval.v_dict->dv_first == NULL; | |
7018 | + || argvars[0].vval.v_dict->dv_hashtable.ht_used == 0; | |
6976 | 7019 | break; |
6977 | 7020 | default: |
6978 | 7021 | EMSG2(_(e_intern2), "f_empty()"); |
@@ -7197,9 +7240,11 @@ | ||
7197 | 7240 | else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) |
7198 | 7241 | { |
7199 | 7242 | dictvar *d1, *d2; |
7200 | - dictitem *d1i, *d2i; | |
7243 | + dictitem *di1; | |
7201 | 7244 | char_u *action; |
7202 | 7245 | int i; |
7246 | + hashitem *hi2; | |
7247 | + int todo; | |
7203 | 7248 | |
7204 | 7249 | d1 = argvars[0].vval.v_dict; |
7205 | 7250 | d2 = argvars[1].vval.v_dict; |
@@ -7225,24 +7270,29 @@ | ||
7225 | 7270 | |
7226 | 7271 | /* Go over all entries in the second dict and add them to the |
7227 | 7272 | * first dict. */ |
7228 | - for (d2i = d2->dv_first; d2i != NULL; d2i = d2i->di_next) | |
7229 | - { | |
7230 | - d1i = dict_find(d1, d2i->di_key, -1, NULL); | |
7231 | - if (d1i == NULL) | |
7232 | - { | |
7233 | - d1i = dictitem_copy(d2i); | |
7234 | - if (d1i != NULL) | |
7235 | - dict_add(d1, d1i); | |
7236 | - } | |
7237 | - else if (*action == 'e') | |
7238 | - { | |
7239 | - EMSG2(_("Key already exists: %s"), d2i->di_key); | |
7240 | - break; | |
7241 | - } | |
7242 | - else if (*action == 'f') | |
7243 | - { | |
7244 | - clear_tv(&d1i->di_tv); | |
7245 | - copy_tv(&d2i->di_tv, &d1i->di_tv); | |
7273 | + todo = d2->dv_hashtable.ht_used; | |
7274 | + for (hi2 = d2->dv_hashtable.ht_array; todo > 0; ++hi2) | |
7275 | + { | |
7276 | + if (!HASHITEM_EMPTY(hi2)) | |
7277 | + { | |
7278 | + --todo; | |
7279 | + di1 = dict_find(d1, hi2->hi_key, -1); | |
7280 | + if (di1 == NULL) | |
7281 | + { | |
7282 | + di1 = dictitem_copy(HI2DI(hi2)); | |
7283 | + if (di1 != NULL && dict_add(d1, di1) == FAIL) | |
7284 | + dictitem_free(di1); | |
7285 | + } | |
7286 | + else if (*action == 'e') | |
7287 | + { | |
7288 | + EMSG2(_("E737: Key already exists: %s"), hi2->hi_key); | |
7289 | + break; | |
7290 | + } | |
7291 | + else if (*action == 'f') | |
7292 | + { | |
7293 | + clear_tv(&di1->di_tv); | |
7294 | + copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv); | |
7295 | + } | |
7246 | 7296 | } |
7247 | 7297 | } |
7248 | 7298 |
@@ -7378,11 +7428,13 @@ | ||
7378 | 7428 | char_u *expr; |
7379 | 7429 | listitem *li, *nli; |
7380 | 7430 | listvar *l = NULL; |
7381 | - dictitem *di, **pdi; | |
7431 | + dictitem *di; | |
7432 | + hashitem *hi; | |
7382 | 7433 | dictvar *d = NULL; |
7383 | 7434 | typeval save_val; |
7384 | 7435 | typeval save_key; |
7385 | 7436 | int rem; |
7437 | + int todo; | |
7386 | 7438 | |
7387 | 7439 | rettv->vval.v_number = 0; |
7388 | 7440 | if (argvars[0].v_type == VAR_LIST) |
@@ -7408,21 +7460,23 @@ | ||
7408 | 7460 | { |
7409 | 7461 | save_key = vimvars[VV_KEY].tv; |
7410 | 7462 | vimvars[VV_KEY].tv.v_type = VAR_STRING; |
7411 | - pdi = &d->dv_first; | |
7412 | - for (di = d->dv_first; di != NULL; di = *pdi) | |
7413 | - { | |
7414 | - vimvars[VV_KEY].tv.vval.v_string = vim_strsave(di->di_key); | |
7415 | - if (filter_map_one(&di->di_tv, expr, map, &rem) == FAIL) | |
7416 | - break; | |
7417 | - if (!map && rem) | |
7418 | - { | |
7419 | - *pdi = di->di_next; | |
7420 | - dictitem_free(di); | |
7421 | - } | |
7422 | - else | |
7423 | - pdi = &di->di_next; | |
7424 | - clear_tv(&vimvars[VV_KEY].tv); | |
7425 | - } | |
7463 | + | |
7464 | + todo = d->dv_hashtable.ht_used; | |
7465 | + for (hi = d->dv_hashtable.ht_array; todo > 0; ++hi) | |
7466 | + { | |
7467 | + if (!HASHITEM_EMPTY(hi)) | |
7468 | + { | |
7469 | + --todo; | |
7470 | + di = HI2DI(hi); | |
7471 | + vimvars[VV_KEY].tv.vval.v_string = vim_strsave(di->di_key); | |
7472 | + if (filter_map_one(&di->di_tv, expr, map, &rem) == FAIL) | |
7473 | + break; | |
7474 | + if (!map && rem) | |
7475 | + dictitem_remove(d, di); | |
7476 | + clear_tv(&vimvars[VV_KEY].tv); | |
7477 | + } | |
7478 | + } | |
7479 | + | |
7426 | 7480 | clear_tv(&vimvars[VV_KEY].tv); |
7427 | 7481 | vimvars[VV_KEY].tv = save_key; |
7428 | 7482 | } |
@@ -7784,7 +7838,7 @@ | ||
7784 | 7838 | { |
7785 | 7839 | if ((d = argvars[0].vval.v_dict) != NULL) |
7786 | 7840 | { |
7787 | - di = dict_find(d, get_tv_string(&argvars[1]), -1, NULL); | |
7841 | + di = dict_find(d, get_tv_string(&argvars[1]), -1); | |
7788 | 7842 | if (di != NULL) |
7789 | 7843 | tv = &di->di_tv; |
7790 | 7844 | } |
@@ -8917,7 +8971,7 @@ | ||
8917 | 8971 | return; |
8918 | 8972 | |
8919 | 8973 | rettv->vval.v_number = dict_find(argvars[0].vval.v_dict, |
8920 | - get_tv_string(&argvars[1]), -1, NULL) != NULL; | |
8974 | + get_tv_string(&argvars[1]), -1) != NULL; | |
8921 | 8975 | } |
8922 | 8976 | |
8923 | 8977 | /* |
@@ -9412,8 +9466,11 @@ | ||
9412 | 9466 | listvar *l; |
9413 | 9467 | listvar *l2; |
9414 | 9468 | dictitem *di; |
9469 | + hashitem *hi; | |
9415 | 9470 | listitem *li; |
9416 | 9471 | listitem *li2; |
9472 | + dictvar *d; | |
9473 | + int todo; | |
9417 | 9474 | |
9418 | 9475 | rettv->vval.v_number = 0; |
9419 | 9476 | if (argvars[0].v_type != VAR_DICT) |
@@ -9421,7 +9478,7 @@ | ||
9421 | 9478 | EMSG(_(e_dictreq)); |
9422 | 9479 | return; |
9423 | 9480 | } |
9424 | - if (argvars[0].vval.v_dict == NULL) | |
9481 | + if ((d = argvars[0].vval.v_dict) == NULL) | |
9425 | 9482 | return; |
9426 | 9483 | |
9427 | 9484 | l = list_alloc(); |
@@ -9431,46 +9488,53 @@ | ||
9431 | 9488 | rettv->vval.v_list = l; |
9432 | 9489 | ++l->lv_refcount; |
9433 | 9490 | |
9434 | - for (di = argvars[0].vval.v_dict->dv_first; di != NULL; di = di->di_next) | |
9435 | - { | |
9436 | - li = listitem_alloc(); | |
9437 | - if (li == NULL) | |
9438 | - break; | |
9439 | - list_append(l, li); | |
9440 | - | |
9441 | - if (what == 0) | |
9442 | - { | |
9443 | - /* keys() */ | |
9444 | - li->li_tv.v_type = VAR_STRING; | |
9445 | - li->li_tv.vval.v_string = vim_strsave(di->di_key); | |
9446 | - } | |
9447 | - else if (what == 1) | |
9448 | - { | |
9449 | - /* values() */ | |
9450 | - copy_tv(&di->di_tv, &li->li_tv); | |
9451 | - } | |
9452 | - else | |
9453 | - { | |
9454 | - /* items() */ | |
9455 | - l2 = list_alloc(); | |
9456 | - li->li_tv.v_type = VAR_LIST; | |
9457 | - li->li_tv.vval.v_list = l2; | |
9458 | - if (l2 == NULL) | |
9491 | + todo = d->dv_hashtable.ht_used; | |
9492 | + for (hi = d->dv_hashtable.ht_array; todo > 0; ++hi) | |
9493 | + { | |
9494 | + if (!HASHITEM_EMPTY(hi)) | |
9495 | + { | |
9496 | + --todo; | |
9497 | + di = HI2DI(hi); | |
9498 | + | |
9499 | + li = listitem_alloc(); | |
9500 | + if (li == NULL) | |
9459 | 9501 | break; |
9460 | - ++l2->lv_refcount; | |
9461 | - | |
9462 | - li2 = listitem_alloc(); | |
9463 | - if (li2 == NULL) | |
9464 | - break; | |
9465 | - list_append(l2, li2); | |
9466 | - li2->li_tv.v_type = VAR_STRING; | |
9467 | - li2->li_tv.vval.v_string = vim_strsave(di->di_key); | |
9468 | - | |
9469 | - li2 = listitem_alloc(); | |
9470 | - if (li2 == NULL) | |
9471 | - break; | |
9472 | - list_append(l2, li2); | |
9473 | - copy_tv(&di->di_tv, &li2->li_tv); | |
9502 | + list_append(l, li); | |
9503 | + | |
9504 | + if (what == 0) | |
9505 | + { | |
9506 | + /* keys() */ | |
9507 | + li->li_tv.v_type = VAR_STRING; | |
9508 | + li->li_tv.vval.v_string = vim_strsave(di->di_key); | |
9509 | + } | |
9510 | + else if (what == 1) | |
9511 | + { | |
9512 | + /* values() */ | |
9513 | + copy_tv(&di->di_tv, &li->li_tv); | |
9514 | + } | |
9515 | + else | |
9516 | + { | |
9517 | + /* items() */ | |
9518 | + l2 = list_alloc(); | |
9519 | + li->li_tv.v_type = VAR_LIST; | |
9520 | + li->li_tv.vval.v_list = l2; | |
9521 | + if (l2 == NULL) | |
9522 | + break; | |
9523 | + ++l2->lv_refcount; | |
9524 | + | |
9525 | + li2 = listitem_alloc(); | |
9526 | + if (li2 == NULL) | |
9527 | + break; | |
9528 | + list_append(l2, li2); | |
9529 | + li2->li_tv.v_type = VAR_STRING; | |
9530 | + li2->li_tv.vval.v_string = vim_strsave(di->di_key); | |
9531 | + | |
9532 | + li2 = listitem_alloc(); | |
9533 | + if (li2 == NULL) | |
9534 | + break; | |
9535 | + list_append(l2, li2); | |
9536 | + copy_tv(&di->di_tv, &li2->li_tv); | |
9537 | + } | |
9474 | 9538 | } |
9475 | 9539 | } |
9476 | 9540 | } |
@@ -10023,22 +10087,26 @@ | ||
10023 | 10087 | else if (argvars[0].v_type == VAR_DICT) |
10024 | 10088 | { |
10025 | 10089 | dictvar *d; |
10026 | - dictitem *di; | |
10090 | + int first = TRUE; | |
10091 | + hashitem *hi; | |
10092 | + int todo; | |
10027 | 10093 | |
10028 | 10094 | d = argvars[0].vval.v_dict; |
10029 | 10095 | if (d != NULL) |
10030 | 10096 | { |
10031 | - di = d->dv_first; | |
10032 | - if (di != NULL) | |
10033 | - { | |
10034 | - n = get_tv_number(&di->di_tv); | |
10035 | - while (1) | |
10036 | - { | |
10037 | - di = di->di_next; | |
10038 | - if (di == NULL) | |
10039 | - break; | |
10040 | - i = get_tv_number(&di->di_tv); | |
10041 | - if (domax ? i > n : i < n) | |
10097 | + todo = d->dv_hashtable.ht_used; | |
10098 | + for (hi = d->dv_hashtable.ht_array; todo > 0; ++hi) | |
10099 | + { | |
10100 | + if (!HASHITEM_EMPTY(hi)) | |
10101 | + { | |
10102 | + --todo; | |
10103 | + i = get_tv_number(&HI2DI(hi)->di_tv); | |
10104 | + if (first) | |
10105 | + { | |
10106 | + n = i; | |
10107 | + first = FALSE; | |
10108 | + } | |
10109 | + else if (domax ? i > n : i < n) | |
10042 | 10110 | n = i; |
10043 | 10111 | } |
10044 | 10112 | } |
@@ -10472,7 +10540,7 @@ | ||
10472 | 10540 | long end; |
10473 | 10541 | char_u *key; |
10474 | 10542 | dictvar *d; |
10475 | - dictitem *di, **pdi; | |
10543 | + dictitem *di; | |
10476 | 10544 | |
10477 | 10545 | rettv->vval.v_number = 0; |
10478 | 10546 | if (argvars[0].v_type == VAR_DICT) |
@@ -10482,18 +10550,15 @@ | ||
10482 | 10550 | else if ((d = argvars[0].vval.v_dict) != NULL) |
10483 | 10551 | { |
10484 | 10552 | key = get_tv_string(&argvars[1]); |
10485 | - pdi = &d->dv_first; | |
10486 | - for (di = d->dv_first; di != NULL; pdi = &di->di_next, di = *pdi) | |
10487 | - if (STRCMP(di->di_key, key) == 0) | |
10488 | - { | |
10489 | - *pdi = di->di_next; | |
10490 | - *rettv = di->di_tv; | |
10491 | - init_tv(&di->di_tv); | |
10492 | - dictitem_free(di); | |
10493 | - break; | |
10494 | - } | |
10553 | + di = dict_find(d, key, -1); | |
10495 | 10554 | if (di == NULL) |
10496 | 10555 | EMSG2(_(e_dictkey), key); |
10556 | + else | |
10557 | + { | |
10558 | + *rettv = di->di_tv; | |
10559 | + init_tv(&di->di_tv); | |
10560 | + dictitem_remove(d, di); | |
10561 | + } | |
10497 | 10562 | } |
10498 | 10563 | } |
10499 | 10564 | else if (argvars[0].v_type != VAR_LIST) |
@@ -13134,9 +13199,11 @@ | ||
13134 | 13199 | break; |
13135 | 13200 | case VAR_LIST: |
13136 | 13201 | list_unref(varp->vval.v_list); |
13202 | + varp->vval.v_list = NULL; | |
13137 | 13203 | break; |
13138 | 13204 | case VAR_DICT: |
13139 | 13205 | dict_unref(varp->vval.v_dict); |
13206 | + varp->vval.v_dict = NULL; | |
13140 | 13207 | break; |
13141 | 13208 | case VAR_NUMBER: |
13142 | 13209 | varp->vval.v_number = 0; |
@@ -14003,6 +14070,8 @@ | ||
14003 | 14070 | */ |
14004 | 14071 | if (!aborting()) |
14005 | 14072 | { |
14073 | + if (!eap->skip && fudi.fd_newkey != NULL) | |
14074 | + EMSG2(_(e_dictkey), fudi.fd_newkey); | |
14006 | 14075 | vim_free(fudi.fd_newkey); |
14007 | 14076 | return; |
14008 | 14077 | } |
@@ -14348,15 +14417,17 @@ | ||
14348 | 14417 | if (fudi.fd_di == NULL) |
14349 | 14418 | { |
14350 | 14419 | /* add new dict entry */ |
14351 | - fudi.fd_di = dictitem_alloc(); | |
14420 | + fudi.fd_di = dictitem_alloc(fudi.fd_newkey); | |
14352 | 14421 | if (fudi.fd_di == NULL) |
14353 | 14422 | { |
14354 | 14423 | vim_free(fp); |
14355 | 14424 | goto erret; |
14356 | 14425 | } |
14357 | - fudi.fd_di->di_key = fudi.fd_newkey; | |
14358 | - fudi.fd_newkey = NULL; | |
14359 | - dict_add(fudi.fd_dict, fudi.fd_di); | |
14426 | + if (dict_add(fudi.fd_dict, fudi.fd_di) == FAIL) | |
14427 | + { | |
14428 | + vim_free(fudi.fd_di); | |
14429 | + goto erret; | |
14430 | + } | |
14360 | 14431 | } |
14361 | 14432 | else |
14362 | 14433 | /* overwrite existing dict entry */ |
@@ -14454,7 +14525,6 @@ | ||
14454 | 14525 | fdp->fd_newkey = lv.ll_newkey; |
14455 | 14526 | lv.ll_newkey = NULL; |
14456 | 14527 | fdp->fd_di = lv.ll_di; |
14457 | - fdp->fd_pdi = lv.ll_pdi; | |
14458 | 14528 | } |
14459 | 14529 | if (lv.ll_tv->v_type == VAR_FUNC && lv.ll_tv->vval.v_string != NULL) |
14460 | 14530 | { |
@@ -14463,8 +14533,8 @@ | ||
14463 | 14533 | } |
14464 | 14534 | else |
14465 | 14535 | { |
14466 | - if (!skip && !(flags & TFN_QUIET) | |
14467 | - && (fdp == NULL || lv.ll_dict == NULL)) | |
14536 | + if (!skip && !(flags & TFN_QUIET) && (fdp == NULL | |
14537 | + || lv.ll_dict == NULL || fdp->fd_newkey == NULL)) | |
14468 | 14538 | EMSG(_(e_funcref)); |
14469 | 14539 | else |
14470 | 14540 | *pp = end; |
@@ -14743,8 +14813,7 @@ | ||
14743 | 14813 | { |
14744 | 14814 | /* Delete the dict item that refers to the function, it will |
14745 | 14815 | * invoke func_unref() and possibly delete the function. */ |
14746 | - *fudi.fd_pdi = fudi.fd_di->di_next; | |
14747 | - dictitem_free(fudi.fd_di); | |
14816 | + dictitem_remove(fudi.fd_dict, fudi.fd_di); | |
14748 | 14817 | } |
14749 | 14818 | else |
14750 | 14819 | func_free(fp); |
@@ -4,7 +4,7 @@ | ||
4 | 4 | # Authors: Zoltan Arpadffy, <arpadffy@polarhome.com> |
5 | 5 | # Sandor Kopanyi, <sandor.kopanyi@mailbox.hu> |
6 | 6 | # |
7 | -# Last change: 2004 Dec 24 | |
7 | +# Last change: 2005 Jan 19 | |
8 | 8 | # |
9 | 9 | # This has been tested on VMS 6.2 to 7.2 on DEC Alpha and VAX. |
10 | 10 | # Edit the lines in the Configuration section below to select. |
@@ -57,7 +57,7 @@ | ||
57 | 57 | test33.out test34.out test35.out test36.out test37.out \ |
58 | 58 | test38.out test39.out test40.out test41.out test42.out \ |
59 | 59 | test43.out test44.out test45.out test46.out \ |
60 | - test48.out test51.out test53.out test54.out | |
60 | + test48.out test51.out test53.out test54.out test55.out | |
61 | 61 | |
62 | 62 | .IFDEF WANT_GUI |
63 | 63 | SCRIPT_GUI = test16.out |