system.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  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. {$I system.inc}
  122. var
  123. heap_base: pointer; external name '__heap_base';
  124. heap_brk: pointer; external name '__heap_brk';
  125. heap_end: pointer; external name '__heap_end';
  126. (* Maximum heap size - only used if heap is allocated as continuous block. *)
  127. {$IFDEF CONTHEAP}
  128. BrkLimit: cardinal;
  129. {$ENDIF CONTHEAP}
  130. {****************************************************************************
  131. Miscellaneous related routines.
  132. ****************************************************************************}
  133. {$asmmode intel}
  134. procedure system_exit; assembler;
  135. asm
  136. mov ah, 04ch
  137. mov al, byte ptr exitcode
  138. call syscall
  139. end {['EAX']};
  140. {$ASMMODE ATT}
  141. function paramcount:longint;assembler;
  142. asm
  143. movl argc,%eax
  144. decl %eax
  145. end {['EAX']};
  146. function args:pointer;assembler;
  147. asm
  148. movl argv,%eax
  149. end {['EAX']};
  150. function paramstr(l:longint):string;
  151. var p:^Pchar;
  152. begin
  153. { There seems to be a problem with EMX for DOS when trying to }
  154. { access paramstr(0), and to avoid problems between DOS and }
  155. { OS/2 they have been separated. }
  156. if os_Mode = OsOs2 then
  157. begin
  158. if L = 0 then
  159. begin
  160. GetMem (P, 260);
  161. p[0] := #0; { in case of error, initialize to empty string }
  162. {$ASMMODE INTEL}
  163. asm
  164. mov edx, P
  165. mov ecx, 260
  166. mov eax, 7F33h
  167. call syscall { error handle already with empty string }
  168. end ['eax', 'ecx', 'edx'];
  169. ParamStr := StrPas (PChar (P));
  170. FreeMem (P, 260);
  171. end
  172. else
  173. if (l>0) and (l<=paramcount) then
  174. begin
  175. p:=args;
  176. paramstr:=strpas(p[l]);
  177. end
  178. else paramstr:='';
  179. end
  180. else
  181. begin
  182. p:=args;
  183. paramstr:=strpas(p[l]);
  184. end;
  185. end;
  186. procedure randomize; assembler;
  187. asm
  188. mov ah, 2Ch
  189. call syscall
  190. mov word ptr [randseed], cx
  191. mov word ptr [randseed + 2], dx
  192. end {['eax', 'ecx', 'edx']};
  193. {$ASMMODE ATT}
  194. {*****************************************************************************
  195. System unit initialization.
  196. ****************************************************************************}
  197. {****************************************************************************
  198. Error Message writing using messageboxes
  199. ****************************************************************************}
  200. type
  201. TWinMessageBox = function (Parent, Owner: cardinal;
  202. BoxText, BoxTitle: PChar; Identity, Style: cardinal): cardinal; cdecl;
  203. TWinInitialize = function (Options: cardinal): cardinal; cdecl;
  204. TWinCreateMsgQueue = function (Handle: cardinal; cmsg: longint): cardinal;
  205. cdecl;
  206. const
  207. ErrorBufferLength = 1024;
  208. mb_OK = $0000;
  209. mb_Error = $0040;
  210. mb_Moveable = $4000;
  211. MBStyle = mb_OK or mb_Error or mb_Moveable;
  212. WinInitialize: TWinInitialize = nil;
  213. WinCreateMsgQueue: TWinCreateMsgQueue = nil;
  214. WinMessageBox: TWinMessageBox = nil;
  215. EnvSize: cardinal = 0;
  216. var
  217. ErrorBuf: array [0..ErrorBufferLength] of char;
  218. ErrorLen: longint;
  219. PMWinHandle: cardinal;
  220. function ErrorWrite (var F: TextRec): integer;
  221. {
  222. An error message should always end with #13#10#13#10
  223. }
  224. var
  225. P: PChar;
  226. I: longint;
  227. begin
  228. if F.BufPos > 0 then
  229. begin
  230. if F.BufPos + ErrorLen > ErrorBufferLength then
  231. I := ErrorBufferLength - ErrorLen
  232. else
  233. I := F.BufPos;
  234. Move (F.BufPtr^, ErrorBuf [ErrorLen], I);
  235. Inc (ErrorLen, I);
  236. ErrorBuf [ErrorLen] := #0;
  237. end;
  238. if ErrorLen > 3 then
  239. begin
  240. P := @ErrorBuf [ErrorLen];
  241. for I := 1 to 4 do
  242. begin
  243. Dec (P);
  244. if not (P^ in [#10, #13]) then
  245. break;
  246. end;
  247. end;
  248. if ErrorLen = ErrorBufferLength then
  249. I := 4;
  250. if (I = 4) then
  251. begin
  252. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  253. ErrorLen := 0;
  254. end;
  255. F.BufPos := 0;
  256. ErrorWrite := 0;
  257. end;
  258. function ErrorClose (var F: TextRec): integer;
  259. begin
  260. if ErrorLen > 0 then
  261. begin
  262. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  263. ErrorLen := 0;
  264. end;
  265. ErrorLen := 0;
  266. ErrorClose := 0;
  267. end;
  268. function ErrorOpen (var F: TextRec): integer;
  269. begin
  270. TextRec(F).InOutFunc := @ErrorWrite;
  271. TextRec(F).FlushFunc := @ErrorWrite;
  272. TextRec(F).CloseFunc := @ErrorClose;
  273. ErrorOpen := 0;
  274. end;
  275. procedure AssignError (var T: Text);
  276. begin
  277. Assign (T, '');
  278. TextRec (T).OpenFunc := @ErrorOpen;
  279. Rewrite (T);
  280. end;
  281. procedure DosEnvInit;
  282. var
  283. Q: PPChar;
  284. I: cardinal;
  285. begin
  286. (* It's a hack, in fact - DOS stores the environment the same way as OS/2 does,
  287. but I don't know how to find Program Segment Prefix and thus the environment
  288. address under EMX, so I'm recreating this structure using EnvP pointer. *)
  289. {$ASMMODE INTEL}
  290. asm
  291. cld
  292. mov ecx, EnvC
  293. mov esi, EnvP
  294. xor eax, eax
  295. xor edx, edx
  296. @L1:
  297. xchg eax, edx
  298. push ecx
  299. mov ecx, -1
  300. mov edi, [esi]
  301. repne
  302. scasb
  303. neg ecx
  304. dec ecx
  305. xchg eax, edx
  306. add eax, ecx
  307. pop ecx
  308. dec ecx
  309. jecxz @Stop
  310. inc esi
  311. inc esi
  312. inc esi
  313. inc esi
  314. jmp @L1
  315. @Stop:
  316. inc eax
  317. mov EnvSize, eax
  318. end ['eax','ecx','edx','esi','edi'];
  319. Environment := GetMem (EnvSize);
  320. asm
  321. cld
  322. mov ecx, EnvC
  323. mov edx, EnvP
  324. mov edi, Environment
  325. @L2:
  326. mov esi, [edx]
  327. @Copying:
  328. lodsb
  329. stosb
  330. or al, al
  331. jnz @Copying
  332. dec ecx
  333. jecxz @Stop2
  334. inc edx
  335. inc edx
  336. inc edx
  337. inc edx
  338. jmp @L2
  339. @Stop2:
  340. stosb
  341. end ['eax','ecx','edx','esi','edi'];
  342. end;
  343. procedure SysInitStdIO;
  344. begin
  345. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  346. displayed in a messagebox }
  347. (*
  348. StdInputHandle := longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  349. StdOutputHandle := longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  350. StdErrorHandle := longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  351. if not IsConsole then
  352. begin
  353. if (DosLoadModule (nil, 0, 'PMWIN', PMWinHandle) = 0) and
  354. (DosQueryProcAddr (PMWinHandle, 789, nil, pointer (WinMessageBox)) = 0)
  355. and
  356. (DosQueryProcAddr (PMWinHandle, 763, nil, pointer (WinInitialize)) = 0)
  357. and
  358. (DosQueryProcAddr (PMWinHandle, 716, nil, pointer (WinCreateMsgQueue))
  359. = 0)
  360. then
  361. begin
  362. WinInitialize (0);
  363. WinCreateMsgQueue (0, 0);
  364. end
  365. else
  366. HandleError (2);
  367. AssignError (StdErr);
  368. AssignError (StdOut);
  369. Assign (Output, '');
  370. Assign (Input, '');
  371. end
  372. else
  373. begin
  374. *)
  375. OpenStdIO (Input, fmInput, StdInputHandle);
  376. OpenStdIO (Output, fmOutput, StdOutputHandle);
  377. OpenStdIO (ErrOutput, fmOutput, StdErrorHandle);
  378. OpenStdIO (StdOut, fmOutput, StdOutputHandle);
  379. OpenStdIO (StdErr, fmOutput, StdErrorHandle);
  380. (*
  381. end;
  382. *)
  383. end;
  384. threadvar
  385. DefaultCreator: ShortString;
  386. DefaultFileType: ShortString;
  387. procedure SetDefaultOS2FileType (FType: ShortString);
  388. begin
  389. {$WARNING Not implemented yet!}
  390. DefaultFileType := FType;
  391. end;
  392. procedure SetDefaultOS2Creator (Creator: ShortString);
  393. begin
  394. {$WARNING Not implemented yet!}
  395. DefaultCreator := Creator;
  396. end;
  397. (* The default handler does not store the OS/2 API error codes. *)
  398. procedure NoErrorTracking (Error: cardinal);
  399. begin
  400. end;
  401. function GetFileHandleCount: longint;
  402. var L1: longint;
  403. L2: cardinal;
  404. begin
  405. L1 := 0; (* Don't change the amount, just check. *)
  406. if DosSetRelMaxFH (L1, L2) <> 0 then GetFileHandleCount := 50
  407. else GetFileHandleCount := L2;
  408. end;
  409. function CheckInitialStkLen (StkLen: SizeUInt): SizeUInt;
  410. begin
  411. CheckInitialStkLen := StkLen;
  412. end;
  413. var TIB: PThreadInfoBlock;
  414. PIB: PProcessInfoBlock;
  415. const
  416. FatalHeap: array [0..33] of char = 'FATAL: Cannot initialize heap!!'#13#10'$';
  417. begin
  418. {Determine the operating system we are running on.}
  419. {$ASMMODE INTEL}
  420. asm
  421. push ebx
  422. mov os_mode, 0
  423. mov eax, 7F0Ah
  424. call syscall
  425. test bx, 512 {Bit 9 is OS/2 flag.}
  426. setne byte ptr os_mode
  427. test bx, 4096
  428. jz @noRSX
  429. mov os_mode, 2
  430. @noRSX:
  431. {Enable the brk area by initializing it with the initial heap size.}
  432. mov eax, 7F01h
  433. mov edx, heap_brk
  434. add edx, heap_base
  435. call syscall
  436. cmp eax, -1
  437. jnz @heapok
  438. lea edx, FatalHeap
  439. mov eax, 900h
  440. call syscall
  441. pop ebx
  442. push dword 204
  443. call HandleError
  444. @heapok:
  445. {$IFDEF CONTHEAP}
  446. { Find out brk limit }
  447. mov eax, 7F02h
  448. mov ecx, 3
  449. call syscall
  450. jcxz @heaplimitknown
  451. mov eax, 0
  452. @heaplimitknown:
  453. mov BrkLimit, eax
  454. {$ELSE CONTHEAP}
  455. { Change sbrk behaviour to allocate arbitrary (non-contiguous) memory blocks }
  456. mov eax, 7F0Fh
  457. mov ecx, 0Ch
  458. mov edx, 8
  459. call syscall
  460. {$ENDIF CONTHEAP}
  461. pop ebx
  462. end ['eax', 'ecx', 'edx'];
  463. { in OS/2 this will always be nil, but in DOS mode }
  464. { this can be changed. }
  465. first_meg := nil;
  466. {Now request, if we are running under DOS,
  467. read-access to the first meg. of memory.}
  468. if os_mode in [osDOS,osDPMI] then
  469. asm
  470. push ebx
  471. mov eax, 7F13h
  472. xor ebx, ebx
  473. mov ecx, 0FFFh
  474. xor edx, edx
  475. call syscall
  476. jc @endmem
  477. mov first_meg, eax
  478. @endmem:
  479. pop ebx
  480. end ['eax', 'ecx', 'edx']
  481. else
  482. begin
  483. (* Initialize the amount of file handles *)
  484. FileHandleCount := GetFileHandleCount;
  485. end;
  486. {At 0.9.2, case for enumeration does not work.}
  487. case os_mode of
  488. osDOS:
  489. begin
  490. stackbottom:=pointer(heap_brk); {In DOS mode, heap_brk is
  491. also the stack bottom.}
  492. StackLength:=sptr-stackbottom;
  493. {$WARNING To be checked/corrected!}
  494. ApplicationType := 1; (* Running under DOS. *)
  495. IsConsole := true;
  496. asm
  497. mov ax, 7F05h
  498. call syscall
  499. mov ProcessID, eax
  500. end ['eax'];
  501. ThreadID := 1;
  502. end;
  503. osOS2:
  504. begin
  505. DosGetInfoBlocks (@TIB, @PIB);
  506. StackLength:=CheckInitialStkLen(InitialStklen);
  507. { OS/2 has top of stack in TIB^.StackLimit - unlike Windows where it is in TIB^.Stack }
  508. StackBottom := TIB^.StackLimit - StackLength;
  509. Environment := pointer (PIB^.Env);
  510. ApplicationType := PIB^.ProcType;
  511. ProcessID := PIB^.PID;
  512. ThreadID := TIB^.TIB2^.TID;
  513. IsConsole := ApplicationType <> 3;
  514. FileNameCasePreserving := true;
  515. end;
  516. osDPMI:
  517. begin
  518. stackbottom:=nil; {Not sure how to get it, but seems to be
  519. always zero.}
  520. StackLength:=sptr-stackbottom;
  521. {$WARNING To be checked/corrected!}
  522. ApplicationType := 1; (* Running under DOS. *)
  523. IsConsole := true;
  524. ThreadID := 1;
  525. end;
  526. end;
  527. exitproc:=nil;
  528. {Initialize the heap.}
  529. initheap;
  530. { ... and exceptions }
  531. SysInitExceptions;
  532. {$ifdef HASWIDESTRING}
  533. InitUnicodeStringManager;
  534. {$endif HASWIDESTRING}
  535. { ... and I/O }
  536. SysInitStdIO;
  537. { no I/O-Error }
  538. inoutres:=0;
  539. InitSystemThreads;
  540. InitSystemDynLibs;
  541. if os_Mode in [osDOS,osDPMI] then
  542. DosEnvInit;
  543. {$IFDEF DUMPGROW}
  544. {$IFDEF CONTHEAP}
  545. WriteLn ('Initial brk size is ', GetHeapSize);
  546. WriteLn ('Brk limit is ', BrkLimit);
  547. {$ENDIF CONTHEAP}
  548. {$ENDIF DUMPGROW}
  549. end.