aboutsummaryrefslogtreecommitdiffstats
path: root/src/editfns.c
diff options
context:
space:
mode:
authorPaul Eggert2018-10-03 09:10:00 -0700
committerPaul Eggert2018-10-06 23:31:03 -0700
commitb5d08da1e9ea7ee1334d810348c656babe6a15d2 (patch)
treee42a93a11f341db5cde167332790ebf9ad717525 /src/editfns.c
parent44bf4a6b012f65327718b8c8334bfac1aee26370 (diff)
downloademacs-b5d08da1e9ea7ee1334d810348c656babe6a15d2.tar.gz
emacs-b5d08da1e9ea7ee1334d810348c656babe6a15d2.zip
Move timestamp-related stuff to timefns.c
This does not change behavior; it’s just long-overdue refactoring (Bug#32902). * src/emacs.c (main): Call init_timefns, syms_of_timefns. * src/timefns.c: New file, containing timestamp-related stuff from editfns.c and sysdep.c. * src/Makefile.in (base_obj): Add timefns.o. * src/editfns.c: Simplify by moving a big chunk to timefns.c. Do not include systime.h, sys/resource.h, sys/param.h, strftime.h, coding.h. (HAVE_TZALLOC_BUG, TM_YEAR_BASE, HAVE_TM_GMTOFF, tzeqlen) (local_tz, utc_tz, emacs_localtime_rz, emacs_mktime_z) (invalid_time_zone_specification, xtzfree, tzlookup) (TIME_T_MIN, TIME_T_MAX, time_overflow, invalid_time) (check_time_validity, hi_time, lo_time, Fcurrent_time) (time_add, time_subtract, time_arith, Ftime_add) (Ftime_subtract, Ftime_less_p, Fget_internal_run_time) (make_lisp_time, disassemble_lisp_time, decode_float_time) (lisp_to_timespec, lisp_time_struct, lisp_time_argument) (lisp_seconds_argument, Ffloat_time, emacs_nmemftime) (Fformat_time_string, format_time_string, Fdecode_time) (check_tm_member, Fencode_time, Fcurrent_time_string) (tm_gmtoff, Fcurrent_time_zone, Fset_time_zone_rule) (emacs_getenv_TZ, emacs_setenv_TZ): Move to timefns.c. * src/emacs.c (main): Adjust to initialization changes. * src/sysdep.c: Include <sys/resource.h> if it's present. Regularize includes a bit. (Fget_internal_run_time): Move here from editfns.c. (init_timefns, syms_of_timefns): New functions. * src/w32.h (w32_get_internal_run_time): Move decl here so that it need not be cloned. * test/src/editfns-tests.el: * test/src/editfns-tests.el (format-time-string-with-zone) (format-time-string-with-outlandish-zone) (editfns-tests--have-leap-seconds) (format-time-string-with-bignum-on-32-bit): Move to ... * test/src/timefns-tests.el: ... this new file.
Diffstat (limited to 'src/editfns.c')
-rw-r--r--src/editfns.c1289
1 files changed, 3 insertions, 1286 deletions
diff --git a/src/editfns.c b/src/editfns.c
index 47509c23d04..e995b38a44d 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -35,34 +35,13 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
35 35
36#include "lisp.h" 36#include "lisp.h"
37 37
38/* systime.h includes <sys/time.h> which, on some systems, is required
39 for <sys/resource.h>; thus systime.h must be included before
40 <sys/resource.h> */
41#include "systime.h"
42
43#if defined HAVE_SYS_RESOURCE_H
44#include <sys/resource.h>
45#endif
46
47#include <errno.h>
48#include <float.h> 38#include <float.h>
49#include <limits.h> 39#include <limits.h>
50#include <math.h> 40#include <math.h>
51 41
52#ifdef HAVE_TIMEZONE_T
53# include <sys/param.h>
54# if defined __NetBSD_Version__ && __NetBSD_Version__ < 700000000
55# define HAVE_TZALLOC_BUG true
56# endif
57#endif
58#ifndef HAVE_TZALLOC_BUG
59# define HAVE_TZALLOC_BUG false
60#endif
61
62#include <c-ctype.h> 42#include <c-ctype.h>
63#include <intprops.h> 43#include <intprops.h>
64#include <stdlib.h> 44#include <stdlib.h>
65#include <strftime.h>
66#include <verify.h> 45#include <verify.h>
67 46
68#include "composite.h" 47#include "composite.h"
@@ -70,34 +49,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
70#include "ptr-bounds.h" 49#include "ptr-bounds.h"
71#include "character.h" 50#include "character.h"
72#include "buffer.h" 51#include "buffer.h"
73#include "coding.h"
74#include "window.h" 52#include "window.h"
75#include "blockinput.h" 53#include "blockinput.h"
76 54
77#define TM_YEAR_BASE 1900
78
79#ifdef WINDOWSNT
80extern Lisp_Object w32_get_internal_run_time (void);
81#endif
82
83static struct lisp_time lisp_time_struct (Lisp_Object, int *);
84static Lisp_Object format_time_string (char const *, ptrdiff_t, struct timespec,
85 Lisp_Object, struct tm *);
86static long int tm_gmtoff (struct tm *);
87static int tm_diff (struct tm *, struct tm *);
88static void update_buffer_properties (ptrdiff_t, ptrdiff_t); 55static void update_buffer_properties (ptrdiff_t, ptrdiff_t);
89static Lisp_Object styled_format (ptrdiff_t, Lisp_Object *, bool); 56static Lisp_Object styled_format (ptrdiff_t, Lisp_Object *, bool);
90 57
91#ifndef HAVE_TM_GMTOFF
92# define HAVE_TM_GMTOFF false
93#endif
94
95enum { tzeqlen = sizeof "TZ=" - 1 };
96
97/* Time zones equivalent to current local time and to UTC, respectively. */
98static timezone_t local_tz;
99static timezone_t const utc_tz = 0;
100
101/* The cached value of Vsystem_name. This is used only to compare it 58/* The cached value of Vsystem_name. This is used only to compare it
102 to Vsystem_name, so it need not be visible to the GC. */ 59 to Vsystem_name, so it need not be visible to the GC. */
103static Lisp_Object cached_system_name; 60static Lisp_Object cached_system_name;
@@ -109,153 +66,9 @@ init_and_cache_system_name (void)
109 cached_system_name = Vsystem_name; 66 cached_system_name = Vsystem_name;
110} 67}
111 68
112static struct tm *
113emacs_localtime_rz (timezone_t tz, time_t const *t, struct tm *tm)
114{
115 tm = localtime_rz (tz, t, tm);
116 if (!tm && errno == ENOMEM)
117 memory_full (SIZE_MAX);
118 return tm;
119}
120
121static time_t
122emacs_mktime_z (timezone_t tz, struct tm *tm)
123{
124 errno = 0;
125 time_t t = mktime_z (tz, tm);
126 if (t == (time_t) -1 && errno == ENOMEM)
127 memory_full (SIZE_MAX);
128 return t;
129}
130
131static _Noreturn void
132invalid_time_zone_specification (Lisp_Object zone)
133{
134 xsignal2 (Qerror, build_string ("Invalid time zone specification"), zone);
135}
136
137/* Free a timezone, except do not free the time zone for local time.
138 Freeing utc_tz is also a no-op. */
139static void
140xtzfree (timezone_t tz)
141{
142 if (tz != local_tz)
143 tzfree (tz);
144}
145
146/* Convert the Lisp time zone rule ZONE to a timezone_t object.
147 The returned value either is 0, or is LOCAL_TZ, or is newly allocated.
148 If SETTZ, set Emacs local time to the time zone rule; otherwise,
149 the caller should eventually pass the returned value to xtzfree. */
150static timezone_t
151tzlookup (Lisp_Object zone, bool settz)
152{
153 static char const tzbuf_format[] = "<%+.*"pI"d>%s%"pI"d:%02d:%02d";
154 char const *trailing_tzbuf_format = tzbuf_format + sizeof "<%+.*"pI"d" - 1;
155 char tzbuf[sizeof tzbuf_format + 2 * INT_STRLEN_BOUND (EMACS_INT)];
156 char const *zone_string;
157 timezone_t new_tz;
158
159 if (NILP (zone))
160 return local_tz;
161 else if (EQ (zone, Qt) || EQ (zone, make_fixnum (0)))
162 {
163 zone_string = "UTC0";
164 new_tz = utc_tz;
165 }
166 else
167 {
168 bool plain_integer = FIXNUMP (zone);
169
170 if (EQ (zone, Qwall))
171 zone_string = 0;
172 else if (STRINGP (zone))
173 zone_string = SSDATA (ENCODE_SYSTEM (zone));
174 else if (plain_integer || (CONSP (zone) && FIXNUMP (XCAR (zone))
175 && CONSP (XCDR (zone))))
176 {
177 Lisp_Object abbr UNINIT;
178 if (!plain_integer)
179 {
180 abbr = XCAR (XCDR (zone));
181 zone = XCAR (zone);
182 }
183
184 EMACS_INT abszone = eabs (XFIXNUM (zone)), hour = abszone / (60 * 60);
185 int hour_remainder = abszone % (60 * 60);
186 int min = hour_remainder / 60, sec = hour_remainder % 60;
187
188 if (plain_integer)
189 {
190 int prec = 2;
191 EMACS_INT numzone = hour;
192 if (hour_remainder != 0)
193 {
194 prec += 2, numzone = 100 * numzone + min;
195 if (sec != 0)
196 prec += 2, numzone = 100 * numzone + sec;
197 }
198 sprintf (tzbuf, tzbuf_format, prec,
199 XFIXNUM (zone) < 0 ? -numzone : numzone,
200 &"-"[XFIXNUM (zone) < 0], hour, min, sec);
201 zone_string = tzbuf;
202 }
203 else
204 {
205 AUTO_STRING (leading, "<");
206 AUTO_STRING_WITH_LEN (trailing, tzbuf,
207 sprintf (tzbuf, trailing_tzbuf_format,
208 &"-"[XFIXNUM (zone) < 0],
209 hour, min, sec));
210 zone_string = SSDATA (concat3 (leading, ENCODE_SYSTEM (abbr),
211 trailing));
212 }
213 }
214 else
215 invalid_time_zone_specification (zone);
216
217 new_tz = tzalloc (zone_string);
218
219 if (HAVE_TZALLOC_BUG && !new_tz && errno != ENOMEM && plain_integer
220 && XFIXNUM (zone) % (60 * 60) == 0)
221 {
222 /* tzalloc mishandles POSIX strings; fall back on tzdb if
223 possible (Bug#30738). */
224 sprintf (tzbuf, "Etc/GMT%+"pI"d", - (XFIXNUM (zone) / (60 * 60)));
225 new_tz = tzalloc (zone_string);
226 }
227
228 if (!new_tz)
229 {
230 if (errno == ENOMEM)
231 memory_full (SIZE_MAX);
232 invalid_time_zone_specification (zone);
233 }
234 }
235
236 if (settz)
237 {
238 block_input ();
239 emacs_setenv_TZ (zone_string);
240 tzset ();
241 timezone_t old_tz = local_tz;
242 local_tz = new_tz;
243 tzfree (old_tz);
244 unblock_input ();
245 }
246
247 return new_tz;
248}
249
250void 69void
251init_editfns (bool dumping) 70init_editfns (void)
252{ 71{
253#if !defined CANNOT_DUMP
254 /* A valid but unlikely setting for the TZ environment variable.
255 It is OK (though a bit slower) if the user chooses this value. */
256 static char dump_tz_string[] = "TZ=UtC0";
257#endif
258
259 const char *user_name; 72 const char *user_name;
260 register char *p; 73 register char *p;
261 struct passwd *pw; /* password entry for the current user */ 74 struct passwd *pw; /* password entry for the current user */
@@ -264,37 +77,6 @@ init_editfns (bool dumping)
264 /* Set up system_name even when dumping. */ 77 /* Set up system_name even when dumping. */
265 init_and_cache_system_name (); 78 init_and_cache_system_name ();
266 79
267#ifndef CANNOT_DUMP
268 /* When just dumping out, set the time zone to a known unlikely value
269 and skip the rest of this function. */
270 if (dumping)
271 {
272 xputenv (dump_tz_string);
273 tzset ();
274 return;
275 }
276#endif
277
278 char *tz = getenv ("TZ");
279
280#if !defined CANNOT_DUMP
281 /* If the execution TZ happens to be the same as the dump TZ,
282 change it to some other value and then change it back,
283 to force the underlying implementation to reload the TZ info.
284 This is needed on implementations that load TZ info from files,
285 since the TZ file contents may differ between dump and execution. */
286 if (tz && strcmp (tz, &dump_tz_string[tzeqlen]) == 0)
287 {
288 ++*tz;
289 tzset ();
290 --*tz;
291 }
292#endif
293
294 /* Set the time zone rule now, so that the call to putenv is done
295 before multiple threads are active. */
296 tzlookup (tz ? build_string (tz) : Qwall, true);
297
298 pw = getpwuid (getuid ()); 80 pw = getpwuid (getuid ());
299#ifdef MSDOS 81#ifdef MSDOS
300 /* We let the real user name default to "root" because that's quite 82 /* We let the real user name default to "root" because that's quite
@@ -1349,7 +1131,7 @@ of the user with that uid, or nil if there is no such user. */)
1349 (That can happen if Emacs is dumpable 1131 (That can happen if Emacs is dumpable
1350 but you decide to run `temacs -l loadup' and not dump. */ 1132 but you decide to run `temacs -l loadup' and not dump. */
1351 if (NILP (Vuser_login_name)) 1133 if (NILP (Vuser_login_name))
1352 init_editfns (false); 1134 init_editfns ();
1353 1135
1354 if (NILP (uid)) 1136 if (NILP (uid))
1355 return Vuser_login_name; 1137 return Vuser_login_name;
@@ -1372,7 +1154,7 @@ This ignores the environment variables LOGNAME and USER, so it differs from
1372 (That can happen if Emacs is dumpable 1154 (That can happen if Emacs is dumpable
1373 but you decide to run `temacs -l loadup' and not dump. */ 1155 but you decide to run `temacs -l loadup' and not dump. */
1374 if (NILP (Vuser_login_name)) 1156 if (NILP (Vuser_login_name))
1375 init_editfns (false); 1157 init_editfns ();
1376 return Vuser_real_login_name; 1158 return Vuser_real_login_name;
1377} 1159}
1378 1160
@@ -1494,1058 +1276,6 @@ Value is a fixnum, if it's small enough, otherwise a bignum. */)
1494} 1276}
1495 1277
1496 1278
1497
1498#ifndef TIME_T_MIN
1499# define TIME_T_MIN TYPE_MINIMUM (time_t)
1500#endif
1501#ifndef TIME_T_MAX
1502# define TIME_T_MAX TYPE_MAXIMUM (time_t)
1503#endif
1504
1505/* Report that a time value is out of range for Emacs. */
1506void
1507time_overflow (void)
1508{
1509 error ("Specified time is not representable");
1510}
1511
1512static _Noreturn void
1513invalid_time (void)
1514{
1515 error ("Invalid time specification");
1516}
1517
1518/* Check a return value compatible with that of decode_time_components. */
1519static void
1520check_time_validity (int validity)
1521{
1522 if (validity <= 0)
1523 {
1524 if (validity < 0)
1525 time_overflow ();
1526 else
1527 invalid_time ();
1528 }
1529}
1530
1531/* Return the upper part of the time T (everything but the bottom 16 bits). */
1532static EMACS_INT
1533hi_time (time_t t)
1534{
1535 time_t hi = t >> LO_TIME_BITS;
1536 if (FIXNUM_OVERFLOW_P (hi))
1537 time_overflow ();
1538 return hi;
1539}
1540
1541/* Return the bottom bits of the time T. */
1542static int
1543lo_time (time_t t)
1544{
1545 return t & ((1 << LO_TIME_BITS) - 1);
1546}
1547
1548DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0,
1549 doc: /* Return the current time, as the number of seconds since 1970-01-01 00:00:00.
1550The time is returned as a list of integers (HIGH LOW USEC PSEC).
1551HIGH has the most significant bits of the seconds, while LOW has the
1552least significant 16 bits. USEC and PSEC are the microsecond and
1553picosecond counts. */)
1554 (void)
1555{
1556 return make_lisp_time (current_timespec ());
1557}
1558
1559static struct lisp_time
1560time_add (struct lisp_time ta, struct lisp_time tb)
1561{
1562 EMACS_INT hi = ta.hi + tb.hi;
1563 int lo = ta.lo + tb.lo;
1564 int us = ta.us + tb.us;
1565 int ps = ta.ps + tb.ps;
1566 us += (1000000 <= ps);
1567 ps -= (1000000 <= ps) * 1000000;
1568 lo += (1000000 <= us);
1569 us -= (1000000 <= us) * 1000000;
1570 hi += (1 << LO_TIME_BITS <= lo);
1571 lo -= (1 << LO_TIME_BITS <= lo) << LO_TIME_BITS;
1572 return (struct lisp_time) { hi, lo, us, ps };
1573}
1574
1575static struct lisp_time
1576time_subtract (struct lisp_time ta, struct lisp_time tb)
1577{
1578 EMACS_INT hi = ta.hi - tb.hi;
1579 int lo = ta.lo - tb.lo;
1580 int us = ta.us - tb.us;
1581 int ps = ta.ps - tb.ps;
1582 us -= (ps < 0);
1583 ps += (ps < 0) * 1000000;
1584 lo -= (us < 0);
1585 us += (us < 0) * 1000000;
1586 hi -= (lo < 0);
1587 lo += (lo < 0) << LO_TIME_BITS;
1588 return (struct lisp_time) { hi, lo, us, ps };
1589}
1590
1591static Lisp_Object
1592time_arith (Lisp_Object a, Lisp_Object b, bool subtract)
1593{
1594 if (FLOATP (a) && !isfinite (XFLOAT_DATA (a)))
1595 {
1596 double da = XFLOAT_DATA (a);
1597 double db = XFLOAT_DATA (Ffloat_time (b));
1598 return make_float (subtract ? da - db : da + db);
1599 }
1600 if (FLOATP (b) && !isfinite (XFLOAT_DATA (b)))
1601 return subtract ? make_float (-XFLOAT_DATA (b)) : b;
1602
1603 int alen, blen;
1604 struct lisp_time ta = lisp_time_struct (a, &alen);
1605 struct lisp_time tb = lisp_time_struct (b, &blen);
1606 struct lisp_time t = (subtract ? time_subtract : time_add) (ta, tb);
1607 if (FIXNUM_OVERFLOW_P (t.hi))
1608 time_overflow ();
1609 Lisp_Object val = Qnil;
1610
1611 switch (max (alen, blen))
1612 {
1613 default:
1614 val = Fcons (make_fixnum (t.ps), val);
1615 FALLTHROUGH;
1616 case 3:
1617 val = Fcons (make_fixnum (t.us), val);
1618 FALLTHROUGH;
1619 case 2:
1620 val = Fcons (make_fixnum (t.lo), val);
1621 val = Fcons (make_fixnum (t.hi), val);
1622 break;
1623 }
1624
1625 return val;
1626}
1627
1628DEFUN ("time-add", Ftime_add, Stime_add, 2, 2, 0,
1629 doc: /* Return the sum of two time values A and B, as a time value.
1630A nil value for either argument stands for the current time.
1631See `current-time-string' for the various forms of a time value. */)
1632 (Lisp_Object a, Lisp_Object b)
1633{
1634 return time_arith (a, b, false);
1635}
1636
1637DEFUN ("time-subtract", Ftime_subtract, Stime_subtract, 2, 2, 0,
1638 doc: /* Return the difference between two time values A and B, as a time value.
1639Use `float-time' to convert the difference into elapsed seconds.
1640A nil value for either argument stands for the current time.
1641See `current-time-string' for the various forms of a time value. */)
1642 (Lisp_Object a, Lisp_Object b)
1643{
1644 return time_arith (a, b, true);
1645}
1646
1647/* Return negative, 0, positive if a < b, a == b, a > b respectively.
1648 Return positive if either a or b is a NaN; this is good enough
1649 for the current callers. */
1650static int
1651time_cmp (Lisp_Object a, Lisp_Object b)
1652{
1653 if ((FLOATP (a) && !isfinite (XFLOAT_DATA (a)))
1654 || (FLOATP (b) && !isfinite (XFLOAT_DATA (b))))
1655 {
1656 double da = FLOATP (a) ? XFLOAT_DATA (a) : 0;
1657 double db = FLOATP (b) ? XFLOAT_DATA (b) : 0;
1658 return da < db ? -1 : da != db;
1659 }
1660
1661 int alen, blen;
1662 struct lisp_time ta = lisp_time_struct (a, &alen);
1663 struct lisp_time tb = lisp_time_struct (b, &blen);
1664 return (ta.hi != tb.hi ? (ta.hi < tb.hi ? -1 : 1)
1665 : ta.lo != tb.lo ? (ta.lo < tb.lo ? -1 : 1)
1666 : ta.us != tb.us ? (ta.us < tb.us ? -1 : 1)
1667 : ta.ps < tb.ps ? -1 : ta.ps != tb.ps);
1668}
1669
1670DEFUN ("time-less-p", Ftime_less_p, Stime_less_p, 2, 2, 0,
1671 doc: /* Return non-nil if time value T1 is earlier than time value T2.
1672A nil value for either argument stands for the current time.
1673See `current-time-string' for the various forms of a time value. */)
1674 (Lisp_Object t1, Lisp_Object t2)
1675{
1676 return time_cmp (t1, t2) < 0 ? Qt : Qnil;
1677}
1678
1679DEFUN ("time-equal-p", Ftime_equal_p, Stime_equal_p, 2, 2, 0,
1680 doc: /* Return non-nil if T1 and T2 are equal time values.
1681A nil value for either argument stands for the current time.
1682See `current-time-string' for the various forms of a time value. */)
1683 (Lisp_Object t1, Lisp_Object t2)
1684{
1685 return time_cmp (t1, t2) == 0 ? Qt : Qnil;
1686}
1687
1688
1689DEFUN ("get-internal-run-time", Fget_internal_run_time, Sget_internal_run_time,
1690 0, 0, 0,
1691 doc: /* Return the current run time used by Emacs.
1692The time is returned as in the style of `current-time'.
1693
1694On systems that can't determine the run time, `get-internal-run-time'
1695does the same thing as `current-time'. */)
1696 (void)
1697{
1698#ifdef HAVE_GETRUSAGE
1699 struct rusage usage;
1700 time_t secs;
1701 int usecs;
1702
1703 if (getrusage (RUSAGE_SELF, &usage) < 0)
1704 /* This shouldn't happen. What action is appropriate? */
1705 xsignal0 (Qerror);
1706
1707 /* Sum up user time and system time. */
1708 secs = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
1709 usecs = usage.ru_utime.tv_usec + usage.ru_stime.tv_usec;
1710 if (usecs >= 1000000)
1711 {
1712 usecs -= 1000000;
1713 secs++;
1714 }
1715 return make_lisp_time (make_timespec (secs, usecs * 1000));
1716#else /* ! HAVE_GETRUSAGE */
1717#ifdef WINDOWSNT
1718 return w32_get_internal_run_time ();
1719#else /* ! WINDOWSNT */
1720 return Fcurrent_time ();
1721#endif /* WINDOWSNT */
1722#endif /* HAVE_GETRUSAGE */
1723}
1724
1725
1726/* Make a Lisp list that represents the Emacs time T. T may be an
1727 invalid time, with a slightly negative tv_nsec value such as
1728 UNKNOWN_MODTIME_NSECS; in that case, the Lisp list contains a
1729 correspondingly negative picosecond count. */
1730Lisp_Object
1731make_lisp_time (struct timespec t)
1732{
1733 time_t s = t.tv_sec;
1734 int ns = t.tv_nsec;
1735 return list4i (hi_time (s), lo_time (s), ns / 1000, ns % 1000 * 1000);
1736}
1737
1738/* Decode a Lisp list SPECIFIED_TIME that represents a time.
1739 Set *PHIGH, *PLOW, *PUSEC, *PPSEC to its parts; do not check their values.
1740 Return 2, 3, or 4 to indicate the effective length of SPECIFIED_TIME
1741 if successful, 0 if unsuccessful. */
1742static int
1743disassemble_lisp_time (Lisp_Object specified_time, Lisp_Object *phigh,
1744 Lisp_Object *plow, Lisp_Object *pusec,
1745 Lisp_Object *ppsec)
1746{
1747 Lisp_Object high = make_fixnum (0);
1748 Lisp_Object low = specified_time;
1749 Lisp_Object usec = make_fixnum (0);
1750 Lisp_Object psec = make_fixnum (0);
1751 int len = 4;
1752
1753 if (CONSP (specified_time))
1754 {
1755 high = XCAR (specified_time);
1756 low = XCDR (specified_time);
1757 if (CONSP (low))
1758 {
1759 Lisp_Object low_tail = XCDR (low);
1760 low = XCAR (low);
1761 if (CONSP (low_tail))
1762 {
1763 usec = XCAR (low_tail);
1764 low_tail = XCDR (low_tail);
1765 if (CONSP (low_tail))
1766 psec = XCAR (low_tail);
1767 else
1768 len = 3;
1769 }
1770 else if (!NILP (low_tail))
1771 {
1772 usec = low_tail;
1773 len = 3;
1774 }
1775 else
1776 len = 2;
1777 }
1778 else
1779 len = 2;
1780
1781 /* When combining components, require LOW to be an integer,
1782 as otherwise it would be a pain to add up times. */
1783 if (! INTEGERP (low))
1784 return 0;
1785 }
1786 else if (INTEGERP (specified_time))
1787 len = 2;
1788
1789 *phigh = high;
1790 *plow = low;
1791 *pusec = usec;
1792 *ppsec = psec;
1793 return len;
1794}
1795
1796/* Convert T into an Emacs time *RESULT, truncating toward minus infinity.
1797 Return true if T is in range, false otherwise. */
1798static bool
1799decode_float_time (double t, struct lisp_time *result)
1800{
1801 double lo_multiplier = 1 << LO_TIME_BITS;
1802 double emacs_time_min = MOST_NEGATIVE_FIXNUM * lo_multiplier;
1803 if (! (emacs_time_min <= t && t < -emacs_time_min))
1804 return false;
1805
1806 double small_t = t / lo_multiplier;
1807 EMACS_INT hi = small_t;
1808 double t_sans_hi = t - hi * lo_multiplier;
1809 int lo = t_sans_hi;
1810 long double fracps = (t_sans_hi - lo) * 1e12L;
1811#ifdef INT_FAST64_MAX
1812 int_fast64_t ifracps = fracps;
1813 int us = ifracps / 1000000;
1814 int ps = ifracps % 1000000;
1815#else
1816 int us = fracps / 1e6L;
1817 int ps = fracps - us * 1e6L;
1818#endif
1819 us -= (ps < 0);
1820 ps += (ps < 0) * 1000000;
1821 lo -= (us < 0);
1822 us += (us < 0) * 1000000;
1823 hi -= (lo < 0);
1824 lo += (lo < 0) << LO_TIME_BITS;
1825 result->hi = hi;
1826 result->lo = lo;
1827 result->us = us;
1828 result->ps = ps;
1829 return true;
1830}
1831
1832/* From the time components HIGH, LOW, USEC and PSEC taken from a Lisp
1833 list, generate the corresponding time value.
1834 If LOW is floating point, the other components should be zero.
1835
1836 If RESULT is not null, store into *RESULT the converted time.
1837 If *DRESULT is not null, store into *DRESULT the number of
1838 seconds since the start of the POSIX Epoch.
1839
1840 Return 1 if successful, 0 if the components are of the
1841 wrong type, and -1 if the time is out of range. */
1842int
1843decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec,
1844 Lisp_Object psec,
1845 struct lisp_time *result, double *dresult)
1846{
1847 EMACS_INT hi, us, ps;
1848 intmax_t lo;
1849 if (! (FIXNUMP (high)
1850 && FIXNUMP (usec) && FIXNUMP (psec)))
1851 return 0;
1852 if (! INTEGERP (low))
1853 {
1854 if (FLOATP (low))
1855 {
1856 double t = XFLOAT_DATA (low);
1857 if (result && ! decode_float_time (t, result))
1858 return -1;
1859 if (dresult)
1860 *dresult = t;
1861 return 1;
1862 }
1863 else if (NILP (low))
1864 {
1865 struct timespec now = current_timespec ();
1866 if (result)
1867 {
1868 result->hi = hi_time (now.tv_sec);
1869 result->lo = lo_time (now.tv_sec);
1870 result->us = now.tv_nsec / 1000;
1871 result->ps = now.tv_nsec % 1000 * 1000;
1872 }
1873 if (dresult)
1874 *dresult = now.tv_sec + now.tv_nsec / 1e9;
1875 return 1;
1876 }
1877 else
1878 return 0;
1879 }
1880
1881 hi = XFIXNUM (high);
1882 if (! integer_to_intmax (low, &lo))
1883 return -1;
1884 us = XFIXNUM (usec);
1885 ps = XFIXNUM (psec);
1886
1887 /* Normalize out-of-range lower-order components by carrying
1888 each overflow into the next higher-order component. */
1889 us += ps / 1000000 - (ps % 1000000 < 0);
1890 lo += us / 1000000 - (us % 1000000 < 0);
1891 if (INT_ADD_WRAPV (lo >> LO_TIME_BITS, hi, &hi))
1892 return -1;
1893 ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0);
1894 us = us % 1000000 + 1000000 * (us % 1000000 < 0);
1895 lo &= (1 << LO_TIME_BITS) - 1;
1896
1897 if (result)
1898 {
1899 if (FIXNUM_OVERFLOW_P (hi))
1900 return -1;
1901 result->hi = hi;
1902 result->lo = lo;
1903 result->us = us;
1904 result->ps = ps;
1905 }
1906
1907 if (dresult)
1908 {
1909 double dhi = hi;
1910 *dresult = (us * 1e6 + ps) / 1e12 + lo + dhi * (1 << LO_TIME_BITS);
1911 }
1912
1913 return 1;
1914}
1915
1916struct timespec
1917lisp_to_timespec (struct lisp_time t)
1918{
1919 if (! ((TYPE_SIGNED (time_t) ? TIME_T_MIN >> LO_TIME_BITS <= t.hi : 0 <= t.hi)
1920 && t.hi <= TIME_T_MAX >> LO_TIME_BITS))
1921 return invalid_timespec ();
1922 time_t s = (t.hi << LO_TIME_BITS) + t.lo;
1923 int ns = t.us * 1000 + t.ps / 1000;
1924 return make_timespec (s, ns);
1925}
1926
1927/* Decode a Lisp list SPECIFIED_TIME that represents a time.
1928 Store its effective length into *PLEN.
1929 If SPECIFIED_TIME is nil, use the current time.
1930 Signal an error if SPECIFIED_TIME does not represent a time. */
1931static struct lisp_time
1932lisp_time_struct (Lisp_Object specified_time, int *plen)
1933{
1934 Lisp_Object high, low, usec, psec;
1935 struct lisp_time t;
1936 int len = disassemble_lisp_time (specified_time, &high, &low, &usec, &psec);
1937 if (!len)
1938 invalid_time ();
1939 int val = decode_time_components (high, low, usec, psec, &t, 0);
1940 check_time_validity (val);
1941 *plen = len;
1942 return t;
1943}
1944
1945/* Like lisp_time_struct, except return a struct timespec.
1946 Discard any low-order digits. */
1947struct timespec
1948lisp_time_argument (Lisp_Object specified_time)
1949{
1950 int len;
1951 struct lisp_time lt = lisp_time_struct (specified_time, &len);
1952 struct timespec t = lisp_to_timespec (lt);
1953 if (! timespec_valid_p (t))
1954 time_overflow ();
1955 return t;
1956}
1957
1958/* Like lisp_time_argument, except decode only the seconds part,
1959 and do not check the subseconds part. */
1960static time_t
1961lisp_seconds_argument (Lisp_Object specified_time)
1962{
1963 Lisp_Object high, low, usec, psec;
1964 struct lisp_time t;
1965
1966 int val = disassemble_lisp_time (specified_time, &high, &low, &usec, &psec);
1967 if (val != 0)
1968 {
1969 val = decode_time_components (high, low, make_fixnum (0),
1970 make_fixnum (0), &t, 0);
1971 if (0 < val
1972 && ! ((TYPE_SIGNED (time_t)
1973 ? TIME_T_MIN >> LO_TIME_BITS <= t.hi
1974 : 0 <= t.hi)
1975 && t.hi <= TIME_T_MAX >> LO_TIME_BITS))
1976 val = -1;
1977 }
1978 check_time_validity (val);
1979 return (t.hi << LO_TIME_BITS) + t.lo;
1980}
1981
1982DEFUN ("float-time", Ffloat_time, Sfloat_time, 0, 1, 0,
1983 doc: /* Return the current time, as a float number of seconds since the epoch.
1984If SPECIFIED-TIME is given, it is the time to convert to float
1985instead of the current time. The argument should have the form
1986\(HIGH LOW) or (HIGH LOW USEC) or (HIGH LOW USEC PSEC). Thus,
1987you can use times from `current-time' and from `file-attributes'.
1988SPECIFIED-TIME can also have the form (HIGH . LOW), but this is
1989considered obsolete.
1990
1991WARNING: Since the result is floating point, it may not be exact.
1992If precise time stamps are required, use either `current-time',
1993or (if you need time as a string) `format-time-string'. */)
1994 (Lisp_Object specified_time)
1995{
1996 double t;
1997 Lisp_Object high, low, usec, psec;
1998 if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec)
1999 && decode_time_components (high, low, usec, psec, 0, &t)))
2000 invalid_time ();
2001 return make_float (t);
2002}
2003
2004/* Write information into buffer S of size MAXSIZE, according to the
2005 FORMAT of length FORMAT_LEN, using time information taken from *TP.
2006 Use the time zone specified by TZ.
2007 Use NS as the number of nanoseconds in the %N directive.
2008 Return the number of bytes written, not including the terminating
2009 '\0'. If S is NULL, nothing will be written anywhere; so to
2010 determine how many bytes would be written, use NULL for S and
2011 ((size_t) -1) for MAXSIZE.
2012
2013 This function behaves like nstrftime, except it allows null
2014 bytes in FORMAT and it does not support nanoseconds. */
2015static size_t
2016emacs_nmemftime (char *s, size_t maxsize, const char *format,
2017 size_t format_len, const struct tm *tp, timezone_t tz, int ns)
2018{
2019 size_t total = 0;
2020
2021 /* Loop through all the null-terminated strings in the format
2022 argument. Normally there's just one null-terminated string, but
2023 there can be arbitrarily many, concatenated together, if the
2024 format contains '\0' bytes. nstrftime stops at the first
2025 '\0' byte so we must invoke it separately for each such string. */
2026 for (;;)
2027 {
2028 size_t len;
2029 size_t result;
2030
2031 if (s)
2032 s[0] = '\1';
2033
2034 result = nstrftime (s, maxsize, format, tp, tz, ns);
2035
2036 if (s)
2037 {
2038 if (result == 0 && s[0] != '\0')
2039 return 0;
2040 s += result + 1;
2041 }
2042
2043 maxsize -= result + 1;
2044 total += result;
2045 len = strlen (format);
2046 if (len == format_len)
2047 return total;
2048 total++;
2049 format += len + 1;
2050 format_len -= len + 1;
2051 }
2052}
2053
2054DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
2055 doc: /* Use FORMAT-STRING to format the time TIME, or now if omitted or nil.
2056TIME is specified as (HIGH LOW USEC PSEC), as returned by
2057`current-time' or `file-attributes'. It can also be a single integer
2058number of seconds since the epoch. The obsolete form (HIGH . LOW) is
2059also still accepted.
2060
2061The optional ZONE is omitted or nil for Emacs local time, t for
2062Universal Time, `wall' for system wall clock time, or a string as in
2063the TZ environment variable. It can also be a list (as from
2064`current-time-zone') or an integer (as from `decode-time') applied
2065without consideration for daylight saving time.
2066
2067The value is a copy of FORMAT-STRING, but with certain constructs replaced
2068by text that describes the specified date and time in TIME:
2069
2070%Y is the year, %y within the century, %C the century.
2071%G is the year corresponding to the ISO week, %g within the century.
2072%m is the numeric month.
2073%b and %h are the locale's abbreviated month name, %B the full name.
2074 (%h is not supported on MS-Windows.)
2075%d is the day of the month, zero-padded, %e is blank-padded.
2076%u is the numeric day of week from 1 (Monday) to 7, %w from 0 (Sunday) to 6.
2077%a is the locale's abbreviated name of the day of week, %A the full name.
2078%U is the week number starting on Sunday, %W starting on Monday,
2079 %V according to ISO 8601.
2080%j is the day of the year.
2081
2082%H is the hour on a 24-hour clock, %I is on a 12-hour clock, %k is like %H
2083 only blank-padded, %l is like %I blank-padded.
2084%p is the locale's equivalent of either AM or PM.
2085%q is the calendar quarter (1–4).
2086%M is the minute (00-59).
2087%S is the second (00-59; 00-60 on platforms with leap seconds)
2088%s is the number of seconds since 1970-01-01 00:00:00 +0000.
2089%N is the nanosecond, %6N the microsecond, %3N the millisecond, etc.
2090%Z is the time zone abbreviation, %z is the numeric form.
2091
2092%c is the locale's date and time format.
2093%x is the locale's "preferred" date format.
2094%D is like "%m/%d/%y".
2095%F is the ISO 8601 date format (like "%Y-%m-%d").
2096
2097%R is like "%H:%M", %T is like "%H:%M:%S", %r is like "%I:%M:%S %p".
2098%X is the locale's "preferred" time format.
2099
2100Finally, %n is a newline, %t is a tab, %% is a literal %, and
2101unrecognized %-sequences stand for themselves.
2102
2103Certain flags and modifiers are available with some format controls.
2104The flags are `_', `-', `^' and `#'. For certain characters X,
2105%_X is like %X, but padded with blanks; %-X is like %X,
2106but without padding. %^X is like %X, but with all textual
2107characters up-cased; %#X is like %X, but with letter-case of
2108all textual characters reversed.
2109%NX (where N stands for an integer) is like %X,
2110but takes up at least N (a number) positions.
2111The modifiers are `E' and `O'. For certain characters X,
2112%EX is a locale's alternative version of %X;
2113%OX is like %X, but uses the locale's number symbols.
2114
2115For example, to produce full ISO 8601 format, use "%FT%T%z".
2116
2117usage: (format-time-string FORMAT-STRING &optional TIME ZONE) */)
2118 (Lisp_Object format_string, Lisp_Object timeval, Lisp_Object zone)
2119{
2120 struct timespec t = lisp_time_argument (timeval);
2121 struct tm tm;
2122
2123 CHECK_STRING (format_string);
2124 format_string = code_convert_string_norecord (format_string,
2125 Vlocale_coding_system, 1);
2126 return format_time_string (SSDATA (format_string), SBYTES (format_string),
2127 t, zone, &tm);
2128}
2129
2130static Lisp_Object
2131format_time_string (char const *format, ptrdiff_t formatlen,
2132 struct timespec t, Lisp_Object zone, struct tm *tmp)
2133{
2134 char buffer[4000];
2135 char *buf = buffer;
2136 ptrdiff_t size = sizeof buffer;
2137 size_t len;
2138 int ns = t.tv_nsec;
2139 USE_SAFE_ALLOCA;
2140
2141 timezone_t tz = tzlookup (zone, false);
2142 /* On some systems, like 32-bit MinGW, tv_sec of struct timespec is
2143 a 64-bit type, but time_t is a 32-bit type. emacs_localtime_rz
2144 expects a pointer to time_t value. */
2145 time_t tsec = t.tv_sec;
2146 tmp = emacs_localtime_rz (tz, &tsec, tmp);
2147 if (! tmp)
2148 {
2149 xtzfree (tz);
2150 time_overflow ();
2151 }
2152 synchronize_system_time_locale ();
2153
2154 while (true)
2155 {
2156 buf[0] = '\1';
2157 len = emacs_nmemftime (buf, size, format, formatlen, tmp, tz, ns);
2158 if ((0 < len && len < size) || (len == 0 && buf[0] == '\0'))
2159 break;
2160
2161 /* Buffer was too small, so make it bigger and try again. */
2162 len = emacs_nmemftime (NULL, SIZE_MAX, format, formatlen, tmp, tz, ns);
2163 if (STRING_BYTES_BOUND <= len)
2164 {
2165 xtzfree (tz);
2166 string_overflow ();
2167 }
2168 size = len + 1;
2169 buf = SAFE_ALLOCA (size);
2170 }
2171
2172 xtzfree (tz);
2173 AUTO_STRING_WITH_LEN (bufstring, buf, len);
2174 Lisp_Object result = code_convert_string_norecord (bufstring,
2175 Vlocale_coding_system, 0);
2176 SAFE_FREE ();
2177 return result;
2178}
2179
2180DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 2, 0,
2181 doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF).
2182The optional TIME should be a list of (HIGH LOW . IGNORED),
2183as from `current-time' and `file-attributes', or nil to use the
2184current time. It can also be a single integer number of seconds since
2185the epoch. The obsolete form (HIGH . LOW) is also still accepted.
2186
2187The optional ZONE is omitted or nil for Emacs local time, t for
2188Universal Time, `wall' for system wall clock time, or a string as in
2189the TZ environment variable. It can also be a list (as from
2190`current-time-zone') or an integer (the UTC offset in seconds) applied
2191without consideration for daylight saving time.
2192
2193The list has the following nine members: SEC is an integer between 0
2194and 60; SEC is 60 for a leap second, which only some operating systems
2195support. MINUTE is an integer between 0 and 59. HOUR is an integer
2196between 0 and 23. DAY is an integer between 1 and 31. MONTH is an
2197integer between 1 and 12. YEAR is an integer indicating the
2198four-digit year. DOW is the day of week, an integer between 0 and 6,
2199where 0 is Sunday. DST is t if daylight saving time is in effect,
2200nil if it is not in effect, and -1 if this information is
2201not available. UTCOFF is an integer indicating the UTC offset in
2202seconds, i.e., the number of seconds east of Greenwich. (Note that
2203Common Lisp has different meanings for DOW and UTCOFF.)
2204
2205usage: (decode-time &optional TIME ZONE) */)
2206 (Lisp_Object specified_time, Lisp_Object zone)
2207{
2208 time_t time_spec = lisp_seconds_argument (specified_time);
2209 struct tm local_tm, gmt_tm;
2210 timezone_t tz = tzlookup (zone, false);
2211 struct tm *tm = emacs_localtime_rz (tz, &time_spec, &local_tm);
2212 xtzfree (tz);
2213
2214 if (! (tm
2215 && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= local_tm.tm_year
2216 && local_tm.tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE))
2217 time_overflow ();
2218
2219 /* Avoid overflow when INT_MAX < EMACS_INT_MAX. */
2220 EMACS_INT tm_year_base = TM_YEAR_BASE;
2221
2222 return CALLN (Flist,
2223 make_fixnum (local_tm.tm_sec),
2224 make_fixnum (local_tm.tm_min),
2225 make_fixnum (local_tm.tm_hour),
2226 make_fixnum (local_tm.tm_mday),
2227 make_fixnum (local_tm.tm_mon + 1),
2228 make_fixnum (local_tm.tm_year + tm_year_base),
2229 make_fixnum (local_tm.tm_wday),
2230 (local_tm.tm_isdst < 0 ? make_fixnum (-1)
2231 : local_tm.tm_isdst == 0 ? Qnil : Qt),
2232 (HAVE_TM_GMTOFF
2233 ? make_fixnum (tm_gmtoff (&local_tm))
2234 : gmtime_r (&time_spec, &gmt_tm)
2235 ? make_fixnum (tm_diff (&local_tm, &gmt_tm))
2236 : Qnil));
2237}
2238
2239/* Return OBJ - OFFSET, checking that OBJ is a valid fixnum and that
2240 the result is representable as an int. */
2241static int
2242check_tm_member (Lisp_Object obj, int offset)
2243{
2244 CHECK_FIXNUM (obj);
2245 EMACS_INT n = XFIXNUM (obj);
2246 int result;
2247 if (INT_SUBTRACT_WRAPV (n, offset, &result))
2248 time_overflow ();
2249 return result;
2250}
2251
2252DEFUN ("encode-time", Fencode_time, Sencode_time, 6, MANY, 0,
2253 doc: /* Convert SECOND, MINUTE, HOUR, DAY, MONTH, YEAR and ZONE to internal time.
2254This is the reverse operation of `decode-time', which see.
2255
2256The optional ZONE is omitted or nil for Emacs local time, t for
2257Universal Time, `wall' for system wall clock time, or a string as in
2258the TZ environment variable. It can also be a list (as from
2259`current-time-zone') or an integer (as from `decode-time') applied
2260without consideration for daylight saving time.
2261
2262You can pass more than 7 arguments; then the first six arguments
2263are used as SECOND through YEAR, and the *last* argument is used as ZONE.
2264The intervening arguments are ignored.
2265This feature lets (apply \\='encode-time (decode-time ...)) work.
2266
2267Out-of-range values for SECOND, MINUTE, HOUR, DAY, or MONTH are allowed;
2268for example, a DAY of 0 means the day preceding the given month.
2269Year numbers less than 100 are treated just like other year numbers.
2270If you want them to stand for years in this century, you must do that yourself.
2271
2272Years before 1970 are not guaranteed to work. On some systems,
2273year values as low as 1901 do work.
2274
2275usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */)
2276 (ptrdiff_t nargs, Lisp_Object *args)
2277{
2278 time_t value;
2279 struct tm tm;
2280 Lisp_Object zone = (nargs > 6 ? args[nargs - 1] : Qnil);
2281
2282 tm.tm_sec = check_tm_member (args[0], 0);
2283 tm.tm_min = check_tm_member (args[1], 0);
2284 tm.tm_hour = check_tm_member (args[2], 0);
2285 tm.tm_mday = check_tm_member (args[3], 0);
2286 tm.tm_mon = check_tm_member (args[4], 1);
2287 tm.tm_year = check_tm_member (args[5], TM_YEAR_BASE);
2288 tm.tm_isdst = -1;
2289
2290 timezone_t tz = tzlookup (zone, false);
2291 value = emacs_mktime_z (tz, &tm);
2292 xtzfree (tz);
2293
2294 if (value == (time_t) -1)
2295 time_overflow ();
2296
2297 return list2i (hi_time (value), lo_time (value));
2298}
2299
2300DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string,
2301 0, 2, 0,
2302 doc: /* Return the current local time, as a human-readable string.
2303Programs can use this function to decode a time,
2304since the number of columns in each field is fixed
2305if the year is in the range 1000-9999.
2306The format is `Sun Sep 16 01:03:52 1973'.
2307However, see also the functions `decode-time' and `format-time-string'
2308which provide a much more powerful and general facility.
2309
2310If SPECIFIED-TIME is given, it is a time to format instead of the
2311current time. The argument should have the form (HIGH LOW . IGNORED).
2312Thus, you can use times obtained from `current-time' and from
2313`file-attributes'. SPECIFIED-TIME can also be a single integer number
2314of seconds since the epoch. The obsolete form (HIGH . LOW) is also
2315still accepted.
2316
2317The optional ZONE is omitted or nil for Emacs local time, t for
2318Universal Time, `wall' for system wall clock time, or a string as in
2319the TZ environment variable. It can also be a list (as from
2320`current-time-zone') or an integer (as from `decode-time') applied
2321without consideration for daylight saving time. */)
2322 (Lisp_Object specified_time, Lisp_Object zone)
2323{
2324 time_t value = lisp_seconds_argument (specified_time);
2325 timezone_t tz = tzlookup (zone, false);
2326
2327 /* Convert to a string in ctime format, except without the trailing
2328 newline, and without the 4-digit year limit. Don't use asctime
2329 or ctime, as they might dump core if the year is outside the
2330 range -999 .. 9999. */
2331 struct tm tm;
2332 struct tm *tmp = emacs_localtime_rz (tz, &value, &tm);
2333 xtzfree (tz);
2334 if (! tmp)
2335 time_overflow ();
2336
2337 static char const wday_name[][4] =
2338 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
2339 static char const mon_name[][4] =
2340 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2341 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
2342 printmax_t year_base = TM_YEAR_BASE;
2343 char buf[sizeof "Mon Apr 30 12:49:17 " + INT_STRLEN_BOUND (int) + 1];
2344 int len = sprintf (buf, "%s %s%3d %02d:%02d:%02d %"pMd,
2345 wday_name[tm.tm_wday], mon_name[tm.tm_mon], tm.tm_mday,
2346 tm.tm_hour, tm.tm_min, tm.tm_sec,
2347 tm.tm_year + year_base);
2348
2349 return make_unibyte_string (buf, len);
2350}
2351
2352/* Yield A - B, measured in seconds.
2353 This function is copied from the GNU C Library. */
2354static int
2355tm_diff (struct tm *a, struct tm *b)
2356{
2357 /* Compute intervening leap days correctly even if year is negative.
2358 Take care to avoid int overflow in leap day calculations,
2359 but it's OK to assume that A and B are close to each other. */
2360 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
2361 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
2362 int a100 = a4 / 25 - (a4 % 25 < 0);
2363 int b100 = b4 / 25 - (b4 % 25 < 0);
2364 int a400 = a100 >> 2;
2365 int b400 = b100 >> 2;
2366 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
2367 int years = a->tm_year - b->tm_year;
2368 int days = (365 * years + intervening_leap_days
2369 + (a->tm_yday - b->tm_yday));
2370 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
2371 + (a->tm_min - b->tm_min))
2372 + (a->tm_sec - b->tm_sec));
2373}
2374
2375/* Yield A's UTC offset, or an unspecified value if unknown. */
2376static long int
2377tm_gmtoff (struct tm *a)
2378{
2379#if HAVE_TM_GMTOFF
2380 return a->tm_gmtoff;
2381#else
2382 return 0;
2383#endif
2384}
2385
2386DEFUN ("current-time-zone", Fcurrent_time_zone, Scurrent_time_zone, 0, 2, 0,
2387 doc: /* Return the offset and name for the local time zone.
2388This returns a list of the form (OFFSET NAME).
2389OFFSET is an integer number of seconds ahead of UTC (east of Greenwich).
2390 A negative value means west of Greenwich.
2391NAME is a string giving the name of the time zone.
2392If SPECIFIED-TIME is given, the time zone offset is determined from it
2393instead of using the current time. The argument should have the form
2394\(HIGH LOW . IGNORED). Thus, you can use times obtained from
2395`current-time' and from `file-attributes'. SPECIFIED-TIME can also be
2396a single integer number of seconds since the epoch. The obsolete form
2397(HIGH . LOW) is also still accepted.
2398
2399The optional ZONE is omitted or nil for Emacs local time, t for
2400Universal Time, `wall' for system wall clock time, or a string as in
2401the TZ environment variable. It can also be a list (as from
2402`current-time-zone') or an integer (as from `decode-time') applied
2403without consideration for daylight saving time.
2404
2405Some operating systems cannot provide all this information to Emacs;
2406in this case, `current-time-zone' returns a list containing nil for
2407the data it can't find. */)
2408 (Lisp_Object specified_time, Lisp_Object zone)
2409{
2410 struct timespec value;
2411 struct tm local_tm, gmt_tm;
2412 Lisp_Object zone_offset, zone_name;
2413
2414 zone_offset = Qnil;
2415 value = make_timespec (lisp_seconds_argument (specified_time), 0);
2416 zone_name = format_time_string ("%Z", sizeof "%Z" - 1, value,
2417 zone, &local_tm);
2418
2419 /* gmtime_r expects a pointer to time_t, but tv_sec of struct
2420 timespec on some systems (MinGW) is a 64-bit field. */
2421 time_t tsec = value.tv_sec;
2422 if (HAVE_TM_GMTOFF || gmtime_r (&tsec, &gmt_tm))
2423 {
2424 long int offset = (HAVE_TM_GMTOFF
2425 ? tm_gmtoff (&local_tm)
2426 : tm_diff (&local_tm, &gmt_tm));
2427 zone_offset = make_fixnum (offset);
2428 if (SCHARS (zone_name) == 0)
2429 {
2430 /* No local time zone name is available; use numeric zone instead. */
2431 long int hour = offset / 3600;
2432 int min_sec = offset % 3600;
2433 int amin_sec = min_sec < 0 ? - min_sec : min_sec;
2434 int min = amin_sec / 60;
2435 int sec = amin_sec % 60;
2436 int min_prec = min_sec ? 2 : 0;
2437 int sec_prec = sec ? 2 : 0;
2438 char buf[sizeof "+0000" + INT_STRLEN_BOUND (long int)];
2439 zone_name = make_formatted_string (buf, "%c%.2ld%.*d%.*d",
2440 (offset < 0 ? '-' : '+'),
2441 hour, min_prec, min, sec_prec, sec);
2442 }
2443 }
2444
2445 return list2 (zone_offset, zone_name);
2446}
2447
2448DEFUN ("set-time-zone-rule", Fset_time_zone_rule, Sset_time_zone_rule, 1, 1, 0,
2449 doc: /* Set the Emacs local time zone using TZ, a string specifying a time zone rule.
2450If TZ is nil or `wall', use system wall clock time; this differs from
2451the usual Emacs convention where nil means current local time. If TZ
2452is t, use Universal Time. If TZ is a list (as from
2453`current-time-zone') or an integer (as from `decode-time'), use the
2454specified time zone without consideration for daylight saving time.
2455
2456Instead of calling this function, you typically want something else.
2457To temporarily use a different time zone rule for just one invocation
2458of `decode-time', `encode-time', or `format-time-string', pass the
2459function a ZONE argument. To change local time consistently
2460throughout Emacs, call (setenv "TZ" TZ): this changes both the
2461environment of the Emacs process and the variable
2462`process-environment', whereas `set-time-zone-rule' affects only the
2463former. */)
2464 (Lisp_Object tz)
2465{
2466 tzlookup (NILP (tz) ? Qwall : tz, true);
2467 return Qnil;
2468}
2469
2470/* A buffer holding a string of the form "TZ=value", intended
2471 to be part of the environment. If TZ is supposed to be unset,
2472 the buffer string is "tZ=". */
2473 static char *tzvalbuf;
2474
2475/* Get the local time zone rule. */
2476char *
2477emacs_getenv_TZ (void)
2478{
2479 return tzvalbuf[0] == 'T' ? tzvalbuf + tzeqlen : 0;
2480}
2481
2482/* Set the local time zone rule to TZSTRING, which can be null to
2483 denote wall clock time. Do not record the setting in LOCAL_TZ.
2484
2485 This function is not thread-safe, in theory because putenv is not,
2486 but mostly because of the static storage it updates. Other threads
2487 that invoke localtime etc. may be adversely affected while this
2488 function is executing. */
2489
2490int
2491emacs_setenv_TZ (const char *tzstring)
2492{
2493 static ptrdiff_t tzvalbufsize;
2494 ptrdiff_t tzstringlen = tzstring ? strlen (tzstring) : 0;
2495 char *tzval = tzvalbuf;
2496 bool new_tzvalbuf = tzvalbufsize <= tzeqlen + tzstringlen;
2497
2498 if (new_tzvalbuf)
2499 {
2500 /* Do not attempt to free the old tzvalbuf, since another thread
2501 may be using it. In practice, the first allocation is large
2502 enough and memory does not leak. */
2503 tzval = xpalloc (NULL, &tzvalbufsize,
2504 tzeqlen + tzstringlen - tzvalbufsize + 1, -1, 1);
2505 tzvalbuf = tzval;
2506 tzval[1] = 'Z';
2507 tzval[2] = '=';
2508 }
2509
2510 if (tzstring)
2511 {
2512 /* Modify TZVAL in place. Although this is dicey in a
2513 multithreaded environment, we know of no portable alternative.
2514 Calling putenv or setenv could crash some other thread. */
2515 tzval[0] = 'T';
2516 strcpy (tzval + tzeqlen, tzstring);
2517 }
2518 else
2519 {
2520 /* Turn 'TZ=whatever' into an empty environment variable 'tZ='.
2521 Although this is also dicey, calling unsetenv here can crash Emacs.
2522 See Bug#8705. */
2523 tzval[0] = 't';
2524 tzval[tzeqlen] = 0;
2525 }
2526
2527
2528#ifndef WINDOWSNT
2529 /* Modifying *TZVAL merely requires calling tzset (which is the
2530 caller's responsibility). However, modifying TZVAL requires
2531 calling putenv; although this is not thread-safe, in practice this
2532 runs only on startup when there is only one thread. */
2533 bool need_putenv = new_tzvalbuf;
2534#else
2535 /* MS-Windows 'putenv' copies the argument string into a block it
2536 allocates, so modifying *TZVAL will not change the environment.
2537 However, the other threads run by Emacs on MS-Windows never call
2538 'xputenv' or 'putenv' or 'unsetenv', so the original cause for the
2539 dicey in-place modification technique doesn't exist there in the
2540 first place. */
2541 bool need_putenv = true;
2542#endif
2543 if (need_putenv)
2544 xputenv (tzval);
2545
2546 return 0;
2547}
2548
2549/* Insert NARGS Lisp objects in the array ARGS by calling INSERT_FUNC 1279/* Insert NARGS Lisp objects in the array ARGS by calling INSERT_FUNC
2550 (if a type of object is Lisp_Int) or INSERT_FROM_STRING_FUNC (if a 1280 (if a type of object is Lisp_Int) or INSERT_FROM_STRING_FUNC (if a
2551 type of object is Lisp_String). INHERIT is passed to 1281 type of object is Lisp_String). INHERIT is passed to
@@ -5764,19 +4494,6 @@ it to be non-nil. */);
5764 defsubr (&Sgroup_real_gid); 4494 defsubr (&Sgroup_real_gid);
5765 defsubr (&Suser_full_name); 4495 defsubr (&Suser_full_name);
5766 defsubr (&Semacs_pid); 4496 defsubr (&Semacs_pid);
5767 defsubr (&Scurrent_time);
5768 defsubr (&Stime_add);
5769 defsubr (&Stime_subtract);
5770 defsubr (&Stime_equal_p);
5771 defsubr (&Stime_less_p);
5772 defsubr (&Sget_internal_run_time);
5773 defsubr (&Sformat_time_string);
5774 defsubr (&Sfloat_time);
5775 defsubr (&Sdecode_time);
5776 defsubr (&Sencode_time);
5777 defsubr (&Scurrent_time_string);
5778 defsubr (&Scurrent_time_zone);
5779 defsubr (&Sset_time_zone_rule);
5780 defsubr (&Ssystem_name); 4497 defsubr (&Ssystem_name);
5781 defsubr (&Smessage); 4498 defsubr (&Smessage);
5782 defsubr (&Smessage_box); 4499 defsubr (&Smessage_box);