home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 10
/
Fresh_Fish_10_2352.bin
/
new
/
dev
/
obero
/
oberon
/
projectoberonsrc
/
files.mod
(
.txt
)
< prev
next >
Wrap
Oberon Text
|
1994-10-17
|
16KB
|
484 lines
Syntax10.Scn.Fnt
MODULE Files; (*NW 11.1.86 / 22.9.93*)
IMPORT SYSTEM, Kernel, FileDir;
(*A file consists of a sequence of pages. The first page
contains the header. Part of the header is the page table, an array
of disk addresses to the pages. A file is referenced through riders.
A rider indicates a current position and refers to a file*)
CONST MaxBufs = 4;
HS = FileDir.HeaderSize;
SS = FileDir.SectorSize;
STS = FileDir.SecTabSize;
XS = FileDir.IndexSize;
TYPE DiskAdr = LONGINT;
File* = POINTER TO Handle;
Buffer = POINTER TO BufferRecord;
FileHd = POINTER TO FileDir.FileHeader;
Index = POINTER TO IndexRecord;
Rider* =
RECORD eof*: BOOLEAN;
res*: LONGINT;
file: File;
apos, bpos: INTEGER;
buf: Buffer;
unused: LONGINT
END ;
Handle =
RECORD next: File;
aleng, bleng: INTEGER;
nofbufs: INTEGER;
modH: BOOLEAN;
firstbuf: Buffer;
sechint: DiskAdr;
name: FileDir.FileName;
time, date: LONGINT;
unused: ARRAY 1 OF LONGINT;
ext: ARRAY FileDir.ExTabSize OF Index;
sec: FileDir.SectorTable
END ;
BufferRecord =
RECORD apos, lim: INTEGER;
mod: BOOLEAN;
next: Buffer;
data: FileDir.DataSector
END ;
IndexRecord =
RECORD adr: DiskAdr;
mod: BOOLEAN;
sec: FileDir.IndexSector
END ;
(*aleng * SS + bleng = length (including header)
apos * SS + bpos = current position
0 <= bpos <= lim <= SS
0 <= apos <= aleng < PgTabSize
(apos < aleng) & (lim = SS) OR (apos = aleng) *)
VAR root: File; (*list of open files*)
(*Exported procedure:
Old, New, Register, Close, Purge, Length, GetDate,
Set, Read, ReadBytes, Write, WriteBytes, Pos, Base,
Rename, Delete*)
PROCEDURE Check(VAR s: ARRAY OF CHAR;
VAR name: FileDir.FileName; VAR res: INTEGER);
VAR i: INTEGER; ch: CHAR;
BEGIN ch := s[0]; i := 0;
IF ("A" <= CAP(ch)) & (CAP(ch) <= "Z") THEN
LOOP name[i] := ch; INC(i); ch := s[i];
IF ch = 0X THEN
WHILE i < FileDir.FnLength DO name[i] := 0X; INC(i) END ;
res := 0; EXIT
END ;
IF ~(("A" <= CAP(ch)) & (CAP(ch) <= "Z")
OR ("0" <= ch) & (ch <= "9") OR (ch = ".")) THEN res := 3; EXIT
END ;
IF i = FileDir.FnLength THEN res := 4; EXIT END ;
END
ELSIF ch = 0X THEN name[0] := 0X; res := -1
ELSE res := 3
END
END Check;
PROCEDURE Old*(name: ARRAY OF CHAR): File;
VAR i, k, res: INTEGER;
f: File;
header: DiskAdr;
buf: Buffer;
head: FileHd;
namebuf: FileDir.FileName;
inxpg: Index;
BEGIN f := NIL; Check(name, namebuf, res);
IF res = 0 THEN
FileDir.Search(namebuf, header);
IF header # 0 THEN f := root;
WHILE (f # NIL) & (f.sec[0] # header) DO f := f.next END ;
IF f = NIL THEN
NEW(buf); buf.apos := 0; buf.next := buf; buf.mod := FALSE;
head := SYSTEM.VAL(FileHd, SYSTEM.ADR(buf.data));
Kernel.GetSector(header, head^);
NEW(f); f.aleng := head.aleng; f.bleng := head.bleng;
f.time := head.time; f.date := head.date;
IF f.aleng = 0 THEN buf.lim := f.bleng ELSE buf.lim := SS END ;
f.firstbuf := buf; f.nofbufs := 1; f.name[0] := 0X;
f.sec := head.sec;
k := (f.aleng + (XS-STS)) DIV XS; i := 0;
WHILE i < k DO
NEW(inxpg); inxpg.adr := head.ext[i]; inxpg.mod := FALSE;
Kernel.GetSector(inxpg.adr, inxpg.sec); f.ext[i] := inxpg; INC(i)
END ;
WHILE i < FileDir.ExTabSize DO f.ext[i] := NIL; INC(i) END ;
f.sechint := header; f.modH := FALSE; f.next := root; root := f
END
END
END ;
RETURN f
END Old;
PROCEDURE New*(name: ARRAY OF CHAR): File;
VAR i, res: INTEGER;
f: File;
buf: Buffer;
head: FileHd;
namebuf: FileDir.FileName;
BEGIN f := NIL; Check(name, namebuf, res);
IF res <= 0 THEN
NEW(buf); buf.apos := 0; buf.mod := TRUE; buf.lim := HS; buf.next := buf;
head := SYSTEM.VAL(FileHd, SYSTEM.ADR(buf.data));
head.mark := FileDir.HeaderMark;
head.aleng := 0; head.bleng := HS; head.name := namebuf;
Kernel.GetClock(head.time, head.date);
NEW(f); f.aleng := 0; f.bleng := HS; f.modH := TRUE;
f.time := head.time; f.date := head.date;
f.firstbuf := buf; f.nofbufs := 1; f.name := namebuf; f.sechint := 0;
i := 0;
REPEAT f.ext[i] := NIL; head.ext[i] := 0; INC(i) UNTIL i = FileDir.ExTabSize;
i := 0;
REPEAT f.sec[i] := 0; head.sec[i] := 0; INC(i) UNTIL i = STS
END ;
RETURN f
END New;
PROCEDURE UpdateHeader(f: File; VAR h: FileDir.FileHeader);
VAR k: INTEGER;
BEGIN h.aleng := f.aleng; h.bleng := f.bleng;
h.sec := f.sec; k := (f.aleng + (XS-STS)) DIV XS;
WHILE k > 0 DO DEC(k); h.ext[k] := f.ext[k].adr END
END UpdateHeader;
PROCEDURE ReadBuf(f: File; buf: Buffer; pos: INTEGER);
VAR sec: DiskAdr;
BEGIN
IF pos < STS THEN sec := f.sec[pos]
ELSE sec := f.ext[(pos-STS) DIV XS].sec.x[(pos-STS) MOD XS]
END ;
Kernel.GetSector(sec, buf.data);
IF pos < f.aleng THEN buf.lim := SS ELSE buf.lim := f.bleng END ;
buf.apos := pos; buf.mod := FALSE
END ReadBuf;
PROCEDURE WriteBuf(f: File; buf: Buffer);
VAR i, k: INTEGER;
secadr: DiskAdr; inx: Index;
BEGIN
IF buf.apos < STS THEN
secadr := f.sec[buf.apos];
IF secadr = 0 THEN
Kernel.AllocSector(f.sechint, secadr);
f.modH := TRUE; f.sec[buf.apos] := secadr; f.sechint := secadr
END ;
IF buf.apos = 0 THEN
UpdateHeader(f, SYSTEM.VAL(FileDir.FileHeader, buf.data)); f.modH := FALSE
END
ELSE i := (buf.apos - STS) DIV XS; inx := f.ext[i];
IF inx = NIL THEN
NEW(inx); inx.adr := 0; inx.sec.x[0] := 0; f.ext[i] := inx; f.modH := TRUE
END ;
k := (buf.apos - STS) MOD XS; secadr := inx.sec.x[k];
IF secadr = 0 THEN
Kernel.AllocSector(f.sechint, secadr);
f.modH := TRUE; inx.mod := TRUE; inx.sec.x[k] := secadr; f.sechint := secadr
END
END ;
Kernel.PutSector(secadr, buf.data); buf.mod := FALSE
END WriteBuf;
PROCEDURE Buf(f: File; pos: INTEGER): Buffer;
VAR buf: Buffer;
BEGIN buf := f.firstbuf;
LOOP
IF buf.apos = pos THEN EXIT END ;
buf := buf.next;
IF buf = f.firstbuf THEN buf := NIL; EXIT END
END ;
RETURN buf
END Buf;
PROCEDURE GetBuf(f: File; pos: INTEGER): Buffer;
VAR buf: Buffer;
BEGIN buf := f.firstbuf;
LOOP
IF buf.apos = pos THEN EXIT END ;
IF buf.next = f.firstbuf THEN
IF f.nofbufs < MaxBufs THEN (*allocate new buffer*)
NEW(buf); buf.next := f.firstbuf.next; f.firstbuf.next := buf;
INC(f.nofbufs)
ELSE (*take one of the buffers*) f.firstbuf := buf;
IF buf.mod THEN WriteBuf(f, buf) END
END ;
buf.apos := pos;
IF pos <= f.aleng THEN ReadBuf(f, buf, pos) END ;
EXIT
END ;
buf := buf.next
END ;
RETURN buf
END GetBuf;
PROCEDURE Unbuffer(f: File);
VAR i, k: INTEGER;
buf: Buffer;
inx: Index;
head: FileDir.FileHeader;
BEGIN buf := f.firstbuf;
REPEAT
IF buf.mod THEN WriteBuf(f, buf) END ;
buf := buf.next
UNTIL buf = f.firstbuf;
k := (f.aleng + (XS-STS)) DIV XS; i := 0;
WHILE i < k DO
inx := f.ext[i]; INC(i);
IF inx.mod THEN
IF inx.adr = 0 THEN
Kernel.AllocSector(f.sechint, inx.adr); f.sechint := inx.adr; f.modH := TRUE
END ;
Kernel.PutSector(inx.adr, inx.sec); inx.mod := FALSE
END
END ;
IF f.modH THEN
Kernel.GetSector(f.sec[0], head); UpdateHeader(f, head);
Kernel.PutSector(f.sec[0], head); f.modH := FALSE
END
END Unbuffer;
PROCEDURE Register*(f: File);
BEGIN
IF (f # NIL) & (f.name[0] > 0X) THEN
Unbuffer(f); FileDir.Insert(f.name, f.sec[0]); f.name[0] := 0X; f.next := root; root := f
END ;
END Register;
PROCEDURE Close*(f: File);
BEGIN
IF f # NIL THEN Unbuffer(f) END ;
END Close;
PROCEDURE Purge*(f: File);
VAR a, i, j, k: INTEGER;
ind: FileDir.IndexSector;
BEGIN
IF f # NIL THEN a := f.aleng + 1; f.aleng := 0; f.bleng := HS;
IF a <= STS THEN i := a
ELSE i := STS; DEC(a, i);
j := (a-1) MOD XS + 1; k := (a-1) DIV XS + 1;
REPEAT DEC(k); Kernel.GetSector(f.ext[k].adr, ind);
REPEAT DEC(j); Kernel.FreeSector(ind.x[j]) UNTIL j = 0;
Kernel.FreeSector(f.ext[k].adr); j := XS
UNTIL k = 0
END ;
REPEAT DEC(i); Kernel.FreeSector(f.sec[i]); f.sec[i] := 0
UNTIL i = 0;
f.nofbufs := 1