]> code.delx.au - gnu-emacs/blobdiff - src/editfns.c
Restore inadvertently-changed non-ASCII character.
[gnu-emacs] / src / editfns.c
index fcc59979fe131894dec1da0c19e3b6cfc583201a..ae6befd5a7f4d9e5a2ba989e42bb9b7af8595a3f 100644 (file)
@@ -122,7 +122,7 @@ init_editfns ()
   tem = Fstring_equal (Vuser_login_name, Vuser_real_login_name);
   Vuser_full_name = Fuser_full_name (NILP (tem)? make_number (geteuid())
                                     : Vuser_login_name);
-  
+
   p = (unsigned char *) getenv ("NAME");
   if (p)
     Vuser_full_name = build_string (p);
@@ -281,25 +281,25 @@ If you set the marker not to point anywhere, the buffer will have no mark.")
    for the text property PROP.  */
 
 static int
-text_property_eq (prop, pos1, pos2)
+char_property_eq (prop, pos1, pos2)
      Lisp_Object prop;
      Lisp_Object pos1, pos2;
 {
   Lisp_Object pval1, pval2;
 
-  pval1 = Fget_text_property (pos1, prop, Qnil);
-  pval2 = Fget_text_property (pos2, prop, Qnil);
+  pval1 = Fget_char_property (pos1, prop, Qnil);
+  pval2 = Fget_char_property (pos2, prop, Qnil);
 
   return EQ (pval1, pval2);
 }
 
-/* Return the direction from which the text-property PROP would be
+/* Return the direction from which the char-property PROP would be
    inherited by any new text inserted at POS: 1 if it would be
    inherited from the char after POS, -1 if it would be inherited from
    the char before POS, and 0 if from neither.  */
 
 static int
-text_property_stickiness (prop, pos)
+char_property_stickiness (prop, pos)
      Lisp_Object prop;
      Lisp_Object pos;
 {
@@ -311,22 +311,22 @@ text_property_stickiness (prop, pos)
       Lisp_Object prev_pos, rear_non_sticky;
 
       prev_pos = make_number (XINT (pos) - 1);
-      rear_non_sticky = Fget_text_property (prev_pos, Qrear_nonsticky, Qnil);
+      rear_non_sticky = Fget_char_property (prev_pos, Qrear_nonsticky, Qnil);
 
       if (EQ (rear_non_sticky, Qnil)
          || (CONSP (rear_non_sticky)
-             && !Fmemq (prop, rear_non_sticky)))
+             && NILP (Fmemq (prop, rear_non_sticky))))
        /* PROP is not rear-non-sticky, and since this takes precedence over
           any front-stickiness, PROP is inherited from before.  */
        return -1;
     }
 
   /* Consider following character.  */
-  front_sticky = Fget_text_property (pos, Qfront_sticky, Qnil);
+  front_sticky = Fget_char_property (pos, Qfront_sticky, Qnil);
 
   if (EQ (front_sticky, Qt)
       || (CONSP (front_sticky)
-         && Fmemq (prop, front_sticky)))
+         && !NILP (Fmemq (prop, front_sticky))))
     /* PROP is inherited from after.  */
     return 1;
 
@@ -337,14 +337,21 @@ text_property_stickiness (prop, pos)
 /* Symbol for the text property used to mark fields.  */
 Lisp_Object Qfield;
 
+/* A special value for Qfield properties.  */
+Lisp_Object Qboundary;
+
 /* Find the field surrounding POS in *BEG and *END.  If POS is nil,
    the value of point is used instead.
 
    If MERGE_AT_BOUNDARY is nonzero, then if POS is at the very first
-   position of a field, then the beginning of the previous field
-   is returned instead of the beginning of POS's field (since the end of
-   a field is actually also the beginning of the next input
-   field, this behavior is sometimes useful).
+   position of a field, then the beginning of the previous field is
+   returned instead of the beginning of POS's field (since the end of a
+   field is actually also the beginning of the next input field, this
+   behavior is sometimes useful).  Additionally in the MERGE_AT_BOUNDARY
+   true case, if two fields are separated by a field with the special
+   value `boundary', and POS lies within it, then the two separated
+   fields are considered to be adjacent, and POS between them, when
+   finding the beginning and ending of the "merged" field.
 
    Either BEG or END may be 0, in which case the corresponding value
    is not stored.  */
@@ -355,83 +362,107 @@ find_field (pos, merge_at_boundary, beg, end)
      Lisp_Object merge_at_boundary;
      int *beg, *end;
 {
+  /* Fields right before and after the point.  */
+  Lisp_Object before_field, after_field;
   /* 1 if POS counts as the start of a field.  */
   int at_field_start = 0;
   /* 1 if POS counts as the end of a field.  */
   int at_field_end = 0;
-  
+
   if (NILP (pos))
     XSETFASTINT (pos, PT);
   else
     CHECK_NUMBER_COERCE_MARKER (pos, 0);
 
-  if (NILP (merge_at_boundary) && XFASTINT (pos) > BEGV)
-    /* See if we need to handle the case where POS is at beginning of a
-       field, which can also be interpreted as the end of the previous
-       field.  We decide which one by seeing which field the `field'
-       property sticks to.  The case where if MERGE_AT_BOUNDARY is
-       non-nil (see function comment) is actually the more natural one;
-       then we avoid treating the beginning of a field specially.  */
-    {
-      /* First see if POS is actually *at* a boundary. */
-      Lisp_Object after_field, before_field;
-
-      after_field = Fget_text_property (pos, Qfield, Qnil);
-      before_field = Fget_text_property (make_number (XINT (pos) - 1),
-                                        Qfield, Qnil);
-
-      if (! EQ (after_field, before_field))
-       /* We are at a boundary, see which direction is inclusive.  */
+  after_field =
+    Fget_char_property (pos, Qfield, Qnil);
+  before_field =
+    (XFASTINT (pos) > BEGV
+     ? Fget_char_property (make_number (XINT (pos) - 1), Qfield, Qnil)
+     : Qnil);
+
+  /* See if we need to handle the case where MERGE_AT_BOUNDARY is nil
+     and POS is at beginning of a field, which can also be interpreted
+     as the end of the previous field.  Note that the case where if
+     MERGE_AT_BOUNDARY is non-nil (see function comment) is actually the
+     more natural one; then we avoid treating the beginning of a field
+     specially.  */
+  if (NILP (merge_at_boundary) && !EQ (after_field, before_field))
+    /* We are at a boundary, see which direction is inclusive.  We
+       decide by seeing which field the `field' property sticks to.  */
+    {
+      int stickiness = char_property_stickiness (Qfield, pos);
+
+      if (stickiness > 0)
+       at_field_start = 1;
+      else if (stickiness < 0)
+       at_field_end = 1;
+      else
+       /* STICKINESS == 0 means that any inserted text will get a
+          `field' char-property of nil, so check to see if that
+          matches either of the adjacent characters (this being a
+          kind of "stickiness by default").  */
        {
-         int stickiness = text_property_stickiness (Qfield, pos);
-
-         if (stickiness > 0)
-           at_field_start = 1;
-         else if (stickiness < 0)
-           at_field_end = 1;
-         else
-           /* STICKINESS == 0 means that any inserted text will get a
-              `field' text-property of nil, so check to see if that
-              matches either of the adjacent characters (this being a
-              kind of "stickiness by default").  */
-           {
-             if (NILP (before_field))
-               at_field_end = 1; /* Sticks to the left.  */
-             else if (NILP (after_field))
-               at_field_start = 1; /* Sticks to the right.  */
-           }
+         if (NILP (before_field))
+           at_field_end = 1; /* Sticks to the left.  */
+         else if (NILP (after_field))
+           at_field_start = 1; /* Sticks to the right.  */
        }
     }
 
+  /* Note about special `boundary' fields:
+
+     Consider the case where the point (`.') is between the fields `x' and `y':
+
+       xxxx.yyyy
+
+     In this situation, if merge_at_boundary is true, we consider the
+     `x' and `y' fields as forming one big merged field, and so the end
+     of the field is the end of `y'.
+
+     However, if `x' and `y' are separated by a special `boundary' field
+     (a field with a `field' char-property of 'boundary), then we ignore
+     this special field when merging adjacent fields.  Here's the same
+     situation, but with a `boundary' field between the `x' and `y' fields:
+
+       xxx.BBBByyyy
+
+     Here, if point is at the end of `x', the beginning of `y', or
+     anywhere in-between (within the `boundary' field), we merge all
+     three fields and consider the beginning as being the beginning of
+     the `x' field, and the end as being the end of the `y' field.  */
+
   if (beg)
-    {
-      if (at_field_start)
-       /* POS is at the edge of a field, and we should consider it as
-          the beginning of the following field.  */
-       *beg = XFASTINT (pos);
-      else
-       /* Find the previous field boundary.  */
-       {
-         Lisp_Object prev;
-         prev = Fprevious_single_property_change (pos, Qfield, Qnil, Qnil);
-         *beg = NILP (prev) ? BEGV : XFASTINT (prev);
-       }
-    }
+    if (at_field_start)
+      /* POS is at the edge of a field, and we should consider it as
+        the beginning of the following field.  */
+      *beg = XFASTINT (pos);
+    else
+      /* Find the previous field boundary.  */
+      {
+       if (!NILP (merge_at_boundary) && before_field == Qboundary)
+         /* Skip a `boundary' field.  */
+         pos = Fprevious_single_char_property_change (pos, Qfield, Qnil,Qnil);
+
+       pos = Fprevious_single_char_property_change (pos, Qfield, Qnil, Qnil);
+       *beg = NILP (pos) ? BEGV : XFASTINT (pos);
+      }
 
   if (end)
-    {
-      if (at_field_end)
-       /* POS is at the edge of a field, and we should consider it as
-          the end of the previous field.  */
-       *end = XFASTINT (pos);
-      else
-       /* Find the next field boundary.  */
-       {
-         Lisp_Object next;
-         next = Fnext_single_property_change (pos, Qfield, Qnil, Qnil);
-         *end = NILP (next) ? ZV : XFASTINT (next);
-       }
-    }
+    if (at_field_end)
+      /* POS is at the edge of a field, and we should consider it as
+        the end of the previous field.  */
+      *end = XFASTINT (pos);
+    else
+      /* Find the next field boundary.  */
+      {
+       if (!NILP (merge_at_boundary) && after_field == Qboundary)
+         /* Skip a `boundary' field.  */
+         pos = Fnext_single_char_property_change (pos, Qfield, Qnil, Qnil);
+
+       pos = Fnext_single_char_property_change (pos, Qfield, Qnil, Qnil);
+       *end = NILP (pos) ? ZV : XFASTINT (pos);
+      }
 }
 \f
 DEFUN ("delete-field", Fdelete_field, Sdelete_field, 0, 1, 0,
@@ -500,8 +531,9 @@ then the end of the *following* field is returned.")
   return make_number (end);
 }
 
-DEFUN ("constrain-to-field", Fconstrain_to_field, Sconstrain_to_field, 2, 4, 0,
+DEFUN ("constrain-to-field", Fconstrain_to_field, Sconstrain_to_field, 2, 5, 0,
   "Return the position closest to NEW-POS that is in the same field as OLD-POS.\n\
+\n\
 A field is a region of text with the same `field' property.\n\
 If NEW-POS is nil, then the current point is used instead, and set to the\n\
 constrained position if that is is different.\n\
@@ -509,10 +541,12 @@ constrained position if that is is different.\n\
 If OLD-POS is at the boundary of two fields, then the allowable\n\
 positions for NEW-POS depends on the value of the optional argument\n\
 ESCAPE-FROM-EDGE: If ESCAPE-FROM-EDGE is nil, then NEW-POS is\n\
-constrained to the field that has the same `field' text-property\n\
+constrained to the field that has the same `field' char-property\n\
 as any new characters inserted at OLD-POS, whereas if ESCAPE-FROM-EDGE\n\
 is non-nil, NEW-POS is constrained to the union of the two adjacent\n\
-fields.\n\
+fields.  Additionally, if two fields are separated by another field with\n\
+the special value `boundary', then any point within this special field is\n\
+also considered to be `on the boundary'.\n\
 \n\
 If the optional argument ONLY-IN-LINE is non-nil and constraining\n\
 NEW-POS would move it to a different line, NEW-POS is returned\n\
@@ -520,9 +554,13 @@ unconstrained.  This useful for commands that move by line, like\n\
 \\[next-line] or \\[beginning-of-line], which should generally respect field boundaries\n\
 only in the case where they can still move to the right line.\n\
 \n\
+If the optional argument INHIBIT-CAPTURE-PROPERTY is non-nil, and OLD-POS has\n\
+a non-nil property of that name, then any field boundaries are ignored.\n\
+\n\
 Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.")
-  (new_pos, old_pos, escape_from_edge, only_in_line)
-     Lisp_Object new_pos, old_pos, escape_from_edge, only_in_line;
+  (new_pos, old_pos, escape_from_edge, only_in_line, inhibit_capture_property)
+     Lisp_Object new_pos, old_pos;
+     Lisp_Object escape_from_edge, only_in_line, inhibit_capture_property;
 {
   /* If non-zero, then the original point, before re-positioning.  */
   int orig_point = 0;
@@ -536,11 +574,13 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.")
 
   if (NILP (Vinhibit_field_text_motion)
       && !EQ (new_pos, old_pos)
-      && !text_property_eq (Qfield, new_pos, old_pos))
+      && !char_property_eq (Qfield, new_pos, old_pos)
+      && (NILP (inhibit_capture_property)
+         || NILP (Fget_char_property(old_pos, inhibit_capture_property, Qnil))))
     /* NEW_POS is not within the same field as OLD_POS; try to
        move NEW_POS so that it is.  */
     {
-      int fwd;
+      int fwd, shortage;
       Lisp_Object field_bound;
 
       CHECK_NUMBER_COERCE_MARKER (new_pos, 0);
@@ -553,20 +593,23 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.")
       else
        field_bound = Ffield_beginning (old_pos, escape_from_edge);
 
-      if (/* If ONLY_IN_LINE is non-nil, we only constrain NEW_POS if doing
-            so would remain within the same line.  */
-         NILP (only_in_line)
-         /* In that case, see if ESCAPE_FROM_EDGE caused FIELD_BOUND
-             to jump to the other side of NEW_POS, which would mean
-             that NEW_POS is already acceptable, and that we don't
-             have to do the line-check.  */
-         || ((XFASTINT (field_bound) < XFASTINT (new_pos)) ? !fwd : fwd)
-         /* If not, see if there's no newline intervening between
-             NEW_POS and FIELD_BOUND.  */
-         || (find_before_next_newline (XFASTINT (new_pos),
-                                       XFASTINT (field_bound),
-                                       fwd ? -1 : 1)
-             == XFASTINT (field_bound)))
+      if (/* See if ESCAPE_FROM_EDGE caused FIELD_BOUND to jump to the
+             other side of NEW_POS, which would mean that NEW_POS is
+             already acceptable, and it's not necessary to constrain it
+             to FIELD_BOUND.  */
+         ((XFASTINT (field_bound) < XFASTINT (new_pos)) ? fwd : !fwd)
+         /* NEW_POS should be constrained, but only if either
+            ONLY_IN_LINE is nil (in which case any constraint is OK),
+            or NEW_POS and FIELD_BOUND are on the same line (in which
+            case the constraint is OK even if ONLY_IN_LINE is non-nil). */
+         && (NILP (only_in_line)
+             /* This is the ONLY_IN_LINE case, check that NEW_POS and
+                FIELD_BOUND are on the same line by seeing whether
+                there's an intervening newline or not.  */
+             || (scan_buffer ('\n',
+                              XFASTINT (new_pos), XFASTINT (field_bound),
+                              fwd ? -1 : 1, &shortage, 1),
+                 shortage != 0)))
        /* Constrain NEW_POS to FIELD_BOUND.  */
        new_pos = field_bound;
 
@@ -609,7 +652,7 @@ This function does not move point.")
   /* Return END constrained to the current input field.  */
   return Fconstrain_to_field (make_number (end), make_number (orig),
                              XINT (n) != 1 ? Qt : Qnil,
-                             Qt);
+                             Qt, Qnil);
 }
 
 DEFUN ("line-end-position", Fline_end_position, Sline_end_position,
@@ -633,7 +676,7 @@ This function does not move point.")
 
   /* Return END_POS constrained to the current input field.  */
   return Fconstrain_to_field (make_number (end_pos), make_number (orig),
-                             Qnil, Qt);
+                             Qnil, Qt, Qnil);
 }
 \f
 Lisp_Object
@@ -645,7 +688,7 @@ save_excursion_save ()
   return Fcons (Fpoint_marker (),
                Fcons (Fcopy_marker (current_buffer->mark, Qnil),
                       Fcons (visible ? Qt : Qnil,
-                             current_buffer->mark_active)));                  
+                             current_buffer->mark_active)));
 }
 
 Lisp_Object
@@ -843,10 +886,7 @@ If BYTEPOS is out of range, the value is nil.")
 \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\
-If `enable-multibyte-characters' is nil or point is not\n\
- at character boundary,  multibyte form is ignored,\n\
- and only one byte following point is returned as a character.")
+At the end of the buffer or accessible region, return 0.")
   ()
 {
   Lisp_Object temp;
@@ -859,10 +899,7 @@ If `enable-multibyte-characters' is nil or point is not\n\
 
 DEFUN ("preceding-char", Fprevious_char, Sprevious_char, 0, 0, 0,
   "Return the character preceding point, as a number.\n\
-At the beginning of the buffer or accessible region, return 0.\n\
-If `enable-multibyte-characters' is nil or point is not\n\
- at character boundary, multi-byte form is ignored,\n\
- and only one byte preceding point is returned as a character.")
+At the beginning of the buffer or accessible region, return 0.")
   ()
 {
   Lisp_Object temp;
@@ -944,7 +981,7 @@ If POS is out of range, the value is nil.")
       CHECK_NUMBER_COERCE_MARKER (pos, 0);
       if (XINT (pos) < BEGV || XINT (pos) >= ZV)
        return Qnil;
-      
+
       pos_byte = CHAR_TO_BYTE (XINT (pos));
     }
 
@@ -1070,22 +1107,22 @@ name, or nil if there is no such user.")
   Lisp_Object full;
 
   if (NILP (uid))
-    return Vuser_full_name; 
+    return Vuser_full_name;
   else if (NUMBERP (uid))
     pw = (struct passwd *) getpwuid (XINT (uid));
-  else if (STRINGP (uid)) 
+  else if (STRINGP (uid))
     pw = (struct passwd *) getpwnam (XSTRING (uid)->data);
   else
     error ("Invalid UID specification");
 
   if (!pw)
     return Qnil;
-  
+
   p = (unsigned char *) USER_FULL_NAME;
   /* Chop off everything after the first comma. */
   q = (unsigned char *) index (p, ',');
   full = make_string (p, q ? q - p : strlen (p));
-  
+
 #ifdef AMPERSAND_FULL_NAME
   p = XSTRING (full)->data;
   q = (unsigned char *) index (p, '&');
@@ -1157,12 +1194,25 @@ resolution finer than a second.")
 \f
 
 static int
-lisp_time_argument (specified_time, result)
+lisp_time_argument (specified_time, result, usec)
      Lisp_Object specified_time;
      time_t *result;
+     int *usec;
 {
   if (NILP (specified_time))
-    return time (result) != -1;
+    {
+      if (usec)
+        {
+          EMACS_TIME t;
+
+          EMACS_GET_TIME (t);
+          *usec = EMACS_USECS (t);
+          *result = EMACS_SECS (t);
+          return 1;
+        }
+      else
+        return time (result) != -1;
+    }
   else
     {
       Lisp_Object high, low;
@@ -1170,13 +1220,49 @@ lisp_time_argument (specified_time, result)
       CHECK_NUMBER (high, 0);
       low = Fcdr (specified_time);
       if (CONSP (low))
-       low = Fcar (low);
+        {
+          if (usec)
+            {
+              Lisp_Object usec_l = Fcdr (low);
+              if (CONSP (usec_l))
+                usec_l = Fcar (usec_l);
+              if (NILP (usec_l))
+                *usec = 0;
+              else
+                {
+                  CHECK_NUMBER (usec_l, 0);
+                  *usec = XINT (usec_l);
+                }
+            }
+          low = Fcar (low);
+        }
+      else if (usec)
+        *usec = 0;
       CHECK_NUMBER (low, 0);
       *result = (XINT (high) << 16) + (XINT (low) & 0xffff);
       return *result >> 16 == XINT (high);
     }
 }
 
+DEFUN ("float-time", Ffloat_time, Sfloat_time, 0, 1, 0,
+  "Return the current time, as a float number of seconds since the epoch.\n\
+If an argument is given, it specifies a time to convert to float\n\
+instead of the current time.  The argument should have the forms:\n\
+ (HIGH . LOW) or (HIGH LOW USEC) or (HIGH LOW . USEC).\n\
+Thus, you can use times obtained from `current-time'\n\
+and from `file-attributes'.")
+  (specified_time)
+     Lisp_Object specified_time;
+{
+  time_t sec;
+  int usec;
+
+  if (! lisp_time_argument (specified_time, &sec, &usec))
+    error ("Invalid time specification");
+
+  return make_float (sec + usec * 0.0000001);
+}
+
 /* Write information into buffer S of size MAXSIZE, according to the
    FORMAT of length FORMAT_LEN, using time information taken from *TP.
    Default to Universal Time if UT is nonzero, local time otherwise.
@@ -1294,7 +1380,7 @@ DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
 
   CHECK_STRING (format_string, 1);
 
-  if (! lisp_time_argument (time, &value))
+  if (! lisp_time_argument (time, &value, NULL))
     error ("Invalid time specification");
 
   format_string = code_convert_string_norecord (format_string,
@@ -1351,8 +1437,8 @@ ZONE is an integer indicating the number of seconds east of Greenwich.\n\
   struct tm save_tm;
   struct tm *decoded_time;
   Lisp_Object list_args[9];
-  
-  if (! lisp_time_argument (specified_time, &time_spec))
+
+  if (! lisp_time_argument (specified_time, &time_spec, NULL))
     error ("Invalid time specification");
 
   decoded_time = localtime (&time_spec);
@@ -1426,7 +1512,7 @@ If you want them to stand for years in this century, you must do that yourself."
       char tzbuf[100];
       char *tzstring;
       char **oldenv = environ, **newenv;
-      
+
       if (EQ (zone, Qt))
        tzstring = "UTC0";
       else if (STRINGP (zone))
@@ -1441,7 +1527,7 @@ If you want them to stand for years in this century, you must do that yourself."
       else
        error ("Invalid time zone specification");
 
-      /* Set TZ before calling mktime; merely adjusting mktime's returned 
+      /* Set TZ before calling mktime; merely adjusting mktime's returned
         value doesn't suffice, since that would mishandle leap seconds.  */
       set_time_zone_rule (tzstring);
 
@@ -1484,7 +1570,7 @@ and from `file-attributes'.")
   char buf[30];
   register char *tem;
 
-  if (! lisp_time_argument (specified_time, &value))
+  if (! lisp_time_argument (specified_time, &value, NULL))
     value = -1;
   tem = (char *) ctime (&value);
 
@@ -1544,7 +1630,7 @@ the data it can't find.")
   struct tm *t;
   struct tm gmt;
 
-  if (lisp_time_argument (specified_time, &value)
+  if (lisp_time_argument (specified_time, &value, NULL)
       && (t = gmtime (&value)) != 0
       && (gmt = *t, t = localtime (&value)) != 0)
     {
@@ -1610,7 +1696,7 @@ If TZ is t, use Universal Time.")
 /* These two values are known to load tz files in buggy implementations,
    i.e. Solaris 1 executables running under either Solaris 1 or Solaris 2.
    Their values shouldn't matter in non-buggy implementations.
-   We don't use string literals for these strings, 
+   We don't use string literals for these strings,
    since if a string in the environment is in readonly
    storage, it runs afoul of bugs in SVR4 and Solaris 2.3.
    See Sun bugs 1113095 and 1114114, ``Timezone routines
@@ -2280,12 +2366,13 @@ Both characters must have the same length of multi-byte form.")
 #define COMBINING_BOTH (COMBINING_BEFORE | COMBINING_AFTER)
   int maybe_byte_combining = COMBINING_NO;
   int last_changed;
+  int multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
 
   validate_region (&start, &end);
   CHECK_NUMBER (fromchar, 2);
   CHECK_NUMBER (tochar, 3);
 
-  if (! NILP (current_buffer->enable_multibyte_characters))
+  if (multibyte_p)
     {
       len = CHAR_STRING (XFASTINT (fromchar), fromstr);
       if (CHAR_STRING (XFASTINT (tochar), tostr) != len)
@@ -2341,7 +2428,10 @@ Both characters must have the same length of multi-byte form.")
          stop = end_byte;
        }
       p = BYTE_POS_ADDR (pos_byte);
-      INC_POS (pos_byte_next);
+      if (multibyte_p)
+       INC_POS (pos_byte_next);
+      else
+       ++pos_byte_next;
       if (pos_byte_next - pos_byte == len
          && p[0] == fromstr[0]
          && (len == 1
@@ -2364,7 +2454,7 @@ Both characters must have the same length of multi-byte form.")
            }
 
          /* Take care of the case where the new character
-            combines with neighboring bytes.  */ 
+            combines with neighboring bytes.  */
          if (maybe_byte_combining
              && (maybe_byte_combining == COMBINING_AFTER
                  ? (pos_byte_next < Z_BYTE
@@ -2395,7 +2485,7 @@ Both characters must have the same length of multi-byte form.")
                pos--;
              else
                INC_POS (pos_byte_next);
-               
+
              if (! NILP (noundo))
                current_buffer->undo_list = tem;
 
@@ -2473,7 +2563,7 @@ It returns the number of characters changed.")
          if (nc != oc)
            {
              /* Take care of the case where the new character
-                combines with neighboring bytes.  */ 
+                combines with neighboring bytes.  */
              if (!ASCII_BYTE_P (nc)
                  && (CHAR_HEAD_P (nc)
                      ? ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1))
@@ -2777,7 +2867,7 @@ minibuffer contents show.")
 {
 #ifdef HAVE_MENUS
   if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
-      && NILP (use_dialog_box))
+      && use_dialog_box)
     return Fmessage_box (nargs, args);
 #endif
   return Fmessage (nargs, args);
@@ -2810,7 +2900,7 @@ properties to add to the result ")
 
   properties = string = Qnil;
   GCPRO2 (properties, string);
-  
+
   /* First argument must be a string.  */
   CHECK_STRING (args[0], 0);
   string = Fcopy_sequence (args[0]);
@@ -2945,7 +3035,10 @@ Use %% to put a single % into the output.")
          }
        else if (SYMBOLP (args[n]))
          {
-           XSETSTRING (args[n], XSYMBOL (args[n])->name);
+           /* Use a temp var to avoid problems when ENABLE_CHECKING
+              is turned on.  */
+           struct Lisp_String *t = XSYMBOL (args[n])->name;
+           XSETSTRING (args[n], t);
            if (STRING_MULTIBYTE (args[n]) && ! multibyte)
              {
                multibyte = 1;
@@ -2963,7 +3056,6 @@ Use %% to put a single % into the output.")
        /* Would get MPV otherwise, since Lisp_Int's `point' to low memory.  */
        else if (INTEGERP (args[n]) && *format != 's')
          {
-#ifdef LISP_FLOAT_TYPE
            /* The following loop assumes the Lisp type indicates
               the proper way to pass the argument.
               So make sure we have a flonum if the argument should
@@ -2971,12 +3063,11 @@ Use %% to put a single % into the output.")
            if (*format == 'e' || *format == 'f' || *format == 'g')
              args[n] = Ffloat (args[n]);
            else
-#endif
              if (*format != 'd' && *format != 'o' && *format != 'x'
                  && *format != 'i' && *format != 'X' && *format != 'c')
                error ("Invalid format operation %%%c", *format);
 
-           thissize = 30;      
+           thissize = 30;
            if (*format == 'c'
                && (! SINGLE_BYTE_CHAR_P (XINT (args[n]))
                    || XINT (args[n]) == 0))
@@ -2990,14 +3081,12 @@ Use %% to put a single % into the output.")
                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);
            thissize = 200;
          }
-#endif
        else
          {
            /* Anything but a string, convert to a string using princ.  */
@@ -3011,7 +3100,7 @@ Use %% to put a single % into the output.")
            args[n] = tem;
            goto string;
          }
-       
+
        if (thissize < minlen)
          thissize = minlen;
 
@@ -3110,7 +3199,7 @@ Use %% to put a single % into the output.")
                      info = (struct info *) alloca (nbytes);
                      bzero (info, nbytes);
                    }
-                 
+
                  info[n].start = start;
                  info[n].end = nchars;
                }
@@ -3134,7 +3223,10 @@ Use %% to put a single % into the output.")
                  && !CHAR_HEAD_P (*((unsigned char *) p)))
                maybe_combine_byte = 1;
              this_nchars = strlen (p);
-             p += this_nchars;
+             if (multibyte)
+               p += str_to_multibyte (p, buf + total - p, this_nchars);
+             else
+               p += this_nchars;
              nchars += this_nchars;
            }
        }
@@ -3174,17 +3266,17 @@ Use %% to put a single % into the output.")
   /* 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);
@@ -3201,6 +3293,10 @@ Use %% to put a single % into the output.")
              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);
+             /* If successive arguments have properites, be sure that
+                the value of `composition' property be the copy.  */
+             if (n > 1 && info[n - 1].end)
+               make_composition_value_copy (props);
              add_text_properties_from_list (val, props,
                                             make_number (info[n].start));
            }
@@ -3273,7 +3369,7 @@ Case is ignored if `case-fold-search' is non-nil in the current buffer.")
    Traverses the entire marker list of the buffer to do so, adding an
    appropriate amount to some, subtracting from some, and leaving the
    rest untouched.  Most of this is copied from adjust_markers in insdel.c.
-  
+
    It's the caller's job to ensure that START1 <= END1 <= START2 <= END2.  */
 
 void
@@ -3310,7 +3406,7 @@ transpose_markers (start1, end1, start2, end2,
   /* The difference between the region's lengths */
   diff = (end2 - start2) - (end1 - start1);
   diff_byte = (end2_byte - start2_byte) - (end1_byte - start1_byte);
-  
+
   /* For shifting each marker in a region by the length of the other
      region plus the distance between the regions.  */
   amt1 = (end2 - start2) + (start2 - end1);
@@ -3362,8 +3458,6 @@ Transposing beyond buffer boundaries is an error.")
   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;
 
   INTERVAL cur_intv, tmp_interval1, tmp_interval_mid, tmp_interval2;
@@ -3401,7 +3495,7 @@ Transposing beyond buffer boundaries is an error.")
      1. Adjacent (contiguous) regions, or separate but equal regions
      (no, really equal, in this case!), or
      2. Separate regions of unequal size.
-     
+
      The worst case is usually No. 2.  It means that (aside from
      potential need for getting the gap out of the way), there also
      needs to be a shifting of the text between the two regions.  So
@@ -3434,61 +3528,31 @@ Transposing beyond buffer boundaries is an error.")
   len1_byte = CHAR_TO_BYTE (end1) - start1_byte;
   len2_byte = CHAR_TO_BYTE (end2) - start2_byte;
 
+#ifdef BYTE_COMBINING_DEBUG
   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;
+      if (count_combining_before (BYTE_POS_ADDR (start2_byte),
+                                 len2_byte, start1, start1_byte)
+         || count_combining_before (BYTE_POS_ADDR (start1_byte),
+                                    len1_byte, end2, start2_byte + len2_byte)
+         || count_combining_after (BYTE_POS_ADDR (start1_byte),
+                                   len1_byte, end2, start2_byte + len2_byte))
+       abort ();
     }
   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 (count_combining_before (BYTE_POS_ADDR (start2_byte),
+                                 len2_byte, start1, start1_byte)
+         || count_combining_before (BYTE_POS_ADDR (start1_byte),
+                                    len1_byte, start2, start2_byte)
+         || count_combining_after (BYTE_POS_ADDR (start2_byte),
+                                   len2_byte, end1, start1_byte + len1_byte)
+         || count_combining_after (BYTE_POS_ADDR (start1_byte),
+                                   len1_byte, end2, start2_byte + len2_byte))
+       abort ();
     }
+#endif
 
-  /* 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
      allocation... interesting.  Later, don't fool with it now.  */
@@ -3526,7 +3590,7 @@ Transposing beyond buffer boundaries is an error.")
           bcopy (start1_addr, start1_addr + len2_byte, len1_byte);
           bcopy (temp, start1_addr, len2_byte);
          if (len2_byte > 20000)
-           free (temp);
+           xfree (temp);
         }
       else
        /* First region not smaller than second.  */
@@ -3541,7 +3605,7 @@ Transposing beyond buffer boundaries is an error.")
           bcopy (start2_addr, start1_addr, len2_byte);
           bcopy (temp, start1_addr + len2_byte, len1_byte);
          if (len1_byte > 20000)
-           free (temp);
+           xfree (temp);
         }
       graft_intervals_into_buffer (tmp_interval1, start1 + len2,
                                    len1, current_buffer, 0);
@@ -3579,7 +3643,7 @@ Transposing beyond buffer boundaries is an error.")
           bcopy (start2_addr, start1_addr, len2_byte);
           bcopy (temp, start2_addr, len1_byte);
          if (len1_byte > 20000)
-           free (temp);
+           xfree (temp);
           graft_intervals_into_buffer (tmp_interval1, start2,
                                        len1, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval2, start1,
@@ -3609,7 +3673,7 @@ Transposing beyond buffer boundaries is an error.")
           safe_bcopy (start1_addr + len1_byte, start1_addr + len2_byte, len_mid);
           bcopy (temp, start1_addr, len2_byte);
          if (len2_byte > 20000)
-           free (temp);
+           xfree (temp);
           graft_intervals_into_buffer (tmp_interval1, end2 - len1,
                                        len1, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
@@ -3641,7 +3705,7 @@ Transposing beyond buffer boundaries is an error.")
           bcopy (start1_addr + len1_byte, start1_addr + len2_byte, len_mid);
           bcopy (temp, start1_addr + len2_byte + len_mid, len1_byte);
          if (len1_byte > 20000)
-           free (temp);
+           xfree (temp);
           graft_intervals_into_buffer (tmp_interval1, end2 - len1,
                                        len1, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
@@ -3710,7 +3774,7 @@ functions if all the text being accessed has this property.");
 
   DEFVAR_LISP ("system-name", &Vsystem_name,
               "The name of the machine Emacs is running on.");
-  
+
   DEFVAR_LISP ("user-full-name", &Vuser_full_name,
               "The full name of the user logged in.");
 
@@ -3737,6 +3801,8 @@ functions if all the text being accessed has this property.");
 
   staticpro (&Qfield);
   Qfield = intern ("field");
+  staticpro (&Qboundary);
+  Qboundary = intern ("boundary");
   defsubr (&Sfield_beginning);
   defsubr (&Sfield_end);
   defsubr (&Sfield_string);
@@ -3784,6 +3850,7 @@ functions if all the text being accessed has this property.");
   defsubr (&Semacs_pid);
   defsubr (&Scurrent_time);
   defsubr (&Sformat_time_string);
+  defsubr (&Sfloat_time);
   defsubr (&Sdecode_time);
   defsubr (&Sencode_time);
   defsubr (&Scurrent_time_string);