system.pas 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  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. DosQueryMem (P, MemSize, MemAttrs);
  125. if (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) then
  341. begin
  342. ExceptEIP [ExceptLevel] := Context^.Reg_EIP;
  343. ExceptError [ExceptLevel] := Err;
  344. ResetFPU [ExceptLevel] := Must_Reset_FPU;
  345. Inc (ExceptLevel);
  346. Context^.Reg_EIP := cardinal (@JumpToHandleErrorFrame);
  347. Report^.Exception_Num := 0;
  348. Res := Xcpt_Continue_Execution;
  349. {$ifdef SYSTEMEXCEPTIONDEBUG}
  350. if IsConsole then
  351. begin
  352. WriteLn (StdErr, 'Exception Continue Exception set at ',
  353. HexStr (ExceptEIP [ExceptLevel], 8));
  354. WriteLn (StdErr, 'EIP changed to ',
  355. HexStr (longint (@JumpToHandleErrorFrame), 8), ', error = ', Err);
  356. end;
  357. {$endif SYSTEMEXCEPTIONDEBUG}
  358. end;
  359. end
  360. else
  361. if (Report^.Exception_Num = Xcpt_Signal) and
  362. (Report^.Parameters [0] and (Xcpt_Signal_Intr or Xcpt_Signal_Break) <> 0)
  363. and Assigned (CtrlBreakHandler) then
  364. {$IFDEF SYSTEMEXCEPTIONDEBUG}
  365. begin
  366. WriteLn (StdErr, 'XCPT_SIGNAL caught, CtrlBreakHandler assigned, Param = ',
  367. Report^.Parameters [0]);
  368. {$ENDIF SYSTEMEXCEPTIONDEBUG}
  369. if CtrlBreakHandler (Report^.Parameters [0] = Xcpt_Signal_Break) then
  370. begin
  371. {$IFDEF SYSTEMEXCEPTIONDEBUG}
  372. WriteLn (StdErr, 'CtrlBreakHandler returned true');
  373. {$ENDIF SYSTEMEXCEPTIONDEBUG}
  374. Report^.Exception_Num := 0;
  375. Res := Xcpt_Continue_Execution;
  376. DosAcknowledgeSignalException (Report^.Parameters [0]);
  377. end
  378. else
  379. Err := 217;
  380. {$IFDEF SYSTEMEXCEPTIONDEBUG}
  381. end
  382. else
  383. if IsConsole then
  384. begin
  385. WriteLn (StdErr, 'Ctx flags = ', HexStr (Context^.ContextFlags, 8));
  386. if Context^.ContextFlags and Context_Floating_Point <> 0 then
  387. begin
  388. for B := 1 to 6 do
  389. Write (StdErr, 'Ctx Env [', B, '] = ', HexStr (Context^.Env [B], 8),
  390. ', ');
  391. WriteLn (StdErr, 'Ctx Env [7] = ', HexStr (Context^.Env [7], 8));
  392. for B := 0 to 6 do
  393. Write (StdErr, 'FPU stack [', B, '] = ', Context^.FPUStack [B], ', ');
  394. WriteLn (StdErr, 'FPU stack [7] = ', Context^.FPUStack [7]);
  395. end;
  396. if Context^.ContextFlags and Context_Segments <> 0 then
  397. WriteLn (StdErr, 'GS = ', HexStr (Context^.Reg_GS, 8),
  398. ', FS = ', HexStr (Context^.Reg_FS, 8),
  399. ', ES = ', HexStr (Context^.Reg_ES, 8),
  400. ', DS = ', HexStr (Context^.Reg_DS, 8));
  401. if Context^.ContextFlags and Context_Integer <> 0 then
  402. begin
  403. WriteLn (StdErr, 'EDI = ', HexStr (Context^.Reg_EDI, 8),
  404. ', ESI = ', HexStr (Context^.Reg_ESI, 8));
  405. WriteLn (StdErr, 'EAX = ', HexStr (Context^.Reg_EAX, 8),
  406. ', EBX = ', HexStr (Context^.Reg_EBX, 8),
  407. ', ECX = ', HexStr (Context^.Reg_ECX, 8),
  408. ', EDX = ', HexStr (Context^.Reg_EDX, 8));
  409. end;
  410. if Context^.ContextFlags and Context_Control <> 0 then
  411. begin
  412. WriteLn (StdErr, 'EBP = ', HexStr (Context^.Reg_EBP, 8),
  413. ', SS = ', HexStr (Context^.Reg_SS, 8),
  414. ', ESP = ', HexStr (Context^.Reg_ESP, 8));
  415. WriteLn (StdErr, 'CS = ', HexStr (Context^.Reg_CS, 8),
  416. ', EIP = ', HexStr (Context^.Reg_EIP, 8),
  417. ', EFlags = ', HexStr (Context^.Flags, 8));
  418. end;
  419. end;
  420. {$endif SYSTEMEXCEPTIONDEBUG}
  421. System_Exception_Handler := Res;
  422. end;
  423. var
  424. ExcptReg: PExceptionRegistrationRecord; public name '_excptregptr';
  425. {$ifdef SYSTEMEXCEPTIONDEBUG}
  426. var
  427. OldExceptAddr,
  428. NewExceptAddr: PtrUInt;
  429. {$endif SYSTEMEXCEPTIONDEBUG}
  430. procedure Install_Exception_Handler;
  431. var
  432. T: cardinal;
  433. begin
  434. {$ifdef SYSTEMEXCEPTIONDEBUG}
  435. (* ThreadInfoBlock is located at FS:[0], the first *)
  436. (* entry is pointer to head of exception handler chain. *)
  437. asm
  438. movl $0,%eax
  439. movl %fs:(%eax),%eax
  440. movl %eax, OldExceptAddr
  441. end;
  442. {$endif SYSTEMEXCEPTIONDEBUG}
  443. with ExcptReg^ do
  444. begin
  445. Prev_Structure := nil;
  446. ExceptionHandler := TExceptionHandler (@System_Exception_Handler);
  447. end;
  448. (* Disable pop-up windows for errors and exceptions *)
  449. DosError (deDisableExceptions);
  450. DosSetExceptionHandler (ExcptReg^);
  451. if IsConsole then
  452. begin
  453. DosSetSignalExceptionFocus (1, T);
  454. DosAcknowledgeSignalException (Xcpt_Signal_Intr);
  455. DosAcknowledgeSignalException (Xcpt_Signal_Break);
  456. end;
  457. {$ifdef SYSTEMEXCEPTIONDEBUG}
  458. asm
  459. movl $0,%eax
  460. movl %fs:(%eax),%eax
  461. movl %eax, NewExceptAddr
  462. end;
  463. {$endif SYSTEMEXCEPTIONDEBUG}
  464. end;
  465. procedure Remove_Exception_Handlers;
  466. begin
  467. DosUnsetExceptionHandler (ExcptReg^);
  468. end;
  469. {$ENDIF OS2EXCEPTIONS}
  470. procedure system_exit;
  471. begin
  472. (* if IsLibrary then
  473. ExitDLL(ExitCode);
  474. *)
  475. (*
  476. if not IsConsole then
  477. begin
  478. Close(stderr);
  479. Close(stdout);
  480. Close(erroutput);
  481. Close(Input);
  482. Close(Output);
  483. end;
  484. *)
  485. {$IFDEF OS2EXCEPTIONS}
  486. Remove_Exception_Handlers;
  487. {$ENDIF OS2EXCEPTIONS}
  488. DosExit (1{process}, exitcode);
  489. end;
  490. {$ASMMODE ATT}
  491. {****************************************************************************
  492. Miscellaneous related routines.
  493. ****************************************************************************}
  494. function paramcount:longint;assembler;
  495. asm
  496. movl argc,%eax
  497. decl %eax
  498. end {['EAX']};
  499. function paramstr(l:longint):string;
  500. var p:^Pchar;
  501. begin
  502. if (l>=0) and (l<=paramcount) then
  503. begin
  504. p:=argv;
  505. paramstr:=strpas(p[l]);
  506. end
  507. else paramstr:='';
  508. end;
  509. procedure randomize;
  510. var
  511. dt: TSysDateTime;
  512. begin
  513. // Hmm... Lets use timer
  514. DosGetDateTime(dt);
  515. randseed:=dt.hour+(dt.minute shl 8)+(dt.second shl 16)+(dt.sec100 shl 32);
  516. end;
  517. {****************************************************************************
  518. Error Message writing using messageboxes
  519. ****************************************************************************}
  520. const
  521. WinInitialize: TWinInitialize = nil;
  522. WinCreateMsgQueue: TWinCreateMsgQueue = nil;
  523. WinMessageBox: TWinMessageBox = nil;
  524. EnvSize: cardinal = 0;
  525. var
  526. ErrorBuf: array [0..ErrorBufferLength] of char;
  527. ErrorLen: longint;
  528. PMWinHandle: cardinal;
  529. function ErrorWrite (var F: TextRec): integer;
  530. {
  531. An error message should always end with #13#10#13#10
  532. }
  533. var
  534. P: PChar;
  535. I: longint;
  536. begin
  537. if F.BufPos > 0 then
  538. begin
  539. if F.BufPos + ErrorLen > ErrorBufferLength then
  540. I := ErrorBufferLength - ErrorLen
  541. else
  542. I := F.BufPos;
  543. Move (F.BufPtr^, ErrorBuf [ErrorLen], I);
  544. Inc (ErrorLen, I);
  545. ErrorBuf [ErrorLen] := #0;
  546. end;
  547. if ErrorLen > 3 then
  548. begin
  549. P := @ErrorBuf [ErrorLen];
  550. for I := 1 to 4 do
  551. begin
  552. Dec (P);
  553. if not (P^ in [#10, #13]) then
  554. break;
  555. end;
  556. end;
  557. if ErrorLen = ErrorBufferLength then
  558. I := 4;
  559. if (I = 4) then
  560. begin
  561. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  562. ErrorLen := 0;
  563. end;
  564. F.BufPos := 0;
  565. ErrorWrite := 0;
  566. end;
  567. function ErrorClose (var F: TextRec): integer;
  568. begin
  569. if ErrorLen > 0 then
  570. begin
  571. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  572. ErrorLen := 0;
  573. end;
  574. ErrorLen := 0;
  575. ErrorClose := 0;
  576. end;
  577. function ErrorOpen (var F: TextRec): integer;
  578. begin
  579. TextRec(F).InOutFunc := @ErrorWrite;
  580. TextRec(F).FlushFunc := @ErrorWrite;
  581. TextRec(F).CloseFunc := @ErrorClose;
  582. ErrorOpen := 0;
  583. end;
  584. procedure AssignError (var T: Text);
  585. begin
  586. Assign (T, '');
  587. TextRec (T).OpenFunc := @ErrorOpen;
  588. Rewrite (T);
  589. end;
  590. procedure SysInitStdIO;
  591. begin
  592. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  593. displayed in a messagebox }
  594. (*
  595. StdInputHandle := longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  596. StdOutputHandle := longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  597. StdErrorHandle := longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  598. if not IsConsole then
  599. begin
  600. if (DosLoadModule (nil, 0, 'PMWIN', PMWinHandle) = 0) and
  601. (DosQueryProcAddr (PMWinHandle, 789, nil, pointer (WinMessageBox)) = 0)
  602. and
  603. (DosQueryProcAddr (PMWinHandle, 763, nil, pointer (WinInitialize)) = 0)
  604. and
  605. (DosQueryProcAddr (PMWinHandle, 716, nil, pointer (WinCreateMsgQueue))
  606. = 0)
  607. then
  608. begin
  609. WinInitialize (0);
  610. WinCreateMsgQueue (0, 0);
  611. end
  612. else
  613. HandleError (2);
  614. AssignError (StdErr);
  615. AssignError (StdOut);
  616. Assign (Output, '');
  617. Assign (Input, '');
  618. end
  619. else
  620. begin
  621. *)
  622. OpenStdIO (Input, fmInput, StdInputHandle);
  623. OpenStdIO (Output, fmOutput, StdOutputHandle);
  624. OpenStdIO (ErrOutput, fmOutput, StdErrorHandle);
  625. OpenStdIO (StdOut, fmOutput, StdOutputHandle);
  626. OpenStdIO (StdErr, fmOutput, StdErrorHandle);
  627. (*
  628. end;
  629. *)
  630. end;
  631. function strcopy(dest,source : pchar) : pchar;assembler;
  632. var
  633. saveeax,saveesi,saveedi : longint;
  634. asm
  635. movl %edi,saveedi
  636. movl %esi,saveesi
  637. {$ifdef REGCALL}
  638. movl %eax,saveeax
  639. movl %edx,%edi
  640. {$else}
  641. movl source,%edi
  642. {$endif}
  643. testl %edi,%edi
  644. jz .LStrCopyDone
  645. leal 3(%edi),%ecx
  646. andl $-4,%ecx
  647. movl %edi,%esi
  648. subl %edi,%ecx
  649. {$ifdef REGCALL}
  650. movl %eax,%edi
  651. {$else}
  652. movl dest,%edi
  653. {$endif}
  654. jz .LStrCopyAligned
  655. .LStrCopyAlignLoop:
  656. movb (%esi),%al
  657. incl %edi
  658. incl %esi
  659. testb %al,%al
  660. movb %al,-1(%edi)
  661. jz .LStrCopyDone
  662. decl %ecx
  663. jnz .LStrCopyAlignLoop
  664. .balign 16
  665. .LStrCopyAligned:
  666. movl (%esi),%eax
  667. movl %eax,%edx
  668. leal 0x0fefefeff(%eax),%ecx
  669. notl %edx
  670. addl $4,%esi
  671. andl %edx,%ecx
  672. andl $0x080808080,%ecx
  673. jnz .LStrCopyEndFound
  674. movl %eax,(%edi)
  675. addl $4,%edi
  676. jmp .LStrCopyAligned
  677. .LStrCopyEndFound:
  678. testl $0x0ff,%eax
  679. jz .LStrCopyByte
  680. testl $0x0ff00,%eax
  681. jz .LStrCopyWord
  682. testl $0x0ff0000,%eax
  683. jz .LStrCopy3Bytes
  684. movl %eax,(%edi)
  685. jmp .LStrCopyDone
  686. .LStrCopy3Bytes:
  687. xorb %dl,%dl
  688. movw %ax,(%edi)
  689. movb %dl,2(%edi)
  690. jmp .LStrCopyDone
  691. .LStrCopyWord:
  692. movw %ax,(%edi)
  693. jmp .LStrCopyDone
  694. .LStrCopyByte:
  695. movb %al,(%edi)
  696. .LStrCopyDone:
  697. {$ifdef REGCALL}
  698. movl saveeax,%eax
  699. {$else}
  700. movl dest,%eax
  701. {$endif}
  702. movl saveedi,%edi
  703. movl saveesi,%esi
  704. end;
  705. threadvar
  706. DefaultCreator: ShortString;
  707. DefaultFileType: ShortString;
  708. procedure SetDefaultOS2FileType (FType: ShortString);
  709. begin
  710. {$WARNING Not implemented yet!}
  711. DefaultFileType := FType;
  712. end;
  713. procedure SetDefaultOS2Creator (Creator: ShortString);
  714. begin
  715. {$WARNING Not implemented yet!}
  716. DefaultCreator := Creator;
  717. end;
  718. procedure InitEnvironment;
  719. var env_count : longint;
  720. dos_env,cp : pchar;
  721. begin
  722. env_count:=0;
  723. cp:=environment;
  724. while cp ^ <> #0 do
  725. begin
  726. inc(env_count);
  727. while (cp^ <> #0) do inc(longint(cp)); { skip to NUL }
  728. inc(longint(cp)); { skip to next character }
  729. end;
  730. envp := sysgetmem((env_count+1) * sizeof(pchar));
  731. envc := env_count;
  732. if (envp = nil) then exit;
  733. cp:=environment;
  734. env_count:=0;
  735. while cp^ <> #0 do
  736. begin
  737. envp[env_count] := sysgetmem(strlen(cp)+1);
  738. strcopy(envp[env_count], cp);
  739. {$IfDef DEBUGENVIRONMENT}
  740. Writeln(stderr,'env ',env_count,' = "',envp[env_count],'"');
  741. {$EndIf}
  742. inc(env_count);
  743. while (cp^ <> #0) do
  744. inc(longint(cp)); { skip to NUL }
  745. inc(longint(cp)); { skip to next character }
  746. end;
  747. envp[env_count]:=nil;
  748. end;
  749. var
  750. (* Initialized by system unit initialization *)
  751. PIB: PProcessInfoBlock;
  752. procedure InitArguments;
  753. var
  754. arglen,
  755. count : PtrInt;
  756. argstart,
  757. pc,arg : pchar;
  758. quote : char;
  759. argvlen : PtrInt;
  760. procedure allocarg(idx,len: PtrInt);
  761. var
  762. oldargvlen : PtrInt;
  763. begin
  764. if idx>=argvlen then
  765. begin
  766. oldargvlen:=argvlen;
  767. argvlen:=(idx+8) and (not 7);
  768. sysreallocmem(argv,argvlen*sizeof(pointer));
  769. { fillchar(argv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);}
  770. end;
  771. { use realloc to reuse already existing memory }
  772. { always allocate, even if length is zero, since }
  773. { the arg. is still present! }
  774. ArgV [Idx] := SysAllocMem (Succ (Len));
  775. end;
  776. begin
  777. CmdLine := SysAllocMem (MaxPathLen);
  778. ArgV := SysAllocMem (8 * SizeOf (pointer));
  779. ArgLen := StrLen (PChar (PIB^.Cmd));
  780. Inc (ArgLen);
  781. if DosQueryModuleName (PIB^.Handle, MaxPathLen, CmdLine) = 0 then
  782. ArgVLen := Succ (StrLen (CmdLine))
  783. else
  784. (* Error occurred - use program name from command line as fallback. *)
  785. begin
  786. Move (PIB^.Cmd^, CmdLine, ArgLen);
  787. ArgVLen := ArgLen;
  788. end;
  789. { Get ArgV [0] }
  790. ArgV [0] := SysAllocMem (ArgVLen);
  791. Move (CmdLine^, ArgV [0]^, ArgVLen);
  792. Count := 1;
  793. (* PC points to leading space after program name on command line *)
  794. PC := PChar (PIB^.Cmd) + ArgLen;
  795. (* ArgLen contains size of command line arguments including leading space. *)
  796. ArgLen := Succ (StrLen (PC));
  797. SysReallocMem (CmdLine, ArgVLen + ArgLen);
  798. Move (PC^, CmdLine [ArgVLen], Succ (ArgLen));
  799. (* ArgV has space for 8 parameters from the first allocation. *)
  800. ArgVLen := 8;
  801. { process arguments }
  802. while pc^<>#0 do
  803. begin
  804. { skip leading spaces }
  805. while pc^ in [#1..#32] do
  806. inc(pc);
  807. if pc^=#0 then
  808. break;
  809. { calc argument length }
  810. quote:=' ';
  811. argstart:=pc;
  812. arglen:=0;
  813. while (pc^<>#0) do
  814. begin
  815. case pc^ of
  816. #1..#32 :
  817. begin
  818. if quote<>' ' then
  819. inc(arglen)
  820. else
  821. break;
  822. end;
  823. '"' :
  824. begin
  825. if quote<>'''' then
  826. begin
  827. if pchar(pc+1)^<>'"' then
  828. begin
  829. if quote='"' then
  830. quote:=' '
  831. else
  832. quote:='"';
  833. end
  834. else
  835. inc(pc);
  836. end
  837. else
  838. inc(arglen);
  839. end;
  840. '''' :
  841. begin
  842. if quote<>'"' then
  843. begin
  844. if pchar(pc+1)^<>'''' then
  845. begin
  846. if quote='''' then
  847. quote:=' '
  848. else
  849. quote:='''';
  850. end
  851. else
  852. inc(pc);
  853. end
  854. else
  855. inc(arglen);
  856. end;
  857. else
  858. inc(arglen);
  859. end;
  860. inc(pc);
  861. end;
  862. { copy argument }
  863. { Don't copy the first one, it is already there.}
  864. If Count<>0 then
  865. begin
  866. allocarg(count,arglen);
  867. quote:=' ';
  868. pc:=argstart;
  869. arg:=argv[count];
  870. while (pc^<>#0) do
  871. begin
  872. case pc^ of
  873. #1..#32 :
  874. begin
  875. if quote<>' ' then
  876. begin
  877. arg^:=pc^;
  878. inc(arg);
  879. end
  880. else
  881. break;
  882. end;
  883. '"' :
  884. begin
  885. if quote<>'''' then
  886. begin
  887. if pchar(pc+1)^<>'"' then
  888. begin
  889. if quote='"' then
  890. quote:=' '
  891. else
  892. quote:='"';
  893. end
  894. else
  895. inc(pc);
  896. end
  897. else
  898. begin
  899. arg^:=pc^;
  900. inc(arg);
  901. end;
  902. end;
  903. '''' :
  904. begin
  905. if quote<>'"' then
  906. begin
  907. if pchar(pc+1)^<>'''' then
  908. begin
  909. if quote='''' then
  910. quote:=' '
  911. else
  912. quote:='''';
  913. end
  914. else
  915. inc(pc);
  916. end
  917. else
  918. begin
  919. arg^:=pc^;
  920. inc(arg);
  921. end;
  922. end;
  923. else
  924. begin
  925. arg^:=pc^;
  926. inc(arg);
  927. end;
  928. end;
  929. inc(pc);
  930. end;
  931. arg^:=#0;
  932. end;
  933. {$IfDef DEBUGARGUMENTS}
  934. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  935. {$EndIf}
  936. inc(count);
  937. end;
  938. { get argc and create an nil entry }
  939. argc:=count;
  940. allocarg(argc,0);
  941. { free unused memory }
  942. sysreallocmem(argv,(argc+1)*sizeof(pointer));
  943. end;
  944. function GetFileHandleCount: longint;
  945. var L1: longint;
  946. L2: cardinal;
  947. begin
  948. L1 := 0; (* Don't change the amount, just check. *)
  949. if DosSetRelMaxFH (L1, L2) <> 0 then GetFileHandleCount := 50
  950. else GetFileHandleCount := L2;
  951. end;
  952. function CheckInitialStkLen (StkLen: SizeUInt): SizeUInt;
  953. begin
  954. CheckInitialStkLen := StkLen;
  955. end;
  956. var TIB: PThreadInfoBlock;
  957. RC: cardinal;
  958. ErrStr: string;
  959. P: pointer;
  960. DosCallsHandle: THandle;
  961. const
  962. DosCallsName: array [0..8] of char = 'DOSCALLS'#0;
  963. {*var}
  964. {* ST: pointer;}
  965. {*}
  966. begin
  967. {$IFDEF OS2EXCEPTIONS}
  968. (* asm
  969. { allocate space for exception registration record }
  970. pushl $0
  971. pushl $0}
  972. {* pushl %fs:(0)}
  973. { movl %esp,%fs:(0)
  974. but don't insert it as it doesn't
  975. point to anything yet
  976. this will be used in signals unit }
  977. movl %esp,%eax
  978. movl %eax,ExcptReg
  979. pushl %ebp
  980. movl %esp,%eax
  981. {* movl %eax,st*}
  982. movl %eax,StackTop
  983. end;
  984. {* StackTop:=st;}
  985. *) asm
  986. xorl %eax,%eax
  987. movw %ss,%ax
  988. movl %eax,_SS
  989. call SysResetFPU
  990. end;
  991. {$ENDIF OS2EXCEPTIONS}
  992. DosGetInfoBlocks (@TIB, @PIB);
  993. StackBottom := TIB^.Stack;
  994. { $IFNDEF OS2EXCEPTIONS}
  995. StackTop := TIB^.StackLimit;
  996. { $ENDIF OS2EXCEPTIONS}
  997. StackLength := CheckInitialStkLen (InitialStkLen);
  998. {Set type of application}
  999. ApplicationType := PIB^.ProcType;
  1000. ProcessID := PIB^.PID;
  1001. ThreadID := TIB^.TIB2^.TID;
  1002. IsConsole := ApplicationType <> 3;
  1003. ExitProc := nil;
  1004. {$IFDEF OS2EXCEPTIONS}
  1005. Install_Exception_Handler;
  1006. {$ENDIF OS2EXCEPTIONS}
  1007. (* Initialize the amount of file handles *)
  1008. FileHandleCount := GetFileHandleCount;
  1009. {Initialize the heap.}
  1010. (* Logic is following:
  1011. The heap is initially restricted to low address space (< 512 MB).
  1012. If underlying OS/2 version allows using more than 512 MB per process
  1013. (OS/2 WarpServer for e-Business, eComStation, possibly OS/2 Warp 4.0
  1014. with FP13 and above as well), use of this high memory is allowed for
  1015. future memory allocations at the end of System unit initialization.
  1016. The consequences are that the compiled application can allocate more
  1017. memory, but it must make sure to use direct DosAllocMem calls if it
  1018. needs a memory block for some system API not supporting high memory.
  1019. This is probably no problem for direct calls to these APIs, but
  1020. there might be situations when a memory block needs to be passed
  1021. to a 3rd party DLL which in turn calls such an API call. In case
  1022. of problems usage of high memory can be turned off by setting
  1023. UseHighMem to false - the program should change the setting at its
  1024. very beginning (e.g. in initialization section of the first unit
  1025. listed in the "uses" section) to avoid having preallocated memory
  1026. from the high memory region before changing value of this variable. *)
  1027. InitHeap;
  1028. if DosQueryModuleHandle (@DosCallsName [0], DosCallsHandle) = 0 then
  1029. begin
  1030. if DosQueryProcAddr (DosCallsHandle, OrdDosOpenL, nil, P) = 0 then
  1031. begin
  1032. Sys_DosOpenL := TDosOpenL (P);
  1033. if DosQueryProcAddr (DosCallsHandle, OrdDosSetFilePtrL, nil, P) = 0
  1034. then
  1035. begin
  1036. Sys_DosSetFilePtrL := TDosSetFilePtrL (P);
  1037. if DosQueryProcAddr (DosCallsHandle, OrdDosSetFileSizeL, nil,
  1038. P) = 0 then
  1039. begin
  1040. Sys_DosSetFileSizeL := TDosSetFileSizeL (P);
  1041. FSApi64 := true;
  1042. end;
  1043. end;
  1044. end;
  1045. end;
  1046. { ... and exceptions }
  1047. SysInitExceptions;
  1048. fpc_cpucodeinit;
  1049. { ... and I/O }
  1050. SysInitStdIO;
  1051. { no I/O-Error }
  1052. inoutres:=0;
  1053. {Initialize environment (must be after InitHeap because allocates memory)}
  1054. Environment := pointer (PIB^.Env);
  1055. InitEnvironment;
  1056. InitArguments;
  1057. DefaultCreator := '';
  1058. DefaultFileType := '';
  1059. InitSystemThreads;
  1060. InitVariantManager;
  1061. {$ifdef HASWIDESTRING}
  1062. {$ifdef VER2_2}
  1063. InitWideStringManager;
  1064. {$else VER2_2}
  1065. InitUnicodeStringManager;
  1066. {$endif VER2_2}
  1067. {$endif HASWIDESTRING}
  1068. {$IFDEF EXTDUMPGROW}
  1069. { Int_HeapSize := high (cardinal);}
  1070. {$ENDIF EXTDUMPGROW}
  1071. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1072. if IsConsole then
  1073. WriteLn (StdErr, 'Old exception ', HexStr (OldExceptAddr, 8),
  1074. ', new exception ', HexStr (NewExceptAddr, 8), ', _SS = ', HexStr (_SS, 8));
  1075. {$endif SYSTEMEXCEPTIONDEBUG}
  1076. end.