! B-tree test program %option "-nonstandard-low" %systemroutinespec phex(%integer i) %systemroutinespec phex2(%integer i) ! The following two must be the same as in TREE.CORE %constinteger free size = 256 - 8 %recordformat header fm((%short checksum, %short root, used, flags, free count, %shortarray free(1 : free size), %short should have, seed) %c %or %bytearray b(0 : 511)) %constinteger block slots = 253 %recordformat block fm(%short checksum, %short flags, %byte pointer limit, text limit, %shortarray x(1 : block slots)) %constinteger leaf = 1; ! Hence no child-pointers %ownrecord(header fm) header %externalintegerfnspec compare(%string(*)%name a, b, %integer case) %externalroutinespec L open file(%record(*)%name access, %string(255) filename, %integer mode, compatible, partition, %integername token, size, flags) %externalroutinespec L close file(%record(*)%name access, %integer token, flags) %externalroutinespec L read block(%record(*)%name access, %integer token, block, %integername bytes, %record(*)%name buffer) %owninteger token = 0 ! Diagnostic stuff %routine dump(%integer bytes, %bytename buffer) %integer i, j, k newline i = 0 %while i < bytes %cycle %for j = 0, 1, 15 %cycle %if i + j >= bytes %then space %and space %c %else phex2(byteinteger(addr(buffer) + j)) space %if j & 3 = 3 %repeat printstring(" [") write(i, -3) printstring("] |") %for j = 0, 1, 15 %cycle %if j + i < bytes %start k = byteinteger(addr(buffer) + j) & 127 %if k = 0 %start k = '.' %else %unless ' ' <= k <= '~' k = '_' %finish printsymbol(k) %else space %finish %repeat printsymbol('|') newline i = i + 16; buffer == buffer [16] %repeat newline %end %routine put filtered(%string(255) s) %integer i, ch %return %if s = "" %for i = 1, 1, length(s) %cycle ch = charno(s, i) %if ' ' <= ch <= '~' %start print symbol(ch) %else print symbol('<') write(ch, 0) print symbol('>') %finish %repeat %end %owninteger have %ownstring(255) previous key %routine print tree(%integer root, indent) %record(block fm) b %shortname p %integer i, bytes %string(*)%name k %unless 0 < root <= header_used %start printstring("Invalid block address ") write(root, 0); newline %signal 13, root %finish L read block(nil, token, root, bytes, b) !! spaces(indent) !! printstring("Pointer limit = "); write(b_pointer limit, 0) !! printstring(", text limit = "); write(b_text limit, 0) !! newline %signal 13, b_pointer limit, b_text limit %c %unless 0 < b_pointer limit < b_text limit indent = indent + 3 %if b_flags & leaf = 0 %start print tree(b_x(1), indent) i = b_pointer limit - 1 p == b_x(2) %else i = b_pointer limit p == b_x(1) %finish %while i > 0 %cycle write(root, indent); printstring(": ") phex(integer(addr(p) + 2)); spaces(2) k == string(addr(b_x(p))); put filtered(k); newline p == p [3] %unless compare(previous key, k, 0) < 0 %start printstring("*** Sort order error ***"); newline %finish previous key = k i = i - 3 have = have + 1 %if b_flags & leaf = 0 %start print tree(p, indent) p == p [1]; i = i - 1 %finish %repeat %end %routine analyse one(%integer n, %record(block fm)%name b) %shortname p %integer i printstring("Block "); write(n, 0); newline printstring(" Pointer limit = "); write(b_pointer limit, 0) printstring(", text limit = "); write(b_text limit, 0) newline %return %unless 0 < b_pointer limit < b_text limit %if b_flags & leaf = 0 %start printstring(" -> "); write(b_x(1), 0) newline i = b_pointer limit - 1 p == b_x(2) %else i = b_pointer limit p == b_x(1) %finish %while i > 0 %cycle phex(integer(addr(p) + 2)); spaces(3) %unless b_text limit <= p <= block slots %start printstring("Dud text pointer "); write(p, 0) p == p [3] %else put filtered(string(addr(b_x(p)))); p == p [3] %finish newline i = i - 3 %if b_flags & leaf = 0 %start printstring(" -> "); write(p, 0) newline p == p [1]; i = i - 1 %finish %repeat %end ! Test program %begin %record(block fm) b %string(255) file %integer command, size, flags, n, bytes %on 3, 4, 9 %start printstring("%signal "); write(event_event, 0) space; write(event_sub, 0) space; write(event_extra, 0) space; printstring(event_message); newline -> done %if token > 0 %stop %finish open input(0, ":T"); select input(0) open output(0, ":T"); select output(0) prompt("File: "); read(file) L open file(nil, file, 16_4001, -1, -1, token, size, flags) L read block(nil, token, 0, bytes, header) printstring("Got header, root at "); write(header_root, 0) newline top: %cycle prompt("Command: ") read symbol(command) %until command > ' ' %if command = 'p' %start have = 0; previous key = "" print tree(header_root, 0) %if header_root # 0 %else %if command = 's' prompt("N "); read(n) L read block(nil, token, n, bytes, b) dump(512, byteinteger(addr(b))) %else %if command = 'x' prompt("N "); read(n) L read block(nil, token, n, bytes, b) analyse one(n, b) %else %if command = 'e' %exit %finish %repeat done: L close file(nil, token, 0) %end %of %program