2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2010 - DIGITEO - Antoine ELIAS
4 * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
5 * Copyright (C) 2013 - Scilab Enterprises - Cedric Delamarre
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
20 #include "scilab_sprintf.hxx"
22 using namespace types;
27 #include "sci_malloc.h"
28 #include "localization.h"
29 #include "charEncoding.h"
30 #include "os_string.h"
32 #include "os_string.h"
35 #define NanString L"Nan"
36 #define InfString L"Inf"
37 #define NegInfString L"-Inf"
39 static wchar_t* replaceAndCountLines(const wchar_t* _pwstInput, int* _piLines, int* _piNewLine);
40 static wchar_t* addl(TokenDef* token);
41 static void updatel(TokenDef* token);
42 wchar_t** scilab_sprintf(const char* _pstName, const wchar_t* _pwstInput, typed_list &in, ArgumentPosition* _pArgs, int _iArgsCount, int* _piOutputRows, int* _piNewLine)
44 /* Force Windows display to have two-digit exponent. */
46 _set_output_format(_TWO_DIGIT_EXPONENT);
48 wchar_t** pwstOutput = NULL;
49 wchar_t* pwstFirstOutput = NULL;
53 //\n \n\r \r \t to string
54 //find number of lines
55 // replace \\n \\t... by \n \t...
56 pwstFirstOutput = replaceAndCountLines(_pwstInput, _piOutputRows, _piNewLine);
58 //no arg, just return _pwstInput value
61 //store all sub parts of the input string
62 //for the input string "bla1 %s bla2 %d bla3"
64 //pwstToken[0] : "bla1 "
65 //pwstToken[1] : "%s bla2 "
66 //pwstToken[2] : "%d bla3"
73 TokenDef* pToken = new TokenDef[_iArgsCount + 1];
74 wchar_t* pwstStart = pwstFirstOutput;
77 bool bPercentPercent = false;
81 wchar_t* pwstEnd = wcsstr(pwstStart + (iToken == 0 ? 0 : 1), L"%");
82 iStart = pwstStart - pwstFirstOutput;
83 bPercentPercent = false;
86 if (iToken && pwstStart[1] == L'%')
89 pwstEnd = wcsstr(pwstEnd + 1, L"%");
93 iEnd = wcslen(pwstFirstOutput);
98 iEnd = pwstEnd - pwstFirstOutput;
103 bPercentPercent = true;
107 iEnd = pwstEnd - pwstFirstOutput;
113 iEnd = wcslen(pwstFirstOutput);
117 pToken[iToken].pwstToken = new wchar_t[iEnd - iStart + 1];
118 wcsncpy(pToken[iToken].pwstToken, pwstFirstOutput + iStart, iEnd - iStart);
119 pToken[iToken].pwstToken[iEnd - iStart] = L'\0';
120 pToken[iToken].outputType = InternalType::ScilabNull;
122 //identify destination type
123 //format : %[flags][width][.precision][length]specifier
124 //pToken[iToken].pwstToken
127 wchar_t* pwstPercent = wcsstr(pToken[iToken].pwstToken, L"%");
128 if (pwstPercent != NULL && bPercentPercent == false)
131 if (*(pwstPercent + 1) == L'-' ||
132 *(pwstPercent + 1) == L'+' ||
133 *(pwstPercent + 1) == L' ' ||
134 *(pwstPercent + 1) == L'#' ||
135 *(pwstPercent + 1) == L'0')
141 pToken[iToken].width = -1;
142 if (*(pwstPercent + 1) == L'*')
149 if (iswdigit(*(pwstPercent + 1)))
151 pToken[iToken].width = os_wtoi(pwstPercent + 1);
152 while (iswdigit(*(pwstPercent + 1)))
159 //looking for precision
160 pToken[iToken].prec = -1;
161 if (*(pwstPercent + 1) == L'.')
165 if (iswdigit(*(pwstPercent + 1)))
167 pToken[iToken].prec = os_wtoi(pwstPercent + 1);
168 while (iswdigit(*(pwstPercent + 1)))
176 if (*(pwstPercent + 1) == L'h' ||
177 *(pwstPercent + 1) == L'l' ||
178 *(pwstPercent + 1) == L'L')
180 pToken[iToken].bLengthFlag = true;
185 pToken[iToken].bLengthFlag = false;
188 wchar_t wcType = *(pwstPercent + 1);
189 pToken[iToken].typePos = (pwstPercent + 1) - pToken[iToken].pwstToken;
192 case L'i' : //integer
193 case L'd' : //integer
195 case L'u' : //unsigned
198 if (_pArgs[iPosArg].type != InternalType::ScilabDouble)
200 Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), _pstName);
205 pToken[iToken].outputType = InternalType::ScilabInt32;
212 case L'g' : //shorter between float or exp
213 case L'G' : //shorter between float or EXP
214 if (_pArgs[iPosArg].type != InternalType::ScilabDouble)
216 Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), _pstName);
221 pToken[iToken].outputType = InternalType::ScilabDouble;
226 if (_pArgs[iPosArg].type != InternalType::ScilabString)
228 Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), _pstName);
233 if (pToken[iToken].bLengthFlag == false)
235 updatel(&(pToken[iToken]));
238 pToken[iToken].outputType = InternalType::ScilabString;
251 FREE(pwstFirstOutput);
252 pwstFirstOutput = NULL;
256 if (strcmp(_pstName, "mfprintf") == 0)
263 iLoop = in[iFirstArg]->getAs<GenericType>()->getRows();
264 for (int i = iFirstArg + 1 ; i < in.size() ; i++)
266 iLoop = std::min(iLoop, in[i]->getAs<GenericType>()->getRows());
270 if (*_piNewLine || (*_piOutputRows) > 1)
272 (*_piOutputRows) *= iLoop;
275 std::wostringstream oFirstOutput;
276 for (int j = 0 ; j < iLoop ; j++)
279 oFirstOutput << pToken[0].pwstToken;
281 //start at 1, the 0th is always without %
282 for (int i = 1 ; i < _iArgsCount + 1 ; i++)
285 if (pToken[i].outputType == InternalType::ScilabDouble)
287 wchar_t pwstTemp[bsiz];
288 double dblVal = in[_pArgs[iPosArg].iArg]->getAs<Double>()->get(j, _pArgs[iPosArg].iPos);
292 os_swprintf(pwstTemp, bsiz, pToken[i].pwstToken, dblVal);
296 wchar_t* newToken = addl(&pToken[i]);
299 os_swprintf(pwstTemp, bsiz, newToken, NanString);
301 else if (std::signbit(dblVal))
303 os_swprintf(pwstTemp, bsiz, newToken, NegInfString);
307 os_swprintf(pwstTemp, bsiz, newToken, InfString);
313 oFirstOutput << pwstTemp;
315 else if (pToken[i].outputType == InternalType::ScilabInt32)
317 wchar_t pwstTemp[bsiz];
318 double dblVal = in[_pArgs[iPosArg].iArg]->getAs<Double>()->get(j, _pArgs[iPosArg].iPos);
319 os_swprintf(pwstTemp, bsiz, pToken[i].pwstToken, (int)dblVal);
321 oFirstOutput << pwstTemp;
323 else if (pToken[i].outputType == InternalType::ScilabString)
325 wchar_t* pwstStr = NULL;
327 if (in[iPosArg + 1]->isDouble() && ISNAN(in[iPosArg + 1]->getAs<types::Double>()->get(0)))
331 else if (in[iPosArg + 1]->isDouble() && finite(in[iPosArg + 1]->getAs<types::Double>()->get(0)) == false)
333 if (std::signbit(in[iPosArg + 1]->getAs<types::Double>()->get(0)))
335 pwstStr = NegInfString;
344 pwstStr = in[_pArgs[iPosArg].iArg]->getAs<types::String>()->get(j, _pArgs[iPosArg].iPos);
347 int posC = (int)wcscspn(pToken[i].pwstToken, L"c");
348 int posS = (int)wcscspn(pToken[i].pwstToken, L"s");
350 if (posS == 0 || posC == 0)
356 bool bC = posC < posS;
358 if (pToken[i].prec == -1)
362 len = (int)wcslen(pwstStr);
369 len = std::min(pToken[i].prec, (int)wcslen(pwstStr));
373 int tokenLen = (int)wcslen(pToken[i].pwstToken);
375 len = std::max(len, pToken[i].width);
376 //add len of string after token like "%20s>>>" add space for ">>>"
377 len += (tokenLen - (bC ? posC : posS));
378 wchar_t* pwstTemp = (wchar_t*)MALLOC((len + 1) * sizeof(wchar_t));
382 os_swprintf(pwstTemp, len + 1, pToken[i].pwstToken, pwstStr[0]);
386 os_swprintf(pwstTemp, len + 1, pToken[i].pwstToken, pwstStr);
389 oFirstOutput << pwstTemp;
396 oFirstOutput << pToken[i].pwstToken;
401 pwstFirstOutput = os_wcsdup((wchar_t*)oFirstOutput.str().c_str());
404 pwstOutput = (wchar_t**)MALLOC((*_piOutputRows) * sizeof(wchar_t*));
406 size_t iLen = wcslen(pwstFirstOutput);
409 for (int i = 0 ; i < iLen ; i++)
411 if (pwstFirstOutput[i] == L'\n')
413 int iSize = i - iStart;
414 pwstOutput[j] = (wchar_t*)MALLOC(sizeof(wchar_t) * (iSize + 1));
415 wcsncpy(pwstOutput[j], pwstFirstOutput + iStart, iSize);
416 pwstOutput[j][iSize] = L'\0';
422 if (j == (*_piOutputRows) - 1)
424 pwstOutput[j] = os_wcsdup(pwstFirstOutput + iStart);
427 FREE(pwstFirstOutput);
430 /*--------------------------------------------------------------------------*/
431 // replace "\\n" "\\r" "\\t" "\\r\\n" by '\n' '\r' '\t' '\n'
432 // count number of lines
433 // indicate if one '\n' is at the end of string
434 static wchar_t* replaceAndCountLines(const wchar_t* _pwstInput, int* _piLines, int* _piNewLine)
436 size_t iInputLen = wcslen(_pwstInput);
437 wchar_t* pwstFirstOutput = (wchar_t*)MALLOC(sizeof(wchar_t) * (iInputLen + 1));
442 for (int i = 0 ; i < iInputLen ; i++)
444 if (_pwstInput[i] == L'\\')
446 if (iInputLen == i + 1)
451 switch (_pwstInput[i + 1])
454 pwstFirstOutput[iPos++] = L'\n';
459 if (iInputLen > i + 3 && _pwstInput[i + 2] == L'\\' && _pwstInput[i + 3] == L'n')
461 pwstFirstOutput[iPos++] = L'\n';
467 pwstFirstOutput[iPos++] = L'\r';
472 pwstFirstOutput[iPos++] = L'\t';
476 pwstFirstOutput[iPos++] = L'\\';
485 pwstFirstOutput[iPos++] = _pwstInput[i];
489 // do not count '\n' if it's at the end of string
490 // it will be manage by piNewLine
491 if (pwstFirstOutput[iPos - 1] == '\n')
497 pwstFirstOutput[iPos] = 0;
498 return pwstFirstOutput;
500 /*--------------------------------------------------------------------------*/
501 wchar_t* addl(TokenDef* token)
503 //replace %s or %c by %ls or %lc to wide char compatibility
504 int iPos = token->typePos;
505 int sizeTotal = (int)wcslen(token->pwstToken);
506 wchar_t* pwstToken = new wchar_t[sizeTotal + 2];
508 wcsncpy(pwstToken, token->pwstToken, iPos);
509 pwstToken[iPos] = L'l';
510 pwstToken[iPos + 1] = L's';
511 wcsncpy(&pwstToken[iPos + 2], token->pwstToken + iPos + 1, sizeTotal - (iPos + 1));
512 pwstToken[sizeTotal + 1] = L'\0';
516 /*--------------------------------------------------------------------------*/
517 void updatel(TokenDef* token)
519 wchar_t* newToken = addl(token);
520 delete[] token->pwstToken;
521 token->pwstToken = newToken;