Merge remote-tracking branch 'origin/master' into jit
[scilab.git] / scilab / modules / ast / src / cpp / types / string.cpp
1 /*
2 *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 *  Copyright (C) 2008-2008 - 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 <sstream>
14 #include "core_math.h"
15 #include "string.hxx"
16 #include "stringexp.hxx"
17 #include "tostring_common.hxx"
18 #include "configvariable.hxx"
19 #include "type_traits.hxx"
20
21 extern "C"
22 {
23 #include "charEncoding.h"
24 #include "os_string.h"
25 #include "sci_malloc.h"
26 }
27
28 #define SIZE_BETWEEN_TWO_STRING_VALUES  2
29 #define SPACE_BETWEEN_TWO_STRING_VALUES L"  "
30
31 namespace types
32 {
33 String::~String()
34 {
35     if (isDeletable() == true)
36     {
37         deleteAll();
38     }
39 #ifndef NDEBUG
40     Inspector::removeItem(this);
41 #endif
42 }
43
44 String::String(int _iDims, const int* _piDims)
45 {
46     wchar_t** pwsData = NULL;
47     create(_piDims, _iDims, &pwsData, NULL);
48 #ifndef NDEBUG
49     Inspector::addItem(this);
50 #endif
51 }
52
53 String::String(const wchar_t* _pwstData)
54 {
55     wchar_t** pwsData = NULL;
56     int piDims[] = {1, 1};
57     create(piDims, 2, &pwsData, NULL);
58     set(0, 0, _pwstData);
59 #ifndef NDEBUG
60     Inspector::addItem(this);
61 #endif
62 }
63
64 String::String(const char *_pstData)
65 {
66     wchar_t** pwsData = NULL;
67     int piDims[] = {1, 1};
68     create(piDims, 2, &pwsData, NULL);
69     wchar_t* data = to_wide_string(const_cast<char*>(_pstData));
70     set(0, 0, data);
71     FREE(data);
72 #ifndef NDEBUG
73     Inspector::addItem(this);
74 #endif
75 }
76
77 String::String(int _iRows, int _iCols)
78 {
79     wchar_t** pwsData = NULL;
80     int piDims[] = {_iRows, _iCols};
81     create(piDims, 2, &pwsData, NULL);
82 #ifndef NDEBUG
83     Inspector::addItem(this);
84 #endif
85 }
86
87 String::String(int _iRows, int _iCols, wchar_t const* const* _pstData)
88 {
89     wchar_t** pwsData = NULL;
90     int piDims[] = {_iRows, _iCols};
91     create(piDims, 2, &pwsData, NULL);
92     for (int i = 0 ; i < m_iSize ; i++)
93     {
94         set(i, _pstData[i]);
95     }
96 #ifndef NDEBUG
97     Inspector::addItem(this);
98 #endif
99 }
100
101 InternalType* String::clone()
102 {
103     String *pstClone = new String(getDims(), getDimsArray());
104     pstClone->set(m_pRealData);
105     return pstClone;
106 }
107
108 void String::whoAmI()
109 {
110     std::cout << "types::String";
111 }
112
113 void String::deleteString(int _iPos)
114 {
115     if (m_pRealData != NULL)
116     {
117         if (m_pRealData[_iPos] != NULL)
118         {
119             FREE(m_pRealData[_iPos]);
120             m_pRealData[_iPos] = NULL;
121         }
122     }
123 }
124
125 void String::deleteAll()
126 {
127     for (int i = 0 ; i < m_iSizeMax ; i++)
128     {
129         deleteString(i);
130     }
131     delete[] m_pRealData;
132     m_pRealData = NULL;
133 }
134
135 void String::deleteImg()
136 {
137     return;
138 }
139
140 bool String::subMatrixToString(std::wostringstream& ostr, int* _piDims, int /*_iDims*/)
141 {
142     int iPrecision = ConfigVariable::getFormatSize();
143     int iLineLen = ConfigVariable::getConsoleWidth();
144     int iMaxLines = ConfigVariable::getConsoleLines();
145     int iCurrentLine = 0;
146
147     // less the two "!" (or two " " in scalar case)
148     // for iLineLen = 50 we will write "!48char!"
149     int iStrMaxSize = iLineLen - 2;
150
151     if (isScalar())
152     {
153         int iMaxLen = 0;
154         _piDims[0]  = 0;
155         _piDims[1]  = 0;
156
157         int iPos = getIndex(_piDims);
158         wchar_t* wcsStr = get(iPos);
159         int iCurLen = static_cast<int>(wcslen(wcsStr));
160         iMaxLen = std::max(iMaxLen, iCurLen);
161         iMaxLen = std::min(iMaxLen, iStrMaxSize);
162
163         if (iCurLen > iMaxLen)
164         {
165             int iStrPos = 0;
166             while (iCurLen > iStrMaxSize)
167             {
168                 ostr << L" ";
169                 ostr.write(wcsStr + iStrPos, iStrMaxSize);
170                 ostr << L" " << std::endl;
171                 iCurLen -= iStrMaxSize;
172                 iStrPos += iStrMaxSize;
173             }
174
175             ostr << L" ";
176             configureStream(&ostr, iStrMaxSize, iPrecision, ' ');
177             ostr << std::left << wcsStr + iStrPos;
178         }
179         else
180         {
181             ostr << L" " << wcsStr << std::endl;
182         }
183     }
184     else if (getCols() == 1)
185     {
186         std::wstring spaces(L"");
187
188         // compte max string size
189         int iMaxLen = 0;
190         for (int i = 0 ; i < getRows() ; i++)
191         {
192             _piDims[1] = 0;
193             _piDims[0] = i;
194             int iPos = getIndex(_piDims);
195             iMaxLen = std::max(iMaxLen, static_cast<int>(wcslen(get(iPos))));
196             iMaxLen = std::min(iMaxLen, iStrMaxSize);
197         }
198
199         int iEmptyLineSize = iMaxLen;
200         if (iMaxLen != iStrMaxSize)
201         {
202             // count SPACE_BETWEEN_TWO_STRING_VALUES size in padding of empty line
203             // only if all lines have not a size greater than max size of a line.
204             iEmptyLineSize += SIZE_BETWEEN_TWO_STRING_VALUES;
205             spaces = SPACE_BETWEEN_TWO_STRING_VALUES;
206         }
207
208         for (int i = m_iRows1PrintState ; i < getRows() ; i++)
209         {
210             iCurrentLine += 2;
211             if ((iMaxLines == 0 && iCurrentLine >= MAX_LINES) || (iMaxLines != 0 && iCurrentLine >= iMaxLines))
212             {
213                 m_iRows1PrintState = i;
214                 return false;
215             }
216
217             _piDims[1] = 0;
218             _piDims[0] = i;
219             int iPos = getIndex(_piDims);
220             wchar_t* wcsStr = get(iPos);
221             int iCurLen = static_cast<int>(wcslen(wcsStr));
222
223             ostr << L"!";
224             if (iCurLen > iMaxLen)
225             {
226                 int iStrPos = 0;
227                 while (iCurLen > iStrMaxSize)
228                 {
229                     ostr.write(wcsStr + iStrPos, iStrMaxSize);
230                     ostr << L"!" << std::endl << L"!";
231                     iCurLen -= iStrMaxSize;
232                     iStrPos += iStrMaxSize;
233                 }
234
235                 configureStream(&ostr, iStrMaxSize, iPrecision, ' ');
236                 ostr << std::left << wcsStr + iStrPos;
237             }
238             else
239             {
240                 configureStream(&ostr, iMaxLen, iPrecision, ' ');
241                 ostr << std::left << wcsStr << spaces;
242             }
243
244             ostr << L"!" << std::endl;
245
246             if ((i + 1) < m_iSize)
247             {
248                 //for all but last one
249                 ostr << L"!";
250                 configureStream(&ostr, iEmptyLineSize, iPrecision, ' ');
251                 ostr << std::left << L" ";
252                 ostr << L"!" << std::endl;
253             }
254         }
255     }
256     else if (getRows() == 1)
257     {
258         std::wostringstream ostemp;
259         int iLastVal = m_iCols1PrintState;
260
261         for (int i = m_iCols1PrintState ; i < getCols() ; i++)
262         {
263             _piDims[0] = 0;
264             _piDims[1] = i;
265             int iPos = getIndex(_piDims);
266
267             int iLen = 0;
268             int iCurLen = static_cast<int>(wcslen(get(iPos)));
269             iLen = iCurLen + SIZE_BETWEEN_TWO_STRING_VALUES + static_cast<int>(ostemp.str().size());
270             if (iLen > iLineLen && iLastVal != i)
271             {
272                 //Max length, new line
273                 iCurrentLine += 4; //"column x to Y" + empty line + value + empty line
274                 if ((iMaxLines == 0 && iCurrentLine >= MAX_LINES) || (iMaxLines != 0 && iCurrentLine >= iMaxLines))
275                 {
276                     m_iCols1PrintState = iLastVal;
277                     return false;
278                 }
279
280                 addColumnString(ostr, iLastVal + 1, i);
281                 ostr << L"!" << ostemp.str() << L"!" << std::endl;
282                 ostemp.str(L"");
283                 iLastVal = i;
284             }
285
286             // Manage case where string length is greater than max line size.
287             if (iStrMaxSize < iCurLen)
288             {
289                 wchar_t* wcsStr = get(iPos);
290                 int iStrPos = 0;
291                 while (iCurLen > iStrMaxSize) // -2 because of two "!"
292                 {
293                     ostemp.write(wcsStr + iStrPos, iStrMaxSize);
294                     ostemp << L"!" << std::endl << L"!";
295                     iCurLen -= iStrMaxSize;
296                     iStrPos += iStrMaxSize;
297                 }
298
299                 configureStream(&ostemp, iStrMaxSize, iPrecision, ' ');
300                 ostemp << std::left << wcsStr + iStrPos;
301             }
302             else
303             {
304                 configureStream(&ostemp, iCurLen + 2, iPrecision, ' ');
305                 ostemp << std::left << get(iPos);
306             }
307         }
308
309         if (iLastVal != 0)
310         {
311             addColumnString(ostr, iLastVal + 1, getCols());
312         }
313
314         ostr << L"!" << ostemp.str() << L"!" << std::endl;
315     }
316     else //Matrix
317     {
318         std::wostringstream ostemp;
319         int iLen = 0;
320         int iLastCol = m_iCols1PrintState;
321
322         //Array with the max printed size of each col
323         int *piSize = new int[getCols()];
324         memset(piSize, 0x00, getCols() * sizeof(int));
325
326         for (int iCols1 = m_iCols1PrintState ; iCols1 < getCols() ; iCols1++)
327         {
328             std::wstring spaces(L"");
329             for (int iRows1 = 0 ; iRows1 < getRows() ; iRows1++)
330             {
331                 _piDims[1] = iCols1;
332                 _piDims[0] = iRows1;
333                 int iPos = getIndex(_piDims);
334                 piSize[iCols1] = std::max(piSize[iCols1], static_cast<int>(wcslen(get(iPos))));
335                 piSize[iCols1] = std::min(piSize[iCols1], iStrMaxSize);
336             }
337
338             int iEmptyLineSize = piSize[iLastCol];
339             if (piSize[iLastCol] != iStrMaxSize)
340             {
341                 // count SPACE_BETWEEN_TWO_STRING_VALUES size in padding of empty line
342                 // only if all lines have not a size greater than max size of a line.
343                 iEmptyLineSize += SIZE_BETWEEN_TWO_STRING_VALUES;
344                 spaces = SPACE_BETWEEN_TWO_STRING_VALUES;
345             }
346
347             if (iLen + piSize[iCols1] > iLineLen && iLastCol != iCols1)
348             {
349                 //find the limit, print this part
350                 for (int iRows2 = m_iRows2PrintState ; iRows2 < getRows() ; iRows2++)
351                 {
352                     iCurrentLine += 2;
353                     if ((iMaxLines == 0 && iCurrentLine >= MAX_LINES) ||
354                             ( (iMaxLines != 0 && iCurrentLine + 3 >= iMaxLines && iRows2 == m_iRows2PrintState) ||
355                               (iMaxLines != 0 && iCurrentLine + 1 >= iMaxLines && iRows2 != m_iRows2PrintState)))
356                     {
357                         if (m_iRows2PrintState == 0 && iRows2 != 0)
358                         {
359                             //add header
360                             addColumnString(ostr, iLastCol + 1, iCols1);
361                         }
362                         ostr << ostemp.str();
363                         m_iRows2PrintState = iRows2;
364                         m_iCols1PrintState = iLastCol;
365                         return false;
366                     }
367
368                     ostemp << L"!";
369                     for (int iCols2 = iLastCol; iCols2 < iCols1; iCols2++)
370                     {
371                         _piDims[0] = iRows2;
372                         _piDims[1] = iCols2;
373                         int iPos = getIndex(_piDims);
374                         wchar_t* wcsStr = get(iPos);
375                         int iLenStr = static_cast<int>(wcslen(wcsStr));
376
377                         // Manage case where string length is greater than max line size.
378                         if (iLenStr > iStrMaxSize)
379                         {
380                             int iStrPos = 0;
381                             while (iLenStr > iStrMaxSize)
382                             {
383                                 ostemp.write(wcsStr + iStrPos, iStrMaxSize);
384                                 ostemp << L"!" << std::endl << L"!";
385                                 iLenStr -= iStrMaxSize;
386                                 iStrPos += iStrMaxSize;
387                             }
388
389                             configureStream(&ostemp, iStrMaxSize, iPrecision, ' ');
390                             ostemp << std::left << wcsStr + iStrPos;
391                         }
392                         else
393                         {
394                             configureStream(&ostemp, piSize[iCols2], iPrecision, ' ');
395                             ostemp << std::left << get(iPos) << spaces;
396                         }
397                     }
398                     ostemp << L"!" << std::endl;
399
400                     if ((iRows2 + 1) != m_iRows)
401                     {
402                         ostemp << L"!";
403                         // -2 because of two "!"
404                         configureStream(&ostemp, iEmptyLineSize, iPrecision, ' ');
405                         ostemp << std::left << L" ";
406                         ostemp << L"!" << std::endl;
407                     }
408                 }
409
410                 iLen = 0;
411                 iCurrentLine += 2;
412                 if (m_iRows2PrintState == 0)
413                 {
414                     iCurrentLine += 3;
415                     addColumnString(ostr, iLastCol + 1, iCols1);
416                 }
417
418                 ostr << ostemp.str();
419                 ostemp.str(L"");
420                 iLastCol = iCols1;
421                 m_iRows2PrintState = 0;
422                 m_iCols1PrintState = 0;
423             }
424             iLen += piSize[iCols1] + SIZE_BETWEEN_TWO_STRING_VALUES;
425         }
426
427         for (int iRows2 = m_iRows2PrintState ; iRows2 < getRows() ; iRows2++)
428         {
429             std::wstring spaces(L"");
430             iCurrentLine += 2;
431             if ((iMaxLines == 0 && iCurrentLine >= MAX_LINES) || (iMaxLines != 0 && iCurrentLine >= iMaxLines))
432             {
433                 if (m_iRows2PrintState == 0 && iLastCol != 0)
434                 {
435                     //add header
436                     addColumnString(ostr, iLastCol + 1, getCols());
437                 }
438
439                 ostr << ostemp.str();
440                 m_iRows2PrintState = iRows2;
441                 m_iCols1PrintState = iLastCol;
442                 return false;
443             }
444
445             int iEmptyLineSize = piSize[iLastCol];
446             if (piSize[iLastCol] != iStrMaxSize)
447             {
448                 // count SPACE_BETWEEN_TWO_STRING_VALUES size in padding of empty line
449                 // only if all lines have not a size greater than max size of a line.
450                 iEmptyLineSize += SIZE_BETWEEN_TWO_STRING_VALUES;
451                 spaces = SPACE_BETWEEN_TWO_STRING_VALUES;
452             }
453
454
455             ostemp << L"!";
456             iLen = 0;
457             for (int iCols2 = iLastCol ; iCols2 < getCols() ; iCols2++)
458             {
459                 _piDims[0] = iRows2;
460                 _piDims[1] = iCols2;
461                 int iPos = getIndex(_piDims);
462                 wchar_t* wcsStr = get(iPos);
463                 int iLenStr = static_cast<int>(wcslen(wcsStr));
464
465                 // Manage case where string length is greater than max line size.
466                 if (iStrMaxSize < iLenStr)
467                 {
468                     int iStrPos = 0;
469                     while (iLenStr > iStrMaxSize)
470                     {
471                         ostemp.write(wcsStr + iStrPos, iStrMaxSize);
472                         ostemp << L"!" << std::endl << L"!";
473                         iLenStr -= iStrMaxSize;
474                         iStrPos += iStrMaxSize;
475                     }
476
477                     configureStream(&ostemp, iStrMaxSize, iPrecision, ' ');
478                     ostemp << wcsStr + iStrPos << std::left;
479                     iLen = iStrMaxSize;
480                 }
481                 else
482                 {
483                     configureStream(&ostemp, piSize[iCols2], iPrecision, ' ');
484                     ostemp << std::left << get(iPos) << spaces;
485                     iLen += piSize[iCols2] + static_cast<int>(spaces.size());
486                 }
487             }
488             ostemp << L"!" << std::endl;
489
490             if ((iRows2 + 1) != m_iRows)
491             {
492                 ostemp << L"!";
493                 configureStream(&ostemp, iLen, iPrecision, ' ');
494                 ostemp << std::left << L" ";
495                 ostemp << L"!" << std::endl;
496             }
497         }
498
499         if (m_iRows2PrintState == 0 && iLastCol != 0)
500         {
501             addColumnString(ostr, iLastCol + 1, getCols());
502         }
503         ostr << ostemp.str();
504     }
505
506     return true;
507 }
508
509 bool String::operator==(const InternalType& it)
510 {
511     if (const_cast<InternalType&>(it).isString() == false)
512     {
513         return false;
514     }
515
516     String* pS = const_cast<InternalType&>(it).getAs<types::String>();
517
518     if (pS->getRows() != getRows() || pS->getCols() != getCols())
519     {
520         return false;
521     }
522
523     wchar_t **p1 = get();
524     wchar_t **p2 = pS->get();
525
526     for (int i = 0 ; i < getSize() ; i++)
527     {
528         if (wcscmp(p1[i], p2[i]) != 0)
529         {
530             return false;
531         }
532     }
533     return true;
534 }
535
536 bool String::operator!=(const InternalType& it)
537 {
538     return !(*this == it);
539 }
540
541 wchar_t* String::getNullValue()
542 {
543     return os_wcsdup(L"");
544 }
545
546 String* String::createEmpty(int _iDims, int* _piDims, bool /*_bComplex*/)
547 {
548     return new String(_iDims, _piDims);
549 }
550
551 wchar_t* String::copyValue(wchar_t* _pwstData)
552 {
553     try
554     {
555         return os_wcsdup(_pwstData);
556     }
557     catch (std::bad_alloc & /*e*/)
558     {
559         char message[bsiz];
560         os_sprintf(message, _("Can not allocate data.\n"));
561         throw ast::InternalError(message);
562     }
563
564     return NULL;
565 }
566
567 wchar_t* String::copyValue(const wchar_t* _pwstData)
568 {
569     return os_wcsdup(_pwstData);
570 }
571
572 void String::deleteData(wchar_t* data)
573 {
574     if (data)
575     {
576         // data are always allocated using C-like malloc API
577         FREE(data);
578     }
579 }
580
581 bool String::set(int _iPos, const wchar_t* _pwstData)
582 {
583     if (m_pRealData == NULL || _iPos >= m_iSize)
584     {
585         return false;
586     }
587
588     deleteString(_iPos);
589     m_pRealData[_iPos] = copyValue(_pwstData);
590     return true;
591 }
592
593 bool String::set(int _iRows, int _iCols, const wchar_t* _pwstData)
594 {
595     int piIndexes[2] = {_iRows, _iCols};
596     return set(getIndex(piIndexes), _pwstData);
597 }
598
599 bool String::set(const wchar_t* const* _pwstData)
600 {
601     for (int i = 0; i < getSize(); i++)
602     {
603         if (set(i, _pwstData[i]) == false)
604         {
605             return false;
606         }
607     }
608     return true;
609 }
610
611 bool String::set(int _iPos, const char* _pcData)
612 {
613     wchar_t* w = to_wide_string(_pcData);
614     bool ret = set(_iPos, w);
615     FREE(w);
616     return ret;
617 }
618
619 bool String::set(int _iRows, int _iCols, const char* _pcData)
620 {
621     int piIndexes[2] = {_iRows, _iCols};
622     return set(getIndex(piIndexes), _pcData);
623 }
624
625 bool String::set(const char* const* _pstrData)
626 {
627     for (int i = 0; i < getSize(); i++)
628     {
629         if (set(i, _pstrData[i]) == false)
630         {
631             return false;
632         }
633     }
634     return true;
635 }
636
637 wchar_t** String::allocData(int _iSize)
638 {
639     wchar_t** pStr = nullptr;
640     try
641     {
642         pStr = new wchar_t*[_iSize];
643         memset(pStr, 0x00, _iSize * sizeof(wchar_t*));
644     }
645     catch (std::bad_alloc & /*e*/)
646     {
647         char message[bsiz];
648         os_sprintf(message, _("Can not allocate %.2f MB memory.\n"), (double)(_iSize * sizeof(char*)) / 1.e6);
649         throw ast::InternalError(message);
650     }
651     return pStr;
652 }
653
654 ast::Exp* String::getExp(const Location& loc)
655 {
656     return new ast::StringExp(loc, this);
657 }
658
659 bool String::transpose(InternalType *& out)
660 {
661     return type_traits::transpose(*this, out);
662 }
663
664 }
665