1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2006-2020. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 
22 
23 /*
24  * Darwin needs conversion!
25  * http://developer.apple.com/library/mac/#qa/qa2001/qa1235.html
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #  include "config.h"
30 #endif
31 
32 #include "sys.h"
33 #include "global.h"
34 
35 #if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__)
36 #define __DARWIN__ 1
37 #endif
38 
39 #if !defined(__WIN32__)
40 #include <locale.h>
41 #if !defined(HAVE_SETLOCALE) || !defined(HAVE_NL_LANGINFO) || !defined(HAVE_LANGINFO_H)
42 #define PRIMITIVE_UTF8_CHECK 1
43 #else
44 #include <langinfo.h>
45 #endif
46 #endif
47 
48 /* Written once and only once */
49 
50 static int filename_encoding = ERL_FILENAME_UNKNOWN;
51 static int filename_warning = ERL_FILENAME_WARNING_WARNING;
52 #if defined(__WIN32__) || defined(__DARWIN__) || defined(__ANDROID__)
53 /* Default to Unicode on Windows, MacOS X and Android */
54 static int user_filename_encoding = ERL_FILENAME_UTF8;
55 #else
56 static int user_filename_encoding = ERL_FILENAME_UNKNOWN;
57 #endif
58 /* This controls the heuristic in printing characters in shell and w/
59    io:format("~tp", ...) etc. */
60 static int printable_character_set = ERL_PRINTABLE_CHARACTERS_LATIN1;
61 
erts_set_user_requested_filename_encoding(int encoding,int warning)62 void erts_set_user_requested_filename_encoding(int encoding, int warning)
63 {
64     user_filename_encoding = encoding;
65     filename_warning = warning;
66 }
67 
erts_get_user_requested_filename_encoding(void)68 int erts_get_user_requested_filename_encoding(void)
69 {
70     return user_filename_encoding;
71 }
72 
erts_get_filename_warning_type(void)73 int erts_get_filename_warning_type(void)
74 {
75     return filename_warning;
76 }
77 
erts_set_printable_characters(int range)78 void erts_set_printable_characters(int range) {
79     /* Not an atomic */
80     printable_character_set = range;
81 }
82 
erts_get_printable_characters(void)83 int erts_get_printable_characters(void) {
84     return  printable_character_set;
85 }
86 
erts_init_sys_common_misc(void)87 void erts_init_sys_common_misc(void)
88 {
89 #if defined(__WIN32__)
90     /* win_efile will totally fail if this is not set. */
91     filename_encoding = ERL_FILENAME_WIN_WCHAR;
92 #else
93     if (user_filename_encoding != ERL_FILENAME_UNKNOWN) {
94 	filename_encoding = user_filename_encoding;
95     } else {
96 	char *l;
97 	filename_encoding = ERL_FILENAME_LATIN1;
98 #  ifdef PRIMITIVE_UTF8_CHECK
99 	setlocale(LC_CTYPE, "");  /* Set international environment,
100 				     ignore result */
101 	if (((l = getenv("LC_ALL"))   && *l) ||
102 	    ((l = getenv("LC_CTYPE")) && *l) ||
103 	    ((l = getenv("LANG"))     && *l)) {
104 	    if (strstr(l, "UTF-8")) {
105 		filename_encoding = ERL_FILENAME_UTF8;
106 	    }
107 	}
108 
109 #  else
110 	l = setlocale(LC_CTYPE, "");  /* Set international environment */
111 	if (l != NULL) {
112 	    if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) {
113 		filename_encoding = ERL_FILENAME_UTF8;
114 	    }
115 	}
116 #  endif
117     }
118 #  if defined(__DARWIN__)
119     if (filename_encoding == ERL_FILENAME_UTF8) {
120 	filename_encoding = ERL_FILENAME_UTF8_MAC;
121     }
122 #  endif
123 #endif
124 }
125 
erts_get_native_filename_encoding(void)126 int erts_get_native_filename_encoding(void)
127 {
128     return filename_encoding;
129 }
130 
131 /* For internal use by sys_double_to_chars_fast() */
find_first_trailing_zero(char * p)132 static char* find_first_trailing_zero(char* p)
133 {
134     for (; *(p-1) == '0'; --p);
135     if (*(p-1) == '.') ++p;
136     return p;
137 }
138 
139 int
sys_double_to_chars(double fp,char * buffer,size_t buffer_size)140 sys_double_to_chars(double fp, char *buffer, size_t buffer_size)
141 {
142     return sys_double_to_chars_ext(fp, buffer, buffer_size, SYS_DEFAULT_FLOAT_DECIMALS);
143 }
144 
145 
146 #if SIZEOF_LONG == 8
147 # define round_int64 lround
148 #elif SIZEOF_LONG_LONG == 8
149 # define round_int64 llround
150 #else
151 # error "No 64-bit integer type?"
152 #endif
153 
154 /* Convert float to string
155  *   decimals must be >= 0
156  *   if compact != 0, the trailing 0's will be truncated
157  */
158 int
sys_double_to_chars_fast(double f,char * buffer,int buffer_size,int decimals,int compact)159 sys_double_to_chars_fast(double f, char *buffer, int buffer_size, int decimals,
160 			 int compact)
161 {
162     #define SYS_DOUBLE_RND_CONST 0.5
163     #define FRAC_SIZE            52
164     #define EXP_SIZE             11
165     #define EXP_MASK             (((Uint64)1 << EXP_SIZE) - 1)
166     #define MAX_DECIMALS         (sizeof(pow10v) / sizeof(pow10v[0]))
167     #define FRAC_MASK            (((Uint64)1 << FRAC_SIZE) - 1)
168     #define FRAC_MASK2           (((Uint64)1 << (FRAC_SIZE + 1)) - 1)
169     #define MAX_FLOAT            ((Uint64)1 << (FRAC_SIZE+1))
170 
171     static const double pow10v[] = {
172         1e0,  1e1,  1e2,  1e3,  1e4,  1e5,  1e6,  1e7,  1e8, 1e9,
173         1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18
174     };
175 
176     double af;
177     Uint64 int_part, frac_part;
178     int neg;
179     int  has_decimals = decimals != 0;
180     char *p = buffer;
181 
182     if (decimals < 0)
183         return -1;
184 
185     if (f < 0) {
186         neg = 1;
187         af = -f;
188     }
189     else {
190         neg = 0;
191         af = f;
192     }
193 
194     /* Don't bother with optimizing too large numbers or too large precision */
195     if (af > MAX_FLOAT || decimals >= MAX_DECIMALS) {
196         int len = erts_snprintf(buffer, buffer_size, "%.*f", decimals, f);
197         char* p = buffer + len;
198         if (len >= buffer_size)
199             return -1;
200         /* Delete trailing zeroes */
201         if (compact)
202             p = find_first_trailing_zero(p);
203         *p = '\0';
204         return p - buffer;
205     }
206 
207     if (decimals) {
208         double int_f = floor(af);
209         double frac_f = round((af - int_f) * pow10v[decimals]);
210 
211         int_part = (Uint64)int_f;
212         frac_part = (Uint64)frac_f;
213 
214         if (frac_f >= pow10v[decimals]) {
215             /* rounding overflow carry into int_part */
216             int_part++;
217             frac_part = 0;
218         }
219 
220         do {
221             Uint64 n;
222             if (!frac_part) {
223                 do {
224                     *p++ = '0';
225                 } while (--decimals);
226                 break;
227             }
228             n = frac_part / 10;
229             *p++ = (char)((frac_part - n*10) + '0');
230             frac_part = n;
231         } while (--decimals);
232 
233         *p++ = '.';
234     }
235     else
236         int_part = (Uint64)round_int64(af);
237 
238     if (!int_part) {
239         *p++ = '0';
240     } else {
241         do {
242             Uint64 n = int_part / 10;
243             *p++ = (char)((int_part - n*10) + '0');
244             int_part = n;
245         } while (int_part);
246     }
247     if (neg)
248         *p++ = '-';
249 
250     {/* Reverse string */
251         int i = 0;
252         int j = p - buffer - 1;
253         for ( ; i < j; i++, j--) {
254             char tmp = buffer[i];
255             buffer[i] = buffer[j];
256             buffer[j] = tmp;
257         }
258     }
259 
260     /* Delete trailing zeroes */
261     if (compact && has_decimals)
262         p = find_first_trailing_zero(p);
263     *p = '\0';
264     return p - buffer;
265 }
266