usr/src/lib/libc/port/gen/catopen.c
changeset 0 68f95e015346
child 6812 febeba71273d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libc/port/gen/catopen.c	Tue Jun 14 00:00:00 2005 -0700
@@ -0,0 +1,336 @@
+/*
+ * 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.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * catopen.c
+ *
+ */
+
+#pragma weak catopen = _catopen
+#pragma weak catclose = _catclose
+
+#include "synonyms.h"
+#include "libc.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <nl_types.h>
+#include <locale.h>
+#include <limits.h>
+#include <errno.h>
+#include "../i18n/_loc_path.h"
+#include "nlspath_checks.h"
+
+#define	SAFE_F		1
+#define	UNSAFE_F	0
+
+static char *
+replace_nls_option(char *, char *, char *, char *, char *, char *, char *);
+static nl_catd file_open(const char *, int);
+static nl_catd process_nls_path(char *, int);
+
+nl_catd
+_catopen(const char *name, int oflag)
+{
+	nl_catd p;
+
+	if (!name) {				/* Null pointer */
+		errno = EFAULT;
+		return ((nl_catd)-1);
+	} else if (!*name) {		/* Empty string */
+		errno = ENOENT;
+		return ((nl_catd)-1);
+	} else if (strchr(name, '/') != NULL) {
+		/* If name contains '/', then it is complete file name */
+		p = file_open(name, SAFE_F);
+	} else {				/* Normal case */
+		p = process_nls_path((char *)name, oflag);
+	}
+
+	if (p == NULL) {  /* Opening catalog file failed */
+		return ((nl_catd)-1);
+	} else {
+		return (p);
+	}
+}
+
+
+/*
+ * This routine will process NLSPATH environment variable.
+ * It will return catd id whenever it finds valid catalog.
+ */
+static nl_catd
+process_nls_path(char *name, int oflag)
+{
+	char	*s, *s1, *s2, *t;
+	char	*nlspath, *lang, *territory, *codeset, *locale;
+	char	pathname[PATH_MAX + 1];
+	nl_catd	p;
+
+	/*
+	 * locale=language_territory.codeset
+	 * XPG4 uses LC_MESSAGES.
+	 * XPG3 uses LANG.
+	 * From the following two lines, choose one depending on XPG3 or 4.
+	 *
+	 * Chose XPG4. If oflag == NL_CAT_LOCALE, use LC_MESSAGES.
+	 */
+	if (oflag == NL_CAT_LOCALE)
+		locale = setlocale(LC_MESSAGES, NULL);
+	else
+		locale = getenv("LANG");
+
+	nlspath = getenv("NLSPATH");
+	lang = NULL;
+	if (nlspath) {
+		territory = NULL;
+		codeset = NULL;
+		/*
+		 * extract lang, territory and codeset from locale name
+		 */
+		if (locale) {
+			lang = s = libc_strdup(locale);
+			if (!lang) {
+				/* strdup failed */
+				return (NULL);
+			}
+			s1 = s2 = NULL;
+			while (s && *s) {
+				if (*s == '_') {
+					s1 = s;
+					*s1++ = NULL;
+				} else if (*s == '.') {
+					s2 = s;
+					*s2++ = NULL;
+				}
+				s++;
+			}
+			territory = s1;
+			codeset   = s2;
+		} /* if (locale) */
+
+		/*
+		 * March through NLSPATH until finds valid cat file
+		 */
+		s = nlspath;
+		while (*s) {
+			if (*s == ':') {
+				/* unqualified pathname is unsafe */
+				p = file_open(name, UNSAFE_F);
+				if (p != NULL) {
+					if (lang)
+						libc_free(lang);
+					return (p);
+				}
+				++s;
+				continue;
+			}
+
+			/* replace Substitution field */
+			s = replace_nls_option(s, name, pathname, locale,
+						lang, territory, codeset);
+
+			p = file_open(pathname, UNSAFE_F);
+			if (p != NULL) {
+				if (lang)
+					libc_free(lang);
+				return (p);
+			}
+			if (*s)
+				++s;
+		} /* while */
+	} /* if (nlspath) */
+
+	/* lang is not used any more, free it */
+	if (lang)
+		libc_free(lang);
+
+	/*
+	 * Implementation dependent default location of XPG3.
+	 * We use /usr/lib/locale/<locale>/LC_MESSAGES/%N.
+	 * If C locale, do not translate message.
+	 */
+	if (locale == NULL) {
+		return (NULL);
+	} else if (locale[0] == 'C' && locale[1] == '\0') {
+		p = libc_malloc(sizeof (struct _nl_catd_struct));
+		if (p == NULL) {
+			/* malloc failed */
+			return (NULL);
+		}
+		p->__content = NULL;
+		p->__size = 0;
+		p->__trust = 1;
+		return (p);
+	}
+
+	s = _DFLT_LOC_PATH;
+	t = pathname;
+	while (*t++ = *s++)
+		continue;
+	t--;
+	s = locale;
+	while (*s && t < pathname + PATH_MAX)
+		*t++ = *s++;
+	s = "/LC_MESSAGES/";
+	while (*s && t < pathname + PATH_MAX)
+		*t++ = *s++;
+	s = name;
+	while (*s && t < pathname + PATH_MAX)
+		*t++ = *s++;
+	*t = NULL;
+	return (file_open(pathname, SAFE_F));
+}
+
+
+/*
+ * This routine will replace substitution parameters in NLSPATH
+ * with appropiate values. Returns expanded pathname.
+ */
+static char *
+replace_nls_option(char *s, char *name, char *pathname, char *locale,
+	char *lang, char *territory, char *codeset)
+{
+	char	*t, *u;
+
+	t = pathname;
+	while (*s && *s != ':') {
+		if (t < pathname + PATH_MAX) {
+			/*
+			 * %% is considered a single % character (XPG).
+			 * %L : LC_MESSAGES (XPG4) LANG(XPG3)
+			 * %l : The language element from the current locale.
+			 *	(XPG3, XPG4)
+			 */
+			if (*s != '%')
+				*t++ = *s;
+			else if (*++s == 'N') {
+				u = name;
+				while (*u && t < pathname + PATH_MAX)
+					*t++ = *u++;
+			} else if (*s == 'L') {
+				if (locale) {
+					u = locale;
+					while (*u && t < pathname + PATH_MAX)
+						*t++ = *u++;
+				}
+			} else if (*s == 'l') {
+				if (lang) {
+					u = lang;
+					while (*u && *u != '_' &&
+						t < pathname + PATH_MAX)
+						*t++ = *u++;
+				}
+			} else if (*s == 't') {
+				if (territory) {
+					u = territory;
+					while (*u && *u != '.' &&
+						t < pathname + PATH_MAX)
+						*t++ = *u++;
+				}
+			} else if (*s == 'c') {
+				if (codeset) {
+					u = codeset;
+					while (*u && t < pathname + PATH_MAX)
+						*t++ = *u++;
+				}
+			} else {
+				if (t < pathname + PATH_MAX)
+					*t++ = *s;
+			}
+		}
+		++s;
+	}
+	*t = NULL;
+	return (s);
+}
+
+/*
+ * This routine will open file, mmap it, and return catd id.
+ */
+static nl_catd
+file_open(const char *name, int safe)
+{
+	int		fd;
+	struct stat64	statbuf;
+	void		*addr;
+	struct _cat_hdr	*tmp;
+	nl_catd		tmp_catd;
+	int		trust;
+
+	fd = nls_safe_open(name, &statbuf, &trust, safe);
+
+	if (fd == -1) {
+		return (NULL);
+	}
+
+	addr = mmap(0, (size_t)statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
+	(void) close(fd);
+
+	if (addr == MAP_FAILED) {
+		return (NULL);
+	}
+
+	/* check MAGIC number of catalogue file */
+	tmp = (struct _cat_hdr *)addr;
+	if (tmp->__hdr_magic != _CAT_MAGIC) {
+		(void) munmap(addr, (size_t)statbuf.st_size);
+		return (NULL);
+	}
+
+	tmp_catd = libc_malloc(sizeof (struct _nl_catd_struct));
+	if (tmp_catd == NULL) {
+		/* malloc failed */
+		(void) munmap(addr, statbuf.st_size);
+		return (NULL);
+	}
+	tmp_catd->__content = addr;
+	tmp_catd->__size = (int)statbuf.st_size;
+	tmp_catd->__trust = trust;
+
+	return (tmp_catd);
+}
+
+int
+_catclose(nl_catd catd)
+{
+	if (catd &&
+	    catd != (nl_catd)-1) {
+		if (catd->__content) {
+			(void) munmap(catd->__content, catd->__size);
+			catd->__content = NULL;
+		}
+		catd->__size = 0;
+		catd->__trust = 0;
+		libc_free(catd);
+	}
+	return (0);
+}