fpc/rtl/objpas/classes/parser.inc
marco 499df41c28 --- Merging r40529 into '.':
U    rtl/objpas/sysutils/sysstr.inc
U    rtl/objpas/sysutils/sysstrh.inc
--- Recording mergeinfo for merge of r40529 into '.':
 U   .
--- Merging r40548 into '.':
U    rtl/unix/unix.pp
--- Recording mergeinfo for merge of r40548 into '.':
 G   .
--- Merging r40803 into '.':
U    utils/ptopu.pp
--- Recording mergeinfo for merge of r40803 into '.':
 G   .
--- Merging r40818 into '.':
U    packages/openssl/src/openssl.pas
--- Recording mergeinfo for merge of r40818 into '.':
 G   .
--- Merging r40838 into '.':
G    packages/openssl/src/openssl.pas
--- Recording mergeinfo for merge of r40838 into '.':
 G   .
--- Merging r40841 into '.':
U    packages/fcl-res/src/coffwriter.pp
--- Recording mergeinfo for merge of r40841 into '.':
 G   .
--- Merging r40908 into '.':
U    rtl/inc/getopts.pp
--- Recording mergeinfo for merge of r40908 into '.':
 G   .
--- Merging r41085 into '.':
U    rtl/objpas/sysutils/syswide.inc
U    rtl/objpas/sysutils/syswideh.inc
--- Recording mergeinfo for merge of r41085 into '.':
 G   .
--- Merging r41263 into '.':
U    packages/rtl-objpas/src/inc/strutils.pp
--- Recording mergeinfo for merge of r41263 into '.':
 G   .
--- Merging r41331 into '.':
U    rtl/objpas/classes/parser.inc
--- Recording mergeinfo for merge of r41331 into '.':
 G   .
--- Merging r41332 into '.':
U    packages/fcl-xml/src/xmlconf.pp
--- Recording mergeinfo for merge of r41332 into '.':
 G   .

# revisions: 40529,40548,40803,40818,40838,40841,40908,41085,41263,41331,41332
r40529 | michael | 2018-12-12 09:29:24 +0100 (Wed, 12 Dec 2018) | 1 line
Changed paths:
   M /trunk/rtl/objpas/sysutils/sysstr.inc
   M /trunk/rtl/objpas/sysutils/sysstrh.inc

Added overloads UintToStr for Delphi compatbibility (bug ID 0034690)
r40548 | michael | 2018-12-14 11:00:44 +0100 (Fri, 14 Dec 2018) | 1 line
Changed paths:
   M /trunk/rtl/unix/unix.pp

* Fix bug #0034499
r40803 | michael | 2019-01-08 04:55:32 +0100 (Tue, 08 Jan 2019) | 1 line
Changed paths:
   M /trunk/utils/ptopu.pp

* Applied patch by Bart Broersma to fix bug ID #34277
r40818 | michael | 2019-01-09 16:04:04 +0100 (Wed, 09 Jan 2019) | 1 line
Changed paths:
   M /trunk/packages/openssl/src/openssl.pas

* Add PEM_write_bio_PKCS7, bug ID  #0034842
r40838 | michael | 2019-01-10 23:11:33 +0100 (Thu, 10 Jan 2019) | 1 line
Changed paths:
   M /trunk/packages/openssl/src/openssl.pas

* Fix stack overflow
r40841 | michael | 2019-01-11 11:53:45 +0100 (Fri, 11 Jan 2019) | 1 line
Changed paths:
   M /trunk/packages/fcl-res/src/coffwriter.pp

* Call inherited constructor
r40908 | michael | 2019-01-19 17:35:30 +0100 (Sat, 19 Jan 2019) | 1 line
Changed paths:
   M /trunk/rtl/inc/getopts.pp

* Fix bug ID #19842 using patch from Bart Broersma
r41085 | marco | 2019-01-27 15:52:52 +0100 (Sun, 27 Jan 2019) | 2 lines
Changed paths:
   M /trunk/rtl/objpas/sysutils/syswide.inc
   M /trunk/rtl/objpas/sysutils/syswideh.inc

 * unicode version of isleadchar. utf8 still to follow, see #34754
r41263 | marco | 2019-02-09 13:31:15 +0100 (Sat, 09 Feb 2019) | 2 lines
Changed paths:
   M /trunk/packages/rtl-objpas/src/inc/strutils.pp

 * Patch from Serge Anvarov with missing strutils aliases. Mantis #35047
r41331 | michael | 2019-02-16 09:39:40 +0100 (Sat, 16 Feb 2019) | 1 line
Changed paths:
   M /trunk/rtl/objpas/classes/parser.inc

Fix bug ID #35086: TParser should reset position (tentative)
r41332 | michael | 2019-02-16 09:50:13 +0100 (Sat, 16 Feb 2019) | 1 line
Changed paths:
   M /trunk/packages/fcl-xml/src/xmlconf.pp

* Fix bug ID #34854

git-svn-id: branches/fixes_3_2@41923 -
2019-04-22 11:51:36 +00:00

516 lines
11 KiB
PHP

{
This file is part of the Free Component Library (FCL)
Copyright (c) 1999-2007 by the Free Pascal development team
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
{****************************************************************************}
{* TParser *}
{****************************************************************************}
const
{$ifdef CPU16}
{ Avoid too big local stack use for
MSDOS tiny memory model that uses less than 4096
bytes for total stack by default. }
ParseBufSize = 512;
{$else not CPU16}
ParseBufSize = 4096;
{$endif not CPU16}
LastSpecialToken = 5;
TokNames : array[0..LastSpecialToken] of string =
(
'EOF',
'Symbol',
'String',
'Integer',
'Float',
'WideString'
);
function TParser.GetTokenName(aTok: char): string;
begin
if ord(aTok) <= LastSpecialToken then
Result:=TokNames[ord(aTok)]
else Result:=aTok;
end;
procedure TParser.LoadBuffer;
var
BytesRead: integer;
begin
BytesRead := FStream.Read(FBuf^, ParseBufSize);
FBuf[BytesRead] := #0;
Inc(FDeltaPos, BytesRead);
FPos := 0;
FBufLen := BytesRead;
FEofReached:=BytesRead = 0;
end;
procedure TParser.CheckLoadBuffer; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
begin
if fBuf[fPos]=#0 then LoadBuffer;
end;
procedure TParser.ProcessChar; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
begin
fLastTokenStr:=fLastTokenStr+fBuf[fPos];
inc(fPos);
CheckLoadBuffer;
end;
function TParser.IsNumber: boolean; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
begin
Result:=fBuf[fPos] in ['0'..'9'];
end;
function TParser.IsHexNum: boolean; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
begin
Result:=fBuf[fPos] in ['0'..'9','A'..'F','a'..'f'];
end;
function TParser.IsAlpha: boolean; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
begin
Result:=fBuf[fPos] in ['_','A'..'Z','a'..'z'];
end;
function TParser.IsAlphaNum: boolean; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
begin
Result:=IsAlpha or IsNumber;
end;
function TParser.GetHexValue(c: char): byte; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
begin
case c of
'0'..'9' : Result:=ord(c)-$30;
'A'..'F' : Result:=ord(c)-$37; //-$41+$0A
'a'..'f' : Result:=ord(c)-$57; //-$61+$0A
end;
end;
function TParser.GetAlphaNum: string;
begin
if not IsAlpha then
ErrorFmt(SParExpected,[GetTokenName(toSymbol)]);
Result:='';
while IsAlphaNum do
begin
Result:=Result+fBuf[fPos];
inc(fPos);
CheckLoadBuffer;
end;
end;
procedure TParser.HandleNewLine;
begin
if fBuf[fPos]=#13 then //CR
begin
inc(fPos);
CheckLoadBuffer;
end;
if fBuf[fPos]=#10 then
begin
inc(fPos); //CR LF or LF
CheckLoadBuffer;
end;
inc(fSourceLine);
fDeltaPos:=-(fPos-1);
end;
procedure TParser.SkipBOM;
var
i : integer;
bom : string[3];
backup : integer;
begin
i:=1;
bom:=' ';
backup:=fPos;
while (fBuf[fPos] in [#$BB,#$BF,#$EF]) and (i<=3) do
begin
bom[i]:=fBuf[fPos];
inc(fPos);
CheckLoadBuffer;
inc(i);
end;
if (bom<>(#$EF+#$BB+#$BF)) then
fPos:=backup;
end;
procedure TParser.SkipSpaces;
begin
while fBuf[fPos] in [' ',#9] do begin
inc(fPos);
CheckLoadBuffer;
end;
end;
procedure TParser.SkipWhitespace;
begin
while true do
begin
case fBuf[fPos] of
' ',#9 : SkipSpaces;
#10,#13 : HandleNewLine
else break;
end;
end;
end;
procedure TParser.HandleEof;
begin
fToken:=toEOF;
fLastTokenStr:='';
end;
procedure TParser.HandleAlphaNum;
begin
fLastTokenStr:=GetAlphaNum;
fToken:=toSymbol;
end;
procedure TParser.HandleNumber;
type
floatPunct = (fpDot,fpE);
floatPuncts = set of floatPunct;
var
allowed : floatPuncts;
begin
fLastTokenStr:='';
while IsNumber do
ProcessChar;
fToken:=toInteger;
if (fBuf[fPos] in ['.','e','E']) then
begin
fToken:=toFloat;
allowed:=[fpDot,fpE];
while (fBuf[fPos] in ['.','e','E','0'..'9']) do
begin
case fBuf[fPos] of
'.' : if fpDot in allowed then Exclude(allowed,fpDot) else break;
'E','e' : if fpE in allowed then
begin
allowed:=[];
ProcessChar;
if (fBuf[fPos] in ['+','-']) then ProcessChar;
if not (fBuf[fPos] in ['0'..'9']) then
ErrorFmt(SParInvalidFloat,[fLastTokenStr+fBuf[fPos]]);
end
else break;
end;
ProcessChar;
end;
end;
if (fBuf[fPos] in ['s','S','d','D','c','C']) then //single, date, currency
begin
fFloatType:=fBuf[fPos];
inc(fPos);
CheckLoadBuffer;
fToken:=toFloat;
end
else fFloatType:=#0;
end;
procedure TParser.HandleHexNumber;
var valid : boolean;
begin
fLastTokenStr:='$';
inc(fPos);
CheckLoadBuffer;
valid:=false;
while IsHexNum do
begin
valid:=true;
ProcessChar;
end;
if not valid then
ErrorFmt(SParInvalidInteger,[fLastTokenStr]);
fToken:=toInteger;
end;
function TParser.HandleQuotedString: string;
begin
Result:='';
inc(fPos);
CheckLoadBuffer;
while true do
begin
case fBuf[fPos] of
#0 : ErrorStr(SParUnterminatedString);
#13,#10 : ErrorStr(SParUnterminatedString);
'''' : begin
inc(fPos);
CheckLoadBuffer;
if fBuf[fPos]<>'''' then exit;
end;
end;
Result:=Result+fBuf[fPos];
inc(fPos);
CheckLoadBuffer;
end;
end;
procedure TParser.HandleDecimalCharacter(var ascii: boolean; out
WideChr: widechar; out StringChr: char);
var i : integer;
begin
inc(fPos);
CheckLoadBuffer;
// read a word number
i:=0;
while IsNumber and (i<high(word)) do
begin
i:=i*10+ord(fBuf[fPos])-ord('0');
inc(fPos);
CheckLoadBuffer;
end;
if i>high(word) then i:=0;
if i>127 then ascii:=false;
WideChr:=widechar(word(i));
if i<256 then
StringChr:=chr(i)
else
StringChr:=#0;
end;
procedure TParser.HandleString;
var ascii : boolean;
s: string;
w: WideChar;
c: char;
begin
fLastTokenWStr:='';
fLastTokenStr:='';
ascii:=true;
while true do
begin
case fBuf[fPos] of
'''' :
begin
// avoid conversions,
// On some systems conversion from ansistring to widestring and back
// to ansistring does not give the original ansistring.
// See bug http://bugs.freepascal.org/view.php?id=15841
s:=HandleQuotedString;
fLastTokenWStr:=fLastTokenWStr+UnicodeString(s);
fLastTokenStr:=fLastTokenStr+s;
end;
'#' :
begin
HandleDecimalCharacter(ascii,w,c);
fLastTokenWStr:=fLastTokenWStr+w;
fLastTokenStr:=fLastTokenStr+c;
end;
else break;
end;
end;
if ascii then
fToken:=Classes.toString
else
fToken:=toWString;
end;
procedure TParser.HandleMinus;
begin
inc(fPos);
CheckLoadBuffer;
if IsNumber then
begin
HandleNumber;
fLastTokenStr:='-'+fLastTokenStr;
end
else
begin
fToken:='-';
fLastTokenStr:=fToken;
end;
end;
procedure TParser.HandleUnknown;
begin
fToken:=fBuf[fPos];
fLastTokenStr:=fToken;
inc(fPos);
CheckLoadBuffer;
end;
constructor TParser.Create(Stream: TStream);
begin
fStream:=Stream;
fBuf:=GetMem(ParseBufSize+1);
fBufLen:=0;
fPos:=0;
fDeltaPos:=1;
fSourceLine:=1;
fEofReached:=false;
fLastTokenStr:='';
fLastTokenWStr:='';
fFloatType:=#0;
fToken:=#0;
LoadBuffer;
SkipBom;
NextToken;
end;
destructor TParser.Destroy;
Var
aCount : Integer;
begin
if fToken=toWString then
aCount:=Length(fLastTokenWStr)*2
else
aCount:=Length(fLastTokenStr);
fStream.Position:=SourcePos-aCount;
FreeMem(fBuf);
end;
procedure TParser.CheckToken(T: Char);
begin
if fToken<>T then
ErrorFmt(SParWrongTokenType,[GetTokenName(T),GetTokenName(fToken)]);
end;
procedure TParser.CheckTokenSymbol(const S: string);
begin
CheckToken(toSymbol);
if CompareText(fLastTokenStr,S)<>0 then
ErrorFmt(SParWrongTokenSymbol,[s,fLastTokenStr]);
end;
procedure TParser.Error(const Ident: string);
begin
ErrorStr(Ident);
end;
procedure TParser.ErrorFmt(const Ident: string; const Args: array of const);
begin
ErrorStr(Format(Ident,Args));
end;
procedure TParser.ErrorStr(const Message: string);
begin
raise EParserError.CreateFmt(Message+SParLocInfo,[SourceLine,fPos+fDeltaPos,SourcePos]);
end;
procedure TParser.HexToBinary(Stream: TStream);
var outbuf : array[0..ParseBufSize-1] of byte;
b : byte;
i : integer;
begin
i:=0;
SkipWhitespace;
while IsHexNum do
begin
b:=(GetHexValue(fBuf[fPos]) shl 4);
inc(fPos);
CheckLoadBuffer;
if not IsHexNum then
Error(SParUnterminatedBinValue);
b:=b or GetHexValue(fBuf[fPos]);
inc(fPos);
CheckLoadBuffer;
outbuf[i]:=b;
inc(i);
if i>=ParseBufSize then
begin
Stream.WriteBuffer(outbuf[0],i);
i:=0;
end;
SkipWhitespace;
end;
if i>0 then
Stream.WriteBuffer(outbuf[0],i);
NextToken;
end;
function TParser.NextToken: Char;
begin
SkipWhiteSpace;
if fEofReached then
HandleEof
else
case fBuf[fPos] of
'_','A'..'Z','a'..'z' : HandleAlphaNum;
'$' : HandleHexNumber;
'-' : HandleMinus;
'0'..'9' : HandleNumber;
'''','#' : HandleString
else
HandleUnknown;
end;
Result:=fToken;
end;
function TParser.SourcePos: Longint;
begin
Result:=fStream.Position-fBufLen+fPos;
end;
function TParser.TokenComponentIdent: string;
begin
if fToken<>toSymbol then
ErrorFmt(SParExpected,[GetTokenName(toSymbol)]);
CheckLoadBuffer;
while fBuf[fPos]='.' do
begin
ProcessChar;
fLastTokenStr:=fLastTokenStr+GetAlphaNum;
end;
Result:=fLastTokenStr;
end;
{$ifndef FPUNONE}
Function TParser.TokenFloat: Extended;
var errcode : word;
begin
Val(fLastTokenStr,Result,errcode);
if errcode<>0 then
ErrorFmt(SParInvalidFloat,[fLastTokenStr]);
end;
{$endif}
Function TParser.TokenInt: Int64;
begin
if not TryStrToInt64(fLastTokenStr,Result) then
Result:=Int64(StrToQWord(fLastTokenStr)); //second chance for malformed files
end;
function TParser.TokenString: string;
begin
case fToken of
toWString : Result:=string(fLastTokenWStr);
toFloat : if fFloatType<>#0 then
Result:=fLastTokenStr+fFloatType
else Result:=fLastTokenStr
else
Result:=fLastTokenStr;
end;
end;
function TParser.TokenWideString: WideString;
begin
if fToken=toWString then
Result:=fLastTokenWStr
else
Result:=WideString(fLastTokenStr);
end;
function TParser.TokenSymbolIs(const S: string): Boolean;
begin
Result:=(fToken=toSymbol) and (CompareText(fLastTokenStr,S)=0);
end;