system.pas 32 KB

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