fpc/rtl/msdos/system.pp
nickysn 4454332d7a * fixed the sysutils.GetEnvironment* functions for i8086-msdos
- removed the envp variable from the msdos system unit, because it's not
  compatible with ppchar in all memory models (we use ppfarchar to avoid copying
  the environment in the program's data segment in near data memory models)

git-svn-id: trunk@32017 -
2015-10-11 13:23:59 +00:00

408 lines
9.7 KiB
ObjectPascal

unit System;
interface
{$DEFINE FPC_NO_DEFAULT_HEAP}
{$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}
{$I tnyheaph.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: Word = $0040;
segA000: Word = $A000;
segB000: Word = $B000;
segB800: Word = $B800;
{ The value that needs to be added to the segment to move the pointer by
64K bytes (BP7 compatibility) }
SelectorInc: Word = $1000;
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';
{ The DOS Program Segment Prefix segment (TP7 compatibility) }
PrefixSeg:Word;public name '__fpc_PrefixSeg';
SaveInt00: FarPointer;public name '__SaveInt00';
AllFilesMask: string [3];
{$ifndef RTLLITE}
{ System info }
LFNSupport : boolean;
{$ELSE RTLLITE}
const
LFNSupport = false;
{$endif RTLLITE}
implementation
procedure DebugWrite(const S: string); forward;
procedure DebugWriteLn(const S: string); forward;
const
fCarry = 1;
{ used for an offset fixup for accessing the proc parameters in asm routines
that use nostackframe. We can't use the parameter name directly, because
i8086 doesn't support sp relative addressing. }
{$ifdef FPC_X86_CODE_FAR}
extra_param_offset = 2;
{$else FPC_X86_CODE_FAR}
extra_param_offset = 0;
{$endif FPC_X86_CODE_FAR}
{$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
extra_data_offset = 2;
{$else}
extra_data_offset = 0;
{$endif}
type
PFarByte = ^Byte;far;
PFarChar = ^Char;far;
PFarWord = ^Word;far;
PPFarChar = ^PFarChar;
var
__stktop : pointer;public name '__stktop';
__stkbottom : pointer;public name '__stkbottom';
__nearheap_start: pointer;public name '__nearheap_start';
__nearheap_end: pointer;public name '__nearheap_end';
dos_version:Word;public name 'dos_version';
envp:PPFarChar;public name '__fpc_envp';
dos_env_count:smallint;public name '__dos_env_count';
dos_argv0 : PFarChar;public name '__fpc_dos_argv0';
{$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';
procedure InstallInterruptHandlers; external name 'FPC_INSTALL_INTERRUPT_HANDLERS';
procedure RestoreInterruptHandlers; external name 'FPC_RESTORE_INTERRUPT_HANDLERS';
function CheckNullArea: Boolean; external name 'FPC_CHECK_NULLAREA';
{$I system.inc}
{$I tinyheap.inc}
procedure DebugWrite(const S: string);
begin
asm
{$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
push ds
lds si, S
{$else}
mov si, S
{$endif}
{$ifdef FPC_ENABLED_CLD}
cld
{$endif FPC_ENABLED_CLD}
lodsb
mov cl, al
xor ch, ch
jcxz @@zero_length
mov ah, 2
@@1:
lodsb
mov dl, al
int 21h
loop @@1
@@zero_length:
{$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
pop ds
{$endif}
end ['ax','bx','cx','dx','si','di'];
end;
procedure DebugWriteLn(const S: string);
begin
DebugWrite(S);
DebugWrite(#13#10);
end;
{*****************************************************************************
ParamStr/Randomize
*****************************************************************************}
procedure setup_environment;
var
env_count : smallint;
cp, dos_env: PFarChar;
begin
env_count:=0;
dos_env:=Ptr(MemW[PrefixSeg:$2C], 0);
cp:=dos_env;
while cp^<>#0 do
begin
inc(env_count);
while (cp^ <> #0) do
inc(cp); { skip to NUL }
inc(cp); { skip to next character }
end;
envp := getmem((env_count+1) * sizeof(PFarChar));
cp:=dos_env;
env_count:=0;
while cp^<>#0 do
begin
envp[env_count] := cp;
inc(env_count);
while (cp^ <> #0) do
inc(cp); { skip to NUL }
inc(cp); { skip to next character }
end;
envp[env_count]:=nil;
dos_env_count := env_count;
if dos_version >= $300 then
begin
inc(cp, 3);
dos_argv0 := cp;
end
else
dos_argv0 := nil;
end;
function GetProgramName: string;
var
cp: PFarChar;
begin
GetProgramName := '';
cp := dos_argv0;
if cp = nil then
exit;
while cp^ <> #0 do
begin
GetProgramName := GetProgramName + cp^;
Inc(cp);
end;
end;
function GetCommandLine: string;
var
len, I: Integer;
begin
len := PFarByte(Ptr(PrefixSeg, $80))^;
SetLength(GetCommandLine, len);
for I := 1 to len do
GetCommandLine[I] := PFarChar(Ptr(PrefixSeg, $80 + I))^;
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
RestoreInterruptHandlers;
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;
{$ifndef FPC_MM_TINY}
if not CheckNullArea then
writeln(stderr, 'Nil pointer assignment');
{$endif FPC_MM_TINY}
asm
mov al, byte [exitcode]
mov ah, 4Ch
int 21h
end;
end;
{*****************************************************************************
SystemUnit Initialization
*****************************************************************************}
procedure InitDosHeap;
type
{$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
TPointerArithmeticType = HugePointer;
{$else}
TPointerArithmeticType = Pointer;
{$endif}
begin
SetMemoryManager(TinyHeapMemoryManager);
RegisterTinyHeapBlock_Simple_Prealigned(__nearheap_start, TPointerArithmeticType(__nearheap_end) - TPointerArithmeticType(__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 := PrefixSeg;
end;
function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
begin
result := stklen;
end;
begin
StackBottom := __stkbottom;
StackLength := __stktop - __stkbottom;
InstallInterruptHandlers;
DetectFPU;
if Test8087>0 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 }
InitDosHeap;
SysInitExceptions;
initunicodestringmanager;
{ Setup stdin, stdout and stderr }
SysInitStdIO;
{ Setup environment and arguments }
Setup_Environment;
{ Use LFNSupport LFN }
LFNSupport:=CheckLFN;
if LFNSupport then
begin
FileNameCasePreserving:=true;
AllFilesMask := '*';
end
else
AllFilesMask := '*.*';
{ Reset IO Error }
InOutRes:=0;
end.