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