2
0

system.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. unit System;
  2. interface
  3. {$DEFINE FPC_NO_DEFAULT_HEAP}
  4. {$define FPC_NO_DEFAULT_MEMORYMANAGER}
  5. {$DEFINE FPC_INCLUDE_SOFTWARE_MUL}
  6. {$DEFINE FPC_INCLUDE_SOFTWARE_MOD_DIV}
  7. {$DEFINE FPC_USE_SMALL_DEFAULTSTACKSIZE}
  8. { To avoid warnings in thread.inc code,
  9. but value must be really given after
  10. systemh.inc is included otherwise the
  11. $mode switch is not effective }
  12. { Use Ansi Char for files }
  13. {$define FPC_ANSI_TEXTFILEREC}
  14. {$ifdef NO_WIDESTRINGS}
  15. { Do NOT use wide Char for files }
  16. {$undef FPC_HAS_FEATURE_WIDESTRINGS}
  17. {$endif NO_WIDESTRINGS}
  18. {$I systemh.inc}
  19. {$I tnyheaph.inc}
  20. const
  21. LineEnding = #13#10;
  22. { LFNSupport is a variable here, defined below!!! }
  23. DirectorySeparator = '\';
  24. DriveSeparator = ':';
  25. ExtensionSeparator = '.';
  26. PathSeparator = ';';
  27. AllowDirectorySeparators : set of char = ['\','/'];
  28. AllowDriveSeparators : set of char = [':'];
  29. { FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }
  30. maxExitCode = 255;
  31. MaxPathLen = 256;
  32. const
  33. { Default filehandles }
  34. UnusedHandle = $ffff;{ instead of -1, as it is a word value}
  35. StdInputHandle = 0;
  36. StdOutputHandle = 1;
  37. StdErrorHandle = 2;
  38. FileNameCaseSensitive : boolean = false;
  39. FileNameCasePreserving: boolean = false;
  40. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  41. sLineBreak = LineEnding;
  42. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  43. { Default memory segments (Tp7 compatibility) }
  44. seg0040: Word = $0040;
  45. segA000: Word = $A000;
  46. segB000: Word = $B000;
  47. segB800: Word = $B800;
  48. { The value that needs to be added to the segment to move the pointer by
  49. 64K bytes (BP7 compatibility) }
  50. SelectorInc: Word = $1000;
  51. var
  52. { Mem[] support }
  53. mem : array[0..$7fff-1] of byte absolute $0:$0;
  54. memw : array[0..($7fff div sizeof(word))-1] of word absolute $0:$0;
  55. meml : array[0..($7fff div sizeof(longint))-1] of longint absolute $0:$0;
  56. { C-compatible arguments and environment }
  57. argc:smallint; //!! public name 'operatingsystem_parameter_argc';
  58. argv:PPchar; //!! public name 'operatingsystem_parameter_argv';
  59. { The DOS Program Segment Prefix segment (TP7 compatibility) }
  60. PrefixSeg:Word;public name '__fpc_PrefixSeg';
  61. SaveInt00: FarPointer;public name '__SaveInt00';
  62. AllFilesMask: string [3];
  63. {$ifndef RTLLITE}
  64. { System info }
  65. LFNSupport : boolean;
  66. {$ELSE RTLLITE}
  67. const
  68. LFNSupport = false;
  69. {$endif RTLLITE}
  70. implementation
  71. procedure DebugWrite(const S: string); forward;
  72. procedure DebugWriteLn(const S: string); forward;
  73. const
  74. fCarry = 1;
  75. { used for an offset fixup for accessing the proc parameters in asm routines
  76. that use nostackframe. We can't use the parameter name directly, because
  77. i8086 doesn't support sp relative addressing. }
  78. {$ifdef FPC_X86_CODE_FAR}
  79. extra_param_offset = 2;
  80. {$else FPC_X86_CODE_FAR}
  81. extra_param_offset = 0;
  82. {$endif FPC_X86_CODE_FAR}
  83. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  84. extra_data_offset = 2;
  85. {$else}
  86. extra_data_offset = 0;
  87. {$endif}
  88. type
  89. PFarByte = ^Byte;far;
  90. PFarChar = ^Char;far;
  91. PFarWord = ^Word;far;
  92. PPFarChar = ^PFarChar;
  93. var
  94. __stktop : pointer;public name '__stktop';
  95. __stkbottom : pointer;public name '__stkbottom';
  96. __nearheap_start: pointer;public name '__nearheap_start';
  97. __nearheap_end: pointer;public name '__nearheap_end';
  98. dos_version:Word;public name 'dos_version';
  99. envp:PPFarChar;public name '__fpc_envp';
  100. dos_env_count:smallint;public name '__dos_env_count';
  101. dos_argv0 : PFarChar;public name '__fpc_dos_argv0';
  102. {$I registers.inc}
  103. procedure Intr(IntNo: Byte; var Regs: Registers); external name 'FPC_INTR';
  104. procedure MsDos(var Regs: Registers); external name 'FPC_MSDOS';
  105. { invokes int 21h with the carry flag set on entry; used for the LFN functions
  106. to ensure that the carry flag is set on exit on older DOS versions which don't
  107. support them }
  108. procedure MsDos_Carry(var Regs: Registers); external name 'FPC_MSDOS_CARRY';
  109. procedure InstallInterruptHandlers; external name 'FPC_INSTALL_INTERRUPT_HANDLERS';
  110. procedure RestoreInterruptHandlers; external name 'FPC_RESTORE_INTERRUPT_HANDLERS';
  111. function CheckNullArea: Boolean; external name 'FPC_CHECK_NULLAREA';
  112. {$I system.inc}
  113. {$I tinyheap.inc}
  114. procedure DebugWrite(const S: string);
  115. begin
  116. asm
  117. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  118. push ds
  119. lds si, S
  120. {$else}
  121. mov si, S
  122. {$endif}
  123. {$ifdef FPC_ENABLED_CLD}
  124. cld
  125. {$endif FPC_ENABLED_CLD}
  126. lodsb
  127. mov cl, al
  128. xor ch, ch
  129. jcxz @@zero_length
  130. mov ah, 2
  131. @@1:
  132. lodsb
  133. mov dl, al
  134. int 21h
  135. loop @@1
  136. @@zero_length:
  137. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  138. pop ds
  139. {$endif}
  140. end ['ax','bx','cx','dx','si','di'];
  141. end;
  142. procedure DebugWriteLn(const S: string);
  143. begin
  144. DebugWrite(S);
  145. DebugWrite(#13#10);
  146. end;
  147. {*****************************************************************************
  148. ParamStr/Randomize
  149. *****************************************************************************}
  150. procedure setup_environment;
  151. var
  152. env_count : smallint;
  153. cp, dos_env: PFarChar;
  154. begin
  155. env_count:=0;
  156. dos_env:=Ptr(MemW[PrefixSeg:$2C], 0);
  157. cp:=dos_env;
  158. while cp^<>#0 do
  159. begin
  160. inc(env_count);
  161. while (cp^ <> #0) do
  162. inc(cp); { skip to NUL }
  163. inc(cp); { skip to next character }
  164. end;
  165. envp := getmem((env_count+1) * sizeof(PFarChar));
  166. cp:=dos_env;
  167. env_count:=0;
  168. while cp^<>#0 do
  169. begin
  170. envp[env_count] := cp;
  171. inc(env_count);
  172. while (cp^ <> #0) do
  173. inc(cp); { skip to NUL }
  174. inc(cp); { skip to next character }
  175. end;
  176. envp[env_count]:=nil;
  177. dos_env_count := env_count;
  178. if dos_version >= $300 then
  179. begin
  180. if cp=dos_env then
  181. inc(cp);
  182. inc(cp, 3);
  183. dos_argv0 := cp;
  184. end
  185. else
  186. dos_argv0 := nil;
  187. end;
  188. procedure setup_arguments;
  189. var
  190. I: SmallInt;
  191. pc: PChar;
  192. pfc: PFarChar;
  193. quote: Char;
  194. count: SmallInt;
  195. arglen, argv0len: SmallInt;
  196. argblock: PChar;
  197. arg: PChar;
  198. doscmd : string[129]; { Dos commandline copied from PSP, max is 128 chars +1 for terminating zero }
  199. begin
  200. { load commandline from psp }
  201. SetLength(doscmd, Mem[PrefixSeg:$80]);
  202. for I := 1 to length(doscmd) do
  203. doscmd[I] := Chr(Mem[PrefixSeg:$80+I]);
  204. doscmd[length(doscmd)+1]:=#0;
  205. {$IfDef SYSTEM_DEBUG_STARTUP}
  206. Writeln(stderr,'Dos command line is #',doscmd,'# size = ',length(doscmd));
  207. {$EndIf }
  208. { find argv0len }
  209. argv0len:=0;
  210. if dos_argv0<>nil then
  211. begin
  212. pfc:=dos_argv0;
  213. while pfc^<>#0 do
  214. begin
  215. Inc(argv0len);
  216. Inc(pfc);
  217. end;
  218. end;
  219. { parse dos commandline }
  220. pc:=@doscmd[1];
  221. count:=1;
  222. { calc total arguments length and count }
  223. arglen:=argv0len+1;
  224. while pc^<>#0 do
  225. begin
  226. { skip leading spaces }
  227. while pc^ in [#1..#32] do
  228. inc(pc);
  229. if pc^=#0 then
  230. break;
  231. { calc argument length }
  232. quote:=' ';
  233. while (pc^<>#0) do
  234. begin
  235. case pc^ of
  236. #1..#32 :
  237. begin
  238. if quote<>' ' then
  239. inc(arglen)
  240. else
  241. break;
  242. end;
  243. '"' :
  244. begin
  245. if quote<>'''' then
  246. begin
  247. if pchar(pc+1)^<>'"' then
  248. begin
  249. if quote='"' then
  250. quote:=' '
  251. else
  252. quote:='"';
  253. end
  254. else
  255. inc(pc);
  256. end
  257. else
  258. inc(arglen);
  259. end;
  260. '''' :
  261. begin
  262. if quote<>'"' then
  263. begin
  264. if pchar(pc+1)^<>'''' then
  265. begin
  266. if quote='''' then
  267. quote:=' '
  268. else
  269. quote:='''';
  270. end
  271. else
  272. inc(pc);
  273. end
  274. else
  275. inc(arglen);
  276. end;
  277. else
  278. inc(arglen);
  279. end;
  280. inc(pc);
  281. end;
  282. inc(arglen); { for the null terminator }
  283. inc(count);
  284. end;
  285. { set argc and allocate argv }
  286. argc:=count;
  287. argv:=AllocMem((count+1)*SizeOf(PChar));
  288. { allocate a single memory block for all arguments }
  289. argblock:=GetMem(arglen);
  290. { create argv[0] }
  291. argv[0]:=argblock;
  292. arg:=argblock;
  293. if dos_argv0<>nil then
  294. begin
  295. pfc:=dos_argv0;
  296. while pfc^<>#0 do
  297. begin
  298. arg^:=pfc^;
  299. Inc(arg);
  300. Inc(pfc);
  301. end;
  302. end;
  303. arg^:=#0;
  304. Inc(arg);
  305. pc:=@doscmd[1];
  306. count:=1;
  307. while pc^<>#0 do
  308. begin
  309. { skip leading spaces }
  310. while pc^ in [#1..#32] do
  311. inc(pc);
  312. if pc^=#0 then
  313. break;
  314. { copy argument }
  315. argv[count]:=arg;
  316. quote:=' ';
  317. while (pc^<>#0) do
  318. begin
  319. case pc^ of
  320. #1..#32 :
  321. begin
  322. if quote<>' ' then
  323. begin
  324. arg^:=pc^;
  325. inc(arg);
  326. end
  327. else
  328. break;
  329. end;
  330. '"' :
  331. begin
  332. if quote<>'''' then
  333. begin
  334. if pchar(pc+1)^<>'"' then
  335. begin
  336. if quote='"' then
  337. quote:=' '
  338. else
  339. quote:='"';
  340. end
  341. else
  342. inc(pc);
  343. end
  344. else
  345. begin
  346. arg^:=pc^;
  347. inc(arg);
  348. end;
  349. end;
  350. '''' :
  351. begin
  352. if quote<>'"' then
  353. begin
  354. if pchar(pc+1)^<>'''' then
  355. begin
  356. if quote='''' then
  357. quote:=' '
  358. else
  359. quote:='''';
  360. end
  361. else
  362. inc(pc);
  363. end
  364. else
  365. begin
  366. arg^:=pc^;
  367. inc(arg);
  368. end;
  369. end;
  370. else
  371. begin
  372. arg^:=pc^;
  373. inc(arg);
  374. end;
  375. end;
  376. inc(pc);
  377. end;
  378. arg^:=#0;
  379. Inc(arg);
  380. {$IfDef SYSTEM_DEBUG_STARTUP}
  381. Writeln(stderr,'dos arg ',count,' #',strlen(argv[count]),'#',argv[count],'#');
  382. {$EndIf SYSTEM_DEBUG_STARTUP}
  383. inc(count);
  384. end;
  385. end;
  386. function paramcount : longint;
  387. begin
  388. paramcount := argc - 1;
  389. end;
  390. function paramstr(l : longint) : string;
  391. begin
  392. if (l>=0) and (l+1<=argc) then
  393. paramstr:=strpas(argv[l])
  394. else
  395. paramstr:='';
  396. end;
  397. procedure randomize;
  398. var
  399. hl : longint;
  400. regs : Registers;
  401. begin
  402. regs.AH:=$2C;
  403. MsDos(regs);
  404. hl:=regs.DX;
  405. randseed:=hl*$10000+ regs.CX;
  406. end;
  407. {*****************************************************************************
  408. System Dependent Exit code
  409. *****************************************************************************}
  410. procedure system_exit;
  411. var
  412. h : byte;
  413. begin
  414. RestoreInterruptHandlers;
  415. for h:=0 to max_files-1 do
  416. if openfiles[h] then
  417. begin
  418. {$ifdef SYSTEMDEBUG}
  419. writeln(stderr,'file ',h,' "',opennames[h],'" not closed at exit');
  420. {$endif SYSTEMDEBUG}
  421. if h>=5 then
  422. do_close(h);
  423. end;
  424. {$ifndef FPC_MM_TINY}
  425. if not CheckNullArea then
  426. writeln(stderr, 'Nil pointer assignment');
  427. {$endif FPC_MM_TINY}
  428. asm
  429. mov al, byte [exitcode]
  430. mov ah, 4Ch
  431. int 21h
  432. end;
  433. end;
  434. {*****************************************************************************
  435. SystemUnit Initialization
  436. *****************************************************************************}
  437. procedure InitDosHeap;
  438. type
  439. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  440. TPointerArithmeticType = HugePointer;
  441. {$else}
  442. TPointerArithmeticType = Pointer;
  443. {$endif}
  444. begin
  445. SetMemoryManager(TinyHeapMemoryManager);
  446. RegisterTinyHeapBlock_Simple_Prealigned(__nearheap_start, TPointerArithmeticType(__nearheap_end) - TPointerArithmeticType(__nearheap_start));
  447. end;
  448. function CheckLFN:boolean;
  449. var
  450. regs : Registers;
  451. RootName : pchar;
  452. buf : array [0..31] of char;
  453. begin
  454. { Check LFN API on drive c:\ }
  455. RootName:='C:\';
  456. { Call 'Get Volume Information' ($71A0) }
  457. regs.AX:=$71a0;
  458. regs.ES:=Seg(buf);
  459. regs.DI:=Ofs(buf);
  460. regs.CX:=32;
  461. regs.DS:=Seg(RootName^);
  462. regs.DX:=Ofs(RootName^);
  463. MsDos_Carry(regs);
  464. { If carryflag=0 and LFN API bit in ebx is set then use Long file names }
  465. CheckLFN:=(regs.Flags and fCarry=0) and (regs.BX and $4000=$4000);
  466. end;
  467. procedure SysInitStdIO;
  468. begin
  469. OpenStdIO(Input,fmInput,StdInputHandle);
  470. OpenStdIO(Output,fmOutput,StdOutputHandle);
  471. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  472. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  473. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  474. end;
  475. function GetProcessID: SizeUInt;
  476. begin
  477. GetProcessID := PrefixSeg;
  478. end;
  479. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  480. begin
  481. result := stklen;
  482. end;
  483. begin
  484. StackBottom := __stkbottom;
  485. StackLength := __stktop - __stkbottom;
  486. InstallInterruptHandlers;
  487. DetectFPU;
  488. if Test8087>0 then
  489. SysInitFPU;
  490. { To be set if this is a GUI or console application }
  491. IsConsole := TRUE;
  492. { To be set if this is a library and not a program }
  493. IsLibrary := FALSE;
  494. { Setup heap }
  495. InitDosHeap;
  496. SysInitExceptions;
  497. initunicodestringmanager;
  498. { Setup stdin, stdout and stderr }
  499. SysInitStdIO;
  500. { Setup environment and arguments }
  501. Setup_Environment;
  502. Setup_Arguments;
  503. {$ifndef RTLLITE}
  504. { Use LFNSupport LFN }
  505. LFNSupport:=CheckLFN;
  506. if LFNSupport then
  507. begin
  508. FileNameCasePreserving:=true;
  509. AllFilesMask := '*';
  510. end
  511. else
  512. {$endif ndef RTLLITE}
  513. AllFilesMask := '*.*';
  514. { Reset IO Error }
  515. InOutRes:=0;
  516. end.