You've already forked lazarus-ccr
fpspreadsheet: Beginning to add cells to calculation of rpn formulas.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3267 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -8,11 +8,12 @@ uses
|
|||||||
Classes, SysUtils, fpspreadsheet;
|
Classes, SysUtils, fpspreadsheet;
|
||||||
|
|
||||||
type
|
type
|
||||||
TsArgumentType = (atNumber, atString, atBool, atError, atEmpty);
|
TsArgumentType = (atCell, atNumber, atString, atBool, atError, atEmpty);
|
||||||
|
|
||||||
TsArgument = record
|
TsArgument = record
|
||||||
IsMissing: Boolean;
|
IsMissing: Boolean;
|
||||||
case ArgumentType: TsArgumentType of
|
case ArgumentType: TsArgumentType of
|
||||||
|
atCell : (Cell: PCell);
|
||||||
atNumber : (NumberValue: Double);
|
atNumber : (NumberValue: Double);
|
||||||
atString : (StringValue: String);
|
atString : (StringValue: String);
|
||||||
atBool : (BoolValue: Boolean);
|
atBool : (BoolValue: Boolean);
|
||||||
@ -26,6 +27,7 @@ type
|
|||||||
function Pop: TsArgument;
|
function Pop: TsArgument;
|
||||||
procedure Push(AValue: TsArgument);
|
procedure Push(AValue: TsArgument);
|
||||||
procedure PushBool(AValue: Boolean);
|
procedure PushBool(AValue: Boolean);
|
||||||
|
procedure PushCell(AValue: PCell);
|
||||||
procedure PushMissing;
|
procedure PushMissing;
|
||||||
procedure PushNumber(AValue: Double);
|
procedure PushNumber(AValue: Double);
|
||||||
procedure PushString(AValue: String);
|
procedure PushString(AValue: String);
|
||||||
@ -133,6 +135,7 @@ function fpsSUBSTITUTE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|||||||
function fpsTRIM (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
function fpsTRIM (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||||
function fpsUPPER (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
function fpsUPPER (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||||
{ info functions }
|
{ info functions }
|
||||||
|
function fpsCELLINFO (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||||
function fpsISERR (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
function fpsISERR (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||||
function fpsISERROR (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
function fpsISERROR (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||||
function fpsISLOGICAL (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
function fpsISLOGICAL (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||||
@ -152,6 +155,55 @@ type
|
|||||||
TFloatArray = array of double;
|
TFloatArray = array of double;
|
||||||
TStrArray = array of string;
|
TStrArray = array of string;
|
||||||
|
|
||||||
|
{ Helpers }
|
||||||
|
|
||||||
|
function CreateArgument: TsArgument;
|
||||||
|
begin
|
||||||
|
FillChar(Result, SizeOf(Result), 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CreateBool(AValue: Boolean): TsArgument;
|
||||||
|
begin
|
||||||
|
Result := CreateArgument;
|
||||||
|
Result.ArgumentType := atBool;
|
||||||
|
Result.Boolvalue := AValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CreateCell(AValue: PCell): TsArgument;
|
||||||
|
begin
|
||||||
|
Result := CreateArgument;
|
||||||
|
Result.ArgumentType := atCell;
|
||||||
|
Result.Cell := AValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CreateNumber(AValue: Double): TsArgument;
|
||||||
|
begin
|
||||||
|
Result := CreateArgument;
|
||||||
|
Result.ArgumentType := atNumber;
|
||||||
|
Result.NumberValue := AValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CreateString(AValue: String): TsArgument;
|
||||||
|
begin
|
||||||
|
Result := CreateArgument;
|
||||||
|
Result.ArgumentType := atString;
|
||||||
|
Result.StringValue := AValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CreateError(AError: TsErrorValue): TsArgument;
|
||||||
|
begin
|
||||||
|
Result := CreateArgument;
|
||||||
|
Result.ArgumentType := atError;
|
||||||
|
Result.ErrorValue := AError;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CreateEmpty: TsArgument;
|
||||||
|
begin
|
||||||
|
Result := CreateArgument;
|
||||||
|
Result.ArgumentType := atEmpty;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TsArgumentStack }
|
{ TsArgumentStack }
|
||||||
|
|
||||||
destructor TsArgumentStack.Destroy;
|
destructor TsArgumentStack.Destroy;
|
||||||
@ -181,60 +233,53 @@ end;
|
|||||||
|
|
||||||
function TsArgumentStack.Pop: TsArgument;
|
function TsArgumentStack.Pop: TsArgument;
|
||||||
var
|
var
|
||||||
P: PsArgument;
|
arg: PsArgument;
|
||||||
begin
|
begin
|
||||||
P := PsArgument(Items[Count-1]);
|
arg := PsArgument(Items[Count-1]);
|
||||||
Result := P^;
|
Result := arg^;
|
||||||
Result.StringValue := P^.StringValue; // necessary?
|
Result.StringValue := arg^.StringValue; // necessary?
|
||||||
|
Result.Cell := arg^.Cell;
|
||||||
Delete(Count-1);
|
Delete(Count-1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsArgumentStack.Push(AValue: TsArgument);
|
procedure TsArgumentStack.Push(AValue: TsArgument);
|
||||||
var
|
var
|
||||||
P: PsArgument;
|
arg: PsArgument;
|
||||||
begin
|
begin
|
||||||
GetMem(P, SizeOf(TsArgument));
|
GetMem(arg, SizeOf(TsArgument));
|
||||||
P^ := AValue;
|
arg^ := AValue;
|
||||||
P^.StringValue := AValue.StringValue;
|
arg^.StringValue := AValue.StringValue;
|
||||||
Add(P);
|
arg^.Cell := AValue.Cell;
|
||||||
|
Add(arg);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsArgumentStack.PushBool(AValue: Boolean);
|
procedure TsArgumentStack.PushBool(AValue: Boolean);
|
||||||
var
|
|
||||||
arg: TsArgument;
|
|
||||||
begin
|
begin
|
||||||
arg.ArgumentType := atBool;
|
Push(CreateBool(AValue));
|
||||||
arg.BoolValue := AValue;
|
end;
|
||||||
arg.IsMissing := false;
|
|
||||||
Push(arg);
|
procedure TsArgumentStack.PushCell(AValue: PCell);
|
||||||
|
begin
|
||||||
|
Push(CreateCell(AValue));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsArgumentStack.PushMissing;
|
procedure TsArgumentStack.PushMissing;
|
||||||
var
|
var
|
||||||
arg: TsArgument;
|
arg: TsArgument;
|
||||||
begin
|
begin
|
||||||
|
arg := CreateArgument;
|
||||||
arg.IsMissing := true;
|
arg.IsMissing := true;
|
||||||
Push(arg);
|
Push(arg);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsArgumentStack.PushNumber(AValue: Double);
|
procedure TsArgumentStack.PushNumber(AValue: Double);
|
||||||
var
|
|
||||||
arg: TsArgument;
|
|
||||||
begin
|
begin
|
||||||
arg.ArgumentType := atNumber;
|
Push(CreateNumber(AValue));
|
||||||
arg.NumberValue := AValue;
|
|
||||||
arg.IsMissing := false;
|
|
||||||
Push(arg);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsArgumentStack.PushString(AValue: String);
|
procedure TsArgumentStack.PushString(AValue: String);
|
||||||
var
|
|
||||||
arg: TsArgument;
|
|
||||||
begin
|
begin
|
||||||
arg.ArgumentType := atString;
|
Push(CreateString(AValue));
|
||||||
arg.StringValue := AValue;
|
|
||||||
arg.IsMissing := false;
|
|
||||||
Push(arg);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -242,11 +287,12 @@ end;
|
|||||||
|
|
||||||
function GetBoolFromArgument(Arg: TsArgument; var AValue: Boolean): TsErrorValue;
|
function GetBoolFromArgument(Arg: TsArgument; var AValue: Boolean): TsErrorValue;
|
||||||
begin
|
begin
|
||||||
|
Result := errOK;
|
||||||
case Arg.ArgumentType of
|
case Arg.ArgumentType of
|
||||||
atBool : begin
|
atBool : AValue := Arg.BoolValue;
|
||||||
AValue := Arg.BoolValue;
|
atCell : if (Arg.Cell <> nil) and (Arg.Cell^.ContentType = cctBool)
|
||||||
Result := errOK;
|
then AValue := Arg.Cell^.BoolValue
|
||||||
end;
|
else Result := errWrongType;
|
||||||
atError: Result := Arg.ErrorValue;
|
atError: Result := Arg.ErrorValue;
|
||||||
else Result := errWrongType;
|
else Result := errWrongType;
|
||||||
end;
|
end;
|
||||||
@ -259,56 +305,31 @@ begin
|
|||||||
atNumber : ANumber := Arg.NumberValue;
|
atNumber : ANumber := Arg.NumberValue;
|
||||||
atString : if not TryStrToFloat(arg.StringValue, ANumber) then Result := errWrongType;
|
atString : if not TryStrToFloat(arg.StringValue, ANumber) then Result := errWrongType;
|
||||||
atBool : if Arg.BoolValue then ANumber := 1.0 else ANumber := 0.0;
|
atBool : if Arg.BoolValue then ANumber := 1.0 else ANumber := 0.0;
|
||||||
|
atCell : if (Arg.Cell <> nil) then
|
||||||
|
case Arg.Cell^.ContentType of
|
||||||
|
cctNumber : ANumber := Arg.Cell^.NumberValue;
|
||||||
|
cctDateTime: ANumber := Arg.Cell^.DateTimeValue;
|
||||||
|
cctBool : if Arg.Cell^.BoolValue then ANumber := 1.0 else ANumber := 0.0;
|
||||||
|
else Result := errWrongType;
|
||||||
|
end;
|
||||||
atError : Result := Arg.ErrorValue;
|
atError : Result := Arg.ErrorValue;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function GetStringFromArgument(Arg: TsArgument; var AString: String): TsErrorValue;
|
function GetStringFromArgument(Arg: TsArgument; var AString: String): TsErrorValue;
|
||||||
begin
|
begin
|
||||||
|
Result := errOK;
|
||||||
case Arg.ArgumentType of
|
case Arg.ArgumentType of
|
||||||
atString : begin
|
atString : AString := Arg.StringValue;
|
||||||
AString := Arg.StringValue;
|
atCell : if (Arg.Cell <> nil) and (Arg.Cell^.ContentType = cctUTF8String) then
|
||||||
Result := errOK;
|
AString := Arg.Cell^.UTF8StringValue
|
||||||
end;
|
else
|
||||||
|
Result := errWrongType;
|
||||||
atError : Result := Arg.ErrorValue;
|
atError : Result := Arg.ErrorValue;
|
||||||
else Result := errWrongType;
|
else Result := errWrongType;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function CreateBool(AValue: Boolean): TsArgument;
|
|
||||||
begin
|
|
||||||
Result.ArgumentType := atBool;
|
|
||||||
Result.Boolvalue := AValue;
|
|
||||||
Result.IsMissing := false;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function CreateNumber(AValue: Double): TsArgument;
|
|
||||||
begin
|
|
||||||
Result.ArgumentType := atNumber;
|
|
||||||
Result.NumberValue := AValue;
|
|
||||||
Result.IsMissing := false;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function CreateString(AValue: String): TsArgument;
|
|
||||||
begin
|
|
||||||
Result.ArgumentType := atString;
|
|
||||||
Result.StringValue := AValue;
|
|
||||||
Result.IsMissing := false;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function CreateError(AError: TsErrorValue): TsArgument;
|
|
||||||
begin
|
|
||||||
Result.ArgumentType := atError;
|
|
||||||
Result.ErrorValue := AError;
|
|
||||||
Result.IsMissing := false;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function CreateEmpty: TsArgument;
|
|
||||||
begin
|
|
||||||
Result.ArgumentType := atEmpty;
|
|
||||||
Result.IsMissing := false;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
Pops boolean values from the argument stack. Is called when calculating rpn
|
Pops boolean values from the argument stack. Is called when calculating rpn
|
||||||
formulas.
|
formulas.
|
||||||
@ -381,7 +402,17 @@ begin
|
|||||||
begin
|
begin
|
||||||
Result := TryStrToDate(arg.StringValue, ADate);
|
Result := TryStrToDate(arg.StringValue, ADate);
|
||||||
if not Result then AErrArg := CreateError(errWrongType);
|
if not Result then AErrArg := CreateError(errWrongType);
|
||||||
end
|
end;
|
||||||
|
atCell:
|
||||||
|
if (arg.Cell <> nil) then begin
|
||||||
|
Result := true;
|
||||||
|
case arg.Cell^.ContentType of
|
||||||
|
cctDateTime: ADate := arg.Cell^.DateTimeValue;
|
||||||
|
cctNumber : ADate := arg.Cell^.NumberValue;
|
||||||
|
else Result := false;
|
||||||
|
AErrArg := CreateError(errWrongType);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -509,7 +540,17 @@ begin
|
|||||||
begin
|
begin
|
||||||
Result := TryStrToTime(arg.StringValue, ATime);
|
Result := TryStrToTime(arg.StringValue, ATime);
|
||||||
if not Result then AErrArg := CreateError(errWrongType);
|
if not Result then AErrArg := CreateError(errWrongType);
|
||||||
end
|
end;
|
||||||
|
atCell:
|
||||||
|
if (arg.Cell <> nil) then begin
|
||||||
|
Result := true;
|
||||||
|
case arg.Cell^.ContentType of
|
||||||
|
cctDateTime: ATime := frac(arg.Cell^.DateTimeValue);
|
||||||
|
cctNumber : ATime := frac(arg.Cell^.NumberValue);
|
||||||
|
else Result := false;
|
||||||
|
AErrArg := CreateError(errWrongType);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1506,6 +1547,155 @@ end;
|
|||||||
|
|
||||||
{ Info functions }
|
{ Info functions }
|
||||||
|
|
||||||
|
function fpsCELLINFO(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||||
|
// CELL( type, [range] )
|
||||||
|
|
||||||
|
{ from http://www.techonthenet.com/excel/formulas/cell.php:
|
||||||
|
|
||||||
|
"type" is the type of information that we retrieve for the cell and can have
|
||||||
|
one of the following values:
|
||||||
|
Value Explanation
|
||||||
|
------------- --------------------------------------------------------------
|
||||||
|
"address" Address of the cell. If the cell refers to a range, it is the
|
||||||
|
first cell in the range.
|
||||||
|
"col" Column number of the cell.
|
||||||
|
"color" Returns 1 if the color is a negative value; Otherwise it returns 0.
|
||||||
|
"contents" Contents of the upper-left cell.
|
||||||
|
"filename" Filename of the file that contains reference.
|
||||||
|
"format" Number format of the cell according to next table:
|
||||||
|
"G" General
|
||||||
|
"F0" 0
|
||||||
|
",0" #,##0
|
||||||
|
"F2" 0.00
|
||||||
|
",2" #,##0.00
|
||||||
|
"C0" $#,##0_);($#,##0)
|
||||||
|
"C0-" $#,##0_);[Red]($#,##0)
|
||||||
|
"C2" $#,##0.00_);($#,##0.00)
|
||||||
|
"C2-" $#,##0.00_);[Red]($#,##0.00)
|
||||||
|
"P0" 0%
|
||||||
|
"P2" 0.00%
|
||||||
|
"S2" 0.00E+00
|
||||||
|
"G" # ?/? or # ??/??
|
||||||
|
"D4" m/d/yy or m/d/yy h:mm or mm/dd/yy
|
||||||
|
"D1" d-mmm-yy or dd-mmm-yy
|
||||||
|
"D2" d-mmm or dd-mmm
|
||||||
|
"D3" mmm-yy
|
||||||
|
"D5" mm/dd
|
||||||
|
"D6" h:mm:ss AM/PM
|
||||||
|
"D7" h:mm AM/PM
|
||||||
|
"D8" h:mm:ss
|
||||||
|
"D9" h:mm
|
||||||
|
"parentheses" Returns 1 if the cell is formatted with parentheses;
|
||||||
|
Otherwise, it returns 0.
|
||||||
|
"prefix" Label prefix for the cell.
|
||||||
|
- Returns a single quote (') if the cell is left-aligned.
|
||||||
|
- Returns a double quote (") if the cell is right-aligned.
|
||||||
|
- Returns a caret (^) if the cell is center-aligned.
|
||||||
|
- Returns a back slash (\) if the cell is fill-aligned.
|
||||||
|
- Returns an empty text value for all others.
|
||||||
|
"protect" Returns 1 if the cell is locked. Returns 0 if the cell is not locked.
|
||||||
|
"row" Row number of the cell.
|
||||||
|
"type" Returns "b" if the cell is empty.
|
||||||
|
Returns "l" if the cell contains a text constant.
|
||||||
|
Returns "v" for all others.
|
||||||
|
"width" Column width of the cell, rounded to the nearest integer.
|
||||||
|
|
||||||
|
!!!! NOT ALL OF THEM ARE SUPPORTED HERE !!!
|
||||||
|
|
||||||
|
"range" is optional in Excel. It is the cell (or range) that you wish to retrieve
|
||||||
|
information for. If the range parameter is omitted, the CELL function will
|
||||||
|
assume that you are retrieving information for the last cell that was changed.
|
||||||
|
|
||||||
|
"range" is NOT OPTIONAL here because we don't know the last cell changed !!!
|
||||||
|
}
|
||||||
|
var
|
||||||
|
arg: TsArgument;
|
||||||
|
cell: PCell;
|
||||||
|
sname: String;
|
||||||
|
data: TStrArray;
|
||||||
|
begin
|
||||||
|
if NumArgs < 2 then begin
|
||||||
|
Result := CreateError(errArgError);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
arg := Args.Pop;
|
||||||
|
if (arg.ArgumentType <> atCell) or (arg.Cell = nil) then begin
|
||||||
|
Result := CreateError(errArgError);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
cell := arg.Cell;
|
||||||
|
if PopStringValues(Args, 1, data, Result) then begin
|
||||||
|
sname := Lowercase(data[0]);
|
||||||
|
if sname = 'address' then
|
||||||
|
Result := CreateString(GetCellString(cell^.Row, cell^.Col, []))
|
||||||
|
else if sname = 'col' then
|
||||||
|
Result := CreateNumber(cell^.Col + 1)
|
||||||
|
else if sname = 'color' then begin
|
||||||
|
if (cell^.NumberFormat = nfCurrencyRed)
|
||||||
|
then Result := CreateNumber(1)
|
||||||
|
else Result := CreateNumber(0);
|
||||||
|
end else if sname = 'contents' then
|
||||||
|
case cell^.ContentType of
|
||||||
|
cctNumber : Result := CreateNumber(cell^.NumberValue);
|
||||||
|
cctDateTime : Result := CreateNumber(cell^.DateTimeValue);
|
||||||
|
cctUTF8String : Result := CreateString(cell^.UTF8StringValue);
|
||||||
|
cctBool : Result := CreateString(BoolToStr(cell^.BoolValue));
|
||||||
|
cctError : Result := CreateString('Error');
|
||||||
|
end
|
||||||
|
else if sname = 'format' then begin
|
||||||
|
Result := CreateString('');
|
||||||
|
case cell^.NumberFormat of
|
||||||
|
nfGeneral:
|
||||||
|
Result := CreateString('G');
|
||||||
|
nfFixed:
|
||||||
|
if cell^.NumberFormatStr= '0' then Result := CreateString('0') else
|
||||||
|
if cell^.NumberFormatStr = '0.00' then Result := CreateString('F0');
|
||||||
|
nfFixedTh:
|
||||||
|
if cell^.NumberFormatStr = '#,##0' then Result := CreateString(',0') else
|
||||||
|
if cell^.NumberFormatStr = '#,##0.00' then Result := CreateString(',2');
|
||||||
|
nfPercentage:
|
||||||
|
if cell^.NumberFormatStr = '0%' then Result := CreateString('P0') else
|
||||||
|
if cell^.NumberFormatStr = '0.00%' then Result := CreateString('P2');
|
||||||
|
nfExp:
|
||||||
|
if cell^.NumberFormatStr = '0.00E+00' then Result := CreateString('S2');
|
||||||
|
nfShortDate, nfLongDate, nfShortDateTime:
|
||||||
|
Result := CreateString('D4');
|
||||||
|
nfLongTimeAM:
|
||||||
|
Result := CreateString('D6');
|
||||||
|
nfShortTimeAM:
|
||||||
|
Result := CreateString('D7');
|
||||||
|
nfLongTime:
|
||||||
|
Result := CreateString('D8');
|
||||||
|
nfShortTime:
|
||||||
|
Result := CreateString('D9');
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
if (sname = 'prefix') then begin
|
||||||
|
Result := CreateString('');
|
||||||
|
if (cell^.ContentType = cctUTF8String) then
|
||||||
|
case cell^.HorAlignment of
|
||||||
|
haLeft : Result := CreateString('''');
|
||||||
|
haCenter: Result := CreateString('^');
|
||||||
|
haRight : Result := CreateString('"');
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
if sname = 'row' then
|
||||||
|
Result := CreateNumber(cell^.Row + 1)
|
||||||
|
else if sname = 'type' then begin
|
||||||
|
if (cell^.ContentType = cctEmpty) then
|
||||||
|
Result := CreateString('b')
|
||||||
|
else if cell^.ContentType = cctUTF8String then begin
|
||||||
|
if (cell^.UTF8StringValue = '')
|
||||||
|
then Result := CreateString('b')
|
||||||
|
else Result := CreateString('l');
|
||||||
|
end else
|
||||||
|
Result := CreateString('v');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function fpsISERR(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
function fpsISERR(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||||
// ISERR( value )
|
// ISERR( value )
|
||||||
// If value is an error value (except #N/A), this function will return TRUE.
|
// If value is an error value (except #N/A), this function will return TRUE.
|
||||||
|
@ -1220,7 +1220,7 @@ const
|
|||||||
(Symbol:'ROW'; MinParams:0; MaxParams:1; Func:nil), // fekROW
|
(Symbol:'ROW'; MinParams:0; MaxParams:1; Func:nil), // fekROW
|
||||||
(Symbol:'ROWS'; MinParams:1; MaxParams:1; Func:nil), // fekROWS
|
(Symbol:'ROWS'; MinParams:1; MaxParams:1; Func:nil), // fekROWS
|
||||||
{ info }
|
{ info }
|
||||||
(Symbol:'CELL'; MinParams:1; MaxParams:2; Func:nil), // fekCELLINFO
|
(Symbol:'CELL'; MinParams:1; MaxParams:2; Func:fpsCELLINFO), // fekCELLINFO
|
||||||
(Symbol:'INFO'; MinParams:1; MaxParams:1; Func:nil), // fekINFO
|
(Symbol:'INFO'; MinParams:1; MaxParams:1; Func:nil), // fekINFO
|
||||||
(Symbol:'ISBLANK'; MinParams:1; MaxParams:1; Func:nil), // fekIsBLANK
|
(Symbol:'ISBLANK'; MinParams:1; MaxParams:1; Func:nil), // fekIsBLANK
|
||||||
(Symbol:'ISERR'; MinParams:1; MaxParams:1; Func:fpsISERR), // fekIsERR
|
(Symbol:'ISERR'; MinParams:1; MaxParams:1; Func:fpsISERR), // fekIsERR
|
||||||
@ -1430,6 +1430,7 @@ var
|
|||||||
func: TsFormulaFunc;
|
func: TsFormulaFunc;
|
||||||
val: TsArgument;
|
val: TsArgument;
|
||||||
fe: TsFormulaElement;
|
fe: TsFormulaElement;
|
||||||
|
cell: PCell;
|
||||||
begin
|
begin
|
||||||
if (Length(ACell^.RPNFormulaValue) = 0) or
|
if (Length(ACell^.RPNFormulaValue) = 0) or
|
||||||
(ACell^.ContentType = cctError)
|
(ACell^.ContentType = cctError)
|
||||||
@ -1441,8 +1442,11 @@ begin
|
|||||||
for i := 0 to Length(ACell^.RPNFormulaValue) - 1 do begin
|
for i := 0 to Length(ACell^.RPNFormulaValue) - 1 do begin
|
||||||
fe := ACell^.RPNFormulaValue[i]; // "formula element"
|
fe := ACell^.RPNFormulaValue[i]; // "formula element"
|
||||||
case fe.ElementKind of
|
case fe.ElementKind of
|
||||||
fekCell: ;
|
fekCell, fekCellRef:
|
||||||
fekCellRef: ;
|
begin
|
||||||
|
cell := FindCell(fe.Row, fe.Col);
|
||||||
|
args.PushCell(cell);
|
||||||
|
end;
|
||||||
fekCellRange: ;
|
fekCellRange: ;
|
||||||
fekNum:
|
fekNum:
|
||||||
args.PushNumber(fe.DoubleValue);
|
args.PushNumber(fe.DoubleValue);
|
||||||
@ -5352,7 +5356,7 @@ end;
|
|||||||
}
|
}
|
||||||
function RPNCellValue(ACellAddress: String; ANext: PRPNItem): PRPNItem;
|
function RPNCellValue(ACellAddress: String; ANext: PRPNItem): PRPNItem;
|
||||||
var
|
var
|
||||||
r,c: Integer;
|
r,c: Cardinal;
|
||||||
flags: TsRelFlags;
|
flags: TsRelFlags;
|
||||||
begin
|
begin
|
||||||
if not ParseCellString(ACellAddress, r, c, flags) then
|
if not ParseCellString(ACellAddress, r, c, flags) then
|
||||||
@ -5392,7 +5396,7 @@ end;
|
|||||||
}
|
}
|
||||||
function RPNCellRef(ACellAddress: String; ANext: PRPNItem): PRPNItem;
|
function RPNCellRef(ACellAddress: String; ANext: PRPNItem): PRPNItem;
|
||||||
var
|
var
|
||||||
r,c: Integer;
|
r,c: Cardinal;
|
||||||
flags: TsRelFlags;
|
flags: TsRelFlags;
|
||||||
begin
|
begin
|
||||||
if not ParseCellString(ACellAddress, r, c, flags) then
|
if not ParseCellString(ACellAddress, r, c, flags) then
|
||||||
@ -5433,7 +5437,7 @@ end;
|
|||||||
}
|
}
|
||||||
function RPNCellRange(ACellRangeAddress: String; ANext: PRPNItem): PRPNItem;
|
function RPNCellRange(ACellRangeAddress: String; ANext: PRPNItem): PRPNItem;
|
||||||
var
|
var
|
||||||
r1,c1, r2,c2: Integer;
|
r1,c1, r2,c2: Cardinal;
|
||||||
flags: TsRelFlags;
|
flags: TsRelFlags;
|
||||||
begin
|
begin
|
||||||
if not ParseCellRangeString(ACellRangeAddress, r1,c1, r2,c2, flags) then
|
if not ParseCellRangeString(ACellRangeAddress, r1,c1, r2,c2, flags) then
|
||||||
|
@ -57,19 +57,19 @@ function LongRGBToExcelPhysical(const RGB: DWord): DWord;
|
|||||||
|
|
||||||
// Other routines
|
// Other routines
|
||||||
function ParseIntervalString(const AStr: string;
|
function ParseIntervalString(const AStr: string;
|
||||||
out AFirstCellRow, AFirstCellCol, ACount: Integer;
|
out AFirstCellRow, AFirstCellCol, ACount: Cardinal;
|
||||||
out ADirection: TsSelectionDirection): Boolean;
|
out ADirection: TsSelectionDirection): Boolean;
|
||||||
function ParseCellRangeString(const AStr: string;
|
function ParseCellRangeString(const AStr: string;
|
||||||
out AFirstCellRow, AFirstCellCol, ALastCellRow, ALastCellCol: Integer;
|
out AFirstCellRow, AFirstCellCol, ALastCellRow, ALastCellCol: Cardinal;
|
||||||
out AFlags: TsRelFlags): Boolean;
|
out AFlags: TsRelFlags): Boolean;
|
||||||
function ParseCellString(const AStr: string;
|
function ParseCellString(const AStr: string;
|
||||||
out ACellRow, ACellCol: Integer; out AFlags: TsRelFlags): Boolean; overload;
|
out ACellRow, ACellCol: Cardinal; out AFlags: TsRelFlags): Boolean; overload;
|
||||||
function ParseCellString(const AStr: string;
|
function ParseCellString(const AStr: string;
|
||||||
out ACellRow, ACellCol: Integer): Boolean; overload;
|
out ACellRow, ACellCol: Cardinal): Boolean; overload;
|
||||||
function ParseCellRowString(const AStr: string;
|
function ParseCellRowString(const AStr: string;
|
||||||
out AResult: Integer): Boolean;
|
out AResult: Cardinal): Boolean;
|
||||||
function ParseCellColString(const AStr: string;
|
function ParseCellColString(const AStr: string;
|
||||||
out AResult: Integer): Boolean;
|
out AResult: Cardinal): Boolean;
|
||||||
|
|
||||||
function GetColString(AColIndex: Integer): String;
|
function GetColString(AColIndex: Integer): String;
|
||||||
function GetCellString(ARow,ACol: Cardinal; AFlags: TsRelFlags): String;
|
function GetCellString(ARow,ACol: Cardinal; AFlags: TsRelFlags): String;
|
||||||
@ -316,11 +316,11 @@ end;
|
|||||||
@return false if the string is not a valid cell range
|
@return false if the string is not a valid cell range
|
||||||
}
|
}
|
||||||
function ParseIntervalString(const AStr: string;
|
function ParseIntervalString(const AStr: string;
|
||||||
out AFirstCellRow, AFirstCellCol, ACount: Integer;
|
out AFirstCellRow, AFirstCellCol, ACount: Cardinal;
|
||||||
out ADirection: TsSelectionDirection): Boolean;
|
out ADirection: TsSelectionDirection): Boolean;
|
||||||
var
|
var
|
||||||
//Cells: TStringList;
|
//Cells: TStringList;
|
||||||
LastCellRow, LastCellCol: Integer;
|
LastCellRow, LastCellCol: Cardinal;
|
||||||
p: Integer;
|
p: Integer;
|
||||||
s1, s2: String;
|
s1, s2: String;
|
||||||
begin
|
begin
|
||||||
@ -381,7 +381,7 @@ end;
|
|||||||
@return false if the string is not a valid cell range
|
@return false if the string is not a valid cell range
|
||||||
}
|
}
|
||||||
function ParseCellRangeString(const AStr: string;
|
function ParseCellRangeString(const AStr: string;
|
||||||
out AFirstCellRow, AFirstCellCol, ALastCellRow, ALastCellCol: Integer;
|
out AFirstCellRow, AFirstCellCol, ALastCellRow, ALastCellCol: Cardinal;
|
||||||
out AFlags: TsRelFlags): Boolean;
|
out AFlags: TsRelFlags): Boolean;
|
||||||
var
|
var
|
||||||
p: Integer;
|
p: Integer;
|
||||||
@ -424,7 +424,7 @@ end;
|
|||||||
@example "AMP$200" --> (rel) column 1029 (= 26*26*1 + 26*16 + 26 - 1)
|
@example "AMP$200" --> (rel) column 1029 (= 26*26*1 + 26*16 + 26 - 1)
|
||||||
(abs) row = 199 (abs)
|
(abs) row = 199 (abs)
|
||||||
}
|
}
|
||||||
function ParseCellString(const AStr: String; out ACellRow, ACellCol: Integer;
|
function ParseCellString(const AStr: String; out ACellRow, ACellCol: Cardinal;
|
||||||
out AFlags: TsRelFlags): Boolean;
|
out AFlags: TsRelFlags): Boolean;
|
||||||
|
|
||||||
function Scan(AStartPos: Integer): Boolean;
|
function Scan(AStartPos: Integer): Boolean;
|
||||||
@ -505,7 +505,7 @@ end;
|
|||||||
@return False if the string is not a valid cell range
|
@return False if the string is not a valid cell range
|
||||||
}
|
}
|
||||||
function ParseCellString(const AStr: string;
|
function ParseCellString(const AStr: string;
|
||||||
out ACellRow, ACellCol: Integer): Boolean;
|
out ACellRow, ACellCol: Cardinal): Boolean;
|
||||||
var
|
var
|
||||||
flags: TsRelFlags;
|
flags: TsRelFlags;
|
||||||
begin
|
begin
|
||||||
@ -519,7 +519,7 @@ end;
|
|||||||
@param AResult Index of the row (zero-based!) (putput)
|
@param AResult Index of the row (zero-based!) (putput)
|
||||||
@return False if the string is not a valid cell row string
|
@return False if the string is not a valid cell row string
|
||||||
}
|
}
|
||||||
function ParseCellRowString(const AStr: string; out AResult: Integer): Boolean;
|
function ParseCellRowString(const AStr: string; out AResult: Cardinal): Boolean;
|
||||||
begin
|
begin
|
||||||
try
|
try
|
||||||
AResult := StrToInt(AStr) - 1;
|
AResult := StrToInt(AStr) - 1;
|
||||||
@ -537,7 +537,7 @@ end;
|
|||||||
@param AResult Zero-based index of the column (output)
|
@param AResult Zero-based index of the column (output)
|
||||||
@return False if the string is not a valid cell column string
|
@return False if the string is not a valid cell column string
|
||||||
}
|
}
|
||||||
function ParseCellColString(const AStr: string; out AResult: Integer): Boolean;
|
function ParseCellColString(const AStr: string; out AResult: Cardinal): Boolean;
|
||||||
const
|
const
|
||||||
INT_NUM_LETTERS = 26;
|
INT_NUM_LETTERS = 26;
|
||||||
begin
|
begin
|
||||||
|
@ -30,7 +30,7 @@ const
|
|||||||
var
|
var
|
||||||
Row: Integer;
|
Row: Integer;
|
||||||
value: Double;
|
value: Double;
|
||||||
r,c: integer;
|
r,c: Cardinal;
|
||||||
celladdr: String;
|
celladdr: String;
|
||||||
fs: TFormatSettings;
|
fs: TFormatSettings;
|
||||||
ls: char;
|
ls: char;
|
||||||
|
@ -124,6 +124,7 @@
|
|||||||
<Unit12>
|
<Unit12>
|
||||||
<Filename Value="rpnformulaunit.pas"/>
|
<Filename Value="rpnformulaunit.pas"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="rpnFormulaUnit"/>
|
||||||
</Unit12>
|
</Unit12>
|
||||||
<Unit13>
|
<Unit13>
|
||||||
<Filename Value="formulatests.pas"/>
|
<Filename Value="formulatests.pas"/>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
RPNNumber(1.0,
|
RPNNumber(1.0,
|
||||||
RPNFunc(fekAdd, nil)))));
|
RPNFunc(fekAdd, nil)))));
|
||||||
SetLength(sollValues, Row+1);
|
SetLength(sollValues, Row+1);
|
||||||
sollValues[Row] := CreateNumber(1.0+1.0);
|
sollValues[Row] := CreateNumber(1.0+1.0); // B1 = 2
|
||||||
|
|
||||||
// Subtraction
|
// Subtraction
|
||||||
inc(Row);
|
inc(Row);
|
||||||
@ -22,7 +22,40 @@
|
|||||||
RPNNumber(10,
|
RPNNumber(10,
|
||||||
RPNFunc(fekSub, nil)))));
|
RPNFunc(fekSub, nil)))));
|
||||||
SetLength(sollValues, Row+1);
|
SetLength(sollValues, Row+1);
|
||||||
sollValues[Row] := CreateNumber(1-10);
|
sollValues[Row] := CreateNumber(1-10); // B2 = -9
|
||||||
|
|
||||||
|
// Add cell values - relative addresses
|
||||||
|
inc(Row);
|
||||||
|
MyWorksheet.WriteUTF8Text(Row, 0, '=B1+B2');
|
||||||
|
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
|
||||||
|
RPNCellValue('B1',
|
||||||
|
RPNCellValue('B2',
|
||||||
|
RPNFunc(fekAdd, nil)))));
|
||||||
|
SetLength(sollValues, Row+1);
|
||||||
|
sollValues[Row] := CreateNumber(-7);
|
||||||
|
// don't refer to the cell contents here because they have not yet been calculated!
|
||||||
|
|
||||||
|
// Add cell values - absolute addresses
|
||||||
|
inc(Row);
|
||||||
|
MyWorksheet.WriteUTF8Text(Row, 0, '=$B$1+$B$2');
|
||||||
|
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
|
||||||
|
RPNCellValue('$B$1',
|
||||||
|
RPNCellValue('$B$2',
|
||||||
|
RPNFunc(fekAdd, nil)))));
|
||||||
|
SetLength(sollValues, Row+1);
|
||||||
|
sollValues[Row] := CreateNumber(-7);
|
||||||
|
// don't refer to the cell contents here because they have not yet been calculated!
|
||||||
|
|
||||||
|
// Add cell values - mixed absolute and relative addresses
|
||||||
|
inc(Row);
|
||||||
|
MyWorksheet.WriteUTF8Text(Row, 0, '=B$1+$B2');
|
||||||
|
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
|
||||||
|
RPNCellValue('B$1',
|
||||||
|
RPNCellValue('$B2',
|
||||||
|
RPNFunc(fekAdd, nil)))));
|
||||||
|
SetLength(sollValues, Row+1);
|
||||||
|
sollValues[Row] := CreateNumber(-7);
|
||||||
|
// don't refer to the cell contents here because they have not yet been calculated!
|
||||||
|
|
||||||
// Multiplication
|
// Multiplication
|
||||||
inc(Row);
|
inc(Row);
|
||||||
@ -1459,6 +1492,63 @@
|
|||||||
{ Information functions }
|
{ Information functions }
|
||||||
{------------------------------------------------------------------------------}
|
{------------------------------------------------------------------------------}
|
||||||
|
|
||||||
|
// INFO
|
||||||
|
MyWorksheet.WriteUTF8Text(Row, 0, '=CELL("address", A1)');
|
||||||
|
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
|
||||||
|
RPNString('address',
|
||||||
|
RPNCellRef('A1',
|
||||||
|
RPNFunc(fekCELLINFO, 2, nil)))));
|
||||||
|
SetLength(sollValues, Row+1);
|
||||||
|
sollValues[Row] := CreateString('$A$1');
|
||||||
|
|
||||||
|
MyWorksheet.WriteUTF8Text(Row, 0, '=CELL("col", B1)');
|
||||||
|
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
|
||||||
|
RPNString('col',
|
||||||
|
RPNCellRef('B1',
|
||||||
|
RPNFunc(fekCELLINFO, 2, nil)))));
|
||||||
|
SetLength(sollValues, Row+1);
|
||||||
|
sollValues[Row] := CreateNumber(2); // Excel starts counting at 1
|
||||||
|
|
||||||
|
MyWorksheet.WriteUTF8Text(Row, 0, '=CELL("format", B1)');
|
||||||
|
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
|
||||||
|
RPNString('format',
|
||||||
|
RPNCellRef('B1',
|
||||||
|
RPNFunc(fekCELLINFO, 2, nil)))));
|
||||||
|
SetLength(sollValues, Row+1);
|
||||||
|
sollValues[Row] := CreateString('G');
|
||||||
|
|
||||||
|
MyWorksheet.WriteUTF8Text(Row, 0, '=CELL("prefix", A1)');
|
||||||
|
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
|
||||||
|
RPNString('prefix',
|
||||||
|
RPNCellRef('A1',
|
||||||
|
RPNFunc(fekCELLINFO, 2, nil)))));
|
||||||
|
SetLength(sollValues, Row+1);
|
||||||
|
sollValues[Row] := CreateString('''');
|
||||||
|
|
||||||
|
MyWorksheet.WriteUTF8Text(Row, 0, '=CELL("row", B1)');
|
||||||
|
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
|
||||||
|
RPNString('row',
|
||||||
|
RPNCellRef('B1',
|
||||||
|
RPNFunc(fekCELLINFO, 2, nil)))));
|
||||||
|
SetLength(sollValues, Row+1);
|
||||||
|
sollValues[Row] := CreateNumber(1); // Excel starts counting at 1
|
||||||
|
|
||||||
|
MyWorksheet.WriteUTF8Text(Row, 0, '=CELL("type", A1)');
|
||||||
|
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
|
||||||
|
RPNString('type',
|
||||||
|
RPNCellRef('A1',
|
||||||
|
RPNFunc(fekCELLINFO, 2, nil)))));
|
||||||
|
SetLength(sollValues, Row+1);
|
||||||
|
sollValues[Row] := CreateString('l');
|
||||||
|
|
||||||
|
MyWorksheet.WriteUTF8Text(Row, 0, '=CELL("type", B1)');
|
||||||
|
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
|
||||||
|
RPNString('type',
|
||||||
|
RPNCellRef('B1',
|
||||||
|
RPNFunc(fekCELLINFO, 2, nil)))));
|
||||||
|
SetLength(sollValues, Row+1);
|
||||||
|
sollValues[Row] := CreateString('v');
|
||||||
|
|
||||||
// IsError
|
// IsError
|
||||||
inc(Row);
|
inc(Row);
|
||||||
MyWorksheet.WriteUTF8Text(Row, 0, '=ISERROR(1/0)');
|
MyWorksheet.WriteUTF8Text(Row, 0, '=ISERROR(1/0)');
|
||||||
|
Reference in New Issue
Block a user