xref: /onnv-gate/usr/src/lib/libc/port/i18n/gettext_real.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  */
211219Sraf 
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 <locale.h>
330Sstevel@tonic-gate #include <stdio.h>
340Sstevel@tonic-gate #include <stdlib.h>
350Sstevel@tonic-gate #include <string.h>
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include <sys/mman.h>
380Sstevel@tonic-gate #include <sys/param.h>
390Sstevel@tonic-gate #include <sys/stat.h>
400Sstevel@tonic-gate #include <libintl.h>
410Sstevel@tonic-gate #include <thread.h>
420Sstevel@tonic-gate #include <synch.h>
430Sstevel@tonic-gate #include <limits.h>
440Sstevel@tonic-gate #include <unistd.h>
450Sstevel@tonic-gate #include "libc.h"
460Sstevel@tonic-gate #include "_loc_path.h"
470Sstevel@tonic-gate #include "msgfmt.h"
480Sstevel@tonic-gate #include "gettext.h"
490Sstevel@tonic-gate #include "nlspath_checks.h"
500Sstevel@tonic-gate 
510Sstevel@tonic-gate static int	process_nlspath(const char *, const char *,
526793Smuffin     const char *, char **);
536793Smuffin static char	*replace_nls_option(char *, const char *, char *,
546793Smuffin     char *, char *, char *, char *);
550Sstevel@tonic-gate 
560Sstevel@tonic-gate char *
_real_gettext_u(const char * domain,const char * msgid1,const char * msgid2,unsigned long int ln,int category,int plural)576793Smuffin _real_gettext_u(const char *domain, const char *msgid1, const char *msgid2,
586793Smuffin     unsigned long int ln, int category, int plural)
590Sstevel@tonic-gate {
600Sstevel@tonic-gate 	char	msgfile[MAXPATHLEN]; 	/* 1024 */
610Sstevel@tonic-gate 	char	mydomain[TEXTDOMAINMAX + 1]; /* 256 + 1 */
620Sstevel@tonic-gate 	char	*cur_binding;	/* points to current binding in list */
636793Smuffin 	char	*cur_locale, *cur_domain, *result, *nlspath;
646793Smuffin 	char	*msgloc, *cb, *cur_domain_binding;
650Sstevel@tonic-gate 	char	*language;
666793Smuffin 	unsigned int	n = (unsigned int)ln;	/* we don't need long for n */
676793Smuffin 	uint32_t	cur_domain_len, cblen;
686793Smuffin 	uint32_t	hash_domain;
691219Sraf 	struct msg_pack	*mp, omp;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
726793Smuffin 	gprintf(0, "*************** _real_gettext_u(\"%s\", \"%s\", "
736793Smuffin 	    "\"%s\", %d, %d, %d)\n",
740Sstevel@tonic-gate 	    domain ? domain : "NULL", msgid1 ? msgid1 : "NULL",
756793Smuffin 	    msgid2 ? msgid2 : "NULL", n, category, plural);
766793Smuffin 	gprintf(0, "***************** global_gt: 0x%p\n", global_gt);
776793Smuffin 	printgt(global_gt, 1);
780Sstevel@tonic-gate #endif
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	if (msgid1 == NULL)
810Sstevel@tonic-gate 		return (NULL);
820Sstevel@tonic-gate 
831219Sraf 	mp = memset(&omp, 0, sizeof (omp));	/* msg pack */
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 	/*
860Sstevel@tonic-gate 	 * category may be LC_MESSAGES or LC_TIME
870Sstevel@tonic-gate 	 * locale contains the value of 'category'
880Sstevel@tonic-gate 	 */
896793Smuffin 	cur_locale = setlocale(category, NULL);
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	language = getenv("LANGUAGE"); /* for GNU */
920Sstevel@tonic-gate 	if (language) {
930Sstevel@tonic-gate 		if (!*language || strchr(language, '/') != NULL) {
940Sstevel@tonic-gate 			/*
950Sstevel@tonic-gate 			 * LANGUAGE is an empty string or
960Sstevel@tonic-gate 			 * LANGUAGE contains '/'.
970Sstevel@tonic-gate 			 * Ignore it.
980Sstevel@tonic-gate 			 */
990Sstevel@tonic-gate 			language = NULL;
1000Sstevel@tonic-gate 		}
1010Sstevel@tonic-gate 	}
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	/*
1040Sstevel@tonic-gate 	 * Query the current domain if domain argument is NULL pointer
1050Sstevel@tonic-gate 	 */
1060Sstevel@tonic-gate 	mydomain[0] = '\0';
1076793Smuffin 	if (domain == NULL) {
1080Sstevel@tonic-gate 		/*
1090Sstevel@tonic-gate 		 * if NULL is specified for domainname,
1100Sstevel@tonic-gate 		 * use the currently bound domain.
1110Sstevel@tonic-gate 		 */
1120Sstevel@tonic-gate 		cur_domain = _textdomain_u(NULL, mydomain);
1130Sstevel@tonic-gate 	} else if (!*domain) {
1140Sstevel@tonic-gate 		/*
1150Sstevel@tonic-gate 		 * if an empty string is specified
1160Sstevel@tonic-gate 		 */
1170Sstevel@tonic-gate 		cur_domain = DEFAULT_DOMAIN;
1180Sstevel@tonic-gate 	} else {
1190Sstevel@tonic-gate 		cur_domain = (char *)domain;
1200Sstevel@tonic-gate 	}
1210Sstevel@tonic-gate 
1226793Smuffin 	hash_domain = get_hashid(cur_domain, &cur_domain_len);
1236793Smuffin 	if (cur_domain_len > TEXTDOMAINMAX) {
1246793Smuffin 		/* domain is invalid, return msg_id */
1256793Smuffin 		DFLTMSG(result, msgid1, msgid2, n, plural);
1266793Smuffin 		return (result);
1276793Smuffin 	}
1286793Smuffin 
1290Sstevel@tonic-gate 	nlspath = getenv("NLSPATH"); /* get the content of NLSPATH */
1306793Smuffin 	if (nlspath == NULL || !*nlspath) {
1310Sstevel@tonic-gate 		/* no NLSPATH is defined in the environ */
1320Sstevel@tonic-gate 		if ((*cur_locale == 'C') && (*(cur_locale + 1) == '\0')) {
1330Sstevel@tonic-gate 			/*
1340Sstevel@tonic-gate 			 * If C locale,
1350Sstevel@tonic-gate 			 * return the original msgid immediately.
1360Sstevel@tonic-gate 			 */
1370Sstevel@tonic-gate 			DFLTMSG(result, msgid1, msgid2, n, plural);
1380Sstevel@tonic-gate 			return (result);
1390Sstevel@tonic-gate 		}
1400Sstevel@tonic-gate 		nlspath = NULL;
1410Sstevel@tonic-gate 	} else {
1420Sstevel@tonic-gate 		/* NLSPATH is set */
1430Sstevel@tonic-gate 		int	ret;
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 		msgloc = setlocale(LC_MESSAGES, NULL);
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 		ret = process_nlspath(cur_domain, msgloc,
1486793Smuffin 		    (const char *)nlspath, &cur_binding);
1490Sstevel@tonic-gate 		if (ret == -1) {
1500Sstevel@tonic-gate 			/* error occurred */
1510Sstevel@tonic-gate 			DFLTMSG(result, msgid1, msgid2, n, plural);
1520Sstevel@tonic-gate 			return (result);
1530Sstevel@tonic-gate 		} else if (ret == 0) {
1540Sstevel@tonic-gate 			nlspath = NULL;
1550Sstevel@tonic-gate 		}
1560Sstevel@tonic-gate 	}
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	cur_domain_binding = _real_bindtextdomain_u(cur_domain,
1596793Smuffin 	    NULL, TP_BINDING);
1606793Smuffin 	if (cur_domain_binding == NULL) {
1610Sstevel@tonic-gate 		DFLTMSG(result, msgid1, msgid2, n, plural);
1620Sstevel@tonic-gate 		return (result);
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	mp->msgid1 = msgid1;
1660Sstevel@tonic-gate 	mp->msgid2 = msgid2;
1670Sstevel@tonic-gate 	mp->msgfile = msgfile;
1680Sstevel@tonic-gate 	mp->domain = cur_domain;
1690Sstevel@tonic-gate 	mp->binding = cur_domain_binding;
1700Sstevel@tonic-gate 	mp->locale = cur_locale;
1710Sstevel@tonic-gate 	mp->language = language;
1720Sstevel@tonic-gate 	mp->domain_len = cur_domain_len;
1730Sstevel@tonic-gate 	mp->n = n;
1740Sstevel@tonic-gate 	mp->category = category;
1750Sstevel@tonic-gate 	mp->plural = plural;
1766793Smuffin 	mp->hash_domain = hash_domain;
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	/*
1790Sstevel@tonic-gate 	 * Spec1170 requires that we use NLSPATH if it's defined, to
1800Sstevel@tonic-gate 	 * override any system default variables.  If NLSPATH is not
1810Sstevel@tonic-gate 	 * defined or if a message catalog is not found in any of the
1820Sstevel@tonic-gate 	 * components (bindings) specified by NLSPATH, dcgettext_u() will
1830Sstevel@tonic-gate 	 * search for the message catalog in either a) the binding path set
1840Sstevel@tonic-gate 	 * by any previous application calls to bindtextdomain() or
1850Sstevel@tonic-gate 	 * b) the default binding path (/usr/lib/locale).  Save the original
1860Sstevel@tonic-gate 	 * binding path so that we can search it if the message catalog
1870Sstevel@tonic-gate 	 * is not found via NLSPATH.  The original binding is restored before
1880Sstevel@tonic-gate 	 * returning from this routine because the gettext routines should
1890Sstevel@tonic-gate 	 * not change the binding set by the application.  This allows
1900Sstevel@tonic-gate 	 * bindtextdomain() to be called once for all gettext() calls in the
1910Sstevel@tonic-gate 	 * application.
1920Sstevel@tonic-gate 	 */
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	/*
1950Sstevel@tonic-gate 	 * First, examine NLSPATH
1960Sstevel@tonic-gate 	 */
1970Sstevel@tonic-gate 	if (nlspath) {
1980Sstevel@tonic-gate 		/*
1990Sstevel@tonic-gate 		 * NLSPATH binding has been successfully built
2000Sstevel@tonic-gate 		 */
2010Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
2026793Smuffin 		gprintf(0, "************************** examining NLSPATH\n");
2036793Smuffin 		gprintf(0, "       cur_binding: \"%s\"\n",
2046793Smuffin 		    cur_binding ? cur_binding : "(null)");
2050Sstevel@tonic-gate #endif
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 		mp->nlsp = 1;
2080Sstevel@tonic-gate 		/*
2090Sstevel@tonic-gate 		 * cur_binding always ends with ':' before a null
2100Sstevel@tonic-gate 		 * termination.
2110Sstevel@tonic-gate 		 */
2120Sstevel@tonic-gate 		while (*cur_binding) {
2130Sstevel@tonic-gate 			cb = cur_binding;
2140Sstevel@tonic-gate 			while (*cur_binding != ':')
2150Sstevel@tonic-gate 				cur_binding++;
2160Sstevel@tonic-gate 			cblen = cur_binding - cb;
2170Sstevel@tonic-gate 			cur_binding++;
2180Sstevel@tonic-gate 			if (cblen >= MAXPATHLEN) {
2190Sstevel@tonic-gate 				/* cur_binding too long */
2200Sstevel@tonic-gate 				DFLTMSG(result, msgid1, msgid2, n, plural);
2210Sstevel@tonic-gate 				return (result);
2220Sstevel@tonic-gate 			}
2230Sstevel@tonic-gate 
2246793Smuffin 			(void) memcpy(mp->msgfile, cb, cblen);
2256793Smuffin 			*(mp->msgfile + cblen) = '\0';
2266793Smuffin 
2270Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
2286793Smuffin 			gprintf(0, "*******************"
2296793Smuffin 			    "********************* \n");
2306793Smuffin 			gprintf(0, "       msgfile: \"%s\"\n",
2316793Smuffin 			    msgfile ? msgfile : "(null)");
2326793Smuffin 			gprintf(0, "*******************"
2336793Smuffin 			    "********************* \n");
2340Sstevel@tonic-gate #endif
2356793Smuffin 			result = handle_mo(mp);
2360Sstevel@tonic-gate 			if (result) {
2370Sstevel@tonic-gate 				return (result);
2380Sstevel@tonic-gate 			}
2390Sstevel@tonic-gate 		}
2400Sstevel@tonic-gate 	}
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	mp->nlsp = 0;
2430Sstevel@tonic-gate 	mp->binding = cur_domain_binding;
2440Sstevel@tonic-gate 	/*
2450Sstevel@tonic-gate 	 * Next, examine LANGUAGE
2460Sstevel@tonic-gate 	 */
2470Sstevel@tonic-gate 	if (language) {
2480Sstevel@tonic-gate 		char	*ret_msg;
2496793Smuffin 		ret_msg = handle_lang(mp);
2500Sstevel@tonic-gate 		if (ret_msg != NULL) {
2516793Smuffin 			/* valid msg found in GNU MO */
2520Sstevel@tonic-gate 			return (ret_msg);
2530Sstevel@tonic-gate 		}
2540Sstevel@tonic-gate 		/*
2556793Smuffin 		 * handle_lang() may have overridden locale
2560Sstevel@tonic-gate 		 */
2570Sstevel@tonic-gate 		mp->locale = cur_locale;
2586793Smuffin 		mp->status = 0;
2590Sstevel@tonic-gate 	}
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	/*
2620Sstevel@tonic-gate 	 * Finally, handle a single binding
2630Sstevel@tonic-gate 	 */
2640Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
2650Sstevel@tonic-gate 	*mp->msgfile = '\0';
2660Sstevel@tonic-gate #endif
2670Sstevel@tonic-gate 	if (mk_msgfile(mp) == NULL) {
2680Sstevel@tonic-gate 		DFLTMSG(result, msgid1, msgid2, n, plural);
2690Sstevel@tonic-gate 		return (result);
2700Sstevel@tonic-gate 	}
2710Sstevel@tonic-gate 
2726793Smuffin 	result = handle_mo(mp);
2730Sstevel@tonic-gate 	if (result) {
2740Sstevel@tonic-gate 		return (result);
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate 	DFLTMSG(result, msgid1, msgid2, n, plural);
2770Sstevel@tonic-gate 	return (result);
2780Sstevel@tonic-gate } /* _real_gettext_u */
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate #define	ALLFREE	\
2816793Smuffin 	free_all(nlstmp, nnp, pathname, ppaths, lang)
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate static void
free_all(Nlstmp * nlstmp,Nls_node * nnp,char * pathname,char * ppaths,char * lang)2840Sstevel@tonic-gate free_all(Nlstmp *nlstmp, Nls_node *nnp, char *pathname,
2856793Smuffin     char *ppaths, char *lang)
2860Sstevel@tonic-gate {
2870Sstevel@tonic-gate 	Nlstmp	*tp, *tq;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	tp = nlstmp;
2900Sstevel@tonic-gate 	while (tp) {
2910Sstevel@tonic-gate 		tq = tp->next;
2920Sstevel@tonic-gate 		free(tp);
2930Sstevel@tonic-gate 		tp = tq;
2940Sstevel@tonic-gate 	}
2950Sstevel@tonic-gate 	if (nnp->locale)
2960Sstevel@tonic-gate 		free(nnp->locale);
2970Sstevel@tonic-gate 	if (nnp->domain)
2980Sstevel@tonic-gate 		free(nnp->domain);
2990Sstevel@tonic-gate 	if (pathname)
3000Sstevel@tonic-gate 		free(pathname);
3010Sstevel@tonic-gate 	if (ppaths)
3020Sstevel@tonic-gate 		free(ppaths);
3030Sstevel@tonic-gate 	if (lang)
3040Sstevel@tonic-gate 		free(lang);
3050Sstevel@tonic-gate 	free(nnp);
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate /*
3090Sstevel@tonic-gate  * process_nlspath(): process the NLSPATH environment variable.
3100Sstevel@tonic-gate  *
3110Sstevel@tonic-gate  *		this routine looks at NLSPATH in the environment,
3120Sstevel@tonic-gate  *		and will try to build up the binding list based
3130Sstevel@tonic-gate  *		on the settings of NLSPATH.
3140Sstevel@tonic-gate  *
3150Sstevel@tonic-gate  * RETURN:
3160Sstevel@tonic-gate  * -1:  Error occurred
3170Sstevel@tonic-gate  *  0:  No error, but no binding list has been built
3180Sstevel@tonic-gate  *  1:  No error, and a binding list has been built
3190Sstevel@tonic-gate  *
3200Sstevel@tonic-gate  */
3210Sstevel@tonic-gate static int
process_nlspath(const char * cur_domain,const char * cur_msgloc,const char * nlspath,char ** binding)3220Sstevel@tonic-gate process_nlspath(const char *cur_domain, const char *cur_msgloc,
3236793Smuffin     const char *nlspath, char **binding)
3240Sstevel@tonic-gate {
3250Sstevel@tonic-gate 	char 	*s;				/* generic string ptr */
3260Sstevel@tonic-gate 	char	*territory;		/* our current territory element */
3270Sstevel@tonic-gate 	char	*codeset;		/* our current codeset element */
3280Sstevel@tonic-gate 	char	*s1;			/* for handling territory */
3290Sstevel@tonic-gate 	char	*s2;			/* for handling codeset */
3300Sstevel@tonic-gate 	char	*lang = NULL;	/* our current language element */
3310Sstevel@tonic-gate 	char	*ppaths = NULL;	/* ptr to all of the templates */
3320Sstevel@tonic-gate 	char	*pathname = NULL;	/* the full pathname to the file */
3330Sstevel@tonic-gate 	size_t	nlspath_len, domain_len, locale_len, path_len;
3340Sstevel@tonic-gate 	size_t	ppaths_len = 0;
3350Sstevel@tonic-gate 	Nlstmp	*nlstmp = NULL;
3360Sstevel@tonic-gate 	Nlstmp	*pnlstmp, *qnlstmp;
3376793Smuffin 	Nls_node	*cur_nls, *nnp;
3380Sstevel@tonic-gate 	Gettext_t	*gt = global_gt;
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
3416793Smuffin 	gprintf(0, "*************** process_nlspath(%s, %s, "
3426793Smuffin 	    "%s, 0x%p)\n", cur_domain,
3430Sstevel@tonic-gate 	    cur_msgloc, nlspath, (void *)binding);
3440Sstevel@tonic-gate #endif
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	cur_nls = gt->c_n_node;
3470Sstevel@tonic-gate 	if (cur_nls &&
3486793Smuffin 	    (strcmp(cur_nls->domain, cur_domain) == 0 &&
3496793Smuffin 	    strcmp(cur_nls->locale, cur_msgloc) == 0 &&
3506793Smuffin 	    strcmp(cur_nls->nlspath, nlspath) == 0)) {
3510Sstevel@tonic-gate 		*binding = cur_nls->ppaths;
3520Sstevel@tonic-gate 		return (1);
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 
3556793Smuffin 	nnp = gt->n_node;
3566793Smuffin 	while (nnp) {
3576793Smuffin 		if (strcmp(nnp->domain, cur_domain) == 0 &&
3586793Smuffin 		    strcmp(nnp->locale, cur_msgloc) == 0 &&
3596793Smuffin 		    strcmp(nnp->nlspath, nlspath) == 0) {
3606793Smuffin 			/* found */
3616793Smuffin 			gt->c_n_node = nnp;
3626793Smuffin 			*binding = nnp->ppaths;
3636793Smuffin 			return (1);
3640Sstevel@tonic-gate 		}
3656793Smuffin 		nnp = nnp->next;
3660Sstevel@tonic-gate 	}
3676793Smuffin 	/* not found */
3680Sstevel@tonic-gate 
3696793Smuffin 	nnp = calloc(1, sizeof (Nls_node));
3706793Smuffin 	if (nnp == NULL) {
3716793Smuffin 		ALLFREE;
3726793Smuffin 		return (-1);
3730Sstevel@tonic-gate 	}
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	nlspath_len = strlen(nlspath);
3760Sstevel@tonic-gate 	locale_len = strlen(cur_msgloc);
3770Sstevel@tonic-gate 	domain_len = strlen(cur_domain);
3780Sstevel@tonic-gate 
3796793Smuffin 	lang = s = strdup(cur_msgloc);
3806793Smuffin 	if (lang == NULL) {
3816793Smuffin 		ALLFREE;
3826793Smuffin 		return (-1);
3836793Smuffin 	}
3846793Smuffin 	s1 = s2 = NULL;
3856793Smuffin 	while (*s) {
3866793Smuffin 		if (*s == '_') {
3876793Smuffin 			s1 = s;
3886793Smuffin 			*s1++ = '\0';
3896793Smuffin 		} else if (*s == '.') {
3906793Smuffin 			s2 = s;
3916793Smuffin 			*s2++ = '\0';
3920Sstevel@tonic-gate 		}
3936793Smuffin 		s++;
3940Sstevel@tonic-gate 	}
3956793Smuffin 	territory = s1;
3966793Smuffin 	codeset = s2;
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	/*
3990Sstevel@tonic-gate 	 * now that we have the name (domain), we first look through NLSPATH,
4000Sstevel@tonic-gate 	 * in an attempt to get the locale. A locale may be completely
4010Sstevel@tonic-gate 	 * specified as "language_territory.codeset". NLSPATH consists
4020Sstevel@tonic-gate 	 * of templates separated by ":" characters. The following are
4030Sstevel@tonic-gate 	 * the substitution values within NLSPATH:
4040Sstevel@tonic-gate 	 *	%N = DEFAULT_DOMAIN
4050Sstevel@tonic-gate 	 *	%L = The value of the LC_MESSAGES category.
4060Sstevel@tonic-gate 	 *	%I = The language element from the LC_MESSAGES category.
4070Sstevel@tonic-gate 	 *	%t = The territory element from the LC_MESSAGES category.
4080Sstevel@tonic-gate 	 *	%c = The codeset element from the LC_MESSAGES category.
4090Sstevel@tonic-gate 	 *	%% = A single character.
4100Sstevel@tonic-gate 	 * if we find one of these characters, we will carry out the
4110Sstevel@tonic-gate 	 * appropriate substitution.
4120Sstevel@tonic-gate 	 */
4136793Smuffin 	pathname = malloc(MAXPATHLEN);
4140Sstevel@tonic-gate 	if (pathname == NULL) {
4150Sstevel@tonic-gate 		ALLFREE;
4160Sstevel@tonic-gate 		return (-1);
4170Sstevel@tonic-gate 	}
4180Sstevel@tonic-gate 	s = (char *)nlspath;		/* s has a content of NLSPATH */
4190Sstevel@tonic-gate 	while (*s) {				/* march through NLSPATH */
4200Sstevel@tonic-gate 		(void) memset(pathname, 0, MAXPATHLEN);
4210Sstevel@tonic-gate 		if (*s == ':') {
4220Sstevel@tonic-gate 			/*
4230Sstevel@tonic-gate 			 * this loop only occurs if we have to replace
4240Sstevel@tonic-gate 			 * ":" by "name". replace_nls_option() below
4250Sstevel@tonic-gate 			 * will handle the subsequent ":"'s.
4260Sstevel@tonic-gate 			 */
4276793Smuffin 			pnlstmp = malloc(sizeof (Nlstmp));
4286793Smuffin 			if (pnlstmp == NULL) {
4290Sstevel@tonic-gate 				ALLFREE;
4300Sstevel@tonic-gate 				return (-1);
4310Sstevel@tonic-gate 			}
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 			(void) memcpy(pnlstmp->pathname, cur_domain,
4346793Smuffin 			    domain_len + 1);
4356793Smuffin 			pnlstmp->len = domain_len;
4366793Smuffin 			ppaths_len += domain_len + 1; /* 1 for ':' */
4376793Smuffin 
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 			pnlstmp->next = NULL;
4400Sstevel@tonic-gate 
4416793Smuffin 			if (nlstmp == NULL) {
4420Sstevel@tonic-gate 				nlstmp = pnlstmp;
4430Sstevel@tonic-gate 				qnlstmp = pnlstmp;
4440Sstevel@tonic-gate 			} else {
4450Sstevel@tonic-gate 				qnlstmp->next = pnlstmp;
4460Sstevel@tonic-gate 				qnlstmp = pnlstmp;
4470Sstevel@tonic-gate 			}
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 			++s;
4500Sstevel@tonic-gate 			continue;
4510Sstevel@tonic-gate 		}
4520Sstevel@tonic-gate 		/* replace Substitution field */
4530Sstevel@tonic-gate 		s = replace_nls_option(s, cur_domain, pathname,
4546793Smuffin 		    (char *)cur_msgloc, lang, territory, codeset);
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 		if (s == NULL) {
4570Sstevel@tonic-gate 			ALLFREE;
4580Sstevel@tonic-gate 			return (-1);
4590Sstevel@tonic-gate 		}
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 		/* if we've found a valid file: */
4620Sstevel@tonic-gate 		if (*pathname) {
4630Sstevel@tonic-gate 			/* add template to end of chain of pathnames: */
4646793Smuffin 			pnlstmp = malloc(sizeof (Nlstmp));
4656793Smuffin 			if (pnlstmp == NULL) {
4660Sstevel@tonic-gate 				ALLFREE;
4670Sstevel@tonic-gate 				return (-1);
4680Sstevel@tonic-gate 			}
4690Sstevel@tonic-gate 
4706793Smuffin 			path_len = strlen(pathname);
4710Sstevel@tonic-gate 			(void) memcpy(pnlstmp->pathname, pathname,
4726793Smuffin 			    path_len + 1);
4736793Smuffin 			pnlstmp->len = path_len;
4746793Smuffin 			ppaths_len += path_len + 1; /* 1 for ':' */
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 			pnlstmp->next = NULL;
4770Sstevel@tonic-gate 
4786793Smuffin 			if (nlstmp == NULL) {
4790Sstevel@tonic-gate 				nlstmp = pnlstmp;
4800Sstevel@tonic-gate 				qnlstmp = pnlstmp;
4810Sstevel@tonic-gate 			} else {
4820Sstevel@tonic-gate 				qnlstmp->next = pnlstmp;
4830Sstevel@tonic-gate 				qnlstmp = pnlstmp;
4840Sstevel@tonic-gate 			}
4850Sstevel@tonic-gate 		}
4860Sstevel@tonic-gate 		if (*s) {
4870Sstevel@tonic-gate 			++s;
4880Sstevel@tonic-gate 		}
4890Sstevel@tonic-gate 	}
4900Sstevel@tonic-gate 	/*
4910Sstevel@tonic-gate 	 * now that we've handled the pathname templates, concatenate them
4920Sstevel@tonic-gate 	 * all into the form "template1:template2:..." for _bindtextdomain_u()
4930Sstevel@tonic-gate 	 */
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	if (ppaths_len != 0) {
4966793Smuffin 		ppaths = malloc(ppaths_len + 1);
4976793Smuffin 		if (ppaths == NULL) {
4980Sstevel@tonic-gate 			ALLFREE;
4990Sstevel@tonic-gate 			return (-1);
5000Sstevel@tonic-gate 		}
5010Sstevel@tonic-gate 		*ppaths = '\0';
5020Sstevel@tonic-gate 	} else {
5030Sstevel@tonic-gate 		ALLFREE;
5040Sstevel@tonic-gate 		return (0);
5050Sstevel@tonic-gate 	}
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	/*
5080Sstevel@tonic-gate 	 * extract the path templates (fifo), and concatenate them
5090Sstevel@tonic-gate 	 * all into a ":" separated string for _bindtextdomain_u()
5100Sstevel@tonic-gate 	 */
5110Sstevel@tonic-gate 	pnlstmp = nlstmp;
5126793Smuffin 	s = ppaths;
5130Sstevel@tonic-gate 	while (pnlstmp) {
5146793Smuffin 		(void) memcpy(s, pnlstmp->pathname, pnlstmp->len);
5156793Smuffin 		s += pnlstmp->len;
5166793Smuffin 		*s++ = ':';
5170Sstevel@tonic-gate 		qnlstmp = pnlstmp->next;
5180Sstevel@tonic-gate 		free(pnlstmp);
5190Sstevel@tonic-gate 		pnlstmp = qnlstmp;
5200Sstevel@tonic-gate 	}
5216793Smuffin 	*s = '\0';
5220Sstevel@tonic-gate 	nlstmp = NULL;
5230Sstevel@tonic-gate 
5246793Smuffin 	nnp->domain = malloc(domain_len + 1);
5256793Smuffin 	if (nnp->domain == NULL) {
5260Sstevel@tonic-gate 		ALLFREE;
5270Sstevel@tonic-gate 		return (-1);
5280Sstevel@tonic-gate 	} else {
5296793Smuffin 		(void) memcpy(nnp->domain, cur_domain, domain_len + 1);
5300Sstevel@tonic-gate 	}
5316793Smuffin 	nnp->locale = malloc(locale_len + 1);
5326793Smuffin 	if (nnp->locale == NULL) {
5330Sstevel@tonic-gate 		ALLFREE;
5340Sstevel@tonic-gate 		return (-1);
5350Sstevel@tonic-gate 	} else {
5366793Smuffin 		(void) memcpy(nnp->locale, cur_msgloc, locale_len + 1);
5376793Smuffin 	}
5386793Smuffin 	nnp->nlspath = malloc(nlspath_len + 1);
5396793Smuffin 	if (nnp->nlspath == NULL) {
5406793Smuffin 		ALLFREE;
5416793Smuffin 		return (-1);
5426793Smuffin 	} else {
5436793Smuffin 		(void) memcpy(nnp->nlspath, nlspath, nlspath_len + 1);
5440Sstevel@tonic-gate 	}
5450Sstevel@tonic-gate 	nnp->ppaths = ppaths;
5460Sstevel@tonic-gate 
5476793Smuffin 	nnp->next = gt->n_node;
5486793Smuffin 	gt->n_node = nnp;
5490Sstevel@tonic-gate 	gt->c_n_node = nnp;
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	free(pathname);
5520Sstevel@tonic-gate 	free(lang);
5530Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
5546793Smuffin 	gprintf(0, "*************** existing process_nlspath with success\n");
5556793Smuffin 	gprintf(0, "       binding: \"%s\"\n", ppaths);
5560Sstevel@tonic-gate #endif
5570Sstevel@tonic-gate 	*binding = ppaths;
5580Sstevel@tonic-gate 	return (1);
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate /*
5630Sstevel@tonic-gate  * This routine will replace substitution parameters in NLSPATH
5640Sstevel@tonic-gate  * with appropiate values.
5650Sstevel@tonic-gate  */
5660Sstevel@tonic-gate static char *
replace_nls_option(char * s,const char * name,char * pathname,char * locale,char * lang,char * territory,char * codeset)5670Sstevel@tonic-gate replace_nls_option(char *s, const char *name, char *pathname,
5686793Smuffin     char *locale, char *lang, char *territory, char *codeset)
5690Sstevel@tonic-gate {
5700Sstevel@tonic-gate 	char	*t, *u;
5710Sstevel@tonic-gate 	char	*limit;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	t = pathname;
5740Sstevel@tonic-gate 	limit = pathname + MAXPATHLEN - 1;
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	while (*s && *s != ':') {
5770Sstevel@tonic-gate 		if (t < limit) {
5780Sstevel@tonic-gate 			/*
5790Sstevel@tonic-gate 			 * %% is considered a single % character (XPG).
5800Sstevel@tonic-gate 			 * %L : LC_MESSAGES (XPG4) LANG(XPG3)
5810Sstevel@tonic-gate 			 * %l : The language element from the current locale.
5820Sstevel@tonic-gate 			 *	(XPG3, XPG4)
5830Sstevel@tonic-gate 			 */
5840Sstevel@tonic-gate 			if (*s != '%')
5850Sstevel@tonic-gate 				*t++ = *s;
5860Sstevel@tonic-gate 			else if (*++s == 'N') {
5870Sstevel@tonic-gate 				if (name) {
5880Sstevel@tonic-gate 					u = (char *)name;
5890Sstevel@tonic-gate 					while (*u && (t < limit))
5900Sstevel@tonic-gate 						*t++ = *u++;
5910Sstevel@tonic-gate 				}
5920Sstevel@tonic-gate 			} else if (*s == 'L') {
5930Sstevel@tonic-gate 				if (locale) {
5940Sstevel@tonic-gate 					u = locale;
5950Sstevel@tonic-gate 					while (*u && (t < limit))
5960Sstevel@tonic-gate 						*t++ = *u++;
5970Sstevel@tonic-gate 				}
5980Sstevel@tonic-gate 			} else if (*s == 'l') {
5990Sstevel@tonic-gate 				if (lang) {
6000Sstevel@tonic-gate 					u = lang;
6010Sstevel@tonic-gate 					while (*u && (*u != '_') &&
6026793Smuffin 					    (t < limit))
6030Sstevel@tonic-gate 						*t++ = *u++;
6040Sstevel@tonic-gate 				}
6050Sstevel@tonic-gate 			} else if (*s == 't') {
6060Sstevel@tonic-gate 				if (territory) {
6070Sstevel@tonic-gate 					u = territory;
6080Sstevel@tonic-gate 					while (*u && (*u != '.') &&
6096793Smuffin 					    (t < limit))
6100Sstevel@tonic-gate 						*t++ = *u++;
6110Sstevel@tonic-gate 				}
6120Sstevel@tonic-gate 			} else if (*s == 'c') {
6130Sstevel@tonic-gate 				if (codeset) {
6140Sstevel@tonic-gate 					u = codeset;
6150Sstevel@tonic-gate 					while (*u && (t < limit))
6160Sstevel@tonic-gate 						*t++ = *u++;
6170Sstevel@tonic-gate 				}
6180Sstevel@tonic-gate 			} else {
6190Sstevel@tonic-gate 				if (t < limit)
6200Sstevel@tonic-gate 					*t++ = *s;
6210Sstevel@tonic-gate 			}
6220Sstevel@tonic-gate 		} else {
6230Sstevel@tonic-gate 			/* too long pathname */
6240Sstevel@tonic-gate 			return (NULL);
6250Sstevel@tonic-gate 		}
6260Sstevel@tonic-gate 		++s;
6270Sstevel@tonic-gate 	}
6280Sstevel@tonic-gate 	*t = '\0';
6290Sstevel@tonic-gate 	return (s);
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate char *
_real_bindtextdomain_u(const char * domain,const char * binding,int type)6340Sstevel@tonic-gate _real_bindtextdomain_u(const char *domain, const char *binding,
6356793Smuffin     int type)
6360Sstevel@tonic-gate {
6370Sstevel@tonic-gate 	struct domain_binding	*bind, *prev;
6380Sstevel@tonic-gate 	Gettext_t	*gt = global_gt;
6390Sstevel@tonic-gate 	char	**binding_addr;
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
6426793Smuffin 	gprintf(0, "*************** _real_bindtextdomain_u(\"%s\", "
6436793Smuffin 	    "\"%s\", \"%s\")\n",
6446793Smuffin 	    (domain ? domain : ""),
6456793Smuffin 	    (binding ? binding : ""),
6466793Smuffin 	    (type == TP_BINDING) ? "TP_BINDING" : "TP_CODESET");
6470Sstevel@tonic-gate #endif
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	/*
6500Sstevel@tonic-gate 	 * If domain is a NULL pointer, no change will occur regardless
6510Sstevel@tonic-gate 	 * of binding value. Just return NULL.
6520Sstevel@tonic-gate 	 */
6536793Smuffin 	if (domain == NULL) {
6540Sstevel@tonic-gate 		return (NULL);
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	/*
6580Sstevel@tonic-gate 	 * Global Binding is not supported any more.
6590Sstevel@tonic-gate 	 * Just return NULL if domain is NULL string.
6600Sstevel@tonic-gate 	 */
6610Sstevel@tonic-gate 	if (*domain == '\0') {
6620Sstevel@tonic-gate 		return (NULL);
6630Sstevel@tonic-gate 	}
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	/* linear search for binding, rebind if found, add if not */
6660Sstevel@tonic-gate 	bind = FIRSTBIND(gt);
6670Sstevel@tonic-gate 	prev = NULL;	/* Two pointers needed for pointer operations */
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	while (bind) {
6700Sstevel@tonic-gate 		if (strcmp(domain, bind->domain) == 0) {
6710Sstevel@tonic-gate 			/*
6720Sstevel@tonic-gate 			 * Domain found.
6730Sstevel@tonic-gate 			 */
6740Sstevel@tonic-gate 			binding_addr = (type == TP_BINDING) ? &(bind->binding) :
6756793Smuffin 			    &(bind->codeset);
6766793Smuffin 			if (binding == NULL) {
6770Sstevel@tonic-gate 				/*
6780Sstevel@tonic-gate 				 * if binding is null, then query
6790Sstevel@tonic-gate 				 */
6800Sstevel@tonic-gate 				return (*binding_addr);
6810Sstevel@tonic-gate 			}
6820Sstevel@tonic-gate 			/* replace existing binding with new binding */
6830Sstevel@tonic-gate 			if (*binding_addr) {
6840Sstevel@tonic-gate 				free(*binding_addr);
6850Sstevel@tonic-gate 			}
6860Sstevel@tonic-gate 			if ((*binding_addr = strdup(binding)) == NULL) {
6870Sstevel@tonic-gate 				return (NULL);
6880Sstevel@tonic-gate 			}
6890Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
6900Sstevel@tonic-gate 			printlist();
6910Sstevel@tonic-gate #endif
6920Sstevel@tonic-gate 			return (*binding_addr);
6930Sstevel@tonic-gate 		}
6940Sstevel@tonic-gate 		prev = bind;
6950Sstevel@tonic-gate 		bind = bind->next;
6960Sstevel@tonic-gate 	} /* while (bind) */
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	/* domain has not been found in the list at this point */
6990Sstevel@tonic-gate 	if (binding) {
7000Sstevel@tonic-gate 		/*
7010Sstevel@tonic-gate 		 * domain is not found, but binding is not NULL.
7020Sstevel@tonic-gate 		 * Then add a new node to the end of linked list.
7030Sstevel@tonic-gate 		 */
7040Sstevel@tonic-gate 
7056793Smuffin 		if ((bind = malloc(sizeof (Dbinding))) == NULL) {
7060Sstevel@tonic-gate 			return (NULL);
7070Sstevel@tonic-gate 		}
7080Sstevel@tonic-gate 		if ((bind->domain = strdup(domain)) == NULL) {
7090Sstevel@tonic-gate 			free(bind);
7100Sstevel@tonic-gate 			return (NULL);
7110Sstevel@tonic-gate 		}
7120Sstevel@tonic-gate 		bind->binding = NULL;
7130Sstevel@tonic-gate 		bind->codeset = NULL;
7140Sstevel@tonic-gate 		binding_addr = (type == TP_BINDING) ? &(bind->binding) :
7156793Smuffin 		    &(bind->codeset);
7160Sstevel@tonic-gate 		if ((*binding_addr = strdup(binding)) == NULL) {
7170Sstevel@tonic-gate 			free(bind->domain);
7180Sstevel@tonic-gate 			free(bind);
7190Sstevel@tonic-gate 			return (NULL);
7200Sstevel@tonic-gate 		}
7210Sstevel@tonic-gate 		bind->next = NULL;
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 		if (prev) {
7240Sstevel@tonic-gate 			/* reached the end of list */
7250Sstevel@tonic-gate 			prev->next = bind;
7260Sstevel@tonic-gate 		} else {
7270Sstevel@tonic-gate 			/* list was empty */
7280Sstevel@tonic-gate 			FIRSTBIND(gt) = bind;
7290Sstevel@tonic-gate 		}
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
7320Sstevel@tonic-gate 		printlist();
7330Sstevel@tonic-gate #endif
7340Sstevel@tonic-gate 		return (*binding_addr);
7350Sstevel@tonic-gate 	} else {
7360Sstevel@tonic-gate 		/*
7370Sstevel@tonic-gate 		 * Query of domain which is not found in the list
7380Sstevel@tonic-gate 		 * for bindtextdomain, returns defaultbind
7390Sstevel@tonic-gate 		 * for bind_textdomain_codeset, returns NULL
7400Sstevel@tonic-gate 		 */
7410Sstevel@tonic-gate 		if (type == TP_BINDING) {
7420Sstevel@tonic-gate 			return ((char *)defaultbind);
7430Sstevel@tonic-gate 		} else {
7440Sstevel@tonic-gate 			return (NULL);
7450Sstevel@tonic-gate 		}
7460Sstevel@tonic-gate 	} /* if (binding) */
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	/* Must not reach here */
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate } /* _real_bindtextdomain_u */
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate char *
_textdomain_u(const char * domain,char * result)7540Sstevel@tonic-gate _textdomain_u(const char *domain, char *result)
7550Sstevel@tonic-gate {
7560Sstevel@tonic-gate 	char	*p;
7570Sstevel@tonic-gate 	size_t	domain_len;
7580Sstevel@tonic-gate 	Gettext_t	*gt = global_gt;
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
7616793Smuffin 	gprintf(0, "*************** _textdomain_u(\"%s\", 0x%p)\n",
7626793Smuffin 	    (domain ? domain : ""), (void *)result);
7630Sstevel@tonic-gate #endif
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	/* Query is performed for NULL domain pointer */
7660Sstevel@tonic-gate 	if (domain == NULL) {
7676793Smuffin 		(void) strcpy(result, CURRENT_DOMAIN(gt));
7680Sstevel@tonic-gate 		return (result);
7690Sstevel@tonic-gate 	}
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	/* check for error. */
7720Sstevel@tonic-gate 	/*
7730Sstevel@tonic-gate 	 * domain is limited to TEXTDOMAINMAX bytes
7740Sstevel@tonic-gate 	 * excluding a null termination.
7750Sstevel@tonic-gate 	 */
7766793Smuffin 	domain_len = strlen(domain);
7770Sstevel@tonic-gate 	if (domain_len > TEXTDOMAINMAX) {
7780Sstevel@tonic-gate 		/* too long */
7790Sstevel@tonic-gate 		return (NULL);
7800Sstevel@tonic-gate 	}
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	/*
7830Sstevel@tonic-gate 	 * Calling textdomain() with a null domain string sets
7840Sstevel@tonic-gate 	 * the domain to the default domain.
7850Sstevel@tonic-gate 	 * If non-null string is passwd, current domain is changed
7860Sstevel@tonic-gate 	 * to the new domain.
7870Sstevel@tonic-gate 	 */
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	/* actually this if clause should be protected from signals */
7900Sstevel@tonic-gate 	if (*domain == '\0') {
7910Sstevel@tonic-gate 		if (CURRENT_DOMAIN(gt) != default_domain) {
7920Sstevel@tonic-gate 			free(CURRENT_DOMAIN(gt));
7930Sstevel@tonic-gate 			CURRENT_DOMAIN(gt) = (char *)default_domain;
7940Sstevel@tonic-gate 		}
7950Sstevel@tonic-gate 	} else {
7966793Smuffin 		p = malloc(domain_len + 1);
7976793Smuffin 		if (p == NULL)
7980Sstevel@tonic-gate 			return (NULL);
7996793Smuffin 		(void) strcpy(p, domain);
8000Sstevel@tonic-gate 		if (CURRENT_DOMAIN(gt) != default_domain)
8010Sstevel@tonic-gate 			free(CURRENT_DOMAIN(gt));
8020Sstevel@tonic-gate 		CURRENT_DOMAIN(gt) = p;
8030Sstevel@tonic-gate 	}
8040Sstevel@tonic-gate 
8056793Smuffin 	(void) strcpy(result, CURRENT_DOMAIN(gt));
8060Sstevel@tonic-gate 	return (result);
8070Sstevel@tonic-gate } /* _textdomain_u */
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate /*
8100Sstevel@tonic-gate  * key_2_text() translates msd_id into target string.
8110Sstevel@tonic-gate  */
8120Sstevel@tonic-gate static char *
key_2_text(Msg_s_node * messages,const char * key_string)8130Sstevel@tonic-gate key_2_text(Msg_s_node *messages, const char *key_string)
8140Sstevel@tonic-gate {
8150Sstevel@tonic-gate 	int	val;
8160Sstevel@tonic-gate 	char	*msg_id_str;
8170Sstevel@tonic-gate 	unsigned char	kc = *(unsigned char *)key_string;
8180Sstevel@tonic-gate 	struct msg_struct	*check_msg_list;
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
8216793Smuffin 	gprintf(0, "*************** key_2_text(0x%p, \"%s\")\n",
8226793Smuffin 	    (void *)messages, key_string ? key_string : "(null)");
8236793Smuffin 	printsunmsg(messages, 1);
8240Sstevel@tonic-gate #endif
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	check_msg_list = messages->msg_list +
8276793Smuffin 	    messages->msg_file_info->msg_mid;
8280Sstevel@tonic-gate 	for (;;) {
8290Sstevel@tonic-gate 		msg_id_str = messages->msg_ids +
8306793Smuffin 		    check_msg_list->msgid_offset;
8310Sstevel@tonic-gate 		/*
8320Sstevel@tonic-gate 		 * To maintain the compatibility with Zeus mo file,
8330Sstevel@tonic-gate 		 * msg_id's are stored in descending order.
8340Sstevel@tonic-gate 		 * If the ascending order is desired, change "msgfmt.c"
8350Sstevel@tonic-gate 		 * and switch msg_id_str and key_string in the following
8360Sstevel@tonic-gate 		 * strcmp() statement.
8370Sstevel@tonic-gate 		 */
8380Sstevel@tonic-gate 		val = *(unsigned char *)msg_id_str - kc;
8390Sstevel@tonic-gate 		if ((val == 0) &&
8406793Smuffin 		    (val = strcmp(msg_id_str, key_string)) == 0) {
8410Sstevel@tonic-gate 			return (messages->msg_strs
8426793Smuffin 			    + check_msg_list->msgstr_offset);
8430Sstevel@tonic-gate 		} else if (val < 0) {
8440Sstevel@tonic-gate 			if (check_msg_list->less != LEAFINDICATOR) {
8450Sstevel@tonic-gate 				check_msg_list = messages->msg_list +
8466793Smuffin 				    check_msg_list->less;
8470Sstevel@tonic-gate 				continue;
8480Sstevel@tonic-gate 			}
8490Sstevel@tonic-gate 			return ((char *)key_string);
8500Sstevel@tonic-gate 		} else {
8510Sstevel@tonic-gate 			/* val > 0 */
8520Sstevel@tonic-gate 			if (check_msg_list->more != LEAFINDICATOR) {
8530Sstevel@tonic-gate 				check_msg_list = messages->msg_list +
8546793Smuffin 				    check_msg_list->more;
8550Sstevel@tonic-gate 				continue;
8560Sstevel@tonic-gate 			}
8570Sstevel@tonic-gate 			return ((char *)key_string);
8580Sstevel@tonic-gate 		}
8590Sstevel@tonic-gate 	}
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate 
8626793Smuffin /*
8636793Smuffin  * sun_setmsg
8646793Smuffin  *
8656793Smuffin  * INPUT
8666793Smuffin  *   mnp  - message node
8676793Smuffin  *   addr - address to the mmapped file
8686793Smuffin  *   size - size of the file
8696793Smuffin  *
8706793Smuffin  * RETURN
8716793Smuffin  *   0   - either T_SUN_MO or T_ILL_MO has been set
8726793Smuffin  *   1   - not a valid sun mo file
8736793Smuffin  *  -1   - failed
8746793Smuffin  */
8756793Smuffin static int
sun_setmsg(Msg_node * mnp,char * addr,size_t size)8766793Smuffin sun_setmsg(Msg_node *mnp, char *addr, size_t size)
8776793Smuffin {
8786793Smuffin 	struct msg_info	*sun_header;
8796793Smuffin 	Msg_s_node	*p;
8806793Smuffin 	uint32_t	first_4bytes;
8816793Smuffin 	int	mid, count;
8826793Smuffin 	int	struct_size, struct_size_old;
8836793Smuffin 	int	msg_struct_size;
8846793Smuffin 
8856793Smuffin 	if (size < sizeof (struct msg_info)) {
8866793Smuffin 		/* invalid mo file */
8876793Smuffin 		mnp->type = T_ILL_MO;
8886793Smuffin #ifdef GETTEXT_DEBUG
8896793Smuffin 		gprintf(0, "********* exiting sun_setmsg\n");
8906793Smuffin 		printmnp(mnp, 1);
8916793Smuffin #endif
8926793Smuffin 		return (0);
8936793Smuffin 	}
8946793Smuffin 
8956793Smuffin 	first_4bytes = *((uint32_t *)(uintptr_t)addr);
8966793Smuffin 	if (first_4bytes > INT_MAX) {
8976793Smuffin 		/*
8986793Smuffin 		 * Not a valid sun mo file
8996793Smuffin 		 */
9006793Smuffin 		return (1);
9016793Smuffin 	}
9026793Smuffin 
9036793Smuffin 	/* candidate for sun mo */
9046793Smuffin 
9056793Smuffin 	sun_header = (struct msg_info *)(uintptr_t)addr;
9066793Smuffin 	mid = sun_header->msg_mid;
9076793Smuffin 	count = sun_header->msg_count;
9086793Smuffin 	msg_struct_size = sun_header->msg_struct_size;
9096793Smuffin 	struct_size_old = (int)(OLD_MSG_STRUCT_SIZE * count);
9106793Smuffin 	struct_size = (int)(MSG_STRUCT_SIZE * count);
9116793Smuffin 
9126793Smuffin 	if ((((count - 1) / 2) != mid) ||
9136793Smuffin 	    ((msg_struct_size != struct_size_old) &&
9146793Smuffin 	    (msg_struct_size != struct_size))) {
9156793Smuffin 		/* invalid mo file */
9166793Smuffin 		mnp->type = T_ILL_MO;
9176793Smuffin #ifdef GETTEXT_DEBUG
9186793Smuffin 		gprintf(0, "********* exiting sun_setmsg\n");
9196793Smuffin 		printmnp(mnp, 1);
9206793Smuffin #endif
9216793Smuffin 		return (0);
9226793Smuffin 	}
9236793Smuffin 	/* valid sun mo file */
9246793Smuffin 
9256793Smuffin 	p = malloc(sizeof (Msg_s_node));
9266793Smuffin 	if (p == NULL) {
9276793Smuffin 		return (-1);
9286793Smuffin 	}
9296793Smuffin 
9306793Smuffin 	p->msg_file_info = sun_header;
9316793Smuffin 	p->msg_list = (struct msg_struct *)(uintptr_t)
9326793Smuffin 	    (addr + sizeof (struct msg_info));
9336793Smuffin 	p->msg_ids = (char *)(addr + sizeof (struct msg_info) +
9346793Smuffin 	    struct_size);
9356793Smuffin 	p->msg_strs = (char *)(addr + sizeof (struct msg_info) +
9366793Smuffin 	    struct_size + sun_header->str_count_msgid);
9376793Smuffin 
9386793Smuffin 	mnp->msg.sunmsg = p;
9396793Smuffin 	mnp->type = T_SUN_MO;
9406793Smuffin #ifdef GETTEXT_DEBUG
9416793Smuffin 	gprintf(0, "******** exiting sun_setmsg\n");
9426793Smuffin 	printmnp(mnp, 1);
9436793Smuffin #endif
9446793Smuffin 	return (0);
9456793Smuffin }
9466793Smuffin 
9476793Smuffin /*
9486793Smuffin  * setmsg
9496793Smuffin  *
9506793Smuffin  * INPUT
9516793Smuffin  *   mnp  - message node
9526793Smuffin  *   addr - address to the mmapped file
9536793Smuffin  *   size - size of the file
9546793Smuffin  *
9556793Smuffin  * RETURN
9566793Smuffin  *   0   - succeeded
9576793Smuffin  *  -1   - failed
9586793Smuffin  */
9596793Smuffin static int
setmsg(Msg_node * mnp,char * addr,size_t size)9606793Smuffin setmsg(Msg_node *mnp, char *addr, size_t size)
9616793Smuffin {
9626793Smuffin 	int	ret;
9636793Smuffin 	if ((ret = sun_setmsg(mnp, addr, size)) <= 0)
9646793Smuffin 		return (ret);
9656793Smuffin 
9666793Smuffin 	return (gnu_setmsg(mnp, addr, size));
9676793Smuffin }
9686793Smuffin 
9690Sstevel@tonic-gate static char *
handle_type_mo(Msg_node * mnp,struct msg_pack * mp)9706793Smuffin handle_type_mo(Msg_node *mnp, struct msg_pack *mp)
9710Sstevel@tonic-gate {
9720Sstevel@tonic-gate 	char	*result;
9730Sstevel@tonic-gate 
9746793Smuffin 	switch (mnp->type) {
9750Sstevel@tonic-gate 	case T_ILL_MO:
9766793Smuffin 		/* invalid MO */
9770Sstevel@tonic-gate 		return (NULL);
9780Sstevel@tonic-gate 	case T_SUN_MO:
9796793Smuffin 		/* Sun MO found */
9806793Smuffin 		mp->status |= ST_SUN_MO_FOUND;
9816793Smuffin 
9820Sstevel@tonic-gate 		if (mp->plural) {
9830Sstevel@tonic-gate 			/*
9840Sstevel@tonic-gate 			 * *ngettext is called against
9850Sstevel@tonic-gate 			 * Sun MO file
9860Sstevel@tonic-gate 			 */
9870Sstevel@tonic-gate 			int	exp = (mp->n == 1);
9880Sstevel@tonic-gate 			result = (char *)mp->msgid1;
9890Sstevel@tonic-gate 			if (!exp)
9900Sstevel@tonic-gate 				result = (char *)mp->msgid2;
9910Sstevel@tonic-gate 			return (result);
9920Sstevel@tonic-gate 		}
9936793Smuffin 		result = key_2_text(mnp->msg.sunmsg, mp->msgid1);
9946793Smuffin 		if (!mnp->trusted) {
9950Sstevel@tonic-gate 			result = check_format(mp->msgid1, result, 0);
9960Sstevel@tonic-gate 		}
9970Sstevel@tonic-gate 		return (result);
9980Sstevel@tonic-gate 	case T_GNU_MO:
9996793Smuffin 		/* GNU MO found */
10006793Smuffin 		mp->status |= ST_GNU_MO_FOUND;
10016793Smuffin 
10026793Smuffin 		result = gnu_key_2_text(mnp->msg.gnumsg,
10036793Smuffin 		    get_codeset(mp->domain), mp);
10046793Smuffin 
10056793Smuffin 		if (result == mp->msgid1 || result == mp->msgid2) {
10066793Smuffin 			/* no valid msg found */
10070Sstevel@tonic-gate 			return (result);
10080Sstevel@tonic-gate 		}
10096793Smuffin 
10106793Smuffin 		/* valid msg found */
10116793Smuffin 		mp->status |= ST_GNU_MSG_FOUND;
10126793Smuffin 
10136793Smuffin 		if (!mnp->trusted) {
10140Sstevel@tonic-gate 			result = check_format(mp->msgid1, result, 0);
10150Sstevel@tonic-gate 			if (result == mp->msgid1) {
10160Sstevel@tonic-gate 				DFLTMSG(result, mp->msgid1, mp->msgid2,
10176793Smuffin 				    mp->n, mp->plural);
10180Sstevel@tonic-gate 			}
10190Sstevel@tonic-gate 		}
10200Sstevel@tonic-gate 		return (result);
10210Sstevel@tonic-gate 	default:
10220Sstevel@tonic-gate 		/* this should never happen */
10236793Smuffin 		DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural);
10246793Smuffin 		return (result);
10250Sstevel@tonic-gate 	}
10260Sstevel@tonic-gate 	/* NOTREACHED */
10270Sstevel@tonic-gate }
10280Sstevel@tonic-gate 
10296793Smuffin /*
10306793Smuffin  * handle_mo() returns NULL if invalid MO found.
10316793Smuffin  */
10326793Smuffin char *
handle_mo(struct msg_pack * mp)10336793Smuffin handle_mo(struct msg_pack *mp)
10340Sstevel@tonic-gate {
10356793Smuffin 	int	fd;
10360Sstevel@tonic-gate 	char	*result;
10370Sstevel@tonic-gate 	struct stat64	statbuf;
10386793Smuffin 	Msg_node	*mnp;
10390Sstevel@tonic-gate 	Gettext_t	*gt = global_gt;
10400Sstevel@tonic-gate 
10416793Smuffin #define	CONNECT_ENTRY	\
10426793Smuffin 	mnp->next = gt->m_node; \
10436793Smuffin 	gt->m_node = mnp; \
10446793Smuffin 	gt->c_m_node = mnp
10456793Smuffin 
10460Sstevel@tonic-gate #ifdef GETTEXT_DEBUG
10476793Smuffin 	gprintf(0, "*************** handle_mo(0x%p)\n", (void *)mp);
10486793Smuffin 	printmp(mp, 1);
10490Sstevel@tonic-gate #endif
10500Sstevel@tonic-gate 
10516793Smuffin 	mnp = check_cache(mp);
10520Sstevel@tonic-gate 
10536793Smuffin 	if (mnp != NULL) {
10540Sstevel@tonic-gate 		/* cache found */
10556793Smuffin 		return (handle_type_mo(mnp, mp));
10560Sstevel@tonic-gate 	}
10576793Smuffin 
10580Sstevel@tonic-gate 	/*
10590Sstevel@tonic-gate 	 * Valid entry not found in the cache
10600Sstevel@tonic-gate 	 */
10616793Smuffin 	mnp = calloc(1, sizeof (Msg_node));
10626793Smuffin 	if (mnp == NULL) {
10636793Smuffin 		DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural);
10646793Smuffin 		return (result);
10650Sstevel@tonic-gate 	}
10666793Smuffin 	mnp->hashid = mp->hash_domain;
10676793Smuffin 	mnp->path = strdup(mp->msgfile);
10686793Smuffin 	if (mnp->path == NULL) {
10696793Smuffin 		free(mnp);
10700Sstevel@tonic-gate 		DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural);
10710Sstevel@tonic-gate 		return (result);
10720Sstevel@tonic-gate 	}
10730Sstevel@tonic-gate 
10746793Smuffin 	fd = nls_safe_open(mp->msgfile, &statbuf, &mp->trusted, !mp->nlsp);
10756793Smuffin 	if ((fd == -1) || (statbuf.st_size > LONG_MAX)) {
10766793Smuffin 		if (fd != -1)
10776793Smuffin 			(void) close(fd);
10786793Smuffin 		mnp->type = T_ILL_MO;
10796793Smuffin 		CONNECT_ENTRY;
10806793Smuffin 		return (NULL);
10816793Smuffin 	}
10826793Smuffin 	mp->fsz = (size_t)statbuf.st_size;
10836793Smuffin 	mp->addr = mmap(NULL, mp->fsz, PROT_READ, MAP_SHARED, fd, 0);
10846793Smuffin 	(void) close(fd);
10856793Smuffin 
10866793Smuffin 	if (mp->addr == MAP_FAILED) {
10876793Smuffin 		free(mnp->path);
10886793Smuffin 		free(mnp);
10896793Smuffin 		DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural);
10906793Smuffin 		return (result);
10916793Smuffin 	}
10926793Smuffin 
10936793Smuffin 	if (setmsg(mnp, (char *)mp->addr, mp->fsz) == -1) {
10946793Smuffin 		free(mnp->path);
10956793Smuffin 		free(mnp);
10960Sstevel@tonic-gate 		(void) munmap(mp->addr, mp->fsz);
10970Sstevel@tonic-gate 		DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural);
10980Sstevel@tonic-gate 		return (result);
10990Sstevel@tonic-gate 	}
11006793Smuffin 	mnp->trusted = mp->trusted;
11016793Smuffin 	CONNECT_ENTRY;
11020Sstevel@tonic-gate 
11036793Smuffin 	return (handle_type_mo(mnp, mp));
11040Sstevel@tonic-gate }
1105