# HG changeset patch # User vimboss # Date 1108218702 0 # Node ID e943e5502fc9cc439294de385dc564226b7311a1 # Parent 8b0ee9d57d7f147cdd06a172c104a4609b2c8c40 updated for version 7.0050 diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -335,10 +335,10 @@ static int list_append_tv __ARGS((list_T static int list_insert_tv __ARGS((list_T *l, typval_T *tv, listitem_T *item)); static int list_extend __ARGS((list_T *l1, list_T *l2, listitem_T *bef)); static int list_concat __ARGS((list_T *l1, list_T *l2, typval_T *tv)); -static list_T *list_copy __ARGS((list_T *orig, int deep)); +static list_T *list_copy __ARGS((list_T *orig, int deep, int copyID)); static void list_remove __ARGS((list_T *l, listitem_T *item, listitem_T *item2)); static char_u *list2string __ARGS((typval_T *tv)); -static void list_join __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo)); +static int list_join __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo)); static dict_T *dict_alloc __ARGS((void)); static void dict_unref __ARGS((dict_T *d)); @@ -347,6 +347,7 @@ static dictitem_T *dictitem_alloc __ARGS static dictitem_T *dictitem_copy __ARGS((dictitem_T *org)); static void dictitem_remove __ARGS((dict_T *dict, dictitem_T *item)); static void dictitem_free __ARGS((dictitem_T *item)); +static dict_T *dict_copy __ARGS((dict_T *orig, int deep, int copyID)); static int dict_add __ARGS((dict_T *d, dictitem_T *item)); static long dict_len __ARGS((dict_T *d)); static dictitem_T *dict_find __ARGS((dict_T *d, char_u *key, int len)); @@ -361,6 +362,7 @@ static int find_internal_func __ARGS((ch static char_u *deref_func_name __ARGS((char_u *name, int *lenp)); static int get_func_tv __ARGS((char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict)); static int call_func __ARGS((char_u *name, int len, typval_T *rettv, int argcount, typval_T *argvars, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict)); +static void emsg_funcname __ARGS((char *msg, char_u *name)); static void f_add __ARGS((typval_T *argvars, typval_T *rettv)); static void f_append __ARGS((typval_T *argvars, typval_T *rettv)); @@ -562,7 +564,7 @@ static void set_var __ARGS((char_u *name 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 int item_copy __ARGS((typval_T *from, typval_T *to, int deep, int copyID)); static char_u *find_option_end __ARGS((char_u **arg, int *opt_flags)); static char_u *trans_function_name __ARGS((char_u **pp, int skip, int flags, funcdict_T *fd)); static int eval_fname_script __ARGS((char_u *p)); @@ -2497,10 +2499,7 @@ ex_call(eap) if (*startarg != '(') { - if (*name == K_SPECIAL) - EMSG2(_("E107: Missing braces: %s"), name + 3); - else - EMSG2(_("E107: Missing braces: %s"), name); + EMSG2(_("E107: Missing braces: %s"), eap->arg); goto end; } @@ -4961,7 +4960,7 @@ list_concat(l1, l2, tv) list_T *l; /* make a copy of the first list. */ - l = list_copy(l1, FALSE); + l = list_copy(l1, FALSE, 0); if (l == NULL) return FAIL; tv->v_type = VAR_LIST; @@ -4974,12 +4973,14 @@ list_concat(l1, l2, tv) /* * Make a copy of list "orig". Shallow if "deep" is FALSE. * The refcount of the new list is set to 1. + * See item_copy() for "copyID". * Returns NULL when out of memory. */ static list_T * -list_copy(orig, deep) +list_copy(orig, deep, copyID) list_T *orig; int deep; + int copyID; { list_T *copy; listitem_T *item; @@ -4991,18 +4992,37 @@ list_copy(orig, deep) copy = list_alloc(); if (copy != NULL) { - for (item = orig->lv_first; item != NULL; item = item->li_next) + if (copyID != 0) + { + /* Do this before adding the items, because one of the items may + * refer back to this list. */ + orig->lv_copyID = copyID; + orig->lv_copylist = copy; + } + for (item = orig->lv_first; item != NULL && !got_int; + item = item->li_next) { ni = listitem_alloc(); if (ni == NULL) break; if (deep) - item_copy(&item->li_tv, &ni->li_tv, deep); + { + if (item_copy(&item->li_tv, &ni->li_tv, deep, copyID) == FAIL) + { + vim_free(ni); + break; + } + } else copy_tv(&item->li_tv, &ni->li_tv); list_append(copy, ni); } ++copy->lv_refcount; + if (item != NULL) + { + list_unref(copy); + copy = NULL; + } } return copy; @@ -5054,7 +5074,11 @@ list2string(tv) return NULL; ga_init2(&ga, (int)sizeof(char), 80); ga_append(&ga, '['); - list_join(&ga, tv->vval.v_list, (char_u *)", ", FALSE); + if (list_join(&ga, tv->vval.v_list, (char_u *)", ", FALSE) == FAIL) + { + vim_free(ga.ga_data); + return NULL; + } ga_append(&ga, ']'); ga_append(&ga, NUL); return (char_u *)ga.ga_data; @@ -5063,8 +5087,9 @@ list2string(tv) /* * Join list "l" into a string in "*gap", using separator "sep". * When "echo" is TRUE use String as echoed, otherwise as inside a List. - */ - static void + * Return FAIL or OK. + */ + static int list_join(gap, l, sep, echo) garray_T *gap; list_T *l; @@ -5077,7 +5102,7 @@ list_join(gap, l, sep, echo) listitem_T *item; char_u *s; - for (item = l->lv_first; item != NULL; item = item->li_next) + for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) { if (first) first = FALSE; @@ -5091,7 +5116,10 @@ list_join(gap, l, sep, echo) if (s != NULL) ga_concat(gap, s); vim_free(tofree); - } + if (s == NULL) + return FAIL; + } + return OK; } /* @@ -5108,6 +5136,7 @@ dict_alloc() hash_init(&d->dv_hashtab); d->dv_lock = 0; d->dv_refcount = 0; + d->dv_copyID = 0; } return d; } @@ -5222,12 +5251,14 @@ dictitem_free(item) /* * Make a copy of dict "d". Shallow if "deep" is FALSE. * The refcount of the new dict is set to 1. + * See item_copy() for "copyID". * Returns NULL when out of memory. */ static dict_T * -dict_copy(orig, deep) +dict_copy(orig, deep, copyID) dict_T *orig; int deep; + int copyID; { dict_T *copy; dictitem_T *di; @@ -5240,8 +5271,13 @@ dict_copy(orig, deep) copy = dict_alloc(); if (copy != NULL) { + if (copyID != 0) + { + orig->dv_copyID = copyID; + orig->dv_copydict = copy; + } todo = orig->dv_hashtab.ht_used; - for (hi = orig->dv_hashtab.ht_array; todo > 0; ++hi) + for (hi = orig->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi) { if (!HASHITEM_EMPTY(hi)) { @@ -5251,7 +5287,14 @@ dict_copy(orig, deep) if (di == NULL) break; if (deep) - item_copy(&HI2DI(hi)->di_tv, &di->di_tv, deep); + { + if (item_copy(&HI2DI(hi)->di_tv, &di->di_tv, deep, + copyID) == FAIL) + { + vim_free(di); + break; + } + } else copy_tv(&HI2DI(hi)->di_tv, &di->di_tv); if (dict_add(copy, di) == FAIL) @@ -5263,6 +5306,11 @@ dict_copy(orig, deep) } ++copy->dv_refcount; + if (todo > 0) + { + dict_unref(copy); + copy = NULL; + } } return copy; @@ -5355,7 +5403,7 @@ dict2string(tv) ga_append(&ga, '{'); todo = d->dv_hashtab.ht_used; - for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) + for (hi = d->dv_hashtab.ht_array; todo > 0 && !got_int; ++hi) { if (!HASHITEM_EMPTY(hi)) { @@ -5377,7 +5425,14 @@ dict2string(tv) if (s != NULL) ga_concat(&ga, s); vim_free(tofree); - } + if (s == NULL) + break; + } + } + if (todo > 0) + { + vim_free(ga.ga_data); + return NULL; } ga_append(&ga, '}'); @@ -5721,7 +5776,7 @@ static struct fst {"count", 2, 4, f_count}, {"cscope_connection",0,3, f_cscope_connection}, {"cursor", 2, 2, f_cursor}, - {"deepcopy", 1, 1, f_deepcopy}, + {"deepcopy", 1, 2, f_deepcopy}, {"delete", 1, 1, f_delete}, {"did_filetype", 0, 0, f_did_filetype}, {"diff_filler", 1, 1, f_diff_filler}, @@ -6043,9 +6098,9 @@ get_func_tv(name, len, rettv, arg, first else if (!aborting()) { if (argcount == MAX_FUNC_ARGS) - EMSG2(_("E740: Too many arguments for function %s"), name); - else - EMSG2(_("E116: Invalid arguments for function %s"), name); + emsg_funcname("E740: Too many arguments for function %s", name); + else + emsg_funcname("E116: Invalid arguments for function %s", name); } while (--argcount >= 0) @@ -6247,21 +6302,21 @@ call_func(name, len, rettv, argcount, ar switch (error) { case ERROR_UNKNOWN: - EMSG2(_("E117: Unknown function: %s"), name); + emsg_funcname("E117: Unknown function: %s", name); break; case ERROR_TOOMANY: - EMSG2(_(e_toomanyarg), name); + emsg_funcname(e_toomanyarg, name); break; case ERROR_TOOFEW: - EMSG2(_("E119: Not enough arguments for function: %s"), + emsg_funcname("E119: Not enough arguments for function: %s", name); break; case ERROR_SCRIPT: - EMSG2(_("E120: Using not in a script context: %s"), + emsg_funcname("E120: Using not in a script context: %s", name); break; case ERROR_DICT: - EMSG2(_("E725: Calling dict function without Dictionary: %s"), + emsg_funcname("E725: Calling dict function without Dictionary: %s", name); break; } @@ -6274,6 +6329,25 @@ call_func(name, len, rettv, argcount, ar return ret; } +/* + * Give an error message with a function name. Handle things. + */ + static void +emsg_funcname(msg, name) + char *msg; + char_u *name; +{ + char_u *p; + + if (*name == K_SPECIAL) + p = concat_str((char_u *)"", name + 3); + else + p = name; + EMSG2(_(msg), p); + if (p != name) + vim_free(p); +} + /********************************************* * Implementation of the built-in functions */ @@ -6906,7 +6980,7 @@ f_copy(argvars, rettv) typval_T *argvars; typval_T *rettv; { - item_copy(&argvars[0], rettv, FALSE); + item_copy(&argvars[0], rettv, FALSE, 0); } /* @@ -7052,7 +7126,15 @@ f_deepcopy(argvars, rettv) typval_T *argvars; typval_T *rettv; { - item_copy(&argvars[0], rettv, TRUE); + static int copyID = 0; + int noref = 0; + + if (argvars[1].v_type != VAR_UNKNOWN) + noref = get_tv_number(&argvars[1]); + if (noref < 0 || noref > 1) + EMSG(_(e_invarg)); + else + item_copy(&argvars[0], rettv, TRUE, noref == 0 ? ++copyID : 0); } /* @@ -10200,7 +10282,7 @@ find_some_match(argvars, rettv, type) char_u *save_cpo; long start = 0; long nth = 1; - int match; + int match = 0; list_T *l = NULL; listitem_T *li = NULL; long idx = 0; @@ -10275,6 +10357,8 @@ find_some_match(argvars, rettv, type) } vim_free(tofree); str = echo_string(&li->li_tv, &tofree, strbuf); + if (str == NULL) + break; } match = vim_regexec_nl(®match, str, (colnr_T)0); @@ -11394,7 +11478,7 @@ f_reverse(argvars, rettv) && !tv_check_lock(l->lv_lock, (char_u *)"reverse()")) { li = l->lv_last; - l->lv_first = l->lv_last = li; + l->lv_first = l->lv_last = NULL; l->lv_len = 0; while (li != NULL) { @@ -14338,7 +14422,8 @@ set_var(name, tv, copy) } if (function_exists(name)) { - EMSG2(_("705: Variable name conflicts with existing function: %s"), name); + EMSG2(_("705: Variable name conflicts with existing function: %s"), + name); return; } } @@ -14520,19 +14605,24 @@ copy_tv(from, to) /* * Make a copy of an item. * Lists and Dictionaries are also copied. A deep copy if "deep" is set. - */ - static void -item_copy(from, to, deep) + * For deepcopy() "copyID" is zero for a full copy or the ID for when a + * reference to an already copied list/dict can be used. + * Returns FAIL or OK. + */ + static int +item_copy(from, to, deep, copyID) typval_T *from; typval_T *to; int deep; + int copyID; { static int recurse = 0; + int ret = OK; if (recurse >= DICT_MAXNEST) { EMSG(_("E698: variable nested too deep for making a copy")); - return; + return FAIL; } ++recurse; @@ -14546,17 +14636,41 @@ item_copy(from, to, deep) case VAR_LIST: to->v_type = VAR_LIST; to->v_lock = 0; - to->vval.v_list = list_copy(from->vval.v_list, deep); + if (from->vval.v_list == NULL) + to->vval.v_list = NULL; + else if (copyID != 0 && from->vval.v_list->lv_copyID == copyID) + { + /* use the copy made earlier */ + to->vval.v_list = from->vval.v_list->lv_copylist; + ++to->vval.v_list->lv_refcount; + } + else + to->vval.v_list = list_copy(from->vval.v_list, deep, copyID); + if (to->vval.v_list == NULL) + ret = FAIL; break; case VAR_DICT: to->v_type = VAR_DICT; to->v_lock = 0; - to->vval.v_dict = dict_copy(from->vval.v_dict, deep); + if (from->vval.v_dict == NULL) + to->vval.v_dict = NULL; + else if (copyID != 0 && from->vval.v_dict->dv_copyID == copyID) + { + /* use the copy made earlier */ + to->vval.v_dict = from->vval.v_dict->dv_copydict; + ++to->vval.v_dict->dv_refcount; + } + else + to->vval.v_dict = dict_copy(from->vval.v_dict, deep, copyID); + if (to->vval.v_dict == NULL) + ret = FAIL; break; default: EMSG2(_(e_intern2), "item_copy()"); + ret = FAIL; } --recurse; + return ret; } /* @@ -14604,31 +14718,34 @@ ex_echo(eap) } else if (eap->cmdidx == CMD_echo) msg_puts_attr((char_u *)" ", echo_attr); - for (p = echo_string(&rettv, &tofree, numbuf); - *p != NUL && !got_int; ++p) - if (*p == '\n' || *p == '\r' || *p == TAB) - { - if (*p != TAB && needclr) + p = echo_string(&rettv, &tofree, numbuf); + if (p != NULL) + for ( ; *p != NUL && !got_int; ++p) + { + if (*p == '\n' || *p == '\r' || *p == TAB) { - /* remove any text still there from the command */ - msg_clr_eos(); - needclr = FALSE; - } - msg_putchar_attr(*p, echo_attr); - } - else - { -#ifdef FEAT_MBYTE - if (has_mbyte) - { - int i = (*mb_ptr2len_check)(p); - - (void)msg_outtrans_len_attr(p, i, echo_attr); - p += i - 1; + if (*p != TAB && needclr) + { + /* remove any text still there from the command */ + msg_clr_eos(); + needclr = FALSE; + } + msg_putchar_attr(*p, echo_attr); } else -#endif - (void)msg_outtrans_len_attr(p, 1, echo_attr); + { +#ifdef FEAT_MBYTE + if (has_mbyte) + { + int i = (*mb_ptr2len_check)(p); + + (void)msg_outtrans_len_attr(p, i, echo_attr); + p += i - 1; + } + else +#endif + (void)msg_outtrans_len_attr(p, 1, echo_attr); + } } vim_free(tofree); } @@ -14906,7 +15023,7 @@ ex_function(eap) } } else - EMSG2(_("E123: Undefined function: %s"), name); + emsg_funcname("E123: Undefined function: %s", name); } goto ret_free; } @@ -15019,7 +15136,7 @@ ex_function(eap) if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL) EMSG(_(e_funcdict)); else if (name != NULL && find_func(name) != NULL) - EMSG2(_(e_funcexts), name); + emsg_funcname(e_funcexts, name); } msg_putchar('\n'); /* don't overwrite the function name */ @@ -15146,7 +15263,8 @@ ex_function(eap) v = find_var(name, NULL); if (v != NULL && v->di_tv.v_type == VAR_FUNC) { - EMSG2(_("E707: Function name conflicts with variable: %s"), name); + emsg_funcname("E707: Function name conflicts with variable: %s", + name); goto erret; } @@ -15155,12 +15273,12 @@ ex_function(eap) { if (!eap->forceit) { - EMSG2(_(e_funcexts), name); + emsg_funcname(e_funcexts, name); goto erret; } if (fp->calls > 0) { - EMSG2(_("E127: Cannot redefine function %s: It is in use"), + emsg_funcname("E127: Cannot redefine function %s: It is in use", name); goto erret; } @@ -16192,14 +16310,14 @@ discard_pending_return(rettv) get_return_cmd(rettv) void *rettv; { - char_u *s; + char_u *s = NULL; char_u *tofree = NULL; char_u numbuf[NUMBUFLEN]; - if (rettv == NULL) + if (rettv != NULL) + s = echo_string((typval_T *)rettv, &tofree, numbuf); + if (s == NULL) s = (char_u *)""; - else - s = echo_string((typval_T *)rettv, &tofree, numbuf); STRCPY(IObuff, ":return "); STRNCPY(IObuff + 8, s, IOSIZE - 8); @@ -16368,6 +16486,7 @@ write_viminfo_varlist(fp) dictitem_T *this_var; int todo; char *s; + char_u *p; char_u *tofree; char_u numbuf[NUMBUFLEN]; @@ -16392,8 +16511,9 @@ write_viminfo_varlist(fp) default: continue; } fprintf(fp, "!%s\t%s\t", this_var->di_key, s); - viminfo_writestring(fp, echo_string(&this_var->di_tv, - &tofree, numbuf)); + p = echo_string(&this_var->di_tv, &tofree, numbuf); + if (p != NULL) + viminfo_writestring(fp, p); vim_free(tofree); } } diff --git a/src/ex_cmds.c b/src/ex_cmds.c --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -3250,32 +3250,57 @@ ex_append(eap) char_u *theline; int did_undo = FALSE; linenr_T lnum = eap->line2; + int indent = 0; + char_u *p; + int vcol; + int empty = (curbuf->b_ml.ml_flags & ML_EMPTY); if (eap->cmdidx != CMD_append) --lnum; + /* when the buffer is empty append to line 0 and delete the dummy line */ + if (empty && lnum == 1) + lnum = 0; + State = INSERT; /* behave like in Insert mode */ if (curbuf->b_p_iminsert == B_IMODE_LMAP) State |= LANGMAP; + while (1) { msg_scroll = TRUE; need_wait_return = FALSE; + if (curbuf->b_p_ai && lnum > 0) + indent = get_indent_lnum(lnum); if (eap->getline == NULL) theline = getcmdline( #ifdef FEAT_EVAL eap->cstack->cs_looplevel > 0 ? -1 : #endif - NUL, 0L, 0); + NUL, 0L, indent); else theline = eap->getline( #ifdef FEAT_EVAL eap->cstack->cs_looplevel > 0 ? -1 : #endif - NUL, eap->cookie, 0); + NUL, eap->cookie, indent); lines_left = Rows - 1; - if (theline == NULL || (theline[0] == '.' && theline[1] == NUL) - || (!did_undo && u_save(lnum, lnum + 1) == FAIL)) + if (theline == NULL) + break; + + /* Look for the "." after automatic indent. */ + vcol = 0; + for (p = theline; indent > vcol; ++p) + { + if (*p == ' ') + ++vcol; + else if (*p == TAB) + vcol += 8 - vcol % 8; + else + break; + } + if ((p[0] == '.' && p[1] == NUL) + || (!did_undo && u_save(lnum, lnum + 1) == FAIL)) { vim_free(theline); break; @@ -3288,6 +3313,12 @@ ex_append(eap) vim_free(theline); ++lnum; msg_didout = TRUE; /* also scroll for empty line */ + + if (empty) + { + ml_delete(2L, FALSE); + empty = FALSE; + } } State = NORMAL; @@ -3341,14 +3372,22 @@ ex_z(eap) exarg_T *eap; { char_u *x; - int bigness = curwin->w_height - 3; - char_u kind; + int bigness; + char_u *kind; int numbered = FALSE; int minus = 0; linenr_T start, end, curs, i; int j; linenr_T lnum = eap->line2; + /* Vi compatible: ":z!" uses display height, without a count uses + * 'scroll' */ + if (eap->forceit) + bigness = curwin->w_height; + else if (firstwin == lastwin) + bigness = curwin->w_p_scr * 2; + else + bigness = curwin->w_height - 3; if (bigness < 1) bigness = 1; @@ -3359,8 +3398,11 @@ ex_z(eap) ++x; } - kind = *x; - if (kind == '-' || kind == '+' || kind == '=' || kind == '^' || kind == '.') + kind = x; + if (*kind == '-' || *kind == '+' || *kind == '=' + || *kind == '^' || *kind == '.') + ++x; + while (*x == '-' || *x == '+') ++x; if (*x != 0) @@ -3371,15 +3413,23 @@ ex_z(eap) return; } else + { bigness = atoi((char *)x); + p_window = bigness; + } } - switch (kind) + /* the number of '-' and '+' multiplies the distance */ + if (*kind == '-' || *kind == '+') + for (x = kind + 1; *x == *kind; ++x) + ; + + switch (*kind) { case '-': - start = lnum - bigness; - end = lnum; - curs = lnum; + start = lnum - bigness * (x - kind); + end = start + bigness; + curs = end; break; case '=': @@ -3403,7 +3453,9 @@ ex_z(eap) default: /* '+' */ start = lnum; - end = lnum + bigness; + if (*kind == '+') + start += bigness * (x - kind - 1); + end = start + bigness; curs = end; break; } @@ -3526,15 +3578,15 @@ do_sub(eap) int which_pat; char_u *cmd; int save_State; - linenr_T first_line = 0; /* first changed line */ - linenr_T last_line= 0; /* below last changed line AFTER the + linenr_T first_line = 0; /* first changed line */ + linenr_T last_line= 0; /* below last changed line AFTER the * change */ linenr_T old_line_count = curbuf->b_ml.ml_line_count; linenr_T line2; - long nmatch; /* number of lines in match */ - linenr_T sub_firstlnum; /* nr of first sub line */ - char_u *sub_firstline; /* allocated copy of first sub line */ - int endcolumn; /* put cursor in last column when done */ + long nmatch; /* number of lines in match */ + linenr_T sub_firstlnum; /* nr of first sub line */ + char_u *sub_firstline; /* allocated copy of first sub line */ + int endcolumn = FALSE; /* cursor in last column when done */ cmd = eap->arg; if (!global_busy) diff --git a/src/memline.c b/src/memline.c --- a/src/memline.c +++ b/src/memline.c @@ -609,6 +609,7 @@ ml_close(buf, del_file) * Close all existing memlines and memfiles. * Only used when exiting. * When 'del_file' is TRUE, delete the memfiles. + * But don't delete files that were ":preserve"d when we are POSIX compatible. */ void ml_close_all(del_file) @@ -617,7 +618,8 @@ ml_close_all(del_file) buf_T *buf; for (buf = firstbuf; buf != NULL; buf = buf->b_next) - ml_close(buf, del_file); + ml_close(buf, del_file && ((buf->b_flags & BF_PRESERVED) == 0 + || vim_strchr(p_cpo, CPO_PRESERVE) == NULL)); #ifdef TEMPDIRNAMES vim_deltempdir(); /* delete created temp directory */ #endif