system.pas 15 KB

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