home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 9 / FreshFishVol9-CD1.bin / useful / dev / obero / oberon-a / source / library / files.mod < prev    next >
Encoding:
Text File  |  1995-02-07  |  15.6 KB  |  703 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.12 $
  8.       $Author: fjc $
  9.         $Date: 1995/02/07 20:20:42 $
  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- *> <* MAIN- *>
  18. <*$ LongVars+ *> <*$ NilChk- *> <*$ IndexChk- *>
  19.  
  20. MODULE Files;
  21.  
  22. IMPORT
  23.   SYS := SYSTEM, Kernel, e := Exec, d := Dos, du := DosUtil,
  24.   str := Strings, conv := Conversions, oc := OberonClock;
  25.  
  26. CONST
  27.   SectorSize = 1024;
  28.   MaxBufs = 4;
  29.  
  30. TYPE
  31.  
  32.   File *= POINTER TO Handle;
  33.  
  34.   Buffer = POINTER TO BufferRecord;
  35.  
  36.   Rider *= RECORD
  37.     eof -: BOOLEAN;
  38.     res -: LONGINT;
  39.     file : File;
  40.     pos : LONGINT;
  41.     buf : Buffer;
  42.     bpos : INTEGER;
  43.   END; (* Rider *)
  44.  
  45.   Handle = RECORD
  46.     fl -: d.FileLockPtr;
  47.     fh -: d.FileHandlePtr;
  48.     name : ARRAY 256 OF CHAR;
  49.     tempNo : LONGINT;
  50.     pos, len : LONGINT;
  51.     nofbufs : INTEGER;
  52.     next : File;
  53.     firstbuf : Buffer;
  54.   END; (* Handle *)
  55.  
  56.   DataSector = ARRAY SectorSize OF SYS.BYTE;
  57.  
  58.   BufferRecord = RECORD
  59.     apos : LONGINT;
  60.     lim : INTEGER;
  61.     mod : BOOLEAN;
  62.     next : Buffer;
  63.     data : DataSector;
  64.   END; (* BufferRecord *)
  65.  
  66.  
  67. VAR
  68.   root : File;
  69.   tempNo : LONGINT;
  70.  
  71. CONST
  72.   tempExt = ".tmp";
  73.   bkpExt = ".bkp";
  74.  
  75.  
  76. PROCEDURE GetTempNo;
  77.  
  78.   VAR time, date : LONGINT;
  79.  
  80. BEGIN (* GetTempNo *)
  81.   oc.GetClock (time, date);
  82.   tempNo := ABS ((date * 10000H + time) DIV 2)
  83. END GetTempNo;
  84.  
  85.  
  86. PROCEDURE MakeName
  87.   ( name : ARRAY OF CHAR;
  88.     tempNo : LONGINT;
  89.     ext : ARRAY OF CHAR;
  90.     VAR tempName : ARRAY OF CHAR );
  91.  
  92.   VAR pathPart : e.LSTRPTR; s : ARRAY 13 OF CHAR;
  93.  
  94. <*$CopyArrays-*>
  95. BEGIN (* MakeName *)
  96.   COPY (name, tempName);
  97.   IF tempName # "" THEN
  98.     pathPart := d.PathPart (tempName); pathPart [0] := 0X
  99.   END;
  100.   ASSERT (conv.IntToStr (tempNo, 16, 0, "0", s));
  101.   str.Append (ext, s);
  102.   ASSERT (d.AddPart (tempName, s, LEN (tempName)))
  103. END MakeName;
  104.  
  105.  
  106. PROCEDURE Search ( fl : d.FileLockPtr ) : File;
  107.  
  108.   VAR f : File;
  109.  
  110. BEGIN (* Search *)
  111.   f := root;
  112.   WHILE (f # NIL) & (d.SameLock (fl, f.fl) # d.same) DO f := f.next END;
  113.   RETURN f
  114. END Search;
  115.  
  116.  
  117. PROCEDURE Unlink (f : File);
  118.  
  119.   VAR f0 : File;
  120.  
  121. BEGIN (* Unlink *)
  122.   IF root # NIL THEN
  123.     IF f = root THEN
  124.       root := root.next
  125.     ELSE
  126.       f0 := root;
  127.       WHILE (f0.next # NIL) & (f0.next # f) DO
  128.         f0 := f0.next
  129.       END;
  130.       IF f0.next = f THEN f0.next := f.next END;
  131.     END
  132.   END;
  133.   f.next := NIL
  134. END Unlink;
  135.  
  136.  
  137. PROCEDURE ReadBuf (f : File; buf : Buffer; pos : LONGINT);
  138.  
  139.   VAR res : LONGINT;
  140.  
  141. BEGIN (* ReadBuf *)
  142.   res := d.Seek (f.fh, pos, d.beginning);
  143.   IF res # -1 THEN
  144.     buf.lim := SHORT (d.Read (f^.fh, buf.data, SectorSize));
  145.     buf.apos := pos;
  146.     buf.mod := FALSE;
  147.   END
  148. END ReadBuf;
  149.  
  150.  
  151. PROCEDURE WriteBuf (f : File; buf : Buffer);
  152.  
  153.   VAR res : LONGINT;
  154.  
  155. BEGIN (* WriteBuf *)
  156.   res := d.Seek (f.fh, buf.apos, d.beginning);
  157.   IF res # -1 THEN
  158.     res := d.Write (f.fh, buf.data, buf.lim);
  159.     IF res = buf.lim THEN
  160.       buf.mod := FALSE;
  161.     END
  162.   END
  163. END WriteBuf;
  164.  
  165.  
  166. PROCEDURE GetBuf (f : File; pos : LONGINT) : Buffer;
  167.  
  168.   VAR buf, last, next : Buffer;
  169.  
  170. BEGIN (* GetBuf *)
  171.   buf := f.firstbuf;
  172.   LOOP
  173.     IF buf.apos = pos THEN EXIT END;
  174.     IF buf.next = f.firstbuf THEN
  175.       last := buf;
  176.       IF f.nofbufs < MaxBufs THEN (* allocate new buffer *)
  177.         NEW (buf); INC (f.nofbufs);
  178.       ELSE (* take one of the buffers (assuming more than one) *)
  179.         buf := f.firstbuf; f.firstbuf := buf.next; last.next := buf.next;
  180.         IF buf.mod THEN WriteBuf (f, buf) END
  181.       END;
  182.       IF pos < f.firstbuf.apos THEN
  183.         f.firstbuf := buf
  184.       ELSIF pos < last.apos THEN
  185.         WHILE last.next.apos < pos DO last := last.next END;
  186.       END;
  187.       buf.next := last.next; last.next := buf;
  188.       buf.apos := pos; buf.lim := 0; buf.mod := FALSE;
  189.       IF pos < f.len THEN ReadBuf (f, buf, pos) END;
  190.       EXIT
  191.     END;
  192.     buf := buf.next
  193.   END; (* LOOP *)
  194.   RETURN buf;
  195. END GetBuf;
  196.  
  197.  
  198. PROCEDURE Unbuffer (f : File);
  199.  
  200.   VAR buf : Buffer;
  201.  
  202. BEGIN (* Unbuffer *)
  203.   buf := f.firstbuf;
  204.   REPEAT
  205.     IF buf.mod THEN WriteBuf (f, buf) END;
  206.     buf := buf.next
  207.   UNTIL buf = f.firstbuf
  208. END Unbuffer;
  209.  
  210.  
  211. PROCEDURE Delete * ( name : ARRAY OF CHAR; VAR res : INTEGER );
  212. <*$CopyArrays-*>
  213. BEGIN (* Delete *)
  214.   IF d.DeleteFile (name) THEN
  215.     res := 0
  216.   ELSE
  217.     res := SHORT (d.IoErr ());
  218.     IF res = d.objectNotFound THEN res := 0 END
  219.   END
  220. END Delete;
  221.  
  222.  
  223. PROCEDURE Rename * ( old, new : ARRAY OF CHAR; VAR res : INTEGER );
  224. <*$CopyArrays-*>
  225. BEGIN (* Rename *)
  226.   IF d.Rename (old, new) THEN res := 0
  227.   ELSE res := SHORT (d.IoErr ())
  228.   END
  229. END Rename;
  230.  
  231.  
  232. PROCEDURE Old * ( name : ARRAY OF CHAR ) : File;
  233.  
  234.   VAR
  235.     f : File; fl : d.FileLockPtr; fh : d.FileHandlePtr;
  236.     fib : d.FileInfoBlockPtr; len : LONGINT; buf : Buffer;
  237.  
  238. <*$CopyArrays-*>
  239. BEGIN (* Old *)
  240.   fl := d.Lock (name, d.sharedLock);
  241.   IF fl # NIL THEN
  242.     f := Search (fl);
  243.     IF f = NIL THEN
  244.       fh := d.Open (name, d.oldFile);
  245.       IF fh # NIL THEN
  246.         fib := d.AllocDosObjectTags (d.fib, NIL);
  247.         IF fib # NIL THEN
  248.           IF d.Examine (fl, fib^) THEN len := fib.size;
  249.           ELSE len := 0
  250.           END;
  251.           d.FreeDosObject (d.fib, fib);
  252.           NEW (f);
  253.           IF f # NIL THEN
  254.             NEW (buf);
  255.             IF buf # NIL THEN
  256.               buf.apos := 0; buf.next := buf; buf.mod := FALSE;
  257.               IF len > SectorSize THEN buf.lim := SectorSize
  258.               ELSE buf.lim := SHORT (len)
  259.               END;
  260.               f.len := len; f.firstbuf := buf; f.nofbufs := 1;
  261.               COPY (name, f.name); f.tempNo := 0;
  262.               f.fl := fl; f.fh := fh; f.pos := 0;
  263.               f.next := root; root := f;
  264.               ReadBuf (f, buf, 0);
  265.               RETURN f
  266.             END;
  267.           END;
  268.         END;
  269.       END;
  270.       d.OldClose (fh)
  271.     END;
  272.     d.UnLock (fl)
  273.   END;
  274.   RETURN f
  275. END Old;
  276.  
  277.  
  278. PROCEDURE New * ( name : ARRAY OF CHAR ) : File;
  279.  
  280.   VAR
  281.     f : File; fl : d.FileLockPtr; fh : d.FileHandlePtr;
  282.     buf : Buffer; tempName : ARRAY 256 OF CHAR;
  283.  
  284. <*$CopyArrays-*>
  285. BEGIN (* New *)
  286.   REPEAT
  287.     IF tempNo < MAX (LONGINT) THEN INC (tempNo) ELSE tempNo := 1 END;
  288.     MakeName (name, tempNo, tempExt, tempName)
  289.   UNTIL ~du.FileExists (tempName);
  290.   fh := d.Open (tempName, d.newFile);
  291.   IF fh # NIL THEN
  292.     NEW (f);
  293.     IF f # NIL THEN
  294.       NEW (buf);
  295.       IF buf # NIL THEN
  296.         buf.apos := 0; buf.next := buf; buf.mod := TRUE;
  297.         buf.lim := 0;
  298.         f.len := 0; f.firstbuf := buf; f.nofbufs := 1;
  299.         COPY (name, f.name); f.tempNo := tempNo;
  300.         f.fl := d.Lock (tempName, d.sharedLock); f.fh := fh; f.pos := 0;
  301.         f.next := root; root := f;
  302.         ReadBuf (f, buf, 0);
  303.         RETURN f
  304.       END
  305.     END
  306.   END;
  307.   d.OldClose (fh);
  308.   RETURN f
  309. END New;
  310.  
  311.  
  312. PROCEDURE Register * ( f : File );
  313.  
  314.   VAR tempName, bkpName : ARRAY 256 OF CHAR; res : INTEGER;
  315.  
  316. BEGIN (* Register *)
  317.   ASSERT (f # NIL, 97);
  318.   IF f.fh # NIL THEN
  319.     Unbuffer (f); Unlink (f);
  320.     IF d.Close (f.fh) THEN
  321.       f.fh := NIL; d.UnLock (f.fl); f.fl := NIL;
  322.       IF f.tempNo # 0 THEN
  323.         MakeName (f.name, f.tempNo, tempExt, tempName);
  324.         IF f.name = "" THEN
  325.           Delete (tempName, res);
  326.         ELSE
  327.           MakeName (f.name, f.tempNo, bkpExt, bkpName);
  328.           Rename (f.name, bkpName, res);
  329.           IF res = 0 THEN
  330.             Rename (tempName, f.name, res);
  331.             IF res = 0 THEN Delete (bkpName, res) END
  332.           ELSIF res = d.objectNotFound THEN
  333.             Rename (tempName, f.name, res);
  334.           END
  335.         END
  336.       END
  337.     END
  338.   END
  339. END Register;
  340.  
  341.  
  342. PROCEDURE Close * ( f : File );
  343. BEGIN (* Close *)
  344.   ASSERT (f # NIL, 97);
  345.   IF f.fh # NIL THEN
  346.     Unbuffer (f); Unlink (f);
  347.     IF d.Close (f.fh) THEN f.fh := NIL; d.UnLock (f.fl); f.fl := NIL END
  348.   END
  349. END Close;
  350.  
  351.  
  352. PROCEDURE Purge * ( f : File );
  353.  
  354.   VAR tempName : ARRAY 256 OF CHAR; res : INTEGER;
  355.  
  356. BEGIN (* Purge *)
  357.   ASSERT (f # NIL, 97);
  358.   IF f.fh # NIL THEN
  359.     Unbuffer (f); Unlink (f);
  360.     IF d.Close (f.fh) THEN f.fh := NIL; d.UnLock (f.fl); f.fl := NIL END;
  361.     IF f.tempNo # 0 THEN
  362.       MakeName (f.name, f.tempNo, tempExt, tempName);
  363.       Delete (tempName, res)
  364.     END
  365.   END
  366. END Purge;
  367.  
  368.  
  369. PROCEDURE Length * ( f : File ) : LONGINT;
  370.  
  371. BEGIN (* Length *)
  372.   ASSERT (f # NIL, 97);
  373.   RETURN f.len
  374. END Length;
  375.  
  376.  
  377. PROCEDURE GetDate * ( f : File; VAR time, day : LONGINT );
  378.  
  379.   VAR fib : d.FileInfoBlockPtr;
  380.  
  381. BEGIN (* GetDate *)
  382.   ASSERT (f # NIL, 97); ASSERT (f.fh # NIL, 97);
  383.   fib := d.AllocDosObjectTags (d.fib, NIL);
  384.   IF fib # NIL THEN
  385.     IF d.ExamineFH (f.fh, fib^) THEN
  386.       oc.ADOS2OberonTime (fib.date, time, day);
  387.     END;
  388.     d.FreeDosObject (d.fib, fib)
  389.   END
  390. END GetDate;
  391.  
  392.  
  393. PROCEDURE Set * ( VAR r : Rider; f : File; pos : LONGINT );
  394.  
  395. BEGIN (* Set *)
  396.   r.eof := FALSE; r.res := 0; r.file := f;
  397.   IF f # NIL THEN
  398.     IF pos < 0 THEN r.pos := 0; r.bpos := 0
  399.     ELSE r.bpos := SHORT (pos MOD SectorSize); r.pos := pos - r.bpos
  400.     END;
  401.     r.buf := f.firstbuf
  402.   END
  403. END Set;
  404.  
  405.  
  406. PROCEDURE Pos * ( VAR r : Rider ) : LONGINT;
  407. BEGIN (* Pos *)
  408.   RETURN r.pos + r.bpos
  409. END Pos;
  410.  
  411.  
  412. PROCEDURE Base * ( VAR r : Rider ) : File;
  413. BEGIN (* Base *)
  414.   RETURN r.file
  415. END Base;
  416.  
  417.  
  418. PROCEDURE Read * ( VAR r : Rider; VAR x : SYS.BYTE );
  419.  
  420.   VAR buf : Buffer;
  421.  
  422. BEGIN (* Read *)
  423.   ASSERT (r.file # NIL, 97);
  424.   IF r.pos # r.buf.apos THEN r.buf := GetBuf (r.file, r.pos) END;
  425.   IF r.bpos < r.buf.lim THEN
  426.     x := r.buf.data [r.bpos]; INC (r.bpos)
  427.   ELSIF (r.pos + SectorSize) < r.file.len THEN
  428.     INC (r.pos, SectorSize);
  429.     r.buf := GetBuf (r.file, r.pos);
  430.     x := r.buf.data [0]; r.bpos := 1
  431.   ELSE
  432.     x := 0X; r.eof := TRUE
  433.   END
  434. END Read;
  435.  
  436.  
  437. PROCEDURE ReadBytes * ( VAR r : Rider; VAR x : ARRAY OF SYS.BYTE;
  438.                           n : LONGINT );
  439.  
  440.   VAR src, dst, m : LONGINT;
  441.       buf : Buffer;
  442.  
  443. BEGIN (* ReadBytes *)
  444.   ASSERT (r.file # NIL, 97); ASSERT (r.file.fh # NIL, 97);
  445.   ASSERT (LEN (x) >= n, 97);
  446.   dst := SYS.VAL (LONGINT, SYS.ADR (x));
  447.   IF r.pos # r.buf.apos THEN r.buf := GetBuf (r.file, r.pos) END;
  448.   LOOP
  449.     IF n <= 0 THEN EXIT END;
  450.     src := SYS.VAL (LONGINT, SYS.ADR(r.buf.data));
  451.     INC (src, r.bpos); m := r.bpos + n;
  452.     IF m <= r.buf.lim THEN
  453.       SYS.MOVE (src, dst, n); r.bpos := SHORT (m); r.res := 0;
  454.       EXIT
  455.     ELSIF r.buf.lim = SectorSize THEN
  456.       m := r.buf.lim - r.bpos;
  457.       IF m > 0 THEN
  458.         SYS.MOVE (src, dst, m); INC (dst, m); DEC (n, m)
  459.       END;
  460.       IF r.pos < r.file.len THEN
  461.         INC (r.pos, SectorSize);
  462.         r.bpos := 0; r.buf := GetBuf (r.file, r.pos);
  463.       ELSE
  464.         r.res := n; r.eof := TRUE; EXIT
  465.       END;
  466.     ELSE
  467.       m := r.buf.lim - r.bpos;
  468.       IF m > 0 THEN
  469.         SYS.MOVE (src, dst, m); r.bpos := r.buf.lim
  470.       END;
  471.       r.res := n - m; r.eof := TRUE; EXIT
  472.     END;
  473.   END; (* LOOP *)
  474. END ReadBytes;
  475.  
  476.  
  477. <*$ < StackChk- IndexChk- *>
  478.  
  479. PROCEDURE SwapWord ( VAR w : ARRAY OF SYS.BYTE );
  480.  
  481.   VAR t : SYS.BYTE;
  482.  
  483. BEGIN (* SwapWord *)
  484.   t := w [0]; w [0] := w [1]; w [1] := t
  485. END SwapWord;
  486.  
  487.  
  488. PROCEDURE SwapLongword ( VAR l : ARRAY OF SYS.BYTE );
  489.  
  490.   VAR t : SYS.BYTE;
  491.  
  492. BEGIN (* SwapLongword *)
  493.   t := l [0]; l [0] := l [3]; l [3] := t;
  494.   t := l [1]; l [1] := l [2]; l [2] := t;
  495. END SwapLongword;
  496.  
  497. <*$ > *>
  498.  
  499.  
  500. PROCEDURE ReadInt * ( VAR r : Rider; VAR x : INTEGER );
  501.  
  502.   VAR i : INTEGER;
  503.  
  504. BEGIN (* ReadInt *)
  505.   ReadBytes (r, i, 2); SwapWord (i); x := i
  506. END ReadInt;
  507.  
  508.  
  509. PROCEDURE ReadLInt * ( VAR r : Rider; VAR x : LONGINT );
  510.  
  511.   VAR i : LONGINT;
  512.  
  513. BEGIN (* ReadLInt *)
  514.   ReadBytes (r, i, 4); SwapLongword (i); x := i
  515. END ReadLInt;
  516.  
  517.  
  518. PROCEDURE ReadReal * ( VAR r : Rider; VAR x : REAL );
  519.  
  520.   VAR y : REAL;
  521.  
  522. BEGIN (* ReadReal *)
  523.   ReadBytes (r, y, 4); SwapLongword (y); x := y
  524. END ReadReal;
  525.  
  526.  
  527. PROCEDURE ReadLReal * ( VAR r : Rider; VAR x : LONGREAL );
  528. BEGIN (* ReadLReal *)
  529.   HALT (99)
  530. END ReadLReal;
  531.  
  532.  
  533. PROCEDURE ReadNum * ( VAR r : Rider; VAR x : LONGINT );
  534.  
  535.   VAR s : SHORTINT; ch : CHAR; n : LONGINT;
  536.  
  537. BEGIN (* ReadNum *)
  538.   s := 0; n := 0; Read(r, ch);
  539.   WHILE ORD(ch) >= 128 DO
  540.     INC(n, ASH(ORD(ch) - 128, s)); INC(s, 7); Read(r, ch)
  541.   END;
  542.   x := n + ASH(ORD(ch) MOD 64 - ORD(ch) DIV 64 * 64, s)
  543. END ReadNum;
  544.  
  545.  
  546. PROCEDURE ReadString * ( VAR r : Rider; VAR x : ARRAY OF CHAR );
  547.  
  548.   VAR ch : CHAR; i : INTEGER;
  549.  
  550. BEGIN (* ReadString *)
  551.   i := 0;
  552.   REPEAT
  553.     Read (r, ch); x [i] := ch; INC (i)
  554.   UNTIL ch = 0X
  555. END ReadString;
  556.  
  557.  
  558. PROCEDURE ReadSet * ( VAR r : Rider; VAR x : SET );
  559.  
  560.   VAR s : SET;
  561.  
  562. BEGIN (* ReadSet *)
  563.   ReadBytes (r, s, 4); SwapLongword (s); x := s
  564. END ReadSet;
  565.  
  566.  
  567. PROCEDURE ReadBool * ( VAR r : Rider; VAR x : BOOLEAN );
  568.  
  569.   VAR i : SHORTINT;
  570.  
  571. BEGIN (* ReadBool *)
  572.   Read (r, i); x := (i # 0)
  573. END ReadBool;
  574.  
  575.  
  576. PROCEDURE Write * ( VAR r : Rider; x : SYS.BYTE );
  577.  
  578.   VAR f : File; buf : Buffer;
  579.  
  580. BEGIN (* Write *)
  581.   ASSERT (r.file # NIL, 97); ASSERT (r.file.fh # NIL, 97);
  582.   IF r.pos # r.buf.apos THEN r.buf := GetBuf (r.file, r.pos) END;
  583.   IF r.bpos >= r.buf.lim THEN
  584.     IF r.bpos < SectorSize THEN
  585.       INC (r.buf.lim); INC (r.file.len)
  586.     ELSE
  587.       f := r.file; INC (r.pos, SectorSize);
  588.       r.buf := GetBuf (f, r.pos);
  589.       IF r.pos >= f.len THEN r.buf.lim := 1; f.len := r.pos END;
  590.       r.bpos := 0
  591.     END
  592.   END;
  593.   r.buf.data [r.bpos] := x; INC (r.bpos); r.buf.mod := TRUE
  594. END Write;
  595.  
  596.  
  597. PROCEDURE WriteBytes * ( VAR r : Rider; VAR x : ARRAY OF SYS.BYTE;
  598.                           n : LONGINT );
  599.  
  600.   VAR src, dst, m : LONGINT; f : File; buf : Buffer;
  601.  
  602. BEGIN (* WriteBytes *)
  603.   ASSERT (r.file # NIL, 97); ASSERT (r.file.fh # NIL, 97);
  604.   ASSERT (LEN (x) >= n, 97);
  605.   src := SYS.VAL (LONGINT, SYS.ADR (x));
  606.   IF r.pos # r.buf.apos THEN r.buf := GetBuf (r.file, r.pos) END;
  607.   LOOP
  608.     IF n <= 0 THEN EXIT END;
  609.     r.buf.mod := TRUE;
  610.     dst := SYS.VAL (LONGINT, SYS.ADR(r.buf.data)); INC (dst, r.bpos);
  611.     m := r.bpos + n;
  612.     IF m <= r.buf.lim THEN
  613.       SYS.MOVE (src, dst, n); r.bpos := SHORT (m); EXIT
  614.     ELSIF m <= SectorSize THEN
  615.       SYS.MOVE (src, dst, n); r.bpos := SHORT (m);
  616.       INC (r.file.len, n); r.buf.lim := SHORT (m); EXIT
  617.     ELSE
  618.       m := SectorSize - r.bpos;
  619.       IF m > 0 THEN
  620.         SYS.MOVE (src, dst, m); INC (src, m); DEC (n, m);
  621.         INC (r.buf.lim, SHORT (m))
  622.       END;
  623.       f := r.file; INC (r.pos, SectorSize);
  624.       r.bpos := 0; r.buf := GetBuf (f, r.pos);
  625.       IF r.pos >= f.len THEN r.buf.lim := 0; f.len := r.pos END;
  626.     END;
  627.   END; (* LOOP *)
  628. END WriteBytes;
  629.  
  630.  
  631. PROCEDURE WriteInt * ( VAR r : Rider; x : INTEGER );
  632. BEGIN (* WriteInt *)
  633.   SwapWord (x); WriteBytes (r, x, 2);
  634. END WriteInt;
  635.  
  636.  
  637. PROCEDURE WriteLInt * ( VAR r : Rider; x : LONGINT );
  638. BEGIN (* WriteLInt *)
  639.   SwapLongword (x); WriteBytes (r, x, 4);
  640. END WriteLInt;
  641.  
  642.  
  643. PROCEDURE WriteReal * ( VAR r : Rider; x : REAL );
  644. BEGIN (* WriteReal *)
  645.   SwapLongword (x); WriteBytes (r, x, 4);
  646. END WriteReal;
  647.  
  648.  
  649. PROCEDURE WriteLReal * ( VAR r : Rider; x : LONGREAL );
  650. BEGIN (* WriteLReal *)
  651.   HALT (99)
  652. END WriteLReal;
  653.  
  654.  
  655. PROCEDURE WriteNum * ( VAR r : Rider; x : LONGINT );
  656. BEGIN (* WriteNum *)
  657.   WHILE (x < -64) OR (x > 63) DO
  658.     Write(r, CHR(x MOD 128 + 128)); x := x DIV 128
  659.   END;
  660.   Write(r, CHR(x MOD 128))
  661. END WriteNum;
  662.  
  663.  
  664. PROCEDURE WriteString * ( VAR r : Rider; x : ARRAY OF CHAR );
  665. <*$CopyArrays-*>
  666. BEGIN (* WriteString *)
  667.   WriteBytes (r, x, str.Length (x)); Write (r, 0X)
  668. END WriteString;
  669.  
  670.  
  671. PROCEDURE WriteSet * ( VAR r : Rider; x : SET );
  672. BEGIN (* WriteSet *)
  673.   SwapLongword (x); WriteBytes (r, x, 4);
  674. END WriteSet;
  675.  
  676.  
  677. PROCEDURE WriteBool * ( VAR r : Rider; x : BOOLEAN );
  678.  
  679.   VAR i : SHORTINT;
  680.  
  681. BEGIN (* WriteBool *)
  682.   IF x THEN i := 1 ELSE i := 0 END; Write (r, i)
  683. END WriteBool;
  684.  
  685.  
  686. PROCEDURE* CloseFiles ( VAR rc : LONGINT );
  687.  
  688. BEGIN (* CloseFiles *)
  689.   WHILE root # NIL DO
  690.     IF root.fh # NIL THEN
  691.       Unbuffer (root);
  692.       IF d.Close (root.fh) THEN END;
  693.       d.UnLock (root.fl);
  694.     END;
  695.     root := root.next
  696.   END;
  697. END CloseFiles;
  698.  
  699.  
  700. BEGIN (* Files *)
  701.   root := NIL; GetTempNo; Kernel.SetCleanup (CloseFiles);
  702. END Files.
  703.