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 *
setlocale(int category,char * locale)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
getlocale_ctype(char * locale,char * ctypep,char * newlocale)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 *
getlocale_numeric(char * locale,struct lconv * lconvp,char * newlocale)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 *
getlocale_monetary(char * locale,struct lconv * lconvp,char * newlocale)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 *
getstr(char * p,char ** strp)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 *
getgrouping(char * p,char ** groupingp)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 *
getnum(char * p,char * nump)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 *
getbool(char * p,char * boolp)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
openlocale(char * category,int cat_id,char * locale,char * newlocale)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 *
localeconv(void)738 localeconv(void)
739 {
740 return (lconv);
741 }
742
743 struct dtconv *
localdtconv(void)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
set_default(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
init_statics(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