0,0 → 1,219 |
(* |
BSD 2-Clause License |
|
Copyright (c) 2018, Anton Krotov |
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. |