* eval.c: define scm_unbound_variable_key ('unbound-variable).
[bpt/guile.git] / libguile / stime.c
CommitLineData
c7abe4f3 1/* Copyright (C) 1995,1996,1997,1998, 1999 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. */
1bbd0b84
GB
41
42/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
0f2d19dd
JB
45\f
46
47#include <stdio.h>
48#include "_scm.h"
876c87ce 49#include "feature.h"
20e6290e 50
1bbd0b84 51#include "scm_validate.h"
20e6290e
JB
52#include "stime.h"
53
0f2d19dd
JB
54#ifdef HAVE_UNISTD_H
55#include <unistd.h>
56#endif
57
58\f
59# ifdef HAVE_SYS_TYPES_H
60# include <sys/types.h>
61# endif
62
63# ifdef TIME_WITH_SYS_TIME
64# include <sys/time.h>
65# include <time.h>
66# else
67# ifdef HAVE_SYS_TIME_H
68# include <sys/time.h>
69# else
70# ifdef HAVE_TIME_H
71# include <time.h>
72# endif
73# endif
74# endif
75
b1978258
GH
76#ifdef HAVE_SYS_TIMES_H
77# include <sys/times.h>
78#endif
79
80#ifdef HAVE_SYS_TIMEB_H
81# include <sys/timeb.h>
82#endif
0f2d19dd 83
b9525b92
GH
84#ifndef tzname /* For SGI. */
85extern char *tzname[]; /* RS6000 and others reject char **tzname. */
86#endif
87
4d3bacdd
JB
88#ifdef MISSING_STRPTIME_DECL
89extern char *strptime ();
90#endif
91
cda55316 92/* This should be figured out by autoconf. */
a2fc27b5
JB
93#if ! defined(CLKTCK) && defined(CLK_TCK)
94# define CLKTCK CLK_TCK
95#endif
96#if ! defined(CLKTCK) && defined(CLOCKS_PER_SEC)
0f2d19dd 97# define CLKTCK CLOCKS_PER_SEC
a2fc27b5
JB
98#endif
99#if ! defined(CLKTCK)
0f2d19dd 100# define CLKTCK 60
0f2d19dd
JB
101#endif
102
a2fc27b5 103
0f2d19dd
JB
104#ifdef __STDC__
105# define timet time_t
106#else
107# define timet long
108#endif
109
110#ifdef HAVE_TIMES
0f2d19dd
JB
111static
112long mytime()
0f2d19dd
JB
113{
114 struct tms time_buffer;
115 times(&time_buffer);
116 return time_buffer.tms_utime + time_buffer.tms_stime;
117}
118#else
119# ifdef LACK_CLOCK
120# define mytime() ((time((timet*)0) - scm_your_base) * CLKTCK)
121# else
122# define mytime clock
123# endif
124#endif
125
19468eff 126extern int errno;
0f2d19dd
JB
127
128#ifdef HAVE_FTIME
129
130struct timeb scm_your_base = {0};
1bbd0b84 131
3b3b36dd 132SCM_DEFINE (scm_get_internal_real_time, "get-internal-real-time", 0, 0, 0,
1bbd0b84 133 (),
4079f87e 134"Returns the number of time units since the interpreter was started.")
1bbd0b84 135#define FUNC_NAME s_scm_get_internal_real_time
0f2d19dd
JB
136{
137 struct timeb time_buffer;
55c4d089
JB
138
139 SCM tmp;
140 ftime (&time_buffer);
0f2d19dd 141 time_buffer.time -= scm_your_base.time;
55c4d089
JB
142 tmp = scm_long2num (time_buffer.millitm - scm_your_base.millitm);
143 tmp = scm_sum (tmp,
144 scm_product (SCM_MAKINUM (1000),
145 SCM_MAKINUM (time_buffer.time)));
146 return scm_quotient (scm_product (tmp, SCM_MAKINUM (CLKTCK)),
147 SCM_MAKINUM (1000));
1bbd0b84
GB
148}
149#undef FUNC_NAME
150
0f2d19dd
JB
151
152#else
153
154timet scm_your_base = 0;
1bbd0b84 155
3b3b36dd 156SCM_DEFINE (scm_get_internal_real_time, "get-internal-real-time", 0, 0, 0,
1bbd0b84 157 (),
717050c8 158"")
1bbd0b84 159#define FUNC_NAME s_scm_get_internal_real_time
0f2d19dd 160{
19468eff 161 return scm_long2num((time((timet*)0) - scm_your_base) * (int)CLKTCK);
0f2d19dd 162}
1bbd0b84
GB
163#undef FUNC_NAME
164
0f2d19dd
JB
165#endif
166
f25f761d 167#ifdef HAVE_TIMES
a1ec6916 168SCM_DEFINE (scm_times, "times", 0, 0, 0,
1bbd0b84 169 (void),
4079f87e
GB
170"Returns an object with information about real and processor time.
171The following procedures accept such an object as an argument and
172return a selected component:
173
174@table @code
175@item tms:clock
176The current real time, expressed as time units relative to an
177arbitrary base.
178@item tms:utime
179The CPU time units used by the calling process.
180@item tms:stime
181The CPU time units used by the system on behalf of the calling process.
182@item tms:cutime
183The CPU time units used by terminated child processes of the calling
184process, whose status has been collected (e.g., using @code{waitpid}).
185@item tms:cstime
186Similarly, the CPU times units used by the system on behalf of
187terminated child processes.
188@end table")
1bbd0b84 189#define FUNC_NAME s_scm_times
6afcd3b2 190{
6afcd3b2
GH
191 struct tms t;
192 clock_t rv;
193
a8741caa 194 SCM result = scm_make_vector (SCM_MAKINUM(5), SCM_UNDEFINED);
6afcd3b2
GH
195 rv = times (&t);
196 if (rv == -1)
1bbd0b84 197 SCM_SYSERROR;
6afcd3b2
GH
198 SCM_VELTS (result)[0] = scm_long2num (rv);
199 SCM_VELTS (result)[1] = scm_long2num (t.tms_utime);
200 SCM_VELTS (result)[2] = scm_long2num (t.tms_stime);
201 SCM_VELTS (result)[3] = scm_long2num (t.tms_cutime);
202 SCM_VELTS (result)[4] = scm_long2num (t.tms_cstime);
203 return result;
6afcd3b2 204}
1bbd0b84 205#undef FUNC_NAME
f25f761d 206#endif /* HAVE_TIMES */
6afcd3b2 207
0e958795
JB
208#ifndef HAVE_TZSET
209/* GNU-WIN32's cygwin.dll doesn't have this. */
210#define tzset()
211#endif
0f2d19dd
JB
212
213
214static long scm_my_base = 0;
215
3b3b36dd 216SCM_DEFINE (scm_get_internal_run_time, "get-internal-run-time", 0, 0, 0,
1bbd0b84 217 (void),
4079f87e
GB
218"Returns the number of time units of processor time used by the interpreter.
219Both "system" and "user" time
220are included but subprocesses are not.")
1bbd0b84 221#define FUNC_NAME s_scm_get_internal_run_time
0f2d19dd 222{
19468eff 223 return scm_long2num(mytime()-scm_my_base);
0f2d19dd 224}
1bbd0b84 225#undef FUNC_NAME
0f2d19dd 226
3b3b36dd 227SCM_DEFINE (scm_current_time, "current-time", 0, 0, 0,
1bbd0b84 228 (void),
4079f87e
GB
229"Returns the number of seconds since 1970-01-01 00:00:00 UTC, excluding
230leap seconds.")
1bbd0b84 231#define FUNC_NAME s_scm_current_time
0f2d19dd 232{
19468eff
GH
233 timet timv;
234
235 SCM_DEFER_INTS;
236 if ((timv = time (0)) == -1)
1bbd0b84 237 SCM_SYSERROR;
19468eff
GH
238 SCM_ALLOW_INTS;
239 return scm_long2num((long) timv);
240}
1bbd0b84 241#undef FUNC_NAME
19468eff 242
a1ec6916 243SCM_DEFINE (scm_gettimeofday, "gettimeofday", 0, 0, 0,
1bbd0b84 244 (void),
4079f87e
GB
245"Returns a pair containing the number of seconds and microseconds since
2461970-01-01 00:00:00 UTC, excluding leap seconds. Note: whether true
247microsecond resolution is available depends on the operating system.")
1bbd0b84 248#define FUNC_NAME s_scm_gettimeofday
19468eff
GH
249{
250#ifdef HAVE_GETTIMEOFDAY
251 struct timeval time;
252
253 SCM_DEFER_INTS;
254 if (gettimeofday (&time, NULL) == -1)
1bbd0b84 255 SCM_SYSERROR;
19468eff
GH
256 SCM_ALLOW_INTS;
257 return scm_cons (scm_long2num ((long) time.tv_sec),
258 scm_long2num ((long) time.tv_usec));
259#else
260# ifdef HAVE_FTIME
261 struct timeb time;
262
263 ftime(&time);
264 return scm_cons (scm_long2num ((long) time.time),
9a81afca 265 SCM_MAKINUM (time.millitm * 1000));
19468eff
GH
266# else
267 timet timv;
268
269 SCM_DEFER_INTS;
270 if ((timv = time (0)) == -1)
1bbd0b84 271 SCM_SYSERROR;
19468eff
GH
272 SCM_ALLOW_INTS;
273 return scm_cons (scm_long2num (timv), SCM_MAKINUM (0));
274# endif
275#endif
276}
1bbd0b84 277#undef FUNC_NAME
19468eff
GH
278
279static SCM
280filltime (struct tm *bd_time, int zoff, char *zname)
281{
a8741caa 282 SCM result = scm_make_vector (SCM_MAKINUM(11), SCM_UNDEFINED);
19468eff
GH
283
284 SCM_VELTS (result)[0] = SCM_MAKINUM (bd_time->tm_sec);
285 SCM_VELTS (result)[1] = SCM_MAKINUM (bd_time->tm_min);
286 SCM_VELTS (result)[2] = SCM_MAKINUM (bd_time->tm_hour);
287 SCM_VELTS (result)[3] = SCM_MAKINUM (bd_time->tm_mday);
288 SCM_VELTS (result)[4] = SCM_MAKINUM (bd_time->tm_mon);
289 SCM_VELTS (result)[5] = SCM_MAKINUM (bd_time->tm_year);
290 SCM_VELTS (result)[6] = SCM_MAKINUM (bd_time->tm_wday);
291 SCM_VELTS (result)[7] = SCM_MAKINUM (bd_time->tm_yday);
292 SCM_VELTS (result)[8] = SCM_MAKINUM (bd_time->tm_isdst);
293 SCM_VELTS (result)[9] = SCM_MAKINUM (zoff);
b9525b92 294 SCM_VELTS (result)[10] = zname ? scm_makfrom0str (zname) : SCM_BOOL_F;
19468eff
GH
295 return result;
296}
297
ef9ff3fd
GH
298static char tzvar[3] = "TZ";
299extern char ** environ;
300
301static char **
3eeba8d4 302setzone (SCM zone, int pos, const char *subr)
b9525b92 303{
ef9ff3fd 304 char **oldenv = 0;
b9525b92
GH
305
306 if (!SCM_UNBNDP (zone))
307 {
ef9ff3fd 308 static char *tmpenv[2];
b9525b92
GH
309 char *buf;
310
ef9ff3fd 311 /* if zone was supplied, set the environment temporarily. */
0c95b57d 312 SCM_ASSERT (SCM_ROSTRINGP (zone), zone, pos, subr);
89958ad0 313 SCM_COERCE_SUBSTR (zone);
ef9ff3fd
GH
314 buf = scm_must_malloc (SCM_LENGTH (zone) + sizeof (tzvar) + 1,
315 subr);
316 sprintf (buf, "%s=%s", tzvar, SCM_ROCHARS (zone));
317 oldenv = environ;
318 tmpenv[0] = buf;
319 tmpenv[1] = 0;
320 environ = tmpenv;
b9525b92
GH
321 tzset();
322 }
ef9ff3fd 323 return oldenv;
b9525b92
GH
324}
325
326static void
3eeba8d4 327restorezone (SCM zone, char **oldenv, const char *subr)
b9525b92
GH
328{
329 if (!SCM_UNBNDP (zone))
330 {
ef9ff3fd
GH
331 scm_must_free (environ[0]);
332 environ = oldenv;
b9525b92
GH
333 tzset();
334 }
335}
336
337
a1ec6916 338SCM_DEFINE (scm_localtime, "localtime", 1, 1, 0,
1bbd0b84 339 (SCM time, SCM zone),
4079f87e
GB
340"Returns an object representing the broken down components of @var{time},
341an integer like the one returned by @code{current-time}. The time zone
342for the calculation is optionally specified by @var{zone} (a string),
343otherwise the @code{TZ} environment variable or the system default is
344used.")
1bbd0b84 345#define FUNC_NAME s_scm_localtime
19468eff
GH
346{
347 timet itime;
4edc089c 348 struct tm *ltptr, lt, *utc;
19468eff
GH
349 SCM result;
350 int zoff;
351 char *zname = 0;
ef9ff3fd 352 char **oldenv;
19468eff
GH
353 int err;
354
1bbd0b84 355 itime = SCM_NUM2LONG (1,time);
19468eff 356 SCM_DEFER_INTS;
1bbd0b84 357 oldenv = setzone (zone, SCM_ARG2, FUNC_NAME);
4edc089c 358 ltptr = localtime (&itime);
19468eff 359 err = errno;
4edc089c 360 if (ltptr)
19468eff 361 {
4d3bacdd 362 const char *ptr;
ef9ff3fd
GH
363
364 /* copy zone name before calling gmtime or tzset. */
b9525b92 365#ifdef HAVE_TM_ZONE
ef9ff3fd 366 ptr = ltptr->tm_zone;
b9525b92
GH
367#else
368# ifdef HAVE_TZNAME
ef9ff3fd 369 ptr = tzname[ (ltptr->tm_isdst == 1) ? 1 : 0 ];
4edc089c 370# else
1bbd0b84 371 SCM_MISC_ERROR ("Not fully implemented on this platform",_EOL);
4edc089c 372# endif
b9525b92 373#endif
1bbd0b84 374 zname = SCM_MUST_MALLOC (strlen (ptr) + 1);
ef9ff3fd 375 strcpy (zname, ptr);
19468eff 376 }
ef9ff3fd
GH
377 /* the struct is copied in case localtime and gmtime share a buffer. */
378 if (ltptr)
379 lt = *ltptr;
380 utc = gmtime (&itime);
381 if (utc == NULL)
382 err = errno;
1bbd0b84 383 restorezone (zone, oldenv, FUNC_NAME);
b9525b92 384 /* delayed until zone has been restored. */
19468eff 385 errno = err;
4edc089c 386 if (utc == NULL || ltptr == NULL)
1bbd0b84 387 SCM_SYSERROR;
19468eff
GH
388
389 /* calculate timezone offset in seconds west of UTC. */
4edc089c
GH
390 zoff = (utc->tm_hour - lt.tm_hour) * 3600 + (utc->tm_min - lt.tm_min) * 60
391 + utc->tm_sec - lt.tm_sec;
392 if (utc->tm_year < lt.tm_year)
19468eff 393 zoff -= 24 * 60 * 60;
4edc089c 394 else if (utc->tm_year > lt.tm_year)
19468eff 395 zoff += 24 * 60 * 60;
4edc089c 396 else if (utc->tm_yday < lt.tm_yday)
19468eff 397 zoff -= 24 * 60 * 60;
4edc089c 398 else if (utc->tm_yday > lt.tm_yday)
19468eff
GH
399 zoff += 24 * 60 * 60;
400
4edc089c 401 result = filltime (&lt, zoff, zname);
19468eff 402 SCM_ALLOW_INTS;
ef9ff3fd 403 scm_must_free (zname);
19468eff
GH
404 return result;
405}
1bbd0b84 406#undef FUNC_NAME
19468eff 407
a1ec6916 408SCM_DEFINE (scm_gmtime, "gmtime", 1, 0, 0,
1bbd0b84 409 (SCM time),
4079f87e
GB
410"Returns an object representing the broken down components of @var{time},
411an integer like the one returned by @code{current-time}. The values
412are calculated for UTC.")
1bbd0b84 413#define FUNC_NAME s_scm_gmtime
19468eff
GH
414{
415 timet itime;
416 struct tm *bd_time;
417 SCM result;
418
1bbd0b84 419 itime = SCM_NUM2LONG (1,time);
19468eff
GH
420 SCM_DEFER_INTS;
421 bd_time = gmtime (&itime);
422 if (bd_time == NULL)
1bbd0b84 423 SCM_SYSERROR;
19468eff
GH
424 result = filltime (bd_time, 0, "GMT");
425 SCM_ALLOW_INTS;
426 return result;
427}
1bbd0b84 428#undef FUNC_NAME
19468eff 429
b9525b92
GH
430/* copy time components from a Scheme object to a struct tm. */
431static void
3eeba8d4 432bdtime2c (SCM sbd_time, struct tm *lt, int pos, const char *subr)
19468eff 433{
55a7fc62
GH
434 SCM *velts;
435 int i;
436
0c95b57d 437 SCM_ASSERT (SCM_VECTORP (sbd_time)
55a7fc62 438 && SCM_LENGTH (sbd_time) == 11,
b9525b92 439 sbd_time, pos, subr);
55a7fc62
GH
440 velts = SCM_VELTS (sbd_time);
441 for (i = 0; i < 10; i++)
442 {
443 SCM_ASSERT (SCM_INUMP (velts[i]), sbd_time, pos, subr);
444 }
0c95b57d 445 SCM_ASSERT (SCM_FALSEP (velts[10]) || SCM_STRINGP (velts[10]),
55a7fc62
GH
446 sbd_time, pos, subr);
447
448 lt->tm_sec = SCM_INUM (velts[0]);
449 lt->tm_min = SCM_INUM (velts[1]);
450 lt->tm_hour = SCM_INUM (velts[2]);
451 lt->tm_mday = SCM_INUM (velts[3]);
452 lt->tm_mon = SCM_INUM (velts[4]);
453 lt->tm_year = SCM_INUM (velts[5]);
454 lt->tm_wday = SCM_INUM (velts[6]);
455 lt->tm_yday = SCM_INUM (velts[7]);
456 lt->tm_isdst = SCM_INUM (velts[8]);
c7abe4f3 457#ifdef HAVE_TM_ZONE
55a7fc62
GH
458 lt->tm_gmtoff = SCM_INUM (velts[9]);
459 if (SCM_FALSEP (velts[10]))
460 lt->tm_zone = NULL;
461 else
462 lt->tm_zone = SCM_CHARS (velts[10]);
c7abe4f3 463#endif
b9525b92
GH
464}
465
a1ec6916 466SCM_DEFINE (scm_mktime, "mktime", 1, 1, 0,
1bbd0b84 467 (SCM sbd_time, SCM zone),
4079f87e
GB
468"@var{bd-time} is an object representing broken down time and @code{zone}
469is an optional time zone specifier (otherwise the TZ environment variable
470or the system default is used).
471
472Returns a pair: the CAR is a corresponding
473integer time value like that returned
474by @code{current-time}; the CDR is a broken down time object, similar to
475as @var{bd-time} but with normalized values.")
1bbd0b84 476#define FUNC_NAME s_scm_mktime
b9525b92
GH
477{
478 timet itime;
479 struct tm lt, *utc;
480 SCM result;
481 int zoff;
482 char *zname = 0;
ef9ff3fd 483 char **oldenv;
b9525b92
GH
484 int err;
485
1bbd0b84 486 bdtime2c (sbd_time, &lt, SCM_ARG1, FUNC_NAME);
19468eff
GH
487
488 SCM_DEFER_INTS;
1bbd0b84 489 oldenv = setzone (zone, SCM_ARG2, FUNC_NAME);
19468eff 490 itime = mktime (&lt);
b9525b92 491 err = errno;
19468eff 492
b9525b92
GH
493 if (itime != -1)
494 {
4d3bacdd 495 const char *ptr;
ef9ff3fd
GH
496
497 /* copy zone name before calling gmtime or tzset. */
b9525b92 498#ifdef HAVE_TM_ZONE
ef9ff3fd 499 ptr = lt.tm_zone;
b9525b92
GH
500#else
501# ifdef HAVE_TZNAME
ef9ff3fd 502 ptr = tzname[ (lt.tm_isdst == 1) ? 1 : 0 ];
4edc089c 503# else
ef9ff3fd 504 scm_misc_error (s_mktime, "Not fully implemented on this platform",
da5b3eb1 505 SCM_EOL);
4edc089c 506# endif
b9525b92 507#endif
1bbd0b84 508 zname = SCM_MUST_MALLOC (strlen (ptr) + 1);
ef9ff3fd 509 strcpy (zname, ptr);
b9525b92 510 }
ef9ff3fd
GH
511
512 /* get timezone offset in seconds west of UTC. */
513 utc = gmtime (&itime);
514 if (utc == NULL)
515 err = errno;
516
1bbd0b84 517 restorezone (zone, oldenv, FUNC_NAME);
b9525b92
GH
518 /* delayed until zone has been restored. */
519 errno = err;
520 if (utc == NULL || itime == -1)
1bbd0b84 521 SCM_SYSERROR;
b9525b92 522
19468eff
GH
523 zoff = (utc->tm_hour - lt.tm_hour) * 3600 + (utc->tm_min - lt.tm_min) * 60
524 + utc->tm_sec - lt.tm_sec;
525 if (utc->tm_year < lt.tm_year)
526 zoff -= 24 * 60 * 60;
527 else if (utc->tm_year > lt.tm_year)
528 zoff += 24 * 60 * 60;
529 else if (utc->tm_yday < lt.tm_yday)
530 zoff -= 24 * 60 * 60;
531 else if (utc->tm_yday > lt.tm_yday)
532 zoff += 24 * 60 * 60;
533
19468eff
GH
534 result = scm_cons (scm_long2num ((long) itime),
535 filltime (&lt, zoff, zname));
536 SCM_ALLOW_INTS;
ef9ff3fd 537 scm_must_free (zname);
19468eff 538 return result;
0f2d19dd 539}
1bbd0b84 540#undef FUNC_NAME
0f2d19dd 541
a1ec6916 542SCM_DEFINE (scm_tzset, "tzset", 0, 0, 0,
1bbd0b84 543 (void),
4079f87e
GB
544"Initialize the timezone from the TZ environment variable or the system
545default. Usually this is done automatically by other procedures which
546use the time zone, but this procedure may need to be used if TZ
547is changed.")
1bbd0b84 548#define FUNC_NAME s_scm_tzset
0f2d19dd 549{
19468eff
GH
550 tzset();
551 return SCM_UNSPECIFIED;
0f2d19dd 552}
1bbd0b84 553#undef FUNC_NAME
0f2d19dd 554
a1ec6916 555SCM_DEFINE (scm_strftime, "strftime", 2, 0, 0,
1bbd0b84 556 (SCM format, SCM stime),
4079f87e
GB
557"Formats a time specification @var{time} using @var{template}. @var{time}
558is an object with time components in the form returned by @code{localtime}
559or @code{gmtime}. @var{template} is a string which can include formatting
560specifications introduced by a @code{%} character. The formatting of
561month and day names is dependent on the current locale. The value returned
562is the formatted string.
563@xref{Formatting Date and Time, , , libc, The GNU C Library Reference Manual}.)")
1bbd0b84 564#define FUNC_NAME s_scm_strftime
b9525b92
GH
565{
566 struct tm t;
567
568 char *tbuf;
569 int size = 50;
570 char *fmt;
571 int len;
ef9ff3fd 572 SCM result;
b9525b92 573
3b3b36dd 574 SCM_VALIDATE_ROSTRING (1,format);
1bbd0b84 575 bdtime2c (stime, &t, SCM_ARG2, FUNC_NAME);
b9525b92 576
89958ad0 577 SCM_COERCE_SUBSTR (format);
b9525b92
GH
578 fmt = SCM_ROCHARS (format);
579 len = SCM_ROLENGTH (format);
580
1bbd0b84 581 tbuf = SCM_MUST_MALLOC (size);
b9525b92
GH
582 while ((len = strftime (tbuf, size, fmt, &t)) == size)
583 {
584 scm_must_free (tbuf);
585 size *= 2;
1bbd0b84 586 tbuf = SCM_MUST_MALLOC (size);
b9525b92 587 }
ef9ff3fd
GH
588 result = scm_makfromstr (tbuf, len, 0);
589 scm_must_free (tbuf);
590 return result;
b9525b92 591}
1bbd0b84 592#undef FUNC_NAME
b9525b92 593
f25f761d 594#ifdef HAVE_STRPTIME
a1ec6916 595SCM_DEFINE (scm_strptime, "strptime", 2, 0, 0,
1bbd0b84 596 (SCM format, SCM string),
4079f87e
GB
597"Performs the reverse action to @code{strftime}, parsing @var{string}
598according to the specification supplied in @var{template}. The
599interpretation of month and day names is dependent on the current
600locale. The
601value returned is a pair. The CAR has an object with time components
602in the form returned by @code{localtime} or @code{gmtime},
603but the time zone components
604are not usefully set.
605The CDR reports the number of characters from @var{string} which
f25f761d 606vwere used for the conversion.")
1bbd0b84 607#define FUNC_NAME s_scm_strptime
b9525b92 608{
b9525b92
GH
609 struct tm t;
610 char *fmt, *str, *rest;
611
3b3b36dd
GB
612 SCM_VALIDATE_ROSTRING (1,format);
613 SCM_VALIDATE_ROSTRING (2,string);
b9525b92 614
89958ad0
JB
615 SCM_COERCE_SUBSTR (format);
616 SCM_COERCE_SUBSTR (string);
b9525b92
GH
617 fmt = SCM_ROCHARS (format);
618 str = SCM_ROCHARS (string);
619
620 /* initialize the struct tm */
621#define tm_init(field) t.field = 0
622 tm_init (tm_sec);
623 tm_init (tm_min);
624 tm_init (tm_hour);
625 tm_init (tm_mday);
626 tm_init (tm_mon);
627 tm_init (tm_year);
628 tm_init (tm_wday);
629 tm_init (tm_yday);
630#undef tm_init
631
632 t.tm_isdst = -1;
633 SCM_DEFER_INTS;
634 if ((rest = strptime (str, fmt, &t)) == NULL)
1bbd0b84 635 SCM_SYSERROR;
b9525b92
GH
636
637 SCM_ALLOW_INTS;
638 return scm_cons (filltime (&t, 0, NULL), SCM_MAKINUM (rest - str));
b9525b92 639}
1bbd0b84 640#undef FUNC_NAME
f25f761d 641#endif /* HAVE_STRPTIME */
b9525b92 642
0f2d19dd
JB
643void
644scm_init_stime()
0f2d19dd
JB
645{
646 scm_sysintern("internal-time-units-per-second",
19468eff 647 scm_long2num((long)CLKTCK));
0f2d19dd
JB
648
649#ifdef HAVE_FTIME
650 if (!scm_your_base.time) ftime(&scm_your_base);
651#else
652 if (!scm_your_base) time(&scm_your_base);
653#endif
654
655 if (!scm_my_base) scm_my_base = mytime();
656
876c87ce 657 scm_add_feature ("current-time");
0f2d19dd
JB
658#include "stime.x"
659}
660