system.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  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. { in protected mode, loading invalid values into segment registers causes an
  122. exception, so we use this function to initialize our Registers structure }
  123. procedure ZeroSegRegs(var regs: Registers); inline;
  124. begin
  125. regs.DS:=0;
  126. regs.ES:=0;
  127. end;
  128. {$I system.inc}
  129. {$IFDEF FPC_X86_DATA_NEAR}
  130. {$I locheap.inc}
  131. {$ELSE FPC_X86_DATA_NEAR}
  132. {$I glbheap.inc}
  133. {$ENDIF FPC_X86_DATA_NEAR}
  134. {*****************************************************************************
  135. ParamStr/Randomize
  136. *****************************************************************************}
  137. {function GetProgramName: string;
  138. var
  139. dos_env_seg: Word;
  140. ofs: Word;
  141. Ch, Ch2: Char;
  142. begin
  143. if dos_version < $300 then
  144. begin
  145. GetProgramName := '';
  146. exit;
  147. end;
  148. dos_env_seg := PFarWord(Ptr(PrefixSeg, $2C))^;
  149. ofs := 1;
  150. repeat
  151. Ch := PFarChar(Ptr(dos_env_seg,ofs - 1))^;
  152. Ch2 := PFarChar(Ptr(dos_env_seg,ofs))^;
  153. if (Ch = #0) and (Ch2 = #0) then
  154. begin
  155. Inc(ofs, 3);
  156. GetProgramName := '';
  157. repeat
  158. Ch := PFarChar(Ptr(dos_env_seg,ofs))^;
  159. if Ch <> #0 then
  160. GetProgramName := GetProgramName + Ch;
  161. Inc(ofs);
  162. if ofs = 0 then
  163. begin
  164. GetProgramName := '';
  165. exit;
  166. end;
  167. until Ch = #0;
  168. exit;
  169. end;
  170. Inc(ofs);
  171. if ofs = 0 then
  172. begin
  173. GetProgramName := '';
  174. exit;
  175. end;
  176. until false;
  177. end;}
  178. function GetArg(ArgNo: Integer; out ArgResult: string): Integer;
  179. var
  180. I: Integer;
  181. InArg: Boolean;
  182. begin
  183. ArgResult := '';
  184. I := 0;
  185. InArg := False;
  186. GetArg := 0;
  187. while CmdLine[I]<>#0 do
  188. begin
  189. if not InArg and (CmdLine[I] <> ' ') then
  190. begin
  191. InArg := True;
  192. Inc(GetArg);
  193. end;
  194. if InArg and (CmdLine[I] = ' ') then
  195. InArg := False;
  196. if InArg and (GetArg = ArgNo) then
  197. ArgResult := ArgResult + CmdLine[I];
  198. Inc(I);
  199. end;
  200. end;
  201. function paramcount : longint;
  202. var
  203. tmpstr: string;
  204. begin
  205. paramcount := GetArg(-1, tmpstr);
  206. end;
  207. function paramstr(l : longint) : string;
  208. begin
  209. if l = 0 then
  210. paramstr := ''{GetProgramName}
  211. else
  212. GetArg(l, paramstr);
  213. end;
  214. procedure randomize;
  215. {var
  216. hl : longint;
  217. regs : Registers;}
  218. begin
  219. { regs.AH:=$2C;
  220. MsDos(regs);
  221. hl:=regs.DX;
  222. randseed:=hl*$10000+ regs.CX;}
  223. end;
  224. {****************************************************************************
  225. Error Message writing using messageboxes
  226. ****************************************************************************}
  227. const
  228. ErrorBufferLength = 1024;
  229. ErrorMessageBoxFlags = MB_OK or MB_ICONHAND or MB_TASKMODAL;
  230. var
  231. ErrorBuf : array[0..ErrorBufferLength] of char;
  232. ErrorLen : SizeInt;
  233. procedure ErrorWrite(Var F: TextRec);
  234. {
  235. An error message should always end with #13#10#13#10
  236. }
  237. var
  238. i : SizeInt;
  239. Begin
  240. while F.BufPos>0 do
  241. begin
  242. begin
  243. if F.BufPos+ErrorLen>ErrorBufferLength then
  244. i:=ErrorBufferLength-ErrorLen
  245. else
  246. i:=F.BufPos;
  247. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  248. inc(ErrorLen,i);
  249. ErrorBuf[ErrorLen]:=#0;
  250. end;
  251. if ErrorLen=ErrorBufferLength then
  252. begin
  253. if not NoErrMsg then
  254. {$IFDEF FPC_X86_DATA_NEAR}
  255. MessageBox(0,Ptr(Seg(ErrorBuf),Ofs(ErrorBuf)),nil,ErrorMessageBoxFlags);
  256. {$ELSE FPC_X86_DATA_NEAR}
  257. MessageBox(0,@ErrorBuf,nil,ErrorMessageBoxFlags);
  258. {$ENDIF FPC_X86_DATA_NEAR}
  259. ErrorLen:=0;
  260. end;
  261. Dec(F.BufPos,i);
  262. end;
  263. End;
  264. procedure ShowErrMsg;
  265. begin
  266. if ErrorLen>0 then
  267. begin
  268. {$IFDEF FPC_X86_DATA_NEAR}
  269. MessageBox(0,Ptr(Seg(ErrorBuf),Ofs(ErrorBuf)),nil,ErrorMessageBoxFlags);
  270. {$ELSE FPC_X86_DATA_NEAR}
  271. MessageBox(0,@ErrorBuf,nil,ErrorMessageBoxFlags);
  272. {$ENDIF FPC_X86_DATA_NEAR}
  273. ErrorLen:=0;
  274. end;
  275. end;
  276. procedure ErrorClose(Var F: TextRec);
  277. begin
  278. ShowErrMsg;
  279. end;
  280. procedure ErrorOpen(Var F: TextRec);
  281. Begin
  282. TextRec(F).Handle:=StdErrorHandle;
  283. TextRec(F).Mode:=fmOutput;
  284. TextRec(F).InOutFunc:=@ErrorWrite;
  285. TextRec(F).FlushFunc:=@ErrorWrite;
  286. TextRec(F).CloseFunc:=@ErrorClose;
  287. ErrorLen:=0;
  288. End;
  289. procedure AssignError(Var T: Text);
  290. begin
  291. Assign(T,'');
  292. TextRec(T).OpenFunc:=@ErrorOpen;
  293. Rewrite(T);
  294. end;
  295. {*****************************************************************************
  296. System Dependent Exit code
  297. *****************************************************************************}
  298. procedure system_exit;
  299. {var
  300. h : byte;}
  301. begin
  302. (* RestoreInterruptHandlers;
  303. for h:=0 to max_files-1 do
  304. if openfiles[h] then
  305. begin
  306. {$ifdef SYSTEMDEBUG}
  307. writeln(stderr,'file ',opennames[h],' not closed at exit');
  308. {$endif SYSTEMDEBUG}
  309. if h>=5 then
  310. do_close(h);
  311. end;
  312. {$ifndef FPC_MM_TINY}
  313. if not CheckNullArea then
  314. writeln(stderr, 'Nil pointer assignment');
  315. {$endif FPC_MM_TINY}*)
  316. Close(stderr);
  317. Close(stdout);
  318. Close(erroutput);
  319. Close(Input);
  320. Close(Output);
  321. ShowErrMsg;
  322. asm
  323. mov al, byte [exitcode]
  324. mov ah, 4Ch
  325. int 21h
  326. end;
  327. end;
  328. {*****************************************************************************
  329. SystemUnit Initialization
  330. *****************************************************************************}
  331. procedure InitWin16Heap;
  332. begin
  333. {$ifdef FPC_X86_DATA_NEAR}
  334. SetMemoryManager(LocalHeapMemoryManager);
  335. {$else FPC_X86_DATA_NEAR}
  336. SetMemoryManager(GlobalHeapMemoryManager);
  337. {$endif FPC_X86_DATA_NEAR}
  338. end;
  339. function CheckLFN:boolean;
  340. var
  341. regs : Registers;
  342. RootName : pchar;
  343. buf : array [0..31] of char;
  344. begin
  345. { Check LFN API on drive c:\ }
  346. RootName:='C:\';
  347. { Call 'Get Volume Information' ($71A0) }
  348. FillChar(regs,SizeOf(regs),0);
  349. regs.AX:=$71a0;
  350. regs.ES:=Seg(buf);
  351. regs.DI:=Ofs(buf);
  352. regs.CX:=32;
  353. regs.DS:=Seg(RootName^);
  354. regs.DX:=Ofs(RootName^);
  355. MsDos_Carry(regs);
  356. { If carryflag=0 and LFN API bit in ebx is set then use Long file names }
  357. CheckLFN:=(regs.Flags and fCarry=0) and (regs.BX and $4000=$4000);
  358. end;
  359. procedure SysInitStdIO;
  360. begin
  361. AssignError(stderr);
  362. AssignError(StdOut);
  363. Assign(Output,'');
  364. Assign(Input,'');
  365. Assign(ErrOutput,'');
  366. end;
  367. function GetProcessID: SizeUInt;
  368. begin
  369. GetProcessID := PrefixSeg;
  370. end;
  371. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  372. begin
  373. result := stklen;
  374. end;
  375. begin
  376. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  377. with PAutoDataSegHeader(Ptr(DSeg,0))^ do
  378. begin
  379. StackBottom := Ptr(SSeg,pStackTop);
  380. StackLength := pStackBot-pStackTop;
  381. end;
  382. {$else}
  383. with PAutoDataSegHeader(0)^ do
  384. begin
  385. StackBottom := NearPointer(pStackTop);
  386. StackLength := pStackBot-pStackTop;
  387. end;
  388. {$endif}
  389. { To be set if this is a GUI or console application }
  390. IsConsole := FALSE;
  391. { To be set if this is a library and not a program }
  392. IsLibrary := FALSE;
  393. { Setup heap }
  394. InitWin16Heap;
  395. SysInitExceptions;
  396. initunicodestringmanager;
  397. { Setup stdin, stdout and stderr }
  398. SysInitStdIO;
  399. { Use LFNSupport LFN }
  400. LFNSupport:=CheckLFN;
  401. if LFNSupport then
  402. begin
  403. FileNameCasePreserving:=true;
  404. AllFilesMask := '*';
  405. end
  406. else
  407. AllFilesMask := '*.*';
  408. { Reset IO Error }
  409. InOutRes:=0;
  410. end.