* stime.c, socket.c, simpos.c, procs.c, posix.c, ports.c,
[bpt/guile.git] / libguile / stime.c
1 /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2003, 2004 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library 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 GNU
11 * Lesser General Public License for more details.
12 *
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
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18
19 \f
20
21 #define _GNU_SOURCE /* ask glibc for everything, in particular strptime */
22 #define _POSIX_C_SOURCE 199506L /* for gmtime_r prototype */
23
24 #if HAVE_CONFIG_H
25 # include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <errno.h>
30
31 #include "libguile/_scm.h"
32 #include "libguile/feature.h"
33 #include "libguile/strings.h"
34 #include "libguile/vectors.h"
35
36 #include "libguile/validate.h"
37 #include "libguile/stime.h"
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 \f
44 # ifdef HAVE_SYS_TYPES_H
45 # include <sys/types.h>
46 # endif
47
48 #ifdef HAVE_STRING_H
49 #include <string.h>
50 #endif
51
52 #ifdef HAVE_SYS_TIMES_H
53 # include <sys/times.h>
54 #endif
55
56 #ifdef HAVE_SYS_TIMEB_H
57 # include <sys/timeb.h>
58 #endif
59
60 #if HAVE_CRT_EXTERNS_H
61 #include <crt_externs.h> /* for Darwin _NSGetEnviron */
62 #endif
63
64 #ifndef tzname /* For SGI. */
65 extern char *tzname[]; /* RS6000 and others reject char **tzname. */
66 #endif
67 #if defined (__MINGW32__)
68 # define tzname _tzname
69 #endif
70
71 #if ! HAVE_DECL_STRPTIME
72 extern char *strptime ();
73 #endif
74
75 #ifdef __STDC__
76 # define timet time_t
77 #else
78 # define timet long
79 #endif
80
81 extern char ** environ;
82
83 /* On Apple Darwin in a shared library there's no "environ" to access
84 directly, instead the address of that variable must be obtained with
85 _NSGetEnviron(). */
86 #if HAVE__NSGETENVIRON && defined (PIC)
87 #define environ (*_NSGetEnviron())
88 #endif
89
90
91 #ifdef HAVE_TIMES
92 static
93 timet mytime()
94 {
95 struct tms time_buffer;
96 times(&time_buffer);
97 return time_buffer.tms_utime + time_buffer.tms_stime;
98 }
99 #else
100 # ifdef LACK_CLOCK
101 # define mytime() ((time((timet*)0) - scm_your_base) * SCM_TIME_UNITS_PER_SECOND)
102 # else
103 # define mytime clock
104 # endif
105 #endif
106
107 #ifdef HAVE_FTIME
108 struct timeb scm_your_base = {0};
109 #else
110 timet scm_your_base = 0;
111 #endif
112
113 SCM_DEFINE (scm_get_internal_real_time, "get-internal-real-time", 0, 0, 0,
114 (),
115 "Return the number of time units since the interpreter was\n"
116 "started.")
117 #define FUNC_NAME s_scm_get_internal_real_time
118 {
119 #ifdef HAVE_FTIME
120 struct timeb time_buffer;
121
122 SCM tmp;
123 ftime (&time_buffer);
124 time_buffer.time -= scm_your_base.time;
125 tmp = scm_from_long (time_buffer.millitm - scm_your_base.millitm);
126 tmp = scm_sum (tmp,
127 scm_product (scm_from_int (1000),
128 scm_from_int (time_buffer.time)));
129 return scm_quotient (scm_product (tmp,
130 scm_from_int (SCM_TIME_UNITS_PER_SECOND)),
131 scm_from_int (1000));
132 #else
133 return scm_from_long ((time((timet*)0) - scm_your_base)
134 * (int)SCM_TIME_UNITS_PER_SECOND);
135 #endif /* HAVE_FTIME */
136 }
137 #undef FUNC_NAME
138
139
140 #ifdef HAVE_TIMES
141 SCM_DEFINE (scm_times, "times", 0, 0, 0,
142 (void),
143 "Return an object with information about real and processor\n"
144 "time. The following procedures accept such an object as an\n"
145 "argument and return a selected component:\n"
146 "\n"
147 "@table @code\n"
148 "@item tms:clock\n"
149 "The current real time, expressed as time units relative to an\n"
150 "arbitrary base.\n"
151 "@item tms:utime\n"
152 "The CPU time units used by the calling process.\n"
153 "@item tms:stime\n"
154 "The CPU time units used by the system on behalf of the calling\n"
155 "process.\n"
156 "@item tms:cutime\n"
157 "The CPU time units used by terminated child processes of the\n"
158 "calling process, whose status has been collected (e.g., using\n"
159 "@code{waitpid}).\n"
160 "@item tms:cstime\n"
161 "Similarly, the CPU times units used by the system on behalf of\n"
162 "terminated child processes.\n"
163 "@end table")
164 #define FUNC_NAME s_scm_times
165 {
166 struct tms t;
167 clock_t rv;
168
169 SCM result = scm_c_make_vector (5, SCM_UNDEFINED);
170 rv = times (&t);
171 if (rv == -1)
172 SCM_SYSERROR;
173 SCM_VECTOR_SET (result, 0, scm_from_long (rv));
174 SCM_VECTOR_SET (result, 1, scm_from_long (t.tms_utime));
175 SCM_VECTOR_SET (result, 2, scm_from_long (t.tms_stime));
176 SCM_VECTOR_SET (result ,3, scm_from_long (t.tms_cutime));
177 SCM_VECTOR_SET (result, 4, scm_from_long (t.tms_cstime));
178 return result;
179 }
180 #undef FUNC_NAME
181 #endif /* HAVE_TIMES */
182
183 static long scm_my_base = 0;
184
185 long
186 scm_c_get_internal_run_time ()
187 {
188 return mytime () - scm_my_base;
189 }
190
191 SCM_DEFINE (scm_get_internal_run_time, "get-internal-run-time", 0, 0, 0,
192 (void),
193 "Return the number of time units of processor time used by the\n"
194 "interpreter. Both @emph{system} and @emph{user} time are\n"
195 "included but subprocesses are not.")
196 #define FUNC_NAME s_scm_get_internal_run_time
197 {
198 return scm_from_long (scm_c_get_internal_run_time ());
199 }
200 #undef FUNC_NAME
201
202 /* For reference, note that current-time and gettimeofday both should be
203 protected against setzone/restorezone changes in another thread, since on
204 DOS the system time is normally kept as local time, which means TZ
205 affects the return from current-time and gettimeofday. Not sure if DJGPP
206 etc actually has concurrent multi-threading, but it seems prudent not to
207 make assumptions about this. */
208
209 SCM_DEFINE (scm_current_time, "current-time", 0, 0, 0,
210 (void),
211 "Return the number of seconds since 1970-01-01 00:00:00 UTC,\n"
212 "excluding leap seconds.")
213 #define FUNC_NAME s_scm_current_time
214 {
215 timet timv;
216
217 SCM_DEFER_INTS;
218 if ((timv = time (0)) == -1)
219 SCM_MISC_ERROR ("current time not available", SCM_EOL);
220 SCM_ALLOW_INTS;
221 return scm_from_long (timv);
222 }
223 #undef FUNC_NAME
224
225 SCM_DEFINE (scm_gettimeofday, "gettimeofday", 0, 0, 0,
226 (void),
227 "Return a pair containing the number of seconds and microseconds\n"
228 "since 1970-01-01 00:00:00 UTC, excluding leap seconds. Note:\n"
229 "whether true microsecond resolution is available depends on the\n"
230 "operating system.")
231 #define FUNC_NAME s_scm_gettimeofday
232 {
233 #ifdef HAVE_GETTIMEOFDAY
234 struct timeval time;
235
236 SCM_DEFER_INTS;
237 if (gettimeofday (&time, NULL) == -1)
238 SCM_SYSERROR;
239 SCM_ALLOW_INTS;
240 return scm_cons (scm_from_long (time.tv_sec),
241 scm_from_long (time.tv_usec));
242 #else
243 # ifdef HAVE_FTIME
244 struct timeb time;
245
246 ftime(&time);
247 return scm_cons (scm_from_long (time.time),
248 scm_from_int (time.millitm * 1000));
249 # else
250 timet timv;
251
252 SCM_DEFER_INTS;
253 if ((timv = time (0)) == -1)
254 SCM_SYSERROR;
255 SCM_ALLOW_INTS;
256 return scm_cons (scm_from_long (timv), scm_from_int (0));
257 # endif
258 #endif
259 }
260 #undef FUNC_NAME
261
262 static SCM
263 filltime (struct tm *bd_time, int zoff, const char *zname)
264 {
265 SCM result = scm_c_make_vector (11, SCM_UNDEFINED);
266
267 SCM_VECTOR_SET (result,0, scm_from_int (bd_time->tm_sec));
268 SCM_VECTOR_SET (result,1, scm_from_int (bd_time->tm_min));
269 SCM_VECTOR_SET (result,2, scm_from_int (bd_time->tm_hour));
270 SCM_VECTOR_SET (result,3, scm_from_int (bd_time->tm_mday));
271 SCM_VECTOR_SET (result,4, scm_from_int (bd_time->tm_mon));
272 SCM_VECTOR_SET (result,5, scm_from_int (bd_time->tm_year));
273 SCM_VECTOR_SET (result,6, scm_from_int (bd_time->tm_wday));
274 SCM_VECTOR_SET (result,7, scm_from_int (bd_time->tm_yday));
275 SCM_VECTOR_SET (result,8, scm_from_int (bd_time->tm_isdst));
276 SCM_VECTOR_SET (result,9, scm_from_int (zoff));
277 SCM_VECTOR_SET (result,10, zname ? scm_makfrom0str (zname) : SCM_BOOL_F);
278 return result;
279 }
280
281 static char tzvar[3] = "TZ";
282
283 /* if zone is set, create a temporary environment with only a TZ
284 string. other threads or interrupt handlers shouldn't be allowed
285 to run until the corresponding restorezone is called. hence the use
286 of a static variable for tmpenv is no big deal. */
287 static char **
288 setzone (SCM zone, int pos, const char *subr)
289 {
290 char **oldenv = 0;
291
292 if (!SCM_UNBNDP (zone))
293 {
294 static char *tmpenv[2];
295 char *buf;
296 size_t zone_len;
297
298 zone_len = scm_to_locale_stringbuf (zone, NULL, 0);
299 buf = scm_malloc (zone_len + sizeof (tzvar) + 1);
300 strcpy (buf, tzvar);
301 buf[sizeof(tzvar)-1] = '=';
302 scm_to_locale_stringbuf (zone, buf+sizeof(tzvar), zone_len);
303 buf[sizeof(tzvar)+zone_len] = '\0';
304 oldenv = environ;
305 tmpenv[0] = buf;
306 tmpenv[1] = 0;
307 environ = tmpenv;
308 }
309 return oldenv;
310 }
311
312 static void
313 restorezone (SCM zone, char **oldenv, const char *subr SCM_UNUSED)
314 {
315 if (!SCM_UNBNDP (zone))
316 {
317 free (environ[0]);
318 environ = oldenv;
319 #ifdef HAVE_TZSET
320 /* for the possible benefit of user code linked with libguile. */
321 tzset();
322 #endif
323 }
324 }
325
326 SCM_DEFINE (scm_localtime, "localtime", 1, 1, 0,
327 (SCM time, SCM zone),
328 "Return an object representing the broken down components of\n"
329 "@var{time}, an integer like the one returned by\n"
330 "@code{current-time}. The time zone for the calculation is\n"
331 "optionally specified by @var{zone} (a string), otherwise the\n"
332 "@code{TZ} environment variable or the system default is used.")
333 #define FUNC_NAME s_scm_localtime
334 {
335 timet itime;
336 struct tm *ltptr, lt, *utc;
337 SCM result;
338 int zoff;
339 char *zname = 0;
340 char **oldenv;
341 int err;
342
343 itime = SCM_NUM2LONG (1, time);
344
345 /* deferring interupts is essential since a) setzone may install a temporary
346 environment b) localtime uses a static buffer. */
347 SCM_DEFER_INTS;
348 oldenv = setzone (zone, SCM_ARG2, FUNC_NAME);
349 #ifdef LOCALTIME_CACHE
350 tzset ();
351 #endif
352 /* POSIX says localtime sets errno, but C99 doesn't say that.
353 Give a sensible default value in case localtime doesn't set it. */
354 errno = EINVAL;
355 ltptr = localtime (&itime);
356 err = errno;
357 if (ltptr)
358 {
359 const char *ptr;
360
361 /* copy zone name before calling gmtime or restoring zone. */
362 #if defined (HAVE_TM_ZONE)
363 ptr = ltptr->tm_zone;
364 #elif defined (HAVE_TZNAME)
365 ptr = tzname[ (ltptr->tm_isdst == 1) ? 1 : 0 ];
366 #else
367 ptr = "";
368 #endif
369 zname = scm_malloc (strlen (ptr) + 1);
370 strcpy (zname, ptr);
371 }
372 /* the struct is copied in case localtime and gmtime share a buffer. */
373 if (ltptr)
374 lt = *ltptr;
375 /* POSIX says gmtime sets errno, but C99 doesn't say that.
376 Give a sensible default value in case gmtime doesn't set it. */
377 errno = EINVAL;
378 utc = gmtime (&itime);
379 if (utc == NULL)
380 err = errno;
381 restorezone (zone, oldenv, FUNC_NAME);
382 /* delayed until zone has been restored. */
383 errno = err;
384 if (utc == NULL || ltptr == NULL)
385 SCM_SYSERROR;
386
387 /* calculate timezone offset in seconds west of UTC. */
388 zoff = (utc->tm_hour - lt.tm_hour) * 3600 + (utc->tm_min - lt.tm_min) * 60
389 + utc->tm_sec - lt.tm_sec;
390 if (utc->tm_year < lt.tm_year)
391 zoff -= 24 * 60 * 60;
392 else if (utc->tm_year > lt.tm_year)
393 zoff += 24 * 60 * 60;
394 else if (utc->tm_yday < lt.tm_yday)
395 zoff -= 24 * 60 * 60;
396 else if (utc->tm_yday > lt.tm_yday)
397 zoff += 24 * 60 * 60;
398
399 result = filltime (&lt, zoff, zname);
400 SCM_ALLOW_INTS;
401 if (zname)
402 free (zname);
403 return result;
404 }
405 #undef FUNC_NAME
406
407 /* tm_zone is normally a pointer, not an array within struct tm, so we might
408 have to worry about the lifespan of what it points to. The posix specs
409 don't seem to say anything about this, let's assume here that tm_zone
410 will be a constant and therefore no protection or anything is needed
411 until we copy it in filltime(). */
412
413 SCM_DEFINE (scm_gmtime, "gmtime", 1, 0, 0,
414 (SCM time),
415 "Return an object representing the broken down components of\n"
416 "@var{time}, an integer like the one returned by\n"
417 "@code{current-time}. The values are calculated for UTC.")
418 #define FUNC_NAME s_scm_gmtime
419 {
420 timet itime;
421 struct tm bd_buf, *bd_time;
422 const char *zname;
423
424 itime = SCM_NUM2LONG (1, time);
425
426 /* POSIX says gmtime sets errno, but C99 doesn't say that.
427 Give a sensible default value in case gmtime doesn't set it. */
428 errno = EINVAL;
429
430 #if HAVE_GMTIME_R
431 bd_time = gmtime_r (&itime, &bd_buf);
432 #else
433 SCM_DEFER_INTS;
434 bd_time = gmtime (&itime);
435 if (bd_time != NULL)
436 bd_buf = *bd_time;
437 SCM_ALLOW_INTS;
438 #endif
439 if (bd_time == NULL)
440 SCM_SYSERROR;
441
442 #if HAVE_STRUCT_TM_TM_ZONE
443 zname = bd_buf.tm_zone;
444 #else
445 zname = "GMT";
446 #endif
447 return filltime (&bd_buf, 0, zname);
448 }
449 #undef FUNC_NAME
450
451 /* copy time components from a Scheme object to a struct tm. */
452 static void
453 bdtime2c (SCM sbd_time, struct tm *lt, int pos, const char *subr)
454 {
455 SCM const *velts;
456 int i;
457
458 SCM_ASSERT (SCM_VECTORP (sbd_time)
459 && SCM_VECTOR_LENGTH (sbd_time) == 11,
460 sbd_time, pos, subr);
461 velts = SCM_VELTS (sbd_time);
462 for (i = 0; i < 10; i++)
463 {
464 SCM_ASSERT (scm_is_integer (velts[i]), sbd_time, pos, subr);
465 }
466 SCM_ASSERT (scm_is_false (velts[10]) || scm_is_string (velts[10]),
467 sbd_time, pos, subr);
468
469 lt->tm_sec = scm_to_int (velts[0]);
470 lt->tm_min = scm_to_int (velts[1]);
471 lt->tm_hour = scm_to_int (velts[2]);
472 lt->tm_mday = scm_to_int (velts[3]);
473 lt->tm_mon = scm_to_int (velts[4]);
474 lt->tm_year = scm_to_int (velts[5]);
475 lt->tm_wday = scm_to_int (velts[6]);
476 lt->tm_yday = scm_to_int (velts[7]);
477 lt->tm_isdst = scm_to_int (velts[8]);
478 #ifdef HAVE_TM_ZONE
479 lt->tm_gmtoff = scm_to_int (velts[9]);
480 if (scm_is_false (velts[10]))
481 lt->tm_zone = NULL;
482 else
483 lt->tm_zone = SCM_STRING_CHARS (velts[10]);
484 #endif
485 }
486
487 SCM_DEFINE (scm_mktime, "mktime", 1, 1, 0,
488 (SCM sbd_time, SCM zone),
489 "@var{bd-time} is an object representing broken down time and @code{zone}\n"
490 "is an optional time zone specifier (otherwise the TZ environment variable\n"
491 "or the system default is used).\n\n"
492 "Returns a pair: the car is a corresponding\n"
493 "integer time value like that returned\n"
494 "by @code{current-time}; the cdr is a broken down time object, similar to\n"
495 "as @var{bd-time} but with normalized values.")
496 #define FUNC_NAME s_scm_mktime
497 {
498 timet itime;
499 struct tm lt, *utc;
500 SCM result;
501 int zoff;
502 char *zname = 0;
503 char **oldenv;
504 int err;
505
506 bdtime2c (sbd_time, &lt, SCM_ARG1, FUNC_NAME);
507
508 SCM_DEFER_INTS;
509 oldenv = setzone (zone, SCM_ARG2, FUNC_NAME);
510 #ifdef LOCALTIME_CACHE
511 tzset ();
512 #endif
513 itime = mktime (&lt);
514 /* POSIX doesn't say mktime sets errno, and on glibc 2.3.2 for instance it
515 doesn't. Force a sensible value for our error message. */
516 err = EINVAL;
517
518 if (itime != -1)
519 {
520 const char *ptr;
521
522 /* copy zone name before calling gmtime or restoring the zone. */
523 #if defined (HAVE_TM_ZONE)
524 ptr = lt.tm_zone;
525 #elif defined (HAVE_TZNAME)
526 ptr = tzname[ (lt.tm_isdst == 1) ? 1 : 0 ];
527 #else
528 ptr = "";
529 #endif
530 zname = scm_malloc (strlen (ptr) + 1);
531 strcpy (zname, ptr);
532 }
533
534 /* get timezone offset in seconds west of UTC. */
535 /* POSIX says gmtime sets errno, but C99 doesn't say that.
536 Give a sensible default value in case gmtime doesn't set it. */
537 utc = gmtime (&itime);
538 if (utc == NULL)
539 err = errno;
540
541 restorezone (zone, oldenv, FUNC_NAME);
542 /* delayed until zone has been restored. */
543 errno = err;
544 if (utc == NULL || itime == -1)
545 SCM_SYSERROR;
546
547 zoff = (utc->tm_hour - lt.tm_hour) * 3600 + (utc->tm_min - lt.tm_min) * 60
548 + utc->tm_sec - lt.tm_sec;
549 if (utc->tm_year < lt.tm_year)
550 zoff -= 24 * 60 * 60;
551 else if (utc->tm_year > lt.tm_year)
552 zoff += 24 * 60 * 60;
553 else if (utc->tm_yday < lt.tm_yday)
554 zoff -= 24 * 60 * 60;
555 else if (utc->tm_yday > lt.tm_yday)
556 zoff += 24 * 60 * 60;
557
558 result = scm_cons (scm_from_long (itime),
559 filltime (&lt, zoff, zname));
560 SCM_ALLOW_INTS;
561 if (zname)
562 free (zname);
563 return result;
564 }
565 #undef FUNC_NAME
566
567 #ifdef HAVE_TZSET
568 SCM_DEFINE (scm_tzset, "tzset", 0, 0, 0,
569 (void),
570 "Initialize the timezone from the TZ environment variable\n"
571 "or the system default. It's not usually necessary to call this procedure\n"
572 "since it's done automatically by other procedures that depend on the\n"
573 "timezone.")
574 #define FUNC_NAME s_scm_tzset
575 {
576 tzset();
577 return SCM_UNSPECIFIED;
578 }
579 #undef FUNC_NAME
580 #endif /* HAVE_TZSET */
581
582 SCM_DEFINE (scm_strftime, "strftime", 2, 0, 0,
583 (SCM format, SCM stime),
584 "Formats a time specification @var{time} using @var{template}. @var{time}\n"
585 "is an object with time components in the form returned by @code{localtime}\n"
586 "or @code{gmtime}. @var{template} is a string which can include formatting\n"
587 "specifications introduced by a @code{%} character. The formatting of\n"
588 "month and day names is dependent on the current locale. The value returned\n"
589 "is the formatted string.\n"
590 "@xref{Formatting Date and Time, , , libc, The GNU C Library Reference Manual}.)")
591 #define FUNC_NAME s_scm_strftime
592 {
593 struct tm t;
594
595 char *tbuf;
596 int size = 50;
597 char *fmt, *myfmt;
598 int len;
599 SCM result;
600
601 SCM_VALIDATE_STRING (1, format);
602 bdtime2c (stime, &t, SCM_ARG2, FUNC_NAME);
603
604 fmt = SCM_STRING_CHARS (format);
605 len = SCM_STRING_LENGTH (format);
606
607 /* Ugly hack: strftime can return 0 if its buffer is too small,
608 but some valid time strings (e.g. "%p") can sometimes produce
609 a zero-byte output string! Workaround is to prepend a junk
610 character to the format string, so that valid returns are always
611 nonzero. */
612 myfmt = scm_malloc (len+2);
613 *myfmt = 'x';
614 strncpy(myfmt+1, fmt, len);
615 myfmt[len+1] = 0;
616
617 tbuf = scm_malloc (size);
618 {
619 #if !defined (HAVE_TM_ZONE)
620 /* it seems the only way to tell non-GNU versions of strftime what
621 zone to use (for the %Z format) is to set TZ in the
622 environment. interrupts and thread switching must be deferred
623 until TZ is restored. */
624 char **oldenv = NULL;
625 SCM *velts = (SCM *) SCM_VELTS (stime);
626 int have_zone = 0;
627
628 if (scm_is_true (velts[10]) && *SCM_STRING_CHARS (velts[10]) != 0)
629 {
630 /* it's not required that the TZ setting be correct, just that
631 it has the right name. so try something like TZ=EST0.
632 using only TZ=EST would be simpler but it doesn't work on
633 some OSs, e.g., Solaris. */
634 SCM zone =
635 scm_string_append (scm_cons (velts[10],
636 scm_cons (scm_makfrom0str ("0"),
637 SCM_EOL)));
638
639 have_zone = 1;
640 SCM_DEFER_INTS;
641 oldenv = setzone (zone, SCM_ARG2, FUNC_NAME);
642 }
643 #endif
644
645 #ifdef LOCALTIME_CACHE
646 tzset ();
647 #endif
648
649 /* POSIX says strftime returns 0 on buffer overrun, but old
650 systems (i.e. libc 4 on GNU/Linux) might return `size' in that
651 case. */
652 while ((len = strftime (tbuf, size, myfmt, &t)) == 0 || len == size)
653 {
654 free (tbuf);
655 size *= 2;
656 tbuf = scm_malloc (size);
657 }
658
659 #if !defined (HAVE_TM_ZONE)
660 if (have_zone)
661 {
662 restorezone (velts[10], oldenv, FUNC_NAME);
663 SCM_ALLOW_INTS;
664 }
665 #endif
666 }
667
668 result = scm_mem2string (tbuf + 1, len - 1);
669 free (tbuf);
670 free (myfmt);
671 return result;
672 }
673 #undef FUNC_NAME
674
675 #ifdef HAVE_STRPTIME
676 SCM_DEFINE (scm_strptime, "strptime", 2, 0, 0,
677 (SCM format, SCM string),
678 "Performs the reverse action to @code{strftime}, parsing\n"
679 "@var{string} according to the specification supplied in\n"
680 "@var{template}. The interpretation of month and day names is\n"
681 "dependent on the current locale. The value returned is a pair.\n"
682 "The car has an object with time components\n"
683 "in the form returned by @code{localtime} or @code{gmtime},\n"
684 "but the time zone components\n"
685 "are not usefully set.\n"
686 "The cdr reports the number of characters from @var{string}\n"
687 "which were used for the conversion.")
688 #define FUNC_NAME s_scm_strptime
689 {
690 struct tm t;
691 char *fmt, *str, *rest;
692
693 SCM_VALIDATE_STRING (1, format);
694 SCM_VALIDATE_STRING (2, string);
695
696 fmt = SCM_STRING_CHARS (format);
697 str = SCM_STRING_CHARS (string);
698
699 /* initialize the struct tm */
700 #define tm_init(field) t.field = 0
701 tm_init (tm_sec);
702 tm_init (tm_min);
703 tm_init (tm_hour);
704 tm_init (tm_mday);
705 tm_init (tm_mon);
706 tm_init (tm_year);
707 tm_init (tm_wday);
708 tm_init (tm_yday);
709 #undef tm_init
710
711 /* GNU glibc strptime() "%s" is affected by the current timezone, since it
712 reads a UTC time_t value and converts with localtime_r() to set the tm
713 fields, hence the use of SCM_DEFER_INTS. */
714 t.tm_isdst = -1;
715 SCM_DEFER_INTS;
716 if ((rest = strptime (str, fmt, &t)) == NULL)
717 {
718 /* POSIX doesn't say strptime sets errno, and on glibc 2.3.2 for
719 instance it doesn't. Force a sensible value for our error
720 message. */
721 errno = EINVAL;
722 SCM_SYSERROR;
723 }
724
725 SCM_ALLOW_INTS;
726 return scm_cons (filltime (&t, 0, NULL),
727 scm_from_signed_integer (rest - str));
728 }
729 #undef FUNC_NAME
730 #endif /* HAVE_STRPTIME */
731
732 void
733 scm_init_stime()
734 {
735 scm_c_define ("internal-time-units-per-second",
736 scm_from_long (SCM_TIME_UNITS_PER_SECOND));
737
738 #ifdef HAVE_FTIME
739 if (!scm_your_base.time) ftime(&scm_your_base);
740 #else
741 if (!scm_your_base) time(&scm_your_base);
742 #endif
743
744 if (!scm_my_base) scm_my_base = mytime();
745
746 scm_add_feature ("current-time");
747 #include "libguile/stime.x"
748 }
749
750
751 /*
752 Local Variables:
753 c-file-style: "gnu"
754 End:
755 */