/* * %CopyrightBegin% * * Copyright Ericsson AB 2006-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * %CopyrightEnd% */ /* * Darwin needs conversion! * http://developer.apple.com/library/mac/#qa/qa2001/qa1235.html */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "sys.h" #include "global.h" #if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) #define __DARWIN__ 1 #endif #if !defined(__WIN32__) #include #if !defined(HAVE_SETLOCALE) || !defined(HAVE_NL_LANGINFO) || !defined(HAVE_LANGINFO_H) #define PRIMITIVE_UTF8_CHECK 1 #else #include #endif #endif /* * erts_check_io_time is used by the erl_check_io implementation. The * global erts_check_io_time variable is declared here since there * (often) exist two versions of erl_check_io (kernel-poll and * non-kernel-poll), and we dont want two versions of this variable. */ erts_smp_atomic_t erts_check_io_time; /* Written once and only once */ static int filename_encoding = ERL_FILENAME_UNKNOWN; static int filename_warning = ERL_FILENAME_WARNING_WARNING; #if defined(__WIN32__) || defined(__DARWIN__) /* Default unicode on windows and MacOS X */ static int user_filename_encoding = ERL_FILENAME_UTF8; #else static int user_filename_encoding = ERL_FILENAME_UNKNOWN; #endif /* This controls the heuristic in printing characters in shell and w/ io:format("~tp", ...) etc. */ static int printable_character_set = ERL_PRINTABLE_CHARACTERS_LATIN1; void erts_set_user_requested_filename_encoding(int encoding, int warning) { user_filename_encoding = encoding; filename_warning = warning; } int erts_get_user_requested_filename_encoding(void) { return user_filename_encoding; } int erts_get_filename_warning_type(void) { return filename_warning; } void erts_set_printable_characters(int range) { /* Not an atomic */ printable_character_set = range; } int erts_get_printable_characters(void) { return printable_character_set; } void erts_init_sys_common_misc(void) { #if defined(__WIN32__) /* win_efile will totally fail if this is not set. */ filename_encoding = ERL_FILENAME_WIN_WCHAR; #else if (user_filename_encoding != ERL_FILENAME_UNKNOWN) { filename_encoding = user_filename_encoding; } else { char *l; filename_encoding = ERL_FILENAME_LATIN1; # ifdef PRIMITIVE_UTF8_CHECK setlocale(LC_CTYPE, ""); /* Set international environment, ignore result */ if (((l = getenv("LC_ALL")) && *l) || ((l = getenv("LC_CTYPE")) && *l) || ((l = getenv("LANG")) && *l)) { if (strstr(l, "UTF-8")) { filename_encoding = ERL_FILENAME_UTF8; } } # else l = setlocale(LC_CTYPE, ""); /* Set international environment */ if (l != NULL) { if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) { filename_encoding = ERL_FILENAME_UTF8; } } # endif } # if defined(__DARWIN__) if (filename_encoding == ERL_FILENAME_UTF8) { filename_encoding = ERL_FILENAME_UTF8_MAC; } # endif #endif } int erts_get_native_filename_encoding(void) { return filename_encoding; } /* For internal use by sys_double_to_chars_fast() */ static char* find_first_trailing_zero(char* p) { for (; *(p-1) == '0'; --p); if (*(p-1) == '.') ++p; return p; } int sys_double_to_chars(double fp, char *buffer, size_t buffer_size) { return sys_double_to_chars_ext(fp, buffer, buffer_size, SYS_DEFAULT_FLOAT_DECIMALS); } /* Convert float to string using fixed point notation. * decimals must be >= 0 * if compact != 0, the trailing 0's will be truncated */ int sys_double_to_chars_fast(double f, char *buffer, int buffer_size, int decimals, int compact) { #define SYS_DOUBLE_RND_CONST 0.5 #define FRAC_SIZE 52 #define EXP_SIZE 11 #define EXP_MASK (((Uint64)1 << EXP_SIZE) - 1) #define MAX_DECIMALS (sizeof(cs_sys_double_pow10) \ / sizeof(cs_sys_double_pow10[0])) #define FRAC_MASK (((Uint64)1 << FRAC_SIZE) - 1) #define FRAC_MASK2 (((Uint64)1 << (FRAC_SIZE + 1)) - 1) #define MAX_FLOAT ((Uint64)1 << (FRAC_SIZE+1)) static const double cs_sys_double_pow10[] = { SYS_DOUBLE_RND_CONST / 1e0, SYS_DOUBLE_RND_CONST / 1e1, SYS_DOUBLE_RND_CONST / 1e2, SYS_DOUBLE_RND_CONST / 1e3, SYS_DOUBLE_RND_CONST / 1e4, SYS_DOUBLE_RND_CONST / 1e5, SYS_DOUBLE_RND_CONST / 1e6, SYS_DOUBLE_RND_CONST / 1e7, SYS_DOUBLE_RND_CONST / 1e8, SYS_DOUBLE_RND_CONST / 1e9, SYS_DOUBLE_RND_CONST / 1e10, SYS_DOUBLE_RND_CONST / 1e11, SYS_DOUBLE_RND_CONST / 1e12, SYS_DOUBLE_RND_CONST / 1e13, SYS_DOUBLE_RND_CONST / 1e14, SYS_DOUBLE_RND_CONST / 1e15, SYS_DOUBLE_RND_CONST / 1e16, SYS_DOUBLE_RND_CONST / 1e17, SYS_DOUBLE_RND_CONST / 1e18 }; Uint64 mantissa, int_part, frac_part; int exp; int fbits; int max; int neg; double fr; union { Uint64 L; double F; } x; char *p = buffer; if (decimals < 0) return -1; if (f >= 0) { neg = 0; fr = decimals < MAX_DECIMALS ? (f + cs_sys_double_pow10[decimals]) : f; x.F = fr; } else { neg = 1; fr = decimals < MAX_DECIMALS ? (f - cs_sys_double_pow10[decimals]) : f; x.F = -fr; } exp = (x.L >> FRAC_SIZE) & EXP_MASK; mantissa = x.L & FRAC_MASK; if (exp == EXP_MASK) { if (mantissa == 0) { if (neg) *p++ = '-'; *p++ = 'i'; *p++ = 'n'; *p++ = 'f'; } else { *p++ = 'n'; *p++ = 'a'; *p++ = 'n'; } *p = '\0'; return p - buffer; } exp -= EXP_MASK >> 1; mantissa |= ((Uint64)1 << FRAC_SIZE); /* Don't bother with optimizing too large numbers or too large precision */ if (x.F > MAX_FLOAT || decimals >= MAX_DECIMALS) { int len = erts_snprintf(buffer, buffer_size, "%.*f", decimals, f); char* p = buffer + len; if (len >= buffer_size) return -1; /* Delete trailing zeroes */ if (compact) p = find_first_trailing_zero(p); *p = '\0'; return p - buffer; } else if (exp >= FRAC_SIZE) { int_part = mantissa << (exp - FRAC_SIZE); frac_part = 0; fbits = FRAC_SIZE; /* not important as frac_part==0 */ } else if (exp >= 0) { fbits = FRAC_SIZE - exp; int_part = mantissa >> fbits; frac_part = mantissa & (((Uint64)1 << fbits) -1); } else /* if (exp < 0) */ { int_part = 0; frac_part = mantissa; fbits = FRAC_SIZE - exp; } if (!int_part) { if (neg) *p++ = '-'; *p++ = '0'; } else { int ret, i, n; while (int_part != 0) { *p++ = (char)((int_part % 10) + '0'); int_part /= 10; } if (neg) *p++ = '-'; /* Reverse string */ ret = p - buffer; for (i = 0, n = ret/2; i < n; i++) { int j = ret - i - 1; char c = buffer[i]; buffer[i] = buffer[j]; buffer[j] = c; } } if (decimals > 0) { int i; *p++ = '.'; max = buffer_size - (p - buffer) - 1 /* leave room for trailing '\0' */; if (decimals > max) return -1; /* the number is not large enough to fit in the buffer */ max = decimals; for (i = 0; i < max; i++) { if (frac_part > (ERTS_UINT64_MAX/5)) { frac_part >>= 3; fbits -= 3; } /* Multiply by 10 (5*2) to extract decimal digit as integer part */ frac_part *= 5; fbits--; if (fbits >= 64) { *p++ = '0'; } else { *p++ = (char)((frac_part >> fbits) + '0'); frac_part &= ((Uint64)1 << fbits) - 1; } } /* Delete trailing zeroes */ if (compact) p = find_first_trailing_zero(p); } *p = '\0'; return p - buffer; }