diff options
Diffstat (limited to 'lib/libc')
-rw-r--r-- | lib/libc/nls/msgcat.c | 346 | ||||
-rw-r--r-- | lib/libc/nls/msgcat.h | 142 |
2 files changed, 96 insertions, 392 deletions
diff --git a/lib/libc/nls/msgcat.c b/lib/libc/nls/msgcat.c index 767f565..8689b7e 100644 --- a/lib/libc/nls/msgcat.c +++ b/lib/libc/nls/msgcat.c @@ -33,14 +33,14 @@ up-to-date. Many thanks. #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/* - * We need a better way of handling errors than printing text. I need - * to add an error handling routine. - */ +#define _NLS_PRIVATE #include "namespace.h" #include <sys/types.h> #include <sys/stat.h> +#include <sys/mman.h> + +#include <arpa/inet.h> /* for ntohl() */ #include <errno.h> #include <fcntl.h> @@ -53,23 +53,17 @@ __FBSDID("$FreeBSD$"); #include <unistd.h> #include "un-namespace.h" -#include "msgcat.h" #include "../locale/setlocale.h" /* for ENCODING_LEN */ #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" -#define TRUE 1 -#define FALSE 0 - #define NLERR ((nl_catd) -1) #define NLRETERR(errc) { errno = errc; return (NLERR); } -static nl_catd loadCat(__const char *); -static int loadSet(MCCatT *, MCSetT *); -static void __nls_free_resources(MCCatT *, int); +static nl_catd load_msgcat(const char *); nl_catd -catopen(__const char *name, int type) +catopen(const char *name, int type) { int spcleft, saverr; char path[PATH_MAX]; @@ -82,7 +76,7 @@ catopen(__const char *name, int type) /* is it absolute path ? if yes, load immediately */ if (strchr(name, '/') != NULL) - return (loadCat(name)); + return (load_msgcat(name)); if (type == NL_CAT_LOCALE) lang = setlocale(LC_MESSAGES, NULL); @@ -172,7 +166,7 @@ catopen(__const char *name, int type) if (stat(path, &sbuf) == 0) { free(plang); free(base); - return (loadCat(path)); + return (load_msgcat(path)); } } else { tmpptr = (char *)name; @@ -185,277 +179,129 @@ catopen(__const char *name, int type) NLRETERR(ENOENT); } -/* - * We've got an odd situation here. The odds are real good that the - * number we are looking for is almost the same as the index. We could - * use the index, check the difference and do something intelligent, but - * I haven't quite figured out what's intelligent. - * - * Here's a start. - * Take an id N. If there are > N items in the list, then N cannot - * be more than N items from the start, since otherwise there would - * have to be duplicate items. So we can safely set the top to N+1 - * (after taking into account that ids start at 1, and arrays at 0) - * - * Let's say we are at position P, and we are looking for N, but have - * V. If N > V, then the furthest away that N could be is - * P + (N-V). So we can safely set hi to P+(N-V)+1. For example: - * We are looking for 10, but have 8 - * 8 ? ? ? ? - * >=9 >=10 >=11 - * - */ +char * +catgets(nl_catd catd, int set_id, int msg_id, const char *s) +{ + struct _nls_cat_hdr *cat_hdr; + struct _nls_set_hdr *set_hdr; + struct _nls_msg_hdr *msg_hdr; + int l, u, i, r; -#define LOOKUP(PARENT, CHILD, ID, NUM, SET) { \ - lo = 0; \ - if (ID - 1 < PARENT->NUM) { \ - cur = ID - 1; \ - hi = ID; \ - } else { \ - hi = PARENT->NUM; \ - cur = (hi - lo) / 2; \ - } \ - while (TRUE) { \ - CHILD = PARENT->SET + cur; \ - if (CHILD->ID == ID) \ - break; \ - if (CHILD->ID < ID) { \ - lo = cur + 1; \ - if (hi > cur + (ID - CHILD->ID) + 1) \ - hi = cur + (ID - CHILD->ID) + 1; \ - dir = 1; \ - } else { \ - hi = cur; \ - dir = -1; \ - } \ - if (lo >= hi) \ - return (NULL); \ - if (hi - lo == 1) \ - cur += dir; \ - else \ - cur += ((hi - lo) / 2) * dir; \ - } \ + if (catd == NULL || catd == NLERR) { + errno = EBADF; + /* LINTED interface problem */ + return (char *) s; } -static MCSetT * -MCGetSet(MCCatT *cat, int setId) -{ - MCSetT *set; - long lo, hi, cur, dir; - - if (cat == NULL || setId <= 0) - return (NULL); - LOOKUP(cat, set, setId, numSets, sets); - if (set->invalid && loadSet(cat, set) <= 0) - return (NULL); - return (set); + cat_hdr = (struct _nls_cat_hdr *)catd->__data; + set_hdr = (struct _nls_set_hdr *)(void *)((char *)catd->__data + + sizeof(struct _nls_cat_hdr)); + + /* binary search, see knuth algorithm b */ + l = 0; + u = ntohl((u_int32_t)cat_hdr->__nsets) - 1; + while (l <= u) { + i = (l + u) / 2; + r = set_id - ntohl((u_int32_t)set_hdr[i].__setno); + + if (r == 0) { + msg_hdr = (struct _nls_msg_hdr *) + (void *)((char *)catd->__data + + sizeof(struct _nls_cat_hdr) + + ntohl((u_int32_t)cat_hdr->__msg_hdr_offset)); + + l = ntohl((u_int32_t)set_hdr[i].__index); + u = l + ntohl((u_int32_t)set_hdr[i].__nmsgs) - 1; + while (l <= u) { + i = (l + u) / 2; + r = msg_id - + ntohl((u_int32_t)msg_hdr[i].__msgno); + if (r == 0) { + return ((char *) catd->__data + + sizeof(struct _nls_cat_hdr) + + ntohl((u_int32_t) + cat_hdr->__msg_txt_offset) + + ntohl((u_int32_t) + msg_hdr[i].__offset)); + } else if (r < 0) { + u = i - 1; + } else { + l = i + 1; + } } -static MCMsgT * -MCGetMsg(MCSetT *set, int msgId) -{ - MCMsgT *msg; - long lo, hi, cur, dir; + /* not found */ + goto notfound; - if (set == NULL || set->invalid || msgId <= 0) - return (NULL); - LOOKUP(set, msg, msgId, numMsgs, u.msgs); - return (msg); + } else if (r < 0) { + u = i - 1; + } else { + l = i + 1; + } } -char * -catgets(nl_catd catd, int setId, int msgId, __const char *dflt) -{ - MCMsgT *msg; - MCCatT *cat = (MCCatT *)catd; - __const char *cptr; - - if (catd == NULL || catd == NLERR) - return ((char *)dflt); - msg = MCGetMsg(MCGetSet(cat, setId), msgId); - if (msg != NULL) - cptr = msg->msg.str; - else - cptr = dflt; - return ((char *)cptr); +notfound: + /* not found */ + errno = ENOMSG; + /* LINTED interface problem */ + return (char *) s; } int catclose(nl_catd catd) { - MCCatT *cat = (MCCatT *)catd; - if (catd == NULL || catd == NLERR) { errno = EBADF; return (-1); } - (void)fclose(cat->fp); - __nls_free_resources(cat, cat->numSets); - free(cat); + munmap(catd->__data, (size_t)catd->__size); + free(catd); return (0); } /* - * Internal routines + * Internal support functions */ -/* Note that only malloc failures are allowed to return an error */ -static char *_errowner = "Message Catalog System"; - -#define CORRUPT() { \ - (void)fclose(cat->fp); \ - (void)fprintf(stderr, "%s: corrupt file.", _errowner); \ - free(cat); \ - NLRETERR(EFTYPE); \ -} - -#define NOSPACE() { \ - saverr = errno; \ - (void)fclose(cat->fp); \ - (void)fprintf(stderr, "%s: no more memory.", _errowner); \ - free(cat); \ - errno = saverr; \ - return (NLERR); \ -} - -static void -__nls_free_resources(MCCatT *cat, int i) -{ - MCSetT *set; - int j; - - for (j = 0; j < i; j++) { - set = cat->sets + j; - if (!set->invalid) { - free(set->data.str); - free(set->u.msgs); - } - } - free(cat->sets); -} - static nl_catd -loadCat(__const char *catpath) +load_msgcat(const char *path) { - MCHeaderT header; - MCCatT *cat; - MCSetT *set; - long i; - off_t nextSet; - int saverr; - - if ((cat = (MCCatT *)malloc(sizeof(MCCatT))) == NULL) + struct stat st; + nl_catd catd; + void *data; + int fd; + + /* XXX: path != NULL? */ + + if ((fd = _open(path, O_RDONLY)) == -1) return (NLERR); - if ((cat->fp = fopen(catpath, "r")) == NULL) { - saverr = errno; - free(cat); - errno = saverr; + if (_fstat(fd, &st) != 0) { + _close(fd); return (NLERR); } - (void)_fcntl(fileno(cat->fp), F_SETFD, FD_CLOEXEC); - - if (fread(&header, sizeof(header), 1, cat->fp) != 1 || - strncmp(header.magic, MCMagic, MCMagicLen) != 0) - CORRUPT(); - - if (header.majorVer != MCMajorVer) { - (void)fclose(cat->fp); - free(cat); - (void)fprintf(stderr, "%s: %s is version %ld, we need %ld.\n", - _errowner, catpath, header.majorVer, MCMajorVer); - NLRETERR(EFTYPE); - } - if (header.numSets <= 0) { - (void)fclose(cat->fp); - free(cat); - (void)fprintf(stderr, "%s: %s has %ld sets!\n", - _errowner, catpath, header.numSets); - NLRETERR(EFTYPE); - } - - cat->numSets = header.numSets; - if ((cat->sets = (MCSetT *)malloc(sizeof(MCSetT) * header.numSets)) == - NULL) - NOSPACE(); - nextSet = header.firstSet; - for (i = 0; i < cat->numSets; ++i) { - if (fseeko(cat->fp, nextSet, SEEK_SET) == -1) { - __nls_free_resources(cat, i); - CORRUPT(); - } + data = mmap(0, (size_t)st.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd, + (off_t)0); + _close(fd); - /* read in the set header */ - set = cat->sets + i; - if (fread(set, sizeof(*set), 1, cat->fp) != 1) { - __nls_free_resources(cat, i); - CORRUPT(); - } - - /* if it's invalid, skip over it (and backup 'i') */ - if (set->invalid) { - --i; - nextSet = set->nextSet; - continue; - } - set->invalid = TRUE; - nextSet = set->nextSet; - } - - return ((nl_catd) cat); -} + if (data == MAP_FAILED) + return (NLERR); -static int -loadSet(MCCatT *cat, MCSetT *set) -{ - MCMsgT *msg; - int i; - int saverr; - - /* Get the data */ - if (fseeko(cat->fp, set->data.off, SEEK_SET) == -1) - return (0); - if ((set->data.str = malloc(set->dataLen)) == NULL) - return (-1); - if (fread(set->data.str, set->dataLen, 1, cat->fp) != 1) { - saverr = errno; - free(set->data.str); - errno = saverr; - return (0); + if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) != + _NLS_MAGIC) { + munmap(data, (size_t)st.st_size); + NLRETERR(EINVAL); } - /* Get the messages */ - if (fseeko(cat->fp, set->u.firstMsg, SEEK_SET) == -1) { - saverr = errno; - free(set->data.str); - errno = saverr; - return (0); - } - if ((set->u.msgs = (MCMsgT *)malloc(sizeof(MCMsgT) * set->numMsgs)) == - NULL) { - saverr = errno; - free(set->data.str); - errno = saverr; - return (-1); + if ((catd = malloc(sizeof (*catd))) == NULL) { + munmap(data, (size_t)st.st_size); + return (NLERR); } - for (i = 0; i < set->numMsgs; ++i) { - msg = set->u.msgs + i; - if (fread(msg, sizeof(*msg), 1, cat->fp) != 1) { - saverr = errno; - free(set->u.msgs); - free(set->data.str); - errno = saverr; - return (0); - } - if (msg->invalid) { - --i; - continue; - } - msg->msg.str = (char *)(set->data.str + msg->msg.off); - } - set->invalid = FALSE; - return (1); + catd->__data = data; + catd->__size = (int)st.st_size; + return (catd); } + diff --git a/lib/libc/nls/msgcat.h b/lib/libc/nls/msgcat.h deleted file mode 100644 index 403b33c..0000000 --- a/lib/libc/nls/msgcat.h +++ /dev/null @@ -1,142 +0,0 @@ -/* $FreeBSD$ */ - -#ifndef _MSGCAT_H_ -#define _MSGCAT_H_ - - -/*********************************************************** -Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that Alfalfa's name not be used in -advertising or publicity pertaining to distribution of the software -without specific, written prior permission. - -ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -If you make any modifications, bugfixes or other changes to this software -we'd appreciate it if you could send a copy to us so we can keep things -up-to-date. Many thanks. - Kee Hinckley - Alfalfa Software, Inc. - 267 Allston St., #3 - Cambridge, MA 02139 USA - nazgul@alfalfa.com - -******************************************************************/ - -/* - * Magic definitions - */ - -#define MCMagicLen 8 -#define MCMagic "*nazgul*" - -#define MCMajorVer 1L -#define MCMinorVer 0 - -/* For or'd constants */ -#define MCMakeId(s,m) (unsigned long) ( ((unsigned short)s << (sizeof(short)*8)) \ - | (unsigned short)m ) - -/* - * Critical note here. Sets and Messages *MUST* be stored in ascending - * order. There are stored that way (by specification) in the original - * data file, however in the process of merging in new stuff you might - * mix that up. Don't! The catget stuff does a binary search and will - * totally lose it if these aren't in order (not contiguous mind you, just - * in order. If this turns out to be a major problem this could be enhanced - * by adding a 'sorted' flag to the db, and sorting msgs and sets at load - * time if things aren't sorted, but I'd like not to have to do that. - */ - -/* - * I have tried here to define data structures which can be used - * while the catalog is on disk, and at runtime. - * This is rather dangerous of course, but I think it can be done without - * overly increasing the memory usage, and it makes loading and storing - * somewhat simpler and less prone to accidents. I have also tried to - * define on disk data structures which can be updated in place, so that - * with a very large catalog (e.g. all system errors) you don't have to - * load everything in memory in order to add or update one set. With - * this in mind there are "invalid" flags which allow items to be - * invalidated and thus not loaded at runtime. Note however that although - * I pay attention to these when I load the DB, I do not currently use - * them in gencat (it just reads everything into memory), so there is - * no guarantee that this will all work. - */ - -/* - * MCOffsetT - Union to handle both disk and runtime pointers - */ -typedef union { - off_t off; - char *str; - void *ptr; - struct _MCMsgT *msg; - struct _MCSetT *set; -} MCOffsetT; - -/* - * MCMsgT - Message structure (disk and runtime) - */ -typedef struct _MCMsgT { - long msgId; /* Id of this message */ - MCOffsetT msg; /* Relative offset on disk or pointer in memory */ - long invalid; /* Valid on disk, loaded in memory */ -} MCMsgT; - -/* - * MCSetT - Set structure (disk and runtime) - */ -typedef struct _MCSetT { - long setId; /* Id of this set */ - off_t nextSet; /* Offset of next set on disk */ - union { - off_t firstMsg; /* Offset to first Msg (while on disk) */ - MCMsgT *msgs; /* Pointer to array of msgs (in mem, loaded) */ - } u; - MCOffsetT data; /* Offset to data, or pointer to data */ - long dataLen; /* Length of data area on disk */ - long numMsgs; /* Number of messages */ - long invalid; /* Valid on disk, loaded in memory */ -} MCSetT; - -/* - * MCCatT - Runtime catalog pointer - */ -typedef struct { - FILE *fp; /* File descriptor of catalog (if load-on-demand) */ - long numSets; /* Number of sets */ - MCSetT *sets; /* Pointer to the sets */ - off_t firstSet; /* Offset of first set on disk */ -} MCCatT; - -/* - * MCHeaderT - Disk file header - */ -typedef struct { - char magic[MCMagicLen]; /* Magic cookie "*nazgul*" */ - long majorVer; /* ++ on incompatible changes */ - long minorVer; /* ++ on compatible changes */ - long flags; /* Informational flags */ - long numSets; /* Number of valid Sets */ - off_t firstSet; /* Offset of first set on disk */ -} MCHeaderT; - -/* Some flags */ -#define MC68KByteOrder 0x01 -#define MCn86ByteOrder 0x02 - -#endif /* !_MSGCAT_H_ */ |