From f8f096dcf8f02c95336919565717197bc2942d46 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Fri, 17 Aug 2018 12:00:02 +0000 Subject: [PATCH] fpspreadsheet: Quote sheet names if they contain illegal characters for the expression parser. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6607 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../source/common/fpsexprparser.pas | 30 +++++++++++---- .../fpspreadsheet/source/common/fpsutils.pas | 38 +++++++++++++------ 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/components/fpspreadsheet/source/common/fpsexprparser.pas b/components/fpspreadsheet/source/common/fpsexprparser.pas index 2480ddf71..dc759ca33 100644 --- a/components/fpspreadsheet/source/common/fpsexprparser.pas +++ b/components/fpspreadsheet/source/common/fpsexprparser.pas @@ -61,7 +61,7 @@ type ttNumber, ttString, ttIdentifier, ttSpreadsheetAddress, ttPlus, ttMinus, ttMul, ttDiv, ttConcat, ttPercent, ttPower, ttLeft, ttRight, ttLessThan, ttLargerThan, ttEqual, ttNotEqual, ttLessThanEqual, ttLargerThanEqual, - ttListSep, ttTrue, ttFalse, ttMissingArg, ttError, ttEOF + ttListSep, ttQuote, ttTrue, ttFalse, ttMissingArg, ttError, ttEOF ); TsExprFloat = Double; @@ -563,6 +563,7 @@ type function GetCol: Cardinal; function GetRow: Cardinal; procedure GetNodeValue(out AResult: TsExpressionResult); override; + function GetQuotedSheetName: String; public constructor Create(AParser: TsExpressionParser; AWorksheet: TsBasicWorksheet; ASheetName: String; ARow, ACol: Cardinal; AFlags: TsRelFlags); @@ -1110,12 +1111,15 @@ function TsExpressionScanner.DoIdentifier: TsTokenType; var C: Char; S: String; + isQuoted: Boolean; begin C := CurrentChar; - while (not IsWordDelim(C)) and (C <> cNULL) do + isQuoted := C = ''''; + while ((not IsWordDelim(C)) or IsQuoted) and (C <> cNULL) do begin FToken := FToken + C; C := NextPos; + if C = '''' then isQuoted := false; end; if ParseCellRangeString(FToken, FSheet1, FSheet2, @@ -1311,7 +1315,7 @@ begin Result := DoNumber else if (C = cError) then Result := DoError - else if IsAlpha(C) or (C = '$') then + else if IsAlpha(C) or (C = '$') or (C = '''') then Result := DoIdentifier else ScanError(Format(rsUnknownCharacter, [FPos, C])); @@ -3922,17 +3926,17 @@ begin r := Getrow; c := GetCol; - if Has3dLink then + if Has3dLink then begin case FParser.Dialect of fdExcelA1: - Result := Format('%s!%s', [GetSheetName, GetCellString(r, c, FFlags)]); + Result := Format('%s!%s', [GetQuotedSheetName, GetCellString(r, c, FFlags)]); fdExcelR1C1: - Result := Format('%s!%s', [GetSheetName, + Result := Format('%s!%s', [GetQuotedSheetName, GetCellString_R1C1(r, c, FFlags, FParser.FSourceCell^.Row, FParser.FSourceCell^.Col)]); fdOpenDocument: - Result := Format('[%s.%s]', [GetSheetName, GetCellString(r, c, FFlags)]); + Result := Format('[%s.%s]', [GetQuotedSheetName, GetCellString(r, c, FFlags)]); end - else + end else case FParser.Dialect of fdExcelA1: Result := GetCellString(GetRow, GetCol, FFlags); @@ -4002,6 +4006,12 @@ begin AResult.Worksheet := GetSheet; end; +function TsCellExprNode.GetQuotedSheetName: String; +begin + Result := GetSheetName; + if SheetNameNeedsQuotes(Result) then + Result := QuotedStr(Result); +end; { See: GetCol } function TsCellExprNode.GetRow: Cardinal; @@ -4168,10 +4178,14 @@ begin s1 := FWorksheet.Name else s1 := (Workbook as TsWorkbook).GetWorksheetByIndex(FSheetIndex[1]).Name; + if SheetNameNeedsQuotes(s1) then s1 := QuotedStr(s1); + if FSheetIndex[2] = -1 then s2 := FWorksheet.Name else s2 := (Workbook as TsWorkbook).GetWorksheetByIndex(FSheetIndex[2]).Name; + if SheetNameNeedsQuotes(s2) then s2 := QuotedStr(s2); + r1 := GetRow(1); c1 := GetCol(1); r2 := GetRow(2); diff --git a/components/fpspreadsheet/source/common/fpsutils.pas b/components/fpspreadsheet/source/common/fpsutils.pas index 4685431e5..7cec861ce 100644 --- a/components/fpspreadsheet/source/common/fpsutils.pas +++ b/components/fpspreadsheet/source/common/fpsutils.pas @@ -112,7 +112,9 @@ function GetCellRangeString_R1C1(ASheet1, ASheet2: String; ARow1, ACol1, ARow2, ACol2: Cardinal; AFlags: TsRelFlags = [rfRelRow, rfRelCol]; ARefRow: Cardinal = Cardinal(-1); ARefCol: Cardinal = Cardinal(-1)): String; overload; - // OpenDocument Syntax +function SheetNameNeedsQuotes(ASheet: String): Boolean; + +// OpenDocument Syntax function GetCellRangeString_ODS(ASheet1, ASheet2: String; ARow1, ACol1, ARow2, ACol2: Cardinal; AFlags: TsRelFlags = rfAllRel): String; overload; function GetCellRangeString_ODS(ARow1, ACol1, ARow2, ACol2: Cardinal; @@ -944,10 +946,10 @@ begin s2 := Copy(AStr, p+1, MaxInt); p := pos(':', s1); if p = 0 then - ASheet1 := s1 + ASheet1 := UnquoteStr(s1) else begin - ASheet1 := copy(s1, 1, p-1); - ASheet2 := copy(s1, p+1, MaxInt); + ASheet1 := UnquoteStr(copy(s1, 1, p-1)); + ASheet2 := UnquoteStr(copy(s1, p+1, MaxInt)); end; end; @@ -1162,20 +1164,32 @@ begin ]); end; +function SheetNameNeedsQuotes(ASheet: String): Boolean; +begin + if ASheet <> '' then begin + Result := true; + if (ASheet[1] in ['0'..'9', '.']) then exit; + if (pos(' ', ASheet) > 0) then exit; + end; + Result := false; +end; + function GetCellRangeString(ASheet1, ASheet2: String; ARow1, ACol1, ARow2, ACol2: Cardinal; AFlags: TsRelFlags = rfAllRel; Compact: Boolean = false): String; -var - s: String; begin - s := GetCellRangeString(ARow1, ACol1, ARow2, ACol2, AFlags, Compact); + Result := GetCellRangeString(ARow1, ACol1, ARow2, ACol2, AFlags, Compact); if (ASheet1 = '') and (ASheet2 = '') then - Result := s - else if ASheet2 = '' then - Result := Format('%s!%s', [ASheet1, s]) + exit; + + if SheetNameNeedsQuotes(ASheet1) then ASheet1 := QuotedStr(ASheet1); + if SheetNameNeedsQuotes(ASheet2) then ASheet2 := QuotedStr(ASheet2); + + if ASheet2 = '' then + Result := Format('%s!%s', [ASheet1, Result]) else if Compact and (ASheet1 = ASheet2) then - Result := Format('%s!%s', [ASheet1, s]) + Result := Format('%s!%s', [ASheet1, Result]) else - Result := Format('%s:%s!%s', [ASheet1, ASheet2, s]); + Result := Format('%s:%s!%s', [ASheet1, ASheet2, Result]); end;