gettext_gnu.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "synonyms.h"
#include "mtlib.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <thread.h>
#include <synch.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include "libc.h"
#include "msgfmt.h"
#include "nlspath_checks.h"
#include "gettext.h"
#ifdef DEBUG
#include <assert.h>
#endif
static const char *nullstr = "";
#define CHARSET_MOD "charset="
#define NPLURALS_MOD "nplurals="
#define PLURAL_MOD "plural="
/*
* free_conv_msgstr
*
* release the memory allocated for storing code-converted messages
*/
static void
{
int i;
unsigned int num_of_str;
#ifdef GETTEXT_DEBUG
(void) printf("*************** free_conv_msgstr(0x%p)\n",
(void *)gmnp);
printgnumsg(gmnp, 0);
#endif
for (i = 0; i < num_of_str; i++) {
if (gmnp->conv_msgstr[i]) {
}
}
}
/*
* dfltmsgstr
*
* choose an appropriate message by evaluating the plural expression,
* and return it.
*/
static char *
{
unsigned int pindex;
const char *p;
#ifdef GETTEXT_DEBUG
(void) printf("*************** dfltmsgstr(0x%p, \"%s\", %d, 0x%p)\n",
(void *)gmnp,
printgnumsg(gmnp, 0);
#endif
} else {
/*
* This mo does not have plural information.
* Using the English form.
*/
if (mp->n == 1)
pindex = 0;
else
pindex = 1;
}
#ifdef GETTEXT_DEBUG
#endif
/* should never happen */
pindex = 0;
}
p = msgstr;
if (!p) {
/*
* null byte not found
* this should never happen
*/
char *result;
return (result);
}
p++; /* skip */
}
return ((char *)p);
}
return ((char *)msgstr);
}
/*
* parse_header
*
* parse the header entry of the GNU MO file and
* extract the src encoding and the plural information of the MO file
*/
static int
{
char *charset_str;
char *nplurals_str, *plural_str;
char *p, *q;
unsigned int nplurals;
int ret;
#ifdef GETTEXT_DEBUG
(void) printf("*************** parse_header(\"%s\", 0x%p)\n",
printgnumsg(gmnp, 0);
#endif
if (!header) {
#ifdef GETTEXT_DEBUG
(void) printf("*************** exiting parse_header\n");
(void) printf("no header\n");
#endif
return (0);
}
if (!charset_str) {
} else {
p = charset_str + CHARSET_LEN;
q = p;
while ((*q != ' ') && (*q != '\t') &&
(*q != '\n')) {
q++;
}
len = q - p;
if (len > 0) {
if (!charset) {
return (-1);
}
} else {
}
}
if (!nplurals_str || !plural_str) {
/* no valid plural specification */
#ifdef GETTEXT_DEBUG
(void) printf("*************** exiting parse_header\n");
(void) printf("no plural entry\n");
#endif
return (0);
} else {
p = nplurals_str + NPLURALS_LEN;
while (*p && isspace((unsigned char)*p)) {
p++;
}
if (p != q) {
} else {
}
p = plural_str + PLURAL_LEN;
#ifdef GETTEXT_DEBUG
(void) printf("plural_str: \"%s\"\n", p);
#endif
if (ret == 0) {
/* parse succeeded */
#ifdef GETTEXT_DEBUG
(void) printf("*************** exiting parse_header\n");
(void) printf("charset: \"%s\"\n",
#endif
return (0);
} else if (ret == 1) {
/* parse error */
return (0);
} else {
/* fatal error */
if (charset)
return (-1);
}
}
/* NOTREACHED */
}
static char *
{
char *result;
return (NULL);
}
} else {
return (NULL);
}
}
}
}
return (result);
}
/*
* handle_lang
*
* take care of the LANGUAGE specification
*/
char *
{
const char *p, *op, *q;
unsigned int hash_locale;
int gnu_mo_found = 0;
int fd;
int ret;
#ifdef GETTEXT_DEBUG
(void) printf("*************** handle_lang(0x%p, 0x%p)\n",
#endif
while (*p) {
op = p;
q = strchr(p, ':');
if (!q) {
locale_len = strlen(p);
p += locale_len;
} else {
locale_len = q - p;
p += locale_len + 1;
}
if ((locale_len >= MAXPATHLEN) ||
(locale_len == 0)) {
/* illegal locale name */
continue;
}
if (olocale_len < locale_len) {
if (!locale) {
if (olocale)
return (result);
}
}
#ifdef GETTEXT_DEBUG
#endif
/* illegal locale name */
continue;
}
if (ret) {
/*
* found in cache
*/
case T_ILL_MO:
/* invalid MO */
continue;
case T_SUN_MO:
/* Solaris MO */
goto out_loop;
case T_GNU_MO:
/* GNU MO */
gnu_mo_found = 1;
if (result) {
return (result);
}
continue;
}
/* NOTREACHED */
}
/*
* not found in cache
*/
return (result);
}
continue;
}
return (result);
}
continue;
}
return (result);
}
return (result);
}
return (result);
}
}
case T_ILL_MO:
/* invalid MO */
continue;
case T_SUN_MO:
/* Solaris MO */
goto out_loop;
case T_GNU_MO:
/* GNU MO */
gnu_mo_found = 1;
if (result) {
return (result);
}
continue;
}
/* NOTREACHED */
}
if (gnu_mo_found) {
return (result);
}
if (locale)
return (NULL);
}
/*
* gnu_msgsearch
*
* Searchs the translation message for the specified msgid1.
* Hash algorithm used in this function is Open Addressing
* with Double Hashing:
* H(k, i) = (H1(k) + i * H2(k)) mod M
* H1(k) = hashvalue % M
* H2(k) = 1 + (hashvalue % (M - 2))
*
* Ref: The Art of Computer Programming Volume 3
* Sorting and Searching, second edition
* Donald E Knuth
*/
static char *
{
unsigned int *hash_table;
char *base;
unsigned int num_of_str;
unsigned int off_msgid_tbl, off_msgstr_tbl;
/* LINTED */
/* LINTED */
#ifdef GETTEXT_DEBUG
(void) printf("*************** gnu_msgsearch("
"0x%p, \"%s\", 0x%p, 0x%p)\n",
(void *)gmnp,
printgnumsg(gmnp, 0);
#endif
/*
* No hash table exists or
* hash size is enough small
*/
char *msg_id_str;
int val;
top = 0;
bottom = num_of_str;
msg_id_str = base +
if (val < 0) {
} else if (val > 0) {
} else {
goto found;
}
}
/* not found */
return ((char *)msgid1);
}
/* use hash table */
msglen = (unsigned int)msgid1_len;
for (;;) {
if (offset == 0) {
return ((char *)msgid1);
}
/* found */
goto found;
}
}
/* NOTREACHED */
if (msgstrlen)
if (midx)
}
/*
* do_conv
*
* Converts the specified string from the src encoding
* to the dst encoding by calling iconv()
*/
static size_t
{
#ifdef GETTEXT_DEBUG
(void) printf("*************** do_conv("
"0x%p, 0x%p, \"%s\", %d)\n",
#endif
if (!to) {
return ((size_t)-1);
}
for (; ; ) {
errno = 0;
#ifdef GETTEXT_DEBUG
(void) printf("******* calling iconv()\n");
#endif
(size_t)-1) {
char *oto;
bufsize *= 2;
if (!to) {
return ((size_t)-1);
}
continue;
} else {
break;
}
}
break;
}
return (tolen);
}
/*
* gnu_key_2_text
*
* Extracts msgstr from the GNU MO file
*/
char *
{
unsigned int midx;
int ret;
char *conv_msgstr, *conv_dst;
size_t *p;
int conversion, new_encoding;
unsigned int num_of_str;
#ifdef GETTEXT_DEBUG
(void) printf("*************** gnu_key_2_text("
"0x%p, \"%s\", 0x%p)\n",
printgnumsg(gmnp, 0);
#endif
/* first checks if header entry has been processed */
char *msg_header;
if (ret == -1) {
/* fatal error */
return (result);
}
}
/* not found */
return (result);
}
#ifdef GETTEXT_DEBUG
printgnumsg(gmnp, 0);
#endif
if (!gmnp->dst_encoding) {
/*
* destination encoding has not been set.
*/
if (!dupcodeset) {
/* strdup failed */
return (result);
}
/*
* target encoding and src encoding
* are the same.
* No conversion required.
*/
conversion = 0;
} else {
/*
* target encoding is different from
* src encoding.
* New conversion required.
*/
/* sanity check */
}
if (gmnp->conv_msgstr)
conversion = 1;
new_encoding = 1;
}
} else {
/*
* dst encoding has been already set.
*/
/*
* dst encoding and target encoding are the same.
*/
== 0) {
/*
* dst encoding and src encoding are the same.
* No conversion required.
*/
conversion = 0;
} else {
/*
* dst encoding is different from src encoding.
* current conversion is valid.
*/
conversion = 1;
new_encoding = 0;
/* checks if iconv_open has succeeded before */
/*
* iconv_open should have failed before
* Assume this conversion is invalid
*/
conversion = 0;
} else {
if (!gmnp->conv_msgstr) {
/*
* memory allocation for
* conv_msgstr should
* have failed before.
*/
new_encoding = 1;
(void) iconv_close(
}
}
}
} else {
/*
* dst encoding is different from target encoding.
* It has changed since before.
*/
if (!dupcodeset) {
msgstr_len, mp);
return (result);
}
== 0) {
/*
* dst encoding and src encoding are the same.
* now, no conversion required.
*/
conversion = 0;
} else {
/*
* dst encoding is different from src encoding.
* new conversion required.
*/
conversion = 1;
new_encoding = 1;
}
}
}
if (gmnp->conv_msgstr)
}
}
if (conversion == 0) {
/* no conversion */
return (result);
}
/* conversion required */
if (new_encoding == 0) {
/* dst codeset hasn't been changed since before */
/* this msgstr hasn't been converted yet */
msgstr_len, mp);
return (result);
}
/* allign to sizeof (size_t) */
if (!p) {
msgstr_len, mp);
return (result);
}
*p = conv_msgstr_len;
conv_msgstr = (char *)(p + 1);
} else {
/* this msgstr is in the conversion cache */
/* LINTED */
conv_msgstr_len = *cmsg;
}
return (result);
}
/* new conversion */
#ifdef GETTEXT_DEBUG
(void) printf("******* calling iconv_open()\n");
(void) printf(" dst: \"%s\", src: \"%s\"\n",
#endif
/*
* iconv_open() failed.
* no conversion
*/
return (result);
}
sizeof (char *));
if (!gmnp->conv_msgstr) {
/* malloc failed */
return (result);
}
(const char *)msgstr, msgstr_len);
return (result);
}
/* allign to sizeof (size_t) */
if (!p) {
return (result);
}
*p = conv_msgstr_len;
conv_msgstr = (char *)(p + 1);
return (result);
}