xref: /illumos-gate/usr/src/lib/libc/port/gen/gtxt.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
30*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate /* __gtxt(): Common part to gettxt() and pfmt()	*/
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #include "synonyms.h"
36*7c478bd9Sstevel@tonic-gate #include "libc.h"
37*7c478bd9Sstevel@tonic-gate #include <mtlib.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
39*7c478bd9Sstevel@tonic-gate #include <string.h>
40*7c478bd9Sstevel@tonic-gate #include <locale.h>
41*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
45*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
46*7c478bd9Sstevel@tonic-gate #include <synch.h>
47*7c478bd9Sstevel@tonic-gate #include <pfmt.h>
48*7c478bd9Sstevel@tonic-gate #include <thread.h>
49*7c478bd9Sstevel@tonic-gate #include <unistd.h>
50*7c478bd9Sstevel@tonic-gate #include <errno.h>
51*7c478bd9Sstevel@tonic-gate #include <limits.h>
52*7c478bd9Sstevel@tonic-gate #include "../i18n/_locale.h"
53*7c478bd9Sstevel@tonic-gate #include "../i18n/_loc_path.h"
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate #define	MESSAGES "/LC_MESSAGES/"
56*7c478bd9Sstevel@tonic-gate static const char *def_locale = "C";
57*7c478bd9Sstevel@tonic-gate static const char *not_found = "Message not found!!\n";
58*7c478bd9Sstevel@tonic-gate static struct db_info *db_info;
59*7c478bd9Sstevel@tonic-gate static int db_count, maxdb;
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate struct db_info {
62*7c478bd9Sstevel@tonic-gate 	char	db_name[DB_NAME_LEN];	/* Name of the message file */
63*7c478bd9Sstevel@tonic-gate 	uintptr_t	addr;		/* Virtual memory address   */
64*7c478bd9Sstevel@tonic-gate 	size_t	length;
65*7c478bd9Sstevel@tonic-gate 	char	*saved_locale;
66*7c478bd9Sstevel@tonic-gate 	char	flag;
67*7c478bd9Sstevel@tonic-gate };
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate #define	DB_EXIST	1		/* The catalogue exists	   */
70*7c478bd9Sstevel@tonic-gate #define	DB_OPEN		2		/* Already tried to open   */
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate /* Minimum number of open catalogues */
73*7c478bd9Sstevel@tonic-gate #define	MINDB		3
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate static char cur_cat[DB_NAME_LEN];
76*7c478bd9Sstevel@tonic-gate static rwlock_t _rw_cur_cat = DEFAULTRWLOCK;
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate /*
80*7c478bd9Sstevel@tonic-gate  * setcat(cat): Specify the default catalogue.
81*7c478bd9Sstevel@tonic-gate  * Return a pointer to the local copy of the default catalogue
82*7c478bd9Sstevel@tonic-gate  */
83*7c478bd9Sstevel@tonic-gate const char *
84*7c478bd9Sstevel@tonic-gate setcat(const char *cat)
85*7c478bd9Sstevel@tonic-gate {
86*7c478bd9Sstevel@tonic-gate 	lrw_wrlock(&_rw_cur_cat);
87*7c478bd9Sstevel@tonic-gate 	if (cat) {
88*7c478bd9Sstevel@tonic-gate 		if (((strchr(cat, '/') != NULL)) ||
89*7c478bd9Sstevel@tonic-gate 		    ((strchr(cat, ':') != NULL))) {
90*7c478bd9Sstevel@tonic-gate 			cur_cat[0] = '\0';
91*7c478bd9Sstevel@tonic-gate 			goto out;
92*7c478bd9Sstevel@tonic-gate 		}
93*7c478bd9Sstevel@tonic-gate 		(void) strncpy(cur_cat, cat, sizeof (cur_cat) - 1);
94*7c478bd9Sstevel@tonic-gate 		cur_cat[sizeof (cur_cat) - 1] = '\0';
95*7c478bd9Sstevel@tonic-gate 	}
96*7c478bd9Sstevel@tonic-gate out:
97*7c478bd9Sstevel@tonic-gate 	lrw_unlock(&_rw_cur_cat);
98*7c478bd9Sstevel@tonic-gate 	return (cur_cat[0] ? cur_cat : NULL);
99*7c478bd9Sstevel@tonic-gate }
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate /*
102*7c478bd9Sstevel@tonic-gate  * load a message catalog which specified with current locale,
103*7c478bd9Sstevel@tonic-gate  * and catalog name.
104*7c478bd9Sstevel@tonic-gate  */
105*7c478bd9Sstevel@tonic-gate static struct db_info *
106*7c478bd9Sstevel@tonic-gate load_db(const char *curloc, const char *catname, int *err)
107*7c478bd9Sstevel@tonic-gate {
108*7c478bd9Sstevel@tonic-gate 	char pathname[PATH_MAX];
109*7c478bd9Sstevel@tonic-gate 	struct	stat64 sb;
110*7c478bd9Sstevel@tonic-gate 	caddr_t	addr;
111*7c478bd9Sstevel@tonic-gate 	struct db_info *db;
112*7c478bd9Sstevel@tonic-gate 	int fd;
113*7c478bd9Sstevel@tonic-gate 	int i;
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 	*err = 0;
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	/* First time called, allocate space */
118*7c478bd9Sstevel@tonic-gate 	if (!db_info) {
119*7c478bd9Sstevel@tonic-gate 		if ((db_info =
120*7c478bd9Sstevel@tonic-gate 		    libc_malloc(MINDB * sizeof (struct db_info))) == NULL) {
121*7c478bd9Sstevel@tonic-gate 			*err = 1;
122*7c478bd9Sstevel@tonic-gate 			return (NULL);
123*7c478bd9Sstevel@tonic-gate 		}
124*7c478bd9Sstevel@tonic-gate 		maxdb = MINDB;
125*7c478bd9Sstevel@tonic-gate 	}
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < db_count; i++) {
128*7c478bd9Sstevel@tonic-gate 		if (db_info[i].flag == 0)
129*7c478bd9Sstevel@tonic-gate 			break;
130*7c478bd9Sstevel@tonic-gate 	}
131*7c478bd9Sstevel@tonic-gate 	/* New catalogue */
132*7c478bd9Sstevel@tonic-gate 	if (i == db_count) {
133*7c478bd9Sstevel@tonic-gate 		if (db_count == maxdb) {
134*7c478bd9Sstevel@tonic-gate 			if ((db = libc_realloc(db_info,
135*7c478bd9Sstevel@tonic-gate 			    ++maxdb * sizeof (struct db_info))) == NULL) {
136*7c478bd9Sstevel@tonic-gate 				*err = 1;
137*7c478bd9Sstevel@tonic-gate 				return (NULL);
138*7c478bd9Sstevel@tonic-gate 			}
139*7c478bd9Sstevel@tonic-gate 			db_info = db;
140*7c478bd9Sstevel@tonic-gate 		}
141*7c478bd9Sstevel@tonic-gate 		db_count++;
142*7c478bd9Sstevel@tonic-gate 	}
143*7c478bd9Sstevel@tonic-gate 	db = &db_info[i];
144*7c478bd9Sstevel@tonic-gate 	db->flag = 0;
145*7c478bd9Sstevel@tonic-gate 	(void) strcpy(db->db_name, catname);
146*7c478bd9Sstevel@tonic-gate 	db->saved_locale = libc_strdup(curloc);
147*7c478bd9Sstevel@tonic-gate 	if (db->saved_locale == NULL) {
148*7c478bd9Sstevel@tonic-gate 		*err = 1;
149*7c478bd9Sstevel@tonic-gate 		return (NULL);
150*7c478bd9Sstevel@tonic-gate 	}
151*7c478bd9Sstevel@tonic-gate 	db->flag = DB_OPEN;
152*7c478bd9Sstevel@tonic-gate 	if (snprintf(pathname, sizeof (pathname),
153*7c478bd9Sstevel@tonic-gate 		_DFLT_LOC_PATH "%s" MESSAGES "%s",
154*7c478bd9Sstevel@tonic-gate 		db->saved_locale, db->db_name) >= sizeof (pathname)) {
155*7c478bd9Sstevel@tonic-gate 		/*
156*7c478bd9Sstevel@tonic-gate 		 * We won't set err here, because an invalid locale is not
157*7c478bd9Sstevel@tonic-gate 		 * the fatal condition, but we can fall back to "C"
158*7c478bd9Sstevel@tonic-gate 		 * locale.
159*7c478bd9Sstevel@tonic-gate 		 */
160*7c478bd9Sstevel@tonic-gate 		return (NULL);
161*7c478bd9Sstevel@tonic-gate 	}
162*7c478bd9Sstevel@tonic-gate 	if ((fd = open(pathname, O_RDONLY)) != -1 &&
163*7c478bd9Sstevel@tonic-gate 		fstat64(fd, &sb) != -1 &&
164*7c478bd9Sstevel@tonic-gate 		(addr = mmap(0, (size_t)sb.st_size, PROT_READ, MAP_SHARED,
165*7c478bd9Sstevel@tonic-gate 			fd, 0)) != MAP_FAILED) {
166*7c478bd9Sstevel@tonic-gate 		db->flag |= DB_EXIST;
167*7c478bd9Sstevel@tonic-gate 		db->addr = (uintptr_t)addr;
168*7c478bd9Sstevel@tonic-gate 		db->length = (size_t)sb.st_size;
169*7c478bd9Sstevel@tonic-gate 	}
170*7c478bd9Sstevel@tonic-gate 	if (fd != -1)
171*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
172*7c478bd9Sstevel@tonic-gate 	return (db);
173*7c478bd9Sstevel@tonic-gate }
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate /*
176*7c478bd9Sstevel@tonic-gate  * unmap the message catalog, and release the db_info slot.
177*7c478bd9Sstevel@tonic-gate  */
178*7c478bd9Sstevel@tonic-gate static void
179*7c478bd9Sstevel@tonic-gate unload_db(struct db_info *db)
180*7c478bd9Sstevel@tonic-gate {
181*7c478bd9Sstevel@tonic-gate 	if ((db->flag & (DB_OPEN|DB_EXIST)) ==
182*7c478bd9Sstevel@tonic-gate 		(DB_OPEN|DB_EXIST)) {
183*7c478bd9Sstevel@tonic-gate 		(void) munmap((caddr_t)db->addr, db->length);
184*7c478bd9Sstevel@tonic-gate 	}
185*7c478bd9Sstevel@tonic-gate 	db->flag = 0;
186*7c478bd9Sstevel@tonic-gate 	if (db->saved_locale)
187*7c478bd9Sstevel@tonic-gate 		libc_free(db->saved_locale);
188*7c478bd9Sstevel@tonic-gate 	db->saved_locale = NULL;
189*7c478bd9Sstevel@tonic-gate }
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate /*
192*7c478bd9Sstevel@tonic-gate  * go through the db_info, and find out a db_info slot regarding
193*7c478bd9Sstevel@tonic-gate  * the given current locale and catalog name.
194*7c478bd9Sstevel@tonic-gate  * If db is not NULL, then search will start from top of the array,
195*7c478bd9Sstevel@tonic-gate  * otherwise it will start from the next of given db.
196*7c478bd9Sstevel@tonic-gate  * If curloc is set to NULL, then return a cache without regards of
197*7c478bd9Sstevel@tonic-gate  * locale.
198*7c478bd9Sstevel@tonic-gate  */
199*7c478bd9Sstevel@tonic-gate static struct db_info *
200*7c478bd9Sstevel@tonic-gate lookup_cache(struct db_info *db, const char *curloc, const char *catname)
201*7c478bd9Sstevel@tonic-gate {
202*7c478bd9Sstevel@tonic-gate 	if (db_info == NULL)
203*7c478bd9Sstevel@tonic-gate 		return (NULL);
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 	if (db == NULL)
206*7c478bd9Sstevel@tonic-gate 		db = db_info;
207*7c478bd9Sstevel@tonic-gate 	else
208*7c478bd9Sstevel@tonic-gate 		db++;
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 	for (; db < &db_info[db_count]; db++) {
211*7c478bd9Sstevel@tonic-gate 		if (db->flag == 0)
212*7c478bd9Sstevel@tonic-gate 			continue;
213*7c478bd9Sstevel@tonic-gate 		if (strcmp(db->db_name, catname) == 0) {
214*7c478bd9Sstevel@tonic-gate 			if (curloc == NULL ||
215*7c478bd9Sstevel@tonic-gate 				(db->saved_locale != NULL &&
216*7c478bd9Sstevel@tonic-gate 				strcmp(db->saved_locale, curloc) == 0)) {
217*7c478bd9Sstevel@tonic-gate 				return (db);
218*7c478bd9Sstevel@tonic-gate 			}
219*7c478bd9Sstevel@tonic-gate 		}
220*7c478bd9Sstevel@tonic-gate 	}
221*7c478bd9Sstevel@tonic-gate 	return (NULL);
222*7c478bd9Sstevel@tonic-gate }
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate static int
225*7c478bd9Sstevel@tonic-gate valid_msg(struct db_info *db, int id)
226*7c478bd9Sstevel@tonic-gate {
227*7c478bd9Sstevel@tonic-gate 	if (db == NULL || (db->flag & DB_EXIST) == 0)
228*7c478bd9Sstevel@tonic-gate 		return (0);
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	/* catalog has been loaded */
231*7c478bd9Sstevel@tonic-gate 	if (id != 0 && id <= *(int *)(db->addr))
232*7c478bd9Sstevel@tonic-gate 		return (1);
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	/* not a valid id */
235*7c478bd9Sstevel@tonic-gate 	return (0);
236*7c478bd9Sstevel@tonic-gate }
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate static char *
239*7c478bd9Sstevel@tonic-gate msg(struct db_info *db, int id)
240*7c478bd9Sstevel@tonic-gate {
241*7c478bd9Sstevel@tonic-gate 	return ((char *)(db->addr + *(int *)(db->addr +
242*7c478bd9Sstevel@tonic-gate 			id * sizeof (int))));
243*7c478bd9Sstevel@tonic-gate }
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate /*
246*7c478bd9Sstevel@tonic-gate  * __gtxt(catname, id, dflt): Return a pointer to a message.
247*7c478bd9Sstevel@tonic-gate  *	catname is the name of the catalog. If null, the default catalog is
248*7c478bd9Sstevel@tonic-gate  *		used.
249*7c478bd9Sstevel@tonic-gate  *	id is the numeric id of the message in the catalogue
250*7c478bd9Sstevel@tonic-gate  *	dflt is the default message.
251*7c478bd9Sstevel@tonic-gate  *
252*7c478bd9Sstevel@tonic-gate  *	Information about non-existent catalogues is kept in db_info, in
253*7c478bd9Sstevel@tonic-gate  *	such a way that subsequent calls with the same catalogue do not
254*7c478bd9Sstevel@tonic-gate  *	try to open the catalogue again.
255*7c478bd9Sstevel@tonic-gate  */
256*7c478bd9Sstevel@tonic-gate const char *
257*7c478bd9Sstevel@tonic-gate __gtxt(const char *catname, int id, const char *dflt)
258*7c478bd9Sstevel@tonic-gate {
259*7c478bd9Sstevel@tonic-gate 	char	*curloc;
260*7c478bd9Sstevel@tonic-gate 	struct db_info *db;
261*7c478bd9Sstevel@tonic-gate 	int	err;
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	/* Check for invalid message id */
264*7c478bd9Sstevel@tonic-gate 	if (id < 0)
265*7c478bd9Sstevel@tonic-gate 		return (not_found);
266*7c478bd9Sstevel@tonic-gate 	if (id == 0)
267*7c478bd9Sstevel@tonic-gate 		return ((dflt && *dflt) ? dflt : not_found);
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	/*
270*7c478bd9Sstevel@tonic-gate 	 * If catalogue is unspecified, use default catalogue.
271*7c478bd9Sstevel@tonic-gate 	 * No catalogue at all is an error
272*7c478bd9Sstevel@tonic-gate 	 */
273*7c478bd9Sstevel@tonic-gate 	if (!catname || !*catname) {
274*7c478bd9Sstevel@tonic-gate 		lrw_rdlock(&_rw_cur_cat);
275*7c478bd9Sstevel@tonic-gate 		if (cur_cat == NULL || !*cur_cat) {
276*7c478bd9Sstevel@tonic-gate 			lrw_unlock(&_rw_cur_cat);
277*7c478bd9Sstevel@tonic-gate 			return (not_found);
278*7c478bd9Sstevel@tonic-gate 		}
279*7c478bd9Sstevel@tonic-gate 		catname = cur_cat;
280*7c478bd9Sstevel@tonic-gate 		lrw_unlock(&_rw_cur_cat);
281*7c478bd9Sstevel@tonic-gate 	}
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	curloc = setlocale(LC_MESSAGES, NULL);
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	/* First look up the cache */
286*7c478bd9Sstevel@tonic-gate 	db = lookup_cache(NULL, curloc, catname);
287*7c478bd9Sstevel@tonic-gate 	if (db != NULL) {
288*7c478bd9Sstevel@tonic-gate 		/*
289*7c478bd9Sstevel@tonic-gate 		 * The catalog has been loaded, and if id seems valid,
290*7c478bd9Sstevel@tonic-gate 		 * then just return.
291*7c478bd9Sstevel@tonic-gate 		 */
292*7c478bd9Sstevel@tonic-gate 		if (valid_msg(db, id))
293*7c478bd9Sstevel@tonic-gate 			return (msg(db, id));
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 		/*
296*7c478bd9Sstevel@tonic-gate 		 * seems given id is out of bound or does not exist. In this
297*7c478bd9Sstevel@tonic-gate 		 * case, we need to look up a message for the "C" locale as
298*7c478bd9Sstevel@tonic-gate 		 * documented in the man page.
299*7c478bd9Sstevel@tonic-gate 		 */
300*7c478bd9Sstevel@tonic-gate 		db = lookup_cache(NULL, def_locale, catname);
301*7c478bd9Sstevel@tonic-gate 		if (db == NULL) {
302*7c478bd9Sstevel@tonic-gate 			/*
303*7c478bd9Sstevel@tonic-gate 			 * Even the message catalog for the "C" has not been
304*7c478bd9Sstevel@tonic-gate 			 * loaded.
305*7c478bd9Sstevel@tonic-gate 			 */
306*7c478bd9Sstevel@tonic-gate 			db = load_db(def_locale, catname, &err);
307*7c478bd9Sstevel@tonic-gate 			if (err)
308*7c478bd9Sstevel@tonic-gate 				return (not_found);
309*7c478bd9Sstevel@tonic-gate 		}
310*7c478bd9Sstevel@tonic-gate 		if (valid_msg(db, id))
311*7c478bd9Sstevel@tonic-gate 			return (msg(db, id));
312*7c478bd9Sstevel@tonic-gate 		/* no message found */
313*7c478bd9Sstevel@tonic-gate 		return ((dflt && *dflt) ? dflt : not_found);
314*7c478bd9Sstevel@tonic-gate 	}
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	/*
317*7c478bd9Sstevel@tonic-gate 	 * The catalog has not been loaded or even has not
318*7c478bd9Sstevel@tonic-gate 	 * attempted to be loaded, invalidate all caches related to
319*7c478bd9Sstevel@tonic-gate 	 * the catname for possibly different locale.
320*7c478bd9Sstevel@tonic-gate 	 */
321*7c478bd9Sstevel@tonic-gate 	db = NULL;
322*7c478bd9Sstevel@tonic-gate 	while ((db = lookup_cache(db, NULL, catname)) != NULL)
323*7c478bd9Sstevel@tonic-gate 		unload_db(db);
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	/*
326*7c478bd9Sstevel@tonic-gate 	 * load a message catalog for the requested locale.
327*7c478bd9Sstevel@tonic-gate 	 */
328*7c478bd9Sstevel@tonic-gate 	db = load_db(curloc, catname, &err);
329*7c478bd9Sstevel@tonic-gate 	if (err)
330*7c478bd9Sstevel@tonic-gate 		return (not_found);
331*7c478bd9Sstevel@tonic-gate 	if (valid_msg(db, id))
332*7c478bd9Sstevel@tonic-gate 		return (msg(db, id));
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	/*
335*7c478bd9Sstevel@tonic-gate 	 * If the requested catalog is either not exist or message
336*7c478bd9Sstevel@tonic-gate 	 * id is invalid, then try to load from "C" locale.
337*7c478bd9Sstevel@tonic-gate 	 */
338*7c478bd9Sstevel@tonic-gate 	db = load_db(def_locale, catname, &err);
339*7c478bd9Sstevel@tonic-gate 	if (err)
340*7c478bd9Sstevel@tonic-gate 		return (not_found);
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	if (valid_msg(db, id))
343*7c478bd9Sstevel@tonic-gate 		return (msg(db, id));
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	/* no message found */
346*7c478bd9Sstevel@tonic-gate 	return ((dflt && *dflt) ? dflt : not_found);
347*7c478bd9Sstevel@tonic-gate }
348