src/java.base/unix/native/libjava/java_props_md.c
changeset 47216 71c04702a3d5
parent 40192 64c0b3d47afb
child 50992 faf1cd52a5b7
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
       
    27 #include <stdio.h>
       
    28 #include <ctype.h>
       
    29 #endif
       
    30 #include <pwd.h>
       
    31 #include <locale.h>
       
    32 #ifndef ARCHPROPNAME
       
    33 #error "The macro ARCHPROPNAME has not been defined"
       
    34 #endif
       
    35 #include <sys/utsname.h>        /* For os_name and os_version */
       
    36 #include <langinfo.h>           /* For nl_langinfo */
       
    37 #include <stdlib.h>
       
    38 #include <string.h>
       
    39 #include <sys/types.h>
       
    40 #include <unistd.h>
       
    41 #include <sys/param.h>
       
    42 #include <time.h>
       
    43 #include <errno.h>
       
    44 
       
    45 #ifdef MACOSX
       
    46 #include "java_props_macosx.h"
       
    47 #endif
       
    48 
       
    49 #if defined(_ALLBSD_SOURCE)
       
    50 #if !defined(P_tmpdir)
       
    51 #include <paths.h>
       
    52 #define P_tmpdir _PATH_VARTMP
       
    53 #endif
       
    54 #endif
       
    55 
       
    56 #include "locale_str.h"
       
    57 #include "java_props.h"
       
    58 
       
    59 #if !defined(_ALLBSD_SOURCE)
       
    60 #ifdef __linux__
       
    61   #ifndef CODESET
       
    62   #define CODESET _NL_CTYPE_CODESET_NAME
       
    63   #endif
       
    64 #else
       
    65 #ifdef ALT_CODESET_KEY
       
    66 #define CODESET ALT_CODESET_KEY
       
    67 #endif
       
    68 #endif
       
    69 #endif /* !_ALLBSD_SOURCE */
       
    70 
       
    71 /* Take an array of string pairs (map of key->value) and a string (key).
       
    72  * Examine each pair in the map to see if the first string (key) matches the
       
    73  * string.  If so, store the second string of the pair (value) in the value and
       
    74  * return 1.  Otherwise do nothing and return 0.  The end of the map is
       
    75  * indicated by an empty string at the start of a pair (key of "").
       
    76  */
       
    77 static int
       
    78 mapLookup(char* map[], const char* key, char** value) {
       
    79     int i;
       
    80     for (i = 0; strcmp(map[i], ""); i += 2){
       
    81         if (!strcmp(key, map[i])){
       
    82             *value = map[i + 1];
       
    83             return 1;
       
    84         }
       
    85     }
       
    86     return 0;
       
    87 }
       
    88 
       
    89 #ifndef P_tmpdir
       
    90 #define P_tmpdir "/var/tmp"
       
    91 #endif
       
    92 
       
    93 static int ParseLocale(JNIEnv* env, int cat, char ** std_language, char ** std_script,
       
    94                        char ** std_country, char ** std_variant, char ** std_encoding) {
       
    95     char *temp = NULL;
       
    96     char *language = NULL, *country = NULL, *variant = NULL,
       
    97          *encoding = NULL;
       
    98     char *p, *encoding_variant, *old_temp, *old_ev;
       
    99     char *lc;
       
   100 
       
   101     /* Query the locale set for the category */
       
   102 
       
   103 #ifdef MACOSX
       
   104     lc = setupMacOSXLocale(cat); // malloc'd memory, need to free
       
   105 #else
       
   106     lc = setlocale(cat, NULL);
       
   107 #endif
       
   108 
       
   109 #ifndef __linux__
       
   110     if (lc == NULL) {
       
   111         return 0;
       
   112     }
       
   113 
       
   114     temp = malloc(strlen(lc) + 1);
       
   115     if (temp == NULL) {
       
   116 #ifdef MACOSX
       
   117         free(lc); // malloced memory
       
   118 #endif
       
   119         JNU_ThrowOutOfMemoryError(env, NULL);
       
   120         return 0;
       
   121     }
       
   122 
       
   123     if (cat == LC_CTYPE) {
       
   124         /*
       
   125          * Workaround for Solaris bug 4201684: Xlib doesn't like @euro
       
   126          * locales. Since we don't depend on the libc @euro behavior,
       
   127          * we just remove the qualifier.
       
   128          * On Linux, the bug doesn't occur; on the other hand, @euro
       
   129          * is needed there because it's a shortcut that also determines
       
   130          * the encoding - without it, we wouldn't get ISO-8859-15.
       
   131          * Therefore, this code section is Solaris-specific.
       
   132          */
       
   133         strcpy(temp, lc);
       
   134         p = strstr(temp, "@euro");
       
   135         if (p != NULL) {
       
   136             *p = '\0';
       
   137             setlocale(LC_ALL, temp);
       
   138         }
       
   139     }
       
   140 #else
       
   141     if (lc == NULL || !strcmp(lc, "C") || !strcmp(lc, "POSIX")) {
       
   142         lc = "en_US";
       
   143     }
       
   144 
       
   145     temp = malloc(strlen(lc) + 1);
       
   146     if (temp == NULL) {
       
   147         JNU_ThrowOutOfMemoryError(env, NULL);
       
   148         return 0;
       
   149     }
       
   150 
       
   151 #endif
       
   152 
       
   153     /*
       
   154      * locale string format in Solaris is
       
   155      * <language name>_<country name>.<encoding name>@<variant name>
       
   156      * <country name>, <encoding name>, and <variant name> are optional.
       
   157      */
       
   158 
       
   159     strcpy(temp, lc);
       
   160 #ifdef MACOSX
       
   161     free(lc); // malloced memory
       
   162 #endif
       
   163     /* Parse the language, country, encoding, and variant from the
       
   164      * locale.  Any of the elements may be missing, but they must occur
       
   165      * in the order language_country.encoding@variant, and must be
       
   166      * preceded by their delimiter (except for language).
       
   167      *
       
   168      * If the locale name (without .encoding@variant, if any) matches
       
   169      * any of the names in the locale_aliases list, map it to the
       
   170      * corresponding full locale name.  Most of the entries in the
       
   171      * locale_aliases list are locales that include a language name but
       
   172      * no country name, and this facility is used to map each language
       
   173      * to a default country if that's possible.  It's also used to map
       
   174      * the Solaris locale aliases to their proper Java locale IDs.
       
   175      */
       
   176 
       
   177     encoding_variant = malloc(strlen(temp)+1);
       
   178     if (encoding_variant == NULL) {
       
   179         free(temp);
       
   180         JNU_ThrowOutOfMemoryError(env, NULL);
       
   181         return 0;
       
   182     }
       
   183 
       
   184     if ((p = strchr(temp, '.')) != NULL) {
       
   185         strcpy(encoding_variant, p); /* Copy the leading '.' */
       
   186         *p = '\0';
       
   187     } else if ((p = strchr(temp, '@')) != NULL) {
       
   188         strcpy(encoding_variant, p); /* Copy the leading '@' */
       
   189         *p = '\0';
       
   190     } else {
       
   191         *encoding_variant = '\0';
       
   192     }
       
   193 
       
   194     if (mapLookup(locale_aliases, temp, &p)) {
       
   195         old_temp = temp;
       
   196         temp = realloc(temp, strlen(p)+1);
       
   197         if (temp == NULL) {
       
   198             free(old_temp);
       
   199             free(encoding_variant);
       
   200             JNU_ThrowOutOfMemoryError(env, NULL);
       
   201             return 0;
       
   202         }
       
   203         strcpy(temp, p);
       
   204         old_ev = encoding_variant;
       
   205         encoding_variant = realloc(encoding_variant, strlen(temp)+1);
       
   206         if (encoding_variant == NULL) {
       
   207             free(old_ev);
       
   208             free(temp);
       
   209             JNU_ThrowOutOfMemoryError(env, NULL);
       
   210             return 0;
       
   211         }
       
   212         // check the "encoding_variant" again, if any.
       
   213         if ((p = strchr(temp, '.')) != NULL) {
       
   214             strcpy(encoding_variant, p); /* Copy the leading '.' */
       
   215             *p = '\0';
       
   216         } else if ((p = strchr(temp, '@')) != NULL) {
       
   217             strcpy(encoding_variant, p); /* Copy the leading '@' */
       
   218             *p = '\0';
       
   219         }
       
   220     }
       
   221 
       
   222     language = temp;
       
   223     if ((country = strchr(temp, '_')) != NULL) {
       
   224         *country++ = '\0';
       
   225     }
       
   226 
       
   227     p = encoding_variant;
       
   228     if ((encoding = strchr(p, '.')) != NULL) {
       
   229         p[encoding++ - p] = '\0';
       
   230         p = encoding;
       
   231     }
       
   232     if ((variant = strchr(p, '@')) != NULL) {
       
   233         p[variant++ - p] = '\0';
       
   234     }
       
   235 
       
   236     /* Normalize the language name */
       
   237     if (std_language != NULL) {
       
   238         *std_language = "en";
       
   239         if (language != NULL && mapLookup(language_names, language, std_language) == 0) {
       
   240             *std_language = malloc(strlen(language)+1);
       
   241             strcpy(*std_language, language);
       
   242         }
       
   243     }
       
   244 
       
   245     /* Normalize the country name */
       
   246     if (std_country != NULL && country != NULL) {
       
   247         if (mapLookup(country_names, country, std_country) == 0) {
       
   248             *std_country = malloc(strlen(country)+1);
       
   249             strcpy(*std_country, country);
       
   250         }
       
   251     }
       
   252 
       
   253     /* Normalize the script and variant name.  Note that we only use
       
   254      * variants listed in the mapping array; others are ignored.
       
   255      */
       
   256     if (variant != NULL) {
       
   257         if (std_script != NULL) {
       
   258             mapLookup(script_names, variant, std_script);
       
   259         }
       
   260 
       
   261         if (std_variant != NULL) {
       
   262             mapLookup(variant_names, variant, std_variant);
       
   263         }
       
   264     }
       
   265 
       
   266     /* Normalize the encoding name.  Note that we IGNORE the string
       
   267      * 'encoding' extracted from the locale name above.  Instead, we use the
       
   268      * more reliable method of calling nl_langinfo(CODESET).  This function
       
   269      * returns an empty string if no encoding is set for the given locale
       
   270      * (e.g., the C or POSIX locales); we use the default ISO 8859-1
       
   271      * converter for such locales.
       
   272      */
       
   273     if (std_encoding != NULL) {
       
   274         /* OK, not so reliable - nl_langinfo() gives wrong answers on
       
   275          * Euro locales, in particular. */
       
   276         if (strcmp(p, "ISO8859-15") == 0)
       
   277             p = "ISO8859-15";
       
   278         else
       
   279             p = nl_langinfo(CODESET);
       
   280 
       
   281         /* Convert the bare "646" used on Solaris to a proper IANA name */
       
   282         if (strcmp(p, "646") == 0)
       
   283             p = "ISO646-US";
       
   284 
       
   285         /* return same result nl_langinfo would return for en_UK,
       
   286          * in order to use optimizations. */
       
   287         *std_encoding = (*p != '\0') ? p : "ISO8859-1";
       
   288 
       
   289 #ifdef __linux__
       
   290         /*
       
   291          * Remap the encoding string to a different value for japanese
       
   292          * locales on linux so that customized converters are used instead
       
   293          * of the default converter for "EUC-JP". The customized converters
       
   294          * omit support for the JIS0212 encoding which is not supported by
       
   295          * the variant of "EUC-JP" encoding used on linux
       
   296          */
       
   297         if (strcmp(p, "EUC-JP") == 0) {
       
   298             *std_encoding = "EUC-JP-LINUX";
       
   299         }
       
   300 #else
       
   301         if (strcmp(p,"eucJP") == 0) {
       
   302             /* For Solaris use customized vendor defined character
       
   303              * customized EUC-JP converter
       
   304              */
       
   305             *std_encoding = "eucJP-open";
       
   306         } else if (strcmp(p, "Big5") == 0 || strcmp(p, "BIG5") == 0) {
       
   307             /*
       
   308              * Remap the encoding string to Big5_Solaris which augments
       
   309              * the default converter for Solaris Big5 locales to include
       
   310              * seven additional ideographic characters beyond those included
       
   311              * in the Java "Big5" converter.
       
   312              */
       
   313             *std_encoding = "Big5_Solaris";
       
   314         } else if (strcmp(p, "Big5-HKSCS") == 0) {
       
   315             /*
       
   316              * Solaris uses HKSCS2001
       
   317              */
       
   318             *std_encoding = "Big5-HKSCS-2001";
       
   319         }
       
   320 #endif
       
   321 #ifdef MACOSX
       
   322         /*
       
   323          * For the case on MacOS X where encoding is set to US-ASCII, but we
       
   324          * don't have any encoding hints from LANG/LC_ALL/LC_CTYPE, use UTF-8
       
   325          * instead.
       
   326          *
       
   327          * The contents of ASCII files will still be read and displayed
       
   328          * correctly, but so will files containing UTF-8 characters beyond the
       
   329          * standard ASCII range.
       
   330          *
       
   331          * Specifically, this allows apps launched by double-clicking a .jar
       
   332          * file to correctly read UTF-8 files using the default encoding (see
       
   333          * 8011194).
       
   334          */
       
   335         if (strcmp(p,"US-ASCII") == 0 && getenv("LANG") == NULL &&
       
   336             getenv("LC_ALL") == NULL && getenv("LC_CTYPE") == NULL) {
       
   337             *std_encoding = "UTF-8";
       
   338         }
       
   339 #endif
       
   340     }
       
   341 
       
   342     free(temp);
       
   343     free(encoding_variant);
       
   344 
       
   345     return 1;
       
   346 }
       
   347 
       
   348 /* This function gets called very early, before VM_CALLS are setup.
       
   349  * Do not use any of the VM_CALLS entries!!!
       
   350  */
       
   351 java_props_t *
       
   352 GetJavaProperties(JNIEnv *env)
       
   353 {
       
   354     static java_props_t sprops;
       
   355     char *v; /* tmp var */
       
   356 
       
   357     if (sprops.user_dir) {
       
   358         return &sprops;
       
   359     }
       
   360 
       
   361     /* tmp dir */
       
   362     sprops.tmp_dir = P_tmpdir;
       
   363 #ifdef MACOSX
       
   364     /* darwin has a per-user temp dir */
       
   365     static char tmp_path[PATH_MAX];
       
   366     int pathSize = confstr(_CS_DARWIN_USER_TEMP_DIR, tmp_path, PATH_MAX);
       
   367     if (pathSize > 0 && pathSize <= PATH_MAX) {
       
   368         sprops.tmp_dir = tmp_path;
       
   369     }
       
   370 #endif /* MACOSX */
       
   371 
       
   372     /* Printing properties */
       
   373 #ifdef MACOSX
       
   374     sprops.printerJob = "sun.lwawt.macosx.CPrinterJob";
       
   375 #else
       
   376     sprops.printerJob = "sun.print.PSPrinterJob";
       
   377 #endif
       
   378 
       
   379     /* patches/service packs installed */
       
   380     sprops.patch_level = "unknown";
       
   381 
       
   382     /* Java 2D/AWT properties */
       
   383 #ifdef MACOSX
       
   384     // Always the same GraphicsEnvironment and Toolkit on Mac OS X
       
   385     sprops.graphics_env = "sun.awt.CGraphicsEnvironment";
       
   386     sprops.awt_toolkit = "sun.lwawt.macosx.LWCToolkit";
       
   387 
       
   388     // check if we're in a GUI login session and set java.awt.headless=true if not
       
   389     sprops.awt_headless = isInAquaSession() ? NULL : "true";
       
   390 #else
       
   391     sprops.graphics_env = "sun.awt.X11GraphicsEnvironment";
       
   392     sprops.awt_toolkit = "sun.awt.X11.XToolkit";
       
   393 #endif
       
   394 
       
   395     /* This is used only for debugging of font problems. */
       
   396     v = getenv("JAVA2D_FONTPATH");
       
   397     sprops.font_dir = v ? v : NULL;
       
   398 
       
   399 #ifdef SI_ISALIST
       
   400     /* supported instruction sets */
       
   401     {
       
   402         char list[258];
       
   403         sysinfo(SI_ISALIST, list, sizeof(list));
       
   404         sprops.cpu_isalist = strdup(list);
       
   405     }
       
   406 #else
       
   407     sprops.cpu_isalist = NULL;
       
   408 #endif
       
   409 
       
   410     /* endianness of platform */
       
   411     {
       
   412         unsigned int endianTest = 0xff000000;
       
   413         if (((char*)(&endianTest))[0] != 0)
       
   414             sprops.cpu_endian = "big";
       
   415         else
       
   416             sprops.cpu_endian = "little";
       
   417     }
       
   418 
       
   419     /* os properties */
       
   420     {
       
   421 #ifdef MACOSX
       
   422         setOSNameAndVersion(&sprops);
       
   423 #else
       
   424         struct utsname name;
       
   425         uname(&name);
       
   426         sprops.os_name = strdup(name.sysname);
       
   427 #ifdef _AIX
       
   428         {
       
   429             char *os_version = malloc(strlen(name.version) +
       
   430                                       strlen(name.release) + 2);
       
   431             if (os_version != NULL) {
       
   432                 strcpy(os_version, name.version);
       
   433                 strcat(os_version, ".");
       
   434                 strcat(os_version, name.release);
       
   435             }
       
   436             sprops.os_version = os_version;
       
   437         }
       
   438 #else
       
   439         sprops.os_version = strdup(name.release);
       
   440 #endif /* _AIX   */
       
   441 #endif /* MACOSX */
       
   442 
       
   443         sprops.os_arch = ARCHPROPNAME;
       
   444 
       
   445         if (getenv("GNOME_DESKTOP_SESSION_ID") != NULL) {
       
   446             sprops.desktop = "gnome";
       
   447         }
       
   448         else {
       
   449             sprops.desktop = NULL;
       
   450         }
       
   451     }
       
   452 
       
   453     /* ABI property (optional) */
       
   454 #ifdef JDK_ARCH_ABI_PROP_NAME
       
   455     sprops.sun_arch_abi = JDK_ARCH_ABI_PROP_NAME;
       
   456 #endif
       
   457 
       
   458     /* Determine the language, country, variant, and encoding from the host,
       
   459      * and store these in the user.language, user.country, user.variant and
       
   460      * file.encoding system properties. */
       
   461     setlocale(LC_ALL, "");
       
   462     if (ParseLocale(env, LC_CTYPE,
       
   463                     &(sprops.format_language),
       
   464                     &(sprops.format_script),
       
   465                     &(sprops.format_country),
       
   466                     &(sprops.format_variant),
       
   467                     &(sprops.encoding))) {
       
   468         ParseLocale(env, LC_MESSAGES,
       
   469                     &(sprops.language),
       
   470                     &(sprops.script),
       
   471                     &(sprops.country),
       
   472                     &(sprops.variant),
       
   473                     NULL);
       
   474     } else {
       
   475         sprops.language = "en";
       
   476         sprops.encoding = "ISO8859-1";
       
   477     }
       
   478     sprops.display_language = sprops.language;
       
   479     sprops.display_script = sprops.script;
       
   480     sprops.display_country = sprops.country;
       
   481     sprops.display_variant = sprops.variant;
       
   482 
       
   483     /* ParseLocale failed with OOME */
       
   484     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
       
   485 
       
   486 #ifdef MACOSX
       
   487     sprops.sun_jnu_encoding = "UTF-8";
       
   488 #else
       
   489     sprops.sun_jnu_encoding = sprops.encoding;
       
   490 #endif
       
   491 
       
   492 #ifdef _ALLBSD_SOURCE
       
   493 #if BYTE_ORDER == _LITTLE_ENDIAN
       
   494      sprops.unicode_encoding = "UnicodeLittle";
       
   495  #else
       
   496      sprops.unicode_encoding = "UnicodeBig";
       
   497  #endif
       
   498 #else /* !_ALLBSD_SOURCE */
       
   499 #ifdef __linux__
       
   500 #if __BYTE_ORDER == __LITTLE_ENDIAN
       
   501     sprops.unicode_encoding = "UnicodeLittle";
       
   502 #else
       
   503     sprops.unicode_encoding = "UnicodeBig";
       
   504 #endif
       
   505 #else
       
   506     sprops.unicode_encoding = "UnicodeBig";
       
   507 #endif
       
   508 #endif /* _ALLBSD_SOURCE */
       
   509 
       
   510     /* user properties */
       
   511     {
       
   512         struct passwd *pwent = getpwuid(getuid());
       
   513         sprops.user_name = pwent ? strdup(pwent->pw_name) : "?";
       
   514 #ifdef MACOSX
       
   515         setUserHome(&sprops);
       
   516 #else
       
   517         sprops.user_home = pwent ? strdup(pwent->pw_dir) : NULL;
       
   518 #endif
       
   519         if (sprops.user_home == NULL) {
       
   520             sprops.user_home = "?";
       
   521         }
       
   522     }
       
   523 
       
   524     /* User TIMEZONE */
       
   525     {
       
   526         /*
       
   527          * We defer setting up timezone until it's actually necessary.
       
   528          * Refer to TimeZone.getDefault(). However, the system
       
   529          * property is necessary to be able to be set by the command
       
   530          * line interface -D. Here temporarily set a null string to
       
   531          * timezone.
       
   532          */
       
   533         tzset();        /* for compatibility */
       
   534         sprops.timezone = "";
       
   535     }
       
   536 
       
   537     /* Current directory */
       
   538     {
       
   539         char buf[MAXPATHLEN];
       
   540         errno = 0;
       
   541         if (getcwd(buf, sizeof(buf))  == NULL)
       
   542             JNU_ThrowByName(env, "java/lang/Error",
       
   543              "Properties init: Could not determine current working directory.");
       
   544         else
       
   545             sprops.user_dir = strdup(buf);
       
   546     }
       
   547 
       
   548     sprops.file_separator = "/";
       
   549     sprops.path_separator = ":";
       
   550     sprops.line_separator = "\n";
       
   551 
       
   552 #ifdef MACOSX
       
   553     setProxyProperties(&sprops);
       
   554 #endif
       
   555 
       
   556     return &sprops;
       
   557 }
       
   558 
       
   559 jstring
       
   560 GetStringPlatform(JNIEnv *env, nchar* cstr)
       
   561 {
       
   562     return JNU_NewStringPlatform(env, cstr);
       
   563 }