home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / undo.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-02-13  |  33.5 KB  |  1,333 lines

  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.
  43.  *
  44.  * All data is allocated with u_alloc_line(), thus it will be freed as soon as
  45.  * we switch files!
  46.  */
  47.  
  48. #include "vim.h"
  49.  
  50. static u_entry_T *u_get_headentry __ARGS((void));
  51. static void u_getbot __ARGS((void));
  52. static int u_savecommon __ARGS((linenr_T, linenr_T, linenr_T));
  53. static void u_doit __ARGS((int count));
  54. static void u_undoredo __ARGS((void));
  55. static void u_undo_end __ARGS((void));
  56. static void u_freelist __ARGS((struct u_header *));
  57. static void u_freeentry __ARGS((u_entry_T *, long));
  58.  
  59. static char_u *u_blockalloc __ARGS((long_u));
  60. static void u_free_line __ARGS((char_u *, int keep));
  61. static char_u *u_alloc_line __ARGS((unsigned));
  62. static char_u *u_save_line __ARGS((linenr_T));
  63.  
  64. static long    u_newcount, u_oldcount;
  65.  
  66. /*
  67.  * When 'u' flag included in 'cpoptions', we behave like vi.  Need to remember
  68.  * the action that "u" should do.
  69.  */
  70. static int    undo_undoes = FALSE;
  71.  
  72. /*
  73.  * save the current line for both the "u" and "U" command
  74.  */
  75.     int
  76. u_save_cursor()
  77. {
  78.     return (u_save((linenr_T)(curwin->w_cursor.lnum - 1),
  79.                       (linenr_T)(curwin->w_cursor.lnum + 1)));
  80. }
  81.  
  82. /*
  83.  * Save the lines between "top" and "bot" for both the "u" and "U" command.
  84.  * "top" may be 0 and bot may be curbuf->b_ml.ml_line_count + 1.
  85.  * Returns FAIL when lines could not be saved, OK otherwise.
  86.  */
  87.     int
  88. u_save(top, bot)
  89.     linenr_T top, bot;
  90. {
  91.     if (undo_off)
  92.     return OK;
  93.  
  94.     if (top > curbuf->b_ml.ml_line_count ||
  95.                 top >= bot || bot > curbuf->b_ml.ml_line_count + 1)
  96.     return FALSE;    /* rely on caller to do error messages */
  97.  
  98.     if (top + 2 == bot)
  99.     u_saveline((linenr_T)(top + 1));
  100.  
  101.     return (u_savecommon(top, bot, (linenr_T)0));
  102. }
  103.  
  104. /*
  105.  * save the line "lnum" (used by ":s" and "~" command)
  106.  * The line is replaced, so the new bottom line is lnum + 1.
  107.  */
  108.     int
  109. u_savesub(lnum)
  110.     linenr_T    lnum;
  111. {
  112.     if (undo_off)
  113.     return OK;
  114.  
  115.     return (u_savecommon(lnum - 1, lnum + 1, lnum + 1));
  116. }
  117.  
  118. /*
  119.  * a new line is inserted before line "lnum" (used by :s command)
  120.  * The line is inserted, so the new bottom line is lnum + 1.
  121.  */
  122.     int
  123. u_inssub(lnum)
  124.     linenr_T    lnum;
  125. {
  126.     if (undo_off)
  127.     return OK;
  128.  
  129.     return (u_savecommon(lnum - 1, lnum, lnum + 1));
  130. }
  131.  
  132. /*
  133.  * save the lines "lnum" - "lnum" + nlines (used by delete command)
  134.  * The lines are deleted, so the new bottom line is lnum, unless the buffer
  135.  * becomes empty.
  136.  */
  137.     int
  138. u_savedel(lnum, nlines)
  139.     linenr_T    lnum;
  140.     long    nlines;
  141. {
  142.     if (undo_off)
  143.     return OK;
  144.  
  145.     return (u_savecommon(lnum - 1, lnum + nlines,
  146.             nlines == curbuf->b_ml.ml_line_count ? 2 : lnum));
  147. }
  148.  
  149.     static int
  150. u_savecommon(top, bot, newbot)
  151.     linenr_T    top, bot;
  152.     linenr_T    newbot;
  153. {
  154.     linenr_T        lnum;
  155.     long        i;
  156.     struct u_header    *uhp;
  157.     u_entry_T        *uep;
  158.     u_entry_T        *prev_uep;
  159.     long        size;
  160.  
  161.     /*
  162.      * Don't allow changes when 'modifiable' is off.  Letting the
  163.      * undo fail is a crude way to make all change commands fail.
  164.      */
  165.     if (!curbuf->b_p_ma)
  166.     {
  167.     EMSG(_(e_modifiable));
  168.     return FAIL;
  169.     }
  170.  
  171. #ifdef HAVE_SANDBOX
  172.     /*
  173.      * In the sandbox it's not allowed to change the text.  Letting the
  174.      * undo fail is a crude way to make all change commands fail.
  175.      */
  176.     if (sandbox != 0)
  177.     {
  178.     EMSG(_(e_sandbox));
  179.     return FAIL;
  180.     }
  181. #endif
  182.  
  183. #ifdef FEAT_NETBEANS_INTG
  184.     /*
  185.      * Netbeans defines areas that cannot be modified.  Bail out here when
  186.      * trying to change text in a guarded area.
  187.      */
  188.     if (usingNetbeans && netbeans_is_guarded(top, bot))
  189.     {
  190.     EMSG(_(e_guarded));
  191.     return FAIL;
  192.     }
  193. #endif
  194.  
  195. #ifdef FEAT_AUTOCMD
  196.     /*
  197.      * Saving text for undo means we are going to make a change.  Give a
  198.      * warning for a read-only file before making the change, so that the
  199.      * FileChangedRO event can replace the buffer with a read-write version
  200.      * (e.g., obtained from a source control system).
  201.      */
  202.     change_warning(0);
  203. #endif
  204.  
  205.     size = bot - top - 1;
  206.  
  207.     /*
  208.      * if curbuf->b_u_synced == TRUE make a new header
  209.      */
  210.     if (curbuf->b_u_synced)
  211.     {
  212.     /*
  213.      * if we undid more than we redid, free the entry lists before and
  214.      * including curbuf->b_u_curhead
  215.      */
  216.     while (curbuf->b_u_curhead != NULL)
  217.         u_freelist(curbuf->b_u_newhead);
  218.  
  219.     /*
  220.      * free headers to keep the size right
  221.      */
  222.     while (curbuf->b_u_numhead > p_ul && curbuf->b_u_oldhead != NULL)
  223.         u_freelist(curbuf->b_u_oldhead);
  224.  
  225.     if (p_ul < 0)        /* no undo at all */
  226.         return OK;
  227.  
  228.     /*
  229.      * make a new header entry
  230.      */
  231.     uhp = (struct u_header *)u_alloc_line((unsigned)
  232.                              sizeof(struct u_header));
  233.     if (uhp == NULL)
  234.         goto nomem;
  235.     uhp->uh_prev = NULL;
  236.     uhp->uh_next = curbuf->b_u_newhead;
  237.     if (curbuf->b_u_newhead != NULL)
  238.         curbuf->b_u_newhead->uh_prev = uhp;
  239.     uhp->uh_entry = NULL;
  240.     uhp->uh_getbot_entry = NULL;
  241.     uhp->uh_cursor = curwin->w_cursor;    /* save cursor pos. for undo */
  242. #ifdef FEAT_VIRTUALEDIT
  243.     if (virtual_active() && curwin->w_cursor.coladd > 0)
  244.         uhp->uh_cursor_vcol = getviscol();
  245.     else
  246.         uhp->uh_cursor_vcol = -1;
  247. #endif
  248.  
  249.     /* save changed and buffer empty flag for undo */
  250.     uhp->uh_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
  251.                ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0);
  252.  
  253.     /* save named marks for undo */
  254.     mch_memmove(uhp->uh_namedm, curbuf->b_namedm, sizeof(pos_T) * NMARKS);
  255.     curbuf->b_u_newhead = uhp;
  256.     if (curbuf->b_u_oldhead == NULL)
  257.         curbuf->b_u_oldhead = uhp;
  258.     ++curbuf->b_u_numhead;
  259.     }
  260.     else
  261.     {
  262.     /*
  263.      * When saving a single line, and it has been saved just before, it
  264.      * doesn't make sense saving it again.  Saves a lot of memory when
  265.      * making lots of changes inside the same line.
  266.      * This is only possible if the previous change didn't increase or
  267.      * decrease the number of lines.
  268.      * Check the ten last changes.  More doesn't make sense and takes too
  269.      * long.
  270.      */
  271.     if (size == 1)
  272.     {
  273.         uep = u_get_headentry();
  274.         prev_uep = NULL;
  275.         for (i = 0; i < 10; ++i)
  276.         {
  277.         if (uep == NULL)
  278.             break;
  279.  
  280.         /* If lines have been inserted/deleted we give up.
  281.          * Also when the line was included in a multi-line save. */
  282.         if ((curbuf->b_u_newhead->uh_getbot_entry != uep
  283.                 ? (uep->ue_top + uep->ue_size + 1
  284.                 != (uep->ue_bot == 0
  285.                     ? curbuf->b_ml.ml_line_count + 1
  286.                     : uep->ue_bot))
  287.                 : uep->ue_lcount != curbuf->b_ml.ml_line_count)
  288.             || (uep->ue_size > 1
  289.                 && top >= uep->ue_top
  290.                 && top + 2 <= uep->ue_top + uep->ue_size + 1))
  291.             break;
  292.  
  293.         /* If it's the same line we can skip saving it again. */
  294.         if (uep->ue_size == 1 && uep->ue_top == top)
  295.         {
  296.             if (i > 0)
  297.             {
  298.             /* It's not the last entry: get ue_bot for the last
  299.              * entry now.  Following deleted/inserted lines go to
  300.              * the re-used entry. */
  301.             u_getbot();
  302.             curbuf->b_u_synced = FALSE;
  303.  
  304.             /* Move the found entry to become the last entry.  The
  305.              * order of undo/redo doesn't matter for the entries
  306.              * we move it over, since they don't change the line
  307.              * count and don't include this line.  It does matter
  308.              * for the found entry if the line count is changed by
  309.              * the executed command. */
  310.             prev_uep->ue_next = uep->ue_next;
  311.             uep->ue_next = curbuf->b_u_newhead->uh_entry;
  312.             curbuf->b_u_newhead->uh_entry = uep;
  313.             }
  314.  
  315.             /* The executed command may change the line count. */
  316.             if (newbot != 0)
  317.             uep->ue_bot = newbot;
  318.             else if (bot > curbuf->b_ml.ml_line_count)
  319.             uep->ue_bot = 0;
  320.             else
  321.             {
  322.             uep->ue_lcount = curbuf->b_ml.ml_line_count;
  323.             curbuf->b_u_newhead->uh_getbot_entry = uep;
  324.             }
  325.             return OK;
  326.         }
  327.         prev_uep = uep;
  328.         uep = uep->ue_next;
  329.         }
  330.     }
  331.  
  332.     /* find line number for ue_bot for previous u_save() */
  333.     u_getbot();
  334.     }
  335.  
  336. #if !defined(UNIX) && !defined(DJGPP) && !defined(WIN32) && !defined(__EMX__)
  337.     /*
  338.      * With Amiga and MSDOS 16 bit we can't handle big undo's, because
  339.      * then u_alloc_line would have to allocate a block larger than 32K
  340.      */
  341.     if (size >= 8000)
  342.     goto nomem;
  343. #endif
  344.  
  345.     /*
  346.      * add lines in front of entry list
  347.      */
  348.     uep = (u_entry_T *)u_alloc_line((unsigned)sizeof(u_entry_T));
  349.     if (uep == NULL)
  350.     goto nomem;
  351.  
  352.     uep->ue_size = size;
  353.     uep->ue_top = top;
  354.     if (newbot != 0)
  355.     uep->ue_bot = newbot;
  356.     /*
  357.      * Use 0 for ue_bot if bot is below last line.
  358.      * Otherwise we have to compute ue_bot later.
  359.      */
  360.     else if (bot > curbuf->b_ml.ml_line_count)
  361.     uep->ue_bot = 0;
  362.     else
  363.     {
  364.     uep->ue_lcount = curbuf->b_ml.ml_line_count;
  365.     curbuf->b_u_newhead->uh_getbot_entry = uep;
  366.     }
  367.  
  368.     if (size)
  369.     {
  370.     if ((uep->ue_array = (char_u **)u_alloc_line(
  371.                 (unsigned)(sizeof(char_u *) * size))) == NULL)
  372.     {
  373.         u_freeentry(uep, 0L);
  374.         goto nomem;
  375.     }
  376.     for (i = 0, lnum = top + 1; i < size; ++i)
  377.     {
  378.         if ((uep->ue_array[i] = u_save_line(lnum++)) == NULL)
  379.         {
  380.         u_freeentry(uep, i);
  381.         goto nomem;
  382.         }
  383.     }
  384.     }
  385.     uep->ue_next = curbuf->b_u_newhead->uh_entry;
  386.     curbuf->b_u_newhead->uh_entry = uep;
  387.     curbuf->b_u_synced = FALSE;
  388.     undo_undoes = FALSE;
  389.  
  390.     return OK;
  391.  
  392. nomem:
  393.     msg_silent = 0;    /* must display the prompt */
  394.     if (ask_yesno((char_u *)_("No undo possible; continue anyway"), TRUE)
  395.                                        == 'y')
  396.     {
  397.     undo_off = TRUE;        /* will be reset when character typed */
  398.     return OK;
  399.     }
  400.     do_outofmem_msg((long_u)0);
  401.     return FAIL;
  402. }
  403.  
  404. /*
  405.  * If 'cpoptions' contains 'u': Undo the previous undo or redo (vi compatible).
  406.  * If 'cpoptions' does not contain 'u': Always undo.
  407.  */
  408.     void
  409. u_undo(count)
  410.     int count;
  411. {
  412.     /*
  413.      * If we get an undo command while executing a macro, we behave like the
  414.      * original vi. If this happens twice in one macro the result will not
  415.      * be compatible.
  416.      */
  417.     if (curbuf->b_u_synced == FALSE)
  418.     {
  419.     u_sync();
  420.     count = 1;
  421.     }
  422.  
  423.     if (vim_strchr(p_cpo, CPO_UNDO) == NULL)
  424.     undo_undoes = TRUE;
  425.     else
  426.     undo_undoes = !undo_undoes;
  427.     u_doit(count);
  428. }
  429.  
  430. /*
  431.  * If 'cpoptions' contains 'u': Repeat the previous undo or redo.
  432.  * If 'cpoptions' does not contain 'u': Always redo.
  433.  */
  434.     void
  435. u_redo(count)
  436.     int count;
  437. {
  438.     if (vim_strchr(p_cpo, CPO_UNDO) == NULL)
  439.     undo_undoes = FALSE;
  440.     u_doit(count);
  441. }
  442.  
  443. /*
  444.  * Undo or redo, depending on 'undo_undoes', 'count' times.
  445.  */
  446.     static void
  447. u_doit(count)
  448.     int count;
  449. {
  450.     /* Don't allow changes when 'modifiable' is off. */
  451.     if (!curbuf->b_p_ma)
  452.     {
  453.     EMSG(_(e_modifiable));
  454.     return;
  455.     }
  456. #ifdef HAVE_SANDBOX
  457.     /* In the sandbox it's not allowed to change the text. */
  458.     if (sandbox != 0)
  459.     {
  460.     EMSG(_(e_sandbox));
  461.     return;
  462.     }
  463. #endif
  464.  
  465.     u_newcount = 0;
  466.     u_oldcount = 0;
  467.     while (count--)
  468.     {
  469.     if (undo_undoes)
  470.     {
  471.         if (curbuf->b_u_curhead == NULL)        /* first undo */
  472.         curbuf->b_u_curhead = curbuf->b_u_newhead;
  473.         else if (p_ul > 0)                /* multi level undo */
  474.         /* get next undo */
  475.         curbuf->b_u_curhead = curbuf->b_u_curhead->uh_next;
  476.         /* nothing to undo */
  477.         if (curbuf->b_u_numhead == 0 || curbuf->b_u_curhead == NULL)
  478.         {
  479.         /* stick curbuf->b_u_curhead at end */
  480.         curbuf->b_u_curhead = curbuf->b_u_oldhead;
  481.         beep_flush();
  482.         break;
  483.         }
  484.  
  485.         u_undoredo();
  486.     }
  487.     else
  488.     {
  489.         if (curbuf->b_u_curhead == NULL || p_ul <= 0)
  490.         {
  491.         beep_flush();    /* nothing to redo */
  492.         break;
  493.         }
  494.  
  495.         u_undoredo();
  496.         /* advance for next redo */
  497.         curbuf->b_u_curhead = curbuf->b_u_curhead->uh_prev;
  498.     }
  499.     }
  500.     u_undo_end();
  501. }
  502.  
  503. /*
  504.  * u_undoredo: common code for undo and redo
  505.  *
  506.  * The lines in the file are replaced by the lines in the entry list at
  507.  * curbuf->b_u_curhead. The replaced lines in the file are saved in the entry
  508.  * list for the next undo/redo.
  509.  */
  510.     static void
  511. u_undoredo()
  512. {
  513.     char_u    **newarray = NULL;
  514.     linenr_T    oldsize;
  515.     linenr_T    newsize;
  516.     linenr_T    top, bot;
  517.     linenr_T    lnum;
  518.     linenr_T    newlnum = MAXLNUM;
  519.     long    i;
  520.     u_entry_T    *uep, *nuep;
  521.     u_entry_T    *newlist = NULL;
  522.     int        old_flags;
  523.     int        new_flags;
  524.     pos_T    namedm[NMARKS];
  525.     int        empty_buffer;            /* buffer became empty */
  526.  
  527.     old_flags = curbuf->b_u_curhead->uh_flags;
  528.     new_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
  529.            ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0);
  530.     setpcmark();
  531.  
  532.     /*
  533.      * save marks before undo/redo
  534.      */
  535.     mch_memmove(namedm, curbuf->b_namedm, sizeof(pos_T) * NMARKS);
  536.     curbuf->b_op_start.lnum = curbuf->b_ml.ml_line_count;
  537.     curbuf->b_op_start.col = 0;
  538.     curbuf->b_op_end.lnum = 0;
  539.     curbuf->b_op_end.col = 0;
  540.  
  541.     for (uep = curbuf->b_u_curhead->uh_entry; uep != NULL; uep = nuep)
  542.     {
  543.     top = uep->ue_top;
  544.     bot = uep->ue_bot;
  545.     if (bot == 0)
  546.         bot = curbuf->b_ml.ml_line_count + 1;
  547.     if (top > curbuf->b_ml.ml_line_count || top >= bot || bot > curbuf->b_ml.ml_line_count + 1)
  548.     {
  549.         EMSG(_("E438: u_undo: line numbers wrong"));
  550.         changed();        /* don't want UNCHANGED now */
  551.         return;
  552.     }
  553.  
  554.     if (top < newlnum)
  555.     {
  556.         newlnum = top;
  557.         curwin->w_cursor.lnum = top + 1;
  558.     }
  559.     oldsize = bot - top - 1;    /* number of lines before undo */
  560.     newsize = uep->ue_size;        /* number of lines after undo */
  561.  
  562.     empty_buffer = FALSE;
  563.  
  564.     /* delete the lines between top and bot and save them in newarray */
  565.     if (oldsize)
  566.     {
  567.         if ((newarray = (char_u **)u_alloc_line(
  568.                 (unsigned)(sizeof(char_u *) * oldsize))) == NULL)
  569.         {
  570.         do_outofmem_msg((long_u)(sizeof(char_u *) * oldsize));
  571.         /*
  572.          * We have messed up the entry list, repair is impossible.
  573.          * we have to free the rest of the list.
  574.          */
  575.         while (uep != NULL)
  576.         {
  577.             nuep = uep->ue_next;
  578.             u_freeentry(uep, uep->ue_size);
  579.             uep = nuep;
  580.         }
  581.         break;
  582.         }
  583.         /* delete backwards, it goes faster in most cases */
  584.         for (lnum = bot - 1, i = oldsize; --i >= 0; --lnum)
  585.         {
  586.         /* what can we do when we run out of memory? */
  587.         if ((newarray[i] = u_save_line(lnum)) == NULL)
  588.             do_outofmem_msg((long_u)0);
  589.         /* remember we deleted the last line in the buffer, and a
  590.          * dummy empty line will be inserted */
  591.         if (curbuf->b_ml.ml_line_count == 1)
  592.             empty_buffer = TRUE;
  593.         ml_delete(lnum, FALSE);
  594.         }
  595.     }
  596.  
  597.     /* insert the lines in u_array between top and bot */
  598.     if (newsize)
  599.     {
  600.         for (lnum = top, i = 0; i < newsize; ++i, ++lnum)
  601.         {
  602.         /*
  603.          * If the file is empty, there is an empty line 1 that we
  604.          * should get rid of, by replacing it with the new line
  605.          */
  606.         if (empty_buffer && lnum == 0)
  607.             ml_replace((linenr_T)1, uep->ue_array[i], TRUE);
  608.         else
  609.             ml_append(lnum, uep->ue_array[i], (colnr_T)0, FALSE);
  610.         u_free_line(uep->ue_array[i], FALSE);
  611.         }
  612.         u_free_line((char_u *)uep->ue_array, FALSE);
  613.     }
  614.  
  615.     /* adjust marks */
  616.     if (oldsize != newsize)
  617.     {
  618.         mark_adjust(top + 1, top + oldsize, (long)MAXLNUM,
  619.                            (long)newsize - (long)oldsize);
  620.         if (curbuf->b_op_start.lnum > top + oldsize)
  621.         curbuf->b_op_start.lnum += newsize - oldsize;
  622.         if (curbuf->b_op_end.lnum > top + oldsize)
  623.         curbuf->b_op_end.lnum += newsize - oldsize;
  624.     }
  625.  
  626.     changed_lines(top + 1, 0, bot, newsize - oldsize);
  627.  
  628.     /* set '[ and '] mark */
  629.     if (top + 1 < curbuf->b_op_start.lnum)
  630.         curbuf->b_op_start.lnum = top + 1;
  631.     if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum)
  632.         curbuf->b_op_end.lnum = top + 1;
  633.     else if (top + newsize > curbuf->b_op_end.lnum)
  634.         curbuf->b_op_end.lnum = top + newsize;
  635.  
  636.     u_newcount += newsize;
  637.     u_oldcount += oldsize;
  638.     uep->ue_size = oldsize;
  639.     uep->ue_array = newarray;
  640.     uep->ue_bot = top + newsize + 1;
  641.  
  642.     /*
  643.      * insert this entry in front of the new entry list
  644.      */
  645.     nuep = uep->ue_next;
  646.     uep->ue_next = newlist;
  647.     newlist = uep;
  648.     }
  649.  
  650.     curbuf->b_u_curhead->uh_entry = newlist;
  651.     curbuf->b_u_curhead->uh_flags = new_flags;
  652.     if ((old_flags & UH_EMPTYBUF) && bufempty())
  653.     curbuf->b_ml.ml_flags |= ML_EMPTY;
  654.     if (old_flags & UH_CHANGED)
  655.     changed();
  656.     else
  657.     unchanged(curbuf, FALSE);
  658.  
  659.     /*
  660.      * restore marks from before undo/redo
  661.      */
  662.     for (i = 0; i < NMARKS; ++i)
  663.     if (curbuf->b_u_curhead->uh_namedm[i].lnum)
  664.     {
  665.         curbuf->b_namedm[i] = curbuf->b_u_curhead->uh_namedm[i];
  666.         curbuf->b_u_curhead->uh_namedm[i] = namedm[i];
  667.     }
  668.  
  669.     /*
  670.      * If the cursor is only off by one line, put it at the same position as
  671.      * before starting the change (for the "o" command).
  672.      * Otherwise the cursor should go to the first undone line.
  673.      */
  674.     if (curbuf->b_u_curhead->uh_cursor.lnum + 1 == curwin->w_cursor.lnum
  675.                          && curwin->w_cursor.lnum > 1)
  676.     --curwin->w_cursor.lnum;
  677.     if (curbuf->b_u_curhead->uh_cursor.lnum == curwin->w_cursor.lnum)
  678.     {
  679.     curwin->w_cursor.col = curbuf->b_u_curhead->uh_cursor.col;
  680. #ifdef FEAT_VIRTUALEDIT
  681.     if (virtual_active() && curbuf->b_u_curhead->uh_cursor_vcol >= 0)
  682.         coladvance((colnr_T)curbuf->b_u_curhead->uh_cursor_vcol);
  683.     else
  684.         curwin->w_cursor.coladd = 0;
  685. #endif
  686.     }
  687.     else if (curwin->w_cursor.lnum <= curbuf->b_ml.ml_line_count)
  688.     beginline(BL_SOL | BL_FIX);
  689.     else
  690.     {
  691.     /* We get here with the current cursor line being past the end (eg
  692.      * after adding lines at the end of the file, and then undoing it).
  693.      * check_cursor() will move the cursor to the last line.  Move it to
  694.      * the first column here. */
  695.     curwin->w_cursor.col = 0;
  696. #ifdef FEAT_VIRTUALEDIT
  697.     curwin->w_cursor.coladd = 0;
  698. #endif
  699.     }
  700.  
  701.     /* Make sure the cursor is on an existing line and column. */
  702.     check_cursor();
  703. }
  704.  
  705. /*
  706.  * If we deleted or added lines, report the number of less/more lines.
  707.  * Otherwise, report the number of changes (this may be incorrect
  708.  * in some cases, but it's better than nothing).
  709.  */
  710.     static void
  711. u_undo_end()
  712. {
  713.     if ((u_oldcount -= u_newcount) != 0)
  714.     msgmore(-u_oldcount);
  715.     else if (u_newcount > p_report)
  716.     {
  717.     if (u_newcount == 1)
  718.         MSG(_("1 change"));
  719.     else
  720.         smsg((char_u *)_("%ld changes"), u_newcount);
  721.     }
  722. #ifdef FEAT_FOLDING
  723.     if ((fdo_flags & FDO_UNDO) && KeyTyped)
  724.     foldOpenCursor();
  725. #endif
  726. }
  727.  
  728. /*
  729.  * u_sync: stop adding to the current entry list
  730.  */
  731.     void
  732. u_sync()
  733. {
  734.     if (curbuf->b_u_synced)
  735.     return;            /* already synced */
  736.     u_getbot();            /* compute ue_bot of previous u_save */
  737.     curbuf->b_u_curhead = NULL;
  738. }
  739.  
  740. /*
  741.  * Called after writing the file and setting b_changed to FALSE.
  742.  * Now an undo means that the buffer is modified.
  743.  */
  744.     void
  745. u_unchanged(buf)
  746.     buf_T    *buf;
  747. {
  748.     struct u_header    *uh;
  749.  
  750.     for (uh = buf->b_u_newhead; uh; uh = uh->uh_next)
  751.     uh->uh_flags |= UH_CHANGED;
  752.     buf->b_did_warn = FALSE;
  753. }
  754.  
  755. /*
  756.  * Get pointer to last added entry.
  757.  * If it's not valid, give an error message and return NULL.
  758.  */
  759.     static u_entry_T *
  760. u_get_headentry()
  761. {
  762.     if (curbuf->b_u_newhead == NULL || curbuf->b_u_newhead->uh_entry == NULL)
  763.     {
  764.     EMSG(_("E439: undo list corrupt"));
  765.     return NULL;
  766.     }
  767.     return curbuf->b_u_newhead->uh_entry;
  768. }
  769.  
  770. /*
  771.  * u_getbot(): compute the line number of the previous u_save
  772.  *        It is called only when b_u_synced is FALSE.
  773.  */
  774.     static void
  775. u_getbot()
  776. {
  777.     u_entry_T    *uep;
  778.     linenr_T    extra;
  779.  
  780.     uep = u_get_headentry();    /* check for corrupt undo list */
  781.     if (uep == NULL)
  782.     return;
  783.  
  784.     uep = curbuf->b_u_newhead->uh_getbot_entry;
  785.     if (uep != NULL)
  786.     {
  787.     /*
  788.      * the new ue_bot is computed from the number of lines that has been
  789.      * inserted (0 - deleted) since calling u_save. This is equal to the
  790.      * old line count subtracted from the current line count.
  791.      */
  792.     extra = curbuf->b_ml.ml_line_count - uep->ue_lcount;
  793.     uep->ue_bot = uep->ue_top + uep->ue_size + 1 + extra;
  794.     if (uep->ue_bot < 1 || uep->ue_bot > curbuf->b_ml.ml_line_count)
  795.     {
  796.         EMSG(_("E440: undo line missing"));
  797.         uep->ue_bot = uep->ue_top + 1;  /* assume all lines deleted, will
  798.                          * get all the old lines back
  799.                          * without deleting the current
  800.                          * ones */
  801.     }
  802.  
  803.     curbuf->b_u_newhead->uh_getbot_entry = NULL;
  804.     }
  805.  
  806.     curbuf->b_u_synced = TRUE;
  807. }
  808.  
  809. /*
  810.  * u_freelist: free one entry list and adjust the pointers
  811.  */
  812.     static void
  813. u_freelist(uhp)
  814.     struct u_header *uhp;
  815. {
  816.     u_entry_T    *uep, *nuep;
  817.  
  818.     for (uep = uhp->uh_entry; uep != NULL; uep = nuep)
  819.     {
  820.     nuep = uep->ue_next;
  821.     u_freeentry(uep, uep->ue_size);
  822.     }
  823.  
  824.     if (curbuf->b_u_curhead == uhp)
  825.     curbuf->b_u_curhead = NULL;
  826.  
  827.     if (uhp->uh_next == NULL)
  828.     curbuf->b_u_oldhead = uhp->uh_prev;
  829.     else
  830.     uhp->uh_next->uh_prev = uhp->uh_prev;
  831.  
  832.     if (uhp->uh_prev == NULL)
  833.     curbuf->b_u_newhead = uhp->uh_next;
  834.     else
  835.     uhp->uh_prev->uh_next = uhp->uh_next;
  836.  
  837.     u_free_line((char_u *)uhp, FALSE);
  838.     --curbuf->b_u_numhead;
  839. }
  840.  
  841. /*
  842.  * free entry 'uep' and 'n' lines in uep->ue_array[]
  843.  */
  844.     static void
  845. u_freeentry(uep, n)
  846.     u_entry_T    *uep;
  847.     long        n;
  848. {
  849.     while (n)
  850.     u_free_line(uep->ue_array[--n], FALSE);
  851.     u_free_line((char_u *)uep, FALSE);
  852. }
  853.  
  854. /*
  855.  * invalidate the undo buffer; called when storage has already been released
  856.  */
  857.     void
  858. u_clearall(buf)
  859.     buf_T    *buf;
  860. {
  861.     buf->b_u_newhead = buf->b_u_oldhead = buf->b_u_curhead = NULL;
  862.     buf->b_u_synced = TRUE;
  863.     buf->b_u_numhead = 0;
  864.     buf->b_u_line_ptr = NULL;
  865.     buf->b_u_line_lnum = 0;
  866. }
  867.  
  868. /*
  869.  * save the line "lnum" for the "U" command
  870.  */
  871.     void
  872. u_saveline(lnum)
  873.     linenr_T lnum;
  874. {
  875.     if (lnum == curbuf->b_u_line_lnum)        /* line is already saved */
  876.     return;
  877.     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)    /* should never happen */
  878.     return;
  879.     u_clearline();
  880.     curbuf->b_u_line_lnum = lnum;
  881.     if (curwin->w_cursor.lnum == lnum)
  882.     curbuf->b_u_line_colnr = curwin->w_cursor.col;
  883.     else
  884.     curbuf->b_u_line_colnr = 0;
  885.     if ((curbuf->b_u_line_ptr = u_save_line(lnum)) == NULL)
  886.     do_outofmem_msg((long_u)0);
  887. }
  888.  
  889. /*
  890.  * clear the line saved for the "U" command
  891.  * (this is used externally for crossing a line while in insert mode)
  892.  */
  893.     void
  894. u_clearline()
  895. {
  896.     if (curbuf->b_u_line_ptr != NULL)
  897.     {
  898.     u_free_line(curbuf->b_u_line_ptr, FALSE);
  899.     curbuf->b_u_line_ptr = NULL;
  900.     curbuf->b_u_line_lnum = 0;
  901.     }
  902. }
  903.  
  904. /*
  905.  * Implementation of the "U" command.
  906.  * Differentiation from vi: "U" can be undone with the next "U".
  907.  * We also allow the cursor to be in another line.
  908.  */
  909.     void
  910. u_undoline()
  911. {
  912.     colnr_T t;
  913.     char_u  *oldp;
  914.  
  915.     if (undo_off)
  916.     return;
  917.  
  918.     if (curbuf->b_u_line_ptr == NULL ||
  919.             curbuf->b_u_line_lnum > curbuf->b_ml.ml_line_count)
  920.     {
  921.     beep_flush();
  922.     return;
  923.     }
  924.     /* first save the line for the 'u' command */
  925.     if (u_savecommon(curbuf->b_u_line_lnum - 1,
  926.                 curbuf->b_u_line_lnum + 1, (linenr_T)0) == FAIL)
  927.     return;
  928.     oldp = u_save_line(curbuf->b_u_line_lnum);
  929.     if (oldp == NULL)
  930.     {
  931.     do_outofmem_msg((long_u)0);
  932.     return;
  933.     }
  934.     ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, TRUE);
  935.     changed_bytes(curbuf->b_u_line_lnum, 0);
  936.     u_free_line(curbuf->b_u_line_ptr, FALSE);
  937.     curbuf->b_u_line_ptr = oldp;
  938.  
  939.     t = curbuf->b_u_line_colnr;
  940.     if (curwin->w_cursor.lnum == curbuf->b_u_line_lnum)
  941.     curbuf->b_u_line_colnr = curwin->w_cursor.col;
  942.     curwin->w_cursor.col = t;
  943.     curwin->w_cursor.lnum = curbuf->b_u_line_lnum;
  944. }
  945.  
  946. /*
  947.  * storage allocation for the undo lines and blocks of the current file
  948.  */
  949.  
  950. /*
  951.  * Memory is allocated in relatively large blocks. These blocks are linked
  952.  * in the allocated block list, headed by curbuf->b_block_head. They are all
  953.  * freed when abandoning a file, so we don't have to free every single line.
  954.  * The list is kept sorted on memory address.
  955.  * block_alloc() allocates a block.
  956.  * m_blockfree() frees all blocks.
  957.  *
  958.  * The available chunks of memory are kept in free chunk lists. There is
  959.  * one free list for each block of allocated memory. The list is kept sorted
  960.  * on memory address.
  961.  * u_alloc_line() gets a chunk from the free lists.
  962.  * u_free_line() returns a chunk to the free lists.
  963.  * curbuf->b_m_search points to the chunk before the chunk that was
  964.  * freed/allocated the last time.
  965.  * curbuf->b_mb_current points to the b_head where curbuf->b_m_search
  966.  * points into the free list.
  967.  *
  968.  *
  969.  *  b_block_head     /---> block #1    /---> block #2
  970.  *     mb_next ---/        mb_next ---/       mb_next ---> NULL
  971.  *     mb_info        mb_info           mb_info
  972.  *        |               |          |
  973.  *        V               V          V
  974.  *      NULL        free chunk #1.1      free chunk #2.1
  975.  *                   |          |
  976.  *                   V          V
  977.  *            free chunk #1.2         NULL
  978.  *                   |
  979.  *                   V
  980.  *                  NULL
  981.  *
  982.  * When a single free chunk list would have been used, it could take a lot
  983.  * of time in u_free_line() to find the correct place to insert a chunk in the
  984.  * free list. The single free list would become very long when many lines are
  985.  * changed (e.g. with :%s/^M$//).
  986.  */
  987.  
  988.  /*
  989.   * this blocksize is used when allocating new lines
  990.   */
  991. #define MEMBLOCKSIZE 2044
  992.  
  993. /*
  994.  * The size field contains the size of the chunk, including the size field
  995.  * itself.
  996.  *
  997.  * When the chunk is not in-use it is preceded with the m_info structure.
  998.  * The m_next field links it in one of the free chunk lists.
  999.  *
  1000.  * On most unix systems structures have to be longword (32 or 64 bit) aligned.
  1001.  * On most other systems they are short (16 bit) aligned.
  1002.  */
  1003.  
  1004. /* the structure definitions are now in structs.h */
  1005.  
  1006. #ifdef ALIGN_LONG
  1007.     /* size of m_size */
  1008. # define M_OFFSET (sizeof(long_u))
  1009. #else
  1010.     /* size of m_size */
  1011. # define M_OFFSET (sizeof(short_u))
  1012. #endif
  1013.  
  1014. /*
  1015.  * Allocate a block of memory and link it in the allocated block list.
  1016.  */
  1017.     static char_u *
  1018. u_blockalloc(size)
  1019.     long_u    size;
  1020. {
  1021.     mblock_T    *p;
  1022.     mblock_T    *mp, *next;
  1023.  
  1024.     p = (mblock_T *)lalloc(size + sizeof(mblock_T), FALSE);
  1025.     if (p != NULL)
  1026.     {
  1027.      /* Insert the block into the allocated block list, keeping it
  1028.             sorted on address. */
  1029.     for (mp = &curbuf->b_block_head;
  1030.         (next = mp->mb_next) != NULL && next < p;
  1031.             mp = next)
  1032.         ;
  1033.     p->mb_next = next;        /* link in block list */
  1034.     p->mb_size = size;
  1035.     mp->mb_next = p;
  1036.     p->mb_info.m_next = NULL;    /* clear free list */
  1037.     p->mb_info.m_size = 0;
  1038.     curbuf->b_mb_current = p;    /* remember current block */
  1039.     curbuf->b_m_search = NULL;
  1040.     p++;                /* return usable memory */
  1041.     }
  1042.     return (char_u *)p;
  1043. }
  1044.  
  1045. /*
  1046.  * free all allocated memory blocks for the buffer 'buf'
  1047.  */
  1048.     void
  1049. u_blockfree(buf)
  1050.     buf_T    *buf;
  1051. {
  1052.     mblock_T    *p, *np;
  1053.  
  1054.     for (p = buf->b_block_head.mb_next; p != NULL; p = np)
  1055.     {
  1056.     np = p->mb_next;
  1057.     vim_free(p);
  1058.     }
  1059.     buf->b_block_head.mb_next = NULL;
  1060.     buf->b_m_search = NULL;
  1061.     buf->b_mb_current = NULL;
  1062. }
  1063.  
  1064. /*
  1065.  * Free a chunk of memory for the current buffer.
  1066.  * Insert the chunk into the correct free list, keeping it sorted on address.
  1067.  */
  1068.     static void
  1069. u_free_line(ptr, keep)
  1070.     char_u    *ptr;
  1071.     int        keep;    /* don't free the block when it's empty */
  1072. {
  1073.     minfo_T    *next;
  1074.     minfo_T    *prev, *curr;
  1075.     minfo_T    *mp;
  1076.     mblock_T    *nextb;
  1077.     mblock_T    *prevb;
  1078.  
  1079.     if (ptr == NULL || ptr == IObuff)
  1080.     return;    /* illegal address can happen in out-of-memory situations */
  1081.  
  1082.     mp = (minfo_T *)(ptr - M_OFFSET);
  1083.  
  1084.     /* find block where chunk could be a part off */
  1085.     /* if we change curbuf->b_mb_current, curbuf->b_m_search is set to NULL */
  1086.     if (curbuf->b_mb_current == NULL || mp < (minfo_T *)curbuf->b_mb_current)
  1087.     {
  1088.     curbuf->b_mb_current = curbuf->b_block_head.mb_next;
  1089.     curbuf->b_m_search = NULL;
  1090.     }
  1091.     if ((nextb = curbuf->b_mb_current->mb_next) != NULL
  1092.                              && (minfo_T *)nextb < mp)
  1093.     {
  1094.     curbuf->b_mb_current = nextb;
  1095.     curbuf->b_m_search = NULL;
  1096.     }
  1097.     while ((nextb = curbuf->b_mb_current->mb_next) != NULL
  1098.                              && (minfo_T *)nextb < mp)
  1099.     curbuf->b_mb_current = nextb;
  1100.  
  1101.     curr = NULL;
  1102.     /*
  1103.      * If mp is smaller than curbuf->b_m_search->m_next go to the start of
  1104.      * the free list
  1105.      */
  1106.     if (curbuf->b_m_search == NULL || mp < (curbuf->b_m_search->m_next))
  1107.     next = &(curbuf->b_mb_current->mb_info);
  1108.     else
  1109.     next = curbuf->b_m_search;
  1110.     /*
  1111.      * The following loop is executed very often.
  1112.      * Therefore it has been optimized at the cost of readability.
  1113.      * Keep it fast!
  1114.      */
  1115. #ifdef SLOW_BUT_EASY_TO_READ
  1116.     do
  1117.     {
  1118.     prev = curr;
  1119.     curr = next;
  1120.     next = next->m_next;
  1121.     }
  1122.     while (mp > next && next != NULL);
  1123. #else
  1124.     do                        /* first, middle, last */
  1125.     {
  1126.     prev = next->m_next;            /* curr, next, prev */
  1127.     if (prev == NULL || mp <= prev)
  1128.     {
  1129.         prev = curr;
  1130.         curr = next;
  1131.         next = next->m_next;
  1132.         break;
  1133.     }
  1134.     curr = prev->m_next;            /* next, prev, curr */
  1135.     if (curr == NULL || mp <= curr)
  1136.     {
  1137.         prev = next;
  1138.         curr = prev->m_next;
  1139.         next = curr->m_next;
  1140.         break;
  1141.     }
  1142.     next = curr->m_next;            /* prev, curr, next */
  1143.     }
  1144.     while (mp > next && next != NULL);
  1145. #endif
  1146.  
  1147.     /* if *mp and *next are concatenated, join them into one chunk */
  1148.     if ((char_u *)mp + mp->m_size == (char_u *)next)
  1149.     {
  1150.     mp->m_size += next->m_size;
  1151.     mp->m_next = next->m_next;
  1152.     }
  1153.     else
  1154.     mp->m_next = next;
  1155.  
  1156.     /* if *curr and *mp are concatenated, join them */
  1157.     if (prev != NULL && (char_u *)curr + curr->m_size == (char_u *)mp)
  1158.     {
  1159.     curr->m_size += mp->m_size;
  1160.     curr->m_next = mp->m_next;
  1161.     curbuf->b_m_search = prev;
  1162.     }
  1163.     else
  1164.     {
  1165.     curr->m_next = mp;
  1166.     curbuf->b_m_search = curr;  /* put curbuf->b_m_search before freed
  1167.                        chunk */
  1168.     }
  1169.  
  1170.     /*
  1171.      * If the block only containes free memory now, release it.
  1172.      */
  1173.     if (!keep && curbuf->b_mb_current->mb_size
  1174.                   == curbuf->b_mb_current->mb_info.m_next->m_size)
  1175.     {
  1176.     /* Find the block before the current one to be able to unlink it from
  1177.      * the list of blocks. */
  1178.     prevb = &curbuf->b_block_head;
  1179.     for (nextb = prevb->mb_next; nextb != curbuf->b_mb_current;
  1180.                                nextb = nextb->mb_next)
  1181.         prevb = nextb;
  1182.     prevb->mb_next = nextb->mb_next;
  1183.     vim_free(nextb);
  1184.     curbuf->b_mb_current = NULL;
  1185.     curbuf->b_m_search = NULL;
  1186.     }
  1187. }
  1188.  
  1189. /*
  1190.  * Allocate and initialize a new line structure with room for at least
  1191.  * 'size' characters plus a terminating NUL.
  1192.  */
  1193.     static char_u *
  1194. u_alloc_line(size)
  1195.     unsigned    size;
  1196. {
  1197.     minfo_T    *mp, *mprev, *mp2;
  1198.     mblock_T    *mbp;
  1199.     int        size_align;
  1200.  
  1201.     /*
  1202.      * Add room for size field and trailing NUL byte.
  1203.      * Adjust for minimal size (must be able to store minfo_T
  1204.      * plus a trailing NUL, so the chunk can be released again)
  1205.      */
  1206.     size += M_OFFSET + 1;
  1207.     if (size < sizeof(minfo_T) + 1)
  1208.     size = sizeof(minfo_T) + 1;
  1209.  
  1210.     /*
  1211.      * round size up for alignment
  1212.      */
  1213.     size_align = (size + ALIGN_MASK) & ~ALIGN_MASK;
  1214.  
  1215.     /*
  1216.      * If curbuf->b_m_search is NULL (uninitialized free list) start at
  1217.      * curbuf->b_block_head
  1218.      */
  1219.     if (curbuf->b_mb_current == NULL || curbuf->b_m_search == NULL)
  1220.     {
  1221.     curbuf->b_mb_current = &curbuf->b_block_head;
  1222.     curbuf->b_m_search = &(curbuf->b_block_head.mb_info);
  1223.     }
  1224.  
  1225.     /* search for space in free list */
  1226.     mprev = curbuf->b_m_search;
  1227.     mbp = curbuf->b_mb_current;
  1228.     mp = curbuf->b_m_search->m_next;
  1229.     if (mp == NULL)
  1230.     {
  1231.     if (mbp->mb_next)
  1232.         mbp = mbp->mb_next;
  1233.     else
  1234.         mbp = &curbuf->b_block_head;
  1235.     mp = curbuf->b_m_search = &(mbp->mb_info);
  1236.     }
  1237.     while (mp->m_size < size)
  1238.     {
  1239.     if (mp == curbuf->b_m_search)        /* back where we started in free
  1240.                            chunk list */
  1241.     {
  1242.         if (mbp->mb_next)
  1243.         mbp = mbp->mb_next;
  1244.         else
  1245.         mbp = &curbuf->b_block_head;
  1246.         mp = curbuf->b_m_search = &(mbp->mb_info);
  1247.         if (mbp == curbuf->b_mb_current)    /* back where we started in
  1248.                            block list */
  1249.         {
  1250.         int    n = (size_align > (MEMBLOCKSIZE / 4)
  1251.                          ? size_align : MEMBLOCKSIZE);
  1252.  
  1253.         mp = (minfo_T *)u_blockalloc((long_u)n);
  1254.         if (mp == NULL)
  1255.             return (NULL);
  1256.         mp->m_size = n;
  1257.         u_free_line((char_u *)mp + M_OFFSET, TRUE);
  1258.         mp = curbuf->b_m_search;
  1259.         mbp = curbuf->b_mb_current;
  1260.         }
  1261.     }
  1262.     mprev = mp;
  1263.     if ((mp = mp->m_next) == NULL)        /* at end of the list */
  1264.         mp = &(mbp->mb_info);        /* wrap around to begin */
  1265.     }
  1266.  
  1267.     /* if the chunk we found is large enough, split it up in two */
  1268.     if ((long)mp->m_size - size_align >= (long)(sizeof(minfo_T) + 1))
  1269.     {
  1270.     mp2 = (minfo_T *)((char_u *)mp + size_align);
  1271.     mp2->m_size = mp->m_size - size_align;
  1272.     mp2->m_next = mp->m_next;
  1273.     mprev->m_next = mp2;
  1274.     mp->m_size = size_align;
  1275.     }
  1276.     else            /* remove *mp from the free list */
  1277.     {
  1278.     mprev->m_next = mp->m_next;
  1279.     }
  1280.     curbuf->b_m_search = mprev;
  1281.     curbuf->b_mb_current = mbp;
  1282.  
  1283.     mp = (minfo_T *)((char_u *)mp + M_OFFSET);
  1284.     *(char_u *)mp = NUL;            /* set the first byte to NUL */
  1285.  
  1286.     return ((char_u *)mp);
  1287. }
  1288.  
  1289. /*
  1290.  * u_save_line(): allocate memory with u_alloc_line() and copy line 'lnum'
  1291.  * into it.
  1292.  */
  1293.     static char_u *
  1294. u_save_line(lnum)
  1295.     linenr_T    lnum;
  1296. {
  1297.     char_u    *src;
  1298.     char_u    *dst;
  1299.     unsigned    len;
  1300.  
  1301.     src = ml_get(lnum);
  1302.     len = (unsigned)STRLEN(src);
  1303.     if ((dst = u_alloc_line(len)) != NULL)
  1304.     mch_memmove(dst, src, (size_t)(len + 1));
  1305.     return (dst);
  1306. }
  1307.  
  1308. /*
  1309.  * Check if the 'modified' flag is set, or 'ff' has changed (only need to
  1310.  * check the first character, because it can only be "dos", "unix" or "mac").
  1311.  * "nofile" and "scratch" type buffers are considered to always be unchanged.
  1312.  */
  1313.     int
  1314. bufIsChanged(buf)
  1315.     buf_T    *buf;
  1316. {
  1317.     return
  1318. #ifdef FEAT_QUICKFIX
  1319.         !bt_dontwrite(buf) &&
  1320. #endif
  1321.         (buf->b_changed || file_ff_differs(buf));
  1322. }
  1323.  
  1324.     int
  1325. curbufIsChanged()
  1326. {
  1327.     return
  1328. #ifdef FEAT_QUICKFIX
  1329.     !bt_dontwrite(curbuf) &&
  1330. #endif
  1331.     (curbuf->b_changed || file_ff_differs(curbuf));
  1332. }
  1333.