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

Reply via email to