system.pp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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. {$I systemh.inc}
  12. {$I tnyheaph.inc}
  13. const
  14. LineEnding = #13#10;
  15. { LFNSupport is a variable here, defined below!!! }
  16. DirectorySeparator = '\';
  17. DriveSeparator = ':';
  18. ExtensionSeparator = '.';
  19. PathSeparator = ';';
  20. AllowDirectorySeparators : set of char = ['\','/'];
  21. AllowDriveSeparators : set of char = [':'];
  22. { FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }
  23. maxExitCode = 255;
  24. MaxPathLen = 256;
  25. const
  26. { Default filehandles }
  27. UnusedHandle = $ffff;{ instead of -1, as it is a word value}
  28. StdInputHandle = 0;
  29. StdOutputHandle = 1;
  30. StdErrorHandle = 2;
  31. FileNameCaseSensitive : boolean = false;
  32. FileNameCasePreserving: boolean = false;
  33. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  34. sLineBreak = LineEnding;
  35. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  36. { Default memory segments (Tp7 compatibility) }
  37. seg0040: Word = $0040;
  38. segA000: Word = $A000;
  39. segB000: Word = $B000;
  40. segB800: Word = $B800;
  41. { The value that needs to be added to the segment to move the pointer by
  42. 64K bytes (BP7 compatibility) }
  43. SelectorInc: Word = $1000;
  44. var
  45. { Mem[] support }
  46. mem : array[0..$7fff-1] of byte absolute $0:$0;
  47. memw : array[0..($7fff div sizeof(word))-1] of word absolute $0:$0;
  48. meml : array[0..($7fff div sizeof(longint))-1] of longint absolute $0:$0;
  49. { C-compatible arguments and environment }
  50. argc:longint; //!! public name 'operatingsystem_parameter_argc';
  51. argv:PPchar; //!! public name 'operatingsystem_parameter_argv';
  52. envp:PPchar; //!! public name 'operatingsystem_parameter_envp';
  53. dos_argv0 : pchar; //!! public name 'dos_argv0';
  54. { The DOS Program Segment Prefix segment (TP7 compatibility) }
  55. PrefixSeg:Word;public name '__fpc_PrefixSeg';
  56. SaveInt00: FarPointer;public name '__SaveInt00';
  57. AllFilesMask: string [3];
  58. {$ifndef RTLLITE}
  59. { System info }
  60. LFNSupport : boolean;
  61. {$ELSE RTLLITE}
  62. const
  63. LFNSupport = false;
  64. {$endif RTLLITE}
  65. implementation
  66. procedure DebugWrite(const S: string); forward;
  67. procedure DebugWriteLn(const S: string); forward;
  68. const
  69. fCarry = 1;
  70. { used for an offset fixup for accessing the proc parameters in asm routines
  71. that use nostackframe. We can't use the parameter name directly, because
  72. i8086 doesn't support sp relative addressing. }
  73. {$ifdef FPC_X86_CODE_FAR}
  74. extra_param_offset = 2;
  75. {$else FPC_X86_CODE_FAR}
  76. extra_param_offset = 0;
  77. {$endif FPC_X86_CODE_FAR}
  78. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  79. extra_data_offset = 2;
  80. {$else}
  81. extra_data_offset = 0;
  82. {$endif}
  83. type
  84. PFarByte = ^Byte;far;
  85. PFarChar = ^Char;far;
  86. PFarWord = ^Word;far;
  87. var
  88. __stktop : pointer;public name '__stktop';
  89. __stkbottom : pointer;public name '__stkbottom';
  90. __nearheap_start: pointer;public name '__nearheap_start';
  91. __nearheap_end: pointer;public name '__nearheap_end';
  92. dos_version:Word;public name 'dos_version';
  93. {$I registers.inc}
  94. procedure Intr(IntNo: Byte; var Regs: Registers); external name 'FPC_INTR';
  95. procedure MsDos(var Regs: Registers); external name 'FPC_MSDOS';
  96. { invokes int 21h with the carry flag set on entry; used for the LFN functions
  97. to ensure that the carry flag is set on exit on older DOS versions which don't
  98. support them }
  99. procedure MsDos_Carry(var Regs: Registers); external name 'FPC_MSDOS_CARRY';
  100. procedure InstallInterruptHandlers; external name 'FPC_INSTALL_INTERRUPT_HANDLERS';
  101. procedure RestoreInterruptHandlers; external name 'FPC_RESTORE_INTERRUPT_HANDLERS';
  102. function CheckNullArea: Boolean; external name 'FPC_CHECK_NULLAREA';
  103. {$I system.inc}
  104. {$I tinyheap.inc}
  105. procedure DebugWrite(const S: string);
  106. begin
  107. asm
  108. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  109. push ds
  110. lds si, S
  111. {$else}
  112. mov si, S
  113. {$endif}
  114. {$ifdef FPC_ENABLED_CLD}
  115. cld
  116. {$endif FPC_ENABLED_CLD}
  117. lodsb
  118. mov cl, al
  119. xor ch, ch
  120. jcxz @@zero_length
  121. mov ah, 2
  122. @@1:
  123. lodsb
  124. mov dl, al
  125. int 21h
  126. loop @@1
  127. @@zero_length:
  128. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  129. pop ds
  130. {$endif}
  131. end ['ax','bx','cx','dx','si','di'];
  132. end;
  133. procedure DebugWriteLn(const S: string);
  134. begin
  135. DebugWrite(S);
  136. DebugWrite(#13#10);
  137. end;
  138. {*****************************************************************************
  139. ParamStr/Randomize
  140. *****************************************************************************}
  141. function GetProgramName: string;
  142. var
  143. dos_env_seg: Word;
  144. ofs: Word;
  145. Ch, Ch2: Char;
  146. begin
  147. if dos_version < $300 then
  148. begin
  149. GetProgramName := '';
  150. exit;
  151. end;
  152. dos_env_seg := PFarWord(Ptr(PrefixSeg, $2C))^;
  153. ofs := 1;
  154. repeat
  155. Ch := PFarChar(Ptr(dos_env_seg,ofs - 1))^;
  156. Ch2 := PFarChar(Ptr(dos_env_seg,ofs))^;
  157. if (Ch = #0) and (Ch2 = #0) then
  158. begin
  159. Inc(ofs, 3);
  160. GetProgramName := '';
  161. repeat
  162. Ch := PFarChar(Ptr(dos_env_seg,ofs))^;
  163. if Ch <> #0 then
  164. GetProgramName := GetProgramName + Ch;
  165. Inc(ofs);
  166. if ofs = 0 then
  167. begin
  168. GetProgramName := '';
  169. exit;
  170. end;
  171. until Ch = #0;
  172. exit;
  173. end;
  174. Inc(ofs);
  175. if ofs = 0 then
  176. begin
  177. GetProgramName := '';
  178. exit;
  179. end;
  180. until false;
  181. end;
  182. function GetCommandLine: string;
  183. var
  184. len, I: Integer;
  185. begin
  186. len := PFarByte(Ptr(PrefixSeg, $80))^;
  187. SetLength(GetCommandLine, len);
  188. for I := 1 to len do
  189. GetCommandLine[I] := PFarChar(Ptr(PrefixSeg, $80 + I))^;
  190. end;
  191. function GetArg(ArgNo: Integer; out ArgResult: string): Integer;
  192. var
  193. cmdln: string;
  194. I: Integer;
  195. InArg: Boolean;
  196. begin
  197. cmdln := GetCommandLine;
  198. ArgResult := '';
  199. I := 1;
  200. InArg := False;
  201. GetArg := 0;
  202. for I := 1 to Length(cmdln) do
  203. begin
  204. if not InArg and (cmdln[I] <> ' ') then
  205. begin
  206. InArg := True;
  207. Inc(GetArg);
  208. end;
  209. if InArg and (cmdln[I] = ' ') then
  210. InArg := False;
  211. if InArg and (GetArg = ArgNo) then
  212. ArgResult := ArgResult + cmdln[I];
  213. end;
  214. end;
  215. function paramcount : longint;
  216. var
  217. tmpstr: string;
  218. begin
  219. paramcount := GetArg(-1, tmpstr);
  220. end;
  221. function paramstr(l : longint) : string;
  222. begin
  223. if l = 0 then
  224. paramstr := GetProgramName
  225. else
  226. GetArg(l, paramstr);
  227. end;
  228. procedure randomize;
  229. var
  230. hl : longint;
  231. regs : Registers;
  232. begin
  233. regs.AH:=$2C;
  234. MsDos(regs);
  235. hl:=regs.DX;
  236. randseed:=hl*$10000+ regs.CX;
  237. end;
  238. {*****************************************************************************
  239. System Dependent Exit code
  240. *****************************************************************************}
  241. procedure system_exit;
  242. var
  243. h : byte;
  244. begin
  245. RestoreInterruptHandlers;
  246. for h:=0 to max_files-1 do
  247. if openfiles[h] then
  248. begin
  249. {$ifdef SYSTEMDEBUG}
  250. writeln(stderr,'file ',opennames[h],' not closed at exit');
  251. {$endif SYSTEMDEBUG}
  252. if h>=5 then
  253. do_close(h);
  254. end;
  255. {$ifndef FPC_MM_TINY}
  256. if not CheckNullArea then
  257. writeln(stderr, 'Nil pointer assignment');
  258. {$endif FPC_MM_TINY}
  259. asm
  260. mov al, byte [exitcode]
  261. mov ah, 4Ch
  262. int 21h
  263. end;
  264. end;
  265. {*****************************************************************************
  266. SystemUnit Initialization
  267. *****************************************************************************}
  268. procedure InitDosHeap;
  269. type
  270. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  271. TPointerArithmeticType = HugePointer;
  272. {$else}
  273. TPointerArithmeticType = Pointer;
  274. {$endif}
  275. begin
  276. SetMemoryManager(TinyHeapMemoryManager);
  277. RegisterTinyHeapBlock_Simple_Prealigned(__nearheap_start, TPointerArithmeticType(__nearheap_end) - TPointerArithmeticType(__nearheap_start));
  278. end;
  279. function CheckLFN:boolean;
  280. var
  281. regs : Registers;
  282. RootName : pchar;
  283. buf : array [0..31] of char;
  284. begin
  285. { Check LFN API on drive c:\ }
  286. RootName:='C:\';
  287. { Call 'Get Volume Information' ($71A0) }
  288. regs.AX:=$71a0;
  289. regs.ES:=Seg(buf);
  290. regs.DI:=Ofs(buf);
  291. regs.CX:=32;
  292. regs.DS:=Seg(RootName^);
  293. regs.DX:=Ofs(RootName^);
  294. MsDos_Carry(regs);
  295. { If carryflag=0 and LFN API bit in ebx is set then use Long file names }
  296. CheckLFN:=(regs.Flags and fCarry=0) and (regs.BX and $4000=$4000);
  297. end;
  298. procedure SysInitStdIO;
  299. begin
  300. OpenStdIO(Input,fmInput,StdInputHandle);
  301. OpenStdIO(Output,fmOutput,StdOutputHandle);
  302. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  303. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  304. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  305. end;
  306. function GetProcessID: SizeUInt;
  307. begin
  308. GetProcessID := PrefixSeg;
  309. end;
  310. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  311. begin
  312. result := stklen;
  313. end;
  314. begin
  315. StackBottom := __stkbottom;
  316. StackLength := __stktop - __stkbottom;
  317. InstallInterruptHandlers;
  318. DetectFPU;
  319. if Test8087>0 then
  320. SysInitFPU;
  321. { To be set if this is a GUI or console application }
  322. IsConsole := TRUE;
  323. { To be set if this is a library and not a program }
  324. IsLibrary := FALSE;
  325. { Setup heap }
  326. InitDosHeap;
  327. SysInitExceptions;
  328. initunicodestringmanager;
  329. { Setup stdin, stdout and stderr }
  330. SysInitStdIO;
  331. { Use LFNSupport LFN }
  332. LFNSupport:=CheckLFN;
  333. if LFNSupport then
  334. begin
  335. FileNameCasePreserving:=true;
  336. AllFilesMask := '*';
  337. end
  338. else
  339. AllFilesMask := '*.*';
  340. { Reset IO Error }
  341. InOutRes:=0;
  342. initvariantmanager;
  343. end.