system.pp 14 KB

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