system.pas 15 KB

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