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.