* Bug 16365 fixed: median(m,'r'|'c') was wrong after 5dc990
[scilab.git] / scilab / modules / string / sci_gateway / cpp / sci_string.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2010-2010 - DIGITEO - Bruno JOFRET
4 *  Copyright (C) 2014 - Scilab Enterprises - Anais AUBERT
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 <math.h>
18 #include <sstream>
19 #include <string>
20 #include "string.hxx"
21 #include "double.hxx"
22 #include "function.hxx"
23 #include "string_gw.hxx"
24 #include "tostring_common.hxx"
25 #include "printvisitor.hxx"
26 #include "macro.hxx"
27 #include "macrofile.hxx"
28 #include "symbol.hxx"
29 #include "tlist.hxx"
30 #include "overload.hxx"
31 #include "sparse.hxx"
32 #include "int.hxx"
33 #include "implicitlist.hxx"
34 #include "polynom.hxx"
35
36 extern "C"
37 {
38 #include "os_string.h"
39 #include "Scierror.h"
40 #include "localization.h"
41 #include "sciprint.h"
42 }
43
44 static void getMacroString(types::Macro* _pM, types::InternalType** _pOut, types::InternalType** _pIn, types::InternalType** _pBody)
45 {
46     //get body
47     ast::Exp* exp = _pM->getBody();
48
49     std::wostringstream ostr;
50     ast::PrintVisitor pv(ostr, false);
51
52     exp->accept(pv);
53
54     std::wstring wstBody = ostr.str();
55     const wchar_t* pwstBody = wstBody.c_str();
56
57     //first loop to find number of lines
58     int iLines = 2; //for first and last one-space lines
59     for (int i = 0 ; i < (int)wcslen(pwstBody) ; i++)
60     {
61         if (pwstBody[i] == L'\n')
62         {
63             iLines++;
64         }
65     }
66
67     types::String* pBody = new types::String(iLines, 1);
68     pBody->set(0, L" ");
69     //second loop to assign lines to output data
70     int iOffset = 0;
71     int iIndex = 1;
72     for (int i = 0 ; i < (int)wcslen(pwstBody) ; i++)
73     {
74         if (pwstBody[i] == L'\n')
75         {
76             int iLen = i - iOffset;
77             wchar_t* pwst = new wchar_t[iLen + 1];
78             wcsncpy(pwst, pwstBody + iOffset, iLen);
79             pwst[iLen] = L'\0';
80             pBody->set(iIndex++, pwst);
81             delete[] pwst;
82             iOffset = i + 1;
83         }
84     }
85
86     pBody->set(iIndex, L" ");
87     *_pBody = pBody;
88
89     //get inputs
90     std::list<symbol::Variable*>* pIn = _pM->getInputs();
91
92     if (pIn->size() == 0)
93     {
94         *_pIn = types::Double::Empty();
95     }
96     else
97     {
98         types::String *pSIn = new types::String(1, (int)pIn->size());
99
100         std::list<symbol::Variable*>::iterator itIn = pIn->begin();
101         for (int i = 0 ; i < pIn->size() ; i++, itIn++)
102         {
103             pSIn->set(i, (*itIn)->getSymbol().getName().c_str());
104         }
105
106         *_pIn = pSIn;
107     }
108
109     //get outputs
110     std::list<symbol::Variable*>* pOut = _pM->getOutputs();
111     if (pOut->size() == 0)
112     {
113         *_pOut = types::Double::Empty();
114     }
115     else
116     {
117         types::String* pSOut = new types::String(1, (int)pOut->size());
118
119         std::list<symbol::Variable*>::iterator itOut = pOut->begin();
120         for (int i = 0 ; i < pOut->size() ; i++, itOut++)
121         {
122             pSOut->set(i, (*itOut)->getSymbol().getName().c_str());
123         }
124
125         *_pOut = pSOut;
126     }
127 }
128
129 static void DoubleComplexMatrix2String(std::wostringstream *_postr,  double _dblR, double _dblI)
130 {
131     /*
132     if R && !C -> R
133     if R && C -> R + Ci
134     if !R && !C -> 0
135     if(!R aa C  -> Ci
136     */
137     DoubleFormat dfR, dfI;
138     dfR.bPrintBlank = false;
139     dfI.bPrintBlank = false;
140
141     getDoubleFormat(_dblR, &dfR);
142     getDoubleFormat(_dblI, &dfI);
143
144     dfR.bPrintPoint = dfR.bExp;
145     dfR.bPaddSign = false;
146
147     dfI.bPrintPoint = dfI.bExp;
148     dfI.bPaddSign = false;
149
150     // decrease precision when the real number will be rounded
151     // format(10) with number 1.12345678 should return 1.1234568
152     if (dfR.iWidth == ConfigVariable::getFormatSize())
153     {
154         if (dfR.iPrec != 0)
155         {
156             dfR.iPrec--;
157         }
158
159         dfR.iWidth--;
160     }
161
162     if (dfI.iWidth == ConfigVariable::getFormatSize())
163     {
164         if (dfI.iPrec != 0)
165         {
166             dfI.iPrec--;
167         }
168
169         dfI.iWidth--;
170     }
171
172     if (_dblR == 0)
173     {
174         //no real part
175         if (_dblI == 0)
176         {
177             //no imaginary part
178
179             //0
180             addDoubleValue(_postr, 0, &dfR);
181         }
182         else
183         {
184             //imaginary part
185
186             //I
187             *_postr << (_dblI < 0 ? L"-" : L"");
188             *_postr << L"%i";
189             if (fabs(_dblI) != 1 || dfI.bExp)
190             {
191                 //specail case if I == 1 write only %i and not %i*1
192                 *_postr << L"*";
193                 addDoubleValue(_postr, fabs(_dblI), &dfI);
194             }
195         }
196     }
197     else
198     {
199         //real part
200         if (_dblI == 0)
201         {
202             //no imaginary part
203
204             //R
205             addDoubleValue(_postr, _dblR, &dfR);
206         }
207         else
208         {
209             //imaginary part
210
211             //R
212             addDoubleValue(_postr, _dblR, &dfR);
213             //I
214             *_postr << (_dblI < 0 ? L"-%i" : L"+%i");
215             if (fabs(_dblI) != 1 || dfI.bExp)
216             {
217                 //special case if I == 1 write only %i and not %i*1
218                 *_postr << L"*";
219                 addDoubleValue(_postr, fabs(_dblI), &dfI);
220             }
221         }
222     }
223 }
224
225 template <class T>
226 types::Function::ReturnValue intString(T* pInt, types::typed_list &out)
227 {
228     int iDims = pInt->getDims();
229     int* piDimsArray = pInt->getDimsArray();
230     types::String *pstOutput = new types::String(iDims, piDimsArray);
231     int iSize = pInt->getSize();
232     for (int i = 0 ; i < iSize ; i++)
233     {
234         std::wostringstream ostr;
235         DoubleComplexMatrix2String(&ostr, (double)pInt->get(i), 0);
236         pstOutput->set(i, ostr.str().c_str());
237     }
238
239     out.push_back(pstOutput);
240     return types::Function::OK;
241 }
242
243 types::Function::ReturnValue booleanString(types::Bool* pB, types::typed_list &out)
244 {
245     int iDims = pB->getDims();
246     int* piDimsArray = pB->getDimsArray();
247     int* pb = pB->get();
248     types::String *pstOutput = new types::String(iDims, piDimsArray);
249     int iSize = pB->getSize();
250     for (int i = 0 ; i < iSize ; i++)
251     {
252         pstOutput->set(i, pb[i] == 0 ? "F" : "T");
253     }
254
255     out.push_back(pstOutput);
256     return types::Function::OK;
257 }
258
259 types::Function::ReturnValue doubleString(types::Double* pDbl, types::typed_list &out)
260 {
261     int iDims = pDbl->getDims();
262     int* piDimsArray = pDbl->getDimsArray();
263     double* pdblReal = pDbl->get();
264
265     // Special case string([]) == []
266     if (pDbl->isEmpty())
267     {
268         out.push_back(types::Double::Empty());
269         return types::Function::OK;
270     }
271     else if (piDimsArray[0] == -1 && piDimsArray[1] == -1)
272     {
273         out.push_back(new types::String(L""));
274         return types::Function::OK;
275     }
276
277     types::String *pstOutput = new types::String(iDims, piDimsArray);
278     if (pDbl->isComplex())
279     {
280         double* pdblImg = pDbl->getImg();
281         for (int i = 0; i < pDbl->getSize(); ++i)
282         {
283             std::wostringstream ostr;
284             DoubleComplexMatrix2String(&ostr, pdblReal[i], pdblImg[i]);
285             pstOutput->set(i, ostr.str().c_str());
286         }
287     }
288     else
289     {
290         double dblImg  = 0.0;
291         for (int i = 0; i < pDbl->getSize(); ++i)
292         {
293             std::wostringstream ostr;
294             DoubleComplexMatrix2String(&ostr, pdblReal[i], dblImg);
295             pstOutput->set(i, ostr.str().c_str());
296         }
297     }
298     out.push_back(pstOutput);
299     return types::Function::OK;
300 }
301
302 types::Function::ReturnValue implicitListString(types::ImplicitList* pIL, types::typed_list &out)
303 {
304     std::wostringstream ostr;
305     pIL->toString(ostr);
306     std::wstring str = ostr.str();
307     //erase fisrt character " "
308     str.erase(str.begin());
309     //erase last character "\n"
310     str.erase(str.end() - 1);
311
312     out.push_back(new types::String(str.c_str()));
313     return types::Function::OK;
314 }
315
316 types::Function::ReturnValue PolynomString(types::Polynom* pPol, types::typed_list &out)
317 {
318     int iDims = pPol->getDims();
319     int* piDimsArray = pPol->getDimsArray();
320     types::String *pStr = new types::String(iDims, piDimsArray);
321     std::list<std::wstring> listWstPoly;
322
323     for (int iPos=0; iPos < pPol->getSize(); iPos++)
324     {
325         pPol->get(iPos)->toStringRealImg(pPol->getVariableName(), &listWstPoly, INT_MAX);
326         pStr->set(iPos,listWstPoly.front().c_str());
327         listWstPoly.clear();
328     }
329
330     out.push_back(pStr);
331     return types::Function::OK;
332 }
333
334
335
336 types::Function::ReturnValue sci_string(types::typed_list &in, int _iRetCount, types::typed_list &out)
337 {
338     if (in.size() != 1)
339     {
340         Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), "string", 1);
341         return types::Function::Error;
342     }
343
344     switch (in[0]->getType())
345     {
346         case types::GenericType::ScilabSparse:
347         {
348             //C=sparse([0 0 4 0 9;0 0 5 0 0;1 3 0 7 0;0 0 6 0 10;2 0 0 8 0]);string(C)
349             types::Sparse* pS = in[0]->getAs<types::Sparse>();
350             int iRows = pS->getRows();
351             int iCols = pS->getCols();
352             bool isComplex = pS->isComplex();
353             std::wostringstream ostr;
354             std::vector<std::wstring> vect;
355
356
357             ostr << "(" << iRows << "," << iCols << ") sparse matrix";
358
359             vect.push_back(ostr.str());
360             ostr.str(L"");
361             ostr.clear();
362
363             for (int i = 0 ; i < iRows ; i++)
364             {
365                 for (int j = 0 ; j < iCols ; j++)
366                 {
367                     std::wostringstream temp;
368                     double real = pS->getReal(i, j);
369                     double cplx = 0;
370                     if (isComplex)
371                     {
372                         cplx = pS->getImg(i, j).imag();
373                     }
374
375                     if (real || cplx )
376                     {
377                         temp << L"(" << i + 1 << L"," << j + 1 << L")    ";
378
379                         if (real)
380                         {
381                             temp << pS->getReal(i, j);
382                         }
383
384                         if (cplx)
385                         {
386                             if (real && cplx > 0)
387                             {
388                                 temp << L"+";
389                             }
390                             else if (cplx < 0)
391                             {
392                                 temp << L"-";
393                             }
394
395                             temp << L"%i*" << std::abs(cplx);
396                         }
397
398                         ostr << temp.str();
399                         vect.push_back(ostr.str());
400                         ostr.str(L"");
401                         ostr.clear();
402                     }
403                 }
404             }
405
406             types::String* pSt = new types::String((int)vect.size(), 1);
407             for (int i = 0 ; i < vect.size(); i++)
408             {
409                 pSt->set(i, vect[i].c_str());
410             }
411
412             out.push_back(pSt);
413             break;
414         }
415
416         case types::InternalType::ScilabInt8 :
417         {
418             return intString(in[0]->getAs<types::Int8>(), out);
419         }
420         case types::InternalType::ScilabUInt8 :
421         {
422             return intString(in[0]->getAs<types::UInt8>(), out);
423         }
424         case types::InternalType::ScilabInt16 :
425         {
426             return intString(in[0]->getAs<types::Int16>(), out);
427         }
428         case types::InternalType::ScilabUInt16 :
429         {
430             return intString(in[0]->getAs<types::UInt16>(), out);
431         }
432         case types::InternalType::ScilabInt32 :
433         {
434             return intString(in[0]->getAs<types::Int32>(), out);
435         }
436         case types::InternalType::ScilabUInt32 :
437         {
438             return intString(in[0]->getAs<types::UInt32>(), out);
439         }
440         case types::InternalType::ScilabInt64 :
441         {
442             return intString(in[0]->getAs<types::Int64>(), out);
443         }
444         case types::InternalType::ScilabUInt64 :
445         {
446             return intString(in[0]->getAs<types::UInt64>(), out);
447         }
448         case types::InternalType::ScilabDouble :
449         {
450             return doubleString(in[0]->getAs<types::Double>(), out);
451         }
452         case types::InternalType::ScilabString :
453         {
454             out.push_back(in[0]);
455             break;
456         }
457         case types::InternalType::ScilabFunction:
458         {
459             Scierror(999, _("%s: Wrong type for input argument #%d.\n"), "string", 1);
460             return types::Function::Error;
461         }
462         case types::InternalType::ScilabMacroFile :
463         {
464             if (_iRetCount != 3)
465             {
466                 Scierror(77, _("%s: Wrong number of output argument(s): %d expected.\n"), "string", 3);
467                 return types::Function::Error;
468             }
469
470             types::MacroFile* pMF = in[0]->getAs<types::MacroFile>();
471             types::InternalType* pOut = NULL;
472             types::InternalType* pIn = NULL;
473             types::InternalType* pBody = NULL;
474
475             getMacroString(pMF->getMacro(), &pOut, &pIn, &pBody);
476
477             out.push_back(pOut);
478             out.push_back(pIn);
479             out.push_back(pBody);
480             break;
481         }
482         case types::InternalType::ScilabMacro :
483         {
484             if (_iRetCount != 3)
485             {
486                 Scierror(77, _("%s: Wrong number of output argument(s): %d expected.\n"), "string", 3);
487                 return types::Function::Error;
488             }
489
490             types::Macro* pM = in[0]->getAs<types::Macro>();
491             types::InternalType* pOut = NULL;
492             types::InternalType* pIn = NULL;
493             types::InternalType* pBody = NULL;
494
495             getMacroString(pM, &pOut, &pIn, &pBody);
496
497             out.push_back(pOut);
498             out.push_back(pIn);
499             out.push_back(pBody);
500             break;
501         }
502         case types::InternalType::ScilabTList :
503         case types::InternalType::ScilabMList :
504         case types::InternalType::ScilabHandle :
505         {
506             std::wstring wstFuncName = L"%" + in[0]->getShortTypeStr() + L"_string";
507             return Overload::call(wstFuncName, in, _iRetCount, out);
508         }
509         case types::InternalType::ScilabBool:
510         {
511             return booleanString(in[0]->getAs<types::Bool>(), out);
512         }
513         case types::InternalType::ScilabLibrary:
514         {
515             types::Library* pL = in[0]->getAs<types::Library>();
516             std::wstring path = pL->getPath();
517             std::list<std::wstring> macros;
518             int size = pL->getMacrosName(macros);
519             types::String* pS = new types::String(size + 1, 1);
520             pS->set(0, path.c_str());
521             int i = 1;
522             for (auto it : macros)
523             {
524                 pS->set(i++, it.c_str());
525             }
526
527             out.push_back(pS);
528             break;
529         }
530         case types::InternalType::ScilabImplicitList:
531         {
532             return implicitListString(in[0]->getAs<types::ImplicitList>(), out);
533         }
534         case types::InternalType::ScilabColon:
535         {
536             out.push_back(new types::String(L""));
537             break;
538         }
539         case types::InternalType::ScilabPolynom :
540         {
541             return PolynomString(in[0]->getAs<types::Polynom>(), out);
542             break;            
543         }
544         
545         default:
546         {
547             std::wostringstream ostr;
548             in[0]->toString(ostr);
549             out.push_back(new types::String(ostr.str().c_str()));
550             break;
551         }
552     }
553     return types::Function::OK;
554 }