Difference between revisions of "Rosetta Stone"

From Lazarus wiki
Jump to navigationJump to search
m (layout mainly)
m (→‎Search and replace in a file: Fixed syntax highlighting; added category)
(44 intermediate revisions by 6 users not shown)
Line 11: Line 11:
 
* [http://mc-computing.com/Languages/ http://mc-computing.com/Languages/] This page has some explanation of the concepts involved
 
* [http://mc-computing.com/Languages/ http://mc-computing.com/Languages/] This page has some explanation of the concepts involved
 
* [http://rosettacode.org/wiki/Category:Pascal http://rosettacode.org/wiki/Category:Pascal] A huge amount of languages, even esoteric, and tasks make this site special
 
* [http://rosettacode.org/wiki/Category:Pascal http://rosettacode.org/wiki/Category:Pascal] A huge amount of languages, even esoteric, and tasks make this site special
 +
* [[Pascal for C users]]
 +
* [[Pascal for CSharp users]]
 +
* [[Pascal for Java users]]
  
 
== Operating systems ==
 
== Operating systems ==
If you know how to do something in an operating system, chances are you can do the same with FPC/Lazarus.
+
If you know how to do something in an operating system, chances are you can do the same using FPC/Lazarus.
  
 
The table below gives a rough mapping of some tasks:
 
The table below gives a rough mapping of some tasks:
 
{| {{table}}
 
{| {{table}}
| align="center" style="background:#f0f0f0;"|'''Windows/DOS'''
+
| style="background:#f0f0f0;"|'''Windows/DOS'''
| align="center" style="background:#f0f0f0;"|'''Unix/Linux'''
+
| style="background:#f0f0f0;"|'''Unix/Linux'''
| align="center" style="background:#f0f0f0;"|'''Description'''
+
| style="background:#f0f0f0;"|'''Description'''
| align="center" style="background:#f0f0f0;"|'''FreePascal/Lazarus'''
+
| style="background:#f0f0f0;"|'''FreePascal/Lazarus'''
 
|-
 
|-
| copy||cp||Copy file||Lazarus fileutil.copyfile; roll your own with filestreams
+
| assoc||||Show/edit file associations||See [[FileAssociation]]
 +
|-
 +
| copy||cp||Copy file||Lazarus [[CopyFile|fileutil.copyfile]]; roll your own with filestreams, see e.g. [[File_Handling_In_Pascal#FileCopy]]
 +
|-
 +
| date /t||date||Show current date||sysutils.now (date/time); sysutils.date (date); sysutils.time (time)
 
|-
 
|-
 
| del, erase||rm, rm -f||Delete file||sysutils.deletefile, erase
 
| del, erase||rm, rm -f||Delete file||sysutils.deletefile, erase
Line 28: Line 35:
 
| deltree, rmdir /s||rm -r,rm -rf ||Remove directories with subdirectories||Lazarus fileutil.deletedirectory
 
| deltree, rmdir /s||rm -r,rm -rf ||Remove directories with subdirectories||Lazarus fileutil.deletedirectory
 
|-
 
|-
| dir||ls||Find files in a directory||Lazarus FindAllFiles  
+
| dir||ls||Find files in a directory||Lazarus [[FindAllFiles]]
 +
|-
 +
| diskpart list volume||mount||Show partitions/volumes/drives on a computer||Windows: see [[Windows_Programming_Tips#Listing_all_available_drives]]
 +
 
 +
Linux: see [[Linux_Programming_Tips#Get_the_list_of_mounted_partitions]]
 +
 
 +
Unix: you'll have to parse some files (e.g. /etc/mtab) yourself, depending on Unix flavour; see [http://lazarus.freepascal.org/index.php/topic,15943.msg86569.html#msg86569 Forum post]
 +
|-
 +
|find||grep||Search for a text/string||Several options, including the pos, ansipos functions. Regular expression support is provided by the [[RegExpr]] unit.
 +
|-
 +
|ldifde||ldapsearch||Search through Active Directory/LDAP||Use [[Synapse]] ldapsend unit to work with LDAP queries; see e.g. [http://leonardorame.blogspot.com/2007_02_01_archive.html example code on Leonardo Ramé's blog]
 +
|-
 +
|md5sum||md5sum||Calculate hash of file contents||You can use the MDFile function in the md5 FPC unit.
 +
|-
 +
|mkdir||mkdir||Create directory||mkdir; forcedirectories (creates entire path, if necessary)
 
|-  
 
|-  
| mkdir||mkdir||Create directory||mkdir; forcedirectories (creates entire path, if necessary)
+
|move||mv||Move file to another directory||Within partition/disk: sysutils.renamefile; otherwise copy and delete original
 
|-  
 
|-  
| move||mv||Move file to another directory||Within partition/disk: sysutils.renamefile; otherwise copy and delete original
+
|rename, ren||mv||Rename file||sysutils.renamefile (can also "move" a file between directories, but only on same partition/disk  
 +
|-
 +
|sc query <servicename>||service --status-all||Show status for service||See [[ServiceManager]]
 +
|-
 +
|?||<nowiki>sed -i 's|Delphi|FreePascal|g' readme.txt</nowiki>||Search and replace text in file.||See example code below.
 +
|-
 +
|shutdown||shutdown||Shut down computer||Windows: see [http://forum.lazarus.freepascal.org/index.php/topic,16258.msg87992.html#msg87992 forum post]
 +
|-
 +
|tasklist||ps||List or find processes||Windows: [[Windows_Programming_Tips#Showing.2Ffinding_processes]]
 +
|-
 +
|?||touch||Create a new empty file||sysutils.filecreate(filename)
 
|-  
 
|-  
| rename, ren||mv||Rename file||sysutils.renamefile (can also \"move\" file between directories, but only on same partition/disk
+
|?||touch||Modify file time||See [[Create a new file date/de]]
 +
|-
 +
|?||uname||Get kernel/system info||See uname function below.
 +
|-
 +
|wget, curl||wget, curl||Download file from HTTP/FTP||Multiple options, e.g. use synapse httpsend or ftpsend units: [[Synapse#Downloading_files]]
 +
|-
 +
|?||which||Search for executable in path||Lazarus fileutil.FindDefaultExecutablePath; see also the example below.
 
|-  
 
|-  
| wget, curl||wget, curl||Download file from HTTP/FTP||Multiple optons, e.g. use synapse httpsend or ftpsend units
+
|?||whoami||Find out username||See UserName function below. On Windows: you can check if you're Administrator: winutils.iswindowsadmin(). On *nix: fpgeteuid shows you the effective userid (0 for root).
 
|-  
 
|-  
 
|  
 
|  
 
|}
 
|}
 +
 +
== Emulating uname ==
 +
Works on Linux, probably FreeBSD:
 +
 +
<syntaxhighlight lang="pascal">
 +
program uname;
 +
 +
uses  baseunix;
 +
 +
var KernelName: UtsName;
 +
 +
begin
 +
fpuname(KernelName);
 +
writeln(kernelname.sysname);
 +
writeln(kernelname.nodename);
 +
writeln(kernelname.release);
 +
writeln(kernelname.version);
 +
writeln(kernelname.machine);
 +
writeln(kernelname.domain);
 +
end.
 +
</syntaxhighlight>
 +
 +
Sample output:
 +
 +
Linux
 +
mydebianmachine
 +
3.12-1-amd64
 +
#1 SMP Debian 3.12.6-2 (2013-12-29)
 +
x86_64
 +
(none)
 +
 +
== Emulating which ==
 +
Although Lazarus has FindDefaultExecutablePath, it has some flaws. Use e.g. this code:
 +
 +
<syntaxhighlight lang="pascal">
 +
function Which(Executable: string): string;
 +
var
 +
  Output: string;
 +
begin
 +
  {$IFDEF UNIX}
 +
  // Note: we're using external which because
 +
  // FindDefaultExecutablePath
 +
  // doesn't check if the user has execute permission
 +
  // on the found file.
 +
  ExecuteCommand('which '+Executable,Output,false);
 +
  // Remove trailing LF(s) and other control codes:
 +
  while (length(output)>0) and (ord(output[length(output)])<$20) do
 +
    delete(output,length(output),1);
 +
  {$ELSE}
 +
  Output:=FindDefaultExecutablePath(Executable);
 +
  {$ENDIF UNIX}
 +
  // Extra check:
 +
  if (Output<>'') and fileexists(Output) then
 +
  begin
 +
    result:=Output;
 +
  end
 +
  else
 +
  begin
 +
    result:=''; //command failed
 +
  end;
 +
end;
 +
</syntaxhighlight>
 +
 +
== Emulating whoami ==
 +
 +
... or getting the current user's operating system username. Returns a UTF8 string.
 +
 +
<syntaxhighlight lang="pascal">
 +
uses
 +
  {$IFDEF UNIX}
 +
  {$IF (DEFINED(LINUX)) OR (DEFINED(FREEBSD))}
 +
  ,users //not available on OSX
 +
  {$ENDIF}
 +
  ,baseunix //for fpgetuid
 +
  .... //other unix stuff
 +
  {$ENDIF}
 +
  {$IFDEF MSWINDOWS}
 +
  ,windows
 +
  {$ENDIF}
 +
  ,lazutf8
 +
 +
function UserName: string;
 +
// Get Operating System user name
 +
{$IFDEF WINDOWS}
 +
const
 +
  MaxLen = 256;
 +
var
 +
  Len: DWORD;
 +
  WS: WideString;
 +
  Res: windows.BOOL;
 +
{$ENDIF}
 +
begin
 +
  Result := '';
 +
  {$IFDEF WINDOWS}
 +
    Len := MaxLen;
 +
    {$IFNDEF WINCE}
 +
    // Check for Win98..WinME:
 +
    if Win32MajorVersion <= 4 then
 +
    begin
 +
      SetLength(Result,MaxLen);
 +
      Res := Windows.GetUserName(@Result[1], Len);
 +
      if Res then
 +
      begin
 +
        SetLength(Result,Len-1);
 +
        Result := SysToUtf8(Result);
 +
      end
 +
      else
 +
        SetLength(Result,0);
 +
    end
 +
    else
 +
    {$ENDIF NOT WINCE}
 +
    begin
 +
      SetLength(WS, MaxLen-1);
 +
      Res := Windows.GetUserNameW(@WS[1], Len);
 +
      if Res then
 +
      begin
 +
        SetLength(WS, Len - 1);
 +
        Result := Utf16ToUtf8(WS);
 +
      end
 +
      else
 +
        SetLength(Result,0);
 +
    end;
 +
    {$ENDIF WINDOWS}
 +
    {$IFDEF UNIX}
 +
    {$IF (DEFINED(LINUX)) OR (DEFINED(FREEBSD))}
 +
    Result := SysToUtf8(GetUserName(fpgetuid));
 +
    {$ENDIF}
 +
    if Result = '' then
 +
      Result := GetEnvironmentVariableUTF8('USER'); //fallback or other unixes which export $USER and don't support GetUserName
 +
  {$ENDIF}
 +
end;
 +
</syntaxhighlight>
 +
 +
== Finding all occurrences of some bytes in a file ==
 +
 +
A sort of grep.
 +
From forum post by KpjComp: [http://lazarus.freepascal.org/index.php/topic,16574.msg90287.html#msg90287]
 +
 +
The block search class:
 +
 +
<syntaxhighlight lang="pascal">
 +
unit block_search;
 +
 +
{$mode objfpc}{$H+}
 +
 +
interface
 +
 +
uses
 +
  Classes, SysUtils, fgl;
 +
 +
type
 +
 +
  { TBlockSearch }
 +
  TBlockSearchResults = specialize TFPGList<int64>;
 +
 +
  TBlockSearch = class
 +
  private
 +
    src:TStream;
 +
    fresults:TBlockSearchResults;
 +
    block:array of byte;
 +
  public
 +
    procedure SearchFor(a:array of byte);
 +
    constructor Create(_Src:TStream; blocksize:integer = 1024*1024);
 +
    destructor Destroy; override;
 +
    property Results:TBlockSearchResults read fResults;
 +
  end;
 +
 +
implementation
 +
 +
{ TBlockSearch }
 +
 +
procedure TBlockSearch.SearchFor(a: array of byte);
 +
var
 +
  readsize:integer;
 +
  fPos:Int64;
 +
  fifoBuff:array of byte;
 +
  fifoSt,fifoEn,searchLen,lpbyte:integer;
 +
 +
  //
 +
  procedure CheckPos;
 +
  var
 +
    l,p:integer;
 +
  begin
 +
    p := fifoST;
 +
    for l := 0 to pred(SearchLen) do
 +
    begin
 +
      if a[l] <> fifoBuff[p] then exit;
 +
      //p := (p+1) mod SearchLen,  the if seems quicker
 +
      inc(p); if p >= SearchLen then p := 0;
 +
    end;
 +
    fresults.Add(fpos-searchLen);
 +
  end;
 +
  //
 +
begin
 +
  fresults.clear;
 +
  src.Position:=0;
 +
  readsize := src.Read(block[0],Length(block));
 +
  searchLen := length(a);
 +
  if searchLen > length(block) then
 +
    raise Exception.Create('Search term larger than blocksize');
 +
  if readsize < searchLen then exit;
 +
  setlength(fifoBuff,searchLen);
 +
  move(block[0],fifoBuff[0],searchLen);
 +
  fPos:=0;
 +
  fifoSt:=0;
 +
  fifoEn:=SearchLen-1;
 +
  CheckPos;
 +
  while readsize > 0 do
 +
  begin
 +
    for lpByte := 0 to pred(readsize) do
 +
    begin
 +
      inc(fifoSt); if fifoSt>=SearchLen then fifoST := 0;
 +
      inc(fifoEn); if fifoEn>=SearchLen then fifoEn := 0;
 +
      fifoBuff[fifoEn] := block[lpByte];
 +
      inc(fPos);
 +
      CheckPos;
 +
    end;
 +
    readsize := src.Read(block[0],Length(block));
 +
  end;
 +
end;
 +
 +
constructor TBlockSearch.Create(_Src: TStream; blocksize: integer);
 +
begin
 +
  inherited Create;
 +
  setlength(block,blocksize);
 +
  src := _src;
 +
  fresults := TBlockSearchResults.Create;
 +
end;
 +
 +
destructor TBlockSearch.Destroy;
 +
begin
 +
  freeAndNil(fresults);
 +
  inherited Destroy;
 +
end;
 +
 +
end.
 +
</syntaxhighlight>
 +
 +
Example of usage:
 +
 +
<syntaxhighlight lang="pascal">
 +
var
 +
  bs:TBlockSearch;
 +
..
 +
..
 +
  bs := TBlockSearch.Create(SourceFile);
 +
  try
 +
    bs.SearchFor(WhatIAmSearchingFor);
 +
    for i := 0 to bs.results.count-1 do
 +
    begin
 +
      // Example: we need to do something at an offset after the result
 +
      SourceFile.Position := bs.Results.Items[i] + 5;
 +
      SourceFile.ReadBuffer(RecordToParse, SizeOf(RecordToParse));
 +
      // And now I work on the data in the second packed record of arrays and output to memo or whatever
 +
    end;
 +
  finally
 +
    bs.free;
 +
  end;
 +
</syntaxhighlight>
 +
 +
== Search and replace in a file ==
 +
 +
This will search and replace by loading the entire file into the stringlist in memory and replacing there, then saving the stringlist again. While fine for small files, performance will likely suffer for large files.
 +
 +
<syntaxhighlight lang="pascal">
 +
procedure FindAndReplace(SearchFor, ReplaceWith, FileName: string);
 +
var
 +
  FileContents: TStringList;
 +
begin
 +
  FileContents:=TStringList.Create;
 +
  try
 +
    FileContents.LoadFromFile(FileName);
 +
    FileContents.Text:=StringReplace(FileContents.Text, SearchFor, ReplaceWith, [rfReplaceAll,rfIgnoreCase]);
 +
    FileContents.SaveToFile(FileName);
 +
  finally
 +
    FileContents.Free;
 +
  end;
 +
end;
 +
</syntaxhighlight>
  
 
[[Category:Tutorials]]
 
[[Category:Tutorials]]
 +
[[Category:Code Snippets]]
 +
[[Category:Code]]
 +
[[Category:FPC]]
 +
[[Category:Lazarus]]
 +
[[Category:Rosetta Stone]]

Revision as of 02:34, 4 February 2020

Introduction

Often, people new to a programming language/library have trouble mapping the things they know how to do in other environments to the new environments.

It can be handy to have a sort of "Rosetta stone" that roughly translates tasks from one environment/language into another.

Programming languages

If you have experience in other programming languages (such as C++, Visual Basic), there are some Rosetta stone web pages that might help you. As FreePascal/Lazarus syntax and library is fairly consistent with Delphi's, sites that "translate" to Delphi are also a valuable resource.

Some useful pages:

Operating systems

If you know how to do something in an operating system, chances are you can do the same using FPC/Lazarus.

The table below gives a rough mapping of some tasks:

Windows/DOS Unix/Linux Description FreePascal/Lazarus
assoc Show/edit file associations See FileAssociation
copy cp Copy file Lazarus fileutil.copyfile; roll your own with filestreams, see e.g. File_Handling_In_Pascal#FileCopy
date /t date Show current date sysutils.now (date/time); sysutils.date (date); sysutils.time (time)
del, erase rm, rm -f Delete file sysutils.deletefile, erase
deltree, rmdir /s rm -r,rm -rf Remove directories with subdirectories Lazarus fileutil.deletedirectory
dir ls Find files in a directory Lazarus FindAllFiles
diskpart list volume mount Show partitions/volumes/drives on a computer Windows: see Windows_Programming_Tips#Listing_all_available_drives

Linux: see Linux_Programming_Tips#Get_the_list_of_mounted_partitions

Unix: you'll have to parse some files (e.g. /etc/mtab) yourself, depending on Unix flavour; see Forum post

find grep Search for a text/string Several options, including the pos, ansipos functions. Regular expression support is provided by the RegExpr unit.
ldifde ldapsearch Search through Active Directory/LDAP Use Synapse ldapsend unit to work with LDAP queries; see e.g. example code on Leonardo Ramé's blog
md5sum md5sum Calculate hash of file contents You can use the MDFile function in the md5 FPC unit.
mkdir mkdir Create directory mkdir; forcedirectories (creates entire path, if necessary)
move mv Move file to another directory Within partition/disk: sysutils.renamefile; otherwise copy and delete original
rename, ren mv Rename file sysutils.renamefile (can also "move" a file between directories, but only on same partition/disk
sc query <servicename> service --status-all Show status for service See ServiceManager
? sed -i 's|Delphi|FreePascal|g' readme.txt Search and replace text in file. See example code below.
shutdown shutdown Shut down computer Windows: see forum post
tasklist ps List or find processes Windows: Windows_Programming_Tips#Showing.2Ffinding_processes
? touch Create a new empty file sysutils.filecreate(filename)
? touch Modify file time See Create a new file date/de
? uname Get kernel/system info See uname function below.
wget, curl wget, curl Download file from HTTP/FTP Multiple options, e.g. use synapse httpsend or ftpsend units: Synapse#Downloading_files
? which Search for executable in path Lazarus fileutil.FindDefaultExecutablePath; see also the example below.
? whoami Find out username See UserName function below. On Windows: you can check if you're Administrator: winutils.iswindowsadmin(). On *nix: fpgeteuid shows you the effective userid (0 for root).

Emulating uname

Works on Linux, probably FreeBSD:

program uname;

uses  baseunix;

var KernelName: UtsName;

begin
 fpuname(KernelName);
 writeln(kernelname.sysname);
 writeln(kernelname.nodename);
 writeln(kernelname.release);
 writeln(kernelname.version);
 writeln(kernelname.machine);
 writeln(kernelname.domain);
end.

Sample output:

Linux
mydebianmachine
3.12-1-amd64
#1 SMP Debian 3.12.6-2 (2013-12-29)
x86_64
(none)

Emulating which

Although Lazarus has FindDefaultExecutablePath, it has some flaws. Use e.g. this code:

function Which(Executable: string): string;
var
  Output: string;
begin
  {$IFDEF UNIX}
  // Note: we're using external which because
  // FindDefaultExecutablePath
  // doesn't check if the user has execute permission
  // on the found file.
  ExecuteCommand('which '+Executable,Output,false);
  // Remove trailing LF(s) and other control codes:
  while (length(output)>0) and (ord(output[length(output)])<$20) do
    delete(output,length(output),1);
  {$ELSE}
  Output:=FindDefaultExecutablePath(Executable);
  {$ENDIF UNIX}
  // Extra check:
  if (Output<>'') and fileexists(Output) then
  begin
    result:=Output;
  end
  else
  begin
    result:=''; //command failed
  end;
end;

Emulating whoami

... or getting the current user's operating system username. Returns a UTF8 string.

uses
  {$IFDEF UNIX}
  {$IF (DEFINED(LINUX)) OR (DEFINED(FREEBSD))}
  ,users //not available on OSX
  {$ENDIF}
  ,baseunix //for fpgetuid
  .... //other unix stuff
  {$ENDIF}
  {$IFDEF MSWINDOWS}
  ,windows
  {$ENDIF}
  ,lazutf8

function UserName: string;
// Get Operating System user name
{$IFDEF WINDOWS}
const
  MaxLen = 256;
var
  Len: DWORD;
  WS: WideString;
  Res: windows.BOOL;
{$ENDIF}
begin
  Result := '';
  {$IFDEF WINDOWS}
    Len := MaxLen;
    {$IFNDEF WINCE}
    // Check for Win98..WinME:
    if Win32MajorVersion <= 4 then
    begin
      SetLength(Result,MaxLen);
      Res := Windows.GetUserName(@Result[1], Len);
      if Res then
      begin
        SetLength(Result,Len-1);
        Result := SysToUtf8(Result);
      end
      else
        SetLength(Result,0);
    end
    else
    {$ENDIF NOT WINCE}
    begin
      SetLength(WS, MaxLen-1);
      Res := Windows.GetUserNameW(@WS[1], Len);
      if Res then
      begin
        SetLength(WS, Len - 1);
        Result := Utf16ToUtf8(WS);
      end
      else
        SetLength(Result,0);
    end;
    {$ENDIF WINDOWS}
    {$IFDEF UNIX}
    {$IF (DEFINED(LINUX)) OR (DEFINED(FREEBSD))}
    Result := SysToUtf8(GetUserName(fpgetuid));
    {$ENDIF}
    if Result = '' then
      Result := GetEnvironmentVariableUTF8('USER'); //fallback or other unixes which export $USER and don't support GetUserName
  {$ENDIF}
end;

Finding all occurrences of some bytes in a file

A sort of grep. From forum post by KpjComp: [1]

The block search class:

unit block_search;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, fgl;

type

  { TBlockSearch }
  TBlockSearchResults = specialize TFPGList<int64>;

  TBlockSearch = class
  private
    src:TStream;
    fresults:TBlockSearchResults;
    block:array of byte;
  public
    procedure SearchFor(a:array of byte);
    constructor Create(_Src:TStream; blocksize:integer = 1024*1024);
    destructor Destroy; override;
    property Results:TBlockSearchResults read fResults;
  end;

implementation

{ TBlockSearch }

procedure TBlockSearch.SearchFor(a: array of byte);
var
  readsize:integer;
  fPos:Int64;
  fifoBuff:array of byte;
  fifoSt,fifoEn,searchLen,lpbyte:integer;

  //
  procedure CheckPos;
  var
    l,p:integer;
  begin
    p := fifoST;
    for l := 0 to pred(SearchLen) do
    begin
      if a[l] <> fifoBuff[p] then exit;
      //p := (p+1) mod SearchLen,   the if seems quicker
      inc(p); if p >= SearchLen then p := 0;
    end;
    fresults.Add(fpos-searchLen);
  end;
  //
begin
  fresults.clear;
  src.Position:=0;
  readsize := src.Read(block[0],Length(block));
  searchLen := length(a);
  if searchLen > length(block) then
    raise Exception.Create('Search term larger than blocksize');
  if readsize < searchLen then exit;
  setlength(fifoBuff,searchLen);
  move(block[0],fifoBuff[0],searchLen);
  fPos:=0;
  fifoSt:=0;
  fifoEn:=SearchLen-1;
  CheckPos;
  while readsize > 0 do
  begin
    for lpByte := 0 to pred(readsize) do
    begin
      inc(fifoSt); if fifoSt>=SearchLen then fifoST := 0;
      inc(fifoEn); if fifoEn>=SearchLen then fifoEn := 0;
      fifoBuff[fifoEn] := block[lpByte];
      inc(fPos);
      CheckPos;
    end;
    readsize := src.Read(block[0],Length(block));
  end;
end;

constructor TBlockSearch.Create(_Src: TStream; blocksize: integer);
begin
  inherited Create;
  setlength(block,blocksize);
  src := _src;
  fresults := TBlockSearchResults.Create;
end;

destructor TBlockSearch.Destroy;
begin
  freeAndNil(fresults);
  inherited Destroy;
end;

end.

Example of usage:

var
  bs:TBlockSearch;
..
..
  bs := TBlockSearch.Create(SourceFile);
  try
    bs.SearchFor(WhatIAmSearchingFor);
    for i := 0 to bs.results.count-1 do
    begin
      // Example: we need to do something at an offset after the result
      SourceFile.Position := bs.Results.Items[i] + 5;
      SourceFile.ReadBuffer(RecordToParse, SizeOf(RecordToParse)); 
      // And now I work on the data in the second packed record of arrays and output to memo or whatever
    end;
  finally
    bs.free;
  end;

Search and replace in a file

This will search and replace by loading the entire file into the stringlist in memory and replacing there, then saving the stringlist again. While fine for small files, performance will likely suffer for large files.

procedure FindAndReplace(SearchFor, ReplaceWith, FileName: string);
var
  FileContents: TStringList;
begin
  FileContents:=TStringList.Create;
  try
    FileContents.LoadFromFile(FileName);
    FileContents.Text:=StringReplace(FileContents.Text, SearchFor, ReplaceWith, [rfReplaceAll,rfIgnoreCase]);
    FileContents.SaveToFile(FileName);
  finally
    FileContents.Free;
  end;
end;