mirror of
git://sourceware.org/git/glibc.git
synced 2024-11-27 03:41:23 +08:00
Thu Sep 28 13:05:54 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
Merge new message handling code from GNU gettext, by Drepper. * intl: New directory. * Makefile (subdirs): Add intl. * sysdeps/generic/dl-sysdep.c (_dl_sysdep_start): Return USER_ENTRY instead of storing it on our stack. * elf/rtld.c (rtld_command): Variable removed. (_dl_skip_args): New variable. (dl_main): Increment _dl_skip_args instead of setting rtld_command. If the link_map for the executable itself is not first in the chain, make it so. * sysdeps/i386/dl-machine.h (RTLD_START): Use _dl_skip_args as count of args to skip. Thu Sep 28 09:20:04 1995 Ulrich Drepper <drepper@gnu.ai.mit.edu> * stdlib/strtod.c (STRTOF): Fix handling of numbers with lots of leading zeroes.
This commit is contained in:
parent
91f62ce6b5
commit
24906b43b9
22
ChangeLog
22
ChangeLog
@ -1,3 +1,25 @@
|
||||
Thu Sep 28 13:05:54 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
|
||||
|
||||
Merge new message handling code from GNU gettext, by Drepper.
|
||||
* intl: New directory.
|
||||
* Makefile (subdirs): Add intl.
|
||||
|
||||
* sysdeps/generic/dl-sysdep.c (_dl_sysdep_start): Return
|
||||
USER_ENTRY instead of storing it on our stack.
|
||||
|
||||
* elf/rtld.c (rtld_command): Variable removed.
|
||||
(_dl_skip_args): New variable.
|
||||
(dl_main): Increment _dl_skip_args instead of setting rtld_command.
|
||||
If the link_map for the executable itself is not first in the chain,
|
||||
make it so.
|
||||
* sysdeps/i386/dl-machine.h (RTLD_START): Use _dl_skip_args as
|
||||
count of args to skip.
|
||||
|
||||
Thu Sep 28 09:20:04 1995 Ulrich Drepper <drepper@gnu.ai.mit.edu>
|
||||
|
||||
* stdlib/strtod.c (STRTOF): Fix handling of numbers with lots of
|
||||
leading zeroes.
|
||||
|
||||
Wed Sep 27 00:27:25 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
|
||||
|
||||
* sysdeps/mach/hurd/getcwd.c (__getcwd): Renamed from getcwd.
|
||||
|
4
Makefile
4
Makefile
@ -51,14 +51,14 @@ sysdep-subdirs := $(subst $(\n), ,$(sysdep-subdirs))
|
||||
endif
|
||||
|
||||
# These are the subdirectories containing the library source.
|
||||
subdirs := csu assert ctype locale math setjmp signal stdio stdlib \
|
||||
subdirs := csu assert ctype locale intl math setjmp signal stdio stdlib \
|
||||
malloc string time dirent grp pwd posix io termios resource \
|
||||
misc socket sysvipc gmon gnulib $(wildcard crypt) manual \
|
||||
$(sysdep-subdirs) elf
|
||||
export subdirs := $(subdirs) # Benign, useless in GNU make before 3.63.
|
||||
|
||||
# The mach and hurd subdirectories have many generated header files which
|
||||
# the much of rest of the library depends on, so it is best to build them
|
||||
# much of the rest of the library depends on, so it is best to build them
|
||||
# first (and mach before hurd, at that). The before-compile additions in
|
||||
# sysdeps/{mach,hurd}/Makefile should make it reliably work for these files
|
||||
# not to exist when making in other directories, but it will be slower that
|
||||
|
9
intl/Makefile
Normal file
9
intl/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
subdir = intl
|
||||
routines = bindtextdom dcgettext dgettext gettext \
|
||||
finddomain loadmsgcat localealias textdomain
|
||||
distribute = gettext.h gettextP.h hash-string.h libgettext.h
|
||||
|
||||
include ../Rules
|
||||
|
||||
CPPFLAGS += -D'GNULOCALEDIR="$(localedir)"' \
|
||||
-D'LOCALE_ALIAS_PATH="$(localedir):$(nlsdir)"'
|
172
intl/bindtextdom.c
Normal file
172
intl/bindtextdom.c
Normal file
@ -0,0 +1,172 @@
|
||||
/* bindtextdom.c -- implementation of the bindtextdomain(3) function
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; 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
|
||||
|
||||
#if defined STDC_HEADERS || defined _LIBC
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
# else
|
||||
void free ();
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined HAVE_STRING_H || defined _LIBC
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#ifdef _LIBC
|
||||
# include <libintl.h>
|
||||
#else
|
||||
# include "libgettext.h"
|
||||
#endif
|
||||
#include "gettext.h"
|
||||
#include "gettextP.h"
|
||||
|
||||
/* @@ end of prolog @@ */
|
||||
|
||||
/* Contains the default location of the message catalogs. */
|
||||
extern const char _nl_default_dirname[];
|
||||
|
||||
/* List with bindings of specific domains. */
|
||||
extern struct binding *_nl_domain_bindings;
|
||||
|
||||
|
||||
/* Names for the libintl functions are a problem. They must not clash
|
||||
with existing names and they should follow ANSI C. But this source
|
||||
code is also used in GNU C Library where the names have a __
|
||||
prefix. So we have to make a difference here. */
|
||||
#ifdef _LIBC
|
||||
# define BINDTEXTDOMAIN __bindtextdomain
|
||||
#else
|
||||
# define BINDTEXTDOMAIN bindtextdomain__
|
||||
#endif
|
||||
|
||||
/* Specify that the DOMAINNAME message catalog will be found
|
||||
in DIRNAME rather than in the system locale data base. */
|
||||
char *
|
||||
BINDTEXTDOMAIN (domainname, dirname)
|
||||
const char *domainname;
|
||||
const char *dirname;
|
||||
{
|
||||
struct binding *binding;
|
||||
|
||||
/* Some sanity checks. */
|
||||
if (domainname == NULL || domainname[0] == '\0')
|
||||
return NULL;
|
||||
|
||||
for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
|
||||
{
|
||||
int compare = strcmp (domainname, binding->domainname);
|
||||
if (compare == 0)
|
||||
/* We found it! */
|
||||
break;
|
||||
if (compare < 0)
|
||||
{
|
||||
/* It is not in the list. */
|
||||
binding = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dirname == NULL)
|
||||
/* The current binding has be to returned. */
|
||||
return binding == NULL ? (char *) _nl_default_dirname : binding->dirname;
|
||||
|
||||
if (binding != NULL)
|
||||
{
|
||||
/* The domain is already bound. Replace the old binding. */
|
||||
char *new_dirname;
|
||||
|
||||
if (strcmp (dirname, _nl_default_dirname) == 0)
|
||||
new_dirname = (char *) _nl_default_dirname;
|
||||
else
|
||||
{
|
||||
size_t len = strlen (dirname) + 1;
|
||||
new_dirname = (char *) malloc (len);
|
||||
if (new_dirname == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy (new_dirname, dirname, len);
|
||||
}
|
||||
|
||||
if (strcmp (binding->dirname, _nl_default_dirname) != 0)
|
||||
free (binding->dirname);
|
||||
|
||||
binding->dirname = new_dirname;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have to create a new binding. */
|
||||
size_t len;
|
||||
struct binding *new_binding =
|
||||
(struct binding *) malloc (sizeof (*new_binding));
|
||||
|
||||
if (new_binding == NULL)
|
||||
return NULL;
|
||||
|
||||
len = strlen (domainname) + 1;
|
||||
new_binding->domainname = (char *) malloc (len);
|
||||
if (new_binding->domainname == NULL)
|
||||
return NULL;
|
||||
memcpy (new_binding->domainname, domainname, len);
|
||||
|
||||
if (strcmp (dirname, _nl_default_dirname) == 0)
|
||||
new_binding->dirname = (char *) _nl_default_dirname;
|
||||
else
|
||||
{
|
||||
len = strlen (dirname) + 1;
|
||||
new_binding->dirname = (char *) malloc (len);
|
||||
if (new_binding->dirname == NULL)
|
||||
return NULL;
|
||||
memcpy (new_binding->dirname, dirname, len);
|
||||
}
|
||||
|
||||
/* Now enqueue it. */
|
||||
if (_nl_domain_bindings == NULL
|
||||
|| strcmp (domainname, _nl_domain_bindings->domainname) < 0)
|
||||
{
|
||||
new_binding->next = _nl_domain_bindings;
|
||||
_nl_domain_bindings = new_binding;
|
||||
}
|
||||
else
|
||||
{
|
||||
binding = _nl_domain_bindings;
|
||||
while (binding->next != NULL
|
||||
&& strcmp (domainname, binding->next->domainname) > 0)
|
||||
binding = binding->next;
|
||||
|
||||
new_binding->next = binding->next;
|
||||
binding->next = new_binding;
|
||||
}
|
||||
|
||||
binding = new_binding;
|
||||
}
|
||||
|
||||
return binding->dirname;
|
||||
}
|
||||
|
||||
#ifdef _LIBC
|
||||
/* Alias for function name in GNU C Library. */
|
||||
weak_alias (__bindtextdomain, bindtextdomain);
|
||||
#endif
|
523
intl/dcgettext.c
Normal file
523
intl/dcgettext.c
Normal file
@ -0,0 +1,523 @@
|
||||
/* dcgettext.c -- implemenatation of the dcgettext(3) function
|
||||
Copyright (C) 1995 Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; 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 <sys/types.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define alloca __builtin_alloca
|
||||
#else
|
||||
# ifdef HAVE_ALLOCA_H || defined _LIBC
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# ifdef _AIX
|
||||
#pragma alloca
|
||||
# else
|
||||
# ifndef alloca
|
||||
char *alloca ();
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#if defined STDC_HEADERS || defined _LIBC
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
char *getenv ();
|
||||
# ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
# else
|
||||
void free ();
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined HAVE_STRING_H || defined _LIBC
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#if !HAVE_STRCHR && !defined _LIBC
|
||||
# ifndef strchr
|
||||
# define strchr index
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined HAVE_UNISTD_H || defined _LIBC
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "gettext.h"
|
||||
#include "gettextP.h"
|
||||
#ifdef _LIBC
|
||||
# include <libintl.h>
|
||||
#else
|
||||
# include "libgettext.h"
|
||||
#endif
|
||||
#include "hash-string.h"
|
||||
|
||||
/* @@ end of prolog @@ */
|
||||
|
||||
#ifdef _LIBC
|
||||
/* Rename the non ANSI C functions. This is required by the standard
|
||||
because some ANSI C functions will require linking with this object
|
||||
file and the name space must not be polluted. */
|
||||
# define getcwd __getcwd
|
||||
# define stpcpy __stpcpy
|
||||
#endif
|
||||
|
||||
#if !defined HAVE_GETCWD && !defined _LIBC
|
||||
char *getwd ();
|
||||
# define getcwd(buf, max) getwd (buf)
|
||||
#else
|
||||
char *getcwd ();
|
||||
#endif
|
||||
|
||||
/* Amount to increase buffer size by in each try. */
|
||||
#define PATH_INCR 32
|
||||
|
||||
/* The following is from pathmax.h. */
|
||||
/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
|
||||
PATH_MAX but might cause redefinition warnings when sys/param.h is
|
||||
later included (as on MORE/BSD 4.3). */
|
||||
#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#ifndef _POSIX_PATH_MAX
|
||||
# define _POSIX_PATH_MAX 255
|
||||
#endif
|
||||
|
||||
#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
|
||||
# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
|
||||
#endif
|
||||
|
||||
/* Don't include sys/param.h if it already has been. */
|
||||
#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if !defined(PATH_MAX) && defined(MAXPATHLEN)
|
||||
# define PATH_MAX MAXPATHLEN
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX _POSIX_PATH_MAX
|
||||
#endif
|
||||
|
||||
/* XPG3 defines the result of `setlocale (category, NULL)' as:
|
||||
``Directs `setlocale()' to query `category' and return the current
|
||||
setting of `local'.''
|
||||
However it does not specify the exact format. And even worse: POSIX
|
||||
defines this not at all. So we can use this feature only on selected
|
||||
system (e.g. those using GNU C Library). */
|
||||
#ifdef _LIBC
|
||||
# define HAVE_LOCALE_NULL
|
||||
#endif
|
||||
|
||||
/* Name of the default domain used for gettext(3) prior any call to
|
||||
textdomain(3). The default value for this is "messages". */
|
||||
const char _nl_default_default_domain[] = "messages";
|
||||
|
||||
/* Value used as the default domain for gettext(3). */
|
||||
const char *_nl_current_default_domain = _nl_default_default_domain;
|
||||
|
||||
/* Contains the default location of the message catalogs. */
|
||||
const char _nl_default_dirname[] = GNULOCALEDIR;
|
||||
|
||||
/* List with bindings of specific domains created by bindtextdomain()
|
||||
calls. */
|
||||
struct binding *_nl_domain_bindings;
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
static char *find_msg __P ((struct loaded_domain *domain, const char *msgid));
|
||||
static const char *category_to_name __P((int category));
|
||||
static const char *guess_category_value __P((int category,
|
||||
const char *categoryname));
|
||||
|
||||
|
||||
/* Names for the libintl functions are a problem. They must not clash
|
||||
with existing names and they should follow ANSI C. But this source
|
||||
code is also used in GNU C Library where the names have a __
|
||||
prefix. So we have to make a difference here. */
|
||||
#ifdef _LIBC
|
||||
# define DCGETTEXT __dcgettext
|
||||
#else
|
||||
# define DCGETTEXT dcgettext__
|
||||
#endif
|
||||
|
||||
/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
|
||||
locale. */
|
||||
char *
|
||||
DCGETTEXT (domainname, msgid, category)
|
||||
const char *domainname;
|
||||
const char *msgid;
|
||||
int category;
|
||||
{
|
||||
struct loaded_domain *domain;
|
||||
struct binding *binding;
|
||||
const char *categoryname;
|
||||
const char *categoryvalue;
|
||||
char *dirname, *xdomainname;
|
||||
char *single_locale;
|
||||
char *retval;
|
||||
|
||||
/* If no real MSGID is given return NULL. */
|
||||
if (msgid == NULL)
|
||||
return NULL;
|
||||
|
||||
/* If DOMAINNAME is NULL, we are interested in the default domain. If
|
||||
CATEGORY is not LC_MESSAGES this might not make much sense but the
|
||||
defintion left this undefined. */
|
||||
if (domainname == NULL)
|
||||
domainname = _nl_current_default_domain;
|
||||
|
||||
/* First find matching binding. */
|
||||
for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
|
||||
{
|
||||
int compare = strcmp (domainname, binding->domainname);
|
||||
if (compare == 0)
|
||||
/* We found it! */
|
||||
break;
|
||||
if (compare < 0)
|
||||
{
|
||||
/* It is not in the list. */
|
||||
binding = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (binding == NULL)
|
||||
dirname = (char *) _nl_default_dirname;
|
||||
else if (binding->dirname[0] == '/')
|
||||
dirname = binding->dirname;
|
||||
else
|
||||
{
|
||||
/* We have a relative path. Make it absolute now. */
|
||||
size_t dirname_len = strlen (binding->dirname) + 1;
|
||||
size_t path_max;
|
||||
char *ret;
|
||||
|
||||
path_max = (unsigned) PATH_MAX;
|
||||
path_max += 2; /* The getcwd docs say to do this. */
|
||||
|
||||
dirname = (char *) alloca (path_max + dirname_len);
|
||||
|
||||
errno = 0;
|
||||
while ((ret = getcwd (dirname, path_max)) == NULL && errno == ERANGE)
|
||||
{
|
||||
path_max += PATH_INCR;
|
||||
dirname = (char *) alloca (path_max + dirname_len);
|
||||
errno = 0;
|
||||
}
|
||||
|
||||
if (ret == NULL)
|
||||
/* We cannot get the current working directory. Don't signal an
|
||||
error but simply return the default string. */
|
||||
return (char *) msgid;
|
||||
|
||||
/* We don't want libintl.a to depend on any other library. So
|
||||
we avoid the non-standard function stpcpy. In GNU C Library
|
||||
this function is available, though. Also allow the symbol
|
||||
HAVE_STPCPY to be defined. */
|
||||
#if defined _LIBC || defined HAVE_STPCPY
|
||||
stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
|
||||
#else
|
||||
strcat (dirname, "/");
|
||||
strcat (dirname, binding->dirname);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Now determine the symbolic name of CATEGORY and its value. */
|
||||
categoryname = category_to_name (category);
|
||||
categoryvalue = guess_category_value (category, categoryname);
|
||||
|
||||
xdomainname = (char *) alloca (strlen (categoryname)
|
||||
+ strlen (domainname) + 5);
|
||||
/* We don't want libintl.a to depend on any other library. So we
|
||||
avoid the non-standard function stpcpy. In GNU C Library this
|
||||
function is available, though. Also allow the symbol HAVE_STPCPY
|
||||
to be defined. */
|
||||
#if defined _LIBC || defined HAVE_STPCPY
|
||||
stpcpy (stpcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
|
||||
domainname),
|
||||
".mo");
|
||||
#else
|
||||
strcpy (xdomainname, categoryname);
|
||||
strcat (xdomainname, "/");
|
||||
strcat (xdomainname, domainname);
|
||||
strcat (xdomainname, ".mo");
|
||||
#endif
|
||||
|
||||
/* Creating working area. */
|
||||
single_locale = (char *) alloca (strlen (categoryvalue) + 1);
|
||||
|
||||
|
||||
/* Search for the given string. This is a loop because we perhaps
|
||||
got an ordered list of languages to consider for th translation. */
|
||||
while (1)
|
||||
{
|
||||
/* Make CATEGORYVALUE point to the next element of the list. */
|
||||
while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
|
||||
++categoryvalue;
|
||||
if (categoryvalue[0] == '\0')
|
||||
{
|
||||
/* The whole contents of CATEGORYVALUE has been searched but
|
||||
no valid entry has been found. We solve this situation
|
||||
by implicitely appending a "C" entry, i.e. no translation
|
||||
will take place. */
|
||||
single_locale[0] = 'C';
|
||||
single_locale[1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
char *cp = single_locale;
|
||||
while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
|
||||
*cp++ = *categoryvalue++;
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
/* If the current locale value is C (or POSIX) we don't load a
|
||||
domain. Return the MSGID. */
|
||||
if (strcmp (single_locale, "C") == 0
|
||||
|| strcmp (single_locale, "POSIX") == 0)
|
||||
return (char *) msgid;
|
||||
|
||||
|
||||
/* Find structure describing the message catalog matching the
|
||||
DOMAINNAME and CATEGORY. */
|
||||
domain = _nl_find_domain (dirname, single_locale, xdomainname);
|
||||
|
||||
if (domain != NULL)
|
||||
{
|
||||
retval = find_msg (domain, msgid);
|
||||
|
||||
if (retval == NULL)
|
||||
{
|
||||
int cnt;
|
||||
|
||||
for (cnt = 6; cnt >= 0 && retval == NULL; --cnt)
|
||||
if (domain->successor[cnt] != NULL)
|
||||
{
|
||||
retval = find_msg (domain->successor[cnt], msgid);
|
||||
|
||||
if (domain->successor[cnt]->data == NULL)
|
||||
domain->successor[cnt] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval != NULL)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
#ifdef _LIBC
|
||||
/* Alias for function name in GNU C Library. */
|
||||
weak_alias (__dcgettext, dcgettext);
|
||||
#endif
|
||||
|
||||
|
||||
static char *
|
||||
find_msg (domain, msgid)
|
||||
struct loaded_domain *domain;
|
||||
const char *msgid;
|
||||
{
|
||||
size_t top, act, bottom;
|
||||
|
||||
if (domain->decided == 0)
|
||||
_nl_load_domain (domain);
|
||||
|
||||
if (domain->data == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Locate the MSGID and its translation. */
|
||||
if (domain->hash_size > 2 && domain->hash_tab != NULL)
|
||||
{
|
||||
/* Use the hashing table. */
|
||||
nls_uint32 len = strlen (msgid);
|
||||
nls_uint32 hash_val = hash_string (msgid);
|
||||
nls_uint32 idx = hash_val % domain->hash_size;
|
||||
nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
|
||||
nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
|
||||
|
||||
if (nstr == 0)
|
||||
/* Hash table entry is empty. */
|
||||
return NULL;
|
||||
|
||||
if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
|
||||
&& strcmp (msgid,
|
||||
domain->data + W (domain->must_swap,
|
||||
domain->orig_tab[nstr - 1].offset)) == 0)
|
||||
return (char *) domain->data + W (domain->must_swap,
|
||||
domain->trans_tab[nstr - 1].offset);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (idx >= W (domain->must_swap, domain->hash_size) - incr)
|
||||
idx -= W (domain->must_swap, domain->hash_size) - incr;
|
||||
else
|
||||
idx += incr;
|
||||
|
||||
nstr = W (domain->must_swap, domain->hash_tab[idx]);
|
||||
if (nstr == 0)
|
||||
/* Hash table entry is empty. */
|
||||
return NULL;
|
||||
|
||||
if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
|
||||
&& strcmp (msgid,
|
||||
domain->data + W (domain->must_swap,
|
||||
domain->orig_tab[nstr - 1].offset))
|
||||
== 0)
|
||||
return (char *) domain->data
|
||||
+ W (domain->must_swap, domain->trans_tab[nstr - 1].offset);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* Now we try the default method: binary search in the sorted
|
||||
array of messages. */
|
||||
bottom = 0;
|
||||
top = domain->nstrings;
|
||||
while (bottom < top)
|
||||
{
|
||||
int cmp_val;
|
||||
|
||||
act = (bottom + top) / 2;
|
||||
cmp_val = strcmp (msgid, domain->data
|
||||
+ W (domain->must_swap,
|
||||
domain->orig_tab[act].offset));
|
||||
if (cmp_val < 0)
|
||||
top = act;
|
||||
else if (cmp_val > 0)
|
||||
bottom = act + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* If an translation is found return this. */
|
||||
return bottom >= top ? NULL : (char *) domain->data
|
||||
+ W (domain->must_swap,
|
||||
domain->trans_tab[act].offset);
|
||||
}
|
||||
|
||||
|
||||
/* Return string representation of locale CATEGORY. */
|
||||
static const char *category_to_name (category)
|
||||
int category;
|
||||
{
|
||||
const char *retval;
|
||||
|
||||
switch (category)
|
||||
{
|
||||
#ifdef LC_COLLATE
|
||||
case LC_COLLATE:
|
||||
retval = "LC_COLLATE";
|
||||
break;
|
||||
#endif
|
||||
#ifdef LC_CTYPE
|
||||
case LC_CTYPE:
|
||||
retval = "LC_CTYPE";
|
||||
break;
|
||||
#endif
|
||||
#ifdef LC_MONETARY
|
||||
case LC_MONETARY:
|
||||
retval = "LC_MONETARY";
|
||||
break;
|
||||
#endif
|
||||
#ifdef LC_NUMERIC
|
||||
case LC_NUMERIC:
|
||||
retval = "LC_NUMERIC";
|
||||
break;
|
||||
#endif
|
||||
#ifdef LC_TIME
|
||||
case LC_TIME:
|
||||
retval = "LC_TIME";
|
||||
break;
|
||||
#endif
|
||||
#ifdef LC_MESSAGES
|
||||
case LC_MESSAGES:
|
||||
retval = "LC_MESSAGES";
|
||||
break;
|
||||
#endif
|
||||
#ifdef LC_RESPONSE
|
||||
case LC_RESPONSE:
|
||||
retval = "LC_RESPONSE";
|
||||
break;
|
||||
#endif
|
||||
#ifdef LC_ALL
|
||||
case LC_ALL:
|
||||
/* This might not make sense but is perhaps better than any other
|
||||
value. */
|
||||
retval = "LC_ALL";
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* If you have a better idea for a default value let me know. */
|
||||
retval = "LC_XXX";
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Guess value of current locale from value of the environment variables. */
|
||||
static const char *guess_category_value (category, categoryname)
|
||||
int category;
|
||||
const char *categoryname;
|
||||
{
|
||||
const char *retval;
|
||||
|
||||
/* The highest priority value is the `LANGUAGE' environment
|
||||
variable. This is a GNU extension. */
|
||||
retval = getenv ("LANGUAGE");
|
||||
if (retval != NULL && retval[0] != '\0')
|
||||
return retval;
|
||||
|
||||
/* `LANGUAGE' is not set. So we have to proceed with the POSIX
|
||||
methods of looking to `LC_ALL', `LC_xxx', and `LANG'. On some
|
||||
systems this can be done by the `setlocale' function itself. */
|
||||
#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
|
||||
return setlocale (category, NULL);
|
||||
#else
|
||||
/* Setting of LC_ALL overwrites all other. */
|
||||
retval = getenv ("LC_ALL");
|
||||
if (retval != NULL && retval[0] != '\0')
|
||||
return retval;
|
||||
|
||||
/* Next comes the name of the desired category. */
|
||||
retval = getenv (categoryname);
|
||||
if (retval != NULL && retval[0] != '\0')
|
||||
return retval;
|
||||
|
||||
/* Last possibility is the LANG environment variable. */
|
||||
retval = getenv ("LANG");
|
||||
if (retval != NULL && retval[0] != '\0')
|
||||
return retval;
|
||||
|
||||
/* We use C as the default domain. POSIX says this is implementation
|
||||
defined. */
|
||||
return "C";
|
||||
#endif
|
||||
}
|
59
intl/dgettext.c
Normal file
59
intl/dgettext.c
Normal file
@ -0,0 +1,59 @@
|
||||
/* dgettext.c -- implementation of the dgettext(3) function
|
||||
Copyright (C) 1995 Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; 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
|
||||
|
||||
#if defined HAVE_LOCALE_H || defined _LIBC
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
#ifdef _LIBC
|
||||
# include <libintl.h>
|
||||
#else
|
||||
# include "libgettext.h"
|
||||
#endif
|
||||
|
||||
/* @@ end of prolog @@ */
|
||||
|
||||
/* Names for the libintl functions are a problem. They must not clash
|
||||
with existing names and they should follow ANSI C. But this source
|
||||
code is also used in GNU C Library where the names have a __
|
||||
prefix. So we have to make a difference here. */
|
||||
#ifdef _LIBC
|
||||
# define DGETTEXT __dgettext
|
||||
# define DCGETTEXT __dcgettext
|
||||
#else
|
||||
# define DGETTEXT dgettext__
|
||||
# define DCGETTEXT dcgettext__
|
||||
#endif
|
||||
|
||||
/* Look up MSGID in the DOMAINNAME message catalog of the current
|
||||
LC_MESSAGES locale. */
|
||||
char *
|
||||
DGETTEXT (domainname, msgid)
|
||||
const char *domainname;
|
||||
const char *msgid;
|
||||
{
|
||||
return DCGETTEXT (domainname, msgid, LC_MESSAGES);
|
||||
}
|
||||
|
||||
#ifdef _LIBC
|
||||
/* Alias for function name in GNU C Library. */
|
||||
weak_alias (__dgettext, dgettext);
|
||||
#endif
|
476
intl/finddomain.c
Normal file
476
intl/finddomain.c
Normal file
@ -0,0 +1,476 @@
|
||||
/* finddomain.c -- handle list of needed message catalogs
|
||||
Copyright (C) 1995 Software Foundation, Inc.
|
||||
Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; 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 <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined STDC_HEADERS || defined _LIBC
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
# else
|
||||
void free ();
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined HAVE_STRING_H || defined _LIBC
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#if !HAVE_STRCHR && !defined _LIBC
|
||||
# ifndef strchr
|
||||
# define strchr index
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined HAVE_UNISTD_H || defined _LIBC
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "gettext.h"
|
||||
#include "gettextP.h"
|
||||
#ifdef _LIBC
|
||||
# include <libintl.h>
|
||||
#else
|
||||
# include "libgettext.h"
|
||||
#endif
|
||||
|
||||
/* @@ end of prolog @@ */
|
||||
|
||||
#ifdef _LIBC
|
||||
/* Rename the non ANSI C functions. This is required by the standard
|
||||
because some ANSI C functions will require linking with this object
|
||||
file and the name space must not be polluted. */
|
||||
# define stpcpy __stpcpy
|
||||
#endif
|
||||
|
||||
/* Encoding of locale name parts. */
|
||||
#define CEN_REVISION 1
|
||||
#define CEN_SPONSOR 2
|
||||
#define CEN_SPECIAL 4
|
||||
#define XPG_CODESET 8
|
||||
#define TERRITORY 16
|
||||
#define CEN_AUDIENCE 32
|
||||
#define XPG_MODIFIER 64
|
||||
|
||||
#define CEN_SPECIFIC (CEN_REVISION|CEN_SPONSOR|CEN_SPECIAL|CEN_AUDIENCE)
|
||||
#define XPG_SPECIFIC (XPG_CODESET|XPG_MODIFIER)
|
||||
|
||||
|
||||
/* List of already loaded domains. */
|
||||
static struct loaded_domain *_nl_loaded_domains;
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
static struct loaded_domain *make_entry_rec __P ((const char *dirname,
|
||||
int mask,
|
||||
const char *language,
|
||||
const char *territory,
|
||||
const char *codeset,
|
||||
const char *modifier,
|
||||
const char *special,
|
||||
const char *sponsor,
|
||||
const char *revision,
|
||||
const char *domainname,
|
||||
int do_allocate));
|
||||
|
||||
|
||||
/* Return a data structure describing the message catalog described by
|
||||
the DOMAINNAME and CATEGORY parameters with respect to the currently
|
||||
established bindings. */
|
||||
struct loaded_domain *
|
||||
_nl_find_domain (dirname, locale, domainname)
|
||||
const char *dirname;
|
||||
char *locale;
|
||||
const char *domainname;
|
||||
{
|
||||
enum { undecided, xpg, cen } syntax;
|
||||
struct loaded_domain *retval;
|
||||
const char *language;
|
||||
const char *modifier = NULL;
|
||||
const char *territory = NULL;
|
||||
const char *codeset = NULL;
|
||||
const char *special = NULL;
|
||||
const char *sponsor = NULL;
|
||||
const char *revision = NULL;
|
||||
const char *alias_value = NULL;
|
||||
char *cp;
|
||||
int mask;
|
||||
|
||||
/* CATEGORYVALUE now possibly contains a colon separated list of
|
||||
locales. Each single locale can consist of up to four recognized
|
||||
parts for the XPG syntax:
|
||||
|
||||
language[_territory[.codeset]][@modifier]
|
||||
|
||||
and six parts for the CEN syntax:
|
||||
|
||||
language[_territory][+audience][+special][,sponsor][_revision]
|
||||
|
||||
Beside the first all of them are allowed to be missing. If the
|
||||
full specified locale is not found, the less specific one are
|
||||
looked for. The various part will be stripped of according to
|
||||
the following order:
|
||||
(1) revision
|
||||
(2) sponsor
|
||||
(3) special
|
||||
(4) codeset
|
||||
(5) territory
|
||||
(6) audience/modifier
|
||||
*/
|
||||
|
||||
/* If we have already tested for this locale entry there has to
|
||||
be one data set in the list of loaded domains. */
|
||||
retval = make_entry_rec (dirname, 0, locale, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, domainname, 0);
|
||||
if (retval != NULL)
|
||||
{
|
||||
/* We know something about this locale. */
|
||||
int cnt;
|
||||
|
||||
if (retval->decided == 0)
|
||||
_nl_load_domain (retval); /* @@@ */
|
||||
|
||||
if (retval->data != NULL)
|
||||
return retval;
|
||||
|
||||
for (cnt = 6; cnt >= 0; --cnt)
|
||||
{
|
||||
if (retval->successor[cnt] == 0)
|
||||
_nl_load_domain (retval->successor[cnt]);
|
||||
|
||||
if (retval->successor[cnt]->data != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
/* We really found some usable information. */
|
||||
return cnt >= 0 ? retval : NULL;
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* See whether the locale value is an alias. If yes its value
|
||||
*overwrites* the alias name. No test for the original value is
|
||||
done. */
|
||||
alias_value = _nl_expand_alias (locale);
|
||||
if (alias_value != NULL)
|
||||
{
|
||||
size_t len = strlen (alias_value) + 1;
|
||||
locale = (char *) malloc (len);
|
||||
if (locale == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy (locale, alias_value, len);
|
||||
}
|
||||
|
||||
/* Now we determine the single parts of the locale name. First
|
||||
look for the language. Termination symbols are `_' and `@' if
|
||||
we use XPG4 style, and `_', `+', and `,' if we use CEN syntax. */
|
||||
mask = 0;
|
||||
syntax = undecided;
|
||||
language = cp = locale;
|
||||
while (cp[0] != '\0' && cp[0] != '_' && cp[0] != '@'
|
||||
&& cp[0] != '+' && cp[0] != ',')
|
||||
++cp;
|
||||
|
||||
if (language == cp)
|
||||
/* This does not make sense: language has to be specified. Use
|
||||
this entry as it is without exploding. Perhaps it is an alias. */
|
||||
cp = strchr (language, '\0');
|
||||
else if (cp[0] == '_')
|
||||
{
|
||||
/* Next is the territory. */
|
||||
cp[0] = '\0';
|
||||
territory = ++cp;
|
||||
|
||||
while (cp[0] != '\0' && cp[0] != '.' && cp[0] != '@'
|
||||
&& cp[0] != '+' && cp[0] != ',' && cp[0] != '_')
|
||||
++cp;
|
||||
|
||||
mask |= TERRITORY;
|
||||
|
||||
if (cp[0] == '.')
|
||||
{
|
||||
/* Next is the codeset. */
|
||||
syntax = xpg;
|
||||
cp[0] = '\0';
|
||||
codeset = ++cp;
|
||||
|
||||
while (cp[0] != '\0' && cp[0] != '@')
|
||||
++cp;
|
||||
|
||||
mask |= XPG_CODESET;
|
||||
}
|
||||
}
|
||||
|
||||
if (cp[0] == '@' || (syntax != xpg && cp[0] == '+'))
|
||||
{
|
||||
/* Next is the modifier. */
|
||||
syntax = cp[0] == '@' ? xpg : cen;
|
||||
cp[0] = '\0';
|
||||
modifier = ++cp;
|
||||
|
||||
while (syntax == cen && cp[0] != '\0' && cp[0] != '+'
|
||||
&& cp[0] != ',' && cp[0] != '_')
|
||||
++cp;
|
||||
|
||||
mask |= XPG_MODIFIER | CEN_AUDIENCE;
|
||||
}
|
||||
|
||||
if (syntax != xpg && (cp[0] == '+' || cp[0] == ',' || cp[0] == '_'))
|
||||
{
|
||||
syntax = cen;
|
||||
|
||||
if (cp[0] == '+')
|
||||
{
|
||||
/* Next is special application (CEN syntax). */
|
||||
cp[0] = '\0';
|
||||
special = ++cp;
|
||||
|
||||
while (cp[0] != '\0' && cp[0] != ',' && cp[0] != '_')
|
||||
++cp;
|
||||
|
||||
mask |= CEN_SPECIAL;
|
||||
}
|
||||
|
||||
if (cp[0] == ',')
|
||||
{
|
||||
/* Next is sponsor (CEN syntax). */
|
||||
cp[0] = '\0';
|
||||
sponsor = ++cp;
|
||||
|
||||
while (cp[0] != '\0' && cp[0] != '_')
|
||||
++cp;
|
||||
|
||||
mask |= CEN_SPONSOR;
|
||||
}
|
||||
|
||||
if (cp[0] == '_')
|
||||
{
|
||||
/* Next is revision (CEN syntax). */
|
||||
cp[0] = '\0';
|
||||
revision = ++cp;
|
||||
|
||||
mask |= CEN_REVISION;
|
||||
}
|
||||
}
|
||||
|
||||
/* For CEN sytnax values it might be important to have the
|
||||
separator character in the file name, not for XPG syntax. */
|
||||
if (syntax == xpg)
|
||||
{
|
||||
if (territory[0] == '\0')
|
||||
mask &= ~TERRITORY;
|
||||
|
||||
if (codeset[0] == '\0')
|
||||
mask &= ~XPG_CODESET;
|
||||
|
||||
if (modifier[0] == '\0')
|
||||
mask &= ~XPG_MODIFIER;
|
||||
}
|
||||
|
||||
/* Create all possible locale entries which might be interested in
|
||||
generalzation. */
|
||||
retval = make_entry_rec (dirname, mask, language, territory, codeset,
|
||||
modifier, special, sponsor, revision,
|
||||
domainname, 1);
|
||||
if (retval == NULL)
|
||||
/* This means we are out of core. */
|
||||
return NULL;
|
||||
|
||||
if (retval->decided == 0)
|
||||
_nl_load_domain (retval);
|
||||
if (retval->data == NULL)
|
||||
{
|
||||
int cnt;
|
||||
for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
|
||||
{
|
||||
if (retval->successor[cnt]->decided == 0)
|
||||
_nl_load_domain (retval->successor[cnt]);
|
||||
if (retval->successor[cnt]->data != NULL)
|
||||
break;
|
||||
|
||||
/* Signal that locale is not available. */
|
||||
retval->successor[cnt] = NULL;
|
||||
}
|
||||
if (retval->successor[cnt] == NULL)
|
||||
retval = NULL;
|
||||
}
|
||||
|
||||
/* The room for an alias was dynamically allocated. Free it now. */
|
||||
if (alias_value != NULL)
|
||||
free (locale);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static struct loaded_domain *
|
||||
make_entry_rec (dirname, mask, language, territory, codeset, modifier,
|
||||
special, sponsor, revision, domain, do_allocate)
|
||||
const char *dirname;
|
||||
int mask;
|
||||
const char *language;
|
||||
const char *territory;
|
||||
const char *codeset;
|
||||
const char *modifier;
|
||||
const char *special;
|
||||
const char *sponsor;
|
||||
const char *revision;
|
||||
const char *domain;
|
||||
int do_allocate;
|
||||
{
|
||||
struct loaded_domain *retval, *last;
|
||||
char *filename, *cp;
|
||||
size_t entries;
|
||||
int cnt;
|
||||
|
||||
/* Allocate room for the full file name. */
|
||||
filename = (char *) malloc (strlen (dirname) + 1
|
||||
+ strlen (language)
|
||||
+ ((mask & TERRITORY) != 0
|
||||
? strlen (territory) : 0)
|
||||
+ ((mask & XPG_CODESET) != 0
|
||||
? strlen (codeset) : 0)
|
||||
+ ((mask & XPG_MODIFIER) != 0 ?
|
||||
strlen (modifier) : 0)
|
||||
+ ((mask & CEN_SPECIAL) != 0
|
||||
? strlen (special) : 0)
|
||||
+ ((mask & CEN_SPONSOR) != 0
|
||||
? strlen (sponsor) : 0)
|
||||
+ ((mask & CEN_REVISION) != 0
|
||||
? strlen (revision) : 0) + 1
|
||||
+ strlen (domain) + 1);
|
||||
|
||||
if (filename == NULL)
|
||||
return NULL;
|
||||
|
||||
retval = NULL;
|
||||
last = NULL;
|
||||
|
||||
/* We don't want libintl.a to depend on any other library. So we
|
||||
avoid the non-standard function stpcpy. In GNU C Library this
|
||||
function is available, though. Also allow the symbol HAVE_STPCPY
|
||||
to be defined. */
|
||||
#if !defined _LIBC && !defined HAVE_STPCPY
|
||||
# define stpcpy(p, s) \
|
||||
(strcpy (p, s), strchr (p, '\0'))
|
||||
#endif
|
||||
|
||||
/* Construct file name. */
|
||||
cp = stpcpy (filename, dirname);
|
||||
*cp++ = '/';
|
||||
cp = stpcpy (cp, language);
|
||||
|
||||
if ((mask & TERRITORY) != 0)
|
||||
{
|
||||
*cp++ = '_';
|
||||
cp = stpcpy (cp, territory);
|
||||
}
|
||||
if ((mask & XPG_CODESET) != 0)
|
||||
{
|
||||
*cp++ = '.';
|
||||
cp = stpcpy (cp, codeset);
|
||||
}
|
||||
if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
|
||||
{
|
||||
/* This component can be part of both syntaces but has different
|
||||
leading characters. For CEN we use `+', else `@'. */
|
||||
*cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
|
||||
cp = stpcpy (cp, modifier);
|
||||
}
|
||||
if ((mask & CEN_SPECIAL) != 0)
|
||||
{
|
||||
*cp++ = '+';
|
||||
cp = stpcpy (cp, special);
|
||||
}
|
||||
if ((mask & CEN_SPONSOR) != 0)
|
||||
{
|
||||
*cp++ = ',';
|
||||
cp = stpcpy (cp, sponsor);
|
||||
}
|
||||
if ((mask & CEN_REVISION) != 0)
|
||||
{
|
||||
*cp++ = '_';
|
||||
cp = stpcpy (cp, revision);
|
||||
}
|
||||
|
||||
*cp++ = '/';
|
||||
stpcpy (cp, domain);
|
||||
|
||||
/* Look in list of already loaded domains whether it is already
|
||||
available. */
|
||||
last = NULL;
|
||||
for (retval = _nl_loaded_domains; retval != NULL; retval = retval->next)
|
||||
{
|
||||
int compare = strcmp (retval->filename, filename);
|
||||
if (compare == 0)
|
||||
/* We found it! */
|
||||
break;
|
||||
if (compare < 0)
|
||||
{
|
||||
/* It's not in the list. */
|
||||
retval = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
last = retval;
|
||||
}
|
||||
|
||||
if (retval != NULL || do_allocate == 0)
|
||||
{
|
||||
free (filename);
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = (struct loaded_domain *) malloc (sizeof (*retval));
|
||||
if (retval == NULL)
|
||||
return NULL;
|
||||
|
||||
retval->filename = filename;
|
||||
retval->decided = 0;
|
||||
|
||||
if (last == NULL)
|
||||
{
|
||||
retval->next = _nl_loaded_domains;
|
||||
_nl_loaded_domains = retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval->next = last->next;
|
||||
last->next = retval;
|
||||
}
|
||||
|
||||
entries = 0;
|
||||
for (cnt = 126; cnt >= 0; --cnt)
|
||||
if (cnt < mask && (cnt & ~mask) == 0
|
||||
&& ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0))
|
||||
retval->successor[entries++] = make_entry_rec (dirname, cnt,
|
||||
language, territory,
|
||||
codeset, modifier,
|
||||
special, sponsor,
|
||||
revision, domain, 1);
|
||||
retval->successor[entries] = NULL;
|
||||
|
||||
return retval;
|
||||
}
|
70
intl/gettext.c
Normal file
70
intl/gettext.c
Normal file
@ -0,0 +1,70 @@
|
||||
/* gettext.c -- implementation of gettext(3) function
|
||||
Copyright (C) 1995 Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; 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
|
||||
|
||||
#ifdef _LIBC
|
||||
# define __need_NULL
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef STDC_HEADERS
|
||||
# include <stdlib.h> /* Just for NULL. */
|
||||
# else
|
||||
# ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
# else
|
||||
# define NULL 0
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _LIBC
|
||||
# include <libintl.h>
|
||||
#else
|
||||
# include "libgettext.h"
|
||||
#endif
|
||||
|
||||
/* @@ end of prolog @@ */
|
||||
|
||||
/* Names for the libintl functions are a problem. They must not clash
|
||||
with existing names and they should follow ANSI C. But this source
|
||||
code is also used in GNU C Library where the names have a __
|
||||
prefix. So we have to make a difference here. */
|
||||
#ifdef _LIBC
|
||||
# define GETTEXT __gettext
|
||||
# define DGETTEXT __dgettext
|
||||
#else
|
||||
# define GETTEXT gettext__
|
||||
# define DGETTEXT dgettext__
|
||||
#endif
|
||||
|
||||
/* Look up MSGID in the current default message catalog for the current
|
||||
LC_MESSAGES locale. If not found, returns MSGID itself (the default
|
||||
text). */
|
||||
char *
|
||||
GETTEXT (msgid)
|
||||
const char *msgid;
|
||||
{
|
||||
return DGETTEXT (NULL, msgid);
|
||||
}
|
||||
|
||||
#ifdef _LIBC
|
||||
/* Alias for function name in GNU C Library. */
|
||||
weak_alias (__gettext, gettext);
|
||||
#endif
|
105
intl/gettext.h
Normal file
105
intl/gettext.h
Normal file
@ -0,0 +1,105 @@
|
||||
/* gettext.h - internal header for GNU gettext internationalization functions
|
||||
Copyright (C) 1995 Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 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 _GETTEXT_H
|
||||
#define _GETTEXT_H 1
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if HAVE_LIMITS_H || _LIBC
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
/* @@ end of prolog @@ */
|
||||
|
||||
/* The magic number of the GNU message catalog format. */
|
||||
#define _MAGIC 0x950412de
|
||||
#define _MAGIC_SWAPPED 0xde120495
|
||||
|
||||
/* Revision number of the currently used .mo (binary) file format. */
|
||||
#define MO_REVISION_NUMBER 0
|
||||
|
||||
/* The following contortions are an attempt to use the C preprocessor
|
||||
to determine an unsigned integral type that is 32 bits wide. An
|
||||
alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
|
||||
doing that would require that the configure script compile and *run*
|
||||
the resulting executable. Locally running cross-compiled executables
|
||||
is usually not possible. */
|
||||
|
||||
#if __STDC__
|
||||
# define UINT_MAX_32_BITS 4294967295U
|
||||
#else
|
||||
# define UINT_MAX_32_BITS 0xFFFFFFFF
|
||||
#endif
|
||||
|
||||
/* If UINT_MAX isn't defined, assume it's a 32-bit type.
|
||||
This should be valid for all systems GNU cares about because
|
||||
that doesn't include 16-bit systems, and only modern systems
|
||||
(that certainly have <limits.h>) have 64+-bit integral types. */
|
||||
|
||||
#ifndef UINT_MAX
|
||||
# define UINT_MAX UINT_MAX_32_BITS
|
||||
#endif
|
||||
|
||||
#if UINT_MAX == UINT_MAX_32_BITS
|
||||
typedef unsigned nls_uint32;
|
||||
#else
|
||||
# if USHRT_MAX == UINT_MAX_32_BITS
|
||||
typedef unsigned short nls_uint32;
|
||||
# else
|
||||
# if ULONG_MAX == UINT_MAX_32_BITS
|
||||
typedef unsigned long nls_uint32;
|
||||
# else
|
||||
/* The following line is intended to throw an error. Using #error is
|
||||
not portable enough. */
|
||||
"Cannot determine unsigned 32-bit data type."
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/* Header for binary .mo file format. */
|
||||
struct mo_file_header
|
||||
{
|
||||
/* The magic number. */
|
||||
nls_uint32 magic;
|
||||
/* The revision number of the file format. */
|
||||
nls_uint32 revision;
|
||||
/* The number of strings pairs. */
|
||||
nls_uint32 nstrings;
|
||||
/* Offset of table with start offsets of original strings. */
|
||||
nls_uint32 orig_tab_offset;
|
||||
/* Offset of table with start offsets of translation strings. */
|
||||
nls_uint32 trans_tab_offset;
|
||||
/* Size of hashing table. */
|
||||
nls_uint32 hash_tab_size;
|
||||
/* Offset of first hashing entry. */
|
||||
nls_uint32 hash_tab_offset;
|
||||
};
|
||||
|
||||
struct string_desc
|
||||
{
|
||||
/* Length of addressed string. */
|
||||
nls_uint32 length;
|
||||
/* Offset of string in file. */
|
||||
nls_uint32 offset;
|
||||
};
|
||||
|
||||
/* @@ begin of epilog @@ */
|
||||
|
||||
#endif /* gettext.h */
|
76
intl/gettextP.h
Normal file
76
intl/gettextP.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* gettextP.h -- header describing internals of gettext library
|
||||
Copyright (C) 1995 Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef _GETTEXTP_H
|
||||
#define _GETTEXTP_H
|
||||
|
||||
/* @@ end of prolog @@ */
|
||||
|
||||
#ifndef __P
|
||||
# if __STDC__
|
||||
# define __P(args) args
|
||||
# else
|
||||
# define __P(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef W
|
||||
# define W(flag, data) ((flag) ? SWAP (data) : (data))
|
||||
#endif
|
||||
|
||||
static inline nls_uint32
|
||||
SWAP (i)
|
||||
nls_uint32 i;
|
||||
{
|
||||
return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
|
||||
}
|
||||
|
||||
|
||||
struct loaded_domain
|
||||
{
|
||||
struct loaded_domain *next;
|
||||
struct loaded_domain *successor[31];
|
||||
|
||||
const char *filename;
|
||||
int decided;
|
||||
|
||||
const char *data;
|
||||
int must_swap;
|
||||
nls_uint32 nstrings;
|
||||
struct string_desc *orig_tab;
|
||||
struct string_desc *trans_tab;
|
||||
nls_uint32 hash_size;
|
||||
nls_uint32 *hash_tab;
|
||||
};
|
||||
|
||||
struct binding
|
||||
{
|
||||
struct binding *next;
|
||||
char *domainname;
|
||||
char *dirname;
|
||||
};
|
||||
|
||||
struct loaded_domain *_nl_find_domain __P ((const char *__dirname,
|
||||
char *__locale,
|
||||
const char *__domainname));
|
||||
void _nl_load_domain __P ((struct loaded_domain *__domain));
|
||||
|
||||
const char *_nl_expand_alias __P ((const char *__name));
|
||||
|
||||
/* @@ begin of epilog @@ */
|
||||
|
||||
#endif /* gettextP.h */
|
56
intl/hash-string.h
Normal file
56
intl/hash-string.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* hash-string - Implements a string hashing function.
|
||||
Copyright (C) 1995 Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifdef HAVE_VALUES_H
|
||||
# include <values.h>
|
||||
#endif
|
||||
|
||||
/* @@ end of prolog @@ */
|
||||
|
||||
#ifndef BITSPERBYTE
|
||||
# define BITSPERBYTE 8
|
||||
#endif
|
||||
|
||||
#ifndef LONGBITS
|
||||
# define LONGBITS (sizeof (long) * BITSPERBYTE)
|
||||
#endif /* LONGBITS */
|
||||
|
||||
/* Defines the so called `hashpjw' function by P.J. Weinberger
|
||||
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
|
||||
1986, 1987 Bell Telephone Laboratories, Inc.] */
|
||||
static inline unsigned long
|
||||
hash_string (str_param)
|
||||
const char *str_param;
|
||||
{
|
||||
unsigned long hval, g;
|
||||
const char *str = str_param;
|
||||
|
||||
/* Compute the hash value for the given string. */
|
||||
hval = 0;
|
||||
while (*str != '\0')
|
||||
{
|
||||
hval <<= 4;
|
||||
hval += (unsigned long) *str++;
|
||||
g = hval & ((unsigned long) 0xf << (LONGBITS - 4));
|
||||
if (g != 0)
|
||||
{
|
||||
hval ^= g >> (LONGBITS - 8);
|
||||
hval ^= g;
|
||||
}
|
||||
}
|
||||
return hval;
|
||||
}
|
184
intl/loadmsgcat.c
Normal file
184
intl/loadmsgcat.c
Normal file
@ -0,0 +1,184 @@
|
||||
/* loadmsgcat.c -- load needed message catalogs
|
||||
Copyright (C) 1995 Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; 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 <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined STDC_HEADERS || defined _LIBC
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if defined HAVE_UNISTD_H || defined _LIBC
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if (defined HAVE_MMAP && defined HAVE_MUNMAP) || defined _LIBC
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "gettext.h"
|
||||
#include "gettextP.h"
|
||||
|
||||
/* @@ end of prolog @@ */
|
||||
|
||||
#ifdef _LIBC
|
||||
/* Rename the non ANSI C functions. This is required by the standard
|
||||
because some ANSI C functions will require linking with this object
|
||||
file and the name space must not be polluted. */
|
||||
# define fstat __fstat
|
||||
# define open __open
|
||||
# define close __close
|
||||
# define read __read
|
||||
# define mmap __mmap
|
||||
# define munmap __munmap
|
||||
#endif
|
||||
|
||||
/* We need a sign, whether a new catalog was loaded, which can be associated
|
||||
with all translations. This is important if the translations are
|
||||
cached by one of GCC's features. */
|
||||
int _nl_msg_cat_cntr;
|
||||
|
||||
|
||||
/* Load the message catalogs specified by FILENAME. If it is no valid
|
||||
message catalog do nothing. */
|
||||
void
|
||||
_nl_load_domain (domain)
|
||||
struct loaded_domain *domain;
|
||||
{
|
||||
int fd;
|
||||
struct stat st;
|
||||
struct mo_file_header *data = (struct mo_file_header *) -1;
|
||||
#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
|
||||
|| defined _LIBC
|
||||
int use_mmap = 0;
|
||||
#endif
|
||||
|
||||
domain->decided = 1;
|
||||
domain->data = NULL;
|
||||
|
||||
/* Try to open the addressed file. */
|
||||
fd = open (domain->filename, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
/* We must know about the size of the file. */
|
||||
if (fstat (fd, &st) != 0
|
||||
&& st.st_size < (off_t) sizeof (struct mo_file_header))
|
||||
{
|
||||
/* Something went wrong. */
|
||||
close (fd);
|
||||
return;
|
||||
}
|
||||
|
||||
#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
|
||||
|| defined _LIBC
|
||||
/* Now we are ready to load the file. If mmap() is available we try
|
||||
this first. If not available or it failed we try to load it. */
|
||||
data = (struct mo_file_header *) mmap (NULL, st.st_size, PROT_READ,
|
||||
MAP_PRIVATE, fd, 0);
|
||||
|
||||
if (data != (struct mo_file_header *) -1)
|
||||
{
|
||||
/* mmap() call was successful. */
|
||||
close (fd);
|
||||
use_mmap = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the data is not yet available (i.e. mmap'ed) we try to load
|
||||
it manually. */
|
||||
if (data == (struct mo_file_header *) -1)
|
||||
{
|
||||
off_t to_read;
|
||||
char *read_ptr;
|
||||
|
||||
data = (struct mo_file_header *) malloc (st.st_size);
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
to_read = st.st_size;
|
||||
read_ptr = (char *) data;
|
||||
do
|
||||
{
|
||||
long int nb = (long int) read (fd, read_ptr, to_read);
|
||||
if (nb == -1)
|
||||
{
|
||||
close (fd);
|
||||
return;
|
||||
}
|
||||
|
||||
read_ptr += nb;
|
||||
to_read -= nb;
|
||||
}
|
||||
while (to_read > 0);
|
||||
|
||||
close (fd);
|
||||
}
|
||||
|
||||
/* Using the magic number we can test whether it really is a message
|
||||
catalog file. */
|
||||
if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED)
|
||||
{
|
||||
/* The magic number is wrong: not a message catalog file. */
|
||||
#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
|
||||
|| defined _LIBC
|
||||
if (use_mmap)
|
||||
munmap ((caddr_t) data, st.st_size);
|
||||
else
|
||||
#endif
|
||||
free (data);
|
||||
return;
|
||||
}
|
||||
|
||||
domain->data = (char *) data;
|
||||
domain->must_swap = data->magic != _MAGIC;
|
||||
|
||||
/* Fill in the information about the available tables. */
|
||||
switch (W (domain->must_swap, data->revision))
|
||||
{
|
||||
case 0:
|
||||
domain->nstrings = W (domain->must_swap, data->nstrings);
|
||||
domain->orig_tab = (struct string_desc *)
|
||||
((char *) data + W (domain->must_swap, data->orig_tab_offset));
|
||||
domain->trans_tab = (struct string_desc *)
|
||||
((char *) data + W (domain->must_swap, data->trans_tab_offset));
|
||||
domain->hash_size = W (domain->must_swap, data->hash_tab_size);
|
||||
domain->hash_tab = (nls_uint32 *)
|
||||
((char *) data + W (domain->must_swap, data->hash_tab_offset));
|
||||
break;
|
||||
default:
|
||||
/* This is an illegal revision. */
|
||||
#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
|
||||
|| defined _LIBC
|
||||
if (use_mmap)
|
||||
munmap ((caddr_t) data, st.st_size);
|
||||
else
|
||||
#endif
|
||||
free (data);
|
||||
domain->data = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Show that one domain is changed. This might make some cached
|
||||
translation invalid. */
|
||||
++_nl_msg_cat_cntr;
|
||||
}
|
315
intl/localealias.c
Normal file
315
intl/localealias.c
Normal file
@ -0,0 +1,315 @@
|
||||
/* localealias.c -- handle aliases for locale names
|
||||
Copyright (C) 1995 Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; 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 <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define alloca __builtin_alloca
|
||||
#else
|
||||
# if defined HAVE_ALLOCA_H || defined _LIBC
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# ifdef _AIX
|
||||
#pragma alloca
|
||||
# else
|
||||
# ifndef alloca
|
||||
char *alloca ();
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined STDC_HEADERS || defined _LIBC
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
char *getenv ();
|
||||
# ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
# else
|
||||
void free ();
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined HAVE_STRING_H || defined _LIBC
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#if !HAVE_STRCHR && !defined _LIBC
|
||||
# ifndef strchr
|
||||
# define strchr index
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "gettext.h"
|
||||
#include "gettextP.h"
|
||||
|
||||
/* @@ end of prolog @@ */
|
||||
|
||||
#ifdef _LIBC
|
||||
/* Rename the non ANSI C functions. This is required by the standard
|
||||
because some ANSI C functions will require linking with this object
|
||||
file and the name space must not be polluted. */
|
||||
# define strcasecmp __strcasecmp
|
||||
#endif
|
||||
|
||||
struct alias_map
|
||||
{
|
||||
const char *alias;
|
||||
const char *value;
|
||||
};
|
||||
|
||||
|
||||
static struct alias_map *map;
|
||||
static size_t nmap = 0;
|
||||
static size_t maxmap = 0;
|
||||
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
static size_t read_alias_file __P ((const char *fname, int fname_len));
|
||||
static void extend_alias_table __P ((void));
|
||||
static int alias_compare __P ((const struct alias_map *map1,
|
||||
const struct alias_map *map2));
|
||||
|
||||
|
||||
const char *
|
||||
_nl_expand_alias (name)
|
||||
const char *name;
|
||||
{
|
||||
static const char *locale_alias_path = LOCALE_ALIAS_PATH;
|
||||
struct alias_map *retval;
|
||||
size_t added;
|
||||
|
||||
do
|
||||
{
|
||||
struct alias_map item;
|
||||
|
||||
item.alias = name;
|
||||
|
||||
if (nmap > 0)
|
||||
retval = (struct alias_map *) bsearch (&item, map, nmap,
|
||||
sizeof (struct alias_map),
|
||||
(int (*) (const void *,
|
||||
const void *))
|
||||
alias_compare);
|
||||
else
|
||||
retval = NULL;
|
||||
|
||||
/* We really found an alias. Return the value. */
|
||||
if (retval != NULL)
|
||||
return retval->value;
|
||||
|
||||
/* Perhaps we can find another alias file. */
|
||||
added = 0;
|
||||
while (added == 0 && locale_alias_path[0] != '\0')
|
||||
{
|
||||
const char *start;
|
||||
|
||||
while (locale_alias_path[0] != '\0' && locale_alias_path[0] == ':')
|
||||
++locale_alias_path;
|
||||
start = locale_alias_path;
|
||||
|
||||
while (locale_alias_path[0] != '\0' && locale_alias_path[0] != ':')
|
||||
++locale_alias_path;
|
||||
|
||||
if (start < locale_alias_path)
|
||||
added = read_alias_file (start, locale_alias_path - start);
|
||||
}
|
||||
}
|
||||
while (added != 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
read_alias_file (fname, fname_len)
|
||||
const char *fname;
|
||||
int fname_len;
|
||||
{
|
||||
FILE *fp;
|
||||
char *full_fname;
|
||||
size_t added;
|
||||
|
||||
full_fname = (char *) alloca (fname_len + sizeof ("/locale.alias"));
|
||||
sprintf (full_fname, "%.*s/locale.alias", fname_len, fname);
|
||||
|
||||
fp = fopen (full_fname, "r");
|
||||
if (fp == NULL)
|
||||
return 0;
|
||||
|
||||
added = 0;
|
||||
while (!feof (fp))
|
||||
{
|
||||
/* It is a reasonable approach to use a fix buffer here because
|
||||
a) we are only interested in the first two fields
|
||||
b) these fields must be usable as file names and so must not
|
||||
be that long
|
||||
*/
|
||||
char buf[BUFSIZ];
|
||||
char *alias;
|
||||
char *value;
|
||||
char *cp;
|
||||
|
||||
if (fgets (buf, BUFSIZ, fp) == NULL)
|
||||
/* EOF reached. */
|
||||
break;
|
||||
|
||||
cp = buf;
|
||||
/* Ignore leading white space. */
|
||||
while (isspace (cp[0]))
|
||||
++cp;
|
||||
|
||||
/* A leading '#' signals a comment line. */
|
||||
if (cp[0] != '\0' && cp[0] != '#')
|
||||
{
|
||||
alias = cp++;
|
||||
while (cp[0] != '\0' && !isspace (cp[0]))
|
||||
++cp;
|
||||
/* Terminate alias name. */
|
||||
if (cp[0] != '\0')
|
||||
*cp++ = '\0';
|
||||
|
||||
/* Now look for the beginning of the value. */
|
||||
while (isspace (cp[0]))
|
||||
++cp;
|
||||
|
||||
if (cp[0] != '\0')
|
||||
{
|
||||
char *tp;
|
||||
size_t len;
|
||||
|
||||
value = cp++;
|
||||
while (cp[0] != '\0' && !isspace (cp[0]))
|
||||
++cp;
|
||||
/* Terminate value. */
|
||||
if (cp[0] == '\n')
|
||||
{
|
||||
/* This has to be done to make the following test
|
||||
for the end of line possible. We are looking for
|
||||
the terminating '\n' which do not overwrite here. */
|
||||
*cp++ = '\0';
|
||||
*cp = '\n';
|
||||
}
|
||||
else if (cp[0] != '\0')
|
||||
*cp++ = '\0';
|
||||
|
||||
if (nmap >= maxmap)
|
||||
extend_alias_table ();
|
||||
|
||||
/* We cannot depend on strdup available in the libc. Sigh! */
|
||||
len = strlen (alias) + 1;
|
||||
tp = (char *) malloc (len);
|
||||
if (tp == NULL)
|
||||
return added;
|
||||
memcpy (tp, alias, len);
|
||||
map[nmap].alias = tp;
|
||||
|
||||
len = strlen (value) + 1;
|
||||
tp = (char *) malloc (len);
|
||||
if (tp == NULL)
|
||||
return added;
|
||||
memcpy (tp, value, len);
|
||||
map[nmap].value = tp;
|
||||
|
||||
++nmap;
|
||||
++added;
|
||||
}
|
||||
}
|
||||
|
||||
/* Possibily not the whole line fits into the buffer. Ignore
|
||||
the rest of the line. */
|
||||
while (strchr (cp, '\n') == NULL)
|
||||
{
|
||||
cp = buf;
|
||||
if (fgets (buf, BUFSIZ, fp) == NULL)
|
||||
/* Make sure the inner loop will be left. The outer loop
|
||||
will exit at the `feof' test. */
|
||||
*cp = '\n';
|
||||
}
|
||||
}
|
||||
|
||||
/* Should we test for ferror()? I think we have to silently ignore
|
||||
errors. --drepper */
|
||||
fclose (fp);
|
||||
|
||||
if (added > 0)
|
||||
qsort (map, nmap, sizeof (struct alias_map),
|
||||
(int (*) (const void *, const void *)) alias_compare);
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
extend_alias_table ()
|
||||
{
|
||||
size_t new_size;
|
||||
struct alias_map *new_map;
|
||||
|
||||
new_size = maxmap == 0 ? 100 : 2 * maxmap;
|
||||
new_map = (struct alias_map *) malloc (new_size
|
||||
* sizeof (struct alias_map));
|
||||
if (new_map == NULL)
|
||||
/* Simply don't extend: we don't have any more core. */
|
||||
return;
|
||||
|
||||
memcpy (new_map, map, nmap * sizeof (struct alias_map));
|
||||
|
||||
if (maxmap != 0)
|
||||
free (map);
|
||||
|
||||
map = new_map;
|
||||
maxmap = new_size;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
alias_compare (map1, map2)
|
||||
const struct alias_map *map1;
|
||||
const struct alias_map *map2;
|
||||
{
|
||||
#if defined _LIBC || defined HAVE_STRCASECMP
|
||||
return strcasecmp (map1->alias, map2->alias);
|
||||
#else
|
||||
const unsigned char *p1 = (const unsigned char *) map1->alias;
|
||||
const unsigned char *p2 = (const unsigned char *) map2->alias;
|
||||
unsigned char c1, c2;
|
||||
|
||||
if (p1 == p2)
|
||||
return 0;
|
||||
|
||||
do
|
||||
{
|
||||
/* I know this seems to be odd but the tolower() function in
|
||||
some systems libc cannot handle nonalpha characters. */
|
||||
c1 = isalpha (*p1) ? tolower (*p1) : *p1;
|
||||
c2 = isalpha (*p2) ? tolower (*p2) : *p2;
|
||||
if (c1 == '\0')
|
||||
break;
|
||||
}
|
||||
while (c1 == c2);
|
||||
|
||||
return c1 - c2;
|
||||
#endif
|
||||
}
|
97
intl/textdomain.c
Normal file
97
intl/textdomain.c
Normal file
@ -0,0 +1,97 @@
|
||||
/* textdomain.c -- implementation of the textdomain(3) function
|
||||
Copyright (C) 1995 Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; 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
|
||||
|
||||
#if defined STDC_HEADERS || defined _LIBC
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if defined STDC_HEADERS || defined HAVE_STRING_H || defined _LIBC
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#ifdef _LIBC
|
||||
# include <libintl.h>
|
||||
#else
|
||||
# include "libgettext.h"
|
||||
#endif
|
||||
|
||||
/* @@ end of prolog @@ */
|
||||
|
||||
/* Name of the default text domain. */
|
||||
extern const char _nl_default_default_domain[];
|
||||
|
||||
/* Default text domain in which entries for gettext(3) are to be found. */
|
||||
extern const char *_nl_current_default_domain;
|
||||
|
||||
|
||||
/* Names for the libintl functions are a problem. They must not clash
|
||||
with existing names and they should follow ANSI C. But this source
|
||||
code is also used in GNU C Library where the names have a __
|
||||
prefix. So we have to make a difference here. */
|
||||
#ifdef _LIBC
|
||||
# define TEXTDOMAIN __textdomain
|
||||
#else
|
||||
# define TEXTDOMAIN textdomain__
|
||||
#endif
|
||||
|
||||
/* Set the current default message catalog to DOMAINNAME.
|
||||
If DOMAINNAME is null, return the current default.
|
||||
If DOMAINNAME is "", reset to the default of "messages". */
|
||||
char *
|
||||
TEXTDOMAIN (domainname)
|
||||
const char *domainname;
|
||||
{
|
||||
char *old;
|
||||
|
||||
/* A NULL pointer requests the current setting. */
|
||||
if (domainname == NULL)
|
||||
return (char *) _nl_current_default_domain;
|
||||
|
||||
old = (char *) _nl_current_default_domain;
|
||||
|
||||
/* If domain name is the null string set to default domain "messages". */
|
||||
if (domainname[0] == '\0'
|
||||
|| strcmp (domainname, _nl_default_default_domain) == 0)
|
||||
_nl_current_default_domain = _nl_default_default_domain;
|
||||
else
|
||||
{
|
||||
/* If the following malloc fails `_nl_current_default_domain'
|
||||
will be NULL. This value will be returned and so signals we
|
||||
are out of core. */
|
||||
size_t len = strlen (domainname) + 1;
|
||||
char *cp = (char *) malloc (len);
|
||||
if (cp != NULL)
|
||||
memcpy (cp, domainname, len);
|
||||
_nl_current_default_domain = cp;
|
||||
}
|
||||
|
||||
if (old != _nl_default_default_domain)
|
||||
free (old);
|
||||
|
||||
return (char *) _nl_current_default_domain;
|
||||
}
|
||||
|
||||
#ifdef _LIBC
|
||||
/* Alias for function name in GNU C Library. */
|
||||
weak_alias (__textdomain, textdomain);
|
||||
#endif
|
@ -42,13 +42,13 @@ _dl_sysdep_start (void **start_argptr,
|
||||
|
||||
user_entry = (Elf32_Addr) &_start;
|
||||
_dl_argc = *(int *) start_argptr;
|
||||
_dl_argv = start_argptr + 1;
|
||||
_dl_argv = (char **) start_argptr + 1;
|
||||
_environ = &_dl_argv[_dl_argc + 1];
|
||||
start_argptr = (void **) _environ;
|
||||
while (*start_argptr)
|
||||
++start_argptr;
|
||||
|
||||
for (av = ++start_argptr; av->a_type != AT_NULL; ++av)
|
||||
for (av = (void *) ++start_argptr; av->a_type != AT_NULL; ++av)
|
||||
switch (av->a_type)
|
||||
{
|
||||
case AT_PHDR:
|
||||
@ -77,7 +77,7 @@ _dl_sysdep_start (void **start_argptr,
|
||||
_dl_secure = uid != euid || gid != egid;
|
||||
|
||||
(*dl_main) (phdr, phnum, &user_entry);
|
||||
start_argptr[-1] = (void *) user_entry;
|
||||
return user_entry;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -182,15 +182,16 @@ _dl_start_user:\n\
|
||||
addl $_GLOBAL_OFFSET_TABLE_+[.-0b], %ebx\n\
|
||||
# See if we were run as a command with the executable file\n\
|
||||
# name as an extra leading argument.\n\
|
||||
movl rtld_command@GOT(%ebx), %eax\n\
|
||||
movl _dl_skip_args@GOT(%ebx), %eax\n\
|
||||
movl (%eax),%eax\n\
|
||||
testl %eax,%eax\n\
|
||||
jz 0f\n\
|
||||
# Pop the original argument count, decrement it, and replace\n\
|
||||
# the original first argument pointer with the new count.\n\
|
||||
popl %eax\n\
|
||||
decl %eax\n\
|
||||
movl %eax,(%esp)\n\
|
||||
# Pop the original argument count.\n\
|
||||
popl %ecx\n\
|
||||
# Subtract _dl_skip_args from it.\n\
|
||||
subl %eax, %ecx\n\
|
||||
# Adjust the stack pointer to skip _dl_skip_args words.\n\
|
||||
leal (%esp,%eax,4), %esp\n\
|
||||
# Push back the modified argument count.\n\
|
||||
pushl %ecx\n\
|
||||
# Call _dl_init_next to return the address of an initializer\n\
|
||||
# function to run.\n\
|
||||
0: call _dl_init_next@PLT\n\
|
||||
|
Loading…
Reference in New Issue
Block a user