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