1/* vi:set ts=8 sts=4 sw=4: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10/* 11 * undo.c: multi level undo facility 12 * 13 * The saved lines are stored in a list of lists (one for each buffer): 14 * 15 * b_u_oldhead------------------------------------------------+ 16 * | 17 * V 18 * +--------------+ +--------------+ +--------------+ 19 * b_u_newhead--->| u_header | | u_header | | u_header | 20 * | uh_next------>| uh_next------>| uh_next---->NULL 21 * NULL<--------uh_prev |<---------uh_prev |<---------uh_prev | 22 * | uh_entry | | uh_entry | | uh_entry | 23 * +--------|-----+ +--------|-----+ +--------|-----+ 24 * | | | 25 * V V V 26 * +--------------+ +--------------+ +--------------+ 27 * | u_entry | | u_entry | | u_entry | 28 * | ue_next | | ue_next | | ue_next | 29 * +--------|-----+ +--------|-----+ +--------|-----+ 30 * | | | 31 * V V V 32 * +--------------+ NULL NULL 33 * | u_entry | 34 * | ue_next | 35 * +--------|-----+ 36 * | 37 * V 38 * etc. 39 * 40 * Each u_entry list contains the information for one undo or redo. 41 * curbuf->b_u_curhead points to the header of the last undo (the next redo), 42 * or is NULL if nothing has been undone (end of the branch). 43 * 44 * For keeping alternate undo/redo branches the uh_alt field is used. Thus at 45 * each point in the list a branch may appear for an alternate to redo. The 46 * uh_seq field is numbered sequentially to be able to find a newer or older 47 * branch. 48 * 49 * +---------------+ +---------------+ 50 * b_u_oldhead --->| u_header | | u_header | 51 * | uh_alt_next ---->| uh_alt_next ----> NULL 52 * NULL <----- uh_alt_prev |<------ uh_alt_prev | 53 * | uh_prev | | uh_prev | 54 * +-----|---------+ +-----|---------+ 55 * | | 56 * V V 57 * +---------------+ +---------------+ 58 * | u_header | | u_header | 59 * | uh_alt_next | | uh_alt_next | 60 * b_u_newhead --->| uh_alt_prev | | uh_alt_prev | 61 * | uh_prev | | uh_prev | 62 * +-----|---------+ +-----|---------+ 63 * | | 64 * V V 65 * NULL +---------------+ +---------------+ 66 * | u_header | | u_header | 67 * | uh_alt_next ---->| uh_alt_next | 68 * | uh_alt_prev |<------ uh_alt_prev | 69 * | uh_prev | | uh_prev | 70 * +-----|---------+ +-----|---------+ 71 * | | 72 * etc. etc. 73 * 74 * 75 * All data is allocated and will all be freed when the buffer is unloaded. 76 */ 77 78/* Uncomment the next line for including the u_check() function. This warns 79 * for errors in the debug information. */ 80/* #define U_DEBUG 1 */ 81#define UH_MAGIC 0x18dade /* value for uh_magic when in use */ 82#define UE_MAGIC 0xabc123 /* value for ue_magic when in use */ 83 84#if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64) 85# include "vimio.h" /* for vim_read(), must be before vim.h */ 86#endif 87 88#include "vim.h" 89 90static void u_unch_branch __ARGS((u_header_T *uhp)); 91static u_entry_T *u_get_headentry __ARGS((void)); 92static void u_getbot __ARGS((void)); 93static void u_doit __ARGS((int count)); 94static void u_undoredo __ARGS((int undo)); 95static void u_undo_end __ARGS((int did_undo, int absolute)); 96static void u_add_time __ARGS((char_u *buf, size_t buflen, time_t tt)); 97static void u_freeheader __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); 98static void u_freebranch __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); 99static void u_freeentries __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); 100static void u_freeentry __ARGS((u_entry_T *, long)); 101#ifdef FEAT_PERSISTENT_UNDO 102static void corruption_error __ARGS((char *mesg, char_u *file_name)); 103static void u_free_uhp __ARGS((u_header_T *uhp)); 104static size_t fwrite_crypt __ARGS((buf_T *buf UNUSED, char_u *ptr, size_t len, FILE *fp)); 105static char_u *read_string_decrypt __ARGS((buf_T *buf UNUSED, FILE *fd, int len)); 106static int serialize_header __ARGS((FILE *fp, buf_T *buf, char_u *hash)); 107static int serialize_uhp __ARGS((FILE *fp, buf_T *buf, u_header_T *uhp)); 108static u_header_T *unserialize_uhp __ARGS((FILE *fp, char_u *file_name)); 109static int serialize_uep __ARGS((FILE *fp, buf_T *buf, u_entry_T *uep)); 110static u_entry_T *unserialize_uep __ARGS((FILE *fp, int *error, char_u *file_name)); 111static void serialize_pos __ARGS((pos_T pos, FILE *fp)); 112static void unserialize_pos __ARGS((pos_T *pos, FILE *fp)); 113static void serialize_visualinfo __ARGS((visualinfo_T *info, FILE *fp)); 114static void unserialize_visualinfo __ARGS((visualinfo_T *info, FILE *fp)); 115static void put_header_ptr __ARGS((FILE *fp, u_header_T *uhp)); 116#endif 117 118#define U_ALLOC_LINE(size) lalloc((long_u)(size), FALSE) 119static char_u *u_save_line __ARGS((linenr_T)); 120 121/* used in undo_end() to report number of added and deleted lines */ 122static long u_newcount, u_oldcount; 123 124/* 125 * When 'u' flag included in 'cpoptions', we behave like vi. Need to remember 126 * the action that "u" should do. 127 */ 128static int undo_undoes = FALSE; 129 130static int lastmark = 0; 131 132#if defined(U_DEBUG) || defined(PROTO) 133/* 134 * Check the undo structures for being valid. Print a warning when something 135 * looks wrong. 136 */ 137static int seen_b_u_curhead; 138static int seen_b_u_newhead; 139static int header_count; 140 141 static void 142u_check_tree(u_header_T *uhp, 143 u_header_T *exp_uh_next, 144 u_header_T *exp_uh_alt_prev) 145{ 146 u_entry_T *uep; 147 148 if (uhp == NULL) 149 return; 150 ++header_count; 151 if (uhp == curbuf->b_u_curhead && ++seen_b_u_curhead > 1) 152 { 153 EMSG("b_u_curhead found twice (looping?)"); 154 return; 155 } 156 if (uhp == curbuf->b_u_newhead && ++seen_b_u_newhead > 1) 157 { 158 EMSG("b_u_newhead found twice (looping?)"); 159 return; 160 } 161 162 if (uhp->uh_magic != UH_MAGIC) 163 EMSG("uh_magic wrong (may be using freed memory)"); 164 else 165 { 166 /* Check pointers back are correct. */ 167 if (uhp->uh_next.ptr != exp_uh_next) 168 { 169 EMSG("uh_next wrong"); 170 smsg((char_u *)"expected: 0x%x, actual: 0x%x", 171 exp_uh_next, uhp->uh_next.ptr); 172 } 173 if (uhp->uh_alt_prev.ptr != exp_uh_alt_prev) 174 { 175 EMSG("uh_alt_prev wrong"); 176 smsg((char_u *)"expected: 0x%x, actual: 0x%x", 177 exp_uh_alt_prev, uhp->uh_alt_prev.ptr); 178 } 179 180 /* Check the undo tree at this header. */ 181 for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next) 182 { 183 if (uep->ue_magic != UE_MAGIC) 184 { 185 EMSG("ue_magic wrong (may be using freed memory)"); 186 break; 187 } 188 } 189 190 /* Check the next alt tree. */ 191 u_check_tree(uhp->uh_alt_next.ptr, uhp->uh_next.ptr, uhp); 192 193 /* Check the next header in this branch. */ 194 u_check_tree(uhp->uh_prev.ptr, uhp, NULL); 195 } 196} 197 198 static void 199u_check(int newhead_may_be_NULL) 200{ 201 seen_b_u_newhead = 0; 202 seen_b_u_curhead = 0; 203 header_count = 0; 204 205 u_check_tree(curbuf->b_u_oldhead, NULL, NULL); 206 207 if (seen_b_u_newhead == 0 && curbuf->b_u_oldhead != NULL 208 && !(newhead_may_be_NULL && curbuf->b_u_newhead == NULL)) 209 EMSGN("b_u_newhead invalid: 0x%x", curbuf->b_u_newhead); 210 if (curbuf->b_u_curhead != NULL && seen_b_u_curhead == 0) 211 EMSGN("b_u_curhead invalid: 0x%x", curbuf->b_u_curhead); 212 if (header_count != curbuf->b_u_numhead) 213 { 214 EMSG("b_u_numhead invalid"); 215 smsg((char_u *)"expected: %ld, actual: %ld", 216 (long)header_count, (long)curbuf->b_u_numhead); 217 } 218} 219#endif 220 221/* 222 * Save the current line for both the "u" and "U" command. 223 * Returns OK or FAIL. 224 */ 225 int 226u_save_cursor() 227{ 228 return (u_save((linenr_T)(curwin->w_cursor.lnum - 1), 229 (linenr_T)(curwin->w_cursor.lnum + 1))); 230} 231 232/* 233 * Save the lines between "top" and "bot" for both the "u" and "U" command. 234 * "top" may be 0 and bot may be curbuf->b_ml.ml_line_count + 1. 235 * Careful: may trigger autocommands that reload the buffer. 236 * Returns FAIL when lines could not be saved, OK otherwise. 237 */ 238 int 239u_save(top, bot) 240 linenr_T top, bot; 241{ 242 if (undo_off) 243 return OK; 244 245 if (top > curbuf->b_ml.ml_line_count || 246 top >= bot || bot > curbuf->b_ml.ml_line_count + 1) 247 return FALSE; /* rely on caller to do error messages */ 248 249 if (top + 2 == bot) 250 u_saveline((linenr_T)(top + 1)); 251 252 return (u_savecommon(top, bot, (linenr_T)0, FALSE)); 253} 254 255/* 256 * Save the line "lnum" (used by ":s" and "~" command). 257 * The line is replaced, so the new bottom line is lnum + 1. 258 * Careful: may trigger autocommands that reload the buffer. 259 * Returns FAIL when lines could not be saved, OK otherwise. 260 */ 261 int 262u_savesub(lnum) 263 linenr_T lnum; 264{ 265 if (undo_off) 266 return OK; 267 268 return (u_savecommon(lnum - 1, lnum + 1, lnum + 1, FALSE)); 269} 270 271/* 272 * A new line is inserted before line "lnum" (used by :s command). 273 * The line is inserted, so the new bottom line is lnum + 1. 274 * Careful: may trigger autocommands that reload the buffer. 275 * Returns FAIL when lines could not be saved, OK otherwise. 276 */ 277 int 278u_inssub(lnum) 279 linenr_T lnum; 280{ 281 if (undo_off) 282 return OK; 283 284 return (u_savecommon(lnum - 1, lnum, lnum + 1, FALSE)); 285} 286 287/* 288 * Save the lines "lnum" - "lnum" + nlines (used by delete command). 289 * The lines are deleted, so the new bottom line is lnum, unless the buffer 290 * becomes empty. 291 * Careful: may trigger autocommands that reload the buffer. 292 * Returns FAIL when lines could not be saved, OK otherwise. 293 */ 294 int 295u_savedel(lnum, nlines) 296 linenr_T lnum; 297 long nlines; 298{ 299 if (undo_off) 300 return OK; 301 302 return (u_savecommon(lnum - 1, lnum + nlines, 303 nlines == curbuf->b_ml.ml_line_count ? 2 : lnum, FALSE)); 304} 305 306/* 307 * Return TRUE when undo is allowed. Otherwise give an error message and 308 * return FALSE. 309 */ 310 int 311undo_allowed() 312{ 313 /* Don't allow changes when 'modifiable' is off. */ 314 if (!curbuf->b_p_ma) 315 { 316 EMSG(_(e_modifiable)); 317 return FALSE; 318 } 319 320#ifdef HAVE_SANDBOX 321 /* In the sandbox it's not allowed to change the text. */ 322 if (sandbox != 0) 323 { 324 EMSG(_(e_sandbox)); 325 return FALSE; 326 } 327#endif 328 329 /* Don't allow changes in the buffer while editing the cmdline. The 330 * caller of getcmdline() may get confused. */ 331 if (textlock != 0) 332 { 333 EMSG(_(e_secure)); 334 return FALSE; 335 } 336 337 return TRUE; 338} 339 340/* 341 * Common code for various ways to save text before a change. 342 * "top" is the line above the first changed line. 343 * "bot" is the line below the last changed line. 344 * "newbot" is the new bottom line. Use zero when not known. 345 * "reload" is TRUE when saving for a buffer reload. 346 * Careful: may trigger autocommands that reload the buffer. 347 * Returns FAIL when lines could not be saved, OK otherwise. 348 */ 349 int 350u_savecommon(top, bot, newbot, reload) 351 linenr_T top, bot; 352 linenr_T newbot; 353 int reload; 354{ 355 linenr_T lnum; 356 long i; 357 u_header_T *uhp; 358 u_header_T *old_curhead; 359 u_entry_T *uep; 360 u_entry_T *prev_uep; 361 long size; 362 363 if (!reload) 364 { 365 /* When making changes is not allowed return FAIL. It's a crude way 366 * to make all change commands fail. */ 367 if (!undo_allowed()) 368 return FAIL; 369 370#ifdef FEAT_NETBEANS_INTG 371 /* 372 * Netbeans defines areas that cannot be modified. Bail out here when 373 * trying to change text in a guarded area. 374 */ 375 if (netbeans_active()) 376 { 377 if (netbeans_is_guarded(top, bot)) 378 { 379 EMSG(_(e_guarded)); 380 return FAIL; 381 } 382 if (curbuf->b_p_ro) 383 { 384 EMSG(_(e_nbreadonly)); 385 return FAIL; 386 } 387 } 388#endif 389 390#ifdef FEAT_AUTOCMD 391 /* 392 * Saving text for undo means we are going to make a change. Give a 393 * warning for a read-only file before making the change, so that the 394 * FileChangedRO event can replace the buffer with a read-write version 395 * (e.g., obtained from a source control system). 396 */ 397 change_warning(0); 398 if (bot > curbuf->b_ml.ml_line_count + 1) 399 { 400 /* This happens when the FileChangedRO autocommand changes the 401 * file in a way it becomes shorter. */ 402 EMSG(_("E834: Line count changed unexpectedly")); 403 return FAIL; 404 } 405#endif 406 } 407 408#ifdef U_DEBUG 409 u_check(FALSE); 410#endif 411 412 size = bot - top - 1; 413 414 /* 415 * If curbuf->b_u_synced == TRUE make a new header. 416 */ 417 if (curbuf->b_u_synced) 418 { 419#ifdef FEAT_JUMPLIST 420 /* Need to create new entry in b_changelist. */ 421 curbuf->b_new_change = TRUE; 422#endif 423 424 if (p_ul >= 0) 425 { 426 /* 427 * Make a new header entry. Do this first so that we don't mess 428 * up the undo info when out of memory. 429 */ 430 uhp = (u_header_T *)U_ALLOC_LINE(sizeof(u_header_T)); 431 if (uhp == NULL) 432 goto nomem; 433#ifdef U_DEBUG 434 uhp->uh_magic = UH_MAGIC; 435#endif 436 } 437 else 438 uhp = NULL; 439 440 /* 441 * If we undid more than we redid, move the entry lists before and 442 * including curbuf->b_u_curhead to an alternate branch. 443 */ 444 old_curhead = curbuf->b_u_curhead; 445 if (old_curhead != NULL) 446 { 447 curbuf->b_u_newhead = old_curhead->uh_next.ptr; 448 curbuf->b_u_curhead = NULL; 449 } 450 451 /* 452 * free headers to keep the size right 453 */ 454 while (curbuf->b_u_numhead > p_ul && curbuf->b_u_oldhead != NULL) 455 { 456 u_header_T *uhfree = curbuf->b_u_oldhead; 457 458 if (uhfree == old_curhead) 459 /* Can't reconnect the branch, delete all of it. */ 460 u_freebranch(curbuf, uhfree, &old_curhead); 461 else if (uhfree->uh_alt_next.ptr == NULL) 462 /* There is no branch, only free one header. */ 463 u_freeheader(curbuf, uhfree, &old_curhead); 464 else 465 { 466 /* Free the oldest alternate branch as a whole. */ 467 while (uhfree->uh_alt_next.ptr != NULL) 468 uhfree = uhfree->uh_alt_next.ptr; 469 u_freebranch(curbuf, uhfree, &old_curhead); 470 } 471#ifdef U_DEBUG 472 u_check(TRUE); 473#endif 474 } 475 476 if (uhp == NULL) /* no undo at all */ 477 { 478 if (old_curhead != NULL) 479 u_freebranch(curbuf, old_curhead, NULL); 480 curbuf->b_u_synced = FALSE; 481 return OK; 482 } 483 484 uhp->uh_prev.ptr = NULL; 485 uhp->uh_next.ptr = curbuf->b_u_newhead; 486 uhp->uh_alt_next.ptr = old_curhead; 487 if (old_curhead != NULL) 488 { 489 uhp->uh_alt_prev.ptr = old_curhead->uh_alt_prev.ptr; 490 if (uhp->uh_alt_prev.ptr != NULL) 491 uhp->uh_alt_prev.ptr->uh_alt_next.ptr = uhp; 492 old_curhead->uh_alt_prev.ptr = uhp; 493 if (curbuf->b_u_oldhead == old_curhead) 494 curbuf->b_u_oldhead = uhp; 495 } 496 else 497 uhp->uh_alt_prev.ptr = NULL; 498 if (curbuf->b_u_newhead != NULL) 499 curbuf->b_u_newhead->uh_prev.ptr = uhp; 500 501 uhp->uh_seq = ++curbuf->b_u_seq_last; 502 curbuf->b_u_seq_cur = uhp->uh_seq; 503 uhp->uh_time = time(NULL); 504 uhp->uh_save_nr = 0; 505 curbuf->b_u_time_cur = uhp->uh_time + 1; 506 507 uhp->uh_walk = 0; 508 uhp->uh_entry = NULL; 509 uhp->uh_getbot_entry = NULL; 510 uhp->uh_cursor = curwin->w_cursor; /* save cursor pos. for undo */ 511#ifdef FEAT_VIRTUALEDIT 512 if (virtual_active() && curwin->w_cursor.coladd > 0) 513 uhp->uh_cursor_vcol = getviscol(); 514 else 515 uhp->uh_cursor_vcol = -1; 516#endif 517 518 /* save changed and buffer empty flag for undo */ 519 uhp->uh_flags = (curbuf->b_changed ? UH_CHANGED : 0) + 520 ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0); 521 522 /* save named marks and Visual marks for undo */ 523 mch_memmove(uhp->uh_namedm, curbuf->b_namedm, sizeof(pos_T) * NMARKS); 524#ifdef FEAT_VISUAL 525 uhp->uh_visual = curbuf->b_visual; 526#endif 527 528 curbuf->b_u_newhead = uhp; 529 if (curbuf->b_u_oldhead == NULL) 530 curbuf->b_u_oldhead = uhp; 531 ++curbuf->b_u_numhead; 532 } 533 else 534 { 535 if (p_ul < 0) /* no undo at all */ 536 return OK; 537 538 /* 539 * When saving a single line, and it has been saved just before, it 540 * doesn't make sense saving it again. Saves a lot of memory when 541 * making lots of changes inside the same line. 542 * This is only possible if the previous change didn't increase or 543 * decrease the number of lines. 544 * Check the ten last changes. More doesn't make sense and takes too 545 * long. 546 */ 547 if (size == 1) 548 { 549 uep = u_get_headentry(); 550 prev_uep = NULL; 551 for (i = 0; i < 10; ++i) 552 { 553 if (uep == NULL) 554 break; 555 556 /* If lines have been inserted/deleted we give up. 557 * Also when the line was included in a multi-line save. */ 558 if ((curbuf->b_u_newhead->uh_getbot_entry != uep 559 ? (uep->ue_top + uep->ue_size + 1 560 != (uep->ue_bot == 0 561 ? curbuf->b_ml.ml_line_count + 1 562 : uep->ue_bot)) 563 : uep->ue_lcount != curbuf->b_ml.ml_line_count) 564 || (uep->ue_size > 1 565 && top >= uep->ue_top 566 && top + 2 <= uep->ue_top + uep->ue_size + 1)) 567 break; 568 569 /* If it's the same line we can skip saving it again. */ 570 if (uep->ue_size == 1 && uep->ue_top == top) 571 { 572 if (i > 0) 573 { 574 /* It's not the last entry: get ue_bot for the last 575 * entry now. Following deleted/inserted lines go to 576 * the re-used entry. */ 577 u_getbot(); 578 curbuf->b_u_synced = FALSE; 579 580 /* Move the found entry to become the last entry. The 581 * order of undo/redo doesn't matter for the entries 582 * we move it over, since they don't change the line 583 * count and don't include this line. It does matter 584 * for the found entry if the line count is changed by 585 * the executed command. */ 586 prev_uep->ue_next = uep->ue_next; 587 uep->ue_next = curbuf->b_u_newhead->uh_entry; 588 curbuf->b_u_newhead->uh_entry = uep; 589 } 590 591 /* The executed command may change the line count. */ 592 if (newbot != 0) 593 uep->ue_bot = newbot; 594 else if (bot > curbuf->b_ml.ml_line_count) 595 uep->ue_bot = 0; 596 else 597 { 598 uep->ue_lcount = curbuf->b_ml.ml_line_count; 599 curbuf->b_u_newhead->uh_getbot_entry = uep; 600 } 601 return OK; 602 } 603 prev_uep = uep; 604 uep = uep->ue_next; 605 } 606 } 607 608 /* find line number for ue_bot for previous u_save() */ 609 u_getbot(); 610 } 611 612#if !defined(UNIX) && !defined(DJGPP) && !defined(WIN32) && !defined(__EMX__) 613 /* 614 * With Amiga and MSDOS 16 bit we can't handle big undo's, because 615 * then u_alloc_line would have to allocate a block larger than 32K 616 */ 617 if (size >= 8000) 618 goto nomem; 619#endif 620 621 /* 622 * add lines in front of entry list 623 */ 624 uep = (u_entry_T *)U_ALLOC_LINE(sizeof(u_entry_T)); 625 if (uep == NULL) 626 goto nomem; 627 vim_memset(uep, 0, sizeof(u_entry_T)); 628#ifdef U_DEBUG 629 uep->ue_magic = UE_MAGIC; 630#endif 631 632 uep->ue_size = size; 633 uep->ue_top = top; 634 if (newbot != 0) 635 uep->ue_bot = newbot; 636 /* 637 * Use 0 for ue_bot if bot is below last line. 638 * Otherwise we have to compute ue_bot later. 639 */ 640 else if (bot > curbuf->b_ml.ml_line_count) 641 uep->ue_bot = 0; 642 else 643 { 644 uep->ue_lcount = curbuf->b_ml.ml_line_count; 645 curbuf->b_u_newhead->uh_getbot_entry = uep; 646 } 647 648 if (size > 0) 649 { 650 if ((uep->ue_array = (char_u **)U_ALLOC_LINE( 651 sizeof(char_u *) * size)) == NULL) 652 { 653 u_freeentry(uep, 0L); 654 goto nomem; 655 } 656 for (i = 0, lnum = top + 1; i < size; ++i) 657 { 658 fast_breakcheck(); 659 if (got_int) 660 { 661 u_freeentry(uep, i); 662 return FAIL; 663 } 664 if ((uep->ue_array[i] = u_save_line(lnum++)) == NULL) 665 { 666 u_freeentry(uep, i); 667 goto nomem; 668 } 669 } 670 } 671 else 672 uep->ue_array = NULL; 673 uep->ue_next = curbuf->b_u_newhead->uh_entry; 674 curbuf->b_u_newhead->uh_entry = uep; 675 curbuf->b_u_synced = FALSE; 676 undo_undoes = FALSE; 677 678#ifdef U_DEBUG 679 u_check(FALSE); 680#endif 681 return OK; 682 683nomem: 684 msg_silent = 0; /* must display the prompt */ 685 if (ask_yesno((char_u *)_("No undo possible; continue anyway"), TRUE) 686 == 'y') 687 { 688 undo_off = TRUE; /* will be reset when character typed */ 689 return OK; 690 } 691 do_outofmem_msg((long_u)0); 692 return FAIL; 693} 694 695#if defined(FEAT_PERSISTENT_UNDO) || defined(PROTO) 696 697# define UF_START_MAGIC "Vim\237UnDo\345" /* magic at start of undofile */ 698# define UF_START_MAGIC_LEN 9 699# define UF_HEADER_MAGIC 0x5fd0 /* magic at start of header */ 700# define UF_HEADER_END_MAGIC 0xe7aa /* magic after last header */ 701# define UF_ENTRY_MAGIC 0xf518 /* magic at start of entry */ 702# define UF_ENTRY_END_MAGIC 0x3581 /* magic after last entry */ 703# define UF_VERSION 2 /* 2-byte undofile version number */ 704# define UF_VERSION_CRYPT 0x8002 /* idem, encrypted */ 705 706/* extra fields for header */ 707# define UF_LAST_SAVE_NR 1 708 709/* extra fields for uhp */ 710# define UHP_SAVE_NR 1 711 712static char_u e_not_open[] = N_("E828: Cannot open undo file for writing: %s"); 713 714/* 715 * Compute the hash for the current buffer text into hash[UNDO_HASH_SIZE]. 716 */ 717 void 718u_compute_hash(hash) 719 char_u *hash; 720{ 721 context_sha256_T ctx; 722 linenr_T lnum; 723 char_u *p; 724 725 sha256_start(&ctx); 726 for (lnum = 1; lnum < curbuf->b_ml.ml_line_count; ++lnum) 727 { 728 p = ml_get(lnum); 729 sha256_update(&ctx, p, (UINT32_T)(STRLEN(p) + 1)); 730 } 731 sha256_finish(&ctx, hash); 732} 733 734/* 735 * Return an allocated string of the full path of the target undofile. 736 * When "reading" is TRUE find the file to read, go over all directories in 737 * 'undodir'. 738 * When "reading" is FALSE use the first name where the directory exists. 739 * Returns NULL when there is no place to write or no file to read. 740 */ 741 char_u * 742u_get_undo_file_name(buf_ffname, reading) 743 char_u *buf_ffname; 744 int reading; 745{ 746 char_u *dirp; 747 char_u dir_name[IOSIZE + 1]; 748 char_u *munged_name = NULL; 749 char_u *undo_file_name = NULL; 750 int dir_len; 751 char_u *p; 752 struct stat st; 753 char_u *ffname = buf_ffname; 754#ifdef HAVE_READLINK 755 char_u fname_buf[MAXPATHL]; 756#endif 757 758 if (ffname == NULL) 759 return NULL; 760 761#ifdef HAVE_READLINK 762 /* Expand symlink in the file name, so that we put the undo file with the 763 * actual file instead of with the symlink. */ 764 if (resolve_symlink(ffname, fname_buf) == OK) 765 ffname = fname_buf; 766#endif 767 768 /* Loop over 'undodir'. When reading find the first file that exists. 769 * When not reading use the first directory that exists or ".". */ 770 dirp = p_udir; 771 while (*dirp != NUL) 772 { 773 dir_len = copy_option_part(&dirp, dir_name, IOSIZE, ","); 774 if (dir_len == 1 && dir_name[0] == '.') 775 { 776 /* Use same directory as the ffname, 777 * "dir/name" -> "dir/.name.un~" */ 778 undo_file_name = vim_strnsave(ffname, (int)(STRLEN(ffname) + 5)); 779 if (undo_file_name == NULL) 780 break; 781 p = gettail(undo_file_name); 782 mch_memmove(p + 1, p, STRLEN(p) + 1); 783 *p = '.'; 784 STRCAT(p, ".un~"); 785 } 786 else 787 { 788 dir_name[dir_len] = NUL; 789 if (mch_isdir(dir_name)) 790 { 791 if (munged_name == NULL) 792 { 793 munged_name = vim_strsave(ffname); 794 if (munged_name == NULL) 795 return NULL; 796 for (p = munged_name; *p != NUL; mb_ptr_adv(p)) 797 if (vim_ispathsep(*p)) 798 *p = '%'; 799 } 800 undo_file_name = concat_fnames(dir_name, munged_name, TRUE); 801 } 802 } 803 804 /* When reading check if the file exists. */ 805 if (undo_file_name != NULL && (!reading 806 || mch_stat((char *)undo_file_name, &st) >= 0)) 807 break; 808 vim_free(undo_file_name); 809 undo_file_name = NULL; 810 } 811 812 vim_free(munged_name); 813 return undo_file_name; 814} 815 816 static void 817corruption_error(mesg, file_name) 818 char *mesg; 819 char_u *file_name; 820{ 821 EMSG3(_("E825: Corrupted undo file (%s): %s"), mesg, file_name); 822} 823 824 static void 825u_free_uhp(uhp) 826 u_header_T *uhp; 827{ 828 u_entry_T *nuep; 829 u_entry_T *uep; 830 831 uep = uhp->uh_entry; 832 while (uep != NULL) 833 { 834 nuep = uep->ue_next; 835 u_freeentry(uep, uep->ue_size); 836 uep = nuep; 837 } 838 vim_free(uhp); 839} 840 841/* 842 * Like fwrite() but crypt the bytes when 'key' is set. 843 * Returns 1 if successful. 844 */ 845 static size_t 846fwrite_crypt(buf, ptr, len, fp) 847 buf_T *buf UNUSED; 848 char_u *ptr; 849 size_t len; 850 FILE *fp; 851{ 852#ifdef FEAT_CRYPT 853 char_u *copy; 854 char_u small_buf[100]; 855 size_t i; 856 857 if (*buf->b_p_key == NUL) 858 return fwrite(ptr, len, (size_t)1, fp); 859 if (len < 100) 860 copy = small_buf; /* no malloc()/free() for short strings */ 861 else 862 { 863 copy = lalloc(len, FALSE); 864 if (copy == NULL) 865 return 0; 866 } 867 crypt_encode(ptr, len, copy); 868 i = fwrite(copy, len, (size_t)1, fp); 869 if (copy != small_buf) 870 vim_free(copy); 871 return i; 872#else 873 return fwrite(ptr, len, (size_t)1, fp); 874#endif 875} 876 877/* 878 * Read a string of length "len" from "fd". 879 * When 'key' is set decrypt the bytes. 880 */ 881 static char_u * 882read_string_decrypt(buf, fd, len) 883 buf_T *buf UNUSED; 884 FILE *fd; 885 int len; 886{ 887 char_u *ptr; 888 889 ptr = read_string(fd, len); 890#ifdef FEAT_CRYPT 891 if (ptr != NULL && *buf->b_p_key != NUL) 892 crypt_decode(ptr, len); 893#endif 894 return ptr; 895} 896 897 static int 898serialize_header(fp, buf, hash) 899 FILE *fp; 900 buf_T *buf; 901 char_u *hash; 902{ 903 int len; 904 905 /* Start writing, first the magic marker and undo info version. */ 906 if (fwrite(UF_START_MAGIC, (size_t)UF_START_MAGIC_LEN, (size_t)1, fp) != 1) 907 return FAIL; 908 909 /* If the buffer is encrypted then all text bytes following will be 910 * encrypted. Numbers and other info is not crypted. */ 911#ifdef FEAT_CRYPT 912 if (*buf->b_p_key != NUL) 913 { 914 char_u *header; 915 int header_len; 916 917 put_bytes(fp, (long_u)UF_VERSION_CRYPT, 2); 918 header = prepare_crypt_write(buf, &header_len); 919 if (header == NULL) 920 return FAIL; 921 len = (int)fwrite(header, (size_t)header_len, (size_t)1, fp); 922 vim_free(header); 923 if (len != 1) 924 { 925 crypt_pop_state(); 926 return FAIL; 927 } 928 } 929 else 930#endif 931 put_bytes(fp, (long_u)UF_VERSION, 2); 932 933 934 /* Write a hash of the buffer text, so that we can verify it is still the 935 * same when reading the buffer text. */ 936 if (fwrite(hash, (size_t)UNDO_HASH_SIZE, (size_t)1, fp) != 1) 937 return FAIL; 938 939 /* buffer-specific data */ 940 put_bytes(fp, (long_u)buf->b_ml.ml_line_count, 4); 941 len = buf->b_u_line_ptr != NULL ? (int)STRLEN(buf->b_u_line_ptr) : 0; 942 put_bytes(fp, (long_u)len, 4); 943 if (len > 0 && fwrite_crypt(buf, buf->b_u_line_ptr, (size_t)len, fp) != 1) 944 return FAIL; 945 put_bytes(fp, (long_u)buf->b_u_line_lnum, 4); 946 put_bytes(fp, (long_u)buf->b_u_line_colnr, 4); 947 948 /* Undo structures header data */ 949 put_header_ptr(fp, buf->b_u_oldhead); 950 put_header_ptr(fp, buf->b_u_newhead); 951 put_header_ptr(fp, buf->b_u_curhead); 952 953 put_bytes(fp, (long_u)buf->b_u_numhead, 4); 954 put_bytes(fp, (long_u)buf->b_u_seq_last, 4); 955 put_bytes(fp, (long_u)buf->b_u_seq_cur, 4); 956 put_time(fp, buf->b_u_time_cur); 957 958 /* Optional fields. */ 959 putc(4, fp); 960 putc(UF_LAST_SAVE_NR, fp); 961 put_bytes(fp, (long_u)buf->b_u_save_nr_last, 4); 962 963 putc(0, fp); /* end marker */ 964 965 return OK; 966} 967 968 static int 969serialize_uhp(fp, buf, uhp) 970 FILE *fp; 971 buf_T *buf; 972 u_header_T *uhp; 973{ 974 int i; 975 u_entry_T *uep; 976 977 if (put_bytes(fp, (long_u)UF_HEADER_MAGIC, 2) == FAIL) 978 return FAIL; 979 980 put_header_ptr(fp, uhp->uh_next.ptr); 981 put_header_ptr(fp, uhp->uh_prev.ptr); 982 put_header_ptr(fp, uhp->uh_alt_next.ptr); 983 put_header_ptr(fp, uhp->uh_alt_prev.ptr); 984 put_bytes(fp, uhp->uh_seq, 4); 985 serialize_pos(uhp->uh_cursor, fp); 986#ifdef FEAT_VIRTUALEDIT 987 put_bytes(fp, (long_u)uhp->uh_cursor_vcol, 4); 988#else 989 put_bytes(fp, (long_u)0, 4); 990#endif 991 put_bytes(fp, (long_u)uhp->uh_flags, 2); 992 /* Assume NMARKS will stay the same. */ 993 for (i = 0; i < NMARKS; ++i) 994 serialize_pos(uhp->uh_namedm[i], fp); 995#ifdef FEAT_VISUAL 996 serialize_visualinfo(&uhp->uh_visual, fp); 997#else 998 { 999 visualinfo_T info; 1000 1001 memset(&info, 0, sizeof(visualinfo_T)); 1002 serialize_visualinfo(&info, fp); 1003 } 1004#endif 1005 put_time(fp, uhp->uh_time); 1006 1007 /* Optional fields. */ 1008 putc(4, fp); 1009 putc(UHP_SAVE_NR, fp); 1010 put_bytes(fp, (long_u)uhp->uh_save_nr, 4); 1011 1012 putc(0, fp); /* end marker */ 1013 1014 /* Write all the entries. */ 1015 for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next) 1016 { 1017 put_bytes(fp, (long_u)UF_ENTRY_MAGIC, 2); 1018 if (serialize_uep(fp, buf, uep) == FAIL) 1019 return FAIL; 1020 } 1021 put_bytes(fp, (long_u)UF_ENTRY_END_MAGIC, 2); 1022 return OK; 1023} 1024 1025 static u_header_T * 1026unserialize_uhp(fp, file_name) 1027 FILE *fp; 1028 char_u *file_name; 1029{ 1030 u_header_T *uhp; 1031 int i; 1032 u_entry_T *uep, *last_uep; 1033 int c; 1034 int error; 1035 1036 uhp = (u_header_T *)U_ALLOC_LINE(sizeof(u_header_T)); 1037 if (uhp == NULL) 1038 return NULL; 1039 vim_memset(uhp, 0, sizeof(u_header_T)); 1040#ifdef U_DEBUG 1041 uhp->uh_magic = UH_MAGIC; 1042#endif 1043 uhp->uh_next.seq = get4c(fp); 1044 uhp->uh_prev.seq = get4c(fp); 1045 uhp->uh_alt_next.seq = get4c(fp); 1046 uhp->uh_alt_prev.seq = get4c(fp); 1047 uhp->uh_seq = get4c(fp); 1048 if (uhp->uh_seq <= 0) 1049 { 1050 corruption_error("uh_seq", file_name); 1051 vim_free(uhp); 1052 return NULL; 1053 } 1054 unserialize_pos(&uhp->uh_cursor, fp); 1055#ifdef FEAT_VIRTUALEDIT 1056 uhp->uh_cursor_vcol = get4c(fp); 1057#else 1058 (void)get4c(fp); 1059#endif 1060 uhp->uh_flags = get2c(fp); 1061 for (i = 0; i < NMARKS; ++i) 1062 unserialize_pos(&uhp->uh_namedm[i], fp); 1063#ifdef FEAT_VISUAL 1064 unserialize_visualinfo(&uhp->uh_visual, fp); 1065#else 1066 { 1067 visualinfo_T info; 1068 unserialize_visualinfo(&info, fp); 1069 } 1070#endif 1071 uhp->uh_time = get8ctime(fp); 1072 1073 /* Optional fields. */ 1074 for (;;) 1075 { 1076 int len = getc(fp); 1077 int what; 1078 1079 if (len == 0) 1080 break; 1081 what = getc(fp); 1082 switch (what) 1083 { 1084 case UHP_SAVE_NR: 1085 uhp->uh_save_nr = get4c(fp); 1086 break; 1087 default: 1088 /* field not supported, skip */ 1089 while (--len >= 0) 1090 (void)getc(fp); 1091 } 1092 } 1093 1094 /* Unserialize the uep list. */ 1095 last_uep = NULL; 1096 while ((c = get2c(fp)) == UF_ENTRY_MAGIC) 1097 { 1098 error = FALSE; 1099 uep = unserialize_uep(fp, &error, file_name); 1100 if (last_uep == NULL) 1101 uhp->uh_entry = uep; 1102 else 1103 last_uep->ue_next = uep; 1104 last_uep = uep; 1105 if (uep == NULL || error) 1106 { 1107 u_free_uhp(uhp); 1108 return NULL; 1109 } 1110 } 1111 if (c != UF_ENTRY_END_MAGIC) 1112 { 1113 corruption_error("entry end", file_name); 1114 u_free_uhp(uhp); 1115 return NULL; 1116 } 1117 1118 return uhp; 1119} 1120 1121/* 1122 * Serialize "uep" to "fp". 1123 */ 1124 static int 1125serialize_uep(fp, buf, uep) 1126 FILE *fp; 1127 buf_T *buf; 1128 u_entry_T *uep; 1129{ 1130 int i; 1131 size_t len; 1132 1133 put_bytes(fp, (long_u)uep->ue_top, 4); 1134 put_bytes(fp, (long_u)uep->ue_bot, 4); 1135 put_bytes(fp, (long_u)uep->ue_lcount, 4); 1136 put_bytes(fp, (long_u)uep->ue_size, 4); 1137 for (i = 0; i < uep->ue_size; ++i) 1138 { 1139 len = STRLEN(uep->ue_array[i]); 1140 if (put_bytes(fp, (long_u)len, 4) == FAIL) 1141 return FAIL; 1142 if (len > 0 && fwrite_crypt(buf, uep->ue_array[i], len, fp) != 1) 1143 return FAIL; 1144 } 1145 return OK; 1146} 1147 1148 static u_entry_T * 1149unserialize_uep(fp, error, file_name) 1150 FILE *fp; 1151 int *error; 1152 char_u *file_name; 1153{ 1154 int i; 1155 u_entry_T *uep; 1156 char_u **array; 1157 char_u *line; 1158 int line_len; 1159 1160 uep = (u_entry_T *)U_ALLOC_LINE(sizeof(u_entry_T)); 1161 if (uep == NULL) 1162 return NULL; 1163 vim_memset(uep, 0, sizeof(u_entry_T)); 1164#ifdef U_DEBUG 1165 uep->ue_magic = UE_MAGIC; 1166#endif 1167 uep->ue_top = get4c(fp); 1168 uep->ue_bot = get4c(fp); 1169 uep->ue_lcount = get4c(fp); 1170 uep->ue_size = get4c(fp); 1171 if (uep->ue_size > 0) 1172 { 1173 array = (char_u **)U_ALLOC_LINE(sizeof(char_u *) * uep->ue_size); 1174 if (array == NULL) 1175 { 1176 *error = TRUE; 1177 return uep; 1178 } 1179 vim_memset(array, 0, sizeof(char_u *) * uep->ue_size); 1180 } 1181 else 1182 array = NULL; 1183 uep->ue_array = array; 1184 1185 for (i = 0; i < uep->ue_size; ++i) 1186 { 1187 line_len = get4c(fp); 1188 if (line_len >= 0) 1189 line = read_string_decrypt(curbuf, fp, line_len); 1190 else 1191 { 1192 line = NULL; 1193 corruption_error("line length", file_name); 1194 } 1195 if (line == NULL) 1196 { 1197 *error = TRUE; 1198 return uep; 1199 } 1200 array[i] = line; 1201 } 1202 return uep; 1203} 1204 1205/* 1206 * Serialize "pos" to "fp". 1207 */ 1208 static void 1209serialize_pos(pos, fp) 1210 pos_T pos; 1211 FILE *fp; 1212{ 1213 put_bytes(fp, (long_u)pos.lnum, 4); 1214 put_bytes(fp, (long_u)pos.col, 4); 1215#ifdef FEAT_VIRTUALEDIT 1216 put_bytes(fp, (long_u)pos.coladd, 4); 1217#else 1218 put_bytes(fp, (long_u)0, 4); 1219#endif 1220} 1221 1222/* 1223 * Unserialize the pos_T at the current position in fp. 1224 */ 1225 static void 1226unserialize_pos(pos, fp) 1227 pos_T *pos; 1228 FILE *fp; 1229{ 1230 pos->lnum = get4c(fp); 1231 if (pos->lnum < 0) 1232 pos->lnum = 0; 1233 pos->col = get4c(fp); 1234 if (pos->col < 0) 1235 pos->col = 0; 1236#ifdef FEAT_VIRTUALEDIT 1237 pos->coladd = get4c(fp); 1238 if (pos->coladd < 0) 1239 pos->coladd = 0; 1240#else 1241 (void)get4c(fp); 1242#endif 1243} 1244 1245/* 1246 * Serialize "info" to "fp". 1247 */ 1248 static void 1249serialize_visualinfo(info, fp) 1250 visualinfo_T *info; 1251 FILE *fp; 1252{ 1253 serialize_pos(info->vi_start, fp); 1254 serialize_pos(info->vi_end, fp); 1255 put_bytes(fp, (long_u)info->vi_mode, 4); 1256 put_bytes(fp, (long_u)info->vi_curswant, 4); 1257} 1258 1259/* 1260 * Unserialize the visualinfo_T at the current position in fp. 1261 */ 1262 static void 1263unserialize_visualinfo(info, fp) 1264 visualinfo_T *info; 1265 FILE *fp; 1266{ 1267 unserialize_pos(&info->vi_start, fp); 1268 unserialize_pos(&info->vi_end, fp); 1269 info->vi_mode = get4c(fp); 1270 info->vi_curswant = get4c(fp); 1271} 1272 1273/* 1274 * Write the pointer to an undo header. Instead of writing the pointer itself 1275 * we use the sequence number of the header. This is converted back to 1276 * pointers when reading. */ 1277 static void 1278put_header_ptr(fp, uhp) 1279 FILE *fp; 1280 u_header_T *uhp; 1281{ 1282 put_bytes(fp, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4); 1283} 1284 1285/* 1286 * Write the undo tree in an undo file. 1287 * When "name" is not NULL, use it as the name of the undo file. 1288 * Otherwise use buf->b_ffname to generate the undo file name. 1289 * "buf" must never be null, buf->b_ffname is used to obtain the original file 1290 * permissions. 1291 * "forceit" is TRUE for ":wundo!", FALSE otherwise. 1292 * "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text. 1293 */ 1294 void 1295u_write_undo(name, forceit, buf, hash) 1296 char_u *name; 1297 int forceit; 1298 buf_T *buf; 1299 char_u *hash; 1300{ 1301 u_header_T *uhp; 1302 char_u *file_name; 1303 int mark; 1304#ifdef U_DEBUG 1305 int headers_written = 0; 1306#endif 1307 int fd; 1308 FILE *fp = NULL; 1309 int perm; 1310 int write_ok = FALSE; 1311#ifdef UNIX 1312 int st_old_valid = FALSE; 1313 struct stat st_old; 1314 struct stat st_new; 1315#endif 1316#ifdef FEAT_CRYPT 1317 int do_crypt = FALSE; 1318#endif 1319 1320 if (name == NULL) 1321 { 1322 file_name = u_get_undo_file_name(buf->b_ffname, FALSE); 1323 if (file_name == NULL) 1324 { 1325 if (p_verbose > 0) 1326 { 1327 verbose_enter(); 1328 smsg((char_u *) 1329 _("Cannot write undo file in any directory in 'undodir'")); 1330 verbose_leave(); 1331 } 1332 return; 1333 } 1334 } 1335 else 1336 file_name = name; 1337 1338 /* 1339 * Decide about the permission to use for the undo file. If the buffer 1340 * has a name use the permission of the original file. Otherwise only 1341 * allow the user to access the undo file. 1342 */ 1343 perm = 0600; 1344 if (buf->b_ffname != NULL) 1345 { 1346#ifdef UNIX 1347 if (mch_stat((char *)buf->b_ffname, &st_old) >= 0) 1348 { 1349 perm = st_old.st_mode; 1350 st_old_valid = TRUE; 1351 } 1352#else 1353 perm = mch_getperm(buf->b_ffname); 1354 if (perm < 0) 1355 perm = 0600; 1356#endif 1357 } 1358 1359 /* strip any s-bit */ 1360 perm = perm & 0777; 1361 1362 /* If the undo file already exists, verify that it actually is an undo 1363 * file, and delete it. */ 1364 if (mch_getperm(file_name) >= 0) 1365 { 1366 if (name == NULL || !forceit) 1367 { 1368 /* Check we can read it and it's an undo file. */ 1369 fd = mch_open((char *)file_name, O_RDONLY|O_EXTRA, 0); 1370 if (fd < 0) 1371 { 1372 if (name != NULL || p_verbose > 0) 1373 { 1374 if (name == NULL) 1375 verbose_enter(); 1376 smsg((char_u *) 1377 _("Will not overwrite with undo file, cannot read: %s"), 1378 file_name); 1379 if (name == NULL) 1380 verbose_leave(); 1381 } 1382 goto theend; 1383 } 1384 else 1385 { 1386 char_u mbuf[UF_START_MAGIC_LEN]; 1387 int len; 1388 1389 len = vim_read(fd, mbuf, UF_START_MAGIC_LEN); 1390 close(fd); 1391 if (len < UF_START_MAGIC_LEN 1392 || memcmp(mbuf, UF_START_MAGIC, UF_START_MAGIC_LEN) != 0) 1393 { 1394 if (name != NULL || p_verbose > 0) 1395 { 1396 if (name == NULL) 1397 verbose_enter(); 1398 smsg((char_u *) 1399 _("Will not overwrite, this is not an undo file: %s"), 1400 file_name); 1401 if (name == NULL) 1402 verbose_leave(); 1403 } 1404 goto theend; 1405 } 1406 } 1407 } 1408 mch_remove(file_name); 1409 } 1410 1411 /* If there is no undo information at all, quit here after deleting any 1412 * existing undo file. */ 1413 if (buf->b_u_numhead == 0 && buf->b_u_line_ptr == NULL) 1414 { 1415 if (p_verbose > 0) 1416 verb_msg((char_u *)_("Skipping undo file write, nothing to undo")); 1417 goto theend; 1418 } 1419 1420 fd = mch_open((char *)file_name, 1421 O_CREAT|O_EXTRA|O_WRONLY|O_EXCL|O_NOFOLLOW, perm); 1422 if (fd < 0) 1423 { 1424 EMSG2(_(e_not_open), file_name); 1425 goto theend; 1426 } 1427 (void)mch_setperm(file_name, perm); 1428 if (p_verbose > 0) 1429 { 1430 verbose_enter(); 1431 smsg((char_u *)_("Writing undo file: %s"), file_name); 1432 verbose_leave(); 1433 } 1434 1435#ifdef U_DEBUG 1436 /* Check there is no problem in undo info before writing. */ 1437 u_check(FALSE); 1438#endif 1439 1440#ifdef UNIX 1441 /* 1442 * Try to set the group of the undo file same as the original file. If 1443 * this fails, set the protection bits for the group same as the 1444 * protection bits for others. 1445 */ 1446 if (st_old_valid 1447 && mch_stat((char *)file_name, &st_new) >= 0 1448 && st_new.st_gid != st_old.st_gid 1449# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */ 1450 && fchown(fd, (uid_t)-1, st_old.st_gid) != 0 1451# endif 1452 ) 1453 mch_setperm(file_name, (perm & 0707) | ((perm & 07) << 3)); 1454# ifdef HAVE_SELINUX 1455 if (buf->b_ffname != NULL) 1456 mch_copy_sec(buf->b_ffname, file_name); 1457# endif 1458#endif 1459 1460 fp = fdopen(fd, "w"); 1461 if (fp == NULL) 1462 { 1463 EMSG2(_(e_not_open), file_name); 1464 close(fd); 1465 mch_remove(file_name); 1466 goto theend; 1467 } 1468 1469 /* Undo must be synced. */ 1470 u_sync(TRUE); 1471 1472 /* 1473 * Write the header. 1474 */ 1475 if (serialize_header(fp, buf, hash) == FAIL) 1476 goto write_error; 1477#ifdef FEAT_CRYPT 1478 if (*buf->b_p_key != NUL) 1479 do_crypt = TRUE; 1480#endif 1481 1482 /* 1483 * Iteratively serialize UHPs and their UEPs from the top down. 1484 */ 1485 mark = ++lastmark; 1486 uhp = buf->b_u_oldhead; 1487 while (uhp != NULL) 1488 { 1489 /* Serialize current UHP if we haven't seen it */ 1490 if (uhp->uh_walk != mark) 1491 { 1492 uhp->uh_walk = mark; 1493#ifdef U_DEBUG 1494 ++headers_written; 1495#endif 1496 if (serialize_uhp(fp, buf, uhp) == FAIL) 1497 goto write_error; 1498 } 1499 1500 /* Now walk through the tree - algorithm from undo_time(). */ 1501 if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != mark) 1502 uhp = uhp->uh_prev.ptr; 1503 else if (uhp->uh_alt_next.ptr != NULL 1504 && uhp->uh_alt_next.ptr->uh_walk != mark) 1505 uhp = uhp->uh_alt_next.ptr; 1506 else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL 1507 && uhp->uh_next.ptr->uh_walk != mark) 1508 uhp = uhp->uh_next.ptr; 1509 else if (uhp->uh_alt_prev.ptr != NULL) 1510 uhp = uhp->uh_alt_prev.ptr; 1511 else 1512 uhp = uhp->uh_next.ptr; 1513 } 1514 1515 if (put_bytes(fp, (long_u)UF_HEADER_END_MAGIC, 2) == OK) 1516 write_ok = TRUE; 1517#ifdef U_DEBUG 1518 if (headers_written != buf->b_u_numhead) 1519 EMSG3("Written %ld headers, but numhead is %ld", 1520 headers_written, buf->b_u_numhead); 1521#endif 1522 1523write_error: 1524 fclose(fp); 1525 if (!write_ok) 1526 EMSG2(_("E829: write error in undo file: %s"), file_name); 1527 1528#if defined(MACOS_CLASSIC) || defined(WIN3264) 1529 /* Copy file attributes; for systems where this can only be done after 1530 * closing the file. */ 1531 if (buf->b_ffname != NULL) 1532 (void)mch_copy_file_attribute(buf->b_ffname, file_name); 1533#endif 1534#ifdef HAVE_ACL 1535 if (buf->b_ffname != NULL) 1536 { 1537 vim_acl_T acl; 1538 1539 /* For systems that support ACL: get the ACL from the original file. */ 1540 acl = mch_get_acl(buf->b_ffname); 1541 mch_set_acl(file_name, acl); 1542 } 1543#endif 1544 1545theend: 1546#ifdef FEAT_CRYPT 1547 if (do_crypt) 1548 crypt_pop_state(); 1549#endif 1550 if (file_name != name) 1551 vim_free(file_name); 1552} 1553 1554/* 1555 * Load the undo tree from an undo file. 1556 * If "name" is not NULL use it as the undo file name. This also means being 1557 * a bit more verbose. 1558 * Otherwise use curbuf->b_ffname to generate the undo file name. 1559 * "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text. 1560 */ 1561 void 1562u_read_undo(name, hash, orig_name) 1563 char_u *name; 1564 char_u *hash; 1565 char_u *orig_name; 1566{ 1567 char_u *file_name; 1568 FILE *fp; 1569 long version, str_len; 1570 char_u *line_ptr = NULL; 1571 linenr_T line_lnum; 1572 colnr_T line_colnr; 1573 linenr_T line_count; 1574 int num_head = 0; 1575 long old_header_seq, new_header_seq, cur_header_seq; 1576 long seq_last, seq_cur; 1577 long last_save_nr = 0; 1578 short old_idx = -1, new_idx = -1, cur_idx = -1; 1579 long num_read_uhps = 0; 1580 time_t seq_time; 1581 int i, j; 1582 int c; 1583 u_header_T *uhp; 1584 u_header_T **uhp_table = NULL; 1585 char_u read_hash[UNDO_HASH_SIZE]; 1586 char_u magic_buf[UF_START_MAGIC_LEN]; 1587#ifdef U_DEBUG 1588 int *uhp_table_used; 1589#endif 1590#ifdef UNIX 1591 struct stat st_orig; 1592 struct stat st_undo; 1593#endif 1594#ifdef FEAT_CRYPT 1595 int do_decrypt = FALSE; 1596#endif 1597 1598 if (name == NULL) 1599 { 1600 file_name = u_get_undo_file_name(curbuf->b_ffname, TRUE); 1601 if (file_name == NULL) 1602 return; 1603 1604#ifdef UNIX 1605 /* For safety we only read an undo file if the owner is equal to the 1606 * owner of the text file. */ 1607 if (mch_stat((char *)orig_name, &st_orig) >= 0 1608 && mch_stat((char *)file_name, &st_undo) >= 0 1609 && st_orig.st_uid != st_undo.st_uid) 1610 { 1611 if (p_verbose > 0) 1612 { 1613 verbose_enter(); 1614 smsg((char_u *)_("Not reading undo file, owner differs: %s"), 1615 file_name); 1616 verbose_leave(); 1617 } 1618 return; 1619 } 1620#endif 1621 } 1622 else 1623 file_name = name; 1624 1625 if (p_verbose > 0) 1626 { 1627 verbose_enter(); 1628 smsg((char_u *)_("Reading undo file: %s"), file_name); 1629 verbose_leave(); 1630 } 1631 1632 fp = mch_fopen((char *)file_name, "r"); 1633 if (fp == NULL) 1634 { 1635 if (name != NULL || p_verbose > 0) 1636 EMSG2(_("E822: Cannot open undo file for reading: %s"), file_name); 1637 goto error; 1638 } 1639 1640 /* 1641 * Read the undo file header. 1642 */ 1643 if (fread(magic_buf, UF_START_MAGIC_LEN, 1, fp) != 1 1644 || memcmp(magic_buf, UF_START_MAGIC, UF_START_MAGIC_LEN) != 0) 1645 { 1646 EMSG2(_("E823: Not an undo file: %s"), file_name); 1647 goto error; 1648 } 1649 version = get2c(fp); 1650 if (version == UF_VERSION_CRYPT) 1651 { 1652#ifdef FEAT_CRYPT 1653 if (*curbuf->b_p_key == NUL) 1654 { 1655 EMSG2(_("E832: Non-encrypted file has encrypted undo file: %s"), 1656 file_name); 1657 goto error; 1658 } 1659 if (prepare_crypt_read(fp) == FAIL) 1660 { 1661 EMSG2(_("E826: Undo file decryption failed: %s"), file_name); 1662 goto error; 1663 } 1664 do_decrypt = TRUE; 1665#else 1666 EMSG2(_("E827: Undo file is encrypted: %s"), file_name); 1667 goto error; 1668#endif 1669 } 1670 else if (version != UF_VERSION) 1671 { 1672 EMSG2(_("E824: Incompatible undo file: %s"), file_name); 1673 goto error; 1674 } 1675 1676 if (fread(read_hash, UNDO_HASH_SIZE, 1, fp) != 1) 1677 { 1678 corruption_error("hash", file_name); 1679 goto error; 1680 } 1681 line_count = (linenr_T)get4c(fp); 1682 if (memcmp(hash, read_hash, UNDO_HASH_SIZE) != 0 1683 || line_count != curbuf->b_ml.ml_line_count) 1684 { 1685 if (p_verbose > 0 || name != NULL) 1686 { 1687 if (name == NULL) 1688 verbose_enter(); 1689 give_warning((char_u *) 1690 _("File contents changed, cannot use undo info"), TRUE); 1691 if (name == NULL) 1692 verbose_leave(); 1693 } 1694 goto error; 1695 } 1696 1697 /* Read undo data for "U" command. */ 1698 str_len = get4c(fp); 1699 if (str_len < 0) 1700 goto error; 1701 if (str_len > 0) 1702 line_ptr = read_string_decrypt(curbuf, fp, str_len); 1703 line_lnum = (linenr_T)get4c(fp); 1704 line_colnr = (colnr_T)get4c(fp); 1705 if (line_lnum < 0 || line_colnr < 0) 1706 { 1707 corruption_error("line lnum/col", file_name); 1708 goto error; 1709 } 1710 1711 /* Begin general undo data */ 1712 old_header_seq = get4c(fp); 1713 new_header_seq = get4c(fp); 1714 cur_header_seq = get4c(fp); 1715 num_head = get4c(fp); 1716 seq_last = get4c(fp); 1717 seq_cur = get4c(fp); 1718 seq_time = get8ctime(fp); 1719 1720 /* Optional header fields. */ 1721 for (;;) 1722 { 1723 int len = getc(fp); 1724 int what; 1725 1726 if (len == 0 || len == EOF) 1727 break; 1728 what = getc(fp); 1729 switch (what) 1730 { 1731 case UF_LAST_SAVE_NR: 1732 last_save_nr = get4c(fp); 1733 break; 1734 default: 1735 /* field not supported, skip */ 1736 while (--len >= 0) 1737 (void)getc(fp); 1738 } 1739 } 1740 1741 /* uhp_table will store the freshly created undo headers we allocate 1742 * until we insert them into curbuf. The table remains sorted by the 1743 * sequence numbers of the headers. 1744 * When there are no headers uhp_table is NULL. */ 1745 if (num_head > 0) 1746 { 1747 uhp_table = (u_header_T **)U_ALLOC_LINE( 1748 num_head * sizeof(u_header_T *)); 1749 if (uhp_table == NULL) 1750 goto error; 1751 } 1752 1753 while ((c = get2c(fp)) == UF_HEADER_MAGIC) 1754 { 1755 if (num_read_uhps >= num_head) 1756 { 1757 corruption_error("num_head too small", file_name); 1758 goto error; 1759 } 1760 1761 uhp = unserialize_uhp(fp, file_name); 1762 if (uhp == NULL) 1763 goto error; 1764 uhp_table[num_read_uhps++] = uhp; 1765 } 1766 1767 if (num_read_uhps != num_head) 1768 { 1769 corruption_error("num_head", file_name); 1770 goto error; 1771 } 1772 if (c != UF_HEADER_END_MAGIC) 1773 { 1774 corruption_error("end marker", file_name); 1775 goto error; 1776 } 1777 1778#ifdef U_DEBUG 1779 uhp_table_used = (int *)alloc_clear( 1780 (unsigned)(sizeof(int) * num_head + 1)); 1781# define SET_FLAG(j) ++uhp_table_used[j] 1782#else 1783# define SET_FLAG(j) 1784#endif 1785 1786 /* We have put all of the headers into a table. Now we iterate through the 1787 * table and swizzle each sequence number we have stored in uh_*_seq into 1788 * a pointer corresponding to the header with that sequence number. */ 1789 for (i = 0; i < num_head; i++) 1790 { 1791 uhp = uhp_table[i]; 1792 if (uhp == NULL) 1793 continue; 1794 for (j = 0; j < num_head; j++) 1795 if (uhp_table[j] != NULL && i != j 1796 && uhp_table[i]->uh_seq == uhp_table[j]->uh_seq) 1797 { 1798 corruption_error("duplicate uh_seq", file_name); 1799 goto error; 1800 } 1801 for (j = 0; j < num_head; j++) 1802 if (uhp_table[j] != NULL 1803 && uhp_table[j]->uh_seq == uhp->uh_next.seq) 1804 { 1805 uhp->uh_next.ptr = uhp_table[j]; 1806 SET_FLAG(j); 1807 break; 1808 } 1809 for (j = 0; j < num_head; j++) 1810 if (uhp_table[j] != NULL 1811 && uhp_table[j]->uh_seq == uhp->uh_prev.seq) 1812 { 1813 uhp->uh_prev.ptr = uhp_table[j]; 1814 SET_FLAG(j); 1815 break; 1816 } 1817 for (j = 0; j < num_head; j++) 1818 if (uhp_table[j] != NULL 1819 && uhp_table[j]->uh_seq == uhp->uh_alt_next.seq) 1820 { 1821 uhp->uh_alt_next.ptr = uhp_table[j]; 1822 SET_FLAG(j); 1823 break; 1824 } 1825 for (j = 0; j < num_head; j++) 1826 if (uhp_table[j] != NULL 1827 && uhp_table[j]->uh_seq == uhp->uh_alt_prev.seq) 1828 { 1829 uhp->uh_alt_prev.ptr = uhp_table[j]; 1830 SET_FLAG(j); 1831 break; 1832 } 1833 if (old_header_seq > 0 && old_idx < 0 && uhp->uh_seq == old_header_seq) 1834 { 1835 old_idx = i; 1836 SET_FLAG(i); 1837 } 1838 if (new_header_seq > 0 && new_idx < 0 && uhp->uh_seq == new_header_seq) 1839 { 1840 new_idx = i; 1841 SET_FLAG(i); 1842 } 1843 if (cur_header_seq > 0 && cur_idx < 0 && uhp->uh_seq == cur_header_seq) 1844 { 1845 cur_idx = i; 1846 SET_FLAG(i); 1847 } 1848 } 1849 1850 /* Now that we have read the undo info successfully, free the current undo 1851 * info and use the info from the file. */ 1852 u_blockfree(curbuf); 1853 curbuf->b_u_oldhead = old_idx < 0 ? NULL : uhp_table[old_idx]; 1854 curbuf->b_u_newhead = new_idx < 0 ? NULL : uhp_table[new_idx]; 1855 curbuf->b_u_curhead = cur_idx < 0 ? NULL : uhp_table[cur_idx]; 1856 curbuf->b_u_line_ptr = line_ptr; 1857 curbuf->b_u_line_lnum = line_lnum; 1858 curbuf->b_u_line_colnr = line_colnr; 1859 curbuf->b_u_numhead = num_head; 1860 curbuf->b_u_seq_last = seq_last; 1861 curbuf->b_u_seq_cur = seq_cur; 1862 curbuf->b_u_time_cur = seq_time; 1863 curbuf->b_u_save_nr_last = last_save_nr; 1864 1865 curbuf->b_u_synced = TRUE; 1866 vim_free(uhp_table); 1867 1868#ifdef U_DEBUG 1869 for (i = 0; i < num_head; ++i) 1870 if (uhp_table_used[i] == 0) 1871 EMSGN("uhp_table entry %ld not used, leaking memory", i); 1872 vim_free(uhp_table_used); 1873 u_check(TRUE); 1874#endif 1875 1876 if (name != NULL) 1877 smsg((char_u *)_("Finished reading undo file %s"), file_name); 1878 goto theend; 1879 1880error: 1881 vim_free(line_ptr); 1882 if (uhp_table != NULL) 1883 { 1884 for (i = 0; i < num_read_uhps; i++) 1885 if (uhp_table[i] != NULL) 1886 u_free_uhp(uhp_table[i]); 1887 vim_free(uhp_table); 1888 } 1889 1890theend: 1891#ifdef FEAT_CRYPT 1892 if (do_decrypt) 1893 crypt_pop_state(); 1894#endif 1895 if (fp != NULL) 1896 fclose(fp); 1897 if (file_name != name) 1898 vim_free(file_name); 1899 return; 1900} 1901 1902#endif /* FEAT_PERSISTENT_UNDO */ 1903 1904 1905/* 1906 * If 'cpoptions' contains 'u': Undo the previous undo or redo (vi compatible). 1907 * If 'cpoptions' does not contain 'u': Always undo. 1908 */ 1909 void 1910u_undo(count) 1911 int count; 1912{ 1913 /* 1914 * If we get an undo command while executing a macro, we behave like the 1915 * original vi. If this happens twice in one macro the result will not 1916 * be compatible. 1917 */ 1918 if (curbuf->b_u_synced == FALSE) 1919 { 1920 u_sync(TRUE); 1921 count = 1; 1922 } 1923 1924 if (vim_strchr(p_cpo, CPO_UNDO) == NULL) 1925 undo_undoes = TRUE; 1926 else 1927 undo_undoes = !undo_undoes; 1928 u_doit(count); 1929} 1930 1931/* 1932 * If 'cpoptions' contains 'u': Repeat the previous undo or redo. 1933 * If 'cpoptions' does not contain 'u': Always redo. 1934 */ 1935 void 1936u_redo(count) 1937 int count; 1938{ 1939 if (vim_strchr(p_cpo, CPO_UNDO) == NULL) 1940 undo_undoes = FALSE; 1941 u_doit(count); 1942} 1943 1944/* 1945 * Undo or redo, depending on 'undo_undoes', 'count' times. 1946 */ 1947 static void 1948u_doit(startcount) 1949 int startcount; 1950{ 1951 int count = startcount; 1952 1953 if (!undo_allowed()) 1954 return; 1955 1956 u_newcount = 0; 1957 u_oldcount = 0; 1958 if (curbuf->b_ml.ml_flags & ML_EMPTY) 1959 u_oldcount = -1; 1960 while (count--) 1961 { 1962 /* Do the change warning now, so that it triggers FileChangedRO when 1963 * needed. This may cause the file to be reloaded, that must happen 1964 * before we do anything, because it may change curbuf->b_u_curhead 1965 * and more. */ 1966 change_warning(0); 1967 1968 if (undo_undoes) 1969 { 1970 if (curbuf->b_u_curhead == NULL) /* first undo */ 1971 curbuf->b_u_curhead = curbuf->b_u_newhead; 1972 else if (p_ul > 0) /* multi level undo */ 1973 /* get next undo */ 1974 curbuf->b_u_curhead = curbuf->b_u_curhead->uh_next.ptr; 1975 /* nothing to undo */ 1976 if (curbuf->b_u_numhead == 0 || curbuf->b_u_curhead == NULL) 1977 { 1978 /* stick curbuf->b_u_curhead at end */ 1979 curbuf->b_u_curhead = curbuf->b_u_oldhead; 1980 beep_flush(); 1981 if (count == startcount - 1) 1982 { 1983 MSG(_("Already at oldest change")); 1984 return; 1985 } 1986 break; 1987 } 1988 1989 u_undoredo(TRUE); 1990 } 1991 else 1992 { 1993 if (curbuf->b_u_curhead == NULL || p_ul <= 0) 1994 { 1995 beep_flush(); /* nothing to redo */ 1996 if (count == startcount - 1) 1997 { 1998 MSG(_("Already at newest change")); 1999 return; 2000 } 2001 break; 2002 } 2003 2004 u_undoredo(FALSE); 2005 2006 /* Advance for next redo. Set "newhead" when at the end of the 2007 * redoable changes. */ 2008 if (curbuf->b_u_curhead->uh_prev.ptr == NULL) 2009 curbuf->b_u_newhead = curbuf->b_u_curhead; 2010 curbuf->b_u_curhead = curbuf->b_u_curhead->uh_prev.ptr; 2011 } 2012 } 2013 u_undo_end(undo_undoes, FALSE); 2014} 2015 2016/* 2017 * Undo or redo over the timeline. 2018 * When "step" is negative go back in time, otherwise goes forward in time. 2019 * When "sec" is FALSE make "step" steps, when "sec" is TRUE use "step" as 2020 * seconds. 2021 * When "file" is TRUE use "step" as a number of file writes. 2022 * When "absolute" is TRUE use "step" as the sequence number to jump to. 2023 * "sec" must be FALSE then. 2024 */ 2025 void 2026undo_time(step, sec, file, absolute) 2027 long step; 2028 int sec; 2029 int file; 2030 int absolute; 2031{ 2032 long target; 2033 long closest; 2034 long closest_start; 2035 long closest_seq = 0; 2036 long val; 2037 u_header_T *uhp; 2038 u_header_T *last; 2039 int mark; 2040 int nomark; 2041 int round; 2042 int dosec = sec; 2043 int dofile = file; 2044 int above = FALSE; 2045 int did_undo = TRUE; 2046 2047 /* First make sure the current undoable change is synced. */ 2048 if (curbuf->b_u_synced == FALSE) 2049 u_sync(TRUE); 2050 2051 u_newcount = 0; 2052 u_oldcount = 0; 2053 if (curbuf->b_ml.ml_flags & ML_EMPTY) 2054 u_oldcount = -1; 2055 2056 /* "target" is the node below which we want to be. 2057 * Init "closest" to a value we can't reach. */ 2058 if (absolute) 2059 { 2060 target = step; 2061 closest = -1; 2062 } 2063 else 2064 { 2065 /* When doing computations with time_t subtract starttime, because 2066 * time_t converted to a long may result in a wrong number. */ 2067 if (dosec) 2068 target = (long)(curbuf->b_u_time_cur - starttime) + step; 2069 else if (dofile) 2070 { 2071 if (step < 0) 2072 { 2073 /* Going back to a previous write. If there were changes after 2074 * the last write, count that as moving one file-write, so 2075 * that ":earlier 1f" undoes all changes since the last save. */ 2076 uhp = curbuf->b_u_curhead; 2077 if (uhp != NULL) 2078 uhp = uhp->uh_next.ptr; 2079 else 2080 uhp = curbuf->b_u_newhead; 2081 if (uhp != NULL && uhp->uh_save_nr != 0) 2082 /* "uh_save_nr" was set in the last block, that means 2083 * there were no changes since the last write */ 2084 target = curbuf->b_u_save_nr_cur + step; 2085 else 2086 /* count the changes since the last write as one step */ 2087 target = curbuf->b_u_save_nr_cur + step + 1; 2088 if (target <= 0) 2089 /* Go to before first write: before the oldest change. Use 2090 * the sequence number for that. */ 2091 dofile = FALSE; 2092 } 2093 else 2094 { 2095 /* Moving forward to a newer write. */ 2096 target = curbuf->b_u_save_nr_cur + step; 2097 if (target > curbuf->b_u_save_nr_last) 2098 { 2099 /* Go to after last write: after the latest change. Use 2100 * the sequence number for that. */ 2101 target = curbuf->b_u_seq_last + 1; 2102 dofile = FALSE; 2103 } 2104 } 2105 } 2106 else 2107 target = curbuf->b_u_seq_cur + step; 2108 if (step < 0) 2109 { 2110 if (target < 0) 2111 target = 0; 2112 closest = -1; 2113 } 2114 else 2115 { 2116 if (dosec) 2117 closest = (long)(time(NULL) - starttime + 1); 2118 else if (dofile) 2119 closest = curbuf->b_u_save_nr_last + 2; 2120 else 2121 closest = curbuf->b_u_seq_last + 2; 2122 if (target >= closest) 2123 target = closest - 1; 2124 } 2125 } 2126 closest_start = closest; 2127 closest_seq = curbuf->b_u_seq_cur; 2128 2129 /* 2130 * May do this twice: 2131 * 1. Search for "target", update "closest" to the best match found. 2132 * 2. If "target" not found search for "closest". 2133 * 2134 * When using the closest time we use the sequence number in the second 2135 * round, because there may be several entries with the same time. 2136 */ 2137 for (round = 1; round <= 2; ++round) 2138 { 2139 /* Find the path from the current state to where we want to go. The 2140 * desired state can be anywhere in the undo tree, need to go all over 2141 * it. We put "nomark" in uh_walk where we have been without success, 2142 * "mark" where it could possibly be. */ 2143 mark = ++lastmark; 2144 nomark = ++lastmark; 2145 2146 if (curbuf->b_u_curhead == NULL) /* at leaf of the tree */ 2147 uhp = curbuf->b_u_newhead; 2148 else 2149 uhp = curbuf->b_u_curhead; 2150 2151 while (uhp != NULL) 2152 { 2153 uhp->uh_walk = mark; 2154 if (dosec) 2155 val = (long)(uhp->uh_time - starttime); 2156 else if (dofile) 2157 val = uhp->uh_save_nr; 2158 else 2159 val = uhp->uh_seq; 2160 2161 if (round == 1 && !(dofile && val == 0)) 2162 { 2163 /* Remember the header that is closest to the target. 2164 * It must be at least in the right direction (checked with 2165 * "b_u_seq_cur"). When the timestamp is equal find the 2166 * highest/lowest sequence number. */ 2167 if ((step < 0 ? uhp->uh_seq <= curbuf->b_u_seq_cur 2168 : uhp->uh_seq > curbuf->b_u_seq_cur) 2169 && ((dosec && val == closest) 2170 ? (step < 0 2171 ? uhp->uh_seq < closest_seq 2172 : uhp->uh_seq > closest_seq) 2173 : closest == closest_start 2174 || (val > target 2175 ? (closest > target 2176 ? val - target <= closest - target 2177 : val - target <= target - closest) 2178 : (closest > target 2179 ? target - val <= closest - target 2180 : target - val <= target - closest)))) 2181 { 2182 closest = val; 2183 closest_seq = uhp->uh_seq; 2184 } 2185 } 2186 2187 /* Quit searching when we found a match. But when searching for a 2188 * time we need to continue looking for the best uh_seq. */ 2189 if (target == val && !dosec) 2190 { 2191 target = uhp->uh_seq; 2192 break; 2193 } 2194 2195 /* go down in the tree if we haven't been there */ 2196 if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != nomark 2197 && uhp->uh_prev.ptr->uh_walk != mark) 2198 uhp = uhp->uh_prev.ptr; 2199 2200 /* go to alternate branch if we haven't been there */ 2201 else if (uhp->uh_alt_next.ptr != NULL 2202 && uhp->uh_alt_next.ptr->uh_walk != nomark 2203 && uhp->uh_alt_next.ptr->uh_walk != mark) 2204 uhp = uhp->uh_alt_next.ptr; 2205 2206 /* go up in the tree if we haven't been there and we are at the 2207 * start of alternate branches */ 2208 else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL 2209 && uhp->uh_next.ptr->uh_walk != nomark 2210 && uhp->uh_next.ptr->uh_walk != mark) 2211 { 2212 /* If still at the start we don't go through this change. */ 2213 if (uhp == curbuf->b_u_curhead) 2214 uhp->uh_walk = nomark; 2215 uhp = uhp->uh_next.ptr; 2216 } 2217 2218 else 2219 { 2220 /* need to backtrack; mark this node as useless */ 2221 uhp->uh_walk = nomark; 2222 if (uhp->uh_alt_prev.ptr != NULL) 2223 uhp = uhp->uh_alt_prev.ptr; 2224 else 2225 uhp = uhp->uh_next.ptr; 2226 } 2227 } 2228 2229 if (uhp != NULL) /* found it */ 2230 break; 2231 2232 if (absolute) 2233 { 2234 EMSGN(_("E830: Undo number %ld not found"), step); 2235 return; 2236 } 2237 2238 if (closest == closest_start) 2239 { 2240 if (step < 0) 2241 MSG(_("Already at oldest change")); 2242 else 2243 MSG(_("Already at newest change")); 2244 return; 2245 } 2246 2247 target = closest_seq; 2248 dosec = FALSE; 2249 dofile = FALSE; 2250 if (step < 0) 2251 above = TRUE; /* stop above the header */ 2252 } 2253 2254 /* If we found it: Follow the path to go to where we want to be. */ 2255 if (uhp != NULL) 2256 { 2257 /* 2258 * First go up the tree as much as needed. 2259 */ 2260 while (!got_int) 2261 { 2262 /* Do the change warning now, for the same reason as above. */ 2263 change_warning(0); 2264 2265 uhp = curbuf->b_u_curhead; 2266 if (uhp == NULL) 2267 uhp = curbuf->b_u_newhead; 2268 else 2269 uhp = uhp->uh_next.ptr; 2270 if (uhp == NULL || uhp->uh_walk != mark 2271 || (uhp->uh_seq == target && !above)) 2272 break; 2273 curbuf->b_u_curhead = uhp; 2274 u_undoredo(TRUE); 2275 uhp->uh_walk = nomark; /* don't go back down here */ 2276 } 2277 2278 /* 2279 * And now go down the tree (redo), branching off where needed. 2280 */ 2281 while (!got_int) 2282 { 2283 /* Do the change warning now, for the same reason as above. */ 2284 change_warning(0); 2285 2286 uhp = curbuf->b_u_curhead; 2287 if (uhp == NULL) 2288 break; 2289 2290 /* Go back to the first branch with a mark. */ 2291 while (uhp->uh_alt_prev.ptr != NULL 2292 && uhp->uh_alt_prev.ptr->uh_walk == mark) 2293 uhp = uhp->uh_alt_prev.ptr; 2294 2295 /* Find the last branch with a mark, that's the one. */ 2296 last = uhp; 2297 while (last->uh_alt_next.ptr != NULL 2298 && last->uh_alt_next.ptr->uh_walk == mark) 2299 last = last->uh_alt_next.ptr; 2300 if (last != uhp) 2301 { 2302 /* Make the used branch the first entry in the list of 2303 * alternatives to make "u" and CTRL-R take this branch. */ 2304 while (uhp->uh_alt_prev.ptr != NULL) 2305 uhp = uhp->uh_alt_prev.ptr; 2306 if (last->uh_alt_next.ptr != NULL) 2307 last->uh_alt_next.ptr->uh_alt_prev.ptr = 2308 last->uh_alt_prev.ptr; 2309 last->uh_alt_prev.ptr->uh_alt_next.ptr = last->uh_alt_next.ptr; 2310 last->uh_alt_prev.ptr = NULL; 2311 last->uh_alt_next.ptr = uhp; 2312 uhp->uh_alt_prev.ptr = last; 2313 2314 if (curbuf->b_u_oldhead == uhp) 2315 curbuf->b_u_oldhead = last; 2316 uhp = last; 2317 if (uhp->uh_next.ptr != NULL) 2318 uhp->uh_next.ptr->uh_prev.ptr = uhp; 2319 } 2320 curbuf->b_u_curhead = uhp; 2321 2322 if (uhp->uh_walk != mark) 2323 break; /* must have reached the target */ 2324 2325 /* Stop when going backwards in time and didn't find the exact 2326 * header we were looking for. */ 2327 if (uhp->uh_seq == target && above) 2328 { 2329 curbuf->b_u_seq_cur = target - 1; 2330 break; 2331 } 2332 2333 u_undoredo(FALSE); 2334 2335 /* Advance "curhead" to below the header we last used. If it 2336 * becomes NULL then we need to set "newhead" to this leaf. */ 2337 if (uhp->uh_prev.ptr == NULL) 2338 curbuf->b_u_newhead = uhp; 2339 curbuf->b_u_curhead = uhp->uh_prev.ptr; 2340 did_undo = FALSE; 2341 2342 if (uhp->uh_seq == target) /* found it! */ 2343 break; 2344 2345 uhp = uhp->uh_prev.ptr; 2346 if (uhp == NULL || uhp->uh_walk != mark) 2347 { 2348 /* Need to redo more but can't find it... */ 2349 EMSG2(_(e_intern2), "undo_time()"); 2350 break; 2351 } 2352 } 2353 } 2354 u_undo_end(did_undo, absolute); 2355} 2356 2357/* 2358 * u_undoredo: common code for undo and redo 2359 * 2360 * The lines in the file are replaced by the lines in the entry list at 2361 * curbuf->b_u_curhead. The replaced lines in the file are saved in the entry 2362 * list for the next undo/redo. 2363 * 2364 * When "undo" is TRUE we go up in the tree, when FALSE we go down. 2365 */ 2366 static void 2367u_undoredo(undo) 2368 int undo; 2369{ 2370 char_u **newarray = NULL; 2371 linenr_T oldsize; 2372 linenr_T newsize; 2373 linenr_T top, bot; 2374 linenr_T lnum; 2375 linenr_T newlnum = MAXLNUM; 2376 long i; 2377 u_entry_T *uep, *nuep; 2378 u_entry_T *newlist = NULL; 2379 int old_flags; 2380 int new_flags; 2381 pos_T namedm[NMARKS]; 2382#ifdef FEAT_VISUAL 2383 visualinfo_T visualinfo; 2384#endif 2385 int empty_buffer; /* buffer became empty */ 2386 u_header_T *curhead = curbuf->b_u_curhead; 2387 2388#ifdef FEAT_AUTOCMD 2389 /* Don't want autocommands using the undo structures here, they are 2390 * invalid till the end. */ 2391 block_autocmds(); 2392#endif 2393 2394#ifdef U_DEBUG 2395 u_check(FALSE); 2396#endif 2397 old_flags = curhead->uh_flags; 2398 new_flags = (curbuf->b_changed ? UH_CHANGED : 0) + 2399 ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0); 2400 setpcmark(); 2401 2402 /* 2403 * save marks before undo/redo 2404 */ 2405 mch_memmove(namedm, curbuf->b_namedm, sizeof(pos_T) * NMARKS); 2406#ifdef FEAT_VISUAL 2407 visualinfo = curbuf->b_visual; 2408#endif 2409 curbuf->b_op_start.lnum = curbuf->b_ml.ml_line_count; 2410 curbuf->b_op_start.col = 0; 2411 curbuf->b_op_end.lnum = 0; 2412 curbuf->b_op_end.col = 0; 2413 2414 for (uep = curhead->uh_entry; uep != NULL; uep = nuep) 2415 { 2416 top = uep->ue_top; 2417 bot = uep->ue_bot; 2418 if (bot == 0) 2419 bot = curbuf->b_ml.ml_line_count + 1; 2420 if (top > curbuf->b_ml.ml_line_count || top >= bot 2421 || bot > curbuf->b_ml.ml_line_count + 1) 2422 { 2423#ifdef FEAT_AUTOCMD 2424 unblock_autocmds(); 2425#endif 2426 EMSG(_("E438: u_undo: line numbers wrong")); 2427 changed(); /* don't want UNCHANGED now */ 2428 return; 2429 } 2430 2431 oldsize = bot - top - 1; /* number of lines before undo */ 2432 newsize = uep->ue_size; /* number of lines after undo */ 2433 2434 if (top < newlnum) 2435 { 2436 /* If the saved cursor is somewhere in this undo block, move it to 2437 * the remembered position. Makes "gwap" put the cursor back 2438 * where it was. */ 2439 lnum = curhead->uh_cursor.lnum; 2440 if (lnum >= top && lnum <= top + newsize + 1) 2441 { 2442 curwin->w_cursor = curhead->uh_cursor; 2443 newlnum = curwin->w_cursor.lnum - 1; 2444 } 2445 else 2446 { 2447 /* Use the first line that actually changed. Avoids that 2448 * undoing auto-formatting puts the cursor in the previous 2449 * line. */ 2450 for (i = 0; i < newsize && i < oldsize; ++i) 2451 if (STRCMP(uep->ue_array[i], ml_get(top + 1 + i)) != 0) 2452 break; 2453 if (i == newsize && newlnum == MAXLNUM && uep->ue_next == NULL) 2454 { 2455 newlnum = top; 2456 curwin->w_cursor.lnum = newlnum + 1; 2457 } 2458 else if (i < newsize) 2459 { 2460 newlnum = top + i; 2461 curwin->w_cursor.lnum = newlnum + 1; 2462 } 2463 } 2464 } 2465 2466 empty_buffer = FALSE; 2467 2468 /* delete the lines between top and bot and save them in newarray */ 2469 if (oldsize > 0) 2470 { 2471 if ((newarray = (char_u **)U_ALLOC_LINE( 2472 sizeof(char_u *) * oldsize)) == NULL) 2473 { 2474 do_outofmem_msg((long_u)(sizeof(char_u *) * oldsize)); 2475 /* 2476 * We have messed up the entry list, repair is impossible. 2477 * we have to free the rest of the list. 2478 */ 2479 while (uep != NULL) 2480 { 2481 nuep = uep->ue_next; 2482 u_freeentry(uep, uep->ue_size); 2483 uep = nuep; 2484 } 2485 break; 2486 } 2487 /* delete backwards, it goes faster in most cases */ 2488 for (lnum = bot - 1, i = oldsize; --i >= 0; --lnum) 2489 { 2490 /* what can we do when we run out of memory? */ 2491 if ((newarray[i] = u_save_line(lnum)) == NULL) 2492 do_outofmem_msg((long_u)0); 2493 /* remember we deleted the last line in the buffer, and a 2494 * dummy empty line will be inserted */ 2495 if (curbuf->b_ml.ml_line_count == 1) 2496 empty_buffer = TRUE; 2497 ml_delete(lnum, FALSE); 2498 } 2499 } 2500 else 2501 newarray = NULL; 2502 2503 /* insert the lines in u_array between top and bot */ 2504 if (newsize) 2505 { 2506 for (lnum = top, i = 0; i < newsize; ++i, ++lnum) 2507 { 2508 /* 2509 * If the file is empty, there is an empty line 1 that we 2510 * should get rid of, by replacing it with the new line 2511 */ 2512 if (empty_buffer && lnum == 0) 2513 ml_replace((linenr_T)1, uep->ue_array[i], TRUE); 2514 else 2515 ml_append(lnum, uep->ue_array[i], (colnr_T)0, FALSE); 2516 vim_free(uep->ue_array[i]); 2517 } 2518 vim_free((char_u *)uep->ue_array); 2519 } 2520 2521 /* adjust marks */ 2522 if (oldsize != newsize) 2523 { 2524 mark_adjust(top + 1, top + oldsize, (long)MAXLNUM, 2525 (long)newsize - (long)oldsize); 2526 if (curbuf->b_op_start.lnum > top + oldsize) 2527 curbuf->b_op_start.lnum += newsize - oldsize; 2528 if (curbuf->b_op_end.lnum > top + oldsize) 2529 curbuf->b_op_end.lnum += newsize - oldsize; 2530 } 2531 2532 changed_lines(top + 1, 0, bot, newsize - oldsize); 2533 2534 /* set '[ and '] mark */ 2535 if (top + 1 < curbuf->b_op_start.lnum) 2536 curbuf->b_op_start.lnum = top + 1; 2537 if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum) 2538 curbuf->b_op_end.lnum = top + 1; 2539 else if (top + newsize > curbuf->b_op_end.lnum) 2540 curbuf->b_op_end.lnum = top + newsize; 2541 2542 u_newcount += newsize; 2543 u_oldcount += oldsize; 2544 uep->ue_size = oldsize; 2545 uep->ue_array = newarray; 2546 uep->ue_bot = top + newsize + 1; 2547 2548 /* 2549 * insert this entry in front of the new entry list 2550 */ 2551 nuep = uep->ue_next; 2552 uep->ue_next = newlist; 2553 newlist = uep; 2554 } 2555 2556 curhead->uh_entry = newlist; 2557 curhead->uh_flags = new_flags; 2558 if ((old_flags & UH_EMPTYBUF) && bufempty()) 2559 curbuf->b_ml.ml_flags |= ML_EMPTY; 2560 if (old_flags & UH_CHANGED) 2561 changed(); 2562 else 2563#ifdef FEAT_NETBEANS_INTG 2564 /* per netbeans undo rules, keep it as modified */ 2565 if (!isNetbeansModified(curbuf)) 2566#endif 2567 unchanged(curbuf, FALSE); 2568 2569 /* 2570 * restore marks from before undo/redo 2571 */ 2572 for (i = 0; i < NMARKS; ++i) 2573 if (curhead->uh_namedm[i].lnum != 0) 2574 { 2575 curbuf->b_namedm[i] = curhead->uh_namedm[i]; 2576 curhead->uh_namedm[i] = namedm[i]; 2577 } 2578#ifdef FEAT_VISUAL 2579 if (curhead->uh_visual.vi_start.lnum != 0) 2580 { 2581 curbuf->b_visual = curhead->uh_visual; 2582 curhead->uh_visual = visualinfo; 2583 } 2584#endif 2585 2586 /* 2587 * If the cursor is only off by one line, put it at the same position as 2588 * before starting the change (for the "o" command). 2589 * Otherwise the cursor should go to the first undone line. 2590 */ 2591 if (curhead->uh_cursor.lnum + 1 == curwin->w_cursor.lnum 2592 && curwin->w_cursor.lnum > 1) 2593 --curwin->w_cursor.lnum; 2594 if (curwin->w_cursor.lnum <= curbuf->b_ml.ml_line_count) 2595 { 2596 if (curhead->uh_cursor.lnum == curwin->w_cursor.lnum) 2597 { 2598 curwin->w_cursor.col = curhead->uh_cursor.col; 2599#ifdef FEAT_VIRTUALEDIT 2600 if (virtual_active() && curhead->uh_cursor_vcol >= 0) 2601 coladvance((colnr_T)curhead->uh_cursor_vcol); 2602 else 2603 curwin->w_cursor.coladd = 0; 2604#endif 2605 } 2606 else 2607 beginline(BL_SOL | BL_FIX); 2608 } 2609 else 2610 { 2611 /* We get here with the current cursor line being past the end (eg 2612 * after adding lines at the end of the file, and then undoing it). 2613 * check_cursor() will move the cursor to the last line. Move it to 2614 * the first column here. */ 2615 curwin->w_cursor.col = 0; 2616#ifdef FEAT_VIRTUALEDIT 2617 curwin->w_cursor.coladd = 0; 2618#endif 2619 } 2620 2621 /* Make sure the cursor is on an existing line and column. */ 2622 check_cursor(); 2623 2624 /* Remember where we are for "g-" and ":earlier 10s". */ 2625 curbuf->b_u_seq_cur = curhead->uh_seq; 2626 if (undo) 2627 /* We are below the previous undo. However, to make ":earlier 1s" 2628 * work we compute this as being just above the just undone change. */ 2629 --curbuf->b_u_seq_cur; 2630 2631 /* Remember where we are for ":earlier 1f" and ":later 1f". */ 2632 if (curhead->uh_save_nr != 0) 2633 { 2634 if (undo) 2635 curbuf->b_u_save_nr_cur = curhead->uh_save_nr - 1; 2636 else 2637 curbuf->b_u_save_nr_cur = curhead->uh_save_nr; 2638 } 2639 2640 /* The timestamp can be the same for multiple changes, just use the one of 2641 * the undone/redone change. */ 2642 curbuf->b_u_time_cur = curhead->uh_time; 2643 2644#ifdef FEAT_AUTOCMD 2645 unblock_autocmds(); 2646#endif 2647#ifdef U_DEBUG 2648 u_check(FALSE); 2649#endif 2650} 2651 2652/* 2653 * If we deleted or added lines, report the number of less/more lines. 2654 * Otherwise, report the number of changes (this may be incorrect 2655 * in some cases, but it's better than nothing). 2656 */ 2657 static void 2658u_undo_end(did_undo, absolute) 2659 int did_undo; /* just did an undo */ 2660 int absolute; /* used ":undo N" */ 2661{ 2662 char *msgstr; 2663 u_header_T *uhp; 2664 char_u msgbuf[80]; 2665 2666#ifdef FEAT_FOLDING 2667 if ((fdo_flags & FDO_UNDO) && KeyTyped) 2668 foldOpenCursor(); 2669#endif 2670 2671 if (global_busy /* no messages now, wait until global is finished */ 2672 || !messaging()) /* 'lazyredraw' set, don't do messages now */ 2673 return; 2674 2675 if (curbuf->b_ml.ml_flags & ML_EMPTY) 2676 --u_newcount; 2677 2678 u_oldcount -= u_newcount; 2679 if (u_oldcount == -1) 2680 msgstr = N_("more line"); 2681 else if (u_oldcount < 0) 2682 msgstr = N_("more lines"); 2683 else if (u_oldcount == 1) 2684 msgstr = N_("line less"); 2685 else if (u_oldcount > 1) 2686 msgstr = N_("fewer lines"); 2687 else 2688 { 2689 u_oldcount = u_newcount; 2690 if (u_newcount == 1) 2691 msgstr = N_("change"); 2692 else 2693 msgstr = N_("changes"); 2694 } 2695 2696 if (curbuf->b_u_curhead != NULL) 2697 { 2698 /* For ":undo N" we prefer a "after #N" message. */ 2699 if (absolute && curbuf->b_u_curhead->uh_next.ptr != NULL) 2700 { 2701 uhp = curbuf->b_u_curhead->uh_next.ptr; 2702 did_undo = FALSE; 2703 } 2704 else if (did_undo) 2705 uhp = curbuf->b_u_curhead; 2706 else 2707 uhp = curbuf->b_u_curhead->uh_next.ptr; 2708 } 2709 else 2710 uhp = curbuf->b_u_newhead; 2711 2712 if (uhp == NULL) 2713 *msgbuf = NUL; 2714 else 2715 u_add_time(msgbuf, sizeof(msgbuf), uhp->uh_time); 2716 2717#ifdef FEAT_CONCEAL 2718 { 2719 win_T *wp; 2720 2721 FOR_ALL_WINDOWS(wp) 2722 { 2723 if (wp->w_buffer == curbuf && wp->w_p_cole > 0) 2724 redraw_win_later(wp, NOT_VALID); 2725 } 2726 } 2727#endif 2728 2729 smsg((char_u *)_("%ld %s; %s #%ld %s"), 2730 u_oldcount < 0 ? -u_oldcount : u_oldcount, 2731 _(msgstr), 2732 did_undo ? _("before") : _("after"), 2733 uhp == NULL ? 0L : uhp->uh_seq, 2734 msgbuf); 2735} 2736 2737/* 2738 * u_sync: stop adding to the current entry list 2739 */ 2740 void 2741u_sync(force) 2742 int force; /* Also sync when no_u_sync is set. */ 2743{ 2744 /* Skip it when already synced or syncing is disabled. */ 2745 if (curbuf->b_u_synced || (!force && no_u_sync > 0)) 2746 return; 2747#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) 2748 if (im_is_preediting()) 2749 return; /* XIM is busy, don't break an undo sequence */ 2750#endif 2751 if (p_ul < 0) 2752 curbuf->b_u_synced = TRUE; /* no entries, nothing to do */ 2753 else 2754 { 2755 u_getbot(); /* compute ue_bot of previous u_save */ 2756 curbuf->b_u_curhead = NULL; 2757 } 2758} 2759 2760/* 2761 * ":undolist": List the leafs of the undo tree 2762 */ 2763 void 2764ex_undolist(eap) 2765 exarg_T *eap UNUSED; 2766{ 2767 garray_T ga; 2768 u_header_T *uhp; 2769 int mark; 2770 int nomark; 2771 int changes = 1; 2772 int i; 2773 2774 /* 2775 * 1: walk the tree to find all leafs, put the info in "ga". 2776 * 2: sort the lines 2777 * 3: display the list 2778 */ 2779 mark = ++lastmark; 2780 nomark = ++lastmark; 2781 ga_init2(&ga, (int)sizeof(char *), 20); 2782 2783 uhp = curbuf->b_u_oldhead; 2784 while (uhp != NULL) 2785 { 2786 if (uhp->uh_prev.ptr == NULL && uhp->uh_walk != nomark 2787 && uhp->uh_walk != mark) 2788 { 2789 if (ga_grow(&ga, 1) == FAIL) 2790 break; 2791 vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7ld ", 2792 uhp->uh_seq, changes); 2793 u_add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff), 2794 uhp->uh_time); 2795 if (uhp->uh_save_nr > 0) 2796 { 2797 while (STRLEN(IObuff) < 32) 2798 STRCAT(IObuff, " "); 2799 vim_snprintf_add((char *)IObuff, IOSIZE, 2800 " %3ld", uhp->uh_save_nr); 2801 } 2802 ((char_u **)(ga.ga_data))[ga.ga_len++] = vim_strsave(IObuff); 2803 } 2804 2805 uhp->uh_walk = mark; 2806 2807 /* go down in the tree if we haven't been there */ 2808 if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != nomark 2809 && uhp->uh_prev.ptr->uh_walk != mark) 2810 { 2811 uhp = uhp->uh_prev.ptr; 2812 ++changes; 2813 } 2814 2815 /* go to alternate branch if we haven't been there */ 2816 else if (uhp->uh_alt_next.ptr != NULL 2817 && uhp->uh_alt_next.ptr->uh_walk != nomark 2818 && uhp->uh_alt_next.ptr->uh_walk != mark) 2819 uhp = uhp->uh_alt_next.ptr; 2820 2821 /* go up in the tree if we haven't been there and we are at the 2822 * start of alternate branches */ 2823 else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL 2824 && uhp->uh_next.ptr->uh_walk != nomark 2825 && uhp->uh_next.ptr->uh_walk != mark) 2826 { 2827 uhp = uhp->uh_next.ptr; 2828 --changes; 2829 } 2830 2831 else 2832 { 2833 /* need to backtrack; mark this node as done */ 2834 uhp->uh_walk = nomark; 2835 if (uhp->uh_alt_prev.ptr != NULL) 2836 uhp = uhp->uh_alt_prev.ptr; 2837 else 2838 { 2839 uhp = uhp->uh_next.ptr; 2840 --changes; 2841 } 2842 } 2843 } 2844 2845 if (ga.ga_len == 0) 2846 MSG(_("Nothing to undo")); 2847 else 2848 { 2849 sort_strings((char_u **)ga.ga_data, ga.ga_len); 2850 2851 msg_start(); 2852 msg_puts_attr((char_u *)_("number changes time saved"), 2853 hl_attr(HLF_T)); 2854 for (i = 0; i < ga.ga_len && !got_int; ++i) 2855 { 2856 msg_putchar('\n'); 2857 if (got_int) 2858 break; 2859 msg_puts(((char_u **)ga.ga_data)[i]); 2860 } 2861 msg_end(); 2862 2863 ga_clear_strings(&ga); 2864 } 2865} 2866 2867/* 2868 * Put the timestamp of an undo header in "buf[buflen]" in a nice format. 2869 */ 2870 static void 2871u_add_time(buf, buflen, tt) 2872 char_u *buf; 2873 size_t buflen; 2874 time_t tt; 2875{ 2876#ifdef HAVE_STRFTIME 2877 struct tm *curtime; 2878 2879 if (time(NULL) - tt >= 100) 2880 { 2881 curtime = localtime(&tt); 2882 (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime); 2883 } 2884 else 2885#endif 2886 vim_snprintf((char *)buf, buflen, _("%ld seconds ago"), 2887 (long)(time(NULL) - tt)); 2888} 2889 2890/* 2891 * ":undojoin": continue adding to the last entry list 2892 */ 2893 void 2894ex_undojoin(eap) 2895 exarg_T *eap UNUSED; 2896{ 2897 if (curbuf->b_u_newhead == NULL) 2898 return; /* nothing changed before */ 2899 if (curbuf->b_u_curhead != NULL) 2900 { 2901 EMSG(_("E790: undojoin is not allowed after undo")); 2902 return; 2903 } 2904 if (!curbuf->b_u_synced) 2905 return; /* already unsynced */ 2906 if (p_ul < 0) 2907 return; /* no entries, nothing to do */ 2908 else 2909 { 2910 /* Go back to the last entry */ 2911 curbuf->b_u_curhead = curbuf->b_u_newhead; 2912 curbuf->b_u_synced = FALSE; /* no entries, nothing to do */ 2913 } 2914} 2915 2916/* 2917 * Called after writing or reloading the file and setting b_changed to FALSE. 2918 * Now an undo means that the buffer is modified. 2919 */ 2920 void 2921u_unchanged(buf) 2922 buf_T *buf; 2923{ 2924 u_unch_branch(buf->b_u_oldhead); 2925 buf->b_did_warn = FALSE; 2926} 2927 2928/* 2929 * After reloading a buffer which was saved for 'undoreload': Find the first 2930 * line that was changed and set the cursor there. 2931 */ 2932 void 2933u_find_first_changed() 2934{ 2935 u_header_T *uhp = curbuf->b_u_newhead; 2936 u_entry_T *uep; 2937 linenr_T lnum; 2938 2939 if (curbuf->b_u_curhead != NULL || uhp == NULL) 2940 return; /* undid something in an autocmd? */ 2941 2942 /* Check that the last undo block was for the whole file. */ 2943 uep = uhp->uh_entry; 2944 if (uep->ue_top != 0 || uep->ue_bot != 0) 2945 return; 2946 2947 for (lnum = 1; lnum < curbuf->b_ml.ml_line_count 2948 && lnum <= uep->ue_size; ++lnum) 2949 if (STRCMP(ml_get_buf(curbuf, lnum, FALSE), 2950 uep->ue_array[lnum - 1]) != 0) 2951 { 2952 clearpos(&(uhp->uh_cursor)); 2953 uhp->uh_cursor.lnum = lnum; 2954 return; 2955 } 2956 if (curbuf->b_ml.ml_line_count != uep->ue_size) 2957 { 2958 /* lines added or deleted at the end, put the cursor there */ 2959 clearpos(&(uhp->uh_cursor)); 2960 uhp->uh_cursor.lnum = lnum; 2961 } 2962} 2963 2964/* 2965 * Increase the write count, store it in the last undo header, what would be 2966 * used for "u". 2967 */ 2968 void 2969u_update_save_nr(buf) 2970 buf_T *buf; 2971{ 2972 u_header_T *uhp; 2973 2974 ++buf->b_u_save_nr_last; 2975 buf->b_u_save_nr_cur = buf->b_u_save_nr_last; 2976 uhp = buf->b_u_curhead; 2977 if (uhp != NULL) 2978 uhp = uhp->uh_next.ptr; 2979 else 2980 uhp = buf->b_u_newhead; 2981 if (uhp != NULL) 2982 uhp->uh_save_nr = buf->b_u_save_nr_last; 2983} 2984 2985 static void 2986u_unch_branch(uhp) 2987 u_header_T *uhp; 2988{ 2989 u_header_T *uh; 2990 2991 for (uh = uhp; uh != NULL; uh = uh->uh_prev.ptr) 2992 { 2993 uh->uh_flags |= UH_CHANGED; 2994 if (uh->uh_alt_next.ptr != NULL) 2995 u_unch_branch(uh->uh_alt_next.ptr); /* recursive */ 2996 } 2997} 2998 2999/* 3000 * Get pointer to last added entry. 3001 * If it's not valid, give an error message and return NULL. 3002 */ 3003 static u_entry_T * 3004u_get_headentry() 3005{ 3006 if (curbuf->b_u_newhead == NULL || curbuf->b_u_newhead->uh_entry == NULL) 3007 { 3008 EMSG(_("E439: undo list corrupt")); 3009 return NULL; 3010 } 3011 return curbuf->b_u_newhead->uh_entry; 3012} 3013 3014/* 3015 * u_getbot(): compute the line number of the previous u_save 3016 * It is called only when b_u_synced is FALSE. 3017 */ 3018 static void 3019u_getbot() 3020{ 3021 u_entry_T *uep; 3022 linenr_T extra; 3023 3024 uep = u_get_headentry(); /* check for corrupt undo list */ 3025 if (uep == NULL) 3026 return; 3027 3028 uep = curbuf->b_u_newhead->uh_getbot_entry; 3029 if (uep != NULL) 3030 { 3031 /* 3032 * the new ue_bot is computed from the number of lines that has been 3033 * inserted (0 - deleted) since calling u_save. This is equal to the 3034 * old line count subtracted from the current line count. 3035 */ 3036 extra = curbuf->b_ml.ml_line_count - uep->ue_lcount; 3037 uep->ue_bot = uep->ue_top + uep->ue_size + 1 + extra; 3038 if (uep->ue_bot < 1 || uep->ue_bot > curbuf->b_ml.ml_line_count) 3039 { 3040 EMSG(_("E440: undo line missing")); 3041 uep->ue_bot = uep->ue_top + 1; /* assume all lines deleted, will 3042 * get all the old lines back 3043 * without deleting the current 3044 * ones */ 3045 } 3046 3047 curbuf->b_u_newhead->uh_getbot_entry = NULL; 3048 } 3049 3050 curbuf->b_u_synced = TRUE; 3051} 3052 3053/* 3054 * Free one header "uhp" and its entry list and adjust the pointers. 3055 */ 3056 static void 3057u_freeheader(buf, uhp, uhpp) 3058 buf_T *buf; 3059 u_header_T *uhp; 3060 u_header_T **uhpp; /* if not NULL reset when freeing this header */ 3061{ 3062 u_header_T *uhap; 3063 3064 /* When there is an alternate redo list free that branch completely, 3065 * because we can never go there. */ 3066 if (uhp->uh_alt_next.ptr != NULL) 3067 u_freebranch(buf, uhp->uh_alt_next.ptr, uhpp); 3068 3069 if (uhp->uh_alt_prev.ptr != NULL) 3070 uhp->uh_alt_prev.ptr->uh_alt_next.ptr = NULL; 3071 3072 /* Update the links in the list to remove the header. */ 3073 if (uhp->uh_next.ptr == NULL) 3074 buf->b_u_oldhead = uhp->uh_prev.ptr; 3075 else 3076 uhp->uh_next.ptr->uh_prev.ptr = uhp->uh_prev.ptr; 3077 3078 if (uhp->uh_prev.ptr == NULL) 3079 buf->b_u_newhead = uhp->uh_next.ptr; 3080 else 3081 for (uhap = uhp->uh_prev.ptr; uhap != NULL; 3082 uhap = uhap->uh_alt_next.ptr) 3083 uhap->uh_next.ptr = uhp->uh_next.ptr; 3084 3085 u_freeentries(buf, uhp, uhpp); 3086} 3087 3088/* 3089 * Free an alternate branch and any following alternate branches. 3090 */ 3091 static void 3092u_freebranch(buf, uhp, uhpp) 3093 buf_T *buf; 3094 u_header_T *uhp; 3095 u_header_T **uhpp; /* if not NULL reset when freeing this header */ 3096{ 3097 u_header_T *tofree, *next; 3098 3099 /* If this is the top branch we may need to use u_freeheader() to update 3100 * all the pointers. */ 3101 if (uhp == buf->b_u_oldhead) 3102 { 3103 u_freeheader(buf, uhp, uhpp); 3104 return; 3105 } 3106 3107 if (uhp->uh_alt_prev.ptr != NULL) 3108 uhp->uh_alt_prev.ptr->uh_alt_next.ptr = NULL; 3109 3110 next = uhp; 3111 while (next != NULL) 3112 { 3113 tofree = next; 3114 if (tofree->uh_alt_next.ptr != NULL) 3115 u_freebranch(buf, tofree->uh_alt_next.ptr, uhpp); /* recursive */ 3116 next = tofree->uh_prev.ptr; 3117 u_freeentries(buf, tofree, uhpp); 3118 } 3119} 3120 3121/* 3122 * Free all the undo entries for one header and the header itself. 3123 * This means that "uhp" is invalid when returning. 3124 */ 3125 static void 3126u_freeentries(buf, uhp, uhpp) 3127 buf_T *buf; 3128 u_header_T *uhp; 3129 u_header_T **uhpp; /* if not NULL reset when freeing this header */ 3130{ 3131 u_entry_T *uep, *nuep; 3132 3133 /* Check for pointers to the header that become invalid now. */ 3134 if (buf->b_u_curhead == uhp) 3135 buf->b_u_curhead = NULL; 3136 if (buf->b_u_newhead == uhp) 3137 buf->b_u_newhead = NULL; /* freeing the newest entry */ 3138 if (uhpp != NULL && uhp == *uhpp) 3139 *uhpp = NULL; 3140 3141 for (uep = uhp->uh_entry; uep != NULL; uep = nuep) 3142 { 3143 nuep = uep->ue_next; 3144 u_freeentry(uep, uep->ue_size); 3145 } 3146 3147#ifdef U_DEBUG 3148 uhp->uh_magic = 0; 3149#endif 3150 vim_free((char_u *)uhp); 3151 --buf->b_u_numhead; 3152} 3153 3154/* 3155 * free entry 'uep' and 'n' lines in uep->ue_array[] 3156 */ 3157 static void 3158u_freeentry(uep, n) 3159 u_entry_T *uep; 3160 long n; 3161{ 3162 while (n > 0) 3163 vim_free(uep->ue_array[--n]); 3164 vim_free((char_u *)uep->ue_array); 3165#ifdef U_DEBUG 3166 uep->ue_magic = 0; 3167#endif 3168 vim_free((char_u *)uep); 3169} 3170 3171/* 3172 * invalidate the undo buffer; called when storage has already been released 3173 */ 3174 void 3175u_clearall(buf) 3176 buf_T *buf; 3177{ 3178 buf->b_u_newhead = buf->b_u_oldhead = buf->b_u_curhead = NULL; 3179 buf->b_u_synced = TRUE; 3180 buf->b_u_numhead = 0; 3181 buf->b_u_line_ptr = NULL; 3182 buf->b_u_line_lnum = 0; 3183} 3184 3185/* 3186 * save the line "lnum" for the "U" command 3187 */ 3188 void 3189u_saveline(lnum) 3190 linenr_T lnum; 3191{ 3192 if (lnum == curbuf->b_u_line_lnum) /* line is already saved */ 3193 return; 3194 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) /* should never happen */ 3195 return; 3196 u_clearline(); 3197 curbuf->b_u_line_lnum = lnum; 3198 if (curwin->w_cursor.lnum == lnum) 3199 curbuf->b_u_line_colnr = curwin->w_cursor.col; 3200 else 3201 curbuf->b_u_line_colnr = 0; 3202 if ((curbuf->b_u_line_ptr = u_save_line(lnum)) == NULL) 3203 do_outofmem_msg((long_u)0); 3204} 3205 3206/* 3207 * clear the line saved for the "U" command 3208 * (this is used externally for crossing a line while in insert mode) 3209 */ 3210 void 3211u_clearline() 3212{ 3213 if (curbuf->b_u_line_ptr != NULL) 3214 { 3215 vim_free(curbuf->b_u_line_ptr); 3216 curbuf->b_u_line_ptr = NULL; 3217 curbuf->b_u_line_lnum = 0; 3218 } 3219} 3220 3221/* 3222 * Implementation of the "U" command. 3223 * Differentiation from vi: "U" can be undone with the next "U". 3224 * We also allow the cursor to be in another line. 3225 * Careful: may trigger autocommands that reload the buffer. 3226 */ 3227 void 3228u_undoline() 3229{ 3230 colnr_T t; 3231 char_u *oldp; 3232 3233 if (undo_off) 3234 return; 3235 3236 if (curbuf->b_u_line_ptr == NULL 3237 || curbuf->b_u_line_lnum > curbuf->b_ml.ml_line_count) 3238 { 3239 beep_flush(); 3240 return; 3241 } 3242 3243 /* first save the line for the 'u' command */ 3244 if (u_savecommon(curbuf->b_u_line_lnum - 1, 3245 curbuf->b_u_line_lnum + 1, (linenr_T)0, FALSE) == FAIL) 3246 return; 3247 oldp = u_save_line(curbuf->b_u_line_lnum); 3248 if (oldp == NULL) 3249 { 3250 do_outofmem_msg((long_u)0); 3251 return; 3252 } 3253 ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, TRUE); 3254 changed_bytes(curbuf->b_u_line_lnum, 0); 3255 vim_free(curbuf->b_u_line_ptr); 3256 curbuf->b_u_line_ptr = oldp; 3257 3258 t = curbuf->b_u_line_colnr; 3259 if (curwin->w_cursor.lnum == curbuf->b_u_line_lnum) 3260 curbuf->b_u_line_colnr = curwin->w_cursor.col; 3261 if (Unix2003_compat) { 3262 /* vi_05 test 276: "U" sets column to start of line */ 3263 t = 0; 3264 } 3265 curwin->w_cursor.col = t; 3266 curwin->w_cursor.lnum = curbuf->b_u_line_lnum; 3267 check_cursor_col(); 3268} 3269 3270/* 3271 * Free all allocated memory blocks for the buffer 'buf'. 3272 */ 3273 void 3274u_blockfree(buf) 3275 buf_T *buf; 3276{ 3277 while (buf->b_u_oldhead != NULL) 3278 u_freeheader(buf, buf->b_u_oldhead, NULL); 3279 vim_free(buf->b_u_line_ptr); 3280} 3281 3282/* 3283 * u_save_line(): allocate memory and copy line 'lnum' into it. 3284 * Returns NULL when out of memory. 3285 */ 3286 static char_u * 3287u_save_line(lnum) 3288 linenr_T lnum; 3289{ 3290 return vim_strsave(ml_get(lnum)); 3291} 3292 3293/* 3294 * Check if the 'modified' flag is set, or 'ff' has changed (only need to 3295 * check the first character, because it can only be "dos", "unix" or "mac"). 3296 * "nofile" and "scratch" type buffers are considered to always be unchanged. 3297 */ 3298 int 3299bufIsChanged(buf) 3300 buf_T *buf; 3301{ 3302 return 3303#ifdef FEAT_QUICKFIX 3304 !bt_dontwrite(buf) && 3305#endif 3306 (buf->b_changed || file_ff_differs(buf)); 3307} 3308 3309 int 3310curbufIsChanged() 3311{ 3312 return 3313#ifdef FEAT_QUICKFIX 3314 !bt_dontwrite(curbuf) && 3315#endif 3316 (curbuf->b_changed || file_ff_differs(curbuf)); 3317} 3318 3319#if defined(FEAT_EVAL) || defined(PROTO) 3320/* 3321 * For undotree(): Append the list of undo blocks at "first_uhp" to "list". 3322 * Recursive. 3323 */ 3324 void 3325u_eval_tree(first_uhp, list) 3326 u_header_T *first_uhp; 3327 list_T *list; 3328{ 3329 u_header_T *uhp = first_uhp; 3330 dict_T *dict; 3331 3332 while (uhp != NULL) 3333 { 3334 dict = dict_alloc(); 3335 if (dict == NULL) 3336 return; 3337 dict_add_nr_str(dict, "seq", uhp->uh_seq, NULL); 3338 dict_add_nr_str(dict, "time", (long)uhp->uh_time, NULL); 3339 if (uhp == curbuf->b_u_newhead) 3340 dict_add_nr_str(dict, "newhead", 1, NULL); 3341 if (uhp == curbuf->b_u_curhead) 3342 dict_add_nr_str(dict, "curhead", 1, NULL); 3343 if (uhp->uh_save_nr > 0) 3344 dict_add_nr_str(dict, "save", uhp->uh_save_nr, NULL); 3345 3346 if (uhp->uh_alt_next.ptr != NULL) 3347 { 3348 list_T *alt_list = list_alloc(); 3349 3350 if (alt_list != NULL) 3351 { 3352 /* Recursive call to add alternate undo tree. */ 3353 u_eval_tree(uhp->uh_alt_next.ptr, alt_list); 3354 dict_add_list(dict, "alt", alt_list); 3355 } 3356 } 3357 3358 list_append_dict(list, dict); 3359 uhp = uhp->uh_prev.ptr; 3360 } 3361} 3362#endif 3363