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.
|