sysutils.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. { Read filename handling functions implementation }
  12. {$i fina.inc}
  13. { variant error codes }
  14. {$i varerror.inc}
  15. Function FileSearch (Const Name, DirList : String) : String;
  16. Var
  17. I : longint;
  18. Temp : String;
  19. begin
  20. // Start with checking the file in the current directory
  21. Result:=Name;
  22. temp:=SetDirSeparators(DirList);
  23. repeat
  24. If (Result<>'') and FileExists(Result) Then
  25. exit;
  26. I:=pos(PathSeparator,Temp);
  27. If I<>0 then
  28. begin
  29. Result:=Copy (Temp,1,i-1);
  30. system.Delete(Temp,1,I);
  31. end
  32. else
  33. begin
  34. Result:=Temp;
  35. Temp:='';
  36. end;
  37. if Result<>'' then
  38. Result:=IncludeTrailingPathDelimiter(Result)+name;
  39. until temp='';
  40. result:='';
  41. end;
  42. {$ifndef OS_FILEISREADONLY}
  43. Function FileIsReadOnly(const FileName: String): Boolean;
  44. begin
  45. Result := (FileGetAttr(FileName) and faReadOnly) <> 0;
  46. end;
  47. {$endif OS_FILEISREADONLY}
  48. {$ifndef OS_FILESETDATEBYNAME}
  49. Function FileSetDate (Const FileName : String;Age : Longint) : Longint;
  50. Var
  51. fd : THandle;
  52. begin
  53. { at least windows requires fmOpenWrite here }
  54. fd:=FileOpen(FileName,fmOpenWrite);
  55. If (Fd<>feInvalidHandle) then
  56. try
  57. Result:=FileSetDate(fd,Age);
  58. finally
  59. FileClose(fd);
  60. end
  61. else
  62. Result:=fd;
  63. end;
  64. {$endif}
  65. { Read String Handling functions implementation }
  66. {$i sysstr.inc}
  67. { Read date & Time function implementations }
  68. {$i dati.inc}
  69. { Read pchar handling functions implementation }
  70. {$i syspch.inc}
  71. { generic internationalisation code }
  72. {$i sysint.inc}
  73. { MCBS functions }
  74. {$i sysansi.inc}
  75. { wide string functions }
  76. {$i syswide.inc}
  77. { threading stuff }
  78. {$i sysuthrd.inc}
  79. { OS utility code }
  80. {$i osutil.inc}
  81. procedure FreeAndNil(var obj);
  82. var
  83. temp: tobject;
  84. begin
  85. temp:=tobject(obj);
  86. pointer(obj):=nil;
  87. temp.free;
  88. end;
  89. { Interfaces support }
  90. {$i sysuintf.inc}
  91. constructor Exception.Create(const msg : string);
  92. begin
  93. inherited create;
  94. fmessage:=msg;
  95. end;
  96. constructor Exception.CreateFmt(const msg : string; const args : array of const);
  97. begin
  98. inherited create;
  99. fmessage:=Format(msg,args);
  100. end;
  101. constructor Exception.CreateRes(ResString: PString);
  102. begin
  103. inherited create;
  104. fmessage:=ResString^;
  105. end;
  106. constructor Exception.CreateResFmt(ResString: PString; const Args: array of const);
  107. begin
  108. inherited create;
  109. fmessage:=Format(ResString^,args);
  110. end;
  111. constructor Exception.CreateHelp(const Msg: string; AHelpContext: Integer);
  112. begin
  113. inherited create;
  114. fmessage:=Msg;
  115. fhelpcontext:=AHelpContext;
  116. end;
  117. constructor Exception.CreateFmtHelp(const Msg: string; const Args: array of const;
  118. AHelpContext: Integer);
  119. begin
  120. inherited create;
  121. fmessage:=Format(Msg,args);
  122. fhelpcontext:=AHelpContext;
  123. end;
  124. constructor Exception.CreateResHelp(ResString: PString; AHelpContext: Integer);
  125. begin
  126. inherited create;
  127. fmessage:=ResString^;
  128. fhelpcontext:=AHelpContext;
  129. end;
  130. constructor Exception.CreateResFmtHelp(ResString: PString; const Args: array of const;
  131. AHelpContext: Integer);
  132. begin
  133. inherited create;
  134. fmessage:=Format(ResString^,args);
  135. fhelpcontext:=AHelpContext;
  136. end;
  137. procedure EHeapMemoryError.FreeInstance;
  138. begin
  139. if AllowFree then
  140. inherited FreeInstance;
  141. end;
  142. Constructor EVariantError.CreateCode (Code : longint);
  143. begin
  144. case Code of
  145. VAR_OK:
  146. Create(SNoError);
  147. VAR_PARAMNOTFOUND:
  148. Create(SVarParamNotFound);
  149. VAR_TYPEMISMATCH:
  150. Create(SInvalidVarCast);
  151. VAR_BADVARTYPE:
  152. Create(SVarBadType);
  153. VAR_OVERFLOW:
  154. Create(SVarOverflow);
  155. VAR_BADINDEX:
  156. Create(SVarArrayBounds);
  157. VAR_ARRAYISLOCKED:
  158. Create(SVarArrayLocked);
  159. VAR_NOTIMPL:
  160. Create(SVarNotImplemented);
  161. VAR_OUTOFMEMORY:
  162. Create(SVarOutOfMemory);
  163. VAR_INVALIDARG:
  164. Create(SVarInvalid);
  165. VAR_UNEXPECTED,
  166. VAR_EXCEPTION:
  167. Create(SVarUnexpected);
  168. else
  169. CreateFmt(SUnknownErrorCode,[Code]);
  170. end;
  171. ErrCode:=Code;
  172. end;
  173. {$ifopt S+}
  174. {$define STACKCHECK_WAS_ON}
  175. {$S-}
  176. {$endif OPT S }
  177. Procedure CatchUnhandledException (Obj : TObject; Addr: Pointer; FrameCount: Longint; Frames: PPointer);[public,alias:'FPC_BREAK_UNHANDLED_EXCEPTION'];
  178. Var
  179. Message : String;
  180. i : longint;
  181. hstdout : ^text;
  182. begin
  183. hstdout:=@stdout;
  184. Writeln(hstdout^,'An unhandled exception occurred at $',HexStr(PtrUInt(Addr),sizeof(PtrUInt)*2),' :');
  185. if Obj is exception then
  186. begin
  187. Message:=Exception(Obj).ClassName+' : '+Exception(Obj).Message;
  188. Writeln(hstdout^,Message);
  189. end
  190. else
  191. Writeln(hstdout^,'Exception object ',Obj.ClassName,' is not of class Exception.');
  192. Writeln(hstdout^,BackTraceStrFunc(Addr));
  193. if (FrameCount>0) then
  194. begin
  195. for i:=0 to FrameCount-1 do
  196. Writeln(hstdout^,BackTraceStrFunc(Frames[i]));
  197. end;
  198. Writeln(hstdout^,'');
  199. end;
  200. Var OutOfMemory : EOutOfMemory;
  201. InValidPointer : EInvalidPointer;
  202. Procedure RunErrorToExcept (ErrNo : Longint; Address,Frame : Pointer);
  203. Var E : Exception;
  204. HS : PString;
  205. begin
  206. Case Errno of
  207. 1,203 : E:=OutOfMemory;
  208. 204 : E:=InvalidPointer;
  209. 2,3,4,5,6,100,101,102,103,105,106 : { I/O errors }
  210. begin
  211. Case Errno of
  212. 2 : HS:=@SFileNotFound;
  213. 3 : HS:=@SInvalidFileName;
  214. 4 : HS:=@STooManyOpenFiles;
  215. 5 : HS:=@SAccessDenied;
  216. 6 : HS:=@SInvalidFileHandle;
  217. 15 : HS:=@SInvalidDrive;
  218. 100 : HS:=@SEndOfFile;
  219. 101 : HS:=@SDiskFull;
  220. 102 : HS:=@SFileNotAssigned;
  221. 103 : HS:=@SFileNotOpen;
  222. 104 : HS:=@SFileNotOpenForInput;
  223. 105 : HS:=@SFileNotOpenForOutput;
  224. 106 : HS:=@SInvalidInput;
  225. end;
  226. E:=EinOutError.Create (HS^);
  227. EInoutError(E).ErrorCode:=IOresult; // Clears InOutRes !!
  228. end;
  229. // We don't set abstracterrorhandler, but we do it here.
  230. // Unless the use sets another handler we'll get here anyway...
  231. 200 : E:=EDivByZero.Create(SDivByZero);
  232. 201 : E:=ERangeError.Create(SRangeError);
  233. 205 : E:=EOverflow.Create(SOverflow);
  234. 206 : E:=EOverflow.Create(SUnderflow);
  235. 207 : E:=EInvalidOp.Create(SInvalidOp);
  236. 211 : E:=EAbstractError.Create(SAbstractError);
  237. 212 : E:=EExternalException.Create(SExternalException);
  238. 214 : E:=EBusError.Create(SBusError);
  239. 215 : E:=EIntOverflow.Create(SIntOverflow);
  240. 216 : E:=EAccessViolation.Create(SAccessViolation);
  241. 217 : E:=EControlC.Create(SControlC);
  242. 218 : E:=EPrivilege.Create(SPrivilege);
  243. 219 : E:=EInvalidCast.Create(SInvalidCast);
  244. 220 : E:=EVariantError.Create(SInvalidVarCast);
  245. 221 : E:=EVariantError.Create(SInvalidVarOp);
  246. 222 : E:=EVariantError.Create(SDispatchError);
  247. 223 : E:=EVariantError.Create(SVarArrayCreate);
  248. 224 : E:=EVariantError.Create(SVarNotArray);
  249. 225 : E:=EVariantError.Create(SVarArrayBounds);
  250. 227 : E:=EAssertionFailed.Create(SAssertionFailed);
  251. 228 : E:=EIntfCastError.Create(SIntfCastError);
  252. 229 : E:=ESafecallException.Create(SSafecallException);
  253. 231 : E:=EConvertError.Create(SiconvError);
  254. 232 : E:=ENoThreadSupport.Create(SNoThreadSupport);
  255. else
  256. E:=Exception.CreateFmt (SUnKnownRunTimeError,[Errno]);
  257. end;
  258. Raise E at Address,Frame;
  259. end;
  260. {$IFDEF HAS_OSERROR}
  261. Procedure RaiseLastOSError;
  262. var
  263. ECode: Cardinal;
  264. E : EOSError;
  265. begin
  266. ECode := GetLastOSError;
  267. If (ECode<>0) then
  268. E:=EOSError.CreateFmt(SOSError, [ECode, SysErrorMessage(ECode)])
  269. else
  270. E:=EOSError.Create(SUnkOSError);
  271. E.ErrorCode:=ECode;
  272. Raise E;
  273. end;
  274. {$else}
  275. Procedure RaiseLastOSError;
  276. begin
  277. Raise Exception.Create('RaiseLastOSError not implemented on this platform.');
  278. end;
  279. {$endif}
  280. Procedure AssertErrorHandler (Const Msg,FN : ShortString;LineNo:longint; TheAddr : pointer);
  281. Var
  282. S : String;
  283. begin
  284. If Msg='' then
  285. S:=SAssertionFailed
  286. else
  287. S:=Msg;
  288. Raise EAssertionFailed.Createfmt(SAssertError,[S,Fn,LineNo]) at Pointer(theAddr);
  289. end;
  290. {$ifdef STACKCHECK_WAS_ON}
  291. {$S+}
  292. {$endif}
  293. Procedure InitExceptions;
  294. {
  295. Must install uncaught exception handler (ExceptProc)
  296. and install exceptions for system exceptions or signals.
  297. (e.g: SIGSEGV -> ESegFault or so.)
  298. }
  299. begin
  300. ExceptionClass := Exception;
  301. ExceptProc:=@CatchUnhandledException;
  302. // Create objects that may have problems when there is no memory.
  303. OutOfMemory:=EOutOfMemory.Create(SOutOfMemory);
  304. OutOfMemory.AllowFree:=false;
  305. InvalidPointer:=EInvalidPointer.Create(SInvalidPointer);
  306. InvalidPointer.AllowFree:=false;
  307. AssertErrorProc:=@AssertErrorHandler;
  308. ErrorProc:=@RunErrorToExcept;
  309. OnShowException:=Nil;
  310. end;
  311. Procedure DoneExceptions;
  312. begin
  313. OutOfMemory.AllowFree:=true;
  314. OutOfMemory.Free;
  315. InValidPointer.AllowFree:=true;
  316. InValidPointer.Free;
  317. end;
  318. { Exception handling routines }
  319. function ExceptObject: TObject;
  320. begin
  321. If RaiseList=Nil then
  322. Result:=Nil
  323. else
  324. Result:=RaiseList^.FObject;
  325. end;
  326. function ExceptAddr: Pointer;
  327. begin
  328. If RaiseList=Nil then
  329. Result:=Nil
  330. else
  331. Result:=RaiseList^.Addr;
  332. end;
  333. function ExceptFrameCount: Longint;
  334. begin
  335. If RaiseList=Nil then
  336. Result:=0
  337. else
  338. Result:=RaiseList^.Framecount;
  339. end;
  340. function ExceptFrames: PPointer;
  341. begin
  342. If RaiseList=Nil then
  343. Result:=Nil
  344. else
  345. Result:=RaiseList^.Frames;
  346. end;
  347. function ExceptionErrorMessage(ExceptObject: TObject; ExceptAddr: Pointer;
  348. Buffer: PChar; Size: Integer): Integer;
  349. Var
  350. S : AnsiString;
  351. Len : Integer;
  352. begin
  353. S:=Format(SExceptionErrorMessage,[ExceptAddr,ExceptObject.ClassName]);
  354. If ExceptObject is Exception then
  355. S:=Format('%s:'#10'%s',[S,Exception(ExceptObject).Message]);
  356. Len:=Length(S);
  357. If S[Len]<>'.' then
  358. begin
  359. S:=S+'.';
  360. Inc(len);
  361. end;
  362. If Len>Size then
  363. Len:=Size;
  364. if Len > 0 then
  365. Move(S[1],Buffer^,Len);
  366. Result:=Len;
  367. end;
  368. procedure ShowException(ExceptObject: TObject; ExceptAddr: Pointer);
  369. // use shortstring. On exception, the heap may be corrupt.
  370. Var
  371. Buf : ShortString;
  372. begin
  373. SetLength(Buf,ExceptionErrorMessage(ExceptObject,ExceptAddr,@Buf[1],255));
  374. If IsConsole Then
  375. writeln(Buf)
  376. else
  377. If Assigned(OnShowException) Then
  378. OnShowException (Buf);
  379. end;
  380. procedure Abort;
  381. begin
  382. Raise EAbort.Create(SAbortError) at Pointer(Get_Caller_addr(Get_Frame));
  383. end;
  384. procedure OutOfMemoryError;
  385. begin
  386. Raise OutOfMemory;
  387. end;
  388. { ---------------------------------------------------------------------
  389. Initialization/Finalization/exit code
  390. ---------------------------------------------------------------------}
  391. Type
  392. PPRecord = ^TPRecord;
  393. TPRecord = Record
  394. Func : TTerminateProc;
  395. NextFunc : PPRecord;
  396. end;
  397. Const
  398. TPList : PPRecord = Nil;
  399. procedure AddTerminateProc(TermProc: TTerminateProc);
  400. Var
  401. TPR : PPRecord;
  402. begin
  403. New(TPR);
  404. With TPR^ do
  405. begin
  406. NextFunc:=TPList;
  407. Func:=TermProc;
  408. end;
  409. TPList:=TPR;
  410. end;
  411. function CallTerminateProcs: Boolean;
  412. Var
  413. TPR : PPRecord;
  414. begin
  415. Result:=True;
  416. TPR:=TPList;
  417. While Result and (TPR<>Nil) do
  418. begin
  419. Result:=TPR^.Func();
  420. TPR:=TPR^.NextFunc;
  421. end;
  422. end;
  423. { ---------------------------------------------------------------------
  424. Diskh functions, OS independent.
  425. ---------------------------------------------------------------------}
  426. function ForceDirectories(Const Dir: string): Boolean;
  427. var
  428. E: EInOutError;
  429. ADrv : String;
  430. function DoForceDirectories(Const Dir: string): Boolean;
  431. var
  432. ADir : String;
  433. begin
  434. Result:=True;
  435. ADir:=ExcludeTrailingPathDelimiter(Dir);
  436. if (ADir='') then Exit;
  437. if Not DirectoryExists(ADir) then
  438. begin
  439. Result:=DoForceDirectories(ExtractFilePath(ADir));
  440. If Result then
  441. Result := CreateDir(ADir);
  442. end;
  443. end;
  444. begin
  445. Result := False;
  446. ADrv := ExtractFileDrive(Dir);
  447. if (ADrv<>'') and (not DirectoryExists(ADrv)) then Exit;
  448. if Dir='' then
  449. begin
  450. E:=EInOutError.Create(SCannotCreateEmptyDir);
  451. E.ErrorCode:=3;
  452. Raise E;
  453. end;
  454. Result := DoForceDirectories(SetDirSeparators(Dir));
  455. end;
  456. Procedure GetRandomBytes(Var Buf; NBytes : Integer);
  457. Var
  458. I : Integer;
  459. P : PByte;
  460. begin
  461. P:=@Buf;
  462. Randomize;
  463. For I:=0 to NBytes-1 do
  464. P[i]:=Random(256);
  465. end;
  466. {$IFDEF HASCREATEGUID}
  467. Function SysCreateGUID(out GUID : TGUID) : Integer; forward;
  468. {$ENDIF}
  469. Function CreateGUID(out GUID : TGUID) : Integer;
  470. begin
  471. If Assigned(OnCreateGUID) then
  472. Result:=OnCreateGUID(GUID)
  473. else
  474. begin
  475. {$IFDEF HASCREATEGUID}
  476. Result:=SysCreateGUID(GUID);
  477. {$ELSE}
  478. GetRandomBytes(GUID,SizeOf(Guid));
  479. Result:=0;
  480. {$ENDIF}
  481. end;
  482. end;
  483. function SafeLoadLibrary(const FileName: AnsiString;
  484. ErrorMode: DWord = {$ifdef windows}SEM_NOOPENFILEERRORBOX{$else windows}0{$endif windows}): HMODULE;
  485. {$if defined(cpui386) or defined(cpux86_64)}
  486. var
  487. mode : DWord;
  488. fpucw : Word;
  489. ssecw : DWord;
  490. {$endif}
  491. begin
  492. {$if defined(win64) or defined(win32)}
  493. mode:=SetErrorMode(ErrorMode);
  494. {$endif}
  495. try
  496. {$if defined(cpui386) or defined(cpux86_64)}
  497. fpucw:=Get8087CW;
  498. {$ifdef cpui386}
  499. if has_sse_support then
  500. {$endif cpui386}
  501. ssecw:=GetSSECSR;
  502. {$endif}
  503. {$if defined(windows) or defined(win32)}
  504. Result:=LoadLibraryA(PChar(Filename));
  505. {$else}
  506. Result:=0;
  507. {$endif}
  508. finally
  509. {$if defined(cpui386) or defined(cpux86_64)}
  510. Set8087CW(fpucw);
  511. {$ifdef cpui386}
  512. if has_sse_support then
  513. {$endif cpui386}
  514. SetSSECSR(ssecw);
  515. {$endif}
  516. {$if defined(win64) or defined(win32)}
  517. SetErrorMode(mode);
  518. {$endif}
  519. end;
  520. end;
  521. function GetModuleName(Module: HMODULE): string;
  522. begin
  523. {$ifdef MSWINDOWS}
  524. SetLength(Result,MAX_PATH);
  525. SetLength(Result,GetModuleFileName(Module, Pchar(Result),Length(Result)));
  526. {$ELSE}
  527. Result:='';
  528. {$ENDIF}
  529. end;