]> code.delx.au - gnu-emacs/blobdiff - src/editfns.c
(Fmessage): Doc fixes.
[gnu-emacs] / src / editfns.c
index b057795f2edc3aa7a34393bceda962baf35377fd..39f8f87c673513ddd87e39c190c204d21a4f1e6c 100644 (file)
@@ -1,6 +1,7 @@
 /* Lisp functions pertaining to editing.
-   Copyright (C) 1985,86,87,89,93,94,95,96,97,98, 1999, 2000, 2001, 02, 2003
-       Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1989, 1993, 1994, 1995, 1996,
+                 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+                 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -16,16 +17,15 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 
 #include <config.h>
 #include <sys/types.h>
+#include <stdio.h>
 
-#ifdef VMS
-#include "vms-pwd.h"
-#else
+#ifdef HAVE_PWD_H
 #include <pwd.h>
 #endif
 
@@ -33,23 +33,30 @@ Boston, MA 02111-1307, USA.  */
 #include <unistd.h>
 #endif
 
-/* Without this, sprintf on Mac OS Classic will produce wrong
-   result.  */
-#ifdef MAC_OS8
-#include <stdio.h>
+#ifdef HAVE_SYS_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+
+#include "lisp.h"
+
+/* systime.h includes <sys/time.h> which, on some systems, is required
+   for <sys/resource.h>; thus systime.h must be included before
+   <sys/resource.h> */
+#include "systime.h"
+
+#if defined HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
 #endif
 
 #include <ctype.h>
 
-#include "lisp.h"
 #include "intervals.h"
 #include "buffer.h"
 #include "charset.h"
 #include "coding.h"
 #include "frame.h"
 #include "window.h"
-
-#include "systime.h"
+#include "blockinput.h"
 
 #ifdef STDC_HEADERS
 #include <float.h>
@@ -66,14 +73,22 @@ Boston, MA 02111-1307, USA.  */
 extern char **environ;
 #endif
 
-extern Lisp_Object make_time P_ ((time_t));
+#define TM_YEAR_BASE 1900
+
+/* Nonzero if TM_YEAR is a struct tm's tm_year value that causes
+   asctime to have well-defined behavior.  */
+#ifndef TM_YEAR_IN_ASCTIME_RANGE
+# define TM_YEAR_IN_ASCTIME_RANGE(tm_year) \
+    (1000 - TM_YEAR_BASE <= (tm_year) && (tm_year) <= 9999 - TM_YEAR_BASE)
+#endif
+
 extern size_t emacs_strftimeu P_ ((char *, size_t, const char *,
                                   const struct tm *, int));
 static int tm_diff P_ ((struct tm *, struct tm *));
 static void find_field P_ ((Lisp_Object, Lisp_Object, Lisp_Object, int *, Lisp_Object, int *));
 static void update_buffer_properties P_ ((int, int));
 static Lisp_Object region_limit P_ ((int));
-static int lisp_time_argument P_ ((Lisp_Object, time_t *, int *));
+int lisp_time_argument P_ ((Lisp_Object, time_t *, int *));
 static size_t emacs_memftimeu P_ ((char *, size_t, const char *,
                                   size_t, const struct tm *, int));
 static void general_insert_function P_ ((void (*) (const unsigned char *, int),
@@ -104,6 +119,7 @@ Lisp_Object Vsystem_name;
 Lisp_Object Vuser_real_login_name;     /* login name of current user ID */
 Lisp_Object Vuser_full_name;           /* full name of current user */
 Lisp_Object Vuser_login_name;          /* user name from LOGNAME or USER */
+Lisp_Object Voperating_system_release;  /* Operating System Release */
 
 /* Symbol for the text property used to mark fields.  */
 
@@ -168,6 +184,16 @@ init_editfns ()
     Vuser_full_name = build_string (p);
   else if (NILP (Vuser_full_name))
     Vuser_full_name = build_string ("unknown");
+
+#ifdef HAVE_SYS_UTSNAME_H
+  {
+    struct utsname uts;
+    uname (&uts);
+    Voperating_system_release = build_string (uts.release);
+  }
+#else
+  Voperating_system_release = Qnil;
+#endif
 }
 \f
 DEFUN ("char-to-string", Fchar_to_string, Schar_to_string, 1, 1, 0,
@@ -248,10 +274,7 @@ clip_to_bounds (lower, num, upper)
 
 DEFUN ("goto-char", Fgoto_char, Sgoto_char, 1, 1, "NGoto char: ",
        doc: /* Set point to POSITION, a number or marker.
-Beginning of buffer is position (point-min), end is (point-max).
-If the position is in the middle of a multibyte form,
-the actual point is set at the head of the multibyte form
-except in the case that `enable-multibyte-characters' is nil.  */)
+Beginning of buffer is position (point-min), end is (point-max).  */)
      (position)
      register Lisp_Object position;
 {
@@ -293,13 +316,13 @@ region_limit (beginningp)
   if (!NILP (Vtransient_mark_mode)
       && NILP (Vmark_even_if_inactive)
       && NILP (current_buffer->mark_active))
-    Fsignal (Qmark_inactive, Qnil);
+    xsignal0 (Qmark_inactive);
 
   m = Fmarker_position (current_buffer->mark);
   if (NILP (m))
     error ("The mark is not set now, so there is no region");
 
-  if ((PT < XFASTINT (m)) == beginningp)
+  if ((PT < XFASTINT (m)) == (beginningp != 0))
     m = make_number (PT);
   return m;
 }
@@ -469,7 +492,7 @@ get_pos_property (position, prop, object)
 }
 
 /* Find the field surrounding POS in *BEG and *END.  If POS is nil,
-   the value of point is used instead.  If BEG or END null,
+   the value of point is used instead.  If BEG or END is null,
    means don't store the beginning or end of the field.
 
    BEG_LIMIT and END_LIMIT serve to limit the ranged of the returned
@@ -513,7 +536,9 @@ find_field (pos, merge_at_boundary, beg_limit, beg, end_limit, end)
     = (XFASTINT (pos) > BEGV
        ? get_char_property_and_overlay (make_number (XINT (pos) - 1),
                                        Qfield, Qnil, NULL)
-       : Qnil);
+       /* Using nil here would be a more obvious choice, but it would
+          fail when the buffer starts with a non-sticky field.  */
+       : after_field);
 
   /* 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
@@ -704,6 +729,8 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.  */)
 {
   /* If non-zero, then the original point, before re-positioning.  */
   int orig_point = 0;
+  int fwd;
+  Lisp_Object prev_old, prev_new;
 
   if (NILP (new_pos))
     /* Use the current point, and afterwards, set it.  */
@@ -712,23 +739,40 @@ Field boundaries are not noticed if `inhibit-field-text-motion' is non-nil.  */)
       XSETFASTINT (new_pos, PT);
     }
 
+  CHECK_NUMBER_COERCE_MARKER (new_pos);
+  CHECK_NUMBER_COERCE_MARKER (old_pos);
+
+  fwd = (XFASTINT (new_pos) > XFASTINT (old_pos));
+
+  prev_old = make_number (XFASTINT (old_pos) - 1);
+  prev_new = make_number (XFASTINT (new_pos) - 1);
+
   if (NILP (Vinhibit_field_text_motion)
       && !EQ (new_pos, old_pos)
       && (!NILP (Fget_char_property (new_pos, Qfield, Qnil))
-         || !NILP (Fget_char_property (old_pos, Qfield, Qnil)))
+          || !NILP (Fget_char_property (old_pos, Qfield, Qnil))
+          /* To recognize field boundaries, we must also look at the
+             previous positions; we could use `get_pos_property'
+             instead, but in itself that would fail inside non-sticky
+             fields (like comint prompts).  */
+          || (XFASTINT (new_pos) > BEGV
+              && !NILP (Fget_char_property (prev_new, Qfield, Qnil)))
+          || (XFASTINT (old_pos) > BEGV
+              && !NILP (Fget_char_property (prev_old, Qfield, Qnil))))
       && (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.  */
+          /* Field boundaries are again a problem; but now we must
+             decide the case exactly, so we need to call
+             `get_pos_property' as well.  */
+          || (NILP (get_pos_property (old_pos, inhibit_capture_property, Qnil))
+              && (XFASTINT (old_pos) <= BEGV
+                  || NILP (Fget_char_property (old_pos, inhibit_capture_property, Qnil))
+                  || NILP (Fget_char_property (prev_old, inhibit_capture_property, Qnil))))))
+    /* It is possible that NEW_POS is not within the same field as
+       OLD_POS; try to move NEW_POS so that it is.  */
     {
-      int fwd, shortage;
+      int shortage;
       Lisp_Object field_bound;
 
-      CHECK_NUMBER_COERCE_MARKER (new_pos);
-      CHECK_NUMBER_COERCE_MARKER (old_pos);
-
-      fwd = (XFASTINT (new_pos) > XFASTINT (old_pos));
-
       if (fwd)
        field_bound = Ffield_end (old_pos, escape_from_edge, new_pos);
       else
@@ -769,9 +813,10 @@ DEFUN ("line-beginning-position",
 With argument N not nil or 1, move forward N - 1 lines first.
 If scan reaches end of buffer, return that position.
 
-The scan does not cross a field boundary unless doing so would move
-beyond there to a different line; if N is nil or 1, and scan starts at a
-field boundary, the scan stops as soon as it starts.  To ignore field
+This function constrains the returned position to the current field
+unless that would be on a different line than the original,
+unconstrained result.  If N is nil or 1, and a front-sticky field
+starts at point, the scan stops as soon as it starts.  To ignore field
 boundaries bind `inhibit-field-text-motion' to t.
 
 This function does not move point.  */)
@@ -779,6 +824,8 @@ This function does not move point.  */)
      Lisp_Object n;
 {
   int orig, orig_byte, end;
+  int count = SPECPDL_INDEX ();
+  specbind (Qinhibit_point_motion_hooks, Qt);
 
   if (NILP (n))
     XSETFASTINT (n, 1);
@@ -792,6 +839,8 @@ This function does not move point.  */)
 
   SET_PT_BOTH (orig, orig_byte);
 
+  unbind_to (count, Qnil);
+
   /* Return END constrained to the current input field.  */
   return Fconstrain_to_field (make_number (end), make_number (orig),
                              XINT (n) != 1 ? Qt : Qnil,
@@ -803,9 +852,10 @@ DEFUN ("line-end-position", Fline_end_position, Sline_end_position, 0, 1, 0,
 With argument N not nil or 1, move forward N - 1 lines first.
 If scan reaches end of buffer, return that position.
 
-The scan does not cross a field boundary unless doing so would move
-beyond there to a different line; if N is nil or 1, and scan starts at a
-field boundary, the scan stops as soon as it starts.  To ignore field
+This function constrains the returned position to the current field
+unless that would be on a different line than the original,
+unconstrained result.  If N is nil or 1, and a rear-sticky field ends
+at point, the scan stops as soon as it starts.  To ignore field
 boundaries bind `inhibit-field-text-motion' to t.
 
 This function does not move point.  */)
@@ -1138,7 +1188,7 @@ DEFUN ("eolp", Feolp, Seolp, 0, 0, 0,
 
 DEFUN ("char-after", Fchar_after, Schar_after, 0, 1, 0,
        doc: /* Return character in current buffer at position POS.
-POS is an integer or a marker.
+POS is an integer or a marker and defaults to point.
 If POS is out of range, the value is nil.  */)
      (pos)
      Lisp_Object pos;
@@ -1171,7 +1221,7 @@ If POS is out of range, the value is nil.  */)
 
 DEFUN ("char-before", Fchar_before, Schar_before, 0, 1, 0,
        doc: /* Return character in current buffer preceding position POS.
-POS is an integer or a marker.
+POS is an integer or a marker and defaults to point.
 If POS is out of range, the value is nil.  */)
      (pos)
      Lisp_Object pos;
@@ -1218,7 +1268,7 @@ If POS is out of range, the value is nil.  */)
 DEFUN ("user-login-name", Fuser_login_name, Suser_login_name, 0, 1, 0,
        doc: /* Return the name under which the user logged in, as a string.
 This is based on the effective uid, not the real uid.
-Also, if the environment variable LOGNAME or USER is set,
+Also, if the environment variables LOGNAME or USER are set,
 that determines the value of this function.
 
 If optional argument UID is an integer, return the login name of the user
@@ -1238,7 +1288,9 @@ with that uid, or nil if there is no such user.  */)
     return Vuser_login_name;
 
   CHECK_NUMBER (uid);
+  BLOCK_INPUT;
   pw = (struct passwd *) getpwuid (XINT (uid));
+  UNBLOCK_INPUT;
   return (pw ? build_string (pw->pw_name) : Qnil);
 }
 
@@ -1292,9 +1344,17 @@ name, or nil if there is no such user.  */)
   if (NILP (uid))
     return Vuser_full_name;
   else if (NUMBERP (uid))
-    pw = (struct passwd *) getpwuid ((uid_t) XFLOATINT (uid));
+    {
+      BLOCK_INPUT;
+      pw = (struct passwd *) getpwuid ((uid_t) XFLOATINT (uid));
+      UNBLOCK_INPUT;
+    }
   else if (STRINGP (uid))
-    pw = (struct passwd *) getpwnam (SDATA (uid));
+    {
+      BLOCK_INPUT;
+      pw = (struct passwd *) getpwnam (SDATA (uid));
+      UNBLOCK_INPUT;
+    }
   else
     error ("Invalid UID specification");
 
@@ -1330,7 +1390,7 @@ name, or nil if there is no such user.  */)
 }
 
 DEFUN ("system-name", Fsystem_name, Ssystem_name, 0, 0, 0,
-       doc: /* Return the name of the machine you are running on, as a string.  */)
+       doc: /* Return the host name of the machine you are running on, as a string.  */)
      ()
 {
   return Vsystem_name;
@@ -1347,6 +1407,15 @@ get_system_name ()
     return "";
 }
 
+char *
+get_operating_system_release()
+{
+  if (STRINGP (Voperating_system_release))
+    return (char *) SDATA (Voperating_system_release);
+  else
+    return "";
+}
+
 DEFUN ("emacs-pid", Femacs_pid, Semacs_pid, 0, 0, 0,
        doc: /* Return the process ID of Emacs, as an integer.  */)
      ()
@@ -1366,18 +1435,53 @@ resolution finer than a second.  */)
      ()
 {
   EMACS_TIME t;
-  Lisp_Object result[3];
 
   EMACS_GET_TIME (t);
-  XSETINT (result[0], (EMACS_SECS (t) >> 16) & 0xffff);
-  XSETINT (result[1], (EMACS_SECS (t) >> 0)  & 0xffff);
-  XSETINT (result[2], EMACS_USECS (t));
+  return list3 (make_number ((EMACS_SECS (t) >> 16) & 0xffff),
+               make_number ((EMACS_SECS (t) >> 0)  & 0xffff),
+               make_number (EMACS_USECS (t)));
+}
 
-  return Flist (3, result);
+DEFUN ("get-internal-run-time", Fget_internal_run_time, Sget_internal_run_time,
+       0, 0, 0,
+       doc: /* Return the current run time used by Emacs.
+The time is returned as a list of three integers.  The first has the
+most significant 16 bits of the seconds, while the second has the
+least significant 16 bits.  The third integer gives the microsecond
+count.
+
+On systems that can't determine the run time, get-internal-run-time
+does the same thing as current-time.  The microsecond count is zero on
+systems that do not provide resolution finer than a second.  */)
+     ()
+{
+#ifdef HAVE_GETRUSAGE
+  struct rusage usage;
+  int secs, usecs;
+
+  if (getrusage (RUSAGE_SELF, &usage) < 0)
+    /* This shouldn't happen.  What action is appropriate?  */
+    xsignal0 (Qerror);
+
+  /* Sum up user time and system time.  */
+  secs = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
+  usecs = usage.ru_utime.tv_usec + usage.ru_stime.tv_usec;
+  if (usecs >= 1000000)
+    {
+      usecs -= 1000000;
+      secs++;
+    }
+
+  return list3 (make_number ((secs >> 16) & 0xffff),
+               make_number ((secs >> 0)  & 0xffff),
+               make_number (usecs));
+#else
+  return Fcurrent_time ();
+#endif
 }
 \f
 
-static int
+int
 lisp_time_argument (specified_time, result, usec)
      Lisp_Object specified_time;
      time_t *result;
@@ -1430,11 +1534,11 @@ lisp_time_argument (specified_time, result, usec)
 
 DEFUN ("float-time", Ffloat_time, Sfloat_time, 0, 1, 0,
        doc: /* Return the current time, as a float number of seconds since the epoch.
-If an argument is given, it specifies a time to convert to float
-instead of the current time.  The argument should have the forms:
- (HIGH . LOW) or (HIGH LOW USEC) or (HIGH LOW . USEC).
-Thus, you can use times obtained from `current-time'
-and from `file-attributes'.
+If SPECIFIED-TIME is given, it is the time to convert to float
+instead of the current time.  The argument should have the form
+(HIGH LOW . IGNORED). Thus, you can use times obtained from
+`current-time' and from `file-attributes'.  SPECIFIED-TIME can also
+have the form (HIGH . LOW), but this is considered obsolete.
 
 WARNING: Since the result is floating point, it may not be exact.
 Do not use this function if precise time stamps are required.  */)
@@ -1506,8 +1610,9 @@ emacs_memftimeu (s, maxsize, format, format_len, tp, ut)
 
 DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
        doc: /* Use FORMAT-STRING to format the time TIME, or now if omitted.
-TIME is specified as (HIGH LOW . IGNORED) or (HIGH . LOW), as returned by
-`current-time' or `file-attributes'.
+TIME is specified as (HIGH LOW . IGNORED), as returned by
+`current-time' or `file-attributes'.  The obsolete form (HIGH . LOW)
+is also still accepted.
 The third, optional, argument UNIVERSAL, if non-nil, means describe TIME
 as Universal Time; nil means describe TIME in the local time zone.
 The value is a copy of FORMAT-STRING, but with certain constructs replaced
@@ -1589,7 +1694,7 @@ For example, to produce full ISO 8601 format, use "%Y-%m-%dT%T%z".  */)
                                SBYTES (format_string),
                                tm, ut);
       if ((result > 0 && result < size) || (result == 0 && buf[0] == '\0'))
-       return code_convert_string_norecord (make_string (buf, result),
+       return code_convert_string_norecord (make_unibyte_string (buf, result),
                                             Vlocale_coding_system, 0);
 
       /* If buffer was too small, make it bigger and try again.  */
@@ -1603,17 +1708,19 @@ For example, to produce full ISO 8601 format, use "%Y-%m-%dT%T%z".  */)
 
 DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 1, 0,
        doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST ZONE).
-The optional SPECIFIED-TIME should be a list of (HIGH LOW . IGNORED)
-or (HIGH . LOW), as from `current-time' and `file-attributes', or `nil'
-to use the current time.  The list has the following nine members:
-SEC is an integer between 0 and 60; SEC is 60 for a leap second, which
-only some operating systems support.  MINUTE is an integer between 0 and 59.
-HOUR is an integer between 0 and 23.  DAY is an integer between 1 and 31.
-MONTH is an integer between 1 and 12.  YEAR is an integer indicating the
-four-digit year.  DOW is the day of week, an integer between 0 and 6, where
-0 is Sunday.  DST is t if daylight savings time is effect, otherwise nil.
-ZONE is an integer indicating the number of seconds east of Greenwich.
-(Note that Common Lisp has different meanings for DOW and ZONE.)  */)
+The optional SPECIFIED-TIME should be a list of (HIGH LOW . IGNORED),
+as from `current-time' and `file-attributes', or `nil' to use the
+current time.  The obsolete form (HIGH . LOW) is also still accepted.
+The list has the following nine members: SEC is an integer between 0
+and 60; SEC is 60 for a leap second, which only some operating systems
+support.  MINUTE is an integer between 0 and 59.  HOUR is an integer
+between 0 and 23.  DAY is an integer between 1 and 31.  MONTH is an
+integer between 1 and 12.  YEAR is an integer indicating the
+four-digit year.  DOW is the day of week, an integer between 0 and 6,
+where 0 is Sunday.  DST is t if daylight savings time is effect,
+otherwise nil.  ZONE is an integer indicating the number of seconds
+east of Greenwich.  (Note that Common Lisp has different meanings for
+DOW and ZONE.)  */)
      (specified_time)
      Lisp_Object specified_time;
 {
@@ -1633,7 +1740,9 @@ ZONE is an integer indicating the number of seconds east of Greenwich.
   XSETFASTINT (list_args[2], decoded_time->tm_hour);
   XSETFASTINT (list_args[3], decoded_time->tm_mday);
   XSETFASTINT (list_args[4], decoded_time->tm_mon + 1);
-  XSETINT (list_args[5], decoded_time->tm_year + 1900);
+  /* On 64-bit machines an int is narrower than EMACS_INT, thus the
+     cast below avoids overflow in int arithmetics.  */
+  XSETINT (list_args[5], TM_YEAR_BASE + (EMACS_INT) decoded_time->tm_year);
   XSETFASTINT (list_args[6], decoded_time->tm_wday);
   list_args[7] = (decoded_time->tm_isdst)? Qt : Qnil;
 
@@ -1660,7 +1769,7 @@ are used as SECOND through YEAR, and the *last* argument is used as ZONE.
 The intervening arguments are ignored.
 This feature lets (apply 'encode-time (decode-time ...)) work.
 
-Out-of-range values for SEC, MINUTE, HOUR, DAY, or MONTH are allowed;
+Out-of-range values for SECOND, MINUTE, HOUR, DAY, or MONTH are allowed;
 for example, a DAY of 0 means the day preceding the given month.
 Year numbers less than 100 are treated just like other year numbers.
 If you want them to stand for years in this century, you must do that yourself.
@@ -1689,7 +1798,7 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE)  */)
   tm.tm_hour = XINT (args[2]);
   tm.tm_mday = XINT (args[3]);
   tm.tm_mon = XINT (args[4]) - 1;
-  tm.tm_year = XINT (args[5]) - 1900;
+  tm.tm_year = XINT (args[5]) - TM_YEAR_BASE;
   tm.tm_isdst = -1;
 
   if (CONSP (zone))
@@ -1740,37 +1849,40 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE)  */)
 DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string, 0, 1, 0,
        doc: /* Return the current time, as a human-readable string.
 Programs can use this function to decode a time,
-since the number of columns in each field is fixed.
+since the number of columns in each field is fixed
+if the year is in the range 1000-9999.
 The format is `Sun Sep 16 01:03:52 1973'.
 However, see also the functions `decode-time' and `format-time-string'
 which provide a much more powerful and general facility.
 
-If an argument is given, it specifies a time to format
-instead of the current time.  The argument should have the form:
-  (HIGH . LOW)
-or the form:
-  (HIGH LOW . IGNORED).
-Thus, you can use times obtained from `current-time'
-and from `file-attributes'.  */)
+If SPECIFIED-TIME is given, it is a time to format instead of the
+current time.  The argument should have the form (HIGH LOW . IGNORED).
+Thus, you can use times obtained from `current-time' and from
+`file-attributes'.  SPECIFIED-TIME can also have the form (HIGH . LOW),
+but this is considered obsolete.  */)
      (specified_time)
      Lisp_Object specified_time;
 {
   time_t value;
-  char buf[30];
+  struct tm *tm;
   register char *tem;
 
   if (! lisp_time_argument (specified_time, &value, NULL))
-    value = -1;
-  tem = (char *) ctime (&value);
+    error ("Invalid time specification");
+
+  /* Convert to a string, checking for out-of-range time stamps.
+     Don't use 'ctime', as that might dump core if VALUE is out of
+     range.  */
+  tm = localtime (&value);
+  if (! (tm && TM_YEAR_IN_ASCTIME_RANGE (tm->tm_year) && (tem = asctime (tm))))
+    error ("Specified time is not representable");
 
-  strncpy (buf, tem, 24);
-  buf[24] = 0;
+  /* Remove the trailing newline.  */
+  tem[strlen (tem) - 1] = '\0';
 
-  return build_string (buf);
+  return build_string (tem);
 }
 
-#define TM_YEAR_BASE 1900
-
 /* Yield A - B, measured in seconds.
    This function is copied from the GNU C Library.  */
 static int
@@ -1801,13 +1913,11 @@ This returns a list of the form (OFFSET NAME).
 OFFSET is an integer number of seconds ahead of UTC (east of Greenwich).
     A negative value means west of Greenwich.
 NAME is a string giving the name of the time zone.
-If an argument is given, it specifies when the time zone offset is determined
-instead of using the current time.  The argument should have the form:
-  (HIGH . LOW)
-or the form:
-  (HIGH LOW . IGNORED).
-Thus, you can use times obtained from `current-time'
-and from `file-attributes'.
+If SPECIFIED-TIME is given, the time zone offset is determined from it
+instead of using the current time.  The argument should have the form
+(HIGH LOW . IGNORED).  Thus, you can use times obtained from
+`current-time' and from `file-attributes'.  SPECIFIED-TIME can also
+have the form (HIGH . LOW), but this is considered obsolete.
 
 Some operating systems cannot provide all this information to Emacs;
 in this case, `current-time-zone' returns a list containing nil for
@@ -2009,7 +2119,6 @@ general_insert_function (insert_func, insert_from_string_func,
   for (argnum = 0; argnum < nargs; argnum++)
     {
       val = args[argnum];
-    retry:
       if (INTEGERP (val))
        {
          unsigned char str[MAX_MULTIBYTE_LENGTH];
@@ -2034,10 +2143,7 @@ general_insert_function (insert_func, insert_from_string_func,
                                      inherit);
        }
       else
-       {
-         val = wrong_type_argument (Qchar_or_string_p, val);
-         goto retry;
-       }
+       wrong_type_argument (Qchar_or_string_p, val);
     }
 }
 
@@ -2347,21 +2453,21 @@ of the buffer.  */)
 
 DEFUN ("insert-buffer-substring", Finsert_buffer_substring, Sinsert_buffer_substring,
        1, 3, 0,
-       doc: /* Insert before point a substring of the contents of buffer BUFFER.
+       doc: /* Insert before point a substring of the contents of BUFFER.
 BUFFER may be a buffer or a buffer name.
-Arguments START and END are character numbers specifying the substring.
-They default to the beginning and the end of BUFFER.  */)
-     (buf, start, end)
-     Lisp_Object buf, start, end;
+Arguments START and END are character positions specifying the substring.
+They default to the values of (point-min) and (point-max) in BUFFER.  */)
+     (buffer, start, end)
+     Lisp_Object buffer, start, end;
 {
   register int b, e, temp;
   register struct buffer *bp, *obuf;
-  Lisp_Object buffer;
+  Lisp_Object buf;
 
-  buffer = Fget_buffer (buf);
-  if (NILP (buffer))
-    nsberror (buf);
-  bp = XBUFFER (buffer);
+  buf = Fget_buffer (buffer);
+  if (NILP (buf))
+    nsberror (buffer);
+  bp = XBUFFER (buf);
   if (NILP (bp->name))
     error ("Selecting deleted buffer");
 
@@ -2410,9 +2516,9 @@ determines whether case is significant or ignored.  */)
 {
   register int begp1, endp1, begp2, endp2, temp;
   register struct buffer *bp1, *bp2;
-  register Lisp_Object *trt
+  register Lisp_Object trt
     = (!NILP (current_buffer->case_fold_search)
-       ? XCHAR_TABLE (current_buffer->case_canon_table)->contents : 0);
+       ? current_buffer->case_canon_table : Qnil);
   int chars = 0;
   int i1, i2, i1_byte, i2_byte;
 
@@ -2531,10 +2637,10 @@ determines whether case is significant or ignored.  */)
          i2++;
        }
 
-      if (trt)
+      if (!NILP (trt))
        {
-         c1 = XINT (trt[c1]);
-         c2 = XINT (trt[c2]);
+         c1 = CHAR_TABLE_TRANSLATE (trt, c1);
+         c2 = CHAR_TABLE_TRANSLATE (trt, c2);
        }
       if (c1 < c2)
        return make_number (- 1 - chars);
@@ -2579,6 +2685,10 @@ Both characters must have the same length of multi-byte form.  */)
      Lisp_Object start, end, fromchar, tochar, noundo;
 {
   register int pos, pos_byte, stop, i, len, end_byte;
+  /* Keep track of the first change in the buffer:
+     if 0 we haven't found it yet.
+     if < 0 we've found it and we've run the before-change-function.
+     if > 0 we've actually performed it and the value is its position.  */
   int changed = 0;
   unsigned char fromstr[MAX_MULTIBYTE_LENGTH], tostr[MAX_MULTIBYTE_LENGTH];
   unsigned char *p;
@@ -2591,6 +2701,8 @@ Both characters must have the same length of multi-byte form.  */)
   int last_changed = 0;
   int multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
 
+ restart:
+
   validate_region (&start, &end);
   CHECK_NUMBER (fromchar);
   CHECK_NUMBER (tochar);
@@ -2599,7 +2711,7 @@ Both characters must have the same length of multi-byte form.  */)
     {
       len = CHAR_STRING (XFASTINT (fromchar), fromstr);
       if (CHAR_STRING (XFASTINT (tochar), tostr) != len)
-       error ("Characters in subst-char-in-region have different byte-lengths");
+       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
@@ -2628,7 +2740,7 @@ Both characters must have the same length of multi-byte form.  */)
      That's faster than getting rid of things,
      and it prevents even the entry for a first change.
      Also inhibit locking the file.  */
-  if (!NILP (noundo))
+  if (!changed && !NILP (noundo))
     {
       record_unwind_protect (subst_char_in_region_unwind,
                             current_buffer->undo_list);
@@ -2662,10 +2774,14 @@ Both characters must have the same length of multi-byte form.  */)
                  && (len == 2 || (p[2] == fromstr[2]
                                 && (len == 3 || p[3] == fromstr[3]))))))
        {
-         if (! changed)
+         if (changed < 0)
+           /* We've already seen this and run the before-change-function;
+              this time we only need to record the actual position. */
+           changed = pos;
+         else if (!changed)
            {
-             changed = pos;
-             modify_region (current_buffer, changed, XINT (end));
+             changed = -1;
+             modify_region (current_buffer, pos, XINT (end), 0);
 
              if (! NILP (noundo))
                {
@@ -2674,6 +2790,10 @@ Both characters must have the same length of multi-byte form.  */)
                  if (MODIFF - 1 == current_buffer->auto_save_modified)
                    current_buffer->auto_save_modified++;
                }
+
+             /* The before-change-function may have moved the gap
+                or even modified the buffer so we should start over. */
+             goto restart;
            }
 
          /* Take care of the case where the new character
@@ -2726,7 +2846,7 @@ Both characters must have the same length of multi-byte form.  */)
       pos++;
     }
 
-  if (changed)
+  if (changed > 0)
     {
       signal_after_change (changed,
                           last_changed - changed, last_changed - changed);
@@ -2737,89 +2857,127 @@ Both characters must have the same length of multi-byte form.  */)
   return Qnil;
 }
 
-DEFUN ("translate-region", Ftranslate_region, Stranslate_region, 3, 3, 0,
-       doc: /* From START to END, translate characters according to TABLE.
+DEFUN ("translate-region-internal", Ftranslate_region_internal,
+       Stranslate_region_internal, 3, 3, 0,
+       doc: /* Internal use only.
+From START to END, translate characters according to TABLE.
 TABLE is a string; the Nth character in it is the mapping
 for the character with code N.
-This function does not alter multibyte characters.
 It returns the number of characters changed.  */)
      (start, end, table)
      Lisp_Object start;
      Lisp_Object end;
      register Lisp_Object table;
 {
-  register int pos_byte, stop; /* Limits of the region. */
   register unsigned char *tt;  /* Trans table. */
   register int nc;             /* New character. */
   int cnt;                     /* Number of changes made. */
   int size;                    /* Size of translate table. */
-  int pos;
+  int pos, pos_byte, end_pos;
   int multibyte = !NILP (current_buffer->enable_multibyte_characters);
+  int string_multibyte;
 
   validate_region (&start, &end);
-  CHECK_STRING (table);
+  if (CHAR_TABLE_P (table))
+    {
+      size = MAX_CHAR;
+      tt = NULL;
+    }
+  else
+    {
+      CHECK_STRING (table);
 
-  size = SBYTES (table);
-  tt = SDATA (table);
+      if (! multibyte && (SCHARS (table) < SBYTES (table)))
+       table = string_make_unibyte (table);
+      string_multibyte = SCHARS (table) < SBYTES (table);
+      size = SCHARS (table);
+      tt = SDATA (table);
+    }
 
-  pos_byte = CHAR_TO_BYTE (XINT (start));
-  stop = CHAR_TO_BYTE (XINT (end));
-  modify_region (current_buffer, XINT (start), XINT (end));
   pos = XINT (start);
+  pos_byte = CHAR_TO_BYTE (pos);
+  end_pos = XINT (end);
+  modify_region (current_buffer, pos, XINT (end), 0);
 
   cnt = 0;
-  for (; pos_byte < stop; )
+  for (; pos < end_pos; )
     {
       register unsigned char *p = BYTE_POS_ADDR (pos_byte);
-      int len;
+      unsigned char *str, buf[MAX_MULTIBYTE_LENGTH];
+      int len, str_len;
       int oc;
-      int pos_byte_next;
 
       if (multibyte)
-       oc = STRING_CHAR_AND_LENGTH (p, stop - pos_byte, len);
+       oc = STRING_CHAR_AND_LENGTH (p, MAX_MULTIBYTE_LENGTH, len);
       else
        oc = *p, len = 1;
-      pos_byte_next = pos_byte + len;
-      if (oc < size && len == 1)
+      if (oc < size)
        {
-         nc = tt[oc];
+         if (tt)
+           {
+             /* Reload as signal_after_change in last iteration may GC.  */
+             tt = SDATA (table);
+             if (string_multibyte)
+               {
+                 str = tt + string_char_to_byte (table, oc);
+                 nc = STRING_CHAR_AND_LENGTH (str, MAX_MULTIBYTE_LENGTH,
+                                              str_len);
+               }
+             else
+               {
+                 nc = tt[oc];
+                 if (! ASCII_BYTE_P (nc) && multibyte)
+                   {
+                     str_len = CHAR_STRING (nc, buf);
+                     str = buf;
+                   }
+                 else
+                   {
+                     str_len = 1;
+                     str = tt + oc;
+                   }
+               }
+           }
+         else
+           {
+             Lisp_Object val;
+             int c;
+
+             nc = oc;
+             val = CHAR_TABLE_REF (table, oc);
+             if (INTEGERP (val)
+                 && (c = XINT (val), CHAR_VALID_P (c, 0)))
+               {
+                 nc = c;
+                 str_len = CHAR_STRING (nc, buf);
+                 str = buf;
+               }
+           }
+
          if (nc != oc)
            {
-             /* 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)))))
+             if (len != str_len)
                {
                  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);
+                    but it should multibyte characters correctly.  */
+                 string = make_multibyte_string (str, 1, str_len);
+                 replace_range (pos, pos + 1, string, 1, 0, 1);
+                 len = str_len;
                }
              else
                {
                  record_change (pos, 1);
-                 *p = nc;
+                 while (str_len-- > 0)
+                   *p++ = *str++;
                  signal_after_change (pos, 1, 1);
                  update_compositions (pos, pos + 1, CHECK_BORDER);
                }
              ++cnt;
            }
        }
-      pos_byte = pos_byte_next;
+      pos_byte += len;
       pos++;
     }
 
@@ -2828,6 +2986,7 @@ It returns the number of characters changed.  */)
 
 DEFUN ("delete-region", Fdelete_region, Sdelete_region, 2, 2, "r",
        doc: /* Delete the text between point and mark.
+
 When called from a program, expects two arguments,
 positions (integers or markers) specifying the stretch to be deleted.  */)
      (start, end)
@@ -2845,6 +3004,8 @@ DEFUN ("delete-and-extract-region", Fdelete_and_extract_region,
      Lisp_Object start, end;
 {
   validate_region (&start, &end);
+  if (XINT (start) == XINT (end))
+    return build_string ("");
   return del_range_1 (XINT (start), XINT (end), 1, 1);
 }
 \f
@@ -3010,14 +3171,22 @@ static char *message_text;
 static int message_length;
 
 DEFUN ("message", Fmessage, Smessage, 1, MANY, 0,
-       doc: /* Print a one-line message at the bottom of the screen.
+       doc: /* Display a message at the bottom of the screen.
+The message also goes into the `*Messages*' buffer.
+\(In keyboard macros, that's all it does.)
+Return the message.
+
 The first argument is a format control string, and the rest are data
 to be formatted under control of the string.  See `format' for details.
 
-If the first argument is nil, clear any existing message; let the
-minibuffer contents show.
+Note: Use (message "%s" VALUE) to print the value of expressions and
+variables to avoid accidentally interpreting `%' as format specifiers.
 
-usage: (message STRING &rest ARGS)  */)
+If the first argument is nil or the empty string, the function clears
+any existing message; this lets the minibuffer contents show.  See
+also `current-message'.
+
+usage: (message FORMAT-STRING &rest ARGS)  */)
      (nargs, args)
      int nargs;
      Lisp_Object *args;
@@ -3027,7 +3196,7 @@ usage: (message STRING &rest ARGS)  */)
          && SBYTES (args[0]) == 0))
     {
       message (0);
-      return Qnil;
+      return args[0];
     }
   else
     {
@@ -3044,10 +3213,10 @@ If a dialog box is not available, use the echo area.
 The first argument is a format control string, and the rest are data
 to be formatted under control of the string.  See `format' for details.
 
-If the first argument is nil, clear any existing message; let the
-minibuffer contents show.
+If the first argument is nil or the empty string, clear any existing
+message; let the minibuffer contents show.
 
-usage: (message-box STRING &rest ARGS)  */)
+usage: (message-box FORMAT-STRING &rest ARGS)  */)
      (nargs, args)
      int nargs;
      Lisp_Object *args;
@@ -3072,7 +3241,7 @@ usage: (message-box STRING &rest ARGS)  */)
        pane = Fcons (Fcons (build_string ("OK"), Qt), Qnil);
        GCPRO1 (pane);
        menu = Fcons (val, pane);
-       obj = Fx_popup_dialog (Qt, menu);
+       obj = Fx_popup_dialog (Qt, menu, Qt);
        UNGCPRO;
        return val;
       }
@@ -3106,10 +3275,10 @@ Otherwise, use the echo area.
 The first argument is a format control string, and the rest are data
 to be formatted under control of the string.  See `format' for details.
 
-If the first argument is nil, clear any existing message; let the
-minibuffer contents show.
+If the first argument is nil or the empty string, clear any existing
+message; let the minibuffer contents show.
 
-usage: (message-or-box STRING &rest ARGS)  */)
+usage: (message-or-box FORMAT-STRING &rest ARGS)  */)
      (nargs, args)
      int nargs;
      Lisp_Object *args;
@@ -3156,10 +3325,7 @@ usage: (propertize STRING &rest PROPERTIES)  */)
   string = Fcopy_sequence (args[0]);
 
   for (i = 1; i < nargs; i += 2)
-    {
-      CHECK_SYMBOL (args[i]);
-      properties = Fcons (args[i], Fcons (args[i + 1], properties));
-    }
+    properties = Fcons (args[i], Fcons (args[i + 1], properties));
 
   Fadd_text_properties (make_number (0),
                        make_number (SCHARS (string)),
@@ -3177,8 +3343,8 @@ usage: (propertize STRING &rest PROPERTIES)  */)
    : SBYTES (STRING))
 
 DEFUN ("format", Fformat, Sformat, 1, MANY, 0,
-       doc: /* Format a string out of a control-string and arguments.
-The first argument is a control string.
+       doc: /* Format a string out of a format-string and arguments.
+The first argument is a format control string.
 The other arguments are substituted into it to make the result, a string.
 It may contain %-sequences meaning to substitute the next argument.
 %s means print a string argument.  Actually, prints any object, with `princ'.
@@ -3193,6 +3359,10 @@ It may contain %-sequences meaning to substitute the next argument.
   The argument used for %d, %o, %x, %e, %f, %g or %c must be a number.
 Use %% to put a single % into the output.
 
+The basic structure of a %-sequence is
+  % <flags> <width> <precision> character
+where flags is [- #0]+, width is [0-9]+, and precision is .[0-9]+
+
 usage: (format STRING &rest OBJECTS)  */)
      (nargs, args)
      int nargs;
@@ -3217,15 +3387,16 @@ usage: (format STRING &rest OBJECTS)  */)
      string itself, will not be used.  Element NARGS, corresponding to
      no argument, *will* be assigned to in the case that a `%' and `.'
      occur after the final format specifier.  */
-  int *precision = (int *) (alloca(nargs * sizeof (int)));
+  int *precision = (int *) (alloca((nargs + 1) * sizeof (int)));
   int longest_format;
   Lisp_Object val;
   int arg_intervals = 0;
+  USE_SAFE_ALLOCA;
 
   /* discarded[I] is 1 if byte I of the format
      string was not copied into the output.
      It is 2 if byte I was not the first byte of its character.  */
-  char *discarded;
+  char *discarded = 0;
 
   /* Each element records, for one argument,
      the start and end bytepos in the output string,
@@ -3250,6 +3421,7 @@ usage: (format STRING &rest OBJECTS)  */)
       /* Piggyback on this loop to initialize precision[N]. */
       precision[n] = -1;
     }
+  precision[nargs] = -1;
 
   CHECK_STRING (args[0]);
   /* We may have to change "%S" to "%s". */
@@ -3269,17 +3441,19 @@ usage: (format STRING &rest OBJECTS)  */)
   longest_format = 0;
 
   /* Make room in result for all the non-%-codes in the control string.  */
-  total = 5 + CONVERTED_BYTE_SIZE (multibyte, args[0]);
+  total = 5 + CONVERTED_BYTE_SIZE (multibyte, args[0]) + 1;
 
-  /* Allocate the info and discarded tables.  */ 
+  /* Allocate the info and discarded tables.  */
   {
-    int nbytes = nargs * sizeof *info;
+    int nbytes = (nargs+1) * sizeof *info;
     int i;
-    info = (struct info *) alloca (nbytes);
+    if (!info)
+      info = (struct info *) alloca (nbytes);
     bzero (info, nbytes);
     for (i = 0; i <= nargs; i++)
       info[i].start = -1;
-    discarded = (char *) alloca (SBYTES (args[0]));
+    if (!discarded)
+      SAFE_ALLOCA (discarded, char *, SBYTES (args[0]));
     bzero (discarded, SBYTES (args[0]));
   }
 
@@ -3300,7 +3474,7 @@ usage: (format STRING &rest OBJECTS)  */)
 
           where
 
-          flags        ::= [#-* 0]+
+          flags        ::= [- #0]+
           field-width  ::= [0-9]+
           precision    ::= '.' [0-9]*
 
@@ -3312,14 +3486,9 @@ usage: (format STRING &rest OBJECTS)  */)
           digits to print after the '.' for floats, or the max.
           number of chars to print from a string.  */
 
-       /* NOTE the handling of specifiers here differs in some ways
-           from the libc model.  There are bugs in this code that lead
-           to incorrect formatting when flags recognized by C but
-           neither parsed nor rejected here are used.  Further
-           revisions will be made soon.  */
-
-        /* incorrect list of flags to skip; will be fixed */
-       while (index ("-*# 0", *format))
+       while (format != end
+              && (*format == '-' || *format == '0' || *format == '#'
+                  || * format == ' '))
          ++format;
 
        if (*format >= '0' && *format <= '9')
@@ -3403,7 +3572,7 @@ usage: (format STRING &rest OBJECTS)  */)
            if (*format == 'c')
              {
                if (! SINGLE_BYTE_CHAR_P (XINT (args[n]))
-                   /* Note: No one can remeber why we have to treat
+                   /* Note: No one can remember why we have to treat
                       the character 0 as a multibyte character here.
                       But, until it causes a real problem, let's
                       don't change it.  */
@@ -3447,7 +3616,7 @@ usage: (format STRING &rest OBJECTS)  */)
            /* 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)
+           if (STRING_MULTIBYTE (tem) && ! multibyte)
              {
                multibyte = 1;
                goto retry;
@@ -3469,10 +3638,7 @@ usage: (format STRING &rest OBJECTS)  */)
 
   /* 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);
+  SAFE_ALLOCA (buf, char *, total);
 
   p = buf;
   nchars = 0;
@@ -3494,17 +3660,19 @@ usage: (format STRING &rest OBJECTS)  */)
          discarded[format - format_start] = 1;
          format++;
 
-         /* Process a numeric arg and skip it.  */
-         /* NOTE atoi is the wrong thing to use here; will be fixed */
+         while (index("-0# ", *format))
+           {
+             if (*format == '-')
+               {
+                 negative = 1;
+               }
+             discarded[format - format_start] = 1;
+             ++format;
+           }
+
          minlen = atoi (format);
-         if (minlen < 0)
-           minlen = - minlen, negative = 1;
-
-         /* NOTE the parsing here is not consistent with the first
-             pass, and neither attempt is what we want to do.  Will be
-             fixed. */
-         while ((*format >= '0' && *format <= '9')
-                || *format == '-' || *format == ' ' || *format == '.')
+
+         while ((*format >= '0' && *format <= '9') || *format == '.')
            {
              discarded[format - format_start] = 1;
              format++;
@@ -3556,7 +3724,7 @@ usage: (format STRING &rest OBJECTS)  */)
                    ++nchars;
                  }
 
-             start = nchars;
+             info[n].start = start = nchars;
              nchars += nchars_string;
              end = nchars;
 
@@ -3571,6 +3739,8 @@ usage: (format STRING &rest OBJECTS)  */)
                              nbytes,
                              STRING_MULTIBYTE (args[n]), multibyte);
 
+             info[n].end = nchars;
+
              if (negative)
                while (padding-- > 0)
                  {
@@ -3592,7 +3762,13 @@ usage: (format STRING &rest OBJECTS)  */)
              this_format[format - this_format_start] = 0;
 
              if (INTEGERP (args[n]))
-               sprintf (p, this_format, XINT (args[n]));
+               {
+                 if (format[-1] == 'd')
+                   sprintf (p, this_format, XINT (args[n]));
+                 /* Don't sign-extend for octal or hex printing.  */
+                 else
+                   sprintf (p, this_format, XUINT (args[n]));
+               }
              else
                sprintf (p, this_format, XFLOAT_DATA (args[n]));
 
@@ -3603,13 +3779,13 @@ usage: (format STRING &rest OBJECTS)  */)
                maybe_combine_byte = 1;
              this_nchars = strlen (p);
              if (multibyte)
-               p += str_to_multibyte (p, buf + total - p, this_nchars);
+               p += str_to_multibyte (p, buf + total - 1 - p, this_nchars);
              else
                p += this_nchars;
              nchars += this_nchars;
+             info[n].end = nchars;
            }
 
-         info[n].end = nchars;
        }
       else if (STRING_MULTIBYTE (args[0]))
        {
@@ -3640,7 +3816,7 @@ usage: (format STRING &rest OBJECTS)  */)
        *p++ = *format++, nchars++;
     }
 
-  if (p > buf + total + 1)
+  if (p > buf + total)
     abort ();
 
   if (maybe_combine_byte)
@@ -3648,8 +3824,7 @@ usage: (format STRING &rest OBJECTS)  */)
   val = make_specified_string (buf, nchars, p - buf, multibyte);
 
   /* If we allocated BUF with malloc, free it too.  */
-  if (total >= 1000)
-    xfree (buf);
+  SAFE_FREE ();
 
   /* If the format string has text properties, or any of the string
      arguments has text properties, set up text properties of the
@@ -3672,11 +3847,13 @@ usage: (format STRING &rest OBJECTS)  */)
 
          /* Adjust the bounds of each text property
             to the proper start and end in the output string.  */
-         /* We take advantage of the fact that the positions in PROPS
-            are in increasing order, so that we can do (effectively)
-            one scan through the position space of the format string.
 
-            BYTEPOS is the byte position in the format string,
+         /* Put the positions in PROPS in increasing order, so that
+            we can do (effectively) one scan through the position
+            space of the format string.  */
+         props = Fnreverse (props);
+
+         /* BYTEPOS is the byte position in the format string,
             POSITION is the untranslated char position in it,
             TRANSLATED is the translated char position in BUF,
             and ARGN is the number of the next arg we will come to.  */
@@ -3712,7 +3889,7 @@ usage: (format STRING &rest OBJECTS)  */)
              /* Likewise adjust the property end position.  */
              pos = XINT (XCAR (XCDR (item)));
 
-             for (; bytepos < pos; bytepos++)
+             for (; position < pos; bytepos++)
                {
                  if (! discarded[bytepos])
                    position++, translated++;
@@ -3877,11 +4054,11 @@ transpose_markers (start1, end1, start2, end2,
 }
 
 DEFUN ("transpose-regions", Ftranspose_regions, Stranspose_regions, 4, 5, 0,
-       doc: /* Transpose region START1 to END1 with START2 to END2.
+       doc: /* Transpose region STARTR1 to ENDR1 with STARTR2 to ENDR2.
 The regions may not be overlapping, because the size of the buffer is
 never changed in a transposition.
 
-Optional fifth arg LEAVE_MARKERS, if non-nil, means don't update
+Optional fifth arg LEAVE-MARKERS, if non-nil, means don't update
 any markers that happen to be located in the regions.
 
 Transposing beyond buffer boundaries is an error.  */)
@@ -3995,7 +4172,7 @@ Transposing beyond buffer boundaries is an error.  */)
 
   if (end1 == start2)          /* adjacent regions */
     {
-      modify_region (current_buffer, start1, end2);
+      modify_region (current_buffer, start1, end2, 0);
       record_change (start1, len1 + len2);
 
       tmp_interval1 = copy_intervals (cur_intv, start1, len1);
@@ -4006,12 +4183,9 @@ Transposing beyond buffer boundaries is an error.  */)
       /* First region smaller than second.  */
       if (len1_byte < len2_byte)
         {
-         /* We use alloca only if it is small,
-            because we want to avoid stack overflow.  */
-         if (len2_byte > 20000)
-           temp = (unsigned char *) xmalloc (len2_byte);
-         else
-           temp = (unsigned char *) alloca (len2_byte);
+         USE_SAFE_ALLOCA;
+
+         SAFE_ALLOCA (temp, unsigned char *, len2_byte);
 
          /* Don't precompute these addresses.  We have to compute them
             at the last minute, because the relocating allocator might
@@ -4022,23 +4196,20 @@ Transposing beyond buffer boundaries is an error.  */)
           bcopy (start2_addr, temp, len2_byte);
           bcopy (start1_addr, start1_addr + len2_byte, len1_byte);
           bcopy (temp, start1_addr, len2_byte);
-         if (len2_byte > 20000)
-           xfree (temp);
+         SAFE_FREE ();
         }
       else
        /* First region not smaller than second.  */
         {
-         if (len1_byte > 20000)
-           temp = (unsigned char *) xmalloc (len1_byte);
-         else
-           temp = (unsigned char *) alloca (len1_byte);
+         USE_SAFE_ALLOCA;
+
+         SAFE_ALLOCA (temp, unsigned char *, len1_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);
-         if (len1_byte > 20000)
-           xfree (temp);
+         SAFE_FREE ();
         }
       graft_intervals_into_buffer (tmp_interval1, start1 + len2,
                                    len1, current_buffer, 0);
@@ -4055,8 +4226,10 @@ Transposing beyond buffer boundaries is an error.  */)
       if (len1_byte == len2_byte)
        /* Regions are same size, though, how nice.  */
         {
-          modify_region (current_buffer, start1, end1);
-          modify_region (current_buffer, start2, end2);
+         USE_SAFE_ALLOCA;
+
+          modify_region (current_buffer, start1, end1, 0);
+          modify_region (current_buffer, start2, end2, 0);
           record_change (start1, len1);
           record_change (start2, len2);
           tmp_interval1 = copy_intervals (cur_intv, start1, len1);
@@ -4066,17 +4239,14 @@ Transposing beyond buffer boundaries is an error.  */)
           Fset_text_properties (make_number (start2), make_number (end2),
                                Qnil, Qnil);
 
-         if (len1_byte > 20000)
-           temp = (unsigned char *) xmalloc (len1_byte);
-         else
-           temp = (unsigned char *) alloca (len1_byte);
+         SAFE_ALLOCA (temp, unsigned char *, len1_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);
-         if (len1_byte > 20000)
-           xfree (temp);
+         SAFE_FREE ();
+
           graft_intervals_into_buffer (tmp_interval1, start2,
                                        len1, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval2, start1,
@@ -4086,7 +4256,9 @@ Transposing beyond buffer boundaries is an error.  */)
       else if (len1_byte < len2_byte)  /* Second region larger than first */
         /* Non-adjacent & unequal size, area between must also be shifted.  */
         {
-          modify_region (current_buffer, start1, end2);
+         USE_SAFE_ALLOCA;
+
+          modify_region (current_buffer, start1, end2, 0);
           record_change (start1, (end2 - start1));
           tmp_interval1 = copy_intervals (cur_intv, start1, len1);
           tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
@@ -4095,18 +4267,15 @@ Transposing beyond buffer boundaries is an error.  */)
                                Qnil, Qnil);
 
          /* holds region 2 */
-         if (len2_byte > 20000)
-           temp = (unsigned char *) xmalloc (len2_byte);
-         else
-           temp = (unsigned char *) alloca (len2_byte);
+         SAFE_ALLOCA (temp, unsigned char *, len2_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);
           bcopy (temp, start1_addr, len2_byte);
-         if (len2_byte > 20000)
-           xfree (temp);
+         SAFE_FREE ();
+
           graft_intervals_into_buffer (tmp_interval1, end2 - len1,
                                        len1, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
@@ -4117,8 +4286,10 @@ Transposing beyond buffer boundaries is an error.  */)
       else
        /* Second region smaller than first.  */
         {
+         USE_SAFE_ALLOCA;
+
           record_change (start1, (end2 - start1));
-          modify_region (current_buffer, start1, end2);
+          modify_region (current_buffer, start1, end2, 0);
 
           tmp_interval1 = copy_intervals (cur_intv, start1, len1);
           tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
@@ -4127,18 +4298,15 @@ Transposing beyond buffer boundaries is an error.  */)
                                Qnil, Qnil);
 
          /* holds region 1 */
-         if (len1_byte > 20000)
-           temp = (unsigned char *) xmalloc (len1_byte);
-         else
-           temp = (unsigned char *) alloca (len1_byte);
+         SAFE_ALLOCA (temp, unsigned char *, len1_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);
           bcopy (temp, start1_addr + len2_byte + len_mid, len1_byte);
-         if (len1_byte > 20000)
-           xfree (temp);
+         SAFE_FREE ();
+
           graft_intervals_into_buffer (tmp_interval1, end2 - len1,
                                        len1, current_buffer, 0);
           graft_intervals_into_buffer (tmp_interval_mid, start1 + len2,
@@ -4159,7 +4327,7 @@ Transposing beyond buffer boundaries is an error.  */)
       transpose_markers (start1, end1, start2, end2,
                         start1_byte, start1_byte + len1_byte,
                         start2_byte, start2_byte + len2_byte);
-      fix_overlays_in_range (start1, end2);
+      fix_start_end_in_overlays (start1, end2);
     }
 
   return Qnil;
@@ -4206,7 +4374,7 @@ functions if all the text being accessed has this property.  */);
   Vbuffer_access_fontified_property = Qnil;
 
   DEFVAR_LISP ("system-name", &Vsystem_name,
-              doc: /* The name of the machine Emacs is running on.  */);
+              doc: /* The host name of the machine Emacs is running on.  */);
 
   DEFVAR_LISP ("user-full-name", &Vuser_full_name,
               doc: /* The full name of the user logged in.  */);
@@ -4217,6 +4385,9 @@ functions if all the text being accessed has this property.  */);
   DEFVAR_LISP ("user-real-login-name", &Vuser_real_login_name,
               doc: /* The user's name, based upon the real uid only.  */);
 
+  DEFVAR_LISP ("operating-system-release", &Voperating_system_release,
+              doc: /* The release of the operating system Emacs is running on.  */);
+
   defsubr (&Spropertize);
   defsubr (&Schar_equal);
   defsubr (&Sgoto_char);
@@ -4282,6 +4453,7 @@ functions if all the text being accessed has this property.  */);
   defsubr (&Suser_full_name);
   defsubr (&Semacs_pid);
   defsubr (&Scurrent_time);
+  defsubr (&Sget_internal_run_time);
   defsubr (&Sformat_time_string);
   defsubr (&Sfloat_time);
   defsubr (&Sdecode_time);
@@ -4299,7 +4471,7 @@ functions if all the text being accessed has this property.  */);
   defsubr (&Sinsert_buffer_substring);
   defsubr (&Scompare_buffer_substrings);
   defsubr (&Ssubst_char_in_region);
-  defsubr (&Stranslate_region);
+  defsubr (&Stranslate_region_internal);
   defsubr (&Sdelete_region);
   defsubr (&Sdelete_and_extract_region);
   defsubr (&Swiden);