fpspreadsheet: Add formula MATCH. Improved error detection on math formulas.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6768 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
3cf0a0592b
commit
8b3b74de88
@ -27,8 +27,14 @@ uses
|
|||||||
{------------------------------------------------------------------------------}
|
{------------------------------------------------------------------------------}
|
||||||
|
|
||||||
procedure fpsABS(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsABS(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
Result := FloatResult(abs(ArgToFloat(Args[0])));
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(abs(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsACOS(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsACOS(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
@ -36,6 +42,9 @@ var
|
|||||||
x: TsExprFloat;
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
x := ArgToFloat(Args[0]);
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
if InRange(x, -1, +1) then
|
if InRange(x, -1, +1) then
|
||||||
Result := FloatResult(arccos(x))
|
Result := FloatResult(arccos(x))
|
||||||
else
|
else
|
||||||
@ -47,8 +56,11 @@ var
|
|||||||
x: TsExprFloat;
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
x := ArgToFloat(Args[0]);
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
if x >= 1 then
|
if x >= 1 then
|
||||||
Result := FloatResult(arccosh(ArgToFloat(Args[0])))
|
Result := FloatResult(arccosh(x))
|
||||||
else
|
else
|
||||||
Result := ErrorResult(errOverflow);
|
Result := ErrorResult(errOverflow);
|
||||||
end;
|
end;
|
||||||
@ -58,20 +70,35 @@ var
|
|||||||
x: TsExprFloat;
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
x := ArgToFloat(Args[0]);
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
if InRange(x, -1, +1) then
|
if InRange(x, -1, +1) then
|
||||||
Result := FloatResult(arcsin(ArgToFloat(Args[0])))
|
Result := FloatResult(arcsin(x))
|
||||||
else
|
else
|
||||||
Result := ErrorResult(errOverflow);
|
Result := ErrorResult(errOverflow);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsASINH(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsASINH(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
Result := FloatResult(arcsinh(ArgToFloat(Args[0])));
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(arcsinh(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsATAN(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsATAN(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
Result := FloatResult(arctan(ArgToFloat(Args[0])));
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(arctan(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsATANH(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsATANH(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
@ -79,8 +106,11 @@ var
|
|||||||
x: TsExprFloat;
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
x := ArgToFloat(Args[0]);
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
if (x > -1) and (x < +1) then
|
if (x > -1) and (x < +1) then
|
||||||
Result := FloatResult(arctanh(ArgToFloat(Args[0])))
|
Result := FloatResult(arctanh(x))
|
||||||
else
|
else
|
||||||
Result := ErrorResult(errOverflow); // #NUM!
|
Result := ErrorResult(errOverflow); // #NUM!
|
||||||
end;
|
end;
|
||||||
@ -93,6 +123,9 @@ var
|
|||||||
begin
|
begin
|
||||||
num := ArgToFloat(Args[0]);
|
num := ArgToFloat(Args[0]);
|
||||||
sig := ArgToFloat(Args[1]);
|
sig := ArgToFloat(Args[1]);
|
||||||
|
if IsNaN(num) or IsNaN(sig) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
if sig = 0 then
|
if sig = 0 then
|
||||||
Result := ErrorResult(errDivideByZero)
|
Result := ErrorResult(errDivideByZero)
|
||||||
else
|
else
|
||||||
@ -100,18 +133,36 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsCOS(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsCOS(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
Result := FloatResult(cos(ArgToFloat(Args[0])));
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(cos(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsCOSH(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsCOSH(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
Result := FloatResult(cosh(ArgToFloat(Args[0])));
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(cosh(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsDEGREES(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsDEGREES(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
Result := FloatResult(RadToDeg(ArgToFloat(Args[0])));
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(RadToDeg(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsEVEN(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsEVEN(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
@ -124,6 +175,9 @@ var
|
|||||||
begin
|
begin
|
||||||
if Args[0].ResultType in [rtCell, rtInteger, rtFloat, rtDateTime, rtEmpty] then begin
|
if Args[0].ResultType in [rtCell, rtInteger, rtFloat, rtDateTime, rtEmpty] then begin
|
||||||
x := ArgToFloat(Args[0]);
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
if x > 0 then
|
if x > 0 then
|
||||||
begin
|
begin
|
||||||
n := Trunc(x) + 1;
|
n := Trunc(x) + 1;
|
||||||
@ -142,8 +196,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsEXP(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsEXP(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
Result := FloatResult(exp(ArgToFloat(Args[0])));
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(exp(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsFACT(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsFACT(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
@ -179,6 +239,9 @@ var
|
|||||||
begin
|
begin
|
||||||
num := ArgToFloat(Args[0]);
|
num := ArgToFloat(Args[0]);
|
||||||
sig := ArgToFloat(Args[1]);
|
sig := ArgToFloat(Args[1]);
|
||||||
|
if IsNaN(num) or IsNaN(sig) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
if sig = 0 then
|
if sig = 0 then
|
||||||
Result := ErrorResult(errDivideByZero)
|
Result := ErrorResult(errDivideByZero)
|
||||||
else
|
else
|
||||||
@ -186,8 +249,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsINT(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsINT(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
Result := FloatResult(floor(ArgToFloat(Args[0])));
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(floor(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsLN(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsLN(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
@ -195,6 +264,9 @@ var
|
|||||||
x: TsExprFloat;
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
x := ArgToFloat(Args[0]);
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
if x > 0 then
|
if x > 0 then
|
||||||
Result := FloatResult(ln(x))
|
Result := FloatResult(ln(x))
|
||||||
else
|
else
|
||||||
@ -208,6 +280,11 @@ var
|
|||||||
base: TsExprFloat;
|
base: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
x := ArgToFloat(Args[0]);
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then begin
|
||||||
|
Result := ErrorResult(errWrongType);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
if x <= 0 then begin
|
if x <= 0 then begin
|
||||||
Result := ErrorResult(errOverflow); // #NUM!
|
Result := ErrorResult(errOverflow); // #NUM!
|
||||||
exit;
|
exit;
|
||||||
@ -221,6 +298,10 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
base := ArgToFloat(Args[1]);
|
base := ArgToFloat(Args[1]);
|
||||||
|
if IsNaN(base) then begin
|
||||||
|
Result := ErrorResult(errWrongType);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
if base < 0 then begin
|
if base < 0 then begin
|
||||||
Result := ErrorResult(errOverflow); // #NUM!
|
Result := ErrorResult(errOverflow); // #NUM!
|
||||||
exit;
|
exit;
|
||||||
@ -236,6 +317,9 @@ var
|
|||||||
x: TsExprFloat;
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
x := ArgToFloat(Args[0]);
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType) // #VALUE!
|
||||||
|
else
|
||||||
if x > 0 then
|
if x > 0 then
|
||||||
Result := FloatResult(log10(x))
|
Result := FloatResult(log10(x))
|
||||||
else
|
else
|
||||||
@ -267,6 +351,9 @@ begin
|
|||||||
if Args[0].ResultType in [rtCell, rtInteger, rtFloat, rtDateTime, rtEmpty] then
|
if Args[0].ResultType in [rtCell, rtInteger, rtFloat, rtDateTime, rtEmpty] then
|
||||||
begin
|
begin
|
||||||
x := ArgToFloat(Args[0]);
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
if x >= 0 then
|
if x >= 0 then
|
||||||
begin
|
begin
|
||||||
n := Trunc(x) + 1;
|
n := Trunc(x) + 1;
|
||||||
@ -289,17 +376,30 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsPOWER(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsPOWER(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x, y: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
try
|
x := ArgToFloat(Args[0]);
|
||||||
Result := FloatResult(Power(ArgToFloat(Args[0]), ArgToFloat(Args[1])));
|
y := ArgToFloat(Args[1]);
|
||||||
except
|
if IsNaN(x) or IsNaN(y) then
|
||||||
Result := ErrorResult(errOverflow);
|
Result := ErrorResult(errWrongType)
|
||||||
end;
|
else
|
||||||
|
try
|
||||||
|
Result := FloatResult(Power(x, y));
|
||||||
|
except
|
||||||
|
Result := ErrorResult(errOverflow);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsRADIANS(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsRADIANS(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
Result := FloatResult(DegToRad(ArgToFloat(Args[0])));
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(DegToRad(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsRAND(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsRAND(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
@ -310,28 +410,54 @@ end;
|
|||||||
|
|
||||||
procedure fpsROUND(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsROUND(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
var
|
var
|
||||||
x: Double;
|
x: TsExprFloat;
|
||||||
n: Integer;
|
n: Integer;
|
||||||
begin
|
begin
|
||||||
x := ArgToFloat(Args[0]);
|
x := ArgToFloat(Args[1]);
|
||||||
n := Round(ArgToFloat(Args[1]));
|
if IsNaN(x) then
|
||||||
Result := FloatResult(RoundTo(x, -n));
|
Result := ErrorResult(errWrongType)
|
||||||
// -n because fpc and Excel have different conventions regarding the sign
|
else begin
|
||||||
|
n := Round(x);
|
||||||
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(RoundTo(x, -n));
|
||||||
|
// -n because fpc and Excel have different conventions regarding the sign
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsSIGN(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsSIGN(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
Result := FloatResult(sign(ArgToFloat(Args[0])));
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(sign(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsSIN(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsSIN(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
Result := FloatResult(sin(ArgToFloat(Args[0])));
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(sin(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsSINH(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsSINH(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
Result := FloatResult(sinh(ArgToFloat(Args[0])));
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(sinh(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsSQRT(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsSQRT(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
@ -339,6 +465,9 @@ var
|
|||||||
x: TsExprFloat;
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
x := ArgToFloat(Args[0]);
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
if x >= 0 then
|
if x >= 0 then
|
||||||
Result := FloatResult(sqrt(x))
|
Result := FloatResult(sqrt(x))
|
||||||
else
|
else
|
||||||
@ -350,15 +479,24 @@ var
|
|||||||
x: TsExprFloat;
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
x := ArgToFloat(Args[0]);
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
if frac(x / (pi*0.5)) = 0 then
|
if frac(x / (pi*0.5)) = 0 then
|
||||||
Result := ErrorResult(errOverflow) // #NUM!
|
Result := ErrorResult(errOverflow) // #NUM!
|
||||||
else
|
else
|
||||||
Result := FloatResult(tan(ArgToFloat(Args[0])));
|
Result := FloatResult(tan(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure fpsTANH(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
procedure fpsTANH(var Result: TsExpressionResult; const Args: TsExprParameterArray);
|
||||||
|
var
|
||||||
|
x: TsExprFloat;
|
||||||
begin
|
begin
|
||||||
Result := FloatResult(tanh(ArgToFloat(Args[0])));
|
x := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(x) then
|
||||||
|
Result := ErrorResult(errWrongType)
|
||||||
|
else
|
||||||
|
Result := FloatResult(tanh(x));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -1956,6 +2094,127 @@ begin
|
|||||||
Result.ResultType := rtHyperlink;
|
Result.ResultType := rtHyperlink;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure fpsMATCH(var Result: TsExpressionResult;
|
||||||
|
const Args: TsExprParameterArray);
|
||||||
|
{ MATCH( value, array, [match_type]
|
||||||
|
match_type = 1 (default): The MATCH function will find the largest value
|
||||||
|
that is less than or equal to value. You should be sure to sort your
|
||||||
|
array in ascending order.
|
||||||
|
match_type = 0: The MATCH function will find the first value that is equal to
|
||||||
|
value. The array can be sorted in any order.)
|
||||||
|
match_type = -1: The MATCH function will find the smallest value that is
|
||||||
|
greater than or equal to value. You should be sure to sort your array in
|
||||||
|
descending order. }
|
||||||
|
var
|
||||||
|
match_type: Integer;
|
||||||
|
searchString: String;
|
||||||
|
numSearchValue: Double = 0.0;
|
||||||
|
r1,c1,r2,c2: Cardinal;
|
||||||
|
r, c: Integer;
|
||||||
|
IsCol: Boolean;
|
||||||
|
arg: TsExpressionResult;
|
||||||
|
sheet: TsWorksheet;
|
||||||
|
book: TsWorkbook;
|
||||||
|
f: TsRelFlags;
|
||||||
|
|
||||||
|
function Matches(ACell: PCell): Boolean;
|
||||||
|
var
|
||||||
|
cellval: Double;
|
||||||
|
s: String;
|
||||||
|
|
||||||
|
ok: boolean;
|
||||||
|
begin
|
||||||
|
Result := false;
|
||||||
|
if ACell = nil then exit;
|
||||||
|
if ACell^.ContentType = cctUTF8String then begin
|
||||||
|
s := ACell^.UTF8StringValue;
|
||||||
|
if IsWild(searchString, '*?', false) then
|
||||||
|
Result := FindPart(searchString, s) > 0
|
||||||
|
// NOTE: FindPart currently supports only the wildcard '?'
|
||||||
|
else
|
||||||
|
Result := SameStr(s, searchString);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
case ACell^.ContentType of
|
||||||
|
cctNumber: cellval := ACell^.Numbervalue;
|
||||||
|
cctDateTime: cellval := ACell^.DateTimeValue;
|
||||||
|
cctBool: cellval := double(ord(ACell^.BoolValue));
|
||||||
|
cctError: cellval := double(ord(ACell^.ErrorValue));
|
||||||
|
cctEmpty: exit;
|
||||||
|
end;
|
||||||
|
case match_type of
|
||||||
|
1 : Result := cellval <= numSearchValue;
|
||||||
|
0 : Result := cellval = numSearchValue;
|
||||||
|
-1 : Result := cellval >= numSearchValue;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
ok := result;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Result := ErrorResult(errArgError);
|
||||||
|
|
||||||
|
if Length(Args) > 2 then
|
||||||
|
match_type := ArgToInt(Args[2])
|
||||||
|
else
|
||||||
|
match_type := 1;
|
||||||
|
if not ((match_type in [0, 1]) or (match_type = -1)) then
|
||||||
|
match_type := 1;
|
||||||
|
|
||||||
|
arg := Args[1];
|
||||||
|
if arg.ResultType <> rtCellRange then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
if arg.ResCellRange.Sheet1 <> arg.ResCellRange.Sheet2 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
r1 := arg.ResCellRange.Row1;
|
||||||
|
r2 := arg.ResCellRange.Row2;
|
||||||
|
c1 := arg.ResCellRange.Col1;
|
||||||
|
c2 := arg.ResCellRange.Col2;
|
||||||
|
|
||||||
|
if r1=r2 then
|
||||||
|
IsCol := false
|
||||||
|
else
|
||||||
|
if c1=c2 then
|
||||||
|
IsCol := true
|
||||||
|
else begin
|
||||||
|
Result := ErrorResult(errArgError);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
sheet := arg.Worksheet as TsWorksheet;
|
||||||
|
book := sheet.Workbook as TsWorkbook;
|
||||||
|
sheet := book.GetWorksheetByIndex(arg.ResCellRange.Sheet1);
|
||||||
|
|
||||||
|
if Args[0].ResultType = rtString then
|
||||||
|
searchString := ArgToString(Args[0])
|
||||||
|
else begin
|
||||||
|
numSearchvalue := ArgToFloat(Args[0]);
|
||||||
|
if IsNaN(numSearchValue) then begin
|
||||||
|
Result := ErrorResult(errWrongType);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if IsCol then
|
||||||
|
begin
|
||||||
|
for r := r2 downto r1 do
|
||||||
|
if Matches(sheet.FindCell(r, c1)) then begin
|
||||||
|
Result := IntegerResult(r - integer(r1) + 1);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
for c := c2 downto c1 do
|
||||||
|
if Matches(sheet.FindCell(r1, c)) then begin
|
||||||
|
Result := IntegerResult(c - Integer(c1) + 1);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// If the procedure gets here, not match has been found --> return error #N/A
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{------------------------------------------------------------------------------}
|
{------------------------------------------------------------------------------}
|
||||||
{ Registration }
|
{ Registration }
|
||||||
@ -2085,6 +2344,7 @@ begin
|
|||||||
// Lookup / reference functions
|
// Lookup / reference functions
|
||||||
cat := bcLookup;
|
cat := bcLookup;
|
||||||
AddFunction(cat, 'HYPERLINK', 'S', 'Ss', INT_EXCEL_SHEET_FUNC_HYPERLINK, @fpsHYPERLINK);
|
AddFunction(cat, 'HYPERLINK', 'S', 'Ss', INT_EXCEL_SHEET_FUNC_HYPERLINK, @fpsHYPERLINK);
|
||||||
|
AddFunction(cat, 'MATCH', 'I', 'SRi', INT_EXCEL_SHEET_FUNC_MATCH, @fpsMATCH);
|
||||||
|
|
||||||
(*
|
(*
|
||||||
AddFunction(cat, 'COLUMN', 'I', 'R', INT_EXCEL_SHEET_FUNC_COLUMN, @fpsCOLUMN);
|
AddFunction(cat, 'COLUMN', 'I', 'R', INT_EXCEL_SHEET_FUNC_COLUMN, @fpsCOLUMN);
|
||||||
|
@ -274,7 +274,7 @@ type
|
|||||||
errIllegalRef, // #REF!
|
errIllegalRef, // #REF!
|
||||||
errWrongName, // #NAME?
|
errWrongName, // #NAME?
|
||||||
errOverflow, // #NUM!
|
errOverflow, // #NUM!
|
||||||
errArgError, // #N/A
|
errArgError, // #N/A ( = #NV in German )
|
||||||
// --- no Excel errors --
|
// --- no Excel errors --
|
||||||
errFormulaNotSupported
|
errFormulaNotSupported
|
||||||
);
|
);
|
||||||
|
@ -2468,7 +2468,7 @@ begin
|
|||||||
Result.DateSeparator := DateSeparator;
|
Result.DateSeparator := DateSeparator;
|
||||||
Result.TimeSeparator := TimeSeparator;
|
Result.TimeSeparator := TimeSeparator;
|
||||||
Result.ShortDateFormat := ShortDateFormat; //'yyyy/m/d'; // the parser returns single digits
|
Result.ShortDateFormat := ShortDateFormat; //'yyyy/m/d'; // the parser returns single digits
|
||||||
Result.LongTimeFormat := LongTimeFormat; //'h:n:s';
|
Result.LongTimeFormat := LongTimeFormat; //'h:n:s';
|
||||||
Result.ShortTimeFormat := ShortTimeFormat; //'h:n';
|
Result.ShortTimeFormat := ShortTimeFormat; //'h:n';
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -150,7 +150,7 @@ const
|
|||||||
INT_EXCEL_SHEET_FUNC_MIRR = 61;
|
INT_EXCEL_SHEET_FUNC_MIRR = 61;
|
||||||
INT_EXCEL_SHEET_FUNC_IRR = 62;
|
INT_EXCEL_SHEET_FUNC_IRR = 62;
|
||||||
INT_EXCEL_SHEET_FUNC_RAND = 63;
|
INT_EXCEL_SHEET_FUNC_RAND = 63;
|
||||||
INT_EXCLE_SHEET_FUNC_MATCH = 64;
|
INT_EXCEL_SHEET_FUNC_MATCH = 64;
|
||||||
INT_EXCEL_SHEET_FUNC_DATE = 65; // $41
|
INT_EXCEL_SHEET_FUNC_DATE = 65; // $41
|
||||||
INT_EXCEL_SHEET_FUNC_TIME = 66; // $42
|
INT_EXCEL_SHEET_FUNC_TIME = 66; // $42
|
||||||
INT_EXCEL_SHEET_FUNC_DAY = 67;
|
INT_EXCEL_SHEET_FUNC_DAY = 67;
|
||||||
|
@ -14,7 +14,8 @@ uses
|
|||||||
|
|
||||||
type
|
type
|
||||||
TFormulaTestKind = (ftkConstants, ftkCellConstant, ftkCells, ftkCellRange,
|
TFormulaTestKind = (ftkConstants, ftkCellConstant, ftkCells, ftkCellRange,
|
||||||
ftkCellRangeSheet, ftkCellRangeSheetRange);
|
ftkCellRangeSheet, ftkCellRangeSheetRange,
|
||||||
|
ftkSortedNumbersASC, ftkSortedNumbersDESC);
|
||||||
TWorksheetTestKind = (wtkRenameWorksheet, wtkDeleteWorksheet);
|
TWorksheetTestKind = (wtkRenameWorksheet, wtkDeleteWorksheet);
|
||||||
|
|
||||||
{ TSpreadDetailedFormulaFormula }
|
{ TSpreadDetailedFormulaFormula }
|
||||||
@ -94,6 +95,12 @@ type
|
|||||||
|
|
||||||
procedure SumIfRangeSheetSheet_BIFF8;
|
procedure SumIfRangeSheetSheet_BIFF8;
|
||||||
|
|
||||||
|
procedure MatchColASC_BIFF8;
|
||||||
|
procedure MatchColDESC_BIFF8;
|
||||||
|
procedure MatchCol0_BIFF8;
|
||||||
|
procedure MatchRowASC_BIFF8;
|
||||||
|
procedure MatchRowDESC_BIFF8;
|
||||||
|
|
||||||
procedure NonExistantSheet_BIFF5;
|
procedure NonExistantSheet_BIFF5;
|
||||||
procedure NonExistantSheet_BIFF8;
|
procedure NonExistantSheet_BIFF8;
|
||||||
procedure NonExistantSheet_OOXML;
|
procedure NonExistantSheet_OOXML;
|
||||||
@ -170,6 +177,7 @@ const
|
|||||||
SHEET1 = 'Sheet1';
|
SHEET1 = 'Sheet1';
|
||||||
SHEET2 = 'Sheet2';
|
SHEET2 = 'Sheet2';
|
||||||
SHEET3 = 'Sheet3';
|
SHEET3 = 'Sheet3';
|
||||||
|
SHEET4 = 'Sheet4';
|
||||||
TESTCELL_ROW = 1; // Cell with formula: C2
|
TESTCELL_ROW = 1; // Cell with formula: C2
|
||||||
TESTCELL_COL = 2;
|
TESTCELL_COL = 2;
|
||||||
var
|
var
|
||||||
@ -213,12 +221,37 @@ begin
|
|||||||
|
|
||||||
if ATestKind = ftkCellRangeSheetRange then begin
|
if ATestKind = ftkCellRangeSheetRange then begin
|
||||||
otherSheet := Workbook.AddWorksheet(SHEET3);
|
otherSheet := Workbook.AddWorksheet(SHEET3);
|
||||||
othersheet.WriteNumber(2, 2, 100.0); // Sheet3C3
|
othersheet.WriteNumber(2, 2, 100.0); // Sheet3!C3
|
||||||
othersheet.WriteNumber(3, 2, -200.0); // Sheet3!C4
|
othersheet.WriteNumber(3, 2, -200.0); // Sheet3!C4
|
||||||
othersheet.WriteNumber(4, 2, 150.0); // Sheet3!C5
|
othersheet.WriteNumber(4, 2, 150.0); // Sheet3!C5
|
||||||
othersheet.WriteNumber(2, 3, 1500.0); // Sheet3!D5
|
othersheet.WriteNumber(2, 3, 1500.0); // Sheet3!D5
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if ATestkind = ftkSortedNumbersAsc then begin
|
||||||
|
othersheet := Workbook.AddWorksheet(SHEET4);
|
||||||
|
othersheet.WriteNumber(2, 2, 10.0); // Sheet4!C3
|
||||||
|
othersheet.WriteNumber(3, 2, 12.0); // Sheet4!C4
|
||||||
|
othersheet.WriteNumber(4, 2, 15.0); // Sheet4!C5
|
||||||
|
othersheet.WriteNumber(5, 2, 20.0); // Sheet4!C6
|
||||||
|
othersheet.WriteNumber(6, 2, 25.0); // Sheet4!C7
|
||||||
|
othersheet.WriteNumber(2, 3, 12.0); // Sheet4!D3
|
||||||
|
othersheet.WriteNumber(2, 4, 15.0); // Sheet4!E3
|
||||||
|
othersheet.WriteNumber(2, 5, 20.0); // Sheet4!F3
|
||||||
|
othersheet.WriteNumber(2, 6, 25.0); // Sheet4!G3
|
||||||
|
end else
|
||||||
|
if ATestkind = ftkSortedNumbersDesc then begin
|
||||||
|
othersheet := Workbook.AddWorksheet(SHEET4);
|
||||||
|
othersheet.WriteNumber(2, 2, 25.0); // Sheet4!C3
|
||||||
|
othersheet.WriteNumber(3, 2, 20.0); // Sheet4!C4
|
||||||
|
othersheet.WriteNumber(4, 2, 15.0); // Sheet4!C5
|
||||||
|
othersheet.WriteNumber(5, 2, 12.0); // Sheet4!C6
|
||||||
|
othersheet.WriteNumber(6, 2, 10.0); // Sheet4!C7
|
||||||
|
othersheet.WriteNumber(2, 3, 20.0); // Sheet4!D3
|
||||||
|
othersheet.WriteNumber(2, 4, 15.0); // Sheet4!E3
|
||||||
|
othersheet.WriteNumber(2, 5, 12.0); // Sheet4!F3
|
||||||
|
othersheet.WriteNumber(2, 6, 10.0); // Sheet4!G3
|
||||||
|
end;
|
||||||
|
|
||||||
// Write the formula
|
// Write the formula
|
||||||
cell := worksheet.WriteFormula(TESTCELL_ROW, TESTCELL_COL, AFormula);
|
cell := worksheet.WriteFormula(TESTCELL_ROW, TESTCELL_COL, AFormula);
|
||||||
|
|
||||||
@ -562,6 +595,33 @@ end;
|
|||||||
|
|
||||||
{ ---- }
|
{ ---- }
|
||||||
|
|
||||||
|
procedure TSpreadSingleFormulaTests.MatchColASC_BIFF8;
|
||||||
|
begin //10,12,15,20,25
|
||||||
|
TestFormula('MATCH(12.5,Sheet4!C3:C7,1)', '2', ftkSortedNumbersASC, sfExcel8);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadSingleFormulaTests.MatchColDESC_BIFF8;
|
||||||
|
begin //25,20,15,12,10
|
||||||
|
TestFormula('MATCH(12.5,Sheet4!C3:C7,-1)', '3', ftkSortedNumbersDESC, sfExcel8);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadSingleFormulaTests.MatchCol0_BIFF8;
|
||||||
|
begin //10,12,15,20,25
|
||||||
|
TestFormula('MATCH(12,Sheet4!C3:C7,0)', '2', ftkSortedNumbersASC, sfExcel8);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadSingleFormulaTests.MatchRowASC_BIFF8;
|
||||||
|
begin
|
||||||
|
TestFormula('MATCH(12,Sheet4!C3:G3,1)', '2', ftkSortedNumbersASC, sfExcel8);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadSingleFormulaTests.MatchRowDESC_BIFF8;
|
||||||
|
begin
|
||||||
|
TestFormula('MATCH(12,Sheet4!C3:G3,-1)', '4', ftkSortedNumbersDESC, sfExcel8);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ --- }
|
||||||
|
|
||||||
procedure TSpreadSingleFormulaTests.NonExistantSheet_BIFF5;
|
procedure TSpreadSingleFormulaTests.NonExistantSheet_BIFF5;
|
||||||
begin
|
begin
|
||||||
TestFormula('Missing!C3', '#REF!', ftkCellRangeSheet, sfExcel5, '#REF!');
|
TestFormula('Missing!C3', '#REF!', ftkCellRangeSheet, sfExcel5, '#REF!');
|
||||||
@ -942,9 +1002,9 @@ begin
|
|||||||
try
|
try
|
||||||
book.Options := book.Options + [boAutoCalc];
|
book.Options := book.Options + [boAutoCalc];
|
||||||
sheet := book.AddWorksheet('Test');
|
sheet := book.AddWorksheet('Test');
|
||||||
sheet.WriteText(0, 0, 'abc'); // A1 = 'abc'
|
sheet.WriteText(0, 0, 'abc'); // A1 = 'abc'
|
||||||
sheet.WriteNumber(1, 0, 1.0); // A2 = 1.0
|
sheet.WriteNumber(1, 0, 1.0); // A2 = 1.0
|
||||||
sheet.WriteText(2, 0, '1'); // A2 = '1';
|
sheet.WriteText(2, 0, '1'); // A2 = '1';
|
||||||
sheet.WriteFormula(0, 1, TestCases[ATest].Formula);
|
sheet.WriteFormula(0, 1, TestCases[ATest].Formula);
|
||||||
s := sheet.ReadAsText(0, 1);
|
s := sheet.ReadAsText(0, 1);
|
||||||
CheckEquals(TestCases[ATest].Expected, s, 'Error value match, formula "' + sheet.ReadFormula(0, 1) + '"');
|
CheckEquals(TestCases[ATest].Expected, s, 'Error value match, formula "' + sheet.ReadFormula(0, 1) + '"');
|
||||||
|
@ -6,7 +6,6 @@ program spreadtestgui;
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
{$IFDEF HEAPTRC}
|
{$IFDEF HEAPTRC}
|
||||||
//HeapTrc,
|
|
||||||
SysUtils,
|
SysUtils,
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
Interfaces, Forms, GuiTestRunner, testsutility,
|
Interfaces, Forms, GuiTestRunner, testsutility,
|
||||||
|
Loading…
Reference in New Issue
Block a user