Quick.Commons.pas 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998
  1. { ***************************************************************************
  2. Copyright (c) 2016-2018 Kike Pérez
  3. Unit : Quick.Commons
  4. Description : Common functions
  5. Author : Kike Pérez
  6. Version : 1.4
  7. Created : 14/07/2017
  8. Modified : 16/05/2018
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.Commons;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. Classes,
  26. SysUtils,
  27. Types,
  28. {$IFDEF MSWINDOWS}
  29. Windows,
  30. ShlObj,
  31. Registry,
  32. {$ENDIF MSWINDOWS}
  33. {$IFDEF FPC}
  34. Quick.Files,
  35. {$IFDEF LINUX}
  36. FileInfo,
  37. {$ENDIF}
  38. {$ELSE}
  39. IOUtils,
  40. {$ENDIF}
  41. DateUtils;
  42. type
  43. TLogEventType = (etInfo, etSuccess, etWarning, etError, etDebug, etTrace);
  44. TLogVerbose = set of TLogEventType;
  45. const
  46. LOG_ONLYERRORS = [etInfo,etError];
  47. LOG_ERRORSANDWARNINGS = [etInfo,etWarning,etError];
  48. LOG_TRACE = [etInfo,etError,etWarning,etTrace];
  49. LOG_ALL = [etInfo,etSuccess,etWarning,etError,etTrace];
  50. LOG_DEBUG = [etInfo,etSuccess,etWarning,etError,etDebug];
  51. {$IFDEF DELPHIXE7_UP}
  52. EventStr : array of string = ['INFO','SUCC','WARN','ERROR','DEBUG','TRACE'];
  53. {$ELSE}
  54. EventStr : array[0..5] of string = ('INFO','SUCC','WARN','ERROR','DEBUG','TRACE');
  55. {$ENDIF}
  56. type
  57. TPasswordComplexity = set of (pfIncludeNumbers,pfIncludeSigns);
  58. {$IFDEF MSWINDOWS}
  59. TEnvironmentPath = record
  60. EXEPATH : string;
  61. WINDOWS : string;
  62. SYSTEM : string;
  63. PROGRAMFILES : string;
  64. COMMONFILES : string;
  65. HOMEDRIVE : string;
  66. TEMP : string;
  67. USERPROFILE : string;
  68. INSTDRIVE : string;
  69. DESKTOP : string;
  70. STARTMENU : string;
  71. DESKTOP_ALLUSERS : string;
  72. STARTMENU_ALLUSERS : string;
  73. STARTUP : string;
  74. APPDATA : String;
  75. PROGRAMDATA : string;
  76. ALLUSERSPROFILE : string;
  77. end;
  78. {$ENDIF MSWINDOWS}
  79. {$IFNDEF FPC}
  80. TFileHelper = record helper for TFile
  81. {$IFDEF MSWINDOWS}
  82. class function IsInUse(const FileName : string) : Boolean; static;
  83. {$ENDIF}
  84. class function GetSize(const FileName: String): Int64; static;
  85. end;
  86. TDirectoryHelper = record helper for TDirectory
  87. class function GetSize(const Path: String): Int64; static;
  88. end;
  89. {$ENDIF}
  90. {$IFDEF FPC}
  91. {$IFDEF LINUX}
  92. UINT = cardinal;
  93. {$ENDIF}
  94. PLASTINPUTINFO = ^LASTINPUTINFO;
  95. tagLASTINPUTINFO = record
  96. cbSize: UINT;
  97. dwTime: DWORD;
  98. end;
  99. LASTINPUTINFO = tagLASTINPUTINFO;
  100. TLastInputInfo = LASTINPUTINFO;
  101. type
  102. TCmdLineSwitchType = (clstValueNextParam, clstValueAppended);
  103. TCmdLineSwitchTypes = set of TCmdLineSwitchType;
  104. {$ENDIF}
  105. TCounter = record
  106. private
  107. fMaxValue : Integer;
  108. fCurrentValue : Integer;
  109. public
  110. property MaxValue : Integer read fMaxValue;
  111. procedure Init(aMaxValue : Integer);
  112. function Count : Integer;
  113. function CountIs(aValue : Integer) : Boolean;
  114. function Check : Boolean;
  115. procedure Reset;
  116. end;
  117. TTimeCounter = record
  118. private
  119. fCurrentTime : TDateTime;
  120. fDoneEvery : Integer;
  121. public
  122. property DoneEvery : Integer read fDoneEvery;
  123. procedure Init(MillisecondsToReach : Integer);
  124. function Check : Boolean;
  125. procedure Reset;
  126. end;
  127. EEnvironmentPath = class(Exception);
  128. EShellError = class(Exception);
  129. //generates a random password with complexity options
  130. function RandomPassword(const PasswordLength : Integer; Complexity : TPasswordComplexity = [pfIncludeNumbers,pfIncludeSigns]) : string;
  131. //extracts file extension from a filename
  132. function ExtractFileNameWithoutExt(const FileName: string): string;
  133. //converts a Unix path to Windows path
  134. function UnixToWindowsPath(const UnixPath: string): string;
  135. //converts a Windows path to Unix path
  136. function WindowsToUnixPath(const WindowsPath: string): string;
  137. //corrects malformed urls
  138. function CorrectURLPath(cUrl : string) : string;
  139. {$IFDEF MSWINDOWS}
  140. //get typical environment paths as temp, desktop, etc
  141. procedure GetEnvironmentPaths;
  142. function GetSpecialFolderPath(folderID : Integer) : string;
  143. //checks if running on a 64bit OS
  144. function Is64bitOS : Boolean;
  145. //checks if is a console app
  146. function IsConsole : Boolean;
  147. //checks if compiled in debug mode
  148. {$ENDIF}
  149. function IsDebug : Boolean;
  150. {$IFDEF MSWINDOWS}
  151. //checks if running as a service
  152. function IsService : Boolean;
  153. //gets number of seconds without user interaction (mouse, keyboard)
  154. function SecondsIdle: DWord;
  155. //frees process memory not needed
  156. procedure FreeUnusedMem;
  157. //changes screen resolution
  158. function SetScreenResolution(Width, Height: integer): Longint;
  159. {$ENDIF MSWINDOWS}
  160. //returns last day of current month
  161. function LastDayCurrentMonth: TDateTime;
  162. {$IFDEF FPC}
  163. function DateTimeInRange(ADateTime: TDateTime; AStartDateTime, AEndDateTime: TDateTime; aInclusive: Boolean = True): Boolean;
  164. {$ENDIF}
  165. //checks if two datetimes are in same day
  166. function IsSameDay(cBefore, cNow : TDateTime) : Boolean;
  167. //returns n times a char
  168. function FillStr(const C : Char; const Count : Byte) : string;
  169. //checks if string exists in array of string
  170. function StrInArray(const aValue : string; const aInArray : array of string) : Boolean;
  171. //returns a number leading zero
  172. function Zeroes(const Number, Len : Int64) : string;
  173. //converts a number to thousand delimeter string
  174. function NumberToStr(const Number : Int64) : string;
  175. //returns n spaces
  176. function Spaces(const Count : Integer) : string;
  177. //returns current date as a string
  178. function NowStr : string;
  179. //returns a new GUID as string
  180. function NewGuidStr : string;
  181. //compare a string with a wildcard pattern (? or *)
  182. function IsLike(cText, Pattern: string) : Boolean;
  183. //Upper case for first letter
  184. function Capitalize(s: string): string;
  185. function CapitalizeWords(s: string): string;
  186. //returns current logged user
  187. function GetLoggedUserName : string;
  188. //returns computer name
  189. function GetComputerName : string;
  190. //Changes incorrect delims in path
  191. function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
  192. //Removes last segment of a path
  193. function RemoveLastPathSegment(cDir : string) : string;
  194. //finds swith in commandline params
  195. function ParamFindSwitch(const Switch : string) : Boolean;
  196. //gets value for a switch if exists
  197. function ParamGetSwitch(const Switch : string; var cvalue : string) : Boolean;
  198. //returns app name (filename based)
  199. function GetAppName : string;
  200. //returns app version (major & minor)
  201. function GetAppVersionStr: string;
  202. //returns app version full (major, minor, release & compiled)
  203. function GetAppVersionFullStr: string;
  204. //UTC DateTime to Local DateTime
  205. function UTCToLocalTime(GMTTime: TDateTime): TDateTime;
  206. //Local DateTime to UTC DateTime
  207. function LocalTimeToUTC(LocalTime : TDateTime): TDateTime;
  208. //return GTM time string
  209. function DateTimeToGMT(aDate : TDateTime) : string;
  210. //count number of digits of a Integer
  211. function CountDigits(anInt: Cardinal): Cardinal; inline;
  212. //save stream to file
  213. procedure SaveStreamToFile(stream : TStream; const filename : string);
  214. {$IFDEF MSWINDOWS}
  215. //process messages on console applications
  216. procedure ProcessMessages;
  217. //get last error message
  218. function GetLastOSError : String;
  219. {$ENDIF}
  220. {$IF DEFINED(FPC) AND DEFINED(MSWINDOWS)}
  221. function GetLastInputInfo(var plii: TLastInputInfo): BOOL;stdcall; external 'user32' name 'GetLastInputInfo';
  222. {$ENDIF}
  223. {$IFDEF MSWINDOWS}
  224. var
  225. path : TEnvironmentPath;
  226. {$ENDIF}
  227. implementation
  228. {TFileHelper}
  229. {$IFNDEF FPC}
  230. {$IFDEF MSWINDOWS}
  231. class function TFileHelper.IsInUse(const FileName : string) : Boolean;
  232. var
  233. HFileRes: HFILE;
  234. begin
  235. Result := False;
  236. if not FileExists(FileName) then Exit;
  237. try
  238. HFileRes := CreateFile(PChar(FileName)
  239. ,GENERIC_READ or GENERIC_WRITE
  240. ,0
  241. ,nil
  242. ,OPEN_EXISTING
  243. ,FILE_ATTRIBUTE_NORMAL
  244. ,0);
  245. Result := (HFileRes = INVALID_HANDLE_VALUE);
  246. if not(Result) then begin
  247. CloseHandle(HFileRes);
  248. end;
  249. except
  250. Result := True;
  251. end;
  252. end;
  253. {$ENDIF}
  254. {$IFDEF MSWINDOWS}
  255. class function TFileHelper.GetSize(const FileName: String): Int64;
  256. var
  257. info: TWin32FileAttributeData;
  258. begin
  259. Result := -1;
  260. if not GetFileAttributesEx(PWideChar(FileName), GetFileExInfoStandard, @info) then Exit;
  261. Result := Int64(info.nFileSizeLow) or Int64(info.nFileSizeHigh shl 32);
  262. end;
  263. {$ELSE}
  264. class function TFileHelper.GetSize(const FileName: String): Int64;
  265. var
  266. sr : TSearchRec;
  267. begin
  268. if FindFirst(fileName, faAnyFile, sr ) = 0 then Result := sr.Size
  269. else Result := -1;
  270. end;
  271. {$ENDIF}
  272. {TDirectoryHelper}
  273. class function TDirectoryHelper.GetSize(const Path: String): Int64;
  274. var
  275. filename : string;
  276. begin
  277. Result := -1;
  278. for filename in TDirectory.GetFiles(Path) do
  279. begin
  280. Result := Result + TFile.GetSize(filename);
  281. end;
  282. end;
  283. {$ENDIF}
  284. {other functions}
  285. function RandomPassword(const PasswordLength : Integer; Complexity : TPasswordComplexity = [pfIncludeNumbers,pfIncludeSigns]) : string;
  286. const
  287. PassAlpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  288. PassSigns = '@!&$';
  289. PassNumbers = '1234567890';
  290. var
  291. MinNumbers,
  292. MinSigns : Integer;
  293. NumNumbers,
  294. NumSigns : Integer;
  295. begin
  296. Result := '';
  297. Randomize;
  298. //fill all alfa
  299. repeat
  300. Result := Result + PassAlpha[Random(Length(PassAlpha))+1];
  301. until (Length(Result) = PasswordLength);
  302. //checks if need include numbers
  303. if pfIncludeNumbers in Complexity then
  304. begin
  305. MinNumbers := Round(PasswordLength / 10 * 2);
  306. NumNumbers := 0;
  307. if MinNumbers = 0 then MinNumbers := 1;
  308. repeat
  309. Result[Random(PasswordLength)+1] := PassNumbers[Random(Length(PassNumbers))+1];
  310. Inc(NumNumbers);
  311. until NumNumbers = MinNumbers;
  312. end;
  313. //checks if need include signs
  314. if pfIncludeNumbers in Complexity then
  315. begin
  316. MinSigns := Round(PasswordLength / 10 * 1);
  317. NumSigns := 0;
  318. if MinSigns = 0 then MinSigns := 1;
  319. repeat
  320. Result[Random(PasswordLength)+1] := PassSigns[Random(Length(PassSigns))+1];
  321. Inc(NumSigns);
  322. until NumSigns = MinSigns;
  323. end;
  324. end;
  325. function ExtractFileNameWithoutExt(const FileName: string): string;
  326. begin
  327. Result := TPath.GetFileNameWithoutExtension(FileName);
  328. end;
  329. function UnixToWindowsPath(const UnixPath: string): string;
  330. begin
  331. Result := StringReplace(UnixPath, '/', '\',[rfReplaceAll, rfIgnoreCase]);
  332. end;
  333. function WindowsToUnixPath(const WindowsPath: string): string;
  334. begin
  335. Result := StringReplace(WindowsPath, '\', '/',[rfReplaceAll, rfIgnoreCase]);
  336. end;
  337. function CorrectURLPath(cUrl : string) : string;
  338. var
  339. nurl : string;
  340. begin
  341. nurl := WindowsToUnixPath(cUrl);
  342. nurl := StringReplace(nurl,'//','/',[rfReplaceAll]);
  343. Result := StringReplace(nurl,' ','%20',[rfReplaceAll]);
  344. //TNetEncoding.Url.Encode()
  345. end;
  346. {$IFDEF MSWINDOWS}
  347. procedure GetEnvironmentPaths;
  348. begin
  349. //gets path
  350. path.EXEPATH := TPath.GetDirectoryName(ParamStr(0));
  351. path.WINDOWS := SysUtils.GetEnvironmentVariable('windir');
  352. path.PROGRAMFILES := SysUtils.GetEnvironmentVariable('ProgramFiles');
  353. path.COMMONFILES := SysUtils.GetEnvironmentVariable('CommonProgramFiles(x86)');
  354. path.HOMEDRIVE := SysUtils.GetEnvironmentVariable('SystemDrive');
  355. path.USERPROFILE := SysUtils.GetEnvironmentVariable('USERPROFILE');
  356. path.PROGRAMDATA := SysUtils.GetEnvironmentVariable('ProgramData');
  357. path.ALLUSERSPROFILE := SysUtils.GetEnvironmentVariable('AllUsersProfile');
  358. path.INSTDRIVE := path.HOMEDRIVE;
  359. path.TEMP := SysUtils.GetEnvironmentVariable('TEMP');
  360. path.SYSTEM := GetSpecialFolderPath(CSIDL_SYSTEM);
  361. path.APPDATA:=GetSpecialFolderPath(CSIDL_APPDATA);
  362. //these paths fail if user is SYSTEM
  363. try
  364. path.DESKTOP := GetSpecialFolderPath(CSIDL_DESKTOP);
  365. path.DESKTOP_ALLUSERS := GetSpecialFolderPath(CSIDL_COMMON_DESKTOPDIRECTORY);
  366. path.STARTMENU:=GetSpecialFolderPath(CSIDL_PROGRAMS);
  367. path.STARTMENU_ALLUSERS:=GetSpecialFolderPath(CSIDL_COMMON_PROGRAMS);
  368. path.STARTMENU_ALLUSERS := path.STARTMENU;
  369. path.STARTUP:=GetSpecialFolderPath(CSIDL_STARTUP);
  370. except
  371. //
  372. end;
  373. end;
  374. function GetSpecialFolderPath(folderID : Integer) : string;
  375. var
  376. ppidl: PItemIdList;
  377. begin
  378. SHGetSpecialFolderLocation(0, folderID, ppidl);
  379. SetLength(Result, MAX_PATH);
  380. if not SHGetPathFromIDList(ppidl,{$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}) then
  381. begin
  382. raise EShellError.create(Format('GetSpecialFolderPath: Invalid PIPL (%d)',[folderID]));
  383. end;
  384. SetLength(Result, lStrLen({$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}));
  385. end;
  386. function Is64bitOS : Boolean;
  387. begin
  388. {$IFDEF WIN64}
  389. Result := True;
  390. {$ELSE}
  391. Result := False;
  392. {$ENDIF WIN64}
  393. end;
  394. function IsConsole: Boolean;
  395. begin
  396. {$IFDEF CONSOLE}
  397. Result := True;
  398. {$ELSE}
  399. Result := False;
  400. {$ENDIF CONSOLE}
  401. end;
  402. {$ENDIF}
  403. function IsDebug: Boolean;
  404. begin
  405. {$IFDEF DEBUG}
  406. Result := True;
  407. {$ELSE}
  408. Result := False;
  409. {$ENDIF DEBUG}
  410. end;
  411. {$IFDEF MSWINDOWS}
  412. function IsService : Boolean;
  413. begin
  414. //only working with my Quick.AppService unit
  415. try
  416. Result := (IsConsole) and (GetStdHandle(STD_OUTPUT_HANDLE) = 0);
  417. except
  418. Result := False;
  419. end;
  420. end;
  421. function SecondsIdle: DWord;
  422. var
  423. liInfo: TLastInputInfo;
  424. begin
  425. liInfo.cbSize := SizeOf(TLastInputInfo) ;
  426. GetLastInputInfo(liInfo) ;
  427. Result := (GetTickCount - liInfo.dwTime) DIV 1000;
  428. end;
  429. procedure FreeUnusedMem;
  430. begin
  431. if Win32Platform = VER_PLATFORM_WIN32_NT then SetProcessWorkingSetSize(GetCurrentProcess, $FFFFFFFF, $FFFFFFFF);
  432. end;
  433. function SetScreenResolution(Width, Height: integer): Longint;
  434. var
  435. DeviceMode: TDeviceMode;
  436. begin
  437. with DeviceMode do
  438. begin
  439. dmSize := SizeOf(TDeviceMode);
  440. dmPelsWidth := Width;
  441. dmPelsHeight := Height;
  442. dmFields := DM_PELSWIDTH or DM_PELSHEIGHT;
  443. end;
  444. Result := ChangeDisplaySettings(DeviceMode, CDS_UPDATEREGISTRY);
  445. end;
  446. {$ENDIF MSWINDOWS}
  447. function LastDayCurrentMonth: TDateTime;
  448. begin
  449. Result := EncodeDate(YearOf(Now),MonthOf(Now), DaysInMonth(Now));
  450. end;
  451. {$IFDEF FPC}
  452. function DateTimeInRange(ADateTime: TDateTime; AStartDateTime, AEndDateTime: TDateTime; aInclusive: Boolean = True): Boolean;
  453. begin
  454. if aInclusive then
  455. Result := (AStartDateTime <= ADateTime) and (ADateTime <= AEndDateTime)
  456. else
  457. Result := (AStartDateTime < ADateTime) and (ADateTime < AEndDateTime);
  458. end;
  459. {$ENDIF}
  460. function IsSameDay(cBefore, cNow : TDateTime) : Boolean;
  461. begin
  462. //Test: Result := MinutesBetween(cBefore,cNow) < 1;
  463. Result := DateTimeInRange(cNow,StartOfTheDay(cBefore),EndOfTheDay(cBefore),True);
  464. end;
  465. function FillStr(const C : Char; const Count : Byte) : string;
  466. var
  467. i : Byte;
  468. begin
  469. Result := '';
  470. for i := 1 to Count do Result := Result + C;
  471. end;
  472. function StrInArray(const aValue : string; const aInArray : array of string) : Boolean;
  473. var
  474. s : string;
  475. begin
  476. for s in aInArray do
  477. begin
  478. if s = aValue then Exit(True);
  479. end;
  480. Result := False;
  481. end;
  482. function Zeroes(const Number, Len : Int64) : string;
  483. begin
  484. if Len > Length(IntToStr(Number)) then Result := FillStr('0',Len - Length(IntToStr(Number))) + IntToStr(Number)
  485. else Result := IntToStr(Number);
  486. end;
  487. function NumberToStr(const Number : Int64) : string;
  488. begin
  489. try
  490. Result := FormatFloat('0,',Number);
  491. except
  492. Result := '#Error';
  493. end;
  494. end;
  495. function Spaces(const Count : Integer) : string;
  496. begin
  497. Result := FillStr(' ',Count);
  498. end;
  499. function NowStr : string;
  500. begin
  501. Result := DateTimeToStr(Now());
  502. end;
  503. function NewGuidStr : string;
  504. var
  505. guid : TGUID;
  506. begin
  507. guid.NewGuid;
  508. Result := guid.ToString
  509. //GUIDToString(guid);
  510. end;
  511. function IsLike(cText, Pattern: string) : Boolean;
  512. var
  513. i, n : Integer;
  514. match : Boolean;
  515. wildcard : Boolean;
  516. CurrentPattern : Char;
  517. begin
  518. Result := False;
  519. wildcard := False;
  520. cText := LowerCase(cText);
  521. Pattern := LowerCase(Pattern);
  522. match := False;
  523. if (Pattern.Length > cText.Length) or (Pattern = '') then Exit;
  524. if Pattern = '*' then
  525. begin
  526. Result := True;
  527. Exit;
  528. end;
  529. for i := 1 to cText.Length do
  530. begin
  531. CurrentPattern := Pattern[i];
  532. if CurrentPattern = '*' then wildcard := True;
  533. if wildcard then
  534. begin
  535. n := Pos(Copy(Pattern,i+1,Pattern.Length),cText);
  536. if (n > i) or (Pattern.Length = i) then
  537. begin
  538. Result := True;
  539. Exit;
  540. end;
  541. end
  542. else
  543. begin
  544. if (cText[i] = CurrentPattern) or (CurrentPattern = '?') then match := True
  545. else match := False;
  546. end;
  547. end;
  548. Result := match;
  549. end;
  550. function Capitalize(s: string): string;
  551. begin
  552. Result := '';
  553. if s.Length = 0 then Exit;
  554. s := LowerCase(s,loUserLocale);
  555. Result := UpperCase(s[1],loUserLocale) + Trim(Copy(s, 2, s.Length));
  556. end;
  557. function CapitalizeWords(s: string): string;
  558. var
  559. cword : string;
  560. begin
  561. Result := '';
  562. if s.Length = 0 then Exit;
  563. s := LowerCase(s,loUserLocale);
  564. for cword in s.Split([' ']) do
  565. begin
  566. if Result = '' then Result := Capitalize(cword)
  567. else Result := Result + ' ' + Capitalize(cword);
  568. end;
  569. end;
  570. function GetLoggedUserName : string;
  571. {$IFDEF MSWINDOWS}
  572. const
  573. cnMaxUserNameLen = 254;
  574. var
  575. sUserName : string;
  576. dwUserNameLen : DWord;
  577. begin
  578. dwUserNameLen := cnMaxUserNameLen-1;
  579. SetLength( sUserName, cnMaxUserNameLen );
  580. GetUserName(PChar( sUserName ),dwUserNameLen );
  581. SetLength( sUserName, dwUserNameLen );
  582. Result := sUserName;
  583. end;
  584. {$ENDIF}
  585. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  586. begin
  587. Result := GetEnvironmentVariable('USERNAME');
  588. end;
  589. {$ENDIF}
  590. function GetComputerName : string;
  591. {$IFDEF MSWINDOWS}
  592. var
  593. dwLength: dword;
  594. begin
  595. dwLength := 253;
  596. SetLength(Result, dwLength+1);
  597. if not Windows.GetComputerName(pchar(result), dwLength) then Result := 'Not detected!';
  598. Result := pchar(result);
  599. end;
  600. {$ENDIF}
  601. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  602. begin
  603. Result := GetEnvironmentVariable('COMPUTERNAME');
  604. end;
  605. {$ENDIF}
  606. function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
  607. begin
  608. if Delim = '\' then Result := StringReplace(cPath,'/',Delim,[rfReplaceAll])
  609. else Result := StringReplace(cPath,'\',Delim,[rfReplaceAll]);
  610. end;
  611. function RemoveLastPathSegment(cDir : string) : string;
  612. var
  613. posi : Integer;
  614. delim : Char;
  615. EndsWithDelim : Boolean;
  616. begin
  617. if cDir.Contains('\') then delim := '\'
  618. else if cDir.Contains('/') then delim := '/'
  619. else
  620. begin
  621. Result := '';
  622. Exit;
  623. end;
  624. NormalizePathDelim(cDir,delim);
  625. if cDir.EndsWith(delim) then
  626. begin
  627. cDir := Copy(cDir,1,cDir.Length-1);
  628. EndsWithDelim := True;
  629. end
  630. else EndsWithDelim := False;
  631. if cDir.CountChar(delim) > 1 then posi := cDir.LastDelimiter(delim)
  632. else posi := Pos(delim,cDir)-1;
  633. if posi = cDir.Length then posi := 0;
  634. Result := Copy(cDir,1,posi);
  635. if (Result <> '') and (EndsWithDelim) then Result := Result + delim;
  636. end;
  637. function ParamFindSwitch(const Switch : string) : Boolean;
  638. begin
  639. Result := FindCmdLineSwitch(Switch,['-', '/'],True);
  640. end;
  641. {$IFDEF FPC}
  642. function FindCmdLineSwitch(const Switch: string; var Value: string; IgnoreCase: Boolean = True;
  643. const SwitchTypes: TCmdLineSwitchTypes = [clstValueNextParam, clstValueAppended]): Boolean; overload;
  644. type
  645. TCompareProc = function(const S1, S2: string): Boolean;
  646. var
  647. Param: string;
  648. I, ValueOfs,
  649. SwitchLen, ParamLen: Integer;
  650. SameSwitch: TCompareProc;
  651. begin
  652. Result := False;
  653. Value := '';
  654. if IgnoreCase then
  655. SameSwitch := SameText else
  656. SameSwitch := SameStr;
  657. SwitchLen := Switch.Length;
  658. for I := 1 to ParamCount do
  659. begin
  660. Param := ParamStr(I);
  661. if CharInSet(Param.Chars[0], SwitchChars) and SameSwitch(Param.SubString(1,SwitchLen), Switch) then
  662. begin
  663. ParamLen := Param.Length;
  664. // Look for an appended value if the param is longer than the switch
  665. if (ParamLen > SwitchLen + 1) then
  666. begin
  667. // If not looking for appended value switches then this is not a matching switch
  668. if not (clstValueAppended in SwitchTypes) then
  669. Continue;
  670. ValueOfs := SwitchLen + 1;
  671. if Param.Chars[ValueOfs] = ':' then
  672. Inc(ValueOfs);
  673. Value := Param.SubString(ValueOfs, MaxInt);
  674. end
  675. // If the next param is not a switch, then treat it as the value
  676. else if (clstValueNextParam in SwitchTypes) and (I < ParamCount) and
  677. not CharInSet(ParamStr(I+1).Chars[0], SwitchChars) then
  678. Value := ParamStr(I+1);
  679. Result := True;
  680. Break;
  681. end;
  682. end;
  683. end;
  684. {$ENDIF}
  685. function ParamGetSwitch(const Switch : string; var cvalue : string) : Boolean;
  686. begin
  687. Result := FindCmdLineSwitch(Switch,cvalue,True,[clstValueAppended]);
  688. end;
  689. function GetAppName : string;
  690. begin
  691. Result := ExtractFilenameWithoutExt(ParamStr(0));
  692. end;
  693. function GetAppVersionStr: string;
  694. {$IFDEF MSWINDOWS}
  695. var
  696. Rec: LongRec;
  697. ver : Cardinal;
  698. begin
  699. ver := GetFileVersion(ParamStr(0));
  700. if ver <> Cardinal(-1) then
  701. begin
  702. Rec := LongRec(ver);
  703. Result := Format('%d.%d', [Rec.Hi, Rec.Lo]);
  704. end
  705. else Result := '';
  706. end;
  707. {$ENDIF}
  708. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  709. var
  710. version : TProgramVersion;
  711. begin
  712. if GetProgramVersion(version) then Result := Format('%d.%d', [version.Major, version.Minor])
  713. else Result := '';
  714. end;
  715. {$ENDIF}
  716. function GetAppVersionFullStr: string;
  717. {$IFDEF MSWINDOWS}
  718. var
  719. Exe: string;
  720. Size, Handle: DWORD;
  721. Buffer: TBytes;
  722. FixedPtr: PVSFixedFileInfo;
  723. begin
  724. Result := '';
  725. Exe := ParamStr(0);
  726. Size := GetFileVersionInfoSize(PChar(Exe), Handle);
  727. if Size = 0 then
  728. begin
  729. //RaiseLastOSError;
  730. //no version info in file
  731. Exit;
  732. end;
  733. SetLength(Buffer, Size);
  734. if not GetFileVersionInfo(PChar(Exe), Handle, Size, Buffer) then
  735. RaiseLastOSError;
  736. if not VerQueryValue(Buffer, '\', Pointer(FixedPtr), Size) then
  737. RaiseLastOSError;
  738. if (LongRec(FixedPtr.dwFileVersionLS).Hi = 0) and (LongRec(FixedPtr.dwFileVersionLS).Lo = 0) then
  739. begin
  740. Result := Format('%d.%d',
  741. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  742. LongRec(FixedPtr.dwFileVersionMS).Lo]); //minor
  743. end
  744. else if (LongRec(FixedPtr.dwFileVersionLS).Lo = 0) then
  745. begin
  746. Result := Format('%d.%d.%d',
  747. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  748. LongRec(FixedPtr.dwFileVersionMS).Lo, //minor
  749. LongRec(FixedPtr.dwFileVersionLS).Hi]); //release
  750. end
  751. else
  752. begin
  753. Result := Format('%d.%d.%d.%d',
  754. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  755. LongRec(FixedPtr.dwFileVersionMS).Lo, //minor
  756. LongRec(FixedPtr.dwFileVersionLS).Hi, //release
  757. LongRec(FixedPtr.dwFileVersionLS).Lo]); //build
  758. end;
  759. end;
  760. {$ENDIF}
  761. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  762. var
  763. version : TProgramVersion;
  764. begin
  765. if GetProgramVersion(version) then Result := Format('%d.%d.%d.%d', [version.Major, version.Minor, version.Revision, version.Build])
  766. else Result := '';
  767. end;
  768. {$ENDIF}
  769. function UTCToLocalTime(GMTTime: TDateTime): TDateTime;
  770. begin
  771. {$IFDEF FPC}
  772. Result := LocalTimeToUniversal(GMTTime);
  773. {$ELSE}
  774. Result := TTimeZone.Local.ToLocalTime(GMTTime);
  775. {$ENDIF}
  776. end;
  777. function LocalTimeToUTC(LocalTime : TDateTime): TDateTime;
  778. begin
  779. {$IFDEF FPC}
  780. Result := UniversalTimeToLocal(Localtime);
  781. {$ELSE}
  782. Result := TTimeZone.Local.ToUniversalTime(LocalTime);
  783. {$ENDIF}
  784. end;
  785. function DateTimeToGMT(aDate : TDateTime) : string;
  786. var
  787. FmtSettings : TFormatSettings;
  788. begin
  789. FmtSettings.DateSeparator := '-';
  790. FmtSettings.TimeSeparator := ':';
  791. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ" GMT"';
  792. Result := DateTimeToStr(aDate,FmtSettings);
  793. end;
  794. function CountDigits(anInt: Cardinal): Cardinal; inline;
  795. var
  796. cmp: Cardinal;
  797. begin
  798. cmp := 10;
  799. Result := 1;
  800. while (Result < 10) and (cmp <= anInt) do
  801. begin
  802. cmp := cmp*10;
  803. Inc(Result);
  804. end;
  805. end;
  806. procedure SaveStreamToFile(stream : TStream; const filename : string);
  807. var
  808. fs : TFileStream;
  809. begin
  810. fs := TFileStream.Create(filename,fmCreate);
  811. try
  812. stream.Seek(0,soBeginning);
  813. fs.CopyFrom(stream,stream.Size);
  814. finally
  815. fs.Free;
  816. end;
  817. end;
  818. { TCounter }
  819. procedure TCounter.Init(aMaxValue : Integer);
  820. begin
  821. fMaxValue := aMaxValue;
  822. fCurrentValue := 0;
  823. end;
  824. function TCounter.Count : Integer;
  825. begin
  826. Result := fCurrentValue;
  827. end;
  828. function TCounter.CountIs(aValue : Integer) : Boolean;
  829. begin
  830. Result := fCurrentValue = aValue;
  831. end;
  832. function TCounter.Check : Boolean;
  833. begin
  834. if fCurrentValue = fMaxValue then
  835. begin
  836. Result := True;
  837. Reset;
  838. end
  839. else
  840. begin
  841. Result := False;
  842. Inc(fCurrentValue);
  843. end;
  844. end;
  845. procedure TCounter.Reset;
  846. begin
  847. fCurrentValue := fMaxValue;
  848. end;
  849. { TimeCounter }
  850. procedure TTimeCounter.Init(MillisecondsToReach : Integer);
  851. begin
  852. fDoneEvery := MillisecondsToReach;
  853. end;
  854. function TTimeCounter.Check : Boolean;
  855. begin
  856. if MilliSecondsBetween(fCurrentTime,Now) > fDoneEvery then
  857. begin
  858. fCurrentTime := Now();
  859. Result := True;
  860. end
  861. else Result := False;
  862. end;
  863. procedure TTimeCounter.Reset;
  864. begin
  865. fCurrentTime := Now();
  866. end;
  867. {$IFDEF MSWINDOWS}
  868. procedure ProcessMessages;
  869. var
  870. Msg: TMsg;
  871. begin
  872. while integer(PeekMessage(Msg, 0, 0, 0, PM_REMOVE)) <> 0 do
  873. begin
  874. TranslateMessage(Msg);
  875. DispatchMessage(Msg);
  876. end;
  877. end;
  878. function GetLastOSError: String;
  879. begin
  880. Result := SysErrorMessage(Windows.GetLastError);
  881. end;
  882. {$ENDIF}
  883. initialization
  884. {$IFDEF MSWINDOWS}
  885. try
  886. GetEnvironmentPaths;
  887. except
  888. on E : Exception do
  889. begin
  890. if not IsService then
  891. begin
  892. if IsConsole then Writeln(Format('[WARN] GetEnvironmentPaths: %s',[E.Message]))
  893. else raise EEnvironmentPath.Create(Format('Get environment path error: %s',[E.Message]));
  894. end;
  895. end;
  896. end;
  897. {$ENDIF}
  898. end.