1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2001-2018. 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 #ifdef HAVE_CONFIG_H
22 #  include "config.h"
23 #endif
24 
25 #include "sys.h"
26 #include "global.h"
27 #include "erl_process.h"
28 
29 void
erts_sys_init_float(void)30 erts_sys_init_float(void)
31 {
32 # ifdef SIGFPE
33     sys_signal(SIGFPE, SIG_IGN); /* Ignore so we can test for NaN and Inf */
34 # endif
35 }
36 
37 /* The following check is incorporated from the Vee machine */
38 
39 #define ISDIGIT(d) ((d) >= '0' && (d) <= '9')
40 
41 /*
42  ** Convert a double to ascii format 0.dddde[+|-]ddd
43  ** return number of characters converted or -1 if error.
44  **
45  ** These two functions should maybe use localeconv() to pick up
46  ** the current radix character, but since it is uncertain how
47  ** expensive such a system call is, and since no-one has heard
48  ** of other radix characters than '.' and ',' an ad-hoc
49  ** low execution time solution is used instead.
50  */
51 
52 int
sys_double_to_chars_ext(double fp,char * buffer,size_t buffer_size,size_t decimals)53 sys_double_to_chars_ext(double fp, char *buffer, size_t buffer_size, size_t decimals)
54 {
55     char *s = buffer;
56 
57     if (erts_snprintf(buffer, buffer_size, "%.*e", decimals, fp) >= buffer_size)
58         return -1;
59     /* Search upto decimal point */
60     if (*s == '+' || *s == '-') s++;
61     while (ISDIGIT(*s)) s++;
62     if (*s == ',') *s++ = '.'; /* Replace ',' with '.' */
63     /* Scan to end of string */
64     while (*s) s++;
65     return s-buffer; /* i.e strlen(buffer) */
66 }
67 
68 /* Float conversion */
69 
70 int
sys_chars_to_double(char * buf,double * fp)71 sys_chars_to_double(char* buf, double* fp)
72 {
73     char *s = buf, *t, *dp;
74 
75     /* Robert says that something like this is what he really wanted:
76      * (The [.,] radix test is NOT what Robert wanted - it was added later)
77      *
78      * 7 == sscanf(Tbuf, "%[+-]%[0-9][.,]%[0-9]%[eE]%[+-]%[0-9]%s", ....);
79      * if (*s2 == 0 || *s3 == 0 || *s4 == 0 || *s6 == 0 || *s7)
80      *   break;
81      */
82 
83     /* Scan string to check syntax. */
84     if (*s == '+' || *s == '-') s++;
85     if (!ISDIGIT(*s))		/* Leading digits. */
86       return -1;
87     while (ISDIGIT(*s)) s++;
88     if (*s != '.' && *s != ',')	/* Decimal part. */
89       return -1;
90     dp = s++;			/* Remember decimal point pos just in case */
91     if (!ISDIGIT(*s))
92       return -1;
93     while (ISDIGIT(*s)) s++;
94     if (*s == 'e' || *s == 'E') {
95 	/* There is an exponent. */
96 	s++;
97 	if (*s == '+' || *s == '-') s++;
98 	if (!ISDIGIT(*s))
99 	  return -1;
100 	while (ISDIGIT(*s)) s++;
101     }
102     if (*s)			/* That should be it */
103       return -1;
104 
105     errno = 0;
106 
107     *fp = strtod(buf, &t);
108 
109     if (!erts_isfinite(*fp)) {
110         return -1;
111     }
112 
113     if (t != s) {		/* Whole string not scanned */
114 	/* Try again with other radix char */
115 	*dp = (*dp == '.') ? ',' : '.';
116 	errno = 0;
117 	__ERTS_FP_CHECK_INIT(fpexnp);
118 	*fp = strtod(buf, &t);
119         if (!erts_isfinite(*fp)) {
120             return -1;
121         }
122     }
123 
124     if (errno == ERANGE) {
125 	if (*fp == HUGE_VAL || *fp == -HUGE_VAL) {
126 	    /* overflow, should give error */
127 	    return -1;
128 	} else if (t == s && *fp == 0.0) {
129 	    /* This should give 0.0 - OTP-7178 */
130 	    errno = 0;
131 
132 	} else if (*fp == 0.0) {
133 	    return -1;
134 	}
135     }
136 
137     return 0;
138 }
139 
140 #ifdef USE_MATHERR
141 
142 int
matherr(struct exception * exc)143 matherr(struct exception *exc)
144 {
145     return 1;
146 }
147 
148 #endif
149