123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 1999-2000 by Florian Klaempfl
- member of the Free Pascal development team
- Sysutils unit for Go32v2
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit sysutils;
- interface
- {$MODE objfpc}
- { force ansistrings }
- {$H+}
- uses
- go32,dos;
- {$DEFINE HAS_SLEEP}
- { Include platform independent interface part }
- {$i sysutilh.inc}
- implementation
- uses
- sysconst;
- {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
- {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
- { Include platform independent implementation part }
- {$i sysutils.inc}
- {****************************************************************************
- File Functions
- ****************************************************************************}
- { some internal constants }
- const
- ofRead = $0000; { Open for reading }
- ofWrite = $0001; { Open for writing }
- ofReadWrite = $0002; { Open for reading/writing }
- faFail = $0000; { Fail if file does not exist }
- faCreate = $0010; { Create if file does not exist }
- faOpen = $0001; { Open if file exists }
- faOpenReplace = $0002; { Clear if file exists }
- Type
- PSearchrec = ^Searchrec;
- { converts S to a pchar and copies it to the transfer-buffer. }
- procedure StringToTB(const S: string);
- var
- P: pchar;
- Len: integer;
- begin
- Len := Length(S) + 1;
- P := StrPCopy(StrAlloc(Len), S);
- SysCopyToDos(longint(P), Len);
- StrDispose(P);
- end ;
- { Native OpenFile function.
- if return value <> 0 call failed. }
- function OpenFile(const FileName: string; var Handle: longint; Mode, Action: word): longint;
- var
- Regs: registers;
- begin
- result := 0;
- Handle := UnusedHandle;
- StringToTB(FileName);
- if LFNSupport then
- begin
- Regs.Eax := $716c; { Use LFN Open/Create API }
- Regs.Edx := Action; { Action if file does/doesn't exist }
- Regs.Esi := tb_offset;
- Regs.Ebx := $2000 + (Mode and $ff); { File open mode }
- end
- else
- begin
- if (Action and $00f0) <> 0 then
- Regs.Eax := $3c00 { Map to Create/Replace API }
- else
- Regs.Eax := $3d00 + (Mode and $ff); { Map to Open_Existing API }
- Regs.Edx := tb_offset;
- end;
- Regs.Ds := tb_segment;
- Regs.Ecx := $20; { Attributes }
- RealIntr($21, Regs);
- if (Regs.Flags and CarryFlag) <> 0 then
- result := Regs.Ax
- else
- Handle := Regs.Ax;
- end;
- Function FileOpen (Const FileName : string; Mode : Integer) : Longint;
- var
- e: integer;
- Begin
- e := OpenFile(FileName, result, Mode, faOpen);
- if e <> 0 then
- result := -1;
- end;
- Function FileCreate (Const FileName : String) : Longint;
- var
- e: integer;
- begin
- e := OpenFile(FileName, result, ofReadWrite, faCreate or faOpenReplace);
- if e <> 0 then
- result := -1;
- end;
- Function FileCreate (Const FileName : String; Mode:longint) : Longint;
- begin
- FileCreate:=FileCreate(FileName);
- end;
- Function FileRead (Handle : Longint; Var Buffer; Count : longint) : Longint;
- var
- regs : registers;
- size,
- readsize : longint;
- begin
- readsize:=0;
- while Count > 0 do
- begin
- if Count>tb_size then
- size:=tb_size
- else
- size:=Count;
- regs.realecx:=size;
- regs.realedx:=tb_offset;
- regs.realds:=tb_segment;
- regs.realebx:=Handle;
- regs.realeax:=$3f00;
- RealIntr($21,regs);
- if (regs.realflags and carryflag) <> 0 then
- begin
- Result:=-1;
- exit;
- end;
- syscopyfromdos(Longint(@Buffer)+readsize,lo(regs.realeax));
- inc(readsize,lo(regs.realeax));
- dec(Count,lo(regs.realeax));
- { stop when not the specified size is read }
- if lo(regs.realeax)<size then
- break;
- end;
- Result:=readsize;
- end;
- Function FileWrite (Handle : Longint; const Buffer; Count : Longint) : Longint;
- var
- regs : registers;
- size,
- writesize : longint;
- begin
- writesize:=0;
- while Count > 0 do
- begin
- if Count>tb_size then
- size:=tb_size
- else
- size:=Count;
- syscopytodos(Longint(@Buffer)+writesize,size);
- regs.realecx:=size;
- regs.realedx:=tb_offset;
- regs.realds:=tb_segment;
- regs.realebx:=Handle;
- regs.realeax:=$4000;
- RealIntr($21,regs);
- if (regs.realflags and carryflag) <> 0 then
- begin
- Result:=-1;
- exit;
- end;
- inc(writesize,lo(regs.realeax));
- dec(Count,lo(regs.realeax));
- { stop when not the specified size is written }
- if lo(regs.realeax)<size then
- break;
- end;
- Result:=WriteSize;
- end;
- Function FileSeek (Handle, FOffset, Origin : Longint) : Longint;
- var
- Regs: registers;
- begin
- Regs.Eax := $4200;
- Regs.Al := Origin;
- Regs.Edx := Lo(FOffset);
- Regs.Ecx := Hi(FOffset);
- Regs.Ebx := Handle;
- RealIntr($21, Regs);
- if Regs.Flags and CarryFlag <> 0 then
- result := -1
- else begin
- LongRec(result).Lo := Regs.Ax;
- LongRec(result).Hi := Regs.Dx;
- end ;
- end;
- Function FileSeek (Handle : Longint; FOffset: Int64; Origin: Integer) : Int64;
- begin
- {$warning need to add 64bit call }
- FileSeek:=FileSeek(Handle,Longint(FOffset),Longint(Origin));
- end;
- Procedure FileClose (Handle : Longint);
- var
- Regs: registers;
- begin
- if Handle<=4 then
- exit;
- Regs.Eax := $3e00;
- Regs.Ebx := Handle;
- RealIntr($21, Regs);
- end;
- Function FileTruncate (Handle,Size: Longint) : boolean;
- var
- regs : trealregs;
- begin
- FileSeek(Handle,Size,0);
- Regs.realecx := 0;
- Regs.realedx := tb_offset;
- Regs.ds := tb_segment;
- Regs.ebx := Handle;
- Regs.eax:=$4000;
- RealIntr($21, Regs);
- FileTruncate:=(regs.realflags and carryflag)=0;
- end;
- Function FileAge (Const FileName : String): Longint;
- var Handle: longint;
- begin
- Handle := FileOpen(FileName, 0);
- if Handle <> -1 then
- begin
- result := FileGetDate(Handle);
- FileClose(Handle);
- end
- else
- result := -1;
- end;
- Function FileExists (Const FileName : String) : Boolean;
- Var
- Sr : Searchrec;
- begin
- DOS.FindFirst(FileName,$3f,sr);
- if DosError = 0 then
- begin
- { No volumeid,directory }
- Result:=(sr.attr and $18)=0;
- Dos.FindClose(sr);
- end
- else
- Result:=false;
- end;
- Function DirectoryExists (Const Directory : String) : Boolean;
- Var
- Sr : Searchrec;
- begin
- DOS.FindFirst(Directory,$3f,sr);
- if DosError = 0 then
- begin
- Result:=(sr.attr and $10)=$10;
- Dos.FindClose(sr);
- end
- else
- Result:=false;
- end;
- Function FindFirst (Const Path : String; Attr : Longint; out Rslt : TSearchRec) : Longint;
- Var Sr : PSearchrec;
- begin
- //!! Sr := New(PSearchRec);
- getmem(sr,sizeof(searchrec));
- Rslt.FindHandle := longint(Sr);
- DOS.FindFirst(Path, Attr, Sr^);
- result := -DosError;
- if result = 0 then
- begin
- Rslt.Time := Sr^.Time;
- Rslt.Size := Sr^.Size;
- Rslt.Attr := Sr^.Attr;
- Rslt.ExcludeAttr := 0;
- Rslt.Name := Sr^.Name;
- end ;
- end;
- Function FindNext (Var Rslt : TSearchRec) : Longint;
- var
- Sr: PSearchRec;
- begin
- Sr := PSearchRec(Rslt.FindHandle);
- if Sr <> nil then
- begin
- DOS.FindNext(Sr^);
- result := -DosError;
- if result = 0 then
- begin
- Rslt.Time := Sr^.Time;
- Rslt.Size := Sr^.Size;
- Rslt.Attr := Sr^.Attr;
- Rslt.ExcludeAttr := 0;
- Rslt.Name := Sr^.Name;
- end;
- end;
- end;
- Procedure FindClose (Var F : TSearchrec);
- var
- Sr: PSearchRec;
- begin
- Sr := PSearchRec(F.FindHandle);
- if Sr <> nil then
- begin
- //!! Dispose(Sr);
- // This call is non dummy if LFNSupport is true PM
- DOS.FindClose(SR^);
- freemem(sr,sizeof(searchrec));
- end;
- F.FindHandle := 0;
- end;
- Function FileGetDate (Handle : Longint) : Longint;
- var
- Regs: registers;
- begin
- //!! for win95 an alternative function is available.
- Regs.Ebx := Handle;
- Regs.Eax := $5700;
- RealIntr($21, Regs);
- if Regs.Flags and CarryFlag <> 0 then
- result := -1
- else
- begin
- LongRec(result).Lo := Regs.cx;
- LongRec(result).Hi := Regs.dx;
- end ;
- end;
- Function FileSetDate (Handle, Age : Longint) : Longint;
- var
- Regs: registers;
- begin
- Regs.Ebx := Handle;
- Regs.Eax := $5701;
- Regs.Ecx := Lo(Age);
- Regs.Edx := Hi(Age);
- RealIntr($21, Regs);
- if Regs.Flags and CarryFlag <> 0 then
- result := -Regs.Ax
- else
- result := 0;
- end;
- Function FileGetAttr (Const FileName : String) : Longint;
- var
- Regs: registers;
- begin
- StringToTB(FileName);
- Regs.Edx := tb_offset;
- Regs.Ds := tb_segment;
- if LFNSupport then
- begin
- Regs.Ax := $7143;
- Regs.Bx := 0;
- end
- else
- Regs.Ax := $4300;
- RealIntr($21, Regs);
- if Regs.Flags and CarryFlag <> 0 then
- result := -1
- else
- result := Regs.Cx;
- end;
- Function FileSetAttr (Const Filename : String; Attr: longint) : Longint;
- var
- Regs: registers;
- begin
- StringToTB(FileName);
- Regs.Edx := tb_offset;
- Regs.Ds := tb_segment;
- if LFNSupport then
- begin
- Regs.Ax := $7143;
- Regs.Bx := 1;
- end
- else
- Regs.Ax := $4301;
- Regs.Cx := Attr;
- RealIntr($21, Regs);
- if Regs.Flags and CarryFlag <> 0 then
- result := -Regs.Ax
- else
- result := 0;
- end;
- Function DeleteFile (Const FileName : String) : Boolean;
- var
- Regs: registers;
- begin
- StringToTB(FileName);
- Regs.Edx := tb_offset;
- Regs.Ds := tb_segment;
- if LFNSupport then
- Regs.Eax := $7141
- else
- Regs.Eax := $4100;
- Regs.Esi := 0;
- Regs.Ecx := 0;
- RealIntr($21, Regs);
- result := (Regs.Flags and CarryFlag = 0);
- end;
- Function RenameFile (Const OldName, NewName : String) : Boolean;
- var
- Regs: registers;
- begin
- StringToTB(OldName + #0 + NewName);
- Regs.Edx := tb_offset;
- Regs.Ds := tb_segment;
- Regs.Edi := tb_offset + Length(OldName) + 1;
- Regs.Es := tb_segment;
- if LFNSupport then
- Regs.Eax := $7156
- else
- Regs.Eax := $5600;
- Regs.Ecx := $ff;
- RealIntr($21, Regs);
- result := (Regs.Flags and CarryFlag = 0);
- end;
- {****************************************************************************
- Disk Functions
- ****************************************************************************}
- TYPE ExtendedFat32FreeSpaceRec=packed Record
- RetSize : WORD; { (ret) size of returned structure}
- Strucversion : WORD; {(call) structure version (0000h)
- (ret) actual structure version (0000h)}
- SecPerClus, {number of sectors per cluster}
- BytePerSec, {number of bytes per sector}
- AvailClusters, {number of available clusters}
- TotalClusters, {total number of clusters on the drive}
- AvailPhysSect, {physical sectors available on the drive}
- TotalPhysSect, {total physical sectors on the drive}
- AvailAllocUnits, {Available allocation units}
- TotalAllocUnits : DWORD; {Total allocation units}
- Dummy,Dummy2 : DWORD; {8 bytes reserved}
- END;
- function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
- VAR S : String;
- Rec : ExtendedFat32FreeSpaceRec;
- regs : registers;
- BEGIN
- if (swap(dosversion)>=$070A) AND LFNSupport then
- begin
- DosError:=0;
- S:='C:\'#0;
- if Drive=0 then
- begin
- GetDir(Drive,S);
- Setlength(S,4);
- S[4]:=#0;
- end
- else
- S[1]:=chr(Drive+64);
- Rec.Strucversion:=0;
- dosmemput(tb_segment,tb_offset,Rec,SIZEOF(ExtendedFat32FreeSpaceRec));
- dosmemput(tb_segment,tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1,S[1],4);
- regs.dx:=tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1;
- regs.ds:=tb_segment;
- regs.di:=tb_offset;
- regs.es:=tb_segment;
- regs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
- regs.ax:=$7303;
- msdos(regs);
- if regs.ax<>$ffff then
- begin
- copyfromdos(rec,Sizeof(ExtendedFat32FreeSpaceRec));
- if Free then
- Do_DiskData:=int64(rec.AvailAllocUnits)*rec.SecPerClus*rec.BytePerSec
- else
- Do_DiskData:=int64(rec.TotalAllocUnits)*rec.SecPerClus*rec.BytePerSec;
- end
- else
- Do_DiskData:=-1;
- end
- else
- begin
- DosError:=0;
- regs.dl:=drive;
- regs.ah:=$36;
- msdos(regs);
- if regs.ax<>$FFFF then
- begin
- if Free then
- Do_DiskData:=int64(regs.ax)*regs.bx*regs.cx
- else
- Do_DiskData:=int64(regs.ax)*regs.cx*regs.dx;
- end
- else
- do_diskdata:=-1;
- end;
- end;
- function diskfree(drive : byte) : int64;
- begin
- diskfree:=Do_DiskData(drive,TRUE);
- end;
- function disksize(drive : byte) : int64;
- begin
- disksize:=Do_DiskData(drive,false);
- end;
- Function GetCurrentDir : String;
- begin
- GetDir(0, result);
- end;
- Function SetCurrentDir (Const NewDir : String) : Boolean;
- begin
- {$I-}
- ChDir(NewDir);
- {$I+}
- result := (IOResult = 0);
- end;
- Function CreateDir (Const NewDir : String) : Boolean;
- begin
- {$I-}
- MkDir(NewDir);
- {$I+}
- result := (IOResult = 0);
- end;
- Function RemoveDir (Const Dir : String) : Boolean;
- begin
- {$I-}
- RmDir(Dir);
- {$I+}
- result := (IOResult = 0);
- end;
- {****************************************************************************
- Time Functions
- ****************************************************************************}
- Procedure GetLocalTime(var SystemTime: TSystemTime);
- var
- Regs: Registers;
- begin
- Regs.ah := $2C;
- RealIntr($21, Regs);
- SystemTime.Hour := Regs.Ch;
- SystemTime.Minute := Regs.Cl;
- SystemTime.Second := Regs.Dh;
- SystemTime.MilliSecond := Regs.Dl*10;
- Regs.ah := $2A;
- RealIntr($21, Regs);
- SystemTime.Year := Regs.Cx;
- SystemTime.Month := Regs.Dh;
- SystemTime.Day := Regs.Dl;
- end ;
- {****************************************************************************
- Misc Functions
- ****************************************************************************}
- procedure Beep;
- begin
- end;
- {****************************************************************************
- Locale Functions
- ****************************************************************************}
- { Codepage constants }
- const
- CP_US = 437;
- CP_MultiLingual = 850;
- CP_SlavicLatin2 = 852;
- CP_Turkish = 857;
- CP_Portugal = 860;
- CP_IceLand = 861;
- CP_Canada = 863;
- CP_NorwayDenmark = 865;
- { CountryInfo }
- type
- TCountryInfo = packed record
- InfoId: byte;
- case integer of
- 1: ( Size: word;
- CountryId: word;
- CodePage: word;
- CountryInfo: array[0..33] of byte );
- 2: ( UpperCaseTable: longint );
- 4: ( FilenameUpperCaseTable: longint );
- 5: ( FilecharacterTable: longint );
- 6: ( CollatingTable: longint );
- 7: ( DBCSLeadByteTable: longint );
- end ;
- procedure GetExtendedCountryInfo(InfoId: integer; CodePage, CountryId: word; var CountryInfo: TCountryInfo);
- Var Regs: Registers;
- begin
- Regs.AH := $65;
- Regs.AL := InfoId;
- Regs.BX := CodePage;
- Regs.DX := CountryId;
- Regs.ES := transfer_buffer div 16;
- Regs.DI := transfer_buffer and 15;
- Regs.CX := SizeOf(TCountryInfo);
- RealIntr($21, Regs);
- DosMemGet(transfer_buffer div 16,
- transfer_buffer and 15,
- CountryInfo, Regs.CX );
- end;
- procedure InitAnsi;
- var
- CountryInfo: TCountryInfo; i: integer;
- begin
- { Fill table entries 0 to 127 }
- for i := 0 to 96 do
- UpperCaseTable[i] := chr(i);
- for i := 97 to 122 do
- UpperCaseTable[i] := chr(i - 32);
- for i := 123 to 127 do
- UpperCaseTable[i] := chr(i);
- for i := 0 to 64 do
- LowerCaseTable[i] := chr(i);
- for i := 65 to 90 do
- LowerCaseTable[i] := chr(i + 32);
- for i := 91 to 255 do
- LowerCaseTable[i] := chr(i);
- { Get country and codepage info }
- GetExtendedCountryInfo(1, $FFFF, $FFFF, CountryInfo);
- if CountryInfo.CodePage = 850 then
- begin
- { Special, known case }
- Move(CP850UCT, UpperCaseTable[128], 128);
- Move(CP850LCT, LowerCaseTable[128], 128);
- end
- else
- begin
- { this needs to be checked !!
- this is correct only if UpperCaseTable is
- and Offset:Segment word record (PM) }
- { get the uppercase table from dosmemory }
- GetExtendedCountryInfo(2, $FFFF, $FFFF, CountryInfo);
- DosMemGet(CountryInfo.UpperCaseTable shr 16, 2 + CountryInfo.UpperCaseTable and 65535, UpperCaseTable[128], 128);
- for i := 128 to 255 do
- begin
- if UpperCaseTable[i] <> chr(i) then
- LowerCaseTable[ord(UpperCaseTable[i])] := chr(i);
- end;
- end;
- end;
- Procedure InitInternational;
- begin
- InitInternationalGeneric;
- InitAnsi;
- end;
- function SysErrorMessage(ErrorCode: Integer): String;
- begin
- Result:=Format(SUnknownErrorCode,[ErrorCode]);
- end;
- {****************************************************************************
- Os utils
- ****************************************************************************}
- Function GetEnvironmentVariable(Const EnvVar : String) : String;
- begin
- Result:=FPCGetEnvVarFromP(envp,EnvVar);
- end;
- Function GetEnvironmentVariableCount : Integer;
- begin
- Result:=FPCCountEnvVar(EnvP);
- end;
- Function GetEnvironmentString(Index : Integer) : String;
- begin
- Result:=FPCGetEnvStrFromP(Envp,Index);
- end;
- function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString):integer;
- var
- e : EOSError;
- CommandLine: AnsiString;
- begin
- dos.exec(path,comline);
- if (Dos.DosError <> 0) then
- begin
- if ComLine <> '' then
- CommandLine := Path + ' ' + ComLine
- else
- CommandLine := Path;
- e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,Dos.DosError]);
- e.ErrorCode:=Dos.DosError;
- raise e;
- end;
- Result := DosExitCode;
- end;
- function ExecuteProcess (const Path: AnsiString;
- const ComLine: array of AnsiString): integer;
- var
- CommandLine: AnsiString;
- I: integer;
- begin
- Commandline := '';
- for I := 0 to High (ComLine) do
- if Pos (' ', ComLine [I]) <> 0 then
- CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
- else
- CommandLine := CommandLine + ' ' + Comline [I];
- ExecuteProcess := ExecuteProcess (Path, CommandLine);
- end;
- {*************************************************************************
- Sleep
- *************************************************************************}
- procedure Sleep (MilliSeconds: Cardinal);
- var
- R: Registers;
- T0, T1, T2: int64;
- DayOver: boolean;
- begin
- (* Sleep is supposed to give up time slice - DOS Idle Interrupt chosen
- because it should be supported in all DOS versions. Not precise at all,
- though - the smallest step is 10 ms even in the best case. *)
- R.AH := $2C;
- RealIntr($21, R);
- T0 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
- T2 := T0 + MilliSeconds;
- DayOver := T2 > (24 * 3600000);
- repeat
- Intr ($28, R);
- (* R.AH := $2C; - should be preserved. *)
- RealIntr($21, R);
- T1 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
- if DayOver and (T1 < T0) then
- Inc (T1, 24 * 3600000);
- until T1 >= T2;
- end;
- {****************************************************************************
- Initialization code
- ****************************************************************************}
- Initialization
- InitExceptions; { Initialize exceptions. OS independent }
- InitInternational; { Initialize internationalization settings }
- Finalization
- DoneExceptions;
- end.
|