/* Buffer insertion/deletion and gap motion for GNU Emacs.
Copyright (C) 1985, 1986, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ Free Software Foundation, Inc.
This file is part of GNU Emacs.
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include "lisp.h"
#include "intervals.h"
#include "buffer.h"
-#include "charset.h"
+#include "character.h"
#include "window.h"
#include "blockinput.h"
#include "region-cache.h"
for (m = BUF_MARKERS (current_buffer); m; m = m->next)
{
- /* In a single-byte buffer, a marker's two positions must be
- equal. */
- if (Z == Z_BYTE)
- {
- if (m->charpos != m->bytepos)
- abort ();
- }
+ eassert (m->bytepos >= m->charpos
+ && m->bytepos - m->charpos <= Z_BYTE - Z);
if (m->bytepos == from_byte)
{
BUF_PT_BYTE (current_buffer) += nbytes;
/* In a single-byte buffer, the two positions must be equal. */
- if (ZV == ZV_BYTE
- && PT != PT_BYTE)
- abort ();
+ eassert (PT_BYTE >= PT && PT_BYTE - PT <= ZV_BYTE - ZV);
}
\f
/* Adjust markers for a replacement of a text at FROM (FROM_BYTE) of
int bytes_left = nbytes;
Lisp_Object tbl = Qnil;
- /* We set the variable tbl to the reverse table of
- Vnonascii_translation_table in advance. */
- if (CHAR_TABLE_P (Vnonascii_translation_table))
- {
- tbl = Fchar_table_extra_slot (Vnonascii_translation_table,
- make_number (0));
- if (!CHAR_TABLE_P (tbl))
- tbl = Qnil;
- }
-
- /* Convert multibyte to single byte. */
while (bytes_left > 0)
{
int thislen, c;
c = STRING_CHAR_AND_LENGTH (from_addr, bytes_left, thislen);
- if (!SINGLE_BYTE_CHAR_P (c))
+ if (!ASCII_CHAR_P (c))
c = multibyte_char_to_unibyte (c, tbl);
*to_addr++ = c;
from_addr += thislen;
current_buffer, inherit);
adjust_point (nchars, outgoing_nbytes);
+
+ CHECK_MARKERS ();
+}
+\f
+/* Insert a sequence of NCHARS chars which occupy NBYTES bytes
+ starting at GPT_ADDR. */
+
+void
+insert_from_gap (nchars, nbytes)
+ register EMACS_INT nchars, nbytes;
+{
+ if (NILP (current_buffer->enable_multibyte_characters))
+ nchars = nbytes;
+
+ record_insert (GPT, nchars);
+ MODIFF++;
+
+ GAP_SIZE -= nbytes;
+ GPT += nchars;
+ ZV += nchars;
+ Z += nchars;
+ GPT_BYTE += nbytes;
+ ZV_BYTE += nbytes;
+ Z_BYTE += nbytes;
+ if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
+
+ if (GPT_BYTE < GPT)
+ abort ();
+
+ adjust_overlays_for_insert (GPT - nchars, nchars);
+ adjust_markers_for_insert (GPT - nchars, GPT_BYTE - nbytes,
+ GPT, GPT_BYTE, 0);
+
+ if (BUF_INTERVALS (current_buffer) != 0)
+ {
+ offset_intervals (current_buffer, GPT - nchars, nchars);
+ graft_intervals_into_buffer (NULL_INTERVAL, GPT - nchars, nchars,
+ current_buffer, 0);
+ }
+
+ if (GPT - nchars < PT)
+ adjust_point (nchars, nbytes);
+
+ CHECK_MARKERS ();
}
\f
/* Insert text from BUF, NCHARS characters starting at CHARPOS, into the
/* Get the intervals for the part of the string we are inserting. */
intervals = BUF_INTERVALS (buf);
- if (outgoing_nbytes < BUF_Z_BYTE (buf) - BUF_BEG_BYTE (buf))
+ if (nchars < BUF_Z (buf) - BUF_BEG (buf))
{
if (buf == current_buffer && PT <= from)
from += nchars;
#define FETCH_END \
(! NILP (end_marker) ? Fmarker_position (end_marker) : end)
+/* Set a variable to nil if an error occurred.
+ Don't change the variable if there was no error.
+ VAL is a cons-cell (VARIABLE . NO-ERROR-FLAG).
+ VARIABLE is the variable to maybe set to nil.
+ NO-ERROR-FLAG is nil if there was an error,
+ anything else meaning no error (so this function does nothing). */
+Lisp_Object
+reset_var_on_error (val)
+ Lisp_Object val;
+{
+ if (NILP (XCDR (val)))
+ Fset (XCAR (val), Qnil);
+ return Qnil;
+}
+
/* Signal a change to the buffer immediately before it happens.
START_INT and END_INT are the bounds of the text to be changed.
Lisp_Object start_marker, end_marker;
Lisp_Object preserve_marker;
struct gcpro gcpro1, gcpro2, gcpro3;
+ int count = SPECPDL_INDEX ();
if (inhibit_modification_hooks)
return;
end_marker = Qnil;
GCPRO3 (preserve_marker, start_marker, end_marker);
+ specbind (Qinhibit_modification_hooks, Qt);
+
/* If buffer is unmodified, run a special hook for that case. */
if (SAVE_MODIFF >= MODIFF
&& !NILP (Vfirst_change_hook)
if (!NILP (Vbefore_change_functions))
{
Lisp_Object args[3];
- Lisp_Object before_change_functions;
- Lisp_Object after_change_functions;
- struct gcpro gcpro1, gcpro2;
- struct buffer *old = current_buffer;
- struct buffer *new;
+ Lisp_Object rvoe_arg = Fcons (Qbefore_change_functions, Qnil);
PRESERVE_VALUE;
PRESERVE_START_END;
- /* "Bind" before-change-functions and after-change-functions
- to nil--but in a way that errors don't know about.
- That way, if there's an error in them, they will stay nil. */
- before_change_functions = Vbefore_change_functions;
- after_change_functions = Vafter_change_functions;
- Vbefore_change_functions = Qnil;
- Vafter_change_functions = Qnil;
- GCPRO2 (before_change_functions, after_change_functions);
+ /* Mark before-change-functions to be reset to nil in case of error. */
+ record_unwind_protect (reset_var_on_error, rvoe_arg);
/* Actually run the hook functions. */
args[0] = Qbefore_change_functions;
args[1] = FETCH_START;
args[2] = FETCH_END;
- run_hook_list_with_args (before_change_functions, 3, args);
+ Frun_hook_with_args (3, args);
- /* "Unbind" the variables we "bound" to nil. Beware a
- buffer-local hook which changes the buffer when run (e.g. W3). */
- if (old != current_buffer)
- {
- new = current_buffer;
- set_buffer_internal (old);
- Vbefore_change_functions = before_change_functions;
- Vafter_change_functions = after_change_functions;
- set_buffer_internal (new);
- }
- else
- {
- Vbefore_change_functions = before_change_functions;
- Vafter_change_functions = after_change_functions;
- }
- UNGCPRO;
+ /* There was no error: unarm the reset_on_error. */
+ XSETCDR (rvoe_arg, Qt);
}
if (current_buffer->overlays_before || current_buffer->overlays_after)
free_marker (end_marker);
RESTORE_VALUE;
UNGCPRO;
+
+ unbind_to (count, Qnil);
}
/* Signal a change immediately after it happens.
signal_after_change (charpos, lendel, lenins)
int charpos, lendel, lenins;
{
+ int count = SPECPDL_INDEX ();
if (inhibit_modification_hooks)
return;
if (!NILP (combine_after_change_list))
Fcombine_after_change_execute ();
+ specbind (Qinhibit_modification_hooks, Qt);
+
if (!NILP (Vafter_change_functions))
{
Lisp_Object args[4];
- Lisp_Object before_change_functions;
- Lisp_Object after_change_functions;
- struct buffer *old = current_buffer;
- struct buffer *new;
- struct gcpro gcpro1, gcpro2;
-
- /* "Bind" before-change-functions and after-change-functions
- to nil--but in a way that errors don't know about.
- That way, if there's an error in them, they will stay nil. */
- before_change_functions = Vbefore_change_functions;
- after_change_functions = Vafter_change_functions;
- Vbefore_change_functions = Qnil;
- Vafter_change_functions = Qnil;
- GCPRO2 (before_change_functions, after_change_functions);
+ Lisp_Object rvoe_arg = Fcons (Qafter_change_functions, Qnil);
+
+ /* Mark after-change-functions to be reset to nil in case of error. */
+ record_unwind_protect (reset_var_on_error, rvoe_arg);
/* Actually run the hook functions. */
args[0] = Qafter_change_functions;
XSETFASTINT (args[1], charpos);
XSETFASTINT (args[2], charpos + lenins);
XSETFASTINT (args[3], lendel);
- run_hook_list_with_args (after_change_functions,
- 4, args);
+ Frun_hook_with_args (4, args);
- /* "Unbind" the variables we "bound" to nil. Beware a
- buffer-local hook which changes the buffer when run (e.g. W3). */
- if (old != current_buffer)
- {
- new = current_buffer;
- set_buffer_internal (old);
- Vbefore_change_functions = before_change_functions;
- Vafter_change_functions = after_change_functions;
- set_buffer_internal (new);
- }
- else
- {
- Vbefore_change_functions = before_change_functions;
- Vafter_change_functions = after_change_functions;
- }
- UNGCPRO;
+ /* There was no error: unarm the reset_on_error. */
+ XSETCDR (rvoe_arg, Qt);
}
if (current_buffer->overlays_before || current_buffer->overlays_after)
if (lendel == 0)
report_interval_modification (make_number (charpos),
make_number (charpos + lenins));
+
+ unbind_to (count, Qnil);
}
Lisp_Object