output_stream/localization: let msprintf() handle parameter field 64/21364/4
Clément DAVID [Wed, 19 Feb 2020 14:23:52 +0000 (15:23 +0100)]
Change-Id: I142b2bd920bd9134093896396e06d2ec619c6fd4

scilab/modules/output_stream/src/cpp/scilab_sprintf.cpp
scilab/modules/output_stream/tests/unit_tests/msprintf.dia.ref [deleted file]
scilab/modules/output_stream/tests/unit_tests/msprintf.tst

index 85a4c57..b084143 100644 (file)
@@ -18,6 +18,7 @@
 #include <stdio.h>
 #include <cmath>
 #include <list>
+#include <numeric>
 #include "types.hxx"
 #include "double.hxx"
 #include "string.hxx"
@@ -86,12 +87,14 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
 
     wchar_t* pwstStart = pwstFirstOutput;
     bool percentpercent = false;
+    std::vector<int> argumentPos;
 
     while (finish == false)
     {
         wchar_t* pwstEnd = wcsstr(pwstStart + (token.size() == 0 ? 0 : 1), L"%");
         start = pwstStart - pwstFirstOutput;
         percentpercent = false;
+        bool positioned = false;
         if (pwstEnd != nullptr)
         {
             if (token.size() && pwstStart[1] == L'%')
@@ -125,6 +128,19 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
             finish = true;
         }
 
+        // parameter field placeholders; manage "%2$d" field
+        if (end > 0)
+        {
+            wchar_t* pwstDollar = wcsstr(pwstStart + (token.size() == 0 ? 0 : 1), L"$");
+            if (pwstDollar != nullptr && (pwstDollar - pwstFirstOutput) < end)
+            {
+                argumentPos.push_back(os_wtoi(pwstStart + 1) - 1);
+                start = pwstDollar - pwstFirstOutput;
+                pwstFirstOutput[start] = L'%';
+                positioned = true;
+            }
+        }
+
         TokenDef* tok = new TokenDef;
         tok->pwstToken = new wchar_t[end - start + 1];
         wcsncpy(tok->pwstToken, pwstFirstOutput + start, end - start);
@@ -237,6 +253,19 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
             wchar_t wcType = *(pwstPercent + 1);
             tok->typePos = static_cast<int>((pwstPercent + 1) - tok->pwstToken);
 
+            //check numer of input
+            //printf("%f") or printf("%$2", 1) for example
+            if (itPos == inPos.end() || (positioned ? argumentPos.back() + 1 : (*itPos).first) >= in.size())
+            {
+                FREE(pwstFirstOutput);
+                Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
+                *_piOutputRows = 0;
+                return nullptr;
+            }
+
+            int p = positioned ? argumentPos.back() + 1 : (*itPos).first;
+            int c = (*itPos).second;
+
             switch (wcType)
             {
                 case L'i': //integer
@@ -250,8 +279,6 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
                         return nullptr;
                     }
 
-                    int p = (*itPos).first;
-                    int c = (*itPos).second;
                     if (in[p]->getType() != types::InternalType::ScilabDouble)
                     {
                         FREE(pwstFirstOutput);
@@ -309,8 +336,6 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
                         return nullptr;
                     }
 
-                    int p = (*itPos).first;
-                    int c = (*itPos).second;
                     if (in[p]->getType() != types::InternalType::ScilabDouble)
                     {
                         FREE(pwstFirstOutput);
@@ -336,8 +361,6 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
                         return nullptr;
                     }
 
-                    int p = (*itPos).first;
-                    int c = (*itPos).second;
                     if (in[p]->getType() != types::InternalType::ScilabString)
                     {
                         FREE(pwstFirstOutput);
@@ -383,6 +406,49 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
         }
     }
 
+    // parameter field placeholders MUST all be specified
+    if (!argumentPos.empty())
+    {
+        std::vector<int> sortedArgumentPos = argumentPos;
+        std::sort(sortedArgumentPos.begin(), sortedArgumentPos.end());
+        int previous = 0;
+        for (int i = 1; i < sortedArgumentPos.size() && 0 <= previous && previous < 2; ++i)
+        {
+            previous = sortedArgumentPos[i] - sortedArgumentPos[i - 1];
+        }
+        if (previous < 0 || 2 < previous)
+        {
+            Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
+            *_piOutputRows = 0;
+            return nullptr;
+        }
+        if (sortedArgumentPos.back() + 1 != token.size() - 1)
+        {
+            Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
+            *_piOutputRows = 0;
+            return nullptr;
+        }
+        if (argumentPos.size() != token.size() - 1)
+        {
+            Scierror(999, _("%s: Wrong number of input arguments: data doesn't fit with format.\n"), funcname.data());
+            *_piOutputRows = 0;
+            return nullptr;
+        }
+
+        /*
+        // update token's pos
+        for (auto it = token.begin(); it != token.end(); ++it)
+        {
+            TokenDef* tok = *it;
+            if (tok->pos == 0)
+            {
+                continue;
+            }
+            tok->pos = argumentPos[tok->pos - 1] + 1;
+        }
+        */
+    }
+
     // count number of output lines in function of \n and size of input args
     (*_piOutputRows) *= iLoop;
     (*_piOutputRows) += *_piNewLine == 1 ? 0 : 1;
@@ -390,7 +456,7 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
     pwstOutput = (wchar_t**)MALLOC((*_piOutputRows) * sizeof(wchar_t*));
     int outputIter = 0;
     std::wostringstream oFirstOutput;
-    for (int j = 0; j < iLoop; j++)
+    for (int j = 0; j < iLoop; ++j)
     {
         wchar_t* tmpToken = NULL;
         for (auto it = token.begin(); it != token.end();/*no inc*/)
@@ -399,7 +465,7 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
             wchar_t* token = tmpToken ? tmpToken : tok->pwstToken;
             // find LF in token
             wchar_t* lf = wcsstr(token, L"\n");
-            if(lf)
+            if (lf)
             {
                 // create tkoen as part of current token
                 size_t sToken = lf - token;
@@ -624,7 +690,7 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
                 }
             }
 
-            if(lf)
+            if (lf)
             {
                 // write current line
                 pwstOutput[outputIter++] = os_wcsdup((wchar_t*)oFirstOutput.str().c_str());
@@ -635,7 +701,7 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
                 // skip LF
                 tmpToken = ++lf;
                 // if not at the end of token, continue with same token
-                if(static_cast<size_t>(lf - tok->pwstToken) < wcslen(tok->pwstToken))
+                if (static_cast<size_t>(lf - tok->pwstToken) < wcslen(tok->pwstToken))
                 {
                     continue;
                 }
@@ -656,7 +722,7 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
     {
         pwstOutput[outputIter++] = os_wcsdup(L"");
     }
-    
+
     for (auto & tok : token)
     {
         delete[] tok->pwstToken;
@@ -808,7 +874,7 @@ static void replace_ld_lld(TokenDef* token)
 static void print_nan_or_inf(wchar_t* pwstTemp, double dblVal, const wchar_t* token, int pos, int width)
 {
     int sizeTotal = (int)wcslen(token);
-    wchar_t* pwstToken = new wchar_t[sizeTotal + 2]{ 0 };
+    wchar_t* pwstToken = new wchar_t[sizeTotal + 2] { 0 };
 
     if (width)
     {
diff --git a/scilab/modules/output_stream/tests/unit_tests/msprintf.dia.ref b/scilab/modules/output_stream/tests/unit_tests/msprintf.dia.ref
deleted file mode 100644 (file)
index 72f308a..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-// =============================================================================
-// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
-// Copyright (C) 2008 - INRIA
-// Copyright (C) 2013 - Scilab Enterprises - Adeline CARNIS
-//
-//  This file is distributed under the same license as the Scilab package.
-// =============================================================================
-// <-- CLI SHELL MODE -->
-// unit tests for msprintf function
-// =============================================================================
-// format '%f'
-// =============================================================================
-assert_checkequal(msprintf("%f",-35), "-35.000000");
-assert_checkequal(msprintf("%f",35.55), "35.550000");
-assert_checkequal(msprintf("%f",0.00433), "0.004330");
-assert_checkequal(msprintf("%f",0.0000000345456), "0.000000");
-assert_checkequal(msprintf("%f",1112423453), "1112423453.000000");
-assert_checkequal(msprintf("%15f",-35), "     -35.000000");
-assert_checkequal(msprintf("%15f",0.00433), "       0.004330");
-assert_checkequal(msprintf("%15f",0.0000000345456), "       0.000000");
-assert_checkequal(msprintf("%15f",1112423453), "1112423453.000000");
-assert_checkequal(msprintf("%.1f" ,-35), "-35.0");
-assert_checkequal(msprintf("%.0f" ,-35), "-35");
-assert_checkequal(msprintf("%#.0f",-35), "-35.");
-assert_checkequal(msprintf("%.1f" ,0.00433), "0.0");
-assert_checkequal(msprintf("%.15f",0.0000000345456), "0.000000034545600");
-assert_checkequal(msprintf("%.1f" ,11124234534545), "11124234534545.0");
-// format '%g'
-// =============================================================================
-assert_checkequal(msprintf("%g" ,-35), "-35");
-assert_checkequal(msprintf("%g" ,35.55), "35.55");
-assert_checkequal(msprintf("%g" ,35.551234567890), "35.5512");
-assert_checkequal(msprintf("%+g",35.551234567890), "+35.5512");
-assert_checkequal(msprintf("%g" ,0.00433), "0.00433");
-assert_checkequal(msprintf("%g" ,0.0000000345456), "3.45456e-08");
-assert_checkequal(msprintf("%g" ,11124234534545), "1.11242e+13");
-assert_checkequal(msprintf("%15g",-35), "            -35");
-assert_checkequal(msprintf("%15g",0.00433), "        0.00433");
-assert_checkequal(msprintf("%15g",0.0000000345456), "    3.45456e-08");
-assert_checkequal(msprintf("%15g",11124234534545), "    1.11242e+13");
-assert_checkequal(msprintf("%.1g",-35.1), "-4e+01");
-assert_checkequal(msprintf("%.0g",-35.1), "-4e+01");
-assert_checkequal(msprintf("%#.0g",-35.1), "-4.e+01");
-assert_checkequal(msprintf("%#.0G",-35.1), "-4.E+01");
-assert_checkequal(msprintf("%.1g",0.00433), "0.004");
-assert_checkequal(msprintf("%.15g",0.0000000345456), "3.45456e-08");
-assert_checkequal(msprintf("%.1g",11124234534545), "1e+13");
-// format '%e'
-// =============================================================================
-assert_checkequal(msprintf("%e",-35), "-3.500000e+01");
-assert_checkequal(msprintf("%e",35.55), "3.555000e+01");
-assert_checkequal(msprintf("%+e",35.55), "+3.555000e+01");
-assert_checkequal(msprintf("%e",35.551234567890), "3.555123e+01");
-assert_checkequal(msprintf("%e",0.00433), "4.330000e-03");
-assert_checkequal(msprintf("%e",0.0000000345456), "3.454560e-08");
-assert_checkequal(msprintf("%e",11124234534545), "1.112423e+13");
-assert_checkequal(msprintf("%E",11124234534545), "1.112423E+13");
-assert_checkequal(msprintf("%15e",-35), "  -3.500000e+01");
-assert_checkequal(msprintf("%15e",0.00433), "   4.330000e-03");
-assert_checkequal(msprintf("%15e",0.0000000345456), "   3.454560e-08");
-assert_checkequal(msprintf("%+15e",0.0000000345456), "  +3.454560e-08");
-assert_checkequal(msprintf("%15e",11124234534545), "   1.112423e+13");
-assert_checkequal(msprintf("%.1e",-35), "-3.5e+01");
-assert_checkequal(msprintf("%.0e",-35.1), "-4e+01");
-assert_checkequal(msprintf("%.1e",0.00433), "4.3e-03");
-assert_checkequal(msprintf("%.15e",0.0000000345456), "3.454560000000000e-08");
-assert_checkequal(msprintf("%.1e",11124234534545), "1.1e+13");
-// format '%c'
-// =============================================================================
-assert_checkequal(msprintf("%c","t"), "t");
-assert_checkequal(msprintf("%10c","t"), "         t");
-assert_checkequal(msprintf("%10.3c","t"), "         t");
-assert_checkequal(msprintf("%-10c","t"), "t         ");
-// format '%s'
-// =============================================================================
-assert_checkequal(msprintf("%s","text"), "text");
-assert_checkequal(msprintf("%10s","text"), "      text");
-assert_checkequal(msprintf("%10.3s","text"), "       tex");
-assert_checkequal(msprintf("%-10s","text"), "text      ");
-assert_checkequal(msprintf("%s","t"), "t");
-// format '%x'
-// =============================================================================
-assert_checkequal(msprintf("%x",123), "7b");
-assert_checkequal(msprintf("%.10x",123), "000000007b");
-assert_checkequal(msprintf("%x",-123), "ffffff85");
-assert_checkequal(msprintf("%X",-123), "FFFFFF85");
-assert_checkequal(msprintf("%#.3X",12), "0X00C");
-// format '%o'
-// =============================================================================
-assert_checkequal(msprintf("%015o",-12), "000037777777764");
-// Vectorisation
-// =============================================================================
-nb_row = 10000;
-// test 1
-A = "row "+string(1:nb_row)';
-B = 100*rand(nb_row,3);
-C = msprintf("%10s => %08.4f %08.4f %08.4f\n",A,B);
-assert_checkequal(size(C), [nb_row,1]);
-for i=1:nb_row
-    assert_checkequal(length(C(i)), 40);
-end
-// test 2
-B = 100*rand(nb_row,2);
-C = 100*rand(nb_row,1);
-D = msprintf("%10s => %08.4f %08.4f %08.4f\n",A,B,C);
-assert_checkequal(size(D), [nb_row,1]);
-for i=1:nb_row
-    assert_checkequal(size(D), [nb_row,1]);
-end
-// test 3
-B = 100*rand(nb_row,1);
-C = 100*rand(nb_row,1);
-D = 100*rand(nb_row,1);
-E = msprintf("%10s => %08.4f %08.4f %08.4f\n",A,B,C,D);
-assert_checkequal(size(E), [nb_row,1]);
-for i=1:nb_row
-    assert_checkequal(size(E), [nb_row,1]);
-end
-// test 4
-B = 100*rand(nb_row,1);
-assert_checkfalse(execstr("msprintf(""%10s => %08.4f %08.4f %08.4f\n"",A,B,B);","errcatch")     == 0);
-refMsg = msprintf(_("%s: Wrong number of input arguments: data doesn''t fit with format.\n"), "msprintf");
-assert_checkerror("msprintf(""%10s => %08.4f %08.4f %08.4f\n"",A,B,B);", refMsg);
-// No arg
-assert_checkfalse(execstr("msprintf();","errcatch")     == 0);
-refMsg = msprintf(_("%s: Wrong number of input arguments: at least %d expected.\n"), "msprintf", 1);
-assert_checkerror("msprintf();", refMsg);
-// overload: Arg not managed
-s=poly(0,"s");
-p=1+s+2*s^2;
-assert_checkfalse(execstr("msprintf(""plop"",p);","errcatch") <> 999);
-assert_checkfalse(execstr("msprintf(""%s %s"",""plop"");","errcatch")     <> 999);
-refMsg = msprintf(_("%s: Wrong number of input arguments: data doesn''t fit with format.\n"), "msprintf");
-assert_checkerror("msprintf(""%s %s"",""plop"");", refMsg);
index 15c48b8..9fddf26 100644 (file)
@@ -7,6 +7,7 @@
 // =============================================================================
 
 // <-- CLI SHELL MODE -->
+// <-- NO CHECK REF -->
 
 // unit tests for msprintf function
 // =============================================================================
@@ -198,3 +199,14 @@ assert_checkfalse(execstr("msprintf(""%s %s"",""plop"");","errcatch")     <> 999
 refMsg = msprintf(_("%s: Wrong number of input arguments: data doesn''t fit with format.\n"), "msprintf");
 assert_checkerror("msprintf(""%s %s"",""plop"");", refMsg);
 
+// parameter field
+// =============================================================================
+
+assert_checkequal(msprintf("%1$d",1), "1");
+assert_checkequal(msprintf("%1$d%2$d", 1, 2), "12");
+assert_checkequal(msprintf("%2$d%1$d", 1, 2), "21");
+
+refMsg = msprintf(_("%s: Wrong number of input arguments: data doesn''t fit with format.\n"), "msprintf");
+assert_checkerror("msprintf(""%2$d"", 1);", refMsg);
+assert_checkerror("msprintf(""%d%1$d"", 1);", refMsg);
+assert_checkerror("msprintf(""%1$d%d"", 1);", refMsg);