Oberon/V5/Files.Mod

MODULE Files; (*NW 11.1.86 / 22.9.93 / 25.5.95 / 25.12.95 / 15.8.2013*) &#32;&#32;IMPORT SYSTEM, Kernel, FileDir; &#32;&#32;(*A file consists of a sequence of pages. The first page &#32;&#32;&#32;&#32;contains the header. Part of the header is the page table, an array &#32;&#32;&#32;&#32;of disk addresses to the pages. A file is referenced through riders. &#32;&#32;&#32;&#32;A rider indicates a current position and refers to a file*) &#32;&#32;CONST MaxBufs   &#61; 4; &#32;&#32;&#32;&#32;&#32;&#32;HS       &#61; FileDir.HeaderSize; &#32;&#32;&#32;&#32;&#32;&#32;SS       &#61; FileDir.SectorSize; &#32;&#32;&#32;&#32;&#32;&#32;STS      &#61; FileDir.SecTabSize; &#32;&#32;&#32;&#32;&#32;&#32;XS       &#61; FileDir.IndexSize; &#32;&#32;TYPE DiskAdr &#61; INTEGER; &#32;&#32;&#32;&#32;&#32;&#32;File*   &#61; POINTER TO FileDesc; &#32;&#32;&#32;&#32;&#32;&#32;Buffer &#61; POINTER TO BufferRecord; &#32;&#32;&#32;&#32;&#32;&#32;Index  &#61; POINTER TO IndexRecord; &#32;&#32;&#32;&#32;Rider* &#61; &#32;&#32;&#32;&#32;&#32;&#32;RECORD eof*&#58; BOOLEAN; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;res*&#58; INTEGER; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;file&#58; File; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;apos, bpos&#58; INTEGER; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;buf&#58; Buffer &#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;FileDesc &#61; &#32;&#32;&#32;&#32;&#32;&#32;RECORD next&#58; INTEGER; (*list of files invisible to the GC*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;nofbufs, aleng, bleng&#58; INTEGER; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;modH, registered&#58; BOOLEAN; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;firstbuf&#58; Buffer; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;sechint&#58; DiskAdr; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;name&#58; FileDir.FileName; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;date&#58; INTEGER; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ext&#58; ARRAY FileDir.ExTabSize OF Index; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;sec&#58; FileDir.SectorTable &#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;BufferRecord &#61; &#32;&#32;&#32;&#32;&#32;&#32;RECORD apos, lim&#58; INTEGER; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;mod&#58; BOOLEAN; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;next&#58; Buffer; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;data&#58; FileDir.DataSector &#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;IndexRecord &#61; &#32;&#32;&#32;&#32;&#32;&#32;RECORD adr&#58; DiskAdr; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;mod&#58; BOOLEAN; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;sec&#58; FileDir.IndexSector &#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;(*aleng * SS + bleng &#61; length (including header) &#32;&#32;&#32;&#32;&#32;&#32;apos * SS + bpos &#61; current position &#32;&#32;&#32;&#32;&#32;&#32;0 &#60;&#61; bpos &#60;&#61; lim &#60;&#61; SS &#32;&#32;&#32;&#32;&#32;&#32;0 &#60;&#61; apos &#60;&#61; aleng &#60; PgTabSize &#32;&#32;&#32;&#32;&#32;&#32;(apos &#60; aleng) &#38; (lim &#61; SS) OR (apos &#61; aleng) *) &#32;&#32;VAR root&#58; INTEGER (*File*); (*list of open files*) &#32;&#32;PROCEDURE Check(s&#58; ARRAY OF CHAR; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;VAR name&#58; FileDir.FileName; VAR res&#58; INTEGER); &#32;&#32;&#32;&#32;VAR i&#58; INTEGER; ch&#58; CHAR; &#32;&#32;BEGIN ch &#58;&#61; s&#91;0&#93;; i &#58;&#61; 0; &#32;&#32;&#32;&#32;IF (ch &#62;&#61; "A") &#38; (ch &#60;&#61; "Z") OR (ch &#62;&#61; "a") &#38; (ch &#60;&#61; "z") THEN &#32;&#32;&#32;&#32;&#32;&#32;REPEAT name&#91;i&#93; &#58;&#61; ch; INC(i); ch &#58;&#61; s&#91;i&#93; &#32;&#32;&#32;&#32;&#32;&#32;UNTIL &#126;((ch &#62;&#61; "0") &#38; (ch &#60;&#61; "9") OR (ch &#62;&#61; "A") &#38; (ch &#60;&#61; "Z") &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;OR (ch &#62;&#61; "a") &#38; (ch &#60;&#61; "z") OR (ch &#61; ".")) OR (i &#61; FileDir.FnLength); &#32;&#32;&#32;&#32;&#32;&#32;IF i &#61; FileDir.FnLength THEN res &#58;&#61; 4 &#32;&#32;&#32;&#32;&#32;&#32;ELSIF ch &#61; 0X THEN res &#58;&#61; 0; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE i &#60; FileDir.FnLength DO name&#91;i&#93; &#58;&#61; 0X; INC(i) END &#32;&#32;&#32;&#32;&#32;&#32;ELSE res &#58;&#61; 5 &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;ELSIF ch &#61; 0X THEN name&#91;0&#93; &#58;&#61; 0X; res &#58;&#61; -1 &#32;&#32;&#32;&#32;ELSE res &#58;&#61; 3 &#32;&#32;&#32;&#32;END &#32;&#32;END Check; &#32;&#32;PROCEDURE Old*(name&#58; ARRAY OF CHAR)&#58; File; &#32;&#32;&#32;&#32;VAR i, k, res&#58; INTEGER; &#32;&#32;&#32;&#32;&#32;&#32;f&#58; File; &#32;&#32;&#32;&#32;&#32;&#32;header&#58; DiskAdr; &#32;&#32;&#32;&#32;&#32;&#32;buf&#58; Buffer; &#32;&#32;&#32;&#32;&#32;&#32;F&#58; FileDir.FileHd; &#32;&#32;&#32;&#32;&#32;&#32;namebuf&#58; FileDir.FileName; &#32;&#32;&#32;&#32;&#32;&#32;inxpg&#58; Index; &#32;&#32;BEGIN f &#58;&#61; NIL; Check(name, namebuf, res); &#32;&#32;&#32;&#32;IF res &#61; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;FileDir.Search(namebuf, header); &#32;&#32;&#32;&#32;&#32;&#32;IF header # 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;f &#58;&#61; SYSTEM.VAL(File, root); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE (f # NIL) &#38; (f.sec&#91;0&#93; # header) DO f &#58;&#61; SYSTEM.VAL(File, f.next) END ; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF f &#61; NIL THEN (*file not yet present*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;NEW(buf); buf.apos &#58;&#61; 0; buf.next &#58;&#61; buf; buf.mod &#58;&#61; FALSE; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;F &#58;&#61; SYSTEM.VAL(FileDir.FileHd, SYSTEM.ADR(buf.data)); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Kernel.GetSector(header, buf.data); ASSERT(F.mark &#61; FileDir.HeaderMark); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;NEW(f); f.aleng &#58;&#61; F.aleng; f.bleng &#58;&#61; F.bleng; f.date &#58;&#61; F.date; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF f.aleng &#61; 0 THEN buf.lim &#58;&#61; f.bleng ELSE buf.lim &#58;&#61; SS END ; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;f.firstbuf &#58;&#61; buf; f.nofbufs &#58;&#61; 1; f.name &#58;&#61; namebuf; f.registered &#58;&#61; TRUE; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;f.sec &#58;&#61; F.sec; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;k &#58;&#61; (f.aleng + (XS-STS)) DIV XS; i &#58;&#61; 0; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE i &#60; k DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;NEW(inxpg); inxpg.adr &#58;&#61; F.ext&#91;i&#93;; inxpg.mod &#58;&#61; FALSE; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Kernel.GetSector(inxpg.adr, inxpg.sec); f.ext&#91;i&#93; &#58;&#61; inxpg; INC(i) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE i &#60; FileDir.ExTabSize DO f.ext&#91;i&#93; &#58;&#61; NIL; INC(i) END ; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;f.sechint &#58;&#61; header; f.modH &#58;&#61; FALSE; f.next &#58;&#61; root; root &#58;&#61; SYSTEM.VAL(INTEGER, f) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;RETURN f &#32;&#32;END Old; &#32;&#32;PROCEDURE New*(name&#58; ARRAY OF CHAR)&#58; File; &#32;&#32;&#32;&#32;VAR i, res&#58; INTEGER; &#32;&#32;&#32;&#32;&#32;&#32;f&#58; File; &#32;&#32;&#32;&#32;&#32;&#32;buf&#58; Buffer; &#32;&#32;&#32;&#32;&#32;&#32;F&#58; FileDir.FileHd; &#32;&#32;&#32;&#32;&#32;&#32;namebuf&#58; FileDir.FileName; &#32;&#32;BEGIN f &#58;&#61; NIL; Check(name, namebuf, res); &#32;&#32;&#32;&#32;IF res &#60;&#61; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;NEW(buf); buf.apos &#58;&#61; 0; buf.mod &#58;&#61; TRUE; buf.lim &#58;&#61; HS; buf.next &#58;&#61; buf; &#32;&#32;&#32;&#32;&#32;&#32;F &#58;&#61; SYSTEM.VAL(FileDir.FileHd, SYSTEM.ADR(buf.data)); &#32;&#32;&#32;&#32;&#32;&#32;F.mark &#58;&#61; FileDir.HeaderMark; &#32;&#32;&#32;&#32;&#32;&#32;F.aleng &#58;&#61; 0; F.bleng &#58;&#61; HS; F.name &#58;&#61; namebuf; &#32;&#32;&#32;&#32;&#32;&#32;F.date &#58;&#61; Kernel.Clock; &#32;&#32;&#32;&#32;&#32;&#32;NEW(f); f.aleng &#58;&#61; 0; f.bleng &#58;&#61; HS; f.modH &#58;&#61; TRUE; &#32;&#32;&#32;&#32;&#32;&#32;f.registered &#58;&#61; FALSE; f.date &#58;&#61; F.date; &#32;&#32;&#32;&#32;&#32;&#32;f.firstbuf &#58;&#61; buf; f.nofbufs &#58;&#61; 1; f.name &#58;&#61; namebuf; f.sechint &#58;&#61; 0; &#32;&#32;&#32;&#32;&#32;&#32;i &#58;&#61; 0; &#32;&#32;&#32;&#32;&#32;&#32;REPEAT f.ext&#91;i&#93; &#58;&#61; NIL; F.ext&#91;i&#93; &#58;&#61; 0; INC(i) UNTIL i &#61; FileDir.ExTabSize; &#32;&#32;&#32;&#32;&#32;&#32;i &#58;&#61; 0; &#32;&#32;&#32;&#32;&#32;&#32;REPEAT f.sec&#91;i&#93; &#58;&#61; 0; F.sec&#91;i&#93; &#58;&#61; 0; INC(i) UNTIL i &#61; STS &#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;RETURN f &#32;&#32;END New; &#32;&#32;PROCEDURE UpdateHeader(f&#58; File; VAR F&#58; FileDir.FileHeader); &#32;&#32;&#32;&#32;VAR k&#58; INTEGER; &#32;&#32;BEGIN F.aleng &#58;&#61; f.aleng; F.bleng &#58;&#61; f.bleng; &#32;&#32;&#32;&#32;F.sec &#58;&#61; f.sec; k &#58;&#61; (f.aleng + (XS-STS)) DIV XS; &#32;&#32;&#32;&#32;WHILE k &#62; 0 DO DEC(k); F.ext&#91;k&#93; &#58;&#61; f.ext&#91;k&#93;.adr END &#32;&#32;END UpdateHeader; &#32;&#32;PROCEDURE ReadBuf(f&#58; File; buf&#58; Buffer; pos&#58; INTEGER); &#32;&#32;&#32;&#32;VAR sec&#58; DiskAdr; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF pos &#60; STS THEN sec &#58;&#61; f.sec&#91;pos&#93; &#32;&#32;&#32;&#32;ELSE sec &#58;&#61; f.ext&#91;(pos-STS) DIV XS&#93;.sec&#91;(pos-STS) MOD XS&#93; &#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;Kernel.GetSector(sec, buf.data); &#32;&#32;&#32;&#32;IF pos &#60; f.aleng THEN buf.lim &#58;&#61; SS ELSE buf.lim &#58;&#61; f.bleng END ; &#32;&#32;&#32;&#32;buf.apos &#58;&#61; pos; buf.mod &#58;&#61; FALSE &#32;&#32;END ReadBuf; &#32;&#32;PROCEDURE WriteBuf(f&#58; File; buf&#58; Buffer); &#32;&#32;&#32;&#32;VAR i, k&#58; INTEGER; &#32;&#32;&#32;&#32;&#32;&#32;secadr&#58; DiskAdr; inx&#58; Index; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF buf.apos &#60; STS THEN &#32;&#32;&#32;&#32;&#32;&#32;secadr &#58;&#61; f.sec&#91;buf.apos&#93;; &#32;&#32;&#32;&#32;&#32;&#32;IF secadr &#61; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Kernel.AllocSector(f.sechint, secadr); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;f.modH &#58;&#61; TRUE; f.sec&#91;buf.apos&#93; &#58;&#61; secadr; f.sechint &#58;&#61; secadr &#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;&#32;&#32;IF buf.apos &#61; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;UpdateHeader(f, SYSTEM.VAL(FileDir.FileHeader, buf.data)); f.modH &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;ELSE i &#58;&#61; (buf.apos - STS) DIV XS; inx &#58;&#61; f.ext&#91;i&#93;; &#32;&#32;&#32;&#32;&#32;&#32;IF inx &#61; NIL THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;NEW(inx); inx.adr &#58;&#61; 0; inx.sec&#91;0&#93; &#58;&#61; 0; f.ext&#91;i&#93; &#58;&#61; inx; f.modH &#58;&#61; TRUE &#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;&#32;&#32;k &#58;&#61; (buf.apos - STS) MOD XS; secadr &#58;&#61; inx.sec&#91;k&#93;; &#32;&#32;&#32;&#32;&#32;&#32;IF secadr &#61; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Kernel.AllocSector(f.sechint, secadr); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;f.modH &#58;&#61; TRUE; inx.mod &#58;&#61; TRUE; inx.sec&#91;k&#93; &#58;&#61; secadr; f.sechint &#58;&#61; secadr &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;Kernel.PutSector(secadr, buf.data); buf.mod &#58;&#61; FALSE &#32;&#32;END WriteBuf; &#32;&#32;PROCEDURE Buf(f&#58; File; pos&#58; INTEGER)&#58; Buffer; &#32;&#32;&#32;&#32;VAR buf&#58; Buffer; &#32;&#32;BEGIN buf &#58;&#61; f.firstbuf; &#32;&#32;&#32;&#32;WHILE (buf.apos # pos) &#38; (buf.next # f.firstbuf) DO buf &#58;&#61; buf.next END ; &#32;&#32;&#32;&#32;IF buf.apos # pos THEN buf &#58;&#61; NIL END ; &#32;&#32;&#32;&#32;RETURN buf &#32;&#32;END Buf; &#32;&#32;PROCEDURE GetBuf(f&#58; File; pos&#58; INTEGER)&#58; Buffer; &#32;&#32;&#32;&#32;VAR buf&#58; Buffer; &#32;&#32;BEGIN buf &#58;&#61; f.firstbuf; &#32;&#32;&#32;&#32;WHILE (buf.apos # pos) &#38; (buf.next # f.firstbuf) DO buf &#58;&#61; buf.next END ; &#32;&#32;&#32;&#32;IF buf.apos # pos THEN &#32;&#32;&#32;&#32;&#32;&#32;IF f.nofbufs &#60; MaxBufs THEN (*allocate new buffer*) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;NEW(buf); buf.next &#58;&#61; f.firstbuf.next; f.firstbuf.next &#58;&#61; buf; INC(f.nofbufs) &#32;&#32;&#32;&#32;&#32;&#32;ELSE (*reuse a buffer*) f.firstbuf &#58;&#61; buf; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF buf.mod THEN WriteBuf(f, buf) END &#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;&#32;&#32;IF pos &#60;&#61; f.aleng THEN ReadBuf(f, buf, pos) ELSE buf.apos &#58;&#61; pos; buf.lim &#58;&#61; 0; buf.mod &#58;&#61; FALSE END &#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;RETURN buf &#32;&#32;END GetBuf; &#32;&#32;PROCEDURE Unbuffer(f&#58; File); &#32;&#32;&#32;&#32;VAR i, k&#58; INTEGER; &#32;&#32;&#32;&#32;&#32;&#32;buf&#58; Buffer; &#32;&#32;&#32;&#32;&#32;&#32;inx&#58; Index; &#32;&#32;&#32;&#32;&#32;&#32;head&#58; FileDir.FileHeader; &#32;&#32;BEGIN buf &#58;&#61; f.firstbuf; &#32;&#32;&#32;&#32;REPEAT &#32;&#32;&#32;&#32;&#32;&#32;IF buf.mod THEN WriteBuf(f, buf) END ; &#32;&#32;&#32;&#32;&#32;&#32;buf &#58;&#61; buf.next &#32;&#32;&#32;&#32;UNTIL buf &#61; f.firstbuf; &#32;&#32;&#32;&#32;k &#58;&#61; (f.aleng + (XS-STS)) DIV XS; i &#58;&#61; 0; &#32;&#32;&#32;&#32;WHILE i &#60; k DO &#32;&#32;&#32;&#32;&#32;&#32;inx &#58;&#61; f.ext&#91;i&#93;; INC(i); &#32;&#32;&#32;&#32;&#32;&#32;IF inx.mod THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF inx.adr &#61; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Kernel.AllocSector(f.sechint, inx.adr); f.sechint &#58;&#61; inx.adr; f.modH &#58;&#61; TRUE &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Kernel.PutSector(inx.adr, inx.sec); inx.mod &#58;&#61; FALSE &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;IF f.modH THEN &#32;&#32;&#32;&#32;&#32;&#32;Kernel.GetSector(f.sec&#91;0&#93;, head); UpdateHeader(f, head); &#32;&#32;&#32;&#32;&#32;&#32;Kernel.PutSector(f.sec&#91;0&#93;, head); f.modH &#58;&#61; FALSE &#32;&#32;&#32;&#32;END &#32;&#32;END Unbuffer; &#32;&#32;PROCEDURE Register*(f&#58; File); &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF (f # NIL) &#38; (f.name&#91;0&#93; # 0X) THEN &#32;&#32;&#32;&#32;&#32;&#32;Unbuffer(f); &#32;&#32;&#32;&#32;&#32;&#32;IF &#126;f.registered THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;FileDir.Insert(f.name, f.sec&#91;0&#93;); f.registered &#58;&#61; TRUE; f.next &#58;&#61; root; root &#58;&#61; SYSTEM.VAL(INTEGER, f) &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END &#32;&#32;END Register; &#32;&#32;PROCEDURE Close*(f&#58; File); &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF f # NIL THEN Unbuffer(f) END &#32;&#32;END Close; &#32;&#32;PROCEDURE Purge*(f&#58; File); &#32;&#32;&#32;&#32;VAR a, i, j, k&#58; INTEGER; &#32;&#32;&#32;&#32;&#32;&#32;ind&#58; FileDir.IndexSector; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF f # NIL THEN a &#58;&#61; f.aleng + 1; f.aleng &#58;&#61; 0; f.bleng &#58;&#61; HS; &#32;&#32;&#32;&#32;&#32;&#32;IF a &#60;&#61; STS THEN i &#58;&#61; a; &#32;&#32;&#32;&#32;&#32;&#32;ELSE i &#58;&#61; STS; DEC(a, i); j &#58;&#61; (a-1) MOD XS; k &#58;&#61; (a-1) DIV XS; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;WHILE k &#62;&#61; 0 DO &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Kernel.GetSector(f.ext&#91;k&#93;.adr, ind); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;REPEAT DEC(j); Kernel.FreeSector(ind&#91;j&#93;) UNTIL j &#61; 0; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Kernel.FreeSector(f.ext&#91;k&#93;.adr); j &#58;&#61; XS; DEC(k) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;&#32;&#32;REPEAT DEC(i); Kernel.FreeSector(f.sec&#91;i&#93;) UNTIL i &#61; 0 &#32;&#32;&#32;&#32;END &#32;&#32;END Purge; &#32;&#32;PROCEDURE Delete*(name&#58; ARRAY OF CHAR; VAR res&#58; INTEGER); &#32;&#32;&#32;&#32;VAR adr&#58; DiskAdr; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;namebuf&#58; FileDir.FileName; &#32;&#32;BEGIN Check(name, namebuf, res); &#32;&#32;&#32;&#32;IF res &#61; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;FileDir.Delete(namebuf, adr); &#32;&#32;&#32;&#32;&#32;&#32;IF adr &#61; 0 THEN res &#58;&#61; 2 END &#32;&#32;&#32;&#32;END &#32;&#32;END Delete; &#32;&#32;PROCEDURE Rename*(old, new&#58; ARRAY OF CHAR; VAR res&#58; INTEGER); &#32;&#32;&#32;&#32;VAR adr&#58; DiskAdr; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;oldbuf, newbuf&#58; FileDir.FileName; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;head&#58; FileDir.FileHeader; &#32;&#32;BEGIN Check(old, oldbuf, res); &#32;&#32;&#32;&#32;IF res &#61; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;Check(new, newbuf, res); &#32;&#32;&#32;&#32;&#32;&#32;IF res &#61; 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;FileDir.Delete(oldbuf, adr); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF adr # 0 THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;FileDir.Insert(newbuf, adr); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;Kernel.GetSector(adr, head); head.name &#58;&#61; newbuf; Kernel.PutSector(adr, head) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE res &#58;&#61; 2 &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END &#32;&#32;END Rename; &#32;&#32;PROCEDURE Length*(f&#58; File)&#58; INTEGER; &#32;&#32;BEGIN RETURN f.aleng * SS + f.bleng - HS &#32;&#32;END Length; &#32;&#32;PROCEDURE Date*(f&#58; File)&#58; INTEGER; &#32;&#32;BEGIN RETURN f.date &#32;&#32;END Date; &#32;&#32;(*---Read---*) &#32;&#32;PROCEDURE Set*(VAR r&#58; Rider; f&#58; File; pos&#58; INTEGER); &#32;&#32;&#32;&#32;VAR a, b&#58; INTEGER; &#32;&#32;BEGIN r.eof &#58;&#61; FALSE; r.res &#58;&#61; 0; &#32;&#32;&#32;&#32;IF f # NIL THEN &#32;&#32;&#32;&#32;&#32;&#32;IF pos &#60; 0 THEN a &#58;&#61; 0; b &#58;&#61; HS &#32;&#32;&#32;&#32;&#32;&#32;ELSIF pos &#60; f.aleng * SS + f.bleng - HS THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;a &#58;&#61; (pos + HS) DIV SS; b &#58;&#61; (pos + HS) MOD SS; &#32;&#32;&#32;&#32;&#32;&#32;ELSE a &#58;&#61; f.aleng; b &#58;&#61; f.bleng &#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;&#32;&#32;r.file &#58;&#61; f; r.apos &#58;&#61; a; r.bpos &#58;&#61; b; r.buf &#58;&#61; f.firstbuf &#32;&#32;&#32;&#32;ELSE r.file&#58;&#61; NIL &#32;&#32;&#32;&#32;END &#32;&#32;END Set; &#32;&#32;PROCEDURE Pos*(VAR r&#58; Rider)&#58; INTEGER; &#32;&#32;BEGIN RETURN r.apos * SS + r.bpos - HS &#32;&#32;END Pos; &#32;&#32;PROCEDURE Base*(VAR r&#58; Rider)&#58; File; &#32;&#32;BEGIN RETURN r.file &#32;&#32;END Base; &#32;&#32;PROCEDURE ReadByte*(VAR r&#58; Rider; VAR x&#58; BYTE); &#32;&#32;&#32;&#32;VAR buf&#58; Buffer; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF r.apos # r.buf.apos THEN r.buf &#58;&#61; GetBuf(r.file, r.apos) END ; &#32;&#32;&#32;&#32;IF r.bpos &#60; r.buf.lim THEN x &#58;&#61; r.buf.data&#91;r.bpos&#93;; INC(r.bpos) &#32;&#32;&#32;&#32;ELSIF r.apos &#60; r.file.aleng THEN &#32;&#32;&#32;&#32;&#32;&#32;INC(r.apos); buf &#58;&#61; Buf(r.file, r.apos); &#32;&#32;&#32;&#32;&#32;&#32;IF buf &#61; NIL THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF r.buf.mod THEN WriteBuf(r.file, r.buf) END ; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ReadBuf(r.file, r.buf, r.apos) &#32;&#32;&#32;&#32;&#32;&#32;ELSE r.buf &#58;&#61; buf &#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;&#32;&#32;x &#58;&#61; r.buf.data&#91;0&#93;; r.bpos &#58;&#61; 1 &#32;&#32;&#32;&#32;ELSE x &#58;&#61; 0; r.eof &#58;&#61; TRUE &#32;&#32;&#32;&#32;END &#32;&#32;END ReadByte; &#32;&#32;PROCEDURE ReadBytes*(VAR r&#58; Rider; VAR x&#58; ARRAY OF BYTE; n&#58; INTEGER); &#32;&#32;&#32;&#32;VAR i&#58; INTEGER; &#32;&#32;BEGIN i &#58;&#61; 0; (*this implementation is to be improved*) &#32;&#32;&#32;&#32;WHILE i &#60; n DO ReadByte(r, x&#91;i&#93;); INC(i) END &#32;&#32;END ReadBytes; &#32;&#32;PROCEDURE Read*(VAR r&#58; Rider; VAR ch&#58; CHAR); &#32;&#32;&#32;&#32;VAR buf&#58; Buffer; (*same as ReadByte*) &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF r.apos # r.buf.apos THEN r.buf &#58;&#61; GetBuf(r.file, r.apos) END ; &#32;&#32;&#32;&#32;IF r.bpos &#60; r.buf.lim THEN ch &#58;&#61; CHR(r.buf.data&#91;r.bpos&#93;); INC(r.bpos) &#32;&#32;&#32;&#32;ELSIF r.apos &#60; r.file.aleng THEN &#32;&#32;&#32;&#32;&#32;&#32;INC(r.apos); buf &#58;&#61; Buf(r.file, r.apos); &#32;&#32;&#32;&#32;&#32;&#32;IF buf &#61; NIL THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF r.buf.mod THEN WriteBuf(r.file, r.buf) END ; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ReadBuf(r.file, r.buf, r.apos) &#32;&#32;&#32;&#32;&#32;&#32;ELSE r.buf &#58;&#61; buf &#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;&#32;&#32;ch &#58;&#61; CHR(r.buf.data&#91;0&#93;); r.bpos &#58;&#61; 1 &#32;&#32;&#32;&#32;ELSE ch &#58;&#61; 0X; r.eof &#58;&#61; TRUE &#32;&#32;&#32;&#32;END &#32;&#32;END Read; &#32;&#32;PROCEDURE ReadInt*(VAR R&#58; Rider; VAR x&#58; INTEGER); &#32;&#32;&#32;&#32;VAR x0, x1, x2, x3&#58; BYTE; &#32;&#32;BEGIN ReadByte(R, x0); ReadByte(R, x1); ReadByte(R, x2); ReadByte(R, x3); &#32;&#32;&#32;&#32;x &#58;&#61; ((x3 * 100H + x2) * 100H + x1) * 100H + x0 &#32;&#32;END ReadInt; &#32;&#32;PROCEDURE ReadSet*(VAR R&#58; Rider; VAR s&#58; SET); &#32;&#32;&#32;&#32;VAR n&#58; INTEGER; &#32;&#32;BEGIN ReadInt(R, SYSTEM.VAL(INTEGER, s)) &#32;&#32;END ReadSet; &#32;&#32;PROCEDURE ReadReal*(VAR R&#58; Rider; VAR x&#58; REAL); &#32;&#32;&#32;&#32;VAR n&#58; INTEGER; &#32;&#32;BEGIN ReadInt(R, SYSTEM.VAL(INTEGER, x)) &#32;&#32;END ReadReal; &#32;&#32;PROCEDURE ReadString*(VAR R&#58; Rider; VAR x&#58; ARRAY OF CHAR); &#32;&#32;&#32;&#32;VAR i&#58; INTEGER; ch&#58; CHAR; &#32;&#32;BEGIN i &#58;&#61; 0; Read(R, ch); &#32;&#32;&#32;&#32;WHILE ch # 0X DO &#32;&#32;&#32;&#32;&#32;&#32;IF i &#60; LEN(x)-1 THEN x&#91;i&#93; &#58;&#61; ch; INC(i) END ; &#32;&#32;&#32;&#32;&#32;&#32;Read(R, ch) &#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;x&#91;i&#93; &#58;&#61; 0X &#32;&#32;END ReadString; &#32;&#32;PROCEDURE ReadNum*(VAR R&#58; Rider; VAR x&#58; INTEGER); &#32;&#32;&#32;&#32;VAR n, y&#58; INTEGER; b&#58; BYTE; &#32;&#32;BEGIN n &#58;&#61; 32; y &#58;&#61; 0; ReadByte(R, b); &#32;&#32;&#32;&#32;WHILE b &#62;&#61; 80H DO y &#58;&#61; ROR(y + b-80H, 7); DEC(n, 7); ReadByte(R, b) END ; &#32;&#32;&#32;&#32;IF n &#60;&#61; 4 THEN x &#58;&#61; ROR(y + b MOD 10H, 4) ELSE x &#58;&#61; ASR(ROR(y + b, 7), n-7) END &#32;&#32;END ReadNum; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32; &#32;&#32;(*---Write---*) &#32;&#32;PROCEDURE NewExt(f&#58; File); &#32;&#32;&#32;&#32;VAR i, k&#58; INTEGER; ext&#58; Index; &#32;&#32;BEGIN k &#58;&#61; (f.aleng - STS) DIV XS; &#32;&#32;&#32;&#32;NEW(ext); ext.adr &#58;&#61; 0; ext.mod &#58;&#61; TRUE; f.ext&#91;k&#93; &#58;&#61; ext; i &#58;&#61; XS; &#32;&#32;&#32;&#32;REPEAT DEC(i); ext.sec&#91;i&#93; &#58;&#61; 0 UNTIL i &#61; 0 &#32;&#32;END NewExt; &#32;&#32;PROCEDURE WriteByte*(VAR r&#58; Rider; x&#58; BYTE); &#32;&#32;&#32;&#32;VAR f&#58; File; buf&#58; Buffer; &#32;&#32;BEGIN &#32;&#32;&#32;&#32;IF r.apos # r.buf.apos THEN r.buf &#58;&#61; GetBuf(r.file, r.apos); END ; &#32;&#32;&#32;&#32;IF r.bpos &#62;&#61; r.buf.lim THEN &#32;&#32;&#32;&#32;&#32;&#32;IF r.bpos &#60; SS THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;INC(r.buf.lim); INC(r.file.bleng); r.file.modH &#58;&#61; TRUE &#32;&#32;&#32;&#32;&#32;&#32;ELSE f &#58;&#61; r.file; WriteBuf(f, r.buf); INC(r.apos); buf &#58;&#61; Buf(r.file, r.apos); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF buf &#61; NIL THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF r.apos &#60;&#61; f.aleng THEN ReadBuf(f, r.buf, r.apos) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE r.buf.apos &#58;&#61; r.apos; r.buf.lim &#58;&#61; 1; f.aleng &#58;&#61; f.aleng + 1; f.bleng &#58;&#61; 1; f.modH &#58;&#61; TRUE; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (f.aleng - STS) MOD XS &#61; 0 THEN NewExt(f) END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE r.buf &#58;&#61; buf &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;r.bpos &#58;&#61; 0 &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;r.buf.data&#91;r.bpos&#93; &#58;&#61; x; INC(r.bpos); r.buf.mod &#58;&#61; TRUE &#32;&#32;END WriteByte; &#32;&#32;PROCEDURE WriteBytes*(VAR r&#58; Rider; x&#58; ARRAY OF BYTE; n&#58; INTEGER); &#32;&#32;&#32;&#32;VAR i&#58; INTEGER; &#32;&#32;BEGIN i &#58;&#61; 0; (*this implementation is to be improed*) &#32;&#32;&#32;&#32;WHILE i &#60; n DO WriteByte(r, x&#91;i&#93;); INC(i) END &#32;&#32;END WriteBytes; &#32;&#32;PROCEDURE Write*(VAR r&#58; Rider; ch&#58; CHAR); &#32;&#32;&#32;&#32;VAR f&#58; File; buf&#58; Buffer; &#32;&#32;BEGIN (*same as WriteByte*) &#32;&#32;&#32;&#32;IF r.apos # r.buf.apos THEN r.buf &#58;&#61; GetBuf(r.file, r.apos); END ; &#32;&#32;&#32;&#32;IF r.bpos &#62;&#61; r.buf.lim THEN &#32;&#32;&#32;&#32;&#32;&#32;IF r.bpos &#60; SS THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;INC(r.buf.lim); INC(r.file.bleng); r.file.modH &#58;&#61; TRUE &#32;&#32;&#32;&#32;&#32;&#32;ELSE f &#58;&#61; r.file; WriteBuf(f, r.buf); INC(r.apos); buf &#58;&#61; Buf(r.file, r.apos); &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF buf &#61; NIL THEN &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF r.apos &#60;&#61; f.aleng THEN ReadBuf(f, r.buf, r.apos) &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE r.buf.apos &#58;&#61; r.apos; r.buf.lim &#58;&#61; 1; f.aleng &#58;&#61; f.aleng + 1; f.bleng &#58;&#61; 1; f.modH &#58;&#61; TRUE; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;IF (f.aleng - STS) MOD XS &#61; 0 THEN NewExt(f) END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;ELSE r.buf &#58;&#61; buf &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;r.bpos &#58;&#61; 0 &#32;&#32;&#32;&#32;&#32;&#32;END &#32;&#32;&#32;&#32;END ; &#32;&#32;&#32;&#32;r.buf.data&#91;r.bpos&#93; &#58;&#61; ORD(ch); INC(r.bpos); r.buf.mod &#58;&#61; TRUE &#32;&#32;END Write; &#32;&#32;PROCEDURE WriteInt*(VAR R&#58; Rider; x&#58; INTEGER); &#32;&#32;BEGIN WriteByte(R, x MOD 100H); &#32;&#32;&#32;&#32;WriteByte(R, x DIV 100H MOD 100H); &#32;&#32;&#32;&#32;WriteByte(R, x DIV 10000H MOD 100H); &#32;&#32;&#32;&#32;WriteByte(R, x DIV 1000000H MOD 100H) &#32;&#32;END WriteInt; &#32;&#32;PROCEDURE WriteSet*(VAR R&#58; Rider; s&#58; SET); &#32;&#32;BEGIN WriteInt(R, ORD(s)) &#32;&#32;END WriteSet; &#32;&#32;PROCEDURE WriteReal*(VAR R&#58; Rider; x&#58; REAL); &#32;&#32;BEGIN WriteInt(R, ORD(x)) &#32;&#32;END WriteReal; &#32;&#32;PROCEDURE WriteString*(VAR R&#58; Rider; x&#58; ARRAY OF CHAR); &#32;&#32;&#32;&#32;VAR i&#58; INTEGER; ch&#58; CHAR; &#32;&#32;BEGIN i &#58;&#61; 0; &#32;&#32;&#32;&#32;REPEAT ch &#58;&#61; x&#91;i&#93;; Write(R, ch); INC(i) UNTIL ch &#61; 0X &#32;&#32;END WriteString; &#32;&#32;PROCEDURE WriteNum*(VAR R&#58; Rider; x&#58; INTEGER); &#32;&#32;BEGIN &#32;&#32;&#32;&#32;WHILE (x &#60; -40H) OR (x &#62;&#61; 40H) DO WriteByte(R, x MOD 80H + 80H); x &#58;&#61; ASR(x, 7) END ; &#32;&#32;&#32;&#32;WriteByte(R, x MOD 80H) &#32;&#32;END WriteNum; &#32;&#32;(*---System use---*) &#32;&#32;PROCEDURE Init*; &#32;&#32;BEGIN root &#58;&#61; 0; Kernel.Init; FileDir.Init &#32;&#32;END Init; &#32;&#32;PROCEDURE RestoreList*; (*after mark phase of garbage collection*) &#32;&#32;&#32;&#32;VAR f, f0&#58; INTEGER; &#32;&#32;&#32;&#32;PROCEDURE mark(f&#58; INTEGER)&#58; INTEGER; &#32;&#32;&#32;&#32;&#32;&#32;VAR m&#58; INTEGER; &#32;&#32;&#32;&#32;BEGIN &#32;&#32;&#32;&#32;&#32;&#32;IF f &#61; 0 THEN m &#58;&#61; -1 ELSE SYSTEM.GET(f-4, m) END ; &#32;&#32;&#32;&#32;&#32;&#32;RETURN m &#32;&#32;&#32;&#32;END mark; &#32;&#32;BEGIN (*field "next" has offset 0*) &#32;&#32;&#32;&#32;WHILE mark(root) &#61; 0 DO SYSTEM.GET(root, root) END ; &#32;&#32;&#32;&#32;f &#58;&#61; root; &#32;&#32;&#32;&#32;WHILE f # 0 DO &#32;&#32;&#32;&#32;&#32;&#32;f0 &#58;&#61; f; &#32;&#32;&#32;&#32;&#32;&#32;REPEAT SYSTEM.GET(f0, f0) UNTIL mark(f0) # 0; &#32;&#32;&#32;&#32;&#32;&#32;SYSTEM.PUT(f, f0); f &#58;&#61; f0 &#32;&#32;&#32;&#32;END &#32;&#32;END RestoreList; END Files.