usr/src/lib/libc/port/gen/gettxt.c
changeset 4447 205a92ede54a
parent 1219 f89f56c2d9ac
child 6812 febeba71273d
equal deleted inserted replaced
4446:10c0cc5993ce 4447:205a92ede54a
     1 /*
     1 /*
     2  * CDDL HEADER START
     2  * CDDL HEADER START
     3  *
     3  *
     4  * The contents of this file are subject to the terms of the
     4  * The contents of this file are subject to the terms of the
     5  * Common Development and Distribution License, Version 1.0 only
     5  * Common Development and Distribution License (the "License").
     6  * (the "License").  You may not use this file except in compliance
     6  * You may not use this file except in compliance with the License.
     7  * with the License.
       
     8  *
     7  *
     9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
    10  * or http://www.opensolaris.org/os/licensing.
     9  * or http://www.opensolaris.org/os/licensing.
    11  * See the License for the specific language governing permissions
    10  * See the License for the specific language governing permissions
    12  * and limitations under the License.
    11  * and limitations under the License.
    19  *
    18  *
    20  * CDDL HEADER END
    19  * CDDL HEADER END
    21  */
    20  */
    22 
    21 
    23 /*
    22 /*
    24  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
    23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
    25  * Use is subject to license terms.
    24  * Use is subject to license terms.
    26  */
    25  */
    27 
    26 
    28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
    27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
    29 
    28 
    32 
    31 
    33 
    32 
    34 #pragma weak gettxt = _gettxt
    33 #pragma weak gettxt = _gettxt
    35 
    34 
    36 #include "synonyms.h"
    35 #include "synonyms.h"
       
    36 #include "libc.h"
       
    37 #include <mtlib.h>
    37 #include <ctype.h>
    38 #include <ctype.h>
    38 #include <string.h>
    39 #include <string.h>
    39 #include <locale.h>
    40 #include <locale.h>
    40 #include <fcntl.h>
    41 #include <fcntl.h>
    41 #include <sys/types.h>
    42 #include <sys/types.h>
    44 #include <sys/stat.h>
    45 #include <sys/stat.h>
    45 #include <pfmt.h>
    46 #include <pfmt.h>
    46 #include <stdlib.h>
    47 #include <stdlib.h>
    47 #include <unistd.h>
    48 #include <unistd.h>
    48 #include <limits.h>
    49 #include <limits.h>
       
    50 #include <thread.h>
    49 #include "../i18n/_locale.h"
    51 #include "../i18n/_locale.h"
    50 #include "../i18n/_loc_path.h"
    52 #include "../i18n/_loc_path.h"
    51 
    53 
    52 #define	MAXDB	10	/* maximum number of data bases per program */
       
    53 #define	MESSAGES 	"/LC_MESSAGES/"
    54 #define	MESSAGES 	"/LC_MESSAGES/"
    54 #define	DB_NAME_LEN	15
    55 #define	DB_NAME_LEN	15
    55 
    56 
    56 char 	*handle_return(const char *);
    57 #define	handle_return(s)	\
    57 
    58 	((char *)((s) != NULL && *(s) != '\0' ? (s) : not_found))
    58 /* support multiple versions of a package */
    59 
    59 
    60 extern char cur_cat[];
    60 char	*Msgdb = (char *)NULL;
    61 extern rwlock_t _rw_cur_cat;
    61 
    62 
    62 static	char	*saved_locale = NULL;
    63 static mutex_t	gettxt_lock = DEFAULTMUTEX;
    63 static  const	char	*not_found = "Message not found!!\n";
    64 static const char	*not_found = "Message not found!!\n";
    64 
    65 static const char	*loc_C = "C";
    65 static	struct	db_info {
    66 
       
    67 struct db_list {
    66 	char	db_name[DB_NAME_LEN];	/* name of the message file */
    68 	char	db_name[DB_NAME_LEN];	/* name of the message file */
    67 	uintptr_t	addr;		/* virtual memory address */
    69 	uintptr_t	addr;		/* virtual memory address */
    68 	size_t  length;
    70 	struct db_list	*next;
    69 } *db_info;
    71 };
    70 
    72 
    71 static	int	db_count;   	/* number of currently accessible data bases */
    73 struct db_cache {
       
    74 	char	*loc;
       
    75 	struct db_list	*info;
       
    76 	struct db_cache	*next;
       
    77 };
       
    78 
       
    79 static struct db_cache	*db_cache;
    72 
    80 
    73 char *
    81 char *
    74 gettxt(const char *msg_id, const char *dflt_str)
    82 gettxt(const char *msg_id, const char *dflt_str)
    75 {
    83 {
    76 	char  msgfile[DB_NAME_LEN];	/* name of static shared library */
    84 	struct db_cache	*dbc;
    77 	int   msgnum;			/* message number */
    85 	struct db_list	*dbl;
    78 	char  pathname[PATH_MAX];	/* full pathname to message file */
    86 	char 	msgfile[DB_NAME_LEN];	/* name of static shared library */
    79 	int   i;
    87 	int	msgnum;			/* message number */
    80 	int   new_locale = 0;
    88 	char	pathname[PATH_MAX];	/* full pathname to message file */
    81 	int   fd;
    89 	int	fd;
    82 	struct stat64 sb;
    90 	struct stat64	sb;
    83 	void	*addr;
    91 	void	*addr;
    84 	char   *tokp;
    92 	char	*tokp;
    85 	size_t   name_len;
    93 	size_t	name_len;
    86 	char	*curloc;
    94 	char	*curloc;
    87 
    95 
    88 	if ((msg_id == NULL) || (*msg_id == NULL)) {
    96 	if ((msg_id == NULL) || (*msg_id == '\0')) {
    89 		return (handle_return(dflt_str));
    97 		return (handle_return(dflt_str));
    90 	}
       
    91 
       
    92 	/* first time called, allocate space */
       
    93 	if (!db_info) {
       
    94 		if ((db_info = (struct db_info *) \
       
    95 		    malloc(MAXDB * sizeof (struct db_info))) == NULL)
       
    96 			return (handle_return(dflt_str));
       
    97 	}
    98 	}
    98 
    99 
    99 	/* parse msg_id */
   100 	/* parse msg_id */
   100 
       
   101 	if (((tokp = strchr(msg_id, ':')) == NULL) || *(tokp+1) == '\0')
   101 	if (((tokp = strchr(msg_id, ':')) == NULL) || *(tokp+1) == '\0')
   102 		return (handle_return(dflt_str));
   102 		return (handle_return(dflt_str));
   103 	if ((name_len = (tokp - msg_id)) >= DB_NAME_LEN)
   103 	if ((name_len = (tokp - msg_id)) >= DB_NAME_LEN)
   104 		return (handle_return(dflt_str));
   104 		return (handle_return(dflt_str));
   105 	if (name_len) {
   105 	if (name_len > 0) {
   106 		(void) strncpy(msgfile, msg_id, name_len);
   106 		(void) strncpy(msgfile, msg_id, name_len);
   107 		msgfile[name_len] = '\0';
   107 		msgfile[name_len] = '\0';
   108 	} else {
   108 	} else {
   109 		if (Msgdb && strlen(Msgdb) < DB_NAME_LEN)
   109 		lrw_rdlock(&_rw_cur_cat);
   110 			(void) strcpy(msgfile, Msgdb);
   110 		if (cur_cat == NULL || *cur_cat == '\0') {
   111 		else {
   111 			lrw_unlock(&_rw_cur_cat);
   112 			char *p;
   112 			return (handle_return(dflt_str));
   113 			p = (char *)setcat((const char *)0);
   113 		}
   114 			if ((p != NULL) && strlen(p) < DB_NAME_LEN)
   114 		/*
   115 				(void) strcpy(msgfile, p);
   115 		 * We know the following strcpy is safe.
   116 			else
   116 		 */
   117 				return (handle_return(dflt_str));
   117 		(void) strcpy(msgfile, cur_cat);
   118 		}
   118 		lrw_unlock(&_rw_cur_cat);
   119 	}
   119 	}
   120 	while (*++tokp)
   120 	while (*++tokp) {
   121 		if (!isdigit(*tokp))
   121 		if (!isdigit((unsigned char)*tokp))
   122 			return (handle_return(dflt_str));
   122 			return (handle_return(dflt_str));
       
   123 	}
   123 	msgnum = atoi(msg_id + name_len + 1);
   124 	msgnum = atoi(msg_id + name_len + 1);
   124 
       
   125 	/* Has locale been changed? */
       
   126 
       
   127 	curloc = setlocale(LC_MESSAGES, NULL);
   125 	curloc = setlocale(LC_MESSAGES, NULL);
   128 	if (saved_locale != NULL && strcmp(curloc, saved_locale) == 0) {
   126 
   129 		for (i = 0; i < db_count; i++)
   127 	lmutex_lock(&gettxt_lock);
   130 			if (strcmp(db_info[i].db_name, msgfile) == 0)
   128 
   131 				break;
   129 try_C:
   132 	} else { /* new locale - clear everything */
   130 	dbc = db_cache;
   133 		if (saved_locale)
   131 	while (dbc) {
   134 			free(saved_locale);
   132 		if (strcmp(curloc, dbc->loc) == 0) {
   135 		/*
   133 			dbl = dbc->info;
   136 		 * allocate at least 2 bytes, so that we can copy "C"
   134 			while (dbl) {
   137 		 * without re-allocating the saved_locale.
   135 				if (strcmp(msgfile, dbl->db_name) == 0) {
   138 		 */
   136 					/* msgfile found */
   139 		if ((saved_locale = malloc(strlen(curloc)+2)) == NULL)
   137 					lmutex_unlock(&gettxt_lock);
   140 			return (handle_return(dflt_str));
   138 					goto msgfile_found;
   141 		(void) strcpy(saved_locale, curloc);
   139 				}
   142 		for (i = 0; i < db_count; i++) {
   140 				dbl = dbl->next;
   143 			(void) munmap((void *)db_info[i].addr,
       
   144 			    db_info[i].length);
       
   145 			(void) strcpy(db_info[i].db_name, "");
       
   146 			new_locale++;
       
   147 		}
       
   148 		db_count = 0;
       
   149 	}
       
   150 	if (new_locale || i == db_count) {
       
   151 		if (db_count == MAXDB)
       
   152 			return (handle_return(dflt_str));
       
   153 		if (snprintf(pathname, sizeof (pathname),
       
   154 			_DFLT_LOC_PATH "%s" MESSAGES "%s",
       
   155 			saved_locale, msgfile) >= sizeof (pathname)) {
       
   156 			return (handle_return(dflt_str));
       
   157 		}
       
   158 		if ((fd = open(pathname, O_RDONLY)) == -1 ||
       
   159 			fstat64(fd, &sb) == -1 ||
       
   160 				(addr = mmap(0, (size_t)sb.st_size,
       
   161 					PROT_READ, MAP_SHARED,
       
   162 						fd, 0)) == MAP_FAILED) {
       
   163 			if (fd != -1)
       
   164 				(void) close(fd);
       
   165 			if (strcmp(saved_locale, "C") == 0)
       
   166 				return (handle_return(dflt_str));
       
   167 
       
   168 			/* Change locale to C */
       
   169 
       
   170 			if (snprintf(pathname, sizeof (pathname),
       
   171 				_DFLT_LOC_PATH "C" MESSAGES "%s",
       
   172 				msgfile) >= sizeof (pathname)) {
       
   173 				return (handle_return(dflt_str));
       
   174 			}
   141 			}
   175 
   142 			/* not found */
   176 			for (i = 0; i < db_count; i++) {
   143 			break;
   177 				(void) munmap((void *)db_info[i].addr,
   144 		}
   178 							db_info[i].length);
   145 		dbc = dbc->next;
   179 				(void) strcpy(db_info[i].db_name, "");
   146 	}
   180 			}
   147 	if (dbc == NULL) {
   181 			db_count = 0;
   148 		/* new locale */
   182 			if ((fd = open(pathname, O_RDONLY)) != -1 &&
   149 		if ((dbc = lmalloc(sizeof (struct db_cache))) == NULL) {
   183 				fstat64(fd, &sb) != -1 &&
   150 			lmutex_unlock(&gettxt_lock);
   184 					(addr = mmap(0, (size_t)sb.st_size,
   151 			return (handle_return(dflt_str));
   185 						PROT_READ, MAP_SHARED,
   152 		}
   186 						fd, 0)) != MAP_FAILED) {
   153 		if ((dbc->loc = lmalloc(strlen(curloc) + 1)) == NULL) {
   187 				(void) strcpy(saved_locale, "C");
   154 			lfree(dbc, sizeof (struct db_cache));
   188 			} else {
   155 			lmutex_unlock(&gettxt_lock);
   189 				if (fd != -1)
   156 			return (handle_return(dflt_str));
   190 					(void) close(fd);
   157 		}
   191 				return (handle_return(dflt_str));
   158 		dbc->info = NULL;
   192 			}
   159 		(void) strcpy(dbc->loc, curloc);
   193 		}
   160 		/* connect dbc to the dbc list */
       
   161 		dbc->next = db_cache;
       
   162 		db_cache = dbc;
       
   163 	}
       
   164 	if ((dbl = lmalloc(sizeof (struct db_list))) == NULL) {
       
   165 		lmutex_unlock(&gettxt_lock);
       
   166 		return (handle_return(dflt_str));
       
   167 	}
       
   168 
       
   169 	if (snprintf(pathname, sizeof (pathname),
       
   170 	    _DFLT_LOC_PATH "%s" MESSAGES "%s", dbc->loc, msgfile) >=
       
   171 	    sizeof (pathname)) {
       
   172 		lfree(dbl, sizeof (struct db_list));
       
   173 		lmutex_unlock(&gettxt_lock);
       
   174 		return (handle_return(dflt_str));
       
   175 	}
       
   176 	if ((fd = open(pathname, O_RDONLY)) == -1 ||
       
   177 	    fstat64(fd, &sb) == -1 ||
       
   178 	    (addr = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_SHARED,
       
   179 	    fd, 0L)) == MAP_FAILED) {
   194 		if (fd != -1)
   180 		if (fd != -1)
   195 			(void) close(fd);
   181 			(void) close(fd);
   196 
   182 		lfree(dbl, sizeof (struct db_list));
   197 		/* save file name, memory address, fd and size */
   183 
   198 
   184 		if (strcmp(dbc->loc, "C") == 0) {
   199 		(void) strcpy(db_info[db_count].db_name, msgfile);
   185 			lmutex_unlock(&gettxt_lock);
   200 		db_info[db_count].addr = (uintptr_t)addr;
   186 			return (handle_return(dflt_str));
   201 		db_info[db_count].length = (size_t)sb.st_size;
   187 		}
   202 		i = db_count;
   188 		/* Change locale to C */
   203 		db_count++;
   189 		curloc = (char *)loc_C;
   204 	}
   190 		goto try_C;
       
   191 	}
       
   192 	(void) close(fd);
       
   193 
       
   194 	/* save file name, memory address, fd and size */
       
   195 	(void) strcpy(dbl->db_name, msgfile);
       
   196 	dbl->addr = (uintptr_t)addr;
       
   197 
       
   198 	/* connect dbl to the dbc->info list */
       
   199 	dbl->next = dbc->info;
       
   200 	dbc->info = dbl;
       
   201 
       
   202 	lmutex_unlock(&gettxt_lock);
       
   203 
       
   204 msgfile_found:
   205 	/* check if msgnum out of domain */
   205 	/* check if msgnum out of domain */
   206 	if (msgnum <= 0 || msgnum > *(int *)(db_info[i].addr))
   206 	if (msgnum <= 0 || msgnum > *(int *)dbl->addr)
   207 		return (handle_return(dflt_str));
   207 		return (handle_return(dflt_str));
   208 	/* return pointer to message */
   208 	/* return pointer to message */
   209 	return ((char *)(db_info[i].addr + *(int *)(db_info[i].addr
   209 	return ((char *)(dbl->addr +
   210 		+ msgnum * sizeof (int))));
   210 	    *(int *)(dbl->addr + msgnum * sizeof (int))));
   211 }
   211 }
   212 
       
   213 char *
       
   214 handle_return(const char *dflt_str)
       
   215 {
       
   216 	return ((char *)(dflt_str && *dflt_str ? dflt_str : not_found));
       
   217 }