xref: /illumos-gate/usr/src/lib/libc/port/i18n/gettext_util.c (revision f13ac6397da869bb7b7bc8a9f0b2e8fff530c346)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*f13ac639Smuffin  * Common Development and Distribution License (the "License").
6*f13ac639Smuffin  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*f13ac639Smuffin 
227c478bd9Sstevel@tonic-gate /*
23*f13ac639Smuffin  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include "synonyms.h"
307c478bd9Sstevel@tonic-gate #include "mtlib.h"
317c478bd9Sstevel@tonic-gate #include <ctype.h>
327c478bd9Sstevel@tonic-gate #include <stdio.h>
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <string.h>
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <unistd.h>
377c478bd9Sstevel@tonic-gate #include <sys/mman.h>
387c478bd9Sstevel@tonic-gate #include <langinfo.h>
397c478bd9Sstevel@tonic-gate #include "libc.h"
407c478bd9Sstevel@tonic-gate #include "_loc_path.h"
417c478bd9Sstevel@tonic-gate #include "msgfmt.h"
427c478bd9Sstevel@tonic-gate #include "gettext.h"
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
457c478bd9Sstevel@tonic-gate #include "plural_parser.h"
467c478bd9Sstevel@tonic-gate #include <stdarg.h>
477c478bd9Sstevel@tonic-gate #endif
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate static const char	*category_name[] = {
507c478bd9Sstevel@tonic-gate 	"LC_CTYPE",
517c478bd9Sstevel@tonic-gate 	"LC_NUMERIC",
527c478bd9Sstevel@tonic-gate 	"LC_TIME",
537c478bd9Sstevel@tonic-gate 	"LC_COLLATE",
547c478bd9Sstevel@tonic-gate 	"LC_MONETARY",
557c478bd9Sstevel@tonic-gate 	"LC_MESSAGES"
567c478bd9Sstevel@tonic-gate };
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate static const int	category_name_len[] = {
597c478bd9Sstevel@tonic-gate 	8,
607c478bd9Sstevel@tonic-gate 	10,
617c478bd9Sstevel@tonic-gate 	7,
627c478bd9Sstevel@tonic-gate 	10,
637c478bd9Sstevel@tonic-gate 	11,
647c478bd9Sstevel@tonic-gate 	11
657c478bd9Sstevel@tonic-gate };
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /*
687c478bd9Sstevel@tonic-gate  * mk_msgfile
697c478bd9Sstevel@tonic-gate  *
707c478bd9Sstevel@tonic-gate  * INPUT
717c478bd9Sstevel@tonic-gate  * mp -	uses the following members:
727c478bd9Sstevel@tonic-gate  * 	msgfile  - buffer to store the pathname to the message file
737c478bd9Sstevel@tonic-gate  *	binding  - directory pathname bound to specified domain
747c478bd9Sstevel@tonic-gate  *	cblen    - length of binding
757c478bd9Sstevel@tonic-gate  *	locale   - locale name
767c478bd9Sstevel@tonic-gate  *	domain   - domain name
777c478bd9Sstevel@tonic-gate  *	category - category
787c478bd9Sstevel@tonic-gate  *	domain_len - length of domain name
797c478bd9Sstevel@tonic-gate  *
807c478bd9Sstevel@tonic-gate  * OUTPUT
817c478bd9Sstevel@tonic-gate  * mp->msgfile - pathname to the message file is stored
827c478bd9Sstevel@tonic-gate  *
837c478bd9Sstevel@tonic-gate  * RETURN
847c478bd9Sstevel@tonic-gate  * mp->msgfile is returned
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate char *
877c478bd9Sstevel@tonic-gate mk_msgfile(struct msg_pack *mp)
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate 	char	*p, *q;
907c478bd9Sstevel@tonic-gate 	const char	*catstr;
91*f13ac639Smuffin 	uint32_t	cblen, loclen, catlen, totallen;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
94*f13ac639Smuffin 	gprintf(0, "*************** mk_msgfile(0x%p)\n", (void *)mp);
95*f13ac639Smuffin 	printmp(mp, 1);
967c478bd9Sstevel@tonic-gate #endif
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	p = mp->msgfile;
997c478bd9Sstevel@tonic-gate 	q = mp->binding;
1007c478bd9Sstevel@tonic-gate 	while (*p = *q++)
1017c478bd9Sstevel@tonic-gate 		p++;
102*f13ac639Smuffin 	cblen = (uint32_t)(p - mp->msgfile);
1037c478bd9Sstevel@tonic-gate 	if (*(p - 1) != '/') {
1047c478bd9Sstevel@tonic-gate 		/*
1057c478bd9Sstevel@tonic-gate 		 * if the last character of binding
1067c478bd9Sstevel@tonic-gate 		 * isn't a '/', adding '/'.
1077c478bd9Sstevel@tonic-gate 		 */
1087c478bd9Sstevel@tonic-gate 		if (cblen + 1 >= MAXPATHLEN) {
1097c478bd9Sstevel@tonic-gate 			/* MAXPATHLEN includes a null termination */
1107c478bd9Sstevel@tonic-gate 			return (NULL);
1117c478bd9Sstevel@tonic-gate 		}
1127c478bd9Sstevel@tonic-gate 		*p++ = '/';
1137c478bd9Sstevel@tonic-gate 		cblen++;
1147c478bd9Sstevel@tonic-gate 	}
1157c478bd9Sstevel@tonic-gate 
116*f13ac639Smuffin 	loclen = strlen(mp->locale);
1177c478bd9Sstevel@tonic-gate 	catstr = category_name[mp->category];
118*f13ac639Smuffin 	catlen = (uint32_t)category_name_len[mp->category];
1197c478bd9Sstevel@tonic-gate 	/*
1207c478bd9Sstevel@tonic-gate 	 * totallen is the length of the msgfile
1217c478bd9Sstevel@tonic-gate 	 * pathname excluding a null termination.
1227c478bd9Sstevel@tonic-gate 	 */
1237c478bd9Sstevel@tonic-gate 
124*f13ac639Smuffin 	totallen = cblen + loclen + 1 + catlen + 1 +
1257c478bd9Sstevel@tonic-gate 	    mp->domain_len + MSGFILESUFFIXLEN;
1267c478bd9Sstevel@tonic-gate 	if (totallen >= MAXPATHLEN)
1277c478bd9Sstevel@tonic-gate 		return (NULL);
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	q = mp->locale;
1307c478bd9Sstevel@tonic-gate 	while (*p++ = *q++)
1317c478bd9Sstevel@tonic-gate 		;
1327c478bd9Sstevel@tonic-gate 	*(p - 1) = '/';
1337c478bd9Sstevel@tonic-gate 	while (*p++ = *catstr++)
1347c478bd9Sstevel@tonic-gate 		;
1357c478bd9Sstevel@tonic-gate 	*(p - 1) = '/';
1367c478bd9Sstevel@tonic-gate 	q = mp->domain;
137*f13ac639Smuffin 	while (*p = *q++)
138*f13ac639Smuffin 		p++;
139*f13ac639Smuffin 	q = MSGFILESUFFIX;
1407c478bd9Sstevel@tonic-gate 	while (*p++ = *q++)
1417c478bd9Sstevel@tonic-gate 		;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
144*f13ac639Smuffin 	gprintf(0, "*************** Exiting mk_msgfile\n");
145*f13ac639Smuffin 	gprintf(0, "mp->msgfile: \"%s\"\n", mp->msgfile);
1467c478bd9Sstevel@tonic-gate #endif
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	return (mp->msgfile);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * check_cache
1537c478bd9Sstevel@tonic-gate  *
1547c478bd9Sstevel@tonic-gate  * INPUT
1557c478bd9Sstevel@tonic-gate  * mp - may use the following members:
1567c478bd9Sstevel@tonic-gate  *	msgfile - pathname to the message catalog file
157*f13ac639Smuffin  *	hash_domain - hash id of this domain
1587c478bd9Sstevel@tonic-gate  *
1597c478bd9Sstevel@tonic-gate  * RETURN
160*f13ac639Smuffin  * non-NULL
161*f13ac639Smuffin  *	pointer to the Msg_node object of the current message catalog
162*f13ac639Smuffin  *	found in the cache
163*f13ac639Smuffin  *
164*f13ac639Smuffin  * NULL
165*f13ac639Smuffin  *	this message catalog does not exist in the cache
1667c478bd9Sstevel@tonic-gate  */
167*f13ac639Smuffin Msg_node *
168*f13ac639Smuffin check_cache(struct msg_pack *mp)
1697c478bd9Sstevel@tonic-gate {
170*f13ac639Smuffin 	Msg_node	*cur_msg, *mnp;
1717c478bd9Sstevel@tonic-gate 	Gettext_t	*gt = global_gt;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
174*f13ac639Smuffin 	gprintf(0, "*************** check_cache(0x%p)\n", mp);
175*f13ac639Smuffin 	printmp(mp, 1);
1767c478bd9Sstevel@tonic-gate #endif
1777c478bd9Sstevel@tonic-gate 
178*f13ac639Smuffin 	cur_msg = gt->c_m_node;		/* current Msg_node */
1797c478bd9Sstevel@tonic-gate 	if (cur_msg &&
180*f13ac639Smuffin 	    cur_msg->hashid == mp->hash_domain &&
181*f13ac639Smuffin 	    strcmp(cur_msg->path, mp->msgfile) == 0) {
1827c478bd9Sstevel@tonic-gate 		/*
1837c478bd9Sstevel@tonic-gate 		 * msgfile is the same as the previous message file
1847c478bd9Sstevel@tonic-gate 		 */
1857c478bd9Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
186*f13ac639Smuffin 		gprintf(0, "*** cache found\n");
187*f13ac639Smuffin 		gprintf(0, "************* exiting check_cache\n");
188*f13ac639Smuffin 		printmnp(cur_msg, 1);
1897c478bd9Sstevel@tonic-gate #endif
190*f13ac639Smuffin 		return (cur_msg);
1917c478bd9Sstevel@tonic-gate 	}
192*f13ac639Smuffin 	mnp = gt->m_node;
193*f13ac639Smuffin 	while (mnp) {
1947c478bd9Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
195*f13ac639Smuffin 		gprintf(0, "========== descending the list\n");
196*f13ac639Smuffin 		gprintf(0, "  hashid: %d, hash_domain: %d\n",
197*f13ac639Smuffin 		    mnp->hashid, mp->hash_domain);
198*f13ac639Smuffin 		printmnp(mnp, 1);
1997c478bd9Sstevel@tonic-gate #endif
200*f13ac639Smuffin 		if (mnp->hashid == mp->hash_domain &&
201*f13ac639Smuffin 		    strcmp(mnp->path, mp->msgfile) == 0) {
2027c478bd9Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
203*f13ac639Smuffin 			gprintf(0, "*** cache found\n");
204*f13ac639Smuffin 			gprintf(0, "******* exiting check_cache\n");
205*f13ac639Smuffin 			printmnp(mnp, 1);
2067c478bd9Sstevel@tonic-gate #endif
207*f13ac639Smuffin 			gt->c_m_node = mnp;
208*f13ac639Smuffin 			return (mnp);
2097c478bd9Sstevel@tonic-gate 		}
210*f13ac639Smuffin 		mnp = mnp->next;
211*f13ac639Smuffin 	}
212*f13ac639Smuffin 
2137c478bd9Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
214*f13ac639Smuffin 	gprintf(0, "*** cache not found\n");
215*f13ac639Smuffin 	gprintf(0, "******* exiting check_cache\n");
2167c478bd9Sstevel@tonic-gate #endif
217*f13ac639Smuffin 	return (NULL);
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate char *
2217c478bd9Sstevel@tonic-gate get_codeset(const char *domain)
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 	char	*codeset;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
226*f13ac639Smuffin 	gprintf(0, "*************** get_codeset(\"%s\")\n",
2277c478bd9Sstevel@tonic-gate 	    domain ? domain : "(null)");
2287c478bd9Sstevel@tonic-gate #endif
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	codeset = _real_bindtextdomain_u(domain, NULL, TP_CODESET);
231*f13ac639Smuffin 	if (codeset == NULL) {
2327c478bd9Sstevel@tonic-gate 		/* no codeset is bound to this domain */
2337c478bd9Sstevel@tonic-gate 		codeset = nl_langinfo(CODESET);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
236*f13ac639Smuffin 	gprintf(0, "*************** existing get_codeset(\"%s\")\n",
2377c478bd9Sstevel@tonic-gate 	    domain ? domain : "(null)");
238*f13ac639Smuffin 	gprintf(0, "                = \"%s\"\n", codeset);
2397c478bd9Sstevel@tonic-gate #endif
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	return (codeset);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate /*
245*f13ac639Smuffin  * get_hashid (hashpjw)
2467c478bd9Sstevel@tonic-gate  *
2477c478bd9Sstevel@tonic-gate  * Calculates the hash value from the specified string.
2487c478bd9Sstevel@tonic-gate  * Actual hashid will be mod(hash value, PRIME_NUMBER).
2497c478bd9Sstevel@tonic-gate  *
2507c478bd9Sstevel@tonic-gate  * Ref: Compilers - Principles, Techniques, and Tools
2517c478bd9Sstevel@tonic-gate  * Aho, Sethi, and Ullman
2527c478bd9Sstevel@tonic-gate  */
253*f13ac639Smuffin uint32_t
254*f13ac639Smuffin get_hashid(const char *str, uint32_t *len)
2557c478bd9Sstevel@tonic-gate {
256*f13ac639Smuffin 	const unsigned char	*p = (unsigned char *)str;
257*f13ac639Smuffin 	uint32_t	h = 0;
258*f13ac639Smuffin 	uint32_t	g;
2597c478bd9Sstevel@tonic-gate 
260*f13ac639Smuffin 	for (; *p; p++) {
2617c478bd9Sstevel@tonic-gate 		h = (h << 4) + *p;
2627c478bd9Sstevel@tonic-gate 		g = h & 0xf0000000;
2637c478bd9Sstevel@tonic-gate 		if (g) {
2647c478bd9Sstevel@tonic-gate 			h = h ^ (g >> 24);
2657c478bd9Sstevel@tonic-gate 			h = h ^ g;
2667c478bd9Sstevel@tonic-gate 		}
2677c478bd9Sstevel@tonic-gate 	}
268*f13ac639Smuffin 
2697c478bd9Sstevel@tonic-gate 	if (len)
270*f13ac639Smuffin 		*len = (uint32_t)(p - (unsigned char *)str);
2717c478bd9Sstevel@tonic-gate 	return (h);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate 
274*f13ac639Smuffin uint32_t
275*f13ac639Smuffin doswap32(uint32_t n)
2767c478bd9Sstevel@tonic-gate {
277*f13ac639Smuffin 	uint32_t	r;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	r = (n << 24) | ((n & 0xff00) << 8) |
2807c478bd9Sstevel@tonic-gate 	    ((n >> 8) & 0xff00) | (n >> 24);
2817c478bd9Sstevel@tonic-gate 	return (r);
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
285*f13ac639Smuffin static uint32_t
286*f13ac639Smuffin search_msg(Msg_g_node *p, const char *id, uint32_t hash_val,
287*f13ac639Smuffin     struct gnu_msg_ent *m)
288*f13ac639Smuffin {
289*f13ac639Smuffin 	char	*base = (char *)p->msg_file_info;
290*f13ac639Smuffin 	uint32_t	hash_size, num_of_str, i, idx, inc;
291*f13ac639Smuffin 	char	*ms;
292*f13ac639Smuffin 
293*f13ac639Smuffin 	num_of_str = p->num_of_str;
294*f13ac639Smuffin 	hash_size = p->hash_size;
295*f13ac639Smuffin 	idx = hash_val % hash_size;
296*f13ac639Smuffin 	inc = 1 + (hash_val % (hash_size - 2));
297*f13ac639Smuffin 
298*f13ac639Smuffin 	while ((i = p->hash_table[idx]) != 0) {
299*f13ac639Smuffin 		ms = (i <= num_of_str) ?
300*f13ac639Smuffin 		    base + SWAP(p, m[i-1].offset) :
301*f13ac639Smuffin 		    p->mchunk + p->d_msg[MSGID][i-num_of_str-1].offset;
302*f13ac639Smuffin 		if (strcmp(id, ms) == 0) {
303*f13ac639Smuffin 			/* found */
304*f13ac639Smuffin 			return (i);
305*f13ac639Smuffin 		}
306*f13ac639Smuffin 		idx = (idx + inc) % hash_size;
307*f13ac639Smuffin 	}
308*f13ac639Smuffin 	/* not found */
309*f13ac639Smuffin 	return (0);
310*f13ac639Smuffin }
311*f13ac639Smuffin 
312*f13ac639Smuffin void
313*f13ac639Smuffin print_rev1_info(Msg_g_node *p)
314*f13ac639Smuffin {
315*f13ac639Smuffin 	char	*base = (char *)p->msg_file_info;
316*f13ac639Smuffin 	struct gnu_msg_info	*header = p->msg_file_info;
317*f13ac639Smuffin 	struct gnu_msg_ent	*m;
318*f13ac639Smuffin 	uint32_t	hv, hidx;
319*f13ac639Smuffin 	char	*ms;
320*f13ac639Smuffin 	enum gnu_msgidstr	v;
321*f13ac639Smuffin 	int	x;
322*f13ac639Smuffin 
323*f13ac639Smuffin #ifdef	GETTEXT_DEBUG_DYMMSG
324*f13ac639Smuffin 	gprintf(0, "******** dynamic msgid/msgstr\n");
325*f13ac639Smuffin 	for (v = MSGID; v <= MSGSTR; v++) {
326*f13ac639Smuffin 		for (x = 0; x < p->num_of_d_str; x++) {
327*f13ac639Smuffin 			gprintf(0, "len: %u\n", p->d_msg[v][x].len);
328*f13ac639Smuffin 			gprintf(0, "str: \"%s\"\n",
329*f13ac639Smuffin 			    p->mchunk + p->d_msg[v][x].offset);
330*f13ac639Smuffin 		}
331*f13ac639Smuffin 	}
332*f13ac639Smuffin #endif
333*f13ac639Smuffin #ifdef	GETTEXT_DEBUG_HASHTBL
334*f13ac639Smuffin 	gprintf(0, "******** dynamic hash table\n");
335*f13ac639Smuffin 	for (x = 0; x < p->hash_size; x++) {
336*f13ac639Smuffin 		gprintf(0, "%d: %u\n", x, p->hash_table[x]);
337*f13ac639Smuffin 	}
338*f13ac639Smuffin #endif
339*f13ac639Smuffin #ifdef	GETTEXT_DEBUG_CHECK_STMSGID
340*f13ac639Smuffin 	gprintf(0, "******** sanity check of static msgid\n");
341*f13ac639Smuffin 	m = (struct gnu_msg_ent *)(uintptr_t)
342*f13ac639Smuffin 	    (base + SWAP(p, header->off_msgid_tbl));
343*f13ac639Smuffin 	for (x = 0; x < p->num_of_str; x++) {
344*f13ac639Smuffin 		ms = base + SWAP(p, m[x].offset);
345*f13ac639Smuffin 		gprintf(0, "\"%s\"\n", ms);
346*f13ac639Smuffin 		hv = get_hashid(ms, NULL);
347*f13ac639Smuffin 		hidx = search_msg(p, ms, hv, m);
348*f13ac639Smuffin 		if (hidx == 0) {
349*f13ac639Smuffin 			gprintf(0,
350*f13ac639Smuffin 			    "failed to find this msg in the hash table\n");
351*f13ac639Smuffin 		} else {
352*f13ac639Smuffin 			if (hidx != x + 1) {
353*f13ac639Smuffin 				gprintf(0, "hash table mismatch\n");
354*f13ac639Smuffin 			}
355*f13ac639Smuffin 		}
356*f13ac639Smuffin 	}
357*f13ac639Smuffin #endif
358*f13ac639Smuffin #ifdef	GETTEXT_DEBUG_CHECK_DYMMSGID
359*f13ac639Smuffin 	gprintf(0, "******* sanity check of dynamic msgid\n");
360*f13ac639Smuffin 	m = (struct gnu_msg_ent *)(uintptr_t)
361*f13ac639Smuffin 	    (base + SWAP(p, header->off_msgid_tbl));
362*f13ac639Smuffin 	for (x = 0; x < p->num_of_d_str; x++) {
363*f13ac639Smuffin 		ms = p->mchunk + p->d_msg[MSGID][x].offset;
364*f13ac639Smuffin 		gprintf(0, "\"%s\"\n", ms);
365*f13ac639Smuffin 		hv = get_hashid(ms, NULL);
366*f13ac639Smuffin 		hidx = search_msg(p, ms, hv, m);
367*f13ac639Smuffin 		if (hidx == 0) {
368*f13ac639Smuffin 			gprintf(0,
369*f13ac639Smuffin 			    "failed to find this msg in the hash table\n");
370*f13ac639Smuffin 		} else {
371*f13ac639Smuffin 			if (hidx != x + p->num_of_str + 1) {
372*f13ac639Smuffin 				gprintf(0, "hash table mismatch\n");
373*f13ac639Smuffin 			}
374*f13ac639Smuffin 		}
375*f13ac639Smuffin 	}
376*f13ac639Smuffin #endif
377*f13ac639Smuffin }
378*f13ac639Smuffin 
3797c478bd9Sstevel@tonic-gate void
3807c478bd9Sstevel@tonic-gate gprintf(int level, const char *format, ...)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate 	va_list	ap;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	va_start(ap, format);
3857c478bd9Sstevel@tonic-gate 
386*f13ac639Smuffin 	while (level-- > 0) {
3877c478bd9Sstevel@tonic-gate 		(void) fputs("   ", stdout);
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 	(void) vprintf(format, ap);
3907c478bd9Sstevel@tonic-gate 	va_end(ap);
391*f13ac639Smuffin 
392*f13ac639Smuffin 	(void) fflush(stdout);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate void
3967c478bd9Sstevel@tonic-gate printlist(void)
3977c478bd9Sstevel@tonic-gate {
3987c478bd9Sstevel@tonic-gate 	struct domain_binding	*ppp;
3997c478bd9Sstevel@tonic-gate 	Gettext_t	*gt = global_gt;
4007c478bd9Sstevel@tonic-gate 
401*f13ac639Smuffin 	gprintf(0, "=== Printing default list and regural list\n");
402*f13ac639Smuffin 	gprintf(0, "   Default domain=<%s>, binding=<%s>\n",
4037c478bd9Sstevel@tonic-gate 	    DEFAULT_DOMAIN, defaultbind);
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	ppp = FIRSTBIND(gt);
4067c478bd9Sstevel@tonic-gate 	while (ppp) {
407*f13ac639Smuffin 		gprintf(0, "   domain=<%s>, binding=<%s>, codeset=<%s>\n",
4087c478bd9Sstevel@tonic-gate 		    ppp->domain ? ppp->domain : "(null)",
4097c478bd9Sstevel@tonic-gate 		    ppp->binding ? ppp->binding : "(null)",
4107c478bd9Sstevel@tonic-gate 		    ppp->codeset ? ppp->codeset : "(null)");
4117c478bd9Sstevel@tonic-gate 		ppp = ppp->next;
4127c478bd9Sstevel@tonic-gate 	}
413*f13ac639Smuffin 	(void) fflush(stdout);
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate void
4177c478bd9Sstevel@tonic-gate printmp(struct msg_pack *mp, int level)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate 	gprintf(level, "=== mp ===\n");
4207c478bd9Sstevel@tonic-gate 	gprintf(level, "   msgid1: \"%s\"\n",
4217c478bd9Sstevel@tonic-gate 	    mp->msgid1 ? mp->msgid1 : "(null)");
4227c478bd9Sstevel@tonic-gate 	gprintf(level, "   msgid2: \"%s\"\n",
4237c478bd9Sstevel@tonic-gate 	    mp->msgid2 ? mp->msgid2 : "(null)");
424*f13ac639Smuffin 	gprintf(level, "   msgfile: \"%s\"\n",
425*f13ac639Smuffin 	    mp->msgfile ? mp->msgfile : "(null)");
4267c478bd9Sstevel@tonic-gate 	gprintf(level, "   domain: \"%s\"\n",
4277c478bd9Sstevel@tonic-gate 	    mp->domain ? mp->domain : "(null)");
4287c478bd9Sstevel@tonic-gate 	gprintf(level, "   binding: \"%s\"\n",
4297c478bd9Sstevel@tonic-gate 	    mp->binding ? mp->binding : "(null)");
4307c478bd9Sstevel@tonic-gate 	gprintf(level, "   locale: \"%s\"\n",
4317c478bd9Sstevel@tonic-gate 	    mp->locale ? mp->locale : "(null)");
4327c478bd9Sstevel@tonic-gate 	gprintf(level, "   language: \"%s\"\n",
4337c478bd9Sstevel@tonic-gate 	    mp->language ? mp->language : "(null)");
4347c478bd9Sstevel@tonic-gate 	gprintf(level, "   addr: 0x%p\n", mp->addr);
4357c478bd9Sstevel@tonic-gate 	gprintf(level, "   fsz: %d\n", mp->fsz);
436*f13ac639Smuffin 	gprintf(level, "   hash_domain: %d\n", mp->hash_domain);
437*f13ac639Smuffin 	gprintf(level, "   domain_len: %d\n", mp->domain_len);
438*f13ac639Smuffin 	gprintf(level, "   n: %d\n", mp->n);
439*f13ac639Smuffin 	gprintf(level, "   category: \"%s\"\n",
440*f13ac639Smuffin 	    category_name[mp->category]);
441*f13ac639Smuffin 	gprintf(level, "   plural: %d\n", mp->plural);
442*f13ac639Smuffin 	gprintf(level, "   nlsp: %d\n", mp->nlsp);
4437c478bd9Sstevel@tonic-gate 	gprintf(level, "   trusted: %d\n", mp->trusted);
444*f13ac639Smuffin 	gprintf(level, "   status: %d\n", mp->status);
4457c478bd9Sstevel@tonic-gate }
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate void
4487c478bd9Sstevel@tonic-gate printsunmsg(Msg_s_node *smnp, int level)
4497c478bd9Sstevel@tonic-gate {
4507c478bd9Sstevel@tonic-gate 	gprintf(level, "=== sunmsg ===\n");
4517c478bd9Sstevel@tonic-gate 	gprintf(level, "   msg_file_info: 0x%p\n",
4527c478bd9Sstevel@tonic-gate 	    (void *)smnp->msg_file_info);
4537c478bd9Sstevel@tonic-gate 	gprintf(level, "      msg_mid: %d\n",
4547c478bd9Sstevel@tonic-gate 	    smnp->msg_file_info->msg_mid);
4557c478bd9Sstevel@tonic-gate 	gprintf(level, "      msg_count: %d\n",
4567c478bd9Sstevel@tonic-gate 	    smnp->msg_file_info->msg_count);
4577c478bd9Sstevel@tonic-gate 	gprintf(level, "      str_count_msgid: %d\n",
4587c478bd9Sstevel@tonic-gate 	    smnp->msg_file_info->str_count_msgid);
4597c478bd9Sstevel@tonic-gate 	gprintf(level, "      str_count_msgstr: %d\n",
4607c478bd9Sstevel@tonic-gate 	    smnp->msg_file_info->str_count_msgstr);
4617c478bd9Sstevel@tonic-gate 	gprintf(level, "      msg_struct_size: %d\n",
4627c478bd9Sstevel@tonic-gate 	    smnp->msg_file_info->msg_struct_size);
4637c478bd9Sstevel@tonic-gate 	gprintf(level, "   msg_list: 0x%p\n",
4647c478bd9Sstevel@tonic-gate 	    (void *)smnp->msg_list);
4657c478bd9Sstevel@tonic-gate 	gprintf(level, "   msg_ids: 0x%p\n",
4667c478bd9Sstevel@tonic-gate 	    (void *)smnp->msg_ids);
4677c478bd9Sstevel@tonic-gate 	gprintf(level, "   msg_strs: 0x%p\n",
4687c478bd9Sstevel@tonic-gate 	    (void *)smnp->msg_strs);
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate void
4727c478bd9Sstevel@tonic-gate printgnumsg(Msg_g_node *gmnp, int level)
4737c478bd9Sstevel@tonic-gate {
4747c478bd9Sstevel@tonic-gate 	gprintf(level, "=== gnumsg ===\n");
475*f13ac639Smuffin 	gprintf(level, "   msg_file_info: 0x%p\n", gmnp->msg_file_info);
4767c478bd9Sstevel@tonic-gate 	gprintf(level, "      magic: 0x%x\n",
4777c478bd9Sstevel@tonic-gate 	    gmnp->msg_file_info->magic);
4787c478bd9Sstevel@tonic-gate 	gprintf(level, "      revision: %d\n",
4797c478bd9Sstevel@tonic-gate 	    SWAP(gmnp, gmnp->msg_file_info->revision));
4807c478bd9Sstevel@tonic-gate 	gprintf(level, "      num_of_str: %d\n",
4817c478bd9Sstevel@tonic-gate 	    SWAP(gmnp, gmnp->msg_file_info->num_of_str));
4827c478bd9Sstevel@tonic-gate 	gprintf(level, "      off_msgid_tbl: %d\n",
4837c478bd9Sstevel@tonic-gate 	    SWAP(gmnp, gmnp->msg_file_info->off_msgid_tbl));
4847c478bd9Sstevel@tonic-gate 	gprintf(level, "      off_msgstr_tbl: %d\n",
4857c478bd9Sstevel@tonic-gate 	    SWAP(gmnp, gmnp->msg_file_info->off_msgstr_tbl));
4867c478bd9Sstevel@tonic-gate 	gprintf(level, "      sz_hashtbl: %d\n",
4877c478bd9Sstevel@tonic-gate 	    SWAP(gmnp, gmnp->msg_file_info->sz_hashtbl));
4887c478bd9Sstevel@tonic-gate 	gprintf(level, "      off_hashtbl: %d\n",
4897c478bd9Sstevel@tonic-gate 	    SWAP(gmnp, gmnp->msg_file_info->off_hashtbl));
490*f13ac639Smuffin 	if (gmnp->flag & ST_REV1) {
491*f13ac639Smuffin 		struct gnu_msg_rev1_info	*a =
492*f13ac639Smuffin 		    (struct gnu_msg_rev1_info *)(uintptr_t)
493*f13ac639Smuffin 		    ((char *)gmnp->msg_file_info +
494*f13ac639Smuffin 		    sizeof (struct gnu_msg_info));
495*f13ac639Smuffin 		gprintf(level, "      num_of_dynamic_macro: %d\n",
496*f13ac639Smuffin 		    SWAP(gmnp, a->num_of_dynamic_macro));
497*f13ac639Smuffin 		gprintf(level, "      off_dynamic_macro: %d\n",
498*f13ac639Smuffin 		    SWAP(gmnp, a->off_dynamic_macro));
499*f13ac639Smuffin 		gprintf(level, "      num_of_dynamic_str: %d\n",
500*f13ac639Smuffin 		    SWAP(gmnp, a->num_of_dynamic_str));
501*f13ac639Smuffin 		gprintf(level, "      off_dynamic_msgid_tbl: %d\n",
502*f13ac639Smuffin 		    SWAP(gmnp, a->off_dynamic_msgid_tbl));
503*f13ac639Smuffin 		gprintf(level, "      off_dynamic_msgstr_tbl: %d\n",
504*f13ac639Smuffin 		    SWAP(gmnp, a->off_dynamic_msgstr_tbl));
505*f13ac639Smuffin 	}
506*f13ac639Smuffin 	gprintf(level, "   fsize: %lu\n", gmnp->fsize);
507*f13ac639Smuffin 	gprintf(level, "   flag: %08x\n", gmnp->flag);
508*f13ac639Smuffin 	gprintf(level, "   num_of_str: %u\n", gmnp->num_of_str);
509*f13ac639Smuffin 	gprintf(level, "   num_of_d_str: %u\n", gmnp->num_of_d_str);
510*f13ac639Smuffin 	gprintf(level, "   hash_size: %u\n", gmnp->hash_size);
511*f13ac639Smuffin 	gprintf(level, "   hash_table: 0x%p\n", (void *)gmnp->hash_table);
512*f13ac639Smuffin 	gprintf(level, "   d_msgid: 0x%p\n", (void *)gmnp->d_msg[MSGID]);
513*f13ac639Smuffin 	gprintf(level, "   d_msgstr: 0x%p\n", (void *)gmnp->d_msg[MSGSTR]);
514*f13ac639Smuffin 	gprintf(level, "   mchunk: 0x%p\n", (void *)gmnp->mchunk);
515*f13ac639Smuffin 
5167c478bd9Sstevel@tonic-gate 	gprintf(level, "   src_encoding: \"%s\"\n",
5177c478bd9Sstevel@tonic-gate 	    gmnp->src_encoding ? gmnp->src_encoding : "(null)");
5187c478bd9Sstevel@tonic-gate 	gprintf(level, "   dst_encoding: \"%s\"\n",
5197c478bd9Sstevel@tonic-gate 	    gmnp->dst_encoding ? gmnp->dst_encoding : "(null)");
5207c478bd9Sstevel@tonic-gate 	gprintf(level, "   nplurals: %d\n",
5217c478bd9Sstevel@tonic-gate 	    gmnp->nplurals);
5227c478bd9Sstevel@tonic-gate 	gprintf(level, "   plural: 0x%p\n",
5237c478bd9Sstevel@tonic-gate 	    (void *)gmnp->plural);
5247c478bd9Sstevel@tonic-gate 	if (gmnp->plural)
5257c478bd9Sstevel@tonic-gate 		printexpr(gmnp->plural, level+1);
5267c478bd9Sstevel@tonic-gate 	gprintf(level, "   fd: 0x%p\n", (void *)gmnp->fd);
5277c478bd9Sstevel@tonic-gate 	gprintf(level, "   conv_msgstr: 0x%p\n",
5287c478bd9Sstevel@tonic-gate 	    (void *)gmnp->conv_msgstr);
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate void
5327c478bd9Sstevel@tonic-gate printexpr(struct expr *e, int level)
5337c478bd9Sstevel@tonic-gate {
5347c478bd9Sstevel@tonic-gate 	static const char	*op_name[] = {
5357c478bd9Sstevel@tonic-gate 	    "NULL", "INIT", "EXP",
5367c478bd9Sstevel@tonic-gate 	    "NUM", "VAR", "?", ":", "||",
5377c478bd9Sstevel@tonic-gate 	    "&&", "==", "!=", ">", "<",
5387c478bd9Sstevel@tonic-gate 	    ">=", "<=", "+", "-", "*", "/",
5397c478bd9Sstevel@tonic-gate 	    "%", "!", "(", ")", "ERR"
5407c478bd9Sstevel@tonic-gate 	};
5417c478bd9Sstevel@tonic-gate 	switch (GETOPNUM(e->op)) {
5427c478bd9Sstevel@tonic-gate 	case 0:
5437c478bd9Sstevel@tonic-gate 		switch (GETTYPE(e->op)) {
5447c478bd9Sstevel@tonic-gate 		case T_NUM:
5457c478bd9Sstevel@tonic-gate 			gprintf(level, "NUM(%d)\n", e->num);
5467c478bd9Sstevel@tonic-gate 			break;
5477c478bd9Sstevel@tonic-gate 		case T_VAR:
5487c478bd9Sstevel@tonic-gate 			gprintf(level, "VAR(n)\n");
5497c478bd9Sstevel@tonic-gate 			break;
5507c478bd9Sstevel@tonic-gate 		}
5517c478bd9Sstevel@tonic-gate 		break;
5527c478bd9Sstevel@tonic-gate 	case 1:
5537c478bd9Sstevel@tonic-gate 		gprintf(level, "OP: !\n");
5547c478bd9Sstevel@tonic-gate 		printexpr(e->nodes[0], level+1);
5557c478bd9Sstevel@tonic-gate 		break;
5567c478bd9Sstevel@tonic-gate 	case 2:
5577c478bd9Sstevel@tonic-gate 		gprintf(level, "OP: %s\n", op_name[GETTYPE(e->op)]);
5587c478bd9Sstevel@tonic-gate 		printexpr(e->nodes[0], level+1);
5597c478bd9Sstevel@tonic-gate 		printexpr(e->nodes[1], level+1);
5607c478bd9Sstevel@tonic-gate 		break;
5617c478bd9Sstevel@tonic-gate 	case 3:
5627c478bd9Sstevel@tonic-gate 		gprintf(level, "OP: ?\n");
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 		printexpr(e->nodes[0], level+1);
5657c478bd9Sstevel@tonic-gate 		printexpr(e->nodes[1], level+1);
5667c478bd9Sstevel@tonic-gate 		printexpr(e->nodes[2], level+1);
5677c478bd9Sstevel@tonic-gate 		break;
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate void
5737c478bd9Sstevel@tonic-gate printmnp(Msg_node *mnp, int level)
5747c478bd9Sstevel@tonic-gate {
5757c478bd9Sstevel@tonic-gate 	gprintf(level, "=== mnp ===\n");
5767c478bd9Sstevel@tonic-gate 
577*f13ac639Smuffin 	gprintf(level, "   hashid: %d\n", mnp->hashid);
5787c478bd9Sstevel@tonic-gate 	gprintf(level, "   type: \"%s\"\n",
5797c478bd9Sstevel@tonic-gate 	    mnp->type == T_ILL_MO ? "T_ILL_MO" :
5807c478bd9Sstevel@tonic-gate 	    mnp->type == T_SUN_MO ? "T_SUN_MO" :
5817c478bd9Sstevel@tonic-gate 	    mnp->type == T_GNU_MO ? "T_GNU_MO" :
5827c478bd9Sstevel@tonic-gate 	    "UNKNOWN TYPE");
5837c478bd9Sstevel@tonic-gate 	gprintf(level, "   path: \"%s\"\n",
5847c478bd9Sstevel@tonic-gate 	    mnp->path ? mnp->path : "(null)");
5857c478bd9Sstevel@tonic-gate 	gprintf(level, "   msg_file_trusted: %d\n",
5867c478bd9Sstevel@tonic-gate 	    mnp->trusted);
5877c478bd9Sstevel@tonic-gate 	if (mnp->type == T_SUN_MO)
5887c478bd9Sstevel@tonic-gate 		printsunmsg(mnp->msg.sunmsg, level+1);
5897c478bd9Sstevel@tonic-gate 	else if (mnp->type == T_GNU_MO)
5907c478bd9Sstevel@tonic-gate 		printgnumsg(mnp->msg.gnumsg, level+1);
5917c478bd9Sstevel@tonic-gate 	gprintf(level, "   next: 0x%p\n", (void *)mnp->next);
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate void
595*f13ac639Smuffin printnls(Nls_node *n, int level)
5967c478bd9Sstevel@tonic-gate {
597*f13ac639Smuffin 	gprintf(level, "=== nls ===\n");
598*f13ac639Smuffin 	gprintf(level, "   domain: \"%s\"\n", n->domain ? n->domain : "NULL");
599*f13ac639Smuffin 	gprintf(level, "   locale: \"%s\"\n", n->locale ? n->locale : "NULL");
600*f13ac639Smuffin 	gprintf(level, "   nlspath: \"%s\"\n", n->nlspath ? n->nlspath :
601*f13ac639Smuffin 	    "NULL");
602*f13ac639Smuffin 	gprintf(level, "   next: 0x%p\n", n->next);
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate void
606*f13ac639Smuffin printdbind(Dbinding *d, int level)
6077c478bd9Sstevel@tonic-gate {
608*f13ac639Smuffin 	gprintf(level, "=== dbind ===\n");
609*f13ac639Smuffin 	gprintf(level, "   domain: \"%s\"\n", d->domain ? d->domain : "NULL");
610*f13ac639Smuffin 	gprintf(level, "   binding: \"%s\"\n", d->binding ? d->binding :
611*f13ac639Smuffin 	    "NULL");
612*f13ac639Smuffin 	gprintf(level, "   codeset: \"%s\"\n", d->codeset ? d->codeset :
613*f13ac639Smuffin 	    "NULL");
614*f13ac639Smuffin 	gprintf(level, "   next: 0x%p\n", d->next);
6157c478bd9Sstevel@tonic-gate }
616*f13ac639Smuffin 
617*f13ac639Smuffin void
618*f13ac639Smuffin printgt(Gettext_t *gt, int level)
619*f13ac639Smuffin {
620*f13ac639Smuffin 	gprintf(level, "=== gt ===\n");
621*f13ac639Smuffin 	gprintf(level, "   cur_domain: \"%s\"\n", gt->cur_domain);
622*f13ac639Smuffin 	if (gt->dbind) {
623*f13ac639Smuffin 		printdbind(gt->dbind, level+1);
624*f13ac639Smuffin 	} else {
625*f13ac639Smuffin 		gprintf(level, "   dbind: NULL\n");
626*f13ac639Smuffin 	}
627*f13ac639Smuffin 	if (gt->m_node) {
628*f13ac639Smuffin 		printmnp(gt->m_node, level + 1);
629*f13ac639Smuffin 	} else {
630*f13ac639Smuffin 		gprintf(level, "   m_node: NULL\n");
631*f13ac639Smuffin 	}
632*f13ac639Smuffin 	if (gt->n_node) {
633*f13ac639Smuffin 		printnls(gt->n_node, level + 1);
634*f13ac639Smuffin 	} else {
635*f13ac639Smuffin 		gprintf(level, "   n_node: NULL\n");
636*f13ac639Smuffin 	}
637*f13ac639Smuffin 	if (gt->c_m_node) {
638*f13ac639Smuffin 		printmnp(gt->c_m_node, level + 1);
639*f13ac639Smuffin 	} else {
640*f13ac639Smuffin 		gprintf(level, "   c_m_node: NULL\n");
641*f13ac639Smuffin 	}
642*f13ac639Smuffin 	if (gt->c_n_node) {
643*f13ac639Smuffin 		printnls(gt->c_n_node, level + 1);
644*f13ac639Smuffin 	} else {
645*f13ac639Smuffin 		gprintf(level, "   c_n_node: NULL\n");
646*f13ac639Smuffin 	}
647*f13ac639Smuffin }
648*f13ac639Smuffin 
6497c478bd9Sstevel@tonic-gate #endif
650