home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Source / GNU / emacs / src / insdel.c < prev    next >
C/C++ Source or Header  |  1991-05-08  |  10KB  |  435 lines

  1. /* Buffer insertion/deletion and gap motion for GNU Emacs.
  2.    Copyright (C) 1985, 1986, 1990 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU Emacs.
  5.  
  6. GNU Emacs is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU Emacs is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Emacs; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20.  
  21. #include "config.h"
  22. #include "lisp.h"
  23. #include "buffer.h"
  24. #include "window.h"
  25.  
  26. /* Move gap to position `pos'.
  27.    Note that this can quit!  */
  28.  
  29. move_gap (pos)
  30.      int pos;
  31. {
  32.   if (pos < GPT)
  33.     gap_left (pos, 0);
  34.   else if (pos > GPT)
  35.     gap_right (pos);
  36. }
  37.  
  38. /* Move the gap to POS, which is less than the current GPT.
  39.    If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged.  */
  40.  
  41. gap_left (pos, newgap)
  42.      register int pos;
  43.      int newgap;
  44. {
  45.   register unsigned char *to, *from;
  46.   register int i;
  47.   int new_s1;
  48.  
  49.   pos--;
  50.  
  51.   if (!newgap)
  52.     {
  53.       if (unchanged_modified == MODIFF)
  54.     {
  55.       beg_unchanged = pos;
  56.       end_unchanged = Z - pos - 1;
  57.     }
  58.       else
  59.     {
  60.       if (Z - GPT < end_unchanged)
  61.         end_unchanged = Z - GPT;
  62.       if (pos < beg_unchanged)
  63.         beg_unchanged = pos;
  64.     }
  65.     }
  66.  
  67.   i = GPT;
  68.   to = GAP_END_ADDR;
  69.   from = GPT_ADDR;
  70.   new_s1 = GPT - BEG;
  71.  
  72.   /* Now copy the characters.  To move the gap down,
  73.      copy characters up.  */
  74.  
  75.   while (1)
  76.     {
  77.       /* I gets number of characters left to copy.  */
  78.       i = new_s1 - pos;
  79.       if (i == 0)
  80.     break;
  81.       /* If a quit is requested, stop copying now.
  82.      Change POS to be where we have actually moved the gap to.  */
  83.       if (QUITP)
  84.     {
  85.       pos = new_s1;
  86.       break;
  87.     }
  88.       /* Move at most 32000 chars before checking again for a quit.  */
  89.       if (i > 32000)
  90.     i = 32000;
  91.       new_s1 -= i;
  92.       while (--i >= 0)
  93.     *--to = *--from;
  94.     }
  95.  
  96.   /* Adjust markers, and buffer data structure, to put the gap at POS.
  97.      POS is where the loop above stopped, which may be what was specified
  98.      or may be where a quit was detected.  */
  99.   adjust_markers (pos + 1, GPT, GAP_SIZE);
  100.   GPT = pos + 1;
  101.   QUIT;
  102. }
  103.  
  104. gap_right (pos)
  105.      register int pos;
  106. {
  107.   register unsigned char *to, *from;
  108.   register int i;
  109.   int new_s1;
  110.  
  111.   pos--;
  112.  
  113.   if (unchanged_modified == MODIFF)
  114.     {
  115.       beg_unchanged = pos;
  116.       end_unchanged = Z - pos - 1;
  117.     }
  118.   else
  119.     {
  120.       if (Z - pos - 1 < end_unchanged)
  121.     end_unchanged = Z - pos - 1;
  122.       if (GPT - BEG < beg_unchanged)
  123.     beg_unchanged = GPT - BEG;
  124.     }
  125.  
  126.   i = GPT;
  127.   from = GAP_END_ADDR;
  128.   to = GPT_ADDR;
  129.   new_s1 = GPT - 1;
  130.  
  131.   /* Now copy the characters.  To move the gap up,
  132.      copy characters down.  */
  133.  
  134.   while (1)
  135.     {
  136.       /* I gets number of characters left to copy.  */
  137.       i = pos - new_s1;
  138.       if (i == 0)
  139.     break;
  140.       /* If a quit is requested, stop copying now.
  141.      Change POS to be where we have actually moved the gap to.  */
  142.       if (QUITP)
  143.     {
  144.       pos = new_s1;
  145.       break;
  146.     }
  147.       /* Move at most 32000 chars before checking again for a quit.  */
  148.       if (i > 32000)
  149.     i = 32000;
  150.       new_s1 += i;
  151.       while (--i >= 0)
  152.     *to++ = *from++;
  153.     }
  154.  
  155.   adjust_markers (GPT + GAP_SIZE, pos + 1 + GAP_SIZE, - GAP_SIZE);
  156.   GPT = pos + 1;
  157.   QUIT;
  158. }
  159.  
  160. /* Add `amount' to the position of every marker in the current buffer
  161.    whose current position is between `from' (exclusive) and `to' (inclusive).
  162.    Also, any markers past the outside of that interval, in the direction
  163.    of adjustment, are first moved back to the near end of the interval
  164.    and then adjusted by `amount'.  */
  165.  
  166. adjust_markers (from, to, amount)
  167.      register int from, to, amount;
  168. {
  169.   Lisp_Object marker;
  170.   register struct Lisp_Marker *m;
  171.   register int mpos;
  172.  
  173.   marker = current_buffer->markers;
  174.  
  175.   while (!NULL (marker))
  176.     {
  177.       m = XMARKER (marker);
  178.       mpos = m->bufpos;
  179.       if (amount > 0)
  180.     {
  181.       if (mpos > to && mpos < to + amount)
  182.         mpos = to + amount;
  183.     }
  184.       else
  185.     {
  186.       if (mpos > from + amount && mpos <= from)
  187.         mpos = from + amount;
  188.     }
  189.       if (mpos > from && mpos <= to)
  190.     mpos += amount;
  191.       m->bufpos = mpos;
  192.       marker = m->chain;
  193.     }
  194. }
  195.  
  196. /* Make the gap INCREMENT characters longer.  */
  197.  
  198. make_gap (increment)
  199.      int increment;
  200. {
  201.   unsigned char *memory;
  202.   Lisp_Object tem;
  203.   int real_gap_loc;
  204.   int old_gap_size;
  205.  
  206.   /* If we have to get more space, get enough to last a while.  */
  207.   increment += 2000;
  208.  
  209.   memory = (unsigned char *) realloc (BEG_ADDR,
  210.                       Z - BEG + GAP_SIZE + increment);
  211.   if (memory == 0)
  212.     memory_full ();
  213.   BEG_ADDR = memory;
  214.  
  215.   /* Prevent quitting in move_gap.  */
  216.   tem = Vinhibit_quit;
  217.   Vinhibit_quit = Qt;
  218.  
  219.   real_gap_loc = GPT;
  220.   old_gap_size = GAP_SIZE;
  221.   /* Call the newly allocated space a gap at the end of the whole space.  */
  222.   GPT = Z + GAP_SIZE;
  223.   GAP_SIZE = increment;
  224.   /* Move the new gap down to be consecutive with the end of the old one.
  225.      This adjusts the markers properly too.  */
  226.   gap_left (real_gap_loc + old_gap_size, 1);
  227.   /* Now combine the two into one large gap.  */
  228.   GAP_SIZE += old_gap_size;
  229.   GPT = real_gap_loc;
  230.  
  231.   Vinhibit_quit = tem;
  232. }
  233.  
  234. /* Insert the character c before point */
  235.  
  236. insert_char (c)
  237.      unsigned char c;
  238. {
  239.   insert (&c, 1);
  240. }
  241.  
  242. /* Insert the null-terminated string s before point */
  243.  
  244. InsStr (s)
  245.      char *s;
  246. {
  247.   insert (s, strlen (s));
  248. }
  249.  
  250. /* Insert a string of specified length before point.
  251.    DO NOT use this for the contents of a Lisp string!
  252.    prepare_to_modify_buffer could relocate the string.  */
  253.  
  254. insert (string, length)
  255.      register unsigned char *string;
  256.      register length;
  257. {
  258.   register Lisp_Object temp;
  259.  
  260.   if (length < 1)
  261.     return;
  262.  
  263.   /* Make sure point-max won't overflow after this insertion.  */
  264.   XSET (temp, Lisp_Int, length + Z);
  265.   if (length + Z != XINT (temp))
  266.     error ("maximum buffer size exceeded");
  267.  
  268.   prepare_to_modify_buffer ();
  269.  
  270.   if (point != GPT)
  271.     move_gap (point);
  272.   if (GAP_SIZE < length)
  273.     make_gap (length - GAP_SIZE);
  274.  
  275.   record_insert (point, length);
  276.   MODIFF++;
  277.  
  278.   bcopy (string, GPT_ADDR, length);
  279.  
  280.   GAP_SIZE -= length;
  281.   GPT += length;
  282.   ZV += length;
  283.   Z += length;
  284.   point += length;
  285. }
  286.  
  287. /* Function to insert part of the text of a string (STRING) consisting
  288.    of LENGTH characters at position POS.
  289.    It does not work to use `insert' for this, becase a GC could happen
  290.    before we bcopy the stuff into the buffer, and relocate the string
  291.    without insert noticing.  */
  292. insert_from_string (string, pos, length)
  293.      Lisp_Object string;
  294.      register int pos, length;
  295. {
  296.   register Lisp_Object temp;
  297.   struct gcpro gcpro1;
  298.  
  299.   if (length < 1)
  300.     return;
  301.  
  302.   /* Make sure point-max won't overflow after this insertion.  */
  303.   XSET (temp, Lisp_Int, length + Z);
  304.   if (length + Z != XINT (temp))
  305.     error ("maximum buffer size exceeded");
  306.  
  307.   GCPRO1 (string);
  308.   prepare_to_modify_buffer ();
  309.  
  310.   if (point != GPT)
  311.     move_gap (point);
  312.   if (GAP_SIZE < length)
  313.     make_gap (length - GAP_SIZE);
  314.  
  315.   record_insert (point, length);
  316.   MODIFF++;
  317.   UNGCPRO;
  318.  
  319.   bcopy (XSTRING (string)->data, GPT_ADDR, length);
  320.  
  321.   GAP_SIZE -= length;
  322.   GPT += length;
  323.   ZV += length;
  324.   Z += length;
  325.   point += length;
  326. }
  327.  
  328. /* Like `insert' except that all markers pointing at the place where
  329.    the insertion happens are adjusted to point after it.
  330.    Don't use this function to insert part of a Lisp string,
  331.    since gc could happen and relocate it.  */
  332.  
  333. insert_before_markers (string, length)
  334.      unsigned char *string;
  335.      register int length;
  336. {
  337.   register int opoint = point;
  338.   insert (string, length);
  339.   adjust_markers (opoint - 1, opoint, length);
  340. }
  341.  
  342. /* Insert part of a Lisp string, relocating markers after.  */
  343.  
  344. insert_from_string_before_markers (string, pos, length)
  345.      Lisp_Object string;
  346.      register int pos, length;
  347. {
  348.   register int opoint = point;
  349.   insert_from_string (string, pos, length);
  350.   adjust_markers (opoint - 1, opoint, length);
  351. }
  352.  
  353. /* Delete characters in current buffer
  354.   from `from' up to (but not incl) `to' */
  355.  
  356. del_range (from, to)
  357.      register int from, to;
  358. {
  359.   register int numdel;
  360.  
  361.   /* Make args be valid */
  362.   if (from < BEGV)
  363.     from = BEGV;
  364.   if (to > ZV)
  365.     to = ZV;
  366.  
  367.   if ((numdel = to - from) <= 0)
  368.     return;
  369.  
  370.   /* Make sure the gap is somewhere in or next to what we are deleting */
  371.   if (from > GPT)
  372.     gap_right (from);
  373.   if (to < GPT)
  374.     gap_left (to, 0);
  375.  
  376.   prepare_to_modify_buffer ();
  377.   record_delete (from, numdel);
  378.   MODIFF++;
  379.  
  380.   /* Relocate point as if it were a marker.  */
  381.   if (from < point)
  382.     {
  383.       if (point < to)
  384.     point = from;
  385.       else
  386.     point -= numdel;
  387.     }
  388.  
  389.   /* Relocate all markers pointing into the new, larger gap
  390.      to point at the end of the text before the gap.  */
  391.   adjust_markers (to + GAP_SIZE, to + GAP_SIZE, - numdel - GAP_SIZE);
  392.  
  393.   GAP_SIZE += numdel;
  394.   ZV -= numdel;
  395.   Z -= numdel;
  396.   GPT = from;
  397.  
  398.   if (GPT - BEG < beg_unchanged)
  399.     beg_unchanged = GPT - BEG;
  400.   if (Z - GPT < end_unchanged)
  401.     end_unchanged = Z - GPT;
  402. }
  403.  
  404. modify_region (start, end)
  405.      int start, end;
  406. {
  407.   prepare_to_modify_buffer ();
  408.   if (start - 1 < beg_unchanged || unchanged_modified == MODIFF)
  409.     beg_unchanged = start - 1;
  410.   if (Z - end < end_unchanged
  411.       || unchanged_modified == MODIFF)
  412.     end_unchanged = Z - end;
  413.   MODIFF++;
  414. }
  415.  
  416. prepare_to_modify_buffer ()
  417. {
  418.   if (!NULL (current_buffer->read_only))
  419.     Fbarf_if_buffer_read_only();
  420.  
  421. #ifdef CLASH_DETECTION
  422.   if (!NULL (current_buffer->filename)
  423.       && current_buffer->save_modified >= MODIFF)
  424.     lock_file (current_buffer->filename);
  425. #else
  426.   /* At least warn if this file has changed on disk since it was visited.  */
  427.   if (!NULL (current_buffer->filename)
  428.       && current_buffer->save_modified >= MODIFF
  429.       && NULL (Fverify_visited_file_modtime (Fcurrent_buffer ()))
  430.       && !NULL (Ffile_exists_p (current_buffer->filename)))
  431.     call1 (intern ("ask-user-about-supersession-threat"),
  432.        current_buffer->filename);
  433. #endif /* not CLASH_DETECTION */
  434. }
  435.