system.pas 33 KB

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