* emacs.scm (emacs-load): Something has changed in the reader so
[bpt/guile.git] / libguile / stime.c
CommitLineData
19468eff 1/* Copyright (C) 1995,1996,1997 Free Software Foundation, Inc.
0f2d19dd
JB
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
0f2d19dd
JB
41\f
42
43#include <stdio.h>
44#include "_scm.h"
876c87ce 45#include "feature.h"
b9525b92 46#include "sequences.h"
20e6290e
JB
47
48#include "stime.h"
49
0f2d19dd
JB
50#ifdef HAVE_UNISTD_H
51#include <unistd.h>
52#endif
53
54\f
55# ifdef HAVE_SYS_TYPES_H
56# include <sys/types.h>
57# endif
58
59# ifdef TIME_WITH_SYS_TIME
60# include <sys/time.h>
61# include <time.h>
62# else
63# ifdef HAVE_SYS_TIME_H
64# include <sys/time.h>
65# else
66# ifdef HAVE_TIME_H
67# include <time.h>
68# endif
69# endif
70# endif
71
b1978258
GH
72#ifdef HAVE_SYS_TIMES_H
73# include <sys/times.h>
74#endif
75
76#ifdef HAVE_SYS_TIMEB_H
77# include <sys/timeb.h>
78#endif
0f2d19dd 79
b9525b92
GH
80#ifndef tzname /* For SGI. */
81extern char *tzname[]; /* RS6000 and others reject char **tzname. */
82#endif
83
84char *strptime ();
85
cda55316 86/* This should be figured out by autoconf. */
0f2d19dd
JB
87#ifdef CLK_TCK
88# define CLKTCK CLK_TCK
89# ifdef CLOCKS_PER_SEC
cda55316 90# if defined (unix) || defined (__unix)
0f2d19dd
JB
91# ifndef ARM_ULIB
92# include <sys/times.h>
93# endif
94# define LACK_CLOCK
95 /* This is because clock() might be POSIX rather than ANSI.
96 This occurs on HP-UX machines */
97# endif
98# endif
99#else
100# ifdef CLOCKS_PER_SEC
101# define CLKTCK CLOCKS_PER_SEC
102# else
103# define LACK_CLOCK
104# define CLKTCK 60
105# endif
106#endif
107
0f2d19dd
JB
108#ifdef __STDC__
109# define timet time_t
110#else
111# define timet long
112#endif
113
114#ifdef HAVE_TIMES
0f2d19dd
JB
115static
116long mytime()
0f2d19dd
JB
117{
118 struct tms time_buffer;
119 times(&time_buffer);
120 return time_buffer.tms_utime + time_buffer.tms_stime;
121}
122#else
123# ifdef LACK_CLOCK
124# define mytime() ((time((timet*)0) - scm_your_base) * CLKTCK)
125# else
126# define mytime clock
127# endif
128#endif
129
19468eff 130extern int errno;
0f2d19dd
JB
131
132#ifdef HAVE_FTIME
133
23858ad1
MD
134extern int ftime (struct timeb *);
135
0f2d19dd
JB
136struct timeb scm_your_base = {0};
137SCM_PROC(s_get_internal_real_time, "get-internal-real-time", 0, 0, 0, scm_get_internal_real_time);
0f2d19dd
JB
138SCM
139scm_get_internal_real_time()
0f2d19dd
JB
140{
141 struct timeb time_buffer;
142 long tmp;
143 ftime(&time_buffer);
144 time_buffer.time -= scm_your_base.time;
145 tmp = time_buffer.millitm - scm_your_base.millitm;
146 tmp = time_buffer.time*1000L + tmp;
147 tmp *= CLKTCK;
148 tmp /= 1000;
19468eff 149 return scm_long2num (tmp);
0f2d19dd
JB
150}
151
152#else
153
154timet scm_your_base = 0;
155SCM_PROC(s_get_internal_real_time, "get-internal-real-time", 0, 0, 0, scm_get_internal_real_time);
0f2d19dd
JB
156SCM
157scm_get_internal_real_time()
0f2d19dd 158{
19468eff 159 return scm_long2num((time((timet*)0) - scm_your_base) * (int)CLKTCK);
0f2d19dd
JB
160}
161#endif
162
0e958795
JB
163#ifndef HAVE_TZSET
164/* GNU-WIN32's cygwin.dll doesn't have this. */
165#define tzset()
166#endif
0f2d19dd
JB
167
168
169static long scm_my_base = 0;
170
171SCM_PROC(s_get_internal_run_time, "get-internal-run-time", 0, 0, 0, scm_get_internal_run_time);
0f2d19dd
JB
172SCM
173scm_get_internal_run_time()
0f2d19dd 174{
19468eff 175 return scm_long2num(mytime()-scm_my_base);
0f2d19dd
JB
176}
177
178SCM_PROC(s_current_time, "current-time", 0, 0, 0, scm_current_time);
0f2d19dd
JB
179SCM
180scm_current_time()
0f2d19dd 181{
19468eff
GH
182 timet timv;
183
184 SCM_DEFER_INTS;
185 if ((timv = time (0)) == -1)
186 scm_syserror (s_current_time);
187 SCM_ALLOW_INTS;
188 return scm_long2num((long) timv);
189}
190
1bf9865d 191SCM_PROC (s_gettimeofday, "gettimeofday", 0, 0, 0, scm_gettimeofday);
19468eff 192SCM
1bf9865d 193scm_gettimeofday (void)
19468eff
GH
194{
195#ifdef HAVE_GETTIMEOFDAY
196 struct timeval time;
197
198 SCM_DEFER_INTS;
199 if (gettimeofday (&time, NULL) == -1)
1bf9865d 200 scm_syserror (s_gettimeofday);
19468eff
GH
201 SCM_ALLOW_INTS;
202 return scm_cons (scm_long2num ((long) time.tv_sec),
203 scm_long2num ((long) time.tv_usec));
204#else
205# ifdef HAVE_FTIME
206 struct timeb time;
207
208 ftime(&time);
209 return scm_cons (scm_long2num ((long) time.time),
9a81afca 210 SCM_MAKINUM (time.millitm * 1000));
19468eff
GH
211# else
212 timet timv;
213
214 SCM_DEFER_INTS;
215 if ((timv = time (0)) == -1)
1bf9865d 216 scm_syserror (s_gettimeofday);
19468eff
GH
217 SCM_ALLOW_INTS;
218 return scm_cons (scm_long2num (timv), SCM_MAKINUM (0));
219# endif
220#endif
221}
222
223static SCM
224filltime (struct tm *bd_time, int zoff, char *zname)
225{
226 SCM result = scm_make_vector(SCM_MAKINUM(11), SCM_UNDEFINED, SCM_UNDEFINED);
227
228 SCM_VELTS (result)[0] = SCM_MAKINUM (bd_time->tm_sec);
229 SCM_VELTS (result)[1] = SCM_MAKINUM (bd_time->tm_min);
230 SCM_VELTS (result)[2] = SCM_MAKINUM (bd_time->tm_hour);
231 SCM_VELTS (result)[3] = SCM_MAKINUM (bd_time->tm_mday);
232 SCM_VELTS (result)[4] = SCM_MAKINUM (bd_time->tm_mon);
233 SCM_VELTS (result)[5] = SCM_MAKINUM (bd_time->tm_year);
234 SCM_VELTS (result)[6] = SCM_MAKINUM (bd_time->tm_wday);
235 SCM_VELTS (result)[7] = SCM_MAKINUM (bd_time->tm_yday);
236 SCM_VELTS (result)[8] = SCM_MAKINUM (bd_time->tm_isdst);
237 SCM_VELTS (result)[9] = SCM_MAKINUM (zoff);
b9525b92 238 SCM_VELTS (result)[10] = zname ? scm_makfrom0str (zname) : SCM_BOOL_F;
19468eff
GH
239 return result;
240}
241
b9525b92
GH
242static char *
243setzone (SCM zone, int pos, char *subr)
244{
245 char *oldtz = 0;
246
247 if (!SCM_UNBNDP (zone))
248 {
249 char *buf;
250
251 /* if zone was supplied, set the environment variable TZ temporarily. */
89958ad0
JB
252 SCM_ASSERT (SCM_NIMP (zone) && SCM_ROSTRINGP (zone), zone, pos, subr);
253 SCM_COERCE_SUBSTR (zone);
b9525b92
GH
254 buf = malloc (SCM_LENGTH (zone) + 4);
255 if (buf == 0)
256 scm_memory_error (subr);
257 oldtz = getenv ("TZ");
258 if (oldtz != NULL)
259 oldtz = oldtz - 3;
89958ad0 260 sprintf (buf, "TZ=%s", SCM_ROCHARS (zone));
b9525b92
GH
261 if (putenv (buf) < 0)
262 scm_syserror (subr);
263 tzset();
264 }
265 return oldtz;
266}
267
268static void
269restorezone (SCM zone, char *oldzone)
270{
271 if (!SCM_UNBNDP (zone))
272 {
273 int rv;
274
275 if (oldzone)
276 rv = putenv (oldzone);
277 else
278 rv = putenv ("TZ");
279 if (rv < 0)
280 scm_syserror ("restorezone");
281 tzset();
282 }
283}
284
285
19468eff
GH
286SCM_PROC (s_localtime, "localtime", 1, 1, 0, scm_localtime);
287SCM
288scm_localtime (SCM time, SCM zone)
289{
290 timet itime;
4edc089c 291 struct tm *ltptr, lt, *utc;
19468eff
GH
292 SCM result;
293 int zoff;
294 char *zname = 0;
b9525b92 295 char *oldtz;
19468eff
GH
296 int err;
297
298 itime = scm_num2long (time, (char *) SCM_ARG1, s_localtime);
299 SCM_DEFER_INTS;
b9525b92 300 oldtz = setzone (zone, SCM_ARG2, s_localtime);
4edc089c 301 ltptr = localtime (&itime);
19468eff 302 err = errno;
4edc089c
GH
303 /* copied in case localtime and gmtime share a buffer. */
304 if (ltptr)
305 lt = *ltptr;
19468eff
GH
306 utc = gmtime (&itime);
307 if (utc == NULL)
308 err = errno;
4edc089c 309 if (ltptr)
19468eff 310 {
b9525b92 311#ifdef HAVE_TM_ZONE
4edc089c 312 zname = lt.tm_zone;
b9525b92
GH
313#else
314# ifdef HAVE_TZNAME
19468eff 315 /* must be copied before calling tzset again. */
4edc089c 316 char *ptr = tzname[ (lt.tm_isdst == 1) ? 1 : 0 ];
19468eff
GH
317
318 zname = scm_must_malloc (strlen (ptr) + 1, s_localtime);
319 strcpy (zname, ptr);
4edc089c
GH
320# else
321 scm_misc_error (s_localtime, "Not fully implemented on this platform",
da5b3eb1 322 SCM_EOL);
4edc089c 323# endif
b9525b92 324#endif
19468eff 325 }
b9525b92
GH
326 restorezone (zone, oldtz);
327 /* delayed until zone has been restored. */
19468eff 328 errno = err;
4edc089c 329 if (utc == NULL || ltptr == NULL)
19468eff
GH
330 scm_syserror (s_localtime);
331
332 /* calculate timezone offset in seconds west of UTC. */
4edc089c
GH
333 zoff = (utc->tm_hour - lt.tm_hour) * 3600 + (utc->tm_min - lt.tm_min) * 60
334 + utc->tm_sec - lt.tm_sec;
335 if (utc->tm_year < lt.tm_year)
19468eff 336 zoff -= 24 * 60 * 60;
4edc089c 337 else if (utc->tm_year > lt.tm_year)
19468eff 338 zoff += 24 * 60 * 60;
4edc089c 339 else if (utc->tm_yday < lt.tm_yday)
19468eff 340 zoff -= 24 * 60 * 60;
4edc089c 341 else if (utc->tm_yday > lt.tm_yday)
19468eff
GH
342 zoff += 24 * 60 * 60;
343
4edc089c 344 result = filltime (&lt, zoff, zname);
19468eff
GH
345 SCM_ALLOW_INTS;
346 return result;
347}
19468eff
GH
348
349SCM_PROC (s_gmtime, "gmtime", 1, 0, 0, scm_gmtime);
350SCM
351scm_gmtime (SCM time)
352{
353 timet itime;
354 struct tm *bd_time;
355 SCM result;
356
357 itime = scm_num2long (time, (char *) SCM_ARG1, s_gmtime);
358 SCM_DEFER_INTS;
359 bd_time = gmtime (&itime);
360 if (bd_time == NULL)
361 scm_syserror (s_gmtime);
362 result = filltime (bd_time, 0, "GMT");
363 SCM_ALLOW_INTS;
364 return result;
365}
366
b9525b92
GH
367/* copy time components from a Scheme object to a struct tm. */
368static void
369bdtime2c (SCM sbd_time, struct tm *lt, int pos, char *subr)
19468eff 370{
b9525b92
GH
371 SCM_ASSERT (SCM_NIMP (sbd_time) && SCM_VECTORP (sbd_time)
372 && scm_obj_length (sbd_time) == 11
373 && SCM_INUMP (SCM_VELTS (sbd_time)[0])
19468eff
GH
374 && SCM_INUMP (SCM_VELTS (sbd_time)[1])
375 && SCM_INUMP (SCM_VELTS (sbd_time)[2])
376 && SCM_INUMP (SCM_VELTS (sbd_time)[3])
377 && SCM_INUMP (SCM_VELTS (sbd_time)[4])
378 && SCM_INUMP (SCM_VELTS (sbd_time)[5])
b9525b92
GH
379 && SCM_INUMP (SCM_VELTS (sbd_time)[6])
380 && SCM_INUMP (SCM_VELTS (sbd_time)[7])
19468eff 381 && SCM_INUMP (SCM_VELTS (sbd_time)[8]),
b9525b92
GH
382 sbd_time, pos, subr);
383 lt->tm_sec = SCM_INUM (SCM_VELTS (sbd_time)[0]);
384 lt->tm_min = SCM_INUM (SCM_VELTS (sbd_time)[1]);
385 lt->tm_hour = SCM_INUM (SCM_VELTS (sbd_time)[2]);
386 lt->tm_mday = SCM_INUM (SCM_VELTS (sbd_time)[3]);
387 lt->tm_mon = SCM_INUM (SCM_VELTS (sbd_time)[4]);
388 lt->tm_year = SCM_INUM (SCM_VELTS (sbd_time)[5]);
389 lt->tm_wday = SCM_INUM (SCM_VELTS (sbd_time)[6]);
390 lt->tm_yday = SCM_INUM (SCM_VELTS (sbd_time)[7]);
391 lt->tm_isdst = SCM_INUM (SCM_VELTS (sbd_time)[8]);
392}
393
394SCM_PROC (s_mktime, "mktime", 1, 1, 0, scm_mktime);
395SCM
396scm_mktime (SCM sbd_time, SCM zone)
397{
398 timet itime;
399 struct tm lt, *utc;
400 SCM result;
401 int zoff;
402 char *zname = 0;
403 char *oldtz = 0;
404 int err;
405
406 SCM_ASSERT (SCM_NIMP (sbd_time) && SCM_VECTORP (sbd_time), sbd_time,
407 SCM_ARG1, s_mktime);
408 bdtime2c (sbd_time, &lt, SCM_ARG1, s_mktime);
19468eff
GH
409
410 SCM_DEFER_INTS;
b9525b92 411 oldtz = setzone (zone, SCM_ARG2, s_mktime);
19468eff 412 itime = mktime (&lt);
b9525b92 413 err = errno;
19468eff
GH
414
415 /* timezone offset in seconds west of UTC. */
416 utc = gmtime (&itime);
b9525b92
GH
417 if (utc == NULL)
418 err = errno;
419
420 if (itime != -1)
421 {
422#ifdef HAVE_TM_ZONE
73f19016 423 zname = lt.tm_zone;
b9525b92
GH
424#else
425# ifdef HAVE_TZNAME
426 /* must be copied before calling tzset again. */
427 char *ptr = tzname[ (lt.tm_isdst == 1) ? 1 : 0 ];
428
429 zname = scm_must_malloc (strlen (ptr) + 1, s_mktime);
430 strcpy (zname, ptr);
4edc089c
GH
431# else
432 scm_misc_error (s_localtime, "Not fully implemented on this platform",
da5b3eb1 433 SCM_EOL);
4edc089c 434# endif
b9525b92
GH
435#endif
436 }
437 restorezone (zone, oldtz);
438 /* delayed until zone has been restored. */
439 errno = err;
440 if (utc == NULL || itime == -1)
441 scm_syserror (s_mktime);
442
19468eff
GH
443 zoff = (utc->tm_hour - lt.tm_hour) * 3600 + (utc->tm_min - lt.tm_min) * 60
444 + utc->tm_sec - lt.tm_sec;
445 if (utc->tm_year < lt.tm_year)
446 zoff -= 24 * 60 * 60;
447 else if (utc->tm_year > lt.tm_year)
448 zoff += 24 * 60 * 60;
449 else if (utc->tm_yday < lt.tm_yday)
450 zoff -= 24 * 60 * 60;
451 else if (utc->tm_yday > lt.tm_yday)
452 zoff += 24 * 60 * 60;
453
19468eff
GH
454 result = scm_cons (scm_long2num ((long) itime),
455 filltime (&lt, zoff, zname));
456 SCM_ALLOW_INTS;
457 return result;
0f2d19dd
JB
458}
459
19468eff
GH
460SCM_PROC (s_tzset, "tzset", 0, 0, 0, scm_tzset);
461SCM
462scm_tzset (void)
0f2d19dd 463{
19468eff
GH
464 tzset();
465 return SCM_UNSPECIFIED;
0f2d19dd
JB
466}
467
b9525b92
GH
468SCM_PROC (s_strftime, "strftime", 2, 0, 0, scm_strftime);
469
470SCM
471scm_strftime (format, stime)
472 SCM format;
473 SCM stime;
474{
475 struct tm t;
476
477 char *tbuf;
478 int size = 50;
479 char *fmt;
480 int len;
481
89958ad0 482 SCM_ASSERT (SCM_NIMP (format) && SCM_ROSTRINGP (format), format, SCM_ARG1,
b9525b92
GH
483 s_strftime);
484 bdtime2c (stime, &t, SCM_ARG2, s_strftime);
485
89958ad0 486 SCM_COERCE_SUBSTR (format);
b9525b92
GH
487 fmt = SCM_ROCHARS (format);
488 len = SCM_ROLENGTH (format);
489
490 tbuf = scm_must_malloc (size, s_strftime);
491 while ((len = strftime (tbuf, size, fmt, &t)) == size)
492 {
493 scm_must_free (tbuf);
494 size *= 2;
495 tbuf = scm_must_malloc (size, s_strftime);
496 }
497 return scm_makfromstr (tbuf, len, 0);
498}
499
500SCM_PROC (s_strptime, "strptime", 2, 0, 0, scm_strptime);
501
502SCM
503scm_strptime (format, string)
504 SCM format;
505 SCM string;
506{
507#ifdef HAVE_STRPTIME
508 struct tm t;
509 char *fmt, *str, *rest;
510
511 SCM_ASSERT (SCM_NIMP (format) && SCM_ROSTRINGP (format), format, SCM_ARG1,
512 s_strptime);
513 SCM_ASSERT (SCM_NIMP (string) && SCM_ROSTRINGP (string), string, SCM_ARG2,
514 s_strptime);
515
89958ad0
JB
516 SCM_COERCE_SUBSTR (format);
517 SCM_COERCE_SUBSTR (string);
b9525b92
GH
518 fmt = SCM_ROCHARS (format);
519 str = SCM_ROCHARS (string);
520
521 /* initialize the struct tm */
522#define tm_init(field) t.field = 0
523 tm_init (tm_sec);
524 tm_init (tm_min);
525 tm_init (tm_hour);
526 tm_init (tm_mday);
527 tm_init (tm_mon);
528 tm_init (tm_year);
529 tm_init (tm_wday);
530 tm_init (tm_yday);
531#undef tm_init
532
533 t.tm_isdst = -1;
534 SCM_DEFER_INTS;
535 if ((rest = strptime (str, fmt, &t)) == NULL)
536 scm_syserror (s_strptime);
537
538 SCM_ALLOW_INTS;
539 return scm_cons (filltime (&t, 0, NULL), SCM_MAKINUM (rest - str));
540
541#else
542 scm_sysmissing (s_strptime);
543#endif
544}
545
0f2d19dd
JB
546void
547scm_init_stime()
0f2d19dd
JB
548{
549 scm_sysintern("internal-time-units-per-second",
19468eff 550 scm_long2num((long)CLKTCK));
0f2d19dd
JB
551
552#ifdef HAVE_FTIME
553 if (!scm_your_base.time) ftime(&scm_your_base);
554#else
555 if (!scm_your_base) time(&scm_your_base);
556#endif
557
558 if (!scm_my_base) scm_my_base = mytime();
559
876c87ce 560 scm_add_feature ("current-time");
0f2d19dd
JB
561#include "stime.x"
562}
563