home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / lemacs-19.6 / src / insdel.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-11  |  15.1 KB  |  643 lines

  1. /* Buffer insertion/deletion and gap motion for GNU Emacs.
  2.    Copyright (C) 1985, 1986, 1991, 1992, 1993 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 2, 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 "extents.h"
  25. #include "window.h"
  26. #include "insdel.h"
  27.  
  28.  
  29. /* Routines for dealing with the gap. */
  30.  
  31. /* Add `amount' to the position of every marker in the current buffer
  32.    whose current position is between `from' (exclusive) and `to' (inclusive).
  33.    Also, any markers past the outside of that range, in the direction
  34.    of adjustment, are first moved back to the near end of the range
  35.    and then adjusted by `amount'.  */
  36.  
  37. static void
  38. adjust_markers (from, to, amount)
  39.      int from, to, amount;
  40. {
  41.   Lisp_Object marker;
  42.   struct Lisp_Marker *m;
  43.   int mpos;
  44.  
  45.   marker = current_buffer->markers;
  46.  
  47.   while (!NILP (marker))
  48.     {
  49.       m = XMARKER (marker);
  50.       mpos = m->bufpos;
  51.       if (amount > 0)
  52.     {
  53.       if (mpos > to && mpos < to + amount)
  54.         mpos = to + amount;
  55.     }
  56.       else
  57.     {
  58.       if (mpos > from + amount && mpos <= from)
  59.         mpos = from + amount;
  60.     }
  61.       if (mpos > from && mpos <= to)
  62.     mpos += amount;
  63.       m->bufpos = mpos;
  64.       marker = m->chain;
  65.     }
  66. }
  67.  
  68. /* Move the gap to POS, which is less than the current GPT.   If NEWGAP
  69.    is nonzero, then don't update beg_unchanged and end_unchanged.  */
  70.  
  71. static void
  72. gap_left (pos, newgap)
  73.      register int pos;
  74.      int newgap;
  75. {
  76.   register unsigned char *to, *from;
  77.   register int i;
  78.   int new_s1;
  79.   pos--;
  80.  
  81.   if (!newgap)
  82.     {
  83.       if (unchanged_modified == MODIFF)
  84.     {
  85.       beg_unchanged = pos;
  86.       end_unchanged = Z - pos - 1;
  87.     }
  88.       else
  89.     {
  90.       if (Z - GPT < end_unchanged)
  91.         end_unchanged = Z - GPT;
  92.       if (pos < beg_unchanged)
  93.         beg_unchanged = pos;
  94.     }
  95.     }
  96.  
  97.   i = GPT;
  98.   to = GAP_END_ADDR;
  99.   from = GPT_ADDR;
  100.   new_s1 = GPT - BEG;
  101.  
  102.   /* Now copy the characters.  To move the gap down,
  103.      copy characters up.  */
  104.  
  105.   while (1)
  106.     {
  107.       /* I gets number of characters left to copy.  */
  108.       i = new_s1 - pos;
  109.       if (i == 0)
  110.     break;
  111.       /* If a quit is requested, stop copying now.
  112.      Change POS to be where we have actually moved the gap to.  */
  113.       if (QUITP)
  114.     {
  115.       pos = new_s1;
  116.       break;
  117.     }
  118.       /* Move at most 32000 chars before checking again for a quit.  */
  119.       if (i > 32000)
  120.     i = 32000;
  121.       new_s1 -= i;
  122.       while (--i >= 0)
  123.     *--to = *--from;
  124.     }
  125.  
  126.   /* Adjust markers, and buffer data structure, to put the gap at POS.
  127.      POS is where the loop above stopped, which may be what was specified
  128.      or may be where a quit was detected.  */
  129.   adjust_markers (pos + 1, GPT, GAP_SIZE);
  130.   adjust_extents (pos + 1, GPT, GAP_SIZE, current_buffer);
  131.   GPT = pos + 1;
  132.   QUIT;
  133. }
  134.  
  135. static void
  136. gap_right (pos)
  137.      register int pos;
  138. {
  139.   register unsigned char *to, *from;
  140.   register int i;
  141.   int new_s1;
  142.   pos--;
  143.  
  144.   if (unchanged_modified == MODIFF)
  145.     {
  146.       beg_unchanged = pos;
  147.       end_unchanged = Z - pos - 1;
  148.     }
  149.   else
  150.     {
  151.       if (Z - pos - 1 < end_unchanged)
  152.     end_unchanged = Z - pos - 1;
  153.       if (GPT - BEG < beg_unchanged)
  154.     beg_unchanged = GPT - BEG;
  155.     }
  156.  
  157.   i = GPT;
  158.   from = GAP_END_ADDR;
  159.   to = GPT_ADDR;
  160.   new_s1 = GPT - 1;
  161.  
  162.   /* Now copy the characters.  To move the gap up,
  163.      copy characters down.  */
  164.  
  165.   while (1)
  166.     {
  167.       /* I gets number of characters left to copy.  */
  168.       i = pos - new_s1;
  169.       if (i == 0)
  170.     break;
  171.       /* If a quit is requested, stop copying now.
  172.      Change POS to be where we have actually moved the gap to.  */
  173.       if (QUITP)
  174.     {
  175.       pos = new_s1;
  176.       break;
  177.     }
  178.       /* Move at most 32000 chars before checking again for a quit.  */
  179.       if (i > 32000)
  180.     i = 32000;
  181.       new_s1 += i;
  182.       while (--i >= 0)
  183.     *to++ = *from++;
  184.     }
  185.  
  186.   adjust_markers (GPT + GAP_SIZE, pos + 1 + GAP_SIZE, - GAP_SIZE);
  187.   adjust_extents (GPT + GAP_SIZE, pos + 1 + GAP_SIZE, - GAP_SIZE,
  188.           current_buffer);
  189.   GPT = pos + 1;
  190.   QUIT;
  191. }
  192.  
  193. /* Move gap to position `pos'.
  194.    Note that this can quit!  */
  195.  
  196. void
  197. move_gap (pos)
  198.      int pos;
  199. {
  200.   if (pos < GPT)
  201.     gap_left (pos, 0);
  202.   else if (pos > GPT)
  203.     gap_right (pos);
  204. }
  205.  
  206. /* Make the gap INCREMENT characters longer.  */
  207.  
  208. void
  209. make_gap (increment)
  210.      int increment;
  211. {
  212.   unsigned char *result;
  213.   Lisp_Object tem;
  214.   int real_gap_loc;
  215.   int old_gap_size;
  216.  
  217.   /* If we have to get more space, get enough to last a while.  We use
  218.      a geometric progession that saves on realloc space. */
  219.   increment += 2000 + (Z - BEG) * .1;
  220.  
  221.   result = BUFFER_REALLOC (BEG_ADDR, (Z - BEG + GAP_SIZE + increment));
  222.   if (result == 0)
  223.     memory_full ();
  224.   BEG_ADDR = result;
  225.  
  226.   /* Prevent quitting in move_gap.  */
  227.   tem = Vinhibit_quit;
  228.   Vinhibit_quit = Qt;
  229.  
  230.   real_gap_loc = GPT;
  231.   old_gap_size = GAP_SIZE;
  232.  
  233.   /* Call the newly allocated space a gap at the end of the whole space.  */
  234.   GPT = Z + GAP_SIZE;
  235.   GAP_SIZE = increment;
  236.  
  237.   /* Move the new gap down to be consecutive with the end of the old one.
  238.      This adjusts the markers properly too.  */
  239.   gap_left (real_gap_loc + old_gap_size, 1);
  240.  
  241.   /* Now combine the two into one large gap.  */
  242.   GAP_SIZE += old_gap_size;
  243.   GPT = real_gap_loc;
  244.  
  245.   Vinhibit_quit = tem;
  246. }
  247.  
  248. void signal_before_change (int, int);
  249.  
  250. /* Check that it is okay to modify the buffer between START and END.
  251.    Run the before-change-function, if any.  */
  252.  
  253. void
  254. prepare_to_modify_buffer (start, end)
  255.      int start, end;
  256. {
  257.   if (!NILP (current_buffer->read_only))
  258.     Fbarf_if_buffer_read_only ();
  259.  
  260.   verify_extent_modification (current_buffer, start, end);
  261.  
  262. #ifdef ENERGIZE
  263.   /* If buffer is unmodified, run a special hook for that case.  */
  264.   if (current_buffer->save_modified >= MODIFF
  265.       && !NILP (Vfirst_change_function))
  266.     {
  267.       safe_funcall_hook (Vfirst_change_function, 0, 0, 0, 0);
  268.     }
  269. #endif
  270.  
  271. #ifdef CLASH_DETECTION
  272.   if (!NILP (current_buffer->filename)
  273.       && current_buffer->save_modified >= MODIFF)
  274.     lock_file (current_buffer->filename);
  275. #else
  276.   /* At least warn if this file has changed on disk since it was visited.  */
  277.   if (!NILP (current_buffer->filename)
  278.       && current_buffer->save_modified >= MODIFF
  279.       && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
  280.       && !NILP (Ffile_exists_p (current_buffer->filename)))
  281.     call1 (intern ("ask-user-about-supersession-threat"),
  282.        current_buffer->filename);
  283. #endif /* not CLASH_DETECTION */
  284.  
  285.   signal_before_change (start, end);
  286. }
  287.  
  288. void
  289. modify_region (start, end)
  290.      int start, end;
  291. {
  292.   prepare_to_modify_buffer (start, end);
  293.  
  294.   if (start - 1 < beg_unchanged || unchanged_modified == MODIFF)
  295.     beg_unchanged = start - 1;
  296.   if (Z - end < end_unchanged
  297.       || unchanged_modified == MODIFF)
  298.     end_unchanged = Z - end;
  299.   MODIFF++;
  300. }
  301.  
  302. static Lisp_Object
  303. before_change_function_restore (value)
  304.      Lisp_Object value;
  305. {
  306.   Vbefore_change_function = value;
  307.   return Qnil;
  308. }
  309.  
  310. static Lisp_Object
  311. after_change_function_restore (value)
  312.      Lisp_Object value;
  313. {
  314.   Vafter_change_function = value;
  315.   return Qnil;
  316. }
  317.  
  318. /* Signal a change to the buffer immediatly before it happens.
  319.    START and END are the bounds of the text to be changed,
  320.    as Lisp objects.  */
  321.  
  322. void
  323. signal_before_change (start, end)
  324.      int start, end;
  325. {
  326.   /* Now in any case run the before-change-function if any.  */
  327.   if (!NILP (Vbefore_change_function))
  328.     {
  329.       int count = specpdl_depth;
  330.       Lisp_Object function, s, e;
  331.  
  332.       function = Vbefore_change_function;
  333.       record_unwind_protect (after_change_function_restore,
  334.                  Vafter_change_function);
  335.       record_unwind_protect (before_change_function_restore,
  336.                  Vbefore_change_function);
  337.       Vafter_change_function = Qnil;
  338.       Vbefore_change_function = Qnil;
  339.  
  340.       XSET (s, Lisp_Int, start);
  341.       XSET (e, Lisp_Int, end);
  342.       safe_funcall_hook (function, 2, s, e, 0);
  343.       unbind_to (count, Qnil);
  344.     }
  345. }
  346.  
  347. /* Signal a change immediatly after it happens.
  348.    POS is the address of the start of the changed text.
  349.    LENDEL is the number of characters of the text before the change.
  350.    (Not the whole buffer; just the part that was changed.)
  351.    LENINS is the number of characters in the changed text.  */
  352.  
  353. void
  354. signal_after_change (pos, lendel, lenins)
  355.      int pos, lendel, lenins;
  356. {
  357.   if (!NILP (Vafter_change_function))
  358.     {
  359.       int count = specpdl_depth;
  360.       Lisp_Object function;
  361.       function = Vafter_change_function;
  362.  
  363.       record_unwind_protect (after_change_function_restore,
  364.                  Vafter_change_function);
  365.       record_unwind_protect (before_change_function_restore,
  366.                  Vbefore_change_function);
  367.       Vafter_change_function = Qnil;
  368.       Vbefore_change_function = Qnil;
  369.  
  370.       safe_funcall_hook (function, 3, make_number (pos),
  371.              make_number (pos + lenins), make_number (lendel));
  372.       unbind_to (count, Qnil);
  373.     }
  374. }
  375.  
  376. /* Insertion of strings. */
  377.  
  378. void
  379. insert_relocatable_raw_string (string, length, obj)
  380.      Lisp_Object obj;
  381.      const char *string;
  382.      int length;
  383. {
  384.   struct gcpro gcpro1;
  385.   Lisp_Object dup_list = 
  386.     (STRINGP (obj))?(XSTRING(obj)->dup_list):Qnil;
  387.   Lisp_Object temp;
  388.   int opoint = point;
  389.  
  390.   if (length < 1)
  391.     return;
  392.  
  393.   GCPRO1 (obj);
  394.  
  395.   /* Make sure that point-max won't exceed the size of an emacs int. */
  396.   XSET (temp, Lisp_Int, length + Z);
  397.   if (length + Z != XINT (temp))
  398.     error ("maximum buffer size exceeded");
  399.  
  400.   prepare_to_modify_buffer (opoint, opoint);
  401.  
  402.   if (opoint != GPT)
  403.     move_gap (opoint);
  404.   if (GAP_SIZE < length)
  405.     make_gap (length - GAP_SIZE);
  406.  
  407.   record_insert (opoint, length);
  408.   MODIFF++;
  409.  
  410.   /* string may have been relocated up to this point */
  411.   if (STRINGP (obj))
  412.     string = (char *) XSTRING (obj) -> data;
  413.  
  414.   memcpy (GPT_ADDR, string, length);
  415.  
  416.   process_extents_for_insertion (opoint, length, current_buffer);
  417.  
  418.   GAP_SIZE -= length;
  419.   GPT += length;
  420.   ZV += length;
  421.   Z += length;
  422.   SET_PT (opoint + length);
  423.  
  424.   splice_in_extent_replicas (opoint, length, dup_list, current_buffer);
  425.   signal_after_change (opoint, 0, length);
  426.  
  427.   UNGCPRO;
  428. }
  429.  
  430. void
  431. insert_from_string (obj, pos, length)
  432.      Lisp_Object obj;
  433.      int pos, length;
  434. {
  435.   unsigned char *string = XSTRING (obj)->data;
  436.   struct gcpro gcpro1;
  437.   Lisp_Object dup_list = 
  438.     (STRINGP (obj)) ? (XSTRING (obj)->dup_list) : Qnil;
  439.   Lisp_Object temp;
  440.   int opoint = point;
  441.  
  442.   (void)pos;            /* pos is always 0 */
  443.  
  444.   if (length < 1)
  445.     return;
  446.  
  447.   GCPRO1 (obj);
  448.  
  449.   /* Make sure that point-max won't exceed the size of an emacs int. */
  450.   XSET (temp, Lisp_Int, length + Z);
  451.   if (length + Z != XINT (temp))
  452.     error ("maximum buffer size exceeded");
  453.  
  454.   prepare_to_modify_buffer (opoint, opoint);
  455.  
  456.   if (opoint != GPT)
  457.     move_gap (opoint);
  458.   if (GAP_SIZE < length)
  459.     make_gap (length - GAP_SIZE);
  460.  
  461.   record_insert (opoint, length);
  462.   MODIFF++;
  463.  
  464.   /* string may have been relocated up to this point */
  465.   if (STRINGP (obj))
  466.     string = XSTRING (obj) -> data;
  467.  
  468.   memcpy (GPT_ADDR, string, length);
  469.  
  470.   process_extents_for_insertion (opoint, length, current_buffer);
  471.  
  472.   GAP_SIZE -= length;
  473.   GPT += length;
  474.   ZV += length;
  475.   Z += length;
  476.   SET_PT (opoint + length);
  477.  
  478.   splice_in_extent_replicas (opoint, length, dup_list, current_buffer);
  479.   signal_after_change (opoint, 0, length);
  480.  
  481.   UNGCPRO;
  482. }
  483.  
  484. /* Insert a raw string of specified length before point */
  485.  
  486. void
  487. insert_raw_string (string, length)
  488.      const char *string;
  489.      int length;
  490. {
  491.   insert_relocatable_raw_string (string, length, 0);
  492.   return;
  493. }
  494.  
  495. void
  496. insert (string, length)
  497.      const char *string;
  498.      int length;
  499. {
  500.   insert_relocatable_raw_string (string, length, 0);
  501.   return;
  502. }
  503.  
  504. /* Insert the null-terminated string S before point */
  505.  
  506. void
  507. insert_string (s)
  508.      const char *s;
  509. {
  510.   insert_raw_string (s, strlen (s));
  511. }
  512.  
  513. /* Insert the character C before point */
  514.  
  515. void
  516. insert_char (char c)
  517. {
  518.   insert_raw_string (&c, 1);
  519. }
  520.  
  521. /* Like `insert_raw_string' except that all markers pointing at the place where
  522.    the insertion happens are adjusted to point after it.  */
  523.  
  524. void
  525. insert_before_markers (string, length)
  526.      const char *string;
  527.      register int length;
  528. {
  529.   register int opoint = point;
  530.   insert_raw_string (string, length);
  531.   adjust_markers (opoint - 1, opoint, length);
  532. }
  533.  
  534. void
  535. insert_from_string_before_markers (string, pos, length)
  536.      Lisp_Object string;
  537.      int pos, length;
  538. {
  539.   register int opoint = point;
  540.   insert_from_string (string, pos, length);
  541.   adjust_markers (opoint - 1, opoint, length);
  542. }
  543.  
  544.  
  545. /* This section deals with fat strings, i.e., those with extents. */
  546.  
  547. /* Insert the string which begins at INDEX in buffer B into
  548.    the current buffer at point. */
  549.  
  550. void
  551. insert_buffer_string (b, index, length)
  552.      struct buffer *b;
  553.      int index, length;
  554. {
  555.   struct gcpro gcpro1;
  556.   Lisp_Object str = make_string_from_buffer (b, index, length);
  557.   GCPRO1 (str);
  558.   insert_from_string (str, 0, XSTRING (str)->size);
  559.   UNGCPRO;
  560. }
  561.  
  562. /* Delete characters in current buffer
  563.    from FROM up to (but not including) TO.  */
  564.  
  565. #ifdef ENERGIZE
  566. extern int inside_parse_buffer; /* total kludge */
  567. #endif
  568.  
  569. void
  570. del_range (from, to)
  571.      register int from, to;
  572. {
  573.   int numdel;
  574.  
  575.   /* Make args be valid */
  576.   if (from < BEGV)
  577.     from = BEGV;
  578.   if (to > ZV)
  579.     to = ZV;
  580.  
  581.   if ((numdel = to - from) <= 0)
  582.     return;
  583.  
  584.   /* Make sure the gap is somewhere in or next to what we are deleting.  */
  585.   if (from > GPT)
  586.     gap_right (from);
  587.   if (to < GPT)
  588.     gap_left (to, 0);
  589.  
  590.   prepare_to_modify_buffer (from, to);
  591.  
  592.   /* Relocate point appropriately relative to the deleted chars. */
  593.   if (from < point)
  594.     {
  595.       if (point < to)
  596.     SET_PT (from);
  597.       else
  598.     SET_PT (point - numdel);
  599.     }
  600.  
  601. #ifdef ENERGIZE
  602.   if (!inside_parse_buffer)
  603. #endif
  604.     record_delete (from, numdel);
  605.  
  606.   MODIFF++;
  607.  
  608.   /* Relocate all markers pointing into the new, larger gap
  609.      to point at the end of the text before the gap.  */
  610.   adjust_markers (to + GAP_SIZE, to + GAP_SIZE, - numdel - GAP_SIZE);
  611.  
  612.   /* this must come AFTER record_delete(), so that the appropriate extents
  613.      will be present to be recorded, and BEFORE the gap size of increased,
  614.      as otherwise we will be confused about where the extents end. */
  615.   /* Passing to + GAP_SIZE ensures that the extent update code leaves no
  616.      extent endpoints hanging inside the gap.
  617.      --Matthieu */
  618.   process_extents_for_deletion (from, to, from, to + GAP_SIZE,
  619.                 current_buffer);
  620.  
  621.   GAP_SIZE += numdel;
  622.   ZV -= numdel;
  623.   Z -= numdel;
  624.   GPT = from;
  625.  
  626.   if (GPT - BEG < beg_unchanged)
  627.     beg_unchanged = GPT - BEG;
  628.   if (Z - GPT < end_unchanged)
  629.     end_unchanged = Z - GPT;
  630.  
  631.   /* Re-synchronize the point-marker with point.  This normally isn't
  632.      necessary, because SET_PT does it, but because we need to set point
  633.      before frobbing markers, above, the point-marker gets frobbed twice.
  634.      */
  635.   {
  636.     int p = point;
  637.     if (p > GPT) p += GAP_SIZE;
  638.     XMARKER (current_buffer->point_marker)->bufpos = p;
  639.   }
  640.  
  641.   signal_after_change (from, numdel, 0);
  642. }
  643.