123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903 |
- {
- This file is part of the Free Component Library
- ECMAScript (JavaScript) source lexical scanner
- 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.
- **********************************************************************}
- {$mode objfpc}
- {$h+}
- unit JSScanner;
- interface
- uses SysUtils, Classes, jstoken;
- resourcestring
- SErrInvalidCharacter = 'Invalid character ''%s''';
- SErrOpenString = 'string exceeds end of line';
- SErrIncludeFileNotFound = 'Could not find include file ''%s''';
- SErrIfXXXNestingLimitReached = 'Nesting of $IFxxx too deep';
- SErrInvalidPPElse = '$ELSE without matching $IFxxx';
- SErrInvalidPPEndif = '$ENDIF without matching $IFxxx';
- SInvalidHexadecimalNumber = 'Invalid decimal number';
- SErrInvalidNonEqual = 'Syntax Error: != or !== expected';
- SErrInvalidRegularExpression = 'Syntax error in regular expression: / expected, got: %s';
- Type
- TLineReader = class
- public
- function IsEOF: Boolean; virtual; abstract;
- function ReadLine: string; virtual; abstract;
- end;
- { TStreamLineReader }
- TStreamLineReader = class(TLineReader)
- private
- FStream : TStream;
- Buffer : Array[0..1024] of Byte;
- FBufPos,
- FBufLen : Integer;
- procedure FillBuffer;
- public
- Constructor Create(AStream : TStream);
- function IsEOF: Boolean; override;
- function ReadLine: string; override;
- end;
- TFileLineReader = class(TLineReader)
- private
- FTextFile: Text;
- FileOpened: Boolean;
- public
- constructor Create(const AFilename: string);
- destructor Destroy; override;
- function IsEOF: Boolean; override;
- function ReadLine: string; override;
- end;
- EJSScannerError = class(Exception);
- { TJSScanner }
- TJSScanner = class
- private
- FReturnComments: Boolean;
- FReturnWhiteSpace: Boolean;
- FSourceFile: TLineReader;
- FSourceFilename: string;
- FCurRow: Integer;
- FCurToken: TJSToken;
- FCurTokenString: string;
- FCurLine: string;
- TokenStr: PChar;
- FWasEndOfLine : Boolean;
- FSourceStream : TStream;
- FOwnSourceFile : Boolean;
- function CommentDiv: TJSToken;
- function DoIdentifier : TJSToken;
- function DoMultiLineComment: TJSToken;
- function DoNumericLiteral: TJSToken;
- function DoSingleLineComment: TJSToken;
- function DoStringLiteral: TJSToken;
- function DoWhiteSpace: TJSToken;
- function FetchLine: Boolean;
- function GetCurColumn: Integer;
- function ReadUnicodeEscape: WideChar;
- Function ReadRegex : TJSToken;
- protected
- procedure Error(const Msg: string);overload;
- procedure Error(const Msg: string; Args: array of Const);overload;
- public
- constructor Create(ALineReader: TLineReader);
- constructor Create(AStream : TStream);
- destructor Destroy; override;
- procedure OpenFile(const AFilename: string);
- Function FetchRegexprToken: TJSToken;
- Function FetchToken: TJSToken;
- Function IsEndOfLine : Boolean;
- Property WasEndOfLine : Boolean Read FWasEndOfLine;
- Property ReturnComments : Boolean Read FReturnComments Write FReturnComments;
- Property ReturnWhiteSpace : Boolean Read FReturnWhiteSpace Write FReturnWhiteSpace;
- property SourceFile: TLineReader read FSourceFile;
- property CurFilename: string read FSourceFilename;
- property CurLine: string read FCurLine;
- property CurRow: Integer read FCurRow;
- property CurColumn: Integer read GetCurColumn;
- property CurToken: TJSToken read FCurToken;
- property CurTokenString: string read FCurTokenString;
- end;
- implementation
- constructor TFileLineReader.Create(const AFilename: string);
- begin
- inherited Create;
- Assign(FTextFile, AFilename);
- Reset(FTextFile);
- FileOpened := true;
- end;
- destructor TFileLineReader.Destroy;
- begin
- if FileOpened then
- Close(FTextFile);
- inherited Destroy;
- end;
- function TFileLineReader.IsEOF: Boolean;
- begin
- Result := EOF(FTextFile);
- end;
- function TFileLineReader.ReadLine: string;
- begin
- ReadLn(FTextFile, Result);
- end;
- constructor TJSScanner.Create(ALineReader: TLineReader);
- begin
- inherited Create;
- FSourceFile := ALineReader;
- end;
- constructor TJSScanner.Create(AStream: TStream);
- begin
- FSourceStream:=ASTream;
- FOwnSourceFile:=True;
- Create(TStreamLineReader.Create(AStream));
- end;
- destructor TJSScanner.Destroy;
- begin
- If FOwnSourceFile then
- FSourceFile.Free;
- inherited Destroy;
- end;
- procedure TJSScanner.OpenFile(const AFilename: string);
- begin
- FSourceFile := TFileLineReader.Create(AFilename);
- FSourceFilename := AFilename;
- end;
- Function TJSScanner.FetchRegexprToken: TJSToken;
- begin
- if (CurToken in [tjsDiv,tjsDivEq]) then
- Result:=ReadRegEx
- else
- Result:=CurToken
- end;
- procedure TJSScanner.Error(const Msg: string);
- begin
- raise EJSScannerError.Create(Msg);
- end;
- procedure TJSScanner.Error(const Msg: string; Args: array of Const);
- begin
- raise EJSScannerError.CreateFmt(Msg, Args);
- end;
- function TJSScanner.FetchLine: Boolean;
- begin
- if FSourceFile.IsEOF then
- begin
- FCurLine := '';
- TokenStr := nil;
- Result := false;
- end else
- begin
- FCurLine := FSourceFile.ReadLine;
- TokenStr := PChar(CurLine);
- Result := true;
- Inc(FCurRow);
- FWasEndofLine:=True;
- end;
- end;
- function TJSScanner.DoWhiteSpace : TJSToken;
- begin
- Result:=tjsWhitespace;
- repeat
- Inc(TokenStr);
- if TokenStr[0] = #0 then
- if not FetchLine then
- begin
- FCurToken := Result;
- exit;
- end;
- until not (TokenStr[0] in [#9, ' ']);
- end;
- function TJSScanner.DoSingleLineComment : TJSToken;
- Var
- TokenStart : PChar;
- Len : Integer;
- begin
- Inc(TokenStr);
- TokenStart := TokenStr;
- while TokenStr[0] <> #0 do
- Inc(TokenStr);
- Len:=TokenStr-TokenStart;
- SetLength(FCurTokenString, Len);
- if (Len>0) then
- Move(TokenStart^,FCurTokenString[1],Len);
- Result := tjsComment;
- end;
- function TJSScanner.DoMultiLineComment : TJSToken;
- Var
- TokenStart : PChar;
- Len,OLen : Integer;
- PrevToken : Char;
- begin
- Inc(TokenStr);
- TokenStart := TokenStr;
- FCurTokenString := '';
- OLen:= 0;
- PrevToken:=#0;
- while Not ((TokenStr[0]='/') and (PrevToken='*')) do
- begin
- if (TokenStr[0]=#0) then
- begin
- Len:=TokenStr-TokenStart+1;
- SetLength(FCurTokenString,OLen+Len);
- if Len>1 then
- Move(TokenStart^,FCurTokenString[OLen+1],Len-1);
- Inc(OLen,Len);
- FCurTokenString[OLen]:=#10;
- if not FetchLine then
- begin
- Result := tjsEOF;
- FCurToken := Result;
- exit;
- end;
- TokenStart := TokenStr;
- PrevToken:=#0;
- end
- else
- begin
- PrevToken:=TokenStr[0];
- Inc(TokenStr);
- end;
- end;
- Len:=TokenStr-TokenStart-1; // -1 for *
- SetLength(FCurTokenString, Olen+Len);
- if (Len>0) then
- Move(TokenStart^, FCurTokenString[Olen + 1], Len);
- Inc(TokenStr);
- Result := tjsComment;
- end;
- function TJSScanner.CommentDiv : TJSToken;
- begin
- FCurTokenString := '';
- Inc(TokenStr);
- if (TokenStr[0] = '/') then // Single-line comment
- Result:=DoSingleLineComment
- else if (TokenStr[0]='*') then
- Result:=DoMultiLineComment
- else if (TokenStr[0] = '=') then // Single-line comment
- begin
- Result:=tjsDiveQ;
- Inc(TokenStr)
- end
- else
- Result:=tjsDiv;
- end;
- function TJSScanner.ReadUnicodeEscape: WideChar;
- Var
- S : String;
- I : Integer;
- begin
- S:='0000';
- For I:=1 to 4 do
- begin
- Inc(TokenStr);
- Case TokenStr[0] of
- '0'..'9','A'..'F','a'..'f' :
- S[i]:=Upcase(TokenStr[0]);
- else
- Error(SErrInvalidCharacter, [TokenStr[0]]);
- end;
- end;
- // Takes care of conversion... This needs improvement !!
- Result:=WideChar(StrToInt('$'+S));
- end;
- Function TJSScanner.ReadRegex: TJSToken;
- Var
- CC : Boolean; // Character class
- Done : Boolean;
- CL,L : Integer;
- TokenStart : PChar;
- begin
- if (CurToken<>tjsDivEq) then
- FCurTokenString := '/'
- else
- FCurTokenString := '/=';
- CL:=Length(FCurTokenString);
- Inc(TokenStr);
- TokenStart:=TokenStr;
- Done:=False;
- CC:=False;
- While Not Done do
- begin
- Case TokenStr[0] of
- #0 : Done:=True;
- '/' : Done:=Not CC;
- '\' : begin
- Inc(TokenStr);
- Done:=TokenStr=#0;
- end;
- '[' : CC:=True;
- ']' : CC:=False;
- end;
- if not Done then
- Inc(TokenStr);
- end;
- If (TokenStr[0]<>'/') then
- Error(SErrInvalidRegularExpression, [TokenStr[0]]);
- repeat
- Inc(TokenStr);
- until not (TokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_','$']);
- L:=(TokenStr-TokenStart);
- SetLength(FCurTokenString,CL+L);
- Move(TokenStart^,FCurTokenString[CL+1],L);
- Result:=tjsRegEx;
- end;
- function TJSScanner.DoStringLiteral: TJSToken;
- Var
- Delim : Char;
- TokenStart : PChar;
- Len,OLen: Integer;
- S : String;
- begin
- Delim:=TokenStr[0];
- Inc(TokenStr);
- TokenStart := TokenStr;
- OLen := 0;
- FCurTokenString := '';
- while not (TokenStr[0] in [#0,Delim]) do
- begin
- if (TokenStr[0]='\') then
- begin
- // Save length
- Len := TokenStr - TokenStart;
- Inc(TokenStr);
- // Read escaped token
- Case TokenStr[0] of
- '"' : S:='"';
- '''' : S:='''';
- 't' : S:=#9;
- 'b' : S:=#8;
- 'n' : S:=#10;
- 'r' : S:=#13;
- 'f' : S:=#12;
- '\' : S:='\';
- '/' : S:='/';
- 'u' : begin
- S:=ReadUniCodeEscape;
- end;
- #0 : Error(SErrOpenString);
- else
- Error(SErrInvalidCharacter, [TokenStr[0]]);
- end;
- SetLength(FCurTokenString, OLen + Len+1+Length(S));
- if Len > 0 then
- Move(TokenStart^, FCurTokenString[OLen + 1], Len);
- Move(S[1],FCurTokenString[OLen + Len+1],Length(S));
- Inc(OLen, Len+Length(S));
- // Next char
- // Inc(TokenStr);
- TokenStart := TokenStr+1;
- end;
- if TokenStr[0] = #0 then
- Error(SErrOpenString);
- Inc(TokenStr);
- end;
- if TokenStr[0] = #0 then
- Error(SErrOpenString);
- Len := TokenStr - TokenStart;
- SetLength(FCurTokenString, OLen + Len);
- if Len > 0 then
- Move(TokenStart^, FCurTokenString[OLen+1], Len);
- Inc(TokenStr);
- Result := tjsString;
- end;
- function TJSScanner.DoNumericLiteral :TJSToken;
- Var
- TokenStart : PChar;
- Len : Integer;
- begin
- TokenStart := TokenStr;
- while true do
- begin
- Inc(TokenStr);
- case TokenStr[0] of
- 'x':
- If (TokenStart[0]='0') and ((TokenStr-TokenStart)=1) then
- begin
- Inc(TokenStr);
- while Upcase(TokenStr[0]) in ['0'..'9','A'..'F'] do
- Inc(TokenStr);
- end
- else
- Error(SInvalidHexadecimalNumber);
- '.':
- begin
- if TokenStr[1] in ['0'..'9', 'e', 'E'] then
- begin
- Inc(TokenStr);
- repeat
- Inc(TokenStr);
- until not (TokenStr[0] in ['0'..'9', 'e', 'E','-','+']);
- end;
- break;
- end;
- '0'..'9': ;
- 'e', 'E':
- begin
- Inc(TokenStr);
- if TokenStr[0] in ['-','+'] then
- Inc(TokenStr);
- while TokenStr[0] in ['0'..'9'] do
- Inc(TokenStr);
- break;
- end;
- else
- break;
- end;
- end;
- Len:=TokenStr-TokenStart;
- Setlength(FCurTokenString, Len);
- if (Len>0) then
- Move(TokenStart^,FCurTokenString[1],Len);
- Result := tjsNumber;
- end;
- function TJSScanner.DoIdentifier : TJSToken;
- Var
- TokenStart:PChar;
- Len : Integer;
- I : TJSToken;
- begin
- Result:=tjsIdentifier;
- TokenStart := TokenStr;
- repeat
- Inc(TokenStr);
- //If (TokenStr[0]='\') and (TokenStr[1]='u') then
- until not (TokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_','$']);
- Len:=(TokenStr-TokenStart);
- SetLength(FCurTokenString,Len);
- if Len > 0 then
- Move(TokenStart^,FCurTokenString[1],Len);
- // Check if this is a keyword or identifier
- // !!!: Optimize this!
- for i:=FirstKeyword to Lastkeyword do
- if CurTokenString=TokenInfos[i] then
- begin
- Result := i;
- FCurToken := Result;
- exit;
- end;
- end;
- Function TJSScanner.FetchToken: TJSToken;
- begin
- if not (FCurtoken in [tjsWhiteSpace,tjsComment]) then
- FWasEndOfLine:=False;
- Repeat
- if TokenStr = nil then
- begin
- if not FetchLine then
- begin
- Result := tjsEOF;
- FCurToken := Result;
- exit;
- end;
- end;
- //CurPos:=TokenStr;
- FCurTokenString := '';
- case TokenStr[0] of
- #0: // Empty line
- begin
- FetchLine;
- Result := tjsWhitespace;
- end;
- '/' :
- Result:=CommentDiv;
- #9, ' ':
- Result := DoWhiteSpace;
- '''','"':
- Result:=DoStringLiteral;
- '0'..'9':
- Result:=DoNumericLiteral;
- '&':
- begin
- Inc(TokenStr);
- If Tokenstr[0]='&' then
- begin
- Inc(TokenStr);
- Result := tjsAndAnd;
- end
- else If Tokenstr[0]='=' then
- begin
- Inc(TokenStr);
- Result := tjsAndEQ;
- end
- else
- Result := tjsAnd;
- end;
- '%':
- begin
- Inc(TokenStr);
- If Tokenstr[0]='=' then
- begin
- Inc(TokenStr);
- Result := tjsModEq;
- end
- else
- Result := tjsMod;
- end;
- '^':
- begin
- Inc(TokenStr);
- If (TokenStr[0]='=') then
- begin
- Result:=tjsXorEq;
- Inc(tokenStr)
- end
- else
- result:=tjsXOR;
- end;
- '|':
- begin
- Inc(TokenStr);
- If Tokenstr[0]='|' then
- begin
- Inc(TokenStr);
- Result := tjsOROR;
- end
- else If Tokenstr[0]='=' then
- begin
- Inc(TokenStr);
- Result := tjsOREQ;
- end
- else
- Result := tjsOR;
- end;
- '(':
- begin
- Inc(TokenStr);
- Result := tjsBraceOpen;
- end;
- ')':
- begin
- Inc(TokenStr);
- Result := tjsBraceClose;
- end;
- '*':
- begin
- Inc(TokenStr);
- If (TokenStr[0]='=') then
- begin
- Inc(TokenStr);
- Result := tjsMulEq;
- end
- else
- Result := tjsMul;
- end;
- '+':
- begin
- Inc(TokenStr);
- If (TokenStr[0]='=') then
- begin
- Inc(TokenStr);
- Result := tjsPlusEq;
- end
- else If (TokenStr[0]='+') then
- begin
- Inc(TokenStr);
- Result := tjsPlusPlus;
- end
- else
- Result := tjsPlus;
- end;
- ',':
- begin
- Inc(TokenStr);
- Result := tjsComma;
- end;
- '-':
- begin
- Inc(TokenStr);
- If (TokenStr[0]='=') then
- begin
- Inc(TokenStr);
- Result:=tjsMinusEq
- end
- else If (TokenStr[0]='-') then
- begin
- Inc(TokenStr);
- Result:=tjsMinusMinus
- end
- else if (TokenStr[0] in ['0'..'9']) then
- begin
- Result:=DoNumericLiteral;
- If (Result=tjsNumber) then
- FCurTokenString:='-'+FCurTokenString;
- end
- else
- Result := tjsMinus;
- end;
- '.':
- begin
- Inc(TokenStr);
- if (TokenStr[0] in ['0'..'9']) then
- begin
- Result:=DoNumericLiteral;
- If (Result=tjsNumber) then
- FCurTokenString:='0.'+FCurTokenString;
- end
- else
- Result := tjsDot;
- end;
- ':':
- begin
- Inc(TokenStr);
- Result := tjsColon;
- end;
- '?':
- begin
- Inc(TokenStr);
- Result := tjsConditional;
- end;
- ';':
- begin
- Inc(TokenStr);
- Result := tjsSemicolon;
- end;
- '<':
- begin
- Inc(TokenStr);
- if TokenStr[0] = '=' then
- begin
- Inc(TokenStr);
- Result := tjsLE;
- end
- else if TokenStr[0] = '<' then
- begin
- Inc(TokenStr);
- if (TokenStr[0] = '=') then
- begin
- Inc(TokenStr);
- Result := tjsLShiftEq;
- end
- else
- Result := tjsLShift;
- end
- else
- Result := tjsLT;
- end;
- '=':
- begin
- Inc(TokenStr);
- if (TokenStr[0]='=') then
- begin
- Inc(TokenStr);
- If (TokenStr[0]='=') then
- begin
- Inc(TokenStr);
- Result:=tjsSEQ;
- end
- else
- Result:=tjsEQ;
- end
- else
- Result := tjsAssign;
- end;
- '!':
- begin
- Inc(TokenStr);
- if (TokenStr[0]='=') then
- begin
- Inc(TokenStr);
- If (TokenStr[0]='=') then
- begin
- Inc(TokenStr);
- Result:=tjsSNE;
- end
- else
- Result:=tjsNE;
- end
- else
- Result:=tjsNot;// Error(SErrInvalidNonEqual);
- end;
- '~':
- begin
- Inc(TokenStr);
- Result:=tjsInv;
- end;
- '>':
- begin
- Inc(TokenStr);
- if TokenStr[0] = '=' then
- begin
- Inc(TokenStr);
- Result:=tjsGE;
- end
- else if TokenStr[0] = '>' then
- begin
- Inc(TokenStr);
- if (TokenStr[0] = '>') then
- begin
- Inc(TokenStr);
- if (TokenStr[0] = '=') then
- begin
- Inc(TokenStr);
- Result:=tjsURSHIFTEQ;
- end
- else
- Result:=tjsURSHIFT;
- end
- else if (TokenStr[0] = '=') then
- begin
- Inc(TokenStr);
- Result:=tjsRSHIFTEq;
- end
- else
- Result:=tjsRSHIFT;
- end
- else
- Result := tjsGT;
- end;
- '[':
- begin
- Inc(TokenStr);
- Result := tJSSquaredBraceOpen;
- end;
- ']':
- begin
- Inc(TokenStr);
- Result := tJSSquaredBraceClose;
- end;
- '{':
- begin
- Inc(TokenStr);
- Result := tJSCurlyBraceOpen;
- end;
- '}':
- begin
- Inc(TokenStr);
- Result := tJSCurlyBraceClose;
- end;
- else
- Result:=DoIdentifier;
- end; // Case
- Until (Not (Result in [tjsComment,tjsWhitespace])) or
- ((Result=tjsComment) and ReturnComments) or
- ((Result=tjsWhiteSpace) and ReturnWhiteSpace);
- end;
- Function TJSScanner.IsEndOfLine: Boolean;
- begin
- Result:=(TokenStr=Nil) or (TokenStr[0] in [#0,#10,#13]);
- end;
- function TJSScanner.GetCurColumn: Integer;
- begin
- Result := TokenStr - PChar(CurLine);
- end;
- { TStreamLineReader }
- constructor TStreamLineReader.Create(AStream: TStream);
- begin
- FStream:=AStream;
- FBufPos:=0;
- FBufLen:=0;
- end;
- function TStreamLineReader.IsEOF: Boolean;
- begin
- Result:=(FBufPos>=FBufLen);
- If Result then
- begin
- FillBuffer;
- Result:=(FBufLen=0);
- end;
- end;
- procedure TStreamLineReader.FillBuffer;
- begin
- FBufLen:=FStream.Read(Buffer,SizeOf(Buffer)-1);
- Buffer[FBufLen]:=0;
- FBufPos:=0;
- end;
- function TStreamLineReader.ReadLine: string;
- Var
- FPos,OLen,Len: Integer;
- PRun : PByte;
- begin
- FPos:=FBufPos;
- SetLength(Result,0);
- Repeat
- PRun:=@Buffer[FBufPos];
- While (FBufPos<FBufLen) and Not (PRun^ in [10,13]) do
- begin
- Inc(PRun);
- Inc(FBufPos);
- end;
- If (FBufPos=FBufLen) then
- begin
- Len:=FBufPos-FPos;
- If (Len>0) then
- begin
- Olen:=Length(Result);
- SetLength(Result,OLen+Len);
- Move(Buffer[FPos],Result[OLen+1],Len);
- end;
- FillBuffer;
- FPos:=FBufPos;
- end;
- until (FBufPos=FBufLen) or (PRun^ in [10,13]);
- Len:=FBufPos-FPos;
- If (Len>0) then
- begin
- Olen:=Length(Result);
- SetLength(Result,OLen+Len);
- Move(Buffer[FPos],Result[OLen+1],Len)
- end;
- If (PRun^ in [10,13]) and (FBufPos<FBufLen) then
- begin
- Inc(FBufPos);
- // Check #13#10
- If (PRun^=13) then
- begin
- If (FBufPos=FBufLen) then
- FillBuffer;
- If (FBufPos<FBufLen) and (Buffer[FBufpos]=10) then
- Inc(FBufPos);
- end;
- end;
- end;
- end.
|