xref: /onnv-gate/usr/src/lib/libc/port/i18n/gettext_gnu.c (revision 6812:febeba71273d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
56793Smuffin  * Common Development and Distribution License (the "License").
66793Smuffin  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
216793Smuffin 
220Sstevel@tonic-gate /*
236793Smuffin  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
29*6812Sraf #include "lint.h"
300Sstevel@tonic-gate #include "mtlib.h"
310Sstevel@tonic-gate #include <ctype.h>
320Sstevel@tonic-gate #include <stdio.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate #include <string.h>
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <sys/mman.h>
370Sstevel@tonic-gate #include <sys/param.h>
380Sstevel@tonic-gate #include <sys/stat.h>
390Sstevel@tonic-gate #include <thread.h>
400Sstevel@tonic-gate #include <synch.h>
410Sstevel@tonic-gate #include <unistd.h>
420Sstevel@tonic-gate #include <limits.h>
430Sstevel@tonic-gate #include <errno.h>
446793Smuffin #include <inttypes.h>
450Sstevel@tonic-gate #include "libc.h"
460Sstevel@tonic-gate #include "msgfmt.h"
470Sstevel@tonic-gate #include "nlspath_checks.h"
480Sstevel@tonic-gate #include "gettext.h"
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #ifdef DEBUG
510Sstevel@tonic-gate #include <assert.h>
520Sstevel@tonic-gate #endif
530Sstevel@tonic-gate 
546793Smuffin /* The following symbols are just for GNU binary compatibility */
556793Smuffin int	_nl_msg_cat_cntr;
566793Smuffin int	*_nl_domain_bindings;
576793Smuffin 
580Sstevel@tonic-gate static const char	*nullstr = "";
590Sstevel@tonic-gate 
600Sstevel@tonic-gate #define	CHARSET_MOD	"charset="
610Sstevel@tonic-gate #define	CHARSET_LEN	(sizeof (CHARSET_MOD) - 1)
620Sstevel@tonic-gate #define	NPLURALS_MOD	"nplurals="
630Sstevel@tonic-gate #define	NPLURALS_LEN	(sizeof (NPLURALS_MOD) - 1)
640Sstevel@tonic-gate #define	PLURAL_MOD	"plural="
650Sstevel@tonic-gate #define	PLURAL_LEN	(sizeof (PLURAL_MOD) - 1)
660Sstevel@tonic-gate 
676793Smuffin static uint32_t	get_hash_index(uint32_t *, uint32_t, uint32_t);
686793Smuffin 
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate  * free_conv_msgstr
710Sstevel@tonic-gate  *
720Sstevel@tonic-gate  * release the memory allocated for storing code-converted messages
736793Smuffin  *
746793Smuffin  * f
756793Smuffin  *	0:	do not free gmnp->conv_msgstr
766793Smuffin  *	1:	free gmnp->conv_msgstr
770Sstevel@tonic-gate  */
780Sstevel@tonic-gate static void
free_conv_msgstr(Msg_g_node * gmnp,int f)796793Smuffin free_conv_msgstr(Msg_g_node *gmnp, int f)
800Sstevel@tonic-gate {
816793Smuffin 	uint32_t	i, num_of_conv;
820Sstevel@tonic-gate 
830Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
846793Smuffin 	gprintf(0, "*************** free_conv_msgstr(0x%p, %d)\n",
856793Smuffin 	    (void *)gmnp, f);
866793Smuffin 	printgnumsg(gmnp, 1);
870Sstevel@tonic-gate #endif
880Sstevel@tonic-gate 
896793Smuffin 	num_of_conv = gmnp->num_of_str + gmnp->num_of_d_str;
906793Smuffin 	for (i = 0; i < num_of_conv; i++) {
910Sstevel@tonic-gate 		if (gmnp->conv_msgstr[i]) {
920Sstevel@tonic-gate 			free(gmnp->conv_msgstr[i]);
930Sstevel@tonic-gate 		}
946793Smuffin 		gmnp->conv_msgstr[i] = NULL;
950Sstevel@tonic-gate 	}
966793Smuffin 	if (f) {
976793Smuffin 		free(gmnp->conv_msgstr);
986793Smuffin 		gmnp->conv_msgstr = NULL;
996793Smuffin 	}
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate /*
1030Sstevel@tonic-gate  * dfltmsgstr
1040Sstevel@tonic-gate  *
1050Sstevel@tonic-gate  * choose an appropriate message by evaluating the plural expression,
1060Sstevel@tonic-gate  * and return it.
1070Sstevel@tonic-gate  */
1080Sstevel@tonic-gate static char *
dfltmsgstr(Msg_g_node * gmnp,const char * msgstr,uint32_t msgstr_len,struct msg_pack * mp)1096793Smuffin dfltmsgstr(Msg_g_node *gmnp, const char *msgstr, uint32_t msgstr_len,
1106793Smuffin     struct msg_pack *mp)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate 	unsigned int	pindex;
1130Sstevel@tonic-gate 	size_t	len;
1140Sstevel@tonic-gate 	const char	*p;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
1176793Smuffin 	gprintf(0, "*************** dfltmsgstr(0x%p, \"%s\", %u, 0x%p)\n",
1186793Smuffin 	    (void *)gmnp,
1196793Smuffin 	    msgstr ? msgstr : "(null)", msgstr_len, (void *)mp);
1206793Smuffin 	printgnumsg(gmnp, 1);
1216793Smuffin 	printmp(mp, 1);
1220Sstevel@tonic-gate #endif
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	if (mp->plural) {
1250Sstevel@tonic-gate 		if (gmnp->plural) {
1260Sstevel@tonic-gate 			pindex = plural_eval(gmnp->plural, mp->n);
1270Sstevel@tonic-gate 		} else {
1280Sstevel@tonic-gate 			/*
1290Sstevel@tonic-gate 			 * This mo does not have plural information.
1300Sstevel@tonic-gate 			 * Using the English form.
1310Sstevel@tonic-gate 			 */
1320Sstevel@tonic-gate 			if (mp->n == 1)
1330Sstevel@tonic-gate 				pindex = 0;
1340Sstevel@tonic-gate 			else
1350Sstevel@tonic-gate 				pindex = 1;
1360Sstevel@tonic-gate 		}
1370Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
1386793Smuffin 		gprintf(0, "plural_eval returned: %u\n", pindex);
1390Sstevel@tonic-gate #endif
1400Sstevel@tonic-gate 		if (pindex >= gmnp->nplurals) {
1410Sstevel@tonic-gate 			/* should never happen */
1420Sstevel@tonic-gate 			pindex = 0;
1430Sstevel@tonic-gate 		}
1440Sstevel@tonic-gate 		p = msgstr;
1450Sstevel@tonic-gate 		for (; pindex != 0; pindex--) {
1460Sstevel@tonic-gate 			len = msgstr_len - (p - msgstr);
1470Sstevel@tonic-gate 			p = memchr(p, '\0', len);
1486793Smuffin 			if (p == NULL) {
1490Sstevel@tonic-gate 				/*
1500Sstevel@tonic-gate 				 * null byte not found
1510Sstevel@tonic-gate 				 * this should never happen
1520Sstevel@tonic-gate 				 */
1530Sstevel@tonic-gate 				char	*result;
1540Sstevel@tonic-gate 				DFLTMSG(result, mp->msgid1, mp->msgid2,
1556793Smuffin 				    mp->n, mp->plural);
1560Sstevel@tonic-gate 				return (result);
1570Sstevel@tonic-gate 			}
1580Sstevel@tonic-gate 			p++;		/* skip */
1590Sstevel@tonic-gate 		}
1600Sstevel@tonic-gate 		return ((char *)p);
1610Sstevel@tonic-gate 	}
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	return ((char *)msgstr);
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate /*
1670Sstevel@tonic-gate  * parse_header
1680Sstevel@tonic-gate  *
1690Sstevel@tonic-gate  * parse the header entry of the GNU MO file and
1700Sstevel@tonic-gate  * extract the src encoding and the plural information of the MO file
1710Sstevel@tonic-gate  */
1720Sstevel@tonic-gate static int
parse_header(const char * header,Msg_g_node * gmnp)1730Sstevel@tonic-gate parse_header(const char *header, Msg_g_node *gmnp)
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate 	char	*charset = NULL;
1760Sstevel@tonic-gate 	char	*charset_str;
1770Sstevel@tonic-gate 	size_t	len;
1780Sstevel@tonic-gate 	char	*nplurals_str, *plural_str;
1790Sstevel@tonic-gate 	plural_expr_t	plural;
1800Sstevel@tonic-gate 	char	*p, *q;
1810Sstevel@tonic-gate 	unsigned int	nplurals;
1820Sstevel@tonic-gate 	int	ret;
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
1856793Smuffin 	gprintf(0, "*************** parse_header(\"%s\", 0x%p)\n",
1866793Smuffin 	    header ? header : "(null)", (void *)gmnp);
1876793Smuffin 	printgnumsg(gmnp, 1);
1880Sstevel@tonic-gate #endif
1890Sstevel@tonic-gate 
1906793Smuffin 	if (header == NULL) {
1910Sstevel@tonic-gate 		gmnp->src_encoding = (char *)nullstr;
1920Sstevel@tonic-gate 		gmnp->nplurals = 2;
1930Sstevel@tonic-gate 		gmnp->plural = NULL;
1940Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
1956793Smuffin 		gprintf(0, "*************** exiting parse_header\n");
1966793Smuffin 		gprintf(0, "no header\n");
1970Sstevel@tonic-gate #endif
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 		return (0);
2000Sstevel@tonic-gate 	}
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	charset_str = strstr(header, CHARSET_MOD);
2036793Smuffin 	if (charset_str == NULL) {
2040Sstevel@tonic-gate 		gmnp->src_encoding = (char *)nullstr;
2050Sstevel@tonic-gate 	} else {
2060Sstevel@tonic-gate 		p = charset_str + CHARSET_LEN;
2070Sstevel@tonic-gate 		q = p;
2080Sstevel@tonic-gate 		while ((*q != ' ') && (*q != '\t') &&
2096793Smuffin 		    (*q != '\n')) {
2100Sstevel@tonic-gate 			q++;
2110Sstevel@tonic-gate 		}
2120Sstevel@tonic-gate 		len = q - p;
2130Sstevel@tonic-gate 		if (len > 0) {
2146793Smuffin 			charset = malloc(len + 1);
2156793Smuffin 			if (charset == NULL) {
2160Sstevel@tonic-gate 				gmnp->src_encoding = (char *)nullstr;
2170Sstevel@tonic-gate 				gmnp->nplurals = 2;
2180Sstevel@tonic-gate 				gmnp->plural = NULL;
2190Sstevel@tonic-gate 				return (-1);
2200Sstevel@tonic-gate 			}
2210Sstevel@tonic-gate 			(void) memcpy(charset, p, len);
2220Sstevel@tonic-gate 			charset[len] = '\0';
2230Sstevel@tonic-gate 			gmnp->src_encoding = charset;
2240Sstevel@tonic-gate 		} else {
2250Sstevel@tonic-gate 			gmnp->src_encoding = (char *)nullstr;
2260Sstevel@tonic-gate 		}
2270Sstevel@tonic-gate 	}
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	nplurals_str = strstr(header, NPLURALS_MOD);
2300Sstevel@tonic-gate 	plural_str = strstr(header, PLURAL_MOD);
2316793Smuffin 	if (nplurals_str == NULL || plural_str == NULL) {
2320Sstevel@tonic-gate 		/* no valid plural specification */
2330Sstevel@tonic-gate 		gmnp->nplurals = 2;
2340Sstevel@tonic-gate 		gmnp->plural = NULL;
2350Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
2366793Smuffin 		gprintf(0, "*************** exiting parse_header\n");
2376793Smuffin 		gprintf(0, "no plural entry\n");
2380Sstevel@tonic-gate #endif
2390Sstevel@tonic-gate 		return (0);
2400Sstevel@tonic-gate 	} else {
2410Sstevel@tonic-gate 		p = nplurals_str + NPLURALS_LEN;
2420Sstevel@tonic-gate 		while (*p && isspace((unsigned char)*p)) {
2430Sstevel@tonic-gate 			p++;
2440Sstevel@tonic-gate 		}
2450Sstevel@tonic-gate 		nplurals = (unsigned int)strtol(p, &q, 10);
2460Sstevel@tonic-gate 		if (p != q) {
2470Sstevel@tonic-gate 			gmnp->nplurals = nplurals;
2480Sstevel@tonic-gate 		} else {
2490Sstevel@tonic-gate 			gmnp->nplurals = 2;
2500Sstevel@tonic-gate 		}
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 		p = plural_str + PLURAL_LEN;
2530Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
2546793Smuffin 		gprintf(0, "plural_str: \"%s\"\n", p);
2550Sstevel@tonic-gate #endif
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 		ret = plural_expr(&plural, (const char *)p);
2580Sstevel@tonic-gate 		if (ret == 0) {
2590Sstevel@tonic-gate 			/* parse succeeded */
2600Sstevel@tonic-gate 			gmnp->plural = plural;
2610Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
2626793Smuffin 		gprintf(0, "*************** exiting parse_header\n");
2636793Smuffin 		gprintf(0, "charset: \"%s\"\n",
2646793Smuffin 		    charset ? charset : "(null)");
2656793Smuffin 		printexpr(plural, 1);
2660Sstevel@tonic-gate #endif
2670Sstevel@tonic-gate 			return (0);
2680Sstevel@tonic-gate 		} else if (ret == 1) {
2690Sstevel@tonic-gate 			/* parse error */
2700Sstevel@tonic-gate 			gmnp->nplurals = 2;
2710Sstevel@tonic-gate 			gmnp->plural = NULL;
2720Sstevel@tonic-gate 			return (0);
2730Sstevel@tonic-gate 		} else {
2740Sstevel@tonic-gate 			/* fatal error */
2750Sstevel@tonic-gate 			if (charset)
2760Sstevel@tonic-gate 				free(charset);
2770Sstevel@tonic-gate 			gmnp->src_encoding = (char *)nullstr;
2780Sstevel@tonic-gate 			gmnp->nplurals = 2;
2790Sstevel@tonic-gate 			gmnp->plural = NULL;
2800Sstevel@tonic-gate 			return (-1);
2810Sstevel@tonic-gate 		}
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate 	/* NOTREACHED */
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate /*
2870Sstevel@tonic-gate  * handle_lang
2880Sstevel@tonic-gate  *
2890Sstevel@tonic-gate  * take care of the LANGUAGE specification
2900Sstevel@tonic-gate  */
2910Sstevel@tonic-gate char *
handle_lang(struct msg_pack * mp)2926793Smuffin handle_lang(struct msg_pack *mp)
2930Sstevel@tonic-gate {
2940Sstevel@tonic-gate 	const char	*p, *op, *q;
2956793Smuffin 	size_t	locale_len;
2966793Smuffin 	char	*result;
2976793Smuffin 	char	locale[MAXPATHLEN];
2986793Smuffin 
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
3016793Smuffin 	gprintf(0, "*************** handle_lang(0x%p)\n", (void *)mp);
3026793Smuffin 	printmp(mp, 1);
3030Sstevel@tonic-gate #endif
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	p = mp->language;
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	while (*p) {
3080Sstevel@tonic-gate 		op = p;
3090Sstevel@tonic-gate 		q = strchr(p, ':');
3106793Smuffin 		if (q == NULL) {
3110Sstevel@tonic-gate 			locale_len = strlen(p);
3120Sstevel@tonic-gate 			p += locale_len;
3130Sstevel@tonic-gate 		} else {
3140Sstevel@tonic-gate 			locale_len = q - p;
3150Sstevel@tonic-gate 			p += locale_len + 1;
3160Sstevel@tonic-gate 		}
3176793Smuffin 		if (locale_len >= MAXPATHLEN || locale_len == 0) {
3180Sstevel@tonic-gate 			/* illegal locale name */
3190Sstevel@tonic-gate 			continue;
3200Sstevel@tonic-gate 		}
3210Sstevel@tonic-gate 		(void) memcpy(locale, op, locale_len);
3220Sstevel@tonic-gate 		locale[locale_len] = '\0';
3230Sstevel@tonic-gate 		mp->locale = locale;
3246793Smuffin 
3250Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
3260Sstevel@tonic-gate 		*mp->msgfile = '\0';
3270Sstevel@tonic-gate #endif
3280Sstevel@tonic-gate 		if (mk_msgfile(mp) == NULL) {
3290Sstevel@tonic-gate 			/* illegal locale name */
3300Sstevel@tonic-gate 			continue;
3310Sstevel@tonic-gate 		}
3320Sstevel@tonic-gate 
3336793Smuffin 		result = handle_mo(mp);
3346793Smuffin 		if (mp->status & ST_GNU_MSG_FOUND)
3356793Smuffin 			return (result);
3360Sstevel@tonic-gate 
3376793Smuffin 		if (mp->status & ST_SUN_MO_FOUND)
3386793Smuffin 			break;
3390Sstevel@tonic-gate 	}
3400Sstevel@tonic-gate 
3416793Smuffin 	/*
3426793Smuffin 	 * no valid locale found, Sun MO found, or
3436793Smuffin 	 * GNU MO found but no valid msg found there.
3446793Smuffin 	 */
3456793Smuffin 
3466793Smuffin 	if (mp->status & ST_GNU_MO_FOUND) {
3476793Smuffin 		/*
3486793Smuffin 		 * GNU MO found but no valid msg found there.
3496793Smuffin 		 * returning DFLTMSG.
3506793Smuffin 		 */
3510Sstevel@tonic-gate 		DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural);
3520Sstevel@tonic-gate 		return (result);
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 	return (NULL);
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate /*
3580Sstevel@tonic-gate  * gnu_msgsearch
3590Sstevel@tonic-gate  *
3600Sstevel@tonic-gate  * Searchs the translation message for the specified msgid1.
3610Sstevel@tonic-gate  * Hash algorithm used in this function is Open Addressing
3620Sstevel@tonic-gate  * with Double Hashing:
3630Sstevel@tonic-gate  * H(k, i) = (H1(k) + i * H2(k)) mod M
3640Sstevel@tonic-gate  * H1(k) = hashvalue % M
3650Sstevel@tonic-gate  * H2(k) = 1 + (hashvalue % (M - 2))
3660Sstevel@tonic-gate  *
3670Sstevel@tonic-gate  * Ref: The Art of Computer Programming Volume 3
3680Sstevel@tonic-gate  * Sorting and Searching, second edition
3690Sstevel@tonic-gate  * Donald E Knuth
3700Sstevel@tonic-gate  */
3710Sstevel@tonic-gate static char *
gnu_msgsearch(Msg_g_node * gmnp,const char * msgid1,uint32_t * msgstrlen,uint32_t * midx)3720Sstevel@tonic-gate gnu_msgsearch(Msg_g_node *gmnp, const char *msgid1,
3736793Smuffin     uint32_t *msgstrlen, uint32_t *midx)
3740Sstevel@tonic-gate {
3750Sstevel@tonic-gate 	struct gnu_msg_info	*header = gmnp->msg_file_info;
3766793Smuffin 	struct gnu_msg_ent	*msgid_tbl, *msgstr_tbl;
3776793Smuffin 	uint32_t	num_of_str, idx, mlen, msglen;
3786793Smuffin 	uint32_t	hash_size, hash_val, hash_id, hash_inc, hash_idx;
3796793Smuffin 	uint32_t	*hash_table;
3806793Smuffin 	char	*base;
3816793Smuffin 	char	*msg;
3826793Smuffin 
3836793Smuffin #ifdef GETTEXT_DEBUG
3846793Smuffin 	gprintf(0, "*************** gnu_msgsearch(0x%p, \"%s\", "
3856793Smuffin 	    "0x%p, 0x%p)\n",
3866793Smuffin 	    (void *)gmnp, msgid1, msgstrlen, midx);
3876793Smuffin 	printgnumsg(gmnp, 1);
3886793Smuffin #endif
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	base = (char *)header;
3910Sstevel@tonic-gate 
3926793Smuffin 	msgid_tbl = gmnp->msg_tbl[MSGID];
3936793Smuffin 	msgstr_tbl = gmnp->msg_tbl[MSGSTR];
3940Sstevel@tonic-gate 	hash_table = gmnp->hash_table;
3956793Smuffin 	hash_size = gmnp->hash_size;
3966793Smuffin 	num_of_str = gmnp->num_of_str;
3970Sstevel@tonic-gate 
3986793Smuffin 	if (!(gmnp->flag & ST_REV1) &&
3996793Smuffin 	    (hash_table == NULL || (hash_size <= 2))) {
4000Sstevel@tonic-gate 		/*
4016793Smuffin 		 * Revision 0 and
4020Sstevel@tonic-gate 		 * No hash table exists or
4036793Smuffin 		 * hash size is enough small.
4040Sstevel@tonic-gate 		 */
4056793Smuffin 		uint32_t	top, bottom;
4060Sstevel@tonic-gate 		char	*msg_id_str;
4070Sstevel@tonic-gate 		int	val;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 		top = 0;
4100Sstevel@tonic-gate 		bottom = num_of_str;
4110Sstevel@tonic-gate 		while (top < bottom) {
4120Sstevel@tonic-gate 			idx = (top + bottom) / 2;
4130Sstevel@tonic-gate 			msg_id_str = base +
4146793Smuffin 			    SWAP(gmnp, msgid_tbl[idx].offset);
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 			val = strcmp(msg_id_str, msgid1);
4170Sstevel@tonic-gate 			if (val < 0) {
4180Sstevel@tonic-gate 				top = idx + 1;
4190Sstevel@tonic-gate 			} else if (val > 0) {
4200Sstevel@tonic-gate 				bottom = idx;
4210Sstevel@tonic-gate 			} else {
4226793Smuffin 				*msgstrlen = (unsigned int)
4236793Smuffin 				    SWAP(gmnp, msgstr_tbl[idx].len) + 1;
4246793Smuffin 				*midx = idx;
4256793Smuffin 				return (base +
4266793Smuffin 				    SWAP(gmnp, msgstr_tbl[idx].offset));
4270Sstevel@tonic-gate 			}
4280Sstevel@tonic-gate 		}
4290Sstevel@tonic-gate 		/* not found */
4300Sstevel@tonic-gate 		return ((char *)msgid1);
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	/* use hash table */
4346793Smuffin 	hash_id = get_hashid(msgid1, &msglen);
4356793Smuffin 	hash_idx = hash_id % hash_size;
4366793Smuffin 	hash_inc = 1 + (hash_id % (hash_size - 2));
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	for (;;) {
4396793Smuffin 		hash_val = HASH_TBL(gmnp, hash_table[hash_idx]);
4400Sstevel@tonic-gate 
4416793Smuffin 		if (hash_val == 0) {
4426793Smuffin 			/* not found */
4430Sstevel@tonic-gate 			return ((char *)msgid1);
4440Sstevel@tonic-gate 		}
4456793Smuffin 		if (hash_val <= num_of_str) {
4466793Smuffin 			/* static message */
4476793Smuffin 			idx = hash_val - 1;
4486793Smuffin 			mlen = SWAP(gmnp, msgid_tbl[idx].len);
4496793Smuffin 			msg = base + SWAP(gmnp, msgid_tbl[idx].offset);
4506793Smuffin 		} else {
4516793Smuffin 			if (!(gmnp->flag & ST_REV1)) {
4526793Smuffin 				/* rev 0 does not have dynamic message */
4536793Smuffin 				return ((char *)msgid1);
4546793Smuffin 			}
4556793Smuffin 			/* dynamic message */
4566793Smuffin 			idx = hash_val - num_of_str - 1;
4576793Smuffin 			mlen = gmnp->d_msg[MSGID][idx].len;
4586793Smuffin 			msg = gmnp->mchunk + gmnp->d_msg[MSGID][idx].offset;
4596793Smuffin 		}
4606793Smuffin 		if (msglen <= mlen && strcmp(msgid1, msg) == 0) {
4610Sstevel@tonic-gate 			/* found */
4626793Smuffin 			break;
4630Sstevel@tonic-gate 		}
4640Sstevel@tonic-gate 		hash_idx = (hash_idx + hash_inc) % hash_size;
4650Sstevel@tonic-gate 	}
4660Sstevel@tonic-gate 
4676793Smuffin 	/* msgstrlen should include a null termination */
4686793Smuffin 	if (hash_val <= num_of_str) {
4690Sstevel@tonic-gate 		*msgstrlen = SWAP(gmnp, msgstr_tbl[idx].len) + 1;
4706793Smuffin 		msg = base + SWAP(gmnp, msgstr_tbl[idx].offset);
4710Sstevel@tonic-gate 		*midx = idx;
4726793Smuffin 	} else {
4736793Smuffin 		*msgstrlen = gmnp->d_msg[MSGSTR][idx].len + 1;
4746793Smuffin 		msg = gmnp->mchunk + gmnp->d_msg[MSGSTR][idx].offset;
4756793Smuffin 		*midx = idx + num_of_str;
4766793Smuffin 	}
4776793Smuffin 
4786793Smuffin 	return (msg);
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate /*
4820Sstevel@tonic-gate  * do_conv
4830Sstevel@tonic-gate  *
4840Sstevel@tonic-gate  * Converts the specified string from the src encoding
4850Sstevel@tonic-gate  * to the dst encoding by calling iconv()
4860Sstevel@tonic-gate  */
4876793Smuffin static uint32_t *
do_conv(iconv_t fd,const char * src,uint32_t srclen)4886793Smuffin do_conv(iconv_t fd, const char *src, uint32_t srclen)
4890Sstevel@tonic-gate {
4906793Smuffin 	uint32_t	tolen;
4916793Smuffin 	uint32_t	*ptr, *optr;
4926793Smuffin 	size_t	oleft, ileft, bufsize, memincr;
4930Sstevel@tonic-gate 	char	*to, *tptr;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
4966793Smuffin 	gprintf(0, "*************** do_conv("
4976793Smuffin 	    "0x%p, \"%s\", %d)\n",
4986793Smuffin 	    (void *)fd, src ? src : "(null)", srclen);
4990Sstevel@tonic-gate #endif
5000Sstevel@tonic-gate 
5016793Smuffin 	memincr = srclen * 2;
5026793Smuffin 	bufsize = memincr;
5030Sstevel@tonic-gate 	ileft = srclen;
5040Sstevel@tonic-gate 	oleft = bufsize;
5056793Smuffin 	ptr = malloc(bufsize + sizeof (uint32_t));
5066793Smuffin 	if (ptr == NULL) {
5076793Smuffin 		return (NULL);
5080Sstevel@tonic-gate 	}
5096793Smuffin 	to = (char *)(ptr + 1);
5100Sstevel@tonic-gate 
5116793Smuffin 	for (;;) {
5120Sstevel@tonic-gate 		tptr = to;
5130Sstevel@tonic-gate 		errno = 0;
5140Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
5156793Smuffin 		gprintf(0, "******* calling iconv()\n");
5160Sstevel@tonic-gate #endif
5176793Smuffin 		if (iconv(fd, &src, &ileft, &tptr, &oleft) == (size_t)-1) {
5180Sstevel@tonic-gate 			if (errno == E2BIG) {
5196793Smuffin #ifdef GETTEXT_DEBUG
5206793Smuffin 				gprintf(0, "******* iconv detected E2BIG\n");
5216793Smuffin 				gprintf(0, "old bufsize: %u\n", bufsize);
5226793Smuffin #endif
5236793Smuffin 
5246793Smuffin 				optr = realloc(ptr,
5256793Smuffin 				    bufsize + memincr + sizeof (uint32_t));
5266793Smuffin 				if (optr == NULL) {
5276793Smuffin 					free(ptr);
5286793Smuffin 					return (NULL);
5290Sstevel@tonic-gate 				}
5306793Smuffin 				ptr = optr;
5316793Smuffin 				to = (char *)(optr + 1);
5326793Smuffin 				to += bufsize - oleft;
5336793Smuffin 				oleft += memincr;
5346793Smuffin 				bufsize += memincr;
5356793Smuffin #ifdef GETTEXT_DEBUG
5366793Smuffin 				gprintf(0, "new bufsize: %u\n", bufsize);
5376793Smuffin #endif
5380Sstevel@tonic-gate 				continue;
5390Sstevel@tonic-gate 			} else {
5406793Smuffin 				tolen = (uint32_t)(bufsize - oleft);
5410Sstevel@tonic-gate 				break;
5420Sstevel@tonic-gate 			}
5430Sstevel@tonic-gate 		}
5446793Smuffin 		tolen = (uint32_t)(bufsize - oleft);
5450Sstevel@tonic-gate 		break;
5460Sstevel@tonic-gate 	}
5476793Smuffin 
5486793Smuffin 	if (tolen < bufsize) {
5496793Smuffin 		/* shrink the buffer */
5506793Smuffin 		optr = realloc(ptr, tolen + sizeof (uint32_t));
5516793Smuffin 		if (optr == NULL) {
5526793Smuffin 			free(ptr);
5536793Smuffin 			return (NULL);
5546793Smuffin 		}
5556793Smuffin 		ptr = optr;
5566793Smuffin 	}
5576793Smuffin 	*ptr = tolen;
5586793Smuffin 
5596793Smuffin #ifdef GETTEXT_DEBUG
5606793Smuffin 	gprintf(0, "******* exiting do_conv()\n");
5616793Smuffin 	gprintf(0, "tolen: %u\n", *ptr);
5626793Smuffin 	gprintf(0, "return: 0x%p\n", ptr);
5636793Smuffin #endif
5646793Smuffin 	return (ptr);
5656793Smuffin }
5666793Smuffin 
5676793Smuffin /*
5686793Smuffin  * conv_msg
5696793Smuffin  */
5706793Smuffin static char *
conv_msg(Msg_g_node * gmnp,char * msgstr,uint32_t msgstr_len,uint32_t midx,struct msg_pack * mp)5716793Smuffin conv_msg(Msg_g_node *gmnp, char *msgstr, uint32_t msgstr_len, uint32_t midx,
5726793Smuffin     struct msg_pack *mp)
5736793Smuffin {
5746793Smuffin 	uint32_t	*conv_dst;
5756793Smuffin 	size_t	num_of_conv, conv_msgstr_len;
5766793Smuffin 	char	*conv_msgstr, *result;
5776793Smuffin 
5786793Smuffin 	if (gmnp->conv_msgstr == NULL) {
5796793Smuffin 		num_of_conv = gmnp->num_of_str + gmnp->num_of_d_str;
5806793Smuffin 		gmnp->conv_msgstr =
5816793Smuffin 		    calloc((size_t)num_of_conv, sizeof (uint32_t *));
5826793Smuffin 		if (gmnp->conv_msgstr == NULL) {
5836793Smuffin 			/* malloc failed */
5846793Smuffin 			result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp);
5856793Smuffin 			return (result);
5866793Smuffin 		}
5876793Smuffin 	}
5886793Smuffin 
5896793Smuffin 	conv_dst = do_conv(gmnp->fd, (const char *)msgstr, msgstr_len);
5906793Smuffin 
5916793Smuffin 	if (conv_dst == NULL) {
5926793Smuffin 		result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp);
5936793Smuffin 		return (result);
5946793Smuffin 	}
5956793Smuffin 	conv_msgstr_len = *conv_dst;
5966793Smuffin 	gmnp->conv_msgstr[midx] = conv_dst;
5976793Smuffin 	conv_msgstr = (char *)(conv_dst + 1);
5986793Smuffin 	result = dfltmsgstr(gmnp, conv_msgstr, conv_msgstr_len, mp);
5996793Smuffin 	return (result);
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate /*
6030Sstevel@tonic-gate  * gnu_key_2_text
6040Sstevel@tonic-gate  *
6050Sstevel@tonic-gate  * Extracts msgstr from the GNU MO file
6060Sstevel@tonic-gate  */
6070Sstevel@tonic-gate char *
gnu_key_2_text(Msg_g_node * gmnp,const char * codeset,struct msg_pack * mp)6080Sstevel@tonic-gate gnu_key_2_text(Msg_g_node *gmnp, const char *codeset,
6096793Smuffin     struct msg_pack *mp)
6100Sstevel@tonic-gate {
6116793Smuffin 	uint32_t	msgstr_len, midx;
6126793Smuffin 	iconv_t	fd;
6130Sstevel@tonic-gate 	char	*result, *msgstr;
6146793Smuffin 	int	ret, conversion, new_encoding;
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
6176793Smuffin 	gprintf(0, "*************** gnu_key_2_text("
6186793Smuffin 	    "0x%p, \"%s\", 0x%p)\n",
6196793Smuffin 	    (void *)gmnp, codeset ? codeset : "(null)", (void *)mp);
6206793Smuffin 	printgnumsg(gmnp, 1);
6216793Smuffin 	printmp(mp, 1);
6220Sstevel@tonic-gate #endif
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	/* first checks if header entry has been processed */
6250Sstevel@tonic-gate 	if (!(gmnp->flag & ST_CHK)) {
6260Sstevel@tonic-gate 		char	*msg_header;
6270Sstevel@tonic-gate 
6286793Smuffin 		msg_header = gnu_msgsearch(gmnp, "", &msgstr_len, &midx);
6290Sstevel@tonic-gate 		ret = parse_header((const char *)msg_header, gmnp);
6300Sstevel@tonic-gate 		if (ret == -1) {
6310Sstevel@tonic-gate 			/* fatal error */
6320Sstevel@tonic-gate 			DFLTMSG(result, mp->msgid1, mp->msgid2,
6336793Smuffin 			    mp->n, mp->plural);
6340Sstevel@tonic-gate 			return (result);
6350Sstevel@tonic-gate 		}
6360Sstevel@tonic-gate 		gmnp->flag |= ST_CHK;
6370Sstevel@tonic-gate 	}
6380Sstevel@tonic-gate 	msgstr = gnu_msgsearch(gmnp, mp->msgid1, &msgstr_len, &midx);
6390Sstevel@tonic-gate 	if (msgstr == mp->msgid1) {
6400Sstevel@tonic-gate 		/* not found */
6410Sstevel@tonic-gate 		DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural);
6420Sstevel@tonic-gate 		return (result);
6430Sstevel@tonic-gate 	}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
6466793Smuffin 	printgnumsg(gmnp, 1);
6470Sstevel@tonic-gate #endif
6486793Smuffin 	if (gmnp->dst_encoding == NULL) {
6490Sstevel@tonic-gate 		/*
6500Sstevel@tonic-gate 		 * destination encoding has not been set.
6510Sstevel@tonic-gate 		 */
6520Sstevel@tonic-gate 		char	*dupcodeset = strdup(codeset);
6536793Smuffin 		if (dupcodeset == NULL) {
6540Sstevel@tonic-gate 			/* strdup failed */
6550Sstevel@tonic-gate 			result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp);
6560Sstevel@tonic-gate 			return (result);
6570Sstevel@tonic-gate 		}
6580Sstevel@tonic-gate 		gmnp->dst_encoding = dupcodeset;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 		if (strcmp(gmnp->dst_encoding, gmnp->src_encoding) == 0) {
6610Sstevel@tonic-gate 			/*
6620Sstevel@tonic-gate 			 * target encoding and src encoding
6630Sstevel@tonic-gate 			 * are the same.
6640Sstevel@tonic-gate 			 * No conversion required.
6650Sstevel@tonic-gate 			 */
6660Sstevel@tonic-gate 			conversion = 0;
6670Sstevel@tonic-gate 		} else {
6680Sstevel@tonic-gate 			/*
6690Sstevel@tonic-gate 			 * target encoding is different from
6700Sstevel@tonic-gate 			 * src encoding.
6710Sstevel@tonic-gate 			 * New conversion required.
6720Sstevel@tonic-gate 			 */
6730Sstevel@tonic-gate 			/* sanity check */
6740Sstevel@tonic-gate 			if (gmnp->fd && (gmnp->fd != (iconv_t)-1)) {
6750Sstevel@tonic-gate 				(void) iconv_close(gmnp->fd);
6760Sstevel@tonic-gate 				gmnp->fd = (iconv_t)-1;
6770Sstevel@tonic-gate 			}
6780Sstevel@tonic-gate 			if (gmnp->conv_msgstr)
6796793Smuffin 				free_conv_msgstr(gmnp, 0);
6800Sstevel@tonic-gate 			conversion = 1;
6810Sstevel@tonic-gate 			new_encoding = 1;
6820Sstevel@tonic-gate 		}
6830Sstevel@tonic-gate 	} else {
6840Sstevel@tonic-gate 		/*
6850Sstevel@tonic-gate 		 * dst encoding has been already set.
6860Sstevel@tonic-gate 		 */
6870Sstevel@tonic-gate 		if (strcmp(gmnp->dst_encoding, codeset) == 0) {
6880Sstevel@tonic-gate 			/*
6890Sstevel@tonic-gate 			 * dst encoding and target encoding are the same.
6900Sstevel@tonic-gate 			 */
6910Sstevel@tonic-gate 			if (strcmp(gmnp->dst_encoding, gmnp->src_encoding)
6926793Smuffin 			    == 0) {
6930Sstevel@tonic-gate 				/*
6940Sstevel@tonic-gate 				 * dst encoding and src encoding are the same.
6950Sstevel@tonic-gate 				 * No conversion required.
6960Sstevel@tonic-gate 				 */
6970Sstevel@tonic-gate 				conversion = 0;
6980Sstevel@tonic-gate 			} else {
6990Sstevel@tonic-gate 				/*
7000Sstevel@tonic-gate 				 * dst encoding is different from src encoding.
7010Sstevel@tonic-gate 				 * current conversion is valid.
7020Sstevel@tonic-gate 				 */
7030Sstevel@tonic-gate 				conversion = 1;
7040Sstevel@tonic-gate 				new_encoding = 0;
7050Sstevel@tonic-gate 				/* checks if iconv_open has succeeded before */
7060Sstevel@tonic-gate 				if (gmnp->fd == (iconv_t)-1) {
7070Sstevel@tonic-gate 					/*
7080Sstevel@tonic-gate 					 * iconv_open should have failed before
7090Sstevel@tonic-gate 					 * Assume this conversion is invalid
7100Sstevel@tonic-gate 					 */
7110Sstevel@tonic-gate 					conversion = 0;
7120Sstevel@tonic-gate 				} else {
7136793Smuffin 					if (gmnp->conv_msgstr == NULL) {
7140Sstevel@tonic-gate 						/*
7150Sstevel@tonic-gate 						 * memory allocation for
7160Sstevel@tonic-gate 						 * conv_msgstr should
7170Sstevel@tonic-gate 						 * have failed before.
7180Sstevel@tonic-gate 						 */
7190Sstevel@tonic-gate 						new_encoding = 1;
7200Sstevel@tonic-gate 						if (gmnp->fd)
7210Sstevel@tonic-gate 							(void) iconv_close(
7226793Smuffin 							    gmnp->fd);
7230Sstevel@tonic-gate 						gmnp->fd = (iconv_t)-1;
7240Sstevel@tonic-gate 					}
7250Sstevel@tonic-gate 				}
7260Sstevel@tonic-gate 			}
7270Sstevel@tonic-gate 		} else {
7280Sstevel@tonic-gate 			/*
7290Sstevel@tonic-gate 			 * dst encoding is different from target encoding.
7300Sstevel@tonic-gate 			 * It has changed since before.
7310Sstevel@tonic-gate 			 */
7320Sstevel@tonic-gate 			char	*dupcodeset = strdup(codeset);
7336793Smuffin 			if (dupcodeset == NULL) {
7340Sstevel@tonic-gate 				result = dfltmsgstr(gmnp, msgstr,
7356793Smuffin 				    msgstr_len, mp);
7360Sstevel@tonic-gate 				return (result);
7370Sstevel@tonic-gate 			}
7380Sstevel@tonic-gate 			free(gmnp->dst_encoding);
7390Sstevel@tonic-gate 			gmnp->dst_encoding = dupcodeset;
7400Sstevel@tonic-gate 			if (strcmp(gmnp->dst_encoding, gmnp->src_encoding)
7416793Smuffin 			    == 0) {
7420Sstevel@tonic-gate 				/*
7430Sstevel@tonic-gate 				 * dst encoding and src encoding are the same.
7440Sstevel@tonic-gate 				 * now, no conversion required.
7450Sstevel@tonic-gate 				 */
7460Sstevel@tonic-gate 				conversion = 0;
7476793Smuffin 				if (gmnp->conv_msgstr)
7486793Smuffin 					free_conv_msgstr(gmnp, 1);
7490Sstevel@tonic-gate 			} else {
7500Sstevel@tonic-gate 				/*
7510Sstevel@tonic-gate 				 * dst encoding is different from src encoding.
7520Sstevel@tonic-gate 				 * new conversion required.
7530Sstevel@tonic-gate 				 */
7540Sstevel@tonic-gate 				conversion = 1;
7550Sstevel@tonic-gate 				new_encoding = 1;
7566793Smuffin 				if (gmnp->conv_msgstr)
7576793Smuffin 					free_conv_msgstr(gmnp, 0);
7580Sstevel@tonic-gate 			}
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 			if (gmnp->fd && (gmnp->fd != (iconv_t)-1)) {
7610Sstevel@tonic-gate 				(void) iconv_close(gmnp->fd);
7620Sstevel@tonic-gate 			}
7630Sstevel@tonic-gate 			if (gmnp->fd != (iconv_t)-1) {
7640Sstevel@tonic-gate 				gmnp->fd = (iconv_t)-1;
7650Sstevel@tonic-gate 			}
7660Sstevel@tonic-gate 		}
7670Sstevel@tonic-gate 	}
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	if (conversion == 0) {
7700Sstevel@tonic-gate 		/* no conversion */
7710Sstevel@tonic-gate 		result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp);
7720Sstevel@tonic-gate 		return (result);
7730Sstevel@tonic-gate 	}
7740Sstevel@tonic-gate 	/* conversion required */
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	if (new_encoding == 0) {
7770Sstevel@tonic-gate 		/* dst codeset hasn't been changed since before */
7786793Smuffin 		uint32_t	*cmsg;
7796793Smuffin 		uint32_t	conv_msgstr_len;
7806793Smuffin 		char	*conv_msgstr;
7816793Smuffin 
7826793Smuffin 		if (gmnp->conv_msgstr[midx] == NULL) {
7830Sstevel@tonic-gate 			/* this msgstr hasn't been converted yet */
7846793Smuffin 			result = conv_msg(gmnp, msgstr, msgstr_len, midx, mp);
7856793Smuffin 			return (result);
7860Sstevel@tonic-gate 		}
7876793Smuffin 		/* this msgstr is in the conversion cache */
7886793Smuffin 		cmsg = (uint32_t *)(uintptr_t)gmnp->conv_msgstr[midx];
7896793Smuffin 		conv_msgstr_len = *cmsg;
7906793Smuffin 		conv_msgstr = (char *)(cmsg + 1);
7910Sstevel@tonic-gate 		result = dfltmsgstr(gmnp, conv_msgstr, conv_msgstr_len, mp);
7920Sstevel@tonic-gate 		return (result);
7930Sstevel@tonic-gate 	}
7940Sstevel@tonic-gate 	/* new conversion */
7950Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
7966793Smuffin 	gprintf(0, "******* calling iconv_open()\n");
7976793Smuffin 	gprintf(0, "      dst: \"%s\", src: \"%s\"\n",
7986793Smuffin 	    gmnp->dst_encoding, gmnp->src_encoding);
7990Sstevel@tonic-gate #endif
8000Sstevel@tonic-gate 	fd = iconv_open(gmnp->dst_encoding, gmnp->src_encoding);
8010Sstevel@tonic-gate 	gmnp->fd = fd;
8020Sstevel@tonic-gate 	if (fd == (iconv_t)-1) {
8030Sstevel@tonic-gate 		/*
8040Sstevel@tonic-gate 		 * iconv_open() failed.
8050Sstevel@tonic-gate 		 * no conversion
8060Sstevel@tonic-gate 		 */
8070Sstevel@tonic-gate 		result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp);
8080Sstevel@tonic-gate 		return (result);
8090Sstevel@tonic-gate 	}
8106793Smuffin 	result = conv_msg(gmnp, msgstr, msgstr_len, midx, mp);
8110Sstevel@tonic-gate 	return (result);
8120Sstevel@tonic-gate }
8136793Smuffin 
8146793Smuffin 
8156793Smuffin #define	PRI_STR(x, n)	PRI##x##n
8166793Smuffin #define	PRI_LEN(x, n)	(char)(sizeof (PRI_STR(x, n)) - 1)
8176793Smuffin #define	PRIS(P, x)	{\
8186793Smuffin /* x/N/ */	P(x, 8), P(x, 16), P(x, 32), P(x, 64), \
8196793Smuffin /* xLEAST/N/ */	P(x, LEAST8), P(x, LEAST16), P(x, LEAST32), P(x, LEAST64), \
8206793Smuffin /* xFAST/N/ */	P(x, FAST8), P(x, FAST16), P(x, FAST32), P(x, FAST64), \
8216793Smuffin /* xMAX,PTR */	P(x, MAX), P(x, PTR) \
8226793Smuffin }
8236793Smuffin 
8246793Smuffin #define	PRI_BIAS_LEAST	4
8256793Smuffin #define	PRI_BIAS_FAST	8
8266793Smuffin #define	PRI_BIAS_MAX	12
8276793Smuffin #define	PRI_BIAS_PTR	13
8286793Smuffin 
8296793Smuffin static const char	*pri_d[] = PRIS(PRI_STR, d);
8306793Smuffin static const char	*pri_i[] = PRIS(PRI_STR, i);
8316793Smuffin static const char	*pri_o[] = PRIS(PRI_STR, o);
8326793Smuffin static const char	*pri_u[] = PRIS(PRI_STR, u);
8336793Smuffin static const char	*pri_x[] = PRIS(PRI_STR, x);
8346793Smuffin static const char	*pri_X[] = PRIS(PRI_STR, X);
8356793Smuffin 
8366793Smuffin static const char	pri_d_len[] = PRIS(PRI_LEN, d);
8376793Smuffin static const char	pri_i_len[] = PRIS(PRI_LEN, i);
8386793Smuffin static const char	pri_o_len[] = PRIS(PRI_LEN, o);
8396793Smuffin static const char	pri_u_len[] = PRIS(PRI_LEN, u);
8406793Smuffin static const char	pri_x_len[] = PRIS(PRI_LEN, x);
8416793Smuffin static const char	pri_X_len[] = PRIS(PRI_LEN, X);
8426793Smuffin 
8436793Smuffin static struct {
8446793Smuffin 	const char	type;
8456793Smuffin 	const char	**str_table;
8466793Smuffin 	const char	*len_table;
8476793Smuffin } pri_table[] = {
8486793Smuffin 	{'d', pri_d, pri_d_len}, {'i', pri_i, pri_i_len},
8496793Smuffin 	{'o', pri_o, pri_o_len}, {'u', pri_u, pri_u_len},
8506793Smuffin 	{'x', pri_x, pri_x_len}, {'X', pri_X, pri_X_len},
8516793Smuffin };
8526793Smuffin 
8536793Smuffin static struct {
8546793Smuffin 	const char	*name;
8556793Smuffin 	const char	nlen;
8566793Smuffin 	const char	want_digits;
8576793Smuffin 	const char	bias;
8586793Smuffin } special_table[] = {
8596793Smuffin 	{"LEAST",	5, 1, PRI_BIAS_LEAST},
8606793Smuffin 	{"FAST",	4, 1, PRI_BIAS_FAST},
8616793Smuffin 	{"MAX",		3, 0, PRI_BIAS_MAX},
8626793Smuffin 	{"PTR",		3, 0, PRI_BIAS_PTR},
8636793Smuffin };
8646793Smuffin 
8656793Smuffin /*
8666793Smuffin  * conv_macro() returns the conversion specifier corresponding
8676793Smuffin  * to the macro name specified in 'name'.  'len' contains the
8686793Smuffin  * length of the macro name including the null termination.
8696793Smuffin  * '*elen' will be set to the length of the returning conversion
8706793Smuffin  * specifier without the null termination.
8716793Smuffin  */
8726793Smuffin static const char *
conv_macro(const char * str,uint32_t len,uint32_t * lenp)8736793Smuffin conv_macro(const char *str, uint32_t len, uint32_t *lenp)
8746793Smuffin {
8756793Smuffin 	const char	**tbl;
8766793Smuffin 	const char	*ltbl;
8776793Smuffin 	char	*next;
8786793Smuffin 	int	n, i, num, bias, idx, want_digits;
8796793Smuffin 
8806793Smuffin 	if (len == 2) {
8816793Smuffin 		if (*str == 'I') {
8826793Smuffin 			/* Solaris does not support %I */
8836793Smuffin 			*lenp = 0;
8846793Smuffin 			return ("");
8856793Smuffin 		}
8866793Smuffin 		return (NULL);
8876793Smuffin 	}
8886793Smuffin 
8896793Smuffin 	if (len <= 4 || strncmp(str, "PRI", 3) != 0)
8906793Smuffin 		return (NULL);
8916793Smuffin 
8926793Smuffin 	str += 3;
8936793Smuffin 
8946793Smuffin 	n = sizeof (pri_table) / sizeof (pri_table[0]);
8956793Smuffin 	for (i = 0; i < n; i++) {
8966793Smuffin 		if (pri_table[i].type == *str)
8976793Smuffin 			break;
8986793Smuffin 	}
8996793Smuffin 	if (i == n)
9006793Smuffin 		return (NULL);
9016793Smuffin 	tbl = pri_table[i].str_table;
9026793Smuffin 	ltbl = pri_table[i].len_table;
9036793Smuffin 
9046793Smuffin 	str++;
9056793Smuffin 	idx = want_digits = 0;
9066793Smuffin 
9076793Smuffin 	if (isdigit((unsigned char)*str)) {
9086793Smuffin 		/* PRIx/N/ */
9096793Smuffin 		bias = 0;
9106793Smuffin 		want_digits = 1;
9116793Smuffin 	} else {
9126793Smuffin 		n = sizeof (special_table) / sizeof (special_table[0]);
9136793Smuffin 		for (i = 0; i < n; i++) {
9146793Smuffin 			if (strncmp(special_table[i].name,
9156793Smuffin 			    str, special_table[i].nlen) == 0) {
9166793Smuffin 				break;
9176793Smuffin 			}
9186793Smuffin 		}
9196793Smuffin 		if (i == n)
9206793Smuffin 			return (NULL);
9216793Smuffin 		bias = special_table[i].bias;
9226793Smuffin 		want_digits = special_table[i].want_digits;
9236793Smuffin 		str += special_table[i].nlen;
9246793Smuffin 	}
9256793Smuffin 
9266793Smuffin 	if (want_digits) {
9276793Smuffin 		if (!isdigit((unsigned char)*str))
9286793Smuffin 			return (NULL);
9296793Smuffin 		num = strtol(str, &next, 10);
9306793Smuffin 		/* see if it is 8/16/32/64 */
9316793Smuffin 		for (n = 8, idx = 0; idx < 4; idx++, n *= 2) {
9326793Smuffin 			if (n == num)
9336793Smuffin 				break;
9346793Smuffin 		}
9356793Smuffin 		if (idx == 4)
9366793Smuffin 			return (NULL);
9376793Smuffin 		str = next;
9386793Smuffin 	}
9396793Smuffin 	if (*str != '\0') {
9406793Smuffin 		/* unknow format */
9416793Smuffin 		return (NULL);
9426793Smuffin 	}
9436793Smuffin 
9446793Smuffin 	*lenp = (uint32_t)ltbl[bias + idx];
9456793Smuffin 	return (tbl[bias + idx]);
9466793Smuffin }
9476793Smuffin 
9486793Smuffin static gnu_d_macro_t *
expand_macros(Msg_g_node * p)9496793Smuffin expand_macros(Msg_g_node *p)
9506793Smuffin {
9516793Smuffin 	char	*base = (char *)p->msg_file_info;
9526793Smuffin 	struct gnu_msg_rev1_info	*rev1_header = p->rev1_header;
9536793Smuffin 	struct gnu_msg_ent	*d_macro_tbl;
9546793Smuffin 	gnu_d_macro_t	*d_macro;
9556793Smuffin 	uint32_t	num_of_d_macro, e_maclen, maclen, i;
9566793Smuffin 	const char	*e_macname;
9576793Smuffin 	char	*macname;
9586793Smuffin 
9596793Smuffin 	/* number of the dynamic macros */
9606793Smuffin 	num_of_d_macro = SWAP(p, rev1_header->num_of_dynamic_macro);
9616793Smuffin 
9626793Smuffin 	d_macro = malloc((size_t)num_of_d_macro * sizeof (gnu_d_macro_t));
9636793Smuffin 	if (d_macro == NULL)
9646793Smuffin 		return (NULL);
9656793Smuffin 
9666793Smuffin 	/* pointer to the dynamic strings table */
9676793Smuffin 	d_macro_tbl = (struct gnu_msg_ent *)(uintptr_t)
9686793Smuffin 	    (base + SWAP(p, rev1_header->off_dynamic_macro));
9696793Smuffin 
9706793Smuffin 	for (i = 0; i < num_of_d_macro; i++) {
9716793Smuffin 		macname = base + SWAP(p, d_macro_tbl[i].offset);
9726793Smuffin 		maclen = SWAP(p, d_macro_tbl[i].len);
9736793Smuffin 
9746793Smuffin 		/*
9756793Smuffin 		 * sanity check
9766793Smuffin 		 * maclen includes a null termination.
9776793Smuffin 		 */
9786793Smuffin 		if (maclen != strlen(macname) + 1) {
9796793Smuffin 			free(d_macro);
9806793Smuffin 			return (NULL);
9816793Smuffin 		}
9826793Smuffin 		e_macname = conv_macro(macname, maclen, &e_maclen);
9836793Smuffin 		if (e_macname == NULL) {
9846793Smuffin 			free(d_macro);
9856793Smuffin 			return (NULL);
9866793Smuffin 		}
9876793Smuffin 		d_macro[i].len = e_maclen;
9886793Smuffin 		d_macro[i].ptr = e_macname;
9896793Smuffin 	}
9906793Smuffin 
9916793Smuffin 	return (d_macro);
9926793Smuffin }
9936793Smuffin 
9946793Smuffin static char *
expand_dynamic_message(Msg_g_node * p,struct gnu_msg_ent ** e_msgs)9956793Smuffin expand_dynamic_message(Msg_g_node *p, struct gnu_msg_ent **e_msgs)
9966793Smuffin {
9976793Smuffin 
9986793Smuffin 	char	*base = (char *)p->msg_file_info;
9996793Smuffin 	struct gnu_msg_rev1_info	*rev1_header = p->rev1_header;
10006793Smuffin 	struct gnu_dynamic_tbl	*d_info;
10016793Smuffin 	struct gnu_dynamic_ent	*entry;
10026793Smuffin 	gnu_d_macro_t	*d_macro;
10036793Smuffin 	uint32_t	num_of_d_str, mlen, dlen, didx, i, j;
10046793Smuffin 	uint32_t	off_d_tbl;
10056793Smuffin 	uint32_t	*d_msg_off_tbl;
10066793Smuffin 	size_t	mchunk_size, used, need;
10076793Smuffin 	char	*mchunk, *msg;
10086793Smuffin 
10096793Smuffin #define	MEM_INCR	(1024)
10106793Smuffin 
10116793Smuffin 	d_macro = expand_macros(p);
10126793Smuffin 	if (d_macro == NULL)
10136793Smuffin 		return (NULL);
10146793Smuffin 
10156793Smuffin 	/* number of dynamic messages */
10166793Smuffin 	num_of_d_str = p->num_of_d_str;
10176793Smuffin 
10186793Smuffin 	mchunk = NULL;
10196793Smuffin 	mchunk_size = 0;	/* size of the allocated memory in mchunk */
10206793Smuffin 	used = 0;		/* size of the used memory in mchunk */
10216793Smuffin 	for (i = MSGID; i <= MSGSTR; i++) {
10226793Smuffin 		/* pointer to the offset table of dynamic msgids/msgstrs */
10236793Smuffin 		off_d_tbl = SWAP(p,
10246793Smuffin 		    i == MSGID ? rev1_header->off_dynamic_msgid_tbl :
10256793Smuffin 		    rev1_header->off_dynamic_msgstr_tbl);
10266793Smuffin 		/* pointer to the dynamic msgids/msgstrs */
10276793Smuffin 		d_msg_off_tbl = (uint32_t *)(uintptr_t)(base + off_d_tbl);
10286793Smuffin 		for (j = 0; j < num_of_d_str; j++) {
10296793Smuffin 			e_msgs[i][j].offset = used;
10306793Smuffin 			d_info = (struct gnu_dynamic_tbl *)(uintptr_t)
10316793Smuffin 			    (base + SWAP(p, d_msg_off_tbl[j]));
10326793Smuffin 			entry = d_info->entry;
10336793Smuffin 			msg = base + SWAP(p, d_info->offset);
10346793Smuffin 
10356793Smuffin 			for (;;) {
10366793Smuffin 				mlen = SWAP(p, entry->len);
10376793Smuffin 				didx = SWAP(p, entry->idx);
10386793Smuffin 				dlen = (didx == NOMORE_DYNAMIC_MACRO) ? 0 :
10396793Smuffin 				    d_macro[didx].len;
10406793Smuffin 				need = used + mlen + dlen;
10416793Smuffin 				if (need >= mchunk_size) {
10426793Smuffin 					char	*t;
10436793Smuffin 					size_t	n = mchunk_size;
10446793Smuffin 					do {
10456793Smuffin 						n += MEM_INCR;
10466793Smuffin 					} while (n <= need);
10476793Smuffin 					t = realloc(mchunk, n);
10486793Smuffin 					if (t == NULL) {
10496793Smuffin 						free(d_macro);
10506793Smuffin 						free(mchunk);
10516793Smuffin 						return (NULL);
10526793Smuffin 					}
10536793Smuffin 					mchunk = t;
10546793Smuffin 					mchunk_size = n;
10556793Smuffin 				}
10566793Smuffin 				(void) memcpy(mchunk + used, msg, (size_t)mlen);
10576793Smuffin 				msg += mlen;
10586793Smuffin 				used += mlen;
10596793Smuffin 
10606793Smuffin 				if (didx == NOMORE_DYNAMIC_MACRO) {
10616793Smuffin 					/*
10626793Smuffin 					 * Last segment of a static
10636793Smuffin 					 * msg string contains a null
10646793Smuffin 					 * termination, so an explicit
10656793Smuffin 					 * null termination is not required
10666793Smuffin 					 * here.
10676793Smuffin 					 */
10686793Smuffin 					break;
10696793Smuffin 				}
10706793Smuffin 				(void) memcpy(mchunk + used,
10716793Smuffin 				    d_macro[didx].ptr, (size_t)dlen);
10726793Smuffin 				used += dlen;
10736793Smuffin 				entry++; /* to next entry */
10746793Smuffin 			}
10756793Smuffin 			/*
10766793Smuffin 			 * e_msgs[][].len does not include a null termination
10776793Smuffin 			 */
10786793Smuffin 			e_msgs[i][j].len = used - e_msgs[i][j].offset - 1;
10796793Smuffin 		}
10806793Smuffin 	}
10816793Smuffin 
10826793Smuffin 	free(d_macro);
10836793Smuffin 
10846793Smuffin 	/* shrink mchunk to 'used' */
10856793Smuffin 	{
10866793Smuffin 		char	*t;
10876793Smuffin 		t = realloc(mchunk, used);
10886793Smuffin 		if (t == NULL) {
10896793Smuffin 			free(mchunk);
10906793Smuffin 			return (NULL);
10916793Smuffin 		}
10926793Smuffin 		mchunk = t;
10936793Smuffin 	}
10946793Smuffin 
10956793Smuffin 	return (mchunk);
10966793Smuffin }
10976793Smuffin 
10986793Smuffin static int
build_rev1_info(Msg_g_node * p)10996793Smuffin build_rev1_info(Msg_g_node *p)
11006793Smuffin {
11016793Smuffin 	uint32_t	*d_hash;
11026793Smuffin 	uint32_t	num_of_d_str, num_of_str;
11036793Smuffin 	uint32_t	idx, hash_value, hash_size;
11046793Smuffin 	size_t	hash_mem_size;
11056793Smuffin 	size_t	d_msgid_size, d_msgstr_size;
11066793Smuffin 	char	*chunk, *mchunk;
11076793Smuffin 	int	i;
11086793Smuffin 
11096793Smuffin #ifdef GETTEXT_DEBUG
11106793Smuffin 	gprintf(0, "******* entering build_rev1_info(0x%p)\n", p);
11116793Smuffin 	printgnumsg(p, 1);
11126793Smuffin #endif
11136793Smuffin 
11146793Smuffin 	if (p->hash_table == NULL) {
11156793Smuffin 		/* Revision 1 always requires the hash table */
11166793Smuffin 		return (-1);
11176793Smuffin 	}
11186793Smuffin 
11196793Smuffin 	num_of_str = p->num_of_str;
11206793Smuffin 	hash_size = p->hash_size;
11216793Smuffin 	num_of_d_str = p->num_of_d_str;
11226793Smuffin 
11236793Smuffin 	hash_mem_size = hash_size * sizeof (uint32_t);
11246793Smuffin 	ROUND(hash_mem_size, sizeof (struct gnu_msg_ent));
11256793Smuffin 
11266793Smuffin 	d_msgid_size = num_of_d_str * sizeof (struct gnu_msg_ent);
11276793Smuffin 	d_msgstr_size = num_of_d_str * sizeof (struct gnu_msg_ent);
11286793Smuffin 
11296793Smuffin 	chunk = malloc(hash_mem_size + d_msgid_size + d_msgstr_size);
11306793Smuffin 	if (chunk == NULL) {
11316793Smuffin 		return (-1);
11326793Smuffin 	}
11336793Smuffin 
11346793Smuffin 	d_hash = (uint32_t *)(uintptr_t)chunk;
11356793Smuffin 	p->d_msg[MSGID] = (struct gnu_msg_ent *)(uintptr_t)
11366793Smuffin 	    (chunk + hash_mem_size);
11376793Smuffin 	p->d_msg[MSGSTR] = (struct gnu_msg_ent *)(uintptr_t)
11386793Smuffin 	    (chunk + hash_mem_size + d_msgid_size);
11396793Smuffin 
11406793Smuffin 	if ((mchunk = expand_dynamic_message(p, p->d_msg)) == NULL) {
11416793Smuffin 		free(chunk);
11426793Smuffin 		return (-1);
11436793Smuffin 	}
11446793Smuffin 
11456793Smuffin 	/* copy the original hash table into the dynamic hash table */
11466793Smuffin 	for (i = 0; i < hash_size; i++) {
11476793Smuffin 		d_hash[i] = SWAP(p, p->hash_table[i]);
11486793Smuffin 	}
11496793Smuffin 
11506793Smuffin 	/* fill in the dynamic hash table with dynamic messages */
11516793Smuffin 	for (i = 0; i < num_of_d_str; i++) {
11526793Smuffin 		hash_value = get_hashid(mchunk + p->d_msg[MSGID][i].offset,
11536793Smuffin 		    NULL);
11546793Smuffin 		idx = get_hash_index(d_hash, hash_value, hash_size);
11556793Smuffin 		d_hash[idx] = num_of_str + i + 1;
11566793Smuffin 	}
11576793Smuffin 
11586793Smuffin 	p->mchunk = mchunk;
11596793Smuffin 	p->hash_table = d_hash;
11606793Smuffin 
11616793Smuffin #ifdef	GETTEXT_DEBUG
11626793Smuffin 	print_rev1_info(p);
11636793Smuffin 	gprintf(0, "******* exiting build_rev1_info()\n");
11646793Smuffin 	printgnumsg(p, 1);
11656793Smuffin #endif
11666793Smuffin 
11676793Smuffin 	return (0);
11686793Smuffin }
11696793Smuffin 
11706793Smuffin /*
11716793Smuffin  * gnu_setmsg
11726793Smuffin  *
11736793Smuffin  * INPUT
11746793Smuffin  *   mnp  - message node
11756793Smuffin  *   addr - address to the mmapped file
11766793Smuffin  *   size - size of the file
11776793Smuffin  *
11786793Smuffin  * RETURN
11796793Smuffin  *   0   - either T_GNU_MO or T_ILL_MO has been set
11806793Smuffin  *  -1   - failed
11816793Smuffin  */
11826793Smuffin int
gnu_setmsg(Msg_node * mnp,char * addr,size_t size)11836793Smuffin gnu_setmsg(Msg_node *mnp, char *addr, size_t size)
11846793Smuffin {
11856793Smuffin 	struct gnu_msg_info	*gnu_header;
11866793Smuffin 	Msg_g_node	*p;
11876793Smuffin 
11886793Smuffin #ifdef GETTEXT_DEBUG
11896793Smuffin 	gprintf(0, "******** entering gnu_setmsg(0x%p, 0x%p, %lu)\n",
11906793Smuffin 	    (void *)mnp, addr, size);
11916793Smuffin 	printmnp(mnp, 1);
11926793Smuffin #endif
11936793Smuffin 
11946793Smuffin 	/* checks the GNU MAGIC number */
11956793Smuffin 	if (size < sizeof (struct gnu_msg_info)) {
11966793Smuffin 		/* invalid mo file */
11976793Smuffin 		mnp->type = T_ILL_MO;
11986793Smuffin #ifdef	GETTEXT_DEBUG
11996793Smuffin 		gprintf(0, "********* exiting gnu_setmsg\n");
12006793Smuffin 		printmnp(mnp, 1);
12016793Smuffin #endif
12026793Smuffin 		return (0);
12036793Smuffin 	}
12046793Smuffin 
12056793Smuffin 	gnu_header = (struct gnu_msg_info *)(uintptr_t)addr;
12066793Smuffin 
12076793Smuffin 	p = calloc(1, sizeof (Msg_g_node));
12086793Smuffin 	if (p == NULL) {
12096793Smuffin 		return (-1);
12106793Smuffin 	}
12116793Smuffin 	p->msg_file_info = gnu_header;
12126793Smuffin 
12136793Smuffin 	if (gnu_header->magic == GNU_MAGIC) {
12146793Smuffin 		switch (gnu_header->revision) {
12156793Smuffin 		case GNU_REVISION_0_1:
12166793Smuffin 		case GNU_REVISION_1_1:
12176793Smuffin 			p->flag |= ST_REV1;
12186793Smuffin 			break;
12196793Smuffin 		}
12206793Smuffin 	} else if (gnu_header->magic == GNU_MAGIC_SWAPPED) {
12216793Smuffin 		p->flag |= ST_SWP;
12226793Smuffin 		switch (gnu_header->revision) {
12236793Smuffin 		case GNU_REVISION_0_1_SWAPPED:
12246793Smuffin 		case GNU_REVISION_1_1_SWAPPED:
12256793Smuffin 			p->flag |= ST_REV1;
12266793Smuffin 			break;
12276793Smuffin 		}
12286793Smuffin 	} else {
12296793Smuffin 		/* invalid mo file */
12306793Smuffin 		free(p);
12316793Smuffin 		mnp->type = T_ILL_MO;
12326793Smuffin #ifdef	GETTEXT_DEBUG
12336793Smuffin 		gprintf(0, "********* exiting gnu_setmsg\n");
12346793Smuffin 		printmnp(mnp, 1);
12356793Smuffin #endif
12366793Smuffin 		return (0);
12376793Smuffin 	}
12386793Smuffin 
12396793Smuffin 	p->fsize = size;
12406793Smuffin 	p->num_of_str = SWAP(p, gnu_header->num_of_str);
12416793Smuffin 	p->hash_size = SWAP(p, gnu_header->sz_hashtbl);
12426793Smuffin 	p->hash_table = p->hash_size <= 2 ? NULL :
12436793Smuffin 	    (uint32_t *)(uintptr_t)
12446793Smuffin 	    (addr + SWAP(p, gnu_header->off_hashtbl));
12456793Smuffin 
12466793Smuffin 	p->msg_tbl[MSGID] = (struct gnu_msg_ent *)(uintptr_t)
12476793Smuffin 	    (addr + SWAP(p, gnu_header->off_msgid_tbl));
12486793Smuffin 	p->msg_tbl[MSGSTR] = (struct gnu_msg_ent *)(uintptr_t)
12496793Smuffin 	    (addr + SWAP(p, gnu_header->off_msgstr_tbl));
12506793Smuffin 
12516793Smuffin 	if (p->flag & ST_REV1) {
12526793Smuffin 		/* Revision 1 */
12536793Smuffin 		struct gnu_msg_rev1_info	*rev1_header;
12546793Smuffin 
12556793Smuffin 		rev1_header = (struct gnu_msg_rev1_info *)
12566793Smuffin 		    (uintptr_t)(addr + sizeof (struct gnu_msg_info));
12576793Smuffin 		p->rev1_header = rev1_header;
12586793Smuffin 		p->num_of_d_str = SWAP(p, rev1_header->num_of_dynamic_str);
12596793Smuffin 		if (build_rev1_info(p) == -1) {
12606793Smuffin 			free(p);
12616793Smuffin #ifdef GETTEXT_DEBUG
12626793Smuffin 			gprintf(0, "******** exiting gnu_setmsg: "
12636793Smuffin 			    "build_rev1_info() failed\n");
12646793Smuffin #endif
12656793Smuffin 			return (-1);
12666793Smuffin 		}
12676793Smuffin 	}
12686793Smuffin 
12696793Smuffin 	mnp->msg.gnumsg = p;
12706793Smuffin 	mnp->type = T_GNU_MO;
12716793Smuffin 
12726793Smuffin #ifdef GETTEXT_DEBUG
12736793Smuffin 	gprintf(0, "********* exiting gnu_setmsg\n");
12746793Smuffin 	printmnp(mnp, 1);
12756793Smuffin #endif
12766793Smuffin 	return (0);
12776793Smuffin }
12786793Smuffin 
12796793Smuffin /*
12806793Smuffin  * get_hash_index
12816793Smuffin  *
12826793Smuffin  * Returns the index to an empty slot in the hash table
12836793Smuffin  * for the specified hash_value.
12846793Smuffin  */
12856793Smuffin static uint32_t
get_hash_index(uint32_t * hash_tbl,uint32_t hash_value,uint32_t hash_size)12866793Smuffin get_hash_index(uint32_t *hash_tbl, uint32_t hash_value, uint32_t hash_size)
12876793Smuffin {
12886793Smuffin 	uint32_t	idx, inc;
12896793Smuffin 
12906793Smuffin 	idx = hash_value % hash_size;
12916793Smuffin 	inc = 1 + (hash_value % (hash_size - 2));
12926793Smuffin 
12936793Smuffin 	for (;;) {
12946793Smuffin 		if (hash_tbl[idx] == 0) {
12956793Smuffin 			/* found an empty slot */
12966793Smuffin 			return (idx);
12976793Smuffin 		}
12986793Smuffin 		idx = (idx + inc) % hash_size;
12996793Smuffin 	}
13006793Smuffin 	/* NOTREACHED */
13016793Smuffin }
1302