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