1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009 |
- {
- 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 OS/2
- 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}
- {$MODESWITCH OUT}
- { force ansistrings }
- {$H+}
- {$modeswitch typehelpers}
- {$modeswitch advancedrecords}
- {$DEFINE HAS_SLEEP}
- {$DEFINE HAS_OSERROR}
- { used OS file system APIs use ansistring }
- {$define SYSUTILS_HAS_ANSISTR_FILEUTIL_IMPL}
- { OS has an ansistring/single byte environment variable API }
- {$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL}
- { OS has an ansistring/single byte API for executing other processes }
- {$DEFINE EXECUTEPROCUNI}
- { Include platform independent interface part }
- {$i sysutilh.inc}
- implementation
- uses
- sysconst, DosCalls;
- type
- (* Necessary here due to a different definition of TDateTime in DosCalls. *)
- TDateTime = System.TDateTime;
- threadvar
- LastOSError: cardinal;
- {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
- {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
- {$DEFINE FPC_FEXPAND_GETENV_PCHAR}
- {$DEFINE HAS_GETTICKCOUNT}
- {$DEFINE HAS_GETTICKCOUNT64}
- { Include platform independent implementation part }
- {$i sysutils.inc}
- {****************************************************************************
- File Functions
- ****************************************************************************}
- const
- ofRead = $0000; {Open for reading}
- ofWrite = $0001; {Open for writing}
- ofReadWrite = $0002; {Open for reading/writing}
- doDenyRW = $0010; {DenyAll (no sharing)}
- faCreateNew = $00010000; {Create if file does not exist}
- faOpenReplace = $00040000; {Truncate if file exists}
- faCreate = $00050000; {Create if file does not exist, truncate otherwise}
- FindResvdMask = $00003737 {Allowed bits for DosFindFirst parameter Attribute}
- and $000000FF; {combined with a mask for allowed attributes only}
- function FileOpen (const FileName: rawbytestring; Mode: integer): THandle;
- Var
- SystemFileName: RawByteString;
- Handle: THandle;
- Rc, Action: cardinal;
- begin
- SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
- (* DenyReadWrite if sharing not specified. *)
- if (Mode and 112 = 0) or (Mode and 112 > 64) then
- Mode := Mode or doDenyRW;
- Rc:=Sys_DosOpenL(PChar (SystemFileName), Handle, Action, 0, 0, 1, Mode, nil);
- If Rc=0 then
- FileOpen:=Handle
- else
- begin
- FileOpen:=feInvalidHandle; //FileOpen:=-RC;
- //should return feInvalidHandle(=-1) if fail, other negative returned value are no more errors
- OSErrorWatch (RC);
- end;
- end;
- function FileCreate (const FileName: RawByteString): THandle;
- begin
- FileCreate := FileCreate (FileName, doDenyRW, 777); (* Sharing to DenyAll *)
- end;
- function FileCreate (const FileName: RawByteString; Rights: integer): THandle;
- begin
- FileCreate := FileCreate (FileName, doDenyRW, Rights);
- (* Sharing to DenyAll *)
- end;
- function FileCreate (const FileName: RawByteString; ShareMode: integer;
- Rights: integer): THandle;
- var
- SystemFileName: RawByteString;
- Handle: THandle;
- RC, Action: cardinal;
- begin
- SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
- ShareMode := ShareMode and 112;
- (* Sharing to DenyAll as default in case of values not allowed by OS/2. *)
- if (ShareMode = 0) or (ShareMode > 64) then
- ShareMode := doDenyRW;
- RC := Sys_DosOpenL (PChar (SystemFileName), Handle, Action, 0, 0, $12,
- faCreate or ofReadWrite or ShareMode, nil);
- if RC = 0 then
- FileCreate := Handle
- else
- begin
- FileCreate := feInvalidHandle;
- OSErrorWatch (RC);
- end;
- End;
- function FileRead (Handle: THandle; Out Buffer; Count: longint): longint;
- Var
- T: cardinal;
- RC: cardinal;
- begin
- RC := DosRead (Handle, Buffer, Count, T);
- if RC = 0 then
- FileRead := longint (T)
- else
- begin
- FileRead := -1;
- OSErrorWatch (RC);
- end;
- end;
- function FileWrite (Handle: THandle; const Buffer; Count: longint): longint;
- Var
- T: cardinal;
- RC: cardinal;
- begin
- RC := DosWrite (Handle, Buffer, Count, T);
- if RC = 0 then
- FileWrite := longint (T)
- else
- begin
- FileWrite := -1;
- OSErrorWatch (RC);
- end;
- end;
- function FileSeek (Handle: THandle; FOffset, Origin: longint): longint;
- var
- NPos: int64;
- RC: cardinal;
- begin
- RC := Sys_DosSetFilePtrL (Handle, FOffset, Origin, NPos);
- if (RC = 0) and (NPos < high (longint)) then
- FileSeek:= longint (NPos)
- else
- begin
- FileSeek:=-1;
- OSErrorWatch (RC);
- end;
- end;
- function FileSeek (Handle: THandle; FOffset: Int64; Origin: Longint): Int64;
- var
- NPos: int64;
- RC: cardinal;
- begin
- RC := Sys_DosSetFilePtrL (Handle, FOffset, Origin, NPos);
- if RC = 0 then
- FileSeek:= NPos
- else
- begin
- FileSeek:=-1;
- OSErrorWatch (RC);
- end;
- end;
- procedure FileClose (Handle: THandle);
- var
- RC: cardinal;
- begin
- RC := DosClose (Handle);
- if RC <> 0 then
- OSErrorWatch (RC);
- end;
- function FileTruncate (Handle: THandle; Size: Int64): boolean;
- var
- RC: cardinal;
- begin
- RC := Sys_DosSetFileSizeL(Handle, Size);
- FileTruncate := RC = 0;
- if RC = 0 then
- FileSeek(Handle, 0, 2)
- else
- OSErrorWatch (RC);
- end;
- function FileAge (const FileName: RawByteString): Int64;
- var Handle: longint;
- begin
- Handle := FileOpen (FileName, 0);
- if Handle <> -1 then
- begin
- Result := FileGetDate (Handle);
- FileClose (Handle);
- end
- else
- Result := -1;
- end;
- function FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean;
- begin
- Result := False;
- end;
- function FileExists (const FileName: RawByteString; FollowLink : Boolean): boolean;
- var
- L: longint;
- begin
- { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
- if FileName = '' then
- Result := false
- else
- begin
- L := FileGetAttr (FileName);
- Result := (L >= 0) and (L and (faDirectory or faVolumeID) = 0);
- (* Neither VolumeIDs nor directories are files. *)
- end;
- end;
- type TRec = record
- T, D: word;
- end;
- PSearchRec = ^TSearchRec;
- Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
- var SR: PSearchRec;
- FStat: PFileFindBuf3L;
- Count: cardinal;
- Err: cardinal;
- I: cardinal;
- SystemEncodedPath: RawByteString;
- begin
- SystemEncodedPath := ToSingleByteFileSystemEncodedFileName(Path);
- New (FStat);
- Rslt.FindHandle := THandle ($FFFFFFFF);
- Count := 1;
- if FSApi64 then
- Err := DosFindFirst (PChar (SystemEncodedPath), Rslt.FindHandle,
- Attr and FindResvdMask, FStat, SizeOf (FStat^), Count, ilStandardL)
- else
- Err := DosFindFirst (PChar (SystemEncodedPath), Rslt.FindHandle,
- Attr and FindResvdMask, FStat, SizeOf (FStat^), Count, ilStandard);
- if Err <> 0 then
- OSErrorWatch (Err)
- else if Count = 0 then
- Err := 18;
- InternalFindFirst := -Err;
- if Err = 0 then
- begin
- Rslt.ExcludeAttr := 0;
- TRec (Rslt.Time).T := FStat^.TimeLastWrite;
- TRec (Rslt.Time).D := FStat^.DateLastWrite;
- if FSApi64 then
- begin
- Rslt.Size := FStat^.FileSize;
- Name := FStat^.Name;
- Rslt.Attr := FStat^.AttrFile;
- end
- else
- begin
- Rslt.Size := PFileFindBuf3 (FStat)^.FileSize;
- Name := PFileFindBuf3 (FStat)^.Name;
- Rslt.Attr := PFileFindBuf3 (FStat)^.AttrFile;
- end;
- SetCodePage (Name, DefaultFileSystemCodePage, false);
- end
- else
- InternalFindClose(Rslt.FindHandle);
- Dispose (FStat);
- end;
- Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
- var
- SR: PSearchRec;
- FStat: PFileFindBuf3L;
- Count: cardinal;
- Err: cardinal;
- begin
- New (FStat);
- Count := 1;
- Err := DosFindNext (Rslt.FindHandle, FStat, SizeOf (FStat^), Count);
- if Err <> 0 then
- OSErrorWatch (Err)
- else if Count = 0 then
- Err := 18;
- InternalFindNext := -Err;
- if Err = 0 then
- begin
- Rslt.ExcludeAttr := 0;
- TRec (Rslt.Time).T := FStat^.TimeLastWrite;
- TRec (Rslt.Time).D := FStat^.DateLastWrite;
- if FSApi64 then
- begin
- Rslt.Size := FStat^.FileSize;
- Name := FStat^.Name;
- Rslt.Attr := FStat^.AttrFile;
- end
- else
- begin
- Rslt.Size := PFileFindBuf3 (FStat)^.FileSize;
- Name := PFileFindBuf3 (FStat)^.Name;
- Rslt.Attr := PFileFindBuf3 (FStat)^.AttrFile;
- end;
- SetCodePage (Name, DefaultFileSystemCodePage, false);
- end;
- Dispose (FStat);
- end;
- Procedure InternalFindClose(var Handle: THandle);
- var
- SR: PSearchRec;
- RC: cardinal;
- begin
- RC := DosFindClose (Handle);
- Handle := 0;
- if RC <> 0 then
- OSErrorWatch (RC);
- end;
- function FileGetDate (Handle: THandle): longint;
- var
- FStat: TFileStatus3;
- Time: Longint;
- RC: cardinal;
- begin
- RC := DosQueryFileInfo(Handle, ilStandard, @FStat, SizeOf(FStat));
- if RC = 0 then
- begin
- Time := FStat.TimeLastWrite + longint (FStat.DateLastWrite) shl 16;
- if Time = 0 then
- Time := FStat.TimeCreation + longint (FStat.DateCreation) shl 16;
- end else
- begin
- Time:=0;
- OSErrorWatch (RC);
- end;
- FileGetDate:=Time;
- end;
- function FileSetDate (Handle: THandle; Age: longint): longint;
- var
- FStat: PFileStatus3;
- RC: cardinal;
- begin
- New (FStat);
- RC := DosQueryFileInfo (Handle, ilStandard, FStat, SizeOf (FStat^));
- if RC <> 0 then
- begin
- FileSetDate := -1;
- OSErrorWatch (RC);
- end
- else
- begin
- FStat^.DateLastAccess := Hi (Age);
- FStat^.DateLastWrite := Hi (Age);
- FStat^.TimeLastAccess := Lo (Age);
- FStat^.TimeLastWrite := Lo (Age);
- RC := DosSetFileInfo (Handle, ilStandard, FStat, SizeOf (FStat^));
- if RC <> 0 then
- begin
- FileSetDate := -1;
- OSErrorWatch (RC);
- end
- else
- FileSetDate := 0;
- end;
- Dispose (FStat);
- end;
- function FileGetAttr (const FileName: RawByteString): longint;
- var
- FS: PFileStatus3;
- SystemFileName: RawByteString;
- RC: cardinal;
- begin
- SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
- New(FS);
- RC := DosQueryPathInfo(PChar (SystemFileName), ilStandard, FS, SizeOf(FS^));
- if RC = 0 then
- Result := FS^.AttrFile
- else
- begin
- Result := - longint (RC);
- OSErrorWatch (RC);
- end;
- Dispose(FS);
- end;
- function FileSetAttr (const Filename: RawByteString; Attr: longint): longint;
- Var
- FS: PFileStatus3;
- SystemFileName: RawByteString;
- RC: cardinal;
- Begin
- SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
- New(FS);
- RC := DosQueryPathInfo (PChar (SystemFileName), ilStandard, FS, SizeOf (FS^));
- if RC = 0 then
- begin
- FS^.AttrFile:=Attr;
- RC := DosSetPathInfo(PChar (SystemFileName), ilStandard, FS, SizeOf(FS^), 0);
- if RC <> 0 then
- OSErrorWatch (RC);
- end
- else
- OSErrorWatch (RC);
- Result := - longint (RC);
- Dispose(FS);
- end;
- function DeleteFile (const FileName: RawByteString): boolean;
- var
- SystemFileName: RawByteString;
- RC: cardinal;
- Begin
- SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
- RC := DosDelete (PChar (SystemFileName));
- if RC <> 0 then
- begin
- Result := false;
- OSErrorWatch (RC);
- end
- else
- Result := true;
- End;
- function RenameFile (const OldName, NewName: RawByteString): boolean;
- var
- OldSystemFileName, NewSystemFileName: RawByteString;
- RC: cardinal;
- Begin
- OldSystemFileName:=ToSingleByteFileSystemEncodedFileName(OldName);
- NewSystemFileName:=ToSingleByteFileSystemEncodedFileName(NewName);
- RC := DosMove (PChar (OldSystemFileName), PChar (NewSystemFileName));
- if RC <> 0 then
- begin
- Result := false;
- OSErrorWatch (RC);
- end
- else
- Result := true;
- End;
- {****************************************************************************
- Disk Functions
- ****************************************************************************}
- function DiskFree (Drive: byte): int64;
- var FI: TFSinfo;
- RC: cardinal;
- begin
- {In OS/2, we use the filesystem information.}
- RC := DosQueryFSInfo (Drive, 1, FI, SizeOf (FI));
- if RC = 0 then
- DiskFree := int64 (FI.Free_Clusters) *
- int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
- else
- begin
- DiskFree := -1;
- OSErrorWatch (RC);
- end;
- end;
- function DiskSize (Drive: byte): int64;
- var FI: TFSinfo;
- RC: cardinal;
- begin
- {In OS/2, we use the filesystem information.}
- RC := DosQueryFSinfo (Drive, 1, FI, SizeOf (FI));
- if RC = 0 then
- DiskSize := int64 (FI.Total_Clusters) *
- int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
- else
- begin
- DiskSize := -1;
- OSErrorWatch (RC);
- end;
- end;
- function DirectoryExists (const Directory: RawByteString; FollowLink : Boolean): boolean;
- var
- L: longint;
- begin
- { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
- if Directory = '' then
- Result := false
- else
- begin
- if ((Length (Directory) = 2) or
- (Length (Directory) = 3) and
- (Directory [3] in AllowDirectorySeparators)) and
- (Directory [2] in AllowDriveSeparators) and
- (UpCase (Directory [1]) in ['A'..'Z']) then
- (* Checking attributes for 'x:' is not possible but for 'x:.' it is. *)
- L := FileGetAttr (Directory + '.')
- else if (Directory [Length (Directory)] in AllowDirectorySeparators) and
- (Length (Directory) > 1) and
- (* Do not remove '\' in '\\' (invalid path, possibly broken UNC path). *)
- not (Directory [Length (Directory) - 1] in AllowDirectorySeparators) then
- L := FileGetAttr (Copy (Directory, 1, Length (Directory) - 1))
- else
- L := FileGetAttr (Directory);
- Result := (L > 0) and (L and faDirectory = faDirectory);
- end;
- end;
- {****************************************************************************
- Time Functions
- ****************************************************************************}
- procedure GetLocalTime (var SystemTime: TSystemTime);
- var
- DT: DosCalls.TDateTime;
- begin
- DosGetDateTime(DT);
- with SystemTime do
- begin
- Year:=DT.Year;
- Month:=DT.Month;
- Day:=DT.Day;
- DayOfWeek:=DT.WeekDay;
- Hour:=DT.Hour;
- Minute:=DT.Minute;
- Second:=DT.Second;
- MilliSecond:=DT.Sec100 * 10;
- end;
- end;
- {****************************************************************************
- Misc Functions
- ****************************************************************************}
- procedure sysbeep;
- begin
- DosBeep (800, 250);
- end;
- {****************************************************************************
- Locale Functions
- ****************************************************************************}
- var
- Country: TCountryCode;
- CtryInfo: TCountryInfo;
- procedure InitAnsi;
- var
- I: byte;
- RC: cardinal;
- begin
- for I := 0 to 255 do
- UpperCaseTable [I] := Chr (I);
- Move (UpperCaseTable, LowerCaseTable, SizeOf (UpperCaseTable));
- FillChar (Country, SizeOf (Country), 0);
- DosMapCase (SizeOf (UpperCaseTable), Country, @UpperCaseTable);
- for I := 0 to 255 do
- if UpperCaseTable [I] <> Chr (I) then
- LowerCaseTable [Ord (UpperCaseTable [I])] := Chr (I);
- end;
- procedure InitInternational;
- var
- Size: cardinal;
- RC: cardinal;
- begin
- Size := 0;
- FillChar (Country, SizeOf (Country), 0);
- FillChar (CtryInfo, SizeOf (CtryInfo), 0);
- RC := DosQueryCtryInfo (SizeOf (CtryInfo), Country, CtryInfo, Size);
- if RC = 0 then
- begin
- DateSeparator := CtryInfo.DateSeparator;
- case CtryInfo.DateFormat of
- 1: begin
- ShortDateFormat := 'd/m/y';
- LongDateFormat := 'dd" "mmmm" "yyyy';
- end;
- 2: begin
- ShortDateFormat := 'y/m/d';
- LongDateFormat := 'yyyy" "mmmm" "dd';
- end;
- 3: begin
- ShortDateFormat := 'm/d/y';
- LongDateFormat := 'mmmm" "dd" "yyyy';
- end;
- end;
- TimeSeparator := CtryInfo.TimeSeparator;
- DecimalSeparator := CtryInfo.DecimalSeparator;
- ThousandSeparator := CtryInfo.ThousandSeparator;
- CurrencyFormat := CtryInfo.CurrencyFormat;
- CurrencyString := PChar (CtryInfo.CurrencyUnit);
- end
- else
- OSErrorWatch (RC);
- InitAnsi;
- InitInternationalGeneric;
- end;
- function SysErrorMessage(ErrorCode: Integer): String;
- const
- SysMsgFile: array [0..10] of char = 'OSO001.MSG'#0;
- var
- OutBuf: array [0..999] of char;
- RetMsgSize: cardinal;
- RC: cardinal;
- begin
- RC := DosGetMessage (nil, 0, @OutBuf [0], SizeOf (OutBuf),
- ErrorCode, @SysMsgFile [0], RetMsgSize);
- if RC = 0 then
- begin
- SetLength (Result, RetMsgSize);
- Move (OutBuf [0], Result [1], RetMsgSize);
- end
- else
- begin
- Result:=Format(SUnknownErrorCode,[ErrorCode]);
- OSErrorWatch (RC);
- end;
- end;
- {****************************************************************************
- OS Utils
- ****************************************************************************}
- function GetEnvPChar (EnvVar: shortstring): PChar;
- (* The assembler version is more than three times as fast as Pascal. *)
- var
- P: PChar;
- begin
- EnvVar := UpCase (EnvVar);
- {$ASMMODE INTEL}
- asm
- cld
- mov edi, Environment
- lea esi, EnvVar
- xor eax, eax
- lodsb
- @NewVar:
- cmp byte ptr [edi], 0
- jz @Stop
- push eax { eax contains length of searched variable name }
- push esi { esi points to the beginning of the variable name }
- mov ecx, -1 { our character ('=' - see below) _must_ be found }
- mov edx, edi { pointer to beginning of variable name saved in edx }
- mov al, '=' { searching until '=' (end of variable name) }
- repne
- scasb { scan until '=' not found }
- neg ecx { what was the name length? }
- dec ecx { corrected }
- dec ecx { exclude the '=' character }
- pop esi { restore pointer to beginning of variable name }
- pop eax { restore length of searched variable name }
- push eax { and save both of them again for later use }
- push esi
- cmp ecx, eax { compare length of searched variable name with name }
- jnz @NotEqual { ... of currently found variable, jump if different }
- xchg edx, edi { pointer to current variable name restored in edi }
- repe
- cmpsb { compare till the end of variable name }
- xchg edx, edi { pointer to beginning of variable contents in edi }
- jz @Equal { finish if they're equal }
- @NotEqual:
- xor eax, eax { look for 00h }
- mov ecx, -1 { it _must_ be found }
- repne
- scasb { scan until found }
- pop esi { restore pointer to beginning of variable name }
- pop eax { restore length of searched variable name }
- jmp @NewVar { ... or continue with new variable otherwise }
- @Stop:
- xor eax, eax
- mov P, eax { Not found - return nil }
- jmp @End
- @Equal:
- pop esi { restore the stack position }
- pop eax
- mov P, edi { place pointer to variable contents in P }
- @End:
- end ['eax','ecx','edx','esi','edi'];
- GetEnvPChar := P;
- end;
- {$ASMMODE ATT}
- Function GetEnvironmentVariable(Const EnvVar : String) : String;
- begin
- GetEnvironmentVariable := GetEnvPChar (EnvVar);
- end;
- Function GetEnvironmentVariableCount : Integer;
- begin
- (* Result:=FPCCountEnvVar(EnvP); - the amount is already known... *)
- GetEnvironmentVariableCount := EnvC;
- end;
- Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
- begin
- Result:=FPCGetEnvStrFromP (EnvP, Index);
- end;
- procedure Sleep (Milliseconds: cardinal);
- begin
- DosSleep (Milliseconds);
- end;
- function SysTimerTick: QWord;
- var
- L: cardinal;
- begin
- DosQuerySysInfo (svMsCount, svMsCount, L, 4);
- SysTimerTick := L;
- end;
- function ExecuteProcess (const Path: RawByteString;
- const ComLine: RawByteString;Flags:TExecuteFlags=[]): integer;
- var
- E: EOSError;
- CommandLine: RawByteString;
- Args0, Args: DosCalls.PByteArray;
- ObjNameBuf: PChar;
- ArgSize: word;
- Res: TResultCodes;
- ObjName: shortstring;
- RC: cardinal;
- ExecAppType: cardinal;
- MaxArgsSize: PtrUInt; (* Amount of memory reserved for arguments in bytes. *)
- MaxArgsSizeInc: word;
- const
- ObjBufSize = 512;
- function StartSession: cardinal;
- var
- HQ: THandle;
- SPID, STID, QName: shortstring;
- SID, PID: cardinal;
- SD: TStartData;
- RD: TRequestData;
- PCI: PChildInfo;
- CISize: cardinal;
- Prio: byte;
- begin
- Result := $FFFFFFFF;
- FillChar (SD, SizeOf (SD), 0);
- SD.Length := SizeOf (SD);
- SD.Related := ssf_Related_Child;
- if FileExists (Path) then
- (* Full path necessary for starting different executable files from current *)
- (* directory. *)
- CommandLine := ExpandFileName (Path)
- else
- CommandLine := Path;
- SD.PgmName := PChar (CommandLine);
- if ComLine <> '' then
- SD.PgmInputs := PChar (ComLine);
- if ExecInheritsHandles in Flags then
- SD.InheritOpt := ssf_InhertOpt_Parent;
- Str (GetProcessID, SPID);
- Str (ThreadID, STID);
- QName := '\QUEUES\FPC_ExecuteProcess_p' + SPID + 't' + STID + '.QUE'#0;
- SD.TermQ := @QName [1];
- SD.ObjectBuffer := ObjNameBuf;
- SD.ObjectBuffLen := ObjBufSize;
- RC := DosCreateQueue (HQ, quFIFO or quConvert_Address, @QName [1]);
- if RC <> 0 then
- begin
- Move (QName [1], ObjNameBuf^, Length (QName));
- OSErrorWatch (RC);
- end
- else
- begin
- RC := DosStartSession (SD, SID, PID);
- if (RC = 0) or (RC = 457) then
- begin
- RC := DosReadQueue (HQ, RD, CISize, PCI, 0, 0, Prio, 0);
- if RC = 0 then
- begin
- Result := PCI^.Return;
- RC := DosCloseQueue (HQ);
- if RC <> 0 then
- OSErrorWatch (RC);
- RC := DosFreeMem (PCI);
- if RC <> 0 then
- OSErrorWatch (RC);
- FreeMem (ObjNameBuf, ObjBufSize);
- end
- else
- begin
- OSErrorWatch (RC);
- RC := DosCloseQueue (HQ);
- OSErrorWatch (RC);
- end;
- end
- else
- begin
- OSErrorWatch (RC);
- RC := DosCloseQueue (HQ);
- if RC <> 0 then
- OSErrorWatch (RC);
- end;
- end;
- end;
- begin
- Result := integer ($FFFFFFFF);
- ObjName := '';
- GetMem (ObjNameBuf, ObjBufSize);
- FillChar (ObjNameBuf^, ObjBufSize, 0);
- RC := DosQueryAppType (PChar (Path), ExecAppType);
- if RC <> 0 then
- begin
- OSErrorWatch (RC);
- if (RC = 190) or (RC = 191) then
- Result := StartSession;
- end
- else
- begin
- if (ApplicationType and 3 = ExecAppType and 3) then
- (* DosExecPgm should work... *)
- begin
- MaxArgsSize := Length (ComLine) + Length (Path) + 256; (* More than enough *)
- if MaxArgsSize > high (word) then
- Exit;
- if ComLine = '' then
- begin
- Args0 := nil;
- Args := nil;
- end
- else
- begin
- GetMem (Args0, MaxArgsSize);
- Args := Args0;
- (* Work around a bug in OS/2 - argument to DosExecPgm *)
- (* should not cross 64K boundary. *)
- while ((PtrUInt (Args) + MaxArgsSize) and $FFFF) < MaxArgsSize do
- begin
- MaxArgsSizeInc := MaxArgsSize -
- ((PtrUInt (Args) + MaxArgsSize) and $FFFF);
- Inc (MaxArgsSize, MaxArgsSizeInc);
- if MaxArgsSize > high (word) then
- Exit;
- ReallocMem (Args0, MaxArgsSize);
- Inc (pointer (Args), MaxArgsSizeInc);
- end;
- ArgSize := 0;
- Move (Path [1], Args^ [ArgSize], Length (Path));
- Inc (ArgSize, Length (Path));
- Args^ [ArgSize] := 0;
- Inc (ArgSize);
- {Now do the real arguments.}
- Move (ComLine [1], Args^ [ArgSize], Length (ComLine));
- Inc (ArgSize, Length (ComLine));
- Args^ [ArgSize] := 0;
- Inc (ArgSize);
- Args^ [ArgSize] := 0;
- end;
- Res.ExitCode := $FFFFFFFF;
- RC := DosExecPgm (ObjNameBuf, ObjBufSize, 0, Args, nil, Res,
- PChar (Path));
- if RC <> 0 then
- OSErrorWatch (RC);
- if Args0 <> nil then
- FreeMem (Args0, MaxArgsSize);
- if RC = 0 then
- begin
- Result := Res.ExitCode;
- FreeMem (ObjNameBuf, ObjBufSize);
- end
- end
- end;
- if RC <> 0 then
- begin
- ObjName := StrPas (ObjNameBuf);
- FreeMem (ObjNameBuf, ObjBufSize);
- if ComLine = '' then
- CommandLine := Path
- else
- CommandLine := Path + ' ' + ComLine;
- if ObjName = '' then
- E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, RC])
- else
- E := EOSError.CreateFmt (SExecuteProcessFailed + ' (' + ObjName + ')', [CommandLine, RC]);
- E.ErrorCode := Result;
- raise E;
- end;
- end;
- function ExecuteProcess (const Path: RawByteString;
- const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): 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;
- function GetTickCount: LongWord;
- var
- L: cardinal;
- begin
- DosQuerySysInfo (svMsCount, svMsCount, L, 4);
- GetTickCount := L;
- end;
- function GetTickCount64: QWord;
- var
- Freq2: cardinal;
- T: QWord;
- begin
- DosTmrQueryFreq (Freq2);
- DosTmrQueryTime (T);
- GetTickCount64 := T div (QWord (Freq2) div 1000);
- {$NOTE GetTickCount64 takes 20 microseconds on 1GHz CPU, GetTickCount not measurable}
- end;
- const
- OrigOSErrorWatch: TOSErrorWatch = nil;
- procedure TrackLastOSError (Error: cardinal);
- begin
- LastOSError := Error;
- OrigOSErrorWatch (Error);
- end;
- function GetLastOSError: Integer;
- begin
- GetLastOSError := Integer (LastOSError);
- end;
- {****************************************************************************
- Initialization code
- ****************************************************************************}
- Initialization
- InitExceptions; { Initialize exceptions. OS independent }
- InitInternational; { Initialize internationalization settings }
- OnBeep:=@SysBeep;
- LastOSError := 0;
- OrigOSErrorWatch := TOSErrorWatch (SetOSErrorTracking (@TrackLastOSError));
- Finalization
- FreeTerminateProcs;
- DoneExceptions;
- end.
|