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