system.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  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. MaxPathLen = 256;
  31. type Tos=(osDOS,osOS2,osDPMI);
  32. var os_mode:Tos;
  33. first_meg:pointer;
  34. type TByteArray = array [0..$ffff] of byte;
  35. PByteArray = ^TByteArray;
  36. TSysThreadIB = record
  37. TID,
  38. Priority,
  39. Version: cardinal;
  40. MCCount,
  41. MCForceFlag: word;
  42. end;
  43. PSysThreadIB = ^TSysThreadIB;
  44. TThreadInfoBlock = record
  45. PExChain,
  46. Stack,
  47. StackLimit: pointer;
  48. TIB2: PSysThreadIB;
  49. Version,
  50. Ordinal: cardinal;
  51. end;
  52. PThreadInfoBlock = ^TThreadInfoBlock;
  53. PPThreadInfoBlock = ^PThreadInfoBlock;
  54. TProcessInfoBlock = record
  55. PID,
  56. ParentPid,
  57. Handle: cardinal;
  58. Cmd,
  59. Env: PByteArray;
  60. Status,
  61. ProcType: cardinal;
  62. end;
  63. PProcessInfoBlock = ^TProcessInfoBlock;
  64. PPProcessInfoBlock = ^PProcessInfoBlock;
  65. const UnusedHandle=-1;
  66. StdInputHandle=0;
  67. StdOutputHandle=1;
  68. StdErrorHandle=2;
  69. LFNSupport: boolean = true;
  70. FileNameCaseSensitive: 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. {$ifdef HASTHREADVAR}
  357. threadvar
  358. {$else HASTHREADVAR}
  359. var
  360. {$endif HASTHREADVAR}
  361. DefaultCreator: ShortString;
  362. DefaultFileType: ShortString;
  363. procedure SetDefaultOS2FileType (FType: ShortString);
  364. begin
  365. {$WARNING Not implemented yet!}
  366. DefaultFileType := FType;
  367. end;
  368. procedure SetDefaultOS2Creator (Creator: ShortString);
  369. begin
  370. {$WARNING Not implemented yet!}
  371. DefaultCreator := Creator;
  372. end;
  373. function GetFileHandleCount: longint;
  374. var L1: longint;
  375. L2: cardinal;
  376. begin
  377. L1 := 0; (* Don't change the amount, just check. *)
  378. if DosSetRelMaxFH (L1, L2) <> 0 then GetFileHandleCount := 50
  379. else GetFileHandleCount := L2;
  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. IsLibrary := FALSE;
  387. {Determine the operating system we are running on.}
  388. {$ASMMODE INTEL}
  389. asm
  390. push ebx
  391. mov os_mode, 0
  392. mov eax, 7F0Ah
  393. call syscall
  394. test bx, 512 {Bit 9 is OS/2 flag.}
  395. setne byte ptr os_mode
  396. test bx, 4096
  397. jz @noRSX
  398. mov os_mode, 2
  399. @noRSX:
  400. {Enable the brk area by initializing it with the initial heap size.}
  401. mov eax, 7F01h
  402. mov edx, heap_brk
  403. add edx, heap_base
  404. call syscall
  405. cmp eax, -1
  406. jnz @heapok
  407. lea edx, FatalHeap
  408. mov eax, 900h
  409. call syscall
  410. pop ebx
  411. push dword 204
  412. call HandleError
  413. @heapok:
  414. {$IFDEF CONTHEAP}
  415. { Find out brk limit }
  416. mov eax, 7F02h
  417. mov ecx, 3
  418. call syscall
  419. jcxz @heaplimitknown
  420. mov eax, 0
  421. @heaplimitknown:
  422. mov BrkLimit, eax
  423. {$ELSE CONTHEAP}
  424. { Change sbrk behaviour to allocate arbitrary (non-contiguous) memory blocks }
  425. mov eax, 7F0Fh
  426. mov ecx, 0Ch
  427. mov edx, 8
  428. call syscall
  429. {$ENDIF CONTHEAP}
  430. pop ebx
  431. end ['eax', 'ecx', 'edx'];
  432. { in OS/2 this will always be nil, but in DOS mode }
  433. { this can be changed. }
  434. first_meg := nil;
  435. {Now request, if we are running under DOS,
  436. read-access to the first meg. of memory.}
  437. if os_mode in [osDOS,osDPMI] then
  438. asm
  439. push ebx
  440. mov eax, 7F13h
  441. xor ebx, ebx
  442. mov ecx, 0FFFh
  443. xor edx, edx
  444. call syscall
  445. jc @endmem
  446. mov first_meg, eax
  447. @endmem:
  448. pop ebx
  449. end ['eax', 'ecx', 'edx']
  450. else
  451. begin
  452. (* Initialize the amount of file handles *)
  453. FileHandleCount := GetFileHandleCount;
  454. end;
  455. {At 0.9.2, case for enumeration does not work.}
  456. case os_mode of
  457. osDOS:
  458. begin
  459. stackbottom:=pointer(heap_brk); {In DOS mode, heap_brk is
  460. also the stack bottom.}
  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. Environment := pointer (PIB^.Env);
  471. ApplicationType := PIB^.ProcType;
  472. ProcessID := PIB^.PID;
  473. ThreadID := TIB^.TIB2^.TID;
  474. IsConsole := ApplicationType <> 3;
  475. end;
  476. osDPMI:
  477. begin
  478. stackbottom:=nil; {Not sure how to get it, but seems to be
  479. always zero.}
  480. ApplicationType := 1; (* Running under DOS. *)
  481. IsConsole := true;
  482. ProcessID := 1;
  483. ThreadID := 1;
  484. end;
  485. end;
  486. exitproc:=nil;
  487. {Initialize the heap.}
  488. initheap;
  489. { ... and exceptions }
  490. SysInitExceptions;
  491. { ... and I/O }
  492. SysInitStdIO;
  493. { no I/O-Error }
  494. inoutres:=0;
  495. InitSystemThreads;
  496. {$ifdef HASVARIANT}
  497. initvariantmanager;
  498. {$endif HASVARIANT}
  499. if os_Mode in [osDOS,osDPMI] then
  500. DosEnvInit;
  501. {$IFDEF DUMPGROW}
  502. {$IFDEF CONTHEAP}
  503. WriteLn ('Initial brk size is ', GetHeapSize);
  504. WriteLn ('Brk limit is ', BrkLimit);
  505. {$ENDIF CONTHEAP}
  506. {$ENDIF DUMPGROW}
  507. end.
  508. {
  509. $Log$
  510. Revision 1.36 2005-05-12 20:29:04 michael
  511. + Added maxpathlen constant (maximum length of filename path)
  512. Revision 1.35 2005/04/03 21:10:59 hajny
  513. * EOF_CTRLZ conditional define replaced with CtrlZMarksEOF, #26 handling made more consistent (fix for bug 2453)
  514. Revision 1.34 2005/02/14 17:13:22 peter
  515. * truncate log
  516. Revision 1.33 2005/02/06 16:57:18 peter
  517. * threads for go32v2,os,emx,netware
  518. }