system.pas 33 KB

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