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