# HG changeset patch # User vimboss # Date 1107199536 0 # Node ID 40a0699b6c62f93e58ae233fcdfd395bbc1bc80f # Parent e85cff741dec840d76cf5c043ee3e81891b9983a updated for version 7.0046 diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -453,6 +453,7 @@ static void f_inputsave __ARGS((typval_T static void f_inputsecret __ARGS((typval_T *argvars, typval_T *rettv)); static void f_insert __ARGS((typval_T *argvars, typval_T *rettv)); static void f_isdirectory __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_islocked __ARGS((typval_T *argvars, typval_T *rettv)); static void f_items __ARGS((typval_T *argvars, typval_T *rettv)); static void f_join __ARGS((typval_T *argvars, typval_T *rettv)); static void f_keys __ARGS((typval_T *argvars, typval_T *rettv)); @@ -556,6 +557,7 @@ static void list_one_var __ARGS((dictite static void list_one_var_a __ARGS((char_u *prefix, char_u *name, int type, char_u *string)); static void set_var __ARGS((char_u *name, typval_T *varp, int copy)); static int var_check_ro __ARGS((int flags, char_u *name)); +static int tv_check_lock __ARGS((int lock, char_u *name)); static void copy_tv __ARGS((typval_T *from, typval_T *to)); static void item_copy __ARGS((typval_T *from, typval_T *to, int deep)); static char_u *find_option_end __ARGS((char_u **arg, int *opt_flags)); @@ -592,7 +594,10 @@ static int tv_op __ARGS((typval_T *tv1, static void list_add_watch __ARGS((list_T *l, listwatch_T *lw)); static void list_rem_watch __ARGS((list_T *l, listwatch_T *lwrem)); static void list_fix_watch __ARGS((list_T *l, listitem_T *item)); +static void ex_unletlock __ARGS((exarg_T *eap, char_u *argstart, int deep)); static int do_unlet_var __ARGS((lval_T *lp, char_u *name_end, int forceit)); +static int do_lock_var __ARGS((lval_T *lp, char_u *name_end, int deep, int lock)); +static void item_lock __ARGS((typval_T *tv, int deep, int lock)); /* * Initialize the global and v: variables. @@ -1169,6 +1174,9 @@ ex_let(eap) expr = vim_strchr(expr, '='); if (expr == NULL) { + /* + * ":let" without "=": list variables + */ if (*arg == '[') EMSG(_(e_invarg)); else if (!ends_excmd(*arg)) @@ -1292,6 +1300,7 @@ ex_let_vars(arg_start, tv, copy, semicol } ltv.v_type = VAR_LIST; + ltv.v_lock = 0; ltv.vval.v_list = l; l->lv_refcount = 1; @@ -2077,7 +2086,7 @@ clear_lval(lp) } /* - * Set a variable that was parsed by get_lval(). + * Set a variable that was parsed by get_lval() to "rettv". * "endp" points to just after the parsed name. * "op" is NULL, "+" for "+=", "-" for "-=", "." for ".=" or "=" for "=". */ @@ -2104,6 +2113,7 @@ set_var_lval(lp, endp, rettv, copy, op) { typval_T tv; + /* handle +=, -= and .= */ if (get_var_tv(lp->ll_name, STRLEN(lp->ll_name), &tv) == OK) { if (tv_op(&tv, rettv, op) == OK) @@ -2116,6 +2126,10 @@ set_var_lval(lp, endp, rettv, copy, op) *endp = cc; } } + else if (tv_check_lock(lp->ll_newkey == NULL + ? lp->ll_tv->v_lock + : lp->ll_tv->vval.v_dict->dv_lock, lp->ll_name)) + ; else if (lp->ll_range) { /* @@ -2143,6 +2157,7 @@ set_var_lval(lp, endp, rettv, copy, op) break; } ni->li_tv.v_type = VAR_NUMBER; + ni->li_tv.v_lock = 0; ni->li_tv.vval.v_number = 0; list_append(lp->ll_list, ni); } @@ -2631,14 +2646,46 @@ end: ex_unlet(eap) exarg_T *eap; { + ex_unletlock(eap, eap->arg, 0); +} + +/* + * ":lockvar" and ":unlockvar" commands + */ + void +ex_lockvar(eap) + exarg_T *eap; +{ char_u *arg = eap->arg; + int deep = 2; + + if (eap->forceit) + deep = -1; + else if (vim_isdigit(*arg)) + { + deep = getdigits(&arg); + arg = skipwhite(arg); + } + + ex_unletlock(eap, arg, deep); +} + +/* + * ":unlet", ":lockvar" and ":unlockvar" are quite similar. + */ + static void +ex_unletlock(eap, argstart, deep) + exarg_T *eap; + char_u *argstart; + int deep; +{ + char_u *arg = argstart; char_u *name_end; int error = FALSE; + lval_T lv; do { - lval_T lv; - /* Parse the name and find the end. */ name_end = get_lval(arg, NULL, &lv, TRUE, eap->skip || error, FALSE); if (lv.ll_name == NULL) @@ -2657,8 +2704,19 @@ ex_unlet(eap) } if (!error && !eap->skip) - if (do_unlet_var(&lv, name_end, eap->forceit) == FAIL) - error = TRUE; + { + if (eap->cmdidx == CMD_unlet) + { + if (do_unlet_var(&lv, name_end, eap->forceit) == FAIL) + error = TRUE; + } + else + { + if (do_lock_var(&lv, name_end, deep, + eap->cmdidx == CMD_lockvar) == FAIL) + error = TRUE; + } + } if (!eap->skip) clear_lval(&lv); @@ -2669,7 +2727,6 @@ ex_unlet(eap) eap->nextcmd = check_nextcmd(arg); } - static int do_unlet_var(lp, name_end, forceit) lval_T *lp; @@ -2687,13 +2744,12 @@ do_unlet_var(lp, name_end, forceit) /* Normal name or expanded name. */ if (check_changedtick(lp->ll_name)) ret = FAIL; - else if (do_unlet(lp->ll_name) == FAIL && !forceit) - { - EMSG2(_("E108: No such variable: \"%s\""), lp->ll_name); + else if (do_unlet(lp->ll_name, forceit) == FAIL) ret = FAIL; - } *name_end = cc; } + else if (tv_check_lock(lp->ll_tv->v_lock, lp->ll_name)) + return FAIL; else if (lp->ll_range) { listitem_T *li; @@ -2722,10 +2778,12 @@ do_unlet_var(lp, name_end, forceit) /* * "unlet" a variable. Return OK if it existed, FAIL if not. + * When "forceit" is TRUE don't complain if the variable doesn't exist. */ int -do_unlet(name) +do_unlet(name, forceit) char_u *name; + int forceit; { hashtab_T *ht; hashitem_T *hi; @@ -2737,16 +2795,154 @@ do_unlet(name) hi = hash_find(ht, varname); if (!HASHITEM_EMPTY(hi)) { - if (!var_check_ro(HI2DI(hi)->di_flags, name)) - { - delete_var(ht, hi); - return OK; - } - } - } + if (var_check_ro(HI2DI(hi)->di_flags, name)) + return FAIL; + delete_var(ht, hi); + return OK; + } + } + if (forceit) + return OK; + EMSG2(_("E108: No such variable: \"%s\""), name); return FAIL; } +/* + * Lock or unlock variable indicated by "lp". + * "deep" is the levels to go (-1 for unlimited); + * "lock" is TRUE for ":lockvar", FALSE for ":unlockvar". + */ + static int +do_lock_var(lp, name_end, deep, lock) + lval_T *lp; + char_u *name_end; + int deep; + int lock; +{ + int ret = OK; + int cc; + dictitem_T *di; + + if (deep == 0) /* nothing to do */ + return OK; + + if (lp->ll_tv == NULL) + { + cc = *name_end; + *name_end = NUL; + + /* Normal name or expanded name. */ + if (check_changedtick(lp->ll_name)) + ret = FAIL; + else + { + di = find_var(lp->ll_name, NULL); + if (di == NULL) + ret = FAIL; + else + { + if (lock) + di->di_flags |= DI_FLAGS_LOCK; + else + di->di_flags &= ~DI_FLAGS_LOCK; + item_lock(&di->di_tv, deep, lock); + } + } + *name_end = cc; + } + else if (lp->ll_range) + { + listitem_T *li = lp->ll_li; + + /* (un)lock a range of List items. */ + while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1)) + { + item_lock(&li->li_tv, deep, lock); + li = li->li_next; + ++lp->ll_n1; + } + } + else if (lp->ll_list != NULL) + /* (un)lock a List item. */ + item_lock(&lp->ll_li->li_tv, deep, lock); + else + /* un(lock) a Dictionary item. */ + item_lock(&lp->ll_di->di_tv, deep, lock); + + return ret; +} + +/* + * Lock or unlock an item. "deep" is nr of levels to go. + */ + static void +item_lock(tv, deep, lock) + typval_T *tv; + int deep; + int lock; +{ + static int recurse = 0; + list_T *l; + listitem_T *li; + dict_T *d; + hashitem_T *hi; + int todo; + + if (recurse >= DICT_MAXNEST) + { + EMSG(_("E743: variable nested too deep for (un)lock")); + return; + } + if (deep == 0) + return; + ++recurse; + + /* lock/unlock the item itself */ + if (lock) + tv->v_lock |= VAR_LOCKED; + else + tv->v_lock &= ~VAR_LOCKED; + + switch (tv->v_type) + { + case VAR_LIST: + if ((l = tv->vval.v_list) != NULL) + { + if (lock) + l->lv_lock |= VAR_LOCKED; + else + l->lv_lock &= ~VAR_LOCKED; + if (deep < 0 || deep > 1) + /* recursive: lock/unlock the items the List contains */ + for (li = l->lv_first; li != NULL; li = li->li_next) + item_lock(&li->li_tv, deep - 1, lock); + } + break; + case VAR_DICT: + if ((d = tv->vval.v_dict) != NULL) + { + if (lock) + d->dv_lock |= VAR_LOCKED; + else + d->dv_lock &= ~VAR_LOCKED; + if (deep < 0 || deep > 1) + { + /* recursive: lock/unlock the items the List contains */ + todo = d->dv_hashtab.ht_used; + for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + --todo; + item_lock(&HI2DI(hi)->di_tv, deep - 1, lock); + } + } + } + } + } + --recurse; +} + #if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO) /* * Delete all "menutrans_" variables. @@ -3621,6 +3817,8 @@ eval6(arg, rettv, evaluate) * function() function call * $VAR environment variable * (expression) nested expression + * [expr, expr] List + * {key: val, key: val} Dictionary * * Also handle: * ! in front logical NOT @@ -4420,6 +4618,7 @@ get_list_tv(arg, rettv, evaluate) if (item != NULL) { item->li_tv = tv; + item->li_tv.v_lock = 0; list_append(l, item); } else @@ -5002,7 +5201,11 @@ dict_alloc() d = (dict_T *)alloc(sizeof(dict_T)); if (d != NULL) + { hash_init(&d->dv_hashtab); + d->dv_lock = 0; + d->dv_refcount = 0; + } return d; } @@ -5058,7 +5261,10 @@ dictitem_alloc(key) di = (dictitem_T *)alloc(sizeof(dictitem_T) + STRLEN(key)); if (di != NULL) + { STRCPY(di->di_key, key); + di->di_flags = 0; + } return di; } @@ -5075,6 +5281,7 @@ dictitem_copy(org) if (di != NULL) { STRCPY(di->di_key, org->di_key); + di->di_flags = 0; copy_tv(&org->di_tv, &di->di_tv); } return di; @@ -5357,6 +5564,7 @@ get_dict_tv(arg, rettv, evaluate) if (item != NULL) { item->di_tv = tv; + item->di_tv.v_lock = 0; if (dict_add(d, item) == FAIL) dictitem_free(item); } @@ -5679,6 +5887,7 @@ static struct fst {"inputsecret", 1, 2, f_inputsecret}, {"insert", 2, 3, f_insert}, {"isdirectory", 1, 1, f_isdirectory}, + {"islocked", 1, 1, f_islocked}, {"items", 1, 1, f_items}, {"join", 1, 2, f_join}, {"keys", 1, 1, f_keys}, @@ -6169,8 +6378,9 @@ f_add(argvars, rettv) rettv->vval.v_number = 1; /* Default: Failed */ if (argvars[0].v_type == VAR_LIST) { - l = argvars[0].vval.v_list; - if (l != NULL && list_append_tv(l, &argvars[1]) == OK) + if ((l = argvars[0].vval.v_list) != NULL + && !tv_check_lock(l->lv_lock, (char_u *)"add()") + && list_append_tv(l, &argvars[1]) == OK) copy_tv(&argvars[0], rettv); } else @@ -6612,7 +6822,9 @@ f_call(argvars, rettv) EMSG(_("E699: Too many arguments")); break; } - /* Make a copy of each argument (is this really needed?) */ + /* Make a copy of each argument. This is needed to be able to set + * v_lock to VAR_FIXED in the copy without changing the original list. + */ copy_tv(&item->li_tv, &argv[argc++]); } @@ -7259,7 +7471,8 @@ f_extend(argvars, rettv) l1 = argvars[0].vval.v_list; l2 = argvars[1].vval.v_list; - if (l1 != NULL && l2 != NULL) + if (l1 != NULL && !tv_check_lock(l1->lv_lock, (char_u *)"extend()") + && l2 != NULL) { if (argvars[2].v_type != VAR_UNKNOWN) { @@ -7290,7 +7503,8 @@ f_extend(argvars, rettv) d1 = argvars[0].vval.v_dict; d2 = argvars[1].vval.v_dict; - if (d1 != NULL && d2 != NULL) + if (d1 != NULL && !tv_check_lock(d1->dv_lock, (char_u *)"extend()") + && d2 != NULL) { /* Check the third argument. */ if (argvars[2].v_type != VAR_UNKNOWN) @@ -7478,21 +7692,25 @@ filter_map(argvars, rettv, map) typval_T save_key; int rem; int todo; + char_u *msg = map ? (char_u *)"map()" : (char_u *)"filter()"; + rettv->vval.v_number = 0; if (argvars[0].v_type == VAR_LIST) { - if ((l = argvars[0].vval.v_list) == NULL) + if ((l = argvars[0].vval.v_list) == NULL + || (map && tv_check_lock(l->lv_lock, msg))) return; } else if (argvars[0].v_type == VAR_DICT) { - if ((d = argvars[0].vval.v_dict) == NULL) + if ((d = argvars[0].vval.v_dict) == NULL + || (map && tv_check_lock(d->dv_lock, msg))) return; } else { - EMSG2(_(e_listdictarg), map ? "map()" : "filter()"); + EMSG2(_(e_listdictarg), msg); return; } @@ -7513,6 +7731,8 @@ filter_map(argvars, rettv, map) { --todo; di = HI2DI(hi); + if (tv_check_lock(di->di_tv.v_lock, msg)) + break; vimvars[VV_KEY].vv_str = vim_strsave(di->di_key); if (filter_map_one(&di->di_tv, expr, map, &rem) == FAIL) break; @@ -7530,6 +7750,8 @@ filter_map(argvars, rettv, map) { for (li = l->lv_first; li != NULL; li = nli) { + if (tv_check_lock(li->li_tv.v_lock, msg)) + break; nli = li->li_next; if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL) break; @@ -8314,6 +8536,7 @@ f_getline(argvars, rettv) break; list_append(l, li); li->li_tv.v_type = VAR_STRING; + li->li_tv.v_lock = 0; li->li_tv.vval.v_string = vim_strsave(ml_get(lnum++)); } rettv->vval.v_list = l; @@ -9471,9 +9694,11 @@ f_insert(argvars, rettv) listitem_T *item; list_T *l; + rettv->vval.v_number = 0; if (argvars[0].v_type != VAR_LIST) EMSG2(_(e_listarg), "insert()"); - else if ((l = argvars[0].vval.v_list) != NULL) + else if ((l = argvars[0].vval.v_list) != NULL + && !tv_check_lock(l->lv_lock, (char_u *)"insert()")) { if (argvars[2].v_type != VAR_UNKNOWN) before = get_tv_number(&argvars[2]); @@ -9502,6 +9727,80 @@ f_isdirectory(argvars, rettv) rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0])); } +static int tv_islocked __ARGS((typval_T *tv)); + +/* + * Return TRUE if typeval "tv" is locked: Either tha value is locked itself or + * it refers to a List or Dictionary that is locked. + */ + static int +tv_islocked(tv) + typval_T *tv; +{ + return (tv->v_lock & VAR_LOCKED) + || (tv->v_type == VAR_LIST + && tv->vval.v_list != NULL + && (tv->vval.v_list->lv_lock & VAR_LOCKED)) + || (tv->v_type == VAR_DICT + && tv->vval.v_dict != NULL + && (tv->vval.v_dict->dv_lock & VAR_LOCKED)); +} + +/* + * "islocked()" function + */ + static void +f_islocked(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + lval_T lv; + char_u *end; + dictitem_T *di; + + rettv->vval.v_number = -1; + end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE, FALSE); + if (end != NULL && lv.ll_name != NULL) + { + if (*end != NUL) + EMSG(_(e_trailing)); + else + { + if (lv.ll_tv == NULL) + { + if (check_changedtick(lv.ll_name)) + rettv->vval.v_number = 1; /* always locked */ + else + { + di = find_var(lv.ll_name, NULL); + if (di != NULL) + { + /* Consider a variable locked when: + * 1. the variable itself is locked + * 2. the value of the variable is locked. + * 3. the List or Dict value is locked. + */ + rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK) + || tv_islocked(&di->di_tv)); + } + } + } + else if (lv.ll_range) + EMSG(_("E745: Range not allowed")); + else if (lv.ll_newkey != NULL) + EMSG2(_(e_dictkey), lv.ll_newkey); + else if (lv.ll_list != NULL) + /* List item. */ + rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv); + else + /* Dictionary item. */ + rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv); + } + } + + clear_lval(&lv); +} + static void dict_list __ARGS((typval_T *argvars, typval_T *rettv, int what)); /* @@ -9558,6 +9857,7 @@ dict_list(argvars, rettv, what) { /* keys() */ li->li_tv.v_type = VAR_STRING; + li->li_tv.v_lock = 0; li->li_tv.vval.v_string = vim_strsave(di->di_key); } else if (what == 1) @@ -9570,6 +9870,7 @@ dict_list(argvars, rettv, what) /* items() */ l2 = list_alloc(); li->li_tv.v_type = VAR_LIST; + li->li_tv.v_lock = 0; li->li_tv.vval.v_list = l2; if (l2 == NULL) break; @@ -9580,6 +9881,7 @@ dict_list(argvars, rettv, what) break; list_append(l2, li2); li2->li_tv.v_type = VAR_STRING; + li2->li_tv.v_lock = 0; li2->li_tv.vval.v_string = vim_strsave(di->di_key); li2 = listitem_alloc(); @@ -10345,6 +10647,7 @@ f_range(argvars, rettv) if (li == NULL) break; li->li_tv.v_type = VAR_NUMBER; + li->li_tv.v_lock = 0; li->li_tv.vval.v_number = i; list_append(l, li); } @@ -10600,7 +10903,8 @@ f_remove(argvars, rettv) { if (argvars[2].v_type != VAR_UNKNOWN) EMSG2(_(e_toomanyarg), "remove()"); - else if ((d = argvars[0].vval.v_dict) != NULL) + else if ((d = argvars[0].vval.v_dict) != NULL + && !tv_check_lock(d->dv_lock, (char_u *)"remove()")) { key = get_tv_string(&argvars[1]); di = dict_find(d, key, -1); @@ -10616,7 +10920,8 @@ f_remove(argvars, rettv) } else if (argvars[0].v_type != VAR_LIST) EMSG2(_(e_listdictarg), "remove()"); - else if ((l = argvars[0].vval.v_list) != NULL) + else if ((l = argvars[0].vval.v_list) != NULL + && !tv_check_lock(l->lv_lock, (char_u *)"remove()")) { idx = get_tv_number(&argvars[1]); item = list_find(l, idx); @@ -10950,7 +11255,8 @@ f_reverse(argvars, rettv) rettv->vval.v_number = 0; if (argvars[0].v_type != VAR_LIST) EMSG2(_(e_listarg), "reverse()"); - else if ((l = argvars[0].vval.v_list) != NULL) + else if ((l = argvars[0].vval.v_list) != NULL + && !tv_check_lock(l->lv_lock, (char_u *)"reverse()")) { li = l->lv_last; l->lv_first = l->lv_last = li; @@ -11553,7 +11859,8 @@ item_compare2(s1, s2) typval_T argv[2]; int dummy; - /* copy the values (is this really needed?) */ + /* copy the values. This is needed to be able to set v_lock to VAR_FIXED + * in the copy without changing the original list items. */ copy_tv(&(*(listitem_T **)s1)->li_tv, &argv[0]); copy_tv(&(*(listitem_T **)s2)->li_tv, &argv[1]); @@ -11591,7 +11898,7 @@ f_sort(argvars, rettv) else { l = argvars[0].vval.v_list; - if (l == NULL) + if (l == NULL || tv_check_lock(l->lv_lock, (char_u *)"sort()")) return; rettv->vval.v_list = l; rettv->v_type = VAR_LIST; @@ -11696,6 +12003,7 @@ f_split(argvars, rettv) if (ni == NULL) break; ni->li_tv.v_type = VAR_STRING; + ni->li_tv.v_lock = 0; ni->li_tv.vval.v_string = vim_strnsave(str, end - str); list_append(l, ni); } @@ -13253,6 +13561,7 @@ clear_tv(varp) default: EMSG2(_(e_intern2), "clear_tv()"); } + varp->v_lock = 0; } } @@ -13534,6 +13843,7 @@ init_var_dict(dict, dict_var) dict->dv_refcount = 99999; dict_var->di_tv.vval.v_dict = dict; dict_var->di_tv.v_type = VAR_DICT; + dict_var->di_tv.v_lock = VAR_FIXED; dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; dict_var->di_key[0] = NUL; } @@ -13696,7 +14006,8 @@ set_var(name, tv, copy) if (v != NULL) { /* existing variable, need to clear the value */ - if (var_check_ro(v->di_flags, name)) + if (var_check_ro(v->di_flags, name) + || tv_check_lock(v->di_tv.v_lock, name)) return; if (v->di_tv.v_type != tv->v_type && !((v->di_tv.v_type == VAR_STRING @@ -13736,16 +14047,17 @@ set_var(name, tv, copy) } else /* add a new variable */ { - v = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T) + STRLEN(varname))); + v = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T) + + STRLEN(varname))); if (v == NULL) return; STRCPY(v->di_key, varname); - v->di_flags = 0; if (hash_add(ht, DI2HIKEY(v)) == FAIL) { vim_free(v); return; } + v->di_flags = 0; } if (copy || tv->v_type == VAR_NUMBER) @@ -13753,6 +14065,7 @@ set_var(name, tv, copy) else { v->di_tv = *tv; + v->di_tv.v_lock = 0; init_tv(tv); } } @@ -13780,6 +14093,30 @@ var_check_ro(flags, name) } /* + * Return TRUE if typeval "tv" is set to be locked (immutable). + * Also give an error message, using "name". + */ + static int +tv_check_lock(lock, name) + int lock; + char_u *name; +{ + if (lock & VAR_LOCKED) + { + EMSG2(_("E741: Value is locked: %s"), + name == NULL ? (char_u *)_("Unknown") : name); + return TRUE; + } + if (lock & VAR_FIXED) + { + EMSG2(_("E742: Cannot change value of %s"), + name == NULL ? (char_u *)_("Unknown") : name); + return TRUE; + } + return FALSE; +} + +/* * Copy the values from typval_T "from" to typval_T "to". * When needed allocates string or increases reference count. * Does not make a copy of a list or dict but copies the reference! @@ -13790,6 +14127,7 @@ copy_tv(from, to) typval_T *to; { to->v_type = from->v_type; + to->v_lock = 0; switch (from->v_type) { case VAR_NUMBER: @@ -13858,10 +14196,12 @@ item_copy(from, to, deep) break; case VAR_LIST: to->v_type = VAR_LIST; + to->v_lock = 0; to->vval.v_list = list_copy(from->vval.v_list, deep); break; case VAR_DICT: to->v_type = VAR_DICT; + to->v_lock = 0; to->vval.v_dict = dict_copy(from->vval.v_dict, deep); break; default: @@ -14529,6 +14869,7 @@ ex_function(eap) /* overwrite existing dict entry */ clear_tv(&fudi.fd_di->di_tv); fudi.fd_di->di_tv.v_type = VAR_FUNC; + fudi.fd_di->di_tv.v_lock = 0; fudi.fd_di->di_tv.vval.v_string = vim_strsave(name); fp->refcount = 1; } @@ -15072,6 +15413,7 @@ call_user_func(fp, argcount, argvars, re v->di_flags = DI_FLAGS_RO + DI_FLAGS_FIX; hash_add(&fc.l_vars.dv_hashtab, DI2HIKEY(v)); v->di_tv.v_type = VAR_DICT; + v->di_tv.v_lock = 0; v->di_tv.vval.v_dict = selfdict; ++selfdict->dv_refcount; } @@ -15089,6 +15431,7 @@ call_user_func(fp, argcount, argvars, re v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; hash_add(&fc.l_avars.dv_hashtab, DI2HIKEY(v)); v->di_tv.v_type = VAR_LIST; + v->di_tv.v_lock = VAR_FIXED; v->di_tv.vval.v_list = &fc.l_varlist; vim_memset(&fc.l_varlist, 0, sizeof(list_T)); fc.l_varlist.lv_refcount = 99999; @@ -15121,7 +15464,8 @@ call_user_func(fp, argcount, argvars, re } else { - v = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T) + STRLEN(name))); + v = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T) + + STRLEN(name))); if (v == NULL) break; v->di_flags = DI_FLAGS_RO; @@ -15129,13 +15473,16 @@ call_user_func(fp, argcount, argvars, re STRCPY(v->di_key, name); hash_add(&fc.l_avars.dv_hashtab, DI2HIKEY(v)); - /* Note: the values are copied directly to avoid alloc/free. */ + /* Note: the values are copied directly to avoid alloc/free. + * "argvars" must have VAR_FIXED for v_lock. */ v->di_tv = argvars[i]; + v->di_tv.v_lock = VAR_FIXED; if (ai >= 0 && ai < MAX_FUNC_ARGS) { list_append(&fc.l_varlist, &fc.l_listitems[ai]); fc.l_listitems[ai].li_tv = argvars[i]; + fc.l_listitems[ai].li_tv.v_lock = VAR_FIXED; } } @@ -15276,6 +15623,7 @@ add_nr_var(dp, v, name, nr) v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; hash_add(&dp->dv_hashtab, DI2HIKEY(v)); v->di_tv.v_type = VAR_NUMBER; + v->di_tv.v_lock = VAR_FIXED; v->di_tv.vval.v_number = nr; } diff --git a/src/ex_cmds.h b/src/ex_cmds.h --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -492,6 +492,8 @@ EX(CMD_loadkeymap, "loadkeymap", ex_load CMDWIN), EX(CMD_lockmarks, "lockmarks", ex_wrongmodifier, NEEDARG|EXTRA|NOTRLCOM), +EX(CMD_lockvar, "lockvar", ex_lockvar, + BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN), EX(CMD_lunmap, "lunmap", ex_unmap, EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), EX(CMD_ls, "ls", buflist_list, @@ -826,6 +828,8 @@ EX(CMD_unhide, "unhide", ex_buffer_all, RANGE|NOTADR|COUNT|TRLBAR), EX(CMD_unlet, "unlet", ex_unlet, BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN), +EX(CMD_unlockvar, "unlockvar", ex_lockvar, + BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN), EX(CMD_unmap, "unmap", ex_unmap, BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), EX(CMD_unmenu, "unmenu", ex_menu, diff --git a/src/if_mzsch.c b/src/if_mzsch.c --- a/src/if_mzsch.c +++ b/src/if_mzsch.c @@ -1,6 +1,6 @@ /* vi:set ts=8 sts=4 sw=4: * - * MzScheme interface by Sergey Khorev + * MzScheme interface by Sergey Khorev * Original work by Brent Fulgham * (Based on lots of help from Matthew Flatt) * @@ -219,11 +219,21 @@ static Scheme_Object *(*dll_scheme_eval_ static Scheme_Object *(*dll_scheme_eval_string_all)(const char *str, Scheme_Env *env, int all); static void (*dll_scheme_finish_primitive_module)(Scheme_Env *env); +# if MZSCHEME_VERSION_MAJOR < 299 static char *(*dll_scheme_format)(char *format, int flen, int argc, Scheme_Object **argv, long *rlen); +# else +static char *(*dll_scheme_format_utf8)(char *format, int flen, int argc, + Scheme_Object **argv, long *rlen); +# endif static void (*dll_scheme_gc_ptr_ok)(void *p); +# if MZSCHEME_VERSION_MAJOR < 299 static char *(*dll_scheme_get_sized_string_output)(Scheme_Object *, long *len); +# else +static char *(*dll_scheme_get_sized_byte_string_output)(Scheme_Object *, + long *len); +# endif static Scheme_Object *(*dll_scheme_intern_symbol)(const char *name); static Scheme_Object *(*dll_scheme_lookup_global)(Scheme_Object *symbol, Scheme_Env *env); @@ -235,8 +245,13 @@ static Scheme_Object *(*dll_scheme_make_ Scheme_Object *argv[]); static Scheme_Object *(*dll_scheme_make_pair)(Scheme_Object *car, Scheme_Object *cdr); +# if MZSCHEME_VERSION_MAJOR < 299 static Scheme_Object *(*dll_scheme_make_string)(const char *chars); static Scheme_Object *(*dll_scheme_make_string_output_port)(); +# else +static Scheme_Object *(*dll_scheme_make_byte_string)(const char *chars); +static Scheme_Object *(*dll_scheme_make_byte_string_output_port)(); +# endif static Scheme_Object *(*dll_scheme_make_struct_instance)(Scheme_Object *stype, int argc, Scheme_Object **argv); static Scheme_Object **(*dll_scheme_make_struct_names)(Scheme_Object *base, @@ -244,7 +259,11 @@ static Scheme_Object **(*dll_scheme_make static Scheme_Object *(*dll_scheme_make_struct_type)(Scheme_Object *base, Scheme_Object *parent, Scheme_Object *inspector, int num_fields, int num_uninit_fields, Scheme_Object *uninit_val, - Scheme_Object *properties); + Scheme_Object *properties +# if MZSCHEME_VERSION_MAJOR >= 299 + , Scheme_Object *guard +# endif + ); static Scheme_Object **(*dll_scheme_make_struct_values)( Scheme_Object *struct_type, Scheme_Object **names, int count, int flags); @@ -262,6 +281,13 @@ static Scheme_Object *(*dll_scheme_read) static void (*dll_scheme_signal_error)(const char *msg, ...); static void (*dll_scheme_wrong_type)(const char *name, const char *expected, int which, int argc, Scheme_Object **argv); +# if MZSCHEME_VERSION_MAJOR >= 299 +static void (*dll_scheme_set_param)(Scheme_Config *c, int pos, + Scheme_Object *o); +static Scheme_Config *(*dll_scheme_current_config)(void); +static Scheme_Object *(*dll_scheme_char_string_to_byte_string) + (Scheme_Object *s); +# endif /* arrays are imported directly */ # define scheme_eof dll_scheme_eof @@ -298,17 +324,32 @@ static void (*dll_scheme_wrong_type)(con # define scheme_eval_string dll_scheme_eval_string # define scheme_eval_string_all dll_scheme_eval_string_all # define scheme_finish_primitive_module dll_scheme_finish_primitive_module -# define scheme_format dll_scheme_format +# if MZSCHEME_VERSION_MAJOR < 299 +# define scheme_format dll_scheme_format +# else +# define scheme_format_utf8 dll_scheme_format_utf8 +# endif # define scheme_gc_ptr_ok dll_scheme_gc_ptr_ok -# define scheme_get_sized_string_output dll_scheme_get_sized_string_output +# if MZSCHEME_VERSION_MAJOR < 299 +# define scheme_get_sized_string_output dll_scheme_get_sized_string_output +# else +# define scheme_get_sized_byte_string_output \ + dll_scheme_get_sized_byte_string_output +# endif # define scheme_intern_symbol dll_scheme_intern_symbol # define scheme_lookup_global dll_scheme_lookup_global # define scheme_make_closed_prim_w_arity dll_scheme_make_closed_prim_w_arity # define scheme_make_integer_value dll_scheme_make_integer_value # define scheme_make_namespace dll_scheme_make_namespace # define scheme_make_pair dll_scheme_make_pair -# define scheme_make_string dll_scheme_make_string -# define scheme_make_string_output_port dll_scheme_make_string_output_port +# if MZSCHEME_VERSION_MAJOR < 299 +# define scheme_make_string dll_scheme_make_string +# define scheme_make_string_output_port dll_scheme_make_string_output_port +# else +# define scheme_make_byte_string dll_scheme_make_byte_string +# define scheme_make_byte_string_output_port \ + dll_scheme_make_byte_string_output_port +# endif # define scheme_make_struct_instance dll_scheme_make_struct_instance # define scheme_make_struct_names dll_scheme_make_struct_names # define scheme_make_struct_type dll_scheme_make_struct_type @@ -325,6 +366,12 @@ static void (*dll_scheme_wrong_type)(con # define scheme_set_stack_base dll_scheme_set_stack_base # define scheme_signal_error dll_scheme_signal_error # define scheme_wrong_type dll_scheme_wrong_type +# if MZSCHEME_VERSION_MAJOR >= 299 +# define scheme_set_param dll_scheme_set_param +# define scheme_current_config dll_scheme_current_config +# define scheme_char_string_to_byte_string \ + dll_scheme_char_string_to_byte_string +# endif typedef struct { @@ -367,10 +414,19 @@ static Thunk_Info mzsch_imports[] = { {"scheme_eval_string_all", (void **)&dll_scheme_eval_string_all}, {"scheme_finish_primitive_module", (void **)&dll_scheme_finish_primitive_module}, +# if MZSCHEME_VERSION_MAJOR < 299 {"scheme_format", (void **)&dll_scheme_format}, +# else + {"scheme_format_utf8", (void **)&dll_scheme_format_utf8}, +#endif {"scheme_gc_ptr_ok", (void **)&dll_scheme_gc_ptr_ok}, +# if MZSCHEME_VERSION_MAJOR < 299 {"scheme_get_sized_string_output", (void **)&dll_scheme_get_sized_string_output}, +# else + {"scheme_get_sized_byte_string_output", + (void **)&dll_scheme_get_sized_byte_string_output}, +#endif {"scheme_intern_symbol", (void **)&dll_scheme_intern_symbol}, {"scheme_lookup_global", (void **)&dll_scheme_lookup_global}, {"scheme_make_closed_prim_w_arity", @@ -378,9 +434,15 @@ static Thunk_Info mzsch_imports[] = { {"scheme_make_integer_value", (void **)&dll_scheme_make_integer_value}, {"scheme_make_namespace", (void **)&dll_scheme_make_namespace}, {"scheme_make_pair", (void **)&dll_scheme_make_pair}, +# if MZSCHEME_VERSION_MAJOR < 299 {"scheme_make_string", (void **)&dll_scheme_make_string}, {"scheme_make_string_output_port", (void **)&dll_scheme_make_string_output_port}, +# else + {"scheme_make_byte_string", (void **)&dll_scheme_make_byte_string}, + {"scheme_make_byte_string_output_port", + (void **)&dll_scheme_make_byte_string_output_port}, +# endif {"scheme_make_struct_instance", (void **)&dll_scheme_make_struct_instance}, {"scheme_make_struct_names", (void **)&dll_scheme_make_struct_names}, @@ -398,6 +460,12 @@ static Thunk_Info mzsch_imports[] = { {"scheme_set_stack_base", (void **)&dll_scheme_set_stack_base}, {"scheme_signal_error", (void **)&dll_scheme_signal_error}, {"scheme_wrong_type", (void **)&dll_scheme_wrong_type}, +# if MZSCHEME_VERSION_MAJOR >= 299 + {"scheme_set_param", (void **)&dll_scheme_set_param}, + {"scheme_current_config", (void **)&dll_scheme_current_config}, + {"scheme_char_string_to_byte_string", + (void **)&dll_scheme_char_string_to_byte_string}, +# endif {NULL, NULL}}; static HINSTANCE hMzGC = 0;