From eaf56590b771af5364b3a5479203fac0be6406e2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Cl=C3=A9ment=20DAVID?= Date: Fri, 10 Apr 2020 15:37:30 +0200 Subject: [PATCH] bug #16370 fixed - msprintf did not handle dollars 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 | 1 + .../output_stream/src/cpp/scilab_sprintf.cpp | 72 +++++++++----------- .../output_stream/tests/nonreg_tests/bug_16370.tst | 23 +++++++ scilab/modules/string/includes/os_wtoi.h | 2 +- scilab/modules/string/src/cpp/os_wtoi.cpp | 33 +++++++-- 5 files changed, 85 insertions(+), 46 deletions(-) create mode 100644 scilab/modules/output_stream/tests/nonreg_tests/bug_16370.tst diff --git a/scilab/CHANGES.md b/scilab/CHANGES.md index 0c16a53..cea824a 100644 --- a/scilab/CHANGES.md +++ b/scilab/CHANGES.md @@ -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. diff --git a/scilab/modules/output_stream/src/cpp/scilab_sprintf.cpp b/scilab/modules/output_stream/src/cpp/scilab_sprintf.cpp index 23b31e7..0edc074 100644 --- a/scilab/modules/output_stream/src/cpp/scilab_sprintf.cpp +++ b/scilab/modules/output_stream/src/cpp/scilab_sprintf.cpp @@ -15,24 +15,24 @@ * */ -#include +#include "scilab_sprintf.hxx" +#include "double.hxx" +#include "string.hxx" +#include "types.hxx" #include #include #include -#include "types.hxx" -#include "double.hxx" -#include "string.hxx" -#include "scilab_sprintf.hxx" +#include +#include 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(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 > inPos; + std::list> inPos; for (int i = first; i < in.size(); ++i) { types::GenericType* gt = in[i]->getAs(); @@ -72,7 +72,7 @@ wchar_t** scilab_sprintf(const std::string& funcname, const wchar_t* _pwstInput, } } - std::list >::iterator itPos = inPos.begin(); + std::list>::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(); tok->width = static_cast(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 index 0000000..2abfb10 --- /dev/null +++ b/scilab/modules/output_stream/tests/nonreg_tests/bug_16370.tst @@ -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) + + + diff --git a/scilab/modules/string/includes/os_wtoi.h b/scilab/modules/string/includes/os_wtoi.h index 494c8ec..ee9f870 100644 --- a/scilab/modules/string/includes/os_wtoi.h +++ b/scilab/modules/string/includes/os_wtoi.h @@ -19,6 +19,6 @@ #include #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__ */ diff --git a/scilab/modules/string/src/cpp/os_wtoi.cpp b/scilab/modules/string/src/cpp/os_wtoi.cpp index ac0d7ef..5ecf65c 100644 --- a/scilab/modules/string/src/cpp/os_wtoi.cpp +++ b/scilab/modules/string/src/cpp/os_wtoi.cpp @@ -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; } -- 1.7.9.5