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:
Mike Kaganski
2025-08-29 18:33:37 +02:00
parent c92495ca41
commit a3597edb52
2 changed files with 55 additions and 34 deletions
@@ -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:
+38 -34
View File
@@ -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
}