Hana 9e216da9ef go.mod: add go.mod and move pygments to third_party
After go1.16, go will use module mode by default,
even when the repository is checked out under GOPATH
or in a one-off directory. Add go.mod, go.sum to keep
this repo buildable without opting out of the module
mode.

> go mod init github.com/mmcgrana/gobyexample
> go mod tidy
> go mod vendor

In module mode, the 'vendor' directory is special
and its contents will be actively maintained by the
go command. pygments aren't the dependency the go will
know about, so it will delete the contents from vendor
directory. Move it to `third_party` directory now.

And, vendor the blackfriday package.

Note: the tutorial contents are not affected by the
change in go1.16 because all the examples in this
tutorial ask users to run the go command with the
explicit list of files to be compiled (e.g.
`go run hello-world.go` or `go build command-line-arguments.go`).
When the source list is provided, the go command does
not have to compute the build list and whether it's
running in GOPATH mode or module mode becomes irrelevant.
2021-02-15 16:45:26 -05:00

2709 lines
61 KiB
ObjectPascal

// vim:ft=pascal
unit YTools;
{===============================================================================
cYcnus.YTools 1.0.3 Beta for Delphi 4+
by licenser and Murphy
©2000-2003 by cYcnus
visit www.cYcnus.de
licenser@cYcnus.de (Heinz N. Gies)
murphy@cYcnus.de (Kornelius Kalnbach)
this unit is published under the terms of the GPL
===============================================================================}
interface
uses
Windows, SysUtils, Classes, YTypes;
const
BackSpace = #8;
Tab = #9;
LF = #10; //Line Feed
CR = #13; //Carriage Return
Space = #32;
EOLChars = [CR, LF];
{$IFNDEF VER140}
sLineBreak = #13#10;
SwitchChars = ['/', '-'];
{$ENDIF}
EOL = sLineBreak;
MaxCard = High(Cardinal);
AllChars = [#0..#255];
Alphabetical = ['A'..'Z', 'a'..'z'];
DecimalChars = ['0'..'9'];
AlphaNumerical = Alphabetical + DecimalChars;
StrangeChars = [#0..#31, #127, #129, #141..#144, #157, #158];
HexadecimalChars = DecimalChars + ['A'..'F', 'a'..'f'];
OctalChars = ['0'..'7'];
BinaryChars = ['0', '1'];
QuoteChars = ['''', '"'];
WildCards = ['*', '?'];
FileNameEnemies = WildCards + ['\', '/', ':', '<', '>', '|'];
HexChar: array[THex] of Char = (
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
LowerHexChar: array[THex] of Char = (
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');
BaseNChar: array[TBaseN] of Char = (
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H',
'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
cYcnusOverlayColor = $050001;
faFindEveryFile = faReadOnly + faHidden + faSysFile + faArchive;
platWin9x = [VER_PLATFORM_WIN32s, VER_PLATFORM_WIN32_WINDOWS];
{ Debugging }
procedure ClearReport(const ReportName: string);
procedure Report(const ReportName, Text: string);
procedure ReportFmt(const ReportName, Fmt: string; const Args: array of const);
{ Params }
procedure GetParams(Strings: TStrings); overload;
function GetParams(const Separator: string = ' '): string; overload;
function ParamNum(const S: string): Integer;
function ParamPrefixNum(const Prefix: string): Integer;
function Param(const S: string): Boolean;
function ParamPrefix(const Prefix: string): Boolean;
function Switch(const Switch: string; const PrefixChars: TCharSet = SwitchChars;
IgnoreCase: Boolean = True): Boolean;
function GetParam(const Prefix: string = ''; const Default: string = ''): string;
{ Dirs & UserName}
function GetMyDir(FullPath: Boolean = False): string;
function WinDir: string;
function SysDir: string;
function UserName: string;
{ Strings & Chars}
function FirstChar(const S: string): Char;
function LastChar(const S: string): Char;
function CharPos(C: Char; const S: string; Offset: Integer = 1): Integer; overload;
function CharPos(C: TCharSet; const S: string; Offset: Integer = 1): Integer; overload;
function CharPosR(C: Char; const S: string; Offset: Integer = -1): Integer;
function PosEx(const SubStr, S: string; Offset: Integer = 1): Integer;
function PosExText(const SubStr, S: string; Offset: Integer = 1): Integer;
function PosExAnsiText(const SubStr, S: string; Offset: Integer = 1): Integer;
function UntilChar(const S: string; Brake: Char): string; overload;
function UntilChar(const S: string; Brake: TCharSet): string; overload;
function UntilLastChar(const S: string; Brake: Char;
IgnoreNoBrake: Boolean = True): string;
function FromChar(const S: string; Brake: Char): string; overload;
function FromChar(const S: string; Brake: TCharSet): string; overload;
function FromLastChar(const S: string; Brake: Char;
IgnoreNoBrake: Boolean = False): string;
function BetweenChars(const S: string; Start, Finish: Char;
Inclusive: Boolean = False): string;
function UntilStr(const S: string; Brake: string): string;
function FromStr(const S: string; Brake: string): string;
function StringWrap(const S: string; Width: Integer; const LineEnd: string = EOL): string;
{ Splitting & Combining }
function Split(const S, Separator: string; IgnoreMultiSep: Boolean = True;
MinCount: Integer = 0): TStrA; overload;
procedure Split(const S, Separator: string; Strings: TStrings;
IgnoreMultiSep: Boolean = True); overload;
function Split(const S: string; Separators: TCharSet;
IgnoreMultiSep: Boolean = True; MinCount: Integer = 0): TStrA; overload;
procedure TileStr(const S: string; BrakeStart: Integer; BrakeEnd: Integer;
out Left, Right: string);
function Join(Strings: TStrings; Separator: string = ' '): string; overload;
function Join(StrA: TStrA; Separator: string = ' '): string; overload;
function MulStr(const S: string; Count: Integer): string;
{ Strings ausrichten }
function AlignR(const S: string; Width: Integer; Filler: Char = ' '): string;
function MaxStr(const S: string; MaxLen: Integer): string;
{ Stringing }
function TrimAll(const S: string): string;
function ControlChar(C: Char): Boolean;
function FriendlyChar(C: Char): Char;
function FriendlyStr(const S: string): string; overload;
function FriendlyStr(a: TByteA): string; overload;
function Quote(const S: string; Quoter: Char = '"'): string;
function UnQuote(const S: string): string;
function DeQuote(const S: string): string;
function StrNumerus(const Value: Integer; const Singular, Plural: string;
const Zero: string = '0'): string;
function MakeStr(const Items: array of const; Separator: string = ''): string;
procedure ShowText(const Items: array of const; Separator: string = '');
{ Delete }
function DeleteChars(const S: string; C: Char): string; overload;
function DeleteChars(const S: string; C: TCharSet): string; overload;
function ExtractChars(const S: string; C: TCharSet): string;
{ Find }
function CharCount(const S: string; C: Char): Integer;
function CharIn(const S: string; C: Char): Boolean; overload;
function CharIn(const S: string; C: TCharSet): Boolean; overload;
function StrAtPos(const S: string; Pos: Integer; const Str: string): Boolean;
function StrAtBegin(const S, Str: string): Boolean;
function StrIn(const S, SubStr: string): Boolean; overload;
function StrIn(A: TStrA; const S: string): Boolean; overload;
function StrIn(SL: TStrings; const S: string): Boolean; overload;
function StrIndex(A: TStrA; const S: string): Integer; overload;
function StrIndex(SL: TStrings; const S: string): Integer; overload;
function TextAtPos(const S: string; Pos: Integer; const Text: string): Boolean;
function TextAtBegin(const S, Text: string): Boolean;
function TextIn(const S, Text: string): Boolean; overload;
function TextIn(A: TStrA; const Text: string): Boolean; overload;
function TextIn(SL: TStrings; const Text: string): Boolean; overload;
function TextIndex(A: TStrA; const Text: string): Integer; overload;
function TextIndex(SL: TStrings; const Text: string): Integer; overload;
{ Replace }
function ReplaceChars(const S: string; Old, New: Char): string; overload;
function ReplaceChars(const S: string; Old: TCharSet; New: Char): string; overload;
function Replace(const S, Old, New: string): string;
{ TStrings }
function SLOfFile(const FileName: string): TStringList;
function ContainsEmptyLines(SL: TStrings): Boolean;
procedure DeleteEmptyLines(SL: TStrings);
procedure DeleteCommentLines(SL: TStrings; const CommentSign: string = '//');
procedure WriteSL(Strings: TStrings; const Prefix: string = '';
const Suffix: string = '');
function FindLine(SL: TStrings; const S: string): Integer;
procedure QuickSortSL(SL: TStringList);
{ TStrA }
function IncStrA(StrA: TStrA): Integer;
{ TByteA }
function StrOfByteA(a: TByteA): string;
function ByteAOfStr(const S: string): TByteA;
function ByteAOfInt(i: Integer): TByteA;
function IntOfByteA(A: TByteA): Integer;
function ByteAOfHex(const Hex: string): TByteA;
function SameByteA(const A, B: TByteA): Boolean;
function Reverse(a: TByteA): TByteA;
function SaveByteA(Data: TByteA; const FileName: string; Overwrite: Boolean = True): Boolean;
function LoadByteA(const FileName: string): TByteA;
function Endian(i: Integer): Integer;
{ Files }
function SizeOfFile(const FileName: string): Integer;
function FileEx(const FileName: string; AllowFolders: Boolean = False): Boolean;
function LWPSolve(const Dir: string): string;
function LWPSlash(const Dir: string): string;
function ExtractDrive(const FileName: string): string;
function ExtractPath(const FileName: string): string;
function ExtractPrefix(const FileName: string): string;
function ExtractSuffix(const FileName: string): string;
function IsValidFileName(const FileName: string): Boolean;
function MakeValidFileName(FileName: string; const Default: string = 'File'): string;
{ Converting }
function IsValidInteger(const S: string): Boolean;
function IsValidCardinal(const S: string): Boolean;
function StrOfBool(flag: Boolean; const TrueStr: string = 'True';
const FalseStr: string = 'False'): string;
function StrOfInt(i: Integer): string;
function CardOfStr(const S: string): Cardinal;
function HexOrd(Hex: Char): THex;
function ByteOfHex(Hex: THexByteStr): Byte;
function DecOfHex(const Hex: string): string;
function HexOfByte(b: Byte): THexByteStr;
function HexOfCard(i: Cardinal): string; overload;
function HexOfCard(i: Cardinal; Digits: Integer): string; overload;
function PascalHexArray(a: TByteA; Name: string): string;
function HexOfByteA(a: TByteA; Blocks: Integer = 1;
const Splitter: string = ' '): string;
function BinOfByteA(a: TByteA; Blocks: Integer = 4;
const Splitter: string = ' '): string;
function CardOfHex(Hex: string): Cardinal;
function IntOfBin(Bin: string): Cardinal;
function BinOfIntFill(n: cardinal; MinCount: Integer = 8): string;
function BinOfInt(n: cardinal): string;
function BaseNOfInt(I: Cardinal; B: TBaseN): string;
function IntOfBaseN(V: string; B: TBaseN): Cardinal;
{ Ranges }
function KeepIn(i, Bottom, Top: Variant): Variant;
function InRange(Value, Bottom, Top: Variant): Boolean;
function InStrictRange(Value, Bottom, Top: Variant): Boolean;
function Min(const A, B: Integer): Integer; overload;
function Min(const A: TIntA): Integer; overload;
function Max(const A, B: Integer): Integer; overload;
function Max(const A: TIntA): Integer; overload;
const
RangesSeparator = ',';
RangeInnerSeparator = '-';
RangeInfinite = '*';
RangeSpecialChars = [RangesSeparator, RangeInnerSeparator, RangeInfinite];
function RangesOfStr(const S: string): TRanges;
function InRanges(Ranges: TRanges; TestValue: Cardinal): Boolean;
function Success(Res: Integer; ResultOnSuccess: Integer = ERROR_SUCCESS): Boolean;
function Failure(Res: Integer; ResultOnSuccess: Integer = ERROR_SUCCESS): Boolean;
function ExpandString(const S: string): string;
{ Files }
procedure DeleteFiles(const Mask: string; ScanSubDirs: Boolean = True;
Attributes: Integer = faFindEveryFile);
procedure FileNew(const FileName: string);
function DateTimeOfFileTime(const FileTime: TFileTime): TDateTime;
{ FileNames }
function GetFileNew(FileName: string; NoFloppyDrives: Boolean = True): string;
{ Finding Files }
function FindAll(Strings: TStrings; const Mask: string;
ScanSubDirs: Boolean = True; Attributes: Integer = faFindEveryFile;
FileReturn: TFileNameFunc = nil): Boolean;
function FindAllFirst(const Mask: string; ScanSubDirs: Boolean = True;
Attributes: Integer = faFindEveryFile): string;
function FullOSInfo: string;
function Win32PlatformStr: string;
function Win9x: Boolean;
function WinNT: Boolean;
function Win2000: Boolean;
function WinXP: Boolean;
var
MyDir: string = '';
LastSuccessRes: Integer = 0;
{ Backward compatibility }
{$IFNDEF VER130}
function SameText(const S1, S2: string): Boolean;
{$ENDIF}
implementation
{$IFNDEF VER140}
uses FileCtrl;
{$ENDIF}
{$IFNDEF VER130}
function SameText(const S1, S2: string): Boolean;
begin
Result := CompareText(S1, S2) = 0;
end;
{$ENDIF}
procedure Report(const ReportName, Text: string);
var
F: TextFile;
FileName: string;
begin
FileName := MyDir + ReportName + '.rep';
Assign(F, FileName);
try
if not FileExists(FileName) then
Rewrite(F)
else
Append(F);
WriteLn(F, Text);
finally
Close(F);
end;
end;
procedure ClearReport(const ReportName: string);
var
FileName: string;
begin
FileName := MyDir + ReportName + '.rep';
DeleteFile(FileName);
end;
procedure ReportFmt(const ReportName, Fmt: string; const Args: array of const);
begin
Report(ReportName, Format(Fmt, Args));
end;
procedure GetParams(Strings: TStrings);
var
P: PChar;
Param: string;
function GetParamStr(var P: PChar; var Param: string): Boolean;
var
Quoted: Boolean;
begin
Param := '';
repeat
while (P[0] <> #0) and (P[0] <= ' ') do
Inc(P);
Quoted := False;
while P[0] <> #0 do begin
if P[0] = '"' then begin
Quoted := not Quoted;
Inc(P);
Continue; end;
if (P[0] <= ' ') and not Quoted then
Break;
Param := Param + P[0];
Inc(P);
end;
until (Param <> '') or (P[0] = #0);
Result := Param <> '';
end;
begin
Strings.Clear;
P := GetCommandLine;
GetParamStr(P, Param);
while GetParamStr(P, Param) do
Strings.Add(Param);
end;
function GetParams(const Separator: string = ' '): string;
var
SL: TStringList;
begin
SL := TStringList.Create;
GetParams(SL);
Result := Join(SL, Separator);
SL.Free;
end;
function Switch(const Switch: string; const PrefixChars: TCharSet = SwitchChars;
IgnoreCase: Boolean = True): Boolean;
//= SysUtils.FindCmdLineSwitch
var
i: Integer;
s: string;
begin
Result := True;
for i := 1 to ParamCount do begin
s := ParamStr(i);
if (s <> '') and (s[1] in PrefixChars) then begin
//i know that always s <> '', but this is saver
s := Copy(s, 2, MaxInt);
if (s = Switch) or (IgnoreCase and (0=AnsiCompareText(s, Switch))) then
Exit;
end;
end;
Result := False;
end;
function ParamNum(const S: string): Integer;
begin
for Result := 1 to ParamCount do
if 0=AnsiCompareText(ParamStr(Result), S) then
Exit;
Result := 0;
end;
function ParamPrefixNum(const Prefix: string): Integer;
var
Len: Integer;
begin
Len := Length(Prefix);
for Result := 1 to ParamCount do
if 0=AnsiCompareText(Copy(ParamStr(Result), 1, Len), Prefix) then
Exit;
Result := 0;
end;
function Param(const S: string): Boolean;
begin
Result := ParamNum(S) > 0;
end;
function ParamPrefix(const Prefix: string): Boolean;
begin
Result := ParamPrefixNum(Prefix) > 0;
end;
function GetParam(const Prefix: string = ''; const Default: string = ''): string;
var
i: Integer;
begin
Result := Default;
if Prefix = '' then begin
Result := ParamStr(1);
Exit; end;
i := ParamPrefixNum(Prefix);
if i > 0 then
Result := Copy(ParamStr(i), Length(Prefix) + 1, MaxInt);
end;
function GetMyDir(FullPath: Boolean = False): string;
var
Buffer: array[0..260] of Char;
begin
Result := '';
SetString(Result, Buffer, GetModuleFileName(0, Buffer, SizeOf(Buffer)));
if FullPath then
Result := GetFileNew(Result);
Result := ExtractPath(Result);
end;
function WinDir: string;
var
Res: PChar;
begin
Result := '\';
GetMem(Res, MAX_PATH);
GetWindowsDirectory(Res, MAX_PATH);
Result := Res + '\';
FreeMem(Res, MAX_PATH);
end;
function SysDir: string;
var
Res: PChar;
begin
Result := '\';
GetMem(Res, MAX_PATH);
GetSystemDirectory(Res, MAX_PATH);
Result := Res + '\';
FreeMem(Res, MAX_PATH);
end;
function UserName: string;
var
Len: Cardinal;
Res: PChar;
begin
Result := '';
GetMem(Res, MAX_PATH);
Len := MAX_PATH;
GetUserName(Res, Len);
Result := Res;
FreeMem(Res, MAX_PATH);
end;
function FirstChar(const S: string): Char;
begin
if s = '' then
Result := #0
else
Result := s[1];
end;
function LastChar(const S: string): Char;
begin
if s = '' then
Result := #0
else
Result := s[Length(s)];
end;
function CharPos(C: Char; const S: string; Offset: Integer = 1): Integer;
var
MaxPosToSearch: Integer;
begin
Result := Offset;
MaxPosToSearch := Length(S);
while Result <= MaxPosToSearch do begin
if S[Result] = C then
Exit;
Inc(Result);
end;
Result := 0;
end;
function CharPos(C: TCharSet; const S: string; Offset: Integer = 1): Integer;
var
MaxPosToSearch: Integer;
begin
Result := Offset;
MaxPosToSearch := Length(S);
while Result <= MaxPosToSearch do begin
if S[Result] in C then
Exit;
Inc(Result);
end;
Result := 0;
end;
function CharPosR(C: Char; const S: string; Offset: Integer = -1): Integer;
begin
if Offset < 0 then
Result := Length(S) + 1 - Offset
else
Result := Offset;
if Result > Length(S) then
Result := Length(S);
while Result > 0 do begin
if S[Result] = C then
Exit;
Dec(Result);
end;
end;
function PosEx(const SubStr, S: string; Offset: Integer = 1): Integer;
var
MaxPosToSearch, LenSubStr, i: Integer;
begin
if SubStr = '' then begin
Result := 0;
Exit; end;
if Offset < 1 then
Result := 1
else
Result := Offset;
LenSubStr := Length(SubStr);
MaxPosToSearch := Length(S) - LenSubStr + 1;
while Result <= MaxPosToSearch do begin
if S[Result] = SubStr[1] then begin
i := 1;
while (i < LenSubStr)
and (S[Result + i] = SubStr[i + 1]) do
Inc(i);
if i = LenSubStr then
Exit;
end;
Inc(Result);
end;
Result := 0;
end;
function PosExText(const SubStr, S: string; Offset: Integer = 1): Integer;
var
MaxPosToSearch, LenSubStr, i: Integer;
function SameChar(a, b: Char): Boolean;
begin
Result := UpCase(a) = UpCase(b)
end;
begin
if SubStr = '' then begin
Result := 0;
Exit; end;
if Offset < 1 then
Result := 1
else
Result := Offset;
LenSubStr := Length(SubStr);
MaxPosToSearch := Length(S) - LenSubStr + 1;
while Result <= MaxPosToSearch do begin
if SameChar(S[Result], SubStr[1]) then begin
i := 1;
while (i < LenSubStr)
and (SameChar(S[Result + i], SubStr[i + 1])) do
Inc(i);
if i = LenSubStr then
Exit;
end;
Inc(Result);
end;
Result := 0;
end;
function PosExAnsiText(const SubStr, S: string; Offset: Integer = 1): Integer;
var
MaxPosToSearch, LenSubStr, i: Integer;
function SameChar(a, b: Char): Boolean;
begin
Result := CharLower(PChar(a)) = CharLower(PChar(b));
end;
begin
if SubStr = '' then begin
Result := 0;
Exit; end;
if Offset < 1 then
Result := 1
else
Result := Offset;
LenSubStr := Length(SubStr);
MaxPosToSearch := Length(S) - LenSubStr + 1;
while Result <= MaxPosToSearch do begin
if SameChar(S[Result], SubStr[1]) then begin
i := 1;
while (i < LenSubStr)
and (SameChar(S[Result + i], SubStr[i + 1])) do
Inc(i);
if i = LenSubStr then
Exit;
end;
Inc(Result);
end;
Result := 0;
end;
function UntilChar(const S: string; Brake: Char): string;
var
p: Integer;
begin
p := CharPos(Brake, S);
if p > 0 then
Result := Copy(S, 1, p - 1)
else
Result := S;
end;
function UntilChar(const S: string; Brake: TCharSet): string;
var
p: Integer;
begin
Result := '';
p := CharPos(Brake, S);
if p > 0 then
Result := Copy(S, 1, p - 1)
else
Result := S;
end;
function UntilLastChar(const S: string; Brake: Char;
IgnoreNoBrake: Boolean = True): string;
var
p: Integer;
begin
Result := '';
p := CharPosR(Brake, S);
if p > 0 then
Result := Copy(S, 1, p - 1)
else if IgnoreNoBrake then
Result := S;
end;
function FromChar(const S: string; Brake: Char): string;
var
p: Integer;
begin
Result := '';
p := CharPos(Brake, S);
if p > 0 then
Result := Copy(S, p + 1, Length(S) - p);
end;
function FromChar(const S: string; Brake: TCharSet): string;
var
p: Integer;
begin
Result := '';
p := CharPos(Brake, S);
if p > 0 then
Result := Copy(S, p + 1, Length(S) - p);
end;
function FromLastChar(const S: string; Brake: Char;
IgnoreNoBrake: Boolean = False): string;
var
p: Integer;
begin
Result := '';
p := CharPosR(Brake, S);
if p > 0 then
Result := Copy(S, p + 1, Length(S) - p)
else if IgnoreNoBrake then
Result := S;
end;
function BetweenChars(const S: string; Start, Finish: Char;
Inclusive: Boolean = False): string;
var
p, fin: Integer;
begin
Result := '';
p := CharPos(Start, S);
if p = 0 then
Exit;
fin := CharPos(Finish, S, p + 1);
if fin = 0 then
Exit;
if not Inclusive then begin
Inc(p);
Dec(fin);
end;
Result := Copy(S, p, fin - p + 1);
end;
function UntilStr(const S: string; Brake: string): string;
var
p: Integer;
begin
if Length(Brake) = 1 then begin
Result := UntilChar(S, Brake[1]);
Exit; end;
p := PosEx(Brake, S);
if p > 0 then
Result := Copy(S, 1, p - 1)
else
Result := S;
end;
function FromStr(const S: string; Brake: string): string;
var
p: Integer;
begin
if Length(Brake) = 1 then begin
Result := FromChar(S, Brake[1]);
Exit; end;
Result := '';
p := PosEx(Brake, s);
if p > 0 then begin
Inc(p, Length(Brake));
Result := Copy(S, p, Length(S) - p + 1);
end;
end;
function StringWrap(const S: string; Width: Integer; const LineEnd: string = EOL): string;
var
i: Integer;
begin
Result := '';
if (S = '') or (Width < 1) then
Exit;
i := 1;
while True do begin
Result := Result + Copy(S, i, Width);
Inc(i, Width);
if i <= Length(S) then
Result := Result + LineEnd
else
Exit;
end;
end;
function Split(const S, Separator: string; IgnoreMultiSep: Boolean = True;
MinCount: Integer = 0): TStrA;
var
p, fin, SepLen: Integer;
procedure Add(const S: string);
begin
if IgnoreMultiSep and (S = '') then
Exit;
SetLength(Result, Length(Result) + 1);
Result[High(Result)] := S;
end;
begin
if S = '' then begin
if Length(Result) < MinCount then
SetLength(Result, MinCount);
Exit; end;
Result := nil;
SepLen := Length(Separator);
p := 1;
fin := PosEx(Separator, S);
while fin > 0 do begin
Add(Copy(S, p, fin - p));
p := fin + SepLen;
fin := PosEx(Separator, S, p);
end;
Add(Copy(S, p, Length(S) - p + 1));
if Length(Result) < MinCount then
SetLength(Result, MinCount);
end;
procedure Split(const S, Separator: string; Strings: TStrings;
IgnoreMultiSep: Boolean = True);
var
p, fin, SepLen: Integer;
procedure Add(const S: string);
begin
if IgnoreMultiSep and (S = '') then
Exit;
Strings.Add(S);
end;
begin
if S = '' then
Exit;
Strings.BeginUpdate;
SepLen := Length(Separator);
p := 1;
fin := PosEx(Separator, S);
while fin > 0 do begin
Add(Copy(S, p, fin - p));
p := fin + SepLen;
fin := PosEx(Separator, S, p);
end;
Add(Copy(S, p, Length(S) - p + 1));
Strings.EndUpdate;
end;
function Split(const S: string; Separators: TCharSet;
IgnoreMultiSep: Boolean = True; MinCount: Integer = 0): TStrA;
var
p, fin: Integer;
procedure Add(const S: string);
begin
if IgnoreMultiSep and (S = '') then
Exit;
SetLength(Result, Length(Result) + 1);
Result[High(Result)] := S;
end;
begin
if S = '' then begin
if Length(Result) < MinCount then
SetLength(Result, MinCount);
Exit; end;
Result := nil;
p := 1;
fin := CharPos(Separators, S);
while fin > 0 do begin
Add(Copy(S, p, fin - p));
p := fin + 1;
fin := CharPos(Separators, S, p);
end;
Add(Copy(S, p, Length(S) - p + 1));
if Length(Result) < MinCount then
SetLength(Result, MinCount);
end;
procedure TileStr(const S: string; BrakeStart: Integer; BrakeEnd: Integer;
out Left, Right: string);
begin
Left := Copy(S, 1, BrakeStart-1);
Right := Copy(S, BrakeEnd + 1, MaxInt);
end;
function Join(Strings: TStrings; Separator: string = ' '): string;
var
i, imax: Integer;
begin
Result := '';
imax := Strings.Count-1;
for i := 0 to imax do begin
Result := Result + Strings[i];
if i < imax then
Result := Result + Separator;
end;
end;
function Join(StrA: TStrA; Separator: string = ' '): string; overload;
var
i: Integer;
begin
Result := '';
for i := 0 to High(StrA) do begin
Result := Result + StrA[i];
if i < High(StrA) then
Result := Result + Separator;
end;
end;
function MulStr(const S: string; Count: Integer): string;
var
P: PChar;
Len, i: Integer;
begin
Result := '';
if Count = 0 then
Exit;
Len := Length(S);
SetLength(Result, Len * Count);
P := Pointer(Result);
for i := 1 to Count do begin
Move(Pointer(S)^, P^, Len);
Inc(P, Len);
end;
end;
function AlignR(const S: string; Width: Integer; Filler: Char = ' '): string;
begin
Result := MulStr(Filler, Width - Length(S)) + S;
end;
function MaxStr(const S: string; MaxLen: Integer): string;
var
Len: Integer;
begin
Len := Length(S);
if Len <= MaxLen then begin
Result := S;
Exit end;
Result := Copy(S, 1, MaxLen - 3) + '...';
end;
function TrimAll(const S: string): string;
var
i: Integer;
begin
for i := 1 to Length(S) do
if S[i] > #32 then
Result := Result + S[i];
end;
function ControlChar(C: Char): Boolean;
begin
Result := C in StrangeChars;
end;
function FriendlyChar(C: Char): Char;
begin
case C of
#0: Result := '.';
#1..#31: Result := '?';
#255: Result := '#';
else
Result := C;
end;
end;
function FriendlyStr(const S: string): string;
var
i: Integer;
begin
SetLength(Result, Length(S));
for i := 1 to Length(S) do
Result[i] := FriendlyChar(S[i]);
end;
function FriendlyStr(a: TByteA): string;
var
i: Integer;
begin
SetLength(Result, Length(a));
for i := 0 to High(a) do
Result[i + 1] := FriendlyChar(Char(a[i]));
end;
function Quote(const S: string; Quoter: Char = '"'): string;
begin
Result := S;
if FirstChar(S) <> Quoter then
Result := Quoter + Result;
if LastChar(S) <> Quoter then
Result := Result + Quoter;
end;
function DeQuote(const S: string): string;
begin
Result := '';
if Length(S) > 2 then
Result := Copy(S, 2, Length(S) - 2);
end;
function UnQuote(const S: string): string;
var
Start, Len: Integer;
begin
Start := 1;
Len := Length(S);
if (S <> '') and (S[1] in ([#0..#32] + QuoteChars)) then begin
if (LastChar(S) = S[1]) then
Dec(Len);
Inc(Start);
end;
Result := Copy(S, Start, Len - Start + 1);
end;
function StrNumerus(const Value: Integer; const Singular, Plural: string;
const Zero: string = '0'): string;
begin
if Abs(Value) = 1 then
Result := IntToStr(Value) + ' ' + Singular
else if Value = 0 then
Result := Zero + ' ' + Plural
else
Result := IntToStr(Value) + ' ' + Plural;
end;
function MakeStr(const Items: array of const; Separator: string = ''): string;
const
BoolStrings: array[Boolean] of string = ('False', 'True');
var
i: Integer;
function StrOfP(P: Pointer): string;
begin
if P = nil then
Result := '[nil]'
else
Result := '[' + IntToStr(Cardinal(P)) + ']';
end;
procedure Add(const S: string);
begin
Result := Result + s + Separator;
end;
begin
Result := '';
for i := 0 to High(Items) do
with Items[i] do
case VType of
vtString: Add(VString^);
vtInteger: Add(IntToStr(VInteger));
vtBoolean: Add(BoolStrings[VBoolean]);
vtChar: Add(VChar);
vtPChar: Add(VPChar);
vtExtended: Add(FloatToStr(VExtended^));
vtObject: if VObject is TComponent then
Add(TComponent(VObject).Name)
else
Add(VObject.ClassName);
vtClass: Add(VClass.ClassName);
vtAnsiString: Add(string(VAnsiString));
vtCurrency: Add(CurrToStr(VCurrency^));
vtInt64: Add(IntToStr(VInt64^));
vtVariant: Add(string(VVariant^));
vtWideChar: Add(VWideChar);
vtPWideChar: Add(VPWideChar);
vtInterface: Add(StrOfP(VInterface));
vtPointer: Add(StrOfP(VPointer));
vtWideString: Add(WideString(VWideString));
end;
if Result <> '' then
SetLength(result, Length(Result) - Length(Separator));
end;
procedure ShowText(const Items: array of const; Separator: string = '');
var
Text: string;
begin
Text := MakeStr(Items, Separator);
MessageBox(0, PChar(Text), 'Info', MB_OK and MB_APPLMODAL);
end;
function DeleteChars(const S: string; C: Char): string;
var
i: Integer;
begin
Result := '';
for i := 1 to Length(S) do
if S[i] <> C then
Result := Result + S[i];
end;
function DeleteChars(const S: string; C: TCharSet): string;
var
i: Integer;
begin
Result := '';
for i := 1 to Length(S) do
if not (S[i] in C) then
Result := Result + S[i];
end;
function ExtractChars(const S: string; C: TCharSet): string;
var
i: Integer;
begin
Result := '';
for i := 1 to Length(S) do
if S[i] in C then
Result := Result + S[i];
end;
function CharCount(const S: string; C: Char): Integer;
var
i: Integer;
begin
Result := 0;
for i := 1 to Length(S) do
if S[i] = C then
Inc(Result);
end;
function StrAtPos(const S: string; Pos: Integer; const Str: string): Boolean;
begin
Result := (Str <> '') and (Str = Copy(S, Pos, Length(Str)));
end;
function TextAtPos(const S: string; Pos: Integer; const Text: string): Boolean;
begin
Result := (Text <> '') and SameText(Text, Copy(S, Pos, Length(Text)));
end;
function StrAtBegin(const S, Str: string): Boolean;
begin
Result := StrAtPos(S, 1, Str);
end;
function TextAtBegin(const S, Text: string): Boolean;
begin
Result := TextAtPos(S, 1, Text);
end;
function CharIn(const S: string; C: Char): Boolean;
var
i: Integer;
begin
Result := True;
for i := 1 to Length(S) do
if S[i] = C then Exit;
Result := False;
end;
function CharIn(const S: string; C: TCharSet): Boolean;
var
i: Integer;
begin
Result := False;
for i := 1 to Length(S) do begin
Result := S[i] in C;
if Result then
Exit;
end;
end;
function StrIn(const S, SubStr: string): Boolean;
begin
Result := PosEx(SubStr, S) > 0;
end;
function StrIn(SL: TStrings; const S: string): Boolean;
var
i: Integer;
begin
Result := False;
for i := 0 to SL.Count-1 do begin
Result := (S = SL[i]);
if Result then
Exit;
end;
end;
function StrIn(A: TStrA; const S: string): Boolean;
var
i: Integer;
begin
Result := False;
for i := Low(A) to High(A) do begin
Result := (S = A[i]);
if Result then
Exit;
end;
end;
function TextIn(const S, Text: string): Boolean;
begin
Result := PosExText(Text, S) > 0;
end;
function TextIn(SL: TStrings; const Text: string): Boolean;
var
i: Integer;
begin
Result := False;
for i := 0 to SL.Count-1 do begin
Result := SameText(Text, SL[i]);
if Result then
Exit;
end;
end;
function TextIn(A: TStrA; const Text: string): Boolean;
var
i: Integer;
begin
Result := False;
for i := Low(A) to High(A) do begin
Result := SameText(Text, A[i]);
if Result then
Exit;
end;
end;
function StrIndex(SL: TStrings; const S: string): Integer;
begin
for Result := 0 to SL.Count-1 do
if S = SL[Result] then
Exit;
Result := -1;
end;
function StrIndex(A: TStrA; const S: string): Integer;
begin
for Result := Low(A) to High(A) do
if S = A[Result] then
Exit;
Result := -1;
end;
function TextIndex(SL: TStrings; const Text: string): Integer;
begin
for Result := 0 to SL.Count-1 do
if SameText(Text, SL[Result]) then
Exit;
Result := -1;
end;
function TextIndex(A: TStrA; const Text: string): Integer;
begin
for Result := Low(A) to High(A) do
if SameText(Text, A[Result]) then
Exit;
Result := -1;
end;
function ReplaceChars(const S: string; Old, New: Char): string;
var
i: Integer;
begin
Result := S;
for i := 1 to Length(Result) do
if Result[i] = Old then
Result[i] := New;
end;
function ReplaceChars(const S: string; Old: TCharSet; New: Char): string;
var
i: Integer;
begin
Result := S;
for i := 1 to Length(Result) do
if Result[i] in Old then
Result[i] := New;
end;
function Replace(const S, Old, New: string): string;
var
oldp, ps: Integer;
begin
ps := 1;
Result := '';
while True do begin
oldp := ps;
ps := PosEx(Old, S, oldp);
if ps = 0 then begin
Result := Result + Copy(S, oldp, Length(S) - oldp + 1);
Exit; end;
Result := Result + Copy(S, oldp, ps - oldp) + New;
Inc(ps, Length(Old));
end;
end;
function SLOfFile(const FileName: string): TStringList;
begin
Result := TStringList.Create;
if FileExists(FileName) then
Result.LoadFromFile(FileName);
end;
function ContainsEmptyLines(SL: TStrings): Boolean;
begin
Result := StrIn(SL, '');
end;
procedure DeleteEmptyLines(SL: TStrings);
var
i: Integer;
begin
i := 0;
while i < SL.Count do begin
if SL[i] = '' then
SL.Delete(i)
else
Inc(i);
end;
end;
procedure DeleteCommentLines(SL: TStrings; const CommentSign: string = '//');
var
i: Integer;
begin
i := 0;
while i < SL.Count do begin
if (SL[i] = '') or (StrAtBegin(TrimLeft(SL[i]), CommentSign)) then
SL.Delete(i)
else
Inc(i);
end;
end;
function FindLine(SL: TStrings; const S: string): Integer;
begin
for Result := 0 to SL.Count-1 do
if TextAtBegin(SL[Result], S) then
Exit;
Result := -1;
end;
procedure QuickSortSL(SL: TStringList);
procedure Sort(l, r: Integer);
var
i,j: Integer;
z,x: string;
begin
i := l;
j := r;
x := SL[(j + i) div 2];
repeat
while SL[i] < x do Inc(i);
while SL[j] > x do Dec(j);
if i <= j then begin
z := SL[i];
SL[i] := SL[j];
SL[j] := z;
Inc(i); Dec(j);
end;
until i > j;
if j > l then Sort(l, j);
if i < r then Sort(i, r);
end;
begin
if SL.Count > 0 then
Sort(0, SL.Count-1);
end;
function IncStrA(StrA: TStrA): Integer;
begin
SetLength(StrA, Length(StrA) + 1);
Result := High(StrA);
end;
function StrOfByteA(a: TByteA): string;
begin
Result := string(Copy(a, 0, Length(a)));
end;
function ByteAOfStr(const S: string): TByteA;
begin
Result := TByteA(Copy(S, 1, Length(s)));
end;
function ByteAOfInt(i: Integer): TByteA;
begin
SetLength(Result, SizeOf(Integer));
Move(i, Pointer(Result)^, SizeOf(Integer));
end;
function IntOfByteA(A: TByteA): Integer;
begin
Result := 0;
Move(Pointer(A)^, Result, Min(Length(A), SizeOf(Integer)));
end;
function ByteAOfHex(const Hex: string): TByteA;
var
i: Integer;
h: string;
begin
h := ExtractChars(Hex, HexadecimalChars);
SetLength(Result, Length(h) div 2);
for i := 0 to High(Result) do
Result[i] := ByteOfHex(Copy(h, (i shl 1) + 1, 2));
end;
function SizeOfFile(const FileName: string): Integer;
var
F: file;
begin
AssignFile(F, FileName);
{$I-}Reset(F, 1);{$I+}
if IOResult = 0 then begin
Result := FileSize(F);
CloseFile(F);
end else
Result := 0;
end;
function FileEx(const FileName: string; AllowFolders: Boolean = False): Boolean;
var
FindData: TWin32FindData;
begin
if FileName = '' then begin
Result := False;
Exit; end;
Result := (AllowFolders and DirectoryExists(FileName)) or
(FindFirstFile(PChar(FileName), FindData) <> INVALID_HANDLE_VALUE);
Result := Result and not CharIn(FileName, WildCards);
Result := Result and (AllowFolders
or ((FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0));
end;
function LWPSolve(const Dir: string): string;
begin
if (Dir <> '') and (Dir[Length(Dir)] = '\') then begin
Result := Copy(Dir, 1, Length(Dir) - 1);
end else
Result := Dir;
end;
function LWPSlash(const Dir: string): string;
begin
if (Dir <> '') and (Dir[Length(Dir)] = '\') then begin
Result := Copy(Dir, 1, Length(Dir));
end else
Result := Dir + '\';
end;
function ExtractDrive(const FileName: string): string;
begin
Result := '';
if (Length(FileName) >= 2) and (FileName[2] = ':') then
Result := UpperCase(FileName[1] + ':\');
end;
function ExtractPath(const FileName: string): string;
var
p: Integer;
begin
p := CharPosR('\', FileName);
if P > 0 then
Result := Copy(FileName, 1, p)
else
Result := FileName;
end;
function ExtractPrefix(const FileName: string): string;
begin
Result := UntilLastChar(ExtractFileName(FileName), '.');
end;
function ExtractSuffix(const FileName: string): string;
begin
Result := FromLastChar(ExtractFileName(FileName), '.');
end;
function SameByteA(const A, B: TByteA): Boolean;
begin
Result := (A = B) or ((Length(A) = Length(B)) and CompareMem(A, B, Length(A)));
end;
function Reverse(A: TByteA): TByteA;
var
i: Integer;
begin
SetLength(Result, Length(A));
for i := 0 to High(A) do
Result[High(Result) - i] := A[i];
end;
function Endian(i: Integer): Integer;
type
EndianArray = packed array[0..3] of Byte;
var
a, b: EndianArray;
begin
a := EndianArray(i);
b[0] := a[3];
b[1] := a[2];
b[2] := a[1];
b[3] := a[0];
Result := Integer(b);
end;
function SaveByteA(Data: TByteA; const FileName: string;
Overwrite: Boolean = True): Boolean;
var
F: file;
begin
if FileExists(FileName) and not Overwrite then begin
Result := False;
Exit end;
AssignFile(F, FileName);
{$I-}Rewrite(F, 1);{$I+}
if IOResult = 0 then begin
if Length(Data) > 0 then
BlockWrite(F, Data[0], Length(Data));
CloseFile(F);
Result := True;
end else
Result := False;
end;
function LoadByteA(const FileName: string): TByteA;
var
F: file;
begin
AssignFile(F, FileName);
{$I-}Reset(F, 1);{$I+}
if IOResult = 0 then begin
SetLength(Result, FileSize(F));
if Length(Result) > 0 then
BlockRead(F, Result[0], FileSize(F));
CloseFile(F);
end else
SetLength(Result, 0);
end;
function IsValidFileName(const FileName: string): Boolean;
begin
Result := (FileName <> '') and not CharIn(FileName, FileNameEnemies)
and CharIn(Trim(FileName), AllChars - ['.']);
end;
function MakeValidFileName(FileName: string; const Default: string = 'File'): string;
begin
if FileName = '' then
FileName := Default;
if CharIn(FileName, FileNameEnemies) then
Result := ReplaceChars(FileName, FileNameEnemies, '_')
else if not CharIn(Trim(FileName), AllChars - ['.']) then
Result := Default
else
Result := FileName;
end;
function IsValidInteger(const S: string): Boolean;
{const
LowInt = '2147483648';
HighInt = '2147483647';
var
len, RealLen, i, o: Integer;
c: Char;
begin
Result := False;
if S = '' then
Exit;
len := Length(S);
o := 1;
if S[1] = '-' then begin
if len = 1 then
Exit;
Inc(o);
while (o <= len) and (S[o] = '0') do
Inc(o);
if o > len then
Exit;
if o < len then begin
RealLen := len - o + 1;
if RealLen > Length(LowInt) then
Exit
else if RealLen = Length(LowInt) then begin
for i := 1 to Length(LowInt) do begin
c := S[i + o - 1];
if (c < '0') or (c > LowInt[i]) then
Exit;
if c in ['0'..Char((Byte(LowInt[i])-1))] then
Break;
end;
Inc(o, i);
end;
end;
end else begin
while (o <= len) and (S[o] = '0') do
Inc(o);
if o <= len then begin
RealLen := len - o + 1;
if RealLen > Length(HighInt) then
Exit
else if RealLen = Length(HighInt) then begin
for i := 1 to Length(HighInt) do begin
c := S[i + o - 1];
if (c < '0') or (c > HighInt[i]) then
Exit;
if c in ['0'..Char((Byte(HighInt[i])-1))] then
Break;
end;
Inc(o, i);
end;
end;
end;
for i := o to len do
if not (S[i] in ['0'..'9']) then
Exit;
Result := True; }
var
i: Int64;
begin
i := StrToInt64Def(S, High(Int64));
Result := (i >= Low(Integer)) and (i <= High(Integer));
end;
function IsValidCardinal(const S: string): Boolean;
{const
HighCard = '4294967295';
var
len, RealLen, i, o: Integer;
begin
Result := False;
if S = '' then
Exit;
len := Length(S);
o := 1;
while (o <= len) and (S[o] = '0') do
Inc(o);
if o <= len then begin
RealLen := len - o + 1;
if RealLen > Length(HighCard) then
Exit
else if RealLen = Length(HighCard) then begin
for i := 1 to Length(HighCard) do begin
if S[i + o - 1] > HighCard[i] then
Exit;
if S[i + o - 1] in ['0'..Char((Byte(HighCard[i])-1))] then
Break;
end;
Inc(o, i);
end;
end;
for i := o to len do
if not (S[i] in ['0'..'9']) then
Exit;
Result := True; }
var
i: Int64;
begin
i := StrToInt64Def(S, -1);
Result := (i >= 0) and (i <= High(Cardinal));
end;
function StrOfBool(flag: Boolean; const TrueStr: string = 'True';
const FalseStr: string = 'False'): string;
begin
if Flag then
Result := TrueStr
else
Result := FalseStr;
end;
function StrOfInt(i: Integer): string;
begin
{ if i = 0 then begin
Result := '0';
Exit end;
while i > 0 do begin
Result := Char(Byte('0') + (i mod 10)) + Result;
i := i div 10;
end;}
Result := IntToStr(i);
end;
function CardOfStr(const S: string): Cardinal;
var
Res: Int64;
begin
Res := StrToInt64Def(S, -1);
if Res > High(Cardinal) then
Res := High(Cardinal)
else if Res < 0 then
Res := 0;
Result := Cardinal(Res);
end;
function HexOrd(Hex: Char): THex;
begin
case Hex of
'0'..'9':
Result := Byte(Hex) - 48;
'A'..'F':
Result := Byte(Hex) - 55;
'a'..'f':
Result := Byte(Hex) - 87;
else
Result := 0;
end;
end;
function ByteOfHex(Hex: THexByteStr): Byte;
begin
Result := (HexOrd(Hex[1]) shl 4) + HexOrd(Hex[2]);
end;
function DecOfHex(const Hex: string): string;
begin
Result := IntToStr(CardOfHex(Hex));
end;
function HexOfByte(b: Byte): THexByteStr;
begin
Result := HexChar[(b and $F0) shr 4]
+ HexChar[ b and $0F ];
end;
{function HexOfCard2(c: Cardinal): string;
var
Data: array[0..(1 shl 4) - 1] of Char;
i: Integer;
begin
for i := 0 to (1 shl 4) - 1 do
if i < 10 then
Data[i] := Char(Ord('0') + i)
else
Data[i] := Char(Ord('A') + i - 10);
Result := Data[(c and (((1 shl (1 shl 2)) - 1) shl (7 shl 2))) shr (7 shl 2)]
+ Data[(c and (((1 shl (1 shl 2)) - 1) shl (6 shl 2))) shr (6 shl 2)]
+ Data[(c and (((1 shl (1 shl 2)) - 1) shl (5 shl 2))) shr (5 shl 2)]
+ Data[(c and (((1 shl (1 shl 2)) - 1) shl (4 shl 2))) shr (4 shl 2)]
+ Data[(c and (((1 shl (1 shl 2)) - 1) shl (3 shl 2))) shr (3 shl 2)]
+ Data[(c and (((1 shl (1 shl 2)) - 1) shl (2 shl 2))) shr (2 shl 2)]
+ Data[(c and (((1 shl (1 shl 2)) - 1) shl (1 shl 2))) shr (1 shl 2)]
+ Data[(c and (((1 shl (1 shl 2)) - 1) shl (0 shl 2))) shr (0 shl 2)];
end; }
function HexOfCard(i: Cardinal): string;
var
a: Cardinal;
begin
Result := '';
while i > 0 do begin
a := i and $F;
Result := HexChar[a] + Result;
i := i shr 4;
end;
end;
function HexOfCard(i: Cardinal; Digits: Integer): string;
var
a: Cardinal;
begin
Result := '';
while i > 0 do begin
a := i and $F;
Result := HexChar[a] + Result;
i := i shr 4;
end;
Result := MulStr('0', Digits - Length(Result)) + Result;
end;
function PascalHexArray(a: TByteA; Name: string): string;
var
i, len: Integer;
begin
Result := 'const' + EOL +
' ' + Name + ': array[0..' + IntToStr(High(a)) + '] of Byte = (';
len := Length(a);
for i := 0 to len-1 do begin
if (i mod 19) = 0 then
Result := Result + EOL + ' ' + ' ';
Result := Result + '$' + HexOfByte(a[i]);
if i < len-1 then
Result := Result + ',';
end;
Result := Result + EOL + ' );';
end;
function HexOfByteA(a: TByteA; Blocks: Integer = 1;
const Splitter: string = ' '): string;
var
i: Integer;
begin
Result := '';
if Blocks > 0 then
for i := 0 to High(a) do begin
Result := Result + HexOfByte(a[i]);
if i < High(a) then
if ((i+1) mod Blocks) = 0 then
Result := Result + Splitter;
end
else
for i := 0 to High(a) do
Result := Result + HexOfByte(a[i]);
end;
function BinOfByteA(a: TByteA; Blocks: Integer = 4;
const Splitter: string = ' '): string;
var
i, max: Integer;
Bit: Boolean;
begin
Result := '';
if Blocks > 0 then begin
max := 8 * (High(a)) + 7;
for i := 0 to max do begin
Bit := 7-(i mod 8) in TBitSet(a[i div 8]);
Result := Result + Char(Byte('0') + Byte(Bit));
if i < max then
if ((i+1) mod Blocks) = 0 then
Result := Result + Splitter;
end;
end else
for i := 0 to High(a) do
Result := Result + Char(Byte('0') + a[i] shr (i and 8));
end;
function CardOfHex(Hex: string): Cardinal;
var
i: Integer;
begin
Result := 0;
Hex := Copy(ExtractChars(Hex, HexadecimalChars), 1, 8);
for i := 1 to Length(Hex) do
if Hex[i] <> '0' then
Inc(Result, HexOrd(Hex[i]) shl ((Length(Hex) - i) shl 2));
end;
function IntOfBin(Bin: string): Cardinal;
var
i: Integer;
begin
Result := 0;
Bin := Copy(ExtractChars(Bin, BinaryChars), 1, 32);
for i := Length(Bin) downto 1 do
if Bin[i] = '1' then
Inc(Result, 1 shl (Length(Bin) - i));
end;
function BinOfInt(n: Cardinal): string;
var
a: Integer;
begin
if n = 0 then begin
Result := '0';
exit; end;
Result := '';
while n > 0 do begin
a := n and 1;
Result := Char(a + Byte('0')) + Result;
n := n shr 1;
end;
end;
function BinOfIntFill(n: Cardinal; MinCount: Integer = 8): string;
var
a: Integer;
begin
if n = 0 then begin
Result := MulStr('0', MinCount);
Exit; end;
Result := '';
while n > 0 do begin
a := n and 1;
Result := Char(a + Byte('0')) + Result;
n := n shr 1;
end;
Result := MulStr('0', MinCount - Length(Result)) + Result;
end;
function BaseNOfInt(I: Cardinal; B: TBaseN): string;
var
a: Integer;
begin
if (B < 2) or (i = 0) then begin
Result := '0';
Exit; end;
Result := '';
while i > 0 do begin
a := i mod B;
Result := BaseNChar[a] + Result;
i := i div B;
end;
end;
function IntOfBaseN(V: string; B: TBaseN): Cardinal;
var
i: Integer;
F: Cardinal;
c: Byte;
begin
Result := 0;
V := TrimAll(V);
F := 1;
for i := Length(V) downto 1 do begin
c := Byte(UpCase(V[i]));
case Char(c) of
'0'..'9': c := c - 48;
'A'..'Z': c := c - 55;
end;
if c < B then
Result := Result + Byte(c) * F;
F := F * B;
end;
end;
function KeepIn(i, Bottom, Top: Variant): Variant;
begin
Result := i;
if Result > Top then
Result := Top
else if Result < Bottom then
Result := Bottom;
end;
function InRange(Value, Bottom, Top: Variant): Boolean;
begin
Result := (Value >= Bottom) and (Value <= Top);
end;
function InStrictRange(Value, Bottom, Top: Variant): Boolean;
begin
Result := (Value > Bottom) and (Value < Top);
end;
function Min(const A, B: Integer): Integer;
begin
if A < B then
Result := A
else
Result := B;
end;
function Min(const A: TIntA): Integer;
var
i: Integer;
begin
Result := 0;
if Length(A) = 0 then
Exit;
Result := A[0];
for i := 1 to High(A) do
if A[i] < Result then
Result := A[i];
end;
function Max(const A, B: Integer): Integer;
begin
if A > B then
Result := A
else
Result := B;
end;
function Max(const A: TIntA): Integer;
var
i: Integer;
begin
Result := 0;
if Length(A) = 0 then
Exit;
Result := A[0];
for i := 1 to High(A) do
if A[i] > Result then
Result := A[i];
end;
function RangesOfStr(const S: string): TRanges;
var
SL: TStringList;
r, b, t: string;
i, p: Integer;
function TryStrToCard(const S: string; out Value: Cardinal): Boolean;
var
E: Integer;
begin
Val(S, Value, E);
Result := E = 0;
end;
begin
Result := nil;
SL := TStringList.Create;
try
Split(S, RangesSeparator, SL);
SetLength(Result, SL.Count);
for i := 0 to SL.Count-1 do begin
r := SL[i];
with Result[i] do begin
p := CharPos(RangeInnerSeparator, r);
Simple := p = 0; // no '-' found
if Simple then begin
if r = RangeInfinite then begin // * --> *-*
Simple := False;
Bottom := Low(Bottom);
Top := High(Top);
end else if not TryStrToCard(r, Value) then
Break;
end else begin
TileStr(r, p, p, b, t);
if b = RangeInfinite then
Bottom := Low(Bottom)
else if not TryStrToCard(b, Bottom) then
Break;
if t = RangeInfinite then
Top := High(Top)
else if not TryStrToCard(t, Top) then
Break;
if Bottom > Top then begin
p := Bottom; Bottom := Top; Top := p;
end;
end;
end;
end;
if i <> SL.Count then
Result := nil;
finally
SL.Free;
end;
end;
function InRanges(Ranges: TRanges; TestValue: Cardinal): Boolean;
var
i: Integer;
begin
Result := True;
for i := 0 to High(Ranges) do
with Ranges[i] do
if Simple then begin
if TestValue = Value then
Exit;
end else begin
if InRange(TestValue, Bottom, Top) then
Exit;
end;
Result := False;
end;
procedure WriteSL(Strings: TStrings; const Prefix: string = '';
const Suffix: string = '');
var
i: Integer;
begin
for i := 0 to Strings.Count-1 do
WriteLn(Prefix + Strings[i] + Suffix);
end;
function Success(Res: Integer; ResultOnSuccess: Integer = ERROR_SUCCESS): Boolean;
begin
Result := (Res = ResultOnSuccess);
LastSuccessRes := Res;
end;
function Failure(Res: Integer; ResultOnSuccess: Integer = ERROR_SUCCESS): Boolean;
begin
Result := not Success(Res, ResultOnSuccess);
end;
function ExpandString(const S: string): string;
var
Len: Integer;
P, Res: PChar;
begin
Result := '';
P := PChar(S);
Len := ExpandEnvironmentStrings(P, nil, 0);
if Len = 0 then
Exit;
GetMem(Res, Len);
ExpandEnvironmentStrings(P, Res, Len);
Result := Res;
FreeMem(Res, Len);
end;
function FindAll(Strings: TStrings; const Mask: string;
ScanSubDirs: Boolean = True; Attributes: Integer = faFindEveryFile;
FileReturn: TFileNameFunc = nil): Boolean;
var
Path, FileName: string;
procedure ScanDir(const Path, FileName: string);
var
PSR: TSearchRec;
Res: Integer;
procedure Add(const S: string);
begin
if S <> '' then
Strings.Add(S);
end;
begin
Res := FindFirst(Path + FileName, Attributes, PSR);
while Success(Res, 0) do begin
if Assigned(FileReturn) then
Add(FileReturn(Path + PSR.Name))
else
Add(Path + PSR.Name);
Res := FindNext(PSR);
end;
FindClose(PSR);
if not ScanSubDirs then
Exit;
Res := FindFirst(Path + '*', faDirectory, PSR);
while Success(Res, 0) do begin
if (PSR.Attr and faDirectory > 0)
and (PSR.Name <> '.') and (PSR.Name <> '..') then
ScanDir(Path + PSR.Name + '\', FileName);
Res := FindNext(PSR);
end;
FindClose(PSR);
end;
begin
Strings.Clear;
Path := ExtractPath(Mask);
FileName := ExtractFileName(Mask);
ScanDir(Path, FileName);
Result := Strings.Count > 0;
end;
function FindAllFirst(const Mask: string; ScanSubDirs: Boolean = True;
Attributes: Integer = faFindEveryFile): string;
var
Path, FileName: string;
function ScanDir(const Path, FileName: string): Boolean;
var
PSR: TSearchRec;
Res: Integer;
begin
Result := False;
if Success(FindFirst(Path + FileName, Attributes, PSR), 0) then begin
FindAllFirst := Path + PSR.Name;
Result := True;
FindClose(PSR);
Exit; end;
if not ScanSubDirs then
Exit;
Res := FindFirst(Path + '*', faDirectory, PSR);
while not Result and Success(Res, 0) do begin
if (PSR.Attr and faDirectory > 0)
and (PSR.Name <> '.') and (PSR.Name <> '..') then
Result := ScanDir(Path + PSR.Name + '\', FileName);
Res := FindNext(PSR);
end;
FindClose(PSR);
end;
begin
Result := '';
Path := ExtractPath(Mask);
FileName := ExtractFileName(Mask);
ScanDir(Path, FileName);
end;
procedure DeleteFiles(const Mask: string; ScanSubDirs: Boolean = True;
Attributes: Integer = faFindEveryFile);
var
Path, FileName: string;
procedure ScanDir(const Path, FileName: string);
var
PSR: TSearchRec;
Res: Integer;
procedure TryDeleteFile(const FileName: string);
begin
try
DeleteFile(Path + PSR.Name);
except
end;
end;
begin
Res := FindFirst(Path + FileName, Attributes, PSR);
while Success(Res, 0) do begin
TryDeleteFile(Path + PSR.Name);
Res := FindNext(PSR);
end;
FindClose(PSR);
if not ScanSubDirs then
Exit;
Res := FindFirst(Path + '*', faDirectory, PSR);
while Success(Res, 0) do begin
if (PSR.Attr and faDirectory > 0)
and (PSR.Name <> '.') and (PSR.Name <> '..') then begin
ScanDir(Path + PSR.Name + '\', FileName);
TryDeleteFile(Path + PSR.Name);
end;
Res := FindNext(PSR);
end;
FindClose(PSR);
end;
begin
Path := ExtractPath(Mask);
FileName := ExtractFileName(Mask);
ScanDir(Path, FileName);
end;
function GetFileNew(FileName: string; NoFloppyDrives: Boolean = True): string;
var
Drive: string;
pf, pd, Len: Integer;
PSR: TSearchRec;
begin
Result := '';
FileName := Trim(FileName);
if Length(FileName) < 2 then
Exit;
Drive := ExtractDrive(FileName);
if not DirectoryExists(Drive) then
Exit;
if NoFloppyDrives and (Drive[1] in ['A', 'B']) then
Exit;
Len := Length(FileName);
Result := Drive;
pf := Length(Drive) + 1;
while pf <= Len do begin
if FileName[pf] = '\' then begin
Result := Result + '\';
Inc(pf);
Continue; end;
pd := CharPos('\', FileName, pf);
if pd = 0 then begin
if 0=FindFirst(Result + Copy(FileName, pf, MaxInt), faFindEveryFile, PSR) then begin
Result := Result + PSR.Name;
Break; end else begin
FindClose(PSR);
if 0=FindFirst(Result + Copy(FileName, pf, MaxInt), faDirectory, PSR) then
Result := Result + PSR.Name + '\'
else
Result := '';
FindClose(PSR);
if Result = '' then
Break;
end;
end;
if 0=FindFirst(Result + Copy(FileName, pf, pd - pf), faDirectory, PSR) then
Result := Result + PSR.Name + '\'
else
Result := '';
FindClose(PSR);
if Result = '' then
Break;
pf := pd + 1;
end;
if (Result <> '') and not FileEx(Result, True) then
Result := '';
end;
function DateTimeOfFileTime(const FileTime: TFileTime): TDateTime;
var
LocalFileTime: TFileTime;
Res: Integer;
begin
Result := 0;
FileTimeToLocalFileTime(FileTime, LocalFileTime);
if not FileTimeToDosDateTime(LocalFileTime, LongRec(Res).Hi,
LongRec(Res).Lo) then
Res := -1;
if (Res = -1) or (Res = 0) then
Exit;
try
Result := FileDateToDateTime(Res);
except
end;
end;
procedure FileNew(const FileName: string);
var
Handle: Integer;
begin
Handle := FileCreate(FileName);
FileClose(Handle);
end;
function Win32PlatformStr: string;
const
PlatformStrings: array[VER_PLATFORM_WIN32s..VER_PLATFORM_WIN32_NT] of string =
('VER_PLATFORM_WIN32s', 'VER_PLATFORM_WIN32_WINDOWS', 'VER_PLATFORM_WIN32_NT');
begin
Result := PlatformStrings[Win32Platform];
end;
function FullOSInfo: string;
begin
Result := Format(
'Platform: %s' + EOL +
'Version: %d.%d Build %d' + EOL +
'CSD: %s',
[
Win32PlatformStr,
Win32MajorVersion, Win32MinorVersion, Win32BuildNumber,
Win32CSDVersion
]
);
end;
function Win9x: Boolean;
begin
Result := Win32Platform = VER_PLATFORM_WIN32_WINDOWS;
end;
function WinNT: Boolean;
begin
Result := Win32Platform = VER_PLATFORM_WIN32_NT;
end;
function Win2000: Boolean;
begin
Result := (Win32Platform = VER_PLATFORM_WIN32_NT)
and (Win32MajorVersion = 4);
end;
function WinXP: Boolean;
begin
Result := Win32MajorVersion >= 5;
end;
initialization
MyDir := GetMyDir;
end.
unit FifoStream;
interface
uses Classes, windows, Dialogs;
const
DefaultChunksize = 32768; // 32kb per chunk as default.
type
PMemChunk = ^TMemChunk;
TMemChunk = record
Filled: Longword;
Read: Longword;
Data: pointer;
end;
TFifo = class
private
FBuffers: TList;
FChunksize: Longword;
FCritSect: TRTLCriticalSection;
FIsWinNT: boolean;
FBytesInFifo: LongWord;
protected
function GetBytesInFifo: LongWord;
public
constructor Create;
destructor Destroy; override;
procedure Write(Data: pointer; Size: LongWord);
procedure Read(Buff: pointer; var ReqSize: LongWord);
procedure PeekData(Buff: pointer; var ReqSize: LongWord);
published
property BytesInFifo: LongWord read FBytesInFifo;
end;
implementation
constructor TFifo.Create;
begin
inherited;
FBuffers := TList.Create;
// set default chunksize...
FChunksize := DefaultChunksize;
InitializeCriticalSection(FCritSect);
end;
destructor TFifo.Destroy;
var
I: Integer;
begin
EnterCriticalSection(FCritSect);
for I := 0 to FBuffers.count - 1 do
begin
FreeMem(PMemChunk(Fbuffers[I]).Data);
Dispose(PMemChunk(Fbuffers[I]));
end;
FBuffers.Clear;
FBuffers.Free;
LeaveCriticalSection(FCritSect);
DeleteCriticalSection(FCritSect);
inherited;
end;
function TFifo.GetBytesInFifo: LongWord;
begin
Result := 0;
if FBuffers.Count = 0 then
begin
exit;
end
else
begin
if FBuffers.Count > 1 then
Inc(Result, (FBuffers.Count - 1) * FChunkSize);
Inc(Result, PMemChunk(FBuffers[Fbuffers.Count - 1]).Filled);
Dec(Result, PMemChunk(FBuffers[0]).Read);
end;
end;
procedure TFifo.Write(Data: pointer; Size: LongWord);
var
Privpointer: pointer;
PrivSize: LongWord;
Chunk: PMemChunk;
PosInChunk: pointer;
begin
if LongWord(Data) = 0 then
begin
// null pointer? somebody is trying to fool us, get out...
Exit;
end;
EnterCriticalSection(FCritSect);
PrivPointer := Data;
PrivSize := 0;
// are already buffers there?
if FBuffers.count > 0 then
begin
// is the last one of them not completely filled?
if PMemChunk(FBuffers[FBuffers.count - 1]).filled < FChunksize then
// not completely filled, so fill up the buffer.
begin
Chunk := PMemChunk(FBuffers[FBuffers.count - 1]);
// fetch chunkdata.
PosInChunk := Chunk.Data;
// move to current fill pos...
Inc(LongWord(PosInChunk), Chunk.Filled);
// can we fill the chunk completely?
if Size > FChunksize - Chunk.Filled then
begin
// yes we can.
Move(PrivPointer^, PosInChunk^, FChunksize - Chunk.Filled);
Inc(PrivSize, FChunksize - Chunk.Filled);
Inc(LongWord(PrivPointer), FChunksize - Chunk.Filled);
Chunk.Filled := FChunkSize;
end
else
// we have to less data for filling the chunk completely,
// just put everything in.
begin
Move(PrivPointer^, PosInChunk^, Size);
Inc(PrivSize, Size);
Inc(Chunk.Filled, Size);
end;
end;
end;
// as long as we have remaining stuff put it into new chunks.
while (PrivSize < Size) do
begin
new(Chunk);
GetMem(Chunk.Data, FChunksize);
Chunk.Read := 0;
// can we fill an entire chunk with the remaining data?
if Privsize + FChunksize < Size then
begin
// yes we can, so put the stuff in.
Move(Privpointer^, Chunk.Data^, FChunksize);
Inc(LongWord(PrivPointer), FChunksize);
Inc(PrivSize, FChunksize);
Chunk.Filled := FChunksize;
end
else // we have to less data to fill the entire chunk, just put the remaining stuff in.
begin
Move(Privpointer^, Chunk.Data^, Size - Privsize);
Chunk.Filled := Size - Privsize;
Inc(PrivSize, Size - Privsize);
end;
Fbuffers.Add(Chunk);
end;
if Size <> Privsize then
Showmessage('miscalculation in TFifo.write');
FBytesInFifo := GetBytesInFifo;
LeaveCriticalSection(FCritSect);
end;
procedure TFifo.Read(Buff: pointer; var ReqSize: LongWord);
var
PrivSize: Integer;
Privpos: pointer;
Chunk: PMemChunk;
ChunkPos: pointer;
begin
if LongWord(Buff) = 0 then
begin
// null pointer? somebody is trying to fool us, get out...
Exit;
end;
EnterCriticalSection(FCritSect);
PrivSize := 0;
Privpos := Buff;
while FBuffers.Count > 0 do
begin
Chunk := PMemChunk(FBuffers[0]);
ChunkPos := Chunk.data;
Inc(LongWord(ChunkPos), Chunk.Read);
// does the remaining part of the chunk fit into the buffer?
if PrivSize + (Chunk.Filled - Chunk.read) < ReqSize then
begin // yep, it fits
Move(ChunkPos^, Privpos^, Chunk.Filled - Chunk.read);
Inc(PrivSize, Chunk.Filled - Chunk.read);
FreeMem(Chunk.Data);
Dispose(Chunk);
FBuffers.Delete(0);
end
else // remaining part didn't fit, get as much as we can and increment the
// read attribute.
begin
Move(ChunkPos^, Privpos^, ReqSize - PrivSize);
Inc(Chunk.read, ReqSize - PrivSize);
Inc(PrivSize, ReqSize - PrivSize);
// as we filled the buffer, we'll have to break here.
break;
end;
end;
FBytesInFifo := GetBytesInFifo;
LeaveCriticalSection(FCritSect);
ReqSize := PrivSize;
end;
// read Data from Stream without removing it from the Stream...
procedure TFifo.PeekData(Buff: pointer; var ReqSize: LongWord);
var
PrivSize: Integer;
Privpos: pointer;
Chunk: PMemChunk;
ChunkPos: pointer;
ChunkNr: Integer;
begin
if LongWord(Buff) = 0 then
begin
// null pointer? somebody is trying to fool us, get out...
Exit;
end;
EnterCriticalSection(FCritSect);
PrivSize := 0;
Privpos := Buff;
ChunkNr := 0;
while FBuffers.Count > ChunkNr do
begin
Chunk := PMemChunk(FBuffers[ChunkNr]);
ChunkPos := Chunk.data;
Inc(LongWord(ChunkPos), Chunk.Read);
// does the remaining part of the chunk fit into the buffer?
if PrivSize + (Chunk.Filled - Chunk.read) < ReqSize then
begin // yep, it fits
Move(ChunkPos^, Privpos^, Chunk.Filled - Chunk.read);
Inc(PrivSize, Chunk.Filled - Chunk.read);
Inc(ChunkNr);
end
else // remaining part didn't fit, get as much as we can and increment the
// read attribute.
begin
Move(ChunkPos^, Privpos^, ReqSize - PrivSize);
Inc(PrivSize, ReqSize - PrivSize);
// as we filled the buffer, we'll have to break here.
break;
end;
end;
LeaveCriticalSection(FCritSect);
ReqSize := PrivSize;
end;
end.