1 /***********************************************************
2 Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that Alfalfa's name not be used in
11 advertising or publicity pertaining to distribution of the software
12 without specific, written prior permission.
14 ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22 If you make any modifications, bugfixes or other changes to this software
23 we'd appreciate it if you could send a copy to us so we can keep things
24 up-to-date. Many thanks.
26 Alfalfa Software, Inc.
28 Cambridge, MA 02139 USA
31 ******************************************************************/
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: src/lib/libc/nls/msgcat.c,v 1.21.2.6 2002/08/12 11:23:54 ache Exp $");
37 * We need a better way of handling errors than printing text. I need
38 * to add an error handling routine.
41 #include <sys/types.h>
43 #include <sys/syslimits.h>
54 #include "../locale/setlocale.h" /* for ENCODING_LEN */
56 #define _DEFAULT_NLS_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:/usr/local/share/nls/%L/%N.cat:/usr/local/share/nls/%N/%L"
61 #define NLERR ((nl_catd) -1)
62 #define NLRETERR(errc) { errno = errc; return (NLERR); }
64 static nl_catd loadCat();
66 static void __nls_free_resources();
75 char *nlspath, *lang, *base, *cptr, *pathP, *tmpptr;
76 char *cptr1, *plang, *pter, *pcode;
79 if (name == NULL || *name == '\0')
82 /* is it absolute path ? if yes, load immediately */
83 if (strchr(name, '/') != NULL)
84 return (loadCat(name));
86 if (type == NL_CAT_LOCALE)
87 lang = setlocale(LC_MESSAGES, NULL);
89 lang = getenv("LANG");
91 if (lang == NULL || *lang == '\0' || strlen(lang) > ENCODING_LEN ||
93 (lang[1] == '\0' || (lang[1] == '.' && lang[2] == '\0'))) ||
94 strchr(lang, '/') != NULL)
97 if ((plang = cptr1 = strdup(lang)) == NULL) {
101 if ((cptr = strchr(cptr1, '@')) != NULL)
104 if ((cptr = strchr(cptr1, '_')) != NULL) {
108 if ((cptr = strchr(cptr1, '.')) != NULL) {
113 if ((nlspath = getenv("NLSPATH")) == NULL
114 #ifndef __NETBSD_SYSCALLS
118 nlspath = _DEFAULT_NLS_PATH;
120 if ((base = cptr = strdup(nlspath)) == NULL) {
126 while ((nlspath = strsep(&cptr, ":")) != NULL) {
129 for (; *nlspath; ++nlspath) {
130 if (*nlspath == '%') {
131 switch (*(nlspath + 1)) {
145 tmpptr = (char *)name;
154 *(pathP++) = *nlspath;
159 spcleft = sizeof(path) -
161 if (strlcpy(pathP, tmpptr, spcleft) >=
166 NLRETERR(ENAMETOOLONG);
168 pathP += strlen(tmpptr);
170 if (pathP - path >= sizeof(path) - 1)
172 *(pathP++) = *nlspath;
176 if (stat(path, &sbuf) == 0) {
179 return (loadCat(path));
182 tmpptr = (char *)name;
193 * We've got an odd situation here. The odds are real good that the
194 * number we are looking for is almost the same as the index. We could
195 * use the index, check the difference and do something intelligent, but
196 * I haven't quite figured out what's intelligent.
199 * Take an id N. If there are > N items in the list, then N cannot
200 * be more than N items from the start, since otherwise there would
201 * have to be duplicate items. So we can safely set the top to N+1
202 * (after taking into account that ids start at 1, and arrays at 0)
204 * Let's say we are at position P, and we are looking for N, but have
205 * V. If N > V, then the furthest away that N could be is
206 * P + (N-V). So we can safely set hi to P+(N-V)+1. For example:
207 * We are looking for 10, but have 8
213 #define LOOKUP(PARENT, CHILD, ID, NUM, SET) { \
215 if (ID - 1 < PARENT->NUM) { \
220 cur = (hi - lo) / 2; \
223 CHILD = PARENT->SET + cur; \
224 if (CHILD->ID == ID) \
226 if (CHILD->ID < ID) { \
228 if (hi > cur + (ID - CHILD->ID) + 1) \
229 hi = cur + (ID - CHILD->ID) + 1; \
240 cur += ((hi - lo) / 2) * dir; \
250 long lo, hi, cur, dir;
252 if (cat == NULL || setId <= 0)
254 LOOKUP(cat, set, setId, numSets, sets);
255 if (set->invalid && loadSet(cat, set) <= 0)
266 long lo, hi, cur, dir;
268 if (set == NULL || set->invalid || msgId <= 0)
270 LOOKUP(set, msg, msgId, numMsgs, u.msgs);
275 catgets(catd, setId, msgId, dflt)
282 MCCatT *cat = (MCCatT *)catd;
285 if (catd == NULL || catd == NLERR)
286 return ((char *)dflt);
287 msg = MCGetMsg(MCGetSet(cat, setId), msgId);
292 return ((char *)cptr);
299 MCCatT *cat = (MCCatT *)catd;
301 if (catd == NULL || catd == NLERR) {
306 if (cat->loadType != MCLoadAll)
308 (void)fclose(cat->fp);
309 __nls_free_resources(cat, cat->numSets);
318 /* Note that only malloc failures are allowed to return an error */
319 static char *_errowner = "Message Catalog System";
321 #define CORRUPT() { \
322 (void)fclose(cat->fp); \
323 (void)fprintf(stderr, "%s: corrupt file.", _errowner); \
328 #define NOSPACE() { \
329 (void)fclose(cat->fp); \
330 (void)fprintf(stderr, "%s: no more memory.", _errowner); \
337 __nls_free_resources(cat, i)
344 for (j = 0; j < i; j++) {
356 __const char *catpath;
365 if ((cat = (MCCatT *)malloc(sizeof(MCCatT))) == NULL) {
369 cat->loadType = MCLoadBySet;
371 if ((cat->fp = fopen(catpath, "r")) == NULL) {
377 (void)_fcntl(fileno(cat->fp), F_SETFD, FD_CLOEXEC);
379 if (fread(&header, sizeof(header), 1, cat->fp) != 1 ||
380 strncmp(header.magic, MCMagic, MCMagicLen) != 0)
383 if (header.majorVer != MCMajorVer) {
384 (void)fclose(cat->fp);
386 (void)fprintf(stderr, "%s: %s is version %ld, we need %ld.\n",
387 _errowner, catpath, header.majorVer, MCMajorVer);
390 if (header.numSets <= 0) {
391 (void)fclose(cat->fp);
393 (void)fprintf(stderr, "%s: %s has %ld sets!\n",
394 _errowner, catpath, header.numSets);
398 cat->numSets = header.numSets;
399 if ((cat->sets = (MCSetT *)malloc(sizeof(MCSetT) * header.numSets)) ==
403 nextSet = header.firstSet;
404 for (i = 0; i < cat->numSets; ++i) {
405 if (fseeko(cat->fp, nextSet, SEEK_SET) == -1) {
406 __nls_free_resources(cat, i);
410 /* read in the set header */
412 if (fread(set, sizeof(*set), 1, cat->fp) != 1) {
413 __nls_free_resources(cat, i);
417 /* if it's invalid, skip over it (and backup 'i') */
420 nextSet = set->nextSet;
424 if (cat->loadType == MCLoadAll) {
427 if ((res = loadSet(cat, set)) <= 0) {
428 __nls_free_resources(cat, i);
436 nextSet = set->nextSet;
439 if (cat->loadType == MCLoadAll) {
440 (void)fclose(cat->fp);
444 return ((nl_catd) cat);
457 if (fseeko(cat->fp, set->data.off, SEEK_SET) == -1)
459 if ((set->data.str = malloc(set->dataLen)) == NULL) {
463 if (fread(set->data.str, set->dataLen, 1, cat->fp) != 1) {
470 /* Get the messages */
471 if (fseeko(cat->fp, set->u.firstMsg, SEEK_SET) == -1) {
477 if ((set->u.msgs = (MCMsgT *)malloc(sizeof(MCMsgT) * set->numMsgs)) ==
484 for (i = 0; i < set->numMsgs; ++i) {
485 msg = set->u.msgs + i;
486 if (fread(msg, sizeof(*msg), 1, cat->fp) != 1) {
497 msg->msg.str = (char *)(set->data.str + msg->msg.off);
499 set->invalid = FALSE;