system.pp 16 KB

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