system.pp 14 KB

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