system.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. {
  2. $Id$
  3. ****************************************************************************
  4. This file is part of the Free Pascal run time library.
  5. Copyright (c) 1999-2002 by Free Pascal development team
  6. Free Pascal - EMX runtime library
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. ****************************************************************************}
  13. unit {$ifdef VER1_0}sysemx{$else}System{$endif};
  14. interface
  15. {Link the startup code.}
  16. {$ifdef VER1_0}
  17. {$l prt1.oo2}
  18. {$else}
  19. {$l prt1.o}
  20. {$endif}
  21. {$I systemh.inc}
  22. const
  23. LineEnding = #13#10;
  24. { LFNSupport is defined separately below!!! }
  25. DirectorySeparator = '\';
  26. DriveSeparator = ':';
  27. PathSeparator = ';';
  28. { FileNameCaseSensitive is defined separately below!!! }
  29. maxExitCode = 255;
  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. {$ifdef HASTHREADVAR}
  356. threadvar
  357. {$else HASTHREADVAR}
  358. var
  359. {$endif HASTHREADVAR}
  360. DefaultCreator: ShortString;
  361. DefaultFileType: ShortString;
  362. procedure SetDefaultOS2FileType (FType: ShortString);
  363. begin
  364. {$WARNING Not implemented yet!}
  365. DefaultFileType := FType;
  366. end;
  367. procedure SetDefaultOS2Creator (Creator: ShortString);
  368. begin
  369. {$WARNING Not implemented yet!}
  370. DefaultCreator := Creator;
  371. end;
  372. function GetFileHandleCount: longint;
  373. var L1: longint;
  374. L2: cardinal;
  375. begin
  376. L1 := 0; (* Don't change the amount, just check. *)
  377. if DosSetRelMaxFH (L1, L2) <> 0 then GetFileHandleCount := 50
  378. else GetFileHandleCount := L2;
  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. IsLibrary := FALSE;
  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. ApplicationType := 1; (* Running under DOS. *)
  461. IsConsole := true;
  462. ProcessID := 1;
  463. ThreadID := 1;
  464. end;
  465. osOS2:
  466. begin
  467. DosGetInfoBlocks (@TIB, @PIB);
  468. StackBottom := pointer (TIB^.Stack);
  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. ApplicationType := 1; (* Running under DOS. *)
  480. IsConsole := true;
  481. ProcessID := 1;
  482. ThreadID := 1;
  483. end;
  484. end;
  485. exitproc:=nil;
  486. {Initialize the heap.}
  487. initheap;
  488. { ... and exceptions }
  489. SysInitExceptions;
  490. { ... and I/O }
  491. SysInitStdIO;
  492. { no I/O-Error }
  493. inoutres:=0;
  494. InitSystemThreads;
  495. {$ifdef HASVARIANT}
  496. initvariantmanager;
  497. {$endif HASVARIANT}
  498. if os_Mode in [osDOS,osDPMI] then
  499. DosEnvInit;
  500. {$IFDEF DUMPGROW}
  501. {$IFDEF CONTHEAP}
  502. WriteLn ('Initial brk size is ', GetHeapSize);
  503. WriteLn ('Brk limit is ', BrkLimit);
  504. {$ENDIF CONTHEAP}
  505. {$ENDIF DUMPGROW}
  506. end.
  507. {
  508. $Log$
  509. Revision 1.35 2005-04-03 21:10:59 hajny
  510. * EOF_CTRLZ conditional define replaced with CtrlZMarksEOF, #26 handling made more consistent (fix for bug 2453)
  511. Revision 1.34 2005/02/14 17:13:22 peter
  512. * truncate log
  513. Revision 1.33 2005/02/06 16:57:18 peter
  514. * threads for go32v2,os,emx,netware
  515. }