bug #16370 fixed - msprintf did not handle dollars 54/21454/8
Clément DAVID [Fri, 10 Apr 2020 13:37:30 +0000 (15:37 +0200)]
Using the `%2$f` format, the number between the % and the $ signs was
not checked on the first pass. This change detect a valid positive
integer and not anything else until the $.

Change-Id: I6636367b96023883911eeca6291370c270b381d0

scilab/CHANGES.md
scilab/modules/output_stream/src/cpp/scilab_sprintf.cpp
scilab/modules/output_stream/tests/nonreg_tests/bug_16370.tst [new file with mode: 0644]
scilab/modules/string/includes/os_wtoi.h
scilab/modules/string/src/cpp/os_wtoi.cpp

index 0c16a53..cea824a 100644 (file)
@@ -271,6 +271,7 @@ Bug Fixes
 * [#16365](https://bugzilla.scilab.org/16365): `median(m,"r")` and `median(m,"c")` yielded wrong results (6.1.0 regression)
 * [#16366](https://bugzilla.scilab.org/16366): `plot([0 1], ":")` plotted a dash-dotted curve instead of a dotted one.
 * [#16369](https://bugzilla.scilab.org/16369): Right divisions / involving one or two sparse numerical matrices were no longer supported.
+* [#16370](https://bugzilla.scilab.org/16370): `msprintf()` did not handle LaTeX dollars anymore.
 * [#16397](https://bugzilla.scilab.org/16397): display of long (real) column vectors was slow (regression).
 * [#16399](https://bugzilla.scilab.org/16399): `mtlb_zeros([])` was crashing Scilab.
 * [#16401](https://bugzilla.scilab.org/16401): global `external_object_java` class was crashing Scilab.
index 23b31e7..0edc074 100644 (file)
  *
  */
 
-#include <stdio.h>
+#include "scilab_sprintf.hxx"
+#include "double.hxx"
+#include "string.hxx"
+#include "types.hxx"
 #include <cmath>
 #include <list>
 #include <numeric>
-#include "types.hxx"
-#include "double.hxx"
-#include "string.hxx"
-#include "scilab_sprintf.hxx"
+#include <stdio.h>
+#include <string>
 
 extern "C"
 {
 #include "Scierror.h"
-#include "sci_malloc.h"
-#include "localization.h"
 #include "charEncoding.h"
+#include "localization.h"
 #include "os_string.h"
 #include "os_wtoi.h"
-#include "os_string.h"
+#include "sci_malloc.h"
 }
 
 static wchar_t* replaceAndCountLines(const wchar_t* _pwstInput, int* _piLines, int* _piNewLine);
@@ -46,7 +46,7 @@ static void print_nan_or_inf(wchar_t* pwstTemp, double dblVal, const wchar_t* to
 #define InfString L"Inf"
 #define NegInfString L"-Inf"
 
-wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput, types::typed_list &in, int* _piOutputRows, int* _piNewLine)
+wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput, types::typed_list& in, int* _piOutputRows, int* _piNewLine)
 {
     wchar_t** pwstOutput = nullptr;
     int rhs = static_cast<int>(in.size());
@@ -61,7 +61,7 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
     }
 
     //compute couple (index in input and col number ).
-    std::list<std::pair<int, int> > inPos;
+    std::list<std::pair<int, int>> inPos;
     for (int i = first; i < in.size(); ++i)
     {
         types::GenericType* gt = in[i]->getAs<types::GenericType>();
@@ -72,7 +72,7 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
         }
     }
 
-    std::list<std::pair<int, int> >::iterator itPos = inPos.begin();
+    std::list<std::pair<int, int>>::iterator itPos = inPos.begin();
 
     //\n \n\r \r \t to string
     //find number of lines
@@ -132,10 +132,13 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
         if (end > 0)
         {
             wchar_t* pwstDollar = wcsstr(pwstStart + (token.size() == 0 ? 0 : 1), L"$");
-            if (pwstDollar != nullptr && (pwstDollar - pwstFirstOutput) < end)
+            // there should be at least one char after the $ sign
+            if (pwstDollar != nullptr && (pwstDollar - pwstFirstOutput + 1) < end)
             {
-                int index = os_wtoi(pwstStart + 1);
-                if (index > 0)
+                std::size_t remaining;
+                int index = os_wtoi(pwstStart + 1, &remaining);
+                // decode a positive integer number until the $ sign
+                if (index > 0 && pwstStart + 1 + remaining == pwstDollar)
                 {
                     argumentPos.push_back(index - 1);
                     start = pwstDollar - pwstFirstOutput;
@@ -154,19 +157,18 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
         wchar_t* pwstPercent = wcsstr(tok->pwstToken, L"%");
         if (pwstPercent != nullptr && percentpercent == false)
         {
-            int offset = 1;
+            size_t offset = 0;
             //looking for flags
-            if (*(pwstPercent + 1) == L'-' ||
-                    *(pwstPercent + 1) == L'+' ||
+            if (*(pwstPercent + 1) == L'+' ||
                     *(pwstPercent + 1) == L' ' ||
                     *(pwstPercent + 1) == L'#' ||
                     *(pwstPercent + 1) == L'0')
             {
-                offset = 2;
+                offset++;
             }
 
             //looking for width
-            if (*(pwstPercent + offset) == L'*')
+            if (*(pwstPercent + offset + 1) == L'*')
             {
                 if (itPos == inPos.end())
                 {
@@ -184,7 +186,6 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
                     return nullptr;
                 }
 
-
                 types::Double* dbl = in[p]->getAs<types::Double>();
                 tok->width = static_cast<int>(dbl->get()[0]);
                 tok->widthStar = true;
@@ -194,30 +195,24 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
             else
             {
                 //number
-                if (iswdigit(*(pwstPercent + offset)))
-                {
-                    tok->width = os_wtoi(pwstPercent + 1);
-                    while (iswdigit(*(pwstPercent + offset)))
-                    {
-                        pwstPercent++;
-                    }
-                }
+                size_t previousOffset = offset;
+                wchar_t* pwstWidth = pwstPercent + offset + 1;
+                tok->width = os_wtoi(pwstWidth, &offset);
+                offset = previousOffset + offset;
             }
 
-            pwstPercent += (offset - 1);
+            pwstPercent += offset;
 
             //looking for precision
             if (*(pwstPercent + 1) == L'.')
             {
                 pwstPercent++;
+                offset = 0;
+                tok->prec = os_wtoi(pwstPercent + 1, &offset);
 
-                if (iswdigit(*(pwstPercent + 1)))
+                if (offset > 0)
                 {
-                    tok->prec = os_wtoi(pwstPercent + 1);
-                    while (iswdigit(*(pwstPercent + 1)))
-                    {
-                        pwstPercent++;
-                    }
+                    pwstPercent += offset;
                 }
                 else if (*(pwstPercent + 1) == L'*')
                 {
@@ -463,7 +458,7 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
     for (int j = 0; j < iLoop; ++j)
     {
         wchar_t* tmpToken = NULL;
-        for (auto it = token.begin(); it != token.end();/*no inc*/)
+        for (auto it = token.begin(); it != token.end(); /*no inc*/)
         {
             TokenDef* tok = *it;
             wchar_t* token = tmpToken ? tmpToken : tok->pwstToken;
@@ -727,7 +722,7 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput,
         pwstOutput[outputIter++] = os_wcsdup(L"");
     }
 
-    for (auto & tok : token)
+    for (auto& tok : token)
     {
         delete[] tok->pwstToken;
         delete tok;
@@ -878,7 +873,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)
     {
@@ -903,5 +898,4 @@ static void print_nan_or_inf(wchar_t* pwstTemp, double dblVal, const wchar_t* to
     }
 
     delete[] pwstToken;
-
 }
diff --git a/scilab/modules/output_stream/tests/nonreg_tests/bug_16370.tst b/scilab/modules/output_stream/tests/nonreg_tests/bug_16370.tst
new file mode 100644 (file)
index 0000000..2abfb10
--- /dev/null
@@ -0,0 +1,23 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2020 - ESI Group - Clement DAVID
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+//
+// <-- CLI SHELL MODE -->
+// <-- NO CHECK REF -->
+//
+// <-- Non-regression test for bug 16370 -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/show_bug.cgi?id=16370
+//
+// <-- Short Description -->
+// msprintf() did not handle dollars to render LaTeX strings
+
+// should not error !
+msprintf("$\\Large \\alpha=%5.2f$",1)
+
+
+
index 494c8ec..ee9f870 100644 (file)
@@ -19,6 +19,6 @@
 #include <string.h>
 #include "dynlib_string.h"
 
-STRING_IMPEXP int os_wtoi(const wchar_t* pwcsStr);
+STRING_IMPEXP int os_wtoi(const wchar_t* pwcsStr, std::size_t* pos);
 
 #endif /* !__OS_WTOI_H__ */
index ac0d7ef..5ecf65c 100644 (file)
@@ -1,5 +1,6 @@
 /*
  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ *  Copyright (C) 2020 - ESI Group - Clement DAVID
  *  Copyright (C) 2014 - Scilab Enterprises - Cedric Delamarre
  *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
@@ -22,13 +23,33 @@ extern "C"
 #include "os_wtoi.h"
 }
 
-int os_wtoi(const wchar_t *_pwcsSource)
+// similar API to std::stoi but does not throw
+// Adapted from http://tinodidriksen.com/uploads/code/cpp/speed-string-to-int.cpp
+int os_wtoi(const wchar_t* str, std::size_t* pos)
 {
-    std::wstring wstr(_pwcsSource);
-    std::wistringstream wstrm(wstr);
-    int num = 0;
-    wstrm >> num;
-    return num;
+    const wchar_t* p = str;
+    int x = 0;
+    bool neg = false;
+    if (*p == '-')
+    {
+        neg = true;
+        ++p;
+    }
+    while (*p >= '0' && *p <= '9')
+    {
+        x = (x * 10) + (*p - '0');
+        ++p;
+    }
+    if (neg)
+    {
+        x = -x;
+    }
+
+    if (pos)
+    {
+        *pos = p - str;
+    }
+    return x;
 }