home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 10 / Fresh_Fish_10_2352.bin / new / dev / obero / oberon-a / source / library / files.mod < prev    next >
Text File  |  1995-06-29  |  16KB  |  702 lines

  1. (*************************************************************************
  2.  
  3.      $RCSfile: Files.mod $
  4.   Description: Operations on files and the file directory.
  5.  
  6.    Created by: fjc (Frank Copeland)
  7.     $Revision: 1.13 $
  8.       $Author: fjc $
  9.         $Date: 1995/06/04 23:22:41 $
  10.  
  11.   Copyright © 1994-1995, Frank Copeland.
  12.   This file is part of the Oberon-A Library.
  13.   See Oberon-A.doc for conditions of use and distribution.
  14.  
  15. *************************************************************************)
  16.  
  17. <* STANDARD- *>
  18.  
  19. MODULE Files;
  20.  
  21. IMPORT
  22.   SYS := SYSTEM, Kernel, e := Exec, d := Dos, du := DosUtil,
  23.   str := Strings, conv := Conversions, oc := OberonClock;
  24.  
  25. CONST
  26.   SectorSize = 1024;
  27.   MaxBufs = 4;
  28.  
  29. TYPE
  30.  
  31.   File *= POINTER TO Handle;
  32.  
  33.   Buffer = POINTER TO BufferRecord;
  34.  
  35.   Rider *= RECORD
  36.     eof -: BOOLEAN;
  37.     res -: LONGINT;
  38.     file : File;
  39.     pos : LONGINT;
  40.     buf : Buffer;
  41.     bpos : INTEGER;
  42.   END; (* Rider *)
  43.  
  44.   Handle = RECORD
  45.     fl -: d.FileLockPtr;
  46.     fh -: d.FileHandlePtr;
  47.     name : ARRAY 256 OF CHAR;
  48.     tempNo : LONGINT;
  49.     pos, len : LONGINT;
  50.     nofbufs : INTEGER;
  51.     next : File;
  52.     firstbuf : Buffer;
  53.   END; (* Handle *)
  54.  
  55.   DataSector = ARRAY SectorSize OF SYS.BYTE;
  56.  
  57.   BufferRecord = RECORD
  58.     apos : LONGINT;
  59.     lim : INTEGER;
  60.     mod : BOOLEAN;
  61.     next : Buffer;
  62.     data : DataSector;
  63.   END; (* BufferRecord *)
  64.  
  65.  
  66. VAR
  67.   root : File;
  68.   tempNo : LONGINT;
  69.  
  70. CONST
  71.   tempExt = ".tmp";
  72.   bkpExt = ".bkp";
  73.  
  74.  
  75. PROCEDURE GetTempNo;
  76.  
  77.   VAR time, date : LONGINT;
  78.  
  79. BEGIN (* GetTempNo *)
  80.   oc.GetClock (time, date);
  81.   tempNo := ABS ((date * 10000H + time) DIV 2)
  82. END GetTempNo;
  83.  
  84.  
  85. PROCEDURE MakeName
  86.   ( name : ARRAY OF CHAR;
  87.     tempNo : LONGINT;
  88.     ext : ARRAY OF CHAR;
  89.     VAR tempName : ARRAY OF CHAR );
  90.  
  91.   VAR pathPart : e.LSTRPTR; s : ARRAY 13 OF CHAR;
  92.  
  93. <*$CopyArrays-*>
  94. BEGIN (* MakeName *)
  95.   COPY (name, tempName);
  96.   IF tempName # "" THEN
  97.     pathPart := d.PathPart (tempName); pathPart [0] := 0X
  98.   END;
  99.   ASSERT (conv.IntToStr (tempNo, 16, 0, "0", s));
  100.   str.Append (ext, s);
  101.   ASSERT (d.AddPart (tempName, s, LEN (tempName)))
  102. END MakeName;
  103.  
  104.  
  105. PROCEDURE Search ( fl : d.FileLockPtr ) : File;
  106.  
  107.   VAR f : File;
  108.  
  109. BEGIN (* Search *)
  110.   f := root;
  111.   WHILE (f # NIL) & (d.SameLock (fl, f.fl) # d.same) DO f := f.next END;
  112.   RETURN f
  113. END Search;
  114.  
  115.  
  116. PROCEDURE Unlink (f : File);
  117.  
  118.   VAR f0 : File;
  119.  
  120. BEGIN (* Unlink *)
  121.   IF root # NIL THEN
  122.     IF f = root THEN
  123.       root := root.next
  124.     ELSE
  125.       f0 := root;
  126.       WHILE (f0.next # NIL) & (f0.next # f) DO
  127.         f0 := f0.next
  128.       END;
  129.       IF f0.next = f THEN f0.next := f.next END;
  130.     END
  131.   END;
  132.   f.next := NIL
  133. END Unlink;
  134.  
  135.  
  136. PROCEDURE ReadBuf (f : File; buf : Buffer; pos : LONGINT);
  137.  
  138.   VAR res : LONGINT;
  139.  
  140. BEGIN (* ReadBuf *)
  141.   res := d.Seek (f.fh, pos, d.beginning);
  142.   IF res # -1 THEN
  143.     buf.lim := SHORT (d.Read (f^.fh, buf.data, SectorSize));
  144.     buf.apos := pos;
  145.     buf.mod := FALSE;
  146.   END
  147. END ReadBuf;
  148.  
  149.  
  150. PROCEDURE WriteBuf (f : File; buf : Buffer);
  151.  
  152.   VAR res : LONGINT;
  153.  
  154. BEGIN (* WriteBuf *)
  155.   res := d.Seek (f.fh, buf.apos, d.beginning);
  156.   IF res # -1 THEN
  157.     res := d.Write (f.fh, buf.data, buf.lim);
  158.     IF res = buf.lim THEN
  159.       buf.mod := FALSE;
  160.     END
  161.   END
  162. END WriteBuf;
  163.  
  164.  
  165. PROCEDURE GetBuf (f : File; pos : LONGINT) : Buffer;
  166.  
  167.   VAR buf, last, next : Buffer;
  168.  
  169. BEGIN (* GetBuf *)
  170.   buf := f.firstbuf;
  171.   LOOP
  172.     IF buf.apos = pos THEN EXIT END;
  173.     IF buf.next = f.firstbuf THEN
  174.       last := buf;
  175.       IF f.nofbufs < MaxBufs THEN (* allocate new buffer *)
  176.         NEW (buf); INC (f.nofbufs);
  177.       ELSE (* take one of the buffers (assuming more than one) *)
  178.         buf := f.firstbuf; f.firstbuf := buf.next; last.next := buf.next;
  179.         IF buf.mod THEN WriteBuf (f, buf) END
  180.       END;
  181.       IF pos < f.firstbuf.apos THEN
  182.         f.firstbuf := buf
  183.       ELSIF pos < last.apos THEN
  184.         WHILE last.next.apos < pos DO last := last.next END;
  185.       END;
  186.       buf.next := last.next; last.next := buf;
  187.       buf.apos := pos; buf.lim := 0; buf.mod := FALSE;
  188.       IF pos < f.len THEN ReadBuf (f, buf, pos) END;
  189.       EXIT
  190.     END;
  191.     buf := buf.next
  192.   END; (* LOOP *)
  193.   RETURN buf;
  194. END GetBuf;
  195.  
  196.  
  197. PROCEDURE Unbuffer (f : File);
  198.  
  199.   VAR buf : Buffer;
  200.  
  201. BEGIN (* Unbuffer *)
  202.   buf := f.firstbuf;
  203.   REPEAT
  204.     IF buf.mod THEN WriteBuf (f, buf) END;
  205.     buf := buf.next
  206.   UNTIL buf = f.firstbuf
  207. END Unbuffer;
  208.  
  209.  
  210. PROCEDURE Delete * ( name : ARRAY OF CHAR; VAR res : INTEGER );
  211. <*$CopyArrays-*>
  212. BEGIN (* Delete *)
  213.   IF d.DeleteFile (name) THEN
  214.     res := 0
  215.   ELSE
  216.     res := SHORT (d.IoErr ());
  217.     IF res = d.objectNotFound THEN res := 0 END
  218.   END
  219. END Delete;
  220.  
  221.  
  222. PROCEDURE Rename * ( old, new : ARRAY OF CHAR; VAR res : INTEGER );
  223. <*$CopyArrays-*>
  224. BEGIN (* Rename *)
  225.   IF d.Rename (old, new) THEN res := 0
  226.   ELSE res := SHORT (d.IoErr ())
  227.   END
  228. END Rename;
  229.  
  230.  
  231. PROCEDURE Old * ( name : ARRAY OF CHAR ) : File;
  232.  
  233.   VAR
  234.     f : File; fl : d.FileLockPtr; fh : d.FileHandlePtr;
  235.     fib : d.FileInfoBlockPtr; len : LONGINT; buf : Buffer;
  236.  
  237. <*$CopyArrays-*>
  238. BEGIN (* Old *)
  239.   fl := d.Lock (name, d.sharedLock);
  240.   IF fl # NIL THEN
  241.     f := Search (fl);
  242.     IF f = NIL THEN
  243.       fh := d.Open (name, d.oldFile);
  244.       IF fh # NIL THEN
  245.         fib := d.AllocDosObjectTags (d.fib, NIL);
  246.         IF fib # NIL THEN
  247.           IF d.Examine (fl, fib^) THEN len := fib.size;
  248.           ELSE len := 0
  249.           END;
  250.           d.FreeDosObject (d.fib, fib);
  251.           NEW (f);
  252.           IF f # NIL THEN
  253.             NEW (buf);
  254.             IF buf # NIL THEN
  255.               buf.apos := 0; buf.next := buf; buf.mod := FALSE;
  256.               IF len > SectorSize THEN buf.lim := SectorSize
  257.               ELSE buf.lim := SHORT (len)
  258.               END;
  259.               f.len := len; f.firstbuf := buf; f.nofbufs := 1;
  260.               COPY (name, f.name); f.tempNo := 0;
  261.               f.fl := fl; f.fh := fh; f.pos := 0;
  262.               f.next := root; root := f;
  263.               ReadBuf (f, buf, 0);
  264.               RETURN f
  265.             END;
  266.           END;
  267.         END;
  268.       END;
  269.       d.OldClose (fh)
  270.     END;
  271.     d.UnLock (fl)
  272.   END;
  273.   RETURN f
  274. END Old;
  275.  
  276.  
  277. PROCEDURE New * ( name : ARRAY OF CHAR ) : File;
  278.  
  279.   VAR
  280.     f : File; fl : d.FileLockPtr; fh : d.FileHandlePtr;
  281.     buf : Buffer; tempName : ARRAY 256 OF CHAR;
  282.  
  283. <*$CopyArrays-*>
  284. BEGIN (* New *)
  285.   REPEAT
  286.     IF tempNo < MAX (LONGINT) THEN INC (tempNo) ELSE tempNo := 1 END;
  287.     MakeName (name, tempNo, tempExt, tempName)
  288.   UNTIL ~du.FileExists (tempName);
  289.   fh := d.Open (tempName, d.newFile);
  290.   IF fh # NIL THEN
  291.     NEW (f);
  292.     IF f # NIL THEN
  293.       NEW (buf);
  294.       IF buf # NIL THEN
  295.         buf.apos := 0; buf.next := buf; buf.mod := TRUE;
  296.         buf.lim := 0;
  297.         f.len := 0; f.firstbuf := buf; f.nofbufs := 1;
  298.         COPY (name, f.name); f.tempNo := tempNo;
  299.         f.fl := d.Lock (tempName, d.sharedLock); f.fh := fh; f.pos := 0;
  300.         f.next := root; root := f;
  301.         ReadBuf (f, buf, 0);
  302.         RETURN f
  303.       END
  304.     END
  305.   END;
  306.   d.OldClose (fh);
  307.   RETURN f
  308. END New;
  309.  
  310.  
  311. PROCEDURE Register * ( f : File );
  312.  
  313.   VAR tempName, bkpName : ARRAY 256 OF CHAR; res : INTEGER;
  314.  
  315. BEGIN (* Register *)
  316.   ASSERT (f # NIL, 97);
  317.   IF f.fh # NIL THEN
  318.     Unbuffer (f); Unlink (f);
  319.     IF d.Close (f.fh) THEN
  320.       f.fh := NIL; d.UnLock (f.fl); f.fl := NIL;
  321.       IF f.tempNo # 0 THEN
  322.         MakeName (f.name, f.tempNo, tempExt, tempName);
  323.         IF f.name = "" THEN
  324.           Delete (tempName, res);
  325.         ELSE
  326.           MakeName (f.name, f.tempNo, bkpExt, bkpName);
  327.           Rename (f.name, bkpName, res);
  328.           IF res = 0 THEN
  329.             Rename (tempName, f.name, res);
  330.             IF res = 0 THEN Delete (bkpName, res) END
  331.           ELSIF res = d.objectNotFound THEN
  332.             Rename (tempName, f.name, res);
  333.           END
  334.         END
  335.       END
  336.     END
  337.   END
  338. END Register;
  339.  
  340.  
  341. PROCEDURE Close * ( f : File );
  342. BEGIN (* Close *)
  343.   ASSERT (f # NIL, 97);
  344.   IF f.fh # NIL THEN
  345.     Unbuffer (f); Unlink (f);
  346.     IF d.Close (f.fh) THEN f.fh := NIL; d.UnLock (f.fl); f.fl := NIL END
  347.   END
  348. END Close;
  349.  
  350.  
  351. PROCEDURE Purge * ( f : File );
  352.  
  353.   VAR tempName : ARRAY 256 OF CHAR; res : INTEGER;
  354.  
  355. BEGIN (* Purge *)
  356.   ASSERT (f # NIL, 97);
  357.   IF f.fh # NIL THEN
  358.     Unbuffer (f); Unlink (f);
  359.     IF d.Close (f.fh) THEN f.fh := NIL; d.UnLock (f.fl); f.fl := NIL END;
  360.     IF f.tempNo # 0