sysutils.inc 14 KB

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