system.pp 14 KB

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