Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. (*
  2.     BSD 2-Clause License
  3.  
  4.     Copyright (c) 2018, Anton Krotov
  5.     All rights reserved.
  6. *)
  7.  
  8. MODULE FILES;
  9.  
  10. IMPORT UTILS, C := COLLECTIONS, CONSOLE;
  11.  
  12.  
  13. TYPE
  14.  
  15.     FILE* = POINTER TO RECORD (C.ITEM)
  16.  
  17.         ptr: INTEGER;
  18.  
  19.         buffer: ARRAY 64*1024 OF BYTE;
  20.         count:  INTEGER
  21.  
  22.     END;
  23.  
  24. VAR
  25.  
  26.     files: C.COLLECTION;
  27.  
  28.  
  29. PROCEDURE copy (src: ARRAY OF BYTE; src_idx: INTEGER; VAR dst: ARRAY OF BYTE; dst_idx: INTEGER; bytes: INTEGER);
  30. BEGIN
  31.     WHILE bytes > 0 DO
  32.         dst[dst_idx] := src[src_idx];
  33.         INC(dst_idx);
  34.         INC(src_idx);
  35.         DEC(bytes)
  36.     END
  37. END copy;
  38.  
  39.  
  40. PROCEDURE flush (file: FILE): INTEGER;
  41. VAR
  42.     res: INTEGER;
  43.  
  44. BEGIN
  45.     IF file # NIL THEN
  46.         res := UTILS.FileWrite(file.ptr, file.buffer, file.count);
  47.         IF res < 0 THEN
  48.             res := 0
  49.         END
  50.     ELSE
  51.         res := 0
  52.     END
  53.  
  54.     RETURN res
  55. END flush;
  56.  
  57.  
  58. PROCEDURE NewFile (): FILE;
  59. VAR
  60.     file:  FILE;
  61.     citem: C.ITEM;
  62.  
  63. BEGIN
  64.     citem := C.pop(files);
  65.     IF citem = NIL THEN
  66.         NEW(file)
  67.     ELSE
  68.         file := citem(FILE)
  69.     END
  70.  
  71.     RETURN file
  72. END NewFile;
  73.  
  74.  
  75. PROCEDURE create* (name: ARRAY OF CHAR): FILE;
  76. VAR
  77.     file: FILE;
  78.     ptr:  INTEGER;
  79.  
  80. BEGIN
  81.     ptr := UTILS.FileCreate(name);
  82.  
  83.     IF ptr > 0 THEN
  84.         file := NewFile();
  85.         file.ptr := ptr;
  86.         file.count := 0
  87.     ELSE
  88.         file := NIL
  89.     END
  90.  
  91.     RETURN file
  92. END create;
  93.  
  94.  
  95. PROCEDURE open* (name: ARRAY OF CHAR): FILE;
  96. VAR
  97.     file: FILE;
  98.     ptr:  INTEGER;
  99.  
  100. BEGIN
  101.     ptr := UTILS.FileOpen(name);
  102.  
  103.     IF ptr > 0 THEN
  104.         file := NewFile();
  105.         file.ptr := ptr;
  106.         file.count := -1
  107.     ELSE
  108.         file := NIL
  109.     END
  110.  
  111.     RETURN file
  112. END open;
  113.  
  114.  
  115. PROCEDURE close* (VAR file: FILE);
  116. VAR
  117.     n: INTEGER;
  118.  
  119. BEGIN
  120.     IF file # NIL THEN
  121.  
  122.         IF file.count > 0 THEN
  123.             n := flush(file)
  124.         END;
  125.  
  126.         file.count := -1;
  127.  
  128.         UTILS.FileClose(file.ptr);
  129.         file.ptr := 0;
  130.  
  131.         C.push(files, file);
  132.         file := NIL
  133.     END
  134. END close;
  135.  
  136.  
  137. PROCEDURE read* (file: FILE; VAR chunk: ARRAY OF BYTE; bytes: INTEGER): INTEGER;
  138. VAR
  139.     res: INTEGER;
  140.  
  141. BEGIN
  142.     IF file # NIL THEN
  143.         res := UTILS.FileRead(file.ptr, chunk, MAX(MIN(bytes, LEN(chunk)), 0));
  144.         IF res < 0 THEN
  145.             res := 0
  146.         END
  147.     ELSE
  148.         res := 0
  149.     END
  150.  
  151.     RETURN res
  152. END read;
  153.  
  154.  
  155. PROCEDURE write* (file: FILE; chunk: ARRAY OF BYTE; bytes: INTEGER): INTEGER;
  156. VAR
  157.     free, n, k, res, idx: INTEGER;
  158.  
  159. BEGIN
  160.     idx := 0;
  161.     res := 0;
  162.     IF (file # NIL) & (file.count >= 0) THEN
  163.  
  164.         free := LEN(file.buffer) - file.count;
  165.         WHILE bytes > 0 DO
  166.             n := MIN(free, bytes);
  167.             copy(chunk, idx, file.buffer, file.count, n);
  168.             INC(res, n);
  169.             DEC(free, n);
  170.             DEC(bytes, n);
  171.             INC(idx, n);
  172.             INC(file.count, n);
  173.             IF free = 0 THEN
  174.                 k := flush(file);
  175.                 IF k # LEN(file.buffer) THEN
  176.                     bytes := 0;
  177.                     DEC(res, n)
  178.                 ELSE
  179.                     file.count := 0;
  180.                     free := LEN(file.buffer)
  181.                 END
  182.             END
  183.         END
  184.  
  185.     END
  186.  
  187.     RETURN res
  188. END write;
  189.  
  190.  
  191. PROCEDURE WriteByte* (file: FILE; byte: BYTE): BOOLEAN;
  192. VAR
  193.     res: BOOLEAN;
  194.  
  195. BEGIN
  196.     res := TRUE;
  197.     IF (file # NIL) & (file.count >= 0) THEN
  198.         IF file.count = LEN(file.buffer) THEN
  199.             IF flush(file) # LEN(file.buffer) THEN
  200.                 res := FALSE
  201.             ELSE
  202.                 file.buffer[0] := byte;
  203.                 file.count := 1
  204.             END
  205.         ELSE
  206.             file.buffer[file.count] := byte;
  207.             INC(file.count)
  208.         END
  209.     ELSE
  210.         res := FALSE
  211.     END
  212.  
  213.     RETURN res
  214. END WriteByte;
  215.  
  216.  
  217. BEGIN
  218.     files := C.create()
  219. END FILES.