]> granicus.if.org Git - vim/commitdiff
updated for version 7.0042 v7.0042
authorBram Moolenaar <Bram@vim.org>
Wed, 19 Jan 2005 22:24:34 +0000 (22:24 +0000)
committerBram Moolenaar <Bram@vim.org>
Wed, 19 Jan 2005 22:24:34 +0000 (22:24 +0000)
runtime/doc/todo.txt
src/Make_djg.mak
src/Make_manx.mak
src/Make_morph.mak
src/eval.c
src/testdir/Make_vms.mms

index ad76e6cec2271220d5de2f89ac65ebc42a43b25d..70a783d6793cc4a4c44bfb0780a32bbb82c05b00 100644 (file)
@@ -1,4 +1,4 @@
-*todo.txt*      For Vim version 7.0aa.  Last change: 2005 Jan 17
+*todo.txt*      For Vim version 7.0aa.  Last change: 2005 Jan 19
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -30,6 +30,12 @@ be worked on, but only if you sponsor Vim development.  See |sponsor|.
                                                        *known-bugs*
 -------------------- Known bugs and current work -----------------------
 
+Hashtable implementation:
+- Use hashtable for variables and syntax keywords.
+
+":grep": display progress (filename, every second or so)
+Can ":grep" made faster somehow?  Do profiling.
+
 Sanity check of eval.c:
 - Go through the code for magic braces.
 
@@ -104,6 +110,7 @@ PLANNED FOR VERSION 7.0:
 -   REFACTORING: The main() function is very long.  Move parts to separate
     functions, especially loops.  Ideas from Walter Briscoe (2003 Apr 3, 2004
     Feb 9).
+    Move the printing stuff to hardcopy.c.
 -   Improve the interface between the generic GUI code and the system-specific
     code.  Generic code handles text window with scrollbars, system-specific
     code menu, toolbar, etc.
@@ -1576,7 +1583,6 @@ Built-in script language:
 7   Add argument to winwidth() to subtract the space taken by 'foldcolumn',
     signs and/or 'number'.
 8   Add functions:
-       search()                Add optional offset argument.
        realname()              Get user name (first, last, full)
                                user_fullname() patch by Nikolai Weibull, Nov
                                3 2002
@@ -2417,6 +2423,8 @@ Java:
     like it's done when there is no code.  And there is no automatic wrapping.
     Recognize comments that come after code.  Should insert the comment leader
     when it's "#" or "//".
+    Other way around: when a C command starts with "* 4" the "*" is repeated
+    while it should not.  Use syntax HL comment recognition?
 7   When using "comments=fg:--", Vim inserts three spaces for a new line.
     When hitting a TAB, these spaces could be removed.
 7   The 'n'esting flag doesn't do the indenting of the last (rightmost) item.
@@ -3236,11 +3244,11 @@ Various improvements:
 8   findmatchlimit() should be able to skip comments.  Solves problem of
     matching the '{' in /* if (foo) { */ (Fiveash)
 -   Add more redirecting of Ex commands:
-       :redir @> register  (append)
-       :redir #  bufname
-       :redir #> bufname   (append)
-       :redir =  variable
-       :redir => variable  (append)
+       :redir @r> register  (append)
+       :redir #>  bufname
+       :redir #>> bufname   (append)
+       :redir =>  variable
+       :redir =>> variable  (append)
 -   Setting of options, specifically for a buffer or window, with
     ":set window.option" or ":set buffer.option=val".  Or use ":buffer.set".
     Also: "buffer.map <F1> quit".
index 02c42b878b64816cd8ca9eba0e821653360866a6..87b799b6c8fc70da21278128e89e2b50a4235243 100644 (file)
@@ -33,6 +33,7 @@ OBJ = \
        obj/fileio.o \
        obj/fold.o \
        obj/getchar.o \
+       obj/hashtable.o \
        obj/main.o \
        obj/mark.o \
        obj/memfile.o \
index b7c06e98605342c9bd4d0c4ce001c26ceaedd5d9..bef1c0b68343c2e60abf766e4d8fae101940ea68 100644 (file)
@@ -48,6 +48,7 @@ SRC = buffer.c \
        fileio.c \
        fold.c \
        getchar.c \
+       hashtable.c \
        main.c \
        mark.c \
        memfile.c \
@@ -90,6 +91,7 @@ OBJ = obj/buffer.o \
        obj/fileio.o \
        obj/fold.o \
        obj/getchar.o \
+       obj/hashtable.o \
        obj/main.o \
        obj/mark.o \
        obj/memfile.o \
@@ -130,6 +132,7 @@ PRO =       proto/buffer.pro \
        proto/fileio.pro \
        proto/fold.pro \
        proto/getchar.pro \
+       proto/hashtable.pro \
        proto/main.pro \
        proto/mark.pro \
        proto/memfile.pro \
@@ -243,6 +246,9 @@ obj/fold.o: fold.c
 obj/getchar.o: getchar.c
        $(CCSYM) $@ getchar.c
 
+obj/hashtable.o:       hashtable.c
+       $(CCSYM) $@ hashtable.c
+
 # Don't use $(SYMS) here, because main.c defines EXTERN
 obj/main.o:    main.c option.h globals.h
        $(CCNOSYM) $@ main.c
index ffcb81454e28b3463819a84a10e922ece40d7a2a..a51e0d457389bc721a4508cfeedf731d8ab83b75 100644 (file)
@@ -38,6 +38,7 @@ SRC = buffer.c                                                \
        fileio.c                                                \
        fold.c                                                  \
        getchar.c                                               \
+       hashtable.c                                             \
        main.c                                                  \
        mark.c                                                  \
        mbyte.c                                                 \
index f2ce3f3e63a1c5bb9448a72148e1a68260d496f9..ed1551e1dd731fe88dd2f9dea0eb056d903d18c9 100644 (file)
@@ -109,23 +109,35 @@ typedef struct listvar_S listvar;
 
 /*
  * Structure to hold an item of a Dictionary.
+ * The key is copied into "di_key" to avoid an extra alloc/free for it.
  */
 struct dictitem_S
 {
-    struct dictitem_S  *di_next;       /* next item in list */
-    char_u             *di_key;        /* key (never NULL!) */
     typeval            di_tv;          /* type and value of the variable */
+    char_u             di_key[1];      /* key (actually longer!) */
 };
 
 typedef struct dictitem_S dictitem;
 
+/*
+ * In a hashtable item "hi_key" points to "di_key" in a dictitem.
+ * This avoids adding a pointer to the hashtable 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 dumdi;
+#define DI2HIKEY(p) ((p)->di_key)
+#define HIKEY2DI(p) ((dictitem *)(p - (dumdi.di_key - (char_u *)&dumdi.di_tv)))
+#define HI2DI(p)    HIKEY2DI((p)->hi_key)
+
 /*
  * Structure to hold info about a Dictionary.
  */
 struct dictvar_S
 {
     int                dv_refcount;    /* reference count */
-    dictitem   *dv_first;      /* first item, NULL if none */
+    hashtable  dv_hashtable;   /* hashtable that refers to the items */
 };
 
 typedef struct dictvar_S dictvar;
@@ -173,7 +185,6 @@ typedef struct lval_S
     dictvar    *ll_dict;       /* The Dictionary or NULL */
     dictitem   *ll_di;         /* The dictitem or NULL */
     char_u     *ll_newkey;     /* New key for Dict in alloc. mem or NULL. */
-    dictitem   **ll_pdi;       /* di_next field pointing to found dictitem */
 } lval;
 
 
@@ -181,10 +192,9 @@ static char *e_letunexp    = N_("E18: Unexpected characters in :let");
 static char *e_listidx = N_("E684: list index out of range: %ld");
 static char *e_undefvar = N_("E121: Undefined variable: %s");
 static char *e_missbrac = N_("E111: Missing ']'");
-static char *e_intern2 = N_("E685: Internal error: %s");
 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 Dictionaary");
-static char *e_emptykey = N_("E713: Empty key in Dictionary");
+static char *e_emptykey = N_("E713: Cannot use empty key for Dictionary");
 static char *e_listreq = N_("E714: List required");
 static char *e_dictreq = N_("E715: Dictionary required");
 static char *e_toomanyarg = N_("E118: Too many arguments for function: %s");
@@ -289,7 +299,6 @@ typedef struct
     dictvar    *fd_dict;       /* Dictionary used */
     char_u     *fd_newkey;     /* new key in "dict" */
     dictitem   *fd_di;         /* Dictionary item used */
-    dictitem   **fd_pdi;       /* field that points to "fd_di" */
 } funcdict;
 
 /*
@@ -451,12 +460,13 @@ static void list_join __ARGS((garray_T *gap, listvar *l, char_u *sep, int echo))
 static dictvar *dict_alloc __ARGS((void));
 static void dict_unref __ARGS((dictvar *d));
 static void dict_free __ARGS((dictvar *d));
-static dictitem *dictitem_alloc __ARGS((void));
+static dictitem *dictitem_alloc __ARGS((char_u *key));
 static dictitem *dictitem_copy __ARGS((dictitem *org));
+static void dictitem_remove __ARGS((dictvar *dict, dictitem *item));
 static void dictitem_free __ARGS((dictitem *item));
-static void dict_add __ARGS((dictvar *d, dictitem *item));
+static int dict_add __ARGS((dictvar *d, dictitem *item));
 static long dict_len __ARGS((dictvar *d));
-static dictitem *dict_find __ARGS((dictvar *d, char_u *key, int len, dictitem ***pdi));
+static dictitem *dict_find __ARGS((dictvar *d, char_u *key, int len));
 static char_u *dict2string __ARGS((typeval *tv));
 static int get_dict_tv __ARGS((char_u **arg, typeval *rettv, int evaluate));
 
@@ -1829,8 +1839,7 @@ get_lval(name, rettv, lp, unlet, skip, quiet)
             * aborting error, an interrupt, or an exception. */
            if (!aborting() && !quiet)
            {
-               if (unlet)
-                   emsg_severe = TRUE;
+               emsg_severe = TRUE;
                EMSG2(_(e_invarg2), name);
                return NULL;
            }
@@ -1970,10 +1979,10 @@ get_lval(name, rettv, lp, unlet, skip, quiet)
            }
            lp->ll_list = NULL;
            lp->ll_dict = lp->ll_tv->vval.v_dict;
-           lp->ll_di = dict_find(lp->ll_dict, key, len, &lp->ll_pdi);
+           lp->ll_di = dict_find(lp->ll_dict, key, len);
            if (lp->ll_di == NULL)
            {
-               /* Key does not exist in dict: may need toadd it. */
+               /* Key does not exist in dict: may need to add it. */
                if (*p == '[' || *p == '.' || unlet)
                {
                    if (!quiet)
@@ -2165,12 +2174,14 @@ set_var_lval(lp, endp, rettv, copy, op)
            }
 
            /* Need to add an item to the Dictionary. */
-           di = dictitem_alloc();
+           di = dictitem_alloc(lp->ll_newkey);
            if (di == NULL)
                return;
-           di->di_key = lp->ll_newkey;
-           lp->ll_newkey = NULL;
-           dict_add(lp->ll_tv->vval.v_dict, di);
+           if (dict_add(lp->ll_tv->vval.v_dict, di) == FAIL)
+           {
+               vim_free(di);
+               return;
+           }
            lp->ll_tv = &di->di_tv;
        }
        else if (op != NULL && *op != '=')
@@ -2532,11 +2543,18 @@ ex_call(eap)
     linenr_T   lnum;
     int                doesrange;
     int                failed = FALSE;
+    funcdict   fudi;
 
-    tofree = trans_function_name(&arg, eap->skip, TFN_INT, NULL);
+    tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi);
+    vim_free(fudi.fd_newkey);
     if (tofree == NULL)
        return;
 
+    /* Increase refcount on dictionary, it could get deleted when evaluating
+     * the arguments. */
+    if (fudi.fd_dict != NULL)
+       ++fudi.fd_dict->dv_refcount;
+
     /* If it is the name of a variable of type VAR_FUNC use its contents. */
     len = STRLEN(tofree);
     name = deref_func_name(tofree, &len);
@@ -2572,7 +2590,8 @@ ex_call(eap)
        }
        arg = startarg;
        if (get_func_tv(name, STRLEN(name), &rettv, &arg,
-               eap->line1, eap->line2, &doesrange, !eap->skip, NULL) == FAIL)
+                   eap->line1, eap->line2, &doesrange,
+                                           !eap->skip, fudi.fd_dict) == FAIL)
        {
            failed = TRUE;
            break;
@@ -2603,6 +2622,7 @@ ex_call(eap)
     }
 
 end:
+    dict_unref(fudi.fd_dict);
     vim_free(tofree);
 }
 
@@ -2691,18 +2711,12 @@ do_unlet_var(lp, name_end, forceit)
     }
     else
     {
-       clear_tv(lp->ll_tv);
        if (lp->ll_list != NULL)
-       {
            /* unlet a List item. */
            listitem_remove(lp->ll_list, lp->ll_li);
-       }
        else
-       {
            /* unlet a Dictionary item. */
-           *lp->ll_pdi = lp->ll_di->di_next;
-           dictitem_free(lp->ll_di);
-       }
+           dictitem_remove(lp->ll_dict, lp->ll_di);
     }
 
     return ret;
@@ -3761,7 +3775,7 @@ eval7(arg, rettv, evaluate)
     /*
      * Handle expr[expr], expr[expr:expr] subscript and .name lookup.
      * Also handle function call with Funcref variable: func(expr)
-     * Can all be combined: dict.func(expr)[idx].func(expr)
+     * Can all be combined: dict.func(expr)[idx]['func'](expr)
      */
     selfdict = NULL;
     while (ret == OK
@@ -3779,21 +3793,27 @@ eval7(arg, rettv, evaluate)
                    curwin->w_cursor.lnum, curwin->w_cursor.lnum,
                    &len, evaluate, selfdict);
 
-           /* Stop the expression evaluation when immediately
-            * aborting on error, or when an interrupt occurred or
-            * an exception was thrown but not caught. */
+           /* Stop the expression evaluation when immediately aborting on
+            * error, or when an interrupt occurred or an exception was thrown
+            * but not caught. */
            if (aborting())
            {
                if (ret == OK)
                    clear_tv(rettv);
                ret = FAIL;
            }
+           dict_unref(selfdict);
            selfdict = NULL;
        }
-       else
+       else /* **arg == '[' || **arg == '.' */
        {
+           dict_unref(selfdict);
            if (rettv->v_type == VAR_DICT)
+           {
                selfdict = rettv->vval.v_dict;
+               if (selfdict != NULL)
+                   ++selfdict->dv_refcount;
+           }
            else
                selfdict = NULL;
            if (eval_index(arg, rettv, evaluate) == FAIL)
@@ -3803,6 +3823,7 @@ eval7(arg, rettv, evaluate)
            }
        }
     }
+    dict_unref(selfdict);
 
     /*
      * Apply logical NOT and unary '-', from right to left, ignore '+'.
@@ -4033,7 +4054,7 @@ eval_index(arg, rettv, evaluate)
                        }
                    }
 
-                   item = dict_find(rettv->vval.v_dict, key, (int)len, NULL);
+                   item = dict_find(rettv->vval.v_dict, key, (int)len);
 
                    if (item == NULL)
                        EMSG2(_(e_dictkey), key);
@@ -4371,6 +4392,8 @@ get_list_tv(arg, rettv, evaluate)
                item->li_tv = tv;
                list_append(l, item);
            }
+           else
+               clear_tv(&tv);
        }
 
        if (**arg == ']')
@@ -4523,18 +4546,25 @@ dict_equal(d1, d2, ic)
     dictvar    *d2;
     int                ic;     /* ignore case for strings */
 {
-    dictitem   *item1, *item2;
+    hashitem   *hi;
+    dictitem   *item2;
+    int                todo;
 
     if (dict_len(d1) != dict_len(d2))
        return FALSE;
 
-    for (item1 = d1->dv_first; item1 != NULL; item1 = item1->di_next)
+    todo = d1->dv_hashtable.ht_used;
+    for (hi = d1->dv_hashtable.ht_array; todo > 0; ++hi)
     {
-       item2 = dict_find(d2, item1->di_key, -1, NULL);
-       if (item2 == NULL)
-           return FALSE;
-       if (!tv_equal(&item1->di_tv, &item2->di_tv, ic))
-           return FALSE;
+       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))
+               return FALSE;
+           --todo;
+       }
     }
     return TRUE;
 }
@@ -4558,6 +4588,13 @@ tv_equal(tv1, tv2, ic)
                   || !list_equal(tv1->vval.v_list, tv2->vval.v_list, ic))
            return FALSE;
     }
+    else if (tv1->v_type == VAR_DICT || tv2->v_type == VAR_DICT)
+    {
+       /* recursive! */
+       if (tv1->v_type != tv2->v_type
+                  || !dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic))
+           return FALSE;
+    }
     else if (tv1->v_type == VAR_FUNC || tv2->v_type == VAR_FUNC)
     {
        if (tv1->v_type != tv2->v_type
@@ -4931,7 +4968,12 @@ list_join(gap, l, sep, echo)
     static dictvar *
 dict_alloc()
 {
-    return (dictvar *)alloc_clear(sizeof(dictvar));
+    dictvar *d;
+
+    d = (dictvar *)alloc(sizeof(dictvar));
+    if (d != NULL)
+       hash_init(&d->dv_hashtable);
+    return d;
 }
 
 /*
@@ -4954,24 +4996,39 @@ dict_unref(d)
 dict_free(d)
     dictvar *d;
 {
-    dictitem *item;
-    dictitem *next;
+    int                todo;
+    hashitem   *hi;
 
-    for (item = d->dv_first; item != NULL; item = next)
+    /* Careful: we free the dictitems while they still appear in the
+     * hashtable.  Must not try to resize the hashtable! */
+    todo = d->dv_hashtable.ht_used;
+    for (hi = d->dv_hashtable.ht_array; todo > 0; ++hi)
     {
-       next = item->di_next;
-       dictitem_free(item);
+       if (!HASHITEM_EMPTY(hi))
+       {
+           dictitem_free(HI2DI(hi));
+           --todo;
+       }
     }
     vim_free(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.
  */
     static dictitem *
-dictitem_alloc()
+dictitem_alloc(key)
+    char_u     *key;
 {
-    return (dictitem *)alloc(sizeof(dictitem));
+    dictitem *di;
+
+    di = (dictitem *)alloc(sizeof(dictitem) + STRLEN(key));
+    if (di != NULL)
+       STRCPY(di->di_key, key);
+    return di;
 }
 
 /*
@@ -4983,20 +5040,33 @@ dictitem_copy(org)
 {
     dictitem *di;
 
-    di = (dictitem *)alloc(sizeof(dictitem));
+    di = (dictitem *)alloc(sizeof(dictitem) + STRLEN(org->di_key));
     if (di != NULL)
     {
-       di->di_key = vim_strsave(org->di_key);
-       if (di->di_key == NULL)
-       {
-           vim_free(di);
-           return NULL;
-       }
+       STRCPY(di->di_key, org->di_key);
        copy_tv(&org->di_tv, &di->di_tv);
     }
     return di;
 }
 
+/*
+ * Remove item "item" from Dictionary "dict" and free it.
+ */
+    static void
+dictitem_remove(dict, item)
+    dictvar    *dict;
+    dictitem   *item;
+{
+    hashitem   *hi;
+
+    hi = hash_find(&dict->dv_hashtable, item->di_key);
+    if (HASHITEM_EMPTY(hi))
+       EMSG2(_(e_intern2), "dictitem_remove()");
+    else
+       hash_remove(&dict->dv_hashtable, hi);
+    dictitem_free(item);
+}
+
 /*
  * Free a dict item.  Also clears the value.
  */
@@ -5004,7 +5074,6 @@ dictitem_copy(org)
 dictitem_free(item)
     dictitem *item;
 {
-    vim_free(item->di_key);
     clear_tv(&item->di_tv);
     vim_free(item);
 }
@@ -5020,8 +5089,9 @@ dict_copy(orig, deep)
     int                deep;
 {
     dictvar    *copy;
-    dictitem   *item;
     dictitem   *di;
+    int                todo;
+    hashitem   *hi;
 
     if (orig == NULL)
        return NULL;
@@ -5029,23 +5099,28 @@ dict_copy(orig, deep)
     copy = dict_alloc();
     if (copy != NULL)
     {
-       for (item = orig->dv_first; item != NULL; item = item->di_next)
+       todo = orig->dv_hashtable.ht_used;
+       for (hi = orig->dv_hashtable.ht_array; todo > 0; ++hi)
        {
-           di = dictitem_alloc();
-           if (di == NULL)
-               break;
-           di->di_key = vim_strsave(item->di_key);
-           if (di->di_key == NULL)
+           if (!HASHITEM_EMPTY(hi))
            {
-               vim_free(di);
-               break;
+               --todo;
+
+               di = dictitem_alloc(hi->hi_key);
+               if (di == NULL)
+                   break;
+               if (deep)
+                   item_copy(&HI2DI(hi)->di_tv, &di->di_tv, deep);
+               else
+                   copy_tv(&HI2DI(hi)->di_tv, &di->di_tv);
+               if (dict_add(copy, di) == FAIL)
+               {
+                   dictitem_free(di);
+                   break;
+               }
            }
-           if (deep)
-               item_copy(&item->di_tv, &di->di_tv, deep);
-           else
-               copy_tv(&item->di_tv, &di->di_tv);
-           dict_add(copy, di);
        }
+
        ++copy->dv_refcount;
     }
 
@@ -5054,69 +5129,15 @@ dict_copy(orig, deep)
 
 /*
  * Add item "item" to Dictionary "d".
+ * Returns FAIL when out of memory and when key already existed.
  */
-    static void
+    static int
 dict_add(d, item)
     dictvar    *d;
     dictitem   *item;
 {
-    item->di_next = d->dv_first;
-    d->dv_first = item;
-}
-
-#if 0  /* not currently used */
-static void dict_set_item __ARGS((dictvar *d, int type, char *key, void *val));
-
-/*
- * Add an item to Dictionary "d" with type "type", key "key" and value "val".
- * If it already exists it is overwritten.
- * The key and value are copied to allocated memory.
- */
-    static void
-dict_set_item(d, type, key, val)
-    dictvar    *d;
-    int                type;
-    char       *key;
-    void       *val;
-{
-    dictitem   *di;
-    char_u     *dkey;
-
-    di = dict_find(d, (char_u *)key, -1, NULL);
-    if (di == NULL)
-    {
-       dkey = vim_strsave((char_u *)key);
-       if (dkey != NULL)
-       {
-           di = dictitem_alloc();
-           if (di == NULL)
-               vim_free(dkey);
-           else
-               di->di_key = dkey;
-       }
-    }
-    else
-       clear_tv(&di->di_tv);
-
-    if (di != NULL)
-    {
-       di->di_tv.v_type = type;
-       switch (type)
-       {
-           case VAR_NUMBER:
-               di->di_tv.vval.v_number = (varnumber_T)val;
-               break;
-           case VAR_FUNC:
-           case VAR_STRING:
-               di->di_tv.vval.v_string = vim_strsave((char_u *)val);
-               break;
-           default:
-               EMSG2(_(e_intern2), "dict_set_item()");
-       }
-       dict_add(d, di);
-    }
+    return hash_add(&d->dv_hashtable, item->di_key);
 }
-#endif
 
 /*
  * Get the number of items in a Dictionary.
@@ -5125,43 +5146,49 @@ dict_set_item(d, type, key, val)
 dict_len(d)
     dictvar    *d;
 {
-    dictitem   *item;
-    long       len = 0;
-
     if (d == NULL)
        return 0L;
-    for (item = d->dv_first; item != NULL; item = item->di_next)
-       ++len;
-    return len;
+    return d->dv_hashtable.ht_used;
 }
 
 /*
  * Find item "key[len]" in Dictionary "d".
  * If "len" is negative use strlen(key).
- * Sets "*pdi" to pointer to found item, unless "pdi" is NULL.
  * Returns NULL when not found.
  */
     static dictitem *
-dict_find(d, key, len, pdi)
+dict_find(d, key, len)
     dictvar    *d;
     char_u     *key;
     int                len;
-    dictitem   ***pdi;
 {
-    static dictitem *di;
+#define AKEYLEN 200
+    char_u     buf[AKEYLEN];
+    char_u     *akey;
+    char_u     *tofree = NULL;
+    hashitem   *hi;
 
-    if (pdi != NULL)
-       *pdi = &d->dv_first;
-    for (di = d->dv_first; di != NULL; di = di->di_next)
+    if (len < 0)
+       akey = key;
+    else if (len >= AKEYLEN)
     {
-       if (len < 0
-               ? STRCMP(di->di_key, key) == 0
-               : STRNCMP(di->di_key, key, len) == 0 && di->di_key[len] == NUL)
-           return di;
-       if (pdi != NULL)
-           *pdi = &di->di_next;
+       tofree = akey = vim_strnsave(key, len);
+       if (akey == NULL)
+           return NULL;
     }
-    return NULL;
+    else
+    {
+       /* Avoid a malloc/free by using buf[]. */
+       STRNCPY(buf, key, len);
+       buf[len] = NUL;
+       akey = buf;
+    }
+
+    hi = hash_find(&d->dv_hashtable, akey);
+    vim_free(tofree);
+    if (HASHITEM_EMPTY(hi))
+       return NULL;
+    return HI2DI(hi);
 }
 
 /*
@@ -5176,32 +5203,40 @@ dict2string(tv)
     int                first = TRUE;
     char_u     *tofree;
     char_u     numbuf[NUMBUFLEN];
-    dictitem   *item;
+    hashitem   *hi;
     char_u     *s;
+    dictvar    *d;
+    int                todo;
 
-    if (tv->vval.v_dict == NULL)
+    if ((d = tv->vval.v_dict) == NULL)
        return NULL;
     ga_init2(&ga, (int)sizeof(char), 80);
     ga_append(&ga, '{');
 
-    for (item = tv->vval.v_dict->dv_first; item != NULL; item = item->di_next)
+    todo = d->dv_hashtable.ht_used;
+    for (hi = d->dv_hashtable.ht_array; todo > 0; ++hi)
     {
-       if (first)
-           first = FALSE;
-       else
-           ga_concat(&ga, (char_u *)", ");
-
-       tofree = string_quote(item->di_key, FALSE);
-       if (tofree != NULL)
+       if (!HASHITEM_EMPTY(hi))
        {
-           ga_concat(&ga, tofree);
+           --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 = tv2string(&HI2DI(hi)->di_tv, &tofree, numbuf);
+           if (s != NULL)
+               ga_concat(&ga, s);
            vim_free(tofree);
        }
-       ga_concat(&ga, (char_u *)": ");
-       s = tv2string(&item->di_tv, &tofree, numbuf);
-       if (s != NULL)
-           ga_concat(&ga, s);
-       vim_free(tofree);
     }
 
     ga_append(&ga, '}');
@@ -5220,10 +5255,12 @@ get_dict_tv(arg, rettv, evaluate)
     int                evaluate;
 {
     dictvar    *d = NULL;
+    typeval    tvkey;
     typeval    tv;
     char_u     *key;
     dictitem   *item;
     char_u     *start = skipwhite(*arg + 1);
+    char_u     buf[NUMBUFLEN];
 
     /*
      * First check if it's not a curly-braces thing: {expr}.
@@ -5246,54 +5283,51 @@ get_dict_tv(arg, rettv, evaluate)
        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, &tv, evaluate) == FAIL)  /* recursive! */
+       if (eval1(arg, &tvkey, evaluate) == FAIL)       /* recursive! */
            goto failret;
        if (**arg != ':')
        {
            EMSG2(_("E720: Missing colon in Dictionary: %s"), *arg);
-           clear_tv(&tv);
+           clear_tv(&tvkey);
            goto failret;
        }
-       key = get_tv_string(&tv);
+       key = get_tv_string_buf(&tvkey, buf);
        if (*key == NUL)
        {
            EMSG(_(e_emptykey));
-           clear_tv(&tv);
+           clear_tv(&tvkey);
            goto failret;
        }
-       key = vim_strsave(key);
-       clear_tv(&tv);
-       if (key == NULL)
-           goto failret;
 
        *arg = skipwhite(*arg + 1);
        if (eval1(arg, &tv, evaluate) == FAIL)  /* recursive! */
        {
-           vim_free(key);
+           clear_tv(&tvkey);
            goto failret;
        }
        if (evaluate)
        {
-           item = dict_find(d, key, -1, NULL);
+           item = dict_find(d, key, -1);
            if (item != NULL)
            {
                EMSG(_("E721: Duplicate key in Dictionary"));
-               vim_free(key);
+               clear_tv(&tvkey);
                clear_tv(&tv);
                goto failret;
            }
-           item = dictitem_alloc();
-           if (item == NULL)
-               vim_free(key);
-           else
+           item = dictitem_alloc(key);
+           clear_tv(&tvkey);
+           if (item != NULL)
            {
-               item->di_key = key;
                item->di_tv = tv;
-               dict_add(d, item);
+               if (dict_add(d, item) == FAIL)
+                   dictitem_free(item);
            }
        }
 
@@ -5994,7 +6028,8 @@ call_func(name, len, rettv, argcount, argvars, firstline, lastline,
                    call_user_func(fp, argcount, argvars, rettv,
                                               firstline, lastline,
                                     (fp->flags & FC_DICT) ? selfdict : NULL);
-                   if (--fp->calls <= 0 && isdigit(*fp->name))
+                   if (--fp->calls <= 0 && isdigit(*fp->name)
+                                                        && fp->refcount <= 0)
                        /* Function was unreferenced while being used, free it
                         * now. */
                        func_free(fp);
@@ -6744,11 +6779,12 @@ f_count(argvars, rettv)
     }
     else if (argvars[0].v_type == VAR_DICT)
     {
-       if (argvars[0].vval.v_dict != NULL)
-       {
-           dictitem    *di;
+       int         todo;
+       dictvar     *d;
+       hashitem    *hi;
 
-           di = argvars[0].vval.v_dict->dv_first;
+       if ((d = argvars[0].vval.v_dict) != NULL)
+       {
            if (argvars[2].v_type != VAR_UNKNOWN)
            {
                ic = get_tv_number(&argvars[2]);
@@ -6756,9 +6792,16 @@ f_count(argvars, rettv)
                    EMSG(_(e_invarg));
            }
 
-           for ( ; di != NULL; di = di->di_next)
-               if (tv_equal(&di->di_tv, &argvars[1], ic))
-                   ++n;
+           todo = d->dv_hashtable.ht_used;
+           for (hi = d->dv_hashtable.ht_array; todo > 0; ++hi)
+           {
+               if (!HASHITEM_EMPTY(hi))
+               {
+                   --todo;
+                   if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic))
+                       ++n;
+               }
+           }
        }
     }
     else
@@ -6972,7 +7015,7 @@ f_empty(argvars, rettv)
            break;
        case VAR_DICT:
            n = argvars[0].vval.v_dict == NULL
-                                 || argvars[0].vval.v_dict->dv_first == NULL;
+                       || argvars[0].vval.v_dict->dv_hashtable.ht_used == 0;
            break;
        default:
            EMSG2(_(e_intern2), "f_empty()");
@@ -7197,9 +7240,11 @@ f_extend(argvars, rettv)
     else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
     {
        dictvar         *d1, *d2;
-       dictitem        *d1i, *d2i;
+       dictitem        *di1;
        char_u          *action;
        int             i;
+       hashitem        *hi2;
+       int             todo;
 
        d1 = argvars[0].vval.v_dict;
        d2 = argvars[1].vval.v_dict;
@@ -7225,24 +7270,29 @@ f_extend(argvars, rettv)
 
            /* Go over all entries in the second dict and add them to the
             * first dict. */
-           for (d2i = d2->dv_first; d2i != NULL; d2i = d2i->di_next)
+           todo = d2->dv_hashtable.ht_used;
+           for (hi2 = d2->dv_hashtable.ht_array; todo > 0; ++hi2)
            {
-               d1i = dict_find(d1, d2i->di_key, -1, NULL);
-               if (d1i == NULL)
+               if (!HASHITEM_EMPTY(hi2))
                {
-                   d1i = dictitem_copy(d2i);
-                   if (d1i != NULL)
-                       dict_add(d1, d1i);
-               }
-               else if (*action == 'e')
-               {
-                   EMSG2(_("Key already exists: %s"), d2i->di_key);
-                   break;
-               }
-               else if (*action == 'f')
-               {
-                   clear_tv(&d1i->di_tv);
-                   copy_tv(&d2i->di_tv, &d1i->di_tv);
+                   --todo;
+                   di1 = dict_find(d1, hi2->hi_key, -1);
+                   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')
+                   {
+                       clear_tv(&di1->di_tv);
+                       copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv);
+                   }
                }
            }
 
@@ -7378,11 +7428,13 @@ filter_map(argvars, rettv, map)
     char_u     *expr;
     listitem   *li, *nli;
     listvar    *l = NULL;
-    dictitem   *di, **pdi;
+    dictitem   *di;
+    hashitem   *hi;
     dictvar    *d = NULL;
     typeval    save_val;
     typeval    save_key;
     int                rem;
+    int                todo;
 
     rettv->vval.v_number = 0;
     if (argvars[0].v_type == VAR_LIST)
@@ -7408,21 +7460,23 @@ filter_map(argvars, rettv, map)
     {
        save_key = vimvars[VV_KEY].tv;
        vimvars[VV_KEY].tv.v_type = VAR_STRING;
-       pdi = &d->dv_first;
-       for (di = d->dv_first; di != NULL; di = *pdi)
+
+       todo = d->dv_hashtable.ht_used;
+       for (hi = d->dv_hashtable.ht_array; todo > 0; ++hi)
        {
-           vimvars[VV_KEY].tv.vval.v_string = vim_strsave(di->di_key);
-           if (filter_map_one(&di->di_tv, expr, map, &rem) == FAIL)
-               break;
-           if (!map && rem)
+           if (!HASHITEM_EMPTY(hi))
            {
-               *pdi = di->di_next;
-               dictitem_free(di);
+               --todo;
+               di = HI2DI(hi);
+               vimvars[VV_KEY].tv.vval.v_string = vim_strsave(di->di_key);
+               if (filter_map_one(&di->di_tv, expr, map, &rem) == FAIL)
+                   break;
+               if (!map && rem)
+                   dictitem_remove(d, di);
+               clear_tv(&vimvars[VV_KEY].tv);
            }
-           else
-               pdi = &di->di_next;
-           clear_tv(&vimvars[VV_KEY].tv);
        }
+
        clear_tv(&vimvars[VV_KEY].tv);
        vimvars[VV_KEY].tv = save_key;
     }
@@ -7784,7 +7838,7 @@ f_get(argvars, rettv)
     {
        if ((d = argvars[0].vval.v_dict) != NULL)
        {
-           di = dict_find(d, get_tv_string(&argvars[1]), -1, NULL);
+           di = dict_find(d, get_tv_string(&argvars[1]), -1);
            if (di != NULL)
                tv = &di->di_tv;
        }
@@ -8917,7 +8971,7 @@ f_has_key(argvars, rettv)
        return;
 
     rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
-                               get_tv_string(&argvars[1]), -1, NULL) != NULL;
+                                     get_tv_string(&argvars[1]), -1) != NULL;
 }
 
 /*
@@ -9412,8 +9466,11 @@ dict_list(argvars, rettv, what)
     listvar    *l;
     listvar    *l2;
     dictitem   *di;
+    hashitem   *hi;
     listitem   *li;
     listitem   *li2;
+    dictvar    *d;
+    int                todo;
 
     rettv->vval.v_number = 0;
     if (argvars[0].v_type != VAR_DICT)
@@ -9421,7 +9478,7 @@ dict_list(argvars, rettv, what)
        EMSG(_(e_dictreq));
        return;
     }
-    if (argvars[0].vval.v_dict == NULL)
+    if ((d = argvars[0].vval.v_dict) == NULL)
        return;
 
     l = list_alloc();
@@ -9431,46 +9488,53 @@ dict_list(argvars, rettv, what)
     rettv->vval.v_list = l;
     ++l->lv_refcount;
 
-    for (di = argvars[0].vval.v_dict->dv_first; di != NULL; di = di->di_next)
+    todo = d->dv_hashtable.ht_used;
+    for (hi = d->dv_hashtable.ht_array; todo > 0; ++hi)
     {
-       li = listitem_alloc();
-       if (li == NULL)
-           break;
-       list_append(l, li);
-
-       if (what == 0)
+       if (!HASHITEM_EMPTY(hi))
        {
-           /* keys() */
-           li->li_tv.v_type = VAR_STRING;
-           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.vval.v_list = l2;
-           if (l2 == NULL)
-               break;
-           ++l2->lv_refcount;
+           --todo;
+           di = HI2DI(hi);
 
-           li2 = listitem_alloc();
-           if (li2 == NULL)
+           li = listitem_alloc();
+           if (li == NULL)
                break;
-           list_append(l2, li2);
-           li2->li_tv.v_type = VAR_STRING;
-           li2->li_tv.vval.v_string = vim_strsave(di->di_key);
+           list_append(l, li);
 
-           li2 = listitem_alloc();
-           if (li2 == NULL)
-               break;
-           list_append(l2, li2);
-           copy_tv(&di->di_tv, &li2->li_tv);
+           if (what == 0)
+           {
+               /* keys() */
+               li->li_tv.v_type = VAR_STRING;
+               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.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.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);
+           }
        }
     }
 }
@@ -10023,22 +10087,26 @@ max_min(argvars, rettv, domax)
     else if (argvars[0].v_type == VAR_DICT)
     {
        dictvar         *d;
-       dictitem        *di;
+       int             first = TRUE;
+       hashitem        *hi;
+       int             todo;
 
        d = argvars[0].vval.v_dict;
        if (d != NULL)
        {
-           di = d->dv_first;
-           if (di != NULL)
+           todo = d->dv_hashtable.ht_used;
+           for (hi = d->dv_hashtable.ht_array; todo > 0; ++hi)
            {
-               n = get_tv_number(&di->di_tv);
-               while (1)
+               if (!HASHITEM_EMPTY(hi))
                {
-                   di = di->di_next;
-                   if (di == NULL)
-                       break;
-                   i = get_tv_number(&di->di_tv);
-                   if (domax ? i > n : i < n)
+                   --todo;
+                   i = get_tv_number(&HI2DI(hi)->di_tv);
+                   if (first)
+                   {
+                       n = i;
+                       first = FALSE;
+                   }
+                   else if (domax ? i > n : i < n)
                        n = i;
                }
            }
@@ -10472,7 +10540,7 @@ f_remove(argvars, rettv)
     long       end;
     char_u     *key;
     dictvar    *d;
-    dictitem   *di, **pdi;
+    dictitem   *di;
 
     rettv->vval.v_number = 0;
     if (argvars[0].v_type == VAR_DICT)
@@ -10482,18 +10550,15 @@ f_remove(argvars, rettv)
        else if ((d = argvars[0].vval.v_dict) != NULL)
        {
            key = get_tv_string(&argvars[1]);
-           pdi = &d->dv_first;
-           for (di = d->dv_first; di != NULL; pdi = &di->di_next, di = *pdi)
-               if (STRCMP(di->di_key, key) == 0)
-               {
-                   *pdi = di->di_next;
-                   *rettv = di->di_tv;
-                   init_tv(&di->di_tv);
-                   dictitem_free(di);
-                   break;
-               }
+           di = dict_find(d, key, -1);
            if (di == NULL)
                EMSG2(_(e_dictkey), key);
+           else
+           {
+               *rettv = di->di_tv;
+               init_tv(&di->di_tv);
+               dictitem_remove(d, di);
+           }
        }
     }
     else if (argvars[0].v_type != VAR_LIST)
@@ -13134,9 +13199,11 @@ clear_tv(varp)
                break;
            case VAR_LIST:
                list_unref(varp->vval.v_list);
+               varp->vval.v_list = NULL;
                break;
            case VAR_DICT:
                dict_unref(varp->vval.v_dict);
+               varp->vval.v_dict = NULL;
                break;
            case VAR_NUMBER:
                varp->vval.v_number = 0;
@@ -14003,6 +14070,8 @@ ex_function(eap)
         */
        if (!aborting())
        {
+           if (!eap->skip && fudi.fd_newkey != NULL)
+               EMSG2(_(e_dictkey), fudi.fd_newkey);
            vim_free(fudi.fd_newkey);
            return;
        }
@@ -14348,15 +14417,17 @@ ex_function(eap)
            if (fudi.fd_di == NULL)
            {
                /* add new dict entry */
-               fudi.fd_di = dictitem_alloc();
+               fudi.fd_di = dictitem_alloc(fudi.fd_newkey);
                if (fudi.fd_di == NULL)
                {
                    vim_free(fp);
                    goto erret;
                }
-               fudi.fd_di->di_key = fudi.fd_newkey;
-               fudi.fd_newkey = NULL;
-               dict_add(fudi.fd_dict, fudi.fd_di);
+               if (dict_add(fudi.fd_dict, fudi.fd_di) == FAIL)
+               {
+                   vim_free(fudi.fd_di);
+                   goto erret;
+               }
            }
            else
                /* overwrite existing dict entry */
@@ -14454,7 +14525,6 @@ trans_function_name(pp, skip, flags, fdp)
            fdp->fd_newkey = lv.ll_newkey;
            lv.ll_newkey = NULL;
            fdp->fd_di = lv.ll_di;
-           fdp->fd_pdi = lv.ll_pdi;
        }
        if (lv.ll_tv->v_type == VAR_FUNC && lv.ll_tv->vval.v_string != NULL)
        {
@@ -14463,8 +14533,8 @@ trans_function_name(pp, skip, flags, fdp)
        }
        else
        {
-           if (!skip && !(flags & TFN_QUIET)
-                                      && (fdp == NULL || lv.ll_dict == NULL))
+           if (!skip && !(flags & TFN_QUIET) && (fdp == NULL
+                            || lv.ll_dict == NULL || fdp->fd_newkey == NULL))
                EMSG(_(e_funcref));
            else
                *pp = end;
@@ -14743,8 +14813,7 @@ ex_delfunction(eap)
        {
            /* Delete the dict item that refers to the function, it will
             * invoke func_unref() and possibly delete the function. */
-           *fudi.fd_pdi = fudi.fd_di->di_next;
-           dictitem_free(fudi.fd_di);
+           dictitem_remove(fudi.fd_dict, fudi.fd_di);
        }
        else
            func_free(fp);
index 1db9fa75ef46617be7f988200fea8fd6ab706819..f706ea383c80b4e6442873c7348d1567ceefb5ef 100644 (file)
@@ -4,7 +4,7 @@
 # Authors:     Zoltan Arpadffy, <arpadffy@polarhome.com>
 #              Sandor Kopanyi,  <sandor.kopanyi@mailbox.hu>
 #
-# Last change:  2004 Dec 24
+# Last change:  2005 Jan 19
 #
 # This has been tested on VMS 6.2 to 7.2 on DEC Alpha and VAX.
 # Edit the lines in the Configuration section below to select.
@@ -57,7 +57,7 @@ SCRIPT = test1.out  test2.out  test3.out  test4.out  test5.out  \
         test33.out test34.out test35.out test36.out test37.out \
         test38.out test39.out test40.out test41.out test42.out \
         test43.out test44.out test45.out test46.out \
-        test48.out test51.out test53.out test54.out
+        test48.out test51.out test53.out test54.out test55.out
 
 .IFDEF WANT_GUI
 SCRIPT_GUI = test16.out