
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.
2709 lines
61 KiB
ObjectPascal
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.
|