diff --git a/components/fpspreadsheet/fpsfunc.pas b/components/fpspreadsheet/fpsfunc.pas
index ae49a7b00..7d9ff2f72 100644
--- a/components/fpspreadsheet/fpsfunc.pas
+++ b/components/fpspreadsheet/fpsfunc.pas
@@ -11,6 +11,8 @@ type
TsArgumentType = (atCell, atCellRange, atNumber, atString,
atBool, atError, atEmpty);
+ TsArgumentTypes = set of TsArgumentType;
+
TsArgBoolArray = array of boolean;
TsArgNumberArray = array of double;
TsArgStringArray = array of string;
@@ -128,6 +130,7 @@ function fpsYEAR (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsAVEDEV (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsAVERAGE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsCOUNT (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsCOUNTA (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsCOUNTBLANK (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsCOUNTIF (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsMAX (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
@@ -1534,7 +1537,7 @@ end;
function fpsCOUNT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
{ counts the number of cells that contain numbers as well as the number of
arguments that contain numbers.
- COUNT( argument1, [argument2, ... argument_n] )
+ COUNT( argument1 [, argument2, ... argument_n] )
}
var
data: TsArgNumberArray;
@@ -1543,6 +1546,38 @@ begin
Result := CreateNumberArg(Length(data));
end;
+function fpsCOUNTA(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// COUNTA (argument1 [, argument2, ... argument_n] )
+// Counts the number of non-empty cells specified by arguments of misc type.
+var
+ arg: TsArgument;
+ counter: Integer;
+ r, c: Integer;
+ cell: PCell;
+ n: Integer;
+begin
+ n := 0;
+ // The order of arguments is not important for counting --> we just pop them from the stack.
+ for counter := 1 to NumArgs do begin
+ arg := Args.Pop;
+ case arg.ArgumentType of
+ atCell:
+ if arg.Cell^.ContentType <> cctEmpty then inc(n);
+ atCellRange:
+ for r := arg.FirstRow to arg.LastRow do
+ for c := arg.FirstCol to arg.LastCol do begin
+ cell := arg.Worksheet.FindCell(r, c);
+ if (cell <> nil) and (cell^.ContentType <> cctEmpty) then inc(n);
+ end;
+ atString:
+ if arg.StringValue <> '' then inc(n);
+ atNumber, atBool, atError:
+ inc(n);
+ end;
+ end;
+ Result := CreateNumberArg(n);
+end;
+
function fpsCOUNTBLANK(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
// COUNTBLANK( range )
// counts the number of empty cells in a range.
diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas
index 6025a3baa..abc6b5fe7 100755
--- a/components/fpspreadsheet/fpspreadsheet.pas
+++ b/components/fpspreadsheet/fpspreadsheet.pas
@@ -1152,7 +1152,7 @@ var
(Symbol:'<'; MinParams:2; MaxParams:2; Func:fpsLess), // fekLess
(Symbol:'<='; MinParams:2; MaxParams:2; Func:fpsLessEqual), // fekLessEqual
(Symbol:'<>'; MinParams:2; MaxParams:2; Func:fpsNotEqual), // fekNotEqual
- (Symbol:''; MinParams:1; MaxParams:1; Func:nil), // fekParen
+ (Symbol:''; MinParams:1; MaxParams:1; Func:nil), // fekParen -- no need to calculate!
{ math }
(Symbol:'ABS'; MinParams:1; MaxParams:1; Func:fpsABS), // fekABS
(Symbol:'ACOS'; MinParams:1; MaxParams:1; Func:fpsACOS), // fekACOS
@@ -1203,7 +1203,7 @@ var
(Symbol:'CHIDIST'; MinParams:2; MaxParams:2; Func:nil), // fekCHIDIST
(Symbol:'CHIINV'; MinParams:2; MaxParams:2; Func:nil), // fekCHIINV
(Symbol:'COUNT'; MinParams:0; MaxParams:30; Func:fpsCOUNT), // fekCOUNT
- (Symbol:'COUNTA'; MinParams:0; MaxParams:30; Func:nil), // fekCOUNTA
+ (Symbol:'COUNTA'; MinParams:0; MaxParams:30; Func:fpsCOUNTA), // fekCOUNTA
(Symbol:'COUNTBLANK';MinParams:1; MaxParams:1; Func:fpsCOUNTBLANK), // fekCOUNTBLANK
(Symbol:'COUNTIF'; MinParams:2; MaxParams:2; Func:fpsCOUNTIF), // fekCOUNTIF
(Symbol:'MAX'; MinParams:1; MaxParams:30; Func:fpsMAX), // fekMAX
diff --git a/components/fpspreadsheet/tests/spreadtestgui.lpi b/components/fpspreadsheet/tests/spreadtestgui.lpi
index 505633548..ed06b19d3 100644
--- a/components/fpspreadsheet/tests/spreadtestgui.lpi
+++ b/components/fpspreadsheet/tests/spreadtestgui.lpi
@@ -80,7 +80,6 @@
-
@@ -89,12 +88,10 @@
-
-
diff --git a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
index 439a4894f..718d1c3be 100644
--- a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
+++ b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
@@ -1286,6 +1286,42 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumberArg(2);
+ // COUNTA
+ MyWorksheet.WriteUTF8Text(Row, 0, '=COUNTA(1, 1.1, 1.2, 0.9, 0.8)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(1.0,
+ RPNNumber(1.1,
+ RPNNumber(1.2,
+ RPNNumber(0.9,
+ RPNNumber(0.8,
+ RPNFunc(fekCOUNTA, 5, nil))))))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumberArg(5);
+
+ MyWorksheet.WriteUTF8Text(Row, 0, '=COUNTA(1, 1.1, 1.2, 0.9, 0.8, "A", "B")');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(1.0,
+ RPNNumber(1.1,
+ RPNNumber(1.2,
+ RPNNumber(0.9,
+ RPNNumber(0.8,
+ RPNString('A',
+ RPNString('B',
+ RPNFunc(fekCOUNTA, 7, nil))))))))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumberArg(7);
+
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=COUNTA(A1:C2,1,2,"A")');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNCellRange('A1:C2',
+ RPNNumber(1,
+ RPNNumber(2,
+ RPNString('A',
+ RPNFunc(fekCOUNTA, 4, nil)))))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumberArg(7);
+
if AFormat <> sfExcel2 then begin
// COUNTBLANK
inc(Row);