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;
|
||||
|
||||
type
|
||||
TsArgumentType = (atNumber, atString, atBool, atError, atEmpty);
|
||||
TsArgumentType = (atCell, atNumber, atString, atBool, atError, atEmpty);
|
||||
|
||||
TsArgument = record
|
||||
IsMissing: Boolean;
|
||||
case ArgumentType: TsArgumentType of
|
||||
atCell : (Cell: PCell);
|
||||
atNumber : (NumberValue: Double);
|
||||
atString : (StringValue: String);
|
||||
atBool : (BoolValue: Boolean);
|
||||
@ -26,6 +27,7 @@ type
|
||||
function Pop: TsArgument;
|
||||
procedure Push(AValue: TsArgument);
|
||||
procedure PushBool(AValue: Boolean);
|
||||
procedure PushCell(AValue: PCell);
|
||||
procedure PushMissing;
|
||||
procedure PushNumber(AValue: Double);
|
||||
procedure PushString(AValue: String);
|
||||
@ -133,6 +135,7 @@ function fpsSUBSTITUTE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||
function fpsTRIM (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||
function fpsUPPER (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||
{ info functions }
|
||||
function fpsCELLINFO (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||
function fpsISERR (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||
function fpsISERROR (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||
function fpsISLOGICAL (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
||||
@ -152,6 +155,55 @@ type
|
||||
TFloatArray = array of double;
|
||||
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 }
|
||||
|
||||
destructor TsArgumentStack.Destroy;
|
||||
@ -181,60 +233,53 @@ end;
|
||||
|
||||
function TsArgumentStack.Pop: TsArgument;
|
||||
var
|
||||
P: PsArgument;
|
||||
arg: PsArgument;
|
||||
begin
|
||||
P := PsArgument(Items[Count-1]);
|
||||
Result := P^;
|
||||
Result.StringValue := P^.StringValue; // necessary?
|
||||
arg := PsArgument(Items[Count-1]);
|
||||
Result := arg^;
|
||||
Result.StringValue := arg^.StringValue; // necessary?
|
||||
Result.Cell := arg^.Cell;
|
||||
Delete(Count-1);
|
||||
end;
|
||||
|
||||
procedure TsArgumentStack.Push(AValue: TsArgument);
|
||||
var
|
||||
P: PsArgument;
|
||||
arg: PsArgument;
|
||||
begin
|
||||
GetMem(P, SizeOf(TsArgument));
|
||||
P^ := AValue;
|
||||
P^.StringValue := AValue.StringValue;
|
||||
Add(P);
|
||||
GetMem(arg, SizeOf(TsArgument));
|
||||
arg^ := AValue;
|
||||
arg^.StringValue := AValue.StringValue;
|
||||
arg^.Cell := AValue.Cell;
|
||||
Add(arg);
|
||||
end;
|
||||
|
||||
procedure TsArgumentStack.PushBool(AValue: Boolean);
|
||||
var
|
||||
arg: TsArgument;
|
||||
begin
|
||||
arg.ArgumentType := atBool;
|
||||
arg.BoolValue := AValue;
|
||||
arg.IsMissing := false;
|
||||
Push(arg);
|
||||
Push(CreateBool(AValue));
|
||||
end;
|
||||
|
||||
procedure TsArgumentStack.PushCell(AValue: PCell);
|
||||
begin
|
||||
Push(CreateCell(AValue));
|
||||
end;
|
||||
|
||||
procedure TsArgumentStack.PushMissing;
|
||||
var
|
||||
arg: TsArgument;
|
||||
begin
|
||||
arg := CreateArgument;
|
||||
arg.IsMissing := true;
|
||||
Push(arg);
|
||||
end;
|
||||
|
||||
procedure TsArgumentStack.PushNumber(AValue: Double);
|
||||
var
|
||||
arg: TsArgument;
|
||||
begin
|
||||
arg.ArgumentType := atNumber;
|
||||
arg.NumberValue := AValue;
|
||||
arg.IsMissing := false;
|
||||
Push(arg);
|
||||
Push(CreateNumber(AValue));
|
||||
end;
|
||||
|
||||
procedure TsArgumentStack.PushString(AValue: String);
|
||||
var
|
||||
arg: TsArgument;
|
||||
begin
|
||||
arg.ArgumentType := atString;
|
||||
arg.StringValue := AValue;
|
||||
arg.IsMissing := false;
|
||||
Push(arg);
|
||||
Push(CreateString(AValue));
|
||||
end;
|
||||
|
||||
|
||||
@ -242,11 +287,12 @@ end;
|
||||
|
||||
function GetBoolFromArgument(Arg: TsArgument; var AValue: Boolean): TsErrorValue;
|
||||
begin
|
||||
case Arg.ArgumentType of
|
||||
atBool : begin
|
||||
AValue := Arg.BoolValue;
|
||||
Result := errOK;
|
||||
end;
|
||||
case Arg.ArgumentType of
|
||||
atBool : AValue := Arg.BoolValue;
|
||||
atCell : if (Arg.Cell <> nil) and (Arg.Cell^.ContentType = cctBool)
|
||||
then AValue := Arg.Cell^.BoolValue
|
||||
else Result := errWrongType;
|
||||
atError: Result := Arg.ErrorValue;
|
||||
else Result := errWrongType;
|
||||
end;
|
||||
@ -259,56 +305,31 @@ begin
|
||||
atNumber : ANumber := Arg.NumberValue;
|
||||
atString : if not TryStrToFloat(arg.StringValue, ANumber) then Result := errWrongType;
|
||||
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;
|
||||
end;
|
||||
end;
|
||||
|
||||
function GetStringFromArgument(Arg: TsArgument; var AString: String): TsErrorValue;
|
||||
begin
|
||||
case Arg.ArgumentType of
|
||||
atString : begin
|
||||
AString := Arg.StringValue;
|
||||
Result := errOK;
|
||||
end;
|
||||
case Arg.ArgumentType of
|
||||
atString : AString := Arg.StringValue;
|
||||
atCell : if (Arg.Cell <> nil) and (Arg.Cell^.ContentType = cctUTF8String) then
|
||||
AString := Arg.Cell^.UTF8StringValue
|
||||
else
|
||||
Result := errWrongType;
|
||||
atError : Result := Arg.ErrorValue;
|
||||
else Result := errWrongType;
|
||||
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
|
||||
formulas.
|
||||
@ -381,7 +402,17 @@ begin
|
||||
begin
|
||||
Result := TryStrToDate(arg.StringValue, ADate);
|
||||
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;
|
||||
|
||||
@ -509,7 +540,17 @@ begin
|
||||
begin
|
||||
Result := TryStrToTime(arg.StringValue, ATime);
|
||||
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;
|
||||
|
||||
@ -1506,6 +1547,155 @@ end;
|
||||
|
||||
{ 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;
|
||||
// ISERR( value )
|
||||
// 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:'ROWS'; MinParams:1; MaxParams:1; Func:nil), // fekROWS
|
||||
{ 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:'ISBLANK'; MinParams:1; MaxParams:1; Func:nil), // fekIsBLANK
|
||||
(Symbol:'ISERR'; MinParams:1; MaxParams:1; Func:fpsISERR), // fekIsERR
|
||||
@ -1430,6 +1430,7 @@ var
|
||||
func: TsFormulaFunc;
|
||||
val: TsArgument;
|
||||
fe: TsFormulaElement;
|
||||
cell: PCell;
|
||||
begin
|
||||
if (Length(ACell^.RPNFormulaValue) = 0) or
|
||||
(ACell^.ContentType = cctError)
|
||||
@ -1441,8 +1442,11 @@ begin
|
||||
for i := 0 to Length(ACell^.RPNFormulaValue) - 1 do begin
|
||||
fe := ACell^.RPNFormulaValue[i]; // "formula element"
|
||||
case fe.ElementKind of
|
||||
fekCell: ;
|
||||
fekCellRef: ;
|
||||
fekCell, fekCellRef:
|
||||
begin
|
||||
cell := FindCell(fe.Row, fe.Col);
|
||||
args.PushCell(cell);
|
||||
end;
|
||||
fekCellRange: ;
|
||||
fekNum:
|
||||
args.PushNumber(fe.DoubleValue);
|
||||
@ -5352,7 +5356,7 @@ end;
|
||||
}
|
||||
function RPNCellValue(ACellAddress: String; ANext: PRPNItem): PRPNItem;
|
||||
var
|
||||
r,c: Integer;
|
||||
r,c: Cardinal;
|
||||
flags: TsRelFlags;
|
||||
begin
|
||||
if not ParseCellString(ACellAddress, r, c, flags) then
|
||||
@ -5392,7 +5396,7 @@ end;
|
||||
}
|
||||
function RPNCellRef(ACellAddress: String; ANext: PRPNItem): PRPNItem;
|
||||
var
|
||||
r,c: Integer;
|
||||
r,c: Cardinal;
|
||||
flags: TsRelFlags;
|
||||
begin
|
||||
if not ParseCellString(ACellAddress, r, c, flags) then
|
||||
@ -5433,7 +5437,7 @@ end;
|
||||
}
|
||||
function RPNCellRange(ACellRangeAddress: String; ANext: PRPNItem): PRPNItem;
|
||||
var
|
||||
r1,c1, r2,c2: Integer;
|
||||
r1,c1, r2,c2: Cardinal;
|
||||
flags: TsRelFlags;
|
||||
begin
|
||||
if not ParseCellRangeString(ACellRangeAddress, r1,c1, r2,c2, flags) then
|
||||
|
@ -57,19 +57,19 @@ function LongRGBToExcelPhysical(const RGB: DWord): DWord;
|
||||
|
||||
// Other routines
|
||||
function ParseIntervalString(const AStr: string;
|
||||
out AFirstCellRow, AFirstCellCol, ACount: Integer;
|
||||
out AFirstCellRow, AFirstCellCol, ACount: Cardinal;
|
||||
out ADirection: TsSelectionDirection): Boolean;
|
||||
function ParseCellRangeString(const AStr: string;
|
||||
out AFirstCellRow, AFirstCellCol, ALastCellRow, ALastCellCol: Integer;
|
||||
out AFirstCellRow, AFirstCellCol, ALastCellRow, ALastCellCol: Cardinal;
|
||||
out AFlags: TsRelFlags): Boolean;
|
||||
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;
|
||||
out ACellRow, ACellCol: Integer): Boolean; overload;
|
||||
out ACellRow, ACellCol: Cardinal): Boolean; overload;
|
||||
function ParseCellRowString(const AStr: string;
|
||||
out AResult: Integer): Boolean;
|
||||
out AResult: Cardinal): Boolean;
|
||||
function ParseCellColString(const AStr: string;
|
||||
out AResult: Integer): Boolean;
|
||||
out AResult: Cardinal): Boolean;
|
||||
|
||||
function GetColString(AColIndex: Integer): 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
|
||||
}
|
||||
function ParseIntervalString(const AStr: string;
|
||||
out AFirstCellRow, AFirstCellCol, ACount: Integer;
|
||||
out AFirstCellRow, AFirstCellCol, ACount: Cardinal;
|
||||
out ADirection: TsSelectionDirection): Boolean;
|
||||
var
|
||||
//Cells: TStringList;
|
||||
LastCellRow, LastCellCol: Integer;
|
||||
LastCellRow, LastCellCol: Cardinal;
|
||||
p: Integer;
|
||||
s1, s2: String;
|
||||
begin
|
||||
@ -381,7 +381,7 @@ end;
|
||||
@return false if the string is not a valid cell range
|
||||
}
|
||||
function ParseCellRangeString(const AStr: string;
|
||||
out AFirstCellRow, AFirstCellCol, ALastCellRow, ALastCellCol: Integer;
|
||||
out AFirstCellRow, AFirstCellCol, ALastCellRow, ALastCellCol: Cardinal;
|
||||
out AFlags: TsRelFlags): Boolean;
|
||||
var
|
||||
p: Integer;
|
||||
@ -424,7 +424,7 @@ end;
|
||||
@example "AMP$200" --> (rel) column 1029 (= 26*26*1 + 26*16 + 26 - 1)
|
||||
(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;
|
||||
|
||||
function Scan(AStartPos: Integer): Boolean;
|
||||
@ -505,7 +505,7 @@ end;
|
||||
@return False if the string is not a valid cell range
|
||||
}
|
||||
function ParseCellString(const AStr: string;
|
||||
out ACellRow, ACellCol: Integer): Boolean;
|
||||
out ACellRow, ACellCol: Cardinal): Boolean;
|
||||
var
|
||||
flags: TsRelFlags;
|
||||
begin
|
||||
@ -519,7 +519,7 @@ end;
|
||||
@param AResult Index of the row (zero-based!) (putput)
|
||||
@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
|
||||
try
|
||||
AResult := StrToInt(AStr) - 1;
|
||||
@ -537,7 +537,7 @@ end;
|
||||
@param AResult Zero-based index of the column (output)
|
||||
@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
|
||||
INT_NUM_LETTERS = 26;
|
||||
begin
|
||||
|
@ -30,7 +30,7 @@ const
|
||||
var
|
||||
Row: Integer;
|
||||
value: Double;
|
||||
r,c: integer;
|
||||
r,c: Cardinal;
|
||||
celladdr: String;
|
||||
fs: TFormatSettings;
|
||||
ls: char;
|
||||
|
@ -124,6 +124,7 @@
|
||||
<Unit12>
|
||||
<Filename Value="rpnformulaunit.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="rpnFormulaUnit"/>
|
||||
</Unit12>
|
||||
<Unit13>
|
||||
<Filename Value="formulatests.pas"/>
|
||||
|
@ -12,7 +12,7 @@
|
||||
RPNNumber(1.0,
|
||||
RPNFunc(fekAdd, nil)))));
|
||||
SetLength(sollValues, Row+1);
|
||||
sollValues[Row] := CreateNumber(1.0+1.0);
|
||||
sollValues[Row] := CreateNumber(1.0+1.0); // B1 = 2
|
||||
|
||||
// Subtraction
|
||||
inc(Row);
|
||||
@ -22,7 +22,40 @@
|
||||
RPNNumber(10,
|
||||
RPNFunc(fekSub, nil)))));
|
||||
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
|
||||
inc(Row);
|
||||
@ -1459,6 +1492,63 @@
|
||||
{ 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
|
||||
inc(Row);
|
||||
MyWorksheet.WriteUTF8Text(Row, 0, '=ISERROR(1/0)');
|
||||
|
Reference in New Issue
Block a user