/* Buffer manipulation primitives for GNU Emacs.
- Copyright (C) 1985,86,87,88,89,93,94,95,97,98, 1999
+ Copyright (C) 1985,86,87,88,89,93,94,95,97,98, 1999, 2000
Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <sys/stat.h>
#include <sys/param.h>
#include <errno.h>
+#include <stdio.h>
+#ifndef USE_CRT_DLL
extern int errno;
+#endif
#ifndef MAXPATHLEN
/* in 4.1, param.h fails to define this. */
#include "region-cache.h"
#include "indent.h"
#include "blockinput.h"
+#include "keyboard.h"
#include "frame.h"
struct buffer *current_buffer; /* the current buffer */
The value has only one nonzero bit.
When a buffer has its own local value for a slot,
- the bit for that slot (found in the same slot in this structure)
- is turned on in the buffer's local_var_flags slot.
+ the entry for that slot (found in the same slot in this structure)
+ is turned on in the buffer's local_flags array.
If a slot in this structure is -1, then even though there may
be a DEFVAR_PER_BUFFER for the slot, there is no default value for it;
/* Flags indicating which built-in buffer-local variables
are permanent locals. */
-static int buffer_permanent_local_flags;
+static char buffer_permanent_local_flags[MAX_PER_BUFFER_VARS];
+
+/* Number of per-buffer variables used. */
+
+int last_per_buffer_idx;
Lisp_Object Fset_buffer ();
void set_buffer_internal ();
Lisp_Object Vbuffer_alist;
/* Functions to call before and after each text change. */
-Lisp_Object Vbefore_change_function;
-Lisp_Object Vafter_change_function;
Lisp_Object Vbefore_change_functions;
Lisp_Object Vafter_change_functions;
Lisp_Object Qinsert_in_front_hooks;
Lisp_Object Qinsert_behind_hooks;
+static void alloc_buffer_text P_ ((struct buffer *, size_t));
+static void free_buffer_text P_ ((struct buffer *b));
+
+
/* For debugging; temporary. See set_buffer_internal. */
/* Lisp_Object Qlisp_mode, Vcheck_symbol; */
BLOCK_INPUT;
/* We allocate extra 1-byte at the tail and keep it always '\0' for
anchoring a search. */
- BUFFER_ALLOC (BUF_BEG_ADDR (b), (BUF_GAP_SIZE (b) + 1));
+ alloc_buffer_text (b, BUF_GAP_SIZE (b) + 1);
UNBLOCK_INPUT;
if (! BUF_BEG_ADDR (b))
buffer_memory_full ();
b->zv_marker = Qnil;
name = Fcopy_sequence (name);
- INITIALIZE_INTERVAL (XSTRING (name), NULL_INTERVAL);
+ XSTRING (name)->intervals = NULL_INTERVAL;
b->name = name;
if (XSTRING (name)->data[0] != ' ')
return buf;
}
-DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer, 2, 2,
+
+/* Clone per-buffer values of buffer FROM.
+
+ Buffer TO gets the same per-buffer values as FROM, with the
+ following exceptions: (1) TO's name is left untouched, (2) markers
+ are copied and made to refer to TO, and (3) overlay lists are
+ copied. */
+
+static void
+clone_per_buffer_values (from, to)
+ struct buffer *from, *to;
+{
+ Lisp_Object to_buffer;
+ int offset;
+
+ XSETBUFFER (to_buffer, to);
+
+ for (offset = PER_BUFFER_VAR_OFFSET (name) + sizeof (Lisp_Object);
+ offset < sizeof *to;
+ offset += sizeof (Lisp_Object))
+ {
+ Lisp_Object obj;
+
+ obj = PER_BUFFER_VALUE (from, offset);
+ if (MARKERP (obj))
+ {
+ struct Lisp_Marker *m = XMARKER (obj);
+ obj = Fmake_marker ();
+ XMARKER (obj)->insertion_type = m->insertion_type;
+ set_marker_both (obj, to_buffer, m->charpos, m->bytepos);
+ }
+
+ PER_BUFFER_VALUE (to, offset) = obj;
+ }
+
+ to->overlays_after = Fcopy_sequence (from->overlays_after);
+ to->overlays_before = Fcopy_sequence (to->overlays_before);
+ bcopy (from->local_flags, to->local_flags, sizeof to->local_flags);
+}
+
+
+DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer,
+ 2, 3,
"bMake indirect buffer (to buffer): \nBName of indirect buffer: ",
"Create and return an indirect buffer for buffer BASE-BUFFER, named NAME.\n\
BASE-BUFFER should be an existing buffer (or buffer name).\n\
-NAME should be a string which is not the name of an existing buffer.")
- (base_buffer, name)
- register Lisp_Object base_buffer, name;
+NAME should be a string which is not the name of an existing buffer.\n\
+Optional argument CLONE non-nil means preserve BASE-BUFFER's state,\n\
+such as major and minor modes, in the indirect buffer.\n\
+CLONE nil means the indirect buffer's state is reset to default values.")
+ (base_buffer, name, clone)
+ Lisp_Object base_buffer, name, clone;
{
- register Lisp_Object buf;
- register struct buffer *b;
+ Lisp_Object buf;
+ struct buffer *b;
buf = Fget_buffer (name);
if (!NILP (buf))
all_buffers = b;
name = Fcopy_sequence (name);
- INITIALIZE_INTERVAL (XSTRING (name), NULL_INTERVAL);
+ XSTRING (name)->intervals = NULL_INTERVAL;
b->name = name;
reset_buffer (b);
XMARKER (b->base_buffer->zv_marker)->insertion_type = 1;
}
- /* Give the indirect buffer markers for its narrowing. */
- b->pt_marker = Fmake_marker ();
- set_marker_both (b->pt_marker, buf, BUF_PT (b), BUF_PT_BYTE (b));
- b->begv_marker = Fmake_marker ();
- set_marker_both (b->begv_marker, buf, BUF_BEGV (b), BUF_BEGV_BYTE (b));
- b->zv_marker = Fmake_marker ();
- set_marker_both (b->zv_marker, buf, BUF_ZV (b), BUF_ZV_BYTE (b));
- XMARKER (b->zv_marker)->insertion_type = 1;
+ if (NILP (clone))
+ {
+ /* Give the indirect buffer markers for its narrowing. */
+ b->pt_marker = Fmake_marker ();
+ set_marker_both (b->pt_marker, buf, BUF_PT (b), BUF_PT_BYTE (b));
+ b->begv_marker = Fmake_marker ();
+ set_marker_both (b->begv_marker, buf, BUF_BEGV (b), BUF_BEGV_BYTE (b));
+ b->zv_marker = Fmake_marker ();
+ set_marker_both (b->zv_marker, buf, BUF_ZV (b), BUF_ZV_BYTE (b));
+ XMARKER (b->zv_marker)->insertion_type = 1;
+ }
+ else
+ clone_per_buffer_values (b->base_buffer, b);
return buf;
}
b->last_selected_window = Qnil;
XSETINT (b->display_count, 0);
b->display_time = Qnil;
- b->extra2 = Qnil;
- b->extra3 = Qnil;
b->enable_multibyte_characters = buffer_defaults.enable_multibyte_characters;
+ b->cursor_type = buffer_defaults.cursor_type;
+ b->extra_line_spacing = buffer_defaults.extra_line_spacing;
}
/* Reset buffer B's local variables info.
int permanent_too;
{
register int offset;
- int dont_reset;
-
- /* Decide which built-in local variables to reset. */
- if (permanent_too)
- dont_reset = 0;
- else
- dont_reset = buffer_permanent_local_flags;
+ int i;
/* Reset the major mode to Fundamental, together with all the
things that depend on the major mode.
/* Reset all (or most) per-buffer variables to their defaults. */
b->local_var_alist = Qnil;
- b->local_var_flags &= dont_reset;
+ for (i = 0; i < last_per_buffer_idx; ++i)
+ if (permanent_too || buffer_permanent_local_flags[i] == 0)
+ SET_PER_BUFFER_VALUE_P (b, i, 0);
/* For each slot that has a default value,
copy that into the slot. */
- for (offset = (char *)&buffer_local_flags.name - (char *)&buffer_local_flags;
- offset < sizeof (struct buffer);
- offset += sizeof (Lisp_Object)) /* sizeof EMACS_INT == sizeof Lisp_Object */
+ for (offset = PER_BUFFER_VAR_OFFSET (name);
+ offset < sizeof *b;
+ offset += sizeof (Lisp_Object))
{
- int flag = XINT (*(Lisp_Object *)(offset + (char *)&buffer_local_flags));
- if ((flag > 0
- /* Don't reset a permanent local. */
- && ! (dont_reset & flag))
- || flag == -2)
- *(Lisp_Object *)(offset + (char *)b)
- = *(Lisp_Object *)(offset + (char *)&buffer_defaults);
+ int idx = PER_BUFFER_IDX (offset);
+ if ((idx > 0
+ && (permanent_too
+ || buffer_permanent_local_flags[idx] == 0))
+ /* Is -2 used anywhere? */
+ || idx == -2)
+ PER_BUFFER_VALUE (b, offset) = PER_BUFFER_DEFAULT (offset);
}
}
/* Add on all the variables stored in special slots. */
{
- register int offset, mask;
+ int offset, idx;
- for (offset = (char *)&buffer_local_symbols.name - (char *)&buffer_local_symbols;
+ for (offset = PER_BUFFER_VAR_OFFSET (name);
offset < sizeof (struct buffer);
- offset += (sizeof (EMACS_INT))) /* sizeof EMACS_INT == sizeof Lisp_Object */
+ /* sizeof EMACS_INT == sizeof Lisp_Object */
+ offset += (sizeof (EMACS_INT)))
{
- mask = XINT (*(Lisp_Object *)(offset + (char *)&buffer_local_flags));
- if (mask == -1 || (buf->local_var_flags & mask))
- if (SYMBOLP (*(Lisp_Object *)(offset
- + (char *)&buffer_local_symbols)))
- result = Fcons (Fcons (*((Lisp_Object *)
- (offset + (char *)&buffer_local_symbols)),
- *(Lisp_Object *)(offset + (char *)buf)),
- result);
+ idx = PER_BUFFER_IDX (offset);
+ if ((idx == -1 || PER_BUFFER_VALUE_P (buf, idx))
+ && SYMBOLP (PER_BUFFER_SYMBOL (offset)))
+ result = Fcons (Fcons (PER_BUFFER_SYMBOL (offset),
+ PER_BUFFER_VALUE (buf, offset)),
+ result);
}
}
return flag;
}
+DEFUN ("restore-buffer-modified-p", Frestore_buffer_modified_p,
+ Srestore_buffer_modified_p, 1, 1, 0,
+ "Like `set-buffer-modified-p', with a differences concerning redisplay.\n\
+It is not ensured that mode lines will be updated to show the modified\n\
+state of the current buffer. Use with care.")
+ (flag)
+ Lisp_Object flag;
+{
+#ifdef CLASH_DETECTION
+ Lisp_Object fn;
+
+ /* If buffer becoming modified, lock the file.
+ If buffer becoming unmodified, unlock the file. */
+
+ fn = current_buffer->file_truename;
+ /* Test buffer-file-name so that binding it to nil is effective. */
+ if (!NILP (fn) && ! NILP (current_buffer->filename))
+ {
+ int already = SAVE_MODIFF < MODIFF;
+ if (!already && !NILP (flag))
+ lock_file (fn);
+ else if (already && NILP (flag))
+ unlock_file (fn);
+ }
+#endif /* CLASH_DETECTION */
+
+ SAVE_MODIFF = NILP (flag) ? MODIFF : 0;
+ return flag;
+}
+
DEFUN ("buffer-modified-tick", Fbuffer_modified_tick, Sbuffer_modified_tick,
0, 1, 0,
"Return BUFFER's tick counter, incremented for each change in text.\n\
error ("Empty string is invalid as a buffer name");
tem = Fget_buffer (newname);
- /* Don't short-circuit if UNIQUE is t. That is a useful way to rename
- the buffer automatically so you can create another with the original name.
- It makes UNIQUE equivalent to
- (rename-buffer (generate-new-buffer-name NEWNAME)). */
- if (NILP (unique) && XBUFFER (tem) == current_buffer)
- return current_buffer->name;
if (!NILP (tem))
{
+ /* Don't short-circuit if UNIQUE is t. That is a useful way to
+ rename the buffer automatically so you can create another
+ with the original name. It makes UNIQUE equivalent to
+ (rename-buffer (generate-new-buffer-name NEWNAME)). */
+ if (NILP (unique) && XBUFFER (tem) == current_buffer)
+ return current_buffer->name;
if (!NILP (unique))
newname = Fgenerate_new_buffer_name (newname, current_buffer->name);
else
}
if (NILP (visible_ok))
- tem = Fget_buffer_window (buf, Qt);
+ tem = Fget_buffer_window (buf, Qvisible);
else
tem = Qnil;
if (NILP (tem))
BLOCK_INPUT;
if (! b->base_buffer)
- BUFFER_FREE (BUF_BEG_ADDR (b));
+ free_buffer_text (b);
if (b->newline_cache)
{
register Lisp_Object tail, valcontents;
Lisp_Object tem;
+#ifdef USE_MMAP_FOR_BUFFERS
+ if (b->text->beg == NULL)
+ enlarge_buffer_text (b, 0);
+#endif /* USE_MMAP_FOR_BUFFERS */
+
if (current_buffer == b)
return;
buffer = buf1;
}
- /* Move buffer to the end of the buffer list. */
- {
- register Lisp_Object aelt, link;
+ /* Move buffer to the end of the buffer list. Do nothing if the
+ buffer is killed. */
+ if (!NILP (XBUFFER (buffer)->name))
+ {
+ Lisp_Object aelt, link;
- aelt = Frassq (buffer, Vbuffer_alist);
- link = Fmemq (aelt, Vbuffer_alist);
- Vbuffer_alist = Fdelq (aelt, Vbuffer_alist);
- XCDR (link) = Qnil;
- Vbuffer_alist = nconc2 (Vbuffer_alist, link);
- }
+ aelt = Frassq (buffer, Vbuffer_alist);
+ link = Fmemq (aelt, Vbuffer_alist);
+ Vbuffer_alist = Fdelq (aelt, Vbuffer_alist);
+ XCDR (link) = Qnil;
+ Vbuffer_alist = nconc2 (Vbuffer_alist, link);
- frames_bury_buffer (buffer);
+ frames_bury_buffer (buffer);
+ }
return Qnil;
}
{
/* We should advance BYTE_POS only when C is a constituent of a
multibyte sequence. */
- DEC_POS (byte_pos);
+ int orig_byte_pos = byte_pos;
+
+ do
+ {
+ byte_pos--;
+ c = FETCH_BYTE (byte_pos);
+ }
+ while (! CHAR_HEAD_P (c) && byte_pos > BEG);
INC_POS (byte_pos);
+ if (byte_pos < orig_byte_pos)
+ byte_pos = orig_byte_pos;
/* If C is a constituent of a multibyte sequence, BYTE_POS was
surely advance to the correct character boundary. If C is
not, BYTE_POS was unchanged. */
{
Lisp_Object tail, markers;
struct buffer *other;
+ int undo_enabled_p = !EQ (current_buffer->undo_list, Qt);
+ int begv = BEGV, zv = ZV;
+ int narrowed = (BEG != begv || Z != zv);
+ int modified_p = !NILP (Fbuffer_modified_p (Qnil));
if (current_buffer->base_buffer)
error ("Cannot do `set-buffer-multibyte' on an indirect buffer");
/* It would be better to update the list,
but this is good enough for now. */
- if (! EQ (current_buffer->undo_list, Qt))
- current_buffer->undo_list = Qnil;
+ if (undo_enabled_p)
+ current_buffer->undo_list = Qt;
/* If the cached position is for this buffer, clear it out. */
clear_charpos_cache (current_buffer);
+ if (narrowed)
+ Fwiden ();
+
if (NILP (flag))
{
+ int pos, stop;
+ unsigned char *p;
+
/* Do this first, so it can use CHAR_TO_BYTE
to calculate the old correspondences. */
set_intervals_multibyte (0);
TEMP_SET_PT_BOTH (PT_BYTE, PT_BYTE);
tail = BUF_MARKERS (current_buffer);
- while (XSYMBOL (tail) != XSYMBOL (Qnil))
+ while (! NILP (tail))
{
XMARKER (tail)->charpos = XMARKER (tail)->bytepos;
tail = XMARKER (tail)->chain;
}
+
+ /* Convert multibyte form of 8-bit characters to unibyte. */
+ pos = BEG;
+ stop = GPT;
+ p = BEG_ADDR;
+ while (1)
+ {
+ int c, bytes;
+
+ if (pos == stop)
+ {
+ if (pos == Z)
+ break;
+ p = GAP_END_ADDR;
+ stop = Z;
+ }
+ if (MULTIBYTE_STR_AS_UNIBYTE_P (p, bytes))
+ p += bytes, pos += bytes;
+ else
+ {
+ c = STRING_CHAR (p, stop - pos);
+ /* Delete all bytes for this 8-bit character but the
+ last one, and change the last one to the charcter
+ code. */
+ bytes--;
+ del_range_2 (pos, pos, pos + bytes, pos + bytes, 0);
+ p = GAP_END_ADDR;
+ *p++ = c;
+ pos++;
+ if (begv > pos)
+ begv -= bytes;
+ if (zv > pos)
+ zv -= bytes;
+ stop = Z;
+ }
+ }
+ if (narrowed)
+ Fnarrow_to_region (make_number (begv), make_number (zv));
}
else
{
+ int pt = PT;
+ int pos, stop;
+ unsigned char *p;
+
/* Be sure not to have a multibyte sequence striding over the GAP.
- Ex: We change this: "...abc\201\241\241 _GAP_ \241\241\241..."
- to: "...abc _GAP_ \201\241\241\241\241\241..." */
+ Ex: We change this: "...abc\201 _GAP_ \241def..."
+ to: "...abc _GAP_ \201\241def..." */
if (GPT_BYTE > 1 && GPT_BYTE < Z_BYTE
&& ! CHAR_HEAD_P (*(GAP_END_ADDR)))
}
}
+ /* Make the buffer contents valid as multibyte by converting
+ 8-bit characters to multibyte form. */
+ pos = BEG;
+ stop = GPT;
+ p = BEG_ADDR;
+ while (1)
+ {
+ int bytes;
+
+ if (pos == stop)
+ {
+ if (pos == Z)
+ break;
+ p = GAP_END_ADDR;
+ stop = Z;
+ }
+
+ if (UNIBYTE_STR_AS_MULTIBYTE_P (p, stop - pos, bytes))
+ p += bytes, pos += bytes;
+ else
+ {
+ unsigned char tmp[MAX_MULTIBYTE_LENGTH];
+
+ bytes = CHAR_STRING (*p, tmp);
+ *p = tmp[0];
+ TEMP_SET_PT_BOTH (pos + 1, pos + 1);
+ bytes--;
+ insert_1_both (tmp + 1, bytes, bytes, 1, 0, 0);
+ /* Now the gap is after the just inserted data. */
+ pos = GPT;
+ p = GAP_END_ADDR;
+ if (pos <= begv)
+ begv += bytes;
+ if (pos <= zv)
+ zv += bytes;
+ if (pos <= pt)
+ pt += bytes;
+ stop = Z;
+ }
+ }
+
+ if (pt != PT)
+ TEMP_SET_PT (pt);
+
+ if (narrowed)
+ Fnarrow_to_region (make_number (begv), make_number (zv));
+
/* Do this first, so that chars_in_text asks the right question.
set_intervals_multibyte needs it too. */
current_buffer->enable_multibyte_characters = Qt;
It is also a signal that it should never create a marker. */
BUF_MARKERS (current_buffer) = Qnil;
- while (XSYMBOL (tail) != XSYMBOL (Qnil))
+ while (! NILP (tail))
{
XMARKER (tail)->bytepos
= advance_to_char_boundary (XMARKER (tail)->bytepos);
set_intervals_multibyte (1);
}
+ if (undo_enabled_p)
+ current_buffer->undo_list = Qnil;
+
/* Changing the multibyteness of a buffer means that all windows
showing that buffer must be updated thoroughly. */
current_buffer->prevent_redisplay_optimizations_p = 1;
other->prevent_redisplay_optimizations_p = 1;
}
+ /* Restore the modifiedness of the buffer. */
+ if (!modified_p && !NILP (Fbuffer_modified_p (Qnil)))
+ Fset_buffer_modified_p (Qnil);
+
return flag;
}
\f
/* Need not do anything if some other buffer's binding is now encached. */
tem = XBUFFER_LOCAL_VALUE (XSYMBOL (sym)->value)->buffer;
- if (XBUFFER (tem) == current_buffer)
+ if (BUFFERP (tem) && XBUFFER (tem) == current_buffer)
{
/* Symbol is set up for this buffer's old local value.
Set it up for the current buffer with the default value. */
If EXTEND is non-zero, we make the vector bigger if necessary.
If EXTEND is zero, we never extend the vector,
and we store only as many overlays as will fit.
- But we still return the total number of overlays. */
+ But we still return the total number of overlays.
+
+ If CHANGE_REQ is true, then any position written into *PREV_PTR or
+ *NEXT_PTR is guaranteed to be not equal to POS, unless it is the
+ default (BEGV or ZV). */
int
-overlays_at (pos, extend, vec_ptr, len_ptr, next_ptr, prev_ptr)
+overlays_at (pos, extend, vec_ptr, len_ptr, next_ptr, prev_ptr, change_req)
int pos;
int extend;
Lisp_Object **vec_ptr;
int *len_ptr;
int *next_ptr;
int *prev_ptr;
+ int change_req;
{
Lisp_Object tail, overlay, start, end;
int idx = 0;
}
else if (endpos < pos && endpos > prev)
prev = endpos;
- else if (endpos == pos && startpos > prev)
+ else if (endpos == pos && startpos > prev
+ && (!change_req || startpos < pos))
prev = startpos;
}
obuffer = Fmarker_buffer (OVERLAY_START (overlay));
b = XBUFFER (buffer);
- ob = XBUFFER (obuffer);
+ ob = BUFFERP (obuffer) ? XBUFFER (obuffer) : (struct buffer *) 0;
/* If the overlay has changed buffers, do a thorough redisplay. */
if (!EQ (buffer, obuffer))
CHECK_NUMBER_COERCE_MARKER (pos, 0);
len = 10;
+ /* We can't use alloca here because overlays_at can call xrealloc. */
overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
/* Put all the overlays we want in a vector in overlay_vec.
Store the length in len. */
noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
- (int *) 0, (int *) 0);
+ (int *) 0, (int *) 0, 0);
/* Make a list of them all. */
result = Flist (noverlays, overlay_vec);
Store the length in len.
endpos gets the position where the next overlay starts. */
noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
- &endpos, (int *) 0);
+ &endpos, (int *) 0, 1);
/* If any of these overlays ends before endpos,
use its ending point instead. */
CHECK_NUMBER_COERCE_MARKER (pos, 0);
- len = 10;
- overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
-
/* At beginning of buffer, we know the answer;
avoid bug subtracting 1 below. */
if (XINT (pos) == BEGV)
return pos;
+ len = 10;
+ overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
+
/* Put all the overlays we want in a vector in overlay_vec.
Store the length in len.
prevpos gets the position of the previous change. */
noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
- (int *) 0, &prevpos);
+ (int *) 0, &prevpos, 1);
xfree (overlay_vec);
return make_number (prevpos);
{
Lisp_Object sym;
char *type_name;
- sym = *(Lisp_Object *)(offset + (char *)&buffer_local_symbols);
- switch (XINT (*(Lisp_Object *)(offset + (char *)&buffer_local_types)))
+
+ switch (XINT (PER_BUFFER_TYPE (offset)))
{
- case Lisp_Int: type_name = "integers"; break;
- case Lisp_String: type_name = "strings"; break;
- case Lisp_Symbol: type_name = "symbols"; break;
-
+ case Lisp_Int:
+ type_name = "integers";
+ break;
+
+ case Lisp_String:
+ type_name = "strings";
+ break;
+
+ case Lisp_Symbol:
+ type_name = "symbols";
+ break;
+
default:
abort ();
}
+ sym = PER_BUFFER_SYMBOL (offset);
error ("Only %s should be stored in the buffer-local variable %s",
type_name, XSYMBOL (sym)->name->data);
}
+
+\f
+/***********************************************************************
+ Allocation with mmap
+ ***********************************************************************/
+
+#ifdef USE_MMAP_FOR_BUFFERS
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#ifndef MAP_ANON
+#ifdef MAP_ANONYMOUS
+#define MAP_ANON MAP_ANONYMOUS
+#else
+#define MAP_ANON 0
+#endif
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#if MAP_ANON == 0
+#include <fcntl.h>
+#endif
+
+#include "coding.h"
+
+
+/* Memory is allocated in regions which are mapped using mmap(2).
+ The current implementation lets the system select mapped
+ addresses; we're not using MAP_FIXED in general, except when
+ trying to enlarge regions.
+
+ Each mapped region starts with a mmap_region structure, the user
+ area starts after that structure, aligned to MEM_ALIGN.
+
+ +-----------------------+
+ | struct mmap_info + |
+ | padding |
+ +-----------------------+
+ | user data |
+ | |
+ | |
+ +-----------------------+ */
+
+struct mmap_region
+{
+ /* User-specified size. */
+ size_t nbytes_specified;
+
+ /* Number of bytes mapped */
+ size_t nbytes_mapped;
+
+ /* Pointer to the location holding the address of the memory
+ allocated with the mmap'd block. The variable actually points
+ after this structure. */
+ POINTER_TYPE **var;
+
+ /* Next and previous in list of all mmap'd regions. */
+ struct mmap_region *next, *prev;
+};
+
+/* Doubly-linked list of mmap'd regions. */
+
+static struct mmap_region *mmap_regions;
+
+/* File descriptor for mmap. If we don't have anonymous mapping,
+ /dev/zero will be opened on it. */
+
+static int mmap_fd;
+
+/* Temporary storage for mmap_set_vars, see there. */
+
+static struct mmap_region *mmap_regions_1;
+static int mmap_fd_1;
+
+/* Page size on this system. */
+
+static int mmap_page_size;
+
+/* 1 means mmap has been intialized. */
+
+static int mmap_initialized_p;
+
+/* Value is X rounded up to the next multiple of N. */
+
+#define ROUND(X, N) (((X) + (N) - 1) / (N) * (N))
+
+/* Size of mmap_region structure plus padding. */
+
+#define MMAP_REGION_STRUCT_SIZE \
+ ROUND (sizeof (struct mmap_region), MEM_ALIGN)
+
+/* Given a pointer P to the start of the user-visible part of a mapped
+ region, return a pointer to the start of the region. */
+
+#define MMAP_REGION(P) \
+ ((struct mmap_region *) ((char *) (P) - MMAP_REGION_STRUCT_SIZE))
+
+/* Given a pointer P to the start of a mapped region, return a pointer
+ to the start of the user-visible part of the region. */
+
+#define MMAP_USER_AREA(P) \
+ ((POINTER_TYPE *) ((char *) (P) + MMAP_REGION_STRUCT_SIZE))
+
+#define MEM_ALIGN sizeof (double)
+
+/* Function prototypes. */
+
+static int mmap_free_1 P_ ((struct mmap_region *));
+static int mmap_enlarge P_ ((struct mmap_region *, int));
+static struct mmap_region *mmap_find P_ ((POINTER_TYPE *, POINTER_TYPE *));
+static POINTER_TYPE *mmap_alloc P_ ((POINTER_TYPE **, size_t));
+static POINTER_TYPE *mmap_realloc P_ ((POINTER_TYPE **, size_t));
+static void mmap_free P_ ((POINTER_TYPE **ptr));
+static void mmap_init P_ ((void));
+
+
+/* Return a region overlapping address range START...END, or null if
+ none. END is not including, i.e. the last byte in the range
+ is at END - 1. */
+
+static struct mmap_region *
+mmap_find (start, end)
+ POINTER_TYPE *start, *end;
+{
+ struct mmap_region *r;
+ char *s = (char *) start, *e = (char *) end;
+
+ for (r = mmap_regions; r; r = r->next)
+ {
+ char *rstart = (char *) r;
+ char *rend = rstart + r->nbytes_mapped;
+
+ if (/* First byte of range, i.e. START, in this region? */
+ (s >= rstart && s < rend)
+ /* Last byte of range, i.e. END - 1, in this region? */
+ || (e > rstart && e <= rend)
+ /* First byte of this region in the range? */
+ || (rstart >= s && rstart < e)
+ /* Last byte of this region in the range? */
+ || (rend > s && rend <= e))
+ break;
+ }
+
+ return r;
+}
+
+
+/* Unmap a region. P is a pointer to the start of the user-araa of
+ the region. Value is non-zero if successful. */
+
+static int
+mmap_free_1 (r)
+ struct mmap_region *r;
+{
+ if (r->next)
+ r->next->prev = r->prev;
+ if (r->prev)
+ r->prev->next = r->next;
+ else
+ mmap_regions = r->next;
+
+ if (munmap (r, r->nbytes_mapped) == -1)
+ {
+ fprintf (stderr, "munmap: %s\n", emacs_strerror (errno));
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Enlarge region R by NPAGES pages. NPAGES < 0 means shrink R.
+ Value is non-zero if successful. */
+
+static int
+mmap_enlarge (r, npages)
+ struct mmap_region *r;
+ int npages;
+{
+ char *region_end = (char *) r + r->nbytes_mapped;
+ size_t nbytes;
+ int success = 0;
+
+ if (npages < 0)
+ {
+ /* Unmap pages at the end of the region. */
+ nbytes = - npages * mmap_page_size;
+ if (munmap (region_end - nbytes, nbytes) == -1)
+ fprintf (stderr, "munmap: %s\n", emacs_strerror (errno));
+ else
+ {
+ r->nbytes_mapped -= nbytes;
+ success = 1;
+ }
+ }
+ else if (npages > 0)
+ {
+ struct mmap_region *r2;
+
+ nbytes = npages * mmap_page_size;
+
+ /* Try to map additional pages at the end of the region. We
+ cannot do this if the address range is already occupied by
+ something else because mmap deletes any previous mapping.
+ I'm not sure this is worth doing, let's see. */
+ r2 = mmap_find (region_end, region_end + nbytes);
+ if (r2 == NULL)
+ {
+ POINTER_TYPE *p;
+
+ p = mmap (region_end, nbytes, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE | MAP_FIXED, mmap_fd, 0);
+ if (p == MAP_FAILED)
+ ; /* fprintf (stderr, "mmap: %s\n", emacs_strerror (errno)); */
+ else if (p != (POINTER_TYPE *) region_end)
+ {
+ /* Kernels are free to choose a different address. In
+ that case, unmap what we've mapped above; we have
+ no use for it. */
+ if (munmap (p, nbytes) == -1)
+ fprintf (stderr, "munmap: %s\n", emacs_strerror (errno));
+ }
+ else
+ {
+ r->nbytes_mapped += nbytes;
+ success = 1;
+ }
+ }
+ }
+
+ return success;
+}
+
+
+/* Set or reset variables holding references to mapped regions. If
+ RESTORE_P is zero, set all variables to null. If RESTORE_P is
+ non-zero, set all variables to the start of the user-areas
+ of mapped regions.
+
+ This function is called from Fdump_emacs to ensure that the dumped
+ Emacs doesn't contain references to memory that won't be mapped
+ when Emacs starts. */
+
+void
+mmap_set_vars (restore_p)
+ int restore_p;
+{
+ struct mmap_region *r;
+
+ if (restore_p)
+ {
+ mmap_regions = mmap_regions_1;
+ mmap_fd = mmap_fd_1;
+ for (r = mmap_regions; r; r = r->next)
+ *r->var = MMAP_USER_AREA (r);
+ }
+ else
+ {
+ for (r = mmap_regions; r; r = r->next)
+ *r->var = NULL;
+ mmap_regions_1 = mmap_regions;
+ mmap_regions = NULL;
+ mmap_fd_1 = mmap_fd;
+ mmap_fd = -1;
+ }
+}
+
+
+/* Allocate a block of storage large enough to hold NBYTES bytes of
+ data. A pointer to the data is returned in *VAR. VAR is thus the
+ address of some variable which will use the data area.
+
+ The allocation of 0 bytes is valid.
+
+ If we can't allocate the necessary memory, set *VAR to null, and
+ return null. */
+
+static POINTER_TYPE *
+mmap_alloc (var, nbytes)
+ POINTER_TYPE **var;
+ size_t nbytes;
+{
+ void *p;
+ size_t map;
+
+ mmap_init ();
+
+ map = ROUND (nbytes + MMAP_REGION_STRUCT_SIZE, mmap_page_size);
+ p = mmap (NULL, map, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
+ mmap_fd, 0);
+
+ if (p == MAP_FAILED)
+ {
+ if (errno != ENOMEM)
+ fprintf (stderr, "mmap: %s\n", emacs_strerror (errno));
+ p = NULL;
+ }
+ else
+ {
+ struct mmap_region *r = (struct mmap_region *) p;
+
+ r->nbytes_specified = nbytes;
+ r->nbytes_mapped = map;
+ r->var = var;
+ r->prev = NULL;
+ r->next = mmap_regions;
+ if (r->next)
+ r->next->prev = r;
+ mmap_regions = r;
+
+ p = MMAP_USER_AREA (p);
+ }
+
+ return *var = p;
+}
+
+
+/* Given a pointer at address VAR to data allocated with mmap_alloc,
+ resize it to size NBYTES. Change *VAR to reflect the new block,
+ and return this value. If more memory cannot be allocated, then
+ leave *VAR unchanged, and return null. */
+
+static POINTER_TYPE *
+mmap_realloc (var, nbytes)
+ POINTER_TYPE **var;
+ size_t nbytes;
+{
+ POINTER_TYPE *result;
+
+ mmap_init ();
+
+ if (*var == NULL)
+ result = mmap_alloc (var, nbytes);
+ else if (nbytes == 0)
+ {
+ mmap_free (var);
+ result = mmap_alloc (var, nbytes);
+ }
+ else
+ {
+ struct mmap_region *r = MMAP_REGION (*var);
+ size_t room = r->nbytes_mapped - MMAP_REGION_STRUCT_SIZE;
+
+ if (room < nbytes)
+ {
+ /* Must enlarge. */
+ POINTER_TYPE *old_ptr = *var;
+
+ /* Try to map additional pages at the end of the region.
+ If that fails, allocate a new region, copy data
+ from the old region, then free it. */
+ if (mmap_enlarge (r, (ROUND (nbytes - room, mmap_page_size)
+ / mmap_page_size)))
+ {
+ r->nbytes_specified = nbytes;
+ *var = result = old_ptr;
+ }
+ else if (mmap_alloc (var, nbytes))
+ {
+ bcopy (old_ptr, *var, r->nbytes_specified);
+ mmap_free_1 (MMAP_REGION (old_ptr));
+ result = *var;
+ r = MMAP_REGION (result);
+ r->nbytes_specified = nbytes;
+ }
+ else
+ {
+ *var = old_ptr;
+ result = NULL;
+ }
+ }
+ else if (room - nbytes >= mmap_page_size)
+ {
+ /* Shrinking by at least a page. Let's give some
+ memory back to the system. */
+ mmap_enlarge (r, - (room - nbytes) / mmap_page_size);
+ result = *var;
+ r->nbytes_specified = nbytes;
+ }
+ else
+ {
+ /* Leave it alone. */
+ result = *var;
+ r->nbytes_specified = nbytes;
+ }
+ }
+
+ return result;
+}
+
+
+/* Free a block of relocatable storage whose data is pointed to by
+ PTR. Store 0 in *PTR to show there's no block allocated. */
+
+static void
+mmap_free (var)
+ POINTER_TYPE **var;
+{
+ mmap_init ();
+
+ if (*var)
+ {
+ mmap_free_1 (MMAP_REGION (*var));
+ *var = NULL;
+ }
+}
+
+
+/* Perform necessary intializations for the use of mmap. */
+
+static void
+mmap_init ()
+{
+#if MAP_ANON == 0
+ /* The value of mmap_fd is initially 0 in temacs, and -1
+ in a dumped Emacs. */
+ if (mmap_fd <= 0)
+ {
+ /* No anonymous mmap -- we need the file descriptor. */
+ mmap_fd = open ("/dev/zero", O_RDONLY);
+ if (mmap_fd == -1)
+ fatal ("Cannot open /dev/zero: %s", emacs_strerror (errno));
+ }
+#endif /* MAP_ANON == 0 */
+
+ if (mmap_initialized_p)
+ return;
+ mmap_initialized_p = 1;
+
+#if MAP_ANON != 0
+ mmap_fd = -1;
+#endif
+
+ mmap_page_size = getpagesize ();
+}
+
+#endif /* USE_MMAP_FOR_BUFFERS */
+
+
\f
+/***********************************************************************
+ Buffer-text Allocation
+ ***********************************************************************/
+
+#ifdef REL_ALLOC
+extern POINTER_TYPE *r_alloc P_ ((POINTER_TYPE **, size_t));
+extern POINTER_TYPE *r_re_alloc P_ ((POINTER_TYPE **, size_t));
+extern void r_alloc_free P_ ((POINTER_TYPE **ptr));
+#endif /* REL_ALLOC */
+
+
+/* Allocate NBYTES bytes for buffer B's text buffer. */
+
+static void
+alloc_buffer_text (b, nbytes)
+ struct buffer *b;
+ size_t nbytes;
+{
+ POINTER_TYPE *p;
+
+ BLOCK_INPUT;
+#if defined USE_MMAP_FOR_BUFFERS
+ p = mmap_alloc ((POINTER_TYPE **) &b->text->beg, nbytes);
+#elif defined REL_ALLOC
+ p = r_alloc ((POINTER_TYPE **) &b->text->beg, nbytes);
+#else
+ p = xmalloc (nbytes);
+#endif
+
+ if (p == NULL)
+ {
+ UNBLOCK_INPUT;
+ memory_full ();
+ }
+
+ b->text->beg = (unsigned char *) p;
+ UNBLOCK_INPUT;
+}
+
+/* Enlarge buffer B's text buffer by DELTA bytes. DELTA < 0 means
+ shrink it. */
+
+void
+enlarge_buffer_text (b, delta)
+ struct buffer *b;
+ int delta;
+{
+ POINTER_TYPE *p;
+ size_t nbytes = (BUF_Z_BYTE (b) - BUF_BEG_BYTE (b) + BUF_GAP_SIZE (b) + 1
+ + delta);
+ BLOCK_INPUT;
+#if defined USE_MMAP_FOR_BUFFERS
+ p = mmap_realloc ((POINTER_TYPE **) &b->text->beg, nbytes);
+#elif defined REL_ALLOC
+ p = r_re_alloc ((POINTER_TYPE **) &b->text->beg, nbytes);
+#else
+ p = xrealloc (b->text->beg, nbytes);
+#endif
+
+ if (p == NULL)
+ {
+ UNBLOCK_INPUT;
+ memory_full ();
+ }
+
+ BUF_BEG_ADDR (b) = (unsigned char *) p;
+ UNBLOCK_INPUT;
+}
+
+
+/* Free buffer B's text buffer. */
+
+static void
+free_buffer_text (b)
+ struct buffer *b;
+{
+ BLOCK_INPUT;
+
+#if defined USE_MMAP_FOR_BUFFERS
+ mmap_free ((POINTER_TYPE **) &b->text->beg);
+#elif defined REL_ALLOC
+ r_alloc_free ((POINTER_TYPE **) &b->text->beg);
+#else
+ xfree (b->text->beg);
+#endif
+
+ BUF_BEG_ADDR (b) = NULL;
+ UNBLOCK_INPUT;
+}
+
+
+\f
+/***********************************************************************
+ Initialization
+ ***********************************************************************/
+
void
init_buffer_once ()
{
- buffer_permanent_local_flags = 0;
+ int idx;
+
+ bzero (buffer_permanent_local_flags, sizeof buffer_permanent_local_flags);
/* Make sure all markable slots in buffer_defaults
are initialized reasonably, so mark_buffer won't choke. */
/* Set up the default values of various buffer slots. */
/* Must do these before making the first buffer! */
- /* real setup is done in loaddefs.el */
+ /* real setup is done in bindings.el */
buffer_defaults.mode_line_format = build_string ("%-");
buffer_defaults.header_line_format = Qnil;
buffer_defaults.abbrev_mode = Qnil;
buffer_defaults.truncate_lines = Qnil;
buffer_defaults.ctl_arrow = Qt;
buffer_defaults.direction_reversed = Qnil;
+ buffer_defaults.cursor_type = Qt;
+ buffer_defaults.extra_line_spacing = Qnil;
#ifdef DOS_NT
buffer_defaults.buffer_file_type = Qnil; /* TEXT */
XSETINT (buffer_local_flags.display_time, -1);
XSETINT (buffer_local_flags.enable_multibyte_characters, -1);
- XSETFASTINT (buffer_local_flags.mode_line_format, 1);
- XSETFASTINT (buffer_local_flags.abbrev_mode, 2);
- XSETFASTINT (buffer_local_flags.overwrite_mode, 4);
- XSETFASTINT (buffer_local_flags.case_fold_search, 8);
- XSETFASTINT (buffer_local_flags.auto_fill_function, 0x10);
- XSETFASTINT (buffer_local_flags.selective_display, 0x20);
+ idx = 1;
+ XSETFASTINT (buffer_local_flags.mode_line_format, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.abbrev_mode, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.overwrite_mode, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.case_fold_search, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.auto_fill_function, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.selective_display, idx); ++idx;
#ifndef old
- XSETFASTINT (buffer_local_flags.selective_display_ellipses, 0x40);
+ XSETFASTINT (buffer_local_flags.selective_display_ellipses, idx); ++idx;
#endif
- XSETFASTINT (buffer_local_flags.tab_width, 0x80);
- XSETFASTINT (buffer_local_flags.truncate_lines, 0x100);
- XSETFASTINT (buffer_local_flags.ctl_arrow, 0x200);
- XSETFASTINT (buffer_local_flags.fill_column, 0x400);
- XSETFASTINT (buffer_local_flags.left_margin, 0x800);
- XSETFASTINT (buffer_local_flags.abbrev_table, 0x1000);
- XSETFASTINT (buffer_local_flags.display_table, 0x2000);
+ XSETFASTINT (buffer_local_flags.tab_width, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.truncate_lines, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.ctl_arrow, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.fill_column, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.left_margin, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.abbrev_table, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.display_table, idx); ++idx;
#ifdef DOS_NT
- XSETFASTINT (buffer_local_flags.buffer_file_type, 0x4000);
+ XSETFASTINT (buffer_local_flags.buffer_file_type, idx);
/* Make this one a permanent local. */
- buffer_permanent_local_flags |= 0x4000;
+ buffer_permanent_local_flags[idx++] = 1;
#endif
- XSETFASTINT (buffer_local_flags.syntax_table, 0x8000);
- XSETFASTINT (buffer_local_flags.cache_long_line_scans, 0x10000);
- XSETFASTINT (buffer_local_flags.category_table, 0x20000);
- XSETFASTINT (buffer_local_flags.direction_reversed, 0x40000);
- XSETFASTINT (buffer_local_flags.buffer_file_coding_system, 0x80000);
+ XSETFASTINT (buffer_local_flags.syntax_table, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.cache_long_line_scans, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.category_table, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.direction_reversed, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.buffer_file_coding_system, idx);
/* Make this one a permanent local. */
- buffer_permanent_local_flags |= 0x80000;
- XSETFASTINT (buffer_local_flags.left_margin_width, 0x100000);
- XSETFASTINT (buffer_local_flags.right_margin_width, 0x200000);
- XSETFASTINT (buffer_local_flags.indicate_empty_lines, 0x400000);
- XSETFASTINT (buffer_local_flags.scroll_up_aggressively, 0x800000);
- XSETFASTINT (buffer_local_flags.scroll_down_aggressively, 0x1000000);
- XSETFASTINT (buffer_local_flags.header_line_format, 0x2000000);
+ buffer_permanent_local_flags[idx++] = 1;
+ XSETFASTINT (buffer_local_flags.left_margin_width, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.right_margin_width, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.indicate_empty_lines, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.scroll_up_aggressively, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.scroll_down_aggressively, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.header_line_format, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.cursor_type, idx); ++idx;
+ XSETFASTINT (buffer_local_flags.extra_line_spacing, idx); ++idx;
+
+ /* Need more room? */
+ if (idx >= MAX_PER_BUFFER_VARS)
+ abort ();
+ last_per_buffer_idx = idx;
Vbuffer_alist = Qnil;
current_buffer = 0;
void
init_buffer ()
{
- char buf[MAXPATHLEN+1];
+ char buf[MAXPATHLEN + 1];
char *pwd;
struct stat dotstat, pwdstat;
Lisp_Object temp;
int rc;
+#ifdef USE_MMAP_FOR_BUFFERS
+ {
+ /* When using the ralloc implementation based on mmap(2), buffer
+ text pointers will have been set to null in the dumped Emacs.
+ Map new memory. */
+ struct buffer *b;
+
+ for (b = all_buffers; b; b = b->next)
+ if (b->text->beg == NULL)
+ enlarge_buffer_text (b, 0);
+ }
+#endif /* USE_MMAP_FOR_BUFFERS */
+
Fset_buffer (Fget_buffer_create (build_string ("*scratch*")));
if (NILP (buffer_defaults.enable_multibyte_characters))
Fset_buffer_multibyte (Qnil);
"Default value of `header-line-format' for buffers that don't override it.\n\
This is the same as (default-value 'header-line-format).");
+ DEFVAR_LISP_NOPRO ("default-cursor-type", &buffer_defaults.cursor_type,
+ "Default value of `cursor-type' for buffers that don't override it.\n\
+This is the same as (default-value 'cursor-type).");
+
+ DEFVAR_LISP_NOPRO ("default-line-spacing",
+ &buffer_defaults.extra_line_spacing,
+ "Default value of `line-spacing' for buffers that don't override it.\n\
+This is the same as (default-value 'line-spacing).");
+
DEFVAR_LISP_NOPRO ("default-abbrev-mode",
&buffer_defaults.abbrev_mode,
"Default value of `abbrev-mode' for buffers that do not override it.\n\
DEFVAR_PER_BUFFER ("auto-fill-function", ¤t_buffer->auto_fill_function,
Qnil,
"Function called (if non-nil) to perform auto-fill.\n\
-It is called after self-inserting a space or newline.\n\
+It is called after self-inserting any character specified in\n\
+the `auto-fill-chars' table.\n\
Each buffer has its own value of this variable.\n\
NOTE: This variable is not a hook;\n\
its value may not be a list of functions.");
"*If a number, scroll display up aggressively.\n\
If scrolling a window because point is above the window start, choose\n\
a new window start so that point ends up that fraction of the window's\n\
-height from the bottom of the window.\n\
+height from the top of the window.\n\
Automatically becomes buffer-local when set in any fashion.");
DEFVAR_PER_BUFFER ("scroll-down-aggressively",
"*If a number, scroll display down aggressively.\n\
If scrolling a window because point is below the window end, choose\n\
a new window start so that point ends up that fraction of the window's\n\
-height from the top of the window.\n\
+height from the bottom of the window.\n\
Automatically becomes buffer-local when set in any fashion.");
/*DEFVAR_LISP ("debug-check-symbol", &Vcheck_symbol,
"Don't ask.");
*/
- DEFVAR_LISP ("before-change-function", &Vbefore_change_function,
- "If non-nil, a function to call before each text change (obsolete).\n\
-Two arguments are passed to the function: the positions of\n\
-the beginning and end of the range of old text to be changed.\n\
-\(For an insertion, the beginning and end are at the same place.)\n\
-No information is given about the length of the text after the change.\n\
-\n\
-Buffer changes made while executing the `before-change-function'\n\
-don't call any before-change or after-change functions.\n\
-That's because these variables are temporarily set to nil.\n\
-As a result, a hook function cannot straightforwardly alter the value of\n\
-these variables. See the Emacs Lisp manual for a way of\n\
-accomplishing an equivalent result by using other variables.\n\n\
-This variable is obsolete; use `before-change-functions' instead.");
- Vbefore_change_function = Qnil;
-
- DEFVAR_LISP ("after-change-function", &Vafter_change_function,
- "If non-nil, a Function to call after each text change (obsolete).\n\
-Three arguments are passed to the function: the positions of\n\
-the beginning and end of the range of changed text,\n\
-and the length of the pre-change text replaced by that range.\n\
-\(For an insertion, the pre-change length is zero;\n\
-for a deletion, that length is the number of bytes deleted,\n\
-and the post-change beginning and end are at the same place.)\n\
-\n\
-Buffer changes made while executing the `after-change-function'\n\
-don't call any before-change or after-change functions.\n\
-That's because these variables are temporarily set to nil.\n\
-As a result, a hook function cannot straightforwardly alter the value of\n\
-these variables. See the Emacs Lisp manual for a way of\n\
-accomplishing an equivalent result by using other variables.\n\n\
-This variable is obsolete; use `after-change-functions' instead.");
- Vafter_change_function = Qnil;
DEFVAR_LISP ("before-change-functions", &Vbefore_change_functions,
"List of functions to call before each text change.\n\
is a member of the list.");
Vinhibit_read_only = Qnil;
+ DEFVAR_PER_BUFFER ("cursor-type", ¤t_buffer->cursor_type, Qnil,
+ "Cursor to use in window displaying this buffer.\n\
+Values are interpreted as follows:\n\
+\n\
+ t use the cursor specified for the frame\n\
+ nil don't display a cursor\n\
+ `bar' display a bar cursor with default width\n\
+ (bar . WIDTH) display a bar cursor with width WIDTH\n\
+ others display a box cursor.");
+
+ DEFVAR_PER_BUFFER ("line-spacing",
+ ¤t_buffer->extra_line_spacing, Qnil,
+ "Additional space to put between lines when displaying a buffer.\n\
+The space is measured in pixels, and put below lines on window systems.");
+
DEFVAR_LISP ("kill-buffer-query-functions", &Vkill_buffer_query_functions,
"List of functions called with no args to query before killing a buffer.");
Vkill_buffer_query_functions = Qnil;
defsubr (&Soverlay_lists);
defsubr (&Soverlay_get);
defsubr (&Soverlay_put);
+ defsubr (&Srestore_buffer_modified_p);
}
void