/* Header file for the buffer manipulation primitives.
   Copyright (C) 1985, 1986, 1992, 1993, 1994 Free Software Foundation, Inc.
   Copyright (C) 1994, 1995 Amdahl Corporation.

This file is part of XEmacs.

XEmacs 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.

XEmacs is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with XEmacs; see the file COPYING.  If not, write to the Free
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

/* Synched up with: FSF 19.28. */

/* Substantially cleaned up and modified by Ben Wing. */

#ifndef _XEMACS_BUFFER_H_
#define _XEMACS_BUFFER_H_

/*----------------------------------------------------------------------*/
/*         Converting between buffer positions and byte indices         */
/*----------------------------------------------------------------------*/

/********** Low-level functions **********/

/* Use these on contiguous strings of data.  If the text you're
   operating on is known to come from a buffer, use the buffer-level
   functions below -- they know about the gap and may be more
   efficient. */

/* VALID_CHARPTR_P(): Given a pointer to text, does it point to
   the beginning of a character? */

#ifdef MULE
# define VALID_CHARPTR_P(ptr) MULE_FIRST_BYTE_P (*ptr)
#else
# define VALID_CHARPTR_P(ptr) 1
#endif

/* ASSERT_VALID_CHARPTR(): If error-checking is enabled, verify
   that the given pointer to text points to the beginning of a
   character. */

#ifdef ERROR_CHECK_BUFPOS
# define ASSERT_VALID_CHARPTR(ptr) assert (VALID_CHARPTR_P (ptr))
#else
# define ASSERT_VALID_CHARPTR(ptr)
#endif

/* INC_CHARPTR(): Given a pointer to text (assumed to point at the
   beginning of a character), modify that pointer so it points to
   the beginning of the next character. */

#define INC_CHARPTR_1(ptr) do			\
{						\
  ptr++;					\
} while (!VALID_CHARPTR_P (*ptr))

#define INC_CHARPTR(ptr) do			\
{						\
  ASSERT_VALID_CHARPTR (ptr);			\
  INC_CHARPTR_1 (ptr);				\
} while (0)

/* DEC_CHARPTR(): Given a pointer to text (assumed to point at the
   beginning of a character), modify that pointer so it points to
   the beginning of the previous character.  We can't do the
   assert() above because we might not be pointing to valid memory --
   we might be just off the end. */

#define DEC_CHARPTR_1(ptr) do			\
{						\
  ptr--;					\
} while (!VALID_CHARPTR_P (*ptr))

#define DEC_CHARPTR(ptr) do			\
{						\
  ASSERT_VALID_CHARPTR (ptr);			\
  DEC_CHARPTR_1 (ptr);				\
} while (0)

/* VALIDATE_CHARPTR_BACKWARD(): Make sure that PTR is pointing to the
   beginning of a character.  If not, back up until this is the case.
   Note that there are not too many places where it is legitimate to
   do this sort of thing.  It's an error if you're passed an "invalid"
   char * pointer. */

# define VALIDATE_CHARPTR_BACKWARD(ptr) do	\
{						\
  while (!VALID_CHARPTR_P (*ptr)) ptr--;	\
} while (0)

/* VALIDATE_CHARPTR_FORWARD(): Make sure that PTR is pointing to the
   beginning of a character.  If not, move forward until this is the
   case.  Note that there are not too many places where it is
   legitimate to do this sort of thing.  It's an error if you're
   passed an "invalid" char * pointer. */

# define VALIDATE_CHARPTR_FORWARD(ptr) do	\
{						\
  while (!VALID_CHARPTR_P (*ptr)) ptr++;	\
} while (0)

#ifdef MULE

#include "mule.h"

/* bytecount_to_charcount(): Given a pointer to a text string and a
   length in bytes, return the equivalent length in characters. */

extern Charcount bytecount_to_charcount (unsigned char *ptr, Bytecount len);

/* charcount_to_bytecount(): Given a pointer to a text string and a
   length in characters, return the equivalent length in bytes. */

extern Bytecount charcount_to_bytecount (unsigned char *ptr, Charcount len);

/* valid_char_p(): Return whether the given Emchar is valid. */

extern int valid_char_p (Emchar ch);

#else /* not MULE */

# define bytecount_to_charcount(ptr, len) (len)
# define charcount_to_bytecount(ptr, len) (len)
# define valid_char_p(ch)		((ch) >= 0 && (ch) < 0400)

#endif /* MULE */

MAC_DECLARE_EXTERN (CONST Bufbyte *, mactemp_charptr)

/* charptr_addr(): Given a pointer to Emacs characters and an offset in
   characters, return a pointer to the beginning of the character
   referenced by the offset. */

#define charptr_addr(ptr, offset)					\
MAC_BEGIN								\
  MAC_DECLARE (CONST Bufbyte *, mactemp_charptr, ptr)			\
  mactemp_charptr + charcount_to_bytecount (mactemp_charptr, offset)	\
MAC_END  

/* charptr_length(): Given a zero-terminated pointer to Emacs characters,
   return the number of Emacs characters contained within. */

#define charptr_length(ptr)						      \
MAC_BEGIN								      \
  MAC_DECLARE (CONST Bufbyte *, mactemp_charptr, ptr)			      \
  bytecount_to_charcount (mactemp_charptr, strlen ((char *) mactemp_charptr)) \
MAC_END

/* charptr_char(): Given a pointer to Emacs characters and an offset in
   characters, return the Emacs character referenced by the offset. */

#define charptr_char(ptr, offset) \
  charptr_to_emchar (charptr_addr (ptr, offset))

/********** Buffer-level functions **********/

/* VALID_BYTIND_P(): Given a byte index, does it point to
   the beginning of a character? */

#ifdef MULE
# define VALID_BYTIND_P(buf, x) \
  MULE_FIRST_BYTE_P (*BI_BUF_BYTE_ADDRESS (buf, x))
#else
# define VALID_BYTIND_P(buf, x) 1
#endif

/* ASSERT_VALID_BYTIND(): If error-checking is enabled, verify
   that the given byte index is within range and points to the
   beginning of a character. */

#ifdef ERROR_CHECK_BUFPOS
# define ASSERT_VALID_BYTIND(buf, x) do				\
{								\
  assert (BUFFER_LIVE_P (buf));					\
  assert ((x) >= BI_BUF_BEG (buf) && x <= BI_BUF_Z (buf));	\
  assert (VALID_BYTIND_P (buf, x));				\
} while (0)
# define ASSERT_VALID_BYTIND_FORWARD(buf, x) do			\
{								\
  assert (BUFFER_LIVE_P (buf));					\
  assert ((x) >= BI_BUF_BEG (buf) && x < BI_BUF_Z (buf));	\
  assert (VALID_BYTIND_P (buf, x));				\
} while (0)
# define ASSERT_VALID_BYTIND_BACKWARD(buf, x) do		\
{								\
  assert (BUFFER_LIVE_P (buf));					\
  assert ((x) > BI_BUF_BEG (buf) && x <= BI_BUF_Z (buf));	\
  assert (VALID_BYTIND_P (buf, x));				\
} while (0)
#else
# define ASSERT_VALID_BYTIND(buf, x)
# define ASSERT_VALID_BYTIND_FORWARD(buf, x)
# define ASSERT_VALID_BYTIND_BACKWARD(buf, x)
#endif

/* VALIDATE_BYTIND_BACKWARD(): Make sure that the given byte index is
   pointing to the beginning of a character.  If not, back up until
   this is the case.  Note that there are not too many places where it
   is legitimate to do this sort of thing.  It's an error if you're
   passed an "invalid" byte index. */

/* #### these should add some error-checking and encapsulate the
   args against multiple evaluation. */

#define VALIDATE_BYTIND_BACKWARD(buf, x) \
  VALIDATE_BYTIND_BACKWARD_1 (buf, x)
#define VALIDATE_BYTIND_FORWARD(buf, x) \
  VALIDATE_BYTIND_FORWARD_1 (buf, x)

/* Note that, although the Mule version will work fine for non-Mule
   as well (it should reduce down to nothing), we provide a separate
   version to avoid compilation warnings and possible non-optimal
   results with stupid compilers. */

/* Note also that this may evaluate the lvalue (x) more than once. */

#ifdef MULE
# define VALIDATE_BYTIND_BACKWARD_1(buf, x) do		\
{							\
  Bufbyte *__ibptr = BI_BUF_BYTE_ADDRESS (buf, x);	\
  while (!VALID_BYTIND_P (*__ibptr))			\
    __ibptr--, (x)--;					\
} while (0)
#else
# define VALIDATE_BYTIND_BACKWARD_1(buf, x)
#endif

/* VALIDATE_BYTIND_FORWARD(): Make sure that the given byte index is
   pointing to the beginning of a character.  If not, move forward
   until this is the case.  Note that there are not too many places
   where it is legitimate to do this sort of thing.  It's an error if
   you're passed an "invalid" byte index. */

/* Note that, although the Mule version will work fine for non-Mule
   as well (it should reduce down to nothing), we provide a separate
   version to avoid compilation warnings and possible non-optimal
   results with stupid compilers. */

/* Note also that this may evaluate the lvalue (x) more than once. */

#ifdef MULE
# define VALIDATE_BYTIND_FORWARD_1(buf, x) do		\
{							\
  Bufbyte *__ibptr = BI_BUF_BYTE_ADDRESS (buf, x);	\
  while (!VALID_BYTIND_P (*__ibptr))			\
    __ibptr++, (x)++;					\
} while (0)
#else
# define VALIDATE_BYTIND_FORWARD_1(buf, x)
#endif

/* INC_BYTIND(): Given a byte index (assumed to point at the beginning
   of a character), modify that value so it points to the beginning
   of the next character. */

/* Note that in the simplest case (no MULE, no ERROR_CHECK_BUFPOS),
   this crap reduces down to simply (x)++. */

#define INC_BYTIND_1(buf, x) do				\
{							\
  /* Note that we do the increment first to		\
     make sure that the pointer in			\
     VALIDATE_BYTIND_FORWARD_1() ends up on		\
     the correct side of the gap */			\
  (x)++;						\
  VALIDATE_BYTIND_FORWARD_1 (buf, x);			\
} while (0)

#define INC_BYTIND(buf, x) do				\
{							\
  struct buffer *__ibbuf = (buf);			\
  Bytind *__ibx = &(x);					\
  ASSERT_VALID_BYTIND_FORWARD (__ibbuf, *__ibx);	\
  INC_BYTIND_1 (__ibbuf, *__ibx);			\
} while (0)

/* DEC_BYTIND(): Given a byte index (assumed to point at the
   beginning of a character), modify that value so it points to
   the beginning of the previous character.  Unlike for DEC_CHARPTR(),
   we can do all the assert()s because there are sentinels at the
   beginning of the gap and the end of the buffer. */

/* Note that in the simplest case (no MULE, no ERROR_CHECK_BUFPOS),
   this crap reduces down to simply (x)--. */

#define DEC_BYTIND_1(buf, x) do				\
{							\
  /* Note that we do the decrement first to		\
     make sure that the pointer in			\
     VALIDATE_BYTIND_FORWARD_1() ends up on		\
     the correct side of the gap */			\
  (x)--;						\
  VALIDATE_BYTIND_BACKWARD_1 (buf, x);			\
} while (0)

#define DEC_BYTIND(buf, x) do				\
{							\
  struct buffer *__ibbuf = (buf);			\
  Bytind *__ibx = &(x);					\
  ASSERT_VALID_BYTIND_BACKWARD (__ibbuf, *__ibx);	\
  DEC_BYTIND_1 (__ibbuf, *__ibx);			\
} while (0)

#if defined (MULE) || defined (ERROR_CHECK_BUFPOS)

extern Bytind bufpos_to_bytind (struct buffer *buf, Bufpos x);
extern Bufpos bytind_to_bufpos (struct buffer *buf, Bytind x);
extern Charcount buf_bytecount_to_charcount (struct buffer *buf,
					     Bytind x,
					     Bytecount len);
extern Bytecount buf_charcount_to_bytecount (struct buffer *buf,
					     Bytind x,
					     Charcount len);

#else

# define bufpos_to_bytind(buf, x)	((Bytind) x)
# define bytind_to_bufpos(buf, x)	((Bufpos) x)
# define buf_bytecount_to_charcount(buf, x, len) (len)
# define buf_charcount_to_bytecount(buf, x, len) (len)

#endif /* not MULE and not ERROR_CHECK_BUFPOS */


/* Maximum number of buffer bytes per Emacs character */
#ifdef MULE
# define MAX_EMCHAR_LEN 4
#else
# define MAX_EMCHAR_LEN 1
#endif

/* flags for get_bufpos() and get_bufrange(). */
/* at most one of GB_COERCE_RANGE and GB_NO_ERROR_IF_BAD should be
   specified. */

#define GB_ALLOW_PAST_ACCESSIBLE	(1 << 0)
#define GB_ALLOW_NIL			(1 << 1)
#define GB_CHECK_ORDER			(1 << 2)
#define GB_COERCE_RANGE			(1 << 3)
#define GB_NO_ERROR_IF_BAD		(1 << 4)

#define BYTIND_INVALID ((Bytind) -1)

/* Some convenience macros for working with buffer positions
   and byte indices. */

#define make_bufpos(buf, ind) make_number (bytind_to_bufpos (buf, ind))

#define c_charptr_from_external_static(ptr, bin) \
  ((char *) charptr_from_external_static (ptr, -1, 0, bin))
#define c_charptr_to_external_static(ptr, bin) \
  charptr_to_external_static ((Bufbyte *) ptr, -1, 0, bin)

#define c_charptr_from_external(ptr) c_charptr_from_external_static (ptr, 0)
#define c_charptr_from_external2(ptr) c_charptr_from_external_static (ptr, 1)
#define c_charptr_from_external3(ptr) c_charptr_from_external_static (ptr, 2)
#define c_charptr_from_external4(ptr) c_charptr_from_external_static (ptr, 3)
#define c_charptr_from_external5(ptr) c_charptr_from_external_static (ptr, 4)

#define c_charptr_to_external(ptr) c_charptr_to_external_static (ptr, 0)
#define c_charptr_to_external2(ptr) c_charptr_to_external_static (ptr, 1)
#define c_charptr_to_external3(ptr) c_charptr_to_external_static (ptr, 2)
#define c_charptr_to_external4(ptr) c_charptr_to_external_static (ptr, 3)
#define c_charptr_to_external5(ptr) c_charptr_to_external_static (ptr, 4)

#define charptr_from_external(ptr, len, len_out) \
  charptr_from_external_static (ptr, len, len_out, 0)
#define charptr_from_external2(ptr, len, len_out) \
  charptr_from_external_static (ptr, len, len_out, 1)
#define charptr_from_external3(ptr, len, len_out) \
  charptr_from_external_static (ptr, len, len_out, 2)
#define charptr_from_external4(ptr, len, len_out) \
  charptr_from_external_static (ptr, len, len_out, 3)
#define charptr_from_external5(ptr, len, len_out) \
  charptr_from_external_static (ptr, len, len_out, 4)

#define charptr_to_external(ptr, len, len_out) \
  charptr_to_external_static (ptr, len, len_out, 0)
#define charptr_to_external2(ptr, len, len_out) \
  charptr_to_external_static (ptr, len, len_out, 1)
#define charptr_to_external3(ptr, len, len_out) \
  charptr_to_external_static (ptr, len, len_out, 2)
#define charptr_to_external4(ptr, len, len_out) \
  charptr_to_external_static (ptr, len, len_out, 3)
#define charptr_to_external5(ptr, len, len_out) \
  charptr_to_external_static (ptr, len, len_out, 4)

/*----------------------------------------------------------------------*/
/*              Converting between positions and addresses              */
/*----------------------------------------------------------------------*/

/* Convert the address of a byte in the buffer into a position.  */
#define BI_BUF_PTR_BYTE_POS(buf, ptr)			\
((ptr) - (buf)->text.beg + 1				\
 - ((ptr - (buf)->text.beg + 1) > (buf)->text.gpt	\
    ? (buf)->text.gap_size : 0))
#define BUF_PTR_BYTE_POS(buf, ptr) \
  bytind_to_bufpos (buf, BI_BUF_PTR_BYTE_POS (buf, ptr))

/* Address of byte at position POS in buffer. */
#define BI_BUF_BYTE_ADDRESS(buf, pos)			\
((buf)->text.beg + (((pos) >= (buf)->text.gpt ?		\
 ((pos) + (buf)->text.gap_size) : (pos)) - 1))
#define BUF_BYTE_ADDRESS(buf, pos) \
  BI_BUF_BYTE_ADDRESS (buf, bufpos_to_bytind (buf, pos))

/* Address of byte before position POS in buffer. */
#define BI_BUF_BYTE_ADDRESS_BEFORE(buf, pos)		\
((buf)->text.beg + (((pos) > (buf)->text.gpt ?		\
 ((pos) + (buf)->text.gap_size) : (pos)) - 2))
#define BUF_BYTE_ADDRESS_BEFORE(buf, pos) \
  BI_BUF_BYTE_ADDRESS_BEFORE (buf, bufpos_to_bytind (buf, pos))

/*----------------------------------------------------------------------*/
/*          Converting between byte indices and memory indices          */
/*----------------------------------------------------------------------*/

#define valid_memind_p(buf, x)						\
  (((x) >= 1 && (x) <= (Memind) (buf)->text.gpt) ||			\
   ((x) > (Memind) ((buf)->text.gpt + (buf)->text.gap_size) &&		\
   (x) <= (Memind) ((buf)->text.z + (buf)->text.gap_size)))
#define bytind_to_memind(buf, x)					\
  ((Memind) ((x) > (buf)->text.gpt ? ((x) + (buf)->text.gap_size) : (x)))
#ifdef ERROR_CHECK_BUFPOS
# define memind_to_bytind(buf, x)					\
  (assert (valid_memind_p (buf, x)),					\
   ((Bytind) ((x) > (Memind) (buf)->text.gpt ?				\
	      ((x) - (buf)->text.gap_size) : (x))))
#else
# define memind_to_bytind(buf, x)					\
  ((Bytind) ((x) > (Memind) (buf)->text.gpt ?				\
	     ((x) - (buf)->text.gap_size) : (x)))
#endif
#define memind_to_bufpos(buf, x)					\
  bytind_to_bufpos (buf, memind_to_bytind (buf, x))
#define bufpos_to_memind(buf, x)					\
  bytind_to_memind (buf, bufpos_to_bytind (buf, x))



/*----------------------------------------------------------------------*/
/*         Converting between buffer bytes and Emacs characters         */
/*----------------------------------------------------------------------*/

# define simple_charptr_to_emchar(str)		((Emchar) (str)[0])
# define simple_emchar_to_charptr(x, str)	((str)[0] = (Bufbyte) (x), 1)

#ifdef MULE
extern Bytecount non_ascii_emchar_to_charptr (Emchar c, Bufbyte *str);
extern Emchar non_ascii_charptr_to_emchar (Bufbyte *str);
# define charptr_to_emchar(str)					\
  (BUFBYTE_ASCII_P (*(str)) ? simple_charptr_to_emchar (str) :	\
   non_ascii_charptr_to_emchar (str))
# define emchar_to_charptr(x, str)				\
  (BUFBYTE_ASCII_P (x) ? simple_emchar_to_charptr (x, str) :	\
   non_ascii_emchar_to_charptr (x, str))
#else
# define charptr_to_emchar(str)		simple_charptr_to_emchar (str)
# define emchar_to_charptr(x, str)	simple_emchar_to_charptr (x, str)
#endif /* MULE */

/* The character at position POS in buffer. */
#define BI_BUF_FETCH_CHAR(buf, pos) \
  charptr_to_emchar (BI_BUF_BYTE_ADDRESS (buf, pos))
#define BUF_FETCH_CHAR(buf, pos) \
  BI_BUF_FETCH_CHAR (buf, bufpos_to_bytind (buf, pos))

/* The character at position POS in buffer, as a string.  This is
   equivalent to emchar_to_charptr (BUF_FETCH_CHAR (buf, pos), str)
   but is faster for Mule. */
#ifdef MULE
# define BI_BUF_FETCH_CHAR_AS_STR(buf, pos, str) ---- no Mule support yet ----
#else
# define BI_BUF_FETCH_CHAR_AS_STR(buf, pos, str) \
  ((str)[0] = (*BI_BUF_BYTE_ADDRESS (buf, pos)), 1)
#endif /* MULE */
#define BUF_FETCH_CHAR_AS_STR(buf, pos, str) \
  BI_BUF_FETCH_CHAR_AS_STR (buf, bufpos_to_bytind (buf, pos), str)


/*----------------------------------------------------------------------*/
/*          Accessor macros for important positions in a buffer         */
/*----------------------------------------------------------------------*/

/* None of these are lvalues.  Use the settor macros below to change
   the positions. */

/* Beginning of buffer.  */ 
#define BI_BUF_BEG(buf) ((Bytind) 1)
#define BUF_BEG(buf) bytind_to_bufpos (buf, BI_BUF_BEG (buf))

/* Beginning of accessible range of buffer.  */ 
#define BI_BUF_BEGV(buf) ((buf)->text.begv + 0)
#define BUF_BEGV(buf) bytind_to_bufpos (buf, BI_BUF_BEGV (buf))

/* End of accessible range of buffer.  */ 
#define BI_BUF_ZV(buf) ((buf)->text.zv + 0)
#define BUF_ZV(buf) bytind_to_bufpos (buf, BI_BUF_ZV (buf))

/* End of buffer.  */ 
#define BI_BUF_Z(buf) ((buf)->text.z + 0)
#define BUF_Z(buf) bytind_to_bufpos (buf, BI_BUF_Z (buf))

/* Point. */
#define BI_BUF_PT(buf) ((buf)->text.pt + 0)
#define BUF_PT(buf) bytind_to_bufpos (buf, BI_BUF_PT (buf))

/*----------------------------------------------------------------------*/
/*           Settor macros for important positions in a buffer          */
/*----------------------------------------------------------------------*/

/* Set beginning of accessible range of buffer.  */ 
#define SET_BI_BUF_BEGV(buf, value) \
  do { (buf)->text.begv = (value); } while (0)
#define SET_BUF_BEGV(buf, value) \
  SET_BI_BUF_BEGV (buf, bytind_to_bufpos (buf, value))

/* Set end of accessible range of buffer.  */ 
#define SET_BI_BUF_ZV(buf, value) do { (buf)->text.zv = (value); } while (0)
#define SET_BUF_ZV(buf, value) \
  SET_BI_BUF_ZV (buf, bytind_to_bufpos (buf, value))

/* Set point. */
#define BI_BUF_SET_PT(buf, value) set_buffer_point (buf, value)
#define BUF_SET_PT(buf, value) \
  BI_BUF_SET_PT (buf, bufpos_to_bytind (buf, value))


#if 0 /* FSFmacs */
/* These macros exist in FSFmacs because SET_PT() in FSFmacs incorrectly
   does too much stuff, such as moving out of invisible extents. */
#define TEMP_SET_PT(position) (temp_set_point ((position), current_buffer))
#define SET_BUF_PT(buf, value) ((buf)->text.pt = (value))
#endif

/*----------------------------------------------------------------------*/
/*                      Miscellaneous buffer values                     */
/*----------------------------------------------------------------------*/

/* Number of characters in buffer */
#define BUF_SIZE(buf) (BUF_Z (buf) - BUF_BEG (buf))

/* Is this buffer narrowed? */
#define BUF_NARROWED(buf) ((BI_BUF_BEGV (buf) != BI_BUF_BEG (buf)) \
			   || (BI_BUF_ZV (buf) != BI_BUF_Z (buf)))

/* Modification count.  */
#define BUF_MODIFF(buf) ((buf)->text.modiff)

/* Face changed.  */
#define BUF_FACECHANGE(buf) ((buf)->text.face_change)

#define POINT_MARKER_P(marker) \
   (XMARKER (marker)->buffer != 0 && \
    EQ ((marker), XMARKER (marker)->buffer->point_marker))

/* WARNING:

   The new definitions of CEILING_OF() and FLOOR_OF() differ semantically
   from the old ones (in FSF Emacs and XEmacs 19.11 and before).
   Conversion is as follows:

   OLD_BI_CEILING_OF(n) = NEW_BI_CEILING_OF(n) - 1
   OLD_BI_FLOOR_OF(n) = NEW_BI_FLOOR_OF(n + 1)

   The definitions were changed because the new definitions are more
   consistent with the way everything else works in Emacs.
 */

/* Properties of CEILING_OF and FLOOR_OF (also apply to BI_ variants):

   1) FLOOR_OF (CEILING_OF (n)) = n
      CEILING_OF (FLOOR_OF (n)) = n

   2) CEILING_OF (n) = n if and only if n = ZV
      FLOOR_OF (n) = n if and only if n = BEGV

   3) CEILING_OF (CEILING_OF (n)) = ZV
      FLOOR_OF (FLOOR_OF (n)) = BEGV

   4) The bytes in the regions

      [BYTE_ADDRESS (n), BYTE_ADDRESS_BEFORE (CEILING_OF (n))]

      and

      [BYTE_ADDRESS (FLOOR_OF (n)), BYTE_ADDRESS_BEFORE (n)]

      are contiguous.
   */


/*  Return the maximum index in the buffer it is safe to scan forwards
    past N to.  This is used to prevent buffer scans from running into
    the gap (e.g. search.c).  All characters between N and CEILING_OF(N)
    are located contiguous in memory.  Note that the character *at*
    CEILING_OF(N) is not contiguous in memory. */
#define BI_BUF_CEILING_OF(b, n)						\
  ((n) < (b)->text.gpt && (b)->text.gpt < BI_BUF_ZV (b) ?		\
   (b)->text.gpt : BI_BUF_ZV (b))
#define BUF_CEILING_OF(b, n)						\
  bytind_to_bufpos (b, BI_BUF_CEILING_OF (b, bufpos_to_bytind (b, n)))

/*  Return the minimum index in the buffer it is safe to scan backwards
    past N to.  All characters between FLOOR_OF(N) and N are located
    contiguous in memory.  Note that the character *at* N may not be
    contiguous in memory. */
#define BI_BUF_FLOOR_OF(b, n)						\
        (BI_BUF_BEGV (b) < (b)->text.gpt && (b)->text.gpt < (n) ?	\
	 (b)->text.gpt : BI_BUF_BEGV (b))
#define BUF_FLOOR_OF(b, n)						\
  bytind_to_bufpos (b, BI_BUF_FLOOR_OF (b, bufpos_to_bytind (b, n)))

#define BI_BUF_CEILING_OF_IGNORE_ACCESSIBLE(b, n)			\
  ((n) < (b)->text.gpt && (b)->text.gpt < BI_BUF_Z (b) ?		\
   (b)->text.gpt : BI_BUF_Z (b))
#define BUF_CEILING_OF_IGNORE_ACCESSIBLE(b, n) 				\
  bytind_to_bufpos							\
   (b, BI_BUF_CEILING_OF_IGNORE_ACCESSIBLE (b, bufpos_to_bytind (b, n)))

#define BI_BUF_FLOOR_OF_IGNORE_ACCESSIBLE(b, n)				\
        (BI_BUF_BEG (b) < (b)->text.gpt && (b)->text.gpt < (n) ?	\
	 (b)->text.gpt : BI_BUF_BEG (b))
#define BUF_FLOOR_OF_IGNORE_ACCESSIBLE(b, n) 				\
  bytind_to_bufpos							\
   (b, BI_BUF_FLOOR_OF_IGNORE_ACCESSIBLE (b, bufpos_to_bytind (b, n)))


struct buffer_text
  {
    Bufbyte *beg;		/* Actual address of buffer contents. */    
    Bytind begv;		/* Index of beginning of accessible range. */
    Bytind pt;			/* Position of point in buffer. */
    Bytind gpt;			/* Index of gap in buffer. */
    Bytind zv;			/* Index of end of accessible range. */
    Bytind z;			/* Index of end of buffer. */
    int gap_size;		/* Size of buffer's gap */
    int modiff;			/* This counts buffer-modification events
				   for this buffer.  It is incremented for
				   each such event, and never otherwise
				   changed.  */
    int face_change;		/* This is set when a change in how the text
				   should be displayed (e.g., font, color)
				   is made. */
  };

struct buffer
  {
    struct lcrecord_header header;

    /* This structure holds the coordinates of the buffer contents.  */
    struct buffer_text text;

    /* Flags saying which DEFVAR_PER_BUFFER variables
       are local to this buffer.  */
    int local_var_flags;

    /* Value of text.modiff as of when visited file was read or written. */
    int save_modified;

    /* Set to the modtime of the visited file when read or written.
       -1 means visited file was nonexistent.
       0 means visited file modtime unknown; in no case complain
       about any mismatch on next save attempt.  */
    int modtime;

    /* the value of text.modiff at the last auto-save. */
    int auto_save_modified;

    /* The time at which we detected a failure to auto-save,
       Or -1 if we didn't have a failure.  */
    int auto_save_failure_time;

    /* Position in buffer at which display started
       the last time this buffer was displayed */
    int last_window_start;

    struct extent_list *extents;
    struct stack_of_extents *soe;
    struct buffer_change_data *changes;
#ifdef MULE
    struct buffer_mule_bufpos_data *mule_data;
#endif

    /* These next two are exceptions -- both slots are be handled 
       "specially" by gc_sweep, and their contents are not lisp-accessible 
       as a local variable, but they are Lisp_Objects. */

    /* The markers that refer to this buffer.  This
       is actually a single marker -- successive elements in its marker
       `chain' are the other markers referring to this buffer */
    struct Lisp_Marker *markers;


    /* Everything from here down must be a Lisp_Object */

#define MARKED_SLOT(x) Lisp_Object x
#include "bufslots.h"
#undef MARKED_SLOT
};

DECLARE_LRECORD (buffer, struct buffer);
#define XBUFFER(x) XRECORD (x, buffer, struct buffer)
#define XSETBUFFER(x, p) XSETRECORD (x, p, buffer)
#define BUFFERP(x) RECORDP (x, buffer)
#define CHECK_BUFFER(x, i) CHECK_RECORD (x, buffer)

#define BUFFER_LIVE_P(b) (!NILP ((b)->name))
extern Lisp_Object Qbuffer_live_p;
#define CHECK_LIVE_BUFFER(x, i) 					\
  do { CHECK_BUFFER (x, i);						\
       if (!BUFFER_LIVE_P (XBUFFER (x)))				\
	 x = wrong_type_argument (Qbuffer_live_p, (x));			\
     } while (0)

#define BUFFER_OR_STRING_P(x) (BUFFERP (x) || STRINGP (x))

extern Lisp_Object Qbuffer_or_string_p;
#define CHECK_BUFFER_OR_STRING(x, i)					\
  do { if (!BUFFER_OR_STRING_P (x))					\
	 x = wrong_type_argument (Qbuffer_or_string_p, (x));		\
     } while (0)

#define CHECK_LIVE_BUFFER_OR_STRING(x, i)				\
  do { CHECK_BUFFER_OR_STRING (x, i);					\
       if (BUFFERP (x))							\
	 CHECK_LIVE_BUFFER (x, i);					\
     } while (0)

extern struct buffer *current_buffer;

/* This structure holds the default values of the buffer-local variables
   defined with DefBufferLispVar, that have special slots in each buffer.
   The default value occupies the same slot in this structure
   as an individual buffer's value occupies in that buffer.
   Setting the default value also goes through the alist of buffers
   and stores into each buffer that does not say it has a local value.  */

extern Lisp_Object Vbuffer_defaults;

/* This structure marks which slots in a buffer have corresponding
   default values in buffer_defaults.
   Each such slot has a nonzero value in this structure.
   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.

   If a slot in this structure is zero, then even though there may
   be a DefBufferLispVar for the slot, there is no default valuefeor it;
   and the corresponding slot in buffer_defaults is not used.  */

extern struct buffer buffer_local_flags;


/* Allocation of buffer data. */

#ifdef REL_ALLOC

extern char* r_alloc (char **, unsigned long);
extern char* r_re_alloc (char **, unsigned long);
extern void r_alloc_free (void **);

#define BUFFER_ALLOC(data,size) \
  ((Bufbyte *) r_alloc ((char **) &data, (size) * sizeof(Bufbyte)))
#define BUFFER_REALLOC(data,size) \
  ((Bufbyte *) r_re_alloc ((char **) &data, (size) * sizeof(Bufbyte)))
#define BUFFER_FREE(data) r_alloc_free ((void **) &(data))
#define R_ALLOC_DECLARE(var,data) r_alloc_declare (&(var), data)

#else /* !REL_ALLOC */

#define BUFFER_ALLOC(data,size)\
	(data = (Bufbyte *) xmalloc ((size) * sizeof(Bufbyte)))
#define BUFFER_REALLOC(data,size)\
	((Bufbyte *) xrealloc (data, (size) * sizeof(Bufbyte)))
/* Avoid excess parentheses, or syntax errors may rear their heads. */
#define BUFFER_FREE(data) xfree (data)
#define R_ALLOC_DECLARE(var,data)

#endif /* !REL_ALLOC */

/* A search buffer, with a fastmap allocated and ready to go.  */
extern struct re_pattern_buffer searchbuf;


extern Lisp_Object Vbuffer_alist;
extern void set_buffer_internal (struct buffer *b);
extern struct buffer *decode_buffer (Lisp_Object buffer, int allow_string);
extern void get_bufrange (struct buffer *b, Lisp_Object from, Lisp_Object to,
			  Bufpos *start, Bufpos *end, unsigned int flags);
extern void get_bufrange_bytind (struct buffer *b, Lisp_Object from,
				 Lisp_Object to, Bytind *start, Bytind *end,
				 unsigned int flags);
extern Bufpos get_bufpos (struct buffer *b, Lisp_Object pos, int flags);
extern Bytind get_bytind (struct buffer *b, Lisp_Object pos, int flags);
extern void record_buffer (Lisp_Object buf);
extern Lisp_Object get_buffer (Lisp_Object name,
                               int error_if_deleted_or_does_not_exist);

/* from editfns.c */
extern void widen_buffer (struct buffer *b, int no_clip);

/* from insdel.c */
extern void set_buffer_point (struct buffer *buf, Bytind position);
extern Bufbyte *charptr_from_external_static (CONST char *ptr, int len,
					      Bytecount *len_out, int bin);
extern char *charptr_to_external_static (CONST Bufbyte *ptr, Bytecount len,
					 int *len_out, int bin);
extern Bufbyte *charptr_from_external_malloc (CONST char *ptr, int len,
					      Bytecount *len_out);
extern char *charptr_to_external_malloc (CONST Bufbyte *ptr, Bytecount len,
					 int *len_out);

#endif /* _XEMACS_BUFFER_H_ */
