xref: /titanic_51/usr/src/lib/libbc/libc/gen/common/setlocale.c (revision 5d54f3d8999eac1762fe0a8c7177d20f1f201fae)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 1995 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984 AT&T	*/
287c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
327c478bd9Sstevel@tonic-gate 
33*5d54f3d8Smuffin #include <sys/fcntl.h>
347c478bd9Sstevel@tonic-gate #include <locale.h>
357c478bd9Sstevel@tonic-gate #include <stdlib.h>
367c478bd9Sstevel@tonic-gate #include "codeset.h"
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate #include <string.h>
397c478bd9Sstevel@tonic-gate #include <memory.h>
407c478bd9Sstevel@tonic-gate #include <malloc.h>
417c478bd9Sstevel@tonic-gate #include <sys/param.h>		/* for MAXPATHLEN */
427c478bd9Sstevel@tonic-gate #include <sys/stat.h>
437c478bd9Sstevel@tonic-gate #include <errno.h>
447c478bd9Sstevel@tonic-gate #include <limits.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #define	TRAILER ".ci"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate struct	_code_set_info _code_set_info = {
507c478bd9Sstevel@tonic-gate 	NULL,
517c478bd9Sstevel@tonic-gate 	CODESET_NONE, 	/* no codeset */
527c478bd9Sstevel@tonic-gate 	NULL, 		/* not defined */
537c478bd9Sstevel@tonic-gate 	0,
547c478bd9Sstevel@tonic-gate };
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /* tolower()  and toupper() conversion table
577c478bd9Sstevel@tonic-gate  * is hidden here to avoid being placed in the
587c478bd9Sstevel@tonic-gate  * extern  .sa file in the dynamic version of libc
597c478bd9Sstevel@tonic-gate  */
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate char _ctype_ul[] = { 0,
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*	 0	 1	 2	 3	 4	 5	 6	 7  */
647c478bd9Sstevel@tonic-gate 	'\000',	'\001',	'\002',	'\003',	'\004',	'\005',	'\006',	'\007',
657c478bd9Sstevel@tonic-gate 	'\010',	'\011',	'\012',	'\013',	'\014',	'\015',	'\016',	'\017',
667c478bd9Sstevel@tonic-gate 	'\020',	'\021',	'\022',	'\023',	'\024',	'\025',	'\026',	'\027',
677c478bd9Sstevel@tonic-gate 	'\030',	'\031',	'\032',	'\033',	'\034',	'\035',	'\036',	'\037',
687c478bd9Sstevel@tonic-gate 	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
697c478bd9Sstevel@tonic-gate 	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
707c478bd9Sstevel@tonic-gate 	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
717c478bd9Sstevel@tonic-gate 	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
727c478bd9Sstevel@tonic-gate 	'@',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
737c478bd9Sstevel@tonic-gate 	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
747c478bd9Sstevel@tonic-gate 	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
757c478bd9Sstevel@tonic-gate 	'x',	'y',	'z',	'[',	'\\',	']',	'^',	'_',
767c478bd9Sstevel@tonic-gate 	'`',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
777c478bd9Sstevel@tonic-gate 	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
787c478bd9Sstevel@tonic-gate 	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
797c478bd9Sstevel@tonic-gate 	'X',	'Y',	'Z',	'{',	'|',	'}',	'~',	'\177',
807c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
817c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
827c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
837c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
847c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
857c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
867c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
877c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
887c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
897c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
907c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
917c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
927c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
937c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
947c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
957c478bd9Sstevel@tonic-gate 	0,	0,	0,	0,	0,	0,	0,	0,
967c478bd9Sstevel@tonic-gate };
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /* following layout is:
997c478bd9Sstevel@tonic-gate  * LC_NUMERIC LC_TIME LC_MONETARY LANGINFO LC_COLLATE LC_MESSAGES
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate char _locales[MAXLOCALE - 1][MAXLOCALENAME + 1] ;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate char _my_time[MAXLOCALENAME + 1];
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate /* The array Default holds the systems notion of default locale. It is normally
1067c478bd9Sstevel@tonic-gate  * found in {LOCALE}/.default and moved to here. Note there is only one
1077c478bd9Sstevel@tonic-gate  * default locale spanning all categories
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate static char Default[MAXLOCALENAME+1];
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate struct	langinfo _langinfo;
1137c478bd9Sstevel@tonic-gate struct	dtconv *_dtconv = NULL;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate static	char *realmonths = NULL;
1167c478bd9Sstevel@tonic-gate static	char *realdays = NULL;
1177c478bd9Sstevel@tonic-gate static	char *realfmts = NULL;
1187c478bd9Sstevel@tonic-gate static  short lang_succ = ON;	/* setlocale success */
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /* Set the values here to guarantee stdio use of the
1227c478bd9Sstevel@tonic-gate    decimal point
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate static struct lconv lconv_arr = {
1257c478bd9Sstevel@tonic-gate 	".", "", "", "", "",
1267c478bd9Sstevel@tonic-gate 	"", "", "", "", "",
1277c478bd9Sstevel@tonic-gate 	CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX,
1287c478bd9Sstevel@tonic-gate 	CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX
1297c478bd9Sstevel@tonic-gate };
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /* lconv is externally defined by ANSI C */
1327c478bd9Sstevel@tonic-gate struct	lconv *lconv = &lconv_arr;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate static	char *lconv_numeric_str = NULL;
1357c478bd9Sstevel@tonic-gate static 	char *lconv_monetary_str = NULL;
1367c478bd9Sstevel@tonic-gate 
137*5d54f3d8Smuffin int	openlocale(char *, int, char *, char *);
138*5d54f3d8Smuffin int	getlocale_ctype(char *, char *, char *);
139*5d54f3d8Smuffin char	*getlocale_numeric(char *, struct lconv *, char *);
140*5d54f3d8Smuffin void	init_statics(void);
141*5d54f3d8Smuffin static char	*getlocale_monetary(char *, struct lconv *, char *);
142*5d54f3d8Smuffin static char	*getstr(char *, char **);
143*5d54f3d8Smuffin static char	*getgrouping(char *, char **);
144*5d54f3d8Smuffin static char	*getnum(char  *, char *);
145*5d54f3d8Smuffin static char	*getbool(char *, char *);
146*5d54f3d8Smuffin static void	set_default(void);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate char *
149*5d54f3d8Smuffin setlocale(int category, char *locale)
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate 	static char buf[MAXLOCALE*(MAXLOCALENAME + 1) + 1];
1527c478bd9Sstevel@tonic-gate 		/* buffer for current LC_ALL value */
1537c478bd9Sstevel@tonic-gate 	int nonuniform;
1547c478bd9Sstevel@tonic-gate 	short ret;
1557c478bd9Sstevel@tonic-gate 	char my_ctype[CTYPE_SIZE];	/* local copy */
1567c478bd9Sstevel@tonic-gate 	struct lconv my_lconv;		/* local copy */
1577c478bd9Sstevel@tonic-gate 	char *my_lconv_numeric_str;
1587c478bd9Sstevel@tonic-gate 	char *my_lconv_monetary_str;
159*5d54f3d8Smuffin 	int i;
160*5d54f3d8Smuffin 	char *p;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	 /* initialize my_lconv to lconv */
1647c478bd9Sstevel@tonic-gate         memcpy(&my_lconv, lconv, sizeof(my_lconv));
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	/*
1677c478bd9Sstevel@tonic-gate 	 *  Following code is to avoid static initialisation of
1687c478bd9Sstevel@tonic-gate 	 *  strings which would otherwise blow up "xstr".
1697c478bd9Sstevel@tonic-gate 	 */
1707c478bd9Sstevel@tonic-gate 	if (_locales[0][0] == '\0')
1717c478bd9Sstevel@tonic-gate 		init_statics();
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	if (locale == NULL) {
1747c478bd9Sstevel@tonic-gate 		if (category == LC_ALL) {
1757c478bd9Sstevel@tonic-gate 			/*
1767c478bd9Sstevel@tonic-gate 			 * Assume all locales are set to the same value.  Then
1777c478bd9Sstevel@tonic-gate 			 * scan through the locales to see if any are
1787c478bd9Sstevel@tonic-gate 			 * different.  If they are the same, return the common
1797c478bd9Sstevel@tonic-gate 			 * value; otherwise, construct a "composite" value.
1807c478bd9Sstevel@tonic-gate 			 */
1817c478bd9Sstevel@tonic-gate 			nonuniform = 0;	/* assume all locales set the same */
1827c478bd9Sstevel@tonic-gate 			for (i = 0; i < MAXLOCALE - 2; i++) {
1837c478bd9Sstevel@tonic-gate 				if (strcmp(_locales[i], _locales[i + 1]) != 0) {
1847c478bd9Sstevel@tonic-gate 					nonuniform = 1;
1857c478bd9Sstevel@tonic-gate 					break;
1867c478bd9Sstevel@tonic-gate 				}
1877c478bd9Sstevel@tonic-gate 			}
1887c478bd9Sstevel@tonic-gate 			if (nonuniform) {
1897c478bd9Sstevel@tonic-gate 				/*
1907c478bd9Sstevel@tonic-gate 				 * They're not all the same.  Construct a list
1917c478bd9Sstevel@tonic-gate 				 * of all the locale values, in order,
1927c478bd9Sstevel@tonic-gate 				 * separated by slashes.  Return that value.
1937c478bd9Sstevel@tonic-gate 				 */
1947c478bd9Sstevel@tonic-gate 				(void) strcpy(buf, _locales[0]);
1957c478bd9Sstevel@tonic-gate 				for (i = 1; i < MAXLOCALE - 1; i++) {
1967c478bd9Sstevel@tonic-gate 					(void) strcat(buf, "/");
1977c478bd9Sstevel@tonic-gate 					(void) strcat(buf, _locales[i]);
1987c478bd9Sstevel@tonic-gate 				}
1997c478bd9Sstevel@tonic-gate 				return (buf);
2007c478bd9Sstevel@tonic-gate 			} else {
2017c478bd9Sstevel@tonic-gate 				/*
2027c478bd9Sstevel@tonic-gate 				 * They're all the same; any one you return is
2037c478bd9Sstevel@tonic-gate 				 * OK.
2047c478bd9Sstevel@tonic-gate 				 */
2057c478bd9Sstevel@tonic-gate 				return (_locales[0]);
2067c478bd9Sstevel@tonic-gate 			}
2077c478bd9Sstevel@tonic-gate 		} else
2087c478bd9Sstevel@tonic-gate 			return (_locales[category - 1]);
2097c478bd9Sstevel@tonic-gate 	}
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	switch (category) {
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	case LC_ALL:
2147c478bd9Sstevel@tonic-gate 		if (strchr(locale, '/') != NULL) {
2157c478bd9Sstevel@tonic-gate 			/*
2167c478bd9Sstevel@tonic-gate 			 * Composite value; extract each category.
2177c478bd9Sstevel@tonic-gate 			 */
2187c478bd9Sstevel@tonic-gate 			if (strlen(locale) > sizeof buf - 1)
2197c478bd9Sstevel@tonic-gate 				return (NULL);	/* too long */
2207c478bd9Sstevel@tonic-gate 			(void) strcpy(buf, locale);
2217c478bd9Sstevel@tonic-gate 			p = buf;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 			/*
2247c478bd9Sstevel@tonic-gate 			 * LC_CTYPE and LC_NUMERIC are set here.
2257c478bd9Sstevel@tonic-gate 			 * Others locales won't be set here,
2267c478bd9Sstevel@tonic-gate 			 * they will be just marked.
2277c478bd9Sstevel@tonic-gate 			 */
2287c478bd9Sstevel@tonic-gate 			for (i = 0; i < MAXLOCALE - 1; i++) {
2297c478bd9Sstevel@tonic-gate 				p = strtok(p, "/");
2307c478bd9Sstevel@tonic-gate 				if (p == NULL)
2317c478bd9Sstevel@tonic-gate 					return (NULL);	/* missing item */
2327c478bd9Sstevel@tonic-gate 				switch (i) {
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 				case LC_CTYPE - 1:
2357c478bd9Sstevel@tonic-gate 					if (setlocale(LC_CTYPE,p) == NULL)
236*5d54f3d8Smuffin 						return (NULL);
2377c478bd9Sstevel@tonic-gate 					break;
2387c478bd9Sstevel@tonic-gate 				case LC_NUMERIC - 1:
2397c478bd9Sstevel@tonic-gate 					if (setlocale(LC_NUMERIC,p) == NULL)
240*5d54f3d8Smuffin 						return (NULL);
2417c478bd9Sstevel@tonic-gate 					break;
2427c478bd9Sstevel@tonic-gate 				case LC_TIME - 1:
2437c478bd9Sstevel@tonic-gate 					if (setlocale(LC_TIME,p) == NULL)
244*5d54f3d8Smuffin 						return (NULL);
2457c478bd9Sstevel@tonic-gate 					break;
2467c478bd9Sstevel@tonic-gate 				case LC_MONETARY - 1:
2477c478bd9Sstevel@tonic-gate 					if (setlocale(LC_MONETARY,p) == NULL)
248*5d54f3d8Smuffin 						return (NULL);
2497c478bd9Sstevel@tonic-gate 					break;
2507c478bd9Sstevel@tonic-gate 				case LANGINFO - 1:
2517c478bd9Sstevel@tonic-gate 					if (setlocale(LANGINFO,p) == NULL)
252*5d54f3d8Smuffin 						return (NULL);
2537c478bd9Sstevel@tonic-gate 					break;
2547c478bd9Sstevel@tonic-gate 				case LC_COLLATE - 1:
2557c478bd9Sstevel@tonic-gate 					if (setlocale(LC_COLLATE,p) == NULL)
256*5d54f3d8Smuffin 						return (NULL);
2577c478bd9Sstevel@tonic-gate 					break;
2587c478bd9Sstevel@tonic-gate 				case LC_MESSAGES - 1:
2597c478bd9Sstevel@tonic-gate 					if (setlocale(LC_MESSAGES,p) == NULL)
260*5d54f3d8Smuffin 						return (NULL);
2617c478bd9Sstevel@tonic-gate 					break;
2627c478bd9Sstevel@tonic-gate 				}
2637c478bd9Sstevel@tonic-gate 				p = NULL;
2647c478bd9Sstevel@tonic-gate 			}
2657c478bd9Sstevel@tonic-gate 			if (strtok((char *)NULL, "/") != NULL)
2667c478bd9Sstevel@tonic-gate 				return (NULL);	/* extra stuff at end */
2677c478bd9Sstevel@tonic-gate 		}
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	/* If category = LC_ALL, Drop through to test each individual
2707c478bd9Sstevel@tonic-gate   	 * category, one at a time. Note default rules where env vars
2717c478bd9Sstevel@tonic-gate 	 * are not set
2727c478bd9Sstevel@tonic-gate 	 */
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	case LC_CTYPE:
2757c478bd9Sstevel@tonic-gate 		if ((ret = getlocale_ctype(locale , my_ctype,
2767c478bd9Sstevel@tonic-gate 		    _locales[LC_CTYPE - 1])) < 0)
2777c478bd9Sstevel@tonic-gate 			return (NULL);
2787c478bd9Sstevel@tonic-gate 		if (ret) {
2797c478bd9Sstevel@tonic-gate 		      (void) memcpy(_ctype_, my_ctype, CTYPE_SIZE/2);
2807c478bd9Sstevel@tonic-gate 		      (void) memcpy(_ctype_ul, my_ctype+(CTYPE_SIZE/2), CTYPE_SIZE/2);
2817c478bd9Sstevel@tonic-gate 		}
2827c478bd9Sstevel@tonic-gate 		if (category != LC_ALL)
2837c478bd9Sstevel@tonic-gate 			break;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	case LC_NUMERIC:
2867c478bd9Sstevel@tonic-gate 		if ((my_lconv_numeric_str =
2877c478bd9Sstevel@tonic-gate 		    getlocale_numeric(locale, &my_lconv,
2887c478bd9Sstevel@tonic-gate 		      _locales[LC_NUMERIC - 1])) == NULL)
2897c478bd9Sstevel@tonic-gate 			return (NULL);
2907c478bd9Sstevel@tonic-gate 		if (*my_lconv_numeric_str) {
2917c478bd9Sstevel@tonic-gate 			if (lconv_numeric_str != NULL)
2927c478bd9Sstevel@tonic-gate 				free((malloc_t)lconv_numeric_str);
2937c478bd9Sstevel@tonic-gate 			lconv_numeric_str = my_lconv_numeric_str;
2947c478bd9Sstevel@tonic-gate 			memcpy(lconv, my_lconv, sizeof(my_lconv));
2957c478bd9Sstevel@tonic-gate 		}
2967c478bd9Sstevel@tonic-gate 		if (category != LC_ALL)
2977c478bd9Sstevel@tonic-gate 			break;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	case LC_TIME:
3007c478bd9Sstevel@tonic-gate 		if ((ret = openlocale("LC_TIME", LC_TIME, locale,
3017c478bd9Sstevel@tonic-gate 		      _locales[LC_TIME -1])) < 0)
3027c478bd9Sstevel@tonic-gate 			return (NULL);
3037c478bd9Sstevel@tonic-gate 		if (ret)
3047c478bd9Sstevel@tonic-gate 			(void) close(ret);
3057c478bd9Sstevel@tonic-gate 		if (category != LC_ALL)
3067c478bd9Sstevel@tonic-gate 			break;
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	case LC_MONETARY:
3097c478bd9Sstevel@tonic-gate 		if ((my_lconv_monetary_str =
3107c478bd9Sstevel@tonic-gate 		    getlocale_monetary(locale, &my_lconv,
3117c478bd9Sstevel@tonic-gate 		      _locales[LC_MONETARY - 1])) == NULL)
3127c478bd9Sstevel@tonic-gate 			return (NULL);
3137c478bd9Sstevel@tonic-gate 		if (*my_lconv_monetary_str) {
3147c478bd9Sstevel@tonic-gate 			if (lconv_monetary_str != NULL)
3157c478bd9Sstevel@tonic-gate 				free((malloc_t)lconv_monetary_str);
3167c478bd9Sstevel@tonic-gate 			lconv_monetary_str = my_lconv_monetary_str;
3177c478bd9Sstevel@tonic-gate 			memcpy(lconv, &my_lconv, sizeof(my_lconv));
3187c478bd9Sstevel@tonic-gate 		}
3197c478bd9Sstevel@tonic-gate 		if (category != LC_ALL)
3207c478bd9Sstevel@tonic-gate 			break;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	case LANGINFO:
3237c478bd9Sstevel@tonic-gate 		if ((ret = openlocale("LANGINFO", LANGINFO, locale,
3247c478bd9Sstevel@tonic-gate 		      _locales[LANGINFO - 1])) < 0) {
3257c478bd9Sstevel@tonic-gate 			lang_succ = OFF;
3267c478bd9Sstevel@tonic-gate 			return (NULL);
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 		if (ret) {
3297c478bd9Sstevel@tonic-gate 			lang_succ = OFF;
3307c478bd9Sstevel@tonic-gate 			(void) close(ret);
3317c478bd9Sstevel@tonic-gate 		}
3327c478bd9Sstevel@tonic-gate 		if (category != LC_ALL)
3337c478bd9Sstevel@tonic-gate 			break;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	case LC_COLLATE:
3367c478bd9Sstevel@tonic-gate 		if ((ret = openlocale("LC_COLLATE", LC_COLLATE, locale,
3377c478bd9Sstevel@tonic-gate 		      _locales[LC_COLLATE - 1])) < 0)
3387c478bd9Sstevel@tonic-gate 			return (NULL);
3397c478bd9Sstevel@tonic-gate 		if (ret) {
3407c478bd9Sstevel@tonic-gate 			(void) close(ret);
3417c478bd9Sstevel@tonic-gate 		}
3427c478bd9Sstevel@tonic-gate 		if (category != LC_ALL)
3437c478bd9Sstevel@tonic-gate 			break;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	case LC_MESSAGES:
3467c478bd9Sstevel@tonic-gate 		if ((ret = openlocale("LC_MESSAGES", LC_MESSAGES, locale,
3477c478bd9Sstevel@tonic-gate 		      _locales[LC_MESSAGES - 1])) < 0)
3487c478bd9Sstevel@tonic-gate 			return (NULL);
3497c478bd9Sstevel@tonic-gate 		if (ret) {
3507c478bd9Sstevel@tonic-gate 			(void) close(ret);
3517c478bd9Sstevel@tonic-gate 		}
3527c478bd9Sstevel@tonic-gate 	}
3537c478bd9Sstevel@tonic-gate 	return (setlocale(category, (char *)NULL));
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate int
357*5d54f3d8Smuffin getlocale_ctype(char *locale, char *ctypep, char *newlocale)
3587c478bd9Sstevel@tonic-gate {
359*5d54f3d8Smuffin 	int fd;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	if ((fd = openlocale("LC_CTYPE", LC_CTYPE, locale, newlocale)) > 0) {
3627c478bd9Sstevel@tonic-gate 		if (read(fd, (char *)ctypep, CTYPE_SIZE) != CTYPE_SIZE) {
3637c478bd9Sstevel@tonic-gate 			(void) close(fd);
3647c478bd9Sstevel@tonic-gate 			fd = -1;
3657c478bd9Sstevel@tonic-gate 		}
3667c478bd9Sstevel@tonic-gate 		(void) close(fd);
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 	return (fd);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /* open and load the numeric information */
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate char *
374*5d54f3d8Smuffin getlocale_numeric(char *locale, struct lconv *lconvp, char *newlocale)
3757c478bd9Sstevel@tonic-gate {
376*5d54f3d8Smuffin 	int fd;
3777c478bd9Sstevel@tonic-gate 	struct stat buf;
3787c478bd9Sstevel@tonic-gate 	char *str;
379*5d54f3d8Smuffin 	char *p;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	if ((fd = openlocale("LC_NUMERIC", LC_NUMERIC, locale, newlocale)) < 0)
3827c478bd9Sstevel@tonic-gate 		return (NULL);
3837c478bd9Sstevel@tonic-gate 	if (fd == 0)
3847c478bd9Sstevel@tonic-gate 		return "";
3857c478bd9Sstevel@tonic-gate 	if ((fstat(fd, &buf)) != 0)
3867c478bd9Sstevel@tonic-gate 		return (NULL);
3877c478bd9Sstevel@tonic-gate 	if ((str = (char*)malloc((unsigned)buf.st_size + 2)) == NULL)
3887c478bd9Sstevel@tonic-gate 		return (NULL);
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	if ((read(fd, str, (int)buf.st_size)) != buf.st_size) {
3917c478bd9Sstevel@tonic-gate 		free((malloc_t)str);
3927c478bd9Sstevel@tonic-gate 		return (NULL);
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	/* Set last character of str to '\0' */
3967c478bd9Sstevel@tonic-gate 	p = &str[buf.st_size];
3977c478bd9Sstevel@tonic-gate 	*p++ = '\n';
3987c478bd9Sstevel@tonic-gate 	*p = '\0';
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	/* p will "walk thru" str */
4017c478bd9Sstevel@tonic-gate 	p = str;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	p = getstr(p, &lconvp->decimal_point);
4047c478bd9Sstevel@tonic-gate 	if (p == NULL)
4057c478bd9Sstevel@tonic-gate 		goto fail;
4067c478bd9Sstevel@tonic-gate 	p = getstr(p, &lconvp->thousands_sep);
4077c478bd9Sstevel@tonic-gate 	if (p == NULL)
4087c478bd9Sstevel@tonic-gate 		goto fail;
4097c478bd9Sstevel@tonic-gate 	p = getgrouping(p, &lconvp->grouping);
4107c478bd9Sstevel@tonic-gate 	if (p == NULL)
4117c478bd9Sstevel@tonic-gate 		goto fail;
4127c478bd9Sstevel@tonic-gate 	(void) close(fd);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	return (str);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate fail:
4177c478bd9Sstevel@tonic-gate 	(void) close(fd);
4187c478bd9Sstevel@tonic-gate 	free((malloc_t)str);
4197c478bd9Sstevel@tonic-gate 	return (NULL);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate static char *
424*5d54f3d8Smuffin getlocale_monetary(char *locale, struct lconv *lconvp, char *newlocale)
4257c478bd9Sstevel@tonic-gate {
426*5d54f3d8Smuffin 	int fd;
4277c478bd9Sstevel@tonic-gate 	struct stat buf;
4287c478bd9Sstevel@tonic-gate 	char *str;
429*5d54f3d8Smuffin 	char *p;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	if ((fd = openlocale("LC_MONETARY", LC_MONETARY, locale, newlocale)) < 0)
4327c478bd9Sstevel@tonic-gate 		return (NULL);
4337c478bd9Sstevel@tonic-gate 	if (fd == 0)
434*5d54f3d8Smuffin 		return ("");
4357c478bd9Sstevel@tonic-gate 	if ((fstat(fd, &buf)) != 0)
4367c478bd9Sstevel@tonic-gate 		return (NULL);
4377c478bd9Sstevel@tonic-gate 	if ((str = (char*)malloc((unsigned)buf.st_size + 2)) == NULL)
4387c478bd9Sstevel@tonic-gate 		return (NULL);
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	if ((read(fd, str, (int)buf.st_size)) != buf.st_size) {
4417c478bd9Sstevel@tonic-gate 		free((malloc_t)str);
4427c478bd9Sstevel@tonic-gate 		return (NULL);
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	/* Set last character of str to '\0' */
4467c478bd9Sstevel@tonic-gate 	p = &str[buf.st_size];
4477c478bd9Sstevel@tonic-gate 	*p++ = '\n';
4487c478bd9Sstevel@tonic-gate 	*p = '\0';
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	/* p will "walk thru" str */
4517c478bd9Sstevel@tonic-gate 	p = str;
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	p = getstr(p, &lconvp->int_curr_symbol);
4547c478bd9Sstevel@tonic-gate 	if (p == NULL)
4557c478bd9Sstevel@tonic-gate 		goto fail;
4567c478bd9Sstevel@tonic-gate 	p = getstr(p, &lconvp->currency_symbol);
4577c478bd9Sstevel@tonic-gate 	if (p == NULL)
4587c478bd9Sstevel@tonic-gate 		goto fail;
4597c478bd9Sstevel@tonic-gate 	p = getstr(p, &lconvp->mon_decimal_point);
4607c478bd9Sstevel@tonic-gate 	if (p == NULL)
4617c478bd9Sstevel@tonic-gate 		goto fail;
4627c478bd9Sstevel@tonic-gate 	p = getstr(p, &lconvp->mon_thousands_sep);
4637c478bd9Sstevel@tonic-gate 	if (p == NULL)
4647c478bd9Sstevel@tonic-gate 		goto fail;
4657c478bd9Sstevel@tonic-gate 	p = getgrouping(p, &lconvp->mon_grouping);
4667c478bd9Sstevel@tonic-gate 	if (p == NULL)
4677c478bd9Sstevel@tonic-gate 		goto fail;
4687c478bd9Sstevel@tonic-gate 	p = getstr(p, &lconvp->positive_sign);
4697c478bd9Sstevel@tonic-gate 	if (p == NULL)
4707c478bd9Sstevel@tonic-gate 		goto fail;
4717c478bd9Sstevel@tonic-gate 	p = getstr(p, &lconvp->negative_sign);
4727c478bd9Sstevel@tonic-gate 	if (p == NULL)
4737c478bd9Sstevel@tonic-gate 		goto fail;
4747c478bd9Sstevel@tonic-gate 	p = getnum(p, &lconvp->frac_digits);
4757c478bd9Sstevel@tonic-gate 	if (p == NULL)
4767c478bd9Sstevel@tonic-gate 		goto fail;
4777c478bd9Sstevel@tonic-gate 	p = getbool(p, &lconvp->p_cs_precedes);
4787c478bd9Sstevel@tonic-gate 	if (p == NULL)
4797c478bd9Sstevel@tonic-gate 		goto fail;
4807c478bd9Sstevel@tonic-gate 	p = getbool(p, &lconvp->p_sep_by_space);
4817c478bd9Sstevel@tonic-gate 	if (p == NULL)
4827c478bd9Sstevel@tonic-gate 		goto fail;
4837c478bd9Sstevel@tonic-gate 	p = getbool(p, &lconvp->n_cs_precedes);
4847c478bd9Sstevel@tonic-gate 	if (p == NULL)
4857c478bd9Sstevel@tonic-gate 		goto fail;
4867c478bd9Sstevel@tonic-gate 	p = getbool(p, &lconvp->n_sep_by_space);
4877c478bd9Sstevel@tonic-gate 	if (p == NULL)
4887c478bd9Sstevel@tonic-gate 		goto fail;
4897c478bd9Sstevel@tonic-gate 	p = getnum(p, &lconvp->p_sign_posn);
4907c478bd9Sstevel@tonic-gate 	if (p == NULL)
4917c478bd9Sstevel@tonic-gate 		goto fail;
4927c478bd9Sstevel@tonic-gate 	p = getnum(p, &lconvp->n_sign_posn);
4937c478bd9Sstevel@tonic-gate 	if (p == NULL)
4947c478bd9Sstevel@tonic-gate 		goto fail;
4957c478bd9Sstevel@tonic-gate 	(void) close(fd);
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	return (str);
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate fail:
5007c478bd9Sstevel@tonic-gate 	(void) close(fd);
5017c478bd9Sstevel@tonic-gate 	free((malloc_t)str);
502*5d54f3d8Smuffin 	return (NULL);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate static char *
506*5d54f3d8Smuffin getstr(char *p, char **strp)
5077c478bd9Sstevel@tonic-gate {
5087c478bd9Sstevel@tonic-gate 	*strp = p;
5097c478bd9Sstevel@tonic-gate 	p = strchr(p, '\n');
5107c478bd9Sstevel@tonic-gate 	if (p == NULL)
5117c478bd9Sstevel@tonic-gate 		return (NULL);	/* no end-of-line */
5127c478bd9Sstevel@tonic-gate 	*p++ = '\0';
5137c478bd9Sstevel@tonic-gate 	return (p);
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate static char *
517*5d54f3d8Smuffin getgrouping(char *p, char **groupingp)
5187c478bd9Sstevel@tonic-gate {
519*5d54f3d8Smuffin 	int c;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	if (*p == '\0')
5227c478bd9Sstevel@tonic-gate 		return (NULL);	/* no grouping */
5237c478bd9Sstevel@tonic-gate 	*groupingp = p;
5247c478bd9Sstevel@tonic-gate 	while ((c = *p) != '\n') {
5257c478bd9Sstevel@tonic-gate 		if (c == '\0')
5267c478bd9Sstevel@tonic-gate 			return (NULL);	/* no end-of-line */
5277c478bd9Sstevel@tonic-gate 		if (c >= '0' && c <= '9')
5287c478bd9Sstevel@tonic-gate 			*p++ = c - '0';
5297c478bd9Sstevel@tonic-gate 		else
5307c478bd9Sstevel@tonic-gate 			*p++ = '\177';
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 	*p++ = '\0';
5337c478bd9Sstevel@tonic-gate 	return (p);
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate static char *
537*5d54f3d8Smuffin getnum(char *p, char *nump)
5387c478bd9Sstevel@tonic-gate {
539*5d54f3d8Smuffin 	int num;
540*5d54f3d8Smuffin 	int c;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	if (*p == '\0')
5437c478bd9Sstevel@tonic-gate 		return (NULL);	/* no number */
5447c478bd9Sstevel@tonic-gate 	if (*p == '\n')
5457c478bd9Sstevel@tonic-gate 		*nump = '\177';	/* blank line - no value */
5467c478bd9Sstevel@tonic-gate 	else {
5477c478bd9Sstevel@tonic-gate 		num = 0;
5487c478bd9Sstevel@tonic-gate 		while ((c = *p) != '\n') {
5497c478bd9Sstevel@tonic-gate 			if (c < '0' || c > '9')
5507c478bd9Sstevel@tonic-gate 				return (NULL);	/* bad number */
5517c478bd9Sstevel@tonic-gate 			num = num*10 + c - '0';
5527c478bd9Sstevel@tonic-gate 			p++;
5537c478bd9Sstevel@tonic-gate 		}
5547c478bd9Sstevel@tonic-gate 		*nump = num;
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 	*p++ = '\0';
5577c478bd9Sstevel@tonic-gate 	return (p);
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate static char *
561*5d54f3d8Smuffin getbool(char *p, char *boolp)
5627c478bd9Sstevel@tonic-gate {
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	if (*p == '\0')
5657c478bd9Sstevel@tonic-gate 		return (NULL);	/* no number */
5667c478bd9Sstevel@tonic-gate 	if (*p == '\n')
5677c478bd9Sstevel@tonic-gate 		*boolp = '\177';	/* blank line - no value */
5687c478bd9Sstevel@tonic-gate 	else {
5697c478bd9Sstevel@tonic-gate 		switch (*p++) {
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 		case 'y':
5727c478bd9Sstevel@tonic-gate 		case 'Y':
5737c478bd9Sstevel@tonic-gate 		case 't':
5747c478bd9Sstevel@tonic-gate 		case 'T':
5757c478bd9Sstevel@tonic-gate 			*boolp = 1;	/* true */
5767c478bd9Sstevel@tonic-gate 			break;
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 		case 'n':
5797c478bd9Sstevel@tonic-gate 		case 'N':
5807c478bd9Sstevel@tonic-gate 		case 'f':
5817c478bd9Sstevel@tonic-gate 		case 'F':
5827c478bd9Sstevel@tonic-gate 			*boolp = 0;	/* false */
5837c478bd9Sstevel@tonic-gate 			break;
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 		default:
5867c478bd9Sstevel@tonic-gate 			return (NULL);	/* bad boolean */
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 		if (*p != '\n')
5897c478bd9Sstevel@tonic-gate 			return (NULL);	/* noise at end of line */
5907c478bd9Sstevel@tonic-gate 	}
5917c478bd9Sstevel@tonic-gate 	*p++ = '\0';
5927c478bd9Sstevel@tonic-gate 	return (p);
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate  * Open a locale file.  First, check the value of "locale"; if it's a null
5977c478bd9Sstevel@tonic-gate  * string, first check the environment variable with the same name as the
5987c478bd9Sstevel@tonic-gate  * category, and then check the environment variable "LANG".  If neither of
5997c478bd9Sstevel@tonic-gate  * them are set to non-null strings, use the LC_default env.var and if this
6007c478bd9Sstevel@tonic-gate  * has no meaning then assume we are running in the C locale. It is expected
6017c478bd9Sstevel@tonic-gate  * That LC_default is set across the whole system. If the resulting locale is
6027c478bd9Sstevel@tonic-gate  * longer than MAXLOCALENAME characters, reject it.  Then, try looking in the
6037c478bd9Sstevel@tonic-gate  * per-machine locale directory for the file in question; if it's not found
6047c478bd9Sstevel@tonic-gate  * there, try looking in the shared locale directory.
6057c478bd9Sstevel@tonic-gate  * If there is no work to do, that is, the last setting of locales is equal
6067c478bd9Sstevel@tonic-gate  * to the current request, then we don't do anything, and exit with value 0.
6077c478bd9Sstevel@tonic-gate  * Copy the name of the locale used into "newlocale".
6087c478bd9Sstevel@tonic-gate  * Exit with positive value if we opened a file
6097c478bd9Sstevel@tonic-gate  * Exit with -1 if an error occured (invalid locale).
6107c478bd9Sstevel@tonic-gate  * Exit with 0 if there is no need to look at the disk file.
6117c478bd9Sstevel@tonic-gate  * (Assumption - there is always at least one fd open before setlocale
6127c478bd9Sstevel@tonic-gate  *  is called)
6137c478bd9Sstevel@tonic-gate  */
6147c478bd9Sstevel@tonic-gate int
615*5d54f3d8Smuffin openlocale(char *category, int cat_id, char *locale, char *newlocale)
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate 	char pathname[MAXPATHLEN], *defp;
6187c478bd9Sstevel@tonic-gate 	int fd, fd2;
6197c478bd9Sstevel@tonic-gate 	struct _code_header code_header;
6207c478bd9Sstevel@tonic-gate 	char *my_info;
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	if (*locale == '\0') {
6237c478bd9Sstevel@tonic-gate 		locale = getenv(category);
6247c478bd9Sstevel@tonic-gate 		if (locale == NULL || *locale == '\0') {
6257c478bd9Sstevel@tonic-gate 			locale = getenv("LANG");
6267c478bd9Sstevel@tonic-gate 			if (locale == NULL || *locale == '\0') {
6277c478bd9Sstevel@tonic-gate 				if (*Default == '\0') {
6287c478bd9Sstevel@tonic-gate 					defp = getenv("LC_default");
6297c478bd9Sstevel@tonic-gate 					if (defp == NULL || *defp == '\0')
6307c478bd9Sstevel@tonic-gate 						strcpy(Default,"C");
6317c478bd9Sstevel@tonic-gate 					else
6327c478bd9Sstevel@tonic-gate 						strcpy(Default, defp);
6337c478bd9Sstevel@tonic-gate 				}
6347c478bd9Sstevel@tonic-gate 				locale = Default;
6357c478bd9Sstevel@tonic-gate 			}
6367c478bd9Sstevel@tonic-gate 		}
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate 	if (strcmp(locale,_locales[cat_id-1]) == 0) {
6397c478bd9Sstevel@tonic-gate 		(void) strcpy(newlocale, locale);
640*5d54f3d8Smuffin 		return (0);
6417c478bd9Sstevel@tonic-gate 	}
6427c478bd9Sstevel@tonic-gate 	if (strlen(locale) > MAXLOCALENAME)
643*5d54f3d8Smuffin 		return (-1);
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	(void) strcpy(pathname, PRIVATE_LOCALE_DIR);
6467c478bd9Sstevel@tonic-gate 	(void) strcat(pathname, category);
6477c478bd9Sstevel@tonic-gate 	(void) strcat(pathname, "/");
6487c478bd9Sstevel@tonic-gate 	(void) strcat(pathname, locale);
6497c478bd9Sstevel@tonic-gate 	if ((fd = open(pathname, O_RDONLY)) < 0 && errno == ENOENT) {
6507c478bd9Sstevel@tonic-gate 		(void) strcpy(pathname, LOCALE_DIR);
6517c478bd9Sstevel@tonic-gate 		(void) strcat(pathname, category);
6527c478bd9Sstevel@tonic-gate 		(void) strcat(pathname, "/");
6537c478bd9Sstevel@tonic-gate 		(void) strcat(pathname, locale);
6547c478bd9Sstevel@tonic-gate 		fd = open(pathname, O_RDONLY);
6557c478bd9Sstevel@tonic-gate 	}
6567c478bd9Sstevel@tonic-gate 	if (fd >= 0)
6577c478bd9Sstevel@tonic-gate 		(void) strcpy(newlocale, locale);
6587c478bd9Sstevel@tonic-gate 	/*
6597c478bd9Sstevel@tonic-gate 	 * bug id 1072740; if by some chance the actual fd we're going to
6607c478bd9Sstevel@tonic-gate 	 * return is 0, change it to be some non-zero descriptor, because
6617c478bd9Sstevel@tonic-gate 	 * returning 0 means something different.  If '0' is the only
6627c478bd9Sstevel@tonic-gate 	 * descriptor left, return an error.
6637c478bd9Sstevel@tonic-gate 	 */
6647c478bd9Sstevel@tonic-gate 	if (fd == 0) {
6657c478bd9Sstevel@tonic-gate 		int dupfd;
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 		if ((dupfd = dup(fd)) < 1) {
6687c478bd9Sstevel@tonic-gate 			(void) close(fd);
6697c478bd9Sstevel@tonic-gate 			fd = -1;
6707c478bd9Sstevel@tonic-gate 		} else {
6717c478bd9Sstevel@tonic-gate 			(void) close(fd);
6727c478bd9Sstevel@tonic-gate 			fd = dupfd;
6737c478bd9Sstevel@tonic-gate 		}
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	if (cat_id == LC_CTYPE) {
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 		/* Go and get the trailer file */
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 		(void) strcat(pathname, TRAILER);
6817c478bd9Sstevel@tonic-gate 		fd2 = open(pathname, O_RDONLY);
6827c478bd9Sstevel@tonic-gate                 if ( fd2 == 0 ) {
6837c478bd9Sstevel@tonic-gate                         fd2 = dup(fd2);
6847c478bd9Sstevel@tonic-gate                         close(0);
6857c478bd9Sstevel@tonic-gate                 }
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 		if (fd2 == -1)  {
6887c478bd9Sstevel@tonic-gate 			set_default();
689*5d54f3d8Smuffin 			return (fd);
6907c478bd9Sstevel@tonic-gate 		}
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 		/*
6937c478bd9Sstevel@tonic-gate 		 * ctype trailer file  exists - read it
6947c478bd9Sstevel@tonic-gate 		 */
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 		if (read (fd2, (char *)&code_header, sizeof (code_header)) !=
6977c478bd9Sstevel@tonic-gate 						    sizeof (code_header)) {
6987c478bd9Sstevel@tonic-gate 			/*
6997c478bd9Sstevel@tonic-gate 			 * File format not correct
7007c478bd9Sstevel@tonic-gate 			 */
7017c478bd9Sstevel@tonic-gate 			 set_default();
7027c478bd9Sstevel@tonic-gate 			 close(fd2);
703*5d54f3d8Smuffin 			 return (-1);
7047c478bd9Sstevel@tonic-gate 		}
7057c478bd9Sstevel@tonic-gate 		/*
7067c478bd9Sstevel@tonic-gate 		 * set up trailer file
7077c478bd9Sstevel@tonic-gate 		 */
7087c478bd9Sstevel@tonic-gate 		 strcpy(_code_set_info.code_name, code_header.code_name);
7097c478bd9Sstevel@tonic-gate 		 _code_set_info.code_id = code_header.code_id;
7107c478bd9Sstevel@tonic-gate 		 if (_code_set_info.code_info != NULL)
7117c478bd9Sstevel@tonic-gate 			free (_code_set_info.code_info);
7127c478bd9Sstevel@tonic-gate 		 if (code_header.code_info_size > 0)  {
7137c478bd9Sstevel@tonic-gate 			my_info = malloc(code_header.code_info_size);
7147c478bd9Sstevel@tonic-gate 			if (read (fd2, (char *)my_info,
7157c478bd9Sstevel@tonic-gate 			 code_header.code_info_size) !=
7167c478bd9Sstevel@tonic-gate 		 	 code_header.code_info_size) {
7177c478bd9Sstevel@tonic-gate 					close(fd2);
7187c478bd9Sstevel@tonic-gate 					set_default();
719*5d54f3d8Smuffin 					return (-1);
7207c478bd9Sstevel@tonic-gate 				}
7217c478bd9Sstevel@tonic-gate 			_code_set_info.code_info = my_info;
7227c478bd9Sstevel@tonic-gate 		 }
7237c478bd9Sstevel@tonic-gate 		 else {
7247c478bd9Sstevel@tonic-gate 		 /*
7257c478bd9Sstevel@tonic-gate 		  * We have a corrupted file too
7267c478bd9Sstevel@tonic-gate 		  */
7277c478bd9Sstevel@tonic-gate 			_code_set_info.code_info = NULL;
7287c478bd9Sstevel@tonic-gate 			close(fd2);
7297c478bd9Sstevel@tonic-gate 			set_default();
730*5d54f3d8Smuffin 			return (-1);
7317c478bd9Sstevel@tonic-gate 		 }
7327c478bd9Sstevel@tonic-gate 		 close (fd2);
7337c478bd9Sstevel@tonic-gate 	}
734*5d54f3d8Smuffin 	return (fd);
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate struct	lconv *
738*5d54f3d8Smuffin localeconv(void)
7397c478bd9Sstevel@tonic-gate {
7407c478bd9Sstevel@tonic-gate 	return (lconv);
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate struct	dtconv *
744*5d54f3d8Smuffin localdtconv(void)
7457c478bd9Sstevel@tonic-gate {
746*5d54f3d8Smuffin 	char *p;
747*5d54f3d8Smuffin 	short i;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	char *rawmonths = "Jan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug\nSep\nOct\nNov\nDec\nJanuary\nFebruary\nMarch\nApril\nMay\nJune\nJuly\nAugust\nSeptember\nOctober\nNovember\nDecember";
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	char *rawdays = "Sun\nMon\nTue\nWed\nThu\nFri\nSat\nSunday\nMonday\nTuesday\nWednesday\nThursday\nFriday\nSaturday";
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate char *rawfmts = "%H:%M:%S\n%m/%d/%y\n%a %b %e %T %Z %Y\nAM\nPM\n%A, %B %e, %Y\n";
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	/* fix for bugid 1067574 ... robinson */
7567c478bd9Sstevel@tonic-gate         (void)getlocale_time();
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	if (_dtconv == NULL) {
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 		/* We malloc both the space for the dtconv struct and the
7617c478bd9Sstevel@tonic-gate 		 * copy of the strings above because this program is later run
7627c478bd9Sstevel@tonic-gate 		 * through xstr and the resultant strings are put in read-only
7637c478bd9Sstevel@tonic-gate 		 * text segment. Therefore we cannot write to the original
7647c478bd9Sstevel@tonic-gate 		 * raw strings but we can to their copies.
7657c478bd9Sstevel@tonic-gate 		 */
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 		_dtconv = (struct dtconv*)malloc(sizeof (struct dtconv));
7687c478bd9Sstevel@tonic-gate 		if (_dtconv == NULL)
7697c478bd9Sstevel@tonic-gate 			return (NULL);
7707c478bd9Sstevel@tonic-gate 		if ((realmonths = malloc(strlen(rawmonths)+1)) == NULL)
7717c478bd9Sstevel@tonic-gate 			return (NULL);
7727c478bd9Sstevel@tonic-gate 		strcpy(realmonths, rawmonths);
7737c478bd9Sstevel@tonic-gate 		if ((realdays = malloc(strlen(rawdays)+1)) == NULL)
7747c478bd9Sstevel@tonic-gate 			return (NULL);
7757c478bd9Sstevel@tonic-gate 		strcpy(realdays, rawdays);
7767c478bd9Sstevel@tonic-gate 		if ((realfmts = malloc(strlen(rawfmts)+1)) == NULL)
7777c478bd9Sstevel@tonic-gate 			return (NULL);
7787c478bd9Sstevel@tonic-gate 		strcpy(realfmts, rawfmts);
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 		/* p will "walk thru" str */
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 		p = realmonths;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 		for (i = 0; i < 12; i++)
7857c478bd9Sstevel@tonic-gate 			p = getstr(p, &(_dtconv->abbrev_month_names[i]));
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 		for (i = 0; i < 12; i++)
7887c478bd9Sstevel@tonic-gate 			p = getstr(p, &(_dtconv->month_names[i]));
7897c478bd9Sstevel@tonic-gate 		p = realdays;
7907c478bd9Sstevel@tonic-gate 		for (i= 0; i < 7; i++)
7917c478bd9Sstevel@tonic-gate 			p = getstr(p, &(_dtconv->abbrev_weekday_names[i]));
7927c478bd9Sstevel@tonic-gate 		for (i = 0; i < 7; i++)
7937c478bd9Sstevel@tonic-gate 			p = getstr(p, &(_dtconv->weekday_names[i]));
7947c478bd9Sstevel@tonic-gate 		p = realfmts;
7957c478bd9Sstevel@tonic-gate 		p = getstr(p, &_dtconv->time_format);
7967c478bd9Sstevel@tonic-gate 		p = getstr(p, &_dtconv->sdate_format);
7977c478bd9Sstevel@tonic-gate 		p = getstr(p, &_dtconv->dtime_format);
7987c478bd9Sstevel@tonic-gate 		p = getstr(p, &_dtconv->am_string);
7997c478bd9Sstevel@tonic-gate 		p = getstr(p, &_dtconv->pm_string);
8007c478bd9Sstevel@tonic-gate 		p = getstr(p, &_dtconv->ldate_format);
8017c478bd9Sstevel@tonic-gate 	}
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	return (_dtconv);
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 
807*5d54f3d8Smuffin static void
808*5d54f3d8Smuffin set_default(void)
8097c478bd9Sstevel@tonic-gate {
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	strcpy(_code_set_info.code_name, Default);
8127c478bd9Sstevel@tonic-gate 	_code_set_info.code_id = CODESET_NONE;
8137c478bd9Sstevel@tonic-gate 	if (_code_set_info.code_info != NULL)
8147c478bd9Sstevel@tonic-gate 		free (_code_set_info.code_info);
8157c478bd9Sstevel@tonic-gate 	_code_set_info.code_info = NULL;
8167c478bd9Sstevel@tonic-gate 	_code_set_info.open_flag = 0;
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate 
819*5d54f3d8Smuffin void
820*5d54f3d8Smuffin init_statics(void)
821*5d54f3d8Smuffin {
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	short i;
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	for (i=0; i<MAXLOCALE-1;i++)
8267c478bd9Sstevel@tonic-gate 		strcpy(_locales[i],"C");
8277c478bd9Sstevel@tonic-gate 	strcpy(_code_set_info.code_name, "default");
8287c478bd9Sstevel@tonic-gate 	strcpy(_my_time,"C");
8297c478bd9Sstevel@tonic-gate 	_langinfo.yesstr = "yes";
8307c478bd9Sstevel@tonic-gate 	_langinfo.nostr = "no";
8317c478bd9Sstevel@tonic-gate }
832