bug 13972 : use of wildcard '*' in printf expressions was not managed
[scilab.git] / scilab / modules / output_stream / src / cpp / scilab_sprintf.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
4  *  Copyright (C) 2013 - Scilab Enterprises - Cedric Delamarre
5  *  Copyright (C) 2015 - Scilab Enterprises - Antoine ELIAS
6  *
7  *  This file must be used under the terms of the CeCILL.
8  *  This source file is licensed as described in the file COPYING, which
9  *  you should have received as part of this distribution.  The terms
10  *  are also available at
11  *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
12  *
13  */
14
15 #include <stdio.h>
16 #include <cmath>
17 #include <list>
18 #include "types.hxx"
19 #include "double.hxx"
20 #include "string.hxx"
21 #include "scilab_sprintf.hxx"
22
23 using namespace types;
24
25 extern "C"
26 {
27 #include "Scierror.h"
28 #include "sci_malloc.h"
29 #include "localization.h"
30 #include "charEncoding.h"
31 #include "os_string.h"
32 #include "os_wtoi.h"
33 #include "os_string.h"
34 }
35
36 static wchar_t* replaceAndCountLines(const wchar_t* _pwstInput, int* _piLines, int* _piNewLine);
37 static wchar_t* addl(TokenDef* token);
38 static void updatel(TokenDef* token);
39
40 #define NanString L"Nan"
41 #define InfString L"Inf"
42 #define NegInfString L"-Inf"
43
44 wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput, typed_list &in, int* _piOutputRows, int* _piNewLine)
45 {
46     /* Force Windows display to have two-digit exponent. */
47 #ifdef _MSC_VER
48     _set_output_format(_TWO_DIGIT_EXPONENT);
49 #endif
50     wchar_t** pwstOutput = nullptr;
51     int rhs = in.size();
52     wchar_t* pwstFirstOutput = nullptr;
53     *_piNewLine = 0;
54     int col = 0;
55
56     int first = 1;
57     if (funcname == "mfprintf")
58     {
59         first = 2;
60     }
61
62     size_t posIn = first;
63
64     //compute couple (index in input and col number ).
65     std::list<std::pair<int, int> > inPos;
66     for (int i = first; i < in.size(); ++i)
67     {
68         GenericType* gt = in[i]->getAs<GenericType>();
69         int col = gt->getCols();
70         for (int j = 0; j < col; ++j)
71         {
72             inPos.emplace_back(i, j);
73         }
74     }
75
76     std::list<std::pair<int, int> >::iterator itPos = inPos.begin();
77
78     //\n \n\r \r \t to string
79     //find number of lines
80     // replace \\n \\t... by \n \t...
81     pwstFirstOutput = replaceAndCountLines(_pwstInput, _piOutputRows, _piNewLine);
82
83     std::list<TokenDef*> token;
84
85     size_t start = 0;
86     size_t end = 0;
87     bool finish = false;
88
89     wchar_t* pwstStart = pwstFirstOutput;
90     bool percentpercent = false;
91
92     while (finish == false)
93     {
94         wchar_t* pwstEnd = wcsstr(pwstStart + (token.size() == 0 ? 0 : 1), L"%");
95         start = pwstStart - pwstFirstOutput;
96         percentpercent = false;
97         if (pwstEnd != nullptr)
98         {
99             if (token.size() && pwstStart[1] == L'%')
100             {
101                 //manage "%%"
102                 pwstEnd = wcsstr(pwstEnd + 1, L"%");
103                 if (pwstEnd == nullptr)
104                 {
105                     //end of string
106                     end = wcslen(pwstFirstOutput);
107                     finish = true;
108                 }
109                 else
110                 {
111                     end = pwstEnd - pwstFirstOutput;
112                 }
113
114                 // skip the first %
115                 start++;
116                 percentpercent = true;
117             }
118             else
119             {
120                 end = pwstEnd - pwstFirstOutput;
121             }
122         }
123         else
124         {
125             //end of string
126             end = wcslen(pwstFirstOutput);
127             finish = true;
128         }
129
130         TokenDef* tok = new TokenDef;
131         tok->pwstToken = new wchar_t[end - start + 1];
132         wcsncpy(tok->pwstToken, pwstFirstOutput + start, end - start);
133         tok->pwstToken[end - start] = L'\0';
134         token.push_back(tok);
135
136         wchar_t* pwstPercent = wcsstr(tok->pwstToken, L"%");
137         if (pwstPercent != nullptr && percentpercent == false)
138         {
139             //looking for flags
140             if (*(pwstPercent + 1) == L'-' ||
141                     *(pwstPercent + 1) == L'+' ||
142                     *(pwstPercent + 1) == L' ' ||
143                     *(pwstPercent + 1) == L'#' ||
144                     *(pwstPercent + 1) == L'0')
145             {
146                 pwstPercent++;
147             }
148
149             //looking for width
150             if (*(pwstPercent + 1) == L'*')
151             {
152                 if (itPos == inPos.end())
153                 {
154                     Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
155                     *_piOutputRows = 0;
156                     return nullptr;
157                 }
158
159                 int p = (*itPos).first;
160                 //input data use to set width
161                 if (in[p]->getId() != InternalType::IdScalarDouble)
162                 {
163                     Scierror(999, _("%s: Wrong type of input arguments #%d: A real scalar expected.\n"), funcname.data(), p);
164                     *_piOutputRows = 0;
165                     return nullptr;
166                 }
167
168
169                 Double* dbl = in[p]->getAs<Double>();
170                 tok->width = static_cast<int>(dbl->get()[0]);
171                 tok->widthStar = true;
172                 ++itPos;
173                 ++pwstPercent;
174             }
175             else
176             {
177                 //number
178                 if (iswdigit(*(pwstPercent + 1)))
179                 {
180                     tok->width = os_wtoi(pwstPercent + 1);
181                     while (iswdigit(*(pwstPercent + 1)))
182                     {
183                         pwstPercent++;
184                     }
185                 }
186             }
187
188             //looking for precision
189             if (*(pwstPercent + 1) == L'.')
190             {
191                 pwstPercent++;
192
193                 if (iswdigit(*(pwstPercent + 1)))
194                 {
195                     tok->prec = os_wtoi(pwstPercent + 1);
196                     while (iswdigit(*(pwstPercent + 1)))
197                     {
198                         pwstPercent++;
199                     }
200                 }
201                 else if (*(pwstPercent + 1) == L'*')
202                 {
203                     if (itPos == inPos.end())
204                     {
205                         Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
206                         *_piOutputRows = 0;
207                         return nullptr;
208                     }
209
210                     int p = (*itPos).first;
211                     //input data use to set prec
212                     if (in[p]->getId() != InternalType::IdScalarDouble)
213                     {
214                         Scierror(999, _("%s: Wrong type of input arguments #%d: A real scalar expected.\n"), funcname.data(), p + 1);
215                         *_piOutputRows = 0;
216                         return nullptr;
217                     }
218
219                     Double* dbl = in[p]->getAs<Double>();
220                     tok->prec = static_cast<int>(dbl->get()[0]);
221                     tok->precStar = true;
222                     ++itPos;
223                     ++pwstPercent;
224                 }
225             }
226
227             //looking for length
228             if (*(pwstPercent + 1) == L'h' ||
229                     *(pwstPercent + 1) == L'l' ||
230                     *(pwstPercent + 1) == L'L')
231             {
232                 tok->length = true;
233                 pwstPercent++;
234             }
235
236             wchar_t wcType = *(pwstPercent + 1);
237             tok->typePos = (pwstPercent + 1) - tok->pwstToken;
238
239             switch (wcType)
240             {
241                 case L'i': //integer
242                 case L'd': //integer
243                 {
244                     if (itPos == inPos.end())
245                     {
246                         Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
247                         *_piOutputRows = 0;
248                         return nullptr;
249                     }
250
251                     int p = (*itPos).first;
252                     int c = (*itPos).second;
253                     if (in[p]->getType() != InternalType::ScilabDouble)
254                     {
255                         Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
256                         *_piOutputRows = 0;
257                         return nullptr;
258                     }
259
260                     tok->outputType = InternalType::ScilabInt32;
261                     tok->pos = p;
262                     tok->col = c;
263                     ++itPos;
264                     break;
265                 }
266                 case L'o': //octal
267                 case L'u': //unsigned
268                 case L'x': //hex
269                 case L'X': //HEX
270                 {
271                     if (itPos == inPos.end())
272                     {
273                         Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
274                         *_piOutputRows = 0;
275                         return nullptr;
276                     }
277
278                     int p = (*itPos).first;
279                     int c = (*itPos).second;
280                     if (in[p]->getType() != InternalType::ScilabDouble)
281                     {
282                         Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
283                         *_piOutputRows = 0;
284                         return nullptr;
285                     }
286
287                     tok->outputType = InternalType::ScilabUInt32;
288                     tok->pos = p;
289                     tok->col = c;
290                     ++itPos;
291                     break;
292                 }
293                 case L'f': //float
294                 case L'e': //exp
295                 case L'E': //EXP
296                 case L'g': //shorter between float or exp
297                 case L'G': //shorter between float or EXP
298                 {
299                     if (itPos == inPos.end())
300                     {
301                         Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
302                         *_piOutputRows = 0;
303                         return nullptr;
304                     }
305
306                     int p = (*itPos).first;
307                     int c = (*itPos).second;
308                     if (in[p]->getType() != InternalType::ScilabDouble)
309                     {
310                         Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
311                         *_piOutputRows = 0;
312                         return nullptr;
313                     }
314
315                     tok->outputType = InternalType::ScilabDouble;
316                     tok->pos = p;
317                     tok->col = c;
318                     ++itPos;
319                     break;
320                 }
321                 case L's':
322                 case L'c':
323                 {
324                     if (itPos == inPos.end())
325                     {
326                         Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
327                         *_piOutputRows = 0;
328                         return nullptr;
329                     }
330
331                     int p = (*itPos).first;
332                     int c = (*itPos).second;
333                     if (in[p]->getType() != InternalType::ScilabString)
334                     {
335                         Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
336                         *_piOutputRows = 0;
337                         return nullptr;
338                     }
339
340                     if (tok->length == false)
341                     {
342                         updatel(tok);
343                     }
344
345                     tok->outputType = InternalType::ScilabString;
346                     tok->pos = p;
347                     tok->col = c;
348                     ++itPos;
349                     break;
350                 }
351                 default:
352                     Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
353                     *_piOutputRows = 0;
354                     return nullptr;
355                     break;
356             }
357         }
358
359         //continue
360         pwstStart = pwstEnd;
361     }
362
363     FREE(pwstFirstOutput);
364     pwstFirstOutput = nullptr;
365
366     int iLoop = 1;
367
368     if (rhs > first)
369     {
370         std::list<TokenDef*>::iterator it = std::next(token.begin());
371         iLoop = in[(*it)->pos]->getAs<GenericType>()->getRows();
372         for (; it != token.end(); ++it)
373         {
374             iLoop = std::min(iLoop, in[(*it)->pos]->getAs<GenericType>()->getRows());
375         }
376     }
377
378     if (*_piNewLine || (*_piOutputRows) > 1)
379     {
380         (*_piOutputRows) *= iLoop;
381     }
382
383     //if ((token.size() - 1) != inPos.size())
384     //{
385     //    Scierror(999, _("%s: Wrong number of input arguments: at most %d expected.\n"), funcname.data(), token.size() - 1);
386     //    *_piOutputRows = 0;
387     //    return nullptr;
388     //}
389
390     std::wostringstream oFirstOutput;
391     for (int j = 0; j < iLoop; j++)
392     {
393         //copy the 0th token
394         TokenDef* f = token.front();
395         oFirstOutput << f->pwstToken;
396
397         //start at 1, the 0th is always without %
398         std::list<TokenDef*>::iterator it = std::next(token.begin());
399         for (; it != token.end(); ++it)
400         {
401             TokenDef* tok = *it;
402             switch (tok->outputType)
403             {
404                 case InternalType::ScilabDouble:
405                 {
406                     wchar_t pwstTemp[bsiz];
407                     double dblVal = in[tok->pos]->getAs<Double>()->get(j, tok->col);
408
409                     if (std::isfinite(dblVal))
410                     {
411                         if (tok->widthStar)
412                         {
413                             if (tok->precStar)
414                             {
415                                 os_swprintf(pwstTemp, bsiz, tok->pwstToken, tok->width, tok->prec, dblVal);
416                             }
417                             else
418                             {
419                                 os_swprintf(pwstTemp, bsiz, tok->pwstToken, tok->width, dblVal);
420                             }
421                         }
422                         else
423                         {
424                             if (tok->precStar)
425                             {
426                                 os_swprintf(pwstTemp, bsiz, tok->pwstToken, tok->prec, dblVal);
427                             }
428                             else
429                             {
430                                 os_swprintf(pwstTemp, bsiz, tok->pwstToken, dblVal);
431                             }
432                         }
433                     }
434                     else
435                     {
436                         wchar_t* newToken = addl(tok);
437
438                         if (std::isnan(dblVal))
439                         {
440                             os_swprintf(pwstTemp, bsiz, newToken, NanString);
441                         }
442                         else if (std::signbit(dblVal))
443                         {
444                             os_swprintf(pwstTemp, bsiz, newToken, NegInfString);
445                         }
446                         else
447                         {
448                             os_swprintf(pwstTemp, bsiz, newToken, InfString);
449                         }
450
451                         delete[] newToken;
452                     }
453
454                     oFirstOutput << pwstTemp;
455                     break;
456                 }
457                 case InternalType::ScilabInt32:
458                 {
459                     wchar_t pwstTemp[bsiz];
460                     double dblVal = in[tok->pos]->getAs<Double>()->get(j, tok->col);
461                     int iVal = (int)dblVal;
462                     if (std::isfinite(dblVal))
463                     {
464                         if (tok->widthStar)
465                         {
466                             if (tok->precStar)
467                             {
468                                 os_swprintf(pwstTemp, bsiz, tok->pwstToken, tok->width, tok->prec, iVal);
469                             }
470                             else
471                             {
472                                 os_swprintf(pwstTemp, bsiz, tok->pwstToken, tok->width, iVal);
473                             }
474                         }
475                         else
476                         {
477                             if (tok->precStar)
478                             {
479                                 os_swprintf(pwstTemp, bsiz, tok->pwstToken, tok->prec, iVal);
480                             }
481                             else
482                             {
483                                 os_swprintf(pwstTemp, bsiz, tok->pwstToken, iVal);
484                             }
485                         }
486                     }
487                     else
488                     {
489                         wchar_t* newToken = addl(tok);
490
491                         if (std::isnan(dblVal))
492                         {
493                             os_swprintf(pwstTemp, bsiz, newToken, NanString);
494                         }
495                         else
496                         {
497                             if (std::signbit(dblVal))
498                             {
499                                 os_swprintf(pwstTemp, bsiz, newToken, NegInfString);
500                             }
501                             else
502                             {
503                                 os_swprintf(pwstTemp, bsiz, newToken, InfString);
504                             }
505                         }
506
507                         delete[] newToken;
508                     }
509
510                     oFirstOutput << pwstTemp;
511                     break;
512                 }
513                 case InternalType::ScilabUInt32:
514                 {
515                     wchar_t pwstTemp[bsiz];
516                     double dblVal = in[tok->pos]->getAs<Double>()->get(j, tok->col);
517                     unsigned int iVal = (unsigned int)dblVal;
518
519                     if (std::isfinite(dblVal))
520                     {
521                         if (tok->widthStar)
522                         {
523                             if (tok->precStar)
524                             {
525                                 os_swprintf(pwstTemp, bsiz, tok->pwstToken, tok->width, tok->prec, iVal);
526                             }
527                             else
528                             {
529                                 os_swprintf(pwstTemp, bsiz, tok->pwstToken, tok->width, iVal);
530                             }
531                         }
532                         else
533                         {
534                             if (tok->precStar)
535                             {
536                                 os_swprintf(pwstTemp, bsiz, tok->pwstToken, tok->prec, iVal);
537                             }
538                             else
539                             {
540                                 os_swprintf(pwstTemp, bsiz, tok->pwstToken, iVal);
541                             }
542                         }
543                     }
544                     else
545                     {
546                         wchar_t* newToken = addl(tok);
547
548                         if (std::isnan(dblVal))
549                         {
550                             os_swprintf(pwstTemp, bsiz, newToken, NanString);
551                         }
552                         else
553                         {
554                             if (std::signbit(dblVal))
555                             {
556                                 os_swprintf(pwstTemp, bsiz, newToken, NegInfString);
557                             }
558                             else
559                             {
560                                 os_swprintf(pwstTemp, bsiz, newToken, InfString);
561                             }
562                         }
563
564                         delete[] newToken;
565                     }
566
567                     oFirstOutput << pwstTemp;
568                     break;
569                 }
570                 case InternalType::ScilabString:
571                 {
572                     wchar_t* pwstStr = nullptr;
573
574                     InternalType* it = in[tok->pos];
575                     if (it->isDouble() && std::isnan(it->getAs<types::Double>()->get(0)))
576                     {
577                         pwstStr = NanString;
578                     }
579                     else if (it->isDouble() && std::isfinite(it->getAs<types::Double>()->get(0)) == false)
580                     {
581                         if (std::signbit(it->getAs<types::Double>()->get(0)))
582                         {
583                             pwstStr = NegInfString;
584                         }
585                         else
586                         {
587                             pwstStr = InfString;
588                         }
589                     }
590                     else
591                     {
592                         pwstStr = it->getAs<types::String>()->get(j, tok->col);
593                     }
594
595                     int posC = (int)wcscspn(tok->pwstToken, L"c");
596                     int posS = (int)wcscspn(tok->pwstToken, L"s");
597
598                     if (posS == 0 || posC == 0)
599                     {
600                         *_piOutputRows = 0;
601                         return nullptr;
602                     }
603
604                     bool bC = posC < posS;
605                     int len = 1;
606                     if (tok->prec)
607                     {
608                         if (bC == false)
609                         {
610                             len = std::min(std::abs(tok->prec), (int)wcslen(pwstStr));
611                         }
612                     }
613                     else
614                     {
615                         if (bC == false)
616                         {
617                             len = (int)wcslen(pwstStr);
618                         }
619                     }
620
621                     int tokenLen = (int)wcslen(tok->pwstToken);
622                     len += tokenLen;
623                     len = std::max(len, std::abs(tok->width));
624                     //add len of string after token like "%20s>>>" add space for ">>>"
625                     len += (tokenLen - (bC ? posC : posS));
626                     wchar_t* pwstTemp = (wchar_t*)MALLOC((len + 1) * sizeof(wchar_t));
627
628                     if (bC)
629                     {
630                         if (tok->widthStar)
631                         {
632                             os_swprintf(pwstTemp, len + 1, tok->pwstToken, tok->width, pwstStr[0]);
633                         }
634                         else
635                         {
636                             os_swprintf(pwstTemp, len + 1, tok->pwstToken, pwstStr[0]);
637                         }
638                     }
639                     else
640                     {
641                         if (tok->widthStar)
642                         {
643                             os_swprintf(pwstTemp, len + 1, tok->pwstToken, tok->width, pwstStr);
644                         }
645                         else
646                         {
647                             os_swprintf(pwstTemp, len + 1, tok->pwstToken, pwstStr);
648                         }
649                     }
650
651                     oFirstOutput << pwstTemp;
652                     FREE(pwstTemp);
653                     break;
654                 }
655                 default:
656                     // management of %%
657                     oFirstOutput << tok->pwstToken;
658                     break;
659             }
660         }
661     }
662
663     pwstFirstOutput = os_wcsdup((wchar_t*)oFirstOutput.str().c_str());
664
665     for (auto& tok : token)
666     {
667         delete[] tok->pwstToken;
668         delete tok;
669     }
670
671     pwstOutput = (wchar_t**)MALLOC((*_piOutputRows) * sizeof(wchar_t*));
672
673     size_t iLen = wcslen(pwstFirstOutput);
674     int iStart = 0;
675     int j = 0;
676     for (int i = 0; i < iLen; i++)
677     {
678         if (pwstFirstOutput[i] == L'\n')
679         {
680             int iSize = i - iStart;
681             pwstOutput[j] = (wchar_t*)MALLOC(sizeof(wchar_t) * (iSize + 1));
682             wcsncpy(pwstOutput[j], pwstFirstOutput + iStart, iSize);
683             pwstOutput[j][iSize] = L'\0';
684             iStart = i + 1;
685             j++;
686         }
687     }
688
689     if (j == (*_piOutputRows) - 1)
690     {
691         pwstOutput[j] = os_wcsdup(pwstFirstOutput + iStart);
692     }
693
694     FREE(pwstFirstOutput);
695     return pwstOutput;
696 }
697 /*--------------------------------------------------------------------------*/
698 /*--------------------------------------------------------------------------*/
699 // replace "\\n" "\\r" "\\t" "\\r\\n" by '\n' '\r' '\t' '\n'
700 // count number of lines
701 // indicate if one '\n' is at the end of string
702 static wchar_t* replaceAndCountLines(const wchar_t* _pwstInput, int* _piLines, int* _piNewLine)
703 {
704     size_t iInputLen = wcslen(_pwstInput);
705     wchar_t* pwstFirstOutput = (wchar_t*)MALLOC(sizeof(wchar_t) * (iInputLen + 1));
706
707     int iPos = 0;
708     *_piLines = 1;
709
710     for (int i = 0; i < iInputLen; i++)
711     {
712         if (_pwstInput[i] == L'\\')
713         {
714             if (iInputLen == i + 1)
715             {
716                 continue;
717             }
718
719             switch (_pwstInput[i + 1])
720             {
721                 case L'n':
722                     pwstFirstOutput[iPos++] = L'\n';
723                     (*_piLines)++;
724                     i++;
725                     break;
726                 case L'r':
727                     if (iInputLen > i + 3 && _pwstInput[i + 2] == L'\\' && _pwstInput[i + 3] == L'n')
728                     {
729                         pwstFirstOutput[iPos++] = L'\n';
730                         (*_piLines)++;
731                         i += 3;
732                     }
733                     else
734                     {
735                         pwstFirstOutput[iPos++] = L'\r';
736                         i++;
737                     }
738                     break;
739                 case L't':
740                     pwstFirstOutput[iPos++] = L'\t';
741                     i++;
742                     break;
743                 case L'\\':
744                     pwstFirstOutput[iPos++] = L'\\';
745                     i++;
746                     break;
747                 default:
748                     break;
749             }
750         }
751         else
752         {
753             pwstFirstOutput[iPos++] = _pwstInput[i];
754         }
755     }
756
757     // do not count '\n' if it's at the end of string
758     // it will be manage by piNewLine
759     if (pwstFirstOutput[iPos - 1] == '\n')
760     {
761         (*_piLines)--;
762         (*_piNewLine) = 1;
763     }
764
765     pwstFirstOutput[iPos] = 0;
766     return pwstFirstOutput;
767 }
768 /*--------------------------------------------------------------------------*/
769 wchar_t* addl(TokenDef* token)
770 {
771     //replace %s or %c by %ls or %lc to wide char compatibility
772     int iPos = token->typePos;
773     int sizeTotal = (int)wcslen(token->pwstToken);
774     wchar_t* pwstToken = new wchar_t[sizeTotal + 2];
775
776     wcsncpy(pwstToken, token->pwstToken, iPos);
777     pwstToken[iPos] = L'l';
778     pwstToken[iPos + 1] = L's';
779     wcsncpy(&pwstToken[iPos + 2], token->pwstToken + iPos + 1, sizeTotal - (iPos + 1));
780     pwstToken[sizeTotal + 1] = L'\0';
781
782     return pwstToken;
783 }
784 /*--------------------------------------------------------------------------*/
785 void updatel(TokenDef* token)
786 {
787     wchar_t* newToken = addl(token);
788     delete[] token->pwstToken;
789     token->pwstToken = newToken;
790 }