(*
    Copyright 2016 Anton Krotov

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    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.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*)

MODULE File;

IMPORT sys := SYSTEM, KOSAPI;

CONST

  SEEK_BEG* = 0; SEEK_CUR* = 1; SEEK_END* = 2;

TYPE

  FNAME* = ARRAY 520 OF CHAR;

  FS* = POINTER TO rFS;

  rFS* = RECORD
    subfunc*, pos*, hpos*, bytes*, buffer*: INTEGER;
    name*: FNAME
  END;

  FD* = POINTER TO rFD;

  rFD* = RECORD
    attr*: INTEGER;
    ntyp*: CHAR;
    reserved: ARRAY 3 OF CHAR;
    time_create*, date_create*,
    time_access*, date_access*,
    time_modif*,  date_modif*,
    size*, hsize*: INTEGER;
    name*: FNAME
  END;

PROCEDURE [stdcall] f_68_27(file_name: INTEGER; VAR size: INTEGER): INTEGER;
BEGIN
  sys.CODE("53");               (* push    ebx              *)
  sys.CODE("6A44");             (* push    68               *)
  sys.CODE("58");               (* pop     eax              *)
  sys.CODE("6A1B");             (* push    27               *)
  sys.CODE("5B");               (* pop     ebx              *)
  sys.CODE("8B4D08");           (* mov     ecx, [ebp + 08h] *)
  sys.CODE("CD40");             (* int     40h              *)
  sys.CODE("8B4D0C");           (* mov     ecx, [ebp + 0Ch] *)
  sys.CODE("8911");             (* mov     [ecx], edx       *)
  sys.CODE("5B");               (* pop     ebx              *)
  sys.CODE("C9");               (* leave                    *)
  sys.CODE("C20800");           (* ret     08h              *)
  RETURN 0
END f_68_27;

PROCEDURE Load*(FName: ARRAY OF CHAR; VAR size: INTEGER): INTEGER;
  RETURN f_68_27(sys.ADR(FName[0]), size)
END Load;

PROCEDURE GetFileInfo*(FName: ARRAY OF CHAR; VAR Info: rFD): BOOLEAN;
VAR res2: INTEGER; fs: rFS;
BEGIN
  fs.subfunc := 5;
  fs.pos := 0;
  fs.hpos := 0;
  fs.bytes := 0;
  fs.buffer := sys.ADR(Info);
  COPY(FName, fs.name)
  RETURN KOSAPI.sysfunc22(70, sys.ADR(fs), res2) = 0
END GetFileInfo;

PROCEDURE Exists*(FName: ARRAY OF CHAR): BOOLEAN;
VAR fd: rFD;
BEGIN
  RETURN GetFileInfo(FName, fd) & ~(4 IN BITS(fd.attr))
END Exists;

PROCEDURE Close*(VAR F: FS);
BEGIN
  IF F # NIL THEN
    DISPOSE(F)
  END
END Close;

PROCEDURE Open*(FName: ARRAY OF CHAR): FS;
VAR F: FS;
BEGIN
  IF Exists(FName) THEN
    NEW(F);
    IF F # NIL THEN
      F.subfunc := 0;
      F.pos := 0;
      F.hpos := 0;
      F.bytes := 0;
      F.buffer := 0;
      COPY(FName, F.name)
    END
  ELSE
    F := NIL
  END
  RETURN F
END Open;

PROCEDURE Delete*(FName: ARRAY OF CHAR): BOOLEAN;
VAR F: FS; res, res2: INTEGER;
BEGIN
  IF Exists(FName) THEN
    NEW(F);
    IF F # NIL THEN
      F.subfunc := 8;
      F.pos := 0;
      F.hpos := 0;
      F.bytes := 0;
      F.buffer := 0;
      COPY(FName, F.name);
      res := KOSAPI.sysfunc22(70, sys.ADR(F^), res2);
      DISPOSE(F)
    ELSE
      res := -1
    END
  ELSE
    res := -1
  END
  RETURN res = 0
END Delete;

PROCEDURE Seek*(F: FS; Offset, Origin: INTEGER): INTEGER;
VAR res: INTEGER; fd: rFD;
BEGIN
  IF (F # NIL) & GetFileInfo(F.name, fd) & (BITS(fd.attr) * {4} = {}) THEN
    CASE Origin OF
    |SEEK_BEG: F.pos := Offset
    |SEEK_CUR: F.pos := F.pos + Offset
    |SEEK_END: F.pos := fd.size + Offset
    ELSE
    END;
    res := F.pos
  ELSE
    res := -1
  END
  RETURN res
END Seek;

PROCEDURE Read*(F: FS; Buffer, Count: INTEGER): INTEGER;
VAR res, res2: INTEGER;
BEGIN
  IF F # NIL THEN
    F.subfunc := 0;
    F.bytes := Count;
    F.buffer := Buffer;
    res := KOSAPI.sysfunc22(70, sys.ADR(F^), res2);
    IF res2 > 0 THEN
      F.pos := F.pos + res2
    END
  ELSE
    res2 := 0
  END
  RETURN res2
END Read;

PROCEDURE Write*(F: FS; Buffer, Count: INTEGER): INTEGER;
VAR res, res2: INTEGER;
BEGIN
  IF F # NIL THEN
    F.subfunc := 3;
    F.bytes := Count;
    F.buffer := Buffer;
    res := KOSAPI.sysfunc22(70, sys.ADR(F^), res2);
    IF res2 > 0 THEN
      F.pos := F.pos + res2
    END
  ELSE
    res2 := 0
  END
  RETURN res2
END Write;

PROCEDURE Create*(FName: ARRAY OF CHAR): FS;
VAR F: FS; res2: INTEGER;
BEGIN
  NEW(F);
  IF F # NIL THEN
    F.subfunc := 2;
    F.pos := 0;
    F.hpos := 0;
    F.bytes := 0;
    F.buffer := 0;
    COPY(FName, F.name);
    IF KOSAPI.sysfunc22(70, sys.ADR(F^), res2) # 0 THEN
      DISPOSE(F)
    END
  END
  RETURN F
END Create;

PROCEDURE DirExists*(FName: ARRAY OF CHAR): BOOLEAN;
VAR fd: rFD;
BEGIN
  RETURN GetFileInfo(FName, fd) & (4 IN BITS(fd.attr))
END DirExists;

PROCEDURE CreateDir*(DirName: ARRAY OF CHAR): BOOLEAN;
VAR F: FS; res, res2: INTEGER;
BEGIN
  NEW(F);
  IF F # NIL THEN
    F.subfunc := 9;
    F.pos := 0;
    F.hpos := 0;
    F.bytes := 0;
    F.buffer := 0;
    COPY(DirName, F.name);
    res := KOSAPI.sysfunc22(70, sys.ADR(F^), res2);
    DISPOSE(F)
  ELSE
    res := -1
  END
  RETURN res = 0
END CreateDir;

PROCEDURE DeleteDir*(DirName: ARRAY OF CHAR): BOOLEAN;
VAR F: FS; res, res2: INTEGER;
BEGIN
  IF DirExists(DirName) THEN
    NEW(F);
    IF F # NIL THEN
      F.subfunc := 8;
      F.pos := 0;
      F.hpos := 0;
      F.bytes := 0;
      F.buffer := 0;
      COPY(DirName, F.name);
      res := KOSAPI.sysfunc22(70, sys.ADR(F^), res2);
      DISPOSE(F)
    ELSE
      res := -1
    END
  ELSE
    res := -1
  END
  RETURN res = 0
END DeleteDir;

END File.