xref: /titanic_51/usr/src/lib/libbc/libc/gen/common/setlocale.c (revision fe598cdcd847f8359013532d5c691bb6190378c0)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1995 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <sys/fcntl.h>
34 #include <locale.h>
35 #include <stdlib.h>
36 #include "codeset.h"
37 #include <ctype.h>
38 #include <string.h>
39 #include <memory.h>
40 #include <malloc.h>
41 #include <sys/param.h>		/* for MAXPATHLEN */
42 #include <sys/stat.h>
43 #include <errno.h>
44 #include <limits.h>
45 
46 #define	TRAILER ".ci"
47 
48 
49 struct	_code_set_info _code_set_info = {
50 	NULL,
51 	CODESET_NONE, 	/* no codeset */
52 	NULL, 		/* not defined */
53 	0,
54 };
55 
56 /* tolower()  and toupper() conversion table
57  * is hidden here to avoid being placed in the
58  * extern  .sa file in the dynamic version of libc
59  */
60 
61 char _ctype_ul[] = { 0,
62 
63 /*	 0	 1	 2	 3	 4	 5	 6	 7  */
64 	'\000',	'\001',	'\002',	'\003',	'\004',	'\005',	'\006',	'\007',
65 	'\010',	'\011',	'\012',	'\013',	'\014',	'\015',	'\016',	'\017',
66 	'\020',	'\021',	'\022',	'\023',	'\024',	'\025',	'\026',	'\027',
67 	'\030',	'\031',	'\032',	'\033',	'\034',	'\035',	'\036',	'\037',
68 	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
69 	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
70 	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
71 	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
72 	'@',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
73 	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
74 	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
75 	'x',	'y',	'z',	'[',	'\\',	']',	'^',	'_',
76 	'`',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
77 	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
78 	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
79 	'X',	'Y',	'Z',	'{',	'|',	'}',	'~',	'\177',
80 	0,	0,	0,	0,	0,	0,	0,	0,
81 	0,	0,	0,	0,	0,	0,	0,	0,
82 	0,	0,	0,	0,	0,	0,	0,	0,
83 	0,	0,	0,	0,	0,	0,	0,	0,
84 	0,	0,	0,	0,	0,	0,	0,	0,
85 	0,	0,	0,	0,	0,	0,	0,	0,
86 	0,	0,	0,	0,	0,	0,	0,	0,
87 	0,	0,	0,	0,	0,	0,	0,	0,
88 	0,	0,	0,	0,	0,	0,	0,	0,
89 	0,	0,	0,	0,	0,	0,	0,	0,
90 	0,	0,	0,	0,	0,	0,	0,	0,
91 	0,	0,	0,	0,	0,	0,	0,	0,
92 	0,	0,	0,	0,	0,	0,	0,	0,
93 	0,	0,	0,	0,	0,	0,	0,	0,
94 	0,	0,	0,	0,	0,	0,	0,	0,
95 	0,	0,	0,	0,	0,	0,	0,	0,
96 };
97 
98 /* following layout is:
99  * LC_NUMERIC LC_TIME LC_MONETARY LANGINFO LC_COLLATE LC_MESSAGES
100  */
101 char _locales[MAXLOCALE - 1][MAXLOCALENAME + 1] ;
102 
103 char _my_time[MAXLOCALENAME + 1];
104 
105 /* The array Default holds the systems notion of default locale. It is normally
106  * found in {LOCALE}/.default and moved to here. Note there is only one
107  * default locale spanning all categories
108  */
109 
110 static char Default[MAXLOCALENAME+1];
111 
112 struct	langinfo _langinfo;
113 struct	dtconv *_dtconv = NULL;
114 
115 static	char *realmonths = NULL;
116 static	char *realdays = NULL;
117 static	char *realfmts = NULL;
118 static  short lang_succ = ON;	/* setlocale success */
119 
120 
121 /* Set the values here to guarantee stdio use of the
122    decimal point
123  */
124 static struct lconv lconv_arr = {
125 	".", "", "", "", "",
126 	"", "", "", "", "",
127 	CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX,
128 	CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX
129 };
130 
131 /* lconv is externally defined by ANSI C */
132 struct	lconv *lconv = &lconv_arr;
133 
134 static	char *lconv_numeric_str = NULL;
135 static 	char *lconv_monetary_str = NULL;
136 
137 int	openlocale(char *, int, char *, char *);
138 int	getlocale_ctype(char *, char *, char *);
139 char	*getlocale_numeric(char *, struct lconv *, char *);
140 void	init_statics(void);
141 static char	*getlocale_monetary(char *, struct lconv *, char *);
142 static char	*getstr(char *, char **);
143 static char	*getgrouping(char *, char **);
144 static char	*getnum(char  *, char *);
145 static char	*getbool(char *, char *);
146 static void	set_default(void);
147 
148 char *
149 setlocale(int category, char *locale)
150 {
151 	static char buf[MAXLOCALE*(MAXLOCALENAME + 1) + 1];
152 		/* buffer for current LC_ALL value */
153 	int nonuniform;
154 	short ret;
155 	char my_ctype[CTYPE_SIZE];	/* local copy */
156 	struct lconv my_lconv;		/* local copy */
157 	char *my_lconv_numeric_str;
158 	char *my_lconv_monetary_str;
159 	int i;
160 	char *p;
161 
162 
163 	 /* initialize my_lconv to lconv */
164         memcpy(&my_lconv, lconv, sizeof(my_lconv));
165 
166 	/*
167 	 *  Following code is to avoid static initialisation of
168 	 *  strings which would otherwise blow up "xstr".
169 	 */
170 	if (_locales[0][0] == '\0')
171 		init_statics();
172 
173 	if (locale == NULL) {
174 		if (category == LC_ALL) {
175 			/*
176 			 * Assume all locales are set to the same value.  Then
177 			 * scan through the locales to see if any are
178 			 * different.  If they are the same, return the common
179 			 * value; otherwise, construct a "composite" value.
180 			 */
181 			nonuniform = 0;	/* assume all locales set the same */
182 			for (i = 0; i < MAXLOCALE - 2; i++) {
183 				if (strcmp(_locales[i], _locales[i + 1]) != 0) {
184 					nonuniform = 1;
185 					break;
186 				}
187 			}
188 			if (nonuniform) {
189 				/*
190 				 * They're not all the same.  Construct a list
191 				 * of all the locale values, in order,
192 				 * separated by slashes.  Return that value.
193 				 */
194 				(void) strcpy(buf, _locales[0]);
195 				for (i = 1; i < MAXLOCALE - 1; i++) {
196 					(void) strcat(buf, "/");
197 					(void) strcat(buf, _locales[i]);
198 				}
199 				return (buf);
200 			} else {
201 				/*
202 				 * They're all the same; any one you return is
203 				 * OK.
204 				 */
205 				return (_locales[0]);
206 			}
207 		} else
208 			return (_locales[category - 1]);
209 	}
210 
211 	switch (category) {
212 
213 	case LC_ALL:
214 		if (strchr(locale, '/') != NULL) {
215 			/*
216 			 * Composite value; extract each category.
217 			 */
218 			if (strlen(locale) > sizeof buf - 1)
219 				return (NULL);	/* too long */
220 			(void) strcpy(buf, locale);
221 			p = buf;
222 
223 			/*
224 			 * LC_CTYPE and LC_NUMERIC are set here.
225 			 * Others locales won't be set here,
226 			 * they will be just marked.
227 			 */
228 			for (i = 0; i < MAXLOCALE - 1; i++) {
229 				p = strtok(p, "/");
230 				if (p == NULL)
231 					return (NULL);	/* missing item */
232 				switch (i) {
233 
234 				case LC_CTYPE - 1:
235 					if (setlocale(LC_CTYPE,p) == NULL)
236 						return (NULL);
237 					break;
238 				case LC_NUMERIC - 1:
239 					if (setlocale(LC_NUMERIC,p) == NULL)
240 						return (NULL);
241 					break;
242 				case LC_TIME - 1:
243 					if (setlocale(LC_TIME,p) == NULL)
244 						return (NULL);
245 					break;
246 				case LC_MONETARY - 1:
247 					if (setlocale(LC_MONETARY,p) == NULL)
248 						return (NULL);
249 					break;
250 				case LANGINFO - 1:
251 					if (setlocale(LANGINFO,p) == NULL)
252 						return (NULL);
253 					break;
254 				case LC_COLLATE - 1:
255 					if (setlocale(LC_COLLATE,p) == NULL)
256 						return (NULL);
257 					break;
258 				case LC_MESSAGES - 1:
259 					if (setlocale(LC_MESSAGES,p) == NULL)
260 						return (NULL);
261 					break;
262 				}
263 				p = NULL;
264 			}
265 			if (strtok((char *)NULL, "/") != NULL)
266 				return (NULL);	/* extra stuff at end */
267 		}
268 
269 	/* If category = LC_ALL, Drop through to test each individual
270   	 * category, one at a time. Note default rules where env vars
271 	 * are not set
272 	 */
273 
274 	case LC_CTYPE:
275 		if ((ret = getlocale_ctype(locale , my_ctype,
276 		    _locales[LC_CTYPE - 1])) < 0)
277 			return (NULL);
278 		if (ret) {
279 		      (void) memcpy(_ctype_, my_ctype, CTYPE_SIZE/2);
280 		      (void) memcpy(_ctype_ul, my_ctype+(CTYPE_SIZE/2), CTYPE_SIZE/2);
281 		}
282 		if (category != LC_ALL)
283 			break;
284 
285 	case LC_NUMERIC:
286 		if ((my_lconv_numeric_str =
287 		    getlocale_numeric(locale, &my_lconv,
288 		      _locales[LC_NUMERIC - 1])) == NULL)
289 			return (NULL);
290 		if (*my_lconv_numeric_str) {
291 			if (lconv_numeric_str != NULL)
292 				free((malloc_t)lconv_numeric_str);
293 			lconv_numeric_str = my_lconv_numeric_str;
294 			memcpy(lconv, my_lconv, sizeof(my_lconv));
295 		}
296 		if (category != LC_ALL)
297 			break;
298 
299 	case LC_TIME:
300 		if ((ret = openlocale("LC_TIME", LC_TIME, locale,
301 		      _locales[LC_TIME -1])) < 0)
302 			return (NULL);
303 		if (ret)
304 			(void) close(ret);
305 		if (category != LC_ALL)
306 			break;
307 
308 	case LC_MONETARY:
309 		if ((my_lconv_monetary_str =
310 		    getlocale_monetary(locale, &my_lconv,
311 		      _locales[LC_MONETARY - 1])) == NULL)
312 			return (NULL);
313 		if (*my_lconv_monetary_str) {
314 			if (lconv_monetary_str != NULL)
315 				free((malloc_t)lconv_monetary_str);
316 			lconv_monetary_str = my_lconv_monetary_str;
317 			memcpy(lconv, &my_lconv, sizeof(my_lconv));
318 		}
319 		if (category != LC_ALL)
320 			break;
321 
322 	case LANGINFO:
323 		if ((ret = openlocale("LANGINFO", LANGINFO, locale,
324 		      _locales[LANGINFO - 1])) < 0) {
325 			lang_succ = OFF;
326 			return (NULL);
327 		}
328 		if (ret) {
329 			lang_succ = OFF;
330 			(void) close(ret);
331 		}
332 		if (category != LC_ALL)
333 			break;
334 
335 	case LC_COLLATE:
336 		if ((ret = openlocale("LC_COLLATE", LC_COLLATE, locale,
337 		      _locales[LC_COLLATE - 1])) < 0)
338 			return (NULL);
339 		if (ret) {
340 			(void) close(ret);
341 		}
342 		if (category != LC_ALL)
343 			break;
344 
345 	case LC_MESSAGES:
346 		if ((ret = openlocale("LC_MESSAGES", LC_MESSAGES, locale,
347 		      _locales[LC_MESSAGES - 1])) < 0)
348 			return (NULL);
349 		if (ret) {
350 			(void) close(ret);
351 		}
352 	}
353 	return (setlocale(category, (char *)NULL));
354 }
355 
356 int
357 getlocale_ctype(char *locale, char *ctypep, char *newlocale)
358 {
359 	int fd;
360 
361 	if ((fd = openlocale("LC_CTYPE", LC_CTYPE, locale, newlocale)) > 0) {
362 		if (read(fd, (char *)ctypep, CTYPE_SIZE) != CTYPE_SIZE) {
363 			(void) close(fd);
364 			fd = -1;
365 		}
366 		(void) close(fd);
367 	}
368 	return (fd);
369 }
370 
371 /* open and load the numeric information */
372 
373 char *
374 getlocale_numeric(char *locale, struct lconv *lconvp, char *newlocale)
375 {
376 	int fd;
377 	struct stat buf;
378 	char *str;
379 	char *p;
380 
381 	if ((fd = openlocale("LC_NUMERIC", LC_NUMERIC, locale, newlocale)) < 0)
382 		return (NULL);
383 	if (fd == 0)
384 		return "";
385 	if ((fstat(fd, &buf)) != 0)
386 		return (NULL);
387 	if ((str = (char*)malloc((unsigned)buf.st_size + 2)) == NULL)
388 		return (NULL);
389 
390 	if ((read(fd, str, (int)buf.st_size)) != buf.st_size) {
391 		free((malloc_t)str);
392 		return (NULL);
393 	}
394 
395 	/* Set last character of str to '\0' */
396 	p = &str[buf.st_size];
397 	*p++ = '\n';
398 	*p = '\0';
399 
400 	/* p will "walk thru" str */
401 	p = str;
402 
403 	p = getstr(p, &lconvp->decimal_point);
404 	if (p == NULL)
405 		goto fail;
406 	p = getstr(p, &lconvp->thousands_sep);
407 	if (p == NULL)
408 		goto fail;
409 	p = getgrouping(p, &lconvp->grouping);
410 	if (p == NULL)
411 		goto fail;
412 	(void) close(fd);
413 
414 	return (str);
415 
416 fail:
417 	(void) close(fd);
418 	free((malloc_t)str);
419 	return (NULL);
420 }
421 
422 
423 static char *
424 getlocale_monetary(char *locale, struct lconv *lconvp, char *newlocale)
425 {
426 	int fd;
427 	struct stat buf;
428 	char *str;
429 	char *p;
430 
431 	if ((fd = openlocale("LC_MONETARY", LC_MONETARY, locale, newlocale)) < 0)
432 		return (NULL);
433 	if (fd == 0)
434 		return ("");
435 	if ((fstat(fd, &buf)) != 0)
436 		return (NULL);
437 	if ((str = (char*)malloc((unsigned)buf.st_size + 2)) == NULL)
438 		return (NULL);
439 
440 	if ((read(fd, str, (int)buf.st_size)) != buf.st_size) {
441 		free((malloc_t)str);
442 		return (NULL);
443 	}
444 
445 	/* Set last character of str to '\0' */
446 	p = &str[buf.st_size];
447 	*p++ = '\n';
448 	*p = '\0';
449 
450 	/* p will "walk thru" str */
451 	p = str;
452 
453 	p = getstr(p, &lconvp->int_curr_symbol);
454 	if (p == NULL)
455 		goto fail;
456 	p = getstr(p, &lconvp->currency_symbol);
457 	if (p == NULL)
458 		goto fail;
459 	p = getstr(p, &lconvp->mon_decimal_point);
460 	if (p == NULL)
461 		goto fail;
462 	p = getstr(p, &lconvp->mon_thousands_sep);
463 	if (p == NULL)
464 		goto fail;
465 	p = getgrouping(p, &lconvp->mon_grouping);
466 	if (p == NULL)
467 		goto fail;
468 	p = getstr(p, &lconvp->positive_sign);
469 	if (p == NULL)
470 		goto fail;
471 	p = getstr(p, &lconvp->negative_sign);
472 	if (p == NULL)
473 		goto fail;
474 	p = getnum(p, &lconvp->frac_digits);
475 	if (p == NULL)
476 		goto fail;
477 	p = getbool(p, &lconvp->p_cs_precedes);
478 	if (p == NULL)
479 		goto fail;
480 	p = getbool(p, &lconvp->p_sep_by_space);
481 	if (p == NULL)
482 		goto fail;
483 	p = getbool(p, &lconvp->n_cs_precedes);
484 	if (p == NULL)
485 		goto fail;
486 	p = getbool(p, &lconvp->n_sep_by_space);
487 	if (p == NULL)
488 		goto fail;
489 	p = getnum(p, &lconvp->p_sign_posn);
490 	if (p == NULL)
491 		goto fail;
492 	p = getnum(p, &lconvp->n_sign_posn);
493 	if (p == NULL)
494 		goto fail;
495 	(void) close(fd);
496 
497 	return (str);
498 
499 fail:
500 	(void) close(fd);
501 	free((malloc_t)str);
502 	return (NULL);
503 }
504 
505 static char *
506 getstr(char *p, char **strp)
507 {
508 	*strp = p;
509 	p = strchr(p, '\n');
510 	if (p == NULL)
511 		return (NULL);	/* no end-of-line */
512 	*p++ = '\0';
513 	return (p);
514 }
515 
516 static char *
517 getgrouping(char *p, char **groupingp)
518 {
519 	int c;
520 
521 	if (*p == '\0')
522 		return (NULL);	/* no grouping */
523 	*groupingp = p;
524 	while ((c = *p) != '\n') {
525 		if (c == '\0')
526 			return (NULL);	/* no end-of-line */
527 		if (c >= '0' && c <= '9')
528 			*p++ = c - '0';
529 		else
530 			*p++ = '\177';
531 	}
532 	*p++ = '\0';
533 	return (p);
534 }
535 
536 static char *
537 getnum(char *p, char *nump)
538 {
539 	int num;
540 	int c;
541 
542 	if (*p == '\0')
543 		return (NULL);	/* no number */
544 	if (*p == '\n')
545 		*nump = '\177';	/* blank line - no value */
546 	else {
547 		num = 0;
548 		while ((c = *p) != '\n') {
549 			if (c < '0' || c > '9')
550 				return (NULL);	/* bad number */
551 			num = num*10 + c - '0';
552 			p++;
553 		}
554 		*nump = num;
555 	}
556 	*p++ = '\0';
557 	return (p);
558 }
559 
560 static char *
561 getbool(char *p, char *boolp)
562 {
563 
564 	if (*p == '\0')
565 		return (NULL);	/* no number */
566 	if (*p == '\n')
567 		*boolp = '\177';	/* blank line - no value */
568 	else {
569 		switch (*p++) {
570 
571 		case 'y':
572 		case 'Y':
573 		case 't':
574 		case 'T':
575 			*boolp = 1;	/* true */
576 			break;
577 
578 		case 'n':
579 		case 'N':
580 		case 'f':
581 		case 'F':
582 			*boolp = 0;	/* false */
583 			break;
584 
585 		default:
586 			return (NULL);	/* bad boolean */
587 		}
588 		if (*p != '\n')
589 			return (NULL);	/* noise at end of line */
590 	}
591 	*p++ = '\0';
592 	return (p);
593 }
594 
595 /*
596  * Open a locale file.  First, check the value of "locale"; if it's a null
597  * string, first check the environment variable with the same name as the
598  * category, and then check the environment variable "LANG".  If neither of
599  * them are set to non-null strings, use the LC_default env.var and if this
600  * has no meaning then assume we are running in the C locale. It is expected
601  * That LC_default is set across the whole system. If the resulting locale is
602  * longer than MAXLOCALENAME characters, reject it.  Then, try looking in the
603  * per-machine locale directory for the file in question; if it's not found
604  * there, try looking in the shared locale directory.
605  * If there is no work to do, that is, the last setting of locales is equal
606  * to the current request, then we don't do anything, and exit with value 0.
607  * Copy the name of the locale used into "newlocale".
608  * Exit with positive value if we opened a file
609  * Exit with -1 if an error occured (invalid locale).
610  * Exit with 0 if there is no need to look at the disk file.
611  * (Assumption - there is always at least one fd open before setlocale
612  *  is called)
613  */
614 int
615 openlocale(char *category, int cat_id, char *locale, char *newlocale)
616 {
617 	char pathname[MAXPATHLEN], *defp;
618 	int fd, fd2;
619 	struct _code_header code_header;
620 	char *my_info;
621 
622 	if (*locale == '\0') {
623 		locale = getenv(category);
624 		if (locale == NULL || *locale == '\0') {
625 			locale = getenv("LANG");
626 			if (locale == NULL || *locale == '\0') {
627 				if (*Default == '\0') {
628 					defp = getenv("LC_default");
629 					if (defp == NULL || *defp == '\0')
630 						strcpy(Default,"C");
631 					else
632 						strcpy(Default, defp);
633 				}
634 				locale = Default;
635 			}
636 		}
637 	}
638 	if (strcmp(locale,_locales[cat_id-1]) == 0) {
639 		(void) strcpy(newlocale, locale);
640 		return (0);
641 	}
642 	if (strlen(locale) > MAXLOCALENAME)
643 		return (-1);
644 
645 	(void) strcpy(pathname, PRIVATE_LOCALE_DIR);
646 	(void) strcat(pathname, category);
647 	(void) strcat(pathname, "/");
648 	(void) strcat(pathname, locale);
649 	if ((fd = open(pathname, O_RDONLY)) < 0 && errno == ENOENT) {
650 		(void) strcpy(pathname, LOCALE_DIR);
651 		(void) strcat(pathname, category);
652 		(void) strcat(pathname, "/");
653 		(void) strcat(pathname, locale);
654 		fd = open(pathname, O_RDONLY);
655 	}
656 	if (fd >= 0)
657 		(void) strcpy(newlocale, locale);
658 	/*
659 	 * bug id 1072740; if by some chance the actual fd we're going to
660 	 * return is 0, change it to be some non-zero descriptor, because
661 	 * returning 0 means something different.  If '0' is the only
662 	 * descriptor left, return an error.
663 	 */
664 	if (fd == 0) {
665 		int dupfd;
666 
667 		if ((dupfd = dup(fd)) < 1) {
668 			(void) close(fd);
669 			fd = -1;
670 		} else {
671 			(void) close(fd);
672 			fd = dupfd;
673 		}
674 	}
675 
676 	if (cat_id == LC_CTYPE) {
677 
678 		/* Go and get the trailer file */
679 
680 		(void) strcat(pathname, TRAILER);
681 		fd2 = open(pathname, O_RDONLY);
682                 if ( fd2 == 0 ) {
683                         fd2 = dup(fd2);
684                         close(0);
685                 }
686 
687 		if (fd2 == -1)  {
688 			set_default();
689 			return (fd);
690 		}
691 
692 		/*
693 		 * ctype trailer file  exists - read it
694 		 */
695 
696 		if (read (fd2, (char *)&code_header, sizeof (code_header)) !=
697 						    sizeof (code_header)) {
698 			/*
699 			 * File format not correct
700 			 */
701 			 set_default();
702 			 close(fd2);
703 			 return (-1);
704 		}
705 		/*
706 		 * set up trailer file
707 		 */
708 		 strcpy(_code_set_info.code_name, code_header.code_name);
709 		 _code_set_info.code_id = code_header.code_id;
710 		 if (_code_set_info.code_info != NULL)
711 			free (_code_set_info.code_info);
712 		 if (code_header.code_info_size > 0)  {
713 			my_info = malloc(code_header.code_info_size);
714 			if (read (fd2, (char *)my_info,
715 			 code_header.code_info_size) !=
716 		 	 code_header.code_info_size) {
717 					close(fd2);
718 					set_default();
719 					return (-1);
720 				}
721 			_code_set_info.code_info = my_info;
722 		 }
723 		 else {
724 		 /*
725 		  * We have a corrupted file too
726 		  */
727 			_code_set_info.code_info = NULL;
728 			close(fd2);
729 			set_default();
730 			return (-1);
731 		 }
732 		 close (fd2);
733 	}
734 	return (fd);
735 }
736 
737 struct	lconv *
738 localeconv(void)
739 {
740 	return (lconv);
741 }
742 
743 struct	dtconv *
744 localdtconv(void)
745 {
746 	char *p;
747 	short i;
748 
749 	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";
750 
751 	char *rawdays = "Sun\nMon\nTue\nWed\nThu\nFri\nSat\nSunday\nMonday\nTuesday\nWednesday\nThursday\nFriday\nSaturday";
752 
753 char *rawfmts = "%H:%M:%S\n%m/%d/%y\n%a %b %e %T %Z %Y\nAM\nPM\n%A, %B %e, %Y\n";
754 
755 	/* fix for bugid 1067574 ... robinson */
756         (void)getlocale_time();
757 
758 	if (_dtconv == NULL) {
759 
760 		/* We malloc both the space for the dtconv struct and the
761 		 * copy of the strings above because this program is later run
762 		 * through xstr and the resultant strings are put in read-only
763 		 * text segment. Therefore we cannot write to the original
764 		 * raw strings but we can to their copies.
765 		 */
766 
767 		_dtconv = (struct dtconv*)malloc(sizeof (struct dtconv));
768 		if (_dtconv == NULL)
769 			return (NULL);
770 		if ((realmonths = malloc(strlen(rawmonths)+1)) == NULL)
771 			return (NULL);
772 		strcpy(realmonths, rawmonths);
773 		if ((realdays = malloc(strlen(rawdays)+1)) == NULL)
774 			return (NULL);
775 		strcpy(realdays, rawdays);
776 		if ((realfmts = malloc(strlen(rawfmts)+1)) == NULL)
777 			return (NULL);
778 		strcpy(realfmts, rawfmts);
779 
780 		/* p will "walk thru" str */
781 
782 		p = realmonths;
783 
784 		for (i = 0; i < 12; i++)
785 			p = getstr(p, &(_dtconv->abbrev_month_names[i]));
786 
787 		for (i = 0; i < 12; i++)
788 			p = getstr(p, &(_dtconv->month_names[i]));
789 		p = realdays;
790 		for (i= 0; i < 7; i++)
791 			p = getstr(p, &(_dtconv->abbrev_weekday_names[i]));
792 		for (i = 0; i < 7; i++)
793 			p = getstr(p, &(_dtconv->weekday_names[i]));
794 		p = realfmts;
795 		p = getstr(p, &_dtconv->time_format);
796 		p = getstr(p, &_dtconv->sdate_format);
797 		p = getstr(p, &_dtconv->dtime_format);
798 		p = getstr(p, &_dtconv->am_string);
799 		p = getstr(p, &_dtconv->pm_string);
800 		p = getstr(p, &_dtconv->ldate_format);
801 	}
802 
803 	return (_dtconv);
804 }
805 
806 
807 static void
808 set_default(void)
809 {
810 
811 	strcpy(_code_set_info.code_name, Default);
812 	_code_set_info.code_id = CODESET_NONE;
813 	if (_code_set_info.code_info != NULL)
814 		free (_code_set_info.code_info);
815 	_code_set_info.code_info = NULL;
816 	_code_set_info.open_flag = 0;
817 }
818 
819 void
820 init_statics(void)
821 {
822 
823 	short i;
824 
825 	for (i=0; i<MAXLOCALE-1;i++)
826 		strcpy(_locales[i],"C");
827 	strcpy(_code_set_info.code_name, "default");
828 	strcpy(_my_time,"C");
829 	_langinfo.yesstr = "yes";
830 	_langinfo.nostr = "no";
831 }
832