%begin; !Filestore Boot Area Manipulator ! Revised version: directory is now two blocks long, and there are ! two independent boot areas, each 1024 blocks long. ! The boot area is a contiguous collection of 512-byte disk blocks, ! which contains textually named files, suitable for reading into ! the controlling machine's memory using the LOADFILE routine in ROM. ! The first block is used as a directory. ! Directory layout (256 32-bit words): ! First longword is a checksum such that the sum of all 256 longwords is 0. ! Remainder comprises of 42 24-byte records plus an extra longword which is ! treated as part of a 43rd 24-byte record. This longword must be 0. ! Each of the file records is a size-name pair. Null names denote ! free space. Zero size denotes the end of the file-record-list. The ! sizes are in bytes. All chunks start at block boundaries. The position ! of file n+1 is given by that of file n, plus the size of file n, rounded ! up to the next block boundary. Sizes of free chunks are multiples of the ! block size. %constinteger maxslot=42,dirlongs=256 %recordformat file f (%integer size, %string(19) name) %recordformat dir f ((%integer sum, %record(filef)%array file(1:maxslot+1)) %c %or %integerarray w(1:dirlongs)) %record(filef)%name file %integer filepos %record(dirf)dir %integer dir xno = 0, offset = 0 %include "i:fs.inc" %include "i:util.inc" %routine error(%string(255)s) selectoutput(0); printstring(s); newline %signal 3 %end %routine hdhtos(%integer n,%string(*)%name s) s = tostring(n>>8+'0') s = s.tostring(n>>4&15+'0') s = s.tostring(n&15+'0') %end %routine close boot area %integer x x = fcomm('K0'+dirxno,"") %unless dirxno=0 dir xno = 0 %end %routine open boot area dir xno = fcomm('A'<<8,"$:BOOTAREA") %if dirxno=0 %end %routine bootread(%integer byte,buffer) %string(3)b %integer n hdhtos((offset+byte)>>9,b) n = fcommr('R0'+dirxno,b,byteinteger(buffer),512) %unless n=512 %start printstring("R:"); write(n,1); newline %finish %end %routine bootwrite(%integer byte,buffer) %string(7)b hdhtos((offset+byte)>>9,b); b = b."," fcommw('W0'+dirxno,b,byteinteger(buffer),512) %end %routine read dir %integer i,a,sum=0 %returnunless dirxno=0 open boot area dir = 0 a = addr(dir) bootread(0,a); bootread(512,a+512) sum = sum+dir_w(i) %for i = 1,1,dirlongs error("Directory checksum error") %unless sum=0 %end %routine write dir %integer i,a,sum=0 sum = sum-dir_w(i) %for i = 2,1,dirlongs dir_sum = sum a = addr(dir) bootwrite(0,a); bootwrite(512,a+512) close bootarea %end %predicate same(%string(*)%name a,b) %integer i,j,k i = length(a); %falseunless i=length(b) %while i>0 %cycle j = charno(a,i); k = charno(b,i)!!j %if k#0 %start %falseunless k=32 %and 'a'<=j!32<='z' %finish i = i-1 %repeat %true %end %routine find(%integer minsize,%string(19)name) %integer i,j read dir filepos = 0; i = 1 %cycle file == dir_file(i); j = file_size error(name." not found") %if j<=0 %returnif j>=minsize %and same(file_name,name) filepos = filepos+((j+511)&\511) i = i+1 %repeat %end %routine rename(%string(19)s,t) find(1,s); file_name = t; write dir %end %routine delete(%string(19)s) %integer i,j %record(filef)%name f,g find(1,s) file_size = (file_size+511)&\511; file_name = "" i = 1 %cycle f == dir_file(i); g == dir_file(i+1) %exitif f_size=0 %or g_size=0 %if f_name="" %and g_name="" %start f_size = f_size+g_size dir_file(j) = dir_file(j+1) %for j = i+1,1,maxslot %finishelse i = i+1 %repeat write dir %end %routine inject(%integer pos,size,%string(19)name) %integer i,low,high,rest %record(filef)%name f,g,h %record(filef)%map elbow(%integer p) %integer i error("No slot") %if dir_file(maxslot)_size#0 dir_file(i+1) = dir_file(i) %for i = maxslot-1,-1,p %result == dir_file(p) %end read dir i = 1; low = 0 %cycle f == dir_file(i) error("Cannot insert ".name) %if f_size=0 high = low+f_size %if low<=pos=size %and f_name="" %start %if low=pos %start %unless pos+((size+511)&\511)=high %start g == elbow(i+1); g = 0 g_size = f_size-((size+511)&\511) %finish f_size = size; f_name = name %else g == elbow(i+1); g = 0 h == elbow(i+2); h = 0 f_size = pos-low g_size = size; g_name = name h_size = high-pos-((size+511)&\511) %finish %exit %finish high = low+((f_size+511)&\511); low = high i = i+1 %repeat write dir %end %routine writefile(%string(19)from,to) %integer start,length,pos connectfile(from,0,start,length) find(length,"") pos = 0 %cycle bootwrite(filepos+pos,start+pos) pos = pos+512 %repeatuntil pos>=length inject(filepos,length,to) %end %routine readfile(%string(19)from,to) %bytearray data(1:512) %integer pos,i find(1,from) openoutput(1,to); selectoutput(1) pos = 0 %cycle bootread(filepos+pos,addr(data(1))) %for i = 1,1,512 %cycle printsymbol(data(i)) %if i-1+pos=file_size closeoutput %end %routine comparefile(%string(19)boot,normal) %bytearray data(1:512) %integer start,length,pos,i find(1,boot) connectfile(normal,0,start,length) pos = file_size-length %unless pos=0 %start printstring(boot." is ") write(|pos|,0); printstring(" bytes ") %if pos>0 %then printstring("longer") %else printstring("shorter") printstring(" than ".normal) newline; %return %finish pos = 0 %cycle bootread(filepos+pos,addr(data(1))) %for i = 1,1,512 %cycle %if pos+i>length %start printstring(boot." and ".normal." are identical") newline; %return %finish %unless byteinteger(start+pos+i-1)=data(i) %start printstring(boot."="); phex2(data(i)) printstring(" and ".normal."="); phex2(byteinteger(start+pos+i-1)) printstring(" differ at byte "); write(pos+i-1,0) newline; %return %finish %repeat pos = pos+512 %repeat %end %routine bad(%integer block,blocks) inject(block<<9-offset,blocks<<9,"BadArea") %end %routine init(%integer blocks) open boot area dir = 0 file == dir_file(1); file_size = dirlongs<<2; file_name = "Directory" file == dir_file(2); file_size = blocks<<9-dirlongs<<2 write dir %end %routine files %integer i,pos=0 read dir %for i = 1,1,maxslot %cycle file == dir_file(i) %unless file_size=0 %and file_name="" %start write(i,2); space phex(pos); space; phex(file_size); space; printstring(file_name); newline pos = pos+((file_size+511)&\511) %finish %repeat %end %routine look at key @16_400031 %byte key printstring("Default area "); printsymbol(key&1+'0') offset = (key&1)<<(10+9) newline %end %routine help printstring("A - Select Area (0 or 1)"); newline printstring("I - Initialise directory (Blocks)"); newline printstring("B - Note Bad Area (Blockno,blocks)"); newline printstring("F - List Files ()"); newline printstring("W - Write File (Normal-source,Boot-dest)"); newline printstring("R - Read File (Boot-source,Normal-dest)"); newline printstring("C - Compare File (Boot-source,Normal-source"); newline printstring("D - Delete File (Boot)"); newline printstring("N - Rename File (Oldboot,Newboot)"); newline printstring("E - Exit ()"); newline %end %routine mmi %integer sym,i,j %string(19)s,t %routine readother read {string}(t); t = s %if t="=" %end %onevent 3,9 %start selectoutput(0) write(event_event,0); write(event_sub,1); write(event_extra,1); space printstring(event_message); newline %finish selectoutput(0); selectinput(0); prompt(">") %cycle selectoutput(0) readsymbol(sym) %and sym = sym!32 %until 'a'<=sym<='z' %exitif sym='e' %if sym='i' %start prompt("Size(blocks) of boot area:") read(i) %if i>1024 %and offset=0 %start printstring("That would overwrite the second directory"); newline %else init(i) %finish %elseif sym='a' prompt("Area:"); read(i) close boot area offset = (i&1)<<(10+9) printstring("Using area "); printsymbol(i&1+'0'); newline %elseif sym='b' prompt("Bad area at block:"); read(i) prompt("Size(blocks):"); read(j) bad(i,j) %elseif sym='f' files %elseif sym='w' prompt("From:"); read {string}(s) prompt("To:"); readother writefile(s,t) %elseif sym='r' prompt("From:"); read {string}(s) prompt("To:"); readother readfile(s,t) %elseif sym='c' prompt("Boot area file:"); read {string}(s) prompt("File system file:"); readother comparefile(s,t) %elseif sym='d' prompt("File:") read {string}(s); delete(s) %elseif sym='n' prompt("File:"); read {string}(s) prompt("Newname:"); read {string}(t) rename(s,t) %else help %finish selectinput(0); prompt(">") readsymbol(sym) %until sym=nl %repeat %end look at key mmi close boot area %endofprogram