Make `build-aux/gendocs.sh' executable.
[bpt/guile.git] / libguile / stime.c
CommitLineData
3baf6e8b 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2013 Free Software Foundation, Inc.
1c299a6b 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
1c299a6b 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
1c299a6b 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
0f2d19dd
JB
20\f
21
464ee095
KR
22/* _POSIX_C_SOURCE is not defined always, because it causes problems on some
23 systems, notably
24
25 - FreeBSD loses all BSD and XOPEN defines.
26 - glibc loses some things like CLK_TCK.
27 - On MINGW it conflicts with the pthread headers.
28
29 But on HP-UX _POSIX_C_SOURCE is needed, as noted, for gmtime_r.
30
31 Perhaps a configure test could figure out what _POSIX_C_SOURCE gives and
32 what it takes away, and decide from that whether to use it, instead of
33 hard coding __hpux. */
34
2baec6a9
LC
35#ifndef _REENTRANT
36# define _REENTRANT /* ask solaris for gmtime_r prototype */
37#endif
464ee095 38#ifdef __hpux
95f31774 39#define _POSIX_C_SOURCE 199506L /* for gmtime_r prototype */
edea856c 40#endif
3c61e80f 41
dbb605f5 42#ifdef HAVE_CONFIG_H
3cf2f52d
RB
43# include <config.h>
44#endif
45
0f2d19dd 46#include <stdio.h>
e6e2e95a 47#include <errno.h>
69f23174 48#include <strftime.h>
587a3355 49#include <unistr.h>
e6e2e95a 50
a0599745 51#include "libguile/_scm.h"
4e047c3e 52#include "libguile/async.h"
a0599745
MD
53#include "libguile/feature.h"
54#include "libguile/strings.h"
55#include "libguile/vectors.h"
cc95e00a 56#include "libguile/dynwind.h"
587a3355 57#include "libguile/strings.h"
20e6290e 58
a0599745
MD
59#include "libguile/validate.h"
60#include "libguile/stime.h"
20e6290e 61
0f2d19dd
JB
62#ifdef HAVE_UNISTD_H
63#include <unistd.h>
64#endif
65
66\f
4a42658f
AW
67#ifdef HAVE_CLOCK_GETTIME
68# include <time.h>
69#endif
70
71#ifdef HAVE_SYS_TYPES_H
72# include <sys/types.h>
73#endif
0f2d19dd 74
a15e6dcc
MV
75#ifdef HAVE_STRING_H
76#include <string.h>
77#endif
78
b1978258
GH
79#ifdef HAVE_SYS_TIMES_H
80# include <sys/times.h>
81#endif
82
83#ifdef HAVE_SYS_TIMEB_H
84# include <sys/timeb.h>
85#endif
0f2d19dd 86
3c61e80f 87#if ! HAVE_DECL_STRPTIME
4d3bacdd
JB
88extern char *strptime ();
89#endif
90
0f2d19dd
JB
91#ifdef __STDC__
92# define timet time_t
93#else
94# define timet long
95#endif
96
eb7e1603 97
4a42658f
AW
98#if SCM_SIZEOF_LONG >= 8 && defined HAVE_CLOCK_GETTIME
99/* Nanoseconds on 64-bit systems with POSIX timers. */
100#define TIME_UNITS_PER_SECOND 1000000000
101#else
102/* Milliseconds for everyone else. */
103#define TIME_UNITS_PER_SECOND 1000
104#endif
105
106long scm_c_time_units_per_second = TIME_UNITS_PER_SECOND;
107
108static long
109time_from_seconds_and_nanoseconds (long s, long ns)
110{
111 return s * TIME_UNITS_PER_SECOND
112 + ns / (1000000000 / TIME_UNITS_PER_SECOND);
113}
114
115
116/* A runtime-selectable mechanism to choose a timing mechanism. Really
117 we want to use POSIX timers, but that's not always possible. Notably,
118 the user may have everything she needs at compile-time, but if she's
119 running on an SMP machine without a common clock source, she can't
120 use POSIX CPUTIME clocks. */
121static long (*get_internal_real_time) (void);
122static long (*get_internal_run_time) (void);
123
124
125#ifdef HAVE_CLOCK_GETTIME
126struct timespec posix_real_time_base;
127
128static long
129get_internal_real_time_posix_timer (void)
130{
131 struct timespec ts;
132 clock_gettime (CLOCK_REALTIME, &ts);
133 return time_from_seconds_and_nanoseconds
134 (ts.tv_sec - posix_real_time_base.tv_sec,
135 ts.tv_nsec - posix_real_time_base.tv_nsec);
136}
137
a02a6067
AW
138#if defined _POSIX_CPUTIME && defined CLOCK_PROCESS_CPUTIME_ID
139/* You see, FreeBSD defines _POSIX_CPUTIME but not
140 CLOCK_PROCESS_CPUTIME_ID. */
141#define HAVE_POSIX_CPUTIME 1
142
4a42658f
AW
143struct timespec posix_run_time_base;
144
145static long
146get_internal_run_time_posix_timer (void)
147{
148 struct timespec ts;
149 clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &ts);
150 return time_from_seconds_and_nanoseconds
151 (ts.tv_sec - posix_run_time_base.tv_sec,
152 ts.tv_nsec - posix_run_time_base.tv_nsec);
153}
154#endif /* _POSIX_CPUTIME */
155#endif /* HAVE_CLOCKTIME */
156
157
158#ifdef HAVE_GETTIMEOFDAY
159struct timeval gettimeofday_real_time_base;
160
161static long
162get_internal_real_time_gettimeofday (void)
163{
164 struct timeval tv;
165 gettimeofday (&tv, NULL);
166 return time_from_seconds_and_nanoseconds
167 (tv.tv_sec - gettimeofday_real_time_base.tv_sec,
168 (tv.tv_usec - gettimeofday_real_time_base.tv_usec) * 1000);
169}
170#endif
171
172
4a42658f
AW
173static long ticks_per_second;
174
175static long
176get_internal_run_time_times (void)
0f2d19dd
JB
177{
178 struct tms time_buffer;
179 times(&time_buffer);
4a42658f
AW
180 return (time_buffer.tms_utime + time_buffer.tms_stime)
181 * TIME_UNITS_PER_SECOND / ticks_per_second;
0f2d19dd 182}
4a42658f 183
40e2a31d
AW
184static timet fallback_real_time_base;
185static long
186get_internal_real_time_fallback (void)
187{
188 return time_from_seconds_and_nanoseconds
189 ((long) time (NULL) - fallback_real_time_base, 0);
190}
191
1bbd0b84 192
1c299a6b 193SCM_DEFINE (scm_get_internal_real_time, "get-internal-real-time", 0, 0, 0,
1bbd0b84 194 (),
1e6808ea
MG
195 "Return the number of time units since the interpreter was\n"
196 "started.")
1bbd0b84 197#define FUNC_NAME s_scm_get_internal_real_time
0f2d19dd 198{
4a42658f 199 return scm_from_long (get_internal_real_time ());
0f2d19dd 200}
1bbd0b84
GB
201#undef FUNC_NAME
202
0f2d19dd 203
1c299a6b 204SCM_DEFINE (scm_times, "times", 0, 0, 0,
1bbd0b84 205 (void),
1e6808ea
MG
206 "Return an object with information about real and processor\n"
207 "time. The following procedures accept such an object as an\n"
208 "argument and return a selected component:\n"
209 "\n"
b380b885
MD
210 "@table @code\n"
211 "@item tms:clock\n"
212 "The current real time, expressed as time units relative to an\n"
213 "arbitrary base.\n"
214 "@item tms:utime\n"
215 "The CPU time units used by the calling process.\n"
216 "@item tms:stime\n"
1e6808ea
MG
217 "The CPU time units used by the system on behalf of the calling\n"
218 "process.\n"
b380b885 219 "@item tms:cutime\n"
1e6808ea
MG
220 "The CPU time units used by terminated child processes of the\n"
221 "calling process, whose status has been collected (e.g., using\n"
222 "@code{waitpid}).\n"
b380b885 223 "@item tms:cstime\n"
1e6808ea 224 "Similarly, the CPU times units used by the system on behalf of\n"
b380b885
MD
225 "terminated child processes.\n"
226 "@end table")
1bbd0b84 227#define FUNC_NAME s_scm_times
6afcd3b2 228{
6afcd3b2
GH
229 struct tms t;
230 clock_t rv;
4a42658f 231 SCM factor;
6afcd3b2 232
00ffa0e7 233 SCM result = scm_c_make_vector (5, SCM_UNDEFINED);
6afcd3b2
GH
234 rv = times (&t);
235 if (rv == -1)
1bbd0b84 236 SCM_SYSERROR;
4a42658f
AW
237
238 factor = scm_quotient (scm_from_long (TIME_UNITS_PER_SECOND),
239 scm_from_long (ticks_per_second));
240
241 SCM_SIMPLE_VECTOR_SET (result, 0,
242 scm_product (scm_from_long (rv), factor));
243 SCM_SIMPLE_VECTOR_SET (result, 1,
244 scm_product (scm_from_long (t.tms_utime), factor));
245 SCM_SIMPLE_VECTOR_SET (result, 2,
246 scm_product (scm_from_long (t.tms_stime), factor));
247 SCM_SIMPLE_VECTOR_SET (result ,3,
248 scm_product (scm_from_long (t.tms_cutime), factor));
249 SCM_SIMPLE_VECTOR_SET (result, 4,
250 scm_product (scm_from_long (t.tms_cstime), factor));
6afcd3b2 251 return result;
6afcd3b2 252}
1bbd0b84 253#undef FUNC_NAME
6afcd3b2 254
1c299a6b 255long
4a42658f 256scm_c_get_internal_run_time (void)
1c299a6b 257{
4a42658f 258 return get_internal_run_time ();
1c299a6b
ML
259}
260
261SCM_DEFINE (scm_get_internal_run_time, "get-internal-run-time", 0, 0, 0,
1bbd0b84 262 (void),
1e6808ea
MG
263 "Return the number of time units of processor time used by the\n"
264 "interpreter. Both @emph{system} and @emph{user} time are\n"
265 "included but subprocesses are not.")
1bbd0b84 266#define FUNC_NAME s_scm_get_internal_run_time
0f2d19dd 267{
b9bd8526 268 return scm_from_long (scm_c_get_internal_run_time ());
0f2d19dd 269}
1bbd0b84 270#undef FUNC_NAME
0f2d19dd 271
f40771d8
KR
272/* For reference, note that current-time and gettimeofday both should be
273 protected against setzone/restorezone changes in another thread, since on
274 DOS the system time is normally kept as local time, which means TZ
275 affects the return from current-time and gettimeofday. Not sure if DJGPP
276 etc actually has concurrent multi-threading, but it seems prudent not to
277 make assumptions about this. */
278
1c299a6b 279SCM_DEFINE (scm_current_time, "current-time", 0, 0, 0,
1bbd0b84 280 (void),
1e6808ea
MG
281 "Return the number of seconds since 1970-01-01 00:00:00 UTC,\n"
282 "excluding leap seconds.")
1bbd0b84 283#define FUNC_NAME s_scm_current_time
0f2d19dd 284{
19468eff
GH
285 timet timv;
286
9de87eea 287 SCM_CRITICAL_SECTION_START;
763313a2 288 timv = time (NULL);
9de87eea 289 SCM_CRITICAL_SECTION_END;
763313a2
KR
290 if (timv == -1)
291 SCM_MISC_ERROR ("current time not available", SCM_EOL);
b9bd8526 292 return scm_from_long (timv);
19468eff 293}
1bbd0b84 294#undef FUNC_NAME
19468eff 295
1c299a6b 296SCM_DEFINE (scm_gettimeofday, "gettimeofday", 0, 0, 0,
1bbd0b84 297 (void),
1e6808ea
MG
298 "Return a pair containing the number of seconds and microseconds\n"
299 "since 1970-01-01 00:00:00 UTC, excluding leap seconds. Note:\n"
300 "whether true microsecond resolution is available depends on the\n"
301 "operating system.")
1bbd0b84 302#define FUNC_NAME s_scm_gettimeofday
19468eff
GH
303{
304#ifdef HAVE_GETTIMEOFDAY
305 struct timeval time;
306
4a42658f
AW
307 if (gettimeofday (&time, NULL))
308 SCM_SYSERROR;
309
b9bd8526
MV
310 return scm_cons (scm_from_long (time.tv_sec),
311 scm_from_long (time.tv_usec));
19468eff 312#else
4a42658f
AW
313 timet t = time (NULL);
314 if (errno)
315 SCM_SYSERROR;
316 else
317 return scm_cons (scm_from_long ((long)t), SCM_INUM0);
19468eff
GH
318#endif
319}
1bbd0b84 320#undef FUNC_NAME
19468eff
GH
321
322static SCM
d6d9e957 323filltime (struct tm *bd_time, int zoff, const char *zname)
19468eff 324{
00ffa0e7 325 SCM result = scm_c_make_vector (11, SCM_UNDEFINED);
19468eff 326
4057a3e0
MV
327 SCM_SIMPLE_VECTOR_SET (result,0, scm_from_int (bd_time->tm_sec));
328 SCM_SIMPLE_VECTOR_SET (result,1, scm_from_int (bd_time->tm_min));
329 SCM_SIMPLE_VECTOR_SET (result,2, scm_from_int (bd_time->tm_hour));
330 SCM_SIMPLE_VECTOR_SET (result,3, scm_from_int (bd_time->tm_mday));
331 SCM_SIMPLE_VECTOR_SET (result,4, scm_from_int (bd_time->tm_mon));
332 SCM_SIMPLE_VECTOR_SET (result,5, scm_from_int (bd_time->tm_year));
333 SCM_SIMPLE_VECTOR_SET (result,6, scm_from_int (bd_time->tm_wday));
334 SCM_SIMPLE_VECTOR_SET (result,7, scm_from_int (bd_time->tm_yday));
335 SCM_SIMPLE_VECTOR_SET (result,8, scm_from_int (bd_time->tm_isdst));
336 SCM_SIMPLE_VECTOR_SET (result,9, scm_from_int (zoff));
337 SCM_SIMPLE_VECTOR_SET (result,10, (zname
338 ? scm_from_locale_string (zname)
339 : SCM_BOOL_F));
19468eff
GH
340 return result;
341}
342
ef9ff3fd 343static char tzvar[3] = "TZ";
ef9ff3fd 344
38c1d3c4
GH
345/* if zone is set, create a temporary environment with only a TZ
346 string. other threads or interrupt handlers shouldn't be allowed
347 to run until the corresponding restorezone is called. hence the use
348 of a static variable for tmpenv is no big deal. */
ef9ff3fd 349static char **
3eeba8d4 350setzone (SCM zone, int pos, const char *subr)
b9525b92 351{
ef9ff3fd 352 char **oldenv = 0;
b9525b92
GH
353
354 if (!SCM_UNBNDP (zone))
355 {
ef9ff3fd 356 static char *tmpenv[2];
b9525b92 357 char *buf;
7f9994d9
MV
358 size_t zone_len;
359
360 zone_len = scm_to_locale_stringbuf (zone, NULL, 0);
361 buf = scm_malloc (zone_len + sizeof (tzvar) + 1);
362 strcpy (buf, tzvar);
363 buf[sizeof(tzvar)-1] = '=';
364 scm_to_locale_stringbuf (zone, buf+sizeof(tzvar), zone_len);
365 buf[sizeof(tzvar)+zone_len] = '\0';
ef9ff3fd
GH
366 oldenv = environ;
367 tmpenv[0] = buf;
368 tmpenv[1] = 0;
369 environ = tmpenv;
b9525b92 370 }
ef9ff3fd 371 return oldenv;
b9525b92
GH
372}
373
374static void
e81d98ec 375restorezone (SCM zone, char **oldenv, const char *subr SCM_UNUSED)
b9525b92
GH
376{
377 if (!SCM_UNBNDP (zone))
378 {
4c9419ac 379 free (environ[0]);
ef9ff3fd 380 environ = oldenv;
38c1d3c4
GH
381#ifdef HAVE_TZSET
382 /* for the possible benefit of user code linked with libguile. */
b9525b92 383 tzset();
38c1d3c4 384#endif
b9525b92
GH
385 }
386}
387
1c299a6b 388SCM_DEFINE (scm_localtime, "localtime", 1, 1, 0,
1bbd0b84 389 (SCM time, SCM zone),
1e6808ea
MG
390 "Return an object representing the broken down components of\n"
391 "@var{time}, an integer like the one returned by\n"
392 "@code{current-time}. The time zone for the calculation is\n"
393 "optionally specified by @var{zone} (a string), otherwise the\n"
394 "@code{TZ} environment variable or the system default is used.")
1bbd0b84 395#define FUNC_NAME s_scm_localtime
19468eff
GH
396{
397 timet itime;
4edc089c 398 struct tm *ltptr, lt, *utc;
19468eff
GH
399 SCM result;
400 int zoff;
401 char *zname = 0;
ef9ff3fd 402 char **oldenv;
19468eff
GH
403 int err;
404
e4b265d8 405 itime = SCM_NUM2LONG (1, time);
38c1d3c4
GH
406
407 /* deferring interupts is essential since a) setzone may install a temporary
408 environment b) localtime uses a static buffer. */
9de87eea 409 SCM_CRITICAL_SECTION_START;
1bbd0b84 410 oldenv = setzone (zone, SCM_ARG2, FUNC_NAME);
38c1d3c4
GH
411#ifdef LOCALTIME_CACHE
412 tzset ();
413#endif
73ae3b4c
KR
414 /* POSIX says localtime sets errno, but C99 doesn't say that.
415 Give a sensible default value in case localtime doesn't set it. */
416 errno = EINVAL;
4edc089c 417 ltptr = localtime (&itime);
19468eff 418 err = errno;
4edc089c 419 if (ltptr)
19468eff 420 {
4d3bacdd 421 const char *ptr;
ef9ff3fd 422
43ff3170
GH
423 /* copy zone name before calling gmtime or restoring zone. */
424#if defined (HAVE_TM_ZONE)
ef9ff3fd 425 ptr = ltptr->tm_zone;
43ff3170 426#elif defined (HAVE_TZNAME)
ef9ff3fd 427 ptr = tzname[ (ltptr->tm_isdst == 1) ? 1 : 0 ];
43ff3170
GH
428#else
429 ptr = "";
b9525b92 430#endif
4c9419ac 431 zname = scm_malloc (strlen (ptr) + 1);
ef9ff3fd 432 strcpy (zname, ptr);
19468eff 433 }
ef9ff3fd
GH
434 /* the struct is copied in case localtime and gmtime share a buffer. */
435 if (ltptr)
436 lt = *ltptr;
73ae3b4c
KR
437 /* POSIX says gmtime sets errno, but C99 doesn't say that.
438 Give a sensible default value in case gmtime doesn't set it. */
439 errno = EINVAL;
ef9ff3fd
GH
440 utc = gmtime (&itime);
441 if (utc == NULL)
442 err = errno;
1bbd0b84 443 restorezone (zone, oldenv, FUNC_NAME);
b9525b92 444 /* delayed until zone has been restored. */
19468eff 445 errno = err;
4edc089c 446 if (utc == NULL || ltptr == NULL)
1bbd0b84 447 SCM_SYSERROR;
19468eff
GH
448
449 /* calculate timezone offset in seconds west of UTC. */
4edc089c
GH
450 zoff = (utc->tm_hour - lt.tm_hour) * 3600 + (utc->tm_min - lt.tm_min) * 60
451 + utc->tm_sec - lt.tm_sec;
452 if (utc->tm_year < lt.tm_year)
19468eff 453 zoff -= 24 * 60 * 60;
4edc089c 454 else if (utc->tm_year > lt.tm_year)
19468eff 455 zoff += 24 * 60 * 60;
4edc089c 456 else if (utc->tm_yday < lt.tm_yday)
19468eff 457 zoff -= 24 * 60 * 60;
4edc089c 458 else if (utc->tm_yday > lt.tm_yday)
19468eff 459 zoff += 24 * 60 * 60;
1c299a6b 460
4edc089c 461 result = filltime (&lt, zoff, zname);
9de87eea 462 SCM_CRITICAL_SECTION_END;
c291b588
LC
463
464 free (zname);
19468eff
GH
465 return result;
466}
1bbd0b84 467#undef FUNC_NAME
19468eff 468
45198ffb
KR
469/* tm_zone is normally a pointer, not an array within struct tm, so we might
470 have to worry about the lifespan of what it points to. The posix specs
471 don't seem to say anything about this, let's assume here that tm_zone
472 will be a constant and therefore no protection or anything is needed
473 until we copy it in filltime(). */
474
1c299a6b 475SCM_DEFINE (scm_gmtime, "gmtime", 1, 0, 0,
1bbd0b84 476 (SCM time),
1e6808ea
MG
477 "Return an object representing the broken down components of\n"
478 "@var{time}, an integer like the one returned by\n"
479 "@code{current-time}. The values are calculated for UTC.")
1bbd0b84 480#define FUNC_NAME s_scm_gmtime
19468eff
GH
481{
482 timet itime;
45198ffb 483 struct tm bd_buf, *bd_time;
d6d9e957 484 const char *zname;
19468eff 485
e4b265d8 486 itime = SCM_NUM2LONG (1, time);
45198ffb 487
73ae3b4c
KR
488 /* POSIX says gmtime sets errno, but C99 doesn't say that.
489 Give a sensible default value in case gmtime doesn't set it. */
490 errno = EINVAL;
45198ffb
KR
491
492#if HAVE_GMTIME_R
493 bd_time = gmtime_r (&itime, &bd_buf);
494#else
9de87eea 495 SCM_CRITICAL_SECTION_START;
19468eff 496 bd_time = gmtime (&itime);
45198ffb
KR
497 if (bd_time != NULL)
498 bd_buf = *bd_time;
9de87eea 499 SCM_CRITICAL_SECTION_END;
45198ffb 500#endif
19468eff 501 if (bd_time == NULL)
1bbd0b84 502 SCM_SYSERROR;
45198ffb 503
d6d9e957 504#if HAVE_STRUCT_TM_TM_ZONE
45198ffb 505 zname = bd_buf.tm_zone;
d6d9e957
KR
506#else
507 zname = "GMT";
508#endif
45198ffb 509 return filltime (&bd_buf, 0, zname);
19468eff 510}
1bbd0b84 511#undef FUNC_NAME
19468eff 512
b9525b92
GH
513/* copy time components from a Scheme object to a struct tm. */
514static void
3eeba8d4 515bdtime2c (SCM sbd_time, struct tm *lt, int pos, const char *subr)
19468eff 516{
4057a3e0
MV
517 SCM_ASSERT (scm_is_simple_vector (sbd_time)
518 && SCM_SIMPLE_VECTOR_LENGTH (sbd_time) == 11,
55a7fc62
GH
519 sbd_time, pos, subr);
520
4057a3e0
MV
521 lt->tm_sec = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 0));
522 lt->tm_min = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 1));
523 lt->tm_hour = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 2));
524 lt->tm_mday = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 3));
525 lt->tm_mon = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 4));
526 lt->tm_year = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 5));
527 lt->tm_wday = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 6));
528 lt->tm_yday = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 7));
529 lt->tm_isdst = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 8));
8ab3d8a0
KR
530#if HAVE_STRUCT_TM_TM_GMTOFF
531 lt->tm_gmtoff = - scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 9));
532#endif
c7abe4f3 533#ifdef HAVE_TM_ZONE
4057a3e0 534 if (scm_is_false (SCM_SIMPLE_VECTOR_REF (sbd_time, 10)))
55a7fc62
GH
535 lt->tm_zone = NULL;
536 else
4057a3e0 537 lt->tm_zone = scm_to_locale_string (SCM_SIMPLE_VECTOR_REF (sbd_time, 10));
c7abe4f3 538#endif
b9525b92
GH
539}
540
1c299a6b 541SCM_DEFINE (scm_mktime, "mktime", 1, 1, 0,
1bbd0b84 542 (SCM sbd_time, SCM zone),
b7e64f8b
BT
543 "@var{sbd_time} is an object representing broken down time and\n"
544 "@code{zone} is an optional time zone specifier (otherwise the\n"
545 "TZ environment variable or the system default is used).\n"
546 "\n"
547 "Returns a pair: the car is a corresponding integer time value\n"
548 "like that returned by @code{current-time}; the cdr is a broken\n"
549 "down time object, similar to as @var{sbd_time} but with\n"
550 "normalized values.")
1bbd0b84 551#define FUNC_NAME s_scm_mktime
b9525b92
GH
552{
553 timet itime;
554 struct tm lt, *utc;
555 SCM result;
556 int zoff;
557 char *zname = 0;
ef9ff3fd 558 char **oldenv;
b9525b92
GH
559 int err;
560
661ae7ab 561 scm_dynwind_begin (0);
cc95e00a 562
1bbd0b84 563 bdtime2c (sbd_time, &lt, SCM_ARG1, FUNC_NAME);
edea856c 564#if HAVE_STRUCT_TM_TM_ZONE
661ae7ab 565 scm_dynwind_free ((char *)lt.tm_zone);
edea856c 566#endif
19468eff 567
661ae7ab 568 scm_dynwind_critical_section (SCM_BOOL_F);
9291479f 569
1bbd0b84 570 oldenv = setzone (zone, SCM_ARG2, FUNC_NAME);
38c1d3c4
GH
571#ifdef LOCALTIME_CACHE
572 tzset ();
573#endif
19468eff 574 itime = mktime (&lt);
73ae3b4c
KR
575 /* POSIX doesn't say mktime sets errno, and on glibc 2.3.2 for instance it
576 doesn't. Force a sensible value for our error message. */
577 err = EINVAL;
19468eff 578
b9525b92
GH
579 if (itime != -1)
580 {
4d3bacdd 581 const char *ptr;
ef9ff3fd 582
43ff3170
GH
583 /* copy zone name before calling gmtime or restoring the zone. */
584#if defined (HAVE_TM_ZONE)
ef9ff3fd 585 ptr = lt.tm_zone;
43ff3170 586#elif defined (HAVE_TZNAME)
ef9ff3fd 587 ptr = tzname[ (lt.tm_isdst == 1) ? 1 : 0 ];
43ff3170
GH
588#else
589 ptr = "";
b9525b92 590#endif
4c9419ac 591 zname = scm_malloc (strlen (ptr) + 1);
ef9ff3fd 592 strcpy (zname, ptr);
b9525b92 593 }
ef9ff3fd
GH
594
595 /* get timezone offset in seconds west of UTC. */
73ae3b4c
KR
596 /* POSIX says gmtime sets errno, but C99 doesn't say that.
597 Give a sensible default value in case gmtime doesn't set it. */
fa0198bf 598 errno = EINVAL;
ef9ff3fd
GH
599 utc = gmtime (&itime);
600 if (utc == NULL)
601 err = errno;
602
1bbd0b84 603 restorezone (zone, oldenv, FUNC_NAME);
b9525b92
GH
604 /* delayed until zone has been restored. */
605 errno = err;
606 if (utc == NULL || itime == -1)
1bbd0b84 607 SCM_SYSERROR;
b9525b92 608
19468eff
GH
609 zoff = (utc->tm_hour - lt.tm_hour) * 3600 + (utc->tm_min - lt.tm_min) * 60
610 + utc->tm_sec - lt.tm_sec;
611 if (utc->tm_year < lt.tm_year)
612 zoff -= 24 * 60 * 60;
613 else if (utc->tm_year > lt.tm_year)
614 zoff += 24 * 60 * 60;
615 else if (utc->tm_yday < lt.tm_yday)
616 zoff -= 24 * 60 * 60;
617 else if (utc->tm_yday > lt.tm_yday)
618 zoff += 24 * 60 * 60;
619
b9bd8526 620 result = scm_cons (scm_from_long (itime),
19468eff 621 filltime (&lt, zoff, zname));
c291b588 622 free (zname);
cc95e00a 623
661ae7ab 624 scm_dynwind_end ();
19468eff 625 return result;
0f2d19dd 626}
1bbd0b84 627#undef FUNC_NAME
0f2d19dd 628
38c1d3c4 629#ifdef HAVE_TZSET
1c299a6b 630SCM_DEFINE (scm_tzset, "tzset", 0, 0, 0,
1bbd0b84 631 (void),
a3c8b9fc
MD
632 "Initialize the timezone from the TZ environment variable\n"
633 "or the system default. It's not usually necessary to call this procedure\n"
634 "since it's done automatically by other procedures that depend on the\n"
635 "timezone.")
1bbd0b84 636#define FUNC_NAME s_scm_tzset
0f2d19dd 637{
19468eff
GH
638 tzset();
639 return SCM_UNSPECIFIED;
0f2d19dd 640}
1bbd0b84 641#undef FUNC_NAME
38c1d3c4 642#endif /* HAVE_TZSET */
0f2d19dd 643
a1ec6916 644SCM_DEFINE (scm_strftime, "strftime", 2, 0, 0,
1bbd0b84 645 (SCM format, SCM stime),
5cd87f55
KR
646 "Return a string which is broken-down time structure @var{stime}\n"
647 "formatted according to the given @var{format} string.\n"
648 "\n"
649 "@var{format} contains field specifications introduced by a\n"
650 "@samp{%} character. See @ref{Formatting Calendar Time,,, libc,\n"
651 "The GNU C Library Reference Manual}, or @samp{man 3 strftime},\n"
652 "for the available formatting.\n"
653 "\n"
654 "@lisp\n"
655 "(strftime \"%c\" (localtime (current-time)))\n"
656 "@result{} \"Mon Mar 11 20:17:43 2002\"\n"
657 "@end lisp\n"
658 "\n"
659 "If @code{setlocale} has been called (@pxref{Locales}), month\n"
660 "and day names are from the current locale and in the locale\n"
661 "character set.")
1bbd0b84 662#define FUNC_NAME s_scm_strftime
b9525b92
GH
663{
664 struct tm t;
665
d40e1ca8 666 char *tbuf;
b9525b92 667 int size = 50;
d40e1ca8
AW
668 char *fmt;
669 char *myfmt;
670 size_t len;
ef9ff3fd 671 SCM result;
b9525b92 672
a6d9e5ab 673 SCM_VALIDATE_STRING (1, format);
1bbd0b84 674 bdtime2c (stime, &t, SCM_ARG2, FUNC_NAME);
b9525b92 675
587a3355
MG
676 /* Convert string to UTF-8 so that non-ASCII characters in the
677 format are passed through unchanged. */
d40e1ca8 678 fmt = scm_to_utf8_stringn (format, &len);
b9525b92 679
a15e6dcc
MV
680 /* Ugly hack: strftime can return 0 if its buffer is too small,
681 but some valid time strings (e.g. "%p") can sometimes produce
682 a zero-byte output string! Workaround is to prepend a junk
683 character to the format string, so that valid returns are always
684 nonzero. */
4c9419ac 685 myfmt = scm_malloc (len+2);
587a3355 686 *myfmt = (scm_t_uint8) 'x';
d40e1ca8 687 strncpy (myfmt + 1, fmt, len);
587a3355
MG
688 myfmt[len + 1] = 0;
689 scm_remember_upto_here_1 (format);
690 free (fmt);
a15e6dcc 691
4c9419ac 692 tbuf = scm_malloc (size);
b8a1b29b
GH
693 {
694#if !defined (HAVE_TM_ZONE)
695 /* it seems the only way to tell non-GNU versions of strftime what
696 zone to use (for the %Z format) is to set TZ in the
697 environment. interrupts and thread switching must be deferred
698 until TZ is restored. */
699 char **oldenv = NULL;
ecc9f40f 700 SCM zone_spec = SCM_SIMPLE_VECTOR_REF (stime, 10);
e652b54f 701 int have_zone = 0;
b8a1b29b 702
ecc9f40f 703 if (scm_is_true (zone_spec) && scm_c_string_length (zone_spec) > 0)
b8a1b29b
GH
704 {
705 /* it's not required that the TZ setting be correct, just that
e652b54f
GH
706 it has the right name. so try something like TZ=EST0.
707 using only TZ=EST would be simpler but it doesn't work on
708 some OSs, e.g., Solaris. */
709 SCM zone =
ecc9f40f
MV
710 scm_string_append (scm_list_2 (zone_spec,
711 scm_from_locale_string ("0")));
1c299a6b 712
e652b54f 713 have_zone = 1;
9de87eea 714 SCM_CRITICAL_SECTION_START;
e652b54f 715 oldenv = setzone (zone, SCM_ARG2, FUNC_NAME);
b8a1b29b
GH
716 }
717#endif
718
38c1d3c4 719#ifdef LOCALTIME_CACHE
b8a1b29b
GH
720 tzset ();
721#endif
722
69f23174
LC
723 /* Use `nstrftime ()' from Gnulib, which supports all GNU extensions
724 supported by glibc. */
d40e1ca8 725 while ((len = nstrftime (tbuf, size, myfmt, &t, 0, 0)) == 0)
b8a1b29b 726 {
4c9419ac 727 free (tbuf);
b8a1b29b 728 size *= 2;
4c9419ac 729 tbuf = scm_malloc (size);
b8a1b29b
GH
730 }
731
732#if !defined (HAVE_TM_ZONE)
e652b54f 733 if (have_zone)
b8a1b29b 734 {
ecc9f40f 735 restorezone (zone_spec, oldenv, FUNC_NAME);
9de87eea 736 SCM_CRITICAL_SECTION_END;
b8a1b29b 737 }
38c1d3c4 738#endif
b9525b92 739 }
b8a1b29b 740
d40e1ca8 741 result = scm_from_utf8_string (tbuf + 1);
4c9419ac
MV
742 free (tbuf);
743 free (myfmt);
168e958c
KR
744#if HAVE_STRUCT_TM_TM_ZONE
745 free ((char *) t.tm_zone);
746#endif
ef9ff3fd 747 return result;
b9525b92 748}
1bbd0b84 749#undef FUNC_NAME
b9525b92 750
f25f761d 751#ifdef HAVE_STRPTIME
a1ec6916 752SCM_DEFINE (scm_strptime, "strptime", 2, 0, 0,
1bbd0b84 753 (SCM format, SCM string),
a8eac221
MG
754 "Performs the reverse action to @code{strftime}, parsing\n"
755 "@var{string} according to the specification supplied in\n"
b7e64f8b 756 "@var{format}. The interpretation of month and day names is\n"
a8eac221
MG
757 "dependent on the current locale. The value returned is a pair.\n"
758 "The car has an object with time components\n"
a3c8b9fc
MD
759 "in the form returned by @code{localtime} or @code{gmtime},\n"
760 "but the time zone components\n"
761 "are not usefully set.\n"
a8eac221
MG
762 "The cdr reports the number of characters from @var{string}\n"
763 "which were used for the conversion.")
1bbd0b84 764#define FUNC_NAME s_scm_strptime
b9525b92 765{
b9525b92 766 struct tm t;
d40e1ca8 767 char *fmt, *str, *rest;
587a3355 768 size_t used_len;
8ab3d8a0 769 long zoff;
b9525b92 770
a6d9e5ab
DH
771 SCM_VALIDATE_STRING (1, format);
772 SCM_VALIDATE_STRING (2, string);
b9525b92 773
587a3355
MG
774 /* Convert strings to UTF-8 so that non-ASCII characters are passed
775 through unchanged. */
d40e1ca8
AW
776 fmt = scm_to_utf8_string (format);
777 str = scm_to_utf8_string (string);
b9525b92
GH
778
779 /* initialize the struct tm */
780#define tm_init(field) t.field = 0
781 tm_init (tm_sec);
782 tm_init (tm_min);
783 tm_init (tm_hour);
784 tm_init (tm_mday);
785 tm_init (tm_mon);
786 tm_init (tm_year);
787 tm_init (tm_wday);
788 tm_init (tm_yday);
8ab3d8a0
KR
789#if HAVE_STRUCT_TM_TM_GMTOFF
790 tm_init (tm_gmtoff);
791#endif
b9525b92
GH
792#undef tm_init
793
03b79aa3
KR
794 /* GNU glibc strptime() "%s" is affected by the current timezone, since it
795 reads a UTC time_t value and converts with localtime_r() to set the tm
9de87eea 796 fields, hence the use of SCM_CRITICAL_SECTION_START. */
b9525b92 797 t.tm_isdst = -1;
9de87eea 798 SCM_CRITICAL_SECTION_START;
d40e1ca8 799 rest = strptime (str, fmt, &t);
9de87eea 800 SCM_CRITICAL_SECTION_END;
763313a2 801 if (rest == NULL)
73ae3b4c
KR
802 {
803 /* POSIX doesn't say strptime sets errno, and on glibc 2.3.2 for
804 instance it doesn't. Force a sensible value for our error
805 message. */
806 errno = EINVAL;
587a3355
MG
807 scm_remember_upto_here_2 (format, string);
808 free (str);
809 free (fmt);
73ae3b4c
KR
810 SCM_SYSERROR;
811 }
b9525b92 812
8ab3d8a0
KR
813 /* tm_gmtoff is set by GNU glibc strptime "%s", so capture it when
814 available */
815#if HAVE_STRUCT_TM_TM_GMTOFF
816 zoff = - t.tm_gmtoff; /* seconds west, not east */
817#else
818 zoff = 0;
819#endif
820
587a3355 821 /* Compute the number of UTF-8 characters. */
d40e1ca8 822 used_len = u8_strnlen ((scm_t_uint8*) str, rest-str);
587a3355
MG
823 scm_remember_upto_here_2 (format, string);
824 free (str);
825 free (fmt);
826
8ab3d8a0 827 return scm_cons (filltime (&t, zoff, NULL),
587a3355 828 scm_from_signed_integer (used_len));
b9525b92 829}
1bbd0b84 830#undef FUNC_NAME
f25f761d 831#endif /* HAVE_STRPTIME */
b9525b92 832
0f2d19dd
JB
833void
834scm_init_stime()
0f2d19dd 835{
86d31dfe 836 scm_c_define ("internal-time-units-per-second",
b9bd8526 837 scm_from_long (SCM_TIME_UNITS_PER_SECOND));
0f2d19dd 838
4a42658f
AW
839 /* Init POSIX timers, and see if we can use them. */
840#ifdef HAVE_CLOCK_GETTIME
841 if (clock_gettime (CLOCK_REALTIME, &posix_real_time_base) == 0)
842 get_internal_real_time = get_internal_real_time_posix_timer;
843
a02a6067 844#ifdef HAVE_POSIX_CPUTIME
4a42658f
AW
845 {
846 clockid_t dummy;
847
848 /* Only use the _POSIX_CPUTIME clock if it's going to work across
849 CPUs. */
850 if (clock_getcpuclockid (0, &dummy) == 0 &&
851 clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &posix_run_time_base) == 0)
852 get_internal_run_time = get_internal_run_time_posix_timer;
853 else
854 errno = 0;
855 }
a02a6067 856#endif /* HAVE_POSIX_CPUTIME */
4a42658f
AW
857#endif /* HAVE_CLOCKTIME */
858
859 /* If needed, init and use gettimeofday timer. */
860#ifdef HAVE_GETTIMEOFDAY
861 if (!get_internal_real_time
862 && gettimeofday (&gettimeofday_real_time_base, NULL) == 0)
863 get_internal_real_time = get_internal_real_time_gettimeofday;
864#endif
865
866 /* Init ticks_per_second for scm_times, and use times(2)-based
867 run-time timer if needed. */
4a42658f
AW
868#ifdef _SC_CLK_TCK
869 ticks_per_second = sysconf (_SC_CLK_TCK);
0f2d19dd 870#else
4a42658f 871 ticks_per_second = CLK_TCK;
0f2d19dd 872#endif
4a42658f
AW
873 if (!get_internal_run_time)
874 get_internal_run_time = get_internal_run_time_times;
0f2d19dd 875
40e2a31d
AW
876 if (!get_internal_real_time)
877 /* No POSIX timers, gettimeofday doesn't work... badness! */
878 {
879 fallback_real_time_base = time (NULL);
880 get_internal_real_time = get_internal_real_time_fallback;
881 }
0f2d19dd 882
876c87ce 883 scm_add_feature ("current-time");
a0599745 884#include "libguile/stime.x"
0f2d19dd
JB
885}
886
89e00824
ML
887
888/*
889 Local Variables:
890 c-file-style: "gnu"
891 End:
892*/