system.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. {
  2. ****************************************************************************
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2002 by Free Pascal development team
  5. Free Pascal - EMX 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. {Link the startup code.}
  15. {$l prt1.o}
  16. {$define FPC_SYSTEM_HAS_SYSDLH}
  17. {$I systemh.inc}
  18. const
  19. (* Are file sizes > 2 GB (64-bit) supported on the current system? *)
  20. FSApi64: boolean = false;
  21. (* Is full Unicode support provided by the underlying OS/2 version available *)
  22. (* and successfully initialized (otherwise dummy routines need to be used). *)
  23. UniAPI: boolean = false;
  24. DosCallsHandle: THandle = THandle (-1);
  25. LineEnding = #13#10;
  26. { LFNSupport is defined separately below!!! }
  27. DirectorySeparator = '\';
  28. DriveSeparator = ':';
  29. ExtensionSeparator = '.';
  30. PathSeparator = ';';
  31. AllowDirectorySeparators : set of char = ['\','/'];
  32. AllowDriveSeparators : set of char = [':'];
  33. { FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }
  34. maxExitCode = 255;
  35. MaxPathLen = 256;
  36. AllFilesMask = '*';
  37. type Tos=(osDOS,osOS2,osDPMI);
  38. var os_mode:Tos;
  39. first_meg:pointer;
  40. type TByteArray = array [0..$ffff] of byte;
  41. PByteArray = ^TByteArray;
  42. TSysThreadIB = record
  43. TID,
  44. Priority,
  45. Version: cardinal;
  46. MCCount,
  47. MCForceFlag: word;
  48. end;
  49. PSysThreadIB = ^TSysThreadIB;
  50. TThreadInfoBlock = record
  51. PExChain,
  52. Stack,
  53. StackLimit: pointer;
  54. TIB2: PSysThreadIB;
  55. Version,
  56. Ordinal: cardinal;
  57. end;
  58. PThreadInfoBlock = ^TThreadInfoBlock;
  59. PPThreadInfoBlock = ^PThreadInfoBlock;
  60. TProcessInfoBlock = record
  61. PID,
  62. ParentPid,
  63. Handle: cardinal;
  64. Cmd,
  65. Env: PByteArray;
  66. Status,
  67. ProcType: cardinal;
  68. end;
  69. PProcessInfoBlock = ^TProcessInfoBlock;
  70. PPProcessInfoBlock = ^PProcessInfoBlock;
  71. const UnusedHandle=-1;
  72. StdInputHandle=0;
  73. StdOutputHandle=1;
  74. StdErrorHandle=2;
  75. LFNSupport: boolean = true;
  76. FileNameCaseSensitive: boolean = false;
  77. FileNameCasePreserving: boolean = false;
  78. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  79. sLineBreak = LineEnding;
  80. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  81. var
  82. { C-compatible arguments and environment }
  83. argc : longint;external name '_argc';
  84. argv : ppchar;external name '_argv';
  85. envp : ppchar;external name '_environ';
  86. EnvC: cardinal; external name '_envc';
  87. (* Pointer to the block of environment variables - used e.g. in unit Dos. *)
  88. Environment: PChar;
  89. var
  90. (* Type / run mode of the current process: *)
  91. (* 0 .. full screen OS/2 session *)
  92. (* 1 .. DOS session *)
  93. (* 2 .. VIO windowable OS/2 session *)
  94. (* 3 .. Presentation Manager OS/2 session *)
  95. (* 4 .. detached (background) OS/2 process *)
  96. ApplicationType: cardinal;
  97. procedure SetDefaultOS2FileType (FType: ShortString);
  98. procedure SetDefaultOS2Creator (Creator: ShortString);
  99. (* Support for tracking I/O errors returned by OS/2 API calls - emulation *)
  100. (* of GetLastError / fpGetError functionality used e.g. in Sysutils. *)
  101. type
  102. TOSErrorWatch = procedure (Error: cardinal);
  103. procedure NoErrorTracking (Error: cardinal);
  104. (* This shall be invoked whenever a non-zero error is returned by OS/2 APIs *)
  105. (* used in the RTL. Direct OS/2 API calls in user programs are not covered! *)
  106. const
  107. OSErrorWatch: TOSErrorWatch = @NoErrorTracking;
  108. type
  109. TDosOpenL = function (FileName: PChar; var Handle: THandle;
  110. var Action: cardinal; InitSize: int64;
  111. Attrib, OpenFlags, FileMode: cardinal;
  112. EA: pointer): cardinal; cdecl;
  113. TDosSetFilePtrL = function (Handle: THandle; Pos: int64; Method: cardinal;
  114. var PosActual: int64): cardinal; cdecl;
  115. TDosSetFileSizeL = function (Handle: THandle; Size: int64): cardinal; cdecl;
  116. var
  117. Sys_DosOpenL: TDosOpenL;
  118. Sys_DosSetFilePtrL: TDosSetFilePtrL;
  119. Sys_DosSetFileSizeL: TDosSetFileSizeL;
  120. implementation
  121. { EMX cross-assembler is way too old to support 64bit opcodes }
  122. {$define OLD_ASSEMBLER}
  123. {$I system.inc}
  124. var
  125. heap_base: pointer; external name '__heap_base';
  126. heap_brk: pointer; external name '__heap_brk';
  127. heap_end: pointer; external name '__heap_end';
  128. (* Maximum heap size - only used if heap is allocated as continuous block. *)
  129. {$IFDEF CONTHEAP}
  130. BrkLimit: cardinal;
  131. {$ENDIF CONTHEAP}
  132. {****************************************************************************
  133. Miscellaneous related routines.
  134. ****************************************************************************}
  135. {$asmmode intel}
  136. procedure system_exit; assembler;
  137. asm
  138. mov ah, 04ch
  139. mov al, byte ptr exitcode
  140. call syscall
  141. end {['EAX']};
  142. {$ASMMODE ATT}
  143. function paramcount:longint;assembler;
  144. asm
  145. movl argc,%eax
  146. decl %eax
  147. end {['EAX']};
  148. function args:pointer;assembler;
  149. asm
  150. movl argv,%eax
  151. end {['EAX']};
  152. function paramstr(l:longint):string;
  153. var p:^Pchar;
  154. begin
  155. { There seems to be a problem with EMX for DOS when trying to }
  156. { access paramstr(0), and to avoid problems between DOS and }
  157. { OS/2 they have been separated. }
  158. if os_Mode = OsOs2 then
  159. begin
  160. if L = 0 then
  161. begin
  162. GetMem (P, 260);
  163. p[0] := #0; { in case of error, initialize to empty string }
  164. {$ASMMODE INTEL}
  165. asm
  166. mov edx, P
  167. mov ecx, 260
  168. mov eax, 7F33h
  169. call syscall { error handle already with empty string }
  170. end ['eax', 'ecx', 'edx'];
  171. ParamStr := StrPas (PChar (P));
  172. FreeMem (P, 260);
  173. end
  174. else
  175. if (l>0) and (l<=paramcount) then
  176. begin
  177. p:=args;
  178. paramstr:=strpas(p[l]);
  179. end
  180. else paramstr:='';
  181. end
  182. else
  183. begin
  184. p:=args;
  185. paramstr:=strpas(p[l]);
  186. end;
  187. end;
  188. procedure randomize; assembler;
  189. asm
  190. mov ah, 2Ch
  191. call syscall
  192. mov word ptr [randseed], cx
  193. mov word ptr [randseed + 2], dx
  194. end {['eax', 'ecx', 'edx']};
  195. {$ASMMODE ATT}
  196. {*****************************************************************************
  197. System unit initialization.
  198. ****************************************************************************}
  199. {****************************************************************************
  200. Error Message writing using messageboxes
  201. ****************************************************************************}
  202. type
  203. TWinMessageBox = function (Parent, Owner: cardinal;
  204. BoxText, BoxTitle: PChar; Identity, Style: cardinal): cardinal; cdecl;
  205. TWinInitialize = function (Options: cardinal): cardinal; cdecl;
  206. TWinCreateMsgQueue = function (Handle: cardinal; cmsg: longint): cardinal;
  207. cdecl;
  208. const
  209. ErrorBufferLength = 1024;
  210. mb_OK = $0000;
  211. mb_Error = $0040;
  212. mb_Moveable = $4000;
  213. MBStyle = mb_OK or mb_Error or mb_Moveable;
  214. WinInitialize: TWinInitialize = nil;
  215. WinCreateMsgQueue: TWinCreateMsgQueue = nil;
  216. WinMessageBox: TWinMessageBox = nil;
  217. EnvSize: cardinal = 0;
  218. var
  219. ErrorBuf: array [0..ErrorBufferLength] of char;
  220. ErrorLen: longint;
  221. PMWinHandle: cardinal;
  222. function ErrorWrite (var F: TextRec): integer;
  223. {
  224. An error message should always end with #13#10#13#10
  225. }
  226. var
  227. P: PChar;
  228. I: longint;
  229. begin
  230. if F.BufPos > 0 then
  231. begin
  232. if F.BufPos + ErrorLen > ErrorBufferLength then
  233. I := ErrorBufferLength - ErrorLen
  234. else
  235. I := F.BufPos;
  236. Move (F.BufPtr^, ErrorBuf [ErrorLen], I);
  237. Inc (ErrorLen, I);
  238. ErrorBuf [ErrorLen] := #0;
  239. end;
  240. if ErrorLen > 3 then
  241. begin
  242. P := @ErrorBuf [ErrorLen];
  243. for I := 1 to 4 do
  244. begin
  245. Dec (P);
  246. if not (P^ in [#10, #13]) then
  247. break;
  248. end;
  249. end;
  250. if ErrorLen = ErrorBufferLength then
  251. I := 4;
  252. if (I = 4) then
  253. begin
  254. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  255. ErrorLen := 0;
  256. end;
  257. F.BufPos := 0;
  258. ErrorWrite := 0;
  259. end;
  260. function ErrorClose (var F: TextRec): integer;
  261. begin
  262. if ErrorLen > 0 then
  263. begin
  264. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  265. ErrorLen := 0;
  266. end;
  267. ErrorLen := 0;
  268. ErrorClose := 0;
  269. end;
  270. function ErrorOpen (var F: TextRec): integer;
  271. begin
  272. TextRec(F).InOutFunc := @ErrorWrite;
  273. TextRec(F).FlushFunc := @ErrorWrite;
  274. TextRec(F).CloseFunc := @ErrorClose;
  275. ErrorOpen := 0;
  276. end;
  277. procedure AssignError (var T: Text);
  278. begin
  279. Assign (T, '');
  280. TextRec (T).OpenFunc := @ErrorOpen;
  281. Rewrite (T);
  282. end;
  283. procedure DosEnvInit;
  284. var
  285. Q: PPChar;
  286. I: cardinal;
  287. begin
  288. (* It's a hack, in fact - DOS stores the environment the same way as OS/2 does,
  289. but I don't know how to find Program Segment Prefix and thus the environment
  290. address under EMX, so I'm recreating this structure using EnvP pointer. *)
  291. {$ASMMODE INTEL}
  292. asm
  293. cld
  294. mov ecx, EnvC
  295. mov esi, EnvP
  296. xor eax, eax
  297. xor edx, edx
  298. @L1:
  299. xchg eax, edx
  300. push ecx
  301. mov ecx, -1
  302. mov edi, [esi]
  303. repne
  304. scasb
  305. neg ecx
  306. dec ecx
  307. xchg eax, edx
  308. add eax, ecx
  309. pop ecx
  310. dec ecx
  311. jecxz @Stop
  312. inc esi
  313. inc esi
  314. inc esi
  315. inc esi
  316. jmp @L1
  317. @Stop:
  318. inc eax
  319. mov EnvSize, eax
  320. end ['eax','ecx','edx','esi','edi'];
  321. Environment := GetMem (EnvSize);
  322. asm
  323. cld
  324. mov ecx, EnvC
  325. mov edx, EnvP
  326. mov edi, Environment
  327. @L2:
  328. mov esi, [edx]
  329. @Copying:
  330. lodsb
  331. stosb
  332. or al, al
  333. jnz @Copying
  334. dec ecx
  335. jecxz @Stop2
  336. inc edx
  337. inc edx
  338. inc edx
  339. inc edx
  340. jmp @L2
  341. @Stop2:
  342. stosb
  343. end ['eax','ecx','edx','esi','edi'];
  344. end;
  345. procedure SysInitStdIO;
  346. begin
  347. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  348. displayed in a messagebox }
  349. (*
  350. StdInputHandle := longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  351. StdOutputHandle := longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  352. StdErrorHandle := longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  353. if not IsConsole then
  354. begin
  355. if (DosLoadModule (nil, 0, 'PMWIN', PMWinHandle) = 0) and
  356. (DosQueryProcAddr (PMWinHandle, 789, nil, pointer (WinMessageBox)) = 0)
  357. and
  358. (DosQueryProcAddr (PMWinHandle, 763, nil, pointer (WinInitialize)) = 0)
  359. and
  360. (DosQueryProcAddr (PMWinHandle, 716, nil, pointer (WinCreateMsgQueue))
  361. = 0)
  362. then
  363. begin
  364. WinInitialize (0);
  365. WinCreateMsgQueue (0, 0);
  366. end
  367. else
  368. HandleError (2);
  369. AssignError (StdErr);
  370. AssignError (StdOut);
  371. Assign (Output, '');
  372. Assign (Input, '');
  373. end
  374. else
  375. begin
  376. *)
  377. OpenStdIO (Input, fmInput, StdInputHandle);
  378. OpenStdIO (Output, fmOutput, StdOutputHandle);
  379. OpenStdIO (ErrOutput, fmOutput, StdErrorHandle);
  380. OpenStdIO (StdOut, fmOutput, StdOutputHandle);
  381. OpenStdIO (StdErr, fmOutput, StdErrorHandle);
  382. (*
  383. end;
  384. *)
  385. end;
  386. threadvar
  387. DefaultCreator: ShortString;
  388. DefaultFileType: ShortString;
  389. procedure SetDefaultOS2FileType (FType: ShortString);
  390. begin
  391. {$WARNING Not implemented yet!}
  392. DefaultFileType := FType;
  393. end;
  394. procedure SetDefaultOS2Creator (Creator: ShortString);
  395. begin
  396. {$WARNING Not implemented yet!}
  397. DefaultCreator := Creator;
  398. end;
  399. (* The default handler does not store the OS/2 API error codes. *)
  400. procedure NoErrorTracking (Error: cardinal);
  401. begin
  402. end;
  403. function GetFileHandleCount: longint;
  404. var L1: longint;
  405. L2: cardinal;
  406. begin
  407. L1 := 0; (* Don't change the amount, just check. *)
  408. if DosSetRelMaxFH (L1, L2) <> 0 then GetFileHandleCount := 50
  409. else GetFileHandleCount := L2;
  410. end;
  411. function CheckInitialStkLen (StkLen: SizeUInt): SizeUInt;
  412. begin
  413. CheckInitialStkLen := StkLen;
  414. end;
  415. var TIB: PThreadInfoBlock;
  416. PIB: PProcessInfoBlock;
  417. const
  418. FatalHeap: array [0..33] of char = 'FATAL: Cannot initialize heap!!'#13#10'$';
  419. begin
  420. {Determine the operating system we are running on.}
  421. {$ASMMODE INTEL}
  422. asm
  423. push ebx
  424. mov os_mode, 0
  425. mov eax, 7F0Ah
  426. call syscall
  427. test bx, 512 {Bit 9 is OS/2 flag.}
  428. setne byte ptr os_mode
  429. test bx, 4096
  430. jz @noRSX
  431. mov os_mode, 2
  432. @noRSX:
  433. {Enable the brk area by initializing it with the initial heap size.}
  434. mov eax, 7F01h
  435. mov edx, heap_brk
  436. add edx, heap_base
  437. call syscall
  438. cmp eax, -1
  439. jnz @heapok
  440. lea edx, FatalHeap
  441. mov eax, 900h
  442. call syscall
  443. pop ebx
  444. push dword 204
  445. call HandleError
  446. @heapok:
  447. {$IFDEF CONTHEAP}
  448. { Find out brk limit }
  449. mov eax, 7F02h
  450. mov ecx, 3
  451. call syscall
  452. jcxz @heaplimitknown
  453. mov eax, 0
  454. @heaplimitknown:
  455. mov BrkLimit, eax
  456. {$ELSE CONTHEAP}
  457. { Change sbrk behaviour to allocate arbitrary (non-contiguous) memory blocks }
  458. mov eax, 7F0Fh
  459. mov ecx, 0Ch
  460. mov edx, 8
  461. call syscall
  462. {$ENDIF CONTHEAP}
  463. pop ebx
  464. end ['eax', 'ecx', 'edx'];
  465. { in OS/2 this will always be nil, but in DOS mode }
  466. { this can be changed. }
  467. first_meg := nil;
  468. {Now request, if we are running under DOS,
  469. read-access to the first meg. of memory.}
  470. if os_mode in [osDOS,osDPMI] then
  471. asm
  472. push ebx
  473. mov eax, 7F13h
  474. xor ebx, ebx
  475. mov ecx, 0FFFh
  476. xor edx, edx
  477. call syscall
  478. jc @endmem
  479. mov first_meg, eax
  480. @endmem:
  481. pop ebx
  482. end ['eax', 'ecx', 'edx']
  483. else
  484. begin
  485. (* Initialize the amount of file handles *)
  486. FileHandleCount := GetFileHandleCount;
  487. end;
  488. {At 0.9.2, case for enumeration does not work.}
  489. case os_mode of
  490. osDOS:
  491. begin
  492. stackbottom:=pointer(heap_brk); {In DOS mode, heap_brk is
  493. also the stack bottom.}
  494. StackLength:=sptr-stackbottom;
  495. {$WARNING To be checked/corrected!}
  496. ApplicationType := 1; (* Running under DOS. *)
  497. IsConsole := true;
  498. asm
  499. mov ax, 7F05h
  500. call syscall
  501. mov ProcessID, eax
  502. end ['eax'];
  503. ThreadID := 1;
  504. end;
  505. osOS2:
  506. begin
  507. DosGetInfoBlocks (@TIB, @PIB);
  508. StackLength:=CheckInitialStkLen(InitialStklen);
  509. { OS/2 has top of stack in TIB^.StackLimit - unlike Windows where it is in TIB^.Stack }
  510. StackBottom := TIB^.StackLimit - StackLength;
  511. Environment := pointer (PIB^.Env);
  512. ApplicationType := PIB^.ProcType;
  513. ProcessID := PIB^.PID;
  514. ThreadID := TIB^.TIB2^.TID;
  515. IsConsole := ApplicationType <> 3;
  516. FileNameCasePreserving := true;
  517. end;
  518. osDPMI:
  519. begin
  520. stackbottom:=nil; {Not sure how to get it, but seems to be
  521. always zero.}
  522. StackLength:=sptr-stackbottom;
  523. {$WARNING To be checked/corrected!}
  524. ApplicationType := 1; (* Running under DOS. *)
  525. IsConsole := true;
  526. ThreadID := 1;
  527. end;
  528. end;
  529. exitproc:=nil;
  530. {Initialize the heap.}
  531. initheap;
  532. { ... and exceptions }
  533. SysInitExceptions;
  534. {$ifdef HASWIDESTRING}
  535. InitUnicodeStringManager;
  536. {$endif HASWIDESTRING}
  537. { ... and I/O }
  538. SysInitStdIO;
  539. { no I/O-Error }
  540. inoutres:=0;
  541. InitSystemThreads;
  542. InitSystemDynLibs;
  543. if os_Mode in [osDOS,osDPMI] then
  544. DosEnvInit;
  545. {$IFDEF DUMPGROW}
  546. {$IFDEF CONTHEAP}
  547. WriteLn ('Initial brk size is ', GetHeapSize);
  548. WriteLn ('Brk limit is ', BrkLimit);
  549. {$ENDIF CONTHEAP}
  550. {$ENDIF DUMPGROW}
  551. end.