From 29be49b4484e0d099b383a80333f1293a63ddf22 Mon Sep 17 00:00:00 2001 From: tshiozak Date: Thu, 23 Sep 2004 16:44:26 +0000 Subject: [PATCH] - add hash table support. - make use of __UNCONST() instead of LINTED. --- lib/libintl/Makefile | 4 +- lib/libintl/gettext.c | 110 ++++++++++++++++++++++++++++++------ lib/libintl/libintl_local.h | 24 +++++++- lib/libintl/strhash.c | 63 +++++++++++++++++++++ lib/libintl/textdomain.c | 6 +- 5 files changed, 182 insertions(+), 25 deletions(-) create mode 100644 lib/libintl/strhash.c diff --git a/lib/libintl/Makefile b/lib/libintl/Makefile index 61f91dc3bb27..093e4beedf53 100644 --- a/lib/libintl/Makefile +++ b/lib/libintl/Makefile @@ -1,9 +1,9 @@ -# $NetBSD: Makefile,v 1.3 2004/01/18 08:40:40 yamt Exp $ +# $NetBSD: Makefile,v 1.4 2004/09/23 16:44:26 tshiozak Exp $ .include LIB= intl -SRCS= gettext.c textdomain.c gettext_iconv.c gettext_dummy.c +SRCS= gettext.c textdomain.c gettext_iconv.c gettext_dummy.c strhash.c INCS= libintl.h INCSDIR=/usr/include diff --git a/lib/libintl/gettext.c b/lib/libintl/gettext.c index cfe66eb7fa19..4e24330e7a65 100644 --- a/lib/libintl/gettext.c +++ b/lib/libintl/gettext.c @@ -1,4 +1,4 @@ -/* $NetBSD: gettext.c,v 1.18 2004/01/18 08:40:40 yamt Exp $ */ +/* $NetBSD: gettext.c,v 1.19 2004/09/23 16:44:26 tshiozak Exp $ */ /*- * Copyright (c) 2000, 2001 Citrus Project, @@ -29,13 +29,14 @@ */ #include -__RCSID("$NetBSD: gettext.c,v 1.18 2004/01/18 08:40:40 yamt Exp $"); +__RCSID("$NetBSD: gettext.c,v 1.19 2004/09/23 16:44:26 tshiozak Exp $"); #include #include #include #include +#include #include #include #include @@ -189,25 +190,25 @@ fail: if (t) { if (c) { snprintf(tmp, sizeof(tmp), "%s_%s.%s@%s", - l, t, c, m); + l, t, c, m); strlcat(result, tmp, sizeof(result)); strlcat(result, ":", sizeof(result)); } - snprintf(tmp, sizeof(tmp), "%s_%s@%s", l, t, m); + snprintf(tmp, sizeof(tmp), "%s_%s@%s", l, t, m); strlcat(result, tmp, sizeof(result)); strlcat(result, ":", sizeof(result)); } - snprintf(tmp, sizeof(tmp), "%s@%s", l, m); + snprintf(tmp, sizeof(tmp), "%s@%s", l, m); strlcat(result, tmp, sizeof(result)); strlcat(result, ":", sizeof(result)); } if (t) { if (c) { - snprintf(tmp, sizeof(tmp), "%s_%s.%s", l, t, c); + snprintf(tmp, sizeof(tmp), "%s_%s.%s", l, t, c); strlcat(result, tmp, sizeof(result)); strlcat(result, ":", sizeof(result)); } - snprintf(tmp, sizeof(tmp), "%s_%s", l, t); + snprintf(tmp, sizeof(tmp), "%s_%s", l, t); strlcat(result, tmp, sizeof(result)); strlcat(result, ":", sizeof(result)); } @@ -309,6 +310,7 @@ mapit(path, db) char *base; u_int32_t magic, revision; struct moentry *otable, *ttable; + const u_int32_t *htable; struct moentry_h *p; struct mo *mo; size_t l; @@ -338,8 +340,18 @@ mapit(path, db) close(fd); goto fail; } - if (read(fd, &revision, sizeof(revision)) != sizeof(revision) || - flip(revision, magic) != MO_REVISION) { + if (read(fd, &revision, sizeof(revision)) != sizeof(revision)) { + close(fd); + goto fail; + } + switch (flip(revision, magic)) { + case MO_MAKE_REV(0, 0): +#if 0 + case MO_MAKE_REV(0, 1): + case MO_MAKE_REV(1, 1): +#endif + break; + default: close(fd); goto fail; } @@ -359,9 +371,12 @@ mapit(path, db) mohandle->mo.mo_magic = mo->mo_magic; mohandle->mo.mo_revision = flip(mo->mo_revision, magic); mohandle->mo.mo_nstring = flip(mo->mo_nstring, magic); + mohandle->mo.mo_hsize = flip(mo->mo_hsize, magic); /* validate otable/ttable */ + /* LINTED: ignore the alignment problem. */ otable = (struct moentry *)(base + flip(mo->mo_otable, magic)); + /* LINTED: ignore the alignment problem. */ ttable = (struct moentry *)(base + flip(mo->mo_ttable, magic)); if (!validate(otable, mohandle) || !validate(&otable[mohandle->mo.mo_nstring], mohandle)) { @@ -408,7 +423,26 @@ mapit(path, db) goto fail; } } - + /* allocate htable, and convert it to the host order. */ + if (mohandle->mo.mo_hsize > 2) { + l = sizeof(u_int32_t) * mohandle->mo.mo_hsize; + mohandle->mo.mo_htable = (u_int32_t *)malloc(l); + if (!mohandle->mo.mo_htable) { + unmapit(db); + goto fail; + } + /* LINTED: ignore the alignment problem. */ + htable = (const u_int32_t *)(base+flip(mo->mo_hoffset, magic)); + for (i=0; i < mohandle->mo.mo_hsize; i++) { + mohandle->mo.mo_htable[i] = flip(htable[i], magic); + if (mohandle->mo.mo_htable[i] >= + mohandle->mo.mo_nstring+1) { + /* illegal string number. */ + unmapit(db); + goto fail; + } + } + } /* grab MIME-header and charset field */ mohandle->mo.mo_header = lookup("", db); if (mohandle->mo.mo_header) @@ -454,22 +488,63 @@ unmapit(db) free(mohandle->mo.mo_ttable); if (mohandle->mo.mo_charset) free(mohandle->mo.mo_charset); + if (mohandle->mo.mo_htable) + free(mohandle->mo.mo_htable); memset(&mohandle->mo, 0, sizeof(mohandle->mo)); return 0; } +/* + * calculate the step value if the hash value is conflicted. + */ +static __inline u_int32_t +calc_collision_step(u_int32_t hashval, u_int32_t hashsize) +{ + _DIAGASSERT(hashsize>2); + return (hashval % (hashsize - 2)) + 1; +} + +/* + * calculate the next index while conflicting. + */ +static __inline u_int32_t +calc_next_index(u_int32_t curidx, u_int32_t hashsize, u_int32_t step) +{ + return curidx+step - (curidx >= hashsize-step ? hashsize : 0); +} + /* ARGSUSED */ static const char * lookup_hash(msgid, db) const char *msgid; struct domainbinding *db; { + struct mohandle *mohandle = &db->mohandle; + u_int32_t idx, hashval, step, strno; + size_t len; - /* - * XXX should try a hashed lookup here, but to do so, we need to - * look inside the GPL'ed *.c and re-implement... - */ - return NULL; + if (mohandle->mo.mo_hsize <= 2 || mohandle->mo.mo_htable == NULL) + return NULL; + + hashval = __intl_string_hash(msgid); + step = calc_collision_step(hashval, mohandle->mo.mo_hsize); + idx = hashval % mohandle->mo.mo_hsize; + len = strlen(msgid); + while (/*CONSTCOND*/1) { + strno = mohandle->mo.mo_htable[idx]; + if (strno == 0) { + /* unexpected miss */ + return NULL; + } + strno--; + if (len <= mohandle->mo.mo_otable[strno].len && + !strcmp(msgid, mohandle->mo.mo_otable[strno].off)) { + /* hit */ + return mohandle->mo.mo_ttable[strno].off; + } + idx = calc_next_index(idx, mohandle->mo.mo_hsize, step); + } + /*NOTREACHED*/ } static const char * @@ -576,7 +651,7 @@ dcngettext(domainname, msgid1, msgid2, n, category) lpath = get_lang_env(cname); if (!lpath) goto fail; - + for (db = __bindings; db; db = db->next) if (strcmp(db->domainname, domainname) == 0) break; @@ -650,6 +725,5 @@ found: } fail: - /* LINTED const cast */ - return (char *)msgid; + return (char *)__UNCONST(msgid); } diff --git a/lib/libintl/libintl_local.h b/lib/libintl/libintl_local.h index 239b00687ef1..0325f2dbd498 100644 --- a/lib/libintl/libintl_local.h +++ b/lib/libintl/libintl_local.h @@ -1,4 +1,4 @@ -/* $NetBSD: libintl_local.h,v 1.7 2004/01/18 08:40:40 yamt Exp $ */ +/* $NetBSD: libintl_local.h,v 1.8 2004/09/23 16:44:26 tshiozak Exp $ */ /*- * Copyright (c) 2000, 2001 Citrus Project, @@ -30,7 +30,9 @@ #define MO_MAGIC 0x950412de #define MO_MAGIC_SWAPPED 0xde120495 -#define MO_REVISION 0 +#define MO_GET_REV_MAJOR(r) (((r) >> 16) & 0xFFFF) +#define MO_GET_REV_MINOR(r) ((r) & 0xFFFF) +#define MO_MAKE_REV(maj, min) (((maj) << 16) | (min)) #define GETTEXT_MMAP_MAX (1024 * 1024) /*XXX*/ @@ -45,6 +47,13 @@ struct mo { u_int32_t mo_ttable; /* T: translated text table offset */ u_int32_t mo_hsize; /* S: size of hashing table */ u_int32_t mo_hoffset; /* H: offset of hashing table */ + /* rev 0.1 / 1.1 */ + /* system dependent string support */ + u_int32_t mo_sysdep_nsegs; /* number of sysdep segments */ + u_int32_t mo_sysdep_segoff; /* offset of sysdep segment table */ + u_int32_t mo_sysdep_nstring; /* number of strings */ + u_int32_t mo_sysdep_otable; /* offset of original text table */ + u_int32_t mo_sysdep_ttable; /* offset of translated text table */ } __attribute__((__packed__)); struct moentry { @@ -52,6 +61,12 @@ struct moentry { u_int32_t off; /* offset of \0-terminated string */ } __attribute__((__packed__)); +struct mosysdepstr +{ + u_int32_t off; /* offset of seed text */ + struct moentry segs[1]; /* text segments */ +} __attribute__((__packed__)); + /* libintl internal data format */ struct moentry_h { size_t len; /* strlen(str), so region will be len + 1 */ @@ -66,6 +81,8 @@ struct mo_h { struct moentry_h *mo_ttable; /* T: translated text table offset */ const char *mo_header; char *mo_charset; + u_int32_t mo_hsize; /* S: size of hashing table */ + u_int32_t *mo_htable; /* H: hashing table */ }; struct mohandle { @@ -85,4 +102,7 @@ struct domainbinding { extern struct domainbinding *__bindings; extern char __current_domainname[PATH_MAX]; +__BEGIN_DECLS const char *__gettext_iconv __P((const char *, struct domainbinding *)); +u_int32_t __intl_string_hash __P((const char *)); +__END_DECLS diff --git a/lib/libintl/strhash.c b/lib/libintl/strhash.c new file mode 100644 index 000000000000..4427d6036442 --- /dev/null +++ b/lib/libintl/strhash.c @@ -0,0 +1,63 @@ +/* $NetBSD: strhash.c,v 1.1 2004/09/23 16:44:26 tshiozak Exp $ */ + +/*- + * Copyright (c)2003, 2004 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: strhash.c,v 1.1 2004/09/23 16:44:26 tshiozak Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include + +#include "libintl_local.h" + +/* + * string hash function by P.J.Weinberger. + * this implementation is derived from src/lib/libc/citrus/citrus_db_hash.c. + */ +u_int32_t +/*ARGSUSED*/ +__intl_string_hash(const char *str) +{ + const u_int8_t *p; + u_int32_t hash = 0, tmp; + + for (p = (const u_int8_t *)str; *p; p++) { + hash <<= 4; + hash += *p; + tmp = hash & 0xF0000000; + if (tmp != 0) { + hash ^= tmp; + hash ^= tmp >> 24; + } + } + return hash; +} diff --git a/lib/libintl/textdomain.c b/lib/libintl/textdomain.c index 10912bd41a1a..46443f0da7cc 100644 --- a/lib/libintl/textdomain.c +++ b/lib/libintl/textdomain.c @@ -1,4 +1,4 @@ -/* $NetBSD: textdomain.c,v 1.10 2004/01/18 08:40:40 yamt Exp $ */ +/* $NetBSD: textdomain.c,v 1.11 2004/09/23 16:44:26 tshiozak Exp $ */ /*- * Copyright (c) 2000, 2001 Citrus Project, @@ -27,7 +27,7 @@ */ #include -__RCSID("$NetBSD: textdomain.c,v 1.10 2004/01/18 08:40:40 yamt Exp $"); +__RCSID("$NetBSD: textdomain.c,v 1.11 2004/09/23 16:44:26 tshiozak Exp $"); #include @@ -98,7 +98,7 @@ bindtextdomain(domainname, dirname) if (p) return (p->path); else - return _PATH_TEXTDOMAIN; + return (char *)__UNCONST(_PATH_TEXTDOMAIN); } strlcpy(p->path, dirname, sizeof(p->path));