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