undo.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:29k
源码类别:

编辑器/阅读器

开发平台:

DOS

  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.  */
  8. /*
  9.  * undo.c: multi level undo facility
  10.  *
  11.  * The saved lines are stored in a list of lists (one for each buffer):
  12.  *
  13.  * b_u_oldhead------------------------------------------------+
  14.  *       |
  15.  *       V
  16.  *   +--------------+    +--------------+   +--------------+
  17.  * b_u_newhead--->| u_header  |    | u_header     |   | u_header  |
  18.  *   | uh_next------>|     uh_next------>| uh_next---->NULL
  19.  *    NULL<--------uh_prev  |<---------uh_prev  |<---------uh_prev  |
  20.  *   | uh_entry |    |     uh_entry |   | uh_entry |
  21.  *   +--------|-----+    +--------|-----+   +--------|-----+
  22.  *    |        |    |
  23.  *    V        V    V
  24.  *   +--------------+    +--------------+   +--------------+
  25.  *   | u_entry  |    | u_entry      |   | u_entry  |
  26.  *   | ue_next  |    |     ue_next  |   | ue_next  |
  27.  *   +--------|-----+    +--------|-----+   +--------|-----+
  28.  *    |        |    |
  29.  *    V        V    V
  30.  *   +--------------+       NULL   NULL
  31.  *   | u_entry  |
  32.  *   | ue_next  |
  33.  *   +--------|-----+
  34.  *    |
  35.  *    V
  36.  *   etc.
  37.  *
  38.  * Each u_entry list contains the information for one undo or redo.
  39.  * curbuf->b_u_curhead points to the header of the last undo (the next redo),
  40.  * or is NULL if nothing has been undone.
  41.  *
  42.  * All data is allocated with u_alloc_line(), thus it will be freed as soon as
  43.  * we switch files!
  44.  */
  45. #include "vim.h"
  46. static void u_getbot __ARGS((void));
  47. static int u_savecommon __ARGS((linenr_t, linenr_t, linenr_t));
  48. static void u_doit __ARGS((int count));
  49. static void u_undoredo __ARGS((void));
  50. static void u_undo_end __ARGS((void));
  51. static void u_freelist __ARGS((struct u_header *));
  52. static void u_freeentry __ARGS((struct u_entry *, long));
  53. static char_u *u_blockalloc __ARGS((long_u));
  54. static void u_free_line __ARGS((char_u *));
  55. static char_u *u_alloc_line __ARGS((unsigned));
  56. static char_u *u_save_line __ARGS((linenr_t));
  57. static long u_newcount, u_oldcount;
  58. /*
  59.  * When 'u' flag included in 'cpoptions', we behave like vi.  Need to remember
  60.  * the action that "u" should do.
  61.  */
  62. static int undo_undoes = FALSE;
  63. /*
  64.  * save the current line for both the "u" and "U" command
  65.  */
  66.     int
  67. u_save_cursor()
  68. {
  69.     return (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
  70.       (linenr_t)(curwin->w_cursor.lnum + 1)));
  71. }
  72. /*
  73.  * Save the lines between "top" and "bot" for both the "u" and "U" command.
  74.  * "top" may be 0 and bot may be curbuf->b_ml.ml_line_count + 1.
  75.  * Returns FAIL when lines could not be saved, OK otherwise.
  76.  */
  77.     int
  78. u_save(top, bot)
  79.     linenr_t top, bot;
  80. {
  81.     if (undo_off)
  82. return OK;
  83.     if (top > curbuf->b_ml.ml_line_count ||
  84.     top >= bot || bot > curbuf->b_ml.ml_line_count + 1)
  85. return FALSE; /* rely on caller to do error messages */
  86.     if (top + 2 == bot)
  87. u_saveline((linenr_t)(top + 1));
  88.     return (u_savecommon(top, bot, (linenr_t)0));
  89. }
  90. /*
  91.  * save the line "lnum" (used by :s command)
  92.  * The line is replaced, so the new bottom line is lnum + 1.
  93.  */
  94.     int
  95. u_savesub(lnum)
  96.     linenr_t lnum;
  97. {
  98.     if (undo_off)
  99. return OK;
  100.     return (u_savecommon(lnum - 1, lnum + 1, lnum + 1));
  101. }
  102. /*
  103.  * a new line is inserted before line "lnum" (used by :s command)
  104.  * The line is inserted, so the new bottom line is lnum + 1.
  105.  */
  106.     int
  107. u_inssub(lnum)
  108.     linenr_t lnum;
  109. {
  110.     if (undo_off)
  111. return OK;
  112.     return (u_savecommon(lnum - 1, lnum, lnum + 1));
  113. }
  114. /*
  115.  * save the lines "lnum" - "lnum" + nlines (used by delete command)
  116.  * The lines are deleted, so the new bottom line is lnum, unless the buffer
  117.  * becomes empty.
  118.  */
  119.     int
  120. u_savedel(lnum, nlines)
  121.     linenr_t lnum;
  122.     long nlines;
  123. {
  124.     if (undo_off)
  125. return OK;
  126.     return (u_savecommon(lnum - 1, lnum + nlines,
  127. nlines == curbuf->b_ml.ml_line_count ? 2 : lnum));
  128. }
  129.     static int
  130. u_savecommon(top, bot, newbot)
  131.     linenr_t top, bot;
  132.     linenr_t newbot;
  133. {
  134.     linenr_t     lnum;
  135.     long     i;
  136.     struct u_header *uhp;
  137.     struct u_entry  *uep;
  138.     long     size;
  139.     /*
  140.      * if curbuf->b_u_synced == TRUE make a new header
  141.      */
  142.     if (curbuf->b_u_synced)
  143.     {
  144. /*
  145.  * if we undid more than we redid, free the entry lists before and
  146.  * including curbuf->b_u_curhead
  147.  */
  148. while (curbuf->b_u_curhead != NULL)
  149.     u_freelist(curbuf->b_u_newhead);
  150. /*
  151.  * free headers to keep the size right
  152.  */
  153. while (curbuf->b_u_numhead > p_ul && curbuf->b_u_oldhead != NULL)
  154.     u_freelist(curbuf->b_u_oldhead);
  155. if (p_ul < 0) /* no undo at all */
  156.     return OK;
  157. /*
  158.  * make a new header entry
  159.  */
  160. uhp = (struct u_header *)u_alloc_line((unsigned)
  161.      sizeof(struct u_header));
  162. if (uhp == NULL)
  163.     goto nomem;
  164. uhp->uh_prev = NULL;
  165. uhp->uh_next = curbuf->b_u_newhead;
  166. if (curbuf->b_u_newhead != NULL)
  167.     curbuf->b_u_newhead->uh_prev = uhp;
  168. uhp->uh_entry = NULL;
  169. uhp->uh_cursor = curwin->w_cursor; /* save cursor pos. for undo */
  170. /* save changed and buffer empty flag for undo */
  171. uhp->uh_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
  172.        ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0);
  173. /* save named marks for undo */
  174. mch_memmove(uhp->uh_namedm, curbuf->b_namedm, sizeof(FPOS) * NMARKS);
  175. curbuf->b_u_newhead = uhp;
  176. if (curbuf->b_u_oldhead == NULL)
  177.     curbuf->b_u_oldhead = uhp;
  178. ++curbuf->b_u_numhead;
  179.     }
  180.     else    /* find line number for ue_bot for previous u_save() */
  181. u_getbot();
  182.     size = bot - top - 1;
  183. #if !defined(UNIX) && !defined(DJGPP) && !defined(WIN32) && !defined(__EMX__)
  184. /*
  185.  * With Amiga and MSDOS 16 bit we can't handle big undo's, because
  186.  * then u_alloc_line would have to allocate a block larger than 32K
  187.  */
  188.     if (size >= 8000)
  189. goto nomem;
  190. #endif
  191.     /*
  192.      * add lines in front of entry list
  193.      */
  194.     uep = (struct u_entry *)u_alloc_line((unsigned)sizeof(struct u_entry));
  195.     if (uep == NULL)
  196. goto nomem;
  197.     uep->ue_size = size;
  198.     uep->ue_top = top;
  199.     uep->ue_lcount = 0;
  200.     if (newbot)
  201. uep->ue_bot = newbot;
  202. /*
  203.  * Use 0 for ue_bot if bot is below last line.
  204.  * Otherwise we have to compute ue_bot later.
  205.  */
  206.     else if (bot > curbuf->b_ml.ml_line_count)
  207. uep->ue_bot = 0;
  208.     else
  209. uep->ue_lcount = curbuf->b_ml.ml_line_count;
  210.     if (size)
  211.     {
  212. if ((uep->ue_array = (char_u **)u_alloc_line((unsigned)(sizeof(char_u *) * size))) == NULL)
  213. {
  214.     u_freeentry(uep, 0L);
  215.     goto nomem;
  216. }
  217. for (i = 0, lnum = top + 1; i < size; ++i)
  218. {
  219.     if ((uep->ue_array[i] = u_save_line(lnum++)) == NULL)
  220.     {
  221. u_freeentry(uep, i);
  222. goto nomem;
  223.     }
  224. }
  225.     }
  226.     uep->ue_next = curbuf->b_u_newhead->uh_entry;
  227.     curbuf->b_u_newhead->uh_entry = uep;
  228.     curbuf->b_u_synced = FALSE;
  229.     undo_undoes = FALSE;
  230.     return OK;
  231. nomem:
  232.     if (ask_yesno((char_u *)"No undo possible; continue anyway", TRUE) == 'y')
  233.     {
  234. undo_off = TRUE;     /* will be reset when character typed */
  235. return OK;
  236.     }
  237.     do_outofmem_msg();
  238.     return FAIL;
  239. }
  240. /*
  241.  * If 'cpoptions' contains 'u': Undo the previous undo or redo (vi compatible).
  242.  * If 'cpoptions' does not contain 'u': Always undo.
  243.  */
  244.     void
  245. u_undo(count)
  246.     int count;
  247. {
  248.     /*
  249.      * If we get an undo command while executing a macro, we behave like the
  250.      * original vi. If this happens twice in one macro the result will not
  251.      * be compatible.
  252.      */
  253.     if (curbuf->b_u_synced == FALSE)
  254.     {
  255. u_sync();
  256. count = 1;
  257.     }
  258.     if (vim_strchr(p_cpo, CPO_UNDO) == NULL)
  259. undo_undoes = TRUE;
  260.     else
  261. undo_undoes = !undo_undoes;
  262.     u_doit(count);
  263. }
  264. /*
  265.  * If 'cpoptions' contains 'u': Repeat the previous undo or redo.
  266.  * If 'cpoptions' does not contain 'u': Always redo.
  267.  */
  268.     void
  269. u_redo(count)
  270.     int count;
  271. {
  272.     if (vim_strchr(p_cpo, CPO_UNDO) == NULL)
  273. undo_undoes = FALSE;
  274.     u_doit(count);
  275. }
  276. /*
  277.  * Undo or redo, depending on 'undo_undoes', 'count' times.
  278.  */
  279.     static void
  280. u_doit(count)
  281.     int count;
  282. {
  283.     u_newcount = 0;
  284.     u_oldcount = 0;
  285.     while (count--)
  286.     {
  287. if (undo_undoes)
  288. {
  289.     if (curbuf->b_u_curhead == NULL) /* first undo */
  290. curbuf->b_u_curhead = curbuf->b_u_newhead;
  291.     else if (p_ul > 0) /* multi level undo */
  292. /* get next undo */
  293. curbuf->b_u_curhead = curbuf->b_u_curhead->uh_next;
  294.     /* nothing to undo */
  295.     if (curbuf->b_u_numhead == 0 || curbuf->b_u_curhead == NULL)
  296.     {
  297. /* stick curbuf->b_u_curhead at end */
  298. curbuf->b_u_curhead = curbuf->b_u_oldhead;
  299. beep_flush();
  300. break;
  301.     }
  302.     u_undoredo();
  303. }
  304. else
  305. {
  306.     if (curbuf->b_u_curhead == NULL || p_ul <= 0)
  307.     {
  308. beep_flush(); /* nothing to redo */
  309. break;
  310.     }
  311.     u_undoredo();
  312.     /* advance for next redo */
  313.     curbuf->b_u_curhead = curbuf->b_u_curhead->uh_prev;
  314. }
  315.     }
  316.     u_undo_end();
  317. }
  318. /*
  319.  * u_undoredo: common code for undo and redo
  320.  *
  321.  * The lines in the file are replaced by the lines in the entry list at
  322.  * curbuf->b_u_curhead. The replaced lines in the file are saved in the entry
  323.  * list for the next undo/redo.
  324.  */
  325.     static void
  326. u_undoredo()
  327. {
  328.     char_u **newarray = NULL;
  329.     linenr_t oldsize;
  330.     linenr_t newsize;
  331.     linenr_t top, bot;
  332.     linenr_t lnum;
  333.     linenr_t newlnum = MAXLNUM;
  334.     long i;
  335.     struct u_entry *uep, *nuep;
  336.     struct u_entry *newlist = NULL;
  337.     int old_flags;
  338.     int new_flags;
  339.     FPOS namedm[NMARKS];
  340.     int empty_buffer;     /* buffer became empty */
  341.     old_flags = curbuf->b_u_curhead->uh_flags;
  342.     new_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
  343.        ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0);
  344.     if (old_flags & UH_CHANGED)
  345. changed();
  346.     else
  347. unchanged(curbuf, FALSE);
  348.     setpcmark();
  349.     changed_line_abv_curs(); /* need to recompute cursor posn on screen */
  350.     /*
  351.      * save marks before undo/redo
  352.      */
  353.     mch_memmove(namedm, curbuf->b_namedm, sizeof(FPOS) * NMARKS);
  354.     curbuf->b_op_start.lnum = curbuf->b_ml.ml_line_count;
  355.     curbuf->b_op_start.col = 0;
  356.     curbuf->b_op_end.lnum = 0;
  357.     curbuf->b_op_end.col = 0;
  358.     for (uep = curbuf->b_u_curhead->uh_entry; uep != NULL; uep = nuep)
  359.     {
  360. top = uep->ue_top;
  361. bot = uep->ue_bot;
  362. if (bot == 0)
  363.     bot = curbuf->b_ml.ml_line_count + 1;
  364. if (top > curbuf->b_ml.ml_line_count || top >= bot || bot > curbuf->b_ml.ml_line_count + 1)
  365. {
  366.     EMSG("u_undo: line numbers wrong");
  367.     changed(); /* don't want UNCHANGED now */
  368.     return;
  369. }
  370. if (top < newlnum)
  371. {
  372.     newlnum = top;
  373.     curwin->w_cursor.lnum = top + 1;
  374. }
  375. oldsize = bot - top - 1;    /* number of lines before undo */
  376. newsize = uep->ue_size;     /* number of lines after undo */
  377. empty_buffer = FALSE;
  378. /* delete the lines between top and bot and save them in newarray */
  379. if (oldsize)
  380. {
  381.     if ((newarray = (char_u **)u_alloc_line((unsigned)(sizeof(char_u *) * oldsize))) == NULL)
  382.     {
  383. do_outofmem_msg();
  384. /*
  385.  * We have messed up the entry list, repair is impossible.
  386.  * we have to free the rest of the list.
  387.  */
  388. while (uep != NULL)
  389. {
  390.     nuep = uep->ue_next;
  391.     u_freeentry(uep, uep->ue_size);
  392.     uep = nuep;
  393. }
  394. break;
  395.     }
  396.     /* delete backwards, it goes faster in most cases */
  397.     for (lnum = bot - 1, i = oldsize; --i >= 0; --lnum)
  398.     {
  399.     /* what can we do when we run out of memory? */
  400. if ((newarray[i] = u_save_line(lnum)) == NULL)
  401.     do_outofmem_msg();
  402.     /* remember we deleted the last line in the buffer, and a
  403.      * dummy empty line will be inserted */
  404. if (curbuf->b_ml.ml_line_count == 1)
  405.     empty_buffer = TRUE;
  406. ml_delete(lnum, FALSE);
  407.     }
  408. }
  409. /* insert the lines in u_array between top and bot */
  410. if (newsize)
  411. {
  412.     for (lnum = top, i = 0; i < newsize; ++i, ++lnum)
  413.     {
  414. /*
  415.  * If the file is empty, there is an empty line 1 that we
  416.  * should get rid of, by replacing it with the new line
  417.  */
  418. if (empty_buffer && lnum == 0)
  419.     ml_replace((linenr_t)1, uep->ue_array[i], TRUE);
  420. else
  421.     ml_append(lnum, uep->ue_array[i], (colnr_t)0, FALSE);
  422. u_free_line(uep->ue_array[i]);
  423.     }
  424.     u_free_line((char_u *)uep->ue_array);
  425. }
  426. /* adjust marks */
  427. if (oldsize != newsize)
  428. {
  429.     mark_adjust(top + 1, top + oldsize, (linenr_t)MAXLNUM,
  430.        (long)newsize - (long)oldsize);
  431.     if (curbuf->b_op_start.lnum > top + oldsize)
  432. curbuf->b_op_start.lnum += newsize - oldsize;
  433.     if (curbuf->b_op_end.lnum > top + oldsize)
  434. curbuf->b_op_end.lnum += newsize - oldsize;
  435. }
  436. /* set '[ and '] mark */
  437. if (top + 1 < curbuf->b_op_start.lnum)
  438.     curbuf->b_op_start.lnum = top + 1;
  439. if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum)
  440.     curbuf->b_op_end.lnum = top + 1;
  441. else if (top + newsize > curbuf->b_op_end.lnum)
  442.     curbuf->b_op_end.lnum = top + newsize;
  443. u_newcount += newsize;
  444. u_oldcount += oldsize;
  445. uep->ue_size = oldsize;
  446. uep->ue_array = newarray;
  447. uep->ue_bot = top + newsize + 1;
  448. /*
  449.  * insert this entry in front of the new entry list
  450.  */
  451. nuep = uep->ue_next;
  452. uep->ue_next = newlist;
  453. newlist = uep;
  454.     }
  455.     curbuf->b_u_curhead->uh_entry = newlist;
  456.     curbuf->b_u_curhead->uh_flags = new_flags;
  457.     if ((old_flags & UH_EMPTYBUF) && bufempty())
  458. curbuf->b_ml.ml_flags |= ML_EMPTY;
  459.     /*
  460.      * restore marks from before undo/redo
  461.      */
  462.     for (i = 0; i < NMARKS; ++i)
  463. if (curbuf->b_u_curhead->uh_namedm[i].lnum)
  464. {
  465.     curbuf->b_namedm[i] = curbuf->b_u_curhead->uh_namedm[i];
  466.     curbuf->b_u_curhead->uh_namedm[i] = namedm[i];
  467. }
  468.     /*
  469.      * If the cursor is only off by one line, put it at the same position as
  470.      * before starting the change (for the "o" command).
  471.      * Otherwise the cursor should go to the first undone line.
  472.      */
  473.     if (curbuf->b_u_curhead->uh_cursor.lnum + 1 == curwin->w_cursor.lnum &&
  474.     curwin->w_cursor.lnum > 1)
  475. --curwin->w_cursor.lnum;
  476.     if (curbuf->b_u_curhead->uh_cursor.lnum == curwin->w_cursor.lnum)
  477. curwin->w_cursor.col = curbuf->b_u_curhead->uh_cursor.col;
  478.     else if (curwin->w_cursor.lnum <= curbuf->b_ml.ml_line_count)
  479. beginline(BL_SOL | BL_FIX);
  480.     /* We still seem to need the case below because sometimes we get here with
  481.      * the current cursor line being one past the end (eg after adding lines
  482.      * at the end of the file, and then undoing it).  Is it fair enough that
  483.      * this happens? -- webb
  484.      */
  485.     else
  486. curwin->w_cursor.col = 0;
  487.     /* Make sure the cursor is on an existing line and column. */
  488.     adjust_cursor();
  489. }
  490. /*
  491.  * If we deleted or added lines, report the number of less/more lines.
  492.  * Otherwise, report the number of changes (this may be incorrect
  493.  * in some cases, but it's better than nothing).
  494.  */
  495.     static void
  496. u_undo_end()
  497. {
  498.     if ((u_oldcount -= u_newcount) != 0)
  499. msgmore(-u_oldcount);
  500.     else if (u_newcount > p_report)
  501. smsg((char_u *)"%ld change%s", u_newcount, plural(u_newcount));
  502.     update_topline();
  503.     update_curbuf(NOT_VALID); /* need to update all windows in this buffer */
  504. }
  505. /*
  506.  * u_sync: stop adding to the current entry list
  507.  */
  508.     void
  509. u_sync()
  510. {
  511.     if (curbuf->b_u_synced)
  512. return;     /* already synced */
  513.     u_getbot();     /* compute ue_bot of previous u_save */
  514.     curbuf->b_u_curhead = NULL;
  515. }
  516. /*
  517.  * Called after writing the file and setting b_changed to FALSE.
  518.  * Now an undo means that the buffer is modified.
  519.  */
  520.     void
  521. u_unchanged(buf)
  522.     BUF     *buf;
  523. {
  524.     struct u_header *uh;
  525.     for (uh = buf->b_u_newhead; uh; uh = uh->uh_next)
  526. uh->uh_flags |= UH_CHANGED;
  527.     buf->b_did_warn = FALSE;
  528. }
  529. /*
  530.  * u_getbot(): compute the line number of the previous u_save
  531.  * It is called only when b_u_synced is FALSE.
  532.  */
  533.     static void
  534. u_getbot()
  535. {
  536.     struct u_entry *uep;
  537.     if (curbuf->b_u_newhead == NULL ||
  538. (uep = curbuf->b_u_newhead->uh_entry) == NULL)
  539.     {
  540. EMSG("undo list corrupt");
  541. return;
  542.     }
  543.     if (uep->ue_lcount != 0)
  544.     {
  545. /*
  546.  * the new ue_bot is computed from the number of lines that has been
  547.  * inserted (0 - deleted) since calling u_save. This is equal to the old
  548.  * line count subtracted from the current line count.
  549.  */
  550. uep->ue_bot = uep->ue_top + uep->ue_size + 1 +
  551. (curbuf->b_ml.ml_line_count - uep->ue_lcount);
  552. if (uep->ue_bot < 1 || uep->ue_bot > curbuf->b_ml.ml_line_count)
  553. {
  554.     EMSG("undo line missing");
  555.     uep->ue_bot = uep->ue_top + 1;  /* assume all lines deleted, will
  556.      * get all the old lines back
  557.      * without deleting the current
  558.      * ones */
  559. }
  560. uep->ue_lcount = 0;
  561.     }
  562.     curbuf->b_u_synced = TRUE;
  563. }
  564. /*
  565.  * u_freelist: free one entry list and adjust the pointers
  566.  */
  567.     static void
  568. u_freelist(uhp)
  569.     struct u_header *uhp;
  570. {
  571.     struct u_entry *uep, *nuep;
  572.     for (uep = uhp->uh_entry; uep != NULL; uep = nuep)
  573.     {
  574. nuep = uep->ue_next;
  575. u_freeentry(uep, uep->ue_size);
  576.     }
  577.     if (curbuf->b_u_curhead == uhp)
  578. curbuf->b_u_curhead = NULL;
  579.     if (uhp->uh_next == NULL)
  580. curbuf->b_u_oldhead = uhp->uh_prev;
  581.     else
  582. uhp->uh_next->uh_prev = uhp->uh_prev;
  583.     if (uhp->uh_prev == NULL)
  584. curbuf->b_u_newhead = uhp->uh_next;
  585.     else
  586. uhp->uh_prev->uh_next = uhp->uh_next;
  587.     u_free_line((char_u *)uhp);
  588.     --curbuf->b_u_numhead;
  589. }
  590. /*
  591.  * free entry 'uep' and 'n' lines in uep->ue_array[]
  592.  */
  593.     static void
  594. u_freeentry(uep, n)
  595.     struct u_entry  *uep;
  596.     long     n;
  597. {
  598.     while (n)
  599. u_free_line(uep->ue_array[--n]);
  600.     u_free_line((char_u *)uep);
  601. }
  602. /*
  603.  * invalidate the undo buffer; called when storage has already been released
  604.  */
  605.     void
  606. u_clearall(buf)
  607.     BUF     *buf;
  608. {
  609.     buf->b_u_newhead = buf->b_u_oldhead = buf->b_u_curhead = NULL;
  610.     buf->b_u_synced = TRUE;
  611.     buf->b_u_numhead = 0;
  612.     buf->b_u_line_ptr = NULL;
  613.     buf->b_u_line_lnum = 0;
  614. }
  615. /*
  616.  * save the line "lnum" for the "U" command
  617.  */
  618.     void
  619. u_saveline(lnum)
  620.     linenr_t lnum;
  621. {
  622.     if (lnum == curbuf->b_u_line_lnum)     /* line is already saved */
  623. return;
  624.     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) /* should never happen */
  625. return;
  626.     u_clearline();
  627.     curbuf->b_u_line_lnum = lnum;
  628.     if (curwin->w_cursor.lnum == lnum)
  629. curbuf->b_u_line_colnr = curwin->w_cursor.col;
  630.     else
  631. curbuf->b_u_line_colnr = 0;
  632.     if ((curbuf->b_u_line_ptr = u_save_line(lnum)) == NULL)
  633. do_outofmem_msg();
  634. }
  635. /*
  636.  * clear the line saved for the "U" command
  637.  * (this is used externally for crossing a line while in insert mode)
  638.  */
  639.     void
  640. u_clearline()
  641. {
  642.     if (curbuf->b_u_line_ptr != NULL)
  643.     {
  644. u_free_line(curbuf->b_u_line_ptr);
  645. curbuf->b_u_line_ptr = NULL;
  646. curbuf->b_u_line_lnum = 0;
  647.     }
  648. }
  649. /*
  650.  * Implementation of the "U" command.
  651.  * Differentiation from vi: "U" can be undone with the next "U".
  652.  * We also allow the cursor to be in another line.
  653.  */
  654.     void
  655. u_undoline()
  656. {
  657.     colnr_t t;
  658.     char_u  *oldp;
  659.     if (undo_off)
  660. return;
  661.     if (curbuf->b_u_line_ptr == NULL ||
  662. curbuf->b_u_line_lnum > curbuf->b_ml.ml_line_count)
  663.     {
  664. beep_flush();
  665. return;
  666.     }
  667. /* first save the line for the 'u' command */
  668.     if (u_savecommon(curbuf->b_u_line_lnum - 1,
  669. curbuf->b_u_line_lnum + 1, (linenr_t)0) == FAIL)
  670. return;
  671.     oldp = u_save_line(curbuf->b_u_line_lnum);
  672.     if (oldp == NULL)
  673.     {
  674. do_outofmem_msg();
  675. return;
  676.     }
  677.     ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, TRUE);
  678.     u_free_line(curbuf->b_u_line_ptr);
  679.     curbuf->b_u_line_ptr = oldp;
  680. #ifdef SYNTAX_HL
  681.     /* recompute syntax hl., starting with current line */
  682.     syn_changed(curbuf->b_u_line_lnum);
  683. #endif
  684.     t = curbuf->b_u_line_colnr;
  685.     if (curwin->w_cursor.lnum == curbuf->b_u_line_lnum)
  686. curbuf->b_u_line_colnr = curwin->w_cursor.col;
  687.     changed_cline_bef_curs();
  688.     curwin->w_cursor.col = t;
  689.     curwin->w_cursor.lnum = curbuf->b_u_line_lnum;
  690.     approximate_botline(); /* w_botline may have changed a bit */
  691.     update_screen(VALID_TO_CURSCHAR);
  692. }
  693. /*
  694.  * storage allocation for the undo lines and blocks of the current file
  695.  */
  696. /*
  697.  * Memory is allocated in relatively large blocks. These blocks are linked
  698.  * in the allocated block list, headed by curbuf->b_block_head. They are all
  699.  * freed when abandoning a file, so we don't have to free every single line.
  700.  * The list is kept sorted on memory address.
  701.  * block_alloc() allocates a block.
  702.  * m_blockfree() frees all blocks.
  703.  *
  704.  * The available chunks of memory are kept in free chunk lists. There is
  705.  * one free list for each block of allocated memory. The list is kept sorted
  706.  * on memory address.
  707.  * u_alloc_line() gets a chunk from the free lists.
  708.  * u_free_line() returns a chunk to the free lists.
  709.  * curbuf->b_m_search points to the chunk before the chunk that was
  710.  * freed/allocated the last time.
  711.  * curbuf->b_mb_current points to the b_head where curbuf->b_m_search
  712.  * points into the free list.
  713.  *
  714.  *
  715.  *  b_block_head     /---> block #1 /---> block #2
  716.  *  mb_next ---/     mb_next ---/       mb_next ---> NULL
  717.  *  mb_info     mb_info        mb_info
  718.  *     |        |   |
  719.  *     V        V   V
  720.  *   NULL free chunk #1.1      free chunk #2.1
  721.  *        |   |
  722.  *        V   V
  723.  * free chunk #1.2  NULL
  724.  *        |
  725.  *        V
  726.  *       NULL
  727.  *
  728.  * When a single free chunk list would have been used, it could take a lot
  729.  * of time in u_free_line() to find the correct place to insert a chunk in the
  730.  * free list. The single free list would become very long when many lines are
  731.  * changed (e.g. with :%s/^M$//).
  732.  */
  733.     /*
  734.      * this blocksize is used when allocating new lines
  735.      */
  736. #define MEMBLOCKSIZE 2044
  737. /*
  738.  * The size field contains the size of the chunk, including the size field
  739.  * itself.
  740.  *
  741.  * When the chunk is not in-use it is preceded with the m_info structure.
  742.  * The m_next field links it in one of the free chunk lists.
  743.  *
  744.  * On most unix systems structures have to be longword (32 or 64 bit) aligned.
  745.  * On most other systems they are short (16 bit) aligned.
  746.  */
  747. /* the structure definitions are now in structs.h */
  748. #ifdef ALIGN_LONG
  749.     /* size of m_size */
  750. # define M_OFFSET (sizeof(long_u))
  751. #else
  752.     /* size of m_size */
  753. # define M_OFFSET (sizeof(short_u))
  754. #endif
  755. /*
  756.  * Allocate a block of memory and link it in the allocated block list.
  757.  */
  758.     static char_u *
  759. u_blockalloc(size)
  760.     long_u  size;
  761. {
  762.     struct m_block *p;
  763.     struct m_block *mp, *next;
  764.     p = (struct m_block *)lalloc(size + sizeof(struct m_block), FALSE);
  765.     if (p != NULL)
  766.     {
  767.  /* Insert the block into the allocated block list, keeping it
  768.     sorted on address. */
  769. for (mp = &curbuf->b_block_head;
  770. (next = mp->mb_next) != NULL && next < p;
  771. mp = next)
  772.     ;
  773. p->mb_next = next; /* link in block list */
  774. mp->mb_next = p;
  775. p->mb_info.m_next = NULL; /* clear free list */
  776. p->mb_info.m_size = 0;
  777. curbuf->b_mb_current = p; /* remember current block */
  778. curbuf->b_m_search = NULL;
  779. p++; /* return usable memory */
  780.     }
  781.     return (char_u *)p;
  782. }
  783. /*
  784.  * free all allocated memory blocks for the buffer 'buf'
  785.  */
  786.     void
  787. u_blockfree(buf)
  788.     BUF     *buf;
  789. {
  790.     struct m_block  *p, *np;
  791.     for (p = buf->b_block_head.mb_next; p != NULL; p = np)
  792.     {
  793. np = p->mb_next;
  794. vim_free(p);
  795.     }
  796.     buf->b_block_head.mb_next = NULL;
  797.     buf->b_m_search = NULL;
  798.     buf->b_mb_current = NULL;
  799. }
  800. /*
  801.  * Free a chunk of memory.
  802.  * Insert the chunk into the correct free list, keeping it sorted on address.
  803.  */
  804.     static void
  805. u_free_line(ptr)
  806.     char_u *ptr;
  807. {
  808.     info_t *next;
  809.     info_t *prev, *curr;
  810.     info_t *mp;
  811.     struct m_block *nextb;
  812.     if (ptr == NULL || ptr == IObuff)
  813. return; /* illegal address can happen in out-of-memory situations */
  814.     mp = (info_t *)(ptr - M_OFFSET);
  815.     /* find block where chunk could be a part off */
  816.     /* if we change curbuf->b_mb_current, curbuf->b_m_search is set to NULL */
  817.     if (curbuf->b_mb_current == NULL || mp < (info_t *)curbuf->b_mb_current)
  818.     {
  819. curbuf->b_mb_current = curbuf->b_block_head.mb_next;
  820. curbuf->b_m_search = NULL;
  821.     }
  822.     if ((nextb = curbuf->b_mb_current->mb_next) != NULL && (info_t *)nextb < mp)
  823.     {
  824. curbuf->b_mb_current = nextb;
  825. curbuf->b_m_search = NULL;
  826.     }
  827.     while ((nextb = curbuf->b_mb_current->mb_next) != NULL &&
  828.  (info_t *)nextb < mp)
  829. curbuf->b_mb_current = nextb;
  830.     curr = NULL;
  831.     /*
  832.      * If mp is smaller than curbuf->b_m_search->m_next go to the start of
  833.      * the free list
  834.      */
  835.     if (curbuf->b_m_search == NULL || mp < (curbuf->b_m_search->m_next))
  836. next = &(curbuf->b_mb_current->mb_info);
  837.     else
  838. next = curbuf->b_m_search;
  839.     /*
  840.      * The following loop is executed very often.
  841.      * Therefore it has been optimized at the cost of readability.
  842.      * Keep it fast!
  843.      */
  844. #ifdef SLOW_BUT_EASY_TO_READ
  845.     do
  846.     {
  847. prev = curr;
  848. curr = next;
  849. next = next->m_next;
  850.     }
  851.     while (mp > next && next != NULL);
  852. #else
  853.     do     /* first, middle, last */
  854.     {
  855. prev = next->m_next;     /* curr, next, prev */
  856. if (prev == NULL || mp <= prev)
  857. {
  858.     prev = curr;
  859.     curr = next;
  860.     next = next->m_next;
  861.     break;
  862. }
  863. curr = prev->m_next;     /* next, prev, curr */
  864. if (curr == NULL || mp <= curr)
  865. {
  866.     prev = next;
  867.     curr = prev->m_next;
  868.     next = curr->m_next;
  869.     break;
  870. }
  871. next = curr->m_next;     /* prev, curr, next */
  872.     }
  873.     while (mp > next && next != NULL);
  874. #endif
  875.     /* if *mp and *next are concatenated, join them into one chunk */
  876.     if ((char_u *)mp + mp->m_size == (char_u *)next)
  877.     {
  878. mp->m_size += next->m_size;
  879. mp->m_next = next->m_next;
  880.     }
  881.     else
  882. mp->m_next = next;
  883.     /* if *curr and *mp are concatenated, join them */
  884.     if (prev != NULL && (char_u *)curr + curr->m_size == (char_u *)mp)
  885.     {
  886. curr->m_size += mp->m_size;
  887. curr->m_next = mp->m_next;
  888. curbuf->b_m_search = prev;
  889.     }
  890.     else
  891.     {
  892. curr->m_next = mp;
  893. curbuf->b_m_search = curr;  /* put curbuf->b_m_search before freed
  894.        chunk */
  895.     }
  896. }
  897. /*
  898.  * Allocate and initialize a new line structure with room for at least
  899.  * 'size' characters plus a terminating NUL.
  900.  */
  901.     static char_u *
  902. u_alloc_line(size)
  903.     unsigned     size;
  904. {
  905.     info_t     *mp, *mprev, *mp2;
  906.     struct m_block  *mbp;
  907.     int     size_align;
  908.     /*
  909.      * Add room for size field and trailing NUL byte.
  910.      * Adjust for minimal size (must be able to store info_t
  911.      * plus a trailing NUL, so the chunk can be released again)
  912.      */
  913.     size += M_OFFSET + 1;
  914.     if (size < sizeof(info_t) + 1)
  915.       size = sizeof(info_t) + 1;
  916.     /*
  917.      * round size up for alignment
  918.      */
  919.     size_align = (size + ALIGN_MASK) & ~ALIGN_MASK;
  920.     /*
  921.      * If curbuf->b_m_search is NULL (uninitialized free list) start at
  922.      * curbuf->b_block_head
  923.      */
  924.     if (curbuf->b_mb_current == NULL || curbuf->b_m_search == NULL)
  925.     {
  926. curbuf->b_mb_current = &curbuf->b_block_head;
  927. curbuf->b_m_search = &(curbuf->b_block_head.mb_info);
  928.     }
  929.     /* search for space in free list */
  930.     mprev = curbuf->b_m_search;
  931.     mbp = curbuf->b_mb_current;
  932.     mp = curbuf->b_m_search->m_next;
  933.     if (mp == NULL)
  934.     {
  935. if (mbp->mb_next)
  936.     mbp = mbp->mb_next;
  937. else
  938.     mbp = &curbuf->b_block_head;
  939. mp = curbuf->b_m_search = &(mbp->mb_info);
  940.     }
  941.     while (mp->m_size < size)
  942.     {
  943. if (mp == curbuf->b_m_search)     /* back where we started in free
  944.        chunk list */
  945. {
  946.     if (mbp->mb_next)
  947. mbp = mbp->mb_next;
  948.     else
  949. mbp = &curbuf->b_block_head;
  950.     mp = curbuf->b_m_search = &(mbp->mb_info);
  951.     if (mbp == curbuf->b_mb_current) /* back where we started in
  952.    block list */
  953.     {
  954. int n = (size_align > (MEMBLOCKSIZE / 4)
  955.  ? size_align : MEMBLOCKSIZE);
  956. mp = (info_t *)u_blockalloc((long_u)n);
  957. if (mp == NULL)
  958.     return (NULL);
  959. mp->m_size = n;
  960. u_free_line((char_u *)mp + M_OFFSET);
  961. mp = curbuf->b_m_search;
  962. mbp = curbuf->b_mb_current;
  963.     }
  964. }
  965. mprev = mp;
  966. if ((mp = mp->m_next) == NULL)     /* at end of the list */
  967.     mp = &(mbp->mb_info);     /* wrap around to begin */
  968.     }
  969.     /* if the chunk we found is large enough, split it up in two */
  970.     if ((long)mp->m_size - size_align >= (long)(sizeof(info_t) + 1))
  971.     {
  972. mp2 = (info_t *)((char_u *)mp + size_align);
  973. mp2->m_size = mp->m_size - size_align;
  974. mp2->m_next = mp->m_next;
  975. mprev->m_next = mp2;
  976. mp->m_size = size_align;
  977.     }
  978.     else     /* remove *mp from the free list */
  979.     {
  980. mprev->m_next = mp->m_next;
  981.     }
  982.     curbuf->b_m_search = mprev;
  983.     curbuf->b_mb_current = mbp;
  984.     mp = (info_t *)((char_u *)mp + M_OFFSET);
  985.     *(char_u *)mp = NUL;     /* set the first byte to NUL */
  986.     return ((char_u *)mp);
  987. }
  988. /*
  989.  * u_save_line(): allocate memory with u_alloc_line() and copy line 'lnum'
  990.  * into it.
  991.  */
  992.     static char_u *
  993. u_save_line(lnum)
  994.     linenr_t lnum;
  995. {
  996.     char_u *src;
  997.     char_u *dst;
  998.     unsigned len;
  999.     src = ml_get(lnum);
  1000.     len = STRLEN(src);
  1001.     if ((dst = u_alloc_line(len)) != NULL)
  1002. mch_memmove(dst, src, (size_t)(len + 1));
  1003.     return (dst);
  1004. }
  1005. /*
  1006.  * Check if the 'modified' flag is set, or 'ff' has changed (only need to
  1007.  * check the first character, because it can only be "dos", "unix" or "mac").
  1008.  */
  1009.     int
  1010. buf_changed(buf)
  1011.     BUF     *buf;
  1012. {
  1013.     return (buf->b_changed || *buf->b_p_ff != buf->b_start_ffc);
  1014. }
  1015.     int
  1016. curbuf_changed()
  1017. {
  1018.     return (curbuf->b_changed || *curbuf->b_p_ff != curbuf->b_start_ffc);
  1019. }