]> git.eshelyaron.com Git - emacs.git/commitdiff
Do not require float-time's arg to fit in time_t (Bug#11825).
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 7 Jul 2012 01:57:42 +0000 (18:57 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 7 Jul 2012 01:57:42 +0000 (18:57 -0700)
This works better on hosts where time_t is unsigned, and where
float-time is applied to the (negative) difference between two times.
* editfns.c (decode_time_components): Last arg is now double *,
not int *, and means to store all the result as a double, without
worrying about whether the seconds part fits in time_t.
All callers changed.
(lisp_time_argument): Remove last int * arg, as it's no longer needed.
All callers changed.
(Ffloat_time): Do not fail merely because the specified time falls
outside of time_t range.

src/ChangeLog
src/editfns.c
src/fileio.c
src/systime.h
src/undo.c

index 03c92804fb8874c252525f7a532c63511b2edf18..435c6d87050c51ae69511f748343275c51d60fee 100644 (file)
@@ -1,3 +1,17 @@
+2012-07-07  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Do not require float-time's arg to fit in time_t (Bug#11825).
+       This works better on hosts where time_t is unsigned, and where
+       float-time is applied to the (negative) difference between two times.
+       * editfns.c (decode_time_components): Last arg is now double *,
+       not int *, and means to store all the result as a double, without
+       worrying about whether the seconds part fits in time_t.
+       All callers changed.
+       (lisp_time_argument): Remove last int * arg, as it's no longer needed.
+       All callers changed.
+       (Ffloat_time): Do not fail merely because the specified time falls
+       outside of time_t range.
+
 2012-07-07  Glenn Morris  <rgm@gnu.org>
 
        * s/darwin.h (HAVE_RES_INIT, HAVE_LIBRESOLV):
index e40bea44e9c7e8ec169393f3084672892a66f78b..fe119490f3fe9c64b8cc2fac7d403eec37b2c324 100644 (file)
@@ -1521,16 +1521,20 @@ disassemble_lisp_time (Lisp_Object specified_time, Lisp_Object *phigh,
 }
 
 /* From the time components HIGH, LOW, USEC and PSEC taken from a Lisp
-   list, generate the corresponding EMACS_TIME value *RESULT, and
-   if RESULT_PSEC is not null store into *RESULT_PSEC the
-   (nonnegative) difference in picoseconds between the input time and
-   the returned time.  Return nonzero if successful.  */
+   list, generate the corresponding time value.
+
+   If RESULT is not null, store into *RESULT the converted time;
+   this can fail if the converted time does not fit into EMACS_TIME.
+   If *DRESULT is not null, store into *DRESULT the number of
+   seconds since the start of the POSIX Epoch.
+
+   Return nonzero if successful.  */
 int
 decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec,
-                       Lisp_Object psec, EMACS_TIME *result, int *result_psec)
+                       Lisp_Object psec,
+                       EMACS_TIME *result, double *dresult)
 {
   EMACS_INT hi, lo, us, ps;
-  time_t sec;
   if (! (INTEGERP (high) && INTEGERP (low)
         && INTEGERP (usec) && INTEGERP (psec)))
     return 0;
@@ -1548,27 +1552,38 @@ decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec,
   us = us % 1000000 + 1000000 * (us % 1000000 < 0);
   lo &= (1 << 16) - 1;
 
-  /* Check for overflow in the highest-order component.  */
-  if (! ((TYPE_SIGNED (time_t) ? TIME_T_MIN >> 16 <= hi : 0 <= hi)
-        && hi <= TIME_T_MAX >> 16))
-    return 0;
+  if (result)
+    {
+      if ((TYPE_SIGNED (time_t) ? TIME_T_MIN >> 16 <= hi : 0 <= hi)
+         && hi <= TIME_T_MAX >> 16)
+       {
+         /* Return the greatest representable time that is not greater
+            than the requested time.  */
+         time_t sec = hi;
+         EMACS_SET_SECS_NSECS (*result, (sec << 16) + lo,
+                               us * 1000 + ps / 1000);
+       }
+      else
+       {
+         /* Overflow in the highest-order component.  */
+         return 0;
+       }
+    }
+
+  if (dresult)
+    *dresult = (us * 1e6 + ps) / 1e12 + lo + hi * 65536.0;
 
-  sec = hi;
-  EMACS_SET_SECS_NSECS (*result, (sec << 16) + lo, us * 1000 + ps / 1000);
-  if (result_psec)
-    *result_psec = ps % 1000;
   return 1;
 }
 
 /* Decode a Lisp list SPECIFIED_TIME that represents a time.
    If SPECIFIED_TIME is nil, use the current time.
-   Round the time down to the nearest EMACS_TIME value, and
-   if PPSEC is not null store into *PPSEC the (nonnegative) difference in
-   picoseconds between the input time and the returned time.
+
+   Round the time down to the nearest EMACS_TIME value.
    Return seconds since the Epoch.
    Signal an error if unsuccessful.  */
 EMACS_TIME
-lisp_time_argument (Lisp_Object specified_time, int *ppsec)
+lisp_time_argument (Lisp_Object specified_time)
 {
   EMACS_TIME t;
   if (NILP (specified_time))
@@ -1577,14 +1592,15 @@ lisp_time_argument (Lisp_Object specified_time, int *ppsec)
     {
       Lisp_Object high, low, usec, psec;
       if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec)
-            && decode_time_components (high, low, usec, psec, &t, ppsec)))
+            && decode_time_components (high, low, usec, psec, &t, 0)))
        error ("Invalid time specification");
     }
   return t;
 }
 
 /* Like lisp_time_argument, except decode only the seconds part,
-   and do not check the subseconds part, and always round down.  */
+   do not allow out-of-range time stamps, do not check the subseconds part,
+   and always round down.  */
 static time_t
 lisp_seconds_argument (Lisp_Object specified_time)
 {
@@ -1616,12 +1632,21 @@ If precise time stamps are required, use either `current-time',
 or (if you need time as a string) `format-time-string'.  */)
   (Lisp_Object specified_time)
 {
-  int psec;
-  EMACS_TIME t = lisp_time_argument (specified_time, &psec);
-  double ps = (1000 * 1000 * 1000 <= INTMAX_MAX / 1000
-              ? EMACS_NSECS (t) * (intmax_t) 1000 + psec
-              : EMACS_NSECS (t) * 1e3 + psec);
-  return make_float (EMACS_SECS (t) + ps / 1e12);
+  double t;
+  if (NILP (specified_time))
+    {
+      EMACS_TIME now;
+      EMACS_GET_TIME (now);
+      t = EMACS_SECS (now) + EMACS_NSECS (now) / 1e9;
+    }
+  else
+    {
+      Lisp_Object high, low, usec, psec;
+      if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec)
+            && decode_time_components (high, low, usec, psec, 0, &t)))
+       error ("Invalid time specification");
+    }
+  return make_float (t);
 }
 
 /* Write information into buffer S of size MAXSIZE, according to the
@@ -1730,7 +1755,7 @@ For example, to produce full ISO 8601 format, use "%Y-%m-%dT%T%z".
 usage: (format-time-string FORMAT-STRING &optional TIME UNIVERSAL)  */)
   (Lisp_Object format_string, Lisp_Object timeval, Lisp_Object universal)
 {
-  EMACS_TIME t = lisp_time_argument (timeval, 0);
+  EMACS_TIME t = lisp_time_argument (timeval);
   struct tm tm;
 
   CHECK_STRING (format_string);
index 0f6a1d5f79951b2de29abda9e9012ba0337e5864..8f3b9e92257d8492813cf38ff95688445c473d2d 100644 (file)
@@ -3031,7 +3031,7 @@ Use the current time if TIMESTAMP is nil.  TIMESTAMP is in the format of
 {
   Lisp_Object absname, encoded_absname;
   Lisp_Object handler;
-  EMACS_TIME t = lisp_time_argument (timestamp, 0);
+  EMACS_TIME t = lisp_time_argument (timestamp);
 
   absname = Fexpand_file_name (filename, BVAR (current_buffer, directory));
 
@@ -5159,7 +5159,7 @@ An argument specifies the modification time value to use
 {
   if (!NILP (time_list))
     {
-      current_buffer->modtime = lisp_time_argument (time_list, 0);
+      current_buffer->modtime = lisp_time_argument (time_list);
       current_buffer->modtime_size = -1;
     }
   else
index 0f91551239e4a1c43349436701c64a3b3e4e0e83..938083a5ffc3cb70503fac4b48e8f4cfeb4341db 100644 (file)
@@ -112,8 +112,8 @@ extern void set_waiting_for_input (EMACS_TIME *);
 /* defined in editfns.c */
 extern Lisp_Object make_lisp_time (EMACS_TIME);
 extern int decode_time_components (Lisp_Object, Lisp_Object, Lisp_Object,
-                                  Lisp_Object, EMACS_TIME *, int *);
-extern EMACS_TIME lisp_time_argument (Lisp_Object, int *);
+                                  Lisp_Object, EMACS_TIME *, double *);
+extern EMACS_TIME lisp_time_argument (Lisp_Object);
 #endif
 
 /* Compare times T1 and T2 for equality, inequality etc.  */
index c4ef557a2212ae35bc62b1831e812730a4159415..bada46563a0fccf193eeaee9d5018936769d2fa9 100644 (file)
@@ -521,7 +521,7 @@ Return what remains of the list.  */)
                      (mod_time, 0,
                       XINT (XCAR (XCDR (XCDR (XCDR (cdr))))) / 1000);
                  else
-                   mod_time = lisp_time_argument (cdr, 0);
+                   mod_time = lisp_time_argument (cdr);
 
                  if (current_buffer->base_buffer)
                    base_buffer = current_buffer->base_buffer;