From 2f338a50a86fa4fe1e8e1de2558b0e52035b368d Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Wed, 2 Jul 2014 15:14:58 +0000 Subject: [PATCH] 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 --- components/fpspreadsheet/fpsfunc.pas | 334 ++++++++++++++---- components/fpspreadsheet/fpspreadsheet.pas | 16 +- components/fpspreadsheet/fpsutils.pas | 26 +- .../fpspreadsheet/tests/rpnformulaunit.pas | 2 +- .../fpspreadsheet/tests/spreadtestgui.lpi | 1 + .../tests/testcases_calcrpnformula.inc | 94 ++++- 6 files changed, 379 insertions(+), 94 deletions(-) diff --git a/components/fpspreadsheet/fpsfunc.pas b/components/fpspreadsheet/fpsfunc.pas index bd4692828..7219c5e54 100644 --- a/components/fpspreadsheet/fpsfunc.pas +++ b/components/fpspreadsheet/fpsfunc.pas @@ -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 + Result := errOK; case Arg.ArgumentType of - atBool : begin - AValue := Arg.BoolValue; - Result := errOK; - end; + 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 + Result := errOK; case Arg.ArgumentType of - atString : begin - AString := Arg.StringValue; - Result := errOK; - end; + 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. diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index 90a8fc3c2..2dc410297 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -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 diff --git a/components/fpspreadsheet/fpsutils.pas b/components/fpspreadsheet/fpsutils.pas index 02c57bba8..353e47b98 100644 --- a/components/fpspreadsheet/fpsutils.pas +++ b/components/fpspreadsheet/fpsutils.pas @@ -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 diff --git a/components/fpspreadsheet/tests/rpnformulaunit.pas b/components/fpspreadsheet/tests/rpnformulaunit.pas index b615c8490..cbec39b50 100644 --- a/components/fpspreadsheet/tests/rpnformulaunit.pas +++ b/components/fpspreadsheet/tests/rpnformulaunit.pas @@ -30,7 +30,7 @@ const var Row: Integer; value: Double; - r,c: integer; + r,c: Cardinal; celladdr: String; fs: TFormatSettings; ls: char; diff --git a/components/fpspreadsheet/tests/spreadtestgui.lpi b/components/fpspreadsheet/tests/spreadtestgui.lpi index 653f2061d..ed06b19d3 100644 --- a/components/fpspreadsheet/tests/spreadtestgui.lpi +++ b/components/fpspreadsheet/tests/spreadtestgui.lpi @@ -124,6 +124,7 @@ + diff --git a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc index 08347d9de..e6c287542 100644 --- a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc +++ b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc @@ -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)');