Module Name: src Committed By: christos Date: Thu Dec 16 18:38:07 UTC 2010
Modified Files: src/lib/libc: shlib_version src/lib/libc/compat/include: time.h src/lib/libc/include: namespace.h src/lib/libc/time: Makefile.inc ctime.3 localtime.c offtime.3 strftime.3 strftime.c time2posix.3 Log Message: Provide a re-entrant and thread-safe set of timezone API's that don't require locking and can operate on user-specified timezones as opposed to having to alter the environment to change a timezone. This work was presented to the tzcode folks and it was generally accepted, but there seems to be a lot of inertia. To generate a diff of this commit: cvs rdiff -u -r1.219 -r1.220 src/lib/libc/shlib_version cvs rdiff -u -r1.2 -r1.3 src/lib/libc/compat/include/time.h cvs rdiff -u -r1.145 -r1.146 src/lib/libc/include/namespace.h cvs rdiff -u -r1.13 -r1.14 src/lib/libc/time/Makefile.inc cvs rdiff -u -r1.35 -r1.36 src/lib/libc/time/ctime.3 cvs rdiff -u -r1.48 -r1.49 src/lib/libc/time/localtime.c cvs rdiff -u -r1.1 -r1.2 src/lib/libc/time/offtime.3 cvs rdiff -u -r1.26 -r1.27 src/lib/libc/time/strftime.3 cvs rdiff -u -r1.20 -r1.21 src/lib/libc/time/strftime.c cvs rdiff -u -r1.15 -r1.16 src/lib/libc/time/time2posix.3 Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libc/shlib_version diff -u src/lib/libc/shlib_version:1.219 src/lib/libc/shlib_version:1.220 --- src/lib/libc/shlib_version:1.219 Fri Sep 24 05:21:53 2010 +++ src/lib/libc/shlib_version Thu Dec 16 13:38:06 2010 @@ -1,4 +1,4 @@ -# $NetBSD: shlib_version,v 1.219 2010/09/24 09:21:53 tnozaki Exp $ +# $NetBSD: shlib_version,v 1.220 2010/12/16 18:38:06 christos Exp $ # Remember to update distrib/sets/lists/base/shl.* when changing # # things we wish to do on next major version bump: @@ -31,4 +31,4 @@ # it's insufficient bitwidth to implement all ctype class. # see isblank's comment in ctype.h. major=12 -minor=174 +minor=175 Index: src/lib/libc/compat/include/time.h diff -u src/lib/libc/compat/include/time.h:1.2 src/lib/libc/compat/include/time.h:1.3 --- src/lib/libc/compat/include/time.h:1.2 Sat Jan 10 21:46:25 2009 +++ src/lib/libc/compat/include/time.h Thu Dec 16 13:38:06 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: time.h,v 1.2 2009/01/11 02:46:25 christos Exp $ */ +/* $NetBSD: time.h,v 1.3 2010/12/16 18:38:06 christos Exp $ */ /* * Copyright (c) 1989, 1993 @@ -86,9 +86,21 @@ struct tm *gmtime_r(const int32_t * __restrict, struct tm * __restrict); struct tm *localtime_r(const int32_t * __restrict, struct tm * __restrict); struct tm *offtime(const int32_t *, long); +struct tm *offtime_r(const int32_t *, long, struct tm *); int32_t timelocal(struct tm *); int32_t timegm(struct tm *); int32_t timeoff(struct tm *, long); int32_t time2posix(int32_t); int32_t posix2time(int32_t); +struct tm *localtime_rz(const timezone_t, const int32_t * __restrict, + struct tm * __restrict); +char *ctime_rz(const timezone_t, const int32_t *, char *); +int32_t mktime_z(const timezone_t, struct tm *); +int32_t timelocal_z(const timezone_t, struct tm *); +int32_t time2posix_z(const timezone_t, int32_t); +int32_t posix2time_z(const timezone_t, int32_t); +timezone_t tzalloc(const char *); +void tzfree(const timezone_t); +const char *tzgetname(const timezone_t, int); + #endif /* !_COMPAT_TIME_H_ */ Index: src/lib/libc/include/namespace.h diff -u src/lib/libc/include/namespace.h:1.145 src/lib/libc/include/namespace.h:1.146 --- src/lib/libc/include/namespace.h:1.145 Wed Nov 17 08:19:32 2010 +++ src/lib/libc/include/namespace.h Thu Dec 16 13:38:06 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: namespace.h,v 1.145 2010/11/17 13:19:32 tron Exp $ */ +/* $NetBSD: namespace.h,v 1.146 2010/12/16 18:38:06 christos Exp $ */ /*- * Copyright (c) 1997-2004 The NetBSD Foundation, Inc. @@ -221,6 +221,7 @@ #define csetexpandtc _csetexpandtc #define ctermid _ctermid #define ctime_r _ctime_r +#define ctime_rz _ctime_rz #define daemon _daemon #define dbopen _dbopen #define devname _devname @@ -432,12 +433,14 @@ #define llabs _llabs #define lldiv _lldiv #define localtime_r _localtime_r +#define localtime_rz _localtime_rz #define lockf _lockf #define lrand48 _lrand48 #define lseek _lseek #define mergesort _mergesort #define mi_vector_hash _mi_vector_hash #define mkstemp _mkstemp +#define mktime_z _mktime_z #define mmap _mmap #define mpool_close _mpool_close #define mpool_filter _mpool_filter @@ -474,6 +477,7 @@ #define pollts _pollts #define popen _popen #define posix2time _posix2time +#define posix2time_z _posix2time_z #define pread _pread #define pselect _pselect #define psignal _psignal @@ -579,6 +583,7 @@ #define strcasecmp _strcasecmp #define strdup _strdup #define stresep _stresep +#define strftime_z _strftime_z #define strndup _strndup #define strncasecmp _strncasecmp #define strptime _strptime Index: src/lib/libc/time/Makefile.inc diff -u src/lib/libc/time/Makefile.inc:1.13 src/lib/libc/time/Makefile.inc:1.14 --- src/lib/libc/time/Makefile.inc:1.13 Thu May 14 22:23:42 2009 +++ src/lib/libc/time/Makefile.inc Thu Dec 16 13:38:07 2010 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.inc,v 1.13 2009/05/15 02:23:42 jakllsch Exp $ +# $NetBSD: Makefile.inc,v 1.14 2010/12/16 18:38:07 christos Exp $ .PATH: ${.CURDIR}/time @@ -9,6 +9,7 @@ CPPFLAGS+=-DALL_STATE -DUSG_COMPAT MLINKS+=ctime.3 ctime_r.3 \ + ctime.3 ctime_rz.3 \ ctime.3 asctime.3 \ ctime.3 asctime_r.3 \ ctime.3 difftime.3 \ @@ -16,10 +17,17 @@ ctime.3 gmtime_r.3 \ ctime.3 localtime.3 \ ctime.3 localtime_r.3 \ + ctime.3 localtime_rz.3 \ ctime.3 mktime.3 \ + ctime.3 mktime_z.3 \ getdate.3 getdate_err.3 \ + offtime.3 offtime_r.3 \ offtime.3 timeoff.3 \ offtime.3 timegm.3 \ offtime.3 timelocal.3 \ + time2posix.3 posix2time.3 \ + time2posix.3 posix2time_z.3 \ + time2posix.3 time2posix_z.3 \ tzset.3 daylight.3 \ - tzset.3 tzsetwall.3 + tzset.3 tzsetwall.3 \ + strftime.3 strftime_z.3 Index: src/lib/libc/time/ctime.3 diff -u src/lib/libc/time/ctime.3:1.35 src/lib/libc/time/ctime.3:1.36 --- src/lib/libc/time/ctime.3:1.35 Thu Dec 9 04:22:31 2010 +++ src/lib/libc/time/ctime.3 Thu Dec 16 13:38:07 2010 @@ -1,5 +1,5 @@ -.\" $NetBSD: ctime.3,v 1.35 2010/12/09 09:22:31 njoly Exp $ -.Dd October 27, 2010 +.\" $NetBSD: ctime.3,v 1.36 2010/12/16 18:38:07 christos Exp $ +.Dd December 14, 2010 .Dt CTIME 3 .Os .Sh NAME @@ -7,22 +7,30 @@ .Nm asctime_r , .Nm ctime , .Nm ctime_r , +.Nm ctime_rz , .Nm difftime , .Nm gmtime , .Nm gmtime_r , .Nm localtime , .Nm localtime_r , -.Nm mktime +.Nm localtime_rz , +.Nm mktime , +.Nm mktime_z , +.Nm tzalloc , +.Nm tzgetname , +.Nm tzfree , .Nd convert date and time to ASCII .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In time.h -.Vt extern char *tzname[2]; +.Dv extern char *tzname[2]; .Ft char * .Fn ctime "const time_t *clock" .Ft char * .Fn ctime_r "const time_t *clock" "char *buf" +.Ft char * +.Fn ctime_rz "const timezone_t tz" "const time_t *clock" "char *buf" .Ft double .Fn difftime "time_t time1" "time_t time0" .Ft char * @@ -34,15 +42,25 @@ .Ft struct tm * .Fn localtime_r "const time_t * restrict clock" "struct tm * restrict result" .Ft struct tm * +.Fn localtime_rz "const timezone_t tz" "const time_t * restrict clock" "struct tm * restrict result" +.Ft struct tm * .Fn gmtime "const time_t *clock" .Ft struct tm * .Fn gmtime_r "const time_t * restrict clock" "struct tm * restrict result" .Ft time_t .Fn mktime "struct tm *tm" +.Ft time_t +.Fn mktime_z "const timezone_t tz" "struct tm *tm" +.Ft timezone_t +.Fn tzalloc "const char *zone" +.Ft const char * +.Fn tzgetname "const timezone_t tz" "int isdst" +.Ft void +.Fn tzfree "const timezone_t tz" .Sh DESCRIPTION .Fn ctime -converts a -.Vt time_t , +converts a +.Tp time_t , pointed to by .Fa clock , representing the time in seconds since @@ -61,11 +79,19 @@ .Fn ctime_r is similar to .Fn ctime , -except it places the result of the conversion on the +except it places the result of the convertion on the .Fa buf argument which should be 26 or more bytes long, instead of using a global static buffer. .Pp +.Fn ctime_rz +is similar to +.Fn ctime_r , +but it also takes a +.Ft "const timezone_t" +argument, returned by a previous call to +.Fn tzalloc . +.Pp .Fn localtime and .Fn gmtime @@ -107,10 +133,17 @@ the application may need to do so by calling .Xr tzset 3 . .Pp +.Fn localtime_rz +is similar to +.Fn localtime_r , +but it also takes a +.Ft "const timezone_t" +argument, returned by a previous call to +.Fn tzalloc . +.Pp .Fn asctime converts a time value contained in a -.Dq tm -structure to a string, +``tm'' structure to a string, as shown in the above example, and returns a pointer to the string. .Pp @@ -163,11 +196,60 @@ represented, it returns .Va "(time_t)-1" . .Pp +.Fn mktime_z +is similar to +.Fn mktime +but it also takes a +.Ft "const timezone_t" +argument, returned by a previous call to +.Fn tzalloc . +.Pp .Fn difftime returns the difference between two calendar times, .Fa ( time1 No - Fa time0 ) , expressed in seconds. .Pp +.Fn tzalloc +takes as an argument a timezone name and returns a +.Ft timezone_t +object suitable to be used in +.Fn ctime_rz , +.Fn localtime_rz , +and +.Fn mktime_z . +Instead of setting the environment variable +.Va TZ , +and globally changing the behavior of the calling program, one can use +multiple timezones at the same time by using separate +.Ft timezone_t +objects allocated by +.Fn tzalloc +and calling the +.Dq z +variants of the functions. +.Pp +.Fn tzgetname +returns the name for the given +.Fa tz . +If +.Fa isdst +is +.Va 0 , +the call is equivalent to +.Va tzname[0] . +If +.Fa isdst +is set to +.Va 1 +the call is equivalent to +.Va tzname[1] . +.Pp +.Fn tzfree +frees the +.Fa tz +argument previously returned by +.Fa tzalloc . +.Pp The structure (of type) .Va "struct tm" includes the following fields: @@ -194,6 +276,17 @@ created. There is no guarantee that these fields will continue to exist in this form in future releases of this code. +The +.Fa tm_zone +field will become invalid and point to freed storage if the corresponding +.Va "struct tm" +was returned by +.Fn localtime_rz +and the +.Ft "const timezone_t" +.Fa tz +argument has been freed by +.Fn tzfree . .Pp .Fa tm_isdst is non-zero if summer time is in effect. @@ -208,9 +301,10 @@ and .Fn ctime functions return a pointer to a static character buffer, and the -.Fn asctime_r +.Fn asctime_r , +.Fn ctime_r , and -.Fn ctime_r +.Fn ctime_rz function return a pointer to the user-supplied buffer. On failure they all return .Dv NULL @@ -222,9 +316,10 @@ functions return a pointer to a statically allocated .Va "struct tm" whereas the -.Fn gmtime_r +.Fn gmtime_r , +.Fn localtime_r , and -.Fn localtime_r +.Fn localtime_rz , functions return a pointer to the user-supplied .Va "struct tm" . On failure they all return @@ -234,16 +329,32 @@ is set to indicate the error. The .Fn mktime +and +.Fn mktime_z function returns the specified time since the Epoch as a -.Vt time_t +.Va time_t type value. If the time cannot be represented, then .Fn mktime -returns +and +.Fn mktime_z +return .Va "(time_t)-1" setting the global variable .Va errno to indicate the error. +The +.Fn tzalloc +function returns a pointer to a +.Ft timezone_t +object or +.Dv NULL +on failure, setting +.Va errno +to indicate the error. +.Fn tzgetzone +function returns string containing the name of the timezone given in +.Fa tz . .Sh FILES .Bl -tag -width /usr/share/zoneinfo/posixrules -compact .It Pa /etc/localtime @@ -264,15 +375,27 @@ The .Fn gmtime_r , .Fn localtime_r , +.Fn localtime_rz , .Fn gmtime , .Fn localtime , and -.Fn mktime +.Fn mktime , +and +.Fn mktime_z will fail when: .Bl -tag -width Er .It Bq Er EOVERFLOW The result cannot be represented. +.It Bq Er EINVAL +The result cannot be represented. .El +.Pp +All functions that return values except their +.Dq z +variants, can also return the same errors as +.Xr open 2 +and +.Xr malloc 3 . .Sh SEE ALSO .Xr getenv 3 , .Xr strftime 3 , Index: src/lib/libc/time/localtime.c diff -u src/lib/libc/time/localtime.c:1.48 src/lib/libc/time/localtime.c:1.49 --- src/lib/libc/time/localtime.c:1.48 Tue Mar 23 16:28:58 2010 +++ src/lib/libc/time/localtime.c Thu Dec 16 13:38:07 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: localtime.c,v 1.48 2010/03/23 20:28:58 drochner Exp $ */ +/* $NetBSD: localtime.c,v 1.49 2010/12/16 18:38:07 christos Exp $ */ /* ** This file is in the public domain, so clarified as of @@ -10,7 +10,7 @@ #if 0 static char elsieid[] = "@(#)localtime.c 8.9"; #else -__RCSID("$NetBSD: localtime.c,v 1.48 2010/03/23 20:28:58 drochner Exp $"); +__RCSID("$NetBSD: localtime.c,v 1.49 2010/12/16 18:38:07 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -28,7 +28,14 @@ #include "reentrant.h" #if defined(__weak_alias) +__weak_alias(ctime_r,_ctime_r) +__weak_alias(ctime_rz,_ctime_rz) __weak_alias(daylight,_daylight) +__weak_alias(mktime_z,_mktime_z) +__weak_alias(localtime_r,_localtime_r) +__weak_alias(localtime_rz,_localtime_rz) +__weak_alias(posix2time,_posix2time) +__weak_alias(posix2time_z,_posix2time_z) __weak_alias(tzname,_tzname) #endif @@ -83,7 +90,7 @@ static const char wildabbr[] = WILDABBR; -static const char gmt[] = "GMT"; +static char gmt[] = "GMT"; /* ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES. @@ -118,7 +125,7 @@ #define MY_TZNAME_MAX 255 #endif /* !defined TZNAME_MAX */ -struct state { +struct __state { int leapcnt; int timecnt; int typecnt; @@ -145,6 +152,9 @@ #define DAY_OF_YEAR 1 /* n - day of year */ #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ +typedef struct tm *(*subfun_t)(const timezone_t sp, const time_t *timep, + long offset, struct tm *tmp); + /* ** Prototypes for static functions. */ @@ -159,11 +169,11 @@ static const char * getsecs(const char * strp, long * secsp); static const char * getoffset(const char * strp, long * offsetp); static const char * getrule(const char * strp, struct rule * rulep); -static void gmtload(struct state * sp); -static struct tm * gmtsub(const time_t * timep, long offset, - struct tm * tmp); -static struct tm * localsub(const time_t * timep, long offset, - struct tm * tmp); +static void gmtload(timezone_t sp); +static struct tm * gmtsub(const timezone_t sp, const time_t *timep, + long offset, struct tm * tmp); +static struct tm * localsub(const timezone_t sp, const time_t *timep, + long offset, struct tm *tmp); static int increment_overflow(int * number, int delta); static int leaps_thru_end_of(int y); static int long_increment_overflow(long * number, int delta); @@ -172,44 +182,31 @@ static int normalize_overflow(int * tensptr, int * unitsptr, int base); static void settzname(void); -static time_t time1(struct tm * tmp, - struct tm * (*funcp)(const time_t *, - long, struct tm *), - long offset); -static time_t time2(struct tm *tmp, - struct tm * (*funcp)(const time_t *, - long, struct tm*), - long offset, int * okayp); -static time_t time2sub(struct tm *tmp, - struct tm * (*funcp)(const time_t *, - long, struct tm*), - long offset, int * okayp, int do_norm_secs); -static struct tm * timesub(const time_t * timep, long offset, - const struct state * sp, struct tm * tmp); +static time_t time1(const timezone_t sp, struct tm * const tmp, + subfun_t funcp, long offset); +static time_t time2(const timezone_t sp, struct tm * const tmp, + subfun_t funcp, + const long offset, int *const okayp); +static time_t time2sub(const timezone_t sp, struct tm * consttmp, + subfun_t funcp, const long offset, + int *const okayp, const int do_norm_secs); +static struct tm * timesub(const timezone_t sp, const time_t * timep, + long offset, struct tm * tmp); static int tmcomp(const struct tm * atmp, const struct tm * btmp); static time_t transtime(time_t janfirst, int year, const struct rule * rulep, long offset); -static int typesequiv(const struct state * sp, int a, int b); -static int tzload(const char * name, struct state * sp, +static int typesequiv(const timezone_t sp, int a, int b); +static int tzload(timezone_t sp, const char * name, int doextend); -static int tzparse(const char * name, struct state * sp, +static int tzparse(timezone_t sp, const char * name, int lastditch); static void tzset_unlocked(void); static void tzsetwall_unlocked(void); -static long leapcorr(time_t * timep); +static long leapcorr(const timezone_t sp, time_t * timep); -#ifdef ALL_STATE -static struct state * lclptr; -static struct state * gmtptr; -#endif /* defined ALL_STATE */ - -#ifndef ALL_STATE -static struct state lclmem; -static struct state gmtmem; -#define lclptr (&lclmem) -#define gmtptr (&gmtmem) -#endif /* State Farm */ +static timezone_t lclptr; +static timezone_t gmtptr; #ifndef TZ_STRLEN_MAX #define TZ_STRLEN_MAX 255 @@ -261,11 +258,10 @@ #endif /* defined ALTZONE */ static long -detzcode(codep) -const char * const codep; +detzcode(const char *const codep) { - register long result; - register int i; + long result; + int i; result = (codep[0] & 0x80) ? ~0L : 0; for (i = 0; i < 4; ++i) @@ -274,11 +270,10 @@ } static time_t -detzcode64(codep) -const char * const codep; +detzcode64(const char *const codep) { - register time_t result; - register int i; + time_t result; + int i; result = (codep[0] & 0x80) ? -1 : 0; for (i = 0; i < 8; ++i) @@ -286,11 +281,49 @@ return result; } +const char * +tzgetname(const timezone_t sp, int isdst) +{ + int i; + for (i = 0; i < sp->timecnt; ++i) { + const struct ttinfo *const ttisp = &sp->ttis[sp->types[i]]; + + if (ttisp->tt_isdst == isdst) + return &sp->chars[ttisp->tt_abbrind]; + } + return NULL; +} + +static void +settzname_z(timezone_t sp) +{ + int i; + + /* + ** Scrub the abbreviations. + ** First, replace bogus characters. + */ + for (i = 0; i < sp->charcnt; ++i) + if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL) + sp->chars[i] = TZ_ABBR_ERR_CHAR; + /* + ** Second, truncate long abbreviations. + */ + for (i = 0; i < sp->typecnt; ++i) { + const struct ttinfo * const ttisp = &sp->ttis[i]; + char * cp = &sp->chars[ttisp->tt_abbrind]; + + if (strlen(cp) > TZ_ABBR_MAX_LEN && + strcmp(cp, GRANDPARENTED) != 0) + *(cp + TZ_ABBR_MAX_LEN) = '\0'; + } +} + static void settzname(void) { - register struct state * const sp = lclptr; - register int i; + timezone_t const sp = lclptr; + int i; tzname[0] = (__aconst char *)__UNCONST(wildabbr); tzname[1] = (__aconst char *)__UNCONST(wildabbr); @@ -301,14 +334,12 @@ #ifdef ALTZONE altzone = 0; #endif /* defined ALTZONE */ -#ifdef ALL_STATE if (sp == NULL) { tzname[0] = tzname[1] = (__aconst char *)__UNCONST(gmt); return; } -#endif /* defined ALL_STATE */ for (i = 0; i < sp->typecnt; ++i) { - register const struct ttinfo * const ttisp = &sp->ttis[i]; + const struct ttinfo * const ttisp = &sp->ttis[i]; tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind]; @@ -334,30 +365,11 @@ tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind]; } - /* - ** Finally, scrub the abbreviations. - ** First, replace bogus characters. - */ - for (i = 0; i < sp->charcnt; ++i) - if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL) - sp->chars[i] = TZ_ABBR_ERR_CHAR; - /* - ** Second, truncate long abbreviations. - */ - for (i = 0; i < sp->typecnt; ++i) { - register const struct ttinfo * const ttisp = &sp->ttis[i]; - register char * cp = &sp->chars[ttisp->tt_abbrind]; - - if (strlen(cp) > TZ_ABBR_MAX_LEN && - strcmp(cp, GRANDPARENTED) != 0) - *(cp + TZ_ABBR_MAX_LEN) = '\0'; - } + settzname_z(sp); } static int -differ_by_repeat(t1, t0) -const time_t t1; -const time_t t0; +differ_by_repeat(const time_t t1, const time_t t0) { /* CONSTCOND */ if (TYPE_INTEGRAL(time_t) && @@ -367,16 +379,13 @@ } static int -tzload(name, sp, doextend) -register const char * name; -register struct state * const sp; -register const int doextend; -{ - register const char * p; - register int i; - register int fid; - register int stored; - register int nread; +tzload(timezone_t sp, const char *name, const int doextend) +{ + const char * p; + int i; + int fid; + int stored; + int nread; union { struct tzhead tzhead; char buf[2 * sizeof(struct tzhead) + @@ -388,7 +397,7 @@ if (name == NULL && (name = TZDEFAULT) == NULL) return -1; { - register int doaccess; + int doaccess; /* ** Section 4.9.1 of the C standard says that ** "FILENAME_MAX expands to an integral constant expression @@ -468,7 +477,7 @@ return -1; } for (i = 0; i < sp->typecnt; ++i) { - register struct ttinfo * ttisp; + struct ttinfo * ttisp; ttisp = &sp->ttis[i]; ttisp->tt_gmtoff = detzcode(p); @@ -485,7 +494,7 @@ sp->chars[i] = *p++; sp->chars[i] = '\0'; /* ensure '\0' at end */ for (i = 0; i < sp->leapcnt; ++i) { - register struct lsinfo * lsisp; + struct lsinfo * lsisp; lsisp = &sp->lsis[i]; lsisp->ls_trans = (stored == 4) ? @@ -495,7 +504,7 @@ p += 4; } for (i = 0; i < sp->typecnt; ++i) { - register struct ttinfo * ttisp; + struct ttinfo * ttisp; ttisp = &sp->ttis[i]; if (ttisstdcnt == 0) @@ -508,7 +517,7 @@ } } for (i = 0; i < sp->typecnt; ++i) { - register struct ttinfo * ttisp; + struct ttinfo * ttisp; ttisp = &sp->ttis[i]; if (ttisgmtcnt == 0) @@ -538,7 +547,7 @@ /* ** Ignore the beginning (harder). */ - register int j; + int j; for (j = 0; j + i < sp->timecnt; ++j) { sp->ats[j] = sp->ats[j + i]; @@ -567,11 +576,11 @@ if (doextend && nread > 2 && u.buf[0] == '\n' && u.buf[nread - 1] == '\n' && sp->typecnt + 2 <= TZ_MAX_TYPES) { - struct state ts; - register int result; + struct __state ts; + int result; u.buf[nread - 1] = '\0'; - result = tzparse(&u.buf[1], &ts, FALSE); + result = tzparse(&ts, &u.buf[1], FALSE); if (result == 0 && ts.typecnt == 2 && sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) { for (i = 0; i < 2; ++i) @@ -619,20 +628,17 @@ } static int -typesequiv(sp, a, b) -const struct state * const sp; -const int a; -const int b; +typesequiv(const timezone_t sp, const int a, const int b) { - register int result; + int result; if (sp == NULL || a < 0 || a >= sp->typecnt || b < 0 || b >= sp->typecnt) result = FALSE; else { - register const struct ttinfo * ap = &sp->ttis[a]; - register const struct ttinfo * bp = &sp->ttis[b]; + const struct ttinfo * ap = &sp->ttis[a]; + const struct ttinfo * bp = &sp->ttis[b]; result = ap->tt_gmtoff == bp->tt_gmtoff && ap->tt_isdst == bp->tt_isdst && ap->tt_ttisstd == bp->tt_ttisstd && @@ -660,9 +666,9 @@ static const char * getzname(strp) -register const char * strp; +const char * strp; { - register char c; + char c; while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && c != '+') @@ -680,9 +686,9 @@ */ static const char * -getqzname(register const char *strp, const int delim) +getqzname(const char *strp, const int delim) { - register int c; + int c; while ((c = *strp) != '\0' && c != delim) ++strp; @@ -698,13 +704,13 @@ static const char * getnum(strp, nump, min, max) -register const char * strp; +const char * strp; int * const nump; const int min; const int max; { - register char c; - register int num; + char c; + int num; if (strp == NULL || !is_digit(c = *strp)) { errno = EINVAL; @@ -736,9 +742,7 @@ */ static const char * -getsecs(strp, secsp) -register const char * strp; -long * const secsp; +getsecs(const char *strp, long *const secsp) { int num; @@ -778,11 +782,9 @@ */ static const char * -getoffset(strp, offsetp) -register const char * strp; -long * const offsetp; +getoffset(const char *strp, long *const offsetp) { - register int neg = 0; + int neg = 0; if (*strp == '-') { neg = 1; @@ -805,9 +807,7 @@ */ static const char * -getrule(strp, rulep) -const char * strp; -register struct rule * const rulep; +getrule(const char *strp, struct rule *const rulep) { if (*strp == 'J') { /* @@ -859,15 +859,12 @@ */ static time_t -transtime(janfirst, year, rulep, offset) -const time_t janfirst; -const int year; -register const struct rule * const rulep; -const long offset; -{ - register int leapyear; - register time_t value; - register int i; +transtime(const time_t janfirst, const int year, const struct rule *const rulep, + const long offset) +{ + int leapyear; + time_t value; + int i; int d, m1, yy0, yy1, yy2, dow; INITIALIZE(value); @@ -954,10 +951,7 @@ */ static int -tzparse(name, sp, lastditch) -const char * name; -register struct state * const sp; -const int lastditch; +tzparse(timezone_t sp, const char *name, const int lastditch) { const char * stdname; const char * dstname; @@ -965,10 +959,10 @@ size_t dstlen; long stdoffset; long dstoffset; - register time_t * atp; - register unsigned char * typep; - register char * cp; - register int load_result; + time_t * atp; + unsigned char * typep; + char * cp; + int load_result; INITIALIZE(dstname); stdname = name; @@ -997,7 +991,7 @@ if (name == NULL) return -1; } - load_result = tzload(TZDEFRULES, sp, FALSE); + load_result = tzload(sp, TZDEFRULES, FALSE); if (load_result != 0) sp->leapcnt = 0; /* so, we're off a little */ if (*name != '\0') { @@ -1023,8 +1017,8 @@ if (*name == ',' || *name == ';') { struct rule start; struct rule end; - register int year; - register time_t janfirst; + int year; + time_t janfirst; time_t starttime; time_t endtime; @@ -1080,12 +1074,12 @@ janfirst = newfirst; } } else { - register long theirstdoffset; - register long theirdstoffset; - register long theiroffset; - register int isdst; - register int i; - register int j; + long theirstdoffset; + long theirdstoffset; + long theiroffset; + int isdst; + int i; + int j; if (*name != '\0') return -1; @@ -1189,11 +1183,30 @@ } static void -gmtload(sp) -struct state * const sp; +gmtload(timezone_t sp) +{ + if (tzload(sp, gmt, TRUE) != 0) + (void) tzparse(sp, gmt, TRUE); +} + +timezone_t +tzalloc(const char *name) +{ + timezone_t sp = calloc(1, sizeof *sp); + if (sp == NULL) + return NULL; + if (tzload(sp, name, TRUE) != 0) { + free(sp); + return NULL; + } + settzname_z(sp); + return sp; +} + +void +tzfree(const timezone_t sp) { - if (tzload(gmt, sp, TRUE) != 0) - (void) tzparse(gmt, sp, TRUE); + free(sp); } static void @@ -1203,7 +1216,6 @@ return; lcl_is_set = -1; -#ifdef ALL_STATE if (lclptr == NULL) { int saveerrno = errno; lclptr = calloc(1, sizeof *lclptr); @@ -1213,8 +1225,7 @@ return; } } -#endif /* defined ALL_STATE */ - if (tzload((char *) NULL, lclptr, TRUE) != 0) + if (tzload(lclptr, NULL, TRUE) != 0) gmtload(lclptr); settzname(); } @@ -1244,7 +1255,7 @@ void tzset_unlocked(void) { - register const char * name; + const char * name; int saveerrno; saveerrno = errno; @@ -1261,7 +1272,6 @@ if (lcl_is_set) (void)strlcpy(lcl_TZname, name, sizeof(lcl_TZname)); -#ifdef ALL_STATE if (lclptr == NULL) { saveerrno = errno; lclptr = calloc(1, sizeof *lclptr); @@ -1271,7 +1281,6 @@ return; } } -#endif /* defined ALL_STATE */ if (*name == '\0') { /* ** User wants it fast rather than right. @@ -1283,8 +1292,8 @@ lclptr->ttis[0].tt_gmtoff = 0; lclptr->ttis[0].tt_abbrind = 0; (void) strlcpy(lclptr->chars, gmt, sizeof(lclptr->chars)); - } else if (tzload(name, lclptr, TRUE) != 0) - if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) + } else if (tzload(lclptr, name, TRUE) != 0) + if (name[0] == ':' || tzparse(lclptr, name, FALSE) != 0) (void) gmtload(lclptr); settzname(); } @@ -1308,28 +1317,20 @@ /*ARGSUSED*/ static struct tm * -localsub(timep, offset, tmp) -const time_t * const timep; -const long offset; -struct tm * const tmp; -{ - register struct state * sp; - register const struct ttinfo * ttisp; - register int i; - register struct tm * result; +localsub(const timezone_t sp, const time_t * const timep, const long offset, + struct tm *const tmp) +{ + const struct ttinfo * ttisp; + int i; + struct tm * result; const time_t t = *timep; - sp = lclptr; -#ifdef ALL_STATE - if (sp == NULL) - return gmtsub(timep, offset, tmp); -#endif /* defined ALL_STATE */ if ((sp->goback && t < sp->ats[0]) || (sp->goahead && t > sp->ats[sp->timecnt - 1])) { time_t newt = t; - register time_t seconds; - register time_t tcycles; - register int_fast64_t icycles; + time_t seconds; + time_t tcycles; + int_fast64_t icycles; if (t < sp->ats[0]) seconds = sp->ats[0] - t; @@ -1351,9 +1352,9 @@ errno = EOVERFLOW; return NULL; /* "cannot happen" */ } - result = localsub(&newt, offset, tmp); + result = localsub(sp, &newt, offset, tmp); if (result == tmp) { - register time_t newy; + time_t newy; newy = tmp->tm_year; if (t < sp->ats[0]) @@ -1375,11 +1376,11 @@ break; } } else { - register int lo = 1; - register int hi = sp->timecnt; + int lo = 1; + int hi = sp->timecnt; while (lo < hi) { - register int mid = (lo + hi) / 2; + int mid = (lo + hi) / 2; if (t < sp->ats[mid]) hi = mid; @@ -1394,7 +1395,7 @@ ** t += ttisp->tt_gmtoff; ** timesub(&t, 0L, sp, tmp); */ - result = timesub(&t, ttisp->tt_gmtoff, sp, tmp); + result = timesub(sp, &t, ttisp->tt_gmtoff, tmp); tmp->tm_isdst = ttisp->tt_isdst; tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; #ifdef TM_ZONE @@ -1403,35 +1404,34 @@ return result; } -struct tm * -localtime(timep) -const time_t * const timep; -{ - struct tm *result; - - rwlock_wrlock(&lcl_lock); - tzset_unlocked(); - result = localsub(timep, 0L, &tm); - rwlock_unlock(&lcl_lock); - return result; -} - /* ** Re-entrant version of localtime. */ struct tm * -localtime_r(timep, tmp) -const time_t * const timep; -struct tm * tmp; +localtime_r(const time_t * __restrict timep, struct tm *tmp) { - struct tm *result; - + rwlock_rdlock(&lcl_lock); rwlock_rdlock(&lcl_lock); tzset_unlocked(); - result = localsub(timep, 0L, tmp); + tmp = localtime_rz(lclptr, timep, tmp); rwlock_unlock(&lcl_lock); - return result; + return tmp; +} + +struct tm * +localtime(const time_t *const timep) +{ + return localtime_r(timep, &tm); +} + +struct tm * +localtime_rz(const timezone_t sp, const time_t * __restrict timep, struct tm *tmp) +{ + if (sp == NULL) + return gmtsub(NULL, timep, 0L, tmp); + else + return localsub(sp, timep, 0L, tmp); } /* @@ -1439,32 +1439,26 @@ */ static struct tm * -gmtsub(timep, offset, tmp) -const time_t * const timep; -const long offset; -struct tm * const tmp; +gmtsub(const timezone_t sp, const time_t * const timep, const long offset, + struct tm *const tmp) { - register struct tm * result; + struct tm * result; #ifdef _REENTRANT static mutex_t gmt_mutex = MUTEX_INITIALIZER; #endif mutex_lock(&gmt_mutex); if (!gmt_is_set) { -#ifdef ALL_STATE int saveerrno; -#endif gmt_is_set = TRUE; -#ifdef ALL_STATE saveerrno = errno; gmtptr = calloc(1, sizeof *gmtptr); errno = saveerrno; if (gmtptr != NULL) -#endif /* defined ALL_STATE */ gmtload(gmtptr); } mutex_unlock(&gmt_mutex); - result = timesub(timep, offset, gmtptr, tmp); + result = timesub(gmtptr, timep, offset, tmp); #ifdef TM_ZONE /* ** Could get fancy here and deliver something such as @@ -1474,24 +1468,18 @@ if (offset != 0) tmp->TM_ZONE = (__aconst char *)__UNCONST(wildabbr); else { -#ifdef ALL_STATE if (gmtptr == NULL) tmp->TM_ZONE = (__aconst char *)__UNCONST(gmt); else tmp->TM_ZONE = gmtptr->chars; -#endif /* defined ALL_STATE */ -#ifndef ALL_STATE - tmp->TM_ZONE = gmtptr->chars; -#endif /* State Farm */ } #endif /* defined TM_ZONE */ return result; } struct tm * -gmtime(timep) -const time_t * const timep; +gmtime(const time_t *const timep) { - return gmtsub(timep, 0L, &tm); + return gmtsub(NULL, timep, 0L, &tm); } /* @@ -1499,21 +1487,23 @@ */ struct tm * -gmtime_r(timep, tmp) -const time_t * const timep; -struct tm * tmp; +gmtime_r(const time_t * const timep, struct tm *tmp) { - return gmtsub(timep, 0L, tmp); + return gmtsub(NULL, timep, 0L, tmp); } #ifdef STD_INSPIRED struct tm * -offtime(timep, offset) -const time_t * const timep; -const long offset; +offtime(const time_t *const timep, long offset) { - return gmtsub(timep, offset, &tm); + return gmtsub(NULL, timep, offset, &tm); +} + +struct tm * +offtime_r(const time_t *timep, long offset, struct tm *tmp) +{ + return gmtsub(NULL, timep, offset, tmp); } #endif /* defined STD_INSPIRED */ @@ -1524,38 +1514,29 @@ */ static int -leaps_thru_end_of(y) -register const int y; +leaps_thru_end_of(const int y) { return (y >= 0) ? (y / 4 - y / 100 + y / 400) : -(leaps_thru_end_of(-(y + 1)) + 1); } static struct tm * -timesub(timep, offset, sp, tmp) -const time_t * const timep; -const long offset; -register const struct state * const sp; -register struct tm * const tmp; -{ - register const struct lsinfo * lp; - register time_t tdays; - register int idays; /* unsigned would be so 2003 */ - register long rem; - int y; - register const int * ip; - register long corr; - register int hit; - register int i; +timesub(const timezone_t sp, const time_t *const timep, const long offset, + struct tm *const tmp) +{ + const struct lsinfo * lp; + time_t tdays; + int idays; /* unsigned would be so 2003 */ + long rem; + int y; + const int * ip; + long corr; + int hit; + int i; corr = 0; hit = 0; -#ifdef ALL_STATE i = (sp == NULL) ? 0 : sp->leapcnt; -#endif /* defined ALL_STATE */ -#ifndef ALL_STATE - i = sp->leapcnt; -#endif /* State Farm */ while (--i >= 0) { lp = &sp->lsis[i]; if (*timep >= lp->ls_trans) { @@ -1581,9 +1562,9 @@ rem = (long) (*timep - tdays * SECSPERDAY); while (tdays < 0 || tdays >= year_lengths[isleap(y)]) { int newy; - register time_t tdelta; - register int idelta; - register int leapdays; + time_t tdelta; + int idelta; + int leapdays; tdelta = tdays / DAYSPERLYEAR; idelta = (int) tdelta; @@ -1605,7 +1586,7 @@ y = newy; } { - register long seconds; + long seconds; seconds = tdays * SECSPERDAY + 0.5; tdays = seconds / SECSPERDAY; @@ -1676,8 +1657,7 @@ } char * -ctime(timep) -const time_t * const timep; +ctime(const time_t *const timep) { /* ** Section 4.12.3.2 of X3.159-1989 requires that @@ -1692,9 +1672,7 @@ } char * -ctime_r(timep, buf) -const time_t * const timep; -char * buf; +ctime_r(const time_t *const timep, char *buf) { struct tm mytm, *rtm; @@ -1704,6 +1682,17 @@ return asctime_r(rtm, buf); } +char * +ctime_rz(const timezone_t sp, const time_t * timep, char *buf) +{ + struct tm mytm, *rtm; + + rtm = localtime_rz(sp, timep, &mytm); + if (rtm == NULL) + return NULL; + return asctime_r(rtm, buf); +} + /* ** Adapted from code provided by Robert Elz, who writes: ** The "best" way to do mktime I think is based on an idea of Bob @@ -1722,9 +1711,7 @@ */ static int -increment_overflow(number, delta) -int * number; -int delta; +increment_overflow(int *number, int delta) { int number0; @@ -1734,9 +1721,7 @@ } static int -long_increment_overflow(number, delta) -long * number; -int delta; +long_increment_overflow(long *number, int delta) { long number0; @@ -1746,12 +1731,9 @@ } static int -normalize_overflow(tensptr, unitsptr, base) -int * const tensptr; -int * const unitsptr; -const int base; +normalize_overflow(int *const tensptr, int *const unitsptr, const int base) { - register int tensdelta; + int tensdelta; tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : @@ -1761,12 +1743,10 @@ } static int -long_normalize_overflow(tensptr, unitsptr, base) -long * const tensptr; -int * const unitsptr; -const int base; +long_normalize_overflow(long *const tensptr, int *const unitsptr, + const int base) { - register int tensdelta; + int tensdelta; tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : @@ -1776,11 +1756,9 @@ } static int -tmcomp(atmp, btmp) -register const struct tm * const atmp; -register const struct tm * const btmp; +tmcomp(const struct tm *const atmp, const struct tm *const btmp) { - register int result; + int result; if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && @@ -1792,20 +1770,15 @@ } static time_t -time2sub(tmp, funcp, offset, okayp, do_norm_secs) -struct tm * const tmp; -struct tm * (* const funcp)(const time_t*, long, struct tm*); -const long offset; -int * const okayp; -const int do_norm_secs; -{ - register const struct state * sp; - register int dir; - register int i, j; - register int saved_seconds; - register long li; - register time_t lo; - register time_t hi; +time2sub(const timezone_t sp, struct tm *const tmp, subfun_t funcp, + const long offset, int *const okayp, const int do_norm_secs) +{ + int dir; + int i, j; + int saved_seconds; + long li; + time_t lo; + time_t hi; long y; time_t newt; time_t t; @@ -1906,7 +1879,7 @@ t = lo; else if (t > hi) t = hi; - if ((*funcp)(&t, offset, &mytm) == NULL) { + if ((*funcp)(sp, &t, offset, &mytm) == NULL) { /* ** Assume that t is too extreme to be represented in ** a struct tm; arrange things so that it is less @@ -1941,12 +1914,8 @@ ** It's okay to guess wrong since the guess ** gets checked. */ - sp = (const struct state *) - ((funcp == localsub) ? lclptr : gmtptr); -#ifdef ALL_STATE if (sp == NULL) return WRONG; -#endif /* defined ALL_STATE */ for (i = sp->typecnt - 1; i >= 0; --i) { if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) continue; @@ -1955,7 +1924,7 @@ continue; newt = t + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff; - if ((*funcp)(&newt, offset, &mytm) == NULL) + if ((*funcp)(sp, &newt, offset, &mytm) == NULL) continue; if (tmcomp(&mytm, &yourtm) != 0) continue; @@ -1975,17 +1944,14 @@ if ((newt < t) != (saved_seconds < 0)) return WRONG; t = newt; - if ((*funcp)(&t, offset, tmp)) + if ((*funcp)(sp, &t, offset, tmp)) *okayp = TRUE; return t; } static time_t -time2(tmp, funcp, offset, okayp) -struct tm * const tmp; -struct tm * (* const funcp)(const time_t*, long, struct tm*); -const long offset; -int * const okayp; +time2(const timezone_t sp, struct tm *const tmp, subfun_t funcp, + const long offset, int *const okayp) { time_t t; @@ -1994,29 +1960,26 @@ ** (in case tm_sec contains a value associated with a leap second). ** If that fails, try with normalization of seconds. */ - t = time2sub(tmp, funcp, offset, okayp, FALSE); - return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE); + t = time2sub(sp, tmp, funcp, offset, okayp, FALSE); + return *okayp ? t : time2sub(sp, tmp, funcp, offset, okayp, TRUE); } static time_t -time1(tmp, funcp, offset) -struct tm * const tmp; -struct tm * (* const funcp)(const time_t *, long, struct tm *); -const long offset; -{ - register time_t t; - register const struct state * sp; - register int samei, otheri; - register int sameind, otherind; - register int i; - register int nseen; +time1(const timezone_t sp, struct tm *const tmp, subfun_t funcp, + long offset) +{ + time_t t; + int samei, otheri; + int sameind, otherind; + int i; + int nseen; int seen[TZ_MAX_TYPES]; int types[TZ_MAX_TYPES]; int okay; if (tmp->tm_isdst > 1) tmp->tm_isdst = 1; - t = time2(tmp, funcp, offset, &okay); + t = time2(sp, tmp, funcp, offset, &okay); #ifdef PCTS /* ** PCTS code courtesy Grant Sullivan. @@ -2036,11 +1999,8 @@ ** We try to divine the type they started from and adjust to the ** type they need. */ - sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); -#ifdef ALL_STATE if (sp == NULL) return WRONG; -#endif /* defined ALL_STATE */ for (i = 0; i < sp->typecnt; ++i) seen[i] = FALSE; nseen = 0; @@ -2060,7 +2020,7 @@ tmp->tm_sec += (int)(sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff); tmp->tm_isdst = !tmp->tm_isdst; - t = time2(tmp, funcp, offset, &okay); + t = time2(sp, tmp, funcp, offset, &okay); if (okay) return t; tmp->tm_sec -= (int)(sp->ttis[otheri].tt_gmtoff - @@ -2072,43 +2032,55 @@ } time_t -mktime(tmp) -struct tm * const tmp; +mktime_z(const timezone_t sp, struct tm *tmp) +{ + if (sp == NULL) + return time1(NULL, tmp, gmtsub, 0L); + else + return time1(sp, tmp, localsub, 0L); +} + +time_t +mktime(struct tm * const tmp) { time_t result; rwlock_wrlock(&lcl_lock); tzset_unlocked(); - result = time1(tmp, localsub, 0L); + result = mktime_z(lclptr, tmp); rwlock_unlock(&lcl_lock); - return (result); + return result; } #ifdef STD_INSPIRED time_t -timelocal(tmp) -struct tm * const tmp; +timelocal_z(const timezone_t sp, struct tm *tmp) +{ + if (tmp != NULL) + tmp->tm_isdst = -1; /* in case it wasn't initialized */ + return mktime_z(sp, tmp); +} + +time_t +timelocal(struct tm *const tmp) { tmp->tm_isdst = -1; /* in case it wasn't initialized */ return mktime(tmp); } time_t -timegm(tmp) -struct tm * const tmp; +timegm(struct tm *const tmp) { tmp->tm_isdst = 0; - return time1(tmp, gmtsub, 0L); + return time1(gmtptr, tmp, gmtsub, 0L); } time_t -timeoff(tmp, offset) -struct tm * const tmp; -const long offset; +timeoff(struct tm *const tmp, const long offset) { tmp->tm_isdst = 0; - return time1(tmp, gmtsub, offset); + return time1(gmtptr, tmp, gmtsub, offset); } #endif /* defined STD_INSPIRED */ @@ -2121,10 +2093,9 @@ */ long -gtime(tmp) -struct tm * const tmp; +gtime(struct tm *const tmp) { - const time_t t = mktime(tmp); + const time_t t = mktime(tmp); if (t == WRONG) return -1; @@ -2148,14 +2119,11 @@ */ static long -leapcorr(timep) -time_t * timep; +leapcorr(const timezone_t sp, time_t *timep) { - register struct state * sp; - register struct lsinfo * lp; - register int i; + struct lsinfo * lp; + int i; - sp = lclptr; i = sp->leapcnt; while (--i >= 0) { lp = &sp->lsis[i]; @@ -2166,56 +2134,68 @@ } time_t -time2posix(t) -time_t t; +time2posix_z(const timezone_t sp, time_t t) { - time_t result; + return t - leapcorr(sp, &t); +} +time_t +time2posix(time_t t) +{ + time_t result; rwlock_wrlock(&lcl_lock); tzset_unlocked(); - result = t - leapcorr(&t); + result = t - leapcorr(lclptr, &t); rwlock_unlock(&lcl_lock); return (result); } time_t -posix2time(t) -time_t t; +posix2time_z(const timezone_t sp, time_t t) { time_t x; time_t y; - rwlock_wrlock(&lcl_lock); - tzset_unlocked(); /* ** For a positive leap second hit, the result ** is not unique. For a negative leap second ** hit, the corresponding time doesn't exist, ** so we return an adjacent second. */ - x = t + leapcorr(&t); - y = x - leapcorr(&x); + x = t + leapcorr(sp, &t); + y = x - leapcorr(sp, &x); if (y < t) { do { x++; - y = x - leapcorr(&x); + y = x - leapcorr(sp, &x); } while (y < t); if (t != y) { - rwlock_unlock(&lcl_lock); return x - 1; } } else if (y > t) { do { --x; - y = x - leapcorr(&x); + y = x - leapcorr(sp, &x); } while (y > t); if (t != y) { - rwlock_unlock(&lcl_lock); return x + 1; } } - rwlock_unlock(&lcl_lock); return x; } + + +time_t +posix2time(time_t t) +{ + time_t result; + + rwlock_wrlock(&lcl_lock); + tzset_unlocked(); + result = posix2time_z(lclptr, t); + rwlock_unlock(&lcl_lock); + return result; +} + #endif /* defined STD_INSPIRED */ Index: src/lib/libc/time/offtime.3 diff -u src/lib/libc/time/offtime.3:1.1 src/lib/libc/time/offtime.3:1.2 --- src/lib/libc/time/offtime.3:1.1 Sun May 9 22:02:00 2004 +++ src/lib/libc/time/offtime.3 Thu Dec 16 13:38:07 2010 @@ -1,7 +1,7 @@ -.\" $NetBSD: offtime.3,v 1.1 2004/05/10 02:02:00 kleink Exp $ +.\" $NetBSD: offtime.3,v 1.2 2010/12/16 18:38:07 christos Exp $ .\" Written by Klaus Klein, May 10, 2004. .\" Public domain. -.Dd May 10, 2004 +.Dd December 14, 2010 .Dt OFFTIME 3 .Os .Sh NAME @@ -16,6 +16,8 @@ .In time.h .Ft struct tm * .Fn offtime "const time_t * clock" "long int offset" +.Ft struct tm * +.Fn offtime_r "const time_t * clock" "long int offset" "struct tm *ret" .Ft time_t .Fn timeoff "struct tm * tm" "long int offset" .Ft time_t @@ -33,6 +35,15 @@ seconds, into broken-down time, expressed as Coordinated Universal Time (UTC). .Pp +.Fn offtime_r +is similar to +.Fn offtime +but it places the returned +.Ft "struct tm *" +in the user supplied +.Fa ret +argument. +.Pp .Fn timeoff converts the broken-down time .Fa tm , Index: src/lib/libc/time/strftime.3 diff -u src/lib/libc/time/strftime.3:1.26 src/lib/libc/time/strftime.3:1.27 --- src/lib/libc/time/strftime.3:1.26 Sat May 29 16:32:18 2010 +++ src/lib/libc/time/strftime.3 Thu Dec 16 13:38:07 2010 @@ -30,13 +30,14 @@ .\" SUCH DAMAGE. .\" .\" from: @(#)strftime.3 5.12 (Berkeley) 6/29/91 -.\" $NetBSD: strftime.3,v 1.26 2010/05/29 20:32:18 dholland Exp $ +.\" $NetBSD: strftime.3,v 1.27 2010/12/16 18:38:07 christos Exp $ .\" -.Dd May 29, 2010 +.Dd December 14, 2010 .Dt STRFTIME 3 .Os .Sh NAME -.Nm strftime +.Nm strftime , +.Nm strftime_z .Nd format date and time .Sh LIBRARY .Lb libc @@ -44,6 +45,8 @@ .In time.h .Ft size_t .Fn strftime "char * restrict buf" "size_t maxsize" "const char * restrict format" "const struct tm * restrict timeptr" +.Ft size_t +.Fn strftime_z "const timezone_t tz" "char * restrict buf" "size_t maxsize" "const char * restrict format" "const struct tm * restrict timeptr" .Sh DESCRIPTION The .Fn strftime @@ -193,6 +196,15 @@ is replaced by .Ql % . .El +.Pp +The +.Fn strftime_z +function is similar to +.Fn strftime , +but it also takes a +.Ft "const timezone_t" +.Fa tz +argument. .Sh SEE ALSO .Xr date 1 , .Xr printf 1 , Index: src/lib/libc/time/strftime.c diff -u src/lib/libc/time/strftime.c:1.20 src/lib/libc/time/strftime.c:1.21 --- src/lib/libc/time/strftime.c:1.20 Thu Dec 31 17:49:16 2009 +++ src/lib/libc/time/strftime.c Thu Dec 16 13:38:07 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: strftime.c,v 1.20 2009/12/31 22:49:16 mlelstv Exp $ */ +/* $NetBSD: strftime.c,v 1.21 2010/12/16 18:38:07 christos Exp $ */ #include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) @@ -6,7 +6,7 @@ static char elsieid[] = "@(#)strftime.c 7.64"; static char elsieid[] = "@(#)strftime.c 8.3"; #else -__RCSID("$NetBSD: strftime.c,v 1.20 2009/12/31 22:49:16 mlelstv Exp $"); +__RCSID("$NetBSD: strftime.c,v 1.21 2010/12/16 18:38:07 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -73,14 +73,18 @@ #include "fcntl.h" #include "locale.h" +#ifdef __weak_alias +__weak_alias(strftime_z, _strftime_z) +#endif + #include "sys/localedef.h" #define Locale _CurrentTimeLocale #define c_fmt d_t_fmt static char * _add(const char *, char *, const char *); static char * _conv(int, const char *, char *, const char *); -static char * _fmt(const char *, const struct tm *, char *, const char *, - int *); +static char * _fmt(const timezone_t, const char *, const struct tm *, char *, + const char *, int *); static char * _yconv(int, int, int, int, char *, const char *); extern char * tzname[]; @@ -95,18 +99,15 @@ #define IN_ALL 3 size_t -strftime(s, maxsize, format, t) -char * const s; -const size_t maxsize; -const char * const format; -const struct tm * const t; +strftime_z(const timezone_t sp, char * const s, const size_t maxsize, + const char * const format, const struct tm * const t) { char * p; int warn; - tzset(); warn = IN_NONE; - p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn); + p = _fmt(sp, ((format == NULL) ? "%c" : format), t, s, s + maxsize, + &warn); #ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) { (void) fprintf(stderr, "\n"); @@ -130,12 +131,8 @@ } static char * -_fmt(format, t, pt, ptlim, warnp) -const char * format; -const struct tm * const t; -char * pt; -const char * const ptlim; -int * warnp; +_fmt(const timezone_t sp, const char *format, const struct tm * const t, + char *pt, const char *const ptlim, int *warnp) { for ( ; *format; ++format) { if (*format == '%') { @@ -184,7 +181,7 @@ { int warn2 = IN_SOME; - pt = _fmt(Locale->c_fmt, t, pt, ptlim, &warn2); + pt = _fmt(sp, Locale->c_fmt, t, pt, ptlim, &warn2); if (warn2 == IN_ALL) warn2 = IN_THIS; if (warn2 > *warnp) @@ -192,7 +189,7 @@ } continue; case 'D': - pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp); + pt = _fmt(sp, "%m/%d/%y", t, pt, ptlim, warnp); continue; case 'd': pt = _conv(t->tm_mday, "%02d", pt, ptlim); @@ -213,7 +210,7 @@ pt = _conv(t->tm_mday, "%2d", pt, ptlim); continue; case 'F': - pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp); + pt = _fmt(sp, "%Y-%m-%d", t, pt, ptlim, warnp); continue; case 'H': pt = _conv(t->tm_hour, "%02d", pt, ptlim); @@ -277,10 +274,10 @@ pt, ptlim); continue; case 'R': - pt = _fmt("%H:%M", t, pt, ptlim, warnp); + pt = _fmt(sp, "%H:%M", t, pt, ptlim, warnp); continue; case 'r': - pt = _fmt(Locale->t_fmt_ampm, t, pt, ptlim, + pt = _fmt(sp, Locale->t_fmt_ampm, t, pt, ptlim, warnp); continue; case 'S': @@ -306,7 +303,7 @@ } continue; case 'T': - pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp); + pt = _fmt(sp, "%H:%M:%S", t, pt, ptlim, warnp); continue; case 't': pt = _add("\t", pt, ptlim); @@ -421,7 +418,7 @@ ** "date as dd-bbb-YYYY" ** (ado, 1993-05-24) */ - pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp); + pt = _fmt(sp, "%e-%b-%Y", t, pt, ptlim, warnp); continue; case 'W': pt = _conv((t->tm_yday + DAYSPERWEEK - @@ -434,13 +431,13 @@ pt = _conv(t->tm_wday, "%d", pt, ptlim); continue; case 'X': - pt = _fmt(Locale->t_fmt, t, pt, ptlim, warnp); + pt = _fmt(sp, Locale->t_fmt, t, pt, ptlim, warnp); continue; case 'x': { int warn2 = IN_SOME; - pt = _fmt(Locale->d_fmt, t, pt, ptlim, &warn2); + pt = _fmt(sp, Locale->d_fmt, t, pt, ptlim, &warn2); if (warn2 == IN_ALL) warn2 = IN_THIS; if (warn2 > *warnp) @@ -463,8 +460,10 @@ else #endif /* defined TM_ZONE */ if (t->tm_isdst >= 0) - pt = _add(tzname[t->tm_isdst != 0], - pt, ptlim); + pt = _add((sp ? + tzgetname(sp, t->tm_isdst) : + tzname[t->tm_isdst != 0]), + pt, ptlim); /* ** C99 says that %Z must be replaced by the ** empty string if the time zone is not @@ -556,7 +555,7 @@ continue; #if 0 case '+': - pt = _fmt(Locale->date_fmt, t, pt, ptlim, + pt = _fmt(sp, Locale->date_fmt, t, pt, ptlim, warnp); continue; #endif @@ -577,6 +576,14 @@ return pt; } +size_t +strftime(char * const s, const size_t maxsize, + const char * const format, const struct tm * const t) +{ + tzset(); + return strftime_z(NULL, s, maxsize, format, t); +} + static char * _conv(n, format, pt, ptlim) const int n; Index: src/lib/libc/time/time2posix.3 diff -u src/lib/libc/time/time2posix.3:1.15 src/lib/libc/time/time2posix.3:1.16 --- src/lib/libc/time/time2posix.3:1.15 Thu Dec 31 17:49:16 2009 +++ src/lib/libc/time/time2posix.3 Thu Dec 16 13:38:07 2010 @@ -1,10 +1,12 @@ -.\" $NetBSD: time2posix.3,v 1.15 2009/12/31 22:49:16 mlelstv Exp $ -.Dd April 1, 2001 +.\" $NetBSD: time2posix.3,v 1.16 2010/12/16 18:38:07 christos Exp $ +.Dd December 4, 2010 .Dt TIME2POSIX 3 .Os .Sh NAME .Nm time2posix , -.Nm posix2time +.Nm time2posix_z , +.Nm posix2time , +.Nm posix2time_z , .Nd convert seconds since the Epoch .Sh LIBRARY .Lb libc @@ -13,7 +15,11 @@ .Ft time_t .Fn time2posix "time_t t" .Ft time_t +.Fn time2posix_z "const timezone_t tz" "time_t t" +.Ft time_t .Fn posix2time "time_t t" +.Ft time_t +.Fn posix2time_z "const timezone_t tz" "time_t t" .Sh DESCRIPTION .St -p1003.1 legislates that a @@ -42,7 +48,10 @@ passed-to functions such as .Xr time 3 , .Xr localtime 3 , +.Xr localtime_r 3 , +.Xr localtime_rz 3 , .Xr mktime 3 , +.Xr mktime_z 3 , and .Xr difftime 3 . However, POSIX gives an arithmetic expression for directly computing a @@ -55,9 +64,11 @@ leap seconds correctly. .Pp The -.Fn time2posix -and +.Fn time2posix , +.Fn time2posix_z , .Fn posix2time +and +.Fn posix2time_z functions are provided to address this .Va time_t mismatch by converting between local @@ -69,19 +80,32 @@ older applications, or when communicating with POSIX-compliant systems. .Pp .Fn time2posix -is single-valued. +and +.Fn time2posix_z +are single-valued. That is, every local .Va time_t corresponds to a single POSIX .Va time_t . .Fn posix2time -is less well-behaved: for a positive leap second hit the result is not +and +.Fn posix2time +are less well-behaved: for a positive leap second hit the result is not unique, and for a negative leap second hit the corresponding POSIX .Va time_t doesn't exist so an adjacent value is returned. Both of these are good indicators of the inferiority of the POSIX representation. .Pp +The +.Dq z +variants of the two functions behave exactly like their counterparts, +but they operate in the given +.Fa tz +argument which was previously allocated using +.Xr tzalloc 3 +and are re-entrant. +.Pp The following table summarizes the relationship between a .Va time_t and its conversion to, and back from, the POSIX representation over @@ -115,7 +139,11 @@ .Sh SEE ALSO .Xr difftime 3 , .Xr localtime 3 , +.Xr localtime_r 3 , +.Xr localtime_rz 3 , +.Xr tzalloc 3 , .Xr mktime 3 , +.Xr mktime_z 3 , .Xr time 3 .\" @(#)time2posix.3 7.7 .\" This file is in the public domain, so clarified as of