tdf#143182: fix string handling in SbxValue::Format
When a value is convertible to number, check if the format string is for numbers of text (in SbxValue::Format). If the value is not convertible to number, handle it according to the format string in printfmtstr. Change-Id: I6e11aeffd8dd8581ebc868762944e9d6d9393514 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190348 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
This commit is contained in:
@@ -21,6 +21,23 @@ Sub verify_testFormat
|
||||
d = "2024-09-16 17:03:30"
|
||||
TestUtil.AssertEqual(Format(d, "YYYY-MM-DD"), "2024-09-16", "Format(d, ""YYYY-MM-DD"")")
|
||||
TestUtil.AssertEqual(Format("2024-09-16 05:03:30 PM", "hh-mm-ss"), "17-03-30", "Format(""2024-09-16 05:03:30 PM"", ""hh-mm-ss"")")
|
||||
' A string that can be converted to number, with a text-format string
|
||||
TestUtil.AssertEqual(Format("001", "foo @ bar"), "foo 001 bar", "Format(""001"", ""foo @ bar"")")
|
||||
' A string that cannot be converted to number, with a text-format string
|
||||
TestUtil.AssertEqual(Format("baz", "foo @ bar"), "foo baz bar", "Format(""baz"", ""foo @ bar"")")
|
||||
' Legacy format strings
|
||||
' leading '!': get only the first character of the source string
|
||||
TestUtil.AssertEqual(Format("abc", "! @"), "a", "Format(""abc"", ""! @"")")
|
||||
' leading '\': get as many characters from source string, as in format string until the next '\', padding with spaces as needed
|
||||
TestUtil.AssertEqual(Format("abcdefgh", "\123\45"), "abcde", "Format(""abcdefgh"", ""\123\45"")")
|
||||
TestUtil.AssertEqual(Format("abcdefgh", "\12345"), "abcdef", "Format(""abcdefgh"", ""\12345"")")
|
||||
TestUtil.AssertEqual(Format("abc", "\12345\"), "abc ", "Format(""abc"", ""\12345\"")")
|
||||
' leading '&': get the whole source string unmodified
|
||||
TestUtil.AssertEqual(Format("abc", "& @"), "abc", "Format(""abc"", ""& @"")")
|
||||
' non-leading positions
|
||||
TestUtil.AssertEqual(Format("abc", "@ !"), "abc !", "Format(""abc"", ""@ !"")")
|
||||
TestUtil.AssertEqual(Format("abc", "1\2345"), "abc", "Format(""abc"", ""1\2345"")")
|
||||
TestUtil.AssertEqual(Format("abc", "@ &"), "abc &", "Format(""abc"", ""@ &"")")
|
||||
|
||||
Exit Sub
|
||||
errorHandler:
|
||||
|
||||
@@ -299,39 +299,6 @@ void ImpCvtNum( double nNum, short nPrec, OUString& rRes, bool bCoreString )
|
||||
rRes = rtl::math::doubleToUString(nNum, rtl_math_StringFormat_Automatic, nPrec, cDecimalSep, true);
|
||||
}
|
||||
|
||||
// formatted number output
|
||||
|
||||
static void printfmtstr(std::u16string_view rStr, OUString& rRes, std::u16string_view rFmt)
|
||||
{
|
||||
if (rFmt.empty())
|
||||
rFmt = u"&";
|
||||
|
||||
OUStringBuffer aTemp;
|
||||
auto pStr = rStr.begin();
|
||||
auto pFmt = rFmt.begin();
|
||||
|
||||
switch( *pFmt )
|
||||
{
|
||||
case '!':
|
||||
if (pStr != rStr.end())
|
||||
aTemp.append(*pStr);
|
||||
break;
|
||||
case '\\':
|
||||
do
|
||||
{
|
||||
aTemp.append(pStr != rStr.end() ? *pStr++ : u' ');
|
||||
} while (++pFmt != rFmt.end() && *pFmt != '\\');
|
||||
aTemp.append(pStr != rStr.end() ? *pStr : u' ');
|
||||
break;
|
||||
case '&':
|
||||
default:
|
||||
aTemp = rStr;
|
||||
break;
|
||||
}
|
||||
rRes = aTemp.makeStringAndClear();
|
||||
}
|
||||
|
||||
|
||||
bool SbxValue::Scan(std::u16string_view rSrc, sal_Int32* pLen)
|
||||
{
|
||||
ErrCode eRes = ERRCODE_NONE;
|
||||
@@ -527,6 +494,40 @@ std::optional<double> GetNumberIntl(const SbxValue& val, OUString& rStrVal,
|
||||
: std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
void printfmtstr(const OUString& rStr, OUString& rRes, const OUString& rFmt)
|
||||
{
|
||||
rRes = rStr;
|
||||
|
||||
switch (rFmt.isEmpty() ? '&' : rFmt[0])
|
||||
{
|
||||
case '!':
|
||||
if (!rStr.isEmpty())
|
||||
rRes = rStr.copy(0, 1);
|
||||
break;
|
||||
case '\\':
|
||||
if (auto i = rFmt.indexOf('\\', 1) + 1, l = i ? i : rFmt.getLength();
|
||||
l < rStr.getLength())
|
||||
rRes = rStr.copy(0, l);
|
||||
else if (l > rStr.getLength())
|
||||
rRes += OUString::Concat(RepeatedUChar(' ', l - rStr.getLength()));
|
||||
break;
|
||||
case '&':
|
||||
break; // Already assigned the correct value
|
||||
default:
|
||||
if (auto formatter = GetFormatter())
|
||||
{
|
||||
sal_uInt32 nIndex;
|
||||
formatter->PutandConvertEntry(
|
||||
// [-loplugin:redundantfcast] a temporary is required here
|
||||
o3tl::temporary(OUString(rFmt)), o3tl::temporary(sal_Int32()),
|
||||
o3tl::temporary(SvNumFormatType()), nIndex, LANGUAGE_ENGLISH_US,
|
||||
Application::GetSettings().GetLanguageTag().getLanguageType(), true);
|
||||
formatter->GetOutputString(rStr, nIndex, rRes, &o3tl::temporary<const Color*>({}));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void SbxValue::Format( OUString& rRes, const OUString* pFmt ) const
|
||||
@@ -658,7 +659,10 @@ void SbxValue::Format( OUString& rRes, const OUString* pFmt ) const
|
||||
else
|
||||
{
|
||||
pFormatter->PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH_US, eLangType, true);
|
||||
pFormatter->GetOutputString(*number, nIndex, rRes, &pCol);
|
||||
if (nType == SvNumFormatType::TEXT && IsString())
|
||||
pFormatter->GetOutputString(GetOUString(), nIndex, rRes, &pCol);
|
||||
else
|
||||
pFormatter->GetOutputString(*number, nIndex, rRes, &pCol);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user