! Directory test program

%include "Moose:Mouse.Inc"
%include "TREE.INC"
%systemroutinespec phex(%integer x)

%constinteger separator = '\'

%recordformat path fm(%record(path fm)%name next, 
                      %integer version, %string(255) component)
%constinteger path size = 8;  ! Excluding string

%externalintegerfnspec directory lookup(%record(*)%name access,
                                        %record(path fm)%name path,
                                        %integername file ID,
                                        %string(*)%name textual translation)
%externalintegerfnspec directory insert ID(%record(*)%name access,
                                           %record(path fm)%name path,
                                           %integer inserting ID)
%externalintegerfnspec directory insert text(%record(*)%name access,
                                             %record(path fm)%name path,
                                             %string(255) inserting text)
%externalrecord(*)%mapspec directory contents(%record(*)%name access,
                                              %record(path fm)%name path,
                                              %integername status)

%externalroutinespec create partition table(%integername p size)
%externalroutinespec initialise partition(%integer partition, size,
                                                   index, index size)

%routine show path(%record(path fm)%name p)
   %while p ## nil %cycle
      print symbol('@');  phex(addr(p))
      printstring(" -> ");  phex(addr(p_next))
      printstring(" v ");  write(p_version, 0)
      printstring(" c ");  printstring(p_component)
      newline
      p == p_next
   %repeat
%end

%routine dispose path(%record(path fm)%name p)
   %record(path fm)%name n
      %while p ## nil %cycle
         !! printstring("Disposing (path) ");  phex(addr(p));  newline
         n == p_next
         dispose(p)
         p == n
      %repeat
%end

%record(path fm)%map split path(%string(255) path)
   %record(path fm)%name head == nil, last, current
   %integer ch, n
   %string(255) s
      %result == nil %if path = ""
      s = ""
      %for n = 1, 1, length(path) %cycle
         ch = charno(path, n)
         %if ch = separator %start
            %if s = "" %or n = length(path) %start
               ! Empty component
               dispose path(head)
               %result == nil
            %finish
            ! Else end of component
            current == record(heap get(length(s) + path size + 1))
            !! printstring("Component ");  printstring(s)
            !! printstring(" at ");  phex(addr(current));  newline
            current_component = s
            current_version = 0
            current_next == nil
            %if head == nil %start
               head == current
               last == current
            %else
               last_next == current
               last == current
            %finish
            s = ""
         %else
            s = s . to string(ch)
         %finish
      %repeat
      ! End of last component
      current == record(heap get(length(s) + path size + 1))
      !! printstring("Component ");  printstring(s)
      !! printstring(" at ");  phex(addr(current));  newline
      current_component = s
      current_version = 0
      current_next == nil
      %if head == nil %start
         head == current
         last == current
      %else
         last_next == current
         last == current
      %finish
      %result == head
%end

%routine print key list(%record(key list fm)%name list)
   %while list ## nil %cycle
      spaces(15 - length(list_key));  printstring(list_key)
      spaces(2);  phex(list_value);  newline
      list == list_next
   %repeat
%end

%routine dispose keylist(%record(key list fm)%name what)
   %record(key list fm)%name n
      %while what ## nil %cycle
         !! printstring("Disposing (key) ");  phex(addr(what));  newline
         n == what_next
         dispose(what)
         what == n
      %repeat
%end

%begin
   %record(path fm)%name path
   %record(key list fm)%name key list
   %integer status, op, ID, token, p size, i size, x
   %string(255) s, text
      %on 9 %start;  %stop;  %finish
      open input(0, ":T");  select input(0)
      open output(0, ":T");  select output(0)
      prompt("Do you want to initialise the disc? ")
      read symbol(x) %until x # NL
      %if x = 'y' %or x = 'Y' %start
         create partition table(p size)
         printstring("Partition size is ")
         write(p size, 0);  newline
         prompt("Index file size: ")
         read(i size) %until 0 < i size <= p size // 2
         initialise partition(1, p size, (p size - i size) // 2, i size)
         initialise partition(2, p size, (p size - i size) // 2, i size)
         initialise partition(3, p size, (p size - i size) // 2, i size)
      %finish
      %cycle
         prompt("i/d/l/t ");  read symbol(op)
         !! printstring("Op: ");  print symbol(op);  newline
         %if op = 'i' %start
            ! Insert integer
            prompt("Path: ");  read(s)
            path == split path(s)
            prompt("ID: ");  read(ID)
            %if path ## nil %start
               show path(path)
               status = directory insert ID(nil, path, ID)
               show path(path)
               dispose path(path)
               %if status < 0 %start
                  printstring("Insert failed ");  write(status, 0)
                  newline
               %finish
            %else
               ! Dud
               printstring("Dud path");  newline
            %finish
         %else %if op = 't'
            ! Insert text
            prompt("Path: ");  read(s)
            path == split path(s)
            prompt("Text: ");  read(text)
            %if path ## nil %start
               show path(path)
               status = directory insert text(nil, path, text)
               show path(path)
               dispose path(path)
               %if status < 0 %start
                  printstring("Insert failed ");  write(status, 0)
                  newline
               %finish
            %else
               ! Dud
               printstring("Dud path");  newline
            %finish
         %else %if op = 'd'
            ! Delete
         %else %if op = 'g'
            ! Translate
            prompt("Path: ");  read(s)
            path == split path(s)
            %if path ## nil %start
               status = directory lookup(nil, path, ID, text)
               dispose path(path)
               %if status < 0 %start
                  printstring("Lookup failed ");  write(status, 0)
                  space;  printstring(text)
                  newline
               %else
                  printstring("-> ");  write(ID, 0)
                  space;  printstring(text)
                  newline
               %finish
            %else
               ! Dud
               printstring("Dud path");  newline
            %finish
         %else %if op = 'l'
            ! List contents
            Prompt("Directory: ");  read(s)
            %if s = "." %then path == nil %c
                        %else path == split path(s)
            key list == directory contents(nil, path, status)
            %if status < 0 %start
               printstring("Get key list failed ");  write(status, 0)
               newline
            %else
               print key list(key list)
            %finish
            dispose key list(key list)
            dispose path(path)
         %finish
      %repeat
%end %of %program
