Home | History | Annotate | Line # | Download | only in locale
setlocale.c revision 1.17.4.2
      1  1.17.4.1   minoura /*	$NetBSD: setlocale.c,v 1.17.4.2 2000/06/23 16:58:58 minoura Exp $	*/
      2      1.10    kleink 
      3       1.1       cgd /*
      4       1.5       jtc  * Copyright (c) 1991, 1993
      5       1.5       jtc  *	The Regents of the University of California.  All rights reserved.
      6       1.5       jtc  *
      7       1.5       jtc  * This code is derived from software contributed to Berkeley by
      8       1.5       jtc  * Paul Borman at Krystal Technologies.
      9       1.1       cgd  *
     10       1.1       cgd  * Redistribution and use in source and binary forms, with or without
     11       1.1       cgd  * modification, are permitted provided that the following conditions
     12       1.1       cgd  * are met:
     13       1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     14       1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     15       1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     17       1.1       cgd  *    documentation and/or other materials provided with the distribution.
     18       1.1       cgd  * 3. All advertising materials mentioning features or use of this software
     19       1.1       cgd  *    must display the following acknowledgement:
     20       1.1       cgd  *	This product includes software developed by the University of
     21       1.1       cgd  *	California, Berkeley and its contributors.
     22       1.1       cgd  * 4. Neither the name of the University nor the names of its contributors
     23       1.1       cgd  *    may be used to endorse or promote products derived from this software
     24       1.1       cgd  *    without specific prior written permission.
     25       1.1       cgd  *
     26       1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27       1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28       1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29       1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30       1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31       1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32       1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33       1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34       1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35       1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36       1.1       cgd  * SUCH DAMAGE.
     37       1.1       cgd  */
     38       1.1       cgd 
     39      1.12  christos #include <sys/cdefs.h>
     40       1.1       cgd #if defined(LIBC_SCCS) && !defined(lint)
     41      1.10    kleink #if 0
     42       1.5       jtc static char sccsid[] = "@(#)setlocale.c	8.1 (Berkeley) 7/4/93";
     43      1.10    kleink #else
     44  1.17.4.1   minoura #ifndef __RCSID
     45  1.17.4.1   minoura #define __RCSID(a)
     46  1.17.4.1   minoura #endif
     47  1.17.4.1   minoura __RCSID("$NetBSD: setlocale.c,v 1.17.4.2 2000/06/23 16:58:58 minoura Exp $");
     48      1.10    kleink #endif
     49       1.1       cgd #endif /* LIBC_SCCS and not lint */
     50       1.1       cgd 
     51      1.11    kleink #define _CTYPE_PRIVATE
     52      1.11    kleink 
     53      1.14    kleink #include "namespace.h"
     54       1.5       jtc #include <sys/localedef.h>
     55      1.11    kleink #include <ctype.h>
     56  1.17.4.1   minoura #include <errno.h>
     57      1.11    kleink #include <limits.h>
     58  1.17.4.1   minoura #define __SINGLE_BYTE_LOCALE_SOURCE__
     59       1.1       cgd #include <locale.h>
     60      1.11    kleink #include <paths.h>
     61       1.6       jtc #include <stdio.h>
     62       1.5       jtc #include <stdlib.h>
     63       1.1       cgd #include <string.h>
     64  1.17.4.2   minoura #include <unistd.h>
     65  1.17.4.1   minoura #ifndef WITH_RUNE
     66      1.11    kleink #include "ctypeio.h"
     67  1.17.4.1   minoura #else
     68  1.17.4.1   minoura #include <sys/stat.h>
     69  1.17.4.1   minoura #include "collate.h"
     70  1.17.4.1   minoura #include "timelocal.h"
     71  1.17.4.1   minoura extern void __runetable_to_netbsd_ctype __P((void));
     72  1.17.4.1   minoura extern int _xpg4_setrunelocale __P((char *));
     73  1.17.4.1   minoura int __fl_rune_singlebyte = 0;
     74  1.17.4.1   minoura #ifdef __NetBSD__
     75  1.17.4.1   minoura #define _NO_NATIVE_ISSETUGID
     76  1.17.4.1   minoura #endif
     77  1.17.4.1   minoura #endif
     78       1.1       cgd 
     79       1.5       jtc /*
     80       1.5       jtc  * Category names for getenv()
     81       1.5       jtc  */
     82      1.13   mycroft static const char *const categories[_LC_LAST] = {
     83       1.5       jtc     "LC_ALL",
     84       1.5       jtc     "LC_COLLATE",
     85       1.5       jtc     "LC_CTYPE",
     86       1.5       jtc     "LC_MONETARY",
     87       1.5       jtc     "LC_NUMERIC",
     88       1.5       jtc     "LC_TIME",
     89       1.5       jtc     "LC_MESSAGES"
     90       1.5       jtc };
     91       1.1       cgd 
     92       1.1       cgd /*
     93       1.5       jtc  * Current locales for each category
     94       1.5       jtc  */
     95       1.5       jtc static char current_categories[_LC_LAST][32] = {
     96       1.5       jtc     "C",
     97       1.5       jtc     "C",
     98       1.5       jtc     "C",
     99       1.5       jtc     "C",
    100       1.5       jtc     "C",
    101       1.5       jtc     "C",
    102       1.5       jtc     "C"
    103       1.5       jtc };
    104       1.5       jtc 
    105       1.5       jtc /*
    106       1.5       jtc  * The locales we are going to try and load
    107       1.1       cgd  */
    108       1.5       jtc static char new_categories[_LC_LAST][32];
    109       1.5       jtc 
    110       1.5       jtc static char current_locale_string[_LC_LAST * 33];
    111  1.17.4.1   minoura #ifndef WITH_RUNE
    112       1.5       jtc static char *PathLocale;
    113  1.17.4.1   minoura static char *PathLocaleUnshared;
    114  1.17.4.1   minoura /*
    115  1.17.4.1   minoura  * Data paths for each category.
    116  1.17.4.1   minoura  */
    117  1.17.4.1   minoura static char **paths[_LC_LAST] = {
    118  1.17.4.1   minoura     &PathLocale,			/* LC_ALL */
    119  1.17.4.1   minoura     &PathLocaleUnshared,		/* LC_COLLATE */
    120  1.17.4.1   minoura     &PathLocaleUnshared,		/* LC_CTYPE */
    121  1.17.4.1   minoura     &PathLocale,			/* LC_MONETARY */
    122  1.17.4.1   minoura     &PathLocale,			/* LC_NUMERIC */
    123  1.17.4.1   minoura     &PathLocale,			/* LC_TIME */
    124  1.17.4.1   minoura     &PathLocale,			/* LC_MESSAGES */
    125  1.17.4.1   minoura };
    126  1.17.4.1   minoura #else
    127  1.17.4.1   minoura #include "setlocale.h"
    128  1.17.4.1   minoura #endif
    129       1.5       jtc 
    130       1.5       jtc static char	*currentlocale __P((void));
    131       1.5       jtc static char	*loadlocale __P((int));
    132  1.17.4.1   minoura #ifdef WITH_RUNE
    133  1.17.4.1   minoura static int	stub_load_locale __P((const char *, int));
    134  1.17.4.1   minoura #endif
    135       1.5       jtc 
    136       1.1       cgd char *
    137  1.17.4.1   minoura __setlocale_mb(category, locale)
    138       1.1       cgd 	int category;
    139       1.1       cgd 	const char *locale;
    140       1.1       cgd {
    141      1.16  christos 	int i;
    142      1.16  christos 	size_t len;
    143       1.5       jtc 	char *env, *r;
    144  1.17.4.1   minoura 	int found;
    145       1.5       jtc 
    146  1.17.4.1   minoura #ifndef WITH_RUNE
    147       1.8       mrg 	/*
    148       1.8       mrg 	 * XXX potential security problem here with set-id programs
    149       1.8       mrg 	 * being able to read files the user can not normally read.
    150       1.8       mrg 	 */
    151  1.17.4.1   minoura 	if (!PathLocale) {
    152  1.17.4.1   minoura 		if(getenv("PATH_LOCALE")) {
    153  1.17.4.1   minoura 			PathLocale = strdup(getenv("PATH_LOCALE"));
    154  1.17.4.1   minoura 			PathLocaleUnshared = PathLocale;
    155  1.17.4.1   minoura 		} else {
    156  1.17.4.1   minoura 			PathLocale = _PATH_LOCALE;
    157  1.17.4.1   minoura 			PathLocaleUnshared = _PATH_LOCALE_UNSHARED;
    158  1.17.4.1   minoura 		}
    159  1.17.4.1   minoura 	}
    160  1.17.4.1   minoura #else
    161  1.17.4.1   minoura 	if (_PathLocale == NULL) {
    162  1.17.4.1   minoura 		char *p = getenv("PATH_LOCALE");
    163  1.17.4.1   minoura 
    164  1.17.4.1   minoura 		if (p != NULL && !issetugid()) {
    165  1.17.4.1   minoura 			if (strlen(p) + 1/*"/"*/ + ENCODING_LEN +
    166  1.17.4.2   minoura 			    1/*"/"*/ + CATEGORY_LEN >= PATH_MAX) {
    167  1.17.4.2   minoura 				errno = EFAULT;
    168  1.17.4.2   minoura 				return(NULL);
    169  1.17.4.2   minoura 			}
    170  1.17.4.1   minoura 			_PathLocale = strdup(p);
    171  1.17.4.1   minoura 			if (_PathLocale == NULL)
    172  1.17.4.2   minoura 				return (NULL);
    173  1.17.4.1   minoura 			_PathLocaleUnshared = _PathLocale;
    174  1.17.4.1   minoura 		} else {
    175  1.17.4.1   minoura 			_PathLocale = _PATH_LOCALE;
    176  1.17.4.1   minoura 			_PathLocaleUnshared = _PATH_LOCALE_UNSHARED;
    177  1.17.4.1   minoura 		}
    178  1.17.4.1   minoura 	}
    179  1.17.4.1   minoura #endif
    180       1.5       jtc 
    181       1.5       jtc 	if (category < 0 || category >= _LC_LAST)
    182       1.1       cgd 		return (NULL);
    183       1.5       jtc 
    184       1.5       jtc 	if (!locale)
    185       1.5       jtc 		return (category ?
    186       1.5       jtc 		    current_categories[category] : currentlocale());
    187       1.5       jtc 
    188       1.5       jtc 	/*
    189       1.5       jtc 	 * Default to the current locale for everything.
    190       1.5       jtc 	 */
    191       1.5       jtc 	for (i = 1; i < _LC_LAST; ++i)
    192       1.7       mrg 		(void)strncpy(new_categories[i], current_categories[i],
    193       1.7       mrg 		    sizeof(new_categories[i]) - 1);
    194       1.5       jtc 
    195       1.5       jtc 	/*
    196       1.5       jtc 	 * Now go fill up new_categories from the locale argument
    197       1.5       jtc 	 */
    198       1.5       jtc 	if (!*locale) {
    199       1.5       jtc 		env = getenv(categories[category]);
    200       1.5       jtc 
    201       1.9    kleink 		if (!env || !*env)
    202       1.5       jtc 			env = getenv(categories[0]);
    203       1.5       jtc 
    204       1.9    kleink 		if (!env || !*env)
    205       1.5       jtc 			env = getenv("LANG");
    206       1.5       jtc 
    207       1.9    kleink 		if (!env || !*env)
    208       1.5       jtc 			env = "C";
    209       1.5       jtc 
    210       1.8       mrg 		(void)strncpy(new_categories[category], env, 31);
    211       1.5       jtc 		new_categories[category][31] = 0;
    212       1.5       jtc 		if (!category) {
    213       1.5       jtc 			for (i = 1; i < _LC_LAST; ++i) {
    214       1.9    kleink 				if (!(env = getenv(categories[i])) || !*env)
    215       1.5       jtc 					env = new_categories[0];
    216       1.5       jtc 				(void)strncpy(new_categories[i], env, 31);
    217       1.5       jtc 				new_categories[i][31] = 0;
    218       1.5       jtc 			}
    219       1.5       jtc 		}
    220       1.8       mrg 	} else if (category) {
    221       1.5       jtc 		(void)strncpy(new_categories[category], locale, 31);
    222       1.5       jtc 		new_categories[category][31] = 0;
    223       1.5       jtc 	} else {
    224       1.5       jtc 		if ((r = strchr(locale, '/')) == 0) {
    225       1.5       jtc 			for (i = 1; i < _LC_LAST; ++i) {
    226       1.5       jtc 				(void)strncpy(new_categories[i], locale, 31);
    227       1.5       jtc 				new_categories[i][31] = 0;
    228       1.5       jtc 			}
    229       1.5       jtc 		} else {
    230       1.5       jtc 			for (i = 1; r[1] == '/'; ++r);
    231       1.5       jtc 			if (!r[1])
    232       1.5       jtc 				return (NULL);	/* Hmm, just slashes... */
    233       1.5       jtc 			do {
    234       1.5       jtc 				len = r - locale > 31 ? 31 : r - locale;
    235       1.5       jtc 				(void)strncpy(new_categories[i++], locale, len);
    236       1.5       jtc 				new_categories[i++][len] = 0;
    237       1.5       jtc 				locale = r;
    238       1.5       jtc 				while (*locale == '/')
    239       1.5       jtc 				    ++locale;
    240       1.5       jtc 				while (*++r && *r != '/');
    241       1.5       jtc 			} while (*locale);
    242       1.5       jtc 			while (i < _LC_LAST)
    243       1.7       mrg 				(void)strncpy(new_categories[i],
    244       1.7       mrg 				    new_categories[i-1],
    245       1.7       mrg 				    sizeof(new_categories[i]) - 1);
    246       1.5       jtc 		}
    247       1.5       jtc 	}
    248       1.5       jtc 
    249       1.5       jtc 	if (category)
    250       1.5       jtc 		return (loadlocale(category));
    251       1.5       jtc 
    252  1.17.4.1   minoura 	found = 0;
    253  1.17.4.1   minoura 	for (i = 1; i < _LC_LAST; ++i) {
    254  1.17.4.1   minoura 		if ( loadlocale(i) != NULL )
    255  1.17.4.1   minoura 			found = 1;
    256  1.17.4.1   minoura 		else if ( !category ) {
    257  1.17.4.1   minoura 			found = 0;
    258  1.17.4.1   minoura 			break;
    259  1.17.4.1   minoura 		}
    260  1.17.4.1   minoura 	}
    261       1.9    kleink 
    262  1.17.4.1   minoura 	return (found ? currentlocale():NULL);
    263       1.5       jtc }
    264       1.5       jtc 
    265       1.5       jtc static char *
    266       1.5       jtc currentlocale()
    267       1.5       jtc {
    268       1.5       jtc 	int i;
    269       1.5       jtc 
    270       1.7       mrg 	(void)strncpy(current_locale_string, current_categories[1],
    271       1.7       mrg 	    sizeof(current_locale_string) - 1);
    272       1.5       jtc 
    273       1.5       jtc 	for (i = 2; i < _LC_LAST; ++i)
    274       1.5       jtc 		if (strcmp(current_categories[1], current_categories[i])) {
    275       1.5       jtc 			(void)snprintf(current_locale_string,
    276       1.5       jtc 			    sizeof(current_locale_string), "%s/%s/%s/%s/%s",
    277       1.5       jtc 			    current_categories[1], current_categories[2],
    278       1.5       jtc 			    current_categories[3], current_categories[4],
    279       1.5       jtc 			    current_categories[5]);
    280       1.5       jtc 			break;
    281       1.5       jtc 		}
    282       1.5       jtc 	return (current_locale_string);
    283       1.5       jtc }
    284       1.5       jtc 
    285      1.15    kleink static char *
    286       1.5       jtc loadlocale(category)
    287       1.5       jtc 	int category;
    288       1.5       jtc {
    289  1.17.4.1   minoura #ifndef WITH_RUNE
    290       1.5       jtc 	char name[PATH_MAX];
    291  1.17.4.1   minoura #endif
    292       1.5       jtc 
    293      1.11    kleink 	if (strcmp(new_categories[category], current_categories[category]) == 0)
    294       1.5       jtc 		return (current_categories[category]);
    295       1.5       jtc 
    296       1.5       jtc 	if (!strcmp(new_categories[category], "C") ||
    297      1.11    kleink 	    !strcmp(new_categories[category], "POSIX")) {
    298      1.11    kleink 
    299      1.11    kleink 		switch (category) {
    300      1.11    kleink 		case LC_CTYPE:
    301      1.11    kleink 			if (_ctype_ != _C_ctype_) {
    302      1.16  christos 				/* LINTED const castaway */
    303      1.11    kleink 				free((void *)_ctype_);
    304      1.11    kleink 				_ctype_ = _C_ctype_;
    305      1.11    kleink 			}
    306      1.11    kleink 			if (_toupper_tab_ != _C_toupper_) {
    307      1.16  christos 				/* LINTED const castaway */
    308      1.11    kleink 				free((void *)_toupper_tab_);
    309      1.11    kleink 				_toupper_tab_ = _C_toupper_;
    310      1.11    kleink 			}
    311      1.11    kleink 			if (_tolower_tab_ != _C_tolower_) {
    312      1.16  christos 				/* LINTED const castaway */
    313      1.11    kleink 				free((void *)_tolower_tab_);
    314      1.11    kleink 				_tolower_tab_ = _C_tolower_;
    315      1.11    kleink 			}
    316  1.17.4.1   minoura #ifdef WITH_RUNE
    317  1.17.4.2   minoura 			(void)_xpg4_setrunelocale("C");
    318  1.17.4.1   minoura #endif
    319      1.11    kleink 		}
    320       1.5       jtc 
    321       1.7       mrg 		(void)strncpy(current_categories[category],
    322       1.7       mrg 		    new_categories[category],
    323       1.7       mrg 		    sizeof(current_categories[category]) - 1);
    324      1.11    kleink 		return current_categories[category];
    325       1.5       jtc 	}
    326       1.5       jtc 
    327  1.17.4.1   minoura #ifndef WITH_RUNE
    328       1.5       jtc 	/*
    329       1.5       jtc 	 * Some day we will actually look at this file.
    330       1.5       jtc 	 */
    331       1.5       jtc 	(void)snprintf(name, sizeof(name), "%s/%s/%s",
    332  1.17.4.1   minoura 	    *paths[category],
    333  1.17.4.1   minoura 	    new_categories[category], categories[category]);
    334  1.17.4.1   minoura #endif
    335       1.5       jtc 
    336       1.5       jtc 	switch (category) {
    337      1.11    kleink 	case LC_CTYPE:
    338  1.17.4.1   minoura #ifndef WITH_RUNE
    339      1.11    kleink 		if (__loadctype(name)) {
    340  1.17.4.1   minoura #else
    341  1.17.4.2   minoura 		if (!_xpg4_setrunelocale(new_categories[category])) {
    342  1.17.4.2   minoura 			__runetable_to_netbsd_ctype();
    343  1.17.4.1   minoura #endif
    344      1.11    kleink 			(void)strncpy(current_categories[category],
    345      1.11    kleink 			    new_categories[category],
    346      1.11    kleink 			    sizeof(current_categories[category]) - 1);
    347      1.11    kleink 			return current_categories[category];
    348  1.17.4.2   minoura 		}
    349      1.11    kleink 		return NULL;
    350      1.11    kleink 
    351      1.11    kleink 	case LC_COLLATE:
    352  1.17.4.1   minoura #ifdef WITH_RUNE
    353  1.17.4.1   minoura 		if (__collate_load_tables(new_categories[category]) == 0)
    354  1.17.4.1   minoura 			return new_categories[category];
    355  1.17.4.1   minoura 		(void)__collate_load_tables(current_categories[category]);
    356  1.17.4.1   minoura 		return NULL;
    357  1.17.4.1   minoura #else
    358  1.17.4.1   minoura 		/* FALLTHROUGH */
    359  1.17.4.1   minoura #endif
    360  1.17.4.1   minoura 	case LC_TIME:
    361  1.17.4.1   minoura #ifdef WITH_RUNE
    362  1.17.4.1   minoura 		if (__time_load_locale(new_categories[category]) == 0)
    363  1.17.4.1   minoura 			return new_categories[category];
    364  1.17.4.1   minoura 		(void)__time_load_locale(current_categories[category]);
    365  1.17.4.1   minoura 		return NULL;
    366  1.17.4.1   minoura 
    367  1.17.4.1   minoura #else
    368  1.17.4.1   minoura 		/* FALLTHROUGH */
    369  1.17.4.1   minoura #endif
    370      1.11    kleink 	case LC_MESSAGES:
    371      1.11    kleink 	case LC_MONETARY:
    372      1.11    kleink 	case LC_NUMERIC:
    373  1.17.4.1   minoura #ifdef WITH_RUNE
    374  1.17.4.1   minoura 		if (stub_load_locale(new_categories[category], category) == 0)
    375  1.17.4.1   minoura 			return new_categories[category];
    376  1.17.4.1   minoura 		stub_load_locale(current_categories[category], category);
    377      1.11    kleink 		return NULL;
    378  1.17.4.1   minoura #else
    379  1.17.4.1   minoura 		return NULL;
    380  1.17.4.1   minoura #endif
    381       1.5       jtc 	}
    382      1.11    kleink 
    383      1.11    kleink 	return NULL;
    384  1.17.4.1   minoura }
    385  1.17.4.1   minoura 
    386  1.17.4.1   minoura /*
    387  1.17.4.1   minoura  * Temporary code until we implement actual LC_* code.
    388  1.17.4.1   minoura  */
    389  1.17.4.1   minoura static int
    390  1.17.4.1   minoura stub_load_locale(encoding, category)
    391  1.17.4.1   minoura  const char *encoding;
    392  1.17.4.1   minoura  int category;
    393  1.17.4.1   minoura {
    394  1.17.4.1   minoura 	char name[PATH_MAX];
    395  1.17.4.1   minoura 	struct stat st;
    396  1.17.4.1   minoura 
    397  1.17.4.1   minoura 	if (!encoding)
    398  1.17.4.1   minoura 		return(1);
    399  1.17.4.1   minoura 	/*
    400  1.17.4.1   minoura 	 * The "C" and "POSIX" locale are always here.
    401  1.17.4.1   minoura 	 */
    402  1.17.4.1   minoura 	if (!strcmp(encoding, "C") || !strcmp(encoding, "POSIX"))
    403  1.17.4.1   minoura 		return(0);
    404  1.17.4.1   minoura 	if (!_PathLocale)	/* XXX: shouldn't we initialize this? */
    405  1.17.4.1   minoura 		return(1);
    406  1.17.4.1   minoura 	/* Range checking not needed, encoding has fixed size */
    407  1.17.4.1   minoura 	strcpy(name, *_LocalePaths[category]);
    408  1.17.4.1   minoura 	strcat(name, "/");
    409  1.17.4.1   minoura 	strcat(name, encoding);
    410  1.17.4.1   minoura #if 0
    411  1.17.4.1   minoura 	/*
    412  1.17.4.1   minoura 	 * Some day we will actually look at this file.
    413  1.17.4.1   minoura 	 */
    414  1.17.4.1   minoura #endif
    415  1.17.4.1   minoura 	return (stat(name, &st) != 0 || !S_ISDIR(st.st_mode));
    416       1.1       cgd }
    417