system.pas 33 KB

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