! Directory and file information routines.      J. Butler   Nov 84
! DIRS LIST returns a list of all directories which match MASK
! FILES LIST returns a list of all files in a directory which match MASK.

! This include file is one of a number of files comprising a source "library".
! It does not have any defined level of support.

! you'll need these...
!%include "inc:fs.imp"
!%include "inc:util.imp"
!%include "inc:fsutil.imp"
recordformat  cell fm(string  (31) datum, record  (cell fm) name  link)
conststring  (1) pathseps = ":"
constinteger  max partition = 7
externalroutinespec  smove block(integer  len, from, to)

record  (cell fm) map  dir list(string  (255) mask)
   !Grab the list of directories on this FS matching MASK and return it as a
   !linked list on the heap.   A pointer to the head of the list is returned
   !Via %result.  NIL indicates no matches. Failure conditions will generate 
   !Events.
   record  (cell fm) head
   record  (cell fm) name  tail
   integer  part, dirtot

   routine  do part(integer  part)
      string  (255) s
      string  (31) name
      integer  i, l
      bytearray  buff(0:511)
   
      on  3 start ; return ; finish  {for filestores with fewer partitions}

      s = tostring(part+'0')
      l = fcommr('¬'<<8,s,buff(0),512)
      for  i = 0, 8, 504 cycle 
         smove block(8, addr(buff(i)), addr(name)+1)
         length(name) = 8
         length(name) = length(name)-1 while  name # "" and  charno(name, length(name)) <= ' '
         unless  name = "---" start 
!??!        length(name) = 31 %if length(name) > 31
            if  matches(name, mask) start 
               tail_link == new(head); tail == tail_link; tail_link == nil
               tail_datum = name
            finish 
         finish 
      repeat 
   end 

   head = 0; tail == head
   for  part = 0, 1, MAX PARTITION cycle 
      do part(part<<1); do part(part<<1+1)
   repeat 
   result  == head_link
end 

record  (cell fm) map  files list(string  (31) mask)
   !Grab the list of accessible files in this directory which match MASK and
   !return it on the heap. 
   !A pointer to the head of the list is returned via %result. NIL indicates
   !no matches.  Failures will generate events.
   !MASK is of form <pathname> <pathsep> <filename>. Both may be wild.

   integer  i
   record  (cell fm) head
   record  (cell fm) name  tail, dirs, old
   string  (31) dir

   routine  get files(string  (31) dir)
      integer  ad, ptr, len
      string  (31) name

      predicate  open directory(string  (31) dir)
         on  3,9 start ; false ; finish 
         dir = dir.pathseps if  dir # ""
         connect file(dir."directory", 0, ad, len)
         ptr = 0
         true 
      end 

      routine  close directory
         heapput(ad)
      end 

      predicate  next line(string  (*) name  s)
         integer  c
         s = ""
         false  if  ptr = len
         cycle 
            c = byteinteger(ad+ptr)
            s = s.tostring(c); ptr = ptr+1
         repeatuntil  c = nl
         length(s) = length(s) - 1
         true 
      end 

      if  open directory(dir) start 
         while  next line(name) cycle 
            if  matches(name, mask) start 
               tail_link == new(head); tail == tail_link; tail_link == nil
               name = dir.pathseps.name if  dir # ""
               tail_datum = name
            finish 
         repeat 
         close directory
      finish 
   end 

   !Resolve MASK on last instance of pathsep
   i = length(mask)
   i=i-1 while  i # 0 and  substring(mask,i,i) # pathseps
   if  i > 0 start 
      dir = substring(mask,1,i); length(dir) = length(dir) - 1
      mask = substring(mask,i+1,length(mask))
   finishelse  dir = ""

   head = 0; tail == head
   
   if  wildness(dir) = 0 then  get files(dir) elsestart 
      dirs == dir list(dir)
      while  dirs ## nil cycle 
         get files(dirs_datum) unless  mask = ""
         old == dirs
         dirs == dirs_link
         dispose(old)
      repeat 
   finish 
   result  == head_link
end 

endoffile