summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog107
-rw-r--r--Makefile5
-rw-r--r--Makerules9
-rw-r--r--db/Makefile3
-rw-r--r--elf/Makefile5
-rw-r--r--hurd/Makefile2
-rw-r--r--libio/putc_u.c4
-rw-r--r--libio/stdio.h10
-rw-r--r--manual/time.texi96
-rw-r--r--math/Makefile1
-rw-r--r--nss/db-Makefile3
-rw-r--r--resolv/Makefile1
-rw-r--r--stdio-common/vfprintf.c17
-rw-r--r--sysdeps/generic/dl-cache.c86
-rw-r--r--sysdeps/mach/hurd/dl-cache.c24
-rw-r--r--sysdeps/unix/sysv/linux/Dist1
-rw-r--r--sysdeps/unix/sysv/linux/i386/Dist1
-rw-r--r--sysdeps/unix/sysv/linux/m68k/Dist1
-rw-r--r--sysdeps/unix/sysv/linux/m68k/sysdep.S39
-rw-r--r--sysdeps/unix/sysv/linux/m68k/sysdep.h20
-rw-r--r--time/Makefile3
-rw-r--r--time/strftime.c399
-rw-r--r--time/time.h28
-rw-r--r--time/tzfile.c2
-rw-r--r--time/tzset.c2
25 files changed, 679 insertions, 190 deletions
diff --git a/ChangeLog b/ChangeLog
index d6c07a6538..eeeb620359 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,110 @@
+Thu Sep 12 03:35:27 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+	* sysdeps/unix/sysv/linux/i386/Dist: Remove init-first.h.
+	* sysdeps/unix/sysv/linux/m68k/Dist: Likewise.
+	* sysdeps/unix/sysv/linux/Dist: Add init-first.h.
+
+1996-09-11  Paul Eggert  <eggert@twinsun.com>
+
+	* strftime.c (strftime):
+	Handle E and O modifiers, required for POSIX.2 and XPG4.
+	Don't use sprintf to format numbers; this way, we can handle time_t
+	correctly regardless of whether it's signed.
+	Don't dump core if format ends in %.
+	In default %c format, use %e instead of %d, for POSIX.2 compatibility.
+	For %z:
+		Use tm_gmtoff if available.
+		Output nothing if tm_isdst is negative.
+		Output correct value even if arg is 1969-12-31 23:59:59 UTC.
+		Don't assume that UTC offset is less than 24 hours;
+		Posix requires support for 24 hours, and there's no point
+		limiting it at all.
+	(HAVE_TM_GMTOFF, TYPE_SIGNED, INT_STRLEN_BOUND): New macros.
+	(CHAR_BIT): Define if <limits.h> doesn't.
+	(tm_diff): New function.
+	(fmt, <stdio.h>): Remove; no longer used.
+
+Thu Sep 12 02:21:44 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+	* db/Makefile: Add extra-libs-others variable so that shared
+	library is built in `others' pass.
+	* elf/Makefile: Likewise.
+	* math/Makefile: Likewise.
+	* resolv/Makefile: Likewise.
+
+	* Makefile (generated): Add version.info.h.
+
+	* time/checktab.awk: New file.  From ADO 96k.
+	* time/iso3166.tab: Likewise.
+	* time/tzselect.ksh: Likewise.
+	* time/zone.tab: Likewise.
+
+	* stdio-common/vfprintf.c: Correct cleanup registration.  We
+	cannot use a macro
+
+1996-09-11  Paul Eggert  <eggert@twinsun.com>
+
+	* time/time.h (tm_gmtoff, tm_zone): Prefix with `__' unless
+	__USE_BSD; this is required for ANSI C compatibility.
+	* manual/time.texi: Replace GMT by UTC, daylight savings by
+ 	daylight saving, timezone by time zone.
+	Rewrite description of %V to match ISO 8601.
+	Fix TZ Posix string example for US Eastern time.
+	Explain tzname[1] when DST isn't used.
+	Explain tzname when multiple abbreviations used (e.g. EST/EWT/EDT).
+	Explain that timezone's sign is opposite from tm_gmtoff, and that
+	timezone lacks DST adjustment whereas tm_gmtoff has it.
+	Deprecate tzname and timezone.
+
+Tue Sep 10 14:46:16 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
+
+	Implement Roland McGrath's idea of how to put an .interp into
+	shared libraries.
+	* interp.c: New file.
+	* Makerules (interp-obj): New object, linked into every shared
+	library.
+	(common-generated): Add interp.so.
+	(CFLAGS-interp.c): Pass name of interpreter.
+
+Tue Sep 10 21:09:35 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
+
+	* db/Makefile: Fix typo.
+
+Tue Sep 10 19:29:53 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
+
+	* nss/db-Makefile ($(VAR_DB)/passwd.db): Look for multiple
+	occurences of the same uid, and only generate a mapping for the
+	first one.
+
+Tue Sep 10 03:14:59 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
+
+	* sysdeps/unix/sysv/linux/system.c: New file, to override
+	sysdeps/unix/system.c.
+
+Tue Sep 10 15:05:40 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
+
+	* Makefile (before-compile): Add version-info.h, needed to build
+	version.d.
+
+Tue Sep 10 14:14:33 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
+
+	* sysdeps/unix/sysv/linux/m68k/sysdep.S: Remove check for
+	EWOULDBLOCK, never true on Linux.
+	(__errno_location): New function.
+	[_LIBC_REENTRANT]: Set errno using __errno_location function.
+	* sysdeps/unix/sysv/linux/m68k/sysdep.h [PIC]: Add second
+ 	syscall_error handler for reentrant libc.
+
+Tue Sep 10 13:27:49 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
+
+	* elf/Makefile (extra-objs): Add eval.so to get dependencies.
+
+Wed Sep 11 04:40:57 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+	* time/tzset.c (__tzname_cur_max): Use type `size_t' to avoid
+ 	warning.
+	* time/tzfile.c (compute_tzname_max): Likewise.
+
 Wed Sep 11 02:57:31 1996  Ulrich Drepper  <drepper@cygnus.com>
 
 	* configure.in: Quote $add_ons argument in loop to generated
diff --git a/Makefile b/Makefile
index fd339fe550..791d788a5e 100644
--- a/Makefile
+++ b/Makefile
@@ -84,6 +84,7 @@ subdirs	:= $(filter mach,$(subdirs)) $(filter hurd,$(subdirs)) \
 headers := errno.h sys/errno.h errnos.h limits.h values.h	\
 	   features.h gnu-versions.h libc-lock.h
 aux	 = sysdep $(libc-init) version
+before-compile = $(objpfx)version-info.h
 
 echo-headers: subdir_echo-headers
 
@@ -251,12 +252,12 @@ distribute  := README INSTALL FAQ NOTES NEWS PROJECTS			\
 	       ansidecl.h mkinstalldirs move-if-change install-sh	\
 	       configure configure.in aclocal.m4 config.sub config.guess\
 	       config.h.in config.make.in config-name.in Makefile.in	\
-	       autolock.sh munch-tmpl.c munch.awk			\
+	       autolock.sh munch-tmpl.c munch.awk interp.c		\
 	       sysdep.h set-hooks.h libc-symbols.h version.h shlib-versions \
 	       rpm/Makefile rpm/template rpm/rpmrc
 
 distribute := $(strip $(distribute))
-generated := $(generated) stubs.h
+generated := $(generated) stubs.h version-info.h
 
 README: README.template version.c ; # Make-dist should update README.
 
diff --git a/Makerules b/Makerules
index 740cc0f247..132165bb38 100644
--- a/Makerules
+++ b/Makerules
@@ -316,6 +316,15 @@ else
 no-whole-archive =
 endif
 
+interp-obj = $(common-objpfx)interp.so
+$(interp-obj): $(common-objpfx)%.so: $(..)%.c
+	$(compile-command.c)
+common-generated += interp.so
+CFLAGS-interp.c = -D'RUNTIME_LINKER="$(slibdir)/$(rtld-installed-name)"'
+
+$(common-objpfx)libc.so: $(interp-obj)
+$(patsubst %,$(objpfx)%.so,$(extra-libs)): $(interp-obj)
+
 define build-shlib
 $(LINK.o) -shared -o $@ $(sysdep-LDFLAGS) $(config-LDFLAGS)  \
 	  -B$(csu-objpfx) \
diff --git a/db/Makefile b/db/Makefile
index 37dc282893..0ed798b6cf 100644
--- a/db/Makefile
+++ b/db/Makefile
@@ -9,6 +9,7 @@ subdir-dirs = btree db hash mpool recno
 vpath %.c $(subdir-dirs)
 
 extra-libs := libdb
+extra-libs-others := $(extra-libs)
 libdb-routines := bt_close bt_conv bt_debug bt_delete bt_get \
 		  bt_open bt_overflow bt_page bt_put bt_search \
 		  bt_seq bt_split bt_utils \
@@ -39,7 +40,7 @@ CFLAGS-hash_func.c := -Wno-unused
 # The db code outsmarts the compiler frequently.
 override CFLAGS += -Wno-uninitialized
 
-ifeq ($(build_shared),yes)
+ifeq ($(build-shared),yes)
 $(objpfx)makedb: $(objpfx)libdb.so$(libdb.so-version)
 else
 $(objpfx)makedb: $(objpfx)libdb.a
diff --git a/elf/Makefile b/elf/Makefile
index cf9eaa8cb4..cbb9c11f42 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -37,7 +37,8 @@ rtld-routines	:= rtld $(dl-routines) dl-sysdep dl-minimal
 distribute	= $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \
 		  soinit.c sofini.c ldd.sh.in eval.c
 
-extra-libs	= libdl
+extra-libs	 = libdl
+extra-libs-others = $(extra-libs)
 libdl-routines	:= dlopen dlclose dlsym dlerror dladdr
 
 
@@ -46,7 +47,7 @@ all: # Make this the default target; it will be defined in Rules.
 include ../Makeconfig
 
 ifeq (yes,$(build-shared))
-extra-objs	= $(rtld-routines:=.so) soinit.so sofini.so
+extra-objs	= $(rtld-routines:=.so) soinit.so sofini.so eval.so
 generated	= librtld.so dl-allobjs.so
 install-others	= $(slibdir)/$(rtld-installed-name)
 install-bin	= ldd
diff --git a/hurd/Makefile b/hurd/Makefile
index 2f2e36defe..873e695297 100644
--- a/hurd/Makefile
+++ b/hurd/Makefile
@@ -49,7 +49,7 @@ routines = hurdstartup hurdinit \
 	   privports \
 	   msgportdemux \
 	   fopenport \
- 	   vpprintf \
+	   vpprintf \
 	   ports-get ports-set hurdports hurdmsg \
 	   $(sig) $(dtable) hurdinline port-cleanup report-wait
 sig	= hurdsig hurdfault siginfo hurd-raise preempt-sig \
diff --git a/libio/putc_u.c b/libio/putc_u.c
index 18bbd491d8..85912e583f 100644
--- a/libio/putc_u.c
+++ b/libio/putc_u.c
@@ -29,3 +29,7 @@ putc_unlocked (c, fp)
   CHECK_FILE (fp, EOF);
   return _IO_putc_unlocked (c, fp);
 }
+
+#ifdef _LIBC_REENTRANT
+weak_alias (putc_unlocked, _IO_putc_unlocked)
+#endif
diff --git a/libio/stdio.h b/libio/stdio.h
index ce3da7df4c..3b399e5502 100644
--- a/libio/stdio.h
+++ b/libio/stdio.h
@@ -237,12 +237,10 @@ extern int putchar_unlocked __P ((int));
 # ifndef _LIBC
 #  define getc_unlocked(fp) _IO_getc_unlocked (fp)
 #  define getc_locked(fp) fgetc (fp)
-#  define getchar_unlocked() getc_unlocked (stdin)
-#  define getchar_locked() getc_locked (stdin)
-#  define getc(fp) getc_locked (fp)
-#  define putchar_unlocked(c) putc_unlocked (c, stdout)
-#  define putchar_locked(c) putc_locked (c, stdout)
-#  define putc(c, fp) putc_locked (c, fp)
+#  define getchar_unlocked() _IO_getc_unlocked (stdin)
+#  define getchar_locked() getc (stdin)
+#  define putchar_unlocked(c) _IO_putc_unlocked (c, stdout)
+#  define putchar_locked(c) putc (c, stdout)
 # endif
 
 #endif /* __USE_REENTRANT */
diff --git a/manual/time.texi b/manual/time.texi
index f439840170..9da23fbfb3 100644
--- a/manual/time.texi
+++ b/manual/time.texi
@@ -318,10 +318,10 @@ about the local time zone.  It has the following members:
 
 @table @code
 @item int tz_minuteswest
-This is the number of minutes west of GMT.
+This is the number of minutes west of UTC.
 
 @item int tz_dsttime
-If nonzero, daylight savings time applies during some part of the year.
+If nonzero, daylight saving time applies during some part of the year.
 @end table
 
 The @code{struct timezone} type is obsolete and should never be used.
@@ -504,15 +504,17 @@ information is not available.
 
 @item long int tm_gmtoff
 This field describes the time zone that was used to compute this
-broken-down time value; it is the amount you must add to the local time
-in that zone to get GMT, in units of seconds.  The value is like that of
-the variable @code{timezone} (@pxref{Time Zone Functions}).  You can
-also think of this as the ``number of seconds west'' of GMT.  The
-@code{tm_gmtoff} field is a GNU library extension.
+broken-down time value, including any adjustment for daylight saving; it
+is the number of seconds that you must add to UTC to get local time.
+You can also think of this as the number of seconds east of UTC.  For
+example, for U.S. Eastern Standard Time, the value is @code{-5*60*60}.
+The @code{tm_gmtoff} field is derived from BSD and is a GNU library
+extension; it is not visible in a strict ANSI C environment.
 
 @item const char *tm_zone
-This field is the name for the time zone that was used to
-compute this broken-down time value.  It is a GNU library extension.
+This field is the name for the time zone that was used to compute this
+broken-down time value.  Like @code{tm_gmtoff}, this field is a BSD and
+GNU extension, and is not visible in a strict ANSI C environment.
 @end table
 @end deftp
 
@@ -538,7 +540,7 @@ Zone Functions}.
 @deftypefun {struct tm *} gmtime (const time_t *@var{time})
 This function is similar to @code{localtime}, except that the broken-down
 time is expressed as Coordinated Universal Time (UTC)---that is, as
-Greenwich Mean Time (GMT) rather than relative to the local time zone.
+Greenwich Mean Time (GMT)---rather than relative to the local time zone.
 
 Recall that calendar times are @emph{always} expressed in coordinated
 universal time.
@@ -728,10 +730,9 @@ The hour and minute in decimal numbers using the format @code{%H:%M}.
 This format is a GNU extension.
 
 @item %s
-The seconds since the epoch, i.e., 1 January 1970 00:00:00 UTC.  Note
+The seconds since the epoch, i.e., 1970-01-01 00:00:00 UTC.  Note
 that this value is the number of seconds between the epoch and the
-current date as defined by the @code{localtime} system call.  It is not
-changed by the @code{--date} option.
+current date as defined by the @code{localtime} system call.
 
 This format is a GNU extension.
 
@@ -754,11 +755,14 @@ the first Sunday as the first day of the first week.  All days preceding
 the first Sunday in the year are considered to be in week @code{0}.
 
 @item %V
-The week number of the current year as a decimal number, starting with
-the first Monday as the first day of the first week.  If the week
-containing January 1 has four or more days in the new year it is
-considered to be week @code{1}.  Otherwise it is week @code{53} of the
-previous year.  This is standardized in @w{ISO 8601:1988}.
+The @w{ISO 8601:1988} week number as a decimal number (range @code{00}
+to @code{53}).  ISO weeks start with Monday and end with Sunday.  Week
+01 of a year is the first week which has the majority of its days in
+that year; this is equivalent to the week containing the year's first
+Thursday, and it is also equivalent to the week containing January 4.
+Week 01 of a year can contain days from the previous year.  The week
+before week 01 of a year is the last week (52 or 53) of the previous
+year even if it contains days from the new year.
 
 @item %w
 The day of the week as a decimal number, Sunday being @code{0}.
@@ -783,10 +787,9 @@ The year as a decimal number, but without a century (range @code{00} to
 The year as a decimal number, including the century.
 
 @item %z
-@w{RFC 822}/@w{ISO 8601:1988} style numeric time zone (e.g., -0600 or
-+0100), or nothing if no time zone is determinable.  This value reflects
-the @emph{current} time zone.  It is not changed by the @code{--date}
-option.
+@w{RFC 822}/@w{ISO 8601:1988} style numeric time zone (e.g.,
+@code{-0600} or @code{+0100}), or nothing if no time zone is
+determinable.
 
 @item %Z
 The time zone or name or abbreviation (empty if the time zone can't be
@@ -822,9 +825,9 @@ for accessing the time zone are declared in @file{time.h}.
 @cindex time zone
 
 You should not normally need to set @code{TZ}.  If the system is
-configured properly, the default timezone will be correct.  You might
+configured properly, the default time zone will be correct.  You might
 set @code{TZ} if you are using a computer over the network from a
-different timezone, and would like times reported to you in the timezone
+different time zone, and would like times reported to you in the time zone
 that local for you, rather than what is local for the computer.
 
 In POSIX.1 systems the value of the @code{TZ} variable can be of one of
@@ -858,7 +861,7 @@ negative if it is east.  The hour must be between @code{0} and
 @code{23}, and the minute and seconds between @code{0} and @code{59}.
 
 For example, here is how we would specify Eastern Standard Time, but
-without any daylight savings time alternative:
+without any daylight saving time alternative:
 
 @smallexample
 EST+5
@@ -872,11 +875,11 @@ The second format is used when there is Daylight Saving Time:
 
 The initial @var{std} and @var{offset} specify the standard time zone, as
 described above.  The @var{dst} string and @var{offset} specify the name
-and offset for the corresponding daylight savings time time zone; if the
+and offset for the corresponding daylight saving time time zone; if the
 @var{offset} is omitted, it defaults to one hour ahead of standard time.
 
-The remainder of the specification describes when daylight savings time is
-in effect.  The @var{start} field is when daylight savings time goes into
+The remainder of the specification describes when daylight saving time is
+in effect.  The @var{start} field is when daylight saving time goes into
 effect and the @var{end} field is when the change is made back to standard
 time.  The following formats are recognized for these fields:
 
@@ -904,16 +907,16 @@ effect, the change to the other time occurs.  If omitted, the default is
 
 For example, here is how one would specify the Eastern time zone in the
 United States, including the appropriate daylight saving time and its dates
-of applicability.  The normal offset from GMT is 5 hours; since this is
+of applicability.  The normal offset from UTC is 5 hours; since this is
 west of the prime meridian, the sign is positive.  Summer time begins on
 the first Sunday in April at 2:00am, and ends on the last Sunday in October
 at 2:00am.
 
 @smallexample
-EST+5EDT,M4.1.0/M10.5.0
+EST+5EDT,M4.1.0/2,M10.5.0/2
 @end smallexample
 
-The schedule of daylight savings time in any particular jurisdiction has
+The schedule of daylight saving time in any particular jurisdiction has
 changed over the years.  To be strictly correct, the conversion of dates
 and times in the past should be based on the schedule that was in effect
 then.  However, this format has no facilities to let you specify how the
@@ -967,15 +970,25 @@ community of volunteers and put in the public domain.
 @deftypevar char * tzname [2]
 The array @code{tzname} contains two strings, which are the standard
 names of the pair of time zones (standard and daylight
-savings) that the user has selected.  @code{tzname[0]} is the name of
+saving) that the user has selected.  @code{tzname[0]} is the name of
 the standard time zone (for example, @code{"EST"}), and @code{tzname[1]}
-is the name for the time zone when daylight savings time is in use (for
+is the name for the time zone when daylight saving time is in use (for
 example, @code{"EDT"}).  These correspond to the @var{std} and @var{dst}
-strings (respectively) from the @code{TZ} environment variable.
+strings (respectively) from the @code{TZ} environment variable.  If
+daylight saving time is never used, @code{tzname[1]} is the empty string.
 
 The @code{tzname} array is initialized from the @code{TZ} environment
 variable whenever @code{tzset}, @code{ctime}, @code{strftime},
-@code{mktime}, or @code{localtime} is called.
+@code{mktime}, or @code{localtime} is called.  If multiple abbreviations
+have been used (e.g. @code{"EWT"} and @code{"EDT"} for U.S. Eastern War
+Time and Eastern Daylight Time), the array contains the most recent
+abbreviation.
+
+The @code{tzname} array is required for POSIX.1 compatibility, but in
+GNU programs it is better to use the @code{tm_zone} member of the
+broken-down time structure, since @code{tm_zone} reports the correct
+abbreviation even when it is not the latest one.
+
 @end deftypevar
 
 @comment time.h
@@ -989,14 +1002,19 @@ depend on the time zone.
 @end deftypefun
 
 The following variables are defined for compatibility with System V
-Unix.  These variables are set by calling @code{tzset}.
+Unix.  Like @code{tzname}, these variables are set by calling
+@code{tzset} or the other time conversion functions.
 
 @comment time.h
 @comment SVID
 @deftypevar {long int} timezone
-This contains the difference between GMT and local standard time, in
-seconds.  For example, in the U.S. Eastern time zone, the value is
-@code{5*60*60}.
+This contains the difference between UTC and the latest local standard
+time, in seconds west of UTC.  For example, in the U.S. Eastern time
+zone, the value is @code{5*60*60}.  Unlike the @code{tm_gmtoff} member
+of the broken-down time structure, this value is not adjusted for
+daylight saving, and its sign is reversed.  In GNU programs it is better
+to use @code{tm_gmtoff}, since it contains the correct offset even when
+it is not the latest one.
 @end deftypevar
 
 @comment time.h
diff --git a/math/Makefile b/math/Makefile
index e0a9c6e86e..2c76633fb4 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -32,6 +32,7 @@ aux		:= fpu_control setfpucw
 # Build the -lm library.
 
 extra-libs	:= libm
+extra-libs-others = $(extra-libc)
 
 libm-support = k_standard s_lib_version s_matherr s_signgam
 libm-calls = e_acos e_acosh e_asin e_atan2 e_atanh e_cosh e_exp e_fmod	\
diff --git a/nss/db-Makefile b/nss/db-Makefile
index 881cabfa4b..55edd66c01 100644
--- a/nss/db-Makefile
+++ b/nss/db-Makefile
@@ -13,7 +13,8 @@ $(VAR_DB)/passwd.db: /etc/passwd
 	@echo -n "$(patsubst %.db,%,$(@F))... "
 	@$(AWK) 'BEGIN { FS=":"; OFS=":" } \
 		 /^[^#]/ { printf ".%s ", $$1; print; \
-			   printf "=%s ", $$3; print }' $^ | \
+			   if (!uids[$$3]++) \
+			     { printf "=%s ", $$3; print } }' $^ | \
 	$(MAKEDB) -o $@ -
 	@echo "done."
 
diff --git a/resolv/Makefile b/resolv/Makefile
index fffaca3948..a141fc7569 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -27,6 +27,7 @@ distribute := ../conf/portability.h mapv4v6addr.h mapv4v6hostent.h
 routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init
 
 extra-libs := libresolv
+extra-libs-others = $(extra-libs)
 libresolv-routines := gethnamaddr getnetnamadr res_comp res_debug	\
 		      res_data res_mkquery res_query res_send		\
 		      inet_net_ntop inet_net_pton inet_neta base64
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index 7c6a498a75..f5a1e23ca9 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -101,9 +101,7 @@ ssize_t __wprintf_pad __P ((FILE *, wchar_t pad, size_t n));
 	}								      \
     } while (0)
 # define UNBUFFERED_P(S) ((S)->_IO_file_flags & _IO_UNBUFFERED)
-# define flockfile(S) _IO_flockfile (S)
 /* This macro must be without parameter!  Don't change it.  */
-# define funlockfile _IO_funlockfile
 #else /* ! USE_IN_LIBIO */
 /* This code is for use in the GNU C library.  */
 # include <stdio.h>
@@ -125,8 +123,8 @@ ssize_t __wprintf_pad __P ((FILE *, wchar_t pad, size_t n));
     }									      \
    while (0)
 # define UNBUFFERED_P(s) ((s)->__buffer == NULL)
-# define flockfile(S) /* nothing */
-# define funlockfile(S) /* nothing */
+# define __flockfile(S) /* nothing */
+# define __funlockfile(S) /* nothing */
 #endif /* USE_IN_LIBIO */
 
 
@@ -849,8 +847,15 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
   f = lead_str_end = find_spec (format, &mbstate);
 
   /* Lock stream.  */
-  __libc_cleanup_region_start ((void (*) (void *)) &funlockfile, s);
-  flockfile (s);
+#ifdef USE_IN_LIBIO
+  __libc_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);
+#else
+#if 0
+  /* XXX For now stdio has no locking.  */
+  __libc_cleanup_region_start ((void (*) (void *)) &__funlockfile, s);
+#endif
+#endif
+  __flockfile (s);
 
   /* Write the literal text before the first format.  */
   outstring ((const UCHAR_T *) format,
diff --git a/sysdeps/generic/dl-cache.c b/sysdeps/generic/dl-cache.c
index 6cd454c7ac..20a312fee3 100644
--- a/sysdeps/generic/dl-cache.c
+++ b/sysdeps/generic/dl-cache.c
@@ -84,3 +84,89 @@ _dl_load_cache_lookup (const char *name)
 
   return NULL;
 }
+/* Support for reading /etc/ld.so.cache files written by Linux ldconfig.
+Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <link.h>
+#include <stddef.h>
+#include <sys/mman.h>
+
+/* System-dependent function to read a file's whole contents
+   in the most convenient manner available.  */
+extern void *_dl_sysdep_read_whole_file (const char *filename,
+					 size_t *filesize_ptr,
+					 int mmap_prot);
+
+#define CACHEMAGIC "ld.so-1.7.0"
+
+struct cache_file
+  {
+    char magic[sizeof CACHEMAGIC - 1];
+    unsigned int nlibs;
+    struct
+      {
+	int flags;		/* This is 1 for an ELF library.  */
+	unsigned int key, value; /* String table indices.  */
+      } libs[0];
+  };
+
+/* Look up NAME in ld.so.cache and return the file name stored there,
+   or null if none is found.  */
+
+const char *
+_dl_load_cache_lookup (const char *name)
+{
+  static struct cache_file *cache;
+  static size_t cachesize;
+  unsigned int i;
+
+  if (cache == (void *) -1)
+    /* Previously looked for the cache file and didn't find it.  */
+    return NULL;
+
+  if (cache == NULL)
+    {
+      /* Read the contents of the file.  */
+      void *file = _dl_sysdep_read_whole_file ("/etc/ld.so.cache", &cachesize,
+					       PROT_READ);
+      if (file && cachesize > sizeof *cache &&
+	  !memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1))
+	/* Looks ok.  */
+	cache = file;
+      else
+	{
+	  if (file)
+	    __munmap (file, cachesize);
+	  cache = (void *) -1;
+	  return NULL;
+	}
+    }
+
+  for (i = 0; i < cache->nlibs; ++i)
+    if (cache->libs[i].flags == 1 && /* ELF library entry.  */
+	/* Make sure string table indices are not bogus before using them.  */
+	cache->libs[i].key < cachesize - sizeof *cache &&
+	cache->libs[i].value < cachesize - sizeof *cache &&
+	/* Does the name match?  */
+	! strcmp (name, ((const char *) &cache->libs[cache->nlibs] +
+			 cache->libs[i].key)))
+      return (const char *) &cache->libs[cache->nlibs] + cache->libs[i].value;
+
+  return NULL;
+}
diff --git a/sysdeps/mach/hurd/dl-cache.c b/sysdeps/mach/hurd/dl-cache.c
index 7d919cd6a9..2981245c00 100644
--- a/sysdeps/mach/hurd/dl-cache.c
+++ b/sysdeps/mach/hurd/dl-cache.c
@@ -22,3 +22,27 @@ _dl_load_cache_lookup (const char *name)
 {
   return 0;
 }
+/* Stubby version of dl-cache; the Hurd doesn't support this "feature".
+Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+const char *
+_dl_load_cache_lookup (const char *name)
+{
+  return 0;
+}
diff --git a/sysdeps/unix/sysv/linux/Dist b/sysdeps/unix/sysv/linux/Dist
index a6b5db6749..db0cd6000d 100644
--- a/sysdeps/unix/sysv/linux/Dist
+++ b/sysdeps/unix/sysv/linux/Dist
@@ -1,3 +1,4 @@
+init-first.h
 sysctl.c
 net/if.h
 nfs/nfs.h
diff --git a/sysdeps/unix/sysv/linux/i386/Dist b/sysdeps/unix/sysv/linux/i386/Dist
index 780edfca50..d5cc620549 100644
--- a/sysdeps/unix/sysv/linux/i386/Dist
+++ b/sysdeps/unix/sysv/linux/i386/Dist
@@ -1,3 +1,2 @@
 sys/perm.h sys/vm86.h
-init-first.h
 clone.S
diff --git a/sysdeps/unix/sysv/linux/m68k/Dist b/sysdeps/unix/sysv/linux/m68k/Dist
index a281cba3f9..738b9cc542 100644
--- a/sysdeps/unix/sysv/linux/m68k/Dist
+++ b/sysdeps/unix/sysv/linux/m68k/Dist
@@ -1,2 +1 @@
-init-first.h
 clone.S
diff --git a/sysdeps/unix/sysv/linux/m68k/sysdep.S b/sysdeps/unix/sysv/linux/m68k/sysdep.S
index 895ea2770b..674715f824 100644
--- a/sysdeps/unix/sysv/linux/m68k/sysdep.S
+++ b/sysdeps/unix/sysv/linux/m68k/sysdep.S
@@ -33,8 +33,9 @@ errno:	.space 4
 _errno = errno	/* This name is expected by hj libc.so.5 startup code.  */
 	.text
 
-/* The following code is not used at all in the shared library.
-   The PIC system call stubs set errno themselves.  */
+/* The following code is only used in the shared library when we
+   compile the reentrant version.  Otherwise each system call defines
+   each own version.  */
 
 #ifndef	PIC
 
@@ -42,30 +43,34 @@ _errno = errno	/* This name is expected by hj libc.so.5 startup code.  */
 #define _ERRNO_H
 #include <errnos.h>
 
-.globl errno
-.globl __syscall_error
-
 /* The syscall stubs jump here when they detect an error.  */
 
 .globl __syscall_error
 __syscall_error:
 	neg.l %d0
-
-#if defined (EWOULDBLOCK_sys) && EWOULDBLOCK_sys != EAGAIN
-	/* We translate the system's EWOULDBLOCK error into EAGAIN.
-	   The GNU C library always defines EWOULDBLOCK==EAGAIN.
-	   EWOULDBLOCK_sys is the original number.  */
-	move.l #EWOULDBLOCK_sys, %d1
-	cmp.l %d0, %d1
-	jne 1f
-	move.l #EAGAIN, %d0
-1:
-#endif
-
 	move.l %d0, errno
+#ifdef _LIBC_REENTRANT
+	move.l %d0, -(%sp)
+	jbsr __errno_location
+	move.l (%sp)+, (%a0)
+#endif
 	move.l #-1, %d0
 	/* Copy return value to %a0 for syscalls that are declared to
 	   return a pointer.  */
 	move.l %d0, %a0
 	rts
+	.size	__syscall_error, . - __syscall_error
 #endif /* PIC */
+
+#ifdef	_LIBC_REENTRANT
+	.globl	__errno_location
+	.type	__errno_location, @function
+__errno_location:
+#ifdef PIC
+	move.l	(%pc, errno@GOTPC), %a0
+#else
+	lea	errno, %a0
+#endif
+	rts
+	.size	__errno_location, . - __errno_location
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/sysdep.h b/sysdeps/unix/sysv/linux/m68k/sysdep.h
index fe2c6aa823..9de750c326 100644
--- a/sysdeps/unix/sysv/linux/m68k/sysdep.h
+++ b/sysdeps/unix/sysv/linux/m68k/sysdep.h
@@ -78,19 +78,37 @@ Cambridge, MA 02139, USA.  */
 
 #ifdef PIC
 /* Store (- %d0) into errno through the GOT.  */
+#ifdef _LIBC_REENTRANT
 #define SYSCALL_ERROR_HANDLER						      \
+    .type syscall_error, @function;					      \
 syscall_error:								      \
     move.l (errno@GOTPC, %pc), %a0;					      \
     neg.l %d0;								      \
     move.l %d0, (%a0);							      \
+    move.l %d0, -(%sp);							      \
+    jbsr __errno_location@PLTPC						      \
+    move.l (%sp)+, (%a0);						      \
     move.l POUND -1, %d0;						      \
     /* Copy return value to %a0 for syscalls that are declared to return      \
        a pointer (e.g., mmap).  */					      \
     move.l %d0, %a0;							      \
     rts;
 #else
+#define SYSCALL_ERROR_HANDLER						      \
+    .type syscall_error, @function;					      \
+syscall_error:								      \
+    move.l (errno@GOTPC, %pc), %a0;					      \
+    neg.l %d0;								      \
+    move.l %d0, (%a0);							      \
+    move.l POUND -1, %d0;						      \
+    /* Copy return value to %a0 for syscalls that are declared to return      \
+       a pointer (e.g., mmap).  */					      \
+    move.l %d0, %a0;							      \
+    rts;
+#endif /* _LIBC_REENTRANT */
+#else
 #define SYSCALL_ERROR_HANDLER	/* Nothing here; code in sysdep.S is used.  */
-#endif
+#endif /* PIC */
 
 /* Linux takes system call arguments in registers:
 
diff --git a/time/Makefile b/time/Makefile
index 84e52306d7..7eeedd4e53 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -22,7 +22,8 @@
 subdir	:= time
 
 headers	:= time.h sys/time.h sys/timeb.h timebits.h
-distribute := tzfile.h private.h scheck.c ialloc.c yearistype
+distribute := tzfile.h private.h scheck.c ialloc.c yearistype	\
+	      iso3166.tab zone.tab tzselect.ksh checktab.awk
 extra-objs = scheck.o ialloc.o $(tzfiles:%=z.%)
 
 routines	:= offtime asctime clock ctime ctime_r difftime	\
diff --git a/time/strftime.c b/time/strftime.c
index 129fd1412c..26f4b7f354 100644
--- a/time/strftime.c
+++ b/time/strftime.c
@@ -23,13 +23,13 @@ Cambridge, MA 02139, USA.  */
 #ifdef _LIBC
 # define HAVE_LIMITS_H 1
 # define HAVE_MBLEN 1
+# define HAVE_TM_GMTOFF 1
 # define HAVE_TM_ZONE 1
 # define STDC_HEADERS 1
 # include <ansidecl.h>
 # include "../locale/localeinfo.h"
 #endif
 
-#include <stdio.h>
 #include <sys/types.h>		/* Some systems define `time_t' here.  */
 
 #ifdef TIME_WITH_SYS_TIME
@@ -75,9 +75,22 @@ Cambridge, MA 02139, USA.  */
 #endif
 #endif
 
-/* Uncomment following line in the production version.  */
-/* #define NDEBUG */
-#include <assert.h>
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#define TYPE_SIGNED(t) ((t) -1 < 0)
+
+/* Bound on length of the string representing an integer value of type t.
+   Subtract one for the sign bit if t is signed;
+   302 / 1000 is log10 (2) rounded up;
+   add one for integer division truncation;
+   add one more for a minus sign if t is signed.  */
+#define INT_STRLEN_BOUND(t) \
+  ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
+
+#define TM_YEAR_BASE 1900
+
 
 static unsigned int week __P ((const struct tm *const, int, int));
 
@@ -97,11 +110,30 @@ static unsigned int week __P ((const struct tm *const, int, int));
     } while (0)
 #define	cpy(n, s)	add ((n), memcpy((PTR) p, (PTR) (s), (n)))
 
-#ifdef _LIBC
-#define	fmt(n, args)	add((n), if (sprintf args != (n)) return 0)
-#else
-#define	fmt(n, args)	add((n), sprintf args; if (strlen (p) != (n)) return 0)
-#endif
+#if ! HAVE_TM_GMTOFF
+/* Yield the difference between *A and *B,
+   measured in seconds, ignoring leap seconds.  */
+static int tm_diff __P ((const struct tm *, const struct tm *));
+static int
+tm_diff (a, b)
+     const struct tm *a;
+     const struct tm *b;
+{
+  int ay = a->tm_year + TM_YEAR_BASE - 1;
+  int by = b->tm_year + TM_YEAR_BASE - 1;
+  /* Divide years by 100, rounding towards minus infinity.  */
+  int ac = ay / 100 - (ay % 100 < 0);
+  int bc = by / 100 - (by % 100 < 0);
+  int intervening_leap_days =
+    ((ay >> 2) - (by >> 2)) - (ac - bc) + ((ac >> 2) - (bc >> 2));
+  int years = ay - by;
+  int days = (365 * years + intervening_leap_days
+	      + (a->tm_yday - b->tm_yday));
+  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+		+ (a->tm_min - b->tm_min))
+	  + (a->tm_sec - b->tm_sec));
+}
+#endif /* ! HAVE_TM_GMTOFF */
 
 
 
@@ -181,6 +213,9 @@ strftime (s, maxsize, format, tp)
   size_t aw_len = strlen(a_wkday);
   size_t am_len = strlen(a_month);
   size_t ap_len = strlen (ampm);
+
+  const char * const*alt_digits = &_NL_CURRENT (LC_TIME, ALT_DIGITS);
+  int nr_alt_digits = (_NL_CURRENT (LC_TIME, ALT_DIGITS + 1) - *alt_digits);
 #else
   const char *const f_wkday = weekday_name[tp->tm_wday];
   const char *const f_month = month_name[tp->tm_mon];
@@ -201,10 +236,6 @@ strftime (s, maxsize, format, tp)
   register size_t i = 0;
   register char *p = s;
   register const char *f;
-  char number_fmt[5];
-
-  /* Initialize the buffer we will use for the sprintf format for numbers.  */
-  number_fmt[0] = '%';
 
   zone = 0;
 #if HAVE_TM_ZONE
@@ -227,9 +258,15 @@ strftime (s, maxsize, format, tp)
   for (f = format; *f != '\0'; ++f)
     {
       enum { pad_zero, pad_space, pad_none } pad; /* Padding for number.  */
-      unsigned int maxdigits;	/* Max digits for numeric format.  */
+      unsigned int digits;	/* Max digits for numeric format.  */
       unsigned int number_value; /* Numeric value to be printed.  */
-      const char *subfmt;
+      int negative_number;	/* 1 if the number is negative.  */
+      const char *subfmt = "";
+      enum { none, alternate, era } modifier;
+      char *bufp;
+      char buf[1 + (sizeof (int) < sizeof (time_t)
+		    ? INT_STRLEN_BOUND (time_t)
+		    : INT_STRLEN_BOUND (int))];
 
 #if HAVE_MBLEN
       if (!isascii (*f))
@@ -267,37 +304,76 @@ strftime (s, maxsize, format, tp)
 	  break;
 	}
 
+      /* Check for modifiers.  */
+      switch (*f)
+	{
+	case 'E':
+	  ++f;
+	  modifier = era;
+	  break;
+	case 'O':
+	  ++f;
+	  modifier = alternate;
+	  break;
+	default:
+	  modifier = none;
+	  break;
+	}
+
       /* Now do the specified format.  */
       switch (*f)
 	{
-	case '\0':
+#define DO_NUMBER(d, v) \
+	  digits = d; number_value = v; goto do_number
+#define DO_NUMBER_SPACEPAD(d, v) \
+	  digits = d; number_value = v; goto do_number_spacepad
+
+	case '\0':		/* GNU extension: % at end of format.  */
+	    --f;
+	    /* Fall through.  */
 	case '%':
+	  if (modifier != none)
+	    goto bad_format;
 	  add (1, *p = *f);
 	  break;
 
 	case 'a':
+	  if (modifier != none)
+	    goto bad_format;
 	  cpy (aw_len, a_wkday);
 	  break;
 
 	case 'A':
+	  if (modifier != none)
+	    goto bad_format;
 	  cpy (wkday_len, f_wkday);
 	  break;
 
 	case 'b':
 	case 'h':		/* GNU extension.  */
+	  if (modifier != none)
+	    goto bad_format;
 	  cpy (am_len, a_month);
 	  break;
 
 	case 'B':
+	  if (modifier != none)
+	    goto bad_format;
 	  cpy (month_len, f_month);
 	  break;
 
 	case 'c':
+	  if (modifier == alternate)
+	    goto bad_format;
 #ifdef _NL_CURRENT
-	  subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
+	  if (modifier == era)
+	    subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
+	  if (*subfmt == '\0')
+	    subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
 #else
-	  subfmt = "%a %b %d %H:%M:%S %Z %Y";
+	  subfmt = "%a %b %e %H:%M:%S %Z %Y";
 #endif
+
 	subformat:
 	  {
 	    size_t len = strftime (p, maxsize - i, subfmt, tp);
@@ -307,17 +383,25 @@ strftime (s, maxsize, format, tp)
 	  }
 	  break;
 
-#define DO_NUMBER(digits, value) \
-	  maxdigits = digits; number_value = value; goto do_number
-#define DO_NUMBER_SPACEPAD(digits, value) \
-	  maxdigits = digits; number_value = value; goto do_number_spacepad
-
 	case 'C':
+	  if (modifier == alternate)
+	    goto bad_format;
+#ifdef _NL_CURRENT
+	  /* XXX I'm not sure about this.  --drepper@gnu */
+	  if (modifier == era &&
+	      *(subfmt = _NL_CURRENT (LC_TIME, ERA)) != '\0')
+	    goto subformat;
+#endif
 	  DO_NUMBER (2, (1900 + tp->tm_year) / 100);
 
 	case 'x':
+	  if (modifier == alternate)
+	    goto bad_format;
 #ifdef _NL_CURRENT
-	  subfmt = _NL_CURRENT (LC_TIME, D_FMT);
+	  if (modifier == era)
+	    subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
+	  if (*subfmt == '\0')
+	    subfmt = _NL_CURRENT (LC_TIME, D_FMT);
 	  goto subformat;
 #endif
 	  /* Fall through.  */
@@ -326,12 +410,18 @@ strftime (s, maxsize, format, tp)
 	  goto subformat;
 
 	case 'd':
+	  if (modifier == era)
+	    goto bad_format;
+
 	  DO_NUMBER (2, tp->tm_mday);
 
 	case 'e':		/* GNU extension: %d, but blank-padded.  */
+	  if (modifier == era)
+	    goto bad_format;
+
 	  DO_NUMBER_SPACEPAD (2, tp->tm_mday);
 
-	  /* All numeric formats set MAXDIGITS and NUMBER_VALUE and then
+	  /* All numeric formats set DIGITS and NUMBER_VALUE and then
 	     jump to one of these two labels.  */
 
 	do_number_spacepad:
@@ -339,56 +429,106 @@ strftime (s, maxsize, format, tp)
 	  pad = pad_space;
 
 	do_number:
+	  /* Format the number according to the MODIFIER flag.  */
+
+#ifdef _NL_CURRENT
+	  if (modifier == alternate && 0 <= number_value
+	      && number_value < (unsigned int) nr_alt_digits)
+	    {
+	      /* ALT_DIGITS is the first entry in an array with
+		 alternative digit symbols.  */
+	      size_t digitlen = strlen (*(alt_digits + number_value));
+	      if (digitlen == 0)
+		break;
+	      cpy (digitlen, *(alt_digits + number_value));
+	      goto done_with_number;
+	    }
+#endif
 	  {
-	    /* Format the number according to the PAD flag.  */
+	    unsigned int u = number_value;
 
-	    register char *nf = &number_fmt[1];
-	    int printed = maxdigits;
+	    bufp = buf + sizeof (buf);
+	    negative_number = number_value < 0;
 
-	    switch (pad)
-	      {
-	      case pad_zero:
-		*nf++ = '0';
-	      case pad_space:
-		*nf++ = '0' + maxdigits;
-	      case pad_none:
-		*nf++ = 'u';
-		*nf = '\0';
-	      }
+	    if (negative_number)
+	      u = -u;
 
-#ifdef _LIBC
-	    add (maxdigits, printed = sprintf (p, number_fmt, number_value));
-#else
-	    add (maxdigits, sprintf (p, number_fmt, number_value);
-		 printed = strlen (p));
-#endif
-	    /* Back up if fewer than MAXDIGITS chars written for pad_none.  */
-	    p -= maxdigits - printed;
-	    i -= maxdigits - printed;
+	    do
+	      *--bufp = u % 10 + '0';
+	    while ((u /= 10) != 0);
+  	  }
 
-	    break;
-	  }
+	do_number_sign_and_padding:
+	  if (negative_number)
+	    *--bufp = '-';
+
+	  if (pad != pad_none)
+	    {
+	      int padding = digits - (buf + sizeof (buf) - bufp);
+
+	      if (pad == pad_space)
+		{
+		  while (0 < padding--)
+		    *--bufp = ' ';
+		}
+	      else
+		{
+		  bufp += negative_number;
+		  while (0 < padding--)
+		    *--bufp = '0';
+		  if (negative_number)
+		    *--bufp = '-';
+		}
+	    }
+
+	  cpy (buf + sizeof (buf) - bufp, bufp);
+
+#ifdef _NL_CURRENT
+	done_with_number:
+#endif
+	  break;
 
 
 	case 'H':
+	  if (modifier == era)
+	    goto bad_format;
+
 	  DO_NUMBER (2, tp->tm_hour);
 
 	case 'I':
+	  if (modifier == era)
+	    goto bad_format;
+
 	  DO_NUMBER (2, hour12);
 
 	case 'k':		/* GNU extension.  */
+	  if (modifier == era)
+	    goto bad_format;
+
 	  DO_NUMBER_SPACEPAD (2, tp->tm_hour);
 
 	case 'l':		/* GNU extension.  */
+	  if (modifier == era)
+	    goto bad_format;
+
 	  DO_NUMBER_SPACEPAD (2, hour12);
 
 	case 'j':
+	  if (modifier == era)
+	    goto bad_format;
+
 	  DO_NUMBER (3, 1 + tp->tm_yday);
 
 	case 'M':
+	  if (modifier == era)
+	    goto bad_format;
+
 	  DO_NUMBER (2, tp->tm_min);
 
 	case 'm':
+	  if (modifier == era)
+	    goto bad_format;
+
 	  DO_NUMBER (2, tp->tm_mon + 1);
 
 	case 'n':		/* GNU extension.  */
@@ -408,32 +548,55 @@ strftime (s, maxsize, format, tp)
 	  goto subformat;
 
 	case 'S':
+	  if (modifier == era)
+	    return 0;
+
 	  DO_NUMBER (2, tp->tm_sec);
 
 	case 's':		/* GNU extension.  */
-	  {
-	    struct tm writable_tm = *tp;
-	    unsigned long int num = (unsigned long int) mktime (&writable_tm);
-	    /* `3 * sizeof (unsigned long int)' is an approximation of
-	       the size of the decimal representation of NUM, valid
-	       for sizes <= 16.  */
-	    int printed = 3 * sizeof (unsigned long int);
-	    maxdigits = printed;
-	    assert (sizeof (unsigned long int) <= 16);
-#ifdef _LIBC
-	    add (maxdigits, printed = sprintf (p, "%lu", num));
-#else
-	    add (maxdigits, sprintf (p, "%lu", num); printed = strlen (p));
-#endif
-	    /* Back up if fewer than MAXDIGITS chars written for pad_none.  */
-	    p -= maxdigits - printed;
-	    i -= maxdigits - printed;
+  	  {
+	    struct tm ltm = *tp;
+	    time_t t = mktime (&ltm);
+
+	    /* Generate string value for T using time_t arithmetic;
+	       this works even if sizeof (long) < sizeof (time_t).  */
+
+	    bufp = buf + sizeof (buf);
+	    negative_number = t < 0;
+
+	    do
+	      {
+		int d = t % 10;
+		t /= 10;
+
+		if (negative_number)
+		  {
+		    d = -d;
+
+		    /* Adjust if division truncates to minus infinity.  */
+		    if (0 < -1 % 10 && d < 0)
+		      {
+			t++;
+			d += 10;
+		      }
+		  }
+
+		*--bufp = d + '0';
+	      }
+	    while (t != 0);
+
+	    digits = 1;
+	    goto do_number_sign_and_padding;
 	  }
-	break;
 
 	case 'X':
+	  if (modifier == alternate)
+	    goto bad_format;
 #ifdef _NL_CURRENT
-	  subfmt = _NL_CURRENT (LC_TIME, T_FMT);
+	  if (modifier == era)
+	    subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
+	  if (*subfmt == '\0')
+	    subfmt = _NL_CURRENT (LC_TIME, T_FMT);
 	  goto subformat;
 #endif
 	  /* Fall through.  */
@@ -446,61 +609,88 @@ strftime (s, maxsize, format, tp)
 	  break;
 
 	case 'U':
+	  if (modifier == era)
+	    goto bad_format;
+
 	  DO_NUMBER (2, y_week0);
 
 	case 'V':
+	  if (modifier == era)
+	    goto bad_format;
+
 	  DO_NUMBER (2, y_week2);
 
 	case 'W':
+	  if (modifier == era)
+	    goto bad_format;
+
 	  DO_NUMBER (2, y_week1);
 
 	case 'w':
+	  if (modifier == era)
+	    goto bad_format;
+
 	  DO_NUMBER (2, tp->tm_wday);
 
 	case 'Y':
-	  DO_NUMBER (4, 1900 + tp->tm_year);
+#ifdef _NL_CURRENT
+	  if (modifier == era
+	      && *(subfmt = _NL_CURRENT (LC_TIME, ERA_YEAR)) != '\0')
+	    goto subformat;
+	  else
+#endif
+	    if (modifier == alternate)
+	      goto bad_format;
+	    else
+	      DO_NUMBER (4, 1900 + tp->tm_year);
 
 	case 'y':
+#ifdef _NL_CURRENT
+	  if (modifier == era
+	      && *(subfmt = _NL_CURRENT (LC_TIME, ERA_YEAR)) != '\0')
+	    goto subformat;
+#endif
 	  DO_NUMBER (2, tp->tm_year % 100);
 
 	case 'Z':
 	  cpy(zonelen, zone);
 	  break;
 
-	case 'z':
+	case 'z':		/* GNU extension.  */
+	  if (tp->tm_isdst < 0)
+	    break;
+
 	  {
-	    struct tm tml = *tp;
-	    struct tm tmg;
-	    time_t t;
-	    time_t offset = 0;
 	    int diff;
+#if HAVE_TM_GMTOFF
+	    diff = tp->tm_gmtoff;
+#else
+	    struct tm gtm;
+	    struct tm ltm = *tp;
+	    time_t lt = mktime (&ltm);
 
-	    t = __mktime_internal (&tml, __localtime_r, &offset);
-
-	    /* Canonicalize the local time.  */
-	    if (t == (time_t) -1 || __localtime_r (&t, &tml) == NULL)
-	      /* We didn't managed to get the local time.  Assume it
-		 GMT as a reasonable default value.  */
-	      diff = 0;
-	    else
+	    if (lt == (time_t) -1)
 	      {
-		__gmtime_r (&t, &tmg);
+		/* mktime returns -1 for errors, but -1 is also a
+		   valid time_t value.  Check whether an error really
+		   occurred.  */
+		struct tm tm;
+		localtime_r (&lt, &tm);
+
+		if ((ltm.tm_sec ^ tm.tm_sec)
+		    | (ltm.tm_min ^ tm.tm_min)
+		    | (ltm.tm_hour ^ tm.tm_hour)
+		    | (ltm.tm_mday ^ tm.tm_mday)
+		    | (ltm.tm_mon ^ tm.tm_mon)
+		    | (ltm.tm_year ^ tm.tm_year))
+		  break;
+	      }
 
-		/* Compute the difference.  */
-		diff = tml.tm_min - tmg.tm_min;
-		diff += 60 * (tml.tm_hour - tmg.tm_hour);
+	    if (! gmtime_r (&lt, &gtm))
+	      break;
 
-		if (tml.tm_mon != tmg.tm_mon)
-		  {
-		    /* We assume no timezone differs from UTC by more
-		       than +- 23 hours.  This should be safe.  */
-		    if (tmg.tm_mday == 1)
-		      tml.tm_mday = 0;
-		    else /* tml.tm_mday == 1 */
-		      tmg.tm_mday = 0;
-		  }
-		diff += 1440 * (tml.tm_mday - tmg.tm_mday);
-	      }
+	    diff = tm_diff (&ltm, &gtm);
+#endif
 
 	    if (diff < 0)
 	      {
@@ -511,11 +701,24 @@ strftime (s, maxsize, format, tp)
 	      add (1, *p = '+');
 
 	    pad = pad_zero;
-	    DO_NUMBER (4, ((diff / 60) % 24) * 100 + diff % 60);
+
+	    diff /= 60;
+	    DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
 	  }
 
 	default:
 	  /* Bad format.  */
+	bad_format:
+	  if (pad == pad_space)
+	    add (1, *p = '_');
+	  else if (pad == pad_zero)
+	    add (1, *p = '0');
+
+	  if (modifier == era)
+	    add (1, *p = 'E');
+	  else if (modifier == alternate)
+	    add (1, *p = 'O');
+
 	  add (1, *p = *f);
 	  break;
 	}
diff --git a/time/time.h b/time/time.h
index 6b955f1986..f4c27f926e 100644
--- a/time/time.h
+++ b/time/time.h
@@ -22,7 +22,7 @@ Cambridge, MA 02139, USA.  */
 
 #ifndef	_TIME_H
 
-#if	(! defined (__need_time_t) && !defined(__need_clock_t) && \
+#if	(! defined (__need_time_t) && !defined (__need_clock_t) && \
 	 ! defined (__need_timespec))
 #define	_TIME_H		1
 #include <features.h>
@@ -54,8 +54,8 @@ __BEGIN_DECLS
 #endif /* <time.h> included.  */
 
 
-#if	!defined(__clock_t_defined) &&			\
-	(defined(_TIME_H) || defined(__need_clock_t))
+#if	!defined (__clock_t_defined) &&			\
+	(defined (_TIME_H) || defined (__need_clock_t))
 #define	__clock_t_defined	1
 
 #include <gnu/types.h>
@@ -66,8 +66,8 @@ typedef __clock_t clock_t;
 #endif /* clock_t not defined and <time.h> or need clock_t.  */
 #undef	__need_clock_t
 
-#if	!defined(__time_t_defined) &&			\
-	(defined(_TIME_H) || defined(__need_time_t))
+#if	!defined (__time_t_defined) &&			\
+	(defined (_TIME_H) || defined (__need_time_t))
 #define	__time_t_defined	1
 
 #include <gnu/types.h>
@@ -79,7 +79,7 @@ typedef __time_t time_t;
 #undef	__need_time_t
 
 
-#if	! defined(__timespec_defined) &&			\
+#if	! defined (__timespec_defined) &&			\
 	((defined (_TIME_H) && defined (__USE_POSIX)) ||	\
 	 defined (__need_timespec))
 #define	__timespec_defined	1
@@ -101,7 +101,7 @@ struct timespec
 /* Used by other time functions.  */
 struct tm
 {
-  int tm_sec;			/* Seconds.	[0-61] (2 leap seconds) */
+  int tm_sec;			/* Seconds.	[0-60] (1 leap second) */
   int tm_min;			/* Minutes.	[0-59] */
   int tm_hour;			/* Hours.	[0-23] */
   int tm_mday;			/* Day.		[1-31] */
@@ -110,8 +110,14 @@ struct tm
   int tm_wday;			/* Day of week.	[0-6] */
   int tm_yday;			/* Days in year.[0-365]	*/
   int tm_isdst;			/* DST.		[-1/0/1]*/
-  long int tm_gmtoff;		/* Seconds west of UTC.  */
+
+#ifdef	__USE_BSD
+  long int tm_gmtoff;		/* Seconds east of UTC.  */
   __const char *tm_zone;	/* Timezone abbreviation.  */
+#else
+  long int __tm_gmtoff;		/* Seconds east of UTC.  */
+  __const char *__tm_zone;	/* Timezone abbreviation.  */
+#endif
 };
 
 #endif /* <time.h> included.  */
@@ -190,7 +196,7 @@ extern void __offtime __P ((__const time_t *__timer,
    that is the representation of TP in this format.  */
 extern char *asctime __P ((__const struct tm *__tp));
 
-/* Equivalent to `asctime(localtime(timer))'.  */
+/* Equivalent to `asctime (localtime (timer))'.  */
 extern char *ctime __P ((__const time_t *__timer));
 
 #ifdef	__USE_REENTRANT
@@ -201,14 +207,14 @@ extern char *ctime __P ((__const time_t *__timer));
 extern char *__asctime_r __P ((__const struct tm *__tp, char *__buf));
 extern char *asctime_r __P ((__const struct tm *__tp, char *__buf));
 
-/* Equivalent to `asctime_r(localtime_r(timer, *TMP*), buf)'.  */
+/* Equivalent to `asctime_r (localtime_r (timer, *TMP*), buf)'.  */
 extern char *ctime_r __P ((__const time_t *__timer, char *__buf));
 #endif	/* reentrant */
 
 
 /* Defined in localtime.c.  */
 extern char *__tzname[2];	/* Current timezone names.  */
-extern int __daylight;		/* If it is daylight savings time.  */
+extern int __daylight;		/* If daylight-saving time is ever in use.  */
 extern long int __timezone;	/* Seconds west of UTC.  */
 
 /* Set time conversion information from the TZ environment variable.
diff --git a/time/tzfile.c b/time/tzfile.c
index 332ed46c33..e334249e77 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -402,7 +402,7 @@ DEFUN(__tzfile_compute, (timer, leap_correct, leap_hit),
 void
 DEFUN(compute_tzname_max, (chars), size_t chars)
 {
-  extern long int __tzname_cur_max; /* Defined in __tzset.c. */
+  extern size_t __tzname_cur_max; /* Defined in __tzset.c. */
 
   const char *p;
 
diff --git a/time/tzset.c b/time/tzset.c
index 8323c7be6d..e5b12f1e51 100644
--- a/time/tzset.c
+++ b/time/tzset.c
@@ -358,7 +358,7 @@ DEFUN_VOID(__tzset)
 /* Maximum length of a timezone name.  __tz_compute keeps this up to date
    (never decreasing it) when ! __use_tzfile.
    tzfile.c keeps it up to date when __use_tzfile.  */
-long int __tzname_cur_max;
+size_t __tzname_cur_max;
 
 long int
 DEFUN_VOID(__tzname_max)