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 * $FreeBSD: src/lib/libc/nls/msgcat.c,v 1.21.2.6 2002/08/12 11:23:54 ache Exp $
34 * $DragonFly: src/lib/libcr/nls/Attic/msgcat.c,v 1.3 2003/08/22 19:31:21 asmodai Exp $
38 * We need a better way of handling errors than printing text. I need
39 * to add an error handling routine.
42 #include <sys/types.h>
44 #include <sys/syslimits.h>
55 #include "../locale/setlocale.h" /* for ENCODING_LEN */
57 #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"
62 #define NLERR ((nl_catd) -1)
63 #define NLRETERR(errc) { errno = errc; return (NLERR); }
65 static nl_catd loadCat();
67 static void __nls_free_resources();
76 char *nlspath, *lang, *base, *cptr, *pathP, *tmpptr;
77 char *cptr1, *plang, *pter, *pcode;
80 if (name == NULL || *name == '\0')
83 /* is it absolute path ? if yes, load immediately */
84 if (strchr(name, '/') != NULL)
85 return (loadCat(name));
87 if (type == NL_CAT_LOCALE)
88 lang = setlocale(LC_MESSAGES, NULL);
90 lang = getenv("LANG");
92 if (lang == NULL || *lang == '\0' || strlen(lang) > ENCODING_LEN ||
94 (lang[1] == '\0' || (lang[1] == '.' && lang[2] == '\0'))) ||
95 strchr(lang, '/') != NULL)
98 if ((plang = cptr1 = strdup(lang)) == NULL) {
102 if ((cptr = strchr(cptr1, '@')) != NULL)
105 if ((cptr = strchr(cptr1, '_')) != NULL) {
109 if ((cptr = strchr(cptr1, '.')) != NULL) {
114 if ((nlspath = getenv("NLSPATH")) == NULL
115 #ifndef __NETBSD_SYSCALLS
119 nlspath = _DEFAULT_NLS_PATH;
121 if ((base = cptr = strdup(nlspath)) == NULL) {
127 while ((nlspath = strsep(&cptr, ":")) != NULL) {
130 for (; *nlspath; ++nlspath) {
131 if (*nlspath == '%') {
132 switch (*(nlspath + 1)) {
146 tmpptr = (char *)name;
155 *(pathP++) = *nlspath;
160 spcleft = sizeof(path) -
162 if (strlcpy(pathP, tmpptr, spcleft) >=
167 NLRETERR(ENAMETOOLONG);
169 pathP += strlen(tmpptr);
171 if (pathP - path >= sizeof(path) - 1)
173 *(pathP++) = *nlspath;
177 if (stat(path, &sbuf) == 0) {
180 return (loadCat(path));
183 tmpptr = (char *)name;
194 * We've got an odd situation here. The odds are real good that the
195 * number we are looking for is almost the same as the index. We could
196 * use the index, check the difference and do something intelligent, but
197 * I haven't quite figured out what's intelligent.
200 * Take an id N. If there are > N items in the list, then N cannot
201 * be more than N items from the start, since otherwise there would
202 * have to be duplicate items. So we can safely set the top to N+1
203 * (after taking into account that ids start at 1, and arrays at 0)
205 * Let's say we are at position P, and we are looking for N, but have
206 * V. If N > V, then the furthest away that N could be is
207 * P + (N-V). So we can safely set hi to P+(N-V)+1. For example:
208 * We are looking for 10, but have 8
214 #define LOOKUP(PARENT, CHILD, ID, NUM, SET) { \
216 if (ID - 1 < PARENT->NUM) { \
221 cur = (hi - lo) / 2; \
224 CHILD = PARENT->SET + cur; \
225 if (CHILD->ID == ID) \
227 if (CHILD->ID < ID) { \
229 if (hi > cur + (ID - CHILD->ID) + 1) \
230 hi = cur + (ID - CHILD->ID) + 1; \
241 cur += ((hi - lo) / 2) * dir; \
251 long lo, hi, cur, dir;
253 if (cat == NULL || setId <= 0)
255 LOOKUP(cat, set, setId, numSets, sets);
256 if (set->invalid && loadSet(cat, set) <= 0)
267 long lo, hi, cur, dir;
269 if (set == NULL || set->invalid || msgId <= 0)
271 LOOKUP(set, msg, msgId, numMsgs, u.msgs);
276 catgets(catd, setId, msgId, dflt)
283 MCCatT *cat = (MCCatT *)catd;
286 if (catd == NULL || catd == NLERR)
287 return ((char *)dflt);
288 msg = MCGetMsg(MCGetSet(cat, setId), msgId);
293 return ((char *)cptr);
300 MCCatT *cat = (MCCatT *)catd;
302 if (catd == NULL || catd == NLERR) {
307 if (cat->loadType != MCLoadAll)
309 (void)fclose(cat->fp);
310 __nls_free_resources(cat, cat->numSets);
319 /* Note that only malloc failures are allowed to return an error */
320 static char *_errowner = "Message Catalog System";
322 #define CORRUPT() { \
323 (void)fclose(cat->fp); \
324 (void)fprintf(stderr, "%s: corrupt file.", _errowner); \
329 #define NOSPACE() { \
330 (void)fclose(cat->fp); \
331 (void)fprintf(stderr, "%s: no more memory.", _errowner); \
338 __nls_free_resources(cat, i)
345 for (j = 0; j < i; j++) {
366 if ((cat = (MCCatT *)malloc(sizeof(MCCatT))) == NULL) {
370 cat->loadType = MCLoadBySet;
372 if ((cat->fp = fopen(catpath, "r")) == NULL) {
378 (void)_fcntl(fileno(cat->fp), F_SETFD, FD_CLOEXEC);
380 if (fread(&header, sizeof(header), 1, cat->fp) != 1 ||
381 strncmp(header.magic, MCMagic, MCMagicLen) != 0)
384 if (header.majorVer != MCMajorVer) {
385 (void)fclose(cat->fp);
387 (void)fprintf(stderr, "%s: %s is version %ld, we need %ld.\n",
388 _errowner, catpath, header.majorVer, MCMajorVer);
391 if (header.numSets <= 0) {
392 (void)fclose(cat->fp);
394 (void)fprintf(stderr, "%s: %s has %ld sets!\n",
395 _errowner, catpath, header.numSets);
399 cat->numSets = header.numSets;
400 if ((cat->sets = (MCSetT *)malloc(sizeof(MCSetT) * header.numSets)) ==
404 nextSet = header.firstSet;
405 for (i = 0; i < cat->numSets; ++i) {
406 if (fseeko(cat->fp, nextSet, SEEK_SET) == -1) {
407 __nls_free_resources(cat, i);
411 /* read in the set header */
413 if (fread(set, sizeof(*set), 1, cat->fp) != 1) {
414 __nls_free_resources(cat, i);
418 /* if it's invalid, skip over it (and backup 'i') */
421 nextSet = set->nextSet;
425 if (cat->loadType == MCLoadAll) {
428 if ((res = loadSet(cat, set)) <= 0) {
429 __nls_free_resources(cat, i);
437 nextSet = set->nextSet;
440 if (cat->loadType == MCLoadAll) {
441 (void)fclose(cat->fp);
445 return ((nl_catd) cat);
458 if (fseeko(cat->fp, set->data.off, SEEK_SET) == -1)
460 if ((set->data.str = malloc(set->dataLen)) == NULL) {
464 if (fread(set->data.str, set->dataLen, 1, cat->fp) != 1) {
471 /* Get the messages */
472 if (fseeko(cat->fp, set->u.firstMsg, SEEK_SET) == -1) {
478 if ((set->u.msgs = (MCMsgT *)malloc(sizeof(MCMsgT) * set->numMsgs)) ==
485 for (i = 0; i < set->numMsgs; ++i) {
486 msg = set->u.msgs + i;
487 if (fread(msg, sizeof(*msg), 1, cat->fp) != 1) {
498 msg->msg.str = (char *)(set->data.str + msg->msg.off);
500 set->invalid = FALSE;