Quick.Commons.pas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  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. //returns a number leading zero
  170. function Zeroes(const Number, Len : Int64) : string;
  171. //converts a number to thousand delimeter string
  172. function NumberToStr(const Number : Int64) : string;
  173. //returns n spaces
  174. function Spaces(const Count : Integer) : string;
  175. //returns current date as a string
  176. function NowStr : string;
  177. //returns a new GUID as string
  178. function NewGuidStr : string;
  179. //compare a string with a wildcard pattern (? or *)
  180. function IsLike(cText, Pattern: string) : Boolean;
  181. //Upper case for first letter
  182. function Capitalize(s: string): string;
  183. function CapitalizeWords(s: string): string;
  184. //returns current logged user
  185. function GetLoggedUserName : string;
  186. //returns computer name
  187. function GetComputerName : string;
  188. //Changes incorrect delims in path
  189. function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
  190. //Removes last segment of a path
  191. function RemoveLastPathSegment(cDir : string) : string;
  192. //finds swith in commandline params
  193. function ParamFindSwitch(const Switch : string) : Boolean;
  194. //gets value for a switch if exists
  195. function ParamGetSwitch(const Switch : string; var cvalue : string) : Boolean;
  196. //returns app name (filename based)
  197. function GetAppName : string;
  198. //returns app version (major & minor)
  199. function GetAppVersionStr: string;
  200. //returns app version full (major, minor, release & compiled)
  201. function GetAppVersionFullStr: string;
  202. //UTC DateTime to Local DateTime
  203. function UTCToLocalTime(GMTTime: TDateTime): TDateTime;
  204. //Local DateTime to UTC DateTime
  205. function LocalTimeToUTC(LocalTime : TDateTime): TDateTime;
  206. //return GTM time string
  207. function DateTimeToGMT(aDate : TDateTime) : string;
  208. //count number of digits of a Integer
  209. function CountDigits(anInt: Cardinal): Cardinal; inline;
  210. //save stream to file
  211. procedure SaveStreamToFile(stream : TStream; const filename : string);
  212. {$IFDEF MSWINDOWS}
  213. //process messages on console applications
  214. procedure ProcessMessages;
  215. //get last error message
  216. function GetLastOSError : String;
  217. {$ENDIF}
  218. {$IF DEFINED(FPC) AND DEFINED(MSWINDOWS)}
  219. function GetLastInputInfo(var plii: TLastInputInfo): BOOL;stdcall; external 'user32' name 'GetLastInputInfo';
  220. {$ENDIF}
  221. {$IFDEF MSWINDOWS}
  222. var
  223. path : TEnvironmentPath;
  224. {$ENDIF}
  225. implementation
  226. {TFileHelper}
  227. {$IFNDEF FPC}
  228. {$IFDEF MSWINDOWS}
  229. class function TFileHelper.IsInUse(const FileName : string) : Boolean;
  230. var
  231. HFileRes: HFILE;
  232. begin
  233. Result := False;
  234. if not FileExists(FileName) then Exit;
  235. try
  236. HFileRes := CreateFile(PChar(FileName)
  237. ,GENERIC_READ or GENERIC_WRITE
  238. ,0
  239. ,nil
  240. ,OPEN_EXISTING
  241. ,FILE_ATTRIBUTE_NORMAL
  242. ,0);
  243. Result := (HFileRes = INVALID_HANDLE_VALUE);
  244. if not(Result) then begin
  245. CloseHandle(HFileRes);
  246. end;
  247. except
  248. Result := True;
  249. end;
  250. end;
  251. {$ENDIF}
  252. {$IFDEF MSWINDOWS}
  253. class function TFileHelper.GetSize(const FileName: String): Int64;
  254. var
  255. info: TWin32FileAttributeData;
  256. begin
  257. Result := -1;
  258. if not GetFileAttributesEx(PWideChar(FileName), GetFileExInfoStandard, @info) then Exit;
  259. Result := Int64(info.nFileSizeLow) or Int64(info.nFileSizeHigh shl 32);
  260. end;
  261. {$ELSE}
  262. class function TFileHelper.GetSize(const FileName: String): Int64;
  263. var
  264. sr : TSearchRec;
  265. begin
  266. if FindFirst(fileName, faAnyFile, sr ) = 0 then Result := sr.Size
  267. else Result := -1;
  268. end;
  269. {$ENDIF}
  270. {TDirectoryHelper}
  271. class function TDirectoryHelper.GetSize(const Path: String): Int64;
  272. var
  273. filename : string;
  274. begin
  275. Result := -1;
  276. for filename in TDirectory.GetFiles(Path) do
  277. begin
  278. Result := Result + TFile.GetSize(filename);
  279. end;
  280. end;
  281. {$ENDIF}
  282. {other functions}
  283. function RandomPassword(const PasswordLength : Integer; Complexity : TPasswordComplexity = [pfIncludeNumbers,pfIncludeSigns]) : string;
  284. const
  285. PassAlpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  286. PassSigns = '@!&$';
  287. PassNumbers = '1234567890';
  288. var
  289. MinNumbers,
  290. MinSigns : Integer;
  291. NumNumbers,
  292. NumSigns : Integer;
  293. begin
  294. Result := '';
  295. Randomize;
  296. //fill all alfa
  297. repeat
  298. Result := Result + PassAlpha[Random(Length(PassAlpha))+1];
  299. until (Length(Result) = PasswordLength);
  300. //checks if need include numbers
  301. if pfIncludeNumbers in Complexity then
  302. begin
  303. MinNumbers := Round(PasswordLength / 10 * 2);
  304. NumNumbers := 0;
  305. if MinNumbers = 0 then MinNumbers := 1;
  306. repeat
  307. Result[Random(PasswordLength)+1] := PassNumbers[Random(Length(PassNumbers))+1];
  308. Inc(NumNumbers);
  309. until NumNumbers = MinNumbers;
  310. end;
  311. //checks if need include signs
  312. if pfIncludeNumbers in Complexity then
  313. begin
  314. MinSigns := Round(PasswordLength / 10 * 1);
  315. NumSigns := 0;
  316. if MinSigns = 0 then MinSigns := 1;
  317. repeat
  318. Result[Random(PasswordLength)+1] := PassSigns[Random(Length(PassSigns))+1];
  319. Inc(NumSigns);
  320. until NumSigns = MinSigns;
  321. end;
  322. end;
  323. function ExtractFileNameWithoutExt(const FileName: string): string;
  324. begin
  325. Result := TPath.GetFileNameWithoutExtension(FileName);
  326. end;
  327. function UnixToWindowsPath(const UnixPath: string): string;
  328. begin
  329. Result := StringReplace(UnixPath, '/', '\',[rfReplaceAll, rfIgnoreCase]);
  330. end;
  331. function WindowsToUnixPath(const WindowsPath: string): string;
  332. begin
  333. Result := StringReplace(WindowsPath, '\', '/',[rfReplaceAll, rfIgnoreCase]);
  334. end;
  335. function CorrectURLPath(cUrl : string) : string;
  336. var
  337. nurl : string;
  338. begin
  339. nurl := WindowsToUnixPath(cUrl);
  340. nurl := StringReplace(nurl,'//','/',[rfReplaceAll]);
  341. Result := StringReplace(nurl,' ','%20',[rfReplaceAll]);
  342. //TNetEncoding.Url.Encode()
  343. end;
  344. {$IFDEF MSWINDOWS}
  345. procedure GetEnvironmentPaths;
  346. begin
  347. //gets path
  348. path.EXEPATH := TPath.GetDirectoryName(ParamStr(0));
  349. path.WINDOWS := SysUtils.GetEnvironmentVariable('windir');
  350. path.PROGRAMFILES := SysUtils.GetEnvironmentVariable('ProgramFiles');
  351. path.COMMONFILES := SysUtils.GetEnvironmentVariable('CommonProgramFiles(x86)');
  352. path.HOMEDRIVE := SysUtils.GetEnvironmentVariable('SystemDrive');
  353. path.USERPROFILE := SysUtils.GetEnvironmentVariable('USERPROFILE');
  354. path.PROGRAMDATA := SysUtils.GetEnvironmentVariable('ProgramData');
  355. path.ALLUSERSPROFILE := SysUtils.GetEnvironmentVariable('AllUsersProfile');
  356. path.INSTDRIVE := path.HOMEDRIVE;
  357. path.TEMP := SysUtils.GetEnvironmentVariable('TEMP');
  358. path.SYSTEM := GetSpecialFolderPath(CSIDL_SYSTEM);
  359. path.APPDATA:=GetSpecialFolderPath(CSIDL_APPDATA);
  360. //these paths fail if user is SYSTEM
  361. try
  362. path.DESKTOP := GetSpecialFolderPath(CSIDL_DESKTOP);
  363. path.DESKTOP_ALLUSERS := GetSpecialFolderPath(CSIDL_COMMON_DESKTOPDIRECTORY);
  364. path.STARTMENU:=GetSpecialFolderPath(CSIDL_PROGRAMS);
  365. path.STARTMENU_ALLUSERS:=GetSpecialFolderPath(CSIDL_COMMON_PROGRAMS);
  366. path.STARTMENU_ALLUSERS := path.STARTMENU;
  367. path.STARTUP:=GetSpecialFolderPath(CSIDL_STARTUP);
  368. except
  369. //
  370. end;
  371. end;
  372. function GetSpecialFolderPath(folderID : Integer) : string;
  373. var
  374. ppidl: PItemIdList;
  375. begin
  376. SHGetSpecialFolderLocation(0, folderID, ppidl);
  377. SetLength(Result, MAX_PATH);
  378. if not SHGetPathFromIDList(ppidl,{$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}) then
  379. begin
  380. raise EShellError.create(Format('GetSpecialFolderPath: Invalid PIPL (%d)',[folderID]));
  381. end;
  382. SetLength(Result, lStrLen({$IFDEF FPC}PAnsiChar(Result){$ELSE}PChar(Result){$ENDIF}));
  383. end;
  384. function Is64bitOS : Boolean;
  385. begin
  386. {$IFDEF WIN64}
  387. Result := True;
  388. {$ELSE}
  389. Result := False;
  390. {$ENDIF WIN64}
  391. end;
  392. function IsConsole: Boolean;
  393. begin
  394. {$IFDEF CONSOLE}
  395. Result := True;
  396. {$ELSE}
  397. Result := False;
  398. {$ENDIF CONSOLE}
  399. end;
  400. {$ENDIF}
  401. function IsDebug: Boolean;
  402. begin
  403. {$IFDEF DEBUG}
  404. Result := True;
  405. {$ELSE}
  406. Result := False;
  407. {$ENDIF DEBUG}
  408. end;
  409. {$IFDEF MSWINDOWS}
  410. function IsService : Boolean;
  411. begin
  412. //only working with my Quick.AppService unit
  413. try
  414. Result := (IsConsole) and (GetStdHandle(STD_OUTPUT_HANDLE) = 0);
  415. except
  416. Result := False;
  417. end;
  418. end;
  419. function SecondsIdle: DWord;
  420. var
  421. liInfo: TLastInputInfo;
  422. begin
  423. liInfo.cbSize := SizeOf(TLastInputInfo) ;
  424. GetLastInputInfo(liInfo) ;
  425. Result := (GetTickCount - liInfo.dwTime) DIV 1000;
  426. end;
  427. procedure FreeUnusedMem;
  428. begin
  429. if Win32Platform = VER_PLATFORM_WIN32_NT then SetProcessWorkingSetSize(GetCurrentProcess, $FFFFFFFF, $FFFFFFFF);
  430. end;
  431. function SetScreenResolution(Width, Height: integer): Longint;
  432. var
  433. DeviceMode: TDeviceMode;
  434. begin
  435. with DeviceMode do
  436. begin
  437. dmSize := SizeOf(TDeviceMode);
  438. dmPelsWidth := Width;
  439. dmPelsHeight := Height;
  440. dmFields := DM_PELSWIDTH or DM_PELSHEIGHT;
  441. end;
  442. Result := ChangeDisplaySettings(DeviceMode, CDS_UPDATEREGISTRY);
  443. end;
  444. {$ENDIF MSWINDOWS}
  445. function LastDayCurrentMonth: TDateTime;
  446. begin
  447. Result := EncodeDate(YearOf(Now),MonthOf(Now), DaysInMonth(Now));
  448. end;
  449. {$IFDEF FPC}
  450. function DateTimeInRange(ADateTime: TDateTime; AStartDateTime, AEndDateTime: TDateTime; aInclusive: Boolean = True): Boolean;
  451. begin
  452. if aInclusive then
  453. Result := (AStartDateTime <= ADateTime) and (ADateTime <= AEndDateTime)
  454. else
  455. Result := (AStartDateTime < ADateTime) and (ADateTime < AEndDateTime);
  456. end;
  457. {$ENDIF}
  458. function IsSameDay(cBefore, cNow : TDateTime) : Boolean;
  459. begin
  460. //Test: Result := MinutesBetween(cBefore,cNow) < 1;
  461. Result := DateTimeInRange(cNow,StartOfTheDay(cBefore),EndOfTheDay(cBefore),True);
  462. end;
  463. function FillStr(const C : Char; const Count : Byte) : string;
  464. var
  465. i : Byte;
  466. begin
  467. Result := '';
  468. for i := 1 to Count do Result := Result + C;
  469. end;
  470. function Zeroes(const Number, Len : Int64) : string;
  471. begin
  472. if Len > Length(IntToStr(Number)) then Result := FillStr('0',Len - Length(IntToStr(Number))) + IntToStr(Number)
  473. else Result := IntToStr(Number);
  474. end;
  475. function NumberToStr(const Number : Int64) : string;
  476. begin
  477. try
  478. Result := FormatFloat('0,',Number);
  479. except
  480. Result := '#Error';
  481. end;
  482. end;
  483. function Spaces(const Count : Integer) : string;
  484. begin
  485. Result := FillStr(' ',Count);
  486. end;
  487. function NowStr : string;
  488. begin
  489. Result := DateTimeToStr(Now());
  490. end;
  491. function NewGuidStr : string;
  492. var
  493. guid : TGUID;
  494. begin
  495. guid.NewGuid;
  496. Result := guid.ToString
  497. //GUIDToString(guid);
  498. end;
  499. function IsLike(cText, Pattern: string) : Boolean;
  500. var
  501. i, n : Integer;
  502. match : Boolean;
  503. wildcard : Boolean;
  504. CurrentPattern : Char;
  505. begin
  506. Result := False;
  507. wildcard := False;
  508. cText := LowerCase(cText);
  509. Pattern := LowerCase(Pattern);
  510. match := False;
  511. if (Pattern.Length > cText.Length) or (Pattern = '') then Exit;
  512. if Pattern = '*' then
  513. begin
  514. Result := True;
  515. Exit;
  516. end;
  517. for i := 1 to cText.Length do
  518. begin
  519. CurrentPattern := Pattern[i];
  520. if CurrentPattern = '*' then wildcard := True;
  521. if wildcard then
  522. begin
  523. n := Pos(Copy(Pattern,i+1,Pattern.Length),cText);
  524. if (n > i) or (Pattern.Length = i) then
  525. begin
  526. Result := True;
  527. Exit;
  528. end;
  529. end
  530. else
  531. begin
  532. if (cText[i] = CurrentPattern) or (CurrentPattern = '?') then match := True
  533. else match := False;
  534. end;
  535. end;
  536. Result := match;
  537. end;
  538. function Capitalize(s: string): string;
  539. begin
  540. Result := '';
  541. if s.Length = 0 then Exit;
  542. s := LowerCase(s,loUserLocale);
  543. Result := UpperCase(s[1],loUserLocale) + Trim(Copy(s, 2, s.Length));
  544. end;
  545. function CapitalizeWords(s: string): string;
  546. var
  547. cword : string;
  548. begin
  549. Result := '';
  550. if s.Length = 0 then Exit;
  551. s := LowerCase(s,loUserLocale);
  552. for cword in s.Split([' ']) do
  553. begin
  554. if Result = '' then Result := Capitalize(cword)
  555. else Result := Result + ' ' + Capitalize(cword);
  556. end;
  557. end;
  558. function GetLoggedUserName : string;
  559. {$IFDEF MSWINDOWS}
  560. const
  561. cnMaxUserNameLen = 254;
  562. var
  563. sUserName : string;
  564. dwUserNameLen : DWord;
  565. begin
  566. dwUserNameLen := cnMaxUserNameLen-1;
  567. SetLength( sUserName, cnMaxUserNameLen );
  568. GetUserName(PChar( sUserName ),dwUserNameLen );
  569. SetLength( sUserName, dwUserNameLen );
  570. Result := sUserName;
  571. end;
  572. {$ENDIF}
  573. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  574. begin
  575. Result := GetEnvironmentVariable('USERNAME');
  576. end;
  577. {$ENDIF}
  578. function GetComputerName : string;
  579. {$IFDEF MSWINDOWS}
  580. var
  581. dwLength: dword;
  582. begin
  583. dwLength := 253;
  584. SetLength(Result, dwLength+1);
  585. if not Windows.GetComputerName(pchar(result), dwLength) then Result := 'Not detected!';
  586. Result := pchar(result);
  587. end;
  588. {$ENDIF}
  589. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  590. begin
  591. Result := GetEnvironmentVariable('COMPUTERNAME');
  592. end;
  593. {$ENDIF}
  594. function NormalizePathDelim(const cPath : string; const Delim : Char) : string;
  595. begin
  596. if Delim = '\' then Result := StringReplace(cPath,'/',Delim,[rfReplaceAll])
  597. else Result := StringReplace(cPath,'\',Delim,[rfReplaceAll]);
  598. end;
  599. function RemoveLastPathSegment(cDir : string) : string;
  600. var
  601. posi : Integer;
  602. delim : Char;
  603. EndsWithDelim : Boolean;
  604. begin
  605. if cDir.Contains('\') then delim := '\'
  606. else if cDir.Contains('/') then delim := '/'
  607. else
  608. begin
  609. Result := '';
  610. Exit;
  611. end;
  612. NormalizePathDelim(cDir,delim);
  613. if cDir.EndsWith(delim) then
  614. begin
  615. cDir := Copy(cDir,1,cDir.Length-1);
  616. EndsWithDelim := True;
  617. end
  618. else EndsWithDelim := False;
  619. if cDir.CountChar(delim) > 1 then posi := cDir.LastDelimiter(delim)
  620. else posi := Pos(delim,cDir)-1;
  621. if posi = cDir.Length then posi := 0;
  622. Result := Copy(cDir,1,posi);
  623. if (Result <> '') and (EndsWithDelim) then Result := Result + delim;
  624. end;
  625. function ParamFindSwitch(const Switch : string) : Boolean;
  626. begin
  627. Result := FindCmdLineSwitch(Switch,['-', '/'],True);
  628. end;
  629. {$IFDEF FPC}
  630. function FindCmdLineSwitch(const Switch: string; var Value: string; IgnoreCase: Boolean = True;
  631. const SwitchTypes: TCmdLineSwitchTypes = [clstValueNextParam, clstValueAppended]): Boolean; overload;
  632. type
  633. TCompareProc = function(const S1, S2: string): Boolean;
  634. var
  635. Param: string;
  636. I, ValueOfs,
  637. SwitchLen, ParamLen: Integer;
  638. SameSwitch: TCompareProc;
  639. begin
  640. Result := False;
  641. Value := '';
  642. if IgnoreCase then
  643. SameSwitch := SameText else
  644. SameSwitch := SameStr;
  645. SwitchLen := Switch.Length;
  646. for I := 1 to ParamCount do
  647. begin
  648. Param := ParamStr(I);
  649. if CharInSet(Param.Chars[0], SwitchChars) and SameSwitch(Param.SubString(1,SwitchLen), Switch) then
  650. begin
  651. ParamLen := Param.Length;
  652. // Look for an appended value if the param is longer than the switch
  653. if (ParamLen > SwitchLen + 1) then
  654. begin
  655. // If not looking for appended value switches then this is not a matching switch
  656. if not (clstValueAppended in SwitchTypes) then
  657. Continue;
  658. ValueOfs := SwitchLen + 1;
  659. if Param.Chars[ValueOfs] = ':' then
  660. Inc(ValueOfs);
  661. Value := Param.SubString(ValueOfs, MaxInt);
  662. end
  663. // If the next param is not a switch, then treat it as the value
  664. else if (clstValueNextParam in SwitchTypes) and (I < ParamCount) and
  665. not CharInSet(ParamStr(I+1).Chars[0], SwitchChars) then
  666. Value := ParamStr(I+1);
  667. Result := True;
  668. Break;
  669. end;
  670. end;
  671. end;
  672. {$ENDIF}
  673. function ParamGetSwitch(const Switch : string; var cvalue : string) : Boolean;
  674. begin
  675. Result := FindCmdLineSwitch(Switch,cvalue,True,[clstValueAppended]);
  676. end;
  677. function GetAppName : string;
  678. begin
  679. Result := ExtractFilenameWithoutExt(ParamStr(0));
  680. end;
  681. function GetAppVersionStr: string;
  682. {$IFDEF MSWINDOWS}
  683. var
  684. Rec: LongRec;
  685. ver : Cardinal;
  686. begin
  687. ver := GetFileVersion(ParamStr(0));
  688. if ver <> Cardinal(-1) then
  689. begin
  690. Rec := LongRec(ver);
  691. Result := Format('%d.%d', [Rec.Hi, Rec.Lo]);
  692. end
  693. else Result := '';
  694. end;
  695. {$ENDIF}
  696. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  697. var
  698. version : TProgramVersion;
  699. begin
  700. if GetProgramVersion(version) then Result := Format('%d.%d', [version.Major, version.Minor])
  701. else Result := '';
  702. end;
  703. {$ENDIF}
  704. function GetAppVersionFullStr: string;
  705. {$IFDEF MSWINDOWS}
  706. var
  707. Exe: string;
  708. Size, Handle: DWORD;
  709. Buffer: TBytes;
  710. FixedPtr: PVSFixedFileInfo;
  711. begin
  712. Result := '';
  713. Exe := ParamStr(0);
  714. Size := GetFileVersionInfoSize(PChar(Exe), Handle);
  715. if Size = 0 then
  716. begin
  717. //RaiseLastOSError;
  718. //no version info in file
  719. Exit;
  720. end;
  721. SetLength(Buffer, Size);
  722. if not GetFileVersionInfo(PChar(Exe), Handle, Size, Buffer) then
  723. RaiseLastOSError;
  724. if not VerQueryValue(Buffer, '\', Pointer(FixedPtr), Size) then
  725. RaiseLastOSError;
  726. if (LongRec(FixedPtr.dwFileVersionLS).Hi = 0) and (LongRec(FixedPtr.dwFileVersionLS).Lo = 0) then
  727. begin
  728. Result := Format('%d.%d',
  729. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  730. LongRec(FixedPtr.dwFileVersionMS).Lo]); //minor
  731. end
  732. else if (LongRec(FixedPtr.dwFileVersionLS).Lo = 0) then
  733. begin
  734. Result := Format('%d.%d.%d',
  735. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  736. LongRec(FixedPtr.dwFileVersionMS).Lo, //minor
  737. LongRec(FixedPtr.dwFileVersionLS).Hi]); //release
  738. end
  739. else
  740. begin
  741. Result := Format('%d.%d.%d.%d',
  742. [LongRec(FixedPtr.dwFileVersionMS).Hi, //major
  743. LongRec(FixedPtr.dwFileVersionMS).Lo, //minor
  744. LongRec(FixedPtr.dwFileVersionLS).Hi, //release
  745. LongRec(FixedPtr.dwFileVersionLS).Lo]); //build
  746. end;
  747. end;
  748. {$ENDIF}
  749. {$IF DEFINED(FPC) AND DEFINED(LINUX)}
  750. var
  751. version : TProgramVersion;
  752. begin
  753. if GetProgramVersion(version) then Result := Format('%d.%d.%d.%d', [version.Major, version.Minor, version.Revision, version.Build])
  754. else Result := '';
  755. end;
  756. {$ENDIF}
  757. function UTCToLocalTime(GMTTime: TDateTime): TDateTime;
  758. begin
  759. {$IFDEF FPC}
  760. Result := LocalTimeToUniversal(GMTTime);
  761. {$ELSE}
  762. Result := TTimeZone.Local.ToLocalTime(GMTTime);
  763. {$ENDIF}
  764. end;
  765. function LocalTimeToUTC(LocalTime : TDateTime): TDateTime;
  766. begin
  767. {$IFDEF FPC}
  768. Result := UniversalTimeToLocal(Localtime);
  769. {$ELSE}
  770. Result := TTimeZone.Local.ToUniversalTime(LocalTime);
  771. {$ENDIF}
  772. end;
  773. function DateTimeToGMT(aDate : TDateTime) : string;
  774. var
  775. FmtSettings : TFormatSettings;
  776. begin
  777. FmtSettings.DateSeparator := '-';
  778. FmtSettings.TimeSeparator := ':';
  779. FmtSettings.ShortDateFormat := 'YYYY-MM-DD"T"HH:NN:SS.ZZZ" GMT"';
  780. Result := DateTimeToStr(aDate,FmtSettings);
  781. end;
  782. function CountDigits(anInt: Cardinal): Cardinal; inline;
  783. var
  784. cmp: Cardinal;
  785. begin
  786. cmp := 10;
  787. Result := 1;
  788. while (Result < 10) and (cmp <= anInt) do
  789. begin
  790. cmp := cmp*10;
  791. Inc(Result);
  792. end;
  793. end;
  794. procedure SaveStreamToFile(stream : TStream; const filename : string);
  795. var
  796. fs : TFileStream;
  797. begin
  798. fs := TFileStream.Create(filename,fmCreate);
  799. try
  800. stream.Seek(0,soBeginning);
  801. fs.CopyFrom(stream,stream.Size);
  802. finally
  803. fs.Free;
  804. end;
  805. end;
  806. { TCounter }
  807. procedure TCounter.Init(aMaxValue : Integer);
  808. begin
  809. fMaxValue := aMaxValue;
  810. fCurrentValue := 0;
  811. end;
  812. function TCounter.Count : Integer;
  813. begin
  814. Result := fCurrentValue;
  815. end;
  816. function TCounter.CountIs(aValue : Integer) : Boolean;
  817. begin
  818. Result := fCurrentValue = aValue;
  819. end;
  820. function TCounter.Check : Boolean;
  821. begin
  822. if fCurrentValue = fMaxValue then
  823. begin
  824. Result := True;
  825. Reset;
  826. end
  827. else
  828. begin
  829. Result := False;
  830. Inc(fCurrentValue);
  831. end;
  832. end;
  833. procedure TCounter.Reset;
  834. begin
  835. fCurrentValue := fMaxValue;
  836. end;
  837. { TimeCounter }
  838. procedure TTimeCounter.Init(MillisecondsToReach : Integer);
  839. begin
  840. fDoneEvery := MillisecondsToReach;
  841. end;
  842. function TTimeCounter.Check : Boolean;
  843. begin
  844. if MilliSecondsBetween(fCurrentTime,Now) > fDoneEvery then
  845. begin
  846. fCurrentTime := Now();
  847. Result := True;
  848. end
  849. else Result := False;
  850. end;
  851. procedure TTimeCounter.Reset;
  852. begin
  853. fCurrentTime := Now();
  854. end;
  855. {$IFDEF MSWINDOWS}
  856. procedure ProcessMessages;
  857. var
  858. Msg: TMsg;
  859. begin
  860. while integer(PeekMessage(Msg, 0, 0, 0, PM_REMOVE)) <> 0 do
  861. begin
  862. TranslateMessage(Msg);
  863. DispatchMessage(Msg);
  864. end;
  865. end;
  866. function GetLastOSError: String;
  867. begin
  868. Result := SysErrorMessage(Windows.GetLastError);
  869. end;
  870. {$ENDIF}
  871. initialization
  872. {$IFDEF MSWINDOWS}
  873. try
  874. GetEnvironmentPaths;
  875. except
  876. on E : Exception do
  877. begin
  878. if not IsService then
  879. begin
  880. if IsConsole then Writeln(Format('[WARN] GetEnvironmentPaths: %s',[E.Message]))
  881. else raise EEnvironmentPath.Create(Format('Get environment path error: %s',[E.Message]));
  882. end;
  883. end;
  884. end;
  885. {$ENDIF}
  886. end.