system.pp 11 KB

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