fpc/rtl/msdos/system.pp
2013-05-24 18:20:08 +00:00

348 lines
8.0 KiB
ObjectPascal

unit system;
{$ASMMODE intel}
interface
{$DEFINE FPC_INCLUDE_SOFTWARE_MUL}
{$DEFINE FPC_INCLUDE_SOFTWARE_MOD_DIV}
{$DEFINE FPC_USE_SMALL_DEFAULTSTACKSIZE}
{ To avoid warnings in thread.inc code,
but value must be really given after
systemh.inc is included otherwise the
$mode switch is not effective }
{$I systemh.inc}
const
LineEnding = #13#10;
{ LFNSupport is a variable here, defined below!!! }
DirectorySeparator = '\';
DriveSeparator = ':';
ExtensionSeparator = '.';
PathSeparator = ';';
AllowDirectorySeparators : set of char = ['\','/'];
AllowDriveSeparators : set of char = [':'];
{ FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }
maxExitCode = 255;
MaxPathLen = 256;
const
{ Default filehandles }
UnusedHandle = $ffff;{ instead of -1, as it is a word value}
StdInputHandle = 0;
StdOutputHandle = 1;
StdErrorHandle = 2;
FileNameCaseSensitive : boolean = false;
FileNameCasePreserving: boolean = false;
CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
sLineBreak = LineEnding;
DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
{ Default memory segments (Tp7 compatibility) }
seg0040 = $0040;
segA000 = $A000;
segB000 = $B000;
segB800 = $B800;
var
{ Mem[] support }
mem : array[0..$7fff-1] of byte absolute $0:$0;
memw : array[0..($7fff div sizeof(word))-1] of word absolute $0:$0;
meml : array[0..($7fff div sizeof(longint))-1] of longint absolute $0:$0;
{ C-compatible arguments and environment }
argc:longint; //!! public name 'operatingsystem_parameter_argc';
argv:PPchar; //!! public name 'operatingsystem_parameter_argv';
envp:PPchar; //!! public name 'operatingsystem_parameter_envp';
dos_argv0 : pchar; //!! public name 'dos_argv0';
dos_psp:Word;public name 'dos_psp';
__stkbottom : pointer;public name '__stkbottom';
__nearheap_start: pointer;public name '__nearheap_start';
__nearheap_end: pointer;public name '__nearheap_end';
AllFilesMask: string [3];
{$ifndef RTLLITE}
{ System info }
LFNSupport : boolean;
{$ELSE RTLLITE}
const
LFNSupport = false;
{$endif RTLLITE}
procedure DebugWrite(const S: string);
procedure DebugWriteLn(const S: string);
implementation
const
fCarry = 1;
type
PFarByte = ^Byte;far;
PFarChar = ^Char;far;
PFarWord = ^Word;far;
var
dos_version:Word;public name 'dos_version';
{$I registers.inc}
procedure Intr(IntNo: Byte; var Regs: Registers); external name 'FPC_INTR';
procedure MsDos(var Regs: Registers); external name 'FPC_MSDOS';
{ invokes int 21h with the carry flag set on entry; used for the LFN functions
to ensure that the carry flag is set on exit on older DOS versions which don't
support them }
procedure MsDos_Carry(var Regs: Registers); external name 'FPC_MSDOS_CARRY';
{$I system.inc}
{$I tinyheap.inc}
procedure DebugWrite(const S: string);
begin
asm
mov si, S
lodsb
mov cl, al
xor ch, ch
mov ah, 2
@@1:
lodsb
mov dl, al
int 21h
loop @@1
end ['ax','bx','cx','dx','si','di'];
end;
procedure DebugWriteLn(const S: string);
begin
DebugWrite(S);
DebugWrite(#13#10);
end;
{*****************************************************************************
ParamStr/Randomize
*****************************************************************************}
function GetProgramName: string;
var
dos_env_seg: Word;
ofs: Word;
Ch, Ch2: Char;
begin
if dos_version < $300 then
begin
GetProgramName := '';
exit;
end;
dos_env_seg := PFarWord(Ptr(dos_psp, $2C))^;
ofs := 1;
repeat
Ch := PFarChar(Ptr(dos_env_seg,ofs - 1))^;
Ch2 := PFarChar(Ptr(dos_env_seg,ofs))^;
if (Ch = #0) and (Ch2 = #0) then
begin
Inc(ofs, 3);
GetProgramName := '';
repeat
Ch := PFarChar(Ptr(dos_env_seg,ofs))^;
if Ch <> #0 then
GetProgramName := GetProgramName + Ch;
Inc(ofs);
if ofs = 0 then
begin
GetProgramName := '';
exit;
end;
until Ch = #0;
exit;
end;
Inc(ofs);
if ofs = 0 then
begin
GetProgramName := '';
exit;
end;
until false;
end;
function GetCommandLine: string;
var
len, I: Integer;
begin
len := PFarByte(Ptr(dos_psp, $80))^;
{$ifdef CG_BUG}
{ doesn't work due to a code generator bug }
SetLength(GetCommandLine, len);
for I := 1 to len do
GetCommandLine[I] := PFarChar(Ptr(dos_psp, $80 + I))^;
{$else CG_BUG}
GetCommandLine := '';
for I := 1 to len do
GetCommandLine := GetCommandLine + PFarChar(Ptr(dos_psp, $80 + I))^;
{$endif CG_BUG}
end;
function GetArg(ArgNo: Integer; out ArgResult: string): Integer;
var
cmdln: string;
I: Integer;
InArg: Boolean;
begin
cmdln := GetCommandLine;
ArgResult := '';
I := 1;
InArg := False;
GetArg := 0;
for I := 1 to Length(cmdln) do
begin
if not InArg and (cmdln[I] <> ' ') then
begin
InArg := True;
Inc(GetArg);
end;
if InArg and (cmdln[I] = ' ') then
InArg := False;
if InArg and (GetArg = ArgNo) then
ArgResult := ArgResult + cmdln[I];
end;
end;
function paramcount : longint;
var
tmpstr: string;
begin
paramcount := GetArg(-1, tmpstr);
end;
function paramstr(l : longint) : string;
begin
if l = 0 then
paramstr := GetProgramName
else
GetArg(l, paramstr);
end;
procedure randomize;
var
hl : longint;
regs : Registers;
begin
regs.AH:=$2C;
MsDos(regs);
hl:=regs.DX;
randseed:=hl*$10000+ regs.CX;
end;
{*****************************************************************************
System Dependent Exit code
*****************************************************************************}
procedure system_exit;
var
h : byte;
begin
for h:=0 to max_files-1 do
if openfiles[h] then
begin
{$ifdef SYSTEMDEBUG}
writeln(stderr,'file ',opennames[h],' not closed at exit');
{$endif SYSTEMDEBUG}
if h>=5 then
do_close(h);
end;
asm
mov al, byte [exitcode]
mov ah, 4Ch
int 21h
end;
end;
{*****************************************************************************
SystemUnit Initialization
*****************************************************************************}
procedure InitNearHeap;
begin
SetMemoryManager(TinyHeapMemoryManager);
RegisterTinyHeapBlock(__nearheap_start, ptruint(__nearheap_end) - ptruint(__nearheap_start));
end;
function CheckLFN:boolean;
var
regs : Registers;
RootName : pchar;
buf : array [0..31] of char;
begin
{ Check LFN API on drive c:\ }
RootName:='C:\';
{ Call 'Get Volume Information' ($71A0) }
regs.AX:=$71a0;
regs.ES:=Seg(buf);
regs.DI:=Ofs(buf);
regs.CX:=32;
regs.DS:=Seg(RootName^);
regs.DX:=Ofs(RootName^);
MsDos_Carry(regs);
{ If carryflag=0 and LFN API bit in ebx is set then use Long file names }
CheckLFN:=(regs.Flags and fCarry=0) and (regs.BX and $4000=$4000);
end;
procedure SysInitStdIO;
begin
OpenStdIO(Input,fmInput,StdInputHandle);
OpenStdIO(Output,fmOutput,StdOutputHandle);
OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
OpenStdIO(StdOut,fmOutput,StdOutputHandle);
OpenStdIO(StdErr,fmOutput,StdErrorHandle);
end;
function GetProcessID: SizeUInt;
begin
GetProcessID := dos_psp;
end;
function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
begin
result := stklen;
end;
begin
StackLength := CheckInitialStkLen(InitialStkLen);
StackBottom := __stkbottom;
if DetectFPU then
SysInitFPU;
{ To be set if this is a GUI or console application }
IsConsole := TRUE;
{ To be set if this is a library and not a program }
IsLibrary := FALSE;
{ Setup heap }
InitNearHeap;
SysInitExceptions;
initunicodestringmanager;
{ Setup stdin, stdout and stderr }
SysInitStdIO;
{ Use LFNSupport LFN }
LFNSupport:=CheckLFN;
if LFNSupport then
begin
FileNameCasePreserving:=true;
AllFilesMask := '*';
end
else
AllFilesMask := '*.*';
{ Reset IO Error }
InOutRes:=0;
initvariantmanager;
end.