Coverity: ast module resource leaks fixed
[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                         delete[] piSize;
369                         return false;
370                     }
371
372                     ostemp << L"!";
373                     for (int iCols2 = iLastCol; iCols2 < iCols1; iCols2++)
374                     {
375                         _piDims[0] = iRows2;
376                         _piDims[1] = iCols2;
377                         int iPos = getIndex(_piDims);
378                         wchar_t* wcsStr = get(iPos);
379                         int iLenStr = static_cast<int>(wcslen(wcsStr));
380
381                         // Manage case where string length is greater than max line size.
382                         if (iLenStr > iStrMaxSize)
383                         {
384                             int iStrPos = 0;
385                             while (iLenStr > iStrMaxSize)
386                             {
387                                 ostemp.write(wcsStr + iStrPos, iStrMaxSize);
388                                 ostemp << L"!" << std::endl << L"!";
389                                 iLenStr -= iStrMaxSize;
390                                 iStrPos += iStrMaxSize;
391                             }
392
393                             configureStream(&ostemp, iStrMaxSize, iPrecision, ' ');
394                             ostemp << std::left << wcsStr + iStrPos;
395                         }
396                         else
397                         {
398                             configureStream(&ostemp, piSize[iCols2], iPrecision, ' ');
399                             ostemp << std::left << get(iPos) << spaces;
400                         }
401                     }
402                     ostemp << L"!" << std::endl;
403
404                     if ((iRows2 + 1) != m_iRows)
405                     {
406                         ostemp << L"!";
407                         // -2 because of two "!"
408                         configureStream(&ostemp, iEmptyLineSize, iPrecision, ' ');
409                         ostemp << std::left << L" ";
410                         ostemp << L"!" << std::endl;
411                     }
412                 }
413
414                 iLen = 0;
415                 iCurrentLine += 2;
416                 if (m_iRows2PrintState == 0)
417                 {
418                     iCurrentLine += 3;
419                     addColumnString(ostr, iLastCol + 1, iCols1);
420                 }
421
422                 ostr << ostemp.str();
423                 ostemp.str(L"");
424                 iLastCol = iCols1;
425                 m_iRows2PrintState = 0;
426                 m_iCols1PrintState = 0;
427             }
428             iLen += piSize[iCols1] + SIZE_BETWEEN_TWO_STRING_VALUES;
429         }
430
431         for (int iRows2 = m_iRows2PrintState ; iRows2 < getRows() ; iRows2++)
432         {
433             std::wstring spaces(L"");
434             iCurrentLine += 2;
435             if ((iMaxLines == 0 && iCurrentLine >= MAX_LINES) || (iMaxLines != 0 && iCurrentLine >= iMaxLines))
436             {
437                 if (m_iRows2PrintState == 0 && iLastCol != 0)
438                 {
439                     //add header
440                     addColumnString(ostr, iLastCol + 1, getCols());
441                 }
442
443                 ostr << ostemp.str();
444                 m_iRows2PrintState = iRows2;
445                 m_iCols1PrintState = iLastCol;
446                 delete[] piSize;
447                 return false;
448             }
449
450             int iEmptyLineSize = piSize[iLastCol];
451             if (piSize[iLastCol] != iStrMaxSize)
452             {
453                 // count SPACE_BETWEEN_TWO_STRING_VALUES size in padding of empty line
454                 // only if all lines have not a size greater than max size of a line.
455                 iEmptyLineSize += SIZE_BETWEEN_TWO_STRING_VALUES;
456                 spaces = SPACE_BETWEEN_TWO_STRING_VALUES;
457             }
458
459
460             ostemp << L"!";
461             iLen = 0;
462             for (int iCols2 = iLastCol ; iCols2 < getCols() ; iCols2++)
463             {
464                 _piDims[0] = iRows2;
465                 _piDims[1] = iCols2;
466                 int iPos = getIndex(_piDims);
467                 wchar_t* wcsStr = get(iPos);
468                 int iLenStr = static_cast<int>(wcslen(wcsStr));
469
470                 // Manage case where string length is greater than max line size.
471                 if (iStrMaxSize < iLenStr)
472                 {
473                     int iStrPos = 0;
474                     while (iLenStr > iStrMaxSize)
475                     {
476                         ostemp.write(wcsStr + iStrPos, iStrMaxSize);
477                         ostemp << L"!" << std::endl << L"!";
478                         iLenStr -= iStrMaxSize;
479                         iStrPos += iStrMaxSize;
480                     }
481
482                     configureStream(&ostemp, iStrMaxSize, iPrecision, ' ');
483                     ostemp << wcsStr + iStrPos << std::left;
484                     iLen = iStrMaxSize;
485                 }
486                 else
487                 {
488                     configureStream(&ostemp, piSize[iCols2], iPrecision, ' ');
489                     ostemp << std::left << get(iPos) << spaces;
490                     iLen += piSize[iCols2] + static_cast<int>(spaces.size());
491                 }
492             }
493             ostemp << L"!" << std::endl;
494
495             if ((iRows2 + 1) != m_iRows)
496             {
497                 ostemp << L"!";
498                 configureStream(&ostemp, iLen, iPrecision, ' ');
499                 ostemp << std::left << L" ";
500                 ostemp << L"!" << std::endl;
501             }
502         }
503
504         if (m_iRows2PrintState == 0 && iLastCol != 0)
505         {
506             addColumnString(ostr, iLastCol + 1, getCols());
507         }
508         ostr << ostemp.str();
509         delete[] piSize;
510     }
511
512     return true;
513 }
514
515 bool String::operator==(const InternalType& it)
516 {
517     if (const_cast<InternalType&>(it).isString() == false)
518     {
519         return false;
520     }
521
522     String* pS = const_cast<InternalType&>(it).getAs<types::String>();
523
524     if (pS->getRows() != getRows() || pS->getCols() != getCols())
525     {
526         return false;
527     }
528
529     wchar_t **p1 = get();
530     wchar_t **p2 = pS->get();
531
532     for (int i = 0 ; i < getSize() ; i++)
533     {
534         if (wcscmp(p1[i], p2[i]) != 0)
535         {
536             return false;
537         }
538     }
539     return true;
540 }
541
542 bool String::operator!=(const InternalType& it)
543 {
544     return !(*this == it);
545 }
546
547 wchar_t* String::getNullValue()
548 {
549     return os_wcsdup(L"");
550 }
551
552 String* String::createEmpty(int _iDims, int* _piDims, bool /*_bComplex*/)
553 {
554     return new String(_iDims, _piDims);
555 }
556
557 wchar_t* String::copyValue(wchar_t* _pwstData)
558 {
559     try
560     {
561         return os_wcsdup(_pwstData);
562     }
563     catch (std::bad_alloc & /*e*/)
564     {
565         char message[bsiz];
566         os_sprintf(message, _("Can not allocate data.\n"));
567         throw ast::InternalError(message);
568     }
569
570     return NULL;
571 }
572
573 wchar_t* String::copyValue(const wchar_t* _pwstData)
574 {
575     return os_wcsdup(_pwstData);
576 }
577
578 void String::deleteData(wchar_t* data)
579 {
580     if (data)
581     {
582         // data are always allocated using C-like malloc API
583         FREE(data);
584     }
585 }
586
587 String* String::set(int _iPos, const wchar_t* _pwstData)
588 {
589     if (m_pRealData == NULL || _iPos >= m_iSize)
590     {
591         return NULL;
592     }
593
594     typedef String* (String::*set_t)(int, const wchar_t*);
595     String* pIT = checkRef(this, (set_t)&String::set, _iPos, _pwstData);
596     if (pIT != this)
597     {
598         return pIT;
599     }
600
601     deleteString(_iPos);
602     m_pRealData[_iPos] = copyValue(_pwstData);
603     return this;
604 }
605
606 String* String::set(int _iRows, int _iCols, const wchar_t* _pwstData)
607 {
608     int piIndexes[2] = {_iRows, _iCols};
609     return set(getIndex(piIndexes), _pwstData);
610 }
611
612 String* String::set(const wchar_t* const* _pwstData)
613 {
614     typedef String* (String::*set_t)(const wchar_t * const*);
615     String* pIT = checkRef(this, (set_t)&String::set, _pwstData);
616     if (pIT != this)
617     {
618         return pIT;
619     }
620
621     for (int i = 0; i < m_iSize; i++)
622     {
623         if (m_pRealData == NULL || i >= m_iSize)
624         {
625             return NULL;
626         }
627
628         deleteString(i);
629         m_pRealData[i] = copyValue(_pwstData[i]);
630     }
631     return this;
632 }
633
634 String* String::set(int _iPos, const char* _pcData)
635 {
636     wchar_t* w = to_wide_string(_pcData);
637     String* ret = set(_iPos, w);
638     FREE(w);
639     return ret;
640 }
641
642 String* String::set(int _iRows, int _iCols, const char* _pcData)
643 {
644     int piIndexes[2] = {_iRows, _iCols};
645     return set(getIndex(piIndexes), _pcData);
646 }
647
648 String* String::set(const char* const* _pstrData)
649 {
650     typedef String* (String::*set_t)(const char * const*);
651     String* pIT = checkRef(this, (set_t)&String::set, _pstrData);
652     if (pIT != this)
653     {
654         return pIT;
655     }
656
657     for (int i = 0; i < m_iSize; i++)
658     {
659         if (set(i, _pstrData[i]) == NULL)
660         {
661             return NULL;
662         }
663     }
664     return this;
665 }
666
667 wchar_t** String::allocData(int _iSize)
668 {
669     wchar_t** pStr = nullptr;
670     try
671     {
672         pStr = new wchar_t*[_iSize];
673         memset(pStr, 0x00, _iSize * sizeof(wchar_t*));
674     }
675     catch (std::bad_alloc & /*e*/)
676     {
677         char message[bsiz];
678         os_sprintf(message, _("Can not allocate %.2f MB memory.\n"), (double)(_iSize * sizeof(char*)) / 1.e6);
679         throw ast::InternalError(message);
680     }
681     return pStr;
682 }
683
684 ast::Exp* String::getExp(const Location& loc)
685 {
686     return new ast::StringExp(loc, this);
687 }
688
689 bool String::transpose(InternalType *& out)
690 {
691     return type_traits::transpose(*this, out);
692 }
693
694 }
695