]>
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
;