2019-03-11 09:59:55 +01:00
|
|
|
(*
|
|
|
|
BSD 2-Clause License
|
|
|
|
|
2019-09-26 22:23:06 +02:00
|
|
|
Copyright (c) 2018, 2019, Anton Krotov
|
2019-03-11 09:59:55 +01:00
|
|
|
All rights reserved.
|
|
|
|
*)
|
|
|
|
|
|
|
|
MODULE FILES;
|
|
|
|
|
|
|
|
IMPORT UTILS, C := COLLECTIONS, CONSOLE;
|
|
|
|
|
|
|
|
|
|
|
|
TYPE
|
|
|
|
|
|
|
|
FILE* = POINTER TO RECORD (C.ITEM)
|
|
|
|
|
|
|
|
ptr: INTEGER;
|
|
|
|
|
|
|
|
buffer: ARRAY 64*1024 OF BYTE;
|
|
|
|
count: INTEGER
|
|
|
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
VAR
|
|
|
|
|
|
|
|
files: C.COLLECTION;
|
|
|
|
|
|
|
|
|
|
|
|
PROCEDURE copy (src: ARRAY OF BYTE; src_idx: INTEGER; VAR dst: ARRAY OF BYTE; dst_idx: INTEGER; bytes: INTEGER);
|
|
|
|
BEGIN
|
|
|
|
WHILE bytes > 0 DO
|
|
|
|
dst[dst_idx] := src[src_idx];
|
|
|
|
INC(dst_idx);
|
|
|
|
INC(src_idx);
|
|
|
|
DEC(bytes)
|
|
|
|
END
|
|
|
|
END copy;
|
|
|
|
|
|
|
|
|
|
|
|
PROCEDURE flush (file: FILE): INTEGER;
|
|
|
|
VAR
|
|
|
|
res: INTEGER;
|
|
|
|
|
|
|
|
BEGIN
|
|
|
|
IF file # NIL THEN
|
|
|
|
res := UTILS.FileWrite(file.ptr, file.buffer, file.count);
|
|
|
|
IF res < 0 THEN
|
|
|
|
res := 0
|
|
|
|
END
|
|
|
|
ELSE
|
|
|
|
res := 0
|
|
|
|
END
|
|
|
|
|
|
|
|
RETURN res
|
|
|
|
END flush;
|
|
|
|
|
|
|
|
|
|
|
|
PROCEDURE NewFile (): FILE;
|
|
|
|
VAR
|
|
|
|
file: FILE;
|
|
|
|
citem: C.ITEM;
|
|
|
|
|
|
|
|
BEGIN
|
|
|
|
citem := C.pop(files);
|
|
|
|
IF citem = NIL THEN
|
|
|
|
NEW(file)
|
|
|
|
ELSE
|
|
|
|
file := citem(FILE)
|
|
|
|
END
|
|
|
|
|
|
|
|
RETURN file
|
|
|
|
END NewFile;
|
|
|
|
|
|
|
|
|
|
|
|
PROCEDURE create* (name: ARRAY OF CHAR): FILE;
|
|
|
|
VAR
|
|
|
|
file: FILE;
|
|
|
|
ptr: INTEGER;
|
|
|
|
|
|
|
|
BEGIN
|
|
|
|
ptr := UTILS.FileCreate(name);
|
|
|
|
|
|
|
|
IF ptr > 0 THEN
|
|
|
|
file := NewFile();
|
|
|
|
file.ptr := ptr;
|
|
|
|
file.count := 0
|
|
|
|
ELSE
|
|
|
|
file := NIL
|
|
|
|
END
|
|
|
|
|
|
|
|
RETURN file
|
|
|
|
END create;
|
|
|
|
|
|
|
|
|
|
|
|
PROCEDURE open* (name: ARRAY OF CHAR): FILE;
|
|
|
|
VAR
|
|
|
|
file: FILE;
|
|
|
|
ptr: INTEGER;
|
|
|
|
|
|
|
|
BEGIN
|
|
|
|
ptr := UTILS.FileOpen(name);
|
|
|
|
|
|
|
|
IF ptr > 0 THEN
|
|
|
|
file := NewFile();
|
|
|
|
file.ptr := ptr;
|
|
|
|
file.count := -1
|
|
|
|
ELSE
|
|
|
|
file := NIL
|
|
|
|
END
|
|
|
|
|
|
|
|
RETURN file
|
|
|
|
END open;
|
|
|
|
|
|
|
|
|
|
|
|
PROCEDURE close* (VAR file: FILE);
|
|
|
|
VAR
|
|
|
|
n: INTEGER;
|
|
|
|
|
|
|
|
BEGIN
|
|
|
|
IF file # NIL THEN
|
|
|
|
|
|
|
|
IF file.count > 0 THEN
|
|
|
|
n := flush(file)
|
|
|
|
END;
|
|
|
|
|
|
|
|
file.count := -1;
|
|
|
|
|
|
|
|
UTILS.FileClose(file.ptr);
|
|
|
|
file.ptr := 0;
|
|
|
|
|
|
|
|
C.push(files, file);
|
|
|
|
file := NIL
|
|
|
|
END
|
|
|
|
END close;
|
|
|
|
|
|
|
|
|
|
|
|
PROCEDURE read* (file: FILE; VAR chunk: ARRAY OF BYTE; bytes: INTEGER): INTEGER;
|
|
|
|
VAR
|
|
|
|
res: INTEGER;
|
|
|
|
|
|
|
|
BEGIN
|
|
|
|
IF file # NIL THEN
|
|
|
|
res := UTILS.FileRead(file.ptr, chunk, MAX(MIN(bytes, LEN(chunk)), 0));
|
|
|
|
IF res < 0 THEN
|
|
|
|
res := 0
|
|
|
|
END
|
|
|
|
ELSE
|
|
|
|
res := 0
|
|
|
|
END
|
|
|
|
|
|
|
|
RETURN res
|
|
|
|
END read;
|
|
|
|
|
|
|
|
|
|
|
|
PROCEDURE write* (file: FILE; chunk: ARRAY OF BYTE; bytes: INTEGER): INTEGER;
|
|
|
|
VAR
|
|
|
|
free, n, k, res, idx: INTEGER;
|
|
|
|
|
|
|
|
BEGIN
|
|
|
|
idx := 0;
|
|
|
|
res := 0;
|
|
|
|
IF (file # NIL) & (file.count >= 0) THEN
|
|
|
|
|
|
|
|
free := LEN(file.buffer) - file.count;
|
|
|
|
WHILE bytes > 0 DO
|
|
|
|
n := MIN(free, bytes);
|
|
|
|
copy(chunk, idx, file.buffer, file.count, n);
|
|
|
|
INC(res, n);
|
|
|
|
DEC(free, n);
|
|
|
|
DEC(bytes, n);
|
|
|
|
INC(idx, n);
|
|
|
|
INC(file.count, n);
|
|
|
|
IF free = 0 THEN
|
|
|
|
k := flush(file);
|
|
|
|
IF k # LEN(file.buffer) THEN
|
|
|
|
bytes := 0;
|
|
|
|
DEC(res, n)
|
|
|
|
ELSE
|
|
|
|
file.count := 0;
|
|
|
|
free := LEN(file.buffer)
|
|
|
|
END
|
|
|
|
END
|
|
|
|
END
|
|
|
|
|
|
|
|
END
|
|
|
|
|
|
|
|
RETURN res
|
|
|
|
END write;
|
|
|
|
|
|
|
|
|
|
|
|
PROCEDURE WriteByte* (file: FILE; byte: BYTE): BOOLEAN;
|
|
|
|
VAR
|
|
|
|
res: BOOLEAN;
|
|
|
|
|
|
|
|
BEGIN
|
|
|
|
res := TRUE;
|
|
|
|
IF (file # NIL) & (file.count >= 0) THEN
|
|
|
|
IF file.count = LEN(file.buffer) THEN
|
|
|
|
IF flush(file) # LEN(file.buffer) THEN
|
|
|
|
res := FALSE
|
|
|
|
ELSE
|
|
|
|
file.buffer[0] := byte;
|
|
|
|
file.count := 1
|
|
|
|
END
|
|
|
|
ELSE
|
|
|
|
file.buffer[file.count] := byte;
|
|
|
|
INC(file.count)
|
|
|
|
END
|
|
|
|
ELSE
|
|
|
|
res := FALSE
|
|
|
|
END
|
|
|
|
|
|
|
|
RETURN res
|
|
|
|
END WriteByte;
|
|
|
|
|
|
|
|
|
|
|
|
BEGIN
|
|
|
|
files := C.create()
|
|
|
|
END FILES.
|