diff options
author | muffin <none@none> | 2008-06-03 15:49:37 -0700 |
---|---|---|
committer | muffin <none@none> | 2008-06-03 15:49:37 -0700 |
commit | f13ac6397da869bb7b7bc8a9f0b2e8fff530c346 (patch) | |
tree | 52cfac8e709209385b4c2165a48baa129a9862dc /usr/src/lib/libc | |
parent | 44f31f1309f988eeccdb6879c1945d72a2b14258 (diff) | |
download | illumos-gate-f13ac6397da869bb7b7bc8a9f0b2e8fff530c346.tar.gz |
PSARC/2007/634 More compatibility with GNU gettext in gettext(3c)
6570425 gettext(3c) should support GNU gettext mo format version 1.0
Diffstat (limited to 'usr/src/lib/libc')
-rw-r--r-- | usr/src/lib/libc/inc/msgfmt.h | 281 | ||||
-rw-r--r-- | usr/src/lib/libc/port/i18n/gettext.h | 145 | ||||
-rw-r--r-- | usr/src/lib/libc/port/i18n/gettext_gnu.c | 1132 | ||||
-rw-r--r-- | usr/src/lib/libc/port/i18n/gettext_real.c | 679 | ||||
-rw-r--r-- | usr/src/lib/libc/port/i18n/gettext_util.c | 804 | ||||
-rw-r--r-- | usr/src/lib/libc/port/mapfile-vers | 3 |
6 files changed, 1719 insertions, 1325 deletions
diff --git a/usr/src/lib/libc/inc/msgfmt.h b/usr/src/lib/libc/inc/msgfmt.h index 4792884879..7618e05eac 100644 --- a/usr/src/lib/libc/inc/msgfmt.h +++ b/usr/src/lib/libc/inc/msgfmt.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 1998, 2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _MSGFMT_H @@ -29,6 +28,9 @@ #pragma ident "%Z%%M% %I% %E% SMI" +#include <stdint.h> +#include <stddef.h> + #ifdef __cplusplus extern "C" { #endif @@ -120,46 +122,49 @@ struct msg_struct { /* * * +-----------------------------------------+ - * 0 | (unsigned int) magic number | + * 0 | (uint32_t) magic number | * +-----------------------------------------+ - * 4 | (unsigned int) format revision | + * 4 | (uint32_t) format revision | * +-----------------------------------------+ - * 8 | (unsigned int) number of strings | == N + * 8 | (uint32_t) number of strings | == N * +-----------------------------------------+ - * 12 | (unsigned int) offset of msgid table | == O + * 12 | (uint32_t) offset of msgid table | == O * +-----------------------------------------+ - * 16 | (unsigned int) offset of msgstr table | == T + * 16 | (uint32_t) offset of msgstr table | == T * +-----------------------------------------+ - * 20 | (unsigned int) size of hashing table | == S + * 20 | (uint32_t) size of hashing table | == S * +-----------------------------------------+ - * 24 | (unsigned int) offset of hashing table | == H + * 24 | (uint32_t) offset of hashing table | == H * +-----------------------------------------+ * +-----------------------------------------+ - * O | (unsigned int) length of 0th msgid | + * O | (uint32_t) length of 0th msgid | * +-----------------------------------------+ - * O+4 | (unsigned int) offset of 0th msgid | == M(0) + * O+4 | (uint32_t) offset of 0th msgid | == M(0) * +-----------------------------------------+ * ............................... * +-----------------------------------------+ - * O+((N-1)*8) | (unsigned int) length of (N-1)th msgid | + * O+((N-1)*8) | (uint32_t) length of (N-1)th msgid | * +-----------------------------------------+ - * O+((N-1)*8) | (unsigned int) offset of (N-1)th msgid | == M(N-1) + * O+((N-1)*8) | (uint32_t) offset of (N-1)th msgid | == M(N-1) * +4 +-----------------------------------------+ - * T | (unsigned int) length of 0th msgstr | * +-----------------------------------------+ - * T+4 | (unsigned int) offset of 0th msgstr | == Q(0) + * T | (uint32_t) length of 0th msgstr | + * +-----------------------------------------+ + * T+4 | (uint32_t) offset of 0th msgstr | == Q(0) * +-----------------------------------------+ * ............................... * +-----------------------------------------+ - * T+((N-1)*8) | (unsigned int) length of (N-1)th msgstr | + * T+((N-1)*8) | (uint32_t) length of (N-1)th msgstr | * +-----------------------------------------+ - * T+((N-1)*8) | (unsigned int) offset of (N-1)th msgstr | == Q(N-1) + * T+((N-1)*8) | (uint32_t) offset of (N-1)th msgstr | == Q(N-1) * +4 +-----------------------------------------+ - * H | (unsigned int) start hashing table | + * +-----------------------------------------+ + * H | (uint32_t) start hashing table | * +-----------------------------------------+ * ............................... * +-----------------------------------------+ - * H + S * 4 | (unsigned int) end hashing table | + * H + S * 4 | (uint32_t) end hashing table | + * +-----------------------------------------+ * +-----------------------------------------+ * M(0) | NULL terminated 0th msgid string | * +-----------------------------------------+ @@ -169,6 +174,7 @@ struct msg_struct { * +-----------------------------------------+ * M(N-1) | NULL terminated (N-1)th msgid string | * +-----------------------------------------+ + * +-----------------------------------------+ * Q(0) | NULL terminated 0th msgstr string | * +-----------------------------------------+ * Q(1) | NULL terminated 1st msgstr string | @@ -179,24 +185,229 @@ struct msg_struct { * +-----------------------------------------+ */ -#define GNU_MAGIC 0x950412de -#define GNU_MAGIC_SWAPPED 0xde120495 -#define GNU_REVISION 0 -#define GNU_REVISION_SWAPPED 0 +/* + * GNU MO file format (Revision 1) + */ +/* + * + * +-----------------------------------------------+ + * 0 | (uint32_t) magic number | + * +-----------------------------------------------+ + * 4 | (uint32_t) format revision | + * +-----------------------------------------------+ + * 8 | (uint32_t) number of strings | == N + * +-----------------------------------------------+ + * 12 | (uint32_t) offset of msgid table | == O + * +-----------------------------------------------+ + * 16 | (uint32_t) offset of msgstr table | == T + * +-----------------------------------------------+ + * 20 | (uint32_t) size of hashing table | == S + * +-----------------------------------------------+ + * 24 | (uint32_t) offset of hashing table | == H + * +-----------------------------------------------+ + * 32 | (uint32_t) number of dynamic macros | == M + * +-----------------------------------------------+ + * 36 | (uint32_t) offset of dynamic macros | == P + * +-----------------------------------------------+ + * 40 | (uint32_t) number of dynamic strings | == D + * +-----------------------------------------------+ + * 44 | (uint32_t) offset of dynamic msgid tbl | == A + * +-----------------------------------------------+ + * 48 | (uint32_t) offset of dynamic msgstr tbl | == B + * +-----------------------------------------------+ + * +-----------------------------------------------+ + * O | (uint32_t) length of 0th msgid | + * +-----------------------------------------------+ + * O+4 | (uint32_t) offset of 0th msgid | == M(0) + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * O+((N-1)*8) | (uint32_t) length of (N-1)th msgid | + * +-----------------------------------------------+ + * O+((N-1)*8) | (uint32_t) offset of (N-1)th msgid | == M(N-1) + * +4 +-----------------------------------------------+ + * +-----------------------------------------------+ + * T | (uint32_t) length of 0th msgstr | + * +-----------------------------------------------+ + * T+4 | (uint32_t) offset of 0th msgstr | == Q(0) + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * T+((N-1)*8) | (uint32_t) length of (N-1)th msgstr | + * +-----------------------------------------------+ + * T+((N-1)*8) | (uint32_t) offset of (N-1)th msgstr | == Q(N-1) + * +4 +-----------------------------------------------+ + * +-----------------------------------------------+ + * H | (uint32_t) start hashing table | + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * H + S * 4 | (uint32_t) end hashing table | + * +-----------------------------------------------+ + * +-----------------------------------------------+ + * P | (uint32_t) length of 0th macro | + * +-----------------------------------------------+ + * P+4 | (uint32_t) offset of 0th macro | == C(0) + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * P+((M-1)*8) | (uint32_t) length of (M-1)th macro | + * +-----------------------------------------------+ + * P+((M-1)*8) | (uint32_t) offset of (M-1)th macro | == C(M-1) + * +4 +-----------------------------------------------+ + * +-----------------------------------------------+ + * A | (uint32_t) offset of 0th d_msgid | == L(0) + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * A+((D-1)*4) | (uint32_t) offset of (D-1)th d_msgid | == L(D-1) + * +-----------------------------------------------+ + * +-----------------------------------------------+ + * B | (uint32_t) offset of 0th d_msgstr | == E(0) + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * B+((D-1)*4) | (uint32_t) offset of (D-1)th d_msgstr | == E(D-1) + * +-----------------------------------------------+ + * +-----------------------------------------------+ + * L(0) | (uint32_t) offset of 0th d_msgid message | == F(0) + * +-----------------------------------------------+ + * L(0)+4 | (uint32_t) length of 0th fixed substring | + * +-----------------------------------------------+ + * L(0)+8 | (uint32_t) index to a dynamic macro | + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * L(0)+4+ | (uint32_t) length of (m-1)th fixed substring | + * ((m-1)*8) +-----------------------------------------------+ + * L(0)+8+ | (uint32_t) NOMORE_DYNAMIC_STR | + * ((m-1)*8) +-----------------------------------------------+ + * +-----------------------------------------------+ + * L(D-1) | (uint32_t) offset of 0th d_msgid message | == F(D-1) + * +-----------------------------------------------+ + * L(D-1)+4 | (uint32_t) length of 0th fixed substring | + * +-----------------------------------------------+ + * L(D-1)+8 | (uint32_t) index to a dynamic macro | + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * L(D-1)+4 | (uint32_t) length of (m-1)th fixed substring | + * ((m-1)*8) +-----------------------------------------------+ + * L(D-1)+8 | (uint32_t) NOMORE_DYNAMIC_STR | + * ((m-1)*8) +-----------------------------------------------+ + * +-----------------------------------------------+ + * E(0) | (uint32_t) offset of 0th d_msgstr message | == G(0) + * +-----------------------------------------------+ + * E(0)+4 | (uint32_t) length of 0th fixed substring | + * +-----------------------------------------------+ + * E(0)+8 | (uint32_t) index to a dynamic macro | + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * E(0)+4+ | (uint32_t) length of (m-1)th fixed substring | + * ((m-1)*8) +-----------------------------------------------+ + * E(0)+8+ | (uint32_t) NOMORE_DYNAMIC_STR | + * ((m-1)*8) +-----------------------------------------------+ + * +-----------------------------------------------+ + * E(D-1) | (uint32_t) offset of 0th d_msgstr message | == G(D-1) + * +-----------------------------------------------+ + * E(D-1)+4 | (uint32_t) length of 0th fixed substring | + * +-----------------------------------------------+ + * E(D-1)+8 | (uint32_t) index to a dynamic macro | + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * E(D-1)+4 | (uint32_t) length of (m-1)th fixed substring | + * ((m-1)*8) +-----------------------------------------------+ + * E(D-1)+8 | (uint32_t) NOMORE_DYNAMIC_STR | + * ((m-1)*8) +-----------------------------------------------+ + * +-----------------------------------------------+ + * M(0) | NULL terminated 0th msgid string | + * +-----------------------------------------------+ + * M(1) | NULL terminated 1st msgid string | + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * M(N-1) | NULL terminated (N-1)th msgid string | + * +-----------------------------------------------+ + * Q(0) | NULL terminated 0th msgstr string | + * +-----------------------------------------------+ + * Q(1) | NULL terminated 1st msgstr string | + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * Q(N-1) | NULL terminated (N-1)th msgstr string | + * +-----------------------------------------------+ + * +-----------------------------------------------+ + * C(0) | NULL terminated 0th macro | + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * C(M-1) | NULL terminated (M-1)th macro | + * +-----------------------------------------------+ + * +-----------------------------------------------+ + * F(0) | NULL terminated 0th dynamic msgid string | + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * F(D-1) | NULL terminated (D-1)th dynamic msgid string | + * +-----------------------------------------------+ + * +-----------------------------------------------+ + * G(0) | NULL terminated 0th dynamic msgstr string | + * +-----------------------------------------------+ + * ............................... + * +-----------------------------------------------+ + * G(D-1) | NULL terminated (D-1)th dynamic msgstr string | + * +-----------------------------------------------+ + */ + +#define GNU_MAGIC 0x950412de +#define GNU_MAGIC_SWAPPED 0xde120495 +#define GNU_REVISION 0 +#define GNU_REVISION_0_0 0 +#define GNU_REVISION_0_0_SWAPPED 0 +#define GNU_REVISION_0_1 0x00000001 +#define GNU_REVISION_0_1_SWAPPED 0x01000000 +#define GNU_REVISION_1_1 0x00010001 +#define GNU_REVISION_1_1_SWAPPED 0x01000100 +#define NOMORE_DYNAMIC_MACRO 0xffffffff + +enum gnu_msgidstr { + MSGID = 0, + MSGSTR = 1 +}; struct gnu_msg_info { - unsigned int magic; - unsigned int revision; - unsigned int num_of_str; - unsigned int off_msgid_tbl; - unsigned int off_msgstr_tbl; - unsigned int sz_hashtbl; - unsigned int off_hashtbl; + uint32_t magic; + uint32_t revision; + uint32_t num_of_str; + uint32_t off_msgid_tbl; + uint32_t off_msgstr_tbl; + uint32_t sz_hashtbl; + uint32_t off_hashtbl; +}; + +struct gnu_msg_rev1_info { + uint32_t num_of_dynamic_macro; + uint32_t off_dynamic_macro; + uint32_t num_of_dynamic_str; + uint32_t off_dynamic_msgid_tbl; + uint32_t off_dynamic_msgstr_tbl; }; struct gnu_msg_ent { - unsigned int len; - unsigned int offset; + uint32_t len; + uint32_t offset; +}; + +struct gnu_dynamic_ent { + uint32_t len; + uint32_t idx; +}; + +struct gnu_dynamic_tbl { + uint32_t offset; + struct gnu_dynamic_ent entry[1]; }; #ifdef __cplusplus diff --git a/usr/src/lib/libc/port/i18n/gettext.h b/usr/src/lib/libc/port/i18n/gettext.h index 181b007ad9..bbfdf66ade 100644 --- a/usr/src/lib/libc/port/i18n/gettext.h +++ b/usr/src/lib/libc/port/i18n/gettext.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -38,10 +38,14 @@ extern "C" { #endif /* Type of MO file */ -#define T_SUN_MO 0x1 -#define T_GNU_MO 0x2 -#define T_GNU_SWAPPED_MO 0x4 -#define T_ILL_MO 0x8 +#define T_MO_MASK 0x07 +#define T_SUN_MO 0x01 +#define T_GNU_MO 0x02 +#define T_ILL_MO 0x04 + +#define T_GNU_MASK 0x300 +#define T_GNU_SWAPPED 0x100 +#define T_GNU_REV1 0x200 #define TP_BINDING 0 #define TP_CODESET 1 @@ -49,6 +53,15 @@ extern "C" { /* Msg_g_node->flag */ #define ST_CHK 0x1 /* header has been checked? */ #define ST_SWP 0x2 /* reversed endian? */ +#define ST_REV1 0x4 /* Revision 1 */ + +/* + * msg_pack->status: + * interaction between handle_lang() and handle_mo() + */ +#define ST_GNU_MSG_FOUND 0x1 /* valid msg found in GNU MO */ +#define ST_GNU_MO_FOUND 0x2 /* GNU MO found */ +#define ST_SUN_MO_FOUND 0x4 /* Sun MO found */ typedef struct domain_binding { char *domain; /* domain name */ @@ -63,6 +76,7 @@ typedef struct domain_binding { */ typedef struct nlstmp { char pathname[MAXPATHLEN]; /* the full pathname to file */ + size_t len; /* length of pathname */ struct nlstmp *next; /* link to the next entry */ } Nlstmp; @@ -76,21 +90,35 @@ typedef struct { typedef struct expr *plural_expr_t; typedef struct { - struct gnu_msg_info *msg_file_info; /* information of msg file */ - unsigned int *hash_table; /* hash table */ + unsigned int len; /* length of the expanded str of macro */ + const char *ptr; /* pointer to the expanded str of macro */ +} gnu_d_macro_t; + +typedef struct { + struct gnu_msg_info *msg_file_info; + struct gnu_msg_rev1_info *rev1_header; + size_t fsize; /* size of the GNU mo file */ + uint32_t flag; /* status */ + uint32_t num_of_str; /* number of static msgs */ + uint32_t num_of_d_str; /* number of dynamic msgs */ + uint32_t hash_size; /* hash table size */ + uint32_t *hash_table; /* hash table */ + struct gnu_msg_ent *msg_tbl[2]; /* msgid/str entries */ + struct gnu_msg_ent *d_msg[2]; /* dynamic msgid/str entries */ + char *mchunk; /* pointer to memory chunk of dynamic strs */ char *src_encoding; /* src encoding */ char *dst_encoding; /* dst encoding */ - int flag; /* status */ - int nplurals; /* number of plural forms */ - plural_expr_t plural; /* plural expression */ - iconv_t fd; /* iconv descriptor */ - char **conv_msgstr; /* code-converted msgstr */ + unsigned int nplurals; /* number of plural forms */ + plural_expr_t plural; /* plural expression */ + iconv_t fd; /* iconv descriptor */ + uint32_t **conv_msgstr; /* code-converted msgstr */ } Msg_g_node; typedef struct msg_node { - int type; /* T_SUN_MO, T_GNU_MO, or T_ILL_MO */ - int trusted; /* is this a trusted source? */ - char *path; /* name of message catalog */ + uint32_t hashid; /* hashed value of the domain name */ + uint16_t type; /* T_SUN_MO, T_GNU_MO, or T_ILL_MO */ + uint16_t trusted; /* is this a trusted source? */ + char *path; /* name of message catalog */ union { Msg_s_node *sunmsg; Msg_g_node *gnumsg; @@ -106,20 +134,11 @@ typedef struct nls_node { struct nls_node *next; /* link to the next */ } Nls_node; -typedef struct cache_node { - unsigned int hashid; /* hashed valued for the locale name */ - Msg_node *m_node; /* link to Msg_node */ - Msg_node *m_last; /* link to the last Msg_node */ - Nls_node *n_node; /* link to Nls_node */ - Nls_node *n_last; /* link to the last Nls_node */ - struct cache_node *next; /* link to the next */ -} Cache_node; - typedef struct { char *cur_domain; /* current domain */ Dbinding *dbind; /* domain binding */ - Cache_node *c_node; /* link to the cache node */ - Cache_node *c_last; /* link to the last cache node */ + Msg_node *m_node; /* link to the Msg_node cache */ + Nls_node *n_node; /* link to the Nls_node cache */ Msg_node *c_m_node; /* link to the current Msg_node */ Nls_node *c_n_node; /* link to the current Nls_node */ } Gettext_t; @@ -134,27 +153,17 @@ struct msg_pack { char *language; /* LANGUAGE env */ caddr_t addr; /* mmap'ed address */ size_t fsz; /* file size */ - size_t msgfile_len; /* length of msgfile */ - size_t domain_len; /* length of domain */ - size_t locale_len; /* length of locale */ - + uint32_t hash_domain; /* hash ID of domain */ + uint32_t domain_len; /* length of domain */ unsigned int n; /* n argument */ - int category; /* category argument */ - int plural; /* plural or not */ - unsigned int hash_locale; /* hash ID of locale */ - int nlsp; /* nlsp */ - int trusted; /* trusted msg catalog or not */ -}; - -struct cache_pack { - int cacheline; - Msg_node *mnp; - Cache_node *cnp; - Cache_node *node_hash; + int category; /* category argument */ + int plural; /* plural or not */ + int nlsp; /* nlsp */ + int trusted; /* trusted msg catalog or not */ + int status; /* status */ }; #define DEFAULT_DOMAIN "messages" -#define DEFAULT_DOMAIN_LEN (sizeof (DEFAULT_DOMAIN) - 1) #define DEFAULT_BINDING _DFLT_LOC_PATH #define MSGFILESUFFIX ".mo" #define MSGFILESUFFIXLEN (sizeof (MSGFILESUFFIX) - 1) @@ -167,47 +176,49 @@ struct cache_pack { ((n == 1) ? (char *)msgid1 : (char *)msgid2) : \ (char *)msgid1) +#define ROUND(m, s) if ((m) % (s)) (m) += ((s) - ((m) % (s))) + #define SWAP(p, ui32) \ (((p)->flag & ST_SWP) ? doswap32(ui32) : (ui32)) +#define HASH_TBL(p, ui32) \ + ((((p)->flag & (ST_REV1|ST_SWP)) == ST_SWP) ? \ + doswap32(ui32) : (ui32)) + extern const char *defaultbind; extern const char default_domain[]; extern Gettext_t *global_gt; -extern char *_textdomain_u(const char *, char *); -extern char *_real_bindtextdomain_u(const char *, const char *, int); -extern char *_real_gettext_u(const char *, const char *, - const char *, unsigned long int, int, int); - -extern int setmsg(Msg_node *, char *, size_t); -extern char *handle_lang(struct cache_pack *, struct msg_pack *); -extern char *mk_msgfile(struct msg_pack *); -extern int check_cache(struct cache_pack *, struct msg_pack *); -extern void connect_entry(struct cache_pack *); -extern int connect_invalid_entry(struct cache_pack *, struct msg_pack *); -extern Msg_node *create_mnp(struct msg_pack *); -extern Cache_node *create_cnp(Msg_node *, struct msg_pack *); -extern void free_mnp_mp(Msg_node *, struct msg_pack *); -extern unsigned int get_hashid(const char *, size_t *); -extern unsigned int doswap32(unsigned int); +extern char *_textdomain_u(const char *, char *); +extern char *_real_bindtextdomain_u(const char *, const char *, int); +extern char *_real_gettext_u(const char *, const char *, + const char *, unsigned long int, int, int); +extern char *handle_mo(struct msg_pack *); + +extern int gnu_setmsg(Msg_node *, char *, size_t); +extern char *handle_lang(struct msg_pack *); +extern char *mk_msgfile(struct msg_pack *); +extern Msg_node *check_cache(struct msg_pack *); +extern uint32_t get_hashid(const char *, uint32_t *); +extern uint32_t doswap32(uint32_t); extern int plural_expr(plural_expr_t *, const char *); extern unsigned int plural_eval(plural_expr_t, unsigned int); -extern char *gnu_key_2_text(Msg_g_node *, const char *, - struct msg_pack *); +extern char *gnu_key_2_text(Msg_g_node *, const char *, struct msg_pack *); -extern char *get_codeset(const char *); +extern char *get_codeset(const char *); #ifdef GETTEXT_DEBUG +extern void gprintf(int, const char *, ...); +extern void printgt(Gettext_t *, int); extern void printmp(struct msg_pack *, int); extern void printsunmsg(Msg_s_node *, int); extern void printgnumsg(Msg_g_node *, int); extern void printexpr(plural_expr_t, int); extern void printmnp(Msg_node *, int); -extern void printcnp(Cache_node *, int); -extern void printcp(struct cache_pack *, int); extern void printlist(void); +extern void print_rev1_info(Msg_g_node *); #endif #ifdef __cplusplus diff --git a/usr/src/lib/libc/port/i18n/gettext_gnu.c b/usr/src/lib/libc/port/i18n/gettext_gnu.c index b4a2424068..89be4bdd25 100644 --- a/usr/src/lib/libc/port/i18n/gettext_gnu.c +++ b/usr/src/lib/libc/port/i18n/gettext_gnu.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -41,6 +41,7 @@ #include <unistd.h> #include <limits.h> #include <errno.h> +#include <inttypes.h> #include "libc.h" #include "msgfmt.h" #include "nlspath_checks.h" @@ -50,6 +51,10 @@ #include <assert.h> #endif +/* The following symbols are just for GNU binary compatibility */ +int _nl_msg_cat_cntr; +int *_nl_domain_bindings; + static const char *nullstr = ""; #define CHARSET_MOD "charset=" @@ -59,32 +64,39 @@ static const char *nullstr = ""; #define PLURAL_MOD "plural=" #define PLURAL_LEN (sizeof (PLURAL_MOD) - 1) +static uint32_t get_hash_index(uint32_t *, uint32_t, uint32_t); + /* * free_conv_msgstr * * release the memory allocated for storing code-converted messages + * + * f + * 0: do not free gmnp->conv_msgstr + * 1: free gmnp->conv_msgstr */ static void -free_conv_msgstr(Msg_g_node *gmnp) +free_conv_msgstr(Msg_g_node *gmnp, int f) { - int i; - unsigned int num_of_str; + uint32_t i, num_of_conv; #ifdef GETTEXT_DEBUG - (void) printf("*************** free_conv_msgstr(0x%p)\n", - (void *)gmnp); - printgnumsg(gmnp, 0); + gprintf(0, "*************** free_conv_msgstr(0x%p, %d)\n", + (void *)gmnp, f); + printgnumsg(gmnp, 1); #endif - num_of_str = SWAP(gmnp, gmnp->msg_file_info->num_of_str); - for (i = 0; i < num_of_str; i++) { + num_of_conv = gmnp->num_of_str + gmnp->num_of_d_str; + for (i = 0; i < num_of_conv; i++) { if (gmnp->conv_msgstr[i]) { free(gmnp->conv_msgstr[i]); } + gmnp->conv_msgstr[i] = NULL; + } + if (f) { + free(gmnp->conv_msgstr); + gmnp->conv_msgstr = NULL; } - free(gmnp->conv_msgstr); - gmnp->conv_msgstr = NULL; - } /* @@ -94,19 +106,19 @@ free_conv_msgstr(Msg_g_node *gmnp) * and return it. */ static char * -dfltmsgstr(Msg_g_node *gmnp, const char *msgstr, size_t msgstr_len, - struct msg_pack *mp) +dfltmsgstr(Msg_g_node *gmnp, const char *msgstr, uint32_t msgstr_len, + struct msg_pack *mp) { unsigned int pindex; size_t len; const char *p; #ifdef GETTEXT_DEBUG - (void) printf("*************** dfltmsgstr(0x%p, \"%s\", %d, 0x%p)\n", - (void *)gmnp, - msgstr ? msgstr : "(null)", msgstr_len, (void *)mp); - printgnumsg(gmnp, 0); - printmp(mp, 0); + gprintf(0, "*************** dfltmsgstr(0x%p, \"%s\", %u, 0x%p)\n", + (void *)gmnp, + msgstr ? msgstr : "(null)", msgstr_len, (void *)mp); + printgnumsg(gmnp, 1); + printmp(mp, 1); #endif if (mp->plural) { @@ -123,7 +135,7 @@ dfltmsgstr(Msg_g_node *gmnp, const char *msgstr, size_t msgstr_len, pindex = 1; } #ifdef GETTEXT_DEBUG - (void) printf("plural_eval returned: %d\n", pindex); + gprintf(0, "plural_eval returned: %u\n", pindex); #endif if (pindex >= gmnp->nplurals) { /* should never happen */ @@ -133,14 +145,14 @@ dfltmsgstr(Msg_g_node *gmnp, const char *msgstr, size_t msgstr_len, for (; pindex != 0; pindex--) { len = msgstr_len - (p - msgstr); p = memchr(p, '\0', len); - if (!p) { + if (p == NULL) { /* * null byte not found * this should never happen */ char *result; DFLTMSG(result, mp->msgid1, mp->msgid2, - mp->n, mp->plural); + mp->n, mp->plural); return (result); } p++; /* skip */ @@ -170,37 +182,37 @@ parse_header(const char *header, Msg_g_node *gmnp) int ret; #ifdef GETTEXT_DEBUG - (void) printf("*************** parse_header(\"%s\", 0x%p)\n", - header ? header : "(null)", (void *)gmnp); - printgnumsg(gmnp, 0); + gprintf(0, "*************** parse_header(\"%s\", 0x%p)\n", + header ? header : "(null)", (void *)gmnp); + printgnumsg(gmnp, 1); #endif - if (!header) { + if (header == NULL) { gmnp->src_encoding = (char *)nullstr; gmnp->nplurals = 2; gmnp->plural = NULL; #ifdef GETTEXT_DEBUG - (void) printf("*************** exiting parse_header\n"); - (void) printf("no header\n"); + gprintf(0, "*************** exiting parse_header\n"); + gprintf(0, "no header\n"); #endif return (0); } charset_str = strstr(header, CHARSET_MOD); - if (!charset_str) { + if (charset_str == NULL) { gmnp->src_encoding = (char *)nullstr; } else { p = charset_str + CHARSET_LEN; q = p; while ((*q != ' ') && (*q != '\t') && - (*q != '\n')) { + (*q != '\n')) { q++; } len = q - p; if (len > 0) { - charset = (char *)malloc(len + 1); - if (!charset) { + charset = malloc(len + 1); + if (charset == NULL) { gmnp->src_encoding = (char *)nullstr; gmnp->nplurals = 2; gmnp->plural = NULL; @@ -216,13 +228,13 @@ parse_header(const char *header, Msg_g_node *gmnp) nplurals_str = strstr(header, NPLURALS_MOD); plural_str = strstr(header, PLURAL_MOD); - if (!nplurals_str || !plural_str) { + if (nplurals_str == NULL || plural_str == NULL) { /* no valid plural specification */ gmnp->nplurals = 2; gmnp->plural = NULL; #ifdef GETTEXT_DEBUG - (void) printf("*************** exiting parse_header\n"); - (void) printf("no plural entry\n"); + gprintf(0, "*************** exiting parse_header\n"); + gprintf(0, "no plural entry\n"); #endif return (0); } else { @@ -239,7 +251,7 @@ parse_header(const char *header, Msg_g_node *gmnp) p = plural_str + PLURAL_LEN; #ifdef GETTEXT_DEBUG - (void) printf("plural_str: \"%s\"\n", p); + gprintf(0, "plural_str: \"%s\"\n", p); #endif ret = plural_expr(&plural, (const char *)p); @@ -247,10 +259,10 @@ parse_header(const char *header, Msg_g_node *gmnp) /* parse succeeded */ gmnp->plural = plural; #ifdef GETTEXT_DEBUG - (void) printf("*************** exiting parse_header\n"); - (void) printf("charset: \"%s\"\n", - charset ? charset : "(null)"); - printexpr(plural, 0); + gprintf(0, "*************** exiting parse_header\n"); + gprintf(0, "charset: \"%s\"\n", + charset ? charset : "(null)"); + printexpr(plural, 1); #endif return (0); } else if (ret == 1) { @@ -271,58 +283,23 @@ parse_header(const char *header, Msg_g_node *gmnp) /* NOTREACHED */ } -static char * -handle_gnu_mo(struct cache_pack *cp, struct msg_pack *mp, - Gettext_t *gt) -{ - char *result; - char *codeset = get_codeset(mp->domain); - - result = gnu_key_2_text(cp->mnp->msg.gnumsg, codeset, mp); - if (mp->plural) { - if (((result == mp->msgid1) && (mp->n == 1)) || - ((result == mp->msgid2) && (mp->n != 1))) { - return (NULL); - } - } else { - if (result == mp->msgid1) { - return (NULL); - } - } - gt->c_m_node = cp->mnp; - if (!cp->mnp->trusted) { - result = check_format(mp->msgid1, result, 0); - if (result == mp->msgid1) { - DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, - mp->plural); - } - } - return (result); -} - /* * handle_lang * * take care of the LANGUAGE specification */ char * -handle_lang(struct cache_pack *cp, struct msg_pack *mp) +handle_lang(struct msg_pack *mp) { - Gettext_t *gt = global_gt; - struct stat64 statbuf; const char *p, *op, *q; - char *locale = NULL, *olocale, *result; - unsigned int hash_locale; - size_t locale_len, olocale_len = 0; - int gnu_mo_found = 0; - int fd; - int ret; + size_t locale_len; + char *result; + char locale[MAXPATHLEN]; + #ifdef GETTEXT_DEBUG - (void) printf("*************** handle_lang(0x%p, 0x%p)\n", - (void *)cp, (void *)mp); - printcp(cp, 0); - printmp(mp, 0); + gprintf(0, "*************** handle_lang(0x%p)\n", (void *)mp); + printmp(mp, 1); #endif p = mp->language; @@ -330,36 +307,21 @@ handle_lang(struct cache_pack *cp, struct msg_pack *mp) while (*p) { op = p; q = strchr(p, ':'); - if (!q) { + if (q == NULL) { locale_len = strlen(p); p += locale_len; } else { locale_len = q - p; p += locale_len + 1; } - if ((locale_len >= MAXPATHLEN) || - (locale_len == 0)) { + if (locale_len >= MAXPATHLEN || locale_len == 0) { /* illegal locale name */ continue; } - if (olocale_len < locale_len) { - olocale = locale; - locale = (char *)realloc(locale, locale_len + 1); - if (!locale) { - if (olocale) - free(olocale); - DFLTMSG(result, mp->msgid1, mp->msgid2, - mp->n, mp->plural); - return (result); - } - olocale_len = locale_len; - } (void) memcpy(locale, op, locale_len); locale[locale_len] = '\0'; - hash_locale = get_hashid(locale, NULL); mp->locale = locale; - mp->hash_locale = hash_locale; - mp->locale_len = locale_len; + #ifdef GETTEXT_DEBUG *mp->msgfile = '\0'; #endif @@ -368,121 +330,30 @@ handle_lang(struct cache_pack *cp, struct msg_pack *mp) continue; } - cp->node_hash = NULL; - - ret = check_cache(cp, mp); - if (ret) { - /* - * found in cache - */ - switch (cp->mnp->type) { - case T_ILL_MO: - /* invalid MO */ - continue; - case T_SUN_MO: - /* Solaris MO */ - goto out_loop; - case T_GNU_MO: - /* GNU MO */ - gnu_mo_found = 1; - result = handle_gnu_mo(cp, mp, gt); - if (result) { - free(locale); - return (result); - } - continue; - } - /* NOTREACHED */ - } - /* - * not found in cache - */ - fd = nls_safe_open(mp->msgfile, &statbuf, &mp->trusted, 1); - if ((fd == -1) || (statbuf.st_size > LONG_MAX)) { - if (connect_invalid_entry(cp, mp) == -1) { - DFLTMSG(result, mp->msgid1, mp->msgid2, - mp->n, mp->plural); - free(locale); - return (result); - } - continue; - } - mp->fsz = (size_t)statbuf.st_size; - mp->addr = mmap(0, mp->fsz, PROT_READ, MAP_SHARED, fd, 0); - (void) close(fd); - - if (mp->addr == (caddr_t)-1) { - if (connect_invalid_entry(cp, mp) == -1) { - DFLTMSG(result, mp->msgid1, mp->msgid2, - mp->n, mp->plural); - free(locale); - return (result); - } - continue; - } - - cp->mnp = create_mnp(mp); - if (!cp->mnp) { - free(locale); - free_mnp_mp(cp->mnp, mp); - DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, - mp->plural); - return (result); - } - - if (setmsg(cp->mnp, (char *)mp->addr, mp->fsz) == -1) { - free(locale); - free_mnp_mp(cp->mnp, mp); - DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, - mp->plural); + result = handle_mo(mp); + if (mp->status & ST_GNU_MSG_FOUND) return (result); - } - if (!cp->cacheline) { - cp->cnp = create_cnp(cp->mnp, mp); - if (!cp->cnp) { - free(locale); - free_mnp_mp(cp->mnp, mp); - DFLTMSG(result, mp->msgid1, mp->msgid2, - mp->n, mp->plural); - return (result); - } - } - cp->mnp->trusted = mp->trusted; - connect_entry(cp); - switch (cp->mnp->type) { - case T_ILL_MO: - /* invalid MO */ - continue; - case T_SUN_MO: - /* Solaris MO */ - goto out_loop; - case T_GNU_MO: - /* GNU MO */ - gnu_mo_found = 1; - - result = handle_gnu_mo(cp, mp, gt); - if (result) { - free(locale); - return (result); - } - continue; - } - /* NOTREACHED */ + if (mp->status & ST_SUN_MO_FOUND) + break; } -out_loop: - if (gnu_mo_found) { + /* + * no valid locale found, Sun MO found, or + * GNU MO found but no valid msg found there. + */ + + if (mp->status & ST_GNU_MO_FOUND) { + /* + * GNU MO found but no valid msg found there. + * returning DFLTMSG. + */ DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural); - free(locale); return (result); } - if (locale) - free(locale); return (NULL); } - /* * gnu_msgsearch * @@ -499,45 +370,39 @@ out_loop: */ static char * gnu_msgsearch(Msg_g_node *gmnp, const char *msgid1, - size_t *msgstrlen, unsigned int *midx) + uint32_t *msgstrlen, uint32_t *midx) { - unsigned int *hash_table; + struct gnu_msg_info *header = gmnp->msg_file_info; struct gnu_msg_ent *msgid_tbl, *msgstr_tbl; + uint32_t num_of_str, idx, mlen, msglen; + uint32_t hash_size, hash_val, hash_id, hash_inc, hash_idx; + uint32_t *hash_table; char *base; - struct gnu_msg_info *header = gmnp->msg_file_info; - unsigned int hash_size, hash_val, hash_inc, hash_idx; - unsigned int offset, msglen, idx; - unsigned int num_of_str; - unsigned int off_msgid_tbl, off_msgstr_tbl; - size_t msgid1_len; + char *msg; + +#ifdef GETTEXT_DEBUG + gprintf(0, "*************** gnu_msgsearch(0x%p, \"%s\", " + "0x%p, 0x%p)\n", + (void *)gmnp, msgid1, msgstrlen, midx); + printgnumsg(gmnp, 1); +#endif base = (char *)header; - off_msgid_tbl = SWAP(gmnp, header->off_msgid_tbl); - off_msgstr_tbl = SWAP(gmnp, header->off_msgstr_tbl); - /* LINTED */ - msgid_tbl = (struct gnu_msg_ent *)(base + off_msgid_tbl); - /* LINTED */ - msgstr_tbl = (struct gnu_msg_ent *)(base + off_msgstr_tbl); + msgid_tbl = gmnp->msg_tbl[MSGID]; + msgstr_tbl = gmnp->msg_tbl[MSGSTR]; hash_table = gmnp->hash_table; - hash_size = SWAP(gmnp, header->sz_hashtbl); - num_of_str = SWAP(gmnp, header->num_of_str); - -#ifdef GETTEXT_DEBUG - (void) printf("*************** gnu_msgsearch(" - "0x%p, \"%s\", 0x%p, 0x%p)\n", - (void *)gmnp, - msgid1 ? msgid1 : "(null)", - (void *)msgstrlen, (void *)midx); - printgnumsg(gmnp, 0); -#endif + hash_size = gmnp->hash_size; + num_of_str = gmnp->num_of_str; - if (!hash_table || (hash_size <= 2)) { + if (!(gmnp->flag & ST_REV1) && + (hash_table == NULL || (hash_size <= 2))) { /* + * Revision 0 and * No hash table exists or - * hash size is enough small + * hash size is enough small. */ - unsigned int top, bottom; + uint32_t top, bottom; char *msg_id_str; int val; @@ -546,7 +411,7 @@ gnu_msgsearch(Msg_g_node *gmnp, const char *msgid1, while (top < bottom) { idx = (top + bottom) / 2; msg_id_str = base + - SWAP(gmnp, msgid_tbl[idx].offset); + SWAP(gmnp, msgid_tbl[idx].offset); val = strcmp(msg_id_str, msgid1); if (val < 0) { @@ -554,7 +419,11 @@ gnu_msgsearch(Msg_g_node *gmnp, const char *msgid1, } else if (val > 0) { bottom = idx; } else { - goto found; + *msgstrlen = (unsigned int) + SWAP(gmnp, msgstr_tbl[idx].len) + 1; + *midx = idx; + return (base + + SWAP(gmnp, msgstr_tbl[idx].offset)); } } /* not found */ @@ -562,36 +431,51 @@ gnu_msgsearch(Msg_g_node *gmnp, const char *msgid1, } /* use hash table */ - hash_val = get_hashid(msgid1, &msgid1_len); - msglen = (unsigned int)msgid1_len; - hash_idx = hash_val % hash_size; - hash_inc = 1 + (hash_val % (hash_size - 2)); + hash_id = get_hashid(msgid1, &msglen); + hash_idx = hash_id % hash_size; + hash_inc = 1 + (hash_id % (hash_size - 2)); for (;;) { - offset = SWAP(gmnp, hash_table[hash_idx]); + hash_val = HASH_TBL(gmnp, hash_table[hash_idx]); - if (offset == 0) { + if (hash_val == 0) { + /* not found */ return ((char *)msgid1); } - - idx = offset - 1; - if ((msglen <= SWAP(gmnp, msgid_tbl[idx].len)) && - strcmp(msgid1, base + - SWAP(gmnp, msgid_tbl[idx].offset)) == 0) { + if (hash_val <= num_of_str) { + /* static message */ + idx = hash_val - 1; + mlen = SWAP(gmnp, msgid_tbl[idx].len); + msg = base + SWAP(gmnp, msgid_tbl[idx].offset); + } else { + if (!(gmnp->flag & ST_REV1)) { + /* rev 0 does not have dynamic message */ + return ((char *)msgid1); + } + /* dynamic message */ + idx = hash_val - num_of_str - 1; + mlen = gmnp->d_msg[MSGID][idx].len; + msg = gmnp->mchunk + gmnp->d_msg[MSGID][idx].offset; + } + if (msglen <= mlen && strcmp(msgid1, msg) == 0) { /* found */ - goto found; + break; } - hash_idx = (hash_idx + hash_inc) % hash_size; } - /* NOTREACHED */ -found: - if (msgstrlen) + /* msgstrlen should include a null termination */ + if (hash_val <= num_of_str) { *msgstrlen = SWAP(gmnp, msgstr_tbl[idx].len) + 1; - if (midx) + msg = base + SWAP(gmnp, msgstr_tbl[idx].offset); *midx = idx; - return (base + SWAP(gmnp, msgstr_tbl[idx].offset)); + } else { + *msgstrlen = gmnp->d_msg[MSGSTR][idx].len + 1; + msg = gmnp->mchunk + gmnp->d_msg[MSGSTR][idx].offset; + *midx = idx + num_of_str; + } + + return (msg); } /* @@ -600,55 +484,119 @@ found: * Converts the specified string from the src encoding * to the dst encoding by calling iconv() */ -static size_t -do_conv(iconv_t fd, char **dst, const char *src, size_t srclen) +static uint32_t * +do_conv(iconv_t fd, const char *src, uint32_t srclen) { - size_t oleft, ileft, bufsize, tolen; + uint32_t tolen; + uint32_t *ptr, *optr; + size_t oleft, ileft, bufsize, memincr; char *to, *tptr; #ifdef GETTEXT_DEBUG - (void) printf("*************** do_conv(" - "0x%p, 0x%p, \"%s\", %d)\n", - (void *)fd, (void *)dst, src ? src : "(null)", srclen); + gprintf(0, "*************** do_conv(" + "0x%p, \"%s\", %d)\n", + (void *)fd, src ? src : "(null)", srclen); #endif - bufsize = srclen * 2; + memincr = srclen * 2; + bufsize = memincr; ileft = srclen; oleft = bufsize; - to = (char *)malloc(bufsize); - if (!to) { - return ((size_t)-1); + ptr = malloc(bufsize + sizeof (uint32_t)); + if (ptr == NULL) { + return (NULL); } + to = (char *)(ptr + 1); - for (; ; ) { + for (;;) { tptr = to; errno = 0; #ifdef GETTEXT_DEBUG - (void) printf("******* calling iconv()\n"); + gprintf(0, "******* calling iconv()\n"); #endif - if (iconv(fd, &src, &ileft, &tptr, &oleft) == - (size_t)-1) { + if (iconv(fd, &src, &ileft, &tptr, &oleft) == (size_t)-1) { if (errno == E2BIG) { - char *oto; - oleft += bufsize; - bufsize *= 2; - oto = to; - to = (char *)realloc(oto, bufsize); - if (!to) { - free(oto); - return ((size_t)-1); +#ifdef GETTEXT_DEBUG + gprintf(0, "******* iconv detected E2BIG\n"); + gprintf(0, "old bufsize: %u\n", bufsize); +#endif + + optr = realloc(ptr, + bufsize + memincr + sizeof (uint32_t)); + if (optr == NULL) { + free(ptr); + return (NULL); } + ptr = optr; + to = (char *)(optr + 1); + to += bufsize - oleft; + oleft += memincr; + bufsize += memincr; +#ifdef GETTEXT_DEBUG + gprintf(0, "new bufsize: %u\n", bufsize); +#endif continue; } else { - tolen = bufsize - oleft; + tolen = (uint32_t)(bufsize - oleft); break; } } - tolen = bufsize - oleft; + tolen = (uint32_t)(bufsize - oleft); break; } - *dst = to; - return (tolen); + + if (tolen < bufsize) { + /* shrink the buffer */ + optr = realloc(ptr, tolen + sizeof (uint32_t)); + if (optr == NULL) { + free(ptr); + return (NULL); + } + ptr = optr; + } + *ptr = tolen; + +#ifdef GETTEXT_DEBUG + gprintf(0, "******* exiting do_conv()\n"); + gprintf(0, "tolen: %u\n", *ptr); + gprintf(0, "return: 0x%p\n", ptr); +#endif + return (ptr); +} + +/* + * conv_msg + */ +static char * +conv_msg(Msg_g_node *gmnp, char *msgstr, uint32_t msgstr_len, uint32_t midx, + struct msg_pack *mp) +{ + uint32_t *conv_dst; + size_t num_of_conv, conv_msgstr_len; + char *conv_msgstr, *result; + + if (gmnp->conv_msgstr == NULL) { + num_of_conv = gmnp->num_of_str + gmnp->num_of_d_str; + gmnp->conv_msgstr = + calloc((size_t)num_of_conv, sizeof (uint32_t *)); + if (gmnp->conv_msgstr == NULL) { + /* malloc failed */ + result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); + return (result); + } + } + + conv_dst = do_conv(gmnp->fd, (const char *)msgstr, msgstr_len); + + if (conv_dst == NULL) { + result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); + return (result); + } + conv_msgstr_len = *conv_dst; + gmnp->conv_msgstr[midx] = conv_dst; + conv_msgstr = (char *)(conv_dst + 1); + result = dfltmsgstr(gmnp, conv_msgstr, conv_msgstr_len, mp); + return (result); } /* @@ -658,37 +606,31 @@ do_conv(iconv_t fd, char **dst, const char *src, size_t srclen) */ char * gnu_key_2_text(Msg_g_node *gmnp, const char *codeset, - struct msg_pack *mp) + struct msg_pack *mp) { - char *result, *msgstr; - size_t msgstr_len; - unsigned int midx; - int ret; - char *conv_msgstr, *conv_dst; - size_t *p; - size_t conv_msgstr_len, buflen; + uint32_t msgstr_len, midx; iconv_t fd; - int conversion, new_encoding; - unsigned int num_of_str; + char *result, *msgstr; + int ret, conversion, new_encoding; #ifdef GETTEXT_DEBUG - (void) printf("*************** gnu_key_2_text(" - "0x%p, \"%s\", 0x%p)\n", - (void *)gmnp, codeset ? codeset : "(null)", (void *)mp); - printgnumsg(gmnp, 0); - printmp(mp, 0); + gprintf(0, "*************** gnu_key_2_text(" + "0x%p, \"%s\", 0x%p)\n", + (void *)gmnp, codeset ? codeset : "(null)", (void *)mp); + printgnumsg(gmnp, 1); + printmp(mp, 1); #endif /* first checks if header entry has been processed */ if (!(gmnp->flag & ST_CHK)) { char *msg_header; - msg_header = gnu_msgsearch(gmnp, "", NULL, NULL); + msg_header = gnu_msgsearch(gmnp, "", &msgstr_len, &midx); ret = parse_header((const char *)msg_header, gmnp); if (ret == -1) { /* fatal error */ DFLTMSG(result, mp->msgid1, mp->msgid2, - mp->n, mp->plural); + mp->n, mp->plural); return (result); } gmnp->flag |= ST_CHK; @@ -701,14 +643,14 @@ gnu_key_2_text(Msg_g_node *gmnp, const char *codeset, } #ifdef GETTEXT_DEBUG - printgnumsg(gmnp, 0); + printgnumsg(gmnp, 1); #endif - if (!gmnp->dst_encoding) { + if (gmnp->dst_encoding == NULL) { /* * destination encoding has not been set. */ char *dupcodeset = strdup(codeset); - if (!dupcodeset) { + if (dupcodeset == NULL) { /* strdup failed */ result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); return (result); @@ -734,7 +676,7 @@ gnu_key_2_text(Msg_g_node *gmnp, const char *codeset, gmnp->fd = (iconv_t)-1; } if (gmnp->conv_msgstr) - free_conv_msgstr(gmnp); + free_conv_msgstr(gmnp, 0); conversion = 1; new_encoding = 1; } @@ -747,7 +689,7 @@ gnu_key_2_text(Msg_g_node *gmnp, const char *codeset, * dst encoding and target encoding are the same. */ if (strcmp(gmnp->dst_encoding, gmnp->src_encoding) - == 0) { + == 0) { /* * dst encoding and src encoding are the same. * No conversion required. @@ -768,7 +710,7 @@ gnu_key_2_text(Msg_g_node *gmnp, const char *codeset, */ conversion = 0; } else { - if (!gmnp->conv_msgstr) { + if (gmnp->conv_msgstr == NULL) { /* * memory allocation for * conv_msgstr should @@ -777,7 +719,7 @@ gnu_key_2_text(Msg_g_node *gmnp, const char *codeset, new_encoding = 1; if (gmnp->fd) (void) iconv_close( - gmnp->fd); + gmnp->fd); gmnp->fd = (iconv_t)-1; } } @@ -788,20 +730,22 @@ gnu_key_2_text(Msg_g_node *gmnp, const char *codeset, * It has changed since before. */ char *dupcodeset = strdup(codeset); - if (!dupcodeset) { + if (dupcodeset == NULL) { result = dfltmsgstr(gmnp, msgstr, - msgstr_len, mp); + msgstr_len, mp); return (result); } free(gmnp->dst_encoding); gmnp->dst_encoding = dupcodeset; if (strcmp(gmnp->dst_encoding, gmnp->src_encoding) - == 0) { + == 0) { /* * dst encoding and src encoding are the same. * now, no conversion required. */ conversion = 0; + if (gmnp->conv_msgstr) + free_conv_msgstr(gmnp, 1); } else { /* * dst encoding is different from src encoding. @@ -809,6 +753,8 @@ gnu_key_2_text(Msg_g_node *gmnp, const char *codeset, */ conversion = 1; new_encoding = 1; + if (gmnp->conv_msgstr) + free_conv_msgstr(gmnp, 0); } if (gmnp->fd && (gmnp->fd != (iconv_t)-1)) { @@ -817,8 +763,6 @@ gnu_key_2_text(Msg_g_node *gmnp, const char *codeset, if (gmnp->fd != (iconv_t)-1) { gmnp->fd = (iconv_t)-1; } - if (gmnp->conv_msgstr) - free_conv_msgstr(gmnp); } } @@ -831,47 +775,27 @@ gnu_key_2_text(Msg_g_node *gmnp, const char *codeset, if (new_encoding == 0) { /* dst codeset hasn't been changed since before */ - if (!gmnp->conv_msgstr[midx]) { + uint32_t *cmsg; + uint32_t conv_msgstr_len; + char *conv_msgstr; + + if (gmnp->conv_msgstr[midx] == NULL) { /* this msgstr hasn't been converted yet */ - conv_msgstr_len = do_conv(gmnp->fd, - &conv_dst, (const char *)msgstr, msgstr_len); - if (conv_msgstr_len == (size_t)-1) { - result = dfltmsgstr(gmnp, msgstr, - msgstr_len, mp); - return (result); - } - buflen = (conv_msgstr_len + sizeof (size_t)); - /* allign to sizeof (size_t) */ - if (buflen % sizeof (size_t)) - buflen += (sizeof (size_t) - - (buflen % sizeof (size_t))); - p = (size_t *)malloc(buflen); - if (!p) { - free(conv_dst); - result = dfltmsgstr(gmnp, msgstr, - msgstr_len, mp); - return (result); - } - *p = conv_msgstr_len; - (void) memcpy(p + 1, conv_dst, conv_msgstr_len); - free(conv_dst); - gmnp->conv_msgstr[midx] = (char *)p; - conv_msgstr = (char *)(p + 1); - } else { - /* this msgstr is in the conversion cache */ - /* LINTED */ - size_t *cmsg = (size_t *)gmnp->conv_msgstr[midx]; - conv_msgstr_len = *cmsg; - conv_msgstr = (char *)(cmsg + 1); + result = conv_msg(gmnp, msgstr, msgstr_len, midx, mp); + return (result); } + /* this msgstr is in the conversion cache */ + cmsg = (uint32_t *)(uintptr_t)gmnp->conv_msgstr[midx]; + conv_msgstr_len = *cmsg; + conv_msgstr = (char *)(cmsg + 1); result = dfltmsgstr(gmnp, conv_msgstr, conv_msgstr_len, mp); return (result); } /* new conversion */ #ifdef GETTEXT_DEBUG - (void) printf("******* calling iconv_open()\n"); - (void) printf(" dst: \"%s\", src: \"%s\"\n", - gmnp->dst_encoding, gmnp->src_encoding); + gprintf(0, "******* calling iconv_open()\n"); + gprintf(0, " dst: \"%s\", src: \"%s\"\n", + gmnp->dst_encoding, gmnp->src_encoding); #endif fd = iconv_open(gmnp->dst_encoding, gmnp->src_encoding); gmnp->fd = fd; @@ -883,37 +807,495 @@ gnu_key_2_text(Msg_g_node *gmnp, const char *codeset, result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); return (result); } - num_of_str = SWAP(gmnp, gmnp->msg_file_info->num_of_str); - gmnp->conv_msgstr = (char **)calloc((size_t)num_of_str, - sizeof (char *)); - if (!gmnp->conv_msgstr) { - /* malloc failed */ - result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); - return (result); + result = conv_msg(gmnp, msgstr, msgstr_len, midx, mp); + return (result); +} + + +#define PRI_STR(x, n) PRI##x##n +#define PRI_LEN(x, n) (char)(sizeof (PRI_STR(x, n)) - 1) +#define PRIS(P, x) {\ +/* x/N/ */ P(x, 8), P(x, 16), P(x, 32), P(x, 64), \ +/* xLEAST/N/ */ P(x, LEAST8), P(x, LEAST16), P(x, LEAST32), P(x, LEAST64), \ +/* xFAST/N/ */ P(x, FAST8), P(x, FAST16), P(x, FAST32), P(x, FAST64), \ +/* xMAX,PTR */ P(x, MAX), P(x, PTR) \ +} + +#define PRI_BIAS_LEAST 4 +#define PRI_BIAS_FAST 8 +#define PRI_BIAS_MAX 12 +#define PRI_BIAS_PTR 13 + +static const char *pri_d[] = PRIS(PRI_STR, d); +static const char *pri_i[] = PRIS(PRI_STR, i); +static const char *pri_o[] = PRIS(PRI_STR, o); +static const char *pri_u[] = PRIS(PRI_STR, u); +static const char *pri_x[] = PRIS(PRI_STR, x); +static const char *pri_X[] = PRIS(PRI_STR, X); + +static const char pri_d_len[] = PRIS(PRI_LEN, d); +static const char pri_i_len[] = PRIS(PRI_LEN, i); +static const char pri_o_len[] = PRIS(PRI_LEN, o); +static const char pri_u_len[] = PRIS(PRI_LEN, u); +static const char pri_x_len[] = PRIS(PRI_LEN, x); +static const char pri_X_len[] = PRIS(PRI_LEN, X); + +static struct { + const char type; + const char **str_table; + const char *len_table; +} pri_table[] = { + {'d', pri_d, pri_d_len}, {'i', pri_i, pri_i_len}, + {'o', pri_o, pri_o_len}, {'u', pri_u, pri_u_len}, + {'x', pri_x, pri_x_len}, {'X', pri_X, pri_X_len}, +}; + +static struct { + const char *name; + const char nlen; + const char want_digits; + const char bias; +} special_table[] = { + {"LEAST", 5, 1, PRI_BIAS_LEAST}, + {"FAST", 4, 1, PRI_BIAS_FAST}, + {"MAX", 3, 0, PRI_BIAS_MAX}, + {"PTR", 3, 0, PRI_BIAS_PTR}, +}; + +/* + * conv_macro() returns the conversion specifier corresponding + * to the macro name specified in 'name'. 'len' contains the + * length of the macro name including the null termination. + * '*elen' will be set to the length of the returning conversion + * specifier without the null termination. + */ +static const char * +conv_macro(const char *str, uint32_t len, uint32_t *lenp) +{ + const char **tbl; + const char *ltbl; + char *next; + int n, i, num, bias, idx, want_digits; + + if (len == 2) { + if (*str == 'I') { + /* Solaris does not support %I */ + *lenp = 0; + return (""); + } + return (NULL); } - conv_msgstr_len = do_conv(gmnp->fd, &conv_dst, - (const char *)msgstr, msgstr_len); - if (conv_msgstr_len == (size_t)-1) { - free_conv_msgstr(gmnp); - result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); - return (result); + + if (len <= 4 || strncmp(str, "PRI", 3) != 0) + return (NULL); + + str += 3; + + n = sizeof (pri_table) / sizeof (pri_table[0]); + for (i = 0; i < n; i++) { + if (pri_table[i].type == *str) + break; } - buflen = (conv_msgstr_len + sizeof (size_t)); - /* allign to sizeof (size_t) */ - if (buflen % sizeof (size_t)) - buflen += (sizeof (size_t) - (buflen % sizeof (size_t))); - p = (size_t *)malloc(buflen); - if (!p) { - free(conv_dst); - free_conv_msgstr(gmnp); - result = dfltmsgstr(gmnp, msgstr, msgstr_len, mp); - return (result); + if (i == n) + return (NULL); + tbl = pri_table[i].str_table; + ltbl = pri_table[i].len_table; + + str++; + idx = want_digits = 0; + + if (isdigit((unsigned char)*str)) { + /* PRIx/N/ */ + bias = 0; + want_digits = 1; + } else { + n = sizeof (special_table) / sizeof (special_table[0]); + for (i = 0; i < n; i++) { + if (strncmp(special_table[i].name, + str, special_table[i].nlen) == 0) { + break; + } + } + if (i == n) + return (NULL); + bias = special_table[i].bias; + want_digits = special_table[i].want_digits; + str += special_table[i].nlen; } - *p = conv_msgstr_len; - (void) memcpy(p + 1, conv_dst, conv_msgstr_len); - free(conv_dst); - gmnp->conv_msgstr[midx] = (char *)p; - conv_msgstr = (char *)(p + 1); - result = dfltmsgstr(gmnp, conv_msgstr, conv_msgstr_len, mp); - return (result); + + if (want_digits) { + if (!isdigit((unsigned char)*str)) + return (NULL); + num = strtol(str, &next, 10); + /* see if it is 8/16/32/64 */ + for (n = 8, idx = 0; idx < 4; idx++, n *= 2) { + if (n == num) + break; + } + if (idx == 4) + return (NULL); + str = next; + } + if (*str != '\0') { + /* unknow format */ + return (NULL); + } + + *lenp = (uint32_t)ltbl[bias + idx]; + return (tbl[bias + idx]); +} + +static gnu_d_macro_t * +expand_macros(Msg_g_node *p) +{ + char *base = (char *)p->msg_file_info; + struct gnu_msg_rev1_info *rev1_header = p->rev1_header; + struct gnu_msg_ent *d_macro_tbl; + gnu_d_macro_t *d_macro; + uint32_t num_of_d_macro, e_maclen, maclen, i; + const char *e_macname; + char *macname; + + /* number of the dynamic macros */ + num_of_d_macro = SWAP(p, rev1_header->num_of_dynamic_macro); + + d_macro = malloc((size_t)num_of_d_macro * sizeof (gnu_d_macro_t)); + if (d_macro == NULL) + return (NULL); + + /* pointer to the dynamic strings table */ + d_macro_tbl = (struct gnu_msg_ent *)(uintptr_t) + (base + SWAP(p, rev1_header->off_dynamic_macro)); + + for (i = 0; i < num_of_d_macro; i++) { + macname = base + SWAP(p, d_macro_tbl[i].offset); + maclen = SWAP(p, d_macro_tbl[i].len); + + /* + * sanity check + * maclen includes a null termination. + */ + if (maclen != strlen(macname) + 1) { + free(d_macro); + return (NULL); + } + e_macname = conv_macro(macname, maclen, &e_maclen); + if (e_macname == NULL) { + free(d_macro); + return (NULL); + } + d_macro[i].len = e_maclen; + d_macro[i].ptr = e_macname; + } + + return (d_macro); +} + +static char * +expand_dynamic_message(Msg_g_node *p, struct gnu_msg_ent **e_msgs) +{ + + char *base = (char *)p->msg_file_info; + struct gnu_msg_rev1_info *rev1_header = p->rev1_header; + struct gnu_dynamic_tbl *d_info; + struct gnu_dynamic_ent *entry; + gnu_d_macro_t *d_macro; + uint32_t num_of_d_str, mlen, dlen, didx, i, j; + uint32_t off_d_tbl; + uint32_t *d_msg_off_tbl; + size_t mchunk_size, used, need; + char *mchunk, *msg; + +#define MEM_INCR (1024) + + d_macro = expand_macros(p); + if (d_macro == NULL) + return (NULL); + + /* number of dynamic messages */ + num_of_d_str = p->num_of_d_str; + + mchunk = NULL; + mchunk_size = 0; /* size of the allocated memory in mchunk */ + used = 0; /* size of the used memory in mchunk */ + for (i = MSGID; i <= MSGSTR; i++) { + /* pointer to the offset table of dynamic msgids/msgstrs */ + off_d_tbl = SWAP(p, + i == MSGID ? rev1_header->off_dynamic_msgid_tbl : + rev1_header->off_dynamic_msgstr_tbl); + /* pointer to the dynamic msgids/msgstrs */ + d_msg_off_tbl = (uint32_t *)(uintptr_t)(base + off_d_tbl); + for (j = 0; j < num_of_d_str; j++) { + e_msgs[i][j].offset = used; + d_info = (struct gnu_dynamic_tbl *)(uintptr_t) + (base + SWAP(p, d_msg_off_tbl[j])); + entry = d_info->entry; + msg = base + SWAP(p, d_info->offset); + + for (;;) { + mlen = SWAP(p, entry->len); + didx = SWAP(p, entry->idx); + dlen = (didx == NOMORE_DYNAMIC_MACRO) ? 0 : + d_macro[didx].len; + need = used + mlen + dlen; + if (need >= mchunk_size) { + char *t; + size_t n = mchunk_size; + do { + n += MEM_INCR; + } while (n <= need); + t = realloc(mchunk, n); + if (t == NULL) { + free(d_macro); + free(mchunk); + return (NULL); + } + mchunk = t; + mchunk_size = n; + } + (void) memcpy(mchunk + used, msg, (size_t)mlen); + msg += mlen; + used += mlen; + + if (didx == NOMORE_DYNAMIC_MACRO) { + /* + * Last segment of a static + * msg string contains a null + * termination, so an explicit + * null termination is not required + * here. + */ + break; + } + (void) memcpy(mchunk + used, + d_macro[didx].ptr, (size_t)dlen); + used += dlen; + entry++; /* to next entry */ + } + /* + * e_msgs[][].len does not include a null termination + */ + e_msgs[i][j].len = used - e_msgs[i][j].offset - 1; + } + } + + free(d_macro); + + /* shrink mchunk to 'used' */ + { + char *t; + t = realloc(mchunk, used); + if (t == NULL) { + free(mchunk); + return (NULL); + } + mchunk = t; + } + + return (mchunk); +} + +static int +build_rev1_info(Msg_g_node *p) +{ + uint32_t *d_hash; + uint32_t num_of_d_str, num_of_str; + uint32_t idx, hash_value, hash_size; + size_t hash_mem_size; + size_t d_msgid_size, d_msgstr_size; + char *chunk, *mchunk; + int i; + +#ifdef GETTEXT_DEBUG + gprintf(0, "******* entering build_rev1_info(0x%p)\n", p); + printgnumsg(p, 1); +#endif + + if (p->hash_table == NULL) { + /* Revision 1 always requires the hash table */ + return (-1); + } + + num_of_str = p->num_of_str; + hash_size = p->hash_size; + num_of_d_str = p->num_of_d_str; + + hash_mem_size = hash_size * sizeof (uint32_t); + ROUND(hash_mem_size, sizeof (struct gnu_msg_ent)); + + d_msgid_size = num_of_d_str * sizeof (struct gnu_msg_ent); + d_msgstr_size = num_of_d_str * sizeof (struct gnu_msg_ent); + + chunk = malloc(hash_mem_size + d_msgid_size + d_msgstr_size); + if (chunk == NULL) { + return (-1); + } + + d_hash = (uint32_t *)(uintptr_t)chunk; + p->d_msg[MSGID] = (struct gnu_msg_ent *)(uintptr_t) + (chunk + hash_mem_size); + p->d_msg[MSGSTR] = (struct gnu_msg_ent *)(uintptr_t) + (chunk + hash_mem_size + d_msgid_size); + + if ((mchunk = expand_dynamic_message(p, p->d_msg)) == NULL) { + free(chunk); + return (-1); + } + + /* copy the original hash table into the dynamic hash table */ + for (i = 0; i < hash_size; i++) { + d_hash[i] = SWAP(p, p->hash_table[i]); + } + + /* fill in the dynamic hash table with dynamic messages */ + for (i = 0; i < num_of_d_str; i++) { + hash_value = get_hashid(mchunk + p->d_msg[MSGID][i].offset, + NULL); + idx = get_hash_index(d_hash, hash_value, hash_size); + d_hash[idx] = num_of_str + i + 1; + } + + p->mchunk = mchunk; + p->hash_table = d_hash; + +#ifdef GETTEXT_DEBUG + print_rev1_info(p); + gprintf(0, "******* exiting build_rev1_info()\n"); + printgnumsg(p, 1); +#endif + + return (0); +} + +/* + * gnu_setmsg + * + * INPUT + * mnp - message node + * addr - address to the mmapped file + * size - size of the file + * + * RETURN + * 0 - either T_GNU_MO or T_ILL_MO has been set + * -1 - failed + */ +int +gnu_setmsg(Msg_node *mnp, char *addr, size_t size) +{ + struct gnu_msg_info *gnu_header; + Msg_g_node *p; + +#ifdef GETTEXT_DEBUG + gprintf(0, "******** entering gnu_setmsg(0x%p, 0x%p, %lu)\n", + (void *)mnp, addr, size); + printmnp(mnp, 1); +#endif + + /* checks the GNU MAGIC number */ + if (size < sizeof (struct gnu_msg_info)) { + /* invalid mo file */ + mnp->type = T_ILL_MO; +#ifdef GETTEXT_DEBUG + gprintf(0, "********* exiting gnu_setmsg\n"); + printmnp(mnp, 1); +#endif + return (0); + } + + gnu_header = (struct gnu_msg_info *)(uintptr_t)addr; + + p = calloc(1, sizeof (Msg_g_node)); + if (p == NULL) { + return (-1); + } + p->msg_file_info = gnu_header; + + if (gnu_header->magic == GNU_MAGIC) { + switch (gnu_header->revision) { + case GNU_REVISION_0_1: + case GNU_REVISION_1_1: + p->flag |= ST_REV1; + break; + } + } else if (gnu_header->magic == GNU_MAGIC_SWAPPED) { + p->flag |= ST_SWP; + switch (gnu_header->revision) { + case GNU_REVISION_0_1_SWAPPED: + case GNU_REVISION_1_1_SWAPPED: + p->flag |= ST_REV1; + break; + } + } else { + /* invalid mo file */ + free(p); + mnp->type = T_ILL_MO; +#ifdef GETTEXT_DEBUG + gprintf(0, "********* exiting gnu_setmsg\n"); + printmnp(mnp, 1); +#endif + return (0); + } + + p->fsize = size; + p->num_of_str = SWAP(p, gnu_header->num_of_str); + p->hash_size = SWAP(p, gnu_header->sz_hashtbl); + p->hash_table = p->hash_size <= 2 ? NULL : + (uint32_t *)(uintptr_t) + (addr + SWAP(p, gnu_header->off_hashtbl)); + + p->msg_tbl[MSGID] = (struct gnu_msg_ent *)(uintptr_t) + (addr + SWAP(p, gnu_header->off_msgid_tbl)); + p->msg_tbl[MSGSTR] = (struct gnu_msg_ent *)(uintptr_t) + (addr + SWAP(p, gnu_header->off_msgstr_tbl)); + + if (p->flag & ST_REV1) { + /* Revision 1 */ + struct gnu_msg_rev1_info *rev1_header; + + rev1_header = (struct gnu_msg_rev1_info *) + (uintptr_t)(addr + sizeof (struct gnu_msg_info)); + p->rev1_header = rev1_header; + p->num_of_d_str = SWAP(p, rev1_header->num_of_dynamic_str); + if (build_rev1_info(p) == -1) { + free(p); +#ifdef GETTEXT_DEBUG + gprintf(0, "******** exiting gnu_setmsg: " + "build_rev1_info() failed\n"); +#endif + return (-1); + } + } + + mnp->msg.gnumsg = p; + mnp->type = T_GNU_MO; + +#ifdef GETTEXT_DEBUG + gprintf(0, "********* exiting gnu_setmsg\n"); + printmnp(mnp, 1); +#endif + return (0); +} + +/* + * get_hash_index + * + * Returns the index to an empty slot in the hash table + * for the specified hash_value. + */ +static uint32_t +get_hash_index(uint32_t *hash_tbl, uint32_t hash_value, uint32_t hash_size) +{ + uint32_t idx, inc; + + idx = hash_value % hash_size; + inc = 1 + (hash_value % (hash_size - 2)); + + for (;;) { + if (hash_tbl[idx] == 0) { + /* found an empty slot */ + return (idx); + } + idx = (idx + inc) % hash_size; + } + /* NOTREACHED */ } diff --git a/usr/src/lib/libc/port/i18n/gettext_real.c b/usr/src/lib/libc/port/i18n/gettext_real.c index c40f103be0..516364835f 100644 --- a/usr/src/lib/libc/port/i18n/gettext_real.c +++ b/usr/src/lib/libc/port/i18n/gettext_real.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -21,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -50,68 +49,44 @@ #include "nlspath_checks.h" static int process_nlspath(const char *, const char *, - const char *, char **); -static char *replace_nls_option(char *, const char *, char *, - char *, char *, char *, char *); -static char *key_2_text(Msg_s_node *, const char *); -static char *handle_mo(struct cache_pack *, struct msg_pack *); -static void mini_strcpy(char *, const char *); -static size_t mini_strlen(const char *); + const char *, char **); +static char *replace_nls_option(char *, const char *, char *, + char *, char *, char *, char *); char * -_real_gettext_u(const char *domain, - const char *msgid1, const char *msgid2, - unsigned long int ln, int category, - int plural) +_real_gettext_u(const char *domain, const char *msgid1, const char *msgid2, + unsigned long int ln, int category, int plural) { char msgfile[MAXPATHLEN]; /* 1024 */ - char binding[MAXPATHLEN]; /* 1024 */ char mydomain[TEXTDOMAINMAX + 1]; /* 256 + 1 */ char *cur_binding; /* points to current binding in list */ - char *bptr, *cur_locale, *cur_domain, *result, *nlspath; - char *locale, *msgloc, *cb, *cur_domain_binding; + char *cur_locale, *cur_domain, *result, *nlspath; + char *msgloc, *cb, *cur_domain_binding; char *language; - int n = (unsigned int)ln; /* we don't need long for n */ - size_t cblen, cur_locale_len, cur_domain_len; - unsigned int hash_locale; - + unsigned int n = (unsigned int)ln; /* we don't need long for n */ + uint32_t cur_domain_len, cblen; + uint32_t hash_domain; struct msg_pack *mp, omp; - struct cache_pack *cp, ocp; #ifdef GETTEXT_DEBUG - (void) printf("*************** _real_gettext_u(%s, %s, " - "%s, %d, %d, %d)\n", + gprintf(0, "*************** _real_gettext_u(\"%s\", \"%s\", " + "\"%s\", %d, %d, %d)\n", domain ? domain : "NULL", msgid1 ? msgid1 : "NULL", - msgid2 ? msgid2 : "NULL", n, category, plural); + msgid2 ? msgid2 : "NULL", n, category, plural); + gprintf(0, "***************** global_gt: 0x%p\n", global_gt); + printgt(global_gt, 1); #endif if (msgid1 == NULL) return (NULL); - cp = memset(&ocp, 0, sizeof (ocp)); /* cache pack */ mp = memset(&omp, 0, sizeof (omp)); /* msg pack */ /* * category may be LC_MESSAGES or LC_TIME * locale contains the value of 'category' - * hash_locale contains the hash value of locale - * msgloc contains the value of LC_MESSAGES - * hash_msgloc contains the hash value of msgloc */ - locale = setlocale(category, NULL); - hash_locale = get_hashid(locale, &cur_locale_len); - - /* - * content of locale will be overridden by - * succeeding setlocale invocation. - * So, duplicate it - */ - cur_locale = (char *)malloc(cur_locale_len + 1); - if (!cur_locale) { - DFLTMSG(result, msgid1, msgid2, n, plural); - return (result); - } - mini_strcpy(cur_locale, locale); + cur_locale = setlocale(category, NULL); language = getenv("LANGUAGE"); /* for GNU */ if (language) { @@ -129,39 +104,36 @@ _real_gettext_u(const char *domain, * Query the current domain if domain argument is NULL pointer */ mydomain[0] = '\0'; - if (!domain) { + if (domain == NULL) { /* * if NULL is specified for domainname, * use the currently bound domain. */ cur_domain = _textdomain_u(NULL, mydomain); - cur_domain_len = mini_strlen(cur_domain); } else if (!*domain) { /* * if an empty string is specified */ cur_domain = DEFAULT_DOMAIN; - cur_domain_len = DEFAULT_DOMAIN_LEN; } else { - cur_domain_len = mini_strlen(domain); - if (cur_domain_len > TEXTDOMAINMAX) { - /* domain is invalid, return msg_id */ - free(cur_locale); - DFLTMSG(result, msgid1, msgid2, n, plural); - return (result); - } cur_domain = (char *)domain; } + hash_domain = get_hashid(cur_domain, &cur_domain_len); + if (cur_domain_len > TEXTDOMAINMAX) { + /* domain is invalid, return msg_id */ + DFLTMSG(result, msgid1, msgid2, n, plural); + return (result); + } + nlspath = getenv("NLSPATH"); /* get the content of NLSPATH */ - if (!nlspath || !*nlspath) { + if (nlspath == NULL || !*nlspath) { /* no NLSPATH is defined in the environ */ if ((*cur_locale == 'C') && (*(cur_locale + 1) == '\0')) { /* * If C locale, * return the original msgid immediately. */ - free(cur_locale); DFLTMSG(result, msgid1, msgid2, n, plural); return (result); } @@ -173,10 +145,9 @@ _real_gettext_u(const char *domain, msgloc = setlocale(LC_MESSAGES, NULL); ret = process_nlspath(cur_domain, msgloc, - (const char *)nlspath, &cur_binding); + (const char *)nlspath, &cur_binding); if (ret == -1) { /* error occurred */ - free(cur_locale); DFLTMSG(result, msgid1, msgid2, n, plural); return (result); } else if (ret == 0) { @@ -185,9 +156,8 @@ _real_gettext_u(const char *domain, } cur_domain_binding = _real_bindtextdomain_u(cur_domain, - NULL, TP_BINDING); - if (!cur_domain_binding) { - free(cur_locale); + NULL, TP_BINDING); + if (cur_domain_binding == NULL) { DFLTMSG(result, msgid1, msgid2, n, plural); return (result); } @@ -199,12 +169,11 @@ _real_gettext_u(const char *domain, mp->binding = cur_domain_binding; mp->locale = cur_locale; mp->language = language; - mp->locale_len = cur_locale_len; mp->domain_len = cur_domain_len; mp->n = n; mp->category = category; mp->plural = plural; - mp->hash_locale = hash_locale; + mp->hash_domain = hash_domain; /* * Spec1170 requires that we use NLSPATH if it's defined, to @@ -225,15 +194,14 @@ _real_gettext_u(const char *domain, /* * First, examine NLSPATH */ - bptr = binding; if (nlspath) { /* * NLSPATH binding has been successfully built */ #ifdef GETTEXT_DEBUG - (void) printf("************************** examining NLSPATH\n"); - (void) printf(" cur_binding: \"%s\"\n", - cur_binding ? cur_binding : "(null)"); + gprintf(0, "************************** examining NLSPATH\n"); + gprintf(0, " cur_binding: \"%s\"\n", + cur_binding ? cur_binding : "(null)"); #endif mp->nlsp = 1; @@ -249,26 +217,23 @@ _real_gettext_u(const char *domain, cur_binding++; if (cblen >= MAXPATHLEN) { /* cur_binding too long */ - free(cur_locale); DFLTMSG(result, msgid1, msgid2, n, plural); return (result); } - (void) memcpy(bptr, cb, cblen); - *(bptr + cblen) = '\0'; - (void) memcpy(mp->msgfile, bptr, cblen + 1); - mp->msgfile_len = cblen; + (void) memcpy(mp->msgfile, cb, cblen); + *(mp->msgfile + cblen) = '\0'; + #ifdef GETTEXT_DEBUG - (void) printf("*******************" - "********************* \n"); - (void) printf(" msgfile: \"%s\"\n", - msgfile ? msgfile : "(null)"); - (void) printf("*******************" - "********************* \n"); + gprintf(0, "*******************" + "********************* \n"); + gprintf(0, " msgfile: \"%s\"\n", + msgfile ? msgfile : "(null)"); + gprintf(0, "*******************" + "********************* \n"); #endif - result = handle_mo(cp, mp); + result = handle_mo(mp); if (result) { - free(cur_locale); return (result); } } @@ -281,21 +246,16 @@ _real_gettext_u(const char *domain, */ if (language) { char *ret_msg; - ret_msg = handle_lang(cp, mp); + ret_msg = handle_lang(mp); if (ret_msg != NULL) { - /* - * GNU MO found - */ - free(cur_locale); + /* valid msg found in GNU MO */ return (ret_msg); } /* - * handle_lang() may have overridden - * locale and hash_locale + * handle_lang() may have overridden locale */ mp->locale = cur_locale; - mp->locale_len = cur_locale_len; - mp->hash_locale = hash_locale; + mp->status = 0; } /* @@ -305,13 +265,11 @@ _real_gettext_u(const char *domain, *mp->msgfile = '\0'; #endif if (mk_msgfile(mp) == NULL) { - free(cur_locale); DFLTMSG(result, msgid1, msgid2, n, plural); return (result); } - result = handle_mo(cp, mp); - free(cur_locale); + result = handle_mo(mp); if (result) { return (result); } @@ -320,11 +278,11 @@ _real_gettext_u(const char *domain, } /* _real_gettext_u */ #define ALLFREE \ - free_all(nlstmp, nnp, pathname, ppaths, lang, cacheline, cnp) + free_all(nlstmp, nnp, pathname, ppaths, lang) static void free_all(Nlstmp *nlstmp, Nls_node *nnp, char *pathname, - char *ppaths, char *lang, int cacheline, Cache_node *cnp) + char *ppaths, char *lang) { Nlstmp *tp, *tq; @@ -344,8 +302,6 @@ free_all(Nlstmp *nlstmp, Nls_node *nnp, char *pathname, free(ppaths); if (lang) free(lang); - if (!cacheline) - free(cnp); free(nnp); } @@ -364,7 +320,7 @@ free_all(Nlstmp *nlstmp, Nls_node *nnp, char *pathname, */ static int process_nlspath(const char *cur_domain, const char *cur_msgloc, - const char *nlspath, char **binding) + const char *nlspath, char **binding) { char *s; /* generic string ptr */ char *territory; /* our current territory element */ @@ -374,112 +330,70 @@ process_nlspath(const char *cur_domain, const char *cur_msgloc, char *lang = NULL; /* our current language element */ char *ppaths = NULL; /* ptr to all of the templates */ char *pathname = NULL; /* the full pathname to the file */ - unsigned int hashid; size_t nlspath_len, domain_len, locale_len, path_len; size_t ppaths_len = 0; - int cacheline = 0; Nlstmp *nlstmp = NULL; Nlstmp *pnlstmp, *qnlstmp; - Cache_node *cnp; - Nls_node *cur_nls, *nnp = NULL; + Nls_node *cur_nls, *nnp; Gettext_t *gt = global_gt; #ifdef GETTEXT_DEBUG - (void) printf("*************** process_nlspath(%s, %s, " - "%s, 0x%p)\n", cur_domain, + gprintf(0, "*************** process_nlspath(%s, %s, " + "%s, 0x%p)\n", cur_domain, cur_msgloc, nlspath, (void *)binding); #endif cur_nls = gt->c_n_node; if (cur_nls && - (strcmp(cur_nls->domain, cur_domain) == 0 && - strcmp(cur_nls->locale, cur_msgloc) == 0 && - strcmp(cur_nls->nlspath, nlspath) == 0)) { + (strcmp(cur_nls->domain, cur_domain) == 0 && + strcmp(cur_nls->locale, cur_msgloc) == 0 && + strcmp(cur_nls->nlspath, nlspath) == 0)) { *binding = cur_nls->ppaths; return (1); } - hashid = get_hashid(cur_msgloc, NULL); - - cnp = gt->c_node; - while (cnp) { - if (cnp->hashid == hashid) { - nnp = cnp->n_node; - cacheline = 1; - while (nnp) { - if (strcmp(nnp->locale, cur_msgloc) == 0 && - strcmp(nnp->domain, cur_domain) == 0 && - strcmp(nnp->nlspath, nlspath) == 0) { - gt->c_n_node = nnp; - *binding = nnp->ppaths; - return (1); - } - nnp = nnp->next; - } - break; - } else { - cnp = cnp->next; + nnp = gt->n_node; + while (nnp) { + if (strcmp(nnp->domain, cur_domain) == 0 && + strcmp(nnp->locale, cur_msgloc) == 0 && + strcmp(nnp->nlspath, nlspath) == 0) { + /* found */ + gt->c_n_node = nnp; + *binding = nnp->ppaths; + return (1); } + nnp = nnp->next; } + /* not found */ - if (cacheline) { - nnp = (Nls_node *)calloc(1, sizeof (Nls_node)); - if (!nnp) { - ALLFREE; - return (-1); - } - } else { - cnp = (Cache_node *)calloc(1, sizeof (Cache_node)); - if (!cnp) { - ALLFREE; - return (-1); - } - cnp->hashid = hashid; - nnp = (Nls_node *)calloc(1, sizeof (Nls_node)); - if (!nnp) { - ALLFREE; - return (-1); - } - cnp->n_node = nnp; - cnp->n_last = nnp; + nnp = calloc(1, sizeof (Nls_node)); + if (nnp == NULL) { + ALLFREE; + return (-1); } nlspath_len = strlen(nlspath); locale_len = strlen(cur_msgloc); domain_len = strlen(cur_domain); - /* - * nlspath_len, locale_len, and domain_len - * are including a null termination. - */ - nlspath_len++; - locale_len++; - domain_len++; - - lang = NULL; - territory = NULL; - codeset = NULL; - - if (cur_msgloc) { - lang = s = strdup(cur_msgloc); - if (lang == NULL) { - ALLFREE; - return (-1); - } - s1 = s2 = NULL; - while (s && *s) { - if (*s == '_') { - s1 = s; - *s1++ = '\0'; - } else if (*s == '.') { - s2 = s; - *s2++ = '\0'; - } - s++; + lang = s = strdup(cur_msgloc); + if (lang == NULL) { + ALLFREE; + return (-1); + } + s1 = s2 = NULL; + while (*s) { + if (*s == '_') { + s1 = s; + *s1++ = '\0'; + } else if (*s == '.') { + s2 = s; + *s2++ = '\0'; } - territory = s1; - codeset = s2; + s++; } + territory = s1; + codeset = s2; /* * now that we have the name (domain), we first look through NLSPATH, @@ -496,7 +410,7 @@ process_nlspath(const char *cur_domain, const char *cur_msgloc, * if we find one of these characters, we will carry out the * appropriate substitution. */ - pathname = (char *)malloc(MAXPATHLEN); + pathname = malloc(MAXPATHLEN); if (pathname == NULL) { ALLFREE; return (-1); @@ -510,19 +424,21 @@ process_nlspath(const char *cur_domain, const char *cur_msgloc, * ":" by "name". replace_nls_option() below * will handle the subsequent ":"'s. */ - pnlstmp = (Nlstmp *)malloc(sizeof (Nlstmp)); - if (!pnlstmp) { + pnlstmp = malloc(sizeof (Nlstmp)); + if (pnlstmp == NULL) { ALLFREE; return (-1); } (void) memcpy(pnlstmp->pathname, cur_domain, - domain_len); - ppaths_len += domain_len; + domain_len + 1); + pnlstmp->len = domain_len; + ppaths_len += domain_len + 1; /* 1 for ':' */ + pnlstmp->next = NULL; - if (!nlstmp) { + if (nlstmp == NULL) { nlstmp = pnlstmp; qnlstmp = pnlstmp; } else { @@ -535,7 +451,7 @@ process_nlspath(const char *cur_domain, const char *cur_msgloc, } /* replace Substitution field */ s = replace_nls_option(s, cur_domain, pathname, - (char *)cur_msgloc, lang, territory, codeset); + (char *)cur_msgloc, lang, territory, codeset); if (s == NULL) { ALLFREE; @@ -545,20 +461,21 @@ process_nlspath(const char *cur_domain, const char *cur_msgloc, /* if we've found a valid file: */ if (*pathname) { /* add template to end of chain of pathnames: */ - pnlstmp = (Nlstmp *)malloc(sizeof (Nlstmp)); - if (!pnlstmp) { + pnlstmp = malloc(sizeof (Nlstmp)); + if (pnlstmp == NULL) { ALLFREE; return (-1); } - path_len = strlen(pathname) + 1; + path_len = strlen(pathname); (void) memcpy(pnlstmp->pathname, pathname, - path_len); - ppaths_len += path_len; + path_len + 1); + pnlstmp->len = path_len; + ppaths_len += path_len + 1; /* 1 for ':' */ pnlstmp->next = NULL; - if (!nlstmp) { + if (nlstmp == NULL) { nlstmp = pnlstmp; qnlstmp = pnlstmp; } else { @@ -576,8 +493,8 @@ process_nlspath(const char *cur_domain, const char *cur_msgloc, */ if (ppaths_len != 0) { - ppaths = (char *)malloc(ppaths_len + 1); - if (!ppaths) { + ppaths = malloc(ppaths_len + 1); + if (ppaths == NULL) { ALLFREE; return (-1); } @@ -592,60 +509,50 @@ process_nlspath(const char *cur_domain, const char *cur_msgloc, * all into a ":" separated string for _bindtextdomain_u() */ pnlstmp = nlstmp; + s = ppaths; while (pnlstmp) { - (void) strcat(ppaths, pnlstmp->pathname); - (void) strcat(ppaths, ":"); + (void) memcpy(s, pnlstmp->pathname, pnlstmp->len); + s += pnlstmp->len; + *s++ = ':'; qnlstmp = pnlstmp->next; free(pnlstmp); pnlstmp = qnlstmp; } + *s = '\0'; nlstmp = NULL; - nnp->domain = (char *)malloc(domain_len); - if (!nnp->domain) { + nnp->domain = malloc(domain_len + 1); + if (nnp->domain == NULL) { ALLFREE; return (-1); } else { - (void) memcpy(nnp->domain, cur_domain, domain_len); + (void) memcpy(nnp->domain, cur_domain, domain_len + 1); } - nnp->locale = (char *)malloc(locale_len); - if (!nnp->locale) { + nnp->locale = malloc(locale_len + 1); + if (nnp->locale == NULL) { ALLFREE; return (-1); } else { - (void) memcpy(nnp->locale, cur_msgloc, locale_len); + (void) memcpy(nnp->locale, cur_msgloc, locale_len + 1); } - nnp->nlspath = (char *)malloc(nlspath_len); - if (!nnp->nlspath) { + nnp->nlspath = malloc(nlspath_len + 1); + if (nnp->nlspath == NULL) { ALLFREE; return (-1); } else { - (void) memcpy(nnp->nlspath, nlspath, nlspath_len); + (void) memcpy(nnp->nlspath, nlspath, nlspath_len + 1); } nnp->ppaths = ppaths; - nnp->next = NULL; - - if (cacheline) { - if (cnp->n_last) - cnp->n_last->next = nnp; - else - cnp->n_node = nnp; - cnp->n_last = nnp; - } else { - if (gt->c_last) - gt->c_last->next = cnp; - else - gt->c_node = cnp; - gt->c_last = cnp; - } + + nnp->next = gt->n_node; + gt->n_node = nnp; gt->c_n_node = nnp; free(pathname); free(lang); #ifdef GETTEXT_DEBUG - (void) printf("*************** existing process_nlspath " - "with success\n"); - (void) printf(" binding: \"%s\"\n", ppaths); + gprintf(0, "*************** existing process_nlspath with success\n"); + gprintf(0, " binding: \"%s\"\n", ppaths); #endif *binding = ppaths; return (1); @@ -658,7 +565,7 @@ process_nlspath(const char *cur_domain, const char *cur_msgloc, */ static char * replace_nls_option(char *s, const char *name, char *pathname, - char *locale, char *lang, char *territory, char *codeset) + char *locale, char *lang, char *territory, char *codeset) { char *t, *u; char *limit; @@ -692,14 +599,14 @@ replace_nls_option(char *s, const char *name, char *pathname, if (lang) { u = lang; while (*u && (*u != '_') && - (t < limit)) + (t < limit)) *t++ = *u++; } } else if (*s == 't') { if (territory) { u = territory; while (*u && (*u != '.') && - (t < limit)) + (t < limit)) *t++ = *u++; } } else if (*s == 'c') { @@ -725,24 +632,25 @@ replace_nls_option(char *s, const char *name, char *pathname, char * _real_bindtextdomain_u(const char *domain, const char *binding, - int type) + int type) { struct domain_binding *bind, *prev; Gettext_t *gt = global_gt; char **binding_addr; #ifdef GETTEXT_DEBUG - (void) printf("*************** _real_bindtextdomain_u(%s, %s, %s)\n", - (domain ? domain : ""), - (binding ? binding : ""), - (type == TP_BINDING) ? "TP_BINDING" : "TP_CODESET"); + gprintf(0, "*************** _real_bindtextdomain_u(\"%s\", " + "\"%s\", \"%s\")\n", + (domain ? domain : ""), + (binding ? binding : ""), + (type == TP_BINDING) ? "TP_BINDING" : "TP_CODESET"); #endif /* * If domain is a NULL pointer, no change will occur regardless * of binding value. Just return NULL. */ - if (!domain) { + if (domain == NULL) { return (NULL); } @@ -764,8 +672,8 @@ _real_bindtextdomain_u(const char *domain, const char *binding, * Domain found. */ binding_addr = (type == TP_BINDING) ? &(bind->binding) : - &(bind->codeset); - if (!binding) { + &(bind->codeset); + if (binding == NULL) { /* * if binding is null, then query */ @@ -794,7 +702,7 @@ _real_bindtextdomain_u(const char *domain, const char *binding, * Then add a new node to the end of linked list. */ - if ((bind = (Dbinding *)malloc(sizeof (Dbinding))) == NULL) { + if ((bind = malloc(sizeof (Dbinding))) == NULL) { return (NULL); } if ((bind->domain = strdup(domain)) == NULL) { @@ -804,7 +712,7 @@ _real_bindtextdomain_u(const char *domain, const char *binding, bind->binding = NULL; bind->codeset = NULL; binding_addr = (type == TP_BINDING) ? &(bind->binding) : - &(bind->codeset); + &(bind->codeset); if ((*binding_addr = strdup(binding)) == NULL) { free(bind->domain); free(bind); @@ -850,13 +758,13 @@ _textdomain_u(const char *domain, char *result) Gettext_t *gt = global_gt; #ifdef GETTEXT_DEBUG - (void) printf("*************** _textdomain_u(\"%s\", 0x%p)\n", - (domain ? domain : ""), (void *)result); + gprintf(0, "*************** _textdomain_u(\"%s\", 0x%p)\n", + (domain ? domain : ""), (void *)result); #endif /* Query is performed for NULL domain pointer */ if (domain == NULL) { - mini_strcpy(result, CURRENT_DOMAIN(gt)); + (void) strcpy(result, CURRENT_DOMAIN(gt)); return (result); } @@ -865,7 +773,7 @@ _textdomain_u(const char *domain, char *result) * domain is limited to TEXTDOMAINMAX bytes * excluding a null termination. */ - domain_len = mini_strlen(domain); + domain_len = strlen(domain); if (domain_len > TEXTDOMAINMAX) { /* too long */ return (NULL); @@ -885,16 +793,16 @@ _textdomain_u(const char *domain, char *result) CURRENT_DOMAIN(gt) = (char *)default_domain; } } else { - p = (char *)malloc(domain_len + 1); - if (!p) + p = malloc(domain_len + 1); + if (p == NULL) return (NULL); - mini_strcpy(p, domain); + (void) strcpy(p, domain); if (CURRENT_DOMAIN(gt) != default_domain) free(CURRENT_DOMAIN(gt)); CURRENT_DOMAIN(gt) = p; } - mini_strcpy(result, CURRENT_DOMAIN(gt)); + (void) strcpy(result, CURRENT_DOMAIN(gt)); return (result); } /* _textdomain_u */ @@ -910,16 +818,16 @@ key_2_text(Msg_s_node *messages, const char *key_string) struct msg_struct *check_msg_list; #ifdef GETTEXT_DEBUG - (void) printf("*************** key_2_text(0x%p, \"%s\")\n", - (void *)messages, key_string ? key_string : "(null)"); - printsunmsg(messages, 0); + gprintf(0, "*************** key_2_text(0x%p, \"%s\")\n", + (void *)messages, key_string ? key_string : "(null)"); + printsunmsg(messages, 1); #endif check_msg_list = messages->msg_list + - messages->msg_file_info->msg_mid; + messages->msg_file_info->msg_mid; for (;;) { msg_id_str = messages->msg_ids + - check_msg_list->msgid_offset; + check_msg_list->msgid_offset; /* * To maintain the compatibility with Zeus mo file, * msg_id's are stored in descending order. @@ -929,13 +837,13 @@ key_2_text(Msg_s_node *messages, const char *key_string) */ val = *(unsigned char *)msg_id_str - kc; if ((val == 0) && - (val = strcmp(msg_id_str, key_string)) == 0) { + (val = strcmp(msg_id_str, key_string)) == 0) { return (messages->msg_strs - + check_msg_list->msgstr_offset); + + check_msg_list->msgstr_offset); } else if (val < 0) { if (check_msg_list->less != LEAFINDICATOR) { check_msg_list = messages->msg_list + - check_msg_list->less; + check_msg_list->less; continue; } return ((char *)key_string); @@ -943,7 +851,7 @@ key_2_text(Msg_s_node *messages, const char *key_string) /* val > 0 */ if (check_msg_list->more != LEAFINDICATOR) { check_msg_list = messages->msg_list + - check_msg_list->more; + check_msg_list->more; continue; } return ((char *)key_string); @@ -951,15 +859,126 @@ key_2_text(Msg_s_node *messages, const char *key_string) } } +/* + * sun_setmsg + * + * INPUT + * mnp - message node + * addr - address to the mmapped file + * size - size of the file + * + * RETURN + * 0 - either T_SUN_MO or T_ILL_MO has been set + * 1 - not a valid sun mo file + * -1 - failed + */ +static int +sun_setmsg(Msg_node *mnp, char *addr, size_t size) +{ + struct msg_info *sun_header; + Msg_s_node *p; + uint32_t first_4bytes; + int mid, count; + int struct_size, struct_size_old; + int msg_struct_size; + + if (size < sizeof (struct msg_info)) { + /* invalid mo file */ + mnp->type = T_ILL_MO; +#ifdef GETTEXT_DEBUG + gprintf(0, "********* exiting sun_setmsg\n"); + printmnp(mnp, 1); +#endif + return (0); + } + + first_4bytes = *((uint32_t *)(uintptr_t)addr); + if (first_4bytes > INT_MAX) { + /* + * Not a valid sun mo file + */ + return (1); + } + + /* candidate for sun mo */ + + sun_header = (struct msg_info *)(uintptr_t)addr; + mid = sun_header->msg_mid; + count = sun_header->msg_count; + msg_struct_size = sun_header->msg_struct_size; + struct_size_old = (int)(OLD_MSG_STRUCT_SIZE * count); + struct_size = (int)(MSG_STRUCT_SIZE * count); + + if ((((count - 1) / 2) != mid) || + ((msg_struct_size != struct_size_old) && + (msg_struct_size != struct_size))) { + /* invalid mo file */ + mnp->type = T_ILL_MO; +#ifdef GETTEXT_DEBUG + gprintf(0, "********* exiting sun_setmsg\n"); + printmnp(mnp, 1); +#endif + return (0); + } + /* valid sun mo file */ + + p = malloc(sizeof (Msg_s_node)); + if (p == NULL) { + return (-1); + } + + p->msg_file_info = sun_header; + p->msg_list = (struct msg_struct *)(uintptr_t) + (addr + sizeof (struct msg_info)); + p->msg_ids = (char *)(addr + sizeof (struct msg_info) + + struct_size); + p->msg_strs = (char *)(addr + sizeof (struct msg_info) + + struct_size + sun_header->str_count_msgid); + + mnp->msg.sunmsg = p; + mnp->type = T_SUN_MO; +#ifdef GETTEXT_DEBUG + gprintf(0, "******** exiting sun_setmsg\n"); + printmnp(mnp, 1); +#endif + return (0); +} + +/* + * setmsg + * + * INPUT + * mnp - message node + * addr - address to the mmapped file + * size - size of the file + * + * RETURN + * 0 - succeeded + * -1 - failed + */ +static int +setmsg(Msg_node *mnp, char *addr, size_t size) +{ + int ret; + if ((ret = sun_setmsg(mnp, addr, size)) <= 0) + return (ret); + + return (gnu_setmsg(mnp, addr, size)); +} + static char * -handle_type_mo(struct cache_pack *cp, struct msg_pack *mp) +handle_type_mo(Msg_node *mnp, struct msg_pack *mp) { char *result; - switch (cp->mnp->type) { + switch (mnp->type) { case T_ILL_MO: + /* invalid MO */ return (NULL); case T_SUN_MO: + /* Sun MO found */ + mp->status |= ST_SUN_MO_FOUND; + if (mp->plural) { /* * *ngettext is called against @@ -971,143 +990,115 @@ handle_type_mo(struct cache_pack *cp, struct msg_pack *mp) result = (char *)mp->msgid2; return (result); } - result = key_2_text(cp->mnp->msg.sunmsg, mp->msgid1); - if (!cp->mnp->trusted) { + result = key_2_text(mnp->msg.sunmsg, mp->msgid1); + if (!mnp->trusted) { result = check_format(mp->msgid1, result, 0); } return (result); case T_GNU_MO: - if (mp->language) { - /* - * LANGUAGE has been set. - * Failed to find out a valid GNU MO in - * handle_lang() using LANGUAGE. - * Now found a valid GNU MO. But, gettext() - * needs to default-return. - */ - DFLTMSG(result, mp->msgid1, mp->msgid2, - mp->n, mp->plural); + /* GNU MO found */ + mp->status |= ST_GNU_MO_FOUND; + + result = gnu_key_2_text(mnp->msg.gnumsg, + get_codeset(mp->domain), mp); + + if (result == mp->msgid1 || result == mp->msgid2) { + /* no valid msg found */ return (result); } - result = gnu_key_2_text(cp->mnp->msg.gnumsg, - get_codeset(mp->domain), mp); - if (!cp->mnp->trusted) { + + /* valid msg found */ + mp->status |= ST_GNU_MSG_FOUND; + + if (!mnp->trusted) { result = check_format(mp->msgid1, result, 0); if (result == mp->msgid1) { DFLTMSG(result, mp->msgid1, mp->msgid2, - mp->n, mp->plural); + mp->n, mp->plural); } } return (result); default: /* this should never happen */ - return (NULL); + DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural); + return (result); } /* NOTREACHED */ } -static char * -handle_mo(struct cache_pack *cp, struct msg_pack *mp) +/* + * handle_mo() returns NULL if invalid MO found. + */ +char * +handle_mo(struct msg_pack *mp) { - int fd, ret; + int fd; char *result; struct stat64 statbuf; + Msg_node *mnp; Gettext_t *gt = global_gt; +#define CONNECT_ENTRY \ + mnp->next = gt->m_node; \ + gt->m_node = mnp; \ + gt->c_m_node = mnp + #ifdef GETTEXT_DEBUG - (void) printf("*************** handle_mo(0x%p, 0x%p)\n", - (void *)cp, (void *)mp); - printcp(cp, 0); - printmp(mp, 0); + gprintf(0, "*************** handle_mo(0x%p)\n", (void *)mp); + printmp(mp, 1); #endif - /* - * At this point, msgfile contains full path for - * domain. - * Look up cache entry first. If cache misses, - * then search domain look-up table. - */ + mnp = check_cache(mp); - ret = check_cache(cp, mp); - - if (ret) { + if (mnp != NULL) { /* cache found */ - gt->c_m_node = cp->mnp; - return (handle_type_mo(cp, mp)); + return (handle_type_mo(mnp, mp)); } + /* * Valid entry not found in the cache */ - fd = nls_safe_open(mp->msgfile, &statbuf, &mp->trusted, - !mp->nlsp); + mnp = calloc(1, sizeof (Msg_node)); + if (mnp == NULL) { + DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural); + return (result); + } + mnp->hashid = mp->hash_domain; + mnp->path = strdup(mp->msgfile); + if (mnp->path == NULL) { + free(mnp); + DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural); + return (result); + } + + fd = nls_safe_open(mp->msgfile, &statbuf, &mp->trusted, !mp->nlsp); if ((fd == -1) || (statbuf.st_size > LONG_MAX)) { - if (connect_invalid_entry(cp, mp) == -1) { - DFLTMSG(result, mp->msgid1, mp->msgid2, - mp->n, mp->plural); - return (result); - } + if (fd != -1) + (void) close(fd); + mnp->type = T_ILL_MO; + CONNECT_ENTRY; return (NULL); } mp->fsz = (size_t)statbuf.st_size; - mp->addr = mmap(0, mp->fsz, PROT_READ, MAP_SHARED, fd, 0); + mp->addr = mmap(NULL, mp->fsz, PROT_READ, MAP_SHARED, fd, 0); (void) close(fd); - if (mp->addr == (caddr_t)-1) { - if (connect_invalid_entry(cp, mp) == -1) { - DFLTMSG(result, mp->msgid1, mp->msgid2, - mp->n, mp->plural); - return (result); - } - return (NULL); - } - - cp->mnp = create_mnp(mp); - if (!cp->mnp) { - free_mnp_mp(cp->mnp, mp); + if (mp->addr == MAP_FAILED) { + free(mnp->path); + free(mnp); DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural); return (result); } - if (setmsg(cp->mnp, (char *)mp->addr, mp->fsz) == -1) { - free_mnp_mp(cp->mnp, mp); + if (setmsg(mnp, (char *)mp->addr, mp->fsz) == -1) { + free(mnp->path); + free(mnp); (void) munmap(mp->addr, mp->fsz); DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural); return (result); } - if (!cp->cacheline) { - cp->cnp = create_cnp(cp->mnp, mp); - if (!cp->cnp) { - free_mnp_mp(cp->mnp, mp); - (void) munmap(mp->addr, mp->fsz); - DFLTMSG(result, mp->msgid1, mp->msgid2, - mp->n, mp->plural); - return (result); - } - } - cp->mnp->trusted = mp->trusted; - connect_entry(cp); - - return (handle_type_mo(cp, mp)); - /* NOTREACHED */ -} - -static void -mini_strcpy(char *dst, const char *src) -{ - const char *p = (const char *)src; - char *q = dst; - while (*q++ = *p++) - ; -} - -static size_t -mini_strlen(const char *str) -{ - const char *p = (const char *)str; - size_t len; + mnp->trusted = mp->trusted; + CONNECT_ENTRY; - while (*p) - p++; - len = (size_t)(p - str); - return (len); + return (handle_type_mo(mnp, mp)); } diff --git a/usr/src/lib/libc/port/i18n/gettext_util.c b/usr/src/lib/libc/port/i18n/gettext_util.c index 58d588db90..f8982665af 100644 --- a/usr/src/lib/libc/port/i18n/gettext_util.c +++ b/usr/src/lib/libc/port/i18n/gettext_util.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -33,9 +33,6 @@ #include <stdlib.h> #include <string.h> #include <sys/types.h> -#include <thread.h> -#include <synch.h> -#include <limits.h> #include <unistd.h> #include <sys/mman.h> #include <langinfo.h> @@ -67,164 +64,6 @@ static const int category_name_len[] = { 11 }; -static int -setmo(Msg_node *mnp, char *addr, int type) -{ -#ifdef GETTEXT_DEBUG - (void) printf("*************** setmo(0x%p, %d)\n", - (void *)mnp, ret); - printmnp(mnp, 0); -#endif - - switch (type) { - case T_ILL_MO: - /* invalid MO */ - mnp->type = T_ILL_MO; -#ifdef GETTEXT_DEBUG - (void) printf("*************** exiting setmo\n"); - printmnp(mnp, 0); -#endif - return (0); - case T_SUN_MO: - { - struct msg_info *sun_header; - int struct_size, info_size, count; - Msg_s_node *p; - p = (Msg_s_node *)calloc(1, sizeof (Msg_s_node)); - if (!p) { - return (-1); - } - /* LINTED */ - sun_header = (struct msg_info *)addr; - count = sun_header->msg_count; - struct_size = (int)(MSG_STRUCT_SIZE * count); - info_size = (int)(sizeof (struct msg_info)); - p->msg_file_info = sun_header; - /* LINTED */ - p->msg_list = (struct msg_struct *)(((char *)addr) + - info_size); - p->msg_ids = (char *)(((char *)addr) + info_size + - struct_size); - p->msg_strs = (char *)(((char *)addr) + info_size + - struct_size + sun_header->str_count_msgid); - - mnp->msg.sunmsg = p; - mnp->type = T_SUN_MO; -#ifdef GETTEXT_DEBUG - (void) printf("*************** exiting setmo\n"); - printmnp(mnp, 0); -#endif - return (0); - } - /* NOTREACHED */ - case T_GNU_MO: - case T_GNU_SWAPPED_MO: - { - struct gnu_msg_info *gnu_header; - Msg_g_node *p; - p = (Msg_g_node *)calloc(1, sizeof (Msg_g_node)); - if (!p) { - return (-1); - } - /* LINTED */ - gnu_header = (struct gnu_msg_info *)addr; - p->msg_file_info = gnu_header; - if (type == T_GNU_SWAPPED_MO) { - /* - * This MO file has been created on - * the reversed endian system - */ - p->flag |= ST_SWP; - } - /* LINTED */ - p->hash_table = (unsigned int *)(((char *)addr) + - SWAP(p, gnu_header->off_hashtbl)); - - mnp->msg.gnumsg = p; - mnp->type = T_GNU_MO; -#ifdef GETTEXT_DEBUG - (void) printf("*************** exiting setmo\n"); - printmnp(mnp, 0); -#endif - return (0); - } - /* NOTREACHED */ - } - /* NOTREACHED */ - return (0); /* keep gcc happy */ -} - -/* - * setmsg - * - * INPUT - * mnp - message node - * addr - address to the mmapped file - * size - size of the file - * - * RETURN - * 0 - succeeded - * -1 - failed - */ -int -setmsg(Msg_node *mnp, char *addr, size_t size) -{ - struct msg_info *sun_header; - struct gnu_msg_info *gnu_header; - unsigned int first_4bytes; - int mid, count; - int struct_size, struct_size_old; - int msg_struct_size; - - if (size < sizeof (struct msg_info)) { - /* invalid mo file */ - return (setmo(mnp, addr, T_ILL_MO)); - } - - /* LINTED */ - first_4bytes = *((unsigned int *)addr); - if (first_4bytes <= INT_MAX) { - /* candidate for sun mo */ - /* LINTED */ - sun_header = (struct msg_info *)addr; - mid = sun_header->msg_mid; - count = sun_header->msg_count; - msg_struct_size = sun_header->msg_struct_size; - struct_size_old = (int)(OLD_MSG_STRUCT_SIZE * count); - struct_size = (int)(MSG_STRUCT_SIZE * count); - - if ((((count - 1) / 2) == mid) && - ((msg_struct_size == struct_size_old) || - (msg_struct_size == struct_size))) { - /* valid sun mo file */ - return (setmo(mnp, addr, T_SUN_MO)); - } - /* invalid mo file */ - return (setmo(mnp, addr, T_ILL_MO)); - } - - /* checks the GNU MAGIC number */ - if (size < sizeof (struct gnu_msg_info)) { - /* invalid mo file */ - return (setmo(mnp, addr, T_ILL_MO)); - } - - /* LINTED */ - gnu_header = (struct gnu_msg_info *)addr; - if ((gnu_header->magic == GNU_MAGIC) && - (gnu_header->revision == GNU_REVISION)) { - /* GNU mo file */ - return (setmo(mnp, addr, T_GNU_MO)); - } else if ((gnu_header->magic == GNU_MAGIC_SWAPPED) && - (gnu_header->revision == GNU_REVISION_SWAPPED)) { - /* endian-swapped GNU mo file */ - return (setmo(mnp, addr, T_GNU_SWAPPED_MO)); - } - - /* invalid mo file */ - return (setmo(mnp, addr, T_ILL_MO)); -} - /* * mk_msgfile * @@ -236,12 +75,10 @@ setmsg(Msg_node *mnp, char *addr, size_t size) * locale - locale name * domain - domain name * category - category - * locale_len - length of locale name * domain_len - length of domain name * * OUTPUT * mp->msgfile - pathname to the message file is stored - * mp->msgfile_len - length of mp->msgfile without null termination * * RETURN * mp->msgfile is returned @@ -251,19 +88,18 @@ mk_msgfile(struct msg_pack *mp) { char *p, *q; const char *catstr; - size_t cblen, catlen, totallen; + uint32_t cblen, loclen, catlen, totallen; #ifdef GETTEXT_DEBUG - (void) printf("*************** mk_msgfile(0x%p)\n", - (void *)mp); - printmp(mp, 0); + gprintf(0, "*************** mk_msgfile(0x%p)\n", (void *)mp); + printmp(mp, 1); #endif p = mp->msgfile; q = mp->binding; while (*p = *q++) p++; - cblen = (size_t)(p - mp->msgfile); + cblen = (uint32_t)(p - mp->msgfile); if (*(p - 1) != '/') { /* * if the last character of binding @@ -277,15 +113,16 @@ mk_msgfile(struct msg_pack *mp) cblen++; } + loclen = strlen(mp->locale); catstr = category_name[mp->category]; - catlen = (size_t)category_name_len[mp->category]; + catlen = (uint32_t)category_name_len[mp->category]; /* * totallen is the length of the msgfile * pathname excluding a null termination. */ - totallen = cblen + mp->locale_len + 1 + catlen + 1 + - mp->domain_len + MSGFILESUFFIXLEN; + totallen = cblen + loclen + 1 + catlen + 1 + + mp->domain_len + MSGFILESUFFIXLEN; if (totallen >= MAXPATHLEN) return (NULL); @@ -297,141 +134,87 @@ mk_msgfile(struct msg_pack *mp) ; *(p - 1) = '/'; q = mp->domain; + while (*p = *q++) + p++; + q = MSGFILESUFFIX; while (*p++ = *q++) ; - *(p - 1) = '.'; - *p = 'm'; - *(p + 1) = 'o'; - *(p + 2) = '\0'; - - mp->msgfile_len = totallen; #ifdef GETTEXT_DEBUG - (void) printf("*************** Exiting mk_msgfile\n"); - (void) printf("mp->msgfile: \"%s\"\n", mp->msgfile); + gprintf(0, "*************** Exiting mk_msgfile\n"); + gprintf(0, "mp->msgfile: \"%s\"\n", mp->msgfile); #endif return (mp->msgfile); } - /* * check_cache * * INPUT - * cp - may use the following members: - * node_hash - pointer to the Cache_node object having this locale - * * mp - may use the following members: * msgfile - pathname to the message catalog file - * hash_locale - hash id of this locale - * - * OUTPUT - * cp - may update the following members: - * mnp - pointer to a Msg_node object - * cnp - pointer to a Cache_node object - * node_hash - pointer to the Cache_node object having this locale - * cacheline - flag to show if the Cache_node for this locale exists + * hash_domain - hash id of this domain * * RETURN - * 1 - Entry for this message catalog exists in the cache - * 0 - Entry for this message catalog doesn't exist in the cache + * non-NULL + * pointer to the Msg_node object of the current message catalog + * found in the cache + * + * NULL + * this message catalog does not exist in the cache */ -int -check_cache(struct cache_pack *cp, struct msg_pack *mp) +Msg_node * +check_cache(struct msg_pack *mp) { - Msg_node *cur_msg; + Msg_node *cur_msg, *mnp; Gettext_t *gt = global_gt; #ifdef GETTEXT_DEBUG - { - int level = 0; - - (void) printf("*************** check_cache(0x%p, 0x%p)\n", - (void *)cp, (void *)mp); - printcp(cp, 0); - printmp(mp, 0); - } + gprintf(0, "*************** check_cache(0x%p)\n", mp); + printmp(mp, 1); #endif - cur_msg = gt->c_m_node; + cur_msg = gt->c_m_node; /* current Msg_node */ if (cur_msg && - (strcmp(cur_msg->path, mp->msgfile) == 0)) { + cur_msg->hashid == mp->hash_domain && + strcmp(cur_msg->path, mp->msgfile) == 0) { /* * msgfile is the same as the previous message file */ - cp->mnp = cur_msg; - cp->cnp = gt->c_node; - cp->cacheline = 1; -#ifdef GETTEXT_DEBUG - (void) printf("************* exiting check_cache\n"); - (void) printf("cache found\n"); - printmnp(cp->mnp, 0); -#endif - return (1); - } - if (cp->node_hash) { - /* - * already cache_node having the same - * hash id found - */ - cp->cnp = cp->node_hash; - cp->mnp = cp->cnp->m_node; - cp->cacheline = 1; - while (cp->mnp) { - if (strcmp(cp->mnp->path, mp->msgfile) == 0) { #ifdef GETTEXT_DEBUG - (void) printf("************* exiting check_cache\n"); - (void) printf("cache found\n"); - printmnp(cp->mnp, 0); + gprintf(0, "*** cache found\n"); + gprintf(0, "************* exiting check_cache\n"); + printmnp(cur_msg, 1); #endif - return (1); - } - cp->mnp = cp->mnp->next; - } -#ifdef GETTEXT_DEBUG - (void) printf("************* exiting check_cache\n"); - (void) printf("cache not found\n"); -#endif - return (0); + return (cur_msg); } - /* search the cache list */ - cp->cnp = gt->c_node; - cp->mnp = NULL; - while (cp->cnp) { - if (cp->cnp->hashid == mp->hash_locale) { - cp->node_hash = cp->cnp; - cp->mnp = cp->cnp->m_node; - cp->cacheline = 1; - while (cp->mnp) { - if (strcmp(cp->mnp->path, mp->msgfile) == 0) { - /* - * msgfile found in the cache - */ + mnp = gt->m_node; + while (mnp) { #ifdef GETTEXT_DEBUG - (void) printf("************* exiting check_cache\n"); - (void) printf("cache found\n"); - printmnp(cp->mnp, 0); + gprintf(0, "========== descending the list\n"); + gprintf(0, " hashid: %d, hash_domain: %d\n", + mnp->hashid, mp->hash_domain); + printmnp(mnp, 1); #endif - return (1); - } - cp->mnp = cp->mnp->next; - } + if (mnp->hashid == mp->hash_domain && + strcmp(mnp->path, mp->msgfile) == 0) { #ifdef GETTEXT_DEBUG - (void) printf("************* exiting check_cache\n"); - (void) printf("cache not found\n"); + gprintf(0, "*** cache found\n"); + gprintf(0, "******* exiting check_cache\n"); + printmnp(mnp, 1); #endif - return (0); - } else { - cp->cnp = cp->cnp->next; + gt->c_m_node = mnp; + return (mnp); } + mnp = mnp->next; } - cp->cacheline = 0; + #ifdef GETTEXT_DEBUG - (void) printf("************* exiting check_cache\n"); - (void) printf("cache not found\n"); + gprintf(0, "*** cache not found\n"); + gprintf(0, "******* exiting check_cache\n"); #endif - return (0); + return (NULL); } char * @@ -440,174 +223,41 @@ get_codeset(const char *domain) char *codeset; #ifdef GETTEXT_DEBUG - (void) printf("*************** get_codeset(\"%s\")\n", - domain ? domain : "(null)"); + gprintf(0, "*************** get_codeset(\"%s\")\n", + domain ? domain : "(null)"); #endif codeset = _real_bindtextdomain_u(domain, NULL, TP_CODESET); - if (!codeset) { + if (codeset == NULL) { /* no codeset is bound to this domain */ codeset = nl_langinfo(CODESET); } #ifdef GETTEXT_DEBUG - (void) printf("*************** existing get_codeset(\"%s\")\n", - domain ? domain : "(null)"); - (void) printf(" = \"%s\"\n", codeset); + gprintf(0, "*************** existing get_codeset(\"%s\")\n", + domain ? domain : "(null)"); + gprintf(0, " = \"%s\"\n", codeset); #endif return (codeset); } -void -connect_entry(struct cache_pack *cp) -{ - Gettext_t *gt = global_gt; - -#ifdef GETTEXT_DEBUG - (void) printf("*************** connect_entry(0x%p)\n", - (void *)cp); - printcp(cp, 0); -#endif - - if (cp->cacheline) { - if (cp->cnp->m_last) - cp->cnp->m_last->next = cp->mnp; - else - cp->cnp->m_node = cp->mnp; - cp->cnp->m_last = cp->mnp; - } else { - if (gt->c_last) - gt->c_last->next = cp->cnp; - else - gt->c_node = cp->cnp; - gt->c_last = cp->cnp; - } - gt->c_m_node = cp->mnp; -} - -int -connect_invalid_entry(struct cache_pack *cp, struct msg_pack *mp) -{ -#ifdef GETTEXT_DEBUG - (void) printf("*************** connect_invalid_entry(0x%p, 0x%p)\n", - (void *)cp, (void *)mp); - printcp(cp, 0); - printmp(mp, 0); -#endif - - cp->mnp = create_mnp(mp); - if (!cp->mnp) { - return (-1); - } - - if (!cp->cacheline) { - cp->cnp = create_cnp(cp->mnp, mp); - if (!cp->cnp) { - free_mnp_mp(cp->mnp, mp); - return (-1); - } - } - cp->mnp->type = T_ILL_MO; - connect_entry(cp); - - return (0); -} - -Msg_node * -create_mnp(struct msg_pack *mp) -{ - Msg_node *mnp; - char *s; - size_t msglen; - -#ifdef GETTEXT_DEBUG - (void) printf("*************** create_mnp(0x%p)\n", (void *)mp); - printmp(mp, 0); -#endif - - mnp = (Msg_node *)calloc(1, sizeof (Msg_node)); - if (!mnp) { - return (NULL); - } - msglen = mp->msgfile_len; - s = (char *)malloc(msglen + 1); - if (!s) { - free(mnp); - return (NULL); - } - (void) memcpy(s, mp->msgfile, msglen + 1); - mnp->path = s; - return (mnp); -} - -Cache_node * -create_cnp(Msg_node *mnp, struct msg_pack *mp) -{ - Cache_node *cnp; - -#ifdef GETTEXT_DEBUG - (void) printf("*************** create_cnp(0x%p, 0x%p)\n", - (void *)mnp, (void *)mp); - printmnp(mnp, 0); - printmp(mp, 0); -#endif - - cnp = (Cache_node *)calloc(1, sizeof (Cache_node)); - if (!cnp) { - return (NULL); - } - cnp->hashid = mp->hash_locale; - cnp->m_node = mnp; - cnp->m_last = mnp; - - return (cnp); -} - -void -free_mnp_mp(Msg_node *mnp, struct msg_pack *mp) -{ -#ifdef GETTEXT_DEBUG - (void) printf("*************** free_mnp_mp(0x%p, 0x%p)\n", - (void *)mnp, (void *)mp); - printmnp(mnp, 0); - printmp(mp, 0); -#endif - - if (mnp) { - if (mnp->path) - free(mnp->path); - switch (mnp->type) { - case T_SUN_MO: - free(mnp->msg.sunmsg); - break; - case T_GNU_MO: - free(mnp->msg.gnumsg); - break; - } - free(mnp); - } - if (mp->addr != (caddr_t)-1) { - (void) munmap(mp->addr, mp->fsz); - } -} - /* - * get_hashid + * get_hashid (hashpjw) * * Calculates the hash value from the specified string. * Actual hashid will be mod(hash value, PRIME_NUMBER). * - * hashpjw * Ref: Compilers - Principles, Techniques, and Tools * Aho, Sethi, and Ullman */ -unsigned int -get_hashid(const char *str, size_t *len) +uint32_t +get_hashid(const char *str, uint32_t *len) { - const char *p; - unsigned int h = 0, g; + const unsigned char *p = (unsigned char *)str; + uint32_t h = 0; + uint32_t g; - for (p = str; *p; p++) { + for (; *p; p++) { h = (h << 4) + *p; g = h & 0xf0000000; if (g) { @@ -615,22 +265,117 @@ get_hashid(const char *str, size_t *len) h = h ^ g; } } + if (len) - *len = (size_t)(p - str); + *len = (uint32_t)(p - (unsigned char *)str); return (h); } -unsigned int -doswap32(unsigned int n) +uint32_t +doswap32(uint32_t n) { - unsigned int r; + uint32_t r; r = (n << 24) | ((n & 0xff00) << 8) | - ((n >> 8) & 0xff00) | (n >> 24); + ((n >> 8) & 0xff00) | (n >> 24); return (r); } #ifdef GETTEXT_DEBUG +static uint32_t +search_msg(Msg_g_node *p, const char *id, uint32_t hash_val, + struct gnu_msg_ent *m) +{ + char *base = (char *)p->msg_file_info; + uint32_t hash_size, num_of_str, i, idx, inc; + char *ms; + + num_of_str = p->num_of_str; + hash_size = p->hash_size; + idx = hash_val % hash_size; + inc = 1 + (hash_val % (hash_size - 2)); + + while ((i = p->hash_table[idx]) != 0) { + ms = (i <= num_of_str) ? + base + SWAP(p, m[i-1].offset) : + p->mchunk + p->d_msg[MSGID][i-num_of_str-1].offset; + if (strcmp(id, ms) == 0) { + /* found */ + return (i); + } + idx = (idx + inc) % hash_size; + } + /* not found */ + return (0); +} + +void +print_rev1_info(Msg_g_node *p) +{ + char *base = (char *)p->msg_file_info; + struct gnu_msg_info *header = p->msg_file_info; + struct gnu_msg_ent *m; + uint32_t hv, hidx; + char *ms; + enum gnu_msgidstr v; + int x; + +#ifdef GETTEXT_DEBUG_DYMMSG + gprintf(0, "******** dynamic msgid/msgstr\n"); + for (v = MSGID; v <= MSGSTR; v++) { + for (x = 0; x < p->num_of_d_str; x++) { + gprintf(0, "len: %u\n", p->d_msg[v][x].len); + gprintf(0, "str: \"%s\"\n", + p->mchunk + p->d_msg[v][x].offset); + } + } +#endif +#ifdef GETTEXT_DEBUG_HASHTBL + gprintf(0, "******** dynamic hash table\n"); + for (x = 0; x < p->hash_size; x++) { + gprintf(0, "%d: %u\n", x, p->hash_table[x]); + } +#endif +#ifdef GETTEXT_DEBUG_CHECK_STMSGID + gprintf(0, "******** sanity check of static msgid\n"); + m = (struct gnu_msg_ent *)(uintptr_t) + (base + SWAP(p, header->off_msgid_tbl)); + for (x = 0; x < p->num_of_str; x++) { + ms = base + SWAP(p, m[x].offset); + gprintf(0, "\"%s\"\n", ms); + hv = get_hashid(ms, NULL); + hidx = search_msg(p, ms, hv, m); + if (hidx == 0) { + gprintf(0, + "failed to find this msg in the hash table\n"); + } else { + if (hidx != x + 1) { + gprintf(0, "hash table mismatch\n"); + } + } + } +#endif +#ifdef GETTEXT_DEBUG_CHECK_DYMMSGID + gprintf(0, "******* sanity check of dynamic msgid\n"); + m = (struct gnu_msg_ent *)(uintptr_t) + (base + SWAP(p, header->off_msgid_tbl)); + for (x = 0; x < p->num_of_d_str; x++) { + ms = p->mchunk + p->d_msg[MSGID][x].offset; + gprintf(0, "\"%s\"\n", ms); + hv = get_hashid(ms, NULL); + hidx = search_msg(p, ms, hv, m); + if (hidx == 0) { + gprintf(0, + "failed to find this msg in the hash table\n"); + } else { + if (hidx != x + p->num_of_str + 1) { + gprintf(0, "hash table mismatch\n"); + } + } + } +#endif +} + void gprintf(int level, const char *format, ...) { @@ -638,11 +383,13 @@ gprintf(int level, const char *format, ...) va_start(ap, format); - while (level-- >= 0) { + while (level-- > 0) { (void) fputs(" ", stdout); } (void) vprintf(format, ap); va_end(ap); + + (void) fflush(stdout); } void @@ -651,19 +398,19 @@ printlist(void) struct domain_binding *ppp; Gettext_t *gt = global_gt; - (void) printf("=== Printing default list and regural list\n"); - (void) printf(" Default domain=<%s>, binding=<%s>\n", + gprintf(0, "=== Printing default list and regural list\n"); + gprintf(0, " Default domain=<%s>, binding=<%s>\n", DEFAULT_DOMAIN, defaultbind); ppp = FIRSTBIND(gt); while (ppp) { - (void) printf( - " domain=<%s>, binding=<%s>, codeset=<%s>\n", + gprintf(0, " domain=<%s>, binding=<%s>, codeset=<%s>\n", ppp->domain ? ppp->domain : "(null)", - ppp->binding ? ppp->binding : "(null)", - ppp->codeset ? ppp->codeset : "(null)"); + ppp->binding ? ppp->binding : "(null)", + ppp->codeset ? ppp->codeset : "(null)"); ppp = ppp->next; } + (void) fflush(stdout); } void @@ -671,27 +418,30 @@ printmp(struct msg_pack *mp, int level) { gprintf(level, "=== mp ===\n"); gprintf(level, " msgid1: \"%s\"\n", - mp->msgid1 ? mp->msgid1 : "(null)"); + mp->msgid1 ? mp->msgid1 : "(null)"); gprintf(level, " msgid2: \"%s\"\n", - mp->msgid2 ? mp->msgid2 : "(null)"); - gprintf(level, " n: %d\n", mp->n); - gprintf(level, " plural: %d\n", mp->plural); - gprintf(level, " category: \"%s\"\n", - category_name[mp->category]); + mp->msgid2 ? mp->msgid2 : "(null)"); + gprintf(level, " msgfile: \"%s\"\n", + mp->msgfile ? mp->msgfile : "(null)"); gprintf(level, " domain: \"%s\"\n", - mp->domain ? mp->domain : "(null)"); + mp->domain ? mp->domain : "(null)"); gprintf(level, " binding: \"%s\"\n", - mp->binding ? mp->binding : "(null)"); - gprintf(level, " msgfile: \"%s\"\n", - mp->msgfile ? mp->msgfile : "(null)"); + mp->binding ? mp->binding : "(null)"); gprintf(level, " locale: \"%s\"\n", - mp->locale ? mp->locale : "(null)"); + mp->locale ? mp->locale : "(null)"); gprintf(level, " language: \"%s\"\n", - mp->language ? mp->language : "(null)"); - gprintf(level, " hash_locale: %d\n", mp->hash_locale); + mp->language ? mp->language : "(null)"); gprintf(level, " addr: 0x%p\n", mp->addr); gprintf(level, " fsz: %d\n", mp->fsz); + gprintf(level, " hash_domain: %d\n", mp->hash_domain); + gprintf(level, " domain_len: %d\n", mp->domain_len); + gprintf(level, " n: %d\n", mp->n); + gprintf(level, " category: \"%s\"\n", + category_name[mp->category]); + gprintf(level, " plural: %d\n", mp->plural); + gprintf(level, " nlsp: %d\n", mp->nlsp); gprintf(level, " trusted: %d\n", mp->trusted); + gprintf(level, " status: %d\n", mp->status); } void @@ -699,73 +449,94 @@ printsunmsg(Msg_s_node *smnp, int level) { gprintf(level, "=== sunmsg ===\n"); gprintf(level, " msg_file_info: 0x%p\n", - (void *)smnp->msg_file_info); + (void *)smnp->msg_file_info); gprintf(level, " msg_mid: %d\n", - smnp->msg_file_info->msg_mid); + smnp->msg_file_info->msg_mid); gprintf(level, " msg_count: %d\n", - smnp->msg_file_info->msg_count); + smnp->msg_file_info->msg_count); gprintf(level, " str_count_msgid: %d\n", - smnp->msg_file_info->str_count_msgid); + smnp->msg_file_info->str_count_msgid); gprintf(level, " str_count_msgstr: %d\n", - smnp->msg_file_info->str_count_msgstr); + smnp->msg_file_info->str_count_msgstr); gprintf(level, " msg_struct_size: %d\n", - smnp->msg_file_info->msg_struct_size); + smnp->msg_file_info->msg_struct_size); gprintf(level, " msg_list: 0x%p\n", - (void *)smnp->msg_list); + (void *)smnp->msg_list); gprintf(level, " msg_ids: 0x%p\n", - (void *)smnp->msg_ids); + (void *)smnp->msg_ids); gprintf(level, " msg_strs: 0x%p\n", - (void *)smnp->msg_strs); + (void *)smnp->msg_strs); } void printgnumsg(Msg_g_node *gmnp, int level) { gprintf(level, "=== gnumsg ===\n"); - gprintf(level, " msg_file_info: 0x%p\n", - (void *)gmnp->msg_file_info); + gprintf(level, " msg_file_info: 0x%p\n", gmnp->msg_file_info); gprintf(level, " magic: 0x%x\n", - gmnp->msg_file_info->magic); + gmnp->msg_file_info->magic); gprintf(level, " revision: %d\n", - SWAP(gmnp, gmnp->msg_file_info->revision)); + SWAP(gmnp, gmnp->msg_file_info->revision)); gprintf(level, " num_of_str: %d\n", - SWAP(gmnp, gmnp->msg_file_info->num_of_str)); + SWAP(gmnp, gmnp->msg_file_info->num_of_str)); gprintf(level, " off_msgid_tbl: %d\n", - SWAP(gmnp, gmnp->msg_file_info->off_msgid_tbl)); + SWAP(gmnp, gmnp->msg_file_info->off_msgid_tbl)); gprintf(level, " off_msgstr_tbl: %d\n", - SWAP(gmnp, gmnp->msg_file_info->off_msgstr_tbl)); + SWAP(gmnp, gmnp->msg_file_info->off_msgstr_tbl)); gprintf(level, " sz_hashtbl: %d\n", - SWAP(gmnp, gmnp->msg_file_info->sz_hashtbl)); + SWAP(gmnp, gmnp->msg_file_info->sz_hashtbl)); gprintf(level, " off_hashtbl: %d\n", - SWAP(gmnp, gmnp->msg_file_info->off_hashtbl)); - gprintf(level, " hash_table: 0x%p\n", - (void *)gmnp->hash_table); - gprintf(level, " header_flag: %08x\n", - gmnp->header_flag); + SWAP(gmnp, gmnp->msg_file_info->off_hashtbl)); + if (gmnp->flag & ST_REV1) { + struct gnu_msg_rev1_info *a = + (struct gnu_msg_rev1_info *)(uintptr_t) + ((char *)gmnp->msg_file_info + + sizeof (struct gnu_msg_info)); + gprintf(level, " num_of_dynamic_macro: %d\n", + SWAP(gmnp, a->num_of_dynamic_macro)); + gprintf(level, " off_dynamic_macro: %d\n", + SWAP(gmnp, a->off_dynamic_macro)); + gprintf(level, " num_of_dynamic_str: %d\n", + SWAP(gmnp, a->num_of_dynamic_str)); + gprintf(level, " off_dynamic_msgid_tbl: %d\n", + SWAP(gmnp, a->off_dynamic_msgid_tbl)); + gprintf(level, " off_dynamic_msgstr_tbl: %d\n", + SWAP(gmnp, a->off_dynamic_msgstr_tbl)); + } + gprintf(level, " fsize: %lu\n", gmnp->fsize); + gprintf(level, " flag: %08x\n", gmnp->flag); + gprintf(level, " num_of_str: %u\n", gmnp->num_of_str); + gprintf(level, " num_of_d_str: %u\n", gmnp->num_of_d_str); + gprintf(level, " hash_size: %u\n", gmnp->hash_size); + gprintf(level, " hash_table: 0x%p\n", (void *)gmnp->hash_table); + gprintf(level, " d_msgid: 0x%p\n", (void *)gmnp->d_msg[MSGID]); + gprintf(level, " d_msgstr: 0x%p\n", (void *)gmnp->d_msg[MSGSTR]); + gprintf(level, " mchunk: 0x%p\n", (void *)gmnp->mchunk); + gprintf(level, " src_encoding: \"%s\"\n", - gmnp->src_encoding ? gmnp->src_encoding : "(null)"); + gmnp->src_encoding ? gmnp->src_encoding : "(null)"); gprintf(level, " dst_encoding: \"%s\"\n", - gmnp->dst_encoding ? gmnp->dst_encoding : "(null)"); + gmnp->dst_encoding ? gmnp->dst_encoding : "(null)"); gprintf(level, " nplurals: %d\n", - gmnp->nplurals); + gmnp->nplurals); gprintf(level, " plural: 0x%p\n", - (void *)gmnp->plural); + (void *)gmnp->plural); if (gmnp->plural) printexpr(gmnp->plural, level+1); gprintf(level, " fd: 0x%p\n", (void *)gmnp->fd); gprintf(level, " conv_msgstr: 0x%p\n", - (void *)gmnp->conv_msgstr); + (void *)gmnp->conv_msgstr); } void printexpr(struct expr *e, int level) { static const char *op_name[] = { - "NULL", "INIT", "EXP", - "NUM", "VAR", "?", ":", "||", - "&&", "==", "!=", ">", "<", - ">=", "<=", "+", "-", "*", "/", - "%", "!", "(", ")", "ERR" + "NULL", "INIT", "EXP", + "NUM", "VAR", "?", ":", "||", + "&&", "==", "!=", ">", "<", + ">=", "<=", "+", "-", "*", "/", + "%", "!", "(", ")", "ERR" }; switch (GETOPNUM(e->op)) { case 0: @@ -803,15 +574,16 @@ printmnp(Msg_node *mnp, int level) { gprintf(level, "=== mnp ===\n"); + gprintf(level, " hashid: %d\n", mnp->hashid); gprintf(level, " type: \"%s\"\n", - mnp->type == T_ILL_MO ? "T_ILL_MO" : - mnp->type == T_SUN_MO ? "T_SUN_MO" : - mnp->type == T_GNU_MO ? "T_GNU_MO" : - "UNKNOWN TYPE"); + mnp->type == T_ILL_MO ? "T_ILL_MO" : + mnp->type == T_SUN_MO ? "T_SUN_MO" : + mnp->type == T_GNU_MO ? "T_GNU_MO" : + "UNKNOWN TYPE"); gprintf(level, " path: \"%s\"\n", - mnp->path ? mnp->path : "(null)"); + mnp->path ? mnp->path : "(null)"); gprintf(level, " msg_file_trusted: %d\n", - mnp->trusted); + mnp->trusted); if (mnp->type == T_SUN_MO) printsunmsg(mnp->msg.sunmsg, level+1); else if (mnp->type == T_GNU_MO) @@ -820,34 +592,58 @@ printmnp(Msg_node *mnp, int level) } void -printcnp(Cache_node *cnp, int level) +printnls(Nls_node *n, int level) { - gprintf(level, "=== cnp ===\n"); - - gprintf(level, " hashid: %d\n", cnp->hashid); - gprintf(level, " m_node: 0x%p\n", (void *)cnp->m_node); - if (cnp->m_node) - printmnp(cnp->m_node, level+1); - gprintf(level, " m_last: 0x%p\n", (void *)cnp->m_last); - if (cnp->m_last) - printmnp(cnp->m_last, level+1); - gprintf(level, " n_node: 0x%p\n", (void *)cnp->n_node); - gprintf(level, " next: 0x%p\n", (void *)cnp->next); + gprintf(level, "=== nls ===\n"); + gprintf(level, " domain: \"%s\"\n", n->domain ? n->domain : "NULL"); + gprintf(level, " locale: \"%s\"\n", n->locale ? n->locale : "NULL"); + gprintf(level, " nlspath: \"%s\"\n", n->nlspath ? n->nlspath : + "NULL"); + gprintf(level, " next: 0x%p\n", n->next); } void -printcp(struct cache_pack *cp, int level) +printdbind(Dbinding *d, int level) { - gprintf(level, "=== cp ===\n"); - gprintf(level, " cacheline: %d\n", cp->cacheline); - gprintf(level, " mnp: 0x%p\n", (void *)cp->mnp); - if (cp->mnp) - printmnp(cp->mnp, level+1); - gprintf(level, " cnp: 0x%p\n", (void *)cp->cnp); - if (cp->cnp) - printcnp(cp->cnp, level+1); - gprintf(level, " node_hash: 0x%p\n", (void *)cp->node_hash); - if (cp->node_hash) - printcnp(cp->node_hash, level+1); + gprintf(level, "=== dbind ===\n"); + gprintf(level, " domain: \"%s\"\n", d->domain ? d->domain : "NULL"); + gprintf(level, " binding: \"%s\"\n", d->binding ? d->binding : + "NULL"); + gprintf(level, " codeset: \"%s\"\n", d->codeset ? d->codeset : + "NULL"); + gprintf(level, " next: 0x%p\n", d->next); } + +void +printgt(Gettext_t *gt, int level) +{ + gprintf(level, "=== gt ===\n"); + gprintf(level, " cur_domain: \"%s\"\n", gt->cur_domain); + if (gt->dbind) { + printdbind(gt->dbind, level+1); + } else { + gprintf(level, " dbind: NULL\n"); + } + if (gt->m_node) { + printmnp(gt->m_node, level + 1); + } else { + gprintf(level, " m_node: NULL\n"); + } + if (gt->n_node) { + printnls(gt->n_node, level + 1); + } else { + gprintf(level, " n_node: NULL\n"); + } + if (gt->c_m_node) { + printmnp(gt->c_m_node, level + 1); + } else { + gprintf(level, " c_m_node: NULL\n"); + } + if (gt->c_n_node) { + printnls(gt->c_n_node, level + 1); + } else { + gprintf(level, " c_n_node: NULL\n"); + } +} + #endif diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers index 9c4a04b8a7..54c8ad230a 100644 --- a/usr/src/lib/libc/port/mapfile-vers +++ b/usr/src/lib/libc/port/mapfile-vers @@ -33,6 +33,9 @@ # SUNW_1.23 { # SunOS 5.11 (Solaris 11) + global: + _nl_domain_bindings; + _nl_msg_cat_cntr; protected: addrtosymstr; aio_cancel; |