/* Lisp functions pertaining to editing.
- Copyright (C) 1985,86,87,89,93,94,95,96,97 Free Software Foundation, Inc.
+ Copyright (C) 1985,86,87,89,93,94,95,96,97,98 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <pwd.h>
#endif
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
#include "lisp.h"
#include "intervals.h"
#include "buffer.h"
}
\f
DEFUN ("char-to-string", Fchar_to_string, Schar_to_string, 1, 1, 0,
- "Convert arg CHAR to a string containing multi-byte form of that character.")
+ "Convert arg CHAR to a string containing that character.")
(character)
Lisp_Object character;
{
CHECK_NUMBER (character, 0);
len = CHAR_STRING (XFASTINT (character), workbuf, str);
- return make_string (str, len);
+ return make_string_from_bytes (str, 1, len);
}
DEFUN ("string-to-char", Fstring_to_char, Sstring_to_char, 1, 1, 0,
CHECK_STRING (string, 0);
p = XSTRING (string);
if (p->size)
- XSETFASTINT (val, STRING_CHAR (p->data, p->size));
- else
- XSETFASTINT (val, 0);
- return val;
-}
-
-DEFUN ("sref", Fsref, Ssref, 2, 2, 0,
- "Return the character in STRING at INDEX. INDEX starts at 0.\n\
-A multibyte character is handled correctly.\n\
-INDEX not pointing at character boundary is an error.")
- (str, idx)
- Lisp_Object str, idx;
-{
- register int idxval, len, i;
- register unsigned char *p, *q;
- register Lisp_Object val;
-
- CHECK_STRING (str, 0);
- CHECK_NUMBER (idx, 1);
- idxval = XINT (idx);
- if (idxval < 0 || idxval >= (len = XVECTOR (str)->size))
- args_out_of_range (str, idx);
-
- p = XSTRING (str)->data + idxval;
- if (!NILP (current_buffer->enable_multibyte_characters)
- && !CHAR_HEAD_P (*p)
- && idxval > 0)
{
- /* We must check if P points to a tailing byte of a multibyte
- form. If so, we signal error. */
- i = idxval - 1;
- q = p - 1;
- while (i > 0 && *q >= 0xA0) i--, q--;
-
- if (*q == LEADING_CODE_COMPOSITION)
- i = multibyte_form_length (XSTRING (str)->data + i, len - i);
+ if (STRING_MULTIBYTE (string))
+ XSETFASTINT (val, STRING_CHAR (p->data, STRING_BYTES (p)));
else
- i = BYTES_BY_CHAR_HEAD (*q);
- if (q + i > p)
- error ("Not character boundary");
+ XSETFASTINT (val, p->data[0]);
}
-
- len = XSTRING (str)->size - idxval;
- XSETFASTINT (val, STRING_CHAR (p, len));
+ else
+ XSETFASTINT (val, 0);
return val;
}
-
\f
static Lisp_Object
buildmark (charpos, bytepos)
int pos;
unsigned char *p;
- if (MARKERP (position))
+ if (MARKERP (position)
+ && current_buffer == XMARKER (position)->buffer)
{
pos = marker_position (position);
if (pos < BEGV)
Executes BODY just like `progn'.\n\
The values of point, mark and the current buffer are restored\n\
even in case of abnormal exit (throw or error).\n\
-The state of activation of the mark is also restored.")
+The state of activation of the mark is also restored.\n\
+\n\
+This construct does not save `deactivate-mark', and therefore\n\
+functions that change the buffer will still cause deactivation\n\
+of the mark at the end of the command. To prevent that, bind\n\
+`deactivate-mark' with `let'.")
(args)
Lisp_Object args;
{
register Lisp_Object val;
int count = specpdl_ptr - specpdl;
- record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+ record_unwind_protect (set_buffer_if_live, Fcurrent_buffer ());
val = Fprogn (args);
return unbind_to (count, val);
return buildmark (ZV, ZV_BYTE);
}
+DEFUN ("gap-position", Fgap_position, Sgap_position, 0, 0, 0,
+ "Return the position of the gap, in the current buffer.\n\
+See also `gap-size'.")
+ ()
+{
+ Lisp_Object temp;
+ XSETFASTINT (temp, GPT);
+ return temp;
+}
+
+DEFUN ("gap-size", Fgap_size, Sgap_size, 0, 0, 0,
+ "Return the size of the current buffer's gap.\n\
+See also `gap-position'.")
+ ()
+{
+ Lisp_Object temp;
+ XSETFASTINT (temp, GAP_SIZE);
+ return temp;
+}
+
+DEFUN ("position-bytes", Fposition_bytes, Sposition_bytes, 1, 1, 0,
+ "Return the byte position for character position POSITION.\n\
+If POSITION is out of range, the value is nil.")
+ (position)
+ Lisp_Object position;
+{
+ CHECK_NUMBER_COERCE_MARKER (position, 1);
+ if (XINT (position) < BEG || XINT (position) > Z)
+ return Qnil;
+ return make_number (CHAR_TO_BYTE (XINT (position)));
+}
+
+DEFUN ("byte-to-position", Fbyte_to_position, Sbyte_to_position, 1, 1, 0,
+ "Return the character position for byte position BYTEPOS.\n\
+If BYTEPOS is out of range, the value is nil.")
+ (bytepos)
+ Lisp_Object bytepos;
+{
+ CHECK_NUMBER (bytepos, 1);
+ if (XINT (bytepos) < BEG_BYTE || XINT (bytepos) > Z_BYTE)
+ return Qnil;
+ return make_number (BYTE_TO_CHAR (XINT (bytepos)));
+}
+\f
DEFUN ("following-char", Ffollowing_char, Sfollowing_char, 0, 0, 0,
"Return the character following point, as a number.\n\
At the end of the buffer or accessible region, return 0.\n\
DEFUN ("char-after", Fchar_after, Schar_after, 0, 1, 0,
"Return character in current buffer at position POS.\n\
POS is an integer or a buffer pointer.\n\
-If POS is out of range, the value is nil.\n\
-If `enable-multibyte-characters' is nil or POS is not at character boundary,\n\
- multi-byte form is ignored, and only one byte at POS\n\
- is returned as a character.")
+If POS is out of range, the value is nil.")
(pos)
Lisp_Object pos;
{
register Lisp_Object val;
if (NILP (pos))
- return make_number (FETCH_CHAR (PT_BYTE));
+ {
+ pos_byte = PT_BYTE;
+ XSETFASTINT (pos, PT);
+ }
if (MARKERP (pos))
- pos_byte = marker_byte_position (pos);
+ {
+ pos_byte = marker_byte_position (pos);
+ if (pos_byte < BEGV_BYTE || pos_byte >= ZV_BYTE)
+ return Qnil;
+ }
else
{
CHECK_NUMBER_COERCE_MARKER (pos, 0);
+ if (XINT (pos) < BEGV || XINT (pos) >= ZV)
+ return Qnil;
pos_byte = CHAR_TO_BYTE (XINT (pos));
}
- if (n < BEGV_BYTE || n >= ZV_BYTE)
- return Qnil;
-
return make_number (FETCH_CHAR (pos_byte));
}
DEFUN ("char-before", Fchar_before, Schar_before, 0, 1, 0,
"Return character in current buffer preceding position POS.\n\
POS is an integer or a buffer pointer.\n\
-If POS is out of range, the value is nil.\n\
-If `enable-multibyte-characters' is nil or POS is not at character boundary,\n\
-multi-byte form is ignored, and only one byte preceding POS\n\
-is returned as a character.")
+If POS is out of range, the value is nil.")
(pos)
Lisp_Object pos;
{
register int pos_byte;
if (NILP (pos))
- pos_byte = PT_BYTE;
- else if (MARKERP (pos))
- pos_byte = marker_byte_position (pos);
+ {
+ pos_byte = PT_BYTE;
+ XSETFASTINT (pos, PT);
+ }
+
+ if (MARKERP (pos))
+ {
+ pos_byte = marker_byte_position (pos);
+
+ if (pos_byte <= BEGV_BYTE || pos_byte > ZV_BYTE)
+ return Qnil;
+ }
else
{
CHECK_NUMBER_COERCE_MARKER (pos, 0);
+ if (XINT (pos) <= BEGV || XINT (pos) > ZV)
+ return Qnil;
+
pos_byte = CHAR_TO_BYTE (XINT (pos));
}
- if (pos_byte <= BEGV_BYTE || pos_byte > ZV_BYTE)
- return Qnil;
-
if (!NILP (current_buffer->enable_multibyte_characters))
{
DEC_POS (pos_byte);
DEFUN ("user-full-name", Fuser_full_name, Suser_full_name, 0, 1, 0,
"Return the full name of the user logged in, as a string.\n\
+If the full name corresponding to Emacs's userid is not known,\n\
+return \"unknown\".\n\
+\n\
If optional argument UID is an integer, return the full name of the user\n\
-with that uid, or \"unknown\" if there is no such user.\n\
+with that uid, or nil if there is no such user.\n\
If UID is a string, return the full name of the user with that login\n\
-name, or \"unknown\" if no such user could be found.")
+name, or nil if there is no such user.")
(uid)
Lisp_Object uid;
{
}
}
+/* Write information into buffer S of size MAXSIZE, according to the
+ FORMAT of length FORMAT_LEN, using time information taken from *TP.
+ Return the number of bytes written, not including the terminating
+ '\0'. If S is NULL, nothing will be written anywhere; so to
+ determine how many bytes would be written, use NULL for S and
+ ((size_t) -1) for MAXSIZE.
+
+ This function behaves like emacs_strftime, except it allows null
+ bytes in FORMAT. */
+static size_t
+emacs_memftime (s, maxsize, format, format_len, tp)
+ char *s;
+ size_t maxsize;
+ const char *format;
+ size_t format_len;
+ const struct tm *tp;
+{
+ size_t total = 0;
+
+ /* Loop through all the null-terminated strings in the format
+ argument. Normally there's just one null-terminated string, but
+ there can be arbitrarily many, concatenated together, if the
+ format contains '\0' bytes. emacs_strftime stops at the first
+ '\0' byte so we must invoke it separately for each such string. */
+ for (;;)
+ {
+ size_t len;
+ size_t result;
+
+ if (s)
+ s[0] = '\1';
+
+ result = emacs_strftime (s, maxsize, format, tp);
+
+ if (s)
+ {
+ if (result == 0 && s[0] != '\0')
+ return 0;
+ s += result + 1;
+ }
+
+ maxsize -= result + 1;
+ total += result;
+ len = strlen (format);
+ if (len == format_len)
+ return total;
+ total++;
+ format += len + 1;
+ format_len -= len + 1;
+ }
+}
+
/*
DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
"Use FORMAT-STRING to format the time TIME, or now if omitted.\n\
{
time_t value;
int size;
+ struct tm *tm;
CHECK_STRING (format_string, 1);
error ("Invalid time specification");
/* This is probably enough. */
- size = XSTRING (format_string)->size * 6 + 50;
+ size = STRING_BYTES (XSTRING (format_string)) * 6 + 50;
+
+ tm = NILP (universal) ? localtime (&value) : gmtime (&value);
+ if (! tm)
+ error ("Specified time is not representable");
while (1)
{
int result;
buf[0] = '\1';
- result = emacs_strftime (buf, size, XSTRING (format_string)->data,
- (NILP (universal) ? localtime (&value)
- : gmtime (&value)));
+ result = emacs_memftime (buf, size, XSTRING (format_string)->data,
+ STRING_BYTES (XSTRING (format_string)),
+ tm);
if ((result > 0 && result < size) || (result == 0 && buf[0] == '\0'))
- return build_string (buf);
+ return make_string (buf, result);
/* If buffer was too small, make it bigger and try again. */
- result = emacs_strftime (NULL, 0x7fffffff, XSTRING (format_string)->data,
- (NILP (universal) ? localtime (&value)
- : gmtime (&value)));
+ result = emacs_memftime (NULL, (size_t) -1,
+ XSTRING (format_string)->data,
+ STRING_BYTES (XSTRING (format_string)),
+ tm);
size = result + 1;
}
}
error ("Invalid time specification");
decoded_time = localtime (&time_spec);
+ if (! decoded_time)
+ error ("Specified time is not representable");
XSETFASTINT (list_args[0], decoded_time->tm_sec);
XSETFASTINT (list_args[1], decoded_time->tm_min);
XSETFASTINT (list_args[2], decoded_time->tm_hour);
{
time_t value;
struct tm *t;
+ struct tm gmt;
if (lisp_time_argument (specified_time, &value)
- && (t = gmtime (&value)) != 0)
+ && (t = gmtime (&value)) != 0
+ && (gmt = *t, t = localtime (&value)) != 0)
{
- struct tm gmt;
- int offset;
- char *s, buf[6];
-
- gmt = *t; /* Make a copy, in case localtime modifies *t. */
- t = localtime (&value);
- offset = tm_diff (t, &gmt);
- s = 0;
+ int offset = tm_diff (t, &gmt);
+ char *s = 0;
+ char buf[6];
#ifdef HAVE_TM_ZONE
if (t->tm_zone)
s = (char *)t->tm_zone;
general_insert_function (insert_func, insert_from_string_func,
inherit, nargs, args)
void (*insert_func) P_ ((unsigned char *, int));
- void (*insert_from_string_func) P_ ((Lisp_Object, int, int, int));
+ void (*insert_from_string_func) P_ ((Lisp_Object, int, int, int, int, int));
int inherit, nargs;
register Lisp_Object *args;
{
if (!NILP (current_buffer->enable_multibyte_characters))
len = CHAR_STRING (XFASTINT (val), workbuf, str);
else
- workbuf[0] = XINT (val), str = workbuf, len = 1;
+ {
+ workbuf[0] = (SINGLE_BYTE_CHAR_P (XINT (val))
+ ? XINT (val)
+ : multibyte_char_to_unibyte (XINT (val), Qnil));
+ str = workbuf;
+ len = 1;
+ }
(*insert_func) (str, len);
}
else if (STRINGP (val))
{
- (*insert_from_string_func) (val, 0, XSTRING (val)->size, inherit);
+ (*insert_from_string_func) (val, 0, 0,
+ XSTRING (val)->size,
+ STRING_BYTES (XSTRING (val)),
+ inherit);
}
else
{
DEFUN ("insert", Finsert, Sinsert, 0, MANY, 0,
"Insert the arguments, either strings or characters, at point.\n\
-Point and before-insertion-markers move forward so that it ends up\n\
+Point and before-insertion markers move forward to end up\n\
after the inserted text.\n\
-Any other markers at the point of insertion remain before the text.")
+Any other markers at the point of insertion remain before the text.\n\
+\n\
+If the current buffer is multibyte, unibyte strings are converted\n\
+to multibyte for insertion (see `unibyte-char-to-multibyte').\n\
+If the current buffer is unibyte, multibyte strings are converted\n\
+to unibyte for insertion.")
(nargs, args)
int nargs;
register Lisp_Object *args;
DEFUN ("insert-and-inherit", Finsert_and_inherit, Sinsert_and_inherit,
0, MANY, 0,
"Insert the arguments at point, inheriting properties from adjoining text.\n\
-Point and before-insertion-markers move forward so that it ends up\n\
+Point and before-insertion markers move forward to end up\n\
after the inserted text.\n\
-Any other markers at the point of insertion remain before the text.")
+Any other markers at the point of insertion remain before the text.\n\
+\n\
+If the current buffer is multibyte, unibyte strings are converted\n\
+to multibyte for insertion (see `unibyte-char-to-multibyte').\n\
+If the current buffer is unibyte, multibyte strings are converted\n\
+to unibyte for insertion.")
(nargs, args)
int nargs;
register Lisp_Object *args;
DEFUN ("insert-before-markers", Finsert_before_markers, Sinsert_before_markers, 0, MANY, 0,
"Insert strings or characters at point, relocating markers after the text.\n\
-Point and before-insertion-markers move forward so that it ends up\n\
- after the inserted text.\n\
-Any other markers at the point of insertion also end up after the text.")
+Point and markers move forward to end up after the inserted text.\n\
+\n\
+If the current buffer is multibyte, unibyte strings are converted\n\
+to multibyte for insertion (see `unibyte-char-to-multibyte').\n\
+If the current buffer is unibyte, multibyte strings are converted\n\
+to unibyte for insertion.")
(nargs, args)
int nargs;
register Lisp_Object *args;
DEFUN ("insert-before-markers-and-inherit", Finsert_and_inherit_before_markers,
Sinsert_and_inherit_before_markers, 0, MANY, 0,
"Insert text at point, relocating markers and inheriting properties.\n\
-Point moves forward so that it ends up after the inserted text.\n\
-Any other markers at the point of insertion also end up after the text.")
+Point and markers move forward to end up after the inserted text.\n\
+\n\
+If the current buffer is multibyte, unibyte strings are converted\n\
+to multibyte for insertion (see `unibyte-char-to-multibyte').\n\
+If the current buffer is unibyte, multibyte strings are converted\n\
+to unibyte for insertion.")
(nargs, args)
int nargs;
register Lisp_Object *args;
\f
DEFUN ("insert-char", Finsert_char, Sinsert_char, 2, 3, 0,
"Insert COUNT (second arg) copies of CHARACTER (first arg).\n\
-Point and before-insertion-markers are affected as in the function `insert'.\n\
Both arguments are required.\n\
+Point, and before-insertion markers, are relocated as in the function `insert'.\n\
The optional third arg INHERIT, if non-nil, says to inherit text properties\n\
from adjoining text, if those properties are sticky.")
(character, count, inherit)
int start, end;
int props;
{
- Lisp_Object result, tem, tem1;
int start_byte = CHAR_TO_BYTE (start);
int end_byte = CHAR_TO_BYTE (end);
+ return make_buffer_string_both (start, start_byte, end, end_byte, props);
+}
+
+/* Return a Lisp_String containing the text of the current buffer from
+ START / START_BYTE to END / END_BYTE.
+
+ If text properties are in use and the current buffer
+ has properties in the range specified, the resulting string will also
+ have them, if PROPS is nonzero.
+
+ We don't want to use plain old make_string here, because it calls
+ make_uninit_string, which can cause the buffer arena to be
+ compacted. make_string has no way of knowing that the data has
+ been moved, and thus copies the wrong data into the string. This
+ doesn't effect most of the other users of make_string, so it should
+ be left as is. But we should use this function when conjuring
+ buffer substrings. */
+
+Lisp_Object
+make_buffer_string_both (start, start_byte, end, end_byte, props)
+ int start, start_byte, end, end_byte;
+ int props;
+{
+ Lisp_Object result, tem, tem1;
+
+ if (INTEGERP (current_buffer->minibuffer_prompt_length))
+ {
+ int len = XFASTINT (current_buffer->minibuffer_prompt_length);
+ start = min (end, max (len, start));
+ start_byte = CHAR_TO_BYTE (start);
+ }
+
if (start < GPT && GPT < end)
move_gap (start);
- result = make_uninit_string (end_byte - start_byte);
+ if (! NILP (current_buffer->enable_multibyte_characters))
+ result = make_uninit_multibyte_string (end - start, end_byte - start_byte);
+ else
+ result = make_uninit_string (end - start);
bcopy (BYTE_POS_ADDR (start_byte), XSTRING (result)->data,
end_byte - start_byte);
DEFUN ("buffer-substring", Fbuffer_substring, Sbuffer_substring, 2, 2, 0,
"Return the contents of part of the current buffer as a string.\n\
The two arguments START and END are character positions;\n\
-they can be in either order.")
+they can be in either order.\n\
+The string returned is multibyte if the buffer is multibyte.")
(start, end)
Lisp_Object start, end;
{
(buffer1, start1, end1, buffer2, start2, end2)
Lisp_Object buffer1, start1, end1, buffer2, start2, end2;
{
- register int begp1, endp1, begp2, endp2, temp, len1, len2, length, i;
+ register int begp1, endp1, begp2, endp2, temp;
register struct buffer *bp1, *bp2;
register Lisp_Object *trt
= (!NILP (current_buffer->case_fold_search)
? XCHAR_TABLE (current_buffer->case_canon_table)->contents : 0);
int chars = 0;
- int beg1_byte, beg2_byte;
+ int i1, i2, i1_byte, i2_byte;
/* Find the first buffer and its substring. */
&& endp2 <= BUF_ZV (bp2)))
args_out_of_range (start2, end2);
- beg1_byte = buf_charpos_to_bytepos (bp1, begp1);
- beg2_byte = buf_charpos_to_bytepos (bp2, begp2);
- len1 = buf_charpos_to_bytepos (bp1, endp1) - begp1;
- len2 = buf_charpos_to_bytepos (bp2, endp2) - begp2;
- length = len1;
- if (len2 < length)
- length = len2;
+ i1 = begp1;
+ i2 = begp2;
+ i1_byte = buf_charpos_to_bytepos (bp1, i1);
+ i2_byte = buf_charpos_to_bytepos (bp2, i2);
- for (i = 0; i < length; i++)
+ while (i1 < endp1 && i2 < endp2)
{
- unsigned char *p1 = BUF_BYTE_ADDRESS (bp1, beg1_byte + i);
- int c1 = *p1;
- int c2 = *BUF_BYTE_ADDRESS (bp2, beg2_byte + i);
+ /* When we find a mismatch, we must compare the
+ characters, not just the bytes. */
+ int c1, c2;
+
+ if (! NILP (bp1->enable_multibyte_characters))
+ {
+ c1 = BUF_FETCH_MULTIBYTE_CHAR (bp1, i1_byte);
+ BUF_INC_POS (bp1, i1_byte);
+ i1++;
+ }
+ else
+ {
+ c1 = BUF_FETCH_BYTE (bp1, i1);
+ c1 = unibyte_char_to_multibyte (c1);
+ i1++;
+ }
- /* If a character begins here,
- count the previous character now. */
- if (i > 0
- && (NILP (current_buffer->enable_multibyte_characters)
- || CHAR_HEAD_P (*p1)))
- chars++;
+ if (! NILP (bp2->enable_multibyte_characters))
+ {
+ c2 = BUF_FETCH_MULTIBYTE_CHAR (bp2, i2_byte);
+ BUF_INC_POS (bp2, i2_byte);
+ i2++;
+ }
+ else
+ {
+ c2 = BUF_FETCH_BYTE (bp2, i2);
+ c2 = unibyte_char_to_multibyte (c2);
+ i2++;
+ }
if (trt)
{
return make_number (- 1 - chars);
if (c1 > c2)
return make_number (chars + 1);
+
+ chars++;
}
/* The strings match as far as they go.
If one is shorter, that one is less. */
- if (length < len1)
+ if (chars < endp1 - begp1)
return make_number (chars + 1);
- else if (length < len2)
+ else if (chars < endp2 - begp2)
return make_number (- chars - 1);
/* Same length too => they are equal. */
(start, end, fromchar, tochar, noundo)
Lisp_Object start, end, fromchar, tochar, noundo;
{
- register int pos, stop, i, len, end_byte;
+ register int pos, pos_byte, stop, i, len, end_byte;
int changed = 0;
unsigned char fromwork[4], *fromstr, towork[4], *tostr, *p;
int count = specpdl_ptr - specpdl;
+#define COMBINING_NO 0
+#define COMBINING_BEFORE 1
+#define COMBINING_AFTER 2
+#define COMBINING_BOTH (COMBINING_BEFORE | COMBINING_AFTER)
+ int maybe_byte_combining = COMBINING_NO;
validate_region (&start, &end);
CHECK_NUMBER (fromchar, 2);
len = CHAR_STRING (XFASTINT (fromchar), fromwork, fromstr);
if (CHAR_STRING (XFASTINT (tochar), towork, tostr) != len)
error ("Characters in subst-char-in-region have different byte-lengths");
+ if (!ASCII_BYTE_P (*tostr))
+ {
+ /* If *TOSTR is in the range 0x80..0x9F and TOCHAR is not a
+ complete multibyte character, it may be combined with the
+ after bytes. If it is in the range 0xA0..0xFF, it may be
+ combined with the before and after bytes. */
+ if (!CHAR_HEAD_P (*tostr))
+ maybe_byte_combining = COMBINING_BOTH;
+ else if (BYTES_BY_CHAR_HEAD (*tostr) > len)
+ maybe_byte_combining = COMBINING_AFTER;
+ }
}
else
{
towork[0] = XFASTINT (tochar), tostr = towork;
}
- pos = CHAR_TO_BYTE (XINT (start));
+ pos = XINT (start);
+ pos_byte = CHAR_TO_BYTE (pos);
stop = CHAR_TO_BYTE (XINT (end));
end_byte = stop;
current_buffer->filename = Qnil;
}
- if (pos < GPT_BYTE)
+ if (pos_byte < GPT_BYTE)
stop = min (stop, GPT_BYTE);
- p = BYTE_POS_ADDR (pos);
while (1)
{
- if (pos >= stop)
+ int pos_byte_next = pos_byte;
+
+ if (pos_byte >= stop)
{
- if (pos >= end_byte) break;
+ if (pos_byte >= end_byte) break;
stop = end_byte;
- p = BYTE_POS_ADDR (pos);
}
- if (p[0] == fromstr[0]
+ p = BYTE_POS_ADDR (pos_byte);
+ INC_POS (pos_byte_next);
+ if (pos_byte_next - pos_byte == len
+ && p[0] == fromstr[0]
&& (len == 1
|| (p[1] == fromstr[1]
&& (len == 2 || (p[2] == fromstr[2]
changed = 1;
}
- if (NILP (noundo))
- record_change (pos, len);
- for (i = 0; i < len; i++) *p++ = tostr[i];
- pos += len;
+ /* Take care of the case where the new character
+ combines with neighboring bytes. */
+ if (maybe_byte_combining
+ && (maybe_byte_combining == COMBINING_AFTER
+ ? (pos_byte_next < Z_BYTE
+ && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte_next)))
+ : ((pos_byte_next < Z_BYTE
+ && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte_next)))
+ || (pos_byte > BEG_BYTE
+ && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1))))))
+ {
+ Lisp_Object tem, string;
+
+ struct gcpro gcpro1;
+
+ tem = current_buffer->undo_list;
+ GCPRO1 (tem);
+
+ /* Make a multibyte string containing this single character. */
+ string = make_multibyte_string (tostr, 1, len);
+ /* replace_range is less efficient, because it moves the gap,
+ but it handles combining correctly. */
+ replace_range (pos, pos + 1, string,
+ 0, 0, 1);
+ pos_byte_next = CHAR_TO_BYTE (pos);
+ if (pos_byte_next > pos_byte)
+ /* Before combining happened. We should not increment
+ POS. So, to cancel the later increment of POS,
+ decrease it now. */
+ pos--;
+ else
+ INC_POS (pos_byte_next);
+
+ if (! NILP (noundo))
+ current_buffer->undo_list = tem;
+
+ UNGCPRO;
+ }
+ else
+ {
+ if (NILP (noundo))
+ record_change (pos, 1);
+ for (i = 0; i < len; i++) *p++ = tostr[i];
+ }
}
- else
- pos++, p++;
+ pos_byte = pos_byte_next;
+ pos++;
}
if (changed)
signal_after_change (XINT (start),
- stop - XINT (start), stop - XINT (start));
+ XINT (end) - XINT (start), XINT (end) - XINT (start));
unbind_to (count, Qnil);
return Qnil;
DEFUN ("translate-region", Ftranslate_region, Stranslate_region, 3, 3, 0,
"From START to END, translate characters according to TABLE.\n\
TABLE is a string; the Nth character in it is the mapping\n\
-for the character with code N. Returns the number of characters changed.")
+for the character with code N.\n\
+This function does not alter multibyte characters.\n\
+It returns the number of characters changed.")
(start, end, table)
Lisp_Object start;
Lisp_Object end;
register int nc; /* New character. */
int cnt; /* Number of changes made. */
int size; /* Size of translate table. */
- int charpos;
+ int pos;
validate_region (&start, &end);
CHECK_STRING (table, 2);
- size = XSTRING (table)->size;
+ size = STRING_BYTES (XSTRING (table));
tt = XSTRING (table)->data;
pos_byte = CHAR_TO_BYTE (XINT (start));
stop = CHAR_TO_BYTE (XINT (end));
modify_region (current_buffer, XINT (start), XINT (end));
- charpos = XINT (start);
+ pos = XINT (start);
cnt = 0;
- for (; pos_byte < stop; ++pos_byte)
+ for (; pos_byte < stop; )
{
register unsigned char *p = BYTE_POS_ADDR (pos_byte);
- register int oc = *p; /* Old character. */
- if (CHAR_HEAD_P (*p))
- charpos++;
+ int len;
+ int oc;
+ int pos_byte_next;
- if (oc < size)
+ oc = STRING_CHAR_AND_LENGTH (p, stop - pos_byte, len);
+ pos_byte_next = pos_byte + len;
+ if (oc < size && len == 1)
{
nc = tt[oc];
if (nc != oc)
{
- record_change (charpos, 1);
- *p = nc;
- signal_after_change (charpos, 1, 1);
+ /* Take care of the case where the new character
+ combines with neighboring bytes. */
+ if (!ASCII_BYTE_P (nc)
+ && (CHAR_HEAD_P (nc)
+ ? ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1))
+ : (pos_byte > BEG_BYTE
+ && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1)))))
+ {
+ Lisp_Object string;
+
+ string = make_multibyte_string (tt + oc, 1, 1);
+ /* This is less efficient, because it moves the gap,
+ but it handles combining correctly. */
+ replace_range (pos, pos + 1, string,
+ 1, 0, 1);
+ pos_byte_next = CHAR_TO_BYTE (pos);
+ if (pos_byte_next > pos_byte)
+ /* Before combining happened. We should not
+ increment POS. So, to cancel the later
+ increment of POS, we decrease it now. */
+ pos--;
+ else
+ INC_POS (pos_byte_next);
+ }
+ else
+ {
+ record_change (pos, 1);
+ *p = nc;
+ signal_after_change (pos, 1, 1);
+ }
++cnt;
}
}
+ pos_byte = pos_byte_next;
+ pos++;
}
return make_number (cnt);
\n\
`save-restriction' can get confused if, within the BODY, you widen\n\
and then make changes outside the area within the saved restrictions.\n\
+See Info node `(elisp)Narrowing' for details and an appropriate technique.\n\
\n\
Note: if you are using both `save-excursion' and `save-restriction',\n\
use `save-excursion' outermost:\n\
{
register Lisp_Object val;
val = Fformat (nargs, args);
- /* Copy the data so that it won't move when we GC. */
- if (! message_text)
- {
- message_text = (char *)xmalloc (80);
- message_length = 80;
- }
- if (XSTRING (val)->size > message_length)
- {
- message_length = XSTRING (val)->size;
- message_text = (char *)xrealloc (message_text, message_length);
- }
- bcopy (XSTRING (val)->data, message_text, XSTRING (val)->size);
- message2 (message_text, XSTRING (val)->size);
+ message3 (val, STRING_BYTES (XSTRING (val)), STRING_MULTIBYTE (val));
return val;
}
}
message_text = (char *)xmalloc (80);
message_length = 80;
}
- if (XSTRING (val)->size > message_length)
+ if (STRING_BYTES (XSTRING (val)) > message_length)
{
- message_length = XSTRING (val)->size;
+ message_length = STRING_BYTES (XSTRING (val));
message_text = (char *)xrealloc (message_text, message_length);
}
- bcopy (XSTRING (val)->data, message_text, XSTRING (val)->size);
- message2 (message_text, XSTRING (val)->size);
+ bcopy (XSTRING (val)->data, message_text, STRING_BYTES (XSTRING (val)));
+ message2 (message_text, STRING_BYTES (XSTRING (val)),
+ STRING_MULTIBYTE (val));
return val;
#endif /* not HAVE_MENUS */
}
"Return the string currently displayed in the echo area, or nil if none.")
()
{
- return (echo_area_glyphs
- ? make_string (echo_area_glyphs, echo_area_glyphs_length)
- : Qnil);
+ return current_message ();
}
+/* Number of bytes that STRING will occupy when put into the result.
+ MULTIBYTE is nonzero if the result should be multibyte. */
+
+#define CONVERTED_BYTE_SIZE(MULTIBYTE, STRING) \
+ (((MULTIBYTE) && ! STRING_MULTIBYTE (STRING)) \
+ ? count_size_as_multibyte (XSTRING (STRING)->data, \
+ STRING_BYTES (XSTRING (STRING))) \
+ : STRING_BYTES (XSTRING (STRING)))
+
DEFUN ("format", Fformat, Sformat, 1, MANY, 0,
"Format a string out of a control-string and arguments.\n\
The first argument is a control string.\n\
%g means print a number in exponential notation\n\
or decimal-point notation, whichever uses fewer characters.\n\
%c means print a number as a single character.\n\
-%S means print any object as an s-expression (using prin1).\n\
+%S means print any object as an s-expression (using `prin1').\n\
The argument used for %d, %o, %x, %e, %f, %g or %c must be a number.\n\
Use %% to put a single % into the output.")
(nargs, args)
register Lisp_Object *args;
{
register int n; /* The number of the next arg to substitute */
- register int total = 5; /* An estimate of the final length */
- char *buf;
+ register int total; /* An estimate of the final length */
+ char *buf, *p;
register unsigned char *format, *end;
- int length;
+ int length, nchars;
+ /* Nonzero if the output should be a multibyte string,
+ which is true if any of the inputs is one. */
+ int multibyte = 0;
+ /* When we make a multibyte string, we must pay attention to the
+ byte combining problem, i.e., a byte may be combined with a
+ multibyte charcter of the previous string. This flag tells if we
+ must consider such a situation or not. */
+ int maybe_combine_byte;
+ unsigned char *this_format;
+ int longest_format;
+ Lisp_Object val;
+ struct info
+ {
+ int start, end;
+ } *info = 0;
+
extern char *index ();
+
/* It should not be necessary to GCPRO ARGS, because
the caller in the interpreter should take care of that. */
+ /* Try to determine whether the result should be multibyte.
+ This is not always right; sometimes the result needs to be multibyte
+ because of an object that we will pass through prin1,
+ and in that case, we won't know it here. */
+ for (n = 0; n < nargs; n++)
+ if (STRINGP (args[n]) && STRING_MULTIBYTE (args[n]))
+ multibyte = 1;
+
CHECK_STRING (args[0], 0);
+
+ /* If we start out planning a unibyte result,
+ and later find it has to be multibyte, we jump back to retry. */
+ retry:
+
format = XSTRING (args[0])->data;
- end = format + XSTRING (args[0])->size;
+ end = format + STRING_BYTES (XSTRING (args[0]));
+ longest_format = 0;
+
+ /* Make room in result for all the non-%-codes in the control string. */
+ total = 5 + CONVERTED_BYTE_SIZE (multibyte, args[0]);
+
+ /* Add to TOTAL enough space to hold the converted arguments. */
n = 0;
while (format != end)
if (*format++ == '%')
{
- int minlen;
+ int minlen, thissize = 0;
+ unsigned char *this_format_start = format - 1;
/* Process a numeric arg and skip it. */
minlen = atoi (format);
|| *format == '-' || *format == ' ' || *format == '.')
format++;
+ if (format - this_format_start + 1 > longest_format)
+ longest_format = format - this_format_start + 1;
+
+ if (format == end)
+ error ("Format string ends in middle of format specifier");
if (*format == '%')
format++;
else if (++n >= nargs)
/* For `S', prin1 the argument and then treat like a string. */
register Lisp_Object tem;
tem = Fprin1_to_string (args[n], Qnil);
+ if (STRING_MULTIBYTE (tem) && ! multibyte)
+ {
+ multibyte = 1;
+ goto retry;
+ }
args[n] = tem;
goto string;
}
else if (SYMBOLP (args[n]))
{
XSETSTRING (args[n], XSYMBOL (args[n])->name);
+ if (STRING_MULTIBYTE (args[n]) && ! multibyte)
+ {
+ multibyte = 1;
+ goto retry;
+ }
goto string;
}
else if (STRINGP (args[n]))
{
string:
if (*format != 's' && *format != 'S')
- error ("format specifier doesn't match argument type");
- total += XSTRING (args[n])->size;
- /* We have to put an arbitrary limit on minlen
- since otherwise it could make alloca fail. */
- if (minlen < XSTRING (args[n])->size + 1000)
- total += minlen;
+ error ("Format specifier doesn't match argument type");
+ thissize = CONVERTED_BYTE_SIZE (multibyte, args[n]);
}
/* Would get MPV otherwise, since Lisp_Int's `point' to low memory. */
else if (INTEGERP (args[n]) && *format != 's')
be a double. */
if (*format == 'e' || *format == 'f' || *format == 'g')
args[n] = Ffloat (args[n]);
+ else
#endif
- total += 30;
- /* We have to put an arbitrary limit on minlen
- since otherwise it could make alloca fail. */
- if (minlen < 1000)
- total += minlen;
+ if (*format != 'd' && *format != 'o' && *format != 'x'
+ && *format != 'i' && *format != 'X' && *format != 'c')
+ error ("Invalid format operation %%%c", *format);
+
+ thissize = 30;
+ if (*format == 'c'
+ && (! SINGLE_BYTE_CHAR_P (XINT (args[n]))
+ || XINT (args[n]) == 0))
+ {
+ if (! multibyte)
+ {
+ multibyte = 1;
+ goto retry;
+ }
+ args[n] = Fchar_to_string (args[n]);
+ thissize = STRING_BYTES (XSTRING (args[n]));
+ }
}
#ifdef LISP_FLOAT_TYPE
else if (FLOATP (args[n]) && *format != 's')
{
if (! (*format == 'e' || *format == 'f' || *format == 'g'))
args[n] = Ftruncate (args[n], Qnil);
- total += 30;
- /* We have to put an arbitrary limit on minlen
- since otherwise it could make alloca fail. */
- if (minlen < 1000)
- total += minlen;
+ thissize = 200;
}
#endif
else
/* Anything but a string, convert to a string using princ. */
register Lisp_Object tem;
tem = Fprin1_to_string (args[n], Qt);
+ if (STRING_MULTIBYTE (tem) & ! multibyte)
+ {
+ multibyte = 1;
+ goto retry;
+ }
args[n] = tem;
goto string;
}
+
+ if (thissize < minlen)
+ thissize = minlen;
+
+ total += thissize + 4;
}
- {
- register int nstrings = n + 1;
+ /* Now we can no longer jump to retry.
+ TOTAL and LONGEST_FORMAT are known for certain. */
- /* Allocate twice as many strings as we have %-escapes; floats occupy
- two slots, and we're not sure how many of those we have. */
- register unsigned char **strings
- = (unsigned char **) alloca (2 * nstrings * sizeof (unsigned char *));
- int i;
+ this_format = (unsigned char *) alloca (longest_format + 1);
- i = 0;
- for (n = 0; n < nstrings; n++)
- {
- if (n >= nargs)
- strings[i++] = (unsigned char *) "";
- else if (INTEGERP (args[n]))
- /* We checked above that the corresponding format effector
- isn't %s, which would cause MPV. */
- strings[i++] = (unsigned char *) XINT (args[n]);
-#ifdef LISP_FLOAT_TYPE
- else if (FLOATP (args[n]))
- {
- union { double d; char *half[2]; } u;
+ /* Allocate the space for the result.
+ Note that TOTAL is an overestimate. */
+ if (total < 1000)
+ buf = (char *) alloca (total + 1);
+ else
+ buf = (char *) xmalloc (total + 1);
- u.d = XFLOAT (args[n])->data;
- strings[i++] = (unsigned char *) u.half[0];
- strings[i++] = (unsigned char *) u.half[1];
- }
-#endif
- else if (i == 0)
- /* The first string is treated differently
- because it is the format string. */
- strings[i++] = XSTRING (args[n])->data;
- else
- strings[i++] = (unsigned char *) XSTRING (args[n]);
- }
+ p = buf;
+ nchars = 0;
+ n = 0;
- /* Make room in result for all the non-%-codes in the control string. */
- total += XSTRING (args[0])->size;
+ /* Scan the format and store result in BUF. */
+ format = XSTRING (args[0])->data;
+ maybe_combine_byte = 0;
+ while (format != end)
+ {
+ if (*format == '%')
+ {
+ int minlen;
+ int negative = 0;
+ unsigned char *this_format_start = format;
- /* Format it in bigger and bigger buf's until it all fits. */
- while (1)
- {
- buf = (char *) alloca (total + 1);
- buf[total - 1] = 0;
+ format++;
- length = doprnt_lisp (buf, total + 1, strings[0],
- end, i-1, (char **) strings + 1);
- if (buf[total - 1] == 0)
- break;
+ /* Process a numeric arg and skip it. */
+ minlen = atoi (format);
+ if (minlen < 0)
+ minlen = - minlen, negative = 1;
- total *= 2;
- }
- }
+ while ((*format >= '0' && *format <= '9')
+ || *format == '-' || *format == ' ' || *format == '.')
+ format++;
- /* UNGCPRO; */
- return make_string (buf, length);
+ if (*format++ == '%')
+ {
+ *p++ = '%';
+ nchars++;
+ continue;
+ }
+
+ ++n;
+
+ if (STRINGP (args[n]))
+ {
+ int padding, nbytes;
+ int width = strwidth (XSTRING (args[n])->data,
+ STRING_BYTES (XSTRING (args[n])));
+ int start = nchars;
+
+ /* If spec requires it, pad on right with spaces. */
+ padding = minlen - width;
+ if (! negative)
+ while (padding-- > 0)
+ {
+ *p++ = ' ';
+ nchars++;
+ }
+
+ if (p > buf
+ && multibyte
+ && !ASCII_BYTE_P (*((unsigned char *) p - 1))
+ && STRING_MULTIBYTE (args[n])
+ && !CHAR_HEAD_P (XSTRING (args[n])->data[0]))
+ maybe_combine_byte = 1;
+ nbytes = copy_text (XSTRING (args[n])->data, p,
+ STRING_BYTES (XSTRING (args[n])),
+ STRING_MULTIBYTE (args[n]), multibyte);
+ p += nbytes;
+ nchars += XSTRING (args[n])->size;
+
+ if (negative)
+ while (padding-- > 0)
+ {
+ *p++ = ' ';
+ nchars++;
+ }
+
+ /* If this argument has text properties, record where
+ in the result string it appears. */
+ if (XSTRING (args[n])->intervals)
+ {
+ if (!info)
+ {
+ int nbytes = nargs * sizeof *info;
+ info = (struct info *) alloca (nbytes);
+ bzero (info, nbytes);
+ }
+
+ info[n].start = start;
+ info[n].end = nchars;
+ }
+ }
+ else if (INTEGERP (args[n]) || FLOATP (args[n]))
+ {
+ int this_nchars;
+
+ bcopy (this_format_start, this_format,
+ format - this_format_start);
+ this_format[format - this_format_start] = 0;
+
+ if (INTEGERP (args[n]))
+ sprintf (p, this_format, XINT (args[n]));
+ else
+ sprintf (p, this_format, XFLOAT (args[n])->data);
+
+ if (p > buf
+ && multibyte
+ && !ASCII_BYTE_P (*((unsigned char *) p - 1))
+ && !CHAR_HEAD_P (*((unsigned char *) p)))
+ maybe_combine_byte = 1;
+ this_nchars = strlen (p);
+ p += this_nchars;
+ nchars += this_nchars;
+ }
+ }
+ else if (STRING_MULTIBYTE (args[0]))
+ {
+ /* Copy a whole multibyte character. */
+ if (p > buf
+ && multibyte
+ && !ASCII_BYTE_P (*((unsigned char *) p - 1))
+ && !CHAR_HEAD_P (*format))
+ maybe_combine_byte = 1;
+ *p++ = *format++;
+ while (! CHAR_HEAD_P (*format)) *p++ = *format++;
+ nchars++;
+ }
+ else if (multibyte)
+ {
+ /* Convert a single-byte character to multibyte. */
+ int len = copy_text (format, p, 1, 0, 1);
+
+ p += len;
+ format++;
+ nchars++;
+ }
+ else
+ *p++ = *format++, nchars++;
+ }
+
+ if (maybe_combine_byte)
+ nchars = multibyte_chars_in_text (buf, p - buf);
+ val = make_specified_string (buf, nchars, p - buf, multibyte);
+
+ /* If we allocated BUF with malloc, free it too. */
+ if (total >= 1000)
+ xfree (buf);
+
+ /* If the format string has text properties, or any of the string
+ arguments has text properties, set up text properties of the
+ result string. */
+
+ if (XSTRING (args[0])->intervals || info)
+ {
+ Lisp_Object len, new_len, props;
+ struct gcpro gcpro1;
+
+ /* Add text properties from the format string. */
+ len = make_number (XSTRING (args[0])->size);
+ props = text_property_list (args[0], make_number (0), len, Qnil);
+ GCPRO1 (props);
+
+ if (CONSP (props))
+ {
+ new_len = make_number (XSTRING (val)->size);
+ extend_property_ranges (props, len, new_len);
+ add_text_properties_from_list (val, props, make_number (0));
+ }
+
+ /* Add text properties from arguments. */
+ if (info)
+ for (n = 1; n < nargs; ++n)
+ if (info[n].end)
+ {
+ len = make_number (XSTRING (args[n])->size);
+ new_len = make_number (info[n].end - info[n].start);
+ props = text_property_list (args[n], make_number (0), len, Qnil);
+ extend_property_ranges (props, len, new_len);
+ add_text_properties_from_list (val, props,
+ make_number (info[n].start));
+ }
+
+ UNGCPRO;
+ }
+
+ return val;
}
/* VARARGS 1 */
args[2] = arg2;
args[3] = arg3;
args[4] = arg4;
- doprnt (buf, sizeof buf, string1, (char *)0, 5, args);
+ doprnt (buf, sizeof buf, string1, (char *)0, 5, (char **) args);
#else
doprnt (buf, sizeof buf, string1, (char *)0, 5, &string1 + 1);
#endif
(c1, c2)
register Lisp_Object c1, c2;
{
+ int i1, i2;
CHECK_NUMBER (c1, 0);
CHECK_NUMBER (c2, 1);
- if (XINT (c1) == XINT (c2)
- && (NILP (current_buffer->case_fold_search)
- || DOWNCASE (XFASTINT (c1)) == DOWNCASE (XFASTINT (c2))))
+ if (XINT (c1) == XINT (c2))
return Qt;
- return Qnil;
+ if (NILP (current_buffer->case_fold_search))
+ return Qnil;
+
+ /* Do these in separate statements,
+ then compare the variables.
+ because of the way DOWNCASE uses temp variables. */
+ i1 = DOWNCASE (XFASTINT (c1));
+ i2 = DOWNCASE (XFASTINT (c2));
+ return (i1 == i2 ? Qt : Qnil);
}
\f
/* Transpose the markers in two regions of the current buffer, and
mpos += diff_byte;
else
mpos -= amt2_byte;
- if (mpos > GPT_BYTE) mpos += GAP_SIZE;
- XMARKER (marker)->bufpos = mpos;
+ XMARKER (marker)->bytepos = mpos;
}
mpos = XMARKER (marker)->charpos;
if (mpos >= start1 && mpos < end2)
int start1_byte, start2_byte, len1_byte, len2_byte;
int gap, len1, len_mid, len2;
unsigned char *start1_addr, *start2_addr, *temp;
+ int combined_before_bytes_1, combined_after_bytes_1;
+ int combined_before_bytes_2, combined_after_bytes_2;
+ struct gcpro gcpro1, gcpro2;
#ifdef USE_TEXT_PROPERTIES
INTERVAL cur_intv, tmp_interval1, tmp_interval_mid, tmp_interval2;
len2 = end2 - start2;
if (start2 < end1)
- error ("Transposed regions not properly ordered");
+ error ("Transposed regions overlap");
else if (start1 == end1 || start2 == end2)
- error ("Transposed region may not be of length 0");
+ error ("Transposed region has length 0");
/* The possibilities are:
1. Adjacent (contiguous) regions, or separate but equal regions
start2_byte = CHAR_TO_BYTE (start2);
len1_byte = CHAR_TO_BYTE (end1) - start1_byte;
len2_byte = CHAR_TO_BYTE (end2) - start2_byte;
+
+ if (end1 == start2)
+ {
+ combined_before_bytes_2
+ = count_combining_before (BYTE_POS_ADDR (start2_byte),
+ len2_byte, start1, start1_byte);
+ combined_before_bytes_1
+ = count_combining_before (BYTE_POS_ADDR (start1_byte),
+ len1_byte, end2, start2_byte + len2_byte);
+ combined_after_bytes_1
+ = count_combining_after (BYTE_POS_ADDR (start1_byte),
+ len1_byte, end2, start2_byte + len2_byte);
+ combined_after_bytes_2 = 0;
+ }
+ else
+ {
+ combined_before_bytes_2
+ = count_combining_before (BYTE_POS_ADDR (start2_byte),
+ len2_byte, start1, start1_byte);
+ combined_before_bytes_1
+ = count_combining_before (BYTE_POS_ADDR (start1_byte),
+ len1_byte, start2, start2_byte);
+ combined_after_bytes_2
+ = count_combining_after (BYTE_POS_ADDR (start2_byte),
+ len2_byte, end1, start1_byte + len1_byte);
+ combined_after_bytes_1
+ = count_combining_after (BYTE_POS_ADDR (start1_byte),
+ len1_byte, end2, start2_byte + len2_byte);
+ }
+
+ /* If any combining is going to happen, do this the stupid way,
+ because replace handles combining properly. */
+ if (combined_before_bytes_1 || combined_before_bytes_2
+ || combined_after_bytes_1 || combined_after_bytes_2)
+ {
+ Lisp_Object text1, text2;
+
+ text1 = text2 = Qnil;
+ GCPRO2 (text1, text2);
+
+ text1 = make_buffer_string_both (start1, start1_byte,
+ end1, start1_byte + len1_byte, 1);
+ text2 = make_buffer_string_both (start2, start2_byte,
+ end2, start2_byte + len2_byte, 1);
+
+ transpose_markers (start1, end1, start2, end2,
+ start1_byte, start1_byte + len1_byte,
+ start2_byte, start2_byte + len2_byte);
+
+ replace_range (start2, end2, text1, 1, 0, 0);
+ replace_range (start1, end1, text2, 1, 0, 0);
+
+ UNGCPRO;
+ return Qnil;
+ }
/* Hmmm... how about checking to see if the gap is large
enough to use as the temporary storage? That would avoid an
/* Don't precompute these addresses. We have to compute them
at the last minute, because the relocating allocator might
have moved the buffer around during the xmalloc. */
- start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1_byte);
- start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2_byte);
+ start1_addr = BYTE_POS_ADDR (start1_byte);
+ start2_addr = BYTE_POS_ADDR (start2_byte);
bcopy (start2_addr, temp, len2_byte);
bcopy (start1_addr, start1_addr + len2_byte, len1_byte);
temp = (unsigned char *) xmalloc (len1_byte);
else
temp = (unsigned char *) alloca (len1_byte);
- start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1_byte);
- start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2_byte);
+ start1_addr = BYTE_POS_ADDR (start1_byte);
+ start2_addr = BYTE_POS_ADDR (start2_byte);
bcopy (start1_addr, temp, len1_byte);
bcopy (start2_addr, start1_addr, len2_byte);
bcopy (temp, start1_addr + len2_byte, len1_byte);
temp = (unsigned char *) xmalloc (len1_byte);
else
temp = (unsigned char *) alloca (len1_byte);
- start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1_byte);
- start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2_byte);
+ start1_addr = BYTE_POS_ADDR (start1_byte);
+ start2_addr = BYTE_POS_ADDR (start2_byte);
bcopy (start1_addr, temp, len1_byte);
bcopy (start2_addr, start1_addr, len2_byte);
bcopy (temp, start2_addr, len1_byte);
temp = (unsigned char *) xmalloc (len2_byte);
else
temp = (unsigned char *) alloca (len2_byte);
- start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1_byte);
- start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2_byte);
+ start1_addr = BYTE_POS_ADDR (start1_byte);
+ start2_addr = BYTE_POS_ADDR (start2_byte);
bcopy (start2_addr, temp, len2_byte);
bcopy (start1_addr, start1_addr + len_mid + len2_byte, len1_byte);
safe_bcopy (start1_addr + len1_byte, start1_addr + len2_byte, len_mid);
temp = (unsigned char *) xmalloc (len1_byte);
else
temp = (unsigned char *) alloca (len1_byte);
- start1_addr = BUF_CHAR_ADDRESS (current_buffer, start1_byte);
- start2_addr = BUF_CHAR_ADDRESS (current_buffer, start2_byte);
+ start1_addr = BYTE_POS_ADDR (start1_byte);
+ start2_addr = BYTE_POS_ADDR (start2_byte);
bcopy (start1_addr, temp, len1_byte);
bcopy (start2_addr, start1_addr, len2_byte);
bcopy (start1_addr + len1_byte, start1_addr + len2_byte, len_mid);
defsubr (&Sgoto_char);
defsubr (&Sstring_to_char);
defsubr (&Schar_to_string);
- defsubr (&Ssref);
defsubr (&Sbuffer_substring);
defsubr (&Sbuffer_substring_no_properties);
defsubr (&Sbuffer_string);
defsubr (&Spoint);
defsubr (&Sregion_beginning);
defsubr (&Sregion_end);
+
+ defsubr (&Sline_beginning_position);
+ defsubr (&Sline_end_position);
+
/* defsubr (&Smark); */
/* defsubr (&Sset_mark); */
defsubr (&Ssave_excursion);
defsubr (&Spoint_min);
defsubr (&Spoint_min_marker);
defsubr (&Spoint_max_marker);
-
- defsubr (&Sline_beginning_position);
- defsubr (&Sline_end_position);
+ defsubr (&Sgap_position);
+ defsubr (&Sgap_size);
+ defsubr (&Sposition_bytes);
+ defsubr (&Sbyte_to_position);
defsubr (&Sbobp);
defsubr (&Seobp);