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