1084e742ede361c01ae85b89afb1230d13afa077
[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 - 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 #include "sciprint.h"
32 }
33
34 #define BLANK_SIZE 1
35 #define POINT_SIZE 1
36 #define EXPOSANT_SIZE 2         //exposant symbol + exposant sign
37
38 //template <typename T>
39 //void GetIntFormat(T _TVal, int *_piWidth)
40 //{
41 // *_piWidth = (int)(log10((double)_abs64(_TVal)) + 1);
42 //}
43
44 //template <typename T>
45 //void AddIntValue(ostringstream *_postr, T _TVal, int _iWidth, bool bPrintPlusSign, bool bPrintOne)
46 //{
47 // if(bPrintPlusSign == true)
48 // {
49 //  *_postr << (_TVal < 0 ? MINUS_STRING_INT : PLUS_STRING);
50 // }
51 // else
52 // {
53 //  *_postr << (_TVal < 0 ? MINUS_STRING_INT : NO_SIGN);
54 // }
55 //
56 // configureStream(_postr, _iWidth, 0, ' ');
57 //
58 // if(bPrintOne == true || _TVal != 1)
59 // {
60 //  *_postr << right << _abs64(_TVal);
61 // }
62 //}
63
64 void addSign(std::wostringstream * _postr, double _dblVal, bool _bPrintPlusSign, bool _bPaddSign)
65 {
66     if (_bPrintPlusSign == true)
67     {
68         *_postr << (_dblVal < 0 ? MINUS_STRING : PLUS_STRING);
69     }
70     else
71     {
72         if (_bPaddSign)
73         {
74             *_postr << (_dblVal < 0 ? MINUS_STRING : NO_SIGN);
75         }
76         else
77         {
78             *_postr << (_dblVal < 0 ? MINUS_STRING : L"");
79         }
80     }
81 }
82
83 //void getDoubleFormat(double _dblVal, int *_piWidth, int *_piPrec, /*in/out*/bool* _pExp)
84 void getDoubleFormat(double _dblVal, DoubleFormat * _pDF)
85 {
86     double dblDec = 0;
87     double dblEnt = 0;
88     double dblAbs = std::fabs(_dblVal);
89     int iNbDigit = 0;
90     int iNbDec = 0;
91     int iBlankSize = _pDF->bPrintBlank ? BLANK_SIZE : 0;
92     _pDF->iSignLen = _pDF->bPrintBlank ? SIGN_LENGTH + BLANK_SIZE : _pDF->iSignLen;
93
94     _pDF->bExp |= ConfigVariable::getFormatMode() == 0;
95     int iTotalLen = 0;
96     int iPrecNeeded = ConfigVariable::getFormatSize();
97
98     if (ISNAN(_dblVal) || !finite(_dblVal))
99     {
100         _pDF->iWidth = 4;      //" nan" or " inf"
101         _pDF->iPrec = 0;
102         return;
103     }
104     //get integer part and fractionnal part
105     dblDec = std::modf(dblAbs, &dblEnt);
106
107     //compute len of entire part
108     if (dblEnt == 0)
109     {
110         //[-1, 1]
111         iNbDigit = (int)std::fabs(std::floor(std::log10(dblAbs)));
112
113         if (iNbDigit >= (iPrecNeeded - 2) || _pDF->bExp)
114         {
115             //exponant
116             _pDF->bExp = true;
117             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE + EXPOSANT_SIZE + std::max(((int)log10((double)iNbDigit)) + 1, 2);
118             _pDF->iWidth = iPrecNeeded;
119             _pDF->iPrec = iPrecNeeded - iTotalLen;
120             return;
121         }
122         else
123         {
124             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE;
125         }
126     }
127     else
128     {
129         double dblTemp = log10(dblEnt);
130
131         if (dblTemp > (iPrecNeeded - 2) || _pDF->bExp)
132         {
133             //exponant mode
134             if (dblTemp == 0)
135             {
136                 dblTemp = 1;    //no incidence on value, just to allow log10(dblTemp)
137             }
138
139             _pDF->bExp = true;
140             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE + EXPOSANT_SIZE + std::max(((int)log10(dblTemp)) + 1, 2);
141             _pDF->iWidth = iPrecNeeded;
142             _pDF->iPrec = iPrecNeeded - iTotalLen;
143             return;
144         }
145         else
146         {
147             //number of digit in integer part
148             iTotalLen = iBlankSize + ((int)dblTemp + 1) + POINT_SIZE;
149         }
150     }
151
152     //prepare fractionnal part to precision asked
153     double dblScale = pow(10., iPrecNeeded - iTotalLen);
154     while (iTotalLen <= iPrecNeeded)
155     {
156         dblDec = dblDec * dblScale;
157         dblDec = floor(dblDec + 0.5);
158         dblDec = dblDec / dblScale;
159
160         // when dblAbs = 1.9999999..., modf function
161         // return a decimal part equal to 1.0
162         if (dblDec == 0. || dblDec == 1.)
163         {
164             break;
165         }
166
167         dblDec = dblDec * 10;
168         int iFloor = (int)floor(dblDec);
169
170         dblDec -= iFloor;
171         iTotalLen++;
172         iNbDec++;
173         dblScale /= 10;
174     }
175
176     _pDF->iWidth = iTotalLen;
177     _pDF->iPrec = iNbDec;
178 }
179
180 //void getComplexFormat(double _dblR, double _dblI, int *_piTotalWidth, int *_piWidthR, int *_piWidthI, int *_piPrecR, int *_piPrecI, bool* _pExpR, bool* _pExpI)
181 void getComplexFormat(double _dblR, double _dblI, int *_piTotalWidth, DoubleFormat * _pDFR, DoubleFormat * _pDFI)
182 {
183     getDoubleFormat(_dblR, _pDFR);
184     getDoubleFormat(_dblI, _pDFI);
185
186     *_piTotalWidth = 0;
187     if (isRealZero(_dblI))
188     {
189         if (isRealZero(_dblR))
190         {
191             *_piTotalWidth += 1;    //"0"
192             _pDFI->iWidth = 0;
193             _pDFI->iSignLen = 0;
194         }
195         else
196         {
197             *_piTotalWidth += _pDFR->iWidth;
198             _pDFI->iWidth = 0;
199             _pDFI->iSignLen = 0;
200         }
201     }
202     else
203     {
204         if (isRealZero(_dblR))
205         {
206             *_piTotalWidth += _pDFI->iWidth;
207             _pDFR->iWidth = 0;
208         }
209         else
210         {
211             *_piTotalWidth += _pDFR->iWidth + _pDFI->iWidth;
212         }
213
214         // i character
215         *_piTotalWidth += 1;
216     }
217 }
218
219 void addDoubleValue(std::wostringstream * _postr, double _dblVal, DoubleFormat * _pDF)
220 {
221     wchar_t pwstFormat[32] = {0};
222     wchar_t pwstOutput[32] = {0};     // > @ format max
223     wchar_t pwstSign[32] = {0};
224     char    pstBuf[32] = {0};
225
226     if (_pDF == NULL)
227     {
228         return;
229     }
230
231     const wchar_t* pBlank = L"";
232     if (_pDF->bPrintBlank)
233     {
234         pBlank = L" ";
235     }
236
237     const wchar_t* pSign = MINUS_STRING;
238     if (_dblVal >= 0 || ISNAN(_dblVal))
239     {
240         if (_pDF->bPrintPlusSign)
241         {
242             pSign = PLUS_STRING;
243         }
244         else if (_pDF->bPaddSign)
245         {
246             pSign = NO_SIGN;
247         }
248         else
249         {
250             // PLUS_SIGN "+" is not written by default
251             pSign = L"";
252         }
253     }
254
255     // Step 1: BLANK and SIGN in pwstSign
256     if (_pDF->bPrintComplexPlusSpace)
257     {
258         os_swprintf(pwstSign, 32, L"%ls%ls%ls", pBlank, pSign, pBlank);
259     }
260     else
261     {
262         os_swprintf(pwstSign, 32, L"%ls%ls", pBlank, pSign);
263     }
264
265
266     if (ISNAN(_dblVal))
267     {
268         //NaN
269         os_swprintf(pwstOutput, 32, L"%ls%-*ls", pwstSign, _pDF->iWidth - 1, L"Nan");
270     }
271     else if (!finite(_dblVal))
272     {
273         //Inf
274         os_swprintf(pwstOutput, 32, L"%ls%-*ls", pwstSign, _pDF->iWidth - 1, L"Inf");
275     }
276     else if (_pDF->bExp)
277     {
278         // Prints the exponent part 1.543D+03 for example
279         int iDecpt = 0;
280         int iSign = 0;
281         char *pRve = nullptr;
282         char *pDtoaStr = dtoa(fabs(_dblVal), 2, _pDF->iPrec + 1, &iDecpt, &iSign, &pRve);
283
284         std::string str(pDtoaStr);
285         freedtoa(pDtoaStr);
286
287         // in format("e") omiting the decimal point has a sense
288         // only if fabs(_dblVal) is an integer in {1...9}
289         if (_pDF->bPrintPoint || str.length() > 1)
290         {
291             /* add trailing zeros */
292             str.append(fmax(0, _pDF->iPrec + 1 - str.length()), '0');
293             str.insert(1, ".");
294         }
295
296         wchar_t* pwstData = to_wide_string(str.data());
297         os_swprintf(pwstOutput, 32, L"%ls%lsD%+.02d", pwstSign, pwstData, iDecpt - 1);
298         FREE(pwstData);
299     }
300     else if ((_pDF->bPrintOne == true) || (isEqual(fabs(_dblVal), 1)) == false)
301     {
302         //do not print if _bPrintOne == false && _dblVal == 1
303         int iDecpt = 0;
304         int iSign = 0;
305         int iWidth = _pDF->iWidth;
306         char *pRve = nullptr;
307         char *pDtoaStr = dtoa(fabs(_dblVal), 2, std::floor(log10(fabs(_dblVal))) + _pDF->iPrec + 1, &iDecpt, &iSign, &pRve);
308
309         std::string str(pDtoaStr);
310         freedtoa(pDtoaStr);
311
312         /* add leading 0.000..., if applicable */
313         if (iDecpt <= 0)
314         {
315             str.insert(str.begin(), 1 - iDecpt, '0');
316             str.insert(1, ".");
317         }
318         else if (_pDF->bPrintPoint || iDecpt < (int)str.length())
319         {
320             str.append(std::max(0, (iDecpt - (int)str.length())), '0');
321             str.insert(iDecpt, ".");
322         }
323         else
324         {
325             str.append(std::max(0, (iDecpt - (int)str.length())), '0');
326             iWidth--;
327         }
328
329         // append trailing zeros, if applicable
330         if (std::atof(str.data()) != fabs(_dblVal))
331         {
332             if (_pDF->bPrintPoint)
333             {
334                 /* str.append(std::max(0, (ConfigVariable::getFormatSize() - (int)str.length()))-1, '0'); */
335             }
336             else
337             {
338                 iWidth = 1+str.length();
339             }
340         }
341
342         wchar_t* pwstData = to_wide_string(str.data());
343         os_swprintf(pwstOutput, 32, L"%ls%-*ls", pwstSign, iWidth-1, pwstData);
344         FREE(pwstData);
345     }
346     else if (wcslen(pwstSign) != 0)
347     {
348         os_swprintf(pwstOutput, 32, L"%ls", pwstSign);
349     }
350
351     *_postr << pwstOutput;
352 }
353
354 /*
355 void addDoubleValue(std::wostringstream *_postr, double _dblVal, int _iWidth, int _iPrec, bool bPrintPlusSign, bool bPrintOne, bool bPaddSign)
356 {
357     addSign(_postr, _dblVal, bPrintPlusSign, bPaddSign);
358     configureStream(_postr, _iWidth, _iPrec, ' ');
359
360     if(bPrintOne == true || isEqual(_dblVal, 1) == false)
361     {
362         NEWprintDoubleVar(_postr, _dblVal, _iWidth, _iPrec);
363     }
364 }
365 */
366 void addDoubleComplexValue(std::wostringstream * _postr, double _dblR, double _dblI, int _iTotalWidth, DoubleFormat * _pDFR, DoubleFormat * _pDFI)
367 {
368     std::wostringstream ostemp;
369
370     /*
371      * if R && !C -> R
372      * if R && C -> R + Ci
373      * if !R && !C -> 0
374      * if(!R && C -> Ci
375      */
376
377     // *_postr << "|%" << _iTotalWitdh << "%|";
378     if (_dblR == 0)
379     {
380         //no real part
381         if (_dblI == 0)
382         {
383             //no imaginary part
384
385             //0
386             DoubleFormat df;
387
388             addDoubleValue(&ostemp, 0, &df);
389         }
390         else
391         {
392             //imaginary part
393
394             //I
395             DoubleFormat df;
396
397             df.iWidth = 0;
398             df.iPrec = _pDFI->iPrec;
399             df.bExp = _pDFI->bExp;
400             df.bPrintPlusSign = false;
401             df.bPrintOne = false;
402             addDoubleValue(&ostemp, _dblI, &df);
403             ostemp << std::left << SYMBOL_I;
404             if (_dblI == 1)
405             {
406                 addSpaces(&ostemp, 1);
407             }
408
409         }
410     }
411     else
412     {
413         //real part
414         if (_dblI == 0)
415         {
416             //no imaginary part
417
418             //R
419             DoubleFormat df;
420
421             df.iWidth = 0;
422             df.iPrec = _pDFR->iPrec;
423             df.bExp = _pDFR->bExp;
424             addDoubleValue(&ostemp, _dblR, &df);
425         }
426         else
427         {
428             //imaginary part
429
430             //R
431             DoubleFormat df;
432
433             df.iPrec = _pDFR->iPrec;
434             df.bExp = _pDFR->bExp;
435
436             addDoubleValue(&ostemp, _dblR, &df);
437
438             //I
439             df.iPrec = _pDFI->iPrec;
440             df.bExp = _pDFI->bExp;
441             df.bPrintPlusSign = true;
442             df.bPrintComplexPlusSpace = true;
443             df.bPrintOne = false;
444
445             addDoubleValue(&ostemp, _dblI, &df);
446             ostemp << std::left << SYMBOL_I;
447             if (_dblI == 1)
448             {
449                 addSpaces(&ostemp, 2);
450             }
451         }
452     }
453
454     configureStream(_postr, _iTotalWidth, 0, ' ');
455     *_postr << std::left << ostemp.str() << std::resetiosflags(std::ios::adjustfield);
456 }
457
458 void addSpaces(std::wostringstream * _postr, int _iSpace)
459 {
460     for (int i = 0; i < _iSpace; i++)
461     {
462         *_postr << L" ";
463     }
464 }
465
466 void configureStream(std::wostringstream * _postr, int _iWidth, int _iPrec, char _cFill)
467 {
468     _postr->setf(std::ios::showpoint);
469     _postr->width(_iWidth);
470     _postr->precision(_iPrec);
471     _postr->fill(_cFill);
472 }
473
474 void addColumnString(std::wostringstream& ostr, int _iFrom, int _iTo)
475 {
476     if (ConfigVariable::isPrintCompact() == false)
477     {
478         ostr << std::endl;
479     }
480     if (_iFrom == _iTo)
481     {
482         ostr << L"         column " << _iFrom << std::endl;
483     }
484     else
485     {
486         ostr << L"         column " << _iFrom << L" to " << _iTo << std::endl;
487     }
488     if (ConfigVariable::isPrintCompact() == false)
489     {
490         ostr << std::endl;
491     }
492 }
493
494 void printEmptyString(std::wostringstream& ostr)
495 {
496     ostr << L"    []";
497 }
498
499 void printDoubleValue(std::wostringstream& ostr, double val)
500 {
501     DoubleFormat df;
502     getDoubleFormat(val, &df);
503     ostr << SPACE_BETWEEN_TWO_VALUES;
504     addDoubleValue(&ostr, val, &df);
505 }
506
507 void printComplexValue(std::wostringstream& ostr, double val_r, double val_i)
508 {
509     DoubleFormat dfR, dfI;
510     getDoubleFormat(ZeroIsZero(val_r), &dfR);
511     getDoubleFormat(ZeroIsZero(val_i), &dfI);
512     ostr << SPACE_BETWEEN_TWO_VALUES;
513     addDoubleComplexValue(&ostr, ZeroIsZero(val_r), ZeroIsZero(val_i), dfR.iWidth + dfI.iWidth, &dfR, &dfI);
514 }