system.pas 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223
  1. {
  2. ****************************************************************************
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2005 by Free Pascal development team
  5. Free Pascal - OS/2 runtime library
  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. unit system;
  13. interface
  14. {$ifdef SYSTEMDEBUG}
  15. {$define SYSTEMEXCEPTIONDEBUG}
  16. {.$define IODEBUG}
  17. {.$define DEBUGENVIRONMENT}
  18. {.$define DEBUGARGUMENTS}
  19. {$endif SYSTEMDEBUG}
  20. {$DEFINE OS2EXCEPTIONS}
  21. {$define DISABLE_NO_THREAD_MANAGER}
  22. {$DEFINE HAS_GETCPUCOUNT}
  23. {$I systemh.inc}
  24. const
  25. LineEnding = #13#10;
  26. { LFNSupport is defined separately below!!! }
  27. DirectorySeparator = '\';
  28. DriveSeparator = ':';
  29. ExtensionSeparator = '.';
  30. PathSeparator = ';';
  31. AllowDirectorySeparators : set of char = ['\','/'];
  32. AllowDriveSeparators : set of char = [':'];
  33. { FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }
  34. MaxExitCode = 65535;
  35. MaxPathLen = 260;
  36. (* MaxPathLen is referenced as constant from unit SysUtils *)
  37. (* - changing to variable or typed constant is not possible. *)
  38. AllFilesMask = '*';
  39. RealMaxPathLen: word = MaxPathLen;
  40. (* Default value only - real value queried from the system on startup. *)
  41. type Tos=(osDOS,osOS2,osDPMI);
  42. const OS_Mode: Tos = osOS2;
  43. First_Meg: pointer = nil;
  44. const UnusedHandle=-1;
  45. StdInputHandle=0;
  46. StdOutputHandle=1;
  47. StdErrorHandle=2;
  48. LFNSupport: boolean = true;
  49. FileNameCaseSensitive: boolean = false;
  50. FileNameCasePreserving: boolean = true;
  51. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  52. sLineBreak = LineEnding;
  53. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  54. var
  55. { C-compatible arguments and environment }
  56. argc : longint;
  57. argv : ppchar;
  58. envp : ppchar;
  59. EnvC: cardinal;
  60. (* Pointer to the block of environment variables - used e.g. in unit Dos. *)
  61. Environment: PChar;
  62. var
  63. (* Type / run mode of the current process: *)
  64. (* 0 .. full screen OS/2 session *)
  65. (* 1 .. DOS session *)
  66. (* 2 .. VIO windowable OS/2 session *)
  67. (* 3 .. Presentation Manager OS/2 session *)
  68. (* 4 .. detached (background) OS/2 process *)
  69. ApplicationType: cardinal;
  70. const
  71. HeapAllocFlags: cardinal = $53; (* Compatible to VP/2 *)
  72. (* mfPag_Commit or mfObj_Tile or mfPag_Write or mfPag_Read *)
  73. function ReadUseHighMem: boolean;
  74. procedure WriteUseHighMem (B: boolean);
  75. (* Is allocation of memory above 512 MB address limit allowed? Initialized *)
  76. (* during initialization of system unit according to capabilities of the *)
  77. (* underlying OS/2 version, can be overridden by user - heap is allocated *)
  78. (* for all threads, so the setting isn't declared as a threadvar and *)
  79. (* should be only changed at the beginning of the main thread if needed. *)
  80. property
  81. UseHighMem: boolean read ReadUseHighMem write WriteUseHighMem;
  82. (* UseHighMem is provided for compatibility with 2.0.x. *)
  83. const
  84. (* Are file sizes > 2 GB (64-bit) supported on the current system? *)
  85. FSApi64: boolean = false;
  86. procedure SetDefaultOS2FileType (FType: ShortString);
  87. procedure SetDefaultOS2Creator (Creator: ShortString);
  88. type
  89. TDosOpenL = function (FileName: PChar; var Handle: THandle;
  90. var Action: cardinal; InitSize: int64;
  91. Attrib, OpenFlags, FileMode: cardinal;
  92. EA: pointer): cardinal; cdecl;
  93. TDosSetFilePtrL = function (Handle: THandle; Pos: int64; Method: cardinal;
  94. var PosActual: int64): cardinal; cdecl;
  95. TDosSetFileSizeL = function (Handle: THandle; Size: int64): cardinal; cdecl;
  96. function DummyDosOpenL (FileName: PChar; var Handle: THandle;
  97. var Action: cardinal; InitSize: int64;
  98. Attrib, OpenFlags, FileMode: cardinal;
  99. EA: pointer): cardinal; cdecl;
  100. function DummyDosSetFilePtrL (Handle: THandle; Pos: int64; Method: cardinal;
  101. var PosActual: int64): cardinal; cdecl;
  102. function DummyDosSetFileSizeL (Handle: THandle; Size: int64): cardinal; cdecl;
  103. const
  104. Sys_DosOpenL: TDosOpenL = @DummyDosOpenL;
  105. Sys_DosSetFilePtrL: TDosSetFilePtrL = @DummyDosSetFilePtrL;
  106. Sys_DosSetFileSizeL: TDosSetFileSizeL = @DummyDosSetFileSizeL;
  107. DosCallsHandle: THandle = THandle (-1);
  108. implementation
  109. {*****************************************************************************
  110. System unit initialization.
  111. ****************************************************************************}
  112. {$I system.inc}
  113. {*****************************************************************************
  114. Exception handling.
  115. ****************************************************************************}
  116. {$IFDEF OS2EXCEPTIONS}
  117. var
  118. { value of the stack segment
  119. to check if the call stack can be written on exceptions }
  120. _SS : Cardinal;
  121. function Is_Prefetch (P: pointer): boolean;
  122. var
  123. A: array [0..15] of byte;
  124. DoAgain: boolean;
  125. InstrLo, InstrHi, OpCode: byte;
  126. I: longint;
  127. MemSize, MemAttrs: cardinal;
  128. begin
  129. Is_Prefetch := false;
  130. MemSize := SizeOf (A);
  131. if (DosQueryMem (P, MemSize, MemAttrs) = 0) and
  132. (MemAttrs and (mfPag_Free or mfPag_Commit) <> 0)
  133. and (MemSize >= SizeOf (A)) then
  134. Move (P^, A [0], SizeOf (A))
  135. else
  136. Exit;
  137. I := 0;
  138. DoAgain := true;
  139. while DoAgain and (I < 15) do
  140. begin
  141. OpCode := A [I];
  142. InstrLo := OpCode and $f;
  143. InstrHi := OpCode and $f0;
  144. case InstrHi of
  145. { prefix? }
  146. $20, $30:
  147. DoAgain := (InstrLo and 7) = 6;
  148. $60:
  149. DoAgain := (InstrLo and $c) = 4;
  150. $f0:
  151. DoAgain := InstrLo in [0, 2, 3];
  152. $0:
  153. begin
  154. Is_Prefetch := (InstrLo = $f) and (A [I + 1] in [$D, $18]);
  155. Exit;
  156. end;
  157. else
  158. DoAgain := false;
  159. end;
  160. Inc (I);
  161. end;
  162. end;
  163. const
  164. MaxExceptionLevel = 16;
  165. ExceptLevel: byte = 0;
  166. var
  167. ExceptEIP: array [0..MaxExceptionLevel - 1] of longint;
  168. ExceptError: array [0..MaxExceptionLevel - 1] of byte;
  169. ResetFPU: array [0..MaxExceptionLevel - 1] of boolean;
  170. {$ifdef SYSTEMEXCEPTIONDEBUG}
  171. procedure DebugHandleErrorAddrFrame (Error: longint; Addr, Frame: pointer);
  172. begin
  173. if IsConsole then
  174. begin
  175. Write (StdErr, ' HandleErrorAddrFrame (error = ', Error);
  176. Write (StdErr, ', addr = ', hexstr (PtrUInt (Addr), 8));
  177. WriteLn (StdErr, ', frame = ', hexstr (PtrUInt (Frame), 8), ')');
  178. end;
  179. HandleErrorAddrFrame (Error, Addr, Frame);
  180. end;
  181. {$endif SYSTEMEXCEPTIONDEBUG}
  182. procedure JumpToHandleErrorFrame;
  183. var
  184. EIP, EBP, Error: longint;
  185. begin
  186. (* save ebp *)
  187. asm
  188. movl (%ebp),%eax
  189. movl %eax,ebp
  190. end;
  191. if (ExceptLevel > 0) then
  192. Dec (ExceptLevel);
  193. EIP := ExceptEIP [ExceptLevel];
  194. Error := ExceptError [ExceptLevel];
  195. {$ifdef SYSTEMEXCEPTIONDEBUG}
  196. if IsConsole then
  197. WriteLn (StdErr, 'In JumpToHandleErrorFrame error = ', Error);
  198. {$endif SYSTEMEXCEPTIONDEBUG}
  199. if ResetFPU [ExceptLevel] then
  200. SysResetFPU;
  201. { build a fake stack }
  202. asm
  203. {$ifdef REGCALL}
  204. movl ebp,%ecx
  205. movl eip,%edx
  206. movl error,%eax
  207. pushl eip
  208. movl ebp,%ebp // Change frame pointer
  209. {$else}
  210. movl ebp,%eax
  211. pushl %eax
  212. movl eip,%eax
  213. pushl %eax
  214. movl error,%eax
  215. pushl %eax
  216. movl eip,%eax
  217. pushl %eax
  218. movl ebp,%ebp // Change frame pointer
  219. {$endif}
  220. {$ifdef SYSTEMEXCEPTIONDEBUG}
  221. jmpl DebugHandleErrorAddrFrame
  222. {$else not SYSTEMEXCEPTIONDEBUG}
  223. jmpl HandleErrorAddrFrame
  224. {$endif SYSTEMEXCEPTIONDEBUG}
  225. end;
  226. end;
  227. function System_Exception_Handler (Report: PExceptionReportRecord;
  228. RegRec: PExceptionRegistrationRecord;
  229. Context: PContextRecord;
  230. DispContext: pointer): cardinal; cdecl;
  231. var
  232. Res: cardinal;
  233. Err: byte;
  234. Must_Reset_FPU: boolean;
  235. {$IFDEF SYSTEMEXCEPTIONDEBUG}
  236. CurSS: cardinal;
  237. B: byte;
  238. {$ENDIF SYSTEMEXCEPTIONDEBUG}
  239. begin
  240. {$ifdef SYSTEMEXCEPTIONDEBUG}
  241. if IsConsole then
  242. begin
  243. asm
  244. xorl %eax,%eax
  245. movw %ss,%ax
  246. movl %eax,CurSS
  247. end;
  248. WriteLn (StdErr, 'In System_Exception_Handler, error = ',
  249. HexStr (Report^.Exception_Num, 8));
  250. WriteLn (StdErr, 'Context SS = ', HexStr (Context^.Reg_SS, 8),
  251. ', current SS = ', HexStr (CurSS, 8));
  252. end;
  253. {$endif SYSTEMEXCEPTIONDEBUG}
  254. Res := Xcpt_Continue_Search;
  255. if Context^.Reg_SS = _SS then
  256. begin
  257. Err := 0;
  258. Must_Reset_FPU := true;
  259. {$ifdef SYSTEMEXCEPTIONDEBUG}
  260. if IsConsole then
  261. Writeln (StdErr, 'Exception ', HexStr (Report^.Exception_Num, 8));
  262. {$endif SYSTEMEXCEPTIONDEBUG}
  263. case Report^.Exception_Num of
  264. Xcpt_Integer_Divide_By_Zero,
  265. Xcpt_Float_Divide_By_Zero:
  266. Err := 200;
  267. Xcpt_Array_Bounds_Exceeded:
  268. begin
  269. Err := 201;
  270. Must_Reset_FPU := false;
  271. end;
  272. Xcpt_Unable_To_Grow_Stack:
  273. begin
  274. Err := 202;
  275. Must_Reset_FPU := false;
  276. end;
  277. Xcpt_Float_Overflow:
  278. Err := 205;
  279. Xcpt_Float_Denormal_Operand,
  280. Xcpt_Float_Underflow:
  281. Err := 206;
  282. {Context^.FloatSave.StatusWord := Context^.FloatSave.StatusWord and $ffffff00;}
  283. Xcpt_Float_Inexact_Result,
  284. Xcpt_Float_Invalid_Operation,
  285. Xcpt_Float_Stack_Check:
  286. Err := 207;
  287. Xcpt_Integer_Overflow:
  288. begin
  289. Err := 215;
  290. Must_Reset_FPU := false;
  291. end;
  292. Xcpt_Illegal_Instruction:
  293. { if we're testing sse support, simply set the flag and continue }
  294. if SSE_Check then
  295. begin
  296. OS_Supports_SSE := false;
  297. { skip the offending movaps %xmm7, %xmm6 instruction }
  298. Inc (Context^.Reg_EIP, 3);
  299. Report^.Exception_Num := 0;
  300. Res := Xcpt_Continue_Execution;
  301. end
  302. else
  303. Err := 216;
  304. Xcpt_Access_Violation:
  305. { Athlon prefetch bug? }
  306. if Is_Prefetch (pointer (Context^.Reg_EIP)) then
  307. begin
  308. { if yes, then retry }
  309. Report^.Exception_Num := 0;
  310. Res := Xcpt_Continue_Execution;
  311. end
  312. else
  313. Err := 216;
  314. Xcpt_Signal:
  315. case Report^.Parameters [0] of
  316. Xcpt_Signal_KillProc:
  317. Err := 217;
  318. Xcpt_Signal_Break,
  319. Xcpt_Signal_Intr:
  320. if Assigned (CtrlBreakHandler) then
  321. if CtrlBreakHandler (Report^.Parameters [0] = Xcpt_Signal_Break) then
  322. begin
  323. {$IFDEF SYSTEMEXCEPTIONDEBUG}
  324. WriteLn (StdErr, 'CtrlBreakHandler returned true');
  325. {$ENDIF SYSTEMEXCEPTIONDEBUG}
  326. Report^.Exception_Num := 0;
  327. Res := Xcpt_Continue_Execution;
  328. DosAcknowledgeSignalException (Report^.Parameters [0]);
  329. end
  330. else
  331. Err := 217;
  332. end;
  333. Xcpt_Privileged_Instruction:
  334. begin
  335. Err := 218;
  336. Must_Reset_FPU := false;
  337. end;
  338. else
  339. begin
  340. if ((Report^.Exception_Num and Xcpt_Severity_Code)
  341. = Xcpt_Fatal_Exception) then
  342. Err := 217
  343. else
  344. Err := 255;
  345. end;
  346. end;
  347. if (Err <> 0) and (ExceptLevel < MaxExceptionLevel)
  348. (* TH: The following line is necessary to avoid an endless loop *)
  349. and (Report^.Exception_Num < Xcpt_Process_Terminate)
  350. then
  351. begin
  352. ExceptEIP [ExceptLevel] := Context^.Reg_EIP;
  353. ExceptError [ExceptLevel] := Err;
  354. ResetFPU [ExceptLevel] := Must_Reset_FPU;
  355. Inc (ExceptLevel);
  356. Context^.Reg_EIP := cardinal (@JumpToHandleErrorFrame);
  357. Report^.Exception_Num := 0;
  358. Res := Xcpt_Continue_Execution;
  359. {$ifdef SYSTEMEXCEPTIONDEBUG}
  360. if IsConsole then
  361. begin
  362. WriteLn (StdErr, 'Exception Continue Exception set at ',
  363. HexStr (ExceptEIP [ExceptLevel], 8));
  364. WriteLn (StdErr, 'EIP changed to ',
  365. HexStr (longint (@JumpToHandleErrorFrame), 8), ', error = ', Err);
  366. end;
  367. {$endif SYSTEMEXCEPTIONDEBUG}
  368. end;
  369. end
  370. else
  371. if (Report^.Exception_Num = Xcpt_Signal) and
  372. (Report^.Parameters [0] and (Xcpt_Signal_Intr or Xcpt_Signal_Break) <> 0)
  373. and Assigned (CtrlBreakHandler) then
  374. {$IFDEF SYSTEMEXCEPTIONDEBUG}
  375. begin
  376. WriteLn (StdErr, 'XCPT_SIGNAL caught, CtrlBreakHandler assigned, Param = ',
  377. Report^.Parameters [0]);
  378. {$ENDIF SYSTEMEXCEPTIONDEBUG}
  379. if CtrlBreakHandler (Report^.Parameters [0] = Xcpt_Signal_Break) then
  380. begin
  381. {$IFDEF SYSTEMEXCEPTIONDEBUG}
  382. WriteLn (StdErr, 'CtrlBreakHandler returned true');
  383. {$ENDIF SYSTEMEXCEPTIONDEBUG}
  384. Report^.Exception_Num := 0;
  385. Res := Xcpt_Continue_Execution;
  386. DosAcknowledgeSignalException (Report^.Parameters [0]);
  387. end
  388. else
  389. Err := 217;
  390. {$IFDEF SYSTEMEXCEPTIONDEBUG}
  391. end
  392. else
  393. if IsConsole then
  394. begin
  395. WriteLn (StdErr, 'Ctx flags = ', HexStr (Context^.ContextFlags, 8));
  396. if Context^.ContextFlags and Context_Floating_Point <> 0 then
  397. begin
  398. for B := 1 to 6 do
  399. Write (StdErr, 'Ctx Env [', B, '] = ', HexStr (Context^.Env [B], 8),
  400. ', ');
  401. WriteLn (StdErr, 'Ctx Env [7] = ', HexStr (Context^.Env [7], 8));
  402. for B := 0 to 6 do
  403. Write (StdErr, 'FPU stack [', B, '] = ', Context^.FPUStack [B], ', ');
  404. WriteLn (StdErr, 'FPU stack [7] = ', Context^.FPUStack [7]);
  405. end;
  406. if Context^.ContextFlags and Context_Segments <> 0 then
  407. WriteLn (StdErr, 'GS = ', HexStr (Context^.Reg_GS, 8),
  408. ', FS = ', HexStr (Context^.Reg_FS, 8),
  409. ', ES = ', HexStr (Context^.Reg_ES, 8),
  410. ', DS = ', HexStr (Context^.Reg_DS, 8));
  411. if Context^.ContextFlags and Context_Integer <> 0 then
  412. begin
  413. WriteLn (StdErr, 'EDI = ', HexStr (Context^.Reg_EDI, 8),
  414. ', ESI = ', HexStr (Context^.Reg_ESI, 8));
  415. WriteLn (StdErr, 'EAX = ', HexStr (Context^.Reg_EAX, 8),
  416. ', EBX = ', HexStr (Context^.Reg_EBX, 8),
  417. ', ECX = ', HexStr (Context^.Reg_ECX, 8),
  418. ', EDX = ', HexStr (Context^.Reg_EDX, 8));
  419. end;
  420. if Context^.ContextFlags and Context_Control <> 0 then
  421. begin
  422. WriteLn (StdErr, 'EBP = ', HexStr (Context^.Reg_EBP, 8),
  423. ', SS = ', HexStr (Context^.Reg_SS, 8),
  424. ', ESP = ', HexStr (Context^.Reg_ESP, 8));
  425. WriteLn (StdErr, 'CS = ', HexStr (Context^.Reg_CS, 8),
  426. ', EIP = ', HexStr (Context^.Reg_EIP, 8),
  427. ', EFlags = ', HexStr (Context^.Flags, 8));
  428. end;
  429. end;
  430. {$endif SYSTEMEXCEPTIONDEBUG}
  431. System_Exception_Handler := Res;
  432. end;
  433. var
  434. ExcptReg: PExceptionRegistrationRecord; public name '_excptregptr';
  435. {$ifdef SYSTEMEXCEPTIONDEBUG}
  436. var
  437. OldExceptAddr,
  438. NewExceptAddr: PtrUInt;
  439. {$endif SYSTEMEXCEPTIONDEBUG}
  440. procedure Install_Exception_Handler;
  441. var
  442. T: cardinal;
  443. begin
  444. {$ifdef SYSTEMEXCEPTIONDEBUG}
  445. (* ThreadInfoBlock is located at FS:[0], the first *)
  446. (* entry is pointer to head of exception handler chain. *)
  447. asm
  448. movl $0,%eax
  449. movl %fs:(%eax),%eax
  450. movl %eax, OldExceptAddr
  451. end;
  452. {$endif SYSTEMEXCEPTIONDEBUG}
  453. with ExcptReg^ do
  454. begin
  455. Prev_Structure := nil;
  456. ExceptionHandler := TExceptionHandler (@System_Exception_Handler);
  457. end;
  458. (* Disable pop-up windows for errors and exceptions *)
  459. DosError (deDisableExceptions);
  460. DosSetExceptionHandler (ExcptReg^);
  461. if IsConsole then
  462. begin
  463. DosSetSignalExceptionFocus (1, T);
  464. DosAcknowledgeSignalException (Xcpt_Signal_Intr);
  465. DosAcknowledgeSignalException (Xcpt_Signal_Break);
  466. end;
  467. {$ifdef SYSTEMEXCEPTIONDEBUG}
  468. asm
  469. movl $0,%eax
  470. movl %fs:(%eax),%eax
  471. movl %eax, NewExceptAddr
  472. end;
  473. {$endif SYSTEMEXCEPTIONDEBUG}
  474. end;
  475. procedure Remove_Exception_Handlers;
  476. begin
  477. DosUnsetExceptionHandler (ExcptReg^);
  478. end;
  479. {$ENDIF OS2EXCEPTIONS}
  480. procedure system_exit;
  481. begin
  482. (* if IsLibrary then
  483. ExitDLL(ExitCode);
  484. *)
  485. (*
  486. if not IsConsole then
  487. begin
  488. Close(stderr);
  489. Close(stdout);
  490. Close(erroutput);
  491. Close(Input);
  492. Close(Output);
  493. end;
  494. *)
  495. {$IFDEF OS2EXCEPTIONS}
  496. Remove_Exception_Handlers;
  497. {$ENDIF OS2EXCEPTIONS}
  498. DosExit (1{process}, exitcode);
  499. end;
  500. {$ASMMODE ATT}
  501. {****************************************************************************
  502. Miscellaneous related routines.
  503. ****************************************************************************}
  504. function paramcount:longint;assembler;
  505. asm
  506. movl argc,%eax
  507. decl %eax
  508. end {['EAX']};
  509. function paramstr(l:longint):string;
  510. var p:^Pchar;
  511. begin
  512. if (l>=0) and (l<=paramcount) then
  513. begin
  514. p:=argv;
  515. paramstr:=strpas(p[l]);
  516. end
  517. else paramstr:='';
  518. end;
  519. procedure randomize;
  520. var
  521. dt: TSysDateTime;
  522. begin
  523. // Hmm... Lets use timer
  524. DosGetDateTime(dt);
  525. randseed:=dt.hour+(dt.minute shl 8)+(dt.second shl 16)+(dt.sec100 shl 32);
  526. end;
  527. {****************************************************************************
  528. Error Message writing using messageboxes
  529. ****************************************************************************}
  530. const
  531. WinInitialize: TWinInitialize = nil;
  532. WinCreateMsgQueue: TWinCreateMsgQueue = nil;
  533. WinMessageBox: TWinMessageBox = nil;
  534. EnvSize: cardinal = 0;
  535. var
  536. ErrorBuf: array [0..ErrorBufferLength] of char;
  537. ErrorLen: longint;
  538. PMWinHandle: cardinal;
  539. function ErrorWrite (var F: TextRec): integer;
  540. {
  541. An error message should always end with #13#10#13#10
  542. }
  543. var
  544. P: PChar;
  545. I: longint;
  546. begin
  547. if F.BufPos > 0 then
  548. begin
  549. if F.BufPos + ErrorLen > ErrorBufferLength then
  550. I := ErrorBufferLength - ErrorLen
  551. else
  552. I := F.BufPos;
  553. Move (F.BufPtr^, ErrorBuf [ErrorLen], I);
  554. Inc (ErrorLen, I);
  555. ErrorBuf [ErrorLen] := #0;
  556. end;
  557. if ErrorLen > 3 then
  558. begin
  559. P := @ErrorBuf [ErrorLen];
  560. for I := 1 to 4 do
  561. begin
  562. Dec (P);
  563. if not (P^ in [#10, #13]) then
  564. break;
  565. end;
  566. end;
  567. if ErrorLen = ErrorBufferLength then
  568. I := 4;
  569. if (I = 4) then
  570. begin
  571. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  572. ErrorLen := 0;
  573. end;
  574. F.BufPos := 0;
  575. ErrorWrite := 0;
  576. end;
  577. function ErrorClose (var F: TextRec): integer;
  578. begin
  579. if ErrorLen > 0 then
  580. begin
  581. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  582. ErrorLen := 0;
  583. end;
  584. ErrorLen := 0;
  585. ErrorClose := 0;
  586. end;
  587. function ErrorOpen (var F: TextRec): integer;
  588. begin
  589. TextRec(F).InOutFunc := @ErrorWrite;
  590. TextRec(F).FlushFunc := @ErrorWrite;
  591. TextRec(F).CloseFunc := @ErrorClose;
  592. ErrorOpen := 0;
  593. end;
  594. procedure AssignError (var T: Text);
  595. begin
  596. Assign (T, '');
  597. TextRec (T).OpenFunc := @ErrorOpen;
  598. Rewrite (T);
  599. end;
  600. procedure SysInitStdIO;
  601. begin
  602. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  603. displayed in a messagebox }
  604. (*
  605. StdInputHandle := longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  606. StdOutputHandle := longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  607. StdErrorHandle := longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  608. if not IsConsole then
  609. begin
  610. if (DosLoadModule (nil, 0, 'PMWIN', PMWinHandle) = 0) and
  611. (DosQueryProcAddr (PMWinHandle, 789, nil, pointer (WinMessageBox)) = 0)
  612. and
  613. (DosQueryProcAddr (PMWinHandle, 763, nil, pointer (WinInitialize)) = 0)
  614. and
  615. (DosQueryProcAddr (PMWinHandle, 716, nil, pointer (WinCreateMsgQueue))
  616. = 0)
  617. then
  618. begin
  619. WinInitialize (0);
  620. WinCreateMsgQueue (0, 0);
  621. end
  622. else
  623. HandleError (2);
  624. AssignError (StdErr);
  625. AssignError (StdOut);
  626. Assign (Output, '');
  627. Assign (Input, '');
  628. end
  629. else
  630. begin
  631. *)
  632. OpenStdIO (Input, fmInput, StdInputHandle);
  633. OpenStdIO (Output, fmOutput, StdOutputHandle);
  634. OpenStdIO (ErrOutput, fmOutput, StdErrorHandle);
  635. OpenStdIO (StdOut, fmOutput, StdOutputHandle);
  636. OpenStdIO (StdErr, fmOutput, StdErrorHandle);
  637. (*
  638. end;
  639. *)
  640. end;
  641. function strcopy(dest,source : pchar) : pchar;assembler;
  642. var
  643. saveeax,saveesi,saveedi : longint;
  644. asm
  645. movl %edi,saveedi
  646. movl %esi,saveesi
  647. {$ifdef REGCALL}
  648. movl %eax,saveeax
  649. movl %edx,%edi
  650. {$else}
  651. movl source,%edi
  652. {$endif}
  653. testl %edi,%edi
  654. jz .LStrCopyDone
  655. leal 3(%edi),%ecx
  656. andl $-4,%ecx
  657. movl %edi,%esi
  658. subl %edi,%ecx
  659. {$ifdef REGCALL}
  660. movl %eax,%edi
  661. {$else}
  662. movl dest,%edi
  663. {$endif}
  664. jz .LStrCopyAligned
  665. .LStrCopyAlignLoop:
  666. movb (%esi),%al
  667. incl %edi
  668. incl %esi
  669. testb %al,%al
  670. movb %al,-1(%edi)
  671. jz .LStrCopyDone
  672. decl %ecx
  673. jnz .LStrCopyAlignLoop
  674. .balign 16
  675. .LStrCopyAligned:
  676. movl (%esi),%eax
  677. movl %eax,%edx
  678. leal 0x0fefefeff(%eax),%ecx
  679. notl %edx
  680. addl $4,%esi
  681. andl %edx,%ecx
  682. andl $0x080808080,%ecx
  683. jnz .LStrCopyEndFound
  684. movl %eax,(%edi)
  685. addl $4,%edi
  686. jmp .LStrCopyAligned
  687. .LStrCopyEndFound:
  688. testl $0x0ff,%eax
  689. jz .LStrCopyByte
  690. testl $0x0ff00,%eax
  691. jz .LStrCopyWord
  692. testl $0x0ff0000,%eax
  693. jz .LStrCopy3Bytes
  694. movl %eax,(%edi)
  695. jmp .LStrCopyDone
  696. .LStrCopy3Bytes:
  697. xorb %dl,%dl
  698. movw %ax,(%edi)
  699. movb %dl,2(%edi)
  700. jmp .LStrCopyDone
  701. .LStrCopyWord:
  702. movw %ax,(%edi)
  703. jmp .LStrCopyDone
  704. .LStrCopyByte:
  705. movb %al,(%edi)
  706. .LStrCopyDone:
  707. {$ifdef REGCALL}
  708. movl saveeax,%eax
  709. {$else}
  710. movl dest,%eax
  711. {$endif}
  712. movl saveedi,%edi
  713. movl saveesi,%esi
  714. end;
  715. threadvar
  716. DefaultCreator: ShortString;
  717. DefaultFileType: ShortString;
  718. procedure SetDefaultOS2FileType (FType: ShortString);
  719. begin
  720. {$WARNING Not implemented yet!}
  721. DefaultFileType := FType;
  722. end;
  723. procedure SetDefaultOS2Creator (Creator: ShortString);
  724. begin
  725. {$WARNING Not implemented yet!}
  726. DefaultCreator := Creator;
  727. end;
  728. procedure InitEnvironment;
  729. var env_count : longint;
  730. dos_env,cp : pchar;
  731. begin
  732. env_count:=0;
  733. cp:=environment;
  734. while cp ^ <> #0 do
  735. begin
  736. inc(env_count);
  737. while (cp^ <> #0) do inc(longint(cp)); { skip to NUL }
  738. inc(longint(cp)); { skip to next character }
  739. end;
  740. envp := sysgetmem((env_count+1) * sizeof(pchar));
  741. envc := env_count;
  742. if (envp = nil) then exit;
  743. cp:=environment;
  744. env_count:=0;
  745. while cp^ <> #0 do
  746. begin
  747. envp[env_count] := sysgetmem(strlen(cp)+1);
  748. strcopy(envp[env_count], cp);
  749. {$IfDef DEBUGENVIRONMENT}
  750. Writeln(stderr,'env ',env_count,' = "',envp[env_count],'"');
  751. {$EndIf}
  752. inc(env_count);
  753. while (cp^ <> #0) do
  754. inc(longint(cp)); { skip to NUL }
  755. inc(longint(cp)); { skip to next character }
  756. end;
  757. envp[env_count]:=nil;
  758. end;
  759. var
  760. (* Initialized by system unit initialization *)
  761. PIB: PProcessInfoBlock;
  762. procedure InitArguments;
  763. var
  764. arglen,
  765. count : PtrInt;
  766. argstart,
  767. pc,arg : pchar;
  768. quote : char;
  769. argvlen : PtrInt;
  770. procedure allocarg(idx,len: PtrInt);
  771. var
  772. oldargvlen : PtrInt;
  773. begin
  774. if idx>=argvlen then
  775. begin
  776. oldargvlen:=argvlen;
  777. argvlen:=(idx+8) and (not 7);
  778. sysreallocmem(argv,argvlen*sizeof(pointer));
  779. { fillchar(argv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);}
  780. end;
  781. { use realloc to reuse already existing memory }
  782. { always allocate, even if length is zero, since }
  783. { the arg. is still present! }
  784. ArgV [Idx] := SysAllocMem (Succ (Len));
  785. end;
  786. begin
  787. CmdLine := SysAllocMem (MaxPathLen);
  788. ArgV := SysAllocMem (8 * SizeOf (pointer));
  789. ArgLen := StrLen (PChar (PIB^.Cmd));
  790. Inc (ArgLen);
  791. if DosQueryModuleName (PIB^.Handle, MaxPathLen, CmdLine) = 0 then
  792. ArgVLen := Succ (StrLen (CmdLine))
  793. else
  794. (* Error occurred - use program name from command line as fallback. *)
  795. begin
  796. Move (PIB^.Cmd^, CmdLine, ArgLen);
  797. ArgVLen := ArgLen;
  798. end;
  799. { Get ArgV [0] }
  800. ArgV [0] := SysAllocMem (ArgVLen);
  801. Move (CmdLine^, ArgV [0]^, ArgVLen);
  802. Count := 1;
  803. (* PC points to leading space after program name on command line *)
  804. PC := PChar (PIB^.Cmd) + ArgLen;
  805. (* ArgLen contains size of command line arguments including leading space. *)
  806. ArgLen := Succ (StrLen (PC));
  807. SysReallocMem (CmdLine, ArgVLen + ArgLen);
  808. Move (PC^, CmdLine [ArgVLen], Succ (ArgLen));
  809. (* ArgV has space for 8 parameters from the first allocation. *)
  810. ArgVLen := 8;
  811. { process arguments }
  812. while pc^<>#0 do
  813. begin
  814. { skip leading spaces }
  815. while pc^ in [#1..#32] do
  816. inc(pc);
  817. if pc^=#0 then
  818. break;
  819. { calc argument length }
  820. quote:=' ';
  821. argstart:=pc;
  822. arglen:=0;
  823. while (pc^<>#0) do
  824. begin
  825. case pc^ of
  826. #1..#32 :
  827. begin
  828. if quote<>' ' then
  829. inc(arglen)
  830. else
  831. break;
  832. end;
  833. '"' :
  834. begin
  835. if quote<>'''' then
  836. begin
  837. if pchar(pc+1)^<>'"' then
  838. begin
  839. if quote='"' then
  840. quote:=' '
  841. else
  842. quote:='"';
  843. end
  844. else
  845. inc(pc);
  846. end
  847. else
  848. inc(arglen);
  849. end;
  850. '''' :
  851. begin
  852. if quote<>'"' then
  853. begin
  854. if pchar(pc+1)^<>'''' then
  855. begin
  856. if quote='''' then
  857. quote:=' '
  858. else
  859. quote:='''';
  860. end
  861. else
  862. inc(pc);
  863. end
  864. else
  865. inc(arglen);
  866. end;
  867. else
  868. inc(arglen);
  869. end;
  870. inc(pc);
  871. end;
  872. { copy argument }
  873. { Don't copy the first one, it is already there.}
  874. If Count<>0 then
  875. begin
  876. allocarg(count,arglen);
  877. quote:=' ';
  878. pc:=argstart;
  879. arg:=argv[count];
  880. while (pc^<>#0) do
  881. begin
  882. case pc^ of
  883. #1..#32 :
  884. begin
  885. if quote<>' ' then
  886. begin
  887. arg^:=pc^;
  888. inc(arg);
  889. end
  890. else
  891. break;
  892. end;
  893. '"' :
  894. begin
  895. if quote<>'''' then
  896. begin
  897. if pchar(pc+1)^<>'"' then
  898. begin
  899. if quote='"' then
  900. quote:=' '
  901. else
  902. quote:='"';
  903. end
  904. else
  905. inc(pc);
  906. end
  907. else
  908. begin
  909. arg^:=pc^;
  910. inc(arg);
  911. end;
  912. end;
  913. '''' :
  914. begin
  915. if quote<>'"' then
  916. begin
  917. if pchar(pc+1)^<>'''' then
  918. begin
  919. if quote='''' then
  920. quote:=' '
  921. else
  922. quote:='''';
  923. end
  924. else
  925. inc(pc);
  926. end
  927. else
  928. begin
  929. arg^:=pc^;
  930. inc(arg);
  931. end;
  932. end;
  933. else
  934. begin
  935. arg^:=pc^;
  936. inc(arg);
  937. end;
  938. end;
  939. inc(pc);
  940. end;
  941. arg^:=#0;
  942. end;
  943. {$IfDef DEBUGARGUMENTS}
  944. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  945. {$EndIf}
  946. inc(count);
  947. end;
  948. { get argc and create an nil entry }
  949. argc:=count;
  950. allocarg(argc,0);
  951. { free unused memory }
  952. sysreallocmem(argv,(argc+1)*sizeof(pointer));
  953. end;
  954. function GetFileHandleCount: longint;
  955. var L1: longint;
  956. L2: cardinal;
  957. begin
  958. L1 := 0; (* Don't change the amount, just check. *)
  959. if DosSetRelMaxFH (L1, L2) <> 0 then GetFileHandleCount := 50
  960. else GetFileHandleCount := L2;
  961. end;
  962. function CheckInitialStkLen (StkLen: SizeUInt): SizeUInt;
  963. begin
  964. CheckInitialStkLen := StkLen;
  965. end;
  966. var TIB: PThreadInfoBlock;
  967. RC: cardinal;
  968. ErrStr: string;
  969. P: pointer;
  970. DW: cardinal;
  971. const
  972. DosCallsName: array [0..8] of char = 'DOSCALLS'#0;
  973. {$IFDEF OS2UNICODE}
  974. {$I sysucode.inc}
  975. {$ENDIF OS2UNICODE}
  976. {*var}
  977. {* ST: pointer;}
  978. {*}
  979. begin
  980. {$IFDEF OS2EXCEPTIONS}
  981. (* asm
  982. { allocate space for exception registration record }
  983. pushl $0
  984. pushl $0}
  985. {* pushl %fs:(0)}
  986. { movl %esp,%fs:(0)
  987. but don't insert it as it doesn't
  988. point to anything yet
  989. this will be used in signals unit }
  990. movl %esp,%eax
  991. movl %eax,ExcptReg
  992. pushl %ebp
  993. movl %esp,%eax
  994. {* movl %eax,st*}
  995. movl %eax,StackTop
  996. end;
  997. {* StackTop:=st;}
  998. *) asm
  999. xorl %eax,%eax
  1000. movw %ss,%ax
  1001. movl %eax,_SS
  1002. end;
  1003. {$ENDIF OS2EXCEPTIONS}
  1004. DosGetInfoBlocks (@TIB, @PIB);
  1005. StackLength := CheckInitialStkLen (InitialStkLen);
  1006. { OS/2 has top of stack in TIB^.StackLimit - unlike Windows where it is in TIB^.Stack }
  1007. StackBottom := TIB^.StackLimit - StackLength;
  1008. {Set type of application}
  1009. ApplicationType := PIB^.ProcType;
  1010. ProcessID := PIB^.PID;
  1011. ThreadID := TIB^.TIB2^.TID;
  1012. IsConsole := ApplicationType <> 3;
  1013. {Query maximum path length (QSV_MAX_PATH_LEN = 1)}
  1014. if DosQuerySysInfo (1, 1, DW, SizeOf (DW)) = 0 then
  1015. RealMaxPathLen := DW;
  1016. ExitProc := nil;
  1017. {$IFDEF OS2EXCEPTIONS}
  1018. Install_Exception_Handler;
  1019. {$ENDIF OS2EXCEPTIONS}
  1020. (* Initialize the amount of file handles *)
  1021. FileHandleCount := GetFileHandleCount;
  1022. {Initialize the heap.}
  1023. (* Logic is following:
  1024. The heap is initially restricted to low address space (< 512 MB).
  1025. If underlying OS/2 version allows using more than 512 MB per process
  1026. (OS/2 WarpServer for e-Business, eComStation, possibly OS/2 Warp 4.0
  1027. with FP13 and above as well), use of this high memory is allowed for
  1028. future memory allocations at the end of System unit initialization.
  1029. The consequences are that the compiled application can allocate more
  1030. memory, but it must make sure to use direct DosAllocMem calls if it
  1031. needs a memory block for some system API not supporting high memory.
  1032. This is probably no problem for direct calls to these APIs, but
  1033. there might be situations when a memory block needs to be passed
  1034. to a 3rd party DLL which in turn calls such an API call. In case
  1035. of problems usage of high memory can be turned off by setting
  1036. UseHighMem to false - the program should change the setting at its
  1037. very beginning (e.g. in initialization section of the first unit
  1038. listed in the "uses" section) to avoid having preallocated memory
  1039. from the high memory region before changing value of this variable. *)
  1040. InitHeap;
  1041. if DosQueryModuleHandle (@DosCallsName [0], DosCallsHandle) = 0 then
  1042. begin
  1043. if DosQueryProcAddr (DosCallsHandle, OrdDosOpenL, nil, P) = 0 then
  1044. begin
  1045. Sys_DosOpenL := TDosOpenL (P);
  1046. if DosQueryProcAddr (DosCallsHandle, OrdDosSetFilePtrL, nil, P) = 0
  1047. then
  1048. begin
  1049. Sys_DosSetFilePtrL := TDosSetFilePtrL (P);
  1050. if DosQueryProcAddr (DosCallsHandle, OrdDosSetFileSizeL, nil,
  1051. P) = 0 then
  1052. begin
  1053. Sys_DosSetFileSizeL := TDosSetFileSizeL (P);
  1054. FSApi64 := true;
  1055. end;
  1056. end;
  1057. end;
  1058. end;
  1059. { ... and exceptions }
  1060. SysInitExceptions;
  1061. fpc_cpucodeinit;
  1062. InitUnicodeStringManager;
  1063. {$ifdef OS2UCODE}
  1064. InitOS2WideStrings;
  1065. {$endif OS2UCODE}
  1066. { ... and I/O }
  1067. SysInitStdIO;
  1068. { no I/O-Error }
  1069. inoutres:=0;
  1070. {Initialize environment (must be after InitHeap because allocates memory)}
  1071. Environment := pointer (PIB^.Env);
  1072. InitEnvironment;
  1073. InitArguments;
  1074. DefaultCreator := '';
  1075. DefaultFileType := '';
  1076. InitSystemThreads;
  1077. InitVariantManager;
  1078. {$IFDEF EXTDUMPGROW}
  1079. { Int_HeapSize := high (cardinal);}
  1080. {$ENDIF EXTDUMPGROW}
  1081. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1082. if IsConsole then
  1083. WriteLn (StdErr, 'Old exception ', HexStr (OldExceptAddr, 8),
  1084. ', new exception ', HexStr (NewExceptAddr, 8), ', _SS = ', HexStr (_SS, 8));
  1085. {$endif SYSTEMEXCEPTIONDEBUG}
  1086. end.