summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1996-04-20 00:05:25 +0000
committerRoland McGrath <roland@gnu.org>1996-04-20 00:05:25 +0000
commita641835acd28fabf507c5a99d7805c694c2ec7e3 (patch)
tree5829796a450826b540dc763b8891b110bafd35b1
parentf24f4dc82d76bc2bed2d7e28877c5e9e469d4931 (diff)
Fri Apr 19 00:49:44 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>cvs/libc-960420
* stdlib/rpmatch.c (rpmatch: try): Take new arg NOMATCH, return value for nonmatching nonerror (instead of !MATCH). (rpmatch): Use it, so we return -1 when NOEXPR doesn't match either. * resolv/getnetnamadr.c (getnetbyaddr): Use u_int32_t instead of unsigned long for variable NET2. * time/etcetera, time/europe, time/solar89: Updated from ADO's 96e. Tue Apr 9 14:37:31 1996 Ulrich Drepper <drepper@cygnus.com> * catgets/Makefile, catgets/catgets.c, catgets/catgetsinfo.h, catgets/config.h, catgets/gencat.c, catgets/nl_types.h, catgets/open_catalog.c: New files. Implementation of XPG4 compliant catgets() function and needed tools. * Makefile (subdirs): Add catgets. Thu Apr 18 23:36:11 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> * math/Makefile (CPPFLAGS): Append -D__NO_MATH_INLINES. Wed Apr 10 20:48:43 1996 Ulrich Drepper <drepper@cygnus.com> * stdio-common/vfprintf.c: Correct some typos. * sysdeps/libm-ieee754/w_gammaf.c, sysdeps/libm-ieee754/w_lgamma.c, sysdeps/libm-ieee754/w_lgammaf.c: Reference signgam instead of __signgam. Thu Apr 18 21:07:27 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu> * Makerules (no-whole-archive): New variable. (build-shlib): Use it. * elf/Makefile (libdl.so): Use it. * configure.in (libc_cv_ld_no_whole_archive): New check for --no-whole-archive. * config.make.in (have-no-whole-archive): New variable. * stdio-common/printf_fp.c: Increase fudge factor for BIGNUM_SIZE calc from 3 to 4. * Make-dist: Include version.mk. (version, release): Variables removed. * Makeconfig (version.mk): New target. Fri Apr 19 01:42:18 1996 Ulrich Drepper <drepper@cygnus.com> * locale/Makefile (headers): Add langinfo.h. (CPPFLAGS): Remove -Iliblib.
-rw-r--r--ChangeLog52
-rw-r--r--Make-dist6
-rw-r--r--Makeconfig7
-rw-r--r--Makefile2
-rw-r--r--Makerules9
-rw-r--r--catgets/Makefile41
-rw-r--r--catgets/catgets.c163
-rw-r--r--catgets/catgetsinfo.h59
-rw-r--r--catgets/config.h14
-rw-r--r--catgets/gencat.c1030
-rw-r--r--catgets/nl_types.h48
-rw-r--r--catgets/open_catalog.c263
-rw-r--r--config.make.in2
-rw-r--r--configure.in13
-rw-r--r--elf/Makefile4
-rw-r--r--locale/Makefile4
-rw-r--r--math/Makefile4
-rw-r--r--posix/regex.c7
-rw-r--r--resolv/getnetnamadr.c6
-rw-r--r--stdio-common/printf_fp.c2
-rw-r--r--stdio-common/vfprintf.c6
-rw-r--r--stdlib/rpmatch.c8
-rw-r--r--sysdeps/libm-ieee754/w_gammaf.c6
-rw-r--r--sysdeps/libm-ieee754/w_lgamma.c6
-rw-r--r--sysdeps/libm-ieee754/w_lgammaf.c6
-rw-r--r--time/etcetera5
-rw-r--r--time/europe9
-rw-r--r--time/solar894
28 files changed, 1747 insertions, 39 deletions
diff --git a/ChangeLog b/ChangeLog
index 6ba50545e7..3966fcd3ac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,55 @@
+Fri Apr 19 00:49:44 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
+
+ * stdlib/rpmatch.c (rpmatch: try): Take new arg NOMATCH, return value
+ for nonmatching nonerror (instead of !MATCH).
+ (rpmatch): Use it, so we return -1 when NOEXPR doesn't match either.
+
+ * resolv/getnetnamadr.c (getnetbyaddr): Use u_int32_t instead of
+ unsigned long for variable NET2.
+
+ * time/etcetera, time/europe, time/solar89: Updated from ADO's 96e.
+
+Tue Apr 9 14:37:31 1996 Ulrich Drepper <drepper@cygnus.com>
+
+ * catgets/Makefile, catgets/catgets.c, catgets/catgetsinfo.h,
+ catgets/config.h, catgets/gencat.c, catgets/nl_types.h,
+ catgets/open_catalog.c: New files. Implementation of XPG4
+ compliant catgets() function and needed tools.
+ * Makefile (subdirs): Add catgets.
+
+Thu Apr 18 23:36:11 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
+
+ * math/Makefile (CPPFLAGS): Append -D__NO_MATH_INLINES.
+
+Wed Apr 10 20:48:43 1996 Ulrich Drepper <drepper@cygnus.com>
+
+ * stdio-common/vfprintf.c: Correct some typos.
+
+ * sysdeps/libm-ieee754/w_gammaf.c, sysdeps/libm-ieee754/w_lgamma.c,
+ sysdeps/libm-ieee754/w_lgammaf.c: Reference signgam instead of
+ __signgam.
+
+Thu Apr 18 21:07:27 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
+
+ * Makerules (no-whole-archive): New variable.
+ (build-shlib): Use it.
+ * elf/Makefile (libdl.so): Use it.
+ * configure.in (libc_cv_ld_no_whole_archive): New check for
+ --no-whole-archive.
+ * config.make.in (have-no-whole-archive): New variable.
+
+ * stdio-common/printf_fp.c: Increase fudge factor for BIGNUM_SIZE calc
+ from 3 to 4.
+
+ * Make-dist: Include version.mk.
+ (version, release): Variables removed.
+ * Makeconfig (version.mk): New target.
+
+Fri Apr 19 01:42:18 1996 Ulrich Drepper <drepper@cygnus.com>
+
+ * locale/Makefile (headers): Add langinfo.h.
+ (CPPFLAGS): Remove -Iliblib.
+
Mon Apr 15 16:49:04 1996 Roland McGrath <roland@whiz-bang.gnu.ai.mit.edu>
* malloc/memalign.c, malloc/malloc.h [__DJGPP__ == 1]: Elide memalign
diff --git a/Make-dist b/Make-dist
index 9ec795e9eb..d3881429df 100644
--- a/Make-dist
+++ b/Make-dist
@@ -105,11 +105,7 @@ foo:=$(shell echo '+tsrcs=$(+tsrcs)'>&2)
foo:=$(shell echo foobie, dammit! >&2)
ifndef tardir
-rel+vers := $(shell sed -n -e 's/^.*RELEASE.*\"\([^"]*\)";$$/\1/p' \
- -e 's/^.*VERSION.*\"\([^"]*\)";$$/\1/p' \
- < $(..)version.h)
-release := $(word 1,$(rel+vers))
-version := $(word 2,$(rel+vers))
+-include $(common-objpfx)version.mk
export tardir := glibc-$(version)
endif
diff --git a/Makeconfig b/Makeconfig
index 3273675d11..e0522ab815 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -468,6 +468,13 @@ cross-compiling := yes
else
cross-compiling := no
endif
+
+# Figure out the version numbers from version.h.
+$(common-objpfx)version.mk: $(..)version.h
+ sed -n -e 's/^.*RELEASE.*\"\([^"]*\)";$$/release=\1/p' \
+ -e 's/^.*VERSION.*\"\([^"]*\)";$$/version=\1/p' \
+ < $< > $@-new
+ mv -f $@-new $@
endif # Makeconfig not yet included
diff --git a/Makefile b/Makefile
index 30e0204bb6..68ad32d226 100644
--- a/Makefile
+++ b/Makefile
@@ -51,7 +51,7 @@ sysdep-subdirs := $(subst $(\n), ,$(sysdep-subdirs))
endif
# These are the subdirectories containing the library source.
-subdirs = csu assert ctype db locale intl math setjmp signal stdlib \
+subdirs = csu assert ctype db locale intl catgets math setjmp signal stdlib \
stdio-common $(stdio) malloc string wcsmbs time dirent grp pwd\
posix io termios resource misc socket sysvipc gmon gnulib \
wctype $(wildcard crypt) manual $(sysdep-subdirs) elf
diff --git a/Makerules b/Makerules
index cb22d03945..a16337806c 100644
--- a/Makerules
+++ b/Makerules
@@ -569,12 +569,19 @@ ifeq (yes,$(build-shared))
# on other shared objects.
lib%.so: lib%_pic.a; $(build-shlib)
+ifeq ($(libc_cv_ld_no_whole_archive),yes)
+no-whole-archive = -Wl,--no-whole-archive
+else
+no-whole-archive =
+endif
+
define build-shlib
$(LINK.o) -shared -o $@ $(sysdep-LDFLAGS) $(config-LDFLAGS) \
-Wl,-soname=lib$(libprefix)$(@F:lib%.so=%).so$($(@F)-version) \
$(LDFLAGS.so) $(LDFLAGS-$(@F:lib%.so=%).so) \
-Wl,-rpath-link=$(common-objdir) \
- -Wl,--whole-archive $^ $(LDLIBS-$(@F:lib%.so=%).so)
+ -Wl,--whole-archive $^ $(no-whole-archive) \
+ $(LDLIBS-$(@F:lib%.so=%).so)
endef
# Don't try to use -lc when making libc.so itself.
diff --git a/catgets/Makefile b/catgets/Makefile
new file mode 100644
index 0000000000..4646dd5a3f
--- /dev/null
+++ b/catgets/Makefile
@@ -0,0 +1,41 @@
+# 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.,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#
+# Makefile for catgets.
+#
+subdir := catgets
+
+headers = nl_types.h
+distribute = catgetsinfo.h config.h
+routines = catgets open_catalog
+others = gencat
+install-bin = gencat
+
+gencat-modules = xmalloc
+
+# To find xmalloc.c
+vpath %.c ../locale/programs
+
+
+include ../Rules
+
+$(objpfx)gencat: $(gencat-modules:%=$(objpfx)%.o)
+
+CPPFLAGS := -DNLSPATH='"$(localedir)/%L/%N:$(localedir)/%L/LC_MESSAGES/%N:"' \
+ -DHAVE_CONFIG_H $(CPPFLAGS)
diff --git a/catgets/catgets.c b/catgets/catgets.c
new file mode 100644
index 0000000000..ca0fdd693c
--- /dev/null
+++ b/catgets/catgets.c
@@ -0,0 +1,163 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+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., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <alloca.h>
+#include <nl_types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "catgetsinfo.h"
+
+
+/* Open the catalog and return a descriptor for the catalog. */
+nl_catd
+catopen (const char *cat_name, int flag)
+{
+ __nl_catd result;
+ const char *env_var;
+
+ result = (__nl_catd) malloc (sizeof (__nl_catd));
+ if (result == NULL)
+ /* We cannot get enough memory. */
+ return (nl_catd) -1;
+
+ result->status = closed;
+
+ result->cat_name = strdup (cat_name);
+ if (result->cat_name == NULL)
+ {
+ free (result);
+ return (nl_catd) -1;
+ }
+
+ if (strchr (cat_name, '/') == NULL)
+ {
+ if (flag == NL_CAT_LOCALE)
+ {
+ env_var = getenv ("LC_ALL");
+ if (env_var == NULL)
+ {
+ env_var = getenv ("LC_MESSAGES");
+ if (env_var == NULL)
+ {
+ env_var = getenv ("LANG");
+ if (env_var == NULL)
+ env_var = "C";
+ }
+ }
+ }
+ else
+ {
+ env_var = getenv ("LANG");
+ if (env_var == NULL)
+ env_var = "C";
+ }
+
+ result->env_var = strdup (env_var);
+ if (result->env_var == NULL)
+ {
+ free ((void *) result->cat_name);
+ free ((void *) result);
+ return (nl_catd) -1;
+ }
+
+ if (getenv ("NLSPATH") != NULL)
+ result->nlspath = strdup (getenv ("NLSPATH"));
+ else
+ result->nlspath = strdup (NLSPATH);
+
+ if (result->nlspath == NULL)
+ {
+ free ((void *) result->cat_name);
+ free ((void *) result->env_var);
+ free ((void *) result);
+ return (nl_catd) -1;
+ }
+ }
+ else
+ {
+ result->env_var = NULL;
+ result->nlspath = NULL;
+ }
+
+ return (nl_catd) result;
+}
+
+
+/* Return message from message catalog. */
+char *
+catgets (nl_catd catalog_desc, int set, int message, const char *string)
+{
+ __nl_catd catalog;
+ size_t idx;
+ size_t cnt;
+
+ /* Be generous if catalog which failed to be open is used. */
+ if (catalog_desc == (nl_catd) -1 || ++set <= 0 || message < 0)
+ return (char *) string;
+
+ catalog = (__nl_catd) catalog_desc;
+
+ if (catalog->status == closed)
+ __open_catalog (catalog, 1);
+
+ if (catalog->status == nonexisting)
+ return (char *) string;
+
+ idx = ((set * message) % catalog->plane_size) * 3;
+ cnt = 0;
+ do
+ {
+ if (catalog->name_ptr[idx + 0] == (u_int32_t) set
+ && catalog->name_ptr[idx + 1] == (u_int32_t) message)
+ return (char *) &catalog->strings[catalog->name_ptr[idx + 2]];
+
+ idx += catalog->plane_size * 3;
+ }
+ while (++cnt < catalog->plane_depth);
+
+ return (char *) string;
+}
+
+
+/* Return resources used for loaded message catalog. */
+int
+catclose (nl_catd catalog_desc)
+{
+ __nl_catd catalog;
+
+ catalog = (__nl_catd) catalog_desc;
+
+ if (catalog->status == mmaped)
+ munmap ((void *) catalog->file_ptr, catalog->file_size);
+ else if (catalog->status == malloced)
+ free ((void *) catalog->file_ptr);
+ else if (catalog->status != closed && catalog->status != nonexisting)
+ return -1;
+
+ if (catalog->nlspath)
+ free ((void *) catalog->nlspath);
+ if (catalog->env_var)
+ free ((void *) catalog->env_var);
+ free ((void *) catalog);
+
+ return 0;
+}
diff --git a/catgets/catgetsinfo.h b/catgets/catgetsinfo.h
new file mode 100644
index 0000000000..7e0a26f798
--- /dev/null
+++ b/catgets/catgetsinfo.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+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., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <sys/types.h>
+
+
+struct catalog_obj
+{
+ u_int32_t magic;
+ u_int32_t plane_size;
+ u_int32_t plane_depth;
+ /* This is in fact two arrays in one: always a pair of name and
+ pointer into the data area. */
+ u_int32_t name_ptr[0];
+};
+
+
+/* This structure will be filled after loading the catalog. */
+typedef struct catalog_info
+{
+ enum { closed, nonexisting, mmaped, malloced } status;
+
+ const char *cat_name;
+ const char *env_var;
+ const char *nlspath;
+
+ size_t plane_size;
+ size_t plane_depth;
+ u_int32_t *name_ptr;
+ const char *strings;
+
+ struct catalog_obj *file_ptr;
+ size_t file_size;
+} *__nl_catd;
+
+
+
+/* The magic number to signal we really have a catalog file. */
+#define CATGETS_MAGIC 0x960408de
+
+
+/* Prototypes for helper functions. */
+void __open_catalog (__nl_catd __catalog, int __with_path);
diff --git a/catgets/config.h b/catgets/config.h
new file mode 100644
index 0000000000..ce7887b351
--- /dev/null
+++ b/catgets/config.h
@@ -0,0 +1,14 @@
+#ifndef _CG_CONFIG_H
+#define _CG_CONFIG_H
+
+/* Use the internal textdomain used for libc messages. */
+#define PACKAGE _libc_intl_domainname
+#ifndef VERSION
+/* Get libc version number. */
+#include "../version.h"
+#endif
+
+
+#include_next <config.h>
+
+#endif
diff --git a/catgets/gencat.c b/catgets/gencat.c
new file mode 100644
index 0000000000..4b6eb43255
--- /dev/null
+++ b/catgets/gencat.c
@@ -0,0 +1,1030 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+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., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <endian.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <libintl.h>
+#include <limits.h>
+#include <nl_types.h>
+#include <obstack.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "version.h"
+
+#include "catgetsinfo.h"
+
+
+#define SWAPU32(w) \
+ (((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >> 24))
+
+struct message_list
+{
+ int number;
+ const char *message;
+
+ const char *fname;
+ size_t line;
+ const char *symbol;
+
+ struct message_list *next;
+};
+
+
+struct set_list
+{
+ int number;
+ int deleted;
+ struct message_list *messages;
+ int last_message;
+
+ const char *fname;
+ size_t line;
+ const char *symbol;
+
+ struct set_list *next;
+};
+
+
+struct catalog
+{
+ struct set_list *all_sets;
+ struct set_list *current_set;
+ size_t total_messages;
+ char quote_char;
+ int last_set;
+
+ struct obstack mem_pool;
+};
+
+
+/* If non-zero force creation of new file, not using existing one. */
+static int force_new;
+
+/* Long options. */
+static const struct option long_options[] =
+{
+ { "header", required_argument, NULL, 'H' },
+ { "help", no_argument, NULL, 'h' },
+ { "new", no_argument, &force_new, 1 },
+ { "output", required_argument, NULL, 'o' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL, 0, NULL, 0 }
+};
+
+/* Wrapper functions with error checking for standard functions. */
+extern void *xmalloc (size_t n);
+
+/* Prototypes for local functions. */
+static void usage (int status) __attribute__ ((noreturn));
+static void error_print (void);
+static struct catalog *read_input_file (struct catalog *current,
+ const char *fname);
+static void write_out (struct catalog *result, const char *output_name,
+ const char *header_name);
+static struct set_list *find_set (struct catalog *current, int number);
+static void normalize_line (const char *fname, size_t line, char *string,
+ char quote_char);
+static void read_old (struct catalog *catalog, const char *file_name);
+
+
+int
+main (int argc, char *argv[])
+{
+ struct catalog *result;
+ const char *output_name;
+ const char *header_name;
+ int do_help;
+ int do_version;
+ int opt;
+
+ /* Set program name for messages. */
+ error_print_progname = error_print;
+
+ /* Set locale via LC_ALL. */
+ setlocale (LC_ALL, "");
+
+ /* Set the text message domain. */
+ textdomain (PACKAGE);
+
+ /* Initialize local variables. */
+ do_help = 0;
+ do_version = 0;
+ output_name = NULL;
+ header_name = NULL;
+ result = NULL;
+
+ while ((opt = getopt_long (argc, argv, "hH:o:V", long_options, NULL)) != EOF)
+ switch (opt)
+ {
+ case '\0': /* Long option. */
+ break;
+ case 'h':
+ do_help = 1;
+ break;
+ case 'H':
+ header_name = optarg;
+ break;
+ case 'o':
+ output_name = optarg;
+ break;
+ case 'V':
+ do_version = 1;
+ break;
+ default:
+ usage (EXIT_FAILURE);
+ }
+
+ /* Version information is requested. */
+ if (do_version)
+ {
+ fprintf (stderr, "%s - GNU %s %s\n", program_invocation_name,
+ PACKAGE, VERSION);
+ exit (EXIT_SUCCESS);
+ }
+
+ /* Help is requested. */
+ if (do_help)
+ usage (EXIT_SUCCESS);
+
+ /* Determine output file. */
+ if (output_name == NULL)
+ output_name = optind < argc ? argv[optind++] : "-";
+
+ /* Process all input files. */
+ setlocale (LC_CTYPE, "C");
+ if (optind < argc)
+ do
+ result = read_input_file (result, argv[optind]);
+ while (++optind < argc);
+ else
+ result = read_input_file (NULL, "-");
+
+ /* Write out the result. */
+ if (result != NULL)
+ write_out (result, output_name, header_name);
+
+ exit (EXIT_SUCCESS);
+}
+
+
+static void
+usage (int status)
+{
+ if (status != EXIT_SUCCESS)
+ fprintf (stderr, gettext ("Try `%s --help' for more information.\n"),
+ program_invocation_name);
+ else
+ printf(gettext ("\
+Usage: %s [OPTION]... -o OUTPUT-FILE [INPUT-FILE]...\n\
+ %s [OPTION]... [OUTPUT-FILE [INPUT-FILE]...]\n\
+Mandatory arguments to long options are mandatory for short options too.\n\
+ -H, --header create C header file containing symbol definitions\n\
+ -h, --help display this help and exit\n\
+ --new do not use existing catalog, force new output file\n\
+ -o, --output=NAME write output to file NAME\n\
+ -V, --version output version information and exit\n\
+If INPUT-FILE is -, input is read from standard input. If OUTPUT-FILE\n\
+is -, output is written to standard output.\n"),
+ program_invocation_name, program_invocation_name);
+
+ exit (status);
+}
+
+
+/* The address of this function will be assigned to the hook in the
+ error functions. */
+static void
+error_print ()
+{
+ /* We don't want the program name to be printed in messages. Emacs'
+ compile.el does not like this. */
+}
+
+
+static struct catalog *
+read_input_file (struct catalog *current, const char *fname)
+{
+ FILE *fp;
+ char *buf;
+ size_t len;
+ size_t line_number;
+
+ if (strcmp (fname, "-") == 0 || strcmp (fname, "/dev/stdin") == 0)
+ {
+ fp = stdin;
+ fname = gettext ("*standard input*");
+ }
+ else
+ fp = fopen (fname, "r");
+ if (fp == NULL)
+ {
+ error (0, errno, gettext ("cannot open input file `%s'"), fname);
+ return current;
+ }
+
+ /* If we haven't seen anything yet, allocate result structure. */
+ if (current == NULL)
+ {
+ current = (struct catalog *) xmalloc (sizeof (*current));
+
+ current->all_sets = NULL;
+ current->total_messages = 0;
+ current->last_set = 0;
+ current->current_set = find_set (current, NL_SETD);
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+ obstack_init (&current->mem_pool);
+ }
+
+ buf = NULL;
+ len = 0;
+ line_number = 0;
+ while (!feof (fp))
+ {
+ int continued;
+ int used;
+ size_t start_line = line_number + 1;
+ char *this_line;
+
+ do
+ {
+ int act_len;
+
+ act_len = getline (&buf, &len, fp);
+ if (act_len <= 0)
+ break;
+ ++line_number;
+
+ /* It the line continued? */
+ if (buf[act_len - 1] == '\n')
+ {
+ --act_len;
+ continued = buf[act_len - 1] == '\\';
+ if (continued)
+ --act_len;
+ }
+ else
+ continued = 0;
+
+ /* Append to currently selected line. */
+ obstack_grow (&current->mem_pool, buf, act_len);
+ }
+ while (continued);
+
+ obstack_1grow (&current->mem_pool, '\0');
+ this_line = (char *) obstack_finish (&current->mem_pool);
+
+ used = 0;
+ if (this_line[0] == '$')
+ {
+ if (isspace (this_line[1]))
+ /* This is a comment line. Do nothing. */;
+ else if (strncmp (&this_line[1], "set", 3) == 0)
+ {
+ int cnt = sizeof ("cnt");
+ size_t set_number;
+ const char *symbol = NULL;
+ while (isspace (this_line[cnt]))
+ ++cnt;
+
+ if (isdigit (this_line[cnt]))
+ {
+ set_number = atol (&this_line[cnt]);
+
+ /* If the given number for the character set is
+ higher than any we used for symbolic set names
+ avoid clashing by using only higher numbers for
+ the following symbolic definitions. */
+ if (set_number > current->last_set)
+ current->last_set = set_number;
+ }
+ else
+ {
+ /* See whether it is a reasonable identifier. */
+ int start = cnt;
+ while (isalnum (this_line[cnt]) || this_line[cnt] == '_')
+ ++cnt;
+
+ if (cnt == start)
+ {
+ /* No correct character found. */
+ error_at_line (0, 0, fname, start_line,
+ gettext ("illegal set number"));
+ set_number = 0;
+ }
+ else
+ {
+ /* We have found seomthing which looks like a
+ correct identifier. */
+ struct set_list *runp;
+
+ this_line[cnt] = '\0';
+ used = 1;
+ symbol = &this_line[start];
+
+ /* Test whether the identifier was already used. */
+ runp = current->all_sets;
+ while (runp != 0)
+ if (runp->symbol != NULL
+ && strcmp (runp->symbol, symbol) == 0)
+ break;
+ else
+ runp = runp->next;
+
+ if (runp != NULL)
+ {
+ /* We cannot allow duplicate identifiers for
+ message sets. */
+ error_at_line (0, 0, fname, start_line,
+ gettext ("duplicate set definition"));
+ error_at_line (0, 0, runp->fname, runp->line,
+ gettext ("\
+this is the first definition"));
+ set_number = 0;
+ }
+ else
+ /* Allocate next free message set for identifier. */
+ set_number = ++current->last_set;
+ }
+ }
+
+ if (set_number != 0)
+ {
+ /* We found a legal set number. */
+ current->current_set = find_set (current, set_number);
+ if (symbol != NULL)
+ used = 1;
+ current->current_set->symbol = symbol;
+ current->current_set->fname = fname;
+ current->current_set->line = start_line;
+ }
+ }
+ else if (strncmp (&this_line[1], "delset", 6) == 0)
+ {
+ int cnt = sizeof ("delset");
+ size_t set_number;
+ while (isspace (this_line[cnt]))
+ ++cnt;
+
+ if (isdigit (this_line[cnt]))
+ {
+ size_t set_number = atol (&this_line[cnt]);
+ struct set_list *set;
+
+ /* Mark the message set with the given number as
+ deleted. */
+ set = find_set (current, set_number);
+ set->deleted = 1;
+ }
+ else
+ {
+ /* See whether it is a reasonable identifier. */
+ int start = cnt;
+ while (isalnum (this_line[cnt]) || this_line[cnt] == '_')
+ ++cnt;
+
+ if (cnt == start)
+ {
+ error_at_line (0, 0, fname, start_line,
+ gettext ("illegal set number"));
+ set_number = 0;
+ }
+ else
+ {
+ const char *symbol;
+ struct set_list *runp;
+
+ this_line[cnt] = '\0';
+ used = 1;
+ symbol = &this_line[start];
+
+ /* We have a symbolic set name. This name must
+ appear somewhere else in the catalogs read so
+ far. */
+ set_number = 0;
+ for (runp = current->all_sets; runp != NULL;
+ runp = runp->next)
+ {
+ if (strcmp (runp->symbol, symbol) == 0)
+ {
+ runp->deleted = 1;
+ break;
+ }
+ }
+ if (runp == NULL)
+ /* Name does not exist before. */
+ error_at_line (0, 0, fname, start_line,
+ gettext ("unknown set `%s'"), symbol);
+ }
+ }
+ }
+ else if (strncmp (&this_line[1], "quote", 5) == 0)
+ {
+ int cnt = sizeof ("quote");
+ while (isspace (this_line[cnt]))
+ ++cnt;
+ /* Yes, the quote char can be '\0'; this means no quote
+ char. */
+ current->quote_char = this_line[cnt];
+ }
+ else
+ {
+ int cnt;
+ cnt = 2;
+ while (this_line[cnt] != '\0' && !isspace (this_line[cnt]))
+ ++cnt;
+ this_line[cnt] = '\0';
+ error_at_line (0, 0, fname, start_line,
+ gettext ("unknown directive `%s': line ignored"),
+ &this_line[1]);
+ }
+ }
+ else if (isalnum (this_line[0]) || this_line[0] == '_')
+ {
+ const char *ident = this_line;
+ int message_number;
+
+ do
+ ++this_line;
+ while (this_line[0] != '\0' && !isspace (this_line[0]));;
+ this_line[0] = '\0'; /* Terminate the identifier. */
+
+ do
+ ++this_line;
+ while (isspace (this_line[0]));
+ /* Now we found the beginning of the message itself. */
+
+ if (isdigit (ident[0]))
+ {
+ struct message_list *runp;
+
+ message_number = atoi (ident);
+
+ /* Find location to insert the new message. */
+ runp = current->current_set->messages;
+ while (runp != NULL)
+ if (runp->number == message_number)
+ break;
+ else
+ runp = runp->next;
+ if (runp != NULL)
+ {
+ /* Oh, oh. There is already a message with this
+ number is the message set. */
+ error_at_line (0, 0, fname, start_line,
+ gettext ("duplicated message number"));
+ error_at_line (0, 0, runp->fname, runp->line,
+ gettext ("this is the first definition"));
+ message_number = 0;
+ }
+ ident = NULL; /* We don't have a symbol. */
+
+ if (message_number != 0
+ && message_number > current->current_set->last_message)
+ current->current_set->last_message = message_number;
+ }
+ else if (ident[0] != '\0')
+ {
+ struct message_list *runp;
+ runp = current->current_set->messages;
+
+ /* Test whether the symbolic name was not used for
+ another message in this message set. */
+ while (runp != NULL)
+ if (runp->symbol != NULL && strcmp (ident, runp->symbol) == 0)
+ break;
+ else
+ runp = runp->next;
+ if (runp != NULL)
+ {
+ /* The name is already used. */
+ error_at_line (0, 0, fname, start_line,
+ gettext ("duplicated message identifier"));
+ error_at_line (0, 0, runp->fname, runp->line,
+ gettext ("this is the first definition"));
+ message_number = 0;
+ }
+ else
+ /* Give the message the next unused number. */
+ message_number = ++current->current_set->last_message;
+ }
+ else
+ message_number = 0;
+
+ if (message_number != 0)
+ {
+ struct message_list *newp;
+
+ used = 1; /* Yes, we use the line. */
+
+ /* Strip quote characters, change escape sequences into
+ correct characters etc. */
+ normalize_line (fname, start_line, this_line,
+ current->quote_char);
+
+ newp = (struct message_list *) xmalloc (sizeof (*newp));
+ newp->number = message_number;
+ newp->message = this_line;
+ /* Remember symbolic name; is NULL if no is given. */
+ newp->symbol = ident;
+ /* Remember where we found the character. */
+ newp->fname = fname;
+ newp->line = start_line;
+
+ /* Find place to insert to message. We keep them in a
+ sorted single linked list. */
+ if (current->current_set->messages == NULL
+ || current->current_set->messages->number > message_number)
+ {
+ newp->next = current->current_set->messages;
+ current->current_set->messages = newp;
+ }
+ else
+ {
+ struct message_list *runp;
+ runp = current->current_set->messages;
+ while (runp->next != NULL)
+ if (runp->next->number > message_number)
+ break;
+ else
+ runp = runp->next;
+ newp->next = runp->next;
+ runp->next = newp;
+ }
+ }
+ ++current->total_messages;
+ }
+ else
+ {
+ size_t cnt;
+
+ cnt = 0;
+ /* See whether we have any non-white space character in this
+ line. */
+ while (this_line[cnt] != '\0' && isspace (this_line[cnt]))
+ ++cnt;
+
+ if (this_line[cnt] != '\0')
+ /* Yes, some unknown characters found. */
+ error_at_line (0, 0, fname, start_line,
+ gettext ("malformed line ignored"));
+ }
+
+ /* We can save the memory for the line if it was not used. */
+ if (!used)
+ obstack_free (&current->mem_pool, this_line);
+ }
+
+ if (fp != stdin)
+ fclose (fp);
+ return current;
+}
+
+
+static void
+write_out (struct catalog *catalog, const char *output_name,
+ const char *header_name)
+{
+ /* Computing the "optimal" size. */
+ struct set_list *set_run;
+ size_t best_total, best_size, best_depth;
+ size_t act_size, act_depth;
+ struct catalog_obj obj;
+ struct obstack string_pool;
+ const char *strings;
+ size_t strings_size;
+ u_int32_t *array1, *array2;
+ size_t cnt;
+ int fd;
+
+ /* If not otherwise told try to read file with existing
+ translations. */
+ if (!force_new)
+ read_old (catalog, output_name);
+
+ /* Initialize best_size with a very high value. */
+ best_total = best_size = best_depth = UINT_MAX;
+
+ /* We need some start size for testing. Let's start with
+ TOTAL_MESSAGES / 5, which theoretically provides a mean depth of
+ 5. */
+ act_size = 1 + catalog->total_messages / 5;
+
+ /* We determine the size of a hash table here. Because the message
+ numbers can be chosen arbitrary by the programmer we cannot use
+ the simple method of accessing the array using the message
+ number. The algorithm is based on the trivial hash function
+ NUMBER % TABLE_SIZE, where collisions are stored in a second
+ dimension up to TABLE_DEPTH. We here compute TABLE_SIZE so that
+ the needed space (= TABLE_SIZE * TABLE_DEPTH) is minimal. */
+ while (act_size <= best_total)
+ {
+ size_t deep[act_size];
+
+ act_depth = 1;
+ memset (deep, '\0', act_size * sizeof (size_t));
+ set_run = catalog->all_sets;
+ while (set_run != NULL)
+ {
+ struct message_list *message_run;
+
+ message_run = set_run->messages;
+ while (message_run != NULL)
+ {
+ size_t idx = (message_run->number * set_run->number) % act_size;
+
+ ++deep[idx];
+ if (deep[idx] > act_depth)
+ {
+ act_depth = deep[idx];
+ if (act_depth * act_size > best_total)
+ break;
+ }
+ message_run = message_run->next;
+ }
+
+ if (act_depth * act_size <= best_total)
+ {
+ /* We have found a better solution. */
+ best_total = act_depth * act_size;
+ best_size = act_size;
+ best_depth = act_depth;
+ }
+ set_run = set_run->next;
+ }
+
+ ++act_size;
+ }
+
+ /* let's be prepared for an empty message file. */
+ if (best_size == UINT_MAX)
+ {
+ best_size = 1;
+ best_depth = 1;
+ }
+
+ /* OK, now we have the size we will use. Fill in the header, build
+ the table and the second one with swapped byte order. */
+ obj.magic = CATGETS_MAGIC;
+ obj.plane_size = best_size;
+ obj.plane_depth = best_depth;
+
+ /* Allocate room for all needed arrays. */
+ array1 =
+ (u_int32_t *) alloca (best_size * best_depth * sizeof (u_int32_t) * 3);
+ memset (array1, '\0', best_size * best_depth * sizeof (u_int32_t) * 3);
+ array2
+ = (u_int32_t *) alloca (best_size * best_depth * sizeof (u_int32_t) * 3);
+ obstack_init (&string_pool);
+
+ set_run = catalog->all_sets;
+ while (set_run != NULL)
+ {
+ struct message_list *message_run;
+
+ message_run = set_run->messages;
+ while (message_run != NULL)
+ {
+ size_t idx = (((message_run->number * set_run->number) % best_size)
+ * 3);
+ /* Determine collision depth. */
+ while (array1[idx] != 0)
+ idx += best_size * 3;
+
+ /* Store set number, message number and pointer into string
+ space, relative to the first string. */
+ array1[idx + 0] = set_run->number;
+ array1[idx + 1] = message_run->number;
+ array1[idx + 2] = obstack_object_size (&string_pool);
+
+ /* Add current string to the continuous space containing all
+ strings. */
+ obstack_grow0 (&string_pool, message_run->message,
+ strlen (message_run->message));
+
+ message_run = message_run->next;
+ }
+
+ set_run = set_run->next;
+ }
+ strings_size = obstack_object_size (&string_pool);
+ strings = obstack_finish (&string_pool);
+
+ /* Compute ARRAY2 by changing the byte order. */
+ for (cnt = 0; cnt < best_size * best_depth * 3; ++cnt)
+ array2[cnt] = SWAPU32 (array1[cnt]);
+
+ /* Now we can write out the whole data. */
+ if (strcmp (output_name, "-") == 0
+ || strcmp (output_name, "/dev/stdout") == 0)
+ fd = STDOUT_FILENO;
+ else
+ {
+ fd = creat (output_name, 0666);
+ if (fd < 0)
+ error (EXIT_FAILURE, errno, gettext ("cannot open output file `%s'"),
+ output_name);
+ }
+
+ /* Write out header. */
+ write (fd, &obj, sizeof (obj));
+
+ /* We always write out the little endian version of the index
+ arrays. */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ write (fd, array1, best_size * best_depth * sizeof (u_int32_t) * 3);
+ write (fd, array2, best_size * best_depth * sizeof (u_int32_t) * 3);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ write (fd, array2, best_size * best_depth * sizeof (u_int32_t) * 3);
+ write (fd, array1, best_size * best_depth * sizeof (u_int32_t) * 3);
+#else
+# error Cannot handle __BYTE_ORDER byte order
+#endif
+
+ /* Finally write the strings. */
+ write (fd, strings, strings_size);
+
+ if (fd != STDOUT_FILENO)
+ close (fd);
+
+ /* If requested now write out the header file. */
+ if (header_name != NULL)
+ {
+ int first = 1;
+ FILE *fp;
+
+ /* Open output file. "-" or "/dev/stdout" means write to
+ standard output. */
+ if (strcmp (header_name, "-") == 0
+ || strcmp (header_name, "/dev/stdout") == 0)
+ fp = stdout;
+ else
+ {
+ fp = fopen (header_name, "w");
+ if (fp == NULL)
+ error (EXIT_FAILURE, errno,
+ gettext ("cannot open output file `%s'"), header_name);
+ }
+
+ /* Iterate over all sets and all messages. */
+ set_run = catalog->all_sets;
+ while (set_run != NULL)
+ {
+ struct message_list *message_run;
+
+ /* If the current message set has a symbolic name write this
+ out first. */
+ if (set_run->symbol != NULL)
+ fprintf (fp, "%s#define %sSet %#x\t/* %s:%u */\n",
+ first ? "" : "\n", set_run->symbol, set_run->number - 1,
+ set_run->fname, set_run->line);
+ first = 0;
+
+ message_run = set_run->messages;
+ while (message_run != NULL)
+ {
+ /* If the current message has a symbolic name write
+ #define out. But we have to take care for the set
+ not having a symbolic name. */
+ if (message_run->symbol != NULL)
+ if (set_run->symbol == NULL)
+ fprintf (fp, "#define AutomaticSet%d%s %#x\t/* %s:%u */\n",
+ set_run->number, message_run->symbol,
+ message_run->number, message_run->fname,
+ message_run->line);
+ else
+ fprintf (fp, "#define %s%s %#x\t/* %s:%u */\n",
+ set_run->symbol, message_run->symbol,
+ message_run->number, message_run->fname,
+ message_run->line);
+
+ message_run = message_run->next;
+ }
+
+ set_run = set_run->next;
+ }
+
+ if (fp != stdout)
+ fclose (fp);
+ }
+}
+
+
+static struct set_list *
+find_set (struct catalog *current, int number)
+{
+ struct set_list *result = current->all_sets;
+
+ /* We must avoid set number 0 because a set of this number signals
+ in the tables that the entry is not occupied. */
+ ++number;
+
+ while (result != NULL)
+ if (result->number == number)
+ return result;
+ else
+ result = result->next;
+
+ /* Prepare new message set. */
+ result = (struct set_list *) xmalloc (sizeof (*result));
+ result->number = number;
+ result->deleted = 0;
+ result->messages = NULL;
+ result->next = current->all_sets;
+ current->all_sets = result;
+
+ return result;
+}
+
+
+/* Normalize given string *in*place* by processing escape sequences
+ and quote characters. */
+static void
+normalize_line (const char *fname, size_t line, char *string, char quote_char)
+{
+ int is_quoted;
+ char *rp = string;
+ char *wp = string;
+
+ if (quote_char != '\0' && *rp == quote_char)
+ {
+ is_quoted = 1;
+ ++rp;
+ }
+ else
+ is_quoted = 0;
+
+ while (*rp != '\0')
+ if (*rp == quote_char)
+ /* We simply end the string when we find the first time an
+ not-escaped quote character. */
+ break;
+ else if (*rp == '\\')
+ {
+ ++rp;
+ if (quote_char != '\0' && *rp == quote_char)
+ /* This is an extension to XPG. */
+ *wp++ = *rp++;
+ else
+ /* Recognize escape sequences. */
+ switch (*rp)
+ {
+ case 'n':
+ *wp++ = '\n';
+ ++rp;
+ break;
+ case 't':
+ *wp++ = '\t';
+ ++rp;
+ break;
+ case 'v':
+ *wp++ = '\v';
+ ++rp;
+ break;
+ case 'b':
+ *wp++ = '\b';
+ ++rp;
+ break;
+ case 'r':
+ *wp++ = '\r';
+ ++rp;
+ break;
+ case 'f':
+ *wp++ = '\f';
+ ++rp;
+ break;
+ case '\\':
+ *wp++ = '\\';
+ ++rp;
+ break;
+ case '0' ... '7':
+ {
+ int number = *rp++ - '0';
+ while (number <= (255 / 8) && *rp >= '0' && *rp <= '7')
+ {
+ number *= 8;
+ number += *rp++ - '0';
+ }
+ *wp++ = (char) number;
+ }
+ break;
+ default:
+ /* Simply ignore the backslash character. */
+ break;
+ }
+ }
+ else
+ *wp++ = *rp++;
+
+ /* If we saw a quote character at the beginning we expect another
+ one at the end. */
+ if (is_quoted && *rp != quote_char)
+ error (0, 0, fname, line, gettext ("unterminated message"));
+
+ /* Terminate string. */
+ *wp = '\0';
+ return;
+}
+
+
+static void
+read_old (struct catalog *catalog, const char *file_name)
+{
+ struct catalog_info old_cat_obj;
+ struct set_list *set = NULL;
+ int last_set = -1;
+ size_t cnt;
+
+ old_cat_obj.status = closed;
+ old_cat_obj.cat_name = file_name;
+
+ /* Try to open catalog, but don't look through the NLSPATH. */
+ __open_catalog (&old_cat_obj, 0);
+
+ if (old_cat_obj.status != mmaped && old_cat_obj.status != malloced)
+ if (errno == ENOENT)
+ /* No problem, the catalog simply does not exist. */
+ return;
+ else
+ error (EXIT_FAILURE, errno, gettext ("while opening old catalog file"));
+
+ /* OK, we have the catalog loaded. Now read all messages and merge
+ them. When set and message number clash for any message the new
+ one is used. */
+ for (cnt = 0; cnt < old_cat_obj.plane_size * old_cat_obj.plane_depth; ++cnt)
+ {
+ struct message_list *message, *last;
+
+ if (old_cat_obj.name_ptr[cnt * 3 + 0] == 0)
+ /* No message in this slot. */
+ continue;
+
+ if (old_cat_obj.name_ptr[cnt * 3 + 0] - 1 != last_set)
+ {
+ last_set = old_cat_obj.name_ptr[cnt * 3 + 0] - 1;
+ set = find_set (catalog, old_cat_obj.name_ptr[cnt * 3 + 0] - 1);
+ }
+
+ last = NULL;
+ message = set->messages;
+ while (message != NULL)
+ {
+ if (message->number >= old_cat_obj.name_ptr[cnt * 3 + 1])
+ break;
+ last = message;
+ message = message->next;
+ }
+
+ if (message == NULL
+ || message->number > old_cat_obj.name_ptr[cnt * 3 + 1])
+ {
+ /* We have found a message which is not yet in the catalog.
+ Insert it at the right position. */
+ struct message_list *newp;
+
+ newp = (struct message_list *) xmalloc (sizeof(*newp));
+ newp->number = old_cat_obj.name_ptr[cnt * 3 + 1];
+ newp->message =
+ &old_cat_obj.strings[old_cat_obj.name_ptr[cnt * 3 + 2]];
+ newp->fname = NULL;
+ newp->line = 0;
+ newp->symbol = NULL;
+ newp->next = message;
+
+ if (last == NULL)
+ set->messages = newp;
+ else
+ last->next = newp;
+
+ ++catalog->total_messages;
+ }
+ }
+}
diff --git a/catgets/nl_types.h b/catgets/nl_types.h
new file mode 100644
index 0000000000..9f78d67468
--- /dev/null
+++ b/catgets/nl_types.h
@@ -0,0 +1,48 @@
+/* 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., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifndef _NL_TYPES_H
+#define _NL_TYPES_H 1
+#include <features.h>
+
+/* The default message set used by the gencat program. */
+#define NL_SETD 1
+
+/* Value for FLAG parameter of `catgets' to say we want XPG4 compliance. */
+#define NL_CAT_LOCALE 1
+
+/* Message catalog descriptor type. */
+typedef void *nl_catd;
+
+
+__BEGIN_DECLS
+
+/* Open message catalog for later use, returning descriptor. */
+extern nl_catd catopen __P ((__const char *__cat_name, int __flag));
+
+/* Return translation with NUMBER in SET of CATALOG; if not found
+ return STRING. */
+extern char *catgets __P ((nl_catd __catalog, int __set, int __number,
+ __const char *__string));
+
+/* Close message CATALOG. */
+extern int catclose __P ((nl_catd __catalog));
+
+__END_DECLS
+
+#endif /* nl_types.h */
diff --git a/catgets/open_catalog.c b/catgets/open_catalog.c
new file mode 100644
index 0000000000..9a8c7e643e
--- /dev/null
+++ b/catgets/open_catalog.c
@@ -0,0 +1,263 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
+
+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., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <endian.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include "catgetsinfo.h"
+
+
+#define SWAPU32(w) \
+ (((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >> 24))
+
+
+void
+__open_catalog (__nl_catd catalog, int with_path)
+{
+ int fd;
+ struct stat st;
+ int swapping;
+
+ if (strchr (catalog->cat_name, '/') != NULL || !with_path)
+ fd = open (catalog->cat_name, O_RDONLY);
+ else
+ {
+ const char *run_nlspath = catalog->nlspath;
+#define ENOUGH(n) \
+ if (bufact + (n) >=bufmax) \
+ { \
+ char *old_buf = buf; \
+ bufmax += 256 + (n); \
+ buf = (char *) alloca (bufmax); \
+ memcpy (buf, old_buf, bufact); \
+ }
+
+ /* The RUN_NLSPATH variable contains a colon separated list of
+ descriptions where we expect to find catalogs. We have to
+ recognize certain % substitutions and stop when we found the
+ first existing file. */
+ char *buf;
+ size_t bufact;
+ size_t bufmax;
+
+ buf = NULL;
+ bufmax = 0;
+
+ fd = -1;
+ while (*run_nlspath != '\0')
+ {
+ bufact = 0;
+ while (*run_nlspath != ':' && *run_nlspath != '\0')
+ if (*run_nlspath == '%')
+ {
+ const char *tmp;
+
+ ++run_nlspath; /* We have seen the `%'. */
+ switch (*run_nlspath++)
+ {
+ case 'N':
+ /* Use the catalog name. */
+ ENOUGH (strlen (catalog->cat_name));
+ bufact = stpcpy (&buf[bufact], catalog->cat_name) - buf;
+ break;
+ case 'L':
+ /* Use the current locale category value. */
+ ENOUGH (strlen (catalog->env_var));
+ bufact = stpcpy (&buf[bufact], catalog->env_var) - buf;
+ break;
+ case 'l':
+ /* Use language element of locale category value. */
+ tmp = catalog->env_var;
+ do
+ {
+ ENOUGH (1);
+ buf[bufact++] = *tmp++;
+ }
+ while (*tmp != '\0' && *tmp != '_' && *tmp != '.');
+ break;
+ case 't':
+ /* Use territory element of locale category value. */
+ tmp = catalog->env_var;
+ do
+ ++tmp;
+ while (*tmp != '\0' && *tmp != '_' && *tmp != '.');
+ if (*tmp == '_')
+ {
+ ++tmp;
+ do
+ {
+ ENOUGH (1);
+ buf[bufact++] = *tmp;
+ }
+ while (*tmp != '\0' && *tmp != '.');
+ }
+ break;
+ case 'c':
+ /* Use code set element of locale category value. */
+ tmp = catalog->env_var;
+ do
+ ++tmp;
+ while (*tmp != '\0' && *tmp != '.');
+ if (*tmp == '.')
+ {
+ ++tmp;
+ do
+ {
+ ENOUGH (1);
+ buf[bufact++] = *tmp;
+ }
+ while (*tmp != '\0');
+ }
+ break;
+ case '%':
+ ENOUGH (1);
+ buf[bufact++] = '%';
+ break;
+ default:
+ /* Unknown variable: ignore this path element. */
+ bufact = 0;
+ while (*run_nlspath != '\0' && *run_nlspath != ':')
+ ++run_nlspath;
+ break;
+ }
+ }
+ else
+ {
+ ENOUGH (1);
+ buf[bufact++] = *run_nlspath++;
+ }
+ ENOUGH (1);
+ buf[bufact] = '\0';
+
+ if (bufact != 0)
+ {
+ fd = open (buf, O_RDONLY);
+ if (fd >= 0)
+ break;
+ }
+
+ ++run_nlspath;
+ }
+ }
+
+ if (fd < 0 || fstat (fd, &st) < 0)
+ {
+ catalog->status = nonexisting;
+ return;
+ }
+
+#ifndef MAP_COPY
+ /* Linux seems to lack read-only copy-on-write. */
+#define MAP_COPY MAP_PRIVATE
+#endif
+#ifndef MAP_FILE
+ /* Some systems do not have this flag; it is superfluous. */
+#define MAP_FILE 0
+#endif
+#ifndef MAP_INHERIT
+ /* Some systems might lack this; they lose. */
+#define MAP_INHERIT 0
+#endif
+ catalog->file_size = st.st_size;
+ catalog->file_ptr =
+ (struct catalog_obj *) mmap (NULL, st.st_size, PROT_READ,
+ MAP_FILE|MAP_COPY|MAP_INHERIT, fd, 0);
+ if (catalog->file_ptr != (struct catalog_obj *) -1)
+ /* Tell the world we managed to mmap the file. */
+ catalog->status = mmaped;
+ else
+ {
+ /* mmap failed perhaps because the system call is not
+ implemented. Try to load the file. */
+ size_t todo;
+ catalog->file_ptr = malloc (st.st_size);
+ if (catalog->file_ptr == NULL)
+ {
+ catalog->status = nonexisting;
+ return;
+ }
+ todo = st.st_size;
+ /* Save read, handle partial reads. */
+ do
+ {
+ size_t now = read (fd, (((char *) &catalog->file_ptr)
+ + (st.st_size - todo)), todo);
+ if (now == 0)
+ {
+ free ((void *) catalog->file_ptr);
+ catalog->status = nonexisting;
+ return;
+ }
+ todo -= now;
+ }
+ while (todo > 0);
+ catalog->status = malloced;
+ }
+
+ /* We don't need the file anymore. */
+ close (fd);
+
+ /* Determine whether the file is a catalog file and if yes whether
+ it is written using the correct byte order. Else we have to swap
+ the values. */
+ if (catalog->file_ptr->magic == CATGETS_MAGIC)
+ swapping = 0;
+ else if (catalog->file_ptr->magic == SWAPU32 (CATGETS_MAGIC))
+ swapping = 1;
+ else
+ {
+ /* Illegal file. Free he resources and mark catalog as not
+ usable. */
+ if (catalog->status == mmaped)
+ munmap ((void *) catalog->file_ptr, catalog->file_size);
+ else
+ free (catalog->file_ptr);
+ catalog->status = nonexisting;
+ return;
+ }
+
+#define SWAP(x) (swapping ? SWAPU32 (x) : (x))
+
+ /* Get dimensions of the used hashing table. */
+ catalog->plane_size = SWAP (catalog->file_ptr->plane_size);
+ catalog->plane_depth = SWAP (catalog->file_ptr->plane_depth);
+
+ /* The file contains two versions of the pointer tables. Pick the
+ right one for the local byte order. */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ catalog->name_ptr = &catalog->file_ptr->name_ptr[0];
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ catalog->name_ptr = &catalog->file_ptr->name_ptr[catalog->plane_size
+ * catalog->plane_depth
+ * 3];
+#else
+# error Cannot handle __BYTE_ORDER byte order
+#endif
+
+ /* The rest of the file contains all the strings. They are
+ addressed relative to the position of the first string. */
+ catalog->strings =
+ (const char *) &catalog->file_ptr->name_ptr[catalog->plane_size
+ * catalog->plane_depth * 3 * 2];
+}
diff --git a/config.make.in b/config.make.in
index 50571745d0..593d9ca908 100644
--- a/config.make.in
+++ b/config.make.in
@@ -17,6 +17,8 @@ config-defines = @DEFS@
elf = @elf@
have-initfini = @libc_cv_have_initfini@
+have-no-whole-archive = @libc_cv_ld_no_whole_archive@
+
# Configuration options.
gnu-as = @gnu_as@
gnu-ld = @gnu_ld@
diff --git a/configure.in b/configure.in
index 734c5ad324..711635cc5d 100644
--- a/configure.in
+++ b/configure.in
@@ -469,6 +469,19 @@ elif test $libc_cv_asm_weakext_directive = yes; then
AC_DEFINE(HAVE_ASM_WEAKEXT_DIRECTIVE)
fi
+AC_CACHE_CHECK(for ld --no-whole-archive, libc_cv_ld_no_whole_archive, [dnl
+cat > conftest.c <<\EOF
+main () { exit (0); }
+EOF
+if ${CC-cc} $CFLAGS -Wl,--no-whole-archive \
+ -o conftest conftest.c 2>/dev/null; then
+ libc_cv_ld_no_whole_archive=yes
+else
+ libc_cv_ld_no_whole_archive=no
+fi
+rm -f conftest*])
+AC_SUBST(libc_cv_ld_no_whole_archive)dnl
+
### End of automated tests.
### Now run sysdeps configure fragments.
diff --git a/elf/Makefile b/elf/Makefile
index a77460d1de..dfb307b682 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -1,6 +1,6 @@
# Makefile for elf subdirectory of GNU C Library.
-# Copyright (C) 1995 Free Software Foundation, Inc.
+# Copyright (C) 1995, 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
@@ -80,7 +80,7 @@ $(objpfx)libdl.so: $(objpfx)libdl_pic.a $(common-objpfx)libc.so $(objpfx)ld.so
$(patsubst %/,cd %;,$(objpfx)) \
$(LINK.o) -shared -o $(@:$(objpfx)%=%) \
$(LDFLAGS.so) $(LDFLAGS-dl.so) \
- -Wl,--whole-archive $(^:$(objpfx)%=%)
+ -Wl,--whole-archive $(^:$(objpfx)%=%) $(no-whole-archive)
$(slibdir)/$(rtld-installed-name): $(objpfx)ld.so; $(do-install-program)
$(slibdir)/ld-linux.so.1: $(objpfx)ld-linux.so.1; $(do-install-program)
diff --git a/locale/Makefile b/locale/Makefile
index 0a30cd27d3..7399eda735 100644
--- a/locale/Makefile
+++ b/locale/Makefile
@@ -21,7 +21,7 @@
#
subdir := locale
-headers = locale.h
+headers = locale.h langinfo.h
distribute = localeinfo.h categories.def \
$(localedef-modules:=.c) $(locale-modules:=.c) \
$(lib-modules:=.c) config.h simple-hash.h iso-4217.def \
@@ -60,7 +60,7 @@ $(objpfx)localedef $(objpfx)locale: $(lib-modules:%=$(objpfx)%.o)
CPPFLAGS := -DLOCALE_PATH='"$(localedir)"' \
-DCHARMAP_PATH='"$(i18ndir)/charmap"' \
-DLOCSRCDIR='"$(i18ndir)/locales"' -DHAVE_CONFIG_H \
- -Iliblib -Iprograms $(CPPFLAGS)
+ -Iprograms $(CPPFLAGS)
CFLAGS-charmap.c = -Wno-write-strings
CFLAGS-locfile.c = -Wno-write-strings
diff --git a/math/Makefile b/math/Makefile
index a2ceb06925..48652167ad 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -71,5 +71,9 @@ include ../Rules
# the error return conventions for the math functions.
CPPFLAGS-s_lib_version.c := -D_POSIX_MODE
+# We don't want the fdlibm code to use the inline math functions,
+# only the fdlibm code.
+CPPFLAGS += -D__NO_MATH_INLINES
+
# The fdlibm code generates a lot of these warnings but is otherwise clean.
override CFLAGS += -Wno-uninitialized -Wno-write-strings
diff --git a/posix/regex.c b/posix/regex.c
index ee066b5efa..dc831cecd1 100644
--- a/posix/regex.c
+++ b/posix/regex.c
@@ -1007,7 +1007,7 @@ static const char *re_error_msgid[] =
#endif
/* Roughly the maximum number of failure points on the stack. Would be
- exactly that if always used MAX_FAILURE_SPACE each time we failed.
+ exactly that if always used MAX_FAILURE_ITEMS items each time we failed.
This is a variable only so users of regex can assign to it; we never
change it ourselves. */
#if defined (MATCH_MAY_ALLOCATE)
@@ -1224,7 +1224,10 @@ typedef struct
#endif
/* We push at most this many items on the stack. */
-#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
+/* We used to use (num_regs - 1), which is the number of registers
+ this regexp will save; but that was changed to 5
+ to avoid stack overflow for a regexp with lots of parens. */
+#define MAX_FAILURE_ITEMS (5 * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
/* We actually push this many items. */
#define NUM_FAILURE_ITEMS \
diff --git a/resolv/getnetnamadr.c b/resolv/getnetnamadr.c
index e5cc505d04..b2c911844e 100644
--- a/resolv/getnetnamadr.c
+++ b/resolv/getnetnamadr.c
@@ -154,7 +154,7 @@ static char *net_aliases[MAXALIASES], netbuf[BUFSIZ+1];
cp += n;
return (NULL);
}
- cp += n;
+ cp += n;
*ap++ = bp;
bp += strlen(bp) + 1;
net_entry.n_addrtype =
@@ -189,7 +189,7 @@ static char *net_aliases[MAXALIASES], netbuf[BUFSIZ+1];
paux1 = pauxt;
}
in = ++st;
- }
+ }
net_entry.n_net = inet_network(paux2);
break;
}
@@ -209,7 +209,7 @@ getnetbyaddr(net, net_type)
int nn, anslen;
querybuf buf;
char qbuf[MAXDNAME];
- unsigned long net2;
+ u_int32_t net2;
struct netent *net_entry;
if (net_type != AF_INET)
diff --git a/stdio-common/printf_fp.c b/stdio-common/printf_fp.c
index 009bdee0d5..4e6104a71b 100644
--- a/stdio-common/printf_fp.c
+++ b/stdio-common/printf_fp.c
@@ -337,7 +337,7 @@ __printf_fp (FILE *fp,
would be really big it could lead to memory problems. */
{
mp_size_t bignum_size = ((ABS (exponent) + BITS_PER_MP_LIMB - 1)
- / BITS_PER_MP_LIMB + 3) * sizeof (mp_limb);
+ / BITS_PER_MP_LIMB + 4) * sizeof (mp_limb);
frac = (mp_limb *) alloca (bignum_size);
tmp = (mp_limb *) alloca (bignum_size);
scale = (mp_limb *) alloca (bignum_size);
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index 26b31a6ed2..04f9e0d5f1 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -895,7 +895,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
tmp = ++f;
if (ISDIGIT (*tmp) && read_int (&tmp) && *tmp == L_('$'))
- /* The width comes from an positional parameter. */
+ /* The width comes from a positional parameter. */
goto do_positional;
width = va_arg (ap, int);
@@ -914,7 +914,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
LABEL (width):
width = read_int (&f);
if (*f == L_('$'))
- /* Oh, oh. The argument comes from an positional parameter. */
+ /* Oh, oh. The argument comes from a positional parameter. */
goto do_positional;
JUMP (*f, step1_jumps);
@@ -926,7 +926,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
tmp = ++f;
if (ISDIGIT (*tmp) && read_int (&tmp) > 0 && *tmp == L_('$'))
- /* The precision comes from an positional parameter. */
+ /* The precision comes from a positional parameter. */
goto do_positional;
prec = va_arg (ap, int);
diff --git a/stdlib/rpmatch.c b/stdlib/rpmatch.c
index 0dcaa6dc87..4774e2cf45 100644
--- a/stdlib/rpmatch.c
+++ b/stdlib/rpmatch.c
@@ -30,7 +30,7 @@ rpmatch (response)
{
/* Match against one of the response patterns, compiling the pattern
first if necessary. */
- inline int try (const int tag, const int match,
+ inline int try (const int tag, const int match, const int nomatch,
const char **lastp, regex_t *re)
{
const char *pattern = nl_langinfo (tag);
@@ -50,13 +50,13 @@ rpmatch (response)
}
/* Try the pattern. */
- return regexec (re, response, 0, NULL, 0) == 0 ? match : !match;
+ return regexec (re, response, 0, NULL, 0) == 0 ? match : nomatch;
}
/* We cache the response patterns and compiled regexps here. */
static const char *yesexpr, *noexpr;
static regex_t yesre, nore;
- return (try (YESEXPR, 1, &yesexpr, &yesre) ?:
- try (NOEXPR, 0, &noexpr, &nore));
+ return (try (YESEXPR, 1, 0, &yesexpr, &yesre) ?:
+ try (NOEXPR, 0, -1, &noexpr, &nore));
}
diff --git a/sysdeps/libm-ieee754/w_gammaf.c b/sysdeps/libm-ieee754/w_gammaf.c
index d0058df9ef..c2d21daf47 100644
--- a/sysdeps/libm-ieee754/w_gammaf.c
+++ b/sysdeps/libm-ieee754/w_gammaf.c
@@ -20,7 +20,7 @@ static char rcsid[] = "$NetBSD: w_gammaf.c,v 1.4 1995/11/20 22:06:48 jtc Exp $";
#include "math.h"
#include "math_private.h"
-extern int __signgam;
+extern int signgam;
#ifdef __STDC__
float __gammaf(float x)
@@ -30,10 +30,10 @@ extern int __signgam;
#endif
{
#ifdef _IEEE_LIBM
- return __ieee754_lgammaf_r(x,&__signgam);
+ return __ieee754_lgammaf_r(x,&signgam);
#else
float y;
- y = __ieee754_lgammaf_r(x,&__signgam);
+ y = __ieee754_lgammaf_r(x,&signgam);
if(_LIB_VERSION == _IEEE_) return y;
if(!__finitef(y)&&__finitef(x)) {
if(__floorf(x)==x&&x<=(float)0.0)
diff --git a/sysdeps/libm-ieee754/w_lgamma.c b/sysdeps/libm-ieee754/w_lgamma.c
index 9868f05782..2563d28f8d 100644
--- a/sysdeps/libm-ieee754/w_lgamma.c
+++ b/sysdeps/libm-ieee754/w_lgamma.c
@@ -23,7 +23,7 @@ static char rcsid[] = "$NetBSD: w_lgamma.c,v 1.6 1995/05/10 20:49:24 jtc Exp $";
#include "math.h"
#include "math_private.h"
-extern int __signgam;
+extern int signgam;
#ifdef __STDC__
double __lgamma(double x)
@@ -33,10 +33,10 @@ extern int __signgam;
#endif
{
#ifdef _IEEE_LIBM
- return __ieee754_lgamma_r(x,&__signgam);
+ return __ieee754_lgamma_r(x,&signgam);
#else
double y;
- y = __ieee754_lgamma_r(x,&__signgam);
+ y = __ieee754_lgamma_r(x,&signgam);
if(_LIB_VERSION == _IEEE_) return y;
if(!__finite(y)&&__finite(x)) {
if(__floor(x)==x&&x<=0.0)
diff --git a/sysdeps/libm-ieee754/w_lgammaf.c b/sysdeps/libm-ieee754/w_lgammaf.c
index 351b7acd33..1fd15a3110 100644
--- a/sysdeps/libm-ieee754/w_lgammaf.c
+++ b/sysdeps/libm-ieee754/w_lgammaf.c
@@ -20,7 +20,7 @@ static char rcsid[] = "$NetBSD: w_lgammaf.c,v 1.3 1995/05/10 20:49:30 jtc Exp $"
#include "math.h"
#include "math_private.h"
-extern int __signgam;
+extern int signgam;
#ifdef __STDC__
float __lgammaf(float x)
@@ -30,10 +30,10 @@ extern int __signgam;
#endif
{
#ifdef _IEEE_LIBM
- return __ieee754_lgammaf_r(x,&__signgam);
+ return __ieee754_lgammaf_r(x,&signgam);
#else
float y;
- y = __ieee754_lgammaf_r(x,&__signgam);
+ y = __ieee754_lgammaf_r(x,&signgam);
if(_LIB_VERSION == _IEEE_) return y;
if(!__finitef(y)&&__finitef(x)) {
if(__floorf(x)==x&&x<=(float)0.0)
diff --git a/time/etcetera b/time/etcetera
index ed619aecfa..73ad68ee0a 100644
--- a/time/etcetera
+++ b/time/etcetera
@@ -1,4 +1,4 @@
-# @(#)etcetera 7.4
+# @(#)etcetera 7.5
# All of these are set up just so people can "zic -l" to a timezone
# that's right for their area, even if it doesn't have a name or DST rules
@@ -27,7 +27,8 @@ Link Etc/GMT Etc/GMT0
# zic -l GMT-12
# so we moved the names into the Etc subdirectory.
-Zone Etc/GMT-13 13 - GMT-13 # 12 hours ahead of GMT, plus DST
+Zone Etc/GMT-14 14 - GMT-14 # 14 hours ahead of GMT
+Zone Etc/GMT-13 13 - GMT-13
Zone Etc/GMT-12 12 - GMT-12
Zone Etc/GMT-11 11 - GMT-11
Zone Etc/GMT-10 10 - GMT-10
diff --git a/time/europe b/time/europe
index 85c05eef11..04273d277c 100644
--- a/time/europe
+++ b/time/europe
@@ -1,4 +1,4 @@
-# @(#)europe 7.31
+# @(#)europe 7.33
# This data is by no means authoritative; if you think you know better,
# go ahead and edit the file (and please send any changes to
@@ -1644,7 +1644,12 @@ Zone Europe/Lisbon -0:36:32 - LMT 1884
# From Rui Pedro Salgueiro <rps@inescca.inescc.pt> (November 12, 1992):
# Portugal has recently (September, 27) changed timezone
# (from WET to MET or CET) to harmonize with EEC.
- 1:00 EC MET%s
+ 1:00 EC MET%s 1996 Mar 31 1:00u
+# Martin Bruckmann <martin@ua.pt> (1996-02-29) reports via Peter Ilieve
+# that Portugal is reverting to 0:00 by not moving its clocks this spring.
+# The new Prime Minister was fed up with getting up in the dark in the winter.
+ 0:00 1:00 "WET DST" 1996 Oct 27 1:00u
+ 0:00 EC WET%s
# We don't know what happened to Madeira or the Azores,
# so we'll just use Shanks for now.
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
diff --git a/time/solar89 b/time/solar89
index 5a720a8dfd..a6d3d718d3 100644
--- a/time/solar89
+++ b/time/solar89
@@ -1,4 +1,4 @@
-# @(#)solar89 7.3
+# @(#)solar89 7.4
# Apparent noon times below are for Riyadh; they're a bit off for other places.
# Times were computed using a formula provided by the U. S. Naval Observatory:
@@ -390,4 +390,4 @@ Zone Asia/Riyadh89 3:07:04 - ?? 1989
3:07:04 sol89 ?? 1990
3:07:04 - ??
# For backward compatibility...
-Link Asia/Riyadh88 Mideast/Riyadh88
+Link Asia/Riyadh89 Mideast/Riyadh89