* Bug 16373 fixed: fix issue of crashing in arm when displaying 0
[scilab.git] / scilab / modules / ast / src / cpp / types / tostring_common.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2009 - DIGITEO - Antoine ELIAS
4 *  Copyright (C) 2018 - 2019 - St├ęphane MOTTELET
5 *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14 *
15 */
16
17 #include <cmath>
18 #include <algorithm>
19 #include <iostream>
20 #include <iomanip>
21 #include "tostring_common.hxx"
22 #include "configvariable.hxx"
23
24 extern "C"
25 {
26 #include "sci_malloc.h"
27 #include "elem_common.h"
28 #include "os_string.h"
29 #include "dtoa.h"
30 #include "charEncoding.h"
31 }
32
33 #define POINT_SIZE 1
34 #define EXPOSANT_SIZE 2         //exposant symbol + exposant sign
35
36 //template <typename T>
37 //void GetIntFormat(T _TVal, int *_piWidth)
38 //{
39 // *_piWidth = (int)(log10((double)_abs64(_TVal)) + 1);
40 //}
41
42 //template <typename T>
43 //void AddIntValue(ostringstream *_postr, T _TVal, int _iWidth, bool bPrintPlusSign, bool bPrintOne)
44 //{
45 // if(bPrintPlusSign == true)
46 // {
47 //  *_postr << (_TVal < 0 ? MINUS_STRING_INT : PLUS_STRING);
48 // }
49 // else
50 // {
51 //  *_postr << (_TVal < 0 ? MINUS_STRING_INT : NO_SIGN);
52 // }
53 //
54 // configureStream(_postr, _iWidth, 0, ' ');
55 //
56 // if(bPrintOne == true || _TVal != 1)
57 // {
58 //  *_postr << right << _abs64(_TVal);
59 // }
60 //}
61
62 void addSign(std::wostringstream * _postr, double _dblVal, bool _bPrintPlusSign, bool _bPaddSign)
63 {
64     if (_bPrintPlusSign == true)
65     {
66         *_postr << (_dblVal < 0 ? MINUS_STRING : PLUS_STRING);
67     }
68     else
69     {
70         if (_bPaddSign)
71         {
72             *_postr << (_dblVal < 0 ? MINUS_STRING : NO_SIGN);
73         }
74         else
75         {
76             *_postr << (_dblVal < 0 ? MINUS_STRING : L"");
77         }
78     }
79 }
80
81 //void getDoubleFormat(double _dblVal, int *_piWidth, int *_piPrec, /*in/out*/bool* _pExp)
82 void getDoubleFormat(double _dblVal, DoubleFormat * _pDF)
83 {
84     double dblDec = 0;
85     double dblEnt = 0;
86     double dblAbs = std::fabs(_dblVal);
87     int iNbDigit = 0;
88     int iNbDec = 0;
89     int iBlankSize = _pDF->bPrintBlank ? BLANK_SIZE : 0;
90     _pDF->iSignLen = _pDF->bPrintBlank ? SIGN_LENGTH + BLANK_SIZE : _pDF->iSignLen;
91
92     _pDF->bExp |= ConfigVariable::getFormatMode() == 0;
93     int iTotalLen = 0;
94     int iPrecNeeded = ConfigVariable::getFormatSize();
95
96     if (ISNAN(_dblVal) || !finite(_dblVal))
97     {
98         _pDF->iWidth = 4;      //" nan" or " inf"
99         _pDF->iPrec = 0;
100         return;
101     }
102     //get integer part and fractionnal part
103     dblDec = std::modf(dblAbs, &dblEnt);
104
105     //compute len of entire part
106     if (dblEnt == 0)
107     {
108         //[-1, 1]
109         if (dblAbs == 0)
110         {
111             iNbDigit = -1;
112         }
113         else
114         {
115             iNbDigit = (int)std::fabs(std::floor(std::log10(dblAbs)));
116         }
117
118         if (iNbDigit >= (iPrecNeeded - 2) || _pDF->bExp)
119         {
120             //exponant
121             _pDF->bExp = true;
122             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE + EXPOSANT_SIZE + std::max(((int)log10((double)iNbDigit)) + 1, 2);
123             _pDF->iWidth = iPrecNeeded;
124             _pDF->iPrec = iPrecNeeded - iTotalLen;
125             return;
126         }
127         else
128         {
129             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE;
130         }
131     }
132     else
133     {
134         double dblTemp = log10(dblEnt);
135
136         if (dblTemp > (iPrecNeeded - 2) || _pDF->bExp)
137         {
138             //exponant mode
139             if (dblTemp == 0)
140             {
141                 dblTemp = 1;    //no incidence on value, just to allow log10(dblTemp)
142             }
143
144             _pDF->bExp = true;
145             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE + EXPOSANT_SIZE + std::max(((int)log10(dblTemp)) + 1, 2);
146             _pDF->iWidth = iPrecNeeded;
147             _pDF->iPrec = iPrecNeeded - iTotalLen;
148             return;
149         }
150         else
151         {
152             //number of digit in integer part
153             iTotalLen = iBlankSize + ((int)dblTemp + 1) + POINT_SIZE;
154         }
155     }
156
157     //prepare fractionnal part to precision asked
158     double dblScale = pow(10., iPrecNeeded - iTotalLen);
159     while (iTotalLen <= iPrecNeeded)
160     {
161         dblDec = dblDec * dblScale;
162         dblDec = floor(dblDec + 0.5);
163         dblDec = dblDec / dblScale;
164
165         // when dblAbs = 1.9999999..., modf function
166         // return a decimal part equal to 1.0
167         if (dblDec == 0. || dblDec == 1.)
168         {
169             break;
170         }
171
172         dblDec = dblDec * 10;
173         int iFloor = (int)floor(dblDec);
174
175         dblDec -= iFloor;
176         iTotalLen++;
177         iNbDec++;
178         dblScale /= 10;
179     }
180
181     _pDF->iWidth = iTotalLen;
182     _pDF->iPrec = iNbDec;
183 }
184
185 //void getComplexFormat(double _dblR, double _dblI, int *_piTotalWidth, int *_piWidthR, int *_piWidthI, int *_piPrecR, int *_piPrecI, bool* _pExpR, bool* _pExpI)
186 void getComplexFormat(double _dblR, double _dblI, int *_piTotalWidth, DoubleFormat * _pDFR, DoubleFormat * _pDFI)
187 {
188     getDoubleFormat(_dblR, _pDFR);
189     getDoubleFormat(_dblI, _pDFI);
190
191     *_piTotalWidth = _pDFR->iWidth + _pDFI->iWidth + 2 * (_pDFR->bPrintBlank ? BLANK_SIZE : 0) + BLANK_SIZE + SIZE_SYMBOL_I;
192 }
193
194 void addDoubleValue(std::wostringstream * _postr, double _dblVal, DoubleFormat * _pDF)
195 {
196     wchar_t pwstFormat[32] = {0};
197     wchar_t pwstOutput[32] = {0};     // > @ format max
198     wchar_t pwstSign[32] = {0};
199     char    pstBuf[32] = {0};
200
201     if (_pDF == NULL)
202     {
203         return;
204     }
205
206     const wchar_t* pBlank = L"";
207     if (_pDF->bPrintBlank)
208     {
209         pBlank = L" ";
210     }
211
212     const wchar_t* pSign = MINUS_STRING;
213     if (_dblVal >= 0 || ISNAN(_dblVal))
214     {
215         if (_pDF->bPrintPlusSign)
216         {
217             pSign = PLUS_STRING;
218         }
219         else if (_pDF->bPaddSign)
220         {
221             pSign = NO_SIGN;
222         }
223         else
224         {
225             // PLUS_SIGN "+" is not written by default
226             pSign = L"";
227         }
228     }
229
230     // Step 1: BLANK and SIGN in pwstSign
231     if (_pDF->bPrintComplexPlusSpace)
232     {
233         os_swprintf(pwstSign, 32, L"%ls%ls%ls", pBlank, pSign, pBlank);
234     }
235     else
236     {
237         os_swprintf(pwstSign, 32, L"%ls%ls", pBlank, pSign);
238     }
239
240
241     if (ISNAN(_dblVal))
242     {
243         //NaN
244         os_swprintf(pwstOutput, 32, L"%ls%-*ls", pwstSign, _pDF->iWidth - 1, L"Nan");
245     }
246     else if (!finite(_dblVal))
247     {
248         //Inf
249         os_swprintf(pwstOutput, 32, L"%ls%-*ls", pwstSign, _pDF->iWidth - 1, L"Inf");
250     }
251     else if (_pDF->bExp)
252     {
253         // Prints the exponent part 1.543D+03 for example
254         int iDecpt = 0;
255         int iSign = 0;
256         char *pRve = nullptr;
257         char *pDtoaStr = dtoa(fabs(_dblVal), 2, _pDF->iPrec + 1, &iDecpt, &iSign, &pRve);
258
259         std::string str(pDtoaStr);
260         freedtoa(pDtoaStr);
261
262         // in format("e") omiting the decimal point has a sense
263         // only if fabs(_dblVal) is an integer in {1...9}
264         if (_pDF->bPrintPoint || str.length() > 1)
265         {
266             /* add trailing zeros */
267             str.append(fmax(0, _pDF->iPrec + 1 - str.length()), '0');
268             str.insert(1, ".");
269         }
270
271         wchar_t* pwstData = to_wide_string(str.data());
272         os_swprintf(pwstOutput, 32, L"%ls%lsD%+.02d", pwstSign, pwstData, iDecpt - 1);
273         FREE(pwstData);
274     }
275     else if ((_pDF->bPrintOne == true) || (isEqual(fabs(_dblVal), 1)) == false)
276     {
277         //do not print if _bPrintOne == false && _dblVal == 1
278         int iDecpt = 0;
279         int iSign = 0;
280         int iWidth = _pDF->iWidth;
281         char *pRve = nullptr;
282         char *pDtoaStr = dtoa(fabs(_dblVal), 2, std::floor(log10(fabs(_dblVal))) + _pDF->iPrec + 1, &iDecpt, &iSign, &pRve);
283
284         std::string str(pDtoaStr);
285         freedtoa(pDtoaStr);
286
287         /* add leading 0.000..., if applicable */
288         if (iDecpt <= 0)
289         {
290             str.insert(str.begin(), 1 - iDecpt, '0');
291             str.insert(1, ".");
292         }
293         else if (_pDF->bPrintPoint || iDecpt < (int)str.length())
294         {
295             str.append(std::max(0, (iDecpt - (int)str.length())), '0');
296             str.insert(iDecpt, ".");
297         }
298         else
299         {
300             str.append(std::max(0, (iDecpt - (int)str.length())), '0');
301             iWidth--;
302         }
303
304         // trim or append trailing zeros, if applicable
305         if (_pDF->bPrintPoint == false)
306         {
307             iWidth = 1 + str.length();
308         }
309         else if (std::atof(str.data()) != fabs(_dblVal) && _pDF->bPrintTrailingZeros == true)
310         {
311             str.append(std::max(0, (ConfigVariable::getFormatSize() - (int)str.length())) - 1, '0');
312         }
313
314         wchar_t* pwstData = to_wide_string(str.data());
315         os_swprintf(pwstOutput, 32, L"%ls%-*ls", pwstSign, iWidth - 1, pwstData);
316         FREE(pwstData);
317     }
318     else if (wcslen(pwstSign) != 0)
319     {
320         os_swprintf(pwstOutput, 32, L"%ls", pwstSign);
321     }
322
323     *_postr << pwstOutput;
324 }
325
326 /*
327 void addDoubleValue(std::wostringstream *_postr, double _dblVal, int _iWidth, int _iPrec, bool bPrintPlusSign, bool bPrintOne, bool bPaddSign)
328 {
329     addSign(_postr, _dblVal, bPrintPlusSign, bPaddSign);
330     configureStream(_postr, _iWidth, _iPrec, ' ');
331
332     if(bPrintOne == true || isEqual(_dblVal, 1) == false)
333     {
334         NEWprintDoubleVar(_postr, _dblVal, _iWidth, _iPrec);
335     }
336 }
337 */
338 void addDoubleComplexValue(std::wostringstream * _postr, double _dblR, double _dblI, int _iTotalWidth, DoubleFormat * _pDFR, DoubleFormat * _pDFI)
339 {
340     std::wostringstream ostemp;
341
342     /*
343      * if R && !C -> R
344      * if R && C -> R + Ci
345      * if !R && !C -> 0
346      * if(!R && C -> Ci
347      */
348
349     // *_postr << "|%" << _iTotalWitdh << "%|";
350
351     //R
352     DoubleFormat df;
353
354     df.iPrec = _pDFR->iPrec;
355     df.bExp = _pDFR->bExp;
356
357     if (ISNAN(_dblR) || !finite(_dblR))
358     {
359         ostemp << std::left << std::setw(_pDFR->iWidth + 1);
360         addDoubleValue(&ostemp, _dblR, &df);
361     }
362     else
363     {
364         // following line allows to align sign of imaginary part
365         addDoubleValue(&ostemp, _dblR, &df);
366         addSpaces(&ostemp, _pDFR->iWidth - ostemp.tellp() + 1);
367     }
368     //I
369     df.iPrec = _pDFI->iPrec;
370     df.bExp = _pDFI->bExp;
371     df.bPrintPlusSign = true;
372     df.bPrintComplexPlusSpace = true;
373     df.bPrintOne = false;
374
375     addDoubleValue(&ostemp, _dblI, &df);
376     ostemp << std::left << SYMBOL_I;
377     if (_dblI == 1 && _pDFI->bExp == false)
378     {
379         addSpaces(&ostemp, 2);
380     }
381
382     configureStream(_postr, _iTotalWidth, 0, ' ');
383     *_postr << std::left << ostemp.str() << std::resetiosflags(std::ios::adjustfield);
384 }
385
386 void addSpaces(std::wostringstream * _postr, int _iSpace)
387 {
388     for (int i = 0; i < _iSpace; i++)
389     {
390         *_postr << L" ";
391     }
392 }
393
394 void configureStream(std::wostringstream * _postr, int _iWidth, int _iPrec, char _cFill)
395 {
396     _postr->setf(std::ios::showpoint);
397     _postr->width(_iWidth);
398     _postr->precision(_iPrec);
399     _postr->fill(_cFill);
400 }
401
402 void addColumnString(std::wostringstream& ostr, int _iFrom, int _iTo)
403 {
404     if (ConfigVariable::isPrintCompact() == false && _iFrom != 1)
405     {
406         ostr << std::endl;
407     }
408     if (_iFrom == _iTo)
409     {
410         ostr << L"         column " << _iFrom << std::endl;
411     }
412     else
413     {
414         ostr << L"         column " << _iFrom << L" to " << _iTo << std::endl;
415     }
416     if (ConfigVariable::isPrintCompact() == false)
417     {
418         ostr << std::endl;
419     }
420 }
421
422 void printEmptyString(std::wostringstream& ostr)
423 {
424     ostr << L"    []";
425 }
426
427 void printDoubleValue(std::wostringstream& ostr, double val)
428 {
429     DoubleFormat df;
430     df.bPrintTrailingZeros = true;
431     getDoubleFormat(val, &df);
432     ostr << SPACE_BETWEEN_TWO_VALUES;
433     addDoubleValue(&ostr, val, &df);
434 }
435
436 void printComplexValue(std::wostringstream& ostr, double val_r, double val_i)
437 {
438     DoubleFormat dfR, dfI;
439     dfR.bPrintTrailingZeros = true;
440     dfI.bPrintTrailingZeros = true;
441
442     int iTotalWidth;
443     getComplexFormat(val_r, val_i, &iTotalWidth, &dfR, &dfI);
444     ostr << SPACE_BETWEEN_TWO_VALUES;
445     addDoubleComplexValue(&ostr, val_r, val_i, iTotalWidth, &dfR, &dfI);
446 }