system.pas 15 KB

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