system.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. unit system;
  2. interface
  3. {$DEFINE FPC_NO_DEFAULT_HEAP}
  4. {$DEFINE FPC_NO_DEFAULT_MEMORYMANAGER}
  5. {$DEFINE HAS_MEMORYMANAGER}
  6. {$DEFINE FPC_INCLUDE_SOFTWARE_MUL}
  7. {$DEFINE FPC_INCLUDE_SOFTWARE_MOD_DIV}
  8. {$DEFINE FPC_USE_SMALL_DEFAULTSTACKSIZE}
  9. { To avoid warnings in thread.inc code,
  10. but value must be really given after
  11. systemh.inc is included otherwise the
  12. $mode switch is not effective }
  13. {$DEFINE HAS_CMDLINE}
  14. {$DEFINE DISABLE_NO_DYNLIBS_MANAGER}
  15. {$DEFINE FPC_SYSTEM_HAS_SYSDLH}
  16. {$I systemh.inc}
  17. {$IFDEF FPC_X86_DATA_NEAR}
  18. {$I locheaph.inc}
  19. {$ELSE FPC_X86_DATA_NEAR}
  20. {$I glbheaph.inc}
  21. {$ENDIF FPC_X86_DATA_NEAR}
  22. const
  23. LineEnding = #13#10;
  24. { LFNSupport is a variable here, defined below!!! }
  25. DirectorySeparator = '\';
  26. DriveSeparator = ':';
  27. ExtensionSeparator = '.';
  28. PathSeparator = ';';
  29. AllowDirectorySeparators : set of char = ['\','/'];
  30. AllowDriveSeparators : set of char = [':'];
  31. { FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }
  32. maxExitCode = 255;
  33. MaxPathLen = 256;
  34. const
  35. { Default filehandles }
  36. UnusedHandle = $ffff;{ instead of -1, as it is a word value}
  37. StdInputHandle = 0;
  38. StdOutputHandle = 1;
  39. StdErrorHandle = 2;
  40. FileNameCaseSensitive : boolean = false;
  41. FileNameCasePreserving: boolean = false;
  42. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  43. sLineBreak = LineEnding;
  44. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  45. { Default memory segments (Tp7 compatibility) }
  46. { seg0040: Word = $0040;
  47. segA000: Word = $A000;
  48. segB000: Word = $B000;
  49. segB800: Word = $B800;}
  50. type
  51. LPSTR = ^Char;far;
  52. PFarChar = ^Char;far;
  53. PHugeChar = ^Char;huge;
  54. var
  55. { Mem[] support }
  56. mem : array[0..$7fff-1] of byte absolute $0:$0;
  57. memw : array[0..($7fff div sizeof(word))-1] of word absolute $0:$0;
  58. meml : array[0..($7fff div sizeof(longint))-1] of longint absolute $0:$0;
  59. { C-compatible arguments and environment }
  60. argc:longint; //!! public name 'operatingsystem_parameter_argc';
  61. argv:PPchar; //!! public name 'operatingsystem_parameter_argv';
  62. envp:PPchar; //!! public name 'operatingsystem_parameter_envp';
  63. dos_argv0 : pchar; //!! public name 'dos_argv0';
  64. { The DOS Program Segment Prefix segment (TP7 compatibility) }
  65. PrefixSeg:Word;public name '__fpc_PrefixSeg';
  66. { BP7 compatible windows variables }
  67. { In C, these are the parameters to WinMain }
  68. CmdLine: LPSTR;public name '__fpc_CmdLine';
  69. CmdShow: SmallInt;public name '__fpc_CmdShow';
  70. HInstance: Word{HINST};public name '__fpc_HInstance';
  71. HPrevInst: Word{HINST};public name '__fpc_HPrevInst';
  72. { The value that needs to be added to the segment to move the pointer by
  73. 64K bytes (BP7 compatibility) }
  74. SelectorInc: Word;public name '__fpc_SelectorInc';
  75. { SaveInt00: FarPointer;public name '__SaveInt00';}
  76. { Required for i8086.inc Stack check code }
  77. __stkbottom : pointer;public name '__stkbottom';
  78. AllFilesMask: string [3];
  79. {$ifndef RTLLITE}
  80. { System info }
  81. LFNSupport : boolean;
  82. {$ELSE RTLLITE}
  83. const
  84. LFNSupport = false;
  85. {$endif RTLLITE}
  86. implementation
  87. const
  88. fCarry = 1;
  89. { used for an offset fixup for accessing the proc parameters in asm routines
  90. that use nostackframe. We can't use the parameter name directly, because
  91. i8086 doesn't support sp relative addressing. }
  92. {$ifdef FPC_X86_CODE_FAR}
  93. extra_param_offset = 2;
  94. {$else FPC_X86_CODE_FAR}
  95. extra_param_offset = 0;
  96. {$endif FPC_X86_CODE_FAR}
  97. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  98. extra_data_offset = 2;
  99. {$else}
  100. extra_data_offset = 0;
  101. {$endif}
  102. type
  103. PFarByte = ^Byte;far;
  104. PFarWord = ^Word;far;
  105. { structure, located at DS:0, initialized by InitTask }
  106. PAutoDataSegHeader = ^TAutoDataSegHeader;
  107. TAutoDataSegHeader = record
  108. null: Word;
  109. oOldSP: Word;
  110. hOldSS: Word;
  111. pLocalHeap: Word;
  112. pAtomTable: Word;
  113. pStackTop: Word;
  114. pStackMin: Word;
  115. pStackBot: Word;
  116. end;
  117. {$I registers.inc}
  118. procedure MsDos(var Regs: Registers); external name 'FPC_MSDOS';
  119. { invokes int 21h with the carry flag set on entry; used for the LFN functions
  120. to ensure that the carry flag is set on exit on older DOS versions which don't
  121. support them }
  122. procedure MsDos_Carry(var Regs: Registers); external name 'FPC_MSDOS_CARRY';
  123. {$define SYSTEMUNIT}
  124. {$I wintypes.inc}
  125. {$I winprocsh.inc}
  126. {$I winprocs.inc}
  127. { in protected mode, loading invalid values into segment registers causes an
  128. exception, so we use this function to initialize our Registers structure }
  129. procedure ZeroSegRegs(var regs: Registers); inline;
  130. begin
  131. regs.DS:=0;
  132. regs.ES:=0;
  133. end;
  134. {$I system.inc}
  135. {$IFDEF FPC_X86_DATA_NEAR}
  136. {$I locheap.inc}
  137. {$ELSE FPC_X86_DATA_NEAR}
  138. {$I glbheap.inc}
  139. {$ENDIF FPC_X86_DATA_NEAR}
  140. {*****************************************************************************
  141. FinalizeHeap
  142. Dummy FinalizeHeap procedure added to fix compilation
  143. *****************************************************************************}
  144. procedure FinalizeHeap;
  145. begin
  146. end;
  147. {*****************************************************************************
  148. ParamStr/Randomize
  149. *****************************************************************************}
  150. {function GetProgramName: string;
  151. var
  152. dos_env_seg: Word;
  153. ofs: Word;
  154. Ch, Ch2: Char;
  155. begin
  156. if dos_version < $300 then
  157. begin
  158. GetProgramName := '';
  159. exit;
  160. end;
  161. dos_env_seg := PFarWord(Ptr(PrefixSeg, $2C))^;
  162. ofs := 1;
  163. repeat
  164. Ch := PFarChar(Ptr(dos_env_seg,ofs - 1))^;
  165. Ch2 := PFarChar(Ptr(dos_env_seg,ofs))^;
  166. if (Ch = #0) and (Ch2 = #0) then
  167. begin
  168. Inc(ofs, 3);
  169. GetProgramName := '';
  170. repeat
  171. Ch := PFarChar(Ptr(dos_env_seg,ofs))^;
  172. if Ch <> #0 then
  173. GetProgramName := GetProgramName + Ch;
  174. Inc(ofs);
  175. if ofs = 0 then
  176. begin
  177. GetProgramName := '';
  178. exit;
  179. end;
  180. until Ch = #0;
  181. exit;
  182. end;
  183. Inc(ofs);
  184. if ofs = 0 then
  185. begin
  186. GetProgramName := '';
  187. exit;
  188. end;
  189. until false;
  190. end;}
  191. function GetArg(ArgNo: Integer; out ArgResult: string): Integer;
  192. var
  193. I: Integer;
  194. InArg: Boolean;
  195. begin
  196. ArgResult := '';
  197. I := 0;
  198. InArg := False;
  199. GetArg := 0;
  200. while CmdLine[I]<>#0 do
  201. begin
  202. if not InArg and (CmdLine[I] <> ' ') then
  203. begin
  204. InArg := True;
  205. Inc(GetArg);
  206. end;
  207. if InArg and (CmdLine[I] = ' ') then
  208. InArg := False;
  209. if InArg and (GetArg = ArgNo) then
  210. ArgResult := ArgResult + CmdLine[I];
  211. Inc(I);
  212. end;
  213. end;
  214. function paramcount : longint;
  215. var
  216. tmpstr: string;
  217. begin
  218. paramcount := GetArg(-1, tmpstr);
  219. end;
  220. function paramstr(l : longint) : string;
  221. begin
  222. if l = 0 then
  223. paramstr := ''{GetProgramName}
  224. else
  225. GetArg(l, paramstr);
  226. end;
  227. procedure randomize;
  228. begin
  229. randseed:=GetTickCount;
  230. end;
  231. {****************************************************************************
  232. Error Message writing using messageboxes
  233. ****************************************************************************}
  234. const
  235. ErrorBufferLength = 1024;
  236. ErrorMessageBoxFlags = MB_OK or MB_ICONHAND or MB_TASKMODAL;
  237. var
  238. ErrorBuf : array[0..ErrorBufferLength] of char;
  239. ErrorLen : SizeInt;
  240. procedure ErrorWrite(Var F: TextRec);
  241. {
  242. An error message should always end with #13#10#13#10
  243. }
  244. var
  245. i : SizeInt;
  246. Begin
  247. while F.BufPos>0 do
  248. begin
  249. begin
  250. if F.BufPos+ErrorLen>ErrorBufferLength then
  251. i:=ErrorBufferLength-ErrorLen
  252. else
  253. i:=F.BufPos;
  254. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  255. inc(ErrorLen,i);
  256. ErrorBuf[ErrorLen]:=#0;
  257. end;
  258. if ErrorLen=ErrorBufferLength then
  259. begin
  260. if not NoErrMsg then
  261. {$IFDEF FPC_X86_DATA_NEAR}
  262. MessageBox(0,Ptr(Seg(ErrorBuf),Ofs(ErrorBuf)),nil,ErrorMessageBoxFlags);
  263. {$ELSE FPC_X86_DATA_NEAR}
  264. MessageBox(0,@ErrorBuf,nil,ErrorMessageBoxFlags);
  265. {$ENDIF FPC_X86_DATA_NEAR}
  266. ErrorLen:=0;
  267. end;
  268. Dec(F.BufPos,i);
  269. end;
  270. End;
  271. procedure ShowErrMsg;
  272. begin
  273. if ErrorLen>0 then
  274. begin
  275. {$IFDEF FPC_X86_DATA_NEAR}
  276. MessageBox(0,Ptr(Seg(ErrorBuf),Ofs(ErrorBuf)),nil,ErrorMessageBoxFlags);
  277. {$ELSE FPC_X86_DATA_NEAR}
  278. MessageBox(0,@ErrorBuf,nil,ErrorMessageBoxFlags);
  279. {$ENDIF FPC_X86_DATA_NEAR}
  280. ErrorLen:=0;
  281. end;
  282. end;
  283. procedure ErrorClose(Var F: TextRec);
  284. begin
  285. ShowErrMsg;
  286. end;
  287. procedure ErrorOpen(Var F: TextRec);
  288. Begin
  289. TextRec(F).Handle:=StdErrorHandle;
  290. TextRec(F).Mode:=fmOutput;
  291. TextRec(F).InOutFunc:=@ErrorWrite;
  292. TextRec(F).FlushFunc:=@ErrorWrite;
  293. TextRec(F).CloseFunc:=@ErrorClose;
  294. ErrorLen:=0;
  295. End;
  296. procedure AssignError(Var T: Text);
  297. begin
  298. Assign(T,'');
  299. TextRec(T).OpenFunc:=@ErrorOpen;
  300. Rewrite(T);
  301. end;
  302. {*****************************************************************************
  303. System Dependent Exit code
  304. *****************************************************************************}
  305. procedure system_exit;
  306. {var
  307. h : byte;}
  308. begin
  309. (* RestoreInterruptHandlers;
  310. for h:=0 to max_files-1 do
  311. if openfiles[h] then
  312. begin
  313. {$ifdef SYSTEMDEBUG}
  314. writeln(stderr,'file ',opennames[h],' not closed at exit');
  315. {$endif SYSTEMDEBUG}
  316. if h>=5 then
  317. do_close(h);
  318. end;
  319. {$ifndef FPC_MM_TINY}
  320. if not CheckNullArea then
  321. writeln(stderr, 'Nil pointer assignment');
  322. {$endif FPC_MM_TINY}*)
  323. Close(stderr);
  324. Close(stdout);
  325. Close(erroutput);
  326. Close(Input);
  327. Close(Output);
  328. ShowErrMsg;
  329. asm
  330. mov al, byte [exitcode]
  331. mov ah, 4Ch
  332. int 21h
  333. end;
  334. end;
  335. {*****************************************************************************
  336. SystemUnit Initialization
  337. *****************************************************************************}
  338. procedure InitWin16Heap;
  339. begin
  340. {$ifdef FPC_X86_DATA_NEAR}
  341. SetMemoryManager(LocalHeapMemoryManager);
  342. {$else FPC_X86_DATA_NEAR}
  343. SetMemoryManager(GlobalHeapMemoryManager);
  344. {$endif FPC_X86_DATA_NEAR}
  345. end;
  346. function CheckLFN:boolean;
  347. var
  348. regs : Registers;
  349. RootName : pchar;
  350. buf : array [0..31] of char;
  351. begin
  352. { Check LFN API on drive c:\ }
  353. RootName:='C:\';
  354. { Call 'Get Volume Information' ($71A0) }
  355. { no need to ZeroSegRegs(regs), because we initialize both DS and ES }
  356. regs.AX:=$71a0;
  357. regs.ES:=Seg(buf);
  358. regs.DI:=Ofs(buf);
  359. regs.CX:=32;
  360. regs.DS:=Seg(RootName^);
  361. regs.DX:=Ofs(RootName^);
  362. MsDos_Carry(regs);
  363. { If carryflag=0 and LFN API bit in ebx is set then use Long file names }
  364. CheckLFN:=(regs.Flags and fCarry=0) and (regs.BX and $4000=$4000);
  365. end;
  366. procedure SysInitStdIO;
  367. begin
  368. AssignError(stderr);
  369. AssignError(StdOut);
  370. Assign(Output,'');
  371. Assign(Input,'');
  372. Assign(ErrOutput,'');
  373. end;
  374. function GetProcessID: SizeUInt;
  375. begin
  376. GetProcessID := PrefixSeg;
  377. end;
  378. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  379. begin
  380. result := stklen;
  381. end;
  382. begin
  383. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  384. with PAutoDataSegHeader(Ptr(DSeg,0))^ do
  385. begin
  386. StackBottom := Ptr(SSeg,pStackTop);
  387. StackLength := pStackBot-pStackTop;
  388. end;
  389. {$else}
  390. with PAutoDataSegHeader(0)^ do
  391. begin
  392. StackBottom := NearPointer(pStackTop);
  393. StackLength := pStackBot-pStackTop;
  394. end;
  395. {$endif}
  396. __stkbottom := StackBottom;
  397. { To be set if this is a GUI or console application }
  398. IsConsole := FALSE;
  399. { To be set if this is a library and not a program }
  400. IsLibrary := FALSE;
  401. { Setup heap }
  402. InitWin16Heap;
  403. SysInitExceptions;
  404. initunicodestringmanager;
  405. { Setup stdin, stdout and stderr }
  406. SysInitStdIO;
  407. { Use LFNSupport LFN }
  408. LFNSupport:=CheckLFN;
  409. if LFNSupport then
  410. begin
  411. FileNameCasePreserving:=true;
  412. AllFilesMask := '*';
  413. end
  414. else
  415. AllFilesMask := '*.*';
  416. InitSystemDynLibs;
  417. { Reset IO Error }
  418. InOutRes:=0;
  419. {$ifdef FPC_HAS_FEATURE_THREADING}
  420. InitSystemThreads;
  421. {$endif}
  422. end.