]>
git.saurik.com Git - apple/libc.git/blob - nls/FreeBSD/msgcat.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 "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(__const
char *);
68 static int loadSet(MCCatT
*, MCSetT
*);
69 static void __nls_free_resources(MCCatT
*, int);
72 catopen(__const
char *name
, int type
)
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
)
100 if ((cptr
= strchr(cptr1
, '@')) != NULL
)
103 if ((cptr
= strchr(cptr1
, '_')) != NULL
) {
107 if ((cptr
= strchr(cptr1
, '.')) != NULL
) {
112 if ((nlspath
= getenv("NLSPATH")) == NULL
|| issetugid())
113 nlspath
= _DEFAULT_NLS_PATH
;
115 if ((base
= cptr
= strdup(nlspath
)) == NULL
) {
122 while ((nlspath
= strsep(&cptr
, ":")) != NULL
) {
125 for (; *nlspath
; ++nlspath
) {
126 if (*nlspath
== '%') {
127 switch (*(nlspath
+ 1)) {
141 tmpptr
= (char *)name
;
150 *(pathP
++) = *nlspath
;
155 spcleft
= sizeof(path
) -
157 if (strlcpy(pathP
, tmpptr
, spcleft
) >=
162 NLRETERR(ENAMETOOLONG
);
164 pathP
+= strlen(tmpptr
);
166 if (pathP
- path
>= sizeof(path
) - 1)
168 *(pathP
++) = *nlspath
;
172 if (stat(path
, &sbuf
) == 0) {
175 return (loadCat(path
));
178 tmpptr
= (char *)name
;
189 * We've got an odd situation here. The odds are real good that the
190 * number we are looking for is almost the same as the index. We could
191 * use the index, check the difference and do something intelligent, but
192 * I haven't quite figured out what's intelligent.
195 * Take an id N. If there are > N items in the list, then N cannot
196 * be more than N items from the start, since otherwise there would
197 * have to be duplicate items. So we can safely set the top to N+1
198 * (after taking into account that ids start at 1, and arrays at 0)
200 * Let's say we are at position P, and we are looking for N, but have
201 * V. If N > V, then the furthest away that N could be is
202 * P + (N-V). So we can safely set hi to P+(N-V)+1. For example:
203 * We are looking for 10, but have 8
209 #define LOOKUP(PARENT, CHILD, ID, NUM, SET) { \
211 if (ID - 1 < PARENT->NUM) { \
216 cur = (hi - lo) / 2; \
219 CHILD = PARENT->SET + cur; \
220 if (CHILD->ID == ID) \
222 if (CHILD->ID < ID) { \
224 if (hi > cur + (ID - CHILD->ID) + 1) \
225 hi = cur + (ID - CHILD->ID) + 1; \
236 cur += ((hi - lo) / 2) * dir; \
241 MCGetSet(MCCatT
*cat
, int setId
)
244 long lo
, hi
, cur
, dir
;
246 if (cat
== NULL
|| setId
<= 0)
248 LOOKUP(cat
, set
, setId
, numSets
, sets
);
249 if (set
->invalid
&& loadSet(cat
, set
) <= 0)
255 MCGetMsg(MCSetT
*set
, int msgId
)
258 long lo
, hi
, cur
, dir
;
260 if (set
== NULL
|| set
->invalid
|| msgId
<= 0)
262 LOOKUP(set
, msg
, msgId
, numMsgs
, u
.msgs
);
267 catgets(nl_catd catd
, int setId
, int msgId
, __const
char *dflt
)
270 MCCatT
*cat
= (MCCatT
*)catd
;
273 if (catd
== NULL
|| catd
== NLERR
)
274 return ((char *)dflt
);
275 msg
= MCGetMsg(MCGetSet(cat
, setId
), msgId
);
280 return ((char *)cptr
);
284 catclose(nl_catd catd
)
286 MCCatT
*cat
= (MCCatT
*)catd
;
288 if (catd
== NULL
|| catd
== NLERR
) {
293 (void)fclose(cat
->fp
);
294 __nls_free_resources(cat
, cat
->numSets
);
303 /* Note that only malloc failures are allowed to return an error */
304 static char *_errowner
= "Message Catalog System";
306 #define CORRUPT() { \
307 (void)fclose(cat->fp); \
308 (void)fprintf(stderr, "%s: corrupt file.", _errowner); \
313 #define NOSPACE() { \
315 (void)fclose(cat->fp); \
316 (void)fprintf(stderr, "%s: no more memory.", _errowner); \
323 __nls_free_resources(MCCatT
*cat
, int i
)
328 for (j
= 0; j
< i
; j
++) {
339 loadCat(__const
char *catpath
)
348 if ((cat
= (MCCatT
*)malloc(sizeof(MCCatT
))) == NULL
)
351 if ((cat
->fp
= fopen(catpath
, "r")) == NULL
) {
357 (void)_fcntl(fileno(cat
->fp
), F_SETFD
, FD_CLOEXEC
);
359 if (fread(&header
, sizeof(header
), 1, cat
->fp
) != 1 ||
360 strncmp(header
.magic
, MCMagic
, MCMagicLen
) != 0)
363 if (header
.majorVer
!= MCMajorVer
) {
364 (void)fclose(cat
->fp
);
366 (void)fprintf(stderr
, "%s: %s is version %ld, we need %ld.\n",
367 _errowner
, catpath
, header
.majorVer
, MCMajorVer
);
370 if (header
.numSets
<= 0) {
371 (void)fclose(cat
->fp
);
373 (void)fprintf(stderr
, "%s: %s has %ld sets!\n",
374 _errowner
, catpath
, header
.numSets
);
378 cat
->numSets
= header
.numSets
;
379 if ((cat
->sets
= (MCSetT
*)malloc(sizeof(MCSetT
) * header
.numSets
)) ==
383 nextSet
= header
.firstSet
;
384 for (i
= 0; i
< cat
->numSets
; ++i
) {
385 if (fseeko(cat
->fp
, nextSet
, SEEK_SET
) == -1) {
386 __nls_free_resources(cat
, i
);
390 /* read in the set header */
392 if (fread(set
, sizeof(*set
), 1, cat
->fp
) != 1) {
393 __nls_free_resources(cat
, i
);
397 /* if it's invalid, skip over it (and backup 'i') */
400 nextSet
= set
->nextSet
;
404 nextSet
= set
->nextSet
;
407 return ((nl_catd
) cat
);
411 loadSet(MCCatT
*cat
, MCSetT
*set
)
418 if (fseeko(cat
->fp
, set
->data
.off
, SEEK_SET
) == -1)
420 if ((set
->data
.str
= malloc(set
->dataLen
)) == NULL
)
422 if (fread(set
->data
.str
, set
->dataLen
, 1, cat
->fp
) != 1) {
429 /* Get the messages */
430 if (fseeko(cat
->fp
, set
->u
.firstMsg
, SEEK_SET
) == -1) {
436 if ((set
->u
.msgs
= (MCMsgT
*)malloc(sizeof(MCMsgT
) * set
->numMsgs
)) ==
444 for (i
= 0; i
< set
->numMsgs
; ++i
) {
445 msg
= set
->u
.msgs
+ i
;
446 if (fread(msg
, sizeof(*msg
), 1, cat
->fp
) != 1) {
457 msg
->msg
.str
= (char *)(set
->data
.str
+ msg
->msg
.off
);
459 set
->invalid
= FALSE
;