]>
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.48 2003/10/29 10:45:01 tjr 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();
75 static void __nls_free_resources();
84 char *nlspath
, *lang
, *base
, *cptr
, *pathP
, *tmpptr
;
85 char *cptr1
, *plang
, *pter
, *pcode
;
88 if (name
== NULL
|| *name
== '\0')
91 /* is it absolute path ? if yes, load immediately */
92 if (strchr(name
, '/') != NULL
)
93 return (loadCat(name
));
95 if (type
== NL_CAT_LOCALE
)
96 lang
= (char *)querylocale(LC_MESSAGES_MASK
, NULL
);
98 lang
= getenv("LANG");
100 if (lang
== NULL
|| *lang
== '\0' || strlen(lang
) > ENCODING_LEN
||
102 (lang
[1] == '\0' || (lang
[1] == '.' && lang
[2] == '\0'))) ||
103 strchr(lang
, '/') != NULL
)
106 if ((plang
= cptr1
= strdup(lang
)) == NULL
)
108 if ((cptr
= strchr(cptr1
, '@')) != NULL
)
111 if ((cptr
= strchr(cptr1
, '_')) != NULL
) {
115 if ((cptr
= strchr(cptr1
, '.')) != NULL
) {
120 if ((nlspath
= getenv("NLSPATH")) == NULL
|| issetugid())
121 nlspath
= _DEFAULT_NLS_PATH
;
123 if ((base
= cptr
= strdup(nlspath
)) == NULL
) {
130 while ((nlspath
= strsep(&cptr
, ":")) != NULL
) {
133 for (; *nlspath
; ++nlspath
) {
134 if (*nlspath
== '%') {
135 switch (*(nlspath
+ 1)) {
149 tmpptr
= (char *)name
;
158 *(pathP
++) = *nlspath
;
163 spcleft
= sizeof(path
) -
165 if (strlcpy(pathP
, tmpptr
, spcleft
) >=
170 NLRETERR(ENAMETOOLONG
);
172 pathP
+= strlen(tmpptr
);
174 if (pathP
- path
>= sizeof(path
) - 1)
176 *(pathP
++) = *nlspath
;
180 if (stat(path
, &sbuf
) == 0) {
183 return (loadCat(path
));
186 tmpptr
= (char *)name
;
197 * We've got an odd situation here. The odds are real good that the
198 * number we are looking for is almost the same as the index. We could
199 * use the index, check the difference and do something intelligent, but
200 * I haven't quite figured out what's intelligent.
203 * Take an id N. If there are > N items in the list, then N cannot
204 * be more than N items from the start, since otherwise there would
205 * have to be duplicate items. So we can safely set the top to N+1
206 * (after taking into account that ids start at 1, and arrays at 0)
208 * Let's say we are at position P, and we are looking for N, but have
209 * V. If N > V, then the furthest away that N could be is
210 * P + (N-V). So we can safely set hi to P+(N-V)+1. For example:
211 * We are looking for 10, but have 8
217 #define LOOKUP(PARENT, CHILD, ID, NUM, SET) { \
219 if (ID - 1 < NUM) { \
224 cur = (hi - lo) / 2; \
227 CHILD = PARENT->SET + cur; \
228 if (ntohl(CHILD->ID) == ID) \
230 if (ntohl(CHILD->ID) < ID) { \
232 if (hi > cur + (ID - ntohl(CHILD->ID)) + 1) \
233 hi = cur + (ID - ntohl(CHILD->ID)) + 1; \
244 cur += ((hi - lo) / 2) * dir; \
249 MCGetSet(MCCatT
*cat
, int setId
)
252 int32_t lo
, hi
, cur
, dir
;
254 if (cat
== NULL
|| setId
<= 0)
256 LOOKUP(cat
, set
, setId
, cat
->numSets
, sets
);
257 if (set
->invalid
&& loadSet(cat
, set
) <= 0)
263 MCGetMsg(MCSetT
*set
, int msgId
)
266 int32_t lo
, hi
, cur
, dir
;
268 if (set
== NULL
|| set
->invalid
|| msgId
<= 0)
270 LOOKUP(set
, msg
, msgId
, ntohl(set
->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() { \
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
++) {
357 __const
char *catpath
;
366 if ((cat
= (MCCatT
*)malloc(sizeof(MCCatT
))) == NULL
)
368 cat
->loadType
= MCLoadBySet
;
370 if ((cat
->fp
= fopen(catpath
, "r")) == NULL
) {
376 (void)_fcntl(fileno(cat
->fp
), F_SETFD
, FD_CLOEXEC
);
378 if (fread(&header
, sizeof(header
), 1, cat
->fp
) != 1 ||
379 strncmp(header
.magic
, MCMagic
, MCMagicLen
) != 0)
382 if (ntohl(header
.majorVer
) != MCMajorVer
) {
383 (void)fclose(cat
->fp
);
385 if (OSSwapInt32(ntohl(header
.majorVer
)) == MCMajorVer
) {
386 (void)fprintf(stderr
, "%s: %s is the wrong byte ordering.\n", _errowner
, catpath
);
388 (void)fprintf(stderr
, "%s: %s is version %d, we need %d.\n", _errowner
, catpath
, (int)ntohl(header
.majorVer
), MCMajorVer
);
392 if (ntohl(header
.numSets
) <= 0) {
393 (void)fclose(cat
->fp
);
395 (void)fprintf(stderr
, "%s: %s has %d sets!\n",
396 _errowner
, catpath
, (int)ntohl(header
.numSets
));
400 cat
->numSets
= ntohl(header
.numSets
);
401 if ((cat
->sets
= (MCSetT
*)malloc(sizeof(MCSetT
) * cat
->numSets
)) ==
405 nextSet
= ntohll(header
.firstSet
);
406 for (i
= 0; i
< cat
->numSets
; ++i
) {
407 if (fseeko(cat
->fp
, nextSet
, SEEK_SET
) == -1) {
408 __nls_free_resources(cat
, i
);
412 /* read in the set header */
414 if (fread(set
, sizeof(*set
), 1, cat
->fp
) != 1) {
415 __nls_free_resources(cat
, i
);
419 /* if it's invalid, skip over it (and backup 'i') */
422 nextSet
= ntohll(set
->nextSet
);
426 if (cat
->loadType
== MCLoadAll
) {
429 if ((res
= loadSet(cat
, set
)) <= 0) {
431 __nls_free_resources(cat
, i
);
440 nextSet
= ntohll(set
->nextSet
);
443 if (cat
->loadType
== MCLoadAll
) {
444 (void)fclose(cat
->fp
);
448 return ((nl_catd
) cat
);
461 if (fseeko(cat
->fp
, ntohll(set
->data
.off
), SEEK_SET
) == -1)
463 if ((set
->data
.str
= malloc(ntohl(set
->dataLen
))) == NULL
)
465 if (fread(set
->data
.str
, ntohl(set
->dataLen
), 1, cat
->fp
) != 1) {
472 /* Get the messages */
473 if (fseeko(cat
->fp
, ntohll(set
->u
.firstMsg
), SEEK_SET
) == -1) {
479 if ((set
->u
.msgs
= (MCMsgT
*)malloc(sizeof(MCMsgT
) * ntohl(set
->numMsgs
))) ==
487 for (i
= 0; i
< ntohl(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
+ ntohll(msg
->msg
.off
));
502 set
->invalid
= FALSE
;