home *** CD-ROM | disk | FTP | other *** search
/ ftp.uv.es / 2014.11.ftp.uv.es.tar / ftp.uv.es / pub / unix / elm-2.4-pl20.tar.Z / elm-2.4-pl20.tar / lib / msgcat.c < prev    next >
C/C++ Source or Header  |  1992-10-03  |  10KB  |  406 lines

  1. /* -*- c++ -*- */
  2.  
  3. /***********************************************************
  4. Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
  5.  
  6.                         All Rights Reserved
  7.  
  8. Permission to use, copy, modify, and distribute this software and its
  9. documentation for any purpose and without fee is hereby granted,
  10. provided that the above copyright notice appear in all copies and that
  11. both that copyright notice and this permission notice appear in
  12. supporting documentation, and that Alfalfa's name not be used in
  13. advertising or publicity pertaining to distribution of the software
  14. without specific, written prior permission.
  15.  
  16. ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  17. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  18. ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  19. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  20. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  21. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  22. SOFTWARE.
  23.  
  24. If you make any modifications, bugfixes or other changes to this software
  25. we'd appreciate it if you could send a copy to us so we can keep things
  26. up-to-date.  Many thanks.
  27.                 Kee Hinckley
  28.                 Alfalfa Software, Inc.
  29.                 267 Allston St., #3
  30.                 Cambridge, MA 02139  USA
  31.                 nazgul@alfalfa.com
  32.     
  33. ******************************************************************/
  34.  
  35. /* Edit History
  36.  
  37. 03/06/91   4 schulert    remove working directory from nlspath
  38. 01/18/91   2 hamilton    #if not rescanned
  39. 01/12/91   3 schulert    conditionally use prototypes
  40. 11/03/90   1 hamilton    Alphalpha->Alfalfa & OmegaMail->Poste
  41. 10/15/90   2 schulert    > #include <unistd.h> if MIPS
  42. 08/13/90   1 schulert    move from ua to omu
  43. */
  44.  
  45. /*
  46.  * We need a better way of handling errors than printing text.  I need
  47.  * to add an error handling routine.
  48.  */
  49.  
  50. #include "nl_types.h"
  51. #include "msgcat.h"
  52.  
  53. #ifdef BSD
  54. #include <sys/file.h>
  55. #include <sys/param.h>
  56. #endif
  57. #include <sys/stat.h>
  58. #include <fcntl.h>
  59. #include <stdio.h>
  60.  
  61. #ifdef MIPS
  62. #include <unistd.h>
  63. #endif
  64.  
  65. #ifndef True
  66. # define True    ~0
  67. # define False    0
  68. #endif
  69.  
  70. /* take care of sysv diffs */
  71. #ifndef MAXPATHLEN
  72. #define MAXPATHLEN 1024
  73. #endif
  74.  
  75. #ifndef FD_CLOEXEC
  76. #define FD_CLOEXEC 1
  77. #endif
  78.  
  79. #define    NLERR    ((nl_catd) -1)
  80.  
  81. char    *MCAppPath = NULL;
  82.  
  83. static nl_catd loadCat();
  84. static nl_catd loadSet();
  85.  
  86. extern char *malloc(), *getenv();
  87.     
  88. nl_catd     catopen( name, type)
  89. char *name;
  90. int type;
  91. {
  92.     char    path[MAXPATHLEN], *catpath = NULL;
  93.     char    *nlspath, *tmppath = NULL;
  94.     char    *lang;
  95.     long    len;
  96.     char    *base, *cptr, *pathP;
  97.     struct stat    sbuf;
  98.     
  99.     if (!name || !*name) return(NLERR);
  100.     if (*name == '/') {
  101.     catpath = name;
  102.     if (stat(catpath, &sbuf)) return(0);
  103.     } else {
  104.     if ((lang = (char *) getenv("LANG")) == NULL) lang = "C";
  105.     if ((nlspath = (char *) getenv("NLSPATH")) == NULL) {
  106.         nlspath = "/nlslib/%L/%N.cat:/nlslib/%N/%L";
  107.     }
  108.     if (MCAppPath) {
  109.         tmppath = (char *) malloc(strlen(nlspath) + strlen(MCAppPath) + 3);
  110.         if (!tmppath) return(NLERR);
  111.         strcpy(tmppath, nlspath);
  112.         if (tmppath[strlen(tmppath)-1] != ':' && *MCAppPath != ':')
  113.           strcat(tmppath, ":");
  114.         strcat(tmppath, MCAppPath);
  115.         nlspath = tmppath;
  116.     }
  117.     
  118.     len = strlen(nlspath);
  119.     base = cptr = (char *) malloc(len + 2);
  120.     if (!base) return(NLERR);
  121.     strcpy(cptr, nlspath);
  122.     cptr[len] = ':';
  123.     cptr[len+1] = '\0';
  124.         
  125.     for (nlspath = cptr; *cptr; ++cptr) {
  126.         if (*cptr == ':') {
  127.         *cptr = '\0';
  128.         for (pathP = path; *nlspath; ++nlspath) {
  129.             if (*nlspath == '%') {
  130.             if (*(nlspath + 1) == 'L') {
  131.                 ++nlspath;
  132.                 strcpy(pathP, lang);
  133.                 pathP += strlen(lang);
  134.             } else if (*(nlspath + 1) == 'N') {
  135.                 ++nlspath;
  136.                 strcpy(pathP, name);
  137.                 pathP += strlen(name);
  138.             } else *(pathP++) = *nlspath;
  139.             } else *(pathP++) = *nlspath;
  140.         }
  141.         *pathP = '\0';
  142.         if (stat(path, &sbuf) == 0) {
  143.             catpath = path;
  144.             break;
  145.         }
  146.         nlspath = cptr+1;
  147.         }
  148.     }
  149.     free(base);
  150.     if (tmppath) free(tmppath);
  151.  
  152.     if (!catpath) return(0);
  153.     }
  154.  
  155.     return(loadCat(catpath, type));
  156. }
  157.  
  158. /*
  159.  * We've got an odd situation here.  The odds are real good that the
  160.  * number we are looking for is almost the same as the index.  We could
  161.  * use the index, check the difference and do something intelligent, but
  162.  * I haven't quite figured out what's intelligent.
  163.  *
  164.  * Here's a start.
  165.  *    Take an id N.  If there are > N items in the list, then N cannot
  166.  *    be more than N items from the start, since otherwise there would
  167.  *    have to be duplicate items.  So we can safely set the top to N+1
  168.  *    (after taking into account that ids start at 1, and arrays at 0)
  169.  *
  170.  *    Let's say we are at position P, and we are looking for N, but have
  171.  *    V.  If N > V, then the furthest away that N could be is
  172.  *    P + (N-V).  So we can safely set hi to P+(N-V)+1.  For example:
  173.  *        We are looking for 10, but have 8
  174.  *        8    ?    ?    ?    ?
  175.  *            >=9    >=10    >=11
  176.  *
  177.  */
  178. MCSetT    *MCGetSet( cat, setId)
  179. MCCatT *cat;
  180. int setId;
  181. {
  182.     MCSetT    *set;
  183.     long    lo, hi, cur, dir;
  184.  
  185.     if (!cat || setId <= 0) return(NULL);
  186.  
  187.     lo = 0;
  188.     if (setId - 1 < cat->numSets) {
  189.     cur = setId - 1;
  190.     hi = setId;
  191.     } else {
  192.     hi = cat->numSets;
  193.     cur = (hi - lo) / 2;
  194.     }
  195.     
  196.     while (True) {
  197.     set = cat->sets + cur;
  198.     if (set->setId == setId) break;
  199.     if (set->setId < setId) {
  200.         lo = cur+1;
  201.         if (hi > cur + (setId - set->setId) + 1) hi = cur+(setId-set->setId)+1;
  202.         dir = 1;
  203.     } else {
  204.         hi = cur;
  205.         dir = -1;
  206.     }
  207.     if (lo >= hi) return(NULL);
  208.     if (hi - lo == 1) cur += dir;
  209.     else cur += ((hi - lo) / 2) * dir;
  210.     }
  211.     if (set->invalid) loadSet(cat, set);
  212.     return(set);
  213. }
  214.  
  215.     
  216. MCMsgT    *MCGetMsg( set, msgId)
  217. MCSetT *set;
  218. int msgId;
  219. {
  220.     MCMsgT    *msg;
  221.     long    lo, hi, cur, dir;
  222.     
  223.     if (!set || set->invalid || msgId <= 0) return(NULL);
  224.     
  225.     lo = 0;
  226.     if (msgId - 1 < set->numMsgs) {
  227.     cur = msgId - 1;
  228.     hi = msgId;
  229.     } else {
  230.     hi = set->numMsgs;
  231.     cur = (hi - lo) / 2;
  232.     }
  233.     
  234.     while (True) {
  235.     msg = set->u.msgs + cur;
  236.     if (msg->msgId == msgId) break;
  237.     if (msg->msgId < msgId) {
  238.         lo = cur+1;
  239.         if (hi > cur + (msgId - msg->msgId) + 1) hi = cur+(msgId-msg->msgId)+1;
  240.         dir = 1;
  241.     } else {
  242.         hi = cur;
  243.         dir = -1;
  244.     }
  245.     if (lo >= hi) return(NULL);
  246.     if (hi - lo == 1) cur += dir;
  247.     else cur += ((hi - lo) / 2) * dir;
  248.     }
  249.     return(msg);
  250. }
  251.  
  252. char        *catgets( catd, setId, msgId, dflt)
  253. nl_catd catd;
  254. int setId;
  255. int msgId;
  256. char *dflt;
  257. {
  258.     MCMsgT    *msg;
  259.     MCCatT    *cat = (MCCatT *) catd;
  260.     char    *cptr;
  261.  
  262.     msg = MCGetMsg(MCGetSet(cat, setId), msgId);
  263.     if (msg) cptr = msg->msg.str;
  264.     else cptr = dflt;
  265.     return(cptr);
  266. }
  267.  
  268.  
  269. void        catclose( catd)
  270. nl_catd catd;
  271. {
  272.     MCCatT    *cat = (MCCatT *) catd;
  273.     MCSetT    *set;
  274.     MCMsgT    *msg;
  275.     int        i, j;
  276.  
  277.     if (!cat) return;
  278.     
  279.     if (cat->loadType != MCLoadAll) close(cat->fd);
  280.     for (i = 0; i < cat->numSets; ++i) {
  281.     set = cat->sets + i;
  282.     if (!set->invalid) {
  283.         free(set->data);
  284.         free(set->u.msgs);
  285.     }
  286.     }
  287.     free(cat->sets);
  288.     free(cat);
  289. }
  290.  
  291. /*
  292.  * Internal routines
  293.  */
  294.  
  295. /* Note that only malloc failures are allowed to return an error */
  296. #define ERRNAME    "Message Catalog System"
  297. #define CORRUPT() {fprintf(stderr, "%s: corrupt file.\n", ERRNAME); return(0);}
  298. #define NOSPACE() {fprintf(stderr, "%s: no more memory.\n", ERRNAME); return(NLERR);}
  299.  
  300. static nl_catd loadCat( catpath, type)
  301. char *catpath;
  302. int type;
  303. {
  304.     MCHeaderT    header;
  305.     MCCatT    *cat;
  306.     MCSetT    *set;
  307.     MCMsgT    *msg;
  308.     long    i, j;
  309.     off_t    nextSet;
  310.  
  311.     cat = (MCCatT *) malloc(sizeof(MCCatT));
  312.     if (!cat) return(NLERR);
  313.     cat->loadType = type;
  314.  
  315.     if ((cat->fd = open(catpath, O_RDONLY)) < 0) {
  316.     return(0);
  317.     }
  318.  
  319.     fcntl(cat->fd, F_SETFD, FD_CLOEXEC);
  320.  
  321.     if (read(cat->fd, &header, sizeof(header)) != sizeof(header)) CORRUPT();
  322.  
  323.     if (strncmp(header.magic, MCMagic, MCMagicLen) != 0) CORRUPT();
  324.     
  325.     if (header.majorVer != MCMajorVer) {
  326.     fprintf(stderr, "%s: %s is version %d, we need %d.\n", ERRNAME,
  327.         catpath, header.majorVer, MCMajorVer);
  328.     return(0);
  329.     }
  330.     
  331.     if (header.numSets <= 0) {
  332.     fprintf(stderr, "%s: %s has %d sets!\n", ERRNAME, catpath,
  333.         header.numSets);
  334.     return(0);
  335.     }
  336.  
  337.     cat->numSets = header.numSets;
  338.     cat->sets = (MCSetT *) malloc(sizeof(MCSetT) * header.numSets);
  339.     if (!cat->sets) NOSPACE();
  340.  
  341.     nextSet = header.firstSet;
  342.     for (i = 0; i < cat->numSets; ++i) {
  343.     if (lseek(cat->fd, nextSet, 0) == -1) CORRUPT();
  344.  
  345.     /* read in the set header */
  346.     set = cat->sets + i;
  347.     if (read(cat->fd, set, sizeof(*set)) != sizeof(*set)) CORRUPT();
  348.  
  349.     /* if it's invalid, skip over it (and backup 'i') */
  350.     
  351.     if (set->invalid) {
  352.         --i;
  353.         nextSet = set->nextSet;
  354.         continue;
  355.     }
  356.  
  357.     if (cat->loadType == MCLoadAll) {
  358.         nl_catd    res;
  359.         if ((res = loadSet(cat, set)) <= 0) {
  360.         if (res == -1) NOSPACE();
  361.         CORRUPT();
  362.         }
  363.     } else set->invalid = True;
  364.     nextSet = set->nextSet;
  365.     }
  366.     if (cat->loadType == MCLoadAll) {
  367.     close(cat->fd);
  368.     cat->fd = -1;
  369.     }
  370.     return((nl_catd) cat);
  371. }
  372.  
  373. static nl_catd loadSet( cat, set)
  374. MCCatT *cat;
  375. MCSetT *set;
  376. {
  377.     MCMsgT    *msg;
  378.     int        i;
  379.  
  380.     /* Get the data */
  381.     if (lseek(cat->fd, set->data.off, 0) == -1) return(0);
  382.     if ((set->data.str = (char *) malloc(set->dataLen)) == NULL) return(-1);
  383.     if (read(cat->fd, set->data.str, set->dataLen) != set->dataLen) return(0);
  384.  
  385.     /* Get the messages */
  386.     if (lseek(cat->fd, set->u.firstMsg, 0) == -1) return(0);
  387.     if ((set->u.msgs = (MCMsgT *) malloc(sizeof(MCMsgT) * set->numMsgs)) == NULL) return(-1);
  388.     
  389.     for (i = 0; i < set->numMsgs; ++i) {
  390.     msg = set->u.msgs + i;
  391.     if (read(cat->fd, msg, sizeof(*msg)) != sizeof(*msg)) return(0);
  392.     if (msg->invalid) {
  393.         --i;
  394.         continue;
  395.     }
  396.     msg->msg.str = (char *) (set->data.str + msg->msg.off);
  397.     }
  398.     set->invalid = False;
  399.     return(1);
  400. }
  401.         
  402.         
  403.         
  404.  
  405.  
  406.