| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699 | {    This file is part of the Free Pascal run time library.    Copyright (c) 2016 by Free Pascal development team    Sysutils unit for Atari    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}{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 }implementation{$IFDEF FPC_DOTTEDUNITS}uses{  TP.DOS,} System.SysConst;{$ELSE FPC_DOTTEDUNITS}uses{  dos,} sysconst;{$ENDIF FPC_DOTTEDUNITS}{$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}{$i gemdos.inc}var  basepage: PPD; external name '__base';{****************************************************************************                              File Functions****************************************************************************}{$I-}{ Required for correct usage of these routines }(****** non portable routines ******)function FileOpen(const FileName: rawbytestring; Mode: Integer): THandle;begin  { Mode has some Share modes. Maybe something for MiNT? }  { Lower three bits of Mode are actually TOS compatible }  FileOpen:=gemdos_fopen(PAnsiChar(FileName), Mode and 3);  if FileOpen < -1 then    FileOpen:=-1;end;function FileGetDate(Handle: THandle) : Int64;var  td: TDOSTIME;begin  { Fdatime doesn't report errors... }  gemdos_fdatime(@td,handle,0);  result:=(td.date shl 16) or td.time;end;function FileSetDate(Handle: THandle; Age: Int64) : LongInt;var  td: TDOSTIME;begin  td.date:=(Age shr 16) and $ffff;  td.time:=Age and $ffff;  gemdos_fdatime(@td,handle,1);  { Fdatime doesn't report errors... }  result:=0;end;function FileSetDate(const FileName: RawByteString; Age: Int64) : LongInt;var  f: THandle;begin  FileSetDate:=-1;  f:=FileOpen(FileName,fmOpenReadWrite);  if f < 0 then    exit;  FileSetDate(f,Age);  FileClose(f);end;function FileCreate(const FileName: RawByteString) : THandle;begin  FileCreate:=gemdos_fcreate(PAnsiChar(FileName),0);  if FileCreate < -1 then    FileCreate:=-1;end;function FileCreate(const FileName: RawByteString; Rights: integer): THandle;begin  { Rights are Un*x extension. Maybe something for MiNT? }  FileCreate:=FileCreate(FileName);end;function FileCreate(const FileName: RawByteString; ShareMode: integer; Rights : integer): THandle;begin  { Rights and ShareMode are Un*x extension. Maybe something for MiNT? }  FileCreate:=FileCreate(FileName);end;function FileRead(Handle: THandle; out Buffer; Count: LongInt): LongInt;begin  FileRead:=-1;  if (Count<=0) then    exit;  FileRead:=gemdos_fread(handle, count, @buffer);  if FileRead < -1 then    FileRead:=-1;end;function FileWrite(Handle: THandle; const Buffer; Count: LongInt): LongInt;begin  FileWrite:=-1;  if (Count<=0) then     exit;  FileWrite:=gemdos_fwrite(handle, count, @buffer);  if FileWrite < -1 then    FileWrite:=-1;end;function FileSeek(Handle: THandle; FOffset, Origin: LongInt) : LongInt;var  dosResult: longint;begin  FileSeek:=-1;  { TOS seek mode flags are actually compatible to DOS/TP }  dosResult:=gemdos_fseek(FOffset, Handle, Origin);  if dosResult < 0 then    exit;  FileSeek:=dosResult;end;function FileSeek(Handle: THandle; FOffset: Int64; Origin: Longint): Int64;begin  FileSeek:=FileSeek(Handle,LongInt(FOffset),Origin);end;procedure FileClose(Handle: THandle);begin  gemdos_fclose(handle);end;function FileTruncate(Handle: THandle; Size: Int64): Boolean;begin  FileTruncate:=False;end;function DeleteFile(const FileName: RawByteString) : Boolean;begin  DeleteFile:=gemdos_fdelete(PAnsiChar(FileName)) >= 0;end;function RenameFile(const OldName, NewName: RawByteString): Boolean;begin  RenameFile:=gemdos_frename(0,PAnsiChar(oldname),PAnsiChar(newname)) >= 0;end;(****** end of non portable routines ******)function FileAge (const FileName : RawByteString): Int64;var  f: THandle;begin  FileAge:=-1;  f:=FileOpen(FileName,fmOpenRead);  if f < 0 then    exit;  FileAge:=FileGetDate(f);  FileClose(f);end;function FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean;begin  Result := False;end;function FileExists (const FileName : RawByteString; FollowLink : Boolean) : Boolean;var  Attr: longint;begin  FileExists:=false;  Attr:=FileGetAttr(FileName);  if Attr < 0 then    exit;  result:=(Attr and (faVolumeID or faDirectory)) = 0;end;type  PInternalFindData = ^TInternalFindData;  TInternalFindData = record    dta_original: pointer;    dta_search: TDTA;  end;Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;var  dosResult: longint;  IFD: PInternalFindData;begin  result:=-1; { We emulate Linux/Unix behaviour, and return -1 on errors. }  new(IFD);  IFD^.dta_original:=gemdos_getdta;  gemdos_setdta(@IFD^.dta_search);  Rslt.FindHandle:=nil;  dosResult:=gemdos_fsfirst(PAnsiChar(path), Attr and faAnyFile);  if dosResult < 0 then    begin      InternalFindClose(IFD);      exit;    end;  Rslt.FindHandle:=IFD;  with IFD^.dta_search do    begin      Name:=d_fname;      SetCodePage(Name,DefaultFileSystemCodePage,false);      Rslt.Time:=(d_date shl 16) or d_time;      Rslt.Size:=d_length;      { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }      Rslt.Attr := 128 or d_attrib;    end;  result:=0;end;Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;var  dosResult: longint;  IFD: PInternalFindData;begin  result:=-1;  IFD:=PInternalFindData(Rslt.FindHandle);  if not assigned(IFD) then    exit;  dosResult:=gemdos_fsnext;  if dosResult < 0 then    exit;  with IFD^.dta_search do    begin      Name:=d_fname;      SetCodePage(Name,DefaultFileSystemCodePage,false);      Rslt.Time:=(d_date shl 16) or d_time;      Rslt.Size:=d_length;      { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }      Rslt.Attr := 128 or d_attrib;    end;  result:=0;end;Procedure InternalFindClose(var Handle: Pointer);var  IFD: PInternalFindData;begin  IFD:=PInternalFindData(Handle);  if not assigned(IFD) then    exit;  gemdos_setdta(IFD^.dta_original);  dispose(IFD);  IFD:=nil;end;(****** end of non portable routines ******)Function FileGetAttr (Const FileName : RawByteString) : Longint;begin  FileGetAttr:=gemdos_fattrib(PAnsiChar(FileName),0,0);end;Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;begin  FileSetAttr:=gemdos_fattrib(PAnsiChar(FileName),1,Attr and faAnyFile);  if FileSetAttr < -1 then    FileSetAttr:=-1  else    FileSetAttr:=0;end;{****************************************************************************                              Disk Functions****************************************************************************}function DiskSize(Drive: Byte): Int64;var  dosResult: longint;  di: TDISKINFO;begin  DiskSize := -1;  dosResult:=gemdos_dfree(@di,drive);  if dosResult < 0 then    exit;  DiskSize:=di.b_total * di.b_secsiz * di.b_clsiz;end;function DiskFree(Drive: Byte): Int64;var  dosResult: longint;  di: TDISKINFO;begin  DiskFree := -1;  dosResult:=gemdos_dfree(@di,drive);  if dosResult < 0 then    exit;  DiskFree:=di.b_free * di.b_secsiz * di.b_clsiz;end;function DirectoryExists(const Directory: RawByteString; FollowLink : Boolean): Boolean;var  Attr: longint;begin  DirectoryExists:=false;  Attr:=FileGetAttr(Directory);  if Attr < 0 then    exit;  result:=(Attr and faDirectory) <> 0;end;{****************************************************************************                              Locale Functions****************************************************************************}Procedure GetLocalTime(var SystemTime: TSystemTime);var  TOSTime: Longint;begin   LongRec(TOSTime).hi:=gemdos_tgetdate;   LongRec(TOSTime).lo:=gemdos_tgettime;   DateTimeToSystemTime(FileDateToDateTime(TOSTime),SystemTime);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****************************************************************************}function fpGetEnv(const envvar : ShortString): RawByteString; external name '_fpc_atari_getenv';function GetPathString: String;begin  {writeln('Unimplemented GetPathString');}  result := '';end;Function GetEnvironmentVariable(Const EnvVar : String) : String;begin   GetEnvironmentVariable := fpgetenv(envvar);end;Function GetEnvironmentVariableCount : Integer;var  hp : PAnsiChar;begin  result:=0;  hp:=basepage^.p_env;  If (Hp<>Nil) then    while hp^<>#0 do      begin      Inc(Result);      hp:=hp+strlen(hp)+1;      end;end;Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};var  hp : PAnsiChar;begin  result:='';  hp:=basepage^.p_env;  If (Hp<>Nil) then    begin      while (hp^<>#0) and (Index>1) do        begin          Dec(Index);          hp:=hp+strlen(hp)+1;        end;    If (hp^<>#0) then      begin        Result:=hp;      end;    end;end;function ExecuteProcess (const Path: RawByteString; const ComLine: RawByteString;Flags:TExecuteFlags=[]):                                                                       integer;var  tmpPath: RawByteString;  pcmdline: ShortString;  CommandLine: RawByteString;  E: EOSError;  env, s: PAnsiChar;  buf, start: PAnsiChar;  enlen, len: SizeInt;  hp : PAnsiChar;begin  tmpPath:=ToSingleByteFileSystemEncodedFileName(Path);  pcmdline:=ToSingleByteFileSystemEncodedFileName(ComLine);  { count up space needed for environment }  enlen := 0;  hp:=basepage^.p_env;  If (Hp<>Nil) then    while hp^<>#0 do      begin      len := strlen(hp) + 1;      inc(enlen, len);      inc(hp, len);      end;  { count up space needed for arguments }  len := strlen(PAnsiChar(tmpPath)) + 1;  inc(enlen, len);  buf := PAnsiChar(ComLine);  while (buf^<>#0) do                   // count nr of args   begin     while (buf^ in [' ',#9,#10]) do    // Kill separators.      inc(buf);     if buf^=#0 Then       break;     if buf^='"' Then                   // quotes argument?       begin         inc(buf);         start := buf;         while not (buf^ in [#0,'"']) do // then end of argument is end of string or next quote           inc(buf);         len := buf - start;         if len=0 then len := 1; (* TODO: needs to set NULL environment variable *)         inc(len);         inc(enlen, len);         if buf^='"' then                // skip closing quote.           inc(buf);       end     else       begin                            // else std         start := buf;         while not (buf^ in [' ',#0,#9,#10]) do           inc(buf);         len := buf - start + 1;         inc(enlen, len);       end;   end;  inc(enlen, 64); { filler for stuff like ARGV= and zeros }  env := gemdos_malloc(enlen);  if env = nil then    result := ENSMEM  else    begin      s := env;      { copy the environment }      hp:=basepage^.p_env;      If (Hp<>Nil) then        while hp^<>#0 do          begin          len := strlen(hp) + 1;          strcopy(s, hp);          inc(hp, len);          inc(s, len);          end;      { start of arguments }      strcopy(s, 'ARGV=');      inc(s, 6); { s+=sizeof("ARGV=") }      { copy argv[0] }      buf := PAnsiChar(tmpPath);      len := strlen(buf) + 1;      strcopy(s, buf);          inc(s, len);      { copy the parameters }          buf:=PAnsiChar(ComLine);          while (buf^<>#0) do           begin             while (buf^ in [' ',#9,#10]) do    // Kill separators.               inc(buf);             if buf^=#0 Then               break;             if buf^='"' Then                   // quotes argument?               begin                 inc(buf);                 start := buf;                 while not (buf^ in [#0,'"']) do // then end of argument is end of string or next quote                   begin                     s^ := buf^;                     inc(s);                     inc(buf);                   end;                 if buf = start then                   begin                     s^ := ' ';                     inc(s);                   end;                 if buf^='"' then                // skip closing quote.                   inc(buf);                 s^ := #0;                 inc(s);               end             else               begin                 start := buf;                 while not (buf^ in [' ',#0,#9,#10]) do                   begin                     s^ := buf^;                     inc(s);                     inc(buf);                   end;                 s^ := #0;                 inc(s);               end;           end;      { tie off environment }      s^ := #0;      inc(s);      s^ := #0;      { signal Extended Argument Passing }      pcmdline[0] := #127;      { the zero offset for cmdline is actually correct here. pexec() expects        pascal formatted string for cmdline, so length in first byte }      result:=gemdos_pexec(0,PAnsiChar(tmpPath),@pcmdline[0],env);      gemdos_mfree(env);    end;  if result < 0 then begin    if ComLine = '' then      CommandLine := Path    else      CommandLine := Path + ' ' + ComLine;    E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, result]);    E.ErrorCode := result;    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  {writeln('Unimplemented Sleep');}end;{****************************************************************************                              Initialization code****************************************************************************}Initialization  InitExceptions;  InitInternational;    { Initialize internationalization settings }  OnBeep:=Nil;          { No SysBeep() on Atari for now. }Finalization  FreeTerminateProcs;  DoneExceptions;end.
 |