home *** CD-ROM | disk | FTP | other *** search
/ Serving the Web / ServingTheWeb1995.disc1of1.iso / linux / slacksrce / d / libc / libc-4.6 / libc-4 / libc-linux / nls / msgcat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-08  |  12.8 KB  |  547 lines

  1. #if 0
  2. static char rcsid[] = "@(#)$Id: msgcat.c,v 5.2 1993/06/10 03:12:10 syd Exp $";
  3. #endif
  4.  
  5. /* -*- c++ -*- */
  6.  
  7. /***********************************************************
  8. Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
  9.  
  10.                         All Rights Reserved
  11.  
  12. Permission to use, copy, modify, and distribute this software and its
  13. documentation for any purpose and without fee is hereby granted,
  14. provided that the above copyright notice appear in all copies and that
  15. both that copyright notice and this permission notice appear in
  16. supporting documentation, and that Alfalfa's name not be used in
  17. advertising or publicity pertaining to distribution of the software
  18. without specific, written prior permission.
  19.  
  20. ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  21. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  22. ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  23. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  24. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  25. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  26. SOFTWARE.
  27.  
  28. If you make any modifications, bugfixes or other changes to this software
  29. we'd appreciate it if you could send a copy to us so we can keep things
  30. up-to-date.  Many thanks.
  31.                 Kee Hinckley
  32.                 Alfalfa Software, Inc.
  33.                 267 Allston St., #3
  34.                 Cambridge, MA 02139  USA
  35.                 nazgul@alfalfa.com
  36.     
  37. ******************************************************************/
  38.  
  39. /* Edit History
  40.  
  41. 11/07/93   1 mitch    fast mmap() support. (m.dsouza@mrc-apu.cam.ac.uk)
  42. 03/06/91   4 schulert    remove working directory from nlspath
  43. 01/18/91   2 hamilton    #if not rescanned
  44. 01/12/91   3 schulert    conditionally use prototypes
  45. 11/03/90   1 hamilton    Alphalpha->Alfalfa & OmegaMail->Poste
  46. 10/15/90   2 schulert    > #include <unistd.h> if MIPS
  47. 08/13/90   1 schulert    move from ua to omu
  48. */
  49.  
  50. /*
  51.  * We need a better way of handling errors than printing text.  I need
  52.  * to add an error handling routine.
  53.  */
  54.  
  55. #include "nl_types.h"
  56. #include "msgcat.h"
  57. #include <locale.h>
  58.  
  59. #ifdef BSD
  60. #include <sys/file.h>
  61. #include <sys/param.h>
  62. #endif
  63. #include <sys/stat.h>
  64. #include <fcntl.h>
  65. #include <stdio.h>
  66.  
  67. #ifdef MIPS
  68. #include <unistd.h>
  69. #endif
  70.  
  71. #ifndef True
  72. # define True    ~0
  73. # define False    0
  74. #endif
  75.  
  76. /* take care of sysv diffs */
  77. #ifndef MAXPATHLEN
  78. #define MAXPATHLEN 1024
  79. #endif
  80.  
  81. #ifndef FD_CLOEXEC
  82. #define FD_CLOEXEC 1
  83. #endif
  84.  
  85. #define    NLERR    ((nl_catd) -1)
  86.  
  87. char    *MCAppPath = NULL;
  88.  
  89. #ifndef __linux__
  90. static nl_catd loadCat();
  91. static nl_catd loadSet();
  92. extern char *malloc(), *getenv();
  93. #else /* Strict prototypes makes better programmers */
  94. #ifdef HAVE_MMAP
  95. /*
  96.  *  We need to find the size of the file if we are mmap()'ing, but we have
  97.  *  already filled in the stat structure in the catopen() routine, so we
  98.  *  just pass this structure back to loadCat() to save an extra stat() call.
  99.  *
  100.  */
  101. static nl_catd loadCat(char *, int, struct stat *);
  102. #else
  103. static nl_catd loadCat(char *, int);
  104. #endif
  105. static nl_catd loadSet(MCCatT *, MCSetT *);
  106. #include <unistd.h>
  107. #include <stdlib.h>
  108. #include <string.h>
  109. #include <malloc.h>
  110. #include <paths.h>
  111. #endif
  112.  
  113. #ifdef HAVE_MMAP
  114. #include <sys/types.h>
  115. #include <sys/mman.h>
  116. #endif
  117.  
  118. nl_catd     catopen( name, type)
  119. const char *name;
  120. int type;
  121. {
  122.     char    path[MAXPATHLEN];
  123.     const char    *catpath = NULL;
  124.     char    *nlspath, *tmppath = NULL;
  125.     char    *lang;
  126.     long    len;
  127.     char    *base, *cptr, *pathP;
  128.     struct stat    sbuf;
  129.     
  130.     if (!name || !*name) return(NLERR);
  131.     if (*name == '/') {
  132.     catpath = name;
  133.     if (stat(catpath, &sbuf)) return(NLERR);
  134.     } else {
  135. #if BROKEN_SETLOCALE
  136.     if ((lang = (char *) getenv("LANG")) == NULL) lang = "C";
  137. #else
  138.     /* Query the locale from the previous setlocale call in msgcat-libc.c*/
  139.     if ((lang = (char *) setlocale(LC_MESSAGES,(char *) NULL)) == NULL)
  140.         lang="C";
  141. #endif
  142.     if ((nlspath = (char *) getenv("NLSPATH")) == NULL) {
  143. #if OLD_NLS_PATHS
  144.         nlspath = "/nlslib/%L/%N.cat:/nlslib/%N/%L";
  145. #else
  146.         nlspath = "/etc/locale/%L/%N.cat:"_PATH_LOCALE"/%L/%N.cat:"_PATH_LOCALE"/%N/%L"
  147.               "/usr/share/locale/%L/%N.cat:/usr/local/share/locale/%L/%N.cat";
  148. #endif
  149.     }
  150.     if (MCAppPath) {
  151.         tmppath = (char *) malloc(strlen(nlspath) + strlen(MCAppPath) + 3);
  152.         if (!tmppath) return(NLERR);
  153.         strcpy(tmppath, nlspath);
  154.         if (tmppath[strlen(tmppath)-1] != ':' && *MCAppPath != ':')
  155.           strcat(tmppath, ":");
  156.         strcat(tmppath, MCAppPath);
  157.         nlspath = tmppath;
  158.     }
  159.     
  160.     len = strlen(nlspath);
  161.     base = cptr = (char *) malloc(len + 2);
  162.     if (!base) return(NLERR);
  163.     strcpy(cptr, nlspath);
  164.     cptr[len] = ':';
  165.     cptr[len+1] = '\0';
  166.         
  167.     for (nlspath = cptr; *cptr; ++cptr) {
  168.         if (*cptr == ':') {
  169.         *cptr = '\0';
  170.         for (pathP = path; *nlspath; ++nlspath) {
  171.             if (*nlspath == '%') {
  172.             if (*(nlspath + 1) == 'L') {
  173.                 ++nlspath;
  174.                 strcpy(pathP, lang);
  175.                 pathP += strlen(lang);
  176.             } else if (*(nlspath + 1) == 'N') {
  177.                 ++nlspath;
  178.                 strcpy(pathP, name);
  179.                 pathP += strlen(name);
  180.             } else *(pathP++) = *nlspath;
  181.             } else *(pathP++) = *nlspath;
  182.         }
  183.         *pathP = '\0';
  184.         if (stat(path, &sbuf) == 0) {
  185.             catpath = path;
  186.             break;
  187.         }
  188.         nlspath = cptr+1;
  189.         }
  190.     }
  191.     free(base);
  192.     if (tmppath) free(tmppath);
  193.  
  194.     if (!catpath) return(NLERR);
  195.     }
  196.  
  197. #ifdef HAVE_MMAP
  198.     return(loadCat(catpath, type, &sbuf));
  199. #else
  200.     return(loadCat(catpath, type));
  201. #endif
  202. }
  203.  
  204. /*
  205.  * We've got an odd situation here.  The odds are real good that the
  206.  * number we are looking for is almost the same as the index.  We could
  207.  * use the index, check the difference and do something intelligent, but
  208.  * I haven't quite figured out what's intelligent.
  209.  *
  210.  * Here's a start.
  211.  *    Take an id N.  If there are > N items in the list, then N cannot
  212.  *    be more than N items from the start, since otherwise there would
  213.  *    have to be duplicate items.  So we can safely set the top to N+1
  214.  *    (after taking into account that ids start at 1, and arrays at 0)
  215.  *
  216.  *    Let's say we are at position P, and we are looking for N, but have
  217.  *    V.  If N > V, then the furthest away that N could be is
  218.  *    P + (N-V).  So we can safely set hi to P+(N-V)+1.  For example:
  219.  *        We are looking for 10, but have 8
  220.  *        8    ?    ?    ?    ?
  221.  *            >=9    >=10    >=11
  222.  *
  223.  */
  224. MCSetT    *MCGetSet( cat, setId)
  225. MCCatT *cat;
  226. int setId;
  227. {
  228.     MCSetT    *set;
  229.     long    lo, hi, cur, dir;
  230.  
  231.     if (cat==(MCCatT *)NLERR || !cat || setId <= 0) return(NULL);
  232.  
  233.     lo = 0;
  234.     if (setId - 1 < cat->numSets) {
  235.     cur = setId - 1;
  236.     hi = setId;
  237.     } else {
  238.     hi = cat->numSets;
  239.     cur = (hi - lo) / 2;
  240.     }
  241.     
  242.     while (True) {
  243.     set = cat->sets + cur;
  244.     if (set->setId == setId) break;
  245.     if (set->setId < setId) {
  246.         lo = cur+1;
  247.         if (hi > cur + (setId - set->setId) + 1) hi = cur+(setId-set->setId)+1;
  248.         dir = 1;
  249.     } else {
  250.         hi = cur;
  251.         dir = -1;
  252.     }
  253.     if (lo >= hi) return(NULL);
  254.     if (hi - lo == 1) cur += dir;
  255.     else cur += ((hi - lo) / 2) * dir;
  256.     }
  257.     if (set->invalid) loadSet(cat, set);
  258.     return(set);
  259. }
  260.  
  261.     
  262. MCMsgT    *MCGetMsg( set, msgId)
  263. MCSetT *set;
  264. int msgId;
  265. {
  266.     MCMsgT    *msg;
  267.     long    lo, hi, cur, dir;
  268.     
  269.     if (!set || set->invalid || msgId <= 0) return(NULL);
  270.     
  271.     lo = 0;
  272.     if (msgId - 1 < set->numMsgs) {
  273.     cur = msgId - 1;
  274.     hi = msgId;
  275.     } else {
  276.     hi = set->numMsgs;
  277.     cur = (hi - lo) / 2;
  278.     }
  279.     
  280.     while (True) {
  281.     msg = set->u.msgs + cur;
  282.     if (msg->msgId == msgId) break;
  283.     if (msg->msgId < msgId) {
  284.         lo = cur+1;
  285.         if (hi > cur + (msgId - msg->msgId) + 1) hi = cur+(msgId-msg->msgId)+1;
  286.         dir = 1;
  287.     } else {
  288.         hi = cur;
  289.         dir = -1;
  290.     }
  291.     if (lo >= hi) return(NULL);
  292.     if (hi - lo == 1) cur += dir;
  293.     else cur += ((hi - lo) / 2) * dir;
  294.     }
  295.     return(msg);
  296. }
  297.  
  298. char        *catgets( catd, setId, msgId, dflt)
  299. nl_catd catd;
  300. int setId;
  301. int msgId;
  302. const char *dflt;
  303. {
  304.     MCMsgT    *msg;
  305.     MCCatT    *cat = (MCCatT *) catd;
  306.     char    *cptr;
  307.  
  308.     msg = MCGetMsg(MCGetSet(cat, setId), msgId);
  309.     if (msg) cptr = msg->msg.str;
  310.     else cptr = dflt;
  311.     return(cptr);
  312. }
  313.  
  314.  
  315. int    catclose (catd)
  316. nl_catd catd;
  317. {
  318.     MCCatT    *cat = (MCCatT *) catd;
  319.     MCSetT    *set;
  320.     MCMsgT    *msg;
  321.     int        i, j;
  322.  
  323.     if (cat==(MCCatT *)NLERR || !cat) return -1;
  324.     
  325.     if (cat->loadType != MCLoadAll)
  326. #ifndef HAVE_MMAP
  327.     close(cat->fd);
  328. #else
  329.     munmap(cat->u.addr,cat->size);
  330. #endif
  331.     for (i = 0; i < cat->numSets; ++i) {
  332.     set = cat->sets + i;
  333.     if (!set->invalid) {
  334. #if 0
  335.         free(set->data);
  336. #endif
  337.         free(set->data.str);
  338.         free(set->u.msgs);
  339.     }
  340.     }
  341.     free(cat->sets);
  342.     free(cat);
  343.     return 0;
  344. }
  345.  
  346. /*
  347.  * Internal routines
  348.  */
  349.  
  350. /* Note that only malloc failures are allowed to return an error */
  351. #define ERRNAME    "Message Catalog System"
  352. #define CORRUPT() {fprintf(stderr, "%s: corrupt file.\n", ERRNAME); return(0);}
  353. #define NOSPACE() {fprintf(stderr, "%s: no more memory.\n", ERRNAME); return(NLERR);}
  354.  
  355. #ifdef HAVE_MMAP
  356. static nl_catd loadCat( catpath, type, st)
  357. #else
  358. static nl_catd loadCat( catpath, type)
  359. #endif
  360. char *catpath;
  361. int type;
  362. #ifdef HAVE_MMAP
  363. struct stat *st;
  364. {
  365. #else
  366. {
  367.     MCHeaderT    header;
  368. #endif
  369.     MCCatT    *cat;
  370.     MCSetT    *set;
  371.     MCMsgT    *msg;
  372.     long    i, j;
  373.     off_t    nextSet;
  374. #ifdef HAVE_MMAP
  375.     caddr_t a;
  376. #endif
  377.  
  378.     cat = (MCCatT *) malloc(sizeof(MCCatT));
  379.     if (!cat) return(NLERR);
  380.     cat->loadType = type;
  381.  
  382. #ifdef HAVE_MMAP
  383.     if ((cat->u.fd = open(catpath, O_RDONLY)) < 0) {
  384. #else
  385.     if ((cat->fd = open(catpath, O_RDONLY)) < 0) {
  386. #endif
  387.     return(0);
  388.     }
  389.  
  390.  
  391. #ifdef HAVE_MMAP
  392.     if ((a=mmap(0,cat->size=st->st_size,
  393.         PROT_READ,MAP_SHARED,cat->u.fd,0))==(caddr_t)-1)
  394.                                 return(0);
  395.     close(cat->u.fd);
  396.     if(cat->size < sizeof(MCHeaderT) ||
  397.        strncmp((cat->u.addr=a), MCMagic, MCMagicLen)!=0) CORRUPT();
  398. #else
  399.  
  400.     fcntl(cat->fd, F_SETFD, FD_CLOEXEC);
  401.     if (read(cat->fd, &header, sizeof(header)) != sizeof(header)) CORRUPT();
  402.  
  403.     if (strncmp(header.magic, MCMagic, MCMagicLen) != 0) CORRUPT();
  404.  
  405. #endif
  406.  
  407. #ifdef HAVE_MMAP
  408.     if (((MCHeaderT *)(cat->u.addr))->majorVer !=MCMajorVer) {
  409. #else
  410.     if (header.majorVer != MCMajorVer) {
  411. #endif
  412.     fprintf(stderr, "%s: %s is version %d, we need %d.\n", ERRNAME, catpath,
  413. #ifdef HAVE_MMAP
  414.         ((MCHeaderT *)(cat->u.addr))->majorVer, MCMajorVer);
  415. #else
  416.         header.majorVer, MCMajorVer);
  417. #endif
  418.     return(0);
  419.     }
  420.  
  421. #ifdef HAVE_MMAP
  422.     if (((MCHeaderT *)(cat->u.addr))->numSets <= 0) {
  423. #else
  424.     if (header.numSets <= 0) {
  425. #endif
  426.     fprintf(stderr, "%s: %s has %d sets!\n", ERRNAME, catpath,
  427. #ifdef HAVE_MMAP
  428.         ((MCHeaderT *)(cat->u.addr))->numSets);
  429. #else
  430.         header.numSets);
  431. #endif
  432.     return(0);
  433.     }
  434. #ifdef HAVE_MMAP
  435.     cat->numSets = ((MCHeaderT *)(cat->u.addr))->numSets;
  436.     cat->sets = (MCSetT *) malloc(sizeof(MCSetT) *
  437.                   ((MCHeaderT *)(cat->u.addr))->numSets);
  438. #else
  439.     cat->numSets = header.numSets;
  440.     cat->sets = (MCSetT *) malloc(sizeof(MCSetT) * header.numSets);
  441. #endif
  442.     if (!cat->sets) NOSPACE();
  443.  
  444. #ifdef HAVE_MMAP
  445.     nextSet = ((MCHeaderT *)(cat->u.addr))->firstSet;
  446. #else
  447.     nextSet = header.firstSet;
  448. #endif
  449.     for (i = 0; i < cat->numSets; ++i) {
  450.  
  451. #ifndef HAVE_MMAP
  452.     if (lseek(cat->fd, nextSet, 0) == -1) CORRUPT();
  453. #else
  454.     if (nextSet > cat->size) CORRUPT();
  455. #endif
  456.     /* read in the set header */
  457.     set = cat->sets + i;
  458.  
  459. #ifdef HAVE_MMAP
  460.     if (nextSet+sizeof(*set) > cat->size) CORRUPT();
  461.     bcopy(cat->u.addr+nextSet,set,sizeof(*set));
  462. #else
  463.     if (read(cat->fd, set, sizeof(*set)) != sizeof(*set)) CORRUPT();
  464. #endif
  465.  
  466.     /* if it's invalid, skip over it (and backup 'i') */
  467.     
  468.     if (set->invalid) {
  469.         --i;
  470.         nextSet = set->nextSet;
  471.         continue;
  472.     }
  473.     if (cat->loadType == MCLoadAll) {
  474.         nl_catd    res;
  475.         if ((res = loadSet(cat, set)) <= 0) {
  476.         if (res == -1) NOSPACE();
  477.         CORRUPT();
  478.         }
  479.     } else set->invalid = True;
  480.     nextSet = set->nextSet;
  481.     }
  482.     if (cat->loadType == MCLoadAll) {
  483. #ifndef HAVE_MMAP
  484.     close(cat->fd);
  485.     cat->fd = -1;
  486. #else
  487.     munmap(cat->u.addr,cat->size);
  488. #endif
  489.     }
  490.     return((nl_catd) cat);
  491. }
  492.  
  493. static nl_catd loadSet( cat, set)
  494. MCCatT *cat;
  495. MCSetT *set;
  496. {
  497.     MCMsgT    *msg;
  498.     int        i;
  499. #ifdef HAVE_MMAP
  500.     long offset;
  501. #endif
  502.  
  503.     /* Get the data */
  504. #ifndef HAVE_MMAP
  505.     if (lseek(cat->fd,set->data.off, 0) == -1) return(0);
  506. #else
  507.    if ((offset=set->data.off) > cat->size) return(0);
  508. #endif
  509.  
  510.     if ((set->data.str = (char *) malloc(set->dataLen)) == NULL) return(-1);
  511.  
  512. #ifndef HAVE_MMAP
  513.     if (read(cat->fd, set->data.str, set->dataLen) != set->dataLen) return(0);
  514. #else
  515.     if (offset+set->dataLen > cat->size) return(0);
  516.     bcopy(cat->u.addr+offset,
  517.       set->data.str,set->dataLen);
  518. #endif
  519.     /* Get the messages */
  520.  
  521. #ifndef HAVE_MMAP
  522.     if (lseek(cat->fd, set->u.firstMsg, 0) == -1) return(0);
  523. #else
  524.     if ((offset=set->u.firstMsg) > cat->size) return(0);
  525. #endif
  526.  
  527.     if ((set->u.msgs = (MCMsgT *) malloc(sizeof(MCMsgT) * set->numMsgs)) == NULL) return(-1);
  528.  
  529.     for (i = 0; i < set->numMsgs; ++i) {
  530.     msg = set->u.msgs + i;
  531. #ifndef  HAVE_MMAP
  532.     if (read(cat->fd, msg, sizeof(*msg)) != sizeof(*msg)) return(0);
  533. #else
  534.     if (offset+sizeof(*msg) > cat->size) return(0);
  535.     bcopy(cat->u.addr+offset+i*sizeof(*msg),
  536.           msg,sizeof(*msg));
  537. #endif
  538.     if (msg->invalid) {
  539.         --i;
  540.         continue;
  541.     }
  542.     msg->msg.str = (char *) (set->data.str + msg->msg.off);
  543.     }
  544.     set->invalid = False;
  545.     return(1);
  546. }
  547.