Пример #1
0
/*
 * gnu_msgsearch
 *
 * Searchs the translation message for the specified msgid1.
 * Hash algorithm used in this function is Open Addressing
 * with Double Hashing:
 * H(k, i) = (H1(k) + i * H2(k)) mod M
 * H1(k) = hashvalue % M
 * H2(k) = 1 + (hashvalue % (M - 2))
 *
 * Ref: The Art of Computer Programming Volume 3
 * Sorting and Searching, second edition
 * Donald E Knuth
 */
static char *
gnu_msgsearch(Msg_g_node *gmnp, const char *msgid1,
	size_t *msgstrlen, unsigned int *midx)
{
	unsigned int	*hash_table;
	struct gnu_msg_ent	*msgid_tbl, *msgstr_tbl;
	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;

	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);
	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

	if (!hash_table || (hash_size <= 2)) {
		/*
		 * No hash table exists or
		 * hash size is enough small
		 */
		unsigned int	top, bottom;
		char	*msg_id_str;
		int	val;

		top = 0;
		bottom = num_of_str;
		while (top < bottom) {
			idx = (top + bottom) / 2;
			msg_id_str = base +
				SWAP(gmnp, msgid_tbl[idx].offset);

			val = strcmp(msg_id_str, msgid1);
			if (val < 0) {
				top = idx + 1;
			} else if (val > 0) {
				bottom = idx;
			} else {
				goto found;
			}
		}
		/* not found */
		return ((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));

	for (;;) {
		offset = SWAP(gmnp, hash_table[hash_idx]);

		if (offset == 0) {
			return ((char *)msgid1);
		}

		idx = offset - 1;
		if ((msglen <= SWAP(gmnp, msgid_tbl[idx].len)) &&
			strcmp(msgid1, base +
			SWAP(gmnp, msgid_tbl[idx].offset)) == 0) {
			/* found */
			goto found;
		}

		hash_idx = (hash_idx + hash_inc) % hash_size;
	}
	/* NOTREACHED */

found:
	if (msgstrlen)
		*msgstrlen = SWAP(gmnp, msgstr_tbl[idx].len) + 1;
	if (midx)
		*midx = idx;
	return (base + SWAP(gmnp, msgstr_tbl[idx].offset));
}
Пример #2
0
char *
_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	mydomain[TEXTDOMAINMAX + 1]; /* 256 + 1 */
	char	*cur_binding;	/* points to current binding in list */
	char	*cur_locale, *cur_domain, *result, *nlspath;
	char	*msgloc, *cb, *cur_domain_binding;
	char	*language;
	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;

#ifdef GETTEXT_DEBUG
	gprintf(0, "*************** _real_gettext_u(\"%s\", \"%s\", "
	    "\"%s\", %d, %d, %d)\n",
	    domain ? domain : "NULL", msgid1 ? msgid1 : "NULL",
	    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);

	mp = memset(&omp, 0, sizeof (omp));	/* msg pack */

	/*
	 * category may be LC_MESSAGES or LC_TIME
	 * locale contains the value of 'category'
	 */
	cur_locale = setlocale(category, NULL);

	language = getenv("LANGUAGE"); /* for GNU */
	if (language) {
		if (!*language || strchr(language, '/') != NULL) {
			/*
			 * LANGUAGE is an empty string or
			 * LANGUAGE contains '/'.
			 * Ignore it.
			 */
			language = NULL;
		}
	}

	/*
	 * Query the current domain if domain argument is NULL pointer
	 */
	mydomain[0] = '\0';
	if (domain == NULL) {
		/*
		 * if NULL is specified for domainname,
		 * use the currently bound domain.
		 */
		cur_domain = _textdomain_u(NULL, mydomain);
	} else if (!*domain) {
		/*
		 * if an empty string is specified
		 */
		cur_domain = DEFAULT_DOMAIN;
	} else {
		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 == 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.
			 */
			DFLTMSG(result, msgid1, msgid2, n, plural);
			return (result);
		}
		nlspath = NULL;
	} else {
		/* NLSPATH is set */
		int	ret;

		msgloc = setlocale(LC_MESSAGES, NULL);

		ret = process_nlspath(cur_domain, msgloc,
		    (const char *)nlspath, &cur_binding);
		if (ret == -1) {
			/* error occurred */
			DFLTMSG(result, msgid1, msgid2, n, plural);
			return (result);
		} else if (ret == 0) {
			nlspath = NULL;
		}
	}

	cur_domain_binding = _real_bindtextdomain_u(cur_domain,
	    NULL, TP_BINDING);
	if (cur_domain_binding == NULL) {
		DFLTMSG(result, msgid1, msgid2, n, plural);
		return (result);
	}

	mp->msgid1 = msgid1;
	mp->msgid2 = msgid2;
	mp->msgfile = msgfile;
	mp->domain = cur_domain;
	mp->binding = cur_domain_binding;
	mp->locale = cur_locale;
	mp->language = language;
	mp->domain_len = cur_domain_len;
	mp->n = n;
	mp->category = category;
	mp->plural = plural;
	mp->hash_domain = hash_domain;

	/*
	 * Spec1170 requires that we use NLSPATH if it's defined, to
	 * override any system default variables.  If NLSPATH is not
	 * defined or if a message catalog is not found in any of the
	 * components (bindings) specified by NLSPATH, dcgettext_u() will
	 * search for the message catalog in either a) the binding path set
	 * by any previous application calls to bindtextdomain() or
	 * b) the default binding path (/usr/lib/locale).  Save the original
	 * binding path so that we can search it if the message catalog
	 * is not found via NLSPATH.  The original binding is restored before
	 * returning from this routine because the gettext routines should
	 * not change the binding set by the application.  This allows
	 * bindtextdomain() to be called once for all gettext() calls in the
	 * application.
	 */

	/*
	 * First, examine NLSPATH
	 */
	if (nlspath) {
		/*
		 * NLSPATH binding has been successfully built
		 */
#ifdef GETTEXT_DEBUG
		gprintf(0, "************************** examining NLSPATH\n");
		gprintf(0, "       cur_binding: \"%s\"\n",
		    cur_binding ? cur_binding : "(null)");
#endif

		mp->nlsp = 1;
		/*
		 * cur_binding always ends with ':' before a null
		 * termination.
		 */
		while (*cur_binding) {
			cb = cur_binding;
			while (*cur_binding != ':')
				cur_binding++;
			cblen = cur_binding - cb;
			cur_binding++;
			if (cblen >= MAXPATHLEN) {
				/* cur_binding too long */
				DFLTMSG(result, msgid1, msgid2, n, plural);
				return (result);
			}

			(void) memcpy(mp->msgfile, cb, cblen);
			*(mp->msgfile + cblen) = '\0';

#ifdef GETTEXT_DEBUG
			gprintf(0, "*******************"
			    "********************* \n");
			gprintf(0, "       msgfile: \"%s\"\n",
			    msgfile ? msgfile : "(null)");
			gprintf(0, "*******************"
			    "********************* \n");
#endif
			result = handle_mo(mp);
			if (result) {
				return (result);
			}
		}
	}

	mp->nlsp = 0;
	mp->binding = cur_domain_binding;
	/*
	 * Next, examine LANGUAGE
	 */
	if (language) {
		char	*ret_msg;
		ret_msg = handle_lang(mp);
		if (ret_msg != NULL) {
			/* valid msg found in GNU MO */
			return (ret_msg);
		}
		/*
		 * handle_lang() may have overridden locale
		 */
		mp->locale = cur_locale;
		mp->status = 0;
	}

	/*
	 * Finally, handle a single binding
	 */
#ifdef GETTEXT_DEBUG
	*mp->msgfile = '\0';
#endif
	if (mk_msgfile(mp) == NULL) {
		DFLTMSG(result, msgid1, msgid2, n, plural);
		return (result);
	}

	result = handle_mo(mp);
	if (result) {
		return (result);
	}
	DFLTMSG(result, msgid1, msgid2, n, plural);
	return (result);
} /* _real_gettext_u */
Пример #3
0
/*
 * handle_lang
 *
 * take care of the LANGUAGE specification
 */
char *
handle_lang(struct cache_pack *cp, 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;

#ifdef GETTEXT_DEBUG
	(void) printf("*************** handle_lang(0x%p, 0x%p)\n",
		(void *)cp, (void *)mp);
	printcp(cp, 0);
	printmp(mp, 0);
#endif

	p = mp->language;

	while (*p) {
		op = p;
		q = strchr(p, ':');
		if (!q) {
			locale_len = strlen(p);
			p += locale_len;
		} else {
			locale_len = q - p;
			p += locale_len + 1;
		}
		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
		if (mk_msgfile(mp) == NULL) {
			/* illegal locale name */
			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);
			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 */
	}

out_loop:
	if (gnu_mo_found) {
		DFLTMSG(result, mp->msgid1, mp->msgid2, mp->n, mp->plural);
		free(locale);
		return (result);
	}
	if (locale)
		free(locale);
	return (NULL);
}