| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977 | {    This file is part of the Free Pascal run time library.    Copyright (c) 2014 by Free Pascal development team    Sysutils unit for AmigaOS & clones    Based on Amiga 1.x version by Carl Eric Codere, and other    parts of the RTL    AmigaOS and MorphOS support by Karoly Balogh    AROS support by Marcus Sackrow    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. **********************************************************************}{$IFNDEF FPC_DOTTEDUNITS}unit sysutils;{$ENDIF FPC_DOTTEDUNITS}interface{$MODE objfpc}{$MODESWITCH OUT}{$IFDEF UNICODERTL}{$MODESWITCH UNICODESTRINGS}{$ELSE}{$H+}{$ENDIF}{$modeswitch typehelpers}{$modeswitch advancedrecords}{$DEFINE OS_FILESETDATEBYNAME}{$DEFINE HAS_SLEEP}{$DEFINE HAS_OSERROR}{$DEFINE HAS_TEMPDIR}{OS has only 1 byte version for ExecuteProcess}{$define executeprocuni}{ 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}{ Include platform independent interface part }{$i sysutilh.inc}{ Platform dependent calls }function DeviceByIdx(Idx: Integer): string;function AddDisk(Const Path: string): Integer;function RefreshDeviceList: Integer;function DiskSize(Drive: AnsiString): Int64;function DiskFree(Drive: AnsiString): Int64;implementation{$IFDEF FPC_DOTTEDUNITS}uses  TP.DOS, System.SysConst;{$ELSE FPC_DOTTEDUNITS}uses  dos, sysconst;{$ENDIF FPC_DOTTEDUNITS}{$DEFINE FPC_FEXPAND_VOLUMES} (* Full paths begin with drive specification *){$DEFINE FPC_FEXPAND_DRIVESEP_IS_ROOT}{$DEFINE FPC_FEXPAND_NO_DEFAULT_PATHS}{$DEFINE FPC_FEXPAND_DIRSEP_IS_UPDIR}{ Include platform independent implementation part }{$i sysutils.inc}{ * Include system specific includes * }{$include execd.inc}{$include execf.inc}{$include timerd.inc}{$include doslibd.inc}{$include doslibf.inc}{$include utilf.inc}{$ifdef cpum68k}{$if defined(amiga_v1_0_only) or defined(amiga_v1_2_only)}{$include legacyexech.inc}{$include legacydosh.inc}{$include legacyutilh.inc}{$endif}{$endif}{ * Followings are implemented in the system unit! * }function PathConv(path: shortstring): shortstring; external name 'PATHCONV';function PathConv(path: RawByteString): RawByteString; external name 'PATHCONVRBS';procedure AddToList(var l: Pointer; h: THandle); external name 'ADDTOLIST';function RemoveFromList(var l: Pointer; h: THandle): boolean; external name 'REMOVEFROMLIST';function CheckInList(var l: Pointer; h: THandle): pointer; external name 'CHECKINLIST';var  ASYS_FileList: Pointer; external name 'ASYS_FILELIST';function BADDR(bval: BPTR): Pointer; Inline;begin  {$if defined(AROS)}  // deactivated for now //and (not defined(AROS_BINCOMPAT))}  BADDR := Pointer(bval);  {$else}  BADDR:=Pointer(bval Shl 2);  {$endif}end;function BSTR2STRING(s : Pointer): PAnsiChar; Inline;begin  {$if defined(AROS)}  // deactivated for now //and (not defined(AROS_BINCOMPAT))}  BSTR2STRING:=PAnsiChar(s);  {$else}  BSTR2STRING:=PAnsiChar(BADDR(PtrInt(s)))+1;  {$endif}end;function BSTR2STRING(s : BPTR): PAnsiChar; Inline;begin  {$if defined(AROS)}  // deactivated for now //and (not defined(AROS_BINCOMPAT))}  BSTR2STRING:=PAnsiChar(s);  {$else}  BSTR2STRING:=PAnsiChar(BADDR(s))+1;  {$endif}end;function AmigaFileDateToDateTime(aDate: TDateStamp; out success: boolean): TDateTime;var  tmpSecs: DWord;  tmpDate: TDateTime;  tmpTime: TDateTime;  clockData: TClockData;begin  with aDate do    tmpSecs:=(ds_Days * (24 * 60 * 60)) + (ds_Minute * 60) + (ds_Tick div TICKS_PER_SECOND);  Amiga2Date(tmpSecs,@clockData);{$HINT TODO: implement msec values, if possible}  with clockData do begin     success:=TryEncodeDate(year,month,mday,tmpDate) and              TryEncodeTime(hour,min,sec,0,tmpTime);  end;  result:=ComposeDateTime(tmpDate,tmpTime);end;function DateTimeToAmigaDateStamp(dateTime: TDateTime): TDateStamp;var  tmpSecs: DWord;  clockData: TClockData;  tmpMSec: Word;begin{$HINT TODO: implement msec values, if possible}  with clockData do begin     DecodeDate(dateTime,year,month,mday);     DecodeTime(dateTime,hour,min,sec,tmpMSec);  end;  tmpSecs:=Date2Amiga(@clockData);  with result do begin     ds_Days:= tmpSecs div (24 * 60 * 60);     ds_Minute:= (tmpSecs div 60) mod ds_Days;     ds_Tick:= (((tmpSecs mod 60) mod ds_Minute) mod ds_Days) * TICKS_PER_SECOND;  end;end;{****************************************************************************                              File Functions****************************************************************************}{$I-}{ Required for correct usage of these routines }(****** non portable routines ******)function FileOpen(const FileName: rawbytestring; Mode: Integer): THandle;var  SystemFileName: RawByteString;  dosResult: THandle;begin  SystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(FileName));  {$WARNING FIX ME! To do: FileOpen Access Modes}  dosResult:=Open(PAnsiChar(SystemFileName),MODE_OLDFILE);  if dosResult=0 then    dosResult:=-1  else    AddToList(ASYS_fileList,dosResult);  FileOpen:=dosResult;end;function FileGetDate(Handle: THandle) : Int64;var  tmpFIB : PFileInfoBlock;  tmpDateTime: TDateTime;  validFile: boolean;begin  validFile:=false;  if (Handle <> 0) then begin    new(tmpFIB);    if ExamineFH(BPTR(Handle),tmpFIB) then begin      tmpDateTime:=AmigaFileDateToDateTime(tmpFIB^.fib_Date,validFile);    end;    dispose(tmpFIB);  end;  if validFile then    result:=DateTimeToFileDate(tmpDateTime)  else    result:=-1;end;function FileSetDate(Handle: THandle; Age: Int64) : LongInt;var  tmpDateStamp: TDateStamp;  tmpName: array[0..255] of AnsiChar;begin  result:=0;  if (Handle <> 0) then begin    if NameFromFH(BPTR(Handle), @tmpName, 256) then begin      tmpDateStamp:=DateTimeToAmigaDateStamp(FileDateToDateTime(Age));      if not SetFileDate(@tmpName,@tmpDateStamp) then begin        IoErr(); // dump the error code for now (TODO)        result:=-1;      end;    end;  end;end;function FileSetDate(const FileName: RawByteString; Age: Int64) : LongInt;var  tmpDateStamp: TDateStamp;  SystemFileName: RawByteString;begin  result:=0;  SystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(FileName));  tmpDateStamp:=DateTimeToAmigaDateStamp(FileDateToDateTime(Age));  if not SetFileDate(PAnsiChar(SystemFileName),@tmpDateStamp) then begin    IoErr(); // dump the error code for now (TODO)    result:=-1;  end;end;function FileCreate(const FileName: RawByteString) : THandle;var  SystemFileName: RawByteString;  dosResult: THandle;begin  dosResult:=-1;  { Open file in MODDE_READWRITE, then truncate it by hand rather than    opening it in MODE_NEWFILE, because that returns an exclusive lock    so some operations might fail with it (KB) }  SystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(FileName));  dosResult:=Open(PAnsiChar(SystemFileName),MODE_READWRITE);  if dosResult = 0 then exit;  if SetFileSize(dosResult, 0, OFFSET_BEGINNING) = 0 then    AddToList(ASYS_fileList,dosResult)  else begin    dosClose(dosResult);    dosResult:=-1;  end;  FileCreate:=dosResult;end;function FileCreate(const FileName: RawByteString; Rights: integer): THandle;begin  {$WARNING FIX ME! To do: FileCreate Access Modes}  FileCreate:=FileCreate(FileName);end;function FileCreate(const FileName: RawByteString; ShareMode: integer; Rights : integer): THandle;begin  {$WARNING FIX ME! To do: FileCreate Access Modes}  FileCreate:=FileCreate(FileName);end;function FileRead(Handle: THandle; out Buffer; Count: LongInt): LongInt;begin  FileRead:=-1;  if (Count<=0) or (Handle=0) or (Handle=-1) then exit;  FileRead:=dosRead(Handle,@Buffer,Count);end;function FileWrite(Handle: THandle; const Buffer; Count: LongInt): LongInt;begin  FileWrite:=-1;  if (Count<=0) or (Handle=0) or (Handle=-1) then exit;  FileWrite:=dosWrite(Handle,@Buffer,Count);end;function FileSeek(Handle: THandle; FOffset, Origin: LongInt) : LongInt;var  seekMode: LongInt;begin  FileSeek:=-1;  if (Handle=0) or (Handle=-1) then exit;  case Origin of    fsFromBeginning: seekMode:=OFFSET_BEGINNING;    fsFromCurrent  : seekMode:=OFFSET_CURRENT;    fsFromEnd      : seekMode:=OFFSET_END;  end;  dosSeek(Handle, FOffset, seekMode);  { get the current position when FileSeek ends, which should return    the *NEW* position, while Amiga Seek() returns the old one }  FileSeek:=dosSeek(Handle, 0, OFFSET_CURRENT);end;function FileSeek(Handle: THandle; FOffset: Int64; Origin: Longint): Int64;begin  {$WARNING Need to add 64bit call }  FileSeek:=FileSeek(Handle,LongInt(FOffset),LongInt(Origin));end;procedure FileClose(Handle: THandle);begin  if (Handle=0) or (Handle=-1) then exit;  dosClose(Handle);  RemoveFromList(ASYS_fileList,Handle);end;function FileTruncate(Handle: THandle; Size: Int64): Boolean;var  dosResult: LongInt;begin  FileTruncate:=False;  if Size > high (longint) then exit;{$WARNING Possible support for 64-bit FS to be checked!}  if (Handle=0) or (Handle=-1) then exit;  dosResult:=SetFileSize(Handle, Size, OFFSET_BEGINNING);  if (dosResult<0) then exit;  FileTruncate:=True;end;function DeleteFile(const FileName: RawByteString) : Boolean;var  SystemFileName: RawByteString;begin  SystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(FileName));  DeleteFile:=dosDeleteFile(PAnsiChar(SystemFileName));end;function RenameFile(const OldName, NewName: RawByteString): Boolean;var  OldSystemFileName, NewSystemFileName: RawByteString;begin  OldSystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(OldName));  NewSystemFileName:=PathConv(ToSingleByteFileSystemEncodedFileName(NewName));  RenameFile:=dosRename(PAnsiChar(OldSystemFileName), PAnsiChar(NewSystemFileName)) <> 0;end;(****** end of non portable routines ******)function FileAge (const FileName : RawByteString): Int64;var  tmpLock: BPTR;  tmpFIB : PFileInfoBlock;  tmpDateTime: TDateTime;  validFile: boolean;  SystemFileName: RawByteString;begin  validFile:=false;  SystemFileName := PathConv(ToSingleByteFileSystemEncodedFileName(FileName));  tmpLock := Lock(PAnsiChar(SystemFileName), SHARED_LOCK);  if (tmpLock <> 0) then begin    new(tmpFIB);    if Examine(tmpLock,tmpFIB) <> 0 then begin      tmpDateTime:=AmigaFileDateToDateTime(tmpFIB^.fib_Date,validFile);    end;    Unlock(tmpLock);    dispose(tmpFIB);  end;  if validFile then    result:=DateTimeToFileDate(tmpDateTime)  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  tmpLock: BPTR;  tmpFIB : PFileInfoBlock;  SystemFileName: RawByteString;begin  result:=false;  SystemFileName := PathConv(ToSingleByteFileSystemEncodedFileName(FileName));  tmpLock := Lock(PAnsiChar(SystemFileName), SHARED_LOCK);  if (tmpLock <> 0) then begin    new(tmpFIB);    if (Examine(tmpLock,tmpFIB) <> 0) and (tmpFIB^.fib_DirEntryType <= 0) then      result:=true;    Unlock(tmpLock);    dispose(tmpFIB);  end;end;Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;var  tmpStr: RawByteString;  Anchor: PAnchorPath;  tmpDateTime: TDateTime;  validDate: boolean;begin  result:=-1; { We emulate Linux/Unix behaviour, and return -1 on errors. }  tmpStr:=PathConv(ToSingleByteFileSystemEncodedFileName(Path));  { $1e = faHidden or faSysFile or faVolumeID or faDirectory }  Rslt.ExcludeAttr := (not Attr) and ($1e);  Rslt.FindHandle  := nil;  new(Anchor);  FillChar(Anchor^,sizeof(TAnchorPath),#0);  Rslt.FindHandle := Anchor;  if MatchFirst(PAnsiChar(tmpStr),Anchor)<>0 then    begin      InternalFindClose(Rslt.FindHandle);      exit;    end;  with Anchor^.ap_Info do begin    Name := fib_FileName;    SetCodePage(Name,DefaultFileSystemCodePage,false);    Rslt.Size := fib_Size;    Rslt.Time := DateTimeToFileDate(AmigaFileDateToDateTime(fib_Date,validDate));    if not validDate then      begin        InternalFindClose(Rslt.FindHandle);        exit;      end;    { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }    Rslt.Attr := 128;    if fib_DirEntryType > 0 then Rslt.Attr:=Rslt.Attr or faDirectory;    if ((fib_Protection and FIBF_READ) <> 0) and       ((fib_Protection and FIBF_WRITE) = 0) then Rslt.Attr:=Rslt.Attr or faReadOnly;    result:=0; { Return zero if everything went OK }  end;end;Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;var  Anchor: PAnchorPath;  validDate: boolean;begin  result:=-1;  Anchor:=PAnchorPath(Rslt.FindHandle);  if not assigned(Anchor) then exit;  if MatchNext(Anchor) <> 0 then exit;  with Anchor^.ap_Info do begin    Name := fib_FileName;    SetCodePage(Name,DefaultFileSystemCodePage,false);    Rslt.Size := fib_Size;    Rslt.Time := DateTimeToFileDate(AmigaFileDateToDateTime(fib_Date,validDate));    if not validDate then exit;    { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }    Rslt.Attr := 128;    if fib_DirEntryType > 0 then Rslt.Attr:=Rslt.Attr or faDirectory;    if ((fib_Protection and FIBF_READ) <> 0) and       ((fib_Protection and FIBF_WRITE) = 0) then Rslt.Attr:=Rslt.Attr or faReadOnly;    result:=0; { Return zero if everything went OK }  end;end;Procedure InternalFindClose(var Handle: Pointer);var  Anchor: PAnchorPath absolute Handle;begin  if not assigned(Anchor) then    exit;  MatchEnd(Anchor);  Dispose(Anchor);  Handle:=nil;end;(****** end of non portable routines ******)Function FileGetAttr (Const FileName : RawByteString) : Longint;var F: file; attr: word;begin Assign(F,FileName); {$IFDEF FPC_DOTTEDUNITS}TP.{$ENDIF}dos.GetFAttr(F,attr); if DosError <> 0 then    FileGetAttr := -1 else    FileGetAttr := Attr;end;Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;var F: file;begin Assign(F, FileName); {$IFDEF FPC_DOTTEDUNITS}TP.{$ENDIF}Dos.SetFAttr(F, Attr and $ffff); FileSetAttr := DosError;end;{****************************************************************************                              Disk Functions****************************************************************************}{  The Diskfree and Disksize functions need a file on the specified drive, since this  is required for the statfs system call.  These filenames are set in drivestr[0..26], and have been preset to :   0 - ':'      (default drive - hence current dir is ok.)   1 - 'DF0:'   (floppy drive 1 - should be adapted to local system )   2 - 'DF1:'   (floppy drive 2 - should be adapted to local system )   3 - 'SYS:'   (C: equivalent of dos is the SYS: partition)   4..26          (can be set by you're own applications)  ! Use AddDisk() to Add new drives !  They both return -1 when a failure occurs.}var  DeviceList: array[0..26] of string[20];  NumDevices: Integer = 0;const  IllegalDevices: array[0..12] of string =(                   'PED:',                   'PRJ:',                   'PIPE:',   // Pipes                   'XPIPE:',  // Extended Pipe                   'CON:',    // Console                   'RAW:',    // RAW: Console                   'KCON:',   // KingCON Console                   'KRAW:',   // KingCON RAW                   'SER:',    // serial Ports                   'SER0:',                   'SER1:',                   'PAR:',    // Parallel Port                   'PRT:');   // Printerfunction IsIllegalDevice(DeviceName: string): Boolean;var  i: Integer;  Str: AnsiString;begin  IsIllegalDevice := False;  Str := UpperCase(DeviceName);  for i := Low(IllegalDevices) to High(IllegalDevices) do  begin    if Str = IllegalDevices[i] then    begin      IsIllegalDevice := True;      Exit;    end;  end;end;function DeviceByIdx(Idx: Integer): string;begin  DeviceByIdx := '';  if (Idx < 0) or (Idx >= NumDevices) then    Exit;  DeviceByIdx := DeviceList[Idx];end;function AddDisk(const Path: string): Integer;begin  // if hit border, restart at 4  if NumDevices > 26 then    NumDevices := 4;  // set the device  DeviceList[NumDevices] := Copy(Path, 1, 20);  // return the Index increment for next run  AddDisk := NumDevices;  Inc(NumDevices);end;function RefreshDeviceList: Integer;var  List: PDosList;  Temp: PAnsiChar;  Str: string;begin  NumDevices := 0;  AddDisk(':');          // Index 0  AddDisk('DF0:');       // Index 1  AddDisk('DF1:');       // Index 2  AddDisk('SYS:');       // Index 3  // Lock the List  List := LockDosList(LDF_DEVICES or LDF_READ);  // Inspect the List  repeat    List := NextDosEntry(List, LDF_DEVICES);    if List <> nil then    begin      Temp := BSTR2STRING(List^.dol_Name);      Str := strpas(Temp) + ':';      if not IsIllegalDevice(str) then        AddDisk(Str);    end;  until List = nil;  UnLockDosList(LDF_DEVICES or LDF_READ);  RefreshDeviceList := NumDevices;end;// New easier DiskSize()//function DiskSize(Drive: AnsiString): Int64;var  DirLock: BPTR;  Inf: TInfoData;  MyProc: PProcess;  OldWinPtr: Pointer;begin  DiskSize := -1;  //  MyProc := PProcess(FindTask(Nil));  OldWinPtr := MyProc^.pr_WindowPtr;  MyProc^.pr_WindowPtr := Pointer(-1);  //  DirLock := Lock(PAnsiChar(Drive), SHARED_LOCK);  if DirLock <> 0 then  begin    if Info(DirLock, @Inf) <> 0 then      DiskSize := Int64(Inf.id_NumBlocks) * Inf.id_BytesPerBlock;    UnLock(DirLock);  end;  if OldWinPtr <> Pointer(-1) then    MyProc^.pr_WindowPtr := OldWinPtr;end;function DiskSize(Drive: Byte): Int64;begin  DiskSize := -1;  if (Drive < 0) or (Drive >= NumDevices) then    Exit;  DiskSize := DiskSize(DeviceList[Drive]);end;// New easier DiskFree()//function DiskFree(Drive: AnsiString): Int64;var  DirLock: BPTR;  Inf: TInfoData;  MyProc: PProcess;  OldWinPtr: Pointer;begin  DiskFree := -1;  //  MyProc := PProcess(FindTask(Nil));  OldWinPtr := MyProc^.pr_WindowPtr;  MyProc^.pr_WindowPtr := Pointer(-1);  //  DirLock := Lock(PAnsiChar(Drive), SHARED_LOCK);  if DirLock <> 0 then  begin    if Info(DirLock, @Inf) <> 0 then      DiskFree := Int64(Inf.id_NumBlocks - Inf.id_NumBlocksUsed) * Inf.id_BytesPerBlock;    UnLock(DirLock);  end;  if OldWinPtr <> Pointer(-1) then    MyProc^.pr_WindowPtr := OldWinPtr;end;function DiskFree(Drive: Byte): Int64;begin  DiskFree := -1;  if (Drive < 0) or (Drive >= NumDevices) then    Exit;  DiskFree := DiskFree(DeviceList[Drive]);end;function DirectoryExists(const Directory: RawByteString; FollowLink : Boolean): Boolean;var  tmpLock: BPTR;  FIB    : PFileInfoBlock;  SystemDirName: RawByteString;begin  result:=false;  if (Directory='') or (InOutRes<>0) then exit;  SystemDirName:=PathConv(ToSingleByteFileSystemEncodedFileName(Directory));  tmpLock:=Lock(PAnsiChar(SystemDirName),SHARED_LOCK);  if tmpLock=0 then exit;  FIB:=nil; new(FIB);  if (Examine(tmpLock,FIB) <> 0) and (FIB^.fib_DirEntryType>0) then    result:=True;  if tmpLock<>0 then Unlock(tmpLock);  if assigned(FIB) then dispose(FIB);end;{****************************************************************************                              Locale Functions****************************************************************************}Procedure GetLocalTime(var SystemTime: TSystemTime);var dayOfWeek: word; Sec100: Word;begin  {$IFDEF FPC_DOTTEDUNITS}TP.{$ENDIF}dos.GetTime(SystemTime.Hour, SystemTime.Minute, SystemTime.Second, Sec100);  SystemTime.Millisecond := Sec100 * 10;  {$IFDEF FPC_DOTTEDUNITS}TP.{$ENDIF}dos.GetDate(SystemTime.Year, SystemTime.Month, SystemTime.Day, DayOfWeek);end;Procedure InitAnsi;Var  i : longint;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 191 do    UpperCaseTable[i] := chr(i);  Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));  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 191 do    LowerCaseTable[i] := chr(i);  Move (CPISO88591LCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));end;Procedure InitInternational;begin  InitInternationalGeneric;  InitAnsi;end;function SysErrorMessage(ErrorCode: Integer): String;begin  Result:=Format(SUnknownErrorCode,[ErrorCode]);end;function GetLastOSError: Integer;begin    result:=-1;end;{****************************************************************************                              OS utility functions****************************************************************************}var  StrOfPaths: String;function SystemTags(const command: PAnsiChar; const tags: array of PtrUInt): LongInt;begin  SystemTags:=SystemTagList(command,@tags);end;function GetPathString: String;var   f : text;   s : string;begin   s := '';   result := '';   { Alternatively, this could use PIPE: handler on systems which     have this by default (not the case on classic Amiga), but then     the child process should be started async, which for a simple     Path command probably isn't worth the trouble. (KB) }   assign(f,'T:'+HexStr(FindTask(nil))+'_path.tmp');   rewrite(f);   { This is a pretty ugly stunt, combining Pascal and Amiga system     functions, but works... }   SystemTags('C:Path',[SYS_Input, 0, SYS_Output, TextRec(f).Handle, TAG_END]);   close(f);   reset(f);   { skip the first line, garbage }   if not eof(f) then readln(f,s);   while not eof(f) do begin      readln(f,s);      if result = '' then        result := s      else        result := result + ';' + s;   end;   close(f);   erase(f);end;Function GetEnvironmentVariable(Const EnvVar : String) : String;begin  if UpCase(envvar) = 'PATH' then begin    if StrOfpaths = '' then StrOfPaths := GetPathString;    Result:=StrOfPaths;  end else    Result:={$IFDEF FPC_DOTTEDUNITS}TP.{$ENDIF}Dos.Getenv(shortstring(EnvVar));end;Function GetEnvironmentVariableCount : Integer;begin  // Result:=FPCCountEnvVar(EnvP);  Result:={$IFDEF FPC_DOTTEDUNITS}TP.{$ENDIF}Dos.envCount;end;Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};begin  // Result:=FPCGetEnvStrFromP(Envp,Index);  Result:={$IFDEF FPC_DOTTEDUNITS}TP.{$ENDIF}Dos.EnvStr(Index);end;function ExecuteProcess (const Path: RawByteString; const ComLine: RawByteString;Flags:TExecuteFlags=[]):                                                                       integer;var  tmpPath,  convPath: RawByteString;  CommandLine: AnsiString;  tmpLock: BPTR;  E: EOSError;begin  DosError:= 0;  convPath:=PathConv(ToSingleByteFileSystemEncodedFileName(Path));  tmpPath:=convPath+' '+ToSingleByteFileSystemEncodedFileName(ComLine);  { Here we must first check if the command we wish to execute }  { actually exists, because this is NOT handled by the        }  { _SystemTagList call (program will abort!!)                 }  { Try to open with shared lock }  tmpLock:=Lock(PAnsiChar(convPath),SHARED_LOCK);  if tmpLock<>0 then    begin      { File exists - therefore unlock it }      Unlock(tmpLock);      result:=SystemTagList(PAnsiChar(tmpPath),nil);      { on return of -1 the shell could not be executed }      { probably because there was not enough memory    }      if result = -1 then        DosError:=8;    end  else    DosError:=3;  if DosError <> 0 then begin    if ComLine = '' then      CommandLine := Path    else      CommandLine := Path + ' ' + ComLine;    E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, DosError]);    E.ErrorCode := DosError;    raise E;  end;end;function ExecuteProcess (const Path: RawByteString;                                  const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;var  CommandLine: RawByteString;  I: integer;begin  Commandline := '';  for I := 0 to High (ComLine) do   if Pos (' ', ComLine [I]) <> 0 then    CommandLine := CommandLine + ' ' + '"' + ToSingleByteFileSystemEncodedFileName(ComLine [I]) + '"'   else    CommandLine := CommandLine + ' ' + ToSingleByteFileSystemEncodedFileName(Comline [I]);  ExecuteProcess := ExecuteProcess (Path, CommandLine);end;procedure Sleep(Milliseconds: cardinal);begin  // Amiga dos.library Delay() has precision of 1/50 seconds  DOSDelay(Milliseconds div 20);end;function GetTempDir(Global: Boolean): string;begin  if Assigned(OnGetTempDir) then    Result := OnGetTempDir(Global)  else  begin    Result := GetEnvironmentVariable('TEMP');    if Result = '' Then      Result:=GetEnvironmentVariable('TMP');    if Result = '' then      Result := 'T:'; // fallback.  end;  if Result <> '' then    Result := IncludeTrailingPathDelimiter(Result);end;{****************************************************************************                              Initialization code****************************************************************************}Initialization  InitExceptions;  InitInternational;    { Initialize internationalization settings }  OnBeep:=Nil;          { No SysBeep() on Amiga, for now. Figure out if we want                          to use intuition.library/DisplayBeep() for this (KB) }  StrOfPaths:='';  RefreshDeviceList;Finalization  FreeTerminateProcs;  DoneExceptions;end.
 |