system.pas 32 KB

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