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