diff options
author | Andy Wingo <wingo@pobox.com> | 2015-10-25 10:36:25 +0000 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2015-10-25 10:43:26 +0000 |
commit | e676e48047b6c2ff7a1a60a541e6e0c92212353f (patch) | |
tree | d08a1ec48a82e5ad2f79775ac2526a6398185187 /libguile | |
parent | f63093c80179f4a0d1ff7b00ccf7d813f43b37dd (diff) | |
download | guile-wip-stime.tar.gz |
Adapt stime.c to gnulib updateswip-stime
* libguile/stime.c: Rely on gnulib to provide time.h and strptime.
(timet): Remove this internal define; replaced with time_t.
(scm_from_struct_tm): Rename from filltime. Take the zone to set as
an SCM.
(scm_to_timezone, scm_struct_tm_zone_name): New helpers.
(scm_to_struct_tm_and_timezone): Rename from bdtime2c and parse out a
timezone_t as well.
(scm_localtime): Use localtime_rz to avoid having to call tzset.
(scm_gmtime): Use gmtime_r.
(scm_mktime): Use mktime_z.
(scm_strftime): Use the timezone_t argument to nstrftime. Use
nstrftime with a NULL buffer to measure how big of a buffer to
allocate.
(scm_strptime): Use scm_from_struct_tm.
Diffstat (limited to 'libguile')
-rw-r--r-- | libguile/stime.c | 496 |
1 files changed, 167 insertions, 329 deletions
diff --git a/libguile/stime.c b/libguile/stime.c index f656d886c..999f9ba88 100644 --- a/libguile/stime.c +++ b/libguile/stime.c @@ -20,26 +20,6 @@ -/* _POSIX_C_SOURCE is not defined always, because it causes problems on some - systems, notably - - - FreeBSD loses all BSD and XOPEN defines. - - glibc loses some things like CLK_TCK. - - On MINGW it conflicts with the pthread headers. - - But on HP-UX _POSIX_C_SOURCE is needed, as noted, for gmtime_r. - - Perhaps a configure test could figure out what _POSIX_C_SOURCE gives and - what it takes away, and decide from that whether to use it, instead of - hard coding __hpux. */ - -#ifndef _REENTRANT -# define _REENTRANT /* ask solaris for gmtime_r prototype */ -#endif -#ifdef __hpux -#define _POSIX_C_SOURCE 199506L /* for gmtime_r prototype */ -#endif - #ifdef HAVE_CONFIG_H # include <config.h> #endif @@ -47,44 +27,29 @@ #include <stdio.h> #include <errno.h> #include <strftime.h> +#include <string.h> +#include <sys/times.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> #include <unistr.h> +#ifdef HAVE_SYS_TIMEB_H +# include <sys/timeb.h> +#endif + #include "libguile/_scm.h" #include "libguile/async.h" #include "libguile/feature.h" #include "libguile/strings.h" #include "libguile/vectors.h" -#include "libguile/dynwind.h" #include "libguile/strings.h" #include "libguile/validate.h" #include "libguile/stime.h" -#include <unistd.h> -#ifdef HAVE_CLOCK_GETTIME -# include <time.h> -#endif - -#include <sys/types.h> -#include <string.h> -#include <sys/times.h> - -#ifdef HAVE_SYS_TIMEB_H -# include <sys/timeb.h> -#endif - -#if ! HAVE_DECL_STRPTIME -extern char *strptime (); -#endif - -#ifdef __STDC__ -# define timet time_t -#else -# define timet long -#endif - #if SCM_SIZEOF_LONG >= 8 && defined HAVE_CLOCK_GETTIME /* Nanoseconds on 64-bit systems with POSIX timers. */ @@ -172,7 +137,7 @@ get_internal_run_time_times (void) * TIME_UNITS_PER_SECOND / ticks_per_second; } -static timet fallback_real_time_base; +static time_t fallback_real_time_base; static long get_internal_real_time_fallback (void) { @@ -273,7 +238,7 @@ SCM_DEFINE (scm_current_time, "current-time", 0, 0, 0, "excluding leap seconds.") #define FUNC_NAME s_scm_current_time { - timet timv; + time_t timv; SCM_CRITICAL_SECTION_START; timv = time (NULL); @@ -301,7 +266,7 @@ SCM_DEFINE (scm_gettimeofday, "gettimeofday", 0, 0, 0, return scm_cons (scm_from_long (time.tv_sec), scm_from_long (time.tv_usec)); #else - timet t = time (NULL); + time_t t = time (NULL); if (errno) SCM_SYSERROR; else @@ -311,68 +276,89 @@ SCM_DEFINE (scm_gettimeofday, "gettimeofday", 0, 0, 0, #undef FUNC_NAME static SCM -filltime (struct tm *bd_time, int zoff, const char *zname) +scm_from_struct_tm (struct tm *tm, int zoff, SCM zone) { SCM result = scm_c_make_vector (11, SCM_UNDEFINED); - SCM_SIMPLE_VECTOR_SET (result,0, scm_from_int (bd_time->tm_sec)); - SCM_SIMPLE_VECTOR_SET (result,1, scm_from_int (bd_time->tm_min)); - SCM_SIMPLE_VECTOR_SET (result,2, scm_from_int (bd_time->tm_hour)); - SCM_SIMPLE_VECTOR_SET (result,3, scm_from_int (bd_time->tm_mday)); - SCM_SIMPLE_VECTOR_SET (result,4, scm_from_int (bd_time->tm_mon)); - SCM_SIMPLE_VECTOR_SET (result,5, scm_from_int (bd_time->tm_year)); - SCM_SIMPLE_VECTOR_SET (result,6, scm_from_int (bd_time->tm_wday)); - SCM_SIMPLE_VECTOR_SET (result,7, scm_from_int (bd_time->tm_yday)); - SCM_SIMPLE_VECTOR_SET (result,8, scm_from_int (bd_time->tm_isdst)); - SCM_SIMPLE_VECTOR_SET (result,9, scm_from_int (zoff)); - SCM_SIMPLE_VECTOR_SET (result,10, (zname - ? scm_from_locale_string (zname) - : SCM_BOOL_F)); + SCM_SIMPLE_VECTOR_SET (result, 0, scm_from_int (tm->tm_sec)); + SCM_SIMPLE_VECTOR_SET (result, 1, scm_from_int (tm->tm_min)); + SCM_SIMPLE_VECTOR_SET (result, 2, scm_from_int (tm->tm_hour)); + SCM_SIMPLE_VECTOR_SET (result, 3, scm_from_int (tm->tm_mday)); + SCM_SIMPLE_VECTOR_SET (result, 4, scm_from_int (tm->tm_mon)); + SCM_SIMPLE_VECTOR_SET (result, 5, scm_from_int (tm->tm_year)); + SCM_SIMPLE_VECTOR_SET (result, 6, scm_from_int (tm->tm_wday)); + SCM_SIMPLE_VECTOR_SET (result, 7, scm_from_int (tm->tm_yday)); + SCM_SIMPLE_VECTOR_SET (result, 8, scm_from_int (tm->tm_isdst)); + SCM_SIMPLE_VECTOR_SET (result, 9, scm_from_int (zoff)); + SCM_SIMPLE_VECTOR_SET (result, 10, zone); + return result; } -static char tzvar[3] = "TZ"; - -/* if zone is set, create a temporary environment with only a TZ - string. other threads or interrupt handlers shouldn't be allowed - to run until the corresponding restorezone is called. hence the use - of a static variable for tmpenv is no big deal. */ -static char ** -setzone (SCM zone, int pos, const char *subr) +static timezone_t +scm_to_timezone (SCM zone, const char *FUNC_NAME) { - char **oldenv = 0; + timezone_t tz; - if (!SCM_UNBNDP (zone)) + if (SCM_UNBNDP (zone)) + /* A NULL argument to tzalloc requests UTC. */ + tz = tzalloc (getenv ("TZ")); + else { - static char *tmpenv[2]; - char *buf; - size_t zone_len; - - zone_len = scm_to_locale_stringbuf (zone, NULL, 0); - buf = scm_malloc (zone_len + sizeof (tzvar) + 1); - strcpy (buf, tzvar); - buf[sizeof(tzvar)-1] = '='; - scm_to_locale_stringbuf (zone, buf+sizeof(tzvar), zone_len); - buf[sizeof(tzvar)+zone_len] = '\0'; - oldenv = environ; - tmpenv[0] = buf; - tmpenv[1] = 0; - environ = tmpenv; + char *zone_str = scm_to_locale_string (zone); + tz = tzalloc (zone_str); + free (zone_str); } - return oldenv; + + if (!tz) + SCM_SYSERROR; + + return tz; +} + +static SCM +scm_struct_tm_zone_name (struct tm *tm) +{ +#if defined HAVE_STRUCT_TM_TM_ZONE + return scm_from_locale_string (tm->tm_zone); +#elif defined HAVE_TZNAME + return scm_from_locale_string (tzname[ (tm->tm_isdst == 1) ? 1 : 0 ]); +#else + return SCM_BOOL_F; +#endif } +/* copy time components from a Scheme object to a struct tm. */ static void -restorezone (SCM zone, char **oldenv, const char *subr SCM_UNUSED) +scm_to_struct_tm_and_timezone (SCM sbd_time, struct tm *tm, timezone_t *tz, + int pos, const char *subr) { - if (!SCM_UNBNDP (zone)) - { - free (environ[0]); - environ = oldenv; -#ifdef HAVE_TZSET - /* for the possible benefit of user code linked with libguile. */ - tzset(); + SCM_ASSERT (scm_is_vector (sbd_time) + && SCM_SIMPLE_VECTOR_LENGTH (sbd_time) == 11, + sbd_time, pos, subr); + + tm->tm_sec = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 0)); + tm->tm_min = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 1)); + tm->tm_hour = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 2)); + tm->tm_mday = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 3)); + tm->tm_mon = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 4)); + tm->tm_year = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 5)); + tm->tm_wday = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 6)); + tm->tm_yday = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 7)); + tm->tm_isdst = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 8)); +#if HAVE_STRUCT_TM_TM_GMTOFF + tm->tm_gmtoff = - scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 9)); +#endif +#ifdef HAVE_STRUCT_TM_TM_ZONE + tm->tm_zone = ""; #endif + + if (tz) + { + SCM zone = SCM_SIMPLE_VECTOR_REF (sbd_time, 10); + /* If the time zone is false, default to the current TZ. */ + *tz = scm_to_timezone (scm_is_true (zone) ? zone : SCM_UNDEFINED, + subr); } } @@ -385,84 +371,47 @@ SCM_DEFINE (scm_localtime, "localtime", 1, 1, 0, "@code{TZ} environment variable or the system default is used.") #define FUNC_NAME s_scm_localtime { - timet itime; - struct tm *ltptr, lt, *utc; - SCM result; + time_t itime; + struct tm lt, utc; + timezone_t tz; + SCM zone_name, result; int zoff; - char *zname = 0; - char **oldenv; - int err; itime = SCM_NUM2LONG (1, time); - /* deferring interupts is essential since a) setzone may install a temporary - environment b) localtime uses a static buffer. */ - SCM_CRITICAL_SECTION_START; - oldenv = setzone (zone, SCM_ARG2, FUNC_NAME); -#ifdef LOCALTIME_CACHE - tzset (); -#endif - /* POSIX says localtime sets errno, but C99 doesn't say that. - Give a sensible default value in case localtime doesn't set it. */ - errno = EINVAL; - ltptr = localtime (&itime); - err = errno; - if (ltptr) + tz = scm_to_timezone (zone, FUNC_NAME); + if (!localtime_rz (tz, &itime, <)) { - const char *ptr; - - /* copy zone name before calling gmtime or restoring zone. */ -#if defined (HAVE_TM_ZONE) - ptr = ltptr->tm_zone; -#elif defined (HAVE_TZNAME) - ptr = tzname[ (ltptr->tm_isdst == 1) ? 1 : 0 ]; -#else - ptr = ""; -#endif - zname = scm_malloc (strlen (ptr) + 1); - strcpy (zname, ptr); + int saved_errno = errno; + tzfree (tz); + errno = saved_errno; + SCM_SYSERROR; } - /* the struct is copied in case localtime and gmtime share a buffer. */ - if (ltptr) - lt = *ltptr; - /* POSIX says gmtime sets errno, but C99 doesn't say that. - Give a sensible default value in case gmtime doesn't set it. */ - errno = EINVAL; - utc = gmtime (&itime); - if (utc == NULL) - err = errno; - restorezone (zone, oldenv, FUNC_NAME); - /* delayed until zone has been restored. */ - errno = err; - if (utc == NULL || ltptr == NULL) + + zone_name = scm_struct_tm_zone_name (<); + tzfree (tz); + + if (!gmtime_r (&itime, &utc)) SCM_SYSERROR; /* calculate timezone offset in seconds west of UTC. */ - zoff = (utc->tm_hour - lt.tm_hour) * 3600 + (utc->tm_min - lt.tm_min) * 60 - + utc->tm_sec - lt.tm_sec; - if (utc->tm_year < lt.tm_year) + zoff = (utc.tm_hour - lt.tm_hour) * 3600 + (utc.tm_min - lt.tm_min) * 60 + + utc.tm_sec - lt.tm_sec; + if (utc.tm_year < lt.tm_year) zoff -= 24 * 60 * 60; - else if (utc->tm_year > lt.tm_year) + else if (utc.tm_year > lt.tm_year) zoff += 24 * 60 * 60; - else if (utc->tm_yday < lt.tm_yday) + else if (utc.tm_yday < lt.tm_yday) zoff -= 24 * 60 * 60; - else if (utc->tm_yday > lt.tm_yday) + else if (utc.tm_yday > lt.tm_yday) zoff += 24 * 60 * 60; - result = filltime (<, zoff, zname); - SCM_CRITICAL_SECTION_END; + result = scm_from_struct_tm (<, zoff, zone_name); - free (zname); return result; } #undef FUNC_NAME -/* tm_zone is normally a pointer, not an array within struct tm, so we might - have to worry about the lifespan of what it points to. The posix specs - don't seem to say anything about this, let's assume here that tm_zone - will be a constant and therefore no protection or anything is needed - until we copy it in filltime(). */ - SCM_DEFINE (scm_gmtime, "gmtime", 1, 0, 0, (SCM time), "Return an object representing the broken down components of\n" @@ -470,64 +419,22 @@ SCM_DEFINE (scm_gmtime, "gmtime", 1, 0, 0, "@code{current-time}. The values are calculated for UTC.") #define FUNC_NAME s_scm_gmtime { - timet itime; - struct tm bd_buf, *bd_time; - const char *zname; + time_t itime; + struct tm utc; + SCM zone_name; itime = SCM_NUM2LONG (1, time); - /* POSIX says gmtime sets errno, but C99 doesn't say that. - Give a sensible default value in case gmtime doesn't set it. */ - errno = EINVAL; - -#if HAVE_GMTIME_R - bd_time = gmtime_r (&itime, &bd_buf); -#else - SCM_CRITICAL_SECTION_START; - bd_time = gmtime (&itime); - if (bd_time != NULL) - bd_buf = *bd_time; - SCM_CRITICAL_SECTION_END; -#endif - if (bd_time == NULL) + if (!gmtime_r (&itime, &utc)) SCM_SYSERROR; -#if HAVE_STRUCT_TM_TM_ZONE - zname = bd_buf.tm_zone; -#else - zname = "GMT"; -#endif - return filltime (&bd_buf, 0, zname); -} -#undef FUNC_NAME - -/* copy time components from a Scheme object to a struct tm. */ -static void -bdtime2c (SCM sbd_time, struct tm *lt, int pos, const char *subr) -{ - SCM_ASSERT (scm_is_vector (sbd_time) - && SCM_SIMPLE_VECTOR_LENGTH (sbd_time) == 11, - sbd_time, pos, subr); + zone_name = scm_struct_tm_zone_name (&utc); + if (scm_is_false (zone_name)) + zone_name = scm_from_latin1_string ("GMT"); - lt->tm_sec = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 0)); - lt->tm_min = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 1)); - lt->tm_hour = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 2)); - lt->tm_mday = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 3)); - lt->tm_mon = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 4)); - lt->tm_year = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 5)); - lt->tm_wday = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 6)); - lt->tm_yday = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 7)); - lt->tm_isdst = scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 8)); -#if HAVE_STRUCT_TM_TM_GMTOFF - lt->tm_gmtoff = - scm_to_int (SCM_SIMPLE_VECTOR_REF (sbd_time, 9)); -#endif -#ifdef HAVE_TM_ZONE - if (scm_is_false (SCM_SIMPLE_VECTOR_REF (sbd_time, 10))) - lt->tm_zone = NULL; - else - lt->tm_zone = scm_to_locale_string (SCM_SIMPLE_VECTOR_REF (sbd_time, 10)); -#endif + return scm_from_struct_tm (&utc, 0, zone_name); } +#undef FUNC_NAME SCM_DEFINE (scm_mktime, "mktime", 1, 1, 0, (SCM sbd_time, SCM zone), @@ -541,78 +448,46 @@ SCM_DEFINE (scm_mktime, "mktime", 1, 1, 0, "normalized values.") #define FUNC_NAME s_scm_mktime { - timet itime; - struct tm lt, *utc; - SCM result; + time_t itime; + struct tm lt, utc; + timezone_t tz; + SCM zone_name, result; int zoff; - char *zname = 0; - char **oldenv; - int err; - scm_dynwind_begin (0); + scm_to_struct_tm_and_timezone (sbd_time, <, NULL, SCM_ARG1, FUNC_NAME); + tz = scm_to_timezone (zone, FUNC_NAME); - bdtime2c (sbd_time, <, SCM_ARG1, FUNC_NAME); -#if HAVE_STRUCT_TM_TM_ZONE - scm_dynwind_free ((char *)lt.tm_zone); -#endif - - scm_dynwind_critical_section (SCM_BOOL_F); - - oldenv = setzone (zone, SCM_ARG2, FUNC_NAME); -#ifdef LOCALTIME_CACHE - tzset (); -#endif - itime = mktime (<); - /* POSIX doesn't say mktime sets errno, and on glibc 2.3.2 for instance it - doesn't. Force a sensible value for our error message. */ - err = EINVAL; - - if (itime != -1) + itime = mktime_z (tz, <); + if (itime == -1) { - const char *ptr; - - /* copy zone name before calling gmtime or restoring the zone. */ -#if defined (HAVE_TM_ZONE) - ptr = lt.tm_zone; -#elif defined (HAVE_TZNAME) - ptr = tzname[ (lt.tm_isdst == 1) ? 1 : 0 ]; -#else - ptr = ""; -#endif - zname = scm_malloc (strlen (ptr) + 1); - strcpy (zname, ptr); + int errno_save = errno; + tzfree (tz); + errno = errno_save; + SCM_SYSERROR; } + zone_name = scm_struct_tm_zone_name (<); + tzfree (tz); + /* get timezone offset in seconds west of UTC. */ - /* POSIX says gmtime sets errno, but C99 doesn't say that. - Give a sensible default value in case gmtime doesn't set it. */ errno = EINVAL; - utc = gmtime (&itime); - if (utc == NULL) - err = errno; - - restorezone (zone, oldenv, FUNC_NAME); - /* delayed until zone has been restored. */ - errno = err; - if (utc == NULL || itime == -1) + if (!gmtime_r (&itime, &utc)) SCM_SYSERROR; - zoff = (utc->tm_hour - lt.tm_hour) * 3600 + (utc->tm_min - lt.tm_min) * 60 - + utc->tm_sec - lt.tm_sec; - if (utc->tm_year < lt.tm_year) + zoff = (utc.tm_hour - lt.tm_hour) * 3600 + (utc.tm_min - lt.tm_min) * 60 + + utc.tm_sec - lt.tm_sec; + if (utc.tm_year < lt.tm_year) zoff -= 24 * 60 * 60; - else if (utc->tm_year > lt.tm_year) + else if (utc.tm_year > lt.tm_year) zoff += 24 * 60 * 60; - else if (utc->tm_yday < lt.tm_yday) + else if (utc.tm_yday < lt.tm_yday) zoff -= 24 * 60 * 60; - else if (utc->tm_yday > lt.tm_yday) + else if (utc.tm_yday > lt.tm_yday) zoff += 24 * 60 * 60; result = scm_cons (scm_from_long (itime), - filltime (<, zoff, zname)); - free (zname); + scm_from_struct_tm (<, zoff, zone_name)); - scm_dynwind_end (); return result; } #undef FUNC_NAME @@ -653,88 +528,51 @@ SCM_DEFINE (scm_strftime, "strftime", 2, 0, 0, #define FUNC_NAME s_scm_strftime { struct tm t; - - char *tbuf; - int size = 50; + timezone_t tz; char *fmt; - char *myfmt; - size_t len; + size_t size, written; SCM result; SCM_VALIDATE_STRING (1, format); - bdtime2c (stime, &t, SCM_ARG2, FUNC_NAME); + scm_to_struct_tm_and_timezone (stime, &t, &tz, SCM_ARG2, FUNC_NAME); - /* Convert string to UTF-8 so that non-ASCII characters in the - format are passed through unchanged. */ - fmt = scm_to_utf8_stringn (format, &len); - - /* Ugly hack: strftime can return 0 if its buffer is too small, - but some valid time strings (e.g. "%p") can sometimes produce - a zero-byte output string! Workaround is to prepend a junk - character to the format string, so that valid returns are always - nonzero. */ - myfmt = scm_malloc (len+2); - *myfmt = (scm_t_uint8) 'x'; - strncpy (myfmt + 1, fmt, len); - myfmt[len + 1] = 0; - scm_remember_upto_here_1 (format); - free (fmt); - - tbuf = scm_malloc (size); + /* Sadly, Gnulib's nstrftime can't or won't extract the zone name from + the timezone_t, so we have to make sure the tm_zone is set as + well. */ +#ifdef HAVE_STRUCT_TM_TM_ZONE { -#if !defined (HAVE_TM_ZONE) - /* it seems the only way to tell non-GNU versions of strftime what - zone to use (for the %Z format) is to set TZ in the - environment. interrupts and thread switching must be deferred - until TZ is restored. */ - char **oldenv = NULL; - SCM zone_spec = SCM_SIMPLE_VECTOR_REF (stime, 10); - int have_zone = 0; - - if (scm_is_true (zone_spec) && scm_c_string_length (zone_spec) > 0) - { - /* it's not required that the TZ setting be correct, just that - it has the right name. so try something like TZ=EST0. - using only TZ=EST would be simpler but it doesn't work on - some OSs, e.g., Solaris. */ - SCM zone = - scm_string_append (scm_list_2 (zone_spec, - scm_from_locale_string ("0"))); - - have_zone = 1; - SCM_CRITICAL_SECTION_START; - oldenv = setzone (zone, SCM_ARG2, FUNC_NAME); - } + SCM zone = SCM_SIMPLE_VECTOR_REF (stime, 10); + t.tm_zone = scm_is_true (zone) ? scm_to_locale_string (zone) : NULL; + } #endif -#ifdef LOCALTIME_CACHE - tzset (); -#endif + /* Convert string to UTF-8 so that non-ASCII characters in the + format are passed through unchanged. */ + fmt = scm_to_utf8_string (format); - /* Use `nstrftime ()' from Gnulib, which supports all GNU extensions - supported by glibc. */ - while ((len = nstrftime (tbuf, size, myfmt, &t, 0, 0)) == 0) - { - free (tbuf); - size *= 2; - tbuf = scm_malloc (size); - } - -#if !defined (HAVE_TM_ZONE) - if (have_zone) - { - restorezone (zone_spec, oldenv, FUNC_NAME); - SCM_CRITICAL_SECTION_END; - } -#endif + /* Use `nstrftime ()' from Gnulib, which supports all GNU extensions + supported by glibc. The first call is to compute how many bytes + are needed in the buffer; the second actually writes them into the + buffer. */ + size = nstrftime (NULL, (size_t)-1, fmt, &t, NULL, 0); + if (size) + { + char *buf = scm_malloc (size + 1); + written = nstrftime (buf, size + 1, fmt, &t, NULL, 0); + if (written != size) + abort (); + result = scm_from_utf8_string (buf); + free (buf); } + else + result = scm_from_latin1_string (""); - result = scm_from_utf8_string (tbuf + 1); - free (tbuf); - free (myfmt); -#if HAVE_STRUCT_TM_TM_ZONE + tzfree (tz); + free (fmt); +#ifdef HAVE_STRUCT_TM_TM_ZONE free ((char *) t.tm_zone); #endif + return result; } #undef FUNC_NAME @@ -815,7 +653,7 @@ SCM_DEFINE (scm_strptime, "strptime", 2, 0, 0, free (str); free (fmt); - return scm_cons (filltime (&t, zoff, NULL), + return scm_cons (scm_from_struct_tm (&t, zoff, SCM_BOOL_F), scm_from_signed_integer (used_len)); } #undef FUNC_NAME |