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/libc/nls/Attic/msgcat.c,v 1.4 2005/01/31 22:29:36 dillon Exp $
38 * We need a better way of handling errors than printing text. I need
39 * to add an error handling routine.
42 #include "namespace.h"
43 #include <sys/types.h>
45 #include <sys/syslimits.h>
54 #include "un-namespace.h"
57 #include "../locale/setlocale.h" /* for ENCODING_LEN */
59 #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"
64 #define NLERR ((nl_catd) -1)
65 #define NLRETERR(errc) { errno = errc; return (NLERR); }
67 static nl_catd loadCat();
69 static void __nls_free_resources();
78 char *nlspath, *lang, *base, *cptr, *pathP, *tmpptr;
79 char *cptr1, *plang, *pter, *pcode;
82 if (name == NULL || *name == '\0')
85 /* is it absolute path ? if yes, load immediately */
86 if (strchr(name, '/') != NULL)
87 return (loadCat(name));
89 if (type == NL_CAT_LOCALE)
90 lang = setlocale(LC_MESSAGES, NULL);
92 lang = getenv("LANG");
94 if (lang == NULL || *lang == '\0' || strlen(lang) > ENCODING_LEN ||
96 (lang[1] == '\0' || (lang[1] == '.' && lang[2] == '\0'))) ||
97 strchr(lang, '/') != NULL)
100 if ((plang = cptr1 = strdup(lang)) == NULL) {
104 if ((cptr = strchr(cptr1, '@')) != NULL)
107 if ((cptr = strchr(cptr1, '_')) != NULL) {
111 if ((cptr = strchr(cptr1, '.')) != NULL) {
116 if ((nlspath = getenv("NLSPATH")) == NULL
117 #ifndef __NETBSD_SYSCALLS
121 nlspath = _DEFAULT_NLS_PATH;
123 if ((base = cptr = strdup(nlspath)) == NULL) {
129 while ((nlspath = strsep(&cptr, ":")) != NULL) {
132 for (; *nlspath; ++nlspath) {
133 if (*nlspath == '%') {
134 switch (*(nlspath + 1)) {
148 tmpptr = (char *)name;
157 *(pathP++) = *nlspath;
162 spcleft = sizeof(path) -
164 if (strlcpy(pathP, tmpptr, spcleft) >=
169 NLRETERR(ENAMETOOLONG);
171 pathP += strlen(tmpptr);
173 if (pathP - path >= sizeof(path) - 1)
175 *(pathP++) = *nlspath;
179 if (stat(path, &sbuf) == 0) {
182 return (loadCat(path));
185 tmpptr = (char *)name;
196 * We've got an odd situation here. The odds are real good that the
197 * number we are looking for is almost the same as the index. We could
198 * use the index, check the difference and do something intelligent, but
199 * I haven't quite figured out what's intelligent.
202 * Take an id N. If there are > N items in the list, then N cannot
203 * be more than N items from the start, since otherwise there would
204 * have to be duplicate items. So we can safely set the top to N+1
205 * (after taking into account that ids start at 1, and arrays at 0)
207 * Let's say we are at position P, and we are looking for N, but have
208 * V. If N > V, then the furthest away that N could be is
209 * P + (N-V). So we can safely set hi to P+(N-V)+1. For example:
210 * We are looking for 10, but have 8
216 #define LOOKUP(PARENT, CHILD, ID, NUM, SET) { \
218 if (ID - 1 < PARENT->NUM) { \
223 cur = (hi - lo) / 2; \
226 CHILD = PARENT->SET + cur; \
227 if (CHILD->ID == ID) \
229 if (CHILD->ID < ID) { \
231 if (hi > cur + (ID - CHILD->ID) + 1) \
232 hi = cur + (ID - CHILD->ID) + 1; \
243 cur += ((hi - lo) / 2) * dir; \
253 long lo, hi, cur, dir;
255 if (cat == NULL || setId <= 0)
257 LOOKUP(cat, set, setId, numSets, sets);
258 if (set->invalid && loadSet(cat, set) <= 0)
269 long lo, hi, cur, dir;
271 if (set == NULL || set->invalid || msgId <= 0)
273 LOOKUP(set, msg, msgId, numMsgs, u.msgs);
278 catgets(catd, setId, msgId, dflt)
285 MCCatT *cat = (MCCatT *)catd;
288 if (catd == NULL || catd == NLERR)
289 return ((char *)dflt);
290 msg = MCGetMsg(MCGetSet(cat, setId), msgId);
295 return ((char *)cptr);
302 MCCatT *cat = (MCCatT *)catd;
304 if (catd == NULL || catd == NLERR) {
309 if (cat->loadType != MCLoadAll)
311 (void)fclose(cat->fp);
312 __nls_free_resources(cat, cat->numSets);
321 /* Note that only malloc failures are allowed to return an error */
322 static char *_errowner = "Message Catalog System";
324 #define CORRUPT() { \
325 (void)fclose(cat->fp); \
326 (void)fprintf(stderr, "%s: corrupt file.", _errowner); \
331 #define NOSPACE() { \
332 (void)fclose(cat->fp); \
333 (void)fprintf(stderr, "%s: no more memory.", _errowner); \
340 __nls_free_resources(cat, i)
347 for (j = 0; j < i; j++) {
368 if ((cat = (MCCatT *)malloc(sizeof(MCCatT))) == NULL) {
372 cat->loadType = MCLoadBySet;
374 if ((cat->fp = fopen(catpath, "r")) == NULL) {
380 (void)_fcntl(fileno(cat->fp), F_SETFD, FD_CLOEXEC);
382 if (fread(&header, sizeof(header), 1, cat->fp) != 1 ||
383 strncmp(header.magic, MCMagic, MCMagicLen) != 0)
386 if (header.majorVer != MCMajorVer) {
387 (void)fclose(cat->fp);
389 (void)fprintf(stderr, "%s: %s is version %ld, we need %ld.\n",
390 _errowner, catpath, header.majorVer, MCMajorVer);
393 if (header.numSets <= 0) {
394 (void)fclose(cat->fp);
396 (void)fprintf(stderr, "%s: %s has %ld sets!\n",
397 _errowner, catpath, header.numSets);
401 cat->numSets = header.numSets;
402 if ((cat->sets = (MCSetT *)malloc(sizeof(MCSetT) * header.numSets)) ==
406 nextSet = header.firstSet;
407 for (i = 0; i < cat->numSets; ++i) {
408 if (fseeko(cat->fp, nextSet, SEEK_SET) == -1) {
409 __nls_free_resources(cat, i);
413 /* read in the set header */
415 if (fread(set, sizeof(*set), 1, cat->fp) != 1) {
416 __nls_free_resources(cat, i);
420 /* if it's invalid, skip over it (and backup 'i') */
423 nextSet = set->nextSet;
427 if (cat->loadType == MCLoadAll) {
430 if ((res = loadSet(cat, set)) <= 0) {
431 __nls_free_resources(cat, i);
439 nextSet = set->nextSet;
442 if (cat->loadType == MCLoadAll) {
443 (void)fclose(cat->fp);
447 return ((nl_catd) cat);
460 if (fseeko(cat->fp, set->data.off, SEEK_SET) == -1)
462 if ((set->data.str = malloc(set->dataLen)) == NULL) {
466 if (fread(set->data.str, set->dataLen, 1, cat->fp) != 1) {
473 /* Get the messages */
474 if (fseeko(cat->fp, set->u.firstMsg, SEEK_SET) == -1) {
480 if ((set->u.msgs = (MCMsgT *)malloc(sizeof(MCMsgT) * set->numMsgs)) ==
487 for (i = 0; i < set->numMsgs; ++i) {
488 msg = set->u.msgs + i;
489 if (fread(msg, sizeof(*msg), 1, cat->fp) != 1) {
500 msg->msg.str = (char *)(set->data.str + msg->msg.off);
502 set->invalid = FALSE;