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 #pragma ident "%Z%%M% %I% %E% SMI"
32 /* __gtxt(): Common part to gettxt() and pfmt() */
34 #pragma weak _setcat = setcat
39 #include <sys/types.h>
43 #include <sys/types.h>
53 #include "../i18n/_locale.h"
54 #include "../i18n/_loc_path.h"
56 #define MESSAGES "/LC_MESSAGES/"
57 static const char *def_locale
= "C";
58 static const char *not_found
= "Message not found!!\n";
59 static struct db_info
*db_info
;
60 static int db_count
, maxdb
;
63 char db_name
[DB_NAME_LEN
]; /* Name of the message file */
64 uintptr_t addr
; /* Virtual memory address */
70 #define DB_EXIST 1 /* The catalogue exists */
71 #define DB_OPEN 2 /* Already tried to open */
73 /* Minimum number of open catalogues */
76 char cur_cat
[DB_NAME_LEN
];
77 rwlock_t _rw_cur_cat
= DEFAULTRWLOCK
;
81 * setcat(cat): Specify the default catalogue.
82 * Return a pointer to the local copy of the default catalogue
85 setcat(const char *cat
)
87 lrw_wrlock(&_rw_cur_cat
);
89 if (((strchr(cat
, '/') != NULL
)) ||
90 ((strchr(cat
, ':') != NULL
))) {
94 (void) strncpy(cur_cat
, cat
, sizeof (cur_cat
) - 1);
95 cur_cat
[sizeof (cur_cat
) - 1] = '\0';
98 lrw_unlock(&_rw_cur_cat
);
99 return (cur_cat
[0] ? cur_cat
: NULL
);
103 * load a message catalog which specified with current locale,
106 static struct db_info
*
107 load_db(const char *curloc
, const char *catname
, int *err
)
109 char pathname
[PATH_MAX
];
118 /* First time called, allocate space */
121 libc_malloc(MINDB
* sizeof (struct db_info
))) == NULL
) {
128 for (i
= 0; i
< db_count
; i
++) {
129 if (db_info
[i
].flag
== 0)
134 if (db_count
== maxdb
) {
135 if ((db
= libc_realloc(db_info
,
136 ++maxdb
* sizeof (struct db_info
))) == NULL
) {
146 (void) strcpy(db
->db_name
, catname
);
147 db
->saved_locale
= libc_strdup(curloc
);
148 if (db
->saved_locale
== NULL
) {
153 if (snprintf(pathname
, sizeof (pathname
),
154 _DFLT_LOC_PATH
"%s" MESSAGES
"%s",
155 db
->saved_locale
, db
->db_name
) >= sizeof (pathname
)) {
157 * We won't set err here, because an invalid locale is not
158 * the fatal condition, but we can fall back to "C"
163 if ((fd
= open(pathname
, O_RDONLY
)) != -1 &&
164 fstat64(fd
, &sb
) != -1 &&
165 (addr
= mmap(0, (size_t)sb
.st_size
, PROT_READ
, MAP_SHARED
,
166 fd
, 0)) != MAP_FAILED
) {
167 db
->flag
|= DB_EXIST
;
168 db
->addr
= (uintptr_t)addr
;
169 db
->length
= (size_t)sb
.st_size
;
177 * unmap the message catalog, and release the db_info slot.
180 unload_db(struct db_info
*db
)
182 if ((db
->flag
& (DB_OPEN
|DB_EXIST
)) ==
183 (DB_OPEN
|DB_EXIST
)) {
184 (void) munmap((caddr_t
)db
->addr
, db
->length
);
187 if (db
->saved_locale
)
188 libc_free(db
->saved_locale
);
189 db
->saved_locale
= NULL
;
193 * go through the db_info, and find out a db_info slot regarding
194 * the given current locale and catalog name.
195 * If db is not NULL, then search will start from top of the array,
196 * otherwise it will start from the next of given db.
197 * If curloc is set to NULL, then return a cache without regards of
200 static struct db_info
*
201 lookup_cache(struct db_info
*db
, const char *curloc
, const char *catname
)
211 for (; db
< &db_info
[db_count
]; db
++) {
214 if (strcmp(db
->db_name
, catname
) == 0) {
215 if (curloc
== NULL
||
216 (db
->saved_locale
!= NULL
&&
217 strcmp(db
->saved_locale
, curloc
) == 0)) {
226 valid_msg(struct db_info
*db
, int id
)
228 if (db
== NULL
|| (db
->flag
& DB_EXIST
) == 0)
231 /* catalog has been loaded */
232 if (id
!= 0 && id
<= *(int *)(db
->addr
))
240 msg(struct db_info
*db
, int id
)
242 return ((char *)(db
->addr
+ *(int *)(db
->addr
+
243 id
* sizeof (int))));
247 * __gtxt(catname, id, dflt): Return a pointer to a message.
248 * catname is the name of the catalog. If null, the default catalog is
250 * id is the numeric id of the message in the catalogue
251 * dflt is the default message.
253 * Information about non-existent catalogues is kept in db_info, in
254 * such a way that subsequent calls with the same catalogue do not
255 * try to open the catalogue again.
258 __gtxt(const char *catname
, int id
, const char *dflt
)
264 /* Check for invalid message id */
268 return ((dflt
&& *dflt
) ? dflt
: not_found
);
271 * If catalogue is unspecified, use default catalogue.
272 * No catalogue at all is an error
274 if (!catname
|| !*catname
) {
275 lrw_rdlock(&_rw_cur_cat
);
276 if (cur_cat
== NULL
|| !*cur_cat
) {
277 lrw_unlock(&_rw_cur_cat
);
281 lrw_unlock(&_rw_cur_cat
);
284 curloc
= setlocale(LC_MESSAGES
, NULL
);
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
);