Mercurial > vim
comparison src/evalvars.c @ 21847:fb74a3387694 v8.2.1473
patch 8.2.1473: items in a list given to :const can still be modified
Commit: https://github.com/vim/vim/commit/021bda56710d98c09a6b35610a476ab2dd8c58ad
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Aug 17 21:07:22 2020 +0200
patch 8.2.1473: items in a list given to :const can still be modified
Problem: Items in a list given to :const can still be modified.
Solution: Work like ":lockvar! name" but don't lock referenced items.
Make locking a blob work.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 17 Aug 2020 21:15:03 +0200 |
parents | 4a4678d26822 |
children | 172b1746489c |
comparison
equal
deleted
inserted
replaced
21846:9b0141b6cfc2 | 21847:fb74a3387694 |
---|---|
171 static void list_tab_vars(int *first); | 171 static void list_tab_vars(int *first); |
172 static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first); | 172 static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first); |
173 static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, int flags, char_u *endchars, char_u *op); | 173 static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, int flags, char_u *endchars, char_u *op); |
174 static int do_unlet_var(lval_T *lp, char_u *name_end, exarg_T *eap, int deep, void *cookie); | 174 static int do_unlet_var(lval_T *lp, char_u *name_end, exarg_T *eap, int deep, void *cookie); |
175 static int do_lock_var(lval_T *lp, char_u *name_end, exarg_T *eap, int deep, void *cookie); | 175 static int do_lock_var(lval_T *lp, char_u *name_end, exarg_T *eap, int deep, void *cookie); |
176 static void item_lock(typval_T *tv, int deep, int lock); | 176 static void item_lock(typval_T *tv, int deep, int lock, int check_refcount); |
177 static void delete_var(hashtab_T *ht, hashitem_T *hi); | 177 static void delete_var(hashtab_T *ht, hashitem_T *hi); |
178 static void list_one_var(dictitem_T *v, char *prefix, int *first); | 178 static void list_one_var(dictitem_T *v, char *prefix, int *first); |
179 static void list_one_var_a(char *prefix, char_u *name, int type, char_u *string, int *first); | 179 static void list_one_var_a(char *prefix, char_u *name, int type, char_u *string, int *first); |
180 | 180 |
181 /* | 181 /* |
1701 { | 1701 { |
1702 if (lock) | 1702 if (lock) |
1703 di->di_flags |= DI_FLAGS_LOCK; | 1703 di->di_flags |= DI_FLAGS_LOCK; |
1704 else | 1704 else |
1705 di->di_flags &= ~DI_FLAGS_LOCK; | 1705 di->di_flags &= ~DI_FLAGS_LOCK; |
1706 item_lock(&di->di_tv, deep, lock); | 1706 item_lock(&di->di_tv, deep, lock, FALSE); |
1707 } | 1707 } |
1708 } | 1708 } |
1709 *name_end = cc; | 1709 *name_end = cc; |
1710 } | 1710 } |
1711 else if (lp->ll_range) | 1711 else if (lp->ll_range) |
1713 listitem_T *li = lp->ll_li; | 1713 listitem_T *li = lp->ll_li; |
1714 | 1714 |
1715 // (un)lock a range of List items. | 1715 // (un)lock a range of List items. |
1716 while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1)) | 1716 while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1)) |
1717 { | 1717 { |
1718 item_lock(&li->li_tv, deep, lock); | 1718 item_lock(&li->li_tv, deep, lock, FALSE); |
1719 li = li->li_next; | 1719 li = li->li_next; |
1720 ++lp->ll_n1; | 1720 ++lp->ll_n1; |
1721 } | 1721 } |
1722 } | 1722 } |
1723 else if (lp->ll_list != NULL) | 1723 else if (lp->ll_list != NULL) |
1724 // (un)lock a List item. | 1724 // (un)lock a List item. |
1725 item_lock(&lp->ll_li->li_tv, deep, lock); | 1725 item_lock(&lp->ll_li->li_tv, deep, lock, FALSE); |
1726 else | 1726 else |
1727 // (un)lock a Dictionary item. | 1727 // (un)lock a Dictionary item. |
1728 item_lock(&lp->ll_di->di_tv, deep, lock); | 1728 item_lock(&lp->ll_di->di_tv, deep, lock, FALSE); |
1729 | 1729 |
1730 return ret; | 1730 return ret; |
1731 } | 1731 } |
1732 | 1732 |
1733 /* | 1733 /* |
1734 * Lock or unlock an item. "deep" is nr of levels to go. | 1734 * Lock or unlock an item. "deep" is nr of levels to go. |
1735 * When "check_refcount" is TRUE do not lock a list or dict with a reference | |
1736 * count larger than 1. | |
1735 */ | 1737 */ |
1736 static void | 1738 static void |
1737 item_lock(typval_T *tv, int deep, int lock) | 1739 item_lock(typval_T *tv, int deep, int lock, int check_refcount) |
1738 { | 1740 { |
1739 static int recurse = 0; | 1741 static int recurse = 0; |
1740 list_T *l; | 1742 list_T *l; |
1741 listitem_T *li; | 1743 listitem_T *li; |
1742 dict_T *d; | 1744 dict_T *d; |
1774 case VAR_JOB: | 1776 case VAR_JOB: |
1775 case VAR_CHANNEL: | 1777 case VAR_CHANNEL: |
1776 break; | 1778 break; |
1777 | 1779 |
1778 case VAR_BLOB: | 1780 case VAR_BLOB: |
1779 if ((b = tv->vval.v_blob) != NULL) | 1781 if ((b = tv->vval.v_blob) != NULL |
1782 && !(check_refcount && b->bv_refcount > 1)) | |
1780 { | 1783 { |
1781 if (lock) | 1784 if (lock) |
1782 b->bv_lock |= VAR_LOCKED; | 1785 b->bv_lock |= VAR_LOCKED; |
1783 else | 1786 else |
1784 b->bv_lock &= ~VAR_LOCKED; | 1787 b->bv_lock &= ~VAR_LOCKED; |
1785 } | 1788 } |
1786 break; | 1789 break; |
1787 case VAR_LIST: | 1790 case VAR_LIST: |
1788 if ((l = tv->vval.v_list) != NULL) | 1791 if ((l = tv->vval.v_list) != NULL |
1792 && !(check_refcount && l->lv_refcount > 1)) | |
1789 { | 1793 { |
1790 if (lock) | 1794 if (lock) |
1791 l->lv_lock |= VAR_LOCKED; | 1795 l->lv_lock |= VAR_LOCKED; |
1792 else | 1796 else |
1793 l->lv_lock &= ~VAR_LOCKED; | 1797 l->lv_lock &= ~VAR_LOCKED; |
1794 if ((deep < 0 || deep > 1) && l->lv_first != &range_list_item) | 1798 if ((deep < 0 || deep > 1) && l->lv_first != &range_list_item) |
1795 // recursive: lock/unlock the items the List contains | 1799 // recursive: lock/unlock the items the List contains |
1796 FOR_ALL_LIST_ITEMS(l, li) | 1800 FOR_ALL_LIST_ITEMS(l, li) |
1797 item_lock(&li->li_tv, deep - 1, lock); | 1801 item_lock(&li->li_tv, deep - 1, lock, check_refcount); |
1798 } | 1802 } |
1799 break; | 1803 break; |
1800 case VAR_DICT: | 1804 case VAR_DICT: |
1801 if ((d = tv->vval.v_dict) != NULL) | 1805 if ((d = tv->vval.v_dict) != NULL |
1806 && !(check_refcount && d->dv_refcount > 1)) | |
1802 { | 1807 { |
1803 if (lock) | 1808 if (lock) |
1804 d->dv_lock |= VAR_LOCKED; | 1809 d->dv_lock |= VAR_LOCKED; |
1805 else | 1810 else |
1806 d->dv_lock &= ~VAR_LOCKED; | 1811 d->dv_lock &= ~VAR_LOCKED; |
1811 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) | 1816 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) |
1812 { | 1817 { |
1813 if (!HASHITEM_EMPTY(hi)) | 1818 if (!HASHITEM_EMPTY(hi)) |
1814 { | 1819 { |
1815 --todo; | 1820 --todo; |
1816 item_lock(&HI2DI(hi)->di_tv, deep - 1, lock); | 1821 item_lock(&HI2DI(hi)->di_tv, deep - 1, lock, |
1822 check_refcount); | |
1817 } | 1823 } |
1818 } | 1824 } |
1819 } | 1825 } |
1820 } | 1826 } |
1821 } | 1827 } |
3085 di->di_tv.v_lock = 0; | 3091 di->di_tv.v_lock = 0; |
3086 init_tv(tv); | 3092 init_tv(tv); |
3087 } | 3093 } |
3088 | 3094 |
3089 if (flags & LET_IS_CONST) | 3095 if (flags & LET_IS_CONST) |
3090 item_lock(&di->di_tv, 1, TRUE); | 3096 // Like :lockvar! name: lock the value and what it contains, but only |
3097 // if the reference count is up to one. That locks only literal | |
3098 // values. | |
3099 item_lock(&di->di_tv, DICT_MAXNEST, TRUE, TRUE); | |
3091 } | 3100 } |
3092 | 3101 |
3093 /* | 3102 /* |
3094 * Return TRUE if di_flags "flags" indicates variable "name" is read-only. | 3103 * Return TRUE if di_flags "flags" indicates variable "name" is read-only. |
3095 * Also give an error message. | 3104 * Also give an error message. |