d1d9addf176f81023f47a75e5c22067547cd47b7
[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 *
5 *  This file must be used under the terms of the CeCILL.
6 *  This source file is licensed as described in the file COPYING, which
7 *  you should have received as part of this distribution.  The terms
8 *  are also available at
9 *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10 *
11 */
12
13 #include <wchar.h>
14 #include <stdio.h>
15 #include <iostream>
16 #include <math.h>
17 #include "tostring_common.hxx"
18 #include "configvariable.hxx"
19
20 extern "C"
21 {
22 #include "elem_common.h"
23 #include "os_swprintf.h"
24 }
25
26 #define BLANK_SIZE 1
27 #define POINT_SIZE 1
28 #define EXPOSANT_SIZE 2         //exposant symbol + exposant sign
29
30 using namespace std;
31
32 //template <typename T>
33 //void GetIntFormat(T _TVal, int *_piWidth)
34 //{
35 // *_piWidth = (int)(log10((double)_abs64(_TVal)) + 1);
36 //}
37
38 //template <typename T>
39 //void AddIntValue(ostringstream *_postr, T _TVal, int _iWidth, bool bPrintPlusSign, bool bPrintOne)
40 //{
41 // if(bPrintPlusSign == true)
42 // {
43 //  *_postr << (_TVal < 0 ? MINUS_STRING_INT : PLUS_STRING);
44 // }
45 // else
46 // {
47 //  *_postr << (_TVal < 0 ? MINUS_STRING_INT : NO_SIGN);
48 // }
49 //
50 // configureStream(_postr, _iWidth, 0, ' ');
51 //
52 // if(bPrintOne == true || _TVal != 1)
53 // {
54 //  *_postr << right << _abs64(_TVal);
55 // }
56 //}
57
58 void addSign(wostringstream * _postr, double _dblVal, bool _bPrintPlusSign, bool _bPaddSign)
59 {
60     if (_bPrintPlusSign == true)
61     {
62         *_postr << (_dblVal < 0 ? MINUS_STRING : PLUS_STRING);
63     }
64     else
65     {
66         if (_bPaddSign)
67         {
68             *_postr << (_dblVal < 0 ? MINUS_STRING : NO_SIGN);
69         }
70         else
71         {
72             *_postr << (_dblVal < 0 ? MINUS_STRING : L"");
73         }
74     }
75 }
76
77 //void getDoubleFormat(double _dblVal, int *_piWidth, int *_piPrec, /*in/out*/bool* _pExp)
78 void getDoubleFormat(double _dblVal, DoubleFormat * _pDF)
79 {
80     double dblDec = 0;
81     double dblEnt = 0;
82     double dblAbs = fabs(_dblVal);
83     int iNbDigit = 0;
84     int iNbDec = 0;
85     int iBlankSize = _pDF->bPrintBlank ? BLANK_SIZE : 0;
86     _pDF->iSignLen = _pDF->bPrintBlank ? _pDF->iSignLen + 1 : _pDF->iSignLen;
87
88     _pDF->bExp |= ConfigVariable::getFormatMode() == 0;
89     int iTotalLen = 0;
90     int iPrecNeeded = ConfigVariable::getFormatSize();
91
92     if (ISNAN(_dblVal) || !finite(_dblVal))
93     {
94         _pDF->iWidth = 5;      //" nan" or " inf"
95         _pDF->iPrec = 0;
96         return;
97     }
98     //get integer part and fractionnal part
99     dblDec = modf(dblAbs, &dblEnt);
100
101     //compute len of entire part
102     if (dblEnt == 0)
103     {
104         //[-1, 1]
105         iNbDigit = (int)fabs(floor(log10(dblAbs)));
106
107         if (iNbDigit >= (iPrecNeeded - 2) || _pDF->bExp)
108         {
109             //exponant
110             _pDF->bExp = true;
111             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE + EXPOSANT_SIZE + (int)log10((double)iNbDigit) + 1;
112             _pDF->iWidth = iPrecNeeded;
113             _pDF->iPrec = iPrecNeeded - iTotalLen;
114             return;
115         }
116         else
117         {
118             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE;
119         }
120     }
121     else
122     {
123         double dblTemp = log10(dblEnt);
124
125         if (dblTemp > (iPrecNeeded - 2) || _pDF->bExp)
126         {
127             //exponant mode
128             if (dblTemp == 0)
129             {
130                 dblTemp = 1;    //no incidence on value, just to allow log10(dblTemp)
131             }
132             _pDF->bExp = true;
133             iTotalLen = iBlankSize + 1 /*integer before dot */  + POINT_SIZE + EXPOSANT_SIZE + (int)log10(dblTemp) + 1;
134             _pDF->iWidth = iPrecNeeded;
135             _pDF->iPrec = iPrecNeeded - iTotalLen;
136             return;
137         }
138         else
139         {
140             //number of digit in integer part
141             iTotalLen = iBlankSize + ((int)dblTemp + 1) + POINT_SIZE;
142         }
143     }
144
145     //prepare fractionnal part to precision asked
146     double dblScale = pow(10., iPrecNeeded - iTotalLen);
147     while (iTotalLen <= iPrecNeeded)
148     {
149         dblDec = dblDec * dblScale;
150         dblDec = floor(dblDec + 0.5);
151         dblDec = dblDec / dblScale;
152
153         // when dblAbs = 1.9999999..., modf function
154         // return a decimal part equal to 1.0
155         if (dblDec == 0. || dblDec == 1.)
156         {
157             break;
158         }
159
160         dblDec = dblDec * 10;
161         int iFloor = (int)floor(dblDec);
162
163         dblDec -= iFloor;
164         iTotalLen++;
165         iNbDec++;
166         dblScale /= 10;
167     }
168
169     _pDF->iWidth = iTotalLen;
170     _pDF->iPrec = iNbDec;
171 }
172
173 //void getComplexFormat(double _dblR, double _dblI, int *_piTotalWidth, int *_piWidthR, int *_piWidthI, int *_piPrecR, int *_piPrecI, bool* _pExpR, bool* _pExpI)
174 void getComplexFormat(double _dblR, double _dblI, int *_piTotalWidth, DoubleFormat * _pDFR, DoubleFormat * _pDFI)
175 {
176     getDoubleFormat(_dblR, _pDFR);
177     getDoubleFormat(_dblI, _pDFI);
178
179     *_piTotalWidth = 0;
180     if (isRealZero(_dblI))
181     {
182         if (isRealZero(_dblR))
183         {
184             *_piTotalWidth += 1;    //"0"
185             _pDFI->iWidth = 0;
186             _pDFI->iSignLen = 0;
187         }
188         else
189         {
190             *_piTotalWidth += _pDFR->iWidth + _pDFR->iSignLen;
191             _pDFI->iWidth = 0;
192             _pDFI->iSignLen = 0;
193         }
194     }
195     else
196     {
197         if (isRealZero(_dblR))
198         {
199             *_piTotalWidth += _pDFI->iWidth + _pDFI->iSignLen;
200             _pDFR->iWidth = 0;
201         }
202         else
203         {
204             *_piTotalWidth += _pDFR->iWidth + _pDFR->iSignLen + _pDFI->iWidth + _pDFI->iSignLen;
205         }
206
207         // i character
208         _pDFI->iWidth += 1;
209         *_piTotalWidth += 1;
210     }
211 }
212
213 void addDoubleValue(std::wostringstream * _postr, double _dblVal, DoubleFormat * _pDF)
214 {
215     wchar_t pwstFormat[32];
216     wchar_t pwstOutput[32];     // > @ format max
217     wchar_t pwstSign[32];
218
219     if (_pDF == NULL)
220     {
221         return;
222     }
223
224     const wchar_t* pBlank = L"";
225     if (_pDF->bPrintBlank)
226     {
227         pBlank = L" ";
228     }
229
230     const wchar_t* pSign = MINUS_STRING;
231     if (_dblVal >= 0)
232     {
233         if (_pDF->bPrintPlusSign)
234         {
235             pSign = PLUS_STRING;
236         }
237         else if (_pDF->bPaddSign)
238         {
239             pSign = NO_SIGN;
240         }
241         else
242         {
243             pSign = L"";
244         }
245     }
246
247     os_swprintf(pwstSign, 32, L"%ls%ls%ls", pBlank, pSign, pBlank);
248
249     if ((_pDF->bPrintOne == true) || (isEqual(fabs(_dblVal), 1)) == false)
250     {
251         //do not print if _bPrintOne == false && _dblVal == 1
252         if (ISNAN(_dblVal))
253         {
254             //NaN
255             os_swprintf(pwstOutput, 32, L"%ls%*ls", pwstSign, _pDF->iPrec, L"Nan");
256         }
257         else if (!finite(_dblVal))
258         {
259             //Inf
260             os_swprintf(pwstOutput, 32, L"%ls%*ls", pwstSign, _pDF->iPrec, L"Inf");
261         }
262         else if (_pDF->bExp)
263         {
264             double dblAbs = fabs(_dblVal);
265             double dblDec = 0;
266             double dblEnt = 0;
267             double dblTemp = 0;
268
269             dblDec = modf(dblAbs, &dblEnt);
270             if (dblEnt == 0)
271             {
272                 dblTemp = floor(log10(dblDec));
273             }
274             else
275             {
276                 dblTemp = log10(dblEnt);
277             }
278             dblDec = dblAbs / pow(10., (double)(int)dblTemp);
279             dblDec = modf(dblDec, &dblEnt) * pow(10., _pDF->iPrec);
280
281             if (_pDF->bPrintPoint)
282             {
283                 os_swprintf(pwstFormat, 32, L"%ls%%#.0f%%0%d.0fD%%+d", pwstSign, _pDF->iPrec);
284             }
285             else
286             {
287                 os_swprintf(pwstFormat, 32, L"%ls%%.0f%%0%d.0fD%%+d", pwstSign, _pDF->iPrec);
288             }
289
290             os_swprintf(pwstOutput, 32, pwstFormat, dblEnt, dblDec, (int)dblTemp);
291         }
292         else
293         {
294             if (_pDF->bPrintPoint)
295             {
296                 os_swprintf(pwstFormat, 32, L"%ls%%#-%d.%df", pwstSign, _pDF->iWidth - 1, _pDF->iPrec);
297             }
298             else
299             {
300                 os_swprintf(pwstFormat, 32, L"%ls%%-%d.%df", pwstSign, _pDF->iWidth - 2, _pDF->iPrec);  //-2 no point needed
301             }
302
303             os_swprintf(pwstOutput, 32, pwstFormat, fabs(_dblVal));
304         }
305
306         *_postr << pwstOutput;
307     }
308     else if (wcslen(pwstSign) != 0)
309     {
310         os_swprintf(pwstOutput, 32, L"%ls", pwstSign);
311         *_postr << pwstOutput;
312     }
313 }
314
315 /*
316 void addDoubleValue(wostringstream *_postr, double _dblVal, int _iWidth, int _iPrec, bool bPrintPlusSign, bool bPrintOne, bool bPaddSign)
317 {
318     addSign(_postr, _dblVal, bPrintPlusSign, bPaddSign);
319     configureStream(_postr, _iWidth, _iPrec, ' ');
320
321     if(bPrintOne == true || isEqual(_dblVal, 1) == false)
322     {
323         NEWprintDoubleVar(_postr, _dblVal, _iWidth, _iPrec);
324     }
325 }
326 */
327 void addDoubleComplexValue(wostringstream * _postr, double _dblR, double _dblI, int _iTotalWidth, DoubleFormat * _pDFR, DoubleFormat * _pDFI)
328 {
329     wostringstream ostemp;
330
331     /*
332      * if R && !C -> R
333      * if R && C -> R + Ci
334      * if !R && !C -> 0
335      * if(!R && C -> Ci
336      */
337
338     // *_postr << "|%" << _iTotalWitdh << "%|";
339     if (_dblR == 0)
340     {
341         //no real part
342         if (_dblI == 0)
343         {
344             //no imaginary part
345
346             //0
347             DoubleFormat df;
348
349             addDoubleValue(&ostemp, 0, &df);
350         }
351         else
352         {
353             //imaginary part
354
355             //I
356             DoubleFormat df;
357
358             df.iWidth = 0;
359             df.iPrec = _pDFI->iPrec;
360             df.bExp = _pDFI->bExp;
361             df.bPrintPlusSign = false;
362             df.bPrintOne = false;
363             addDoubleValue(&ostemp, _dblI, &df);
364             ostemp << left << SYMBOL_I;
365             if (_dblI == 1)
366             {
367                 addSpaces(&ostemp, 2);
368             }
369
370         }
371     }
372     else
373     {
374         //real part
375         if (_dblI == 0)
376         {
377             //no imaginary part
378
379             //R
380             DoubleFormat df;
381
382             df.iWidth = 0;
383             df.iPrec = _pDFR->iPrec;
384             df.bExp = _pDFR->bExp;
385             addDoubleValue(&ostemp, _dblR, &df);
386         }
387         else
388         {
389             //imaginary part
390
391             //R
392             DoubleFormat df;
393
394             df.iPrec = _pDFR->iPrec;
395             df.bExp = _pDFR->bExp;
396
397             addDoubleValue(&ostemp, _dblR, &df);
398
399             //I
400             df.iPrec = _pDFI->iPrec;
401             df.bExp = _pDFI->bExp;
402             df.bPrintPlusSign = true;
403             df.bPrintOne = false;
404
405             addDoubleValue(&ostemp, _dblI, &df);
406             ostemp << left << SYMBOL_I;
407             if (_dblI == 1)
408             {
409                 addSpaces(&ostemp, 2);
410             }
411         }
412     }
413
414     configureStream(_postr, _iTotalWidth - 3, 0, ' ');
415     *_postr << left << ostemp.str();
416 }
417
418 void addSpaces(wostringstream * _postr, int _iSpace)
419 {
420     for (int i = 0; i < _iSpace; i++)
421     {
422         *_postr << L" ";
423     }
424 }
425
426 void configureStream(wostringstream * _postr, int _iWidth, int _iPrec, char _cFill)
427 {
428     _postr->setf(ios::showpoint);
429     _postr->width(_iWidth);
430     _postr->precision(_iPrec);
431     _postr->fill(_cFill);
432 }