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