]>
git.saurik.com Git - apple/libc.git/blob - nls/msgcat-fbsd.c
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.49 2005/02/01 16:04:55 phantom Exp $");
37 * We need a better way of handling errors than printing text. I need
38 * to add an error handling routine.
41 #include "namespace.h"
42 #include <sys/types.h>
54 #include <machine/endian.h>
55 #include <libkern/OSByteOrder.h>
56 #include "un-namespace.h"
59 #include "setlocale.h" /* for ENCODING_LEN */
62 #define ntohll(x) OSSwapBigToHostInt64(x)
65 #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"
70 #define NLERR ((nl_catd) -1)
71 #define NLRETERR(errc) { errno = errc; return (NLERR); }
73 static nl_catd
loadCat(__const
char *);
74 static int loadSet(MCCatT
*, MCSetT
*);
75 static void __nls_free_resources(MCCatT
*, int);
78 catopen(__const
char *name
, int type
)
82 char *nlspath
, *lang
, *base
, *cptr
, *pathP
, *tmpptr
;
83 char *cptr1
, *plang
, *pter
, *pcode
;
86 if (name
== NULL
|| *name
== '\0')
89 /* is it absolute path ? if yes, load immediately */
90 if (strchr(name
, '/') != NULL
)
91 return (loadCat(name
));
93 if (type
== NL_CAT_LOCALE
)
94 lang
= (char *)querylocale(LC_MESSAGES_MASK
, NULL
);
96 lang
= getenv("LANG");
98 if (lang
== NULL
|| *lang
== '\0' || strlen(lang
) > ENCODING_LEN
||
100 (lang
[1] == '\0' || (lang
[1] == '.' && lang
[2] == '\0'))) ||
101 strchr(lang
, '/') != NULL
)
104 if ((plang
= cptr1
= strdup(lang
)) == NULL
)
106 if ((cptr
= strchr(cptr1
, '@')) != NULL
)
109 if ((cptr
= strchr(cptr1
, '_')) != NULL
) {
113 if ((cptr
= strchr(cptr1
, '.')) != NULL
) {
118 if ((nlspath
= getenv("NLSPATH")) == NULL
|| issetugid())
119 nlspath
= _DEFAULT_NLS_PATH
;
121 if ((base
= cptr
= strdup(nlspath
)) == NULL
) {
128 while ((nlspath
= strsep(&cptr
, ":")) != NULL
) {
131 for (; *nlspath
; ++nlspath
) {
132 if (*nlspath
== '%') {
133 switch (*(nlspath
+ 1)) {
147 tmpptr
= (char *)name
;
156 *(pathP
++) = *nlspath
;
161 spcleft
= sizeof(path
) -
163 if (strlcpy(pathP
, tmpptr
, spcleft
) >=
168 NLRETERR(ENAMETOOLONG
);
170 pathP
+= strlen(tmpptr
);
172 if (pathP
- path
>= sizeof(path
) - 1)
174 *(pathP
++) = *nlspath
;
178 if (stat(path
, &sbuf
) == 0) {
181 return (loadCat(path
));
184 tmpptr
= (char *)name
;
195 * We've got an odd situation here. The odds are real good that the
196 * number we are looking for is almost the same as the index. We could
197 * use the index, check the difference and do something intelligent, but
198 * I haven't quite figured out what's intelligent.
201 * Take an id N. If there are > N items in the list, then N cannot
202 * be more than N items from the start, since otherwise there would
203 * have to be duplicate items. So we can safely set the top to N+1
204 * (after taking into account that ids start at 1, and arrays at 0)
206 * Let's say we are at position P, and we are looking for N, but have
207 * V. If N > V, then the furthest away that N could be is
208 * P + (N-V). So we can safely set hi to P+(N-V)+1. For example:
209 * We are looking for 10, but have 8
215 #define LOOKUP(PARENT, CHILD, ID, NUM, SET) { \
217 if (ID - 1 < NUM) { \
222 cur = (hi - lo) / 2; \
225 CHILD = PARENT->SET + cur; \
226 if (ntohl(CHILD->ID) == ID) \
228 if (ntohl(CHILD->ID) < ID) { \
230 if (hi > cur + (ID - ntohl(CHILD->ID)) + 1) \
231 hi = cur + (ID - ntohl(CHILD->ID)) + 1; \
242 cur += ((hi - lo) / 2) * dir; \
247 MCGetSet(MCCatT
*cat
, int setId
)
250 int32_t lo
, hi
, cur
, dir
;
252 if (cat
== NULL
|| setId
<= 0)
254 LOOKUP(cat
, set
, setId
, cat
->numSets
, sets
);
255 if (set
->invalid
&& loadSet(cat
, set
) <= 0)
261 MCGetMsg(MCSetT
*set
, int msgId
)
264 int32_t lo
, hi
, cur
, dir
;
266 if (set
== NULL
|| set
->invalid
|| msgId
<= 0)
268 LOOKUP(set
, msg
, msgId
, ntohl(set
->numMsgs
), u
.msgs
);
273 catgets(nl_catd catd
, int setId
, int msgId
, __const
char *dflt
)
276 MCCatT
*cat
= (MCCatT
*)catd
;
279 if (catd
== NULL
|| catd
== NLERR
)
280 return ((char *)dflt
);
281 msg
= MCGetMsg(MCGetSet(cat
, setId
), msgId
);
286 return ((char *)cptr
);
290 catclose(nl_catd catd
)
292 MCCatT
*cat
= (MCCatT
*)catd
;
294 if (catd
== NULL
|| catd
== NLERR
) {
299 (void)fclose(cat
->fp
);
300 __nls_free_resources(cat
, cat
->numSets
);
309 /* Note that only malloc failures are allowed to return an error */
310 static char *_errowner
= "Message Catalog System";
312 #define CORRUPT() { \
313 (void)fclose(cat->fp); \
314 (void)fprintf(stderr, "%s: corrupt file.", _errowner); \
319 #define NOSPACE() { \
321 (void)fclose(cat->fp); \
322 (void)fprintf(stderr, "%s: no more memory.", _errowner); \
329 __nls_free_resources(MCCatT
*cat
, int i
)
334 for (j
= 0; j
< i
; j
++) {
345 loadCat(__const
char *catpath
)
354 if ((cat
= (MCCatT
*)malloc(sizeof(MCCatT
))) == NULL
)
357 if ((cat
->fp
= fopen(catpath
, "r")) == NULL
) {
363 (void)_fcntl(fileno(cat
->fp
), F_SETFD
, FD_CLOEXEC
);
365 if (fread(&header
, sizeof(header
), 1, cat
->fp
) != 1 ||
366 strncmp(header
.magic
, MCMagic
, MCMagicLen
) != 0)
369 if (ntohl(header
.majorVer
) != MCMajorVer
) {
370 (void)fclose(cat
->fp
);
372 if (OSSwapInt32(ntohl(header
.majorVer
)) == MCMajorVer
) {
373 (void)fprintf(stderr
, "%s: %s is the wrong byte ordering.\n", _errowner
, catpath
);
375 (void)fprintf(stderr
, "%s: %s is version %d, we need %d.\n", _errowner
, catpath
, (int)ntohl(header
.majorVer
), MCMajorVer
);
379 if (ntohl(header
.numSets
) <= 0) {
380 (void)fclose(cat
->fp
);
382 (void)fprintf(stderr
, "%s: %s has %d sets!\n",
383 _errowner
, catpath
, (int)ntohl(header
.numSets
));
387 cat
->numSets
= ntohl(header
.numSets
);
388 if ((cat
->sets
= (MCSetT
*)malloc(sizeof(MCSetT
) * cat
->numSets
)) ==
392 nextSet
= ntohll(header
.firstSet
);
393 for (i
= 0; i
< cat
->numSets
; ++i
) {
394 if (fseeko(cat
->fp
, nextSet
, SEEK_SET
) == -1) {
395 __nls_free_resources(cat
, i
);
399 /* read in the set header */
401 if (fread(set
, sizeof(*set
), 1, cat
->fp
) != 1) {
402 __nls_free_resources(cat
, i
);
406 /* if it's invalid, skip over it (and backup 'i') */
409 nextSet
= ntohll(set
->nextSet
);
413 nextSet
= ntohll(set
->nextSet
);
416 return ((nl_catd
) cat
);
420 loadSet(MCCatT
*cat
, MCSetT
*set
)
427 if (fseeko(cat
->fp
, ntohll(set
->data
.off
), SEEK_SET
) == -1)
429 if ((set
->data
.str
= malloc(ntohl(set
->dataLen
))) == NULL
)
431 if (fread(set
->data
.str
, ntohl(set
->dataLen
), 1, cat
->fp
) != 1) {
438 /* Get the messages */
439 if (fseeko(cat
->fp
, ntohll(set
->u
.firstMsg
), SEEK_SET
) == -1) {
445 if ((set
->u
.msgs
= (MCMsgT
*)malloc(sizeof(MCMsgT
) * ntohl(set
->numMsgs
))) ==
453 for (i
= 0; i
< ntohl(set
->numMsgs
); ++i
) {
454 msg
= set
->u
.msgs
+ i
;
455 if (fread(msg
, sizeof(*msg
), 1, cat
->fp
) != 1) {
466 msg
->msg
.str
= (char *)(set
->data
.str
+ ntohll(msg
->msg
.off
));
468 set
->invalid
= FALSE
;