diff options
| author | itojun <itojun@NetBSD.org> | 2000-10-31 10:45:04 +0000 |
|---|---|---|
| committer | itojun <itojun@NetBSD.org> | 2000-10-31 10:45:04 +0000 |
| commit | bb42e65bfecc3a76253c9b8889051cfe941a4b9a (patch) | |
| tree | a911cb364c6dead82bf2de14b4bf9ca7ac12aa48 | |
| parent | ef28de501182943a2433b9a2fd6127dafe6e3583 (diff) | |
BSD-licensed libintl, fully compatible with GNU libintl (in GNU gettext).
from Citrus project xpg4dl repository.
| -rw-r--r-- | lib/libintl/Makefile | 19 | ||||
| -rw-r--r-- | lib/libintl/gettext.3 | 390 | ||||
| -rw-r--r-- | lib/libintl/gettext.c | 589 | ||||
| -rw-r--r-- | lib/libintl/libintl.h | 47 | ||||
| -rw-r--r-- | lib/libintl/libintl_local.h | 75 | ||||
| -rw-r--r-- | lib/libintl/pathnames.h | 29 | ||||
| -rw-r--r-- | lib/libintl/shlib_version | 5 | ||||
| -rw-r--r-- | lib/libintl/textdomain.c | 91 |
8 files changed, 1245 insertions, 0 deletions
diff --git a/lib/libintl/Makefile b/lib/libintl/Makefile new file mode 100644 index 00000000000..e1e96df1d78 --- /dev/null +++ b/lib/libintl/Makefile @@ -0,0 +1,19 @@ +# $NetBSD: Makefile,v 1.1.1.1 2000/10/31 10:45:04 itojun Exp $ + +.include <bsd.own.mk> + +LIB= intl +SRCS= gettext.c textdomain.c +INCS= libintl.h +INCSDIR=/usr/include + +#CFLAGS+=-g +CPPFLAGS+=-I${.CURDIR} + +MAN= gettext.3 +MLINKS= gettext.3 dgettext.3 gettext.3 dcgettext.3 \ + gettext.3 ngettext.3 gettext.3 dngettext.3 \ + gettext.3 dcngettext.3 gettext.3 textdomain.3 \ + gettext.3 bindtextdomain.3 gettext.3 bind_textdomain_codeset.3 + +.include <bsd.lib.mk> diff --git a/lib/libintl/gettext.3 b/lib/libintl/gettext.3 new file mode 100644 index 00000000000..12862c72859 --- /dev/null +++ b/lib/libintl/gettext.3 @@ -0,0 +1,390 @@ +.\" $NetBSD: gettext.3,v 1.1.1.1 2000/10/31 10:45:05 itojun Exp $ +.\" +.\" Copyright (c) 2000 Citrus Project, +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd October 20, 2000 +.Dt GETTEXT 3 +.Os +.Sh NAME +.Nm gettext , +.Nm dgettext , +.Nm ngettext , +.Nm dngettext , +.Nm textdomain , +.Nm bindtextdomain , +.Nm bind_textdomain_codeset , +.Nm dcgettext , +.Nm dcngettext +.Nd message handling functions +.Sh LIBRARY +libintl +.Sh SYNOPSIS +.Fd #include <libintl.h> +.Ft char * +.Fn gettext "const char *msgid" +.Ft char * +.Fn dgettext "const char *domainname" "const char *msgid" +.Ft char * +.Fn ngettext "const char *domainname" "const char *msgid" "unsigned long int n" +.Ft char * +.Fn dngettext "const char *domainname" "const char *msgid1" "const char *msgid2" "unsigned long int n" +.Ft char * +.Fn textdomain "const char *domainname" +.Ft char * +.Fn bindtextdomain "const char *domainname" "const char *dirname" +.Ft char * +.Fn bind_textdomain_codeset "const char *domainname" "const char *codeset" +.Fd #include <libintl.h> +.Fd #include <locale.h> +.Ft char * +.Fn dcgettext "const char *domainname" "const char *msgid" "int category" +.Ft char * +.Fn dcngettext "const char *domainname" "const char *msgid1" "const char *msgid2" "unsigned long int n" "int category" +.Sh DESCRIPTION +The +.Fn gettext , +.Fn dgettext , +and +.Fn dcgettext +functions attempt to retrieve a +target string based on the specified +.Fa msgid +argument within the context of a +specific domain and the current locale. +The length of strings returned by +.Fn gettext , +.Fn dgettext , +and +.fn dcgettext +is undetermined until the function is +called. +The +.Fa msgid +argument is a null-terminated string. +.Pp +The +.Fn ngettext , +.Fn dngettext +and +.Fn dcngettext +functions are equivalent to +.Fn gettext , +.Fn dgettext +and +.Fn dcgettext , +respectively, except for the handling of +plural forms. +The +.Fn ngettext , +.Fn dngettext +and +.Fn dcngettext +searches for the +message string using the +.Fa msgid1 +argument as the key, using the argument +.Fa n +to +determine the plural form. +If no message catalogs are found, +.Fa msgid1 +is returned +if +.Fa n Li == 1 , +otherwise +.Fa msgid2 +is returned. +.Pp +The +.Dv LANGUAGE +environment variable is examined first to determine the message +catalogs to be used. +The value of the +.Dv LANGUAGE +environment variable is a list +of locale names separated by colon (:) character. +If the +.Dv LANGUAGE +environment +variable is defined, each locale name is tried in the specified order and if a +message catalog containing the requested message is found, the message is +returned. +If the +.Dv LANGUAGE +environment variable is defined but failed to locate +a message catalog, the +.Fa msgid +string will be returned. +.Pp +If the +.Dv LANGUAGE +environment variable is not defined, +.Dv LC_ALL , +.Dv LC_xxx +and +.Dv LANG +environment variables are examined to locate the message catalog, following the +convention used by the +.Xr setlocale 3 +function. +.Pp +The pathname used to locate the message catalog is +.Pa dirname/locale/category/domainname.mo, +where dirname is the directory specified by +.Fn bindtextdomain , +locale is a locale name determined by the definition of environment variables, +.Fa category +is +.Dv LC_MESSAGES +if +.Fn gettext , +.Fn ngettext , +.Fn dgettext +or +.Fn dngettext +is +called, otherwise +.Dv LC_xxx +where the name is the same as the locale category name +specified by the +.Fa category +argument of +.Fn dcgettext +or +.Fn dcngettext . +.Fa domainname +is the name of the domain specified by +.Fn textdomain +or the +.Fa domainname +argument of +.Fn dgettext , +.Fn dngettext , +.Fn dcgettext +or +.Fn dcngettext . +.Pp +For +.Fn gettext +and +.Fn ngettext , +the domain used is set by the last valid call to +.Fn textdomain . +If a valid call to +.Fn textdomain +has not been made, the default +domain (called messages) is used. +.Pp +For +.Fn dgettext , +.Fn dngettext , +.Fn dcgettext +and +.Fn dcngettext , +the domain used is +specified by the +.Fa domainname +argument. +The +.Fa domainname +argument is equivalent in +syntax and meaning to the +.Fa domainname +argument to +.Fn textdomain , +except that the +selection of the domain is valid only for the duration of the +.Fn dgettext , +.Fn dngettext , +.Fn dcgettext +or +.Fn dcngettext +function call. +.Pp +The +.Fn dcgettext +and +.Fn dcngettext +functions require additional argument +.Fa category +for retrieving message string for other than +.Dv LC_MESSAGES +category. +Available value for the +.Fa category +argument are +.Dv LC_CTYPE , +.Dv LC_COLLATE , +.Dv LC_MESSAGES , +.Dv LC_MONETARY , +.Dv LC_NUMERIC +and +.Dv LC_TIME . +The call of +.Fn dcgettext "domainname" "msgid" "LC_MESSAGES" +is equivalent to +.Fn dgettext "domainname" "msgid" . +Note that +.Dv LC_ALL +must not be used. +.Pp +The +.Fn textdomain +function sets or queries the name of the current domain of the +active +.Dv LC_MESSAGES +locale category. +The +.Fa domainname +argument is a +null-terminated string that can contain only the characters allowed in legal +filenames. +.Pp +The +.Fa domainname +argument is the unique name of a domain on the system. +If there +are multiple versions of the same domain on one system, namespace collisions +can be avoided by using +.Fn bindtextdomain . +If +.Fn textdomain +is not called, a +default domain is selected. +The setting of domain made by the last valid call +to +.Fn textdomain +remains valid across subsequent calls to +.Xr setlocale 3 , +and +.Fn gettext . +.Pp +The +.Fa domainname +argument is applied to the currently active LC_MESSAGES locale. +.Pp +The current setting of the domain can be queried without affecting the current +state of the domain by calling +.Fn textdomain +with +.Fa domainname +set to the null pointer. +Calling +.Fn textdomain +with a +.Fa domainname +argument of a null string sets +the domain to the default domain +.Pq messages . +.Pp +The +.Fn bindtextdomain +function binds the path predicate for a message domain +.Fa domainname +to the value contained in dirname. +If +.Fa domainname +is a non-empty +string and has not been bound previously, +.Fn bindtextdomain +binds +.Fa domainname +with +.Fa dirname . +.Pp +If +.Fa domainname +is a non-empty string and has been bound previously, +.Fn bindtextdomain +replaces the old binding with dirname. +The dirname argument +can be an absolute or relative pathname being resolved when +.Fn gettext , +.Fn ngettext , +.Fn dgettext , +.Fn dngettext , +.Fn dcgettext , +or +.Fn dcngettext +are called. +If +.Fa domainname +is a null pointer or an empty string, +.Fn bindtextdomain +returns null pointer. +If +.Fn bindtextdomain +is not called, implementation-defined default directory is used. +.Pp +The +.Fn bind_textdomain_codeset +function can be used to specify the output +.Fa codeset +for message catalogs for domain +.Fa domainname . +The +.Fa codeset +argument must +be a valid codeset name which can be used for the +.Xr iconv_open 3 +function. +.Pp +If the +.Fa codeset +argument is the null pointer, +.Fn bind_textdomain_codeset +returns the currently selected +.Fa codeset +for the domain with the name +.Fa domainname . +It returns null pointer if no +.Fa codeset +has yet been selected. +.Pp +The +.Fn bind_textdomain_codeset +function can be used several times. +If used multiple times, with the same +.Fa domainname +argument, +the later call overrides the +settings made by the earlier one. +.Pp +The +.Fn bind_textdomain_codeset +function returns a pointer to a string containing +the name of the selected +.Fa codeset . +.\".Sh "RETURN VALUES" +.\".Sh EXAMPLES +.Sh SEE ALSO +.Xr setlocale 3 +.\".Sh STANDARDS +.Sh HISTORY +The functions are implemented by Citrus project, +based on the documentations for GNU gettext. +.Sh BUGS +The text was ripped off from Annex C of +.Dq LI18NUX 2000 Globalization Specification Version 1.0 . diff --git a/lib/libintl/gettext.c b/lib/libintl/gettext.c new file mode 100644 index 00000000000..57129b33b00 --- /dev/null +++ b/lib/libintl/gettext.c @@ -0,0 +1,589 @@ +/* $NetBSD: gettext.c,v 1.1.1.1 2000/10/31 10:45:04 itojun Exp $ */ + +/*- + * Copyright (c) 2000 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: gettext.c,v 1.1.1.1 2000/10/31 10:45:04 itojun Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/uio.h> + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#if 0 +#include <util.h> +#endif +#include <libintl.h> +#include <locale.h> +#include "libintl_local.h" +#include "pathnames.h" + +static struct mohandle mohandle; + +static const char *lookup_category __P((int)); +static const char *split_locale __P((const char *)); +static const char *lookup_mofile __P((char *, size_t, const char *, + char *, const char *, const char *)); +static u_int32_t flip __P((u_int32_t, u_int32_t)); +static int validate __P((void *)); +static int mapit __P((const char *)); +static int unmapit __P((void)); +static const char *lookup_hash __P((const char *)); +static const char *lookup_bsearch __P((const char *)); +static const char *lookup __P((const char *)); + +/* + * shortcut functions. the main implementation resides in dcngettext(). + */ +char * +gettext(msgid) + const char *msgid; +{ + + return dcngettext(NULL, msgid, NULL, 1UL, LC_MESSAGES); +} + +char * +dgettext(domainname, msgid) + const char *domainname; + const char *msgid; +{ + + return dcngettext(domainname, msgid, NULL, 1UL, LC_MESSAGES); +} + +char * +dcgettext(domainname, msgid, category) + const char *domainname; + const char *msgid; + int category; +{ + + return dcngettext(domainname, msgid, NULL, 1UL, category); +} + +char * +ngettext(msgid1, msgid2, n) + const char *msgid1; + const char *msgid2; + unsigned long int n; +{ + + return dcngettext(NULL, msgid1, msgid2, n, LC_MESSAGES); +} + +char * +dngettext(domainname, msgid1, msgid2, n) + const char *domainname; + const char *msgid1; + const char *msgid2; + unsigned long int n; +{ + + return dcngettext(domainname, msgid1, msgid2, n, LC_MESSAGES); +} + +/* + * dcngettext() - + * lookup internationalized message on database locale/category/domainname + * (like ja_JP.eucJP/LC_MESSAGES/domainname). + * if n equals to 1, internationalized message will be looked up for msgid1. + * otherwise, message will be looked up for msgid2. + * if the lookup fails, the function will return msgid1 or msgid2 as is. + * + * Even though the return type is "char *", caller should not rewrite the + * region pointed to by the return value (should be "const char *", but can't + * change it for compatibility with other implementations). + * + * by default (if domainname == NULL), domainname is taken from the value set + * by textdomain(). usually name of the application (like "ls") is used as + * domainname. category is usually LC_MESSAGES. + * + * the code reads in *.mo files generated by GNU gettext. *.mo is a host- + * endian encoded file. both endians are supported here, as the files are in + * /usr/share/locale! (or we should move those files into /usr/libdata) + */ + +static const char * +lookup_category(category) + int category; +{ + + switch (category) { + case LC_COLLATE: return "LC_COLLATE"; + case LC_CTYPE: return "LC_CTYPE"; + case LC_MONETARY: return "LC_MONETARY"; + case LC_NUMERIC: return "LC_NUMERIC"; + case LC_TIME: return "LC_TIME"; + case LC_MESSAGES: return "LC_MESSAGES"; + } + return NULL; +} + +/* + * XPG syntax: language[_territory[.codeset]][@modifier] + * XXX boundary check on "result" is lacking + */ +static const char * +split_locale(lname) + const char *lname; +{ + char buf[BUFSIZ], tmp[BUFSIZ]; + char *l, *t, *c, *m; + static char result[BUFSIZ]; + + memset(result, 0, sizeof(result)); + + if (strlen(lname) + 1 > sizeof(buf)) { +fail: + return lname; + } + + strlcpy(buf, lname, sizeof(buf)); + m = strrchr(buf, '@'); + if (m) + *m++ = '\0'; + c = strrchr(buf, '.'); + if (c) + *c++ = '\0'; + t = strrchr(buf, '_'); + if (t) + *t++ = '\0'; + l = buf; + if (strlen(l) == 0) + goto fail; + if (c && !t) + goto fail; + + if (m) { + if (t) { + if (c) { + snprintf(tmp, sizeof(tmp), "%s_%s.%s@%s", + l, t, c, m); + strlcat(result, tmp, sizeof(result)); + strlcat(result, ":", sizeof(result)); + } + snprintf(tmp, sizeof(tmp), "%s_%s@%s", l, t, m); + strlcat(result, tmp, sizeof(result)); + strlcat(result, ":", sizeof(result)); + } + snprintf(tmp, sizeof(tmp), "%s@%s", l, m); + strlcat(result, tmp, sizeof(result)); + strlcat(result, ":", sizeof(result)); + } + if (t) { + if (c) { + snprintf(tmp, sizeof(tmp), "%s_%s.%s", l, t, c); + strlcat(result, tmp, sizeof(result)); + strlcat(result, ":", sizeof(result)); + } + strlcat(result, tmp, sizeof(result)); + strlcat(result, ":", sizeof(result)); + } + strlcat(result, l, sizeof(result)); + + return result; +} + +static const char * +lookup_mofile(buf, len, dir, lpath, category, domainname) + char *buf; + size_t len; + const char *dir; + char *lpath; /* list of locales to be tried */ + const char *category; + const char *domainname; +{ + struct stat st; + char *p, *q; + + q = lpath; + while (1) { + p = strsep(&q, ":"); + if (!p) + break; + if (!*p) + continue; + + /* don't mess with default locales */ + if (strcmp(p, "C") == 0 || strcmp(p, "POSIX") == 0) + return NULL; + + /* validate pathname */ + if (strchr(p, '/') || strchr(category, '/')) + continue; +#if 1 /*?*/ + if (strchr(domainname, '/')) + continue; +#endif + + snprintf(buf, len, "%s/%s/%s/%s.mo", dir, p, + category, domainname); + if (stat(buf, &st) < 0) + continue; + if ((st.st_mode & S_IFMT) != S_IFREG) + continue; + + if (mapit(buf) == 0) + return buf; + } + + return NULL; +} + +static u_int32_t +flip(v, magic) + u_int32_t v; + u_int32_t magic; +{ + + if (magic == MO_MAGIC) + return v; + else if (magic == MO_MAGIC_SWAPPED) { + v = ((v >> 24) & 0xff) | ((v >> 8) & 0xff00) | + ((v << 8) & 0xff0000) | ((v << 24) & 0xff000000); + return v; + } else { + abort(); + /*NOTREACHED*/ + } +} + +static int +validate(arg) + void *arg; +{ + char *p; + + p = (char *)arg; + if (p < (char *)mohandle.addr || + p > (char *)mohandle.addr + mohandle.len) + return 0; + else + return 1; +} + +int +mapit(path) + const char *path; +{ + int fd; + struct stat st; + char *base; + u_int32_t magic, revision; + struct moentry *otable, *ttable; + struct moentry_h *p; + struct mo *mo; + size_t l; + int i; + char *v; + + if (mohandle.addr && strcmp(path, mohandle.path) == 0) + return 0; /*already opened*/ + + unmapit(); + +#if 0 + if (secure_path(path) != 0) + goto fail; +#endif + if (stat(path, &st) < 0) + goto fail; + if ((st.st_mode & S_IFMT) != S_IFREG || st.st_size > GETTEXT_MMAP_MAX) + goto fail; + fd = open(path, O_RDONLY); + if (fd < 0) + goto fail; + if (read(fd, &magic, sizeof(magic)) < 0 || + (magic != MO_MAGIC && magic != MO_MAGIC_SWAPPED)) { + close(fd); + goto fail; + } + if (read(fd, &revision, sizeof(revision)) < 0 || + flip(revision, magic) != MO_REVISION) { + close(fd); + goto fail; + } + mohandle.addr = mmap(NULL, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED, + fd, (off_t)0); + if (!mohandle.addr) { + close(fd); + goto fail; + } + close(fd); + mohandle.len = st.st_size; + strlcpy(mohandle.path, path, sizeof(mohandle.path)); + + base = mohandle.addr; + mo = (struct mo *)mohandle.addr; + + /* flip endian. do not flip magic number! */ + mohandle.mo.mo_magic = mo->mo_magic; + mohandle.mo.mo_revision = flip(mo->mo_revision, magic); + mohandle.mo.mo_nstring = flip(mo->mo_nstring, magic); + + /* validate otable/ttable */ + otable = (struct moentry *)(base + flip(mo->mo_otable, magic)); + ttable = (struct moentry *)(base + flip(mo->mo_ttable, magic)); + if (!validate(otable) || !validate(&otable[mohandle.mo.mo_nstring])) { + unmapit(); + goto fail; + } + if (!validate(ttable) || !validate(&ttable[mohandle.mo.mo_nstring])) { + unmapit(); + goto fail; + } + + /* allocate [ot]table, and convert to normal pointer representation. */ + l = sizeof(struct moentry_h) * mohandle.mo.mo_nstring; + mohandle.mo.mo_otable = (struct moentry_h *)malloc(l); + if (!mohandle.mo.mo_otable) { + unmapit(); + goto fail; + } + mohandle.mo.mo_ttable = (struct moentry_h *)malloc(l); + if (!mohandle.mo.mo_ttable) { + unmapit(); + goto fail; + } + p = mohandle.mo.mo_otable; + for (i = 0; i < mohandle.mo.mo_nstring; i++) { + p[i].len = flip(otable[i].len, magic); + p[i].off = base + flip(otable[i].off, magic); + + if (!validate(p[i].off) || !validate(p[i].off + p[i].len + 1)) { + unmapit(); + goto fail; + } + } + p = mohandle.mo.mo_ttable; + for (i = 0; i < mohandle.mo.mo_nstring; i++) { + p[i].len = flip(ttable[i].len, magic); + p[i].off = base + flip(ttable[i].off, magic); + + if (!validate(p[i].off) || !validate(p[i].off + p[i].len + 1)) { + unmapit(); + goto fail; + } + } + + /* grab MIME-header and charset field */ + mohandle.mo.mo_header = lookup(""); + if (mohandle.mo.mo_header) + v = strstr(mohandle.mo.mo_header, "charset="); + else + v = NULL; + if (v) { + mohandle.mo.mo_charset = strdup(v + 8); + v = strchr(mohandle.mo.mo_charset, '\n'); + if (v) + *v = '\0'; + } + + /* + * XXX check charset, reject it if we are unable to support the charset + * with the current locale. + * for example, if we are using euc-jp locale and we are looking at + * *.mo file encoded by euc-kr (charset=euc-kr), we should reject + * the *.mo file as we cannot support it. + */ + + return 0; + +fail: + return -1; +} + +static int +unmapit() +{ + + /* unmap if there's already mapped region */ + if (mohandle.addr) + munmap(mohandle.addr, mohandle.len); + mohandle.addr = NULL; + mohandle.path[0] = '\0'; + if (mohandle.mo.mo_otable) + free(mohandle.mo.mo_otable); + if (mohandle.mo.mo_ttable) + free(mohandle.mo.mo_ttable); + if (mohandle.mo.mo_charset) + free(mohandle.mo.mo_charset); + memset(&mohandle.mo, 0, sizeof(mohandle.mo)); + return 0; +} + +static const char * +lookup_hash(msgid) + const char *msgid; +{ + + /* + * XXX should try a hashed lookup here, but to do so, we need to + * look inside the GPL'ed *.c and re-implement... + */ + return NULL; +} + +static const char * +lookup_bsearch(msgid) + const char *msgid; +{ + size_t l; + int top, bottom, middle, omiddle; + int n; + + l = strlen(msgid); + + top = 0; + bottom = mohandle.mo.mo_nstring; + omiddle = -1; + while (1) { + if (top > bottom) + return NULL; + middle = (top + bottom) / 2; + /* avoid possible infinite loop, when the data is not sorted */ + if (omiddle == middle) + return NULL; + if (middle < 0 || middle >= mohandle.mo.mo_nstring) + return NULL; + + n = strcmp(msgid, mohandle.mo.mo_otable[middle].off); + if (n == 0) + return (const char *)mohandle.mo.mo_ttable[middle].off; + else if (n < 0) + bottom = middle; + else + top = middle; + omiddle = middle; + } + + return NULL; +} + +static const char * +lookup(msgid) + const char *msgid; +{ + const char *v; + + v = lookup_hash(msgid); + if (v) + return v; + + return lookup_bsearch(msgid); +} + +char * +dcngettext(domainname, msgid1, msgid2, n, category) + const char *domainname; + const char *msgid1; + const char *msgid2; + unsigned long int n; + int category; +{ + const char *msgid; + char path[PATH_MAX]; + static char lpath[PATH_MAX]; + static char olpath[PATH_MAX]; + const char *locale; + const char *language; + const char *cname; + const char *v; + + msgid = (n == 1) ? msgid1 : msgid2; + + if (!domainname) + domainname = __domainname; + cname = lookup_category(category); + if (!domainname || !cname) + goto fail; + + language = getenv("LANGUAGE"); + locale = setlocale(LC_MESSAGES, NULL); /*XXX*/ + if (locale) + locale = split_locale(locale); + if (language && locale) { + if (strlen(language) + strlen(locale) + 2 > sizeof(lpath)) + goto fail; + snprintf(lpath, sizeof(lpath), "%s:%s", language, locale); + } else if (language) { + if (strlen(language) + 1 > sizeof(lpath)) + goto fail; + strlcpy(lpath, language, sizeof(lpath)); + } else if (locale) { + if (strlen(locale) + 1 > sizeof(lpath)) + goto fail; + strlcpy(lpath, locale, sizeof(lpath)); + } else + goto fail; + + /* don't bother looking it up if the values are the same */ + if (strcmp(lpath, olpath) == 0) + goto found; + + strlcpy(olpath, lpath, sizeof(olpath)); + + /* try to find appropriate file, from $LANGUAGE */ + if (lookup_mofile(path, sizeof(path), __domainpath, lpath, cname, + domainname) != NULL) + goto found; + + goto fail; + +found: + v = lookup(msgid); + if (v) { + /* + * XXX call iconv() here, if translated text is encoded + * differently from currently-selected encoding (locale). + * look at Content-type header in *.mo file, in string obtained + * by gettext(""). + */ + + /* + * Given the amount of printf-format security issues, it may + * be a good idea to validate if the original msgid and the + * translated message format string carry the same printf-like + * format identifiers. + */ + + msgid = v; + } + +fail: + /* LINTED const cast */ + return (char *)msgid; +} diff --git a/lib/libintl/libintl.h b/lib/libintl/libintl.h new file mode 100644 index 00000000000..b792baa83a5 --- /dev/null +++ b/lib/libintl/libintl.h @@ -0,0 +1,47 @@ +/* $NetBSD: libintl.h,v 1.1.1.1 2000/10/31 10:45:04 itojun Exp $ */ + +/*- + * Copyright (c) 2000 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __LIBINTL_H_DEFINED__ +#define __LIBINTL_H_DEFINED__ + +#include <sys/cdefs.h> + +extern char *gettext __P((const char *)); +extern char *dgettext __P((const char *, const char *)); +extern char *dcgettext __P((const char *, const char *, int)); +extern char *ngettext __P((const char *, const char *, unsigned long int)); +extern char *dngettext __P((const char *, const char *, const char *, + unsigned long int)); +extern char *dcngettext __P((const char *, const char *, const char *, + unsigned long int, int)); + +extern char *textdomain __P((const char *)); +extern char *bindtextdomain __P((const char *, const char *)); +extern char *bind_textdomain_codeset __P((const char *, const char *)); + +#endif /*__LIBINTL_H_DEFINED__*/ diff --git a/lib/libintl/libintl_local.h b/lib/libintl/libintl_local.h new file mode 100644 index 00000000000..a166c57744c --- /dev/null +++ b/lib/libintl/libintl_local.h @@ -0,0 +1,75 @@ +/* $NetBSD: libintl_local.h,v 1.1.1.1 2000/10/31 10:45:04 itojun Exp $ */ + +/*- + * Copyright (c) 2000 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +extern const char *__domainpath; +extern const char *__domainname; + +#define MO_MAGIC 0x950412de +#define MO_MAGIC_SWAPPED 0xde120495 +#define MO_REVISION 0 + +#define GETTEXT_MMAP_MAX (64 * 1024) /*XXX*/ + +/* *.mo file format */ +struct mo { + u_int32_t mo_magic; /* determines endian */ + u_int32_t mo_revision; /* file format revision: 0 */ + u_int32_t mo_nstring; /* N: number of strings */ + u_int32_t mo_otable; /* O: original text table offset */ + u_int32_t mo_ttable; /* T: translated text table offset */ + u_int32_t mo_hsize; /* S: size of hashing table */ + u_int32_t mo_hoffset; /* H: offset of hashing table */ +}; + +struct moentry { + u_int32_t len; /* strlen(str), so region will be len + 1 */ + u_int32_t off; /* offset of \0-terminated string */ +}; + +/* libintl internal data format */ +struct moentry_h { + size_t len; /* strlen(str), so region will be len + 1 */ + char *off; /* offset of \0-terminated string */ +}; + +struct mo_h { + u_int32_t mo_magic; /* determines endian */ + u_int32_t mo_revision; /* file format revision: 0 */ + u_int32_t mo_nstring; /* N: number of strings */ + struct moentry_h *mo_otable; /* O: original text table offset */ + struct moentry_h *mo_ttable; /* T: translated text table offset */ + const char *mo_header; + char *mo_charset; +}; + +struct mohandle { + char path[PATH_MAX]; + void *addr; /* mmap'ed region */ + size_t len; + struct mo_h mo; /* endian-flipped mo file header */ +}; diff --git a/lib/libintl/pathnames.h b/lib/libintl/pathnames.h new file mode 100644 index 00000000000..ce6bb408115 --- /dev/null +++ b/lib/libintl/pathnames.h @@ -0,0 +1,29 @@ +/* $NetBSD: pathnames.h,v 1.1.1.1 2000/10/31 10:45:04 itojun Exp $ */ + +/*- + * Copyright (c) 2000 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define _PATH_TEXTDOMAIN "/usr/share/locale" diff --git a/lib/libintl/shlib_version b/lib/libintl/shlib_version new file mode 100644 index 00000000000..5c159d4644d --- /dev/null +++ b/lib/libintl/shlib_version @@ -0,0 +1,5 @@ +# $NetBSD: shlib_version,v 1.1.1.1 2000/10/31 10:45:04 itojun Exp $ +# Remember to update distrib/sets/lists/base/shl.* when changing +# +major=0 +minor=0 diff --git a/lib/libintl/textdomain.c b/lib/libintl/textdomain.c new file mode 100644 index 00000000000..83d612bcdc8 --- /dev/null +++ b/lib/libintl/textdomain.c @@ -0,0 +1,91 @@ +/* $NetBSD: textdomain.c,v 1.1.1.1 2000/10/31 10:45:04 itojun Exp $ */ + +/*- + * Copyright (c) 2000 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: textdomain.c,v 1.1.1.1 2000/10/31 10:45:04 itojun Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> + +#include <stdio.h> +#include <string.h> +#include <libintl.h> +#include "libintl_local.h" +#include "pathnames.h" + +static char dpath[PATH_MAX]; +static char dname[PATH_MAX]; /*XXX*/ +const char *__domainpath = _PATH_TEXTDOMAIN; +const char *__domainname; + +/* + * set the default domainname for dcngettext() and friends. + */ +char * +textdomain(domainname) + const char *domainname; +{ + + return bindtextdomain(domainname, _PATH_TEXTDOMAIN); +} + +char * +bindtextdomain(domainname, dirname) + const char *domainname; + const char *dirname; +{ + + if (strlen(dirname) + 1 > sizeof(dpath)) + return NULL; + /* disallow relative path */ + if (dirname[0] != '/') + return NULL; + + if (strlen(domainname) + 1 > sizeof(dname)) + return NULL; + + strlcpy(dpath, dirname, sizeof(dpath)); + __domainpath = dpath; + strlcpy(dname, domainname, sizeof(dname)); + __domainname = dname; + + /* LINTED const cast */ + return (char *)domainname; +} + +char * +bind_textdomain_codeset(domainname, codeset) + const char *domainname; + const char *codeset; +{ + + /* yet to be done - always fail */ + return NULL; +} |
