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