system.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. unit System;
  2. interface
  3. {$define FPC_IS_SYSTEM}
  4. { The heap for MSDOS is implemented
  5. in tinyheap.inc include file,
  6. but it uses default SysGetMem names }
  7. {$define HAS_MEMORYMANAGER}
  8. { define TEST_FPU_INT10 to force keeping local int10,
  9. for testing purpose only }
  10. {$DEFINE FPC_INCLUDE_SOFTWARE_MUL}
  11. {$DEFINE FPC_INCLUDE_SOFTWARE_MOD_DIV}
  12. {$DEFINE FPC_USE_SMALL_DEFAULTSTACKSIZE}
  13. { To avoid warnings in thread.inc code,
  14. but value must be really given after
  15. systemh.inc is included otherwise the
  16. $mode switch is not effective }
  17. { Use Ansi Char for files }
  18. {$define FPC_ANSI_TEXTFILEREC}
  19. {$define FPC_STDOUT_TRUE_ALIAS}
  20. {$ifdef NO_WIDESTRINGS}
  21. { Do NOT use wide Char for files }
  22. {$undef FPC_HAS_FEATURE_WIDESTRINGS}
  23. {$endif NO_WIDESTRINGS}
  24. {$I systemh.inc}
  25. {$I tnyheaph.inc}
  26. {$I portsh.inc}
  27. {$ifndef FPUNONE}
  28. {$ifdef FPC_HAS_FEATURE_SOFTFPU}
  29. {$define fpc_softfpu_interface}
  30. {$i softfpu.pp}
  31. {$undef fpc_softfpu_interface}
  32. {$endif FPC_HAS_FEATURE_SOFTFPU}
  33. {$endif FPUNONE}
  34. const
  35. LineEnding = #13#10;
  36. { LFNSupport is a variable here, defined below!!! }
  37. DirectorySeparator = '\';
  38. DriveSeparator = ':';
  39. ExtensionSeparator = '.';
  40. PathSeparator = ';';
  41. AllowDirectorySeparators : set of char = ['\','/'];
  42. AllowDriveSeparators : set of char = [':'];
  43. { FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }
  44. maxExitCode = 255;
  45. MaxPathLen = 256;
  46. const
  47. { Default filehandles }
  48. UnusedHandle = $ffff;{ instead of -1, as it is a word value}
  49. StdInputHandle = 0;
  50. StdOutputHandle = 1;
  51. { MSX-DOS does not have a separate StdErr }
  52. StdErrorHandle = 1;
  53. FileNameCaseSensitive : boolean = false;
  54. FileNameCasePreserving: boolean = false;
  55. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  56. sLineBreak = LineEnding;
  57. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  58. var
  59. { Mem[] support }
  60. mem : array[0..$7fff-1] of byte absolute $0;
  61. memw : array[0..($7fff div sizeof(word))-1] of word absolute $0;
  62. meml : array[0..($7fff div sizeof(longint))-1] of longint absolute $0;
  63. { C-compatible arguments and environment }
  64. argc:smallint; //!! public name 'operatingsystem_parameter_argc';
  65. argv:PPchar; //!! public name 'operatingsystem_parameter_argv';
  66. { The DOS Program Segment Prefix segment (TP7 compatibility) }
  67. PrefixSeg:Word;public name '__fpc_PrefixSeg';
  68. SaveInt00: FarPointer;public name '__SaveInt00';
  69. SaveInt10: FarPointer;public name '__SaveInt10';
  70. SaveInt75: FarPointer;public name '__SaveInt75';
  71. fpu_status: word;public name '__fpu_status';
  72. const
  73. AllFilesMask: string [3] = '*.*';
  74. const
  75. LFNSupport = false;
  76. implementation
  77. procedure DebugWrite(s: PChar); forward;
  78. procedure DebugWrite(const S: string); forward;
  79. procedure DebugWriteLn(const S: string); forward;
  80. {$ifdef todo}
  81. const
  82. { used for an offset fixup for accessing the proc parameters in asm routines
  83. that use nostackframe. We can't use the parameter name directly, because
  84. i8086 doesn't support sp relative addressing. }
  85. {$ifdef FPC_X86_CODE_FAR}
  86. extra_param_offset = 2;
  87. {$else FPC_X86_CODE_FAR}
  88. extra_param_offset = 0;
  89. {$endif FPC_X86_CODE_FAR}
  90. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  91. extra_data_offset = 2;
  92. {$else}
  93. extra_data_offset = 0;
  94. {$endif}
  95. type
  96. PFarByte = ^Byte;//far;
  97. PFarChar = ^Char;//far;
  98. PFarWord = ^Word;//far;
  99. PPFarChar = ^PFarChar;
  100. {$endif}
  101. var
  102. stklen: word; external name '__stklen';
  103. __heapsize: Word;external name '__heapsize';
  104. __fpc_initialheap: array[0..0] of byte;external name '__fpc_initialheap';
  105. var
  106. __stktop : pointer;public name '__stktop';
  107. dos_version:Word;public name 'dos_version';
  108. dos_env_count:smallint;public name '__dos_env_count';
  109. dos_argv0 : PChar;public name '__fpc_dos_argv0';
  110. {$I registers.inc}
  111. procedure Intr(IntNo: Byte; var Regs: Registers); external name 'FPC_INTR';
  112. procedure MsxDos(var Regs: Registers); assembler; nostackframe; public name 'FPC_MSXDOS';
  113. asm
  114. //in a, (0x2e)
  115. { store registers contents }
  116. push AF
  117. push BC
  118. push DE
  119. push HL
  120. push IX
  121. push IY
  122. { allocate an additional scratch space }
  123. push IY
  124. { Regs now resides at SP + 16 }
  125. { IY is not used for parameters, so base everything on that;
  126. for that we need to load the address of Regs into IY }
  127. ld IX, 0x10
  128. add IX, SP
  129. ld L,(IX+0)
  130. ld H,(IX+1)
  131. push HL
  132. pop IY
  133. { fill IX with the help of HL }
  134. ld L,(IY+8)
  135. ld H,(IY+9)
  136. push HL
  137. pop IX
  138. ld B,(IY+1)
  139. ld C,(IY+0)
  140. ld D,(IY+3)
  141. ld E,(IY+2)
  142. // load A last
  143. //ld A,(IY+4)
  144. ld H,(IY+7)
  145. ld L,(IY+6)
  146. ld A,(IY+4)
  147. { store IY to scratch location }
  148. ex (SP),IY
  149. { call to DOS }
  150. call 0x0005
  151. { store IY to scratch and restore pointer address of Regs }
  152. ex (SP),IY
  153. ld (IY+1),B
  154. ld (IY+0),C
  155. ld (IY+3),D
  156. ld (IY+2),E
  157. ld (IY+4),A
  158. // skip F
  159. ld (IY+7),H
  160. ld (IY+6),L
  161. { store IX with the help of HL }
  162. push IX
  163. pop HL
  164. ld (IY+8),L
  165. ld (IY+9),H
  166. { store the stored IY with the help of HL }
  167. ex (SP),HL
  168. ld (IY+10),L
  169. ld (IY+11),H
  170. { cleanup stack }
  171. pop IY
  172. pop IY
  173. pop IX
  174. pop HL
  175. pop DE
  176. pop BC
  177. pop AF
  178. end;
  179. procedure InstallInterruptHandlers; external name 'FPC_INSTALL_INTERRUPT_HANDLERS';
  180. procedure RestoreInterruptHandlers; external name 'FPC_RESTORE_INTERRUPT_HANDLERS';
  181. function CheckNullArea: Boolean; external name 'FPC_CHECK_NULLAREA';
  182. {$I system.inc}
  183. {$I tinyheap.inc}
  184. {$I ports.inc}
  185. {$ifndef FPUNONE}
  186. {$ifdef FPC_HAS_FEATURE_SOFTFPU}
  187. {$define fpc_softfpu_implementation}
  188. {$i softfpu.pp}
  189. {$undef fpc_softfpu_implementation}
  190. { we get these functions and types from the softfpu code }
  191. {$define FPC_SYSTEM_HAS_float64}
  192. {$define FPC_SYSTEM_HAS_float32}
  193. {$define FPC_SYSTEM_HAS_flag}
  194. {$define FPC_SYSTEM_HAS_extractFloat64Frac0}
  195. {$define FPC_SYSTEM_HAS_extractFloat64Frac1}
  196. {$define FPC_SYSTEM_HAS_extractFloat64Exp}
  197. {$define FPC_SYSTEM_HAS_extractFloat64Frac}
  198. {$define FPC_SYSTEM_HAS_extractFloat64Sign}
  199. {$define FPC_SYSTEM_HAS_ExtractFloat32Frac}
  200. {$define FPC_SYSTEM_HAS_extractFloat32Exp}
  201. {$define FPC_SYSTEM_HAS_extractFloat32Sign}
  202. {$endif FPC_HAS_FEATURE_SOFTFPU}
  203. {$endif FPUNONE}
  204. procedure DebugWrite(S: PChar);
  205. var
  206. regs: Registers;
  207. begin
  208. while S^ <> #0 do begin
  209. regs.C := $02;
  210. regs.E := Ord(S^);
  211. MsxDos(regs);
  212. Inc(S);
  213. end;
  214. end;
  215. procedure DebugWrite(const S: string);
  216. var
  217. regs: Registers;
  218. i: Byte;
  219. begin
  220. for i := 1 to Length(S) do begin
  221. regs.C := $02;
  222. regs.E := Ord(S[i]);
  223. MsxDos(regs);
  224. end;
  225. end;
  226. procedure DebugWriteLn(const S: string);
  227. begin
  228. DebugWrite(S);
  229. DebugWrite(#13#10);
  230. end;
  231. {*****************************************************************************
  232. ParamStr/Randomize
  233. *****************************************************************************}
  234. var
  235. internal_envp : PPChar = nil;
  236. procedure setup_environment;
  237. {$ifdef todo}
  238. var
  239. env_count : smallint;
  240. cp, dos_env: PFarChar;
  241. {$endif}
  242. begin
  243. {$ifdef todo}
  244. env_count:=0;
  245. dos_env:=Ptr(MemW[PrefixSeg:$2C], 0);
  246. cp:=dos_env;
  247. while cp^<>#0 do
  248. begin
  249. inc(env_count);
  250. while (cp^ <> #0) do
  251. inc(cp); { skip to NUL }
  252. inc(cp); { skip to next character }
  253. end;
  254. internal_envp := getmem((env_count+1) * sizeof(PFarChar));
  255. cp:=dos_env;
  256. env_count:=0;
  257. while cp^<>#0 do
  258. begin
  259. internal_envp[env_count] := cp;
  260. inc(env_count);
  261. while (cp^ <> #0) do
  262. inc(cp); { skip to NUL }
  263. inc(cp); { skip to next character }
  264. end;
  265. internal_envp[env_count]:=nil;
  266. dos_env_count := env_count;
  267. if dos_version >= $300 then
  268. begin
  269. if cp=dos_env then
  270. inc(cp);
  271. inc(cp, 3);
  272. dos_argv0 := cp;
  273. end
  274. else
  275. dos_argv0 := nil;
  276. {$endif}
  277. end;
  278. function envp:PPChar;public name '__fpc_envp';
  279. begin
  280. if not assigned(internal_envp) then
  281. setup_environment;
  282. envp:=internal_envp;
  283. end;
  284. function GetEnvVar(aName: PChar): String;
  285. var
  286. regs: Registers;
  287. i: SizeInt;
  288. begin
  289. SetLength(Result, 255);
  290. regs.C := $6B;
  291. regs.HL := PtrUInt(aName);
  292. regs.DE := PtrUInt(@Result[1]);
  293. regs.B := 255;
  294. regs.A := 0;
  295. MsxDos(regs);
  296. if regs.A = 0 then begin
  297. i := 1;
  298. aName := PChar(@Result[1]);
  299. while i < 256 do begin
  300. if aName^ = #0 then begin
  301. SetLength(Result, i);
  302. Break;
  303. end;
  304. Inc(i);
  305. Inc(aName);
  306. end;
  307. end else
  308. SetLength(Result, 0);
  309. end;
  310. procedure setup_arguments;
  311. var
  312. i: SmallInt;
  313. pc: PChar;
  314. quote: Char;
  315. count: SmallInt;
  316. arglen, argv0len: SmallInt;
  317. argblock: PChar;
  318. arg: PChar;
  319. doscmd : string[129]; { Dos commandline copied from PSP, max is 128 chars +1 for terminating zero }
  320. tmp: String;
  321. regs: Registers;
  322. begin
  323. tmp := GetEnvVar('PROGRAM');
  324. argv0len := Length(tmp);
  325. tmp := GetEnvVar('PARAMETERS');
  326. {$IfDef SYSTEM_DEBUG_STARTUP}
  327. Writeln(stderr,'Dos command line is #',tmp,'# size = ',length(tmp));
  328. {$EndIf }
  329. { parse dos commandline }
  330. pc:=@tmp[1];
  331. count:=1;
  332. { calc total arguments length and count }
  333. arglen:=argv0len+1;
  334. while pc^<>#0 do
  335. begin
  336. { skip leading spaces }
  337. while pc^ in [#1..#32] do
  338. inc(pc);
  339. if pc^=#0 then
  340. break;
  341. { calc argument length }
  342. quote:=' ';
  343. while (pc^<>#0) do
  344. begin
  345. case pc^ of
  346. #1..#32 :
  347. begin
  348. if quote<>' ' then
  349. inc(arglen)
  350. else
  351. break;
  352. end;
  353. '"' :
  354. begin
  355. if quote<>'''' then
  356. begin
  357. if pchar(pc+1)^<>'"' then
  358. begin
  359. if quote='"' then
  360. quote:=' '
  361. else
  362. quote:='"';
  363. end
  364. else
  365. inc(pc);
  366. end
  367. else
  368. inc(arglen);
  369. end;
  370. '''' :
  371. begin
  372. if quote<>'"' then
  373. begin
  374. if pchar(pc+1)^<>'''' then
  375. begin
  376. if quote='''' then
  377. quote:=' '
  378. else
  379. quote:='''';
  380. end
  381. else
  382. inc(pc);
  383. end
  384. else
  385. inc(arglen);
  386. end;
  387. else
  388. inc(arglen);
  389. end;
  390. inc(pc);
  391. end;
  392. inc(arglen); { for the null terminator }
  393. inc(count);
  394. end;
  395. Writeln(stderr,'Arg count: ', count, ', size: ', arglen);
  396. { set argc and allocate argv }
  397. argc:=count;
  398. argv:=AllocMem((count+1)*SizeOf(PChar));
  399. { allocate a single memory block for all arguments }
  400. argblock:=GetMem(arglen);
  401. writeln('Allocated arg vector at ', hexstr(argv), ' and block at ', hexstr(argblock));
  402. { create argv[0] }
  403. argv[0]:=argblock;
  404. arg:=argblock+argv0len;
  405. arg^:=#0;
  406. Inc(arg);
  407. pc:=@tmp[1];
  408. count:=1;
  409. while pc^<>#0 do
  410. begin
  411. { skip leading spaces }
  412. while pc^ in [#1..#32] do
  413. inc(pc);
  414. if pc^=#0 then
  415. break;
  416. { copy argument }
  417. //writeln('Setting arg ',count,' to ', hexstr(arg));
  418. asm
  419. in a,(0x2e)
  420. end ['a'];
  421. argv[count]:=arg;
  422. quote:=' ';
  423. while (pc^<>#0) do
  424. begin
  425. case pc^ of
  426. #1..#32 :
  427. begin
  428. if quote<>' ' then
  429. begin
  430. arg^:=pc^;
  431. inc(arg);
  432. end
  433. else
  434. break;
  435. end;
  436. '"' :
  437. begin
  438. if quote<>'''' then
  439. begin
  440. if pchar(pc+1)^<>'"' then
  441. begin
  442. if quote='"' then
  443. quote:=' '
  444. else
  445. quote:='"';
  446. end
  447. else
  448. inc(pc);
  449. end
  450. else
  451. begin
  452. arg^:=pc^;
  453. inc(arg);
  454. end;
  455. end;
  456. '''' :
  457. begin
  458. if quote<>'"' then
  459. begin
  460. if pchar(pc+1)^<>'''' then
  461. begin
  462. if quote='''' then
  463. quote:=' '
  464. else
  465. quote:='''';
  466. end
  467. else
  468. inc(pc);
  469. end
  470. else
  471. begin
  472. arg^:=pc^;
  473. inc(arg);
  474. end;
  475. end;
  476. else
  477. begin
  478. arg^:=pc^;
  479. inc(arg);
  480. end;
  481. end;
  482. inc(pc);
  483. end;
  484. arg^:=#0;
  485. Inc(arg);
  486. {$IfDef SYSTEM_DEBUG_STARTUP}
  487. Writeln(stderr,'dos arg ',count,' #',strlen(argv[count]),'#',argv[count],'#');
  488. {$EndIf SYSTEM_DEBUG_STARTUP}
  489. inc(count);
  490. end;
  491. arg:=argblock;
  492. tmp:=GetEnvVar('PROGRAM');
  493. pc:=@tmp[1];
  494. while pc^ <> #0 do
  495. begin
  496. arg^ := pc^;
  497. Inc(arg);
  498. Inc(pc);
  499. end;
  500. for count:=0 to argc-1 do
  501. writeln('arg ',count,' at ',hexstr(argv[count]));
  502. end;
  503. function paramcount : longint;
  504. begin
  505. if argv=nil then
  506. setup_arguments;
  507. paramcount := argc - 1;
  508. end;
  509. function paramstr(l : longint) : string;
  510. begin
  511. if argv=nil then
  512. setup_arguments;
  513. if (l>=0) and (l+1<=argc) then
  514. paramstr:=strpas(argv[l])
  515. else
  516. paramstr:='';
  517. end;
  518. procedure randomize;
  519. {$ifdef todo}
  520. var
  521. hl : longint;
  522. regs : Registers;
  523. {$endif}
  524. begin
  525. {$ifdef todo}
  526. regs.AH:=$2C;
  527. MsDos(regs);
  528. hl:=regs.DX;
  529. randseed:=hl*$10000+ regs.CX;
  530. {$endif}
  531. end;
  532. {*****************************************************************************
  533. System Dependent Exit code
  534. *****************************************************************************}
  535. procedure system_exit;
  536. var
  537. h : byte;
  538. begin
  539. {$ifdef todo}
  540. RestoreInterruptHandlers;
  541. {$endif}
  542. for h:=0 to max_files-1 do
  543. if openfiles[h] then
  544. begin
  545. {$ifdef SYSTEMDEBUG}
  546. writeln(stderr,'file ',h,' "',opennames[h],'" not closed at exit');
  547. {$endif SYSTEMDEBUG}
  548. if h>=5 then
  549. do_close(h);
  550. end;
  551. {$ifndef FPC_MM_TINY}
  552. {$ifdef todo}
  553. if not CheckNullArea then
  554. writeln(stderr, 'Nil pointer assignment');
  555. {$endif}
  556. {$endif FPC_MM_TINY}
  557. asm
  558. ld a, exitcode
  559. ld b, a
  560. ld c, 0x62
  561. call 0x0005
  562. end;
  563. end;
  564. {*****************************************************************************
  565. SystemUnit Initialization
  566. *****************************************************************************}
  567. procedure InitDosHeap;
  568. begin
  569. RegisterTinyHeapBlock_Simple_Prealigned(@__fpc_initialheap,__heapsize);
  570. end;
  571. procedure SysInitStdIO;
  572. begin
  573. OpenStdIO(Input,fmInput,StdInputHandle);
  574. OpenStdIO(Output,fmOutput,StdOutputHandle);
  575. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  576. {$ifndef FPC_STDOUT_TRUE_ALIAS}
  577. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  578. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  579. {$endif FPC_STDOUT_TRUE_ALIAS}
  580. end;
  581. function GetProcessID: SizeUInt;
  582. begin
  583. GetProcessID := PrefixSeg;
  584. end;
  585. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  586. begin
  587. result := stklen;
  588. end;
  589. procedure InitDosVersion;
  590. var
  591. regs: Registers;
  592. begin
  593. regs.C := $6F;
  594. regs.A := 0;
  595. MsxDos(regs);
  596. if regs.A <> 0 then
  597. dos_version := 0
  598. else if regs.B < 2 then
  599. dos_version := $100
  600. else
  601. dos_version := regs.DE;
  602. end;
  603. begin
  604. StackLength := stklen;
  605. StackBottom := __stktop - stklen;
  606. InitDosVersion;
  607. { for now we don't support MSX-DOS 1 }
  608. if dos_version < $100 then
  609. Halt($85);
  610. {$ifdef todo}
  611. InstallInterruptHandlers;
  612. {$endif}
  613. { To be set if this is a GUI or console application }
  614. IsConsole := TRUE;
  615. {$ifdef FPC_HAS_FEATURE_DYNLIBS}
  616. { If dynlibs feature is disabled,
  617. IsLibrary is a constant, which can thus not be set to a value }
  618. { To be set if this is a library and not a program }
  619. IsLibrary := FALSE;
  620. {$endif def FPC_HAS_FEATURE_DYNLIBS}
  621. { Setup heap }
  622. InitDosHeap;
  623. SysInitExceptions;
  624. {$ifdef FPC_HAS_FEATURE_UNICODESTRINGS}
  625. initunicodestringmanager;
  626. {$endif def FPC_HAS_FEATURE_UNICODESTRINGS}
  627. { Setup stdin, stdout and stderr }
  628. SysInitStdIO;
  629. { Setup environment and arguments }
  630. { Done on request only Setup_Environment; }
  631. { Done on request only Setup_Arguments; }
  632. { Reset IO Error }
  633. InOutRes:=0;
  634. {$ifdef FPC_HAS_FEATURE_THREADING}
  635. InitSystemThreads;
  636. {$endif}
  637. end.