aboutsummaryrefslogtreecommitdiffstats
path: root/src/timefns.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/timefns.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/timefns.c')
-rw-r--r--src/timefns.c1287
1 files changed, 1287 insertions, 0 deletions
diff --git a/src/timefns.c b/src/timefns.c
new file mode 100644
index 00000000000..fcb4485ae30
--- /dev/null
+++ b/src/timefns.c
@@ -0,0 +1,1287 @@
1/* Timestamp functions for Emacs
2
3Copyright (C) 1985-1987, 1989, 1993-2018 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20#include <config.h>
21
22#include "systime.h"
23
24#include "blockinput.h"
25#include "coding.h"
26#include "lisp.h"
27
28#include <strftime.h>
29
30#include <errno.h>
31#include <math.h>
32#include <stdio.h>
33#include <stdlib.h>
34
35#ifdef HAVE_TIMEZONE_T
36# include <sys/param.h>
37# if defined __NetBSD_Version__ && __NetBSD_Version__ < 700000000
38# define HAVE_TZALLOC_BUG true
39# endif
40#endif
41#ifndef HAVE_TZALLOC_BUG
42# define HAVE_TZALLOC_BUG false
43#endif
44
45#define TM_YEAR_BASE 1900
46
47#ifndef HAVE_TM_GMTOFF
48# define HAVE_TM_GMTOFF false
49#endif
50
51#ifndef TIME_T_MIN
52# define TIME_T_MIN TYPE_MINIMUM (time_t)
53#endif
54#ifndef TIME_T_MAX
55# define TIME_T_MAX TYPE_MAXIMUM (time_t)
56#endif
57
58/* Return a struct timeval that is roughly equivalent to T.
59 Use the least timeval not less than T.
60 Return an extremal value if the result would overflow. */
61struct timeval
62make_timeval (struct timespec t)
63{
64 struct timeval tv;
65 tv.tv_sec = t.tv_sec;
66 tv.tv_usec = t.tv_nsec / 1000;
67
68 if (t.tv_nsec % 1000 != 0)
69 {
70 if (tv.tv_usec < 999999)
71 tv.tv_usec++;
72 else if (tv.tv_sec < TYPE_MAXIMUM (time_t))
73 {
74 tv.tv_sec++;
75 tv.tv_usec = 0;
76 }
77 }
78
79 return tv;
80}
81
82/* Yield A's UTC offset, or an unspecified value if unknown. */
83static long int
84tm_gmtoff (struct tm *a)
85{
86#if HAVE_TM_GMTOFF
87 return a->tm_gmtoff;
88#else
89 return 0;
90#endif
91}
92
93/* Yield A - B, measured in seconds.
94 This function is copied from the GNU C Library. */
95static int
96tm_diff (struct tm *a, struct tm *b)
97{
98 /* Compute intervening leap days correctly even if year is negative.
99 Take care to avoid int overflow in leap day calculations,
100 but it's OK to assume that A and B are close to each other. */
101 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
102 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
103 int a100 = a4 / 25 - (a4 % 25 < 0);
104 int b100 = b4 / 25 - (b4 % 25 < 0);
105 int a400 = a100 >> 2;
106 int b400 = b100 >> 2;
107 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
108 int years = a->tm_year - b->tm_year;
109 int days = (365 * years + intervening_leap_days
110 + (a->tm_yday - b->tm_yday));
111 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
112 + (a->tm_min - b->tm_min))
113 + (a->tm_sec - b->tm_sec));
114}
115
116enum { tzeqlen = sizeof "TZ=" - 1 };
117
118/* Time zones equivalent to current local time and to UTC, respectively. */
119static timezone_t local_tz;
120static timezone_t const utc_tz = 0;
121
122static struct tm *
123emacs_localtime_rz (timezone_t tz, time_t const *t, struct tm *tm)
124{
125 tm = localtime_rz (tz, t, tm);
126 if (!tm && errno == ENOMEM)
127 memory_full (SIZE_MAX);
128 return tm;
129}
130
131static time_t
132emacs_mktime_z (timezone_t tz, struct tm *tm)
133{
134 errno = 0;
135 time_t t = mktime_z (tz, tm);
136 if (t == (time_t) -1 && errno == ENOMEM)
137 memory_full (SIZE_MAX);
138 return t;
139}
140
141static _Noreturn void
142invalid_time_zone_specification (Lisp_Object zone)
143{
144 xsignal2 (Qerror, build_string ("Invalid time zone specification"), zone);
145}
146
147/* Free a timezone, except do not free the time zone for local time.
148 Freeing utc_tz is also a no-op. */
149static void
150xtzfree (timezone_t tz)
151{
152 if (tz != local_tz)
153 tzfree (tz);
154}
155
156/* Convert the Lisp time zone rule ZONE to a timezone_t object.
157 The returned value either is 0, or is LOCAL_TZ, or is newly allocated.
158 If SETTZ, set Emacs local time to the time zone rule; otherwise,
159 the caller should eventually pass the returned value to xtzfree. */
160static timezone_t
161tzlookup (Lisp_Object zone, bool settz)
162{
163 static char const tzbuf_format[] = "<%+.*"pI"d>%s%"pI"d:%02d:%02d";
164 char const *trailing_tzbuf_format = tzbuf_format + sizeof "<%+.*"pI"d" - 1;
165 char tzbuf[sizeof tzbuf_format + 2 * INT_STRLEN_BOUND (EMACS_INT)];
166 char const *zone_string;
167 timezone_t new_tz;
168
169 if (NILP (zone))
170 return local_tz;
171 else if (EQ (zone, Qt) || EQ (zone, make_fixnum (0)))
172 {
173 zone_string = "UTC0";
174 new_tz = utc_tz;
175 }
176 else
177 {
178 bool plain_integer = FIXNUMP (zone);
179
180 if (EQ (zone, Qwall))
181 zone_string = 0;
182 else if (STRINGP (zone))
183 zone_string = SSDATA (ENCODE_SYSTEM (zone));
184 else if (plain_integer || (CONSP (zone) && FIXNUMP (XCAR (zone))
185 && CONSP (XCDR (zone))))
186 {
187 Lisp_Object abbr UNINIT;
188 if (!plain_integer)
189 {
190 abbr = XCAR (XCDR (zone));
191 zone = XCAR (zone);
192 }
193
194 EMACS_INT abszone = eabs (XFIXNUM (zone)), hour = abszone / (60 * 60);
195 int hour_remainder = abszone % (60 * 60);
196 int min = hour_remainder / 60, sec = hour_remainder % 60;
197
198 if (plain_integer)
199 {
200 int prec = 2;
201 EMACS_INT numzone = hour;
202 if (hour_remainder != 0)
203 {
204 prec += 2, numzone = 100 * numzone + min;
205 if (sec != 0)
206 prec += 2, numzone = 100 * numzone + sec;
207 }
208 sprintf (tzbuf, tzbuf_format, prec,
209 XFIXNUM (zone) < 0 ? -numzone : numzone,
210 &"-"[XFIXNUM (zone) < 0], hour, min, sec);
211 zone_string = tzbuf;
212 }
213 else
214 {
215 AUTO_STRING (leading, "<");
216 AUTO_STRING_WITH_LEN (trailing, tzbuf,
217 sprintf (tzbuf, trailing_tzbuf_format,
218 &"-"[XFIXNUM (zone) < 0],
219 hour, min, sec));
220 zone_string = SSDATA (concat3 (leading, ENCODE_SYSTEM (abbr),
221 trailing));
222 }
223 }
224 else
225 invalid_time_zone_specification (zone);
226
227 new_tz = tzalloc (zone_string);
228
229 if (HAVE_TZALLOC_BUG && !new_tz && errno != ENOMEM && plain_integer
230 && XFIXNUM (zone) % (60 * 60) == 0)
231 {
232 /* tzalloc mishandles POSIX strings; fall back on tzdb if
233 possible (Bug#30738). */
234 sprintf (tzbuf, "Etc/GMT%+"pI"d", - (XFIXNUM (zone) / (60 * 60)));
235 new_tz = tzalloc (zone_string);
236 }
237
238 if (!new_tz)
239 {
240 if (errno == ENOMEM)
241 memory_full (SIZE_MAX);
242 invalid_time_zone_specification (zone);
243 }
244 }
245
246 if (settz)
247 {
248 block_input ();
249 emacs_setenv_TZ (zone_string);
250 tzset ();
251 timezone_t old_tz = local_tz;
252 local_tz = new_tz;
253 tzfree (old_tz);
254 unblock_input ();
255 }
256
257 return new_tz;
258}
259
260void
261init_timefns (bool dumping)
262{
263#ifndef CANNOT_DUMP
264 /* A valid but unlikely setting for the TZ environment variable.
265 It is OK (though a bit slower) if the user chooses this value. */
266 static char dump_tz_string[] = "TZ=UtC0";
267
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
299/* Report that a time value is out of range for Emacs. */
300void
301time_overflow (void)
302{
303 error ("Specified time is not representable");
304}
305
306static _Noreturn void
307invalid_time (void)
308{
309 error ("Invalid time specification");
310}
311
312/* Check a return value compatible with that of decode_time_components. */
313static void
314check_time_validity (int validity)
315{
316 if (validity <= 0)
317 {
318 if (validity < 0)
319 time_overflow ();
320 else
321 invalid_time ();
322 }
323}
324
325/* Return the upper part of the time T (everything but the bottom 16 bits). */
326static EMACS_INT
327hi_time (time_t t)
328{
329 time_t hi = t >> LO_TIME_BITS;
330 if (FIXNUM_OVERFLOW_P (hi))
331 time_overflow ();
332 return hi;
333}
334
335/* Return the bottom bits of the time T. */
336static int
337lo_time (time_t t)
338{
339 return t & ((1 << LO_TIME_BITS) - 1);
340}
341
342/* Decode a Lisp list SPECIFIED_TIME that represents a time.
343 Set *PHIGH, *PLOW, *PUSEC, *PPSEC to its parts; do not check their values.
344 Return 2, 3, or 4 to indicate the effective length of SPECIFIED_TIME
345 if successful, 0 if unsuccessful. */
346static int
347disassemble_lisp_time (Lisp_Object specified_time, Lisp_Object *phigh,
348 Lisp_Object *plow, Lisp_Object *pusec,
349 Lisp_Object *ppsec)
350{
351 Lisp_Object high = make_fixnum (0);
352 Lisp_Object low = specified_time;
353 Lisp_Object usec = make_fixnum (0);
354 Lisp_Object psec = make_fixnum (0);
355 int len = 4;
356
357 if (CONSP (specified_time))
358 {
359 high = XCAR (specified_time);
360 low = XCDR (specified_time);
361 if (CONSP (low))
362 {
363 Lisp_Object low_tail = XCDR (low);
364 low = XCAR (low);
365 if (CONSP (low_tail))
366 {
367 usec = XCAR (low_tail);
368 low_tail = XCDR (low_tail);
369 if (CONSP (low_tail))
370 psec = XCAR (low_tail);
371 else
372 len = 3;
373 }
374 else if (!NILP (low_tail))
375 {
376 usec = low_tail;
377 len = 3;
378 }
379 else
380 len = 2;
381 }
382 else
383 len = 2;
384
385 /* When combining components, require LOW to be an integer,
386 as otherwise it would be a pain to add up times. */
387 if (! INTEGERP (low))
388 return 0;
389 }
390 else if (INTEGERP (specified_time))
391 len = 2;
392
393 *phigh = high;
394 *plow = low;
395 *pusec = usec;
396 *ppsec = psec;
397 return len;
398}
399
400/* Convert T into an Emacs time *RESULT, truncating toward minus infinity.
401 Return true if T is in range, false otherwise. */
402static bool
403decode_float_time (double t, struct lisp_time *result)
404{
405 double lo_multiplier = 1 << LO_TIME_BITS;
406 double emacs_time_min = MOST_NEGATIVE_FIXNUM * lo_multiplier;
407 if (! (emacs_time_min <= t && t < -emacs_time_min))
408 return false;
409
410 double small_t = t / lo_multiplier;
411 EMACS_INT hi = small_t;
412 double t_sans_hi = t - hi * lo_multiplier;
413 int lo = t_sans_hi;
414 long double fracps = (t_sans_hi - lo) * 1e12L;
415#ifdef INT_FAST64_MAX
416 int_fast64_t ifracps = fracps;
417 int us = ifracps / 1000000;
418 int ps = ifracps % 1000000;
419#else
420 int us = fracps / 1e6L;
421 int ps = fracps - us * 1e6L;
422#endif
423 us -= (ps < 0);
424 ps += (ps < 0) * 1000000;
425 lo -= (us < 0);
426 us += (us < 0) * 1000000;
427 hi -= (lo < 0);
428 lo += (lo < 0) << LO_TIME_BITS;
429 result->hi = hi;
430 result->lo = lo;
431 result->us = us;
432 result->ps = ps;
433 return true;
434}
435
436/* From the time components HIGH, LOW, USEC and PSEC taken from a Lisp
437 list, generate the corresponding time value.
438 If LOW is floating point, the other components should be zero.
439
440 If RESULT is not null, store into *RESULT the converted time.
441 If *DRESULT is not null, store into *DRESULT the number of
442 seconds since the start of the POSIX Epoch.
443
444 Return 1 if successful, 0 if the components are of the
445 wrong type, and -1 if the time is out of range. */
446int
447decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec,
448 Lisp_Object psec,
449 struct lisp_time *result, double *dresult)
450{
451 EMACS_INT hi, us, ps;
452 intmax_t lo;
453 if (! (FIXNUMP (high)
454 && FIXNUMP (usec) && FIXNUMP (psec)))
455 return 0;
456 if (! INTEGERP (low))
457 {
458 if (FLOATP (low))
459 {
460 double t = XFLOAT_DATA (low);
461 if (result && ! decode_float_time (t, result))
462 return -1;
463 if (dresult)
464 *dresult = t;
465 return 1;
466 }
467 else if (NILP (low))
468 {
469 struct timespec now = current_timespec ();
470 if (result)
471 {
472 result->hi = hi_time (now.tv_sec);
473 result->lo = lo_time (now.tv_sec);
474 result->us = now.tv_nsec / 1000;
475 result->ps = now.tv_nsec % 1000 * 1000;
476 }
477 if (dresult)
478 *dresult = now.tv_sec + now.tv_nsec / 1e9;
479 return 1;
480 }
481 else
482 return 0;
483 }
484
485 hi = XFIXNUM (high);
486 if (! integer_to_intmax (low, &lo))
487 return -1;
488 us = XFIXNUM (usec);
489 ps = XFIXNUM (psec);
490
491 /* Normalize out-of-range lower-order components by carrying
492 each overflow into the next higher-order component. */
493 us += ps / 1000000 - (ps % 1000000 < 0);
494 lo += us / 1000000 - (us % 1000000 < 0);
495 if (INT_ADD_WRAPV (lo >> LO_TIME_BITS, hi, &hi))
496 return -1;
497 ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0);
498 us = us % 1000000 + 1000000 * (us % 1000000 < 0);
499 lo &= (1 << LO_TIME_BITS) - 1;
500
501 if (result)
502 {
503 if (FIXNUM_OVERFLOW_P (hi))
504 return -1;
505 result->hi = hi;
506 result->lo = lo;
507 result->us = us;
508 result->ps = ps;
509 }
510
511 if (dresult)
512 {
513 double dhi = hi;
514 *dresult = (us * 1e6 + ps) / 1e12 + lo + dhi * (1 << LO_TIME_BITS);
515 }
516
517 return 1;
518}
519
520struct timespec
521lisp_to_timespec (struct lisp_time t)
522{
523 if (! ((TYPE_SIGNED (time_t) ? TIME_T_MIN >> LO_TIME_BITS <= t.hi : 0 <= t.hi)
524 && t.hi <= TIME_T_MAX >> LO_TIME_BITS))
525 return invalid_timespec ();
526 time_t s = (t.hi << LO_TIME_BITS) + t.lo;
527 int ns = t.us * 1000 + t.ps / 1000;
528 return make_timespec (s, ns);
529}
530
531/* Decode a Lisp list SPECIFIED_TIME that represents a time.
532 Store its effective length into *PLEN.
533 If SPECIFIED_TIME is nil, use the current time.
534 Signal an error if SPECIFIED_TIME does not represent a time. */
535static struct lisp_time
536lisp_time_struct (Lisp_Object specified_time, int *plen)
537{
538 Lisp_Object high, low, usec, psec;
539 struct lisp_time t;
540 int len = disassemble_lisp_time (specified_time, &high, &low, &usec, &psec);
541 if (!len)
542 invalid_time ();
543 int val = decode_time_components (high, low, usec, psec, &t, 0);
544 check_time_validity (val);
545 *plen = len;
546 return t;
547}
548
549/* Like lisp_time_struct, except return a struct timespec.
550 Discard any low-order digits. */
551struct timespec
552lisp_time_argument (Lisp_Object specified_time)
553{
554 int len;
555 struct lisp_time lt = lisp_time_struct (specified_time, &len);
556 struct timespec t = lisp_to_timespec (lt);
557 if (! timespec_valid_p (t))
558 time_overflow ();
559 return t;
560}
561
562/* Like lisp_time_argument, except decode only the seconds part,
563 and do not check the subseconds part. */
564static time_t
565lisp_seconds_argument (Lisp_Object specified_time)
566{
567 Lisp_Object high, low, usec, psec;
568 struct lisp_time t;
569
570 int val = disassemble_lisp_time (specified_time, &high, &low, &usec, &psec);
571 if (val != 0)
572 {
573 val = decode_time_components (high, low, make_fixnum (0),
574 make_fixnum (0), &t, 0);
575 if (0 < val
576 && ! ((TYPE_SIGNED (time_t)
577 ? TIME_T_MIN >> LO_TIME_BITS <= t.hi
578 : 0 <= t.hi)
579 && t.hi <= TIME_T_MAX >> LO_TIME_BITS))
580 val = -1;
581 }
582 check_time_validity (val);
583 return (t.hi << LO_TIME_BITS) + t.lo;
584}
585
586static struct lisp_time
587time_add (struct lisp_time ta, struct lisp_time tb)
588{
589 EMACS_INT hi = ta.hi + tb.hi;
590 int lo = ta.lo + tb.lo;
591 int us = ta.us + tb.us;
592 int ps = ta.ps + tb.ps;
593 us += (1000000 <= ps);
594 ps -= (1000000 <= ps) * 1000000;
595 lo += (1000000 <= us);
596 us -= (1000000 <= us) * 1000000;
597 hi += (1 << LO_TIME_BITS <= lo);
598 lo -= (1 << LO_TIME_BITS <= lo) << LO_TIME_BITS;
599 return (struct lisp_time) { hi, lo, us, ps };
600}
601
602static struct lisp_time
603time_subtract (struct lisp_time ta, struct lisp_time tb)
604{
605 EMACS_INT hi = ta.hi - tb.hi;
606 int lo = ta.lo - tb.lo;
607 int us = ta.us - tb.us;
608 int ps = ta.ps - tb.ps;
609 us -= (ps < 0);
610 ps += (ps < 0) * 1000000;
611 lo -= (us < 0);
612 us += (us < 0) * 1000000;
613 hi -= (lo < 0);
614 lo += (lo < 0) << LO_TIME_BITS;
615 return (struct lisp_time) { hi, lo, us, ps };
616}
617
618static Lisp_Object
619time_arith (Lisp_Object a, Lisp_Object b, bool subtract)
620{
621 if (FLOATP (a) && !isfinite (XFLOAT_DATA (a)))
622 {
623 double da = XFLOAT_DATA (a);
624 double db = XFLOAT_DATA (Ffloat_time (b));
625 return make_float (subtract ? da - db : da + db);
626 }
627 if (FLOATP (b) && !isfinite (XFLOAT_DATA (b)))
628 return subtract ? make_float (-XFLOAT_DATA (b)) : b;
629
630 int alen, blen;
631 struct lisp_time ta = lisp_time_struct (a, &alen);
632 struct lisp_time tb = lisp_time_struct (b, &blen);
633 struct lisp_time t = (subtract ? time_subtract : time_add) (ta, tb);
634 if (FIXNUM_OVERFLOW_P (t.hi))
635 time_overflow ();
636 Lisp_Object val = Qnil;
637
638 switch (max (alen, blen))
639 {
640 default:
641 val = Fcons (make_fixnum (t.ps), val);
642 FALLTHROUGH;
643 case 3:
644 val = Fcons (make_fixnum (t.us), val);
645 FALLTHROUGH;
646 case 2:
647 val = Fcons (make_fixnum (t.lo), val);
648 val = Fcons (make_fixnum (t.hi), val);
649 break;
650 }
651
652 return val;
653}
654
655DEFUN ("time-add", Ftime_add, Stime_add, 2, 2, 0,
656 doc: /* Return the sum of two time values A and B, as a time value.
657A nil value for either argument stands for the current time.
658See `current-time-string' for the various forms of a time value. */)
659 (Lisp_Object a, Lisp_Object b)
660{
661 return time_arith (a, b, false);
662}
663
664DEFUN ("time-subtract", Ftime_subtract, Stime_subtract, 2, 2, 0,
665 doc: /* Return the difference between two time values A and B, as a time value.
666Use `float-time' to convert the difference into elapsed seconds.
667A nil value for either argument stands for the current time.
668See `current-time-string' for the various forms of a time value. */)
669 (Lisp_Object a, Lisp_Object b)
670{
671 return time_arith (a, b, true);
672}
673
674/* Return negative, 0, positive if a < b, a == b, a > b respectively.
675 Return positive if either a or b is a NaN; this is good enough
676 for the current callers. */
677static int
678time_cmp (Lisp_Object a, Lisp_Object b)
679{
680 if ((FLOATP (a) && !isfinite (XFLOAT_DATA (a)))
681 || (FLOATP (b) && !isfinite (XFLOAT_DATA (b))))
682 {
683 double da = FLOATP (a) ? XFLOAT_DATA (a) : 0;
684 double db = FLOATP (b) ? XFLOAT_DATA (b) : 0;
685 return da < db ? -1 : da != db;
686 }
687
688 int alen, blen;
689 struct lisp_time ta = lisp_time_struct (a, &alen);
690 struct lisp_time tb = lisp_time_struct (b, &blen);
691 return (ta.hi != tb.hi ? (ta.hi < tb.hi ? -1 : 1)
692 : ta.lo != tb.lo ? (ta.lo < tb.lo ? -1 : 1)
693 : ta.us != tb.us ? (ta.us < tb.us ? -1 : 1)
694 : ta.ps < tb.ps ? -1 : ta.ps != tb.ps);
695}
696
697DEFUN ("time-less-p", Ftime_less_p, Stime_less_p, 2, 2, 0,
698 doc: /* Return non-nil if time value T1 is earlier than time value T2.
699A nil value for either argument stands for the current time.
700See `current-time-string' for the various forms of a time value. */)
701 (Lisp_Object t1, Lisp_Object t2)
702{
703 return time_cmp (t1, t2) < 0 ? Qt : Qnil;
704}
705
706DEFUN ("time-equal-p", Ftime_equal_p, Stime_equal_p, 2, 2, 0,
707 doc: /* Return non-nil if T1 and T2 are equal time values.
708A nil value for either argument stands for the current time.
709See `current-time-string' for the various forms of a time value. */)
710 (Lisp_Object t1, Lisp_Object t2)
711{
712 return time_cmp (t1, t2) == 0 ? Qt : Qnil;
713}
714
715
716/* Make a Lisp list that represents the Emacs time T. T may be an
717 invalid time, with a slightly negative tv_nsec value such as
718 UNKNOWN_MODTIME_NSECS; in that case, the Lisp list contains a
719 correspondingly negative picosecond count. */
720Lisp_Object
721make_lisp_time (struct timespec t)
722{
723 time_t s = t.tv_sec;
724 int ns = t.tv_nsec;
725 return list4i (hi_time (s), lo_time (s), ns / 1000, ns % 1000 * 1000);
726}
727
728DEFUN ("float-time", Ffloat_time, Sfloat_time, 0, 1, 0,
729 doc: /* Return the current time, as a float number of seconds since the epoch.
730If SPECIFIED-TIME is given, it is the time to convert to float
731instead of the current time. The argument should have the form
732\(HIGH LOW) or (HIGH LOW USEC) or (HIGH LOW USEC PSEC). Thus,
733you can use times from `current-time' and from `file-attributes'.
734SPECIFIED-TIME can also have the form (HIGH . LOW), but this is
735considered obsolete.
736
737WARNING: Since the result is floating point, it may not be exact.
738If precise time stamps are required, use either `current-time',
739or (if you need time as a string) `format-time-string'. */)
740 (Lisp_Object specified_time)
741{
742 double t;
743 Lisp_Object high, low, usec, psec;
744 if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec)
745 && decode_time_components (high, low, usec, psec, 0, &t)))
746 invalid_time ();
747 return make_float (t);
748}
749
750/* Write information into buffer S of size MAXSIZE, according to the
751 FORMAT of length FORMAT_LEN, using time information taken from *TP.
752 Use the time zone specified by TZ.
753 Use NS as the number of nanoseconds in the %N directive.
754 Return the number of bytes written, not including the terminating
755 '\0'. If S is NULL, nothing will be written anywhere; so to
756 determine how many bytes would be written, use NULL for S and
757 ((size_t) -1) for MAXSIZE.
758
759 This function behaves like nstrftime, except it allows null
760 bytes in FORMAT and it does not support nanoseconds. */
761static size_t
762emacs_nmemftime (char *s, size_t maxsize, const char *format,
763 size_t format_len, const struct tm *tp, timezone_t tz, int ns)
764{
765 size_t total = 0;
766
767 /* Loop through all the null-terminated strings in the format
768 argument. Normally there's just one null-terminated string, but
769 there can be arbitrarily many, concatenated together, if the
770 format contains '\0' bytes. nstrftime stops at the first
771 '\0' byte so we must invoke it separately for each such string. */
772 for (;;)
773 {
774 size_t len;
775 size_t result;
776
777 if (s)
778 s[0] = '\1';
779
780 result = nstrftime (s, maxsize, format, tp, tz, ns);
781
782 if (s)
783 {
784 if (result == 0 && s[0] != '\0')
785 return 0;
786 s += result + 1;
787 }
788
789 maxsize -= result + 1;
790 total += result;
791 len = strlen (format);
792 if (len == format_len)
793 return total;
794 total++;
795 format += len + 1;
796 format_len -= len + 1;
797 }
798}
799
800static Lisp_Object
801format_time_string (char const *format, ptrdiff_t formatlen,
802 struct timespec t, Lisp_Object zone, struct tm *tmp)
803{
804 char buffer[4000];
805 char *buf = buffer;
806 ptrdiff_t size = sizeof buffer;
807 size_t len;
808 int ns = t.tv_nsec;
809 USE_SAFE_ALLOCA;
810
811 timezone_t tz = tzlookup (zone, false);
812 /* On some systems, like 32-bit MinGW, tv_sec of struct timespec is
813 a 64-bit type, but time_t is a 32-bit type. emacs_localtime_rz
814 expects a pointer to time_t value. */
815 time_t tsec = t.tv_sec;
816 tmp = emacs_localtime_rz (tz, &tsec, tmp);
817 if (! tmp)
818 {
819 xtzfree (tz);
820 time_overflow ();
821 }
822 synchronize_system_time_locale ();
823
824 while (true)
825 {
826 buf[0] = '\1';
827 len = emacs_nmemftime (buf, size, format, formatlen, tmp, tz, ns);
828 if ((0 < len && len < size) || (len == 0 && buf[0] == '\0'))
829 break;
830
831 /* Buffer was too small, so make it bigger and try again. */
832 len = emacs_nmemftime (NULL, SIZE_MAX, format, formatlen, tmp, tz, ns);
833 if (STRING_BYTES_BOUND <= len)
834 {
835 xtzfree (tz);
836 string_overflow ();
837 }
838 size = len + 1;
839 buf = SAFE_ALLOCA (size);
840 }
841
842 xtzfree (tz);
843 AUTO_STRING_WITH_LEN (bufstring, buf, len);
844 Lisp_Object result = code_convert_string_norecord (bufstring,
845 Vlocale_coding_system, 0);
846 SAFE_FREE ();
847 return result;
848}
849
850DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
851 doc: /* Use FORMAT-STRING to format the time TIME, or now if omitted or nil.
852TIME is specified as (HIGH LOW USEC PSEC), as returned by
853`current-time' or `file-attributes'. It can also be a single integer
854number of seconds since the epoch. The obsolete form (HIGH . LOW) is
855also still accepted.
856
857The optional ZONE is omitted or nil for Emacs local time, t for
858Universal Time, `wall' for system wall clock time, or a string as in
859the TZ environment variable. It can also be a list (as from
860`current-time-zone') or an integer (as from `decode-time') applied
861without consideration for daylight saving time.
862
863The value is a copy of FORMAT-STRING, but with certain constructs replaced
864by text that describes the specified date and time in TIME:
865
866%Y is the year, %y within the century, %C the century.
867%G is the year corresponding to the ISO week, %g within the century.
868%m is the numeric month.
869%b and %h are the locale's abbreviated month name, %B the full name.
870 (%h is not supported on MS-Windows.)
871%d is the day of the month, zero-padded, %e is blank-padded.
872%u is the numeric day of week from 1 (Monday) to 7, %w from 0 (Sunday) to 6.
873%a is the locale's abbreviated name of the day of week, %A the full name.
874%U is the week number starting on Sunday, %W starting on Monday,
875 %V according to ISO 8601.
876%j is the day of the year.
877
878%H is the hour on a 24-hour clock, %I is on a 12-hour clock, %k is like %H
879 only blank-padded, %l is like %I blank-padded.
880%p is the locale's equivalent of either AM or PM.
881%q is the calendar quarter (1–4).
882%M is the minute (00-59).
883%S is the second (00-59; 00-60 on platforms with leap seconds)
884%s is the number of seconds since 1970-01-01 00:00:00 +0000.
885%N is the nanosecond, %6N the microsecond, %3N the millisecond, etc.
886%Z is the time zone abbreviation, %z is the numeric form.
887
888%c is the locale's date and time format.
889%x is the locale's "preferred" date format.
890%D is like "%m/%d/%y".
891%F is the ISO 8601 date format (like "%Y-%m-%d").
892
893%R is like "%H:%M", %T is like "%H:%M:%S", %r is like "%I:%M:%S %p".
894%X is the locale's "preferred" time format.
895
896Finally, %n is a newline, %t is a tab, %% is a literal %, and
897unrecognized %-sequences stand for themselves.
898
899Certain flags and modifiers are available with some format controls.
900The flags are `_', `-', `^' and `#'. For certain characters X,
901%_X is like %X, but padded with blanks; %-X is like %X,
902but without padding. %^X is like %X, but with all textual
903characters up-cased; %#X is like %X, but with letter-case of
904all textual characters reversed.
905%NX (where N stands for an integer) is like %X,
906but takes up at least N (a number) positions.
907The modifiers are `E' and `O'. For certain characters X,
908%EX is a locale's alternative version of %X;
909%OX is like %X, but uses the locale's number symbols.
910
911For example, to produce full ISO 8601 format, use "%FT%T%z".
912
913usage: (format-time-string FORMAT-STRING &optional TIME ZONE) */)
914 (Lisp_Object format_string, Lisp_Object timeval, Lisp_Object zone)
915{
916 struct timespec t = lisp_time_argument (timeval);
917 struct tm tm;
918
919 CHECK_STRING (format_string);
920 format_string = code_convert_string_norecord (format_string,
921 Vlocale_coding_system, 1);
922 return format_time_string (SSDATA (format_string), SBYTES (format_string),
923 t, zone, &tm);
924}
925
926DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 2, 0,
927 doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF).
928The optional TIME should be a list of (HIGH LOW . IGNORED),
929as from `current-time' and `file-attributes', or nil to use the
930current time. It can also be a single integer number of seconds since
931the epoch. The obsolete form (HIGH . LOW) is also still accepted.
932
933The optional ZONE is omitted or nil for Emacs local time, t for
934Universal Time, `wall' for system wall clock time, or a string as in
935the TZ environment variable. It can also be a list (as from
936`current-time-zone') or an integer (the UTC offset in seconds) applied
937without consideration for daylight saving time.
938
939The list has the following nine members: SEC is an integer between 0
940and 60; SEC is 60 for a leap second, which only some operating systems
941support. MINUTE is an integer between 0 and 59. HOUR is an integer
942between 0 and 23. DAY is an integer between 1 and 31. MONTH is an
943integer between 1 and 12. YEAR is an integer indicating the
944four-digit year. DOW is the day of week, an integer between 0 and 6,
945where 0 is Sunday. DST is t if daylight saving time is in effect,
946nil if it is not in effect, and -1 if daylight saving information is
947not available. UTCOFF is an integer indicating the UTC offset in
948seconds, i.e., the number of seconds east of Greenwich. (Note that
949Common Lisp has different meanings for DOW and UTCOFF.)
950
951usage: (decode-time &optional TIME ZONE) */)
952 (Lisp_Object specified_time, Lisp_Object zone)
953{
954 time_t time_spec = lisp_seconds_argument (specified_time);
955 struct tm local_tm, gmt_tm;
956 timezone_t tz = tzlookup (zone, false);
957 struct tm *tm = emacs_localtime_rz (tz, &time_spec, &local_tm);
958 xtzfree (tz);
959
960 if (! (tm
961 && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= local_tm.tm_year
962 && local_tm.tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE))
963 time_overflow ();
964
965 /* Avoid overflow when INT_MAX < EMACS_INT_MAX. */
966 EMACS_INT tm_year_base = TM_YEAR_BASE;
967
968 return CALLN (Flist,
969 make_fixnum (local_tm.tm_sec),
970 make_fixnum (local_tm.tm_min),
971 make_fixnum (local_tm.tm_hour),
972 make_fixnum (local_tm.tm_mday),
973 make_fixnum (local_tm.tm_mon + 1),
974 make_fixnum (local_tm.tm_year + tm_year_base),
975 make_fixnum (local_tm.tm_wday),
976 (local_tm.tm_isdst < 0 ? make_fixnum (-1)
977 : local_tm.tm_isdst == 0 ? Qnil : Qt),
978 (HAVE_TM_GMTOFF
979 ? make_fixnum (tm_gmtoff (&local_tm))
980 : gmtime_r (&time_spec, &gmt_tm)
981 ? make_fixnum (tm_diff (&local_tm, &gmt_tm))
982 : Qnil));
983}
984
985/* Return OBJ - OFFSET, checking that OBJ is a valid fixnum and that
986 the result is representable as an int. */
987static int
988check_tm_member (Lisp_Object obj, int offset)
989{
990 CHECK_FIXNUM (obj);
991 EMACS_INT n = XFIXNUM (obj);
992 int result;
993 if (INT_SUBTRACT_WRAPV (n, offset, &result))
994 time_overflow ();
995 return result;
996}
997
998DEFUN ("encode-time", Fencode_time, Sencode_time, 6, MANY, 0,
999 doc: /* Convert SECOND, MINUTE, HOUR, DAY, MONTH, YEAR and ZONE to internal time.
1000This is the reverse operation of `decode-time', which see.
1001
1002The optional ZONE is omitted or nil for Emacs local time, t for
1003Universal Time, `wall' for system wall clock time, or a string as in
1004the TZ environment variable. It can also be a list (as from
1005`current-time-zone') or an integer (as from `decode-time') applied
1006without consideration for daylight saving time.
1007
1008You can pass more than 7 arguments; then the first six arguments
1009are used as SECOND through YEAR, and the *last* argument is used as ZONE.
1010The intervening arguments are ignored.
1011This feature lets (apply \\='encode-time (decode-time ...)) work.
1012
1013Out-of-range values for SECOND, MINUTE, HOUR, DAY, or MONTH are allowed;
1014for example, a DAY of 0 means the day preceding the given month.
1015Year numbers less than 100 are treated just like other year numbers.
1016If you want them to stand for years in this century, you must do that yourself.
1017
1018Years before 1970 are not guaranteed to work. On some systems,
1019year values as low as 1901 do work.
1020
1021usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */)
1022 (ptrdiff_t nargs, Lisp_Object *args)
1023{
1024 time_t value;
1025 struct tm tm;
1026 Lisp_Object zone = (nargs > 6 ? args[nargs - 1] : Qnil);
1027
1028 tm.tm_sec = check_tm_member (args[0], 0);
1029 tm.tm_min = check_tm_member (args[1], 0);
1030 tm.tm_hour = check_tm_member (args[2], 0);
1031 tm.tm_mday = check_tm_member (args[3], 0);
1032 tm.tm_mon = check_tm_member (args[4], 1);
1033 tm.tm_year = check_tm_member (args[5], TM_YEAR_BASE);
1034 tm.tm_isdst = -1;
1035
1036 timezone_t tz = tzlookup (zone, false);
1037 value = emacs_mktime_z (tz, &tm);
1038 xtzfree (tz);
1039
1040 if (value == (time_t) -1)
1041 time_overflow ();
1042
1043 return list2i (hi_time (value), lo_time (value));
1044}
1045
1046DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0,
1047 doc: /* Return the current time, as the number of seconds since 1970-01-01 00:00:00.
1048The time is returned as a list of integers (HIGH LOW USEC PSEC).
1049HIGH has the most significant bits of the seconds, while LOW has the
1050least significant 16 bits. USEC and PSEC are the microsecond and
1051picosecond counts. */)
1052 (void)
1053{
1054 return make_lisp_time (current_timespec ());
1055}
1056
1057DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string,
1058 0, 2, 0,
1059 doc: /* Return the current local time, as a human-readable string.
1060Programs can use this function to decode a time,
1061since the number of columns in each field is fixed
1062if the year is in the range 1000-9999.
1063The format is `Sun Sep 16 01:03:52 1973'.
1064However, see also the functions `decode-time' and `format-time-string'
1065which provide a much more powerful and general facility.
1066
1067If SPECIFIED-TIME is given, it is a time to format instead of the
1068current time. The argument should have the form (HIGH LOW . IGNORED).
1069Thus, you can use times obtained from `current-time' and from
1070`file-attributes'. SPECIFIED-TIME can also be a single integer number
1071of seconds since the epoch. The obsolete form (HIGH . LOW) is also
1072still accepted.
1073
1074The optional ZONE is omitted or nil for Emacs local time, t for
1075Universal Time, `wall' for system wall clock time, or a string as in
1076the TZ environment variable. It can also be a list (as from
1077`current-time-zone') or an integer (as from `decode-time') applied
1078without consideration for daylight saving time. */)
1079 (Lisp_Object specified_time, Lisp_Object zone)
1080{
1081 time_t value = lisp_seconds_argument (specified_time);
1082 timezone_t tz = tzlookup (zone, false);
1083
1084 /* Convert to a string in ctime format, except without the trailing
1085 newline, and without the 4-digit year limit. Don't use asctime
1086 or ctime, as they might dump core if the year is outside the
1087 range -999 .. 9999. */
1088 struct tm tm;
1089 struct tm *tmp = emacs_localtime_rz (tz, &value, &tm);
1090 xtzfree (tz);
1091 if (! tmp)
1092 time_overflow ();
1093
1094 static char const wday_name[][4] =
1095 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
1096 static char const mon_name[][4] =
1097 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1098 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1099 printmax_t year_base = TM_YEAR_BASE;
1100 char buf[sizeof "Mon Apr 30 12:49:17 " + INT_STRLEN_BOUND (int) + 1];
1101 int len = sprintf (buf, "%s %s%3d %02d:%02d:%02d %"pMd,
1102 wday_name[tm.tm_wday], mon_name[tm.tm_mon], tm.tm_mday,
1103 tm.tm_hour, tm.tm_min, tm.tm_sec,
1104 tm.tm_year + year_base);
1105
1106 return make_unibyte_string (buf, len);
1107}
1108
1109DEFUN ("current-time-zone", Fcurrent_time_zone, Scurrent_time_zone, 0, 2, 0,
1110 doc: /* Return the offset and name for the local time zone.
1111This returns a list of the form (OFFSET NAME).
1112OFFSET is an integer number of seconds ahead of UTC (east of Greenwich).
1113 A negative value means west of Greenwich.
1114NAME is a string giving the name of the time zone.
1115If SPECIFIED-TIME is given, the time zone offset is determined from it
1116instead of using the current time. The argument should have the form
1117\(HIGH LOW . IGNORED). Thus, you can use times obtained from
1118`current-time' and from `file-attributes'. SPECIFIED-TIME can also be
1119a single integer number of seconds since the epoch. The obsolete form
1120(HIGH . LOW) is also still accepted.
1121
1122The optional ZONE is omitted or nil for Emacs local time, t for
1123Universal Time, `wall' for system wall clock time, or a string as in
1124the TZ environment variable. It can also be a list (as from
1125`current-time-zone') or an integer (as from `decode-time') applied
1126without consideration for daylight saving time.
1127
1128Some operating systems cannot provide all this information to Emacs;
1129in this case, `current-time-zone' returns a list containing nil for
1130the data it can't find. */)
1131 (Lisp_Object specified_time, Lisp_Object zone)
1132{
1133 struct timespec value;
1134 struct tm local_tm, gmt_tm;
1135 Lisp_Object zone_offset, zone_name;
1136
1137 zone_offset = Qnil;
1138 value = make_timespec (lisp_seconds_argument (specified_time), 0);
1139 zone_name = format_time_string ("%Z", sizeof "%Z" - 1, value,
1140 zone, &local_tm);
1141
1142 /* gmtime_r expects a pointer to time_t, but tv_sec of struct
1143 timespec on some systems (MinGW) is a 64-bit field. */
1144 time_t tsec = value.tv_sec;
1145 if (HAVE_TM_GMTOFF || gmtime_r (&tsec, &gmt_tm))
1146 {
1147 long int offset = (HAVE_TM_GMTOFF
1148 ? tm_gmtoff (&local_tm)
1149 : tm_diff (&local_tm, &gmt_tm));
1150 zone_offset = make_fixnum (offset);
1151 if (SCHARS (zone_name) == 0)
1152 {
1153 /* No local time zone name is available; use numeric zone instead. */
1154 long int hour = offset / 3600;
1155 int min_sec = offset % 3600;
1156 int amin_sec = min_sec < 0 ? - min_sec : min_sec;
1157 int min = amin_sec / 60;
1158 int sec = amin_sec % 60;
1159 int min_prec = min_sec ? 2 : 0;
1160 int sec_prec = sec ? 2 : 0;
1161 char buf[sizeof "+0000" + INT_STRLEN_BOUND (long int)];
1162 zone_name = make_formatted_string (buf, "%c%.2ld%.*d%.*d",
1163 (offset < 0 ? '-' : '+'),
1164 hour, min_prec, min, sec_prec, sec);
1165 }
1166 }
1167
1168 return list2 (zone_offset, zone_name);
1169}
1170
1171DEFUN ("set-time-zone-rule", Fset_time_zone_rule, Sset_time_zone_rule, 1, 1, 0,
1172 doc: /* Set the Emacs local time zone using TZ, a string specifying a time zone rule.
1173If TZ is nil or `wall', use system wall clock time; this differs from
1174the usual Emacs convention where nil means current local time. If TZ
1175is t, use Universal Time. If TZ is a list (as from
1176`current-time-zone') or an integer (as from `decode-time'), use the
1177specified time zone without consideration for daylight saving time.
1178
1179Instead of calling this function, you typically want something else.
1180To temporarily use a different time zone rule for just one invocation
1181of `decode-time', `encode-time', or `format-time-string', pass the
1182function a ZONE argument. To change local time consistently
1183throughout Emacs, call (setenv "TZ" TZ): this changes both the
1184environment of the Emacs process and the variable
1185`process-environment', whereas `set-time-zone-rule' affects only the
1186former. */)
1187 (Lisp_Object tz)
1188{
1189 tzlookup (NILP (tz) ? Qwall : tz, true);
1190 return Qnil;
1191}
1192
1193/* A buffer holding a string of the form "TZ=value", intended
1194 to be part of the environment. If TZ is supposed to be unset,
1195 the buffer string is "tZ=". */
1196 static char *tzvalbuf;
1197
1198/* Get the local time zone rule. */
1199char *
1200emacs_getenv_TZ (void)
1201{
1202 return tzvalbuf[0] == 'T' ? tzvalbuf + tzeqlen : 0;
1203}
1204
1205/* Set the local time zone rule to TZSTRING, which can be null to
1206 denote wall clock time. Do not record the setting in LOCAL_TZ.
1207
1208 This function is not thread-safe, in theory because putenv is not,
1209 but mostly because of the static storage it updates. Other threads
1210 that invoke localtime etc. may be adversely affected while this
1211 function is executing. */
1212
1213int
1214emacs_setenv_TZ (const char *tzstring)
1215{
1216 static ptrdiff_t tzvalbufsize;
1217 ptrdiff_t tzstringlen = tzstring ? strlen (tzstring) : 0;
1218 char *tzval = tzvalbuf;
1219 bool new_tzvalbuf = tzvalbufsize <= tzeqlen + tzstringlen;
1220
1221 if (new_tzvalbuf)
1222 {
1223 /* Do not attempt to free the old tzvalbuf, since another thread
1224 may be using it. In practice, the first allocation is large
1225 enough and memory does not leak. */
1226 tzval = xpalloc (NULL, &tzvalbufsize,
1227 tzeqlen + tzstringlen - tzvalbufsize + 1, -1, 1);
1228 tzvalbuf = tzval;
1229 tzval[1] = 'Z';
1230 tzval[2] = '=';
1231 }
1232
1233 if (tzstring)
1234 {
1235 /* Modify TZVAL in place. Although this is dicey in a
1236 multithreaded environment, we know of no portable alternative.
1237 Calling putenv or setenv could crash some other thread. */
1238 tzval[0] = 'T';
1239 strcpy (tzval + tzeqlen, tzstring);
1240 }
1241 else
1242 {
1243 /* Turn 'TZ=whatever' into an empty environment variable 'tZ='.
1244 Although this is also dicey, calling unsetenv here can crash Emacs.
1245 See Bug#8705. */
1246 tzval[0] = 't';
1247 tzval[tzeqlen] = 0;
1248 }
1249
1250
1251#ifndef WINDOWSNT
1252 /* Modifying *TZVAL merely requires calling tzset (which is the
1253 caller's responsibility). However, modifying TZVAL requires
1254 calling putenv; although this is not thread-safe, in practice this
1255 runs only on startup when there is only one thread. */
1256 bool need_putenv = new_tzvalbuf;
1257#else
1258 /* MS-Windows 'putenv' copies the argument string into a block it
1259 allocates, so modifying *TZVAL will not change the environment.
1260 However, the other threads run by Emacs on MS-Windows never call
1261 'xputenv' or 'putenv' or 'unsetenv', so the original cause for the
1262 dicey in-place modification technique doesn't exist there in the
1263 first place. */
1264 bool need_putenv = true;
1265#endif
1266 if (need_putenv)
1267 xputenv (tzval);
1268
1269 return 0;
1270}
1271
1272void
1273syms_of_timefns (void)
1274{
1275 defsubr (&Scurrent_time);
1276 defsubr (&Stime_add);
1277 defsubr (&Stime_subtract);
1278 defsubr (&Stime_less_p);
1279 defsubr (&Stime_equal_p);
1280 defsubr (&Sformat_time_string);
1281 defsubr (&Sfloat_time);
1282 defsubr (&Sdecode_time);
1283 defsubr (&Sencode_time);
1284 defsubr (&Scurrent_time_string);
1285 defsubr (&Scurrent_time_zone);
1286 defsubr (&Sset_time_zone_rule);
1287}