1
0

Files.Mod.txt 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. MODULE Files; (*NW 11.1.86 / 22.9.93 / 25.5.95 / 25.12.95 / 15.8.2013*)
  2. IMPORT SYSTEM, Kernel, FileDir;
  3. (*A file consists of a sequence of pages. The first page
  4. contains the header. Part of the header is the page table, an array
  5. of disk addresses to the pages. A file is referenced through riders.
  6. A rider indicates a current position and refers to a file*)
  7. CONST MaxBufs = 4;
  8. HS = FileDir.HeaderSize;
  9. SS = FileDir.SectorSize;
  10. STS = FileDir.SecTabSize;
  11. XS = FileDir.IndexSize;
  12. TYPE DiskAdr = INTEGER;
  13. File* = POINTER TO FileDesc;
  14. Buffer = POINTER TO BufferRecord;
  15. Index = POINTER TO IndexRecord;
  16. Rider* =
  17. RECORD eof*: BOOLEAN;
  18. res*: INTEGER;
  19. file: File;
  20. apos, bpos: INTEGER;
  21. buf: Buffer
  22. END ;
  23. FileDesc =
  24. RECORD next: INTEGER; (*list of files invisible to the GC*)
  25. nofbufs, aleng, bleng: INTEGER;
  26. modH, registered: BOOLEAN;
  27. firstbuf: Buffer;
  28. sechint: DiskAdr;
  29. name: FileDir.FileName;
  30. date: INTEGER;
  31. ext: ARRAY FileDir.ExTabSize OF Index;
  32. sec: FileDir.SectorTable
  33. END ;
  34. BufferRecord =
  35. RECORD apos, lim: INTEGER;
  36. mod: BOOLEAN;
  37. next: Buffer;
  38. data: FileDir.DataSector
  39. END ;
  40. IndexRecord =
  41. RECORD adr: DiskAdr;
  42. mod: BOOLEAN;
  43. sec: FileDir.IndexSector
  44. END ;
  45. (*aleng * SS + bleng = length (including header)
  46. apos * SS + bpos = current position
  47. 0 <= bpos <= lim <= SS
  48. 0 <= apos <= aleng < PgTabSize
  49. (apos < aleng) & (lim = SS) OR (apos = aleng) *)
  50. VAR root: INTEGER (*File*); (*list of open files*)
  51. PROCEDURE Check(s: ARRAY OF CHAR;
  52. VAR name: FileDir.FileName; VAR res: INTEGER);
  53. VAR i: INTEGER; ch: CHAR;
  54. BEGIN ch := s[0]; i := 0;
  55. IF (ch >= "A") & (ch <= "Z") OR (ch >= "a") & (ch <= "z") THEN
  56. REPEAT name[i] := ch; INC(i); ch := s[i]
  57. UNTIL ~((ch >= "0") & (ch <= "9") OR (ch >= "A") & (ch <= "Z")
  58. OR (ch >= "a") & (ch <= "z") OR (ch = ".")) OR (i = FileDir.FnLength);
  59. IF i = FileDir.FnLength THEN res := 4
  60. ELSIF ch = 0X THEN res := 0;
  61. WHILE i < FileDir.FnLength DO name[i] := 0X; INC(i) END
  62. ELSE res := 5
  63. END
  64. ELSIF ch = 0X THEN name[0] := 0X; res := -1
  65. ELSE res := 3
  66. END
  67. END Check;
  68. PROCEDURE Old*(name: ARRAY OF CHAR): File;
  69. VAR i, k, res: INTEGER;
  70. f: File;
  71. header: DiskAdr;
  72. buf: Buffer;
  73. F: FileDir.FileHd;
  74. namebuf: FileDir.FileName;
  75. inxpg: Index;
  76. BEGIN f := NIL; Check(name, namebuf, res);
  77. IF res = 0 THEN
  78. FileDir.Search(namebuf, header);
  79. IF header # 0 THEN
  80. f := SYSTEM.VAL(File, root);
  81. WHILE (f # NIL) & (f.sec[0] # header) DO f := SYSTEM.VAL(File, f.next) END ;
  82. IF f = NIL THEN (*file not yet present*)
  83. NEW(buf); buf.apos := 0; buf.next := buf; buf.mod := FALSE;
  84. F := SYSTEM.VAL(FileDir.FileHd, SYSTEM.ADR(buf.data));
  85. Kernel.GetSector(header, buf.data); ASSERT(F.mark = FileDir.HeaderMark);
  86. NEW(f); f.aleng := F.aleng; f.bleng := F.bleng; f.date := F.date;
  87. IF f.aleng = 0 THEN buf.lim := f.bleng ELSE buf.lim := SS END ;
  88. f.firstbuf := buf; f.nofbufs := 1; f.name := namebuf; f.registered := TRUE;
  89. f.sec := F.sec;
  90. k := (f.aleng + (XS-STS)) DIV XS; i := 0;
  91. WHILE i < k DO
  92. NEW(inxpg); inxpg.adr := F.ext[i]; inxpg.mod := FALSE;
  93. Kernel.GetSector(inxpg.adr, inxpg.sec); f.ext[i] := inxpg; INC(i)
  94. END ;
  95. WHILE i < FileDir.ExTabSize DO f.ext[i] := NIL; INC(i) END ;
  96. f.sechint := header; f.modH := FALSE; f.next := root; root := SYSTEM.VAL(INTEGER, f)
  97. END
  98. END
  99. END ;
  100. RETURN f
  101. END Old;
  102. PROCEDURE New*(name: ARRAY OF CHAR): File;
  103. VAR i, res: INTEGER;
  104. f: File;
  105. buf: Buffer;
  106. F: FileDir.FileHd;
  107. namebuf: FileDir.FileName;
  108. BEGIN f := NIL; Check(name, namebuf, res);
  109. IF res <= 0 THEN
  110. NEW(buf); buf.apos := 0; buf.mod := TRUE; buf.lim := HS; buf.next := buf;
  111. F := SYSTEM.VAL(FileDir.FileHd, SYSTEM.ADR(buf.data));
  112. F.mark := FileDir.HeaderMark;
  113. F.aleng := 0; F.bleng := HS; F.name := namebuf;
  114. F.date := Kernel.Clock();
  115. NEW(f); f.aleng := 0; f.bleng := HS; f.modH := TRUE;
  116. f.registered := FALSE; f.date := F.date;
  117. f.firstbuf := buf; f.nofbufs := 1; f.name := namebuf; f.sechint := 0;
  118. i := 0;
  119. REPEAT f.ext[i] := NIL; F.ext[i] := 0; INC(i) UNTIL i = FileDir.ExTabSize;
  120. i := 0;
  121. REPEAT f.sec[i] := 0; F.sec[i] := 0; INC(i) UNTIL i = STS
  122. END ;
  123. RETURN f
  124. END New;
  125. PROCEDURE UpdateHeader(f: File; VAR F: FileDir.FileHeader);
  126. VAR k: INTEGER;
  127. BEGIN F.aleng := f.aleng; F.bleng := f.bleng;
  128. F.sec := f.sec; k := (f.aleng + (XS-STS)) DIV XS;
  129. WHILE k > 0 DO DEC(k); F.ext[k] := f.ext[k].adr END
  130. END UpdateHeader;
  131. PROCEDURE ReadBuf(f: File; buf: Buffer; pos: INTEGER);
  132. VAR sec: DiskAdr;
  133. BEGIN
  134. IF pos < STS THEN sec := f.sec[pos]
  135. ELSE sec := f.ext[(pos-STS) DIV XS].sec[(pos-STS) MOD XS]
  136. END ;
  137. Kernel.GetSector(sec, buf.data);
  138. IF pos < f.aleng THEN buf.lim := SS ELSE buf.lim := f.bleng END ;
  139. buf.apos := pos; buf.mod := FALSE
  140. END ReadBuf;
  141. PROCEDURE WriteBuf(f: File; buf: Buffer);
  142. VAR i, k: INTEGER;
  143. secadr: DiskAdr; inx: Index;
  144. BEGIN
  145. IF buf.apos < STS THEN
  146. secadr := f.sec[buf.apos];
  147. IF secadr = 0 THEN
  148. Kernel.AllocSector(f.sechint, secadr);
  149. f.modH := TRUE; f.sec[buf.apos] := secadr; f.sechint := secadr
  150. END ;
  151. IF buf.apos = 0 THEN
  152. UpdateHeader(f, SYSTEM.VAL(FileDir.FileHeader, buf.data)); f.modH := FALSE
  153. END
  154. ELSE i := (buf.apos - STS) DIV XS; inx := f.ext[i];
  155. IF inx = NIL THEN
  156. NEW(inx); inx.adr := 0; inx.sec[0] := 0; f.ext[i] := inx; f.modH := TRUE
  157. END ;
  158. k := (buf.apos - STS) MOD XS; secadr := inx.sec[k];
  159. IF secadr = 0 THEN
  160. Kernel.AllocSector(f.sechint, secadr);
  161. f.modH := TRUE; inx.mod := TRUE; inx.sec[k] := secadr; f.sechint := secadr
  162. END
  163. END ;
  164. Kernel.PutSector(secadr, buf.data); buf.mod := FALSE
  165. END WriteBuf;
  166. PROCEDURE Buf(f: File; pos: INTEGER): Buffer;
  167. VAR buf: Buffer;
  168. BEGIN buf := f.firstbuf;
  169. WHILE (buf.apos # pos) & (buf.next # f.firstbuf) DO buf := buf.next END ;
  170. IF buf.apos # pos THEN buf := NIL END ;
  171. RETURN buf
  172. END Buf;
  173. PROCEDURE GetBuf(f: File; pos: INTEGER): Buffer;
  174. VAR buf: Buffer;
  175. BEGIN buf := f.firstbuf;
  176. WHILE (buf.apos # pos) & (buf.next # f.firstbuf) DO buf := buf.next END ;
  177. IF buf.apos # pos THEN
  178. IF f.nofbufs < MaxBufs THEN (*allocate new buffer*)
  179. NEW(buf); buf.next := f.firstbuf.next; f.firstbuf.next := buf; INC(f.nofbufs)
  180. ELSE (*reuse a buffer*) f.firstbuf := buf;
  181. IF buf.mod THEN WriteBuf(f, buf) END
  182. END ;
  183. IF pos <= f.aleng THEN ReadBuf(f, buf, pos) ELSE buf.apos := pos; buf.lim := 0; buf.mod := FALSE END
  184. END ;
  185. RETURN buf
  186. END GetBuf;
  187. PROCEDURE Unbuffer(f: File);
  188. VAR i, k: INTEGER;
  189. buf: Buffer;
  190. inx: Index;
  191. head: FileDir.FileHeader;
  192. BEGIN buf := f.firstbuf;
  193. REPEAT
  194. IF buf.mod THEN WriteBuf(f, buf) END ;
  195. buf := buf.next
  196. UNTIL buf = f.firstbuf;
  197. k := (f.aleng + (XS-STS)) DIV XS; i := 0;
  198. WHILE i < k DO
  199. inx := f.ext[i]; INC(i);
  200. IF inx.mod THEN
  201. IF inx.adr = 0 THEN
  202. Kernel.AllocSector(f.sechint, inx.adr); f.sechint := inx.adr; f.modH := TRUE
  203. END ;
  204. Kernel.PutSector(inx.adr, inx.sec); inx.mod := FALSE
  205. END
  206. END ;
  207. IF f.modH THEN
  208. Kernel.GetSector(f.sec[0], head); UpdateHeader(f, head);
  209. Kernel.PutSector(f.sec[0], head); f.modH := FALSE
  210. END
  211. END Unbuffer;
  212. PROCEDURE Register*(f: File);
  213. BEGIN
  214. IF (f # NIL) & (f.name[0] # 0X) THEN
  215. Unbuffer(f);
  216. IF ~f.registered THEN
  217. FileDir.Insert(f.name, f.sec[0]); f.registered := TRUE; f.next := root; root := SYSTEM.VAL(INTEGER, f)
  218. END
  219. END
  220. END Register;
  221. PROCEDURE Close*(f: File);
  222. BEGIN
  223. IF f # NIL THEN Unbuffer(f) END
  224. END Close;
  225. PROCEDURE Purge*(f: File);
  226. VAR a, i, j, k: INTEGER;
  227. ind: FileDir.IndexSector;
  228. BEGIN
  229. IF f # NIL THEN a := f.aleng + 1; f.aleng := 0; f.bleng := HS;
  230. IF a <= STS THEN i := a;
  231. ELSE i := STS; DEC(a, i); j := (a-1) MOD XS; k := (a-1) DIV XS;
  232. WHILE k >= 0 DO
  233. Kernel.GetSector(f.ext[k].adr, ind);
  234. REPEAT DEC(j); Kernel.FreeSector(ind[j]) UNTIL j = 0;
  235. Kernel.FreeSector(f.ext[k].adr); j := XS; DEC(k)
  236. END
  237. END ;
  238. REPEAT DEC(i); Kernel.FreeSector(f.sec[i]) UNTIL i = 0
  239. END
  240. END Purge;
  241. PROCEDURE Delete*(name: ARRAY OF CHAR; VAR res: INTEGER);
  242. VAR adr: DiskAdr;
  243. namebuf: FileDir.FileName;
  244. BEGIN Check(name, namebuf, res);
  245. IF res = 0 THEN
  246. FileDir.Delete(namebuf, adr);
  247. IF adr = 0 THEN res := 2 END
  248. END
  249. END Delete;
  250. PROCEDURE Rename*(old, new: ARRAY OF CHAR; VAR res: INTEGER);
  251. VAR adr: DiskAdr;
  252. oldbuf, newbuf: FileDir.FileName;
  253. head: FileDir.FileHeader;
  254. BEGIN Check(old, oldbuf, res);
  255. IF res = 0 THEN
  256. Check(new, newbuf, res);
  257. IF res = 0 THEN
  258. FileDir.Delete(oldbuf, adr);
  259. IF adr # 0 THEN
  260. FileDir.Insert(newbuf, adr);
  261. Kernel.GetSector(adr, head); head.name := newbuf; Kernel.PutSector(adr, head)
  262. ELSE res := 2
  263. END
  264. END
  265. END
  266. END Rename;
  267. PROCEDURE Length*(f: File): INTEGER;
  268. BEGIN RETURN f.aleng * SS + f.bleng - HS
  269. END Length;
  270. PROCEDURE Date*(f: File): INTEGER;
  271. BEGIN RETURN f.date
  272. END Date;
  273. (*---------------------------Read---------------------------*)
  274. PROCEDURE Set*(VAR r: Rider; f: File; pos: INTEGER);
  275. VAR a, b: INTEGER;
  276. BEGIN r.eof := FALSE; r.res := 0;
  277. IF f # NIL THEN
  278. IF pos < 0 THEN a := 0; b := HS
  279. ELSIF pos < f.aleng * SS + f.bleng - HS THEN
  280. a := (pos + HS) DIV SS; b := (pos + HS) MOD SS;
  281. ELSE a := f.aleng; b := f.bleng
  282. END ;
  283. r.file := f; r.apos := a; r.bpos := b; r.buf := f.firstbuf
  284. ELSE r.file:= NIL
  285. END
  286. END Set;
  287. PROCEDURE Pos*(VAR r: Rider): INTEGER;
  288. BEGIN RETURN r.apos * SS + r.bpos - HS
  289. END Pos;
  290. PROCEDURE Base*(VAR r: Rider): File;
  291. BEGIN RETURN r.file
  292. END Base;
  293. PROCEDURE ReadByte*(VAR r: Rider; VAR x: BYTE);
  294. VAR buf: Buffer;
  295. BEGIN
  296. IF r.apos # r.buf.apos THEN r.buf := GetBuf(r.file, r.apos) END ;
  297. IF r.bpos < r.buf.lim THEN x := r.buf.data[r.bpos]; INC(r.bpos)
  298. ELSIF r.apos < r.file.aleng THEN
  299. INC(r.apos); buf := Buf(r.file, r.apos);
  300. IF buf = NIL THEN
  301. IF r.buf.mod THEN WriteBuf(r.file, r.buf) END ;
  302. ReadBuf(r.file, r.buf, r.apos)
  303. ELSE r.buf := buf
  304. END ;
  305. x := r.buf.data[0]; r.bpos := 1
  306. ELSE x := 0; r.eof := TRUE
  307. END
  308. END ReadByte;
  309. PROCEDURE ReadBytes*(VAR r: Rider; VAR x: ARRAY OF BYTE; n: INTEGER);
  310. VAR i: INTEGER;
  311. BEGIN i := 0; (*this implementation is to be improved*)
  312. WHILE i < n DO ReadByte(r, x[i]); INC(i) END
  313. END ReadBytes;
  314. PROCEDURE Read*(VAR r: Rider; VAR ch: CHAR);
  315. VAR buf: Buffer; (*same as ReadByte*)
  316. BEGIN
  317. IF r.apos # r.buf.apos THEN r.buf := GetBuf(r.file, r.apos) END ;
  318. IF r.bpos < r.buf.lim THEN ch := CHR(r.buf.data[r.bpos]); INC(r.bpos)
  319. ELSIF r.apos < r.file.aleng THEN
  320. INC(r.apos); buf := Buf(r.file, r.apos);
  321. IF buf = NIL THEN
  322. IF r.buf.mod THEN WriteBuf(r.file, r.buf) END ;
  323. ReadBuf(r.file, r.buf, r.apos)
  324. ELSE r.buf := buf
  325. END ;
  326. ch := CHR(r.buf.data[0]); r.bpos := 1
  327. ELSE ch := 0X; r.eof := TRUE
  328. END
  329. END Read;
  330. PROCEDURE ReadInt*(VAR R: Rider; VAR x: INTEGER);
  331. VAR x0, x1, x2, x3: BYTE;
  332. BEGIN ReadByte(R, x0); ReadByte(R, x1); ReadByte(R, x2); ReadByte(R, x3);
  333. x := ((x3 * 100H + x2) * 100H + x1) * 100H + x0
  334. END ReadInt;
  335. PROCEDURE ReadSet*(VAR R: Rider; VAR s: SET);
  336. VAR n: INTEGER;
  337. BEGIN ReadInt(R, SYSTEM.VAL(INTEGER, s))
  338. END ReadSet;
  339. PROCEDURE ReadReal*(VAR R: Rider; VAR x: REAL);
  340. VAR n: INTEGER;
  341. BEGIN ReadInt(R, SYSTEM.VAL(INTEGER, x))
  342. END ReadReal;
  343. PROCEDURE ReadString*(VAR R: Rider; VAR x: ARRAY OF CHAR);
  344. VAR i: INTEGER; ch: CHAR;
  345. BEGIN i := 0; Read(R, ch);
  346. WHILE ch # 0X DO
  347. IF i < LEN(x)-1 THEN x[i] := ch; INC(i) END ;
  348. Read(R, ch)
  349. END ;
  350. x[i] := 0X
  351. END ReadString;
  352. PROCEDURE ReadNum*(VAR R: Rider; VAR x: INTEGER);
  353. VAR n, y: INTEGER; b: BYTE;
  354. BEGIN n := 32; y := 0; ReadByte(R, b);
  355. WHILE b >= 80H DO y := ROR(y + b-80H, 7); DEC(n, 7); ReadByte(R, b) END ;
  356. IF n <= 4 THEN x := ROR(y + b MOD 10H, 4) ELSE x := ASR(ROR(y + b, 7), n-7) END
  357. END ReadNum;
  358. (*---------------------------Write---------------------------*)
  359. PROCEDURE NewExt(f: File);
  360. VAR i, k: INTEGER; ext: Index;
  361. BEGIN k := (f.aleng - STS) DIV XS;
  362. NEW(ext); ext.adr := 0; ext.mod := TRUE; f.ext[k] := ext; i := XS;
  363. REPEAT DEC(i); ext.sec[i] := 0 UNTIL i = 0
  364. END NewExt;
  365. PROCEDURE WriteByte*(VAR r: Rider; x: BYTE);
  366. VAR f: File; buf: Buffer;
  367. BEGIN
  368. IF r.apos # r.buf.apos THEN r.buf := GetBuf(r.file, r.apos); END ;
  369. IF r.bpos >= r.buf.lim THEN
  370. IF r.bpos < SS THEN
  371. INC(r.buf.lim); INC(r.file.bleng); r.file.modH := TRUE
  372. ELSE f := r.file; WriteBuf(f, r.buf); INC(r.apos); buf := Buf(r.file, r.apos);
  373. IF buf = NIL THEN
  374. IF r.apos <= f.aleng THEN ReadBuf(f, r.buf, r.apos)
  375. ELSE r.buf.apos := r.apos; r.buf.lim := 1; f.aleng := f.aleng + 1; f.bleng := 1; f.modH := TRUE;
  376. IF (f.aleng - STS) MOD XS = 0 THEN NewExt(f) END
  377. END
  378. ELSE r.buf := buf
  379. END ;
  380. r.bpos := 0
  381. END
  382. END ;
  383. r.buf.data[r.bpos] := x; INC(r.bpos); r.buf.mod := TRUE
  384. END WriteByte;
  385. PROCEDURE WriteBytes*(VAR r: Rider; x: ARRAY OF BYTE; n: INTEGER);
  386. VAR i: INTEGER;
  387. BEGIN i := 0; (*this implementation is to be improed*)
  388. WHILE i < n DO WriteByte(r, x[i]); INC(i) END
  389. END WriteBytes;
  390. PROCEDURE Write*(VAR r: Rider; ch: CHAR);
  391. VAR f: File; buf: Buffer;
  392. BEGIN (*same as WriteByte*)
  393. IF r.apos # r.buf.apos THEN r.buf := GetBuf(r.file, r.apos); END ;
  394. IF r.bpos >= r.buf.lim THEN
  395. IF r.bpos < SS THEN
  396. INC(r.buf.lim); INC(r.file.bleng); r.file.modH := TRUE
  397. ELSE f := r.file; WriteBuf(f, r.buf); INC(r.apos); buf := Buf(r.file, r.apos);
  398. IF buf = NIL THEN
  399. IF r.apos <= f.aleng THEN ReadBuf(f, r.buf, r.apos)
  400. ELSE r.buf.apos := r.apos; r.buf.lim := 1; f.aleng := f.aleng + 1; f.bleng := 1; f.modH := TRUE;
  401. IF (f.aleng - STS) MOD XS = 0 THEN NewExt(f) END
  402. END
  403. ELSE r.buf := buf
  404. END ;
  405. r.bpos := 0
  406. END
  407. END ;
  408. r.buf.data[r.bpos] := ORD(ch); INC(r.bpos); r.buf.mod := TRUE
  409. END Write;
  410. PROCEDURE WriteInt*(VAR R: Rider; x: INTEGER);
  411. BEGIN WriteByte(R, x MOD 100H);
  412. WriteByte(R, x DIV 100H MOD 100H);
  413. WriteByte(R, x DIV 10000H MOD 100H);
  414. WriteByte(R, x DIV 1000000H MOD 100H)
  415. END WriteInt;
  416. PROCEDURE WriteSet*(VAR R: Rider; s: SET);
  417. BEGIN WriteInt(R, ORD(s))
  418. END WriteSet;
  419. PROCEDURE WriteReal*(VAR R: Rider; x: REAL);
  420. BEGIN WriteInt(R, ORD(x))
  421. END WriteReal;
  422. PROCEDURE WriteString*(VAR R: Rider; x: ARRAY OF CHAR);
  423. VAR i: INTEGER; ch: CHAR;
  424. BEGIN i := 0;
  425. REPEAT ch := x[i]; Write(R, ch); INC(i) UNTIL ch = 0X
  426. END WriteString;
  427. PROCEDURE WriteNum*(VAR R: Rider; x: INTEGER);
  428. BEGIN
  429. WHILE (x < -40H) OR (x >= 40H) DO WriteByte(R, x MOD 80H + 80H); x := ASR(x, 7) END ;
  430. WriteByte(R, x MOD 80H)
  431. END WriteNum;
  432. (*---------------------------System use---------------------------*)
  433. PROCEDURE Init*;
  434. BEGIN root := 0; Kernel.Init; FileDir.Init
  435. END Init;
  436. PROCEDURE RestoreList*; (*after mark phase of garbage collection*)
  437. VAR f, f0: INTEGER;
  438. PROCEDURE mark(f: INTEGER): INTEGER;
  439. VAR m: INTEGER;
  440. BEGIN
  441. IF f = 0 THEN m := -1 ELSE SYSTEM.GET(f-4, m) END ;
  442. RETURN m
  443. END mark;
  444. BEGIN (*field "next" has offset 0*)
  445. WHILE mark(root) = 0 DO SYSTEM.GET(root, root) END ;
  446. f := root;
  447. WHILE f # 0 DO
  448. f0 := f;
  449. REPEAT SYSTEM.GET(f0, f0) UNTIL mark(f0) # 0;
  450. SYSTEM.PUT(f, f0); f := f0
  451. END
  452. END RestoreList;
  453. END Files.