[ast] fix missing cases after 603f3ba1
[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         iNbDigit = (int)std::fabs(std::floor(std::log10(dblAbs)));
110
111         if (iNbDigit >= (iPrecNeeded - 2) || _pDF->bExp)
112         {
113             //exponant
114             _pDF->bExp = true;
115             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE + EXPOSANT_SIZE + std::max(((int)log10((double)iNbDigit)) + 1, 2);
116             _pDF->iWidth = iPrecNeeded;
117             _pDF->iPrec = iPrecNeeded - iTotalLen;
118             return;
119         }
120         else
121         {
122             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE;
123         }
124     }
125     else
126     {
127         double dblTemp = log10(dblEnt);
128
129         if (dblTemp > (iPrecNeeded - 2) || _pDF->bExp)
130         {
131             //exponant mode
132             if (dblTemp == 0)
133             {
134                 dblTemp = 1;    //no incidence on value, just to allow log10(dblTemp)
135             }
136
137             _pDF->bExp = true;
138             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE + EXPOSANT_SIZE + std::max(((int)log10(dblTemp)) + 1, 2);
139             _pDF->iWidth = iPrecNeeded;
140             _pDF->iPrec = iPrecNeeded - iTotalLen;
141             return;
142         }
143         else
144         {
145             //number of digit in integer part
146             iTotalLen = iBlankSize + ((int)dblTemp + 1) + POINT_SIZE;
147         }
148     }
149
150     //prepare fractionnal part to precision asked
151     double dblScale = pow(10., iPrecNeeded - iTotalLen);
152     while (iTotalLen <= iPrecNeeded)
153     {
154         dblDec = dblDec * dblScale;
155         dblDec = floor(dblDec + 0.5);
156         dblDec = dblDec / dblScale;
157
158         // when dblAbs = 1.9999999..., modf function
159         // return a decimal part equal to 1.0
160         if (dblDec == 0. || dblDec == 1.)
161         {
162             break;
163         }
164
165         dblDec = dblDec * 10;
166         int iFloor = (int)floor(dblDec);
167
168         dblDec -= iFloor;
169         iTotalLen++;
170         iNbDec++;
171         dblScale /= 10;
172     }
173
174     _pDF->iWidth = iTotalLen;
175     _pDF->iPrec = iNbDec;
176 }
177
178 //void getComplexFormat(double _dblR, double _dblI, int *_piTotalWidth, int *_piWidthR, int *_piWidthI, int *_piPrecR, int *_piPrecI, bool* _pExpR, bool* _pExpI)
179 void getComplexFormat(double _dblR, double _dblI, int *_piTotalWidth, DoubleFormat * _pDFR, DoubleFormat * _pDFI)
180 {
181     getDoubleFormat(_dblR, _pDFR);
182     getDoubleFormat(_dblI, _pDFI);
183     
184     *_piTotalWidth = _pDFR->iWidth + _pDFI->iWidth + 2*(_pDFR->bPrintBlank ? BLANK_SIZE : 0) + BLANK_SIZE + SIZE_SYMBOL_I;
185 }
186
187 void addDoubleValue(std::wostringstream * _postr, double _dblVal, DoubleFormat * _pDF)
188 {
189     wchar_t pwstFormat[32] = {0};
190     wchar_t pwstOutput[32] = {0};     // > @ format max
191     wchar_t pwstSign[32] = {0};
192     char    pstBuf[32] = {0};
193
194     if (_pDF == NULL)
195     {
196         return;
197     }
198
199     const wchar_t* pBlank = L"";
200     if (_pDF->bPrintBlank)
201     {
202         pBlank = L" ";
203     }
204
205     const wchar_t* pSign = MINUS_STRING;
206     if (_dblVal >= 0 || ISNAN(_dblVal))
207     {
208         if (_pDF->bPrintPlusSign)
209         {
210             pSign = PLUS_STRING;
211         }
212         else if (_pDF->bPaddSign)
213         {
214             pSign = NO_SIGN;
215         }
216         else
217         {
218             // PLUS_SIGN "+" is not written by default
219             pSign = L"";
220         }
221     }
222
223     // Step 1: BLANK and SIGN in pwstSign
224     if (_pDF->bPrintComplexPlusSpace)
225     {
226         os_swprintf(pwstSign, 32, L"%ls%ls%ls", pBlank, pSign, pBlank);
227     }
228     else
229     {
230         os_swprintf(pwstSign, 32, L"%ls%ls", pBlank, pSign);
231     }
232
233
234     if (ISNAN(_dblVal))
235     {
236         //NaN
237         os_swprintf(pwstOutput, 32, L"%ls%-*ls", pwstSign, _pDF->iWidth - 1, L"Nan");
238     }
239     else if (!finite(_dblVal))
240     {
241         //Inf
242         os_swprintf(pwstOutput, 32, L"%ls%-*ls", pwstSign, _pDF->iWidth - 1, L"Inf");
243     }
244     else if (_pDF->bExp)
245     {
246         // Prints the exponent part 1.543D+03 for example
247         int iDecpt = 0;
248         int iSign = 0;
249         char *pRve = nullptr;
250         char *pDtoaStr = dtoa(fabs(_dblVal), 2, _pDF->iPrec + 1, &iDecpt, &iSign, &pRve);
251
252         std::string str(pDtoaStr);
253         freedtoa(pDtoaStr);
254
255         // in format("e") omiting the decimal point has a sense
256         // only if fabs(_dblVal) is an integer in {1...9}
257         if (_pDF->bPrintPoint || str.length() > 1)
258         {
259             /* add trailing zeros */
260             str.append(fmax(0, _pDF->iPrec + 1 - str.length()), '0');
261             str.insert(1, ".");
262         }
263
264         wchar_t* pwstData = to_wide_string(str.data());
265         os_swprintf(pwstOutput, 32, L"%ls%lsD%+.02d", pwstSign, pwstData, iDecpt - 1);
266         FREE(pwstData);
267     }
268     else if ((_pDF->bPrintOne == true) || (isEqual(fabs(_dblVal), 1)) == false)
269     {
270         //do not print if _bPrintOne == false && _dblVal == 1
271         int iDecpt = 0;
272         int iSign = 0;
273         int iWidth = _pDF->iWidth;
274         char *pRve = nullptr;
275         char *pDtoaStr = dtoa(fabs(_dblVal), 2, std::floor(log10(fabs(_dblVal))) + _pDF->iPrec + 1, &iDecpt, &iSign, &pRve);
276
277         std::string str(pDtoaStr);
278         freedtoa(pDtoaStr);
279
280         /* add leading 0.000..., if applicable */
281         if (iDecpt <= 0)
282         {
283             str.insert(str.begin(), 1 - iDecpt, '0');
284             str.insert(1, ".");
285         }
286         else if (_pDF->bPrintPoint || iDecpt < (int)str.length())
287         {
288             str.append(std::max(0, (iDecpt - (int)str.length())), '0');
289             str.insert(iDecpt, ".");
290         }
291         else
292         {
293             str.append(std::max(0, (iDecpt - (int)str.length())), '0');
294             iWidth--;
295         }
296
297         // append trailing zeros, if applicable
298         if (std::atof(str.data()) != fabs(_dblVal))
299         {
300             if (_pDF->bPrintPoint)
301             {
302                 /*str.append(std::max(0, (ConfigVariable::getFormatSize() - (int)str.length()))-1, '0');*/
303             }
304             else
305             {
306                 iWidth = 1 + str.length();
307             }
308         }
309
310         wchar_t* pwstData = to_wide_string(str.data());
311         os_swprintf(pwstOutput, 32, L"%ls%-*ls", pwstSign, iWidth - 1, pwstData);
312         FREE(pwstData);
313     }
314     else if (wcslen(pwstSign) != 0)
315     {
316         os_swprintf(pwstOutput, 32, L"%ls", pwstSign);
317     }
318
319     *_postr << pwstOutput;
320 }
321
322 /*
323 void addDoubleValue(std::wostringstream *_postr, double _dblVal, int _iWidth, int _iPrec, bool bPrintPlusSign, bool bPrintOne, bool bPaddSign)
324 {
325     addSign(_postr, _dblVal, bPrintPlusSign, bPaddSign);
326     configureStream(_postr, _iWidth, _iPrec, ' ');
327
328     if(bPrintOne == true || isEqual(_dblVal, 1) == false)
329     {
330         NEWprintDoubleVar(_postr, _dblVal, _iWidth, _iPrec);
331     }
332 }
333 */
334 void addDoubleComplexValue(std::wostringstream * _postr, double _dblR, double _dblI, int _iTotalWidth, DoubleFormat * _pDFR, DoubleFormat * _pDFI)
335 {
336     std::wostringstream ostemp;
337
338     /*
339      * if R && !C -> R
340      * if R && C -> R + Ci
341      * if !R && !C -> 0
342      * if(!R && C -> Ci
343      */
344
345     // *_postr << "|%" << _iTotalWitdh << "%|";
346
347     //R
348     DoubleFormat df;
349
350     df.iPrec = _pDFR->iPrec;
351     df.bExp = _pDFR->bExp;
352
353     if (ISNAN(_dblR) || !finite(_dblR))
354     {
355         ostemp << std::left << std::setw(_pDFR->iWidth + 1);
356         addDoubleValue(&ostemp, _dblR, &df);
357     }
358     else
359     {
360         // following line allows to align sign of imaginary part
361         addDoubleValue(&ostemp, _dblR, &df);
362         addSpaces(&ostemp, _pDFR->iWidth - ostemp.tellp() + 1);
363     }
364     //I
365     df.iPrec = _pDFI->iPrec;
366     df.bExp = _pDFI->bExp;
367     df.bPrintPlusSign = true;
368     df.bPrintComplexPlusSpace = true;
369     df.bPrintOne = false;
370
371     addDoubleValue(&ostemp, _dblI, &df);
372     ostemp << std::left << SYMBOL_I;
373     if (_dblI == 1 && _pDFI->bExp == false)
374     {
375         addSpaces(&ostemp, 2);
376     }
377
378     configureStream(_postr, _iTotalWidth, 0, ' ');
379     *_postr << std::left << ostemp.str() << std::resetiosflags(std::ios::adjustfield);
380 }
381
382 void addSpaces(std::wostringstream * _postr, int _iSpace)
383 {
384     for (int i = 0; i < _iSpace; i++)
385     {
386         *_postr << L" ";
387     }
388 }
389
390 void configureStream(std::wostringstream * _postr, int _iWidth, int _iPrec, char _cFill)
391 {
392     _postr->setf(std::ios::showpoint);
393     _postr->width(_iWidth);
394     _postr->precision(_iPrec);
395     _postr->fill(_cFill);
396 }
397
398 void addColumnString(std::wostringstream& ostr, int _iFrom, int _iTo)
399 {
400     if (ConfigVariable::isPrintCompact() == false && _iFrom != 1)
401     {
402         ostr << std::endl;
403     }
404     if (_iFrom == _iTo)
405     {
406         ostr << L"         column " << _iFrom << std::endl;
407     }
408     else
409     {
410         ostr << L"         column " << _iFrom << L" to " << _iTo << std::endl;
411     }
412     if (ConfigVariable::isPrintCompact() == false)
413     {
414         ostr << std::endl;
415     }
416 }
417
418 void printEmptyString(std::wostringstream& ostr)
419 {
420     ostr << L"    []";
421 }
422
423 void printDoubleValue(std::wostringstream& ostr, double val)
424 {
425     DoubleFormat df;
426     getDoubleFormat(val, &df);
427     ostr << SPACE_BETWEEN_TWO_VALUES;
428     addDoubleValue(&ostr, val, &df);
429 }
430
431 void printComplexValue(std::wostringstream& ostr, double val_r, double val_i)
432 {
433     DoubleFormat dfR, dfI;
434     int iTotalWidth;
435     getComplexFormat(ZeroIsZero(val_r), ZeroIsZero(val_i), &iTotalWidth, &dfR, &dfI);
436     ostr << SPACE_BETWEEN_TWO_VALUES;
437     addDoubleComplexValue(&ostr, ZeroIsZero(val_r), ZeroIsZero(val_i), iTotalWidth, &dfR, &dfI);
438 }