system.pas 14 KB

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