summaryrefslogtreecommitdiff
path: root/UCoreUtils.pas
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@users.sourceforge.net>2008-06-07 20:34:49 +0200
committerTomas Bzatek <tbzatek@users.sourceforge.net>2008-06-07 20:34:49 +0200
commitecde167da74c86bc047aaf84c5e548cf65a5da98 (patch)
treea015dfda84f28a65811e3aa0d369f8f211ec8c60 /UCoreUtils.pas
downloadtuxcmd-ecde167da74c86bc047aaf84c5e548cf65a5da98.tar.xz
Diffstat (limited to 'UCoreUtils.pas')
-rw-r--r--UCoreUtils.pas1821
1 files changed, 1821 insertions, 0 deletions
diff --git a/UCoreUtils.pas b/UCoreUtils.pas
new file mode 100644
index 0000000..0e12550
--- /dev/null
+++ b/UCoreUtils.pas
@@ -0,0 +1,1821 @@
+(*
+ Tux Commander - UCoreUtils - Some other useful core functions
+ Copyright (C) 2008 Tomas Bzatek <tbzatek@users.sourceforge.net>
+ Check for updates on tuxcmd.sourceforge.net
+
+ Portions of this unit (CRC32, THash_MD5) are part of the Delphi Encryption Compendium
+ Copyright: Hagen Reddmann mailto:HaReddmann@AOL.COM
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*)
+unit UCoreUtils;
+
+interface
+
+uses gdk2pixbuf, gtk2, gdk2, glib2, SysUtils, Classes, Libc, GTKControls, GTKStdCtrls, GTKClasses, UEngines;
+
+type
+ PIntArray = ^TIntArray;
+ TIntArray = array[0..1023] of LongWord;
+
+ TOpenStringArray = array of string;
+
+ THash_MD5 = class
+ private
+ FCount: Int64;
+ FBuffer: array[0..63] of Byte;
+ FDigest: array[0..9] of LongWord;
+ protected
+ function TestVector: Pointer;
+ procedure Transform(Buffer: PIntArray);
+ public
+ constructor Create;
+ procedure Init;
+ procedure Done;
+ procedure Calc(const Data; DataSize: Integer);
+ function DigestKey: string;
+ function GetKeyStrH: string;
+ end;
+
+
+const ConstERRSpawn = 26;
+ ConstQuotationCharacters = [' ', '"', '''', '(', ')', ':', '&'];
+
+function GetErrorString(ErrorNo: integer): string;
+function GetSignalString(SignalNo: integer): string;
+
+function UnixTimeToTDateTime(UnixTime: Int64): TDateTime;
+function FormatSize(Value: Int64; Base: integer): string;
+
+function AttrToStr(const Mode: Cardinal; IncludeFileType: boolean = True): string;
+function AttrToOctal(const Mode: Cardinal): integer;
+function OctalToAttr(Octal: Cardinal): Cardinal;
+{ Convert an octal specified number to decimal }
+{ Copied from linux.pp (Free Pascal run time library) - Copyright (c) 1999-2000 by Michael Van Canneyt, BSD parts (c) 2000 by Marco van de Voort, members of the Free Pascal development team }
+
+function PosEnd(Substr: string; S: string): Integer;
+function GetHomePath: string;
+function GetUserName: string;
+function GetHostName: string;
+procedure SeparateExt(const Original: string; var Name, Ext: string);
+procedure SeparateNameDir(Original: string; var Path, FileName: string);
+function PadRightStr(const Str: string; Len: byte): string;
+
+function IsWild(InputStr, Wilds: string; IgnoreCase: Boolean): Boolean;
+{ IsWild compares InputString with WildCard string and returns True if corresponds. }
+{ Copied from Delphi VCL Extensions (RX) - Copyright (c) 1995, 1996 AO ROSNO, Copyright (c) 1997, 1998 Master-Bank }
+function ReplaceStr(const S, Srch, Replace: string): string;
+{ Returns string with every occurrence of Srch string replaced with Replace string. }
+{ Copied from Delphi VCL Extensions (RX) - Copyright (c) 1995, 1996 AO ROSNO, Copyright (c) 1997, 1998 Master-Bank }
+function NumCountChars(const Char: char; const S: string): integer;
+
+procedure ParseString(const Str, Separator: string; var SubStrings: TOpenStringArray);
+
+
+function ProcessPattern(Engine: TPanelEngine; Pattern, APath, FileName: string; const Directory: boolean): string;
+// Processess pattern with FileName located in APath and return destination path+filename
+procedure ShowAbout;
+
+procedure TrimCRLFESC(var s: string);
+procedure TrimQuotes(var s: string);
+function QuoteStr(const Str: string): string;
+function QuoteMarkupStr(const Str: string): string;
+function QuotePercentStr(const Str: string): string;
+function RemoveQuotation(const Str: string): string;
+function GetStrSize(s: string): Int64;
+procedure DebugMsg(Params: array of const);
+function SpawnProcess(const AppPath: string; var Running: boolean; const Parameters: array of string): Cardinal;
+function ExecuteProgram(const AppCMDLine, CWD: string; const AutodetectGUI, RunInTerminal: boolean; var ErrorSignal: integer): boolean;
+function IsItX11App(const Application: string): boolean;
+function HandleSystemCommand(const Command, ErrorText: string): boolean;
+
+function CompareTextsEx(S1, S2: PChar): integer;
+function LVCompareItems(Data1, Data2: PDataItem; const Ascending: boolean; const SortColumnID: integer): integer;
+procedure SortDataList(var List: TList; const Ascending: boolean; const SortColumnID: integer);
+procedure GetFirstLastPanelColumn(var FirstColumn, LastColumn: integer);
+
+procedure SetupColors;
+
+function ConstructURI(HidePasswd: boolean; Protocol, Server, Username, Password, Dir: string): string;
+function URIHidePassword(const SrcURI: string): string;
+
+{$IFDEF __FPC__}
+function StrToDateDef(const S: string; const Default: TDateTime): TDateTime;
+function UnixToDateTime(const AValue: Int64): TDateTime;
+{$ENDIF}
+
+procedure SaveItemToHistory(s: string; History: TStringList);
+
+
+
+
+// Calculate CRC32 Checksum, CRC is default $FFFFFFFF,
+// After calc you must inverse Result with NOT
+function CRC32(CRC: LongWord; Data: Pointer; DataSize: LongWord): LongWord;
+
+procedure ReportGTKVersion;
+
+// Internal locking
+procedure InternalLock;
+procedure InternalUnLock;
+function InternalLockUnlocked: boolean;
+procedure InternalLockInit(Locked: boolean);
+
+var ChildExitStatus: sig_atomic_t;
+
+ AppPath, IconPath: string; // Used in UFileTypeSettings
+
+ NormalItemGDKColor, ActiveItemGDKColor, InactiveItemGDKColor, SelectedItemGDKColor, DotFileItemGDKColor, LinkItemGDKColor,
+ NormalItemGDKBackground, ActiveItemGDKBackground, InactiveItemGDKBackground: PGdkColor;
+ InactiveItemBGColorNum: LongWord;
+
+
+implementation
+
+uses DateUtils, GTKForms, GTKUtils, GTKView, ULocale, UConfig, UCore, UGnome, UMain;
+
+(********************************************************************************************************************************)
+function GetErrorString(ErrorNo: integer): string;
+begin
+ if ErrorNo >= 0 then Result := String(strerror(ErrorNo))
+ else
+ case ErrorNo of
+ ERRException : Result := LANGUnknownException;
+ ERRNoAccess : Result := LANGNoAccess;
+ else Result := LANGUnknownError;
+ end;
+end;
+
+(********************************************************************************************************************************)
+function GetSignalString(SignalNo: integer): string;
+begin
+ Result := strsignal(SignalNo);
+end;
+
+(********************************************************************************************************************************)
+function UnixTimeToTDateTime(UnixTime: Int64): TDateTime;
+//var tm : PUnixTime;
+begin
+ Result := UnixToDateTime(UnixTime);
+{ tm := localtime(@UnixTime);
+ Result := EncodeDate(tm^.tm_year + 1900, tm^.tm_mon + 1, tm^.tm_mday) +
+ EncodeTime(tm^.tm_hour, tm^.tm_min, tm^.tm_sec, 0); }
+end;
+
+(********************************************************************************************************************************)
+function FormatFloat64(Value: Int64; Sep: string): string;
+var i : integer;
+ Orig : string;
+begin
+ Result := IntToStr(Value);
+ Orig := Result;
+ if (Sep <> '') and (Length(Result) > 2) then
+ for i := Length(Result) downto 2 do
+ if (Length(Orig) - i + 1) mod 3 = 0 then
+ Insert(Sep, Result, i);
+end;
+
+function FormatSize(Value: Int64; Base: integer): string;
+var s: string;
+ i: integer;
+begin
+ if Base < 1 then Base := 1;
+ case ConfSizeFormat of
+ 0 : begin // System default formatting
+ Result := FormatFloat('###,###,##0', Value div Base);
+ end;
+ 1 : begin // 123456
+ Result := IntToStr(Value div Base);
+ end;
+ 2 : begin // 123,456
+ Result := FormatFloat64(Value div Base, ',');
+ end;
+ 3 : begin // 123 456
+ Result := FormatFloat64(Value div Base, ' ');
+ end;
+ 4 : begin // 123'456
+ Result := FormatFloat64(Value div Base, '''');
+ end;
+ 5 : begin // 123kB - Grouped
+ s := '###,###,##0';
+ if ConfSizeGroupPrecision > 0 then begin
+ s := s + '.';
+ for i := 1 to ConfSizeGroupPrecision do
+ if ConfSizeGroupRequestZeroDigits then s := s + '0'
+ else s := s + '#';
+ end;
+ if (Value >= 1024*1024*1024) or (Base = 1024*1024*1024) then Result := FormatFloat(s + ' GB', Value / (1024*1024*1024)) else
+ if (Value >= 1024*1024) or (Base = 1024*1024) then Result := FormatFloat(s + ' MB', Value / (1024*1024)) else
+ if (Value >= 1024) or (Base = 1024) then Result := FormatFloat(s + ' kB', Value / (1024)) else
+ Result := IntToStr(Value);
+ end;
+ end;
+ if ConfSizeFormat in [0..4] then begin
+ if Result = '' then Result := '0';
+ if Base = 1024 then Result := Result + ' kB' else
+ if Base = 1024*1024 then Result := Result + ' MB' else
+ if Base = 1024*1024*1024 then Result := Result + ' GB';
+ end;
+ if Result = '' then Result := '0';
+end;
+
+(********************************************************************************************************************************)
+function AttrToStr(const Mode: Cardinal; IncludeFileType: boolean = True): string;
+begin
+ if IncludeFileType then begin
+ if __S_ISTYPE(Mode, __S_IFLNK) then Result := 'l' else
+ if __S_ISTYPE(Mode, __S_IFDIR) then Result := 'd' else
+ if __S_ISTYPE(Mode, __S_IFBLK) then Result := 'b' else
+ if __S_ISTYPE(Mode, __S_IFCHR) then Result := 'c' else
+ if __S_ISTYPE(Mode, __S_IFIFO) then Result := 'f' else
+ if __S_ISTYPE(Mode, __S_IFSOCK) then Result := 's' else Result := '-';
+ end else Result := '';
+ if Mode and S_IRUSR = S_IRUSR then Result := Result + 'r' else Result := Result + '-';
+ if Mode and S_IWUSR = S_IWUSR then Result := Result + 'w' else Result := Result + '-';
+ if Mode and __S_ISUID = __S_ISUID then if Mode and S_IXUSR = S_IXUSR then Result := Result + 's' else Result := Result + 'S' else
+ if Mode and S_IXUSR = S_IXUSR then Result := Result + 'x' else Result := Result + '-';
+ if Mode and S_IRGRP = S_IRGRP then Result := Result + 'r' else Result := Result + '-';
+ if Mode and S_IWGRP = S_IWGRP then Result := Result + 'w' else Result := Result + '-';
+ if Mode and __S_ISGID = __S_ISGID then if Mode and S_IXGRP = S_IXGRP then Result := Result + 's' else Result := Result + 'S' else
+ if Mode and S_IXGRP = S_IXGRP then Result := Result + 'x' else Result := Result + '-';
+ if Mode and S_IROTH = S_IROTH then Result := Result + 'r' else Result := Result + '-';
+ if Mode and S_IWOTH = S_IWOTH then Result := Result + 'w' else Result := Result + '-';
+ if Mode and __S_ISVTX = __S_ISVTX then if Mode and S_IXOTH = S_IXOTH then Result := Result + 't' else Result := Result + 'T' else
+ if Mode and S_IXOTH = S_IXOTH then Result := Result + 'x' else Result := Result + '-';
+end;
+
+(********************************************************************************************************************************)
+function AttrToOctal(const Mode: Cardinal): integer;
+var x, Mult: Cardinal;
+begin
+ Result := 0;
+ Mult := 1;
+ x := Mode;
+ while x > 0 do begin
+ Result := Result + Integer((x mod 8) * Mult);
+ x := x div 8;
+ Mult := Mult * 10;
+ end;
+end;
+
+(********************************************************************************************************************************)
+function OctalToAttr(Octal: Cardinal): Cardinal;
+var octnr, oct : Cardinal;
+begin
+ octnr := 0;
+ oct := 0;
+ while (Octal > 0) do begin
+ oct := oct or ((Octal mod 10) shl octnr);
+ Octal := Octal div 10;
+ inc(octnr, 3);
+ end;
+ Result := oct;
+end;
+
+(********************************************************************************************************************************)
+function PosEnd(Substr: string; S: string): Integer;
+var i : integer;
+begin
+ Result := 0;
+ if (Length(Trim(S)) < 1) or (Length(Trim(Substr)) < 1) or (Length(Trim(Substr)) > Length(Trim(S))) then Exit;
+ for i := Length(S) - Length(SubStr) downto 1 do
+ if Copy(s, i, Length(Substr)) = SubStr then begin
+ Result := i;
+ Break;
+ end;
+end;
+
+(********************************************************************************************************************************)
+function GetHomePath: string;
+begin
+ Result := PgcharToString(g_get_home_dir);
+end;
+
+(********************************************************************************************************************************)
+function GetUserName: string;
+begin
+ Result := PgcharToString(g_get_user_name);
+end;
+
+(********************************************************************************************************************************)
+function GetHostName: string;
+var s: PChar;
+begin
+ s := Libc.malloc(65536);
+ Libc.memset(s, 0, 65536);
+ Libc.gethostname(s, 65536);
+ Result := PgcharToString(strdup(s));
+ Libc.free(s);
+end;
+
+(********************************************************************************************************************************)
+procedure SeparateExt(const Original: string; var Name, Ext: string);
+var j: integer;
+begin
+ Ext := '';
+ Name := Original;
+ if {(Pos('.', Original) > 1) and } (Length(Original) > 2) then begin
+ j := LastDelimiter('.', Original);
+ if (j > 1) and (j < Length(Original)) then begin
+ Ext := Copy(Original, j + 1, Length(Original) - j);
+ Delete(Name, j, Length(Name) - j + 1);
+ end;
+ end;
+end;
+
+(********************************************************************************************************************************)
+procedure SeparateNameDir(Original: string; var Path, FileName: string);
+var j: integer;
+begin
+ Original := ExcludeTrailingPathDelimiter(Original);
+ Path := Original;
+ FileName := '';
+ if (Pos('/', Original) > 0) and (Length(Original) > 2) then begin
+ j := LastDelimiter('/', Original);
+ if j > 0 then begin
+ FileName := Copy(Original, j + 1, Length(Original) - j);
+ Delete(Path, j, Length(Original) - j + 1);
+ end;
+ end;
+end;
+
+(********************************************************************************************************************************)
+function PadRightStr(const Str: string; Len: byte): string;
+var i: integer;
+begin
+ Result := Str;
+ for i := 1 to Len - Length(Str) do Insert(' ', Result, 1);
+end;
+
+(********************************************************************************************************************************)
+function SearchNext(var Wilds: string): Integer;
+
+{ looking for next *, returns position and string until position }
+begin
+ Result := Pos('*', Wilds);
+ if Result > 0 then Wilds := Copy(Wilds, 1, Result - 1);
+end;
+
+
+function FindPart(const HelpWilds, InputStr: string): Integer;
+
+{ FindPart compares a string with '?' and another, returns the position of HelpWilds in InputStr. }
+var
+ I, J: Integer;
+ Diff: Integer;
+begin
+ I := Pos('?', HelpWilds);
+ if I = 0 then begin
+ { if no '?' in HelpWilds }
+ Result := Pos(HelpWilds, InputStr);
+ Exit;
+ end;
+ { '?' in HelpWilds }
+ Diff := Length(InputStr) - Length(HelpWilds);
+ if Diff < 0 then begin
+ Result := 0;
+ Exit;
+ end;
+ { now move HelpWilds over InputStr }
+ for I := 0 to Diff do begin
+ for J := 1 to Length(HelpWilds) do begin
+ if (InputStr[I + J] = HelpWilds[J]) or
+ (HelpWilds[J] = '?') then
+ begin
+ if J = Length(HelpWilds) then begin
+ Result := I + 1;
+ Exit;
+ end;
+ end
+ else Break;
+ end;
+ end;
+ Result := 0;
+end;
+
+
+function IsWild(InputStr, Wilds: string; IgnoreCase: Boolean): Boolean;
+
+var
+ CWild, CInputWord: Integer; { counter for positions }
+ I, LenHelpWilds: Integer;
+ MaxInputWord, MaxWilds: Integer; { Length of InputStr and Wilds }
+ HelpWilds: string;
+begin
+ if Wilds = InputStr then begin
+ Result := True;
+ Exit;
+ end;
+ repeat { delete '**', because '**' = '*' }
+ I := Pos('**', Wilds);
+ if I > 0 then
+ Wilds := Copy(Wilds, 1, I - 1) + '*' + Copy(Wilds, I + 2, MaxInt);
+ until I = 0;
+ if (Wilds = '*') or (Wilds = '*.*') then begin { for fast end, if Wilds only '*' }
+ Result := True;
+ Exit;
+ end;
+ MaxInputWord := Length(InputStr);
+ MaxWilds := Length(Wilds);
+ if IgnoreCase then begin { upcase all letters }
+ InputStr := AnsiUpperCase(InputStr);
+ Wilds := AnsiUpperCase(Wilds);
+ end;
+ if (MaxWilds = 0) or (MaxInputWord = 0) then begin
+ Result := False;
+ Exit;
+ end;
+ CInputWord := 1;
+ CWild := 1;
+ Result := True;
+ repeat
+ if InputStr[CInputWord] = Wilds[CWild] then begin { equal letters }
+ { goto next letter }
+ Inc(CWild);
+ Inc(CInputWord);
+ Continue;
+ end;
+ if Wilds[CWild] = '?' then begin { equal to '?' }
+ { goto next letter }
+ Inc(CWild);
+ Inc(CInputWord);
+ Continue;
+ end;
+ if Wilds[CWild] = '*' then begin { handling of '*' }
+ HelpWilds := Copy(Wilds, CWild + 1, MaxWilds);
+ I := SearchNext(HelpWilds);
+ LenHelpWilds := Length(HelpWilds);
+ if I = 0 then begin
+ { no '*' in the rest, compare the ends }
+ if HelpWilds = '' then Exit; { '*' is the last letter }
+ { check the rest for equal Length and no '?' }
+ {$R-}
+ for I := 0 to LenHelpWilds - 1 do begin
+ if (HelpWilds[LenHelpWilds - I] <> InputStr[MaxInputWord - I]) and
+ (HelpWilds[LenHelpWilds - I]<> '?') then
+ begin
+ Result := False;
+ Exit;
+ end;
+ end;
+ {$R+}
+ Exit;
+ end;
+ { handle all to the next '*' }
+ Inc(CWild, 1 + LenHelpWilds);
+ I := FindPart(HelpWilds, Copy(InputStr, CInputWord, MaxInt));
+ if I = 0 then begin
+ Result := False;
+ Exit;
+ end;
+ CInputWord := I + LenHelpWilds;
+ Continue;
+ end;
+ Result := False;
+ Exit;
+ until (CInputWord > MaxInputWord) or (CWild > MaxWilds);
+ { no completed evaluation }
+ if CInputWord <= MaxInputWord then Result := False;
+ if (CWild <= MaxWilds) and (Wilds[MaxWilds] <> '*') then Result := False;
+end;
+
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+
+
+(********************************************************************************************************************************)
+type TPatternCacheItem = record
+ Pattern, APath, FileName: string;
+ DirDidNotExist: boolean;
+ end;
+
+var PatternCache : array of TPatternCacheItem;
+
+function ProcessPattern(Engine: TPanelEngine; Pattern, APath, FileName: string; const Directory: boolean): string;
+var Path : string;
+
+ procedure ProcessParam(const Part: string);
+ begin
+ // Check for upper directory
+ if (Length(Part) >= 2) and (Copy(Part, 1, 2) = '..') then begin
+ if (Path <> '/') and (LastDelimiter('/', Path) > 1) then begin
+ Path := ExcludeTrailingPathDelimiter(Path);
+ Delete(Path, LastDelimiter('/', Path), Length(Path) - LastDelimiter('/', Path) + 1);
+ Path := IncludeTrailingPathDelimiter(Path);
+ end;
+ end else
+ if Part = '.' then begin end else // On current dir ('.') do nothing
+ // Add directory
+ Path := IncludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(Path) + Part);
+ end;
+
+ function ProcessPart(WildPart, FilePart: string): string;
+ var i, j, CWild, CInputWord, MaxInputWord, MaxWilds, LenHelpWilds: integer;
+ HelpWilds, s: string;
+ begin
+ Result := '';
+ if (WildPart = '*') or (Length(WildPart) = 0) then Result := FilePart else
+ if LastDelimiter('*?', WildPart) = 0 then Result := WildPart else
+ begin
+ repeat { delete '**', because '**' = '*' }
+ I := Pos('**', WildPart);
+ if I > 0 then WildPart := Copy(WildPart, 1, I - 1) + '*' + Copy(WildPart, I + 2, MaxInt);
+ until I = 0;
+ MaxInputWord := Length(FilePart);
+ MaxWilds := Length(WildPart);
+ CInputWord := 1;
+ CWild := 1;
+ repeat
+ if not (WildPart[CWild] in ['?', '*']) then begin
+ Result := Result + WildPart[CWild];
+ if WildPart[CWild] = FilePart[CInputWord] then Inc(CInputWord);
+ Inc(CWild);
+ Continue;
+ end;
+ if WildPart[CWild] = '?' then begin
+ if Length(FilePart) <= CWild then Result := Result + FilePart[CWild];
+ Inc(CWild);
+ if Length(FilePart) < CWild then Inc(CInputWord);
+ Continue;
+ end;
+ if WildPart[CWild] = '*' then begin { handling of '*' }
+ HelpWilds := Copy(WildPart, CWild + 1, MaxWilds);
+ I := SearchNext(HelpWilds);
+ LenHelpWilds := Length(HelpWilds);
+ if (I = 0) and (HelpWilds = '') then begin
+ { no '*' in the rest, compare the ends }
+ Result := Result + Copy(FilePart, CInputWord, MaxInputWord - CInputWord + 1);
+ Break; { '*' is the last letter }
+ end;
+ if (I = 0) and (Pos('?', HelpWilds) = 0) then begin
+ Result := Result + Copy(FilePart, CInputWord, MaxInputWord - CInputWord + 1) + HelpWilds;
+ Break;
+ end;
+ s := Copy(FilePart, CInputWord, MaxInputWord - CInputWord + 1);
+ i := FindPart(HelpWilds, s);
+ if i = 0 then Result := Result + HelpWilds else
+ begin
+ for j := 1 to Length(HelpWilds) do
+ if HelpWilds[j] = '?' then HelpWilds[j] := s[j - 1 + i];
+ Result := Result + Copy(s, 1, i + Length(HelpWilds) - 1);
+ Inc(CInputWord, i + LenHelpWilds - 1);
+ end;
+ Inc(CWild, 1 + LenHelpWilds);
+ Continue;
+ end;
+ Break;
+ until (CInputWord > MaxInputWord) or (CWild > MaxWilds);
+ end;
+ end;
+
+ function ProcessWilds(WildStr, AFile: string): string;
+ var i, j, WPC, FPC: integer;
+ DotFile: boolean;
+ begin
+ if (WildStr = '*.*') or (WildStr = '') then Result := AFile else
+ if WildStr = '*' then begin
+ if (Pos('.', AFile) = 0) or (Copy(AFile, 1, 1) = '.') then Result := AFile else
+ Result := Copy(AFile, 1, LastDelimiter('.', AFile) - 1);
+ end else begin
+ Result := '';
+ DotFile := False;
+ if (Length(AFile) > 0) and (AFile[1] = '.') then begin
+ DotFile := True;
+ Delete(AFile, 1, 1);
+ end;
+ // Trim redundant parameters
+ WPC := 0;
+ for i := 1 to Length(WildStr) do if WildStr[i] = '.' then Inc(WPC);
+ FPC := 0;
+ for i := 1 to Length(AFile) do if AFile[i] = '.' then Inc(FPC);
+ if WPC > FPC then
+ for j := 1 to WPC - FPC do begin
+ Result := '.' + Copy(WildStr, LastDelimiter('.', WildStr) + 1, Length(WildStr) - LastDelimiter('.', WildStr)) + Result;
+ Delete(WildStr, LastDelimiter('.', WildStr), Length(WildStr) - LastDelimiter('.', WildStr) + 1);
+ end;
+ // Going processing
+ while (LastDelimiter('.', WildStr) > 0) and (LastDelimiter('.', AFile) > 0) do begin
+ Result := '.' + ProcessPart(Copy(WildStr, LastDelimiter('.', WildStr) + 1, Length(WildStr) - LastDelimiter('.', WildStr)),
+ Copy(AFile, LastDelimiter('.', AFile) + 1, Length(AFile) - LastDelimiter('.', AFile))) + Result;
+ Delete(WildStr, LastDelimiter('.', WildStr), Length(WildStr) - LastDelimiter('.', WildStr) + 1);
+ Delete(AFile, LastDelimiter('.', AFile), Length(AFile) - LastDelimiter('.', AFile) + 1);
+ end;
+ if WildStr <> '' then Result := ProcessPart(WildStr, AFile) + Result;
+ if DotFile then Result := '.' + Result;
+ end;
+ // Trim unwanted characters
+ if Length(Result) > 0 then
+ for i := 1 to Length(Result) do
+ if Result[i] in ['*', '?', '/'] then Result[i] := '_';
+ end;
+
+ function FindInCache: integer;
+ var i: integer;
+ begin
+ Result := -1;
+ if LengtH(PatternCache) > 0 then
+ for i := 0 to Length(PatternCache) - 1 do
+ if (PatternCache[i].Pattern = Pattern) and (PatternCache[i].APath = APath) and (Pos(PatternCache[i].FileName, FileName) = 1) then
+ begin
+ Result := i;
+ Break;
+ end;
+ end;
+
+ function CaseDirExists(DPath, DFileName: string): boolean;
+ begin
+ if (AnsiCompareStr(Pattern, FileName) <> 0) and (AnsiCompareText(Pattern, FileName) = 0) and Directory and
+ Engine.TwoSameFiles(DPath + Pattern, DPath + FileName)
+ then Result := False
+ else Result := Engine.DirectoryExists(DPath + DFileName);
+ end;
+
+
+
+
+var s: string;
+ x: integer;
+begin
+ Result := '';
+ if Pattern = '' then Exit;
+ // Select basic directory
+ case Pattern[1] of
+ '/' : begin
+ Path := '/';
+ if Length(Pattern) > 1 then Delete(Pattern, 1, 1);
+ end;
+ '~' : begin
+ Path := IncludeTrailingPathDelimiter(GetHomePath);
+ Delete(Pattern, 1, 1);
+ end;
+ else Path := IncludeTrailingPathDelimiter(APath);
+ end;
+ // Process directories in pattern
+ while Pos('/', Pattern) > 0 do begin
+ s := Copy(Pattern, 1, Pos('/', Pattern) - 1);
+ Delete(Pattern, 1, Pos('/', Pattern));
+ ProcessParam(s);
+ end;
+ // Add rest of pattern parts
+ if (Pos('?', Pattern) = 0) and (Pos('*', Pattern) = 0) then begin
+ if (Pattern <> '.') and (Pattern <> '..') and (not CaseDirExists(IncludeTrailingPathDelimiter(Path), Pattern)) then begin
+ if Directory then Path := IncludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(Path) + Pattern)
+ else Path := ExcludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(Path) + Pattern);
+ SetLength(PatternCache, Length(PatternCache) + 1);
+ PatternCache[Length(PatternCache) - 1].Pattern := Pattern;
+ PatternCache[Length(PatternCache) - 1].APath := APath;
+ PatternCache[Length(PatternCache) - 1].FileName := FileName;
+ end else begin
+ if Length(Pattern) > 0 then ProcessParam(Pattern);
+ x := FindInCache;
+ if x < 0 then begin
+ Path := IncludeTrailingPathDelimiter(Path) + FileName;
+ end else begin
+ Delete(FileName, 1, Length(IncludeTrailingPathDelimiter(PatternCache[x].FileName)));
+ Path := IncludeTrailingPathDelimiter(Path) + FileName;
+ end;
+ if Directory then Path := IncludeTrailingPathDelimiter(Path)
+ else Path := ExcludeTrailingPathDelimiter(Path);
+ end;
+ end else Path := Path + ProcessWilds(Pattern, FileName);
+
+ Result := Path;
+end;
+
+
+(********************************************************************************************************************************)
+(********************************************************************************************************************************)
+procedure ShowAbout;
+const Authors : array[0..1] of PChar = ('Tomáš Bžatek <tbzatek@users.sourceforge.net>', nil);
+ Translations : PChar = 'Tomáš Bžatek <tbzatek@users.sourceforge.net> - English, Czech'#10 +
+ 'Maxim Baranov <maxbaranov@hotbox.ru> - Russian'#10 +
+ 'Sven Laufersweiler <laufersweiler@bettercad.de> - German'#10 +
+ 'Johan Åkesson <johan@badanka.com> - Swedish'#10 +
+ 'Marie-Agnès Pauchet-Le Héricy <marie@kerplh.com> - French'#10 +
+ 'Daniel Areiza <nnoseman@hotmail.com> - Spanish'#10 +
+ 'Dominik Zabłotny <dominz@wp.pl> - Polish'#10 +
+ 'Serhij Dubyk <dubyk@ukr.net> - Ukrainian'#10 +
+ 'Bojan Božović <bojanb@sbb.co.yu> - Serbian'#10 +
+ 'Marián Képesi <m_kepesi@yahoo.com> - Hungarian'#10 +
+ 'Francesco Turco <fctk86@gmail.com> - Italian';
+var AboutBox: PGtkWidget;
+begin
+ if (libGnomeUI2Handle = nil) or (@gnome_about_new = nil)
+ then Application.MessageBox(Format(LANGAboutString, [ConstAboutVersion, ConstAboutBuildDate]))
+ else begin
+ AboutBox := gnome_about_new('Tux Commander', nil, 'Copyright © 2008 Tomáš Bžatek',
+ PChar(Format(LANGAboutStringGnome, [ConstAboutVersion, ConstAboutBuildDate])),
+ @Authors, nil, Translations, nil);
+ gtk_window_set_transient_for(GTK_WINDOW(AboutBox), GTK_WINDOW(FMain.FWidget));
+ gtk_dialog_run(GTK_DIALOG(AboutBox));
+ end;
+end;
+
+(********************************************************************************************************************************)
+procedure TrimCRLFESC(var s: string);
+begin
+ while (Length(s) > 0) and (s[1] in [#13, #10, #27]) do Delete(s, 1, 1);
+ while (Length(s) > 0) and (s[Length(s)] in [#13, #10, #27]) do Delete(s, Length(s), 1);
+end;
+
+(********************************************************************************************************************************)
+procedure TrimQuotes(var s: string);
+begin
+ while (Length(s) > 0) and (s[1] in ['"', '''']) do Delete(s, 1, 1);
+ while (Length(s) > 0) and (s[Length(s)] in ['"', '''']) do Delete(s, Length(s), 1);
+end;
+
+(********************************************************************************************************************************)
+function QuoteStr(const Str: string): string;
+var i: integer;
+begin
+ Result := '';
+ if Length(Str) > 0 then
+ for i := 1 to Length(Str) do begin
+ if Str[i] in ConstQuotationCharacters then Result := Result + '\';
+ Result := Result + Str[i];
+ end;
+end;
+
+(********************************************************************************************************************************)
+function QuotePercentStr(const Str: string): string;
+var i: integer;
+begin
+ Result := '';
+ if Length(Str) > 0 then
+ for i := 1 to Length(Str) do begin
+ if Str[i] = '%' then Result := Result + '%';
+ Result := Result + Str[i];
+ end;
+end;
+
+(********************************************************************************************************************************)
+function QuoteMarkupStr(const Str: string): string;
+var i: integer;
+begin
+ Result := '';
+ if Length(Str) > 0 then
+ for i := 1 to Length(Str) do begin
+ if Str[i] = '<' then Result := Result + '&#60;' else
+ if Str[i] = '>' then Result := Result + '&#62;' else
+ if Str[i] = '&' then Result := Result + '&amp;' else
+// if Str[i] = '_' then Result := Result + '__' else
+ Result := Result + Str[i];
+ end;
+end;
+
+(********************************************************************************************************************************)
+function RemoveQuotation(const Str: string): string;
+var b: boolean;
+ i: integer;
+begin
+ Result := Str;
+ if Length(Result) < 2 then Exit;
+ b := True;
+ for i := 2 to Length(Result) do
+ if (Result[i] in ConstQuotationCharacters) and (Result[i - 1] <> '\') then b := False;
+ if b then for i := Length(Result) downto 2 do
+ if (Result[i] in ConstQuotationCharacters) and (Result[i - 1] = '\') then Delete(Result, i - 1, 1);
+end;
+
+(********************************************************************************************************************************)
+function ReplaceStr(const S, Srch, Replace: string): string;
+var
+ I: Integer;
+ Source: string;
+begin
+ Source := S;
+ Result := '';
+ repeat
+ I := Pos(Srch, Source);
+ if I > 0 then begin
+ Result := Result + Copy(Source, 1, I - 1) + Replace;
+ Source := Copy(Source, I + Length(Srch), MaxInt);
+ end
+ else Result := Result + Source;
+ until I <= 0;
+end;
+
+(********************************************************************************************************************************)
+function NumCountChars(const Char: char; const S: string): integer;
+var i: integer;
+begin
+ Result := 0;
+ if Length(S) > 0 then
+ for i := 1 to Length(S) do
+ if S[i] = Char then Inc(Result);
+end;
+
+(********************************************************************************************************************************)
+procedure ParseString(const Str, Separator: string; var SubStrings: TOpenStringArray);
+var s: string;
+ i: integer;
+begin
+ s := Str;
+ while Pos(Separator, s) > 0 do begin
+ i := Pos(Separator, s);
+ SetLength(SubStrings, Length(SubStrings) + 1);
+ SubStrings[Length(SubStrings) - 1] := Copy(s, 1, i - 1);
+ Delete(s, 1, i);
+ end;
+ if Length(s) > 0 then begin // Add the last element
+ SetLength(SubStrings, Length(SubStrings) + 1);
+ SubStrings[Length(SubStrings) - 1] := s;
+ end;
+end;
+
+(********************************************************************************************************************************)
+function GetStrSize(s: string): Int64;
+var i: integer;
+ x: Double;
+ b: boolean;
+begin
+ Result := 0;
+ x := 0;
+ s := AnsiUpperCase(Trim(s));
+ if Length(s) = 0 then Exit;
+ for i := Length(s) downto 1 do
+ if s[i] in [#32, ThousandSeparator] then Delete(s, i, 1);
+ b := False;
+ for i := 2 to Length(s) do
+ if not (s[i] in ['0', '1'..'9', DecimalSeparator]) then
+ begin
+ x := StrToFloatDef(Copy(s, 1, i - 1), 0);
+ case s[i] of
+ 'G': x := x * 1000 * 1000 * 1000;
+ 'M': x := x * 1000 * 1000;
+ 'K': x := x * 1024;
+ end;
+ b := True;
+ Break;
+ end;
+ if not b then x := StrToInt64Def(s, Trunc(x));
+ Result := Trunc(x);
+end;
+
+(********************************************************************************************************************************)
+function ConstructURI(HidePasswd: boolean; Protocol, Server, Username, Password, Dir: string): string;
+begin
+ Result := Protocol + '://';
+ if Length(Username) > 0 then begin
+ Result := Result + Username;
+ if Length(Password) > 0 then
+ if HidePasswd then Result := Result + ':' + StringOfChar('*', Length(Password))
+ else Result := Result + ':' + Password;
+ Result := Result + '@';
+ end;
+ Result := Result + Server;
+ if Length(Dir) > 0 then begin
+ if Dir[1] <> '/' then Result := Result + '/';
+ Result := Result + Dir;
+ end;
+end;
+
+(********************************************************************************************************************************)
+function URIHidePassword(const SrcURI: string): string;
+var i: integer;
+ InPasswd, BeforeServer: boolean;
+begin
+ Result := SrcURI;
+ InPasswd := False;
+ BeforeServer := True;
+ if Length(SrcURI) > 0 then
+ if Pos('://', SrcURI) > 0 then
+ for i := Pos('://', SrcURI) + 2 to Length(SrcURI) do begin
+ if SrcURI[i] = '@' then begin
+ InPasswd := False;
+ BeforeServer := False;
+ end;
+ if (not InPasswd) or (not BeforeServer)
+ then InPasswd := BeforeServer and (SrcURI[i] = ':')
+ else Result[i] := '*';
+ end;
+end;
+
+(********************************************************************************************************************************)
+procedure DebugMsg(Params: array of const);
+var
+ I: Integer;
+begin
+ if ParamDebug then begin
+ for I := 0 to High(Params) do
+ with Params[I] do
+ case VType of
+ vtInteger: Write(ErrOutput, IntToStr(VInteger));
+ vtBoolean: Write(ErrOutput, VBoolean);
+ vtChar: Write(ErrOutput, VChar);
+ vtExtended: Write(ErrOutput, FloatToStr(VExtended^));
+ vtString: Write(ErrOutput, VString^);
+ vtPChar: Write(ErrOutput, VPChar);
+ vtObject: Write(ErrOutput, VObject.ClassName);
+ vtClass: Write(ErrOutput, VClass.ClassName);
+ vtAnsiString: Write(ErrOutput, string(VAnsiString));
+ vtCurrency: Write(ErrOutput, CurrToStr(VCurrency^));
+ vtVariant: Write(ErrOutput, string(VVariant^));
+ vtInt64: Write(ErrOutput, IntToStr(VInt64^));
+ end;
+ WriteLn(ErrOutput);
+ end;
+end;
+
+(********************************************************************************************************************************)
+function SpawnProcess(const AppPath: string; var Running: boolean; const Parameters: array of string): Cardinal;
+var child_pid: __pid_t;
+ args_list: System.PPChar;
+ i: integer;
+ Temp: string;
+ sv: sigval_t;
+begin
+ Result := 0;
+ Running := False;
+ ChildExitStatus := -1;
+
+ // Make the args_list array
+ args_list := nil;
+ if Length(Parameters) > 0 then begin
+ args_list := Libc.malloc((Length(Parameters) + 1) * SizeOf(PChar));
+ Libc.memset(args_list, 0, (Length(Parameters) + 1) * SizeOf(PChar));
+ for I := 0 to Length(Parameters) - 1 do
+ begin
+ Temp := Parameters[i];
+ {$R-}
+// PCharArray(args_list^)[I] := Libc.malloc(Length(Temp)+1);
+// Libc.memset(PCharArray(args_list^)[I], 0, Length(Temp)+1);
+// StrCopy(PCharArray(args_list^)[I], PChar(Temp));
+ PCharArray(args_list^)[I] := strdup(PChar(Temp));
+ {$R+}
+ end;
+ {$R-}
+ PCharArray(args_list^)[Length(Parameters)] := nil;
+ {$R+}
+ end;
+
+ // Duplicate this process
+ child_pid := fork;
+ if child_pid <> 0 then begin
+ Result := child_pid;
+ Sleep(100);
+ Application.ProcessMessages;
+ Running := ChildExitStatus < 0;
+ if not Running then Result := 0;
+ if not WIFEXITED(ChildExitStatus) then Result := WTERMSIG(ChildExitStatus);
+ end else begin
+ // Now execute AppPath, searching for it in the path
+ execvp(PChar(AppPath), args_list);
+ // The execvp function returns only if an error occurs
+ sigqueue(getppid, SIGUSR1, sv);
+ Halt(ConstERRSpawn);
+ end;
+ ChildExitStatus := -1;
+end;
+
+(********************************************************************************************************************************)
+procedure SplitArgs(var Args: TOpenStringArray; CMDLine: string);
+var InQuotes: boolean;
+ i, Start: integer;
+ QuoteChar: char;
+ s: string;
+begin
+ SetLength(Args, 0);
+ InQuotes := False;
+ CMDLine := Trim(CMDLine);
+ if Length(CMDLine) = 0 then Exit;
+ Start := 1;
+ QuoteChar := #0;
+ for i := 1 to Length(CMDLine) do
+ case CMDLine[i] of
+ ' ': if (not InQuotes) and ((i = 1) or (CMDLine[i - 1] <> '\')) then begin
+ s := Trim(Copy(CMDLine, Start, i - Start));
+ TrimQuotes(s);
+ Start := i;
+ if s = '' then Continue;
+ SetLength(Args, Length(Args) + 1);
+ Args[Length(Args) - 1] := s;
+ end;
+ '"', '''': if (i = 1) or (CMDLine[i - 1] <> '\') then
+ if not InQuotes then begin
+ InQuotes := True;
+ QuoteChar := CMDLine[i];
+// Start := i;
+ end else
+ if CMDLine[i] = QuoteChar then begin
+ InQuotes := False;
+ s := Trim(Copy(CMDLine, Start, i + 1 - Start));
+ TrimQuotes(s);
+ Start := i;
+ if s = '' then Continue;
+ if (Pos('"', s) > 1) and (Pos('"', s) < Length(s)) and (NumCountChars('"', s) mod 2 = 1) then s := s + '"';
+// if (Pos('''', s) > 1) and (Pos('''', s) < Length(s)) and (NumCountChars('''', s) mod 2 = 1) then s := s + '''';
+ SetLength(Args, Length(Args) + 1);
+ Args[Length(Args) - 1] := s;
+ end;
+ end;
+ if (Start <> Length(CMDLine)) or (Start = 1) then begin
+ SetLength(Args, Length(Args) + 1);
+ Args[Length(Args) - 1] := Trim(Copy(CMDLine, Start, Length(CMDLine) + 1 - Start));
+ TrimQuotes(Args[Length(Args) - 1]);
+ end;
+end;
+
+function ExecuteProgram(const AppCMDLine, CWD: string; const AutodetectGUI, RunInTerminal: boolean; var ErrorSignal: integer): boolean;
+var Args: TOpenStringArray;
+ s, s2: string;
+ Running, Term: boolean;
+ x: integer;
+begin
+ Result := False;
+ try
+ DebugMsg(['*** Running ExecuteProgram begin']);
+ s := Trim(AppCMDLine);
+ ErrorSignal := 0;
+ Term := RunInTerminal;
+ SplitArgs(Args, s);
+
+ if AutodetectGUI then
+ if Length(Trim(Args[0])) > 0 then Term := not IsItX11App(Trim(Args[0]));
+
+ if Term then begin
+ x := 1;
+ while x <= Length(s) do begin
+ if (s[x] in [{'"',} '''']) and ((x = 1) or (s[x - 1] <> '\')) then
+ Insert('\', s, x);
+ Inc(x);
+ end;
+ s2 := ReplaceStr(ConfTerminalCommand, '%cwd', QuoteStr(CWD));
+ s := Format(s2, [s]);
+ SplitArgs(Args, s);
+ end;
+
+ if ConfUseLibcSystem then begin
+ s := s + ' &';
+ DebugMsg([s]);
+ DebugMsg(['**** Running libc.system']);
+ x := Libc.system(PChar(s));
+ Result := x <> -1; // -1 means fork failed
+ DebugMsg(['**** Running libc.system = ', x, ' --- done']);
+ end else begin
+ if Length(Args) = 0 then Exit;
+ for x := 0 to Length(Args) - 1 do Args[x] := RemoveQuotation(Args[x]);
+ DebugMsg(['**** Running spawn']);
+ x := SpawnProcess(Args[0], Running, Args);
+ DebugMsg(['**** Running spawn -- done']);
+ Result := Running;
+ if not Running then ErrorSignal := x;
+ end;
+
+ except
+ end;
+ DebugMsg(['*** Running ExecuteProgram end']);
+end;
+
+(********************************************************************************************************************************)
+function IsItX11App(const Application: string): boolean;
+const BSize = 32768;
+ What = 'libX11.so';
+var stream: PIOFile;
+ Buffer: Pointer;
+ i: integer;
+ str: string;
+begin
+ Result := False;
+ DebugMsg(['***** function IsItX11App(''', Application, ''') begin --']);
+
+ try
+// setenv('LD_TRACE_LOADED_OBJECTS', '1', True);
+ stream := popen(PChar('LD_TRACE_LOADED_OBJECTS=1 ' + Application), 'r');
+// stream := popen(PChar(Application), 'r');
+ DebugMsg(['***** IsItX11App: popen OK']);
+ if Assigned(stream) then begin
+ Buffer := Libc.malloc(BSize);
+ if buffer = nil then Writeln('buffer nil: ', integer(errno));
+ if stream = nil then Writeln('stream nil');
+ Libc.memset(Buffer, 0, BSize);
+ DebugMsg(['***** IsItX11App: malloc() OK']);
+
+ while feof(stream) = 0 do begin
+ i := Libc.fread(Buffer, 1, BSize, stream);
+ if i > 0 then begin
+ SetLength(str, i);
+ memcpy(@str[1], Buffer, i);
+ Result := Result or (Pos(What, str) > 0);
+ end;
+ end;
+ pclose(stream);
+ end;
+// unsetenv('LD_TRACE_LOADED_OBJECTS');
+
+ except
+ on E: Exception do DebugMsg(['*** IsItX11App(''', Application, '''):Exception: ', E.Message]);
+ end;
+ DebugMsg(['***** function IsItX11App(''', Application, ''') = ', Result]);
+end;
+
+function HandleSystemCommand(const Command, ErrorText: string): boolean;
+const BSize = 32768;
+var stream: PIOFile;
+ Buffer: Pointer;
+ i, NumRead: integer;
+ child_pid: __pid_t;
+ fds: array[0..1] of integer;
+ Parameters: TOpenStringArray;
+ args_list: System.PPChar;
+ Temp, s: string;
+begin
+ Result := False;
+ DebugMsg(['***** function HandleSystemCommand(''', Command, ''') begin --']);
+
+ try
+ DebugMsg(['***** HandleSystemCommand: before fork']);
+ pipe(@fds);
+ child_pid := fork;
+ DebugMsg(['***** HandleSystemCommand: fork, child_pid = ', child_pid]);
+
+
+ // Main application
+ if child_pid <> 0 then begin
+ __close(fds[1]);
+ stream := fdopen(fds[0], 'r');
+ Buffer := Libc.malloc(BSize);
+ DebugMsg(['x0']);
+ Libc.memset(Buffer, 0, BSize);
+ DebugMsg(['x1']);
+ if buffer = nil then Writeln('buffer nil: ', integer(errno));
+ if stream = nil then Writeln('stream nil');
+
+ SetLength(s, 0);
+ while feof(stream) = 0 do begin
+ NumRead := fread(Buffer, 1, BSize, stream);
+ DebugMsg(['***** HandleSystemCommand: NumRead = ', NumRead]);
+ if NumRead > 0 then begin
+ SetLength(s, Length(s) + NumRead);
+ memcpy(@s[Length(s) - NumRead + 1], Buffer, NumRead);
+ end;
+ end;
+ __close(fds[0]);
+ DebugMsg(['x2']);
+ TrimCRLFESC(s);
+ DebugMsg(['x3']);
+
+ Libc.free(Buffer);
+ DebugMsg(['x4']);
+ end
+
+ // forked PID
+ else begin
+ try
+ SplitArgs(Parameters, Command);
+ // Fill the args_list array
+ args_list := nil;
+ if Length(Parameters) > 0 then begin
+ args_list := Libc.malloc((Length(Parameters) + 1) * SizeOf(PChar));
+ Libc.memset(args_list, 0, (Length(Parameters) + 1) * SizeOf(PChar));
+ for I := 0 to Length(Parameters) - 1 do
+ begin
+ Temp := Parameters[i];
+ {$R-}
+// PCharArray(args_list^)[I] := Libc.malloc(Length(Temp)+1);
+// Libc.memset(PCharArray(args_list^)[I], 0, Length(Temp)+1);
+// StrCopy(PCharArray(args_list^)[I], PChar(Temp));
+ PCharArray(args_list^)[I] := strdup(PChar(Temp));
+ {$R+}
+ end;
+ {$R-}
+ PCharArray(args_list^)[Length(Parameters)] := nil;
+ {$R+}
+ end;
+ except
+ on E: Exception do DebugMsg(['*** forked ** function HandleSystemCommand(''', Command, '''):Exception: ', E.Message]);
+ end;
+
+ __close(fds[0]); // Close copy of reader file descriptor
+ dup2(fds[1], STDERR_FILENO);
+ execvp(PChar(Parameters[0]), args_list);
+ DebugMsg(['***** HandleSystemCommand: failed execvp: something went wrong...']);
+ WriteLn(erroutput, 'Error executing command');
+ Halt(ConstERRSpawn);
+ end;
+
+ Result := Length(s) = 0;
+ if not Result then Application.MessageBox(Format('%s%s', [ErrorText, ANSIToUTF8(s)]), [mbOK], mbError, mbOK, mbOK);
+ except
+ on E: Exception do DebugMsg(['***** function HandleSystemCommand(''', Command, '''):Exception: ', E.Message]);
+ end;
+ DebugMsg(['***** finished function HandleSystemCommand(''', Command, ''') = ', Result]);
+end;
+
+
+(********************************************************************************************************************************)
+function CompareTextsEx(S1, S2: PChar): integer;
+const PriorityChars = '.[]_0123456789';
+var i, j, k, l1, l2 : integer;
+ Str1, Str2: string;
+begin
+ Result := -2;
+ Str1 := UpperCase(String(S1));
+ Str2 := UpperCase(String(S2));
+ l1 := Length(Str1);
+ l2 := Length(Str2);
+ if (l1 > 0) and (l2 > 0) then begin
+ if (Str1[1] = '.') and (Str2[1] <> '.') then Result := -1 else // Priority for dot files
+ if (Str2[1] = '.') and (Str1[1] <> '.') then Result := 1 else
+ for i := 1 to l1 do
+ if l2 >= i then
+ if Str1[i] <> Str2[i] then begin
+ j := Pos(Str1[i], PriorityChars);
+ k := Pos(Str2[i], PriorityChars);
+ if (j > 0) and (k > 0) then begin
+ if j < k then Result := -1 else
+ if j > k then Result := 1;
+ end else
+ if j > 0 then Result := -1 else
+ if k > 0 then Result := 1;
+ Break;
+ end;
+ if Result = -2 then Result := CompareText(Str1, Str2);
+ end else Result := CompareText(Str1, Str2);
+end;
+
+(********************************************************************************************************************************)
+function LVCompareItems(Data1, Data2: PDataItem; const Ascending: boolean; const SortColumnID: integer): integer;
+var mp: integer;
+ s1, s2, s3, s4: string;
+begin
+ if Ascending then mp := 1 else mp := -1;
+ if Data1^.UpDir then Result := -1*mp else
+ if Data2^.UpDir then Result := 1*mp else
+ if Data1^.IsDir and (not Data2^.IsDir) then Result := -1*mp else
+ if Data2^.IsDir and (not Data1^.IsDir) then Result := 1*mp else
+ case SortColumnID of
+ 1, 2 : begin
+ Result := CompareTextsEx(Data1^.AName, Data2^.AName);
+ if Data1^.IsDir and Data2^.IsDir then Result := Result * mp;
+ end;
+ 3 : if Data1^.IsDir and Data2^.IsDir then Result := CompareTextsEx(Data1^.AName, Data2^.AName)*mp else begin
+ SeparateExt(String(Data1^.AName), s1, s2);
+ SeparateExt(String(Data2^.AName), s3, s4);
+ if ANSIUpperCase(s2) <> ANSIUpperCase(s4)
+ then Result := CompareTextsEx(PChar(s2), PChar(s4))
+ else Result := CompareTextsEx(PChar(s1), PChar(s3));
+ end;
+ 4 : if Data1^.IsDir and Data2^.IsDir then Result := CompareTextsEx(Data1^.AName, Data2^.AName)*mp else
+ if Data1^.Size > Data2^.Size then Result := -1 else
+ if Data1^.Size < Data2^.Size then Result := 1 else
+ Result := CompareTextsEx(Data1^.AName, Data2^.AName);
+ 5, 6 : if Data1^.IsDir and Data2^.IsDir then Result := CompareTextsEx(Data1^.AName, Data2^.AName)*mp else
+ if Data1^.ModifyTime > Data2^.ModifyTime then Result := -1 else
+ if Data1^.ModifyTime < Data2^.ModifyTime then Result := 1 else
+ Result := CompareTextsEx(Data1^.AName, Data2^.AName);
+ 7 : if Data1^.IsDir and Data2^.IsDir then Result := CompareTextsEx(Data1^.AName, Data2^.AName)*mp else
+ if Frac(Data1^.ModifyTime) > Frac(Data2^.ModifyTime) then Result := -1 else
+ if Frac(Data1^.ModifyTime) < Frac(Data2^.ModifyTime) then Result := 1 else
+ Result := CompareTextsEx(Data1^.AName, Data2^.AName);
+ 8 : if Data1^.IsDir and Data2^.IsDir then Result := CompareTextsEx(Data1^.AName, Data2^.AName)*mp else
+ if Data1^.UID > Data2^.UID then Result := -1 else
+ if Data1^.UID < Data2^.UID then Result := 1 else
+ Result := CompareTextsEx(Data1^.AName, Data2^.AName);
+ 9 : if Data1^.IsDir and Data2^.IsDir then Result := CompareTextsEx(Data1^.AName, Data2^.AName)*mp else
+ if Data1^.GID > Data2^.GID then Result := -1 else
+ if Data1^.GID < Data2^.GID then Result := 1 else
+ Result := CompareTextsEx(Data1^.AName, Data2^.AName);
+ 10 : if Data1^.IsDir and Data2^.IsDir then Result := CompareTextsEx(Data1^.AName, Data2^.AName)*mp else
+ if Data1^.Mode > Data2^.Mode then Result := -1 else
+ if Data1^.Mode < Data2^.Mode then Result := 1 else
+ Result := CompareTextsEx(Data1^.AName, Data2^.AName);
+ else Result := 0;
+ end;
+end;
+
+(********************************************************************************************************************************)
+procedure SortDataList(var List: TList; const Ascending: boolean; const SortColumnID: integer);
+var AscCorr: integer;
+
+ procedure QuickSort(iLo, iHi: Integer);
+ var Lo, Hi : Integer;
+ Mid, x: Pointer;
+ begin
+ Lo := iLo;
+ Hi := iHi;
+ Mid := List[(Lo + Hi) div 2];
+ repeat
+ while LVCompareItems(List[Lo], Mid, Ascending, SortColumnID)*AscCorr < 0 do Inc(Lo);
+ while LVCompareItems(List[Hi], Mid, Ascending, SortColumnID)*AscCorr > 0 do Dec(Hi);
+ if Lo <= Hi then begin
+ x := List[Lo];
+ List[Lo] := List[Hi];
+ List[Hi] := x;
+ Inc(Lo);
+ Dec(Hi);
+ end;
+ until Lo > Hi;
+ if Hi > iLo then QuickSort(iLo, Hi);
+ if Lo < iHi then QuickSort(Lo, iHi);
+ end;
+
+begin
+ AscCorr := 2*Ord(Ascending) - 1;
+ QuickSort(0, List.Count - 1);
+end;
+
+(********************************************************************************************************************************)
+{$IFDEF CPU64}
+function CRC32(CRC: LongWord; Data: Pointer; DataSize: LongWord): LongWord;
+begin
+ Result := 0;
+end;
+{$ELSE}
+function CRC32(CRC: LongWord; Data: Pointer; DataSize: LongWord): LongWord; assembler;
+asm
+ AND EDX,EDX
+ JZ @Exit
+ AND ECX,ECX
+ JLE @Exit
+ PUSH EBX
+ PUSH EDI
+ XOR EBX,EBX
+ LEA EDI,CS:[OFFSET @CRC32]
+@Start: MOV BL,AL
+ SHR EAX,8
+ XOR BL,[EDX]
+ XOR EAX,[EDI + EBX * 4]
+ INC EDX
+ DEC ECX
+ JNZ @Start
+ POP EDI
+ POP EBX
+@Exit: RET
+ DB 0, 0, 0, 0, 0 // Align Table
+@CRC32: DD 000000000h, 077073096h, 0EE0E612Ch, 0990951BAh
+ DD 0076DC419h, 0706AF48Fh, 0E963A535h, 09E6495A3h
+ DD 00EDB8832h, 079DCB8A4h, 0E0D5E91Eh, 097D2D988h
+ DD 009B64C2Bh, 07EB17CBDh, 0E7B82D07h, 090BF1D91h
+ DD 01DB71064h, 06AB020F2h, 0F3B97148h, 084BE41DEh
+ DD 01ADAD47Dh, 06DDDE4EBh, 0F4D4B551h, 083D385C7h
+ DD 0136C9856h, 0646BA8C0h, 0FD62F97Ah, 08A65C9ECh
+ DD 014015C4Fh, 063066CD9h, 0FA0F3D63h, 08D080DF5h
+ DD 03B6E20C8h, 04C69105Eh, 0D56041E4h, 0A2677172h
+ DD 03C03E4D1h, 04B04D447h, 0D20D85FDh, 0A50AB56Bh
+ DD 035B5A8FAh, 042B2986Ch, 0DBBBC9D6h, 0ACBCF940h
+ DD 032D86CE3h, 045DF5C75h, 0DCD60DCFh, 0ABD13D59h
+ DD 026D930ACh, 051DE003Ah, 0C8D75180h, 0BFD06116h
+ DD 021B4F4B5h, 056B3C423h, 0CFBA9599h, 0B8BDA50Fh
+ DD 02802B89Eh, 05F058808h, 0C60CD9B2h, 0B10BE924h
+ DD 02F6F7C87h, 058684C11h, 0C1611DABh, 0B6662D3Dh
+ DD 076DC4190h, 001DB7106h, 098D220BCh, 0EFD5102Ah
+ DD 071B18589h, 006B6B51Fh, 09FBFE4A5h, 0E8B8D433h
+ DD 07807C9A2h, 00F00F934h, 09609A88Eh, 0E10E9818h
+ DD 07F6A0DBBh, 0086D3D2Dh, 091646C97h, 0E6635C01h
+ DD 06B6B51F4h, 01C6C6162h, 0856530D8h, 0F262004Eh
+ DD 06C0695EDh, 01B01A57Bh, 08208F4C1h, 0F50FC457h
+ DD 065B0D9C6h, 012B7E950h, 08BBEB8EAh, 0FCB9887Ch
+ DD 062DD1DDFh, 015DA2D49h, 08CD37CF3h, 0FBD44C65h
+ DD 04DB26158h, 03AB551CEh, 0A3BC0074h, 0D4BB30E2h
+ DD 04ADFA541h, 03DD895D7h, 0A4D1C46Dh, 0D3D6F4FBh
+ DD 04369E96Ah, 0346ED9FCh, 0AD678846h, 0DA60B8D0h
+ DD 044042D73h, 033031DE5h, 0AA0A4C5Fh, 0DD0D7CC9h
+ DD 05005713Ch, 0270241AAh, 0BE0B1010h, 0C90C2086h
+ DD 05768B525h, 0206F85B3h, 0B966D409h, 0CE61E49Fh
+ DD 05EDEF90Eh, 029D9C998h, 0B0D09822h, 0C7D7A8B4h
+ DD 059B33D17h, 02EB40D81h, 0B7BD5C3Bh, 0C0BA6CADh
+ DD 0EDB88320h, 09ABFB3B6h, 003B6E20Ch, 074B1D29Ah
+ DD 0EAD54739h, 09DD277AFh, 004DB2615h, 073DC1683h
+ DD 0E3630B12h, 094643B84h, 00D6D6A3Eh, 07A6A5AA8h
+ DD 0E40ECF0Bh, 09309FF9Dh, 00A00AE27h, 07D079EB1h
+ DD 0F00F9344h, 08708A3D2h, 01E01F268h, 06906C2FEh
+ DD 0F762575Dh, 0806567CBh, 0196C3671h, 06E6B06E7h
+ DD 0FED41B76h, 089D32BE0h, 010DA7A5Ah, 067DD4ACCh
+ DD 0F9B9DF6Fh, 08EBEEFF9h, 017B7BE43h, 060B08ED5h
+ DD 0D6D6A3E8h, 0A1D1937Eh, 038D8C2C4h, 04FDFF252h
+ DD 0D1BB67F1h, 0A6BC5767h, 03FB506DDh, 048B2364Bh
+ DD 0D80D2BDAh, 0AF0A1B4Ch, 036034AF6h, 041047A60h
+ DD 0DF60EFC3h, 0A867DF55h, 0316E8EEFh, 04669BE79h
+ DD 0CB61B38Ch, 0BC66831Ah, 0256FD2A0h, 05268E236h
+ DD 0CC0C7795h, 0BB0B4703h, 0220216B9h, 05505262Fh
+ DD 0C5BA3BBEh, 0B2BD0B28h, 02BB45A92h, 05CB36A04h
+ DD 0C2D7FFA7h, 0B5D0CF31h, 02CD99E8Bh, 05BDEAE1Dh
+ DD 09B64C2B0h, 0EC63F226h, 0756AA39Ch, 0026D930Ah
+ DD 09C0906A9h, 0EB0E363Fh, 072076785h, 005005713h
+ DD 095BF4A82h, 0E2B87A14h, 07BB12BAEh, 00CB61B38h
+ DD 092D28E9Bh, 0E5D5BE0Dh, 07CDCEFB7h, 00BDBDF21h
+ DD 086D3D2D4h, 0F1D4E242h, 068DDB3F8h, 01FDA836Eh
+ DD 081BE16CDh, 0F6B9265Bh, 06FB077E1h, 018B74777h
+ DD 088085AE6h, 0FF0F6A70h, 066063BCAh, 011010B5Ch
+ DD 08F659EFFh, 0F862AE69h, 0616BFFD3h, 0166CCF45h
+ DD 0A00AE278h, 0D70DD2EEh, 04E048354h, 03903B3C2h
+ DD 0A7672661h, 0D06016F7h, 04969474Dh, 03E6E77DBh
+ DD 0AED16A4Ah, 0D9D65ADCh, 040DF0B66h, 037D83BF0h
+ DD 0A9BCAE53h, 0DEBB9EC5h, 047B2CF7Fh, 030B5FFE9h
+ DD 0BDBDF21Ch, 0CABAC28Ah, 053B39330h, 024B4A3A6h
+ DD 0BAD03605h, 0CDD70693h, 054DE5729h, 023D967BFh
+ DD 0B3667A2Eh, 0C4614AB8h, 05D681B02h, 02A6F2B94h
+ DD 0B40BBE37h, 0C30C8EA1h, 05A05DF1Bh, 02D02EF8Dh
+ DD 074726F50h, 0736E6F69h, 0706F4320h, 067697279h
+ DD 028207468h, 031202963h, 020393939h, 048207962h
+ DD 06E656761h, 064655220h, 06E616D64h, 06FBBA36Eh
+end;
+{$ENDIF}
+(********************************************************************************************************************************)
+constructor THash_MD5.Create;
+begin
+ Init;
+end;
+
+function THash_MD5.DigestKey: string;
+type TCharArray = array[1..40] of char;
+ PCharArray = ^TCharArray;
+begin
+ Result := Copy(PCharArray(@FDigest)^, 1, 16);
+end;
+
+procedure THash_MD5.Init;
+begin
+ FillChar(FBuffer, SizeOf(FBuffer), 0);
+ FDigest[0] := $67452301;
+ FDigest[1] := $EFCDAB89;
+ FDigest[2] := $98BADCFE;
+ FDigest[3] := $10325476;
+ FDigest[4] := $C3D2E1F0;
+ FCount := 0;
+end;
+
+{$R-}
+procedure THash_MD5.Done;
+var
+ I: Integer;
+ S: Int64;
+begin
+ try
+ I := FCount and $3F;
+ FBuffer[I] := $80;
+ Inc(I);
+ if I > 64 - 8 then
+ begin
+ FillChar(FBuffer[I], 64 - I, 0);
+ Transform(@FBuffer);
+ I := 0;
+ end;
+ FillChar(FBuffer[I], 64 - I, 0);
+ S := Int64(FCount) * 8;
+ Move(S, FBuffer[64 - 8], SizeOf(S));
+ Transform(@FBuffer);
+ FillChar(FBuffer, SizeOf(FBuffer), 0);
+ except
+ end;
+end;
+
+procedure THash_MD5.Calc(const Data; DataSize: Integer);
+var
+ Index: Integer;
+ P: PChar;
+begin
+ if DataSize <= 0 then Exit;
+ Index := FCount and $3F;
+ Inc(FCount, DataSize);
+ if Index > 0 then
+ begin
+ if DataSize < 64 - Index then
+ begin
+ Move(Data, FBuffer[Index], DataSize);
+ Exit;
+ end;
+ Move(Data, FBuffer[Index], 64 - Index);
+ Transform(@FBuffer);
+ Index := 64 - Index;
+ Dec(DataSize, Index);
+ end;
+ P := @TByteArray(Data)[Index];
+ Inc(Index, DataSize and not $3F);
+ while DataSize >= 64 do
+ begin
+ Transform(Pointer(P));
+ Inc(P, 64);
+ Dec(DataSize, 64);
+ end;
+ Move(TByteArray(Data)[Index], FBuffer, DataSize);
+end;
+{$R+}
+
+function THash_MD5.GetKeyStrH: string;
+const HexTable = '0123456789ABCDEF';
+var i: integer;
+ Value: string;
+begin
+ Result := '';
+ Value := DigestKey;
+ if Value = '' then Exit;
+ for i := 1 to Length(Value) do
+ Result := Result + HexTable[Byte(Value[i]) shr 4 + 1] + HexTable[Byte(Value[i]) and $F + 1];
+end;
+
+{$IFDEF CPU64}
+function THash_MD5.TestVector: Pointer;
+begin
+ Result := nil;
+end;
+{$ELSE}
+function THash_MD5.TestVector: Pointer;
+asm
+ MOV EAX,OFFSET @Vector
+ RET
+@Vector: DB 03Eh,0D8h,034h,08Ch,0D2h,0A4h,045h,0D6h
+ DB 075h,05Dh,04Bh,0C9h,0FEh,0DCh,0C2h,0C6h
+end;
+{$ENDIF}
+
+{$Q-}
+procedure THash_MD5.Transform(Buffer: PIntArray);
+var
+ A, B, C, D: LongWord;
+begin
+ A := FDigest[0];
+ B := FDigest[1];
+ C := FDigest[2];
+ D := FDigest[3];
+
+ Inc(A, Buffer[ 0] + $D76AA478 + (D xor (B and (C xor D)))); A := A shl 7 or A shr 25 + B;
+ Inc(D, Buffer[ 1] + $E8C7B756 + (C xor (A and (B xor C)))); D := D shl 12 or D shr 20 + A;
+ Inc(C, Buffer[ 2] + $242070DB + (B xor (D and (A xor B)))); C := C shl 17 or C shr 15 + D;
+ Inc(B, Buffer[ 3] + $C1BDCEEE + (A xor (C and (D xor A)))); B := B shl 22 or B shr 10 + C;
+ Inc(A, Buffer[ 4] + $F57C0FAF + (D xor (B and (C xor D)))); A := A shl 7 or A shr 25 + B;
+ Inc(D, Buffer[ 5] + $4787C62A + (C xor (A and (B xor C)))); D := D shl 12 or D shr 20 + A;
+ Inc(C, Buffer[ 6] + $A8304613 + (B xor (D and (A xor B)))); C := C shl 17 or C shr 15 + D;
+ Inc(B, Buffer[ 7] + $FD469501 + (A xor (C and (D xor A)))); B := B shl 22 or B shr 10 + C;
+ Inc(A, Buffer[ 8] + $698098D8 + (D xor (B and (C xor D)))); A := A shl 7 or A shr 25 + B;
+ Inc(D, Buffer[ 9] + $8B44F7AF + (C xor (A and (B xor C)))); D := D shl 12 or D shr 20 + A;
+ Inc(C, Buffer[10] + $FFFF5BB1 + (B xor (D and (A xor B)))); C := C shl 17 or C shr 15 + D;
+ Inc(B, Buffer[11] + $895CD7BE + (A xor (C and (D xor A)))); B := B shl 22 or B shr 10 + C;
+ Inc(A, Buffer[12] + $6B901122 + (D xor (B and (C xor D)))); A := A shl 7 or A shr 25 + B;
+ Inc(D, Buffer[13] + $FD987193 + (C xor (A and (B xor C)))); D := D shl 12 or D shr 20 + A;
+ Inc(C, Buffer[14] + $A679438E + (B xor (D and (A xor B)))); C := C shl 17 or C shr 15 + D;
+ Inc(B, Buffer[15] + $49B40821 + (A xor (C and (D xor A)))); B := B shl 22 or B shr 10 + C;
+
+ Inc(A, Buffer[ 1] + $F61E2562 + (C xor (D and (B xor C)))); A := A shl 5 or A shr 27 + B;
+ Inc(D, Buffer[ 6] + $C040B340 + (B xor (C and (A xor B)))); D := D shl 9 or D shr 23 + A;
+ Inc(C, Buffer[11] + $265E5A51 + (A xor (B and (D xor A)))); C := C shl 14 or C shr 18 + D;
+ Inc(B, Buffer[ 0] + $E9B6C7AA + (D xor (A and (C xor D)))); B := B shl 20 or B shr 12 + C;
+ Inc(A, Buffer[ 5] + $D62F105D + (C xor (D and (B xor C)))); A := A shl 5 or A shr 27 + B;
+ Inc(D, Buffer[10] + $02441453 + (B xor (C and (A xor B)))); D := D shl 9 or D shr 23 + A;
+ Inc(C, Buffer[15] + $D8A1E681 + (A xor (B and (D xor A)))); C := C shl 14 or C shr 18 + D;
+ Inc(B, Buffer[ 4] + $E7D3FBC8 + (D xor (A and (C xor D)))); B := B shl 20 or B shr 12 + C;
+ Inc(A, Buffer[ 9] + $21E1CDE6 + (C xor (D and (B xor C)))); A := A shl 5 or A shr 27 + B;
+ Inc(D, Buffer[14] + $C33707D6 + (B xor (C and (A xor B)))); D := D shl 9 or D shr 23 + A;
+ Inc(C, Buffer[ 3] + $F4D50D87 + (A xor (B and (D xor A)))); C := C shl 14 or C shr 18 + D;
+ Inc(B, Buffer[ 8] + $455A14ED + (D xor (A and (C xor D)))); B := B shl 20 or B shr 12 + C;
+ Inc(A, Buffer[13] + $A9E3E905 + (C xor (D and (B xor C)))); A := A shl 5 or A shr 27 + B;
+ Inc(D, Buffer[ 2] + $FCEFA3F8 + (B xor (C and (A xor B)))); D := D shl 9 or D shr 23 + A;
+ Inc(C, Buffer[ 7] + $676F02D9 + (A xor (B and (D xor A)))); C := C shl 14 or C shr 18 + D;
+ Inc(B, Buffer[12] + $8D2A4C8A + (D xor (A and (C xor D)))); B := B shl 20 or B shr 12 + C;
+
+ Inc(A, Buffer[ 5] + $FFFA3942 + (B xor C xor D)); A := A shl 4 or A shr 28 + B;
+ Inc(D, Buffer[ 8] + $8771F681 + (A xor B xor C)); D := D shl 11 or D shr 21 + A;
+ Inc(C, Buffer[11] + $6D9D6122 + (D xor A xor B)); C := C shl 16 or C shr 16 + D;
+ Inc(B, Buffer[14] + $FDE5380C + (C xor D xor A)); B := B shl 23 or B shr 9 + C;
+ Inc(A, Buffer[ 1] + $A4BEEA44 + (B xor C xor D)); A := A shl 4 or A shr 28 + B;
+ Inc(D, Buffer[ 4] + $4BDECFA9 + (A xor B xor C)); D := D shl 11 or D shr 21 + A;
+ Inc(C, Buffer[ 7] + $F6BB4B60 + (D xor A xor B)); C := C shl 16 or C shr 16 + D;
+ Inc(B, Buffer[10] + $BEBFBC70 + (C xor D xor A)); B := B shl 23 or B shr 9 + C;
+ Inc(A, Buffer[13] + $289B7EC6 + (B xor C xor D)); A := A shl 4 or A shr 28 + B;
+ Inc(D, Buffer[ 0] + $EAA127FA + (A xor B xor C)); D := D shl 11 or D shr 21 + A;
+ Inc(C, Buffer[ 3] + $D4EF3085 + (D xor A xor B)); C := C shl 16 or C shr 16 + D;
+ Inc(B, Buffer[ 6] + $04881D05 + (C xor D xor A)); B := B shl 23 or B shr 9 + C;
+ Inc(A, Buffer[ 9] + $D9D4D039 + (B xor C xor D)); A := A shl 4 or A shr 28 + B;
+ Inc(D, Buffer[12] + $E6DB99E5 + (A xor B xor C)); D := D shl 11 or D shr 21 + A;
+ Inc(C, Buffer[15] + $1FA27CF8 + (D xor A xor B)); C := C shl 16 or C shr 16 + D;
+ Inc(B, Buffer[ 2] + $C4AC5665 + (C xor D xor A)); B := B shl 23 or B shr 9 + C;
+
+ Inc(A, Buffer[ 0] + $F4292244 + (C xor (B or not D))); A := A shl 6 or A shr 26 + B;
+ Inc(D, Buffer[ 7] + $432AFF97 + (B xor (A or not C))); D := D shl 10 or D shr 22 + A;
+ Inc(C, Buffer[14] + $AB9423A7 + (A xor (D or not B))); C := C shl 15 or C shr 17 + D;
+ Inc(B, Buffer[ 5] + $FC93A039 + (D xor (C or not A))); B := B shl 21 or B shr 11 + C;
+ Inc(A, Buffer[12] + $655B59C3 + (C xor (B or not D))); A := A shl 6 or A shr 26 + B;
+ Inc(D, Buffer[ 3] + $8F0CCC92 + (B xor (A or not C))); D := D shl 10 or D shr 22 + A;
+ Inc(C, Buffer[10] + $FFEFF47D + (A xor (D or not B))); C := C shl 15 or C shr 17 + D;
+ Inc(B, Buffer[ 1] + $85845DD1 + (D xor (C or not A))); B := B shl 21 or B shr 11 + C;
+ Inc(A, Buffer[ 8] + $6FA87E4F + (C xor (B or not D))); A := A shl 6 or A shr 26 + B;
+ Inc(D, Buffer[15] + $FE2CE6E0 + (B xor (A or not C))); D := D shl 10 or D shr 22 + A;
+ Inc(C, Buffer[ 6] + $A3014314 + (A xor (D or not B))); C := C shl 15 or C shr 17 + D;
+ Inc(B, Buffer[13] + $4E0811A1 + (D xor (C or not A))); B := B shl 21 or B shr 11 + C;
+ Inc(A, Buffer[ 4] + $F7537E82 + (C xor (B or not D))); A := A shl 6 or A shr 26 + B;
+ Inc(D, Buffer[11] + $BD3AF235 + (B xor (A or not C))); D := D shl 10 or D shr 22 + A;
+ Inc(C, Buffer[ 2] + $2AD7D2BB + (A xor (D or not B))); C := C shl 15 or C shr 17 + D;
+ Inc(B, Buffer[ 9] + $EB86D391 + (D xor (C or not A))); B := B shl 21 or B shr 11 + C;
+
+ Inc(FDigest[0], A);
+ Inc(FDigest[1], B);
+ Inc(FDigest[2], C);
+ Inc(FDigest[3], D);
+end;
+{$Q+}
+(********************************************************************************************************************************)
+
+procedure signal_proc(signal_number: integer); cdecl;
+var pid, status: integer;
+begin
+// !!!!!!!!!! Warning
+// There should be no debug outputs in this function because it probably cause program freezes after fork
+// I mean REALLY NO outputs to console
+
+// DebugMsg(['SIGCHLD signal received']);
+// DebugMsg(['Signal received: ', signal_number]);
+// DebugMsg(['*** Signal received: ', signal_number, ' = ', GetSignalString(signal_number)]);
+ case signal_number of
+{ SIGUSR1: begin
+ DebugMsg(['begin wait']);
+ wait(@status);
+ DebugMsg(['end wait']);
+ ChildExitStatus := status;
+ end;}
+ SIGCHLD, SIGUSR1: begin
+// DebugMsg(['begin wait']);
+// wait(@status);
+ pid := waitpid(-1, @status, WNOHANG);
+// DebugMsg(['**** waitpid result: pid = ', pid, ', status = ', status]);
+// DebugMsg(['end wait']);
+ if signal_number = SIGUSR1 then ChildExitStatus := status;
+ end;
+ end;
+end;
+
+procedure SetupSignals;
+var sigchld_action: __sigaction;
+begin
+ Libc.memset(@sigchld_action, 0, SizeOf(__sigaction));
+ sigchld_action.__sigaction_handler := @signal_proc;
+ sigaction(SIGUSR1, @sigchld_action, nil);
+ sigaction(SIGCHLD, @sigchld_action, nil);
+end;
+
+procedure SetupColors;
+var Color: TGDKColor;
+ LocalListView: TGTKListView;
+begin
+ LocalListView := TGTKListView.Create(Application);
+ try
+ if ConfNormalItemDefaultColors then begin
+ NormalItemGDKColor := GetDefaultTextColor(LocalListView, GTK_STATE_NORMAL);
+ NormalItemGDKBackground := GetDefaultBaseColor(LocalListView, GTK_STATE_NORMAL);
+ end else begin
+ StringToGDKColor(ConfNormalItemFGColor, Color);
+ NormalItemGDKColor := GDKColorToPGdkColor(Color);
+ StringToGDKColor(ConfNormalItemBGColor, Color);
+ NormalItemGDKBackground := GDKColorToPGdkColor(Color);
+ end;
+ if ConfCursorDefaultColors then begin
+ ActiveItemGDKColor := GetDefaultTextColor(LocalListView, GTK_STATE_SELECTED);
+ ActiveItemGDKBackground := GetDefaultBaseColor(LocalListView, GTK_STATE_SELECTED);
+ end else begin
+ StringToGDKColor(ConfActiveItemFGColor, Color);
+ ActiveItemGDKColor := GDKColorToPGdkColor(Color);
+ StringToGDKColor(ConfActiveItemBGColor, Color);
+ ActiveItemGDKBackground := GDKColorToPGdkColor(Color);
+ end;
+ if ConfInactiveItemDefaultColors then begin
+ InactiveItemGDKColor := GetDefaultTextColor(LocalListView, GTK_STATE_ACTIVE);
+ InactiveItemGDKBackground := GetDefaultBaseColor(LocalListView, GTK_STATE_ACTIVE);
+ end else begin
+ StringToGDKColor(ConfInactiveItemFGColor, Color);
+ InactiveItemGDKColor := GDKColorToPGdkColor(Color);
+ StringToGDKColor(ConfInactiveItemBGColor, Color);
+ InactiveItemGDKBackground := GDKColorToPGdkColor(Color);
+ end;
+ StringToGDKColor(ConfSelectedItemFGColor, Color);
+ SelectedItemGDKColor := GDKColorToPGdkColor(Color);
+ StringToGDKColor(ConfDotFileItemFGColor, Color);
+ DotFileItemGDKColor := GDKColorToPGdkColor(Color);
+ StringToGDKColor(ConfLinkItemFGColor, Color);
+ LinkItemGDKColor := GDKColorToPGdkColor(Color);
+ try
+ InactiveItemBGColorNum := $FF + (InactiveItemGDKBackground^.red div 256) shl 24
+ + (InactiveItemGDKBackground^.green div 256) shl 16
+ + (InactiveItemGDKBackground^.blue div 256) shl 8;
+ except InactiveItemBGColorNum := $D0D0D0FF; end;
+ finally
+ LocalListView.Free;
+ end;
+end;
+
+procedure ReportGTKVersion;
+begin
+ if Application.GTKVersion_2_8_0_Up then DebugMsg(['Using GTK+ version >= 2.8.0']) else
+ if Application.GTKVersion_2_6_0_Up then DebugMsg(['Using GTK+ version >= 2.6.0']) else
+ if Application.GTKVersion_2_4_0_Up then DebugMsg(['Using GTK+ version >= 2.4.0']) else
+ if Application.GTKVersion_2_2_0_Up then DebugMsg(['Using GTK+ version >= 2.2.0']) else
+ if Application.GTKVersion_2_0_5_Up then DebugMsg(['Using GTK+ version >= 2.0.5']) else
+ DebugMsg(['Using GTK+ version < 2.0.5']);
+end;
+
+
+(********************************************************************************************************************************)
+var InternalLockVar: integer;
+procedure InternalLock;
+begin
+ Inc(InternalLockVar);
+ DebugMsg(['Lock']);
+end;
+
+procedure InternalUnLock;
+begin
+ Dec(InternalLockVar);
+ if InternalLockVar < 0 then InternalLockVar := 0;
+ DebugMsg(['Unlock']);
+end;
+
+function InternalLockUnlocked: boolean;
+begin
+ Result := InternalLockVar = 0;
+end;
+
+procedure InternalLockInit(Locked: boolean);
+begin
+ InternalLockVar := Ord(Locked);
+end;
+
+
+(********************************************************************************************************************************)
+procedure GetFirstLastPanelColumn(var FirstColumn, LastColumn: integer);
+var i: integer;
+begin
+ FirstColumn := 1;
+ LastColumn := ConstNumPanelColumns;
+ for i := 1 to ConstNumPanelColumns do
+ if ConfColumnVisible[i] then begin
+ FirstColumn := i;
+ Break;
+ end;
+ for i := ConstNumPanelColumns downto 1 do
+ if ConfColumnVisible[i] then begin
+ LastColumn := i;
+ Break;
+ end;
+end;
+
+(********************************************************************************************************************************)
+
+
+
+
+(********************************************************************************************************************************)
+{$IFDEF __FPC__}
+function StrToDateDef(const S: string; const Default: TDateTime): TDateTime;
+begin
+ try
+ Result := StrToDate(S);
+ except
+ Result := Default;
+ end;
+end;
+
+
+function UnixToDateTime(const AValue: Int64): TDateTime;
+begin
+ Result := AValue / SecsPerDay + UnixDateDelta;
+end;
+{$ENDIF}
+
+(********************************************************************************************************************************)
+procedure SaveItemToHistory(s: string; History: TStringList);
+var i: integer;
+begin
+ s:= Trim(s);
+ if Length(s) > 0 then begin
+ if History.IndexOf(s) > -1 then
+ History.Delete(History.IndexOf(s));
+ History.Insert(0, s);
+ if History.Count > ConfNumHistoryItems then
+ for i := History.Count downto ConfNumHistoryItems do
+ History.Delete(i - 1);
+ end;
+end;
+
+
+(********************************************************************************************************************************)
+
+
+
+
+
+
+
+
+
+
+initialization
+ InternalLockInit(True);
+ SetupSignals;
+ AppPath := IncludeTrailingPathDelimiter(GetHomePath);
+ IconPath := IncludeTrailingPathDelimiter(GetHomePath);
+end.