From 5506dd8bcf587ac4472ce28d26c174bfdfd08f91 Mon Sep 17 00:00:00 2001 From: Xisco Fauli Date: Fri, 24 Jan 2025 14:13:06 +0100 Subject: [PATCH] tdf#151001: Add support for EXPAND function Change-Id: I4eabd526d656c13da7792d3c195f036ce78bd0d9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180706 Tested-by: Jenkins Reviewed-by: Xisco Fauli --- formula/inc/core_resource.hrc | 6 + formula/source/core/api/FormulaCompiler.cxx | 1 + include/formula/compiler.hxx | 15 +- include/formula/opcode.hxx | 2 + sc/README.md | 1 + sc/inc/helpids.h | 1 + sc/inc/scfuncs.hrc | 14 + sc/qa/extras/scfunctionlistobj.cxx | 2 +- .../functions/spreadsheet/fods/expand.fods | 6012 +++++++++++++++++ sc/qa/unit/ucalc.cxx | 1 + sc/source/core/data/funcdesc.cxx | 1 + sc/source/core/inc/interpre.hxx | 1 + sc/source/core/tool/interpr1.cxx | 134 + sc/source/core/tool/interpr4.cxx | 1 + sc/source/core/tool/parclass.cxx | 1 + sc/source/core/tool/token.cxx | 1 + sc/source/filter/excel/xlformula.cxx | 1 + sc/source/filter/oox/formulabase.cxx | 1 + 18 files changed, 6188 insertions(+), 8 deletions(-) create mode 100644 sc/qa/unit/data/functions/spreadsheet/fods/expand.fods diff --git a/formula/inc/core_resource.hrc b/formula/inc/core_resource.hrc index 712f60817abc..5b6165a35202 100644 --- a/formula/inc/core_resource.hrc +++ b/formula/inc/core_resource.hrc @@ -282,6 +282,7 @@ const std::pair RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF[] = { "COM.MICROSOFT.SORT" , SC_OPCODE_SORT }, { "COM.MICROSOFT.SORTBY" , SC_OPCODE_SORTBY }, { "COM.MICROSOFT.DROP" , SC_OPCODE_DROP }, + { "COM.MICROSOFT.EXPAND" , SC_OPCODE_EXPAND }, { "COM.MICROSOFT.TAKE" , SC_OPCODE_TAKE }, { "COM.MICROSOFT.TOCOL" , SC_OPCODE_TOCOL }, { "COM.MICROSOFT.TOROW" , SC_OPCODE_TOROW }, @@ -745,6 +746,7 @@ const std::pair RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML[] = { "_xlfn._xlws.SORT" , SC_OPCODE_SORT }, { "_xlfn.SORTBY" , SC_OPCODE_SORTBY }, { "_xlfn.DROP" , SC_OPCODE_DROP }, + { "_xlfn.EXPAND" , SC_OPCODE_EXPAND }, { "_xlfn.TAKE" , SC_OPCODE_TAKE }, { "_xlfn.TOCOL" , SC_OPCODE_TOCOL }, { "_xlfn.TOROW" , SC_OPCODE_TOROW }, @@ -1211,6 +1213,7 @@ const std::pair RID_STRLIST_FUNCTION_NAMES_ENGLISH_PODF[] = { "SORT" , SC_OPCODE_SORT }, { "SORTBY" , SC_OPCODE_SORTBY }, { "DROP" , SC_OPCODE_DROP }, + { "EXPAND" , SC_OPCODE_EXPAND }, { "TAKE" , SC_OPCODE_TAKE }, { "TOCOL" , SC_OPCODE_TOCOL }, { "TOROW" , SC_OPCODE_TOROW }, @@ -1677,6 +1680,7 @@ const std::pair RID_STRLIST_FUNCTION_NAMES_ENGLISH_API[] = { "SORT" , SC_OPCODE_SORT }, { "SORTBY" , SC_OPCODE_SORTBY }, { "DROP" , SC_OPCODE_DROP }, + { "EXPAND" , SC_OPCODE_EXPAND }, { "TAKE" , SC_OPCODE_TAKE }, { "TOCOL" , SC_OPCODE_TOCOL }, { "TOROW" , SC_OPCODE_TOROW }, @@ -2141,6 +2145,7 @@ const std::pair RID_STRLIST_FUNCTION_NAMES_ENGLISH[] = { "SORT" , SC_OPCODE_SORT }, { "SORTBY" , SC_OPCODE_SORTBY }, { "DROP" , SC_OPCODE_DROP }, + { "EXPAND" , SC_OPCODE_EXPAND }, { "TAKE" , SC_OPCODE_TAKE }, { "TOCOL" , SC_OPCODE_TOCOL }, { "TOROW" , SC_OPCODE_TOROW }, @@ -2586,6 +2591,7 @@ const std::pair RID_STRLIST_FUNCTION_NAMES[] = { NC_("RID_STRLIST_FUNCTION_NAMES", "SORT") , SC_OPCODE_SORT }, { NC_("RID_STRLIST_FUNCTION_NAMES", "SORTBY") , SC_OPCODE_SORTBY }, { NC_("RID_STRLIST_FUNCTION_NAMES", "DROP") , SC_OPCODE_DROP }, + { NC_("RID_STRLIST_FUNCTION_NAMES", "EXPAND") , SC_OPCODE_EXPAND }, { NC_("RID_STRLIST_FUNCTION_NAMES", "TAKE") , SC_OPCODE_TAKE }, { NC_("RID_STRLIST_FUNCTION_NAMES", "TOCOL") , SC_OPCODE_TOCOL }, { NC_("RID_STRLIST_FUNCTION_NAMES", "TOROW") , SC_OPCODE_TOROW }, diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx index c1eb3ac94e67..eafb6220c78a 100644 --- a/formula/source/core/api/FormulaCompiler.cxx +++ b/formula/source/core/api/FormulaCompiler.cxx @@ -1280,6 +1280,7 @@ bool FormulaCompiler::IsMatrixFunction( OpCode eOpCode ) case ocSortBy : case ocRandArray : case ocDrop : + case ocExpand : case ocTake : case ocToCol : case ocToRow : diff --git a/include/formula/compiler.hxx b/include/formula/compiler.hxx index 9dd7d6efafac..a8962479a432 100644 --- a/include/formula/compiler.hxx +++ b/include/formula/compiler.hxx @@ -518,13 +518,14 @@ #define SC_OPCODE_MAT_SEQUENCE 503 #define SC_OPCODE_RANDARRAY 504 #define SC_OPCODE_DROP 505 -#define SC_OPCODE_TAKE 506 -#define SC_OPCODE_TOCOL 507 -#define SC_OPCODE_TOROW 508 -#define SC_OPCODE_UNIQUE 509 -#define SC_OPCODE_WRAPCOLS 510 -#define SC_OPCODE_WRAPROWS 511 -#define SC_OPCODE_STOP_2_PAR 512 /* last function with two or more parameters' OpCode + 1 */ +#define SC_OPCODE_EXPAND 506 +#define SC_OPCODE_TAKE 507 +#define SC_OPCODE_TOCOL 508 +#define SC_OPCODE_TOROW 509 +#define SC_OPCODE_UNIQUE 510 +#define SC_OPCODE_WRAPCOLS 511 +#define SC_OPCODE_WRAPROWS 512 +#define SC_OPCODE_STOP_2_PAR 513 /* last function with two or more parameters' OpCode + 1 */ #define SC_OPCODE_STOP_FUNCTION SC_OPCODE_STOP_2_PAR /* last function's OpCode + 1 */ #define SC_OPCODE_LAST_OPCODE_ID (SC_OPCODE_STOP_FUNCTION - 1) /* last OpCode */ diff --git a/include/formula/opcode.hxx b/include/formula/opcode.hxx index 84c9066f65f9..81774d97e255 100644 --- a/include/formula/opcode.hxx +++ b/include/formula/opcode.hxx @@ -514,6 +514,7 @@ enum OpCode : sal_uInt16 ocMatSequence = SC_OPCODE_MAT_SEQUENCE, ocRandArray = SC_OPCODE_RANDARRAY, ocDrop = SC_OPCODE_DROP, + ocExpand = SC_OPCODE_EXPAND, ocTake = SC_OPCODE_TAKE, ocToCol = SC_OPCODE_TOCOL, ocToRow = SC_OPCODE_TOROW, @@ -1005,6 +1006,7 @@ inline std::string OpCodeEnumToString(OpCode eCode) case ocSort: return "Sort"; case ocSortBy: return "SortBy"; case ocDrop: return "Drop"; + case ocExpand: return "Expand"; case ocTake: return "Take"; case ocToCol: return "ToCol"; case ocToRow: return "ToRow"; diff --git a/sc/README.md b/sc/README.md index db19b8757bf8..d73a59535424 100644 --- a/sc/README.md +++ b/sc/README.md @@ -56,6 +56,7 @@ https://docs.oasis-open.org/office/OpenDocument/v1.3/os/part4-formula/OpenDocume * Array Functions * DROP + * EXPAND * TAKE * TOCOL * TOROW diff --git a/sc/inc/helpids.h b/sc/inc/helpids.h index e46f41a7a222..fbf2a1194a6a 100644 --- a/sc/inc/helpids.h +++ b/sc/inc/helpids.h @@ -601,6 +601,7 @@ inline constexpr OUString HID_FUNC_FILTER_MS = u"SC_HID_FUNC_FILTER_MS"_ustr; inline constexpr OUString HID_FUNC_SORT_MS = u"SC_HID_FUNC_SORT_MS"_ustr; inline constexpr OUString HID_FUNC_SORTBY_MS = u"SC_HID_FUNC_SORTBY_MS"_ustr; inline constexpr OUString HID_FUNC_DROP_MS = u"SC_HID_FUNC_DROP_MS"_ustr; +inline constexpr OUString HID_FUNC_EXPAND_MS = u"SC_HID_FUNC_EXPAND_MS"_ustr; inline constexpr OUString HID_FUNC_TAKE_MS = u"SC_HID_FUNC_TAKE_MS"_ustr; inline constexpr OUString HID_FUNC_TOCOL_MS = u"SC_HID_FUNC_TOCOL_MS"_ustr; inline constexpr OUString HID_FUNC_TOROW_MS = u"SC_HID_FUNC_TOROW_MS"_ustr; diff --git a/sc/inc/scfuncs.hrc b/sc/inc/scfuncs.hrc index 25dc2f1b540e..f52b86bbc70b 100644 --- a/sc/inc/scfuncs.hrc +++ b/sc/inc/scfuncs.hrc @@ -4263,6 +4263,20 @@ const TranslateId SC_OPCODE_DROP_ARY[] = NC_("SC_OPCODE_DROP", "The number of columns to drop. A negative value drops from the end of the array.") }; +// -=*# Resource for function EXPAND #*=- +const TranslateId SC_OPCODE_EXPAND_ARY[] = +{ + NC_("SC_OPCODE_EXPAND", "Expands or pads an array to specified row and column dimensions."), + NC_("SC_OPCODE_EXPAND", "Array"), + NC_("SC_OPCODE_EXPAND", "The array to expand."), + NC_("SC_OPCODE_EXPAND", "Rows"), + NC_("SC_OPCODE_EXPAND", "The number of rows in the expanded array. If missing, rows will not be expanded."), + NC_("SC_OPCODE_EXPAND", "Column"), + NC_("SC_OPCODE_EXPAND", "The number of columns in the expanded array. If missing, columns will not be expanded."), + NC_("SC_OPCODE_EXPAND", "Pad with"), + NC_("SC_OPCODE_EXPAND", "The value with which to pad. The default is #N/A.") +}; + // -=*# Resource for function TAKE #*=- const TranslateId SC_OPCODE_TAKE_ARY[] = { diff --git a/sc/qa/extras/scfunctionlistobj.cxx b/sc/qa/extras/scfunctionlistobj.cxx index 13dad4c73f9e..b96cbadd487a 100644 --- a/sc/qa/extras/scfunctionlistobj.cxx +++ b/sc/qa/extras/scfunctionlistobj.cxx @@ -77,7 +77,7 @@ public: ScFunctionListObj::ScFunctionListObj() : UnoApiTest(u"/sc/qa/extras/testdocuments"_ustr) , XElementAccess(cppu::UnoType>::get()) - , XIndexAccess(410) + , XIndexAccess(411) , XNameAccess(u"IF"_ustr) , XServiceInfo(u"stardiv.StarCalc.ScFunctionListObj"_ustr, u"com.sun.star.sheet.FunctionDescriptions"_ustr) diff --git a/sc/qa/unit/data/functions/spreadsheet/fods/expand.fods b/sc/qa/unit/data/functions/spreadsheet/fods/expand.fods new file mode 100644 index 000000000000..7a2b5f14a51d --- /dev/null +++ b/sc/qa/unit/data/functions/spreadsheet/fods/expand.fods @@ -0,0 +1,6012 @@ + + + + 2024-01-16T18:30:06.278000000PT6H26M39S128LibreOfficeDev/25.8.0.0.alpha0$Linux_X86_64 LibreOffice_project/b9a6803df10e6056c6f0a798cd07c85f4e7a00ac2025-01-24T14:12:12.846946910 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + € + + + + - + + + € + + + + + + Kč + + + + - + + + Kč + + + + \ + + + + + \- + + + + + + % + + + \ + + + + + + \ + + - + + + + + \ + + - + + + + + + + + + + £ + + + + + - + £ + + + + + + + + $ + + + + + + $ + + ( + + ) + + + $ + + - + + + + + + + + + + + + + . + + . + + + + + + + + + + + + ( + + ) + + + + € + + + + + € + - + + + + + $ + + + + + ($ + + ) + + + + + + + + + + + + ( + + ) + + + - + + + + + + + + + + ⌀ + + + + + € + + + - + + € + + + - € + + + + + + + + + + + + + + + + € + + + + + + € + + + - + + + + + - + + - + + + + £ + + + + - + £ + + + + + + - + + + + + + + + + + + + + + + + - + + + + + + - + + + + + + + + + + + + € + + + + + + + ( + € + + + ) + + + + + + + + + + $ + + + + + + + + ( + + ) + + + + + + Kč + + + + - + + + Kč + + + + $ + + + + + - + $ + + + + + + + + + + + - + + + + + + - + + + + + + + + + + + + Kč + + + + - + + + Kč + + + + Yes + + + Yes + + + No + + + + + + + + + + + + + EUR + + + + - + + + EUR + + + + + € + + + - + + € + + + + \ + + + + \- + + + + + \ + + + + + + \ + + - + + + + + \ + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + ( + + ) + + + + - + + + + + + + + + + £ + + + + - + £ + + + + + + + + + + + + + EUR + + + + - + + + EUR + + + + + € + + + + - + + € + + + + + - + + - + + + + $ + + + + + + $ + + ( + + ) + + + $ + + - + + + + + + + + + + $ + + + + + $( + + ) + + + $- + + + + + + + + + + + + + + + + £ + + + + + - + £ + + + + + + On + + + On + + + Off + + + + + $ + + + + + + ($ + + ) + + + + + € + + + - + + € + + + + + + + $ + + + + + ($ + + ) + + + + $ + + + + + + ($ + + ) + + + + + + + + + + + + + ( + + ) + + + + - + + + + + + + + + + + + + + Kč + + + - + + + Kč + + + + + + + True + + + True + + + False + + + + + + € + + + - + + € + + + - + + € + + + + + + + + + + + + + + + + + - + + + + + - + + + + + + + + + + + / + + + + £ + + + + + - + £ + + + + + £ + + + + + - + £ + + + + + $ + + + + + $( + + ) + + + $- + + + + + + + + + + + + + + + + - + + + + + - + + + + + + + + + + + + WAHR + + + WAHR + + + FALSCH + + + + + + . + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + + + + + + ( + + ) + + + - + + + + + + + + + + + + + : + + + + + : + + + + £ + + + + + - + £ + + + + + + \ + + + + + \- + + + + + € + + + + + € + - + + + + + + + € + + + + - + + + € + + + + + + + + + + + € + + + + - + + € + + + + + + Kč + + + - + + + Kč + + + + + : + + : + + + + \ + + + + \- + + + + + + + + + - + + + € + + + + + + + / + + / + + + + + + + / + + / + + + + € + + + + + + - + € + + + + + + + Kč + + + - + + Kč + + + + + Kč + + + + - + + Kč + + + + + Kč + + + - + + Kč + + + + + Kč + + + + - + + Kč + + + + + + + - + + + + + + + + + - + + + + + + + + - + + + + + + + + + - + + + + + + + + + + - + + + + + + + - + + + + + + + + + + + + Kč + + + - + + + Kč + + + + - Kč + + + + + + + + + + + + + + + - + + + + + + + - + + + + + + + + + + + + + + Kč + + + - + + + Kč + + + + - + + Kč + + + + + + + + + + ¥€ + + + + + + + + + ( + € + + + + + ) + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + - + + + + + + + + + + + - + + + + + + + % + + + + % + + + + % + + + + % + + + + % + + + + % + + + + % + + + + % + + + + % + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + + € + + + + - + + + € + + + + + % + + + + % + + + + % + + + + % + + + + % + + + + % + + + + + + $ + + + + + ( + $ + + ) + + + + + % + + + + % + + + + - + + % + + + + + + + + - + + + + + + - + + - + + + + £ + + + + + - + £ + + + + + £ + + + + + - + £ + + + + + + % + + + + - + + % + + + + + DM + + + - + + DM + + + + + DM + + + + - + + DM + + + + + DM + + + - + + DM + + + + + DM + + + + - + + DM + + + + + + + + + + - + + + + + + + + - + + + + + + + + + + + + + + DM + + + - + + + DM + + + + + - DM + + + + + + + + + + + + + + + + + - + + + + + + + + - + + + + + + + + + + + + + + + + DM + + + - + + + DM + + + + + - + + DM + + + + + + + + + + + Ouch! - + + - Error detected! + + + + - Result=0 - No Errordetection + + + + / + + / + + + + + . + + . + + + + + + + + + + - + + + + + + + + - + + + + + + + + + + + + + + € + + + - + + + € + + + + + - € + + + + + + + + + + + + + + + + + - + + + + + + + + - + + + + + + + + + + + + + + + + € + + + - + + + € + + + + + - + + € + + + + + + + + + + + $ + + + + $ + + + + + - + $ + + + + + + . + + . + + + + + . + + + + + + + . + + + + + + + + + + : + + + + + + + : + + : + + + + + + + . + + . + + + + : + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + - + + + + + + + + + + + - + + + + + + $ + + + + $ + + + + -$ + + + + + $ + + + + + -$ + + + + + $ + + + + -$ + + + + + $ + + + + + -$ + + + + + -$ + + + + $ + + + + -$ + + + + $- + + + + + - + + + + + + + - + + + + - + + + + + -$ + + + + $ + + + + -$ + + + + $- + + + + + + - + + + + + + + - + + + + - + + + + + + + Ft + + + - + + Ft + + + + + Ft + + + + - + + Ft + + + + + Ft + + + - + + Ft + + + + + Ft + + + + - + + Ft + + + + + . + + . + + + + + . + + . + + + + + . + + + + + . + + + + + . + + . + + + + : + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + + + - + + + + + + + + - + + + + + + + + + + + + + + Ft + + + - + + + Ft + + + + + - Ft + + + + + + + + + + + + + + + + + - + + + + + + + + - + + + + + + + + + + + + + + + + Ft + + + - + + + Ft + + + + + - + + Ft + + + + + + + + + + + + - + + - + + + + + - + + + + + - + + + + + : + + + + + : + + : + + + + + / + + / + + + + : + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + + + - + + + + + + + + - + + + + + + + + + + + + + + € + + + - + + + € + + + + + - € + + + + + + + + + + + + + + + + + - + + + + + + + + - + + + + + + + + + + + + + + + + € + + + - + + + € + + + + + - + + € + + + + + + + + + + + + / + + / + + + + + - + + - + + + + + - + + + + + - + + + + + : + + + + + + + : + + : + + + + + + + : + + + + + : + + : + + + + + / + + / + + + + : + + + + + + + + + ( + + ) + + + + + + + + + ( + + ) + + + + + + + + + ( + + + ) + + + + + + + + + + ( + + + ) + + + + + + + + + ( + + + ) + + + + + + + + + + ( + + + ) + + + + + + + + ( + + ) + + + + + + + + ( + + ) + + + + + + + + + + ( + + ) + + + + - + + + + + + + + + + + + + + + + + + ( + + ) + + + + + - + + + + + + + + + + + + + + + + ( + + ) + + + + - + + + + + + + + + + + + + + + + + + + + ( + + ) + + + + + - + + + + + + + + + + + + + + + + + + + - + + + + + : + + : + + + + + : + + + + + + + + % + + + + + + + - + + - + + + + + + + + + - + + + + + + + + + . + + + + + + + . + + + + + + + + + + : + + + + + + + : + + : + + + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + - + + + + + + + + + + + - + + + + + + + € + + + - + + € + + + + + € + + + + - + + € + + + + + € + + + - + + € + + + + + € + + + + - + + € + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ??? + + + + + Page 1 + + + + + + + + ???(???) + + + 00/00/0000, 00:00:00 + + + + + + Page 1/ 99 + + + + + + + + + + + + + + + Expand Function + + + + + + + + + + Result + + + VERDADERO + + + + + + + + + Sheet + + + Result + + + Description + + + + + 2 + + + VERDADERO + + + Simple EXPAND formulas with local references and values + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Function + + + + Expected + + + + Correct + + + FunctionString + + + Comment + + + Data + + + + + + Data + + + + Data + + + + Missing rows + + + + + + + + + + + + January + + + 100 + + + 1 + + + + January + + + 100 + + + 1 + + + + VERDADERO + + + {=EXPAND(L3:N8;)} + + + + January + + + 100 + + + 1 + + + + + + + February + + + 150 + + + 2 + + + + February + + + 150 + + + 2 + + + + VERDADERO + + + {=EXPAND(L3:N8;)} + + + + February + + + 150 + + + 2 + + + + + + + #N/A + + + #N/A + + + #N/A + + + + #N/A + + + #N/A + + + #N/A + + + + VERDADERO + + + {=EXPAND(L3:N8;)} + + + + #N/A + + + #N/A + + + #N/A + + + + + + + + + + + + + + + + + + + VERDADERO + + + {=EXPAND(L3:N8;)} + + + + + + + + April + + + 250 + + + 4 + + + + April + + + 250 + + + 4 + + + + VERDADERO + + + {=EXPAND(L3:N8;)} + + + + April + + + 250 + + + 4 + + + + + + + May + + + 300 + + + 5 + + + + May + + + 300 + + + 5 + + + + VERDADERO + + + {=EXPAND(L3:N8;)} + + + + May + + + 300 + + + 5 + + + + + + + + + + Missing columns + + + + + + + + January + + + 100 + + + 1 + + + + January + + + 100 + + + 1 + + + + VERDADERO + + + {=EXPAND(L3:N8;;)} + + + + + + + + February + + + 150 + + + 2 + + + + February + + + 150 + + + 2 + + + + VERDADERO + + + {=EXPAND(L3:N8;;)} + + + + + + + + + + + #N/A + + + #N/A + + + #N/A + + + + #N/A + + + #N/A + + + #N/A + + + + VERDADERO + + + {=EXPAND(L3:N8;;)} + + + + + + + + + + + + + + + + + + + + + + + VERDADERO + + + {=EXPAND(L3:N8;;)} + + + + + + + + + April + + + 250 + + + 4 + + + + April + + + 250 + + + 4 + + + + VERDADERO + + + {=EXPAND(L3:N8;;)} + + + + + + + + + + + May + + + 300 + + + 5 + + + + May + + + 300 + + + 5 + + + + VERDADERO + + + {=EXPAND(L3:N8;;)} + + + + + + + + + + + + + + Missing rows and colums + + + + + + + + + + January + + + 100 + + + 1 + + + + January + + + 100 + + + 1 + + + + VERDADERO + + + {=EXPAND(L3:N8;;;"-")} + + + + + + + + + + + February + + + 150 + + + 2 + + + + February + + + 150 + + + 2 + + + + VERDADERO + + + {=EXPAND(L3:N8;;;"-")} + + + + + + + + + + + #N/A + + + #N/A + + + #N/A + + + + #N/A + + + #N/A + + + #N/A + + + + VERDADERO + + + {=EXPAND(L3:N8;;;"-")} + + + + + + + + + + + + + + + + + + + + + + + VERDADERO + + + {=EXPAND(L3:N8;;;"-")} + + + + + + April + + + 250 + + + 4 + + + + April + + + 250 + + + 4 + + + + VERDADERO + + + {=EXPAND(L3:N8;;;"-")} + + + + + + May + + + 300 + + + 5 + + + + May + + + 300 + + + 5 + + + + VERDADERO + + + {=EXPAND(L3:N8;;;"-")} + + + + + + + + + different row values + + + + + + Err:502 + + + + + + + + VERDADERO + + + {=EXPAND(L3:N8;1)} + + + + + + Err:502 + + + + + + + VERDADERO + + + {=EXPAND(L3:N8;2)} + + + + + + Err:502 + + + + + + VERDADERO + + + {=EXPAND(L3:N8;3)} + + + + + + Err:502 + + + + + + VERDADERO + + + {=EXPAND(L3:N8;4)} + + + + + + Err:502 + + + + + + VERDADERO + + + {=EXPAND(L3:N8;5)} + + + + + + January + + + 100 + + + 1 + + + + January + + + 100 + + + 1 + + + + VERDADERO + + + {=EXPAND(L3:N8;6)} + + + + + + February + + + 150 + + + 2 + + + + February + + + 150 + + + 2 + + + + VERDADERO + + + {=EXPAND(L3:N8;6)} + + + + + + #N/A + + + #N/A + + + #N/A + + + + #N/A + + + #N/A + + + #N/A + + + + VERDADERO + + + {=EXPAND(L3:N8;6)} + + + + + + + + + + + + + + + + + + VERDADERO + + + {=EXPAND(L3:N8;6)} + + + + + + April + + + 250 + + + 4 + + + + April + + + 250 + + + 4 + + + + VERDADERO + + + {=EXPAND(L3:N8;6)} + + + + + + May + + + 300 + + + 5 + + + + May + + + 300 + + + 5 + + + + VERDADERO + + + {=EXPAND(L3:N8;6)} + + + + + + January + + + 100 + + + 1 + + + + January + + + 100 + + + 1 + + + + VERDADERO + + + {=EXPAND(L3:N8;7)} + + + + + + February + + + 150 + + + 2 + + + + February + + + 150 + + + 2 + + + + VERDADERO + + + {=EXPAND(L3:N8;7)} + + + + + + #N/A + + + #N/A + + + #N/A + + + + #N/A + + + #N/A + + + #N/A + + + + VERDADERO + + + {=EXPAND(L3:N8;7)} + + + + + + + + + + + + + + + + + + VERDADERO + + + {=EXPAND(L3:N8;7)} + + + + + + April + + + 250 + + + 4 + + + + April + + + 250 + + + 4 + + + + VERDADERO + + + {=EXPAND(L3:N8;7)} + + + + + + May + + + 300 + + + 5 + + + + May + + + 300 + + + 5 + + + + VERDADERO + + + {=EXPAND(L3:N8;7)} + + + + + + #N/A + + + #N/A + + + #N/A + + + + #N/A + + + #N/A + + + #N/A + + + + VERDADERO + + + {=EXPAND(L3:N8;7)} + + + + + + January + + + 100 + + + 1 + + + + January + + + 100 + + + 1 + + + + VERDADERO + + + {=EXPAND(L3:N8;7;;"-")} + + + + + + February + + + 150 + + + 2 + + + + February + + + 150 + + + 2 + + + + VERDADERO + + + {=EXPAND(L3:N8;7;;"-")} + + + + + + #N/A + + + #N/A + + + #N/A + + + + #N/A + + + #N/A + + + #N/A + + + + VERDADERO + + + {=EXPAND(L3:N8;7;;"-")} + + + + + + + + + + + + + + + + + + VERDADERO + + + {=EXPAND(L3:N8;7;;"-")} + + + + + + April + + + 250 + + + 4 + + + + April + + + 250 + + + 4 + + + + VERDADERO + + + {=EXPAND(L3:N8;7;;"-")} + + + + + + May + + + 300 + + + 5 + + + + May + + + 300 + + + 5 + + + + VERDADERO + + + {=EXPAND(L3:N8;7;;"-")} + + + + + + - + + + - + + + - + + + + - + + + - + + + + VERDADERO + + + {=EXPAND(L3:N8;7;;"-")} + + + + + + + + + different column values + + + + + + Err:502 + + + + + + VERDADERO + + + {=EXPAND(L3:N8;;1)} + + + + + + Err:502 + + + + + + VERDADERO + + + {=EXPAND(L3:N8;;2)} + + + + + + January + + + 100 + + + 1 + + + + January + + + 100 + + + 1 + + + + VERDADERO + + + {=EXPAND(L3:N8;;3)} + + + + + + February + + + 150 + + + 2 + + + + February + + + 150 + + + 2 + + + + VERDADERO + + + {=EXPAND(L3:N8;;3)} + + + + + + #N/A + + + #N/A + + + #N/A + + + + #N/A + + + #N/A + + + #N/A + + + + VERDADERO + + + {=EXPAND(L3:N8;;3)} + + + + + + + + + + + + + + + + + + VERDADERO + + + {=EXPAND(L3:N8;;3)} + + + + + + April + + + 250 + + + 4 + + + + April + + + 250 + + + 4 + + + + VERDADERO + + + {=EXPAND(L3:N8;;3)} + + + + + + May + + + 300 + + + 5 + + + + May + + + 300 + + + 5 + + + + VERDADERO + + + {=EXPAND(L3:N8;;3)} + + + + + + January + + + 100 + + + 1 + + + #N/A + + + January + + + 100 + + + 1 + + + #N/A + + + VERDADERO + + + {=EXPAND(L3:N8;;4)} + + + + + + February + + + 150 + + + 2 + + + #N/A + + + February + + + 150 + + + 2 + + + #N/A + + + VERDADERO + + + {=EXPAND(L3:N8;;4)} + + + + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + VERDADERO + + + {=EXPAND(L3:N8;;4)} + + + + + + + + + + + + + + + #N/A + + + + + #N/A + + + VERDADERO + + + {=EXPAND(L3:N8;;4)} + + + + + + April + + + 250 + + + 4 + + + #N/A + + + April + + + 250 + + + 4 + + + #N/A + + + VERDADERO + + + {=EXPAND(L3:N8;;4)} + + + + + + May + + + 300 + + + 5 + + + #N/A + + + May + + + 300 + + + 5 + + + #N/A + + + VERDADERO + + + {=EXPAND(L3:N8;;4)} + + + + + + January + + + 100 + + + 1 + + + - + + + January + + + 100 + + + 1 + + + - + + + VERDADERO + + + {=EXPAND(L3:N8;;4;"-")} + + + + + + February + + + 150 + + + 2 + + + - + + + February + + + 150 + + + 2 + + + - + + + VERDADERO + + + {=EXPAND(L3:N8;;4;"-")} + + + + + + #N/A + + + #N/A + + + #N/A + + + - + + + #N/A + + + #N/A + + + #N/A + + + - + + + VERDADERO + + + {=EXPAND(L3:N8;;4;"-")} + + + + + + + + + + + + + + + - + + + + + - + + + VERDADERO + + + {=EXPAND(L3:N8;;4;"-")} + + + + + + April + + + 250 + + + 4 + + + - + + + April + + + 250 + + + 4 + + + - + + + VERDADERO + + + {=EXPAND(L3:N8;;4;"-")} + + + + + + May + + + 300 + + + 5 + + + - + + + May + + + 300 + + + 5 + + + - + + + VERDADERO + + + {=EXPAND(L3:N8;;4;"-")} + + + + + + + + + column and rows + + + + + + January + + + 100 + + + 1 + + + #N/A + + + January + + + 100 + + + 1 + + + #N/A + + + VERDADERO + + + {=EXPAND(L3:N8;7;4)} + + + + + + February + + + 150 + + + 2 + + + #N/A + + + February + + + 150 + + + 2 + + + #N/A + + + VERDADERO + + + {=EXPAND(L3:N8;7;4)} + + + + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + VERDADERO + + + {=EXPAND(L3:N8;7;4)} + + + + + + + + + + + + + + + #N/A + + + + + #N/A + + + VERDADERO + + + {=EXPAND(L3:N8;7;4)} + + + + + + April + + + 250 + + + 4 + + + #N/A + + + April + + + 250 + + + 4 + + + #N/A + + + VERDADERO + + + {=EXPAND(L3:N8;7;4)} + + + + + + May + + + 300 + + + 5 + + + #N/A + + + May + + + 300 + + + 5 + + + #N/A + + + VERDADERO + + + {=EXPAND(L3:N8;7;4)} + + + + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + #N/A + + + VERDADERO + + + {=EXPAND(L3:N8;7;4)} + + + + + + + + + column and rows with “-” + + + + + + January + + + 100 + + + 1 + + + - + + + January + + + 100 + + + 1 + + + - + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;"-")} + + + + + + February + + + 150 + + + 2 + + + - + + + February + + + 150 + + + 2 + + + - + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;"-")} + + + + + + #N/A + + + #N/A + + + #N/A + + + - + + + #N/A + + + #N/A + + + #N/A + + + - + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;"-")} + + + + + + + + + + + + + + + - + + + + + - + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;"-")} + + + + + + April + + + 250 + + + 4 + + + - + + + April + + + 250 + + + 4 + + + - + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;"-")} + + + + + + May + + + 300 + + + 5 + + + - + + + May + + + 300 + + + 5 + + + - + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;"-")} + + + + + + - + + + - + + + - + + + - + + + - + + + - + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;"-")} + + + + + + + + + column and rows with 5 + + + + + + January + + + 100 + + + 1 + + + 5 + + + January + + + 100 + + + 1 + + + 5 + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;5)} + + + + + + February + + + 150 + + + 2 + + + 5 + + + February + + + 150 + + + 2 + + + 5 + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;5)} + + + + + + #N/A + + + #N/A + + + #N/A + + + 5 + + + #N/A + + + #N/A + + + #N/A + + + 5 + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;5)} + + + + + + + + + + + + + + + 5 + + + + + 5 + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;5)} + + + + + + April + + + 250 + + + 4 + + + 5 + + + April + + + 250 + + + 4 + + + 5 + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;5)} + + + + + + May + + + 300 + + + 5 + + + 5 + + + May + + + 300 + + + 5 + + + 5 + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;5)} + + + + + + 5 + + + 5 + + + 5 + + + 5 + + + 5 + + + 5 + + + VERDADERO + + + {=EXPAND(L3:N8;7;4;5)} + + + + + + + + + + + + + + + diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index 09674dbf8875..230b7da34588 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -3103,6 +3103,7 @@ CPPUNIT_TEST_FIXTURE(Test, testFunctionLists) "DROP", "ERROR.TYPE", "ERRORTYPE", + "EXPAND", "FILTER", "GETPIVOTDATA", "HLOOKUP", diff --git a/sc/source/core/data/funcdesc.cxx b/sc/source/core/data/funcdesc.cxx index 045ecea7a657..b16b776e024c 100644 --- a/sc/source/core/data/funcdesc.cxx +++ b/sc/source/core/data/funcdesc.cxx @@ -794,6 +794,7 @@ ScFunctionList::ScFunctionList( bool bEnglishFunctionNames ) { SC_OPCODE_MAT_SEQUENCE, ENTRY(SC_OPCODE_MAT_SEQUENCE_ARY), 0, ID_FUNCTION_GRP_MATRIX, HID_FUNC_MSEQUENCE_MS, 4, { 0, 1, 1, 1 }, 0 }, { SC_OPCODE_RANDARRAY, ENTRY(SC_OPCODE_RANDARRAY_ARY), 0, ID_FUNCTION_GRP_MATH, HID_FUNC_RANDARRAY_MS, 5, { 1, 1, 1, 1, 1 }, 0 }, { SC_OPCODE_DROP, ENTRY(SC_OPCODE_DROP_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_DROP_MS, 3, { 0, 0, 1 }, 0 }, + { SC_OPCODE_EXPAND, ENTRY(SC_OPCODE_EXPAND_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_EXPAND_MS, 4, { 0, 0, 1, 1 }, 0 }, { SC_OPCODE_TAKE, ENTRY(SC_OPCODE_TAKE_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_TAKE_MS, 3, { 0, 1, 1 }, 0 }, { SC_OPCODE_TOCOL, ENTRY(SC_OPCODE_TOCOL_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_TOCOL_MS, 3, { 0, 1, 1 }, 0 }, { SC_OPCODE_TOROW, ENTRY(SC_OPCODE_TOROW_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_TOROW_MS, 3, { 0, 1, 1 }, 0 }, diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx index ee98386e1f10..05419ea73f83 100644 --- a/sc/source/core/inc/interpre.hxx +++ b/sc/source/core/inc/interpre.hxx @@ -725,6 +725,7 @@ private: void ScSort(); void ScSortBy(); void ScDrop(); + void ScExpand(); void ScTake(); void ScToCol(); void ScToRow(); diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index fdfa26ae5b93..45fdac1ae057 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -8936,6 +8936,140 @@ void ScInterpreter::ScDrop() PushMatrix(pResMat); } +void ScInterpreter::ScExpand() +{ + sal_uInt8 nParamCount = GetByte(); + if (!MustHaveParamCount(nParamCount, 2, 4)) + return; + + // 4rd argument optional - pad_with + std::optional bDouble; + double fNumber(0.0); + svl::SharedString aString; + if (nParamCount == 4) + bDouble = GetDoubleOrString(fNumber, aString); + + // 3rd argument optional - columns + std::optional nArgCols; + if (nParamCount >= 3) + { + if (!IsMissing()) + nArgCols = GetInt32(); + else + Pop(); + } + + // 2nd argument - rows + std::optional nArgRows; + if (nParamCount >= 2) + { + if (!IsMissing()) + nArgRows = GetInt32(); + else + Pop(); + } + + // 1st argument: take unique search range + ScMatrixRef pMatSource = nullptr; + SCSIZE nsC = 0, nsR = 0; + switch (GetStackType()) + { + case svSingleRef: + case svDoubleRef: + case svMatrix: + case svExternalSingleRef: + case svExternalDoubleRef: + { + pMatSource = GetMatrix(); + if (!pMatSource) + { + PushIllegalParameter(); + return; + } + + pMatSource->GetDimensions(nsC, nsR); + } + break; + + default: + PushIllegalParameter(); + return; + } + + if (nGlobalError != FormulaError::NONE || nsC < 1 || nsR < 1) + { + PushIllegalArgument(); + return; + } + + SCSIZE nColumns = nsC; + SCSIZE nRows = nsR; + if (nArgCols.has_value()) + { + if (o3tl::make_unsigned(std::abs(nArgCols.value())) < nsC) + { + PushIllegalArgument(); + return; + } + else + nColumns = nArgCols.value(); + } + + if (nArgRows.has_value()) + { + if (o3tl::make_unsigned(std::abs(nArgRows.value())) < nsR) + { + PushIllegalArgument(); + return; + } + else + nRows = nArgRows.value(); + } + + ScMatrixRef pResMat = GetNewMat(nColumns, nRows, /*bEmpty*/true); + if (!pResMat) + { + PushIllegalArgument(); + return; + } + + for (SCSIZE col = 0; col < nColumns; ++col) + { + for (SCSIZE row = 0; row < nRows; ++row) + { + if (col < nsC && row < nsR) + { + if (pMatSource->IsEmptyCell(col, row)) + { + pResMat->PutEmpty(col, row); + } + else if (!pMatSource->IsStringOrEmpty(col, row)) + { + pResMat->PutDouble(pMatSource->GetDouble(col, row), col, row); + } + else + { + pResMat->PutString(pMatSource->GetString(col, row), col, row); + } + } + else + { + if (bDouble.has_value()) + { + if (bDouble.value()) + pResMat->PutDouble(fNumber, col, row); + else + pResMat->PutString(aString, col, row); + } + else + pResMat->PutError(FormulaError::NotAvailable, col, row); + } + } + } + + PushMatrix(pResMat); +} + void ScInterpreter::ScTake() { sal_uInt8 nParamCount = GetByte(); diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index 1dfc4ea8ee5b..18c4300af5e7 100644 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -4160,6 +4160,7 @@ StackVar ScInterpreter::Interpret() case ocSort : ScSort(); break; case ocSortBy : ScSortBy(); break; case ocDrop : ScDrop(); break; + case ocExpand : ScExpand(); break; case ocTake : ScTake(); break; case ocToCol : ScToCol(); break; case ocToRow : ScToRow(); break; diff --git a/sc/source/core/tool/parclass.cxx b/sc/source/core/tool/parclass.cxx index f8e8506623b7..1964e949fd9f 100644 --- a/sc/source/core/tool/parclass.cxx +++ b/sc/source/core/tool/parclass.cxx @@ -137,6 +137,7 @@ const ScParameterClassification::RawData ScParameterClassification::pRawData[] = { ocDevSq, {{ Reference }, 1, Value }}, { ocDiv, {{ Array, Array }, 0, Value }}, { ocDrop, {{ ReferenceOrRefArray, Value, Value, }, 0, ForceArrayReturn } }, + { ocExpand, {{ ReferenceOrRefArray, Value, Value, }, 0, ForceArrayReturn } }, { ocEqual, {{ Array, Array }, 0, Value }}, { ocFTest, {{ ForceArray, ForceArray }, 0, Value }}, { ocFalse, {{ Bounds }, 0, Value }}, diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index 451a79a2ea39..b0d036613ffa 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -1592,6 +1592,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r ) case ocMatSequence: case ocRandArray: case ocDrop: + case ocExpand: case ocTake: case ocToCol: case ocToRow: diff --git a/sc/source/filter/excel/xlformula.cxx b/sc/source/filter/excel/xlformula.cxx index 23aa4f0a24a2..92355939bd9d 100644 --- a/sc/source/filter/excel/xlformula.cxx +++ b/sc/source/filter/excel/xlformula.cxx @@ -620,6 +620,7 @@ const XclFunctionInfo saFuncTable_2021[] = const XclFunctionInfo saFuncTable_2024[] = { EXC_FUNCENTRY_V_VR( ocDrop, 1, 3, 0, "DROP" ), + EXC_FUNCENTRY_V_VR( ocExpand, 2, 4, 0, "EXPAND" ), EXC_FUNCENTRY_V_VR( ocTake, 1, 3, 0, "TAKE" ), EXC_FUNCENTRY_V_VR( ocToCol, 1, 3, 0, "TOCOL" ), EXC_FUNCENTRY_V_VR( ocToRow, 1, 3, 0, "TOROW" ), diff --git a/sc/source/filter/oox/formulabase.cxx b/sc/source/filter/oox/formulabase.cxx index e7d331fcbf3c..09024d5ca98e 100644 --- a/sc/source/filter/oox/formulabase.cxx +++ b/sc/source/filter/oox/formulabase.cxx @@ -895,6 +895,7 @@ const FunctionData saFuncTable2021[] = const FunctionData saFuncTable2024[] = { { "COM.MICROSOFT.DROP", "DROP", NOID, NOID, 1, 3, A, { VO }, FuncFlags::MACROCALL_NEW }, + { "COM.MICROSOFT.EXPAND", "EXPAND", NOID, NOID, 2, 4, A, { VO }, FuncFlags::MACROCALL_NEW }, { "COM.MICROSOFT.TAKE", "TAKE", NOID, NOID, 1, 3, A, { VO }, FuncFlags::MACROCALL_NEW }, { "COM.MICROSOFT.TOCOL", "TOCOL", NOID, NOID, 1, 3, A, { VO }, FuncFlags::MACROCALL_NEW }, { "COM.MICROSOFT.TOROW", "TOROW", NOID, NOID, 1, 3, A, { VO }, FuncFlags::MACROCALL_NEW },