4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
30 /* __gtxt(): Common part to gettxt() and pfmt() */
32 #pragma weak _setcat = setcat
37 #include <sys/types.h>
41 #include <sys/types.h>
51 #include "../i18n/_locale.h"
52 #include "../i18n/_loc_path.h"
54 #define MESSAGES "/LC_MESSAGES/"
55 static const char *def_locale
= "C";
56 static const char *not_found
= "Message not found!!\n";
57 static struct db_info
*db_info
;
58 static int db_count
, maxdb
;
61 char db_name
[DB_NAME_LEN
]; /* Name of the message file */
62 uintptr_t addr
; /* Virtual memory address */
68 #define DB_EXIST 1 /* The catalogue exists */
69 #define DB_OPEN 2 /* Already tried to open */
71 /* Minimum number of open catalogues */
74 char cur_cat
[DB_NAME_LEN
];
75 rwlock_t _rw_cur_cat
= DEFAULTRWLOCK
;
79 * setcat(cat): Specify the default catalogue.
80 * Return a pointer to the local copy of the default catalogue
83 setcat(const char *cat
)
85 lrw_wrlock(&_rw_cur_cat
);
87 if (((strchr(cat
, '/') != NULL
)) ||
88 ((strchr(cat
, ':') != NULL
))) {
92 (void) strncpy(cur_cat
, cat
, sizeof (cur_cat
) - 1);
93 cur_cat
[sizeof (cur_cat
) - 1] = '\0';
96 lrw_unlock(&_rw_cur_cat
);
97 return (cur_cat
[0] ? cur_cat
: NULL
);
101 * load a message catalog which specified with current locale,
104 static struct db_info
*
105 load_db(const char *curloc
, const char *catname
, int *err
)
107 char pathname
[PATH_MAX
];
116 /* First time called, allocate space */
119 libc_malloc(MINDB
* sizeof (struct db_info
))) == NULL
) {
126 for (i
= 0; i
< db_count
; i
++) {
127 if (db_info
[i
].flag
== 0)
132 if (db_count
== maxdb
) {
133 if ((db
= libc_realloc(db_info
,
134 ++maxdb
* sizeof (struct db_info
))) == NULL
) {
144 (void) strcpy(db
->db_name
, catname
);
145 db
->saved_locale
= libc_strdup(curloc
);
146 if (db
->saved_locale
== NULL
) {
151 if (snprintf(pathname
, sizeof (pathname
),
152 _DFLT_LOC_PATH
"%s" MESSAGES
"%s",
153 db
->saved_locale
, db
->db_name
) >= sizeof (pathname
)) {
155 * We won't set err here, because an invalid locale is not
156 * the fatal condition, but we can fall back to "C"
161 if ((fd
= open(pathname
, O_RDONLY
)) != -1 &&
162 fstat64(fd
, &sb
) != -1 &&
163 (addr
= mmap(NULL
, (size_t)sb
.st_size
, PROT_READ
, MAP_SHARED
,
164 fd
, 0)) != MAP_FAILED
) {
165 db
->flag
|= DB_EXIST
;
166 db
->addr
= (uintptr_t)addr
;
167 db
->length
= (size_t)sb
.st_size
;
175 * unmap the message catalog, and release the db_info slot.
178 unload_db(struct db_info
*db
)
180 if ((db
->flag
& (DB_OPEN
|DB_EXIST
)) ==
181 (DB_OPEN
|DB_EXIST
)) {
182 (void) munmap((caddr_t
)db
->addr
, db
->length
);
185 if (db
->saved_locale
)
186 libc_free(db
->saved_locale
);
187 db
->saved_locale
= NULL
;
191 * go through the db_info, and find out a db_info slot regarding
192 * the given current locale and catalog name.
193 * If db is not NULL, then search will start from top of the array,
194 * otherwise it will start from the next of given db.
195 * If curloc is set to NULL, then return a cache without regards of
198 static struct db_info
*
199 lookup_cache(struct db_info
*db
, const char *curloc
, const char *catname
)
209 for (; db
< &db_info
[db_count
]; db
++) {
212 if (strcmp(db
->db_name
, catname
) == 0) {
213 if (curloc
== NULL
||
214 (db
->saved_locale
!= NULL
&&
215 strcmp(db
->saved_locale
, curloc
) == 0)) {
224 valid_msg(struct db_info
*db
, int id
)
226 if (db
== NULL
|| (db
->flag
& DB_EXIST
) == 0)
229 /* catalog has been loaded */
230 if (id
!= 0 && id
<= *(int *)(db
->addr
))
238 msg(struct db_info
*db
, int id
)
240 return ((char *)(db
->addr
+ *(int *)(db
->addr
+
241 id
* sizeof (int))));
245 * __gtxt(catname, id, dflt): Return a pointer to a message.
246 * catname is the name of the catalog. If null, the default catalog is
248 * id is the numeric id of the message in the catalogue
249 * dflt is the default message.
251 * Information about non-existent catalogues is kept in db_info, in
252 * such a way that subsequent calls with the same catalogue do not
253 * try to open the catalogue again.
256 __gtxt(const char *catname
, int id
, const char *dflt
)
263 /* Check for invalid message id */
267 return ((dflt
&& *dflt
) ? dflt
: not_found
);
270 * If catalogue is unspecified, use default catalogue.
271 * No catalogue at all is an error
273 if (!catname
|| !*catname
) {
274 lrw_rdlock(&_rw_cur_cat
);
275 if (cur_cat
== NULL
|| !*cur_cat
) {
276 lrw_unlock(&_rw_cur_cat
);
280 lrw_unlock(&_rw_cur_cat
);
283 loc
= uselocale(NULL
);
284 curloc
= current_locale(loc
, LC_MESSAGES
);
286 /* First look up the cache */
287 db
= lookup_cache(NULL
, curloc
, catname
);
290 * The catalog has been loaded, and if id seems valid,
293 if (valid_msg(db
, id
))
294 return (msg(db
, id
));
297 * seems given id is out of bound or does not exist. In this
298 * case, we need to look up a message for the "C" locale as
299 * documented in the man page.
301 db
= lookup_cache(NULL
, def_locale
, catname
);
304 * Even the message catalog for the "C" has not been
307 db
= load_db(def_locale
, catname
, &err
);
311 if (valid_msg(db
, id
))
312 return (msg(db
, id
));
313 /* no message found */
314 return ((dflt
&& *dflt
) ? dflt
: not_found
);
318 * The catalog has not been loaded or even has not
319 * attempted to be loaded, invalidate all caches related to
320 * the catname for possibly different locale.
323 while ((db
= lookup_cache(db
, NULL
, catname
)) != NULL
)
327 * load a message catalog for the requested locale.
329 db
= load_db(curloc
, catname
, &err
);
332 if (valid_msg(db
, id
))
333 return (msg(db
, id
));
336 * If the requested catalog is either not exist or message
337 * id is invalid, then try to load from "C" locale.
339 db
= load_db(def_locale
, catname
, &err
);
343 if (valid_msg(db
, id
))
344 return (msg(db
, id
));
346 /* no message found */
347 return ((dflt
&& *dflt
) ? dflt
: not_found
);