sysutils.inc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197
  1. {%MainUnit sysutils.pp}
  2. {
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Florian Klaempfl
  5. member of the Free Pascal development team
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. { MCBS functions }
  13. {$i sysansi.inc}
  14. {$i syscodepages.inc}
  15. {$macro on}
  16. {$define PathStr:=UnicodeString}
  17. {$define PathPChar:=PUnicodeChar}
  18. {$define SYSUTILSUNICODE}
  19. { Read filename handling functions implementation }
  20. {$i fina.inc}
  21. { Read disk function implementations }
  22. {$i disk.inc}
  23. {$undef SYSUTILSUNICODE}
  24. {$define PathStr:=RawByteString}
  25. {$define PathPChar:=PAnsiChar}
  26. { Read filename handling functions implementation }
  27. {$i fina.inc}
  28. { Read disk function implementations }
  29. {$i disk.inc}
  30. {$undef PathStr}
  31. {$undef PathPChar}
  32. { Read file utility functions implementation }
  33. {$i filutil.inc}
  34. { variant error codes }
  35. {$i varerror.inc}
  36. { Type helpers}
  37. {$i syshelp.inc}
  38. {$IFDEF FPC_HAS_FEATURE_UNICODESTRINGS}
  39. { strange Delphi thing }
  40. {$i sysmarshal.inc}
  41. {$ENDIF}
  42. {$ifndef OS_FILEISREADONLY}
  43. Function FileIsReadOnly(const FileName: RawByteString): Boolean;
  44. begin
  45. Result := (FileGetAttr(FileName) and faReadOnly) <> 0;
  46. end;
  47. Function FileIsReadOnly(const FileName: UnicodeString): Boolean;
  48. begin
  49. Result := (FileGetAttr(FileName) and faReadOnly) <> 0;
  50. end;
  51. {$endif OS_FILEISREADONLY}
  52. {$ifndef OS_FILESETDATEBYNAME}
  53. Function FileSetDate (Const FileName : RawByteString;Age : Int64) : Longint;
  54. Var
  55. fd : THandle;
  56. begin
  57. { at least windows requires fmOpenWrite here }
  58. fd:=FileOpen(FileName,fmOpenWrite);
  59. If (Fd<>feInvalidHandle) then
  60. try
  61. Result:=FileSetDate(fd,Age);
  62. finally
  63. FileClose(fd);
  64. end
  65. else
  66. {$ifdef HAS_OSERROR}
  67. Result:=GetLastOSError;
  68. {$else}
  69. Result:=-1;
  70. {$endif}
  71. end;
  72. Function FileSetDate (Const FileName : UnicodeString;Age : Int64) : Longint;
  73. Var
  74. fd : THandle;
  75. begin
  76. { at least windows requires fmOpenWrite here }
  77. fd:=FileOpen(FileName,fmOpenWrite);
  78. If (Fd<>feInvalidHandle) then
  79. try
  80. Result:=FileSetDate(fd,Age);
  81. finally
  82. FileClose(fd);
  83. end
  84. else
  85. {$ifdef HAS_OSERROR}
  86. Result:=GetLastOSError;
  87. {$else}
  88. Result:=-1;
  89. {$endif}
  90. end;
  91. {$endif}
  92. { Read String Handling functions implementation }
  93. {$i sysstr.inc}
  94. { Read date & Time function implementations }
  95. {$ifndef FPUNONE}
  96. {$i dati.inc}
  97. {$endif}
  98. {$IFNDEF HAS_GETTICKCOUNT}
  99. function GetTickCount: LongWord;
  100. begin
  101. Result := LongWord(GetTickCount64);
  102. end;
  103. {$ENDIF}
  104. {$IFNDEF HAS_GETTICKCOUNT64}
  105. function GetTickCount64: QWord;
  106. begin
  107. {$IFDEF FPU_NONE}
  108. {$IFDEF HAS_SYSTIMERTICK}
  109. Result := SysTimerTick;
  110. {$ELSE}
  111. Result := 0;
  112. {$ENDIF}
  113. {$ELSE}
  114. Result := Trunc(Now * 24 * 60 * 60 * 1000);
  115. {$ENDIF}
  116. end;
  117. {$ENDIF}
  118. { Read PAnsiChar handling functions implementation }
  119. {$i syspch.inc}
  120. { generic internationalisation code }
  121. {$i sysint.inc}
  122. { wide string functions }
  123. {$i syswide.inc}
  124. {$ifdef FPC_HAS_UNICODESTRING}
  125. { unicode string functions }
  126. {$i sysuni.inc}
  127. {$i sysencoding.inc}
  128. {$endif FPC_HAS_UNICODESTRING}
  129. { threading stuff }
  130. {$i sysuthrd.inc}
  131. { OS utility code }
  132. {$i osutil.inc}
  133. procedure FreeAndNil(var obj);
  134. var
  135. temp: tobject;
  136. begin
  137. temp:=tobject(obj);
  138. pointer(obj):=nil;
  139. temp.free;
  140. end;
  141. procedure FreeMemAndNil(var p);
  142. var
  143. temp:Pointer;
  144. begin
  145. temp := Pointer(p);
  146. Pointer(P):=nil;
  147. FreeMem(temp);
  148. end;
  149. { Interfaces support }
  150. {$i sysuintf.inc}
  151. constructor Exception.Create(const msg : string);
  152. begin
  153. inherited create;
  154. fmessage:=msg;
  155. end;
  156. constructor Exception.CreateFmt(const msg : string; const args : array of const);
  157. begin
  158. inherited create;
  159. fmessage:=Format(msg,args);
  160. end;
  161. constructor Exception.CreateRes(ResString: PResStringRec);
  162. begin
  163. inherited create;
  164. fmessage:=ResString^;
  165. end;
  166. constructor Exception.CreateResFmt(ResString: PResStringRec; const Args: array of const);
  167. begin
  168. inherited create;
  169. fmessage:=Format(ResString^,args);
  170. end;
  171. constructor Exception.CreateHelp(const Msg: string; AHelpContext: Longint);
  172. begin
  173. inherited create;
  174. fmessage:=Msg;
  175. fhelpcontext:=AHelpContext;
  176. end;
  177. constructor Exception.CreateFmtHelp(const Msg: string; const Args: array of const;
  178. AHelpContext: Longint);
  179. begin
  180. inherited create;
  181. fmessage:=Format(Msg,args);
  182. fhelpcontext:=AHelpContext;
  183. end;
  184. constructor Exception.CreateResHelp(ResString: PResStringRec; AHelpContext: Longint);
  185. begin
  186. inherited create;
  187. fmessage:=ResString^;
  188. fhelpcontext:=AHelpContext;
  189. end;
  190. constructor Exception.CreateResFmtHelp(ResString: PResStringRec; const Args: array of const;
  191. AHelpContext: Longint);
  192. begin
  193. inherited create;
  194. fmessage:=Format(ResString^,args);
  195. fhelpcontext:=AHelpContext;
  196. end;
  197. Function Exception.ToString : RTLString;
  198. begin
  199. Result:=ClassName+': '+Message;
  200. end;
  201. procedure EHeapMemoryError.FreeInstance;
  202. begin
  203. if AllowFree then
  204. inherited FreeInstance;
  205. end;
  206. function Exception.GetBaseException : Exception;
  207. var
  208. _ExceptObjectStack : PExceptObject;
  209. begin
  210. _ExceptObjectStack:=RaiseList;
  211. While Assigned(_ExceptObjectStack) do
  212. begin
  213. result:=Exception(_ExceptObjectStack^.FObject);
  214. _ExceptObjectStack:=_ExceptObjectStack^.Next;
  215. end;
  216. end;
  217. Constructor EVariantError.CreateCode (Code : longint);
  218. begin
  219. case Code of
  220. VAR_OK:
  221. Create(SNoError);
  222. VAR_PARAMNOTFOUND:
  223. Create(SVarParamNotFound);
  224. VAR_TYPEMISMATCH:
  225. Create(SInvalidVarCast);
  226. VAR_BADVARTYPE:
  227. Create(SVarBadType);
  228. VAR_OVERFLOW:
  229. Create(SVarOverflow);
  230. VAR_BADINDEX:
  231. Create(SVarArrayBounds);
  232. VAR_ARRAYISLOCKED:
  233. Create(SVarArrayLocked);
  234. VAR_NOTIMPL:
  235. Create(SVarNotImplemented);
  236. VAR_OUTOFMEMORY:
  237. Create(SVarOutOfMemory);
  238. VAR_INVALIDARG:
  239. Create(SVarInvalid);
  240. VAR_UNEXPECTED,
  241. VAR_EXCEPTION:
  242. Create(SVarUnexpected);
  243. else
  244. CreateFmt(SUnknownErrorCode,[Code]);
  245. end;
  246. ErrCode:=Code;
  247. end;
  248. {$if defined(win32) or defined(win64) or defined (wince)}
  249. function EExternal.GetExceptionRecord: PExceptionRecord;
  250. begin
  251. result:=@FExceptionRecord;
  252. end;
  253. {$endif win32 or win64 or wince}
  254. {$push}
  255. {$S-}
  256. Procedure CatchUnhandledException (Obj : TObject; Addr: CodePointer; FrameCount: Longint; Frames: PCodePointer);[public,alias:'FPC_BREAK_UNHANDLED_EXCEPTION'];
  257. Var
  258. i : longint;
  259. hstdout : ^text;
  260. begin
  261. if WriteErrorsToStdErr then
  262. hstdout:=@stderr
  263. else
  264. hstdout:=@stdout;
  265. Writeln(hstdout^,'An unhandled exception occurred at $',HexStr(Addr),':');
  266. if Obj is exception then
  267. Writeln(hstdout^,Obj.ClassName,': ',Exception(Obj).Message)
  268. else if Obj is TObject then
  269. Writeln(hstdout^,'Exception object ',Obj.ClassName,' is not of class Exception.')
  270. else
  271. Writeln(hstdout^,'Exception object is not a valid class.');
  272. {$IFDEF HAS_OSERROR}
  273. {$IFDEF DEBUG_EXCEPTIONS_LASTOSERROR}
  274. WriteLn (HStdOut^, 'Last OS error detected in the RTL: ', GetLastOSError);
  275. {$ENDIF DEBUG_EXCEPTIONS_LASTOSERROR}
  276. {$ENDIF HAS_OSERROR}
  277. Writeln(hstdout^,BackTraceStrFunc(Addr));
  278. if (FrameCount>0) then
  279. begin
  280. for i:=0 to FrameCount-1 do
  281. Writeln(hstdout^,BackTraceStrFunc(Frames[i]));
  282. end;
  283. Writeln(hstdout^,'');
  284. end;
  285. type
  286. PExceptMapEntry=^TExceptMapEntry;
  287. TExceptMapEntry=record
  288. code: byte;
  289. cls: ExceptClass;
  290. {$IFDEF FPC_HAS_FEATURE_RESOURCES} // This is necessary for 2.4.4, which does not have reasources as a separate feature
  291. msg: PResStringRec;
  292. {$else FPC_HAS_FEATURE_RESOURCES}
  293. msg: PAnsiString;
  294. {$endif FPC_HAS_FEATURE_RESOURCES}
  295. end;
  296. const
  297. exceptmap: array[0..30] of TExceptMapEntry = (
  298. (code: 200; cls: EDivByZero; msg: @SDivByZero),
  299. (code: 201; cls: ERangeError; msg: @SRangeError),
  300. (code: 202; cls: EStackOverflow; msg: @SStackOverflow),
  301. (code: 205; cls: EOverflow; msg: @SOverflow),
  302. (code: 206; cls: EUnderflow; msg: @SUnderflow),
  303. (code: 207; cls: EInvalidOp; msg: @SInvalidOp),
  304. { Delphi distinguishes reDivByZero from reZeroDivide, but maps both to code 200. }
  305. (code: 208; cls: EZeroDivide; msg: @SZeroDivide),
  306. (code: 210; cls: EObjectCheck; msg: @SObjectCheckError),
  307. (code: 211; cls: EAbstractError; msg: @SAbstractError),
  308. (code: 212; cls: EExternalException; msg: @SExternalException),
  309. (code: 214; cls: EBusError; msg: @SBusError),
  310. (code: 215; cls: EIntOverflow; msg: @SIntOverflow),
  311. (code: 216; cls: EAccessViolation; msg: @SAccessViolation),
  312. (code: 217; cls: EControlC; msg: @SControlC),
  313. (code: 218; cls: EPrivilege; msg: @SPrivilege),
  314. (code: 219; cls: EInvalidCast; msg: @SInvalidCast),
  315. (code: 220; cls: EVariantError; msg: @SInvalidVarCast),
  316. (code: 221; cls: EVariantError; msg: @SInvalidVarOp),
  317. (code: 222; cls: EVariantError; msg: @SDispatchError),
  318. (code: 223; cls: EVariantError; msg: @SVarArrayCreate),
  319. (code: 224; cls: EVariantError; msg: @SVarNotArray),
  320. (code: 225; cls: EVariantError; msg: @SVarArrayBounds),
  321. (code: 227; cls: EAssertionFailed; msg: @SAssertionFailed),
  322. (code: 228; cls: EIntfCastError; msg: @SIntfCastError),
  323. (code: 229; cls: ESafecallException; msg: @SSafecallException),
  324. (code: 231; cls: EConvertError; msg: @SiconvError),
  325. (code: 232; cls: ENoThreadSupport; msg: @SNoThreadSupport),
  326. (code: 233; cls: ESigQuit; msg: @SSigQuit),
  327. (code: 234; cls: ENoWideStringSupport; msg: @SMissingWStringManager),
  328. (code: 235; cls: ENoDynLibsSupport; msg: @SNoDynLibsSupport),
  329. (code: 236; cls: EThreadError; msg: @SThreadError)
  330. );
  331. function FindExceptMapEntry(err: longint): PExceptMapEntry;
  332. var
  333. i: longint;
  334. begin
  335. for i:=low(exceptmap) to high(exceptmap) do
  336. if err=exceptmap[i].code then
  337. begin
  338. result:=@exceptmap[i];
  339. exit;
  340. end;
  341. result:=nil;
  342. end;
  343. Var OutOfMemory : EOutOfMemory;
  344. InValidPointer : EInvalidPointer;
  345. Procedure RunErrorToExcept (ErrNo : Longint; Address : CodePointer; Frame : Pointer);
  346. var
  347. E: Exception;
  348. HS: PResStringRec;
  349. Entry: PExceptMapEntry;
  350. begin
  351. Case Errno of
  352. 1,203 : E:=OutOfMemory;
  353. 204 : E:=InvalidPointer;
  354. else
  355. Entry:=FindExceptMapEntry(ErrNo);
  356. if Assigned(Entry) then
  357. E:=Entry^.cls.CreateRes(Entry^.msg)
  358. else
  359. begin
  360. HS:=nil;
  361. Case Errno of
  362. 2 : HS:=@SFileNotFound;
  363. 3 : HS:=@SInvalidFileName;
  364. 4 : HS:=@STooManyOpenFiles;
  365. 5 : HS:=@SAccessDenied;
  366. 6 : HS:=@SInvalidFileHandle;
  367. 15 : HS:=@SInvalidDrive;
  368. 100 : HS:=@SEndOfFile;
  369. 101 : HS:=@SDiskFull;
  370. 102 : HS:=@SFileNotAssigned;
  371. 103 : HS:=@SFileNotOpen;
  372. 104 : HS:=@SFileNotOpenForInput;
  373. 105 : HS:=@SFileNotOpenForOutput;
  374. 106 : HS:=@SInvalidInput;
  375. end;
  376. if Assigned(HS) then
  377. E:=EInOutError.CreateRes(HS)
  378. else
  379. E:=EInOutError.CreateResFmt(@SUnknownRunTimeError,[errno]);
  380. // this routine can be called from FPC_IOCHECK,
  381. // which clears inoutres and then passes its
  382. // original value to HandleErrorFrame() (which calls
  383. // us). So use errno rather than IOResult, and clear
  384. // InOutRes explicitly in case we can also be called
  385. // from a place that does not clear InOutRes explicitly
  386. EInoutError(E).ErrorCode:=errno;
  387. inoutres:=0;
  388. end;
  389. end;
  390. Raise E at Address,Frame;
  391. end;
  392. {$IFDEF HAS_OSERROR}
  393. Procedure RaiseLastOSError;overload;
  394. begin
  395. RaiseLastOSError(GetLastOSError);
  396. end;
  397. Procedure RaiseLastOSError(LastError: Integer);overload;
  398. var
  399. E : EOSError;
  400. begin
  401. If (LastError<>0) then
  402. E:=EOSError.CreateFmt(SOSError, [LastError, SysErrorMessage(LastError)])
  403. else
  404. E:=EOSError.Create(SUnkOSError);
  405. E.ErrorCode:=LastError;
  406. Raise E;
  407. end;
  408. {$else}
  409. Procedure RaiseLastOSError;overload;
  410. begin
  411. Raise Exception.Create('RaiseLastOSError not implemented on this platform.');
  412. end;
  413. Procedure RaiseLastOSError(LastError: Integer);overload;
  414. begin
  415. RaiseLastOSError;
  416. end;
  417. {$endif}
  418. procedure CheckOSError(LastError: Integer);
  419. begin
  420. if LastError <> 0 then
  421. RaiseLastOSError(LastError);
  422. end;
  423. Procedure AssertErrorHandler (Const Msg,FN : ShortString;LineNo:longint; TheAddr : pointer);
  424. Var
  425. S : String;
  426. begin
  427. If Msg='' then
  428. S:=SAssertionFailed
  429. else
  430. S:=Msg;
  431. Raise EAssertionFailed.Createfmt(SAssertError,[S,Fn,LineNo]) at get_caller_addr(theAddr), get_caller_frame(theAddr);
  432. end;
  433. {$pop} //{$S-} for Error handling functions
  434. Procedure InitExceptions;
  435. {
  436. Must install uncaught exception handler (ExceptProc)
  437. and install exceptions for system exceptions or signals.
  438. (e.g: SIGSEGV -> ESegFault or so.)
  439. }
  440. begin
  441. ExceptionClass := Exception;
  442. ExceptProc:=@CatchUnhandledException;
  443. // Create objects that may have problems when there is no memory.
  444. OutOfMemory:=EOutOfMemory.Create(SOutOfMemory);
  445. OutOfMemory.AllowFree:=false;
  446. InvalidPointer:=EInvalidPointer.Create(SInvalidPointer);
  447. InvalidPointer.AllowFree:=false;
  448. AssertErrorProc:=@AssertErrorHandler;
  449. ErrorProc:=@RunErrorToExcept;
  450. OnShowException:=Nil;
  451. end;
  452. Procedure DoneExceptions;
  453. begin
  454. OutOfMemory.AllowFree:=true;
  455. OutOfMemory.Free;
  456. InValidPointer.AllowFree:=true;
  457. InValidPointer.Free;
  458. end;
  459. { Exception handling routines }
  460. function ExceptObject: TObject;
  461. begin
  462. If RaiseList=Nil then
  463. Result:=Nil
  464. else
  465. Result:=RaiseList^.FObject;
  466. end;
  467. function ExceptAddr: CodePointer;
  468. begin
  469. If RaiseList=Nil then
  470. Result:=Nil
  471. else
  472. Result:=RaiseList^.Addr;
  473. end;
  474. function ExceptFrameCount: Longint;
  475. begin
  476. If RaiseList=Nil then
  477. Result:=0
  478. else
  479. Result:=RaiseList^.Framecount;
  480. end;
  481. function ExceptFrames: PCodePointer;
  482. begin
  483. If RaiseList=Nil then
  484. Result:=Nil
  485. else
  486. Result:=RaiseList^.Frames;
  487. end;
  488. function ExceptionErrorMessage(ExceptObject: TObject; ExceptAddr: Pointer;
  489. Buffer: PAnsiChar; Size: Integer): Integer;
  490. Var
  491. S : AnsiString;
  492. Len : Integer;
  493. begin
  494. S:=Format(SExceptionErrorMessage,[ExceptAddr,ExceptObject.ClassName]);
  495. If ExceptObject is Exception then
  496. S:=Format('%s:'#10'%s',[S,Exception(ExceptObject).Message]);
  497. Len:=Length(S);
  498. If S[Len]<>'.' then
  499. begin
  500. S:=S+'.';
  501. Inc(len);
  502. end;
  503. If Len>Size then
  504. Len:=Size;
  505. if Len > 0 then
  506. Move(S[1],Buffer^,Len);
  507. Result:=Len;
  508. end;
  509. procedure ShowException(ExceptObject: TObject; ExceptAddr: Pointer);
  510. // use shortstring. On exception, the heap may be corrupt.
  511. Var
  512. Buf : ShortString;
  513. begin
  514. SetLength(Buf,ExceptionErrorMessage(ExceptObject,ExceptAddr,@Buf[1],255));
  515. If IsConsole Then
  516. writeln(Buf)
  517. else
  518. If Assigned(OnShowException) Then
  519. OnShowException (Buf);
  520. end;
  521. procedure Abort;
  522. begin
  523. Raise EAbort.Create(SAbortError) at CodePointer(Get_Caller_addr(Get_Frame));
  524. end;
  525. procedure OutOfMemoryError;
  526. begin
  527. Raise OutOfMemory;
  528. end;
  529. { ---------------------------------------------------------------------
  530. Initialization/Finalization/exit code
  531. ---------------------------------------------------------------------}
  532. Type
  533. PPRecord = ^TPRecord;
  534. TPRecord = Record
  535. Func : TTerminateProc;
  536. NextFunc : PPRecord;
  537. end;
  538. Const
  539. TPList : PPRecord = Nil;
  540. procedure AddTerminateProc(TermProc: TTerminateProc);
  541. Var
  542. TPR : PPRecord;
  543. begin
  544. New(TPR);
  545. With TPR^ do
  546. begin
  547. NextFunc:=TPList;
  548. Func:=TermProc;
  549. end;
  550. TPList:=TPR;
  551. end;
  552. function CallTerminateProcs: Boolean;
  553. Var
  554. TPR : PPRecord;
  555. begin
  556. Result:=True;
  557. TPR:=TPList;
  558. While Result and (TPR<>Nil) do
  559. begin
  560. Result:=TPR^.Func();
  561. TPR:=TPR^.NextFunc;
  562. end;
  563. end;
  564. procedure FreeTerminateProcs;
  565. var
  566. TPR1, TPR2: PPRecord;
  567. begin
  568. TPR1 := TPList;
  569. TPList := Nil;
  570. while Assigned(TPR1) do begin
  571. TPR2 := TPR1^.NextFunc;
  572. Dispose(TPR1);
  573. TPR1 := TPR2;
  574. end;
  575. end;
  576. { ---------------------------------------------------------------------
  577. Diskh functions, OS independent.
  578. ---------------------------------------------------------------------}
  579. Function GetCurrentDir: {$ifdef FPC_UNICODE_RTL}UnicodeString{$else}AnsiString{$endif};
  580. begin
  581. GetDir(0,Result);
  582. end;
  583. { ---------------------------------------------------------------------
  584. Other functions, OS independent.
  585. ---------------------------------------------------------------------}
  586. Var
  587. GUIDCalledRandomize : Boolean = False;
  588. Procedure GetRandomBytes(Var Buf; NBytes : Integer);
  589. Var
  590. I : Integer;
  591. P : PByte;
  592. begin
  593. P:=@Buf;
  594. If Not GUIDCalledRandomize then
  595. begin
  596. Randomize;
  597. GUIDCalledRandomize:=True;
  598. end;
  599. For I:=0 to NBytes-1 do
  600. P[i]:=Random(256);
  601. end;
  602. {$IFDEF HASCREATEGUID}
  603. Function SysCreateGUID(out GUID : TGUID) : Integer; forward;
  604. {$ENDIF}
  605. Function CreateGUID(out GUID : TGUID) : Integer;
  606. begin
  607. If Assigned(OnCreateGUID) then
  608. Result:=OnCreateGUID(GUID)
  609. else
  610. begin
  611. {$IFDEF HASCREATEGUID}
  612. Result:=SysCreateGUID(GUID);
  613. {$ELSE}
  614. GetRandomBytes(GUID,SizeOf(Guid));
  615. guid.clock_seq_hi_and_reserved:=(guid.clock_seq_hi_and_reserved and $3F) + 64;
  616. guid.time_hi_and_version :=(guid.time_hi_and_version and $0FFF)+ $4000;
  617. Result:=0;
  618. {$ENDIF}
  619. end;
  620. end;
  621. function SafeLoadLibrary(const FileName: AnsiString; ErrorMode: DWord = {$ifdef windows}SEM_NOOPENFILEERRORBOX{$else windows}0{$endif windows}): HMODULE;
  622. {$if defined(win64) or defined(win32)}
  623. var
  624. mode : DWord;
  625. begin
  626. mode:=SetErrorMode(ErrorMode);
  627. try
  628. Result:=System.SafeLoadLibrary(FileName);
  629. finally
  630. SetErrorMode(mode);
  631. end;
  632. end;
  633. {$else}
  634. begin
  635. {$ifdef FPC_HAS_FEATURE_DYNLIBS}
  636. Result:=System.SafeLoadLibrary(FileName);
  637. {$else}
  638. Result:=HModule(nil);
  639. {$endif not FPC_HAS_FEATURE_DYNLIBS}
  640. end;
  641. {$endif}
  642. {$if defined(win32) or defined(win64) or defined(wince)}
  643. function GetModuleName(Module: HMODULE): string;
  644. var
  645. ResultLength, BufferLength: DWORD;
  646. Buffer: UnicodeString;
  647. begin
  648. BufferLength := MAX_PATH div 2;
  649. repeat
  650. Inc(BufferLength, BufferLength);
  651. SetLength(Buffer, BufferLength);
  652. ResultLength := GetModuleFileNameW(Module, Pointer(Buffer), BufferLength);
  653. if ResultLength = 0 then
  654. Exit('');
  655. until ResultLength < BufferLength;
  656. SetLength(Buffer, ResultLength);
  657. Result := Buffer;
  658. end;
  659. {$elseif defined(win16)}
  660. function GetModuleName(Module: HMODULE): string;
  661. var
  662. ResultLength, BufferLength: DWORD;
  663. Buffer: RawByteString;
  664. begin
  665. BufferLength := MAX_PATH div 2;
  666. repeat
  667. Inc(BufferLength, BufferLength);
  668. SetLength(Buffer, BufferLength);
  669. ResultLength := GetModuleFileName(Module, FarAddr(Buffer[1]), BufferLength);
  670. if ResultLength = 0 then
  671. Exit('');
  672. until ResultLength < BufferLength;
  673. SetLength(Buffer, ResultLength);
  674. Result := Buffer;
  675. end;
  676. {$else}
  677. function GetModuleName(Module: HMODULE): string;
  678. begin
  679. Result:='';
  680. end;
  681. {$endif}
  682. { Beep support }
  683. procedure Beep;
  684. begin
  685. If Assigned(OnBeep) then
  686. OnBeep;
  687. end;
  688. // OSes that only provide 1 byte versions can enable the following define
  689. {$ifdef executeprocuni}
  690. function ExecuteProcess(Const Path: UnicodeString; Const ComLine: UnicodeString;Flags:TExecuteFlags=[]):integer;
  691. begin
  692. result:=ExecuteProcess(ToSingleByteFileSystemEncodedFileName(Path),ToSingleByteFileSystemEncodedFileName(ComLine));
  693. end;
  694. function ExecuteProcess(Const Path: UnicodeString; Const ComLine: Array of UnicodeString;Flags:TExecuteFlags=[]):integer;
  695. var
  696. ComLineA : array of RawByteString;
  697. I : Integer;
  698. begin
  699. SetLength(ComLineA,high(comline)-low(comline)+1);
  700. For I:=0 to length(ComLineA)-1 Do
  701. ComLineA[i]:=ToSingleByteFileSystemEncodedFileName(ComLine[I]);
  702. result:=ExecuteProcess(ToSingleByteFileSystemEncodedFileName(Path),ComLineA);
  703. end;
  704. {$endif}
  705. // generic ifthen..
  706. {$IFNDEF VER3_0}
  707. generic function IfThen<T>(val:boolean;const iftrue:T; const iffalse:T) :T; inline; overload;
  708. begin
  709. if val then
  710. Result := ifTrue
  711. else
  712. Result:=ifFalse;
  713. end;
  714. {$ENDIF}
  715. Function ArrayOfConstToStrArray(Args: array of const) : TUTF8StringDynArray;
  716. var
  717. i: Integer;
  718. O : TObject;
  719. C : TClass;
  720. S : String;
  721. begin
  722. SetLength(Result,Length(Args));
  723. for i:=Low(Args) to High(Args) do
  724. case Args[i].VType of
  725. vtInteger: Result[i]:=IntToStr(Args[i].VInteger);
  726. vtBoolean: Result[i]:=BoolToStr(Args[i].VBoolean);
  727. vtChar: Result[i] := Args[i].VChar;
  728. {$ifndef FPUNONE}
  729. vtExtended: Result[i]:= FloatToStr(Args[i].VExtended^);
  730. {$ENDIF}
  731. vtString: Result[i] := Args[i].VString^;
  732. vtPointer: Result[i] := '0x'+HexStr(PtrInt(Args[i].VPointer),SizeOF(PtrInt));
  733. vtPChar: Result[i] := Args[i].VPChar;
  734. vtObject:
  735. begin
  736. O:=Args[i].VObject;
  737. if Assigned(O) then
  738. begin
  739. try
  740. S:=O.ClassName;
  741. except
  742. S:='<Invalid instance>';
  743. end;
  744. end
  745. else
  746. S:='';
  747. Result[I] := '<Object '+S+' 0x'+HexStr(PtrInt(O),SizeOF(PtrInt))+'>';
  748. end;
  749. vtClass:
  750. begin
  751. C:=Args[i].VClass;
  752. if Assigned(C) then
  753. begin
  754. try
  755. S:=C.ClassName;
  756. except
  757. S:='<Invalid Class>';
  758. end;
  759. end
  760. else
  761. S:='';
  762. Result[I] := '<Class '+S+' 0x'+HexStr(PtrInt(C),SizeOF(PtrInt))+'>';
  763. end;
  764. vtWideChar: Result[i] := UTF8Encode(Args[i].VWideChar);
  765. vtPWideChar: Result[i] := UTF8Encode(Args[i].VPWideChar^);
  766. vtAnsiString: Result[i] := AnsiString(Args[i].VAnsiString);
  767. vtCurrency: Result[i] := FLoatToSTr(Args[i].VCurrency^);
  768. vtVariant: Result[i] := Args[i].VVariant^;
  769. vtInterface: Result[I] := '<Interface 0x'+HexStr(PtrInt(Args[i].VInterface),SizeOF(PtrInt))+'>';
  770. vtWidestring: Result[i] := UTF8ENcode(WideString(Args[i].VWideString));
  771. vtInt64: Result[i] := IntToStr(Args[i].VInt64^);
  772. vtQWord: Result[i] := IntToStr(Args[i].VQWord^);
  773. vtUnicodeString:Result[i] := UTF8Encode(UnicodeString(Args[i].VUnicodeString));
  774. end;
  775. end;
  776. Function ArrayOfConstToStr(Args: array of const ; aSeparator : Char = ','; aQuoteBegin : Char = '"'; aQuoteEnd : Char = '"') : UTF8String;
  777. Procedure Add(s: UTF8String);
  778. begin
  779. if aQuoteBegin<>#0 then
  780. S:=aQuoteBegin+S;
  781. if aQuoteEnd<>#0 then
  782. S:=S+aQuoteEnd;
  783. if Result<>'' then
  784. Result:=Result+aSeparator;
  785. Result:=Result+S;
  786. end;
  787. Var
  788. S : UTF8String;
  789. begin
  790. Result:='';
  791. For S in ArrayOfConstToStrArray(Args) do
  792. Add(S);
  793. end;
  794. Function GetCompiledArchitecture : TOSVersion.TArchitecture;
  795. begin
  796. Result:=arOther;
  797. {$ifdef i386}
  798. Result:=arIntelX86;
  799. {$endif i386}
  800. {$ifdef m68k}
  801. Result:=arM68k;
  802. {$endif m68k}
  803. {$ifdef powerpc}
  804. Result:=arPowerPC
  805. {$endif powerpc}
  806. {$ifdef powerpc64}
  807. Result:=arPower64
  808. {$endif powerpc64}
  809. {$ifdef arm}
  810. Result:=arARM32;
  811. {$endif arm}
  812. {$ifdef aarch64}
  813. Result:=arARM64
  814. {$endif aarch64}
  815. {$ifdef sparc}
  816. Result:=arSparc;
  817. {$endif sparc}
  818. {$ifdef sparc64}
  819. Result:=arSparc64;
  820. {$endif sparc64}
  821. {$ifdef CPUX86_64}
  822. Result:=arIntelX64;
  823. {$endif x86_64}
  824. {$ifdef mipsel}
  825. Result:=arMipsel
  826. {$else : not mipsel}
  827. {$ifdef mips}
  828. Result:=arMips;
  829. {$endif mips}
  830. {$endif not mipsel}
  831. {$ifdef riscv32}
  832. Result:=arRiscV32;
  833. {$endif riscv32}
  834. {$ifdef riscv64}
  835. Result:=arRiscV64;
  836. {$endif riscv64}
  837. {$ifdef xtensa}
  838. Result:=arExtensa;
  839. {$endif xtensa}
  840. {$ifdef wasm32}
  841. Result:=arWasm32;
  842. {$endif wasm32}
  843. {$ifdef loongarch64}
  844. Result:=arLoongArch64;
  845. {$endif loongarch64}
  846. end;
  847. Function GetCompiledPlatform : TOSVersion.TPlatform;
  848. begin
  849. Result:=pfOther;
  850. {$IFDEF WINDOWS}
  851. Result:=pfWindows;
  852. {$ENDIF}
  853. {$Ifdef darwin}
  854. Result:=pfMacOS;
  855. {$ENDIF}
  856. {$IFDEF IOS}
  857. Result:=pfiOS;
  858. {$ENDIF}
  859. {$IFDEF ANDROID}
  860. Result:=pfAndroid;
  861. {$ENDIF}
  862. {$IFDEF LINUX}
  863. Result:=pfLinux;
  864. {$ENDIF}
  865. {$IFDEF GO32V2}
  866. Result:=pfGo32v2;
  867. {$ENDIF}
  868. {$IFDEF OS2}
  869. Result:=pfOS2;
  870. {$ENDIF}
  871. {$IFDEF FREEBSD}
  872. Result:=pfFreeBSD;
  873. {$ENDIF}
  874. {$IFDEF BEOS}
  875. Result:=pfBeos;
  876. {$ENDIF}
  877. {$IFDEF NETBSD}
  878. Result:=pfNetBSD;
  879. {$ENDIF}
  880. {$IFDEF AMIGA}
  881. Result:=pfAmiga;
  882. {$ENDIF}
  883. {$IFDEF ATARI}
  884. Result:=pfAtari;
  885. {$ENDIF}
  886. {$IFDEF SUNOS}
  887. Result:=pfSolaris;
  888. {$ENDIF}
  889. {$IFDEF QNX}
  890. Result:=pfQNX;
  891. {$ENDIF}
  892. {$IFDEF Netware}
  893. Result:=pfNetware;
  894. {$ENDIF}
  895. {$IFDEF OpenBSD}
  896. Result:=pfOpenBSD;
  897. {$ENDIF}
  898. {$IFDEF WDosX}
  899. Result:=pfWDosX;
  900. {$ENDIF}
  901. {$IFDEF PALMOS}
  902. Result:=pfPalmos;
  903. {$ENDIF}
  904. {$IFDEF MacOSClassic}
  905. Result:=pfMacOSClassic;
  906. {$ENDIF}
  907. {$IFDEF DARWIN}
  908. Result:=pfDarwin;
  909. {$ENDIF}
  910. {$IFDEF EMX}
  911. Result:=pfEMX;
  912. {$ENDIF}
  913. {$IFDEF WATCOM}
  914. Result:=pfWatcom;
  915. {$ENDIF}
  916. {$IFDEF MORPHOS}
  917. Result:=pfMorphos;
  918. {$ENDIF}
  919. {$IFDEF NETWLIBC}
  920. Result:=pfNetwLibC;
  921. {$ENDIF}
  922. {$IFDEF WINCE}
  923. Result:=pfWinCE;
  924. {$ENDIF}
  925. {$IFDEF GBA}
  926. Result:=pfGBA;
  927. {$ENDIF}
  928. {$IFDEF NDS}
  929. Result:=pfNDS;
  930. {$ENDIF}
  931. {$IFDEF EMBEDDED}
  932. Result:=pfEmbedded;
  933. {$ENDIF}
  934. {$IFDEF SYMBIAN}
  935. Result:=pfSymbian;
  936. {$ENDIF}
  937. {$IFDEF HAIKU}
  938. Result:=pfHaiku;
  939. {$ENDIF}
  940. {$IFDEF IPHONESIM}
  941. Result:=pfIPhoneSim;
  942. {$ENDIF}
  943. {$IFDEF AIX}
  944. Result:=pfAIX;
  945. {$ENDIF}
  946. {$IFDEF JAVA}
  947. Result:=pfJava;
  948. {$ENDIF}
  949. {$IFDEF NATIVENT}
  950. Result:=pfNativeNT;
  951. {$ENDIF}
  952. {$IFDEF MSDOS}
  953. Result:=pfMSDos;
  954. {$ENDIF}
  955. {$IFDEF WII}
  956. Result:=pfWII;
  957. {$ENDIF}
  958. {$IFDEF AROS}
  959. Result:=pfAROS;
  960. {$ENDIF}
  961. {$IFDEF DRAGONFLY}
  962. Result:=pfDragonFly;
  963. {$ENDIF}
  964. {$IFDEF WIN16}
  965. Result:=pfWin16;
  966. {$ENDIF}
  967. {$IFDEF FREERTOS}
  968. Result:=pfFreeRTOS;
  969. {$ENDIF}
  970. {$IFDEF ZXSPECTRUM}
  971. Result:=pfZXSpectrum;
  972. {$ENDIF}
  973. {$IFDEF MSXDOS}
  974. Result:=pfMSXDOS;
  975. {$ENDIF}
  976. {$IFDEF AMSTRADCPC}
  977. Result:=pfAmstradCPC;
  978. {$ENDIF}
  979. {$IFDEF SINCLAIRQL}
  980. Result:=pfSinclairQL;
  981. {$ENDIF}
  982. {$IFDEF WASI}
  983. Result:=pfWasi;
  984. {$ENDIF}
  985. end;
  986. class constructor TOSVersion.Create;
  987. {$IFNDEF HAS_OSVERSION}
  988. var
  989. S : String;
  990. {$ENDIF}
  991. begin
  992. FArchitecture:=GetCompiledArchitecture;
  993. FPlatform:=GetCompiledPlatform;
  994. FBuild:=0;
  995. FMajor:=0;
  996. FMinor:=0;
  997. FServicePackMajor:=0;
  998. FServicePackMinor:=0;
  999. {$IFDEF HAS_OSVERSION}
  1000. InitOSVersion;
  1001. {$ELSE}
  1002. WriteStr(S,GetCompiledPlatform);
  1003. FName:=Copy(S,3);
  1004. WriteStr(S,GetCompiledArchitecture);
  1005. FFull:=Copy(S,3)+'-'+FName;
  1006. {$ENDIF}
  1007. end;
  1008. class function TOSVersion.Check(aMajor: Integer): Boolean; overload; static; inline;
  1009. begin
  1010. Result:=(Major>=aMajor);
  1011. end;
  1012. class function TOSVersion.Check(aMajor, aMinor: Integer): Boolean; overload; static; inline;
  1013. begin
  1014. Result:=(Major>aMajor)
  1015. or ((Major=aMajor) and (Minor>=aMinor))
  1016. end;
  1017. class function TOSVersion.Check(aMajor, aMinor, aServicePackMajor: Integer): Boolean; overload; static; inline;
  1018. begin
  1019. Result:=(Major>AMajor)
  1020. or ((Major=aMajor) and (Minor>aMinor))
  1021. or ((Major=aMajor) and (Minor=aMinor) and (ServicePackMajor>=aServicePackMajor));
  1022. end;
  1023. class function TOSVersion.ToString: string; static;
  1024. begin
  1025. Result:=FFull;
  1026. end;