summaryrefslogtreecommitdiffstats
path: root/lib/libc/nls
diff options
context:
space:
mode:
authorphantom <phantom@FreeBSD.org>2005-02-27 16:26:49 +0000
committerphantom <phantom@FreeBSD.org>2005-02-27 16:26:49 +0000
commitdb7bc61c50a6090bfd3c674fa7500228355b2479 (patch)
tree43e3c252995e89db311de89090ba60d8b23a10c9 /lib/libc/nls
parent49c043ebad5e3e4430e15cb48c0ea5a07f1a04c1 (diff)
downloadFreeBSD-src-db7bc61c50a6090bfd3c674fa7500228355b2479.zip
FreeBSD-src-db7bc61c50a6090bfd3c674fa7500228355b2479.tar.gz
Bring in NetBSD's improvements and cleanups to NLS subsystem, making
it type and endian clean and removing of stdio dependency from NLS functions (catalog files now are processed via mmap()) Also following changes were done (against NetBSD version): . If mmap() failed, set errno to EINVAL and do not try to munmap() file Obtained from: NetBSD
Diffstat (limited to 'lib/libc/nls')
-rw-r--r--lib/libc/nls/msgcat.c346
-rw-r--r--lib/libc/nls/msgcat.h142
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_ */
OpenPOWER on IntegriCloud