IMPLEMENTATION MODULE Directories;

FROM DateTime IMPORT Date, Time;
FROM Streams IMPORT InputStream;
IMPORT SYSTEM;

INLINE 
  %#include <stdio.h>
  %
  %#ifndef MVS
  %#ifdef OS2
  %#define INCL_DOSFILEMGR
  %#define INCL_DOSERRORS
  %#include <os2.h>
  %#include <time.h>
  %#else
  %#ifdef UNIX
  %#include <unistd.h>
  %#endif
  %#include <sys/types.h>
  %#include <sys/stat.h>
  %#endif
  %#endif
  %
  %#ifdef YAFL_MICROSOFT
  %#include <io.h>
  %#include <direct.h>
  %#define stat _stat     /* !!! */
  %#define getcwd _getcwd
  %#define chdir _chdir
  %#endif 
  %
  %#ifdef LCC
  %#include <direct.h>
  %#endif
  END;

  CLASS DirectoryEntry;
  
    VAR
      TheSize: INTEGER;
      TheLastModification, TheLastAccess: Instant;
      TheName: ARRAY OF CHAR;
      
    METHOD SetLastModification (LastModification: Instant);
      BEGIN                   
      TheLastModification := LastModification;
      END SetLastModification;

    METHOD SetLastAccess (LastAccess: Instant);
      BEGIN                   
      TheLastAccess := LastAccess;
      END SetLastAccess;

    METHOD SetSize (Size: INTEGER);
      BEGIN
      TheSize := Size;
      END SetSize;
      
    METHOD SetName(Name: ARRAY OF CHAR);
      BEGIN       
      TheName := Name;
      END SetName;
  
    METHOD Size: INTEGER;
      BEGIN
      RESULT := TheSize;
      END Size;
      
    METHOD LastModification: Instant;
      BEGIN
      RESULT := TheLastModification;
      END LastModification;
      
    METHOD LastAccess: Instant;
      BEGIN
      RESULT := TheLastAccess;
      END LastAccess;
      
    METHOD Name: ARRAY OF CHAR;
      BEGIN    
      RESULT := TheName;
      END Name;
      
  END DirectoryEntry;

  ONCE CLASS Operations;

    METHOD CurrentDir : ARRAY OF CHAR;
      BEGIN	  
      INLINE
        % {
        %#ifdef OS2
        % ULONG ulDriveNum = 0; /* Drive number: current=0, A=1, B=2, ... */
	% CHAR chDirName[256] = "";
        % ULONG cbDirPathLen = 255;
        % APIRET rc = NO_ERROR;
	% rc = DosQueryCurrentDir (ulDriveNum, chDirName, &cbDirPathLen);
	% if (rc == NO_ERROR)
        %   {
        %   sprintf(chDirName, "\\%s", chDirName);
	%   Y_RESULT = new_string(chDirName);
        %   }
	%#else
	% char buff[66], *t;
	% t = getcwd (buff, 64);  
	% if (t)
	%   Y_RESULT = new_string(buff);
        %#endif
	% }
	END; -- INLINE
      END CurrentDir;
    	
    METHOD ChangeDir (Path : ARRAY OF CHAR) : BOOLEAN; 
      VAR
        i : INTEGER;
      BEGIN   
      INLINE
        % {
        %#ifdef OS2
        % APIRET rc = NO_ERROR;
	% rc = DosSetCurrentDir ((PSZ) Y_Path);
	% Y_i = (rc != NO_ERROR);
	%#else
	% Y_i = chdir ((char *) Y_Path);
        %#endif
	% }
        END; -- INLINE	
      RESULT := i = 0;	
      END ChangeDir;
      
    METHOD Delete (FName: ARRAY OF CHAR);
      BEGIN
      INLINE
        %#ifdef UNIX
        %  unlink((char *)Y_FName);
        %#else
        % (void) remove((char *) Y_FName);
        %#endif
        END;
      END Delete;

    METHOD Rename (From, To: ARRAY OF CHAR) : BOOLEAN;
      BEGIN
      INLINE
        %#ifdef UNIX
        %  Y_RESULT = link((char*) Y_From, (char *)Y_To) == 0;
        %  if (Y_RESULT)
        %    unlink((char*) Y_From);
        %#else
        % Y_RESULT = rename((char *) Y_From, (char *) Y_To) == 0;
        %#endif
        END;
      END Rename;                                     
      
    METHOD BuildInstant (Seconds: INTEGER): Instant;
      VAR
        Remains: INTEGER;    
        Days: INTEGER;
        TheDate: Date;
        TheTime: Time;
      BEGIN            
      Days := Seconds / (24 * 3600);
      TheDate.CREATE (1, 1, 70);
      TheDate.IncDate (Days);
      Remains := Seconds MOD (24 * 3600);
      TheTime.CREATE (0, 0, 0);
      TheTime.SetFromSeconds (Remains);
      RESULT.CREATE (TheDate, TheTime);
      END BuildInstant;
      
    METHOD GetEntry (FName: ARRAY OF CHAR): DirectoryEntry;
      VAR
        i,
        Size,
        LModif, 
        LAcc: INTEGER;
      BEGIN
      i := 1;     
      INLINE
        %{
        %#ifdef OS2
        %  /* If there is a better solution, let me know. M.Dehennin 15/08/96 */
        %
        %  FILESTATUS3  FileStatus      = {{0}};       /* File Info Buffer    */
        %  ULONG        BufSize = sizeof(FILESTATUS3); /* Buffer Size         */
        %  HFILE        FileHandle      = 0;           /* File handle         */
        %  ULONG        OpenAction      = 0;           /* for DosOpen         */
        %  struct tm    timestamp;
        %
        %  Y_i = DosOpen((PSZ) Y_FName,
        %                &FileHandle,
        %                &OpenAction,
        %                0L, 0L, /* Primary allocation and attributes ignored */
        %                OPEN_ACTION_FAIL_IF_NEW |
        %                OPEN_ACTION_OPEN_IF_EXISTS,    /* Existing file only */
        %                OPEN_FLAGS_NOINHERIT | OPEN_ACCESS_READONLY |
        %                OPEN_SHARE_DENYNONE,           /* Read access only   */
        %                0L);                /* Extended attributes (ignored) */
        %
        % if (Y_i == NO_ERROR) {
        %   Y_i = DosQueryFileInfo(FileHandle, FIL_STANDARD,
        %                          &FileStatus, BufSize);
        %   if (Y_i == NO_ERROR) {
        %     Y_Size = (yint) FileStatus.cbFile; /* File Data size */
        %
        %     timestamp.tm_wday = 0;   /* Unknown Day of the Week      */
        %     timestamp.tm_yday = 0;   /* Unknown Day of the Year      */
        %     timestamp.tm_isdst = -1; /* Unknown Daylight Saving Time */
        %
        %     timestamp.tm_sec = FileStatus.ftimeLastWrite.twosecs * 2;
        %     timestamp.tm_min = FileStatus.ftimeLastWrite.minutes;
        %     timestamp.tm_hour = FileStatus.ftimeLastWrite.hours;
        %     timestamp.tm_mday = FileStatus.fdateLastWrite.day;
        %     timestamp.tm_mon = FileStatus.fdateLastWrite.month - 1;
        %     timestamp.tm_year = FileStatus.fdateLastWrite.year + 80;
        %
        %     Y_LModif = (yint) mktime(&timestamp);
        %
        %     timestamp.tm_wday = 0;   /* Unknown Day of the Week      */
        %     timestamp.tm_yday = 0;   /* Unknown Day of the Year      */
        %     timestamp.tm_isdst = -1; /* Unknown Daylight Saving Time */
        %
        %     timestamp.tm_sec = FileStatus.ftimeLastAccess.twosecs * 2;
        %     timestamp.tm_min = FileStatus.ftimeLastAccess.minutes;
        %     timestamp.tm_hour = FileStatus.ftimeLastAccess.hours;
        %     timestamp.tm_mday = FileStatus.fdateLastAccess.day;
        %     timestamp.tm_mon = FileStatus.fdateLastAccess.month - 1;
        %     timestamp.tm_year = FileStatus.fdateLastAccess.year + 80;
        %
        %     Y_LAcc = (yint) mktime(&timestamp);
        %
        %     }
        %
        %   DosClose(FileHandle);
        %
        %   }
        %
        %#else
        %
        %#ifndef MVS
        %       
        %  struct stat Stat;
        %
        %  Y_i = stat(Y_FName, &Stat);
        %  if (Y_i == 0)
        %    {
        %    Y_Size = (yint) Stat.st_size;
        %    Y_LModif = (yint) Stat.st_mtime;
        %    Y_LAcc = (yint) Stat.st_atime;
        %    }
        %
        %#endif
        %
        %#endif
        %} 
        END;

      IF i = 0 THEN
        RESULT.CREATE;
        RESULT.SetName (FName);
        RESULT.SetSize (Size);
        RESULT.SetLastModification (BuildInstant (LModif));
        RESULT.SetLastAccess (BuildInstant(LAcc));
        END;
      END GetEntry;
      
    METHOD Exist (FName: ARRAY OF CHAR): BOOLEAN;
      VAR
        Input: InputStream;
      BEGIN
      IF SYSTEM.OperatingSystem = SYSTEM.Mvs THEN
        Input.CREATE;
        Input.Open (FName, Input.ReadAccess);
        IF Input.ErrorCode = Input.NoError THEN
          Input.Close;
          RESULT := TRUE;
          END;
       ELSE 
        RESULT := (GetEntry(FName) <> VOID);
        END; 
      END Exist;
      
  END Operations;

END Directories;
